问题描述
我正在x86-64中编写一个函数,将一个1字节的值转换为代表该字节ASCII码的十六进制字符串。在我的功能开始时,我尝试使用
movb %dil,%r11b
将1字节的值存储在寄存器%r11的最低字节中。但是,当我在gdb中进行检查时,从未设置%r11b。而是设置了%r11的较高字节。这是使用gdb时得到的:
Breakpoint 1,0x00000000004011f0 in byte_as_hex ()
(gdb) print /x $r11b
$1 = 0x0
(gdb) print /x $r11
$2 = 0x246
(gdb) print /x $rdi
$3 = 0x48
(gdb) print /x $dil
$4 = 0x48
(gdb) stepi /* subq $8,%rsp */
0x00000000004011f4 in byte_as_hex ()
(gdb) print /x $r11b
$5 = 0x0
(gdb) print /x $r11
$6 = 0x246
(gdb) print /x $rdi
$7 = 0x48
(gdb) print /x $dil
$8 = 0x48
(gdb) stepi /* movb %dil,%r11b */
0x00000000004011f7 in byte_as_hex ()
(gdb) print /x $r11b
$9 = 0x0
(gdb) print /x $r11
$10 = 0x248
(gdb) print /x $rdi
$11 = 0x48
(gdb) print /x $dil
$12 = 0x48
(gdb) print /x $r11d
$13 = 0x248
(gdb) print /x $r11w
$14 = 0x248
(gdb) print /x $r11b
$15 = 0x0
我很困惑,因为我专门尝试将%dil移到%r11b,但是我仍然无法设置字节。谁能向我解释为什么会这样?谢谢!
解决方法
这里有多个问题:
- (报告为GDB bug。)使用显式格式说明符打印时,未定义的convenience variable(以
$
开头的GDB局部变量)显示为0,而不是默认void
,未指定格式时显示:
$ gdb /bin/true
Reading symbols from /bin/true...
(gdb) p $asdf
$1 = void <------ undefined,OK
(gdb) p/x $asdf
$2 = 0x0 <------ the problem
(gdb) set $asdf=4345
(gdb) p $asdf
$3 = 4345
(gdb) p/x $asdf
$4 = 0x10f9
(gdb)
- 寄存器值与便捷变量的值具有相同的语法。因此,当您错误输入寄存器名称时,例如使用
r11b
而不是GDB的r11l
,则指的是(n个未定义)便捷变量。而且,即使您只是在不正确的情况下使用正确的名称(例如R11L
),也会遇到这种情况。 - GDB对x86(_64)寄存器使用其自己的名称集。有时它们与给定的名称不同,例如英特尔手册中的内容(例如
ftag
,而不是英特尔的FTW
)。无论如何,通用寄存器的最低字节在GDB中具有以下名称:
al
cl
dl
bl
spl
bpl
sil
dil
r8l
...
r15l
没有别名,例如r11b
代表r11l
,因此必须使用正确的名称。