Windows下动态加载可执行代码原理简述
xiaotie同學比較蛋疼,問C#里面能不能動態加載SIMD的匯編代碼。C#我不知道,反正c/c++下面這事情很好做。順手花了幾個小時寫了個例子和這篇博客。
總的來說,windows下要動態加載binary的話,基本上分以下幾步。
1. 首先要得到可執行代碼的binary。 無論是在程序里面編譯也好,或者從什么地方讀出來,或者用戶手把手的敲進去。
2. 為這些binary分配一段具有可執行屬性的內存。這是因為有Data Execution Prevention的存在,一般用malloc和new分配的內存頁面不具有可執行這個屬性,一旦執行就會產生STATUS_ACCESS_VIOLATION的異常。
3. 下一步就是要跳轉到這段內存上去執行了,可能要寫一些匯編指令,在調用的過程中要注意棧是否平衡。
基本上就是這三點了,下面來看具體的代碼:
第一步,拿到可執行的binary。這里我寫了一個用SIMD指令的fastercopy函數,然后編譯以后把它的二進制代碼寫成一個數組。
int emitcode[] ={0x83ec8b55,0x565340ec,0x0c758b57,0x8b087d8b,
0x348d104d,0xcf3c8dce,0x6f0fd9f7,0x6f0fce04,
0x0f08ce4c,0x10ce546f,0xce5c6f0f,0x646f0f18,
0x6f0f20ce,0x0f28ce6c,0x30ce746f,0xce7c6f0f,
0x04e70f38,0x4ce70fcf,0xe70f08cf,0x0f10cf54,
0x18cf5ce7,0xcf64e70f,0x6ce70f20,0xe70f28cf,
0x0f30cf74,0x38cf7ce7,0x7508c183,0xf8ae0fad,
0x5e5f770f,0x5de58b5b,0xccccccc3};
fastercopy函數是這樣寫的
View Code void fastercopy(void* dst, void* src, int len){
__asm {
mov esi, [src] // source array
mov edi, [dst] // destination array
mov ecx, [len] // number of QWORDS (8 bytes)
lea esi, [esi+ecx*8] // end of source
lea edi, [edi+ecx*8] // end of destination
neg ecx // use a negative offset
copyloop:
movq mm0, qword ptr[esi+ecx*8]
movq mm1, qword ptr[esi+ecx*8+8]
movq mm2, qword ptr[esi+ecx*8+16]
movq mm3, qword ptr[esi+ecx*8+24]
movq mm4, qword ptr[esi+ecx*8+32]
movq mm5, qword ptr[esi+ecx*8+40]
movq mm6, qword ptr[esi+ecx*8+48]
movq mm7, qword ptr[esi+ecx*8+56]
movntq qword ptr[edi+ecx*8], mm0
movntq qword ptr[edi+ecx*8+8], mm1
movntq qword ptr[edi+ecx*8+16], mm2
movntq qword ptr[edi+ecx*8+24], mm3
movntq qword ptr[edi+ecx*8+32], mm4
movntq qword ptr[edi+ecx*8+40], mm5
movntq qword ptr[edi+ecx*8+48], mm6
movntq qword ptr[edi+ecx*8+56], mm7
add ecx, 8
jnz copyloop
sfence // flush write buffer
emms
}
}
第二步,分配內存了。這里調用的是VirtualAlloc這個windows函數。在最后一個參數指定PAGE_EXECUTE_READWRITE屬性。
void* address = NULL;address= VirtualAlloc(NULL,
sizeof(emitcode),
MEM_COMMIT|MEM_RESERVE,
PAGE_EXECUTE_READWRITE);
memcpy(address,emitcode,sizeof(emitcode));
第三步,調用這個存在address中的代碼。
可以自己寫匯編代碼調用:
__asm {push 20h
mov eax,dword ptr [src]
push eax
mov ecx,dword ptr [dst]
push ecx
mov ecx, dword ptr [address]
call ecx
add esp,0Ch
}
也可以使用函數指針來調用,反正知道函數的原型是啥。
typedef void (*FASTCALL)(void* dst, void* src, int len);FASTCALL fastcall;
fastcall = (FASTCALL)address;
fastcall(dst2,src,64/2);
這些實驗是在Win7+VS2010 debug版本做的
如果園子們在其他環境下做不出來,概不負責。
如果在Win7+VS2010也做不出來,也概不負責。
工程文件打包下載在這里(http://files.cnblogs.com/aoaoblogs/EmitSIMD.7z)
據說博客要配圖才有說服力,七夕到了,送些福利給QS們
轉載于:https://www.cnblogs.com/aoaoblogs/archive/2011/08/04/2127143.html
總結
以上是生活随笔為你收集整理的Windows下动态加载可执行代码原理简述的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 发现自己的代码写的越来越玄幻了
- 下一篇: 不装oracle进行远程连接解决办法 .