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