forked from OSchip/llvm-project
Change how we apply relocations.
With this patch we use the first scan over the relocations to remember the information we found about them: will them be relaxed, will a plt be used, etc. With that the actual relocation application becomes much simpler. That is particularly true for the interfaces in Target.h. This unfortunately means that we now do two passes over relocations for non SHF_ALLOC sections. I think this can be solved by factoring out the code that scans a single relocation. It can then be used both as a scan that record info and for a dedicated direct relocation of non SHF_ALLOC sections. I also think it is possible to reduce the number of enum values by representing a target with just an OutputSection and an offset (which can be from the start or end). This should unblock adding features like relocation optimizations. llvm-svn: 266158
This commit is contained in:
parent
b2d2a018d6
commit
22ef956a45
|
@ -147,183 +147,132 @@ void InputSection<ELFT>::copyRelocations(uint8_t *Buf, ArrayRef<RelTy> Rels) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class RelTy>
|
// Page(Expr) is the page address of the expression Expr, defined
|
||||||
static uint32_t getMipsPairType(const RelTy *Rel, const SymbolBody &Sym) {
|
// as (Expr & ~0xFFF). (This applies even if the machine page size
|
||||||
switch (Rel->getType(Config->Mips64EL)) {
|
// supported by the platform has a different value.)
|
||||||
case R_MIPS_HI16:
|
static uint64_t getAArch64Page(uint64_t Expr) {
|
||||||
return R_MIPS_LO16;
|
return Expr & (~static_cast<uint64_t>(0xFFF));
|
||||||
case R_MIPS_GOT16:
|
|
||||||
return Sym.isLocal() ? R_MIPS_LO16 : R_MIPS_NONE;
|
|
||||||
case R_MIPS_PCHI16:
|
|
||||||
return R_MIPS_PCLO16;
|
|
||||||
case R_MICROMIPS_HI16:
|
|
||||||
return R_MICROMIPS_LO16;
|
|
||||||
default:
|
|
||||||
return R_MIPS_NONE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template <endianness E> static int16_t readSignedLo16(uint8_t *Loc) {
|
|
||||||
return read32<E>(Loc) & 0xffff;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class ELFT>
|
template <class ELFT>
|
||||||
template <class RelTy>
|
static typename ELFT::uint
|
||||||
int32_t
|
getSymVA(uint32_t Type, typename ELFT::uint A, typename ELFT::uint P,
|
||||||
InputSectionBase<ELFT>::findMipsPairedAddend(uint8_t *Buf, uint8_t *BufLoc,
|
const SymbolBody &Body, uint8_t *BufLoc,
|
||||||
SymbolBody &Sym, const RelTy *Rel,
|
const elf::ObjectFile<ELFT> &File, RelExpr Expr) {
|
||||||
const RelTy *End) {
|
switch (Expr) {
|
||||||
uint32_t SymIndex = Rel->getSymbol(Config->Mips64EL);
|
case R_TLSLD:
|
||||||
uint32_t Type = getMipsPairType(Rel, Sym);
|
return Out<ELFT>::Got->getTlsIndexVA() + A;
|
||||||
|
case R_TLSLD_PC:
|
||||||
// Some MIPS relocations use addend calculated from addend of the relocation
|
return Out<ELFT>::Got->getTlsIndexVA() + A - P;
|
||||||
// itself and addend of paired relocation. ABI requires to compute such
|
case R_THUNK:
|
||||||
// combined addend in case of REL relocation record format only.
|
return Body.getThunkVA<ELFT>();
|
||||||
// See p. 4-17 at ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
|
case R_PPC_TOC:
|
||||||
if (RelTy::IsRela || Type == R_MIPS_NONE)
|
return getPPC64TocBase() + A;
|
||||||
return 0;
|
case R_TLSGD:
|
||||||
|
return Out<ELFT>::Got->getGlobalDynAddr(Body) + A;
|
||||||
for (const RelTy *RI = Rel; RI != End; ++RI) {
|
case R_TLSGD_PC:
|
||||||
if (RI->getType(Config->Mips64EL) != Type)
|
return Out<ELFT>::Got->getGlobalDynAddr(Body) + A - P;
|
||||||
continue;
|
case R_PLT:
|
||||||
if (RI->getSymbol(Config->Mips64EL) != SymIndex)
|
return Body.getPltVA<ELFT>() + A;
|
||||||
continue;
|
case R_PLT_PC:
|
||||||
uintX_t Offset = getOffset(RI->r_offset);
|
case R_PPC_PLT_OPD:
|
||||||
if (Offset == (uintX_t)-1)
|
return Body.getPltVA<ELFT>() + A - P;
|
||||||
break;
|
case R_SIZE:
|
||||||
const endianness E = ELFT::TargetEndianness;
|
return Body.getSize<ELFT>() + A;
|
||||||
return ((read32<E>(BufLoc) & 0xffff) << 16) +
|
case R_GOT:
|
||||||
readSignedLo16<E>(Buf + Offset);
|
case R_RELAX_TLS_GD_TO_IE:
|
||||||
}
|
return Body.getGotVA<ELFT>() + A;
|
||||||
unsigned OldType = Rel->getType(Config->Mips64EL);
|
case R_GOT_PAGE_PC:
|
||||||
StringRef OldName = getELFRelocationTypeName(Config->EMachine, OldType);
|
return getAArch64Page(Body.getGotVA<ELFT>() + A) - getAArch64Page(P);
|
||||||
StringRef NewName = getELFRelocationTypeName(Config->EMachine, Type);
|
case R_GOT_PC:
|
||||||
warning("can't find matching " + NewName + " relocation for " + OldName);
|
case R_RELAX_TLS_GD_TO_IE_PC:
|
||||||
return 0;
|
return Body.getGotVA<ELFT>() + A - P;
|
||||||
}
|
case R_ABS:
|
||||||
|
case R_RELAX_TLS_GD_TO_LE:
|
||||||
template <class ELFT, class uintX_t>
|
case R_RELAX_TLS_IE_TO_LE:
|
||||||
static uintX_t adjustMipsSymVA(uint32_t Type, const elf::ObjectFile<ELFT> &File,
|
case R_RELAX_TLS_LD_TO_LE:
|
||||||
const SymbolBody &Body, uintX_t AddrLoc,
|
return Body.getVA<ELFT>(A);
|
||||||
uintX_t SymVA) {
|
case R_MIPS_GP0:
|
||||||
if (Type == R_MIPS_HI16 && &Body == ElfSym<ELFT>::MipsGpDisp)
|
|
||||||
return SymVA - AddrLoc;
|
|
||||||
if (Type == R_MIPS_LO16 && &Body == ElfSym<ELFT>::MipsGpDisp)
|
|
||||||
return SymVA - AddrLoc + 4;
|
|
||||||
if (Body.isLocal() && (Type == R_MIPS_GPREL16 || Type == R_MIPS_GPREL32))
|
|
||||||
// We need to adjust SymVA value in case of R_MIPS_GPREL16/32
|
// We need to adjust SymVA value in case of R_MIPS_GPREL16/32
|
||||||
// relocations because they use the following expression to calculate
|
// relocations because they use the following expression to calculate
|
||||||
// the relocation's result for local symbol: S + A + GP0 - G.
|
// the relocation's result for local symbol: S + A + GP0 - G.
|
||||||
return SymVA + File.getMipsGp0();
|
return Body.getVA<ELFT>(A) + File.getMipsGp0();
|
||||||
return SymVA;
|
case R_MIPS_GOT_LOCAL:
|
||||||
}
|
|
||||||
|
|
||||||
template <class ELFT, class uintX_t>
|
|
||||||
static uintX_t getMipsGotVA(const SymbolBody &Body, uintX_t SymVA,
|
|
||||||
uint8_t *BufLoc) {
|
|
||||||
if (Body.isLocal())
|
|
||||||
// If relocation against MIPS local symbol requires GOT entry, this entry
|
// If relocation against MIPS local symbol requires GOT entry, this entry
|
||||||
// should be initialized by 'page address'. This address is high 16-bits
|
// should be initialized by 'page address'. This address is high 16-bits
|
||||||
// of sum the symbol's value and the addend.
|
// of sum the symbol's value and the addend.
|
||||||
return Out<ELFT>::Got->getMipsLocalPageAddr(SymVA);
|
return Out<ELFT>::Got->getMipsLocalPageAddr(Body.getVA<ELFT>(A));
|
||||||
if (!Body.isPreemptible())
|
case R_MIPS_GOT:
|
||||||
// For non-local symbols GOT entries should contain their full
|
// For non-local symbols GOT entries should contain their full
|
||||||
// addresses. But if such symbol cannot be preempted, we do not
|
// addresses. But if such symbol cannot be preempted, we do not
|
||||||
// have to put them into the "global" part of GOT and use dynamic
|
// have to put them into the "global" part of GOT and use dynamic
|
||||||
// linker to determine their actual addresses. That is why we
|
// linker to determine their actual addresses. That is why we
|
||||||
// create GOT entries for them in the "local" part of GOT.
|
// create GOT entries for them in the "local" part of GOT.
|
||||||
return Out<ELFT>::Got->getMipsLocalFullAddr(Body);
|
return Out<ELFT>::Got->getMipsLocalEntryAddr(Body.getVA<ELFT>(A));
|
||||||
return Body.getGotVA<ELFT>();
|
case R_PPC_OPD: {
|
||||||
|
uint64_t SymVA = Body.getVA<ELFT>(A);
|
||||||
|
// If we have an undefined weak symbol, we might get here with a symbol
|
||||||
|
// address of zero. That could overflow, but the code must be unreachable,
|
||||||
|
// so don't bother doing anything at all.
|
||||||
|
if (!SymVA)
|
||||||
|
return 0;
|
||||||
|
if (Out<ELF64BE>::Opd) {
|
||||||
|
// If this is a local call, and we currently have the address of a
|
||||||
|
// function-descriptor, get the underlying code address instead.
|
||||||
|
uint64_t OpdStart = Out<ELF64BE>::Opd->getVA();
|
||||||
|
uint64_t OpdEnd = OpdStart + Out<ELF64BE>::Opd->getSize();
|
||||||
|
bool InOpd = OpdStart <= SymVA && SymVA < OpdEnd;
|
||||||
|
if (InOpd)
|
||||||
|
SymVA = read64be(&Out<ELF64BE>::OpdBuf[SymVA - OpdStart]);
|
||||||
|
}
|
||||||
|
return SymVA - P;
|
||||||
|
}
|
||||||
|
case R_PC:
|
||||||
|
return Body.getVA<ELFT>(A) - P;
|
||||||
|
case R_PAGE_PC:
|
||||||
|
return getAArch64Page(Body.getVA<ELFT>(A)) - getAArch64Page(P);
|
||||||
|
}
|
||||||
|
llvm_unreachable("Invalid expression");
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class ELFT>
|
template <class ELFT>
|
||||||
template <class RelTy>
|
void InputSectionBase<ELFT>::relocate(uint8_t *Buf, uint8_t *BufEnd) {
|
||||||
void InputSectionBase<ELFT>::relocate(uint8_t *Buf, uint8_t *BufEnd,
|
const unsigned Bits = sizeof(uintX_t) * 8;
|
||||||
ArrayRef<RelTy> Rels) {
|
for (const Relocation &Rel : Relocations) {
|
||||||
size_t Num = Rels.end() - Rels.begin();
|
uintX_t Offset = Rel.Offset;
|
||||||
for (size_t I = 0; I < Num; ++I) {
|
|
||||||
const RelTy &RI = *(Rels.begin() + I);
|
|
||||||
uintX_t Offset = getOffset(RI.r_offset);
|
|
||||||
if (Offset == (uintX_t)-1)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
uintX_t A = getAddend<ELFT>(RI);
|
|
||||||
uint32_t SymIndex = RI.getSymbol(Config->Mips64EL);
|
|
||||||
uint32_t Type = RI.getType(Config->Mips64EL);
|
|
||||||
uint8_t *BufLoc = Buf + Offset;
|
uint8_t *BufLoc = Buf + Offset;
|
||||||
|
uint32_t Type = Rel.Type;
|
||||||
|
uintX_t A = Rel.Addend;
|
||||||
|
|
||||||
uintX_t AddrLoc = OutSec->getVA() + Offset;
|
uintX_t AddrLoc = OutSec->getVA() + Offset;
|
||||||
|
RelExpr Expr = Rel.Expr;
|
||||||
|
uint64_t SymVA = SignExtend64<Bits>(
|
||||||
|
getSymVA<ELFT>(Type, A, AddrLoc, *Rel.Sym, BufLoc, *File, Expr));
|
||||||
|
|
||||||
if (Target->pointsToLocalDynamicGotEntry(Type) &&
|
if (Expr == R_RELAX_TLS_IE_TO_LE) {
|
||||||
!Target->canRelaxTls(Type, nullptr)) {
|
Target->relaxTlsIeToLe(BufLoc, Type, SymVA);
|
||||||
Target->relocateOne(BufLoc, BufEnd, Type, AddrLoc,
|
continue;
|
||||||
Out<ELFT>::Got->getTlsIndexVA() + A);
|
}
|
||||||
|
if (Expr == R_RELAX_TLS_LD_TO_LE) {
|
||||||
|
Target->relaxTlsLdToLe(BufLoc, Type, SymVA);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (Expr == R_RELAX_TLS_GD_TO_LE) {
|
||||||
|
Target->relaxTlsGdToLe(BufLoc, Type, SymVA);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (Expr == R_RELAX_TLS_GD_TO_IE_PC || Expr == R_RELAX_TLS_GD_TO_IE) {
|
||||||
|
Target->relaxTlsGdToIe(BufLoc, Type, SymVA);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
SymbolBody &Body = File->getSymbolBody(SymIndex).repl();
|
if (Expr == R_PPC_PLT_OPD) {
|
||||||
|
uint32_t Nop = 0x60000000;
|
||||||
if (Target->canRelaxTls(Type, &Body)) {
|
if (BufLoc + 8 <= BufEnd && read32be(BufLoc + 4) == Nop)
|
||||||
uintX_t SymVA;
|
write32be(BufLoc + 4, 0xe8410028); // ld %r2, 40(%r1)
|
||||||
if (Target->needsGot(Type, Body))
|
|
||||||
SymVA = Body.getGotVA<ELFT>();
|
|
||||||
else
|
|
||||||
SymVA = Body.getVA<ELFT>();
|
|
||||||
// By optimizing TLS relocations, it is sometimes needed to skip
|
|
||||||
// relocations that immediately follow TLS relocations. This function
|
|
||||||
// knows how many slots we need to skip.
|
|
||||||
I += Target->relaxTls(BufLoc, BufEnd, Type, AddrLoc, SymVA, Body);
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// PPC64 has a special relocation representing the TOC base pointer
|
Target->relocateOne(BufLoc, Type, SymVA);
|
||||||
// that does not have a corresponding symbol.
|
|
||||||
if (Config->EMachine == EM_PPC64 && RI.getType(false) == R_PPC64_TOC) {
|
|
||||||
uintX_t SymVA = getPPC64TocBase() + A;
|
|
||||||
Target->relocateOne(BufLoc, BufEnd, Type, AddrLoc, SymVA);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Target->isTlsGlobalDynamicRel(Type) &&
|
|
||||||
!Target->canRelaxTls(Type, &Body)) {
|
|
||||||
Target->relocateOne(BufLoc, BufEnd, Type, AddrLoc,
|
|
||||||
Out<ELFT>::Got->getGlobalDynAddr(Body) + A);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!RelTy::IsRela)
|
|
||||||
A += Target->getImplicitAddend(BufLoc, Type);
|
|
||||||
if (Config->EMachine == EM_MIPS)
|
|
||||||
A += findMipsPairedAddend(Buf, BufLoc, Body, &RI, Rels.end());
|
|
||||||
uintX_t SymVA = Body.getVA<ELFT>(A);
|
|
||||||
|
|
||||||
if (Target->needsPlt(Type, Body)) {
|
|
||||||
SymVA = Body.getPltVA<ELFT>() + A;
|
|
||||||
} else if (Target->needsGot(Type, Body)) {
|
|
||||||
if (Config->EMachine == EM_MIPS)
|
|
||||||
SymVA = getMipsGotVA<ELFT>(Body, SymVA, BufLoc);
|
|
||||||
else
|
|
||||||
SymVA = Body.getGotVA<ELFT>() + A;
|
|
||||||
if (Body.isTls())
|
|
||||||
Type = Target->getTlsGotRel(Type);
|
|
||||||
} else if (Target->isSizeRel(Type) && Body.isPreemptible()) {
|
|
||||||
// A SIZE relocation is supposed to set a symbol size, but if a symbol
|
|
||||||
// can be preempted, the size at runtime may be different than link time.
|
|
||||||
// If that's the case, we leave the field alone rather than filling it
|
|
||||||
// with a possibly incorrect value.
|
|
||||||
continue;
|
|
||||||
} else if (Target->needsThunk(Type, *this->getFile(), Body)) {
|
|
||||||
// Get address of a thunk code related to the symbol.
|
|
||||||
SymVA = Body.getThunkVA<ELFT>();
|
|
||||||
} else if (!Target->needsCopyRel<ELFT>(Type, Body) &&
|
|
||||||
Body.isPreemptible()) {
|
|
||||||
continue;
|
|
||||||
} else if (Config->EMachine == EM_MIPS) {
|
|
||||||
SymVA = adjustMipsSymVA<ELFT>(Type, *File, Body, AddrLoc, SymVA);
|
|
||||||
}
|
|
||||||
if (Target->isSizeRel(Type))
|
|
||||||
SymVA = Body.getSize<ELFT>() + A;
|
|
||||||
|
|
||||||
Target->relocateOne(BufLoc, BufEnd, Type, AddrLoc, SymVA);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -348,12 +297,7 @@ 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();
|
||||||
for (const Elf_Shdr *RelSec : this->RelocSections) {
|
this->relocate(Buf, BufEnd);
|
||||||
if (RelSec->sh_type == SHT_RELA)
|
|
||||||
this->relocate(Buf, BufEnd, EObj.relas(RelSec));
|
|
||||||
else
|
|
||||||
this->relocate(Buf, BufEnd, EObj.rels(RelSec));
|
|
||||||
}
|
|
||||||
|
|
||||||
// The section might have a data/code generated by the linker and need
|
// 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
|
// to be written after the section. Usually these are thunks - small piece
|
||||||
|
|
|
@ -24,6 +24,42 @@ template <class ELFT> class ObjectFile;
|
||||||
template <class ELFT> class OutputSection;
|
template <class ELFT> class OutputSection;
|
||||||
template <class ELFT> class OutputSectionBase;
|
template <class ELFT> class OutputSectionBase;
|
||||||
|
|
||||||
|
enum RelExpr {
|
||||||
|
R_ABS,
|
||||||
|
R_GOT,
|
||||||
|
R_GOT_PAGE_PC,
|
||||||
|
R_GOT_PC,
|
||||||
|
R_MIPS_GOT,
|
||||||
|
R_MIPS_GOT_LOCAL,
|
||||||
|
R_MIPS_GP0,
|
||||||
|
R_PAGE_PC,
|
||||||
|
R_PC,
|
||||||
|
R_PLT,
|
||||||
|
R_PLT_PC,
|
||||||
|
R_PPC_OPD,
|
||||||
|
R_PPC_PLT_OPD,
|
||||||
|
R_PPC_TOC,
|
||||||
|
R_RELAX_TLS_GD_TO_IE,
|
||||||
|
R_RELAX_TLS_GD_TO_IE_PC,
|
||||||
|
R_RELAX_TLS_GD_TO_LE,
|
||||||
|
R_RELAX_TLS_IE_TO_LE,
|
||||||
|
R_RELAX_TLS_LD_TO_LE,
|
||||||
|
R_SIZE,
|
||||||
|
R_THUNK,
|
||||||
|
R_TLSGD,
|
||||||
|
R_TLSGD_PC,
|
||||||
|
R_TLSLD,
|
||||||
|
R_TLSLD_PC
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Relocation {
|
||||||
|
RelExpr Expr;
|
||||||
|
uint32_t Type;
|
||||||
|
uint64_t Offset;
|
||||||
|
uint64_t Addend;
|
||||||
|
SymbolBody *Sym;
|
||||||
|
};
|
||||||
|
|
||||||
// This corresponds to a section of an input file.
|
// This corresponds to a section of an input file.
|
||||||
template <class ELFT> class InputSectionBase {
|
template <class ELFT> class InputSectionBase {
|
||||||
protected:
|
protected:
|
||||||
|
@ -78,13 +114,8 @@ public:
|
||||||
InputSectionBase<ELFT> *getRelocTarget(const Elf_Rel &Rel) const;
|
InputSectionBase<ELFT> *getRelocTarget(const Elf_Rel &Rel) const;
|
||||||
InputSectionBase<ELFT> *getRelocTarget(const Elf_Rela &Rel) const;
|
InputSectionBase<ELFT> *getRelocTarget(const Elf_Rela &Rel) const;
|
||||||
|
|
||||||
template <class RelTy>
|
void relocate(uint8_t *Buf, uint8_t *BufEnd);
|
||||||
void relocate(uint8_t *Buf, uint8_t *BufEnd, llvm::ArrayRef<RelTy> Rels);
|
std::vector<Relocation> Relocations;
|
||||||
|
|
||||||
private:
|
|
||||||
template <class RelTy>
|
|
||||||
int32_t findMipsPairedAddend(uint8_t *Buf, uint8_t *BufLoc, SymbolBody &Sym,
|
|
||||||
const RelTy *Rel, const RelTy *End);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class ELFT> InputSectionBase<ELFT> InputSectionBase<ELFT>::Discarded;
|
template <class ELFT> InputSectionBase<ELFT> InputSectionBase<ELFT>::Discarded;
|
||||||
|
|
|
@ -164,12 +164,6 @@ template <class ELFT> bool GotSection<ELFT>::addTlsIndex() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class ELFT>
|
|
||||||
typename GotSection<ELFT>::uintX_t
|
|
||||||
GotSection<ELFT>::getMipsLocalFullAddr(const SymbolBody &B) {
|
|
||||||
return getMipsLocalEntryAddr(B.getVA<ELFT>());
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class ELFT>
|
template <class ELFT>
|
||||||
typename GotSection<ELFT>::uintX_t
|
typename GotSection<ELFT>::uintX_t
|
||||||
GotSection<ELFT>::getMipsLocalPageAddr(uintX_t EntryValue) {
|
GotSection<ELFT>::getMipsLocalPageAddr(uintX_t EntryValue) {
|
||||||
|
@ -1211,16 +1205,8 @@ template <class ELFT> void EHOutputSection<ELFT>::writeTo(uint8_t *Buf) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (EHInputSection<ELFT> *S : Sections) {
|
for (EHInputSection<ELFT> *S : Sections)
|
||||||
const Elf_Shdr *RelSec = S->RelocSection;
|
S->relocate(Buf, nullptr);
|
||||||
if (!RelSec)
|
|
||||||
continue;
|
|
||||||
ELFFile<ELFT> &EObj = S->getFile()->getObj();
|
|
||||||
if (RelSec->sh_type == SHT_RELA)
|
|
||||||
S->relocate(Buf, nullptr, EObj.relas(RelSec));
|
|
||||||
else
|
|
||||||
S->relocate(Buf, nullptr, EObj.rels(RelSec));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class ELFT>
|
template <class ELFT>
|
||||||
|
|
|
@ -112,7 +112,7 @@ public:
|
||||||
bool addDynTlsEntry(SymbolBody &Sym);
|
bool addDynTlsEntry(SymbolBody &Sym);
|
||||||
bool addTlsIndex();
|
bool addTlsIndex();
|
||||||
bool empty() const { return MipsLocalEntries == 0 && Entries.empty(); }
|
bool empty() const { return MipsLocalEntries == 0 && Entries.empty(); }
|
||||||
uintX_t getMipsLocalFullAddr(const SymbolBody &B);
|
uintX_t getMipsLocalEntryAddr(uintX_t EntryValue);
|
||||||
uintX_t getMipsLocalPageAddr(uintX_t Addr);
|
uintX_t getMipsLocalPageAddr(uintX_t Addr);
|
||||||
uintX_t getGlobalDynAddr(const SymbolBody &B) const;
|
uintX_t getGlobalDynAddr(const SymbolBody &B) const;
|
||||||
uintX_t getGlobalDynOffset(const SymbolBody &B) const;
|
uintX_t getGlobalDynOffset(const SymbolBody &B) const;
|
||||||
|
@ -139,7 +139,6 @@ private:
|
||||||
llvm::SmallPtrSet<const OutputSectionBase<ELFT> *, 10> MipsOutSections;
|
llvm::SmallPtrSet<const OutputSectionBase<ELFT> *, 10> MipsOutSections;
|
||||||
llvm::DenseMap<uintX_t, size_t> MipsLocalGotPos;
|
llvm::DenseMap<uintX_t, size_t> MipsLocalGotPos;
|
||||||
|
|
||||||
uintX_t getMipsLocalEntryAddr(uintX_t EntryValue);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class ELFT>
|
template <class ELFT>
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -10,6 +10,7 @@
|
||||||
#ifndef LLD_ELF_TARGET_H
|
#ifndef LLD_ELF_TARGET_H
|
||||||
#define LLD_ELF_TARGET_H
|
#define LLD_ELF_TARGET_H
|
||||||
|
|
||||||
|
#include "InputSection.h"
|
||||||
#include "llvm/ADT/StringRef.h"
|
#include "llvm/ADT/StringRef.h"
|
||||||
#include "llvm/Object/ELF.h"
|
#include "llvm/Object/ELF.h"
|
||||||
|
|
||||||
|
@ -68,16 +69,15 @@ public:
|
||||||
|
|
||||||
virtual void writeThunk(uint8_t *Buf, uint64_t S) const {}
|
virtual void writeThunk(uint8_t *Buf, uint64_t S) const {}
|
||||||
|
|
||||||
virtual void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type,
|
virtual RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const = 0;
|
||||||
uint64_t P, uint64_t SA) const = 0;
|
virtual void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const = 0;
|
||||||
virtual bool isGotRelative(uint32_t Type) const;
|
virtual bool isGotRelative(uint32_t Type) const;
|
||||||
bool canRelaxTls(uint32_t Type, const SymbolBody *S) const;
|
bool canRelaxTls(uint32_t Type, const SymbolBody *S) const;
|
||||||
template <class ELFT>
|
template <class ELFT>
|
||||||
bool needsCopyRel(uint32_t Type, const SymbolBody &S) const;
|
bool needsCopyRel(uint32_t Type, const SymbolBody &S) const;
|
||||||
size_t relaxTls(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P,
|
|
||||||
uint64_t SA, const SymbolBody &S) const;
|
|
||||||
virtual ~TargetInfo();
|
virtual ~TargetInfo();
|
||||||
|
|
||||||
|
unsigned TlsGdToLeSkip = 1;
|
||||||
unsigned PageSize = 4096;
|
unsigned PageSize = 4096;
|
||||||
|
|
||||||
// On freebsd x86_64 the first page cannot be mmaped.
|
// On freebsd x86_64 the first page cannot be mmaped.
|
||||||
|
@ -103,18 +103,14 @@ public:
|
||||||
uint32_t ThunkSize = 0;
|
uint32_t ThunkSize = 0;
|
||||||
bool UseLazyBinding = false;
|
bool UseLazyBinding = false;
|
||||||
|
|
||||||
|
virtual void relaxTlsGdToIe(uint8_t *Loc, uint32_t Type, uint64_t Val) const;
|
||||||
|
virtual void relaxTlsGdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const;
|
||||||
|
virtual void relaxTlsIeToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const;
|
||||||
|
virtual void relaxTlsLdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
virtual bool needsCopyRelImpl(uint32_t Type) const;
|
virtual bool needsCopyRelImpl(uint32_t Type) const;
|
||||||
virtual bool needsPltImpl(uint32_t Type) const;
|
virtual bool needsPltImpl(uint32_t Type) const;
|
||||||
|
|
||||||
virtual size_t relaxTlsGdToIe(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type,
|
|
||||||
uint64_t P, uint64_t SA) const;
|
|
||||||
virtual size_t relaxTlsGdToLe(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type,
|
|
||||||
uint64_t P, uint64_t SA) const;
|
|
||||||
virtual size_t relaxTlsIeToLe(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type,
|
|
||||||
uint64_t P, uint64_t SA) const;
|
|
||||||
virtual size_t relaxTlsLdToLe(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type,
|
|
||||||
uint64_t P, uint64_t SA) const;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
uint64_t getPPC64TocBase();
|
uint64_t getPPC64TocBase();
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include "llvm/ADT/SmallPtrSet.h"
|
#include "llvm/ADT/SmallPtrSet.h"
|
||||||
#include "llvm/ADT/StringMap.h"
|
#include "llvm/ADT/StringMap.h"
|
||||||
#include "llvm/ADT/StringSwitch.h"
|
#include "llvm/ADT/StringSwitch.h"
|
||||||
|
#include "llvm/Support/Endian.h"
|
||||||
#include "llvm/Support/FileOutputBuffer.h"
|
#include "llvm/Support/FileOutputBuffer.h"
|
||||||
#include "llvm/Support/StringSaver.h"
|
#include "llvm/Support/StringSaver.h"
|
||||||
#include "llvm/Support/raw_ostream.h"
|
#include "llvm/Support/raw_ostream.h"
|
||||||
|
@ -24,6 +25,7 @@
|
||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
using namespace llvm::ELF;
|
using namespace llvm::ELF;
|
||||||
using namespace llvm::object;
|
using namespace llvm::object;
|
||||||
|
using namespace llvm::support::endian;
|
||||||
|
|
||||||
using namespace lld;
|
using namespace lld;
|
||||||
using namespace lld::elf;
|
using namespace lld::elf;
|
||||||
|
@ -268,23 +270,40 @@ template <bool Is64Bits> struct DenseMapInfo<SectionKey<Is64Bits>> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the number of relocations processed.
|
// Returns the number of relocations processed.
|
||||||
template <class ELFT, class RelT>
|
template <class ELFT>
|
||||||
static unsigned handleTlsRelocation(uint32_t Type, SymbolBody &Body,
|
static unsigned handleTlsRelocation(uint32_t Type, SymbolBody &Body,
|
||||||
InputSectionBase<ELFT> &C, RelT &RI) {
|
InputSectionBase<ELFT> &C,
|
||||||
|
typename ELFT::uint Offset,
|
||||||
|
typename ELFT::uint Addend, RelExpr Expr) {
|
||||||
|
if (!(C.getSectionHdr()->sh_flags & SHF_ALLOC))
|
||||||
|
return 0;
|
||||||
|
|
||||||
typedef typename ELFT::uint uintX_t;
|
typedef typename ELFT::uint uintX_t;
|
||||||
if (Target->pointsToLocalDynamicGotEntry(Type)) {
|
if (Target->pointsToLocalDynamicGotEntry(Type)) {
|
||||||
if (Target->canRelaxTls(Type, nullptr))
|
if (Target->canRelaxTls(Type, nullptr)) {
|
||||||
|
C.Relocations.push_back(
|
||||||
|
{R_RELAX_TLS_LD_TO_LE, Type, Offset, Addend, &Body});
|
||||||
return 2;
|
return 2;
|
||||||
|
}
|
||||||
if (Out<ELFT>::Got->addTlsIndex())
|
if (Out<ELFT>::Got->addTlsIndex())
|
||||||
Out<ELFT>::RelaDyn->addReloc({Target->TlsModuleIndexRel, Out<ELFT>::Got,
|
Out<ELFT>::RelaDyn->addReloc({Target->TlsModuleIndexRel, Out<ELFT>::Got,
|
||||||
Out<ELFT>::Got->getTlsIndexOff(), false,
|
Out<ELFT>::Got->getTlsIndexOff(), false,
|
||||||
nullptr, 0});
|
nullptr, 0});
|
||||||
|
Expr = Expr == R_PC ? R_TLSLD_PC : R_TLSLD;
|
||||||
|
C.Relocations.push_back({Expr, Type, Offset, Addend, &Body});
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Body.isTls())
|
if (!Body.isTls())
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
if (Target->isTlsLocalDynamicRel(Type) &&
|
||||||
|
Target->canRelaxTls(Type, nullptr)) {
|
||||||
|
C.Relocations.push_back(
|
||||||
|
{R_RELAX_TLS_LD_TO_LE, Type, Offset, Addend, &Body});
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (Target->isTlsGlobalDynamicRel(Type)) {
|
if (Target->isTlsGlobalDynamicRel(Type)) {
|
||||||
if (!Target->canRelaxTls(Type, &Body)) {
|
if (!Target->canRelaxTls(Type, &Body)) {
|
||||||
if (Out<ELFT>::Got->addDynTlsEntry(Body)) {
|
if (Out<ELFT>::Got->addDynTlsEntry(Body)) {
|
||||||
|
@ -295,17 +314,30 @@ static unsigned handleTlsRelocation(uint32_t Type, SymbolBody &Body,
|
||||||
Off + (uintX_t)sizeof(uintX_t), false,
|
Off + (uintX_t)sizeof(uintX_t), false,
|
||||||
&Body, 0});
|
&Body, 0});
|
||||||
}
|
}
|
||||||
|
Expr = Expr == R_PC ? R_TLSGD_PC : R_TLSGD;
|
||||||
|
C.Relocations.push_back({Expr, Type, Offset, Addend, &Body});
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if (!Body.isPreemptible())
|
|
||||||
|
if (Body.isPreemptible()) {
|
||||||
|
Expr = Expr == R_PC ? R_RELAX_TLS_GD_TO_IE_PC : R_RELAX_TLS_GD_TO_IE;
|
||||||
|
C.Relocations.push_back({Expr, Type, Offset, Addend, &Body});
|
||||||
|
if (!Body.isInGot()) {
|
||||||
|
Out<ELFT>::Got->addEntry(Body);
|
||||||
|
Out<ELFT>::RelaDyn->addReloc({Target->TlsGotRel, Out<ELFT>::Got,
|
||||||
|
Body.getGotOffset<ELFT>(), false, &Body,
|
||||||
|
0});
|
||||||
|
}
|
||||||
return 2;
|
return 2;
|
||||||
if (!Body.isInGot()) {
|
|
||||||
Out<ELFT>::Got->addEntry(Body);
|
|
||||||
Out<ELFT>::RelaDyn->addReloc({Target->TlsGotRel, Out<ELFT>::Got,
|
|
||||||
Body.getGotOffset<ELFT>(), false, &Body,
|
|
||||||
0});
|
|
||||||
}
|
}
|
||||||
return 2;
|
C.Relocations.push_back(
|
||||||
|
{R_RELAX_TLS_GD_TO_LE, Type, Offset, Addend, &Body});
|
||||||
|
return Target->TlsGdToLeSkip;
|
||||||
|
}
|
||||||
|
if (Target->isTlsInitialExecRel(Type) && Target->canRelaxTls(Type, &Body)) {
|
||||||
|
C.Relocations.push_back(
|
||||||
|
{R_RELAX_TLS_IE_TO_LE, Type, Offset, Addend, &Body});
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -329,6 +361,56 @@ void Writer<ELFT>::scanRelocsForThunks(const elf::ObjectFile<ELFT> &File,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <endianness E> static int16_t readSignedLo16(const uint8_t *Loc) {
|
||||||
|
return read32<E>(Loc) & 0xffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class RelTy>
|
||||||
|
static uint32_t getMipsPairType(const RelTy *Rel, const SymbolBody &Sym) {
|
||||||
|
switch (Rel->getType(Config->Mips64EL)) {
|
||||||
|
case R_MIPS_HI16:
|
||||||
|
return R_MIPS_LO16;
|
||||||
|
case R_MIPS_GOT16:
|
||||||
|
return Sym.isLocal() ? R_MIPS_LO16 : R_MIPS_NONE;
|
||||||
|
case R_MIPS_PCHI16:
|
||||||
|
return R_MIPS_PCLO16;
|
||||||
|
case R_MICROMIPS_HI16:
|
||||||
|
return R_MICROMIPS_LO16;
|
||||||
|
default:
|
||||||
|
return R_MIPS_NONE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class ELFT, class RelTy>
|
||||||
|
static int32_t findMipsPairedAddend(const uint8_t *Buf, const uint8_t *BufLoc,
|
||||||
|
SymbolBody &Sym, const RelTy *Rel,
|
||||||
|
const RelTy *End) {
|
||||||
|
uint32_t SymIndex = Rel->getSymbol(Config->Mips64EL);
|
||||||
|
uint32_t Type = getMipsPairType(Rel, Sym);
|
||||||
|
|
||||||
|
// Some MIPS relocations use addend calculated from addend of the relocation
|
||||||
|
// itself and addend of paired relocation. ABI requires to compute such
|
||||||
|
// combined addend in case of REL relocation record format only.
|
||||||
|
// See p. 4-17 at ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
|
||||||
|
if (RelTy::IsRela || Type == R_MIPS_NONE)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
for (const RelTy *RI = Rel; RI != End; ++RI) {
|
||||||
|
if (RI->getType(Config->Mips64EL) != Type)
|
||||||
|
continue;
|
||||||
|
if (RI->getSymbol(Config->Mips64EL) != SymIndex)
|
||||||
|
continue;
|
||||||
|
const endianness E = ELFT::TargetEndianness;
|
||||||
|
return ((read32<E>(BufLoc) & 0xffff) << 16) +
|
||||||
|
readSignedLo16<E>(Buf + RI->r_offset);
|
||||||
|
}
|
||||||
|
unsigned OldType = Rel->getType(Config->Mips64EL);
|
||||||
|
StringRef OldName = getELFRelocationTypeName(Config->EMachine, OldType);
|
||||||
|
StringRef NewName = getELFRelocationTypeName(Config->EMachine, Type);
|
||||||
|
warning("can't find matching " + NewName + " relocation for " + OldName);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
// The reason we have to do this early scan is as follows
|
// The reason we have to do this early scan is as follows
|
||||||
// * To mmap the output file, we need to know the size
|
// * To mmap the output file, we need to know the size
|
||||||
// * For that, we need to know how many dynamic relocs we will have.
|
// * For that, we need to know how many dynamic relocs we will have.
|
||||||
|
@ -345,7 +427,16 @@ void Writer<ELFT>::scanRelocsForThunks(const elf::ObjectFile<ELFT> &File,
|
||||||
template <class ELFT>
|
template <class ELFT>
|
||||||
template <class RelTy>
|
template <class RelTy>
|
||||||
void Writer<ELFT>::scanRelocs(InputSectionBase<ELFT> &C, ArrayRef<RelTy> Rels) {
|
void Writer<ELFT>::scanRelocs(InputSectionBase<ELFT> &C, ArrayRef<RelTy> Rels) {
|
||||||
|
bool IsAlloc = C.getSectionHdr()->sh_flags & SHF_ALLOC;
|
||||||
|
|
||||||
|
auto AddDyn = [=](const DynamicReloc<ELFT> &Reloc) {
|
||||||
|
if (IsAlloc)
|
||||||
|
Out<ELFT>::RelaDyn->addReloc(Reloc);
|
||||||
|
};
|
||||||
|
|
||||||
const elf::ObjectFile<ELFT> &File = *C.getFile();
|
const elf::ObjectFile<ELFT> &File = *C.getFile();
|
||||||
|
ArrayRef<uint8_t> SectionData = C.getSectionData();
|
||||||
|
const uint8_t *Buf = SectionData.begin();
|
||||||
for (auto I = Rels.begin(), E = Rels.end(); I != E; ++I) {
|
for (auto I = Rels.begin(), E = Rels.end(); I != E; ++I) {
|
||||||
const RelTy &RI = *I;
|
const RelTy &RI = *I;
|
||||||
uint32_t SymIndex = RI.getSymbol(Config->Mips64EL);
|
uint32_t SymIndex = RI.getSymbol(Config->Mips64EL);
|
||||||
|
@ -369,22 +460,33 @@ void Writer<ELFT>::scanRelocs(InputSectionBase<ELFT> &C, ArrayRef<RelTy> Rels) {
|
||||||
if (auto *S = dyn_cast<SharedSymbol<ELFT>>(&Body))
|
if (auto *S = dyn_cast<SharedSymbol<ELFT>>(&Body))
|
||||||
S->File->IsUsed = true;
|
S->File->IsUsed = true;
|
||||||
|
|
||||||
|
RelExpr Expr = Target->getRelExpr(Type, Body);
|
||||||
|
|
||||||
|
uintX_t Addend = getAddend<ELFT>(RI);
|
||||||
|
const uint8_t *BufLoc = Buf + RI.r_offset;
|
||||||
|
if (!RelTy::IsRela)
|
||||||
|
Addend += Target->getImplicitAddend(BufLoc, Type);
|
||||||
|
if (Config->EMachine == EM_MIPS)
|
||||||
|
Addend += findMipsPairedAddend<ELFT>(Buf, BufLoc, Body, &RI, E);
|
||||||
|
|
||||||
bool Preemptible = Body.isPreemptible();
|
bool Preemptible = Body.isPreemptible();
|
||||||
if (unsigned Processed = handleTlsRelocation<ELFT>(Type, Body, C, RI)) {
|
if (unsigned Processed =
|
||||||
|
handleTlsRelocation<ELFT>(Type, Body, C, Offset, Addend, Expr)) {
|
||||||
I += (Processed - 1);
|
I += (Processed - 1);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Target->needsDynRelative(Type))
|
if (Target->needsDynRelative(Type))
|
||||||
Out<ELFT>::RelaDyn->addReloc({Target->RelativeRel, C.OutSec, Offset, true,
|
AddDyn({Target->RelativeRel, C.OutSec, Offset, true, &Body,
|
||||||
&Body, getAddend<ELFT>(RI)});
|
getAddend<ELFT>(RI)});
|
||||||
|
|
||||||
// If a symbol in a DSO is referenced directly instead of through GOT,
|
// If a symbol in a DSO is referenced directly instead of through GOT,
|
||||||
// we need to create a copy relocation for the symbol.
|
// we need to create a copy relocation for the symbol.
|
||||||
if (auto *B = dyn_cast<SharedSymbol<ELFT>>(&Body)) {
|
if (auto *B = dyn_cast<SharedSymbol<ELFT>>(&Body)) {
|
||||||
if (Target->needsCopyRel<ELFT>(Type, Body)) {
|
if (IsAlloc && Target->needsCopyRel<ELFT>(Type, *B)) {
|
||||||
if (!B->needsCopy())
|
if (!B->needsCopy())
|
||||||
addCopyRelSymbol(B);
|
addCopyRelSymbol(B);
|
||||||
|
C.Relocations.push_back({Expr, Type, Offset, Addend, &Body});
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -395,6 +497,15 @@ void Writer<ELFT>::scanRelocs(InputSectionBase<ELFT> &C, ArrayRef<RelTy> Rels) {
|
||||||
if (NeedPlt) {
|
if (NeedPlt) {
|
||||||
if (NeedPlt == TargetInfo::Plt_Implicit)
|
if (NeedPlt == TargetInfo::Plt_Implicit)
|
||||||
Body.NeedsCopyOrPltAddr = true;
|
Body.NeedsCopyOrPltAddr = true;
|
||||||
|
RelExpr E;
|
||||||
|
if (Expr == R_PPC_OPD)
|
||||||
|
E = R_PPC_PLT_OPD;
|
||||||
|
else if (Expr == R_PC)
|
||||||
|
E = R_PLT_PC;
|
||||||
|
else
|
||||||
|
E = R_PLT;
|
||||||
|
C.Relocations.push_back({E, Type, Offset, Addend, &Body});
|
||||||
|
|
||||||
if (Body.isInPlt())
|
if (Body.isInPlt())
|
||||||
continue;
|
continue;
|
||||||
Out<ELFT>::Plt->addEntry(Body);
|
Out<ELFT>::Plt->addEntry(Body);
|
||||||
|
@ -407,22 +518,43 @@ void Writer<ELFT>::scanRelocs(InputSectionBase<ELFT> &C, ArrayRef<RelTy> Rels) {
|
||||||
|
|
||||||
if (Target->UseLazyBinding) {
|
if (Target->UseLazyBinding) {
|
||||||
Out<ELFT>::GotPlt->addEntry(Body);
|
Out<ELFT>::GotPlt->addEntry(Body);
|
||||||
Out<ELFT>::RelaPlt->addReloc({Rel, Out<ELFT>::GotPlt,
|
if (IsAlloc)
|
||||||
Body.getGotPltOffset<ELFT>(),
|
Out<ELFT>::RelaPlt->addReloc({Rel, Out<ELFT>::GotPlt,
|
||||||
!Preemptible, &Body, 0});
|
Body.getGotPltOffset<ELFT>(),
|
||||||
|
!Preemptible, &Body, 0});
|
||||||
} else {
|
} else {
|
||||||
if (Body.isInGot())
|
if (Body.isInGot())
|
||||||
continue;
|
continue;
|
||||||
Out<ELFT>::Got->addEntry(Body);
|
Out<ELFT>::Got->addEntry(Body);
|
||||||
Out<ELFT>::RelaDyn->addReloc({Rel, Out<ELFT>::Got,
|
AddDyn({Rel, Out<ELFT>::Got, Body.getGotOffset<ELFT>(), !Preemptible,
|
||||||
Body.getGotOffset<ELFT>(), !Preemptible,
|
&Body, 0});
|
||||||
&Body, 0});
|
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Target->needsThunk(Type, File, Body)) {
|
||||||
|
C.Relocations.push_back({R_THUNK, Type, Offset, Addend, &Body});
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// If a relocation needs GOT, we create a GOT slot for the symbol.
|
// If a relocation needs GOT, we create a GOT slot for the symbol.
|
||||||
if (Target->needsGot(Type, Body)) {
|
if (Target->needsGot(Type, Body)) {
|
||||||
|
uint32_t T = Body.isTls() ? Target->getTlsGotRel(Type) : Type;
|
||||||
|
RelExpr E;
|
||||||
|
if (Expr == R_PC)
|
||||||
|
E = R_GOT_PC;
|
||||||
|
else if (Expr == R_PAGE_PC)
|
||||||
|
E = R_GOT_PAGE_PC;
|
||||||
|
else if (Config->EMachine == EM_MIPS) {
|
||||||
|
if (Body.isLocal())
|
||||||
|
E = R_MIPS_GOT_LOCAL;
|
||||||
|
else if (!Body.isPreemptible())
|
||||||
|
E = R_MIPS_GOT;
|
||||||
|
else
|
||||||
|
E = R_GOT;
|
||||||
|
} else
|
||||||
|
E = R_GOT;
|
||||||
|
C.Relocations.push_back({E, T, Offset, Addend, &Body});
|
||||||
if (Body.isInGot())
|
if (Body.isInGot())
|
||||||
continue;
|
continue;
|
||||||
Out<ELFT>::Got->addEntry(Body);
|
Out<ELFT>::Got->addEntry(Body);
|
||||||
|
@ -443,26 +575,23 @@ void Writer<ELFT>::scanRelocs(InputSectionBase<ELFT> &C, ArrayRef<RelTy> Rels) {
|
||||||
DynType = Target->GotRel;
|
DynType = Target->GotRel;
|
||||||
else
|
else
|
||||||
DynType = Target->RelativeRel;
|
DynType = Target->RelativeRel;
|
||||||
Out<ELFT>::RelaDyn->addReloc({DynType, Out<ELFT>::Got,
|
AddDyn({DynType, Out<ELFT>::Got, Body.getGotOffset<ELFT>(),
|
||||||
Body.getGotOffset<ELFT>(), !Preemptible,
|
!Preemptible, &Body, 0});
|
||||||
&Body, 0});
|
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// MIPS _gp_disp designates offset between start of function and 'gp'
|
|
||||||
// pointer into GOT. __gnu_local_gp is equal to the current value of
|
|
||||||
// the 'gp'. Therefore any relocations against them do not require
|
|
||||||
// dynamic relocation.
|
|
||||||
if (Config->EMachine == EM_MIPS && (&Body == ElfSym<ELFT>::MipsGpDisp ||
|
|
||||||
&Body == ElfSym<ELFT>::MipsLocalGp))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (Preemptible) {
|
if (Preemptible) {
|
||||||
// We don't know anything about the finaly symbol. Just ask the dynamic
|
// We don't know anything about the finaly symbol. Just ask the dynamic
|
||||||
// linker to handle the relocation for us.
|
// linker to handle the relocation for us.
|
||||||
Out<ELFT>::RelaDyn->addReloc({Target->getDynRel(Type), C.OutSec, Offset,
|
AddDyn({Target->getDynRel(Type), C.OutSec, Offset, false, &Body, Addend});
|
||||||
false, &Body, getAddend<ELFT>(RI)});
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Config->EMachine == EM_PPC64 && RI.getType(false) == R_PPC64_TOC) {
|
||||||
|
C.Relocations.push_back({R_PPC_TOC, Type, Offset, Addend, &Body});
|
||||||
|
AddDyn({R_PPC64_RELATIVE, C.OutSec, Offset, false, nullptr,
|
||||||
|
(uintX_t)getPPC64TocBase() + Addend});
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -473,18 +602,20 @@ void Writer<ELFT>::scanRelocs(InputSectionBase<ELFT> &C, ArrayRef<RelTy> Rels) {
|
||||||
// We can however do better than just copying the incoming relocation. We
|
// We can however do better than just copying the incoming relocation. We
|
||||||
// can process some of it and and just ask the dynamic linker to add the
|
// can process some of it and and just ask the dynamic linker to add the
|
||||||
// load address.
|
// load address.
|
||||||
if (!Config->Pic || Target->isRelRelative(Type) || Target->isSizeRel(Type))
|
if (Target->isSizeRel(Type)) {
|
||||||
continue;
|
C.Relocations.push_back({R_SIZE, Type, Offset, Addend, &Body});
|
||||||
|
|
||||||
uintX_t Addend = getAddend<ELFT>(RI);
|
|
||||||
if (Config->EMachine == EM_PPC64 && RI.getType(false) == R_PPC64_TOC) {
|
|
||||||
Out<ELFT>::RelaDyn->addReloc({R_PPC64_RELATIVE, C.OutSec, Offset, false,
|
|
||||||
nullptr,
|
|
||||||
(uintX_t)getPPC64TocBase() + Addend});
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Out<ELFT>::RelaDyn->addReloc(
|
if (!Config->Pic || Target->isRelRelative(Type) || Expr == R_PC) {
|
||||||
{Target->RelativeRel, C.OutSec, Offset, true, &Body, Addend});
|
if (Config->EMachine == EM_MIPS && Body.isLocal() &&
|
||||||
|
(Type == R_MIPS_GPREL16 || Type == R_MIPS_GPREL32))
|
||||||
|
Expr = R_MIPS_GP0;
|
||||||
|
C.Relocations.push_back({Expr, Type, Offset, Addend, &Body});
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
AddDyn({Target->RelativeRel, C.OutSec, Offset, true, &Body, Addend});
|
||||||
|
C.Relocations.push_back({R_ABS, Type, Offset, Addend, &Body});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scan relocations for necessary thunks.
|
// Scan relocations for necessary thunks.
|
||||||
|
@ -493,9 +624,8 @@ void Writer<ELFT>::scanRelocs(InputSectionBase<ELFT> &C, ArrayRef<RelTy> Rels) {
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class ELFT> void Writer<ELFT>::scanRelocs(InputSection<ELFT> &C) {
|
template <class ELFT> void Writer<ELFT>::scanRelocs(InputSection<ELFT> &C) {
|
||||||
if (C.getSectionHdr()->sh_flags & SHF_ALLOC)
|
for (const Elf_Shdr *RelSec : C.RelocSections)
|
||||||
for (const Elf_Shdr *RelSec : C.RelocSections)
|
scanRelocs(C, *RelSec);
|
||||||
scanRelocs(C, *RelSec);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class ELFT>
|
template <class ELFT>
|
||||||
|
|
|
@ -22,9 +22,9 @@
|
||||||
// DISASM-NEXT: 1104d: 49 81 c4 fc ff ff ff addq $-4, %r12
|
// DISASM-NEXT: 1104d: 49 81 c4 fc ff ff ff addq $-4, %r12
|
||||||
// Corrupred output:
|
// Corrupred output:
|
||||||
// DISASM-NEXT: 11054: 48 8d 80 f8 ff ff ff leaq -8(%rax), %rax
|
// DISASM-NEXT: 11054: 48 8d 80 f8 ff ff ff leaq -8(%rax), %rax
|
||||||
// DISASM-NEXT: 1105b: 48 d1 81 c4 f8 ff ff rolq -1852(%rcx)
|
// DISASM-NEXT: 1105b: 48 d1 81 c4 fc ff ff rolq -828(%rcx)
|
||||||
// DISASM-NEXT: 11062: ff 48 d1 decl -47(%rax)
|
// DISASM-NEXT: 11062: ff 48 d1 decl -47(%rax)
|
||||||
// DISASM-NEXT: 11065: 81 c4 f8 ff ff ff addl $4294967288, %esp
|
// DISASM-NEXT: 11065: 81 c4 fc ff ff ff addl $4294967292, %esp
|
||||||
// LD to LE:
|
// LD to LE:
|
||||||
// DISASM-NEXT: 1106b: 66 66 66 64 48 8b 04 25 00 00 00 00 movq %fs:0, %rax
|
// DISASM-NEXT: 1106b: 66 66 66 64 48 8b 04 25 00 00 00 00 movq %fs:0, %rax
|
||||||
// DISASM-NEXT: 11077: 48 8d 88 f8 ff ff ff leaq -8(%rax), %rcx
|
// DISASM-NEXT: 11077: 48 8d 88 f8 ff ff ff leaq -8(%rax), %rcx
|
||||||
|
|
Loading…
Reference in New Issue