[ELF][ARM] Garbage collection support for .ARM.exidx sections

.ARM.exidx sections have a reverse dependency on the section they have
a SHF_LINK_ORDER dependency on. In other words a .ARM.exidx section is
live only if the executable section it describes is live. We implement
this with a reverse dependency field in InputSection.

Adding the dependency to InputSection is the simplest implementation
but it could be moved out to a separate map if it were found to decrease
performance for non ARM targets.

Differential revision: https://reviews.llvm.org/D25234

llvm-svn: 283734
This commit is contained in:
Peter Smith 2016-10-10 10:10:27 +00:00
parent 50188b2771
commit 0760605ac5
5 changed files with 149 additions and 0 deletions

View File

@ -145,6 +145,8 @@ void elf::ObjectFile<ELFT>::parse(DenseSet<StringRef> &ComdatGroups) {
// Read section and symbol tables.
initializeSections(ComdatGroups);
initializeSymbols();
if (Config->GcSections && Config->EMachine == EM_ARM )
initializeReverseDependencies();
}
// Sections with SHT_GROUP and comdat bits define comdat section groups.
@ -270,6 +272,24 @@ void elf::ObjectFile<ELFT>::initializeSections(
}
}
// .ARM.exidx sections have a reverse dependency on the InputSection they
// have a SHF_LINK_ORDER dependency, this is identified by the sh_link.
template <class ELFT>
void elf::ObjectFile<ELFT>::initializeReverseDependencies() {
unsigned I = -1;
for (const Elf_Shdr &Sec : this->ELFObj.sections()) {
++I;
if ((Sections[I] == &InputSection<ELFT>::Discarded) ||
!(Sec.sh_flags & SHF_LINK_ORDER))
continue;
if (Sec.sh_link >= Sections.size())
fatal(getFilename(this) + ": invalid sh_link index: " +
Twine(Sec.sh_link));
auto *IS = cast<InputSection<ELFT>>(Sections[Sec.sh_link]);
IS->DependentSection = Sections[I];
}
}
template <class ELFT>
InputSectionBase<ELFT> *
elf::ObjectFile<ELFT>::getRelocTarget(const Elf_Shdr &Sec) {

View File

@ -179,6 +179,7 @@ public:
private:
void initializeSections(llvm::DenseSet<StringRef> &ComdatGroups);
void initializeSymbols();
void initializeReverseDependencies();
InputSectionBase<ELFT> *getRelocTarget(const Elf_Shdr &Sec);
InputSectionBase<ELFT> *createInputSection(const Elf_Shdr &Sec);

View File

@ -235,6 +235,9 @@ public:
// to. The writer sets a value.
uint64_t OutSecOff = 0;
// InputSection that is dependent on us (reverse dependency for GC)
InputSectionBase<ELFT> *DependentSection = nullptr;
static bool classof(const InputSectionBase<ELFT> *S);
InputSectionBase<ELFT> *getRelocatedSection();

View File

@ -91,6 +91,8 @@ static void forEachSuccessor(InputSection<ELFT> &Sec,
Fn(resolveReloc(Sec, Rel));
}
}
if (Sec.DependentSection)
Fn({Sec.DependentSection, 0});
}
// The .eh_frame section is an unfortunate special case.

123
lld/test/ELF/arm-exidx-gc.s Normal file
View File

