qemu技術(shù)分析-TCG基本原理_第1頁(yè)
qemu技術(shù)分析-TCG基本原理_第2頁(yè)
qemu技術(shù)分析-TCG基本原理_第3頁(yè)
qemu技術(shù)分析-TCG基本原理_第4頁(yè)
qemu技術(shù)分析-TCG基本原理_第5頁(yè)
已閱讀5頁(yè),還剩2頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

QEMU技術(shù)分析2-TCG(TinyCodeGenerator)基本原理從QEMU-0.10.0開始,TCG成為QEMU新的翻譯引擎,做到了“真正”的動(dòng)態(tài)翻譯(從某種意義上說(shuō),舊版本是從編譯后的目標(biāo)文件中復(fù)制二進(jìn)制指令)。TCG的全稱為“TinyCodeGenerator”,QEMU的作者FabriceBellard在TCG的說(shuō)明文件中寫到,TCG起源于一個(gè)C編譯器后端,后來(lái)被簡(jiǎn)化為QEMU的動(dòng)態(tài)代碼生成器(FabriceBellard以前還寫過(guò)一個(gè)很牛的編譯器TinyCC)。實(shí)際上TCG的作用也和一個(gè)真正的編譯器后端一樣,主要負(fù)責(zé)分析、優(yōu)化Target代碼以及生成Host代碼。

Target指令---->TCG---->Host指令

以下的講述以X86平臺(tái)為例(Host和Target都是X86)。

我在上篇文章中講到,動(dòng)態(tài)翻譯的基本思想就是把每一條Target指令切分成為若干條微操作,每條微操作由一段簡(jiǎn)單的C代碼來(lái)實(shí)現(xiàn),運(yùn)行時(shí)通過(guò)一個(gè)動(dòng)態(tài)代碼生成器把這些微操作組合成一個(gè)函數(shù),最后執(zhí)行這個(gè)函數(shù),就相當(dāng)于執(zhí)行了一條Target指令。這種思想的基礎(chǔ)是因?yàn)镃PU指令都是很規(guī)則的,每條指令的長(zhǎng)度、操作碼、操作數(shù)都有固定格式,根據(jù)前面就可推導(dǎo)出后面,所以只需通過(guò)反匯編引擎分析出指令的操作碼、輸入?yún)?shù)、輸出參數(shù)等,剩下的工作就是編碼為目標(biāo)指令了。

那么現(xiàn)在的CPU指令這么多,怎么知道要分為哪些微操作呢?其實(shí)CPU指令看似名目繁多,異常復(fù)雜,實(shí)際上多數(shù)指令不外乎以下幾大類:數(shù)據(jù)傳送、算術(shù)運(yùn)算、邏輯運(yùn)算、程序控制;例如,數(shù)據(jù)傳送包括:傳送指令(如MOV)、堆棧操作(PUSH、POP)等,程序控制包括:函數(shù)調(diào)用(CALL)、轉(zhuǎn)移指令(JMP)等;

基于此,TCG就把微操作按以上幾大類定義(見tcg/i386/tcg-target.c),例如:其中一個(gè)最簡(jiǎn)單的函數(shù)tcg_out_movi如下:

//tcg/tcg.c

staticinlinevoidtcg_out8(TCGContext*s,uint8_tv)

{

*s->code_ptr++=v;

}

staticinlinevoidtcg_out32(TCGContext*s,uint32_tv)

{

*(uint32_t*)s->code_ptr=v;

s->code_ptr+=4;

}

//tcg/i386/tcg-target.c

staticinlinevoidtcg_out_movi(TCGContext*s,TCGTypetype,

intret,int32_targ)

{

if(arg==0){

/*xorr0,r0*/

tcg_out_modrm(s,0x01|(ARITH_XOR<<3),ret,ret);

}else{

tcg_out8(s,0xb8+ret);//輸出操作碼,ret是寄存器索引

tcg_out32(s,arg);//輸出操作數(shù)

}

}

0xb8-0xbf正是x86指令中的movR,Iv系列操作的16進(jìn)制碼,所以,tcg_out_movi的功能就是輸出mov操作的指令碼到緩沖區(qū)中。可以看出,TCG在生成目標(biāo)指令的過(guò)程中是采用硬編碼的,因此,要讓TCG運(yùn)行在不同的Host平臺(tái)上,就必須為不同的平臺(tái)編寫微指令函數(shù)。

