[lld] 9b29dae - [lld-macho] Allow exporting weak_def_can_be_hidden(AKA "autohide") symbols

Vy Nguyen via llvm-commits llvm-commits at lists.llvm.org
Fri Nov 12 18:57:42 PST 2021


Author: Vy Nguyen
Date: 2021-11-12T21:57:30-05:00
New Revision: 9b29dae3cae1860f663698fcb709a19cf0c398be

URL: https://github.com/llvm/llvm-project/commit/9b29dae3cae1860f663698fcb709a19cf0c398be
DIFF: https://github.com/llvm/llvm-project/commit/9b29dae3cae1860f663698fcb709a19cf0c398be.diff

LOG: [lld-macho] Allow exporting weak_def_can_be_hidden(AKA "autohide") symbols

autohide symbols behaves similarly to private_extern symbols.
However, LD64 allows exporting autohide symbols. LLD currently does not.
This patch allows LLD to export them.

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

Added: 
    

Modified: 
    lld/MachO/ConcatOutputSection.cpp
    lld/MachO/Driver.cpp
    lld/MachO/InputFiles.cpp
    lld/MachO/SymbolTable.cpp
    lld/MachO/SymbolTable.h
    lld/MachO/Symbols.cpp
    lld/MachO/Symbols.h
    lld/test/MachO/export-options.s

Removed: 
    


################################################################################
diff  --git a/lld/MachO/ConcatOutputSection.cpp b/lld/MachO/ConcatOutputSection.cpp
index 17da4d045585d..46cd15a40025d 100644
--- a/lld/MachO/ConcatOutputSection.cpp
+++ b/lld/MachO/ConcatOutputSection.cpp
@@ -329,7 +329,7 @@ void ConcatOutputSection::finalize() {
           thunkName, /*file=*/nullptr, thunkInfo.isec, /*value=*/0,
           /*size=*/thunkSize, /*isWeakDef=*/false, /*isPrivateExtern=*/true,
           /*isThumb=*/false, /*isReferencedDynamically=*/false,
-          /*noDeadStrip=*/false);
+          /*noDeadStrip=*/false, /*isWeakDefCanBeHidden=*/false);
       thunkInfo.sym->used = true;
       target->populateThunk(thunkInfo.isec, funcSym);
       finalizeOne(thunkInfo.isec);

