[lld] Add target support for SystemZ (s390x) (#75643)

This patch adds full support for linking SystemZ (ELF s390x) object
files. Support should be generally complete:
- All relocation types are supported.
- Full shared library support (DYNAMIC, GOT, PLT, ifunc).
- Relaxation of TLS and GOT relocations where appropriate.
- Platform-specific test cases.

In addition to new platform code and the obvious changes, there were a
few additional changes to common code:

- Add three new RelExpr members (R_GOTPLT_OFF, R_GOTPLT_PC, and
R_PLT_GOTREL) needed to support certain s390x relocations. I chose not
to use a platform-specific name since nothing in the definition of these
relocs is actually platform-specific; it is well possible that other
platforms will need the same.

- A couple of tweaks to TLS relocation handling, as the particular
semantics of the s390x versions differ slightly. See comments in the
code.

This was tested by building and testing >1500 Fedora packages, with only
a handful of failures; as these also have issues when building with LLD
on other architectures, they seem unrelated.

Co-authored-by: Tulio Magno Quites Machado Filho <tuliom@redhat.com>
This commit is contained in:
Ulrich Weigand
2024-02-13 11:29:21 +01:00
committed by GitHub
parent 4c931091a3
commit fe3406e349
36 changed files with 1959 additions and 10 deletions

607
lld/ELF/Arch/SystemZ.cpp Normal file
View File

@@ -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@plt R_390_TLS_GDCALL x
// :tls_gdcall:x R_390_PLT32DBL __tls_get_offset
// la %r2,0(%r2,%rX)
//
// .LC0:
// .quad x@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@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@plt R_390_TLS_GDCALL x
// :tls_gdcall:x R_390_PLT32DBL __tls_get_offset
// la %r2,0(%r2,%rX)
//
// .LC0:
// .quad x@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@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@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@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@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@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@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;
}

View File

@@ -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

View File

