了解进入标签时 'stack' 在 gdb 中显示的内容

Understanding what the 'stack' is showing in gdb when going into a label

我有以下程序集:

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

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

  1. mov $strings, %rbx

    0x00000000004000c4  ? mov    [=12=]x6000ea,%rbx # memory address of 'strings'
    
    ─── Stack ──────────────────────────────────────────────────────────────────────────────────────────────────────
    [0] from 0x00000000004000c4 in _start
    
  2. mov , %r12d

    0x00000000004000cb  ? mov    [=13=]x1,%r12d
    
    ─── Stack ───────────────────────────────────────────────────────────────────────────────────────────────────────
    [0] from 0x00000000004000cb in _start
    
  3. 但是在第三条指令上——标签之后的第一条指令——事情看起来很不稳定:

    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

What does that mean exactly,

这意味着 GDB 认为您在 print_loop 函数内部执行,并且它认为该函数是从地址 0x1 的某些代码调用的,而地址是从地址 0x7fffffffe5aa 调用的], 等等

and why does it show things like that?

一头雾水

It seems like the stack should still show one line:

正确。


现在,您的下一个问题可能是“为什么 GDB 会混淆?”。

答案有点复杂。

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

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

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

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

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

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