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,6 +23,11 @@ class PPC final : public TargetInfo { public: PPC(); + void writeGotHeader(uint8_t *Buf) 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; @@ -28,17 +35,64 @@ } // 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; + GotHeaderEntriesNum = Config->SecurePlt ? 3 : 4; + GotPltHeaderEntriesNum = 0; + + NeedsThunks = true; + + DefaultMaxPageSize = 65536; + DefaultImageBase = 0x10000000; + + write32(TrapInstr.data(), 0x7fe00008); +} + +void PPC::writeGotHeader(uint8_t *Buf) const { + if (!Config->SecurePlt) { + // _GLOBAL_OFFSET_TABLE[-1] = blrl + write32(Buf, 0x4e800021); + Buf += 4; + } + + // _GLOBAL_OFFSET_TABLE_[0] = _DYNAMIC + write32(Buf, In.Dynamic->getVA()); + // _GLOBAL_OFFSET_TABLE_[1,2] are reserved. +} + +bool PPC::needsThunk(RelExpr Expr, RelType Type, const InputFile *File, + uint64_t BranchAddr, const Symbol &S) const { + if (!Config->SecurePlt || (Type != R_PPC_REL24 && Type != R_PPC_PLTREL24)) + return false; + return Expr == R_PLT_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_GOT16: + return R_GOT_OFF; + case R_PPC_REL24: case R_PPC_PLTREL24: return R_PLT_PC; default: @@ -49,25 +103,43 @@ 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); + 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: + case R_PPC_PLTREL24: { + uint32_t Mask = 0x03FFFFFC; + if (Type == R_PPC_PLTREL24 && Config->SecurePlt) + Val -= 0x8000; + 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/Config.h =================================================================== --- ELF/Config.h +++ ELF/Config.h @@ -173,6 +173,7 @@ bool Relocatable; bool RelrPackDynRelocs; bool SaveTemps; + bool SecurePlt; bool SingleRoRx; bool Shared; bool Static = false; Index: ELF/Driver.cpp =================================================================== --- ELF/Driver.cpp +++ ELF/Driver.cpp @@ -859,6 +859,7 @@ Config->SaveTemps = Args.hasArg(OPT_save_temps); Config->SearchPaths = args::getStrings(Args, OPT_library_path); Config->SectionStartMap = getSectionStartMap(Args); + Config->SecurePlt = Args.hasArg(OPT_secure_plt, OPT_bss_plt, false); Config->Shared = Args.hasArg(OPT_shared); Config->SingleRoRx = Args.hasArg(OPT_no_rosegment); Config->SoName = Args.getLastArgValue(OPT_soname); 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 @@ -707,6 +707,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 { Index: ELF/Options.td =================================================================== --- ELF/Options.td +++ ELF/Options.td @@ -27,6 +27,8 @@ def Bstatic: F<"Bstatic">, HelpText<"Do not link against shared libraries">; +def bss_plt: F<"bss-plt">, HelpText<"Use old-style BSS PLT for PowerPC32">; + def build_id: F<"build-id">, HelpText<"Alias for --build-id=fast">; def build_id_eq: J<"build-id=">, HelpText<"Generate build ID note">, @@ -306,6 +308,8 @@ Eq<"retain-symbols-file", "Retain only the symbols listed in the file">, MetaVarName<"">; +def secure_plt: F<"secure-plt">, HelpText<"Use new-style PLT for PowerPC32 (default)">; + defm script: Eq<"script", "Read linker script">; defm section_start: Eq<"section-start", "Set address of section">, Index: ELF/Relocations.cpp =================================================================== --- ELF/Relocations.cpp +++ ELF/Relocations.cpp @@ -838,8 +838,17 @@ RelocationBaseSection *Rel, RelType Type, Symbol &Sym) { Plt->addEntry(Sym); GotPlt->addEntry(Sym); - Rel->addReloc( - {Type, GotPlt, Sym.getGotPltOffset(), !Sym.IsPreemptible, &Sym, 0}); + uint64_t Offset; + if (Config->EMachine == EM_PPC && !Config->SecurePlt) { + // PPC32 BSS-PLT ABI encodes PLT differently. See the comment in + // GotPltSection::getSize(). + Offset = 72 + 8 * Sym.PltIndex; + if (Sym.PltIndex > 8192) + Offset += 4 * (Sym.PltIndex - 8192); + } else { + Offset = Sym.getGotPltOffset(); + } + Rel->addReloc({Type, GotPlt, Offset, !Sym.IsPreemptible, &Sym, 0}); } static void addGotEntry(Symbol &Sym) { @@ -1633,12 +1642,12 @@ // 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) && + T->isCompatibleWith(*IS, Type) && Target->inBranchRange(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, Type, Sym); ThunkVec->push_back(T); return std::make_pair(T, true); } Index: ELF/SyntheticSections.h =================================================================== --- ELF/SyntheticSections.h +++ ELF/SyntheticSections.h @@ -661,7 +661,7 @@ PltSection(bool IsIplt); void writeTo(uint8_t *Buf) override; size_t getSize() const override; - bool isNeeded() const override { return !Entries.empty(); } + bool isNeeded() const override; void addSymbols(); template void addEntry(Symbol &Sym); @@ -1034,6 +1034,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 { return true; } + 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 @@ -1093,6 +1104,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 @@ -1028,10 +1028,19 @@ // 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) { + if (!Config->SecurePlt) { + Flags |= SHF_EXECINSTR; + Type = SHT_NOBITS; + } + Name = ".plt"; + } else if (Config->EMachine == EM_PPC64) { + Type = SHT_NOBITS; + Name = ".plt"; + } +} void GotPltSection::addEntry(Symbol &Sym) { assert(Sym.PltIndex == Entries.size()); @@ -1039,6 +1048,13 @@ } size_t GotPltSection::getSize() const { + if (Config->EMachine == EM_PPC && !Config->SecurePlt) { + // In PPC32 BSS-PLT ABI, first 72 bytes are reserved for the dynamic loader. + // For the first 8192 entries, each needs 12 bytes. Other entries need 20 + // bytes. + return 72 + 12 * Entries.size() + + (Entries.size() > 8192 ? 8 * (Entries.size() - 8192) : 0); + } return (Target->GotPltHeaderEntriesNum + Entries.size()) * Config->Wordsize; } @@ -1375,6 +1391,9 @@ } } + if (Config->EMachine == EM_PPC && Config->SecurePlt) + addInt(DT_LOPROC + 1, ElfSym::GlobalOffsetTable->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 @@ -2291,6 +2310,10 @@ return HeaderSize + Entries.size() * Target->PltEntrySize; } +bool PltSection::isNeeded() const { + return Config->EMachine != EM_PPC && !Entries.empty(); +} + // Some architectures such as additional symbols in the PLT section. For // example ARM uses mapping symbols to aid disassembly void PltSection::addSymbols() { @@ -3207,6 +3230,26 @@ return Changed; } +PPC32Got2Section::PPC32Got2Section() + : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, 4, ".got2") {} + +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/Thunks.h =================================================================== --- ELF/Thunks.h +++ ELF/Thunks.h @@ -48,7 +48,9 @@ // To reuse a Thunk the caller as identified by the Type must be // compatible with it. - virtual bool isCompatibleWith(RelType Type) const { return true; } + virtual bool isCompatibleWith(const InputSection &IS, RelType Type) const { + return true; + } Defined *getThunkTargetSym() const { return Syms[0]; } @@ -61,8 +63,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, RelType Type, Symbol &S); } // namespace elf } // namespace lld Index: ELF/Thunks.cpp =================================================================== --- ELF/Thunks.cpp +++ ELF/Thunks.cpp @@ -78,7 +78,7 @@ 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, RelType Type) const override; // Returns the size of a long thunk. virtual uint32_t sizeLong() = 0; @@ -107,7 +107,7 @@ 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, RelType Type) const override; // Returns the size of a long thunk. virtual uint32_t sizeLong() = 0; @@ -170,7 +170,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, + uint32_t RelocType) const override; }; class ARMV5PILongThunk final : public ARMThunk { @@ -180,7 +181,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, + uint32_t RelocType) const override; }; // Implementations of Thunks for Arm v6-M. Only Thumb instructions are permitted @@ -235,6 +237,17 @@ InputSection *getTargetInputSection() const override; }; +class PPC32PltCallStub final : public Thunk { + const InputFile *File; + +public: + PPC32PltCallStub(const InputSection &IS, Symbol &Dest) + : Thunk(Dest), 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, RelType Type) const override; +}; // PPC64 Plt call stubs. // Any call site that needs to call through a plt entry needs a call stub in @@ -396,7 +409,7 @@ Target->relocateOne(Buf, R_ARM_JUMP24, Offset); } -bool ARMThunk::isCompatibleWith(RelType Type) const { +bool ARMThunk::isCompatibleWith(const InputSection &IS, RelType Type) const { // Thumb branch relocations can't use BLX return Type != R_ARM_THM_JUMP19 && Type != R_ARM_THM_JUMP24; } @@ -433,7 +446,7 @@ Target->relocateOne(Buf, R_ARM_THM_JUMP24, Offset); } -bool ThumbThunk::isCompatibleWith(RelType Type) const { +bool ThumbThunk::isCompatibleWith(const InputSection &IS, RelType Type) const { // ARM branch relocations can't use BLX return Type != R_ARM_JUMP24 && Type != R_ARM_PC24 && Type != R_ARM_PLT32; } @@ -532,7 +545,8 @@ addSymbol("$d", STT_NOTYPE, 4, IS); } -bool ARMV5ABSLongThunk::isCompatibleWith(uint32_t RelocType) const { +bool ARMV5ABSLongThunk::isCompatibleWith(const InputSection &IS, + uint32_t RelocType) const { // Thumb branch relocations can't use BLX return RelocType != R_ARM_THM_JUMP19 && RelocType != R_ARM_THM_JUMP24; } @@ -557,7 +571,8 @@ addSymbol("$d", STT_NOTYPE, 12, IS); } -bool ARMV5PILongThunk::isCompatibleWith(uint32_t RelocType) const { +bool ARMV5PILongThunk::isCompatibleWith(const InputSection &IS, + uint32_t RelocType) const { // Thumb branch relocations can't use BLX return RelocType != R_ARM_THM_JUMP19 && RelocType != R_ARM_THM_JUMP24; } @@ -681,6 +696,44 @@ return dyn_cast(DR.Section); } +void PPC32PltCallStub::writeTo(uint8_t *Buf) { + if (Config->Pic) { + // In PIC mode, the stub loads an address relative to r30 (.got2+0x8000). + // The address of .got2 is different in another object file, so a stub + // cannot be shared. + uint32_t Offset = + Destination.getGotPltVA() - (In.PPC32Got2->getParent()->getVA() + + File->PPC32Got2OutSecOff + 0x8000); + 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 + } + } else { + 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 + } +} + +void PPC32PltCallStub::addSymbols(ThunkSection &IS) { + addSymbol(Saver.save("__plt_" + Destination.getName()), STT_FUNC, 0, IS); +} + +bool PPC32PltCallStub::isCompatibleWith(const InputSection &IS, + uint32_t RelocType) const { + return IS.File == File || !Config->Pic; +} + static void writePPCLoadAndBranch(uint8_t *Buf, int64_t Offset) { uint16_t OffHa = (Offset + 0x8000) >> 16; uint16_t OffLo = Offset & 0xffff; @@ -814,6 +867,12 @@ return make(S); } +static Thunk *addThunkPPC32(const InputSection &IS, RelType Type, Symbol &S) { + assert((Type == R_PPC_REL24 || Type == R_PPC_PLTREL24) && + "unexpected relocation type for thunk"); + return make(IS, S); +} + static Thunk *addThunkPPC64(RelType Type, Symbol &S) { assert(Type == R_PPC64_REL24 && "unexpected relocation type for thunk"); if (S.isInPlt()) @@ -825,7 +884,7 @@ return make(S); } -Thunk *addThunk(RelType Type, Symbol &S) { +Thunk *addThunk(const InputSection &IS, RelType Type, Symbol &S) { if (Config->EMachine == EM_AARCH64) return addThunkAArch64(Type, S); @@ -835,6 +894,9 @@ if (Config->EMachine == EM_MIPS) return addThunkMips(Type, S); + if (Config->EMachine == EM_PPC && Config->SecurePlt) + return addThunkPPC32(IS, Type, S); + if (Config->EMachine == EM_PPC64) return addThunkPPC64(Type, S); Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -225,7 +225,12 @@ StringRef GotSymName = (Config->EMachine == EM_PPC64) ? ".TOC." : "_GLOBAL_OFFSET_TABLE_"; - if (Symbol *S = Symtab->find(GotSymName)) { + if (Config->EMachine == EM_PPC) { + ElfSym::GlobalOffsetTable = cast(Symtab->addSymbol( + Defined{/*File=*/nullptr, GotSymName, STB_GLOBAL, STV_HIDDEN, + STT_NOTYPE, uint64_t(Config->SecurePlt ? 0 : 4), + /*Size=*/0, Out::ElfHeader})); + } else if (Symbol *S = Symtab->find(GotSymName)) { if (S->isDefined()) { error(toString(S->File) + " cannot redefine linker defined symbol '" + GotSymName + "'"); @@ -233,9 +238,8 @@ } 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, STT_NOTYPE, GotOff, /*Size=*/0, Out::ElfHeader}); ElfSym::GlobalOffsetTable = cast(S); @@ -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); @@ -1769,6 +1778,7 @@ finalizeSynthetic(In.RelaPlt); finalizeSynthetic(In.Plt); finalizeSynthetic(In.Iplt); + finalizeSynthetic(In.PPC32Got2); finalizeSynthetic(In.EhFrameHdr); finalizeSynthetic(In.VerSym); finalizeSynthetic(In.VerNeed); @@ -2096,7 +2106,7 @@ static uint64_t computeFileOffset(OutputSection *OS, uint64_t Off) { // File offsets are not significant for .bss sections. By convention, we keep // section offsets monotonically increasing rather than setting to zero. - if (OS->Type == SHT_NOBITS) + if (OS->Type == SHT_NOBITS && !(OS->PtLoad && OS->PtLoad->FirstSec == OS)) return Off; // If the section is not in a PT_LOAD, we just have to align it. Index: test/ELF/basic-ppc64.s =================================================================== --- test/ELF/basic-ppc64.s +++ test/ELF/basic-ppc64.s @@ -28,7 +28,7 @@ // CHECK-NEXT: Version: 1 // CHECK-NEXT: Entry: 0x10000 // CHECK-NEXT: ProgramHeaderOffset: 0x40 -// CHECK-NEXT: SectionHeaderOffset: 0x200F8 +// CHECK-NEXT: SectionHeaderOffset: 0x30098 // CHECK-NEXT: Flags [ (0x2) // CHECK-NEXT: 0x2 // CHECK-NEXT: ] @@ -163,7 +163,7 @@ // CHECK-NEXT: SHF_WRITE (0x1) // CHECK-NEXT: ] // CHECK-NEXT: Address: 0x30000 -// CHECK-NEXT: Offset: 0x20060 +// CHECK-NEXT: Offset: 0x30000 // CHECK-NEXT: Size: 0 // CHECK-NEXT: Link: 0 // CHECK-NEXT: Info: 0 @@ -179,7 +179,7 @@ // CHECK-NEXT: SHF_STRINGS (0x20) // CHECK-NEXT: ] // CHECK-NEXT: Address: 0x0 -// CHECK-NEXT: Offset: 0x20060 +// CHECK-NEXT: Offset: 0x30000 // CHECK-NEXT: Size: 8 // CHECK-NEXT: Link: 0 // CHECK-NEXT: Info: 0 @@ -196,7 +196,7 @@ // CHECK-NEXT: Flags [ (0x0) // CHECK-NEXT: ] // CHECK-NEXT: Address: 0x0 -// CHECK-NEXT: Offset: 0x20068 +// CHECK-NEXT: Offset: 0x30008 // CHECK-NEXT: Size: 48 // CHECK-NEXT: Link: 10 // CHECK-NEXT: Info: 2 @@ -215,7 +215,7 @@ // CHECK-NEXT: Flags [ (0x0) // CHECK-NEXT: ] // CHECK-NEXT: Address: 0x0 -// CHECK-NEXT: Offset: 0x20098 +// CHECK-NEXT: Offset: 0x30038 // CHECK-NEXT: Size: 84 // CHECK-NEXT: Link: 0 // CHECK-NEXT: Info: 0 @@ -237,7 +237,7 @@ // CHECK-NEXT: Flags [ (0x0) // CHECK-NEXT: ] // CHECK-NEXT: Address: 0x0 -// CHECK-NEXT: Offset: 0x200EC +// CHECK-NEXT: Offset: 0x3008C // CHECK-NEXT: Size: 10 // CHECK-NEXT: Link: 0 // CHECK-NEXT: Info: 0 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-call-pic.s =================================================================== --- /dev/null +++ test/ELF/ppc32-call-pic.s @@ -0,0 +1,82 @@ +# 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 -o %t1.so + +# RUN: ld.lld -pie %t.o %t1.so -o %t +# RUN: llvm-readobj -r %t | FileCheck --check-prefix=RELOC %s +# RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck %s + +# RUN: ld.lld -shared %t.o %t1.so -o %t +# RUN: llvm-readobj -r %t | FileCheck --check-prefix=RELOC %s +# RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck %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: } + +## .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 __plt_f +# CHECK-NEXT: bl .+24 +# CHECK-NEXT: bl .+20 +## Two bl __plt_g +# CHECK-NEXT: bl .+32 +# CHECK-NEXT: bl .+28 +## Two bl __plt_h +# CHECK-NEXT: bl .+40 +# CHECK-NEXT: bl .+36 +# CHECK-EMPTY: + +# CHECK-NEXT: __plt_f: +# CHECK-NEXT: lwz 11, 32760(30) +# CHECK-NEXT: mtctr 11 +# CHECK-NEXT: bctr +# CHECK-NEXT: nop +# CHECK-EMPTY: +# CHECK-NEXT: __plt_g: +# CHECK-NEXT: lwz 11, 32764(30) +# CHECK-NEXT: mtctr 11 +# CHECK-NEXT: bctr +# CHECK-NEXT: nop +# CHECK-EMPTY: + +## __plt_h needs two instructions addis+lwz to represent the offset 65536*1-32768. +# CHECK-NEXT: __plt_h: +# CHECK-NEXT: addis 11, 30, 1 +# CHECK-NEXT: lwz 11, -32768(11) +# CHECK-NEXT: mtctr 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+32768@plt + bl f+32768@plt + bl g+32768@plt + bl g+32768@plt + bl h+32768@plt + bl h+32768@plt Index: test/ELF/ppc32-reloc-addr.s =================================================================== --- /dev/null +++ test/ELF/ppc32-reloc-addr.s @@ -0,0 +1,29 @@ +# 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 +# RUN: llvm-objdump -s --no-show-raw-insn %t | FileCheck --check-prefix=HEX %s + +.section .R_PPC_ADDR16_HA,"ax",@progbits +1: + lis 4, 1b@ha +# CHECK-LABEL: section .R_PPC_ADDR16_HA: +# CHECK: 10010000: lis 4, 4097 + +.section .R_PPC_ADDR16_HI,"ax",@progbits +1: + lis 4,1b@h +# CHECK-LABEL: section .R_PPC_ADDR16_HI: +# CHECK: 10010004: lis 4, 4097 + +.section .R_PPC_ADDR16_LO,"ax",@progbits +1: + addi 4, 4, 1b@l +# CHECK-LABEL: section .R_PPC_ADDR16_LO: +# CHECK: 10010008: addi 4, 4, 8 + +.section .R_PPC_ADDR32,"a",@progbits +.Lfoo: + .long .Lfoo +# HEX-LABEL: section .R_PPC_ADDR32: +# HEX-NEXT: 1001000c 1001000c Index: test/ELF/ppc32-reloc-rel.s =================================================================== --- /dev/null +++ test/ELF/ppc32-reloc-rel.s @@ -0,0 +1,28 @@ +# 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 Index: test/ELF/relocation-copy-align-common.s =================================================================== --- test/ELF/relocation-copy-align-common.s +++ test/ELF/relocation-copy-align-common.s @@ -15,7 +15,7 @@ # CHECK-NEXT: SHF_WRITE # CHECK-NEXT: ] # CHECK-NEXT: Address: 0x203000 -# CHECK-NEXT: Offset: 0x20B0 +# CHECK-NEXT: Offset: 0x3000 # CHECK-NEXT: Size: 16 # CHECK-NEXT: Link: 0 # CHECK-NEXT: Info: 0