从汇编看c语言函数调用


学C语言时,就听老师说函数调用时是通过栈来记录信息,又听说什么“保留现场”,"恢复现场"一些既听不懂,也不知道怎么弄懂的东西。最近正在学习Linux下的汇编,现在就通过一个简单的例子来展示一下汇编级的函数调用,这样能够增加大家对C语言的理解。虽然并不是很完善,但是足够阐明函数调用的思想。

在Linux下通过命令gcc -S functest.c,可以生成汇编程序functest.s

//functest.c

#include <stdio.h>

void func(int a, int b)

{

int c;

int d;

c = a;

d = b;

}

int main()

{

func(2, 3);

return 0;

}

在Linux下通过命令gcc -S functest.c,可以生成汇编程序functest.s

首先可以看到一点,一个简单的C程序的汇编却是如此之长,可以想到良好的程序书写习惯有多大的好处。

言归正传,我们不分析每条指令都是什么意思,我们重点看函数调用那一部分。

我们注意在调用call func之前,第25,26,27行是为func准备参数。首先把%esp减去8个字节,这是因为在Linux中int型为4个字节(想想谭浩强C语言程序设计书中说int为2个字节?这东西依赖于具体的操作系统和编译器),即手动修改栈指针,可以发现C语言中函数参数是保存在栈中的,进一步,我们发现gcc把3先压入栈中,之后是2,可以说明,C中函数参数的压栈顺序和函数书写顺序正好相反。执行完这3条指令后,栈中的内容如下:

之后28行调用func,通过call指令。执行call指令时,不仅仅去调用func函数,而且做了一个我们程序员看不到的动作,就是把下一条指令的地址压入到栈中。这点我们稍后会讲到,而且从这我们也能略窥到,函数名只不过是地址的别名,只不过是为了方便程序员理解,我们可以完全用16进制地址取代这些别名,当然计算机并不觉得用地址比用别名更困难。

现在我们进入func。6,7行的两条指令可以认为是套路,具体原因可以见[注1]。先把%ebp的值压入栈,之后把栈顶赋给%ebp,隐约我们可以猜到,因为在这里修改了%ebp,而又不想原来的%ebp被覆盖,那么只好先把原来的%ebp存储到栈中,必要的时候可以在栈中恢复原来的%ebp。第8行,将栈顶向下移,这个操作的目的是为函数中的临时变量在栈中分配存储空间。有人会想为什么不用其它的内存或者寄存器去存储临时变量?这是因为如果为大型项目编写程序,要跟踪哪些变量使用内存,而哪些使用寄存器简直就是恶梦,所以C中用栈存储临时变量,因为在栈在函数调用后会释放或者清空,那么这些变量是不可能被其它函数所调用,故这也是“局部变量”的由来。这个行为也使程序员在函数中要对操作得非常小心,例如我们在函数中开了一个很大的数组,那么在为这个数组开辟栈空间时,很可能出现段错误。执行完6,7,8三行后,栈中的内容如下:

9,10行是把3赋值给d11,12是把2赋值给c。那么栈中的内容确定下来如下:

可以看到,有两个为局部变量开辟的占空间实际并没有被使用到。

有人现在有疑问那个标记”XXXX”的单元式干什么用的,现在我来告诉你那个其实就是函数的返回地址,记得我前面说过,call指令会把调用函数后的下一条指令地址入栈,那么那个地址就存在XXXX那个单元中,这样执行完函数时可以根据栈中的这个地址返回到主调用程序,继续运行。那么完整的栈内容如下:

这样函数基本执行完毕,leave是恢复调用func之前的栈内容和%ebp内容,完全可以用以下指令替代:

movl %ebp, %esp

popl %ebp

ret 指令就是返回到主程序,不赘述。

30行为主程序中从栈中删除调用func时的参数2,3。

这样一个函数的完整调用过程就给大家展示完了,希望对大家有所帮助。本人刚学汇编,如有错误,还望大家指出。

注1:这样做,是为了对函数参数容易进行读取。在设计之初,考虑到用根据%esp和偏移量来对栈中的参数进行访问,但是由于在函数中%esp极有可能改变,那么维护这个偏移量也变的复杂,所以利用%ebp记录进入函数时栈指针的位置,而%ebp在这个函数中不会被改变,那么通过%ebp去定位函数参数就变的非常容易,所以一般有人把%ebp也称为栈底指针,而这也成为了汇编程序员的习惯。

优质内容筛选与推荐>>
1、62 ip与int类型的转换
2、python queue模块
3、遍历图像
4、IOS 如何选择delegate、notification、KVO
5、Django - ORM字段和字段参数


长按二维码向我转账

受苹果公司新规定影响,微信 iOS 版的赞赏功能被关闭,可通过二维码转账支持公众号。

    阅读
    好看
    已推荐到看一看
    你的朋友可以在“发现”-“看一看”看到你认为好看的文章。
    已取消,“好看”想法已同步删除
    已推荐到看一看 和朋友分享想法
    最多200字,当前共 发送

    已发送

    朋友将在看一看看到

    确定
    分享你的想法...
    取消

    分享想法到看一看

    确定
    最多200字,当前共

    发送中

    网络异常,请稍后重试

    微信扫一扫
    关注该公众号