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

问题描述 投票:-1回答:2

我想将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位相对跳跃?

assembly 64bit x86-64 att
2个回答
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
投票

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

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

当位移是链接时间常数时,相对位移才有意义,在这种情况下,您(链接器)通常将源和目标放在彼此的2GiB内,这样您就可以使用jmp rel32

如果你不能这样做,那么通常你会使用(对于一个“巨大的”代码模型,假设其他地址大于32位)movabs $imm64, %rax / jmp *%rax。不过,这仍然很糟糕。 (并且它不是与位置无关的,所以如果你想随机化它的加载地址,你需要为64位绝对目标地址加载时修复。可执行文件格式如Linux上的ELF确实支持它,所以即使在PIE可执行文件或PIC共享库代码中,也可以在跳转表中使用64位绝对地址。)

© www.soinside.com 2019 - 2024. All rights reserved.