Skip to content

Commit 744e589

Browse files
committed
[llvm-objcopy][ELF] Preserve sh_link to .symtab when applicable
This change to llvm-objcopy preserves the ELF section sh_link to .symtab so long as none of the symbol table indices have been changed. Previously, any invocation of llvm-objcopy including a "no-op" would clear any section sh_link to .symtab. Differential Revision: https://reviews.llvm.org/D150859
1 parent e4a589b commit 744e589

File tree

4 files changed

+90
-6
lines changed

4 files changed

+90
-6
lines changed

lld/test/ELF/icf-safe.s

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,17 @@
22

33
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o
44
# RUN: llvm-objcopy %t1.o %t1copy.o
5+
# RUN: llvm-objcopy --localize-symbol=h1 %t1.o %t1changed.o
6+
# RUN: ld.lld -r %t1.o -o %t1reloc.o
57
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %S/Inputs/icf-safe.s -o %t2.o
68
# RUN: ld.lld %t1.o %t2.o -o %t2 --icf=safe --print-icf-sections | FileCheck %s
9+
# RUN: ld.lld %t1copy.o %t2.o -o %t2 --icf=safe --print-icf-sections | FileCheck %s
710
# RUN: ld.lld %t1.o %t2.o -o %t3 --icf=safe --print-icf-sections -shared | FileCheck --check-prefix=EXPORT %s
811
# RUN: ld.lld %t1.o %t2.o -o %t3 --icf=safe --print-icf-sections --export-dynamic | FileCheck --check-prefix=EXPORT %s
912
# RUN: ld.lld %t1.o %t2.o -o %t2 --icf=all --print-icf-sections | FileCheck --check-prefix=ALL %s
1013
# RUN: ld.lld %t1.o %t2.o -o %t2 --icf=all --print-icf-sections --export-dynamic | FileCheck --check-prefix=ALL-EXPORT %s
11-
# RUN: ld.lld %t1copy.o -o %t4 --icf=safe 2>&1 | FileCheck --check-prefix=OBJCOPY %s
14+
# RUN: ld.lld %t1changed.o -o %t4 --icf=safe 2>&1 | FileCheck --check-prefix=SH_LINK_0 %s
15+
# RUN: ld.lld %t1reloc.o -o %t4 --icf=safe 2>&1 | FileCheck --check-prefix=SH_LINK_0 %s
1216

1317
# CHECK-NOT: selected section {{.*}}:(.text.f1)
1418
# CHECK: selected section {{.*}}:(.text.f3)
@@ -89,7 +93,7 @@
8993
# ALL-EXPORT: removing identical section {{.*}}:(.text.non_addrsig2)
9094
# ALL-EXPORT-NOT: selected section
9195

92-
# OBJCOPY: --icf=safe conservatively ignores SHT_LLVM_ADDRSIG [index [[#]]] with sh_link=0 (likely created using objcopy or ld -r)
96+
# SH_LINK_0: --icf=safe conservatively ignores SHT_LLVM_ADDRSIG [index [[#]]] with sh_link=0 (likely created using objcopy or ld -r)
9397

9498
.section .text.f1,"ax",@progbits
9599
.globl f1

llvm/lib/ObjCopy/ELF/ELFObject.cpp

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,13 @@ Error Section::accept(MutableSectionVisitor &Visitor) {
429429
return Visitor.visit(*this);
430430
}
431431

