通过bp寄存器查看调用栈关系

                                                       通过bp寄存器查看调用栈关系

      首先介绍下几个概念:

1)栈

        栈是向下生长的,所谓向下生长是指从内存高地址->低地址的路径延伸,栈有栈底和栈顶,栈顶的地址要比栈底低。对x86体系的CPU而言,其中

      寄存器ebp(basepointer )可称为“帧指针”或“基址指针”,64位机器为rbp。

      寄存器esp(stackpointer)可称为“ 栈指针”,64位机器为rsp。

      ebp 在未受改变之前始终指向栈帧的开始,也就是栈底,所以ebp的用途是在堆栈中寻址用的。

      esp是会随着数据的入栈和出栈移动的,esp始终指向栈顶。

       见下图,假设函数A调用函数B,我们称A函数为"调用者",B函数为“被调用者”则函数调用过程可以这么描述:

(1)先将调用者(A)的堆栈的基址(ebp)入栈,以保存之前任务的信息。

(2)然后将调用者(A)的栈顶指针(esp)的值赋给ebp,作为新的基址(即被调用者B的栈底)。

(3)然后在这个基址(被调用者B的栈底)上开辟(一般用sub指令)相应的空间用作被调用者B的栈空间。

(4)函数B返回后,从当前栈帧的ebp即恢复为调用者A的栈顶(esp),使栈顶恢复函数B被调用前的位置;然后调用者A再从恢复后的栈顶可弹出之前的ebp值。这样,ebp和esp就都恢复了调用函数B前的位置,也就是栈恢复函数B调用前的状态。


2)堆栈格式

=====参数n======

=====参数n-1=====

=======......======

=====参数1======

=====返回地址====== +4/+832&$ebp+4 ==>+4; 64&$rbp+8==>+8

==入栈保存的bp===32位机器为ebp寄存器,64位为rbp寄存器

====被保存的寄存器====

====临时变量=======

 

由于优化、调用方式、编译器的不同,上述布局部可能有所不同,但一般来说,ebp前(&($ebp)+4 )是函数返回后下一条指令的地址,ebp存的是上一级函数的ebp的地址

 

 

3)实际调用关系例子

bt.c源码

gcc-g -o bt bt.c 编译

#include <stdio.h>
int f1(int i)
{
	int a1 = 0;
	int b1 = 1;
	return a1+b1+f2(i);
}
int f2(int i)
{
	int a2 = 1;
	int b2 = 2;
	
	return a2*b2+f3(i);
}
int f3(int j)
{
	int a3 = 3;
	int b3 = 4;
	return a3+b3+j-3;
}
int main()
{
	f1(4);
	return 0;
}


$ gdb bt

GNU gdb (GDB) 7.6.1

Copyright (C) 2013 Free Software Foundation, Inc.

License GPLv3+: GNU GPL version 3 or later<http://gnu.org/licenses/gpl.html>

This is free software: you are free to change and redistributeit.

There is NO WARRANTY, to the extent permitted by law.  Type "show copying"

and "show warranty" for details.

This GDB was configured as "mingw32".

For bug reporting instructions, please see:

<http://www.gnu.org/software/gdb/bugs/>...

Reading symbols from d:\test\gdb\bt.exe...done.

(gdb) start

Temporary breakpoint 1 at 0x4014a6: file bt.c, line 23.

Starting program: d:\test\gdb/bt.exe

[New Thread 6468.0x1564]

 

Temporary breakpoint 1, main () at bt.c:23

23              f1(4);

(gdb) p $ebp

$1 = (void *) 0x28ff48

(gdb) x/xw $1+4

0x28ff4c:       0x00401250

(gdb) b f1

Breakpoint 2 at 0x401417: file bt.c, line 4.

(gdb) c

Continuing.

 

Breakpoint 2, f1 (i=4) at bt.c:4

4               int a1 =0;

(gdb) p $ebp

$2 = (void *) 0x28ff28

(gdb) x/xw $2+4

0x28ff2c:      0x004014b2 //f1函数调用返回后,下一条pc指令

(gdb) disas /m main

Dump of assembler code for function main:

