Skip to content

Commit f15b60b

Browse files
committed
[ELF][PPC32] Support range extension thunks with addends
* Generalize the code added in D70637 and D70937. We should eventually remove the EM_MIPS special case. * Handle R_PPC_LOCAL24PC the same way as R_PPC_REL24. Reviewed By: Bdragon28 Differential Revision: https://reviews.llvm.org/D73424 (cherry picked from commit 70389be)
1 parent 6f8ad14 commit f15b60b

File tree

4 files changed

+140
-23
lines changed

4 files changed

+140
-23
lines changed

lld/ELF/Arch/PPC.cpp

+5-5
Original file line numberDiff line numberDiff line change
@@ -193,21 +193,21 @@ void PPC::writeGotPlt(uint8_t *buf, const Symbol &s) const {
193193
}
194194

195195
bool PPC::needsThunk(RelExpr expr, RelType type, const InputFile *file,
196-
uint64_t branchAddr, const Symbol &s, int64_t /*a*/) const {
197-
if (type != R_PPC_REL24 && type != R_PPC_PLTREL24)
196+
uint64_t branchAddr, const Symbol &s, int64_t a) const {
197+
if (type != R_PPC_LOCAL24PC && type != R_PPC_REL24 && type != R_PPC_PLTREL24)
198198
return false;
199199
if (s.isInPlt())
200200
return true;
201201
if (s.isUndefWeak())
202202
return false;
203-
return !(expr == R_PC && PPC::inBranchRange(type, branchAddr, s.getVA()));
203+
return !PPC::inBranchRange(type, branchAddr, s.getVA(a));
204204
}
205205

206206
uint32_t PPC::getThunkSectionSpacing() const { return 0x2000000; }
207207

208208
bool PPC::inBranchRange(RelType type, uint64_t src, uint64_t dst) const {
209209
uint64_t offset = dst - src;
210-
if (type == R_PPC_REL24 || type == R_PPC_PLTREL24)
210+
if (type == R_PPC_LOCAL24PC || type == R_PPC_REL24 || type == R_PPC_PLTREL24)
211211
return isInt<26>(offset);
212212
llvm_unreachable("unsupported relocation type used in branch");
213213
}
@@ -230,13 +230,13 @@ RelExpr PPC::getRelExpr(RelType type, const Symbol &s,
230230
return R_DTPREL;
231231
case R_PPC_REL14:
232232
case R_PPC_REL32:
233-
case R_PPC_LOCAL24PC:
234233
case R_PPC_REL16_LO:
235234
case R_PPC_REL16_HI:
236235
case R_PPC_REL16_HA:
237236
return R_PC;
238237
case R_PPC_GOT16:
239238
return R_GOT_OFF;
239+
case R_PPC_LOCAL24PC:
240240
case R_PPC_REL24:
241241
return R_PLT_PC;
242242
case R_PPC_PLTREL24:

lld/ELF/Relocations.cpp

+7-14
Original file line numberDiff line numberDiff line change
@@ -1304,10 +1304,10 @@ static void scanReloc(InputSectionBase &sec, OffsetGetter &getOffset, RelTy *&i,
13041304
if (expr == R_GOT_PC && !isAbsoluteValue(sym)) {
13051305
expr = target->adjustRelaxExpr(type, relocatedAddr, expr);
13061306
} else {
1307-
// Addend of R_PPC_PLTREL24 is used to choose call stub type. It should be
1308-
// ignored if optimized to R_PC.
1307+
// The 0x8000 bit of r_addend of R_PPC_PLTREL24 is used to choose call
1308+
// stub type. It should be ignored if optimized to R_PC.
13091309
if (config->emachine == EM_PPC && expr == R_PPC32_PLTREL)
1310-
addend = 0;
1310+
addend &= ~0x8000;
13111311
expr = fromPlt(expr);
13121312
}
13131313
}
@@ -1826,9 +1826,7 @@ bool ThunkCreator::normalizeExistingThunk(Relocation &rel, uint64_t src) {
18261826
rel.sym->getVA(rel.addend) + getPCBias(rel.type)))
18271827
return true;
18281828
rel.sym = &t->destination;
1829-
// TODO Restore addend on all targets.
1830-
if (config->emachine == EM_AARCH64 || config->emachine == EM_PPC64)
1831-
rel.addend = t->addend;
1829+
rel.addend = t->addend;
18321830
if (rel.sym->isInPlt())
18331831
rel.expr = toPlt(rel.expr);
18341832
}
@@ -1906,16 +1904,11 @@ bool ThunkCreator::createThunks(ArrayRef<OutputSection *> outputSections) {
19061904
rel.sym = t->getThunkTargetSym();
19071905
rel.expr = fromPlt(rel.expr);
19081906

1909-
// On AArch64 and PPC64, a jump/call relocation may be encoded as
1907+
// On AArch64 and PPC, a jump/call relocation may be encoded as
19101908
// STT_SECTION + non-zero addend, clear the addend after
19111909
// redirection.
1912-
//
1913-
// The addend of R_PPC_PLTREL24 should be ignored after changing to
1914-
// R_PC.
1915-
if (config->emachine == EM_AARCH64 ||
1916-
config->emachine == EM_PPC64 ||
1917-
(config->emachine == EM_PPC && rel.type == R_PPC_PLTREL24))
1918-
rel.addend = 0;
1910+
if (config->emachine != EM_MIPS)
1911+
rel.addend = -getPCBias(rel.type);
19191912
}
19201913