432+
void Section::restoreSymTabLink(SymbolTableSection &SymTab) {
433+
if (HasSymTabLink) {
434+
assert(LinkSection == nullptr);
435+
LinkSection = &SymTab;
436+
}
437+
}
438+
432439
Error SectionWriter::visit(const OwnedDataSection &Sec) {
433440
llvm::copy(Sec.Data, Out.getBufferStart() + Sec.Offset);
434441
return Error::success();
@@ -680,8 +687,11 @@ bool Symbol::isCommon() const { return getShndx() == SHN_COMMON; }
680687

681688
void SymbolTableSection::assignIndices() {
682689
uint32_t Index = 0;
683-
for (auto &Sym : Symbols)
690+
for (auto &Sym : Symbols) {
691+
if (Sym->Index != Index)
692+
IndicesChanged = true;
684693
Sym->Index = Index++;
694+
}
685695
}
686696

687697
void SymbolTableSection::addSymbol(Twine Name, uint8_t Bind, uint8_t Type,
@@ -741,7 +751,10 @@ Error SymbolTableSection::removeSymbols(
741751
std::remove_if(std::begin(Symbols) + 1, std::end(Symbols),
742752
[ToRemove](const SymPtr &Sym) { return ToRemove(*Sym); }),
743753
std::end(Symbols));
754+
auto PrevSize = Size;
744755
Size = Symbols.size() * EntrySize;
756+
if (Size < PrevSize)
757+
IndicesChanged = true;
745758
assignIndices();
746759
return Error::success();
747760
}
@@ -1106,8 +1119,10 @@ Error Section::initialize(SectionTableRef SecTable) {
11061119

11071120
LinkSection = *Sec;
11081121

1109-
if (LinkSection->Type == ELF::SHT_SYMTAB)
1122+
if (LinkSection->Type == ELF::SHT_SYMTAB) {
1123+
HasSymTabLink = true;
11101124
LinkSection = nullptr;
1125+
}
11111126

11121127
return Error::success();
11131128
}
@@ -2515,6 +2530,12 @@ template <class ELFT> Error ELFWriter<ELFT>::finalize() {
25152530
if (Error E = removeUnneededSections(Obj))
25162531
return E;
25172532

2533+
// If the .symtab indices have not been changed, restore the sh_link to
2534+
// .symtab for sections that were linked to .symtab.
2535+
if (Obj.SymbolTable && !Obj.SymbolTable->indicesChanged())
2536+
for (SectionBase &Sec : Obj.sections())
2537+
Sec.restoreSymTabLink(*Obj.SymbolTable);
2538+
25182539
// We need to assign indexes before we perform layout because we need to know
25192540
// if we need large indexes or not. We can assign indexes first and check as
25202541
// we go to see if we will actully need large indexes.

llvm/lib/ObjCopy/ELF/ELFObject.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -432,6 +432,8 @@ class SectionBase {
432432
virtual bool hasContents() const { return false; }
433433
// Notify the section that it is subject to removal.
434434
virtual void onRemove();
435+
436+
virtual void restoreSymTabLink(SymbolTableSection &) {}
435437
};
436438

437439
class Segment {
@@ -483,6 +485,7 @@ class Section : public SectionBase {
483485

484486
ArrayRef<uint8_t> Contents;
485487
SectionBase *LinkSection = nullptr;
488+
bool HasSymTabLink = false;
486489

487490
public:
488491
explicit Section(ArrayRef<uint8_t> Data) : Contents(Data) {}
@@ -497,6 +500,7 @@ class Section : public SectionBase {
497500
bool hasContents() const override {
498501
return Type != ELF::SHT_NOBITS && Type != ELF::SHT_NULL;
499502
}
503+
void restoreSymTabLink(SymbolTableSection &SymTab) override;
500504
};
501505

502506
class OwnedDataSection : public SectionBase {
@@ -691,6 +695,7 @@ class SymbolTableSection : public SectionBase {
691695
std::vector<std::unique_ptr<Symbol>> Symbols;
692696
StringTableSection *SymbolNames = nullptr;
693697
SectionIndexSection *SectionIndexTable = nullptr;
698+
bool IndicesChanged = false;
694699

695700
using SymPtr = std::unique_ptr<Symbol>;
696701

@@ -703,6 +708,7 @@ class SymbolTableSection : public SectionBase {
703708
void prepareForLayout();
704709
// An 'empty' symbol table still contains a null symbol.
705710
bool empty() const { return Symbols.size() == 1; }
711+
bool indicesChanged() const { return IndicesChanged; }
706712
void setShndxTable(SectionIndexSection *ShndxTable) {
707713
SectionIndexTable = ShndxTable;
708714
}
Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,31 @@
11
# RUN: yaml2obj %s -o %t
2+
## No-op copy.
23
# RUN: llvm-objcopy %t %t2
34
# RUN: llvm-readobj --sections %t2 | FileCheck %s
5+
## No-op strip.
46
# RUN: cp %t %t3
57
# RUN: llvm-strip --no-strip-all %t3
68
# RUN: llvm-readobj --sections %t3 | FileCheck %s
9+
## Add symbol.
10+
# RUN: llvm-objcopy --add-symbol=another=.text:0,function %t %t4
11+
# RUN: llvm-readobj --sections %t4 | FileCheck %s
12+
13+
## A section with sh_link referencing SHT_SYMTAB indicates that its content may
14+
## use the old symbol indices. If the symbol indices change, reset sh_link to 0
15+
## to inform tools like linkers that the sh_link has been invalidated.
16+
17+
## Strip first symbol.
18+
# RUN: llvm-objcopy --strip-symbol bar %t %t5
19+
# RUN: llvm-readobj --sections %t5 | FileCheck %s --check-prefix=LINK-0
20+
## Strip last symbol.
21+
# RUN: llvm-objcopy --strip-symbol baz %t %t6
22+
# RUN: llvm-readobj --sections %t6 | FileCheck %s --check-prefix=LINK-0
23+
## Re-order symbols.
24+
# RUN: llvm-objcopy --localize-symbol baz %t %t7
25+
# RUN: llvm-readobj --sections %t7 | FileCheck %s --check-prefix=LINK-0
26+
## Remove .text section.
27+
# RUN: llvm-objcopy --remove-section=.text %t %t8
28+
# RUN: llvm-readobj --sections %t8 | FileCheck %s --check-prefix=LINK-0
729

830
!ELF
931
FileHeader:
@@ -12,11 +34,29 @@ FileHeader:
1234
Type: ET_REL
1335
Machine: EM_X86_64
1436
Sections:
37+
- Name: .text
38+
Type: SHT_PROGBITS
39+
Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
40+
Address: 0x1000
41+
AddressAlign: 0x0000000000000010
42+
Size: 32
1543
- Name: .foo
1644
Link: .symtab
1745
Type: SHT_PROGBITS
1846
Flags: [ ]
19-
Symbols: []
47+
Symbols:
48+
- Name: bar
49+
Type: STT_FUNC
50+
Size: 8
51+
Section: .text
52+
Value: 0x1000
53+
Binding: STB_GLOBAL
54+
- Name: baz
55+
Type: STT_FUNC
56+
Size: 8
57+
Section: .text
58+
Value: 0x1010
59+
Binding: STB_GLOBAL
2060

2161
# CHECK: Name: .foo
2262
# CHECK-NEXT: Type:
@@ -25,4 +65,17 @@ Symbols: []
2565
# CHECK-NEXT: Address:
2666
# CHECK-NEXT: Offset:
2767
# CHECK-NEXT: Size:
28-
# CHECK-NEXT: Link: 0
68+
# CHECK-NEXT: Link: [[#SYMTABIDX:]]
69+
70+
# CHECK: Index: [[#SYMTABIDX]]
71+
# CHECK-NEXT: Name: .symtab
72+
# CHECK-NEXT: Type: SHT_SYMTAB
73+
74+
# LINK-0: Name: .foo
75+
# LINK-0-NEXT: Type:
76+
# LINK-0-NEXT: Flags [ (0x0)
77+
# LINK-0-NEXT: ]
78+
# LINK-0-NEXT: Address:
79+
# LINK-0-NEXT: Offset:
80+
# LINK-0-NEXT: Size:
81+
# LINK-0-NEXT: Link: 0

0 commit comments

Comments
 (0)