構造使用類C語言的指令碼引擎(2)
作者 :kevin_qing
轉貼請註明
考慮到指令碼編譯器部分可以單獨作為一個進程實現,並且編譯器需要虛擬機器對其結果進行調試,
目前先從最底層的虛擬機器部分開始開發。
1.虛擬機器結構.
考慮到目前不支援內建函式定義,採用寄存器方式,以後擴充棧也較為方便
變數寄存器REG[256] 其中REG[0]為外部call時存放傳回值
指令寄存器IP;
比較寄存器CFlag;
程式碼片段,資料區段均為虛擬指令不可改寫的
1.虛擬機器運行模式
使用函數數組實現,指令採取順序編碼,且按word方式對齊以加快數組索引速度
運行時函數
bool run(){
while(bRun_){
uint16_t op=op_readw();
assert((op>=0) &&(op<countof(vmop) );
vmop[op]();
}
}
2.指令定義
[r]代表REG[n]
[i]立即數
[s]字串
[f]外部函數ID
[ip]絕對ip地址
mov 類:
mov [r] [r]
mov [r] [i]
運算比較指令等
重點說明函數call和switch
SReset //重設選擇隊列
case [i] [ip]//選擇id/ip對
switch [r] //開始跳轉
--------------------------
FReset //重設外部函數參數隊列
FPush [r] //加入一個數字參數
FPush [s] //加入一個字串參數
FPush [i]
FCall [f] //調用函數
---------------------------
switch可以不使用虛擬指令進行多次比較,而在vmop_switch()內部進行比較.
如果輸入的case是排序的話,會大大節約比較時間
--------------------------------------------------------------------------
fcall的參數隊列使類似printf這種可變參數得以可行,也就是說,所有外部函數都可以是可變參數。
這裡是我的外部函數定義
#define SC_API __cdecl
typedef int (SC_API *FP_SC_API)(int nParm,...);
struct SC_API_TAB{
FP_SC_API pAPI;
int nParm;
const char* APIname;
};
#define DECL_SCAPI(name,nParm) {&name,nParm,#name}
extern const SC_API_TAB api_table[];
SC_API_TAB api_table[]={
DECL_ACAPI(say,1),
.....
};
vmop_fcall的實現:採用inline彙編,因為不管是C還是C++都不能動態實現可變參數調用。
vmop_fcall(){
int nParm=this->nParm;
DWORD* pParm=fifo_parm;
WORD fd=ipGetW();
void* pf=api_table[fd].pAPI;
DWORD retc;
__asm{
mov ecx,nParm
inc ecx
mov ebx,pParm
mov edx,pf
push_loop:
dec ecx
jz call_fun
mov eax,[ebx]
add ebx,4
push eax
jmp push_loop
call_fun:
mov ecx,nParm
inc ecx
push ecx
call edx
mov retc,eax
pop ecx
dec ecx
shl ecx,2
add esp,ecx
}
Reg[0]=retc;
}
}
fcall目前未做任何最佳化
其他指令都很容易實現,就不一一說明了。
調試:
逐步執行和寄存器參看都很容易實現,也不說了.
反組譯碼我是通過字串數組實現
const char* OP_[]={
"HALT",
"MOV",//move r r
"MOV",//move r i
.....
};
const uint32_t OP_SIZE[]={
0,
2,
4,
....
};
反組譯碼時通過查表即可實現