




版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
1、SKYEYE 指令動(dòng)態(tài)翻譯模擬 (DBCT) 實(shí)現(xiàn)介紹 v0.0teawater()轉(zhuǎn)載請(qǐng)標(biāo)明來(lái)自 修改記錄: v0.02006-06-16 , v0.0 版本編寫完成。2006-05-27 ,文檔創(chuàng)建。目錄1. 寫在前面2. 概述3. 微指令3.1. 微指令的結(jié)構(gòu)和初始化3.2. 微指令中的變量3.3. 微指令中的函數(shù)調(diào)用3.4. 微指令中的異常處理3.5. 微指令中的跳轉(zhuǎn)3.6. 微指令分類介紹3.6.1. 概述3.6.2. arm2x86.c:op_init3.6.3. arm2x86_test.c:ar
2、m2x86_test_init3.6.4. arm2x86_shift.c:arm2x86_shift_init3.6.5. arm2x86_psr.c:arm2x86_psr_init3.6.6. arm2x86_movl.c:arm2x86_movl_init3.6.7. arm2x86_mul.c:arm2x86_mul_init3.6.8. arm2x86_mem.c:arm2x86_mem_init3.6.9. arm2x86_dp.c:arm2x86_dp_init3.6.10. arm2x86_coproc.c:arm2x86_coproc_init3.6.11. arm2x86
3、_other.c:arm2x86_other_init4. 翻譯塊 (TB)4.1. 概述4.2. tb.h:struct tb_s4.3. TB_TBT_SIZE 和 TB_TBP_SIZE4.4. tb.c:tb_memory_init4.5. tb.c:tb_insn_len_max_init5. 初始化函數(shù) arm2x86.c:arm2x86_init6. 翻譯執(zhí)行過程6.1. armemu.c:ARMul_Emulate32_dbct6.2. tb.c:tb_find6.4. tb.c:tb_translate6.5. tb.c:translate_word1. 寫在前面本文針對(duì) s
4、kyeye-1.2-RC7-3 進(jìn)行編寫。關(guān)于 skyeye 本身結(jié)構(gòu)的介紹可以參見 skyeye 學(xué)習(xí)筆記 (/forum /gshowthreaded.php?Cat=&Board=program&Number=522443&page=1& amp;view=collapsed&sb=5&o=all&fpart=) 。在下面為了方便介紹,都將 SKYEYE 指令動(dòng)態(tài)翻譯模擬簡(jiǎn) 稱為 DBCT 。DBCT 的實(shí)現(xiàn)并不算是很好的, 個(gè)人推薦對(duì)動(dòng)態(tài)翻譯有興趣的朋友們讀一下 QEMU 的代碼。2. 概述DBCT 是在指令模擬思想上參照了 QEMU(h
5、ttp:/fabrice.bellard.free.fr/qemu/) ,但在實(shí)現(xiàn)上也 有不同,后面進(jìn) 行每個(gè)部分介紹的時(shí)候,我會(huì)依次介紹到。DBCT 就是將若干條連續(xù)的被模擬指令組成一組(稱為一個(gè)翻譯塊 TB) ,將每條指令根據(jù)其行為直接翻譯成若干條微指令 (這里跟 QEMU 不同, QEMU 在翻譯過程中有中間碼存在 ), 每條微指令代表一種操作行為并由若干條本地指令組成, 最后就得到一組跟 TB 對(duì)應(yīng)的本地 指令, 再在結(jié)尾增加返回指令, 對(duì)這組指令開始的地址進(jìn)行函數(shù)調(diào)用, 就達(dá)到了指令模擬的 目的。然后對(duì)指令進(jìn)行解碼分析, 根, SKYEYE 普通指令模擬方C 語(yǔ)言的函數(shù)等,然后編譯其
6、他我所了解指令模擬方式還有最常見的 直接讀入一條指令, 據(jù)需要進(jìn)行其操作,然后再讀入下一條指令,重復(fù)剛才的工作 式就是這種類型。還有一種模擬方式是將要模擬的硬件行為翻譯成某種語(yǔ)言比如 執(zhí)行來(lái)進(jìn)行指令模擬。3. 微指令3.1. 微指令的結(jié)構(gòu)和初始化在 arm2x86_init 函數(shù)中在 tb_insn_len_max_init 函數(shù)之前的被調(diào)用的函數(shù)都是 微指令初始化 函數(shù)。在 DBCT 代碼中,每條微指令都被封裝在定義在 arm2x86.h 的 op_table_t 結(jié)構(gòu)中,這個(gè)結(jié)構(gòu) 中的 op 是指向這個(gè)微指令的地址,而 len 則是這個(gè)微指令的長(zhǎng)度 。每條微指令的的初始化 都是由一個(gè)名稱為
7、 get_op_xxx 形式的函數(shù)來(lái)完成的,這個(gè)函數(shù)會(huì)將微指令的地址返回,用 來(lái)設(shè)置在 op 中,而其的參數(shù)指針是用來(lái)設(shè)置 len 的,這些函數(shù)都會(huì)在微指令初始化函數(shù)中 被調(diào)用。在這個(gè)函數(shù)中有 2 個(gè)定義在 arm2x86.h 中的宏 OP_BEGIN 和 OP_END ,這 2 個(gè)宏都是 X86 指令。在這 2 個(gè)宏之間的代碼就是微指令的代碼。#define OP_BEGIN (f)_asm_ _volatile_(jmp .f_teawater_op_endnt.f_teawater_op_begin:nt)#define OP_END (f)_asm_ _volatile_ (.f_te
8、awater_op_end:ntmovl$.f_teawater_op_begin,%0ntmovl $.f_teawater_op_end,%1nt:=g(begin), =g(end); OP_BEGIN 先是一條跳轉(zhuǎn)指令, 跳轉(zhuǎn)到聲明在 OP_END 中的符號(hào)地址 .f_teawater_op_end , 這句的作用是跳過 OP_BEGIN 和 OP_END 中間的代碼, 防止他們被執(zhí)行, 我為什么沒有直 接使用普通的跳轉(zhuǎn)語(yǔ)句 goto 呢?因?yàn)槿绻褂昧?goto 語(yǔ)句,編譯器就會(huì)知道微指令的代碼 沒被執(zhí)行, 就會(huì)將這部分代碼優(yōu)化掉, 而 使用跳轉(zhuǎn)指令編譯器無(wú)法判斷匯編語(yǔ)句的行為 ,所
9、 以不會(huì)優(yōu)化掉 2 個(gè)宏之間的微指令代碼。 然后是一條聲明符號(hào)的偽指令, 這個(gè)符號(hào)指向的地 址就是微指令開始的地址。OP_END 先是一條聲明符號(hào)的偽指令,這個(gè)符號(hào)的地址就是指向微指令結(jié)束的地址,OP_BEGIN 中的跳轉(zhuǎn)指令也是跳到了這個(gè)地址。然后跟著是兩條賦值指令,將 微指令開始 和結(jié)束的地址存到初始化函數(shù)開始聲明的begin 和 end 變量中, 這樣在函數(shù)中就取得微指令的開始和結(jié)束地址。從上面對(duì) 2 個(gè)宏的的介紹就可以基本清楚微指令的生成過程, 在取得了微指令的開始和結(jié)束 地址后,就可以通過計(jì)算取得其的長(zhǎng)度最后返回。在 QEMU 的微指令的生成過程跟 DBCT 不同, QEMU 采用的
10、方式是每個(gè)微指令都在一個(gè)函 數(shù)中,編譯完成后,通過特定的程序?qū)⑽⒅噶畹拈_始地址和長(zhǎng)度取出。3.2. 微指令中的變量在微指令的代碼中,都沒有使用動(dòng)態(tài)局部變量,也就是棧中的地址,而直接使用了寄存器, 當(dāng)然在寄存器不夠的情況下也使用了全局變量 。這個(gè)使用的方法是參考的 QEMU 中微指令 對(duì)變量的使用方法。個(gè)人認(rèn)為這樣做因?yàn)槿舾蓷l微指令才能組成一條指令(尤其是在 ARM 這種單條指令實(shí)現(xiàn)若干功能的體系結(jié)構(gòu)更是如此 ),這些微指令之間要相互傳遞計(jì)算等得到的值,如果通過棧傳 遞也可以,但是實(shí)現(xiàn)相對(duì)復(fù)雜,而且頻繁的內(nèi)存操作速度也會(huì)受到影響。對(duì)這些 寄存器的聲明在 arm2x86_self.h 這個(gè)單獨(dú)的頭
11、文件中, 因?yàn)閷?duì)寄存器的聲明有時(shí)候會(huì) 影響代碼編譯,所以只在 DBCT 相關(guān)的文件中包含了這個(gè)頭文件。ebp寄存器聲明為 ARMul_State結(jié)構(gòu)的指針st,其將在微指令的代碼開始之前指向state也就是存儲(chǔ)了 SKYEYE 模擬 CPU 所有信息的結(jié)構(gòu) ,這樣微指令就可以方便的訪問這個(gè)結(jié)構(gòu)。ebx、esi和edi聲明為uint32_t類型的變量T0,T1和T2,這幾個(gè)變量在微指令中可以靈活使用。 注意因?yàn)檫@幾個(gè)寄存器保存了棧指針等信息, 所以在運(yùn)行微指令以前需要進(jìn)行保存, 具體在 介紹 DBCT 運(yùn)行的時(shí)候會(huì)進(jìn)行介紹。其他eax等寄存器因?yàn)槭窃?GCC中是局部寄存器,不能作為全局變量聲明,
12、所以不能作為 微指令中的變量使用。3.3. 微指令中的函數(shù)調(diào)用在微指令中有時(shí)候需要對(duì)函數(shù)進(jìn)行調(diào)用, 因?yàn)槲⒅噶钍褂梅椒ǖ脑? 這里不能進(jìn)行普通的 函數(shù)調(diào)用,而需要特殊處理。下面就以 arm2x86.c:get_op_begin 中對(duì) tea_begin 函數(shù)的調(diào)用為例子進(jìn)行介紹。這里首先是對(duì)esp減Oxc也就是在棧中分配 Oxc的空間,然后將ebp也就是指向ARMul_State結(jié)構(gòu)的指針push到棧中,這2條匯編指令是將 st作為參數(shù)傳遞給被調(diào)用函數(shù)tea_begin,前面在棧中分配 0xc 的空間是要保證傳遞參數(shù)的 0x10 對(duì)齊, 0xc 加 32位的長(zhǎng)度就是 0x10。 沒有存儲(chǔ)使用
13、的ebp、ebx、esi和edi,因?yàn)檫@幾個(gè)全局寄存器的值是由被調(diào)用函數(shù)進(jìn)行保存 的,如果調(diào)用函數(shù)修改了這幾個(gè)寄存器的值就進(jìn)行保存, 在函數(shù)返回時(shí)恢復(fù), 如果沒有就使 用就不進(jìn)行保存和恢復(fù)。然后是將tea_begin的地址賦值給T2,然后再對(duì)其進(jìn)行調(diào)用,這樣做的目的是進(jìn)行直接地址 調(diào)用。因?yàn)橐话愕暮瘮?shù)調(diào)用都是直接地址調(diào)用, 所以調(diào)用跟當(dāng)前這個(gè)調(diào)用指令的地址是相關(guān) 的,但是微指令會(huì)被拷貝到 TB 上的某地址執(zhí)行,調(diào)用指令的地址發(fā)生了變化,所以如果進(jìn) 行相對(duì)地址調(diào)用, 肯定要產(chǎn)生錯(cuò)誤, 所以這里都使用直接地址調(diào)用。 在某些函數(shù)中為了適應(yīng) CYGWIN 使用函數(shù)指針進(jìn)行調(diào)用也是出于同樣的目的。最后是
14、取得返回值,一般一個(gè)32位數(shù)的返回值都是放在寄存器eax中,如果有需要就將其存入 T0 等寄存器變量然后使用。3.4. 微指令中的異常處理模擬指令一般來(lái)說(shuō)都模擬異常處理, DBCT 也不例外。DBCT 的做法是當(dāng)有異常處理的時(shí)候,設(shè)置 st-trap 或者 state-trap 為異常的類型 (定義在 arm2x86.h,TRAP_XXX 的都是),然后根據(jù)情況調(diào)用 X86匯編指令ret返回到正常模式,然 后在非 DBCT 運(yùn)行模式中進(jìn)行實(shí)際的處理。因?yàn)檫@種處理減少了微指令中實(shí)現(xiàn)的難度,所以類似 TRAP_SETS_R15 、 TRAP_SET_CPSR 以及 TRAP_SET_R15 等幾個(gè)
15、非異常處理 也采用了同一種處理方式。3.5. 微指令中的跳轉(zhuǎn)這里的跳轉(zhuǎn)不是指模擬的被模擬指令的跳轉(zhuǎn), 而是指微指令根據(jù)需要跳轉(zhuǎn)指定的長(zhǎng)度。 比如 某條被模擬指令有 condition判斷,其中就會(huì)需要這種跳轉(zhuǎn),當(dāng)condition和PSR中的值不符合的時(shí)候, 就需要跳過當(dāng)前指令被翻譯成的微指令代碼, 這個(gè)時(shí)候就需要跳轉(zhuǎn)過指令的長(zhǎng) 度。在 DBCT 中的做法是先寫一條類似_asm_ _volatile_ (jmp 0xffffffff) ;的指令, 一般來(lái)說(shuō)后 4 個(gè)字節(jié)就是跳轉(zhuǎn)長(zhǎng)度,在翻譯指令的時(shí)候?qū)⒁D(zhuǎn)的長(zhǎng)度寫入就可以。在后面介紹 指令翻譯過程 的時(shí)候,還會(huì)對(duì)微指令跳轉(zhuǎn)的使用再作詳細(xì)介紹。
16、3.6. 微指令分類介紹3.6.1. 概述因?yàn)橐?guī)劃設(shè)計(jì)的問題, 微指令的分類有點(diǎn)亂, 所以就以初始化函數(shù)為分類基礎(chǔ)進(jìn)行分類介紹。3.6.2. arm2x86.c op_init這里初始化的最重要的 2 個(gè)微指令是 op_begin 和 op_begin_test_T0 ,這 2 個(gè)指令都是在翻譯ARM 指令的時(shí)候放在每條指令最開始的部分的。op_begin 是被翻譯的 ARM 指令的 condition 是 AL 或者 NV 也就是不進(jìn)行條件判斷時(shí)候使用的微指令。這里先調(diào)用了函數(shù)arm2x86.c:tea_begin ,而這個(gè)函數(shù)調(diào)用了arm2x86.c: tea_check_out,這個(gè)函數(shù)
17、類似普通指令執(zhí)行模式中指令開始執(zhí)行時(shí)候作的操作一 樣, 檢查是否需要單步返回,檢查是否有硬件中斷發(fā)生進(jìn)行異常處理,檢查當(dāng)前 TB 是否已 經(jīng)標(biāo)記為臟 (如果當(dāng)前 TB 中執(zhí)行的微指令寫了當(dāng)前 TB 相關(guān)的內(nèi)存,就會(huì)有這樣的情況發(fā) 生,這時(shí)返回到普通模式重新執(zhí)行,就會(huì)自動(dòng)對(duì)這個(gè) TB 進(jìn)行重新翻譯 ),最后一步執(zhí)行 armio.c:io_do_cycle 調(diào)用全部虛擬設(shè)備執(zhí)行。 tea_begin 函數(shù)返回以后會(huì)判斷返回值,如果為 真就返回。op_begin_test_T0 是被翻譯的 ARM 指令需要條件判斷時(shí)候使用的微指令 。在這條指令運(yùn)行 以前, 被翻譯指令的 condition 已經(jīng)被存
18、到 T0 中 ,這里首先以 st 和 T0 為參數(shù)調(diào)用 arm2x86.c:tea_begin_test,這個(gè)函數(shù)也是調(diào)用 tea_check_out檢查是否有異常等需要從 DBCT 模式返回普通執(zhí)行模式, 如果沒有則調(diào)用 arm2x86_psr.h:gen_op_condition 判斷當(dāng)前被翻譯指 令是否可以執(zhí)行。tea_begin_test返回后,先判斷是否有異常需要返回普通執(zhí)行模式;然后判斷是否這條指令是否因?yàn)?condition 而不被執(zhí)行,如果是則就執(zhí)行一條 jmp 指令,也就是 前面介紹過的微指令跳轉(zhuǎn)。其他幾個(gè)微指令比較簡(jiǎn)單不作詳細(xì)介紹。3.6.3. arm2x86_test.c
19、:arm2x86_test_init這里初始化了幾個(gè)簡(jiǎn)單的測(cè)試情況然后進(jìn)行一些處理的微指令。3.6.4. arm2x86_shift.c:arm2x86_shift_init這里初始化的是各種 移位微指令 。 這里移位的長(zhǎng)度如果是變量的處理起來(lái)比較簡(jiǎn)單,前面在別的微指令中存到某個(gè)寄存器變 量,然后在這條微指令中直接操作就可以。如果移位的長(zhǎng)度是立即數(shù),則處理辦法有點(diǎn)類似前面的微指令跳轉(zhuǎn)。先用一條類似“T1 = T1<< 31; 的語(yǔ)”句,這樣其最后一個(gè)值是一個(gè) 8位的移位長(zhǎng)度 ,然后在實(shí)際翻譯的過程中 替換成實(shí)際翻譯的立即數(shù)就可以了。3.6.5. arm2x86_psr.c:arm2
20、x86_psr_init這里初始化的是跟 ARM的狀態(tài)寄存器PSR(包括CPSR和SPSR)相關(guān)的微指令。3.6.6. arm2x86_movl.c:arm2x86_movl_init這里 初始化是用來(lái)對(duì)某模擬寄存器或者某寄存器變量等賦值的微指令。其中的立即數(shù)賦值也比較類似前面的微指令跳轉(zhuǎn) ,先用類似 “T2 = ULONG_MAX”; 的語(yǔ)句, 這樣其最后一個(gè)值就是 32 位長(zhǎng)度的立即數(shù) ULONG_MAX ,然后在實(shí)際翻譯的過程中替換成實(shí)際翻譯的立即數(shù)就可以了。3.6.7. arm2x86_mul.c:arm2x86_mul_init這里 初始化是用來(lái)對(duì)乘法指令進(jìn)行模擬的微指令 。3.6.
21、8. arm2x86_mem.c:arm2x86_mem_init這里 初始化是用來(lái)對(duì)內(nèi)存操作進(jìn)行模擬的微指令 。這里對(duì)內(nèi)存的操作采用的辦法是調(diào)用 SKYEYE 原有的內(nèi)存操作函數(shù),直接取得返回值,然 后進(jìn)行各種操作。這里這么做而不是直接訪問相應(yīng)的內(nèi)存地址,因?yàn)橛?MMU 的時(shí)候,需 要先通過 MMU 中的 TLB 和頁(yè)表等轉(zhuǎn)換地址, 而且還有地址是 IO 地址, 所以直接調(diào)用內(nèi)存 操作函數(shù)是比較簡(jiǎn)單的實(shí)現(xiàn)方法。3.6.9. arm2x86_dp.c:arm2x86_dp_init這里初始化的是對(duì) ARM 中 DP 指令 進(jìn)行模擬的微指令。3.6.10. arm2x86_coproc.c:ar
22、m2x86_coproc_init這里初始化的是對(duì) ARM 中 協(xié)處理器指令 進(jìn)行模擬的微指令。3.6.11. arm2x86_other.c:arm2x86_other_init這里對(duì)所有 其他微指令 進(jìn)行初始化。4. 翻譯塊(TB)4.1.概述在 DBCT 中,將 tb.h:TB_LEN 長(zhǎng)度的被模擬指令翻譯成一系列微指令 (這一系列 微指令的長(zhǎng) 度最大值為 tb.h:TB_INSN_LEN_MAX ,由 tb.c:tb_insn_len_max_init 取得 ) ,這一系列微指令(存儲(chǔ)這些微指令的內(nèi)存稱為 TBP)以及地址信息等其他信息封裝在一起稱為一個(gè)TB。在DBCT 初始化的時(shí)候,
23、 會(huì)根據(jù)配置文件以及實(shí)際情況對(duì) TB 進(jìn)行初始化, 介紹 tb_memory_init 的時(shí)候會(huì)詳細(xì)進(jìn)行介紹。4.2. tb.h:struct tb_s這個(gè)結(jié)構(gòu)是 TB 的核心結(jié)構(gòu),每個(gè) TB 塊都將對(duì)應(yīng)一個(gè) tb_s 結(jié)構(gòu)。 下面對(duì)其的每個(gè)成員變量進(jìn)行介紹:struct list_headlist;當(dāng)使用第二種方法使用 TB 的時(shí)候,這個(gè) list 將所有使用過的 TB 全部用 tb.c:tbp_dynamic_list 以及這個(gè) list 結(jié)構(gòu)組成的鏈表連接起來(lái),在每次使用某個(gè) TB 的時(shí)候,都將其先從鏈表中刪 除,然后連接到鏈表的最后。當(dāng)對(duì)某地址進(jìn)行執(zhí)行 ,而所有 TB 都不是這個(gè)地址相
24、關(guān)的,并 且沒有未使用過的 TB ,需要從現(xiàn)有 TB 中選擇一個(gè) TB 使用的時(shí)候,就會(huì) 使用鏈表第一個(gè) TB 。這樣做的好處是,最不常用的已翻譯過的 TB 肯定是在鏈表第一個(gè),選擇其影響會(huì)最 小,提高了效率。在后面介紹翻譯執(zhí)行的時(shí)候會(huì)進(jìn)行更具體的介紹。int ted;這個(gè)變量為 0 表明這個(gè) TB 中數(shù)據(jù)是沒有翻譯過的,為 1 表明其中數(shù)據(jù)是翻譯過的。在需要 標(biāo)記某個(gè)TB為臟的時(shí)候,就可以通過設(shè)置ted為0來(lái)實(shí)現(xiàn)。uint8_t*insn_addrTB_LEN / sizeof(uint8_t *);在翻譯過程中, 將把 每條指令對(duì)應(yīng)的微指令地址 都存儲(chǔ)到這個(gè)數(shù)組中, 這樣在執(zhí)行已經(jīng)翻譯 過
25、的 TB 的時(shí)候,可以直接取得對(duì)應(yīng)地址的微指令地址開始執(zhí)行。原來(lái)的 DBCT 中也采用過不存儲(chǔ)微指令地址,在執(zhí)行的時(shí)候再重新翻譯取得地址的方法, 最多是將取得后的地址存儲(chǔ)起來(lái), 后來(lái)考慮即使將所有地址都存起來(lái)也不 會(huì)使用很多內(nèi)存, 所以就用了所有翻譯過的地址都存起來(lái)的方法。uint8_t*tbp;這個(gè)成員變量指向 當(dāng)前 TB 存儲(chǔ)微指令的內(nèi)存 ,顯然這里指向內(nèi)存塊的大小為 TB_LEN / sizeof (ARMword) * TB_INSN_LEN_MAX 。ARMwordaddr;這個(gè)成員變量是 當(dāng)前 TB 對(duì)應(yīng)的被模擬指令的地址 。ARMwordtran_addr;在 TB 翻譯過程中,
26、并不是一次將整個(gè) TB 范圍內(nèi)的被模擬指令都翻譯成微指令,而是每次 翻譯到一個(gè) 必定發(fā)生返回的指令 ,并且實(shí)際要取得的微指令地址(注意翻 譯是從 TB 開始的地址開始的 ) 也已經(jīng)取得, 就不再繼續(xù)進(jìn)行翻譯, 等下次請(qǐng)求一個(gè)地址比翻譯到的地址大的 時(shí)候,就繼續(xù)對(duì) TB 進(jìn)行翻譯。這個(gè)成員變量 tran_addr 記錄的就是翻譯到的指令地址的下一個(gè)指令的地址,也就是如果繼 續(xù)翻譯的地址。uint8_t *tbp_now;該成員變量指向當(dāng)前可以寫入微指令的地址, 在 tbt-ted 為 0 也就是這個(gè) TB 從 tbt-addr 開 始翻譯的時(shí)候初始化 為 tbt-tbp ,每增加一個(gè)微指令都順序
27、增加,并且在向上面 tran_addr 提到的那種繼續(xù)翻譯的時(shí)候,可以繼續(xù)使用。ARMword last_addr;uint8_t *last_tbp;這2個(gè)成員在指令翻譯的時(shí)候使用。last_addr存儲(chǔ)這個(gè)TB上次被使用時(shí)候的地址,而last_tbp 就是對(duì)應(yīng)的微指令地址。這樣如果下次還使用這個(gè)TB的這個(gè)地址last_addr,就可以快速取得微指令地址last_tbp,提高執(zhí)行速度。ARMwordret_addr;介紹 tran_addr 的時(shí)候,已經(jīng)提到了只翻譯到必定發(fā)生返回的指令就不再繼續(xù)翻譯,但是這 里還有一種情況需要考慮到,就是 DBCT 在翻譯當(dāng)前 TB 范圍內(nèi)的 被模擬指令跳轉(zhuǎn)
28、的時(shí)候 , 都是將這個(gè)跳轉(zhuǎn)指令翻譯為微指令跳轉(zhuǎn)指令 ,而不是通常的設(shè)置 PC 寄存器然后返回的 方 式,這樣的跳轉(zhuǎn)如果是向后跳轉(zhuǎn),并且超過了翻譯結(jié)束的地址肯定是不行的。如何防止提前翻譯結(jié)束?在翻譯開始的時(shí)候設(shè)置ret_addr為0,一旦有TB內(nèi)跳轉(zhuǎn)出現(xiàn),并且這個(gè)地址的值比ret_addr大,就設(shè)置ret_addr為這個(gè)地址。在翻譯完一條指令并確定翻譯 也許可以結(jié)束的時(shí)候,對(duì)ret_addr進(jìn)行檢查,只有在 ret_addr小于下一條將翻譯的指令地址的時(shí)候,翻譯才結(jié)束。4.3. TB_TBT_SIZE 和 TB_TBP_SIZE在 tb.c 中有 TB_TBT_SIZE 和 TB_TBP_SIZ
29、E , TB 的初始化就要根據(jù)其的值來(lái)進(jìn)行,他們的 定義為:#define TB_TBT_SIZEskyeye_config.tb_tbt_size#define TB_TBP_SIZEskyeye_config.tb_tbp_sizeTB_TBT_SIZE是DBCT中所有TB的條目也就是tb_t結(jié)構(gòu)所占空間。如果設(shè)置為0則就在 使用的時(shí)候分配在被模擬內(nèi)存結(jié)構(gòu) armmem.h:mem_state_t-tbt 上,也就是只要運(yùn)行某塊內(nèi) 存,就分配其的 tb_t 結(jié)構(gòu)。 如果設(shè)置為非 0 就使用 tb.c:tbt_table 和 tb.c:tbt_table_size 的內(nèi)存 進(jìn)行動(dòng)態(tài)分配。TB
30、_TBP_SIZE 是 TB 中實(shí)際儲(chǔ)存微指令的內(nèi)存所占空間 。如果設(shè)置為 0則就在使用的時(shí)候 分配在被模擬內(nèi)存結(jié)構(gòu) armmem.h:mem_state_t-tbp 上,也就是只要運(yùn)行某塊內(nèi)存,就分配 其的tbp。如果設(shè)置為非 0會(huì)同時(shí)標(biāo)記tbp_dynamic為1表明是TBP動(dòng)態(tài)分配,并且 TBP 所用的內(nèi)存使用 tb.c:tbp_begin、tb.c:tbp_now 和 tbp_now_size 進(jìn)行動(dòng)態(tài)分配。skyeye_config.tb_tbt_size 和 skyeye_config.tb_tbp_size 是從配置文件中讀出的值, 他們的初始 化也就是 設(shè)置默認(rèn)值在 skyey
31、e_options.c:skyeye_option_init 函數(shù)中。在這里我們可以看到 config-tb_tbt_size 也就是 TB_TBT_SIZE 初始化為 0,因?yàn)?tb_t 結(jié)構(gòu)占用空間不 大; config-tb_tbp_size 也就是 TB_TBP_SIZE 初始化為 TB_TBP_DEFAULT(1024 * 1024 * 64),這里沒有也初始化因?yàn)槊織l被模擬的 ARM 指令都包含若干條微指令,這樣跟 一個(gè) TB 存儲(chǔ) 的指令對(duì)應(yīng)的微指令存儲(chǔ)空間會(huì)比較大 ,甚至有超過 32 位尋址 空間大小的情況, 所以這里 一般不設(shè)置為 0。注意 TB_TBT_SIZE 和 TB_
32、TBP_SIZE 并不是從配置文件中讀出后直接使用,而是在 tb_memory_init 進(jìn)行過初始化后才使用,和其 相關(guān)的幾個(gè)變量也是在 tb_memory_init 中進(jìn)行的初始化。4.4. tb.c:tb_memory_init這個(gè)函數(shù)用來(lái)對(duì) DBCT 中的 TB 進(jìn)行初始化。下面介紹執(zhí)行過程: 第一步,先判斷 TB_TBT_SIZE 是否為 0,如果不為 0,就會(huì)執(zhí)行一部分針對(duì) TB_TBT_SIZE 的代碼。注意這里我犯了一個(gè)比較大的錯(cuò)誤,其中的結(jié)構(gòu)應(yīng)該使用tb_t,而我這里全部錯(cuò)誤的使用了 tb_cache_t,而這個(gè)tb_cache_t也是一個(gè)不再需要的東西,早應(yīng)該從代碼中去掉,
33、下面的 介紹全都假定成tb_cache_t已經(jīng)被換成了 tb_t。先對(duì)TB_TBT_SIZE進(jìn)行基本的處理 和檢查,然后取得所有被模擬內(nèi)存一共需要 tb_t 所 占的空間,其跟 TB_TBT_SIZE 進(jìn)行比 較。如果TB_TBT_SIZE大于等于這個(gè)值,則表明 DBCT不需要?jiǎng)討B(tài)分配tb_t來(lái)節(jié)省空間, 就設(shè)置 TB_TBT_SIZE 為 0,使用固定分配的形勢(shì)。如果 TB_TBT_SIZE 小于這個(gè)值,則初 始化存儲(chǔ) tb_t 的空間 tbt_table 和 tb_t 的數(shù) 量 tbt_table_size 。這樣 TB_TBT_SIZE 就初始化完成,同時(shí)還對(duì) tbt_table 和 t
34、bt_table_size 進(jìn)行了設(shè)置。第二步,如果 TB_TBP_SIZE 為非 0,則對(duì)其進(jìn)行基本的處理和檢查。第三步,再次判斷 TB_TBT_SIZE 是否為 0,然后對(duì) TB_TBP_SIZE 進(jìn)行處理。如果TB_TBT_SIZE不為0,首先取得這個(gè)長(zhǎng)度的 tb_t結(jié)構(gòu)組需要的tbp的長(zhǎng)度tmp_u64, 跟 TB_TBP_SIZE 進(jìn)行比較。如果 TB_TBP_SIZE 大于 tmp_u64 或者 TB_TBP_SIZE 為 0, 則 TB_TBP_SIZE 設(shè)置為這個(gè)值,這么作因?yàn)樵?TB_TBT_SIZE 動(dòng)態(tài)分配后, TB 無(wú)法對(duì)大 于其管理范圍的微指令內(nèi)存 TBP 進(jìn)行管理,
35、所以進(jìn)行這個(gè)設(shè)置。如果 TB_TBP_SIZE 小于 tmp_u64,則設(shè)置 tb.c:tbp_dynamic為1,也就是設(shè)置 DBCT中TBP為動(dòng)態(tài)分配。如果 TB_TBT_SIZE 為 0,將判斷 TB_TBP_SIZE 是否為 0。如果為 0 很顯然不需要再作任何 初始化工作, tbp_dynamic 使用默認(rèn)值 0,全部在 DBCT 運(yùn)行時(shí)根據(jù)需要分配在 mem_state_t-tbt 和 mem_state_t-tbp 上就可以。如 果不為 0 則先取得全部被模擬內(nèi)存需要 的TBP的長(zhǎng)度tmp_u64,然后跟 TB_TBP_SIZE進(jìn)行比較。如果 TB_TBP_SIZE大于等于 tm
36、p_u64,則表明TBP已經(jīng)不需要?jiǎng)討B(tài)分配,就設(shè)置 TB_TBP_SIZE為0。如果TB_TBP_SIZE 小于tmp_u64,則表明需要?jiǎng)討B(tài)分配,設(shè)置tbp_dynamic為1。這樣 TB_TBP_SIZE 就初始化完成,同時(shí)也根據(jù)需要對(duì) tbp_dynamic 進(jìn)行了設(shè)置。第四步,這時(shí) TB_TBP_SIZE 的值已經(jīng)得到了確定,這里就是給 tbp_begin 分配空間,注意 這里用 mmap 分配內(nèi)存的時(shí)候設(shè)置了權(quán)限為可運(yùn)行 PROT_EXEC 。然后對(duì) tbp_now_size 和 tbp_now 也進(jìn)行了初始化。這樣用來(lái)進(jìn)行 TBP 動(dòng)態(tài)分配的 tbp_begin、tbp_now_s
37、ize 和 tbp_now 進(jìn)行了初始化??偨Y(jié)一下, DBCT 中用來(lái)維護(hù) TBT 和 TBP 動(dòng)態(tài)分配的幾個(gè)變量用的有點(diǎn)繁瑣了。4.5. tb.c:tb_insn_len_max_init 這個(gè)函數(shù)用來(lái)對(duì) tb.c:tb_insn_len_max 也就是 TB_INSN_LEN_MAX 進(jìn)行了初始化。 做法是將所有被翻譯指令被翻譯成的微指令長(zhǎng)度都取得,然后進(jìn)行比較,將最長(zhǎng)的設(shè)置為 tb_insn_len_max 。5. 初始化函數(shù) arm2x86.c:arm2x86_init這個(gè)函數(shù)是 DBCT 的初始化函數(shù),其在函數(shù) arminit.c:ARMul_Reset 中被調(diào)用。 這個(gè)函數(shù)先會(huì)調(diào)用
38、前面介紹過的幾個(gè)微指令初始化函數(shù),然后是函數(shù) tb_insn_len_max_init , 最后是函數(shù) tb_memory_init 。6. 翻譯執(zhí)行過程6.1.armemu.c:ARMul_Emulate32_dbct這是 整個(gè) DBCT 翻譯執(zhí)行的核心函數(shù) ,類似普通指令執(zhí)行方式的 ARMul_Emulate32 函數(shù), 也是在 arminit.c:ARMul_DoProg 和 arminit.c:ARMul_DoInstr 被調(diào)用。下面介紹執(zhí)行過程: 第一步,給 R15 寄存器也就是 PC 寄存器的值增加一個(gè)指令長(zhǎng)度 INSN_SIZE ,這是因?yàn)?ARM 的多級(jí)流水線PC寄存器對(duì)應(yīng)用是
39、非透明的,而在這個(gè)函數(shù)外面的函數(shù)都將R15當(dāng)作當(dāng)前PC值,所以在開始執(zhí)行前先對(duì)R15寄存器進(jìn)行設(shè)置。第二步,設(shè)置 state-trap 為 0。第三步,調(diào)用函數(shù)tb.c:tb_find,在這個(gè)函數(shù)中 根據(jù)參數(shù)提供的PC寄存器值,進(jìn)行全部的分 配TB以及指令翻譯的工作,最后將跟PC對(duì)應(yīng)的微指令 地址返回。如果返回NULL則表示執(zhí)行失敗,設(shè)置 state-trap為TRAP_INSN_ABORT 也就是取指異常,跳轉(zhuǎn)到后面對(duì) state-trap 進(jìn)行處理的部分。第四步, 對(duì)將在微指令中作為變量的寄存器進(jìn)行保存 ,保存的原因前面介紹過, 因?yàn)檫@幾個(gè) 寄存器的值都是被調(diào)用函數(shù)來(lái)保存,所以在這里進(jìn)行保
40、存。調(diào)用取得的指向微指令內(nèi)存的指針gen_func。返回后恢復(fù)幾個(gè)寄存器的值。第五步,在介紹微指令的時(shí)候, 介紹過異常等特殊情況, 都是先設(shè)置state-trap然后就返回, 而這里就是實(shí)際對(duì) 異常等進(jìn)行處理 的地 方。這部分代碼比較清晰,就是根據(jù) state-trap 進(jìn) 行不同的處理,不作詳細(xì)介紹。第六步,判斷是否還繼續(xù)執(zhí)行 ,或者函數(shù)返回。如果繼續(xù)執(zhí)行就返回到第二步。第七步,state-Reg15減INSN_SIZE,恢復(fù)PC指向當(dāng)前程序執(zhí)行的地址,然后返回。6.2. tb.c:tb_find在這個(gè)函數(shù)中 根據(jù)參數(shù)提供的 PC 寄存器值,進(jìn)行全部的分配 TB 以及指令翻譯的工作 , 最
41、后將跟 PC 對(duì)應(yīng)的微指令地址返回 。下面介紹執(zhí)行過程:第一步,調(diào)用 armmmu.c:mmu_v2p_dbct 函數(shù)通過 SKYEYE 的 MMU 功能 取得跟執(zhí)行地址 ADDR對(duì)應(yīng)的被模擬物理地址addr,如果失敗則函數(shù)出錯(cuò)返回。然后通過TB_ALIGN取得跟TB_LEN長(zhǎng)度對(duì)齊的地址 align_addr,這個(gè)地址就是 addr對(duì)應(yīng)TB的地址。第二步, 檢查 align_addr 是否和 靜態(tài)局部變量 save_align_addr 相同, 如果相同表明前面已經(jīng) 對(duì)這個(gè)物理地址的 TB 進(jìn)行過請(qǐng)求,已經(jīng)取 得了翻譯前需要的各種指針,都存在靜態(tài)局部 變量中, 所以跳過分配 TB 的代碼直接
42、執(zhí)行指令翻譯的代碼。 注意 save_align_addr 的初始值 為 0x1 是為了保證不跟任何地址一樣。第三步,這里開始的就是對(duì) TB 進(jìn)行分配的代碼, 首先判斷 tbt_table_size 是否為 0 來(lái)確定 tb_t 是否是動(dòng)態(tài)分配的。第四步,如果是動(dòng)態(tài)分配,就會(huì)以哈希計(jì)算的方法從 tbt_table 中取出跟 align_addr 對(duì)應(yīng)地址 的 tb_t。比較tbt-addr和align_addr,如果tbt-addr跟align_addr不同表明其先前是其他地址的TB,就會(huì)進(jìn)行一些清除過去記錄的工作,設(shè)置 tbt-ted 為 0,設(shè)置 tbt-addr 為 align_addr
43、。然后就是取得tbt-tbp也就是TBP。如果tbt-tbp為NULL,則表明這個(gè) TB中的TBP沒有 分配或者已經(jīng)被 其他 TB 使用,這時(shí)候需要調(diào)用 tb.c:tb_get_tbp 進(jìn)行 TBP 的分配。如果 tbt-tbp 不為 NULL ,則 TBP 已經(jīng)分配過, 則按照前面在介紹 tbt-list 那樣,先將其從 tbp_dynamic_list 鏈表中刪除掉。第五步, 如果不是動(dòng)態(tài)分配, 首先通過函數(shù) tb.c:tb_get_mbp 取得 align_addr 對(duì)應(yīng)模擬內(nèi)存的 mem_bank_t 結(jié)構(gòu)指針 mbp。檢查結(jié)構(gòu)中的 state-mem.tbtbank_num 是否為空
44、,如果為空表明 tbt 和 tbp 未分配相應(yīng)的空 間,如果 tbp_dynamic為0表明是靜態(tài)分配 TBP,則將先給 state-mem.tbpbank_num分配 空間,然后給 state-mem.tbtbank_num 分配空間。分配好空間后設(shè)置 TB 結(jié)構(gòu)。在取得 TB 結(jié)構(gòu)后檢查 tbt-tbp 也就是 TBP 是否為空。如果為空就根據(jù) tbp_dynamic 對(duì)其進(jìn) 行設(shè)置,動(dòng)態(tài)分配跟前面一樣使用 tb.c:tb_get_tbp 函數(shù),靜態(tài)從 state-mem.tbpbank_num 中取得。如果不為空也跟前面一樣判斷 tbp_dynamic 根據(jù)情況將 TB 結(jié)構(gòu)從列表中刪除
45、?,F(xiàn)在, TB 結(jié)構(gòu)和其中的 TBP 都已經(jīng)取得。第六步,用取得的 TB 進(jìn)行一些設(shè)置。設(shè)置 state-tb_now 為剛?cè)〉玫?TB 結(jié)構(gòu),其的作用是微指令在運(yùn)行的時(shí)候可以訪問當(dāng)前運(yùn)行 的TB,比如在標(biāo)記 TB為臟之后,微指令可以馬上判斷出來(lái)然后退出。設(shè)置為 save_align_addr為 align_addr,目 的在第二步介紹過。如果 tbp_dynamic 為真表明是動(dòng)態(tài) TBP 分配,將 TB 結(jié)構(gòu)增加到 tbp_dynamic_list 鏈表的最后面,這么作的目的在介紹 tbt-list 已經(jīng)介紹過。第七步,現(xiàn)在開始的就是對(duì)被模擬指令進(jìn)行翻譯的代碼。 先判斷 tbt-ted 的
46、值來(lái)確定這個(gè) TB 結(jié)構(gòu)是否被翻譯過。第八步,如果這個(gè) TB 結(jié)構(gòu) 已經(jīng)翻譯過 。先檢查 tbt-last_addr 是否跟 addr 相同,如果相同就返回tbt-last_tbp 。這里在前面介紹tbt-last_addr 和 tbt-last_tbp 的已經(jīng)介紹過了。判斷需要翻譯的物理地址 addr 是否大于等于 tbt-tran_addr ,這個(gè) tbt-tran_addr 在前面也介 紹 過。如果 addr 小于 tbt-tran_addr 則表明 TB 中現(xiàn)有微指令代碼已經(jīng)可以滿足 addr 的需要,直接 從 tbt-insn_addr 取出跟 addr 對(duì)應(yīng)的 TBP 地址作為返回
47、值設(shè)置到 ret 就可以。如果 addr 大于等于 tbt-tran_addr 則表明需要繼續(xù)翻譯, 首先取得跟 tbt-tran_addr 地址對(duì)應(yīng) 的 在被模擬內(nèi)存塊中指針real_begin_addr ,以及和 addr 對(duì)應(yīng)的在被模擬內(nèi)存塊中指針real_addr。然后就調(diào)用tb.c:tb_translate從給定的real_begin_addr開始的內(nèi)存進(jìn)行翻譯。最后 取得跟 addr 對(duì)應(yīng)的微指令地址設(shè)置到 ret。第九步,如果這個(gè) TB 結(jié)構(gòu) 還沒有翻譯過 ,就需要重新翻譯。也是首先取得跟tbt-tran_addr地址對(duì)應(yīng)的在被模擬內(nèi)存塊中指針real_begin_addr,以及
48、和addr對(duì)應(yīng)的在被模擬內(nèi)存塊中指針 real_addr。然后初始化tbt-tran_addr為align_addr,初始化tbt-tbp_now為tbp,這兩個(gè)成員變量在前面介紹過,這里就不再介紹。調(diào)用tb.c:tb_translate從給定的real_begin_addr開始的內(nèi)存進(jìn)行翻譯。最后取得跟addr對(duì)應(yīng)的微指令地址設(shè)置到ret。并且設(shè)置tbt-ted為1表明 這個(gè)TB已經(jīng)被翻譯過。現(xiàn)在返回值ret,也就是跟ADDR對(duì)應(yīng)的微指令地址已經(jīng)取得。第十步,將 addr 和 ret 都設(shè)置到 tbt-last_addr 和 tbt-last_tbp 上,將 ret 返回。6.3. tb.c: tb_get_tbp這個(gè)函數(shù)用來(lái)對(duì) TBP 進(jìn)行動(dòng)態(tài)分配。下面介紹執(zhí)行過程:第一步,判斷 tbp_now
溫馨提示
- 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ì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 第2.6講 指數(shù)與指數(shù)函數(shù)(解析版)-2024年高考數(shù)學(xué)一輪復(fù)習(xí)精講精練寶典(新高考專用)
- 浙教版2023小學(xué)信息技術(shù)六年級(jí)上冊(cè)《算法的多樣性》教學(xué)設(shè)計(jì)及反思
- (一模)萍鄉(xiāng)市2025年高三第一次模擬考試歷史試卷(含答案解析)
- 2025年B2B營(yíng)銷業(yè)務(wù) AI提示詞手冊(cè)
- 陶瓷攔水帶施工方案
- 高樓地鐵隧道施工方案
- 砂漿基礎(chǔ)知識(shí)培訓(xùn)課件
- 2025年山東聊城高三一模高考數(shù)學(xué)試卷試題(含答案詳解)
- 2025年藥具科技工作培訓(xùn)標(biāo)準(zhǔn)教案
- 寫贈(zèng)予房產(chǎn)合同范例
- (精心整理)林海雪原閱讀題及答案
- 適合汽車行業(yè)的英語(yǔ)愛好者
- 專用夾具設(shè)計(jì)說(shuō)明書
- 氣缸選型介紹.ppt課件
- 國(guó)內(nèi)汽車產(chǎn)銷數(shù)據(jù)四個(gè)統(tǒng)計(jì)口徑數(shù)據(jù)利益鏈
- 消防設(shè)施檢測(cè)內(nèi)容及流程
- 零序保護(hù)整定說(shuō)明
- 帆船帆板俱樂部創(chuàng)業(yè)計(jì)劃書
- 砌體墻的基本構(gòu)造做法及附圖
- 第二章 法國(guó)學(xué)前教育
- 精雕JDPaint常用快捷鍵
評(píng)論
0/150
提交評(píng)論