Index: ELF/Relocations.h =================================================================== --- ELF/Relocations.h +++ ELF/Relocations.h @@ -148,6 +148,8 @@ uint64_t Src); ThunkSection *addThunkSection(OutputSection *OS, std::vector *, uint64_t Off); + bool normalizeExistingThunk(Relocation &Rel, uint64_t Src); + // Record all the available Thunks for a Symbol llvm::DenseMap> ThunkedSymbols; @@ -161,12 +163,16 @@ // The Mips LA25 Thunk is an example of an inline ThunkSection. llvm::DenseMap ThunkedSections; - // All the ThunkSections that we have created, organised by OutputSection + // All the ThunkSections that we have created, organised by InputSectionRange // will contain a mix of ThunkSections that have been created this pass, and - // ThunkSections that have been merged into the OutputSection on previous + // ThunkSections that have been merged into InputSectionRanges on previous // passes std::map *, std::vector> ThunkSections; + + // All the ThunkSections that we have created, organised by InputSectionRange + std::map *, std::vector> + NewThunkSections; }; // Return a int64_t to make sure we get the sign extension out of the way as Index: ELF/Relocations.cpp =================================================================== --- ELF/Relocations.cpp +++ ELF/Relocations.cpp @@ -969,7 +969,7 @@ // offsets. // This may invalidate any output section offsets stored outside of InputSection void ThunkCreator::mergeThunks() { - for (auto &KV : ThunkSections) { + for (auto &KV : NewThunkSections) { std::vector *ISR = KV.first; std::vector &Thunks = KV.second; @@ -995,12 +995,18 @@ // std::merge requires a strict weak ordering. if (A->OutSecOff < B->OutSecOff) return true; - if (A->OutSecOff == B->OutSecOff) + if (A->OutSecOff == B->OutSecOff) { + auto *TA = dyn_cast(A); + auto *TB = dyn_cast(B); // Check if Thunk is immediately before any specific Target InputSection // for example Mips LA25 Thunks. - if (auto *TA = dyn_cast(A)) - if (TA && TA->getTargetInputSection() == B) - return true; + if (TA && TA->getTargetInputSection() == B) + return true; + else if (TA && !TB && !TA->getTargetInputSection()) + // In general place Thunk Sections without specific targets before + // non-Thunk Sections + return true; + } return false; }; std::merge(ISR->begin(), ISR->end(), Thunks.begin(), Thunks.end(), @@ -1100,6 +1106,7 @@ uint64_t Off) { auto *TS = make(OS, Off); ThunkSections[ISR].push_back(TS); + NewThunkSections[ISR].push_back(TS); return TS; } @@ -1139,6 +1146,19 @@ } } +// If this Relocation is using a Thunk, use it if it hasn't gone out +// of range. If it has we revert back to the original Target. +bool ThunkCreator::normalizeExistingThunk(Relocation &Rel, uint64_t Src) { + if (Thunk *ET = Thunks.lookup(Rel.Sym)) { + if (Target->inBranchRange(Rel.Type, Src, Rel.Sym->getVA())) + return true; + Rel.Sym = &ET->Destination; + if (Rel.Sym->isInPlt()) + Rel.Expr = toPlt(Rel.Expr); + } + return false; +} + // Process all relocations from the InputSections that have been assigned // to OutputSections and redirect through Thunks if needed. // @@ -1146,13 +1166,16 @@ // each InputSection. It must be called before the static symbol table is // finalized. If any Thunks are added to an OutputSection the output section // offsets of the InputSections will change. -// -// FIXME: Initial support for RangeThunks, only one pass supported bool ThunkCreator::createThunks( ArrayRef OutputSections) { - if (Pass > 0) - ThunkSections.clear(); - else if (Target->ThunkSectionSpacing) + bool AddressesChanged = false; + if (Pass > 0) { + NewThunkSections.clear(); + // With Thunk Size much smaller than branch range we expect to + // converge quickly, if we get to 10 something has gone wrong. + if (Pass == 10) + fatal("Thunk creation not converged"); + } else if (Target->ThunkSectionSpacing) createInitialThunkSections(OutputSections); // Create all the Thunks and insert them into synthetic ThunkSections. The @@ -1162,18 +1185,23 @@ // ThunkSections back into the OutputSection as ThunkSections are not always // inserted into the same OutputSection as the caller. forEachExecInputSection( - OutputSections, [&](OutputSection *OS, std::vector *ISR, + OutputSections, [&](OutputSection *OS, std::vector *ISR, InputSection *IS) { for (Relocation &Rel : IS->Relocations) { - SymbolBody &Body = *Rel.Sym; uint64_t Src = OS->Addr + IS->OutSecOff + Rel.Offset; - if (Thunks.find(&Body) != Thunks.end() || - !Target->needsThunk(Rel.Expr, Rel.Type, IS->File, Src, Body)) + + // If relocation to a valid existing Thunk, use it, if invalid Thunk + // redirect relocation to original target + if (Pass > 0 && normalizeExistingThunk(Rel, Src)) + continue; + + if (!Target->needsThunk(Rel.Expr, Rel.Type, IS->File, Src, *Rel.Sym)) continue; Thunk *T; bool IsNew; - std::tie(T, IsNew) = getThunk(Body, Rel.Type, Src); + std::tie(T, IsNew) = getThunk(*Rel.Sym, Rel.Type, Src); if (IsNew) { + AddressesChanged = true; // Find or create a ThunkSection for the new Thunk ThunkSection *TS; if (auto *TIS = T->getTargetInputSection()) @@ -1191,7 +1219,7 @@ // Merge all created synthetic ThunkSections back into OutputSection mergeThunks(); ++Pass; - return !ThunkSections.empty(); + return AddressesChanged; } template void elf::scanRelocations(InputSectionBase &); Index: ELF/Thunks.h =================================================================== --- ELF/Thunks.h +++ ELF/Thunks.h @@ -27,7 +27,7 @@ // Thunks are assigned to synthetic ThunkSections class Thunk { public: - Thunk(const SymbolBody &Destination); + Thunk(SymbolBody &Destination); virtual ~Thunk(); virtual uint32_t size() const { return 0; } @@ -47,7 +47,7 @@ // The alignment requirement for this Thunk, defaults to the size of the // typical code section alignment. - const SymbolBody &Destination; + SymbolBody &Destination; SymbolBody *ThunkSym; uint64_t Offset; uint32_t alignment = 4; Index: ELF/Thunks.cpp =================================================================== --- ELF/Thunks.cpp +++ ELF/Thunks.cpp @@ -52,7 +52,7 @@ // Source State, TargetState, Target Requirement, ABS or PI, Range class ARMV7ABSLongThunk final : public Thunk { public: - ARMV7ABSLongThunk(const SymbolBody &Dest) : Thunk(Dest) {} + ARMV7ABSLongThunk(SymbolBody &Dest) : Thunk(Dest) {} uint32_t size() const override { return 12; } void writeTo(uint8_t *Buf, ThunkSection &IS) const override; @@ -62,7 +62,7 @@ class ARMV7PILongThunk final : public Thunk { public: - ARMV7PILongThunk(const SymbolBody &Dest) : Thunk(Dest) {} + ARMV7PILongThunk(SymbolBody &Dest) : Thunk(Dest) {} uint32_t size() const override { return 16; } void writeTo(uint8_t *Buf, ThunkSection &IS) const override; @@ -72,7 +72,7 @@ class ThumbV7ABSLongThunk final : public Thunk { public: - ThumbV7ABSLongThunk(const SymbolBody &Dest) : Thunk(Dest) { + ThumbV7ABSLongThunk(SymbolBody &Dest) : Thunk(Dest) { alignment = 2; } @@ -84,7 +84,7 @@ class ThumbV7PILongThunk final : public Thunk { public: - ThumbV7PILongThunk(const SymbolBody &Dest) : Thunk(Dest) { + ThumbV7PILongThunk(SymbolBody &Dest) : Thunk(Dest) { alignment = 2; } @@ -97,7 +97,7 @@ // MIPS LA25 thunk class MipsThunk final : public Thunk { public: - MipsThunk(const SymbolBody &Dest) : Thunk(Dest) {} + MipsThunk(SymbolBody &Dest) : Thunk(Dest) {} uint32_t size() const override { return 16; } void writeTo(uint8_t *Buf, ThunkSection &IS) const override; @@ -237,7 +237,7 @@ return dyn_cast(DR->Section); } -Thunk::Thunk(const SymbolBody &D) : Destination(D), Offset(0) {} +Thunk::Thunk(SymbolBody &D) : Destination(D), Offset(0) {} Thunk::~Thunk() = default; Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -1308,12 +1308,10 @@ // when no more Thunks are added ThunkCreator TC; Script->assignAddresses(); - if (TC.createThunks(OutputSectionCommands)) { + while (TC.createThunks(OutputSectionCommands)) { applySynthetic({InX::MipsGot}, [](SyntheticSection *SS) { SS->updateAllocSize(); }); Script->assignAddresses(); - if (TC.createThunks(OutputSectionCommands)) - fatal("All non-range thunks should be created in first call"); } }