diff --git a/lld/ELF/Arch/PPC.cpp b/lld/ELF/Arch/PPC.cpp --- a/lld/ELF/Arch/PPC.cpp +++ b/lld/ELF/Arch/PPC.cpp @@ -72,6 +72,18 @@ } void writePPC32GlinkSection(uint8_t *buf, size_t numEntries) { + // Create canonical PLT entries for non-PIE code. Compilers don't generate + // non-GOT-non-PLT relocations referencing external functions for -fpie/-fPIE. + uint32_t glink = in.plt->getVA(); // VA of .glink + if (!config->isPic) { + for (const Symbol *sym : in.plt->entries) + if (sym->needsPltAddr) { + writePPC32PltCallStub(buf, sym->getGotPltVA(), nullptr, 0); + buf += 16; + glink += 16; + } + } + // On PPC Secure PLT ABI, bl foo@plt jumps to a call stub, which loads an // absolute address from a specific .plt slot (usually called .got.plt on // other targets) and jumps there. @@ -90,15 +102,14 @@ // 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->isPic) { - uint32_t afterBcl = in.plt->getSize() - target->pltHeaderSize + 12; + uint32_t afterBcl = 4 * in.plt->getNumEntries() + 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 + 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 @@ -118,16 +129,16 @@ 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 + 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 + 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) + write32(buf + 24, 0x818c0000 | lo(got + 8)); // lwz r12,GOT+8@l(r12) else write32(buf + 24, 0x818c0000 | 4); // lwz r12,4(r12) write32(buf + 28, 0x7d605a14); // add r11,r0,r11 @@ -151,7 +162,7 @@ gotBaseSymInGotPlt = false; gotHeaderEntriesNum = 3; gotPltHeaderEntriesNum = 0; - pltHeaderSize = 64; // size of PLTresolve in .glink + pltHeaderSize = 0; pltEntrySize = 4; ipltEntrySize = 16; @@ -183,7 +194,7 @@ 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); + write32(buf, in.plt->getVA() + in.plt->headerSize + 4 * s.pltIndex); } bool PPC::needsThunk(RelExpr expr, RelType type, const InputFile *file, diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp --- a/lld/ELF/Relocations.cpp +++ b/lld/ELF/Relocations.cpp @@ -1198,10 +1198,16 @@ getLocation(sec, sym, offset)); if (!sym.isInPlt()) addPltEntry(in.plt, in.gotPlt, in.relaPlt, target->pltRel, sym); - if (!sym.isDefined()) + if (!sym.isDefined()) { replaceWithDefined( sym, in.plt, target->pltHeaderSize + target->pltEntrySize * sym.pltIndex, 0); + if (config->emachine == EM_PPC) { + // PPC32 canonical PLT entries are at the beginning of .glink + cast(sym).value = in.plt->headerSize; + in.plt->headerSize += 16; + } + } sym.needsPltAddr = true; sec.relocations.push_back({expr, type, offset, addend, &sym}); return; diff --git a/lld/ELF/SyntheticSections.h b/lld/ELF/SyntheticSections.h --- a/lld/ELF/SyntheticSections.h +++ b/lld/ELF/SyntheticSections.h @@ -683,9 +683,9 @@ void addEntry(Symbol &sym); size_t getNumEntries() const { return entries.size(); } - size_t headerSize = 0; + size_t headerSize; + size_t footerSize = 0; -private: std::vector entries; }; diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp --- a/lld/ELF/SyntheticSections.cpp +++ b/lld/ELF/SyntheticSections.cpp @@ -2449,6 +2449,9 @@ if (config->emachine == EM_PPC || config->emachine == EM_PPC64) { name = ".glink"; alignment = 4; + // PLTresolve is at the end. + if (config->emachine == EM_PPC) + footerSize = 64; } // On x86 when IBT is enabled, this section contains the second PLT (lazy @@ -2486,7 +2489,7 @@ } size_t PltSection::getSize() const { - return headerSize + entries.size() * target->pltEntrySize; + return headerSize + entries.size() * target->pltEntrySize + footerSize; } bool PltSection::isNeeded() const { diff --git a/lld/test/ELF/ppc32-canonical-plt.s b/lld/test/ELF/ppc32-canonical-plt.s new file mode 100644 --- /dev/null +++ b/lld/test/ELF/ppc32-canonical-plt.s @@ -0,0 +1,72 @@ +# REQUIRES: ppc + +## Test that we create canonical PLT entries for -no-pie. + +# RUN: llvm-mc -filetype=obj -triple=powerpc %s -o %t.o +# RUN: llvm-mc -filetype=obj -triple=powerpc %p/Inputs/canonical-plt-pcrel.s -o %t1.o +# RUN: ld.lld %t1.o -o %t1.so -shared -soname=so + +# RUN: ld.lld %t.o %t1.so -o %t +# RUN: llvm-readobj -r %t | FileCheck --check-prefix=REL %s +# RUN: llvm-readelf -S -s %t | FileCheck --check-prefix=SYM %s +# RUN: llvm-readelf -x .plt %t | FileCheck --check-prefix=HEX %s +# RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck %s + +# REL: Relocations [ +# REL-NEXT: .rela.plt { +# REL-NEXT: R_PPC_JMP_SLOT func 0x0 +# REL-NEXT: R_PPC_JMP_SLOT ifunc 0x0 +# REL-NEXT: } +# REL-NEXT: ] + +# SYM: .glink PROGBITS 100101dc + +## st_value points to the canonical PLT entry in .glink +# SYM: Symbol table '.dynsym' +# SYM: 100101dc 0 FUNC GLOBAL DEFAULT UND func +# SYM: 100101ec 0 FUNC GLOBAL DEFAULT UND ifunc +# SYM: Symbol table '.symtab' +# SYM: 100101dc 0 FUNC GLOBAL DEFAULT UND func +# SYM: 100101ec 0 FUNC GLOBAL DEFAULT UND ifunc + +# HEX: 0x100302b4 100101fc 10010200 + +## Canonical PLT entry of func. +## 0x100101dc + 4*2 + 64 = 0x10010224 +## 0x1001021c = 65536*4099+692 +# CHECK: 100101dc .glink: +# CHECK-NEXT: lis 11, 4099 +# CHECK-NEXT: lwz 11, 692(11) +# CHECK-NEXT: mtctr 11 +# CHECK-NEXT: bctr + +## Canonical PLT entry of ifunc. +## 0x10010220 = 65536*4099+696 +# CHECK-NEXT: 100101ec: lis 11, 4099 +# CHECK-NEXT: lwz 11, 696(11) +# CHECK-NEXT: mtctr 11 +# CHECK-NEXT: bctr + +## The 2 b instructions are referenced by .plt entries. +# CHECK-NEXT: 100101fc: b .+8 +# CHECK-NEXT: b .+4 + +## PLTresolve of 64 bytes is at the end. +## Operands of addis & addi: -0x100101fc = 65536*-4097-508 +# CHECK-NEXT: lis 12, 0 +# CHECK-NEXT: addis 11, 11, -4097 +# CHECK-NEXT: lwz 0, 4(12) +# CHECK-NEXT: addi 11, 11, -508 +# CHECK-NEXT: mtctr 0 +# CHECK-NEXT: add 0, 11, 11 +# CHECK-NEXT: lwz 12, 8(12) +# CHECK-NEXT: add 11, 0, 11 +# CHECK-NEXT: bctr +# CHECK-COUNT-7: nop + +.globl _start +_start: + lis 3, func@ha + la 3, func@l(3) + lis 4, ifunc@ha + la 4, ifunc@l(4)