[lld] 48aebfc - [ELF][ARM] Do not create .ARM.exidx sections for out of range inputs

Peter Smith via llvm-commits llvm-commits at lists.llvm.org
Tue May 5 02:02:22 PDT 2020


Author: Peter Smith
Date: 2020-05-05T09:59:45+01:00
New Revision: 48aebfc908ba7b9372aaa478a9c200789491096e

URL: https://github.com/llvm/llvm-project/commit/48aebfc908ba7b9372aaa478a9c200789491096e
DIFF: https://github.com/llvm/llvm-project/commit/48aebfc908ba7b9372aaa478a9c200789491096e.diff

LOG: [ELF][ARM] Do not create .ARM.exidx sections for out of range inputs

A linker will create .ARM.exidx sections for InputSections that don't
have them. This can cause a relocation out of range error If the
InputSection happens to be extremely far away from the other sections.
This is often the case for the vector table on older ARM CPUs as the only
two places that the table can be placed is 0 or 0xffff0000. We fix this
by removing InputSections that need a linker generated .ARM.exidx
section if that would cause an error.

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

Added: 
    lld/test/ELF/arm-exidx-range.s

Modified: 
    lld/ELF/SyntheticSections.cpp

Removed: 
    


################################################################################
diff  --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp
index e1322cdb69f0..bffea2352489 100644
--- a/lld/ELF/SyntheticSections.cpp
+++ b/lld/ELF/SyntheticSections.cpp
@@ -3363,8 +3363,19 @@ void ARMExidxSyntheticSection::finalizeContents() {
   // ICF may remove executable InputSections and their dependent .ARM.exidx
   // section that we recorded earlier.
   auto isDiscarded = [](const InputSection *isec) { return !isec->isLive(); };
-  llvm::erase_if(executableSections, isDiscarded);
   llvm::erase_if(exidxSections, isDiscarded);
+  // We need to remove discarded InputSections and InputSections without
+  // .ARM.exidx sections that if we generated the .ARM.exidx it would be out
+  // of range.
+  auto isDiscardedOrOutOfRange = [this](InputSection *isec) {
+    if (!isec->isLive())
+      return true;
+    if (findExidxSection(isec))
+      return false;
+    int64_t off = static_cast<int64_t>(isec->getVA() - getVA());
+    return off != llvm::SignExtend64(off, 31);
+  };
+  llvm::erase_if(executableSections, isDiscardedOrOutOfRange);
 
   // Sort the executable sections that may or may not have associated
   // .ARM.exidx sections by order of ascending address. This requires the

diff  --git a/lld/test/ELF/arm-exidx-range.s b/lld/test/ELF/arm-exidx-range.s
new file mode 100644
index 000000000000..69763705276c
--- /dev/null
+++ b/lld/test/ELF/arm-exidx-range.s
@@ -0,0 +1,35 @@
+// REQUIRES: arm
+// RUN: llvm-mc --arm-add-build-attributes --triple=armv7a-linux-gnueabihf -filetype=obj %s -o %t.o
+// RUN: echo "SECTIONS { \
+// RUN:         . = 0x80000000; \
+// RUN:         .text : { *(.text) } \
+// RUN:         .vectors 0xffff0000 : { *(.vectors) } \
+// RUN: } " > %t.script
+// RUN: ld.lld --script %t.script %t.o -o %t
+// RUN: llvm-readobj -x .ARM.exidx %t | FileCheck %s
+/// Adapted from Linux kernel linker script failing due to out of range
+/// relocation. The .vectors at 0xffff0000 is a common occurrence as the vector
+/// table can only be placed at either 0 or 0xffff0000 in older ARM CPUs.
+/// In the example the .vectors won't have an exception table so if LLD creates
+/// one then we'll get a relocation out of range error. Check that we don't
+/// synthesise a table entry or place a sentinel out of range.
+
+/// Expect only .ARM.exidx from _start and sentinel
+// CHECK: Hex dump of section '.ARM.exidx':
+// CHECK-NEXT: 0x80000000 10000000 01000000 0c000000 01000000
+// CHECK-NOT:  0x80000010
+
+ .text
+ .global _start
+ .type _start, %function
+_start:
+ .fnstart
+ bx lr
+ .cantunwind
+ .fnend
+
+ .section .vectors, "ax", %progbits
+ .global vecs
+ .type vecs, %function
+vecs:
+ bx lr


        


More information about the llvm-commits mailing list