非常大的地址被复制为负值

Posted

技术标签:

【中文标题】非常大的地址被复制为负值【英文标题】:Very large address copied as negative value 【发布时间】:2017-08-15 09:56:07 【问题描述】:

我正在浏览一个对应于 C 程序的二进制文件。 我有一个非常大的地址存储在%eax。 当尝试通过gdb 查看该值时,它会打印一个负值(原因here)。

现在当执行mov %eax, 0x4c(%esp) 时,0x4c(%esp) 中的结果值有时为正有时为负。此效果cmp $0, 0x4c(%esp) 声明如下!

有人可以解释一下这种行为吗?

如果这有帮助:core: ELF 32-bit LSB core file Intel 80386, version 1 (SYSV), SVR4-style

【问题讨论】:

您实际上是如何在gdb 中显示这些值的? 您复制的位序列始终相同,但解释可能不同,可能 gdb 默认为二进制补码 32 位值 我使用print %eax显示%eax 0x4c(%esp)的内容如何显示? FWIW,它不影响cmp 指令。它只是设置不同的标志,由您来解释它们,例如在条件跳转中使用jajb(用于无符号比较)或jgjl(用于有符号比较),或使用setasetb等。 【参考方案1】:

寄存器没有标志;他们持有比特。如何解释它们取决于您。堆栈也是如此:它保存位,如何解释它们取决于您。如果将值从寄存器移动到堆栈,则会复制这些位。如果你像解释寄存器中的位一样解释堆栈上的位,你会得到相同的值。

请注意,有 指令将这些位解释为值 - 乘法、比较等。但MOV 不是其中之一。

【讨论】:

加1用于解释数据之间的差异以及对此类数据的解释 但是,当0x4c(%esp) 用于cmp 时,我得到不同的结果。为什么会这样? @JithinPavithran:我不知道这意味着什么。猜测:你的意思是紧接着,cmp %eax, 0x4c(%esp; jne ... 跳转?我不知道为什么这个序列会出现在编译的 C 代码中。 不,不是马上。在 mov 之后,有一个 jmp(无条件),然后是 cmp,然后是 jmp,具体取决于结果。 (代码有一个heisenbug,我正在尝试深入理解) @JithinPavithran:mov %eax,(...)在内存中存储的值是32位值。您可以按照自己的意愿解释它,它仍然是相同的值(在位级别)。无论您对 "cmp 和代码流" 有什么困惑,一定有其他原因,cmp $0,... 针对地址有点荒谬,因为通常测试地址为零的唯一充分理由是捕获nullptr 值,因此符号位的值也无关紧要(然后使用jz(je)/jnz(jne) 之一)。很难说你在那里看到了什么,因为你没有发布它。【参考方案2】:

您复制的位序列始终相同,但解释可能不同,可能 gdb 默认为二进制补码 32 位值

如何更改 gdb 输出格式:

https://sourceware.org/gdb/onlinedocs/gdb/Output-Formats.html

【讨论】:

【参考方案3】:

如果在 GDB 中使用以下命令:

print $esp-0x4c

您实际上显示的是 地址 -0x4c(%esp)(即:寄存器 esp 的值加上偏移量 -0x4c)并且 不是 位于此地址的内容。为了显示-0x4c(%esp)内容(即:查看此地址的实际内容),您可以使用x 命令:

x $esp-0x4c

【讨论】:

以上是关于非常大的地址被复制为负值的主要内容,如果未能解决你的问题,请参考以下文章

以独立于类型的变量属性为条件替换所有负值

为啥堆栈会增长到较低的地址? [复制]

margin值为负值

GDB无法插入断点,无法访问地址XXX处的内存? [复制]

[转]OpenGL 使用 PBO 高速复制屏幕图像到内存或者纹理中

虚拟存储器