Index: ELF/OutputSections.h =================================================================== --- ELF/OutputSections.h +++ ELF/OutputSections.h @@ -82,7 +82,7 @@ uint64_t Addr = 0; uint32_t ShName = 0; - void addSection(InputSection *IS); + void addSection(InputSection *IS, InputSectionDescription *Hint = nullptr); // Location in the output buffer. uint8_t *Loc = nullptr; Index: ELF/OutputSections.cpp =================================================================== --- ELF/OutputSections.cpp +++ ELF/OutputSections.cpp @@ -88,7 +88,11 @@ Type == SHT_NOTE; } -void OutputSection::addSection(InputSection *IS) { +// Add IS to the output section. +// If Hint is provided, it will be used to keep IS. +// Overwise, a new InputSectionDescription will be added. +void OutputSection::addSection(InputSection *IS, + InputSectionDescription *Hint) { if (!Live) { // If IS is the first section to be added to this section, // initialize Type and Entsize from IS. @@ -126,10 +130,13 @@ if (!IS->Assigned) { IS->Assigned = true; - if (SectionCommands.empty() || - !isa(SectionCommands.back())) - SectionCommands.push_back(make("")); - auto *ISD = cast(SectionCommands.back()); + auto ISD = Hint; + if (!ISD) { + if (SectionCommands.empty() || + !isa(SectionCommands.back())) + SectionCommands.push_back(make("")); + ISD = cast(SectionCommands.back()); + } ISD->Sections.push_back(IS); } } Index: ELF/SyntheticSections.h =================================================================== --- ELF/SyntheticSections.h +++ ELF/SyntheticSections.h @@ -784,9 +784,12 @@ class ARMExidxSentinelSection : public SyntheticSection { public: - ARMExidxSentinelSection(); + ARMExidxSentinelSection(InputSection *Highest); size_t getSize() const override { return 8; } void writeTo(uint8_t *Buf) override; + +private: + InputSection *Highest; }; // A container for one or more linker generated thunks. Instances of these Index: ELF/SyntheticSections.cpp =================================================================== --- ELF/SyntheticSections.cpp +++ ELF/SyntheticSections.cpp @@ -2556,9 +2556,10 @@ : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, Config->Wordsize, ".rld_map") {} -ARMExidxSentinelSection::ARMExidxSentinelSection() +ARMExidxSentinelSection::ARMExidxSentinelSection(InputSection *Highest) : SyntheticSection(SHF_ALLOC | SHF_LINK_ORDER, SHT_ARM_EXIDX, - Config->Wordsize, ".ARM.exidx") {} + Config->Wordsize, ".ARM.exidx"), + Highest(Highest) {} // 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. @@ -2567,23 +2568,6 @@ // 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()); 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(); @@ -1160,24 +1159,37 @@ template void Writer::resolveShfLinkOrder() { for (OutputSection *Sec : OutputSections) { - if (!(Sec->Flags & SHF_LINK_ORDER)) + if (!(Sec->Flags & SHF_LINK_ORDER) || !Sec->Live) continue; // Link order may be distributed across several InputSectionDescriptions // but sort must consider them all at once. std::vector ScriptSections; std::vector Sections; + InputSectionDescription *LastISD = nullptr; for (BaseCommand *Base : Sec->SectionCommands) { if (auto *ISD = dyn_cast(Base)) { + if (ISD->Sections.empty()) + continue; + LastISD = ISD; for (InputSection *&IS : ISD->Sections) { ScriptSections.push_back(&IS); Sections.push_back(IS); } } } + if (!LastISD) + continue; std::stable_sort(Sections.begin(), Sections.end(), compareByFilePosition); for (int I = 0, N = Sections.size(); I < N; ++I) *ScriptSections[I] = Sections[I]; + + // 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. + if (!Config->Relocatable && Sec->Name == ".ARM.exidx") { + auto *Sentinel = make(Sections.back()); + Sec->addSection(Sentinel, LastISD); + } } } @@ -1331,7 +1343,6 @@ if (errorCount()) return; - addPredefinedSections(); removeUnusedSyntheticSections(); sortSections(); @@ -1427,17 +1438,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/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 @@ -7,7 +7,8 @@ ## We used to crash if the last output section command for .ARM.exidx ## was anything but an input section description. # RUN: ld.lld -T %t.script %t.o -shared -o %t.so -# RUN: llvm-objdump -s -triple=armv7a-none-linux-gnueabi %t.so | FileCheck %s +# 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: -// 1000 + 1000 = 0x2000 = _start -// 1008 + 0ffc = 0x2004 = _start + sizeof(_start) -// CHECK-NEXT: 1000 00100000 01000000 fc0f0000 01000000 +# DUMP: Contents of section .ARM.exidx: +# 1000 + 1000 = 0x2000 = _start +# 1008 + 0ffc = 0x2004 = _start + sizeof(_start) +# 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