1.简单的c程序如下:
- int g(int x)
- {
- return x + 1;
- }
- int f(int x)
- {
- return g(x);
- }
- int main(void)
- {
- return f(1) + 1;
- }
通过命令 gcc -S -o main.s main.c -m32得到汇编代码,实验截图如下:
2.汇编代码的工作过程中堆栈的变化如下:
1)几个寄存器的说明:
eip:自动执行下一条指令。
ebp:指向堆栈栈底。
esp:指向堆栈栈顶。
eax:函数返回默认使用eax寄存器返回上一级函数。
2)关于push和pop指令的说明(32位):
push:esp的值减4。
pop:esp的值加4。
3)下面仔细说明各指令执行时堆栈的变化(从main函数开始,为了方便模拟堆栈的变化,采用标号的形式,每一个标号代表4个 字节,执行push操作esp指向的标号就加1,pop操作esp指向的标号就减1):
堆栈的初始状态:
1. pushl %ebp
2. movl %esp, %ebp
ebp 指向标号为1的位置
3. subl $4, %esp
4. movl $1,(%esp)
5. call f
等同于这两条指令:push %eip
movl f,%eip
执行call指令时,eip实际指向的时call的下条指令,行号为23行的指令
此时,eip指向了f:,从第9行开始执行。
6. push %ebp
7. movl %esp,%ebp
8. subl $4,%esp
9. movl 8(%ebp),%eax
此时,堆栈无变化,变址寻址,ebp的值加8,就是标号为2的位置,将标号2的内容赋给寄存器eax,eax=1。
10. movl %eax,(%esp)
11. call g 同上call f
12. pushl %ebp
13. movl %esp,%ebp
14. movl 8(%ebp),eax
同上,堆栈无变化,eax=1
15. addl $1,%eax
堆栈无变化,eax加1,eax=2
16.popl %ebp
ebp 又指向了原来标号为4的位置
17. ret
等同于指令:pop %eip
eip指向了代码第15行,执行指令leave
18. leave
等同于这两条指令:movl %ebp, %esp
popl %ebp
堆栈变化为:movl %ebp,%esp
popl %ebp
19. ret
此时,eip指向了代码第23行
20. addl $1,%eax
eax=2+1=3
21. leave
同上,最后堆栈为:
最后回到main函数的最初的状态。
22. ret 返回到main函数之前的堆栈
3.总结:
计算机的工作过程就是处理一个有一个程序的过程,计算机在执行程序时,预先要把指挥计算机如何进行操作的指令序列(称为程序)和原始数据通过输入设备输送到计算机内存寄存器中。每一条指令中明确规定了计算机从哪个地址取数,进行什么操作,然后送到什么地址去等步骤。计算机在运行时,先从内存中取出第一条指令,通过控制器的译码,按指令的要求,从存储器中取出数据进行指定的运算和逻辑操作等加工,然后再按地址把结果送到内存中去。接下来,再取出第二条指令,在控制器的指挥下完成规定操作。依此进行下去。直至遇到停止指
《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000