diff options
Diffstat (limited to 'lld/ELF/Relocations.cpp')
-rw-r--r-- | lld/ELF/Relocations.cpp | 140 |
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> &); |