C语言函数参数入栈的理解分析

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

先来看这样一段程序:

view plain copy

print?

1.#include

2.#include

3.#include

4.

5.void print1(int a,int b,int c)

6.{

7. printf("%p\n",&a);

8. printf("%p\n",&b);

9. printf("%p\n",&c);

10.}

11.

12.int main(void)

13.{

14. print1(1,2,3);

15. exit(0);

16.}

它的输出是:

[cpp]view plain copy

print?

1.0022FF40

2.0022FF44

3.0022FF48

发现a,b,c的地址是逐渐增大的,差值是4个字节。这和我所知道的:C函数参数入栈的顺序是从右到左是相匹配的,而且地址的增大值也

与变量所占的字节数相匹配。

不过当把程序稍微做一下修改,如下:

[cpp]view plain copy

print?

1.#include

2.

3.

4.

5.char char char

6.

7.

8.

9.

10.

11.

12.int

13.

14.

15.

16.

再观察一下它的输出:

view plain copy

print?

1.0022FF2C

2.0022FF28

3.0022FF24

怎么和上面的效果是相反的!虽然我知道这肯定编译器的一个技巧,不过参数入栈的顺序是从右到左的概念却动摇了。

为了弄清楚其中的道理,必须观察程序生成的中间.s文件,为此,我执行了以下一条命令:

[cpp]view plain copy

print?

1.gcc -S test.c(当前C文件中保存的程序是文章一开始的那个) 在当前目录下生成test.s

文件

使用vim打开test.s文件(只截取主要内容了):

esp是指向栈顶的指针,ebp是用来备份这个指针的。栈的形状如下:

esp

ebp

|____________________________________________________

栈的最大值栈的最小值

每压入一个参数入栈,就执行 esp = esp - sizoeof(参数)。不过在esp值变之前,先备份一下ebp = esp,这样不管最后esp指到哪里去了,函数结束时就用这个ebp就能顺利回到调用者了。

view plain copy

print?

1.print1:

2. pushl %ebp//6.先把ebp压栈,保存这个指针

3. movl %esp, %ebp//7.使ebp这个指针保存着esp这个指针指向的地址值

4. subl $8, %esp//8.使esp - 8,也就是说空下8个字节以便实现某个功能

5. leal 8(%ebp), %eax//9.把(ebp + 8)的地址给eax 这个地方为什么要+8 因为这

个函数在经历第5,6步的时候存在着压了两个4字节入栈的操作。此时+8就指向了实参

1

6. movl %eax, 4(%esp)//10.这个时候就用到第8步空下来的8个字节中的4个了,原

来是保存值,原理就是用C语言写两个数交换值时的那个第三个变量,即缓冲区

7. movl $.LC0, (%esp) //11.把字符

串“%p\n”压栈从第10,11步来看,两个参数的入栈顺序,其实不管顺序了,两个参

数,最右边的在高地址,最左边的在低地址

8. call printf//12.调用函数printf,又是压栈出栈的操作了 到此可以得到8个字节的缓冲区全部用完了

9. leal 12(%ebp), %eax//13.同第9步,此时获取的是实参2的地址

10. movl %eax, 4(%esp)//14.我想说同上

11. movl $.LC0, (%esp) //15.我想说

同上

12. call printf//16.我想说同上

13. leal 16(%ebp), %eax//17.同第9步,此时获取的是实参3的地址

14. movl %eax, 4(%esp)//18.我想说同上

15. movl $.LC0, (%esp) //19.我想说

同上

16. call printf//20.我想说同上。到了此处我们就知道,printf打印参数的地址,这

个地址是在main函数中压栈时分配的,是什么就是什么,符合参数入栈的顺序是从右到左

这个说法。

17. leave

相关文档
最新文档