GDB 信息注册命令 - 输出的第二列

GDB info registers command - Second column of output

在 gdb 中 运行 info registers 后,我们得到类似于以下的输出:

rax            0x1c 28
rbx            0x0  0
rcx            0x400a60 4196960
rdx            0x7fffffffde88   140737488346760
rsi            0x1  1
rdi            0x400932 4196658
rbp            0x0  0x0
rsp            0x7fffffffde68   0x7fffffffde68
r8             0x400ad0 4197072
r9             0x7ffff7dea560   140737351951712
r10            0x7fffffffdc30   140737488346160
r11            0x7ffff7732dd0   140737344908752
r12            0x4007f0 4196336
r13            0x7fffffffde80   140737488346752
r14            0x0  0
r15            0x0  0
rip            0x7ffff7732dd0   0x7ffff7732dd0
eflags         0x202    [ IF ]
cs             0x33 51
ss             0x2b 43
ds             0x0  0
es             0x0  0
fs             0x0  0
gs             0x0  0

虽然我理解 raxrcx 等,但 GDB 正在将第二列的值转换为十进制,这似乎并不一致。一些寄存器,即 rsprip 以十六进制显示相同的值,即使在第二列中也是如此。另一方面,eflags 在第二列显示标志。

gdb这样做的原因是什么?如果它要显示相同的信息(在 rsprip 的情况下),这不是多余的吗?此外,这如何推广到其他架构? (以上输出适用于 x86-64)。

info registers 命令以原始格式(十六进制)和自然格式打印出寄存器。

自然格式基于寄存器的类型,在 gdb 源代码的 xml 文件中声明。例如,i386/64bit-core.xml 包含:

<reg name="rax" bitsize="64" type="int64"/>
<reg name="rbx" bitsize="64" type="int64"/>
<reg name="rcx" bitsize="64" type="int64"/>
<reg name="rdx" bitsize="64" type="int64"/>
<reg name="rsi" bitsize="64" type="int64"/>
<reg name="rdi" bitsize="64" type="int64"/>
<reg name="rbp" bitsize="64" type="data_ptr"/>
<reg name="rsp" bitsize="64" type="data_ptr"/>
<reg name="r8" bitsize="64" type="int64"/>
<reg name="r9" bitsize="64" type="int64"/>
<reg name="r10" bitsize="64" type="int64"/>
<reg name="r11" bitsize="64" type="int64"/>
<reg name="r12" bitsize="64" type="int64"/>
<reg name="r13" bitsize="64" type="int64"/>
<reg name="r14" bitsize="64" type="int64"/>
<reg name="r15" bitsize="64" type="int64"/>

<reg name="rip" bitsize="64" type="code_ptr"/>
<reg name="eflags" bitsize="32" type="i386_eflags"/>
<reg name="cs" bitsize="32" type="int32"/>
<reg name="ss" bitsize="32" type="int32"/>
<reg name="ds" bitsize="32" type="int32"/>
<reg name="es" bitsize="32" type="int32"/>
<reg name="fs" bitsize="32" type="int32"/>
<reg name="gs" bitsize="32" type="int32"/>

你可以看到带有type="int64"type="int32"的寄存器在它们的自然输出中显示为十进制值,因为它们通常是通用寄存器并且可以用于引用内存和分配值。

虽然 type="data_ptr"type="code_ptr" 的寄存器具有自然格式的十六进制值,因为它们通常用于引用内存地址。

对于具有 type="i386_eflags" 的寄存器输出设置的标志 'true',因为对于这个寄存器,对于人类来说,知道设置了哪个标志 'True' 而不是十六进制值。

对于其他架构,这取决于寄存器类型在其源代码中的定义方式。您可以在 binutils-gdb/gdb/features/ 查看 ARM, ARM-64, x86-32bit 和许多其他代码的源代码


编辑:

来源:@MarkPlotnick 在 and @perror answer at https://reverseengineering.stackexchange.com/questions/9221/output-of-gdb-info-registers/9222#9222 的回答。

对不起,我忘了提到来源。

事实上,在汇编中你只能找到三种类型的值:

  1. 数值;
  2. 内存地址;
  3. 指令(操作码)。

通用寄存器,例如raxrbx、...,用于存储数值(将触发程序的行为)或内存地址(知道去哪里 read/write 或跳转)。

当然,由于大多数人习惯于在程序中使用十进制格式的值,因此当寄存器可能包含这些值时,显示十进制格式很重要。

现在,重要的是要知道内存地址通常以十六进制格式给出(主要是为了紧凑的原因)。而且,通用寄存器也可能包含内存地址。这就是为什么 gdb 同时显示十进制和十六进制格式,以防其中一种最适合当前值。

寄存器rsprip(和rbp)是特殊情况,因为它们专门用于存储地址(而且只有这个),所以没有用将此类寄存器的内容转换为十进制格式。这就是为什么 gdb 只为这些寄存器提供十六进制格式。

最后,rflags/eflags的情况有点特殊,因为这个寄存器的含义是逐位依赖的(见下图)。

因此,给出十进制、十六进制或二进制格式对用户来说并不是很有用(除非你可以立即将数字与标志相关联)。但是,提供设置为 'true' 的标志列表会更有用(这是您在示例中看到的 [ IF ])。然而,gdb 给出了 eflags 的十六进制值,因为它可以被访问并用作程序中的值(我看到这个是为了混淆目的)。