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:
Rafael Espindola 2016-04-13 01:40:19 +00:00
parent b2d2a018d6
commit 22ef956a45
8 changed files with 612 additions and 532 deletions

View File

@ -147,183 +147,132 @@ void InputSection<ELFT>::copyRelocations(uint8_t *Buf, ArrayRef<RelTy> Rels) {
}
}
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 <endianness E> static int16_t readSignedLo16(uint8_t *Loc) {
return read32<E>(Loc) & 0xffff;
// Page(Expr) is the page address of the expression Expr, defined
// as (Expr & ~0xFFF). (This applies even if the machine page size
// supported by the platform has a different value.)
static uint64_t getAArch64Page(uint64_t Expr) {
return Expr & (~static_cast<uint64_t>(0xFFF));
}
template <class ELFT>
template <class RelTy>
int32_t
InputSectionBase<ELFT>::findMipsPairedAddend(uint8_t *Buf, 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;
uintX_t Offset = getOffset(RI->r_offset);
if (Offset == (uintX_t)-1)
break;
const endianness E = ELFT::TargetEndianness;
return ((read32<E>(BufLoc) & 0xffff) << 16) +
readSignedLo16<E>(Buf + 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;
}
template <class ELFT, class uintX_t>
static uintX_t adjustMipsSymVA(uint32_t Type, const elf::ObjectFile<ELFT> &File,
const SymbolBody &Body, uintX_t AddrLoc,
uintX_t SymVA) {
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))
static typename ELFT::uint
getSymVA(uint32_t Type, typename ELFT::uint A, typename ELFT::uint P,
const SymbolBody &Body, uint8_t *BufLoc,
const elf::ObjectFile<ELFT> &File, RelExpr Expr) {
switch (Expr) {
case R_TLSLD:
return Out<ELFT>::Got->getTlsIndexVA() + A;
case R_TLSLD_PC:
return Out<ELFT>::Got->getTlsIndexVA() + A - P;
case R_THUNK:
return Body.getThunkVA<ELFT>();
case R_PPC_TOC:
return getPPC64TocBase() + A;
case R_TLSGD:
return Out<ELFT>::Got->getGlobalDynAddr(Body) + A;
case R_TLSGD_PC:
return Out<ELFT>::Got->getGlobalDynAddr(Body) + A - P;
case R_PLT:
return Body.getPltVA<ELFT>() + A;
case R_PLT_PC:
case R_PPC_PLT_OPD:
return Body.getPltVA<ELFT>() + A - P;
case R_SIZE:
return Body.getSize<ELFT>() + A;
case R_GOT:
case R_RELAX_TLS_GD_TO_IE:
return Body.getGotVA<ELFT>() + A;
case R_GOT_PAGE_PC:
return getAArch64Page(Body.getGotVA<ELFT>() + A) - getAArch64Page(P);
case R_GOT_PC:
case R_RELAX_TLS_GD_TO_IE_PC:
return Body.getGotVA<ELFT>() + A - P;
case R_ABS:
case R_RELAX_TLS_GD_TO_LE:
case R_RELAX_TLS_IE_TO_LE:
case R_RELAX_TLS_LD_TO_LE:
return Body.getVA<ELFT>(A);
case R_MIPS_GP0:
// We need to adjust SymVA value in case of R_MIPS_GPREL16/32
// relocations because they use the following expression to calculate
// the relocation's result for local symbol: S + A + GP0 - G.
return SymVA + File.getMipsGp0();
return SymVA;
}
template <class ELFT, class uintX_t>
static uintX_t getMipsGotVA(const SymbolBody &Body, uintX_t SymVA,
uint8_t *BufLoc) {
if (Body.isLocal())
return Body.getVA<ELFT>(A) + File.getMipsGp0();
case R_MIPS_GOT_LOCAL:
// If relocation against MIPS local symbol requires GOT entry, this entry
// should be initialized by 'page address'. This address is high 16-bits
// of sum the symbol's value and the addend.
return Out<ELFT>::Got->getMipsLocalPageAddr(SymVA);
if (!Body.isPreemptible())
return Out<ELFT>::Got->getMipsLocalPageAddr(Body.getVA<ELFT>(A));
case R_MIPS_GOT:
// For non-local symbols GOT entries should contain their full
// addresses. But if such symbol cannot be preempted, we do not
// have to put them into the "global" part of GOT and use dynamic
// linker to determine their actual addresses. That is why we
// create GOT entries for them in the "local" part of GOT.
return Out<ELFT>::Got->getMipsLocalFullAddr(Body);
return Body.getGotVA<ELFT>();
return Out<ELFT>::Got->getMipsLocalEntryAddr(Body.getVA<ELFT>(A));
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 RelTy>
void InputSectionBase<ELFT>::relocate(uint8_t *Buf, uint8_t *BufEnd,
ArrayRef<RelTy> Rels) {
size_t Num = Rels.end() - Rels.begin();
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);
void InputSectionBase<ELFT>::relocate(uint8_t *Buf, uint8_t *BufEnd) {
const unsigned Bits = sizeof(uintX_t) * 8;
for (const Relocation &Rel : Relocations) {
uintX_t Offset = Rel.Offset;
uint8_t *BufLoc = Buf + Offset;
uint32_t Type = Rel.Type;
uintX_t A = Rel.Addend;
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) &&
!Target->canRelaxTls(Type, nullptr)) {
Target->relocateOne(BufLoc, BufEnd, Type, AddrLoc,
Out<ELFT>::Got->getTlsIndexVA() + A);
if (Expr == R_RELAX_TLS_IE_TO_LE) {
Target->relaxTlsIeToLe(BufLoc, Type, SymVA);
continue;
}
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;
}
SymbolBody &Body = File->getSymbolBody(SymIndex).repl();
if (Target->canRelaxTls(Type, &Body)) {
uintX_t SymVA;
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;
if (Expr == R_PPC_PLT_OPD) {
uint32_t Nop = 0x60000000;
if (BufLoc + 8 <= BufEnd && read32be(BufLoc + 4) == Nop)
write32be(BufLoc + 4, 0xe8410028); // ld %r2, 40(%r1)
}
// PPC64 has a special relocation representing the TOC base pointer
// 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);
Target->relocateOne(BufLoc, Type, 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.
uint8_t *BufEnd = Buf + OutSecOff + Data.size();
for (const Elf_Shdr *RelSec : this->RelocSections) {
if (RelSec->sh_type == SHT_RELA)
this->relocate(Buf, BufEnd, EObj.relas(RelSec));
else
this->relocate(Buf, BufEnd, EObj.rels(RelSec));
}
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

View File

@ -24,6 +24,42 @@ template <class ELFT> class ObjectFile;
template <class ELFT> class OutputSection;
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.
template <class ELFT> class InputSectionBase {
protected:
@ -78,13 +114,8 @@ public:
InputSectionBase<ELFT> *getRelocTarget(const Elf_Rel &Rel) const;
InputSectionBase<ELFT> *getRelocTarget(const Elf_Rela &Rel) const;
template <class RelTy>
void relocate(uint8_t *Buf, uint8_t *BufEnd, llvm::ArrayRef<RelTy> Rels);
private:
template <class RelTy>
int32_t findMipsPairedAddend(uint8_t *Buf, uint8_t *BufLoc, SymbolBody &Sym,
const RelTy *Rel, const RelTy *End);
void relocate(uint8_t *Buf, uint8_t *BufEnd);
std::vector<Relocation> Relocations;
};
template <class ELFT> InputSectionBase<ELFT> InputSectionBase<ELFT>::Discarded;

View File

@ -164,12 +164,6 @@ template <class ELFT> bool GotSection<ELFT>::addTlsIndex() {
return true;
}
template <class ELFT>
typename GotSection<ELFT>::uintX_t
GotSection<ELFT>::getMipsLocalFullAddr(const SymbolBody &B) {
return getMipsLocalEntryAddr(B.getVA<ELFT>());
}
template <class ELFT>
typename GotSection<ELFT>::uintX_t
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) {
const Elf_Shdr *RelSec = S->RelocSection;
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));
}
for (EHInputSection<ELFT> *S : Sections)
S->relocate(Buf, nullptr);
}
template <class ELFT>

View File

@ -112,7 +112,7 @@ public:
bool addDynTlsEntry(SymbolBody &Sym);
bool addTlsIndex();
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 getGlobalDynAddr(const SymbolBody &B) const;
uintX_t getGlobalDynOffset(const SymbolBody &B) const;
@ -139,7 +139,6 @@ private:
llvm::SmallPtrSet<const OutputSectionBase<ELFT> *, 10> MipsOutSections;
llvm::DenseMap<uintX_t, size_t> MipsLocalGotPos;
uintX_t getMipsLocalEntryAddr(uintX_t EntryValue);
};
template <class ELFT>

