summaryrefslogtreecommitdiffstats
path: root/lld/ELF/Relocations.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lld/ELF/Relocations.cpp')
-rw-r--r--lld/ELF/Relocations.cpp140
1 files changed, 25 insertions, 115 deletions
diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp
index 4d2ff37d803..4e370a4f595 100644
--- a/lld/ELF/Relocations.cpp
+++ b/lld/ELF/Relocations.cpp
@@ -43,7 +43,6 @@
#include "Relocations.h"
#include "Config.h"
-#include "Memory.h"
#include "OutputSections.h"
#include "Strings.h"
#include "SymbolTable.h"
@@ -53,7 +52,6 @@
#include "llvm/Support/Endian.h"
#include "llvm/Support/raw_ostream.h"
-#include <algorithm>
using namespace llvm;
using namespace llvm::ELF;
@@ -302,14 +300,16 @@ template <class ELFT> static bool isAbsoluteValue(const SymbolBody &Body) {
}
static bool needsPlt(RelExpr Expr) {
- return isRelExprOneOf<R_PLT_PC, R_PPC_PLT_OPD, R_PLT, R_PLT_PAGE_PC>(Expr);
+ return isRelExprOneOf<R_PLT_PC, R_PPC_PLT_OPD, R_PLT, R_PLT_PAGE_PC,
+ R_THUNK_PLT_PC>(Expr);
}
// True if this expression is of the form Sym - X, where X is a position in the
// file (PC, or GOT for example).
static bool isRelExpr(RelExpr Expr) {
return isRelExprOneOf<R_PC, R_GOTREL, R_GOTREL_FROM_END, R_MIPS_GOTREL,
- R_PAGE_PC, R_RELAX_GOT_PC>(Expr);
+ R_PAGE_PC, R_RELAX_GOT_PC, R_THUNK_PC, R_THUNK_PLT_PC>(
+ Expr);
}
template <class ELFT>
@@ -321,7 +321,8 @@ static bool isStaticLinkTimeConstant(RelExpr E, uint32_t Type,
if (isRelExprOneOf<R_SIZE, R_GOT_FROM_END, R_GOT_OFF, R_MIPS_GOT_LOCAL_PAGE,
R_MIPS_GOT_OFF, R_MIPS_GOT_OFF32, R_MIPS_TLSGD,
R_GOT_PAGE_PC, R_GOT_PC, R_PLT_PC, R_TLSGD_PC, R_TLSGD,
- R_PPC_PLT_OPD, R_TLSDESC_CALL, R_TLSDESC_PAGE, R_HINT>(E))
+ R_PPC_PLT_OPD, R_TLSDESC_CALL, R_TLSDESC_PAGE, R_HINT,
+ R_THUNK_PC, R_THUNK_PLT_PC>(E))
return true;
// These never do, except if the entire file is position dependent or if
@@ -466,6 +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);
if (IsWrite || isStaticLinkTimeConstant<ELFT>(Expr, Type, Body, S, RelOff))
return Expr;
@@ -683,6 +685,7 @@ static void scanRelocs(InputSectionBase<ELFT> &C, ArrayRef<RelTy> Rels) {
continue;
if (needsPlt(Expr) ||
+ isRelExprOneOf<R_THUNK_ABS, R_THUNK_PC, R_THUNK_PLT_PC>(Expr) ||
refersToGotEntry(Expr) || !isPreemptible(Body, Type)) {
// If the relocation points to something in the file, we can process it.
bool Constant =
@@ -802,126 +805,33 @@ template <class ELFT> void scanRelocations(InputSectionBase<ELFT> &S) {
scanRelocs(S, S.rels());
}
-// Insert the Thunks for OutputSection OS into their designated place
-// in the Sections vector, and recalculate the InputSection output section
-// offsets.
-// This may invalidate any output section offsets stored outside of InputSection
-template <class ELFT>
-static void mergeThunks(OutputSection<ELFT> *OS,
- std::vector<ThunkSection<ELFT> *> &Thunks) {
- // Order Thunks in ascending OutSecOff
- auto ThunkCmp = [](const ThunkSection<ELFT> *A, const ThunkSection<ELFT> *B) {
- return A->OutSecOff < B->OutSecOff;
- };
- std::stable_sort(Thunks.begin(), Thunks.end(), ThunkCmp);
-
- // Merge sorted vectors of Thunks and InputSections by OutSecOff
- std::vector<InputSection<ELFT> *> Tmp;
- Tmp.reserve(OS->Sections.size() + Thunks.size());
- auto MergeCmp = [](const ThunkSection<ELFT> *Thunk,
- const InputSection<ELFT> *IS) {
- // All thunks go before any non-executable InputSections
- if ((IS->Flags & SHF_EXECINSTR) == 0)
- return true;
- // Some Thunk Sections such as the Mips LA25 thunk must be placed before
- // the InputSections that they target. We represent this by assigning the
- // ThunkSection the same OutSecOff and always placing the Thunk first if
- // the OutSecOff values are the same.
- return Thunk->OutSecOff <= IS->OutSecOff;
- };
- std::merge(OS->Sections.begin(), OS->Sections.end(), Thunks.begin(),
- Thunks.end(), std::back_inserter(Tmp), MergeCmp);
- OS->Sections = std::move(Tmp);
- OS->Size = 0;
- OS->assignOffsets();
-}
-
-// Process all relocations from the InputSections that have been assigned
-// to OutputSections and redirect through Thunks if needed.
-//
-// createThunks must be called after scanRelocs has created the Relocations for
-// 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: All Thunks are assumed to be in range of the relocation. Range
-// extension Thunks are not yet supported.
template <class ELFT>
void createThunks(ArrayRef<OutputSectionBase *> OutputSections) {
- // Track Symbols that already have a Thunk
- DenseMap<SymbolBody *, Thunk<ELFT> *> ThunkedSymbols;
- // Track InputSections that have a ThunkSection placed in front
- DenseMap<InputSection<ELFT> *, ThunkSection<ELFT> *> ThunkedSections;
- // Track the ThunksSections that need to be inserted into an OutputSection
- std::map<OutputSection<ELFT> *, std::vector<ThunkSection<ELFT> *>>
- ThunkSections;
-
- // Find or create a Thunk for Body for relocation Type
- auto GetThunk = [&](SymbolBody &Body, uint32_t Type) {
- auto res = ThunkedSymbols.insert({&Body, nullptr});
- if (res.second == true)
- res.first->second = addThunk<ELFT>(Type, Body);
- return std::make_pair(res.first->second, res.second);
- };
-
- // Find or create a ThunkSection to be placed immediately before IS
- auto GetISThunkSec = [&](InputSection<ELFT> *IS, OutputSection<ELFT> *OS) {
- ThunkSection<ELFT> *TS = ThunkedSections.lookup(IS);
- if (TS)
- return TS;
- auto *TOS = cast<OutputSection<ELFT>>(IS->OutSec);
- TS = make<ThunkSection<ELFT>>(TOS, IS->OutSecOff);
- ThunkSections[OS].push_back(TS);
- ThunkedSections[IS] = TS;
- return TS;
- };
- // Find or create a ThunkSection to be placed at the end of OS
- auto GetOSThunkSec = [&](ThunkSection<ELFT> *&TS, OutputSection<ELFT> *OS) {
- if (TS == nullptr) {
- TS = make<ThunkSection<ELFT>>(OS, OS->Size);
- ThunkSections[OS].push_back(TS);
- }
- return TS;
- };
- // Create all the Thunks and insert them into synthetic ThunkSections. The
- // ThunkSections are later inserted back into the OutputSection.
-
- // We separate the creation of ThunkSections from the insertion of the
- // ThunkSections back into the OutputSection as ThunkSections are not always
- // inserted into the same OutputSection as the caller.
for (OutputSectionBase *Base : OutputSections) {
auto *OS = dyn_cast<OutputSection<ELFT>>(Base);
if (OS == nullptr)
continue;
-
- ThunkSection<ELFT> *OSTS = nullptr;
for (InputSection<ELFT> *IS : OS->Sections) {
- for (Relocation &Rel : IS->Relocations) {
- SymbolBody &Body = *Rel.Sym;
- if (Target->needsThunk(Rel.Expr, Rel.Type, IS->getFile(), Body)) {
- Thunk<ELFT> *T;
- bool IsNew;
- std::tie(T, IsNew) = GetThunk(Body, Rel.Type);
- if (IsNew) {
- // Find or create a ThunkSection for the new Thunk
- ThunkSection<ELFT> *TS;
- if (auto *TIS = T->getTargetInputSection())
- TS = GetISThunkSec(TIS, OS);
- else
- TS = GetOSThunkSec(OSTS, OS);
- TS->addThunk(T);
- }
- // Redirect relocation to Thunk, we never go via the PLT to a Thunk
- Rel.Sym = T->ThunkSym;
- Rel.Expr = fromPlt(Rel.Expr);
- }
+ for (const Relocation &Rel : IS->Relocations) {
+ if (Rel.Sym == nullptr)
+ continue;
+ RelExpr Expr = Rel.Expr;
+ // 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>(Rel.Type, *Rel.Sym, *IS);
}
}
}
-
- // Merge all created synthetic ThunkSections back into OutputSection
- for (auto &KV : ThunkSections)
- mergeThunks<ELFT>(KV.first, KV.second);
+ // 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> &);
OpenPOWER on IntegriCloud