Index: ELF/SyntheticSections.h =================================================================== --- ELF/SyntheticSections.h +++ ELF/SyntheticSections.h @@ -782,9 +782,14 @@ class ARMExidxSentinelSection : public SyntheticSection { public: + static ARMExidxSentinelSection *create(); + ARMExidxSentinelSection(); size_t getSize() const override { return 8; } void writeTo(uint8_t *Buf) override; + bool empty() const override; + + InputSection *Highest = 0; }; // A container for one or more linker generated thunks. Instances of these Index: ELF/SyntheticSections.cpp =================================================================== --- ELF/SyntheticSections.cpp +++ ELF/SyntheticSections.cpp @@ -2550,6 +2550,13 @@ : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, Config->Wordsize, ".rld_map") {} +ARMExidxSentinelSection *ARMExidxSentinelSection::create() { + if (Config->Relocatable) + return nullptr; + + return make(); +} + ARMExidxSentinelSection::ARMExidxSentinelSection() : SyntheticSection(SHF_ALLOC | SHF_LINK_ORDER, SHT_ARM_EXIDX, Config->Wordsize, ".ARM.exidx") {} @@ -2561,31 +2568,25 @@ // The sentinel must have the PREL31 value of an address higher than any // address described by any other table entry. 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. - OutputSection *C = getParent(); - InputSection *Highest = nullptr; - unsigned Skip = 1; - for (const BaseCommand *Base : llvm::reverse(C->SectionCommands)) { - if (!isa(Base)) - continue; - auto L = cast(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 S = + Highest->getParent()->Addr + Highest->getOffset(Highest->getSize()); uint64_t P = getVA(); Target->relocateOne(Buf, R_ARM_PREL31, S - P); write32le(Buf + 4, 1); } +// The sentinel has to be removed if there are no other .ARM.exidx entries. +bool ARMExidxSentinelSection::empty() const { + OutputSection *OS = getParent(); + for (auto *B : OS->SectionCommands) + if (auto *ISD = dyn_cast(B)) + for (auto *S : ISD->Sections) + if (!isa(S)) + return false; + return true; +} + ThunkSection::ThunkSection(OutputSection *OS, uint64_t Off) : SyntheticSection(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS, Config->Wordsize, ".text.thunk") { Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -54,7 +54,6 @@ void resolveShfLinkOrder(); void sortInputSections(); void finalizeSections(); - void addPredefinedSections(); void setReservedSymbolSections(); std::vector createPhdrs(); @@ -390,6 +389,12 @@ Add(InX::ShStrTab); if (InX::StrTab) Add(InX::StrTab); + + if (Config->EMachine == EM_ARM) + // Add a sentinel to terminate .ARM.exidx. It helps an unwinder + // to find the exact address range of the last entry. + if (auto *Sec = ARMExidxSentinelSection::create()) + Add(Sec); } // The main function of the writer. @@ -1145,10 +1150,10 @@ } static bool compareByFilePosition(InputSection *A, InputSection *B) { - // Synthetic doesn't have link order dependecy, stable_sort will keep it last + // Synthetic, i. e. a sentinel section, should go last. if (A->kind() == InputSectionBase::Synthetic || B->kind() == InputSectionBase::Synthetic) - return false; + return A->kind() != InputSectionBase::Synthetic; InputSection *LA = A->getLinkOrderDep(); InputSection *LB = B->getLinkOrderDep(); OutputSection *AOut = LA->getParent(); @@ -1231,23 +1236,37 @@ } std::stable_sort(Sections.begin(), Sections.end(), compareByFilePosition); - if (Config->MergeArmExidx && !Config->Relocatable && - Config->EMachine == EM_ARM && Sec->Type == SHT_ARM_EXIDX) { - // The EHABI for the Arm Architecture permits consecutive identical - // table entries to be merged. We use a simple implementation that - // removes a .ARM.exidx Input Section if it can be merged into the - // previous one. This does not require any rewriting of InputSection - // contents but misses opportunities for fine grained deduplication where - // only a subset of the InputSection contents can be merged. - int Cur = 1; - int Prev = 0; - int N = Sections.size(); - while (Cur < N) { - if (isDuplicateArmExidxSec(Sections[Prev], Sections[Cur])) - Sections[Cur] = nullptr; - else - Prev = Cur; - ++Cur; + if (!Config->Relocatable && Config->EMachine == EM_ARM && + Sec->Type == SHT_ARM_EXIDX) { + + if (!Sections.empty() && isa(Sections.back())) { + assert(Sections.size() >= 2 && + "We should create a sentinel section only if there are " + "alive regular exidx sections."); + // The last executable section is required to fill the sentinel. + // Remember it here so that we don't have to find it again. + auto *Sentinel = cast(Sections.back()); + Sentinel->Highest = Sections[Sections.size() - 2]->getLinkOrderDep(); + } + + if (Config->MergeArmExidx) { + // The EHABI for the Arm Architecture permits consecutive identical + // table entries to be merged. We use a simple implementation that + // removes a .ARM.exidx Input Section if it can be merged into the + // previous one. This does not require any rewriting of InputSection + // contents but misses opportunities for fine grained deduplication + // where only a subset of the InputSection contents can be merged. + int Cur = 1; + int Prev = 0; + // The last one is a sentinel entry which should not be removed. + int N = Sections.size() - 1; + while (Cur < N) { + if (isDuplicateArmExidxSec(Sections[Prev], Sections[Cur])) + Sections[Cur] = nullptr; + else + Prev = Cur; + ++Cur; + } } } @@ -1413,7 +1432,6 @@ if (errorCount()) return; - addPredefinedSections(); removeUnusedSyntheticSections(); sortSections(); @@ -1510,17 +1528,6 @@ [](SyntheticSection *SS) { SS->postThunkContents(); }); } -template void Writer::addPredefinedSections() { - // ARM ABI requires .ARM.exidx to be terminated by some piece of data. - // We have the terminater synthetic section class. Add that at the end. - OutputSection *Cmd = findSection(".ARM.exidx"); - if (!Cmd || !Cmd->Live || Config->Relocatable) - return; - - auto *Sentinel = make(); - Cmd->addSection(Sentinel); -} - // The linker is expected to define SECNAME_start and SECNAME_end // symbols for a few sections. This function defines them. template void Writer::addStartEndSymbols() { Index: test/ELF/arm-exidx-dedup-and-sentinel.s =================================================================== --- /dev/null +++ test/ELF/arm-exidx-dedup-and-sentinel.s @@ -0,0 +1,29 @@ +// REQUIRES: arm +// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t.o +// RUN: ld.lld %t.o -shared -o %t.so --section-start .text=0x2000 --section-start .ARM.exidx=0x1000 +// RUN: llvm-objdump -s -triple=armv7a-none-linux-gnueabi %t.so | FileCheck %s + + .syntax unified + + .section .text.foo, "ax", %progbits + .globl foo +foo: + .fnstart + bx lr + .cantunwind + .fnend + + .section .text.bar, "ax", %progbits + .globl bar +bar: + .fnstart + bx lr + .cantunwind + .fnend + +// CHECK: Contents of section .ARM.exidx: +// 1000 + 1000 = 0x2000 = foo +// The entry for bar is the same as previous and is eliminated. +// The sentinel entry should be preserved. +// 1008 + 1000 = 0x2008 = bar + sizeof(bar) +// CHECK-NEXT: 1000 00100000 01000000 00100000 01000000 Index: test/ELF/linkerscript/arm-exidx-sentinel-and-assignment.s =================================================================== --- test/ELF/linkerscript/arm-exidx-sentinel-and-assignment.s +++ test/ELF/linkerscript/arm-exidx-sentinel-and-assignment.s @@ -1,13 +1,14 @@ -# 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 --no-merge-exidx-entries -T %t.script %t.o -shared -o %t.so -# RUN: llvm-objdump -s -triple=armv7a-none-linux-gnueabi %t.so | FileCheck %s +// 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 --no-merge-exidx-entries -T %t.script %t.o -shared -o %t.so +// RUN: llvm-objdump -s -triple=armv7a-none-linux-gnueabi %t.so | FileCheck %s --check-prefix=DUMP +// RUN: llvm-readobj -s -t %t.so | FileCheck %s .syntax unified .text @@ -18,7 +19,23 @@ bx lr .fnend -// CHECK: Contents of section .ARM.exidx: +// DUMP: Contents of section .ARM.exidx: // 1000 + 1000 = 0x2000 = _start // 1008 + 0ffc = 0x2004 = _start + sizeof(_start) -// CHECK-NEXT: 1000 00100000 01000000 fc0f0000 01000000 +// DUMP-NEXT: 1000 00100000 01000000 fc0f0000 01000000 + +// CHECK: Section { +// CHECK: Name: .ARM.exidx +// CHECK-NEXT: Type: SHT_ARM_EXIDX +// CHECK-NEXT: Flags [ +// CHECK-NEXT: SHF_ALLOC +// CHECK-NEXT: SHF_LINK_ORDER +// CHECK-NEXT: ] +// CHECK-NEXT: Address: 0x1000 +// CHECK-NEXT: Offset: +// CHECK-NEXT: Size: 16 + +// Symbol 'foo' is expected to point at the end of the section. +// CHECK: Symbol { +// CHECK: Name: foo +// CHECK-NEXT: Value: 0x1010