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