Skip to content

Commit

Permalink
[ELF] Move createThunks() after scanRelocations()
Browse files Browse the repository at this point in the history
    
A necessary first step towards range extension thunks is to delay
the creation of thunks until the layout of InputSections within
OutputSections has been done.
    
The change scans the relocations directly from InputSections rather
than looking in the ELF File the InputSection came from. This will
allow a future change to redirect the relocations to symbols defined
by Thunks rather than indirect when resolving relocations.
    
A side-effect of moving ThunkCreation is that the OutSecOff of
InputSections may change in an OutputSection that contains Thunks.
In well behaved programs thunks are not in OutputSections with
dynamic relocations.
    
Differential Revision: https://reviews.llvm.org/D28811

llvm-svn: 292359
  • Loading branch information
smithp35 committed Jan 18, 2017
1 parent 0c0240c commit ee6d718
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 44 deletions.
63 changes: 35 additions & 28 deletions lld/ELF/Relocations.cpp
Expand Up @@ -467,7 +467,7 @@ static RelExpr adjustExpr(const elf::ObjectFile<ELFT> &File, SymbolBody &Body,
if (Expr == R_GOT_PC && !isAbsoluteValue<ELFT>(Body))
Expr = Target->adjustRelaxExpr(Type, Data, Expr);
}
Expr = Target->getThunkExpr(Expr, Type, File, Body);
Expr = Target->getThunkExpr(Expr, Type, &File, Body);

if (IsWrite || isStaticLinkTimeConstant<ELFT>(Expr, Type, Body, S, RelOff))
return Expr;
Expand Down Expand Up @@ -805,41 +805,48 @@ template <class ELFT> void scanRelocations(InputSectionBase<ELFT> &S) {
scanRelocs(S, S.rels());
}

