diff --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp index c85b72564213d..341ddaf870a66 100644 --- a/lld/MachO/Driver.cpp +++ b/lld/MachO/Driver.cpp @@ -1043,14 +1043,7 @@ bool macho::link(ArrayRef argsArr, bool canExitEarly, } 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(); for (const Arg *arg : args.filtered(OPT_sectcreate)) { StringRef segName = arg->getValue(0); diff --git a/lld/MachO/SymbolTable.cpp b/lld/MachO/SymbolTable.cpp index 1d812538005dd..311c0018379d9 100644 --- a/lld/MachO/SymbolTable.cpp +++ b/lld/MachO/SymbolTable.cpp @@ -159,10 +159,10 @@ Symbol *SymbolTable::addLazy(StringRef name, ArchiveFile *file, 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; + bool includeInSymtab) { + Defined *s = addDefined(name, nullptr, isec, value, + /*isWeakDef=*/false, isPrivateExtern); + s->includeInSymtab = includeInSymtab; return s; } diff --git a/lld/MachO/SymbolTable.h b/lld/MachO/SymbolTable.h index 8964713c7a748..9aed8c90064f7 100644 --- 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" @@ -50,7 +52,7 @@ class SymbolTable { const llvm::object::Archive::Symbol &sym); Defined *addSynthetic(StringRef name, InputSection *, uint32_t value, - bool isPrivateExtern, bool isLinkerInternal); + bool isPrivateExtern, bool includeInSymtab); ArrayRef getSymbols() const { return symVector; } Symbol *find(llvm::CachedHashStringRef name); diff --git a/lld/MachO/Symbols.h b/lld/MachO/Symbols.h index ada5bc164c82c..e815b7de9c205 100644 --- a/lld/MachO/Symbols.h +++ b/lld/MachO/Symbols.h @@ -99,7 +99,7 @@ class Defined : public Symbol { 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 @@ class Defined : public Symbol { 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.cpp b/lld/MachO/SyntheticSections.cpp index 1834a48f0e562..cf7d40398e62a 100644 --- a/lld/MachO/SyntheticSections.cpp +++ b/lld/MachO/SyntheticSections.cpp @@ -53,7 +53,12 @@ SyntheticSection::SyntheticSection(const char *segname, const char *name) // dyld3's MachOLoaded::getSlide() assumes that the __TEXT segment starts // from the beginning of the file (i.e. the header). MachHeaderSection::MachHeaderSection() - : SyntheticSection(segment_names::text, section_names::header) {} + : SyntheticSection(segment_names::text, section_names::header) { + // XXX: This is a hack. (See D97007) + // Setting the index to 1 to pretend that this section is the text + // section. + index = 1; +} void MachHeaderSection::addLoadCommand(LoadCommand *lc) { loadCommands.push_back(lc); @@ -754,7 +759,7 @@ void SymtabSection::finalizeContents() { for (Symbol *sym : symtab->getSymbols()) { if (auto *defined = dyn_cast(sym)) { - if (defined->linkerInternal) + if (!defined->includeInSymtab) continue; assert(defined->isExternal()); addSymbol(externalSymbols, defined); @@ -993,3 +998,56 @@ void CodeSignatureSection::writeTo(uint8_t *buf) const { memcpy(id, fileName.begin(), fileName.size()); memset(id + fileName.size(), 0, fileNamePad); } + +void macho::createSyntheticSymbols() { + auto addHeaderSymbol = [](const char *name) { + symtab->addSynthetic(name, in.header->isec, 0, + /*privateExtern=*/true, + /*includeInSymtab*/ false); + }; + + switch (config->outputType) { + // FIXME: Assign the right addresse value for these symbols + // (rather than 0). But we need to do that after assignAddresses(). + case MH_EXECUTE: + // If linking PIE, __mh_execute_header is a defined symbol in + // __TEXT, __text) + // Otherwise, it's an absolute symbol. + if (config->isPic) + symtab->addSynthetic("__mh_execute_header", in.header->isec, 0, + /*privateExtern*/ false, + /*includeInSymbtab*/ true); + else + symtab->addSynthetic("__mh_execute_header", + /*isec*/ nullptr, 0, + /*privateExtern*/ false, + /*includeInSymbtab*/ true); + break; + + // 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: + addHeaderSymbol("__mh_bundle_header"); + break; + case MH_DYLIB: + addHeaderSymbol("__mh_dylib_header"); + break; + case MH_DYLINKER: + addHeaderSymbol("__mh_dylinker_header"); + break; + case MH_OBJECT: + addHeaderSymbol("__mh_object_header"); + break; + default: + llvm_unreachable("unexpected outputType"); + break; + } + + // 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"); +} diff --git a/lld/MachO/SyntheticSections.h b/lld/MachO/SyntheticSections.h index 74a6d3c9475c4..92869476390a8 100644 --- a/lld/MachO/SyntheticSections.h +++ b/lld/MachO/SyntheticSections.h @@ -500,6 +500,8 @@ struct InStruct { extern InStruct in; extern std::vector syntheticSections; +void createSyntheticSymbols(); + } // namespace macho } // namespace lld diff --git a/lld/MachO/Writer.cpp b/lld/MachO/Writer.cpp index b2d3163558072..4070a2077937f 100644 --- a/lld/MachO/Writer.cpp +++ b/lld/MachO/Writer.cpp @@ -751,7 +751,6 @@ static void sortSegmentsAndSections() { // output section indices. if (!osec->isHidden()) osec->index = ++sectionIndex; - if (!firstTLVDataSection && isThreadLocalData(osec->flags)) firstTLVDataSection = osec; diff --git a/lld/test/MachO/export-trie.s b/lld/test/MachO/export-trie.s index c479e166561cc..cab8312fe1d0c 100644 --- a/lld/test/MachO/export-trie.s +++ b/lld/test/MachO/export-trie.s @@ -15,7 +15,9 @@ # EXPORTS-DAG: [[#%x, HELLO_WORLD_ADDR:]] {{.*}} _hello_world # EXPORTS-DAG: [[#%x, HELLO_ITS_ME_ADDR:]] {{.*}} _hello_its_me # EXPORTS-DAG: [[#%x, HELLO_ITS_YOU_ADDR:]] {{.*}} _hello_its_you +# EXPORTS-DAG: {{0+}} g *ABS* __mh_execute_header # EXPORTS-LABEL: Exports trie: +# EXPORTS-DAG: 0x{{0+}} __mh_execute_header [absolute] # EXPORTS-DAG: 0x{{0*}}[[#%X, MAIN_ADDR]] _main # EXPORTS-DAG: 0x{{0*}}[[#%X, HELLO_ADDR]] _hello # EXPORTS-DAG: 0x{{0*}}[[#%X, HELLO_WORLD_ADDR]] _hello_world @@ -27,13 +29,16 @@ # CHECK-LABEL: ExportTrie: # CHECK: Name: '' # CHECK: Name: _ -# CHECK: Name: main -# CHECK: Name: hello +# CHECK-DAG: Name: _mh_execute_header +# CHECK-DAG: Name: main +# CHECK-DAG: Name: hello # CHECK: Name: _ # CHECK: Name: world # CHECK: Name: its_ -# CHECK: Name: you -# CHECK: Name: me +# CHECK-DAG: Name: you +# CHECK-DAG: Name: me + + .section __TEXT,__cstring .globl _hello, _hello_world, _hello_its_me, _hello_its_you, _main diff --git a/lld/test/MachO/map-file.s b/lld/test/MachO/map-file.s index ac5fb93898d37..215d193aa622f 100644 --- a/lld/test/MachO/map-file.s +++ b/lld/test/MachO/map-file.s @@ -29,6 +29,7 @@ _main: # CHECK-NEXT: [[#%x,MAIN:]] g F __TEXT,__text _main # CHECK-NEXT: [[#%x,NUMBER:]] g O __DATA,__common _number # CHECK-NEXT: [[#%x,FOO:]] g O __TEXT,obj _foo +# CHECK-NEXT: {{0+}} g *ABS* __mh_execute_header # CHECK-NEXT: # Path: {{.*}}{{/|\\}}map-file.s.tmp/test-map # CHECK-NEXT: # Arch: x86_64 diff --git a/lld/test/MachO/mh-execute-header.s b/lld/test/MachO/mh-execute-header.s new file mode 100644 index 0000000000000..4a62b27bb8fa8 --- /dev/null +++ b/lld/test/MachO/mh-execute-header.s @@ -0,0 +1,16 @@ +# REQUIRES: x86 +# RUN: rm -rf %t; mkdir %t +# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %s -o %t/test.o +# RUN: %lld -o %t/test.pie %t/test.o -pie +# RUN: llvm-objdump --macho --syms %t/test.pie | FileCheck %s --check-prefix=PIE + +# RUN: %lld -o %t/test.no_pie %t/test.o -no_pie +# RUN: llvm-objdump --macho --syms %t/test.no_pie | FileCheck %s --check-prefix=NO-PIE + +# PIE: 0000000100000000 g F __TEXT,__text __mh_execute_header +# NO-PIE: 0000000000000000 g *ABS* __mh_execute_header + +.text +.global _main +_main: + ret diff --git a/lld/test/MachO/mh-header-link.s b/lld/test/MachO/mh-header-link.s new file mode 100644 index 0000000000000..0813435397b73 --- /dev/null +++ b/lld/test/MachO/mh-header-link.s @@ -0,0 +1,43 @@ +# REQUIRES: x86 + +## This tests that we can link against these synthetic symbols even +## if they are not in the symbol table. + +# RUN: rm -rf %t; split-file %s %t + +## Test that in a dylib, we can link against __mh_dylib_header +## (but not in other types of files) + +# RUN: llvm-mc %t/dylib.s -triple=x86_64-apple-macos11.0 -filetype=obj -o %t/dylib.o +# RUN: %lld -pie -dylib %t/dylib.o -o %t/dylib.out +# RUN: llvm-objdump -m --syms %t/dylib.out | FileCheck %s --check-prefix DYLIB + +# RUN: not %lld -pie -o /dev/null %t/dylib.o 2>&1 | FileCheck %s --check-prefix ERR-DYLIB + +# DYLIB: SYMBOL TABLE: +# DYLIB-NEXT: {{[0-9a-f]+}} g F __TEXT,__text _main +# DYLIB-NEXT-EMPTY: +# ERR-DYLIB: error: undefined symbol: __mh_dylib_header + +## Test that in an executable, we can link against __mh_execute_header +# RUN: llvm-mc %t/main.s -triple=x86_64-apple-macos11.0 -filetype=obj -o %t/exec.o +# RUN: %lld -pie %t/exec.o -o %t/exec.out + +## But it would be an error trying to reference __mh_execute_header in a dylib +# RUN: not %lld -pie -o /dev/null -dylib %t/exec.o 2>&1 | FileCheck %s --check-prefix ERR-EXEC + +# ERR-EXEC: error: undefined symbol: __mh_execute_header + +#--- main.s +.text +.globl _main +_main: + mov __mh_execute_header@GOTPCREL(%rip), %rax + ret + +#--- dylib.s +.text +.globl _main +_main: + mov __mh_dylib_header@GOTPCREL(%rip), %rax + ret diff --git a/lld/test/MachO/objc.s b/lld/test/MachO/objc.s index 53dd12e8f1909..06f47d2c3b783 100644 --- 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 index 09735feb5b263..6a72ff246e1da 100644 --- 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 diff --git a/lld/test/MachO/symtab.s b/lld/test/MachO/symtab.s index 44d42068ffb53..35fc961d1b350 100644 --- a/lld/test/MachO/symtab.s +++ b/lld/test/MachO/symtab.s @@ -56,6 +56,16 @@ # CHECK-NEXT: ] # CHECK-NEXT: Value: 0x1{{[0-9a-f]*}} # CHECK-NEXT: } +# CHECK-NEXT: Symbol { +# CHECK-NEXT: Name: __mh_execute_header (81) +# CHECK-NEXT: Extern +# CHECK-NEXT: Type: Abs (0x2) +# CHECK-NEXT: Section: (0x0) +# CHECK-NEXT: RefType: UndefinedNonLazy (0x0) +# CHECK-NEXT: Flags [ (0x0) +# CHECK-NEXT: ] +# CHECK-NEXT: Value: 0x0 +# CHECK-NEXT: } # CHECK-NEXT: Symbol { # CHECK-NEXT: Name: dyld_stub_binder # CHECK-NEXT: Extern @@ -82,8 +92,8 @@ # CHECK-NEXT: ilocalsym: 0 # CHECK-NEXT: nlocalsym: 2 # CHECK-NEXT: iextdefsym: 2 -# CHECK-NEXT: nextdefsym: 3 -# CHECK-NEXT: iundefsym: 5 +# CHECK-NEXT: nextdefsym: 4 +# CHECK-NEXT: iundefsym: 6 # CHECK-NEXT: nundefsym: 2 ## Verify that the first entry in the StringTable is a space, and that