Index: ELF/InputFiles.h =================================================================== --- ELF/InputFiles.h +++ ELF/InputFiles.h @@ -132,7 +132,7 @@ ArrayRef *> getSections() const { return Sections; } InputSectionBase *getSection(const Elf_Sym &Sym) const; - + InputSectionBase *getLinkedToSection(const Elf_Shdr &Sec) const; SymbolBody &getSymbolBody(uint32_t SymbolIndex) const { return *SymbolBodies[SymbolIndex]; } Index: ELF/InputFiles.cpp =================================================================== --- ELF/InputFiles.cpp +++ ELF/InputFiles.cpp @@ -366,6 +366,25 @@ } template +InputSectionBase * +elf::ObjectFile::getLinkedToSection(const Elf_Shdr &Sec) const { + assert(Sec.sh_flags & SHF_LINK_ORDER); + uint32_t Idx = Sec.sh_link; + if (Idx == 0) + return nullptr; + if (Idx >= Sections.size()) + fatal(getFilename(this) + ": invalid link order index: " + Twine(Idx)); + InputSectionBase *Target = Sections[Idx]; + + if (Target == &InputSection::Discarded) + return nullptr; + + if (!Target) + fatal(getFilename(this) + ": unsupported link order reference"); + return Target; +} + +template SymbolBody *elf::ObjectFile::createSymbolBody(const Elf_Sym *Sym) { int Binding = Sym->getBinding(); InputSectionBase *Sec = getSection(*Sym); Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ ELF/LinkerScript.cpp @@ -123,6 +123,7 @@ if (fileMatches(I, sys::path::filename(F->getName()))) for (InputSectionBase *S : F->getSections()) if (!isDiscarded(S) && !S->OutSec && + !(Config->Relocatable && hasLinkOrderDependency(S)) && match(Patterns, S->getSectionName())) Ret.push_back(S); } Index: ELF/OutputSections.h =================================================================== --- ELF/OutputSections.h +++ ELF/OutputSections.h @@ -398,6 +398,7 @@ void addSection(InputSectionBase *C) override; void sortInitFini(); void sortCtorsDtors(); + void sortLinkOrder(); void writeTo(uint8_t *Buf) override; void finalize() override; void assignOffsets() override; @@ -843,6 +844,11 @@ template std::vector>> Out::Pool; +template +InputSection* getLinkOrderDependency(const InputSectionBase* S); +template +bool hasLinkOrderDependency(const InputSectionBase* S); + } // namespace elf } // namespace lld Index: ELF/OutputSections.cpp =================================================================== --- ELF/OutputSections.cpp +++ ELF/OutputSections.cpp @@ -828,7 +828,33 @@ this->Header.sh_entsize = sizeof(Elf_Rel); } +template +InputSection* +elf::getLinkOrderDependency(const InputSectionBase* S) { + const typename ELFT::Shdr *Hdr = S->getSectionHdr(); + if ((Hdr->sh_flags & SHF_LINK_ORDER) && + Hdr->sh_link != 0) { + auto Obj = S->getFile(); + InputSectionBase* ISB = Obj->getLinkedToSection(*S->getSectionHdr()); + return dyn_cast>(ISB); + } + return nullptr; +} + template void OutputSection::finalize() { + if ((this->Header.sh_flags & SHF_LINK_ORDER) && !this->Sections.empty()) { + for(InputSection *S : Sections) { + InputSection *D = getLinkOrderDependency(S); + if(D) { + // For Relocatable links all InputSections will have the same + // OutSec. For non-relocatable links the sh_link is irrelevant but + // some ELF processing tools can complain if it is not set so we use + // the first InputSection. + this->Header.sh_link = D->OutSec->SectionIndex; + return; + } + } + } uint32_t Type = this->Header.sh_type; if (Type != SHT_RELA && Type != SHT_REL) return; @@ -953,6 +979,50 @@ std::stable_sort(Sections.begin(), Sections.end(), compCtors); } +template +bool elf::hasLinkOrderDependency(const InputSectionBase* S) { + return getLinkOrderDependency(S) != nullptr; +} + +// Within an OutputSection the InputSections with the SHF_LINK_ORDER flag set +// are reorderd to match the order of the linked-to InputSections. The order +// of an InputSection without the SHF_LINK_ORDER flag will not be changed. +// Requires InputSections to have VA calculated +template +void OutputSection::sortLinkOrder() { + // Extract the InputSections with SHF_LINK_ORDER dependencies + std::vector*> V; + for (InputSection *S : Sections) { + if (hasLinkOrderDependency(S)) + V.push_back(S); + } + // We are done if there are no sections with link order dependencies. + if (V.empty()) + return; + + auto LinkOrderComp = [](const InputSection *A, + const InputSection *B) { + const InputSection *LinkedToA = getLinkOrderDependency(A); + const InputSection *LinkedToB = getLinkOrderDependency(B); + return LinkedToA->OutSec->getVA() < LinkedToB->OutSec->getVA(); + }; + + std::stable_sort(V.begin(), V.end(), LinkOrderComp); + // Put the ordered list of InputSections with link order dependencies + // back into the OutputSection + size_t Lidx = 0; + for (size_t Sidx = 0; Sidx < Sections.size(); ++Sidx) { + if (hasLinkOrderDependency(Sections[Sidx])) + Sections[Sidx] = V[Lidx++]; + } + assert(Lidx == V.size()); + // We may have changed the order of InputSections so the offsets within the + // OutputSection need to be recalculated. The assignOffsets() function starts + // from Header.sh_size so we must reset it to its original value. + this->Header.sh_size = Sections[0]->OutSecOff; + assignOffsets(); +} + static void fill(uint8_t *Buf, size_t Size, ArrayRef A) { size_t I = 0; for (; I + A.size() < Size; I += A.size()) Index: ELF/Target.h =================================================================== --- ELF/Target.h +++ ELF/Target.h @@ -94,7 +94,7 @@ unsigned TcbSize = 0; bool NeedsThunks = false; - + bool NeedsLinkOrder = false; virtual RelExpr adjustRelaxExpr(uint32_t Type, const uint8_t *Data, RelExpr Expr) const; virtual void relaxGot(uint8_t *Loc, uint64_t Val) const; Index: ELF/Target.cpp =================================================================== --- ELF/Target.cpp +++ ELF/Target.cpp @@ -1503,6 +1503,7 @@ // ARM uses Variant 1 TLS TcbSize = 8; NeedsThunks = true; + NeedsLinkOrder = true; } RelExpr ARMTargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S) const { Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -52,6 +52,7 @@ std::function &, const typename ELFT::Shdr &)> Fn); void finalizeSections(); + void sortLinkOrder(); void addPredefinedSections(); bool needsGot(); @@ -90,6 +91,15 @@ template StringRef elf::getOutputSectionName(InputSectionBase *S) { StringRef Name = S->getSectionName(); + if (Config->Relocatable && hasLinkOrderDependency(S) && + Name.startswith(".ARM.exidx.")) { + // .ARM.exidx.name sections where .name is not in the list below + // should retain the full section name in a Relocatable file to + // maintain the link order dependency + InputSectionBase* LT = getLinkOrderDependency(S); + if (LT->getSectionName() == getOutputSectionName(LT)) + return S->getSectionName(); + } for (StringRef V : {".text.", ".rodata.", ".data.rel.ro.", ".data.", ".bss.", ".init_array.", ".fini_array.", ".ctors.", ".dtors.", ".tbss.", ".gcc_except_table.", ".tdata.", ".ARM.exidx."}) @@ -261,6 +271,8 @@ return; if (Config->Relocatable) { + if (Target->NeedsLinkOrder) + sortLinkOrder(); assignFileOffsets(); } else { Phdrs = Script::X->hasPhdrsCommands() ? Script::X->createPhdrs() @@ -273,6 +285,9 @@ assignAddresses(); } + if (Target->NeedsLinkOrder) + sortLinkOrder(); + if (!Config->OFormatBinary) assignFileOffsets(); else @@ -896,6 +911,17 @@ Define("__fini_array_start", "__fini_array_end", Out::FiniArray); } +// If the OutputSection contains any InputSections with the SHF_LINK_ORDER flag +// then they must be ordered within the OutputSection to conform to the order +// of the linked-to sections. +template void Writer::sortLinkOrder() { + for (OutputSectionBase *Sec : OutputSections) { + auto *OS = dyn_cast>(Sec); + if (OS) + OS->sortLinkOrder(); + } +} + // If a section name is valid as a C identifier (which is rare because of // the leading '.'), linkers are expected to define __start_ and // __stop_ symbols. They are at beginning and end of the section, Index: test/ELF/Inputs/arm-exidx-cantunwind.s =================================================================== --- /dev/null +++ test/ELF/Inputs/arm-exidx-cantunwind.s @@ -0,0 +1,50 @@ +// Functions that will generate a .ARM.exidx section with SHF_LINK_ORDER +// dependency on the progbits section containing the .cantunwind directive + .syntax unified + .section .func1, "ax",%progbits + .globl func1 + .align 2 + .type func1,%function +func1: + .fnstart + bx lr + .cantunwind + .fnend + + .section .func2, "ax", %progbits + .globl func2 + .align 2 + .type func2,%function +func2: + .fnstart + bx lr + .cantunwind + .fnend + + .section .func3, "ax",%progbits + .globl func3 + .align 2 + .type func3,%function +func3: + .fnstart + bx lr + .cantunwind + .fnend + + .section .text, "ax",%progbits + .globl func4 + .align 2 + .type func4,%function +func4: + .fnstart + bx lr + .cantunwind + .fnend + .globl func5 + .align 2 + .type func5,%function +func5: + .fnstart + bx lr + .cantunwind + .fnend Index: test/ELF/arm-shf-link-order.s =================================================================== --- /dev/null +++ test/ELF/arm-shf-link-order.s @@ -0,0 +1,200 @@ +// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t +// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %S/Inputs/arm-exidx-cantunwind.s -o %tcantunwind +// RUN: ld.lld %t %tcantunwind -o %t2 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 +// RUN: echo "SECTIONS { \ +// RUN: .text : { *(.text*) } \ +// RUN: .ARM.exidx : { *(.ARM.exidx) } } " > %t.script +// RUN: ld.lld --script %t.script %tcantunwind %t -o %t3 2>&1 +// RUN: llvm-objdump -d -triple=armv7a-none-linux-gnueabi %t3 | FileCheck -check-prefix=CHECK-SCRIPT %s +// RUN: llvm-objdump -s -triple=armv7a-none-linux-gnueabi %t3 | FileCheck -check-prefix=CHECK-SCRIPT-EXIDX %s +// RUN: ld.lld -r %t %tcantunwind -o %t4 2>&1 +// RUN: llvm-readobj -s %t4 | FileCheck -check-prefix=CHECK-RELOCATABLE %s +// RUN: ld.lld %t4 -o %t5 +// RUN: llvm-objdump -d -triple=armv7a-none-linux-gnueabi %t5 | FileCheck %s +// REQUIRES: arm + +// Each assembler created .ARM.exidx section has the SHF_LINK_ORDER flag set +// with the sh_link containing the section index of the executable section +// containing the function it describes. The linker must combine the .ARM.exidx +// InputSections in the same order that it has combined the executable section, +// such that the combined .ARM.exidx OutputSection can be used as a binary +// search table. + + .syntax unified + .section .text, "ax",%progbits + .globl _start + .align 2 + .type _start,%function +_start: + .fnstart + bx lr + .cantunwind + .fnend + + .section .text.f1, "ax", %progbits + .globl f1 + .align 2 + .type f1,%function +f1: + .fnstart + bx lr + .cantunwind + .fnend + + .section .text.f2, "ax", %progbits + .globl f2 + .align 2 + .type f2,%function +f2: + .fnstart + bx lr + .cantunwind + .fnend + .globl f3 + .align 2 + .type f3,%function +f3: + .fnstart + bx lr + .cantunwind + .fnend + +// Check default no linker script order. + +// CHECK: Disassembly of section .text: +// CHECK: _start: +// CHECK-NEXT: 11000: 1e ff 2f e1 bx lr +// CHECK: f1: +// CHECK-NEXT: 11004: 1e ff 2f e1 bx lr +// CHECK: f2: +// CHECK-NEXT: 11008: 1e ff 2f e1 bx lr +// CHECK: f3: +// CHECK-NEXT: 1100c: 1e ff 2f e1 bx lr +// CHECK: func4: +// CHECK-NEXT: 11010: 1e ff 2f e1 bx lr +// CHECK: func5: +// CHECK-NEXT: 11014: 1e ff 2f e1 bx lr +// CHECK: Disassembly of section .func1: +// CHECK-NEXT: func1: +// CHECK-NEXT: 11018: 1e ff 2f e1 bx lr +// CHECK: Disassembly of section .func2: +// CHECK-NEXT: func2: +// CHECK-NEXT: 1101c: 1e ff 2f e1 bx lr +// CHECK: Disassembly of section .func3: +// CHECK-NEXT: func3: +// CHECK-NEXT: 11020: 1e ff 2f e1 bx lr + +// Each .ARM.exidx section has two 4 byte fields +// Field 1 is the 31-bit offset to the function. The top bit is used to +// indicate whether Field 2 is a pointer or an inline table entry. +// Field 2 is either a pointer to a .ARM.extab section or an inline table +// In this example all Field 2 entries are inline can't unwind (0x1) +// We expect to see the entries in the same order as the functions + +// Contents of section .ARM.exidx: +// 100b4 + f4c = 11000 = _start +// 100bc + f48 = 11004 = f1 +// CHECK-EXIDX: 100b4 4c0f0000 01000000 480f0000 01000000 +// 100c4 + f44 = 11008 = f2 +// 100cc + f40 = 1100c = f3 +// CHECK-EXIDX-NEXT: 100c4 440f0000 01000000 400f0000 01000000 +// 100d4 + f3c = 11010 = func4 +// 100dc + f38 = 11014 = func5 +// CHECK-EXIDX-NEXT: 100d4 3c0f0000 01000000 380f0000 01000000 +// 100e4 + f34 = 11018 = func1 +// 100ec + f30 = 1101c = func2 +// CHECK-EXIDX-NEXT: 100e4 340f0000 01000000 300f0000 01000000 +// 100f4 + f2c = 11020 = func3 +// CHECK-EXIDX-NEXT: 100f4 2c0f0000 01000000 + +// Check linker script order. The .ARM.exidx section will be inserted after +// the .text section but before the orphan sections + +// CHECK-SCRIPT: Disassembly of section .text: +// CHECK-SCRIPT-NEXT: func4: +// CHECK-SCRIPT-NEXT: f4: 1e ff 2f e1 bx lr +// CHECK-SCRIPT: func5: +// CHECK-SCRIPT-NEXT: f8: 1e ff 2f e1 bx lr +// CHECK-SCRIPT: _start: +// CHECK-SCRIPT-NEXT: fc: 1e ff 2f e1 bx lr +// CHECK-SCRIPT: f1: +// CHECK-SCRIPT-NEXT: 100: 1e ff 2f e1 bx lr +// CHECK-SCRIPT: f2: +// CHECK-SCRIPT-NEXT: 104: 1e ff 2f e1 bx lr +// CHECK-SCRIPT: f3: +// CHECK-SCRIPT-NEXT: 108: 1e ff 2f e1 bx lr +// CHECK-SCRIPT-NEXT: Disassembly of section .func1: +// CHECK-SCRIPT-NEXT: func1: +// CHECK-SCRIPT-NEXT: 154: 1e ff 2f e1 bx lr +// CHECK-SCRIPT-NEXT: Disassembly of section .func2: +// CHECK-SCRIPT-NEXT: func2: +// CHECK-SCRIPT-NEXT: 158: 1e ff 2f e1 bx lr +// CHECK-SCRIPT-NEXT: Disassembly of section .func3: +// CHECK-SCRIPT-NEXT: func3: +// CHECK-SCRIPT-NEXT: 15c: 1e ff 2f e1 bx lr + +// Check that the .ARM.exidx section is sorted in order as the functions +// The offset in field 1, is 32-bit so in the binary the most significant bit +// will be e and not f. +// 10c - 18 = f4 +// 114 - 1c = f8 +// CHECK-SCRIPT-EXIDX: 010c e8ffff7f 01000000 e4ffff7f 01000000 +// 11c - 20 = fc +// 124 - 24 = 100 +// CHECK-SCRIPT-EXIDX-NEXT: 011c e0ffff7f 01000000 dcffff7f 01000000 +// 12c - 28 = 104 +// 134 - 2c = 108 +// CHECK-SCRIPT-EXIDX-NEXT: 012c d8ffff7f 01000000 d4ffff7f 01000000 +// 13c + 18 = 154 +// 144 + 14 = 158 +// CHECK-SCRIPT-EXIDX-NEXT: 013c 18000000 01000000 14000000 01000000 +// 14c + 10 = 15c +// CHECK-SCRIPT-EXIDX-NEXT: 014c 10000000 01000000 + +// For a relocatable link check that the .ARM.exidx sections preserve their +// SHF_LINK_ORDER dependencies and the sh_link points at the appropriate +// progbits output section. When the relocatable object is linked as an input +// to a full link the output should match the test above. + +// CHECK-RELOCATABLE: Name: .ARM.exidx +// CHECK-RELOCATABLE-NEXT: Type: SHT_ARM_EXIDX +// CHECK-RELOCATABLE-NEXT: Flags [ +// CHECK-RELOCATABLE-NEXT: SHF_ALLOC +// CHECK-RELOCATABLE-NEXT: SHF_LINK_ORDER +// CHECK-RELOCATABLE: Link: 5 +// CHECK-RELOCATABLE: Name: .ARM.exidx.func1 +// CHECK-RELOCATABLE-NEXT: Type: SHT_ARM_EXIDX +// CHECK-RELOCATABLE-NEXT: Flags [ +// CHECK-RELOCATABLE-NEXT: SHF_ALLOC +// CHECK-RELOCATABLE-NEXT: SHF_LINK_ORDER +// CHECK-RELOCATABLE: Link: 6 +// CHECK-RELOCATABLE: Name: .ARM.exidx.func2 +// CHECK-RELOCATABLE-NEXT: Type: SHT_ARM_EXIDX +// CHECK-RELOCATABLE-NEXT: Flags [ +// CHECK-RELOCATABLE-NEXT: SHF_ALLOC +// CHECK-RELOCATABLE-NEXT: SHF_LINK_ORDER +// CHECK-RELOCATABLE: Link: 7 +// CHECK-RELOCATABLE: Name: .ARM.exidx.func3 +// CHECK-RELOCATABLE-NEXT: Type: SHT_ARM_EXIDX +// CHECK-RELOCATABLE-NEXT: Flags [ +// CHECK-RELOCATABLE-NEXT: SHF_ALLOC +// CHECK-RELOCATABLE-NEXT: SHF_LINK_ORDER +// CHECK-RELOCATABLE: Link: 8 +// CHECK-RELOCATABLE: Section { +// CHECK-RELOCATABLE-NEXT: Index: 5 +// CHECK-RELOCATABLE-NEXT: Name: .text +// CHECK-RELOCATABLE-NEXT: Type: SHT_PROGBITS +// CHECK-RELOCATABLE: Section { +// CHECK-RELOCATABLE-NEXT: Index: 6 +// CHECK-RELOCATABLE-NEXT: Name: .func1 +// CHECK-RELOCATABLE-NEXT: Type: SHT_PROGBITS +// CHECK-RELOCATABLE: Section { +// CHECK-RELOCATABLE-NEXT: Index: 7 +// CHECK-RELOCATABLE-NEXT: Name: .func2 +// CHECK-RELOCATABLE-NEXT: Type: SHT_PROGBITS +// CHECK-RELOCATABLE: Section { +// CHECK-RELOCATABLE-NEXT: Index: 8 +// CHECK-RELOCATABLE-NEXT: Name: .func3 +// CHECK-RELOCATABLE-NEXT: Type: SHT_PROGBITS