通用Thunk
2010-07-15 20:45:23 来源:WEB开发网3、使用__cdecl 的成员函数使用 RET 返回
CdeclToCdecl类与ThisToCdecl十分相似:
thunk对象调用一个 Hook函数来准备this指针,保存old_esp,返回地址,然后跳转到被调用者。
被调用者返回之后,thunk代码修改ESP,然后跳转到调用者。
不同之处在Hook函数,它将this指针插入到参数1与返回值之间,而不是将它传送到ECX。
更详细的实现见 CdeclToCdecl.h 和CdeclToCdecl.cpp
设计 StdToCdecl
让我们拿它和CdeclToCdecl做比较。
唯一不同的是,成员函数使用RET N+4而不是 RET。
当被调用者返回后,不管是RET N+4,还是RET,ESP都将被恢复。
因此,CdeclToCdecl可以胜任StdToCdecl
所以,StdToCdecl 只是一个 typedef “typedef CdeclToCdecl StdToCdecl;” ^_^
设计 CdeclToStd
使用__stdcall 的调用者将堆栈平衡工作交给被调用者。
使用__cdecl 的被调用者使用RET返回到调用者。
而关于ESP的信息在这之中丢失了!
非常不幸,我没办法设计出一个通用的thunk类。 -_-
关于 __fastcall 和更进一步的工作
__fastcall调用约定将小于或等于dword的头2个参数用ECX和EDX传递。
所以设计出一个通用的thunk类似乎是不可能的。(因为和参数相关)
但是特殊的解决方案是存在的。
我认为Thunk的理论比实现更重要。
在你打算解决一个特定的问题 (比如为了特定参数的 __fastcall 和 CdeclToStd ),在另一平台上实现,或者想继续优化这份实现的时候,如果这篇文章能对你有所帮助,我非常高兴 ^_^
源代码可以任意使用,作者不会为此承担任何责任 ^_^。
关于FlushInstructionCache
这些类通常是按如下方式被使用:class CNeedCallback {
private:
CThunk m_thunk;
public:
CNeedCallback() :m_thunk(this,Thunk::Helper::PointerToInt32(&CNeedCallback::Callback)) {}
private:
returnType Callback(….) {}
}
所以,每个thunk对象的Obj和Method属性在构造后就不再改变。我不知道在这种情况下FlushInstructionCache是否有必要。如果你认为有,请在 ThunkBase.cpp中定义 THUNK_FLUSHINSTRUCTIONCACHE ,或者简单的去掉第4行注释。
特别感谢
Illidan_Ne 和Sean Ewington ^_^.
本文配套源码
更多精彩
赞助商链接