diff  --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp
index ceaefeda839d2..ddd84bce35c6c 100644
--- a/lld/MachO/Driver.cpp
+++ b/lld/MachO/Driver.cpp
@@ -1467,8 +1467,16 @@ bool macho::link(ArrayRef<const char *> argsArr, bool canExitEarly,
           StringRef symbolName = defined->getName();
           if (config->exportedSymbols.match(symbolName)) {
             if (defined->privateExtern) {
-              warn("cannot export hidden symbol " + symbolName +
-                   "\n>>> defined in " + toString(defined->getFile()));
+              if (defined->weakDefCanBeHidden) {
+                // weak_def_can_be_hidden symbols behave similarly to
+                // private_extern symbols in most cases, except for when
+                // it is explicitly exported.
+                // The former can be exported but the latter cannot.
+                defined->privateExtern = false;
+              } else {
+                warn("cannot export hidden symbol " + symbolName +
+                     "\n>>> defined in " + toString(defined->getFile()));
+              }
             }
           } else {
             defined->privateExtern = true;

diff  --git a/lld/MachO/InputFiles.cpp b/lld/MachO/InputFiles.cpp
index 1b233920ffb27..769fdddf67f72 100644
--- a/lld/MachO/InputFiles.cpp
+++ b/lld/MachO/InputFiles.cpp
@@ -567,16 +567,22 @@ static macho::Symbol *createDefined(const NList &sym, StringRef name,
     // with ld64's semantics, because it means the non-private-extern
     // definition will continue to take priority if more private extern
     // definitions are encountered. With lld's semantics there's no observable
-    // 
diff erence between a symbol that's isWeakDefCanBeHidden or one that's
-    // privateExtern -- neither makes it into the dynamic symbol table. So just
-    // promote isWeakDefCanBeHidden to isPrivateExtern here.
-    if (isWeakDefCanBeHidden)
+    // 
diff erence between a symbol that's isWeakDefCanBeHidden(autohide) or one
+    // that's privateExtern -- neither makes it into the dynamic symbol table,
+    // unless the autohide symbol is explicitly exported.
+    // But if a symbol is both privateExtern and autohide then it can't
+    // be exported.
+    // So we nullify the autohide flag when privateExtern is present
+    // and promote the symbol to privateExtern when it is not already.
+    if (isWeakDefCanBeHidden && isPrivateExtern)
+      isWeakDefCanBeHidden = false;
+    else if (isWeakDefCanBeHidden)
       isPrivateExtern = true;
-
     return symtab->addDefined(
         name, isec->getFile(), isec, value, size, sym.n_desc & N_WEAK_DEF,
         isPrivateExtern, sym.n_desc & N_ARM_THUMB_DEF,
-        sym.n_desc & REFERENCED_DYNAMICALLY, sym.n_desc & N_NO_DEAD_STRIP);
+        sym.n_desc & REFERENCED_DYNAMICALLY, sym.n_desc & N_NO_DEAD_STRIP,
+        isWeakDefCanBeHidden);
   }
   assert(!isWeakDefCanBeHidden &&
          "weak_def_can_be_hidden on already-hidden symbol?");
@@ -596,7 +602,8 @@ static macho::Symbol *createAbsolute(const NList &sym, InputFile *file,
     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,
-        /*isReferencedDynamically=*/false, sym.n_desc & N_NO_DEAD_STRIP);
+        /*isReferencedDynamically=*/false, sym.n_desc & N_NO_DEAD_STRIP,
+        /*isWeakDefCanBeHidden=*/false);
   }
   return make<Defined>(name, file, nullptr, sym.n_value, /*size=*/0,
                        /*isWeakDef=*/false,
@@ -1448,7 +1455,8 @@ static macho::Symbol *createBitcodeSymbol(const lto::InputFile::Symbol &objSym,
                             /*size=*/0, objSym.isWeak(), isPrivateExtern,
                             /*isThumb=*/false,
                             /*isReferencedDynamically=*/false,
-                            /*noDeadStrip=*/false);
+                            /*noDeadStrip=*/false,
+                            /*isWeakDefCanBeHidden=*/false);
 }
 
 BitcodeFile::BitcodeFile(MemoryBufferRef mb, StringRef archiveName,

diff  --git a/lld/MachO/SymbolTable.cpp b/lld/MachO/SymbolTable.cpp
index df7237468ae3d..c212516a47804 100644
--- a/lld/MachO/SymbolTable.cpp
+++ b/lld/MachO/SymbolTable.cpp
@@ -49,8 +49,8 @@ Defined *SymbolTable::addDefined(StringRef name, InputFile *file,
                                  InputSection *isec, uint64_t value,
                                  uint64_t size, bool isWeakDef,
                                  bool isPrivateExtern, bool isThumb,
-                                 bool isReferencedDynamically,
-                                 bool noDeadStrip) {
+                                 bool isReferencedDynamically, bool noDeadStrip,
+                                 bool isWeakDefCanBeHidden) {
   Symbol *s;
   bool wasInserted;
   bool overridesWeakDef = false;
@@ -62,10 +62,10 @@ Defined *SymbolTable::addDefined(StringRef name, InputFile *file,
   if (!wasInserted) {
     if (auto *defined = dyn_cast<Defined>(s)) {
       if (isWeakDef) {
-
         // See further comment in createDefined() in InputFiles.cpp
         if (defined->isWeakDef()) {
           defined->privateExtern &= isPrivateExtern;
+          defined->weakDefCanBeHidden &= isWeakDefCanBeHidden;
           defined->referencedDynamically |= isReferencedDynamically;
           defined->noDeadStrip |= noDeadStrip;
         }
@@ -98,8 +98,8 @@ Defined *SymbolTable::addDefined(StringRef name, InputFile *file,
 
   Defined *defined = replaceSymbol<Defined>(
       s, name, file, isec, value, size, isWeakDef, /*isExternal=*/true,
-      isPrivateExtern, isThumb, isReferencedDynamically, noDeadStrip);
-  defined->overridesWeakDef = overridesWeakDef;
+      isPrivateExtern, isThumb, isReferencedDynamically, noDeadStrip,
+      overridesWeakDef, isWeakDefCanBeHidden);
   return defined;
 }
 
@@ -195,10 +195,11 @@ Defined *SymbolTable::addSynthetic(StringRef name, InputSection *isec,
                                    uint64_t value, bool isPrivateExtern,
                                    bool includeInSymtab,
                                    bool referencedDynamically) {
-  Defined *s = addDefined(name, nullptr, isec, value, /*size=*/0,
-                          /*isWeakDef=*/false, isPrivateExtern,
-                          /*isThumb=*/false, referencedDynamically,
-                          /*noDeadStrip=*/false);
+  Defined *s =
+      addDefined(name, nullptr, isec, value, /*size=*/0,
+                 /*isWeakDef=*/false, isPrivateExtern,
+                 /*isThumb=*/false, referencedDynamically,
+                 /*noDeadStrip=*/false, /*isWeakDefCanBeHidden=*/false);
   s->includeInSymtab = includeInSymtab;
   return s;
 }

diff  --git a/lld/MachO/SymbolTable.h b/lld/MachO/SymbolTable.h
index 17f1ecbd346bd..625f78aa61411 100644
--- a/lld/MachO/SymbolTable.h
+++ b/lld/MachO/SymbolTable.h
@@ -40,7 +40,8 @@ class SymbolTable {
   Defined *addDefined(StringRef name, InputFile *, InputSection *,
                       uint64_t value, uint64_t size, bool isWeakDef,
                       bool isPrivateExtern, bool isThumb,
-                      bool isReferencedDynamically, bool noDeadStrip);
+                      bool isReferencedDynamically, bool noDeadStrip,
+                      bool isWeakDefCanBeHidden);
 
   Symbol *addUndefined(StringRef name, InputFile *, bool isWeakRef);
 

diff  --git a/lld/MachO/Symbols.cpp b/lld/MachO/Symbols.cpp
index c663b21dd7d9c..7b04d2512f677 100644
--- a/lld/MachO/Symbols.cpp
+++ b/lld/MachO/Symbols.cpp
@@ -34,12 +34,14 @@ uint64_t Symbol::getTlvVA() const { return in.tlvPointers->getVA(gotIndex); }
 Defined::Defined(StringRefZ name, InputFile *file, InputSection *isec,
                  uint64_t value, uint64_t size, bool isWeakDef, bool isExternal,
                  bool isPrivateExtern, bool isThumb,
-                 bool isReferencedDynamically, bool noDeadStrip)
+                 bool isReferencedDynamically, bool noDeadStrip,
+                 bool canOverrideWeakDef, bool isWeakDefCanBeHidden)
     : Symbol(DefinedKind, name, file), isec(isec), value(value), size(size),
-      overridesWeakDef(false), privateExtern(isPrivateExtern),
+      overridesWeakDef(canOverrideWeakDef), privateExtern(isPrivateExtern),
       includeInSymtab(true), thumb(isThumb),
       referencedDynamically(isReferencedDynamically), noDeadStrip(noDeadStrip),
-      weakDef(isWeakDef), external(isExternal) {
+      weakDef(isWeakDef), external(isExternal),
+      weakDefCanBeHidden(isWeakDefCanBeHidden) {
   if (isec) {
     isec->symbols.push_back(this);
     // Maintain sorted order.

diff  --git a/lld/MachO/Symbols.h b/lld/MachO/Symbols.h
index 54f1a35127282..2d38eea88be08 100644
--- a/lld/MachO/Symbols.h
+++ b/lld/MachO/Symbols.h
@@ -113,7 +113,8 @@ 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 isReferencedDynamically, bool noDeadStrip);
+          bool isThumb, bool isReferencedDynamically, bool noDeadStrip,
+          bool canOverrideWeakDef = false, bool isWeakDefCanBeHidden = false);
 
   bool isWeakDef() const override { return weakDef; }
   bool isExternalWeakDef() const {
@@ -160,6 +161,8 @@ class Defined : public Symbol {
   // to the output.
   bool noDeadStrip : 1;
 
+  bool weakDefCanBeHidden : 1;
+
 private:
   const bool weakDef : 1;
   const bool external : 1;

diff  --git a/lld/test/MachO/export-options.s b/lld/test/MachO/export-options.s
index 30f05effad1b8..5678a48719a65 100644
--- a/lld/test/MachO/export-options.s
+++ b/lld/test/MachO/export-options.s
@@ -119,6 +119,33 @@
 # GLOBBY-DAG: globby_also
 # GLOBBY-NOT: literal_only
 
+# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-macos \
+# RUN:     %t/autohide.s -o %t/autohide.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-macos \
+# RUN:     %t/autohide-private-extern.s -o %t/autohide-private-extern.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-macos \
+# RUN:     %t/glob-private-extern.s -o %t/glob-private-extern.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-macos \
+# RUN:     %t/weak-private-extern.s -o %t/weak-private-extern.o
+## Test that we can export the autohide symbol but not when it's also
+## private-extern
+# RUN: %lld -dylib -exported_symbol "_foo" %t/autohide.o -o %t/exp-autohide.dylib
+# RUN: llvm-nm -g %t/exp-autohide.dylib | FileCheck %s --check-prefix=EXP-AUTOHIDE
+
+# RUN: not %lld -dylib -exported_symbol "_foo" %t/autohide-private-extern.o \
+# RUN: -o /dev/null  2>&1 | FileCheck %s --check-prefix=AUTOHIDE-PRIVATE
+
+# RUN: not %lld -dylib -exported_symbol "_foo" %t/autohide.o \
+# RUN:   %t/glob-private-extern.o -o /dev/null 2>&1 | \
+# RUN:   FileCheck %s --check-prefix=AUTOHIDE-PRIVATE
+
+# RUN: not %lld -dylib -exported_symbol "_foo" %t/autohide.o \
+# RUN:   %t/weak-private-extern.o -o /dev/null 2>&1 | \
+# RUN:   FileCheck %s --check-prefix=AUTOHIDE-PRIVATE
+
+# EXP-AUTOHIDE: T _foo        
+# AUTOHIDE-PRIVATE: error: cannot export hidden symbol _foo
+        
 #--- default.s
 
 .globl _keep_globl, _hide_globl
@@ -164,3 +191,29 @@ globby_also:
   l?ter[aeiou]l_*[^y] # comment
 
   *gl?bby_*
+
+#--- autohide.s
+.globl _foo
+.weak_def_can_be_hidden _foo
+_foo:
+  retq
+
+#--- autohide-private-extern.s
+.globl _foo
+.weak_def_can_be_hidden _foo
+.private_extern _foo
+_foo:
+  retq
+
+#--- glob-private-extern.s
+.global _foo
+.private_extern _foo
+_foo:
+  retq
+
+#--- weak-private-extern.s
+.global _foo
+.weak_definition _foo
+.private_extern _foo        
+_foo:
+  retq


        


More information about the llvm-commits mailing list