首页 > 解决方案 > 了解进入标签时 gdb 中“堆栈”显示的内容

问题描述

我有以下程序集:

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

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

  1. mov $strings, %rbx

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

    0x00000000004000cb  ? mov    $0x1,%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

标签: assemblyx86stackgdb

解决方案


究竟是什么意思,

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

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

它很困惑。

似乎堆栈仍应显示一行:

正确的。


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

答案有些复杂。

在不使用专用帧指针寄存器的平台上,例如GDBx86_64没有通用的方法来展开堆栈,它需要编译器的帮助才能这样做。编译器创建“展开表”,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可以在此处找到各种指令的文档。


推荐阅读