[ELF][ARM] Garbage collection support for .ARM.exidx sections
authorPeter Smith <peter.smith@linaro.org>
Mon, 10 Oct 2016 10:10:27 +0000 (10:10 +0000)
committerPeter Smith <peter.smith@linaro.org>
Mon, 10 Oct 2016 10:10:27 +0000 (10:10 +0000)
.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

lld/ELF/InputFiles.cpp
lld/ELF/InputFiles.h
lld/ELF/InputSection.h
lld/ELF/MarkLive.cpp
lld/test/ELF/arm-exidx-gc.s [new file with mode: 0644]

index d963079..aa6a53c 100644 (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) {
index b8cdcc5..c489bd6 100644 (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);
 
index 6b82ad4..3ee1697 100644 (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();
index 73ee0c8..8475757 100644 (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.
diff --git a/lld/test/ELF/arm-exidx-gc.s b/lld/test/ELF/arm-exidx-gc.s
new file mode 100644 (file)
index 0000000..4587830
--- /dev/null
@@ -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