Index: ELF/InputSection.h =================================================================== --- ELF/InputSection.h +++ ELF/InputSection.h @@ -23,6 +23,40 @@ template class OutputSection; template class OutputSectionBase; +struct Relocation { + enum RelExpr { + R_ABS, + R_GOT, + R_GOT_PAGE_PC, + R_GOT_PC, + R_MIPS, + R_MIPS_GOT, + R_MIPS_PC, + R_PAGE_PC, + R_PC, + R_PLT, + R_PLT_OPD, + R_PLT_PC, + R_PPC_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 + } Expr; + uint32_t Type; + uint64_t Offset; + uint64_t Addend; + SymbolBody *Sym; +}; + // This corresponds to a section of an input file. template class InputSectionBase { protected: @@ -75,14 +109,8 @@ InputSectionBase *getRelocTarget(const Elf_Rel &Rel) const; InputSectionBase *getRelocTarget(const Elf_Rela &Rel) const; - template - void relocate(uint8_t *Buf, uint8_t *BufEnd, - llvm::iterator_range Rels); - -private: - template - 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 Relocations; }; template Index: ELF/InputSection.cpp =================================================================== --- ELF/InputSection.cpp +++ ELF/InputSection.cpp @@ -147,65 +147,10 @@ } } -template -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 static int16_t readSignedLo16(uint8_t *Loc) { - return read32(Loc) & 0xffff; -} - -template -template -int32_t -InputSectionBase::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(BufLoc) & 0xffff) << 16) + - readSignedLo16(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 static uintX_t adjustMipsSymVA(uint32_t Type, const elf::ObjectFile &File, const SymbolBody &Body, uintX_t AddrLoc, - uintX_t SymVA) { + uint64_t SymVA) { if (Type == R_MIPS_HI16 && &Body == Config->MipsGpDisp) return getMipsGpAddr() - AddrLoc; if (Type == R_MIPS_LO16 && &Body == Config->MipsGpDisp) @@ -238,94 +183,159 @@ return Body.getGotVA(); } +// 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(0xFFF)); +} + template -template -void InputSectionBase::relocate(uint8_t *Buf, uint8_t *BufEnd, - iterator_range 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); +static uint64_t getSymVA(uint32_t Type, typename ELFT::uint A, + typename ELFT::uint P, const SymbolBody &Body, + uint8_t *BufLoc, const elf::ObjectFile &File, + Relocation::RelExpr Expr) { + uint64_t SymVA; + switch (Expr) { + case Relocation::R_TLSLD_PC: + case Relocation::R_TLSLD: + SymVA = Out::Got->getTlsIndexVA() + A; + break; + case Relocation::R_THUNK: + SymVA = Body.getThunkVA(); + break; + case Relocation::R_PPC_TOC: + SymVA = getPPC64TocBase() + A; + break; + case Relocation::R_TLSGD: + case Relocation::R_TLSGD_PC: + SymVA = Out::Got->getGlobalDynAddr(Body) + A; + break; + case Relocation::R_PLT: + case Relocation::R_PLT_PC: + case Relocation::R_PLT_OPD: + SymVA = Body.getPltVA() + A; + break; + case Relocation::R_SIZE: + SymVA = Body.getSize() + A; + break; + case Relocation::R_GOT: + case Relocation::R_GOT_PC: + case Relocation::R_GOT_PAGE_PC: + case Relocation::R_RELAX_TLS_GD_TO_IE: + case Relocation::R_RELAX_TLS_GD_TO_IE_PC: + SymVA = Body.getGotVA() + A; + break; + case Relocation::R_MIPS_GOT: + case Relocation::R_MIPS: + case Relocation::R_MIPS_PC: + case Relocation::R_ABS: + case Relocation::R_PC: + case Relocation::R_PAGE_PC: + case Relocation::R_PPC_OPD: + case Relocation::R_RELAX_TLS_GD_TO_LE: + case Relocation::R_RELAX_TLS_LD_TO_LE: + case Relocation::R_RELAX_TLS_IE_TO_LE: + SymVA = Body.getVA(A); + break; + } + + if (Expr == Relocation::R_MIPS || Expr == Relocation::R_MIPS_PC) { + SymVA = adjustMipsSymVA(Type, File, Body, P, SymVA); + } else if (Expr == Relocation::R_MIPS_GOT) { + SymVA = getMipsGotVA(Body, SymVA, BufLoc); + } else if (Expr == Relocation::R_PPC_OPD) { + // 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::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::Opd->getVA(); + uint64_t OpdEnd = OpdStart + Out::Opd->getSize(); + bool InOpd = OpdStart <= SymVA && SymVA < OpdEnd; + if (InOpd) + SymVA = read64be(&Out::OpdBuf[SymVA - OpdStart]); + } + } + + switch (Expr) { + case Relocation::R_ABS: + case Relocation::R_MIPS: + case Relocation::R_TLSLD: + case Relocation::R_TLSGD: + case Relocation::R_PPC_TOC: + case Relocation::R_PLT: + case Relocation::R_SIZE: + case Relocation::R_GOT: + case Relocation::R_MIPS_GOT: + case Relocation::R_RELAX_TLS_GD_TO_IE: + case Relocation::R_RELAX_TLS_GD_TO_LE: + case Relocation::R_RELAX_TLS_LD_TO_LE: + case Relocation::R_RELAX_TLS_IE_TO_LE: + case Relocation::R_THUNK: + return SymVA; + case Relocation::R_MIPS_PC: + case Relocation::R_GOT_PC: + case Relocation::R_PC: + case Relocation::R_TLSLD_PC: + case Relocation::R_TLSGD_PC: + case Relocation::R_PLT_PC: + case Relocation::R_PLT_OPD: + case Relocation::R_PPC_OPD: + case Relocation::R_RELAX_TLS_GD_TO_IE_PC: + return SymVA - P; + case Relocation::R_PAGE_PC: + case Relocation::R_GOT_PAGE_PC: + return getAArch64Page(SymVA) - getAArch64Page(P); + } +} + +template +void InputSectionBase::relocate(uint8_t *Buf, uint8_t *BufEnd) { + for (size_t I = 0, N = Relocations.size(); I < N; ++I) { + const Relocation &Rel = Relocations[I]; + uintX_t Offset = getOffset(Rel.Offset); if (Offset == (uintX_t)-1) continue; - uintX_t A = getAddend(RI); - uint32_t SymIndex = RI.getSymbol(Config->Mips64EL); - uint32_t Type = RI.getType(Config->Mips64EL); uint8_t *BufLoc = Buf + Offset; + uint32_t Type = Rel.Type; + SymbolBody &Body = *Rel.Sym; + uintX_t A = Rel.Addend; + uintX_t AddrLoc = OutSec->getVA() + Offset; + Relocation::RelExpr Expr = Rel.Expr; + uint64_t SymVA = + getSymVA(Type, A, AddrLoc, Body, BufLoc, *File, Expr); - if (Target->pointsToLocalDynamicGotEntry(Type) && - !Target->canRelaxTls(Type, nullptr)) { - Target->relocateOne(BufLoc, BufEnd, Type, AddrLoc, - Out::Got->getTlsIndexVA() + A); + if (Expr == Relocation::R_RELAX_TLS_IE_TO_LE) { + Target->relaxTlsIeToLe(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(); - else - SymVA = Body.getVA(); - // 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); + if (Expr == Relocation::R_RELAX_TLS_LD_TO_LE) { + Target->relaxTlsLdToLe(BufLoc, Type, SymVA); continue; } - - // 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); + if (Expr == Relocation::R_RELAX_TLS_GD_TO_LE) { + Target->relaxTlsGdToLe(BufLoc, Type, SymVA); continue; } - - if (Target->isTlsGlobalDynamicRel(Type) && - !Target->canRelaxTls(Type, &Body)) { - Target->relocateOne(BufLoc, BufEnd, Type, AddrLoc, - Out::Got->getGlobalDynAddr(Body) + A); + if (Expr == Relocation::R_RELAX_TLS_GD_TO_IE_PC || + Expr == Relocation::R_RELAX_TLS_GD_TO_IE) { + Target->relaxTlsGdToIe(BufLoc, Type, SymVA); 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(A); - - if (Target->needsPlt(Type, Body)) { - SymVA = Body.getPltVA() + A; - } else if (Target->needsGot(Type, Body)) { - if (Config->EMachine == EM_MIPS) - SymVA = getMipsGotVA(Body, SymVA, BufLoc); - else - SymVA = Body.getGotVA() + 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(); - } else if (!Target->needsCopyRel(Type, Body) && - Body.isPreemptible()) { - continue; - } else if (Config->EMachine == EM_MIPS) { - SymVA = adjustMipsSymVA(Type, *File, Body, AddrLoc, SymVA); + if (Expr == Relocation::R_PLT_OPD) { + uint32_t Nop = 0x60000000; + if (BufLoc + 8 <= BufEnd && read32be(BufLoc + 4) == Nop) + write32be(BufLoc + 4, 0xe8410028); // ld %r2, 40(%r1) } - if (Target->isSizeRel(Type)) - SymVA = Body.getSize() + A; - Target->relocateOne(BufLoc, BufEnd, Type, AddrLoc, SymVA); + Target->relocateOne(BufLoc, Type, SymVA); } } @@ -350,12 +360,7 @@ // 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 Index: ELF/OutputSections.cpp =================================================================== --- ELF/OutputSections.cpp +++ ELF/OutputSections.cpp @@ -1214,16 +1214,8 @@ } } - for (EHInputSection *S : Sections) { - const Elf_Shdr *RelSec = S->RelocSection; - if (!RelSec) - continue; - ELFFile &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 *S : Sections) + S->relocate(Buf, nullptr); } template Index: ELF/Target.h =================================================================== --- ELF/Target.h +++ ELF/Target.h @@ -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 @@ 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 Relocation::RelExpr getRelExpr(uint32_t Type) const; + virtual void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t SA) const = 0; virtual bool isGotRelative(uint32_t Type) const; bool canRelaxTls(uint32_t Type, const SymbolBody *S) const; template 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 @@ uint32_t ThunkSize = 0; bool UseLazyBinding = false; + virtual void relaxTlsGdToIe(uint8_t *Loc, uint32_t Type, uint64_t SA) const; + virtual void relaxTlsGdToLe(uint8_t *Loc, uint32_t Type, uint64_t SA) const; + virtual void relaxTlsIeToLe(uint8_t *Loc, uint32_t Type, uint64_t SA) const; + virtual void relaxTlsLdToLe(uint8_t *Loc, uint32_t Type, uint64_t SA) 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(); Index: ELF/Target.cpp =================================================================== --- ELF/Target.cpp +++ ELF/Target.cpp @@ -70,6 +70,7 @@ class X86TargetInfo final : public TargetInfo { public: X86TargetInfo(); + Relocation::RelExpr getRelExpr(uint32_t Type) const override; uint64_t getImplicitAddend(const uint8_t *Buf, uint32_t Type) const override; void writeGotPltHeader(uint8_t *Buf) const override; uint32_t getDynRel(uint32_t Type) const override; @@ -87,17 +88,12 @@ bool needsDynRelative(uint32_t Type) const override; bool needsGot(uint32_t Type, const SymbolBody &S) const override; bool needsPltImpl(uint32_t Type) const override; - void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P, - uint64_t SA) const override; - - size_t relaxTlsGdToIe(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, - uint64_t P, uint64_t SA) const override; - size_t relaxTlsGdToLe(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, - uint64_t P, uint64_t SA) const override; - size_t relaxTlsIeToLe(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, - uint64_t P, uint64_t SA) const override; - size_t relaxTlsLdToLe(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, - uint64_t P, uint64_t SA) const override; + void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t SA) const override; + + void relaxTlsGdToIe(uint8_t *Loc, uint32_t Type, uint64_t SA) const override; + void relaxTlsGdToLe(uint8_t *Loc, uint32_t Type, uint64_t SA) const override; + void relaxTlsIeToLe(uint8_t *Loc, uint32_t Type, uint64_t SA) const override; + void relaxTlsLdToLe(uint8_t *Loc, uint32_t Type, uint64_t SA) const override; bool isGotRelative(uint32_t Type) const override; bool refersToGotEntry(uint32_t Type) const override; @@ -106,6 +102,7 @@ class X86_64TargetInfo final : public TargetInfo { public: X86_64TargetInfo(); + Relocation::RelExpr getRelExpr(uint32_t Type) const override; uint32_t getDynRel(uint32_t Type) const override; uint32_t getTlsGotRel(uint32_t Type) const override; bool pointsToLocalDynamicGotEntry(uint32_t Type) const override; @@ -121,44 +118,39 @@ bool needsGot(uint32_t Type, const SymbolBody &S) const override; bool refersToGotEntry(uint32_t Type) const override; bool needsPltImpl(uint32_t Type) const override; - void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P, - uint64_t SA) const override; + void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t SA) const override; bool isRelRelative(uint32_t Type) const override; bool isSizeRel(uint32_t Type) const override; - size_t relaxTlsGdToIe(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, - uint64_t P, uint64_t SA) const override; - size_t relaxTlsGdToLe(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, - uint64_t P, uint64_t SA) const override; - size_t relaxTlsIeToLe(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, - uint64_t P, uint64_t SA) const override; - size_t relaxTlsLdToLe(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, - uint64_t P, uint64_t SA) const override; + void relaxTlsGdToIe(uint8_t *Loc, uint32_t Type, uint64_t SA) const override; + void relaxTlsGdToLe(uint8_t *Loc, uint32_t Type, uint64_t SA) const override; + void relaxTlsIeToLe(uint8_t *Loc, uint32_t Type, uint64_t SA) const override; + void relaxTlsLdToLe(uint8_t *Loc, uint32_t Type, uint64_t SA) const override; }; class PPCTargetInfo final : public TargetInfo { public: PPCTargetInfo(); - void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P, - uint64_t SA) const override; + void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t SA) const override; bool isRelRelative(uint32_t Type) const override; }; class PPC64TargetInfo final : public TargetInfo { public: PPC64TargetInfo(); + Relocation::RelExpr getRelExpr(uint32_t Type) const override; void writePlt(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const override; bool needsGot(uint32_t Type, const SymbolBody &S) const override; bool needsPltImpl(uint32_t Type) const override; - void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P, - uint64_t SA) const override; + void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t SA) const override; bool isRelRelative(uint32_t Type) const override; }; class AArch64TargetInfo final : public TargetInfo { public: AArch64TargetInfo(); + Relocation::RelExpr getRelExpr(uint32_t Type) const override; uint32_t getDynRel(uint32_t Type) const override; bool isTlsGlobalDynamicRel(uint32_t Type) const override; bool isTlsInitialExecRel(uint32_t Type) const override; @@ -171,12 +163,9 @@ bool needsCopyRelImpl(uint32_t Type) const override; bool needsGot(uint32_t Type, const SymbolBody &S) const override; bool needsPltImpl(uint32_t Type) const override; - void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P, - uint64_t SA) const override; - size_t relaxTlsGdToLe(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, - uint64_t P, uint64_t SA) const override; - size_t relaxTlsIeToLe(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, - uint64_t P, uint64_t SA) const override; + void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t SA) const override; + void relaxTlsGdToLe(uint8_t *Loc, uint32_t Type, uint64_t SA) const override; + void relaxTlsIeToLe(uint8_t *Loc, uint32_t Type, uint64_t SA) const override; private: static const uint64_t TcbSize = 16; @@ -185,13 +174,13 @@ class AMDGPUTargetInfo final : public TargetInfo { public: AMDGPUTargetInfo() {} - void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P, - uint64_t SA) const override; + void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t SA) const override; }; template class MipsTargetInfo final : public TargetInfo { public: MipsTargetInfo(); + Relocation::RelExpr getRelExpr(uint32_t Type) const override; uint64_t getImplicitAddend(const uint8_t *Buf, uint32_t Type) const override; uint32_t getDynRel(uint32_t Type) const override; void writeGotPlt(uint8_t *Buf, uint64_t Plt) const override; @@ -205,8 +194,7 @@ bool needsPltImpl(uint32_t Type) const override; bool needsThunk(uint32_t Type, const InputFile &File, const SymbolBody &S) const override; - void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P, - uint64_t SA) const override; + void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t SA) const override; bool isHintRel(uint32_t Type) const override; bool isRelRelative(uint32_t Type) const override; bool refersToGotEntry(uint32_t Type) const override; @@ -242,6 +230,10 @@ TargetInfo::~TargetInfo() {} +Relocation::RelExpr TargetInfo::getRelExpr(uint32_t Type) const { + return Relocation::R_ABS; +} + uint64_t TargetInfo::getImplicitAddend(const uint8_t *Buf, uint32_t Type) const { return 0; @@ -353,37 +345,23 @@ return false; } -size_t TargetInfo::relaxTls(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, - uint64_t P, uint64_t SA, - const SymbolBody &S) const { - if (isTlsGlobalDynamicRel(Type)) { - if (S.isPreemptible()) - return relaxTlsGdToIe(Loc, BufEnd, Type, P, SA); - return relaxTlsGdToLe(Loc, BufEnd, Type, P, SA); - } - if (isTlsLocalDynamicRel(Type)) - return relaxTlsLdToLe(Loc, BufEnd, Type, P, SA); - assert(isTlsInitialExecRel(Type)); - return relaxTlsIeToLe(Loc, BufEnd, Type, P, SA); -} - -size_t TargetInfo::relaxTlsGdToLe(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, - uint64_t P, uint64_t SA) const { +void TargetInfo::relaxTlsGdToLe(uint8_t *Loc, uint32_t Type, + uint64_t SA) const { llvm_unreachable("Should not have claimed to be relaxable"); } -size_t TargetInfo::relaxTlsGdToIe(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, - uint64_t P, uint64_t SA) const { +void TargetInfo::relaxTlsGdToIe(uint8_t *Loc, uint32_t Type, + uint64_t SA) const { llvm_unreachable("Should not have claimed to be relaxable"); } -size_t TargetInfo::relaxTlsIeToLe(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, - uint64_t P, uint64_t SA) const { +void TargetInfo::relaxTlsIeToLe(uint8_t *Loc, uint32_t Type, + uint64_t SA) const { llvm_unreachable("Should not have claimed to be relaxable"); } -size_t TargetInfo::relaxTlsLdToLe(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, - uint64_t P, uint64_t SA) const { +void TargetInfo::relaxTlsLdToLe(uint8_t *Loc, uint32_t Type, + uint64_t SA) const { llvm_unreachable("Should not have claimed to be relaxable"); } @@ -399,6 +377,18 @@ UseLazyBinding = true; PltEntrySize = 16; PltZeroSize = 16; + TlsGdToLeSkip = 2; +} + +Relocation::RelExpr X86TargetInfo::getRelExpr(uint32_t Type) const { + switch (Type) { + default: + return Relocation::R_ABS; + case R_386_PLT32: + case R_386_PC32: + case R_386_GOTPC: + return Relocation::R_PC; + } } bool X86TargetInfo::isRelRelative(uint32_t Type) const { @@ -537,8 +527,8 @@ } } -void X86TargetInfo::relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, - uint64_t P, uint64_t SA) const { +void X86TargetInfo::relocateOne(uint8_t *Loc, uint32_t Type, + uint64_t SA) const { switch (Type) { case R_386_32: write32le(Loc, SA); @@ -554,11 +544,11 @@ write32le(Loc, SA - Out::Got->getVA()); break; case R_386_GOTPC: - write32le(Loc, SA + Out::Got->getVA() - P); + write32le(Loc, SA + Out::Got->getVA()); break; case R_386_PC32: case R_386_PLT32: - write32le(Loc, SA - P); + write32le(Loc, SA); break; case R_386_TLS_GD: case R_386_TLS_LDM: @@ -588,9 +578,8 @@ return Config->Shared && Type == R_386_TLS_IE; } -size_t X86TargetInfo::relaxTlsGdToLe(uint8_t *Loc, uint8_t *BufEnd, - uint32_t Type, uint64_t P, - uint64_t SA) const { +void X86TargetInfo::relaxTlsGdToLe(uint8_t *Loc, uint32_t Type, + uint64_t SA) const { // GD can be optimized to LE: // leal x@tlsgd(, %ebx, 1), // call __tls_get_addr@plt @@ -605,11 +594,7 @@ 0x81, 0xe8, 0x00, 0x00, 0x00, 0x00 // subl 0(%ebx), %eax }; memcpy(Loc - 3, Inst, sizeof(Inst)); - relocateOne(Loc + 5, BufEnd, R_386_32, P, - Out::TlsPhdr->p_memsz - SA); - - // The next relocation should be against __tls_get_addr, so skip it - return 1; + relocateOne(Loc + 5, R_386_32, Out::TlsPhdr->p_memsz - SA); } // "Ulrich Drepper, ELF Handling For Thread-Local Storage" (5.1 @@ -620,20 +605,15 @@ // Is converted to: // movl %gs:0, %eax // addl x@gotntpoff(%ebx), %eax -size_t X86TargetInfo::relaxTlsGdToIe(uint8_t *Loc, uint8_t *BufEnd, - uint32_t Type, uint64_t P, - uint64_t SA) const { +void X86TargetInfo::relaxTlsGdToIe(uint8_t *Loc, uint32_t Type, + uint64_t SA) const { const uint8_t Inst[] = { 0x65, 0xa1, 0x00, 0x00, 0x00, 0x00, // movl %gs:0, %eax 0x03, 0x83, 0x00, 0x00, 0x00, 0x00 // addl 0(%ebx), %eax }; memcpy(Loc - 3, Inst, sizeof(Inst)); - relocateOne(Loc + 5, BufEnd, R_386_32, P, - SA - Out::Got->getVA() - - Out::Got->getNumEntries() * 4); - - // The next relocation should be against __tls_get_addr, so skip it - return 1; + relocateOne(Loc + 5, R_386_32, SA - Out::Got->getVA() - + Out::Got->getNumEntries() * 4); } // In some conditions, relocations can be optimized to avoid using GOT. @@ -641,10 +621,8 @@ // Read "ELF Handling For Thread-Local Storage, 5.1 // IA-32 Linker Optimizations" (http://www.akkadia.org/drepper/tls.pdf) // by Ulrich Drepper for details. - -size_t X86TargetInfo::relaxTlsIeToLe(uint8_t *Loc, uint8_t *BufEnd, - uint32_t Type, uint64_t P, - uint64_t SA) const { +void X86TargetInfo::relaxTlsIeToLe(uint8_t *Loc, uint32_t Type, + uint64_t SA) const { // Ulrich's document section 6.2 says that @gotntpoff can // be used with MOVL or ADDL instructions. // @indntpoff is similar to @gotntpoff, but for use in @@ -678,17 +656,14 @@ else *Op = 0x80 | Reg | (Reg << 3); } - relocateOne(Loc, BufEnd, R_386_TLS_LE, P, SA); - - return 0; + relocateOne(Loc, R_386_TLS_LE, SA); } -size_t X86TargetInfo::relaxTlsLdToLe(uint8_t *Loc, uint8_t *BufEnd, - uint32_t Type, uint64_t P, - uint64_t SA) const { +void X86TargetInfo::relaxTlsLdToLe(uint8_t *Loc, uint32_t Type, + uint64_t SA) const { if (Type == R_386_TLS_LDO_32) { - relocateOne(Loc, BufEnd, R_386_TLS_LE, P, SA); - return 0; + relocateOne(Loc, R_386_TLS_LE, SA); + return; } // LD can be optimized to LE: @@ -704,9 +679,6 @@ 0x8d, 0x74, 0x26, 0x00 // leal 0(%esi,1),%esi }; memcpy(Loc - 2, Inst, sizeof(Inst)); - - // The next relocation should be against __tls_get_addr, so skip it - return 1; } X86_64TargetInfo::X86_64TargetInfo() { @@ -721,6 +693,21 @@ UseLazyBinding = true; PltEntrySize = 16; PltZeroSize = 16; + TlsGdToLeSkip = 2; +} + +Relocation::RelExpr X86_64TargetInfo::getRelExpr(uint32_t Type) const { + switch (Type) { + default: + return Relocation::R_ABS; + case R_X86_64_GOTPCREL: + case R_X86_64_PLT32: + case R_X86_64_PC32: + case R_X86_64_TLSLD: + case R_X86_64_GOTTPOFF: + case R_X86_64_TLSGD: + return Relocation::R_PC; + } } void X86_64TargetInfo::writeGotPltHeader(uint8_t *Buf) const { @@ -844,18 +831,14 @@ // Is converted to: // mov %fs:0x0,%rax // lea x@tpoff,%rax -size_t X86_64TargetInfo::relaxTlsGdToLe(uint8_t *Loc, uint8_t *BufEnd, - uint32_t Type, uint64_t P, - uint64_t SA) const { +void X86_64TargetInfo::relaxTlsGdToLe(uint8_t *Loc, uint32_t Type, + uint64_t SA) const { const uint8_t Inst[] = { 0x64, 0x48, 0x8b, 0x04, 0x25, 0x00, 0x00, 0x00, 0x00, // mov %fs:0x0,%rax 0x48, 0x8d, 0x80, 0x00, 0x00, 0x00, 0x00 // lea x@tpoff,%rax }; memcpy(Loc - 4, Inst, sizeof(Inst)); - relocateOne(Loc + 8, BufEnd, R_X86_64_TPOFF32, P, SA); - - // The next relocation should be against __tls_get_addr, so skip it - return 1; + relocateOne(Loc + 8, R_X86_64_TPOFF32, SA + 4); } // "Ulrich Drepper, ELF Handling For Thread-Local Storage" (5.5 @@ -869,18 +852,14 @@ // Is converted to: // mov %fs:0x0,%rax // addq x@tpoff,%rax -size_t X86_64TargetInfo::relaxTlsGdToIe(uint8_t *Loc, uint8_t *BufEnd, - uint32_t Type, uint64_t P, - uint64_t SA) const { +void X86_64TargetInfo::relaxTlsGdToIe(uint8_t *Loc, uint32_t Type, + uint64_t SA) const { const uint8_t Inst[] = { 0x64, 0x48, 0x8b, 0x04, 0x25, 0x00, 0x00, 0x00, 0x00, // mov %fs:0x0,%rax 0x48, 0x03, 0x05, 0x00, 0x00, 0x00, 0x00 // addq x@tpoff,%rax }; memcpy(Loc - 4, Inst, sizeof(Inst)); - relocateOne(Loc + 8, BufEnd, R_X86_64_PC32, P + 12, SA); - - // The next relocation should be against __tls_get_addr, so skip it - return 1; + relocateOne(Loc + 8, R_X86_64_PC32, SA - 8); } // In some conditions, R_X86_64_GOTTPOFF relocation can be optimized to @@ -888,9 +867,8 @@ // This function does that. Read "ELF Handling For Thread-Local Storage, // 5.5 x86-x64 linker optimizations" (http://www.akkadia.org/drepper/tls.pdf) // by Ulrich Drepper for details. -size_t X86_64TargetInfo::relaxTlsIeToLe(uint8_t *Loc, uint8_t *BufEnd, - uint32_t Type, uint64_t P, - uint64_t SA) const { +void X86_64TargetInfo::relaxTlsIeToLe(uint8_t *Loc, uint32_t Type, + uint64_t SA) const { // Ulrich's document section 6.5 says that @gottpoff(%rip) must be // used in MOVQ or ADDQ instructions only. // "MOVQ foo@GOTTPOFF(%RIP), %REG" is transformed to "MOVQ $foo, %REG". @@ -916,8 +894,7 @@ if (*Prefix == 0x4c) *Prefix = (IsMov || RspAdd) ? 0x49 : 0x4d; *RegSlot = (IsMov || RspAdd) ? (0xc0 | Reg) : (0x80 | Reg | (Reg << 3)); - relocateOne(Loc, BufEnd, R_X86_64_TPOFF32, P, SA); - return 0; + relocateOne(Loc, R_X86_64_TPOFF32, SA + 4); } // "Ulrich Drepper, ELF Handling For Thread-Local Storage" (5.5 @@ -931,16 +908,15 @@ // .byte 0x66 // mov %fs:0,%rax // leaq bar@tpoff(%rax), %rcx -size_t X86_64TargetInfo::relaxTlsLdToLe(uint8_t *Loc, uint8_t *BufEnd, - uint32_t Type, uint64_t P, - uint64_t SA) const { +void X86_64TargetInfo::relaxTlsLdToLe(uint8_t *Loc, uint32_t Type, + uint64_t SA) const { if (Type == R_X86_64_DTPOFF64) { write64le(Loc, SA - Out::TlsPhdr->p_memsz); - return 0; + return; } if (Type == R_X86_64_DTPOFF32) { - relocateOne(Loc, BufEnd, R_X86_64_TPOFF32, P, SA); - return 0; + relocateOne(Loc, R_X86_64_TPOFF32, SA); + return; } const uint8_t Inst[] = { @@ -949,12 +925,10 @@ 0x64, 0x48, 0x8b, 0x04, 0x25, 0x00, 0x00, 0x00, 0x00 // mov %fs:0,%rax }; memcpy(Loc - 3, Inst, sizeof(Inst)); - // The next relocation should be against __tls_get_addr, so skip it - return 1; } -void X86_64TargetInfo::relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, - uint64_t P, uint64_t SA) const { +void X86_64TargetInfo::relocateOne(uint8_t *Loc, uint32_t Type, + uint64_t SA) const { switch (Type) { case R_X86_64_32: checkUInt<32>(SA, Type); @@ -978,7 +952,7 @@ case R_X86_64_PLT32: case R_X86_64_TLSGD: case R_X86_64_TLSLD: - write32le(Loc, SA - P); + write32le(Loc, SA); break; case R_X86_64_SIZE32: write32le(Loc, SA); @@ -1012,8 +986,8 @@ PPCTargetInfo::PPCTargetInfo() {} bool PPCTargetInfo::isRelRelative(uint32_t Type) const { return false; } -void PPCTargetInfo::relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, - uint64_t P, uint64_t SA) const { +void PPCTargetInfo::relocateOne(uint8_t *Loc, uint32_t Type, + uint64_t SA) const { switch (Type) { case R_PPC_ADDR16_HA: write16be(Loc, applyPPCHa(SA)); @@ -1063,6 +1037,15 @@ return TocVA + 0x8000; } +Relocation::RelExpr PPC64TargetInfo::getRelExpr(uint32_t Type) const { + switch (Type) { + default: + return Relocation::R_ABS; + case R_PPC64_REL24: + return Relocation::R_PPC_OPD; + } +} + void PPC64TargetInfo::writePlt(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const { @@ -1115,8 +1098,8 @@ } } -void PPC64TargetInfo::relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, - uint64_t P, uint64_t SA) const { +void PPC64TargetInfo::relocateOne(uint8_t *Loc, uint32_t Type, + uint64_t SA) const { uint64_t TB = getPPC64TocBase(); // For a TOC-relative relocation, adjust the addend and proceed in terms of @@ -1179,51 +1162,26 @@ write64be(Loc, SA); break; case R_PPC64_REL16_HA: - write16be(Loc, applyPPCHa(SA - P)); + write16be(Loc, applyPPCHa(SA)); break; case R_PPC64_REL16_HI: - write16be(Loc, applyPPCHi(SA - P)); + write16be(Loc, applyPPCHi(SA)); break; case R_PPC64_REL16_LO: - write16be(Loc, applyPPCLo(SA - P)); + write16be(Loc, applyPPCLo(SA)); break; case R_PPC64_REL24: { - // 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 (!SA) - break; - - uint64_t PltStart = Out::Plt->getVA(); - uint64_t PltEnd = PltStart + Out::Plt->getSize(); - bool InPlt = PltStart <= SA && SA < PltEnd; - - if (!InPlt && Out::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::Opd->getVA(); - uint64_t OpdEnd = OpdStart + Out::Opd->getSize(); - bool InOpd = OpdStart <= SA && SA < OpdEnd; - - if (InOpd) - SA = read64be(&Out::OpdBuf[SA - OpdStart]); - } - uint32_t Mask = 0x03FFFFFC; - checkInt<24>(SA - P, Type); - write32be(Loc, (read32be(Loc) & ~Mask) | ((SA - P) & Mask)); - - uint32_t Nop = 0x60000000; - if (InPlt && Loc + 8 <= BufEnd && read32be(Loc + 4) == Nop) - write32be(Loc + 4, 0xe8410028); // ld %r2, 40(%r1) + checkInt<24>(SA, Type); + write32be(Loc, (read32be(Loc) & ~Mask) | (SA & Mask)); break; } case R_PPC64_REL32: - checkInt<32>(SA - P, Type); - write32be(Loc, SA - P); + checkInt<32>(SA, Type); + write32be(Loc, SA); break; case R_PPC64_REL64: - write64be(Loc, SA - P); + write64be(Loc, SA); break; case R_PPC64_TOC: write64be(Loc, SA); @@ -1247,6 +1205,26 @@ PltZeroSize = 32; } +Relocation::RelExpr AArch64TargetInfo::getRelExpr(uint32_t Type) const { + switch (Type) { + default: + return Relocation::R_ABS; + case R_AARCH64_JUMP26: + case R_AARCH64_CALL26: + case R_AARCH64_PREL16: + case R_AARCH64_PREL32: + case R_AARCH64_PREL64: + case R_AARCH64_CONDBR19: + case R_AARCH64_ADR_PREL_LO21: + case R_AARCH64_TSTBR14: + return Relocation::R_PC; + case R_AARCH64_ADR_GOT_PAGE: + case R_AARCH64_ADR_PREL_PG_HI21: + case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21: + return Relocation::R_PAGE_PC; + } +} + bool AArch64TargetInfo::isRelRelative(uint32_t Type) const { switch (Type) { default: @@ -1296,6 +1274,10 @@ write64le(Buf, Out::Plt->getVA()); } +static uint64_t getAArch64Page(uint64_t Expr) { + return Expr & (~static_cast(0xFFF)); +} + void AArch64TargetInfo::writePltZero(uint8_t *Buf) const { const uint8_t PltData[] = { 0xf0, 0x7b, 0xbf, 0xa9, // stp x16, x30, [sp,#-16]! @@ -1311,11 +1293,10 @@ uint64_t Got = Out::GotPlt->getVA(); uint64_t Plt = Out::Plt->getVA(); - relocateOne(Buf + 4, Buf + 8, R_AARCH64_ADR_PREL_PG_HI21, Plt + 4, Got + 16); - relocateOne(Buf + 8, Buf + 12, R_AARCH64_LDST64_ABS_LO12_NC, Plt + 8, - Got + 16); - relocateOne(Buf + 12, Buf + 16, R_AARCH64_ADD_ABS_LO12_NC, Plt + 12, - Got + 16); + relocateOne(Buf + 4, R_AARCH64_ADR_PREL_PG_HI21, + getAArch64Page(Got + 16) - getAArch64Page(Plt + 4)); + relocateOne(Buf + 8, R_AARCH64_LDST64_ABS_LO12_NC, Got + 16); + relocateOne(Buf + 12, R_AARCH64_ADD_ABS_LO12_NC, Got + 16); } void AArch64TargetInfo::writePlt(uint8_t *Buf, uint64_t GotEntryAddr, @@ -1329,12 +1310,10 @@ }; memcpy(Buf, Inst, sizeof(Inst)); - relocateOne(Buf, Buf + 4, R_AARCH64_ADR_PREL_PG_HI21, PltEntryAddr, - GotEntryAddr); - relocateOne(Buf + 4, Buf + 8, R_AARCH64_LDST64_ABS_LO12_NC, PltEntryAddr + 4, - GotEntryAddr); - relocateOne(Buf + 8, Buf + 12, R_AARCH64_ADD_ABS_LO12_NC, PltEntryAddr + 8, - GotEntryAddr); + relocateOne(Buf, R_AARCH64_ADR_PREL_PG_HI21, + getAArch64Page(GotEntryAddr) - getAArch64Page(PltEntryAddr)); + relocateOne(Buf + 4, R_AARCH64_LDST64_ABS_LO12_NC, GotEntryAddr); + relocateOne(Buf + 8, R_AARCH64_ADD_ABS_LO12_NC, GotEntryAddr); } uint32_t AArch64TargetInfo::getTlsGotRel(uint32_t Type) const { @@ -1398,15 +1377,7 @@ or32le(L, (Imm & 0xFFF) << 10); } -// 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(0xFFF)); -} - -void AArch64TargetInfo::relocateOne(uint8_t *Loc, uint8_t *BufEnd, - uint32_t Type, uint64_t P, +void AArch64TargetInfo::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t SA) const { switch (Type) { case R_AARCH64_ABS16: @@ -1428,33 +1399,33 @@ or32le(Loc, (SA & 0xFFF) << 10); break; case R_AARCH64_ADR_GOT_PAGE: { - uint64_t X = getAArch64Page(SA) - getAArch64Page(P); + uint64_t X = SA; checkInt<33>(X, Type); updateAArch64Addr(Loc, (X >> 12) & 0x1FFFFF); // X[32:12] break; } case R_AARCH64_ADR_PREL_LO21: { - uint64_t X = SA - P; + uint64_t X = SA; checkInt<21>(X, Type); updateAArch64Addr(Loc, X & 0x1FFFFF); break; } case R_AARCH64_ADR_PREL_PG_HI21: case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21: { - uint64_t X = getAArch64Page(SA) - getAArch64Page(P); + uint64_t X = SA; checkInt<33>(X, Type); updateAArch64Addr(Loc, (X >> 12) & 0x1FFFFF); // X[32:12] break; } case R_AARCH64_CALL26: case R_AARCH64_JUMP26: { - uint64_t X = SA - P; + uint64_t X = SA; checkInt<28>(X, Type); or32le(Loc, (X & 0x0FFFFFFC) >> 2); break; } case R_AARCH64_CONDBR19: { - uint64_t X = SA - P; + uint64_t X = SA; checkInt<21>(X, Type); or32le(Loc, (X & 0x1FFFFC) << 3); break; @@ -1480,18 +1451,18 @@ or32le(Loc, (SA & 0xFF8) << 7); break; case R_AARCH64_PREL16: - checkIntUInt<16>(SA - P, Type); - write16le(Loc, SA - P); + checkIntUInt<16>(SA, Type); + write16le(Loc, SA); break; case R_AARCH64_PREL32: - checkIntUInt<32>(SA - P, Type); - write32le(Loc, SA - P); + checkIntUInt<32>(SA, Type); + write32le(Loc, SA); break; case R_AARCH64_PREL64: - write64le(Loc, SA - P); + write64le(Loc, SA); break; case R_AARCH64_TSTBR14: { - uint64_t X = SA - P; + uint64_t X = SA; checkInt<16>(X, Type); or32le(Loc, (X & 0xFFFC) << 3); break; @@ -1512,9 +1483,8 @@ } } -size_t AArch64TargetInfo::relaxTlsGdToLe(uint8_t *Loc, uint8_t *BufEnd, - uint32_t Type, uint64_t P, - uint64_t SA) const { +void AArch64TargetInfo::relaxTlsGdToLe(uint8_t *Loc, uint32_t Type, + uint64_t SA) const { // TLSDESC Global-Dynamic relocation are in the form: // adrp x0, :tlsdesc:v [R_AARCH64_TLSDESC_ADR_PAGE21] // ldr x1, [x0, #:tlsdesc_lo12:v [R_AARCH64_TLSDESC_LD64_LO12_NC] @@ -1548,13 +1518,10 @@ llvm_unreachable("unsupported Relocation for TLS GD to LE relax"); } write32le(Loc, NewInst); - - return 0; } -size_t AArch64TargetInfo::relaxTlsIeToLe(uint8_t *Loc, uint8_t *BufEnd, - uint32_t Type, uint64_t P, - uint64_t SA) const { +void AArch64TargetInfo::relaxTlsIeToLe(uint8_t *Loc, uint32_t Type, + uint64_t SA) const { uint64_t TPOff = llvm::alignTo(TcbSize, Out::TlsPhdr->p_align); uint64_t X = SA + TPOff; checkUInt<32>(X, Type); @@ -1573,16 +1540,14 @@ llvm_unreachable("invalid Relocation for TLS IE to LE Relax"); } write32le(Loc, NewInst); - - return 0; } // Implementing relocations for AMDGPU is low priority since most // programs don't use relocations now. Thus, this function is not // actually called (relocateOne is called for each relocation). // That's why the AMDGPU port works without implementing this function. -void AMDGPUTargetInfo::relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, - uint64_t P, uint64_t SA) const { +void AMDGPUTargetInfo::relocateOne(uint8_t *Loc, uint32_t Type, + uint64_t SA) const { llvm_unreachable("not implemented"); } @@ -1600,6 +1565,22 @@ } template +Relocation::RelExpr MipsTargetInfo::getRelExpr(uint32_t Type) const { + switch (Type) { + default: + return Relocation::R_ABS; + case R_MIPS_PC32: + case R_MIPS_PC16: + case R_MIPS_PC19_S2: + case R_MIPS_PC21_S2: + case R_MIPS_PC26_S2: + case R_MIPS_PCHI16: + case R_MIPS_PCLO16: + return Relocation::R_PC; + } +} + +template uint32_t MipsTargetInfo::getDynRel(uint32_t Type) const { if (Type == R_MIPS_32 || Type == R_MIPS_64) return R_MIPS_REL32; @@ -1648,11 +1629,9 @@ } template -static void applyMipsPcReloc(uint8_t *Loc, uint32_t Type, uint64_t P, - uint64_t SA) { +static void applyMipsPcReloc(uint8_t *Loc, uint32_t Type, uint64_t V) { uint32_t Mask = 0xffffffff >> (32 - BSIZE); uint32_t Instr = read32(Loc); - int64_t V = SA - P; if (SHIFT > 0) checkAlignment<(1 << SHIFT)>(V, Type); checkInt(V, Type); @@ -1802,8 +1781,7 @@ } template -void MipsTargetInfo::relocateOne(uint8_t *Loc, uint8_t *BufEnd, - uint32_t Type, uint64_t P, +void MipsTargetInfo::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t SA) const { const endianness E = ELFT::TargetEndianness; // Thread pointer and DRP offsets from the start of TLS data area. @@ -1846,25 +1824,25 @@ writeMipsLo16(Loc, SA); break; case R_MIPS_PC16: - applyMipsPcReloc(Loc, Type, P, SA); + applyMipsPcReloc(Loc, Type, SA); break; case R_MIPS_PC19_S2: - applyMipsPcReloc(Loc, Type, P, SA); + applyMipsPcReloc(Loc, Type, SA); break; case R_MIPS_PC21_S2: - applyMipsPcReloc(Loc, Type, P, SA); + applyMipsPcReloc(Loc, Type, SA); break; case R_MIPS_PC26_S2: - applyMipsPcReloc(Loc, Type, P, SA); + applyMipsPcReloc(Loc, Type, SA); break; case R_MIPS_PC32: - applyMipsPcReloc(Loc, Type, P, SA); + applyMipsPcReloc(Loc, Type, SA); break; case R_MIPS_PCHI16: - writeMipsHi16(Loc, SA - P); + writeMipsHi16(Loc, SA); break; case R_MIPS_PCLO16: - writeMipsLo16(Loc, SA - P); + writeMipsLo16(Loc, SA); break; case R_MIPS_TLS_DTPREL_HI16: writeMipsHi16(Loc, SA - DTPOffset); Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -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; @@ -276,20 +278,35 @@ // Returns the number of relocations processed. template static unsigned handleTlsRelocation(uint32_t Type, SymbolBody &Body, - InputSectionBase &C, RelT &RI) { + InputSectionBase &C, RelT &RI, + typename ELFT::uint Addend, + Relocation::RelExpr Expr) { if (Target->pointsToLocalDynamicGotEntry(Type)) { - if (Target->canRelaxTls(Type, nullptr)) - return 1; + if (Target->canRelaxTls(Type, nullptr)) { + C.Relocations.push_back( + {Relocation::R_RELAX_TLS_LD_TO_LE, Type, RI.r_offset, Addend, &Body}); + return 2; + } if (Out::Got->addTlsIndex()) Out::RelaDyn->addReloc({Target->TlsModuleIndexRel, DynamicReloc::Off_LTlsIndex, nullptr}); + Expr = + Expr == Relocation::R_PC ? Relocation::R_TLSLD_PC : Relocation::R_TLSLD; + C.Relocations.push_back({Expr, Type, RI.r_offset, Addend, &Body}); return 1; } if (!Body.IsTls) return 0; + if (Target->isTlsLocalDynamicRel(Type) && + Target->canRelaxTls(Type, nullptr)) { + C.Relocations.push_back( + {Relocation::R_RELAX_TLS_LD_TO_LE, Type, RI.r_offset, Addend, &Body}); + return 1; + } + if (Target->isTlsGlobalDynamicRel(Type)) { if (!Target->canRelaxTls(Type, &Body)) { if (Out::Got->addDynTlsEntry(Body)) { @@ -299,16 +316,31 @@ Out::RelaDyn->addReloc( {Target->TlsOffsetRel, DynamicReloc::Off_GTlsOffset, &Body}); } + Expr = Expr == Relocation::R_PC ? Relocation::R_TLSGD_PC + : Relocation::R_TLSGD; + C.Relocations.push_back({Expr, Type, RI.r_offset, Addend, &Body}); return 1; } - if (!Body.isPreemptible()) - return 1; - if (!Body.isInGot()) { - Out::Got->addEntry(Body); - Out::RelaDyn->addReloc( - {Target->TlsGotRel, DynamicReloc::Off_Got, false, &Body}); + + if (Body.isPreemptible()) { + Expr = Expr == Relocation::R_PC ? Relocation::R_RELAX_TLS_GD_TO_IE_PC + : Relocation::R_RELAX_TLS_GD_TO_IE; + C.Relocations.push_back({Expr, Type, RI.r_offset, Addend, &Body}); + if (!Body.isInGot()) { + Out::Got->addEntry(Body); + Out::RelaDyn->addReloc( + {Target->TlsGotRel, DynamicReloc::Off_Got, false, &Body}); + } + return 2; } - return 2; + C.Relocations.push_back( + {Relocation::R_RELAX_TLS_GD_TO_LE, Type, RI.r_offset, Addend, &Body}); + return Target->TlsGdToLeSkip; + } + if (Target->isTlsInitialExecRel(Type) && Target->canRelaxTls(Type, &Body)) { + C.Relocations.push_back( + {Relocation::R_RELAX_TLS_IE_TO_LE, Type, RI.r_offset, Addend, &Body}); + return 1; } return 0; } @@ -332,6 +364,56 @@ } } +template static int16_t readSignedLo16(const uint8_t *Loc) { + return read32(Loc) & 0xffff; +} + +template +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 +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(BufLoc) & 0xffff) << 16) + + readSignedLo16(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. @@ -350,6 +432,8 @@ void Writer::scanRelocs(InputSectionBase &C, iterator_range Rels) { const elf::ObjectFile &File = *C.getFile(); + ArrayRef 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,8 +453,18 @@ if (auto *S = dyn_cast>(&Body)) S->File->IsUsed = true; + Relocation::RelExpr Expr = Target->getRelExpr(Type); + + uintX_t Addend = getAddend(RI); + const uint8_t *BufLoc = Buf + RI.r_offset; + if (!RelTy::IsRela) + Addend += Target->getImplicitAddend(BufLoc, Type); + if (Config->EMachine == EM_MIPS) + Addend += findMipsPairedAddend(Buf, BufLoc, Body, &RI, E); + bool Preemptible = Body.isPreemptible(); - if (unsigned Processed = handleTlsRelocation(Type, Body, C, RI)) { + if (unsigned Processed = + handleTlsRelocation(Type, Body, C, RI, Addend, Expr)) { I += (Processed - 1); continue; } @@ -382,12 +476,13 @@ // 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>(&Body)) { - if (B->needsCopy()) - continue; - if (Target->needsCopyRel(Type, *B)) { + if (!B->needsCopy() && Target->needsCopyRel(Type, *B)) { B->NeedsCopyOrPltAddr = true; Out::RelaDyn->addReloc( {Target->CopyRel, DynamicReloc::Off_Bss, B}); + } + if (B->needsCopy()) { + C.Relocations.push_back({Expr, Type, RI.r_offset, Addend, &Body}); continue; } } @@ -398,6 +493,15 @@ if (NeedPlt) { if (NeedPlt == TargetInfo::Plt_Implicit) Body.NeedsCopyOrPltAddr = true; + Relocation::RelExpr E; + if (Expr == Relocation::R_PPC_OPD) + E = Relocation::R_PLT_OPD; + else if (Expr == Relocation::R_PC) + E = Relocation::R_PLT_PC; + else + E = Relocation::R_PLT; + C.Relocations.push_back({E, Type, RI.r_offset, Addend, &Body}); + if (Body.isInPlt()) continue; Out::Plt->addEntry(Body); @@ -422,8 +526,25 @@ continue; } + if (Target->needsThunk(Type, File, Body)) { + C.Relocations.push_back( + {Relocation::R_THUNK, Type, RI.r_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; + Relocation::RelExpr E; + if (Expr == Relocation::R_PC) + E = Relocation::R_GOT_PC; + else if (Expr == Relocation::R_PAGE_PC) + E = Relocation::R_GOT_PAGE_PC; + else if (Config->EMachine == EM_MIPS) + E = Relocation::R_MIPS_GOT; + else + E = Relocation::R_GOT; + C.Relocations.push_back({E, T, RI.r_offset, Addend, &Body}); if (Body.isInGot()) continue; Out::Got->addEntry(Body); @@ -457,14 +578,26 @@ // the 'gp'. Therefore any relocations against them do not require // dynamic relocation. if (Config->EMachine == EM_MIPS && - (&Body == Config->MipsGpDisp || &Body == Config->MipsLocalGp)) + (&Body == Config->MipsGpDisp || &Body == Config->MipsLocalGp)) { + C.Relocations.push_back( + {Relocation::R_MIPS, Type, RI.r_offset, Addend, &Body}); continue; + } if (Preemptible) { // We don't know anything about the finaly symbol. Just ask the dynamic // linker to handle the relocation for us. - Out::RelaDyn->addReloc({Target->getDynRel(Type), &C, RI.r_offset, - false, &Body, getAddend(RI)}); + Out::RelaDyn->addReloc( + {Target->getDynRel(Type), &C, RI.r_offset, false, &Body, Addend}); + continue; + } + + if (Config->EMachine == EM_PPC64 && RI.getType(false) == R_PPC64_TOC) { + C.Relocations.push_back( + {Relocation::R_PPC_TOC, Type, RI.r_offset, Addend, &Body}); + Out::RelaDyn->addReloc({R_PPC64_RELATIVE, &C, RI.r_offset, false, + nullptr, + (uintX_t)getPPC64TocBase() + Addend}); continue; } @@ -475,18 +608,19 @@ // 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; + bool IsSizeRel = Target->isSizeRel(Type); + if (!Config->Pic || Target->isRelRelative(Type) || IsSizeRel) { + if (IsSizeRel) + Expr = Relocation::R_SIZE; + C.Relocations.push_back({Expr, Type, RI.r_offset, Addend, &Body}); - uintX_t Addend = getAddend(RI); - if (Config->EMachine == EM_PPC64 && RI.getType(false) == R_PPC64_TOC) { - Out::RelaDyn->addReloc({R_PPC64_RELATIVE, &C, RI.r_offset, false, - nullptr, - (uintX_t)getPPC64TocBase() + Addend}); continue; } + Out::RelaDyn->addReloc( {Target->RelativeRel, &C, RI.r_offset, true, &Body, Addend}); + C.Relocations.push_back( + {Relocation::R_ABS, Type, RI.r_offset, Addend, &Body}); } // Scan relocations for necessary thunks. Index: test/ELF/tls-opt.s =================================================================== --- test/ELF/tls-opt.s +++ test/ELF/tls-opt.s @@ -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