19211914
for (auto &p : isd->thunkSections)

lld/ELF/Thunks.cpp

+41-4
Original file line numberDiff line numberDiff line change
@@ -245,8 +245,7 @@ class PPC32PltCallStub final : public Thunk {
245245
// decide the offsets in the call stub.
246246
PPC32PltCallStub(const InputSection &isec, const Relocation &rel,
247247
Symbol &dest)
248-
: Thunk(dest, rel.type == R_PPC_PLTREL24 ? rel.addend : 0),
249-
file(isec.file) {}
248+
: Thunk(dest, rel.addend), file(isec.file) {}
250249
uint32_t size() override { return 16; }
251250
void writeTo(uint8_t *buf) override;
252251
void addSymbols(ThunkSection &isec) override;
@@ -257,6 +256,14 @@ class PPC32PltCallStub final : public Thunk {
257256
const InputFile *file;
258257
};
259258

259+
class PPC32LongThunk final : public Thunk {
260+
public:
261+
PPC32LongThunk(Symbol &dest, int64_t addend) : Thunk(dest, addend) {}
262+
uint32_t size() override { return config->isPic ? 32 : 16; }
263+
void writeTo(uint8_t *buf) override;
264+
void addSymbols(ThunkSection &isec) override;
265+
};
266+
260267
// PPC64 Plt call stubs.
261268
// Any call site that needs to call through a plt entry needs a call stub in
262269
// the .text section. The call stub is responsible for:
@@ -765,6 +772,33 @@ bool PPC32PltCallStub::isCompatibleWith(const InputSection &isec,
765772
return !config->isPic || (isec.file == file && rel.addend == addend);
766773
}
767774

775+
void PPC32LongThunk::addSymbols(ThunkSection &isec) {
776+
addSymbol(saver.save("__LongThunk_" + destination.getName()), STT_FUNC, 0,
777+
isec);
778+
}
779+
780+
void PPC32LongThunk::writeTo(uint8_t *buf) {
781+
auto ha = [](uint32_t v) -> uint16_t { return (v + 0x8000) >> 16; };
782+
auto lo = [](uint32_t v) -> uint16_t { return v; };
783+
uint32_t d = destination.getVA(addend);
784+
if (config->isPic) {
785+
uint32_t off = d - (getThunkTargetSym()->getVA() + 8);
786+
write32(buf + 0, 0x7c0802a6); // mflr r12,0
787+
write32(buf + 4, 0x429f0005); // bcl r20,r31,.+4
788+
write32(buf + 8, 0x7d8802a6); // mtctr r12
789+
write32(buf + 12, 0x3d8c0000 | ha(off)); // addis r12,r12,off@ha
790+
write32(buf + 16, 0x398c0000 | lo(off)); // addi r12,r12,off@l
791+
write32(buf + 20, 0x7c0803a6); // mtlr r0
792+
buf += 24;
793+
} else {
794+
write32(buf + 0, 0x3d800000 | ha(d)); // lis r12,d@ha
795+
write32(buf + 4, 0x398c0000 | lo(d)); // addi r12,r12,d@l
796+
buf += 8;
797+
}
798+
write32(buf + 0, 0x7d8903a6); // mtctr r12
799+
write32(buf + 4, 0x4e800420); // bctr
800+
}
801+
768802
void writePPC64LoadAndBranch(uint8_t *buf, int64_t offset) {
769803
uint16_t offHa = (offset + 0x8000) >> 16;
770804
uint16_t offLo = offset & 0xffff;
@@ -902,9 +936,12 @@ static Thunk *addThunkMips(RelType type, Symbol &s) {
902936

903937
static Thunk *addThunkPPC32(const InputSection &isec, const Relocation &rel,
904938
Symbol &s) {
905-
assert((rel.type == R_PPC_REL24 || rel.type == R_PPC_PLTREL24) &&
939+
assert((rel.type == R_PPC_LOCAL24PC || rel.type == R_PPC_REL24 ||
940+
rel.type == R_PPC_PLTREL24) &&
906941
"unexpected relocation type for thunk");
907-
return make<PPC32PltCallStub>(isec, rel, s);
942+
if (s.isInPlt())
943+
return make<PPC32PltCallStub>(isec, rel, s);
944+
return make<PPC32LongThunk>(s, rel.addend);
908945
}
909946

910947
static Thunk *addThunkPPC64(RelType type, Symbol &s, int64_t a) {

lld/test/ELF/ppc32-long-thunk.s

+87
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
# REQUIRES: ppc
2+
# RUN: echo 'SECTIONS { \
3+
# RUN: .text_low 0x2000: { *(.text_low) } \
4+
# RUN: .text_high 0x2002000 : { *(.text_high) } \
5+
# RUN: }' > %t.script
6+
7+
# RUN: llvm-mc -filetype=obj -triple=powerpc %s -o %t.o
8+
# RUN: ld.lld -T %t.script %t.o -o %t
9+
# RUN: llvm-readelf -r %t | FileCheck --check-prefix=SEC %s
10+
# RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck --check-prefixes=CHECK,PD %s
11+
12+
# RUN: ld.lld -T %t.script -pie %t.o -o %t
13+
# RUN: llvm-readelf -r %t | FileCheck --check-prefix=SEC %s
14+
# RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck --check-prefixes=CHECK,PI %s
15+
16+
# SEC: There are no relocations in this file.
17+
18+
# CHECK: _start:
19+
# CHECK-NEXT: 2000: bl .+24
20+
# CHECK-NEXT: bl .+20
21+
# CHECK-NEXT: bl .+16
22+
# CHECK-NEXT: bl .+33554428
23+
# PD-NEXT: bl .+24
24+
# PI-NEXT: bl .+40
25+
26+
## high = 0x02002008 = 65536*512+8200
27+
# PD: __LongThunk_high:
28+
# PD-NEXT: 2018: lis 12, 512
29+
# PD-NEXT: addi 12, 12, 8200
30+
# PD-NEXT: mtctr 12
31+
# PD-NEXT: bctr
32+
33+
## .text_high+16 = 0x02002010 = 65536*512+8208
34+
# PD: __LongThunk_:
35+
# PD-NEXT: 2028: lis 12, 512
36+
# PD-NEXT: addi 12, 12, 8208
37+
# PD-NEXT: mtctr 12
38+
# PD-NEXT: bctr
39+
40+
## high-0x2028 = 0x02002008-0x2020 = 65536*512-24
41+
# PI: __LongThunk_high:
42+
# PI-NEXT: 2018: mflr 0
43+
# PI-NEXT: bcl 20, 31, .+4
44+
# PI-NEXT: 2020: mflr 12
45+
# PI-NEXT: addis 12, 12, 512
46+
# PI-NEXT: addi 12, 12, -24
47+
# PI-NEXT: mtlr 0
48+
# PI-NEXT: mtctr 12
49+
# PI-NEXT: bctr
50+
51+
## .text_high+16-0x2048 = 0x02002010-0x2048 = 65536*512-48
52+
# PI: __LongThunk_:
53+
# PI-NEXT: 2038: mflr 0
54+
# PI-NEXT: bcl 20, 31, .+4
55+
# PI-NEXT: 2040: mflr 12
56+
# PI-NEXT: addis 12, 12, 512
57+
# PI-NEXT: addi 12, 12, -48
58+
# PI-NEXT: mtlr 0
59+
# PI-NEXT: mtctr 12
60+
# PI-NEXT: bctr
61+
62+
.section .text_low, "ax", %progbits
63+
.globl _start
64+
_start:
65+
bl high@local # Need a thunk
66+
bl high@local # Need a thunk
67+
bl high+32768@plt # Need a thunk
68+
bl high
69+
bl .text_high+16 # Need a thunk
70+
blr
71+
72+
# PD: 02002008 high:
73+
# PD-NEXT: bl .-33554432
74+
# PD-NEXT: bl .+4
75+
# PD: __LongThunk_:
76+
# PD-NEXT: 2002010: lis 12, 0
77+
# PD-NEXT: addi 12, 12, 8200
78+
# PD-NEXT: mtctr 12
79+
# PD-NEXT: bctr
80+
81+
.section .text_high, "ax", %progbits
82+
nop
83+
nop
84+
.globl high
85+
high:
86+
bl .text_low+8
87+
bl .text_low+8 # Need a thunk

0 commit comments

Comments
 (0)