[lld/mac] Propagate -(un)exported_symbol(s_list) to privateExtern in Driver
authorNico Weber <thakis@chromium.org>
Tue, 18 May 2021 00:53:55 +0000 (20:53 -0400)
committerNico Weber <thakis@chromium.org>
Tue, 18 May 2021 11:42:58 +0000 (07:42 -0400)
That way, it's done only once instead of every time shouldExportSymbol() is
called.

Possibly a bit faster:

    % ministat at_main at_symtodo
    x at_main
    + at_symtodo
        N           Min           Max        Median           Avg        Stddev
    x  30     3.9732189      4.114846      4.024621     4.0304692   0.037022865
    +  30       3.93766     4.0510042     3.9973931      3.991469   0.028472565
    Difference at 95.0% confidence
            -0.0390002 +/- 0.0170714
            -0.967635% +/- 0.423559%
            (Student's t, pooled s = 0.0330256)

In other runs with n=30 it makes no perf difference, so maybe it's just noise.
But being able to quickly and conveniently answer "is this symbol exported?"
is useful for fixing PR50373 and for implementing -dead_strip, so this seems
like a good change regardless.

No behavior change.

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

lld/MachO/Driver.cpp
lld/MachO/SyntheticSections.cpp

index 135ca2d..6ce261c 100644 (file)
@@ -1196,6 +1196,27 @@ bool macho::link(ArrayRef<const char *> argsArr, bool canExitEarly,
     createSyntheticSections();
     createSyntheticSymbols();
 
+    if (!config->exportedSymbols.empty()) {
+      for (Symbol *sym : symtab->getSymbols()) {
+        if (auto *defined = dyn_cast<Defined>(sym)) {
+          StringRef symbolName = defined->getName();
+          if (config->exportedSymbols.match(symbolName)) {
+            if (defined->privateExtern) {
+              error("cannot export hidden symbol " + symbolName +
+                    "\n>>> defined in " + toString(defined->getFile()));
+            }
+          } else {
+            defined->privateExtern = true;
+          }
+        }
+      }
+    } else if (!config->unexportedSymbols.empty()) {
+      for (Symbol *sym : symtab->getSymbols())
+        if (auto *defined = dyn_cast<Defined>(sym))
+          if (config->unexportedSymbols.match(defined->getName()))
+            defined->privateExtern = true;
+    }
+
     for (const Arg *arg : args.filtered(OPT_sectcreate)) {
       StringRef segName = arg->getValue(0);
       StringRef sectName = arg->getValue(1);
index f1afbc7..38c93e1 100644 (file)
@@ -566,40 +566,11 @@ uint32_t LazyBindingSection::encode(const DylibSymbol &sym) {
 ExportSection::ExportSection()
     : LinkEditSection(segment_names::linkEdit, section_names::export_) {}
 
-static void validateExportSymbol(const Defined *defined) {
-  StringRef symbolName = defined->getName();
-  if (defined->privateExtern && config->exportedSymbols.match(symbolName))
-    error("cannot export hidden symbol " + symbolName + "\n>>> defined in " +
-          toString(defined->getFile()));
-}
-
-static bool shouldExportSymbol(const Defined *defined) {
-  if (defined->privateExtern) {
-    assert(defined->isExternal() && "invalid input file");
-    return false;
-  }
-  // TODO: Is this a performance bottleneck? If a build has mostly
-  // global symbols in the input but uses -exported_symbols to filter
-  // out most of them, then it would be better to set the value of
-  // privateExtern at parse time instead of calling
-  // exportedSymbols.match() more than once.
-  //
-  // Measurements show that symbol ordering (which again looks up
-  // every symbol in a hashmap) is the biggest bottleneck when linking
-  // chromium_framework, so this will likely be worth optimizing.
-  if (!config->exportedSymbols.empty())
-    return config->exportedSymbols.match(defined->getName());
-  if (!config->unexportedSymbols.empty())
-    return !config->unexportedSymbols.match(defined->getName());
-  return true;
-}
-
 void ExportSection::finalizeContents() {
   trieBuilder.setImageBase(in.header->addr);
   for (const Symbol *sym : symtab->getSymbols()) {
     if (const auto *defined = dyn_cast<Defined>(sym)) {
-      validateExportSymbol(defined);
-      if (!shouldExportSymbol(defined))
+      if (defined->privateExtern)
         continue;
       trieBuilder.addSymbol(*defined);
       hasWeakSymbol = hasWeakSymbol || sym->isWeakDef();
@@ -834,7 +805,7 @@ template <class LP> void SymtabSectionImpl<LP>::writeTo(uint8_t *buf) const {
     // TODO populate n_desc with more flags
     if (auto *defined = dyn_cast<Defined>(entry.sym)) {
       uint8_t scope = 0;
-      if (!shouldExportSymbol(defined)) {
+      if (defined->privateExtern) {
         // Private external -- dylib scoped symbol.
         // Promote to non-external at link time.
         scope = N_PEXT;