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