Index: ELF/OutputSections.cpp =================================================================== --- ELF/OutputSections.cpp +++ ELF/OutputSections.cpp @@ -181,8 +181,24 @@ this->Entsize = getEntsize(Type); } +template +static bool compareByFilePosition(InputSection *A, + InputSection *B) { + auto *LA = cast>(A->getLinkOrderDep()); + auto *LB = cast>(B->getLinkOrderDep()); + OutputSectionBase *AOut = LA->OutSec; + OutputSectionBase *BOut = LB->OutSec; + if (AOut != BOut) + return AOut->SectionIndex < BOut->SectionIndex; + return LA->OutSecOff < LB->OutSecOff; +} + template void OutputSection::finalize() { if ((this->Flags & SHF_LINK_ORDER) && !this->Sections.empty()) { + std::sort(Sections.begin(), Sections.end(), compareByFilePosition); + Size = 0; + assignOffsets(); + // 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/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -1478,61 +1478,6 @@ Sec->writeTo(Buf + Sec->Offset); } -// Convert the .ARM.exidx table entries that use relative PREL31 offsets to -// Absolute addresses. This form is internal to LLD and is only used to -// make reordering the table simpler. -static void ARMExidxEntryPrelToAbs(uint8_t *Loc, uint64_t EntryVA) { - uint64_t Addr = Target->getImplicitAddend(Loc, R_ARM_PREL31) + EntryVA; - bool InlineEntry = - (read32le(Loc + 4) == 1 || (read32le(Loc + 4) & 0x80000000)); - if (InlineEntry) - // Set flag in unused bit of code address so that when we convert back we - // know which table entries to leave alone. - Addr |= 0x1; - else - write32le(Loc + 4, - Target->getImplicitAddend(Loc + 4, R_ARM_PREL31) + EntryVA + 4); - write32le(Loc, Addr); -} - -// Convert the .ARM.exidx table entries from the internal to LLD form using -// absolute addresses back to relative PREL31 offsets. -static void ARMExidxEntryAbsToPrel(uint8_t *Loc, uint64_t EntryVA) { - uint64_t Off = read32le(Loc) - EntryVA; - // ARMExidxEntryPreltoAbs sets bit 0 if the table entry has inline data - // that is not an address - bool InlineEntry = Off & 0x1; - Target->relocateOne(Loc, R_ARM_PREL31, Off & ~0x1); - if (!InlineEntry) - Target->relocateOne(Loc + 4, R_ARM_PREL31, - read32le(Loc + 4) - (EntryVA + 4)); -} - -// The table formed by the .ARM.exidx OutputSection has entries with two -// 4-byte fields: -// | PREL31 offset to function | Action to take for function | -// The table must be ordered in ascending virtual address of the functions -// identified by the first field of the table. Instead of using the -// SHF_LINK_ORDER dependency to reorder the sections prior to relocation we -// sort the table post-relocation. -// Ref: Exception handling ABI for the ARM architecture -static void sortARMExidx(uint8_t *Buf, uint64_t OutSecVA, uint64_t Size) { - struct ARMExidxEntry { - ulittle32_t Target; - ulittle32_t Action; - }; - ARMExidxEntry *Start = (ARMExidxEntry *)Buf; - size_t NumEnt = Size / sizeof(ARMExidxEntry); - for (uint64_t Off = 0; Off < Size; Off += 8) - ARMExidxEntryPrelToAbs(Buf + Off, OutSecVA + Off); - std::stable_sort(Start, Start + NumEnt, - [](const ARMExidxEntry &A, const ARMExidxEntry &B) { - return A.Target < B.Target; - }); - for (uint64_t Off = 0; Off < Size; Off += 8) - ARMExidxEntryAbsToPrel(Buf + Off, OutSecVA + Off); -} - // Write section contents to a mmap'ed file. template void Writer::writeSections() { uint8_t *Buf = Buffer->getBufferStart(); @@ -1556,11 +1501,6 @@ if (Sec != Out::Opd && Sec != Out::EhFrameHdr) Sec->writeTo(Buf + Sec->Offset); - OutputSectionBase *ARMExidx = findSection(".ARM.exidx"); - if (!Config->Relocatable) - if (auto *OS = dyn_cast_or_null>(ARMExidx)) - sortARMExidx(Buf + OS->Offset, OS->Addr, OS->Size); - // The .eh_frame_hdr depends on .eh_frame section contents, therefore // it should be written after .eh_frame is written. if (!Out::EhFrame->empty() && Out::EhFrameHdr)