forked from OSchip/llvm-project
[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:
parent
50188b2771
commit
0760605ac5
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
Loading…
Reference in New Issue