gpt4 book ai didi

assembly - GDB - 它如何知道函数调用堆栈?

转载 作者:行者123 更新时间:2023-12-05 08:56:54 25 4
gpt4 key购买 nike

使用gdb调试汇编程序时,bt会打印调用栈。

问题是:

  • (a) gdb 是否根据当前函数存储在寄存器中的 rbp 值以及先前 rbp 值存储在堆栈中知道这一点?
  • 如果是,(b-1) gdb 如何根据 rbp 值知道它是哪个函数? (b-2) 编译时指定-g选项时,栈基和函数之间的映射是否存储在可执行文件中? (b-3) 以及如何使用 readelf 读取映射数据?哪一部分?
  • 如果不是,(c) 那么 gdb 如何跟踪函数调用堆栈?

最佳答案

像 GDB 这样的调试器有两种主要的遍历堆栈的方法来打印回溯。他们要么假定帧指针寄存器 (RBP) 中的值是指向堆栈帧链表开始的指针,要么使用存储在可执行文件中的特殊展开信息来描述如何遍历(展开)堆栈。

使用帧指针

当使用帧指针时,假定它指向当前函数保存其调用者帧指针值的位置。它还假定就在保存的帧指针之前是存储当前函数的返回地址的地方。这就是它如何知道调用函数的 RBP 值是什么,以及调用当前函数的函数,它可以很容易地从返回地址确定。然后,它可以通过遍历链接的 RBP 值找到堆栈中所有先前的堆栈帧和函数。

但是,这假定函数以这种方式使用帧指针,并且通常不能保证它们会这样做。基本上它假设函数序言和结尾看起来像这样:

func:
push %rbp # save previous frame pointer
mov %rsp, %rbp # new frame pointer points to previous value
sub $24, %rsp # allocate stack space for this funciton

...

pop %rbp # restore previous frame pointer
ret

但是在优化时,许多编译器不会这样做,因为它们很少需要使用帧指针,而是会像对待任何其他通用寄存器一样对待 RBP,并将其用于其他用途。

使用展开信息

因此,为了在不使用 RBP 作为帧指针的函数之间生成回溯,调试器可能会使用展开信息。这是存储在可执行文件(和动态库)中的特殊数据,它准确地描述了如何在函数执行过程中的任何时间点虚拟撤消函数执行的所有堆栈操作。展开信息的格式和位置因可执行格式和 CPU 类型而异。对于 ELF x86-64 可执行文件,展开信息以基于 DWARF 的格式存储在 .eh_frame 部分中调试格式的展开信息。这种格式太复杂,无法在此处描述,但您可以阅读 System V AMD64 ABI了解更多详情。

关于assembly - GDB - 它如何知道函数调用堆栈?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38158006/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com