2014-10-09 95 views
7

我想了解與上面的C代碼有關的彙編代碼。我不確定我是否在正確的軌道上,所以也許有人可以幫助我更好地理解這一點。瞭解彙編語言

int silly(int n, int *p) 
{ 
    int val, val2; 
    if (n > 0) 
     val2 = silly(n << 1, &val); 
    else 
     val = val2 = 0; 
    *p = val + val2 + n; 
    return val + val2; 
} 

我們得到以下的機器代碼:

silly: 
pushl %ebp    // Here I am making space for the function on the stack 
movl %esp,%ebp   // Moving the stack pointer where the base pointer is 
subl $20,%esp   // Subtracting 20 from the stack pointer to allocate more space 
pushl %ebx    // Pushing the %ebx register on top of the stack 
movl 8(%ebp),%ebx  // Getting the first argument(which is n) and store it in register %ebx 
testl %ebx,%ebx  // The first if-statement which compares if n > 0 
jle .L3    // Jump if less or equal - meaning if n < 0 then jump to .L3 
addl $-8,%esp   // Add -8 to %esp to allocate more space 
leal -4(%ebp),%eax  // Storing the first local variable (which is val) in %eax 
pushl %eax    // Pushing the register %eax on top of the stack 
leal (%ebx,%ebx),%eax // n + n and stores it as 2n in %eax 
pushl %eax    // Pushing register %eax on top of the stack (Which I find strange 
         // considering that I've just pushed %eax onto the stack above 
call silly    // Call the function silly 
jmp .L4    // Jump to .L4 (Unconditionally) 
.p2align 4,,7   // Don't know what this means. 
.L3:     // .L3 is the else-statement 
xorl %eax,%eax   // Basically making %eax = 0 
movl %eax,-4(%ebp)  // Moving the value in %eax which is 0 to the first local variable 
         // meaning val = 0 
.L4:     // .L4 is the section after the else-statement 
movl -4(%ebp),%edx  // Getting val again and now storing it in %edx 
addl %eax,%edx   // Adding what is in %eax (which is 0) to %edx 
movl 12(%ebp),%eax  // Getting the second parameter (*p) and storing it in %eax 
addl %edx,%ebx   // Adding value from %edx to %ebx - meaning val + n 
movl %ebx,(%eax)  // Moving what is in %ebx and storing it in memory location of %eax 
movl -24(%ebp),%ebx // Getting the second local variable (val2) and moving it to %ebx 
movl %edx,%eax   // Move val to %eax - and the return value will be in %eax 
movl %ebp,%esp   
popl %ebp 
ret 

我想換我解決這個頭,我剛開始想組裝等主題的指針將是非常好的。我有幾個我需要問這個彙編代碼,可以幫助棧我的理解的問題:

  • (a)是存儲在堆棧上的變量val?
    (b)如果是這樣,在什麼字節oset(相對於%ebp)被存儲?
    (c)爲什麼需要將它存儲在堆棧中?

  • (a)變量val2是否存儲在堆棧中?
    (b)如果是這樣,在什麼字節oset(相對於%ebp)被存儲?
    (c)爲什麼需要將它存儲在堆棧中? (a)什麼(如果有的話)存儲在-24(%ebp)?
    (b)如果有東西存儲在那裏,爲什麼需要存儲它? (a)什麼(如果有的話)存儲在-8(%ebp)?(0127)
    (b)如果有東西存儲在那裏,爲什麼需要存儲它?

感謝提前:)

+4

你的問題到底是什麼? – o11c 2014-10-09 21:36:10

+0

我剛剛更新了這個問題。對不起:) – drleifz 2014-10-09 21:41:38

+0

注意:'val2'是未初始化的。有時。有時候'val'也是如此。 – wildplasser 2014-10-09 22:34:45

回答

1

在回答您的問題之前。我沒有評論代碼在做什麼,我評論了所有值都在寄存器或堆棧中的位置。

參數在堆棧上,返回值爲%eax

寄存器%eax,%ecx%edx被保存。所有其他寄存器,包括%ebx,%ebp%esp,都被調用保存(%edi%esi未使用)。

我的堆棧符號一次是4個字節,我使用;作爲ebp點的位置(如果已知)。

