brintos

brintos / llvm-project-archived public Read only

0
0
Text · 18.7 KiB · a912580 Raw
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