x64:如何做一个相对jmp *%rax?

时间:2015-11-02 01:49:20

标签: assembly 64-bit x86-64 att

我想将64位相对跳转编码为x64汇编中存储在%rax中的地址。 AFAIK,没有这个操作码,所以我手动计算相对地址的相应绝对地址,然后我绝对跳转到绝对地址:

# destination address, relative to end of jmp instruction, is stored in %rax
00007ffff7ff6020: 0x0000488d1505000000   lea 0x5(%rip),%rdx # load %rip+5 (rip + size of add and jmpq) into %rdx
00007ffff7ff6027: 0x0000000000004801d0   add %rdx,%rax # calculate absolute address based on %rdx (behind jmpq) and %rax (the relative address)
00007ffff7ff602a: 0x00000000000000ffe0   jmpq *%rax # do an absolute jump to absolute address

但这对我来说看起来不那么复杂。有更少的指示是否有更好的方法?或者是否还有其他原因可以避免64位相对跳跃?

2 个答案:

答案 0 :(得分:1)

所有相对跳转指令都将指令中的跳转距离编码为立即(=整数常量)操作数。存在相对跳跃(和调用)以将执行从代码中的一个已知位置转移到正常执行过程中的另一个,例如,执行条件跳转(想想许多高级编程语言中的 if 运算符),无条件跳转(想想BASIC或C / C ++中的 goto 或无条件跳转隐藏在 if for 语句中)或调用子例程。为此目的(这是一个非常重要的目的)就足够了。

如果需要访问与RIP相关的数据,可以这样做,因为在64位模式下,有一种方法可以将内存操作数编码为RIP相关(在32位模式下没有这样的编码)。这有助于生成与位置无关的代码,并有助于减少将所有代码和静态数据装入2GB内存的程序中完整64位地址的开销。

其他xIP相关用途不太常见。 计算跳转(除了从子程序返回之外)也是如此。计算跳转是实现诸如 switch 语句之类的常见方法,例如在C / C ++,Java。有几种方法可以实现切换,但最明显的一种方法是使用一个数组/地址表来跳转到哪里,然后只使用一个整数索引来检索它对应的地址。然后你可以使用间接跳转来跳转,例如jmp rax(或AT& T语法中的任何内容)。你可以从数组/表中获取地址并一次跳转:jmp [table + rax*8](调整你的AT& T语法)。

答案 1 :(得分:1)

应避免64位相对跳转,因为jmp rel32直接跳转的+ -2GiB代码大小范围通常足够大。

如果目标距离较远,通常只知道绝对地址,而首先不应该计算64位相对位移。

相对位移仅在位移为链接时间常数时才有意义,在这种情况下,您(链接器)通常将源和目标放置在彼此的2GiB之内,因此您可以使用{ {1}}。

如果您不能这样做,通常使用jmp rel32 / movabs $imm64, %rax(对于“巨大”的代码模型,其中假定其他地址的距离> 32位)。不过,这仍然很糟糕。 (而且它不是位置独立的,因此,如果要随机化其加载地址,则需要对64位绝对目标地址进行加载时修复。不过,Linux上的ELF等可执行文件格式确实支持该功能,因此您甚至可以在PIE可执行文件或PIC共享库代码中的跳转表中使用64位绝对地址。)