diff options
| -rw-r--r-- | lld/ELF/InputFiles.cpp | 2 | ||||
| -rw-r--r-- | lld/ELF/InputSection.cpp | 37 | ||||
| -rw-r--r-- | lld/ELF/InputSection.h | 13 | ||||
| -rw-r--r-- | lld/ELF/LTO.cpp | 15 | ||||
| -rw-r--r-- | lld/ELF/LTO.h | 2 | ||||
| -rw-r--r-- | lld/ELF/Relocations.cpp | 140 | ||||
| -rw-r--r-- | lld/ELF/Relocations.h | 3 | ||||
| -rw-r--r-- | lld/ELF/SymbolTable.cpp | 6 | ||||
| -rw-r--r-- | lld/ELF/Symbols.cpp | 38 | ||||
| -rw-r--r-- | lld/ELF/Symbols.h | 20 | ||||
| -rw-r--r-- | lld/ELF/SyntheticSections.cpp | 26 | ||||
| -rw-r--r-- | lld/ELF/SyntheticSections.h | 20 | ||||
| -rw-r--r-- | lld/ELF/Target.cpp | 47 | ||||
| -rw-r--r-- | lld/ELF/Target.h | 15 | ||||
| -rw-r--r-- | lld/ELF/Thunks.cpp | 178 | ||||
| -rw-r--r-- | lld/ELF/Thunks.h | 38 | ||||
| -rw-r--r-- | lld/ELF/Writer.cpp | 12 | ||||
| -rw-r--r-- | lld/test/ELF/arm-thumb-interwork-shared.s | 7 | ||||
| -rw-r--r-- | lld/test/ELF/arm-thumb-interwork-thunk.s | 185 | ||||
| -rw-r--r-- | lld/test/ELF/mips-npic-call-pic.s | 169 |
20 files changed, 509 insertions, 464 deletions
diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp index 6bfc49baabf..1e66f51ca8c 100644 --- a/lld/ELF/InputFiles.cpp +++ b/lld/ELF/InputFiles.cpp @@ -488,7 +488,7 @@ SymbolBody *elf::ObjectFile<ELFT>::createSymbolBody(const Elf_Sym *Sym) { StringRefZ Name = this->StringTable.data() + Sym->st_name; if (Sym->st_shndx == SHN_UNDEF) return new (BAlloc) - Undefined<ELFT>(Name, /*IsLocal=*/true, StOther, Type, this); + Undefined(Name, /*IsLocal=*/true, StOther, Type, this); return new (BAlloc) DefinedRegular<ELFT>(Name, /*IsLocal=*/true, StOther, Type, Value, Size, Sec, this); diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp index 7503767ada9..f8115a6eb4a 100644 --- a/lld/ELF/InputSection.cpp +++ b/lld/ELF/InputSection.cpp @@ -99,10 +99,6 @@ template <class ELFT> size_t InputSectionBase<ELFT>::getSize() const { if (auto *S = dyn_cast<SyntheticSection<ELFT>>(this)) return S->getSize(); - if (auto *D = dyn_cast<InputSection<ELFT>>(this)) - if (D->getThunksSize() > 0) - return D->getThunkOff() + D->getThunksSize(); - return Data.size(); } @@ -214,21 +210,6 @@ InputSectionBase<ELFT> *InputSection<ELFT>::getRelocatedSection() { return Sections[this->Info]; } -template <class ELFT> void InputSection<ELFT>::addThunk(const Thunk<ELFT> *T) { - Thunks.push_back(T); -} - -template <class ELFT> uint64_t InputSection<ELFT>::getThunkOff() const { - return this->Data.size(); -} - -template <class ELFT> uint64_t InputSection<ELFT>::getThunksSize() const { - uint64_t Total = 0; - for (const Thunk<ELFT> *T : Thunks) - Total += T->size(); - return Total; -} - // This is used for -r. We can't use memcpy to copy relocations because we need // to update symbol table offset and section index for each relocation. So we // copy relocations one by one. @@ -302,11 +283,6 @@ getRelocTargetVA(uint32_t Type, typename ELFT::uint A, typename ELFT::uint P, return In<ELFT>::Got->getTlsIndexOff() + A - In<ELFT>::Got->getSize(); case R_TLSLD_PC: return In<ELFT>::Got->getTlsIndexVA() + A - P; - case R_THUNK_ABS: - return Body.getThunkVA<ELFT>() + A; - case R_THUNK_PC: - case R_THUNK_PLT_PC: - return Body.getThunkVA<ELFT>() + A - P; case R_PPC_TOC: return getPPC64TocBase() + A; case R_TLSGD: @@ -551,19 +527,6 @@ template <class ELFT> void InputSection<ELFT>::writeTo(uint8_t *Buf) { // Iterate over all relocation sections that apply to this section. uint8_t *BufEnd = Buf + OutSecOff + Data.size(); this->relocate(Buf, BufEnd); - - // The section might have a data/code generated by the linker and need - // to be written after the section. Usually these are thunks - small piece - // of code used to jump between "incompatible" functions like PIC and non-PIC - // or if the jump target too far and its address does not fit to the short - // jump istruction. - if (!Thunks.empty()) { - Buf += OutSecOff + getThunkOff(); - for (const Thunk<ELFT> *T : Thunks) { - T->writeTo(Buf); - Buf += T->size(); - } - } } template <class ELFT> diff --git a/lld/ELF/InputSection.h b/lld/ELF/InputSection.h index 3f3a055dcc3..7b098265d7d 100644 --- a/lld/ELF/InputSection.h +++ b/lld/ELF/InputSection.h @@ -280,17 +280,6 @@ public: InputSectionBase<ELFT> *getRelocatedSection(); - // Register thunk related to the symbol. When the section is written - // to a mmap'ed file, target is requested to write an actual thunk code. - // Now thunks is supported for MIPS and ARM target only. - void addThunk(const Thunk<ELFT> *T); - - // The offset of synthetic thunk code from beginning of this section. - uint64_t getThunkOff() const; - - // Size of chunk with thunks code. - uint64_t getThunksSize() const; - template <class RelTy> void relocateNonAlloc(uint8_t *Buf, llvm::ArrayRef<RelTy> Rels); @@ -303,8 +292,6 @@ public: private: template <class RelTy> void copyRelocations(uint8_t *Buf, llvm::ArrayRef<RelTy> Rels); - - llvm::TinyPtrVector<const Thunk<ELFT> *> Thunks; }; template <class ELFT> InputSection<ELFT> InputSection<ELFT>::Discarded; diff --git a/lld/ELF/LTO.cpp b/lld/ELF/LTO.cpp index 2eb7bc6c296..7aaddcfb674 100644 --- a/lld/ELF/LTO.cpp +++ b/lld/ELF/LTO.cpp @@ -96,12 +96,12 @@ BitcodeCompiler::BitcodeCompiler() : LTOObj(createLTO()) {} BitcodeCompiler::~BitcodeCompiler() = default; -template <class ELFT> static void undefine(Symbol *S) { - replaceBody<Undefined<ELFT>>(S, S->body()->getName(), /*IsLocal=*/false, - STV_DEFAULT, S->body()->Type, nullptr); +static void undefine(Symbol *S) { + replaceBody<Undefined>(S, S->body()->getName(), /*IsLocal=*/false, + STV_DEFAULT, S->body()->Type, nullptr); } -template <class ELFT> void BitcodeCompiler::add(BitcodeFile &F) { +void BitcodeCompiler::add(BitcodeFile &F) { lto::InputFile &Obj = *F.Obj; unsigned SymNum = 0; std::vector<Symbol *> Syms = F.getSymbols(); @@ -126,7 +126,7 @@ template <class ELFT> void BitcodeCompiler::add(BitcodeFile &F) { R.VisibleToRegularObj = Sym->IsUsedInRegularObj || (R.Prevailing && Sym->includeInDynsym()); if (R.Prevailing) - undefine<ELFT>(Sym); + undefine(Sym); } checkError(LTOObj->add(std::move(F.Obj), Resols)); } @@ -157,8 +157,3 @@ std::vector<InputFile *> BitcodeCompiler::compile() { } return Ret; } - -template void BitcodeCompiler::template add<ELF32LE>(BitcodeFile &); -template void BitcodeCompiler::template add<ELF32BE>(BitcodeFile &); -template void BitcodeCompiler::template add<ELF64LE>(BitcodeFile &); -template void BitcodeCompiler::template add<ELF64BE>(BitcodeFile &); diff --git a/lld/ELF/LTO.h b/lld/ELF/LTO.h index 3cb763650e1..b3d734f2d38 100644 --- a/lld/ELF/LTO.h +++ b/lld/ELF/LTO.h @@ -43,7 +43,7 @@ public: BitcodeCompiler(); ~BitcodeCompiler(); - template <class ELFT> void add(BitcodeFile &F); + void add(BitcodeFile &F); std::vector<InputFile *> compile(); private: diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp index a57996fccae..a14cff6fe3b 100644 --- a/lld/ELF/Relocations.cpp +++ b/lld/ELF/Relocations.cpp @@ -43,6 +43,7 @@ #include "Relocations.h" #include "Config.h" +#include "Memory.h" #include "OutputSections.h" #include "Strings.h" #include "SymbolTable.h" @@ -52,6 +53,7 @@ #include "llvm/Support/Endian.h" #include "llvm/Support/raw_ostream.h" +#include <algorithm> using namespace llvm; using namespace llvm::ELF; @@ -300,16 +302,14 @@ 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, - R_THUNK_PLT_PC>(Expr); + return isRelExprOneOf<R_PLT_PC, R_PPC_PLT_OPD, R_PLT, R_PLT_PAGE_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, R_THUNK_PC, R_THUNK_PLT_PC>( - Expr); + R_PAGE_PC, R_RELAX_GOT_PC>(Expr); } template <class ELFT> @@ -321,8 +321,7 @@ 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, - R_THUNK_PC, R_THUNK_PLT_PC>(E)) + R_PPC_PLT_OPD, R_TLSDESC_CALL, R_TLSDESC_PAGE, R_HINT>(E)) return true; // These never do, except if the entire file is position dependent or if @@ -467,7 +466,6 @@ 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; @@ -685,7 +683,6 @@ 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 = @@ -805,33 +802,126 @@ 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 (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); + 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); + } } } } - // 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(); - } + + // Merge all created synthetic ThunkSections back into OutputSection + for (auto &KV : ThunkSections) + mergeThunks<ELFT>(KV.first, KV.second); } template void scanRelocations<ELF32LE>(InputSectionBase<ELF32LE> &); diff --git a/lld/ELF/Relocations.h b/lld/ELF/Relocations.h index 161ce7484fc..2671b1e5886 100644 --- a/lld/ELF/Relocations.h +++ b/lld/ELF/Relocations.h @@ -61,9 +61,6 @@ enum RelExpr { R_RELAX_TLS_IE_TO_LE, R_RELAX_TLS_LD_TO_LE, R_SIZE, - R_THUNK_ABS, - R_THUNK_PC, - R_THUNK_PLT_PC, R_TLS, R_TLSDESC, R_TLSDESC_PAGE, diff --git a/lld/ELF/SymbolTable.cpp b/lld/ELF/SymbolTable.cpp index ce257933c26..1f23f1f59f4 100644 --- a/lld/ELF/SymbolTable.cpp +++ b/lld/ELF/SymbolTable.cpp @@ -115,7 +115,7 @@ template <class ELFT> void SymbolTable<ELFT>::addCombinedLTOObject() { // Compile bitcode files and replace bitcode symbols. LTO.reset(new BitcodeCompiler); for (BitcodeFile *F : BitcodeFiles) - LTO->add<ELFT>(*F); + LTO->add(*F); for (InputFile *File : LTO->compile()) { ObjectFile<ELFT> *Obj = cast<ObjectFile<ELFT>>(File); @@ -256,7 +256,7 @@ Symbol *SymbolTable<ELFT>::addUndefined(StringRef Name, bool IsLocal, insert(Name, Type, getVisibility(StOther), CanOmitFromDynSym, File); if (WasInserted) { S->Binding = Binding; - replaceBody<Undefined<ELFT>>(S, Name, IsLocal, StOther, Type, File); + replaceBody<Undefined>(S, Name, IsLocal, StOther, Type, File); return S; } if (Binding != STB_WEAK) { @@ -428,7 +428,7 @@ void SymbolTable<ELFT>::addShared(SharedFile<ELFT> *F, StringRef Name, // Make sure we preempt DSO symbols with default visibility. if (Sym.getVisibility() == STV_DEFAULT) S->ExportDynamic = true; - if (WasInserted || isa<Undefined<ELFT>>(S->body())) { + if (WasInserted || isa<Undefined>(S->body())) { replaceBody<SharedSymbol<ELFT>>(S, F, Name, Sym, Verdef); if (!S->isWeak()) F->IsUsed = true; diff --git a/lld/ELF/Symbols.cpp b/lld/ELF/Symbols.cpp index 43af44ec4b8..46d865ce815 100644 --- a/lld/ELF/Symbols.cpp +++ b/lld/ELF/Symbols.cpp @@ -132,14 +132,6 @@ bool SymbolBody::isPreemptible() const { return true; } -template <class ELFT> bool SymbolBody::hasThunk() const { - if (auto *DR = dyn_cast<DefinedRegular<ELFT>>(this)) - return DR->ThunkData != nullptr; - if (auto *S = dyn_cast<SharedSymbol<ELFT>>(this)) - return S->ThunkData != nullptr; - return false; -} - template <class ELFT> typename ELFT::uint SymbolBody::getVA(typename ELFT::uint Addend) const { typename ELFT::uint OutVA = getSymVA<ELFT>(*this, Addend); @@ -171,16 +163,6 @@ template <class ELFT> typename ELFT::uint SymbolBody::getPltVA() const { PltIndex * Target->PltEntrySize; } -template <class ELFT> typename ELFT::uint SymbolBody::getThunkVA() const { - if (const auto *DR = dyn_cast<DefinedRegular<ELFT>>(this)) - return DR->ThunkData->getVA(); - if (const auto *S = dyn_cast<SharedSymbol<ELFT>>(this)) - return S->ThunkData->getVA(); - if (const auto *S = dyn_cast<Undefined<ELFT>>(this)) - return S->ThunkData->getVA(); - fatal("getThunkVA() not supported for Symbol class\n"); -} - template <class ELFT> typename ELFT::uint SymbolBody::getSize() const { if (const auto *C = dyn_cast<DefinedCommon>(this)) return C->Size; @@ -241,9 +223,8 @@ template <class ELFT> bool DefinedRegular<ELFT>::isMipsPIC() const { (Section->getFile()->getObj().getHeader()->e_flags & EF_MIPS_PIC); } -template <typename ELFT> -Undefined<ELFT>::Undefined(StringRefZ Name, bool IsLocal, uint8_t StOther, - uint8_t Type, InputFile *File) +Undefined::Undefined(StringRefZ Name, bool IsLocal, uint8_t StOther, + uint8_t Type, InputFile *File) : SymbolBody(SymbolBody::UndefinedKind, Name, IsLocal, StOther, Type) { this->File = File; } @@ -338,11 +319,6 @@ std::string lld::toString(const SymbolBody &B) { return B.getName(); } -template bool SymbolBody::hasThunk<ELF32LE>() const; -template bool SymbolBody::hasThunk<ELF32BE>() const; -template bool SymbolBody::hasThunk<ELF64LE>() const; -template bool SymbolBody::hasThunk<ELF64BE>() const; - template uint32_t SymbolBody::template getVA<ELF32LE>(uint32_t) const; template uint32_t SymbolBody::template getVA<ELF32BE>(uint32_t) const; template uint64_t SymbolBody::template getVA<ELF64LE>(uint64_t) const; @@ -363,11 +339,6 @@ template uint32_t SymbolBody::template getGotPltVA<ELF32BE>() const; template uint64_t SymbolBody::template getGotPltVA<ELF64LE>() const; template uint64_t SymbolBody::template getGotPltVA<ELF64BE>() const; -template uint32_t SymbolBody::template getThunkVA<ELF32LE>() const; -template uint32_t SymbolBody::template getThunkVA<ELF32BE>() const; -template uint64_t SymbolBody::template getThunkVA<ELF64LE>() const; -template uint64_t SymbolBody::template getThunkVA<ELF64BE>() const; - template uint32_t SymbolBody::template getGotPltOffset<ELF32LE>() const; template uint32_t SymbolBody::template getGotPltOffset<ELF32BE>() const; template uint64_t SymbolBody::template getGotPltOffset<ELF64LE>() const; @@ -383,11 +354,6 @@ template uint32_t SymbolBody::template getSize<ELF32BE>() const; template uint64_t SymbolBody::template getSize<ELF64LE>() const; template uint64_t SymbolBody::template getSize<ELF64BE>() const; -template class elf::Undefined<ELF32LE>; -template class elf::Undefined<ELF32BE>; -template class elf::Undefined<ELF64LE>; -template class elf::Undefined<ELF64BE>; - template class elf::SharedSymbol<ELF32LE>; template class elf::SharedSymbol<ELF32BE>; template class elf::SharedSymbol<ELF64LE>; diff --git a/lld/ELF/Symbols.h b/lld/ELF/Symbols.h index 7acb89ad071..12f65cf1dcc 100644 --- a/lld/ELF/Symbols.h +++ b/lld/ELF/Symbols.h @@ -76,7 +76,6 @@ public: bool isInGot() const { return GotIndex != -1U; } bool isInPlt() const { return PltIndex != -1U; } - template <class ELFT> bool hasThunk() const; template <class ELFT> typename ELFT::uint getVA(typename ELFT::uint Addend = 0) const; @@ -86,7 +85,6 @@ public: template <class ELFT> typename ELFT::uint getGotPltOffset() const; template <class ELFT> typename ELFT::uint getGotPltVA() const; template <class ELFT> typename ELFT::uint getPltVA() const; - template <class ELFT> typename ELFT::uint getThunkVA() const; template <class ELFT> typename ELFT::uint getSize() const; // The file from which this symbol was created. @@ -210,10 +208,6 @@ public: // If this is null, the symbol is an absolute symbol. InputSectionBase<ELFT> *&Section; - // If non-null the symbol has a Thunk that may be used as an alternative - // destination for callers of this Symbol. - Thunk<ELFT> *ThunkData = nullptr; - private: static InputSectionBase<ELFT> *NullInputSection; }; @@ -242,7 +236,7 @@ public: const OutputSectionBase *Section; }; -template <class ELFT> class Undefined : public SymbolBody { +class Undefined : public SymbolBody { public: Undefined(StringRefZ Name, bool IsLocal, uint8_t StOther, uint8_t Type, InputFile *F); @@ -251,12 +245,6 @@ public: return S->kind() == UndefinedKind; } - // If non-null the symbol has a Thunk that may be used as an alternative - // destination for callers of this Symbol. When linking a DSO undefined - // symbols are implicitly imported, the symbol lookup will be performed by - // the dynamic loader. A call to an undefined symbol will be given a PLT - // entry and on ARM this may need a Thunk if the caller is in Thumb state. - Thunk<ELFT> *ThunkData = nullptr; InputFile *file() { return this->File; } }; @@ -291,9 +279,6 @@ public: // CopyOffset is significant only when needsCopy() is true. uintX_t CopyOffset = 0; - // If non-null the symbol has a Thunk that may be used as an alternative - // destination for callers of this Symbol. - Thunk<ELFT> *ThunkData = nullptr; bool needsCopy() const { return this->NeedsCopyOrPltAddr && !this->isFunc(); } OutputSection<ELFT> *getBssSectionForCopy() const; @@ -431,8 +416,7 @@ struct Symbol { // ELFT, and we verify this with the static_asserts in replaceBody. llvm::AlignedCharArrayUnion< DefinedCommon, DefinedRegular<llvm::object::ELF64LE>, DefinedSynthetic, - Undefined<llvm::object::ELF64LE>, SharedSymbol<llvm::object::ELF64LE>, - LazyArchive, LazyObject> + Undefined, SharedSymbol<llvm::object::ELF64LE>, LazyArchive, LazyObject> Body; SymbolBody *body() { return reinterpret_cast<SymbolBody *>(Body.buffer); } diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp index f2ead75b127..0bfe5e47bfc 100644 --- a/lld/ELF/SyntheticSections.cpp +++ b/lld/ELF/SyntheticSections.cpp @@ -1904,6 +1904,27 @@ void ARMExidxSentinelSection<ELFT>::writeTo(uint8_t *Buf) { write32le(Buf + 4, 0x1); } +template <class ELFT> +ThunkSection<ELFT>::ThunkSection(OutputSectionBase *OS, uint64_t Off) + : SyntheticSection<ELFT>(SHF_ALLOC, SHT_PROGBITS, + sizeof(typename ELFT::uint), ".text.thunk") { + this->OutSec = OS; + this->OutSecOff = Off; +} + +template <class ELFT> void ThunkSection<ELFT>::addThunk(Thunk<ELFT> *T) { + uint64_t Off = alignTo(Size, T->alignment); + T->Offset = Off; + Thunks.push_back(T); + T->addSymbols(*this); + Size = Off + T->size(); +} + +template <class ELFT> void ThunkSection<ELFT>::writeTo(uint8_t *Buf) { + for (const Thunk<ELFT> *T : Thunks) + T->writeTo(Buf + T->Offset, *this); +} + template InputSection<ELF32LE> *elf::createCommonSection(); template InputSection<ELF32BE> *elf::createCommonSection(); template InputSection<ELF64LE> *elf::createCommonSection(); @@ -2046,3 +2067,8 @@ template class elf::ARMExidxSentinelSection<ELF32LE>; template class elf::ARMExidxSentinelSection<ELF32BE>; template class elf::ARMExidxSentinelSection<ELF64LE>; template class elf::ARMExidxSentinelSection<ELF64BE>; + +template class elf::ThunkSection<ELF32LE>; +template class elf::ThunkSection<ELF32BE>; +template class elf::ThunkSection<ELF64LE>; +template class elf::ThunkSection<ELF64BE>; diff --git a/lld/ELF/SyntheticSections.h b/lld/ELF/SyntheticSections.h index 605144d77d8..e5a62955d65 100644 --- a/lld/ELF/SyntheticSections.h +++ b/lld/ELF/SyntheticSections.h @@ -699,6 +699,26 @@ public: void writeTo(uint8_t *Buf) override; }; +// A container for one or more linker generated thunks. Instances of these +// thunks including ARM interworking and Mips LA25 PI to non-PI thunks. +template <class ELFT> class ThunkSection : public SyntheticSection<ELFT> { +public: + // ThunkSection in OS, with desired OutSecOff of Off + ThunkSection(OutputSectionBase *OS, uint64_t Off); + + // Add a newly created Thunk to this container: + // Thunk is given offset from start of this InputSection + // Thunk defines a symbol in this InputSection that can be used as target + // of a relocation + void addThunk(Thunk<ELFT> *T); + size_t getSize() const override { return Size; } + void writeTo(uint8_t *Buf) override; + +private: + std::vector<const Thunk<ELFT> *> Thunks; + size_t Size = 0; +}; + template <class ELFT> InputSection<ELFT> *createCommonSection(); template <class ELFT> InputSection<ELFT> *createInterpSection(); template <class ELFT> MergeInputSection<ELFT> *createCommentSection(); diff --git a/lld/ELF/Target.cpp b/lld/ELF/Target.cpp index 85bb7f700fb..086b3ad5594 100644 --- a/lld/ELF/Target.cpp +++ b/lld/ELF/Target.cpp @@ -228,8 +228,8 @@ public: int32_t Index, unsigned RelOff) const override; void addPltSymbols(InputSectionData *IS, uint64_t Off) const override; void addPltHeaderSymbols(InputSectionData *ISD) const override; - RelExpr getThunkExpr(RelExpr Expr, uint32_t RelocType, const InputFile *File, - const SymbolBody &S) const override; + bool needsThunk(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; }; @@ -246,8 +246,8 @@ public: 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, - const SymbolBody &S) const override; + bool needsThunk(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; }; @@ -298,10 +298,9 @@ 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 SymbolBody &S) const { - return Expr; +bool TargetInfo::needsThunk(RelExpr Expr, uint32_t RelocType, + const InputFile *File, const SymbolBody &S) const { + return false; } bool TargetInfo::isTlsInitialExecRel(uint32_t Type) const { return false; } @@ -1771,15 +1770,15 @@ void ARMTargetInfo::addPltSymbols(InputSectionData *ISD, uint64_t Off) const { addSyntheticLocal("$d", STT_NOTYPE, Off + 12, 0, IS); } -RelExpr ARMTargetInfo::getThunkExpr(RelExpr Expr, uint32_t RelocType, - const InputFile *File, - const SymbolBody &S) const { +bool ARMTargetInfo::needsThunk(RelExpr Expr, uint32_t RelocType, + 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) - return Expr; + return false; // 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 // R_ARM_THM_CALL. @@ -1790,19 +1789,17 @@ RelExpr ARMTargetInfo::getThunkExpr(RelExpr Expr, uint32_t RelocType, // Source is ARM, all PLT entries are ARM so no interworking required. // Otherwise we need to interwork if Symbol has bit 0 set (Thumb). if (Expr == R_PC && ((S.getVA<ELF32LE>() & 1) == 1)) - return R_THUNK_PC; + return true; break; case R_ARM_THM_JUMP19: case R_ARM_THM_JUMP24: // Source is Thumb, all PLT entries are ARM so interworking is required. // Otherwise we need to interwork if Symbol has bit 0 clear (ARM). - if (Expr == R_PLT_PC) - return R_THUNK_PLT_PC; - if ((S.getVA<ELF32LE>() & 1) == 0) - return R_THUNK_PC; + if (Expr == R_PLT_PC || ((S.getVA<ELF32LE>() & 1) == 0)) + return true; break; } - return Expr; + return false; } void ARMTargetInfo::relocateOne(uint8_t *Loc, uint32_t Type, @@ -2215,26 +2212,26 @@ 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 SymbolBody &S) const { +bool MipsTargetInfo<ELFT>::needsThunk(RelExpr Expr, uint32_t Type, + 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 // we cannot make the jump directly and need to create a small stubs // to save the target function address. // See page 3-38 ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf if (Type != R_MIPS_26) - return Expr; + return false; auto *F = dyn_cast_or_null<ELFFileBase<ELFT>>(File); if (!F) - return Expr; + return false; // If current file has PIC code, LA25 stub is not required. if (F->getObj().getHeader()->e_flags & EF_MIPS_PIC) - return Expr; + return false; auto *D = dyn_cast<DefinedRegular<ELFT>>(&S); // LA25 is required if target file has PIC code // or target symbol is a PIC symbol. - return D && D->isMipsPIC() ? R_THUNK_ABS : Expr; + return D && D->isMipsPIC(); } template <class ELFT> diff --git a/lld/ELF/Target.h b/lld/ELF/Target.h index 76db720d4da..e439b20f852 100644 --- a/lld/ELF/Target.h +++ b/lld/ELF/Target.h @@ -41,8 +41,8 @@ public: virtual void writePlt(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const {} - virtual void addPltHeaderSymbols(InputSectionData* IS) const {} - virtual void addPltSymbols(InputSectionData* IS, uint64_t Off) const {} + virtual void addPltHeaderSymbols(InputSectionData *IS) const {} + virtual void addPltSymbols(InputSectionData *IS, uint64_t Off) const {} // Returns true if a relocation only uses the low bits of a value such that // all those bits are in in the same page. For example, if the relocation // only uses the low 12 bits in a system with 4k pages. If this is true, the @@ -51,14 +51,9 @@ public: virtual bool usesOnlyLowPageBits(uint32_t Type) const; // Decide whether a Thunk is needed for the relocation from File - // targeting S. Returns one of: - // Expr if there is no Thunk required - // R_THUNK_ABS if thunk is required and expression is absolute - // 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 SymbolBody &S) const; + // targeting S. + virtual bool needsThunk(RelExpr Expr, uint32_t RelocType, + 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; virtual ~TargetInfo(); diff --git a/lld/ELF/Thunks.cpp b/lld/ELF/Thunks.cpp index 397a0ee6631..7ba48fc7516 100644 --- a/lld/ELF/Thunks.cpp +++ b/lld/ELF/Thunks.cpp @@ -28,6 +28,7 @@ #include "Memory.h" #include "OutputSections.h" #include "Symbols.h" +#include "SyntheticSections.h" #include "Target.h" #include "llvm/Support/Casting.h" #include "llvm/Support/ELF.h" @@ -52,53 +53,54 @@ namespace { template <class ELFT> class ARMToThumbV7ABSLongThunk final : public Thunk<ELFT> { public: - ARMToThumbV7ABSLongThunk(const SymbolBody &Dest, - const InputSection<ELFT> &Owner) - : Thunk<ELFT>(Dest, Owner) {} + ARMToThumbV7ABSLongThunk(const SymbolBody &Dest) : Thunk<ELFT>(Dest) {} uint32_t size() const override { return 12; } - void writeTo(uint8_t *Buf) const override; + void writeTo(uint8_t *Buf, ThunkSection<ELFT> &IS) const override; + void addSymbols(ThunkSection<ELFT> &IS) override; }; template <class ELFT> class ARMToThumbV7PILongThunk final : public Thunk<ELFT> { public: - ARMToThumbV7PILongThunk(const SymbolBody &Dest, - const InputSection<ELFT> &Owner) - : Thunk<ELFT>(Dest, Owner) {} + ARMToThumbV7PILongThunk(const SymbolBody &Dest) : Thunk<ELFT>(Dest) {} uint32_t size() const override { return 16; } - void writeTo(uint8_t *Buf) const override; + void writeTo(uint8_t *Buf, ThunkSection<ELFT> &IS) const override; + void addSymbols(ThunkSection<ELFT> &IS) override; }; template <class ELFT> class ThumbToARMV7ABSLongThunk final : public Thunk<ELFT> { public: - ThumbToARMV7ABSLongThunk(const SymbolBody &Dest, - const InputSection<ELFT> &Owner) - : Thunk<ELFT>(Dest, Owner) {} + ThumbToARMV7ABSLongThunk(const SymbolBody &Dest) : Thunk<ELFT>(Dest) { + this->alignment = 2; + } uint32_t size() const override { return 10; } - void writeTo(uint8_t *Buf) const override; + void writeTo(uint8_t *Buf, ThunkSection<ELFT> &IS) const override; + void addSymbols(ThunkSection<ELFT> &IS) override; }; template <class ELFT> class ThumbToARMV7PILongThunk final : public Thunk<ELFT> { public: - ThumbToARMV7PILongThunk(const SymbolBody &Dest, - const InputSection<ELFT> &Owner) - : Thunk<ELFT>(Dest, Owner) {} + ThumbToARMV7PILongThunk(const SymbolBody &Dest) : Thunk<ELFT>(Dest) { + this->alignment = 2; + } uint32_t size() const override { return 12; } - void writeTo(uint8_t *Buf) const override; + void writeTo(uint8_t *Buf, ThunkSection<ELFT> &IS) const override; + void addSymbols(ThunkSection<ELFT> &IS) override; }; // MIPS LA25 thunk template <class ELFT> class MipsThunk final : public Thunk<ELFT> { public: - MipsThunk(const SymbolBody &Dest, const InputSection<ELFT> &Owner) - : Thunk<ELFT>(Dest, Owner) {} + MipsThunk(const SymbolBody &Dest) : Thunk<ELFT>(Dest) {} uint32_t size() const override { return 16; } - void writeTo(uint8_t *Buf) const override; + void writeTo(uint8_t *Buf, ThunkSection<ELFT> &IS) const override; + void addSymbols(ThunkSection<ELFT> &IS) override; + InputSection<ELFT> *getTargetInputSection() const override; }; } // end anonymous namespace @@ -110,7 +112,8 @@ template <class ELFT> static uint64_t getARMThunkDestVA(const SymbolBody &S) { } template <class ELFT> -void ARMToThumbV7ABSLongThunk<ELFT>::writeTo(uint8_t *Buf) const { +void ARMToThumbV7ABSLongThunk<ELFT>::writeTo(uint8_t *Buf, + ThunkSection<ELFT> &IS) const { const uint8_t Data[] = { 0x00, 0xc0, 0x00, 0xe3, // movw ip,:lower16:S 0x00, 0xc0, 0x40, 0xe3, // movt ip,:upper16:S @@ -123,7 +126,16 @@ void ARMToThumbV7ABSLongThunk<ELFT>::writeTo(uint8_t *Buf) const { } template <class ELFT> -void ThumbToARMV7ABSLongThunk<ELFT>::writeTo(uint8_t *Buf) const { +void ARMToThumbV7ABSLongThunk<ELFT>::addSymbols(ThunkSection<ELFT> &IS) { + this->ThunkSym = addSyntheticLocal( + Saver.save("__ARMToThumbv7ABSLongThunk_" + this->Destination.getName()), + STT_FUNC, this->Offset, size(), &IS); + addSyntheticLocal("$a", STT_NOTYPE, this->Offset, 0, &IS); +} + +template <class ELFT> +void ThumbToARMV7ABSLongThunk<ELFT>::writeTo(uint8_t *Buf, + ThunkSection<ELFT> &IS) const { const uint8_t Data[] = { 0x40, 0xf2, 0x00, 0x0c, // movw ip, :lower16:S 0xc0, 0xf2, 0x00, 0x0c, // movt ip, :upper16:S @@ -136,7 +148,16 @@ void ThumbToARMV7ABSLongThunk<ELFT>::writeTo(uint8_t *Buf) const { } template <class ELFT> -void ARMToThumbV7PILongThunk<ELFT>::writeTo(uint8_t *Buf) const { +void ThumbToARMV7ABSLongThunk<ELFT>::addSymbols(ThunkSection<ELFT> &IS) { + this->ThunkSym = addSyntheticLocal( + Saver.save("__ThumbToARMv7ABSLongThunk_" + this->Destination.getName()), + STT_FUNC, this->Offset, size(), &IS); + addSyntheticLocal("$t", STT_NOTYPE, this->Offset, 0, &IS); +} + +template <class ELFT> +void ARMToThumbV7PILongThunk<ELFT>::writeTo(uint8_t *Buf, + ThunkSection<ELFT> &IS) const { const uint8_t Data[] = { 0xf0, 0xcf, 0x0f, 0xe3, // P: movw ip,:lower16:S - (P + (L1-P) +8) 0x00, 0xc0, 0x40, 0xe3, // movt ip,:upper16:S - (P + (L1-P+4) +8) @@ -144,14 +165,23 @@ void ARMToThumbV7PILongThunk<ELFT>::writeTo(uint8_t *Buf) const { 0x1c, 0xff, 0x2f, 0xe1, // bx r12 }; uint64_t S = getARMThunkDestVA<ELFT>(this->Destination); - uint64_t P = this->getVA(); + uint64_t P = this->ThunkSym->template getVA<ELFT>(); memcpy(Buf, Data, sizeof(Data)); Target->relocateOne(Buf, R_ARM_MOVW_PREL_NC, S - P - 16); Target->relocateOne(Buf + 4, R_ARM_MOVT_PREL, S - P - 12); } template <class ELFT> -void ThumbToARMV7PILongThunk<ELFT>::writeTo(uint8_t *Buf) const { +void ARMToThumbV7PILongThunk<ELFT>::addSymbols(ThunkSection<ELFT> &IS) { + this->ThunkSym = addSyntheticLocal( + Saver.save("__ARMToThumbV7PILongThunk_" + this->Destination.getName()), + STT_FUNC, this->Offset, size(), &IS); + addSyntheticLocal("$a", STT_NOTYPE, this->Offset, 0, &IS); +} + +template <class ELFT> +void ThumbToARMV7PILongThunk<ELFT>::writeTo(uint8_t *Buf, + ThunkSection<ELFT> &IS) const { const uint8_t Data[] = { 0x4f, 0xf6, 0xf4, 0x7c, // P: movw ip,:lower16:S - (P + (L1-P) + 4) 0xc0, 0xf2, 0x00, 0x0c, // movt ip,:upper16:S - (P + (L1-P+4) + 4) @@ -159,14 +189,23 @@ void ThumbToARMV7PILongThunk<ELFT>::writeTo(uint8_t *Buf) const { 0x60, 0x47, // bx r12 }; uint64_t S = getARMThunkDestVA<ELFT>(this->Destination); - uint64_t P = this->getVA(); + uint64_t P = this->ThunkSym->template getVA<ELFT>(); memcpy(Buf, Data, sizeof(Data)); Target->relocateOne(Buf, R_ARM_THM_MOVW_PREL_NC, S - P - 12); Target->relocateOne(Buf + 4, R_ARM_THM_MOVT_PREL, S - P - 8); } +template <class ELFT> +void ThumbToARMV7PILongThunk<ELFT>::addSymbols(ThunkSection<ELFT> &IS) { + this->ThunkSym = addSyntheticLocal( + Saver.save("__ThumbToARMV7PILongThunk_" + this->Destination.getName()), + STT_FUNC, this->Offset, size(), &IS); + addSyntheticLocal("$t", STT_NOTYPE, this->Offset, 0, &IS); +} + // Write MIPS LA25 thunk code to call PIC function from the non-PIC one. -template <class ELFT> void MipsThunk<ELFT>::writeTo(uint8_t *Buf) const { +template <class ELFT> +void MipsThunk<ELFT>::writeTo(uint8_t *Buf, ThunkSection<ELFT> &) const { const endianness E = ELFT::TargetEndianness; uint64_t S = this->Destination.template getVA<ELFT>(); @@ -178,20 +217,26 @@ template <class ELFT> void MipsThunk<ELFT>::writeTo(uint8_t *Buf) const { Target->relocateOne(Buf + 8, R_MIPS_LO16, S); } -template <class ELFT> -Thunk<ELFT>::Thunk(const SymbolBody &D, const InputSection<ELFT> &O) - : Destination(D), Owner(O), Offset(O.getThunkOff() + O.getThunksSize()) {} +template <class ELFT> void MipsThunk<ELFT>::addSymbols(ThunkSection<ELFT> &IS) { + this->ThunkSym = addSyntheticLocal( + Saver.save("__LA25Thunk_" + this->Destination.getName()), STT_FUNC, + this->Offset, size(), &IS); +} -template <class ELFT> typename ELFT::uint Thunk<ELFT>::getVA() const { - return Owner.OutSec->Addr + Owner.OutSecOff + Offset; +template <class ELFT> +InputSection<ELFT> *MipsThunk<ELFT>::getTargetInputSection() const { + auto *DR = dyn_cast<DefinedRegular<ELFT>>(&this->Destination); + return dyn_cast<InputSection<ELFT>>(DR->Section); } +template <class ELFT> +Thunk<ELFT>::Thunk(const SymbolBody &D) : Destination(D), Offset(0) {} + template <class ELFT> Thunk<ELFT>::~Thunk() = default; // Creates a thunk for Thumb-ARM interworking. template <class ELFT> -static Thunk<ELFT> *createThunkArm(uint32_t Reloc, SymbolBody &S, - InputSection<ELFT> &IS) { +static Thunk<ELFT> *addThunkArm(uint32_t Reloc, SymbolBody &S) { // ARM relocations need ARM to Thumb interworking Thunks. // Thumb relocations need Thumb to ARM relocations. // Use position independent Thunks if we require position independent code. @@ -200,71 +245,34 @@ static Thunk<ELFT> *createThunkArm(uint32_t Reloc, SymbolBody &S, case R_ARM_PLT32: case R_ARM_JUMP24: if (Config->Pic) - return new (BAlloc) ARMToThumbV7PILongThunk<ELFT>(S, IS); - return new (BAlloc) ARMToThumbV7ABSLongThunk<ELFT>(S, IS); + return make<ARMToThumbV7PILongThunk<ELFT>>(S); + return make<ARMToThumbV7ABSLongThunk<ELFT>>(S); case R_ARM_THM_JUMP19: case R_ARM_THM_JUMP24: if (Config->Pic) - return new (BAlloc) ThumbToARMV7PILongThunk<ELFT>(S, IS); - return new (BAlloc) ThumbToARMV7ABSLongThunk<ELFT>(S, IS); + return make<ThumbToARMV7PILongThunk<ELFT>>(S); + return make<ThumbToARMV7ABSLongThunk<ELFT>>(S); } fatal("unrecognized relocation type"); } -template <class ELFT> -static void addThunkARM(uint32_t Reloc, SymbolBody &S, InputSection<ELFT> &IS) { - // Only one Thunk supported per symbol. - if (S.hasThunk<ELFT>()) - return; - - // ARM Thunks are added to the same InputSection as the relocation. This - // isn't strictly necessary but it makes it more likely that a limited range - // branch can reach the Thunk, and it makes Thunks to the PLT section easier - Thunk<ELFT> *T = createThunkArm(Reloc, S, IS); - IS.addThunk(T); - if (auto *Sym = dyn_cast<DefinedRegular<ELFT>>(&S)) - Sym->ThunkData = T; - else if (auto *Sym = dyn_cast<SharedSymbol<ELFT>>(&S)) - Sym->ThunkData = T; - else if (auto *Sym = dyn_cast<Undefined<ELFT>>(&S)) - Sym->ThunkData = T; - else - fatal("symbol not DefinedRegular or Shared"); -} - -template <class ELFT> -static void addThunkMips(uint32_t RelocType, SymbolBody &S, - InputSection<ELFT> &IS) { - // Only one Thunk supported per symbol. - if (S.hasThunk<ELFT>()) - return; - - // Mips Thunks are added to the InputSection defining S. - auto *R = cast<DefinedRegular<ELFT>>(&S); - auto *Sec = cast<InputSection<ELFT>>(R->Section); - auto *T = new (BAlloc) MipsThunk<ELFT>(S, *Sec); - Sec->addThunk(T); - R->ThunkData = T; +template <class ELFT> static Thunk<ELFT> *addThunkMips(SymbolBody &S) { + return make<MipsThunk<ELFT>>(S); } -template <class ELFT> -void addThunk(uint32_t RelocType, SymbolBody &S, InputSection<ELFT> &IS) { +template <class ELFT> Thunk<ELFT> *addThunk(uint32_t RelocType, SymbolBody &S) { if (Config->EMachine == EM_ARM) - addThunkARM<ELFT>(RelocType, S, IS); + return addThunkArm<ELFT>(RelocType, S); else if (Config->EMachine == EM_MIPS) - addThunkMips<ELFT>(RelocType, S, IS); - else - llvm_unreachable("add Thunk only supported for ARM and Mips"); + return addThunkMips<ELFT>(S); + llvm_unreachable("add Thunk only supported for ARM and Mips"); + return nullptr; } -template void addThunk<ELF32LE>(uint32_t, SymbolBody &, - InputSection<ELF32LE> &); -template void addThunk<ELF32BE>(uint32_t, SymbolBody &, - InputSection<ELF32BE> &); -template void addThunk<ELF64LE>(uint32_t, SymbolBody &, - InputSection<ELF64LE> &); -template void addThunk<ELF64BE>(uint32_t, SymbolBody &, - InputSection<ELF64BE> &); +template Thunk<ELF32LE> *addThunk<ELF32LE>(uint32_t, SymbolBody &); +template Thunk<ELF32BE> *addThunk<ELF32BE>(uint32_t, SymbolBody &); +template Thunk<ELF64LE> *addThunk<ELF64LE>(uint32_t, SymbolBody &); +template Thunk<ELF64BE> *addThunk<ELF64BE>(uint32_t, SymbolBody &); template class Thunk<ELF32LE>; template class Thunk<ELF32BE>; diff --git a/lld/ELF/Thunks.h b/lld/ELF/Thunks.h index b937d791849..b49f5ae393a 100644 --- a/lld/ELF/Thunks.h +++ b/lld/ELF/Thunks.h @@ -15,8 +15,8 @@ namespace lld { namespace elf { class SymbolBody; -template <class ELFT> class InputSection; - +template <class ELFT> class ThunkSection; +class OutputSectionBase; // Class to describe an instance of a Thunk. // A Thunk is a code-sequence inserted by the linker in between a caller and // the callee. The relocation to the callee is redirected to the Thunk, which @@ -24,31 +24,35 @@ template <class ELFT> class InputSection; // include transferring control from non-pi to pi and changing state on // targets like ARM. // -// Thunks can be created for DefinedRegular and Shared Symbols. The Thunk -// is stored in a field of the Symbol Destination. -// Thunks to be written to an InputSection are recorded by the InputSection. +// Thunks can be created for DefinedRegular, Shared and Undefined Symbols. +// Thunks are assigned to synthetic ThunkSections template <class ELFT> class Thunk { - typedef typename ELFT::uint uintX_t; - public: - Thunk(const SymbolBody &Destination, const InputSection<ELFT> &Owner); + Thunk(const SymbolBody &Destination); virtual ~Thunk(); virtual uint32_t size() const { return 0; } - virtual void writeTo(uint8_t *Buf) const {} - uintX_t getVA() const; + virtual void writeTo(uint8_t *Buf, ThunkSection<ELFT> &IS) const {} + + // All Thunks must define at least one symbol ThunkSym so that we can + // redirect relocations to it. + virtual void addSymbols(ThunkSection<ELFT> &IS) {} + + // 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<ELFT> *getTargetInputSection() const { return nullptr; } -protected: + // The alignment requirement for this Thunk, defaults to the size of the + // typical code section alignment. const SymbolBody &Destination; - const InputSection<ELFT> &Owner; + SymbolBody *ThunkSym; uint64_t Offset; + uint32_t alignment = 4; }; -// For a Relocation to symbol S from InputSection Src, create a Thunk and -// update the fields of S and the InputSection that the Thunk body will be -// written to. At present there are implementations for ARM and Mips Thunks. -template <class ELFT> -void addThunk(uint32_t RelocType, SymbolBody &S, InputSection<ELFT> &Src); +// For a Relocation to symbol S create a Thunk to be added to a synthetic +// ThunkSection. At present there are implementations for ARM and Mips Thunks. +template <class ELFT> Thunk<ELFT> *addThunk(uint32_t RelocType, SymbolBody &S); } // namespace elf } // namespace lld diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp index 3ed91fd51a0..6e53fbfb462 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -1027,6 +1027,12 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() { if (In<ELFT>::Iplt && !In<ELFT>::Iplt->empty()) In<ELFT>::Iplt->addSymbols(); + // 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); + // Now that we have defined all possible symbols including linker- // synthesized ones. Visit all symbols to give the finishing touches. for (Symbol *S : Symtab<ELFT>::X->getSymbols()) { @@ -1072,12 +1078,6 @@ 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. diff --git a/lld/test/ELF/arm-thumb-interwork-shared.s b/lld/test/ELF/arm-thumb-interwork-shared.s index b76aa3bb55f..ecc2a33e304 100644 --- a/lld/test/ELF/arm-thumb-interwork-shared.s +++ b/lld/test/ELF/arm-thumb-interwork-shared.s @@ -16,12 +16,15 @@ sym1: // CHECK: Disassembly of section .text: // CHECK-NEXT: sym1: -// CHECK: 1000: 00 f0 02 b8 b.w #4 -// CHECK-NEXT: 1004: 00 f0 06 b8 b.w #12 +// CHECK-NEXT: 1000: 00 f0 02 b8 b.w #4 <__ThumbToARMV7PILongThunk_elsewhere+0x4> +// CHECK-NEXT: 1004: 00 f0 06 b8 b.w #12 <__ThumbToARMV7PILongThunk_weakref+0x4> +// CHECK: __ThumbToARMV7PILongThunk_elsewhere: // CHECK-NEXT: 1008: 40 f2 20 0c movw r12, #32 // CHECK-NEXT: 100c: c0 f2 00 0c movt r12, #0 // CHECK-NEXT: 1010: fc 44 add r12, pc // CHECK-NEXT: 1012: 60 47 bx r12 + +// CHECK: __ThumbToARMV7PILongThunk_weakref: // CHECK-NEXT: 1014: 40 f2 24 0c movw r12, #36 // CHECK-NEXT: 1018: c0 f2 00 0c movt r12, #0 // CHECK-NEXT: 101c: fc 44 add r12, pc diff --git a/lld/test/ELF/arm-thumb-interwork-thunk.s b/lld/test/ELF/arm-thumb-interwork-thunk.s index 3fd36b910cd..73e475b44d6 100644 --- a/lld/test/ELF/arm-thumb-interwork-thunk.s +++ b/lld/test/ELF/arm-thumb-interwork-thunk.s @@ -78,62 +78,65 @@ arm_caller: beq arm_callee2 bne arm_callee3 bx lr -// CHECK-ABS-ARM: Disassembly of section .arm_caller: -// CHECK-ABS-ARM-NEXT: arm_caller: -// CHECK-ABS-ARM-NEXT: 1300: 3e ff ff fa blx #-776 <thumb_callee1> -// CHECK-ABS-ARM-NEXT: 1304: 3d ff ff fa blx #-780 <thumb_callee1> -// CHECK-ABS-ARM-NEXT: 1308: 06 00 00 ea b #24 <arm_caller+0x28> -// CHECK-ABS-ARM-NEXT: 130c: 05 00 00 ea b #20 <arm_caller+0x28> -// CHECK-ABS-ARM-NEXT: 1310: 07 00 00 ea b #28 <arm_caller+0x34> -// CHECK-ABS-ARM-NEXT: 1314: 09 00 00 ea b #36 <arm_caller+0x40> -// CHECK-ABS-ARM-NEXT: 1318: 78 ff ff ea b #-544 <arm_callee1> -// CHECK-ABS-ARM-NEXT: 131c: b7 00 00 0a beq #732 <arm_callee2> -// CHECK-ABS-ARM-NEXT: 1320: b7 00 00 1a bne #732 <arm_callee3> -// CHECK-ABS-ARM-NEXT: 1324: 1e ff 2f e1 bx lr +// CHECK-ARM-ABS-ARM: Disassembly of section .arm_caller: +// CHECK-ARM-ABS-ARM-NEXT: arm_caller: +// CHECK-ARM-ABS-ARM-NEXT: 1300: 3e ff ff fa blx #-776 <thumb_callee1> +// CHECK-ARM-ABS-ARM-NEXT: 1304: 3d ff ff fa blx #-780 <thumb_callee1> +// CHECK-ARM-ABS-ARM-NEXT: 1308: 06 00 00 ea b #24 <__ARMToThumbv7ABSLongThunk_thumb_callee1> +// CHECK-ARM-ABS-ARM-NEXT: 130c: 05 00 00 ea b #20 <__ARMToThumbv7ABSLongThunk_thumb_callee1> +// CHECK-ARM-ABS-ARM-NEXT: 1310: 07 00 00 ea b #28 <__ARMToThumbv7ABSLongThunk_thumb_callee2> +// CHECK-ARM-ABS-ARM-NEXT: 1314: 09 00 00 ea b #36 <__ARMToThumbv7ABSLongThunk_thumb_callee3> +// CHECK-ARM-ABS-ARM-NEXT: 1318: 78 ff ff ea b #-544 <arm_callee1> +// CHECK-ARM-ABS-ARM-NEXT: 131c: b7 00 00 0a beq #732 <arm_callee2> +// CHECK-ARM-ABS-ARM-NEXT: 1320: b7 00 00 1a bne #732 <arm_callee3> +// CHECK-ARM-ABS-ARM-NEXT: 1324: 1e ff 2f e1 bx lr +// CHECK-ARM-ABS-ARM: __ARMToThumbv7ABSLongThunk_thumb_callee1: // 0x1001 = thumb_callee1 -// CHECK-ABS-ARM-NEXT: 1328: 01 c0 01 e3 movw r12, #4097 -// CHECK-ABS-ARM-NEXT: 132c: 00 c0 40 e3 movt r12, #0 -// CHECK-ABS-ARM-NEXT: 1330: 1c ff 2f e1 bx r12 +// CHECK-ARM-ABS-ARM-NEXT: 1328: 01 c0 01 e3 movw r12, #4097 +// CHECK-ARM-ABS-ARM-NEXT: 132c: 00 c0 40 e3 movt r12, #0 +// CHECK-ARM-ABS-ARM-NEXT: 1330: 1c ff 2f e1 bx r12 // 0x1501 = thumb_callee2 -// CHECK-ABS-ARM-NEXT: 1334: 01 c5 01 e3 movw r12, #5377 -// CHECK-ABS-ARM-NEXT: 1338: 00 c0 40 e3 movt r12, #0 -// CHECK-ABS-ARM-NEXT: 133c: 1c ff 2f e1 bx r12 +// CHECK-ARM-ABS-ARM: __ARMToThumbv7ABSLongThunk_thumb_callee2: +// CHECK-ARM-ABS-ARM-NEXT: 1334: 01 c5 01 e3 movw r12, #5377 +// CHECK-ARM-ABS-ARM-NEXT: 1338: 00 c0 40 e3 movt r12, #0 +// CHECK-ARM-ABS-ARM-NEXT: 133c: 1c ff 2f e1 bx r12 // 0x1503 = thumb_callee3 -// CHECK-ABS-ARM-NEXT: 1340: 03 c5 01 e3 movw r12, #5379 -// CHECK-ABS-ARM-NEXT: 1344: 00 c0 40 e3 movt r12, #0 -// CHECK-ABS-ARM-NEXT: 1348: 1c ff 2f e1 bx r12 +// CHECK-ARM-ABS-ARM: __ARMToThumbv7ABSLongThunk_thumb_callee3: +// CHECK-ARM-ABS-ARM-NEXT: 1340: 03 c5 01 e3 movw r12, #5379 +// CHECK-ARM-ABS-ARM-NEXT: 1344: 00 c0 40 e3 movt r12, #0 +// CHECK-ARM-ABS-ARM-NEXT: 1348: 1c ff 2f e1 bx r12 // CHECK-PI-ARM: Disassembly of section .arm_caller: // CHECK-PI-ARM-NEXT: arm_caller: -// CHECK-PI-ARM-NEXT: 1300: 3e ff ff fa blx #-776 <thumb_callee1> -// CHECK-PI-ARM-NEXT: 1304: 3d ff ff fa blx #-780 <thumb_callee1> -// 0x1308 + 8 + 0x18 = 0x1328 -// CHECK-PI-ARM-NEXT: 1308: 06 00 00 ea b #24 <arm_caller+0x28> -// 0x130c + 8 + 0x14 = 0x1328 -// CHECK-PI-ARM-NEXT: 130c: 05 00 00 ea b #20 <arm_caller+0x28> -// 0x1310 + 8 + 0x20 = 0x1338 -// CHECK-PI-ARM-NEXT: 1310: 08 00 00 ea b #32 <arm_caller+0x38> -// 0x1314 + 8 + 0x2c = 0x1348 -// CHECK-PI-ARM-NEXT: 1314: 0b 00 00 ea b #44 <arm_caller+0x48> -// CHECK-PI-ARM-NEXT: 1318: 78 ff ff ea b #-544 <arm_callee1> -// CHECK-PI-ARM-NEXT: 131c: b7 00 00 0a beq #732 <arm_callee2> -// CHECK-PI-ARM-NEXT: 1320: b7 00 00 1a bne #732 <arm_callee3> -// CHECK-PI-ARM-NEXT: 1324: 1e ff 2f e1 bx lr +// CHECK-PI-ARM-NEXT: 1300: 3e ff ff fa blx #-776 <thumb_callee1> +// CHECK-PI-ARM-NEXT: 1304: 3d ff ff fa blx #-780 <thumb_callee1> +// CHECK-PI-ARM-NEXT: 1308: 06 00 00 ea b #24 <__ARMToThumbV7PILongThunk_thumb_callee1> +// CHECK-PI-ARM-NEXT: 130c: 05 00 00 ea b #20 <__ARMToThumbV7PILongThunk_thumb_callee1> +// CHECK-PI-ARM-NEXT: 1310: 08 00 00 ea b #32 <__ARMToThumbV7PILongThunk_thumb_callee2> +// CHECK-PI-ARM-NEXT: 1314: 0b 00 00 ea b #44 <__ARMToThumbV7PILongThunk_thumb_callee3> +// CHECK-PI-ARM-NEXT: 1318: 78 ff ff ea b #-544 <arm_callee1> +// CHECK-PI-ARM-NEXT: 131c: b7 00 00 0a beq #732 <arm_callee2> +// CHECK-PI-ARM-NEXT: 1320: b7 00 00 1a bne #732 <arm_callee3> +// CHECK-PI-ARM-NEXT: 1324: 1e ff 2f e1 bx lr +// CHECK-PI-ARM: __ARMToThumbV7PILongThunk_thumb_callee1: // 0x1330 + 8 - 0x337 = 0x1001 = thumb_callee1 -// CHECK-PI-ARM-NEXT: 1328: c9 cc 0f e3 movw r12, #64713 -// CHECK-PI-ARM-NEXT: 132c: ff cf 4f e3 movt r12, #65535 -// CHECK-PI-ARM-NEXT: 1330: 0f c0 8c e0 add r12, r12, pc -// CHECK-PI-ARM-NEXT: 1334: 1c ff 2f e1 bx r12 +// CHECK-PI-ARM-NEXT: 1328: c9 cc 0f e3 movw r12, #64713 +// CHECK-PI-ARM-NEXT: 132c: ff cf 4f e3 movt r12, #65535 +// CHECK-PI-ARM-NEXT: 1330: 0f c0 8c e0 add r12, r12, pc +// CHECK-PI-ARM-NEXT: 1334: 1c ff 2f e1 bx r12 +// CHECK-PI-ARM: __ARMToThumbV7PILongThunk_thumb_callee2: + +// CHECK-PI-ARM-NEXT: 1338: b9 c1 00 e3 movw r12, #441 +// CHECK-PI-ARM-NEXT: 133c: 00 c0 40 e3 movt r12, #0 +// CHECK-PI-ARM-NEXT: 1340: 0f c0 8c e0 add r12, r12, pc +// CHECK-PI-ARM-NEXT: 1344: 1c ff 2f e1 bx r12 +// CHECK-PI-ARM: __ARMToThumbV7PILongThunk_thumb_callee3: // 0x1340 + 8 + 0x1b9 = 0x1501 -// CHECK-PI-ARM-NEXT: 1338: b9 c1 00 e3 movw r12, #441 -// CHECK-PI-ARM-NEXT: 133c: 00 c0 40 e3 movt r12, #0 -// CHECK-PI-ARM-NEXT: 1340: 0f c0 8c e0 add r12, r12, pc -// CHECK-PI-ARM-NEXT: 1344: 1c ff 2f e1 bx r12 +// CHECK-PI-ARM-NEXT: 1348: ab c1 00 e3 movw r12, #427 +// CHECK-PI-ARM-NEXT: 134c: 00 c0 40 e3 movt r12, #0 +// CHECK-PI-ARM-NEXT: 1350: 0f c0 8c e0 add r12, r12, pc +// CHECK-PI-ARM-NEXT: 1354: 1c ff 2f e1 bx r12 // 1350 + 8 + 0x1ab = 0x1503 -// CHECK-PI-ARM-NEXT: 1348: ab c1 00 e3 movw r12, #427 -// CHECK-PI-ARM-NEXT: 134c: 00 c0 40 e3 movt r12, #0 -// CHECK-PI-ARM-NEXT: 1350: 0f c0 8c e0 add r12, r12, pc -// CHECK-PI-ARM-NEXT: 1354: 1c ff 2f e1 bx r12 // All PLT entries are ARM, no need for interworking thunks // CHECK-PI-ARM-PLT: Disassembly of section .arm_caller: @@ -182,60 +185,58 @@ thumb_caller: bne.w arm_callee3 // CHECK-ABS-THUMB: Disassembly of section .thumb_caller: // CHECK-ABS-THUMB-NEXT: thumb_caller: -// 0x1400 + 4 - 0x304 = 0x1100 = arm_callee1 -// CHECK-ABS-THUMB-NEXT: 1400: ff f7 7e ee blx #-772 -// 0x1404 + 4 - 0x308 = 0x1100 = arm_callee1 -// CHECK-ABS-THUMB-NEXT: 1404: ff f7 7c ee blx #-776 -// 0x1408 + 4 + 0x14 = 0x520 -// CHECK-ABS-THUMB-NEXT: 1408: 00 f0 0a b8 b.w #20 -// 0x140c + 4 + 0x1a = 0x52a -// CHECK-ABS-THUMB-NEXT: 140c: 00 f0 0d b8 b.w #26 -// 0x1410 + 4 + 0x20 = 0x534 -// CHECK-ABS-THUMB-NEXT: 1410: 00 f0 10 b8 b.w #32 -// 0x1414 + 4 + 8 = 0x520 -// CHECK-ABS-THUMB-NEXT: 1414: 00 f0 04 80 beq.w #8 -// 0x1418 + 4 + 0xe = 0x52a -// CHECK-ABS-THUMB-NEXT: 1418: 00 f0 07 80 beq.w #14 -// 0x141c + 4 + 0x14 = 0x534 -// CHECK-ABS-THUMB-NEXT: 141c: 40 f0 0a 80 bne.w #20 +// CHECK-ABS-THUMB-NEXT: 1400: ff f7 7e ee blx #-772 +// CHECK-ABS-THUMB-NEXT: 1404: ff f7 7c ee blx #-776 +// CHECK-ABS-THUMB-NEXT: 1408: 00 f0 0a b8 b.w #20 <__ThumbToARMv7ABSLongThunk_arm_callee1+0x4> +// CHECK-ABS-THUMB-NEXT: 140c: 00 f0 0d b8 b.w #26 <__ThumbToARMv7ABSLongThunk_arm_callee2+0x4> +// CHECK-ABS-THUMB-NEXT: 1410: 00 f0 10 b8 b.w #32 <__ThumbToARMv7ABSLongThunk_arm_callee3+0x4> +// CHECK-ABS-THUMB-NEXT: 1414: 00 f0 04 80 beq.w #8 <__ThumbToARMv7ABSLongThunk_arm_callee1+0x4> +// CHECK-ABS-THUMB-NEXT: 1418: 00 f0 07 80 beq.w #14 <__ThumbToARMv7ABSLongThunk_arm_callee2+0x4> +// CHECK-ABS-THUMB-NEXT: 141c: 40 f0 0a 80 bne.w #20 <__ThumbToARMv7ABSLongThunk_arm_callee3+0x4> +// CHECK-ABS-THUMB: __ThumbToARMv7ABSLongThunk_arm_callee1: // 0x1100 = arm_callee1 -// CHECK-ABS-THUMB-NEXT: 1420: 41 f2 00 1c movw r12, #4352 -// CHECK-ABS-THUMB-NEXT: 1424: c0 f2 00 0c movt r12, #0 -// CHECK-ABS-THUMB-NEXT: 1428: 60 47 bx r12 +// CHECK-ABS-THUMB-NEXT: 1420: 41 f2 00 1c movw r12, #4352 +// CHECK-ABS-THUMB-NEXT: 1424: c0 f2 00 0c movt r12, #0 +// CHECK-ABS-THUMB-NEXT: 1428: 60 47 bx r12 +// CHECK-ABS-THUMB: __ThumbToARMv7ABSLongThunk_arm_callee2: // 0x1600 = arm_callee2 -// CHECK-ABS-THUMB-NEXT: 142a: 41 f2 00 6c movw r12, #5632 -// CHECK-ABS-THUMB-NEXT: 142e: c0 f2 00 0c movt r12, #0 -// CHECK-ABS-THUMB-NEXT: 1432: 60 47 bx r12 +// CHECK-ABS-THUMB-NEXT: 142a: 41 f2 00 6c movw r12, #5632 +// CHECK-ABS-THUMB-NEXT: 142e: c0 f2 00 0c movt r12, #0 +// CHECK-ABS-THUMB-NEXT: 1432: 60 47 bx r12 // 0x1604 = arm_callee3 -// CHECK-ABS-THUMB-NEXT: 1434: 41 f2 04 6c movw r12, #5636 -// CHECK-ABS-THUMB-NEXT: 1438: c0 f2 00 0c movt r12, #0 -// CHECK-ABS-THUMB-NEXT: 143c: 60 47 bx r12 +// CHECK-ABS-THUMB: __ThumbToARMv7ABSLongThunk_arm_callee3: +// CHECK-ABS-THUMB-NEXT: 1434: 41 f2 04 6c movw r12, #5636 +// CHECK-ABS-THUMB-NEXT: 1438: c0 f2 00 0c movt r12, #0 +// CHECK-ABS-THUMB-NEXT: 143c: 60 47 bx r12 // CHECK-PI-THUMB: Disassembly of section .thumb_caller: // CHECK-PI-THUMB-NEXT: thumb_caller: -// CHECK-PI-THUMB-NEXT: 1400: ff f7 7e ee blx #-772 -// CHECK-PI-THUMB-NEXT: 1404: ff f7 7c ee blx #-776 -// CHECK-PI-THUMB-NEXT: 1408: 00 f0 0a b8 b.w #20 -// CHECK-PI-THUMB-NEXT: 140c: 00 f0 0e b8 b.w #28 -// CHECK-PI-THUMB-NEXT: 1410: 00 f0 12 b8 b.w #36 -// CHECK-PI-THUMB-NEXT: 1414: 00 f0 04 80 beq.w #8 -// CHECK-PI-THUMB-NEXT: 1418: 00 f0 08 80 beq.w #16 -// CHECK-PI-THUMB-NEXT: 141c: 40 f0 0c 80 bne.w #24 +// CHECK-PI-THUMB-NEXT: 1400: ff f7 7e ee blx #-772 +// CHECK-PI-THUMB-NEXT: 1404: ff f7 7c ee blx #-776 +// CHECK-PI-THUMB-NEXT: 1408: 00 f0 0a b8 b.w #20 <__ThumbToARMV7PILongThunk_arm_callee1+0x4> +// CHECK-PI-THUMB-NEXT: 140c: 00 f0 0e b8 b.w #28 <__ThumbToARMV7PILongThunk_arm_callee2+0x4> +// CHECK-PI-THUMB-NEXT: 1410: 00 f0 12 b8 b.w #36 <__ThumbToARMV7PILongThunk_arm_callee3+0x4> +// CHECK-PI-THUMB-NEXT: 1414: 00 f0 04 80 beq.w #8 <__ThumbToARMV7PILongThunk_arm_callee1+0x4> +// CHECK-PI-THUMB-NEXT: 1418: 00 f0 08 80 beq.w #16 <__ThumbToARMV7PILongThunk_arm_callee2+0x4> +// CHECK-PI-THUMB-NEXT: 141c: 40 f0 0c 80 bne.w #24 <__ThumbToARMV7PILongThunk_arm_callee3+0x4> +// CHECK-PI-THUMB: __ThumbToARMV7PILongThunk_arm_callee1: // 0x1428 + 4 - 0x32c = 0x1100 = arm_callee1 -// CHECK-PI-THUMB-NEXT: 1420: 4f f6 d4 4c movw r12, #64724 -// CHECK-PI-THUMB-NEXT: 1424: cf f6 ff 7c movt r12, #65535 -// CHECK-PI-THUMB-NEXT: 1428: fc 44 add r12, pc -// CHECK-PI-THUMB-NEXT: 142a: 60 47 bx r12 +// CHECK-PI-THUMB-NEXT: 1420: 4f f6 d4 4c movw r12, #64724 +// CHECK-PI-THUMB-NEXT: 1424: cf f6 ff 7c movt r12, #65535 +// CHECK-PI-THUMB-NEXT: 1428: fc 44 add r12, pc +// CHECK-PI-THUMB-NEXT: 142a: 60 47 bx r12 +// CHECK-PI-THUMB: __ThumbToARMV7PILongThunk_arm_callee2: // 0x1434 + 4 + 0x1c8 = 0x1600 = arm_callee2 -// CHECK-PI-THUMB-NEXT: 142c: 40 f2 c8 1c movw r12, #456 -// CHECK-PI-THUMB-NEXT: 1430: c0 f2 00 0c movt r12, #0 -// CHECK-PI-THUMB-NEXT: 1434: fc 44 add r12, pc -// CHECK-PI-THUMB-NEXT: 1436: 60 47 bx r12 +// CHECK-PI-THUMB-NEXT: 142c: 40 f2 c8 1c movw r12, #456 +// CHECK-PI-THUMB-NEXT: 1430: c0 f2 00 0c movt r12, #0 +// CHECK-PI-THUMB-NEXT: 1434: fc 44 add r12, pc +// CHECK-PI-THUMB-NEXT: 1436: 60 47 bx r12 +// CHECK-PI-THUMB: __ThumbToARMV7PILongThunk_arm_callee3: // 0x1440 + 4 + 0x1c0 = 0x1604 = arm_callee3 -// CHECK-PI-THUMB-NEXT: 1438: 40 f2 c0 1c movw r12, #448 -// CHECK-PI-THUMB-NEXT: 143c: c0 f2 00 0c movt r12, #0 -// CHECK-PI-THUMB-NEXT: 1440: fc 44 add r12, pc -// CHECK-PI-THUMB-NEXT: 1442: 60 47 bx r12 +// CHECK-PI-THUMB-NEXT: 1438: 40 f2 c0 1c movw r12, #448 +// CHECK-PI-THUMB-NEXT: 143c: c0 f2 00 0c movt r12, #0 +// CHECK-PI-THUMB-NEXT: 1440: fc 44 add r12, pc +// CHECK-PI-THUMB-NEXT: 1442: 60 47 bx r12 // CHECK-PI-THUMB-PLT: Disassembly of section .arm_caller: // CHECK-PI-THUMB-PLT-NEXT: thumb_caller: diff --git a/lld/test/ELF/mips-npic-call-pic.s b/lld/test/ELF/mips-npic-call-pic.s index 76c392e1f66..a5a99d71998 100644 --- a/lld/test/ELF/mips-npic-call-pic.s +++ b/lld/test/ELF/mips-npic-call-pic.s @@ -15,60 +15,65 @@ # CHECK: Disassembly of section .text: # CHECK-NEXT: __start: -# CHECK-NEXT: 20000: 0c 00 80 0e jal 131128 <foo1b+0x4> -# ^-- .pic.foo1a +# CHECK-NEXT: 20000: 0c 00 80 0c jal 131120 <__LA25Thunk_foo1a> # CHECK-NEXT: 20004: 00 00 00 00 nop -# CHECK-NEXT: 20008: 0c 00 80 19 jal 131172 <foo2+0x4> -# ^-- .pic.foo2 +# CHECK-NEXT: 20008: 0c 00 80 16 jal 131160 <__LA25Thunk_foo2> # CHECK-NEXT: 2000c: 00 00 00 00 nop -# CHECK-NEXT: 20010: 0c 00 80 12 jal 131144 <foo1b+0x14> -# ^-- .pic.foo1b +# CHECK-NEXT: 20010: 0c 00 80 10 jal 131136 <__LA25Thunk_foo1b> # CHECK-NEXT: 20014: 00 00 00 00 nop -# CHECK-NEXT: 20018: 0c 00 80 19 jal 131172 <foo2+0x4> -# ^-- .pic.foo2 +# CHECK-NEXT: 20018: 0c 00 80 16 jal 131160 <__LA25Thunk_foo2> # CHECK-NEXT: 2001c: 00 00 00 00 nop -# CHECK-NEXT: 20020: 0c 00 80 25 jal 131220 <fnpic+0x4> -# ^-- .pic.fpic +# CHECK-NEXT: 20020: 0c 00 80 1d jal 131188 <__LA25Thunk_fpic> # CHECK-NEXT: 20024: 00 00 00 00 nop -# CHECK-NEXT: 20028: 0c 00 80 24 jal 131216 <fnpic> +# CHECK-NEXT: 20028: 0c 00 80 28 jal 131232 <fnpic> # CHECK-NEXT: 2002c: 00 00 00 00 nop # -# CHECK: foo1a: -# CHECK-NEXT: 20030: 00 00 00 00 nop -# -# CHECK: foo1b: -# CHECK-NEXT: 20034: 00 00 00 00 nop -# -# CHECK-NEXT: 20038: 3c 19 00 02 lui $25, 2 -# CHECK-NEXT: 2003c: 08 00 80 0c j 131120 <foo1a> -# CHECK-NEXT: 20040: 27 39 00 30 addiu $25, $25, 48 -# CHECK-NEXT: 20044: 00 00 00 00 nop -# CHECK-NEXT: 20048: 3c 19 00 02 lui $25, 2 -# CHECK-NEXT: 2004c: 08 00 80 0d j 131124 <foo1b> -# CHECK-NEXT: 20050: 27 39 00 34 addiu $25, $25, 52 +# CHECK: __LA25Thunk_foo1a: +# CHECK-NEXT: 20030: 3c 19 00 02 lui $25, 2 +# CHECK-NEXT: 20034: 08 00 80 14 j 131152 <foo1a> +# CHECK-NEXT: 20038: 27 39 00 50 addiu $25, $25, 80 +# CHECK-NEXT: 2003c: 00 00 00 00 nop + +# CHECK: __LA25Thunk_foo1b: +# CHECK-NEXT: 20040: 3c 19 00 02 lui $25, 2 +# CHECK-NEXT: 20044: 08 00 80 15 j 131156 <foo1b> +# CHECK-NEXT: 20048: 27 39 00 54 addiu $25, $25, 84 +# CHECK-NEXT: 2004c: 00 00 00 00 nop + +# CHECK: foo1a: +# CHECK-NEXT: 20050: 00 00 00 00 nop + +# CHECK: foo1b: # CHECK-NEXT: 20054: 00 00 00 00 nop -# CHECK-NEXT: 20058: 00 00 00 00 nop -# CHECK-NEXT: 2005c: 00 00 00 00 nop -# -# CHECK: foo2: -# CHECK-NEXT: 20060: 00 00 00 00 nop -# -# CHECK-NEXT: 20064: 3c 19 00 02 lui $25, 2 -# CHECK-NEXT: 20068: 08 00 80 18 j 131168 <foo2> -# CHECK-NEXT: 2006c: 27 39 00 60 addiu $25, $25, 96 + +# CHECK: __LA25Thunk_foo2: +# CHECK-NEXT: 20058: 3c 19 00 02 lui $25, 2 +# CHECK-NEXT: 2005c: 08 00 80 1c j 131184 <foo2> +# CHECK-NEXT: 20060: 27 39 00 70 addiu $25, $25, 112 +# CHECK-NEXT: 20064: 00 00 00 00 nop +# CHECK-NEXT: 20068: 00 00 00 00 nop +# CHECK-NEXT: 2006c: 00 00 00 00 nop + +# CHECK: foo2: # CHECK-NEXT: 20070: 00 00 00 00 nop -# CHECK-NEXT: 20074: 00 00 00 00 nop -# CHECK-NEXT: 20078: 00 00 00 00 nop -# CHECK-NEXT: 2007c: 00 00 00 00 nop -# -# CHECK: fpic: -# CHECK-NEXT: 20080: 00 00 00 00 nop -# -# CHECK: fnpic: + +# CHECK: __LA25Thunk_fpic: +# CHECK-NEXT: 20074: 3c 19 00 02 lui $25, 2 +# CHECK-NEXT: 20078: 08 00 80 24 j 131216 <fpic> +# CHECK-NEXT: 2007c: 27 39 00 90 addiu $25, $25, 144 +# CHECK-NEXT: 20080: 00 00 00 00 nop +# CHECK-NEXT: 20084: 00 00 00 00 nop +# CHECK-NEXT: 20088: 00 00 00 00 nop +# CHECK-NEXT: 2008c: 00 00 00 00 nop + +# CHECK: fpic: # CHECK-NEXT: 20090: 00 00 00 00 nop -# CHECK-NEXT: 20094: 3c 19 00 02 lui $25, 2 -# CHECK-NEXT: 20098: 08 00 80 20 j 131200 <fpic> -# CHECK-NEXT: 2009c: 27 39 00 80 addiu $25, $25, 128 +# CHECK-NEXT: 20094: 00 00 00 00 nop +# CHECK-NEXT: 20098: 00 00 00 00 nop +# CHECK-NEXT: 2009c: 00 00 00 00 nop + +# CHECK: fnpic: +# CHECK-NEXT: 200a0: 00 00 00 00 nop # Make sure the thunks are created properly no matter how # objects are laid out. @@ -76,54 +81,58 @@ # RUN: ld.lld %t-pic.o %t-npic.o %t-sto-pic.o -o %t.exe # RUN: llvm-objdump -d %t.exe | FileCheck -check-prefix=REVERSE %s -# REVERSE: foo1a: -# REVERSE-NEXT: 20000: 00 00 00 00 nop -# -# REVERSE: foo1b: -# REVERSE-NEXT: 20004: 00 00 00 00 nop -# REVERSE-NEXT: 20008: 3c 19 00 02 lui $25, 2 -# REVERSE-NEXT: 2000c: 08 00 80 00 j 131072 <foo1a> -# REVERSE-NEXT: 20010: 27 39 00 00 addiu $25, $25, 0 -# REVERSE-NEXT: 20014: 00 00 00 00 nop -# REVERSE-NEXT: 20018: 3c 19 00 02 lui $25, 2 -# REVERSE-NEXT: 2001c: 08 00 80 01 j 131076 <foo1b> -# REVERSE-NEXT: 20020: 27 39 00 04 addiu $25, $25, 4 +# REVERSE: Disassembly of section .text: +# REVERSE-NEXT: __LA25Thunk_foo1a: +# REVERSE-NEXT: 20000: 3c 19 00 02 lui $25, 2 +# REVERSE-NEXT: 20004: 08 00 80 08 j 131104 <foo1a> +# REVERSE-NEXT: 20008: 27 39 00 20 addiu $25, $25, 32 +# REVERSE-NEXT: 2000c: 00 00 00 00 nop +# REVERSE: __LA25Thunk_foo1b: +# REVERSE-NEXT: 20010: 3c 19 00 02 lui $25, 2 +# REVERSE-NEXT: 20014: 08 00 80 09 j 131108 <foo1b> +# REVERSE-NEXT: 20018: 27 39 00 24 addiu $25, $25, 36 +# REVERSE-NEXT: 2001c: 00 00 00 00 nop +# REVERSE: foo1a: +# REVERSE-NEXT: 20020: 00 00 00 00 nop +# REVERSE: foo1b: # REVERSE-NEXT: 20024: 00 00 00 00 nop -# REVERSE-NEXT: 20028: 00 00 00 00 nop -# REVERSE-NEXT: 2002c: 00 00 00 00 nop -# -# REVERSE: foo2: -# REVERSE-NEXT: 20030: 00 00 00 00 nop -# REVERSE-NEXT: 20034: 3c 19 00 02 lui $25, 2 -# REVERSE-NEXT: 20038: 08 00 80 0c j 131120 <foo2> -# REVERSE-NEXT: 2003c: 27 39 00 30 addiu $25, $25, 48 +# REVERSE: __LA25Thunk_foo2: +# REVERSE-NEXT: 20028: 3c 19 00 02 lui $25, 2 +# REVERSE-NEXT: 2002c: 08 00 80 10 j 131136 <foo2> +# REVERSE-NEXT: 20030: 27 39 00 40 addiu $25, $25, 64 +# REVERSE-NEXT: 20034: 00 00 00 00 nop +# REVERSE-NEXT: 20038: 00 00 00 00 nop +# REVERSE-NEXT: 2003c: 00 00 00 00 nop +# REVERSE: foo2: # REVERSE-NEXT: 20040: 00 00 00 00 nop # REVERSE-NEXT: 20044: 00 00 00 00 nop # REVERSE-NEXT: 20048: 00 00 00 00 nop # REVERSE-NEXT: 2004c: 00 00 00 00 nop -# -# REVERSE: __start: -# REVERSE-NEXT: 20050: 0c 00 80 02 jal 131080 <foo1b+0x4> +# REVERSE: __start: +# REVERSE-NEXT: 20050: 0c 00 80 00 jal 131072 <__LA25Thunk_foo1a> # REVERSE-NEXT: 20054: 00 00 00 00 nop -# REVERSE-NEXT: 20058: 0c 00 80 0d jal 131124 <foo2+0x4> +# REVERSE-NEXT: 20058: 0c 00 80 0a jal 131112 <__LA25Thunk_foo2> # REVERSE-NEXT: 2005c: 00 00 00 00 nop -# REVERSE-NEXT: 20060: 0c 00 80 06 jal 131096 <foo1b+0x14> +# REVERSE-NEXT: 20060: 0c 00 80 04 jal 131088 <__LA25Thunk_foo1b> # REVERSE-NEXT: 20064: 00 00 00 00 nop -# REVERSE-NEXT: 20068: 0c 00 80 0d jal 131124 <foo2+0x4> +# REVERSE-NEXT: 20068: 0c 00 80 0a jal 131112 <__LA25Thunk_foo2> # REVERSE-NEXT: 2006c: 00 00 00 00 nop -# REVERSE-NEXT: 20070: 0c 00 80 25 jal 131220 <fnpic+0x4> +# REVERSE-NEXT: 20070: 0c 00 80 20 jal 131200 <__LA25Thunk_fpic> # REVERSE-NEXT: 20074: 00 00 00 00 nop -# REVERSE-NEXT: 20078: 0c 00 80 24 jal 131216 <fnpic> +# REVERSE-NEXT: 20078: 0c 00 80 28 jal 131232 <fnpic> # REVERSE-NEXT: 2007c: 00 00 00 00 nop -# -# REVERSE: fpic: -# REVERSE-NEXT: 20080: 00 00 00 00 nop -# -# REVERSE: fnpic: +# REVERSE: __LA25Thunk_fpic: +# REVERSE-NEXT: 20080: 3c 19 00 02 lui $25, 2 +# REVERSE-NEXT: 20084: 08 00 80 24 j 131216 <fpic> +# REVERSE-NEXT: 20088: 27 39 00 90 addiu $25, $25, 144 +# REVERSE-NEXT: 2008c: 00 00 00 00 nop +# REVERSE: fpic: # REVERSE-NEXT: 20090: 00 00 00 00 nop -# REVERSE-NEXT: 20094: 3c 19 00 02 lui $25, 2 -# REVERSE-NEXT: 20098: 08 00 80 20 j 131200 <fpic> -# REVERSE-NEXT: 2009c: 27 39 00 80 addiu $25, $25, 128 +# REVERSE-NEXT: 20094: 00 00 00 00 nop +# REVERSE-NEXT: 20098: 00 00 00 00 nop +# REVERSE-NEXT: 2009c: 00 00 00 00 nop +# REVERSE: fnpic: +# REVERSE-NEXT: 200a0: 00 00 00 00 nop .text .globl __start |

