Index: lld/trunk/ELF/Relocations.cpp =================================================================== --- lld/trunk/ELF/Relocations.cpp +++ lld/trunk/ELF/Relocations.cpp @@ -1263,7 +1263,7 @@ // Check existing Thunks for Sym to see if they can be reused for (Thunk *ET : *ThunkVec) if (ET->isCompatibleWith(Type) && - Target->inBranchRange(Type, Src, ET->ThunkSym->getVA())) + Target->inBranchRange(Type, Src, ET->getThunkTargetSym()->getVA())) return std::make_pair(ET, false); // No existing compatible Thunk in range, create a new one Thunk *T = addThunk(Type, Sym); @@ -1358,7 +1358,6 @@ bool IsNew; 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()) @@ -1366,13 +1365,18 @@ else TS = getISDThunkSec(OS, IS, ISD, Rel.Type, Src); TS->addThunk(T); - Thunks[T->ThunkSym] = T; + Thunks[T->getThunkTargetSym()] = T; } // Redirect relocation to Thunk, we never go via the PLT to a Thunk - Rel.Sym = T->ThunkSym; + Rel.Sym = T->getThunkTargetSym(); Rel.Expr = fromPlt(Rel.Expr); } + for (auto &P : ISD->ThunkSections) + AddressesChanged |= P.first->assignOffsets(); }); + for (auto &P : ThunkedSections) + AddressesChanged |= P.second->assignOffsets(); + // Merge all created synthetic ThunkSections back into OutputSection mergeThunks(OutputSections); ++Pass; Index: lld/trunk/ELF/SyntheticSections.h =================================================================== --- lld/trunk/ELF/SyntheticSections.h +++ lld/trunk/ELF/SyntheticSections.h @@ -30,6 +30,7 @@ namespace lld { namespace elf { +class Defined; class SharedSymbol; class SyntheticSection : public InputSection { @@ -823,6 +824,7 @@ size_t getSize() const override { return Size; } void writeTo(uint8_t *Buf) override; InputSection *getTargetInputSection() const; + bool assignOffsets(); private: std::vector Thunks; @@ -834,8 +836,8 @@ void decompressSections(); void mergeSections(); -Symbol *addSyntheticLocal(StringRef Name, uint8_t Type, uint64_t Value, - uint64_t Size, InputSectionBase &Section); +Defined *addSyntheticLocal(StringRef Name, uint8_t Type, uint64_t Value, + uint64_t Size, InputSectionBase &Section); // Linker generated sections which can be used as inputs. struct InX { Index: lld/trunk/ELF/SyntheticSections.cpp =================================================================== --- lld/trunk/ELF/SyntheticSections.cpp +++ lld/trunk/ELF/SyntheticSections.cpp @@ -264,8 +264,8 @@ return Sec; } -Symbol *elf::addSyntheticLocal(StringRef Name, uint8_t Type, uint64_t Value, - uint64_t Size, InputSectionBase &Section) { +Defined *elf::addSyntheticLocal(StringRef Name, uint8_t Type, uint64_t Value, + uint64_t Size, InputSectionBase &Section) { auto *S = make(Section.File, Name, STB_LOCAL, STV_DEFAULT, Type, Value, Size, &Section); if (InX::SymTab) @@ -2621,11 +2621,8 @@ } void ThunkSection::addThunk(Thunk *T) { - uint64_t Off = alignTo(Size, T->Alignment); - T->Offset = Off; Thunks.push_back(T); T->addSymbols(*this); - Size = Off + T->size(); } void ThunkSection::writeTo(uint8_t *Buf) { @@ -2640,6 +2637,20 @@ return T->getTargetInputSection(); } +bool ThunkSection::assignOffsets() { + uint64_t Off = 0; + for (Thunk *T : Thunks) { + Off = alignTo(Off, T->Alignment); + T->setOffset(Off); + uint32_t Size = T->size(); + T->getThunkTargetSym()->Size = Size; + Off += Size; + } + bool Changed = Off != Size; + Size = Off; + return Changed; +} + InputSection *InX::ARMAttributes; BssSection *InX::Bss; BssSection *InX::BssRelRo; Index: lld/trunk/ELF/Thunks.h =================================================================== --- lld/trunk/ELF/Thunks.h +++ lld/trunk/ELF/Thunks.h @@ -14,6 +14,7 @@ namespace lld { namespace elf { +class Defined; class Symbol; class ThunkSection; // Class to describe an instance of a Thunk. @@ -33,10 +34,15 @@ virtual uint32_t size() = 0; virtual void writeTo(uint8_t *Buf) = 0; - // All Thunks must define at least one symbol ThunkSym so that we can - // redirect relocations to it. + // All Thunks must define at least one symbol, known as the thunk target + // symbol, so that we can redirect relocations to it. The thunk may define + // additional symbols, but these are never targets for relocations. virtual void addSymbols(ThunkSection &IS) = 0; + void setOffset(uint64_t Offset); + Defined *addSymbol(StringRef Name, uint8_t Type, uint64_t Value, + InputSectionBase &Section); + // Some Thunks must be placed immediately before their Target as they elide // a branch and fall through to the first Symbol in the Target. virtual InputSection *getTargetInputSection() const { return nullptr; } @@ -45,10 +51,12 @@ // compatible with it. virtual bool isCompatibleWith(RelType Type) const { return true; } + Defined *getThunkTargetSym() const { return Syms[0]; } + // The alignment requirement for this Thunk, defaults to the size of the // typical code section alignment. Symbol &Destination; - Symbol *ThunkSym; + llvm::SmallVector Syms; uint64_t Offset = 0; uint32_t Alignment = 4; }; Index: lld/trunk/ELF/Thunks.cpp =================================================================== --- lld/trunk/ELF/Thunks.cpp +++ lld/trunk/ELF/Thunks.cpp @@ -141,6 +141,19 @@ } // end anonymous namespace +Defined *Thunk::addSymbol(StringRef Name, uint8_t Type, uint64_t Value, + InputSectionBase &Section) { + Defined *D = addSyntheticLocal(Name, Type, Value, /*Size=*/0, Section); + Syms.push_back(D); + return D; +} + +void Thunk::setOffset(uint64_t NewOffset) { + for (Defined *D : Syms) + D->Value = D->Value - Offset + NewOffset; + Offset = NewOffset; +} + // AArch64 long range Thunks static uint64_t getAArch64ThunkDestVA(const Symbol &S) { @@ -161,11 +174,10 @@ } void AArch64ABSLongThunk::addSymbols(ThunkSection &IS) { - ThunkSym = addSyntheticLocal( - Saver.save("__AArch64AbsLongThunk_" + Destination.getName()), STT_FUNC, - Offset, size(), IS); - addSyntheticLocal("$x", STT_NOTYPE, Offset, 0, IS); - addSyntheticLocal("$d", STT_NOTYPE, Offset + 8, 0, IS); + addSymbol(Saver.save("__AArch64AbsLongThunk_" + Destination.getName()), + STT_FUNC, 0, IS); + addSymbol("$x", STT_NOTYPE, 0, IS); + addSymbol("$d", STT_NOTYPE, 8, IS); } // This Thunk has a maximum range of 4Gb, this is sufficient for all programs @@ -180,19 +192,17 @@ 0x00, 0x02, 0x1f, 0xd6, // br x16 }; uint64_t S = getAArch64ThunkDestVA(Destination); - uint64_t P = ThunkSym->getVA(); + uint64_t P = getThunkTargetSym()->getVA(); memcpy(Buf, Data, sizeof(Data)); Target->relocateOne(Buf, R_AARCH64_ADR_PREL_PG_HI21, getAArch64Page(S) - getAArch64Page(P)); Target->relocateOne(Buf + 4, R_AARCH64_ADD_ABS_LO12_NC, S); } -void AArch64ADRPThunk::addSymbols(ThunkSection &IS) -{ - ThunkSym = addSyntheticLocal( - Saver.save("__AArch64ADRPThunk_" + Destination.getName()), STT_FUNC, - Offset, size(), IS); - addSyntheticLocal("$x", STT_NOTYPE, Offset, 0, IS); +void AArch64ADRPThunk::addSymbols(ThunkSection &IS) { + addSymbol(Saver.save("__AArch64ADRPThunk_" + Destination.getName()), STT_FUNC, + 0, IS); + addSymbol("$x", STT_NOTYPE, 0, IS); } // ARM Target Thunks @@ -214,10 +224,9 @@ } void ARMV7ABSLongThunk::addSymbols(ThunkSection &IS) { - ThunkSym = addSyntheticLocal( - Saver.save("__ARMv7ABSLongThunk_" + Destination.getName()), STT_FUNC, - Offset, size(), IS); - addSyntheticLocal("$a", STT_NOTYPE, Offset, 0, IS); + addSymbol(Saver.save("__ARMv7ABSLongThunk_" + Destination.getName()), + STT_FUNC, 0, IS); + addSymbol("$a", STT_NOTYPE, 0, IS); } bool ARMV7ABSLongThunk::isCompatibleWith(RelType Type) const { @@ -238,10 +247,9 @@ } void ThumbV7ABSLongThunk::addSymbols(ThunkSection &IS) { - ThunkSym = addSyntheticLocal( - Saver.save("__Thumbv7ABSLongThunk_" + Destination.getName()), STT_FUNC, - Offset | 0x1, size(), IS); - addSyntheticLocal("$t", STT_NOTYPE, Offset, 0, IS); + addSymbol(Saver.save("__Thumbv7ABSLongThunk_" + Destination.getName()), + STT_FUNC, 1, IS); + addSymbol("$t", STT_NOTYPE, 0, IS); } bool ThumbV7ABSLongThunk::isCompatibleWith(RelType Type) const { @@ -257,7 +265,7 @@ 0x1c, 0xff, 0x2f, 0xe1, // bx r12 }; uint64_t S = getARMThunkDestVA(Destination); - uint64_t P = ThunkSym->getVA(); + uint64_t P = getThunkTargetSym()->getVA(); uint64_t Offset = S - P - 16; memcpy(Buf, Data, sizeof(Data)); Target->relocateOne(Buf, R_ARM_MOVW_PREL_NC, Offset); @@ -265,10 +273,9 @@ } void ARMV7PILongThunk::addSymbols(ThunkSection &IS) { - ThunkSym = addSyntheticLocal( - Saver.save("__ARMV7PILongThunk_" + Destination.getName()), STT_FUNC, - Offset, size(), IS); - addSyntheticLocal("$a", STT_NOTYPE, Offset, 0, IS); + addSymbol(Saver.save("__ARMV7PILongThunk_" + Destination.getName()), STT_FUNC, + 0, IS); + addSymbol("$a", STT_NOTYPE, 0, IS); } bool ARMV7PILongThunk::isCompatibleWith(RelType Type) const { @@ -284,7 +291,7 @@ 0x60, 0x47, // bx r12 }; uint64_t S = getARMThunkDestVA(Destination); - uint64_t P = ThunkSym->getVA() & ~0x1; + uint64_t P = getThunkTargetSym()->getVA() & ~0x1; uint64_t Offset = S - P - 12; memcpy(Buf, Data, sizeof(Data)); Target->relocateOne(Buf, R_ARM_THM_MOVW_PREL_NC, Offset); @@ -292,10 +299,9 @@ } void ThumbV7PILongThunk::addSymbols(ThunkSection &IS) { - ThunkSym = addSyntheticLocal( - Saver.save("__ThumbV7PILongThunk_" + Destination.getName()), STT_FUNC, - Offset | 0x1, size(), IS); - addSyntheticLocal("$t", STT_NOTYPE, Offset, 0, IS); + addSymbol(Saver.save("__ThumbV7PILongThunk_" + Destination.getName()), + STT_FUNC, 1, IS); + addSymbol("$t", STT_NOTYPE, 0, IS); } bool ThumbV7PILongThunk::isCompatibleWith(RelType Type) const { @@ -315,9 +321,8 @@ } void MipsThunk::addSymbols(ThunkSection &IS) { - ThunkSym = - addSyntheticLocal(Saver.save("__LA25Thunk_" + Destination.getName()), - STT_FUNC, Offset, size(), IS); + addSymbol(Saver.save("__LA25Thunk_" + Destination.getName()), STT_FUNC, 0, + IS); } InputSection *MipsThunk::getTargetInputSection() const { @@ -339,10 +344,9 @@ } void MicroMipsThunk::addSymbols(ThunkSection &IS) { - ThunkSym = - addSyntheticLocal(Saver.save("__microLA25Thunk_" + Destination.getName()), - STT_FUNC, Offset, size(), IS); - ThunkSym->StOther |= STO_MIPS_MICROMIPS; + Defined *D = addSymbol( + Saver.save("__microLA25Thunk_" + Destination.getName()), STT_FUNC, 0, IS); + D->StOther |= STO_MIPS_MICROMIPS; } InputSection *MicroMipsThunk::getTargetInputSection() const { @@ -354,7 +358,7 @@ // to call PIC function from the non-PIC one. void MicroMipsR6Thunk::writeTo(uint8_t *Buf) { uint64_t S = Destination.getVA() | 1; - uint64_t P = ThunkSym->getVA(); + uint64_t P = getThunkTargetSym()->getVA(); write16(Buf, 0x1320); // lui $25, %hi(func) write16(Buf + 4, 0x3339); // addiu $25, $25, %lo(func) write16(Buf + 8, 0x9400); // bc func @@ -364,10 +368,9 @@ } void MicroMipsR6Thunk::addSymbols(ThunkSection &IS) { - ThunkSym = - addSyntheticLocal(Saver.save("__microLA25Thunk_" + Destination.getName()), - STT_FUNC, Offset, size(), IS); - ThunkSym->StOther |= STO_MIPS_MICROMIPS; + Defined *D = addSymbol( + Saver.save("__microLA25Thunk_" + Destination.getName()), STT_FUNC, 0, IS); + D->StOther |= STO_MIPS_MICROMIPS; } InputSection *MicroMipsR6Thunk::getTargetInputSection() const {