ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

C++ 动态库旁边的 .lib到底是什么:导入库本质全景

C++ 动态库旁边的 .lib到底是什么:导入库本质全景 Windows 下 C 动态库生成的.lib通常不是“代码库”而是“导入库Import Library”。它不包含 DLL 的实现代码只包含让链接器把调用方和 DLL 绑起来的元数据与桩。很多人把.lib当成“半个 DLL”这是最根本的误解。一、先分清两种.lib完全不是一回事Windows 里.lib只是扩展名背后有两种东西类型本质链接时发生什么静态库.lib多个.obj的归档包把需要的机器码/数据复制进 exe/dll导入库.libDLL 的“符号名片”不复制实现只让链接器生成导入表/IAT动态库项目编译出来的那个.lib是第二种。二、导入库里“有”什么以 MSVC 为例Math.dll配套生成Math.lib里面大致包含1. 导出符号清单C 函数名AddC 修饰名?AddYANNNZ变量符号?g_counter3HA可选 ordinal导出序号作用告诉链接器“这些名字合法它们住在某个 DLL 里”。2. 目标 DLL 名每个导入项都绑定到具体 DLLMath.dll链接器据此在 exe 的导入表里写需要加载 Math.dll 需要解析符号 Add3. 短导入描述符short import recordMSVC 的导入库本质上是COFF/“short import” 记录的归档。一条记录里会有machinex86 / x64 / ARM64symbol nameDLL nameordinal / hintimport-by-name 还是 import-by-ordinal它不是普通.obj但是能被link.exe读懂。4. 桩 / 间接符号__imp_机制对函数导入库会提供导入符号Add可能对应一个跳板/引用__imp_Add指向 IAT 槽位函数指针地址源码里写__declspec(dllimport) int Add(int, int);编译器会优先用__imp_Add生成call qword ptr [__imp_Add]运行时 Windows 加载器把Math.dll里Add的真实地址填进这个槽。5. 给链接器用的“重定位意图”导入库不包含最终地址但包含这是个外部符号要走 IAT加载时由系统回填所以 exe 里看到的是Import TableImport Address Table对__imp_xxx的引用而不是Add的函数体。三、导入库里“没有”什么导入库不包含DLL 里函数的机器码全局变量的实际内存C 类成员函数的实现运行时地址完整 PDB / 源码 / 调试信息PDB 是独立文件资源对话框/图标/字符串表通常在 DLL 里所以删掉 DLL只留.lib能编过链接运行必炸。删掉.lib留 DLLMSVC 链接器找不到符号链接失败除非手写LoadLibrary/GetProcAddress。四、为什么 Windows 需要导入库Linux 不需要Windows / PElink.exe不能直接解析.dll来解析未定义符号需要.lib做“编译期符号目录”运行时再由 NT 加载器填 IATLinux / ELF.so自身带符号表ld可以直接读.so解析符号链接结果里写DT_NEEDED: libfoo.so.1所以没有“导入库”这个概念.a只是静态库一句话导入库是 PE 格式的历史/设计产物不是 C 语言本身的要求。五、用dumpbin看导入库在骗你之前先信它dumpbin /exports Math.dll dumpbin /symbols Math.lib dumpbin /directives Math.lib你会看到.dll真正有RVA、Export Table、代码段.lib一堆UNDEF外部符号 Math.dll引用 __imp_*符号六、C 项目里最容易混的三件事1. 头文件提供声明不产生符号解析能力。2. 导入库.lib让链接器相信“符号存在运行时再补地址”。3. DLL.dll运行时提供代码和数据。缺头文件编译报错缺.lib链接报错unresolved external缺.dll启动/运行时报错找不到模块或找不到入口点七、一句话总结动态库.lib导入库导入库 符号名 DLL 名 ordinal/hint IAT 桩没有实现代码没有运行时地址只在链接期告诉link.exe“别慌这函数开机后系统帮你填”Linux 的.so把“导入库 部分链接信息”合一了所以你看不到.lib
返回列表