[ELF] Refine ctx.arg.exportDynamic condition

--export-dynamic should be a no-op when ctx.hasDynsym is false.

* Drop unneeded ctx.hasDynsym checks.
* Static linking with --export-dynamic does not prevent devirtualization.
This commit is contained in:
Fangrui Song
2025-02-16 12:12:00 -08:00
parent f5d63ccb22
commit c22d84f7bb
4 changed files with 14 additions and 14 deletions

View File

@@ -2617,8 +2617,7 @@ void LinkerDriver::compileBitcodeFiles(bool skipLinkedOutput) {
for (Symbol *sym : obj->getGlobalSymbols()) {
if (!sym->isDefined())
continue;
if (ctx.hasDynsym && ctx.arg.exportDynamic &&
sym->computeBinding(ctx) != STB_LOCAL)
if (ctx.arg.exportDynamic && sym->computeBinding(ctx) != STB_LOCAL)
sym->isExported = true;
if (sym->hasVersionSuffix)
sym->parseSymbolVersion(ctx);
@@ -2965,6 +2964,7 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &args) {
// Create dynamic sections for dynamic linking and static PIE.
ctx.hasDynsym = !ctx.sharedFiles.empty() || ctx.arg.isPic;
ctx.arg.exportDynamic &= ctx.hasDynsym;
// If an entry symbol is in a static archive, pull out that file now.
if (Symbol *sym = ctx.symtab->find(ctx.arg.entry))

View File

@@ -361,13 +361,10 @@ void elf::parseVersionAndComputeIsPreemptible(Ctx &ctx) {
// 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);
if (!hasDynsym)
continue;
if (sym->computeBinding(ctx) == STB_LOCAL) {
sym->isExported = false;
continue;
@@ -377,7 +374,7 @@ void elf::parseVersionAndComputeIsPreemptible(Ctx &ctx) {
} else if (ctx.arg.exportDynamic &&
(sym->isUsedInRegularObj || !sym->ltoCanOmit)) {
sym->isExported = true;
sym->isPreemptible = computeIsPreemptible(ctx, *sym);
sym->isPreemptible = maybePreemptible && computeIsPreemptible(ctx, *sym);
}
}
}

View File

@@ -284,7 +284,6 @@ static void demoteDefined(Defined &sym, DenseMap<SectionBase *, size_t> &map) {
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)) {
@@ -301,9 +300,8 @@ static void demoteSymbolsAndComputeIsPreemptible(Ctx &ctx) {
}
}
if (hasDynsym)
sym->isPreemptible = maybePreemptible &&
(sym->isUndefined() || sym->isExported) &&
if (maybePreemptible)
sym->isPreemptible = (sym->isUndefined() || sym->isExported) &&
computeIsPreemptible(ctx, *sym);
}
}
@@ -1853,7 +1851,7 @@ 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 && ctx.arg.exportDynamic)
if (ctx.arg.exportDynamic)
for (Symbol *sym : ctx.synthesizedSymbols)
if (sym->computeBinding(ctx) != STB_LOCAL)
sym->isExported = true;

View File

@@ -9,6 +9,10 @@
; RUN: ld.lld %t2.o -o %t3 -save-temps --lto-whole-program-visibility \
; RUN: -mllvm -pass-remarks=. 2>&1 | FileCheck %s --check-prefix=REMARK
; RUN: llvm-dis %t2.o.4.opt.bc -o - | FileCheck %s --check-prefix=CHECK-IR
;; --export-dynamic without .dynsym does not prevent devirtualization.
; RUN: ld.lld %t2.o -o %t3 -save-temps --lto-whole-program-visibility \
; RUN: -mllvm -pass-remarks=. \
; RUN: --export-dynamic 2>&1 | FileCheck %s --check-prefix=REMARK
;; Hybrid WPD
;; Generate split module with summary for hybrid Thin/Regular LTO WPD.
@@ -33,19 +37,20 @@
; RUN: ld.lld -shared -soname=ta %ta.o -o %ta.so
;; Index based WPD
; RUN: ld.lld %t2.o -o %t3 -save-temps --lto-whole-program-visibility \
; RUN: ld.lld %t2.o %ta.so -o %t3 -save-temps --lto-whole-program-visibility \
; RUN: -mllvm -pass-remarks=. \
; RUN: --export-dynamic 2>&1 | FileCheck /dev/null --implicit-check-not single-impl --allow-empty
; RUN: llvm-dis %t2.o.4.opt.bc -o - | FileCheck %s --check-prefix=CHECK-NODEVIRT-IR
;; Hybrid WPD
; RUN: ld.lld %t.o -o %t3 -save-temps --lto-whole-program-visibility \
; RUN: ld.lld %t.o %ta.so -o %t3 -save-temps --lto-whole-program-visibility \
; RUN: -mllvm -pass-remarks=. \
; RUN: --export-dynamic 2>&1 | FileCheck /dev/null --implicit-check-not single-impl --allow-empty
; RUN: llvm-dis %t.o.4.opt.bc -o - | FileCheck %s --check-prefix=CHECK-NODEVIRT-IR
;; Regular LTO WPD
; RUN: ld.lld %t4.o -o %t3 -save-temps --lto-whole-program-visibility \
; RUN: ld.lld %t4.o %ta.so -o %t3 -save-temps --lto-whole-program-visibility \
; RUN: -mllvm -pass-remarks=. \
; RUN: --export-dynamic 2>&1 | FileCheck /dev/null --implicit-check-not single-impl --allow-empty
; RUN: llvm-dis %t3.0.4.opt.bc -o - | FileCheck %s --check-prefix=CHECK-NODEVIRT-IR