接下來(lái),我還是以一條Target指令jmpf000:e05b來(lái)講述它是如何被翻譯成Host指令的。其中幾個(gè)關(guān)鍵變量的定義如下:

gen_opc_buf:操作碼緩沖區(qū)

gen_opparam_buf:參數(shù)緩沖區(qū)

gen_code_buf:存放翻譯后指令的緩沖區(qū)

gen_opc_ptr、gen_opparam_ptr、gen_code_ptr三個(gè)指針變量分別指向上述緩沖區(qū)。

jmpf000:e05b的編碼是:EA5BE000F0,首先是disas_insn()函數(shù)翻譯指令,當(dāng)碰到第1個(gè)字節(jié)EA,分析可知這是一條16位無(wú)條件跳轉(zhuǎn)指令,因此依次從后續(xù)字節(jié)中得到offset和selector,然后分為如下微指令操作:

gen_op_movl_T0_im(selector);

gen_op_movl_T1_imu(offset);

gen_op_movl_seg_T0_vm(R_CS);

gen_op_movl_T0_T1();

gen_op_jmp_T0();

這幾個(gè)微操作的函數(shù)定義如下(功能可看注釋):

staticinlinevoidgen_op_movl_T0_im(int32_tval)

{

tcg_gen_movi_tl(cpu_T[0],val);//相當(dāng)于cpu_T[0]=val

}

staticinlinevoidgen_op_movl_T1_imu(uint32_tval)

{

tcg_gen_movi_tl(cpu_T[1],val);//相當(dāng)于cpu_T[1]=val

}

staticinlinevoidgen_op_movl_seg_T0_vm(intseg_reg)

{

tcg_gen_andi_tl(cpu_T[0],cpu_T[0],0xffff);//cpu_T[0]=cpu_T[0]&0xffff

tcg_gen_st32_tl(cpu_T[0],cpu_env,

offsetof(CPUX86State,segs[seg_reg].selector));//thevalueofcpu_T[0]storetothe'offset'ofcpu_env

tcg_gen_shli_tl(cpu_T[0],cpu_T[0],4);//cpu_T[0]=cpu_T[0]<<4

tcg_gen_st_tl(cpu_T[0],cpu_env,

offsetof(CPUX86State,segs[seg_reg].base));//thevalueofcpu_T[0]storetothe'offset'ofcpu_env

}

staticinlinevoidgen_op_movl_T0_T1(void)

{

tcg_gen_mov_tl(cpu_T[0],cpu_T[1]);//cpu_T[0]=cpu_T[1]

}

staticinlinevoidgen_op_jmp_T0(void)

{

tcg_gen_st_tl(cpu_T[0],cpu_env,offsetof(CPUState,eip));////thevalueofcpu_T[0]storetothe'offset'ofcpu_env

}

其中,cpu_T[0]、cpu_T[1]和前面講過(guò)的T0、T1功能一樣,都是用來(lái)臨時(shí)存儲(chǔ)的變量。在32位目標(biāo)機(jī)上,tcg_gen_movi_tl就是tcg_gen_op2i_i32函數(shù),它的定義如下:

staticinlinevoidtcg_gen_op2i_i32(intopc,TCGv_i32arg1,TCGArgarg2)

{

*gen_opc_ptr++=opc;

*gen_opparam_ptr++=GET_TCGV_I32(arg1);

*gen_opparam_ptr++=arg2;

}

staticinlinevoidtcg_gen_movi_i32(TCGv_i32ret,int32_targ)

{

tcg_gen_op2i_i32(INDEX_op_movi_i32,ret,arg);

}

gen_opparam_buf是用來(lái)存放操作數(shù)的緩沖區(qū),它的存放順序是:第1個(gè)4字節(jié)代表s->temps(用來(lái)存放目標(biāo)值的數(shù)組,即輸出參數(shù))的索引,第2個(gè)4字節(jié)及之后字節(jié)代表輸入?yún)?shù),對(duì)它的具體解析過(guò)程可見tcg_reg_alloc_movi函數(shù),示例代碼如下:

TCGTemp*ots;

tcg_target_ulongval;

ots=&s->temps[args[0]];

val=args[1];

ots->val_type=TEMP_VAL_CONST;

