【问题标题】:JIT emulation and tracking dirty memory blocksJIT 仿真和跟踪脏内存块
【发布时间】:2015-04-26 07:54:52
【问题描述】:

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

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

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

【问题讨论】:

  • 嘿!为什么投反对票?
  • 可能是因为没有明确的问题。 :-)
  • 感谢您回答为什么投反对票。我会尝试重写。我是在医院候诊室漫长的一天前用手机写的……

标签: code-generation jit emulation


【解决方案1】:

即使使用中等复杂的数据结构来跟踪客户内存的变化,问题在于必须可以从 jitted 代码中查询和更新它。为了避免代码大小的荒谬爆炸,您可能需要插入对某个函数的调用,该函数在 jitted 代码执行存储指令时写入区间树(而不是内联写入)。性能可能会受到影响,以至于您也可以从一开始就解释代码。此外,必须格外小心,以免模拟器的其他部分在不更新数据结构的情况下写入相应的页面。

有一种可移植性稍差的方法涉及利用主机操作系统的虚拟内存设施。当您的 JIT 为一块客户内存发出代码时,您将相应的虚拟内存页面标记为只读。任何后续的写入尝试都会触发一个异常(例如SIGSEGV),该异常可以被您的主机程序捕获。收到此异常后,您的主机程序会立即使从客户内存中生成的与故障页面重叠的所有 jitted 代码无效,然后重新启用对该页面的写访问,以便完成存储。

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

  1. jitted 代码存储到客户内存的一部分,从该部分中,紧随其后的指令之一被jit了。
  2. 主机程序引发并处理异常。来自错误页面的所有 jitted 代码(包括其存储首先触发异常的代码)都将失效。写入权限再次启用。
  3. 异常处理程序返回,但在哪里?为什么,对于错误指令,当然,这是无效代码的一部分!呃-哦!

据我所知,有两种选择。要么你忽略这个问题,有效地使修改其附近指令的代码行为未定义,要么你在异常处理程序中设置某种无效标志并在每次存储后对其进行测试,如果测试失败则退出解释器。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多