为什么x86-64的jmpq只需要32位长度的地址?

时间:2014-11-16 08:31:06

标签: assembly x86-64 computer-architecture

当我使用objdump -D来反汇编二进制文件时,jmpq的典型代码就像e9 7f fe ff ff,用于表示负偏移量。但是,x86-64的地址是64(48)位(据我所知),那么这个32位地址7f fe ff ff如何表示64位绝对地址的负偏移?

此外,还有其他指令,例如jmpjmpq,但是有64位地址位移吗?如何在英特尔或AMD手册中找到相关说明(我搜索了jmpq但未找到任何内容)?


当我搜索时,它似乎被称为RIP相对寻址。似乎并非所有说明都这样做。是否有64位相对寻址?如果是间接跳转,则64位绝对地址将在寄存器或存储器中,对吗?

3 个答案:

答案 0 :(得分:7)

正如其他人所说," jmp亲戚" x86-64的指令仅限于32位有符号位移,用作相对于程序计数器的相对偏移量。

OP询问为什么没有64位偏移的相对跳转。我无法代表英特尔的设计人员,但很明显,这条指令根本不是很有用,特别是对于32位相对jmp的可用性。唯一需要的是当你的程序大小超过2千兆字节时,因此32位相对jmp无法从其中的任何一点到达所有这些。最近看过任何2Gb的目标文件?因此,这些指令的明显效用似乎很小。

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

为了完成,x86(许多版本)也有非常短的jmp相关指令(8位带符号偏移)。实际上,甚至很少需要32位jmp相关指令,特别是如果你有一个可以重新排列代码块的良好代码生成器。出于同样的原因,英特尔可能会将这些问题排除在外;我怀疑它们的效用是否足以证明晶体管的合理性。

"大文字操作数"在许多架构中以有趣的方式出现。如果你检查代码中文字值的分布,你会发现小值(0,1,ascii字符代码)覆盖了相当不错的百分比;几乎其他一切都是内存地址。所以你有点不需要"大文字价值"在程序中但你必须以某种方式处理内存地址。 Sparc芯片的着名之处是将字面值加载到寄存器中#34; (意思是"小常数")和较少使用的"加载字面值高" (用于填充寄存器中的高位)用作第二条指令以产生大常数,并且使用频率较低。除非你需要一个大常数,否则这会使代码保持较小;小代码意味着更高的有效指令获取率并且有助于提高性能。

答案 1 :(得分:5)

64位模式下的E9操作码将32位符号位移符号扩展为64位:

  

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

FF操作码可用于跳转到64位地址:

  

FF / 4 - > JMP r / m64 - >跳转,绝对间接,RIP =寄存器或存储器的64位偏移

摘自Intel instruction set manual entry for JMP

答案 2 :(得分: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]