forked from OSchip/llvm-project
[ELF][PPC32] Support canonical PLT
-fno-pie produces a pair of non-GOT-non-PLT relocations R_PPC_ADDR16_{HA,LO} (R_ABS) referencing external functions. ``` lis 3, func@ha la 3, func@l(3) ``` In a -no-pie/-pie link, if func is not defined in the executable, a canonical PLT entry (st_value>0, st_shndx=0) will be needed. References to func in shared objects will be resolved to this address. -fno-pie -pie should fail with "can't create dynamic relocation ... against ...", so we just need to think about -no-pie. On x86, the PLT entry passes the JMP_SLOT offset to the rtld PLT resolver. On x86-64: the PLT entry passes the JUMP_SLOT index to the rtld PLT resolver. On ARM/AArch64: the PLT entry passes &.got.plt[n]. The PLT header passes &.got.plt[fixed-index]. The rtld PLT resolver can compute the JUMP_SLOT index from the two addresses. For these targets, the canonical PLT entry can just reuse the regular PLT entry (in PltSection). On PPC32: PltSection (.glink) consists of `b PLTresolve` instructions and `PLTresolve`. The rtld PLT resolver depends on r11 having been set up to the .plt (GotPltSection) entry. On PPC64 ELFv2: PltSection (.glink) consists of `__glink_PLTresolve` and `bl __glink_PLTresolve`. The rtld PLT resolver depends on r12 having been set up to the .plt (GotPltSection) entry. We cannot reuse a `b PLTresolve`/`bl __glink_PLTresolve` in PltSection as a canonical PLT entry. PPC64 ELFv2 avoids the problem by using TOC for any external reference, even in non-pic code, so the canonical PLT entry scenario should not happen in the first place. For PPC32, we have to create a PLT call stub as the canonical PLT entry. The code sequence sets up r11. Reviewed By: Bdragon28 Differential Revision: https://reviews.llvm.org/D73399
This commit is contained in:
parent
713562f548
commit
837e8a9c0c
|
@ -72,6 +72,18 @@ static void writeFromHalf16(uint8_t *loc, uint32_t insn) {
|
|||
}
|
||||
|
||||
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 @@ void writePPC32GlinkSection(uint8_t *buf, size_t numEntries) {
|
|||
// 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 @@ void writePPC32GlinkSection(uint8_t *buf, size_t numEntries) {
|
|||
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 @@ PPC::PPC() {
|
|||
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::writeGotHeader(uint8_t *buf) const {
|
|||
|
||||
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,
|
||||
|
|
|
@ -1198,10 +1198,16 @@ static void processRelocAux(InputSectionBase &sec, RelExpr expr, RelType type,
|
|||
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<Defined>(sym).value = in.plt->headerSize;
|
||||
in.plt->headerSize += 16;
|
||||
}
|
||||
}
|
||||
sym.needsPltAddr = true;
|
||||
sec.relocations.push_back({expr, type, offset, addend, &sym});
|
||||
return;
|
||||
|
|
|
@ -2449,6 +2449,9 @@ PltSection::PltSection()
|
|||
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 @@ void PltSection::addEntry(Symbol &sym) {
|
|||
}
|
||||
|
||||
size_t PltSection::getSize() const {
|
||||
return headerSize + entries.size() * target->pltEntrySize;
|
||||
return headerSize + entries.size() * target->pltEntrySize + footerSize;
|
||||
}
|
||||
|
||||
bool PltSection::isNeeded() const {
|
||||
|
|
|
@ -683,9 +683,9 @@ public:
|
|||
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<const Symbol *> entries;
|
||||
};
|
||||
|
||||
|
|
|
@ -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)
|
Loading…
Reference in New Issue