[llvm-branch-commits] [lld] release/18.x: [lld] Add target support for SystemZ (s390x) (#75643) (PR #81675)
via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Tue Feb 13 14:01:28 PST 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-lld-elf
Author: None (llvmbot)
<details>
<summary>Changes</summary>
Backport fe3406e349884e4ef61480dd0607f1e237102c74
Requested by: @<!-- -->uweigand
---
Patch is 81.58 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/81675.diff
36 Files Affected:
- (added) lld/ELF/Arch/SystemZ.cpp (+607)
- (modified) lld/ELF/CMakeLists.txt (+1)
- (modified) lld/ELF/Driver.cpp (+2-1)
- (modified) lld/ELF/InputFiles.cpp (+2)
- (modified) lld/ELF/InputSection.cpp (+7)
- (modified) lld/ELF/Relocations.cpp (+16-9)
- (modified) lld/ELF/Relocations.h (+3)
- (modified) lld/ELF/ScriptParser.cpp (+1)
- (modified) lld/ELF/SyntheticSections.cpp (+3)
- (modified) lld/ELF/Target.cpp (+2)
- (modified) lld/ELF/Target.h (+1)
- (added) lld/test/ELF/Inputs/systemz-init.s (+5)
- (added) lld/test/ELF/basic-systemz.s (+63)
- (added) lld/test/ELF/emulation-systemz.s (+29)
- (added) lld/test/ELF/lto/systemz.ll (+18)
- (added) lld/test/ELF/systemz-got.s (+16)
- (added) lld/test/ELF/systemz-gotent-relax-align.s (+48)
- (added) lld/test/ELF/systemz-gotent-relax-und-dso.s (+68)
- (added) lld/test/ELF/systemz-gotent-relax.s (+91)
- (added) lld/test/ELF/systemz-ifunc-nonpreemptible.s (+75)
- (added) lld/test/ELF/systemz-init-padding.s (+27)
- (added) lld/test/ELF/systemz-pie.s (+38)
- (added) lld/test/ELF/systemz-plt.s (+83)
- (added) lld/test/ELF/systemz-reloc-abs.s (+32)
- (added) lld/test/ELF/systemz-reloc-disp12.s (+21)
- (added) lld/test/ELF/systemz-reloc-disp20.s (+21)
- (added) lld/test/ELF/systemz-reloc-got.s (+92)
- (added) lld/test/ELF/systemz-reloc-gotrel.s (+36)
- (added) lld/test/ELF/systemz-reloc-pc16.s (+39)
- (added) lld/test/ELF/systemz-reloc-pc32.s (+39)
- (added) lld/test/ELF/systemz-reloc-pcdbl.s (+68)
- (added) lld/test/ELF/systemz-tls-gd.s (+142)
- (added) lld/test/ELF/systemz-tls-ie.s (+87)
- (added) lld/test/ELF/systemz-tls-ld.s (+114)
- (added) lld/test/ELF/systemz-tls-le.s (+61)
- (modified) lld/test/lit.cfg.py (+1)
``````````diff
diff --git a/lld/ELF/Arch/SystemZ.cpp b/lld/ELF/Arch/SystemZ.cpp
new file mode 100644
index 00000000000000..d37db6877559dc
--- /dev/null
+++ b/lld/ELF/Arch/SystemZ.cpp
@@ -0,0 +1,607 @@
+//===- SystemZ.cpp --------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "OutputSections.h"
+#include "Symbols.h"
+#include "SyntheticSections.h"
+#include "Target.h"
+#include "lld/Common/ErrorHandler.h"
+#include "llvm/BinaryFormat/ELF.h"
+#include "llvm/Support/Endian.h"
+
+using namespace llvm;
+using namespace llvm::support::endian;
+using namespace llvm::ELF;
+using namespace lld;
+using namespace lld::elf;
+
+namespace {
+class SystemZ : public TargetInfo {
+public:
+ SystemZ();
+ int getTlsGdRelaxSkip(RelType type) const override;
+ RelExpr getRelExpr(RelType type, const Symbol &s,
+ const uint8_t *loc) const override;
+ RelType getDynRel(RelType type) const override;
+ void writeGotHeader(uint8_t *buf) const override;
+ void writeGotPlt(uint8_t *buf, const Symbol &s) const override;
+ void writeIgotPlt(uint8_t *buf, const Symbol &s) const override;
+ void writePltHeader(uint8_t *buf) const override;
+ void addPltHeaderSymbols(InputSection &isd) const override;
+ void writePlt(uint8_t *buf, const Symbol &sym,
+ uint64_t pltEntryAddr) const override;
+ RelExpr adjustTlsExpr(RelType type, RelExpr expr) const override;
+ RelExpr adjustGotPcExpr(RelType type, int64_t addend,
+ const uint8_t *loc) const override;
+ bool relaxOnce(int pass) const override;
+ void relocate(uint8_t *loc, const Relocation &rel,
+ uint64_t val) const override;
+ int64_t getImplicitAddend(const uint8_t *buf, RelType type) const override;
+
+private:
+ void relaxGot(uint8_t *loc, const Relocation &rel, uint64_t val) const;
+ void relaxTlsGdToIe(uint8_t *loc, const Relocation &rel, uint64_t val) const;
+ void relaxTlsGdToLe(uint8_t *loc, const Relocation &rel, uint64_t val) const;
+ void relaxTlsLdToLe(uint8_t *loc, const Relocation &rel, uint64_t val) const;
+};
+} // namespace
+
+SystemZ::SystemZ() {
+ copyRel = R_390_COPY;
+ gotRel = R_390_GLOB_DAT;
+ pltRel = R_390_JMP_SLOT;
+ relativeRel = R_390_RELATIVE;
+ iRelativeRel = R_390_IRELATIVE;
+ symbolicRel = R_390_64;
+ tlsGotRel = R_390_TLS_TPOFF;
+ tlsModuleIndexRel = R_390_TLS_DTPMOD;
+ tlsOffsetRel = R_390_TLS_DTPOFF;
+ gotHeaderEntriesNum = 3;
+ gotPltHeaderEntriesNum = 0;
+ gotEntrySize = 8;
+ pltHeaderSize = 32;
+ pltEntrySize = 32;
+ ipltEntrySize = 32;
+
+ // This "trap instruction" is used to fill gaps between sections.
+ // On SystemZ, the behavior of the GNU ld is to fill those gaps
+ // with nop instructions instead - and unfortunately the default
+ // glibc crt object files (used to) rely on that behavior since
+ // they use an alignment on the .init section fragments that causes
+ // gaps which must be filled with nops as they are being executed.
+ // Therefore, we provide a nop instruction as "trapInstr" here.
+ trapInstr = {0x07, 0x07, 0x07, 0x07};
+
+ defaultImageBase = 0x1000000;
+}
+
+RelExpr SystemZ::getRelExpr(RelType type, const Symbol &s,
+ const uint8_t *loc) const {
+ switch (type) {
+ case R_390_NONE:
+ return R_NONE;
+ // Relocations targeting the symbol value.
+ case R_390_8:
+ case R_390_12:
+ case R_390_16:
+ case R_390_20:
+ case R_390_32:
+ case R_390_64:
+ return R_ABS;
+ case R_390_PC16:
+ case R_390_PC32:
+ case R_390_PC64:
+ case R_390_PC12DBL:
+ case R_390_PC16DBL:
+ case R_390_PC24DBL:
+ case R_390_PC32DBL:
+ return R_PC;
+ case R_390_GOTOFF16:
+ case R_390_GOTOFF: // a.k.a. R_390_GOTOFF32
+ case R_390_GOTOFF64:
+ return R_GOTREL;
+ // Relocations targeting the PLT associated with the symbol.
+ case R_390_PLT32:
+ case R_390_PLT64:
+ case R_390_PLT12DBL:
+ case R_390_PLT16DBL:
+ case R_390_PLT24DBL:
+ case R_390_PLT32DBL:
+ return R_PLT_PC;
+ case R_390_PLTOFF16:
+ case R_390_PLTOFF32:
+ case R_390_PLTOFF64:
+ return R_PLT_GOTREL;
+ // Relocations targeting the GOT entry associated with the symbol.
+ case R_390_GOTENT:
+ return R_GOT_PC;
+ case R_390_GOT12:
+ case R_390_GOT16:
+ case R_390_GOT20:
+ case R_390_GOT32:
+ case R_390_GOT64:
+ return R_GOT_OFF;
+ // Relocations targeting the GOTPLT entry associated with the symbol.
+ case R_390_GOTPLTENT:
+ return R_GOTPLT_PC;
+ case R_390_GOTPLT12:
+ case R_390_GOTPLT16:
+ case R_390_GOTPLT20:
+ case R_390_GOTPLT32:
+ case R_390_GOTPLT64:
+ return R_GOTPLT_GOTREL;
+ // Relocations targeting _GLOBAL_OFFSET_TABLE_.
+ case R_390_GOTPC:
+ case R_390_GOTPCDBL:
+ return R_GOTONLY_PC;
+ // TLS-related relocations.
+ case R_390_TLS_LOAD:
+ return R_NONE;
+ case R_390_TLS_GDCALL:
+ return R_TLSGD_PC;
+ case R_390_TLS_LDCALL:
+ return R_TLSLD_PC;
+ case R_390_TLS_GD32:
+ case R_390_TLS_GD64:
+ return R_TLSGD_GOT;
+ case R_390_TLS_LDM32:
+ case R_390_TLS_LDM64:
+ return R_TLSLD_GOT;
+ case R_390_TLS_LDO32:
+ case R_390_TLS_LDO64:
+ return R_DTPREL;
+ case R_390_TLS_LE32:
+ case R_390_TLS_LE64:
+ return R_TPREL;
+ case R_390_TLS_IE32:
+ case R_390_TLS_IE64:
+ return R_GOT;
+ case R_390_TLS_GOTIE12:
+ case R_390_TLS_GOTIE20:
+ case R_390_TLS_GOTIE32:
+ case R_390_TLS_GOTIE64:
+ return R_GOT_OFF;
+ case R_390_TLS_IEENT:
+ return R_GOT_PC;
+
+ default:
+ error(getErrorLocation(loc) + "unknown relocation (" + Twine(type) +
+ ") against symbol " + toString(s));
+ return R_NONE;
+ }
+}
+
+void SystemZ::writeGotHeader(uint8_t *buf) const {
+ // _GLOBAL_OFFSET_TABLE_[0] holds the value of _DYNAMIC.
+ // _GLOBAL_OFFSET_TABLE_[1] and [2] are reserved.
+ write64be(buf, mainPart->dynamic->getVA());
+}
+
+void SystemZ::writeGotPlt(uint8_t *buf, const Symbol &s) const {
+ write64be(buf, s.getPltVA() + 14);
+}
+
+void SystemZ::writeIgotPlt(uint8_t *buf, const Symbol &s) const {
+ if (config->writeAddends)
+ write64be(buf, s.getVA());
+}
+
+void SystemZ::writePltHeader(uint8_t *buf) const {
+ const uint8_t pltData[] = {
+ 0xe3, 0x10, 0xf0, 0x38, 0x00, 0x24, // stg %r1,56(%r15)
+ 0xc0, 0x10, 0x00, 0x00, 0x00, 0x00, // larl %r1,_GLOBAL_OFFSET_TABLE_
+ 0xd2, 0x07, 0xf0, 0x30, 0x10, 0x08, // mvc 48(8,%r15),8(%r1)
+ 0xe3, 0x10, 0x10, 0x10, 0x00, 0x04, // lg %r1,16(%r1)
+ 0x07, 0xf1, // br %r1
+ 0x07, 0x00, // nopr
+ 0x07, 0x00, // nopr
+ 0x07, 0x00, // nopr
+ };
+ memcpy(buf, pltData, sizeof(pltData));
+ uint64_t got = in.got->getVA();
+ uint64_t plt = in.plt->getVA();
+ write32be(buf + 8, (got - plt - 6) >> 1);
+}
+
+void SystemZ::addPltHeaderSymbols(InputSection &isec) const {
+ // The PLT header needs a reference to _GLOBAL_OFFSET_TABLE_, so we
+ // must ensure the .got section is created even if otherwise unused.
+ in.got->hasGotOffRel.store(true, std::memory_order_relaxed);
+}
+
+void SystemZ::writePlt(uint8_t *buf, const Symbol &sym,
+ uint64_t pltEntryAddr) const {
+ const uint8_t inst[] = {
+ 0xc0, 0x10, 0x00, 0x00, 0x00, 0x00, // larl %r1,<.got.plt slot>
+ 0xe3, 0x10, 0x10, 0x00, 0x00, 0x04, // lg %r1,0(%r1)
+ 0x07, 0xf1, // br %r1
+ 0x0d, 0x10, // basr %r1,%r0
+ 0xe3, 0x10, 0x10, 0x0c, 0x00, 0x14, // lgf %r1,12(%r1)
+ 0xc0, 0xf4, 0x00, 0x00, 0x00, 0x00, // jg <plt header>
+ 0x00, 0x00, 0x00, 0x00, // <relocation offset>
+ };
+ memcpy(buf, inst, sizeof(inst));
+
+ write32be(buf + 2, (sym.getGotPltVA() - pltEntryAddr) >> 1);
+ write32be(buf + 24, (in.plt->getVA() - pltEntryAddr - 22) >> 1);
+ write32be(buf + 28, in.relaPlt->entsize * sym.getPltIdx());
+}
+
+int64_t SystemZ::getImplicitAddend(const uint8_t *buf, RelType type) const {
+ switch (type) {
+ case R_390_8:
+ return SignExtend64<8>(*buf);
+ case R_390_16:
+ case R_390_PC16:
+ return SignExtend64<16>(read16be(buf));
+ case R_390_PC16DBL:
+ return SignExtend64<16>(read16be(buf)) << 1;
+ case R_390_32:
+ case R_390_PC32:
+ return SignExtend64<32>(read32be(buf));
+ case R_390_PC32DBL:
+ return SignExtend64<32>(read32be(buf)) << 1;
+ case R_390_64:
+ case R_390_PC64:
+ case R_390_TLS_DTPMOD:
+ case R_390_TLS_DTPOFF:
+ case R_390_TLS_TPOFF:
+ case R_390_GLOB_DAT:
+ case R_390_RELATIVE:
+ case R_390_IRELATIVE:
+ return read64be(buf);
+ case R_390_COPY:
+ case R_390_JMP_SLOT:
+ case R_390_NONE:
+ // These relocations are defined as not having an implicit addend.
+ return 0;
+ default:
+ internalLinkerError(getErrorLocation(buf),
+ "cannot read addend for relocation " + toString(type));
+ return 0;
+ }
+}
+
+RelType SystemZ::getDynRel(RelType type) const {
+ if (type == R_390_64 || type == R_390_PC64)
+ return type;
+ return R_390_NONE;
+}
+
+RelExpr SystemZ::adjustTlsExpr(RelType type, RelExpr expr) const {
+ if (expr == R_RELAX_TLS_GD_TO_IE)
+ return R_RELAX_TLS_GD_TO_IE_GOT_OFF;
+ return expr;
+}
+
+int SystemZ::getTlsGdRelaxSkip(RelType type) const {
+ // A __tls_get_offset call instruction is marked with 2 relocations:
+ //
+ // R_390_TLS_GDCALL / R_390_TLS_LDCALL: marker relocation
+ // R_390_PLT32DBL: __tls_get_offset
+ //
+ // After the relaxation we no longer call __tls_get_offset and should skip
+ // both relocations to not create a false dependence on __tls_get_offset
+ // being defined.
+ //
+ // Note that this mechanism only works correctly if the R_390_TLS_[GL]DCALL
+ // is seen immediately *before* the R_390_PLT32DBL. Unfortunately, current
+ // compilers on the platform will typically generate the inverse sequence.
+ // To fix this, we sort relocations by offset in RelocationScanner::scan;
+ // this ensures the correct sequence as the R_390_TLS_[GL]DCALL applies to
+ // the first byte of the brasl instruction, while the R_390_PLT32DBL applies
+ // to its third byte (the relative displacement).
+
+ if (type == R_390_TLS_GDCALL || type == R_390_TLS_LDCALL)
+ return 2;
+ return 1;
+}
+
+void SystemZ::relaxTlsGdToIe(uint8_t *loc, const Relocation &rel,
+ uint64_t val) const {
+ // The general-dynamic code sequence for a global `x`:
+ //
+ // Instruction Relocation Symbol
+ // ear %rX,%a0
+ // sllg %rX,%rX,32
+ // ear %rX,%a1
+ // larl %r12,_GLOBAL_OFFSET_TABLE_ R_390_GOTPCDBL _GLOBAL_OFFSET_TABLE_
+ // lgrl %r2,.LC0 R_390_PC32DBL .LC0
+ // brasl %r14,__tls_get_offset at plt R_390_TLS_GDCALL x
+ // :tls_gdcall:x R_390_PLT32DBL __tls_get_offset
+ // la %r2,0(%r2,%rX)
+ //
+ // .LC0:
+ // .quad x at TLSGD R_390_TLS_GD64 x
+ //
+ // Relaxing to initial-exec entails:
+ // 1) Replacing the call by a load from the GOT.
+ // 2) Replacing the relocation on the constant LC0 by R_390_TLS_GOTIE64.
+
+ switch (rel.type) {
+ case R_390_TLS_GDCALL:
+ // brasl %r14,__tls_get_offset at plt -> lg %r2,0(%r2,%r12)
+ write16be(loc, 0xe322);
+ write32be(loc + 2, 0xc0000004);
+ break;
+ case R_390_TLS_GD64:
+ relocateNoSym(loc, R_390_TLS_GOTIE64, val);
+ break;
+ default:
+ llvm_unreachable("unsupported relocation for TLS GD to IE relaxation");
+ }
+}
+
+void SystemZ::relaxTlsGdToLe(uint8_t *loc, const Relocation &rel,
+ uint64_t val) const {
+ // The general-dynamic code sequence for a global `x`:
+ //
+ // Instruction Relocation Symbol
+ // ear %rX,%a0
+ // sllg %rX,%rX,32
+ // ear %rX,%a1
+ // larl %r12,_GLOBAL_OFFSET_TABLE_ R_390_GOTPCDBL _GLOBAL_OFFSET_TABLE_
+ // lgrl %r2,.LC0 R_390_PC32DBL .LC0
+ // brasl %r14,__tls_get_offset at plt R_390_TLS_GDCALL x
+ // :tls_gdcall:x R_390_PLT32DBL __tls_get_offset
+ // la %r2,0(%r2,%rX)
+ //
+ // .LC0:
+ // .quad x at tlsgd R_390_TLS_GD64 x
+ //
+ // Relaxing to local-exec entails:
+ // 1) Replacing the call by a nop.
+ // 2) Replacing the relocation on the constant LC0 by R_390_TLS_LE64.
+
+ switch (rel.type) {
+ case R_390_TLS_GDCALL:
+ // brasl %r14,__tls_get_offset at plt -> brcl 0,.
+ write16be(loc, 0xc004);
+ write32be(loc + 2, 0x00000000);
+ break;
+ case R_390_TLS_GD64:
+ relocateNoSym(loc, R_390_TLS_LE64, val);
+ break;
+ default:
+ llvm_unreachable("unsupported relocation for TLS GD to LE relaxation");
+ }
+}
+
+void SystemZ::relaxTlsLdToLe(uint8_t *loc, const Relocation &rel,
+ uint64_t val) const {
+ // The local-dynamic code sequence for a global `x`:
+ //
+ // Instruction Relocation Symbol
+ // ear %rX,%a0
+ // sllg %rX,%rX,32
+ // ear %rX,%a1
+ // larl %r12,_GLOBAL_OFFSET_TABLE_ R_390_GOTPCDBL _GLOBAL_OFFSET_TABLE_
+ // lgrl %r2,.LC0 R_390_PC32DBL .LC0
+ // brasl %r14,__tls_get_offset at plt R_390_TLS_LDCALL <sym>
+ // :tls_ldcall:<sym> R_390_PLT32DBL __tls_get_offset
+ // la %r2,0(%r2,%rX)
+ // lgrl %rY,.LC1 R_390_PC32DBL .LC1
+ // la %r2,0(%r2,%rY)
+ //
+ // .LC0:
+ // .quad <sym>@tlsldm R_390_TLS_LDM64 <sym>
+ // .LC1:
+ // .quad x at dtpoff R_390_TLS_LDO64 x
+ //
+ // Relaxing to local-exec entails:
+ // 1) Replacing the call by a nop.
+ // 2) Replacing the constant LC0 by 0 (i.e. ignoring the relocation).
+ // 3) Replacing the relocation on the constant LC1 by R_390_TLS_LE64.
+
+ switch (rel.type) {
+ case R_390_TLS_LDCALL:
+ // brasl %r14,__tls_get_offset at plt -> brcl 0,.
+ write16be(loc, 0xc004);
+ write32be(loc + 2, 0x00000000);
+ break;
+ case R_390_TLS_LDM64:
+ break;
+ case R_390_TLS_LDO64:
+ relocateNoSym(loc, R_390_TLS_LE64, val);
+ break;
+ default:
+ llvm_unreachable("unsupported relocation for TLS LD to LE relaxation");
+ }
+}
+
+RelExpr SystemZ::adjustGotPcExpr(RelType type, int64_t addend,
+ const uint8_t *loc) const {
+ // Only R_390_GOTENT with addend 2 can be relaxed.
+ if (!config->relax || addend != 2 || type != R_390_GOTENT)
+ return R_GOT_PC;
+ const uint16_t op = read16be(loc - 2);
+
+ // lgrl rx,sym at GOTENT -> larl rx, sym
+ // This relaxation is legal if "sym" binds locally (which was already
+ // verified by our caller) and is in-range and properly aligned for a
+ // LARL instruction. We cannot verify the latter constraint here, so
+ // we assume it is true and revert the decision later on in relaxOnce
+ // if necessary.
+ if ((op & 0xff0f) == 0xc408)
+ return R_RELAX_GOT_PC;
+
+ return R_GOT_PC;
+}
+
+bool SystemZ::relaxOnce(int pass) const {
+ // If we decided in adjustGotPcExpr to relax a R_390_GOTENT,
+ // we need to validate the target symbol is in-range and aligned.
+ SmallVector<InputSection *, 0> storage;
+ bool changed = false;
+ for (OutputSection *osec : outputSections) {
+ if (!(osec->flags & SHF_EXECINSTR))
+ continue;
+ for (InputSection *sec : getInputSections(*osec, storage)) {
+ for (Relocation &rel : sec->relocs()) {
+ if (rel.expr != R_RELAX_GOT_PC)
+ continue;
+
+ uint64_t v = sec->getRelocTargetVA(
+ sec->file, rel.type, rel.addend,
+ sec->getOutputSection()->addr + rel.offset, *rel.sym, rel.expr);
+ if (isInt<33>(v) && !(v & 1))
+ continue;
+ if (rel.sym->auxIdx == 0) {
+ rel.sym->allocateAux();
+ addGotEntry(*rel.sym);
+ changed = true;
+ }
+ rel.expr = R_GOT_PC;
+ }
+ }
+ }
+ return changed;
+}
+
+void SystemZ::relaxGot(uint8_t *loc, const Relocation &rel,
+ uint64_t val) const {
+ assert(isInt<33>(val) &&
+ "R_390_GOTENT should not have been relaxed if it overflows");
+ assert(!(val & 1) &&
+ "R_390_GOTENT should not have been relaxed if it is misaligned");
+ const uint16_t op = read16be(loc - 2);
+
+ // lgrl rx,sym at GOTENT -> larl rx, sym
+ if ((op & 0xff0f) == 0xc408) {
+ write16be(loc - 2, 0xc000 | (op & 0x00f0));
+ write32be(loc, val >> 1);
+ }
+}
+
+void SystemZ::relocate(uint8_t *loc, const Relocation &rel,
+ uint64_t val) const {
+ switch (rel.expr) {
+ case R_RELAX_GOT_PC:
+ return relaxGot(loc, rel, val);
+ case R_RELAX_TLS_GD_TO_IE_GOT_OFF:
+ return relaxTlsGdToIe(loc, rel, val);
+ case R_RELAX_TLS_GD_TO_LE:
+ return relaxTlsGdToLe(loc, rel, val);
+ case R_RELAX_TLS_LD_TO_LE:
+ return relaxTlsLdToLe(loc, rel, val);
+ default:
+ break;
+ }
+ switch (rel.type) {
+ case R_390_8:
+ checkIntUInt(loc, val, 8, rel);
+ *loc = val;
+ break;
+ case R_390_12:
+ case R_390_GOT12:
+ case R_390_GOTPLT12:
+ case R_390_TLS_GOTIE12:
+ checkUInt(loc, val, 12, rel);
+ write16be(loc, (read16be(loc) & 0xF000) | val);
+ break;
+ case R_390_PC12DBL:
+ case R_390_PLT12DBL:
+ checkInt(loc, val, 13, rel);
+ checkAlignment(loc, val, 2, rel);
+ write16be(loc, (read16be(loc) & 0xF000) | ((val >> 1) & 0x0FFF));
+ break;
+ case R_390_16:
+ case R_390_GOT16:
+ case R_390_GOTPLT16:
+ case R_390_GOTOFF16:
+ case R_390_PLTOFF16:
+ checkIntUInt(loc, val, 16, rel);
+ write16be(loc, val);
+ break;
+ case R_390_PC16:
+ checkInt(loc, val, 16, rel);
+ write16be(loc, val);
+ break;
+ case R_390_PC16DBL:
+ case R_390_PLT16DBL:
+ checkInt(loc, val, 17, rel);
+ checkAlignment(loc, val, 2, rel);
+ write16be(loc, val >> 1);
+ break;
+ case R_390_20:
+ case R_390_GOT20:
+ case R_390_GOTPLT20:
+ case R_390_TLS_GOTIE20:
+ checkInt(loc, val, 20, rel);
+ write32be(loc, (read32be(loc) & 0xF00000FF) | ((val & 0xFFF) << 16) |
+ ((val & 0xFF000) >> 4));
+ break;
+ case R_390_PC24DBL:
+ case R_390_PLT24DBL:
+ checkInt(loc, val, 25, rel);
+ checkAlignment(loc, val, 2, rel);
+ loc[0] = val >> 17;
+ loc[1] = val >> 9;
+ loc[2] = val >> 1;
+ break;
+ case R_390_32:
+ case R_390_GOT32:
+ case R_390_GOTPLT32:
+ case R_390_GOTOFF:
+ case R_390_PLTOFF32:
+ case R_390_TLS_IE32:
+ case R_390_TLS_GOTIE32:
+ case R_390_TLS_GD32:
+ case R_390_TLS_LDM32:
+ case R_390_TLS_LDO32:
+ case R_390_TLS_LE32:
+ checkIntUInt(loc, val, 32, rel);
+ write32be(loc, val);
+ break;
+ case R_390_PC32:
+ case R_390_PLT32:
+ checkInt(loc, val, 32, rel);
+ write32be(loc, val);
+ break;
+ case R_390_PC32DBL:
+ case R_390_PLT32DBL:
+ case R_390_GOTPCDBL:
+ case R_390_GOTENT:
+ case R_390_GOTPLTENT:
+ case R_390_TLS_IEENT:
+ checkInt(loc, val, 33, rel);
+ checkAlignment(loc, val, 2, rel);
+ write32be(loc, val >> 1);
+ break;
+ case R_390_64:
+ case R_390_PC64:
+ case R_390_PLT64:
+ case R_390_GOT64:
+ case R_390_GOTPLT64:
+ case R_390_GOTOFF64:
+ case R_390_PLTOFF64:
+ case R_390_GOTPC:
+ case R_390_TLS_IE64:
+ case R_390_TLS_GOTIE64:
+ case R_390_TLS_GD64:
+ case R_390_TLS_LDM64:
+ case R_390_TLS_LDO64:
+ case R_390_TLS_LE64:
+ case R_390_TLS_DTPMOD:
+ case R_390_TLS_DTPOFF:
+ case R_390_TLS_TPOFF:
+ write64be(loc, val);
+ break;
+ case R_390_TLS_LOAD:
+ case R_390_TLS_GDCALL:
+ case R_390_TLS_LDCALL:
+ break;
+ default:
+ llvm_unreachable("unknown relocation");
+ }
+}
+
+TargetInfo *elf::getSystemZTargetInfo() {
+ static SystemZ t;
+ return &t;
+}
diff --git a/lld/ELF/CMakeLists.txt b/lld/ELF/CMakeLists.txt
index 475f7dea1dd7e9..83d816ddb0601e 100644
--- a/lld/ELF/CMakeLists.txt
+++ b/lld/ELF/CMakeLists.txt
@@ -33,6 +33,7 @@ add_lld_library(lldELF
Arch/PPC64.cpp
Arch/RISCV.cpp
Arch/SPARCV9.cpp
+ Arch/SystemZ.cpp
Arch/X86.cpp
Arch/X86_64.cpp
ARMErrataFix.cpp
diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp
index f4b7d1c9d5b973..8b2c32b1534821 100644
--- a/lld/ELF/Driver.cpp
+++ b/lld/ELF/Driver.cpp
@@ -200,6 +200,7 @@ static std::tuple<ELFKind, uint16_t, uint8_t> parseEmulation(StringRef emul) {
.C...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/81675
More information about the llvm-branch-commits
mailing list