Index: ELF/InputSection.h =================================================================== --- ELF/InputSection.h +++ ELF/InputSection.h @@ -24,6 +24,42 @@ template class OutputSection; template 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 InputSectionBase { protected: @@ -78,13 +114,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::ArrayRef 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 InputSectionBase InputSectionBase::Discarded; Index: ELF/InputSection.cpp =================================================================== --- ELF/InputSection.cpp +++ ELF/InputSection.cpp @@ -147,183 +147,132 @@ } } -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; +// 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 -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) { - if (Type == R_MIPS_HI16 && &Body == ElfSym::MipsGpDisp) - return SymVA - AddrLoc; - if (Type == R_MIPS_LO16 && &Body == ElfSym::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 &File, RelExpr Expr) { + switch (Expr) { + case R_TLSLD: + return Out::Got->getTlsIndexVA() + A; + case R_TLSLD_PC: + return Out::Got->getTlsIndexVA() + A - P; + case R_THUNK: + return Body.getThunkVA(); + case R_PPC_TOC: + return getPPC64TocBase() + A; + case R_TLSGD: + return Out::Got->getGlobalDynAddr(Body) + A; + case R_TLSGD_PC: + return Out::Got->getGlobalDynAddr(Body) + A - P; + case R_PLT: + return Body.getPltVA() + A; + case R_PLT_PC: + case R_PPC_PLT_OPD: + return Body.getPltVA() + A - P; + case R_SIZE: + return Body.getSize() + A; + case R_GOT: + case R_RELAX_TLS_GD_TO_IE: + return Body.getGotVA() + A; + case R_GOT_PAGE_PC: + return getAArch64Page(Body.getGotVA() + A) - getAArch64Page(P); + case R_GOT_PC: + case R_RELAX_TLS_GD_TO_IE_PC: + return Body.getGotVA() + 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(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 -static uintX_t getMipsGotVA(const SymbolBody &Body, uintX_t SymVA, - uint8_t *BufLoc) { - if (Body.isLocal()) + return Body.getVA(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::Got->getMipsLocalPageAddr(SymVA); - if (!Body.isPreemptible()) + return Out::Got->getMipsLocalPageAddr(Body.getVA(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::Got->getMipsLocalFullAddr(Body); - return Body.getGotVA(); + return Out::Got->getMipsLocalEntryAddr(Body.getVA(A)); + case R_PPC_OPD: { + uint64_t SymVA = Body.getVA(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::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]); + } + return SymVA - P; + } + case R_PC: + return Body.getVA(A) - P; + case R_PAGE_PC: + return getAArch64Page(Body.getVA(A)) - getAArch64Page(P); + } + llvm_unreachable("Invalid expression"); } template -template -void InputSectionBase::relocate(uint8_t *Buf, uint8_t *BufEnd, - ArrayRef 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(RI); - uint32_t SymIndex = RI.getSymbol(Config->Mips64EL); - uint32_t Type = RI.getType(Config->Mips64EL); +void InputSectionBase::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( + getSymVA(Type, A, AddrLoc, *Rel.Sym, BufLoc, *File, Expr)); - if (Target->pointsToLocalDynamicGotEntry(Type) && - !Target->canRelaxTls(Type, nullptr)) { - Target->relocateOne(BufLoc, BufEnd, Type, AddrLoc, - Out::Got->getTlsIndexVA() + A); + if (Expr == 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 == 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 == 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 == R_RELAX_TLS_GD_TO_IE_PC || Expr == 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 == R_PPC_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); } } @@ -348,12 +297,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.h =================================================================== --- ELF/OutputSections.h +++ ELF/OutputSections.h @@ -112,7 +112,7 @@ 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 @@ llvm::SmallPtrSet *, 10> MipsOutSections; llvm::DenseMap MipsLocalGotPos; - uintX_t getMipsLocalEntryAddr(uintX_t EntryValue); }; template Index: ELF/OutputSections.cpp =================================================================== --- ELF/OutputSections.cpp +++ ELF/OutputSections.cpp @@ -166,12 +166,6 @@ template typename GotSection::uintX_t -GotSection::getMipsLocalFullAddr(const SymbolBody &B) { - return getMipsLocalEntryAddr(B.getVA()); -} - -template -typename GotSection::uintX_t GotSection::getMipsLocalPageAddr(uintX_t EntryValue) { // Initialize the entry by the %hi(EntryValue) expression // but without right-shifting. @@ -1211,16 +1205,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 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 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 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(); Index: ELF/Target.cpp =================================================================== --- ELF/Target.cpp +++ ELF/Target.cpp @@ -11,7 +11,7 @@ // GOT or PLT entries, etc., are handled in this file. // // Refer the ELF spec for the single letter varaibles, S, A or P, used -// in this file. SA is S+A. +// in this file. // //===----------------------------------------------------------------------===// @@ -70,6 +70,7 @@ class X86TargetInfo final : public TargetInfo { public: X86TargetInfo(); + RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) 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 Val) const override; + + void relaxTlsGdToIe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; + void relaxTlsGdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; + void relaxTlsIeToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; + void relaxTlsLdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) 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(); + RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) 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,40 @@ 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 Val) 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 Val) const override; + void relaxTlsGdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; + void relaxTlsIeToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; + void relaxTlsLdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) 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 Val) const override; bool isRelRelative(uint32_t Type) const override; + RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const override; }; class PPC64TargetInfo final : public TargetInfo { public: PPC64TargetInfo(); + RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) 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 Val) const override; bool isRelRelative(uint32_t Type) const override; }; class AArch64TargetInfo final : public TargetInfo { public: AArch64TargetInfo(); + RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const override; uint32_t getDynRel(uint32_t Type) const override; bool isTlsGlobalDynamicRel(uint32_t Type) const override; bool isTlsInitialExecRel(uint32_t Type) const override; @@ -172,12 +165,9 @@ 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; - 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 Val) const override; + void relaxTlsGdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; + void relaxTlsIeToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; private: static const uint64_t TcbSize = 16; @@ -186,13 +176,14 @@ 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 Val) const override; + RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const override; }; template class MipsTargetInfo final : public TargetInfo { public: MipsTargetInfo(); + RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) 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; @@ -206,8 +197,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 Val) const override; bool isHintRel(uint32_t Type) const override; bool isRelRelative(uint32_t Type) const override; bool refersToGotEntry(uint32_t Type) const override; @@ -354,37 +344,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 Val) 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 Val) 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 Val) 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 Val) const { llvm_unreachable("Should not have claimed to be relaxable"); } @@ -400,6 +376,18 @@ UseLazyBinding = true; PltEntrySize = 16; PltZeroSize = 16; + TlsGdToLeSkip = 2; +} + +RelExpr X86TargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S) const { + switch (Type) { + default: + return R_ABS; + case R_386_PLT32: + case R_386_PC32: + case R_386_GOTPC: + return R_PC; + } } bool X86TargetInfo::isRelRelative(uint32_t Type) const { @@ -538,33 +526,33 @@ } } -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 Val) const { switch (Type) { case R_386_32: - write32le(Loc, SA); + write32le(Loc, Val); break; case R_386_GOT32: { - uint64_t V = SA - Out::Got->getVA() - + uint64_t V = Val - Out::Got->getVA() - Out::Got->getNumEntries() * 4; checkInt<32>(V, Type); write32le(Loc, V); break; } case R_386_GOTOFF: - write32le(Loc, SA - Out::Got->getVA()); + write32le(Loc, Val - Out::Got->getVA()); break; case R_386_GOTPC: - write32le(Loc, SA + Out::Got->getVA() - P); + write32le(Loc, Val + Out::Got->getVA()); break; case R_386_PC32: case R_386_PLT32: - write32le(Loc, SA - P); + write32le(Loc, Val); break; case R_386_TLS_GD: case R_386_TLS_LDM: case R_386_TLS_TPOFF: { - uint64_t V = SA - Out::Got->getVA() - + uint64_t V = Val - Out::Got->getVA() - Out::Got->getNumEntries() * 4; checkInt<32>(V, Type); write32le(Loc, V); @@ -572,13 +560,13 @@ } case R_386_TLS_IE: case R_386_TLS_LDO_32: - write32le(Loc, SA); + write32le(Loc, Val); break; case R_386_TLS_LE: - write32le(Loc, SA - Out::TlsPhdr->p_memsz); + write32le(Loc, Val - Out::TlsPhdr->p_memsz); break; case R_386_TLS_LE_32: - write32le(Loc, Out::TlsPhdr->p_memsz - SA); + write32le(Loc, Out::TlsPhdr->p_memsz - Val); break; default: fatal("unrecognized reloc " + Twine(Type)); @@ -589,9 +577,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 Val) const { // GD can be optimized to LE: // leal x@tlsgd(, %ebx, 1), // call __tls_get_addr@plt @@ -606,11 +593,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 - Val); } // "Ulrich Drepper, ELF Handling For Thread-Local Storage" (5.1 @@ -621,20 +604,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 Val) 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, Val - Out::Got->getVA() - + Out::Got->getNumEntries() * 4); } // In some conditions, relocations can be optimized to avoid using GOT. @@ -642,10 +620,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 Val) 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 @@ -679,17 +655,14 @@ else *Op = 0x80 | Reg | (Reg << 3); } - relocateOne(Loc, BufEnd, R_386_TLS_LE, P, SA); - - return 0; + relocateOne(Loc, R_386_TLS_LE, Val); } -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 Val) 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, Val); + return; } // LD can be optimized to LE: @@ -705,9 +678,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() { @@ -722,6 +692,21 @@ UseLazyBinding = true; PltEntrySize = 16; PltZeroSize = 16; + TlsGdToLeSkip = 2; +} + +RelExpr X86_64TargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S) const { + switch (Type) { + default: + return 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 R_PC; + } } void X86_64TargetInfo::writeGotPltHeader(uint8_t *Buf) const { @@ -847,18 +832,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 Val) 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, Val + 4); } // "Ulrich Drepper, ELF Handling For Thread-Local Storage" (5.5 @@ -872,18 +853,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 Val) 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, Val - 8); } // In some conditions, R_X86_64_GOTTPOFF relocation can be optimized to @@ -891,9 +868,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 Val) 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". @@ -919,8 +895,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, Val + 4); } // "Ulrich Drepper, ELF Handling For Thread-Local Storage" (5.5 @@ -934,16 +909,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 Val) const { if (Type == R_X86_64_DTPOFF64) { - write64le(Loc, SA - Out::TlsPhdr->p_memsz); - return 0; + write64le(Loc, Val - Out::TlsPhdr->p_memsz); + return; } if (Type == R_X86_64_DTPOFF32) { - relocateOne(Loc, BufEnd, R_X86_64_TPOFF32, P, SA); - return 0; + relocateOne(Loc, R_X86_64_TPOFF32, Val); + return; } const uint8_t Inst[] = { @@ -952,27 +926,25 @@ 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 Val) const { switch (Type) { case R_X86_64_32: - checkUInt<32>(SA, Type); - write32le(Loc, SA); + checkUInt<32>(Val, Type); + write32le(Loc, Val); break; case R_X86_64_32S: - checkInt<32>(SA, Type); - write32le(Loc, SA); + checkInt<32>(Val, Type); + write32le(Loc, Val); break; case R_X86_64_64: case R_X86_64_DTPOFF64: - write64le(Loc, SA); + write64le(Loc, Val); break; case R_X86_64_DTPOFF32: - write32le(Loc, SA); + write32le(Loc, Val); break; case R_X86_64_GOTPCREL: case R_X86_64_GOTPCRELX: @@ -981,16 +953,16 @@ case R_X86_64_PLT32: case R_X86_64_TLSGD: case R_X86_64_TLSLD: - write32le(Loc, SA - P); + write32le(Loc, Val); break; case R_X86_64_SIZE32: - write32le(Loc, SA); + write32le(Loc, Val); break; case R_X86_64_SIZE64: - write64le(Loc, SA); + write64le(Loc, Val); break; case R_X86_64_TPOFF32: { - uint64_t Val = SA - Out::TlsPhdr->p_memsz; + Val -= Out::TlsPhdr->p_memsz; checkInt<32>(Val, Type); write32le(Loc, Val); break; @@ -1015,20 +987,24 @@ 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 Val) const { switch (Type) { case R_PPC_ADDR16_HA: - write16be(Loc, applyPPCHa(SA)); + write16be(Loc, applyPPCHa(Val)); break; case R_PPC_ADDR16_LO: - write16be(Loc, applyPPCLo(SA)); + write16be(Loc, applyPPCLo(Val)); break; default: fatal("unrecognized reloc " + Twine(Type)); } } +RelExpr PPCTargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S) const { + return R_ABS; +} + PPC64TargetInfo::PPC64TargetInfo() { GotRel = R_PPC64_GLOB_DAT; RelativeRel = R_PPC64_RELATIVE; @@ -1066,6 +1042,15 @@ return TocVA + 0x8000; } +RelExpr PPC64TargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S) const { + switch (Type) { + default: + return R_ABS; + case R_PPC64_REL24: + return R_PPC_OPD; + } +} + void PPC64TargetInfo::writePlt(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const { @@ -1118,118 +1103,93 @@ } } -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 Val) const { uint64_t TB = getPPC64TocBase(); // For a TOC-relative relocation, adjust the addend and proceed in terms of // the corresponding ADDR16 relocation type. switch (Type) { - case R_PPC64_TOC16: Type = R_PPC64_ADDR16; SA -= TB; break; - case R_PPC64_TOC16_DS: Type = R_PPC64_ADDR16_DS; SA -= TB; break; - case R_PPC64_TOC16_HA: Type = R_PPC64_ADDR16_HA; SA -= TB; break; - case R_PPC64_TOC16_HI: Type = R_PPC64_ADDR16_HI; SA -= TB; break; - case R_PPC64_TOC16_LO: Type = R_PPC64_ADDR16_LO; SA -= TB; break; - case R_PPC64_TOC16_LO_DS: Type = R_PPC64_ADDR16_LO_DS; SA -= TB; break; + case R_PPC64_TOC16: Type = R_PPC64_ADDR16; Val -= TB; break; + case R_PPC64_TOC16_DS: Type = R_PPC64_ADDR16_DS; Val -= TB; break; + case R_PPC64_TOC16_HA: Type = R_PPC64_ADDR16_HA; Val -= TB; break; + case R_PPC64_TOC16_HI: Type = R_PPC64_ADDR16_HI; Val -= TB; break; + case R_PPC64_TOC16_LO: Type = R_PPC64_ADDR16_LO; Val -= TB; break; + case R_PPC64_TOC16_LO_DS: Type = R_PPC64_ADDR16_LO_DS; Val -= TB; break; default: break; } switch (Type) { case R_PPC64_ADDR14: { - checkAlignment<4>(SA, Type); + checkAlignment<4>(Val, Type); // Preserve the AA/LK bits in the branch instruction uint8_t AALK = Loc[3]; - write16be(Loc + 2, (AALK & 3) | (SA & 0xfffc)); + write16be(Loc + 2, (AALK & 3) | (Val & 0xfffc)); break; } case R_PPC64_ADDR16: - checkInt<16>(SA, Type); - write16be(Loc, SA); + checkInt<16>(Val, Type); + write16be(Loc, Val); break; case R_PPC64_ADDR16_DS: - checkInt<16>(SA, Type); - write16be(Loc, (read16be(Loc) & 3) | (SA & ~3)); + checkInt<16>(Val, Type); + write16be(Loc, (read16be(Loc) & 3) | (Val & ~3)); break; case R_PPC64_ADDR16_HA: - write16be(Loc, applyPPCHa(SA)); + write16be(Loc, applyPPCHa(Val)); break; case R_PPC64_ADDR16_HI: - write16be(Loc, applyPPCHi(SA)); + write16be(Loc, applyPPCHi(Val)); break; case R_PPC64_ADDR16_HIGHER: - write16be(Loc, applyPPCHigher(SA)); + write16be(Loc, applyPPCHigher(Val)); break; case R_PPC64_ADDR16_HIGHERA: - write16be(Loc, applyPPCHighera(SA)); + write16be(Loc, applyPPCHighera(Val)); break; case R_PPC64_ADDR16_HIGHEST: - write16be(Loc, applyPPCHighest(SA)); + write16be(Loc, applyPPCHighest(Val)); break; case R_PPC64_ADDR16_HIGHESTA: - write16be(Loc, applyPPCHighesta(SA)); + write16be(Loc, applyPPCHighesta(Val)); break; case R_PPC64_ADDR16_LO: - write16be(Loc, applyPPCLo(SA)); + write16be(Loc, applyPPCLo(Val)); break; case R_PPC64_ADDR16_LO_DS: - write16be(Loc, (read16be(Loc) & 3) | (applyPPCLo(SA) & ~3)); + write16be(Loc, (read16be(Loc) & 3) | (applyPPCLo(Val) & ~3)); break; case R_PPC64_ADDR32: - checkInt<32>(SA, Type); - write32be(Loc, SA); + checkInt<32>(Val, Type); + write32be(Loc, Val); break; case R_PPC64_ADDR64: - write64be(Loc, SA); + write64be(Loc, Val); break; case R_PPC64_REL16_HA: - write16be(Loc, applyPPCHa(SA - P)); + write16be(Loc, applyPPCHa(Val)); break; case R_PPC64_REL16_HI: - write16be(Loc, applyPPCHi(SA - P)); + write16be(Loc, applyPPCHi(Val)); break; case R_PPC64_REL16_LO: - write16be(Loc, applyPPCLo(SA - P)); + write16be(Loc, applyPPCLo(Val)); 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>(Val, Type); + write32be(Loc, (read32be(Loc) & ~Mask) | (Val & Mask)); break; } case R_PPC64_REL32: - checkInt<32>(SA - P, Type); - write32be(Loc, SA - P); + checkInt<32>(Val, Type); + write32be(Loc, Val); break; case R_PPC64_REL64: - write64be(Loc, SA - P); + write64be(Loc, Val); break; case R_PPC64_TOC: - write64be(Loc, SA); + write64be(Loc, Val); break; default: fatal("unrecognized reloc " + Twine(Type)); @@ -1250,6 +1210,27 @@ PltZeroSize = 32; } +RelExpr AArch64TargetInfo::getRelExpr(uint32_t Type, + const SymbolBody &S) const { + switch (Type) { + default: + return 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 R_PC; + case R_AARCH64_ADR_GOT_PAGE: + case R_AARCH64_ADR_PREL_PG_HI21: + case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21: + return R_PAGE_PC; + } +} + bool AArch64TargetInfo::isRelRelative(uint32_t Type) const { switch (Type) { default: @@ -1303,6 +1284,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]! @@ -1318,11 +1303,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, @@ -1336,12 +1320,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 { @@ -1409,112 +1391,104 @@ 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, - uint64_t SA) const { +void AArch64TargetInfo::relocateOne(uint8_t *Loc, uint32_t Type, + uint64_t Val) const { switch (Type) { case R_AARCH64_ABS16: - checkIntUInt<16>(SA, Type); - write16le(Loc, SA); + checkIntUInt<16>(Val, Type); + write16le(Loc, Val); break; case R_AARCH64_ABS32: - checkIntUInt<32>(SA, Type); - write32le(Loc, SA); + checkIntUInt<32>(Val, Type); + write32le(Loc, Val); break; case R_AARCH64_ABS64: - write64le(Loc, SA); + write64le(Loc, Val); break; case R_AARCH64_ADD_ABS_LO12_NC: // This relocation stores 12 bits and there's no instruction // to do it. Instead, we do a 32 bits store of the value // of r_addend bitwise-or'ed Loc. This assumes that the addend // bits in Loc are zero. - or32le(Loc, (SA & 0xFFF) << 10); + or32le(Loc, (Val & 0xFFF) << 10); break; case R_AARCH64_ADR_GOT_PAGE: { - uint64_t X = getAArch64Page(SA) - getAArch64Page(P); + uint64_t X = Val; 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 = Val; 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 = Val; 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 = Val; checkInt<28>(X, Type); or32le(Loc, (X & 0x0FFFFFFC) >> 2); break; } case R_AARCH64_CONDBR19: { - uint64_t X = SA - P; + uint64_t X = Val; checkInt<21>(X, Type); or32le(Loc, (X & 0x1FFFFC) << 3); break; } case R_AARCH64_LD64_GOT_LO12_NC: case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: - checkAlignment<8>(SA, Type); - or32le(Loc, (SA & 0xFF8) << 7); + checkAlignment<8>(Val, Type); + or32le(Loc, (Val & 0xFF8) << 7); break; case R_AARCH64_LDST128_ABS_LO12_NC: - or32le(Loc, (SA & 0x0FF8) << 6); + or32le(Loc, (Val & 0x0FF8) << 6); break; case R_AARCH64_LDST16_ABS_LO12_NC: - or32le(Loc, (SA & 0x0FFC) << 9); + or32le(Loc, (Val & 0x0FFC) << 9); break; case R_AARCH64_LDST8_ABS_LO12_NC: - or32le(Loc, (SA & 0xFFF) << 10); + or32le(Loc, (Val & 0xFFF) << 10); break; case R_AARCH64_LDST32_ABS_LO12_NC: - or32le(Loc, (SA & 0xFFC) << 8); + or32le(Loc, (Val & 0xFFC) << 8); break; case R_AARCH64_LDST64_ABS_LO12_NC: - or32le(Loc, (SA & 0xFF8) << 7); + or32le(Loc, (Val & 0xFF8) << 7); break; case R_AARCH64_PREL16: - checkIntUInt<16>(SA - P, Type); - write16le(Loc, SA - P); + checkIntUInt<16>(Val, Type); + write16le(Loc, Val); break; case R_AARCH64_PREL32: - checkIntUInt<32>(SA - P, Type); - write32le(Loc, SA - P); + checkIntUInt<32>(Val, Type); + write32le(Loc, Val); break; case R_AARCH64_PREL64: - write64le(Loc, SA - P); + write64le(Loc, Val); break; case R_AARCH64_TSTBR14: { - uint64_t X = SA - P; + uint64_t X = Val; checkInt<16>(X, Type); or32le(Loc, (X & 0xFFFC) << 3); break; } case R_AARCH64_TLSLE_ADD_TPREL_HI12: { - uint64_t V = llvm::alignTo(TcbSize, Out::TlsPhdr->p_align) + SA; + uint64_t V = llvm::alignTo(TcbSize, Out::TlsPhdr->p_align) + Val; checkInt<24>(V, Type); updateAArch64Add(Loc, (V & 0xFFF000) >> 12); break; } case R_AARCH64_TLSLE_ADD_TPREL_LO12_NC: { - uint64_t V = llvm::alignTo(TcbSize, Out::TlsPhdr->p_align) + SA; + uint64_t V = llvm::alignTo(TcbSize, Out::TlsPhdr->p_align) + Val; updateAArch64Add(Loc, V & 0xFFF); break; } @@ -1523,9 +1497,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 Val) 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] @@ -1537,7 +1510,7 @@ // nop // nop uint64_t TPOff = llvm::alignTo(TcbSize, Out::TlsPhdr->p_align); - uint64_t X = SA + TPOff; + uint64_t X = Val + TPOff; checkUInt<32>(X, Type); uint32_t NewInst; @@ -1559,15 +1532,12 @@ 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 Val) const { uint64_t TPOff = llvm::alignTo(TcbSize, Out::TlsPhdr->p_align); - uint64_t X = SA + TPOff; + uint64_t X = Val + TPOff; checkUInt<32>(X, Type); uint32_t Inst = read32le(Loc); @@ -1584,16 +1554,18 @@ 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 Val) const { + llvm_unreachable("not implemented"); +} + +RelExpr AMDGPUTargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S) const { llvm_unreachable("not implemented"); } @@ -1611,6 +1583,31 @@ } template +RelExpr MipsTargetInfo::getRelExpr(uint32_t Type, + const SymbolBody &S) const { + switch (Type) { + default: + return R_ABS; + case R_MIPS_HI16: + // 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 (&S == ElfSym::MipsGpDisp) + return R_PC; + return 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 R_PC; + } +} + +template uint32_t MipsTargetInfo::getDynRel(uint32_t Type) const { if (Type == R_MIPS_32 || Type == R_MIPS_64) return R_MIPS_REL32; @@ -1659,11 +1656,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); @@ -1813,9 +1808,8 @@ } template -void MipsTargetInfo::relocateOne(uint8_t *Loc, uint8_t *BufEnd, - uint32_t Type, uint64_t P, - uint64_t SA) const { +void MipsTargetInfo::relocateOne(uint8_t *Loc, uint32_t Type, + uint64_t Val) const { const endianness E = ELFT::TargetEndianness; // Thread pointer and DRP offsets from the start of TLS data area. // https://www.linux-mips.org/wiki/NPTL @@ -1823,71 +1817,71 @@ const uint32_t DTPOffset = 0x8000; switch (Type) { case R_MIPS_32: - write32(Loc, SA); + write32(Loc, Val); break; case R_MIPS_26: { uint32_t Instr = read32(Loc); - write32(Loc, (Instr & ~0x3ffffff) | (SA >> 2)); + write32(Loc, (Instr & ~0x3ffffff) | (Val >> 2)); break; } case R_MIPS_CALL16: case R_MIPS_GOT16: { - int64_t V = SA - getMipsGpAddr(); + int64_t V = Val - getMipsGpAddr(); if (Type == R_MIPS_GOT16) checkInt<16>(V, Type); writeMipsLo16(Loc, V); break; } case R_MIPS_GPREL16: { - int64_t V = SA - getMipsGpAddr(); + int64_t V = Val - getMipsGpAddr(); checkInt<16>(V, Type); writeMipsLo16(Loc, V); break; } case R_MIPS_GPREL32: - write32(Loc, SA - getMipsGpAddr()); + write32(Loc, Val - getMipsGpAddr()); break; case R_MIPS_HI16: - writeMipsHi16(Loc, SA); + writeMipsHi16(Loc, Val); break; case R_MIPS_JALR: // Ignore this optimization relocation for now break; case R_MIPS_LO16: - writeMipsLo16(Loc, SA); + writeMipsLo16(Loc, Val); break; case R_MIPS_PC16: - applyMipsPcReloc(Loc, Type, P, SA); + applyMipsPcReloc(Loc, Type, Val); break; case R_MIPS_PC19_S2: - applyMipsPcReloc(Loc, Type, P, SA); + applyMipsPcReloc(Loc, Type, Val); break; case R_MIPS_PC21_S2: - applyMipsPcReloc(Loc, Type, P, SA); + applyMipsPcReloc(Loc, Type, Val); break; case R_MIPS_PC26_S2: - applyMipsPcReloc(Loc, Type, P, SA); + applyMipsPcReloc(Loc, Type, Val); break; case R_MIPS_PC32: - applyMipsPcReloc(Loc, Type, P, SA); + applyMipsPcReloc(Loc, Type, Val); break; case R_MIPS_PCHI16: - writeMipsHi16(Loc, SA - P); + writeMipsHi16(Loc, Val); break; case R_MIPS_PCLO16: - writeMipsLo16(Loc, SA - P); + writeMipsLo16(Loc, Val); break; case R_MIPS_TLS_DTPREL_HI16: - writeMipsHi16(Loc, SA - DTPOffset); + writeMipsHi16(Loc, Val - DTPOffset); break; case R_MIPS_TLS_DTPREL_LO16: - writeMipsLo16(Loc, SA - DTPOffset); + writeMipsLo16(Loc, Val - DTPOffset); break; case R_MIPS_TLS_TPREL_HI16: - writeMipsHi16(Loc, SA - TPOffset); + writeMipsHi16(Loc, Val - TPOffset); break; case R_MIPS_TLS_TPREL_LO16: - writeMipsLo16(Loc, SA - TPOffset); + writeMipsLo16(Loc, Val - TPOffset); break; default: fatal("unrecognized reloc " + Twine(Type)); 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; @@ -268,23 +270,40 @@ } // Returns the number of relocations processed. -template +template static unsigned handleTlsRelocation(uint32_t Type, SymbolBody &Body, - InputSectionBase &C, RelT &RI) { + InputSectionBase &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::Got->addTlsIndex()) Out::RelaDyn->addReloc({Target->TlsModuleIndexRel, Out::Got, Out::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::Got->addDynTlsEntry(Body)) { @@ -295,17 +314,30 @@ 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()) + + 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::Got->addEntry(Body); + Out::RelaDyn->addReloc({Target->TlsGotRel, Out::Got, + Body.getGotOffset(), false, &Body, + 0}); + } return 2; - if (!Body.isInGot()) { - Out::Got->addEntry(Body); - Out::RelaDyn->addReloc({Target->TlsGotRel, Out::Got, - Body.getGotOffset(), 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; } @@ -329,6 +361,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. @@ -345,7 +427,16 @@ template template void Writer::scanRelocs(InputSectionBase &C, ArrayRef Rels) { + bool IsAlloc = C.getSectionHdr()->sh_flags & SHF_ALLOC; + + auto AddDyn = [=](const DynamicReloc &Reloc) { + if (IsAlloc) + Out::RelaDyn->addReloc(Reloc); + }; + 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,22 +460,33 @@ if (auto *S = dyn_cast>(&Body)) S->File->IsUsed = true; + RelExpr Expr = Target->getRelExpr(Type, Body); + + 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, Offset, Addend, Expr)) { I += (Processed - 1); continue; } if (Target->needsDynRelative(Type)) - Out::RelaDyn->addReloc({Target->RelativeRel, C.OutSec, Offset, true, - &Body, getAddend(RI)}); + AddDyn({Target->RelativeRel, C.OutSec, Offset, true, &Body, + getAddend(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>(&Body)) { - if (Target->needsCopyRel(Type, Body)) { + if (IsAlloc && Target->needsCopyRel(Type, *B)) { if (!B->needsCopy()) addCopyRelSymbol(B); + C.Relocations.push_back({Expr, Type, Offset, Addend, &Body}); continue; } } @@ -395,6 +497,15 @@ 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::Plt->addEntry(Body); @@ -407,22 +518,43 @@ if (Target->UseLazyBinding) { Out::GotPlt->addEntry(Body); - Out::RelaPlt->addReloc({Rel, Out::GotPlt, - Body.getGotPltOffset(), - !Preemptible, &Body, 0}); + if (IsAlloc) + Out::RelaPlt->addReloc({Rel, Out::GotPlt, + Body.getGotPltOffset(), + !Preemptible, &Body, 0}); } else { if (Body.isInGot()) continue; Out::Got->addEntry(Body); - Out::RelaDyn->addReloc({Rel, Out::Got, - Body.getGotOffset(), !Preemptible, - &Body, 0}); + AddDyn({Rel, Out::Got, Body.getGotOffset(), !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::Got->addEntry(Body); @@ -443,26 +575,23 @@ DynType = Target->GotRel; else DynType = Target->RelativeRel; - Out::RelaDyn->addReloc({DynType, Out::Got, - Body.getGotOffset(), !Preemptible, - &Body, 0}); + AddDyn({DynType, Out::Got, Body.getGotOffset(), + !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::MipsGpDisp || - &Body == ElfSym::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::RelaDyn->addReloc({Target->getDynRel(Type), C.OutSec, Offset, - false, &Body, getAddend(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 @@ // 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)) + if (Target->isSizeRel(Type)) { + C.Relocations.push_back({R_SIZE, Type, Offset, Addend, &Body}); continue; - - uintX_t Addend = getAddend(RI); - if (Config->EMachine == EM_PPC64 && RI.getType(false) == R_PPC64_TOC) { - Out::RelaDyn->addReloc({R_PPC64_RELATIVE, C.OutSec, Offset, false, - nullptr, - (uintX_t)getPPC64TocBase() + 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; } - Out::RelaDyn->addReloc( - {Target->RelativeRel, C.OutSec, Offset, true, &Body, Addend}); + + 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,9 +624,8 @@ } template void Writer::scanRelocs(InputSection &C) { - if (C.getSectionHdr()->sh_flags & SHF_ALLOC) - for (const Elf_Shdr *RelSec : C.RelocSections) - scanRelocs(C, *RelSec); + for (const Elf_Shdr *RelSec : C.RelocSections) + scanRelocs(C, *RelSec); } template 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