1 | //===- SystemZ.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 "lld/Common/ErrorHandler.h" |
14 | #include "llvm/BinaryFormat/ELF.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 | namespace { |
24 | class SystemZ : public TargetInfo { |
25 | public: |
26 | SystemZ(); |
27 | int getTlsGdRelaxSkip(RelType type) const override; |
28 | RelExpr getRelExpr(RelType type, const Symbol &s, |
29 | const uint8_t *loc) const override; |
30 | RelType getDynRel(RelType type) const override; |
31 | void writeGotHeader(uint8_t *buf) const override; |
32 | void writeGotPlt(uint8_t *buf, const Symbol &s) const override; |
33 | void writeIgotPlt(uint8_t *buf, const Symbol &s) const override; |
34 | void writePltHeader(uint8_t *buf) const override; |
35 | void addPltHeaderSymbols(InputSection &isd) const override; |
36 | void writePlt(uint8_t *buf, const Symbol &sym, |
37 | uint64_t pltEntryAddr) const override; |
38 | RelExpr adjustTlsExpr(RelType type, RelExpr expr) const override; |
39 | RelExpr adjustGotPcExpr(RelType type, int64_t addend, |
40 | const uint8_t *loc) const override; |
41 | bool relaxOnce(int pass) const override; |
42 | void relocate(uint8_t *loc, const Relocation &rel, |
43 | uint64_t val) const override; |
44 | int64_t getImplicitAddend(const uint8_t *buf, RelType type) const override; |
45 | |
46 | private: |
47 | void relaxGot(uint8_t *loc, const Relocation &rel, uint64_t val) const; |
48 | void relaxTlsGdToIe(uint8_t *loc, const Relocation &rel, uint64_t val) const; |
49 | void relaxTlsGdToLe(uint8_t *loc, const Relocation &rel, uint64_t val) const; |
50 | void relaxTlsLdToLe(uint8_t *loc, const Relocation &rel, uint64_t val) const; |
51 | }; |
52 | } // namespace |
53 | |
54 | SystemZ::SystemZ() { |
55 | copyRel = R_390_COPY; |
56 | gotRel = R_390_GLOB_DAT; |
57 | pltRel = R_390_JMP_SLOT; |
58 | relativeRel = R_390_RELATIVE; |
59 | iRelativeRel = R_390_IRELATIVE; |
60 | symbolicRel = R_390_64; |
61 | tlsGotRel = R_390_TLS_TPOFF; |
62 | tlsModuleIndexRel = R_390_TLS_DTPMOD; |
63 | tlsOffsetRel = R_390_TLS_DTPOFF; |
64 | gotHeaderEntriesNum = 3; |
65 | gotPltHeaderEntriesNum = 0; |
66 | gotEntrySize = 8; |
67 | pltHeaderSize = 32; |
68 | pltEntrySize = 32; |
69 | ipltEntrySize = 32; |
70 | |
71 | // This "trap instruction" is used to fill gaps between sections. |
72 | // On SystemZ, the behavior of the GNU ld is to fill those gaps |
73 | // with nop instructions instead - and unfortunately the default |
74 | // glibc crt object files (used to) rely on that behavior since |
75 | // they use an alignment on the .init section fragments that causes |
76 | // gaps which must be filled with nops as they are being executed. |
77 | // Therefore, we provide a nop instruction as "trapInstr" here. |
78 | trapInstr = {0x07, 0x07, 0x07, 0x07}; |
79 | |
80 | defaultImageBase = 0x1000000; |
81 | } |
82 | |
83 | RelExpr SystemZ::getRelExpr(RelType type, const Symbol &s, |
84 | const uint8_t *loc) const { |
85 | switch (type) { |
86 | case R_390_NONE: |
87 | return R_NONE; |
88 | // Relocations targeting the symbol value. |
89 | case R_390_8: |
90 | case R_390_12: |
91 | case R_390_16: |
92 | case R_390_20: |
93 | case R_390_32: |
94 | case R_390_64: |
95 | return R_ABS; |
96 | case R_390_PC16: |
97 | case R_390_PC32: |
98 | case R_390_PC64: |
99 | case R_390_PC12DBL: |
100 | case R_390_PC16DBL: |
101 | case R_390_PC24DBL: |
102 | case R_390_PC32DBL: |
103 | return R_PC; |
104 | case R_390_GOTOFF16: |
105 | case R_390_GOTOFF: // a.k.a. R_390_GOTOFF32 |
106 | case R_390_GOTOFF64: |
107 | return R_GOTREL; |
108 | // Relocations targeting the PLT associated with the symbol. |
109 | case R_390_PLT32: |
110 | case R_390_PLT64: |
111 | case R_390_PLT12DBL: |
112 | case R_390_PLT16DBL: |
113 | case R_390_PLT24DBL: |
114 | case R_390_PLT32DBL: |
115 | return R_PLT_PC; |
116 | case R_390_PLTOFF16: |
117 | case R_390_PLTOFF32: |
118 | case R_390_PLTOFF64: |
119 | return R_PLT_GOTREL; |
120 | // Relocations targeting the GOT entry associated with the symbol. |
121 | case R_390_GOTENT: |
122 | return R_GOT_PC; |
123 | case R_390_GOT12: |
124 | case R_390_GOT16: |
125 | case R_390_GOT20: |
126 | case R_390_GOT32: |
127 | case R_390_GOT64: |
128 | return R_GOT_OFF; |
129 | // Relocations targeting the GOTPLT entry associated with the symbol. |
130 | case R_390_GOTPLTENT: |
131 | return R_GOTPLT_PC; |
132 | case R_390_GOTPLT12: |
133 | case R_390_GOTPLT16: |
134 | case R_390_GOTPLT20: |
135 | case R_390_GOTPLT32: |
136 | case R_390_GOTPLT64: |
137 | return R_GOTPLT_GOTREL; |
138 | // Relocations targeting _GLOBAL_OFFSET_TABLE_. |
139 | case R_390_GOTPC: |
140 | case R_390_GOTPCDBL: |
141 | return R_GOTONLY_PC; |
142 | // TLS-related relocations. |
143 | case R_390_TLS_LOAD: |
144 | return R_NONE; |
145 | case R_390_TLS_GDCALL: |
146 | return R_TLSGD_PC; |
147 | case R_390_TLS_LDCALL: |
148 | return R_TLSLD_PC; |
149 | case R_390_TLS_GD32: |
150 | case R_390_TLS_GD64: |
151 | return R_TLSGD_GOT; |
152 | case R_390_TLS_LDM32: |
153 | case R_390_TLS_LDM64: |
154 | return R_TLSLD_GOT; |
155 | case R_390_TLS_LDO32: |
156 | case R_390_TLS_LDO64: |
157 | return R_DTPREL; |
158 | case R_390_TLS_LE32: |
159 | case R_390_TLS_LE64: |
160 | return R_TPREL; |
161 | case R_390_TLS_IE32: |
162 | case R_390_TLS_IE64: |
163 | return R_GOT; |
164 | case R_390_TLS_GOTIE12: |
165 | case R_390_TLS_GOTIE20: |
166 | case R_390_TLS_GOTIE32: |
167 | case R_390_TLS_GOTIE64: |
168 | return R_GOT_OFF; |
169 | case R_390_TLS_IEENT: |
170 | return R_GOT_PC; |
171 | |
172 | default: |
173 | error(msg: getErrorLocation(loc) + "unknown relocation (" + Twine(type) + |
174 | ") against symbol " + toString(s)); |
175 | return R_NONE; |
176 | } |
177 | } |
178 | |
179 | void SystemZ::(uint8_t *buf) const { |
180 | // _GLOBAL_OFFSET_TABLE_[0] holds the value of _DYNAMIC. |
181 | // _GLOBAL_OFFSET_TABLE_[1] and [2] are reserved. |
182 | write64be(P: buf, V: mainPart->dynamic->getVA()); |
183 | } |
184 | |
185 | void SystemZ::writeGotPlt(uint8_t *buf, const Symbol &s) const { |
186 | write64be(P: buf, V: s.getPltVA() + 14); |
187 | } |
188 | |
189 | void SystemZ::writeIgotPlt(uint8_t *buf, const Symbol &s) const { |
190 | if (config->writeAddends) |
191 | write64be(P: buf, V: s.getVA()); |
192 | } |
193 | |
194 | void SystemZ::(uint8_t *buf) const { |
195 | const uint8_t pltData[] = { |
196 | 0xe3, 0x10, 0xf0, 0x38, 0x00, 0x24, // stg %r1,56(%r15) |
197 | 0xc0, 0x10, 0x00, 0x00, 0x00, 0x00, // larl %r1,_GLOBAL_OFFSET_TABLE_ |
198 | 0xd2, 0x07, 0xf0, 0x30, 0x10, 0x08, // mvc 48(8,%r15),8(%r1) |
199 | 0xe3, 0x10, 0x10, 0x10, 0x00, 0x04, // lg %r1,16(%r1) |
200 | 0x07, 0xf1, // br %r1 |
201 | 0x07, 0x00, // nopr |
202 | 0x07, 0x00, // nopr |
203 | 0x07, 0x00, // nopr |
204 | }; |
205 | memcpy(dest: buf, src: pltData, n: sizeof(pltData)); |
206 | uint64_t got = in.got->getVA(); |
207 | uint64_t plt = in.plt->getVA(); |
208 | write32be(P: buf + 8, V: (got - plt - 6) >> 1); |
209 | } |
210 | |
211 | void SystemZ::(InputSection &isec) const { |
212 | // The PLT header needs a reference to _GLOBAL_OFFSET_TABLE_, so we |
213 | // must ensure the .got section is created even if otherwise unused. |
214 | in.got->hasGotOffRel.store(i: true, m: std::memory_order_relaxed); |
215 | } |
216 | |
217 | void SystemZ::writePlt(uint8_t *buf, const Symbol &sym, |
218 | uint64_t pltEntryAddr) const { |
219 | const uint8_t inst[] = { |
220 | 0xc0, 0x10, 0x00, 0x00, 0x00, 0x00, // larl %r1,<.got.plt slot> |
221 | 0xe3, 0x10, 0x10, 0x00, 0x00, 0x04, // lg %r1,0(%r1) |
222 | 0x07, 0xf1, // br %r1 |
223 | 0x0d, 0x10, // basr %r1,%r0 |
224 | 0xe3, 0x10, 0x10, 0x0c, 0x00, 0x14, // lgf %r1,12(%r1) |
225 | 0xc0, 0xf4, 0x00, 0x00, 0x00, 0x00, // jg <plt header> |
226 | 0x00, 0x00, 0x00, 0x00, // <relocation offset> |
227 | }; |
228 | memcpy(dest: buf, src: inst, n: sizeof(inst)); |
229 | |
230 | write32be(P: buf + 2, V: (sym.getGotPltVA() - pltEntryAddr) >> 1); |
231 | write32be(P: buf + 24, V: (in.plt->getVA() - pltEntryAddr - 22) >> 1); |
232 | write32be(P: buf + 28, V: in.relaPlt->entsize * sym.getPltIdx()); |
233 | } |
234 | |
235 | int64_t SystemZ::getImplicitAddend(const uint8_t *buf, RelType type) const { |
236 | switch (type) { |
237 | case R_390_8: |
238 | return SignExtend64<8>(x: *buf); |
239 | case R_390_16: |
240 | case R_390_PC16: |
241 | return SignExtend64<16>(x: read16be(P: buf)); |
242 | case R_390_PC16DBL: |
243 | return SignExtend64<16>(x: read16be(P: buf)) << 1; |
244 | case R_390_32: |
245 | case R_390_PC32: |
246 | return SignExtend64<32>(x: read32be(P: buf)); |
247 | case R_390_PC32DBL: |
248 | return SignExtend64<32>(x: read32be(P: buf)) << 1; |
249 | case R_390_64: |
250 | case R_390_PC64: |
251 | case R_390_TLS_DTPMOD: |
252 | case R_390_TLS_DTPOFF: |
253 | case R_390_TLS_TPOFF: |
254 | case R_390_GLOB_DAT: |
255 | case R_390_RELATIVE: |
256 | case R_390_IRELATIVE: |
257 | return read64be(P: buf); |
258 | case R_390_COPY: |
259 | case R_390_JMP_SLOT: |
260 | case R_390_NONE: |
261 | // These relocations are defined as not having an implicit addend. |
262 | return 0; |
263 | default: |
264 | internalLinkerError(loc: getErrorLocation(loc: buf), |
265 | msg: "cannot read addend for relocation " + toString(type)); |
266 | return 0; |
267 | } |
268 | } |
269 | |
270 | RelType SystemZ::getDynRel(RelType type) const { |
271 | if (type == R_390_64 || type == R_390_PC64) |
272 | return type; |
273 | return R_390_NONE; |
274 | } |
275 | |
276 | RelExpr SystemZ::adjustTlsExpr(RelType type, RelExpr expr) const { |
277 | if (expr == R_RELAX_TLS_GD_TO_IE) |
278 | return R_RELAX_TLS_GD_TO_IE_GOT_OFF; |
279 | return expr; |
280 | } |
281 | |
282 | int SystemZ::getTlsGdRelaxSkip(RelType type) const { |
283 | // A __tls_get_offset call instruction is marked with 2 relocations: |
284 | // |
285 | // R_390_TLS_GDCALL / R_390_TLS_LDCALL: marker relocation |
286 | // R_390_PLT32DBL: __tls_get_offset |
287 | // |
288 | // After the relaxation we no longer call __tls_get_offset and should skip |
289 | // both relocations to not create a false dependence on __tls_get_offset |
290 | // being defined. |
291 | // |
292 | // Note that this mechanism only works correctly if the R_390_TLS_[GL]DCALL |
293 | // is seen immediately *before* the R_390_PLT32DBL. Unfortunately, current |
294 | // compilers on the platform will typically generate the inverse sequence. |
295 | // To fix this, we sort relocations by offset in RelocationScanner::scan; |
296 | // this ensures the correct sequence as the R_390_TLS_[GL]DCALL applies to |
297 | // the first byte of the brasl instruction, while the R_390_PLT32DBL applies |
298 | // to its third byte (the relative displacement). |
299 | |
300 | if (type == R_390_TLS_GDCALL || type == R_390_TLS_LDCALL) |
301 | return 2; |
302 | return 1; |
303 | } |
304 | |
305 | void SystemZ::relaxTlsGdToIe(uint8_t *loc, const Relocation &rel, |
306 | uint64_t val) const { |
307 | // The general-dynamic code sequence for a global `x`: |
308 | // |
309 | // Instruction Relocation Symbol |
310 | // ear %rX,%a0 |
311 | // sllg %rX,%rX,32 |
312 | // ear %rX,%a1 |
313 | // larl %r12,_GLOBAL_OFFSET_TABLE_ R_390_GOTPCDBL _GLOBAL_OFFSET_TABLE_ |
314 | // lgrl %r2,.LC0 R_390_PC32DBL .LC0 |
315 | // brasl %r14,__tls_get_offset@plt R_390_TLS_GDCALL x |
316 | // :tls_gdcall:x R_390_PLT32DBL __tls_get_offset |
317 | // la %r2,0(%r2,%rX) |
318 | // |
319 | // .LC0: |
320 | // .quad x@TLSGD R_390_TLS_GD64 x |
321 | // |
322 | // Relaxing to initial-exec entails: |
323 | // 1) Replacing the call by a load from the GOT. |
324 | // 2) Replacing the relocation on the constant LC0 by R_390_TLS_GOTIE64. |
325 | |
326 | switch (rel.type) { |
327 | case R_390_TLS_GDCALL: |
328 | // brasl %r14,__tls_get_offset@plt -> lg %r2,0(%r2,%r12) |
329 | write16be(P: loc, V: 0xe322); |
330 | write32be(P: loc + 2, V: 0xc0000004); |
331 | break; |
332 | case R_390_TLS_GD64: |
333 | relocateNoSym(loc, type: R_390_TLS_GOTIE64, val); |
334 | break; |
335 | default: |
336 | llvm_unreachable("unsupported relocation for TLS GD to IE relaxation" ); |
337 | } |
338 | } |
339 | |
340 | void SystemZ::relaxTlsGdToLe(uint8_t *loc, const Relocation &rel, |
341 | uint64_t val) const { |
342 | // The general-dynamic code sequence for a global `x`: |
343 | // |
344 | // Instruction Relocation Symbol |
345 | // ear %rX,%a0 |
346 | // sllg %rX,%rX,32 |
347 | // ear %rX,%a1 |
348 | // larl %r12,_GLOBAL_OFFSET_TABLE_ R_390_GOTPCDBL _GLOBAL_OFFSET_TABLE_ |
349 | // lgrl %r2,.LC0 R_390_PC32DBL .LC0 |
350 | // brasl %r14,__tls_get_offset@plt R_390_TLS_GDCALL x |
351 | // :tls_gdcall:x R_390_PLT32DBL __tls_get_offset |
352 | // la %r2,0(%r2,%rX) |
353 | // |
354 | // .LC0: |
355 | // .quad x@tlsgd R_390_TLS_GD64 x |
356 | // |
357 | // Relaxing to local-exec entails: |
358 | // 1) Replacing the call by a nop. |
359 | // 2) Replacing the relocation on the constant LC0 by R_390_TLS_LE64. |
360 | |
361 | switch (rel.type) { |
362 | case R_390_TLS_GDCALL: |
363 | // brasl %r14,__tls_get_offset@plt -> brcl 0,. |
364 | write16be(P: loc, V: 0xc004); |
365 | write32be(P: loc + 2, V: 0x00000000); |
366 | break; |
367 | case R_390_TLS_GD64: |
368 | relocateNoSym(loc, type: R_390_TLS_LE64, val); |
369 | break; |
370 | default: |
371 | llvm_unreachable("unsupported relocation for TLS GD to LE relaxation" ); |
372 | } |
373 | } |
374 | |
375 | void SystemZ::relaxTlsLdToLe(uint8_t *loc, const Relocation &rel, |
376 | uint64_t val) const { |
377 | // The local-dynamic code sequence for a global `x`: |
378 | // |
379 | // Instruction Relocation Symbol |
380 | // ear %rX,%a0 |
381 | // sllg %rX,%rX,32 |
382 | // ear %rX,%a1 |
383 | // larl %r12,_GLOBAL_OFFSET_TABLE_ R_390_GOTPCDBL _GLOBAL_OFFSET_TABLE_ |
384 | // lgrl %r2,.LC0 R_390_PC32DBL .LC0 |
385 | // brasl %r14,__tls_get_offset@plt R_390_TLS_LDCALL <sym> |
386 | // :tls_ldcall:<sym> R_390_PLT32DBL __tls_get_offset |
387 | // la %r2,0(%r2,%rX) |
388 | // lgrl %rY,.LC1 R_390_PC32DBL .LC1 |
389 | // la %r2,0(%r2,%rY) |
390 | // |
391 | // .LC0: |
392 | // .quad <sym>@tlsldm R_390_TLS_LDM64 <sym> |
393 | // .LC1: |
394 | // .quad x@dtpoff R_390_TLS_LDO64 x |
395 | // |
396 | // Relaxing to local-exec entails: |
397 | // 1) Replacing the call by a nop. |
398 | // 2) Replacing the constant LC0 by 0 (i.e. ignoring the relocation). |
399 | // 3) Replacing the relocation on the constant LC1 by R_390_TLS_LE64. |
400 | |
401 | switch (rel.type) { |
402 | case R_390_TLS_LDCALL: |
403 | // brasl %r14,__tls_get_offset@plt -> brcl 0,. |
404 | write16be(P: loc, V: 0xc004); |
405 | write32be(P: loc + 2, V: 0x00000000); |
406 | break; |
407 | case R_390_TLS_LDM64: |
408 | break; |
409 | case R_390_TLS_LDO64: |
410 | relocateNoSym(loc, type: R_390_TLS_LE64, val); |
411 | break; |
412 | default: |
413 | llvm_unreachable("unsupported relocation for TLS LD to LE relaxation" ); |
414 | } |
415 | } |
416 | |
417 | RelExpr SystemZ::adjustGotPcExpr(RelType type, int64_t addend, |
418 | const uint8_t *loc) const { |
419 | // Only R_390_GOTENT with addend 2 can be relaxed. |
420 | if (!config->relax || addend != 2 || type != R_390_GOTENT) |
421 | return R_GOT_PC; |
422 | const uint16_t op = read16be(P: loc - 2); |
423 | |
424 | // lgrl rx,sym@GOTENT -> larl rx, sym |
425 | // This relaxation is legal if "sym" binds locally (which was already |
426 | // verified by our caller) and is in-range and properly aligned for a |
427 | // LARL instruction. We cannot verify the latter constraint here, so |
428 | // we assume it is true and revert the decision later on in relaxOnce |
429 | // if necessary. |
430 | if ((op & 0xff0f) == 0xc408) |
431 | return R_RELAX_GOT_PC; |
432 | |
433 | return R_GOT_PC; |
434 | } |
435 | |
436 | bool SystemZ::relaxOnce(int pass) const { |
437 | // If we decided in adjustGotPcExpr to relax a R_390_GOTENT, |
438 | // we need to validate the target symbol is in-range and aligned. |
439 | SmallVector<InputSection *, 0> storage; |
440 | bool changed = false; |
441 | for (OutputSection *osec : outputSections) { |
442 | if (!(osec->flags & SHF_EXECINSTR)) |
443 | continue; |
444 | for (InputSection *sec : getInputSections(os: *osec, storage)) { |
445 | for (Relocation &rel : sec->relocs()) { |
446 | if (rel.expr != R_RELAX_GOT_PC) |
447 | continue; |
448 | |
449 | uint64_t v = sec->getRelocTargetVA( |
450 | File: sec->file, Type: rel.type, A: rel.addend, |
451 | P: sec->getOutputSection()->addr + rel.offset, Sym: *rel.sym, Expr: rel.expr); |
452 | if (isInt<33>(x: v) && !(v & 1)) |
453 | continue; |
454 | if (rel.sym->auxIdx == 0) { |
455 | rel.sym->allocateAux(); |
456 | addGotEntry(sym&: *rel.sym); |
457 | changed = true; |
458 | } |
459 | rel.expr = R_GOT_PC; |
460 | } |
461 | } |
462 | } |
463 | return changed; |
464 | } |
465 | |
466 | void SystemZ::relaxGot(uint8_t *loc, const Relocation &rel, |
467 | uint64_t val) const { |
468 | assert(isInt<33>(val) && |
469 | "R_390_GOTENT should not have been relaxed if it overflows" ); |
470 | assert(!(val & 1) && |
471 | "R_390_GOTENT should not have been relaxed if it is misaligned" ); |
472 | const uint16_t op = read16be(P: loc - 2); |
473 | |
474 | // lgrl rx,sym@GOTENT -> larl rx, sym |
475 | if ((op & 0xff0f) == 0xc408) { |
476 | write16be(P: loc - 2, V: 0xc000 | (op & 0x00f0)); |
477 | write32be(P: loc, V: val >> 1); |
478 | } |
479 | } |
480 | |
481 | void SystemZ::relocate(uint8_t *loc, const Relocation &rel, |
482 | uint64_t val) const { |
483 | switch (rel.expr) { |
484 | case R_RELAX_GOT_PC: |
485 | return relaxGot(loc, rel, val); |
486 | case R_RELAX_TLS_GD_TO_IE_GOT_OFF: |
487 | return relaxTlsGdToIe(loc, rel, val); |
488 | case R_RELAX_TLS_GD_TO_LE: |
489 | return relaxTlsGdToLe(loc, rel, val); |
490 | case R_RELAX_TLS_LD_TO_LE: |
491 | return relaxTlsLdToLe(loc, rel, val); |
492 | default: |
493 | break; |
494 | } |
495 | switch (rel.type) { |
496 | case R_390_8: |
497 | checkIntUInt(loc, v: val, n: 8, rel); |
498 | *loc = val; |
499 | break; |
500 | case R_390_12: |
501 | case R_390_GOT12: |
502 | case R_390_GOTPLT12: |
503 | case R_390_TLS_GOTIE12: |
504 | checkUInt(loc, v: val, n: 12, rel); |
505 | write16be(P: loc, V: (read16be(P: loc) & 0xF000) | val); |
506 | break; |
507 | case R_390_PC12DBL: |
508 | case R_390_PLT12DBL: |
509 | checkInt(loc, v: val, n: 13, rel); |
510 | checkAlignment(loc, v: val, n: 2, rel); |
511 | write16be(P: loc, V: (read16be(P: loc) & 0xF000) | ((val >> 1) & 0x0FFF)); |
512 | break; |
513 | case R_390_16: |
514 | case R_390_GOT16: |
515 | case R_390_GOTPLT16: |
516 | case R_390_GOTOFF16: |
517 | case R_390_PLTOFF16: |
518 | checkIntUInt(loc, v: val, n: 16, rel); |
519 | write16be(P: loc, V: val); |
520 | break; |
521 | case R_390_PC16: |
522 | checkInt(loc, v: val, n: 16, rel); |
523 | write16be(P: loc, V: val); |
524 | break; |
525 | case R_390_PC16DBL: |
526 | case R_390_PLT16DBL: |
527 | checkInt(loc, v: val, n: 17, rel); |
528 | checkAlignment(loc, v: val, n: 2, rel); |
529 | write16be(P: loc, V: val >> 1); |
530 | break; |
531 | case R_390_20: |
532 | case R_390_GOT20: |
533 | case R_390_GOTPLT20: |
534 | case R_390_TLS_GOTIE20: |
535 | checkInt(loc, v: val, n: 20, rel); |
536 | write32be(P: loc, V: (read32be(P: loc) & 0xF00000FF) | ((val & 0xFFF) << 16) | |
537 | ((val & 0xFF000) >> 4)); |
538 | break; |
539 | case R_390_PC24DBL: |
540 | case R_390_PLT24DBL: |
541 | checkInt(loc, v: val, n: 25, rel); |
542 | checkAlignment(loc, v: val, n: 2, rel); |
543 | loc[0] = val >> 17; |
544 | loc[1] = val >> 9; |
545 | loc[2] = val >> 1; |
546 | break; |
547 | case R_390_32: |
548 | case R_390_GOT32: |
549 | case R_390_GOTPLT32: |
550 | case R_390_GOTOFF: |
551 | case R_390_PLTOFF32: |
552 | case R_390_TLS_IE32: |
553 | case R_390_TLS_GOTIE32: |
554 | case R_390_TLS_GD32: |
555 | case R_390_TLS_LDM32: |
556 | case R_390_TLS_LDO32: |
557 | case R_390_TLS_LE32: |
558 | checkIntUInt(loc, v: val, n: 32, rel); |
559 | write32be(P: loc, V: val); |
560 | break; |
561 | case R_390_PC32: |
562 | case R_390_PLT32: |
563 | checkInt(loc, v: val, n: 32, rel); |
564 | write32be(P: loc, V: val); |
565 | break; |
566 | case R_390_PC32DBL: |
567 | case R_390_PLT32DBL: |
568 | case R_390_GOTPCDBL: |
569 | case R_390_GOTENT: |
570 | case R_390_GOTPLTENT: |
571 | case R_390_TLS_IEENT: |
572 | checkInt(loc, v: val, n: 33, rel); |
573 | checkAlignment(loc, v: val, n: 2, rel); |
574 | write32be(P: loc, V: val >> 1); |
575 | break; |
576 | case R_390_64: |
577 | case R_390_PC64: |
578 | case R_390_PLT64: |
579 | case R_390_GOT64: |
580 | case R_390_GOTPLT64: |
581 | case R_390_GOTOFF64: |
582 | case R_390_PLTOFF64: |
583 | case R_390_GOTPC: |
584 | case R_390_TLS_IE64: |
585 | case R_390_TLS_GOTIE64: |
586 | case R_390_TLS_GD64: |
587 | case R_390_TLS_LDM64: |
588 | case R_390_TLS_LDO64: |
589 | case R_390_TLS_LE64: |
590 | case R_390_TLS_DTPMOD: |
591 | case R_390_TLS_DTPOFF: |
592 | case R_390_TLS_TPOFF: |
593 | write64be(P: loc, V: val); |
594 | break; |
595 | case R_390_TLS_LOAD: |
596 | case R_390_TLS_GDCALL: |
597 | case R_390_TLS_LDCALL: |
598 | break; |
599 | default: |
600 | llvm_unreachable("unknown relocation" ); |
601 | } |
602 | } |
603 | |
604 | TargetInfo *elf::getSystemZTargetInfo() { |
605 | static SystemZ t; |
606 | return &t; |
607 | } |
608 | |