转载:http://cmchao.pixnet.net/blog/post/16035915
在qmeu中,將qmeu 本身所執行的平台稱為 host,模擬的平台稱target,而將target code 轉為 host code 的過程稱為code generation。但因為qemu 是在動態執行中將target code 轉為 host code,所以多加了一個dynammic來形容。而整個過程在qemu 中稱為 dyngen。
0.9.1 版之前的dyngen 概念很簡單(但實作起來有很多細部的東東,整個就是複雜),dyegen 定義了四個pesudo register:env, T0, T1, T2,這四個register分別mapping 到 host 上真實的general register,在x86上就是 ebp, ebx, esi, edi,在x86_64上就是 r14, r15, r12, r13 (為什麼不是r12, r13, 14, 15,怪),定義在dyngen-exec.h
之後target 必需定義一些簡單的operation function,此operation function 被定義在每個 target-machine/op.c ,底下是target-arm 的例是,每個平台大同小異
,這些operation 很簡單,定義如何在pesudo register 之間搬資料,做一些簡單的動作。
void OPPROTO op_movl_T0_T1(void)
{
T0 = T1;
}void OPPROTO op_movl_T1_im(void)
{
T1 = PARAM1;
}void OPPROTO op_addl_T1_im(void)
{
T1 += PARAM1;
}void OPPROTO op_addl_T1_T2(void)
{
T1 += T2;
}void OPPROTO op_subl_T1_T2(void)
{
T1 -= T2;
}
有了這些基本的operation後,在build qemu時會將的會將op.c 編譯成 op.o,再從op.o 將每個operation 所對應的host code抽出來,產生op.h opc.h,target-machine/translate.c 利用產生出來的個這兩個header file將每個target instruction 對應到數個operation function。就像底下的arm 例子,
op = (insn >> 11) & 3;
rd = (insn >> 8) & 0x7;
if (op == 0) {
gen_op_movl_T0_im(insn & 0xff);
} else {
gen_movl_T0_reg(s, rd);
gen_op_movl_T1_im(insn & 0xff);
}
switch (op) {
case 0: /* mov */
gen_op_logic_T0_cc();
break;
case 1: /* cmp */
gen_op_subl_T0_T1_cc();
break;
case 2: /* add */
gen_op_addl_T0_T1_cc();
break;
case 3: /* sub */
gen_op_subl_T0_T1_cc();
break;
}
if (op != 1)
gen_movl_reg_T0(s, rd);
底下是截取 objdump op.o 的部份,dyngen 會把retq 以上的部份copy 出來,再經過一些patch 就產生相對應的code 啦,上面粗體的gen_xxx_xxx的function 就會把相對應的找出來,轉換就完成啦
00000000000001e7 :
1e7: 45 01 ec add %r13d,%r12d
1ea: c3 retq00000000000001eb :
1eb: 45 29 ec sub %r13d,%r12d
1ee: c3 retq00000000000001ef :
1ef: 45 01 e7 add %r12d,%r15d
1f2: c3 retq
講起來好像很簡單,那是因為假裝略過 control flow 的東東,有興趣的人自已看吧,講寫的東東其實是第二篇,先騙騙錢。