@ -0,0 +1,123 @@
// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t
// RUN: ld.lld %t -o %t2 --gc-sections 2>&1
// RUN: llvm-objdump -d -triple=armv7a-none-linux-gnueabi %t2 | FileCheck %s
// RUN: llvm-objdump -s -triple=armv7a-none-linux-gnueabi %t2 | FileCheck -check-prefix=CHECK-EXIDX %s
// REQUIRES: arm
// Test the behavior of .ARM.exidx sections under garbage collection
// A .ARM.exidx section is live if it has a relocation to a live executable
// section.
// A .ARM.exidx section may have a relocation to a .ARM.extab section, if the
// .ARM.exidx is live then the .ARM.extab section is live
.syntax unified
.section .text.func1, "ax",%progbits
.global func1
func1:
.fnstart
bx lr
.save {r7, lr}
.setfp r7, sp, #0
.fnend
.section .text.unusedfunc1, "ax",%progbits
.global unusedfunc1
unusedfunc1:
.fnstart
bx lr
.cantunwind
.fnend
// Unwinding instructions for .text2 too large for an inline entry ARM.exidx
// entry. A separate .ARM.extab section is created to hold the unwind entries
// The .ARM.exidx table entry has a reference to the .ARM.extab section.
.section .text.func2, "ax",%progbits
.global func2
func2:
.fnstart
bx lr
.personality __gxx_personality_v0
.handlerdata
.section .text.func2
.fnend
// An unused function with a reference to a .ARM.extab section. Both should
// be removed by gc.
.section .text.unusedfunc2, "ax",%progbits
.global unusedfunc2
unusedfunc2:
.fnstart
bx lr
.personality __gxx_personality_v1
.handlerdata
.section .text.unusedfunc2
.fnend
// Dummy implementation of personality routines to satisfy reference from
// exception tables
.section .text.__gcc_personality_v0, "ax", %progbits
.global __gxx_personality_v0
__gxx_personality_v0:
.fnstart
bx lr
.cantunwind
.fnend
.section .text.__gcc_personality_v1, "ax", %progbits
.global __gxx_personality_v1
__gxx_personality_v1:
.fnstart
bx lr
.cantunwind
.fnend
.section .text.__aeabi_unwind_cpp_pr0, "ax", %progbits
.global __aeabi_unwind_cpp_pr0
__aeabi_unwind_cpp_pr0:
.fnstart
bx lr
.cantunwind
.fnend
// Entry point for GC
.text
.global _start
_start:
bl func1
bl func2
bx lr
// GC should have only removed unusedfunc1 and unusedfunc2 the personality
// routines are kept alive by references from live .ARM.exidx and .ARM.extab
// sections
// CHECK: Disassembly of section .text:
// CHECK-NEXT: _start:
// CHECK-NEXT: 11000: 01 00 00 eb bl #4 <func1>
// CHECK-NEXT: 11004: 01 00 00 eb bl #4 <func2>
// CHECK-NEXT: 11008: 1e ff 2f e1 bx lr
// CHECK: func1:
// CHECK-NEXT: 1100c: 1e ff 2f e1 bx lr
// CHECK: func2:
// CHECK-NEXT: 11010: 1e ff 2f e1 bx lr
// CHECK: __gxx_personality_v0:
// CHECK-NEXT: 11014: 1e ff 2f e1 bx lr
// CHECK: __aeabi_unwind_cpp_pr0:
// CHECK-NEXT: 11018: 1e ff 2f e1 bx lr
// GC should have removed table entries for unusedfunc1, unusedfunc2
// and __gxx_personality_v1
// CHECK-NOT: unusedfunc1
// CHECK-NOT: unusedfunc2
// CHECK-NOT: __gxx_personality_v1
// CHECK-EXIDX-NOT: Contents of section .ARM.extab.text.unusedfunc2:
// CHECK-EXIDX: Contents of section .ARM.exidx:
// 100d4 + f38 = 1100c = func1
// 100dc + f34 = 11010 = func2 (100e0 + 14 = 100f4 = .ARM.extab.text.func2)
// CHECK-EXIDX-NEXT: 100d4 380f0000 08849780 340f0000 14000000
// 100e4 + f30 = 11014 = __gxx_personality_v0
// 100ec + f2c = 11018 = __aeabi_unwind_cpp_pr0
// CHECK-EXIDX-NEXT: 100e4 300f0000 01000000 2c0f0000 01000000
// CHECK-EXIDX-NEXT: Contents of section .ARM.extab.text.func2:
// 100f4 + f20 = 11014 = __gxx_personality_v0
// CHECK-EXIDX-NEXT: 100f4 200f0000 b0b0b000