汇编 - x86调用指令和内存地址?

时间:2015-08-04 20:38:12

标签: assembly linker x86 nasm masm

我一直在阅读一些汇编代码,我开始看到调用指令实际上是程序计数器相对的。

然而,每当我使用visual studio或windbg进行调试时,它总是会调用0xFFFFFF ...这对我来说意味着它会说我要跳转到那个地址。

谁是对的? Visual Studio是否隐藏了指令编码的复杂性,只是说这就是程序的意思,那就是调试器知道它是一个与pc相关的指令,并且因为它知道pc,它只是为你做数学运算? / p>

非常困惑。

1 个答案:

答案 0 :(得分:4)

如果您正在反汇编尚未链接的.o目标文件,则调用地址将只是一个占位符,由链接器填充。

您可以使用objdump -drwc -Mintel 显示来自.o 的重定位类型+符号名称(-r选项是密钥。或-R已经链接的共享库。)

用户显示跳转目标的实际地址更有用,而不是将其反汇编为jcc eip-1234H或其他东西。对象文件具有默认加载地址,因此反汇编程序在每条指令处都有eip的值,这通常出现在反汇编输出中。

e.g。在我编写的一些asm代码中(我使用符号名称将其放入目标文件中,因此循环分支目标实际上对反汇编程序可见):

objdump -M intel  -d rs-asmbench:
...
00000000004020a0 <.loop>:
  4020a0:       0f b6 c2                movzx  eax,dl
  4020a3:       0f b6 de                movzx  ebx,dh
   ...
  402166:       49 83 c3 10             add    r11,0x10
  40216a:       0f 85 30 ff ff ff       jne    4020a0 <.loop>

0000000000402170 <.last8>:
  402170:       0f b6 c2                movzx  eax,dl

请注意,jne指令的编码是带符号的小端32位移位,-0xD0字节。 (跳转后,跳转将其位移添加到e/rip的值。跳转指令本身长度为6个字节,因此位移必须为-0xD0,而不仅仅是-0xCA。){{ 1}},这是2的补码位移的最低有效字节的值。

在你的问题中,你所说的是0x100 - 0xD0 = 0x30的呼叫地址,除非那只是一个占位符,或者你认为位移中的非0xFFFF...字节属于操作码。

在链接之前,对外部符号的引用如下所示:

0xFF

请注意objdump -M intel -d main.o ... a5: 31 f6 xor esi,esi a7: e8 00 00 00 00 call ac <main+0xac> ac: 4c 63 e0 movsxd r12,eax af: ba 00 00 00 00 mov edx,0x0 b4: 48 89 de mov rsi,rbx b7: 44 89 f7 mov edi,r14d ba: e8 00 00 00 00 call bf <main+0xbf> bf: 83 f8 ff cmp eax,0xffffffff c2: 75 cc jne 90 <main+0x90> ... 指令的相对位移= 0。因此,在链接器插入实际相对值之前,它们会在调用后立即编写带有指令目标的call。 (即call)。 RIP = RIP+0后面会紧跟一条从该部分开头call bf开始的指令。另一个0xbf具有不同的目标地址,因为它位于文件中的不同位置。 (gcc将call放在其自己的部分中:main)。

因此,如果您想了解实际调用的内容,请查看链接的可执行文件,或者获取一个反汇编程序,该反汇编程序查看目标文件符号以插入调用目标的符号名称,而不是将其显示为调用零位移。

在链接之前已经解析了对本地符号的相对跳转:

.text.startup

注意,相同的指令编码相对跳转到同一文件中的符号,即使文件没有基地址,因此反汇编程序只是将其视为零。

有关指令编码,请参阅英特尔参考手册。 https://stackoverflow.com/tags/x86/info的链接。即使在64位模式下,objdump -Mintel -d asm-pinsrw.o: 0000000000000040 <.loop>: 40: 0f b6 c2 movzx eax,dl 43: 0f b6 de movzx ebx,dh ... 106: 49 83 c3 10 add r11,0x10 10a: 0f 85 30 ff ff ff jne 40 <.loop> 0000000000000110 <.last8>: 110: 0f b6 c2 movzx eax,dl 也只支持32位符号扩展相对偏移。支持64位地址作为绝对地址。 (在32位模式下,支持16位相对地址,带有操作数大小前缀,我想保存一个指令字节。)