和AI对话的日常--(link.exe)链接过程中符号的查找规则和处理方法

下面梳理一下 lld-link 执行链接时的符号查找与处理流程,特别是符号在 obj 和 lib(静态库/导入库)中的情况:


1. 加载输入文件

  • 命令行输入的每个文件(obj、lib、import lib等)都被解析为 InputFile 的子类(如 ObjFileArchiveFileImportFile)。
  • obj 文件会立即解析所有符号,lib 文件则注册为“懒加载”。

2. 符号表构建

a. obj 文件中的符号

  • 解析 obj 时,所有符号(定义和未定义)都被加入符号表(SymbolTable)。
  • 已定义的符号(如函数、全局变量)会直接插入符号表,类型如 DefinedRegular
  • 未定义的符号(引用的外部符号)会插入为 Undefined

b. lib(静态库)中的符号

  • 解析 lib 时,不会立即解包所有成员(obj),而是为每个符号注册一个 LazyArchive
  • 只有当链接器遇到未定义符号且该符号在 lib 中有定义时,才会解包对应成员(obj),并将其符号插入符号表。

c. import lib(导入库)中的符号

  • 解析 import lib 时,每个成员(通常一个 API)会被解包为 ImportFile,并立即注册导入符号(如 MessageBoxA__imp_MessageBoxA)到符号表。
  • 这些符号类型为 DefinedImportThunkDefinedImportData

3. 符号查找与决策

a. 符号只在 obj 中

  • 直接用 obj 中的定义。
  • 如果有未定义符号,继续查找其它 obj、lib、import lib。

b. 符号只在 lib 中

  • 如果 obj/其它输入文件引用了该符号,链接器会解包 lib 中对应成员(obj),并将其符号插入符号表。
  • 只解包被引用的成员,未被引用的不处理。

c. 符号只在 import lib 中

  • 如果 obj/其它输入文件引用了该符号,直接用 import lib 注册的导入符号(thunk/IAT)。
  • 这些符号会生成导入表项,最终链接到 DLL。

d. 符号在 obj 和 lib 中都存在

  • obj 优先:如果 obj 已经定义了符号,lib 中的同名符号不会被解包。
  • 如果两个都是强符号,且都被解包,会报 duplicate symbol 错误。

e. 符号在 obj 和 import lib 中都存在

  • obj 优先:如果 obj 已经定义了符号,import lib 的同名符号不会覆盖 obj 的定义。
  • 如果两个都是强符号,会报 duplicate symbol 错误(见 reportDuplicate)。

4. 相关代码路径

  • SymbolTable::insert:所有符号插入符号表的入口。
  • SymbolTable::addRegular:obj 文件定义符号。
  • SymbolTable::addLazyArchive:lib 注册懒加载符号。
  • SymbolTable::addImportData/addImportThunk:import lib 注册导入符号。
  • forceLazy:遇到 undefined 符号时,触发 lib 解包成员。
  • reportDuplicate:遇到重复定义时报错。

5. 总结

  • obj 优先于 lib 和 import lib
  • lib 只解包被引用的成员。
  • import lib 的所有符号都注册,但只有被引用的才会被链接进最终输出。
  • 重复定义会报错,除非是弱符号或用 /FORCE:MULTIPLE

如需具体代码行或更细致的流程,可进一步追踪 SymbolTable.cpp 中的相关函数实现。

posted @ 2025-05-29 17:15  吱吱的笔记  阅读(88)  评论(0)    收藏  举报