Revert "[ELF][ARM] Use SyntheticSections for Thunks"
This reverts commit r293283 because it broke MSVC build. llvm-svn: 293352
This commit is contained in:
@@ -488,7 +488,7 @@ SymbolBody *elf::ObjectFile<ELFT>::createSymbolBody(const Elf_Sym *Sym) {
|
|||||||
StringRefZ Name = this->StringTable.data() + Sym->st_name;
|
StringRefZ Name = this->StringTable.data() + Sym->st_name;
|
||||||
if (Sym->st_shndx == SHN_UNDEF)
|
if (Sym->st_shndx == SHN_UNDEF)
|
||||||
return new (BAlloc)
|
return new (BAlloc)
|
||||||
Undefined(Name, /*IsLocal=*/true, StOther, Type, this);
|
Undefined<ELFT>(Name, /*IsLocal=*/true, StOther, Type, this);
|
||||||
|
|
||||||
return new (BAlloc) DefinedRegular<ELFT>(Name, /*IsLocal=*/true, StOther,
|
return new (BAlloc) DefinedRegular<ELFT>(Name, /*IsLocal=*/true, StOther,
|
||||||
Type, Value, Size, Sec, this);
|
Type, Value, Size, Sec, this);
|
||||||
|
|||||||
@@ -99,6 +99,10 @@ template <class ELFT> size_t InputSectionBase<ELFT>::getSize() const {
|
|||||||
if (auto *S = dyn_cast<SyntheticSection<ELFT>>(this))
|
if (auto *S = dyn_cast<SyntheticSection<ELFT>>(this))
|
||||||
return S->getSize();
|
return S->getSize();
|
||||||
|
|
||||||
|
if (auto *D = dyn_cast<InputSection<ELFT>>(this))
|
||||||
|
if (D->getThunksSize() > 0)
|
||||||
|
return D->getThunkOff() + D->getThunksSize();
|
||||||
|
|
||||||
return Data.size();
|
return Data.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -210,6 +214,21 @@ InputSectionBase<ELFT> *InputSection<ELFT>::getRelocatedSection() {
|
|||||||
return Sections[this->Info];
|
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
|
// 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
|
// to update symbol table offset and section index for each relocation. So we
|
||||||
// copy relocations one by one.
|
// copy relocations one by one.
|
||||||
@@ -283,6 +302,11 @@ getRelocTargetVA(uint32_t Type, typename ELFT::uint A, typename ELFT::uint P,
|
|||||||
return In<ELFT>::Got->getTlsIndexOff() + A - In<ELFT>::Got->getSize();
|
return In<ELFT>::Got->getTlsIndexOff() + A - In<ELFT>::Got->getSize();
|
||||||
case R_TLSLD_PC:
|
case R_TLSLD_PC:
|
||||||
return In<ELFT>::Got->getTlsIndexVA() + A - P;
|
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:
|
case R_PPC_TOC:
|
||||||
return getPPC64TocBase() + A;
|
return getPPC64TocBase() + A;
|
||||||
case R_TLSGD:
|
case R_TLSGD:
|
||||||
@@ -527,6 +551,19 @@ template <class ELFT> void InputSection<ELFT>::writeTo(uint8_t *Buf) {
|
|||||||
// Iterate over all relocation sections that apply to this section.
|
// Iterate over all relocation sections that apply to this section.
|
||||||
uint8_t *BufEnd = Buf + OutSecOff + Data.size();
|
uint8_t *BufEnd = Buf + OutSecOff + Data.size();
|
||||||
this->relocate(Buf, BufEnd);
|
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>
|
template <class ELFT>
|
||||||
|
|||||||
@@ -280,6 +280,17 @@ public:
|
|||||||
|
|
||||||
InputSectionBase<ELFT> *getRelocatedSection();
|
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>
|
template <class RelTy>
|
||||||
void relocateNonAlloc(uint8_t *Buf, llvm::ArrayRef<RelTy> Rels);
|
void relocateNonAlloc(uint8_t *Buf, llvm::ArrayRef<RelTy> Rels);
|
||||||
|
|
||||||
@@ -292,6 +303,8 @@ public:
|
|||||||
private:
|
private:
|
||||||
template <class RelTy>
|
template <class RelTy>
|
||||||
void copyRelocations(uint8_t *Buf, llvm::ArrayRef<RelTy> Rels);
|
void copyRelocations(uint8_t *Buf, llvm::ArrayRef<RelTy> Rels);
|
||||||
|
|
||||||
|
llvm::TinyPtrVector<const Thunk<ELFT> *> Thunks;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class ELFT> InputSection<ELFT> InputSection<ELFT>::Discarded;
|
template <class ELFT> InputSection<ELFT> InputSection<ELFT>::Discarded;
|
||||||
|
|||||||
@@ -96,12 +96,12 @@ BitcodeCompiler::BitcodeCompiler() : LTOObj(createLTO()) {}
|
|||||||
|
|
||||||
BitcodeCompiler::~BitcodeCompiler() = default;
|
BitcodeCompiler::~BitcodeCompiler() = default;
|
||||||
|
|
||||||
static void undefine(Symbol *S) {
|
template <class ELFT> static void undefine(Symbol *S) {
|
||||||
replaceBody<Undefined>(S, S->body()->getName(), /*IsLocal=*/false,
|
replaceBody<Undefined<ELFT>>(S, S->body()->getName(), /*IsLocal=*/false,
|
||||||
STV_DEFAULT, S->body()->Type, nullptr);
|
STV_DEFAULT, S->body()->Type, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BitcodeCompiler::add(BitcodeFile &F) {
|
template <class ELFT> void BitcodeCompiler::add(BitcodeFile &F) {
|
||||||
lto::InputFile &Obj = *F.Obj;
|
lto::InputFile &Obj = *F.Obj;
|
||||||
unsigned SymNum = 0;
|
unsigned SymNum = 0;
|
||||||
std::vector<Symbol *> Syms = F.getSymbols();
|
std::vector<Symbol *> Syms = F.getSymbols();
|
||||||
@@ -126,7 +126,7 @@ void BitcodeCompiler::add(BitcodeFile &F) {
|
|||||||
R.VisibleToRegularObj =
|
R.VisibleToRegularObj =
|
||||||
Sym->IsUsedInRegularObj || (R.Prevailing && Sym->includeInDynsym());
|
Sym->IsUsedInRegularObj || (R.Prevailing && Sym->includeInDynsym());
|
||||||
if (R.Prevailing)
|
if (R.Prevailing)
|
||||||
undefine(Sym);
|
undefine<ELFT>(Sym);
|
||||||
}
|
}
|
||||||
checkError(LTOObj->add(std::move(F.Obj), Resols));
|
checkError(LTOObj->add(std::move(F.Obj), Resols));
|
||||||
}
|
}
|
||||||
@@ -157,3 +157,8 @@ std::vector<InputFile *> BitcodeCompiler::compile() {
|
|||||||
}
|
}
|
||||||
return Ret;
|
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 &);
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ public:
|
|||||||
BitcodeCompiler();
|
BitcodeCompiler();
|
||||||
~BitcodeCompiler();
|
~BitcodeCompiler();
|
||||||
|
|
||||||
void add(BitcodeFile &F);
|
template <class ELFT> void add(BitcodeFile &F);
|
||||||
std::vector<InputFile *> compile();
|
std::vector<InputFile *> compile();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -43,7 +43,6 @@
|
|||||||
|
|
||||||
#include "Relocations.h"
|
#include "Relocations.h"
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
#include "Memory.h"
|
|
||||||
#include "OutputSections.h"
|
#include "OutputSections.h"
|
||||||
#include "Strings.h"
|
#include "Strings.h"
|
||||||
#include "SymbolTable.h"
|
#include "SymbolTable.h"
|
||||||
@@ -53,7 +52,6 @@
|
|||||||
|
|
||||||
#include "llvm/Support/Endian.h"
|
#include "llvm/Support/Endian.h"
|
||||||
#include "llvm/Support/raw_ostream.h"
|
#include "llvm/Support/raw_ostream.h"
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
using namespace llvm::ELF;
|
using namespace llvm::ELF;
|
||||||
@@ -302,14 +300,16 @@ template <class ELFT> static bool isAbsoluteValue(const SymbolBody &Body) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool needsPlt(RelExpr Expr) {
|
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
|
// True if this expression is of the form Sym - X, where X is a position in the
|
||||||
// file (PC, or GOT for example).
|
// file (PC, or GOT for example).
|
||||||
static bool isRelExpr(RelExpr Expr) {
|
static bool isRelExpr(RelExpr Expr) {
|
||||||
return isRelExprOneOf<R_PC, R_GOTREL, R_GOTREL_FROM_END, R_MIPS_GOTREL,
|
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>
|
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,
|
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_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_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;
|
return true;
|
||||||
|
|
||||||
// These never do, except if the entire file is position dependent or if
|
// 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))
|
if (Expr == R_GOT_PC && !isAbsoluteValue<ELFT>(Body))
|
||||||
Expr = Target->adjustRelaxExpr(Type, Data, Expr);
|
Expr = Target->adjustRelaxExpr(Type, Data, Expr);
|
||||||
}
|
}
|
||||||
|
Expr = Target->getThunkExpr(Expr, Type, &File, Body);
|
||||||
|
|
||||||
if (IsWrite || isStaticLinkTimeConstant<ELFT>(Expr, Type, Body, S, RelOff))
|
if (IsWrite || isStaticLinkTimeConstant<ELFT>(Expr, Type, Body, S, RelOff))
|
||||||
return Expr;
|
return Expr;
|
||||||
@@ -683,6 +685,7 @@ static void scanRelocs(InputSectionBase<ELFT> &C, ArrayRef<RelTy> Rels) {
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (needsPlt(Expr) ||
|
if (needsPlt(Expr) ||
|
||||||
|
isRelExprOneOf<R_THUNK_ABS, R_THUNK_PC, R_THUNK_PLT_PC>(Expr) ||
|
||||||
refersToGotEntry(Expr) || !isPreemptible(Body, Type)) {
|
refersToGotEntry(Expr) || !isPreemptible(Body, Type)) {
|
||||||
// If the relocation points to something in the file, we can process it.
|
// If the relocation points to something in the file, we can process it.
|
||||||
bool Constant =
|
bool Constant =
|
||||||
@@ -802,126 +805,33 @@ template <class ELFT> void scanRelocations(InputSectionBase<ELFT> &S) {
|
|||||||
scanRelocs(S, S.rels());
|
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>
|
template <class ELFT>
|
||||||
void createThunks(ArrayRef<OutputSectionBase *> OutputSections) {
|
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) {
|
for (OutputSectionBase *Base : OutputSections) {
|
||||||
auto *OS = dyn_cast<OutputSection<ELFT>>(Base);
|
auto *OS = dyn_cast<OutputSection<ELFT>>(Base);
|
||||||
if (OS == nullptr)
|
if (OS == nullptr)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
ThunkSection<ELFT> *OSTS = nullptr;
|
|
||||||
for (InputSection<ELFT> *IS : OS->Sections) {
|
for (InputSection<ELFT> *IS : OS->Sections) {
|
||||||
for (Relocation &Rel : IS->Relocations) {
|
for (const Relocation &Rel : IS->Relocations) {
|
||||||
SymbolBody &Body = *Rel.Sym;
|
if (Rel.Sym == nullptr)
|
||||||
if (Target->needsThunk(Rel.Expr, Rel.Type, IS->getFile(), Body)) {
|
continue;
|
||||||
Thunk<ELFT> *T;
|
RelExpr Expr = Rel.Expr;
|
||||||
bool IsNew;
|
// Some targets might require creation of thunks for relocations.
|
||||||
std::tie(T, IsNew) = GetThunk(Body, Rel.Type);
|
// Now we support only MIPS which requires LA25 thunk to call PIC
|
||||||
if (IsNew) {
|
// code from non-PIC one, and ARM which requires interworking.
|
||||||
// Find or create a ThunkSection for the new Thunk
|
if (Expr == R_THUNK_ABS || Expr == R_THUNK_PC ||
|
||||||
ThunkSection<ELFT> *TS;
|
Expr == R_THUNK_PLT_PC)
|
||||||
if (auto *TIS = T->getTargetInputSection())
|
addThunk<ELFT>(Rel.Type, *Rel.Sym, *IS);
|
||||||
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> &);
|
template void scanRelocations<ELF32LE>(InputSectionBase<ELF32LE> &);
|
||||||
|
|||||||
@@ -61,6 +61,9 @@ enum RelExpr {
|
|||||||
R_RELAX_TLS_IE_TO_LE,
|
R_RELAX_TLS_IE_TO_LE,
|
||||||
R_RELAX_TLS_LD_TO_LE,
|
R_RELAX_TLS_LD_TO_LE,
|
||||||
R_SIZE,
|
R_SIZE,
|
||||||
|
R_THUNK_ABS,
|
||||||
|
R_THUNK_PC,
|
||||||
|
R_THUNK_PLT_PC,
|
||||||
R_TLS,
|
R_TLS,
|
||||||
R_TLSDESC,
|
R_TLSDESC,
|
||||||
R_TLSDESC_PAGE,
|
R_TLSDESC_PAGE,
|
||||||
|
|||||||
@@ -115,7 +115,7 @@ template <class ELFT> void SymbolTable<ELFT>::addCombinedLTOObject() {
|
|||||||
// Compile bitcode files and replace bitcode symbols.
|
// Compile bitcode files and replace bitcode symbols.
|
||||||
LTO.reset(new BitcodeCompiler);
|
LTO.reset(new BitcodeCompiler);
|
||||||
for (BitcodeFile *F : BitcodeFiles)
|
for (BitcodeFile *F : BitcodeFiles)
|
||||||
LTO->add(*F);
|
LTO->add<ELFT>(*F);
|
||||||
|
|
||||||
for (InputFile *File : LTO->compile()) {
|
for (InputFile *File : LTO->compile()) {
|
||||||
ObjectFile<ELFT> *Obj = cast<ObjectFile<ELFT>>(File);
|
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);
|
insert(Name, Type, getVisibility(StOther), CanOmitFromDynSym, File);
|
||||||
if (WasInserted) {
|
if (WasInserted) {
|
||||||
S->Binding = Binding;
|
S->Binding = Binding;
|
||||||
replaceBody<Undefined>(S, Name, IsLocal, StOther, Type, File);
|
replaceBody<Undefined<ELFT>>(S, Name, IsLocal, StOther, Type, File);
|
||||||
return S;
|
return S;
|
||||||
}
|
}
|
||||||
if (Binding != STB_WEAK) {
|
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.
|
// Make sure we preempt DSO symbols with default visibility.
|
||||||
if (Sym.getVisibility() == STV_DEFAULT)
|
if (Sym.getVisibility() == STV_DEFAULT)
|
||||||
S->ExportDynamic = true;
|
S->ExportDynamic = true;
|
||||||
if (WasInserted || isa<Undefined>(S->body())) {
|
if (WasInserted || isa<Undefined<ELFT>>(S->body())) {
|
||||||
replaceBody<SharedSymbol<ELFT>>(S, F, Name, Sym, Verdef);
|
replaceBody<SharedSymbol<ELFT>>(S, F, Name, Sym, Verdef);
|
||||||
if (!S->isWeak())
|
if (!S->isWeak())
|
||||||
F->IsUsed = true;
|
F->IsUsed = true;
|
||||||
|
|||||||
@@ -132,6 +132,14 @@ bool SymbolBody::isPreemptible() const {
|
|||||||
return true;
|
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>
|
template <class ELFT>
|
||||||
typename ELFT::uint SymbolBody::getVA(typename ELFT::uint Addend) const {
|
typename ELFT::uint SymbolBody::getVA(typename ELFT::uint Addend) const {
|
||||||
typename ELFT::uint OutVA = getSymVA<ELFT>(*this, Addend);
|
typename ELFT::uint OutVA = getSymVA<ELFT>(*this, Addend);
|
||||||
@@ -163,6 +171,16 @@ template <class ELFT> typename ELFT::uint SymbolBody::getPltVA() const {
|
|||||||
PltIndex * Target->PltEntrySize;
|
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 {
|
template <class ELFT> typename ELFT::uint SymbolBody::getSize() const {
|
||||||
if (const auto *C = dyn_cast<DefinedCommon>(this))
|
if (const auto *C = dyn_cast<DefinedCommon>(this))
|
||||||
return C->Size;
|
return C->Size;
|
||||||
@@ -223,7 +241,8 @@ template <class ELFT> bool DefinedRegular<ELFT>::isMipsPIC() const {
|
|||||||
(Section->getFile()->getObj().getHeader()->e_flags & EF_MIPS_PIC);
|
(Section->getFile()->getObj().getHeader()->e_flags & EF_MIPS_PIC);
|
||||||
}
|
}
|
||||||
|
|
||||||
Undefined::Undefined(StringRefZ Name, bool IsLocal, uint8_t StOther,
|
template <typename ELFT>
|
||||||
|
Undefined<ELFT>::Undefined(StringRefZ Name, bool IsLocal, uint8_t StOther,
|
||||||
uint8_t Type, InputFile *File)
|
uint8_t Type, InputFile *File)
|
||||||
: SymbolBody(SymbolBody::UndefinedKind, Name, IsLocal, StOther, Type) {
|
: SymbolBody(SymbolBody::UndefinedKind, Name, IsLocal, StOther, Type) {
|
||||||
this->File = File;
|
this->File = File;
|
||||||
@@ -319,6 +338,11 @@ std::string lld::toString(const SymbolBody &B) {
|
|||||||
return B.getName();
|
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<ELF32LE>(uint32_t) const;
|
||||||
template uint32_t SymbolBody::template getVA<ELF32BE>(uint32_t) const;
|
template uint32_t SymbolBody::template getVA<ELF32BE>(uint32_t) const;
|
||||||
template uint64_t SymbolBody::template getVA<ELF64LE>(uint64_t) const;
|
template uint64_t SymbolBody::template getVA<ELF64LE>(uint64_t) const;
|
||||||
@@ -339,6 +363,11 @@ template uint32_t SymbolBody::template getGotPltVA<ELF32BE>() const;
|
|||||||
template uint64_t SymbolBody::template getGotPltVA<ELF64LE>() const;
|
template uint64_t SymbolBody::template getGotPltVA<ELF64LE>() const;
|
||||||
template uint64_t SymbolBody::template getGotPltVA<ELF64BE>() 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<ELF32LE>() const;
|
||||||
template uint32_t SymbolBody::template getGotPltOffset<ELF32BE>() const;
|
template uint32_t SymbolBody::template getGotPltOffset<ELF32BE>() const;
|
||||||
template uint64_t SymbolBody::template getGotPltOffset<ELF64LE>() const;
|
template uint64_t SymbolBody::template getGotPltOffset<ELF64LE>() const;
|
||||||
@@ -354,6 +383,11 @@ template uint32_t SymbolBody::template getSize<ELF32BE>() const;
|
|||||||
template uint64_t SymbolBody::template getSize<ELF64LE>() const;
|
template uint64_t SymbolBody::template getSize<ELF64LE>() const;
|
||||||
template uint64_t SymbolBody::template getSize<ELF64BE>() 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<ELF32LE>;
|
||||||
template class elf::SharedSymbol<ELF32BE>;
|
template class elf::SharedSymbol<ELF32BE>;
|
||||||
template class elf::SharedSymbol<ELF64LE>;
|
template class elf::SharedSymbol<ELF64LE>;
|
||||||
|
|||||||
@@ -76,6 +76,7 @@ public:
|
|||||||
|
|
||||||
bool isInGot() const { return GotIndex != -1U; }
|
bool isInGot() const { return GotIndex != -1U; }
|
||||||
bool isInPlt() const { return PltIndex != -1U; }
|
bool isInPlt() const { return PltIndex != -1U; }
|
||||||
|
template <class ELFT> bool hasThunk() const;
|
||||||
|
|
||||||
template <class ELFT>
|
template <class ELFT>
|
||||||
typename ELFT::uint getVA(typename ELFT::uint Addend = 0) const;
|
typename ELFT::uint getVA(typename ELFT::uint Addend = 0) const;
|
||||||
@@ -85,6 +86,7 @@ public:
|
|||||||
template <class ELFT> typename ELFT::uint getGotPltOffset() const;
|
template <class ELFT> typename ELFT::uint getGotPltOffset() const;
|
||||||
template <class ELFT> typename ELFT::uint getGotPltVA() const;
|
template <class ELFT> typename ELFT::uint getGotPltVA() const;
|
||||||
template <class ELFT> typename ELFT::uint getPltVA() 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;
|
template <class ELFT> typename ELFT::uint getSize() const;
|
||||||
|
|
||||||
// The file from which this symbol was created.
|
// The file from which this symbol was created.
|
||||||
@@ -208,6 +210,10 @@ public:
|
|||||||
// If this is null, the symbol is an absolute symbol.
|
// If this is null, the symbol is an absolute symbol.
|
||||||
InputSectionBase<ELFT> *&Section;
|
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:
|
private:
|
||||||
static InputSectionBase<ELFT> *NullInputSection;
|
static InputSectionBase<ELFT> *NullInputSection;
|
||||||
};
|
};
|
||||||
@@ -236,7 +242,7 @@ public:
|
|||||||
const OutputSectionBase *Section;
|
const OutputSectionBase *Section;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Undefined : public SymbolBody {
|
template <class ELFT> class Undefined : public SymbolBody {
|
||||||
public:
|
public:
|
||||||
Undefined(StringRefZ Name, bool IsLocal, uint8_t StOther, uint8_t Type,
|
Undefined(StringRefZ Name, bool IsLocal, uint8_t StOther, uint8_t Type,
|
||||||
InputFile *F);
|
InputFile *F);
|
||||||
@@ -245,6 +251,12 @@ public:
|
|||||||
return S->kind() == UndefinedKind;
|
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; }
|
InputFile *file() { return this->File; }
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -279,6 +291,9 @@ public:
|
|||||||
// CopyOffset is significant only when needsCopy() is true.
|
// CopyOffset is significant only when needsCopy() is true.
|
||||||
uintX_t CopyOffset = 0;
|
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(); }
|
bool needsCopy() const { return this->NeedsCopyOrPltAddr && !this->isFunc(); }
|
||||||
|
|
||||||
OutputSection<ELFT> *getBssSectionForCopy() const;
|
OutputSection<ELFT> *getBssSectionForCopy() const;
|
||||||
@@ -416,7 +431,8 @@ struct Symbol {
|
|||||||
// ELFT, and we verify this with the static_asserts in replaceBody.
|
// ELFT, and we verify this with the static_asserts in replaceBody.
|
||||||
llvm::AlignedCharArrayUnion<
|
llvm::AlignedCharArrayUnion<
|
||||||
DefinedCommon, DefinedRegular<llvm::object::ELF64LE>, DefinedSynthetic,
|
DefinedCommon, DefinedRegular<llvm::object::ELF64LE>, DefinedSynthetic,
|
||||||
Undefined, SharedSymbol<llvm::object::ELF64LE>, LazyArchive, LazyObject>
|
Undefined<llvm::object::ELF64LE>, SharedSymbol<llvm::object::ELF64LE>,
|
||||||
|
LazyArchive, LazyObject>
|
||||||
Body;
|
Body;
|
||||||
|
|
||||||
SymbolBody *body() { return reinterpret_cast<SymbolBody *>(Body.buffer); }
|
SymbolBody *body() { return reinterpret_cast<SymbolBody *>(Body.buffer); }
|
||||||
|
|||||||
@@ -1904,27 +1904,6 @@ void ARMExidxSentinelSection<ELFT>::writeTo(uint8_t *Buf) {
|
|||||||
write32le(Buf + 4, 0x1);
|
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<ELF32LE> *elf::createCommonSection();
|
||||||
template InputSection<ELF32BE> *elf::createCommonSection();
|
template InputSection<ELF32BE> *elf::createCommonSection();
|
||||||
template InputSection<ELF64LE> *elf::createCommonSection();
|
template InputSection<ELF64LE> *elf::createCommonSection();
|
||||||
@@ -2067,8 +2046,3 @@ template class elf::ARMExidxSentinelSection<ELF32LE>;
|
|||||||
template class elf::ARMExidxSentinelSection<ELF32BE>;
|
template class elf::ARMExidxSentinelSection<ELF32BE>;
|
||||||
template class elf::ARMExidxSentinelSection<ELF64LE>;
|
template class elf::ARMExidxSentinelSection<ELF64LE>;
|
||||||
template class elf::ARMExidxSentinelSection<ELF64BE>;
|
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>;
|
|
||||||
|
|||||||
@@ -699,26 +699,6 @@ public:
|
|||||||
void writeTo(uint8_t *Buf) override;
|
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> *createCommonSection();
|
||||||
template <class ELFT> InputSection<ELFT> *createInterpSection();
|
template <class ELFT> InputSection<ELFT> *createInterpSection();
|
||||||
template <class ELFT> MergeInputSection<ELFT> *createCommentSection();
|
template <class ELFT> MergeInputSection<ELFT> *createCommentSection();
|
||||||
|
|||||||
@@ -228,7 +228,7 @@ public:
|
|||||||
int32_t Index, unsigned RelOff) const override;
|
int32_t Index, unsigned RelOff) const override;
|
||||||
void addPltSymbols(InputSectionData *IS, uint64_t Off) const override;
|
void addPltSymbols(InputSectionData *IS, uint64_t Off) const override;
|
||||||
void addPltHeaderSymbols(InputSectionData *ISD) const override;
|
void addPltHeaderSymbols(InputSectionData *ISD) const override;
|
||||||
bool needsThunk(RelExpr Expr, uint32_t RelocType, const InputFile *File,
|
RelExpr getThunkExpr(RelExpr Expr, uint32_t RelocType, const InputFile *File,
|
||||||
const SymbolBody &S) const override;
|
const SymbolBody &S) const override;
|
||||||
void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
|
void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
|
||||||
};
|
};
|
||||||
@@ -246,7 +246,7 @@ public:
|
|||||||
void writePltHeader(uint8_t *Buf) const override;
|
void writePltHeader(uint8_t *Buf) const override;
|
||||||
void writePlt(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr,
|
void writePlt(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr,
|
||||||
int32_t Index, unsigned RelOff) const override;
|
int32_t Index, unsigned RelOff) const override;
|
||||||
bool needsThunk(RelExpr Expr, uint32_t RelocType, const InputFile *File,
|
RelExpr getThunkExpr(RelExpr Expr, uint32_t RelocType, const InputFile *File,
|
||||||
const SymbolBody &S) const override;
|
const SymbolBody &S) const override;
|
||||||
void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
|
void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
|
||||||
bool usesOnlyLowPageBits(uint32_t Type) const override;
|
bool usesOnlyLowPageBits(uint32_t Type) const override;
|
||||||
@@ -298,9 +298,10 @@ uint64_t TargetInfo::getImplicitAddend(const uint8_t *Buf,
|
|||||||
|
|
||||||
bool TargetInfo::usesOnlyLowPageBits(uint32_t Type) const { return false; }
|
bool TargetInfo::usesOnlyLowPageBits(uint32_t Type) const { return false; }
|
||||||
|
|
||||||
bool TargetInfo::needsThunk(RelExpr Expr, uint32_t RelocType,
|
RelExpr TargetInfo::getThunkExpr(RelExpr Expr, uint32_t RelocType,
|
||||||
const InputFile *File, const SymbolBody &S) const {
|
const InputFile *File,
|
||||||
return false;
|
const SymbolBody &S) const {
|
||||||
|
return Expr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TargetInfo::isTlsInitialExecRel(uint32_t Type) const { return false; }
|
bool TargetInfo::isTlsInitialExecRel(uint32_t Type) const { return false; }
|
||||||
@@ -1770,7 +1771,7 @@ void ARMTargetInfo::addPltSymbols(InputSectionData *ISD, uint64_t Off) const {
|
|||||||
addSyntheticLocal("$d", STT_NOTYPE, Off + 12, 0, IS);
|
addSyntheticLocal("$d", STT_NOTYPE, Off + 12, 0, IS);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ARMTargetInfo::needsThunk(RelExpr Expr, uint32_t RelocType,
|
RelExpr ARMTargetInfo::getThunkExpr(RelExpr Expr, uint32_t RelocType,
|
||||||
const InputFile *File,
|
const InputFile *File,
|
||||||
const SymbolBody &S) const {
|
const SymbolBody &S) const {
|
||||||
// If S is an undefined weak symbol in an executable we don't need a Thunk.
|
// If S is an undefined weak symbol in an executable we don't need a Thunk.
|
||||||
@@ -1778,7 +1779,7 @@ bool ARMTargetInfo::needsThunk(RelExpr Expr, uint32_t RelocType,
|
|||||||
// which may need a thunk.
|
// which may need a thunk.
|
||||||
if (S.isUndefined() && !S.isLocal() && S.symbol()->isWeak() &&
|
if (S.isUndefined() && !S.isLocal() && S.symbol()->isWeak() &&
|
||||||
!Config->Shared)
|
!Config->Shared)
|
||||||
return false;
|
return Expr;
|
||||||
// A state change from ARM to Thumb and vice versa must go through an
|
// 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
|
// interworking thunk if the relocation type is not R_ARM_CALL or
|
||||||
// R_ARM_THM_CALL.
|
// R_ARM_THM_CALL.
|
||||||
@@ -1789,17 +1790,19 @@ bool ARMTargetInfo::needsThunk(RelExpr Expr, uint32_t RelocType,
|
|||||||
// Source is ARM, all PLT entries are ARM so no interworking required.
|
// Source is ARM, all PLT entries are ARM so no interworking required.
|
||||||
// Otherwise we need to interwork if Symbol has bit 0 set (Thumb).
|
// Otherwise we need to interwork if Symbol has bit 0 set (Thumb).
|
||||||
if (Expr == R_PC && ((S.getVA<ELF32LE>() & 1) == 1))
|
if (Expr == R_PC && ((S.getVA<ELF32LE>() & 1) == 1))
|
||||||
return true;
|
return R_THUNK_PC;
|
||||||
break;
|
break;
|
||||||
case R_ARM_THM_JUMP19:
|
case R_ARM_THM_JUMP19:
|
||||||
case R_ARM_THM_JUMP24:
|
case R_ARM_THM_JUMP24:
|
||||||
// Source is Thumb, all PLT entries are ARM so interworking is required.
|
// Source is Thumb, all PLT entries are ARM so interworking is required.
|
||||||
// Otherwise we need to interwork if Symbol has bit 0 clear (ARM).
|
// Otherwise we need to interwork if Symbol has bit 0 clear (ARM).
|
||||||
if (Expr == R_PLT_PC || ((S.getVA<ELF32LE>() & 1) == 0))
|
if (Expr == R_PLT_PC)
|
||||||
return true;
|
return R_THUNK_PLT_PC;
|
||||||
|
if ((S.getVA<ELF32LE>() & 1) == 0)
|
||||||
|
return R_THUNK_PC;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return false;
|
return Expr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ARMTargetInfo::relocateOne(uint8_t *Loc, uint32_t Type,
|
void ARMTargetInfo::relocateOne(uint8_t *Loc, uint32_t Type,
|
||||||
@@ -2212,7 +2215,7 @@ void MipsTargetInfo<ELFT>::writePlt(uint8_t *Buf, uint64_t GotEntryAddr,
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <class ELFT>
|
template <class ELFT>
|
||||||
bool MipsTargetInfo<ELFT>::needsThunk(RelExpr Expr, uint32_t Type,
|
RelExpr MipsTargetInfo<ELFT>::getThunkExpr(RelExpr Expr, uint32_t Type,
|
||||||
const InputFile *File,
|
const InputFile *File,
|
||||||
const SymbolBody &S) const {
|
const SymbolBody &S) const {
|
||||||
// Any MIPS PIC code function is invoked with its address in register $t9.
|
// Any MIPS PIC code function is invoked with its address in register $t9.
|
||||||
@@ -2221,17 +2224,17 @@ bool MipsTargetInfo<ELFT>::needsThunk(RelExpr Expr, uint32_t Type,
|
|||||||
// to save the target function address.
|
// to save the target function address.
|
||||||
// See page 3-38 ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
|
// See page 3-38 ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
|
||||||
if (Type != R_MIPS_26)
|
if (Type != R_MIPS_26)
|
||||||
return false;
|
return Expr;
|
||||||
auto *F = dyn_cast_or_null<ELFFileBase<ELFT>>(File);
|
auto *F = dyn_cast_or_null<ELFFileBase<ELFT>>(File);
|
||||||
if (!F)
|
if (!F)
|
||||||
return false;
|
return Expr;
|
||||||
// If current file has PIC code, LA25 stub is not required.
|
// If current file has PIC code, LA25 stub is not required.
|
||||||
if (F->getObj().getHeader()->e_flags & EF_MIPS_PIC)
|
if (F->getObj().getHeader()->e_flags & EF_MIPS_PIC)
|
||||||
return false;
|
return Expr;
|
||||||
auto *D = dyn_cast<DefinedRegular<ELFT>>(&S);
|
auto *D = dyn_cast<DefinedRegular<ELFT>>(&S);
|
||||||
// LA25 is required if target file has PIC code
|
// LA25 is required if target file has PIC code
|
||||||
// or target symbol is a PIC symbol.
|
// or target symbol is a PIC symbol.
|
||||||
return D && D->isMipsPIC();
|
return D && D->isMipsPIC() ? R_THUNK_ABS : Expr;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class ELFT>
|
template <class ELFT>
|
||||||
|
|||||||
@@ -51,9 +51,14 @@ public:
|
|||||||
virtual bool usesOnlyLowPageBits(uint32_t Type) const;
|
virtual bool usesOnlyLowPageBits(uint32_t Type) const;
|
||||||
|
|
||||||
// Decide whether a Thunk is needed for the relocation from File
|
// Decide whether a Thunk is needed for the relocation from File
|
||||||
// targeting S.
|
// targeting S. Returns one of:
|
||||||
virtual bool needsThunk(RelExpr Expr, uint32_t RelocType,
|
// Expr if there is no Thunk required
|
||||||
const InputFile *File, const SymbolBody &S) const;
|
// 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;
|
||||||
virtual RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const = 0;
|
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 void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const = 0;
|
||||||
virtual ~TargetInfo();
|
virtual ~TargetInfo();
|
||||||
|
|||||||
@@ -28,7 +28,6 @@
|
|||||||
#include "Memory.h"
|
#include "Memory.h"
|
||||||
#include "OutputSections.h"
|
#include "OutputSections.h"
|
||||||
#include "Symbols.h"
|
#include "Symbols.h"
|
||||||
#include "SyntheticSections.h"
|
|
||||||
#include "Target.h"
|
#include "Target.h"
|
||||||
#include "llvm/Support/Casting.h"
|
#include "llvm/Support/Casting.h"
|
||||||
#include "llvm/Support/ELF.h"
|
#include "llvm/Support/ELF.h"
|
||||||
@@ -53,54 +52,53 @@ namespace {
|
|||||||
template <class ELFT>
|
template <class ELFT>
|
||||||
class ARMToThumbV7ABSLongThunk final : public Thunk<ELFT> {
|
class ARMToThumbV7ABSLongThunk final : public Thunk<ELFT> {
|
||||||
public:
|
public:
|
||||||
ARMToThumbV7ABSLongThunk(const SymbolBody &Dest) : Thunk<ELFT>(Dest) {}
|
ARMToThumbV7ABSLongThunk(const SymbolBody &Dest,
|
||||||
|
const InputSection<ELFT> &Owner)
|
||||||
|
: Thunk<ELFT>(Dest, Owner) {}
|
||||||
|
|
||||||
uint32_t size() const override { return 12; }
|
uint32_t size() const override { return 12; }
|
||||||
void writeTo(uint8_t *Buf, ThunkSection<ELFT> &IS) const override;
|
void writeTo(uint8_t *Buf) const override;
|
||||||
void addSymbols(ThunkSection<ELFT> &IS) override;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class ELFT> class ARMToThumbV7PILongThunk final : public Thunk<ELFT> {
|
template <class ELFT> class ARMToThumbV7PILongThunk final : public Thunk<ELFT> {
|
||||||
public:
|
public:
|
||||||
ARMToThumbV7PILongThunk(const SymbolBody &Dest) : Thunk<ELFT>(Dest) {}
|
ARMToThumbV7PILongThunk(const SymbolBody &Dest,
|
||||||
|
const InputSection<ELFT> &Owner)
|
||||||
|
: Thunk<ELFT>(Dest, Owner) {}
|
||||||
|
|
||||||
uint32_t size() const override { return 16; }
|
uint32_t size() const override { return 16; }
|
||||||
void writeTo(uint8_t *Buf, ThunkSection<ELFT> &IS) const override;
|
void writeTo(uint8_t *Buf) const override;
|
||||||
void addSymbols(ThunkSection<ELFT> &IS) override;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class ELFT>
|
template <class ELFT>
|
||||||
class ThumbToARMV7ABSLongThunk final : public Thunk<ELFT> {
|
class ThumbToARMV7ABSLongThunk final : public Thunk<ELFT> {
|
||||||
public:
|
public:
|
||||||
ThumbToARMV7ABSLongThunk(const SymbolBody &Dest) : Thunk<ELFT>(Dest) {
|
ThumbToARMV7ABSLongThunk(const SymbolBody &Dest,
|
||||||
this->alignment = 2;
|
const InputSection<ELFT> &Owner)
|
||||||
}
|
: Thunk<ELFT>(Dest, Owner) {}
|
||||||
|
|
||||||
uint32_t size() const override { return 10; }
|
uint32_t size() const override { return 10; }
|
||||||
void writeTo(uint8_t *Buf, ThunkSection<ELFT> &IS) const override;
|
void writeTo(uint8_t *Buf) const override;
|
||||||
void addSymbols(ThunkSection<ELFT> &IS) override;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class ELFT> class ThumbToARMV7PILongThunk final : public Thunk<ELFT> {
|
template <class ELFT> class ThumbToARMV7PILongThunk final : public Thunk<ELFT> {
|
||||||
public:
|
public:
|
||||||
ThumbToARMV7PILongThunk(const SymbolBody &Dest) : Thunk<ELFT>(Dest) {
|
ThumbToARMV7PILongThunk(const SymbolBody &Dest,
|
||||||
this->alignment = 2;
|
const InputSection<ELFT> &Owner)
|
||||||
}
|
: Thunk<ELFT>(Dest, Owner) {}
|
||||||
|
|
||||||
uint32_t size() const override { return 12; }
|
uint32_t size() const override { return 12; }
|
||||||
void writeTo(uint8_t *Buf, ThunkSection<ELFT> &IS) const override;
|
void writeTo(uint8_t *Buf) const override;
|
||||||
void addSymbols(ThunkSection<ELFT> &IS) override;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// MIPS LA25 thunk
|
// MIPS LA25 thunk
|
||||||
template <class ELFT> class MipsThunk final : public Thunk<ELFT> {
|
template <class ELFT> class MipsThunk final : public Thunk<ELFT> {
|
||||||
public:
|
public:
|
||||||
MipsThunk(const SymbolBody &Dest) : Thunk<ELFT>(Dest) {}
|
MipsThunk(const SymbolBody &Dest, const InputSection<ELFT> &Owner)
|
||||||
|
: Thunk<ELFT>(Dest, Owner) {}
|
||||||
|
|
||||||
uint32_t size() const override { return 16; }
|
uint32_t size() const override { return 16; }
|
||||||
void writeTo(uint8_t *Buf, ThunkSection<ELFT> &IS) const override;
|
void writeTo(uint8_t *Buf) const override;
|
||||||
void addSymbols(ThunkSection<ELFT> &IS) override;
|
|
||||||
InputSection<ELFT> *getTargetInputSection() const override;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // end anonymous namespace
|
} // end anonymous namespace
|
||||||
@@ -112,8 +110,7 @@ template <class ELFT> static uint64_t getARMThunkDestVA(const SymbolBody &S) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <class ELFT>
|
template <class ELFT>
|
||||||
void ARMToThumbV7ABSLongThunk<ELFT>::writeTo(uint8_t *Buf,
|
void ARMToThumbV7ABSLongThunk<ELFT>::writeTo(uint8_t *Buf) const {
|
||||||
ThunkSection<ELFT> &IS) const {
|
|
||||||
const uint8_t Data[] = {
|
const uint8_t Data[] = {
|
||||||
0x00, 0xc0, 0x00, 0xe3, // movw ip,:lower16:S
|
0x00, 0xc0, 0x00, 0xe3, // movw ip,:lower16:S
|
||||||
0x00, 0xc0, 0x40, 0xe3, // movt ip,:upper16:S
|
0x00, 0xc0, 0x40, 0xe3, // movt ip,:upper16:S
|
||||||
@@ -126,16 +123,7 @@ void ARMToThumbV7ABSLongThunk<ELFT>::writeTo(uint8_t *Buf,
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <class ELFT>
|
template <class ELFT>
|
||||||
void ARMToThumbV7ABSLongThunk<ELFT>::addSymbols(ThunkSection<ELFT> &IS) {
|
void ThumbToARMV7ABSLongThunk<ELFT>::writeTo(uint8_t *Buf) const {
|
||||||
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[] = {
|
const uint8_t Data[] = {
|
||||||
0x40, 0xf2, 0x00, 0x0c, // movw ip, :lower16:S
|
0x40, 0xf2, 0x00, 0x0c, // movw ip, :lower16:S
|
||||||
0xc0, 0xf2, 0x00, 0x0c, // movt ip, :upper16:S
|
0xc0, 0xf2, 0x00, 0x0c, // movt ip, :upper16:S
|
||||||
@@ -148,16 +136,7 @@ void ThumbToARMV7ABSLongThunk<ELFT>::writeTo(uint8_t *Buf,
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <class ELFT>
|
template <class ELFT>
|
||||||
void ThumbToARMV7ABSLongThunk<ELFT>::addSymbols(ThunkSection<ELFT> &IS) {
|
void ARMToThumbV7PILongThunk<ELFT>::writeTo(uint8_t *Buf) const {
|
||||||
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[] = {
|
const uint8_t Data[] = {
|
||||||
0xf0, 0xcf, 0x0f, 0xe3, // P: movw ip,:lower16:S - (P + (L1-P) +8)
|
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)
|
0x00, 0xc0, 0x40, 0xe3, // movt ip,:upper16:S - (P + (L1-P+4) +8)
|
||||||
@@ -165,23 +144,14 @@ void ARMToThumbV7PILongThunk<ELFT>::writeTo(uint8_t *Buf,
|
|||||||
0x1c, 0xff, 0x2f, 0xe1, // bx r12
|
0x1c, 0xff, 0x2f, 0xe1, // bx r12
|
||||||
};
|
};
|
||||||
uint64_t S = getARMThunkDestVA<ELFT>(this->Destination);
|
uint64_t S = getARMThunkDestVA<ELFT>(this->Destination);
|
||||||
uint64_t P = this->ThunkSym->template getVA<ELFT>();
|
uint64_t P = this->getVA();
|
||||||
memcpy(Buf, Data, sizeof(Data));
|
memcpy(Buf, Data, sizeof(Data));
|
||||||
Target->relocateOne(Buf, R_ARM_MOVW_PREL_NC, S - P - 16);
|
Target->relocateOne(Buf, R_ARM_MOVW_PREL_NC, S - P - 16);
|
||||||
Target->relocateOne(Buf + 4, R_ARM_MOVT_PREL, S - P - 12);
|
Target->relocateOne(Buf + 4, R_ARM_MOVT_PREL, S - P - 12);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class ELFT>
|
template <class ELFT>
|
||||||
void ARMToThumbV7PILongThunk<ELFT>::addSymbols(ThunkSection<ELFT> &IS) {
|
void ThumbToARMV7PILongThunk<ELFT>::writeTo(uint8_t *Buf) const {
|
||||||
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[] = {
|
const uint8_t Data[] = {
|
||||||
0x4f, 0xf6, 0xf4, 0x7c, // P: movw ip,:lower16:S - (P + (L1-P) + 4)
|
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)
|
0xc0, 0xf2, 0x00, 0x0c, // movt ip,:upper16:S - (P + (L1-P+4) + 4)
|
||||||
@@ -189,23 +159,14 @@ void ThumbToARMV7PILongThunk<ELFT>::writeTo(uint8_t *Buf,
|
|||||||
0x60, 0x47, // bx r12
|
0x60, 0x47, // bx r12
|
||||||
};
|
};
|
||||||
uint64_t S = getARMThunkDestVA<ELFT>(this->Destination);
|
uint64_t S = getARMThunkDestVA<ELFT>(this->Destination);
|
||||||
uint64_t P = this->ThunkSym->template getVA<ELFT>();
|
uint64_t P = this->getVA();
|
||||||
memcpy(Buf, Data, sizeof(Data));
|
memcpy(Buf, Data, sizeof(Data));
|
||||||
Target->relocateOne(Buf, R_ARM_THM_MOVW_PREL_NC, S - P - 12);
|
Target->relocateOne(Buf, R_ARM_THM_MOVW_PREL_NC, S - P - 12);
|
||||||
Target->relocateOne(Buf + 4, R_ARM_THM_MOVT_PREL, S - P - 8);
|
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.
|
// Write MIPS LA25 thunk code to call PIC function from the non-PIC one.
|
||||||
template <class ELFT>
|
template <class ELFT> void MipsThunk<ELFT>::writeTo(uint8_t *Buf) const {
|
||||||
void MipsThunk<ELFT>::writeTo(uint8_t *Buf, ThunkSection<ELFT> &) const {
|
|
||||||
const endianness E = ELFT::TargetEndianness;
|
const endianness E = ELFT::TargetEndianness;
|
||||||
|
|
||||||
uint64_t S = this->Destination.template getVA<ELFT>();
|
uint64_t S = this->Destination.template getVA<ELFT>();
|
||||||
@@ -217,26 +178,20 @@ void MipsThunk<ELFT>::writeTo(uint8_t *Buf, ThunkSection<ELFT> &) const {
|
|||||||
Target->relocateOne(Buf + 8, R_MIPS_LO16, S);
|
Target->relocateOne(Buf + 8, R_MIPS_LO16, S);
|
||||||
}
|
}
|
||||||
|
|
||||||
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>
|
template <class ELFT>
|
||||||
InputSection<ELFT> *MipsThunk<ELFT>::getTargetInputSection() const {
|
Thunk<ELFT>::Thunk(const SymbolBody &D, const InputSection<ELFT> &O)
|
||||||
auto *DR = dyn_cast<DefinedRegular<ELFT>>(&this->Destination);
|
: Destination(D), Owner(O), Offset(O.getThunkOff() + O.getThunksSize()) {}
|
||||||
return dyn_cast<InputSection<ELFT>>(DR->Section);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class ELFT>
|
template <class ELFT> typename ELFT::uint Thunk<ELFT>::getVA() const {
|
||||||
Thunk<ELFT>::Thunk(const SymbolBody &D) : Destination(D), Offset(0) {}
|
return Owner.OutSec->Addr + Owner.OutSecOff + Offset;
|
||||||
|
}
|
||||||
|
|
||||||
template <class ELFT> Thunk<ELFT>::~Thunk() = default;
|
template <class ELFT> Thunk<ELFT>::~Thunk() = default;
|
||||||
|
|
||||||
// Creates a thunk for Thumb-ARM interworking.
|
// Creates a thunk for Thumb-ARM interworking.
|
||||||
template <class ELFT>
|
template <class ELFT>
|
||||||
static Thunk<ELFT> *addThunkArm(uint32_t Reloc, SymbolBody &S) {
|
static Thunk<ELFT> *createThunkArm(uint32_t Reloc, SymbolBody &S,
|
||||||
|
InputSection<ELFT> &IS) {
|
||||||
// ARM relocations need ARM to Thumb interworking Thunks.
|
// ARM relocations need ARM to Thumb interworking Thunks.
|
||||||
// Thumb relocations need Thumb to ARM relocations.
|
// Thumb relocations need Thumb to ARM relocations.
|
||||||
// Use position independent Thunks if we require position independent code.
|
// Use position independent Thunks if we require position independent code.
|
||||||
@@ -245,34 +200,71 @@ static Thunk<ELFT> *addThunkArm(uint32_t Reloc, SymbolBody &S) {
|
|||||||
case R_ARM_PLT32:
|
case R_ARM_PLT32:
|
||||||
case R_ARM_JUMP24:
|
case R_ARM_JUMP24:
|
||||||
if (Config->Pic)
|
if (Config->Pic)
|
||||||
return make<ARMToThumbV7PILongThunk<ELFT>>(S);
|
return new (BAlloc) ARMToThumbV7PILongThunk<ELFT>(S, IS);
|
||||||
return make<ARMToThumbV7ABSLongThunk<ELFT>>(S);
|
return new (BAlloc) ARMToThumbV7ABSLongThunk<ELFT>(S, IS);
|
||||||
case R_ARM_THM_JUMP19:
|
case R_ARM_THM_JUMP19:
|
||||||
case R_ARM_THM_JUMP24:
|
case R_ARM_THM_JUMP24:
|
||||||
if (Config->Pic)
|
if (Config->Pic)
|
||||||
return make<ThumbToARMV7PILongThunk<ELFT>>(S);
|
return new (BAlloc) ThumbToARMV7PILongThunk<ELFT>(S, IS);
|
||||||
return make<ThumbToARMV7ABSLongThunk<ELFT>>(S);
|
return new (BAlloc) ThumbToARMV7ABSLongThunk<ELFT>(S, IS);
|
||||||
}
|
}
|
||||||
fatal("unrecognized relocation type");
|
fatal("unrecognized relocation type");
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class ELFT> static Thunk<ELFT> *addThunkMips(SymbolBody &S) {
|
template <class ELFT>
|
||||||
return make<MipsThunk<ELFT>>(S);
|
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> Thunk<ELFT> *addThunk(uint32_t RelocType, SymbolBody &S) {
|
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>
|
||||||
|
void addThunk(uint32_t RelocType, SymbolBody &S, InputSection<ELFT> &IS) {
|
||||||
if (Config->EMachine == EM_ARM)
|
if (Config->EMachine == EM_ARM)
|
||||||
return addThunkArm<ELFT>(RelocType, S);
|
addThunkARM<ELFT>(RelocType, S, IS);
|
||||||
else if (Config->EMachine == EM_MIPS)
|
else if (Config->EMachine == EM_MIPS)
|
||||||
return addThunkMips<ELFT>(S);
|
addThunkMips<ELFT>(RelocType, S, IS);
|
||||||
|
else
|
||||||
llvm_unreachable("add Thunk only supported for ARM and Mips");
|
llvm_unreachable("add Thunk only supported for ARM and Mips");
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template Thunk<ELF32LE> *addThunk<ELF32LE>(uint32_t, SymbolBody &);
|
template void addThunk<ELF32LE>(uint32_t, SymbolBody &,
|
||||||
template Thunk<ELF32BE> *addThunk<ELF32BE>(uint32_t, SymbolBody &);
|
InputSection<ELF32LE> &);
|
||||||
template Thunk<ELF64LE> *addThunk<ELF64LE>(uint32_t, SymbolBody &);
|
template void addThunk<ELF32BE>(uint32_t, SymbolBody &,
|
||||||
template Thunk<ELF64BE> *addThunk<ELF64BE>(uint32_t, SymbolBody &);
|
InputSection<ELF32BE> &);
|
||||||
|
template void addThunk<ELF64LE>(uint32_t, SymbolBody &,
|
||||||
|
InputSection<ELF64LE> &);
|
||||||
|
template void addThunk<ELF64BE>(uint32_t, SymbolBody &,
|
||||||
|
InputSection<ELF64BE> &);
|
||||||
|
|
||||||
template class Thunk<ELF32LE>;
|
template class Thunk<ELF32LE>;
|
||||||
template class Thunk<ELF32BE>;
|
template class Thunk<ELF32BE>;
|
||||||
|
|||||||
@@ -15,8 +15,8 @@
|
|||||||
namespace lld {
|
namespace lld {
|
||||||
namespace elf {
|
namespace elf {
|
||||||
class SymbolBody;
|
class SymbolBody;
|
||||||
template <class ELFT> class ThunkSection;
|
template <class ELFT> class InputSection;
|
||||||
class OutputSectionBase;
|
|
||||||
// Class to describe an instance of a Thunk.
|
// Class to describe an instance of a Thunk.
|
||||||
// A Thunk is a code-sequence inserted by the linker in between a caller and
|
// 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
|
// the callee. The relocation to the callee is redirected to the Thunk, which
|
||||||
@@ -24,35 +24,31 @@ class OutputSectionBase;
|
|||||||
// include transferring control from non-pi to pi and changing state on
|
// include transferring control from non-pi to pi and changing state on
|
||||||
// targets like ARM.
|
// targets like ARM.
|
||||||
//
|
//
|
||||||
// Thunks can be created for DefinedRegular, Shared and Undefined Symbols.
|
// Thunks can be created for DefinedRegular and Shared Symbols. The Thunk
|
||||||
// Thunks are assigned to synthetic ThunkSections
|
// is stored in a field of the Symbol Destination.
|
||||||
|
// Thunks to be written to an InputSection are recorded by the InputSection.
|
||||||
template <class ELFT> class Thunk {
|
template <class ELFT> class Thunk {
|
||||||
|
typedef typename ELFT::uint uintX_t;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Thunk(const SymbolBody &Destination);
|
Thunk(const SymbolBody &Destination, const InputSection<ELFT> &Owner);
|
||||||
virtual ~Thunk();
|
virtual ~Thunk();
|
||||||
|
|
||||||
virtual uint32_t size() const { return 0; }
|
virtual uint32_t size() const { return 0; }
|
||||||
virtual void writeTo(uint8_t *Buf, ThunkSection<ELFT> &IS) const {}
|
virtual void writeTo(uint8_t *Buf) const {}
|
||||||
|
uintX_t getVA() const;
|
||||||
|
|
||||||
// All Thunks must define at least one symbol ThunkSym so that we can
|
protected:
|
||||||
// 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; }
|
|
||||||
|
|
||||||
// The alignment requirement for this Thunk, defaults to the size of the
|
|
||||||
// typical code section alignment.
|
|
||||||
const SymbolBody &Destination;
|
const SymbolBody &Destination;
|
||||||
SymbolBody *ThunkSym;
|
const InputSection<ELFT> &Owner;
|
||||||
uint64_t Offset;
|
uint64_t Offset;
|
||||||
uint32_t alignment = 4;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// For a Relocation to symbol S create a Thunk to be added to a synthetic
|
// For a Relocation to symbol S from InputSection Src, create a Thunk and
|
||||||
// ThunkSection. At present there are implementations for ARM and Mips Thunks.
|
// update the fields of S and the InputSection that the Thunk body will be
|
||||||
template <class ELFT> Thunk<ELFT> *addThunk(uint32_t RelocType, SymbolBody &S);
|
// 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);
|
||||||
|
|
||||||
} // namespace elf
|
} // namespace elf
|
||||||
} // namespace lld
|
} // namespace lld
|
||||||
|
|||||||
@@ -1027,12 +1027,6 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
|
|||||||
if (In<ELFT>::Iplt && !In<ELFT>::Iplt->empty())
|
if (In<ELFT>::Iplt && !In<ELFT>::Iplt->empty())
|
||||||
In<ELFT>::Iplt->addSymbols();
|
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-
|
// Now that we have defined all possible symbols including linker-
|
||||||
// synthesized ones. Visit all symbols to give the finishing touches.
|
// synthesized ones. Visit all symbols to give the finishing touches.
|
||||||
for (Symbol *S : Symtab<ELFT>::X->getSymbols()) {
|
for (Symbol *S : Symtab<ELFT>::X->getSymbols()) {
|
||||||
@@ -1078,6 +1072,12 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
|
|||||||
fixHeaders();
|
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
|
// Fill other section headers. The dynamic table is finalized
|
||||||
// at the end because some tags like RELSZ depend on result
|
// at the end because some tags like RELSZ depend on result
|
||||||
// of finalizing other sections.
|
// of finalizing other sections.
|
||||||
|
|||||||
@@ -16,15 +16,12 @@ sym1:
|
|||||||
|
|
||||||
// CHECK: Disassembly of section .text:
|
// CHECK: Disassembly of section .text:
|
||||||
// CHECK-NEXT: sym1:
|
// CHECK-NEXT: sym1:
|
||||||
// CHECK-NEXT: 1000: 00 f0 02 b8 b.w #4 <__ThumbToARMV7PILongThunk_elsewhere+0x4>
|
// CHECK: 1000: 00 f0 02 b8 b.w #4
|
||||||
// CHECK-NEXT: 1004: 00 f0 06 b8 b.w #12 <__ThumbToARMV7PILongThunk_weakref+0x4>
|
// CHECK-NEXT: 1004: 00 f0 06 b8 b.w #12
|
||||||
// CHECK: __ThumbToARMV7PILongThunk_elsewhere:
|
|
||||||
// CHECK-NEXT: 1008: 40 f2 20 0c movw r12, #32
|
// CHECK-NEXT: 1008: 40 f2 20 0c movw r12, #32
|
||||||
// CHECK-NEXT: 100c: c0 f2 00 0c movt r12, #0
|
// CHECK-NEXT: 100c: c0 f2 00 0c movt r12, #0
|
||||||
// CHECK-NEXT: 1010: fc 44 add r12, pc
|
// CHECK-NEXT: 1010: fc 44 add r12, pc
|
||||||
// CHECK-NEXT: 1012: 60 47 bx r12
|
// CHECK-NEXT: 1012: 60 47 bx r12
|
||||||
|
|
||||||
// CHECK: __ThumbToARMV7PILongThunk_weakref:
|
|
||||||
// CHECK-NEXT: 1014: 40 f2 24 0c movw r12, #36
|
// CHECK-NEXT: 1014: 40 f2 24 0c movw r12, #36
|
||||||
// CHECK-NEXT: 1018: c0 f2 00 0c movt r12, #0
|
// CHECK-NEXT: 1018: c0 f2 00 0c movt r12, #0
|
||||||
// CHECK-NEXT: 101c: fc 44 add r12, pc
|
// CHECK-NEXT: 101c: fc 44 add r12, pc
|
||||||
|
|||||||
@@ -78,65 +78,62 @@ arm_caller:
|
|||||||
beq arm_callee2
|
beq arm_callee2
|
||||||
bne arm_callee3
|
bne arm_callee3
|
||||||
bx lr
|
bx lr
|
||||||
// CHECK-ARM-ABS-ARM: Disassembly of section .arm_caller:
|
// CHECK-ABS-ARM: Disassembly of section .arm_caller:
|
||||||
// CHECK-ARM-ABS-ARM-NEXT: arm_caller:
|
// CHECK-ABS-ARM-NEXT: arm_caller:
|
||||||
// CHECK-ARM-ABS-ARM-NEXT: 1300: 3e ff ff fa blx #-776 <thumb_callee1>
|
// CHECK-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-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-ABS-ARM-NEXT: 1308: 06 00 00 ea b #24 <arm_caller+0x28>
|
||||||
// CHECK-ARM-ABS-ARM-NEXT: 130c: 05 00 00 ea b #20 <__ARMToThumbv7ABSLongThunk_thumb_callee1>
|
// CHECK-ABS-ARM-NEXT: 130c: 05 00 00 ea b #20 <arm_caller+0x28>
|
||||||
// CHECK-ARM-ABS-ARM-NEXT: 1310: 07 00 00 ea b #28 <__ARMToThumbv7ABSLongThunk_thumb_callee2>
|
// CHECK-ABS-ARM-NEXT: 1310: 07 00 00 ea b #28 <arm_caller+0x34>
|
||||||
// CHECK-ARM-ABS-ARM-NEXT: 1314: 09 00 00 ea b #36 <__ARMToThumbv7ABSLongThunk_thumb_callee3>
|
// CHECK-ABS-ARM-NEXT: 1314: 09 00 00 ea b #36 <arm_caller+0x40>
|
||||||
// CHECK-ARM-ABS-ARM-NEXT: 1318: 78 ff ff ea b #-544 <arm_callee1>
|
// CHECK-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-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-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-ABS-ARM-NEXT: 1324: 1e ff 2f e1 bx lr
|
||||||
// CHECK-ARM-ABS-ARM: __ARMToThumbv7ABSLongThunk_thumb_callee1:
|
|
||||||
// 0x1001 = thumb_callee1
|
// 0x1001 = thumb_callee1
|
||||||
// CHECK-ARM-ABS-ARM-NEXT: 1328: 01 c0 01 e3 movw r12, #4097
|
// CHECK-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-ABS-ARM-NEXT: 132c: 00 c0 40 e3 movt r12, #0
|
||||||
// CHECK-ARM-ABS-ARM-NEXT: 1330: 1c ff 2f e1 bx r12
|
// CHECK-ABS-ARM-NEXT: 1330: 1c ff 2f e1 bx r12
|
||||||
// 0x1501 = thumb_callee2
|
// 0x1501 = thumb_callee2
|
||||||
// CHECK-ARM-ABS-ARM: __ARMToThumbv7ABSLongThunk_thumb_callee2:
|
// CHECK-ABS-ARM-NEXT: 1334: 01 c5 01 e3 movw r12, #5377
|
||||||
// CHECK-ARM-ABS-ARM-NEXT: 1334: 01 c5 01 e3 movw r12, #5377
|
// CHECK-ABS-ARM-NEXT: 1338: 00 c0 40 e3 movt r12, #0
|
||||||
// CHECK-ARM-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-NEXT: 133c: 1c ff 2f e1 bx r12
|
|
||||||
// 0x1503 = thumb_callee3
|
// 0x1503 = thumb_callee3
|
||||||
// CHECK-ARM-ABS-ARM: __ARMToThumbv7ABSLongThunk_thumb_callee3:
|
// CHECK-ABS-ARM-NEXT: 1340: 03 c5 01 e3 movw r12, #5379
|
||||||
// CHECK-ARM-ABS-ARM-NEXT: 1340: 03 c5 01 e3 movw r12, #5379
|
// CHECK-ABS-ARM-NEXT: 1344: 00 c0 40 e3 movt r12, #0
|
||||||
// CHECK-ARM-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-NEXT: 1348: 1c ff 2f e1 bx r12
|
|
||||||
|
|
||||||
// CHECK-PI-ARM: Disassembly of section .arm_caller:
|
// CHECK-PI-ARM: Disassembly of section .arm_caller:
|
||||||
// CHECK-PI-ARM-NEXT: 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: 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: 1304: 3d ff ff fa blx #-780 <thumb_callee1>
|
||||||
// CHECK-PI-ARM-NEXT: 1308: 06 00 00 ea b #24 <__ARMToThumbV7PILongThunk_thumb_callee1>
|
// 0x1308 + 8 + 0x18 = 0x1328
|
||||||
// CHECK-PI-ARM-NEXT: 130c: 05 00 00 ea b #20 <__ARMToThumbV7PILongThunk_thumb_callee1>
|
// CHECK-PI-ARM-NEXT: 1308: 06 00 00 ea b #24 <arm_caller+0x28>
|
||||||
// CHECK-PI-ARM-NEXT: 1310: 08 00 00 ea b #32 <__ARMToThumbV7PILongThunk_thumb_callee2>
|
// 0x130c + 8 + 0x14 = 0x1328
|
||||||
// CHECK-PI-ARM-NEXT: 1314: 0b 00 00 ea b #44 <__ARMToThumbV7PILongThunk_thumb_callee3>
|
// 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: 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: 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: 1320: b7 00 00 1a bne #732 <arm_callee3>
|
||||||
// CHECK-PI-ARM-NEXT: 1324: 1e ff 2f e1 bx lr
|
// CHECK-PI-ARM-NEXT: 1324: 1e ff 2f e1 bx lr
|
||||||
// CHECK-PI-ARM: __ARMToThumbV7PILongThunk_thumb_callee1:
|
|
||||||
// 0x1330 + 8 - 0x337 = 0x1001 = thumb_callee1
|
// 0x1330 + 8 - 0x337 = 0x1001 = thumb_callee1
|
||||||
// CHECK-PI-ARM-NEXT: 1328: c9 cc 0f e3 movw r12, #64713
|
// 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: 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: 1330: 0f c0 8c e0 add r12, r12, pc
|
||||||
// CHECK-PI-ARM-NEXT: 1334: 1c ff 2f e1 bx r12
|
// CHECK-PI-ARM-NEXT: 1334: 1c ff 2f e1 bx r12
|
||||||
// CHECK-PI-ARM: __ARMToThumbV7PILongThunk_thumb_callee2:
|
// 0x1340 + 8 + 0x1b9 = 0x1501
|
||||||
|
|
||||||
// CHECK-PI-ARM-NEXT: 1338: b9 c1 00 e3 movw r12, #441
|
// 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: 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: 1340: 0f c0 8c e0 add r12, r12, pc
|
||||||
// CHECK-PI-ARM-NEXT: 1344: 1c ff 2f e1 bx r12
|
// CHECK-PI-ARM-NEXT: 1344: 1c ff 2f e1 bx r12
|
||||||
// CHECK-PI-ARM: __ARMToThumbV7PILongThunk_thumb_callee3:
|
// 1350 + 8 + 0x1ab = 0x1503
|
||||||
// 0x1340 + 8 + 0x1b9 = 0x1501
|
|
||||||
// CHECK-PI-ARM-NEXT: 1348: ab c1 00 e3 movw r12, #427
|
// 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: 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: 1350: 0f c0 8c e0 add r12, r12, pc
|
||||||
// CHECK-PI-ARM-NEXT: 1354: 1c ff 2f e1 bx r12
|
// CHECK-PI-ARM-NEXT: 1354: 1c ff 2f e1 bx r12
|
||||||
// 1350 + 8 + 0x1ab = 0x1503
|
|
||||||
|
|
||||||
// All PLT entries are ARM, no need for interworking thunks
|
// All PLT entries are ARM, no need for interworking thunks
|
||||||
// CHECK-PI-ARM-PLT: Disassembly of section .arm_caller:
|
// CHECK-PI-ARM-PLT: Disassembly of section .arm_caller:
|
||||||
@@ -185,26 +182,31 @@ thumb_caller:
|
|||||||
bne.w arm_callee3
|
bne.w arm_callee3
|
||||||
// CHECK-ABS-THUMB: Disassembly of section .thumb_caller:
|
// CHECK-ABS-THUMB: Disassembly of section .thumb_caller:
|
||||||
// CHECK-ABS-THUMB-NEXT: 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
|
// 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
|
// 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>
|
// 0x1408 + 4 + 0x14 = 0x520
|
||||||
// CHECK-ABS-THUMB-NEXT: 140c: 00 f0 0d b8 b.w #26 <__ThumbToARMv7ABSLongThunk_arm_callee2+0x4>
|
// CHECK-ABS-THUMB-NEXT: 1408: 00 f0 0a b8 b.w #20
|
||||||
// CHECK-ABS-THUMB-NEXT: 1410: 00 f0 10 b8 b.w #32 <__ThumbToARMv7ABSLongThunk_arm_callee3+0x4>
|
// 0x140c + 4 + 0x1a = 0x52a
|
||||||
// CHECK-ABS-THUMB-NEXT: 1414: 00 f0 04 80 beq.w #8 <__ThumbToARMv7ABSLongThunk_arm_callee1+0x4>
|
// CHECK-ABS-THUMB-NEXT: 140c: 00 f0 0d b8 b.w #26
|
||||||
// CHECK-ABS-THUMB-NEXT: 1418: 00 f0 07 80 beq.w #14 <__ThumbToARMv7ABSLongThunk_arm_callee2+0x4>
|
// 0x1410 + 4 + 0x20 = 0x534
|
||||||
// CHECK-ABS-THUMB-NEXT: 141c: 40 f0 0a 80 bne.w #20 <__ThumbToARMv7ABSLongThunk_arm_callee3+0x4>
|
// CHECK-ABS-THUMB-NEXT: 1410: 00 f0 10 b8 b.w #32
|
||||||
// CHECK-ABS-THUMB: __ThumbToARMv7ABSLongThunk_arm_callee1:
|
// 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
|
||||||
// 0x1100 = arm_callee1
|
// 0x1100 = arm_callee1
|
||||||
// CHECK-ABS-THUMB-NEXT: 1420: 41 f2 00 1c movw r12, #4352
|
// 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: 1424: c0 f2 00 0c movt r12, #0
|
||||||
// CHECK-ABS-THUMB-NEXT: 1428: 60 47 bx r12
|
// CHECK-ABS-THUMB-NEXT: 1428: 60 47 bx r12
|
||||||
// CHECK-ABS-THUMB: __ThumbToARMv7ABSLongThunk_arm_callee2:
|
|
||||||
// 0x1600 = arm_callee2
|
// 0x1600 = arm_callee2
|
||||||
// CHECK-ABS-THUMB-NEXT: 142a: 41 f2 00 6c movw r12, #5632
|
// 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: 142e: c0 f2 00 0c movt r12, #0
|
||||||
// CHECK-ABS-THUMB-NEXT: 1432: 60 47 bx r12
|
// CHECK-ABS-THUMB-NEXT: 1432: 60 47 bx r12
|
||||||
// 0x1604 = arm_callee3
|
// 0x1604 = arm_callee3
|
||||||
// CHECK-ABS-THUMB: __ThumbToARMv7ABSLongThunk_arm_callee3:
|
|
||||||
// CHECK-ABS-THUMB-NEXT: 1434: 41 f2 04 6c movw r12, #5636
|
// 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: 1438: c0 f2 00 0c movt r12, #0
|
||||||
// CHECK-ABS-THUMB-NEXT: 143c: 60 47 bx r12
|
// CHECK-ABS-THUMB-NEXT: 143c: 60 47 bx r12
|
||||||
@@ -213,25 +215,22 @@ thumb_caller:
|
|||||||
// CHECK-PI-THUMB-NEXT: thumb_caller:
|
// CHECK-PI-THUMB-NEXT: thumb_caller:
|
||||||
// CHECK-PI-THUMB-NEXT: 1400: ff f7 7e ee blx #-772
|
// 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: 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: 1408: 00 f0 0a b8 b.w #20
|
||||||
// CHECK-PI-THUMB-NEXT: 140c: 00 f0 0e b8 b.w #28 <__ThumbToARMV7PILongThunk_arm_callee2+0x4>
|
// CHECK-PI-THUMB-NEXT: 140c: 00 f0 0e b8 b.w #28
|
||||||
// CHECK-PI-THUMB-NEXT: 1410: 00 f0 12 b8 b.w #36 <__ThumbToARMV7PILongThunk_arm_callee3+0x4>
|
// CHECK-PI-THUMB-NEXT: 1410: 00 f0 12 b8 b.w #36
|
||||||
// CHECK-PI-THUMB-NEXT: 1414: 00 f0 04 80 beq.w #8 <__ThumbToARMV7PILongThunk_arm_callee1+0x4>
|
// CHECK-PI-THUMB-NEXT: 1414: 00 f0 04 80 beq.w #8
|
||||||
// CHECK-PI-THUMB-NEXT: 1418: 00 f0 08 80 beq.w #16 <__ThumbToARMV7PILongThunk_arm_callee2+0x4>
|
// CHECK-PI-THUMB-NEXT: 1418: 00 f0 08 80 beq.w #16
|
||||||
// CHECK-PI-THUMB-NEXT: 141c: 40 f0 0c 80 bne.w #24 <__ThumbToARMV7PILongThunk_arm_callee3+0x4>
|
// CHECK-PI-THUMB-NEXT: 141c: 40 f0 0c 80 bne.w #24
|
||||||
// CHECK-PI-THUMB: __ThumbToARMV7PILongThunk_arm_callee1:
|
|
||||||
// 0x1428 + 4 - 0x32c = 0x1100 = arm_callee1
|
// 0x1428 + 4 - 0x32c = 0x1100 = arm_callee1
|
||||||
// CHECK-PI-THUMB-NEXT: 1420: 4f f6 d4 4c movw r12, #64724
|
// 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: 1424: cf f6 ff 7c movt r12, #65535
|
||||||
// CHECK-PI-THUMB-NEXT: 1428: fc 44 add r12, pc
|
// CHECK-PI-THUMB-NEXT: 1428: fc 44 add r12, pc
|
||||||
// CHECK-PI-THUMB-NEXT: 142a: 60 47 bx r12
|
// CHECK-PI-THUMB-NEXT: 142a: 60 47 bx r12
|
||||||
// CHECK-PI-THUMB: __ThumbToARMV7PILongThunk_arm_callee2:
|
|
||||||
// 0x1434 + 4 + 0x1c8 = 0x1600 = arm_callee2
|
// 0x1434 + 4 + 0x1c8 = 0x1600 = arm_callee2
|
||||||
// CHECK-PI-THUMB-NEXT: 142c: 40 f2 c8 1c movw r12, #456
|
// 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: 1430: c0 f2 00 0c movt r12, #0
|
||||||
// CHECK-PI-THUMB-NEXT: 1434: fc 44 add r12, pc
|
// CHECK-PI-THUMB-NEXT: 1434: fc 44 add r12, pc
|
||||||
// CHECK-PI-THUMB-NEXT: 1436: 60 47 bx r12
|
// CHECK-PI-THUMB-NEXT: 1436: 60 47 bx r12
|
||||||
// CHECK-PI-THUMB: __ThumbToARMV7PILongThunk_arm_callee3:
|
|
||||||
// 0x1440 + 4 + 0x1c0 = 0x1604 = arm_callee3
|
// 0x1440 + 4 + 0x1c0 = 0x1604 = arm_callee3
|
||||||
// CHECK-PI-THUMB-NEXT: 1438: 40 f2 c0 1c movw r12, #448
|
// 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: 143c: c0 f2 00 0c movt r12, #0
|
||||||
|
|||||||
@@ -15,65 +15,60 @@
|
|||||||
|
|
||||||
# CHECK: Disassembly of section .text:
|
# CHECK: Disassembly of section .text:
|
||||||
# CHECK-NEXT: __start:
|
# CHECK-NEXT: __start:
|
||||||
# CHECK-NEXT: 20000: 0c 00 80 0c jal 131120 <__LA25Thunk_foo1a>
|
# CHECK-NEXT: 20000: 0c 00 80 0e jal 131128 <foo1b+0x4>
|
||||||
|
# ^-- .pic.foo1a
|
||||||
# CHECK-NEXT: 20004: 00 00 00 00 nop
|
# CHECK-NEXT: 20004: 00 00 00 00 nop
|
||||||
# CHECK-NEXT: 20008: 0c 00 80 16 jal 131160 <__LA25Thunk_foo2>
|
# CHECK-NEXT: 20008: 0c 00 80 19 jal 131172 <foo2+0x4>
|
||||||
|
# ^-- .pic.foo2
|
||||||
# CHECK-NEXT: 2000c: 00 00 00 00 nop
|
# CHECK-NEXT: 2000c: 00 00 00 00 nop
|
||||||
# CHECK-NEXT: 20010: 0c 00 80 10 jal 131136 <__LA25Thunk_foo1b>
|
# CHECK-NEXT: 20010: 0c 00 80 12 jal 131144 <foo1b+0x14>
|
||||||
|
# ^-- .pic.foo1b
|
||||||
# CHECK-NEXT: 20014: 00 00 00 00 nop
|
# CHECK-NEXT: 20014: 00 00 00 00 nop
|
||||||
# CHECK-NEXT: 20018: 0c 00 80 16 jal 131160 <__LA25Thunk_foo2>
|
# CHECK-NEXT: 20018: 0c 00 80 19 jal 131172 <foo2+0x4>
|
||||||
|
# ^-- .pic.foo2
|
||||||
# CHECK-NEXT: 2001c: 00 00 00 00 nop
|
# CHECK-NEXT: 2001c: 00 00 00 00 nop
|
||||||
# CHECK-NEXT: 20020: 0c 00 80 1d jal 131188 <__LA25Thunk_fpic>
|
# CHECK-NEXT: 20020: 0c 00 80 25 jal 131220 <fnpic+0x4>
|
||||||
|
# ^-- .pic.fpic
|
||||||
# CHECK-NEXT: 20024: 00 00 00 00 nop
|
# CHECK-NEXT: 20024: 00 00 00 00 nop
|
||||||
# CHECK-NEXT: 20028: 0c 00 80 28 jal 131232 <fnpic>
|
# CHECK-NEXT: 20028: 0c 00 80 24 jal 131216 <fnpic>
|
||||||
# CHECK-NEXT: 2002c: 00 00 00 00 nop
|
# CHECK-NEXT: 2002c: 00 00 00 00 nop
|
||||||
#
|
#
|
||||||
# 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: foo1a:
|
||||||
# CHECK-NEXT: 20050: 00 00 00 00 nop
|
# CHECK-NEXT: 20030: 00 00 00 00 nop
|
||||||
|
#
|
||||||
# CHECK: foo1b:
|
# 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-NEXT: 20054: 00 00 00 00 nop
|
# CHECK-NEXT: 20054: 00 00 00 00 nop
|
||||||
|
# CHECK-NEXT: 20058: 00 00 00 00 nop
|
||||||
# CHECK: __LA25Thunk_foo2:
|
# CHECK-NEXT: 2005c: 00 00 00 00 nop
|
||||||
# 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: 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-NEXT: 20070: 00 00 00 00 nop
|
# CHECK-NEXT: 20070: 00 00 00 00 nop
|
||||||
|
# CHECK-NEXT: 20074: 00 00 00 00 nop
|
||||||
# CHECK: __LA25Thunk_fpic:
|
# CHECK-NEXT: 20078: 00 00 00 00 nop
|
||||||
# CHECK-NEXT: 20074: 3c 19 00 02 lui $25, 2
|
# CHECK-NEXT: 2007c: 00 00 00 00 nop
|
||||||
# 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: fpic:
|
||||||
# CHECK-NEXT: 20090: 00 00 00 00 nop
|
# CHECK-NEXT: 20080: 00 00 00 00 nop
|
||||||
# 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: fnpic:
|
||||||
# CHECK-NEXT: 200a0: 00 00 00 00 nop
|
# 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
|
||||||
|
|
||||||
# Make sure the thunks are created properly no matter how
|
# Make sure the thunks are created properly no matter how
|
||||||
# objects are laid out.
|
# objects are laid out.
|
||||||
@@ -81,58 +76,54 @@
|
|||||||
# RUN: ld.lld %t-pic.o %t-npic.o %t-sto-pic.o -o %t.exe
|
# 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
|
# RUN: llvm-objdump -d %t.exe | FileCheck -check-prefix=REVERSE %s
|
||||||
|
|
||||||
# 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: foo1a:
|
||||||
# REVERSE-NEXT: 20020: 00 00 00 00 nop
|
# REVERSE-NEXT: 20000: 00 00 00 00 nop
|
||||||
|
#
|
||||||
# REVERSE: foo1b:
|
# 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-NEXT: 20024: 00 00 00 00 nop
|
# REVERSE-NEXT: 20024: 00 00 00 00 nop
|
||||||
# REVERSE: __LA25Thunk_foo2:
|
# REVERSE-NEXT: 20028: 00 00 00 00 nop
|
||||||
# REVERSE-NEXT: 20028: 3c 19 00 02 lui $25, 2
|
# REVERSE-NEXT: 2002c: 00 00 00 00 nop
|
||||||
# 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: 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-NEXT: 20040: 00 00 00 00 nop
|
# REVERSE-NEXT: 20040: 00 00 00 00 nop
|
||||||
# REVERSE-NEXT: 20044: 00 00 00 00 nop
|
# REVERSE-NEXT: 20044: 00 00 00 00 nop
|
||||||
# REVERSE-NEXT: 20048: 00 00 00 00 nop
|
# REVERSE-NEXT: 20048: 00 00 00 00 nop
|
||||||
# REVERSE-NEXT: 2004c: 00 00 00 00 nop
|
# REVERSE-NEXT: 2004c: 00 00 00 00 nop
|
||||||
|
#
|
||||||
# REVERSE: __start:
|
# REVERSE: __start:
|
||||||
# REVERSE-NEXT: 20050: 0c 00 80 00 jal 131072 <__LA25Thunk_foo1a>
|
# REVERSE-NEXT: 20050: 0c 00 80 02 jal 131080 <foo1b+0x4>
|
||||||
# REVERSE-NEXT: 20054: 00 00 00 00 nop
|
# REVERSE-NEXT: 20054: 00 00 00 00 nop
|
||||||
# REVERSE-NEXT: 20058: 0c 00 80 0a jal 131112 <__LA25Thunk_foo2>
|
# REVERSE-NEXT: 20058: 0c 00 80 0d jal 131124 <foo2+0x4>
|
||||||
# REVERSE-NEXT: 2005c: 00 00 00 00 nop
|
# REVERSE-NEXT: 2005c: 00 00 00 00 nop
|
||||||
# REVERSE-NEXT: 20060: 0c 00 80 04 jal 131088 <__LA25Thunk_foo1b>
|
# REVERSE-NEXT: 20060: 0c 00 80 06 jal 131096 <foo1b+0x14>
|
||||||
# REVERSE-NEXT: 20064: 00 00 00 00 nop
|
# REVERSE-NEXT: 20064: 00 00 00 00 nop
|
||||||
# REVERSE-NEXT: 20068: 0c 00 80 0a jal 131112 <__LA25Thunk_foo2>
|
# REVERSE-NEXT: 20068: 0c 00 80 0d jal 131124 <foo2+0x4>
|
||||||
# REVERSE-NEXT: 2006c: 00 00 00 00 nop
|
# REVERSE-NEXT: 2006c: 00 00 00 00 nop
|
||||||
# REVERSE-NEXT: 20070: 0c 00 80 20 jal 131200 <__LA25Thunk_fpic>
|
# REVERSE-NEXT: 20070: 0c 00 80 25 jal 131220 <fnpic+0x4>
|
||||||
# REVERSE-NEXT: 20074: 00 00 00 00 nop
|
# REVERSE-NEXT: 20074: 00 00 00 00 nop
|
||||||
# REVERSE-NEXT: 20078: 0c 00 80 28 jal 131232 <fnpic>
|
# REVERSE-NEXT: 20078: 0c 00 80 24 jal 131216 <fnpic>
|
||||||
# REVERSE-NEXT: 2007c: 00 00 00 00 nop
|
# REVERSE-NEXT: 2007c: 00 00 00 00 nop
|
||||||
# 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: fpic:
|
||||||
# REVERSE-NEXT: 20090: 00 00 00 00 nop
|
# REVERSE-NEXT: 20080: 00 00 00 00 nop
|
||||||
# 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: fnpic:
|
||||||
# REVERSE-NEXT: 200a0: 00 00 00 00 nop
|
# 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
|
||||||
|
|
||||||
.text
|
.text
|
||||||
.globl __start
|
.globl __start
|
||||||
|
|||||||
Reference in New Issue
Block a user