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