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 "RelocScan.h"
11#include "Symbols.h"
12#include "SyntheticSections.h"
13#include "Target.h"
14#include "llvm/BinaryFormat/ELF.h"
15#include "llvm/Support/Endian.h"
16
17using namespace llvm;
18using namespace llvm::support::endian;
19using namespace llvm::ELF;
20using namespace lld;
21using namespace lld::elf;
22
23namespace {
24class SystemZ : public TargetInfo {
25public:
26 SystemZ(Ctx &);
27 RelExpr getRelExpr(RelType type, const Symbol &s,
28 const uint8_t *loc) const override;
29 RelType getDynRel(RelType type) const override;
30 void writeGotHeader(uint8_t *buf) const override;
31 void writeGotPlt(uint8_t *buf, const Symbol &s) const override;
32 void writeIgotPlt(uint8_t *buf, const Symbol &s) const override;
33 void writePltHeader(uint8_t *buf) const override;
34 void addPltHeaderSymbols(InputSection &isd) const override;
35 void writePlt(uint8_t *buf, const Symbol &sym,
36 uint64_t pltEntryAddr) const override;
37 template <class ELFT, class RelTy>
38 void scanSectionImpl(InputSectionBase &sec, Relocs<RelTy> rels,
39 unsigned shard);
40 void scanSection(InputSectionBase &sec, unsigned shard) override;
41 RelExpr adjustGotPcExpr(RelType type, int64_t addend,
42 const uint8_t *loc) const override;
43 bool relaxOnce(int pass) const override;
44 void relocate(uint8_t *loc, const Relocation &rel,
45 uint64_t val) const override;
46 int64_t getImplicitAddend(const uint8_t *buf, RelType type) const override;
47
48private:
49 void relaxGot(uint8_t *loc, const Relocation &rel, uint64_t val) const;
50 void relaxTlsGdCall(uint8_t *loc, const Relocation &rel) const;
51};
52} // namespace
53
54SystemZ::SystemZ(Ctx &ctx) : TargetInfo(ctx) {
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// Only handles relocations used by relocateNonAlloc and preprocessRelocs.
84RelExpr SystemZ::getRelExpr(RelType type, const Symbol &s,
85 const uint8_t *loc) const {
86 switch (type) {
87 case R_390_NONE:
88 return R_NONE;
89 case R_390_32:
90 case R_390_64:
91 return R_ABS;
92 case R_390_TLS_LDO32:
93 case R_390_TLS_LDO64:
94 return R_DTPREL;
95 case R_390_PC32:
96 case R_390_PC64:
97 return R_PC;
98 default:
99 Err(ctx) << getErrorLoc(ctx, loc) << "unknown relocation (" << type.v
100 << ") against symbol " << &s;
101 return R_NONE;
102 }
103}
104
105void SystemZ::writeGotHeader(uint8_t *buf) const {
106 // _GLOBAL_OFFSET_TABLE_[0] holds the value of _DYNAMIC.
107 // _GLOBAL_OFFSET_TABLE_[1] and [2] are reserved.
108 write64be(P: buf, V: ctx.in.dynamic->getVA());
109}
110
111void SystemZ::writeGotPlt(uint8_t *buf, const Symbol &s) const {
112 write64be(P: buf, V: s.getPltVA(ctx) + 14);
113}
114
115void SystemZ::writeIgotPlt(uint8_t *buf, const Symbol &s) const {
116 if (ctx.arg.writeAddends)
117 write64be(P: buf, V: s.getVA(ctx));
118}
119
120void SystemZ::writePltHeader(uint8_t *buf) const {
121 const uint8_t pltData[] = {
122 0xe3, 0x10, 0xf0, 0x38, 0x00, 0x24, // stg %r1,56(%r15)
123 0xc0, 0x10, 0x00, 0x00, 0x00, 0x00, // larl %r1,_GLOBAL_OFFSET_TABLE_
124 0xd2, 0x07, 0xf0, 0x30, 0x10, 0x08, // mvc 48(8,%r15),8(%r1)
125 0xe3, 0x10, 0x10, 0x10, 0x00, 0x04, // lg %r1,16(%r1)
126 0x07, 0xf1, // br %r1
127 0x07, 0x00, // nopr
128 0x07, 0x00, // nopr
129 0x07, 0x00, // nopr
130 };
131 memcpy(dest: buf, src: pltData, n: sizeof(pltData));
132 uint64_t got = ctx.in.got->getVA();
133 uint64_t plt = ctx.in.plt->getVA();
134 write32be(P: buf + 8, V: (got - plt - 6) >> 1);
135}
136
137void SystemZ::addPltHeaderSymbols(InputSection &isec) const {
138 // The PLT header needs a reference to _GLOBAL_OFFSET_TABLE_, so we
139 // must ensure the .got section is created even if otherwise unused.
140 ctx.in.got->hasGotOffRel.store(i: true, m: std::memory_order_relaxed);
141}
142
143void SystemZ::writePlt(uint8_t *buf, const Symbol &sym,
144 uint64_t pltEntryAddr) const {
145 const uint8_t inst[] = {
146 0xc0, 0x10, 0x00, 0x00, 0x00, 0x00, // larl %r1,<.got.plt slot>
147 0xe3, 0x10, 0x10, 0x00, 0x00, 0x04, // lg %r1,0(%r1)
148 0x07, 0xf1, // br %r1
149 0x0d, 0x10, // basr %r1,%r0
150 0xe3, 0x10, 0x10, 0x0c, 0x00, 0x14, // lgf %r1,12(%r1)
151 0xc0, 0xf4, 0x00, 0x00, 0x00, 0x00, // jg <plt header>
152 0x00, 0x00, 0x00, 0x00, // <relocation offset>
153 };
154 memcpy(dest: buf, src: inst, n: sizeof(inst));
155
156 write32be(P: buf + 2, V: (sym.getGotPltVA(ctx) - pltEntryAddr) >> 1);
157 write32be(P: buf + 24, V: (ctx.in.plt->getVA() - pltEntryAddr - 22) >> 1);
158 write32be(P: buf + 28, V: ctx.in.relaPlt->entsize * sym.getPltIdx(ctx));
159}
160
161int64_t SystemZ::getImplicitAddend(const uint8_t *buf, RelType type) const {
162 switch (type) {
163 case R_390_8:
164 return SignExtend64<8>(x: *buf);
165 case R_390_16:
166 case R_390_PC16:
167 return SignExtend64<16>(x: read16be(P: buf));
168 case R_390_PC16DBL:
169 return SignExtend64<16>(x: read16be(P: buf)) << 1;
170 case R_390_32:
171 case R_390_PC32:
172 return SignExtend64<32>(x: read32be(P: buf));
173 case R_390_PC32DBL:
174 return SignExtend64<32>(x: read32be(P: buf)) << 1;
175 case R_390_64:
176 case R_390_PC64:
177 case R_390_TLS_DTPMOD:
178 case R_390_TLS_DTPOFF:
179 case R_390_TLS_TPOFF:
180 case R_390_GLOB_DAT:
181 case R_390_RELATIVE:
182 case R_390_IRELATIVE:
183 return read64be(P: buf);
184 case R_390_COPY:
185 case R_390_JMP_SLOT:
186 case R_390_NONE:
187 // These relocations are defined as not having an implicit addend.
188 return 0;
189 default:
190 InternalErr(ctx, buf) << "cannot read addend for relocation " << type;
191 return 0;
192 }
193}
194
195template <class ELFT, class RelTy>
196void SystemZ::scanSectionImpl(InputSectionBase &sec, Relocs<RelTy> rels,
197 unsigned shard) {
198 RelocScan rs(ctx, &sec, shard);
199 sec.relocations.reserve(N: rels.size());
200
201 for (auto it = rels.begin(); it != rels.end(); ++it) {
202 RelType type = it->getType(false);
203
204 // The assembler emits R_390_PLT32DBL (at the displacement field) before
205 // R_390_TLS_GDCALL/LDCALL (at the instruction start) for the same brasl.
206 // When optimizing TLS, skip PLT32DBL before maybeReportUndefined would
207 // flag __tls_get_offset as undefined.
208 if (type == R_390_PLT32DBL && !ctx.arg.shared &&
209 std::next(it) != rels.end()) {
210 RelType nextType = std::next(it)->getType(false);
211 if (nextType == R_390_TLS_GDCALL || nextType == R_390_TLS_LDCALL)
212 continue;
213 }
214
215 uint32_t symIdx = it->getSymbol(false);
216 Symbol &sym = sec.getFile<ELFT>()->getSymbol(symIdx);
217 uint64_t offset = it->r_offset;
218 if (sym.isUndefined() && symIdx != 0 &&
219 rs.maybeReportUndefined(sym&: cast<Undefined>(Val&: sym), offset))
220 continue;
221 int64_t addend = rs.getAddend<ELFT>(*it, type);
222 RelExpr expr;
223 // Relocation types that only need a RelExpr set `expr` and break out of
224 // the switch to reach rs.process(). Types that need special handling
225 // (fast-path helpers, TLS) call a handler and use `continue`.
226 switch (type) {
227 case R_390_NONE:
228 case R_390_TLS_LOAD:
229 continue;
230
231 // Absolute relocations:
232 case R_390_8:
233 case R_390_12:
234 case R_390_16:
235 case R_390_20:
236 case R_390_32:
237 case R_390_64:
238 expr = R_ABS;
239 break;
240
241 // PC-relative relocations:
242 case R_390_PC16:
243 case R_390_PC32:
244 case R_390_PC64:
245 case R_390_PC12DBL:
246 case R_390_PC16DBL:
247 case R_390_PC24DBL:
248 case R_390_PC32DBL:
249 rs.processR_PC(type, offset, addend, sym);
250 continue;
251
252 // PLT-generating relocations:
253 case R_390_PLT32:
254 case R_390_PLT64:
255 case R_390_PLT12DBL:
256 case R_390_PLT16DBL:
257 case R_390_PLT24DBL:
258 case R_390_PLT32DBL:
259 rs.processR_PLT_PC(type, offset, addend, sym);
260 continue;
261 case R_390_PLTOFF16:
262 case R_390_PLTOFF32:
263 case R_390_PLTOFF64:
264 expr = R_PLT_GOTREL;
265 break;
266
267 // GOT-generating relocations:
268 case R_390_GOTOFF16:
269 case R_390_GOTOFF: // a.k.a. R_390_GOTOFF32
270 case R_390_GOTOFF64:
271 ctx.in.got->hasGotOffRel.store(i: true, m: std::memory_order_relaxed);
272 expr = R_GOTREL;
273 break;
274 case R_390_GOTENT:
275 expr = R_GOT_PC;
276 break;
277 case R_390_GOT12:
278 case R_390_GOT16:
279 case R_390_GOT20:
280 case R_390_GOT32:
281 case R_390_GOT64:
282 expr = R_GOT_OFF;
283 break;
284
285 case R_390_GOTPLTENT:
286 expr = R_GOTPLT_PC;
287 break;
288 case R_390_GOTPLT12:
289 case R_390_GOTPLT16:
290 case R_390_GOTPLT20:
291 case R_390_GOTPLT32:
292 case R_390_GOTPLT64:
293 expr = R_GOTPLT_GOTREL;
294 break;
295 case R_390_GOTPC:
296 case R_390_GOTPCDBL:
297 ctx.in.got->hasGotOffRel.store(i: true, m: std::memory_order_relaxed);
298 expr = R_GOTONLY_PC;
299 break;
300
301 // TLS relocations:
302 case R_390_TLS_LE32:
303 case R_390_TLS_LE64:
304 if (rs.checkTlsLe(offset, sym, type))
305 continue;
306 expr = R_TPREL;
307 break;
308 case R_390_TLS_IE32:
309 case R_390_TLS_IE64:
310 // There is no IE to LE optimization.
311 rs.handleTlsIe<false>(ieExpr: R_GOT, type, offset, addend, sym);
312 continue;
313 case R_390_TLS_GOTIE12:
314 case R_390_TLS_GOTIE20:
315 case R_390_TLS_GOTIE32:
316 case R_390_TLS_GOTIE64:
317 sym.setFlags(NEEDS_TLSIE);
318 sec.addReloc(r: {.expr: R_GOT_OFF, .type: type, .offset: offset, .addend: addend, .sym: &sym});
319 continue;
320 case R_390_TLS_IEENT:
321 sym.setFlags(NEEDS_TLSIE);
322 sec.addReloc(r: {.expr: R_GOT_PC, .type: type, .offset: offset, .addend: addend, .sym: &sym});
323 continue;
324 case R_390_TLS_GDCALL:
325 // Use dummy R_ABS for `sharedExpr` (no optimization), which is a no-op in
326 // relocate().
327 rs.handleTlsGd(sharedExpr: R_ABS, ieExpr: R_GOT_OFF, leExpr: R_TPREL, type, offset, addend, sym);
328 continue;
329 case R_390_TLS_GD32:
330 case R_390_TLS_GD64:
331 rs.handleTlsGd(sharedExpr: R_TLSGD_GOT, ieExpr: R_GOT_OFF, leExpr: R_TPREL, type, offset, addend,
332 sym);
333 continue;
334
335 case R_390_TLS_LDCALL:
336 // Use dummy R_ABS for `sharedExpr` (no optimization), which is a no-op in
337 // relocate().
338 rs.handleTlsLd(sharedExpr: R_ABS, type, offset, addend, sym);
339 continue;
340 // TLS LD GOT relocations:
341 case R_390_TLS_LDM32:
342 case R_390_TLS_LDM64:
343 rs.handleTlsLd(sharedExpr: R_TLSLD_GOT, type, offset, addend, sym);
344 continue;
345 // TLS DTPREL relocations:
346 case R_390_TLS_LDO32:
347 case R_390_TLS_LDO64:
348 if (ctx.arg.shared)
349 sec.addReloc(r: {.expr: R_DTPREL, .type: type, .offset: offset, .addend: addend, .sym: &sym});
350 else
351 sec.addReloc(r: {.expr: R_TPREL, .type: type, .offset: offset, .addend: addend, .sym: &sym});
352 continue;
353
354 default:
355 Err(ctx) << getErrorLoc(ctx, loc: sec.content().data() + offset)
356 << "unknown relocation (" << type.v << ") against symbol "
357 << &sym;
358 continue;
359 }
360 rs.process(expr, type, offset, sym, addend);
361 }
362}
363
364void SystemZ::scanSection(InputSectionBase &sec, unsigned shard) {
365 elf::scanSection1<SystemZ, ELF64BE>(target&: *this, sec, shard);
366}
367
368RelType SystemZ::getDynRel(RelType type) const {
369 if (type == R_390_64 || type == R_390_PC64)
370 return type;
371 return R_390_NONE;
372}
373
374// Rewrite the brasl instruction at loc for TLS GD/LD optimization.
375//
376// The general-dynamic code sequence for a global `x`:
377//
378// Instruction Relocation Symbol
379// ear %rX,%a0
380// sllg %rX,%rX,32
381// ear %rX,%a1
382// larl %r12,_GLOBAL_OFFSET_TABLE_ R_390_GOTPCDBL _GLOBAL_OFFSET_TABLE_
383// lgrl %r2,.LC0 R_390_PC32DBL .LC0
384// brasl %r14,__tls_get_offset@plt R_390_TLS_GDCALL x
385// :tls_gdcall:x R_390_PLT32DBL __tls_get_offset
386// la %r2,0(%r2,%rX)
387//
388// .LC0:
389// .quad x@TLSGD R_390_TLS_GD64 x
390//
391// GD -> IE: replacing the call by a GOT load and LC0 by R_390_TLS_GOTIE64.
392// GD -> LE: replacing the call by a nop and LC0 by R_390_TLS_LE64.
393//
394// The local-dynamic code sequence for a global `x`:
395//
396// Instruction Relocation Symbol
397// ear %rX,%a0
398// sllg %rX,%rX,32
399// ear %rX,%a1
400// larl %r12,_GLOBAL_OFFSET_TABLE_ R_390_GOTPCDBL _GLOBAL_OFFSET_TABLE_
401// lgrl %r2,.LC0 R_390_PC32DBL .LC0
402// brasl %r14,__tls_get_offset@plt R_390_TLS_LDCALL <sym>
403// :tls_ldcall:<sym> R_390_PLT32DBL __tls_get_offset
404// la %r2,0(%r2,%rX)
405// lgrl %rY,.LC1 R_390_PC32DBL .LC1
406// la %r2,0(%r2,%rY)
407//
408// .LC0:
409// .quad <sym>@tlsldm R_390_TLS_LDM64 <sym>
410// .LC1:
411// .quad x@dtpoff R_390_TLS_LDO64 x
412//
413// LD -> LE: replacing the call by a nop, LC0 by 0, LC1 by R_390_TLS_LE64.
414void SystemZ::relaxTlsGdCall(uint8_t *loc, const Relocation &rel) const {
415 if (rel.expr == R_GOT_OFF) {
416 // brasl %r14,__tls_get_offset@plt -> lg %r2,0(%r2,%r12)
417 write16be(P: loc, V: 0xe322);
418 write32be(P: loc + 2, V: 0xc0000004);
419 } else {
420 // brasl %r14,__tls_get_offset@plt -> brcl 0,.
421 write16be(P: loc, V: 0xc004);
422 write32be(P: loc + 2, V: 0x00000000);
423 }
424}
425
426RelExpr SystemZ::adjustGotPcExpr(RelType type, int64_t addend,
427 const uint8_t *loc) const {
428 // Only R_390_GOTENT with addend 2 can be relaxed.
429 if (!ctx.arg.relax || addend != 2 || type != R_390_GOTENT)
430 return R_GOT_PC;
431 const uint16_t op = read16be(P: loc - 2);
432
433 // lgrl rx,sym@GOTENT -> larl rx, sym
434 // This relaxation is legal if "sym" binds locally (which was already
435 // verified by our caller) and is in-range and properly aligned for a
436 // LARL instruction. We cannot verify the latter constraint here, so
437 // we assume it is true and revert the decision later on in relaxOnce
438 // if necessary.
439 if ((op & 0xff0f) == 0xc408)
440 return R_RELAX_GOT_PC;
441
442 return R_GOT_PC;
443}
444
445bool SystemZ::relaxOnce(int pass) const {
446 // If we decided in adjustGotPcExpr to relax a R_390_GOTENT,
447 // we need to validate the target symbol is in-range and aligned.
448 SmallVector<InputSection *, 0> storage;
449 bool changed = false;
450 for (OutputSection *osec : ctx.outputSections) {
451 if (!(osec->flags & SHF_EXECINSTR))
452 continue;
453 for (InputSection *sec : getInputSections(os: *osec, storage)) {
454 for (Relocation &rel : sec->relocs()) {
455 if (rel.expr != R_RELAX_GOT_PC)
456 continue;
457
458 uint64_t v = sec->getRelocTargetVA(
459 ctx, r: rel, p: sec->getOutputSection()->addr + rel.offset);
460 if (isInt<33>(x: v) && !(v & 1))
461 continue;
462 if (rel.sym->auxIdx == 0) {
463 rel.sym->allocateAux(ctx);
464 addGotEntry(ctx, sym&: *rel.sym);
465 changed = true;
466 }
467 rel.expr = R_GOT_PC;
468 }
469 }
470 }
471 return changed;
472}
473
474void SystemZ::relaxGot(uint8_t *loc, const Relocation &rel,
475 uint64_t val) const {
476 assert(isInt<33>(val) &&
477 "R_390_GOTENT should not have been relaxed if it overflows");
478 assert(!(val & 1) &&
479 "R_390_GOTENT should not have been relaxed if it is misaligned");
480 const uint16_t op = read16be(P: loc - 2);
481
482 // lgrl rx,sym@GOTENT -> larl rx, sym
483 if ((op & 0xff0f) == 0xc408) {
484 write16be(P: loc - 2, V: 0xc000 | (op & 0x00f0));
485 write32be(P: loc, V: val >> 1);
486 }
487}
488
489void SystemZ::relocate(uint8_t *loc, const Relocation &rel,
490 uint64_t val) const {
491 if (rel.expr == R_RELAX_GOT_PC)
492 return relaxGot(loc, rel, val);
493
494 // Handle TLS optimizations. GDCALL/LDCALL: rewrite the brasl instruction
495 // and return. LDM slots are zeroed when relaxed to LE. Other TLS data slot
496 // types (GD32/GD64, LDO) fall through to the normal type-based switch below.
497 switch (rel.type) {
498 case R_390_TLS_GDCALL:
499 case R_390_TLS_LDCALL:
500 if (rel.expr == R_ABS) // Shared: no optimization.
501 return;
502 relaxTlsGdCall(loc, rel);
503 return;
504 case R_390_TLS_LDM32:
505 case R_390_TLS_LDM64:
506 if (rel.expr == R_TPREL)
507 return; // LD -> LE: slot stays 0.
508 break;
509 default:
510 break;
511 }
512
513 switch (rel.type) {
514 case R_390_8:
515 checkIntUInt(ctx, loc, v: val, n: 8, rel);
516 *loc = val;
517 break;
518 case R_390_12:
519 case R_390_GOT12:
520 case R_390_GOTPLT12:
521 case R_390_TLS_GOTIE12:
522 checkUInt(ctx, loc, v: val, n: 12, rel);
523 write16be(P: loc, V: (read16be(P: loc) & 0xF000) | val);
524 break;
525 case R_390_PC12DBL:
526 case R_390_PLT12DBL:
527 checkInt(ctx, loc, v: val, n: 13, rel);
528 checkAlignment(ctx, loc, v: val, n: 2, rel);
529 write16be(P: loc, V: (read16be(P: loc) & 0xF000) | ((val >> 1) & 0x0FFF));
530 break;
531 case R_390_16:
532 case R_390_GOT16:
533 case R_390_GOTPLT16:
534 case R_390_GOTOFF16:
535 case R_390_PLTOFF16:
536 checkIntUInt(ctx, loc, v: val, n: 16, rel);
537 write16be(P: loc, V: val);
538 break;
539 case R_390_PC16:
540 checkInt(ctx, loc, v: val, n: 16, rel);
541 write16be(P: loc, V: val);
542 break;
543 case R_390_PC16DBL:
544 case R_390_PLT16DBL:
545 checkInt(ctx, loc, v: val, n: 17, rel);
546 checkAlignment(ctx, loc, v: val, n: 2, rel);
547 write16be(P: loc, V: val >> 1);
548 break;
549 case R_390_20:
550 case R_390_GOT20:
551 case R_390_GOTPLT20:
552 case R_390_TLS_GOTIE20:
553 checkInt(ctx, loc, v: val, n: 20, rel);
554 write32be(P: loc, V: (read32be(P: loc) & 0xF00000FF) | ((val & 0xFFF) << 16) |
555 ((val & 0xFF000) >> 4));
556 break;
557 case R_390_PC24DBL:
558 case R_390_PLT24DBL:
559 checkInt(ctx, loc, v: val, n: 25, rel);
560 checkAlignment(ctx, loc, v: val, n: 2, rel);
561 loc[0] = val >> 17;
562 loc[1] = val >> 9;
563 loc[2] = val >> 1;
564 break;
565 case R_390_32:
566 case R_390_GOT32:
567 case R_390_GOTPLT32:
568 case R_390_GOTOFF:
569 case R_390_PLTOFF32:
570 case R_390_TLS_IE32:
571 case R_390_TLS_GOTIE32:
572 case R_390_TLS_GD32:
573 case R_390_TLS_LDM32:
574 case R_390_TLS_LDO32:
575 case R_390_TLS_LE32:
576 checkIntUInt(ctx, loc, v: val, n: 32, rel);
577 write32be(P: loc, V: val);
578 break;
579 case R_390_PC32:
580 case R_390_PLT32:
581 checkInt(ctx, loc, v: val, n: 32, rel);
582 write32be(P: loc, V: val);
583 break;
584 case R_390_PC32DBL:
585 case R_390_PLT32DBL:
586 case R_390_GOTPCDBL:
587 case R_390_GOTENT:
588 case R_390_GOTPLTENT:
589 case R_390_TLS_IEENT:
590 checkInt(ctx, loc, v: val, n: 33, rel);
591 checkAlignment(ctx, loc, v: val, n: 2, rel);
592 write32be(P: loc, V: val >> 1);
593 break;
594 case R_390_64:
595 case R_390_PC64:
596 case R_390_PLT64:
597 case R_390_GOT64:
598 case R_390_GOTPLT64:
599 case R_390_GOTOFF64:
600 case R_390_PLTOFF64:
601 case R_390_GOTPC:
602 case R_390_TLS_IE64:
603 case R_390_TLS_GOTIE64:
604 case R_390_TLS_GD64:
605 case R_390_TLS_LDM64:
606 case R_390_TLS_LDO64:
607 case R_390_TLS_LE64:
608 case R_390_TLS_DTPMOD:
609 case R_390_TLS_DTPOFF:
610 case R_390_TLS_TPOFF:
611 write64be(P: loc, V: val);
612 break;
613 case R_390_TLS_LOAD:
614 break;
615 default:
616 llvm_unreachable("unknown relocation");
617 }
618}
619
620void elf::setSystemZTargetInfo(Ctx &ctx) { ctx.target.reset(p: new SystemZ(ctx)); }
621