[lld] r283734 - [ELF][ARM] Garbage collection support for .ARM.exidx sections

Peter Smith via llvm-commits llvm-commits at lists.llvm.org
Mon Oct 10 03:10:27 PDT 2016


Author: psmith
Date: Mon Oct 10 05:10:27 2016
New Revision: 283734

URL: http://llvm.org/viewvc/llvm-project?rev=283734&view=rev
Log:
[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

Added:
    lld/trunk/test/ELF/arm-exidx-gc.s
Modified:
    lld/trunk/ELF/InputFiles.cpp
    lld/trunk/ELF/InputFiles.h
    lld/trunk/ELF/InputSection.h
    lld/trunk/ELF/MarkLive.cpp

Modified: lld/trunk/ELF/InputFiles.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputFiles.cpp?rev=283734&r1=283733&r2=283734&view=diff
==============================================================================
--- lld/trunk/ELF/InputFiles.cpp (original)
+++ lld/trunk/ELF/InputFiles.cpp Mon Oct 10 05:10:27 2016
@@ -145,6 +145,8 @@ void elf::ObjectFile<ELFT>::parse(DenseS
   // 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>::initializeSe
   }
 }
 
+// .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) {

Modified: lld/trunk/ELF/InputFiles.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputFiles.h?rev=283734&r1=283733&r2=283734&view=diff
==============================================================================
--- lld/trunk/ELF/InputFiles.h (original)
+++ lld/trunk/ELF/InputFiles.h Mon Oct 10 05:10:27 2016
@@ -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);
 

Modified: lld/trunk/ELF/InputSection.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputSection.h?rev=283734&r1=283733&r2=283734&view=diff
==============================================================================
--- lld/trunk/ELF/InputSection.h (original)
+++ lld/trunk/ELF/InputSection.h Mon Oct 10 05:10:27 2016
@@ -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();

Modified: lld/trunk/ELF/MarkLive.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/MarkLive.cpp?rev=283734&r1=283733&r2=283734&view=diff
==============================================================================
--- lld/trunk/ELF/MarkLive.cpp (original)
+++ lld/trunk/ELF/MarkLive.cpp Mon Oct 10 05:10:27 2016
@@ -91,6 +91,8 @@ static void forEachSuccessor(InputSectio
         Fn(resolveReloc(Sec, Rel));
     }
   }
+  if (Sec.DependentSection)
+    Fn({Sec.DependentSection, 0});
 }
 
 // The .eh_frame section is an unfortunate special case.

Added: lld/trunk/test/ELF/arm-exidx-gc.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/arm-exidx-gc.s?rev=283734&view=auto
==============================================================================
--- lld/trunk/test/ELF/arm-exidx-gc.s (added)
+++ lld/trunk/test/ELF/arm-exidx-gc.s Mon Oct 10 05:10:27 2016
@@ -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




More information about the llvm-commits mailing list