Windows VS下静态库平台相关函数的运行时导入方案问询
Windows+VS环境下静态库平台依赖函数的处理方案
问题1:能否通过C代码告知VC编译器/链接器,平台函数在运行时导入?
可以实现,有两种主流方式:
方式1:利用VC的延迟加载(Delay Load)机制
- 在静态库的头文件中,将依赖的平台函数声明为
__declspec(dllimport),示例:__declspec(dllimport) HANDLE CreateFileA(LPCSTR, DWORD, DWORD, LPSECURITY_ATTRIBUTES, DWORD, DWORD, HANDLE); - 给静态库项目添加链接器选项:
/DELAYLOAD:kernel32.dll(替换为实际依赖的DLL),同时必须在链接器输入的附加依赖项中添加delayimp.lib。 - 配置完成后,VC链接器在将exe/dll与静态库链接时,不会因找不到平台函数符号报错,而是生成延迟加载相关代码,程序运行时第一次调用该函数才会加载目标DLL并解析函数地址。
方式2:手动动态加载
- 在静态库内部对平台函数做一层封装,完全通过
LoadLibrary和GetProcAddress在运行时获取函数地址,示例代码:typedef HANDLE(WINAPI* PFN_CREATEFILEA)(LPCSTR, DWORD, DWORD, LPSECURITY_ATTRIBUTES, DWORD, DWORD, HANDLE); static PFN_CREATEFILEA pCreateFileA = NULL; HANDLE MyCreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) { if (!pCreateFileA) { HMODULE hKernel32 = LoadLibraryA("kernel32.dll"); if (hKernel32) pCreateFileA = (PFN_CREATEFILEA)GetProcAddress(hKernel32, "CreateFileA"); } if (pCreateFileA) return pCreateFileA(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile); return INVALID_HANDLE_VALUE; } - 静态库中所有依赖
CreateFileA的地方都调用封装后的MyCreateFileA,这样编译静态库时不会依赖平台函数的符号,完全在运行时动态解析。
问题2:汇编桩代码实现示例
如果需要用汇编桩模拟DLL导入库的行为,以下是x86和x64平台的示例:
x86汇编桩(stub.asm)
.386 .model flat, C ; 声明导入表中的函数地址符号 EXTERN __imp__CreateFileA@28:DWORD ; 导出桩函数,名称要和静态库中依赖的函数名一致 PUBLIC _CreateFileA _CreateFileA: ; 跳转到导入表中的函数地址,由加载器在运行时填充 jmp DWORD PTR __imp__CreateFileA@28
编译命令:ml /c /coff stub.asm,生成stub.obj后添加到静态库项目中。
x64汇编桩(stub64.asm)
.code ; 声明导入表中的函数地址符号 EXTERN __imp_CreateFileA:QWORD ; 导出桩函数 PUBLIC CreateFileA CreateFileA PROC ; 跳转到导入表地址 jmp QWORD PTR __imp_CreateFileA CreateFileA ENDP END
编译命令:ml64 /c stub64.asm,生成stub64.obj后添加到静态库项目。
这种桩代码的作用是给链接器提供符号占位,链接exe/dll时会将该桩与目标DLL的导入表关联,程序加载时由系统加载器自动解析真正的函数地址。
内容的提问来源于stack exchange,提问作者CVO
相关产品推荐
相关产品推荐

