Skip to content

Commit 6f8ad14

Browse files
committed
[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 (cherry picked from commit 837e8a9)
1 parent c21e178 commit 6f8ad14

File tree

5 files changed

+104
-12
lines changed

5 files changed

+104
-12
lines changed

lld/ELF/Arch/PPC.cpp

+19-8
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,18 @@ static void writeFromHalf16(uint8_t *loc, uint32_t insn) {
6767
}
6868

6969
void writePPC32GlinkSection(uint8_t *buf, size_t numEntries) {
70+
// Create canonical PLT entries for non-PIE code. Compilers don't generate
71+
// non-GOT-non-PLT relocations referencing external functions for -fpie/-fPIE.
72+
uint32_t glink = in.plt->getVA(); // VA of .glink
73+
if (!config->isPic) {
74+
for (const Symbol *sym : in.plt->entries)
75+
if (sym->needsPltAddr) {
76+
writePPC32PltCallStub(buf, sym->getGotPltVA(), nullptr, 0);
77+
buf += 16;
78+
glink += 16;
79+
}
80+
}
81+
7082
// On PPC Secure PLT ABI, bl foo@plt jumps to a call stub, which loads an
7183
// absolute address from a specific .plt slot (usually called .got.plt on
7284
// other targets) and jumps there.
@@ -85,15 +97,14 @@ void writePPC32GlinkSection(uint8_t *buf, size_t numEntries) {
8597
// computes the PLT index (by computing the distance from the landing b to
8698
// itself) and calls _dl_runtime_resolve() (in glibc).
8799
uint32_t got = in.got->getVA();
88-
uint32_t glink = in.plt->getVA(); // VA of .glink
89100
const uint8_t *end = buf + 64;
90101
if (config->isPic) {
91-
uint32_t afterBcl = in.plt->getSize() - target->pltHeaderSize + 12;
102+
uint32_t afterBcl = 4 * in.plt->getNumEntries() + 12;
92103
uint32_t gotBcl = got + 4 - (glink + afterBcl);
93104
write32(buf + 0, 0x3d6b0000 | ha(afterBcl)); // addis r11,r11,1f-glink@ha
94105
write32(buf + 4, 0x7c0802a6); // mflr r0
95106
write32(buf + 8, 0x429f0005); // bcl 20,30,.+4
96-
write32(buf + 12, 0x396b0000 | lo(afterBcl)); // 1: addi r11,r11,1b-.glink@l
107+
write32(buf + 12, 0x396b0000 | lo(afterBcl)); // 1: addi r11,r11,1b-glink@l
97108
write32(buf + 16, 0x7d8802a6); // mflr r12
98109
write32(buf + 20, 0x7c0803a6); // mtlr r0
99110
write32(buf + 24, 0x7d6c5850); // sub r11,r11,r12
@@ -113,16 +124,16 @@ void writePPC32GlinkSection(uint8_t *buf, size_t numEntries) {
113124
buf += 56;
114125
} else {
115126
write32(buf + 0, 0x3d800000 | ha(got + 4)); // lis r12,GOT+4@ha
116-
write32(buf + 4, 0x3d6b0000 | ha(-glink)); // addis r11,r11,-Glink@ha
127+
write32(buf + 4, 0x3d6b0000 | ha(-glink)); // addis r11,r11,-glink@ha
117128
if (ha(got + 4) == ha(got + 8))
118129
write32(buf + 8, 0x800c0000 | lo(got + 4)); // lwz r0,GOT+4@l(r12)
119130
else
120131
write32(buf + 8, 0x840c0000 | lo(got + 4)); // lwzu r0,GOT+4@l(r12)
121-
write32(buf + 12, 0x396b0000 | lo(-glink)); // addi r11,r11,-Glink@l
132+
write32(buf + 12, 0x396b0000 | lo(-glink)); // addi r11,r11,-glink@l
122133
write32(buf + 16, 0x7c0903a6); // mtctr r0
123134
write32(buf + 20, 0x7c0b5a14); // add r0,r11,r11
124135
if (ha(got + 4) == ha(got + 8))
125-
write32(buf + 24, 0x818c0000 | lo(got + 8)); // lwz r12,GOT+8@ha(r12)
136+
write32(buf + 24, 0x818c0000 | lo(got + 8)); // lwz r12,GOT+8@l(r12)
126137
else
127138
write32(buf + 24, 0x818c0000 | 4); // lwz r12,4(r12)
128139
write32(buf + 28, 0x7d605a14); // add r11,r0,r11
@@ -146,7 +157,7 @@ PPC::PPC() {
146157
gotBaseSymInGotPlt = false;
147158
gotHeaderEntriesNum = 3;
148159
gotPltHeaderEntriesNum = 0;
149-
pltHeaderSize = 64; // size of PLTresolve in .glink
160+
pltHeaderSize = 0;
150161
pltEntrySize = 4;
151162
ipltEntrySize = 16;
152163

@@ -178,7 +189,7 @@ void PPC::writeGotHeader(uint8_t *buf) const {
178189

179190
void PPC::writeGotPlt(uint8_t *buf, const Symbol &s) const {
180191
// Address of the symbol resolver stub in .glink .
181-
write32(buf, in.plt->getVA() + 4 * s.pltIndex);
192+
write32(buf, in.plt->getVA() + in.plt->headerSize + 4 * s.pltIndex);
182193
}
183194

184195
bool PPC::needsThunk(RelExpr expr, RelType type, const InputFile *file,

lld/ELF/Relocations.cpp

+7-1
Original file line numberDiff line numberDiff line change
@@ -1198,10 +1198,16 @@ static void processRelocAux(InputSectionBase &sec, RelExpr expr, RelType type,
11981198
getLocation(sec, sym, offset));
11991199
if (!sym.isInPlt())
12001200
addPltEntry(in.plt, in.gotPlt, in.relaPlt, target->pltRel, sym);
1201-
if (!sym.isDefined())
1201+
if (!sym.isDefined()) {
12021202
replaceWithDefined(
12031203
sym, in.plt,
12041204
target->pltHeaderSize + target->pltEntrySize * sym.pltIndex, 0);
1205+
if (config->emachine == EM_PPC) {
1206+
// PPC32 canonical PLT entries are at the beginning of .glink
1207+
cast<Defined>(sym).value = in.plt->headerSize;
1208+
in.plt->headerSize += 16;
1209+
}
1210+
}
12051211
sym.needsPltAddr = true;
12061212
sec.relocations.push_back({expr, type, offset, addend, &sym});
12071213
return;

lld/ELF/SyntheticSections.cpp

+4-1
Original file line numberDiff line numberDiff line change
@@ -2449,6 +2449,9 @@ PltSection::PltSection()
24492449
if (config->emachine == EM_PPC || config->emachine == EM_PPC64) {
24502450
name = ".glink";
24512451
alignment = 4;
2452+
// PLTresolve is at the end.
2453+
if (config->emachine == EM_PPC)
2454+
footerSize = 64;
24522455
}
24532456

24542457
// On x86 when IBT is enabled, this section contains the second PLT (lazy
@@ -2486,7 +2489,7 @@ void PltSection::addEntry(Symbol &sym) {
24862489
}
24872490

24882491
size_t PltSection::getSize() const {
2489-
return headerSize + entries.size() * target->pltEntrySize;
2492+
return headerSize + entries.size() * target->pltEntrySize + footerSize;
24902493
}
24912494

24922495
bool PltSection::isNeeded() const {

lld/ELF/SyntheticSections.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -683,9 +683,9 @@ class PltSection : public SyntheticSection {
683683
void addEntry(Symbol &sym);
684684
size_t getNumEntries() const { return entries.size(); }
685685

686-
size_t headerSize = 0;
686+
size_t headerSize;
687+
size_t footerSize = 0;
687688

688-
private:
689689
std::vector<const Symbol *> entries;
690690
};
691691

lld/test/ELF/ppc32-canonical-plt.s

+72
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
# REQUIRES: ppc
2+
3+
## Test that we create canonical PLT entries for -no-pie.
4+
5+
# RUN: llvm-mc -filetype=obj -triple=powerpc %s -o %t.o
6+
# RUN: llvm-mc -filetype=obj -triple=powerpc %p/Inputs/canonical-plt-pcrel.s -o %t1.o
7+
# RUN: ld.lld %t1.o -o %t1.so -shared -soname=so
8+
9+
# RUN: ld.lld %t.o %t1.so -o %t
10+
# RUN: llvm-readobj -r %t | FileCheck --check-prefix=REL %s
11+
# RUN: llvm-readelf -S -s %t | FileCheck --check-prefix=SYM %s
12+
# RUN: llvm-readelf -x .plt %t | FileCheck --check-prefix=HEX %s
13+
# RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck %s
14+
15+
# REL: Relocations [
16+
# REL-NEXT: .rela.plt {
17+
# REL-NEXT: R_PPC_JMP_SLOT func 0x0
18+
# REL-NEXT: R_PPC_JMP_SLOT ifunc 0x0
19+
# REL-NEXT: }
20+
# REL-NEXT: ]
21+
22+
# SYM: .glink PROGBITS 100101dc
23+
24+
## st_value points to the canonical PLT entry in .glink
25+
# SYM: Symbol table '.dynsym'
26+
# SYM: 100101dc 0 FUNC GLOBAL DEFAULT UND func
27+
# SYM: 100101ec 0 FUNC GLOBAL DEFAULT UND ifunc
28+
# SYM: Symbol table '.symtab'
29+
# SYM: 100101dc 0 FUNC GLOBAL DEFAULT UND func
30+
# SYM: 100101ec 0 FUNC GLOBAL DEFAULT UND ifunc
31+
32+
# HEX: 0x100302b4 100101fc 10010200
33+
34+
## Canonical PLT entry of func.
35+
## 0x100101dc + 4*2 + 64 = 0x10010224
36+
## 0x1001021c = 65536*4099+692
37+
# CHECK: 100101dc .glink:
38+
# CHECK-NEXT: lis 11, 4099
39+
# CHECK-NEXT: lwz 11, 692(11)
40+
# CHECK-NEXT: mtctr 11
41+
# CHECK-NEXT: bctr
42+
43+
## Canonical PLT entry of ifunc.
44+
## 0x10010220 = 65536*4099+696
45+
# CHECK-NEXT: 100101ec: lis 11, 4099
46+
# CHECK-NEXT: lwz 11, 696(11)
47+
# CHECK-NEXT: mtctr 11
48+
# CHECK-NEXT: bctr
49+
50+
## The 2 b instructions are referenced by .plt entries.
51+
# CHECK-NEXT: 100101fc: b .+8
52+
# CHECK-NEXT: b .+4
53+
54+
## PLTresolve of 64 bytes is at the end.
55+
## Operands of addis & addi: -0x100101fc = 65536*-4097-508
56+
# CHECK-NEXT: lis 12, 0
57+
# CHECK-NEXT: addis 11, 11, -4097
58+
# CHECK-NEXT: lwz 0, 4(12)
59+
# CHECK-NEXT: addi 11, 11, -508
60+
# CHECK-NEXT: mtctr 0
61+
# CHECK-NEXT: add 0, 11, 11
62+
# CHECK-NEXT: lwz 12, 8(12)
63+
# CHECK-NEXT: add 11, 0, 11
64+
# CHECK-NEXT: bctr
65+
# CHECK-COUNT-7: nop
66+
67+
.globl _start
68+
_start:
69+
lis 3, func@ha
70+
la 3, func@l(3)
71+
lis 4, ifunc@ha
72+
la 4, ifunc@l(4)

0 commit comments

Comments
 (0)