我一直在读一些汇编代码,我已经开始看到的是调用指令计数器相对程序实际上是。
但是,每当我使用Visual Studio或WinDBG的调试,它总是说叫0XFFFFFF ......这对我来说意味着它在说我要跳转到该地址。
谁是谁非?是Visual Studio中隐藏指令编码的复杂性,只是说哦,是这样的计划意味着什么,那就是调试器知道这是一个PC相关的指令,并且因为它知道个人电脑,它只是和做数学的吗?
非常困惑。
如果你正在拆卸那些尚未关联.o
目标文件,调出地址将只是通过链接填写的占位符。
您可以使用objdump -drwc -Mintel
从.o
表明搬迁类型+符号的名称(-r
的选择是关键。或者-R
一个已经连接的共享库。)
这是对用户更有用,显示跳转目标的实际地址,而不是拆解为jcc eip-1234H
什么的。目标文件有一个默认加载地址,所以拆装具有在每一个指令eip
的值,这通常出现在反汇编输出。
例如在一些汇编代码我写的(在这里我使用了它成目标文件的符号名称,因此该循环分支目标实际上是可见的反汇编):
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
)0x100 - 0xD0 = 0x30
,这是对最不显著字节的值2的补位移。
在你的问题,你在谈论呼叫地址为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>
...
注意call
说明如何有自己的相对位移= 0。所以之前的连接器在实际的相对价值已经开槽,它们编码与指令的目标的call
通话之后。 (即RIP = RIP+0
)。该call bf
之后紧接着开始于0xbf
从节开始的指令。另call
有不同的目标地址,因为它是在文件在不同的地方。 (GCC把main
在自己的部分:.text.startup
)。
所以,如果你想什么实际被称为意义上说,看一个链接的可执行文件,或让有着眼于目标文件符号的符号名插槽,用于呼叫目标,而不是显示他们与零位移呼叫的反汇编。
相对跳转到本地符号链接之前已得到解决:
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
请注意,在相对跳转到一个符号相同的文件完全相同的指令编码,即使该文件没有基地址,所以拆装只是将其视为零。
请参见英特尔的指令编码参考手册。链接在https://stackoverflow.com/tags/x86/info。即使是在64位模式下,call
仅支持32位符号扩展相对偏移。 64位地址,支持为绝对的。 (在32位模式,16位相对地址被支撑,与操作数大小前缀,我想节省一个指令字节。)