[lld/mac] Honor REFERENCED_DYAMICALLY, set it on __mh_execute_header
authorNico Weber <thakis@chromium.org>
Mon, 17 May 2021 13:15:39 +0000 (09:15 -0400)
committerNico Weber <thakis@chromium.org>
Mon, 17 May 2021 18:22:12 +0000 (14:22 -0400)
Has the effect that `__mh_execute_header` stays in the symbol table of
outputs even after running `strip` on the output. I don't know if that's
important for anything -- my motivation for the patch is just is to make
the output more similar to ld64.

(Corresponds to symbolTableInAndNeverStrip in ld64.)

Differential Revision: https://reviews.llvm.org/D102619

lld/MachO/Driver.cpp
lld/MachO/InputFiles.cpp
lld/MachO/MergedOutputSection.cpp
lld/MachO/SymbolTable.cpp
lld/MachO/SymbolTable.h
lld/MachO/Symbols.h
lld/MachO/SyntheticSections.cpp
lld/MachO/UnwindInfoSection.cpp
lld/test/MachO/referenced-dynamically.s [new file with mode: 0644]
lld/test/MachO/stabs.s
lld/test/MachO/symtab.s

index c561d7c..135ca2d 100644 (file)
@@ -521,7 +521,8 @@ static void replaceCommonSymbols() {
                            /*size=*/0,
                            /*isWeakDef=*/false,
                            /*isExternal=*/true, common->privateExtern,
-                           /*isThumb=*/false);
+                           /*isThumb=*/false,
+                           /*isReferencedDynamically=*/false);
   }
 }
 
index 26230a0..a6d63e2 100644 (file)
@@ -492,7 +492,8 @@ static macho::Symbol *createDefined(const NList &sym, StringRef name,
 
     return symtab->addDefined(name, isec->file, isec, value, size,
                               sym.n_desc & N_WEAK_DEF, isPrivateExtern,
-                              sym.n_desc & N_ARM_THUMB_DEF);
+                              sym.n_desc & N_ARM_THUMB_DEF,
+                              sym.n_desc & REFERENCED_DYNAMICALLY);
   }
 
   assert(!isWeakDefCanBeHidden &&
@@ -500,7 +501,8 @@ static macho::Symbol *createDefined(const NList &sym, StringRef name,
   return make<Defined>(name, isec->file, isec, value, size,
                        sym.n_desc & N_WEAK_DEF,
                        /*isExternal=*/false, /*isPrivateExtern=*/false,
-                       sym.n_desc & N_ARM_THUMB_DEF);
+                       sym.n_desc & N_ARM_THUMB_DEF,
+                       sym.n_desc & REFERENCED_DYNAMICALLY);
 }
 
 // Absolute symbols are defined symbols that do not have an associated
@@ -512,12 +514,14 @@ static macho::Symbol *createAbsolute(const NList &sym, InputFile *file,
     assert((sym.n_type & N_EXT) && "invalid input");
     return symtab->addDefined(name, file, nullptr, sym.n_value, /*size=*/0,
                               /*isWeakDef=*/false, sym.n_type & N_PEXT,
-                              sym.n_desc & N_ARM_THUMB_DEF);
+                              sym.n_desc & N_ARM_THUMB_DEF,
+                              /*isReferencedDynamically=*/false);
   }
   return make<Defined>(name, file, nullptr, sym.n_value, /*size=*/0,
                        /*isWeakDef=*/false,
                        /*isExternal=*/false, /*isPrivateExtern=*/false,
-                       sym.n_desc & N_ARM_THUMB_DEF);
+                       sym.n_desc & N_ARM_THUMB_DEF,
+                       /*isReferencedDynamically=*/false);
 }
 
 template <class NList>
@@ -1015,7 +1019,8 @@ static macho::Symbol *createBitcodeSymbol(const lto::InputFile::Symbol &objSym,
 
   return symtab->addDefined(name, &file, /*isec=*/nullptr, /*value=*/0,
                             /*size=*/0, objSym.isWeak(), isPrivateExtern,
-                            /*isThumb=*/false);
+                            /*isThumb=*/false,
+                            /*isReferencedDynamically=*/false);
 }
 
 BitcodeFile::BitcodeFile(MemoryBufferRef mbref)
