2014-11-16 20 views
10

正如我使用objdump -D拆卸二元,的jmpq典型的代码是这样e9 7f fe ff ff,其用于表示负偏移。然而,x86-64的地址是64(48)位(据我所知),那么32位地址7f fe ff ff如何代表64位绝对地址的负偏移?为什么x86-64的jmpq只需要32位长度的地址?

此外,有没有其他的指令,如jmpjmpq,但有64位地址位移?我如何在英特尔或AMD手册中找到说明(我搜索了jmpq,但什么也没找到)?


当我搜索时,它似乎被称为RIP相对寻址。看来并不是所有的指令都这样做。是否有64位相对寻址?如果是间接跳转,则64位绝对地址将位于寄存器或内存中,对吗?

+0

跳转指令具有32位偏移版本。如果偏移量符合32位,则可以使用32位偏移版本并保存几个字节(通过64位绝对地址或其他)。 –

+0

感谢您的评论。 64位偏移版本的指令是什么? – WindChaser

+1

我不相信有一个64位的偏移版本。 –

回答

7

正如其他人指出,对于X86-64“相对的jmp”指令被限制在32位带符号的位移,作为相对于相对于程序计数器的偏移。

OP问为什么有一个64位无相对跳转偏移。我不能为英特尔的设计人员说话,但看起来很明显,这条指令不会很有用,特别是在32位相对jmp的可用性方面。唯一需要的是当你的程序的大小为2G时,以便32位相对jmp无法从其中的任何一点到达它。最近看到任何2Gb目标文件?所以这种说明的显然效用似乎很小。

大多数时候,程序得到真正的大,他们一开始就被分解成可以以不同的速度发展更易于管理的要素。 (DLL是这方面的一个例子)。这些元素之间的接口是通过更加神秘的手段(跳转向量等)完成的,以确保接口在进化过程中保持不变。一个非常长的jmp亲戚可以用来从应用程序到达另一个模块的入口点,但将绝对地址加载到寄存器并进行寄存器间接调用的实际成本足够小,在实践中它足够小值得优化。现代的CPU设计都是关于优化晶体管放置位置以最大限度地提高性能。

只要是完整的,在x86(许多种)有很短的JMP相对指令(8位有符号偏移量),太。实际上,即使是32位jmp相对指令也很少需要,特别是如果你有一个好的代码生成器可以重新安排代码块。英特尔可能会出于同样的原因而放弃这些。我怀疑它们的效用足够高以证明晶体管的合理性。

“大字面操作数”的问题在许多架构中以有趣的方式出现。如果您检查代码中文字值的分布,您会发现小值(0,1,ascii字符代码)涵盖了相当不错的百分比;几乎所有的东西都是内存地址。所以你在程序中不需要“大的字面值”,但你必须以某种方式处理内存地址。 Sparc芯片着名的有“将字面值低加载到寄存器中”(意思是“小常量”),并且较少使用“加载字面值高”(填充寄存器中的高位)作为第二条指令来产生大常数,使用较少。这使代码变得很小,除非你需要一个很大的常量;小代码意味着更高的指令取指速率,并有助于提高性能。

+0

MIPS也有'lui'来加载高16位的部分。下半部分可以用'ori'或'addiu'加载。 ARM可以加载8位立即数,即使旋转数为偶数,但新版本也可以单独加载高低16位部分 –

5

在64位模式的E9操作码取扩展到64位32位的符号位移符号:

E9 CD - > JMP rel32 - >跳转附近,相对的,RIP = RIP + 32位 位移符号扩展到64位

的FF操作码可以用来跳到一个64位地址:

FF/4 - > JMP R/M64 - >跳转附近,绝对间接RIP = 64位的fset从寄存器或内存

行情取自Intel instruction set manual entry for JMP

+2

“/ 4”是什么意思?如果第一位是1(第一个字节的范围是从“8”到“f”,偏移量会自动扩展,如“ff ff ff ff 12 34 56”)? – WindChaser

+0

您可以参考英特尔手册,但请您为那些不熟悉手册术语的人士解释'cd'和'/ 4'的含义。 –

+0

/4的意思是“操作码扩展”。看到我的帖子在这里:https://stackoverflow.com/questions/26824941/opcode-ff-4-which-value-is-give-to-eip/26830328#26830328 – zx485

1

以下内容适用于64位模式。

JMP可以直接或间接完成。

直接跳转是相对于指令指针RIP。有两种类型的直接跳转:短和近。

  • 短跳转使用操作码EB,后跟8位有符号位移,因此是RIP –128 to +127字节。
  • 接近跳转使用操作码E9,后跟32位有符号位移,因此为RIP -2147483648 to +2147483647

当汇编程序可以使用短跳转,因为它们只需要两个字节。但是在NASM中,您可以使用near关键字(例如,

test: 
    jmp test   ; eb fb 
    jmp near test ; e9 f6 ff ff ff 

64位寻址模式是:RIP相对,绝对值为32位,绝对值为64位,相对于基址指针。 JMP指令可以使用除64位绝对值之外的所有指令。间接跳转使用操作码FF。使用NASM语法的一些示例:

jmp [a]    ;ff 24 25 00 00 00 00 - 32-bit absolute 
jmp [rel a]   ;ff 25 e7 ff ff ff - RIP + 32-bit displacement 
jmp [rdi]    ;ff 27    - base pointer 
jmp [rdi +4*rsi + a] ;ff a4 b7 00 00 00 00 - base pointer +4*index + displacement 

On OSX, however, 32-bit absolute addressing is not possible because the image base is greater than 2^32

唯一可以使用64位绝对寻址的指令是mov,然后源或目标必须是AL, AX, EAX or RAX。例如NASM

mov rax, [qword a] 
+0

'jmp [rdi]'是跳转到存储在8字节中的64位“绝对地址”内存地址,这是寄存器'rdi'的值,对吗? – WindChaser

+0

@WindChaser,没错。 –

+0

@WindChaser证明你也可以做'jump rdi'。 –

相关问题