【问题标题】:Unable to set the lowest byte in a register x86-64? [duplicate]无法在寄存器 x86-64 中设置最低字节? [复制]
【发布时间】:2021-01-14 19:15:34
【问题描述】:

我正在 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

我很困惑,因为我专门尝试将 movb 从 %dil 移动到 %r11b,但我仍然无法设置字节。谁能向我解释为什么会这样?谢谢!

【问题讨论】:

  • 您能否展示每个步骤的说明,以便更容易理解假设发生的事情?这似乎是损坏/错误的 GDB 行为。
  • 我想知道GDB是否会与%r11l这样的reg名称不同?字节寄存器名称有两种不同的约定:r11br11l。我忘了是谁发明的。 GDB 似乎确实将r11b 识别为寄存器名称,所以不应该这样,但您永远不知道可能存在错误。
  • 我的函数的开头行是byte_as_hex: subq $8, %rsp movb %dil, %r11b shr $4, %r11b 在尝试 movb 之前我唯一做的就是调整堆栈指针,所以我不确定会出现什么问题。
  • 当然,这很好,但是edit 你的问题是要为每个stepi 执行哪条指令,例如作为“注释”或 GDB 输出中的额外行。您的指令几乎可以肯定执行得很好,而 GDB 只是无法正常工作。 (GDB 已经不是第一次出现错误了。你有什么版本的 GDB?)
  • 我刚刚检查了r11l 而不是r11b,结果发现这是存储值的位置。我仍然不太确定发生了什么,但至少我知道该值存储在某个地方。我的 gdb 版本是 Fedora 8.3.50.20190824-30.fc31。我现在将编辑我的问题 - 这是我的第一个问题,所以我仍在学习如何在这里回复。感谢您的帮助!

标签: gdb x86-64 cpu-registers


【解决方案1】:

这里有多个问题:

  1. (报告为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) 
  1. 寄存器值的语法与便利变量的值相同。因此,当您弄错寄存器的名称时,例如使用r11b 而不是GDB 的r11l,你指的是一个(n undefined) 便利变量。此外,即使您只是在不正确的情况下使用正确的名称,例如R11L,您也会遇到这种情况。
  2. GDB 使用自己的 x86(_64) 寄存器名称集。有时它们与给出的名称不同,例如在英特尔手册中(例如 ftag 而不是英特尔的 FTW)。无论如何,通用寄存器的最低字节在 GDB 中具有以下名称:
al
cl
dl
bl
spl
bpl
sil
dil
r8l
...
r15l

它们没有别名,例如r11b 对应 r11l,所以必须使用正确的名称。

【讨论】:

  • Why does Apple use R8l for the byte registers instead of R8b? - 这些名称不是 GDB 独有的;我认为它们起源于 AMD64 中的 AMD,它早于 Intel IA-32e。但是,是的,英特尔的手册只提到了 r8..r15 的 r11b 名称。另见What are the names of the new X86_64 processors registers?
  • @PeterCordes 哦,现在说得通了。我很“幸运”选择了RSP 而不是R8-R15 来测试低字节命名:) (请注意,这是相反的:它是AMD 使用*B 作为编号注册,根据您的第一个链接)
  • 哎呀,谢谢,是的,我自己总是使用r8b 样式,忘记了哪个供应商在他们的手册中使用了哪个。
  • How do you access low-byte registers for r8-r15 from gdb in x86-64? 是针对第 1 点中的 GDB 错误的规范问答。显然,未来的 GDB 版本应该打印 void 而不是 0 即使使用格式。我认为这个问答实际上是重复的,尽管您的答案有更多信息,例如大写字母和其他寄存器名称,例如 ftag
猜你喜欢
  • 2021-07-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-13
  • 2019-04-21
  • 2016-09-24
  • 2011-04-27
  • 1970-01-01
相关资源
最近更新 更多