我最近一直在查看计算机上的各种 DLL,我认为一个不错的起点是图像入口点(通常是 _DllMainCRTStartup)。
从我所看到的 CRT 源代码 (MSVC) 来看,它使用相同的参数(HMODULE、DWORD、LPVOID)调用另一个函数(__DllMainCRTStartup)。然而,我看过的许多二进制文件似乎都偏离了这一点:
push dword ptr [ebp+8]
mov ecx,dword ptr [ebp+10h]
mov edx,dword ptr [ebp+0Ch]
call 10024E5B // __DllMainCRTStartup
这看起来是在推送第一个参数 (HMODULE),然后通过寄存器 ecx/edx 传递另外两个参数。被调用的函数也希望它们在那里。我期望看到的是所有三个都被推送到堆栈上,我相信这就是 _cdecl 约定的工作方式。这是一个例子:
push dword ptr [ebp+10h]
push dword ptr [ebp+0Ch]
push dword ptr [ebp+8]
call 3DC40E2E // __DllMainCRTStartup
有谁知道第一个变体来自哪里?它是旧版本的 CRT 吗?或者可能是完全不同的编译器?如果您也知道它是什么类型的调用约定,那么对我来说看起来像是 __fastcall 的奇怪表亲!
非常感谢!
编辑:
以为我会从 CRT 源代码中添加函数原型(至少是 VS 2012 附带的版本)
__declspec(noinline)
BOOL __cdecl
__DllMainCRTStartup(
HANDLE hDllHandle,
DWORD dwReason,
LPVOID lpreserved
)
编辑x2:
我刚刚看到了“相关”链接:什么 x86 调用约定通过 ESI 传递第一个参数?
看起来这可能是 LTCG 的结果,链接器基本上只是决定做任何它喜欢的事情,因为它知道所有组件!