如何使用动态重新编译?
我注意到一些模拟器和虚拟机使用动态重新编译。 他们如何做到这一点? 在C中,我知道如何使用类型转换来调用ram中的函数(尽管我从未尝试过),但是如何读取操作码并为其生成代码? 该人是否需要预先制作组装块并将它们复制/批处理? 是用C编写的程序集吗? 如果是的话,你如何找到代码的长度? 你如何解释系统中断?
-编辑-
系统中断以及如何(重新)编译数据是我最感兴趣的。经过更多的研究,我听说有一个人(没有可用的源代码)使用js,读取机器代码,输出js源代码并使用eval来“编译” js源码。 有趣。
这听起来像我必须知道目标平台机器代码来动态重新编译
是的,一点没错。 这就是为什么部分Java虚拟机必须为每个架构重写(即JIT)的原因。
当你编写虚拟机时,你有一个特定的主机体系结构和一个特定的客户体系结构。 便携式虚拟机最好称为仿真器,因为您将模拟来宾架构的每条指令(访客寄存器将被表示为主变量而不是主寄存器)。
当客户和主机体系结构相同时,如VMWare,可以进行大量(相当整洁的)优化,以加速虚拟化 - 现在我们认为这种类型的虚拟机比直接在处理器上运行。 当然,这是非常依赖于架构的 - 你可能会更好地从头开始重写大部分VMWare,而不是尝试移植它。
很可能 - 虽然显然不是微不足道的),从内存指针反汇编代码,以某种方式优化代码,然后将优化后的代码写回原始位置或跳转到原始位置跳转到新位置。
当然,模拟器和虚拟机不必重写,他们可以在加载时执行此操作。
这是一个悬而未决的问题,不确定你想去哪里。 维基百科使用通用答案覆盖了通用主题。 被模拟或虚拟化的本地代码被替换为本地代码。 代码运行得越多,替换的代码就越多。
我认为你需要做一些事情,首先决定你是在谈论仿真还是像虚拟机或虚拟机这样的虚拟机。 模拟处理器和硬件是使用软件模拟的,所以下一条指令被仿真器读取,操作码被代码拉开,您决定如何处理它。 我一直在做一些6502仿真和静态二进制翻译,这是动态重新编译,但是预处理而不是实时。 所以你的仿真器可能需要一个LDA#10,加载一个立即的,仿真器看到负载一个立即指令,知道它必须读取下一个字节,它是立即模拟器在A寄存器的代码中有一个变量,该变量的即时值。 在完成指令之前,仿真器需要更新标志,在这种情况下,零标志清零,N标志清零,C和V不变。 但是如果下一条指令是一个立即的加载X呢? 没什么大不了的? 好吧,负载x也会修改z和n标志,所以下次执行load指令时,你可能会发现你不必计算标志,因为它们将被销毁,它在仿真中是死代码。 你可以继续这种想法,比如说你看到的代码将x寄存器复制到一个寄存器,然后将一个寄存器压入堆栈,然后将y寄存器复制到一个寄存器并推入堆栈,你可以替换该块只需将x和y寄存器推入堆栈。 或者您可能会看到几个链接在一起的添加链接,以执行16位添加并将结果存储在相邻的内存位置。 基本上寻找模拟处理器无法做到的操作,但在仿真中很容易实现。 静态二进制翻译,我建议你在动态重新编译之前查看一下,以静态方式执行此分析和翻译,如在运行代码之前。 例如,您不需要模拟将操作码转换为C,而是尽可能多地删除死代码(一个很好的功能是C编译器可以为您删除更多的死代码)。
一旦理解了仿真和翻译的概念,你就可以尝试动态地做到这一点,这当然不是微不足道的。 我会建议再次尝试将二进制文件静态转换为目标处理器的机器代码,这是一个很好的练习。 我不会尝试动态运行时优化,直到我成功地对一个/二进制进行了静态执行。
虚拟化是一个不同的故事,你正在谈论在同一个处理器上运行同一个处理器。 例如x86上的x86。 这里的美妙之处在于使用非x86处理器,您可以将程序虚拟化并在实际处理器上运行实际的操作码,无需仿真。 您可以在处理器中设置陷阱来捕捉事物,以便在AX中加载值并添加BX等,这些都是在处理器上实时发生的,当AX要读取或写入内存时,它取决于您的陷阱机制,如果地址在虚拟机ram空间,没有陷阱,但可以说程序写入到虚拟化uart的地址,你有处理器陷阱,然后vmware或任何解码,写入和模拟它与真正的串行端口交谈。 这一条指令虽然不是实时的,但执行需要很长时间。 如果您选择替换该指令或一组写入虚拟串行端口值的指令,然后再写入另一个可能是真正的串行端口或某些其他不会去的位置导致虚拟机管理器不得不模拟指令的错误。 或者在虚拟内存空间中添加一些代码,在没有陷阱的情况下执行写入uart,然后让该代码分支到这个uart写入例程。 当你下一次点击这段代码时,它现在可以实时运行。
你可以做的另一件事是例如模拟,并且当你转换为虚拟中间bytcode时,就像llvm的。 从那里你可以从中间机器翻译到本地机器,最终如果不是整个事情,它们将取代大部分程序。 你仍然需要处理外设和I / O。
链接地址: http://www.djcxy.com/p/50553.html