22      {

   0x00401498<+0>:     push   %ebp

   0x00401499<+1>:     mov    %esp,%ebp

   0x0040149b<+3>:     and    $0xfffffff0,%esp

   0x0040149e<+6>:     sub    $0x10,%esp

   0x004014a1<+9>:     call   0x401940 <__main>

 

23              f1(4);

   0x004014a6<+14>:    movl   $0x4,(%esp)

   0x004014ad<+21>:   call   0x401410 <f1>

 

24              return 0;

   0x004014b2<+26>:    mov    $0x0,%eax

 

25      }   0x004014b7 <+31>:   leave

   0x004014b8<+32>:    ret

 

End of assembler dump.

(gdb) b f2

Breakpoint 3 at 0x401448: file bt.c, line 10.

(gdb) c

Continuing.

 

Breakpoint 3, f2 (i=4) at bt.c:10

10              int a2 =1;

(gdb) p $ebp

$3 = (void *) 0x28fef8

(gdb) x/xw $3+4

0x28fefc:      0x00401439

(gdb) disas /m f1

Dump of assembler code for function f1:

3       {

   0x00401410<+0>:     push   %ebp

   0x00401411<+1>:     mov    %esp,%ebp

   0x00401413<+3>:     push   %ebx

   0x00401414<+4>:     sub    $0x24,%esp

 

4               int a1 =0;

   0x00401417<+7>:     movl   $0x0,-0xc(%ebp)

 

5               int b1 =1;

   0x0040141e<+14>:    movl   $0x1,-0x10(%ebp)

 

6               returna1+b1+f2(i);

   0x00401425<+21>:    mov    -0xc(%ebp),%edx

   0x00401428<+24>:    mov    -0x10(%ebp),%eax

   0x0040142b<+27>:    lea    (%edx,%eax,1),%ebx

   0x0040142e<+30>:    mov    0x8(%ebp),%eax

   0x00401431<+33>:    mov    %eax,(%esp)

   0x00401434 <+36>:    call   0x401441 <f2>

   0x00401439<+41>:    add   %ebx,%eax

 

7       }

   0x0040143b<+43>:    add    $0x24,%esp

   0x0040143e <+46>:    pop   %ebx

   0x0040143f<+47>:    pop    %ebp

   0x00401440<+48>:    ret

 

End of assembler dump.

(gdb) b f3

Breakpoint 4 at 0x401478: file bt.c, line 17.

(gdb) c

Continuing.

 

Breakpoint 4, f3 (j=4) at bt.c:17

17              int a3 =3;

(gdb) p $ebp

$4 = (void *) 0x28fec8

(gdb) x/xw $4+4

0x28fecc:      0x0040146a //f3函数调用返回后,下一条pc指令

(gdb) disas /m f2

Dump of assembler code for function f2:

9       {

   0x00401441<+0>:     push   %ebp

   0x00401442<+1>:     mov    %esp,%ebp

   0x00401444 <+3>:     push  %ebx

   0x00401445<+4>:     sub    $0x24,%esp

 

10              int a2 =1;

   0x00401448<+7>:     movl   $0x1,-0xc(%ebp)

 

11              int b2 =2;

   0x0040144f<+14>:    movl   $0x2,-0x10(%ebp)

 

12

13              returna2*b2+f3(i);

   0x00401456<+21>:    mov    -0xc(%ebp),%eax

   0x00401459<+24>:    imul   -0x10(%ebp),%eax

   0x0040145d<+28>:    mov    %eax,%ebx

   0x0040145f<+30>:    mov    0x8(%ebp),%eax

   0x00401462<+33>:    mov    %eax,(%esp)

   0x00401465 <+36>:    call  0x401472 <f3>

   0x0040146a <+41>:    add   %ebx,%eax

 

14      }

   0x0040146c<+43>:    add    $0x24,%esp

   0x0040146f<+46>:    pop    %ebx

   0x00401470<+47>:    pop    %ebp

   0x00401471<+48>:    ret

 

End of assembler dump.

(gdb) p $ebp  //f3中的ebp中的值为f2中ebp寄存器的地址
$5 = (void *) 0x28fec8
(gdb) x/xw 0x28fec8
0x28fec8:       0x0028fef8 //f2中ebp的值
(gdb) x/xw 0x0028fef8      //f1中ebp的地址
0x28fef8:       0x0028ff28 //f1中ebp的值
(gdb) x/wx 0x0028ff28    //main中ebp的地址
0x28ff28:       0x0028ff48

 

 

 

 



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值