[ELF][ARM] Fix crash when discarding InputSections that have .ARM.exidx
authorPeter Smith <peter.smith@linaro.org>
Tue, 24 Sep 2019 21:44:14 +0000 (21:44 +0000)
committerPeter Smith <peter.smith@linaro.org>
Tue, 24 Sep 2019 21:44:14 +0000 (21:44 +0000)
When /DISCARD/ is used on an input section, that input section may have
a .ARM.exidx metadata section that depends on it. As the discard handling
comes after the .ARM.exidx synthetic section is created we need to make
sure that we account for the case where the .ARM.exidx output section
should be removed because there are no more live input sections.

Differential Revision: https://reviews.llvm.org/D67848

llvm-svn: 372781

lld/ELF/SyntheticSections.cpp
lld/ELF/SyntheticSections.h
lld/test/ELF/arm-exidx-discard.s [deleted file]
lld/test/ELF/linkerscript/arm-exidx-discard-all.s [new file with mode: 0644]
lld/test/ELF/linkerscript/arm-exidx-discard.s [new file with mode: 0644]

index 1948da930952ea3d4edc794088a348c4b5734d30..ddfd317c72637c50e793c0ca443a9b6224545471 100644 (file)
@@ -3160,17 +3160,23 @@ static InputSection *findExidxSection(InputSection *isec) {
   return nullptr;
 }
 
+static bool isValidExidxSectionDep(InputSection *isec) {
+  return (isec->flags & SHF_ALLOC) && (isec->flags & SHF_EXECINSTR) &&
+         isec->getSize() > 0;
+}
+
 bool ARMExidxSyntheticSection::addSection(InputSection *isec) {
   if (isec->type == SHT_ARM_EXIDX) {
-    exidxSections.push_back(isec);
-    return true;
+    if (InputSection* dep = isec->getLinkOrderDep())
+      if (isValidExidxSectionDep(dep)) {
+        exidxSections.push_back(isec);
+        return true;
+      }
+    return false;
   }
 
-  if ((isec->flags & SHF_ALLOC) && (isec->flags & SHF_EXECINSTR) &&
-      isec->getSize() > 0) {
+  if (isValidExidxSectionDep(isec)) {
     executableSections.push_back(isec);
-    if (empty && findExidxSection(isec))
-      empty = false;
     return false;
   }
 
@@ -3337,6 +3343,12 @@ void ARMExidxSyntheticSection::writeTo(uint8_t *buf) {
   assert(size == offset + 8);
 }
 
+bool ARMExidxSyntheticSection::isNeeded() const {
+  return llvm::find_if(exidxSections, [](InputSection *isec) {
+           return isec->isLive();
+         }) != exidxSections.end();
+}
+
 bool ARMExidxSyntheticSection::classof(const SectionBase *d) {
   return d->kind() == InputSectionBase::Synthetic && d->type == SHT_ARM_EXIDX;
 }
index 7442f33f0b0a31f7e2275114a225f5763a0eeb70..d592dcb84e1264b1cc03333faa6e1a1d2bdfb833 100644 (file)
@@ -994,7 +994,7 @@ public:
 
   size_t getSize() const override { return size; }
   void writeTo(uint8_t *buf) override;
-  bool isNeeded() const override { return !empty; }
+  bool isNeeded() const override;
   // Sort and remove duplicate entries.
   void finalizeContents() override;
   InputSection *getLinkOrderDep() const;
@@ -1008,9 +1008,6 @@ public:
 private:
   size_t size;
 
-  // Empty if ExecutableSections contains no dependent .ARM.exidx sections.
-  bool empty = true;
-
   // Instead of storing pointers to the .ARM.exidx InputSections from
   // InputObjects, we store pointers to the executable sections that need
   // .ARM.exidx sections. We can then use the dependentSections of these to
diff --git a/lld/test/ELF/arm-exidx-discard.s b/lld/test/ELF/arm-exidx-discard.s
deleted file mode 100644 (file)
index beffdfb..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-// REQUIRES: arm
-// RUN: llvm-mc -filetype=obj -triple arm-gnu-linux-eabi -mcpu cortex-a7 -arm-add-build-attributes %s -o %t.o
-// RUN: echo "ENTRY(__entrypoint) SECTIONS { . = 0x10000; .text : { *(.text .text.*) } /DISCARD/ : { *(.ARM.exidx*) *(.gnu.linkonce.armexidx.*) } }" > %t.script
-// RUN: ld.lld -T %t.script %t.o -o %t.elf
-// RUN: llvm-readobj --sections %t.elf | FileCheck %s
-
-.globl  __entrypoint
-__entrypoint:
-.fnstart
-    bx  lr
- .save {r7, lr}
- .setfp r7, sp, #0
- .fnend
-// Check that .ARM.exidx/.gnu.linkonce.armexidx
-// are correctly removed if they were added.
-// CHECK-NOT: .ARM.exidx
-// CHECK-NOT: .gnu.linkonce.armexidx.
diff --git a/lld/test/ELF/linkerscript/arm-exidx-discard-all.s b/lld/test/ELF/linkerscript/arm-exidx-discard-all.s
new file mode 100644 (file)
index 0000000..ce74b27
--- /dev/null
@@ -0,0 +1,19 @@
+// REQUIRES: arm
+// RUN: llvm-mc -filetype=obj -triple arm-gnu-linux-eabi -mcpu cortex-a7 -arm-add-build-attributes %s -o %t.o
+// RUN: echo "ENTRY(__entrypoint) SECTIONS { /DISCARD/ : { *(.text.1) } }" > %t.script
+// RUN: ld.lld -T %t.script %t.o -o %t.elf
+// RUN: llvm-readobj --sections %t.elf | FileCheck %s
+
+/// Test that when we /DISCARD/ all the input sections with associated
+/// .ARM.exidx sections then we also discard all the .ARM.exidx sections.
+
+ .section .text.1, "ax", %progbits
+ .global foo
+ .type foo, %function
+ .fnstart
+foo:
+  bx lr
+  .cantunwind
+  .fnend
+
+// CHECK-NOT: .ARM.exidx
diff --git a/lld/test/ELF/linkerscript/arm-exidx-discard.s b/lld/test/ELF/linkerscript/arm-exidx-discard.s
new file mode 100644 (file)
index 0000000..beffdfb
--- /dev/null
@@ -0,0 +1,17 @@
+// REQUIRES: arm
+// RUN: llvm-mc -filetype=obj -triple arm-gnu-linux-eabi -mcpu cortex-a7 -arm-add-build-attributes %s -o %t.o
+// RUN: echo "ENTRY(__entrypoint) SECTIONS { . = 0x10000; .text : { *(.text .text.*) } /DISCARD/ : { *(.ARM.exidx*) *(.gnu.linkonce.armexidx.*) } }" > %t.script
+// RUN: ld.lld -T %t.script %t.o -o %t.elf
+// RUN: llvm-readobj --sections %t.elf | FileCheck %s
+
+.globl  __entrypoint
+__entrypoint:
+.fnstart
+    bx  lr
+ .save {r7, lr}
+ .setfp r7, sp, #0
+ .fnend
+// Check that .ARM.exidx/.gnu.linkonce.armexidx
+// are correctly removed if they were added.
+// CHECK-NOT: .ARM.exidx
+// CHECK-NOT: .gnu.linkonce.armexidx.