gpt4 book ai didi

assembly - JIT 跳转 (x86_64)

转载 作者:行者123 更新时间:2023-12-02 21:45:23 26 4
gpt4 key购买 nike

我正在用 C 语言为 x86_64 linux 编写一个 JIT 编译器。

目前的想法是在可执行内存的缓冲区中生成一些字节码(例如通过 mmap 调用获得)并使用函数指针跳转到它。

我希望能够将多个可执行内存块链接在一起,以便它们可以仅使用 native 指令在彼此之间跳转。

理想情况下,指向可执行 block 的 C 级指针可以作为绝对跳转地址写入另一个 block ,如下所示:

unsigned char *code_1 = { 0xAB, 0xCD, ... };
void *exec_block_1 = mmap(code1, ... );
write_bytecode(code_1, code_block_1);
...
unsigned char *code_2 = { 0xAB, 0xCD, ... , exec_block_1, ... };
void *exec_block_2 = mmap(code2, ... );
write_bytecode(code_2, exec_block_2); // bytecode contains code_block_1 as a jump
// address so that the code in the second block
// can jump to the code in the first block

但是我发现 x86_64 的限制在这里是一个很大的障碍。无法跳转到 x86_64 中的绝对 64 位地址,因为所有可用的 64 位跳转操作都是相对于指令指针的。这意味着我无法使用 C 指针作为生成代码的跳转目标。

是否有解决此问题的方法,使我可以按照我所描述的方式将 block 链接在一起?也许是我不知道的 x86_64 指令?

最佳答案

如果您在发出跳转指令时知道 block 的地址,则只需检查从跳转指令的地址到目标 block 的地址的字节距离是否符合jXX 系列指令的 32 位有符号偏移量。

即使您分别 mmap 每个 block ,您也很可能不会获得相距超过 ±2GiB 的两个相邻(在控制流意义上) block 。话虽这么说,有几个很好的理由像这样单独映射每个 block 。首先,mmap 的最小分配单位是(几乎按照定义)一个页面,可能至少为 4KiB。这意味着每个 block 的代码后面未使用的空间被浪费了。其次,更紧密地打包基本 block 可以提高指令缓存的利用率以及更短的跳转编码有效的机会。

Perhaps an x86_64 instruction that I'm not aware of?

顺便说一句,有一条指令用于将 64 位立即数加载到 rax 中。 GNU 工具链将其称为 movabs:

0000000000000000 <.text>:
0: 49 b8 ff ff ff ff ff movabs rax,0x7fffffffffffffff
7: ff ff 7f

因此,如果您确实愿意,可以简单地将指针加载到 rax 中并使用跳转来注册。

关于assembly - JIT 跳转 (x86_64),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29797866/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com