做者 雲青
原創做品轉載請註明出處html
基本的彙編知識:ubuntu
movl,subl,pushl,topl,ret,addl,leave,enter
參考資料下載地址。http://pan.baidu.com/s/1cdISDC
課程地址:《Linux內核分析》MOOC課程http://mooc.study.163.com/cou...框架
建立文件,並進行編譯ide
int g(int x) { return x + 3; } int f(int x) { return g(x); } int main(void) { return f(8) + 1; }
編譯命令:函數
gcc -S -o demo1.s demo1.c -m32
運行完畢後生成以下文件:spa
.file "demo1.c" .text .globl g .type g, @function g: .LFB0: .cfi_startproc pushl %ebp .cfi_def_cfa_offset 8 .cfi_offset 5, -8 movl %esp, %ebp .cfi_def_cfa_register 5 movl 8(%ebp), %eax addl $3, %eax popl %ebp .cfi_restore 5 .cfi_def_cfa 4, 4 ret .cfi_endproc .LFE0: .size g, .-g .globl f .type f, @function f: .LFB1: .cfi_startproc pushl %ebp .cfi_def_cfa_offset 8 .cfi_offset 5, -8 movl %esp, %ebp .cfi_def_cfa_register 5 subl $4, %esp movl 8(%ebp), %eax movl %eax, (%esp) call g leave .cfi_restore 5 .cfi_def_cfa 4, 4 ret .cfi_endproc .LFE1: .size f, .-f .globl main .type main, @function main: .LFB2: .cfi_startproc pushl %ebp .cfi_def_cfa_offset 8 .cfi_offset 5, -8 movl %esp, %ebp .cfi_def_cfa_register 5 subl $4, %esp movl $8, (%esp) call f addl $1, %eax leave .cfi_restore 5 .cfi_def_cfa 4, 4 ret .cfi_endproc .LFE2: .size main, .-main .ident "GCC: (Ubuntu 4.8.4-2ubuntu1~14.04.3) 4.8.4" .section .note.GNU-stack,"",@progbits
咱們將命令簡化獲得以下彙編指令:.net
g: pushl %ebp movl %esp, %ebp movl 8(%ebp), %eax addl $3, %eax popl %ebp ret f: pushl %ebp movl %esp, %ebp subl $4, %esp movl 8(%ebp), %eax movl %eax, (%esp) call g leave ret main: pushl %ebp movl %esp, %ebp subl $4, %esp movl $8, (%esp) call f addl $1, %eax leave ret
備註:
%開頭表示寄存器
$開頭表示當即數
()表示間接尋址,樣例(GAS = C語言):(%eax)= *eax [[2]](http://www.cnblogs.com/lxgeek...
Imm(Ea) ,變址尋址,樣例(GAS = C語言):4(%eax) = *(4+eax)3d
咱們以簡化版爲例:rest
C語言的都是從mian函數開始運行的,同理,彙編也是從main函數開始運行的,下面咱們來從main函數入手。
首先執行的是18行pushl指令,
先畫出內存的棧此時的狀況:esp和ebp此時都指向棧底。code
pushl %ebx ,即將數據壓棧,指令至關於
subl $4, %esp
movl %ebx,(%esp)
二、執行movl %esp,%ebp,以後eip指向下一條指令,變爲
三、執行 subl $4, %esp
四、執行movl $8, (%esp)
5 、call f
call f等價於
pushl %eip
movl f %eip
6 、pushl %ebp
七、movl %esp, %ebp
八、 subl $4, %esp
九、movl 8(%ebp), %eax
十、movl %eax, (%esp)
十一、call g
十二、
pushl %ebp
movl %esp,%ebp
每進入一個函數都會執行這兩個彙編指令
這兩步操做是個規範化步驟, 叫作前序(prologue) [1]。
執行函數時,彙編會生成一個堆棧調用框架:
具體以下:
//創建被調用者函數的堆棧框架 pushl %ebp movl %esp,%ebp //被調用者函數體 //do something //拆除被調用者的函數的堆棧框架 movl %ebp,%esp popl %ebp ret
1三、 movl 8(%ebp), %eax
1四、addl $3,%eax
1五、popl %ebp
popl %ebp 至關於
movl (%esp),%ebp
addl $4,%esb
1六、ret
等價於 popl %eip
1七、leave 等價於
movl %ebp,%esp
popl %ebp
1八、ret
1九、addl $1,%eax
20 leave
2一、ret
main函數運行結束,將%eax的值返回,即12
參考文章:
[1] X86彙編調用框架淺析與CFI簡介
[2] http://www.cnblogs.com/lxgeek...