Index: lld/trunk/ELF/SyntheticSections.h =================================================================== --- lld/trunk/ELF/SyntheticSections.h +++ lld/trunk/ELF/SyntheticSections.h @@ -785,6 +785,9 @@ 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: lld/trunk/ELF/SyntheticSections.cpp =================================================================== --- lld/trunk/ELF/SyntheticSections.cpp +++ lld/trunk/ELF/SyntheticSections.cpp @@ -2561,31 +2561,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: lld/trunk/ELF/Writer.cpp =================================================================== --- lld/trunk/ELF/Writer.cpp +++ lld/trunk/ELF/Writer.cpp @@ -54,7 +54,6 @@ void resolveShfLinkOrder(); void sortInputSections(); void finalizeSections(); - void addPredefinedSections(); void setReservedSymbolSections(); std::vector createPhdrs(); @@ -390,6 +389,11 @@ Add(InX::ShStrTab); if (InX::StrTab) Add(InX::StrTab); + + if (Config->EMachine == EM_ARM && !Config->Relocatable) + // Add a sentinel to terminate .ARM.exidx. It helps an unwinder + // to find the exact address range of the last entry. + Add(make()); } // The main function of the writer. @@ -1145,10 +1149,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 +1235,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 +1431,6 @@ if (errorCount()) return; - addPredefinedSections(); removeUnusedSyntheticSections(); sortSections(); @@ -1510,17 +1527,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: lld/trunk/test/ELF/arm-exidx-dedup-and-sentinel.s =================================================================== --- lld/trunk/test/ELF/arm-exidx-dedup-and-sentinel.s +++ lld/trunk/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: lld/trunk/test/ELF/linkerscript/arm-exidx-sentinel-and-assignment.s =================================================================== --- lld/trunk/test/ELF/linkerscript/arm-exidx-sentinel-and-assignment.s +++ lld/trunk/test/ELF/linkerscript/arm-exidx-sentinel-and-assignment.s @@ -8,6 +8,7 @@ ## 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 +# RUN: llvm-readobj -s -t %t.so | FileCheck %s --check-prefix=SYMBOL .syntax unified .text @@ -22,3 +23,19 @@ # 1000 + 1000 = 0x2000 = _start # 1008 + 0ffc = 0x2004 = _start + sizeof(_start) # CHECK-NEXT: 1000 00100000 01000000 fc0f0000 01000000 + +# SYMBOL: Section { +# SYMBOL: Name: .ARM.exidx +# SYMBOL-NEXT: Type: SHT_ARM_EXIDX +# SYMBOL-NEXT: Flags [ +# SYMBOL-NEXT: SHF_ALLOC +# SYMBOL-NEXT: SHF_LINK_ORDER +# SYMBOL-NEXT: ] +# SYMBOL-NEXT: Address: 0x1000 +# SYMBOL-NEXT: Offset: +# SYMBOL-NEXT: Size: 16 + +# Symbol 'foo' is expected to point at the end of the section. +# SYMBOL: Symbol { +# SYMBOL: Name: foo +# SYMBOL-NEXT: Value: 0x1010