gdb调试--堆栈相关

GDB调试程序最常用的莫过于使用bt命令查看发生问题时的调用栈了。显示的堆栈信息依次是从最底层到最上层的一个被调用关系。

那这些堆栈信息是如何而来的?函数在调用的时候会自动的将一些信息压栈。以x86架构下为情况说明,首先压入的是参数,在有多个多个参数的情况下,从右往左依次压入;然后是调用函数的返回地址;接着是压调用函数的栈帧的帧指针ebp(或者rsp);再下来就是被调用函数的局部变量了。

gdb调试--堆栈相关_第1张图片

 

图1

下面以上图中所示代码为例看下是如何压栈的?

在第13行打断点,运行到此断点的情况如下:

 

 

图2

红色框部分就是建立栈帧的过程,将rbp寄存器压栈,并将rsp的值赋给rbp,正如用i reg命令查看寄存器看到rbp等于rsp,这时候栈帧为空,栈底部等于顶部位置。

 

蓝色框部分是准备将func的参数压栈,在x86架构下传参是通过压栈的方式(ARM下面是通过寄存器的方式传递参数的,当然x86下面也是可以通过__attribute__((regparm(n)))的方式,来用寄存器传参的,后面会讲)。

rsi/esi寄存器用来传递第二个参数,rdi/edi寄存器用来传递第一个参数。图2中就是讲第一个参数1赋给edi,第二个参数赋给esi。

 

按s进入func函数

gdb调试--堆栈相关_第2张图片

 

图3

绿色框部分是func函数建立堆栈的一个过程。看下此时寄存器的值是什么情况。

gdb调试--堆栈相关_第3张图片

 

图4

 

Func函数栈帧的栈顶部在rsp指向的0x7fffffffe5d0位置处,栈底部在rbp指向的0x7fffffffe5f0位置处。此时堆栈的大致情况如下图5所示。图3中红色框部分就是将参数1和2压栈的指令,蓝色框部分就是将局部变量0和1压栈的指令。

gdb调试--堆栈相关_第4张图片

 

图5

用”x 地址”方式可以查看堆栈各个位置的信息,以作验证。

 

在函数调用的过程中建立栈帧会消耗一定的时间,例如在频繁调用库函数的场景下,我们是否可以不建立栈帧,来节省这一时间呢?在编译的时候带上-fomit-frame-pointer选项,就能够做到。

 

 

 

你可能感兴趣的:(linux,gdb,调试)