Skip to content

Commit

Permalink
ELF: Allow thunks to change size. NFCI.
Browse files Browse the repository at this point in the history
Differential Revision: https://reviews.llvm.org/D44962

llvm-svn: 328841
  • Loading branch information
pcc committed Mar 29, 2018
1 parent 4778bb8 commit c5391ce
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 56 deletions.
12 changes: 8 additions & 4 deletions lld/ELF/Relocations.cpp
Expand Up @@ -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);
Expand Down Expand Up @@ -1358,21 +1358,25 @@ 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())
TS = getISThunkSec(TIS);
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;
Expand Down
21 changes: 16 additions & 5 deletions lld/ELF/SyntheticSections.cpp
Expand Up @@ -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)
Expand Down Expand Up @@ -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) {
Expand All @@ -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;
Expand Down
6 changes: 4 additions & 2 deletions lld/ELF/SyntheticSections.h
Expand Up @@ -30,6 +30,7 @@

namespace lld {
namespace elf {
class Defined;
class SharedSymbol;

class SyntheticSection : public InputSection {
Expand Down Expand Up @@ -823,6 +824,7 @@ class ThunkSection : public SyntheticSection {
size_t getSize() const override { return Size; }
void writeTo(uint8_t *Buf) override;
InputSection *getTargetInputSection() const;
bool assignOffsets();

private:
std::vector<Thunk *> Thunks;
Expand All @@ -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 {
Expand Down
87 changes: 45 additions & 42 deletions lld/ELF/Thunks.cpp
Expand Up @@ -141,6 +141,19 @@ class MicroMipsR6Thunk final : public Thunk {

} // 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) {
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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 {
Expand All @@ -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 {
Expand All @@ -257,18 +265,17 @@ 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);
Target->relocateOne(Buf + 4, R_ARM_MOVT_PREL, Offset);
}

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 {
Expand All @@ -284,18 +291,17 @@ 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);
Target->relocateOne(Buf + 4, R_ARM_THM_MOVT_PREL, Offset);
}

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 {
Expand All @@ -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 {
Expand All @@ -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 {
Expand All @@ -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
Expand All @@ -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 {
Expand Down
14 changes: 11 additions & 3 deletions lld/ELF/Thunks.h
Expand Up @@ -14,6 +14,7 @@

namespace lld {
namespace elf {
class Defined;
class Symbol;
class ThunkSection;
// Class to describe an instance of a Thunk.
Expand All @@ -33,10 +34,15 @@ class Thunk {
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; }
Expand All @@ -45,10 +51,12 @@ class Thunk {
// 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;
};
Expand Down

0 comments on commit c5391ce

Please sign in to comment.