实验
1、编写main.c代码并编译为汇编代码
2、打开main.s文件查看汇编代码
完整汇编代码如下:
.file "main.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 $e, %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.2-19ubuntu1) 4.8.2"
.section .note.GNU-stack,"",@progbits
3、分析过程中堆栈变化
- pushl %ebp 将esp的值减4,再将ebp的值放入esp指向的地址中
- movl %esp, %ebp 把esp的值赋值给ebp,则esp和ebp指向同一位置
- subl $4, %esp 将esp的值减4
- movl $8, (%esp) 将8放入esp指向的位置
- call f 将esp的地址减4,使栈顶指针指向下一个存储单元,并将eip寄存器中存放的地址放入栈顶指针esp所指的存储单元;然后把函数f起始地址放入eip寄存器中
- pushl %ebp 将esp的值减4,再将ebp的值放入esp指向的地址中
- movl %esp, %ebp 把esp的值传送给ebp,则esp和ebp指向同一位置
- subl $4, %esp 将esp的值减4
- movl 8(%ebp), %eax 将8(%ebp)中的内容存入eax寄存器中
- movl %eax, (%esp) 将eax的值放入esp指向的地址中
- call g 将esp的地址减4,使栈顶指针指向下一个存储单元,并将eip寄存器中存放的地址放入栈顶指针esp所指的存储单元;然后把函数g起始地址放入eip寄存器中
- pushl %ebp 将esp的值减4,再将ebp的值放入esp指向的地址中
- movl %esp, %ebp 把esp的值传送给ebp,两者指向同一位置
- movl 8(%ebp), %eax 将ebp+8后的值存入eax寄存器中
- addl $1, %eax 将eax寄存器中存放的数据加1,得到的结果仍放在eax寄存器中
- popl %ebp 将栈顶指针esp所指存储单元中存放的数据传给栈底指针ebp,使该数据即为栈底指针所代表地址;栈顶指针esp所代表的地址加4,使栈顶指针指向前一个存储单元
- ret g程序返回
- leave 将EBP寄存器的内容复制到ESP寄存器中,以释放分配给该过程的所有堆栈空间。然后,它从堆栈恢复EBP寄存器的旧值
- ret f程序返回
- addl $1, %eax 将eax寄存器中存放的数据加1,得到的结果仍放在eax寄存器中
- leave 将EBP寄存器的内容复制到ESP寄存器中,以释放分配给该过程的所有堆栈空间。然后,它从堆栈恢复EBP寄存器的旧值
- ret main程序返回
总结
计算机中栈顶指针为esp,栈底指针为ebp,eip指向下一条将要执行的指令,eax等寄存器保存计算结果。pushl %eax相当于subl $4, %esp;movl %eax,(%esp)。popl %eax相当于movl (%esp),%eax;addl $4,%esp。call 0x12345相当于pushl %eip;movl $0x12345,%eip。ret相当于popl %eip。leave相当于movl %ebp,%esp;popl %ebp。