Index: ELF/Arch/PPC.cpp =================================================================== --- ELF/Arch/PPC.cpp +++ ELF/Arch/PPC.cpp @@ -6,7 +6,9 @@ // //===----------------------------------------------------------------------===// +#include "OutputSections.h" #include "Symbols.h" +#include "SyntheticSections.h" #include "Target.h" #include "lld/Common/ErrorHandler.h" #include "llvm/Support/Endian.h" @@ -21,26 +23,155 @@ class PPC final : public TargetInfo { public: PPC(); + void writeGotHeader(uint8_t *Buf) const override; + void writePPC32GlinkSection(uint8_t *Buf, size_t NumEntries) const override; + void writeGotPlt(uint8_t *Buf, const Symbol &S) const override; + bool needsThunk(RelExpr Expr, RelType RelocType, const InputFile *File, + uint64_t BranchAddr, const Symbol &S) const override; + uint32_t getThunkSectionSpacing() const override; + bool inBranchRange(RelType Type, uint64_t Src, uint64_t Dst) 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; }; } // namespace +static uint16_t lo(uint32_t V) { return V; } +static uint16_t ha(uint32_t V) { return (V + 0x8000) >> 16; } + PPC::PPC() { + GotRel = R_PPC_GLOB_DAT; NoneRel = R_PPC_NONE; + PltRel = R_PPC_JMP_SLOT; + RelativeRel = R_PPC_RELATIVE; GotBaseSymInGotPlt = false; + GotHeaderEntriesNum = 3; + GotPltHeaderEntriesNum = 0; + PltHeaderSize = 64; // size of PLTresolve in .glink + PltEntrySize = 4; + + NeedsThunks = true; + + DefaultMaxPageSize = 65536; + DefaultImageBase = 0x10000000; + + write32(TrapInstr.data(), 0x7fe00008); +} + +void PPC::writeGotHeader(uint8_t *Buf) const { + // _GLOBAL_OFFSET_TABLE_[0] = _DYNAMIC + // glibc stores _dl_runtime_resolve in _GLOBAL_OFFSET_TABLE_[1], + // link_map in _GLOBAL_OFFSET_TABLE_[2]. + write32(Buf, In.Dynamic->getVA()); +} + +void PPC::writePPC32GlinkSection(uint8_t *Buf, size_t NumEntries) const { + // On PPC Secure-PLT ABI, bl foo@plt jumps to a Secure-PLT call stub, which + // arranges for reading the address from .plt (called .got.plt on other + // targets) and jumping there. + // + // a) With immediate PLT resolution (bindnow), the .plt entry stores the entry + // point of the target function, which was overwritten by the dynamic linker. + // b) With lazy PLT resolution. The .plt address is a `b PLTresolve` + // instruction in .glink, filled at link-time by PPC::writeGotPlt(). + + // Write N `b PLTresolve` first. A Secure-PLT call stub jumps to one of the + // instructions through a .plt entry. + for (size_t I = 0; I != NumEntries; ++I) + write32(Buf + 4 * I, 0x48000000 | 4 * (NumEntries - I)); + Buf += 4 * NumEntries; + + // Then write PLTresolve, which has two forms: PIC and non-PIC. PLTresolve() + // computes the PLT index (by computing the distance from the landing b to + // itself) and calls _dl_runtime_resolve() in glibc. + uint32_t GOT = In.Got->getVA(); + uint32_t Glink = In.Plt->getVA(); // VA of .glink + const uint8_t *End = Buf + 64; + if (Config->Pic) { + uint32_t AfterBcl = In.Plt->getSize() - Target->PltHeaderSize + 12; + uint32_t GotBcl = GOT + 4 - (Glink + AfterBcl); + write32(Buf + 0, 0x3d6b0000 | ha(AfterBcl)); // addis r11,r11,1f-glink@ha + write32(Buf + 4, 0x7c0802a6); // mflr r0 + write32(Buf + 8, 0x429f0005); // bcl 20,30,.+4 + write32(Buf + 12, 0x396b0000 | lo(AfterBcl)); // 1: addi r11,r11,1b-.glink@l + write32(Buf + 16, 0x7d8802a6); // mflr r12 + write32(Buf + 20, 0x7c0803a6); // mtlr r0 + write32(Buf + 24, 0x7d6c5850); // sub r11,r11,r12 + write32(Buf + 28, 0x3d8c0000 | ha(GotBcl)); // addis 12,12,GOT+4-1b@ha + if (ha(GotBcl) == ha(GotBcl + 4)) { + write32(Buf + 32, 0x800c0000 | lo(GotBcl)); // lwz r0,r12,GOT+4-1b@l(r12) + write32(Buf + 36, + 0x818c0000 | lo(GotBcl + 4)); // lwz r12,r12,GOT+8-1b@l(r12) + } else { + write32(Buf + 32, 0x840c0000 | lo(GotBcl)); // lwzu r0,r12,GOT+4-1b@l(r12) + write32(Buf + 36, 0x818c0000 | 4); // lwz r12,r12,4(r12) + } + write32(Buf + 40, 0x7c0903a6); // mtctr 0 + write32(Buf + 44, 0x7c0b5a14); // add r0,11,11 + write32(Buf + 48, 0x7d605a14); // add r11,0,11 + write32(Buf + 52, 0x4e800420); // bctr + Buf += 56; + } else { + write32(Buf + 0, 0x3d800000 | ha(GOT + 4)); // lis r12,GOT+4@ha + write32(Buf + 4, 0x3d6b0000 | ha(-Glink)); // addis r11,r11,-Glink@ha + if (ha(GOT + 4) == ha(GOT + 8)) + write32(Buf + 8, 0x800c0000 | lo(GOT + 4)); // lwz r0,GOT+4@l(r12) + else + write32(Buf + 8, 0x840c0000 | lo(GOT + 4)); // lwzu r0,GOT+4@l(r12) + write32(Buf + 12, 0x396b0000 | lo(-Glink)); // addi r11,r11,-Glink@l + write32(Buf + 16, 0x7c0903a6); // mtctr r0 + write32(Buf + 20, 0x7c0b5a14); // add r0,r11,r11 + if (ha(GOT + 4) == ha(GOT + 8)) + write32(Buf + 24, 0x818c0000 | lo(GOT + 8)); // lwz r12,GOT+8@ha(r12) + else + write32(Buf + 24, 0x818c0000 | 4); // lwz r12,4(r12) + write32(Buf + 28, 0x7d605a14); // add r11,r0,r11 + write32(Buf + 32, 0x4e800420); // bctr + Buf += 36; + } + + // Pad with nop. They should not be executed. + for (; Buf < End; Buf += 4) + write32(Buf, 0x60000000); +} + +void PPC::writeGotPlt(uint8_t *Buf, const Symbol &S) const { + // Address of the symbol resolver stub in .glink . + write32(Buf, In.Plt->getVA() + 4 * S.PltIndex); +} + +bool PPC::needsThunk(RelExpr Expr, RelType Type, const InputFile *File, + uint64_t BranchAddr, const Symbol &S) const { + if (Type != R_PPC_REL24 && Type != R_PPC_PLTREL24) + return false; + return !(Expr == R_PC && PPC::inBranchRange(Type, BranchAddr, S.getVA())); +} + +uint32_t PPC::getThunkSectionSpacing() const { return 0x2000000; } + +bool PPC::inBranchRange(RelType Type, uint64_t Src, uint64_t Dst) const { + uint64_t Offset = Dst - Src; + if (Type == R_PPC_REL24 || R_PPC_PLTREL24) + return isInt<26>(Offset); + llvm_unreachable("unsupported relocation type used in branch"); } RelExpr PPC::getRelExpr(RelType Type, const Symbol &S, const uint8_t *Loc) const { switch (Type) { 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_PPC_PLTREL24: + case R_PPC_GOT16: + return R_GOT_OFF; + case R_PPC_REL24: return R_PLT_PC; + case R_PPC_PLTREL24: + return R_PPC32_PLTREL; default: return R_ABS; } @@ -48,26 +179,43 @@ void PPC::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { switch (Type) { + case R_PPC_ADDR16: + case R_PPC_GOT16: + checkInt(Loc, Val, 16, Type); + write16(Loc, Val); + break; 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); + 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_PLTREL24: + } case R_PPC_REL24: - write32be(Loc, read32be(Loc) | (Val & 0x3FFFFFC)); + case R_PPC_LOCAL24PC: + case R_PPC_PLTREL24: { + 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/InputFiles.h =================================================================== --- ELF/InputFiles.h +++ ELF/InputFiles.h @@ -117,6 +117,10 @@ // True if this is an argument for --just-symbols. Usually false. bool JustSymbols = false; + // OutSecOff of .got2 in the current file. This is used by PPC32 secure PLT to + // compute offsets in PLT call stubs. + uint32_t PPC32Got2OutSecOff = 0; + // On PPC64 we need to keep track of which files contain small code model // relocations that access the .toc section. To minimize the chance of a // relocation overflow, files that do contain said relocations should have Index: ELF/InputSection.cpp =================================================================== --- ELF/InputSection.cpp +++ ELF/InputSection.cpp @@ -718,6 +718,8 @@ Dest = getARMUndefinedRelativeWeakVA(Type, A, P); else if (Config->EMachine == EM_AARCH64) Dest = getAArch64UndefinedRelativeWeakVA(Type, A, P); + else if (Config->EMachine == EM_PPC && !Config->Pic) + Dest = Target->getImageBase(); else Dest = Sym.getVA(A); } else { @@ -730,6 +732,11 @@ case R_PLT_PC: case R_PPC64_CALL_PLT: return Sym.getPltVA() + A - P; + case R_PPC32_PLTREL: + // R_PPC_PLTREL24 uses the addend (usually 0 or 0x8000) to indicate r30 + // stores _GLOBAL_OFFSET_TABLE_ or .got2+0x8000. The addend is ignored for + // target VA compuation. + return Sym.getPltVA() - P; case R_PPC64_CALL: { uint64_t SymVA = Sym.getVA(A); // If we have an undefined weak symbol, we might get here with a symbol Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ ELF/LinkerScript.cpp @@ -663,6 +663,13 @@ assert(S->getOutputSection()->SectionIndex == UINT32_MAX); }; + if (Config->EMachine == EM_PPC) { + // Older glibc assumes .rela.dyn includes .rela.plt + Add(In.RelaDyn); + if (In.RelaPlt->isLive() && !In.RelaPlt->Parent) + In.RelaDyn->getParent()->addSection(In.RelaPlt); + } + // For futher --emit-reloc handling code we need target output section // to be created before we create relocation output section, so we want // to create target sections first. We do not want priority handling Index: ELF/Options.td =================================================================== --- ELF/Options.td +++ ELF/Options.td @@ -537,6 +537,7 @@ def: Flag<["-"], "p">; def: Separate<["--", "-"], "rpath-link">; def: J<"rpath-link=">; +def: F<"secure-plt">; def: F<"sort-common">; def: F<"stats">; def: F<"warn-execstack">; Index: ELF/Relocations.h =================================================================== --- ELF/Relocations.h +++ ELF/Relocations.h @@ -91,6 +91,7 @@ R_MIPS_GOT_OFF32, R_MIPS_TLSGD, R_MIPS_TLSLD, + R_PPC32_PLTREL, R_PPC64_CALL, R_PPC64_CALL_PLT, R_PPC64_RELAX_TOC, @@ -136,7 +137,7 @@ void createInitialThunkSections(ArrayRef OutputSections); - std::pair getThunk(InputSection *IS, Symbol &Sym, RelType Type, + std::pair getThunk(InputSection *IS, Relocation &Rel, uint64_t Src); ThunkSection *addThunkSection(OutputSection *OS, InputSectionDescription *, Index: ELF/Relocations.cpp =================================================================== --- ELF/Relocations.cpp +++ ELF/Relocations.cpp @@ -363,7 +363,7 @@ // Returns true if Expr refers a PLT entry. static bool needsPlt(RelExpr Expr) { - return oneof(Expr); + return oneof(Expr); } // Returns true if Expr refers a GOT entry. Note that this function @@ -399,8 +399,8 @@ R_MIPS_GOT_LOCAL_PAGE, R_MIPS_GOTREL, R_MIPS_GOT_OFF, R_MIPS_GOT_OFF32, R_MIPS_GOT_GP_PC, R_MIPS_TLSGD, R_AARCH64_GOT_PAGE_PC, R_GOT_PC, R_GOTONLY_PC, R_GOTPLTONLY_PC, - R_PLT_PC, R_TLSGD_GOT, R_TLSGD_GOTPLT, R_TLSGD_PC, R_PPC64_CALL_PLT, - R_PPC64_RELAX_TOC, R_TLSDESC_CALL, R_TLSDESC_PC, + R_PLT_PC, R_TLSGD_GOT, R_TLSGD_GOTPLT, R_TLSGD_PC, R_PPC32_PLTREL, + R_PPC64_CALL_PLT, R_PPC64_RELAX_TOC, R_TLSDESC_CALL, R_TLSDESC_PC, R_AARCH64_TLSDESC_PAGE, R_HINT, R_TLSLD_HINT, R_TLSIE_HINT>(E)) return true; @@ -469,6 +469,7 @@ // reference to the symbol itself. switch (Expr) { case R_PLT_PC: + case R_PPC32_PLTREL: return R_PC; case R_PPC64_CALL_PLT: return R_PPC64_CALL; @@ -1105,6 +1106,9 @@ getLocation(Sec, Sym, Offset)); } + // Read an addend. + int64_t Addend = computeAddend(Rel, End, Sec, Expr, Sym.isLocal()); + // Relax relocations. // // If we know that a PLT entry will be resolved within the same ELF module, we @@ -1114,10 +1118,15 @@ // runtime, because the main exectuable is always at the beginning of a search // list. We can leverage that fact. if (!Sym.IsPreemptible && (!Sym.isGnuIFunc() || Config->ZIfuncNoplt)) { - if (Expr == R_GOT_PC && !isAbsoluteValue(Sym)) + if (Expr == R_GOT_PC && !isAbsoluteValue(Sym)) { Expr = Target->adjustRelaxExpr(Type, RelocatedAddr, Expr); - else + } else { + // Addend of R_PPC_PLTREL24 is used to choose call stub type. It should be + // ignored if optimized to R_PC. + if (Config->EMachine == EM_PPC && Expr == R_PPC32_PLTREL) + Addend = 0; Expr = fromPlt(Expr); + } } // If the relocation does not emit a GOT or GOTPLT entry but its computation @@ -1131,9 +1140,6 @@ In.Got->HasGotOffRel = true; } - // Read an addend. - int64_t Addend = computeAddend(Rel, End, Sec, Expr, Sym.isLocal()); - // Process some TLS relocations, including relaxing TLS relocations. // Note that this function does not handle all TLS relocations. if (unsigned Processed = @@ -1618,27 +1624,27 @@ return true; } -std::pair ThunkCreator::getThunk(InputSection *IS, Symbol &Sym, - RelType Type, uint64_t Src) { +std::pair ThunkCreator::getThunk(InputSection *IS, + Relocation &Rel, uint64_t Src) { std::vector *ThunkVec = nullptr; // We use (section, offset) pair to find the thunk position if possible so // that we create only one thunk for aliased symbols or ICFed sections. - if (auto *D = dyn_cast(&Sym)) + if (auto *D = dyn_cast(Rel.Sym)) if (!D->isInPlt() && D->Section) ThunkVec = &ThunkedSymbolsBySection[{D->Section->Repl, D->Value}]; if (!ThunkVec) - ThunkVec = &ThunkedSymbols[&Sym]; + ThunkVec = &ThunkedSymbols[Rel.Sym]; // Check existing Thunks for Sym to see if they can be reused for (Thunk *T : *ThunkVec) if (isThunkSectionCompatible(IS, T->getThunkTargetSym()->Section) && - T->isCompatibleWith(Type) && - Target->inBranchRange(Type, Src, T->getThunkTargetSym()->getVA())) + T->isCompatibleWith(*IS, Rel) && + Target->inBranchRange(Rel.Type, Src, T->getThunkTargetSym()->getVA())) return std::make_pair(T, false); // No existing compatible Thunk in range, create a new one - Thunk *T = addThunk(Type, Sym); + Thunk *T = addThunk(*IS, Rel); ThunkVec->push_back(T); return std::make_pair(T, true); } @@ -1717,7 +1723,7 @@ Thunk *T; bool IsNew; - std::tie(T, IsNew) = getThunk(IS, *Rel.Sym, Rel.Type, Src); + std::tie(T, IsNew) = getThunk(IS, Rel, Src); if (IsNew) { // Find or create a ThunkSection for the new Thunk @@ -1733,6 +1739,10 @@ // Redirect relocation to Thunk, we never go via the PLT to a Thunk Rel.Sym = T->getThunkTargetSym(); Rel.Expr = fromPlt(Rel.Expr); + + // Addend of R_PPC_PLTREL24 should be ignored after changing to R_PC. + if (Config->EMachine == EM_PPC && Rel.Type == R_PPC_PLTREL24) + Rel.Addend = 0; } for (auto &P : ISD->ThunkSections) Index: ELF/SyntheticSections.h =================================================================== --- ELF/SyntheticSections.h +++ ELF/SyntheticSections.h @@ -1041,6 +1041,17 @@ size_t Size = 0; }; +// Used to compute OutSecOff of .got2 in each object file. This is needed to +// synthesize PLT entries for PPC32 secure PLT ABI. +class PPC32Got2Section final : public SyntheticSection { +public: + PPC32Got2Section(); + size_t getSize() const override { return 0; } + bool isNeeded() const override; + void finalizeContents() override; + void writeTo(uint8_t *Buf) override {} +}; + // This section is used to store the addresses of functions that are called // in range-extending thunks on PowerPC64. When producing position dependant // code the addresses are link-time constants and the table is written out to @@ -1100,6 +1111,7 @@ MipsRldMapSection *MipsRldMap; PltSection *Plt; PltSection *Iplt; + PPC32Got2Section *PPC32Got2; RelocationBaseSection *RelaDyn; RelrBaseSection *RelrDyn; RelocationBaseSection *RelaPlt; Index: ELF/SyntheticSections.cpp =================================================================== --- ELF/SyntheticSections.cpp +++ ELF/SyntheticSections.cpp @@ -1057,10 +1057,15 @@ // section. I don't know why we have a BSS style type for the section but it is // consitent across both 64-bit PowerPC ABIs as well as the 32-bit PowerPC ABI. GotPltSection::GotPltSection() - : SyntheticSection(SHF_ALLOC | SHF_WRITE, - Config->EMachine == EM_PPC64 ? SHT_NOBITS : SHT_PROGBITS, - Config->Wordsize, - Config->EMachine == EM_PPC64 ? ".plt" : ".got.plt") {} + : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, Config->Wordsize, + ".got.plt") { + if (Config->EMachine == EM_PPC) { + Name = ".plt"; + } else if (Config->EMachine == EM_PPC64) { + Type = SHT_NOBITS; + Name = ".plt"; + } +} void GotPltSection::addEntry(Symbol &Sym) { assert(Sym.PltIndex == Entries.size()); @@ -1404,6 +1409,11 @@ } } + // DT_PPC_GOT indicates to glibc Secure PLT is used. If DT_PPC_GOT is absent, + // glibc assumes the old-style BSS PLT layout which we don't support. + if (Config->EMachine == EM_PPC) + add(DT_PPC_GOT, [] { return In.Got->getVA(); }); + // Glink dynamic tag is required by the V2 abi if the plt section isn't empty. if (Config->EMachine == EM_PPC64 && In.Plt->isNeeded()) { // The Glink tag points to 32 bytes before the first lazy symbol resolution @@ -2279,8 +2289,11 @@ // 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, - Config->EMachine == EM_PPC64 ? ".glink" : ".plt"), + : SyntheticSection( + SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS, 16, + (Config->EMachine == EM_PPC || Config->EMachine == EM_PPC64) + ? ".glink" + : ".plt"), HeaderSize(!IsIplt || Config->ZRetpolineplt ? Target->PltHeaderSize : 0), IsIplt(IsIplt) { // The PLT needs to be writable on SPARC as the dynamic linker will @@ -2290,6 +2303,11 @@ } void PltSection::writeTo(uint8_t *Buf) { + if (Config->EMachine == EM_PPC) { + Target->writePPC32GlinkSection(Buf, Entries.size()); + return; + } + // At beginning of PLT or retpoline IPLT, we have code to call the dynamic // linker to resolve dynsyms at runtime. Write such code. if (HeaderSize) @@ -3236,6 +3254,37 @@ return Changed; } +PPC32Got2Section::PPC32Got2Section() + : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, 4, ".got2") {} + +bool PPC32Got2Section::isNeeded() const { + // See the comment below. This is not needed if there is no other + // InputSection. + for (BaseCommand *Base : getParent()->SectionCommands) + if (auto *ISD = dyn_cast(Base)) + for (InputSection *IS : ISD->Sections) + if (IS != this) + return true; + return false; +} + +void PPC32Got2Section::finalizeContents() { + // In PIC code, PPC32 may have multiple GOT sections, one per file in .got2 . + // This function computes OutSecOff of each .got2 to be used in + // PPC32PltCallStub::writeTo(). The purpose of this empty synthetic section is + // to collect input sections named ".got2". + uint32_t Offset = 0; + for (BaseCommand *Base : getParent()->SectionCommands) + if (auto *ISD = dyn_cast(Base)) { + for (InputSection *IS : ISD->Sections) { + if (IS == this) + continue; + IS->File->PPC32Got2OutSecOff = Offset; + Offset += (uint32_t)IS->getSize(); + } + } +} + // If linking position-dependent code then the table will store the addresses // directly in the binary so the section has type SHT_PROGBITS. If linking // position-independent code the section has type SHT_NOBITS since it will be Index: ELF/Target.h =================================================================== --- ELF/Target.h +++ ELF/Target.h @@ -42,6 +42,7 @@ virtual void writePlt(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const {} + virtual void writePPC32GlinkSection(uint8_t *Buf, size_t NumEntries) const {} virtual void addPltHeaderSymbols(InputSection &IS) const {} virtual void addPltSymbols(InputSection &IS, uint64_t Off) const {} Index: ELF/Thunks.h =================================================================== --- ELF/Thunks.h +++ ELF/Thunks.h @@ -46,9 +46,12 @@ // a branch and fall through to the first Symbol in the Target. virtual InputSection *getTargetInputSection() const { return nullptr; } - // To reuse a Thunk the caller as identified by the Type must be - // compatible with it. - virtual bool isCompatibleWith(RelType Type) const { return true; } + // To reuse a Thunk the InputSection and the relocation must be compatible + // with it. + virtual bool isCompatibleWith(const InputSection &, + const Relocation &) const { + return true; + } Defined *getThunkTargetSym() const { return Syms[0]; } @@ -61,8 +64,8 @@ }; // For a Relocation to symbol S create a Thunk to be added to a synthetic -// ThunkSection. At present there are implementations for ARM and Mips Thunks. -Thunk *addThunk(RelType Type, Symbol &S); +// ThunkSection. +Thunk *addThunk(const InputSection &IS, Relocation &Rel); } // namespace elf } // namespace lld Index: ELF/Thunks.cpp =================================================================== --- ELF/Thunks.cpp +++ ELF/Thunks.cpp @@ -78,7 +78,8 @@ bool mayUseShortThunk(); uint32_t size() override { return mayUseShortThunk() ? 4 : sizeLong(); } void writeTo(uint8_t *Buf) override; - bool isCompatibleWith(RelType Type) const override; + bool isCompatibleWith(const InputSection &IS, + const Relocation &Rel) const override; // Returns the size of a long thunk. virtual uint32_t sizeLong() = 0; @@ -107,7 +108,8 @@ bool mayUseShortThunk(); uint32_t size() override { return mayUseShortThunk() ? 4 : sizeLong(); } void writeTo(uint8_t *Buf) override; - bool isCompatibleWith(RelType Type) const override; + bool isCompatibleWith(const InputSection &IS, + const Relocation &Rel) const override; // Returns the size of a long thunk. virtual uint32_t sizeLong() = 0; @@ -170,7 +172,8 @@ uint32_t sizeLong() override { return 8; } void writeLong(uint8_t *Buf) override; void addSymbols(ThunkSection &IS) override; - bool isCompatibleWith(uint32_t RelocType) const override; + bool isCompatibleWith(const InputSection &IS, + const Relocation &Rel) const override; }; class ARMV5PILongThunk final : public ARMThunk { @@ -180,7 +183,8 @@ uint32_t sizeLong() override { return 16; } void writeLong(uint8_t *Buf) override; void addSymbols(ThunkSection &IS) override; - bool isCompatibleWith(uint32_t RelocType) const override; + bool isCompatibleWith(const InputSection &IS, + const Relocation &Rel) const override; }; // Implementations of Thunks for Arm v6-M. Only Thumb instructions are permitted @@ -235,6 +239,24 @@ InputSection *getTargetInputSection() const override; }; +class PPC32PltCallStub final : public Thunk { +public: + PPC32PltCallStub(const InputSection &IS, const Relocation &Rel, Symbol &Dest) + : Thunk(Dest), Addend(Rel.Type == R_PPC_PLTREL24 ? Rel.Addend : 0), + File(IS.File) {} + uint32_t size() override { return 16; } + void writeTo(uint8_t *Buf) override; + void addSymbols(ThunkSection &IS) override; + bool isCompatibleWith(const InputSection &IS, const Relocation &Rel) const override; + +private: + // For R_PPC_PLTREL24, this records the addend, which will be used to decide + // the offsets in the call stub. + uint32_t Addend; + + // Records the call site of the call stub. + const InputFile *File; +}; // PPC64 Plt call stubs. // Any call site that needs to call through a plt entry needs a call stub in @@ -396,9 +418,10 @@ Target->relocateOne(Buf, R_ARM_JUMP24, Offset); } -bool ARMThunk::isCompatibleWith(RelType Type) const { +bool ARMThunk::isCompatibleWith(const InputSection &IS, + const Relocation &Rel) const { // Thumb branch relocations can't use BLX - return Type != R_ARM_THM_JUMP19 && Type != R_ARM_THM_JUMP24; + return Rel.Type != R_ARM_THM_JUMP19 && Rel.Type != R_ARM_THM_JUMP24; } // This function returns true if the target is Thumb and is within 2^25, and @@ -433,9 +456,10 @@ Target->relocateOne(Buf, R_ARM_THM_JUMP24, Offset); } -bool ThumbThunk::isCompatibleWith(RelType Type) const { +bool ThumbThunk::isCompatibleWith(const InputSection &IS, + const Relocation &Rel) const { // ARM branch relocations can't use BLX - return Type != R_ARM_JUMP24 && Type != R_ARM_PC24 && Type != R_ARM_PLT32; + return Rel.Type != R_ARM_JUMP24 && Rel.Type != R_ARM_PC24 && Rel.Type != R_ARM_PLT32; } void ARMV7ABSLongThunk::writeLong(uint8_t *Buf) { @@ -532,9 +556,10 @@ addSymbol("$d", STT_NOTYPE, 4, IS); } -bool ARMV5ABSLongThunk::isCompatibleWith(uint32_t RelocType) const { +bool ARMV5ABSLongThunk::isCompatibleWith(const InputSection &IS, + const Relocation &Rel) const { // Thumb branch relocations can't use BLX - return RelocType != R_ARM_THM_JUMP19 && RelocType != R_ARM_THM_JUMP24; + return Rel.Type != R_ARM_THM_JUMP19 && Rel.Type != R_ARM_THM_JUMP24; } void ARMV5PILongThunk::writeLong(uint8_t *Buf) { @@ -557,9 +582,10 @@ addSymbol("$d", STT_NOTYPE, 12, IS); } -bool ARMV5PILongThunk::isCompatibleWith(uint32_t RelocType) const { +bool ARMV5PILongThunk::isCompatibleWith(const InputSection &IS, + const Relocation &Rel) const { // Thumb branch relocations can't use BLX - return RelocType != R_ARM_THM_JUMP19 && RelocType != R_ARM_THM_JUMP24; + return Rel.Type != R_ARM_THM_JUMP19 && Rel.Type != R_ARM_THM_JUMP24; } void ThumbV6MABSLongThunk::writeLong(uint8_t *Buf) { @@ -681,6 +707,60 @@ return dyn_cast(DR.Section); } +void PPC32PltCallStub::writeTo(uint8_t *Buf) { + if (!Config->Pic) { + uint64_t VA = Destination.getGotPltVA(); + write32(Buf + 0, 0x3d600000 | (VA + 0x8000) >> 16); // lis r11,ha + write32(Buf + 4, 0x816b0000 | (uint16_t)VA); // lwz r11,l(r11) + write32(Buf + 8, 0x7d6903a6); // mtctr r11 + write32(Buf + 12, 0x4e800420); // bctr + return; + } + uint32_t Offset; + if (Addend >= 0x8000) { + // The stub loads an address relative to r30 (.got2+Addend). Addend is + // almost always 0x8000. The address of .got2 is different in another object + // file, so a stub cannot be shared. + Offset = Destination.getGotPltVA() - (In.PPC32Got2->getParent()->getVA() + + File->PPC32Got2OutSecOff + Addend); + } else { + // The stub loads an address relative to _GLOBAL_OFFSET_TABLE_ (which is + // currently the address of .got). + Offset = Destination.getGotPltVA() - In.Got->getVA(); + } + uint16_t HA = (Offset + 0x8000) >> 16, L = (uint16_t)Offset; + if (HA == 0) { + write32(Buf + 0, 0x817e0000 | L); // lwz r11,l(r30) + write32(Buf + 4, 0x7d6903a6); // mtctr r11 + write32(Buf + 8, 0x4e800420); // bctr + write32(Buf + 12, 0x60000000); // nop + } else { + write32(Buf + 0, 0x3d7e0000 | HA); // addis r11,r30,ha + write32(Buf + 4, 0x816b0000 | L); // lwz r11,l(r11) + write32(Buf + 8, 0x7d6903a6); // mtctr r11 + write32(Buf + 12, 0x4e800420); // bctr + } +} + +void PPC32PltCallStub::addSymbols(ThunkSection &IS) { + std::string Buf; + raw_string_ostream OS(Buf); + OS << format_hex_no_prefix(Addend, 8); + if (!Config->Pic) + OS << ".plt_call32."; + else if (Addend >= 0x8000) + OS << ".got2.plt_pic32."; + else + OS << ".plt_pic32."; + OS << Destination.getName(); + addSymbol(Saver.save(OS.str()), STT_FUNC, 0, IS); +} + +bool PPC32PltCallStub::isCompatibleWith(const InputSection &IS, + const Relocation &Rel) const { + return !Config->Pic || (IS.File == File && Rel.Addend == Addend); +} + static void writePPCLoadAndBranch(uint8_t *Buf, int64_t Offset) { uint16_t OffHa = (Offset + 0x8000) >> 16; uint16_t OffLo = Offset & 0xffff; @@ -814,6 +894,12 @@ return make(S); } +static Thunk *addThunkPPC32(const InputSection &IS, const Relocation &Rel, Symbol &S) { + assert((Rel.Type == R_PPC_REL24 || Rel.Type == R_PPC_PLTREL24) && + "unexpected relocation type for thunk"); + return make(IS, Rel, S); +} + static Thunk *addThunkPPC64(RelType Type, Symbol &S) { assert(Type == R_PPC64_REL24 && "unexpected relocation type for thunk"); if (S.isInPlt()) @@ -825,18 +911,23 @@ return make(S); } -Thunk *addThunk(RelType Type, Symbol &S) { +Thunk *addThunk(const InputSection &IS, Relocation &Rel) { + Symbol &S = *Rel.Sym; + if (Config->EMachine == EM_AARCH64) - return addThunkAArch64(Type, S); + return addThunkAArch64(Rel.Type, S); if (Config->EMachine == EM_ARM) - return addThunkArm(Type, S); + return addThunkArm(Rel.Type, S); if (Config->EMachine == EM_MIPS) - return addThunkMips(Type, S); + return addThunkMips(Rel.Type, S); + + if (Config->EMachine == EM_PPC) + return addThunkPPC32(IS, Rel, S); if (Config->EMachine == EM_PPC64) - return addThunkPPC64(Type, S); + return addThunkPPC64(Rel.Type, S); llvm_unreachable("add Thunk only supported for ARM, Mips and PowerPC"); } Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -212,6 +212,10 @@ // https://sourceware.org/ml/binutils/2004-12/msg00094.html if (Symtab->find("__gnu_local_gp")) ElfSym::MipsLocalGp = addAbsolute("__gnu_local_gp"); + } else if (Config->EMachine == EM_PPC) { + // glibc *crt1.o has a undefined reference to _SDA_BASE_. Since we don't + // support Small Data Area, define it arbitrarily as 0. + addOptionalRegular("_SDA_BASE_", nullptr, 0, STV_HIDDEN); } // The Power Architecture 64-bit v2 ABI defines a TableOfContents (TOC) which @@ -233,7 +237,7 @@ } uint64_t GotOff = 0; - if (Config->EMachine == EM_PPC || Config->EMachine == EM_PPC64) + if (Config->EMachine == EM_PPC64) GotOff = 0x8000; S->resolve(Defined{/*File=*/nullptr, GotSymName, STB_GLOBAL, STV_HIDDEN, @@ -387,6 +391,11 @@ Add(In.Got); } + if (Config->EMachine == EM_PPC) { + In.PPC32Got2 = make(); + Add(In.PPC32Got2); + } + if (Config->EMachine == EM_PPC64) { In.PPC64LongBranchTarget = make(); Add(In.PPC64LongBranchTarget); @@ -1773,6 +1782,7 @@ finalizeSynthetic(In.RelaPlt); finalizeSynthetic(In.Plt); finalizeSynthetic(In.Iplt); + finalizeSynthetic(In.PPC32Got2); finalizeSynthetic(In.EhFrameHdr); finalizeSynthetic(In.VerSym); finalizeSynthetic(In.VerNeed); Index: test/ELF/basic-ppc.s =================================================================== --- test/ELF/basic-ppc.s +++ test/ELF/basic-ppc.s @@ -1,7 +1,7 @@ # REQUIRES: ppc -# RUN: llvm-mc -filetype=obj -triple=powerpc-unknown-freebsd %s -o %t -# RUN: ld.lld --hash-style=sysv -discard-all -shared %t -o %t2 -# RUN: llvm-readobj --file-headers --sections --section-data -l %t2 | FileCheck %s +# RUN: llvm-mc -filetype=obj -triple=powerpc-unknown-freebsd %s -o %t.o +# RUN: ld.lld %t.o -o %t +# RUN: llvm-readobj --file-headers --sections --section-data -l %t | FileCheck %s # exits with return code 42 on FreeBSD .text @@ -23,20 +23,20 @@ // CHECK-NEXT: ABIVersion: 0 // CHECK-NEXT: Unused: (00 00 00 00 00 00 00) // CHECK-NEXT: } -// CHECK-NEXT: Type: SharedObject (0x3) +// CHECK-NEXT: Type: Executable (0x2) // CHECK-NEXT: Machine: EM_PPC (0x14) // CHECK-NEXT: Version: 1 -// CHECK-NEXT: Entry: 0x1000 +// CHECK-NEXT: Entry: 0x10010000 // CHECK-NEXT: ProgramHeaderOffset: 0x34 -// CHECK-NEXT: SectionHeaderOffset: 0x20AC +// CHECK-NEXT: SectionHeaderOffset: 0x11044 // CHECK-NEXT: Flags [ (0x0) // CHECK-NEXT: ] // CHECK-NEXT: HeaderSize: 52 // CHECK-NEXT: ProgramHeaderEntrySize: 32 -// CHECK-NEXT: ProgramHeaderCount: 7 +// CHECK-NEXT: ProgramHeaderCount: 4 // CHECK-NEXT: SectionHeaderEntrySize: 40 -// CHECK-NEXT: SectionHeaderCount: 10 -// CHECK-NEXT: StringTableSectionIndex: 8 +// CHECK-NEXT: SectionHeaderCount: 6 +// CHECK-NEXT: StringTableSectionIndex: 4 // CHECK-NEXT: } // CHECK-NEXT: Sections [ // CHECK-NEXT: Section { @@ -57,68 +57,14 @@ // CHECK-NEXT: } // CHECK-NEXT: Section { // CHECK-NEXT: Index: 1 -// CHECK-NEXT: Name: .dynsym -// CHECK-NEXT: Type: SHT_DYNSYM (0xB) -// CHECK-NEXT: Flags [ (0x2) -// CHECK-NEXT: SHF_ALLOC (0x2) -// CHECK-NEXT: ] -// CHECK-NEXT: Address: 0x114 -// CHECK-NEXT: Offset: 0x114 -// CHECK-NEXT: Size: 16 -// CHECK-NEXT: Link: 3 -// CHECK-NEXT: Info: 1 -// CHECK-NEXT: AddressAlignment: 4 -// CHECK-NEXT: EntrySize: 16 -// CHECK-NEXT: SectionData ( -// CHECK-NEXT: 0000: 00000000 00000000 00000000 00000000 |................| -// CHECK-NEXT: ) -// CHECK-NEXT: } -// CHECK-NEXT: Section { -// CHECK-NEXT: Index: 2 -// CHECK-NEXT: Name: .hash -// CHECK-NEXT: Type: SHT_HASH (0x5) -// CHECK-NEXT: Flags [ (0x2) -// CHECK-NEXT: SHF_ALLOC (0x2) -// CHECK-NEXT: ] -// CHECK-NEXT: Address: 0x124 -// CHECK-NEXT: Offset: 0x124 -// CHECK-NEXT: Size: 16 -// CHECK-NEXT: Link: 1 -// CHECK-NEXT: Info: 0 -// CHECK-NEXT: AddressAlignment: 4 -// CHECK-NEXT: EntrySize: 4 -// CHECK-NEXT: SectionData ( -// CHECK-NEXT: 0000: 00000001 00000001 00000000 00000000 |................| -// CHECK-NEXT: ) -// CHECK-NEXT: } -// CHECK-NEXT: Section { -// CHECK-NEXT: Index: 3 -// CHECK-NEXT: Name: .dynstr -// CHECK-NEXT: Type: SHT_STRTAB (0x3) -// CHECK-NEXT: Flags [ (0x2) -// CHECK-NEXT: SHF_ALLOC (0x2) -// CHECK-NEXT: ] -// CHECK-NEXT: Address: 0x134 -// CHECK-NEXT: Offset: 0x134 -// CHECK-NEXT: Size: 1 -// CHECK-NEXT: Link: 0 -// CHECK-NEXT: Info: 0 -// CHECK-NEXT: AddressAlignment: 1 -// CHECK-NEXT: EntrySize: 0 -// CHECK-NEXT: SectionData ( -// CHECK-NEXT: 0000: 00 |.| -// CHECK-NEXT: ) -// CHECK-NEXT: } -// CHECK-NEXT: Section { -// CHECK-NEXT: Index: 4 // CHECK-NEXT: Name: .text // CHECK-NEXT: Type: SHT_PROGBITS (0x1) // CHECK-NEXT: Flags [ (0x6) // CHECK-NEXT: SHF_ALLOC (0x2) // CHECK-NEXT: SHF_EXECINSTR (0x4) // CHECK-NEXT: ] -// CHECK-NEXT: Address: 0x1000 -// CHECK-NEXT: Offset: 0x1000 +// CHECK-NEXT: Address: 0x10010000 +// CHECK-NEXT: Offset: 0x10000 // CHECK-NEXT: Size: 12 // CHECK-NEXT: Link: 0 // CHECK-NEXT: Info: 0 @@ -129,28 +75,7 @@ // CHECK-NEXT: ) // CHECK-NEXT: } // CHECK-NEXT: Section { -// CHECK-NEXT: Index: 5 -// CHECK-NEXT: Name: .dynamic -// CHECK-NEXT: Type: SHT_DYNAMIC (0x6) -// CHECK-NEXT: Flags [ (0x3) -// CHECK-NEXT: SHF_ALLOC (0x2) -// CHECK-NEXT: SHF_WRITE (0x1) -// CHECK-NEXT: ] -// CHECK-NEXT: Address: 0x2000 -// CHECK-NEXT: Offset: 0x2000 -// CHECK-NEXT: Size: 48 -// CHECK-NEXT: Link: 3 -// CHECK-NEXT: Info: 0 -// CHECK-NEXT: AddressAlignment: 4 -// CHECK-NEXT: EntrySize: 8 -// CHECK-NEXT: SectionData ( -// CHECK-NEXT: 0000: 00000006 00000114 0000000B 00000010 -// CHECK-NEXT: 0010: 00000005 00000134 0000000A 00000001 -// CHECK-NEXT: 0020: 00000004 00000124 00000000 00000000 -// CHECK-NEXT: ) -// CHECK-NEXT: } -// CHECK-NEXT: Section { -// CHECK-NEXT: Index: 6 +// CHECK-NEXT: Index: 2 // CHECK-NEXT: Name: .comment // CHECK-NEXT: Type: SHT_PROGBITS (0x1) // CHECK-NEXT: Flags [ (0x30) @@ -158,70 +83,59 @@ // CHECK-NEXT: SHF_STRINGS (0x20) // CHECK-NEXT: ] // CHECK-NEXT: Address: 0x0 -// CHECK-NEXT: Offset: 0x2030 +// CHECK-NEXT: Offset: 0x11000 // CHECK-NEXT: Size: 8 // CHECK-NEXT: Link: 0 // CHECK-NEXT: Info: 0 // CHECK-NEXT: AddressAlignment: 1 // CHECK-NEXT: EntrySize: 1 -// CHECK-NEXT: SectionData ( -// CHECK-NEXT: 0000: 4C4C4420 312E3000 |LLD 1.0.| -// CHECK-NEXT: ) -// CHECK-NEXT: } +// CHECK: } // CHECK-NEXT: Section { -// CHECK-NEXT: Index: 7 +// CHECK-NEXT: Index: 3 // CHECK-NEXT: Name: .symtab // CHECK-NEXT: Type: SHT_SYMTAB (0x2) // CHECK-NEXT: Flags [ (0x0) // CHECK-NEXT: ] // CHECK-NEXT: Address: 0x0 -// CHECK-NEXT: Offset: 0x2038 -// CHECK-NEXT: Size: 32 -// CHECK-NEXT: Link: 9 -// CHECK-NEXT: Info: 2 +// CHECK-NEXT: Offset: 0x11008 +// CHECK-NEXT: Size: 16 +// CHECK-NEXT: Link: 5 +// CHECK-NEXT: Info: 1 // CHECK-NEXT: AddressAlignment: 4 // CHECK-NEXT: EntrySize: 16 // CHECK-NEXT: SectionData ( // CHECK-NEXT: 0000: 00000000 00000000 00000000 00000000 |................| -// CHECK-NEXT: 0010: 00000001 00002000 00000000 00020005 |...... .........| // CHECK-NEXT: ) // CHECK-NEXT: } // CHECK-NEXT: Section { -// CHECK-NEXT: Index: 8 +// CHECK-NEXT: Index: 4 // CHECK-NEXT: Name: .shstrtab // CHECK-NEXT: Type: SHT_STRTAB (0x3) // CHECK-NEXT: Flags [ (0x0) // CHECK-NEXT: ] // CHECK-NEXT: Address: 0x0 -// CHECK-NEXT: Offset: 0x2058 -// CHECK-NEXT: Size: 73 +// CHECK-NEXT: Offset: 0x11018 +// CHECK-NEXT: Size: 42 // CHECK-NEXT: Link: 0 // CHECK-NEXT: Info: 0 // CHECK-NEXT: AddressAlignment: 1 // CHECK-NEXT: EntrySize: 0 -// CHECK-NEXT: SectionData ( -// CHECK-NEXT: 0000: 002E6479 6E73796D 002E6861 7368002E |..dynsym..hash..| -// CHECK-NEXT: 0010: 64796E73 7472002E 74657874 002E6479 |dynstr..text..dy| -// CHECK-NEXT: 0020: 6E616D69 63002E63 6F6D6D65 6E74002E |namic..comment..| -// CHECK-NEXT: 0030: 73796D74 6162002E 73687374 72746162 |symtab..shstrtab| -// CHECK-NEXT: 0040: 002E7374 72746162 00 |..strtab.| -// CHECK-NEXT: ) -// CHECK-NEXT: } +// CHECK: } // CHECK-NEXT: Section { -// CHECK-NEXT: Index: 9 +// CHECK-NEXT: Index: 5 // CHECK-NEXT: Name: .strtab // CHECK-NEXT: Type: SHT_STRTAB (0x3) // CHECK-NEXT: Flags [ (0x0) // CHECK-NEXT: ] // CHECK-NEXT: Address: 0x0 -// CHECK-NEXT: Offset: 0x20A1 -// CHECK-NEXT: Size: 10 +// CHECK-NEXT: Offset: 0x11042 +// CHECK-NEXT: Size: 1 // CHECK-NEXT: Link: 0 // CHECK-NEXT: Info: 0 // CHECK-NEXT: AddressAlignment: 1 // CHECK-NEXT: EntrySize: 0 // CHECK-NEXT: SectionData ( -// CHECK-NEXT: 0000: 005F4459 4E414D49 4300 |._DYNAMIC.| +// CHECK-NEXT: 0000: 00 // CHECK-NEXT: ) // CHECK-NEXT: } // CHECK-NEXT: ] @@ -229,10 +143,10 @@ // CHECK-NEXT: ProgramHeader { // CHECK-NEXT: Type: PT_PHDR (0x6) // CHECK-NEXT: Offset: 0x34 -// CHECK-NEXT: VirtualAddress: 0x34 -// CHECK-NEXT: PhysicalAddress: 0x34 -// CHECK-NEXT: FileSize: 224 -// CHECK-NEXT: MemSize: 224 +// CHECK-NEXT: VirtualAddress: 0x10000034 +// CHECK-NEXT: PhysicalAddress: 0x10000034 +// CHECK-NEXT: FileSize: 128 +// CHECK-NEXT: MemSize: 128 // CHECK-NEXT: Flags [ (0x4) // CHECK-NEXT: PF_R (0x4) // CHECK-NEXT: ] @@ -241,65 +155,27 @@ // CHECK-NEXT: ProgramHeader { // CHECK-NEXT: Type: PT_LOAD (0x1) // CHECK-NEXT: Offset: 0x0 -// CHECK-NEXT: VirtualAddress: 0x0 -// CHECK-NEXT: PhysicalAddress: 0x0 -// CHECK-NEXT: FileSize: 309 -// CHECK-NEXT: MemSize: 309 +// CHECK-NEXT: VirtualAddress: 0x10000000 +// CHECK-NEXT: PhysicalAddress: 0x10000000 +// CHECK-NEXT: FileSize: 180 +// CHECK-NEXT: MemSize: 180 // CHECK-NEXT: Flags [ (0x4) // CHECK-NEXT: PF_R (0x4) // CHECK-NEXT: ] -// CHECK-NEXT: Alignment: 4096 +// CHECK-NEXT: Alignment: 65536 // CHECK-NEXT: } // CHECK-NEXT: ProgramHeader { // CHECK-NEXT: Type: PT_LOAD (0x1) // CHECK-NEXT: Offset: 0x1000 -// CHECK-NEXT: VirtualAddress: 0x1000 -// CHECK-NEXT: PhysicalAddress: 0x1000 -// CHECK-NEXT: FileSize: 12 -// CHECK-NEXT: MemSize: 12 +// CHECK-NEXT: VirtualAddress: 0x10010000 +// CHECK-NEXT: PhysicalAddress: 0x10010000 +// CHECK-NEXT: FileSize: 4096 +// CHECK-NEXT: MemSize: 4096 // CHECK-NEXT: Flags [ (0x5) // CHECK-NEXT: PF_R (0x4) // CHECK-NEXT: PF_X (0x1) // CHECK-NEXT: ] -// CHECK-NEXT: Alignment: 4096 -// CHECK-NEXT: } -// CHECK-NEXT: ProgramHeader { -// CHECK-NEXT: Type: PT_LOAD (0x1) -// CHECK-NEXT: Offset: 0x2000 -// CHECK-NEXT: VirtualAddress: 0x2000 -// CHECK-NEXT: PhysicalAddress: 0x2000 -// CHECK-NEXT: FileSize: 48 -// CHECK-NEXT: MemSize: 48 -// CHECK-NEXT: Flags [ (0x6) -// CHECK-NEXT: PF_R (0x4) -// CHECK-NEXT: PF_W (0x2) -// CHECK-NEXT: ] -// CHECK-NEXT: Alignment: 4096 -// CHECK-NEXT: } -// CHECK-NEXT: ProgramHeader { -// CHECK-NEXT: Type: PT_DYNAMIC (0x2) -// CHECK-NEXT: Offset: 0x2000 -// CHECK-NEXT: VirtualAddress: 0x2000 -// CHECK-NEXT: PhysicalAddress: 0x2000 -// CHECK-NEXT: FileSize: 48 -// CHECK-NEXT: MemSize: 48 -// CHECK-NEXT: Flags [ (0x6) -// CHECK-NEXT: PF_R (0x4) -// CHECK-NEXT: PF_W (0x2) -// CHECK-NEXT: ] -// CHECK-NEXT: Alignment: 4 -// CHECK-NEXT: } -// CHECK-NEXT: ProgramHeader { -// CHECK-NEXT: Type: PT_GNU_RELRO (0x6474E552) -// CHECK-NEXT: Offset: 0x2000 -// CHECK-NEXT: VirtualAddress: 0x2000 -// CHECK-NEXT: PhysicalAddress: 0x2000 -// CHECK-NEXT: FileSize: 48 -// CHECK-NEXT: MemSize: 4096 -// CHECK-NEXT: Flags [ (0x4) -// CHECK-NEXT: PF_R (0x4) -// CHECK-NEXT: ] -// CHECK-NEXT: Alignment: 1 +// CHECK-NEXT: Alignment: 65536 // CHECK-NEXT: } // CHECK-NEXT: ProgramHeader { // CHECK-NEXT: Type: PT_GNU_STACK (0x6474E551) Index: test/ELF/ppc-rela.s =================================================================== --- test/ELF/ppc-rela.s +++ test/ELF/ppc-rela.s @@ -7,5 +7,5 @@ .long foo // CHECK: Section ({{.*}}) .rela.dyn { -// CHECK-NEXT: 0x2000 R_PPC_ADDR32 foo 0x0 +// CHECK-NEXT: 0x20000 R_PPC_ADDR32 foo 0x0 // CHECK-NEXT: } Index: test/ELF/ppc-relocs.s =================================================================== --- test/ELF/ppc-relocs.s +++ /dev/null @@ -1,106 +0,0 @@ -# REQUIRES: ppc -# RUN: llvm-mc -filetype=obj -triple=powerpc-unknown-freebsd %s -o %t.o -# RUN: ld.lld %t.o -o %t -# RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck %s -# RUN: llvm-objdump -s --no-show-raw-insn %t | FileCheck --check-prefix=HEX %s - -.section .R_PPC_ADDR16_HA,"ax",@progbits -.globl _start -_start: - lis 4, msg@ha -msg: - .string "foo" - len = . - msg - -# CHECK: Disassembly of section .R_PPC_ADDR16_HA: -# CHECK-EMPTY: -# CHECK: _start: -# CHECK: 11000: lis 4, 1 -# CHECK: msg: -# CHECK: 11004: oris 15, 19, 28416 - -.section .R_PPC_ADDR16_HI,"ax",@progbits -.globl _starti -_starti: - lis 4,msgi@h -msgi: - .string "foo" - leni = . - msgi - -# CHECK: Disassembly of section .R_PPC_ADDR16_HI: -# CHECK-EMPTY: -# CHECK: _starti: -# CHECK: 11008: lis 4, 1 -# CHECK: msgi: -# CHECK: 1100c: oris 15, 19, 28416 - -.section .R_PPC_ADDR16_LO,"ax",@progbits - addi 4, 4, msg@l -mystr: - .asciz "blah" - len = . - mystr - -# CHECK: Disassembly of section .R_PPC_ADDR16_LO: -# CHECK-EMPTY: -# CHECK: .R_PPC_ADDR16_LO: -# CHECK: 11010: addi 4, 4, 4100 -# CHECK: mystr: -# CHECK: 11014: ori 12, 19, 24936 - -.align 2 -.section .R_PPC_REL24,"ax",@progbits -.globl .FR_PPC_REL24 -.FR_PPC_REL24: - b .Lfoox -.section .R_PPC_REL24_2,"ax",@progbits -.Lfoox: - -# CHECK: Disassembly of section .R_PPC_REL24: -# CHECK-EMPTY: -# CHECK: .FR_PPC_REL24: -# CHECK: 1101c: b .+4 - -.section .R_PPC_REL14,"ax",@progbits -.globl .FR_PPC_REL14 -.FR_PPC_REL14: - beq .Lfooy -.section .R_PPC_REL14_2,"ax",@progbits -.Lfooy: - -# CHECK: Disassembly of section .R_PPC_REL14: -# CHECK-EMPTY: -# CHECK: .FR_PPC_REL14: -# CHECK: 11020: bt 2, .+4 - -.section .R_PPC_REL32,"ax",@progbits -.globl .FR_PPC_REL32 -.FR_PPC_REL32: - .long .Lfoox3 - . -.section .R_PPC_REL32_2,"ax",@progbits -.Lfoox3: - -# HEX: .R_PPC_REL32: -# HEX-NEXT: 11024 00000004 - -.section .R_PPC_ADDR32,"ax",@progbits -.globl .FR_PPC_ADDR32 -.FR_PPC_ADDR32: - .long .Lfoox2 -.section .R_PPC_ADDR32_2,"ax",@progbits -.Lfoox2: - -# HEX: .R_PPC_ADDR32: -# HEX-NEXT: 11028 0001102c - -.align 2 -.section .R_PPC_PLTREL24,"ax",@progbits -.globl .R_PPC_PLTREL24 -.FR_PPC_PLTREL24: - b .Lfoox4@PLT -.section .R_PPC_PLTREL24_2,"ax",@progbits -.Lfoox4: - -# CHECK: Disassembly of section .R_PPC_PLTREL24: -# CHECK-EMPTY: -# CHECK: .R_PPC_PLTREL24: -# CHECK: 1102c: b .+4 Index: test/ELF/ppc32-abs-pic.s =================================================================== --- /dev/null +++ test/ELF/ppc32-abs-pic.s @@ -0,0 +1,23 @@ +# REQUIRES: ppc +# RUN: llvm-mc -filetype=obj -triple=powerpc %s -o %t.o +# RUN: ld.lld -shared %t.o -o %t.so +# RUN: llvm-nm %t.so | FileCheck --check-prefix=NM %s +# RUN: llvm-readobj -r %t.so | FileCheck --check-prefix=RELOC %s + +## R_PPC_ADDR32 is an absolute relocation type. +## In PIC mode, it creates a relative relocation if the symbol is non-preemptable. + +# NM: 00020004 d b + +# RELOC: .rela.dyn { +# RELOC-NEXT: 0x20004 R_PPC_RELATIVE - 0x20004 +# RELOC-NEXT: 0x20000 R_PPC_ADDR32 a 0 +# RELOC-NEXT: } + +.globl a, b +.hidden b + +.data +.long a +b: +.long b Index: test/ELF/ppc32-call-stub-nopic.s =================================================================== --- /dev/null +++ test/ELF/ppc32-call-stub-nopic.s @@ -0,0 +1,81 @@ +# REQUIRES: ppc +# RUN: llvm-mc -filetype=obj -triple=powerpc %s -o %t.o +# RUN: echo '.globl f, g, h; f: g: h:' | llvm-mc -filetype=obj -triple=powerpc - -o %t1.o +# RUN: ld.lld -shared %t1.o -soname t1.so -o %t1.so + +## Check we can create PLT entries for -fno-PIE executable. +# RUN: ld.lld %t.o %t1.so -o %t +# RUN: llvm-readobj -r -d %t | FileCheck --check-prefix=RELOC %s +# RUN: llvm-readelf -S %t | FileCheck --check-prefix=SEC %s +# RUN: llvm-readelf -x .plt %t | FileCheck --check-prefix=HEX %s +# RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck %s + +# RELOC: .rela.plt { +# RELOC-NEXT: 0x10030000 R_PPC_JMP_SLOT f 0x0 +# RELOC-NEXT: 0x10030004 R_PPC_JMP_SLOT g 0x0 +# RELOC-NEXT: } + +# SEC: .got PROGBITS 10020070 +# RELOC: PPC_GOT 0x10020070 + +## .got2+0x8000-0x10004 = 0x30000+0x8000-0x10004 = 65536*2+32764 +# CHECK-LABEL: _start: +# CHECK-NEXT: bl .+16 +# CHECK-NEXT: bl .+12 +# CHECK-NEXT: bl .+24 +# CHECK-NEXT: bl .+20 +# CHECK-EMPTY: + +## -fno-PIC call stubs of f and g. +## .plt[0] = 0x10030000 = 65536*4099+0 +## .plt[1] = 0x10030004 = 65536*4099+4 +# CHECK-NEXT: 00000000.plt_call32.f: +# CHECK-NEXT: lis 11, 4099 +# CHECK-NEXT: lwz 11, 0(11) +# CHECK-NEXT: mtctr 11 +# CHECK-NEXT: bctr +# CHECK-EMPTY: +# CHECK-NEXT: 00000000.plt_call32.g: +# CHECK-NEXT: lis 11, 4099 +# CHECK-NEXT: lwz 11, 4(11) +# CHECK-NEXT: mtctr 11 +# CHECK-NEXT: bctr +# CHECK-EMPTY: + +## In Secure PLT ABI, .plt stores function pointers to first instructions of .glink +# HEX: 0x10030000 10010040 10010044 + +## These instructions are referenced by .plt entries. +# CHECK: 0000000010010040 .glink: +# CHECK-NEXT: b .+8 +# CHECK-NEXT: b .+4 + +## PLTresolve +## Operands of lis & lwz: .got+4 = 0x10020070+4 = 65536*4098+116 +## Operands of addis & addi: -.glink = -0x10010040 = 65536*-4097-48 +# CHECK-NEXT: lis 12, 4098 +# CHECK-NEXT: addis 11, 11, -4097 +# CHECK-NEXT: lwz 0, 116(12) +# CHECK-NEXT: addi 11, 11, -64 + +# CHECK-NEXT: mtctr 0 +# CHECK-NEXT: add 0, 11, 11 +# CHECK-NEXT: lwz 12, 120(12) +# CHECK-NEXT: add 11, 0, 11 +# CHECK-NEXT: bctr + +## glibc crti.o references _GLOBAL_OFFSET_TABLE_. +.section .init + bcl 20, 31, .+4 +.L: + mflr 30 + addis 30, 30, _GLOBAL_OFFSET_TABLE_-.L@ha + addi 30, 30, _GLOBAL_OFFSET_TABLE_-.L@l + +.text +.globl _start +_start: + bl f + bl f + bl g + bl g Index: test/ELF/ppc32-call-stub-pic.s =================================================================== --- /dev/null +++ test/ELF/ppc32-call-stub-pic.s @@ -0,0 +1,151 @@ +# REQUIRES: ppc +# RUN: llvm-mc -filetype=obj -triple=powerpc %s -o %t.o +# RUN: echo '.globl f, g, h; f: g: h:' | llvm-mc -filetype=obj -triple=powerpc - -o %t1.o +# RUN: ld.lld -shared %t1.o -soname t1.so -o %t1.so +# RUN: echo 'bl f+0x8000@plt' | llvm-mc -filetype=obj -triple=powerpc - -o %t2.o + +## Check we can create PLT entries for -fPIE or -fpie executable. +# RUN: ld.lld -pie %t.o %t1.so %t2.o -o %t +# RUN: llvm-readobj -r %t | FileCheck --check-prefix=RELOC %s +# RUN: llvm-readobj -d %t | FileCheck --check-prefix=DYN %s +# RUN: llvm-readelf -S %t | FileCheck --check-prefix=SEC %s +# RUN: llvm-readelf -x .plt %t | FileCheck --check-prefix=HEX %s +# RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck --check-prefixes=CHECK,PIE %s + +## Check we can create PLT entries for -fPIC or -fpic DSO. +# RUN: ld.lld -shared %t.o %t1.so %t2.o -o %t +# RUN: llvm-readobj -r %t | FileCheck --check-prefix=RELOC %s +# RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck --check-prefixes=CHECK,SHARED %s + +# RELOC: .rela.dyn { +# RELOC-NEXT: R_PPC_ADDR32 f 0x0 +# RELOC-NEXT: R_PPC_ADDR32 g 0x0 +# RELOC-NEXT: R_PPC_ADDR32 h 0x0 +# RELOC-NEXT: } +# RELOC-NEXT: .rela.plt { +# RELOC-NEXT: R_PPC_JMP_SLOT f 0x0 +# RELOC-NEXT: R_PPC_JMP_SLOT g 0x0 +# RELOC-NEXT: R_PPC_JMP_SLOT h 0x0 +# RELOC-NEXT: } + +# SEC: .got PROGBITS 00020088 +# DYN: PPC_GOT 0x20088 + +## .got2+0x8000-0x10004 = 0x30000+0x8000-0x10004 = 65536*2+32764 +# CHECK-LABEL: _start: +# CHECK-NEXT: bcl 20, 31, .+4 +# CHECK-NEXT: 10004: mflr 30 +# CHECK-NEXT: addis 30, 30, 2 +# CHECK-NEXT: addi 30, 30, 32764 + +## Two bl 00008000.got2.plt_pic32.f +# CHECK-NEXT: bl .+40 +# CHECK-NEXT: bl .+36 +## Two bl 00008000.got2.plt_pic32.g +# CHECK-NEXT: bl .+48 +# CHECK-NEXT: bl .+44 +## Two bl 00008000.got2.plt_pic32.h +# CHECK-NEXT: bl .+56 +# CHECK-NEXT: bl .+52 +# CHECK-NEXT: addis 30, 30, {{.*}} +# CHECK-NEXT: addi 30, 30, {{.*}} +## bl 00008000.plt_pic32.f +# CHECK-NEXT: bl .+56 +## bl 00008000.plt_pic32.f +# CHECK-NEXT: bl .+68 +# CHECK-EMPTY: + +## -fPIC call stubs of f and g. +# CHECK-NEXT: 00008000.got2.plt_pic32.f: +# CHECK-NEXT: lwz 11, 32760(30) +# CHECK-NEXT: mtctr 11 +# CHECK-NEXT: bctr +# CHECK-NEXT: nop +# CHECK-EMPTY: +# CHECK-NEXT: 00008000.got2.plt_pic32.g: +# CHECK-NEXT: lwz 11, 32764(30) +# CHECK-NEXT: mtctr 11 +# CHECK-NEXT: bctr +# CHECK-NEXT: nop +# CHECK-EMPTY: + +## The -fPIC call stub of h needs two instructions addis+lwz to represent the offset 65536*1-32768. +# CHECK-NEXT: 00008000.got2.plt_pic32.h: +# CHECK-NEXT: addis 11, 30, 1 +# CHECK-NEXT: lwz 11, -32768(11) +# CHECK-NEXT: mtctr 11 +# CHECK-NEXT: bctr +# CHECK-EMPTY: + +## -fpic call stub of f. +# CHECK-NEXT: 00000000.plt_pic32.f: +# CHECK-NEXT: addis 11, 30, 2 +# PIE-NEXT: lwz 11, -144(11) +# SHARED-NEXT: lwz 11, -136(11) +# CHECK-NEXT: mtctr 11 +# CHECK-NEXT: bctr +# CHECK-EMPTY: + +## Another -fPIC call stub of f from another object file %t2.o +## .got2 may have different addresses in different object files, +## so the call stub cannot be shared. +# CHECK-NEXT: 00008000.got2.plt_pic32.f: + +## In Secure PLT ABI, .plt stores function pointers to first instructions of .glink +# HEX: 0x0003fff8 00010090 00010094 00010098 + +## These instructions are referenced by .plt entries. +# CHECK: 0000000000010090 .glink: +# CHECK-NEXT: b .+12 +# CHECK-NEXT: b .+8 +# CHECK-NEXT: b .+4 + +## PLTresolve +## Operand of addi: 0x100a8-.glink = 24 +# CHECK-NEXT: addis 11, 11, 0 +# CHECK-NEXT: mflr 0 +# CHECK-NEXT: bcl 20, 31, .+4 +# CHECK-NEXT: 100a8: addi 11, 11, 24 + +# CHECK-NEXT: mflr 12 +# CHECK-NEXT: mtlr 0 +# CHECK-NEXT: subf 11, 12, 11 + +## Operand of lwz in -pie mode: &.got[1] - 0x100a8 = 0x20088+4 - 0x100a8 = 65536*1-28 +# CHECK-NEXT: addis 12, 12, 1 +# PIE-NEXT: lwz 0, -28(12) +# SHARED-NEXT: lwz 0, -36(12) + +# PIE-NEXT: lwz 12, -24(12) +# SHARED-NEXT: lwz 12, -32(12) +# CHECK-NEXT: mtctr 0 +# CHECK-NEXT: add 0, 11, 11 +# CHECK-NEXT: add 11, 0, 11 +# CHECK-NEXT: bctr + +.section .got2,"aw" +.space 65516 +.long f +.long g +.long h + +.text +.globl _start +_start: + bcl 20,31,.L +.L: + mflr 30 + addis 30, 30, .got2+0x8000-.L@ha + addi 30, 30, .got2+0x8000-.L@l + bl f+0x8000@plt + bl f+0x8000@plt + bl g+0x8000@plt + bl g+0x8000@plt + bl h+0x8000@plt + bl h+0x8000@plt + +## An addend of 0 indicates r30 is stored in _GLOBAL_OFFSET_TABLE_. +## The existing thunk is incompatible, thus it cannot be reused. + addis 30, 30, _GLOBAL_OFFSET_TABLE_-.L@ha + addi 30, 30, _GLOBAL_OFFSET_TABLE_-.L@l + bl f@plt Index: test/ELF/ppc32-local-branch.s =================================================================== --- /dev/null +++ test/ELF/ppc32-local-branch.s @@ -0,0 +1,21 @@ +# REQUIRES: ppc +# RUN: llvm-mc -filetype=obj -triple=powerpc %s -o %t.o +# RUN: echo '.globl foo; foo: blr' | llvm-mc -filetype=obj -triple=powerpc - -o %t1.o +# RUN: ld.lld %t.o %t1.o -o %t +# RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck %s + +## R_PPC_REL24 and R_PPC_PLTREL24 are converted to PC relative relocations if the +## symbol is non-preemptable. The addend of R_PPC_PLTREL24 should be ignored. + +# CHECK: _start: +# CHECK-NEXT: b .+12 +# CHECK-NEXT: b .+8 +# CHECK-NEXT: b .+4 +# CHECK-EMPTY: +# CHECK-NEXT: foo: + +.globl _start +_start: + b foo # R_PPC_REL24 + b foo@plt # R_PPC_PLTREL24 + b foo+32768@plt #_PPC_PLTREL24 with addend Index: test/ELF/ppc32-reloc-addr.s =================================================================== --- /dev/null +++ test/ELF/ppc32-reloc-addr.s @@ -0,0 +1,34 @@ +# REQUIRES: ppc +# RUN: llvm-mc -filetype=obj -triple=powerpc %s -o %t.o +# RUN: ld.lld --noinhibit-exec %t.o --defsym=a=0x1234 --defsym=b=0xbcdef -o %t 2>&1 | \ +# RUN: FileCheck --check-prefix=WARN %s +# RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck %s +# RUN: llvm-objdump -s --no-show-raw-insn %t | FileCheck --check-prefix=HEX %s + +.section .R_PPC_ADDR16,"ax",@progbits + lis 4, a + lis 4, b +# CHECK-LABEL: section .R_PPC_ADDR16: +# CHECK: lis 4, 4660 +# WARN: warning: {{.*}}.o:(.R_PPC_ADDR16+0x6): relocation R_PPC_ADDR16 out of range: 773615 is not in [-32768, 32767] + +.section .R_PPC_ADDR16_HA,"ax",@progbits + lis 4, a@ha +# CHECK-LABEL: section .R_PPC_ADDR16_HA: +# CHECK: lis 4, 0 + +.section .R_PPC_ADDR16_HI,"ax",@progbits + lis 4, a@h +# CHECK-LABEL: section .R_PPC_ADDR16_HI: +# CHECK: lis 4, 0 + +.section .R_PPC_ADDR16_LO,"ax",@progbits + addi 4, 4, a@l +# CHECK-LABEL: section .R_PPC_ADDR16_LO: +# CHECK: addi 4, 4, 4660 + +.section .R_PPC_ADDR32,"a",@progbits + .long a + .long b +# HEX-LABEL: section .R_PPC_ADDR32: +# HEX-NEXT: 100000b4 00001234 000bcdef Index: test/ELF/ppc32-reloc-got.s =================================================================== --- /dev/null +++ test/ELF/ppc32-reloc-got.s @@ -0,0 +1,20 @@ +# REQUIRES: ppc +# RUN: llvm-mc -filetype=obj -triple=powerpc %s -o %t.o +# RUN: ld.lld -shared %t.o -o %t.so +# RUN: llvm-readobj -r %t.so | FileCheck --check-prefix=RELOC %s +# RUN: llvm-objdump -d --no-show-raw-insn %t.so | FileCheck %s + +## Check we can handle R_PPC_GOT16, which may be generated by -fpic code. + +# SEC: .got PROGBITS 00020058 020058 000008 + +# RELOC: .rela.dyn { +# RELOC-NEXT: 0x20058 R_PPC_GLOB_DAT a 0x0 +# RELOC-NEXT: 0x2005C R_PPC_GLOB_DAT b 0x0 +# RELOC-NEXT: } + +# CHECK: lwz 3, 0(30) +# CHECK: lwz 3, 4(30) + +lwz 3,a@got(30) +lwz 3,b@got(30) Index: test/ELF/ppc32-reloc-rel.s =================================================================== --- /dev/null +++ test/ELF/ppc32-reloc-rel.s @@ -0,0 +1,34 @@ +# REQUIRES: ppc +# RUN: llvm-mc -filetype=obj -triple=powerpc %s -o %t.o +# RUN: ld.lld %t.o -o %t +# RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck %s + +.section .R_PPC_REL14,"ax",@progbits + beq 1f +1: +# CHECK-LABEL: section .R_PPC_REL14: +# CHECK: bt 2, .+4 + +.section .R_PPC_REL24,"ax",@progbits + b 1f +1: +# CHECK-LABEL: section .R_PPC_REL24: +# CHECK: b .+4 + +.section .R_PPC_REL32,"ax",@progbits + .long 1f - . +1: +# HEX-LABEL: section .R_PPC_REL32: +# HEX-NEXT: 10010008 00000004 + +.section .R_PPC_PLTREL24,"ax",@progbits + b 1f@PLT+32768 +1: +# CHECK-LABEL: section .R_PPC_PLTREL24: +# CHECK: b .+4 + +.section .R_PPC_LOCAL24REL,"ax",@progbits + b 1f@local +1: +# CHECK-LABEL: section .R_PPC_LOCAL24REL: +# CHECK: b .+4