在编写JIT编译器时,何处存储代码常量?

时间:2014-05-30 16:51:20

标签: c++ assembly x86-64 jit

我正在为x86-64编写一个JIT编译器,我有一个关于将常量包含在我生成的机器代码中的最佳实践的问题。

到目前为止我的方法很简单:

  • 使用VirtualAllocmmap
  • 分配一大块RW内存
  • 将机器代码加载到所述内存区域。
  • 使用VirtualProtectmprotect标记页面可执行文件(并删除写入权限以确保安全性)。
  • 执行。

当我生成代码时,我必须包含常量(数字,字符串),我不确定什么是最好的方法。我有几种方法:

  • 将所有常量作为立即值存储到指令的操作码中。除了可能是小标量值之外,这似乎是一个坏主意。
  • 为常量分配一个单独的内存区域。这对我来说似乎是最好的想法,但它使内存管理稍微复杂化和编译工作流程 - 在开始编写可执行文件之前我必须先知道内存位置码。此外,我不确定这是否会因为更糟糕的内存位置而影响性能。
  • 将常量存储在与代码相同的区域中,并使用RIP相对寻址访问它。我喜欢这种方法,因为它将程序的相关部分保持在一起,但我对混合指令和数据感到有些不安。
  • 完全不同的东西?

最好的方法是什么?

1 个答案:

答案 0 :(得分:4)

很大程度上取决于您如何生成二进制代码。如果你使用一个处理标签和计算偏移的JIT汇编器,事情就很容易了。您可以在代码结束后将常量粘贴在一个块中,使用对这些标签的pc相对引用,最后得到一个包含代码和常量的单个字节块(易于管理)。如果您正在尝试动态生成二进制代码,那么您已经遇到了如何处理前向pc相对引用(例如前向分支)的问题。如果使用反向修补,则需要扩展它以支持对常量块的引用。

您可以通过将常量放在单独的块中并将该块的地址作为参数传递给代码来避免pc相对偏移计算。这几乎就是你提出的“为常量分配一个单独的区域”。如果将其作为参数传递,则无需知道块的地址。