forked from OSchip/llvm-project
ELF: Allow thunks to change size. NFCI.
Differential Revision: https://reviews.llvm.org/D44962 llvm-svn: 328841
This commit is contained in:
parent
4778bb88ef
commit
c5391ce51e
|
@ -1263,7 +1263,7 @@ std::pair<Thunk *, bool> ThunkCreator::getThunk(Symbol &Sym, RelType Type,
|
|||
// 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 ThunkCreator::createThunks(ArrayRef<OutputSection *> OutputSections) {
|
|||
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 @@ bool ThunkCreator::createThunks(ArrayRef<OutputSection *> OutputSections) {
|
|||
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;
|
||||
|
|
|
@ -264,8 +264,8 @@ InputSection *elf::createInterpSection() {
|
|||
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<Defined>(Section.File, Name, STB_LOCAL, STV_DEFAULT, Type,
|
||||
Value, Size, &Section);
|
||||
if (InX::SymTab)
|
||||
|
@ -2621,11 +2621,8 @@ ThunkSection::ThunkSection(OutputSection *OS, uint64_t Off)
|
|||
}
|
||||
|
||||
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 @@ InputSection *ThunkSection::getTargetInputSection() const {
|
|||
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;
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
|
||||
namespace lld {
|
||||
namespace elf {
|
||||
class Defined;
|
||||
class SharedSymbol;
|
||||
|
||||
class SyntheticSection : public InputSection {
|
||||
|
@ -823,6 +824,7 @@ public:
|
|||
size_t getSize() const override { return Size; }
|
||||
void writeTo(uint8_t *Buf) override;
|
||||
InputSection *getTargetInputSection() const;
|
||||
bool assignOffsets();
|
||||
|
||||
private:
|
||||
std::vector<Thunk *> Thunks;
|
||||
|
@ -834,8 +836,8 @@ MergeInputSection *createCommentSection();
|
|||
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 {
|
||||
|
|
|
@ -141,6 +141,19 @@ public:
|
|||
|
||||
} // 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::writeTo(uint8_t *Buf) {
|
|||
}
|
||||
|
||||
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 @@ void AArch64ADRPThunk::writeTo(uint8_t *Buf) {
|
|||
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::writeTo(uint8_t *Buf) {
|
|||
}
|
||||
|
||||
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::writeTo(uint8_t *Buf) {
|
|||
}
|
||||
|
||||
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 @@ void ARMV7PILongThunk::writeTo(uint8_t *Buf) {
|
|||
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::writeTo(uint8_t *Buf) {
|
|||
}
|
||||
|
||||
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 @@ void ThumbV7PILongThunk::writeTo(uint8_t *Buf) {
|
|||
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::writeTo(uint8_t *Buf) {
|
|||
}
|
||||
|
||||
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::writeTo(uint8_t *Buf) {
|
|||
}
|
||||
|
||||
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::writeTo(uint8_t *Buf) {
|
|||
}
|
||||
|
||||
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 @@ InputSection *MicroMipsThunk::getTargetInputSection() const {
|
|||
// 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::writeTo(uint8_t *Buf) {
|
|||
}
|
||||
|
||||
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 {
|
||||
|
|
|
@ -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 @@ public:
|
|||
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 @@ public:
|
|||
// 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<Defined *, 3> Syms;
|
||||
uint64_t Offset = 0;
|
||||
uint32_t Alignment = 4;
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue