12

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

此外,是否有任何其他指令,例如jmpand jmpq,但具有 64 位地址位移?如何在 Intel 或 AMD 的手册中找到说明(我搜索过jmpq但一无所获)?


当我搜索时,它似乎被称为 RIP 相对寻址。似乎并非所有指令都这样做。是否有 64 位相对寻址?如果是间接跳转,那么 64 位绝对地址应该在寄存器或内存中,对吧?

4

3 回答 3

8

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

OP 询问为什么没有 64 位偏移的相对跳转。我不能代表英特尔的设计人员,但很明显,这条指令根本不会很有用,尤其是在 32 位相对 jmp 可用的情况下。唯一需要它的时候是您的程序大小超过 2 GB,因此 32 位相对 jmp 无法从其中的任何点到达所有它。最近看到过任何 2Gb 的目标文件吗?因此,此类指令的明显效用似乎非常小。

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

为了完整起见,x86(许多口味)也有非常短的 jmp 相对指令(8 位有符号偏移)。在实践中,即使是 32 位 jmp 相关指令也很少需要,特别是如果您有一个可以重新排列代码块的良好代码生成器。出于同样的原因,英特尔可能会忽略这些。我怀疑它们的效用稍微高到足以证明晶体管的合理性。

“大文字操作数”的问题在许多架构中以有趣的方式出现。如果您检查代码中文字值的分布,您会发现较小的值(0,1,ascii 字符代码)占相当大的百分比;几乎所有其他东西都是内存地址。所以你在程序中不需要“大字面值”,但你必须以某种方式处理内存地址。Sparc 芯片以“将文字值低加载到寄存器”(意思是“小常量”)而著称,而较少使用的“加载文字值高”(填充寄存器中的高位)用作第二条指令以生成大常量,并且使用较少。这使代码保持较小,除非您需要一个大常数;

于 2014-11-16T13:08:21.783 回答
7

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

E9 cd -> JMP rel32 -> Jump near, relative, RIP = RIP + 32 位位移符号扩展为 64 位

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

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

引用自JMP的Intel 指令集手册条目

于 2014-11-16T08:55:14.287 回答
2

以下适用于 64 位模式。

JMP 可以直接或间接完成。

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

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

您的汇编程序将尽可能使用短跳转,因为它们只需要两个字节。near但是在 NASM 中,您可以使用关键字来强制进行近跳,例如

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

64 位寻址模式有:RIP 相对、32 位绝对、64 位绝对和相对于基指针。该JMP指令可以使用除 64 位绝对值之外的所有这些。间接跳转使用 Opcode 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

然而,在 OSX 上,32 位绝对寻址是不可能的,因为图像基数大于 2^32

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

mov rax, [qword a]
于 2014-11-17T10:56:22.767 回答