1 //===- SystemZ.cpp --------------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "OutputSections.h"
11 #include "SyntheticSections.h"
13 #include "lld/Common/ErrorHandler.h"
14 #include "llvm/BinaryFormat/ELF.h"
15 #include "llvm/Support/Endian.h"
18 using namespace llvm::support::endian
;
19 using namespace llvm::ELF
;
21 using namespace lld::elf
;
24 class SystemZ
: public TargetInfo
{
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
;
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;
54 SystemZ::SystemZ(Ctx
&ctx
) : TargetInfo(ctx
) {
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;
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};
80 defaultImageBase
= 0x1000000;
83 RelExpr
SystemZ::getRelExpr(RelType type
, const Symbol
&s
,
84 const uint8_t *loc
) const {
88 // Relocations targeting the symbol value.
105 case R_390_GOTOFF
: // a.k.a. R_390_GOTOFF32
108 // Relocations targeting the PLT associated with the symbol.
120 // Relocations targeting the GOT entry associated with the symbol.
129 // Relocations targeting the GOTPLT entry associated with the symbol.
130 case R_390_GOTPLTENT
:
137 return R_GOTPLT_GOTREL
;
138 // Relocations targeting _GLOBAL_OFFSET_TABLE_.
142 // TLS-related relocations.
145 case R_390_TLS_GDCALL
:
147 case R_390_TLS_LDCALL
:
152 case R_390_TLS_LDM32
:
153 case R_390_TLS_LDM64
:
155 case R_390_TLS_LDO32
:
156 case R_390_TLS_LDO64
:
164 case R_390_TLS_GOTIE12
:
165 case R_390_TLS_GOTIE20
:
166 case R_390_TLS_GOTIE32
:
167 case R_390_TLS_GOTIE64
:
169 case R_390_TLS_IEENT
:
173 Err(ctx
) << getErrorLoc(ctx
, loc
) << "unknown relocation (" << type
.v
174 << ") against symbol " << &s
;
179 void SystemZ::writeGotHeader(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(buf
, ctx
.mainPart
->dynamic
->getVA());
185 void SystemZ::writeGotPlt(uint8_t *buf
, const Symbol
&s
) const {
186 write64be(buf
, s
.getPltVA(ctx
) + 14);
189 void SystemZ::writeIgotPlt(uint8_t *buf
, const Symbol
&s
) const {
190 if (ctx
.arg
.writeAddends
)
191 write64be(buf
, s
.getVA(ctx
));
194 void SystemZ::writePltHeader(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
205 memcpy(buf
, pltData
, sizeof(pltData
));
206 uint64_t got
= ctx
.in
.got
->getVA();
207 uint64_t plt
= ctx
.in
.plt
->getVA();
208 write32be(buf
+ 8, (got
- plt
- 6) >> 1);
211 void SystemZ::addPltHeaderSymbols(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 ctx
.in
.got
->hasGotOffRel
.store(true, std::memory_order_relaxed
);
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>
228 memcpy(buf
, inst
, sizeof(inst
));
230 write32be(buf
+ 2, (sym
.getGotPltVA(ctx
) - pltEntryAddr
) >> 1);
231 write32be(buf
+ 24, (ctx
.in
.plt
->getVA() - pltEntryAddr
- 22) >> 1);
232 write32be(buf
+ 28, ctx
.in
.relaPlt
->entsize
* sym
.getPltIdx(ctx
));
235 int64_t SystemZ::getImplicitAddend(const uint8_t *buf
, RelType type
) const {
238 return SignExtend64
<8>(*buf
);
241 return SignExtend64
<16>(read16be(buf
));
243 return SignExtend64
<16>(read16be(buf
)) << 1;
246 return SignExtend64
<32>(read32be(buf
));
248 return SignExtend64
<32>(read32be(buf
)) << 1;
251 case R_390_TLS_DTPMOD
:
252 case R_390_TLS_DTPOFF
:
253 case R_390_TLS_TPOFF
:
256 case R_390_IRELATIVE
:
257 return read64be(buf
);
261 // These relocations are defined as not having an implicit addend.
264 InternalErr(ctx
, buf
) << "cannot read addend for relocation " << type
;
269 RelType
SystemZ::getDynRel(RelType type
) const {
270 if (type
== R_390_64
|| type
== R_390_PC64
)
275 RelExpr
SystemZ::adjustTlsExpr(RelType type
, RelExpr expr
) const {
276 if (expr
== R_RELAX_TLS_GD_TO_IE
)
277 return R_RELAX_TLS_GD_TO_IE_GOT_OFF
;
281 int SystemZ::getTlsGdRelaxSkip(RelType type
) const {
282 // A __tls_get_offset call instruction is marked with 2 relocations:
284 // R_390_TLS_GDCALL / R_390_TLS_LDCALL: marker relocation
285 // R_390_PLT32DBL: __tls_get_offset
287 // After the relaxation we no longer call __tls_get_offset and should skip
288 // both relocations to not create a false dependence on __tls_get_offset
291 // Note that this mechanism only works correctly if the R_390_TLS_[GL]DCALL
292 // is seen immediately *before* the R_390_PLT32DBL. Unfortunately, current
293 // compilers on the platform will typically generate the inverse sequence.
294 // To fix this, we sort relocations by offset in RelocationScanner::scan;
295 // this ensures the correct sequence as the R_390_TLS_[GL]DCALL applies to
296 // the first byte of the brasl instruction, while the R_390_PLT32DBL applies
297 // to its third byte (the relative displacement).
299 if (type
== R_390_TLS_GDCALL
|| type
== R_390_TLS_LDCALL
)
304 void SystemZ::relaxTlsGdToIe(uint8_t *loc
, const Relocation
&rel
,
305 uint64_t val
) const {
306 // The general-dynamic code sequence for a global `x`:
308 // Instruction Relocation Symbol
312 // larl %r12,_GLOBAL_OFFSET_TABLE_ R_390_GOTPCDBL _GLOBAL_OFFSET_TABLE_
313 // lgrl %r2,.LC0 R_390_PC32DBL .LC0
314 // brasl %r14,__tls_get_offset@plt R_390_TLS_GDCALL x
315 // :tls_gdcall:x R_390_PLT32DBL __tls_get_offset
319 // .quad x@TLSGD R_390_TLS_GD64 x
321 // Relaxing to initial-exec entails:
322 // 1) Replacing the call by a load from the GOT.
323 // 2) Replacing the relocation on the constant LC0 by R_390_TLS_GOTIE64.
326 case R_390_TLS_GDCALL
:
327 // brasl %r14,__tls_get_offset@plt -> lg %r2,0(%r2,%r12)
328 write16be(loc
, 0xe322);
329 write32be(loc
+ 2, 0xc0000004);
332 relocateNoSym(loc
, R_390_TLS_GOTIE64
, val
);
335 llvm_unreachable("unsupported relocation for TLS GD to IE relaxation");
339 void SystemZ::relaxTlsGdToLe(uint8_t *loc
, const Relocation
&rel
,
340 uint64_t val
) const {
341 // The general-dynamic code sequence for a global `x`:
343 // Instruction Relocation Symbol
347 // larl %r12,_GLOBAL_OFFSET_TABLE_ R_390_GOTPCDBL _GLOBAL_OFFSET_TABLE_
348 // lgrl %r2,.LC0 R_390_PC32DBL .LC0
349 // brasl %r14,__tls_get_offset@plt R_390_TLS_GDCALL x
350 // :tls_gdcall:x R_390_PLT32DBL __tls_get_offset
354 // .quad x@tlsgd R_390_TLS_GD64 x
356 // Relaxing to local-exec entails:
357 // 1) Replacing the call by a nop.
358 // 2) Replacing the relocation on the constant LC0 by R_390_TLS_LE64.
361 case R_390_TLS_GDCALL
:
362 // brasl %r14,__tls_get_offset@plt -> brcl 0,.
363 write16be(loc
, 0xc004);
364 write32be(loc
+ 2, 0x00000000);
367 relocateNoSym(loc
, R_390_TLS_LE64
, val
);
370 llvm_unreachable("unsupported relocation for TLS GD to LE relaxation");
374 void SystemZ::relaxTlsLdToLe(uint8_t *loc
, const Relocation
&rel
,
375 uint64_t val
) const {
376 // The local-dynamic code sequence for a global `x`:
378 // Instruction Relocation Symbol
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_LDCALL <sym>
385 // :tls_ldcall:<sym> R_390_PLT32DBL __tls_get_offset
387 // lgrl %rY,.LC1 R_390_PC32DBL .LC1
391 // .quad <sym>@tlsldm R_390_TLS_LDM64 <sym>
393 // .quad x@dtpoff R_390_TLS_LDO64 x
395 // Relaxing to local-exec entails:
396 // 1) Replacing the call by a nop.
397 // 2) Replacing the constant LC0 by 0 (i.e. ignoring the relocation).
398 // 3) Replacing the relocation on the constant LC1 by R_390_TLS_LE64.
401 case R_390_TLS_LDCALL
:
402 // brasl %r14,__tls_get_offset@plt -> brcl 0,.
403 write16be(loc
, 0xc004);
404 write32be(loc
+ 2, 0x00000000);
406 case R_390_TLS_LDM64
:
408 case R_390_TLS_LDO64
:
409 relocateNoSym(loc
, R_390_TLS_LE64
, val
);
412 llvm_unreachable("unsupported relocation for TLS LD to LE relaxation");
416 RelExpr
SystemZ::adjustGotPcExpr(RelType type
, int64_t addend
,
417 const uint8_t *loc
) const {
418 // Only R_390_GOTENT with addend 2 can be relaxed.
419 if (!ctx
.arg
.relax
|| addend
!= 2 || type
!= R_390_GOTENT
)
421 const uint16_t op
= read16be(loc
- 2);
423 // lgrl rx,sym@GOTENT -> larl rx, sym
424 // This relaxation is legal if "sym" binds locally (which was already
425 // verified by our caller) and is in-range and properly aligned for a
426 // LARL instruction. We cannot verify the latter constraint here, so
427 // we assume it is true and revert the decision later on in relaxOnce
429 if ((op
& 0xff0f) == 0xc408)
430 return R_RELAX_GOT_PC
;
435 bool SystemZ::relaxOnce(int pass
) const {
436 // If we decided in adjustGotPcExpr to relax a R_390_GOTENT,
437 // we need to validate the target symbol is in-range and aligned.
438 SmallVector
<InputSection
*, 0> storage
;
439 bool changed
= false;
440 for (OutputSection
*osec
: ctx
.outputSections
) {
441 if (!(osec
->flags
& SHF_EXECINSTR
))
443 for (InputSection
*sec
: getInputSections(*osec
, storage
)) {
444 for (Relocation
&rel
: sec
->relocs()) {
445 if (rel
.expr
!= R_RELAX_GOT_PC
)
448 uint64_t v
= sec
->getRelocTargetVA(
449 ctx
, rel
, sec
->getOutputSection()->addr
+ rel
.offset
);
450 if (isInt
<33>(v
) && !(v
& 1))
452 if (rel
.sym
->auxIdx
== 0) {
453 rel
.sym
->allocateAux(ctx
);
454 addGotEntry(ctx
, *rel
.sym
);
464 void SystemZ::relaxGot(uint8_t *loc
, const Relocation
&rel
,
465 uint64_t val
) const {
466 assert(isInt
<33>(val
) &&
467 "R_390_GOTENT should not have been relaxed if it overflows");
469 "R_390_GOTENT should not have been relaxed if it is misaligned");
470 const uint16_t op
= read16be(loc
- 2);
472 // lgrl rx,sym@GOTENT -> larl rx, sym
473 if ((op
& 0xff0f) == 0xc408) {
474 write16be(loc
- 2, 0xc000 | (op
& 0x00f0));
475 write32be(loc
, val
>> 1);
479 void SystemZ::relocate(uint8_t *loc
, const Relocation
&rel
,
480 uint64_t val
) const {
483 return relaxGot(loc
, rel
, val
);
484 case R_RELAX_TLS_GD_TO_IE_GOT_OFF
:
485 return relaxTlsGdToIe(loc
, rel
, val
);
486 case R_RELAX_TLS_GD_TO_LE
:
487 return relaxTlsGdToLe(loc
, rel
, val
);
488 case R_RELAX_TLS_LD_TO_LE
:
489 return relaxTlsLdToLe(loc
, rel
, val
);
495 checkIntUInt(ctx
, loc
, val
, 8, rel
);
501 case R_390_TLS_GOTIE12
:
502 checkUInt(ctx
, loc
, val
, 12, rel
);
503 write16be(loc
, (read16be(loc
) & 0xF000) | val
);
507 checkInt(ctx
, loc
, val
, 13, rel
);
508 checkAlignment(ctx
, loc
, val
, 2, rel
);
509 write16be(loc
, (read16be(loc
) & 0xF000) | ((val
>> 1) & 0x0FFF));
516 checkIntUInt(ctx
, loc
, val
, 16, rel
);
520 checkInt(ctx
, loc
, val
, 16, rel
);
525 checkInt(ctx
, loc
, val
, 17, rel
);
526 checkAlignment(ctx
, loc
, val
, 2, rel
);
527 write16be(loc
, val
>> 1);
532 case R_390_TLS_GOTIE20
:
533 checkInt(ctx
, loc
, val
, 20, rel
);
534 write32be(loc
, (read32be(loc
) & 0xF00000FF) | ((val
& 0xFFF) << 16) |
535 ((val
& 0xFF000) >> 4));
539 checkInt(ctx
, loc
, val
, 25, rel
);
540 checkAlignment(ctx
, loc
, val
, 2, rel
);
551 case R_390_TLS_GOTIE32
:
553 case R_390_TLS_LDM32
:
554 case R_390_TLS_LDO32
:
556 checkIntUInt(ctx
, loc
, val
, 32, rel
);
561 checkInt(ctx
, loc
, val
, 32, rel
);
568 case R_390_GOTPLTENT
:
569 case R_390_TLS_IEENT
:
570 checkInt(ctx
, loc
, val
, 33, rel
);
571 checkAlignment(ctx
, loc
, val
, 2, rel
);
572 write32be(loc
, val
>> 1);
583 case R_390_TLS_GOTIE64
:
585 case R_390_TLS_LDM64
:
586 case R_390_TLS_LDO64
:
588 case R_390_TLS_DTPMOD
:
589 case R_390_TLS_DTPOFF
:
590 case R_390_TLS_TPOFF
:
594 case R_390_TLS_GDCALL
:
595 case R_390_TLS_LDCALL
:
598 llvm_unreachable("unknown relocation");
602 void elf::setSystemZTargetInfo(Ctx
&ctx
) { ctx
.target
.reset(new SystemZ(ctx
)); }