簡體   English   中英

理解匯編語言

[英]Understanding assembly language

我試圖理解與上面的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)?
    (b)如果存儲了某些東西,為什么需要存儲它?

提前致謝 :)

在回答你的問題之前。 而不是什么注釋代碼是干什么的,我的評論,所有的值都在寄存器或堆棧。

參數在堆棧上,返回值在%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]

停止

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

但無論如何 ...


  1. 一種。 val通常在堆棧上,為-4(%ebp) 唯一沒有的是xorl %eax,%eax
    它存儲在-4(%ebp) ,如線leal -4(%ebp),%eaxmovl %eax,-4(%ebp)movl -4(%ebp),%edx 另外,前一幀的val*p
    C。 val必須位於堆棧上,以便可以獲取其地址並將其傳遞給遞歸調用。
  2. 一種。 val2永遠不會存儲在堆棧中,盡管很可能是其中的一部分? s是為它保留的空間。
    它被存儲在regixter eax.L4 ,其在披函數的第一支路是遞歸調用的返回值,並在第二分支是值0 ,將其也存儲在val
    C。 val2永遠不需要在堆棧上,因為它的地址不被占用,它在遞歸調用之前不存在,所以它不需要保存,並且使用的寄存器很少,不需要溢出。
  3. 一種。 -24(%ebp)%ebx的保存值,來自pushl %ebx
    %ebx是被調用者保存的寄存器,因此必須保留其值。
  4. 一種。 不,那里什么都沒有。
    如果有必要泄漏,它很可能是val2 我最好的猜測是其他三個? s保留用於未使用的遞歸調用調用者保存的寄存器: %eax%ecx%edx

你問了很多。

我將從這部分開始......

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

了解; 模糊不清,不是嗎!

程序員(在您的情況下看起來像編譯器)希望L3:處的指令位於所謂的“16字節邊界”上。

你可以在這里閱讀有關這些東西的詳細信息。 如果這沒有意義,請回到這里,我會再解釋一下。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM