Skip to content

Commit 6b435f9

Browse files
committed
[lld][ELF] Prevent merging two sections when they point to non-globals
1 parent adef51a commit 6b435f9

File tree

2 files changed

+43
-13
lines changed

2 files changed

+43
-13
lines changed

lld/ELF/ICF.cpp

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -111,11 +111,11 @@ template <class ELFT> class ICF {
111111
Relocs<RelTy> relsB);
112112

113113
template <class RelTy>
114-
bool variableEq(const InputSection *a, Relocs<RelTy> relsA,
115-
const InputSection *b, Relocs<RelTy> relsB);
114+
bool variableEq(InputSection *a, Relocs<RelTy> relsA, InputSection *b,
115+
Relocs<RelTy> relsB);
116116

117117
bool equalsConstant(InputSection *a, InputSection *b);
118-
bool equalsVariable(const InputSection *a, const InputSection *b);
118+
bool equalsVariable(InputSection *a, InputSection *b);
119119

120120
size_t findBoundary(size_t begin, size_t end);
121121

@@ -315,7 +315,7 @@ bool ICF<ELFT>::constantEq(InputSection *secA, Relocs<RelTy> ra,
315315
if (isa<InputSection>(da->section)) {
316316
if (da->value + addA == db->value + addB) {
317317
// For non-trivial relocations, if we cannot merge symbols together,
318-
// we must not merge them.
318+
// we must not merge sections either.
319319
if (!isTrivialRelocation(secA, sa, *rai) &&
320320
!canMergeSymbols(addA, addB))
321321
return false;
@@ -392,8 +392,8 @@ getRelocTargetSyms(const InputSection *sec) {
392392
// relocations point to the same section in terms of ICF.
393393
template <class ELFT>
394394
template <class RelTy>
395-
bool ICF<ELFT>::variableEq(const InputSection *secA, Relocs<RelTy> ra,
396-
const InputSection *secB, Relocs<RelTy> rb) {
395+
bool ICF<ELFT>::variableEq(InputSection *secA, Relocs<RelTy> ra,
396+
InputSection *secB, Relocs<RelTy> rb) {
397397
assert(ra.size() == rb.size());
398398

399399
auto rai = ra.begin(), rae = ra.end(), rbi = rb.begin();
@@ -407,6 +407,15 @@ bool ICF<ELFT>::variableEq(const InputSection *secA, Relocs<RelTy> ra,
407407
auto *da = cast<Defined>(&sa);
408408
auto *db = cast<Defined>(&sb);
409409

410+
// Prevent sections containing local symbols from merging into sections with
411+
// global symbols, or vice-versa. This is to prevent local-global symbols
412+
// getting merged into each other (done later in ICF). We do this as
413+
// post-ICF passes cannot handle duplicates when iterating over local
414+
// symbols. There are also assertions that prevent this.
415+
if ((!da->isGlobal() || !db->isGlobal()) &&
416+
!isTrivialRelocation(secA, sa, *rai))
417+
return false;
418+
410419
// We already dealt with absolute and non-InputSection symbols in
411420
// constantEq, and for InputSections we have already checked everything
412421
// except the equivalence class.
@@ -430,7 +439,7 @@ bool ICF<ELFT>::variableEq(const InputSection *secA, Relocs<RelTy> ra,
430439

431440
// Compare "moving" part of two InputSections, namely relocation targets.
432441
template <class ELFT>
433-
bool ICF<ELFT>::equalsVariable(const InputSection *a, const InputSection *b) {
442+
bool ICF<ELFT>::equalsVariable(InputSection *a, InputSection *b) {
434443
const RelsOrRelas<ELFT> ra = a->template relsOrRelas<ELFT>();
435444
const RelsOrRelas<ELFT> rb = b->template relsOrRelas<ELFT>();
436445
if (ra.areRelocsCrel() || rb.areRelocsCrel())
@@ -610,9 +619,7 @@ template <class ELFT> void ICF<ELFT>::run() {
610619
assert(syms.size() == replacedSyms.size() &&
611620
"Should have same number of syms!");
612621
for (size_t i = 0; i < syms.size(); i++) {
613-
if (syms[i].first == replacedSyms[i].first ||
614-
!syms[i].first->isGlobal() || !replacedSyms[i].first->isGlobal() ||
615-
!canMergeSymbols(syms[i].second, replacedSyms[i].second))
622+
if (!canMergeSymbols(syms[i].second, replacedSyms[i].second))
616623
continue;
617624
symbolEquivalence.unionSets(syms[i].first, replacedSyms[i].first);
618625
}

lld/test/ELF/aarch64-got-merging-icf.s

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
# RUN: llvm-mc -filetype=obj -triple=aarch64 %s -o %t
55
# RUN: llvm-mc -filetype=obj -crel -triple=aarch64 %s -o %tcrel
6-
# RUN: ld.lld %t -o %t2 --icf=all
6+
# RUN: ld.lld %t -o %t2 --icf=all --print-icf-sections
77
# RUN: ld.lld %tcrel -o %tcrel2 --icf=all
88

99
# RUN: llvm-objdump --section-headers %t2 | FileCheck %s --check-prefix=EXE
@@ -17,10 +17,32 @@
1717

1818
## All global g* symbols should merge into a single GOT entry while non-global
1919
## gets its own GOT entry.
20-
# EXE: {{.*}}.got 00000010{{.*}}
20+
# EXE: {{.*}}.got 00000018{{.*}}
2121

2222
## When symbols are preemptible in DSO mode, GOT entries wouldn't be merged
23-
# DSO: {{.*}}.got 00000028{{.*}}
23+
# DSO: {{.*}}.got 00000030{{.*}}
24+
25+
# 1. Sections containing local symbols (f4, f5) are not merged together.
26+
# 2. Sections containing global symbols are merged together.
27+
28+
# CHECK: selected section {{.*}}:(.rodata.g0)
29+
# CHECK-NEXT: removing identical section {{.*}}:(.rodata.g1)
30+
# CHECK-NEXT: removing identical section {{.*}}:(.rodata.g2)
31+
# CHECK-NEXT: removing identical section {{.*}}:(.rodata.g3)
32+
# CHECK-NEXT: removing identical section {{.*}}:(.rodata.g4)
33+
# CHECK-NEXT: removing identical section {{.*}}:(.rodata.g5)
34+
# CHECK-NEXT: selected section {{.*}}:(.text.t2_0)
35+
# CHECK-NEXT: removing identical section {{.*}}:(.text.t2_1)
36+
# CHECK-NEXT: selected section {{.*}}:(.text.f2_0)
37+
# CHECK-NEXT: removing identical section {{.*}}:(.text.f2_1)
38+
# CHECK-NEXT: removing identical section {{.*}}:(.text.f2_2)
39+
# CHECK-NEXT: removing identical section {{.*}}:(.text.f2_3)
40+
# CHECK-NEXT: redirecting 'g1' in symtab to 'g0'
41+
# CHECK-NEXT: redirecting 'g2' in symtab to 'g0'
42+
# CHECK-NEXT: redirecting 'g3' in symtab to 'g0'
43+
# CHECK-NEXT: redirecting 'g1' to 'g0'
44+
# CHECK-NEXT: redirecting 'g2' to 'g0'
45+
# CHECK-NEXT: redirecting 'g3' to 'g0'
2446

2547
.addrsig
2648

@@ -93,3 +115,4 @@ f 1 1
93115
f 2 1
94116
f 3 1
95117
f 4
118+
f 5

0 commit comments

Comments
 (0)