silly:      ; eax: ?, ebx: ebx0, edx: ?, stack: [eip0, n, p] 
    pushl %ebp    ; eax: ?, ebx: ebx0, edx: ?, stack: [ebp0, eip0, n, p] 
    movl %esp,%ebp   ; eax: ?, ebx: ebx0, edx: ?, stack: [; ebp0, eip0, n, p] 
    subl $20,%esp   ; eax: ?, ebx: ebx0, edx: ?, stack: [?, ?, ?, ?, ?; ebp0, eip0, n, p] 
    pushl %ebx    ; eax: ?, ebx: ebx0, edx: ?, stack: [ebx0, ?, ?, ?, ?, ?; ebp0, eip0, n, p] 
    movl 8(%ebp),%ebx  ; eax: ?, ebx: n, edx: ?, stack: [ebx0, ?, ?, ?, ?, ?; ebp0, eip0, n, p] 
    testl %ebx,%ebx  ; set flags from n 
    jle .L3    ; if flags indicates <= 0, goto .L3, else fallthrough 

          ; set up for calling the function 
    addl $-8,%esp   ; eax: ?, ebx: n, edx: ?, stack: [?, ?, ebx0, ?, ?, ?, ?, ?; ebp0, eip0, n, p] 
    leal -4(%ebp),%eax  ; eax: &val, ebx: n, edx: ?, stack: [?, ?, ebx0, ?, ?, ?, ?, (stackeax); ebp0, eip0, n, p] 
    pushl %eax    ; eax: &val, ebx: n, edx: ?, stack: [&val, ?, ?, ebx0, ?, ?, ?, ?, val=?; ebp0, eip0, n, p] 
    leal (%ebx,%ebx),%eax ; eax: 2*n, ebx: n, edx: ?, stack: [&val, ?, ?, ebx0, ?, ?, ?, ?, val=?; ebp0, eip0, n, p] 
    pushl %eax    ; eax: 2*n, ebx: n, edx: ?, stack: [2*n, &val, ?, ?, ebx0, ?, ?, ?, ?, val=?; ebp0, eip0, n, p] 
    call silly    ; pushes eip; args: (2*n, &val); val will be initialized on return 
    jmp .L4    ; 
          ; 
.p2align 4,,7    ; request alignment (there should be one before `silly:` too) 
.L3:      ; 
    xorl %eax,%eax   ; eax: val=0, ebx: n, edx: ?, stack: [ebx0, ?, ?, ?, ?, ?; ebp0, eip0, n, p] 
    movl %eax,-4(%ebp)  ; eax: val=0, ebx: n, edx: ?, stack: [ebx0, ?, ?, ?, ?, val; ebp0, eip0, n, p] 
          ; 
.L4:      ; eax: val2=φ(function result, 0), ebx: n, edx: ?, stack: [..., ebx0, ?, ?, ?, ?, val; ebp0, eip0, n, p] 
    movl -4(%ebp),%edx  ; eax: val2, ebx: n, edx: val, stack: [..., ebx0, ?, ?, ?, ?, val; ebp0, eip0, n, p] 
    addl %eax,%edx   ; eax: val2, ebx: n, edx: val+val2, stack: [..., ebx0, ?, ?, ?, ?, val; ebp0, eip0, n, p] 
    movl 12(%ebp),%eax  ; eax: p, ebx: n, edx: val+val2, stack: [..., ebx0, ?, ?, ?, ?, val; ebp0, eip0, n, p] 
    addl %edx,%ebx   ; eax: p, ebx: n+val+val2, edx: val+val2, stack: [..., ebx0, ?, ?, ?, ?, val; ebp0, eip0, n, p] 
    movl %ebx,(%eax)  ; *p = n+val+val2 
    movl -24(%ebp),%ebx ; eax: p, ebx: ebx0, edx: val+val2, stack: [..., ebx0, ?, ?, ?, ?, val; ebp0, eip0, n, p] 
    movl %edx,%eax   ; eax: val+val2, ebx: ebx0, edx: val+val2, stack: [..., ebx0, ?, ?, ?, ?, val; ebp0, eip0, n, p] 
    movl %ebp,%esp   ; eax: val+val2, ebx: ebx0, edx: val+val2, stack: [; ebp0, eip0, n, p] 
    popl %ebp    ; eax: val+val2, ebx: ebx0, edx: val+val2, stack: [eip0, n, p] 
    ret     ; eax: val+val2, ebx: ebx0, edx: val+val2, stack: [n, p] 

STOP

返回並重新讀取代碼。如果你不自己想出答案,你只會傷害自己。我寫的評論應該很容易。

但無論如何...


  1. 一個。 val通常位於堆棧上,位於-4(%ebp)。唯一不是的是xorl %eax,%eax
    b。它存儲在-4(%ebp),如線路leal -4(%ebp),%eaxmovl %eax,-4(%ebp)movl -4(%ebp),%edx所示。此外,前一幀的val*p
    c。 val必須位於堆棧上,以便其地址可以被接受並傳遞給遞歸調用。
  2. a。 val2永遠不會存儲在堆棧中,儘管很可能其中一些?是爲其保留的空間。 b。它存儲在regixter eax.L4,它在phi函數的第一個分支上是遞歸調用的返回值,在第二個分支上是值0,它也存儲在val中。
    c。 val2永遠不需要在堆棧上,因爲它的地址沒有被佔用,它在遞歸調用之前不存在,所以它不需要被保存,並且沒有足夠的寄存器在使用,因此不需要溢出。
  3. a。 -24(%ebp)是保存的值%ebx,從行pushl %ebx
    b。 %ebx是一個被調用者保存的寄存器,所以它的值必須保留。
  4. a。不,沒有什麼。 b。如果有必要泄漏,最有可能是val2。我最好的猜測是其他三個?被保留用於遞歸調用呼叫者保存的未使用寄存器:%eax,%ecx%edx
0

你已經問了很多。

我會用這部分開始...

.p2align 4,,7 // Don't know what this means.

明白了;模糊,不是嗎!

程序員(在你的情況下看起來像編譯器)想要L3:的指令位於所謂的「16字節邊界」。

你可以閱讀關於那東西HERE的細節。如果這沒有意義,請回到這裏,我會解釋一些。