从C语言中的函数调用过程理解计算机执行原理
2016-02-28 本文已影响446人
梅花小筑
本文是Mooc <Linxu操作系统分析>课程第一次作业.
姓名:石维康
转载请注明出处.
经过简单的数字修改,需要编译的C语言代码如下:
int g(int x)
{
return x + 2;
}
int f(int x)
{
return g(x);
}
int main(void)
{
return f(5) + 4;
}
编译后生成的汇编代码如下所示:
生成的完整汇编代码如下:
g:
pushl %ebp
movl %esp, %ebp
movl 8(%ebp), %eax
addl $2, %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 $5, (%esp)
call f
addl $4, %eax
leave
ret
完整截图(对应汇编代码函数):
汇编代码
与视频中采用相同约定,假设初始esp= ebp =0.
先进入main函数执行到call f后,esp=3,ebp=1,堆栈目前的情况
编号 内容
| --- | --- |
ebp | 1 | 0 |
| --- | --- |
| --- | --- |
| 2 | 5 |
| --- | --- |
| --- | --- |
esp | 3 | 23 |
| --- | --- |
| --- | --- |
| 4 | |
| --- | --- |
进入f函数,执行到call g后,堆栈如下
ebp=4
| --- | --- |
| 1 | 0 |
| --- | --- |
| --- | --- |
| 2 | 5 |
| --- | --- |
| --- | --- |
| 3 | 23 |
| --- | --- |
| --- | --- |
ebp-> | 4 | 1 |
| --- | --- |
| --- | --- |
| 5 | 5 |
| --- | --- |
| --- | --- |
esp-> | 6 | 14 |
| --- | --- |
进入g函数执行运算,执行到addl $2, %eax 这句. eax=5+2=7
| --- | --- |
| 1 | 0 |
| --- | --- |
| --- | --- |
| 2 | 5 |
| --- | --- |
| --- | --- |
| 3 | 23 |
| --- | --- |
| --- | --- |
| 4 | 1 |
| --- | --- |
| --- | --- |
| 5 | 5 |
| --- | --- |
| --- | --- |
| 6 | 15 |
| --- | --- |
| --- | --- |
esp,ebp-> | 7 | 4 |
| --- | --- |
在g函数值中,在eip指向ret语句时(即执行完popl %ebp),堆栈如下:
| --- | --- |
| 1 | 0 |
| --- | --- |
| --- | --- |
| 2 | 5 |
| --- | --- |
| --- | --- |
| 3 | 23 |
| --- | --- |
| --- | --- |
ebp-> | 4 | 1 |
| --- | --- |
| --- | --- |
| 5 | 5 |
| --- | --- |
| --- | --- |
esp-> | 6 | 15 |
| --- | --- |
ret 后 eip=15,堆栈变成如下:
| --- | --- |
| 1 | 0 |
| --- | --- |
| --- | --- |
| 2 | 5 |
| --- | --- |
| --- | --- |
| 3 | 23 |
| --- | --- |
| --- | --- |
ebp-> | 4 | 1 |
| --- | --- |
| --- | --- |
esp-> | 5 | 5 |
| --- | --- |
f中的leave执行完之后:
| --- | --- |
ebp-> | 1 | 0 |
| --- | --- |
| --- | --- |
| 2 | 5 |
| --- | --- |
| --- | --- |
esp-> | 3 | 23 |
| --- | --- |
执行f中的ret后,eip=23,eax=7:
| --- | --- |
ebp-> | 1 | 0 |
| --- | --- |
| --- | --- |
esp-> | 2 | 5 |
| --- | --- |
执行main中的leave后,堆栈如下,eax=11,esp=ebp=0:
ebp,esp-> | --- | --- |
| 1 | 0 |
| --- | --- |
回到初始态.
我对计算机执行程序的理解:
计算机只是机械的从PC指针指向的位置取指令并解析执行.而数据与指令都是以二进制形式进行存储.
在C语言层面上的函数调用与返回的语义,在x86层面上是通过call指令与ret指令来完成.