在 gdb 中翻转字节顺序?

Flipping endianness in gdb?

gdb 中,我很困惑为什么有时它从左到右打印字节,有时从右到左打印字节。这是一个示例,其中 运行 之间没有指令:

>>> x/4b $rbp-4
0x7fffffffe43c: 0x04    0x00    0x03    0x16
>>> x/2h $rbp-4
0x7fffffffe43c: 0x0004  0x1603

为什么要在 gdb 中完成?我认为它总是将它们打印为:

04 00 03 16

GDB 使用目标机器的本机字节序(默认情况下1)将您请求的大小的块解释为整数,块之间的地址从左到右递增。 x86 是 little-endian.

在块中,04 00 被解释为 16 位 little-endian 整数 0x0004。例如,这使得 GDB 以您期望的方式转储 short 的数组。您向 GDB 询问 16 位整数块,因此它会按照您的指示进行操作,使用标准 place-value 表示法显示整数 value,最左边的数字最重要。它不会尝试单独打印字节,因为您要求 half-words.

如果你想要内存顺序的字节,使用b。这就是它的用途。


脚注 1:

您可以更改 GDB 的字节顺序设置; show endian 显示当前设置。但是,set endian big 会导致问题,破坏寄存器值。例如当停在 _start 时:

(gdb) p /x $rsp
 = 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
 = 0xd0e6ffffff7f0000   # this is obviously broken, byte-reversed

寄存器没有字节顺序,在将它们的值扩展为另一个命令的地址时翻转它们完全被破坏了。


相关的不完全重复:

  • Is GDB interpreting the memory address correctly?

Peter 给出了正确且被接受的答案,但我也会在这里做一个非常简短的解释,这有助于我的理解。


假设我们要将数字 22(十六进制的 0x16)作为 two-byte 值存储在内存中。

因为 x86 是 little-endian(将最高有效字节存储在最高内存地址),我们将这样存储它:

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

现在,如果我们按内存地址的递增顺序打印它 byte-by-byte,它显然看起来像这样:

0xAA1:  0x16 0x00                (2 bytes, byte by byte in increasing memory address)

但是如果我们想要返回 22 的原始值,我们需要将 two-byte 值解释为 little-endian 所以它 returns 正确的值:

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