张震涛 - 原创作品转载请注明出处 - 《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000
首先编写一个简单的c程序:
int g(int x) {
return x + 6;
}
int f(int x) {
return g(x);
}
int main() {
return f(81) + 1;
}
在Linux下用gcc编译为汇编代码:
gcc -S -o main.s main.c -m32
生成的汇编代码中有很多"."开头的行,都是链接信息,我们把这些行删除,以免影响阅读。最后剩下的汇编代码为:
g:
pushl %ebp
movl %esp, %ebp
movl 8(%ebp), %eax
addl $6, %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 $81, (%esp)
call f
addl $1, %eax
leave
ret
我们来详细分析一下这段代码。首先解释一下几个寄存器的含义:
- EBP - 存放栈的基地址
- ESP - 存放栈的顶地址
- EIP - 存放下一条指令的地址(这里我们为了描述简单用代码的行号表示)
- EAX - 存放数值(后面会看到,它通常存放函数的返回值)
好,下面开始解释每条代码的含义
通过分析这个小程序的汇编代码,我们了解了程序执行的基本逻辑:
- 也就是通过堆栈的操作来执行函数的跳转,以及返回。
- 同时在每个函数执行期间,函数内部的变量都在栈上进行操作。
- 而返回值一般通过EAX来返回。