From 3ce9af9370d091b7d959902216482f3015e965fc Mon Sep 17 00:00:00 2001 From: Peter Smith Date: Thu, 28 Mar 2019 11:10:20 +0000 Subject: [PATCH] [ELF][ARM] Recommit Redesign of .ARM.exidx handling to use a SyntheticSection Recommit r356666 with fixes for buildbot failure, as well as handling for --emit-relocs, which we decide not to emit any relocation sections as the table is already position independent and an offline tool can deduce the relocations. Instead of creating extra Synthetic .ARM.exidx sections to account for gaps in the table, create a single .ARM.exidx SyntheticSection that can derive the contents of the gaps from a sorted list of the executable InputSections. This has the benefit of moving the ARM specific code for SyntheticSections in SHF_LINK_ORDER processing and the table merging code into the ARM specific SyntheticSection. This also makes it easier to create EXIDX_CANTUNWIND table entries for executable InputSections that don't have an associated .ARM.exidx section. Fixes pr40277 Differential Revision: https://reviews.llvm.org/D59216 llvm-svn: 357160 --- lld/ELF/OutputSections.cpp | 4 +- lld/ELF/SyntheticSections.cpp | 205 ++++++++++++++++++++++++++++---- lld/ELF/SyntheticSections.h | 74 ++++++++++-- lld/ELF/Writer.cpp | 109 +++-------------- lld/test/ELF/arm-data-prel.s | 20 ++-- lld/test/ELF/arm-exidx-add-missing.s | 66 ++++++++++ lld/test/ELF/arm-exidx-canunwind.s | 27 ++--- lld/test/ELF/arm-exidx-dedup.s | 25 ++-- lld/test/ELF/arm-exidx-discard.s | 5 +- lld/test/ELF/arm-exidx-emit-relocs.s | 71 +++++++++++ lld/test/ELF/arm-exidx-gc.s | 23 ++-- lld/test/ELF/arm-exidx-shared.s | 8 +- lld/test/ELF/arm-exidx-synthetic-link.s | 37 ++++++ 13 files changed, 498 insertions(+), 176 deletions(-) create mode 100644 lld/test/ELF/arm-exidx-add-missing.s create mode 100644 lld/test/ELF/arm-exidx-emit-relocs.s create mode 100644 lld/test/ELF/arm-exidx-synthetic-link.s diff --git a/lld/ELF/OutputSections.cpp b/lld/ELF/OutputSections.cpp index a7f35eb..4cb5a3c 100644 --- a/lld/ELF/OutputSections.cpp +++ b/lld/ELF/OutputSections.cpp @@ -289,7 +289,9 @@ void OutputSection::finalize() { // SHF_LINK_ORDER flag. The dependency is indicated by the sh_link field. We // need to translate the InputSection sh_link to the OutputSection sh_link, // all InputSections in the OutputSection have the same dependency. - if (auto *D = First->getLinkOrderDep()) + if (auto *EX = dyn_cast(First)) + Link = EX->getLinkOrderDep()->getParent()->SectionIndex; + else if (auto *D = First->getLinkOrderDep()) Link = D->getParent()->SectionIndex; } diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp index 5e67610..142caaa 100644 --- a/lld/ELF/SyntheticSections.cpp +++ b/lld/ELF/SyntheticSections.cpp @@ -3039,33 +3039,194 @@ MipsRldMapSection::MipsRldMapSection() : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, Config->Wordsize, ".rld_map") {} -ARMExidxSentinelSection::ARMExidxSentinelSection() +ARMExidxSyntheticSection::ARMExidxSyntheticSection() : SyntheticSection(SHF_ALLOC | SHF_LINK_ORDER, SHT_ARM_EXIDX, - Config->Wordsize, ".ARM.exidx") {} - -// Write a terminating sentinel entry to the end of the .ARM.exidx table. -// This section will have been sorted last in the .ARM.exidx table. -// This table entry will have the form: -// | PREL31 upper bound of code that has exception tables | EXIDX_CANTUNWIND | -// 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) { - assert(Highest); - uint64_t S = Highest->getVA(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 { - for (InputSection *IS : getInputSections(getParent())) - if (!isa(IS)) + Config->Wordsize, ".ARM.exidx") { + for (InputSectionBase *&IS : InputSections) { + if (isa(IS) && IS->Type == SHT_ARM_EXIDX) { + ExidxSections.push_back(cast(IS)); + IS = nullptr; + } else if (IS->Live && isa(IS) && + IS->kind() != SectionBase::Synthetic && + (IS->Flags & SHF_ALLOC) && (IS->Flags & SHF_EXECINSTR) && + IS->getSize() > 0) { + ExecutableSections.push_back(cast(IS)); + } + } + setSizeAndOffsets(); + + // FIXME: we do not output a relocation section when --emit-relocs is used + // as we do not have relocation sections for linker generated table entries + // and we would have to erase at a late stage relocations from merged entries. + // Given that exception tables are already position independent and a binary + // analyzer could derive the relocations we choose to erase the relocations. + if (Config->EmitRelocs) + for (InputSectionBase *&IS : InputSections) + if (IS && isa(IS) && IS->Type == SHT_REL) { + InputSection *RS = cast(IS); + if (InputSectionBase *EX = RS->getRelocatedSection()) + if (isa(EX) && EX->Type == SHT_ARM_EXIDX) + IS = nullptr; + } + + std::vector &V = InputSections; + V.erase(std::remove(V.begin(), V.end(), nullptr), V.end()); +} + +static InputSection *findExidxSection(InputSection *IS) { + for (InputSection *D : IS->DependentSections) + if (D->Type == SHT_ARM_EXIDX) + return D; + return nullptr; +} + +void ARMExidxSyntheticSection::setSizeAndOffsets() { + size_t Offset = 0; + Size = 0; + for (InputSection *IS : ExecutableSections) { + if (InputSection *D = findExidxSection(IS)) { + D->OutSecOff = Offset; + D->Parent = getParent(); + Offset += D->getSize(); + Empty = false; + } else { + Offset += 8; + } + } + // Size includes Sentinel. + Size = Offset + 8; +} + +// References to .ARM.Extab Sections have bit 31 clear and are not the +// special EXIDX_CANTUNWIND bit-pattern. +static bool isExtabRef(uint32_t Unwind) { + return (Unwind & 0x80000000) == 0 && Unwind != 0x1; +} + +// Return true if the .ARM.exidx section Cur can be merged into the .ARM.exidx +// section Prev, where Cur follows Prev in the table. This can be done if the +// unwinding instructions in Cur are identical to Prev. Linker generated +// EXIDX_CANTUNWIND entries are represented by nullptr as they do not have an +// InputSection. +static bool isDuplicateArmExidxSec(InputSection *Prev, InputSection *Cur) { + + struct ExidxEntry { + ulittle32_t Fn; + ulittle32_t Unwind; + }; + // Get the last table Entry from the previous .ARM.exidx section. If Prev is + // nullptr then it will be a synthesized EXIDX_CANTUNWIND entry. + ExidxEntry PrevEntry = {ulittle32_t(0), ulittle32_t(1)}; + if (Prev) + PrevEntry = Prev->getDataAs().back(); + if (isExtabRef(PrevEntry.Unwind)) + return false; + + // We consider the unwind instructions of an .ARM.exidx table entry + // a duplicate if the previous unwind instructions if: + // - Both are the special EXIDX_CANTUNWIND. + // - Both are the same inline unwind instructions. + // We do not attempt to follow and check links into .ARM.extab tables as + // consecutive identical entries are rare and the effort to check that they + // are identical is high. + + // If Cur is nullptr then this is synthesized EXIDX_CANTUNWIND entry. + if (Cur == nullptr) + return PrevEntry.Unwind == 1; + + for (const ExidxEntry Entry : Cur->getDataAs()) + if (isExtabRef(Entry.Unwind) || Entry.Unwind != PrevEntry.Unwind) return false; + + // All table entries in this .ARM.exidx Section can be merged into the + // previous Section. return true; } -bool ARMExidxSentinelSection::classof(const SectionBase *D) { +// The .ARM.exidx table must be sorted in ascending order of the address of the +// functions the table describes. Optionally duplicate adjacent table entries +// can be removed. At the end of the function the ExecutableSections must be +// sorted in ascending order of address, Sentinel is set to the InputSection +// with the highest address and any InputSections that have mergeable +// .ARM.exidx table entries are removed from it. +void ARMExidxSyntheticSection::finalizeContents() { + // Sort the executable sections that may or may not have associated + // .ARM.exidx sections by order of ascending address. This requires the + // relative positions of InputSections to be known. + auto CompareByFilePosition = [](const InputSection *A, + const InputSection *B) { + OutputSection *AOut = A->getParent(); + OutputSection *BOut = B->getParent(); + + if (AOut != BOut) + return AOut->SectionIndex < BOut->SectionIndex; + return A->OutSecOff < B->OutSecOff; + }; + std::stable_sort(ExecutableSections.begin(), ExecutableSections.end(), + CompareByFilePosition); + Sentinel = ExecutableSections.back(); + // Optionally merge adjacent duplicate entries. + if (Config->MergeArmExidx) { + std::vector SelectedSections; + SelectedSections.reserve(ExecutableSections.size()); + SelectedSections.push_back(ExecutableSections[0]); + size_t Prev = 0; + for (size_t I = 1; I < ExecutableSections.size(); ++I) { + InputSection *EX1 = findExidxSection(ExecutableSections[Prev]); + InputSection *EX2 = findExidxSection(ExecutableSections[I]); + if (!isDuplicateArmExidxSec(EX1, EX2)) { + SelectedSections.push_back(ExecutableSections[I]); + Prev = I; + } + } + ExecutableSections = std::move(SelectedSections); + } + setSizeAndOffsets(); +} + +InputSection *ARMExidxSyntheticSection::getLinkOrderDep() const { + return ExecutableSections.front(); +} + +// To write the .ARM.exidx table from the ExecutableSections we have three cases +// 1.) The InputSection has a .ARM.exidx InputSection in its dependent sections. +// We write the .ARM.exidx section contents and apply its relocations. +// 2.) The InputSection does not have a dependent .ARM.exidx InputSection. We +// must write the contents of an EXIDX_CANTUNWIND directly. We use the +// start of the InputSection as the purpose of the linker generated +// section is to terminate the address range of the previous entry. +// 3.) A trailing EXIDX_CANTUNWIND sentinel section is required at the end of +// the table to terminate the address range of the final entry. +void ARMExidxSyntheticSection::writeTo(uint8_t *Buf) { + + const uint8_t CantUnwindData[8] = {0, 0, 0, 0, // PREL31 to target + 1, 0, 0, 0}; // EXIDX_CANTUNWIND + + uint64_t Offset = 0; + for (InputSection *IS : ExecutableSections) { + assert(IS->getParent() != nullptr); + if (InputSection *D = findExidxSection(IS)) { + memcpy(Buf + Offset, D->data().data(), D->data().size()); + D->relocateAlloc(Buf, Buf + D->getSize()); + Offset += D->getSize(); + } else { + // A Linker generated CANTUNWIND section. + memcpy(Buf + Offset, CantUnwindData, sizeof(CantUnwindData)); + uint64_t S = IS->getVA(); + uint64_t P = getVA() + Offset; + Target->relocateOne(Buf + Offset, R_ARM_PREL31, S - P); + Offset += 8; + } + } + // Write Sentinel. + memcpy(Buf + Offset, CantUnwindData, sizeof(CantUnwindData)); + uint64_t S = Sentinel->getVA(Sentinel->getSize()); + uint64_t P = getVA() + Offset; + Target->relocateOne(Buf + Offset, R_ARM_PREL31, S - P); + assert(Size == Offset + 8); +} + +bool ARMExidxSyntheticSection::classof(const SectionBase *D) { return D->kind() == InputSectionBase::Synthetic && D->Type == SHT_ARM_EXIDX; } diff --git a/lld/ELF/SyntheticSections.h b/lld/ELF/SyntheticSections.h index 371be2e..7923435 100644 --- a/lld/ELF/SyntheticSections.h +++ b/lld/ELF/SyntheticSections.h @@ -938,19 +938,76 @@ public: void writeTo(uint8_t *Buf) override {} }; -class ARMExidxSentinelSection : public SyntheticSection { +// Representation of the combined .ARM.Exidx input sections. We process these +// as a SyntheticSection like .eh_frame as we need to merge duplicate entries +// and add terminating sentinel entries. +// +// The .ARM.exidx input sections after SHF_LINK_ORDER processing is done form +// a table that the unwinder can derive (Addresses are encoded as offsets from +// table): +// | Address of function | Unwind instructions for function | +// where the unwind instructions are either a small number of unwind or the +// special EXIDX_CANTUNWIND entry representing no unwinding information. +// When an exception is thrown from an address A, the unwinder searches the +// table for the closest table entry with Address of function <= A. This means +// that for two consecutive table entries: +// | A1 | U1 | +// | A2 | U2 | +// The range of addresses described by U1 is [A1, A2) +// +// There are two cases where we need a linker generated table entry to fixup +// the address ranges in the table +// Case 1: +// - A sentinel entry added with an address higher than all +// executable sections. This was needed to work around libunwind bug pr31091. +// - After address assignment we need to find the highest addressed executable +// section and use the limit of that section so that the unwinder never +// matches it. +// Case 2: +// - InputSections without a .ARM.exidx section (usually from Assembly) +// need a table entry so that they terminate the range of the previously +// function. This is pr40277. +// +// 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 +// either find the .ARM.exidx section or know that we need to generate one. +class ARMExidxSyntheticSection : public SyntheticSection { public: - ARMExidxSentinelSection(); - size_t getSize() const override { return 8; } + ARMExidxSyntheticSection(); + size_t getSize() const override { return Size; } void writeTo(uint8_t *Buf) override; - bool empty() const override; + bool empty() const override { return Empty; } + // Sort and remove duplicate entries. + void finalizeContents() override; + InputSection *getLinkOrderDep() const; static bool classof(const SectionBase *D); - // The last section referenced by a regular .ARM.exidx section. - // It is found and filled in Writer::resolveShfLinkOrder(). - // The sentinel points at the end of that section. - InputSection *Highest = nullptr; + // Links to the ARMExidxSections so we can transfer the relocations once the + // layout is known. + std::vector ExidxSections; + +private: + // Derive Size from contents of ExecutableSections, including any linker + // generated sentinels. Also set the OutSecOff of the ExidxSections. + void setSizeAndOffsets(); + 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 + // either find the .ARM.exidx section or know that we need to generate one. + std::vector ExecutableSections; + + // The executable InputSection with the highest address to use for the + // sentinel. We store separately from ExecutableSections as merging of + // duplicate entries may mean this InputSection is removed from + // ExecutableSections. + InputSection *Sentinel = nullptr; }; // A container for one or more linker generated thunks. Instances of these @@ -1005,6 +1062,7 @@ Defined *addSyntheticLocal(StringRef Name, uint8_t Type, uint64_t Value, // Linker generated sections which can be used as inputs. struct InStruct { InputSection *ARMAttributes; + ARMExidxSyntheticSection *ARMExidx; BssSection *Bss; BssSection *BssRelRo; BuildIdSection *BuildId; diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp index 3ba8027..5d899c0 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -444,10 +444,12 @@ template static void createSyntheticSections() { if (In.StrTab) Add(In.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()); + if (Config->EMachine == EM_ARM && !Config->Relocatable) { + // The ARMExidxsyntheticsection replaces all the individual .ARM.exidx + // InputSections. + In.ARMExidx = make(); + Add(In.ARMExidx); + } } // The main function of the writer. @@ -930,6 +932,9 @@ void Writer::forEachRelSec( Fn(*IS); for (EhInputSection *ES : In.EhFrame->Sections) Fn(*ES); + if (In.ARMExidx && In.ARMExidx->Live) + for (InputSection *Ex : In.ARMExidx->ExidxSections) + Fn(*Ex); } // This function generates assignments for predefined symbols (e.g. _end or @@ -1392,11 +1397,6 @@ template void Writer::sortSections() { } static bool compareByFilePosition(InputSection *A, InputSection *B) { - // Synthetic, i. e. a sentinel section, should go last. - if (A->kind() == InputSectionBase::Synthetic || - B->kind() == InputSectionBase::Synthetic) - return A->kind() != InputSectionBase::Synthetic; - InputSection *LA = A->getLinkOrderDep(); InputSection *LB = B->getLinkOrderDep(); OutputSection *AOut = LA->getParent(); @@ -1407,53 +1407,6 @@ static bool compareByFilePosition(InputSection *A, InputSection *B) { return LA->OutSecOff < LB->OutSecOff; } -// This function is used by the --merge-exidx-entries to detect duplicate -// .ARM.exidx sections. It is Arm only. -// -// The .ARM.exidx section is of the form: -// | PREL31 offset to function | Unwind instructions for function | -// where the unwind instructions are either a small number of unwind -// instructions inlined into the table entry, the special CANT_UNWIND value of -// 0x1 or a PREL31 offset into a .ARM.extab Section that contains unwind -// instructions. -// -// We return true if all the unwind instructions in the .ARM.exidx entries of -// Cur can be merged into the last entry of Prev. -static bool isDuplicateArmExidxSec(InputSection *Prev, InputSection *Cur) { - - // References to .ARM.Extab Sections have bit 31 clear and are not the - // special EXIDX_CANTUNWIND bit-pattern. - auto IsExtabRef = [](uint32_t Unwind) { - return (Unwind & 0x80000000) == 0 && Unwind != 0x1; - }; - - struct ExidxEntry { - ulittle32_t Fn; - ulittle32_t Unwind; - }; - - // Get the last table Entry from the previous .ARM.exidx section. - const ExidxEntry &PrevEntry = Prev->getDataAs().back(); - if (IsExtabRef(PrevEntry.Unwind)) - return false; - - // We consider the unwind instructions of an .ARM.exidx table entry - // a duplicate if the previous unwind instructions if: - // - Both are the special EXIDX_CANTUNWIND. - // - Both are the same inline unwind instructions. - // We do not attempt to follow and check links into .ARM.extab tables as - // consecutive identical entries are rare and the effort to check that they - // are identical is high. - - for (const ExidxEntry Entry : Cur->getDataAs()) - if (IsExtabRef(Entry.Unwind) || Entry.Unwind != PrevEntry.Unwind) - return false; - - // All table entries in this .ARM.exidx Section can be merged into the - // previous Section. - return true; -} - template void Writer::resolveShfLinkOrder() { for (OutputSection *Sec : OutputSections) { if (!(Sec->Flags & SHF_LINK_ORDER)) @@ -1471,46 +1424,17 @@ template void Writer::resolveShfLinkOrder() { } } } - std::stable_sort(Sections.begin(), Sections.end(), compareByFilePosition); + // The ARM.exidx section use SHF_LINK_ORDER, but we have consolidated + // this processing inside the ARMExidxsyntheticsection::finalizeContents(). if (!Config->Relocatable && Config->EMachine == EM_ARM && - Sec->Type == SHT_ARM_EXIDX) { - - if (auto *Sentinel = dyn_cast(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. - Sentinel->Highest = Sections[Sections.size() - 2]->getLinkOrderDep(); - } + Sec->Type == SHT_ARM_EXIDX) + continue; - // 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. - if (Config->MergeArmExidx) { - size_t Prev = 0; - // The last one is a sentinel entry which should not be removed. - for (size_t I = 1; I < Sections.size() - 1; ++I) { - if (isDuplicateArmExidxSec(Sections[Prev], Sections[I])) - Sections[I] = nullptr; - else - Prev = I; - } - } - } + std::stable_sort(Sections.begin(), Sections.end(), compareByFilePosition); for (int I = 0, N = Sections.size(); I < N; ++I) *ScriptSections[I] = Sections[I]; - - // Remove the Sections we marked as duplicate earlier. - for (BaseCommand *Base : Sec->SectionCommands) - if (auto *ISD = dyn_cast(Base)) - llvm::erase_if(ISD->Sections, [](InputSection *IS) { return !IS; }); } } @@ -1780,6 +1704,7 @@ template void Writer::finalizeSections() { // Dynamic section must be the last one in this list and dynamic // symbol table section (DynSymTab) must be the first one. finalizeSynthetic(In.DynSymTab); + finalizeSynthetic(In.ARMExidx); finalizeSynthetic(In.Bss); finalizeSynthetic(In.BssRelRo); finalizeSynthetic(In.GnuHashTab); @@ -1806,8 +1731,8 @@ template void Writer::finalizeSections() { if (!Script->HasSectionsCommand && !Config->Relocatable) fixSectionAlignments(); - // After link order processing .ARM.exidx sections can be deduplicated, which - // needs to be resolved before any other address dependent operation. + // SHFLinkOrder processing must be processed after relative section placements are + // known but before addresses are allocated. resolveShfLinkOrder(); // Jump instructions in many ISAs have small displacements, and therefore they diff --git a/lld/test/ELF/arm-data-prel.s b/lld/test/ELF/arm-data-prel.s index 78b4281..e5bb6fa 100644 --- a/lld/test/ELF/arm-data-prel.s +++ b/lld/test/ELF/arm-data-prel.s @@ -1,9 +1,8 @@ // REQUIRES: arm -// RUN: llvm-mc %s -triple=armv7-unknown-linux-gnueabi -filetype=obj -o %t.o +// RUN: llvm-mc %s -triple=armv7-unknown-linux-gnueabi -filetype=obj --arm-add-build-attributes -o %t.o // RUN: echo "SECTIONS { \ // RUN: .text : { *(.text) } \ // RUN: .prel.test : { *(.ARM.exidx) } \ -// RUN: .prel.test.TEST1 : { *(.ARM.exidx.TEST1) } \ // RUN: .TEST1 : { *(.TEST1) } } " > %t.script // RUN: ld.lld --script %t.script %t.o -o %t // RUN: llvm-readobj -s -sd %t | FileCheck --check-prefix=CHECK %s @@ -47,17 +46,14 @@ __aeabi_unwind_cpp_pr0: // The expected value of the exception table is // Word0 0 in bit 31, -4 encoded in 31-bit signed offset // Word1 Inline table entry EHT Inline Personality Routine #0 -// CHECK: Name: .prel.test -// CHECK: SectionData ( -// CHECK: 0000: FCFFFF7F B0B0B080 -// CHECK: ) - -// The expected value of the exception table is -// Word0 0 in bit 31, +8 encoded in 31-bit signed offset -// Word1 Inline table entry EHT Inline Personality Routine #0 +// Word3 0 in bit 31, +10 encoded in 31-bit signed offset +// Word4 Inline table entry EHT Inline Personality Routine #0 // set vsp = r11 // pop r11, r14 -// CHECK: Name: .prel.test.TEST1 +// Word5 Sentinel +18 EXIDX_CANTUNWIND + +// CHECK: Name: .prel.test // CHECK: SectionData ( -// CHECK: 0000: 08000000 80849B80 +// CHECK: 0000: FCFFFF7F B0B0B080 10000000 80849B80 +// CHECK: 0010: 18000000 01000000 // CHECK: ) diff --git a/lld/test/ELF/arm-exidx-add-missing.s b/lld/test/ELF/arm-exidx-add-missing.s new file mode 100644 index 0000000..7e452c6 --- /dev/null +++ b/lld/test/ELF/arm-exidx-add-missing.s @@ -0,0 +1,66 @@ +// REQUIRES: arm +// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi --arm-add-build-attributes %s -o %t +// RUN: ld-lld %t --no-merge-exidx-entries -o %t2 +// RUN: llvm-objdump -s %t2 | FileCheck %s +// RUN: ld-lld %t -o %t3 +// RUN: llvm-objdump -s %t3 | FileCheck %s -check-prefix=CHECK-MERGE + +// The ARM.exidx section is a table of 8-byte entries of the form: +// | PREL31 Relocation to start of function | Unwinding information | +// The range of addresses covered by the table entry is terminated by the +// next table entry. This means that an executable section without a .ARM.exidx +// section does not terminate the range of addresses. To fix this the linker +// synthesises an EXIDX_CANTUNWIND entry for each section wihout a .ARM.exidx +// section. + + .syntax unified + + // Expect inline unwind instructions + .section .text.01, "ax", %progbits + .global f1 +f1: + .fnstart + bx lr + .save {r7, lr} + .setfp r7, sp, #0 + .fnend + + // Expect no unwind information from assembler. The linker must + // synthesise an EXIDX_CANTUNWIND entry to prevent an exception + // thrown through f2 from matching against the unwind instructions + // for f1. + .section .text.02, "ax", %progbits + .global f2 +f2: + bx lr + + + // Expect 1 EXIDX_CANTUNWIND entry that can be merged into the linker + // generated EXIDX_CANTUNWIND as if the assembler had generated it. + .section .text.03, "ax",%progbits + .global f3 +f3: + .fnstart + bx lr + .cantunwind + .fnend + + // Dummy implementation of personality routines to satisfy reference + // from exception tables, linker will generate EXIDX_CANTUNWIND. + .section .text.__aeabi_unwind_cpp_pr0, "ax", %progbits + .global __aeabi_unwind_cpp_pr0 +__aeabi_unwind_cpp_pr0: + bx lr + +// f1, f2 +// CHECK: 100d4 2c0f0000 08849780 280f0000 01000000 +// f3, __aeabi_unwind_cpp_pr0 +// CHECK-NEXT: 100e4 240f0000 01000000 200f0000 01000000 +// sentinel +// CHECK-NEXT: 100f4 1c0f0000 01000000 + +// f1, (f2, f3, __aeabi_unwind_cpp_pr0) +// CHECK-MERGE: 100d4 2c0f0000 08849780 280f0000 01000000 +// sentinel +// CHECK-MERGE-NEXT: 100e4 2c0f0000 01000000 + diff --git a/lld/test/ELF/arm-exidx-canunwind.s b/lld/test/ELF/arm-exidx-canunwind.s index df89d00..cb15886 100644 --- a/lld/test/ELF/arm-exidx-canunwind.s +++ b/lld/test/ELF/arm-exidx-canunwind.s @@ -1,6 +1,6 @@ // REQUIRES: arm -// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t -// RUN: ld.lld %t -o %t2 2>&1 +// RUN: llvm-mc -filetype=obj --arm-add-build-attributes -triple=armv7a-none-linux-gnueabi %s -o %t +// RUN: ld.lld %t -o %t2 // RUN: llvm-objdump -d -triple=armv7a-none-linux-gnueabi %t2 | FileCheck %s // RUN: llvm-objdump -s -triple=armv7a-none-linux-gnueabi %t2 | FileCheck -check-prefix=CHECK-EXIDX %s // RUN: llvm-readobj --program-headers --sections %t2 | FileCheck -check-prefix=CHECK-PT %s @@ -66,15 +66,14 @@ _start: // CHECK: __aeabi_unwind_cpp_pr0: // CHECK-NEXT: 11018: 1e ff 2f e1 bx lr -// CHECK-EXIDX: Contents of section .ARM.exidx: -// 100d4 + f38 = 1100c = func1 (inline unwinding data) -// 100dc + f34 = 11010 = func2 (100e0 + c = 100ec = .ARM.extab entry) -// CHECK-EXIDX-NEXT: 100d4 380f0000 08849780 340f0000 0c000000 -// 100e4 + f30 = 11014 = terminate = func2 + sizeof(func2) -// CHECK-EXIDX-NEXT: 100e4 300f0000 01000000 -// CHECK-EXIDX-NEXT: Contents of section .ARM.extab: -// 100ec + f28 = 11014 = __gxx_personality_v0 -// CHECK-EXIDX-NEXT: 100ec 280f0000 b0b0b000 00000000 +// 100d4 + f2c = 11000 = main (linker generated cantunwind) +// 100dc + f30 = 1100c = func1 (inline unwinding data) +// CHECK-EXIDX: 100d4 2c0f0000 01000000 300f0000 08849780 +// 100e4 + f2c = 11010 = func2 (100e8 + 14 = 100fc = .ARM.extab entry) +// 100ec + f28 = 11014 = __gcc_personality_v0 (linker generated cantunwind) +// CHECK-EXIDX-NEXT: 100e4 2c0f0000 14000000 280f0000 01000000 +// 100f4 + f28 = 1101c = sentinel +// CHECK-EXIDX-NEXT: 100f4 280f0000 01000000 // CHECK-PT: Name: .ARM.exidx // CHECK-PT-NEXT: Type: SHT_ARM_EXIDX (0x70000001) @@ -84,14 +83,14 @@ _start: // CHECK-PT-NEXT: ] // CHECK-PT-NEXT: Address: 0x100D4 // CHECK-PT-NEXT: Offset: 0xD4 -// CHECK-PT-NEXT: Size: 24 +// CHECK-PT-NEXT: Size: 40 // CHECK-PT: Type: PT_ARM_EXIDX (0x70000001) // CHECK-PT-NEXT: Offset: 0xD4 // CHECK-PT-NEXT: VirtualAddress: 0x100D4 // CHECK-PT-NEXT: PhysicalAddress: 0x100D4 -// CHECK-PT-NEXT: FileSize: 24 -// CHECK-PT-NEXT: MemSize: 24 +// CHECK-PT-NEXT: FileSize: 40 +// CHECK-PT-NEXT: MemSize: 40 // CHECK-PT-NEXT: Flags [ (0x4) // CHECK-PT-NEXT: PF_R (0x4) // CHECK-PT-NEXT: ] diff --git a/lld/test/ELF/arm-exidx-dedup.s b/lld/test/ELF/arm-exidx-dedup.s index 49d4c2c..d916418 100644 --- a/lld/test/ELF/arm-exidx-dedup.s +++ b/lld/test/ELF/arm-exidx-dedup.s @@ -1,27 +1,29 @@ // REQUIRES: arm -// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t +// RUN: llvm-mc -filetype=obj --arm-add-build-attributes -triple=armv7a-none-linux-gnueabi %s -o %t // RUN: ld.lld %t --no-merge-exidx-entries -o %t2 // RUN: llvm-objdump -s %t2 | FileCheck --check-prefix CHECK-DUPS %s // RUN: ld.lld %t -o %t3 // RUN: llvm-objdump -s %t3 | FileCheck %s + // Test that lld can at least remove duplicate .ARM.exidx sections. A more // fine grained implementation will be able to remove duplicate entries within // a .ARM.exidx section. // With duplicate entries // CHECK-DUPS: Contents of section .ARM.exidx: -// CHECK-DUPS-NEXT: 100d4 2c0f0000 01000000 280f0000 01000000 -// CHECK-DUPS-NEXT: 100e4 240f0000 01000000 200f0000 01000000 -// CHECK-DUPS-NEXT: 100f4 1c0f0000 08849780 180f0000 08849780 -// CHECK-DUPS-NEXT: 10104 140f0000 08849780 100f0000 14000000 -// CHECK-DUPS-NEXT: 10114 0c0f0000 18000000 080f0000 01000000 +// CHECK-DUPS-NEXT: 100d4 2c0f0000 01000000 280f0000 01000000 +// CHECK-DUPS-NEXT: 100e4 240f0000 01000000 200f0000 01000000 +// CHECK-DUPS-NEXT: 100f4 1c0f0000 08849780 180f0000 08849780 +// CHECK-DUPS-NEXT: 10104 140f0000 08849780 100f0000 24000000 +// CHECK-DUPS-NEXT: 10114 0c0f0000 28000000 080f0000 01000000 +// CHECK-DUPS-NEXT: 10124 040f0000 01000000 000f0000 01000000 // CHECK-DUPS-NEXT: Contents of section .ARM.extab: // After duplicate entry removal // CHECK: Contents of section .ARM.exidx: -// CHECK-NEXT: 100d4 2c0f0000 01000000 340f0000 08849780 -// CHECK-NEXT: 100e4 380f0000 14000000 340f0000 18000000 -// CHECK-NEXT: 100f4 300f0000 01000000 +// CHECK-NEXT: 100d4 2c0f0000 01000000 340f0000 08849780 +// CHECK-NEXT: 100e4 380f0000 1c000000 340f0000 20000000 +// CHECK-NEXT: 100f4 300f0000 01000000 300f0000 01000000 // CHECK-NEXT: Contents of section .ARM.extab: .syntax unified @@ -113,8 +115,9 @@ f8: .long 0 .fnend - // Dummy implementation of personality routines to satisfy reference from - // exception tables +// Dummy implementation of personality routines to satisfy reference from +// exception tables +// Expect Linker generated EXIDX_CANTUNWIND tables .section .text.__gcc_personality_v0, "ax", %progbits .global __gxx_personality_v0 __gxx_personality_v0: diff --git a/lld/test/ELF/arm-exidx-discard.s b/lld/test/ELF/arm-exidx-discard.s index 2a204a0..6b5579d 100644 --- a/lld/test/ELF/arm-exidx-discard.s +++ b/lld/test/ELF/arm-exidx-discard.s @@ -6,8 +6,11 @@ .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 diff --git a/lld/test/ELF/arm-exidx-emit-relocs.s b/lld/test/ELF/arm-exidx-emit-relocs.s new file mode 100644 index 0000000..e7dff5b --- /dev/null +++ b/lld/test/ELF/arm-exidx-emit-relocs.s @@ -0,0 +1,71 @@ +// REQUIRES: arm +// RUN: llvm-mc -filetype=obj --arm-add-build-attributes -triple=armv7a-none-linux-gnueabi %s -o %t +// RUN: ld.lld --emit-relocs %t -o %t2 +// RUN: llvm-objdump -s -triple=armv7a-none-linux-gnueabi %t2 | FileCheck %s +// RUN: llvm-readelf --relocs %t2 | FileCheck -check-prefix=CHECK-RELOCS %s + +// LLD does not support --emit-relocs for .ARM.exidx sections as the relocations +// from synthetic table entries won't be represented. Given the known use cases +// of --emit-relocs, relocating kernels, and binary analysis, the former doesn't +// use exceptions and the latter can derive the relocations from the table if +// they need them. + .syntax unified + // Will produce an ARM.exidx entry with inline unwinding instructions + .section .text.func1, "ax",%progbits + .global func1 +func1: + .fnstart + bx lr + .save {r7, lr} + .setfp r7, sp, #0 + .fnend + + .syntax unified + .section .text.func2, "ax",%progbits +// A function with the same inline unwinding instructions, expect merge. + .global func2 +func2: + .fnstart + bx lr + .save {r7, lr} + .setfp r7, sp, #0 + .fnend + + .section .text.25, "ax", %progbits + .global func25 +func25: + .fnstart + bx lr + .cantunwind + .fnend + + .section .text.26, "ax", %progbits + .global func26 +func26: + .fnstart + bx lr + .cantunwind + .fnend + + .syntax unified + .section .text.func3, "ax",%progbits +// A function with the same inline unwinding instructions, expect merge. + .global func3 +func3: + .fnstart + bx lr + .save {r7, lr} + .setfp r7, sp, #0 + .fnend + + .section .text.__aeabi_unwind_cpp_pr0, "ax", %progbits + .global __aeabi_unwind_cpp_pr0 +__aeabi_unwind_cpp_pr0: + bx lr + +// CHECK: Contents of section .ARM.exidx: +// CHECK-NEXT: 100d4 2c0f0000 08849780 2c0f0000 01000000 +// CHECK-NEXT: 100e4 2c0f0000 08849780 280f0000 01000000 +// CHECK-NEXT: 100f4 240f0000 01000000 + +// CHECK-RELOCS-NOT: Relocation section '.rel.ARM.exidx' diff --git a/lld/test/ELF/arm-exidx-gc.s b/lld/test/ELF/arm-exidx-gc.s index 50c8616..b5431cb 100644 --- a/lld/test/ELF/arm-exidx-gc.s +++ b/lld/test/ELF/arm-exidx-gc.s @@ -1,5 +1,5 @@ // REQUIRES: arm -// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t +// RUN: llvm-mc -filetype=obj --arm-add-build-attributes -triple=armv7a-none-linux-gnueabi %s -o %t // RUN: ld.lld %t --no-merge-exidx-entries -o %t2 --gc-sections 2>&1 // RUN: llvm-objdump -d -triple=armv7a-none-linux-gnueabi %t2 | FileCheck %s // RUN: llvm-objdump -s -triple=armv7a-none-linux-gnueabi %t2 | FileCheck -check-prefix=CHECK-EXIDX %s @@ -111,14 +111,15 @@ _start: // CHECK-NOT: __gxx_personality_v1 // CHECK-EXIDX: Contents of section .ARM.exidx: -// 100d4 + f38 = 1100c = func1 -// 100dc + f34 = 11010 = func2 (100e0 + 1c = 100fc = .ARM.extab) -// CHECK-EXIDX-NEXT: 100d4 380f0000 08849780 340f0000 1c000000 -// 100e4 + f30 = 11014 = __gxx_personality_v0 -// 100ec + f2c = 11018 = __aeabi_unwind_cpp_pr0 -// CHECK-EXIDX-NEXT: 100e4 300f0000 01000000 2c0f0000 01000000 -// 100f4 + f28 = 1101c = __aeabi_unwind_cpp_pr0 + sizeof(__aeabi_unwind_cpp_pr0) -// CHECK-EXIDX-NEXT: 100f4 280f0000 01000000 +// 100d4 + f2c = 11000 +// 100dc + f30 = 1100c = func1 +// CHECK-EXIDX-NEXT: 100d4 2c0f0000 01000000 300f0000 08849780 +// 100e4 + f2c = 11010 = func2 (100e8 + 1c = 10104 = .ARM.extab) +// 100ec + f28 = 11014 = __gxx_personality_v0 +// CHECK-EXIDX-NEXT: 100e4 2c0f0000 1c000000 280f0000 01000000 +// 100f4 + f24 = 11018 = __aeabi_unwind_cpp_pr0 +// 100fc + f20 = 1101c = __aeabi_unwind_cpp_pr0 + sizeof(__aeabi_unwind_cpp_pr0) +// CHECK-EXIDX-NEXT: 100f4 240f0000 01000000 200f0000 01000000 // CHECK-EXIDX-NEXT: Contents of section .ARM.extab: -// 100fc + f18 = 11014 = __gxx_personality_v0 -// CHECK-EXIDX-NEXT: 100fc 180f0000 b0b0b000 +// 10104 + f10 = 11014 = __gxx_personality_v0 +// CHECK-EXIDX-NEXT: 10104 100f0000 b0b0b000 diff --git a/lld/test/ELF/arm-exidx-shared.s b/lld/test/ELF/arm-exidx-shared.s index 9b7a246..7987035 100644 --- a/lld/test/ELF/arm-exidx-shared.s +++ b/lld/test/ELF/arm-exidx-shared.s @@ -1,8 +1,8 @@ // REQUIRES: arm -// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t +// RUN: llvm-mc -filetype=obj -arm-add-build-attributes -triple=armv7a-none-linux-gnueabi %s -o %t // RUN: ld.lld --hash-style=sysv %t --shared -o %t2 2>&1 // RUN: llvm-readobj --relocations %t2 | FileCheck %s -// RUN: llvm-objdump -s -triple=armv7a-none-linux-gnueabi %t2 | FileCheck -check-prefix=CHECK-EXTAB %s +// RUN: llvm-objdump -s -triple=armv7a-none-linux-gnueabi %t2 | FileCheck --check-prefix=CHECK-EXTAB-NEXT %s // Check that the relative R_ARM_PREL31 relocation can access a PLT entry // for when the personality routine is referenced from a shared library. @@ -41,5 +41,5 @@ __aeabi_unwind_cpp_pr0: // CHECK-NEXT: 0x300C R_ARM_JUMP_SLOT __gxx_personality_v0 // CHECK-EXTAB: Contents of section .ARM.extab: -// 0x0210 + 0x0e20 = 0x1030 = __gxx_personality_v0(PLT) -// CHECK-EXTAB-NEXT: 0230 000e0000 b0b0b000 00000000 +// 0x0238 + 0xdf8 = 0x1030 = __gxx_personality_v0(PLT) +// CHECK-EXTAB-NEXT: 0238 f80d0000 b0b0b000 00000000 diff --git a/lld/test/ELF/arm-exidx-synthetic-link.s b/lld/test/ELF/arm-exidx-synthetic-link.s new file mode 100644 index 0000000..c308bee0 --- /dev/null +++ b/lld/test/ELF/arm-exidx-synthetic-link.s @@ -0,0 +1,37 @@ +// REQUIRES: arm +// RUN: llvm-mc -filetype=obj -arm-add-build-attributes -triple=armv7a-none-linux-gnueabi %s -o %t.o +// RUN: ld.lld %t.o -o %t.so -shared +// RUN: llvm-readobj -s %t.so | FileCheck %s + +// Test that when all the .ARM.exidx sections are merged into a single +// synthetic EXIDX_CANTUNWIND entry we can still set the SHF_LINK_ORDER +// link. + .syntax unified + .section .text.1, "ax", %progbits + .globl f1 + .type f1, %function +f1: + bx lr + + .section .text.2, "ax", %progbits + .globl f2 + .type f2, %function +f2: + .fnstart + bx lr + .cantunwind + .fnend + +// 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: +// CHECK-NEXT: Offset: +// CHECK-NEXT: Size: +// CHECK-NEXT: Link: [[INDEX:.*]] + +// CHECK: Index: [[INDEX]] +// CHECK-NEXT: Name: .text -- 2.7.4