Index: ELF/LinkerScript.h =================================================================== --- ELF/LinkerScript.h +++ ELF/LinkerScript.h @@ -258,6 +258,8 @@ std::vector *OutputSections; void fabricateDefaultCommands(); + std::vector *> + inputSectionRanges(OutputSection* OS); void addOrphanSections(OutputSectionFactory &Factory); void removeEmptyCommands(); void adjustSectionsBeforeSorting(); Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ ELF/LinkerScript.cpp @@ -480,6 +480,22 @@ 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(OutputSection *OS) { + std::vector *> Ranges; + OutputSectionCommand *OutCmd = getCmd(OS); + if (!OutCmd) + return Ranges; + 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) { for (InputSectionBase *S : InputSections) { Index: ELF/SyntheticSections.cpp =================================================================== --- ELF/SyntheticSections.cpp +++ ELF/SyntheticSections.cpp @@ -2181,13 +2181,29 @@ // 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) { - // Get the InputSection before us, we are by definition last - auto RI = this->OutSec->Sections.rbegin(); - InputSection *LE = *(++RI); - InputSection *LC = cast(LE->getLinkOrderDep()); - uint64_t S = LC->OutSec->Addr + LC->getOffset(LC->getSize()); - uint64_t P = this->getVA(); + uint64_t S = 0; + uint64_t P = getVA(); + InputSection *Highest = nullptr; + std::vector *> Ranges = + Script->inputSectionRanges(OutSec); + // The Sections are sorted in order of ascending PREL31 address with the + // sentinel last. We need to find the InputSection that precedes the + // sentinel, this may not be in the same Range. + for (auto Range = Ranges.rbegin(); Range != Ranges.rend(); ++Range) { + auto NonSentinel = std::find_if( + (*Range)->rbegin(), (*Range)->rend(), + [](InputSection *IS) { return !isa(IS); }); + if (NonSentinel != (*Range)->rend()) { + Highest = *NonSentinel; + break; + } + } + assert(Highest != nullptr); + InputSection *LS = cast(Highest->getLinkOrderDep()); + S = std::max(S, LS->OutSec->Addr + LS->getOffset(LS->getSize())); Target->relocateOne(Buf, R_ARM_PREL31, S - P); write32le(Buf + 4, 0x1); }