index de84cde..867f76e 100644 (file)
@@ -299,7 +299,7 @@ void MergedOutputSection::finalize() {
       r.referent = thunkInfo.sym = symtab->addDefined(
           thunkName, /*file=*/nullptr, thunkInfo.isec, /*value=*/0,
           /*size=*/thunkSize, /*isWeakDef=*/false, /*isPrivateExtern=*/true,
-          /*isThumb=*/false);
+          /*isThumb=*/false, /*isReferencedDynamically=*/false);
       target->populateThunk(thunkInfo.isec, funcSym);
       finalizeOne(thunkInfo.isec);
       thunks.push_back(thunkInfo.isec);
index ad163d3..565137e 100644 (file)
@@ -45,7 +45,8 @@ std::pair<Symbol *, bool> SymbolTable::insert(StringRef name,
 Defined *SymbolTable::addDefined(StringRef name, InputFile *file,
                                  InputSection *isec, uint64_t value,
                                  uint64_t size, bool isWeakDef,
-                                 bool isPrivateExtern, bool isThumb) {
+                                 bool isPrivateExtern, bool isThumb,
+                                 bool isReferencedDynamically) {
   Symbol *s;
   bool wasInserted;
   bool overridesWeakDef = false;
@@ -57,10 +58,11 @@ Defined *SymbolTable::addDefined(StringRef name, InputFile *file,
   if (!wasInserted) {
     if (auto *defined = dyn_cast<Defined>(s)) {
       if (isWeakDef) {
-        // Both old and new symbol weak (e.g. inline function in two TUs):
-        // If one of them isn't private extern, the merged symbol isn't.
         if (defined->isWeakDef()) {
+          // Both old and new symbol weak (e.g. inline function in two TUs):
+          // If one of them isn't private extern, the merged symbol isn't.
           defined->privateExtern &= isPrivateExtern;
+          defined->referencedDynamically |= isReferencedDynamically;
 
           // FIXME: Handle this for bitcode files.
           // FIXME: We currently only do this if both symbols are weak.
@@ -84,9 +86,9 @@ Defined *SymbolTable::addDefined(StringRef name, InputFile *file,
     // of a name conflict, we fall through to the replaceSymbol() call below.
   }
 
-  Defined *defined =
-      replaceSymbol<Defined>(s, name, file, isec, value, size, isWeakDef,
-                             /*isExternal=*/true, isPrivateExtern, isThumb);
+  Defined *defined = replaceSymbol<Defined>(
+      s, name, file, isec, value, size, isWeakDef, /*isExternal=*/true,
+      isPrivateExtern, isThumb, isReferencedDynamically);
   defined->overridesWeakDef = overridesWeakDef;
   return defined;
 }
@@ -178,10 +180,11 @@ Symbol *SymbolTable::addLazy(StringRef name, ArchiveFile *file,
 
 Defined *SymbolTable::addSynthetic(StringRef name, InputSection *isec,
                                    uint64_t value, bool isPrivateExtern,
-                                   bool includeInSymtab) {
+                                   bool includeInSymtab,
+                                   bool referencedDynamically) {
   Defined *s = addDefined(name, nullptr, isec, value, /*size=*/0,
                           /*isWeakDef=*/false, isPrivateExtern,
-                          /*isThumb=*/false);
+                          /*isThumb=*/false, referencedDynamically);
   s->includeInSymtab = includeInSymtab;
   return s;
 }
index 1239cd9..462c84b 100644 (file)
@@ -39,7 +39,8 @@ class SymbolTable {
 public:
   Defined *addDefined(StringRef name, InputFile *, InputSection *,
                       uint64_t value, uint64_t size, bool isWeakDef,
-                      bool isPrivateExtern, bool isThumb);
+                      bool isPrivateExtern, bool isThumb,
+                      bool isReferencedDynamically);
 
   Symbol *addUndefined(StringRef name, InputFile *, bool isWeakRef);
 
@@ -53,7 +54,8 @@ public:
                   const llvm::object::Archive::Symbol &sym);
 
   Defined *addSynthetic(StringRef name, InputSection *, uint64_t value,
-                        bool isPrivateExtern, bool includeInSymtab);
+                        bool isPrivateExtern, bool includeInSymtab,
+                        bool referencedDynamically);
 
   ArrayRef<Symbol *> getSymbols() const { return symVector; }
   Symbol *find(llvm::CachedHashStringRef name);
index 9428e74..82637ee 100644 (file)
@@ -112,10 +112,11 @@ class Defined : public Symbol {
 public:
   Defined(StringRefZ name, InputFile *file, InputSection *isec, uint64_t value,
           uint64_t size, bool isWeakDef, bool isExternal, bool isPrivateExtern,
-          bool isThumb)
+          bool isThumb, bool isReferencedDynamically)
       : Symbol(DefinedKind, name, file), isec(isec), value(value), size(size),
         overridesWeakDef(false), privateExtern(isPrivateExtern),
-        includeInSymtab(true), thumb(isThumb), weakDef(isWeakDef),
+        includeInSymtab(true), thumb(isThumb),
+        referencedDynamically(isReferencedDynamically), weakDef(isWeakDef),
         external(isExternal) {
     if (isec)
       isec->numRefs++;
@@ -151,6 +152,11 @@ public:
   bool includeInSymtab : 1;
   // Only relevant when compiling for Thumb-supporting arm32 archs.
   bool thumb : 1;
+  // Symbols marked referencedDynamically won't be removed from the output's
+  // symbol table by tools like strip. In theory, this could be set on arbitrary
+  // symbols in input object files. In practice, it's used solely for the
+  // synthetic __mh_execute_header symbol.
+  bool referencedDynamically : 1;
 
 private:
   const bool weakDef : 1;
index 7727ad1..7301452 100644 (file)
@@ -472,7 +472,7 @@ void StubHelperSection::setup() {
       make<Defined>("__dyld_private", nullptr, in.imageLoaderCache, 0, 0,
                     /*isWeakDef=*/false,
                     /*isExternal=*/false, /*isPrivateExtern=*/false,
-                    /*isThumb=*/false);
+                    /*isThumb=*/false, /*isReferencedDynamically=*/false);
 }
 
 ImageLoaderCacheSection::ImageLoaderCacheSection() {
@@ -856,6 +856,8 @@ template <class LP> void SymtabSectionImpl<LP>::writeTo(uint8_t *buf) const {
       }
       nList->n_desc |= defined->thumb ? N_ARM_THUMB_DEF : 0;
       nList->n_desc |= defined->isExternalWeakDef() ? N_WEAK_DEF : 0;
+      nList->n_desc |=
+          defined->referencedDynamically ? REFERENCED_DYNAMICALLY : 0;
     } else if (auto *dysym = dyn_cast<DylibSymbol>(entry.sym)) {
       uint16_t n_desc = nList->n_desc;
       int16_t ordinal = ordinalForDylibSymbol(*dysym);
@@ -1091,9 +1093,9 @@ void BitcodeBundleSection::writeTo(uint8_t *buf) const {
 
 void macho::createSyntheticSymbols() {
   auto addHeaderSymbol = [](const char *name) {
-    symtab->addSynthetic(name, in.header->isec, 0,
-                         /*privateExtern=*/true,
-                         /*includeInSymtab=*/false);
+    symtab->addSynthetic(name, in.header->isec, /*value=*/0,
+                         /*privateExtern=*/true, /*includeInSymtab=*/false,
+                         /*referencedDynamically=*/false);
   };
 
   switch (config->outputType) {
@@ -1105,16 +1107,15 @@ void macho::createSyntheticSymbols() {
     // Otherwise, it's an absolute symbol.
     if (config->isPic)
       symtab->addSynthetic("__mh_execute_header", in.header->isec, /*value=*/0,
-                           /*privateExtern=*/false,
-                           /*includeInSymtab=*/true);
+                           /*privateExtern=*/false, /*includeInSymtab=*/true,
+                           /*referencedDynamically=*/true);
     else
-      symtab->addSynthetic("__mh_execute_header",
-                           /*isec*/ nullptr, /*value=*/0,
-                           /*privateExtern=*/false,
-                           /*includeInSymtab=*/true);
+      symtab->addSynthetic("__mh_execute_header", /*isec=*/nullptr, /*value=*/0,
+                           /*privateExtern=*/false, /*includeInSymtab=*/true,
+                           /*referencedDynamically=*/true);
     break;
 
-    // The following symbols are  N_SECT symbols, even though the header is not
+    // 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:
index a9f0bbd..93a2e80 100644 (file)
@@ -187,7 +187,7 @@ void UnwindInfoSectionImpl<Ptr>::prepareRelocations(InputSection *isec) {
         s = make<Defined>("<internal>", /*file=*/nullptr, referentIsec,
                           r.addend, /*size=*/0, /*isWeakDef=*/false,
                           /*isExternal=*/false, /*isPrivateExtern=*/false,
-                          /*isThumb=*/false);
+                          /*isThumb=*/false, /*isReferencedDynamically=*/false);
         in.got->addEntry(s);
       }
       r.referent = s;
diff --git a/lld/test/MachO/referenced-dynamically.s b/lld/test/MachO/referenced-dynamically.s
new file mode 100644 (file)
index 0000000..d75e99b
--- /dev/null
@@ -0,0 +1,35 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %s -o %t.o
+
+# RUN: %lld %t.o -lSystem -o %t.out
+# RUN: llvm-readobj --syms %t.out | FileCheck %s
+
+## ld64 has a "TEMP work around until <rdar://problem/7702923> goes in"
+## that promotes PrivateExtern ReferencedDynamically symbols in dylibs to
+## normal Externs. lld does not do this.
+# RUN: %lld -dylib %t.o -o %t.dylib
+# RUN: llvm-readobj --syms %t.dylib | FileCheck %s
+
+# CHECK:         Name: ___crashreporter_info__
+# CHECK-NEXT:    PrivateExtern
+# CHECK-NEXT:    Type: Section (0xE)
+# CHECK-NEXT:    Section: __common
+# CHECK-NEXT:    RefType: UndefinedNonLazy (0x0)
+# CHECK-NEXT:    Flags [ (0x10)
+# CHECK-NEXT:      ReferencedDynamically (0x10)
+# CHECK-NEXT:    ]
+
+## Reduced from lib/Support/PrettyStackTrace.cpp
+.section __TEXT,__text,regular,pure_instructions
+
+.globl _main
+_main:
+  ret
+
+## .private_extern maches what PrettyStackTrace.cpp does, but it makes
+## the ReferencedDynamically pointless: https://reviews.llvm.org/D27683#2763729
+.private_extern ___crashreporter_info__
+.globl ___crashreporter_info__
+.desc ___crashreporter_info__,16
+.zerofill __DATA,__common,___crashreporter_info__,8,3
+.subsections_via_symbols
index 65d447b..c921328 100644 (file)
@@ -78,7 +78,7 @@
 # CHECK-DAG:  (     SECT EXT) [[#%.2d,COMM_ID + 1]]      0000   [[#ZERO]]          '_zero'
 # CHECK-DAG:  (     SECT EXT) [[#%.2d,MORE_TEXT_ID + 1]] 0000   [[#FUN]]           '_fun'
 # CHECK-DAG:  (     SECT EXT) [[#%.2d,TEXT_ID + 1]]      0000   {{[0-9a-f]+}}      '_no_debug'
-# CHECK-DAG:  (       {{.*}}) {{[0-9]+}}                 0000   {{[0-9a-f]+}}      '__mh_execute_header'
+# CHECK-DAG:  (       {{.*}}) {{[0-9]+}}                 0010   {{[0-9a-f]+}}      '__mh_execute_header'
 # CHECK-EMPTY:
 
 ## Check that we don't attempt to emit rebase opcodes for the debug sections
index 5a26bfd..2a23b3f 100644 (file)
@@ -62,7 +62,8 @@
 # CHECK-NEXT:    Type: Section (0xE)
 # CHECK-NEXT:    Section: __text (0x1)
 # CHECK-NEXT:    RefType: UndefinedNonLazy (0x0)
-# CHECK-NEXT:    Flags [ (0x0)
+# CHECK-NEXT:    Flags [ (0x10)
+# CHECK-NEXT:      ReferencedDynamically (0x10)
 # CHECK-NEXT:    ]
 # CHECK-NEXT:    Value: 0x100000000
 # CHECK-NEXT:  }