-
Notifications
You must be signed in to change notification settings - Fork 12.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[ELF] Fix PROVIDE_HIDDEN -shared regression with bitcode file references #112386
[ELF] Fix PROVIDE_HIDDEN -shared regression with bitcode file references #112386
Conversation
Created using spr 1.3.6-beta.1
@llvm/pr-subscribers-lld-elf @llvm/pr-subscribers-lld Author: Fangrui Song (MaskRay) ChangesThe inaccurate #111945 condition fixes a PROVIDE regression (#111478) Fix this by making the condition accurate: use a map to track defined Full diff: https://github.com/llvm/llvm-project/pull/112386.diff 3 Files Affected:
diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp
index 418f689cee2167..0560065ffa4780 100644
--- a/lld/ELF/LinkerScript.cpp
+++ b/lld/ELF/LinkerScript.cpp
@@ -200,7 +200,7 @@ static bool shouldDefineSym(Ctx &ctx, SymbolAssignment *cmd) {
if (cmd->name == ".")
return false;
- return !cmd->provide || LinkerScript::shouldAddProvideSym(ctx, cmd->name);
+ return !cmd->provide || ctx.script->shouldAddProvideSym(cmd->name);
}
// Called by processSymbolAssignments() to assign definitions to
@@ -1798,7 +1798,7 @@ void LinkerScript::addScriptReferencedSymbolsToSymTable() {
DenseSet<StringRef> added;
SmallVector<const SmallVector<StringRef, 0> *, 0> symRefsVec;
for (const auto &[name, symRefs] : provideMap)
- if (shouldAddProvideSym(ctx, name) && added.insert(name).second)
+ if (shouldAddProvideSym(name) && added.insert(name).second)
symRefsVec.push_back(&symRefs);
while (symRefsVec.size()) {
for (StringRef name : *symRefsVec.pop_back_val()) {
@@ -1806,7 +1806,7 @@ void LinkerScript::addScriptReferencedSymbolsToSymTable() {
// Prevent the symbol from being discarded by --gc-sections.
referencedSymbols.push_back(name);
auto it = provideMap.find(name);
- if (it != provideMap.end() && shouldAddProvideSym(ctx, name) &&
+ if (it != provideMap.end() && shouldAddProvideSym(name) &&
added.insert(name).second) {
symRefsVec.push_back(&it->second);
}
@@ -1814,14 +1814,17 @@ void LinkerScript::addScriptReferencedSymbolsToSymTable() {
}
}
-bool LinkerScript::shouldAddProvideSym(Ctx &ctx, StringRef symName) {
+bool LinkerScript::shouldAddProvideSym(StringRef symName) {
// This function is called before and after garbage collection. To prevent
// undefined references from the RHS, the result of this function for a
- // symbol must be the same for each call. We use isUsedInRegularObj to not
- // change the return value of a demoted symbol. The exportDynamic condition,
- // while not so accurate, allows PROVIDE to define a symbol referenced by a
- // DSO.
+ // symbol must be the same for each call. We use unusedProvideSyms to not
+ // change the return value of a demoted symbol.
Symbol *sym = ctx.symtab->find(symName);
- return sym && !sym->isDefined() && !sym->isCommon() &&
- (sym->isUsedInRegularObj || sym->exportDynamic);
+ if (!sym)
+ return false;
+ if (sym->isDefined() || sym->isCommon()) {
+ unusedProvideSyms.insert(sym);
+ return false;
+ }
+ return !unusedProvideSyms.count(sym);
}
diff --git a/lld/ELF/LinkerScript.h b/lld/ELF/LinkerScript.h
index eda152dd3582ab..f5c418d1f6af52 100644
--- a/lld/ELF/LinkerScript.h
+++ b/lld/ELF/LinkerScript.h
@@ -389,7 +389,7 @@ class LinkerScript final {
// Returns true if the PROVIDE symbol should be added to the link.
// A PROVIDE symbol is added to the link only if it satisfies an
// undefined reference.
- static bool shouldAddProvideSym(Ctx &, StringRef symName);
+ bool shouldAddProvideSym(StringRef symName);
// SECTIONS command list.
SmallVector<SectionCommand *, 0> sectionCommands;
@@ -433,6 +433,7 @@ class LinkerScript final {
//
// then provideMap should contain the mapping: 'v' -> ['a', 'b', 'c']
llvm::MapVector<StringRef, SmallVector<StringRef, 0>> provideMap;
+ llvm::DenseSet<Symbol *> unusedProvideSyms;
// List of potential spill locations (PotentialSpillSection) for an input
// section.
diff --git a/lld/test/ELF/linkerscript/provide-defined.s b/lld/test/ELF/linkerscript/provide-defined.s
index 1d44bef3d4068d..650925cac4051f 100644
--- a/lld/test/ELF/linkerscript/provide-defined.s
+++ b/lld/test/ELF/linkerscript/provide-defined.s
@@ -4,15 +4,27 @@
# RUN: rm -rf %t && split-file %s %t && cd %t
# RUN: llvm-mc -filetype=obj -triple=x86_64 a.s -o a.o
# RUN: llvm-mc -filetype=obj -triple=x86_64 b.s -o b.o
+# RUN: llvm-as c.ll -o c.bc
# RUN: ld.lld -T a.t --gc-sections a.o b.o -o a
# RUN: llvm-readelf -s a | FileCheck %s
+# RUN: ld.lld -T a.t -shared a.o b.o c.bc -o a.so
+# RUN: llvm-readelf -s -r a.so | FileCheck %s --check-prefix=DSO
+
# CHECK: 1: {{.*}} 0 NOTYPE GLOBAL DEFAULT 1 _start
-# CHECK-NEXT:2: {{.*}} 0 NOTYPE GLOBAL DEFAULT 2 f3
+# CHECK-NEXT:2: {{.*}} 0 NOTYPE WEAK DEFAULT 2 f3
# CHECK-NOT: {{.}}
+# DSO: .rela.plt
+# DSO-NOT: f5
+# DSO: Symbol table '.dynsym'
+# DSO-NOT: f5
+# DSO: Symbol table '.symtab'
+# DSO: {{.*}} 0 NOTYPE LOCAL HIDDEN [[#]] f5
+
#--- a.s
-.global _start, f1, f2, f3, bar
+.global _start, f1, f2, bar
+.weak f3
_start:
call f3
@@ -26,6 +38,17 @@ _start:
#--- b.s
call f2
+#--- c.ll
+target triple = "x86_64-unknown-linux-gnu"
+target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+
+declare void @f5()
+
+define void @f3() {
+ call void @f5()
+ ret void
+}
+
#--- a.t
SECTIONS {
. = . + SIZEOF_HEADERS;
@@ -33,4 +56,5 @@ SECTIONS {
PROVIDE(f2 = bar+2);
PROVIDE(f3 = bar+3);
PROVIDE(f4 = comm+4);
+ PROVIDE_HIDDEN(f5 = bar+5);
}
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. A map will definitely keep the return values in sync. Apologies for missing the corner case in first review.
Created using spr 1.3.6-beta.1
The inaccurate llvm#111945 condition fixes a PROVIDE regression (llvm#111478) but introduces another regression: in a DSO link, if a symbol referenced only by bitcode files is defined as PROVIDE_HIDDEN, lld would not set the visibility correctly, leading to an assertion failure in DynamicReloc::getSymIndex (https://reviews.llvm.org/D123985). This is because `(sym->isUsedInRegularObj || sym->exportDynamic)` is initially false (bitcode undef does not set `isUsedInRegularObj`) then true (in `addSymbol`, after LTO compilation). Fix this by making the condition accurate: use a map to track defined symbols. Reviewers: smithp35 Reviewed By: smithp35 Pull Request: llvm#112386
The inaccurate #111945 condition fixes a PROVIDE regression (#111478)
but introduces another regression: in a DSO link, if a symbol referenced
only by bitcode files is defined as PROVIDE_HIDDEN, lld would not set
the visibility correctly, leading to an assertion failure in
DynamicReloc::getSymIndex (https://reviews.llvm.org/D123985).
This is because
(sym->isUsedInRegularObj || sym->exportDynamic)
isinitially false (bitcode undef does not set
isUsedInRegularObj
) thentrue (in
addSymbol
, after LTO compilation).Fix this by making the condition accurate: use a map to track defined
symbols.