File diff suppressed because it is too large Load Diff

View File

@ -10,6 +10,7 @@
#ifndef LLD_ELF_TARGET_H
#define LLD_ELF_TARGET_H
#include "InputSection.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Object/ELF.h"
@ -68,16 +69,15 @@ public:
virtual void writeThunk(uint8_t *Buf, uint64_t S) const {}
virtual void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type,
uint64_t P, uint64_t SA) 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 bool isGotRelative(uint32_t Type) const;
bool canRelaxTls(uint32_t Type, const SymbolBody *S) const;
template <class ELFT>
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();
unsigned TlsGdToLeSkip = 1;
unsigned PageSize = 4096;
// On freebsd x86_64 the first page cannot be mmaped.
@ -103,18 +103,14 @@ public:
uint32_t ThunkSize = 0;
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:
virtual bool needsCopyRelImpl(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();

View File

@ -17,6 +17,7 @@
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/FileOutputBuffer.h"
#include "llvm/Support/StringSaver.h"
#include "llvm/Support/raw_ostream.h"
@ -24,6 +25,7 @@
using namespace llvm;
using namespace llvm::ELF;
using namespace llvm::object;
using namespace llvm::support::endian;
using namespace lld;
using namespace lld::elf;
@ -268,23 +270,40 @@ template <bool Is64Bits> struct DenseMapInfo<SectionKey<Is64Bits>> {
}
// Returns the number of relocations processed.
template <class ELFT, class RelT>
template <class ELFT>
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;
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;
}
if (Out<ELFT>::Got->addTlsIndex())
Out<ELFT>::RelaDyn->addReloc({Target->TlsModuleIndexRel, Out<ELFT>::Got,
Out<ELFT>::Got->getTlsIndexOff(), false,
nullptr, 0});
Expr = Expr == R_PC ? R_TLSLD_PC : R_TLSLD;
C.Relocations.push_back({Expr, Type, Offset, Addend, &Body});
return 1;
}
if (!Body.isTls())
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->canRelaxTls(Type, &Body)) {
if (Out<ELFT>::Got->addDynTlsEntry(Body)) {
@ -295,10 +314,14 @@ static unsigned handleTlsRelocation(uint32_t Type, SymbolBody &Body,
Off + (uintX_t)sizeof(uintX_t), false,
&Body, 0});
}
Expr = Expr == R_PC ? R_TLSGD_PC : R_TLSGD;
C.Relocations.push_back({Expr, Type, Offset, Addend, &Body});
return 1;
}
if (!Body.isPreemptible())
return 2;
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,
@ -307,6 +330,15 @@ static unsigned handleTlsRelocation(uint32_t Type, SymbolBody &Body,
}
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;
}
@ -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
// * To mmap the output file, we need to know the size
// * 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 RelTy>
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();
ArrayRef<uint8_t> SectionData = C.getSectionData();
const uint8_t *Buf = SectionData.begin();
for (auto I = Rels.begin(), E = Rels.end(); I != E; ++I) {
const RelTy &RI = *I;
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))
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();
if (unsigned Processed = handleTlsRelocation<ELFT>(Type, Body, C, RI)) {
if (unsigned Processed =
handleTlsRelocation<ELFT>(Type, Body, C, Offset, Addend, Expr)) {
I += (Processed - 1);
continue;
}
if (Target->needsDynRelative(Type))
Out<ELFT>::RelaDyn->addReloc({Target->RelativeRel, C.OutSec, Offset, true,
&Body, getAddend<ELFT>(RI)});
AddDyn({Target->RelativeRel, C.OutSec, Offset, true, &Body,
getAddend<ELFT>(RI)});
// If a symbol in a DSO is referenced directly instead of through GOT,
// we need to create a copy relocation for the symbol.
if (auto *B = dyn_cast<SharedSymbol<ELFT>>(&Body)) {
if (Target->needsCopyRel<ELFT>(Type, Body)) {
if (IsAlloc && Target->needsCopyRel<ELFT>(Type, *B)) {
if (!B->needsCopy())
addCopyRelSymbol(B);
C.Relocations.push_back({Expr, Type, Offset, Addend, &Body});
continue;
}
}
@ -395,6 +497,15 @@ void Writer<ELFT>::scanRelocs(InputSectionBase<ELFT> &C, ArrayRef<RelTy> Rels) {
if (NeedPlt) {
if (NeedPlt == TargetInfo::Plt_Implicit)
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())
continue;
Out<ELFT>::Plt->addEntry(Body);
@ -407,6 +518,7 @@ void Writer<ELFT>::scanRelocs(InputSectionBase<ELFT> &C, ArrayRef<RelTy> Rels) {
if (Target->UseLazyBinding) {
Out<ELFT>::GotPlt->addEntry(Body);
if (IsAlloc)
Out<ELFT>::RelaPlt->addReloc({Rel, Out<ELFT>::GotPlt,
Body.getGotPltOffset<ELFT>(),
!Preemptible, &Body, 0});
@ -414,15 +526,35 @@ void Writer<ELFT>::scanRelocs(InputSectionBase<ELFT> &C, ArrayRef<RelTy> Rels) {
if (Body.isInGot())
continue;
Out<ELFT>::Got->addEntry(Body);
Out<ELFT>::RelaDyn->addReloc({Rel, Out<ELFT>::Got,
Body.getGotOffset<ELFT>(), !Preemptible,
AddDyn({Rel, Out<ELFT>::Got, Body.getGotOffset<ELFT>(), !Preemptible,
&Body, 0});
}
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 (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())
continue;
Out<ELFT>::Got->addEntry(Body);
@ -443,26 +575,23 @@ void Writer<ELFT>::scanRelocs(InputSectionBase<ELFT> &C, ArrayRef<RelTy> Rels) {
DynType = Target->GotRel;
else
DynType = Target->RelativeRel;
Out<ELFT>::RelaDyn->addReloc({DynType, Out<ELFT>::Got,
Body.getGotOffset<ELFT>(), !Preemptible,
&Body, 0});
AddDyn({DynType, Out<ELFT>::Got, Body.getGotOffset<ELFT>(),
!Preemptible, &Body, 0});
}
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) {
// We don't know anything about the finaly symbol. Just ask the dynamic
// linker to handle the relocation for us.
Out<ELFT>::RelaDyn->addReloc({Target->getDynRel(Type), C.OutSec, Offset,
false, &Body, getAddend<ELFT>(RI)});
AddDyn({Target->getDynRel(Type), C.OutSec, Offset, false, &Body, Addend});
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;
}
@ -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
// can process some of it and and just ask the dynamic linker to add the
// load address.
if (!Config->Pic || Target->isRelRelative(Type) || Target->isSizeRel(Type))
continue;
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});
if (Target->isSizeRel(Type)) {
C.Relocations.push_back({R_SIZE, Type, Offset, Addend, &Body});
continue;
}
Out<ELFT>::RelaDyn->addReloc(
{Target->RelativeRel, C.OutSec, Offset, true, &Body, Addend});
if (!Config->Pic || Target->isRelRelative(Type) || Expr == R_PC) {
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.
@ -493,7 +624,6 @@ void Writer<ELFT>::scanRelocs(InputSectionBase<ELFT> &C, ArrayRef<RelTy> Rels) {
}
template <class ELFT> void Writer<ELFT>::scanRelocs(InputSection<ELFT> &C) {
if (C.getSectionHdr()->sh_flags & SHF_ALLOC)
for (const Elf_Shdr *RelSec : C.RelocSections)
scanRelocs(C, *RelSec);
}

View File

@ -22,9 +22,9 @@
// DISASM-NEXT: 1104d: 49 81 c4 fc ff ff ff addq $-4, %r12
// Corrupred output:
// 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: 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:
// 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