c语言中函数调用怎么编程,C语言函数调用分析

今天突发奇想想要研究一下C语言的函数调用.

因为以前有个课程设计涉及到C语言函数返回地址的问题,今天看Thinking in C++的时候,看到类似的东西...就想要验证一下.

编译器:gcc4.0.1 on darwin

操作系统:Mac OS X 10.5.8

编辑器:MacVim  :)

首先上C语言源程序

#include

void a(int b);

int main()

{

int x = 0x11223344;

printf("&x == %p\n", &x);

a(x);

x = 1;

printf("x == %d\n", x);

return 0;

}

void a(int b){

int c = 0x11223344;

void *p = &c;

int i = 0;

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

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

printf("%d\n", &b - &c);

for(i = 0; i < 32; ++i){

printf("@%p = %x\n", p + i, *(char * )(p + i));

}

}

用gcc -g 编译以后..用gdb进行调试

首先看生成的汇编代码..

输入disas main查看main函数汇编

0x00001ec2 : push %ebp

0x00001ec3 : mov %esp,%ebp

0x00001ec5 : push %ebx

0x00001ec6 : sub $0x24,%esp

0x00001ec9 : call 0x1ece

0x00001ece : pop %ebx

0x00001ecf : movl $0x11223344,-0xc(%ebp) //注意点1

0x00001ed6 : lea -0xc(%ebp),%eax

0x00001ed9 : mov %eax,0x4(%esp)

0x00001edd : lea 0xfd(%ebx),%eax

0x00001ee3 : mov %eax,(%esp)

0x00001ee6 : call 0x3005

0x00001eeb : mov -0xc(%ebp),%eax //注意点2

0x00001eee : mov %eax,(%esp)

0x00001ef1 : call 0x1f1d

0x00001ef6 : movl $0x1,-0xc(%ebp)//注意点3

0x00001efd : mov -0xc(%ebp),%eax

0x00001f00 : mov %eax,0x4(%esp)

0x00001f04 : lea 0x107(%ebx),%eax

0x00001f0a : mov %eax,(%esp)

0x00001f0d : call 0x3005

0x00001f12 : mov $0x0,%eax

0x00001f17 : add $0x24,%esp

0x00001f1a : pop %ebx

0x00001f1b : leave

0x00001f1c : ret

然后输入disas a查看a函数的汇编代码

0x00001f1d : push %ebp //注意点4

0x00001f1e : mov %esp,%ebp

0x00001f20 : push %ebx

0x00001f21 : sub $0x24,%esp

0x00001f24 : call 0x1f29

0x00001f29 : pop %ebx

0x00001f2a : movl $0x55667788,-0x14(%ebp)

0x00001f31 : lea -0x14(%ebp),%eax

0x00001f34 : mov %eax,-0x10(%ebp)

0x00001f37 : movl $0x0,-0xc(%ebp)

0x00001f3e : lea 0x8(%ebp),%eax

0x00001f41 : mov %eax,0x4(%esp)

0x00001f45 : lea 0xb5(%ebx),%eax

0x00001f4b : mov %eax,(%esp)

0x00001f4e : call 0x3005

0x00001f53 : lea -0x14(%ebp),%eax

0x00001f56 : mov %eax,0x4(%esp)

0x00001f5a : lea 0xbe(%ebx),%eax

0x00001f60 : mov %eax,(%esp)

0x00001f63 : call 0x3005

0x00001f68 : lea 0x8(%ebp),%edx

0x00001f6b : lea -0x14(%ebp),%eax

0x00001f6e : mov %edx,%ecx

0x00001f70 : sub %eax,%ecx

0x00001f72 : mov %ecx,%eax

0x00001f74 : sar $0x2,%eax

0x00001f77 : mov %eax,0x4(%esp)

0x00001f7b : lea 0xc7(%ebx),%eax

0x00001f81 : mov %eax,(%esp)

0x00001f84 : call 0x3005

0x00001f89 : movl $0x0,-0xc(%ebp)

0x00001f90 : jmp 0x1fbf

0x00001f92 : mov -0xc(%ebp),%eax

0x00001f95 : add -0x10(%ebp),%eax

0x00001f98 : movzbl (%eax),%eax

0x00001f9b : movsbl %al,%edx

0x00001f9e : mov -0xc(%ebp),%eax

0x00001fa1 : add -0x10(%ebp),%eax

0x00001fa4 : mov %edx,0x8(%esp)

0x00001fa8 : mov %eax,0x4(%esp)

0x00001fac : lea 0xcb(%ebx),%eax

0x00001fb2 : mov %eax,(%esp)

0x00001fb5 : call 0x3005

0x00001fba : lea -0xc(%ebp),%eax

0x00001fbd : incl (%eax)

0x00001fbf : cmpl $0x1f,-0xc(%ebp)

0x00001fc3 : jle 0x1f92

0x00001fc5 : add $0x24,%esp

0x00001fc8 : pop %ebx

0x00001fc9 : leave

0x00001fca : ret

果然和书上写的一样..从右往左压参数,再压返回值,再压局部变量。

下面解释一下汇编代码里面的注意点...

注意点1:因为x是main函数的局部变量..所以需要将局部变量压栈.注意压栈的地址是%ebp - c..因为unix下面的栈是从高地址往低地址的方向延伸的.所以用减

注意点2:把a函数的参数压到栈里面...可以想象,在传值过程中,值会被复制一份到栈里面..那么对象也会重新生成一个在栈里面..难怪要搞拷贝构造函数了....这里一个疑问是为什么不用push?

注意点3:这个时候下一条命令的地址是0x00001ef6

注意点4:把栈基址推到栈里面...这里是一个关键哦...

ok...接着按l显示源代码..然后输入 b 8在第8行做了一个断点...

按r执行函数...

到断点的时候..输入i reg看一下寄存器..

esp 0xbffff630 0xbffff630

ebp 0xbffff658 0xbffff658

ok...按s进入函数

再按一下n 执行那条int c的声明语句.

这时候看一下寄存器

esp 0xbffff600 0xbffff600

ebp 0xbffff628 0xbffff628

有变化了..

输入x/20x $esp查看一下esp后面的地址内容

0xbffff600: 0xa054e638 0xa054ade0 0x00001fcb 0xbffff634

0xbffff610: 0x00000004 0x55667788 0xbffff678 0xbffff634

0xbffff620: 0x00001ece 0x00001ece 0xbffff658 0x00001ef6

0xbffff630: 0x11223344 0xbffff64c 0x8fe0154b 0x00001000

0xbffff640: 0x00000000 0x00000000 0xbffff66c 0x11223344

ok..看见我们可爱的 11223344 和55667788了..

而11223344下面的一个地址内容..果然是注意3里面提到的地址..

而注意4里面的..也再他恰当的位置出现了.....

唯一还存在疑问的地方就是....

我们的55667788并没有按照书上所说的..紧紧跟着原来老的$ebp的值后面出现....

中间多了16个字节奇怪的数字...

究竟这些数字是做什么用的....

如果有人知道..可以回帖....

我也会查资料去了解的....

恩...C语言还是很奇妙的东东

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值