我正在 x86-64 系统上使用 GDB 调试 GAS 汇编程序。当我将rax寄存器设置为-1然后将eax设置为1时,rax的值变为0xffffffff00000001,但我期望它是0x0000000000000001,因为我认为设置eax会清除rax的高32位(基于我的内容)已阅读有关 x86-64 如何处理 eax 的信息)。
这就是我所做的:
(gdb) set $rax=-1
(gdb) info register rax
rax 0xffffffffffffffff -1
(gdb) set $eax=1
(gdb) info register rax
rax 0xffffffff00000001 -4294967295 # (???)
GDB 通过更改内存中的字节来更改寄存器(例如,在 Linux 上通过
struct pt_regs
系统调用在目标进程的 ptrace
中)。不是通过在目标进程的上下文中在 CPU 上运行类似 mov eax, ...
的指令。
如果我没有看到你的实验,我可能会猜测
set $eax=1
可能会零扩展到完整的 RAX 以匹配 asm 语义,但在考虑之后,它似乎很合理,它没有。 这简化了 GDB 的内部结构,不必以与 32 位部分寄存器不同的方式处理 8 位和 16 位部分寄存器,只需修改为所有 4 个宽度实际指定的操作数的宽度即可。
如果您想设置完整的寄存器,通过命名它仍然很容易做到(
$rax
)。 要截断和零扩展任意表达式,我想 set $rax=(uint32_t)(a*b + c | d)
或其他。
对于 128 位
$xmm0
,保留 $ymm0 / $zmm0
的高位不修改会匹配旧版 SSE 语义,而不是 VEX/EVEX 语义。 因此,即使模拟写入寄存器的 asm 指令,您也可能想要它,并且如果零扩展是唯一的选择,则很难实现。