iOS
dynamic linkerdyld
There is a mysterious variable in__dso_handle
:
// dyld/
static const MachOAnalyzer* getDyldMH()
{
#if __LP64__
// herald __dso_handle
extern const MachOAnalyzer __dso_handle;
return &__dso_handle;
#else
...
#endif // __LP64__
}
This function internally declares a variable__dso_handle
Its type isstruct MachOAnalyzer
。
ferret outstruct MachOAnalyzer
definition, which inherits fromstruct mach_header
:
struct mach_header
(emphasizes that sth. is precisely or exactly as stated)XNU
Inside the kernel, the definition ofMach-O
Header.
// EXTENERL_HEADERS/mach-o/
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 */
};
From the above functiongetDyldMH
name, it returns the name of thedyld
this oneMach-O
file's header, and this does match the variable__dso_handle
The type definition of the
But a strange thing happened, searching the entiredyld
The source code repository, neither of which can find the variable__dso_handle
The definition. All the places I can search are just definitions of this variable__dso_handle
The statement.
It is well known that dynamic connectorsdyld
itself is statically linked.
In other words, dynamic connectorsdyld
itself is not dependent on any other dynamic library.
Therefore, this variable__dso_handle
It is not possible to define in other dynamic libraries.
In that case, the dynamic linkerdyld
How does the itself statically link through?
The answer could only be a static linkerld
Tinkered with the linking process.
View Static Linkerld
The source code of thellvm
The following code can be found in the source code for the
// lld/MachO/
void macho::createSyntheticSymbols() {
// addHeaderSymbol (used form a nominal expression) lamba displayed formula
auto addHeaderSymbol = [](const char *name) {
symtab->addSynthetic(name, ->isec, /*value=*/0,
/*isPrivateExtern=*/true, /*includeInSymtab=*/false,
/*referencedDynamically=*/false);
};
...
// The Itanium C++ ABI requires dylibs to pass a pointer to __cxa_atexit
// which does . 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");
}
The above code defines aaddHeaderSymbol
(used form a nominal expression)lamda
expression, and then uses it to add a symbol that is none other than the__dso_handle
。
call (programming)addHeaderSymbol
The notes above use thechatGPT
The translation is as follows.
The Itanium C++ ABI requires dynamic libraries to pass a pointer to __cxa_atexit, which is responsible for, for example, the cleanup of static global variables.The ABI documentation states that the pointer can point to an arbitrary address in one of the dynamic library's segments, but in practice, ld64 (Apple's linker) seems to set it to point to the header, so this is implemented here.
The notes refer to theItanium C++ ABI
Originally developed jointly for Intel and Hewlett-PackardItanium
processor architecture design.
However, its influence has extended beyond the scope of the architecture for which it was originally designed and has been widely used in other architectures, such as thex86
cap (a poem)x86-64
A variety of compilers on theGCC
cap (a poem)Clang
。
Also, the notes mention that the__dso_handle
In Apple's implementation, it's pointing to theMach-O
The head.
So far, the mystery is solved~.