学习qemu已经有半个月了,有了一点小想法,在这里做个小记录。
首先要说的是一个很经典的流程图,也许有很多人提到了这个,这里再次重复一下:
这里分两部分:
前端————>把guest code(这里也称作target code) 转换成TCG IR(这里也称作TCG-ops,这是一种独立于具体机器的中间代码);
后端————>利用TCG把TCG IR转换成host上能够运行的主机代码。
这里加入一部分博主翻译内容,以便加深理解(原文来自:Qemu Detailed Study: 7 Chapter):
QEMU的作用就是,提取客户代码,然后转换成主机代码。整个转换过程由两部分组成:首先,Target Code的代码块(TB)被转换成TCG-ops(独立于机器的中间代码),第二步,就是用HOST 架构对应的TCG,把由TB生成的TCG-ops转换成Host Code。这个的优化过程在这两个步骤的中间完成。
当前,在QEMU中可以模拟的处理器架构有: Alpha, ARM, Cris,i386, M68K, PPC, Sparc, Mips, MicroBlaze, S390X and SH4。这些架构的处理器对应的/target -xyz/下的code,把TBs转换成TCG-ops,这里的xyz就是上面所说的架构名。因此,arm对应的code可以在/target-arm/下面找到。这部分可以被称为TCG前端。
主机端用/tcg/下的code把TCG-ops生成主机能运行的代码,这部分被称为TCG的后端。
在代码执行前,编译器要把源代码生成目标代码。为了将一个函数调用生成目标代码,编译器(如gcc)会产生一些特殊的代码,这些特殊代码应用在函数调用前和函数返回前。这些特殊代码被称为 Function Prologue 和 Epilogue。(本人认为,就是函数调用前的进栈和出栈处理)。
众所周知,TCG使用的是动态转换(Dynamic Translation)技术。所谓动态转换,就是在需要的时候才转换code。目的是,把大部分时间花费在执行生成的代码上。每次由TB块生成的code在被执行之前,都会被存在code cache中。大多数的时候,相同的TBs会被多次执行,因此从cache中调用是最好的方式,而不重新生成。一旦code cache被填满了,所有的code cache将被清空。