选择显示字体大小

函数调用分析

测试环境:red hat linux 7.2

注解 :
eip 寄存器内容式当前执行指令的下一条指令的地址;
mov eax, ebx 将寄存器eax内容移到ebx; 机器指令2字节。
leave 指令所做的操作相当于mov ebp, esp 然后 pop ebp; 机器指令1字节。
ret 指令所做的操作相当于pop eip; 机器指令1字节。
call addr 指令所做的操作相当于push eip 然后 jmp addr; 机器指令4字节。
jmp addr 执行所做的操作相当于 mov addr, eip; 机器指令2字节。

注意:我们所说的”相当于”是在功能上的等价,并不是实际机器指令的等价。


1. 编写测试程序,如下:
//file name : cc.c
#include

int foo(int fi,int fj)
{
int fk;
fk=3;
return(0);
}
int main()
{
int mi;
int mj;
mi=1;
mj=2;
foo(mi,mj);

return(0);
}

2. 对代码进行编译:
gcc –g –o cc cc.c

3. 用gdb进行debug:gdb cc
(1) 查看源程序:
(gdb) list
4 {
5 int fk;
6 fk=3;
7 return(0);
8 }
9 int main()
10 {
11 int mi;
12 int mj;
13 mi=1;
(gdb)
14 mj=2;
15 foo(mi,mj);
16
17 return(0);
18 }

(2)查看汇编代码:
(gdb) disass main
dump of assembler code for function main:
0x8048444 : push %ebp
0x8048445 : mov %esp,%ebp
0x8048447 : sub $0x8,%esp
0x804844a : movl $0x1,0xfffffffc(%ebp)
0x8048451 : movl $0x2,0xfffffff8(%ebp)
0x8048458 : sub $0x8,%esp
0x804845b : pushl 0xfffffff8(%ebp)
0x804845e : pushl 0xfffffffc(%ebp)
0x8048461 : call 0x8048430
0x8048466 : add $0x10,%esp
0x8048469 : mov $0x0,%eax
0x804846e : leave
0x804846f : ret
end of assembler dump.
(gdb) disass foo
dump of assembler code for function foo:
0x8048430 : push %ebp
0x8048431 : mov %esp,%ebp
0x8048433 : sub $0x4,%esp
0x8048436 : movl $0x3,0xfffffffc(%ebp)
0x804843d : mov $0x0,%eax
0x8048442 : leave
0x8048443 : ret
end of assembler dump.

(3)在主函数设置断点,并执行程序,让程序在main函数刚开始时暂停:
(gdb) break 9
breakpoint 1 at 0x8048444: file c1.c, line 9.
(gdb) run
starting program: /home/syf/p/cc