@@ -200,6 +200,7 @@ static std::tuple<ELFKind, uint16_t, uint8_t> parseEmulation(StringRef emul) {
.Case("msp430elf", {ELF32LEKind, EM_MSP430})
.Case("elf64_amdgpu", {ELF64LEKind, EM_AMDGPU})
.Case("elf64loongarch", {ELF64LEKind, EM_LOONGARCH})
.Case("elf64_s390", {ELF64BEKind, EM_S390})
.Default({ELFNoneKind, EM_NONE});
if (ret.first == ELFNoneKind)
@@ -1137,7 +1138,7 @@ static SmallVector<StringRef, 0> getSymbolOrderingFile(MemoryBufferRef mb) {
static bool getIsRela(opt::InputArgList &args) {
// The psABI specifies the default relocation entry format.
bool rela = is_contained({EM_AARCH64, EM_AMDGPU, EM_HEXAGON, EM_LOONGARCH,
EM_PPC, EM_PPC64, EM_RISCV, EM_X86_64},
EM_PPC, EM_PPC64, EM_RISCV, EM_S390, EM_X86_64},
config->emachine);
// If -z rel or -z rela is specified, use the last option.
for (auto *arg : args.filtered(OPT_z)) {

View File

@@ -1614,6 +1614,8 @@ static uint16_t getBitcodeMachineKind(StringRef path, const Triple &t) {
return EM_RISCV;
case Triple::sparcv9:
return EM_SPARCV9;
case Triple::systemz:
return EM_S390;
case Triple::x86:
return t.isOSIAMCU() ? EM_IAMCU : EM_386;
case Triple::x86_64:

View File

@@ -655,6 +655,7 @@ static int64_t getTlsTpOffset(const Symbol &s) {
// Variant 2.
case EM_HEXAGON:
case EM_S390:
case EM_SPARCV9:
case EM_386:
case EM_X86_64:
@@ -717,6 +718,10 @@ uint64_t InputSectionBase::getRelocTargetVA(const InputFile *file, RelType type,
case R_GOT_PC:
case R_RELAX_TLS_GD_TO_IE:
return sym.getGotVA() + a - p;
case R_GOTPLT_GOTREL:
return sym.getGotPltVA() + a - in.got->getVA();
case R_GOTPLT_PC:
return sym.getGotPltVA() + a - p;
case R_LOONGARCH_GOT_PAGE_PC:
if (sym.hasFlag(NEEDS_TLSGD))
return getLoongArchPageDelta(in.got->getGlobalDynAddr(sym) + a, p, type);
@@ -808,6 +813,8 @@ uint64_t InputSectionBase::getRelocTargetVA(const InputFile *file, RelType type,
return getLoongArchPageDelta(sym.getPltVA() + a, p, type);
case R_PLT_GOTPLT:
return sym.getPltVA() + a - in.gotPlt->getVA();
case R_PLT_GOTREL:
return sym.getPltVA() + a - in.got->getVA();
case R_PPC32_PLTREL:
// R_PPC_PLTREL24 uses the addend (usually 0 or 0x8000) to indicate r30
// stores _GLOBAL_OFFSET_TABLE_ or .got2+0x8000. The addend is ignored for

View File

@@ -203,8 +203,9 @@ static bool isAbsoluteValue(const Symbol &sym) {
// Returns true if Expr refers a PLT entry.
static bool needsPlt(RelExpr expr) {
return oneof<R_PLT, R_PLT_PC, R_PLT_GOTPLT, R_LOONGARCH_PLT_PAGE_PC,
R_PPC32_PLTREL, R_PPC64_CALL_PLT>(expr);
return oneof<R_PLT, R_PLT_PC, R_PLT_GOTREL, R_PLT_GOTPLT, R_GOTPLT_GOTREL,
R_GOTPLT_PC, R_LOONGARCH_PLT_PAGE_PC, R_PPC32_PLTREL,
R_PPC64_CALL_PLT>(expr);
}
bool lld::elf::needsGot(RelExpr expr) {
@@ -233,6 +234,8 @@ static RelExpr toPlt(RelExpr expr) {
return R_PLT_PC;
case R_ABS:
return R_PLT;
case R_GOTREL:
return R_PLT_GOTREL;
default:
return expr;
}
@@ -253,6 +256,8 @@ static RelExpr fromPlt(RelExpr expr) {
return R_ABS;
case R_PLT_GOTPLT:
return R_GOTPLTREL;
case R_PLT_GOTREL:
return R_GOTREL;
default:
return expr;
}
@@ -979,10 +984,10 @@ bool RelocationScanner::isStaticLinkTimeConstant(RelExpr e, RelType type,
if (oneof<R_GOTPLT, R_GOT_OFF, R_RELAX_HINT, R_MIPS_GOT_LOCAL_PAGE,
R_MIPS_GOTREL, R_MIPS_GOT_OFF, R_MIPS_GOT_OFF32, R_MIPS_GOT_GP_PC,
R_AARCH64_GOT_PAGE_PC, R_GOT_PC, R_GOTONLY_PC, R_GOTPLTONLY_PC,
R_PLT_PC, R_PLT_GOTPLT, R_PPC32_PLTREL, R_PPC64_CALL_PLT,
R_PPC64_RELAX_TOC, R_RISCV_ADD, R_AARCH64_GOT_PAGE,
R_LOONGARCH_PLT_PAGE_PC, R_LOONGARCH_GOT, R_LOONGARCH_GOT_PAGE_PC>(
e))
R_PLT_PC, R_PLT_GOTREL, R_PLT_GOTPLT, R_GOTPLT_GOTREL, R_GOTPLT_PC,
R_PPC32_PLTREL, R_PPC64_CALL_PLT, R_PPC64_RELAX_TOC, R_RISCV_ADD,
R_AARCH64_GOT_PAGE, R_LOONGARCH_PLT_PAGE_PC, R_LOONGARCH_GOT,
R_LOONGARCH_GOT_PAGE_PC>(e))
return true;
// These never do, except if the entire file is position dependent or if
@@ -1374,8 +1379,8 @@ static unsigned handleTlsRelocation(RelType type, Symbol &sym,
R_LOONGARCH_GOT_PAGE_PC, R_GOT_OFF, R_TLSIE_HINT>(expr)) {
ctx.hasTlsIe.store(true, std::memory_order_relaxed);
// Initial-Exec relocs can be optimized to Local-Exec if the symbol is
// locally defined.
if (execOptimize && isLocalInExecutable) {
// locally defined. This is not supported on SystemZ.
if (execOptimize && isLocalInExecutable && config->emachine != EM_S390) {
c.addReloc({R_RELAX_TLS_IE_TO_LE, type, offset, addend, &sym});
} else if (expr != R_TLSIE_HINT) {
sym.setFlags(NEEDS_TLSIE);
@@ -1534,8 +1539,10 @@ void RelocationScanner::scan(ArrayRef<RelTy> rels) {
// For EhInputSection, OffsetGetter expects the relocations to be sorted by
// r_offset. In rare cases (.eh_frame pieces are reordered by a linker
// script), the relocations may be unordered.
// On SystemZ, all sections need to be sorted by r_offset, to allow TLS
// relaxation to be handled correctly - see SystemZ::getTlsGdRelaxSkip.
SmallVector<RelTy, 0> storage;
if (isa<EhInputSection>(sec))
if (isa<EhInputSection>(sec) || config->emachine == EM_S390)
rels = sortRels(rels, storage);
end = static_cast<const void *>(rels.end());

View File

@@ -40,11 +40,14 @@ enum RelExpr {
R_GOTPLT,
R_GOTPLTREL,
R_GOTREL,
R_GOTPLT_GOTREL,
R_GOTPLT_PC,
R_NONE,
R_PC,
R_PLT,
R_PLT_PC,
R_PLT_GOTPLT,
R_PLT_GOTREL,
R_RELAX_HINT,
R_RELAX_GOT_PC,
R_RELAX_GOT_PC_NOPIC,

View File

@@ -445,6 +445,7 @@ static std::pair<ELFKind, uint16_t> parseBfdName(StringRef s) {
.Case("elf32-msp430", {ELF32LEKind, EM_MSP430})
.Case("elf32-loongarch", {ELF32LEKind, EM_LOONGARCH})
.Case("elf64-loongarch", {ELF64LEKind, EM_LOONGARCH})
.Case("elf64-s390", {ELF64BEKind, EM_S390})
.Default({ELFNoneKind, EM_NONE});
}

View File

@@ -1419,6 +1419,9 @@ DynamicSection<ELFT>::computeContents() {
case EM_MIPS:
addInSec(DT_MIPS_PLTGOT, *in.gotPlt);
break;
case EM_S390:
addInSec(DT_PLTGOT, *in.got);
break;
case EM_SPARCV9:
addInSec(DT_PLTGOT, *in.plt);
break;

View File

@@ -87,6 +87,8 @@ TargetInfo *elf::getTarget() {
return getRISCVTargetInfo();
case EM_SPARCV9:
return getSPARCV9TargetInfo();
case EM_S390:
return getSystemZTargetInfo();
case EM_X86_64:
return getX86_64TargetInfo();
default:

View File

@@ -188,6 +188,7 @@ TargetInfo *getPPC64TargetInfo();
TargetInfo *getPPCTargetInfo();
TargetInfo *getRISCVTargetInfo();
TargetInfo *getSPARCV9TargetInfo();
TargetInfo *getSystemZTargetInfo();
TargetInfo *getX86TargetInfo();
TargetInfo *getX86_64TargetInfo();
template <class ELFT> TargetInfo *getMipsTargetInfo();

View File

@@ -0,0 +1,5 @@
// glibc < 2.39 used to align .init and .fini code at a 4-byte boundary.
// This file aims to recreate that behavior.
.section .init,"ax",@progbits
.align 4
lg %r4, 272(%r15)

View File

@@ -0,0 +1,63 @@
# REQUIRES: systemz
# RUN: llvm-mc -filetype=obj -triple=s390x-unknown-linux %s -o %t.o
# RUN: ld.lld --hash-style=sysv -discard-all -shared %t.o -o %t.so
# RUN: llvm-readelf --file-header --program-headers --section-headers --dynamic-table %t.so | FileCheck %s
# Exits with return code 55 on linux.
.text
lghi 2,55
svc 1
# CHECK: ELF Header:
# CHECK-NEXT: Magic: 7f 45 4c 46 02 02 01 00 00 00 00 00 00 00 00 00
# CHECK-NEXT: Class: ELF64
# CHECK-NEXT: Data: 2's complement, big endian
# CHECK-NEXT: Version: 1 (current)
# CHECK-NEXT: OS/ABI: UNIX - System V
# CHECK-NEXT: ABI Version: 0
# CHECK-NEXT: Type: DYN (Shared object file)
# CHECK-NEXT: Machine: IBM S/390
# CHECK-NEXT: Version: 0x1
# CHECK-NEXT: Entry point address: 0x0
# CHECK-NEXT: Start of program headers: 64 (bytes into file)
# CHECK-NEXT: Start of section headers: 768 (bytes into file)
# CHECK-NEXT: Flags: 0x0
# CHECK-NEXT: Size of this header: 64 (bytes)
# CHECK-NEXT: Size of program headers: 56 (bytes)
# CHECK-NEXT: Number of program headers: 7
# CHECK-NEXT: Size of section headers: 64 (bytes)
# CHECK-NEXT: Number of section headers: 11
# CHECK-NEXT: Section header string table index: 9
# CHECK: Section Headers:
# CHECK-NEXT: [Nr] Name Type Address Off Size ES Flg Lk Inf Al
# CHECK-NEXT: [ 0] NULL 0000000000000000 000000 000000 00 0 0 0
# CHECK-NEXT: [ 1] .dynsym DYNSYM 00000000000001c8 0001c8 000018 18 A 3 1 8
# CHECK-NEXT: [ 2] .hash HASH 00000000000001e0 0001e0 000010 04 A 1 0 4
# CHECK-NEXT: [ 3] .dynstr STRTAB 00000000000001f0 0001f0 000001 00 A 0 0 1
# CHECK-NEXT: [ 4] .text PROGBITS 00000000000011f4 0001f4 000006 00 AX 0 0 4
# CHECK-NEXT: [ 5] .dynamic DYNAMIC 0000000000002200 000200 000060 10 WA 3 0 8
# CHECK-NEXT: [ 6] .relro_padding NOBITS 0000000000002260 000260 000da0 00 WA 0 0 1
# CHECK-NEXT: [ 7] .comment PROGBITS 0000000000000000 000260 000008 01 MS 0 0 1
# CHECK-NEXT: [ 8] .symtab SYMTAB 0000000000000000 000268 000030 18 10 2 8
# CHECK-NEXT: [ 9] .shstrtab STRTAB 0000000000000000 000298 000058 00 0 0 1
# CHECK-NEXT: [10] .strtab STRTAB 0000000000000000 0002f0 00000a 00 0 0 1
# CHECK: Program Headers:
# CHECK-NEXT: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
# CHECK-NEXT: PHDR 0x000040 0x0000000000000040 0x0000000000000040 0x000188 0x000188 R 0x8
# CHECK-NEXT: LOAD 0x000000 0x0000000000000000 0x0000000000000000 0x0001f1 0x0001f1 R 0x1000
# CHECK-NEXT: LOAD 0x0001f4 0x00000000000011f4 0x00000000000011f4 0x000006 0x000006 R E 0x1000
# CHECK-NEXT: LOAD 0x000200 0x0000000000002200 0x0000000000002200 0x000060 0x000e00 RW 0x1000
# CHECK-NEXT: DYNAMIC 0x000200 0x0000000000002200 0x0000000000002200 0x000060 0x000060 RW 0x8
# CHECK-NEXT: GNU_RELRO 0x000200 0x0000000000002200 0x0000000000002200 0x000060 0x000e00 R 0x1
# CHECK-NEXT: GNU_STACK 0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW 0x0
# CHECK: Dynamic section at offset 0x200 contains 6 entries:
# CHECK-NEXT: Tag Type Name/Value
# CHECK-NEXT: 0x0000000000000006 (SYMTAB) 0x1c8
# CHECK-NEXT: 0x000000000000000b (SYMENT) 24 (bytes)
# CHECK-NEXT: 0x0000000000000005 (STRTAB) 0x1f0
# CHECK-NEXT: 0x000000000000000a (STRSZ) 1 (bytes)
# CHECK-NEXT: 0x0000000000000004 (HASH) 0x1e0
# CHECK-NEXT: 0x0000000000000000 (NULL) 0x0

View File

@@ -0,0 +1,29 @@
# REQUIRES: systemz
# RUN: llvm-mc -filetype=obj -triple=s390x-unknown-linux %s -o %t.o
# RUN: ld.lld -m elf64_s390 %t.o -o %t1
# RUN: llvm-readelf --file-header %t1 | FileCheck %s
# RUN: ld.lld %t.o -o %t2
# RUN: llvm-readelf --file-header %t2 | FileCheck %s
# RUN: echo 'OUTPUT_FORMAT(elf64-s390)' > %t.script
# RUN: ld.lld %t.script %t.o -o %t3
# RUN: llvm-readelf --file-header %t3 | FileCheck %s
# CHECK: ELF Header:
# CHECK-NEXT: Magic: 7f 45 4c 46 02 02 01 00 00 00 00 00 00 00 00 00
# CHECK-NEXT: Class: ELF64
# CHECK-NEXT: Data: 2's complement, big endian
# CHECK-NEXT: Version: 1 (current)
# CHECK-NEXT: OS/ABI: UNIX - System V
# CHECK-NEXT: ABI Version: 0
# CHECK-NEXT: Type: EXEC (Executable file)
# CHECK-NEXT: Machine: IBM S/390
# CHECK-NEXT: Version: 0x1
# CHECK-NEXT: Entry point address:
# CHECK-NEXT: Start of program headers: 64 (bytes into file)
# CHECK-NEXT: Start of section headers:
# CHECK-NEXT: Flags: 0x0
# CHECK-NEXT: Size of this header: 64 (bytes)
# CHECK-NEXT: Size of program headers: 56 (bytes)
.globl _start
_start:

View File

@@ -0,0 +1,18 @@
; REQUIRES: systemz
;; Test we can infer the e_machine value EM_S390 from a bitcode file.
; RUN: llvm-as %s -o %t.o
; RUN: ld.lld %t.o -o %t
; RUN: llvm-readobj -h %t | FileCheck %s
; CHECK: Class: 64-bit
; CHECK: DataEncoding: BigEndian
; CHECK: Machine: EM_S390
target datalayout = "E-m:e-i1:8:16-i8:8:16-i64:64-f128:64-v128:64-a:8:16-n32:64"
target triple = "s390x-unknown-linux-gnu"
define void @_start() {
entry:
ret void
}

View File

@@ -0,0 +1,16 @@
# REQUIRES: systemz
# RUN: llvm-mc -filetype=obj -triple=s390x-unknown-linux %s -o %t.o
# RUN: llvm-mc -filetype=obj -triple=s390x-unknown-linux %p/Inputs/shared.s -o %t2.o
# RUN: ld.lld -shared %t2.o -soname=%t2.so -o %t2.so
# RUN: ld.lld -dynamic-linker /lib/ld64.so.1 %t.o %t2.so -o %t
# RUN: llvm-readelf -S -r %t | FileCheck %s
# CHECK: .got PROGBITS {{.*}} {{.*}} 000020 00 WA 0 0 8
# CHECK: Relocation section '.rela.dyn' at offset {{.*}} contains 1 entries:
# CHECK: {{.*}} 000000010000000a R_390_GLOB_DAT 0000000000000000 bar + 0
.global _start
_start:
lgrl %r1,bar@GOT

View File

@@ -0,0 +1,48 @@
# REQUIRES: systemz
## Verify that R_390_GOTENT optimization is not performed on misaligned symbols.
# RUN: llvm-mc -filetype=obj -relax-relocations -triple=s390x-unknown-linux %s -o %t.o
# RUN: ld.lld %t.o -o %t1
# RUN: llvm-readelf -S -r -x .got -x .got.plt %t1 | FileCheck --check-prefixes=CHECK %s
# RUN: llvm-objdump --no-print-imm-hex -d %t1 | FileCheck --check-prefix=DISASM %s
## We retain one .got entry for the unaligned symbol.
# CHECK: Name Type Address Off Size ES Flg Lk Inf Al
# CHECK: .got PROGBITS 00000000010021e0 0001e0 000020 00 WA 0 0 8
# CHECK-NEXT: .relro_padding NOBITS 0000000001002200 000200 000e00 00 WA 0 0 1
# CHECK-NEXT: .data PROGBITS 0000000001003200 000200 000006 00 WA 0 0 2
# CHECK-LABEL: Hex dump of section '.got':
# CHECK-NEXT: 0x010021e0 00000000 00000000 00000000 00000000
# CHECK-NEXT: 0x010021f0 00000000 00000000 00000000 01003205
# DISASM: Disassembly of section .text:
# DISASM: <_start>:
# DISASM-NEXT: larl %r1, 0x1003200
# DISASM-NEXT: larl %r1, 0x1003200
# DISASM-NEXT: lgrl %r1, 0x10021f8
# DISASM-NEXT: lgrl %r1, 0x10021f8
.data
.globl var_align
.hidden var_align
.align 2
var_align:
.long 0
.data
.globl var_unalign
.hidden var_unalign
.align 2
.byte 0
var_unalign:
.byte 0
.text
.globl _start
.type _start, @function
_start:
lgrl %r1, var_align@GOT
lgrl %r1, var_align@GOT
lgrl %r1, var_unalign@GOT
lgrl %r1, var_unalign@GOT

View File

@@ -0,0 +1,68 @@
# REQUIRES: systemz
# RUN: llvm-mc -filetype=obj -relax-relocations -triple=s390x-unknown-linux %s -o %t.o
# RUN: llvm-mc -filetype=obj -relax-relocations -triple=s390x-unknown-linux %S/Inputs/gotpc-relax-und-dso.s -o %tdso.o
# RUN: ld.lld -shared %tdso.o -soname=t.so -o %t.so
# RUN: ld.lld --hash-style=sysv -shared %t.o %t.so -o %t
# RUN: llvm-readelf -r %t | FileCheck --check-prefix=RELOC %s
# RUN: llvm-objdump --no-print-imm-hex -d %t | FileCheck --check-prefix=DISASM %s
# RELOC-LABEL: Relocation section '.rela.dyn' at offset {{.*}} contains 3 entries:
# RELOC: 00000000000023f8 000000010000000a R_390_GLOB_DAT 00000000000012d8 foo + 0
# RELOC: 0000000000002400 000000030000000a R_390_GLOB_DAT 0000000000000000 und + 0
# RELOC: 0000000000002408 000000040000000a R_390_GLOB_DAT 0000000000000000 dsofoo + 0
# DISASM: Disassembly of section .text:
# DISASM-EMPTY:
# DISASM-NEXT: <foo>:
# DISASM-NEXT: bc 0, 0
# DISASM: <hid>:
# DISASM-NEXT: bc 0, 0
# DISASM: <_start>:
# DISASM-NEXT: lgrl %r1, 0x2400
# DISASM-NEXT: lgrl %r1, 0x2400
# DISASM-NEXT: lgrl %r1, 0x2408
# DISASM-NEXT: lgrl %r1, 0x2408
# DISASM-NEXT: larl %r1, 0x12dc
# DISASM-NEXT: larl %r1, 0x12dc
# DISASM-NEXT: lgrl %r1, 0x23f8
# DISASM-NEXT: lgrl %r1, 0x23f8
# DISASM-NEXT: lgrl %r1, 0x2400
# DISASM-NEXT: lgrl %r1, 0x2400
# DISASM-NEXT: lgrl %r1, 0x2408
# DISASM-NEXT: lgrl %r1, 0x2408
# DISASM-NEXT: larl %r1, 0x12dc
# DISASM-NEXT: larl %r1, 0x12dc
# DISASM-NEXT: lgrl %r1, 0x23f8
# DISASM-NEXT: lgrl %r1, 0x23f8
.text
.globl foo
.type foo, @function
foo:
nop
.globl hid
.hidden hid
.type hid, @function
hid:
nop
.globl _start
.type _start, @function
_start:
lgrl %r1, und@GOT
lgrl %r1, und@GOT
lgrl %r1, dsofoo@GOT
lgrl %r1, dsofoo@GOT
lgrl %r1, hid@GOT
lgrl %r1, hid@GOT
lgrl %r1, foo@GOT
lgrl %r1, foo@GOT
lgrl %r1, und@GOT
lgrl %r1, und@GOT
lgrl %r1, dsofoo@GOT
lgrl %r1, dsofoo@GOT
lgrl %r1, hid@GOT
lgrl %r1, hid@GOT
lgrl %r1, foo@GOT
lgrl %r1, foo@GOT

View File

@@ -0,0 +1,91 @@
# REQUIRES: systemz
## Test R_390_GOTENT optimization.
# RUN: llvm-mc -filetype=obj -relax-relocations -triple=s390x-unknown-linux %s -o %t.o
# RUN: ld.lld %t.o -o %t1 --no-apply-dynamic-relocs
# RUN: llvm-readelf -S -r -x .got.plt %t1 | FileCheck --check-prefixes=CHECK,NOAPPLY %s
# RUN: ld.lld %t.o -o %t1 --apply-dynamic-relocs
# RUN: llvm-readelf -S -r -x .got.plt %t1 | FileCheck --check-prefixes=CHECK,APPLY %s
# RUN: ld.lld %t.o -o %t1
# RUN: llvm-objdump --no-print-imm-hex -d %t1 | FileCheck --check-prefix=DISASM %s
## --no-relax disables GOT optimization.
# RUN: ld.lld --no-relax %t.o -o %t2
# RUN: llvm-objdump --no-print-imm-hex -d %t2 | FileCheck --check-prefix=NORELAX %s
## In our implementation, .got is retained even if all GOT-generating relocations are optimized.
# CHECK: Name Type Address Off Size ES Flg Lk Inf Al
# CHECK: .iplt PROGBITS 0000000001001240 000240 000020 00 AX 0 0 16
# CHECK-NEXT: .got PROGBITS 0000000001002260 000260 000018 00 WA 0 0 8
# CHECK-NEXT: .relro_padding NOBITS 0000000001002278 000278 000d88 00 WA 0 0 1
# CHECK-NEXT: .got.plt PROGBITS 0000000001003278 000278 000008 00 WA 0 0 8
## There is one R_S390_IRELATIVE relocation.
# CHECK-LABEL: Relocation section '.rela.dyn' at offset {{.*}} contains 1 entries:
# CHECK: 0000000001003278 000000000000003d R_390_IRELATIVE 10011e8
# CHECK-LABEL: Hex dump of section '.got.plt':
# NOAPPLY-NEXT: 0x01003278 00000000 00000000
# APPLY-NEXT: 0x01003278 00000000 010011e8
# DISASM: Disassembly of section .text:
# DISASM: 00000000010011e0 <foo>:
# DISASM-NEXT: bc 0, 0
# DISASM: 00000000010011e4 <hid>:
# DISASM-NEXT: bc 0, 0
# DISASM: 00000000010011e8 <ifunc>:
# DISASM-NEXT: br %r14
# DISASM: 00000000010011ea <_start>:
# DISASM-NEXT: larl %r1, 0x10011e0
# DISASM-NEXT: larl %r1, 0x10011e0
# DISASM-NEXT: larl %r1, 0x10011e4
# DISASM-NEXT: larl %r1, 0x10011e4
# DISASM-NEXT: lgrl %r1, 0x1003278
# DISASM-NEXT: lgrl %r1, 0x1003278
# DISASM-NEXT: larl %r1, 0x10011e0
# DISASM-NEXT: larl %r1, 0x10011e0
# DISASM-NEXT: larl %r1, 0x10011e4
# DISASM-NEXT: larl %r1, 0x10011e4
# DISASM-NEXT: lgrl %r1, 0x1003278
# DISASM-NEXT: lgrl %r1, 0x1003278
# NORELAX-LABEL: <_start>:
# NORELAX-COUNT-12: lgrl
.text
.globl foo
.text
.globl foo
.type foo, @function
foo:
nop
.globl hid
.hidden hid
.type hid, @function
hid:
nop
.text
.type ifunc STT_GNU_IFUNC
.globl ifunc
.type ifunc, @function
ifunc:
br %r14
.globl _start
.type _start, @function
_start:
lgrl %r1, foo@GOT
lgrl %r1, foo@GOT
lgrl %r1, hid@GOT
lgrl %r1, hid@GOT
lgrl %r1, ifunc@GOT
lgrl %r1, ifunc@GOT
lgrl %r1, foo@GOT
lgrl %r1, foo@GOT
lgrl %r1, hid@GOT
lgrl %r1, hid@GOT
lgrl %r1, ifunc@GOT
lgrl %r1, ifunc@GOT

View File

@@ -0,0 +1,75 @@
# REQUIRES: systemz
# RUN: llvm-mc -filetype=obj -triple=s390x-none-linux-gnu %s -o %t.o
# RUN: ld.lld -static %t.o -o %t
# RUN: ld.lld -static %t.o -o %t.apply --apply-dynamic-relocs
# RUN: llvm-readelf --section-headers --relocations --symbols %t | FileCheck %s
# RUN: llvm-readelf -x .got.plt %t | FileCheck %s --check-prefix=NO-APPLY-RELOC
# RUN: llvm-readelf -x .got.plt %t.apply | FileCheck %s --check-prefix=APPLY-RELOC
# RUN: llvm-objdump --no-print-imm-hex -d --no-show-raw-insn %t | FileCheck %s --check-prefix=DISASM
# CHECK: Section Headers:
# CHECK-NEXT: [Nr] Name Type Address Off Size ES Flg Lk Inf Al
# CHECK-NEXT: [ 0] NULL 0000000000000000 000000 000000 00 0 0 0
# CHECK-NEXT: [ 1] .rela.dyn RELA 0000000001000158 000158 000030 18 AI 0 4 8
# CHECK-NEXT: [ 2] .text PROGBITS 0000000001001188 000188 00001c 00 AX 0 0 4
# CHECK-NEXT: [ 3] .iplt PROGBITS 00000000010011b0 0001b0 000040 00 AX 0 0 16
# CHECK-NEXT: [ 4] .got.plt PROGBITS 00000000010021f0 0001f0 000010 00 WA 0 0 8
# CHECK: Relocation section '.rela.dyn' at offset 0x158 contains 2 entries:
# CHECK-NEXT: Offset Info Type Symbol's Value Symbol's Name + Addend
# CHECK-NEXT: 00000000010021f0 000000000000003d R_390_IRELATIVE 1001188
# CHECK-NEXT: 00000000010021f8 000000000000003d R_390_IRELATIVE 100118a
# CHECK: Symbol table '.symtab' contains 6 entries:
# CHECK-NEXT: Num: Value Size Type Bind Vis Ndx Name
# CHECK-NEXT: 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
# CHECK-NEXT: 1: 0000000001000158 0 NOTYPE LOCAL HIDDEN 1 __rela_iplt_start
# CHECK-NEXT: 2: 0000000001000188 0 NOTYPE LOCAL HIDDEN 1 __rela_iplt_end
# CHECK-NEXT: 3: 0000000001001188 0 IFUNC GLOBAL DEFAULT 2 foo
# CHECK-NEXT: 4: 000000000100118a 0 IFUNC GLOBAL DEFAULT 2 bar
# CHECK-NEXT: 5: 000000000100118c 0 NOTYPE GLOBAL DEFAULT 2 _start
# NO-APPLY-RELOC-LABEL: Hex dump of section '.got.plt':
# NO-APPLY-RELOC-NEXT: 0x010021f0 00000000 00000000 00000000 00000000
# NO-APPLY-RELOC-EMPTY:
# APPLY-RELOC-LABEL: Hex dump of section '.got.plt':
# APPLY-RELOC-NEXT: 0x010021f0 00000000 01001188 00000000 0100118a
# APPLY-RELOC-EMPTY:
# DISASM: Disassembly of section .text:
# DISASM: 0000000001001188 <foo>:
# DISASM-NEXT: br %r14
# DISASM: 000000000100118a <bar>:
# DISASM-NEXT: br %r14
# DISASM: 000000000100118c <_start>:
# DISASM-NEXT: brasl %r14, 0x10011b0
# DISASM-NEXT: brasl %r14, 0x10011d0
# DISASM-NEXT: larl %r2, 0x1000158
# DISASM-NEXT: larl %r2, 0x1000188
# DISASM: Disassembly of section .iplt:
# DISASM: <.iplt>:
# DISASM: 10011b0: larl %r1, 0x10021f0
# DISASM-NEXT: 10011b6: lg %r1, 0(%r1)
# DISASM-NEXT: 10011bc: br %r1
# DISASM: 10011d0: larl %r1, 0x10021f8
# DISASM-NEXT: 10011d6: lg %r1, 0(%r1)
# DISASM-NEXT: 10011dc: br %r1
.text
.type foo STT_GNU_IFUNC
.globl foo
foo:
br %r14
.type bar STT_GNU_IFUNC
.globl bar
bar:
br %r14
.globl _start
_start:
brasl %r14, foo@plt
brasl %r14, bar@plt
larl %r2, __rela_iplt_start
larl %r2, __rela_iplt_end

View File

@@ -0,0 +1,27 @@
# REQUIRES: systemz
# RUN: llvm-mc -filetype=obj -triple=s390x-unknown-linux %p/Inputs/systemz-init.s -o systemz-init.o
# RUN: llvm-mc -filetype=obj -triple=s390x-unknown-linux %s -o %t.o
# RUN: ld.lld -dynamic-linker /lib/ld64.so.1 %t.o systemz-init.o -o %t
# RUN: llvm-objdump -d --no-show-raw-insn -j .init %t | FileCheck %s
# glibc < 2.39 used to align .init and .fini code at a 4-byte boundary.
# When that happens, the linker must not pad the code with invalid
# instructions, e.g. null bytes.
.section .init,"ax",@progbits
brasl %r14, startup
# CHECK: <.init>:
# CHECK-NEXT: brasl %r14,
# CHECK-NEXT: bcr 0, %r7
# CHECK-NEXT: lg %r4, 272(%r15)
.text
.globl startup
.p2align 4
startup:
br %r14
.globl main
.p2align 4
main:
br %r14

View File

@@ -0,0 +1,38 @@
# REQUIRES: systemz
# RUN: llvm-mc -filetype=obj -triple=s390x-unknown-linux %s -o %t1.o
## Check -pie.
# RUN: ld.lld -pie %t1.o -o %t
# RUN: llvm-readelf --file-headers --program-headers --dynamic %t | FileCheck %s
# CHECK: ELF Header:
# CHECK-NEXT: Magic: 7f 45 4c 46 02 02 01 00 00 00 00 00 00 00 00 00
# CHECK-NEXT: Class: ELF64
# CHECK-NEXT: Data: 2's complement, big endian
# CHECK-NEXT: Version: 1 (current)
# CHECK-NEXT: OS/ABI: UNIX - System V
# CHECK-NEXT: ABI Version: 0
# CHECK-NEXT: Type: DYN (Shared object file)
# CHECK-NEXT: Machine: IBM S/390
# CHECK-NEXT: Version: 0x1
# CHECK: Program Headers:
# CHECK-NEXT: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
# CHECK-NEXT: PHDR 0x000040 0x0000000000000040 0x0000000000000040 0x000188 0x000188 R 0x8
# CHECK-NEXT: LOAD 0x000000 0x0000000000000000 0x0000000000000000 0x00020d 0x00020d R 0x1000
# CHECK-NEXT: LOAD 0x000210 0x0000000000002210 0x0000000000002210 0x000090 0x000df0 RW 0x1000
# CHECK-NEXT: DYNAMIC 0x000210 0x0000000000002210 0x0000000000002210 0x000090 0x000090 RW 0x8
# CHECK-NEXT: GNU_RELRO 0x000210 0x0000000000002210 0x0000000000002210 0x000090 0x000df0 R 0x1
# CHECK-NEXT: GNU_STACK 0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW 0x0
# CHECK: Dynamic section at offset 0x210 contains 9 entries:
# CHECK-NEXT: Tag Type Name/Value
# CHECK-NEXT: 0x000000006ffffffb (FLAGS_1) PIE
## Check -nopie
# RUN: ld.lld -no-pie %t1.o -o %t2
# RUN: llvm-readelf --file-headers %t2 | FileCheck %s --check-prefix=NOPIE
# NOPIE-NOT: Type: DYN
.globl _start
_start:

View File

@@ -0,0 +1,83 @@
# REQUIRES: systemz
# RUN: echo '.globl bar, weak; .type bar,@function; .type weak,@function; bar: weak:' > %t1.s
# RUN: llvm-mc -filetype=obj -triple=s390x-unknown-linux %t1.s -o %t1.o
# RUN: ld.lld -shared %t1.o -soname=t1.so -o %t1.so
# RUN: llvm-mc -filetype=obj -triple=s390x-unknown-linux %s -o %t.o
# RUN: ld.lld %t.o %t1.so -z separate-code -o %t
# RUN: llvm-readelf -S -s -r -x .got.plt %t | FileCheck %s
# RUN: llvm-objdump -d %t | FileCheck --check-prefixes=DIS %s
# CHECK: Section Headers:
# CHECK: .plt PROGBITS 0000000001001020 001020 000060 00 AX 0 0 16
# CHECK: .got PROGBITS 00000000010020d0 0020d0 000018 00 WA 0 0 8
# CHECK: .got.plt PROGBITS 00000000010030e8 0020e8 000010 00 WA 0 0 8
# CHECK: Relocation section '.rela.plt' at offset {{.*}} contains 2 entries:
# CHECK: 00000000010030e8 000000010000000b R_390_JMP_SLOT 0000000000000000 bar + 0
# CHECK: 00000000010030f0 000000020000000b R_390_JMP_SLOT 0000000000000000 weak + 0
## A canonical PLT has a non-zero st_value. bar and weak are called but their
## addresses are not taken, so a canonical PLT is not necessary.
# CHECK: Symbol table '.dynsym' contains 3 entries:
# CHECK-NEXT: Num: Value Size Type Bind Vis Ndx Name
# CHECK-NEXT: 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
# CHECK-NEXT: 1: 0000000000000000 0 FUNC GLOBAL DEFAULT UND bar
# CHECK-NEXT: 2: 0000000000000000 0 FUNC WEAK DEFAULT UND weak
## The .got.plt slots relocated by .rela.plt point to .plt
## This is required by glibc.
# CHECK: Hex dump of section '.got.plt':
# CHECK-NEXT: 0x010030e8 00000000 0100104e 00000000 0100106e
# DIS: Disassembly of section .text:
# DIS: 0000000001001000 <_start>:
# DIS-NEXT: brasl %r14, 0x1001012
# DIS-NEXT: brasl %r14, 0x1001040
# DIS-NEXT: brasl %r14, 0x1001060
# DIS: 0000000001001012 <foo>:
# DIS-NEXT: br %r14
# DIS: Disassembly of section .plt:
# DIS: 0000000001001020 <.plt>:
# DIS-NEXT: 1001020: e3 10 f0 38 00 24 stg %r1, 56(%r15)
# DIS-NEXT: 1001026: c0 10 00 00 08 55 larl %r1, 0x10020d0
# DIS-NEXT: 100102c: d2 07 f0 30 10 08 mvc 48(8,%r15), 8(%r1)
# DIS-NEXT: 1001032: e3 10 10 10 00 04 lg %r1, 16(%r1)
# DIS-NEXT: 1001038: 07 f1 br %r1
# DIS-NEXT: 100103a: 07 00 bcr 0, %r0
# DIS-NEXT: 100103c: 07 00 bcr 0, %r0
# DIS-NEXT: 100103e: 07 00 bcr 0, %r0
# DIS-NEXT: 1001040: c0 10 00 00 10 54 larl %r1, 0x10030e8
# DIS-NEXT: 1001046: e3 10 10 00 00 04 lg %r1, 0(%r1)
# DIS-NEXT: 100104c: 07 f1 br %r1
# DIS-NEXT: 100104e: 0d 10 basr %r1, 0
# DIS-NEXT: 1001050: e3 10 10 0c 00 14 lgf %r1, 12(%r1)
# DIS-NEXT: 1001056: c0 f4 ff ff ff e5 jg 0x1001020
# DIS-NEXT: 100105c: 00 00 <unknown>
# DIS-NEXT: 100105e: 00 00 <unknown>
# DIS-NEXT: 1001060: c0 10 00 00 10 48 larl %r1, 0x10030f0
# DIS-NEXT: 1001066: e3 10 10 00 00 04 lg %r1, 0(%r1)
# DIS-NEXT: 100106c: 07 f1 br %r1
# DIS-NEXT: 100106e: 0d 10 basr %r1, 0
# DIS-NEXT: 1001070: e3 10 10 0c 00 14 lgf %r1, 12(%r1)
# DIS-NEXT: 1001076: c0 f4 ff ff ff d5 jg 0x1001020
# DIS-NEXT: 100107c: 00 00 <unknown>
# DIS-NEXT: 100107e: 00 18 <unknown>
.global _start, foo, bar
.weak weak
_start:
## Use @plt to avoid generating direct references that would force
## allocation of a canonical PLT entry.
brasl %r14, foo@plt
brasl %r14, bar@plt
brasl %r14, weak@plt
## foo is local and non-preemptable, no PLT is generated.
foo:
br %r14

View File

@@ -0,0 +1,32 @@
# REQUIRES: systemz
# RUN: llvm-mc -filetype=obj -triple=s390x %s -o %t.o
# RUN: llvm-mc -filetype=obj -triple=s390x %S/Inputs/abs255.s -o %t255.o
# RUN: llvm-mc -filetype=obj -triple=s390x %S/Inputs/abs256.s -o %t256.o
# RUN: llvm-mc -filetype=obj -triple=s390x %S/Inputs/abs257.s -o %t257.o
# RUN: ld.lld %t.o %t256.o -o %t
# RUN: llvm-readelf -x .data %t | FileCheck %s
# CHECK: 0x{{[0-9a-f]+}} ff80ffff 8000ffff ffff8000 0000ffff
# CHECK-NEXT: ffffffff ffff8000 00000000 0000
# RUN: not ld.lld %t.o %t255.o -o /dev/null 2>&1 | FileCheck --check-prefix=OVERFLOW1 %s
# OVERFLOW1: relocation R_390_8 out of range: -129 is not in [-128, 255]
# OVERFLOW1: relocation R_390_16 out of range: -32769 is not in [-32768, 65535]
# OVERFLOW1: relocation R_390_32 out of range: -2147483649 is not in [-2147483648, 4294967295]
# RUN: not ld.lld %t.o %t257.o -o /dev/null 2>&1 | FileCheck --check-prefix=OVERFLOW2 %s
# OVERFLOW2: relocation R_390_8 out of range: 256 is not in [-128, 255]
# OVERFLOW2: relocation R_390_16 out of range: 65536 is not in [-32768, 65535]
# OVERFLOW2: relocation R_390_32 out of range: 4294967296 is not in [-2147483648, 4294967295]
.globl _start
_start:
.data
.byte foo - 1
.byte foo - 384
.word foo + 0xfeff
.word foo - 0x8100
.long foo + 0xfffffeff
.long foo - 0x80000100
.quad foo + 0xfffffffffffffeff
.quad foo - 0x8000000000000100

View File

@@ -0,0 +1,21 @@
# REQUIRES: systemz
# RUN: llvm-mc -filetype=obj -triple=s390x -defsym DISP=291 %s -o %t1.o
# RUN: llvm-mc -filetype=obj -triple=s390x -defsym DISP=4095 %s -o %t2.o
# RUN: llvm-mc -filetype=obj -triple=s390x -defsym DISP=4096 %s -o %t3.o
# RUN: ld.lld --section-start=.text=0x0 %t1.o -o %t1out
# RUN: ld.lld --section-start=.text=0x0 %t2.o -o %t2out
# RUN: not ld.lld --section-start=.text=0x0 %t3.o -o /dev/null 2>&1 | FileCheck %s --check-prefix RANGE
# RANGE: relocation R_390_12 out of range: 4096 is not in [0, 4095]
# RUN: llvm-readelf --hex-dump=.text %t1out | FileCheck %s -DINSN=58678123 --check-prefix DUMP
# RUN: llvm-readelf --hex-dump=.text %t2out | FileCheck %s -DINSN=58678fff --check-prefix DUMP
# DUMP: 0x00000000 [[INSN]]
.text
.globl _start
_start:
.reloc .+2, R_390_12, DISP
l %r6, 0(%r7,%r8)

View File

@@ -0,0 +1,21 @@
# REQUIRES: systemz
# RUN: llvm-mc -filetype=obj -triple=s390x -defsym DISP=74565 %s -o %t1.o
# RUN: llvm-mc -filetype=obj -triple=s390x -defsym DISP=524287 %s -o %t2.o
# RUN: llvm-mc -filetype=obj -triple=s390x -defsym DISP=524288 %s -o %t3.o
# RUN: ld.lld --section-start=.text=0x0 %t1.o -o %t1out
# RUN: ld.lld --section-start=.text=0x0 %t2.o -o %t2out
# RUN: not ld.lld --section-start=.text=0x0 %t3.o -o /dev/null 2>&1 | FileCheck %s --check-prefix RANGE
# RANGE: relocation R_390_20 out of range: 524288 is not in [-524288, 524287]
# RUN: llvm-readelf --hex-dump=.text %t1out | FileCheck %s -DINSN="e3678345 1204" --check-prefix DUMP
# RUN: llvm-readelf --hex-dump=.text %t2out | FileCheck %s -DINSN="e3678fff 7f04" --check-prefix DUMP
# DUMP: 0x00000000 [[INSN]]
.text
.globl _start
_start:
.reloc .+2, R_390_20, DISP
lg %r6, 0(%r7,%r8)

View File

@@ -0,0 +1,92 @@
# REQUIRES: systemz
# RUN: llvm-mc -filetype=obj -triple=s390x-unknown-linux %s -o %t.o
# RUN: ld.lld -z norelro -shared %t.o -soname=t.so -o %t.so
## Note: Without norelro the distance between .got and .got.plt causes
## R_390_GOTPLT12 relocations to always overflow.
# RUN: llvm-readelf -S -x .data %t.so | FileCheck %s
# RUN: llvm-objdump -d --no-show-raw-insn %t.so | FileCheck %s --check-prefix=DISASM
# CHECK: Section Headers:
# CHECK: .got PROGBITS 0000000000002458
# CHECK: .got.plt PROGBITS 0000000000002480
## Note: _GLOBAL_OFFSET_TABLE is at .got
## GOT (foo) is at .got + 24 == 0x2470
## GOT (bar) is at .got + 32 == 0x2478
## GOTPLT (foo) is at .got.plt + 0 == .got + 40 == 0x2480
## GOTPLT (bar) is at .got.plt + 8 == .got + 48 == 0x2488
# DISASM: larl %r12, 0x2458
# DISASM-NEXT: larl %r1, 0x2470
# DISASM-NEXT: larl %r1, 0x2478
# DISASM-NEXT: larl %r1, 0x2480
# DISASM-NEXT: larl %r1, 0x2488
# DISASM-NEXT: l %r1, 24(%r12)
# DISASM-NEXT: l %r1, 32(%r12)
# DISASM-NEXT: l %r1, 40(%r12)
# DISASM-NEXT: l %r1, 48(%r12)
# DISASM-NEXT: lg %r1, 24(%r12)
# DISASM-NEXT: lg %r1, 32(%r12)
# DISASM-NEXT: lg %r1, 40(%r12)
# DISASM-NEXT: lg %r1, 48(%r12)
# CHECK: Hex dump of section '.data':
# CHECK-NEXT: 00180020 00280030 00000018 00000020
# CHECK-NEXT: 00000028 00000030 00000000 00000018
# CHECK-NEXT: 00000000 00000020 00000000 00000028
# CHECK-NEXT: 00000000 00000030
.text
larl %r12, _GLOBAL_OFFSET_TABLE_
.reloc .+2, R_390_GOTENT, foo+2
larl %r1, 0
.reloc .+2, R_390_GOTENT, bar+2
larl %r1, 0
.reloc .+2, R_390_GOTPLTENT, foo+2
larl %r1, 0
.reloc .+2, R_390_GOTPLTENT, bar+2
larl %r1, 0
.reloc .+2, R_390_GOT12, foo
l %r1, 0(%r12)
.reloc .+2, R_390_GOT12, bar
l %r1, 0(%r12)
.reloc .+2, R_390_GOTPLT12, foo
l %r1, 0(%r12)
.reloc .+2, R_390_GOTPLT12, bar
l %r1, 0(%r12)
.reloc .+2, R_390_GOT20, foo
lg %r1, 0(%r12)
.reloc .+2, R_390_GOT20, bar
lg %r1, 0(%r12)
.reloc .+2, R_390_GOTPLT20, foo
lg %r1, 0(%r12)
.reloc .+2, R_390_GOTPLT20, bar
lg %r1, 0(%r12)
.data
.reloc ., R_390_GOT16, foo
.space 2
.reloc ., R_390_GOT16, bar
.space 2
.reloc ., R_390_GOTPLT16, foo
.space 2
.reloc ., R_390_GOTPLT16, bar
.space 2
.reloc ., R_390_GOT32, foo
.space 4
.reloc ., R_390_GOT32, bar
.space 4
.reloc ., R_390_GOTPLT32, foo
.space 4
.reloc ., R_390_GOTPLT32, bar
.space 4
.reloc ., R_390_GOT64, foo
.space 8
.reloc ., R_390_GOT64, bar
.space 8
.reloc ., R_390_GOTPLT64, foo
.space 8
.reloc ., R_390_GOTPLT64, bar
.space 8

View File

@@ -0,0 +1,36 @@
# REQUIRES: systemz
# RUN: llvm-mc -filetype=obj -triple=s390x-unknown-linux %s -o %t.o
# RUN: ld.lld -shared %t.o -soname=t.so -o %t.so
# RUN: llvm-readelf -S -s -x .data %t.so | FileCheck %s
# CHECK: Section Headers:
# CHECK: .plt PROGBITS 0000000000001290
# CHECK: .got PROGBITS 0000000000002390
# CHECK: Symbol table '.symtab'
# CHECK: 0000000000001288 {{.*}} bar
## Note: foo is the first (and only) PLT entry, which resides at .plt + 32
## PLTOFF (foo) is (.plt + 32) - .got == 0x12b0 - 0x2390 == 0xffffef20
## GOTOFF (bar) is bar - .got == 0x1288 - 0x2390 == 0xffffeef8
# CHECK: Hex dump of section '.data':
# CHECK-NEXT: eef8ef20 ffffeef8 ffffef20 ffffffff
# CHECK-NEXT: ffffeef8 ffffffff ffffef20
bar:
br %r14
.data
.reloc ., R_390_GOTOFF16, bar
.space 2
.reloc ., R_390_PLTOFF16, foo
.space 2
.reloc ., R_390_GOTOFF, bar
.space 4
.reloc ., R_390_PLTOFF32, foo
.space 4
.reloc ., R_390_GOTOFF64, bar
.space 8
.reloc ., R_390_PLTOFF64, foo
.space 8

View File

@@ -0,0 +1,39 @@
# REQUIRES: systemz
# RUN: rm -rf %t && split-file %s %t
## Check recompile with -fPIC error message
# RUN: llvm-mc -filetype=obj -triple=s390x-unknown-linux %t/shared.s -o %t/shared.o
# RUN: not ld.lld -shared %t/shared.o -o /dev/null 2>&1 | FileCheck %s
# CHECK: error: relocation R_390_PC16 cannot be used against symbol '_shared'; recompile with -fPIC
# CHECK: >>> defined in {{.*}}
# CHECK: >>> referenced by {{.*}}:(.data+0x1)
## Check patching of negative addends
# RUN: llvm-mc -filetype=obj -triple=s390x -defsym ADDEND=1 %t/addend.s -o %t/1.o
# RUN: llvm-mc -filetype=obj -triple=s390x -defsym ADDEND=32768 %t/addend.s -o %t/2.o
# RUN: llvm-mc -filetype=obj -triple=s390x -defsym ADDEND=32769 %t/addend.s -o %t/3.o
# RUN: ld.lld --section-start=.text=0x0 %t/1.o -o %t/1out
# RUN: ld.lld --section-start=.text=0x0 %t/2.o -o %t/2out
# RUN: not ld.lld --section-start=.text=0x0 %t/3.o -o /dev/null 2>&1 | FileCheck %s -DFILE=%t/3.o --check-prefix RANGE
# RANGE: error: [[FILE]]:(.text+0x0): relocation R_390_PC16 out of range
# RUN: llvm-readelf --hex-dump=.text %t/1out | FileCheck %s -DADDEND=ffff --check-prefix DUMP
# RUN: llvm-readelf --hex-dump=.text %t/2out | FileCheck %s -DADDEND=8000 --check-prefix DUMP
# DUMP: 0x00000000 [[ADDEND]]
#--- shared.s
.data
.byte 0xe8
.word _shared - .
#--- addend.s
.text
.globl _start
_start:
.reloc ., R_390_PC16, .text-ADDEND
.space 2

View File

@@ -0,0 +1,39 @@
# REQUIRES: systemz
# RUN: rm -rf %t && split-file %s %t
## Check recompile with -fPIC error message
# RUN: llvm-mc -filetype=obj -triple=s390x-unknown-linux %t/shared.s -o %t/shared.o
# RUN: not ld.lld -shared %t/shared.o -o /dev/null 2>&1 | FileCheck %s
# CHECK: error: relocation R_390_PC32 cannot be used against symbol '_shared'; recompile with -fPIC
# CHECK: >>> defined in {{.*}}
# CHECK: >>> referenced by {{.*}}:(.data+0x1)
## Check patching of negative addends
# RUN: llvm-mc -filetype=obj -triple=s390x -defsym ADDEND=1 %t/addend.s -o %t/1.o
# RUN: llvm-mc -filetype=obj -triple=s390x -defsym ADDEND=2147483648 %t/addend.s -o %t/2.o
# RUN: llvm-mc -filetype=obj -triple=s390x -defsym ADDEND=2147483649 %t/addend.s -o %t/3.o
# RUN: ld.lld --section-start=.text=0x0 %t/1.o -o %t/1out
# RUN: ld.lld --section-start=.text=0x0 %t/2.o -o %t/2out
# RUN: not ld.lld --section-start=.text=0x0 %t/3.o -o /dev/null 2>&1 | FileCheck %s -DFILE=%t/3.o --check-prefix RANGE
# RANGE: error: [[FILE]]:(.text+0x0): relocation R_390_PC32 out of range
# RUN: llvm-readelf --hex-dump=.text %t/1out | FileCheck %s -DADDEND=ffffffff --check-prefix DUMP
# RUN: llvm-readelf --hex-dump=.text %t/2out | FileCheck %s -DADDEND=80000000 --check-prefix DUMP
# DUMP: 0x00000000 [[ADDEND]]
#--- shared.s
.data
.byte 0xe8
.long _shared - .
#--- addend.s
.text
.globl _start
_start:
.reloc ., R_390_PC32, .text-ADDEND
.space 4

View File

@@ -0,0 +1,68 @@
# REQUIRES: systemz
# RUN: llvm-mc --filetype=obj --triple=s390x-unknown-linux -mcpu=z13 %s -o %t.o
# RUN: ld.lld %t.o --defsym foo16=pc16dbl+4 --defsym bar16=pc16dbl --defsym foo32=pc32dbl+6 --defsym bar32=pc32dbl --defsym foo12=pc12dbl+6 --defsym bar12=pc12dbl --defsym foo24=pc24dbl+6 --defsym bar24=pc24dbl -o %t
# RUN: llvm-objdump --no-show-raw-insn --mcpu=z13 -d %t | FileCheck %s --check-prefix=CHECK
# CHECK: 0000000001001120 <pc16dbl>:
# CHECK: je 0x1001124
# CHECK: jne 0x1001120
# CHECK: 0000000001001128 <pc32dbl>:
# CHECK: jge 0x100112e
# CHECK: jgne 0x1001128
# CHECK: 0000000001001134 <pc12dbl>:
# CHECK: bprp 5, 0x100113a, 0x1001134
# CHECK: bprp 6, 0x1001134, 0x100113a
# CHECK: 0000000001001140 <pc24dbl>:
# CHECK: bprp 5, 0x1001140, 0x1001146
# CHECK: bprp 6, 0x1001146, 0x1001140
# RUN: ld.lld %t.o --defsym foo16=pc16dbl+0xfffe --defsym bar16=pc16dbl+4-0x10000 --defsym foo32=pc32dbl+0xfffffffe --defsym bar32=pc32dbl+6-0x100000000 --defsym foo12=pc12dbl+0xffe --defsym bar12=pc12dbl+6-0x1000 --defsym foo24=pc24dbl+0xfffffe --defsym bar24=pc24dbl+6-0x1000000 -o %t.limits
# RUN: llvm-objdump --no-show-raw-insn --mcpu=z13 -d %t.limits | FileCheck %s --check-prefix=LIMITS
# LIMITS: je 0x101111e
# LIMITS-NEXT: jne 0xff1124
# LIMITS: jge 0x101001126
# LIMITS-NEXT: jgne 0xffffffff0100112e
# LIMITS: bprp 5, 0x1002132, 0x1001134
# LIMITS-NEXT: bprp 6, 0x100013a, 0x100113a
# LIMITS: bprp 5, 0x1001140, 0x200113e
# LIMITS-NEXT: bprp 6, 0x1001146, 0x1146
# RUN: not ld.lld %t.o --defsym foo16=pc16dbl+0x10000 --defsym bar16=pc16dbl+4-0x10002 --defsym foo32=pc32dbl+0x100000000 --defsym bar32=pc32dbl+6-0x100000002 --defsym foo12=pc12dbl+0x1000 --defsym bar12=pc12dbl+6-0x1002 --defsym foo24=pc24dbl+0x1000000 --defsym bar24=pc24dbl+6-0x1000002 -o /dev/null 2>&1 | FileCheck -DFILE=%t.o --check-prefix=ERROR-RANGE %s
# ERROR-RANGE: error: [[FILE]]:(.text+0x2): relocation R_390_PC16DBL out of range: 65536 is not in [-65536, 65535]; references 'foo16'
# ERROR-RANGE: error: [[FILE]]:(.text+0x6): relocation R_390_PC16DBL out of range: -65538 is not in [-65536, 65535]; references 'bar16'
# ERROR-RANGE: error: [[FILE]]:(.text+0xa): relocation R_390_PC32DBL out of range: 4294967296 is not in [-4294967296, 4294967295]; references 'foo32'
# ERROR-RANGE: error: [[FILE]]:(.text+0x10): relocation R_390_PC32DBL out of range: -4294967298 is not in [-4294967296, 4294967295]; references 'bar32'
# ERROR-RANGE: error: [[FILE]]:(.text+0x15): relocation R_390_PC12DBL out of range: 4096 is not in [-4096, 4095]; references 'foo12'
# ERROR-RANGE: error: [[FILE]]:(.text+0x1b): relocation R_390_PC12DBL out of range: -4098 is not in [-4096, 4095]; references 'bar12'
# ERROR-RANGE: error: [[FILE]]:(.text+0x23): relocation R_390_PC24DBL out of range: 16777216 is not in [-16777216, 16777215]; references 'foo24'
# ERROR-RANGE: error: [[FILE]]:(.text+0x29): relocation R_390_PC24DBL out of range: -16777218 is not in [-16777216, 16777215]; references 'bar24'
# RUN: not ld.lld %t.o --defsym foo16=pc16dbl+1 --defsym bar16=pc16dbl-1 --defsym foo32=pc32dbl+1 --defsym bar32=pc32dbl-1 --defsym foo12=pc12dbl+1 --defsym bar12=pc12dbl-1 --defsym foo24=pc24dbl+1 --defsym bar24=pc24dbl-1 -o /dev/null 2>&1 | FileCheck -DFILE=%t.o --check-prefix=ERROR-ALIGN %s
# ERROR-ALIGN: error: [[FILE]]:(.text+0x2): improper alignment for relocation R_390_PC16DBL: 0x1 is not aligned to 2 bytes
# ERROR-ALIGN-NEXT: error: [[FILE]]:(.text+0x6): improper alignment for relocation R_390_PC16DBL: 0xFFFFFFFFFFFFFFFB is not aligned to 2 bytes
# ERROR-ALIGN-NEXT: error: [[FILE]]:(.text+0xa): improper alignment for relocation R_390_PC32DBL: 0x1 is not aligned to 2 bytes
# ERROR-ALIGN-NEXT: error: [[FILE]]:(.text+0x10): improper alignment for relocation R_390_PC32DBL: 0xFFFFFFFFFFFFFFF9 is not aligned to 2 bytes
# ERROR-ALIGN-NEXT: error: [[FILE]]:(.text+0x15): improper alignment for relocation R_390_PC12DBL: 0x1 is not aligned to 2 bytes
# ERROR-ALIGN-NEXT: error: [[FILE]]:(.text+0x1b): improper alignment for relocation R_390_PC12DBL: 0xFFFFFFFFFFFFFFF9 is not aligned to 2 bytes
# ERROR-ALIGN-NEXT: error: [[FILE]]:(.text+0x23): improper alignment for relocation R_390_PC24DBL: 0x1 is not aligned to 2 bytes
# ERROR-ALIGN-NEXT: error: [[FILE]]:(.text+0x29): improper alignment for relocation R_390_PC24DBL: 0xFFFFFFFFFFFFFFF9 is not aligned to 2 bytes
.global _start
.global pc16dbl
.global pc32dbl
.global pc12dbl
.global pc24dbl
_start:
pc16dbl:
je foo16
jne bar16
pc32dbl:
jge foo32
jgne bar32
pc12dbl:
bprp 5,foo12,0
bprp 6,bar12,0
pc24dbl:
bprp 5,0,foo24
bprp 6,0,bar24

View File

@@ -0,0 +1,142 @@
# REQUIRES: systemz
# RUN: llvm-mc -filetype=obj -triple=s390x-unknown-linux %s -o %t.o
# RUN: echo '.tbss; .globl b, c; b: .zero 4; c:' | llvm-mc -filetype=obj -triple=s390x-unknown-linux - -o %t1.o
# RUN: ld.lld -shared -soname=t1.so %t1.o -o %t1.so
# RUN: ld.lld -shared %t.o %t1.o -o %t.so
# RUN: llvm-readelf -r %t.so | FileCheck --check-prefix=GD-REL %s
# RUN: llvm-objdump -d --no-show-raw-insn %t.so | FileCheck --check-prefix=GD %s
# RUN: llvm-objdump --section .data.rel.ro --full-contents %t.so | FileCheck --check-prefix=GD-DATA %s
# RUN: ld.lld %t.o %t1.o -o %t.le
# RUN: llvm-readelf -r %t.le | FileCheck --check-prefix=NOREL %s
# RUN: llvm-objdump -d --no-show-raw-insn %t.le | FileCheck --check-prefix=LE %s
# RUN: llvm-objdump --section .data.rel.ro --full-contents %t.le | FileCheck --check-prefix=LE-DATA %s
# RUN: ld.lld %t.o %t1.so -o %t.ie
# RUN: llvm-readelf -r %t.ie | FileCheck --check-prefix=IE-REL %s
# RUN: llvm-objdump -d --no-show-raw-insn %t.ie | FileCheck --check-prefix=IE %s
# RUN: llvm-objdump --section .data.rel.ro --full-contents %t.ie | FileCheck --check-prefix=IE-DATA %s
# GD-REL: Relocation section '.rela.dyn' at offset {{.*}} contains 6 entries:
# GD-REL: 0000000000002570 0000000200000036 R_390_TLS_DTPMOD 0000000000000008 a + 0
# GD-REL-NEXT: 0000000000002578 0000000200000037 R_390_TLS_DTPOFF 0000000000000008 a + 0
# GD-REL-NEXT: 0000000000002580 0000000300000036 R_390_TLS_DTPMOD 000000000000000c b + 0
# GD-REL-NEXT: 0000000000002588 0000000300000037 R_390_TLS_DTPOFF 000000000000000c b + 0
# GD-REL-NEXT: 0000000000002590 0000000400000036 R_390_TLS_DTPMOD 0000000000000010 c + 0
# GD-REL-NEXT: 0000000000002598 0000000400000037 R_390_TLS_DTPOFF 0000000000000010 c + 0
## _GLOBAL_OFFSET_TABLE is at 0x2558
# GD: larl %r12, 0x2558
## GOT offset of the TLS module ID / offset pair for a is at 0x2460
# GD-NEXT: lgrl %r2, 0x2460
# GD-NEXT: brasl %r14, 0x1440
# GD-NEXT: lgf %r2, 0(%r2,%r7)
## GOT offset of the TLS module ID / offset pair for b is at 0x2468
# GD-NEXT: lgrl %r2, 0x2468
# GD-NEXT: brasl %r14, 0x1440
# GD-NEXT: lgf %r2, 0(%r2,%r7)
## GOT offset of the TLS module ID / offset pair for c is at 0x2470
# GD-NEXT: lgrl %r2, 0x2470
# GD-NEXT: brasl %r14, 0x1440
# GD-NEXT: lgf %r2, 0(%r2,%r7)
## Constant pool holding GOT offsets of TLS module ID / offset pairs:
# a: 0x2570 / 0x18
# b: 0x2580 / 0x28
# c: 0x2590 / 0x38
# GD-DATA: 2460 00000000 00000018 00000000 00000028
# GD-DATA-NEXT: 2470 00000000 00000038
# NOREL: no relocations
## _GLOBAL_OFFSET_TABLE is at 0x1002230
# LE: larl %r12, 0x1002230
## TP offset of a is at 0x1002218
# LE-NEXT: lgrl %r2, 0x1002218
# LE-NEXT: brcl 0,
# LE-NEXT: lgf %r2, 0(%r2,%r7)
## TP offset of b is at 0x1002220
# LE-NEXT: lgrl %r2, 0x1002220
# LE-NEXT: brcl 0,
# LE-NEXT: lgf %r2, 0(%r2,%r7)
## TP offset of c is at 0x1002228
# LE-NEXT: lgrl %r2, 0x1002228
# LE-NEXT: brcl 0,
# LE-NEXT: lgf %r2, 0(%r2,%r7)
## TP offsets
# a: -8
# b: -4
# c: 0
# LE-DATA: 1002218 ffffffff fffffff8 ffffffff fffffffc
# LE-DATA-NEXT: 1002228 00000000 00000000
# IE-REL: Relocation section '.rela.dyn' at offset {{.*}} contains 2 entries:
# IE-REL: 0000000001002430 0000000200000038 R_390_TLS_TPOFF 0000000000000000 b + 0
# IE-REL-NEXT: 0000000001002438 0000000300000038 R_390_TLS_TPOFF 0000000000000000 c + 0
## _GLOBAL_OFFSET_TABLE is at 0x1002418
# IE: larl %r12, 0x1002418
## TP offset of a is at 0x1002340
# IE-NEXT: lgrl %r2, 0x1002340
# IE-NEXT: brcl 0,
# IE-NEXT: lgf %r2, 0(%r2,%r7)
## GOT offset of the TP offset for b is at 0x1002348
# IE-NEXT: lgrl %r2, 0x1002348
# IE-NEXT: lg %r2, 0(%r2,%r12)
# IE-NEXT: lgf %r2, 0(%r2,%r7)
## GOT offset of the TP offset for c is at 0x1002350
# IE-NEXT: lgrl %r2, 0x1002350
# IE-NEXT: lg %r2, 0(%r2,%r12)
# IE-NEXT: lgf %r2, 0(%r2,%r7)
## TP offsets (a) / GOT offset of TP offsets (b, c)
# a: -4
# b: 0x1002430 / 0x18
# c: 0x1002438 / 0x20
# IE-DATA: 1002340 ffffffff fffffffc 00000000 00000018
# IE-DATA-NEXT: 1002350 00000000 00000020
ear %r7,%a0
sllg %r7,%r1,32
ear %r7,%a1
larl %r12,_GLOBAL_OFFSET_TABLE_
lgrl %r2,.LC0
brasl %r14,__tls_get_offset@PLT:tls_gdcall:a
lgf %r2,0(%r2,%r7)
lgrl %r2,.LC1
brasl %r14,__tls_get_offset@PLT:tls_gdcall:b
lgf %r2,0(%r2,%r7)
lgrl %r2,.LC2
brasl %r14,__tls_get_offset@PLT:tls_gdcall:c
lgf %r2,0(%r2,%r7)
.section .data.rel.ro,"aw"
.align 8
.LC0:
.quad a@TLSGD
.LC1:
.quad b@TLSGD
.LC2:
.quad c@TLSGD
.section .tbss
.globl a
.zero 8
a:
.zero 4

View File

@@ -0,0 +1,87 @@
# REQUIRES: systemz
# RUN: llvm-mc -filetype=obj -triple=s390x-unknown-linux %s -o %t.o
# RUN: ld.lld -shared %t.o -o %t.so
# RUN: llvm-readelf -r %t.so | FileCheck --check-prefix=IE-REL %s
# RUN: llvm-objdump -d --no-show-raw-insn %t.so | FileCheck --check-prefix=IE %s
# RUN: llvm-objdump --section .data --full-contents %t.so | FileCheck --check-prefix=IE-DATA %s
# RUN: ld.lld %t.o -o %t
# RUN: llvm-readelf -r %t | FileCheck --check-prefix=NOREL %s
# RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck --check-prefix=LE %s
# RUN: llvm-objdump --section .data --full-contents %t | FileCheck --check-prefix=LE-DATA %s
# RUN: llvm-objdump --section .got --full-contents %t | FileCheck --check-prefix=LE-GOT %s
# IE-REL: Relocation section '.rela.dyn' at offset {{.*}} contains 4 entries:
# IE-REL: 0000000000003478 000000000000000c R_390_RELATIVE 2460
# IE-REL: 0000000000002460 0000000100000038 R_390_TLS_TPOFF 0000000000000008 a + 0
# IE-REL: 0000000000002468 0000000200000038 R_390_TLS_TPOFF 000000000000000c b + 0
# IE-REL: 0000000000002470 0000000300000038 R_390_TLS_TPOFF 0000000000000010 c + 0
## TP offset for a is at 0x2460
# IE: lgrl %r1, 0x2460
# IE-NEXT: lgf %r1, 0(%r1,%r7)
## TP offset for b is at 0x2468
# IE-NEXT: lgrl %r1, 0x2468
# IE-NEXT: lgf %r1, 0(%r1,%r7)
## TP offset for c is at 0x2470
# IE-NEXT: lgrl %r1, 0x2470
# IE-NEXT: lgf %r1, 0(%r1,%r7)
## Data element: TP offset for a is at 0x2460 (relocated via R_390_RELATIVE above)
# IE-DATA: 3478 00000000 00000000
# NOREL: no relocations
## TP offset for a is at 0x1002250
# LE: lgrl %r1, 0x1002250
# LE-NEXT: lgf %r1, 0(%r1,%r7)
## TP offset for b is at 0x1002258
# LE-NEXT: lgrl %r1, 0x1002258
# LE-NEXT: lgf %r1, 0(%r1,%r7)
## TP offset for c is at 0x1002260
# LE-NEXT: lgrl %r1, 0x1002260
# LE-NEXT: lgf %r1, 0(%r1,%r7)
## Data element: TP offset for a is at 0x1002250
# LE-DATA: 00000000 01002250
## TP offsets in GOT:
# a: -8
# b: -4
# c: 0
# LE-GOT: 1002238 00000000 00000000 00000000 00000000
# LE-GOT: 1002248 00000000 00000000 ffffffff fffffff8
# LE-GOT: 1002258 ffffffff fffffffc 00000000 00000000
ear %r7,%a0
sllg %r7,%r1,32
ear %r7,%a1
lgrl %r1, a@indntpoff
lgf %r1,0(%r1,%r7)
lgrl %r1, b@indntpoff
lgf %r1,0(%r1,%r7)
lgrl %r1, c@indntpoff
lgf %r1,0(%r1,%r7)
.data
.reloc .,R_390_TLS_IE64,a
.space 8
.section .tbss
.globl a
.globl b
.globl c
.zero 8
a:
.zero 4
b:
.zero 4
c:

View File

@@ -0,0 +1,114 @@
# REQUIRES: systemz
# RUN: llvm-mc -filetype=obj -triple=s390x-unknown-linux %s -o %t.o
# RUN: ld.lld -shared %t.o -o %t.so
# RUN: llvm-readelf -r %t.so | FileCheck --check-prefix=LD-REL %s
# RUN: llvm-objdump -d --no-show-raw-insn %t.so | FileCheck --check-prefix=LD %s
# RUN: llvm-objdump --section .data.rel.ro --full-contents %t.so | FileCheck --check-prefix=LD-DATA %s
# RUN: ld.lld %t.o -o %t
# RUN: llvm-readelf -r %t | FileCheck --check-prefix=NOREL %s
# RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck --check-prefix=LE %s
# RUN: llvm-objdump --section .data.rel.ro --full-contents %t | FileCheck --check-prefix=LE-DATA %s
# LD-REL: Relocation section '.rela.dyn' at offset {{.*}} contains 1 entries:
# LD-REL: 00000000000024f8 0000000000000036 R_390_TLS_DTPMOD 0
## _GLOBAL_OFFSET_TABLE is at 0x24e0
# LD: larl %r12, 0x24e0
## GOT offset of the LDM TLS module ID is at 0x23e0
# LD-NEXT: lgrl %r2, 0x23e0
# LD-NEXT: brasl %r14, 0x13c0
# LD-NEXT: la %r2, 0(%r2,%r7)
## DTP offset for a is at 0x23e8
# LD-NEXT: lgrl %r1, 0x23e8
# LD-NEXT: lgf %r1, 0(%r1,%r2)
## DTP offset for b is at 0x23f0
# LD-NEXT: lgrl %r1, 0x23f0
# LD-NEXT: lgf %r1, 0(%r1,%r2)
## DTP offset for c is at 0x23f8
# LD-NEXT: lgrl %r1, 0x23f8
# LD-NEXT: lgf %r1, 0(%r1,%r2)
## Constant pool holding GOT offsets of TLS module ID and DTP offsets:
# TLS module ID: 0x24f8 / 0x18
# a: 8
# b: 12
# c: 16
# LD-DATA: 23e0 00000000 00000018 00000000 00000008
# LD-DATA: 23f0 00000000 0000000c 00000000 00000010
# NOREL: no relocations
## _GLOBAL_OFFSET_TABLE is at 0x1002230
# LE: larl %r12, 0x1002230
## GOT offset of the LDM TLS module ID is at 0x1002210
# LE-NEXT: lgrl %r2, 0x1002210
# LE-NEXT: brcl 0,
# LE-NEXT: la %r2, 0(%r2,%r7)
## TP offset for a is at 0x1002218
# LE-NEXT: lgrl %r1, 0x1002218
# LE-NEXT: lgf %r1, 0(%r1,%r2)
## TP offset for b is at 0x1002220
# LE-NEXT: lgrl %r1, 0x1002220
# LE-NEXT: lgf %r1, 0(%r1,%r2)
## TP offset for c is at 0x1002228
# LE-NEXT: lgrl %r1, 0x1002228
# LE-NEXT: lgf %r1, 0(%r1,%r2)
## zeroed LDM / TP offsets:
# LDM TLS: 0
# a: -8
# b: -4
# c: 0
# LE-DATA: 1002210 00000000 00000000 ffffffff fffffff8
# LE-DATA: 1002220 ffffffff fffffffc 00000000 00000000
ear %r7,%a0
sllg %r7,%r1,32
ear %r7,%a1
larl %r12,_GLOBAL_OFFSET_TABLE_
lgrl %r2,.LC0
brasl %r14,__tls_get_offset@PLT:tls_ldcall:a
la %r2,0(%r2,%r7)
lgrl %r1, .LC1
lgf %r1,0(%r1,%r2)
lgrl %r1, .LC2
lgf %r1,0(%r1,%r2)
lgrl %r1, .LC3
lgf %r1,0(%r1,%r2)
.section .data.rel.ro,"aw"
.align 8
.LC0:
.quad a@TLSLDM
.LC1:
.quad a@DTPOFF
.LC2:
.quad b@DTPOFF
.LC3:
.quad c@DTPOFF
.section .tbss
.globl a
.globl b
.globl c
.zero 8
a:
.zero 4
b:
.zero 4
c:

View File

@@ -0,0 +1,61 @@
# REQUIRES: systemz
# RUN: llvm-mc -filetype=obj -triple=s390x-unknown-linux %s -o %t.o
# RUN: ld.lld %t.o -o %t
# RUN: llvm-readelf -r %t | FileCheck --check-prefix=NOREL %s
# RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck --check-prefix=LE %s
# RUN: llvm-objdump --section .data.rel.ro --full-contents %t | FileCheck --check-prefix=LE-DATA %s
# NOREL: no relocations
## TP offset for a is at 0x1002200
# LE: lgrl %r1, 0x1002200
# LE-NEXT: lgf %r1, 0(%r1,%r7)
## TP offset for b is at 0x1002208
# LE-NEXT: lgrl %r1, 0x1002208
# LE-NEXT: lgf %r1, 0(%r1,%r7)
## TP offset for c is at 0x1002210
# LE-NEXT: lgrl %r1, 0x1002210
# LE-NEXT: lgf %r1, 0(%r1,%r7)
## TP offsets:
# a: -8
# b: -4
# c: 0
# LE-DATA: 1002200 ffffffff fffffff8 ffffffff fffffffc
# LE-DATA: 1002210 00000000 00000000
ear %r7,%a0
sllg %r7,%r1,32
ear %r7,%a1
lgrl %r1, .LC0
lgf %r1,0(%r1,%r7)
lgrl %r1, .LC1
lgf %r1,0(%r1,%r7)
lgrl %r1, .LC2
lgf %r1,0(%r1,%r7)
.section .data.rel.ro,"aw"
.align 8
.LC0:
.quad a@ntpoff
.LC1:
.quad b@ntpoff
.LC2:
.quad c@ntpoff
.section .tbss
.globl a
.globl b
.globl c
.zero 8
a:
.zero 4
b:
.zero 4
c:

View File

@@ -83,6 +83,7 @@ llvm_config.feature_config(
"PowerPC": "ppc",
"RISCV": "riscv",
"Sparc": "sparc",
"SystemZ": "systemz",
"WebAssembly": "wasm",
"X86": "x86",
},