1 | //===- PPC.cpp ------------------------------------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "OutputSections.h" |
10 | #include "Symbols.h" |
11 | #include "SyntheticSections.h" |
12 | #include "Target.h" |
13 | #include "Thunks.h" |
14 | |
15 | using namespace llvm; |
16 | using namespace llvm::support::endian; |
17 | using namespace llvm::ELF; |
18 | using namespace lld; |
19 | using namespace lld::elf; |
20 | |
21 | // Undefine the macro predefined by GCC powerpc32. |
22 | #undef PPC |
23 | |
24 | namespace { |
25 | class PPC final : public TargetInfo { |
26 | public: |
27 | PPC(Ctx &); |
28 | RelExpr getRelExpr(RelType type, const Symbol &s, |
29 | const uint8_t *loc) const override; |
30 | RelType getDynRel(RelType type) const override; |
31 | int64_t getImplicitAddend(const uint8_t *buf, RelType type) const override; |
32 | void writeGotHeader(uint8_t *buf) const override; |
33 | void (uint8_t *buf) const override { |
34 | llvm_unreachable("should call writePPC32GlinkSection() instead" ); |
35 | } |
36 | void writePlt(uint8_t *buf, const Symbol &sym, |
37 | uint64_t pltEntryAddr) const override { |
38 | llvm_unreachable("should call writePPC32GlinkSection() instead" ); |
39 | } |
40 | void writeIplt(uint8_t *buf, const Symbol &sym, |
41 | uint64_t pltEntryAddr) const override; |
42 | void writeGotPlt(uint8_t *buf, const Symbol &s) const override; |
43 | bool needsThunk(RelExpr expr, RelType relocType, const InputFile *file, |
44 | uint64_t branchAddr, const Symbol &s, |
45 | int64_t a) const override; |
46 | uint32_t getThunkSectionSpacing() const override; |
47 | bool inBranchRange(RelType type, uint64_t src, uint64_t dst) const override; |
48 | void relocate(uint8_t *loc, const Relocation &rel, |
49 | uint64_t val) const override; |
50 | RelExpr adjustTlsExpr(RelType type, RelExpr expr) const override; |
51 | int getTlsGdRelaxSkip(RelType type) const override; |
52 | void relocateAlloc(InputSectionBase &sec, uint8_t *buf) const override; |
53 | |
54 | private: |
55 | void relaxTlsGdToIe(uint8_t *loc, const Relocation &rel, uint64_t val) const; |
56 | void relaxTlsGdToLe(uint8_t *loc, const Relocation &rel, uint64_t val) const; |
57 | void relaxTlsLdToLe(uint8_t *loc, const Relocation &rel, uint64_t val) const; |
58 | void relaxTlsIeToLe(uint8_t *loc, const Relocation &rel, uint64_t val) const; |
59 | }; |
60 | } // namespace |
61 | |
62 | static uint16_t lo(uint32_t v) { return v; } |
63 | static uint16_t ha(uint32_t v) { return (v + 0x8000) >> 16; } |
64 | |
65 | static uint32_t readFromHalf16(Ctx &ctx, const uint8_t *loc) { |
66 | return read32(ctx, p: ctx.arg.isLE ? loc : loc - 2); |
67 | } |
68 | |
69 | static void writeFromHalf16(Ctx &ctx, uint8_t *loc, uint32_t insn) { |
70 | write32(ctx, p: ctx.arg.isLE ? loc : loc - 2, v: insn); |
71 | } |
72 | |
73 | void elf::writePPC32GlinkSection(Ctx &ctx, uint8_t *buf, size_t numEntries) { |
74 | // Create canonical PLT entries for non-PIE code. Compilers don't generate |
75 | // non-GOT-non-PLT relocations referencing external functions for -fpie/-fPIE. |
76 | uint32_t glink = ctx.in.plt->getVA(); // VA of .glink |
77 | if (!ctx.arg.isPic) { |
78 | for (const Symbol *sym : |
79 | cast<PPC32GlinkSection>(Val&: *ctx.in.plt).canonical_plts) { |
80 | writePPC32PltCallStub(ctx, buf, gotPltVA: sym->getGotPltVA(ctx), file: nullptr, addend: 0); |
81 | buf += 16; |
82 | glink += 16; |
83 | } |
84 | } |
85 | |
86 | // On PPC Secure PLT ABI, bl foo@plt jumps to a call stub, which loads an |
87 | // absolute address from a specific .plt slot (usually called .got.plt on |
88 | // other targets) and jumps there. |
89 | // |
90 | // a) With immediate binding (BIND_NOW), the .plt entry is resolved at load |
91 | // time. The .glink section is not used. |
92 | // b) With lazy binding, the .plt entry points to a `b PLTresolve` |
93 | // instruction in .glink, filled in by PPC::writeGotPlt(). |
94 | |
95 | // Write N `b PLTresolve` first. |
96 | for (size_t i = 0; i != numEntries; ++i) |
97 | write32(ctx, p: buf + 4 * i, v: 0x48000000 | 4 * (numEntries - i)); |
98 | buf += 4 * numEntries; |
99 | |
100 | // Then write PLTresolve(), which has two forms: PIC and non-PIC. PLTresolve() |
101 | // computes the PLT index (by computing the distance from the landing b to |
102 | // itself) and calls _dl_runtime_resolve() (in glibc). |
103 | uint32_t got = ctx.in.got->getVA(); |
104 | const uint8_t *end = buf + 64; |
105 | if (ctx.arg.isPic) { |
106 | uint32_t afterBcl = 4 * ctx.in.plt->getNumEntries() + 12; |
107 | uint32_t gotBcl = got + 4 - (glink + afterBcl); |
108 | write32(ctx, p: buf + 0, |
109 | v: 0x3d6b0000 | ha(v: afterBcl)); // addis r11,r11,1f-glink@ha |
110 | write32(ctx, p: buf + 4, v: 0x7c0802a6); // mflr r0 |
111 | write32(ctx, p: buf + 8, v: 0x429f0005); // bcl 20,30,.+4 |
112 | write32(ctx, p: buf + 12, |
113 | v: 0x396b0000 | lo(v: afterBcl)); // 1: addi r11,r11,1b-glink@l |
114 | write32(ctx, p: buf + 16, v: 0x7d8802a6); // mflr r12 |
115 | write32(ctx, p: buf + 20, v: 0x7c0803a6); // mtlr r0 |
116 | write32(ctx, p: buf + 24, v: 0x7d6c5850); // sub r11,r11,r12 |
117 | write32(ctx, p: buf + 28, v: 0x3d8c0000 | ha(v: gotBcl)); // addis 12,12,GOT+4-1b@ha |
118 | if (ha(v: gotBcl) == ha(v: gotBcl + 4)) { |
119 | write32(ctx, p: buf + 32, |
120 | v: 0x800c0000 | lo(v: gotBcl)); // lwz r0,r12,GOT+4-1b@l(r12) |
121 | write32(ctx, p: buf + 36, |
122 | v: 0x818c0000 | lo(v: gotBcl + 4)); // lwz r12,r12,GOT+8-1b@l(r12) |
123 | } else { |
124 | write32(ctx, p: buf + 32, |
125 | v: 0x840c0000 | lo(v: gotBcl)); // lwzu r0,r12,GOT+4-1b@l(r12) |
126 | write32(ctx, p: buf + 36, v: 0x818c0000 | 4); // lwz r12,r12,4(r12) |
127 | } |
128 | write32(ctx, p: buf + 40, v: 0x7c0903a6); // mtctr 0 |
129 | write32(ctx, p: buf + 44, v: 0x7c0b5a14); // add r0,11,11 |
130 | write32(ctx, p: buf + 48, v: 0x7d605a14); // add r11,0,11 |
131 | write32(ctx, p: buf + 52, v: 0x4e800420); // bctr |
132 | buf += 56; |
133 | } else { |
134 | write32(ctx, p: buf + 0, v: 0x3d800000 | ha(v: got + 4)); // lis r12,GOT+4@ha |
135 | write32(ctx, p: buf + 4, v: 0x3d6b0000 | ha(v: -glink)); // addis r11,r11,-glink@ha |
136 | if (ha(v: got + 4) == ha(v: got + 8)) |
137 | write32(ctx, p: buf + 8, v: 0x800c0000 | lo(v: got + 4)); // lwz r0,GOT+4@l(r12) |
138 | else |
139 | write32(ctx, p: buf + 8, v: 0x840c0000 | lo(v: got + 4)); // lwzu r0,GOT+4@l(r12) |
140 | write32(ctx, p: buf + 12, v: 0x396b0000 | lo(v: -glink)); // addi r11,r11,-glink@l |
141 | write32(ctx, p: buf + 16, v: 0x7c0903a6); // mtctr r0 |
142 | write32(ctx, p: buf + 20, v: 0x7c0b5a14); // add r0,r11,r11 |
143 | if (ha(v: got + 4) == ha(v: got + 8)) |
144 | write32(ctx, p: buf + 24, v: 0x818c0000 | lo(v: got + 8)); // lwz r12,GOT+8@l(r12) |
145 | else |
146 | write32(ctx, p: buf + 24, v: 0x818c0000 | 4); // lwz r12,4(r12) |
147 | write32(ctx, p: buf + 28, v: 0x7d605a14); // add r11,r0,r11 |
148 | write32(ctx, p: buf + 32, v: 0x4e800420); // bctr |
149 | buf += 36; |
150 | } |
151 | |
152 | // Pad with nop. They should not be executed. |
153 | for (; buf < end; buf += 4) |
154 | write32(ctx, p: buf, v: 0x60000000); |
155 | } |
156 | |
157 | PPC::PPC(Ctx &ctx) : TargetInfo(ctx) { |
158 | copyRel = R_PPC_COPY; |
159 | gotRel = R_PPC_GLOB_DAT; |
160 | pltRel = R_PPC_JMP_SLOT; |
161 | relativeRel = R_PPC_RELATIVE; |
162 | iRelativeRel = R_PPC_IRELATIVE; |
163 | symbolicRel = R_PPC_ADDR32; |
164 | gotHeaderEntriesNum = 3; |
165 | gotPltHeaderEntriesNum = 0; |
166 | pltHeaderSize = 0; |
167 | pltEntrySize = 4; |
168 | ipltEntrySize = 16; |
169 | |
170 | needsThunks = true; |
171 | |
172 | tlsModuleIndexRel = R_PPC_DTPMOD32; |
173 | tlsOffsetRel = R_PPC_DTPREL32; |
174 | tlsGotRel = R_PPC_TPREL32; |
175 | |
176 | defaultMaxPageSize = 65536; |
177 | defaultImageBase = 0x10000000; |
178 | |
179 | write32(ctx, p: trapInstr.data(), v: 0x7fe00008); |
180 | } |
181 | |
182 | void PPC::writeIplt(uint8_t *buf, const Symbol &sym, |
183 | uint64_t /*pltEntryAddr*/) const { |
184 | // In -pie or -shared mode, assume r30 points to .got2+0x8000, and use a |
185 | // .got2.plt_pic32. thunk. |
186 | writePPC32PltCallStub(ctx, buf, gotPltVA: sym.getGotPltVA(ctx), file: sym.file, addend: 0x8000); |
187 | } |
188 | |
189 | void PPC::(uint8_t *buf) const { |
190 | // _GLOBAL_OFFSET_TABLE_[0] = _DYNAMIC |
191 | // glibc stores _dl_runtime_resolve in _GLOBAL_OFFSET_TABLE_[1], |
192 | // link_map in _GLOBAL_OFFSET_TABLE_[2]. |
193 | write32(ctx, p: buf, v: ctx.mainPart->dynamic->getVA()); |
194 | } |
195 | |
196 | void PPC::writeGotPlt(uint8_t *buf, const Symbol &s) const { |
197 | // Address of the symbol resolver stub in .glink . |
198 | write32(ctx, p: buf, |
199 | v: ctx.in.plt->getVA() + ctx.in.plt->headerSize + 4 * s.getPltIdx(ctx)); |
200 | } |
201 | |
202 | bool PPC::needsThunk(RelExpr expr, RelType type, const InputFile *file, |
203 | uint64_t branchAddr, const Symbol &s, int64_t a) const { |
204 | if (type != R_PPC_LOCAL24PC && type != R_PPC_REL24 && type != R_PPC_PLTREL24) |
205 | return false; |
206 | if (s.isInPlt(ctx)) |
207 | return true; |
208 | if (s.isUndefWeak()) |
209 | return false; |
210 | return !PPC::inBranchRange(type, src: branchAddr, dst: s.getVA(ctx, addend: a)); |
211 | } |
212 | |
213 | uint32_t PPC::getThunkSectionSpacing() const { return 0x2000000; } |
214 | |
215 | bool PPC::inBranchRange(RelType type, uint64_t src, uint64_t dst) const { |
216 | uint64_t offset = dst - src; |
217 | if (type == R_PPC_LOCAL24PC || type == R_PPC_REL24 || type == R_PPC_PLTREL24) |
218 | return isInt<26>(x: offset); |
219 | llvm_unreachable("unsupported relocation type used in branch" ); |
220 | } |
221 | |
222 | RelExpr PPC::getRelExpr(RelType type, const Symbol &s, |
223 | const uint8_t *loc) const { |
224 | switch (type) { |
225 | case R_PPC_NONE: |
226 | return R_NONE; |
227 | case R_PPC_ADDR16_HA: |
228 | case R_PPC_ADDR16_HI: |
229 | case R_PPC_ADDR16_LO: |
230 | case R_PPC_ADDR24: |
231 | case R_PPC_ADDR32: |
232 | return R_ABS; |
233 | case R_PPC_DTPREL16: |
234 | case R_PPC_DTPREL16_HA: |
235 | case R_PPC_DTPREL16_HI: |
236 | case R_PPC_DTPREL16_LO: |
237 | case R_PPC_DTPREL32: |
238 | return R_DTPREL; |
239 | case R_PPC_REL14: |
240 | case R_PPC_REL32: |
241 | case R_PPC_REL16_LO: |
242 | case R_PPC_REL16_HI: |
243 | case R_PPC_REL16_HA: |
244 | return R_PC; |
245 | case R_PPC_GOT16: |
246 | return R_GOT_OFF; |
247 | case R_PPC_LOCAL24PC: |
248 | case R_PPC_REL24: |
249 | return R_PLT_PC; |
250 | case R_PPC_PLTREL24: |
251 | return RE_PPC32_PLTREL; |
252 | case R_PPC_GOT_TLSGD16: |
253 | return R_TLSGD_GOT; |
254 | case R_PPC_GOT_TLSLD16: |
255 | return R_TLSLD_GOT; |
256 | case R_PPC_GOT_TPREL16: |
257 | return R_GOT_OFF; |
258 | case R_PPC_TLS: |
259 | return R_TLSIE_HINT; |
260 | case R_PPC_TLSGD: |
261 | return R_TLSDESC_CALL; |
262 | case R_PPC_TLSLD: |
263 | return R_TLSLD_HINT; |
264 | case R_PPC_TPREL16: |
265 | case R_PPC_TPREL16_HA: |
266 | case R_PPC_TPREL16_LO: |
267 | case R_PPC_TPREL16_HI: |
268 | return R_TPREL; |
269 | default: |
270 | Err(ctx) << getErrorLoc(ctx, loc) << "unknown relocation (" << type.v |
271 | << ") against symbol " << &s; |
272 | return R_NONE; |
273 | } |
274 | } |
275 | |
276 | RelType PPC::getDynRel(RelType type) const { |
277 | if (type == R_PPC_ADDR32) |
278 | return type; |
279 | return R_PPC_NONE; |
280 | } |
281 | |
282 | int64_t PPC::getImplicitAddend(const uint8_t *buf, RelType type) const { |
283 | switch (type) { |
284 | case R_PPC_NONE: |
285 | case R_PPC_GLOB_DAT: |
286 | case R_PPC_JMP_SLOT: |
287 | return 0; |
288 | case R_PPC_ADDR32: |
289 | case R_PPC_REL32: |
290 | case R_PPC_RELATIVE: |
291 | case R_PPC_IRELATIVE: |
292 | case R_PPC_DTPMOD32: |
293 | case R_PPC_DTPREL32: |
294 | case R_PPC_TPREL32: |
295 | return SignExtend64<32>(x: read32(ctx, p: buf)); |
296 | default: |
297 | InternalErr(ctx, buf) << "cannot read addend for relocation " << type; |
298 | return 0; |
299 | } |
300 | } |
301 | |
302 | static std::pair<RelType, uint64_t> fromDTPREL(RelType type, uint64_t val) { |
303 | uint64_t dtpBiasedVal = val - 0x8000; |
304 | switch (type) { |
305 | case R_PPC_DTPREL16: |
306 | return {R_PPC64_ADDR16, dtpBiasedVal}; |
307 | case R_PPC_DTPREL16_HA: |
308 | return {R_PPC_ADDR16_HA, dtpBiasedVal}; |
309 | case R_PPC_DTPREL16_HI: |
310 | return {R_PPC_ADDR16_HI, dtpBiasedVal}; |
311 | case R_PPC_DTPREL16_LO: |
312 | return {R_PPC_ADDR16_LO, dtpBiasedVal}; |
313 | case R_PPC_DTPREL32: |
314 | return {R_PPC_ADDR32, dtpBiasedVal}; |
315 | default: |
316 | return {type, val}; |
317 | } |
318 | } |
319 | |
320 | void PPC::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const { |
321 | RelType newType; |
322 | std::tie(args&: newType, args&: val) = fromDTPREL(type: rel.type, val); |
323 | switch (newType) { |
324 | case R_PPC_ADDR16: |
325 | checkIntUInt(ctx, loc, v: val, n: 16, rel); |
326 | write16(ctx, p: loc, v: val); |
327 | break; |
328 | case R_PPC_GOT16: |
329 | case R_PPC_GOT_TLSGD16: |
330 | case R_PPC_GOT_TLSLD16: |
331 | case R_PPC_GOT_TPREL16: |
332 | case R_PPC_TPREL16: |
333 | checkInt(ctx, loc, v: val, n: 16, rel); |
334 | write16(ctx, p: loc, v: val); |
335 | break; |
336 | case R_PPC_ADDR16_HA: |
337 | case R_PPC_DTPREL16_HA: |
338 | case R_PPC_GOT_TLSGD16_HA: |
339 | case R_PPC_GOT_TLSLD16_HA: |
340 | case R_PPC_GOT_TPREL16_HA: |
341 | case R_PPC_REL16_HA: |
342 | case R_PPC_TPREL16_HA: |
343 | write16(ctx, p: loc, v: ha(v: val)); |
344 | break; |
345 | case R_PPC_ADDR16_HI: |
346 | case R_PPC_DTPREL16_HI: |
347 | case R_PPC_GOT_TLSGD16_HI: |
348 | case R_PPC_GOT_TLSLD16_HI: |
349 | case R_PPC_GOT_TPREL16_HI: |
350 | case R_PPC_REL16_HI: |
351 | case R_PPC_TPREL16_HI: |
352 | write16(ctx, p: loc, v: val >> 16); |
353 | break; |
354 | case R_PPC_ADDR16_LO: |
355 | case R_PPC_DTPREL16_LO: |
356 | case R_PPC_GOT_TLSGD16_LO: |
357 | case R_PPC_GOT_TLSLD16_LO: |
358 | case R_PPC_GOT_TPREL16_LO: |
359 | case R_PPC_REL16_LO: |
360 | case R_PPC_TPREL16_LO: |
361 | write16(ctx, p: loc, v: val); |
362 | break; |
363 | case R_PPC_ADDR32: |
364 | case R_PPC_REL32: |
365 | write32(ctx, p: loc, v: val); |
366 | break; |
367 | case R_PPC_REL14: { |
368 | uint32_t mask = 0x0000FFFC; |
369 | checkInt(ctx, loc, v: val, n: 16, rel); |
370 | checkAlignment(ctx, loc, v: val, n: 4, rel); |
371 | write32(ctx, p: loc, v: (read32(ctx, p: loc) & ~mask) | (val & mask)); |
372 | break; |
373 | } |
374 | case R_PPC_ADDR24: |
375 | case R_PPC_REL24: |
376 | case R_PPC_LOCAL24PC: |
377 | case R_PPC_PLTREL24: { |
378 | uint32_t mask = 0x03FFFFFC; |
379 | checkInt(ctx, loc, v: val, n: 26, rel); |
380 | checkAlignment(ctx, loc, v: val, n: 4, rel); |
381 | write32(ctx, p: loc, v: (read32(ctx, p: loc) & ~mask) | (val & mask)); |
382 | break; |
383 | } |
384 | default: |
385 | llvm_unreachable("unknown relocation" ); |
386 | } |
387 | } |
388 | |
389 | RelExpr PPC::adjustTlsExpr(RelType type, RelExpr expr) const { |
390 | if (expr == R_RELAX_TLS_GD_TO_IE) |
391 | return R_RELAX_TLS_GD_TO_IE_GOT_OFF; |
392 | if (expr == R_RELAX_TLS_LD_TO_LE) |
393 | return R_RELAX_TLS_LD_TO_LE_ABS; |
394 | return expr; |
395 | } |
396 | |
397 | int PPC::getTlsGdRelaxSkip(RelType type) const { |
398 | // A __tls_get_addr call instruction is marked with 2 relocations: |
399 | // |
400 | // R_PPC_TLSGD / R_PPC_TLSLD: marker relocation |
401 | // R_PPC_REL24: __tls_get_addr |
402 | // |
403 | // After the relaxation we no longer call __tls_get_addr and should skip both |
404 | // relocations to not create a false dependence on __tls_get_addr being |
405 | // defined. |
406 | if (type == R_PPC_TLSGD || type == R_PPC_TLSLD) |
407 | return 2; |
408 | return 1; |
409 | } |
410 | |
411 | void PPC::relaxTlsGdToIe(uint8_t *loc, const Relocation &rel, |
412 | uint64_t val) const { |
413 | switch (rel.type) { |
414 | case R_PPC_GOT_TLSGD16: { |
415 | // addi rT, rA, x@got@tlsgd --> lwz rT, x@got@tprel(rA) |
416 | uint32_t insn = readFromHalf16(ctx, loc); |
417 | writeFromHalf16(ctx, loc, insn: 0x80000000 | (insn & 0x03ff0000)); |
418 | relocateNoSym(loc, type: R_PPC_GOT_TPREL16, val); |
419 | break; |
420 | } |
421 | case R_PPC_TLSGD: |
422 | // bl __tls_get_addr(x@tldgd) --> add r3, r3, r2 |
423 | write32(ctx, p: loc, v: 0x7c631214); |
424 | break; |
425 | default: |
426 | llvm_unreachable("unsupported relocation for TLS GD to IE relaxation" ); |
427 | } |
428 | } |
429 | |
430 | void PPC::relaxTlsGdToLe(uint8_t *loc, const Relocation &rel, |
431 | uint64_t val) const { |
432 | switch (rel.type) { |
433 | case R_PPC_GOT_TLSGD16: |
434 | // addi r3, r31, x@got@tlsgd --> addis r3, r2, x@tprel@ha |
435 | writeFromHalf16(ctx, loc, insn: 0x3c620000 | ha(v: val)); |
436 | break; |
437 | case R_PPC_TLSGD: |
438 | // bl __tls_get_addr(x@tldgd) --> add r3, r3, x@tprel@l |
439 | write32(ctx, p: loc, v: 0x38630000 | lo(v: val)); |
440 | break; |
441 | default: |
442 | llvm_unreachable("unsupported relocation for TLS GD to LE relaxation" ); |
443 | } |
444 | } |
445 | |
446 | void PPC::relaxTlsLdToLe(uint8_t *loc, const Relocation &rel, |
447 | uint64_t val) const { |
448 | switch (rel.type) { |
449 | case R_PPC_GOT_TLSLD16: |
450 | // addi r3, rA, x@got@tlsgd --> addis r3, r2, 0 |
451 | writeFromHalf16(ctx, loc, insn: 0x3c620000); |
452 | break; |
453 | case R_PPC_TLSLD: |
454 | // r3+x@dtprel computes r3+x-0x8000, while we want it to compute r3+x@tprel |
455 | // = r3+x-0x7000, so add 4096 to r3. |
456 | // bl __tls_get_addr(x@tlsld) --> addi r3, r3, 4096 |
457 | write32(ctx, p: loc, v: 0x38631000); |
458 | break; |
459 | case R_PPC_DTPREL16: |
460 | case R_PPC_DTPREL16_HA: |
461 | case R_PPC_DTPREL16_HI: |
462 | case R_PPC_DTPREL16_LO: |
463 | relocate(loc, rel, val); |
464 | break; |
465 | default: |
466 | llvm_unreachable("unsupported relocation for TLS LD to LE relaxation" ); |
467 | } |
468 | } |
469 | |
470 | void PPC::relaxTlsIeToLe(uint8_t *loc, const Relocation &rel, |
471 | uint64_t val) const { |
472 | switch (rel.type) { |
473 | case R_PPC_GOT_TPREL16: { |
474 | // lwz rT, x@got@tprel(rA) --> addis rT, r2, x@tprel@ha |
475 | uint32_t rt = readFromHalf16(ctx, loc) & 0x03e00000; |
476 | writeFromHalf16(ctx, loc, insn: 0x3c020000 | rt | ha(v: val)); |
477 | break; |
478 | } |
479 | case R_PPC_TLS: { |
480 | uint32_t insn = read32(ctx, p: loc); |
481 | if (insn >> 26 != 31) |
482 | ErrAlways(ctx) << "unrecognized instruction for IE to LE R_PPC_TLS" ; |
483 | // addi rT, rT, x@tls --> addi rT, rT, x@tprel@l |
484 | unsigned secondaryOp = (read32(ctx, p: loc) & 0x000007fe) >> 1; |
485 | uint32_t dFormOp = getPPCDFormOp(secondaryOp); |
486 | if (dFormOp == 0) { // Expecting a DS-Form instruction. |
487 | dFormOp = getPPCDSFormOp(secondaryOp); |
488 | if (dFormOp == 0) |
489 | ErrAlways(ctx) << "unrecognized instruction for IE to LE R_PPC_TLS" ; |
490 | } |
491 | write32(ctx, p: loc, v: (dFormOp | (insn & 0x03ff0000) | lo(v: val))); |
492 | break; |
493 | } |
494 | default: |
495 | llvm_unreachable("unsupported relocation for TLS IE to LE relaxation" ); |
496 | } |
497 | } |
498 | |
499 | void PPC::relocateAlloc(InputSectionBase &sec, uint8_t *buf) const { |
500 | uint64_t secAddr = sec.getOutputSection()->addr; |
501 | if (auto *s = dyn_cast<InputSection>(Val: &sec)) |
502 | secAddr += s->outSecOff; |
503 | for (const Relocation &rel : sec.relocs()) { |
504 | uint8_t *loc = buf + rel.offset; |
505 | const uint64_t val = |
506 | SignExtend64(X: sec.getRelocTargetVA(ctx, r: rel, p: secAddr + rel.offset), B: 32); |
507 | switch (rel.expr) { |
508 | case R_RELAX_TLS_GD_TO_IE_GOT_OFF: |
509 | relaxTlsGdToIe(loc, rel, val); |
510 | break; |
511 | case R_RELAX_TLS_GD_TO_LE: |
512 | relaxTlsGdToLe(loc, rel, val); |
513 | break; |
514 | case R_RELAX_TLS_LD_TO_LE_ABS: |
515 | relaxTlsLdToLe(loc, rel, val); |
516 | break; |
517 | case R_RELAX_TLS_IE_TO_LE: |
518 | relaxTlsIeToLe(loc, rel, val); |
519 | break; |
520 | default: |
521 | relocate(loc, rel, val); |
522 | break; |
523 | } |
524 | } |
525 | } |
526 | |
527 | void elf::setPPCTargetInfo(Ctx &ctx) { ctx.target.reset(p: new PPC(ctx)); } |
528 | |