[llvm-branch-commits] [lld] release/20.x: [ELF] Refine isExported/isPreemptible condition (PR #125334)

via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Fri Jan 31 20:56:45 PST 2025


https://github.com/llvmbot created https://github.com/llvm/llvm-project/pull/125334

Backport 45f538ecba1a51768002a5bc0c194b5af4cd9c27 d6fa74ab3d4cc77005836e72a2d6fe222bab4c59 994cea3f0a2d0caf4d66321ad5a06ab330144d89

Requested by: @MaskRay

>From c6326a22ed1251a1527f7abc8971683e1d7c078c Mon Sep 17 00:00:00 2001
From: Fangrui Song <i at maskray.me>
Date: Thu, 30 Jan 2025 19:03:38 -0800
Subject: [PATCH 1/3] [ELF] ICF: replace includeInDynsym with isExported

Similar to the change to MarkLive.cpp when isExported was introduced.
includeInDynsym might return true even when isExported is false for
statically linked executables.

(cherry picked from commit 45f538ecba1a51768002a5bc0c194b5af4cd9c27)
---
 lld/ELF/Driver.cpp      | 2 +-
 lld/test/ELF/icf-safe.s | 9 ++++++---
 2 files changed, 7 insertions(+), 4 deletions(-)

diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp
index 9d0c992c1e85164..98523429a5078c3 100644
--- a/lld/ELF/Driver.cpp
+++ b/lld/ELF/Driver.cpp
@@ -2413,7 +2413,7 @@ static void findKeepUniqueSections(Ctx &ctx, opt::InputArgList &args) {
   // or DSOs, so we conservatively mark them as address-significant.
   bool icfSafe = ctx.arg.icf == ICFLevel::Safe;
   for (Symbol *sym : ctx.symtab->getSymbols())
-    if (sym->includeInDynsym(ctx))
+    if (sym->isExported)
       markAddrsig(icfSafe, sym);
 
   // Visit the address-significance table in each object file and mark each
diff --git a/lld/test/ELF/icf-safe.s b/lld/test/ELF/icf-safe.s
index 96776feccbc6777..53815326099381e 100644
--- a/lld/test/ELF/icf-safe.s
+++ b/lld/test/ELF/icf-safe.s
@@ -1,16 +1,19 @@
 # REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64 %S/Inputs/shared.s -o %ta.o
+# RUN: ld.lld -shared -soname=ta %ta.o -o %ta.so
 
 # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o
 # RUN: llvm-objcopy %t1.o %t1copy.o
 # RUN: llvm-objcopy --localize-symbol=h1 %t1.o %t1changed.o
 # RUN: ld.lld -r %t1.o -o %t1reloc.o
 # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %S/Inputs/icf-safe.s -o %t2.o
-# RUN: ld.lld %t1.o %t2.o -o %t2 --icf=safe --print-icf-sections | FileCheck %s
+# RUN: ld.lld %t1.o %t2.o -o %t2 --icf=safe --print-icf-sections --export-dynamic | FileCheck %s
 # RUN: ld.lld %t1copy.o %t2.o -o %t2 --icf=safe --print-icf-sections | FileCheck %s
 # RUN: ld.lld %t1.o %t2.o -o %t3 --icf=safe --print-icf-sections -shared | FileCheck --check-prefix=EXPORT %s
-# RUN: ld.lld %t1.o %t2.o -o %t3 --icf=safe --print-icf-sections --export-dynamic | FileCheck --check-prefix=EXPORT %s
+## Exported symbols are suppressed for ICF when dynamic linking is enabled.
+# RUN: ld.lld %t1.o %t2.o %ta.so -o %t3 --icf=safe --print-icf-sections --export-dynamic | FileCheck --check-prefix=EXPORT %s
 # RUN: ld.lld %t1.o %t2.o -o %t2 --icf=all --print-icf-sections | FileCheck --check-prefix=ALL %s
-# RUN: ld.lld %t1.o %t2.o -o %t2 --icf=all --print-icf-sections --export-dynamic | FileCheck --check-prefix=ALL-EXPORT %s
+# RUN: ld.lld %t1.o %t2.o %ta.so -o %t2 --icf=all --print-icf-sections --export-dynamic | FileCheck --check-prefix=ALL-EXPORT %s
 # RUN: ld.lld %t1changed.o -o %t4 --icf=safe 2>&1 | FileCheck --check-prefix=SH_LINK_0 %s
 # RUN: ld.lld %t1reloc.o -o %t4 --icf=safe 2>&1 | FileCheck --check-prefix=SH_LINK_0 %s
 

>From 3234454c49a30447b7989529bf87928924e9f0af Mon Sep 17 00:00:00 2001
From: Fangrui Song <i at maskray.me>
Date: Thu, 30 Jan 2025 22:24:04 -0800
Subject: [PATCH 2/3] [ELF] Merge exportDynamic/isExported and remove
 Symbol::includeInDynsym

Commit 3733ed6f1c6b0eef1e13e175ac81ad309fc0b080 introduced isExported to
cache includeInDynsym. If we don't unnecessarily set isExported for
undefined symbols, exportDynamic/includeInDynsym can be replaced with
isExported.

(cherry picked from commit d6fa74ab3d4cc77005836e72a2d6fe222bab4c59)
---
 lld/ELF/Driver.cpp            |  3 ++-
 lld/ELF/InputFiles.cpp        |  4 ++--
 lld/ELF/SymbolTable.cpp       |  8 +++-----
 lld/ELF/Symbols.cpp           | 27 +++++++++++++--------------
 lld/ELF/Symbols.h             | 15 +++++----------
 lld/ELF/SyntheticSections.cpp |  4 ++--
 lld/ELF/Writer.cpp            | 13 +++++++------
 7 files changed, 34 insertions(+), 40 deletions(-)

diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp
index 98523429a5078c3..acbc97b331b0e1c 100644
--- a/lld/ELF/Driver.cpp
+++ b/lld/ELF/Driver.cpp
@@ -2554,7 +2554,8 @@ void LinkerDriver::compileBitcodeFiles(bool skipLinkedOutput) {
       for (Symbol *sym : obj->getGlobalSymbols()) {
         if (!sym->isDefined())
           continue;
-        if (ctx.hasDynsym && sym->includeInDynsym(ctx))
+        if (ctx.hasDynsym && ctx.arg.exportDynamic &&
+            sym->computeBinding(ctx) != STB_LOCAL)
           sym->isExported = true;
         if (sym->hasVersionSuffix)
           sym->parseSymbolVersion(ctx);
diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp
index 42d0e4c202ec617..16943c484d96bc6 100644
--- a/lld/ELF/InputFiles.cpp
+++ b/lld/ELF/InputFiles.cpp
@@ -1574,7 +1574,7 @@ template <class ELFT> void SharedFile::parse() {
       }
       Symbol *s = ctx.symtab->addSymbol(
           Undefined{this, name, sym.getBinding(), sym.st_other, sym.getType()});
-      s->exportDynamic = true;
+      s->isExported = true;
       if (sym.getBinding() != STB_WEAK &&
           ctx.arg.unresolvedSymbolsInShlib != UnresolvedPolicy::Ignore)
         requiredSymbols.push_back(s);
@@ -1771,7 +1771,7 @@ static void createBitcodeSymbol(Ctx &ctx, Symbol *&sym,
                    nullptr);
     // The definition can be omitted if all bitcode definitions satisfy
     // `canBeOmittedFromSymbolTable()` and isUsedInRegularObj is false.
-    // The latter condition is tested in Symbol::includeInDynsym.
+    // The latter condition is tested in parseVersionAndComputeIsPreemptible.
     sym->ltoCanOmit = objSym.canBeOmittedFromSymbolTable() &&
                       (!sym->isDefined() || sym->ltoCanOmit);
     sym->resolve(ctx, newSym);
diff --git a/lld/ELF/SymbolTable.cpp b/lld/ELF/SymbolTable.cpp
index 975700505facb4f..b8a70d4e898fc2e 100644
--- a/lld/ELF/SymbolTable.cpp
+++ b/lld/ELF/SymbolTable.cpp
@@ -203,7 +203,7 @@ void SymbolTable::handleDynamicList() {
       syms = findByVersion(ver);
 
     for (Symbol *sym : syms)
-      sym->exportDynamic = sym->inDynamicList = true;
+      sym->isExported = sym->inDynamicList = true;
   }
 }
 
@@ -350,10 +350,8 @@ void SymbolTable::scanVersionScript() {
         assignAsterisk(pat, &v, true);
   }
 
-  // isPreemptible is false at this point. To correctly compute the binding of a
-  // Defined (which is used by includeInDynsym(ctx)), we need to know if it is
-  // VER_NDX_LOCAL or not. Compute symbol versions before handling
-  // --dynamic-list.
+  // Handle --dynamic-list. If a specified symbol is also matched by local: in a
+  // version script, the version script takes precedence.
   handleDynamicList();
 }
 
diff --git a/lld/ELF/Symbols.cpp b/lld/ELF/Symbols.cpp
index b10391c65dfdc31..890877cb1bc0463 100644
--- a/lld/ELF/Symbols.cpp
+++ b/lld/ELF/Symbols.cpp
@@ -268,16 +268,6 @@ uint8_t Symbol::computeBinding(Ctx &ctx) const {
   return binding;
 }
 
-bool Symbol::includeInDynsym(Ctx &ctx) const {
-  if (computeBinding(ctx) == STB_LOCAL)
-    return false;
-  if (!isDefined() && !isCommon())
-    return true;
-
-  return exportDynamic ||
-         (ctx.arg.exportDynamic && (isUsedInRegularObj || !ltoCanOmit));
-}
-
 // Print out a log message for --trace-symbol.
 void elf::printTraceSymbol(const Symbol &sym, StringRef name) {
   std::string s;
@@ -374,9 +364,18 @@ void elf::parseVersionAndComputeIsPreemptible(Ctx &ctx) {
   for (Symbol *sym : ctx.symtab->getSymbols()) {
     if (sym->hasVersionSuffix)
       sym->parseSymbolVersion(ctx);
-    if (hasDynsym) {
-      sym->isExported = sym->includeInDynsym(ctx);
-      sym->isPreemptible = sym->isExported && computeIsPreemptible(ctx, *sym);
+    if (!hasDynsym)
+      continue;
+    if (sym->computeBinding(ctx) == STB_LOCAL) {
+      sym->isExported = false;
+      continue;
+    }
+    if (!sym->isDefined() && !sym->isCommon()) {
+      sym->isPreemptible = computeIsPreemptible(ctx, *sym);
+    } else if (ctx.arg.exportDynamic &&
+               (sym->isUsedInRegularObj || !sym->ltoCanOmit)) {
+      sym->isExported = true;
+      sym->isPreemptible = computeIsPreemptible(ctx, *sym);
     }
   }
 }
@@ -655,7 +654,7 @@ void Symbol::resolve(Ctx &ctx, const LazySymbol &other) {
 }
 
 void Symbol::resolve(Ctx &ctx, const SharedSymbol &other) {
-  exportDynamic = true;
+  isExported = true;
   if (isPlaceholder()) {
     other.overwrite(*this);
     return;
diff --git a/lld/ELF/Symbols.h b/lld/ELF/Symbols.h
index 48df6f60db864bb..64f2f6eaa8d09d8 100644
--- a/lld/ELF/Symbols.h
+++ b/lld/ELF/Symbols.h
@@ -105,6 +105,9 @@ class Symbol {
   uint8_t partition;
 
   // True if this symbol is preemptible at load time.
+  //
+  // Primarily set in two locations, (a) parseVersionAndComputeIsPreemptible and
+  // (b) demoteSymbolsAndComputeIsPreemptible.
   LLVM_PREFERRED_TYPE(bool)
   uint8_t isPreemptible : 1;
 
@@ -131,16 +134,9 @@ class Symbol {
   // - If -shared or --export-dynamic is specified, any symbol in an object
   //   file/bitcode sets this property, unless suppressed by LTO
   //   canBeOmittedFromSymbolTable().
-  //
-  // Primarily set in two locations, (a) after parseSymbolVersion and
-  // (b) during demoteSymbols.
   LLVM_PREFERRED_TYPE(bool)
   uint8_t isExported : 1;
 
-  // Used to compute isExported. Set when defined or referenced by a SharedFile.
-  LLVM_PREFERRED_TYPE(bool)
-  uint8_t exportDynamic : 1;
-
   LLVM_PREFERRED_TYPE(bool)
   uint8_t ltoCanOmit : 1;
 
@@ -159,7 +155,6 @@ class Symbol {
     stOther = (stOther & ~3) | visibility;
   }
 
-  bool includeInDynsym(Ctx &) const;
   uint8_t computeBinding(Ctx &) const;
   bool isGlobal() const { return binding == llvm::ELF::STB_GLOBAL; }
   bool isWeak() const { return binding == llvm::ELF::STB_WEAK; }
@@ -247,8 +242,8 @@ class Symbol {
   Symbol(Kind k, InputFile *file, StringRef name, uint8_t binding,
          uint8_t stOther, uint8_t type)
       : file(file), nameData(name.data()), nameSize(name.size()), type(type),
-        binding(binding), stOther(stOther), symbolKind(k), exportDynamic(false),
-        ltoCanOmit(false), archSpecificBit(false) {}
+        binding(binding), stOther(stOther), symbolKind(k), ltoCanOmit(false),
+        archSpecificBit(false) {}
 
   void overwrite(Symbol &sym, Kind k) const {
     if (sym.traced)
diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp
index eb07d82fc96012e..ffa6e3c008c48ed 100644
--- a/lld/ELF/SyntheticSections.cpp
+++ b/lld/ELF/SyntheticSections.cpp
@@ -4776,8 +4776,8 @@ template <class ELFT> void elf::createSyntheticSections(Ctx &ctx) {
       add(*part.buildId);
     }
 
-    // dynSymTab is always present to simplify sym->includeInDynsym(ctx) in
-    // finalizeSections.
+    // dynSymTab is always present to simplify several finalizeSections
+    // functions.
     part.dynStrTab = std::make_unique<StringTableSection>(ctx, ".dynstr", true);
     part.dynSymTab =
         std::make_unique<SymbolTableSection<ELFT>>(ctx, *part.dynStrTab);
diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp
index 6c7bcee02047b57..3ba1cdbce572b79 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -296,13 +296,12 @@ static void demoteSymbolsAndComputeIsPreemptible(Ctx &ctx) {
                   sym->type)
             .overwrite(*sym);
         sym->versionId = VER_NDX_GLOBAL;
-        if (hasDynsym && sym->includeInDynsym(ctx))
-          sym->isExported = true;
       }
     }
 
     if (hasDynsym)
-      sym->isPreemptible = sym->isExported && computeIsPreemptible(ctx, *sym);
+      sym->isPreemptible = (sym->isUndefined() || sym->isExported) &&
+                           computeIsPreemptible(ctx, *sym);
   }
 }
 
@@ -1841,9 +1840,10 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
 
   // If the previous code block defines any non-hidden symbols (e.g.
   // __global_pointer$), they may be exported.
-  if (ctx.hasDynsym)
+  if (ctx.hasDynsym && ctx.arg.exportDynamic)
     for (Symbol *sym : ctx.synthesizedSymbols)
-      sym->isExported = sym->includeInDynsym(ctx);
+      if (sym->computeBinding(ctx) != STB_LOCAL)
+        sym->isExported = true;
 
   demoteSymbolsAndComputeIsPreemptible(ctx);
 
@@ -1931,7 +1931,8 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
 
       // computeBinding might localize a linker-synthesized hidden symbol
       // (e.g. __global_pointer$) that was considered exported.
-      if (sym->isExported && !sym->isLocal()) {
+      if (ctx.hasDynsym && (sym->isUndefined() || sym->isExported) &&
+          !sym->isLocal()) {
         ctx.partitions[sym->partition - 1].dynSymTab->addSymbol(sym);
         if (auto *file = dyn_cast<SharedFile>(sym->file))
           if (file->isNeeded && !sym->isUndefined())

>From 3495ffab2787c228d230d5ed097f8944a20c579e Mon Sep 17 00:00:00 2001
From: Fangrui Song <i at maskray.me>
Date: Fri, 31 Jan 2025 20:37:17 -0800
Subject: [PATCH 3/3] [ELF] Refine isExported/isPreemptible condition

Commit f10441ad003236ef3b9e5415a571d2be0c0ce5ce dropped a special case
for isUndefWeak and --no-dynamic-linking but also made --export-dynamic
ineffective for static PIE.

This change restores the --export-dynamic behavior and entirely drops
special handling of --no-dynamic-linker:

* -pie with no input DSO, similar to --no-dynamic-linker, suppresses
  undefined symbols in .dynsym

The new behaviors resemble GNU ld more.

(cherry picked from commit 994cea3f0a2d0caf4d66321ad5a06ab330144d89)
---
 lld/ELF/Config.h                              |  2 --
 lld/ELF/Driver.cpp                            | 11 ++---------
 lld/ELF/Symbols.cpp                           |  4 +++-
 lld/ELF/SyntheticSections.cpp                 |  4 ++--
 lld/ELF/Writer.cpp                            |  7 ++++---
 lld/test/ELF/executable-undefined-ignoreall.s |  6 ++++--
 lld/test/ELF/ppc32-weak-undef-call.s          |  6 +++---
 lld/test/ELF/ppc64-undefined-weak.s           | 16 ++++++++--------
 lld/test/ELF/riscv-gp.s                       | 13 ++++++++-----
 lld/test/ELF/weak-undef-lib.s                 |  2 +-
 lld/test/ELF/weak-undef-no-dynamic-linker.s   |  7 +++----
 lld/test/ELF/weak-undef-rw.s                  | 16 ++++++++--------
 12 files changed, 46 insertions(+), 48 deletions(-)

diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h
index c2aadb2cef5200f..df262fdc811b09a 100644
--- a/lld/ELF/Config.h
+++ b/lld/ELF/Config.h
@@ -292,7 +292,6 @@ struct Config {
   bool gdbIndex;
   bool gnuHash = false;
   bool gnuUnique;
-  bool hasDynSymTab;
   bool ignoreDataAddressEquality;
   bool ignoreFunctionAddressEquality;
   bool ltoCSProfileGenerate;
@@ -306,7 +305,6 @@ struct Config {
   bool mipsN32Abi = false;
   bool mmapOutputFile;
   bool nmagic;
-  bool noDynamicLinker = false;
   bool noinhibitExec;
   bool nostdlib;
   bool oFormatBinary;
diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp
index acbc97b331b0e1c..d92338608b059d4 100644
--- a/lld/ELF/Driver.cpp
+++ b/lld/ELF/Driver.cpp
@@ -781,11 +781,8 @@ static StringRef getDynamicLinker(Ctx &ctx, opt::InputArgList &args) {
   auto *arg = args.getLastArg(OPT_dynamic_linker, OPT_no_dynamic_linker);
   if (!arg)
     return "";
-  if (arg->getOption().getID() == OPT_no_dynamic_linker) {
-    // --no-dynamic-linker suppresses undefined weak symbols in .dynsym
-    ctx.arg.noDynamicLinker = true;
+  if (arg->getOption().getID() == OPT_no_dynamic_linker)
     return "";
-  }
   return arg->getValue();
 }
 
@@ -2900,12 +2897,8 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &args) {
 
   parseFiles(ctx, files);
 
-  // Dynamic linking is used if there is an input DSO,
-  // or -shared or non-static pie is specified.
-  ctx.hasDynsym = !ctx.sharedFiles.empty() || ctx.arg.shared ||
-                  (ctx.arg.pie && !ctx.arg.noDynamicLinker);
   // Create dynamic sections for dynamic linking and static PIE.
-  ctx.arg.hasDynSymTab = ctx.hasDynsym || ctx.arg.isPic;
+  ctx.hasDynsym = !ctx.sharedFiles.empty() || ctx.arg.isPic;
 
   // If an entry symbol is in a static archive, pull out that file now.
   if (Symbol *sym = ctx.symtab->find(ctx.arg.entry))
diff --git a/lld/ELF/Symbols.cpp b/lld/ELF/Symbols.cpp
index 890877cb1bc0463..80b069142800725 100644
--- a/lld/ELF/Symbols.cpp
+++ b/lld/ELF/Symbols.cpp
@@ -360,7 +360,9 @@ void elf::parseVersionAndComputeIsPreemptible(Ctx &ctx) {
   // Symbol themselves might know their versions because symbols
   // can contain versions in the form of <name>@<version>.
   // Let them parse and update their names to exclude version suffix.
+  // In addition, compute isExported and isPreemptible.
   bool hasDynsym = ctx.hasDynsym;
+  bool maybePreemptible = ctx.sharedFiles.size() || ctx.arg.shared;
   for (Symbol *sym : ctx.symtab->getSymbols()) {
     if (sym->hasVersionSuffix)
       sym->parseSymbolVersion(ctx);
@@ -371,7 +373,7 @@ void elf::parseVersionAndComputeIsPreemptible(Ctx &ctx) {
       continue;
     }
     if (!sym->isDefined() && !sym->isCommon()) {
-      sym->isPreemptible = computeIsPreemptible(ctx, *sym);
+      sym->isPreemptible = maybePreemptible && computeIsPreemptible(ctx, *sym);
     } else if (ctx.arg.exportDynamic &&
                (sym->isUsedInRegularObj || !sym->ltoCanOmit)) {
       sym->isExported = true;
diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp
index ffa6e3c008c48ed..b03c4282ab1aa5d 100644
--- a/lld/ELF/SyntheticSections.cpp
+++ b/lld/ELF/SyntheticSections.cpp
@@ -4740,7 +4740,7 @@ template <class ELFT> void elf::createSyntheticSections(Ctx &ctx) {
 
   // Add MIPS-specific sections.
   if (ctx.arg.emachine == EM_MIPS) {
-    if (!ctx.arg.shared && ctx.arg.hasDynSymTab) {
+    if (!ctx.arg.shared && ctx.hasDynsym) {
       ctx.in.mipsRldMap = std::make_unique<MipsRldMapSection>(ctx);
       add(*ctx.in.mipsRldMap);
     }
@@ -4803,7 +4803,7 @@ template <class ELFT> void elf::createSyntheticSections(Ctx &ctx) {
       part.relaDyn = std::make_unique<RelocationSection<ELFT>>(
           ctx, relaDynName, ctx.arg.zCombreloc, threadCount);
 
-    if (ctx.arg.hasDynSymTab) {
+    if (ctx.hasDynsym) {
       add(*part.dynSymTab);
 
       part.verSym = std::make_unique<VersionTableSection>(ctx);
diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp
index 3ba1cdbce572b79..487fb119a966b12 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -284,6 +284,7 @@ static void demoteSymbolsAndComputeIsPreemptible(Ctx &ctx) {
   llvm::TimeTraceScope timeScope("Demote symbols");
   DenseMap<InputFile *, DenseMap<SectionBase *, size_t>> sectionIndexMap;
   bool hasDynsym = ctx.hasDynsym;
+  bool maybePreemptible = ctx.sharedFiles.size() || ctx.arg.shared;
   for (Symbol *sym : ctx.symtab->getSymbols()) {
     if (auto *d = dyn_cast<Defined>(sym)) {
       if (d->section && !d->section->isLive())
@@ -300,7 +301,8 @@ static void demoteSymbolsAndComputeIsPreemptible(Ctx &ctx) {
     }
 
     if (hasDynsym)
-      sym->isPreemptible = (sym->isUndefined() || sym->isExported) &&
+      sym->isPreemptible = maybePreemptible &&
+                           (sym->isUndefined() || sym->isExported) &&
                            computeIsPreemptible(ctx, *sym);
   }
 }
@@ -1931,8 +1933,7 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
 
       // computeBinding might localize a linker-synthesized hidden symbol
       // (e.g. __global_pointer$) that was considered exported.
-      if (ctx.hasDynsym && (sym->isUndefined() || sym->isExported) &&
-          !sym->isLocal()) {
+      if ((sym->isExported || sym->isPreemptible) && !sym->isLocal()) {
         ctx.partitions[sym->partition - 1].dynSymTab->addSymbol(sym);
         if (auto *file = dyn_cast<SharedFile>(sym->file))
           if (file->isNeeded && !sym->isUndefined())
diff --git a/lld/test/ELF/executable-undefined-ignoreall.s b/lld/test/ELF/executable-undefined-ignoreall.s
index 073b22bd84543a6..1f83b1b61830a4f 100644
--- a/lld/test/ELF/executable-undefined-ignoreall.s
+++ b/lld/test/ELF/executable-undefined-ignoreall.s
@@ -1,11 +1,13 @@
 # REQUIRES: x86
 
-## --unresolved-symbols=ignore-all behaves similar to -shared:
+## In dynamic linking, --unresolved-symbols=ignore-all behaves similar to -shared:
 ## for PLT relocations to undefined symbols, produce dynamic relocations if we
 ## emit .dynsym.
 
+# RUN: llvm-mc -filetype=obj -triple=x86_64 %S/Inputs/shared.s -o %ta.o
+# RUN: ld.lld -shared -soname=ta %ta.o -o %ta.so
 # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
-# RUN: ld.lld %t.o -o %t --unresolved-symbols=ignore-all -pie
+# RUN: ld.lld %t.o %ta.so -o %t --unresolved-symbols=ignore-all -pie
 # RUN: llvm-readobj -r %t | FileCheck %s
 
 # CHECK:      Relocations [
diff --git a/lld/test/ELF/ppc32-weak-undef-call.s b/lld/test/ELF/ppc32-weak-undef-call.s
index dfb45e5fe18cfd3..1ad280a49c038f1 100644
--- a/lld/test/ELF/ppc32-weak-undef-call.s
+++ b/lld/test/ELF/ppc32-weak-undef-call.s
@@ -1,15 +1,15 @@
 # REQUIRES: ppc
 # RUN: llvm-mc -filetype=obj -triple=powerpc %s -o %t.o
 # RUN: ld.lld %t.o -o %t
-# RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck --check-prefix=PDE %s
+# RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck --check-prefix=STATIC %s
 # RUN: ld.lld -pie %t.o -o %t
-# RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck --check-prefix=PIC %s
+# RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck --check-prefix=STATIC %s
 # RUN: ld.lld -shared %t.o -o %t
 # RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck --check-prefix=PIC %s
 
 ## It does not really matter how we fixup it, but we cannot overflow and
 ## should not generate a call stub (this would waste space).
-# PDE: bl 0x100100b4
+# STATIC: bl {{.*}} <.text>
 
 ## With -pie or -shared, create a call stub. ld.bfd produces bl .+0
 # PIC:       bl 0x[[PLT:[0-9a-f]+]]
diff --git a/lld/test/ELF/ppc64-undefined-weak.s b/lld/test/ELF/ppc64-undefined-weak.s
index 7b1be5e36dd3278..e9168020b216fdf 100644
--- a/lld/test/ELF/ppc64-undefined-weak.s
+++ b/lld/test/ELF/ppc64-undefined-weak.s
@@ -2,25 +2,25 @@
 
 # RUN: llvm-mc -filetype=obj -triple=powerpc64le %s -o %t.o
 # RUN: ld.lld %t.o -o %t
-# RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck %s --check-prefix=PDE
+# RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck %s --check-prefix=STATIC
 # RUN: ld.lld -pie %t.o -o %t
-# RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck %s --check-prefix=PIC
+# RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck %s --check-prefix=STATIC
 # RUN: ld.lld -shared %t.o -o %t.so
 # RUN: llvm-objdump -d --no-show-raw-insn %t.so | FileCheck %s --check-prefix=PIC
 
 # RUN: llvm-mc -filetype=obj -triple=powerpc64 %s -o %t.o
 # RUN: ld.lld %t.o -o %t
-# RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck %s --check-prefix=PDE
+# RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck %s --check-prefix=STATIC
 
 ## Branches to an undefined weak symbol need a thunk iff a dynamic relocation is
 ## produced. undefweak2 is hidden and does not need a dynamic relocation, so we
 ## suppress the thunk. undefweak1 needs a thunk iff -pie or -shared.
 
-# PDE-LABEL: <_start>:
-# PDE-NEXT:    bl {{.*}} <_start>
-# PDE-NEXT:    nop
-# PDE-NEXT:    bl {{.*}} <_start+0x8>
-# PDE-NEXT:    nop
+# STATIC-LABEL: <_start>:
+# STATIC-NEXT:    bl {{.*}} <_start>
+# STATIC-NEXT:    nop
+# STATIC-NEXT:    bl {{.*}} <_start+0x8>
+# STATIC-NEXT:    nop
 
 # PIC-LABEL: <_start>:
 # PIC-NEXT:    bl {{.*}} <__plt_undefweak1>
diff --git a/lld/test/ELF/riscv-gp.s b/lld/test/ELF/riscv-gp.s
index a30f5e9fbc6250a..2f715e1470f2da8 100644
--- a/lld/test/ELF/riscv-gp.s
+++ b/lld/test/ELF/riscv-gp.s
@@ -14,17 +14,20 @@
 # SEC32: {{0*}}000039c0 0 NOTYPE GLOBAL DEFAULT [[#SDATA]] __global_pointer$
 
 # SEC64: [ [[#SDATA:]]] .sdata PROGBITS {{0*}}000032e0
+# SEC64:     '.dynsym'
+# SEC64-NOT: __global_pointer$
+# SEC64:     '.symtab'
 # SEC64: {{0*}}00003ae0 0 NOTYPE GLOBAL DEFAULT [[#SDATA]] __global_pointer$
 
 # ERR: error: relocation R_RISCV_PCREL_HI20 cannot be used against symbol '__global_pointer$'; recompile with -fPIC
 
 # RUN: ld.lld -pie --no-dynamic-linker --export-dynamic %t.64.o -o %t.64e
-# RUN: llvm-readelf -s %t.64e | FileCheck %s --check-prefix=STATICPIE
+# RUN: llvm-readelf -s %t.64e | FileCheck %s --check-prefix=STATICE
 
-# STATICPIE:     '.dynsym'
-# STATICPIE-NOT: __global_pointer$
-# STATICPIE:     '.symtab'
-# STATICPIE:     __global_pointer$
+# STATICE:     '.dynsym'
+# STATICE:     __global_pointer$
+# STATICE:     '.symtab'
+# STATICE:     __global_pointer$
 
 ## -r mode does not define __global_pointer$.
 # RUN: ld.lld -r %t.64.o -o %t.64.ro
diff --git a/lld/test/ELF/weak-undef-lib.s b/lld/test/ELF/weak-undef-lib.s
index a554e1d5a2f899d..0ff1bc755f0750b 100644
--- a/lld/test/ELF/weak-undef-lib.s
+++ b/lld/test/ELF/weak-undef-lib.s
@@ -7,7 +7,7 @@
 # RUN: llvm-readobj --dyn-syms %t.so | FileCheck %s
 
 # RUN: ld.lld -pie -o %t %t1.o --start-lib %t2.o
-# RUN: llvm-readobj --dyn-syms %t | FileCheck %s
+# RUN: llvm-readelf --dyn-syms %t | FileCheck %s --check-prefix=STATICPIE
 
 # CHECK:      Name: foo
 # CHECK-NEXT: Value: 0x0
diff --git a/lld/test/ELF/weak-undef-no-dynamic-linker.s b/lld/test/ELF/weak-undef-no-dynamic-linker.s
index fa6936e1ef393fc..11abd5351af9de9 100644
--- a/lld/test/ELF/weak-undef-no-dynamic-linker.s
+++ b/lld/test/ELF/weak-undef-no-dynamic-linker.s
@@ -1,13 +1,12 @@
 # REQUIRES: x86
 # RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o
 # RUN: ld.lld -pie %t.o -o %t
-# RUN: llvm-readobj --dyn-syms %t | FileCheck %s
+# RUN: llvm-readobj --dyn-syms %t | FileCheck --check-prefix=NO %s
 # RUN: ld.lld -pie --no-dynamic-linker %t.o -o %t
 # RUN: llvm-readobj --dyn-syms %t | FileCheck --check-prefix=NO %s
 
-## With --no-dynamic-linker, don't emit undefined weak symbols to .dynsym .
-## This will suppress a relocation.
-# CHECK: Name: foo
+## With static PIE (whether or not --no-dynamic-linker is specified), don't
+## emit undefined weak symbols to .dynsym . This suppresses relocations.
 # NO-NOT: Name: foo
 
 .weak foo
diff --git a/lld/test/ELF/weak-undef-rw.s b/lld/test/ELF/weak-undef-rw.s
index ec3e4ce7348957e..c5cf1bdcaba68f4 100644
--- a/lld/test/ELF/weak-undef-rw.s
+++ b/lld/test/ELF/weak-undef-rw.s
@@ -1,23 +1,23 @@
 # REQUIRES: x86
 # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
 # RUN: ld.lld %t.o -o %t --export-dynamic
-# RUN: llvm-readelf -r --hex-dump=.data %t | FileCheck %s --check-prefix=NOPIC
+# RUN: llvm-readelf -r --hex-dump=.data %t | FileCheck %s --check-prefix=STATIC
 # RUN: ld.lld %t.o -o %t.pie -pie
-# RUN: llvm-readobj -r %t.pie | FileCheck %s --check-prefix=PIC
+# RUN: llvm-readelf -r --hex-dump=.data %t.pie | FileCheck %s --check-prefix=STATIC
 # RUN: ld.lld %t.o -o %t.so -shared
 # RUN: llvm-readobj -r %t.so | FileCheck %s --check-prefix=PIC
 
 ## gABI leaves the behavior of weak undefined references implementation defined.
-## We choose to resolve them statically for -no-pie and produce dynamic relocations
-## for -pie and -shared.
+## We choose to resolve them statically for static linking and produce dynamic relocations
+## for dynamic linking (-shared or at least one input DSO).
 ##
 ## Note: Some ports of GNU ld support -z nodynamic-undefined-weak that we don't
 ## implement.
 
-# NOPIC: no relocations
-# NOPIC: Hex dump of section '.data':
-# NOPIC-NEXT: {{.*}} 00000000 00000000 
-# NOPIC-EMPTY:
+# STATIC:      no relocations
+# STATIC:      Hex dump of section '.data':
+# STATIC-NEXT: {{.*}} 00000000 00000000 .
+# STATIC-EMPTY:
 
 # PIC:      .rela.dyn {
 # PIC-NEXT:   R_X86_64_64 foobar 0x0



More information about the llvm-branch-commits mailing list