Skip to content

Commit

Permalink
[ELF] Make shouldAddProvideSym return values consistent when demoted …
Browse files Browse the repository at this point in the history
…to Undefined

Case: `PROVIDE(f1 = bar);` when both `f1` and `bar` are in separate
sections that would be discarded by GC.

Due to `demoteDefined`, `shouldAddProvideSym(f1)` may initially return
false (when Defined) and then return true (been demoted to Undefined).

```
addScriptReferencedSymbolsToSymTable
  shouldAddProvideSym(f1): false
  // the RHS (bar) is not added to `referencedSymbols` and may be GCed
declareSymbols
  shouldAddProvideSym(f1): false
markLive
demoteSymbolsAndComputeIsPreemptible
  // demoted f1 to Undefined
processSymbolAssignments
  addSymbol
    shouldAddProvideSym(f1): true
```

The inconsistency can cause `cmd->expression()` in `addSymbol` to be
evaluated, leading to `symbol not found: bar` errors (since `bar` in the
RHS is not in `referencedSymbols` and is GCed) (llvm#111478).

Fix this by adding a `sym->isUsedInRegularObj` condition, making
`shouldAddProvideSym(f1)` values consistent. In addition, we need a
`sym->exportDynamic` condition to keep provide-shared.s working.

Fixes: ebb326a

Pull Request: llvm#111945
  • Loading branch information
MaskRay authored Oct 11, 2024
1 parent 2d5f3b0 commit 1c6688a
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 1 deletion.
9 changes: 8 additions & 1 deletion lld/ELF/LinkerScript.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1814,6 +1814,13 @@ void LinkerScript::addScriptReferencedSymbolsToSymTable() {
}

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 *sym = elf::ctx.symtab->find(symName);
return sym && !sym->isDefined() && !sym->isCommon();
return sym && !sym->isDefined() && !sym->isCommon() &&
(sym->isUsedInRegularObj || sym->exportDynamic);
}
36 changes: 36 additions & 0 deletions lld/test/ELF/linkerscript/provide-defined.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# REQUIRES: x86
## Test the GC behavior when the PROVIDE symbol is defined by a relocatable file.

# 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: ld.lld -T a.t --gc-sections a.o b.o -o a
# RUN: llvm-readelf -s a | FileCheck %s

# CHECK: 1: {{.*}} 0 NOTYPE GLOBAL DEFAULT 1 _start
# CHECK-NEXT:2: {{.*}} 0 NOTYPE GLOBAL DEFAULT 2 f3
# CHECK-NOT: {{.}}

#--- a.s
.global _start, f1, f2, f3, bar
_start:
call f3

.section .text.f1,"ax"; f1:
.section .text.f2,"ax"; f2: # referenced by another relocatable file
.section .text.f3,"ax"; f3: # live
.section .text.bar,"ax"; bar:

.comm comm,4,4

#--- b.s
call f2

#--- a.t
SECTIONS {
. = . + SIZEOF_HEADERS;
PROVIDE(f1 = bar+1);
PROVIDE(f2 = bar+2);
PROVIDE(f3 = bar+3);
PROVIDE(f4 = comm+4);
}

0 comments on commit 1c6688a

Please sign in to comment.