diff --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp --- a/lld/MachO/Driver.cpp +++ b/lld/MachO/Driver.cpp @@ -984,8 +984,9 @@ } } + const bool isLinkingPie = isPie(args); config->isPic = config->outputType == MH_DYLIB || - config->outputType == MH_BUNDLE || isPie(args); + config->outputType == MH_BUNDLE || isLinkingPie; // Now that all dylibs have been loaded, search for those that should be // re-exported. @@ -1032,14 +1033,7 @@ } createSyntheticSections(); - - // 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. - symtab->addSynthetic("___dso_handle", in.header->isec, 0, - /*privateExtern=*/true, /*linkerInternal=*/true); + createSyntheticSymbols(isLinkingPie); for (const Arg *arg : args.filtered(OPT_sectcreate)) { StringRef segName = arg->getValue(0); diff --git a/lld/MachO/OutputSegment.h b/lld/MachO/OutputSegment.h --- a/lld/MachO/OutputSegment.h +++ b/lld/MachO/OutputSegment.h @@ -24,6 +24,7 @@ constexpr const char dataConst[] = "__DATA_CONST"; constexpr const char ld[] = "__LD"; // output only with -r constexpr const char dwarf[] = "__DWARF"; +constexpr const char header[] = "__HEADER"; } // namespace segment_names diff --git a/lld/MachO/SymbolTable.h b/lld/MachO/SymbolTable.h --- a/lld/MachO/SymbolTable.h +++ b/lld/MachO/SymbolTable.h @@ -9,6 +9,8 @@ #ifndef LLD_MACHO_SYMBOL_TABLE_H #define LLD_MACHO_SYMBOL_TABLE_H +#include "Symbols.h" + #include "lld/Common/LLVM.h" #include "llvm/ADT/CachedHashString.h" #include "llvm/ADT/DenseMap.h" @@ -49,8 +51,8 @@ Symbol *addLazy(StringRef name, ArchiveFile *file, const llvm::object::Archive::Symbol &sym); - Defined *addSynthetic(StringRef name, InputSection *, uint32_t value, - bool isPrivateExtern, bool isLinkerInternal); + Symbol *addSynthetic(StringRef name, InputSection *, uint32_t value, + bool isPrivateExtern, bool includeInSymtab); ArrayRef getSymbols() const { return symVector; } Symbol *find(StringRef name); diff --git a/lld/MachO/SymbolTable.cpp b/lld/MachO/SymbolTable.cpp --- a/lld/MachO/SymbolTable.cpp +++ b/lld/MachO/SymbolTable.cpp @@ -158,12 +158,12 @@ return s; } -Defined *SymbolTable::addSynthetic(StringRef name, InputSection *isec, - uint32_t value, bool isPrivateExtern, - bool isLinkerInternal) { - Defined *s = addDefined(name, nullptr, isec, value, /*isWeakDef=*/false, - isPrivateExtern); - s->linkerInternal = isLinkerInternal; +Symbol *SymbolTable::addSynthetic(StringRef name, InputSection *isec, + uint32_t value, bool isPrivateExtern, + bool includeInSymtab) { + Defined *s = addDefined(name, nullptr, isec, value, + /*isWeakDef=*/false, isPrivateExtern); + s->includeInSymtab = includeInSymtab; return s; } diff --git a/lld/MachO/Symbols.h b/lld/MachO/Symbols.h --- a/lld/MachO/Symbols.h +++ b/lld/MachO/Symbols.h @@ -99,7 +99,7 @@ bool isWeakDef, bool isExternal, bool isPrivateExtern) : Symbol(DefinedKind, name, file), isec(isec), value(value), overridesWeakDef(false), privateExtern(isPrivateExtern), - linkerInternal(false), weakDef(isWeakDef), external(isExternal) {} + includeInSymtab(true), weakDef(isWeakDef), external(isExternal) {} bool isWeakDef() const override { return weakDef; } bool isExternalWeakDef() const { @@ -124,8 +124,8 @@ bool overridesWeakDef : 1; // Whether this symbol should appear in the output binary's export trie. bool privateExtern : 1; - // Whether this symbol should appear in the output binary's symbol table. - bool linkerInternal : 1; + // Whether this symbol should appear in the output symbol table. + bool includeInSymtab : 1; private: const bool weakDef : 1; diff --git a/lld/MachO/SyntheticSections.h b/lld/MachO/SyntheticSections.h --- a/lld/MachO/SyntheticSections.h +++ b/lld/MachO/SyntheticSections.h @@ -46,6 +46,11 @@ // This fake InputSection makes it easier for us to write code that applies // generically to both user inputs and synthetics. InputSection *isec; + // If true, SyntheticSection only exists for convenience and does + // not need to be added to output. + // It could be used to represent some "real" section that already + // exists but which we don't have a handle to at the moment. + bool cosmetic; }; // All sections in __LINKEDIT should inherit from this. @@ -83,11 +88,20 @@ uint64_t getSize() const override; void writeTo(uint8_t *buf) const override; +protected: + MachHeaderSection(const char *segname, const char *name); + private: std::vector loadCommands; uint32_t sizeOfCmds = 0; }; +// Represent the __TEXT (segment) __text (section) +class TextSection : public MachHeaderSection { +public: + TextSection(); +}; + // A hidden section that exists solely for the purpose of creating the // __PAGEZERO segment, which is used to catch null pointer dereferences. class PageZeroSection : public SyntheticSection { @@ -506,11 +520,14 @@ StubsSection *stubs = nullptr; StubHelperSection *stubHelper = nullptr; ImageLoaderCacheSection *imageLoaderCache = nullptr; + TextSection *textSection = nullptr; }; extern InStruct in; extern std::vector syntheticSections; +void createSyntheticSymbols(bool isPie); + } // namespace macho } // namespace lld diff --git a/lld/MachO/SyntheticSections.cpp b/lld/MachO/SyntheticSections.cpp --- a/lld/MachO/SyntheticSections.cpp +++ b/lld/MachO/SyntheticSections.cpp @@ -41,7 +41,7 @@ std::vector macho::syntheticSections; SyntheticSection::SyntheticSection(const char *segname, const char *name) - : OutputSection(SyntheticKind, name), segname(segname) { + : OutputSection(SyntheticKind, name), segname(segname), cosmetic(false) { isec = make(); isec->segname = segname; isec->name = name; @@ -55,6 +55,14 @@ MachHeaderSection::MachHeaderSection() : SyntheticSection(segment_names::text, section_names::header) {} +MachHeaderSection::MachHeaderSection(const char *segname, const char *name) + : SyntheticSection(segname, name) {} + +TextSection::TextSection() + : MachHeaderSection(segment_names::text, section_names::text) { + cosmetic = true; +} + void MachHeaderSection::addLoadCommand(LoadCommand *lc) { loadCommands.push_back(lc); sizeOfCmds += lc->getSize(); @@ -766,7 +774,7 @@ for (Symbol *sym : symtab->getSymbols()) { if (auto *defined = dyn_cast(sym)) { - if (defined->linkerInternal) + if (!defined->includeInSymtab) continue; assert(defined->isExternal()); addSymbol(externalSymbols, defined); @@ -1005,3 +1013,51 @@ memcpy(id, fileName.begin(), fileName.size()); memset(id + fileName.size(), 0, fileNamePad); } + +void macho::createSyntheticSymbols(bool isPie) { + auto addSynSymMachHeader = [](const char *name, bool privateExtern = true) { + symtab->addSynthetic(name, in.header->isec, 0, + /*privateExtern=*/privateExtern, + /*includeInSymtab*/ false); + }; + + switch (config->outputType) { + // From the Apple documentation, this symbol is an absolute + // symbol if not linking a PIE. + case MH_EXECUTE: + if (isPie) { + // FIXME: Try to find the (__TEXT, __text) section + // and put it there. + } else + symtab->addSynthetic("__mh_execute_header", + /*isec*/ nullptr, 0, + /*privateExtern*/ false, + /*includeInSymbtab*/ true); + break; + + // From the Apple documentation, the following symbols are + // N_SECT symbols, even though the header is not part of any section + // and that they are private to the bundle/dylib/object they are part of. + case MH_BUNDLE: + addSynSymMachHeader("__mh_bundle_header"); + break; + case MH_DYLIB: + addSynSymMachHeader("__mh_dylib_header"); + break; + case MH_DYLINKER: + addSynSymMachHeader("__mh_dylinker_header"); + break; + case MH_OBJECT: + addSynSymMachHeader("__mh_object_header"); + break; + default: + break; + } +#undef addSynHelper + // 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. + addSynSymMachHeader("___dso_handle", /*privateExtern*/ true); +} diff --git a/lld/MachO/Writer.cpp b/lld/MachO/Writer.cpp --- a/lld/MachO/Writer.cpp +++ b/lld/MachO/Writer.cpp @@ -785,7 +785,7 @@ if (it == mergedOutputSections.end()) { if (ssec->isNeeded()) getOrCreateOutputSegment(ssec->segname)->addOutputSection(ssec); - } else { + } else if (!ssec->cosmetic) { error("section from " + toString(it->second->firstSection()->file) + " conflicts with synthetic section " + ssec->segname + "," + ssec->name); @@ -914,6 +914,7 @@ in.stubs = make(); in.stubHelper = make(); in.imageLoaderCache = make(); + in.textSection = make(); } OutputSection *macho::firstTLVDataSection = nullptr; diff --git a/lld/test/MachO/objc.s b/lld/test/MachO/objc.s --- a/lld/test/MachO/objc.s +++ b/lld/test/MachO/objc.s @@ -32,7 +32,7 @@ # NO-OBJC-EMPTY: # NO-OBJC-NEXT: SYMBOL TABLE: # NO-OBJC-NEXT: g F __TEXT,__text _main -# NO-OBJC-EMPTY: +# NO_OBJC-NEXT: g *ABS* __mh_execute_header #--- has-objc-symbol.s .globl _OBJC_CLASS_$_MyObject diff --git a/lld/test/MachO/stabs.s b/lld/test/MachO/stabs.s --- a/lld/test/MachO/stabs.s +++ b/lld/test/MachO/stabs.s @@ -60,6 +60,7 @@ # CHECK-NEXT: [[#ZERO]] S _zero # CHECK-NEXT: [[#FOO]] T _foo # CHECK-NEXT: {{[0-9af]+}} T _no_debug +# CHECK-NEXT: {{0+}} A __mh_execute_header # CHECK-EMPTY: ## Check that we don't attempt to emit rebase opcodes for the debug sections