template <class ELFT, class RelTy>
static void createThunks(InputSectionBase<ELFT> &C, ArrayRef<RelTy> Rels) {
const elf::ObjectFile<ELFT> *File = C.getFile();
for (const RelTy &Rel : Rels) {
SymbolBody &Body = File->getRelocTargetSym(Rel);
uint32_t Type = Rel.getType(Config->Mips64EL);
RelExpr Expr = Target->getRelExpr(Type, Body);
if (!isPreemptible(Body, Type) && needsPlt(Expr))
Expr = fromPlt(Expr);
Expr = Target->getThunkExpr(Expr, Type, *File, Body);
// Some targets might require creation of thunks for relocations.
// Now we support only MIPS which requires LA25 thunk to call PIC
// code from non-PIC one, and ARM which requires interworking.
if (Expr == R_THUNK_ABS || Expr == R_THUNK_PC || Expr == R_THUNK_PLT_PC) {
auto *Sec = cast<InputSection<ELFT>>(&C);
addThunk<ELFT>(Type, Body, *Sec);
template <class ELFT>
void createThunks(ArrayRef<OutputSectionBase *> OutputSections) {
for (OutputSectionBase *Base : OutputSections) {
if (auto *OS = dyn_cast<OutputSection<ELFT>>(Base)) {
for (InputSection<ELFT> *IS : OS->Sections) {
for (const Relocation &Rel : IS->Relocations) {
if (Rel.Sym == nullptr) {
continue;
}
SymbolBody &Body = *Rel.Sym;
uint32_t Type = Rel.Type;
RelExpr Expr = Rel.Expr;
if (!isPreemptible(Body, Type) && needsPlt(Expr))
Expr = fromPlt(Expr);
Expr = Target->getThunkExpr(Expr, Type, IS->getFile(), Body);
// Some targets might require creation of thunks for relocations.
// Now we support only MIPS which requires LA25 thunk to call PIC
// code from non-PIC one, and ARM which requires interworking.
if (Expr == R_THUNK_ABS || Expr == R_THUNK_PC ||
Expr == R_THUNK_PLT_PC)
addThunk<ELFT>(Type, Body, *IS);
}
}
}
}
}

template <class ELFT> void createThunks(InputSectionBase<ELFT> &S) {
if (S.AreRelocsRela)
createThunks(S, S.relas());
else
createThunks(S, S.rels());
// Added thunks may affect the output section offset
for (OutputSectionBase *Base : OutputSections)
if (auto *OS = dyn_cast<OutputSection<ELFT>>(Base))
if (OS->Type == SHT_PROGBITS) {
OS->Size = 0;
OS->assignOffsets();
}
}

template void scanRelocations<ELF32LE>(InputSectionBase<ELF32LE> &);
template void scanRelocations<ELF32BE>(InputSectionBase<ELF32BE> &);
template void scanRelocations<ELF64LE>(InputSectionBase<ELF64LE> &);
template void scanRelocations<ELF64BE>(InputSectionBase<ELF64BE> &);

template void createThunks<ELF32LE>(InputSectionBase<ELF32LE> &);
template void createThunks<ELF32BE>(InputSectionBase<ELF32BE> &);
template void createThunks<ELF64LE>(InputSectionBase<ELF64LE> &);
template void createThunks<ELF64BE>(InputSectionBase<ELF64BE> &);
template void createThunks<ELF32LE>(ArrayRef<OutputSectionBase *>);
template void createThunks<ELF32BE>(ArrayRef<OutputSectionBase *>);
template void createThunks<ELF64LE>(ArrayRef<OutputSectionBase *>);
template void createThunks<ELF64BE>(ArrayRef<OutputSectionBase *>);
}
}
4 changes: 3 additions & 1 deletion lld/ELF/Relocations.h
Expand Up @@ -18,6 +18,7 @@ class SymbolBody;
class InputSectionData;
template <class ELFT> class InputSection;
template <class ELFT> class InputSectionBase;
class OutputSectionBase;

// List of target-independent relocation types. Relocations read
// from files are converted to these types so that the main code
Expand Down Expand Up @@ -113,7 +114,8 @@ struct Relocation {

template <class ELFT> void scanRelocations(InputSectionBase<ELFT> &);

template <class ELFT> void createThunks(InputSectionBase<ELFT> &);
template <class ELFT>
void createThunks(ArrayRef<OutputSectionBase *> OutputSections);

template <class ELFT>
static inline typename ELFT::uint getAddend(const typename ELFT::Rel &Rel) {
Expand Down
16 changes: 8 additions & 8 deletions lld/ELF/Target.cpp
Expand Up @@ -223,7 +223,7 @@ class ARMTargetInfo final : public TargetInfo {
void writePltHeader(uint8_t *Buf) const override;
void writePlt(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr,
int32_t Index, unsigned RelOff) const override;
RelExpr getThunkExpr(RelExpr Expr, uint32_t RelocType, const InputFile &File,
RelExpr getThunkExpr(RelExpr Expr, uint32_t RelocType, const InputFile *File,
const SymbolBody &S) const override;
void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
};
Expand All @@ -241,7 +241,7 @@ template <class ELFT> class MipsTargetInfo final : public TargetInfo {
void writePltHeader(uint8_t *Buf) const override;
void writePlt(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr,
int32_t Index, unsigned RelOff) const override;
RelExpr getThunkExpr(RelExpr Expr, uint32_t RelocType, const InputFile &File,
RelExpr getThunkExpr(RelExpr Expr, uint32_t RelocType, const InputFile *File,
const SymbolBody &S) const override;
void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
bool usesOnlyLowPageBits(uint32_t Type) const override;
Expand Down Expand Up @@ -294,7 +294,7 @@ uint64_t TargetInfo::getImplicitAddend(const uint8_t *Buf,
bool TargetInfo::usesOnlyLowPageBits(uint32_t Type) const { return false; }

RelExpr TargetInfo::getThunkExpr(RelExpr Expr, uint32_t RelocType,
const InputFile &File,
const InputFile *File,
const SymbolBody &S) const {
return Expr;
}
Expand Down Expand Up @@ -1749,13 +1749,13 @@ void ARMTargetInfo::writePlt(uint8_t *Buf, uint64_t GotEntryAddr,
}

RelExpr ARMTargetInfo::getThunkExpr(RelExpr Expr, uint32_t RelocType,
const InputFile &File,
const InputFile *File,
const SymbolBody &S) const {
// If S is an undefined weak symbol in an executable we don't need a Thunk.
// In a DSO calls to undefined symbols, including weak ones get PLT entries
// which may need a thunk.
if (S.isUndefined() && !S.isLocal() && S.symbol()->isWeak()
&& !Config->Shared)
if (S.isUndefined() && !S.isLocal() && S.symbol()->isWeak() &&
!Config->Shared)
return Expr;
// A state change from ARM to Thumb and vice versa must go through an
// interworking thunk if the relocation type is not R_ARM_CALL or
Expand Down Expand Up @@ -2193,7 +2193,7 @@ void MipsTargetInfo<ELFT>::writePlt(uint8_t *Buf, uint64_t GotEntryAddr,

template <class ELFT>
RelExpr MipsTargetInfo<ELFT>::getThunkExpr(RelExpr Expr, uint32_t Type,
const InputFile &File,
const InputFile *File,
const SymbolBody &S) const {
// Any MIPS PIC code function is invoked with its address in register $t9.
// So if we have a branch instruction from non-PIC code to the PIC one
Expand All @@ -2202,7 +2202,7 @@ RelExpr MipsTargetInfo<ELFT>::getThunkExpr(RelExpr Expr, uint32_t Type,
// See page 3-38 ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
if (Type != R_MIPS_26)
return Expr;
auto *F = dyn_cast<ELFFileBase<ELFT>>(&File);
auto *F = dyn_cast_or_null<ELFFileBase<ELFT>>(File);
if (!F)
return Expr;
// If current file has PIC code, LA25 stub is not required.
Expand Down
2 changes: 1 addition & 1 deletion lld/ELF/Target.h
Expand Up @@ -56,7 +56,7 @@ class TargetInfo {
// R_THUNK_PC if thunk is required and expression is pc rel
// R_THUNK_PLT_PC if thunk is required to PLT entry and expression is pc rel
virtual RelExpr getThunkExpr(RelExpr Expr, uint32_t RelocType,
const InputFile &File,
const InputFile *File,
const SymbolBody &S) const;
virtual RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const = 0;
virtual void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const = 0;
Expand Down
12 changes: 6 additions & 6 deletions lld/ELF/Writer.cpp
Expand Up @@ -158,12 +158,6 @@ template <class ELFT> void Writer<ELFT>::run() {
if (!Config->Relocatable)
addReservedSymbols();

// Some architectures use small displacements for jump instructions.
// It is linker's responsibility to create thunks containing long
// jump instructions if jump targets are too far. Create thunks.
if (Target->NeedsThunks)
forEachRelSec(createThunks<ELFT>);

// Create output sections.
Script<ELFT>::X->OutputSections = &OutputSections;
if (ScriptConfig->HasSections) {
Expand Down Expand Up @@ -1088,6 +1082,12 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
fixHeaders();
}

// Some architectures use small displacements for jump instructions.
// It is linker's responsibility to create thunks containing long
// jump instructions if jump targets are too far. Create thunks.
if (Target->NeedsThunks)
createThunks<ELFT>(OutputSections);

// Fill other section headers. The dynamic table is finalized
// at the end because some tags like RELSZ depend on result
// of finalizing other sections.
Expand Down

0 comments on commit ee6d718

Please sign in to comment.