ots->val=val;//把輸入值暫時(shí)存放在ots結(jié)構(gòu)中

接下來(lái),根據(jù)gen_opc_buf保存的操作碼列表,gen_opparam_buf保存的參數(shù)列表,以及TCGContext結(jié)構(gòu),經(jīng)過(guò)tcg_gen_code_common函數(shù)調(diào)用,jmpf000:e05b生成的最終指令如下:

099D0040B800F00000

mov

eax,0F000h

099D004581E0FFFF0000and

eax,0FFFFh

099D004B894550

mov

dwordptr[ebp+50h],eax

099D004EC1E004

shl

eax,4

099D0051894554

mov

dwordptr[ebp+54h],eax

099D0054B85BE00000

mov

eax,0E05Bh

099D0059894520

mov

dwordptr[ebp+20h],eax

099D005C31C0

xor

eax,eax

099D005EE9255DCA06

jmp

_code_gen_prologue+8(10675D88h)/*返回*/

從上面可以看出,生成的Host代碼很簡(jiǎn)潔,在調(diào)試中,把QEMU執(zhí)行Target指令的過(guò)程和Bochs比較是一件很有趣的事情,當(dāng)然,這只是設(shè)計(jì)理念的不同,而并沒有技術(shù)上的優(yōu)劣之分。2樓:你不應(yīng)該使用“微指令”這一詞,使人容易產(chǎn)生混淆,感覺和processor的微碼混在一起。

微碼是processor內(nèi)部的產(chǎn)物,x86指令經(jīng)過(guò)processor內(nèi)部的decode單元譯碼后產(chǎn)生的最小processor執(zhí)行命令。

使用“微操作”一詞比較合適一些。比較符合作者說(shuō)的“tinycode”本質(zhì)

像你上面所說(shuō)的jmpfarf000:e05b指令

作者是這樣處理:

(1)將f000放入buf

(2)將e05b放入buf

(3)jmp[buf]

(buf里存放著f000:e05b)

-------------------------------------------------------------------

通過(guò)上述一些操作,實(shí)現(xiàn)jmpf000:e05b的結(jié)果。而并不是將jmpfar指令分解為微指令或微碼。

指令:jmpf000:e05b---->原本的opcode是EA

經(jīng)過(guò)等價(jià)效果轉(zhuǎn)換為----->

opcode為FF/05(jmp[mem16:16])

不過(guò),或許作者就是通過(guò)這樣達(dá)到他期望的動(dòng)態(tài)效果吧。

我所認(rèn)為的分解應(yīng)該是:

像下面這條簡(jiǎn)單的c語(yǔ)句:

a=b+c;

1、確定兩個(gè)主要操作:

(1)"+"加法操作。

(2)"="賦值操作。

所以,我若分解的話,會(huì)分解為:

intadd_2ops(op1,op2)

{

source_reg=get_reg();

/*經(jīng)過(guò)分析取得可用regID*/

dest_reg=get_reg();

/*得取可用的regID*/

......

/*調(diào)用由兩個(gè)operandsID合成而來(lái)的函數(shù)*/

add_2ops_generator[OP_ID(source_reg)|OP_ID(dest_reg)](op1,op2);

......

}

voidmove_dword()

{

.......

}

比較實(shí)在的根據(jù)語(yǔ)句原意分解為相應(yīng)的匯編碼或機(jī)器碼3樓:QUOTE:原帖由mik于2009-8-2523:25發(fā)表

你不應(yīng)該使用“微指令”這一詞,使人容易產(chǎn)生混淆,感覺和processor的微碼混在一起。

微碼是processor內(nèi)部的產(chǎn)物,x86指令經(jīng)過(guò)processor內(nèi)部的decode單元譯碼后產(chǎn)生的最小processor執(zhí)行命令。

...

感謝mik老大把加為精華貼。從思路上說(shuō),我覺得QEMU這種分解指令的做法和處理器的微碼有相通之處,但有可能引起誤解,感謝你的建議,用“微操作”來(lái)表示的確是個(gè)更好的詞,我待會(huì)改一下。

不過(guò)你說(shuō)的QUOTE:jmpfarf000:e05b指令,作者是這樣處理:

(1)將f000放入buf

(2)將e05b放入buf

(3)jmp[buf]

(buf里存放著f000:e05b)

-----------------------------------------

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論