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
虽然我理解 rax
、rcx
等,但 GDB 正在将第二列的值转换为十进制,这似乎并不一致。一些寄存器,即 rsp
和 rip
以十六进制显示相同的值,即使在第二列中也是如此。另一方面,eflags
在第二列显示标志。
gdb
这样做的原因是什么?如果它要显示相同的信息(在 rsp
和 rip
的情况下),这不是多余的吗?此外,这如何推广到其他架构? (以上输出适用于 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 的回答。
对不起,我忘了提到来源。
事实上,在汇编中你只能找到三种类型的值:
- 数值;
- 内存地址;
- 指令(操作码)。
通用寄存器,例如rax
、rbx
、...,用于存储数值(将触发程序的行为)或内存地址(知道去哪里 read/write 或跳转)。
当然,由于大多数人习惯于在程序中使用十进制格式的值,因此当寄存器可能包含这些值时,显示十进制格式很重要。
现在,重要的是要知道内存地址通常以十六进制格式给出(主要是为了紧凑的原因)。而且,通用寄存器也可能包含内存地址。这就是为什么 gdb
同时显示十进制和十六进制格式,以防其中一种最适合当前值。
寄存器rsp
、rip
(和rbp
)是特殊情况,因为它们专门用于存储地址(而且只有这个),所以没有用将此类寄存器的内容转换为十进制格式。这就是为什么 gdb
只为这些寄存器提供十六进制格式。
最后,rflags
/eflags
的情况有点特殊,因为这个寄存器的含义是逐位依赖的(见下图)。
因此,给出十进制、十六进制或二进制格式对用户来说并不是很有用(除非你可以立即将数字与标志相关联)。但是,提供设置为 'true' 的标志列表会更有用(这是您在示例中看到的 [ IF ]
)。然而,gdb
给出了 eflags
的十六进制值,因为它可以被访问并用作程序中的值(我看到这个是为了混淆目的)。
在 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
虽然我理解 rax
、rcx
等,但 GDB 正在将第二列的值转换为十进制,这似乎并不一致。一些寄存器,即 rsp
和 rip
以十六进制显示相同的值,即使在第二列中也是如此。另一方面,eflags
在第二列显示标志。
gdb
这样做的原因是什么?如果它要显示相同的信息(在 rsp
和 rip
的情况下),这不是多余的吗?此外,这如何推广到其他架构? (以上输出适用于 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 在
对不起,我忘了提到来源。
事实上,在汇编中你只能找到三种类型的值:
- 数值;
- 内存地址;
- 指令(操作码)。
通用寄存器,例如rax
、rbx
、...,用于存储数值(将触发程序的行为)或内存地址(知道去哪里 read/write 或跳转)。
当然,由于大多数人习惯于在程序中使用十进制格式的值,因此当寄存器可能包含这些值时,显示十进制格式很重要。
现在,重要的是要知道内存地址通常以十六进制格式给出(主要是为了紧凑的原因)。而且,通用寄存器也可能包含内存地址。这就是为什么 gdb
同时显示十进制和十六进制格式,以防其中一种最适合当前值。
寄存器rsp
、rip
(和rbp
)是特殊情况,因为它们专门用于存储地址(而且只有这个),所以没有用将此类寄存器的内容转换为十进制格式。这就是为什么 gdb
只为这些寄存器提供十六进制格式。
最后,rflags
/eflags
的情况有点特殊,因为这个寄存器的含义是逐位依赖的(见下图)。
因此,给出十进制、十六进制或二进制格式对用户来说并不是很有用(除非你可以立即将数字与标志相关联)。但是,提供设置为 'true' 的标志列表会更有用(这是您在示例中看到的 [ IF ]
)。然而,gdb
给出了 eflags
的十六进制值,因为它可以被访问并用作程序中的值(我看到这个是为了混淆目的)。