breakpoint 1, main () at c1.c:10
10 {

(4)查看关键寄存器内容:
(gdb) i reg esp
esp 0xbffffaec 0xbffffaec
(gdb) i reg ebp
ebp 0xbffffb28 0xbffffb28
(gdb) i reg eip
eip 0x8048444 0x8048444

(5)查看栈空间内容:
(gdb) x/32xw 0xbffffae0
0xbffffae0: 0x080494e8 0x080495e4 0xbffffaf8 0x40046507
0xbffffaf0: 0x00000001 0xbffffb54 0xbffffb5c 0x080482d2
0xbffffb00: 0x080484b0 0x00000000 0xbffffb28 0x400464f1
0xbffffb10: 0x00000000 0xbffffb5c 0x4015ec3c 0x40016300
0xbffffb20: 0x00000001 0x08048330 0x00000000 0x08048351
0xbffffb30: 0x08048444 0x00000001 0xbffffb54 0x080482bc
0xbffffb40: 0x080484b0 0x4000dc14 0xbffffb4c 0x40016944
0xbffffb50: 0x00000001 0xbffffc53 0x00000000 0xbffffc62

注意:ebp内容是:0xbffffb28,这个地址对应的内容是0x00000000;

(6)执行一条机器指令(0x8048444 : push %ebp),即将ebp压栈:
(gdb) si
0x08048445 10 {
(gdb) i reg esp
esp 0xbffffae8 0xbffffae8
(gdb) i reg ebp
ebp 0xbffffb28 0xbffffb28
(gdb) i reg eip
eip 0x8048445 0x8048445
(gdb) x/12xw 0xbffffae0
0xbffffae0: 0x080494e8 0x080495e4 0xbffffb28 0x40046507
0xbffffaf0: 0x00000001 0xbffffb54 0xbffffb5c 0x080482d2
0xbffffb00: 0x080484b0 0x00000000 0xbffffb28 0x400464f1

可以看到,ebp(内容是0xbffffb28)被压到0xbffffae8处。

(7)执行一条机器指令(0x8048445 : mov %esp,%ebp),即将esp->ebp,查看寄存器内容和堆内容:
(gdb) si
0x08048447 in main () at c1.c:10
10 {
(gdb) i reg ebp
ebp 0xbffffae8 0xbffffae8
(gdb) i reg esp
esp 0xbffffae8 0xbffffae8
(gdb) i reg eip
eip 0x8048447 0x8048447
(gdb) x/12xw 0xbffffae0
0xbffffae0: 0x080494e8 0x080495e4 0xbffffb28 0x40046507
0xbffffaf0: 0x00000001 0xbffffb54 0xbffffb5c 0x080482d2
0xbffffb00: 0x080484b0 0x00000000 0xbffffb28 0x400464f1

可以看到,栈空间内容没变,只是寄存器ebp变成了esp的值。

(8) 执行三条机器指令,为mi,mj赋值。
三条指令是:
0x8048447 : sub $0x8,%esp
0x804844a : movl $0x1,0xfffffffc(%ebp)
0x8048451 : movl $0x2,0xfffffff8(%ebp)
这三条指令的作用是为mi,mi赋值。

(gdb) si
13 mi=1;
(gdb) si
14 mj=2;
(gdb) si
15 foo(mi,mj);
(gdb) i reg esp
esp 0xbffffae0 0xbffffae0
(gdb) i reg ebp
ebp 0xbffffae8 0xbffffae8
(gdb) i reg eip
eip 0x8048458 0x8048458
(gdb) x/12xw 0xbffffae0
0xbffffae0: 0x00000002 0x00000001 0xbffffb28 0x40046507
0xbffffaf0: 0x00000001 0xbffffb54 0xbffffb5c 0x080482d2
0xbffffb00: 0x080484b0 0x00000000 0xbffffb28 0x400464f1

可以看到,系统为mi,mj在栈内分配了空间(对应的地址分别是:0xbffffae4,0xbffffae0),并进行了赋值(分别是:0x00000001,0x00000002)。

(9)执行下一条指令(0x8048458 : sub $0x8,%esp),将堆栈栈空间加8个字节的空间,没有意义,可以略去,在优化代码时,将被略去。
注:优化代码的方法是:gcc –o –o cc cc.c
(gdb) si
0x0804845b 15 foo(mi,mj);

(10)执行下两条指令,堆将要调用的函数foo(int, int)的参数压栈。两条指令是:
0x804845b : pushl 0xfffffff8(%ebp)
0x804845e : pushl 0xfffffffc(%ebp)
这两条指令的作用是对调用的函数foo(int fi, int fj)的参数压栈。

(gdb) si
0x0804845e 15 foo(mi,mj);
(gdb) si
0x08048461 15 foo(mi,mj);
(gdb) i reg esp
esp 0xbffffad0 0xbffffad0
(gdb) i reg ebp
ebp 0xbffffae8 0xbffffae8
(gdb) i reg eip
eip 0x8048461 0x8048461
(gdb) x/12xw 0xbffffad0
0xbffffad0: 0x00000001 0x00000002 0xbffffaf8 0x08048411
0xbffffae0: 0x00000002 0x00000001 0xbffffb28 0x40046507
0xbffffaf0: 0x00000001 0xbffffb54 0xbffffb5c 0x080482d2

(11)执行下一条指令:0x8048461 : call 0x8048430 。
这条call指令可以分解成两条指令:push eip;jmp 0x8048430。
其作用是保存main函数的foo(int, int)函数调用后的下一条指令的地址(0x8048466),以便foo(int ,int)函数调用返回后在main()函数继续指令,同时还要跳转到foo(int, int)的地址(0x8048430),以便执行函数foo(int ,int);

注意:此时的eip为0x8048466,对应的指令是:0x8048466 : add $0x10,%esp

(gdb) si
foo (fi=1, fj=-1073743020) at c1.c:4
4 {
(gdb) i reg esp
esp 0xbffffacc 0xbffffacc
(gdb) i reg ebp
ebp 0xbffffae8 0xbffffae8
(gdb) i reg eip
eip 0x8048430 0x8048430
(gdb) x/12xw 0xbffffacc
0xbffffacc: 0x08048466 0x00000001 0x00000002 0xbffffaf8
0xbffffadc: 0x08048411 0x00000002 0x00000001 0xbffffb28
0xbffffaec: 0x40046507 0x00000001 0xbffffb54 0xbffffb5c

(12)执行下两条指令,并查看寄存器和堆内容:
这两条指令是:
0x8048430 : push %ebp
0x8048431 : mov %esp,%ebp

这两条指令的作用是对main函数中的 ebp进行压栈,以便返回时用(和第15步对应),同时将esp赋值为ebp(ebp->esp),一般本函数返回(和第16步对应)。

(gdb) si
0x08048431 4 {
(gdb) si
0x08048433 in foo (fi=1, fj=2) at c1.c:4
4 {
(gdb) i reg esp
esp 0xbffffac8 0xbffffac8
(gdb) i reg ebp
ebp 0xbffffac8 0xbffffac8
(gdb) i reg eip
eip 0x8048433 0x8048433
(gdb) x/12xw 0xbffffac8
0xbffffac8: 0xbffffae8 0x08048466 0x00000001 0x00000002
0xbffffad8: 0xbffffaf8 0x08048411 0x00000002 0x00000001
0xbffffae8: 0xbffffb28 0x40046507 0x00000001 0xbffffb54

可以看到ebp的内容被压栈,压在地址0xbffffac8处。

(13)执行下两条指令,并查看寄存器和堆内容:
这两条指令是:
0x8048433 : sub $0x4,%esp
0x8048436 : movl $0x3,0xfffffffc(%ebp)
其作用是为fk赋值。

(gdb) si
7 return(0);
(gdb) i reg esp
esp 0xbffffac4 0xbffffac4
(gdb) i reg ebp
ebp 0xbffffac8 0xbffffac8
(gdb) i reg eip
eip 0x804843d 0x804843d
(gdb) x/12xw 0xbffffac4
0xbffffac4: 0x00000003 0xbffffae8 0x08048466 0x00000001
0xbffffad4: 0x00000002 0xbffffaf8 0x08048411 0x00000002
0xbffffae4: 0x00000001 0xbffffb28 0x40046507 0x00000001

可以看到系统在堆中为fk分配空间(0xbffffac4),并赋值(0x00000003)。

(14)执行下一条指令(0x8048469 : mov $0x0,%eax),其作用是为eax清空,即使返回值为0。
(gdb) i reg esp
esp 0xbffffac4 0xbffffac4
(gdb) i reg ebp
ebp 0xbffffac8 0xbffffac8
(gdb) i reg eip
eip 0x8048442 0x8048442
(gdb) x/12xw 0xbffffac4
0xbffffac4: 0x00000003 0xbffffae8 0x08048466 0x00000001
0xbffffad4: 0x00000002 0xbffffaf8 0x08048411 0x00000002
0xbffffae4: 0x00000001 0xbffffb28 0x40046507 0x00000001

(15)执行下一条指令(0x8048442 : leave),这条指令可以分解为mov ebp esp和pop ebp,其作用使弹出12步中保存的main函数中的ebp,为返回做准备.
(gdb) si
0x08048443 in foo (fi=1, fj=-1073743020) at c1.c:8
8 }
(gdb) i reg esp
esp 0xbffffacc 0xbffffacc
(gdb) i reg ebp
ebp 0xbffffae8 0xbffffae8
(gdb) i reg eip
eip 0x8048443 0x8048443
(gdb) x/12xw 0xbffffacc
0xbffffacc: 0x08048466 0x00000001 0x00000002 0xbffffaf8
0xbffffadc: 0x08048411 0x00000002 0x00000001 0xbffffb28
0xbffffaec: 0x40046507 0x00000001 0xbffffb54 0xbffffb5c

(16)执行下一条指令(0x8048443 : ret),即pop eip,返回11步中保存的返回地址:0x8048466 : add $0x10,%esp。

(gdb) si
0x08048466 in main () at c1.c:15
15 foo(mi,mj);
(gdb) i reg esp
esp 0xbffffad0 0xbffffad0
(gdb) i reg ebp
ebp 0xbffffae8 0xbffffae8
(gdb) i reg eip
eip 0x8048466 0x8048466
(gdb) x/12xw 0xbffffad0
0xbffffad0: 0x00000001 0x00000002 0xbffffaf8 0x08048411
0xbffffae0: 0x00000002 0x00000001 0xbffffb28 0x40046507
0xbffffaf0: 0x00000001 0xbffffb54 0xbffffb5c 0x080482d2

(17)此时,eip为:0x8048466 : add $0x10,%esp,
其后的指令还有:
0x8048466 : add $0x10,%esp
0x8048469 : mov $0x0,%eax
0x804846e : leave
0x804846f : ret

至此函数调用完成,我们不对下面的内容进行分析。   


 


关键字 本文所属关键字

相关 与本文相关文章

分类 所有文章关键字导航

源码编程相关

Java   Asp   PHP   .Net   XML   C/C++   CGI   VB   Jsp   J2ee   J2se   J2me   EJB   Servlet   Tomcat   Resin   Struts   Weblogic   Eclipse   ANT   GUI   JMS   Web servise   IDEA   Webphere   Hibernate   Spring   Jboss   Applet   Swing   Socket   Javamail   Perl   Ajax   P2P   安全   模式   框架   测试   开源   游戏

SQL数据库相关

My-SQL   Ms-SQL   Access   DB2   Oracle   Sybase   SQLserver   索引   存储过程   加密   数据库   分页   视图  

手机无线相关

3G   Wap   CDMA   GRPS   GSM   IVR   彩信   短信   无线   增值业务

网页设计制作相关

HTML   CSS   网页配色   网页特效   Javascript   VBscript   Dreamweaver   Frontpage   JS   Web   网站设计

网站建设推广相关

建站经验   网站优化   网站排名   推广   Alexa

操作系统/服务器相关

Windows XP   Windows 2000   Windows 2003   Windows Me   Windows 9.x   Linux   UNIX   注册表   操作系统   服务器   应用服务器

图形图像多媒体相关

Photoshop   Fireworks   Flash   Coreldraw   Illustrator   Freehand   Photoimpact   多媒体   图形图像

标准 网站致力的规范

Valid CSS!

无不良内容,无不良广告,无恶意代码

Valid XHTML 1.0 Transitional

creativecommons