我正在研究像Bochs和QEMU这样的模拟器如何工作并且有一个问题 - 如果我在x86主机上模拟x86客户操作系统并且guest执行一些指令来分配寄存器(例如,mov eax) 3),是否保证甚至可能将该值实际分配给仿真器运行的代码中实际硬件上的eax寄存器?
我认为没有理由不这样做,因为QEMU流程是它自己独立的流程(所以它不必与任何其他流程共享通用寄存器),因为它们都是主机和客户机架构是相同的,因此具有相同的通用寄存器。
另外,如果我要在QEMU中执行一个有两条指令的程序:
mov eax 3
add eax 2
如果它可以确定这样做不会改变程序的执行,它会将两者组合成单个mov eax, 5
指令,因为它通过执行指令块而不是单独执行每个指令来执行程序?
请注意,在这种情况下,我指的是纯仿真(Bochs或非KVM QEMU),而不是硬件虚拟化。
答案 0 :(得分:7)
不,QEMU不能那样工作。 x86-to-x86不是特殊情况,并且与仿真中的任何其他guest /主机组合一样处理。所有访客代码首先被翻译成中间表示。然后运行一个简单的优化传递(这是我们发现'加载2;加3'简化为'加载5'的地方)。最后,我们注册分配并从IR生成本机主机代码。
在IR中,guest虚拟机寄存器用“TCG值”表示,它们类似于更高级语言中的变量。 guest寄存器被定义为存在于主机存储器中的CPU状态结构中的值,但TCG足够聪明,在实际需要之前不会将它们写回存储器,因此通常宾客寄存器的“实时”副本将在主机注册。但是因为寄存器分配是完全独立的代码位,所以分配器不太可能选择与客户代码最初使用的x86寄存器相同的。
对于编译器或JIT(和TCG QEMU是JIT),使用这样的IR是一种非常常见的设计模式。优点是,您可以轻松支持多个前端和后端,而不需要考虑的不同组合数量的爆炸性增长; QEMU目前支持18个前端和9个后端。它还意味着常见的优化(比如删除单独的add指令的常量折叠)只需要实现一次,纯粹在IR上工作。
TCG IR记录在此处:http://wiki.qemu.org/Documentation/TCG