這邊是參考How to JIT - an introduction 和Hello, JIT World: The Joy of Simple JITs 的感想。
Sample Code 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/mman.h> void * alloc_executable_memory (size_t size ) { void * ptr = mmap(0 , size , PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1 , 0 ); if (ptr == (void *)-1 ) { perror("mmap" ); return NULL ; } return ptr; } void emit_code_into_memory (unsigned char * m) { unsigned char code[] = { 0x48 , 0x89 , 0xf8 , 0x48 , 0x83 , 0xc0 , 0x04 , 0xc3 }; memcpy (m, code, sizeof (code)); } const size_t SIZE = 1024 ;typedef long (*JittedFunc) (long ) ;void run_from_rwx () { void * m = alloc_executable_memory(SIZE); emit_code_into_memory(m); JittedFunc func = m; int result = func(2 ); printf ("result = %d\n" , result); }
我們知道,為了安全性,Process被執行的時候,只有Code section有執行的權限,在Data section或是Heap的資料無法執行。 因此上面的alloc_executable_memory
要求OS分配一塊記憶體,不僅可讀寫,而且可執行 。這是所有JIT不可或缺得部份。 Security的部份,可以參照上面兩偏的方法,一開始先分派城可讀寫,把Machine code複製進去之後,關閉寫入,更改成可執行。
雖然上面的程式展示了JIT如何運行,不過最大的問題是,誰看得懂emit_code_into_memory
那群鬼Code是幹甚麼的 ,Assemlby Code都很難讀了,更何況一堆數字。 因此人門想了一堆方法,用以簡化這個過程。
Use AsmJIT for simplify work 直接看程式碼吧。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 #include <asmjit/asmjit.h> using namespace asmjit;int main (int argc, char * argv[]) { JitRuntime runtime; X86Compiler c (&runtime) ; c.addFunc(kFuncConvHost, FuncBuilder1<int , int >()); X86GpVar a (c, kVarTypeInt32, "a" ) ; c.setArg(0 , a); c.add(a, 4 ); c.ret(a); c.endFunc(); void * funcPtr = c.make(); typedef int (*FuncType) (int ) ; FuncType func = asmjit_cast<FuncType>(funcPtr); int x = func(2 ); printf ("result = %d\n" , x); runtime.release ((void *)func); return 0 ; }
如果之前有看過LLVM API的話,發現他門實在相當類似。好得方法就會互相參考。 比起文章一開始的程式碼,這方式的可讀性強多了。