在gdb中反转字节序?

4
gdb 中,有时会以左向右和右向左的方式打印字节,这让我感到有些困惑。以下是一个示例,在其中没有运行任何指令:
>>> x/4b $rbp-4
0x7fffffffe43c: 0x04    0x00    0x03    0x16
>>> x/2h $rbp-4
0x7fffffffe43c: 0x0004  0x1603

为什么要在gdb中这样做?我认为它应该总是打印它们,如下所示:
04 00 03 16
2个回答

3
默认情况下,GDB使用目标机器的本地字节顺序(小端)来解释你请求大小的数据块作为整数,地址在块之间从左到右递增。x86 是小端格式。

在一个数据块中,当被解释为 16 位小端整数时,“04 00” 就是 “0x0004”。这使得 GDB 按照你的期望显示了一个 short 类型数组的转储,例如。你请求 GDB 显示 16 位整数块,所以它展示了整数值,并使用标准阶位表示法,最左边的数字是最高有效位。它没有尝试分别打印字节,因为你请求了半字。

如果你想要按内存顺序显示字节,请使用 b 命令。那就是它的用途。

注1:
你可以更改 GDB 的字节顺序设置;show endian 显示当前设置。然而,set endian big 会导致问题,损坏寄存器值。例如,当停在 _start 处时:
(gdb) p /x $rsp
$1 = 0x7fffffffe6d0       # this is normal for x86-64
(gdb) set endian big
The target is assumed to be big endian
(gdb) x /16xw $rsp
0xd0e6ffffff7f0000:     Cannot access memory at address 0xd0e6ffffff7f0000
(gdb) p /x $rsp
$2 = 0xd0e6ffffff7f0000   # this is obviously broken, byte-reversed

寄存器没有字节序,当将其作为另一个命令的地址进行扩展时翻转它们只会导致完全失败。


相关但不完全相同的问题:


我明白了,这很棘手!因此,在大端存储中,它以 00 04 的形式存储,当需要正确解释2个字节时,它不需要再次进行“翻转”吗? - samuelbrody1249
1
@samuelbrody1249:我不会这么说。 00 04 的大端解释是 0x0004。对于 GDB 在小端主机上运行时获取该值,它必须在将其提供给其正常的十六进制打印函数之前对该值进行字节交换。GDB 打印你告诉它的任何宽度的整数,而不是单独的字节。 - Peter Cordes
谢谢。我已经自己添加了一个答案,基本上只是把我学到的东西打出来。如果您想检查一下我的答案是否有问题,请告诉我。 - samuelbrody1249

1

Peter已经给出了正确和被接受的答案,但我也会在这里简要解释一下,这有助于我的理解。


假设我们想要将数字22(十六进制表示为0x16)以两个字节的形式存储在内存中。

由于x86是小端存储(将最高位字节存储在最高的内存地址),我们将按照以下方式存储它:

0xAA1: 0x16                       (LSB)
0xAA2: 0x00                       (MSB)

现在,如果我们按照内存地址递增的顺序逐字节打印它,显然会像这样:
0xAA1:  0x16 0x00                (2 bytes, byte by byte in increasing memory address)

但是如果我们想要回到原始值22,我们需要将这个两字节的值解释为小端序,这样才能返回正确的值:

0xAA1:  0x0016 # 22 in decimal  (bytes flipped back to interpret it properly in program  

1
说字节被“翻转回来”对我来说仍然听起来像是错误的心理模型。0x0016的十六进制数字按位值顺序排列,始终以最高位为先。将这2个字节翻转以将其解释为值为22的16位整数,即0x16,是在打印该值作为十六进制之前发生的。(请注意,GDB内部必须特别注意这一点,因为它可以进行远程调试。例如,它可能在小端x86-64主机上运行并调试大端MIPS目标。) - Peter Cordes
1
是的,我们传统的最高有效数字优先位值系统用于使用阿拉伯数字编写数字,恰好与内存中字节的顺序相反。因此,如果您正在使用x86上的SIMD(例如像这样)编写int-> ASCII十六进制字符串函数,则确实需要在其中进行字节反转。但是,一次一个数字,从整数寄存器中的值开始,您可以将顶部4位旋转到底部,而不考虑内存的字节顺序。将其加载为整数将已经将二进制值放入您可以移位/旋转的寄存器中。 - Peter Cordes
@PeterCordes 感谢您的反馈。哇,那个问题/答案很深奥,超出了我目前的能力和理解范围,但是我会仔细阅读并尝试吸收其中的概念。 - samuelbrody1249

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接