Index: ELF/LinkerScript.h =================================================================== --- ELF/LinkerScript.h +++ ELF/LinkerScript.h @@ -227,6 +227,8 @@ MemoryRegion *findMemoryRegion(OutputSectionCommand *Cmd); + void resetAddressState(); + void switchTo(OutputSection *Sec); void flush(); void output(InputSection *Sec); @@ -257,6 +259,8 @@ std::vector *OutputSections; void fabricateDefaultCommands(bool AllocateHeader); + std::vector *> + inputSectionRanges(StringRef S); void addOrphanSections(OutputSectionFactory &Factory); void removeEmptyCommands(); void adjustSectionsBeforeSorting(); Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ ELF/LinkerScript.cpp @@ -463,6 +463,28 @@ Opt.Commands = std::move(Commands); } +// For an OutputSection S, return the InputSectionDescriptions that are +// associated with S. The intention is that callers can iterate over +// InputSectionDescription::Sections and insert sections such as Thunks. +std::vector *> +LinkerScript::inputSectionRanges(StringRef S) { + std::vector *> Ranges; + auto OutCmdPos = std::find_if( + Opt.Commands.begin(), Opt.Commands.end(), [=](BaseCommand *Cmd) { + if (auto *OSCmd = dyn_cast(Cmd)) + return (OSCmd->Name == S); + return false; + }); + if (OutCmdPos == Opt.Commands.end()) + return Ranges; + auto *OutCmd = cast(*OutCmdPos); + for (auto *BaseCmd : OutCmd->Commands) { + if (auto *ISD = dyn_cast(BaseCmd)) + Ranges.push_back(&ISD->Sections); + } + return Ranges; +} + // Add sections that didn't match any sections command. void LinkerScript::addOrphanSections(OutputSectionFactory &Factory) { std::map> Orphanage; @@ -487,13 +509,6 @@ // A new OutputSection, we handle this case in placeOrphanSections() continue; auto *OSCmd = cast(*Pos); - if (KV.second.front()->Name.startswith(".ARM.exidx")) - // .ARM.exidx sections must be handled in one InputSectionDescription - // FIXME: OutputSections still sorts the OutputSection::Sections so we - // can give the wrong answer when the order of the input objects does - // not match the address assignment. - continue; - auto *ISD = make(""); OSCmd->Commands.push_back(ISD); ISD->Sections = std::move(KV.second); @@ -648,6 +663,21 @@ return nullptr; } +// Reset the members associated with address assigment to their initial values +// this permits addressAssignment to be run again. +void LinkerScript::resetAddressState() { + LMAOffset = 0; + CurOutSec = nullptr; + CurMemRegion = nullptr; + ThreadBssOffset = 0; + for (auto &MRI : Opt.MemoryRegions) { + MemoryRegion &MR = MRI.second; + MR.Offset = MR.Origin; + } + AlreadyOutputOS.clear(); + AlreadyOutputIS.clear(); +} + // This function assigns offsets to input sections and an output section // for a single sections command (e.g. ".text { *(.text); }"). void LinkerScript::assignOffsets(OutputSectionCommand *Cmd) { @@ -889,6 +919,7 @@ void LinkerScript::assignAddresses(std::vector &Phdrs) { // Assign addresses as instructed by linker script SECTIONS sub-commands. Dot = 0; + resetAddressState(); ErrorOnMissingSection = true; switchTo(Aether); Index: ELF/OutputSections.cpp =================================================================== --- ELF/OutputSections.cpp +++ ELF/OutputSections.cpp @@ -70,7 +70,7 @@ /*Info*/ 0, /*Link*/ 0) {} -static bool compareByFilePosition(InputSection *A, InputSection *B) { +static bool compareByFilePosition(InputSectionBase *A, InputSectionBase *B) { // Synthetic doesn't have link order dependecy, stable_sort will keep it last if (A->kind() == InputSectionBase::Synthetic || B->kind() == InputSectionBase::Synthetic) @@ -113,9 +113,28 @@ template void OutputSection::finalize() { if ((this->Flags & SHF_LINK_ORDER) && !this->Sections.empty()) { - std::sort(Sections.begin(), Sections.end(), compareByFilePosition); - assignOffsets(); - + if (Config->Relocatable) { + std::sort(Sections.begin(), Sections.end(), compareByFilePosition); + assignOffsets(); + } else { + std::vector *> InputRanges = + Script->inputSectionRanges(Name); + auto &FirstRange = *InputRanges.front(); + if (InputRanges.size() > 1) { + // We must sort over a single InputSectionRange to produce a contiguous + // table, account for scripts with *(.ARM.exidx) instead of + // *(.ARM.exidx*) + // Move all the Sections into a the first range. + auto Iter = InputRanges.begin(); + auto End = InputRanges.end(); + for (++Iter; Iter != End; ++Iter) { + auto *Range = *Iter; + FirstRange.insert(FirstRange.begin(), Range->begin(), Range->end()); + Range->clear(); + } + } + std::sort(FirstRange.begin(), FirstRange.end(), compareByFilePosition); + } // We must preserve the link order dependency of sections with the // 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, Index: ELF/SyntheticSections.cpp =================================================================== --- ELF/SyntheticSections.cpp +++ ELF/SyntheticSections.cpp @@ -2197,8 +2197,10 @@ // | PREL31 upper bound of code that has exception tables | EXIDX_CANTUNWIND | void ARMExidxSentinelSection::writeTo(uint8_t *Buf) { // Get the InputSection before us, we are by definition last - auto RI = cast(this->OutSec)->Sections.rbegin(); - InputSection *LE = *(++RI); + std::vector *> InputRanges = + Script->inputSectionRanges(this->OutSec->Name); + auto RI = InputRanges.front()->rbegin(); + InputSection *LE = cast(*(++RI)); InputSection *LC = cast(LE->getLinkOrderDep()); uint64_t S = LC->OutSec->Addr + LC->getOffset(LC->getSize()); uint64_t P = this->getVA(); Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -250,10 +250,6 @@ if (Config->Relocatable) { assignFileOffsets(); } else { - if (!Script->Opt.HasSections) { - fixSectionAlignments(); - Script->fabricateDefaultCommands(Config->MaxPageSize); - } Script->assignAddresses(Phdrs); // Remove empty PT_LOAD to avoid causing the dynamic linker to try to mmap a @@ -1208,6 +1204,17 @@ applySynthetic({In::MipsGot}, [](SyntheticSection *SS) { SS->updateAllocSize(); }); } + + // The OutputSection finalize below reorders the ARM.exidx sections + // using fabricated script commands. For now we must be placed after + // createThunks() as that still inserts into OutputSections::Sections. + if (!Script->Opt.HasSections) { + fixSectionAlignments(); + Script->fabricateDefaultCommands(Config->MaxPageSize); + } + if (Config->EMachine == EM_ARM && !Config->Relocatable) + Script->assignAddresses(Phdrs); + // Fill other section headers. The dynamic table is finalized // at the end because some tags like RELSZ depend on result // of finalizing other sections. @@ -1229,8 +1236,19 @@ // 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. auto *OS = dyn_cast_or_null(findSection(".ARM.exidx")); - if (OS && !OS->Sections.empty() && !Config->Relocatable) - OS->addSection(make()); + if (!OS || OS->Sections.empty() || Config->Relocatable) + return; + auto *Sentinel = make(); + OS->addSection(Sentinel); + // If the script has a section pattern matching .ARM.exidx we will need + // to add the Sentinel to the InputSectionDescription. In the non-script + // case fabricateDefaultCommands() will add it for us. + if (Script->Opt.HasSections) { + std::vector *> InputRanges = + Script->inputSectionRanges(OS->Name); + if (!InputRanges.empty()) + InputRanges.front()->push_back(Sentinel); + } } // The linker is expected to define SECNAME_start and SECNAME_end Index: test/ELF/arm-exidx-script.s =================================================================== --- /dev/null +++ test/ELF/arm-exidx-script.s @@ -0,0 +1,30 @@ +// REQUIRES: arm +// 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: echo "SECTIONS { \ +// RUN: .ARM.exidx 0x11000 : { *(.ARM.exidx*) } \ +// RUN: .func : { *(.func*) } \ +// RUN: .text : { *(.text*) } } " > %t.script +// RUN: ld.lld --script %t.script %t %tcantunwind -o %t2 2>&1 +// RUN: llvm-objdump -s -triple=armv7a-none-linux-gnueabi %t2 | FileCheck %s +// Check that a linker script that describes .ARM.exidx sections orders the +// .ARM.exidx sections in ascending order of their link order dependencies. + .syntax unified + .text + .global _start +_start: + .fnstart + bx lr + .cantunwind +.fnend +// Check ascending order of first word of each 2 word entry +// [PREL31 to target, unwind info] +// 11000 + 38 = 11038, 11008 + 34 = 1103c ... 11030 + 20 = 11050 +// CHECK: 11000 38000000 01000000 34000000 01000000 +// CHECK-NEXT: 11010 30000000 01000000 2c000000 01000000 +// CHECK-NEXT: 11020 28000000 01000000 24000000 01000000 +// CHECK-NEXT: 11030 20000000 01000000 +// CHECK-NEXT: Contents of section .func: +// CHECK-NEXT: 11038 1eff2fe1 1eff2fe1 1eff2fe1 +// CHECK-NEXT: Contents of section .text: +// CHECK-NEXT: 11044 1eff2fe1 1eff2fe1 1eff2fe1