如何解决初学者汇编语言C-减法查找添加的CPU
000000000040050f <oranges>:
...
40053f: 89 cf mov %eax,%edi
400541: e8 a7 ff ff ff callq 4004ed<apples>
400546: 0f af c3 imul %ebx,%eax
...
桔子两次叫苹果。苹果从0x00000000004004ed开始。但是,在机器代码中第二次调用苹果时,函数调用中的数字为0xFFFFFFA7
我需要弄清楚CPU加上0xFFFFFFA7多少个数字才能获得apple()0x00000000004004ed的地址
本质上,我需要做一个减法问题。我如何减去0xFFFFFFA7和0x00000000004004ed以查找添加到CPU的内容?进行转换以使其有意义的正确方法是什么?
解决方法
call rel32
相对于调用指令的 end 。
小尾数rel32是2的补码整数,因此0xFFFFFFA7
是一个小的负数。 0xFFFFFFA7 - 2^32 = -89
(十进制),即向后跳89个字节。
您已将4字节的Little-endian rel32位移正确解码为二进制整数,但没有将其重新解释为有符号2的补码。 (它不会被减去,而是被添加。这就是为什么它是负数的原因。)
e8 a7 ff ff ff callq rel32
在地址0x400546
(下一条指令的开始)处结束,因此在执行期间将是RIP。执行后的新RIP 将
0x400546 - 89 = 0x4004ed
,与打印的objdump -d
相同。
objdump当然会以与我相同的方式计算该地址。
(尽管objdump可能在添加到64位代码地址之前将位移符号扩展为64位。计算出位模式0xFFFFFFA7表示-89
十进制作为2的补码整数基本上就像读取那些将4个字节放入int32_t
中并将其添加到uint64_t
中。(https://www.felixcloutier.com/x86/call的英特尔手册还将该过程描述为对rel32进行符号扩展以进行二进制加法,但这只是另一种表达方式相同的数学运算以更机器友好的方式显示,除了符号扩展以外,所有这些都在任何模式下对直接相对call
和jmp
指令都有效,jmp rel8
使用8位2的补码分支位移。)
半相关:How does $ work in NASM,exactly?的示例是将call
手动编码为给定的目标地址。
一目了然[...]
您正在以64位模式使用x86。
64位模式具有一种特殊的寻址模式,称为“ RIP相对”寻址。
编辑:尽管偏移量的计算方法相同,但从Peter看来,寻址方式实际上是call rel32
,而不是RIP relative
。
%rip
寄存器是程序计数器。每条指令都会改变。
因此,当使用此模式时,偏移量是目标地址(例如apples
)与当前指令的地址(与指令的%rip
中的地址)之间的距离。
由于您有两条 callq
指令(根据您的描述,但代码中未显示 ),它们每个都有不同的地址,因此偏移量到apples
的地方会有所不同。
这允许“位置无关代码”。它还允许使用偏移量,该偏移量通常小于完整的64位绝对地址。这就是callq
指令(操作码+偏移量/地址)只有5个字节(相对于9个字节)的原因,因为偏移量是32位有符号数。
更新:
我认为可能涉及撕裂。在这种情况下,您能帮助我解释如何找到rip%或如何解决该特定问题吗?
您可以执行以下操作:objdump --disassemble myprogram
进行反汇编并查看反汇编。或者,您可以使用gdb
命令通过调试器(例如disassemble
)进行此操作。
在您的列表中,callq
的地址为0x400541,并且[您提到] apples
的地址为0x4004ed。
因此,与callq
指令的 start 的偏移是:
-84 FFFFFFFFFFFFFFAC
但是,指令的偏移量为:
0xFFFFFFFA7
(请记住,反汇编只是输出字节,因此我们必须手动反转字节,因为偏移量是little-endian)。
因此,这意味着使用的%rip
值不是指令的 start ,而是 end 指令。
因此,我们必须按照指令的长度[5]来调整偏移量,以获得0xFFFFFFA7。也就是说,%rip
指令[使用的callq
值是指令的地址+5。在伪代码中,计算为:
offset = apples - (&callq + 5)
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。