通用Thunk
2010-07-15 20:45:23 来源:WEB开发网优化
sizeof(ThisToCdecl)==36 , 我认为这是不可接受的。
如果我们使用PUSH old_return 来代替 MOV DWORD PTR[ESP],old_return,可以节省2字节(因此,我们必须在保存old_esp之前弹栈),于此同时,也增加了一个额外的堆栈操作。(见 ThisToCdecl 34.h)
在这种情况下,相对于时间上的优化,我更加倾向空间上的优化。所以第3个实现如下:
我们可以使用一个叫做Hook的函数来准备this指针,保存old_esp和返回地址,设置被调用者的返回地址,然后跳转到被调用者。这样,thunk对象将包含更少的指令,而变的更小。(23字节)ThisToCdecl.h
这些机器码首先调用“Hook”函数,这个函数做如下工作:
#define THIS_TO_CDECL_CODES()
/* CALL Hook */
CONST CODE_FIRST(byte,CALL,0xE8)
CONST CODE(dword,HOOK,0)
/* this and member function */
CODE(dword,m_memFunc,0)
CODE(dword_ptr,m_this,0)
/* member function return here! */
/* MOV ESP,oldESP */
CONST CODE(byte,MOV_ESP,0xBC)
CONST CODE(dword,oldESP,0)
/* JMP oldRet */
CONST CODE(byte,JMP,0xE9)
CONST CODE(dword,oldRet,0)
1. 保存 the oldESP 和 oldRet。
2. 将被调用者的返回地址设置到 “member function return here!”。
3. 将ECX设置为this指针。
4. 跳转到成员函数
当成员函数返回后,剩下的thunk代码将修改ESP然后返回到调用者。
Hook函数被实现为:void __declspec( naked ) ThisToCdecl::Hook() {
_asm {
POP EAX //1
// p=&m_memFunc; &m_this=p+4; &oldESP=p+9; &oldRet=p+14
// Save ESP
MOV DWORD PTR [EAX+9],ESP //3
ADD DWORD PTR [EAX+9],4 //4
// Save CallerReturn(by offset)
//src=&JMP=p+13,dst=CallerReturn,offset=CallerReturn-p-13-5
MOV ECX,DWORD PTR [ESP] //3
SUB ECX,EAX //2
SUB ECX,18 //3
MOV DWORD PTR [EAX+14],ECX //3
// Set CalleeReturn
MOV DWORD PTR [ESP],EAX //3
ADD DWORD PTR [ESP],8 //4
// Set m_this
MOV ECX,DWORD PTR [EAX+4] //3
// Jump to m_memFunc
JMP DWORD PTR[EAX ] //2
}
}
更多精彩
赞助商链接