我刚刚发现调用指令,我们通常实际上是程序计数器相对的。然而,x86指令使用32位宽偏移量来指示相对数字。
如果我想跳转怎么办? 4GB之外?
答案 0 :(得分:1)
我想如果你将一些代码JIT分配到距离需要调用的某些函数超过2 ^ 32的缓冲区中,就会出现这种情况。简单的答案是:不要这样做。
在Linux上,例如,如果您希望JITed代码在主可执行文件中mmap(MAP_32BIT)
运行,请使用call
在低2GiB的虚拟地址空间中分配内存。 (假设一个与位置相关的可执行文件)。
在PIE可执行文件或共享库(通常无法映射到虚拟地址空间的低32位)中,您可以尝试通过尝试mmap
<来在您自己的代码附近分配内存em>没有 MAP_FIXED
和trying different addresses in range if that doesn't work the first time。 mmap(hint_address, ...)
/检查它是否在代码和/或数据的+ -2GiB范围内,达到/ munmap
并使用不同的提示重试。
原因是唯一的解决方法是使用绝对地址间接调用。见Call an absolute pointer in x86 machine code。您需要将目标地址加载到寄存器中,或将地址作为指针存储在内存中,然后跳转到该地址。请参阅英特尔的insn参考手册,其中all the available encodings of call
are listed.
此x86 tag wiki链接指向https://www-ssl.intel.com/content/www/us/en/processors/architectures-software-developer-manuals.html
如果您不需要它超级高效,实际JIT绝对间接调用的一种方法是将指针表放在相对于JITed代码的已知位置,以便它可以使用间接call [rel pointer_to_func1]
(RIP相对寻址)。这类似于Unix共享库使用的全局偏移表,以及编译器生成的代码如果使用gcc -fno-plt
编译时如何调用共享库函数。
答案 1 :(得分:0)
我碰巧有这个非常需要:在一些动态创建的代码中发出一个绝对的64位地址的调用,结果证明并不是很难,虽然与我们的直接绝对跳转相比有点笨拙在32位模式下(您的确切asm语法可能会有所不同,具体取决于您碰巧使用的汇编程序),例如:
.error