JIT仿真和跟踪脏内存块

时间:2015-02-24 15:44:33

标签: code-generation jit emulation

我正在为玩具CPU(TR3200 cpu)开发一个模拟器。实际上我有一个纯粹的解释器核心,但我正在研究开发一个跟踪JIT cpu核心。 我怀疑如何通过模拟代码(自修改代码或类似操作系统将编程加载到RAM)修改已被引用的源机器代码的跟踪方式 我正在考虑使用段或间隔树,但是我找不到任何关于如何处理它的信息或示例。

换句话说......我知道JIT(我正在考虑使用asmjit),我应该将jitted代码存储在使用jitted块的开始地址作为索引的地图上;我知道如何处理循环计数和设备与jitted代码同步。但是我并不清楚客户程序在jitted内存块上写入时的处理方式。

例如:我们有一个简单的操作系统,它在地址0x100-0x500处执行了一个程序并正确返回。 JIT cpu核心(乐观)会生成一个代表这些代码块的本机机器代码。现在,如果操作系统加载另一个程序并将其放在0x200-0x300地址块上,则不应使0x100-0x500的旧jitted块无效,因为它会被覆盖。 或者最糟糕的情况是,一个自我重写的程序,使得jitted块无效。 如何检测到这一点?

1 个答案:

答案 0 :(得分:3)

使用即使是中等复杂的数据结构来跟踪来宾内存的更改的问题是必须能够从jitted代码中查询和更新它。为了避免代码大小的荒谬爆炸,您可能需要在每次jitted代码执行存储指令时插入对写入间隔树(而不是内联写入)的函数的调用。性能可能会受到影响,您可以将代码解释为开头。此外,必须非常小心,以免模拟器的其他部分在不更新数据结构的情况下写入相应的页面。

有一种稍微不那么便携的方法,涉及利用主机操作系统的虚拟内存设施。当JIT为大量guest虚拟机内存发出代码时,会将相应的虚拟内存页标记为只读。任何后续写入尝试都将触发主机程序可以捕获的异常(例如SIGSEGV)。收到此异常后,您的主机程序会立即使从guest虚拟机内存生成的与错误页面重叠的所有jitted代码无效,然后重新启用对该页面的写访问权限,以便存储可以完成。

虽然这个解决方案可以处理大多数写入,但它不能处理一段jitted代码修改紧随其后的指令的情况。要了解原因,请考虑将会发生什么:

  1. jitted代码存储到guest虚拟机内存部分,其中一条紧接着的指令已被执行。
  2. 由主程序引发并处理异常。来自错误页面的所有jitted代码(包括其存储首先触发异常的代码)都将失效。再次启用写访问权。
  3. 异常处理程序返回,但在哪里?为什么,对于错误的指令,当然,是无效代码的一部分!呃 - 哦!
  4. 据我所知,有两种选择。您可以忽略此问题,有效地使修改其附近的指令的代码行为未定义,或者在异常处理程序中设置某种失效标志并在每个存储之后对其进行测试,如果测试失败则挽救到解释器中。

    快速搜索建议QEMU might be using a similar mechanism处理对来宾内存的修改,但我无法验证它。