[lld] fae6bd7 - [lld-macho] Support -non_global_symbols_strip_list, -non_global_symbols_no_strip_list, -x

Vy Nguyen via llvm-commits llvm-commits at lists.llvm.org
Wed May 25 05:27:30 PDT 2022


Author: Vy Nguyen
Date: 2022-05-25T19:22:04+07:00
New Revision: fae6bd7563ca54139d6f7f66683c12b88783501f

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

LOG: [lld-macho] Support  -non_global_symbols_strip_list, -non_global_symbols_no_strip_list, -x

PR/55600

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

Added: 
    lld/test/MachO/local-symbol-output.s

Modified: 
    lld/MachO/Config.h
    lld/MachO/Driver.cpp
    lld/MachO/Options.td
    lld/MachO/SyntheticSections.cpp

Removed: 
    


################################################################################
diff  --git a/lld/MachO/Config.h b/lld/MachO/Config.h
index 46b3dca0c03dd..de64dc47591d1 100644
--- a/lld/MachO/Config.h
+++ b/lld/MachO/Config.h
@@ -94,6 +94,13 @@ class SymbolPatterns {
   bool match(llvm::StringRef symbolName) const;
 };
 
+enum class SymtabPresence {
+  All,
+  None,
+  SelectivelyIncluded,
+  SelectivelyExcluded,
+};
+
 struct Configuration {
   Symbol *entry = nullptr;
   bool hasReexports = false;
@@ -179,6 +186,9 @@ struct Configuration {
   SymbolPatterns unexportedSymbols;
   SymbolPatterns whyLive;
 
+  SymtabPresence localSymbolsPresence = SymtabPresence::All;
+  SymbolPatterns localSymbolPatterns;
+
   bool zeroModTime = false;
 
   llvm::StringRef osoPrefix;

diff  --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp
index bfbfb26bb6b54..c04c4fb1899bb 100644
--- a/lld/MachO/Driver.cpp
+++ b/lld/MachO/Driver.cpp
@@ -938,26 +938,29 @@ bool SymbolPatterns::match(StringRef symbolName) const {
   return matchLiteral(symbolName) || matchGlob(symbolName);
 }
 
+static void handleSymbolPatternsListHelper(const Arg *arg,
+                                           SymbolPatterns &symbolPatterns) {
+  StringRef path = arg->getValue();
+  Optional<MemoryBufferRef> buffer = readFile(path);
+  if (!buffer) {
+    error("Could not read symbol file: " + path);
+    return;
+  }
+  MemoryBufferRef mbref = *buffer;
+  for (StringRef line : args::getLines(mbref)) {
+    line = line.take_until([](char c) { return c == '#'; }).trim();
+    if (!line.empty())
+      symbolPatterns.insert(line);
+  }
+}
 static void handleSymbolPatterns(InputArgList &args,
                                  SymbolPatterns &symbolPatterns,
                                  unsigned singleOptionCode,
                                  unsigned listFileOptionCode) {
   for (const Arg *arg : args.filtered(singleOptionCode))
     symbolPatterns.insert(arg->getValue());
-  for (const Arg *arg : args.filtered(listFileOptionCode)) {
-    StringRef path = arg->getValue();
-    Optional<MemoryBufferRef> buffer = readFile(path);
-    if (!buffer) {
-      error("Could not read symbol file: " + path);
-      continue;
-    }
-    MemoryBufferRef mbref = *buffer;
-    for (StringRef line : args::getLines(mbref)) {
-      line = line.take_until([](char c) { return c == '#'; }).trim();
-      if (!line.empty())
-        symbolPatterns.insert(line);
-    }
-  }
+  for (const Arg *arg : args.filtered(listFileOptionCode))
+    handleSymbolPatternsListHelper(arg, symbolPatterns);
 }
 
 static void createFiles(const InputArgList &args) {
@@ -1406,9 +1409,53 @@ bool macho::link(ArrayRef<const char *> argsArr, llvm::raw_ostream &stdoutOS,
           ">>> ignoring unexports");
     config->unexportedSymbols.clear();
   }
+
+  // Imitating LD64's:
+  // -non_global_symbols_no_strip_list and -non_global_symbols_strip_list can't
+  // both be present.
+  // But -x can be used with either of these two, in which case, the last arg
+  // takes effect.
+  // (TODO: This is kind of confusing - considering disallowing using them
+  // together for a more straightforward behaviour)
+  {
+    bool includeLocal = false;
+    bool excludeLocal = false;
+    for (const Arg *arg :
+         args.filtered(OPT_x, OPT_non_global_symbols_no_strip_list,
+                       OPT_non_global_symbols_strip_list)) {
+      switch (arg->getOption().getID()) {
+      case OPT_x:
+        config->localSymbolsPresence = SymtabPresence::None;
+
+        break;
+      case OPT_non_global_symbols_no_strip_list:
+        if (excludeLocal) {
+          error("cannot use both -non_global_symbols_no_strip_list and "
+                "-non_global_symbols_strip_list");
+        } else {
+          includeLocal = true;
+          config->localSymbolsPresence = SymtabPresence::SelectivelyIncluded;
+          handleSymbolPatternsListHelper(arg, config->localSymbolPatterns);
+        }
+        break;
+      case OPT_non_global_symbols_strip_list:
+        if (includeLocal) {
+          error("cannot use both -non_global_symbols_no_strip_list and "
+                "-non_global_symbols_strip_list");
+        } else {
+          excludeLocal = true;
+          config->localSymbolsPresence = SymtabPresence::SelectivelyExcluded;
+          handleSymbolPatternsListHelper(arg, config->localSymbolPatterns);
+        }
+        break;
+      default:
+        llvm_unreachable("unexpected option");
+      }
+    }
+  }
   // Explicitly-exported literal symbols must be defined, but might
-  // languish in an archive if unreferenced elsewhere. Light a fire
-  // under those lazy symbols!
+  // languish in an archive if unreferenced elsewhere or if they are in the
+  // non-global strip list. Light a fire under those lazy symbols!
   for (const CachedHashStringRef &cachedName : config->exportedSymbols.literals)
     symtab->addUndefined(cachedName.val(), /*file=*/nullptr,
                          /*isWeakRef=*/false);

diff  --git a/lld/MachO/Options.td b/lld/MachO/Options.td
index 5678ae567f935..21d9dc00b5bb9 100644
--- a/lld/MachO/Options.td
+++ b/lld/MachO/Options.td
@@ -581,17 +581,14 @@ def S : Flag<["-"], "S">,
     Group<grp_symtab>;
 def x : Flag<["-"], "x">,
     HelpText<"Exclude non-global symbols from the output symbol table">,
-    Flags<[HelpHidden]>,
     Group<grp_symtab>;
 def non_global_symbols_strip_list : Separate<["-"], "non_global_symbols_strip_list">,
     MetaVarName<"<path>">,
     HelpText<"Specify in <path> the non-global symbols that should be removed from the output symbol table">,
-    Flags<[HelpHidden]>,
     Group<grp_symtab>;
 def non_global_symbols_no_strip_list : Separate<["-"], "non_global_symbols_no_strip_list">,
     MetaVarName<"<path>">,
     HelpText<"Specify in <path> the non-global symbols that should remain in the output symbol table">,
-    Flags<[HelpHidden]>,
     Group<grp_symtab>;
 def oso_prefix : Separate<["-"], "oso_prefix">,
     MetaVarName<"<path>">,

diff  --git a/lld/MachO/SyntheticSections.cpp b/lld/MachO/SyntheticSections.cpp
index 61597ccf9ebf5..3a5e9daad7291 100644
--- a/lld/MachO/SyntheticSections.cpp
+++ b/lld/MachO/SyntheticSections.cpp
@@ -963,16 +963,41 @@ void SymtabSection::finalizeContents() {
     symbols.push_back({sym, strx});
   };
 
+  std::function<void(Symbol *)> localSymbolsHandler;
+  switch (config->localSymbolsPresence) {
+  case SymtabPresence::All:
+    localSymbolsHandler = [&](Symbol *sym) { addSymbol(localSymbols, sym); };
+    break;
+  case SymtabPresence::None:
+    localSymbolsHandler = [&](Symbol *) { /* Do nothing*/ };
+    break;
+  case SymtabPresence::SelectivelyIncluded:
+    localSymbolsHandler = [&](Symbol *sym) {
+      if (config->localSymbolPatterns.match(sym->getName()))
+        addSymbol(localSymbols, sym);
+    };
+    break;
+  case SymtabPresence::SelectivelyExcluded:
+    localSymbolsHandler = [&](Symbol *sym) {
+      if (!config->localSymbolPatterns.match(sym->getName()))
+        addSymbol(localSymbols, sym);
+    };
+    break;
+  }
+
   // Local symbols aren't in the SymbolTable, so we walk the list of object
   // files to gather them.
-  for (const InputFile *file : inputFiles) {
-    if (auto *objFile = dyn_cast<ObjFile>(file)) {
-      for (Symbol *sym : objFile->symbols) {
-        if (auto *defined = dyn_cast_or_null<Defined>(sym)) {
-          if (defined->isExternal() || !defined->isLive() ||
-              !defined->includeInSymtab)
-            continue;
-          addSymbol(localSymbols, sym);
+  // But if `-x` is set, then we don't need to.
+  if (config->localSymbolsPresence != SymtabPresence::None) {
+    for (const InputFile *file : inputFiles) {
+      if (auto *objFile = dyn_cast<ObjFile>(file)) {
+        for (Symbol *sym : objFile->symbols) {
+          if (auto *defined = dyn_cast_or_null<Defined>(sym)) {
+            if (defined->isExternal() || !defined->isLive() ||
+                !defined->includeInSymtab)
+              continue;
+            localSymbolsHandler(sym);
+          }
         }
       }
     }
@@ -981,7 +1006,7 @@ void SymtabSection::finalizeContents() {
   // __dyld_private is a local symbol too. It's linker-created and doesn't
   // exist in any object file.
   if (Defined *dyldPrivate = in.stubHelper->dyldPrivate)
-    addSymbol(localSymbols, dyldPrivate);
+    localSymbolsHandler(dyldPrivate);
 
   for (Symbol *sym : symtab->getSymbols()) {
     if (!sym->isLive())
@@ -991,7 +1016,7 @@ void SymtabSection::finalizeContents() {
         continue;
       assert(defined->isExternal());
       if (defined->privateExtern)
-        addSymbol(localSymbols, defined);
+        localSymbolsHandler(defined);
       else
         addSymbol(externalSymbols, defined);
     } else if (auto *dysym = dyn_cast<DylibSymbol>(sym)) {

diff  --git a/lld/test/MachO/local-symbol-output.s b/lld/test/MachO/local-symbol-output.s
new file mode 100644
index 0000000000000..3fd9458c00a54
--- /dev/null
+++ b/lld/test/MachO/local-symbol-output.s
@@ -0,0 +1,141 @@
+# REQUIRES: x86
+
+# RUN: rm -rf %t; split-file %s %t
+# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-macos %t/main.s -o %t/main.o
+
+## Check that -non_global_symbols_no_strip_list and -non_global_symbols_strip_list
+## can't be used at the same time.
+# RUN: not %lld %t/main.o -o /dev/null \
+# RUN:       -non_global_symbols_no_strip_list %t/foo.txt \
+# RUN:       -non_global_symbols_strip_list %t/foo.txt 2>&1 | \
+# RUN:     FileCheck --check-prefix=CONFLICT %s
+
+# CONFLICT: error: cannot use both -non_global_symbols_no_strip_list and -non_global_symbols_strip_list
+
+## Check that -x causes none of the local symbols to be emitted.
+# RUN: %lld %t/main.o -x -o %t/no_local.out
+# RUN: llvm-nm %t/no_local.out | FileCheck --check-prefix NO_LOCAL %s
+
+# NO_LOCAL-NOT: t _foo
+# NO_LOCAL-NOT: t _bar
+# NO_LOCAL-NOT: t _baz
+# NO_LOCAL: T _main
+
+## Check that when using -x with -non_global_symbols_no_strip_list, whichever appears
+## last in the command line arg list will take precedence.
+# RUN: %lld %t/main.o -x -non_global_symbols_no_strip_list %t/foo.txt -o %t/x_then_no_strip.out
+# RUN: llvm-nm %t/x_then_no_strip.out | FileCheck --check-prefix X-NO-STRIP %s
+
+# RUN: %lld %t/main.o -non_global_symbols_no_strip_list %t/foo.txt -x -o %t/no_strip_then_x.out
+# RUN: llvm-nm %t/no_strip_then_x.out | FileCheck --check-prefix NO_LOCAL %s
+
+# X-NO-STRIP-NOT: t _bar
+# X-NO-STRIP-DAG: t _foo
+# X-NO-STRIP-DAG: T _main
+
+## Check that -non_global_symbols_no_strip_list can be specified more than once
+## (The final no-strip list is the union of all these)
+# RUN: %lld %t/main.o -o %t/no_strip_multi.out \
+# RUN:    -non_global_symbols_no_strip_list %t/foo.txt \
+# RUN:    -non_global_symbols_no_strip_list %t/bar.txt
+# RUN: llvm-nm %t/no_strip_multi.out | FileCheck --check-prefix NO-STRIP-MULTI %s
+
+# NO-STRIP-MULTI-NOT: t _baz
+# NO-STRIP-MULTI-DAG: t _foo
+# NO-STRIP-MULTI-DAG: t _bar
+# NO-STRIP-MULTI-DAG: T _main
+
+## Check that when using -x with -non_global_symbols_strip_list, whichever appears
+## last in the command line arg list will take precedence.
+# RUN: %lld %t/main.o -x -non_global_symbols_strip_list %t/foo.txt -o %t/x_then_strip.out
+# RUN: llvm-nm %t/x_then_strip.out | FileCheck --check-prefix X-STRIP %s
+
+# RUN: %lld %t/main.o -non_global_symbols_strip_list %t/foo.txt -x -o %t/strip_then_x.out
+# RUN: llvm-nm %t/no_strip_then_x.out | FileCheck --check-prefix NO_LOCAL %s
+
+# X-STRIP-NOT: t _foo
+# X-STRIP-DAG: t _bar
+# X-STRIP-DAG: t _baz
+# X-STRIP-DAG: T _main
+
+## Check that -non_global_symbols_strip_list can be specified more than once
+## (The final strip list is the union of all these)
+# RUN: %lld %t/main.o -o %t/strip_multi.out \
+# RUN:    -non_global_symbols_strip_list %t/foo.txt \
+# RUN:    -non_global_symbols_strip_list %t/bar.txt
+# RUN: llvm-nm %t/strip_multi.out | FileCheck --check-prefix STRIP-MULTI %s
+
+# STRIP-MULTI-NOT: t _foo
+# STRIP-MULTI-NOT: t _bar
+# STRIP-MULTI-DAG: t _baz
+# STRIP-MULTI-DAG: T _main
+
+## Test interactions with exported_symbol.
+# RUN: %lld %t/main.o -o %t/strip_all_export_one.out \
+# RUN:    -x -exported_symbol _foo \
+# RUN:    -undefined dynamic_lookup
+# RUN: llvm-nm %t/strip_all_export_one.out | FileCheck --check-prefix STRIP-EXP %s
+
+# STRIP-EXP: U _foo
+# STRIP-EXP-EMPTY:
+
+## Test interactions of -x and -non_global_symbols_strip_list with unexported_symbol.
+# RUN: %lld %t/main.o -o %t/strip_x_unexport_one.out \
+# RUN:    -x -unexported_symbol _globby \
+# RUN:    -undefined dynamic_lookup
+
+# RUN: %lld %t/main.o -o %t/strip_all_unexport_one.out \
+# RUN:    -non_global_symbols_strip_list %t/globby.txt \
+# RUN:    -non_global_symbols_strip_list %t/foo.txt \
+# RUN:    -non_global_symbols_strip_list %t/bar.txt \
+# RUN:    -unexported_symbol _globby \
+# RUN:    -undefined dynamic_lookup
+
+# RUN: llvm-nm %t/strip_x_unexport_one.out | FileCheck --check-prefix STRIP-UNEXP %s
+# RUN: llvm-nm %t/strip_all_unexport_one.out | FileCheck --check-prefix STRIP-UNEXP %s
+
+## -unexported_symbol made _globby a local, therefore it should be stripped by -x too
+# STRIP-UNEXP: T __mh_execute_header
+# STRIP-UNEXP-DAG: T _main
+# STRIP-UNEXP-EMPTY:
+
+## Test interactions of -non_global_symbols_strip_list and unexported_symbol.
+# RUN: %lld %t/main.o -undefined dynamic_lookup -o %t/no_strip_unexport.out \
+# RUN:    -non_global_symbols_no_strip_list %t/globby.txt \
+# RUN:    -unexported_symbol _globby
+
+# RUN: llvm-nm %t/no_strip_unexport.out | FileCheck --check-prefix NOSTRIP-UNEXP %s
+
+# NOSTRIP-UNEXP: T __mh_execute_header
+# NOSTRIP-UNEXP-DAG: T _main
+# NOSTRIP-UNEXP-DAG: t _globby
+# NOSTRIP-UNEXP-EMPTY:
+
+#--- foo.txt
+_foo
+
+#--- bar.txt
+_bar
+
+#--- globby.txt
+_globby
+
+#--- main.s
+.globl _main
+.globl _globby
+
+_foo:
+  ret
+
+_bar:
+  ret
+
+_baz:
+  ret
+
+_main:
+  callq _foo
+  ret
+
+ _globby:
+  ret
\ No newline at end of file


        


More information about the llvm-commits mailing list