当您需要调用大于 2^32 位的函数时会发生什么?
What happens when you need to call a function that is > 2^32-bit away?
我才发现我们平时的call指令其实是程序计数器相关的。然而x86指令使用32位宽的偏移量来表示一个相对数。
如果我想跳转 > 4GB 怎么办?
我想如果您将一些代码 JIT 到一个缓冲区中,该缓冲区分配的距离它需要调用的某些函数超过 2^32。简单的答案是:不要那样做。
在Linux上,例如,使用mmap(MAP_32BIT)
在虚拟地址space的低2GiB分配内存,如果你想让JITed代码到call
函数在主执行程序中table。 (假设位置相关的 executable)。
在 PIE executable 或共享库中(通常不会映射到虚拟地址的低 32 位 space),您可能会尝试在自己附近分配内存通过尝试 mmap
没有 MAP_FIXED
和 trying different addresses in range if that doesn't work the first time 来编码。 mmap(hint_address, ...)
/ 检查它是否在代码 and/or 需要到达的数据的 +-2GiB 范围内 / munmap
并用不同的提示重试。
原因是唯一的解决方法是使用绝对地址间接调用。参见 Call an absolute pointer in x86 machine code. You'd need to load the target address into a register, or have the address stored in memory as a pointer, and jump to that. See Intel's insn ref manual, where all the available encodings of call
are listed.
还有x86 tag wiki links to https://www-ssl.intel.com/content/www/us/en/processors/architectures-software-developer-manuals.html
如果您不需要它非常高效,实际 JIT 绝对间接调用的一种方法是将 table 指针放在相对于 JIT 代码的已知位置,这样它可以使用间接 call [rel pointer_to_func1]
(RIP 相对寻址)。这就像 Unix 共享库使用的全局偏移量 table,以及如果使用 gcc -fno-plt
.
编译,编译器生成的代码如何调用共享库函数
我恰好有这个需求:将对绝对 64 位地址的调用发送到一些动态创建的代码中,事实证明它一点也不难,尽管与直接绝对跳转相比有点笨拙我们有 32 位模式(您的确切 asm 语法可能会有所不同,具体取决于您碰巧使用的汇编程序)例如:
call qword ptr [rel @1]
jmp @2
@1:
dq <64-bit address>
@2:
我才发现我们平时的call指令其实是程序计数器相关的。然而x86指令使用32位宽的偏移量来表示一个相对数。
如果我想跳转 > 4GB 怎么办?
我想如果您将一些代码 JIT 到一个缓冲区中,该缓冲区分配的距离它需要调用的某些函数超过 2^32。简单的答案是:不要那样做。
在Linux上,例如,使用mmap(MAP_32BIT)
在虚拟地址space的低2GiB分配内存,如果你想让JITed代码到call
函数在主执行程序中table。 (假设位置相关的 executable)。
在 PIE executable 或共享库中(通常不会映射到虚拟地址的低 32 位 space),您可能会尝试在自己附近分配内存通过尝试 mmap
没有 MAP_FIXED
和 trying different addresses in range if that doesn't work the first time 来编码。 mmap(hint_address, ...)
/ 检查它是否在代码 and/or 需要到达的数据的 +-2GiB 范围内 / munmap
并用不同的提示重试。
原因是唯一的解决方法是使用绝对地址间接调用。参见 Call an absolute pointer in x86 machine code. You'd need to load the target address into a register, or have the address stored in memory as a pointer, and jump to that. See Intel's insn ref manual, where all the available encodings of call
are listed.
还有x86 tag wiki links to https://www-ssl.intel.com/content/www/us/en/processors/architectures-software-developer-manuals.html
如果您不需要它非常高效,实际 JIT 绝对间接调用的一种方法是将 table 指针放在相对于 JIT 代码的已知位置,这样它可以使用间接 call [rel pointer_to_func1]
(RIP 相对寻址)。这就像 Unix 共享库使用的全局偏移量 table,以及如果使用 gcc -fno-plt
.
我恰好有这个需求:将对绝对 64 位地址的调用发送到一些动态创建的代码中,事实证明它一点也不难,尽管与直接绝对跳转相比有点笨拙我们有 32 位模式(您的确切 asm 语法可能会有所不同,具体取决于您碰巧使用的汇编程序)例如:
call qword ptr [rel @1]
jmp @2
@1:
dq <64-bit address>
@2: