dyld: __dso_handle是什么神秘机制?

摘要:iOS动态链接器dyld中有一个神秘的变量__dso_handle:dylddyldMain.cpp static const MachOAnalyzer* getDyldMH() { #if __LP64__声明 __d
iOS动态链接器dyld中有一个神秘的变量__dso_handle: // dyld/dyldMain.cpp static const MachOAnalyzer* getDyldMH() { #if __LP64__ // 声明 __dso_handle extern const MachOAnalyzer __dso_handle; return &__dso_handle; #else ... #endif // __LP64__ } 这个函数内部声明了一个变量__dso_handle,其类型是struct MachOAnalyzer。 查看struct MachOAnalyzer的定义,它继承自struct mach_header: struct mach_header正是XNU内核里面,定义的Mach-O文件头: // EXTENERL_HEADERS/mach-o/loader.h struct mach_header { uint32_t magic; /* mach magic number identifier */ cpu_type_t cputype; /* cpu specifier */ cpu_subtype_t cpusubtype; /* machine specifier */ uint32_t filetype; /* type of file */ uint32_t ncmds; /* number of load commands */ uint32_t sizeofcmds; /* the size of all the load commands */ uint32_t flags; /* flags */ }; 从上面函数getDyldMH的名字来看,它返回dyld这个Mach-O文件的文件头,而这确实也符合变量__dso_handle的类型定义。 但是奇怪的事情发生了,搜遍整个dyld源码库,都无法找到变量__dso_handle的定义。所有能搜到的地方,都只是对这个变量__dso_handle的声明。 众所周知,动态连接器dyld本身是静态链接的。 也就是说,动态连接器dyld本身是不依赖任何其他动态库的。 因此,这个变量__dso_handle不可能定义在其他动态库。 既然这样,动态链接器dyld本身是如何静态链接通过的呢? 答案只可能是静态链接器ld在链接过程中做了手脚。 查看静态链接器ld的源码,也就是llvm的源码,可以找到如下代码: // lld/MachO/SyntheticSections.cpp void macho::createSyntheticSymbols() { // addHeaderSymbol 的 lamba 表达式 auto addHeaderSymbol = [](const char *name) { symtab->addSynthetic(name, in.header->isec, /*value=*/0, /*isPrivateExtern=*/true, /*includeInSymtab=*/false, /*referencedDynamically=*/false); }; ... // The Itanium C++ ABI requires dylibs to pass a pointer to __cxa_atexit // which does e.g. cleanup of static global variables. The ABI document // says that the pointer can point to any address in one of the dylib's // segments, but in practice ld64 seems to set it to point to the header, // so that's what's implemented here. addHeaderSymbol("___dso_handle"); } 上面代码定义了一个addHeaderSymbol的lamda表达式,然后使用它添加了一个符号,这个符号正是__dso_handle。
阅读全文