Index: ELF/Arch/PPC.cpp =================================================================== --- ELF/Arch/PPC.cpp +++ ELF/Arch/PPC.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "Symbols.h" +#include "SyntheticSections.h" #include "Target.h" #include "lld/Common/ErrorHandler.h" #include "llvm/Support/Endian.h" @@ -21,6 +22,7 @@ class PPC final : public TargetInfo { public: PPC(); + void writeGotHeader(uint8_t *Buf) const override; void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override; RelExpr getRelExpr(RelType Type, const Symbol &S, const uint8_t *Loc) const override; @@ -28,8 +30,24 @@ } // namespace PPC::PPC() { + GotRel = R_PPC_GLOB_DAT; NoneRel = R_PPC_NONE; + PltRel = R_PPC_JMP_SLOT; + RelativeRel = R_PPC_RELATIVE; GotBaseSymInGotPlt = false; + RelativeRel = R_PPC_RELATIVE; + GotEntrySize = 4; + PltEntrySize = 12; + GotHeaderEntriesNum = 4; + PltHeaderSize = 72; +} + +void PPC::writeGotHeader(uint8_t *Buf) const { + // _GLOBAL_OFFSET_TABLE[-1] = blrl + write32(Buf, 0x4e800021); + // _GLOBAL_OFFSET_TABLE_[0] = _DYNAMIC + write32(Buf + 4, In.Dynamic->getVA()); + // _GLOBAL_OFFSET_TABLE_[1,2] are reserved. } RelExpr PPC::getRelExpr(RelType Type, const Symbol &S, @@ -38,7 +56,13 @@ case R_PPC_REL14: case R_PPC_REL24: case R_PPC_REL32: + case R_PPC_LOCAL24PC: + case R_PPC_REL16_LO: + case R_PPC_REL16_HI: + case R_PPC_REL16_HA: return R_PC; + case R_PPC64_GOT16: + return R_GOT_OFF; case R_PPC_PLTREL24: return R_PLT_PC; default: @@ -49,25 +73,42 @@ void PPC::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { switch (Type) { case R_PPC_ADDR16_HA: - write16be(Loc, (Val + 0x8000) >> 16); + case R_PPC_REL16_HA: + write16(Loc, (Val + 0x8000) >> 16); break; case R_PPC_ADDR16_HI: - write16be(Loc, Val >> 16); + case R_PPC_REL16_HI: + write16(Loc, Val >> 16); break; case R_PPC_ADDR16_LO: - write16be(Loc, Val); + case R_PPC_REL16_LO: + write16(Loc, Val); break; case R_PPC_ADDR32: case R_PPC_REL32: - write32be(Loc, Val); + checkInt(Loc, Val, 32, Type); + write32(Loc, Val); break; - case R_PPC_REL14: - write32be(Loc, read32be(Loc) | (Val & 0xFFFC)); + case R_PPC_REL14: { + uint32_t Mask = 0x0000FFFC; + checkInt(Loc, Val, 16, Type); + checkAlignment(Loc, Val, 4, Type); + write32(Loc, (read32(Loc) & ~Mask) | (Val & Mask)); + break; + } + case R_PPC_GOT16: + checkInt(Loc, Val, 16, Type); + write16(Loc, Val); break; case R_PPC_PLTREL24: case R_PPC_REL24: - write32be(Loc, read32be(Loc) | (Val & 0x3FFFFFC)); + case R_PPC_LOCAL24PC: { + uint32_t Mask = 0x03FFFFFC; + checkInt(Loc, Val, 26, Type); + checkAlignment(Loc, Val, 4, Type); + write32(Loc, (read32(Loc) & ~Mask) | (Val & Mask)); break; + } default: error(getErrorLocation(Loc) + "unrecognized relocation " + toString(Type)); } Index: ELF/Relocations.cpp =================================================================== --- ELF/Relocations.cpp +++ ELF/Relocations.cpp @@ -832,9 +832,14 @@ static void addPltEntry(PltSection *Plt, GotPltSection *GotPlt, RelocationBaseSection *Rel, RelType Type, Symbol &Sym) { Plt->addEntry(Sym); - GotPlt->addEntry(Sym); - Rel->addReloc( - {Type, GotPlt, Sym.getGotPltOffset(), !Sym.IsPreemptible, &Sym, 0}); + if (Config->EMachine == EM_PPC) { + Rel->addReloc( + {Type, Plt, 72 + Sym.getGotPltOffset(), !Sym.IsPreemptible, &Sym, 0}); + } else { + GotPlt->addEntry(Sym); + Rel->addReloc( + {Type, GotPlt, Sym.getGotPltOffset(), !Sym.IsPreemptible, &Sym, 0}); + } } static void addGotEntry(Symbol &Sym) { Index: ELF/SyntheticSections.cpp =================================================================== --- ELF/SyntheticSections.cpp +++ ELF/SyntheticSections.cpp @@ -2251,7 +2251,10 @@ // On PowerPC64 the lazy symbol resolvers go into the `global linkage table` // in the .glink section, rather then the typical .plt section. PltSection::PltSection(bool IsIplt) - : SyntheticSection(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS, 16, + : SyntheticSection(SHF_ALLOC | SHF_EXECINSTR | + (Config->EMachine == EM_PPC ? SHF_WRITE : 0), + Config->EMachine == EM_PPC ? SHT_NOBITS : SHT_PROGBITS, + Config->EMachine == EM_PPC ? 4 : 16, Config->EMachine == EM_PPC64 ? ".glink" : ".plt"), HeaderSize(!IsIplt || Config->ZRetpolineplt ? Target->PltHeaderSize : 0), IsIplt(IsIplt) { Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -236,7 +236,9 @@ } uint64_t GotOff = 0; - if (Config->EMachine == EM_PPC || Config->EMachine == EM_PPC64) + if (Config->EMachine == EM_PPC) + GotOff = 4; + else if (Config->EMachine == EM_PPC64) GotOff = 0x8000; Symtab->addSymbol(Defined{/*File=*/nullptr, GotSymName, STB_GLOBAL, @@ -245,6 +247,12 @@ ElfSym::GlobalOffsetTable = cast(S); } + if (Config->EMachine == EM_PPC) + if (Symbol *S = Symtab->find("_SDA_BASE_")) + if (!S->isDefined()) + S->resolve(Defined{/*File=*/nullptr, "_SDA_BASE", STB_GLOBAL, + STV_HIDDEN, STT_NOTYPE, 4, /*Size=*/0, In.Got}); + // __ehdr_start is the location of ELF file headers. Note that we define // this symbol unconditionally even when using a linker script, which // differs from the behavior implemented by GNU linker which only define