summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIgor Kudrin <ikudrin@accesssoftek.com>2017-12-14 06:23:50 +0000
committerIgor Kudrin <ikudrin@accesssoftek.com>2017-12-14 06:23:50 +0000
commitf01caab4b7ee9673d010c849b5a77c2489670db7 (patch)
tree69915328c76747a568aa27ec11e3b24514134ff3
parentb308cace8496a54e4674b305481f7e5886284306 (diff)
downloadbcm5719-llvm-f01caab4b7ee9673d010c849b5a77c2489670db7.tar.gz
bcm5719-llvm-f01caab4b7ee9673d010c849b5a77c2489670db7.zip
[ELF] Prevent crash in writing an .ARM.exidx sentinel entry.
We might crash in 'ARMExidxSentinelSection::writeTo()' because it expected the sentinel entry to be put in the same 'InputSectionDescription' as the last real entry. This assumption fails if the last output section command for .ARM.exidx is anything but an input section description, because in this case 'OutputSection::addSection()' creates a new 'InputSectionDescription'. Differential Revision: https://reviews.llvm.org/D41105 llvm-svn: 320668
-rw-r--r--lld/ELF/SyntheticSections.cpp24
-rw-r--r--lld/test/ELF/linkerscript/arm-exidx-sentinel-and-assignment.s24
2 files changed, 39 insertions, 9 deletions
diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp
index 0afe90102c9..c9d31d735d7 100644
--- a/lld/ELF/SyntheticSections.cpp
+++ b/lld/ELF/SyntheticSections.cpp
@@ -2569,16 +2569,22 @@ ARMExidxSentinelSection::ARMExidxSentinelSection()
void ARMExidxSentinelSection::writeTo(uint8_t *Buf) {
// The Sections are sorted in order of ascending PREL31 address with the
// sentinel last. We need to find the InputSection that precedes the
- // sentinel. By construction the Sentinel is in the last
- // InputSectionDescription as the InputSection that precedes it.
+ // sentinel.
OutputSection *C = getParent();
- auto ISD =
- std::find_if(C->SectionCommands.rbegin(), C->SectionCommands.rend(),
- [](const BaseCommand *Base) {
- return isa<InputSectionDescription>(Base);
- });
- auto L = cast<InputSectionDescription>(*ISD);
- InputSection *Highest = L->Sections[L->Sections.size() - 2];
+ InputSection *Highest = nullptr;
+ int Skip = 1;
+ for (const BaseCommand *Base : llvm::reverse(C->SectionCommands)) {
+ if (!isa<InputSectionDescription>(Base))
+ continue;
+ auto L = cast<InputSectionDescription>(Base);
+ if (Skip >= L->Sections.size()) {
+ Skip -= L->Sections.size();
+ continue;
+ }
+ Highest = L->Sections[L->Sections.size() - Skip - 1];
+ break;
+ }
+ assert(Highest);
InputSection *LS = Highest->getLinkOrderDep();
uint64_t S = LS->getParent()->Addr + LS->getOffset(LS->getSize());
uint64_t P = getVA();
diff --git a/lld/test/ELF/linkerscript/arm-exidx-sentinel-and-assignment.s b/lld/test/ELF/linkerscript/arm-exidx-sentinel-and-assignment.s
new file mode 100644
index 00000000000..cbf295aa706
--- /dev/null
+++ b/lld/test/ELF/linkerscript/arm-exidx-sentinel-and-assignment.s
@@ -0,0 +1,24 @@
+# REQUIRES: arm
+# RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t.o
+# RUN: echo "SECTIONS { \
+# RUN: .ARM.exidx 0x1000 : { *(.ARM.exidx*) foo = .; } \
+# RUN: .text 0x2000 : { *(.text*) } \
+# RUN: }" > %t.script
+## We used to crash if the last output section command for .ARM.exidx
+## was anything but an input section description.
+# RUN: ld.lld -T %t.script %t.o -shared -o %t.so
+# RUN: llvm-objdump -s -triple=armv7a-none-linux-gnueabi %t.so | FileCheck %s
+
+ .syntax unified
+ .text
+ .global _start
+_start:
+ .fnstart
+ .cantunwind
+ bx lr
+ .fnend
+
+// CHECK: Contents of section .ARM.exidx:
+// 1000 + 1000 = 0x2000 = _start
+// 1008 + 0ffc = 0x2004 = _start + sizeof(_start)
+// CHECK-NEXT: 1000 00100000 01000000 fc0f0000 01000000
OpenPOWER on IntegriCloud