了解进入标签时 gdb 中“堆栈”显示的内容

Posted

技术标签:

【中文标题】了解进入标签时 gdb 中“堆栈”显示的内容【英文标题】:Understanding what the 'stack' is showing in gdb when going into a label 【发布时间】:2021-01-05 00:13:08 【问题描述】:

我有以下程序集:

_start:    
    mov $strings,   %rbx
    mov $1,         %r12d
  print_loop:
    mov %rbx,       %rdi

这很简单,但下面是它在gdb 中针对这三行/指令中的每一个显示的内容:

    mov $strings, %rbx

    0x00000000004000c4  ? mov    $0x6000ea,%rbx # memory address of 'strings'
    
    ─── Stack ──────────────────────────────────────────────────────────────────────────────────────────────────────
    [0] from 0x00000000004000c4 in _start
    

    mov $1, %r12d

    0x00000000004000cb  ? mov    $0x1,%r12d
    
    ─── Stack ───────────────────────────────────────────────────────────────────────────────────────────────────────
    [0] from 0x00000000004000cb in _start
    

    但是在第三条指令——标签后的第一条指令——事情看起来很奇怪:

    0x00000000004000d1  ? mov    %rbx,%rdi
    
    ─── Stack ───────────────────────────────────────────────────────────────────────────────────────────────────────
    [0] from 0x00000000004000d1 in print_loop
    [1] from 0x0000000000000001
    [2] from 0x00007fffffffe5aa
    [3] from 0x0000000000000000
    

这到底是什么意思,为什么会显示这样的内容?似乎堆栈仍应显示一行:

[0] from 0x00000000004000d1 in print_loop
- or - 
[0] from 0x00000000004000d1 in _start

【问题讨论】:

【参考方案1】:

这到底是什么意思,

这意味着GDB认为你在print_loop函数内部执行,并且它认为这个函数是从地址0x1的一些代码调用的,它是从地址0x7fffffffe5aa调用的,等等。

为什么它会显示这样的东西?

迷糊了。

看起来堆栈应该仍然显示一行:

正确。


现在,您的下一个问题可能是“为什么 GDB 会感到困惑?”。

答案有些复杂。

在不使用专用帧指针寄存器的平台上,例如x86_64,GDB 没有通用方法来展开堆栈,它需要编译器的帮助才能这样做.编译器创建“展开表”,GDB 将其解释为执行堆栈展开。

由于您是用汇编语言编写的,并且没有使用.cfi_... 指令,因此您的代码没有任何展开描述符。

在没有展开描述符的情况下,GDB只能猜测,这里猜测不正确。

要解决此问题,您可以提供展开描述符,如下所示(未经测试):

_start:
    .cfi_startproc
    .cfi_undefined(rip)     # no unwinding past this function    
    mov $strings,   %rbx
    mov $1,         %r12d
  print_loop:
    mov %rbx,       %rdi
...
    .cfi_endproc

这应该不会混淆 GDB。各种.cfi 指令的文档可以在here 找到。

【讨论】:

GDB 特殊情况_start 是否在堆栈内部执行时不尝试展开堆栈?因为它知道堆栈内容将是argcargv[].... .cfi 是“Call Frame”的缩写吗?或者这些指令通常与什么相关? @samuelbrody1249 我相信CFI 代表“调用框架信息”。 @samuelbrody1249:site:***.com cfi directive 的快速谷歌搜索找到了包括What are CFI directives in Gnu Assembler (GAS) used for? 在内的一堆东西,它们回答了这个问题。请参阅sourceware.org/binutils/docs/as/CFI-directives.html。一般来说,请先尝试在谷歌上搜索您的问题,然后再让其他人花时间回答 cmets,尤其是宽泛的问题。

以上是关于了解进入标签时 gdb 中“堆栈”显示的内容的主要内容,如果未能解决你的问题,请参考以下文章

Swift - 以编程方式向堆栈视图添加标签

使用堆栈视图时的对齐问题

如何使用 GDB 查看堆栈的内容?

堆栈视图,将空间折叠到内容

Swift UIView 从堆栈视图中消失

在内联汇编中使用函数范围的标签