免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1599 | 回复: 0
打印 上一主题 下一主题

用gdb跟踪函数栈桢的变化情况 [复制链接]

论坛徽章:
36
IT运维版块每日发帖之星
日期:2016-04-10 06:20:00IT运维版块每日发帖之星
日期:2016-04-16 06:20:0015-16赛季CBA联赛之广东
日期:2016-04-16 19:59:32IT运维版块每日发帖之星
日期:2016-04-18 06:20:00IT运维版块每日发帖之星
日期:2016-04-19 06:20:00每日论坛发贴之星
日期:2016-04-19 06:20:00IT运维版块每日发帖之星
日期:2016-04-25 06:20:00IT运维版块每日发帖之星
日期:2016-05-06 06:20:00IT运维版块每日发帖之星
日期:2016-05-08 06:20:00IT运维版块每日发帖之星
日期:2016-05-13 06:20:00IT运维版块每日发帖之星
日期:2016-05-28 06:20:00每日论坛发贴之星
日期:2016-05-28 06:20:00
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2010-01-26 18:10 |只看该作者 |倒序浏览

                                                                                                代码如下:
#include
void hello()
{
    int i = 0;
    printf("i = %d, hello world\n", i);
}
int main()
{
    hello();
    return 0;
}
gdb生成调试信息,跟进去看看。
在调用hello之前,在main函数内查看寄存器情况时,打印如下:
(gdb) info registers
eax            0xbff644a4    -1074379612
ecx            0xbff64420    -1074379744
edx            0x1    1
ebx            0xb7f2fff4    -1208811532
esp            0xbff64400    0xbff64400
ebp            0xbff64408    0xbff64408
esi            0x8048420    134513696
edi            0x8048310    134513424
eip            0x80483f7    0x80483f7
eflags         0x286    [ PF SF IF ]
cs             0x73    115
ss             0x7b    123
ds             0x7b    123
es             0x7b    123
fs             0x0    0
gs             0x33    51
在进入hello函数之后,查看寄存器情况,打印如下:
(gdb) info registers
eax            0xbff644a4    -1074379612
ecx            0xbff64420    -1074379744
edx            0x1    1
ebx            0xb7f2fff4    -1208811532
esp            0xbff643e0    0xbff643e0
ebp            0xbff643f8    0xbff643f8
esi            0x8048420    134513696
edi            0x8048310    134513424
eip            0x80483ca    0x80483ca
eflags         0x282    [ SF IF ]
cs             0x73    115
ss             0x7b    123
ds             0x7b    123
es             0x7b    123
fs             0x0    0
gs             0x33    51
根据两个栈桢中寄存器的数据,看看变化前的esp - 变化后的ebp,得到以下结果:
(gdb) print 0xbff64400 - 0xbff643f8
$1 = 8
再看看 在hello之中*(ebp), *(ebp + 4)的数据:
(gdb) x 0xbff643f8
0xbff643f8:    0xbff64408
(gdb) x 0xbff643f8+4
0xbff643fc:    0x080483fc
其中, 第一次打印的结果0xbff64408是main栈桢中ebp寄存器的数据。
而反汇编main函数的结果如下:
(gdb) disassemble main
Dump of assembler code for function main:
0x080483e6 :    lea    0x4(%esp),%ecx
0x080483ea :    and    $0xfffffff0,%esp
0x080483ed :    pushl  -0x4(%ecx)
0x080483f0 :    push   %ebp
0x080483f1 :    mov    %esp,%ebp
0x080483f3 :    push   %ecx
0x080483f4 :    sub    $0x4,%esp
0x080483f7 :    call   0x80483c4
0x080483fc :    mov    $0x0,%eax
0x08048401 :    add    $0x4,%esp
0x08048404 :    pop    %ecx
0x08048405 :    pop    %ebp
0x08048406 :    lea    -0x4(%ecx),%esp
0x08048409 :    ret   
End of assembler dump.
可以看到,在调用call hello的下一句指令的地址是0x080483fc,就是上面
(gdb) x 0xbff643f8+4
0xbff643fc:    0x080483fc
的结果。
【Godbach注1】程序调用函数时,会执行call指令,此时会将下一条要执行指令地址压栈。这里就是0x080483fc。也就是下图中调用hello之后的栈分布图中保存的EIP指令。
因此,可以给出函数调用前后栈桢的分布图如下:

另外,在图中没有显示出来的是hello栈桢中的局部变量从(ebp - 4)地址开始,你可以在hello栈桢中打印*(ebp-4)的数据看看。
结论如下:
1) 调用前的esp - 调用后的ebp = 8,因为需要保存两个寄存器的数据
2)*(ebp)存放的是上一个栈桢的ebp数据,而*(ebp+4)存放的是返回上一个栈桢时需要执行的下一条语句的地址,即函数调用返回时存入到eip寄存器的数据。
3)根据结论2),有一个问题:为什么下一条指令的地址高于所要保存的ebp寄存器的地址?因为在call指令执行的时候首先保存下一条指令的地址,再跳转到函数的执行地址。
4)根据结论3),将与函数调用有关的几条汇编指令再进行一下讲解:
a)call指令:上面已经做了解释,重复如下:首先保存下一条指令的地址,再跳转到函数的执行地址
b)进入一个函数时首先会调用的几条语句:
push   %ebp            ;保存ebp寄存器
mov    %esp,%ebp    ;将esp寄存器保存到ebp
sub    $0x18,%esp    ;调整esp,用以保存返回地址和局部变量,这个调整值并不确定,根据局部变量的情况而定
这几句指令就是用于保存上一个栈桢的ebp寄存器地址,向地址低位扩展栈位置。
其中的pushl %ebp
相当于:
subl $4, %esp
movl %ebp, (%esp)
c)退出一个函数时,执行的几条指令是:
退出一个函数时:
leave                        ; 相当于 movl %ebp, %esp;popl %ebp(也就是将ebp保存的esp地址恢复,然后恢复ebp寄存器数据)
ret                           ; 相当于popl %eip;jmp %eip的作用
【Godbach注2】上面注1中已经提到函数调用的时候会将下一条执令的地址压栈。当函数调用结束前,会先先执行leave指令,esp就指向了之前保存的下一条指令的地址。然后就通过ret指令,将该指令的地址保存到eip寄存器,通过jmp %eip继续执行函数调用后的代码,而esp也恢复到了函数调用前的状态。
5) 两个名词不能混淆了,栈(stack)指的是一个进程中所有用于给函数调用局部变量的空间,这是对进程全局而言的;而栈桢(stack frame)针对的是进程内一个单一的函数的空间,因此,栈桢是栈的子集。
注意,以上说明均在X86平台下。
               
               
               
               
               
               
               
               
               
               
               
               
               
               
               

本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u/33048/showart_2161514.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP