分析函數調用過程棧的佈局(stack frame layout)

int add(int x, int y)
{
    int res = x + y;
    return res;
}

int main()
{    
    add(1, 2);
    return 0;
}

平臺:x86,Ubuntu14.10ubuntu

gcc -S -m32 -masm=intel add.c -o add.side


1. 將1和2推到棧中函數

push 2
push 1


注:圖中上面的位置是內存高地址,是the bottom of stack;下面的位置是內存低地址,是the top of stack。棧增加的方向是從內存高地址到內存低地址。
spa

2. 調用函數add指針

call add

call指令會把call後的下一條指令的地址(eip)壓入棧中,即add函數的返回地址壓入棧中。rest


3. 保存上一個函數棧幀的開始位置到棧中,並保存當前esp位置到ebp中code

push ebp
mov ebp, esp



4. 若函數要用局部變量,則要在堆棧中開闢點空間ip

sub esp, 16



5. 具體的邏輯運算內存

; 將[ebp+8],即1送到edx寄存器
mov edx, DWORD PTR [ebp+8]
; 將[ebp+12],即2送到eax寄存器
mov eax, DWORD PTR [ebp+12]
; 將edx值加到eax中,eax的值變爲3
add eax, edx
; 將eax的值送到[ebp-4],以下圖所示
mov DWORD PTR [ebp-4], eax
; 將[ebp-4]中的值送到eax寄存器中,以便執行ret後還能訪問
mov eax, DWORD PTR [ebp-4]



6. 恢復堆棧指針get

leave

leave至關於:

mov esp, ebp
pop ebp

步驟1、

    

步驟2、



7. 執行return操做

ret

ret指令將call下一條指令的地址(調用call時存放在棧中)從棧中彈出到eip寄存器中。



8. 收尾,保持堆棧平衡

add esp, 8



附:完整的彙編代碼

 .file "add.c"
 .intel_syntax noprefix
 .text
 .globl add
 .type add, @function
add:
.LFB0:
 .cfi_startproc
 push ebp
 .cfi_def_cfa_offset 8
 .cfi_offset 5, -8
 mov ebp, esp
 .cfi_def_cfa_register 5
 sub esp, 16
 mov edx, DWORD PTR [ebp+8]
 mov eax, DWORD PTR [ebp+12]
 add eax, edx
 mov DWORD PTR [ebp-4], eax
 mov eax, DWORD PTR [ebp-4]
 leave
 .cfi_restore 5
 .cfi_def_cfa 4, 4
 ret
 .cfi_endproc
.LFE0:
 .size add, .-add
 .globl main
 .type main, @function
main:
.LFB1:
 .cfi_startproc
 push ebp
 .cfi_def_cfa_offset 8
 .cfi_offset 5, -8
 mov ebp, esp
 .cfi_def_cfa_register 5
 push 2
 push 1
 call add
 add esp, 8
 mov eax, 0
 leave
 .cfi_restore 5
 .cfi_def_cfa 4, 4
 ret
 .cfi_endproc
.LFE1:
 .size main, .-main
 .ident "GCC: (Ubuntu 4.9.1-16ubuntu6) 4.9.1"
 .section .note.GNU-stack,"",@progbits




來自爲知筆記(Wiz)



附件列表

相關文章
相關標籤/搜索