我在网上阅读了一些关于 Vtable thunk 的文章,我在某处读到了 thunk 可用于挂钩 /chain 过程调用。
它可以实现吗?
有谁知道它是如何工作的,我也找不到解释 thunk 的好资源。对此有什么建议吗?
以 v-table thunk 的样式实现原始 thunk 是最后的手段。无论您需要完成什么,很可能都可以使用包装函数来实现,而且痛苦会少得多。
通常,thunk 执行以下操作:
要查看它如何工作的示例,让我们转向我们的好朋友 Raymond Chen 和他对调整器 thunk 的讨论:
http://blogs.msdn.com/oldnewthing/archive/2004/02/06/68695.aspx
他使用的thunk如下:
[thunk]:CSample::QueryInterface`adjustor{4}':
sub DWORD PTR [esp+4], 4 ; this -= sizeof(lpVtbl)
jmp CSample::QueryInterface
正如他所描述的,您有一个通过多个接口实现相同方法的类,因此它有多个 v-table。(如果您不了解 COM,您只需要知道它直接与 v-tables 一起使用,因此指向特定接口的指针必须依次包含指向该接口所有方法的函数指针。)
如果您在特定插槽中实现两个具有不同方法的接口,则需要多个 v-table。但是,您只需编写一次重叠方法,因此该方法需要能够使用两个“this”指针。为此,编译器会生成一个方法来进行必要的修复并调用原始实现。
因此,此 thunk 执行以下步骤:
这就是jmp
指令的来源。通常,如果您要使用 调用该函数call
,它会返回给您,而您必须ret
返回给您的调用者。由于无需清理,编译器会进行优化,将执行直接移至实际实现,让实际实现的 return 语句返回给调用者。这只是一种优化,而不是 thunking 的基本部分。例如,16/32 位 thunk 会根据需要在 16 位和 32 位之间转换输入/输出参数,因此不能跳过清理步骤;它必须call
,不是jmp
。
这个故事的寓意是:如果你需要做一些jmp
你不能直接用 C++ 或你选择的其他高级语言编写的优化,那么继续写一个汇编语言 thunk。否则,只需编写一个包装器并完成它。
老实说,听起来您要求进行性能优化,并且大多数时候(1)编译器在优化方面比我们想象的要好,(2)它不会像您想象的那样给您带来很大的改进。
好吧,您读到 thunk 是一种解决方案,而现在您正在寻找要解决的问题?
Thunks 通常是简短的“转发”功能,提供较小的(通常是硬编码的)调整。
目前,维基百科对VTable 块进行了很好的解释。他们使用通用模式:生成一个小函数以避免在运行时进行计算/额外工作。
我见过/使用过的其他地方:
将窗口句柄与窗口对象相关联:对于每个要子类化的窗口,动态生成一个小的 thunk,它使用对象引用调用窗口过程,然后将 thunk 用作窗口过程。
延迟加载 DLL:thunk 确保在第一次调用任何函数时加载 DLL。
捕获 COM 接口调用:thunk 为诊断提供注入点,并跳转到实际方法。