[lld][ELF] Support LoongArch
This adds support for the LoongArch ELF psABI v2.00 [1] relocation model to LLD. The deprecated stack-machine-based psABI v1 relocs are not supported. The code is tested by successfully bootstrapping a Gentoo/LoongArch stage3, complete with common GNU userland tools and both the LLVM and GNU toolchains (GNU toolchain is present only for building glibc, LLVM+Clang+LLD are used for the rest). Large programs like QEMU are tested to work as well. [1]: https://loongson.github.io/LoongArch-Documentation/LoongArch-ELF-ABI-EN.html Reviewed By: MaskRay, SixWeining Differential Revision: https://reviews.llvm.org/D138135
This commit is contained in:
687
lld/ELF/Arch/LoongArch.cpp
Normal file
687
lld/ELF/Arch/LoongArch.cpp
Normal file
@@ -0,0 +1,687 @@
|
||||
//===- LoongArch.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 "InputFiles.h"
|
||||
#include "OutputSections.h"
|
||||
#include "Symbols.h"
|
||||
#include "SyntheticSections.h"
|
||||
#include "Target.h"
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::object;
|
||||
using namespace llvm::support::endian;
|
||||
using namespace llvm::ELF;
|
||||
using namespace lld;
|
||||
using namespace lld::elf;
|
||||
|
||||
namespace {
|
||||
class LoongArch final : public TargetInfo {
|
||||
public:
|
||||
LoongArch();
|
||||
uint32_t calcEFlags() const override;
|
||||
int64_t getImplicitAddend(const uint8_t *buf, RelType type) 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 writePlt(uint8_t *buf, const Symbol &sym,
|
||||
uint64_t pltEntryAddr) const override;
|
||||
RelType getDynRel(RelType type) const override;
|
||||
RelExpr getRelExpr(RelType type, const Symbol &s,
|
||||
const uint8_t *loc) const override;
|
||||
bool usesOnlyLowPageBits(RelType type) const override;
|
||||
void relocate(uint8_t *loc, const Relocation &rel,
|
||||
uint64_t val) const override;
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
||||
enum Op {
|
||||
SUB_W = 0x00110000,
|
||||
SUB_D = 0x00118000,
|
||||
BREAK = 0x002a0000,
|
||||
SRLI_W = 0x00448000,
|
||||
SRLI_D = 0x00450000,
|
||||
ADDI_W = 0x02800000,
|
||||
ADDI_D = 0x02c00000,
|
||||
ANDI = 0x03400000,
|
||||
PCADDU12I = 0x1c000000,
|
||||
LD_W = 0x28800000,
|
||||
LD_D = 0x28c00000,
|
||||
JIRL = 0x4c000000,
|
||||
};
|
||||
|
||||
enum Reg {
|
||||
R_ZERO = 0,
|
||||
R_RA = 1,
|
||||
R_TP = 2,
|
||||
R_T0 = 12,
|
||||
R_T1 = 13,
|
||||
R_T2 = 14,
|
||||
R_T3 = 15,
|
||||
};
|
||||
|
||||
// Mask out the input's lowest 12 bits for use with `pcalau12i`, in sequences
|
||||
// like `pcalau12i + addi.[wd]` or `pcalau12i + {ld,st}.*` where the `pcalau12i`
|
||||
// produces a PC-relative intermediate value with the lowest 12 bits zeroed (the
|
||||
// "page") for the next instruction to add in the "page offset". (`pcalau12i`
|
||||
// stands for something like "PC ALigned Add Upper that starts from the 12th
|
||||
// bit, Immediate".)
|
||||
//
|
||||
// Here a "page" is in fact just another way to refer to the 12-bit range
|
||||
// allowed by the immediate field of the addi/ld/st instructions, and not
|
||||
// related to the system or the kernel's actual page size. The sematics happens
|
||||
// to match the AArch64 `adrp`, so the concept of "page" is borrowed here.
|
||||
static uint64_t getLoongArchPage(uint64_t p) {
|
||||
return p & ~static_cast<uint64_t>(0xfff);
|
||||
}
|
||||
|
||||
static uint32_t lo12(uint32_t val) { return val & 0xfff; }
|
||||
|
||||
// Calculate the adjusted page delta between dest and PC.
|
||||
uint64_t elf::getLoongArchPageDelta(uint64_t dest, uint64_t pc) {
|
||||
// Consider the large code model access pattern, of which the smaller code
|
||||
// models' access patterns are a subset:
|
||||
//
|
||||
// pcalau12i U, %foo_hi20(sym) ; b in [-0x80000, 0x7ffff]
|
||||
// addi.d T, zero, %foo_lo12(sym) ; a in [-0x800, 0x7ff]
|
||||
// lu32i.d T, %foo64_lo20(sym) ; c in [-0x80000, 0x7ffff]
|
||||
// lu52i.d T, T, %foo64_hi12(sym) ; d in [-0x800, 0x7ff]
|
||||
// {ldx,stx,add}.* dest, U, T
|
||||
//
|
||||
// Let page(pc) = 0xRRR'QQQQQ'PPPPP'000 and dest = 0xZZZ'YYYYY'XXXXX'AAA,
|
||||
// with RQ, P, ZY, X and A representing the respective bitfields as unsigned
|
||||
// integers. We have:
|
||||
//
|
||||
// page(dest) = 0xZZZ'YYYYY'XXXXX'000
|
||||
// - page(pc) = 0xRRR'QQQQQ'PPPPP'000
|
||||
// ----------------------------------
|
||||
// 0xddd'ccccc'bbbbb'000
|
||||
//
|
||||
// Now consider the above pattern's actual effects:
|
||||
//
|
||||
// page(pc) 0xRRR'QQQQQ'PPPPP'000
|
||||
// pcalau12i + 0xiii'iiiii'bbbbb'000
|
||||
// addi + 0xjjj'jjjjj'kkkkk'AAA
|
||||
// lu32i.d & lu52i.d + 0xddd'ccccc'00000'000
|
||||
// --------------------------------------------------
|
||||
// dest = U + T
|
||||
// = ((RQ<<32) + (P<<12) + i + (b<<12)) + (j + k + A + (cd<<32))
|
||||
// = (((RQ+cd)<<32) + i + j) + (((P+b)<<12) + k) + A
|
||||
// = (ZY<<32) + (X<<12) + A
|
||||
//
|
||||
// ZY<<32 = (RQ<<32)+(cd<<32)+i+j, X<<12 = (P<<12)+(b<<12)+k
|
||||
// cd<<32 = (ZY<<32)-(RQ<<32)-i-j, b<<12 = (X<<12)-(P<<12)-k
|
||||
//
|
||||
// where i and k are terms representing the effect of b's and A's sign
|
||||
// extension respectively.
|
||||
//
|
||||
// i = signed b < 0 ? -0x10000'0000 : 0
|
||||
// k = signed A < 0 ? -0x1000 : 0
|
||||
//
|
||||
// The j term is a bit complex: it represents the higher half of
|
||||
// sign-extended bits from A that are effectively lost if i == 0 but k != 0,
|
||||
// due to overwriting by lu32i.d & lu52i.d.
|
||||
//
|
||||
// j = signed A < 0 && signed b >= 0 ? 0x10000'0000 : 0
|
||||
//
|
||||
// The actual effect of the instruction sequence before the final addition,
|
||||
// i.e. our desired result value, is thus:
|
||||
//
|
||||
// result = (cd<<32) + (b<<12)
|
||||
// = (ZY<<32)-(RQ<<32)-i-j + (X<<12)-(P<<12)-k
|
||||
// = ((ZY<<32)+(X<<12)) - ((RQ<<32)+(P<<12)) - i - j - k
|
||||
// = page(dest) - page(pc) - i - j - k
|
||||
//
|
||||
// when signed A >= 0 && signed b >= 0:
|
||||
//
|
||||
// i = j = k = 0
|
||||
// result = page(dest) - page(pc)
|
||||
//
|
||||
// when signed A >= 0 && signed b < 0:
|
||||
//
|
||||
// i = -0x10000'0000, j = k = 0
|
||||
// result = page(dest) - page(pc) + 0x10000'0000
|
||||
//
|
||||
// when signed A < 0 && signed b >= 0:
|
||||
//
|
||||
// i = 0, j = 0x10000'0000, k = -0x1000
|
||||
// result = page(dest) - page(pc) - 0x10000'0000 + 0x1000
|
||||
//
|
||||
// when signed A < 0 && signed b < 0:
|
||||
//
|
||||
// i = -0x10000'0000, j = 0, k = -0x1000
|
||||
// result = page(dest) - page(pc) + 0x1000
|
||||
uint64_t result = getLoongArchPage(dest) - getLoongArchPage(pc);
|
||||
bool negativeA = lo12(dest) > 0x7ff;
|
||||
bool negativeB = (result & 0x8000'0000) != 0;
|
||||
|
||||
if (negativeA)
|
||||
result += 0x1000;
|
||||
if (negativeA && !negativeB)
|
||||
result -= 0x10000'0000;
|
||||
else if (!negativeA && negativeB)
|
||||
result += 0x10000'0000;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static uint32_t hi20(uint32_t val) { return (val + 0x800) >> 12; }
|
||||
|
||||
static uint32_t insn(uint32_t op, uint32_t d, uint32_t j, uint32_t k) {
|
||||
return op | d | (j << 5) | (k << 10);
|
||||
}
|
||||
|
||||
// Extract bits v[begin:end], where range is inclusive.
|
||||
static uint32_t extractBits(uint64_t v, uint32_t begin, uint32_t end) {
|
||||
return begin == 63 ? v >> end : (v & ((1ULL << (begin + 1)) - 1)) >> end;
|
||||
}
|
||||
|
||||
static uint32_t setD5k16(uint32_t insn, uint32_t imm) {
|
||||
uint32_t immLo = extractBits(imm, 15, 0);
|
||||
uint32_t immHi = extractBits(imm, 20, 16);
|
||||
return (insn & 0xfc0003e0) | (immLo << 10) | immHi;
|
||||
}
|
||||
|
||||
static uint32_t setD10k16(uint32_t insn, uint32_t imm) {
|
||||
uint32_t immLo = extractBits(imm, 15, 0);
|
||||
uint32_t immHi = extractBits(imm, 25, 16);
|
||||
return (insn & 0xfc000000) | (immLo << 10) | immHi;
|
||||
}
|
||||
|
||||
static uint32_t setJ20(uint32_t insn, uint32_t imm) {
|
||||
return (insn & 0xfe00001f) | (extractBits(imm, 19, 0) << 5);
|
||||
}
|
||||
|
||||
static uint32_t setK12(uint32_t insn, uint32_t imm) {
|
||||
return (insn & 0xffc003ff) | (extractBits(imm, 11, 0) << 10);
|
||||
}
|
||||
|
||||
static uint32_t setK16(uint32_t insn, uint32_t imm) {
|
||||
return (insn & 0xfc0003ff) | (extractBits(imm, 15, 0) << 10);
|
||||
}
|
||||
|
||||
static bool isJirl(uint32_t insn) {
|
||||
return (insn & 0xfc000000) == JIRL;
|
||||
}
|
||||
|
||||
LoongArch::LoongArch() {
|
||||
// The LoongArch ISA itself does not have a limit on page sizes. According to
|
||||
// the ISA manual, the PS (page size) field in MTLB entries and CSR.STLBPS is
|
||||
// 6 bits wide, meaning the maximum page size is 2^63 which is equivalent to
|
||||
// "unlimited".
|
||||
// However, practically the maximum usable page size is constrained by the
|
||||
// kernel implementation, and 64KiB is the biggest non-huge page size
|
||||
// supported by Linux as of v6.4. The most widespread page size in use,
|
||||
// though, is 16KiB.
|
||||
defaultCommonPageSize = 16384;
|
||||
defaultMaxPageSize = 65536;
|
||||
write32le(trapInstr.data(), BREAK); // break 0
|
||||
|
||||
copyRel = R_LARCH_COPY;
|
||||
pltRel = R_LARCH_JUMP_SLOT;
|
||||
relativeRel = R_LARCH_RELATIVE;
|
||||
iRelativeRel = R_LARCH_IRELATIVE;
|
||||
|
||||
if (config->is64) {
|
||||
symbolicRel = R_LARCH_64;
|
||||
tlsModuleIndexRel = R_LARCH_TLS_DTPMOD64;
|
||||
tlsOffsetRel = R_LARCH_TLS_DTPREL64;
|
||||
tlsGotRel = R_LARCH_TLS_TPREL64;
|
||||
} else {
|
||||
symbolicRel = R_LARCH_32;
|
||||
tlsModuleIndexRel = R_LARCH_TLS_DTPMOD32;
|
||||
tlsOffsetRel = R_LARCH_TLS_DTPREL32;
|
||||
tlsGotRel = R_LARCH_TLS_TPREL32;
|
||||
}
|
||||
|
||||
gotRel = symbolicRel;
|
||||
|
||||
// .got.plt[0] = _dl_runtime_resolve, .got.plt[1] = link_map
|
||||
gotPltHeaderEntriesNum = 2;
|
||||
|
||||
pltHeaderSize = 32;
|
||||
pltEntrySize = 16;
|
||||
ipltEntrySize = 16;
|
||||
}
|
||||
|
||||
static uint32_t getEFlags(const InputFile *f) {
|
||||
if (config->is64)
|
||||
return cast<ObjFile<ELF64LE>>(f)->getObj().getHeader().e_flags;
|
||||
return cast<ObjFile<ELF32LE>>(f)->getObj().getHeader().e_flags;
|
||||
}
|
||||
|
||||
static bool inputFileHasCode(const InputFile *f) {
|
||||
for (const auto *sec : f->getSections())
|
||||
if (sec && sec->flags & SHF_EXECINSTR)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t LoongArch::calcEFlags() const {
|
||||
// If there are only binary input files (from -b binary), use a
|
||||
// value of 0 for the ELF header flags.
|
||||
if (ctx.objectFiles.empty())
|
||||
return 0;
|
||||
|
||||
uint32_t target = 0;
|
||||
const InputFile *targetFile;
|
||||
for (const InputFile *f : ctx.objectFiles) {
|
||||
// Do not enforce ABI compatibility if the input file does not contain code.
|
||||
// This is useful for allowing linkage with data-only object files produced
|
||||
// with tools like objcopy, that have zero e_flags.
|
||||
if (!inputFileHasCode(f))
|
||||
continue;
|
||||
|
||||
// Take the first non-zero e_flags as the reference.
|
||||
uint32_t flags = getEFlags(f);
|
||||
if (target == 0 && flags != 0) {
|
||||
target = flags;
|
||||
targetFile = f;
|
||||
}
|
||||
|
||||
if ((flags & EF_LOONGARCH_ABI_MODIFIER_MASK) !=
|
||||
(target & EF_LOONGARCH_ABI_MODIFIER_MASK))
|
||||
error(toString(f) +
|
||||
": cannot link object files with different ABI from " +
|
||||
toString(targetFile));
|
||||
|
||||
// We cannot process psABI v1.x / object ABI v0 files (containing stack
|
||||
// relocations), unlike ld.bfd.
|
||||
//
|
||||
// Instead of blindly accepting every v0 object and only failing at
|
||||
// relocation processing time, just disallow interlink altogether. We
|
||||
// don't expect significant usage of object ABI v0 in the wild (the old
|
||||
// world may continue using object ABI v0 for a while, but as it's not
|
||||
// binary-compatible with the upstream i.e. new-world ecosystem, it's not
|
||||
// being considered here).
|
||||
//
|
||||
// There are briefly some new-world systems with object ABI v0 binaries too.
|
||||
// It is because these systems were built before the new ABI was finalized.
|
||||
// These are not supported either due to the extremely small number of them,
|
||||
// and the few impacted users are advised to simply rebuild world or
|
||||
// reinstall a recent system.
|
||||
if ((flags & EF_LOONGARCH_OBJABI_MASK) != EF_LOONGARCH_OBJABI_V1)
|
||||
error(toString(f) + ": unsupported object file ABI version");
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
int64_t LoongArch::getImplicitAddend(const uint8_t *buf, RelType type) const {
|
||||
switch (type) {
|
||||
default:
|
||||
internalLinkerError(getErrorLocation(buf),
|
||||
"cannot read addend for relocation " + toString(type));
|
||||
return 0;
|
||||
case R_LARCH_32:
|
||||
case R_LARCH_TLS_DTPMOD32:
|
||||
case R_LARCH_TLS_DTPREL32:
|
||||
case R_LARCH_TLS_TPREL32:
|
||||
return SignExtend64<32>(read32le(buf));
|
||||
case R_LARCH_64:
|
||||
case R_LARCH_TLS_DTPMOD64:
|
||||
case R_LARCH_TLS_DTPREL64:
|
||||
case R_LARCH_TLS_TPREL64:
|
||||
return read64le(buf);
|
||||
case R_LARCH_RELATIVE:
|
||||
case R_LARCH_IRELATIVE:
|
||||
return config->is64 ? read64le(buf) : read32le(buf);
|
||||
case R_LARCH_NONE:
|
||||
case R_LARCH_JUMP_SLOT:
|
||||
// These relocations are defined as not having an implicit addend.
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void LoongArch::writeGotPlt(uint8_t *buf, const Symbol &s) const {
|
||||
if (config->is64)
|
||||
write64le(buf, in.plt->getVA());
|
||||
else
|
||||
write32le(buf, in.plt->getVA());
|
||||
}
|
||||
|
||||
void LoongArch::writeIgotPlt(uint8_t *buf, const Symbol &s) const {
|
||||
if (config->writeAddends) {
|
||||
if (config->is64)
|
||||
write64le(buf, s.getVA());
|
||||
else
|
||||
write32le(buf, s.getVA());
|
||||
}
|
||||
}
|
||||
|
||||
void LoongArch::writePltHeader(uint8_t *buf) const {
|
||||
// The LoongArch PLT is currently structured just like that of RISCV.
|
||||
// Annoyingly, this means the PLT is still using `pcaddu12i` to perform
|
||||
// PC-relative addressing (because `pcaddu12i` is the same as RISCV `auipc`),
|
||||
// in contrast to the AArch64-like page-offset scheme with `pcalau12i` that
|
||||
// is used everywhere else involving PC-relative operations in the LoongArch
|
||||
// ELF psABI v2.00.
|
||||
//
|
||||
// The `pcrel_{hi20,lo12}` operators are illustrative only and not really
|
||||
// supported by LoongArch assemblers.
|
||||
//
|
||||
// pcaddu12i $t2, %pcrel_hi20(.got.plt)
|
||||
// sub.[wd] $t1, $t1, $t3
|
||||
// ld.[wd] $t3, $t2, %pcrel_lo12(.got.plt) ; t3 = _dl_runtime_resolve
|
||||
// addi.[wd] $t1, $t1, -pltHeaderSize-12 ; t1 = &.plt[i] - &.plt[0]
|
||||
// addi.[wd] $t0, $t2, %pcrel_lo12(.got.plt)
|
||||
// srli.[wd] $t1, $t1, (is64?1:2) ; t1 = &.got.plt[i] - &.got.plt[0]
|
||||
// ld.[wd] $t0, $t0, Wordsize ; t0 = link_map
|
||||
// jr $t3
|
||||
uint32_t offset = in.gotPlt->getVA() - in.plt->getVA();
|
||||
uint32_t sub = config->is64 ? SUB_D : SUB_W;
|
||||
uint32_t ld = config->is64 ? LD_D : LD_W;
|
||||
uint32_t addi = config->is64 ? ADDI_D : ADDI_W;
|
||||
uint32_t srli = config->is64 ? SRLI_D : SRLI_W;
|
||||
write32le(buf + 0, insn(PCADDU12I, R_T2, hi20(offset), 0));
|
||||
write32le(buf + 4, insn(sub, R_T1, R_T1, R_T3));
|
||||
write32le(buf + 8, insn(ld, R_T3, R_T2, lo12(offset)));
|
||||
write32le(buf + 12, insn(addi, R_T1, R_T1, lo12(-target->pltHeaderSize - 12)));
|
||||
write32le(buf + 16, insn(addi, R_T0, R_T2, lo12(offset)));
|
||||
write32le(buf + 20, insn(srli, R_T1, R_T1, config->is64 ? 1 : 2));
|
||||
write32le(buf + 24, insn(ld, R_T0, R_T0, config->wordsize));
|
||||
write32le(buf + 28, insn(JIRL, R_ZERO, R_T3, 0));
|
||||
}
|
||||
|
||||
void LoongArch::writePlt(uint8_t *buf, const Symbol &sym,
|
||||
uint64_t pltEntryAddr) const {
|
||||
// See the comment in writePltHeader for reason why pcaddu12i is used instead
|
||||
// of the pcalau12i that's more commonly seen in the ELF psABI v2.0 days.
|
||||
//
|
||||
// pcaddu12i $t3, %pcrel_hi20(f@.got.plt)
|
||||
// ld.[wd] $t3, $t3, %pcrel_lo12(f@.got.plt)
|
||||
// jirl $t1, $t3, 0
|
||||
// nop
|
||||
uint32_t offset = sym.getGotPltVA() - pltEntryAddr;
|
||||
write32le(buf + 0, insn(PCADDU12I, R_T3, hi20(offset), 0));
|
||||
write32le(buf + 4,
|
||||
insn(config->is64 ? LD_D : LD_W, R_T3, R_T3, lo12(offset)));
|
||||
write32le(buf + 8, insn(JIRL, R_T1, R_T3, 0));
|
||||
write32le(buf + 12, insn(ANDI, R_ZERO, R_ZERO, 0));
|
||||
}
|
||||
|
||||
RelType LoongArch::getDynRel(RelType type) const {
|
||||
return type == target->symbolicRel ? type
|
||||
: static_cast<RelType>(R_LARCH_NONE);
|
||||
}
|
||||
|
||||
RelExpr LoongArch::getRelExpr(const RelType type, const Symbol &s,
|
||||
const uint8_t *loc) const {
|
||||
switch (type) {
|
||||
case R_LARCH_NONE:
|
||||
case R_LARCH_MARK_LA:
|
||||
case R_LARCH_MARK_PCREL:
|
||||
return R_NONE;
|
||||
case R_LARCH_32:
|
||||
case R_LARCH_64:
|
||||
case R_LARCH_ABS_HI20:
|
||||
case R_LARCH_ABS_LO12:
|
||||
case R_LARCH_ABS64_LO20:
|
||||
case R_LARCH_ABS64_HI12:
|
||||
return R_ABS;
|
||||
case R_LARCH_PCALA_LO12:
|
||||
// We could just R_ABS, but the JIRL instruction reuses the relocation type
|
||||
// for a different purpose. The questionable usage is part of glibc 2.37
|
||||
// libc_nonshared.a [1], which is linked into user programs, so we have to
|
||||
// work around it for a while, even if a new relocation type may be
|
||||
// introduced in the future [2].
|
||||
//
|
||||
// [1]: https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=9f482b73f41a9a1bbfb173aad0733d1c824c788a
|
||||
// [2]: https://github.com/loongson/la-abi-specs/pull/3
|
||||
return isJirl(read32le(loc)) ? R_PLT : R_ABS;
|
||||
case R_LARCH_TLS_DTPREL32:
|
||||
case R_LARCH_TLS_DTPREL64:
|
||||
return R_DTPREL;
|
||||
case R_LARCH_TLS_TPREL32:
|
||||
case R_LARCH_TLS_TPREL64:
|
||||
case R_LARCH_TLS_LE_HI20:
|
||||
case R_LARCH_TLS_LE_LO12:
|
||||
case R_LARCH_TLS_LE64_LO20:
|
||||
case R_LARCH_TLS_LE64_HI12:
|
||||
return R_TPREL;
|
||||
case R_LARCH_ADD8:
|
||||
case R_LARCH_ADD16:
|
||||
case R_LARCH_ADD32:
|
||||
case R_LARCH_ADD64:
|
||||
case R_LARCH_SUB8:
|
||||
case R_LARCH_SUB16:
|
||||
case R_LARCH_SUB32:
|
||||
case R_LARCH_SUB64:
|
||||
// The LoongArch add/sub relocs behave like the RISCV counterparts; reuse
|
||||
// the RelExpr to avoid code duplication.
|
||||
return R_RISCV_ADD;
|
||||
case R_LARCH_32_PCREL:
|
||||
case R_LARCH_64_PCREL:
|
||||
return R_PC;
|
||||
case R_LARCH_B16:
|
||||
case R_LARCH_B21:
|
||||
case R_LARCH_B26:
|
||||
return R_PLT_PC;
|
||||
case R_LARCH_GOT_PC_HI20:
|
||||
case R_LARCH_GOT64_PC_LO20:
|
||||
case R_LARCH_GOT64_PC_HI12:
|
||||
case R_LARCH_TLS_IE_PC_HI20:
|
||||
case R_LARCH_TLS_IE64_PC_LO20:
|
||||
case R_LARCH_TLS_IE64_PC_HI12:
|
||||
return R_LOONGARCH_GOT_PAGE_PC;
|
||||
case R_LARCH_GOT_PC_LO12:
|
||||
case R_LARCH_TLS_IE_PC_LO12:
|
||||
return R_LOONGARCH_GOT;
|
||||
case R_LARCH_TLS_LD_PC_HI20:
|
||||
case R_LARCH_TLS_GD_PC_HI20:
|
||||
return R_LOONGARCH_TLSGD_PAGE_PC;
|
||||
case R_LARCH_PCALA_HI20:
|
||||
// Why not R_LOONGARCH_PAGE_PC, majority of references don't go through PLT
|
||||
// anyway so why waste time checking only to get everything relaxed back to
|
||||
// it?
|
||||
//
|
||||
// This is again due to the R_LARCH_PCALA_LO12 on JIRL case, where we want
|
||||
// both the HI20 and LO12 to potentially refer to the PLT. But in reality
|
||||
// the HI20 reloc appears earlier, and the relocs don't contain enough
|
||||
// information to let us properly resolve semantics per symbol.
|
||||
// Unlike RISCV, our LO12 relocs *do not* point to their corresponding HI20
|
||||
// relocs, hence it is nearly impossible to 100% accurately determine each
|
||||
// HI20's "flavor" without taking big performance hits, in the presence of
|
||||
// edge cases (e.g. HI20 without pairing LO12; paired LO12 placed so far
|
||||
// apart that relationship is not certain anymore), and programmer mistakes
|
||||
// (e.g. as outlined in https://github.com/loongson/la-abi-specs/pull/3).
|
||||
//
|
||||
// Ideally we would scan in an extra pass for all LO12s on JIRL, then mark
|
||||
// every HI20 reloc referring to the same symbol differently; this is not
|
||||
// feasible with the current function signature of getRelExpr that doesn't
|
||||
// allow for such inter-pass state.
|
||||
//
|
||||
// So, unfortunately we have to again workaround this quirk the same way as
|
||||
// BFD: assuming every R_LARCH_PCALA_HI20 is potentially PLT-needing, only
|
||||
// relaxing back to R_LOONGARCH_PAGE_PC if it's known not so at a later
|
||||
// stage.
|
||||
return R_LOONGARCH_PLT_PAGE_PC;
|
||||
case R_LARCH_PCALA64_LO20:
|
||||
case R_LARCH_PCALA64_HI12:
|
||||
return R_LOONGARCH_PAGE_PC;
|
||||
case R_LARCH_GOT_HI20:
|
||||
case R_LARCH_GOT_LO12:
|
||||
case R_LARCH_GOT64_LO20:
|
||||
case R_LARCH_GOT64_HI12:
|
||||
case R_LARCH_TLS_IE_HI20:
|
||||
case R_LARCH_TLS_IE_LO12:
|
||||
case R_LARCH_TLS_IE64_LO20:
|
||||
case R_LARCH_TLS_IE64_HI12:
|
||||
return R_GOT;
|
||||
case R_LARCH_TLS_LD_HI20:
|
||||
return R_TLSLD_GOT;
|
||||
case R_LARCH_TLS_GD_HI20:
|
||||
return R_TLSGD_GOT;
|
||||
case R_LARCH_RELAX:
|
||||
// LoongArch linker relaxation is not implemented yet.
|
||||
return R_NONE;
|
||||
|
||||
// Other known relocs that are explicitly unimplemented:
|
||||
//
|
||||
// - psABI v1 relocs that need a stateful stack machine to work, and not
|
||||
// required when implementing psABI v2;
|
||||
// - relocs that are not used anywhere (R_LARCH_{ADD,SUB}_24 [1], and the
|
||||
// two GNU vtable-related relocs).
|
||||
//
|
||||
// [1]: https://web.archive.org/web/20230709064026/https://github.com/loongson/LoongArch-Documentation/issues/51
|
||||
default:
|
||||
error(getErrorLocation(loc) + "unknown relocation (" + Twine(type) +
|
||||
") against symbol " + toString(s));
|
||||
return R_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
bool LoongArch::usesOnlyLowPageBits(RelType type) const {
|
||||
switch (type) {
|
||||
default:
|
||||
return false;
|
||||
case R_LARCH_PCALA_LO12:
|
||||
case R_LARCH_GOT_LO12:
|
||||
case R_LARCH_GOT_PC_LO12:
|
||||
case R_LARCH_TLS_IE_PC_LO12:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void LoongArch::relocate(uint8_t *loc, const Relocation &rel,
|
||||
uint64_t val) const {
|
||||
switch (rel.type) {
|
||||
case R_LARCH_32_PCREL:
|
||||
checkInt(loc, val, 32, rel);
|
||||
[[fallthrough]];
|
||||
case R_LARCH_32:
|
||||
case R_LARCH_TLS_DTPREL32:
|
||||
write32le(loc, val);
|
||||
return;
|
||||
case R_LARCH_64:
|
||||
case R_LARCH_TLS_DTPREL64:
|
||||
case R_LARCH_64_PCREL:
|
||||
write64le(loc, val);
|
||||
return;
|
||||
|
||||
case R_LARCH_B16:
|
||||
checkInt(loc, val, 18, rel);
|
||||
checkAlignment(loc, val, 4, rel);
|
||||
write32le(loc, setK16(read32le(loc), val >> 2));
|
||||
return;
|
||||
|
||||
case R_LARCH_B21:
|
||||
checkInt(loc, val, 23, rel);
|
||||
checkAlignment(loc, val, 4, rel);
|
||||
write32le(loc, setD5k16(read32le(loc), val >> 2));
|
||||
return;
|
||||
|
||||
case R_LARCH_B26:
|
||||
checkInt(loc, val, 28, rel);
|
||||
checkAlignment(loc, val, 4, rel);
|
||||
write32le(loc, setD10k16(read32le(loc), val >> 2));
|
||||
return;
|
||||
|
||||
// Relocs intended for `addi`, `ld` or `st`.
|
||||
case R_LARCH_PCALA_LO12:
|
||||
// We have to again inspect the insn word to handle the R_LARCH_PCALA_LO12
|
||||
// on JIRL case: firstly JIRL wants its immediate's 2 lowest zeroes
|
||||
// removed by us (in contrast to regular R_LARCH_PCALA_LO12), secondly
|
||||
// its immediate slot width is different too (16, not 12).
|
||||
// In this case, process like an R_LARCH_B16, but without overflow checking
|
||||
// and only taking the value's lowest 12 bits.
|
||||
if (isJirl(read32le(loc))) {
|
||||
checkAlignment(loc, val, 4, rel);
|
||||
val = SignExtend64<12>(val);
|
||||
write32le(loc, setK16(read32le(loc), val >> 2));
|
||||
return;
|
||||
}
|
||||
[[fallthrough]];
|
||||
case R_LARCH_ABS_LO12:
|
||||
case R_LARCH_GOT_PC_LO12:
|
||||
case R_LARCH_GOT_LO12:
|
||||
case R_LARCH_TLS_LE_LO12:
|
||||
case R_LARCH_TLS_IE_PC_LO12:
|
||||
case R_LARCH_TLS_IE_LO12:
|
||||
write32le(loc, setK12(read32le(loc), extractBits(val, 11, 0)));
|
||||
return;
|
||||
|
||||
// Relocs intended for `lu12i.w` or `pcalau12i`.
|
||||
case R_LARCH_ABS_HI20:
|
||||
case R_LARCH_PCALA_HI20:
|
||||
case R_LARCH_GOT_PC_HI20:
|
||||
case R_LARCH_GOT_HI20:
|
||||
case R_LARCH_TLS_LE_HI20:
|
||||
case R_LARCH_TLS_IE_PC_HI20:
|
||||
case R_LARCH_TLS_IE_HI20:
|
||||
case R_LARCH_TLS_LD_PC_HI20:
|
||||
case R_LARCH_TLS_LD_HI20:
|
||||
case R_LARCH_TLS_GD_PC_HI20:
|
||||
case R_LARCH_TLS_GD_HI20:
|
||||
write32le(loc, setJ20(read32le(loc), extractBits(val, 31, 12)));
|
||||
return;
|
||||
|
||||
// Relocs intended for `lu32i.d`.
|
||||
case R_LARCH_ABS64_LO20:
|
||||
case R_LARCH_PCALA64_LO20:
|
||||
case R_LARCH_GOT64_PC_LO20:
|
||||
case R_LARCH_GOT64_LO20:
|
||||
case R_LARCH_TLS_LE64_LO20:
|
||||
case R_LARCH_TLS_IE64_PC_LO20:
|
||||
case R_LARCH_TLS_IE64_LO20:
|
||||
write32le(loc, setJ20(read32le(loc), extractBits(val, 51, 32)));
|
||||
return;
|
||||
|
||||
// Relocs intended for `lu52i.d`.
|
||||
case R_LARCH_ABS64_HI12:
|
||||
case R_LARCH_PCALA64_HI12:
|
||||
case R_LARCH_GOT64_PC_HI12:
|
||||
case R_LARCH_GOT64_HI12:
|
||||
case R_LARCH_TLS_LE64_HI12:
|
||||
case R_LARCH_TLS_IE64_PC_HI12:
|
||||
case R_LARCH_TLS_IE64_HI12:
|
||||
write32le(loc, setK12(read32le(loc), extractBits(val, 63, 52)));
|
||||
return;
|
||||
|
||||
case R_LARCH_ADD8:
|
||||
*loc += val;
|
||||
return;
|
||||
case R_LARCH_ADD16:
|
||||
write16le(loc, read16le(loc) + val);
|
||||
return;
|
||||
case R_LARCH_ADD32:
|
||||
write32le(loc, read32le(loc) + val);
|
||||
return;
|
||||
case R_LARCH_ADD64:
|
||||
write64le(loc, read64le(loc) + val);
|
||||
return;
|
||||
case R_LARCH_SUB8:
|
||||
*loc -= val;
|
||||
return;
|
||||
case R_LARCH_SUB16:
|
||||
write16le(loc, read16le(loc) - val);
|
||||
return;
|
||||
case R_LARCH_SUB32:
|
||||
write32le(loc, read32le(loc) - val);
|
||||
return;
|
||||
case R_LARCH_SUB64:
|
||||
write64le(loc, read64le(loc) - val);
|
||||
return;
|
||||
|
||||
case R_LARCH_MARK_LA:
|
||||
case R_LARCH_MARK_PCREL:
|
||||
// no-op
|
||||
return;
|
||||
|
||||
case R_LARCH_RELAX:
|
||||
return; // Ignored (for now)
|
||||
|
||||
default:
|
||||
llvm_unreachable("unknown relocation");
|
||||
}
|
||||
}
|
||||
|
||||
TargetInfo *elf::getLoongArchTargetInfo() {
|
||||
static LoongArch target;
|
||||
return ⌖
|
||||
}
|
||||
@@ -25,6 +25,7 @@ add_lld_library(lldELF
|
||||
Arch/ARM.cpp
|
||||
Arch/AVR.cpp
|
||||
Arch/Hexagon.cpp
|
||||
Arch/LoongArch.cpp
|
||||
Arch/Mips.cpp
|
||||
Arch/MipsArchTree.cpp
|
||||
Arch/MSP430.cpp
|
||||
|
||||
@@ -180,6 +180,7 @@ static std::tuple<ELFKind, uint16_t, uint8_t> parseEmulation(StringRef emul) {
|
||||
.Case("elf32lriscv", {ELF32LEKind, EM_RISCV})
|
||||
.Cases("elf32ppc", "elf32ppclinux", {ELF32BEKind, EM_PPC})
|
||||
.Cases("elf32lppc", "elf32lppclinux", {ELF32LEKind, EM_PPC})
|
||||
.Case("elf32loongarch", {ELF32LEKind, EM_LOONGARCH})
|
||||
.Case("elf64btsmip", {ELF64BEKind, EM_MIPS})
|
||||
.Case("elf64ltsmip", {ELF64LEKind, EM_MIPS})
|
||||
.Case("elf64lriscv", {ELF64LEKind, EM_RISCV})
|
||||
@@ -191,6 +192,7 @@ static std::tuple<ELFKind, uint16_t, uint8_t> parseEmulation(StringRef emul) {
|
||||
.Case("elf64_sparc", {ELF64BEKind, EM_SPARCV9})
|
||||
.Case("msp430elf", {ELF32LEKind, EM_MSP430})
|
||||
.Case("elf64_amdgpu", {ELF64LEKind, EM_AMDGPU})
|
||||
.Case("elf64loongarch", {ELF64LEKind, EM_LOONGARCH})
|
||||
.Default({ELFNoneKind, EM_NONE});
|
||||
|
||||
if (ret.first == ELFNoneKind)
|
||||
@@ -1085,8 +1087,9 @@ static bool getIsRela(opt::InputArgList &args) {
|
||||
|
||||
// Otherwise use the psABI defined relocation entry format.
|
||||
uint16_t m = config->emachine;
|
||||
return m == EM_AARCH64 || m == EM_AMDGPU || m == EM_HEXAGON || m == EM_PPC ||
|
||||
m == EM_PPC64 || m == EM_RISCV || m == EM_X86_64;
|
||||
return m == EM_AARCH64 || m == EM_AMDGPU || m == EM_HEXAGON ||
|
||||
m == EM_LOONGARCH || m == EM_PPC || m == EM_PPC64 || m == EM_RISCV ||
|
||||
m == EM_X86_64;
|
||||
}
|
||||
|
||||
static void parseClangOption(StringRef opt, const Twine &msg) {
|
||||
@@ -1693,8 +1696,9 @@ static void setConfigs(opt::InputArgList &args) {
|
||||
// have support for reading Elf_Rel addends, so we only enable for a subset.
|
||||
#ifndef NDEBUG
|
||||
bool checkDynamicRelocsDefault = m == EM_AARCH64 || m == EM_ARM ||
|
||||
m == EM_386 || m == EM_MIPS ||
|
||||
m == EM_X86_64 || m == EM_RISCV;
|
||||
m == EM_386 || m == EM_LOONGARCH ||
|
||||
m == EM_MIPS || m == EM_RISCV ||
|
||||
m == EM_X86_64;
|
||||
#else
|
||||
bool checkDynamicRelocsDefault = false;
|
||||
#endif
|
||||
|
||||
@@ -1575,6 +1575,9 @@ static uint16_t getBitcodeMachineKind(StringRef path, const Triple &t) {
|
||||
return EM_AVR;
|
||||
case Triple::hexagon:
|
||||
return EM_HEXAGON;
|
||||
case Triple::loongarch32:
|
||||
case Triple::loongarch64:
|
||||
return EM_LOONGARCH;
|
||||
case Triple::mips:
|
||||
case Triple::mipsel:
|
||||
case Triple::mips64:
|
||||
|
||||
@@ -610,6 +610,7 @@ static int64_t getTlsTpOffset(const Symbol &s) {
|
||||
// to allow a signed 16-bit offset to reach 0x1000 of TCB/thread-library
|
||||
// data and 0xf000 of the program's TLS segment.
|
||||
return s.getVA(0) + (tls->p_vaddr & (tls->p_align - 1)) - 0x7000;
|
||||
case EM_LOONGARCH:
|
||||
case EM_RISCV:
|
||||
return s.getVA(0) + (tls->p_vaddr & (tls->p_align - 1));
|
||||
|
||||
@@ -644,6 +645,14 @@ uint64_t InputSectionBase::getRelocTargetVA(const InputFile *file, RelType type,
|
||||
case R_GOT:
|
||||
case R_RELAX_TLS_GD_TO_IE_ABS:
|
||||
return sym.getGotVA() + a;
|
||||
case R_LOONGARCH_GOT:
|
||||
// The LoongArch TLS GD relocs reuse the R_LARCH_GOT_PC_LO12 reloc type
|
||||
// for their page offsets. The arithmetics are different in the TLS case
|
||||
// so we have to duplicate some logic here.
|
||||
if (sym.hasFlag(NEEDS_TLSGD) && type != R_LARCH_TLS_IE_PC_LO12)
|
||||
// Like R_LOONGARCH_TLSGD_PAGE_PC but taking the absolute value.
|
||||
return in.got->getGlobalDynAddr(sym) + a;
|
||||
return getRelocTargetVA(file, type, a, p, sym, R_GOT);
|
||||
case R_GOTONLY_PC:
|
||||
return in.got->getVA() + a - p;
|
||||
case R_GOTPLTONLY_PC:
|
||||
@@ -668,6 +677,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_LOONGARCH_GOT_PAGE_PC:
|
||||
if (sym.hasFlag(NEEDS_TLSGD))
|
||||
return getLoongArchPageDelta(in.got->getGlobalDynAddr(sym) + a, p);
|
||||
return getLoongArchPageDelta(sym.getGotVA() + a, p);
|
||||
case R_MIPS_GOTREL:
|
||||
return sym.getVA(a) - in.mipsGot->getGp(file);
|
||||
case R_MIPS_GOT_GP:
|
||||
@@ -716,6 +729,8 @@ uint64_t InputSectionBase::getRelocTargetVA(const InputFile *file, RelType type,
|
||||
*hiRel->sym, hiRel->expr);
|
||||
return 0;
|
||||
}
|
||||
case R_LOONGARCH_PAGE_PC:
|
||||
return getLoongArchPageDelta(sym.getVA(a), p);
|
||||
case R_PC:
|
||||
case R_ARM_PCA: {
|
||||
uint64_t dest;
|
||||
@@ -749,6 +764,8 @@ uint64_t InputSectionBase::getRelocTargetVA(const InputFile *file, RelType type,
|
||||
case R_PLT_PC:
|
||||
case R_PPC64_CALL_PLT:
|
||||
return sym.getPltVA() + a - p;
|
||||
case R_LOONGARCH_PLT_PAGE_PC:
|
||||
return getLoongArchPageDelta(sym.getPltVA() + a, p);
|
||||
case R_PLT_GOTPLT:
|
||||
return sym.getPltVA() + a - in.gotPlt->getVA();
|
||||
case R_PPC32_PLTREL:
|
||||
@@ -809,6 +826,8 @@ uint64_t InputSectionBase::getRelocTargetVA(const InputFile *file, RelType type,
|
||||
return in.got->getGlobalDynAddr(sym) + a - in.gotPlt->getVA();
|
||||
case R_TLSGD_PC:
|
||||
return in.got->getGlobalDynAddr(sym) + a - p;
|
||||
case R_LOONGARCH_TLSGD_PAGE_PC:
|
||||
return getLoongArchPageDelta(in.got->getGlobalDynAddr(sym) + a, p);
|
||||
case R_TLSLD_GOTPLT:
|
||||
return in.got->getVA() + in.got->getTlsIndexOff() + a - in.gotPlt->getVA();
|
||||
case R_TLSLD_GOT:
|
||||
|
||||
@@ -195,8 +195,8 @@ 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_PPC32_PLTREL, R_PPC64_CALL_PLT>(
|
||||
expr);
|
||||
return oneof<R_PLT, R_PLT_PC, R_PLT_GOTPLT, R_LOONGARCH_PLT_PAGE_PC,
|
||||
R_PPC32_PLTREL, R_PPC64_CALL_PLT>(expr);
|
||||
}
|
||||
|
||||
// Returns true if Expr refers a GOT entry. Note that this function
|
||||
@@ -205,7 +205,8 @@ static bool needsPlt(RelExpr expr) {
|
||||
static bool needsGot(RelExpr expr) {
|
||||
return oneof<R_GOT, R_GOT_OFF, R_MIPS_GOT_LOCAL_PAGE, R_MIPS_GOT_OFF,
|
||||
R_MIPS_GOT_OFF32, R_AARCH64_GOT_PAGE_PC, R_GOT_PC, R_GOTPLT,
|
||||
R_AARCH64_GOT_PAGE>(expr);
|
||||
R_AARCH64_GOT_PAGE, R_LOONGARCH_GOT, R_LOONGARCH_GOT_PAGE_PC>(
|
||||
expr);
|
||||
}
|
||||
|
||||
// True if this expression is of the form Sym - X, where X is a position in the
|
||||
@@ -213,12 +214,14 @@ static bool needsGot(RelExpr expr) {
|
||||
static bool isRelExpr(RelExpr expr) {
|
||||
return oneof<R_PC, R_GOTREL, R_GOTPLTREL, R_MIPS_GOTREL, R_PPC64_CALL,
|
||||
R_PPC64_RELAX_TOC, R_AARCH64_PAGE_PC, R_RELAX_GOT_PC,
|
||||
R_RISCV_PC_INDIRECT, R_PPC64_RELAX_GOT_PC>(expr);
|
||||
R_RISCV_PC_INDIRECT, R_PPC64_RELAX_GOT_PC, R_LOONGARCH_PAGE_PC>(
|
||||
expr);
|
||||
}
|
||||
|
||||
|
||||
static RelExpr toPlt(RelExpr expr) {
|
||||
switch (expr) {
|
||||
case R_LOONGARCH_PAGE_PC:
|
||||
return R_LOONGARCH_PLT_PAGE_PC;
|
||||
case R_PPC64_CALL:
|
||||
return R_PPC64_CALL_PLT;
|
||||
case R_PC:
|
||||
@@ -237,6 +240,8 @@ static RelExpr fromPlt(RelExpr expr) {
|
||||
case R_PLT_PC:
|
||||
case R_PPC32_PLTREL:
|
||||
return R_PC;
|
||||
case R_LOONGARCH_PLT_PAGE_PC:
|
||||
return R_LOONGARCH_PAGE_PC;
|
||||
case R_PPC64_CALL_PLT:
|
||||
return R_PPC64_CALL;
|
||||
case R_PLT:
|
||||
@@ -951,7 +956,9 @@ bool RelocationScanner::isStaticLinkTimeConstant(RelExpr e, RelType type,
|
||||
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>(e))
|
||||
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
|
||||
@@ -1055,7 +1062,9 @@ void RelocationScanner::processAux(RelExpr expr, RelType type, uint64_t offset,
|
||||
// for detailed description:
|
||||
// ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
|
||||
in.mipsGot->addEntry(*sec->file, sym, addend, expr);
|
||||
} else {
|
||||
} else if (!sym.isTls() || config->emachine != EM_LOONGARCH) {
|
||||
// Many LoongArch TLS relocs reuse the R_LOONGARCH_GOT type, in which
|
||||
// case the NEEDS_GOT flag shouldn't get set.
|
||||
sym.setFlags(NEEDS_GOT);
|
||||
}
|
||||
} else if (needsPlt(expr)) {
|
||||
@@ -1095,7 +1104,8 @@ void RelocationScanner::processAux(RelExpr expr, RelType type, uint64_t offset,
|
||||
(isa<EhInputSection>(sec) && config->emachine != EM_MIPS));
|
||||
if (canWrite) {
|
||||
RelType rel = target->getDynRel(type);
|
||||
if (expr == R_GOT || (rel == target->symbolicRel && !sym.isPreemptible)) {
|
||||
if (oneof<R_GOT, R_LOONGARCH_GOT>(expr) ||
|
||||
(rel == target->symbolicRel && !sym.isPreemptible)) {
|
||||
addRelativeReloc<true>(*sec, offset, sym, addend, expr, type);
|
||||
return;
|
||||
} else if (rel != 0) {
|
||||
@@ -1247,11 +1257,13 @@ static unsigned handleTlsRelocation(RelType type, Symbol &sym,
|
||||
return 1;
|
||||
}
|
||||
|
||||
// ARM, Hexagon and RISC-V do not support GD/LD to IE/LE relaxation. For
|
||||
// PPC64, if the file has missing R_PPC64_TLSGD/R_PPC64_TLSLD, disable
|
||||
// ARM, Hexagon, LoongArch and RISC-V do not support GD/LD to IE/LE
|
||||
// relaxation.
|
||||
// For PPC64, if the file has missing R_PPC64_TLSGD/R_PPC64_TLSLD, disable
|
||||
// relaxation as well.
|
||||
bool toExecRelax = !config->shared && config->emachine != EM_ARM &&
|
||||
config->emachine != EM_HEXAGON &&
|
||||
config->emachine != EM_LOONGARCH &&
|
||||
config->emachine != EM_RISCV &&
|
||||
!c.file->ppc64DisableTLSRelax;
|
||||
|
||||
@@ -1268,8 +1280,7 @@ static unsigned handleTlsRelocation(RelType type, Symbol &sym,
|
||||
// being suitable for being dynamically loaded via dlopen. GOT[e0] is the
|
||||
// module index, with a special value of 0 for the current module. GOT[e1] is
|
||||
// unused. There only needs to be one module index entry.
|
||||
if (oneof<R_TLSLD_GOT, R_TLSLD_GOTPLT, R_TLSLD_PC, R_TLSLD_HINT>(
|
||||
expr)) {
|
||||
if (oneof<R_TLSLD_GOT, R_TLSLD_GOTPLT, R_TLSLD_PC, R_TLSLD_HINT>(expr)) {
|
||||
// Local-Dynamic relocs can be relaxed to Local-Exec.
|
||||
if (toExecRelax) {
|
||||
c.addReloc({target->adjustTlsExpr(type, R_RELAX_TLS_LD_TO_LE), type,
|
||||
@@ -1300,7 +1311,8 @@ static unsigned handleTlsRelocation(RelType type, Symbol &sym,
|
||||
}
|
||||
|
||||
if (oneof<R_AARCH64_TLSDESC_PAGE, R_TLSDESC, R_TLSDESC_CALL, R_TLSDESC_PC,
|
||||
R_TLSDESC_GOTPLT, R_TLSGD_GOT, R_TLSGD_GOTPLT, R_TLSGD_PC>(expr)) {
|
||||
R_TLSDESC_GOTPLT, R_TLSGD_GOT, R_TLSGD_GOTPLT, R_TLSGD_PC,
|
||||
R_LOONGARCH_TLSGD_PAGE_PC>(expr)) {
|
||||
if (!toExecRelax) {
|
||||
sym.setFlags(NEEDS_TLSGD);
|
||||
c.addReloc({expr, type, offset, addend, &sym});
|
||||
@@ -1320,8 +1332,8 @@ static unsigned handleTlsRelocation(RelType type, Symbol &sym,
|
||||
return target->getTlsGdRelaxSkip(type);
|
||||
}
|
||||
|
||||
if (oneof<R_GOT, R_GOTPLT, R_GOT_PC, R_AARCH64_GOT_PAGE_PC, R_GOT_OFF,
|
||||
R_TLSIE_HINT>(expr)) {
|
||||
if (oneof<R_GOT, R_GOTPLT, R_GOT_PC, R_AARCH64_GOT_PAGE_PC,
|
||||
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 relaxed to Local-Exec if the symbol is locally
|
||||
// defined.
|
||||
|
||||
@@ -102,6 +102,15 @@ enum RelExpr {
|
||||
R_PPC64_RELAX_GOT_PC,
|
||||
R_RISCV_ADD,
|
||||
R_RISCV_PC_INDIRECT,
|
||||
// Same as R_PC but with page-aligned semantics.
|
||||
R_LOONGARCH_PAGE_PC,
|
||||
// Same as R_PLT_PC but with page-aligned semantics.
|
||||
R_LOONGARCH_PLT_PAGE_PC,
|
||||
// In addition to having page-aligned semantics, LoongArch GOT relocs are
|
||||
// also reused for TLS, making the semantics differ from other architectures.
|
||||
R_LOONGARCH_GOT,
|
||||
R_LOONGARCH_GOT_PAGE_PC,
|
||||
R_LOONGARCH_TLSGD_PAGE_PC,
|
||||
};
|
||||
|
||||
// Architecture-neutral representation of relocation.
|
||||
|
||||
@@ -445,6 +445,8 @@ static std::pair<ELFKind, uint16_t> parseBfdName(StringRef s) {
|
||||
.Case("elf64-littleriscv", {ELF64LEKind, EM_RISCV})
|
||||
.Case("elf64-sparc", {ELF64BEKind, EM_SPARCV9})
|
||||
.Case("elf32-msp430", {ELF32LEKind, EM_MSP430})
|
||||
.Case("elf32-loongarch", {ELF32LEKind, EM_LOONGARCH})
|
||||
.Case("elf64-loongarch", {ELF64LEKind, EM_LOONGARCH})
|
||||
.Default({ELFNoneKind, EM_NONE});
|
||||
}
|
||||
|
||||
|
||||
@@ -62,6 +62,8 @@ TargetInfo *elf::getTarget() {
|
||||
return getAVRTargetInfo();
|
||||
case EM_HEXAGON:
|
||||
return getHexagonTargetInfo();
|
||||
case EM_LOONGARCH:
|
||||
return getLoongArchTargetInfo();
|
||||
case EM_MIPS:
|
||||
switch (config->ekind) {
|
||||
case ELF32LEKind:
|
||||
|
||||
@@ -179,6 +179,7 @@ TargetInfo *getAMDGPUTargetInfo();
|
||||
TargetInfo *getARMTargetInfo();
|
||||
TargetInfo *getAVRTargetInfo();
|
||||
TargetInfo *getHexagonTargetInfo();
|
||||
TargetInfo *getLoongArchTargetInfo();
|
||||
TargetInfo *getMSP430TargetInfo();
|
||||
TargetInfo *getPPC64TargetInfo();
|
||||
TargetInfo *getPPCTargetInfo();
|
||||
@@ -225,6 +226,7 @@ void addPPC64SaveRestore();
|
||||
uint64_t getPPC64TocBase();
|
||||
uint64_t getAArch64Page(uint64_t expr);
|
||||
template <typename ELFT> void writeARMCmseImportLib();
|
||||
uint64_t getLoongArchPageDelta(uint64_t dest, uint64_t pc);
|
||||
void riscvFinalizeRelax(int passes);
|
||||
void mergeRISCVAttributesSections();
|
||||
void addArmInputSectionMappingSymbols();
|
||||
|
||||
@@ -51,6 +51,7 @@ ELF Improvements
|
||||
* Program header assignment can now be used within ``OVERLAY``. This functionality was accidentally lost in 2020.
|
||||
(`D150445 <https://reviews.llvm.org/D150445>`_)
|
||||
* Operators ``^`` and ``^=`` can now be used in linker scripts.
|
||||
* LoongArch is now supported.
|
||||
* ``DT_AARCH64_MEMTAG_*`` dynamic tags are now supported.
|
||||
(`D143769 <https://reviews.llvm.org/D143769>`_)
|
||||
* AArch32 port now supports BE-8 and BE-32 modes for big-endian.
|
||||
|
||||
@@ -22,10 +22,11 @@ Features
|
||||
machine, you can expect that LLD runs more than twice as fast as the GNU
|
||||
gold linker. Your mileage may vary, though.
|
||||
|
||||
- It supports various CPUs/ABIs including AArch64, AMDGPU, ARM, Hexagon, MIPS
|
||||
32/64 big/little-endian, PowerPC, PowerPC64, RISC-V, SPARC V9, x86-32 and
|
||||
x86-64. Among these, AArch64, ARM (>= v4), PowerPC, PowerPC64, RISC-V, x86-32
|
||||
and x86-64 have production quality. MIPS seems decent too.
|
||||
- It supports various CPUs/ABIs including AArch64, AMDGPU, ARM, Hexagon,
|
||||
LoongArch, MIPS 32/64 big/little-endian, PowerPC, PowerPC64, RISC-V,
|
||||
SPARC V9, x86-32 and x86-64. Among these, AArch64, ARM (>= v4), LoongArch,
|
||||
PowerPC, PowerPC64, RISC-V, x86-32 and x86-64 have production quality.
|
||||
MIPS seems decent too.
|
||||
|
||||
- It is always a cross-linker, meaning that it always supports all the
|
||||
above targets however it was built. In fact, we don't provide a
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
.\"
|
||||
.\" This man page documents only lld's ELF linking support, obtained originally
|
||||
.\" from FreeBSD.
|
||||
.Dd Feb 9, 2023
|
||||
.Dd Jul 25, 2023
|
||||
.Dt LD.LLD 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
@@ -27,8 +27,8 @@ It accepts most of the same command line arguments and linker scripts
|
||||
as GNU linkers.
|
||||
.Pp
|
||||
.Nm
|
||||
currently supports i386, x86-64, ARM, AArch64, PowerPC32, PowerPC64,
|
||||
MIPS32, MIPS64, RISC-V, AMDGPU, Hexagon and SPARC V9 targets.
|
||||
currently supports i386, x86-64, ARM, AArch64, LoongArch, PowerPC32,
|
||||
PowerPC64, MIPS32, MIPS64, RISC-V, AMDGPU, Hexagon and SPARC V9 targets.
|
||||
.Nm
|
||||
acts as a Microsoft link.exe-compatible linker if invoked as
|
||||
.Nm lld-link
|
||||
|
||||
78
lld/test/ELF/emulation-loongarch.s
Normal file
78
lld/test/ELF/emulation-loongarch.s
Normal file
@@ -0,0 +1,78 @@
|
||||
# REQUIRES: loongarch
|
||||
|
||||
# RUN: llvm-mc -filetype=obj -triple=loongarch32 %s -o %t.o
|
||||
# RUN: ld.lld %t.o -o %t
|
||||
# RUN: llvm-readobj --file-headers %t | FileCheck --check-prefix=LA32 %s
|
||||
# RUN: ld.lld -m elf32loongarch %t.o -o %t
|
||||
# RUN: llvm-readobj --file-headers %t | FileCheck --check-prefix=LA32 %s
|
||||
# RUN: echo 'OUTPUT_FORMAT(elf32-loongarch)' > %t.script
|
||||
# RUN: ld.lld %t.script %t.o -o %t
|
||||
# RUN: llvm-readobj --file-headers %t | FileCheck --check-prefix=LA32 %s
|
||||
|
||||
# LA32: ElfHeader {
|
||||
# LA32-NEXT: Ident {
|
||||
# LA32-NEXT: Magic: (7F 45 4C 46)
|
||||
# LA32-NEXT: Class: 32-bit (0x1)
|
||||
# LA32-NEXT: DataEncoding: LittleEndian (0x1)
|
||||
# LA32-NEXT: FileVersion: 1
|
||||
# LA32-NEXT: OS/ABI: SystemV (0x0)
|
||||
# LA32-NEXT: ABIVersion: 0
|
||||
# LA32-NEXT: Unused: (00 00 00 00 00 00 00)
|
||||
# LA32-NEXT: }
|
||||
# LA32-NEXT: Type: Executable (0x2)
|
||||
# LA32-NEXT: Machine: EM_LOONGARCH (0x102)
|
||||
# LA32-NEXT: Version: 1
|
||||
# LA32-NEXT: Entry:
|
||||
# LA32-NEXT: ProgramHeaderOffset: 0x34
|
||||
# LA32-NEXT: SectionHeaderOffset:
|
||||
# LA32-NEXT: Flags [ (0x43)
|
||||
# LA32-NEXT: EF_LOONGARCH_ABI_DOUBLE_FLOAT (0x3)
|
||||
# LA32-NEXT: EF_LOONGARCH_OBJABI_V1 (0x40)
|
||||
# LA32-NEXT: ]
|
||||
# LA32-NEXT: HeaderSize: 52
|
||||
# LA32-NEXT: ProgramHeaderEntrySize: 32
|
||||
# LA32-NEXT: ProgramHeaderCount:
|
||||
# LA32-NEXT: SectionHeaderEntrySize: 40
|
||||
# LA32-NEXT: SectionHeaderCount:
|
||||
# LA32-NEXT: StringTableSectionIndex:
|
||||
# LA32-NEXT: }
|
||||
|
||||
# RUN: llvm-mc -filetype=obj -triple=loongarch64 %s -o %t.o
|
||||
# RUN: ld.lld %t.o -o %t
|
||||
# RUN: llvm-readobj --file-headers %t | FileCheck --check-prefix=LA64 %s
|
||||
# RUN: ld.lld -m elf64loongarch %t.o -o %t
|
||||
# RUN: llvm-readobj --file-headers %t | FileCheck --check-prefix=LA64 %s
|
||||
# RUN: echo 'OUTPUT_FORMAT(elf64-loongarch)' > %t.script
|
||||
# RUN: ld.lld %t.script %t.o -o %t
|
||||
# RUN: llvm-readobj --file-headers %t | FileCheck --check-prefix=LA64 %s
|
||||
|
||||
# LA64: ElfHeader {
|
||||
# LA64-NEXT: Ident {
|
||||
# LA64-NEXT: Magic: (7F 45 4C 46)
|
||||
# LA64-NEXT: Class: 64-bit (0x2)
|
||||
# LA64-NEXT: DataEncoding: LittleEndian (0x1)
|
||||
# LA64-NEXT: FileVersion: 1
|
||||
# LA64-NEXT: OS/ABI: SystemV (0x0)
|
||||
# LA64-NEXT: ABIVersion: 0
|
||||
# LA64-NEXT: Unused: (00 00 00 00 00 00 00)
|
||||
# LA64-NEXT: }
|
||||
# LA64-NEXT: Type: Executable (0x2)
|
||||
# LA64-NEXT: Machine: EM_LOONGARCH (0x102)
|
||||
# LA64-NEXT: Version: 1
|
||||
# LA64-NEXT: Entry:
|
||||
# LA64-NEXT: ProgramHeaderOffset: 0x40
|
||||
# LA64-NEXT: SectionHeaderOffset:
|
||||
# LA64-NEXT: Flags [ (0x43)
|
||||
# LA64-NEXT: EF_LOONGARCH_ABI_DOUBLE_FLOAT (0x3)
|
||||
# LA64-NEXT: EF_LOONGARCH_OBJABI_V1 (0x40)
|
||||
# LA64-NEXT: ]
|
||||
# LA64-NEXT: HeaderSize: 64
|
||||
# LA64-NEXT: ProgramHeaderEntrySize: 56
|
||||
# LA64-NEXT: ProgramHeaderCount:
|
||||
# LA64-NEXT: SectionHeaderEntrySize: 64
|
||||
# LA64-NEXT: SectionHeaderCount:
|
||||
# LA64-NEXT: StringTableSectionIndex:
|
||||
# LA64-NEXT: }
|
||||
|
||||
.globl _start
|
||||
_start:
|
||||
64
lld/test/ELF/loongarch-abs64.s
Normal file
64
lld/test/ELF/loongarch-abs64.s
Normal file
@@ -0,0 +1,64 @@
|
||||
# REQUIRES: loongarch
|
||||
|
||||
# RUN: llvm-mc --filetype=obj --triple=loongarch64-unknown-elf %s -o %t.la64.o
|
||||
|
||||
# RUN: ld.lld %t.la64.o --defsym foo=0 --defsym bar=42 -o %t.la64.1
|
||||
# RUN: llvm-objdump --no-show-raw-insn -d %t.la64.1 | FileCheck --check-prefix=CASE1 %s
|
||||
# CASE1: lu12i.w $a0, 0
|
||||
# CASE1-NEXT: ori $a0, $a0, 0
|
||||
# CASE1-NEXT: lu32i.d $a0, 0
|
||||
# CASE1-NEXT: lu52i.d $a0, $a0, 0
|
||||
# CASE1-NEXT: lu12i.w $a1, 0
|
||||
# CASE1-NEXT: ori $a1, $a1, 42
|
||||
# CASE1-NEXT: lu32i.d $a1, 0
|
||||
# CASE1-NEXT: lu52i.d $a1, $a1, 0
|
||||
|
||||
# RUN: ld.lld %t.la64.o --defsym foo=0x12345678 --defsym bar=0x87654321 -o %t.la64.2
|
||||
# RUN: llvm-objdump --no-show-raw-insn -d %t.la64.2 | FileCheck --check-prefix=CASE2 %s
|
||||
# CASE2: lu12i.w $a0, 74565
|
||||
# CASE2-NEXT: ori $a0, $a0, 1656
|
||||
# CASE2-NEXT: lu32i.d $a0, 0
|
||||
# CASE2-NEXT: lu52i.d $a0, $a0, 0
|
||||
# CASE2-NEXT: lu12i.w $a1, -493996
|
||||
# CASE2-NEXT: ori $a1, $a1, 801
|
||||
# CASE2-NEXT: lu32i.d $a1, 0
|
||||
# CASE2-NEXT: lu52i.d $a1, $a1, 0
|
||||
|
||||
# RUN: ld.lld %t.la64.o --defsym foo=0x12345fedcb678 --defsym bar=0xfedcb12345000 -o %t.la64.3
|
||||
# RUN: llvm-objdump --no-show-raw-insn -d %t.la64.3 | FileCheck --check-prefix=CASE3 %s
|
||||
# CASE3: lu12i.w $a0, -4661
|
||||
# CASE3-NEXT: ori $a0, $a0, 1656
|
||||
# CASE3-NEXT: lu32i.d $a0, 74565
|
||||
# CASE3-NEXT: lu52i.d $a0, $a0, 0
|
||||
# CASE3-NEXT: lu12i.w $a1, 74565
|
||||
# CASE3-NEXT: ori $a1, $a1, 0
|
||||
# CASE3-NEXT: lu32i.d $a1, -4661
|
||||
# CASE3-NEXT: lu52i.d $a1, $a1, 0
|
||||
|
||||
# RUN: ld.lld %t.la64.o --defsym foo=0xfffffeeeeeddd --defsym bar=0xfff00000f1111222 -o %t.la64.4
|
||||
# RUN: llvm-objdump --no-show-raw-insn -d %t.la64.4 | FileCheck --check-prefix=CASE4 %s
|
||||
# CASE4: lu12i.w $a0, -69906
|
||||
# CASE4-NEXT: ori $a0, $a0, 3549
|
||||
# CASE4-NEXT: lu32i.d $a0, -1
|
||||
# CASE4-NEXT: lu52i.d $a0, $a0, 0
|
||||
# CASE4-NEXT: lu12i.w $a1, -61167
|
||||
# CASE4-NEXT: ori $a1, $a1, 546
|
||||
# CASE4-NEXT: lu32i.d $a1, 0
|
||||
# CASE4-NEXT: lu52i.d $a1, $a1, -1
|
||||
|
||||
.global _start
|
||||
|
||||
_start:
|
||||
1:
|
||||
lu12i.w $a0, %abs_hi20(foo)
|
||||
.reloc 1b, R_LARCH_MARK_LA, foo
|
||||
ori $a0, $a0, %abs_lo12(foo)
|
||||
lu32i.d $a0, %abs64_lo20(foo)
|
||||
lu52i.d $a0, $a0, %abs64_hi12(foo)
|
||||
|
||||
2:
|
||||
lu12i.w $a1, %abs_hi20(bar)
|
||||
.reloc 1b, R_LARCH_MARK_LA, bar
|
||||
ori $a1, $a1, %abs_lo12(bar)
|
||||
lu32i.d $a1, %abs64_lo20(bar)
|
||||
lu52i.d $a1, $a1, %abs64_hi12(bar)
|
||||
36
lld/test/ELF/loongarch-add-sub.s
Normal file
36
lld/test/ELF/loongarch-add-sub.s
Normal file
@@ -0,0 +1,36 @@
|
||||
# REQUIRES: loongarch
|
||||
|
||||
# RUN: llvm-mc --filetype=obj --triple=loongarch64-unknown-elf %s -o %t.la64.o
|
||||
|
||||
# RUN: ld.lld --section-start=.rodata=0x1234567890 --section-start=.text=0x9876543210 %t.la64.o -o %t.la64
|
||||
# RUN: llvm-readelf -x .rodata %t.la64 | FileCheck --check-prefix=CHECK %s
|
||||
# CHECK: section '.rodata':
|
||||
# CHECK-NEXT: 0x1234567890 10325476 98badcfe 80b9fd41 86000000
|
||||
# CHECK-NEXT: 0x12345678a0 80b9fd41 80b980
|
||||
|
||||
.global _start
|
||||
|
||||
_start:
|
||||
1:
|
||||
break 0
|
||||
|
||||
.rodata
|
||||
2:
|
||||
.dword 0xfedcba9876543210
|
||||
|
||||
foo:
|
||||
.dword 0
|
||||
.reloc foo, R_LARCH_ADD64, 1b
|
||||
.reloc foo, R_LARCH_SUB64, 2b
|
||||
bar:
|
||||
.word 0
|
||||
.reloc bar, R_LARCH_ADD32, 1b
|
||||
.reloc bar, R_LARCH_SUB32, 2b
|
||||
baz:
|
||||
.short 0
|
||||
.reloc baz, R_LARCH_ADD16, 1b
|
||||
.reloc baz, R_LARCH_SUB16, 2b
|
||||
quux:
|
||||
.byte 0
|
||||
.reloc quux, R_LARCH_ADD8, 1b
|
||||
.reloc quux, R_LARCH_SUB8, 2b
|
||||
68
lld/test/ELF/loongarch-branch.s
Normal file
68
lld/test/ELF/loongarch-branch.s
Normal file
@@ -0,0 +1,68 @@
|
||||
# REQUIRES: loongarch
|
||||
|
||||
# RUN: llvm-mc --filetype=obj --triple=loongarch32-unknown-elf %s -o %t.la32.o
|
||||
# RUN: llvm-mc --filetype=obj --triple=loongarch64-unknown-elf %s -o %t.la64.o
|
||||
|
||||
# RUN: ld.lld %t.la32.o --defsym foo16=b16+4 --defsym bar16=b16 --defsym foo21=b21+4 --defsym bar21=b21 --defsym foo26=b26+4 --defsym bar26=b26 -o %t.la32
|
||||
# RUN: ld.lld %t.la64.o --defsym foo16=b16+4 --defsym bar16=b16 --defsym foo21=b21+4 --defsym bar21=b21 --defsym foo26=b26+4 --defsym bar26=b26 -o %t.la64
|
||||
# RUN: llvm-objdump --no-show-raw-insn -d %t.la32 | FileCheck %s --check-prefix=CHECK
|
||||
# RUN: llvm-objdump --no-show-raw-insn -d %t.la64 | FileCheck %s --check-prefix=CHECK
|
||||
# CHECK: beq $zero, $zero, 4
|
||||
# CHECK: bne $zero, $zero, -4
|
||||
# CHECK: beqz $s8, 4
|
||||
# CHECK: bnez $s8, -4
|
||||
# CHECK: b 4
|
||||
# CHECK: bl -4
|
||||
|
||||
# RUN: ld.lld %t.la32.o --defsym foo16=b16+0x1fffc --defsym bar16=b16+4-0x20000 --defsym foo21=b21+0x3ffffc --defsym bar21=b21+4-0x400000 --defsym foo26=b26+0x7fffffc --defsym bar26=b26+4-0x8000000 -o %t.la32.limits
|
||||
# RUN: ld.lld %t.la64.o --defsym foo16=b16+0x1fffc --defsym bar16=b16+4-0x20000 --defsym foo21=b21+0x3ffffc --defsym bar21=b21+4-0x400000 --defsym foo26=b26+0x7fffffc --defsym bar26=b26+4-0x8000000 -o %t.la64.limits
|
||||
# RUN: llvm-objdump --no-show-raw-insn -d %t.la32.limits | FileCheck --check-prefix=LIMITS %s
|
||||
# RUN: llvm-objdump --no-show-raw-insn -d %t.la64.limits | FileCheck --check-prefix=LIMITS %s
|
||||
# LIMITS: beq $zero, $zero, 131068
|
||||
# LIMITS-NEXT: bne $zero, $zero, -131072
|
||||
# LIMITS: beqz $s8, 4194300
|
||||
# LIMITS-NEXT: bnez $s8, -4194304
|
||||
# LIMITS: b 134217724
|
||||
# LIMITS-NEXT: bl -134217728
|
||||
|
||||
# RUN: not ld.lld %t.la32.o --defsym foo16=b16+0x20000 --defsym bar16=b16+4-0x20004 --defsym foo21=b21+0x400000 --defsym bar21=b21+4-0x400004 --defsym foo26=b26+0x8000000 --defsym bar26=b26+4-0x8000004 -o /dev/null 2>&1 | FileCheck -DFILE=%t.la32.o --check-prefix=ERROR-RANGE %s
|
||||
# RUN: not ld.lld %t.la64.o --defsym foo16=b16+0x20000 --defsym bar16=b16+4-0x20004 --defsym foo21=b21+0x400000 --defsym bar21=b21+4-0x400004 --defsym foo26=b26+0x8000000 --defsym bar26=b26+4-0x8000004 -o /dev/null 2>&1 | FileCheck -DFILE=%t.la64.o --check-prefix=ERROR-RANGE %s
|
||||
# ERROR-RANGE: error: [[FILE]]:(.text+0x0): relocation R_LARCH_B16 out of range: 131072 is not in [-131072, 131071]; references 'foo16'
|
||||
# ERROR-RANGE: error: [[FILE]]:(.text+0x4): relocation R_LARCH_B16 out of range: -131076 is not in [-131072, 131071]; references 'bar16'
|
||||
# ERROR-RANGE: error: [[FILE]]:(.text+0x8): relocation R_LARCH_B21 out of range: 4194304 is not in [-4194304, 4194303]; references 'foo21'
|
||||
# ERROR-RANGE: error: [[FILE]]:(.text+0xc): relocation R_LARCH_B21 out of range: -4194308 is not in [-4194304, 4194303]; references 'bar21'
|
||||
# ERROR-RANGE: error: [[FILE]]:(.text+0x10): relocation R_LARCH_B26 out of range: 134217728 is not in [-134217728, 134217727]; references 'foo26'
|
||||
# ERROR-RANGE: error: [[FILE]]:(.text+0x14): relocation R_LARCH_B26 out of range: -134217732 is not in [-134217728, 134217727]; references 'bar26'
|
||||
|
||||
# RUN: not ld.lld %t.la32.o --defsym foo16=b16+1 --defsym bar16=b16-1 --defsym foo21=b21+1 --defsym bar21=b21-1 --defsym foo26=b26+1 --defsym bar26=b26-1 -o /dev/null 2>&1 | FileCheck -DFILE=%t.la32.o --check-prefix=ERROR-ALIGN-1 %s
|
||||
# RUN: not ld.lld %t.la64.o --defsym foo16=b16+1 --defsym bar16=b16-1 --defsym foo21=b21+1 --defsym bar21=b21-1 --defsym foo26=b26+1 --defsym bar26=b26-1 -o /dev/null 2>&1 | FileCheck -DFILE=%t.la64.o --check-prefix=ERROR-ALIGN-1 %s
|
||||
# ERROR-ALIGN-1: error: [[FILE]]:(.text+0x0): improper alignment for relocation R_LARCH_B16: 0x1 is not aligned to 4 bytes
|
||||
# ERROR-ALIGN-1-NEXT: error: [[FILE]]:(.text+0x4): improper alignment for relocation R_LARCH_B16: 0xFFFFFFFFFFFFFFFB is not aligned to 4 bytes
|
||||
# ERROR-ALIGN-1-NEXT: error: [[FILE]]:(.text+0x8): improper alignment for relocation R_LARCH_B21: 0x1 is not aligned to 4 bytes
|
||||
# ERROR-ALIGN-1-NEXT: error: [[FILE]]:(.text+0xc): improper alignment for relocation R_LARCH_B21: 0xFFFFFFFFFFFFFFFB is not aligned to 4 bytes
|
||||
# ERROR-ALIGN-1-NEXT: error: [[FILE]]:(.text+0x10): improper alignment for relocation R_LARCH_B26: 0x1 is not aligned to 4 bytes
|
||||
# ERROR-ALIGN-1-NEXT: error: [[FILE]]:(.text+0x14): improper alignment for relocation R_LARCH_B26: 0xFFFFFFFFFFFFFFFB is not aligned to 4 bytes
|
||||
|
||||
# RUN: not ld.lld %t.la32.o --defsym foo16=b16+2 --defsym bar16=b16-2 --defsym foo21=b21+2 --defsym bar21=b21-2 --defsym foo26=b26+2 --defsym bar26=b26-2 -o /dev/null 2>&1 | FileCheck -DFILE=%t.la32.o --check-prefix=ERROR-ALIGN-2 %s
|
||||
# RUN: not ld.lld %t.la64.o --defsym foo16=b16+2 --defsym bar16=b16-2 --defsym foo21=b21+2 --defsym bar21=b21-2 --defsym foo26=b26+2 --defsym bar26=b26-2 -o /dev/null 2>&1 | FileCheck -DFILE=%t.la64.o --check-prefix=ERROR-ALIGN-2 %s
|
||||
# ERROR-ALIGN-2: error: [[FILE]]:(.text+0x0): improper alignment for relocation R_LARCH_B16: 0x2 is not aligned to 4 bytes
|
||||
# ERROR-ALIGN-2-NEXT: error: [[FILE]]:(.text+0x4): improper alignment for relocation R_LARCH_B16: 0xFFFFFFFFFFFFFFFA is not aligned to 4 bytes
|
||||
# ERROR-ALIGN-2-NEXT: error: [[FILE]]:(.text+0x8): improper alignment for relocation R_LARCH_B21: 0x2 is not aligned to 4 bytes
|
||||
# ERROR-ALIGN-2-NEXT: error: [[FILE]]:(.text+0xc): improper alignment for relocation R_LARCH_B21: 0xFFFFFFFFFFFFFFFA is not aligned to 4 bytes
|
||||
# ERROR-ALIGN-2-NEXT: error: [[FILE]]:(.text+0x10): improper alignment for relocation R_LARCH_B26: 0x2 is not aligned to 4 bytes
|
||||
# ERROR-ALIGN-2-NEXT: error: [[FILE]]:(.text+0x14): improper alignment for relocation R_LARCH_B26: 0xFFFFFFFFFFFFFFFA is not aligned to 4 bytes
|
||||
|
||||
.global _start
|
||||
.global b16
|
||||
.global b21
|
||||
.global b26
|
||||
_start:
|
||||
b16:
|
||||
beq $zero, $zero, foo16
|
||||
bne $zero, $zero, bar16
|
||||
b21:
|
||||
beqz $s8, foo21
|
||||
bnez $s8, bar21
|
||||
b26:
|
||||
b foo26
|
||||
bl bar26
|
||||
84
lld/test/ELF/loongarch-interlink.test
Normal file
84
lld/test/ELF/loongarch-interlink.test
Normal file
@@ -0,0 +1,84 @@
|
||||
# REQUIRES: loongarch
|
||||
# RUN: rm -rf %t && split-file %s %t
|
||||
|
||||
# RUN: yaml2obj %t/blob.yaml -o %t/blob.o
|
||||
# RUN: yaml2obj %t/v0-lp64d.yaml -o %t/v0-lp64d.o
|
||||
# RUN: llvm-mc --filetype=obj --triple=loongarch64-unknown-gnu %t/start.s -o %t/v1-lp64d.o
|
||||
# RUN: llvm-mc --filetype=obj --triple=loongarch64-unknown-gnusf %t/start.s -o %t/v1-lp64s.o
|
||||
# RUN: llvm-mc --filetype=obj --triple=loongarch64-unknown-gnu %t/bar.s -o %t/v1-b-lp64d.o
|
||||
|
||||
## Check that binary input results in e_flags=0 output.
|
||||
# RUN: ld.lld -m elf64loongarch -b binary %t/blob.bin -o %t/blob.out
|
||||
# RUN: llvm-readobj -h %t/blob.out | FileCheck --check-prefix=EMPTY %s
|
||||
# EMPTY: Flags [
|
||||
# EMPTY-NEXT: ]
|
||||
|
||||
## Check that interlink between e_flags=0 and normal input (that contain code)
|
||||
## is allowed.
|
||||
## Also check that the e_flags logic work as intended regardless of input file
|
||||
## order.
|
||||
# RUN: ld.lld %t/blob.o %t/v1-lp64d.o -o %t/v1-lp64d.out
|
||||
# RUN: ld.lld %t/v1-lp64s.o %t/blob.o -o %t/v1-lp64s.out
|
||||
# RUN: llvm-readobj -h %t/v1-lp64d.out | FileCheck --check-prefix=V1-LP64D %s
|
||||
# RUN: llvm-readobj -h %t/v1-lp64s.out | FileCheck --check-prefix=V1-LP64S %s
|
||||
# V1-LP64D: Flags [ (0x43)
|
||||
# V1-LP64S: Flags [ (0x41)
|
||||
|
||||
## Check that interlink between different ABIs is disallowed.
|
||||
# RUN: not ld.lld %t/v1-lp64s.o %t/v1-b-lp64d.o -o /dev/null 2>&1 | FileCheck -DFILE1=%t/v1-b-lp64d.o -DFILE2=%t/v1-lp64s.o --check-prefix=INTERLINK-ERR %s
|
||||
# INTERLINK-ERR: error: [[FILE1]]: cannot link object files with different ABI from [[FILE2]]
|
||||
|
||||
## Check that interlink between different object ABI versions is disallowed.
|
||||
# RUN: not ld.lld %t/v0-lp64d.o %t/v1-b-lp64d.o %t/blob.o -o /dev/null 2>&1 | FileCheck -DFILE=%t/v0-lp64d.o --check-prefix=VERSION-ERR %s
|
||||
# VERSION-ERR: error: [[FILE]]: unsupported object file ABI version
|
||||
|
||||
#--- blob.bin
|
||||
BLOB
|
||||
|
||||
#--- blob.yaml
|
||||
--- !ELF
|
||||
FileHeader:
|
||||
Class: ELFCLASS64
|
||||
Data: ELFDATA2LSB
|
||||
Type: ET_REL
|
||||
Machine: EM_LOONGARCH
|
||||
SectionHeaderStringTable: .strtab
|
||||
Sections:
|
||||
- Name: .data
|
||||
Type: SHT_PROGBITS
|
||||
Flags: [ SHF_WRITE, SHF_ALLOC ]
|
||||
AddressAlign: 0x1
|
||||
Content: 424C4F42
|
||||
Symbols:
|
||||
- Name: blob
|
||||
Section: .data
|
||||
Binding: STB_GLOBAL
|
||||
|
||||
#--- v0-lp64d.yaml
|
||||
--- !ELF
|
||||
FileHeader:
|
||||
Class: ELFCLASS64
|
||||
Data: ELFDATA2LSB
|
||||
Type: ET_REL
|
||||
Machine: EM_LOONGARCH
|
||||
Flags: [ EF_LOONGARCH_ABI_DOUBLE_FLOAT ]
|
||||
SectionHeaderStringTable: .strtab
|
||||
Sections:
|
||||
- Name: .text
|
||||
Type: SHT_PROGBITS
|
||||
Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
|
||||
AddressAlign: 0x4
|
||||
Content: 0000a002
|
||||
|
||||
#--- start.s
|
||||
.global _start
|
||||
_start:
|
||||
la $a0, blob
|
||||
ld.b $a0, $a0, 0
|
||||
li.w $a7, 94
|
||||
syscall 0
|
||||
|
||||
#--- bar.s
|
||||
bar:
|
||||
move $a0, $zero
|
||||
ret
|
||||
283
lld/test/ELF/loongarch-pc-aligned.s
Normal file
283
lld/test/ELF/loongarch-pc-aligned.s
Normal file
@@ -0,0 +1,283 @@
|
||||
# REQUIRES: loongarch
|
||||
# RUN: rm -rf %t && split-file %s %t
|
||||
|
||||
# RUN: llvm-mc --filetype=obj --triple=loongarch32 %t/a.s -o %t/a.la32.o
|
||||
# RUN: llvm-mc --filetype=obj --triple=loongarch64 %t/a.s -o %t/a.la64.o
|
||||
# RUN: llvm-mc --filetype=obj --triple=loongarch64 %t/extreme.s -o %t/extreme.o
|
||||
|
||||
# RUN: ld.lld %t/a.la32.o --section-start=.rodata=0x11000 --section-start=.text=0x11ffc -o %t/case1.la32
|
||||
# RUN: ld.lld %t/a.la64.o --section-start=.rodata=0x11000 --section-start=.text=0x11ffc -o %t/case1.la64
|
||||
# RUN: llvm-objdump -d --no-show-raw-insn %t/case1.la32 | FileCheck %s --check-prefix=CASE1
|
||||
# RUN: llvm-objdump -d --no-show-raw-insn %t/case1.la64 | FileCheck %s --check-prefix=CASE1
|
||||
# CASE1: pcalau12i $a0, 0
|
||||
# CASE1-NEXT: ld.w $a0, $a0, 0
|
||||
|
||||
# RUN: ld.lld %t/a.la32.o --section-start=.rodata=0x11000 --section-start=.text=0x12000 -o %t/case2.la32
|
||||
# RUN: ld.lld %t/a.la64.o --section-start=.rodata=0x11000 --section-start=.text=0x12000 -o %t/case2.la64
|
||||
# RUN: llvm-objdump -d --no-show-raw-insn %t/case2.la32 | FileCheck %s --check-prefix=CASE2
|
||||
# RUN: llvm-objdump -d --no-show-raw-insn %t/case2.la64 | FileCheck %s --check-prefix=CASE2
|
||||
# CASE2: pcalau12i $a0, -1
|
||||
# CASE2-NEXT: ld.w $a0, $a0, 0
|
||||
|
||||
# RUN: ld.lld %t/a.la32.o --section-start=.rodata=0x117ff --section-start=.text=0x12000 -o %t/case3.la32
|
||||
# RUN: ld.lld %t/a.la64.o --section-start=.rodata=0x117ff --section-start=.text=0x12000 -o %t/case3.la64
|
||||
# RUN: llvm-objdump -d --no-show-raw-insn %t/case3.la32 | FileCheck %s --check-prefix=CASE3
|
||||
# RUN: llvm-objdump -d --no-show-raw-insn %t/case3.la64 | FileCheck %s --check-prefix=CASE3
|
||||
# CASE3: pcalau12i $a0, -1
|
||||
# CASE3-NEXT: ld.w $a0, $a0, 2047
|
||||
|
||||
# RUN: ld.lld %t/a.la32.o --section-start=.rodata=0x11800 --section-start=.text=0x12000 -o %t/case4.la32
|
||||
# RUN: ld.lld %t/a.la64.o --section-start=.rodata=0x11800 --section-start=.text=0x12000 -o %t/case4.la64
|
||||
# RUN: llvm-objdump -d --no-show-raw-insn %t/case4.la32 | FileCheck %s --check-prefix=CASE4
|
||||
# RUN: llvm-objdump -d --no-show-raw-insn %t/case4.la64 | FileCheck %s --check-prefix=CASE4
|
||||
# CASE4: pcalau12i $a0, 0
|
||||
# CASE4-NEXT: ld.w $a0, $a0, -2048
|
||||
|
||||
# RUN: ld.lld %t/a.la32.o --section-start=.rodata=0x12004 --section-start=.text=0x11ffc -o %t/case5.la32
|
||||
# RUN: ld.lld %t/a.la64.o --section-start=.rodata=0x12004 --section-start=.text=0x11ffc -o %t/case5.la64
|
||||
# RUN: llvm-objdump -d --no-show-raw-insn %t/case5.la32 | FileCheck %s --check-prefix=CASE5
|
||||
# RUN: llvm-objdump -d --no-show-raw-insn %t/case5.la64 | FileCheck %s --check-prefix=CASE5
|
||||
# CASE5: pcalau12i $a0, 1
|
||||
# CASE5-NEXT: ld.w $a0, $a0, 4
|
||||
|
||||
# RUN: ld.lld %t/a.la32.o --section-start=.rodata=0x12800 --section-start=.text=0x11ffc -o %t/case6.la32
|
||||
# RUN: ld.lld %t/a.la64.o --section-start=.rodata=0x12800 --section-start=.text=0x11ffc -o %t/case6.la64
|
||||
# RUN: llvm-objdump -d --no-show-raw-insn %t/case6.la32 | FileCheck %s --check-prefix=CASE6
|
||||
# RUN: llvm-objdump -d --no-show-raw-insn %t/case6.la64 | FileCheck %s --check-prefix=CASE6
|
||||
# CASE6: pcalau12i $a0, 2
|
||||
# CASE6-NEXT: ld.w $a0, $a0, -2048
|
||||
|
||||
# RUN: ld.lld %t/a.la32.o --section-start=.rodata=0x7ffff123 --section-start=.text=0x0 -o %t/case7.la32
|
||||
# RUN: ld.lld %t/a.la64.o --section-start=.rodata=0x7ffff123 --section-start=.text=0x0 -o %t/case7.la64
|
||||
# RUN: llvm-objdump -d --no-show-raw-insn %t/case7.la32 | FileCheck %s --check-prefix=CASE7
|
||||
# RUN: llvm-objdump -d --no-show-raw-insn %t/case7.la64 | FileCheck %s --check-prefix=CASE7
|
||||
# CASE7: pcalau12i $a0, 524287
|
||||
# CASE7-NEXT: ld.w $a0, $a0, 291
|
||||
|
||||
# RUN: ld.lld %t/a.la32.o --section-start=.rodata=0x7ffffabc --section-start=.text=0x0 -o %t/case8.la32
|
||||
# RUN: ld.lld %t/a.la64.o --section-start=.rodata=0x7ffffabc --section-start=.text=0x0 -o %t/case8.la64
|
||||
# RUN: llvm-objdump -d --no-show-raw-insn %t/case8.la32 | FileCheck %s --check-prefix=CASE8
|
||||
# RUN: llvm-objdump -d --no-show-raw-insn %t/case8.la64 | FileCheck %s --check-prefix=CASE8
|
||||
# CASE8: pcalau12i $a0, -524288
|
||||
# CASE8-NEXT: ld.w $a0, $a0, -1348
|
||||
|
||||
# RUN: ld.lld %t/a.la32.o --section-start=.rodata=0x10123 --section-start=.text=0x80010000 -o %t/case9.la32
|
||||
# RUN: ld.lld %t/a.la64.o --section-start=.rodata=0x10123 --section-start=.text=0x80010000 -o %t/case9.la64
|
||||
# RUN: llvm-objdump -d --no-show-raw-insn %t/case9.la32 | FileCheck %s --check-prefix=CASE9
|
||||
# RUN: llvm-objdump -d --no-show-raw-insn %t/case9.la64 | FileCheck %s --check-prefix=CASE9
|
||||
# CASE9: pcalau12i $a0, -524288
|
||||
# CASE9-NEXT: ld.w $a0, $a0, 291
|
||||
|
||||
## page delta = 0x4443333322222000, page offset = 0x111
|
||||
## %pc_lo12 = 0x111 = 273
|
||||
## %pc_hi20 = 0x22222 = 139810
|
||||
## %pc64_lo20 = 0x33333 = 209715
|
||||
## %pc64_hi12 = 0x444 = 1092
|
||||
# RUN: ld.lld %t/extreme.o --section-start=.rodata=0x4443333334567111 --section-start=.text=0x0000000012345678 -o %t/extreme0
|
||||
# RUN: llvm-objdump -d --no-show-raw-insn %t/extreme0 | FileCheck %s --check-prefix=EXTREME0
|
||||
# EXTREME0: addi.d $t0, $zero, 273
|
||||
# EXTREME0-NEXT: pcalau12i $t1, 139810
|
||||
# EXTREME0-NEXT: lu32i.d $t0, 209715
|
||||
# EXTREME0-NEXT: lu52i.d $t0, $t0, 1092
|
||||
|
||||
## page delta = 0x4443333222223000, page offset = 0x888
|
||||
## %pc_lo12 = 0x888 = -1912
|
||||
## %pc_hi20 = 0x22223 = 139811
|
||||
## %pc64_lo20 = 0x33332 = 209714
|
||||
## %pc64_hi12 = 0x444 = 1092
|
||||
# RUN: ld.lld %t/extreme.o --section-start=.rodata=0x4443333334567888 --section-start=.text=0x0000000012345678 -o %t/extreme1
|
||||
# RUN: llvm-objdump -d --no-show-raw-insn %t/extreme1 | FileCheck %s --check-prefix=EXTREME1
|
||||
# EXTREME1: addi.d $t0, $zero, -1912
|
||||
# EXTREME1-NEXT: pcalau12i $t1, 139811
|
||||
# EXTREME1-NEXT: lu32i.d $t0, 209714
|
||||
# EXTREME1-NEXT: lu52i.d $t0, $t0, 1092
|
||||
|
||||
## page delta = 0x4443333499999000, page offset = 0x111
|
||||
## %pc_lo12 = 0x111 = 273
|
||||
## %pc_hi20 = 0x99999 = -419431
|
||||
## %pc64_lo20 = 0x33334 = 209716
|
||||
## %pc64_hi12 = 0x444 = 1092
|
||||
# RUN: ld.lld %t/extreme.o --section-start=.rodata=0x44433333abcde111 --section-start=.text=0x0000000012345678 -o %t/extreme2
|
||||
# RUN: llvm-objdump -d --no-show-raw-insn %t/extreme2 | FileCheck %s --check-prefix=EXTREME2
|
||||
# EXTREME2: addi.d $t0, $zero, 273
|
||||
# EXTREME2-NEXT: pcalau12i $t1, -419431
|
||||
# EXTREME2-NEXT: lu32i.d $t0, 209716
|
||||
# EXTREME2-NEXT: lu52i.d $t0, $t0, 1092
|
||||
|
||||
## page delta = 0x444333339999a000, page offset = 0x888
|
||||
## %pc_lo12 = 0x888 = -1912
|
||||
## %pc_hi20 = 0x9999a = -419430
|
||||
## %pc64_lo20 = 0x33333 = 209715
|
||||
## %pc64_hi12 = 0x444 = 1092
|
||||
# RUN: ld.lld %t/extreme.o --section-start=.rodata=0x44433333abcde888 --section-start=.text=0x0000000012345678 -o %t/extreme3
|
||||
# RUN: llvm-objdump -d --no-show-raw-insn %t/extreme3 | FileCheck %s --check-prefix=EXTREME3
|
||||
# EXTREME3: addi.d $t0, $zero, -1912
|
||||
# EXTREME3-NEXT: pcalau12i $t1, -419430
|
||||
# EXTREME3-NEXT: lu32i.d $t0, 209715
|
||||
# EXTREME3-NEXT: lu52i.d $t0, $t0, 1092
|
||||
|
||||
## page delta = 0x444aaaaa22222000, page offset = 0x111
|
||||
## %pc_lo12 = 0x111 = 273
|
||||
## %pc_hi20 = 0x22222 = 139810
|
||||
## %pc64_lo20 = 0xaaaaa = -349526
|
||||
## %pc64_hi12 = 0x444 = 1092
|
||||
# RUN: ld.lld %t/extreme.o --section-start=.rodata=0x444aaaaa34567111 --section-start=.text=0x0000000012345678 -o %t/extreme4
|
||||
# RUN: llvm-objdump -d --no-show-raw-insn %t/extreme4 | FileCheck %s --check-prefix=EXTREME4
|
||||
# EXTREME4: addi.d $t0, $zero, 273
|
||||
# EXTREME4-NEXT: pcalau12i $t1, 139810
|
||||
# EXTREME4-NEXT: lu32i.d $t0, -349526
|
||||
# EXTREME4-NEXT: lu52i.d $t0, $t0, 1092
|
||||
|
||||
## page delta = 0x444aaaa922223000, page offset = 0x888
|
||||
## %pc_lo12 = 0x888 = -1912
|
||||
## %pc_hi20 = 0x22223 = 139811
|
||||
## %pc64_lo20 = 0xaaaa9 = -349527
|
||||
## %pc64_hi12 = 0x444 = 1092
|
||||
# RUN: ld.lld %t/extreme.o --section-start=.rodata=0x444aaaaa34567888 --section-start=.text=0x0000000012345678 -o %t/extreme5
|
||||
# RUN: llvm-objdump -d --no-show-raw-insn %t/extreme5 | FileCheck %s --check-prefix=EXTREME5
|
||||
# EXTREME5: addi.d $t0, $zero, -1912
|
||||
# EXTREME5-NEXT: pcalau12i $t1, 139811
|
||||
# EXTREME5-NEXT: lu32i.d $t0, -349527
|
||||
# EXTREME5-NEXT: lu52i.d $t0, $t0, 1092
|
||||
|
||||
## page delta = 0x444aaaab99999000, page offset = 0x111
|
||||
## %pc_lo12 = 0x111 = 273
|
||||
## %pc_hi20 = 0x99999 = -419431
|
||||
## %pc64_lo20 = 0xaaaab = -349525
|
||||
## %pc64_hi12 = 0x444 = 1092
|
||||
# RUN: ld.lld %t/extreme.o --section-start=.rodata=0x444aaaaaabcde111 --section-start=.text=0x0000000012345678 -o %t/extreme6
|
||||
# RUN: llvm-objdump -d --no-show-raw-insn %t/extreme6 | FileCheck %s --check-prefix=EXTREME6
|
||||
# EXTREME6: addi.d $t0, $zero, 273
|
||||
# EXTREME6-NEXT: pcalau12i $t1, -419431
|
||||
# EXTREME6-NEXT: lu32i.d $t0, -349525
|
||||
# EXTREME6-NEXT: lu52i.d $t0, $t0, 1092
|
||||
|
||||
## page delta = 0x444aaaaa9999a000, page offset = 0x888
|
||||
## %pc_lo12 = 0x888 = -1912
|
||||
## %pc_hi20 = 0x9999a = -419430
|
||||
## %pc64_lo20 = 0xaaaaa = -349526
|
||||
## %pc64_hi12 = 0x444 = 1092
|
||||
# RUN: ld.lld %t/extreme.o --section-start=.rodata=0x444aaaaaabcde888 --section-start=.text=0x0000000012345678 -o %t/extreme7
|
||||
# RUN: llvm-objdump -d --no-show-raw-insn %t/extreme7 | FileCheck %s --check-prefix=EXTREME7
|
||||
# EXTREME7: addi.d $t0, $zero, -1912
|
||||
# EXTREME7-NEXT: pcalau12i $t1, -419430
|
||||
# EXTREME7-NEXT: lu32i.d $t0, -349526
|
||||
# EXTREME7-NEXT: lu52i.d $t0, $t0, 1092
|
||||
|
||||
## page delta = 0xbbb3333322222000, page offset = 0x111
|
||||
## %pc_lo12 = 0x111 = 273
|
||||
## %pc_hi20 = 0x22222 = 139810
|
||||
## %pc64_lo20 = 0x33333 = 209715
|
||||
## %pc64_hi12 = 0xbbb = -1093
|
||||
# RUN: ld.lld %t/extreme.o --section-start=.rodata=0xbbb3333334567111 --section-start=.text=0x0000000012345678 -o %t/extreme8
|
||||
# RUN: llvm-objdump -d --no-show-raw-insn %t/extreme8 | FileCheck %s --check-prefix=EXTREME8
|
||||
# EXTREME8: addi.d $t0, $zero, 273
|
||||
# EXTREME8-NEXT: pcalau12i $t1, 139810
|
||||
# EXTREME8-NEXT: lu32i.d $t0, 209715
|
||||
# EXTREME8-NEXT: lu52i.d $t0, $t0, -1093
|
||||
|
||||
## page delta = 0xbbb3333222223000, page offset = 0x888
|
||||
## %pc_lo12 = 0x888 = -1912
|
||||
## %pc_hi20 = 0x22223 = 139811
|
||||
## %pc64_lo20 = 0x33332 = 209714
|
||||
## %pc64_hi12 = 0xbbb = -1093
|
||||
# RUN: ld.lld %t/extreme.o --section-start=.rodata=0xbbb3333334567888 --section-start=.text=0x0000000012345678 -o %t/extreme9
|
||||
# RUN: llvm-objdump -d --no-show-raw-insn %t/extreme9 | FileCheck %s --check-prefix=EXTREME9
|
||||
# EXTREME9: addi.d $t0, $zero, -1912
|
||||
# EXTREME9-NEXT: pcalau12i $t1, 139811
|
||||
# EXTREME9-NEXT: lu32i.d $t0, 209714
|
||||
# EXTREME9-NEXT: lu52i.d $t0, $t0, -1093
|
||||
|
||||
## page delta = 0xbbb3333499999000, page offset = 0x111
|
||||
## %pc_lo12 = 0x111 = 273
|
||||
## %pc_hi20 = 0x99999 = -419431
|
||||
## %pc64_lo20 = 0x33334 = 209716
|
||||
## %pc64_hi12 = 0xbbb = -1093
|
||||
# RUN: ld.lld %t/extreme.o --section-start=.rodata=0xbbb33333abcde111 --section-start=.text=0x0000000012345678 -o %t/extreme10
|
||||
# RUN: llvm-objdump -d --no-show-raw-insn %t/extreme10 | FileCheck %s --check-prefix=EXTREME10
|
||||
# EXTREME10: addi.d $t0, $zero, 273
|
||||
# EXTREME10-NEXT: pcalau12i $t1, -419431
|
||||
# EXTREME10-NEXT: lu32i.d $t0, 209716
|
||||
# EXTREME10-NEXT: lu52i.d $t0, $t0, -1093
|
||||
|
||||
## page delta = 0xbbb333339999a000, page offset = 0x888
|
||||
## %pc_lo12 = 0x888 = -1912
|
||||
## %pc_hi20 = 0x9999a = -419430
|
||||
## %pc64_lo20 = 0x33333 = 209715
|
||||
## %pc64_hi12 = 0xbbb = -1093
|
||||
# RUN: ld.lld %t/extreme.o --section-start=.rodata=0xbbb33333abcde888 --section-start=.text=0x0000000012345678 -o %t/extreme11
|
||||
# RUN: llvm-objdump -d --no-show-raw-insn %t/extreme11 | FileCheck %s --check-prefix=EXTREME11
|
||||
# EXTREME11: addi.d $t0, $zero, -1912
|
||||
# EXTREME11-NEXT: pcalau12i $t1, -419430
|
||||
# EXTREME11-NEXT: lu32i.d $t0, 209715
|
||||
# EXTREME11-NEXT: lu52i.d $t0, $t0, -1093
|
||||
|
||||
## page delta = 0xbbbaaaaa22222000, page offset = 0x111
|
||||
## %pc_lo12 = 0x111 = 273
|
||||
## %pc_hi20 = 0x22222 = 139810
|
||||
## %pc64_lo20 = 0xaaaaa = -349526
|
||||
## %pc64_hi12 = 0xbbb = -1093
|
||||
# RUN: ld.lld %t/extreme.o --section-start=.rodata=0xbbbaaaaa34567111 --section-start=.text=0x0000000012345678 -o %t/extreme12
|
||||
# RUN: llvm-objdump -d --no-show-raw-insn %t/extreme12 | FileCheck %s --check-prefix=EXTREME12
|
||||
# EXTREME12: addi.d $t0, $zero, 273
|
||||
# EXTREME12-NEXT: pcalau12i $t1, 139810
|
||||
# EXTREME12-NEXT: lu32i.d $t0, -349526
|
||||
# EXTREME12-NEXT: lu52i.d $t0, $t0, -1093
|
||||
|
||||
## page delta = 0xbbbaaaa922223000, page offset = 0x888
|
||||
## %pc_lo12 = 0x888 = -1912
|
||||
## %pc_hi20 = 0x22223 = 139811
|
||||
## %pc64_lo20 = 0xaaaa9 = -349527
|
||||
## %pc64_hi12 = 0xbbb = -1093
|
||||
# RUN: ld.lld %t/extreme.o --section-start=.rodata=0xbbbaaaaa34567888 --section-start=.text=0x0000000012345678 -o %t/extreme13
|
||||
# RUN: llvm-objdump -d --no-show-raw-insn %t/extreme13 | FileCheck %s --check-prefix=EXTREME13
|
||||
# EXTREME13: addi.d $t0, $zero, -1912
|
||||
# EXTREME13-NEXT: pcalau12i $t1, 139811
|
||||
# EXTREME13-NEXT: lu32i.d $t0, -349527
|
||||
# EXTREME13-NEXT: lu52i.d $t0, $t0, -1093
|
||||
|
||||
## page delta = 0xbbbaaaab99999000, page offset = 0x111
|
||||
## %pc_lo12 = 0x111 = 273
|
||||
## %pc_hi20 = 0x99999 = -419431
|
||||
## %pc64_lo20 = 0xaaaab = -349525
|
||||
## %pc64_hi12 = 0xbbb = -1093
|
||||
# RUN: ld.lld %t/extreme.o --section-start=.rodata=0xbbbaaaaaabcde111 --section-start=.text=0x0000000012345678 -o %t/extreme14
|
||||
# RUN: llvm-objdump -d --no-show-raw-insn %t/extreme14 | FileCheck %s --check-prefix=EXTREME14
|
||||
# EXTREME14: addi.d $t0, $zero, 273
|
||||
# EXTREME14-NEXT: pcalau12i $t1, -419431
|
||||
# EXTREME14-NEXT: lu32i.d $t0, -349525
|
||||
# EXTREME14-NEXT: lu52i.d $t0, $t0, -1093
|
||||
|
||||
## page delta = 0xbbbaaaaa9999a000, page offset = 0x888
|
||||
## %pc_lo12 = 0x888 = -1912
|
||||
## %pc_hi20 = 0x9999a = -419430
|
||||
## %pc64_lo20 = 0xaaaaa = -349526
|
||||
## %pc64_hi12 = 0xbbb = -1093
|
||||
# RUN: ld.lld %t/extreme.o --section-start=.rodata=0xbbbaaaaaabcde888 --section-start=.text=0x0000000012345678 -o %t/extreme15
|
||||
# RUN: llvm-objdump -d --no-show-raw-insn %t/extreme15 | FileCheck %s --check-prefix=EXTREME15
|
||||
# EXTREME15: addi.d $t0, $zero, -1912
|
||||
# EXTREME15-NEXT: pcalau12i $t1, -419430
|
||||
# EXTREME15-NEXT: lu32i.d $t0, -349526
|
||||
# EXTREME15-NEXT: lu52i.d $t0, $t0, -1093
|
||||
|
||||
#--- a.s
|
||||
.rodata
|
||||
x:
|
||||
.word 10
|
||||
.text
|
||||
.global _start
|
||||
_start:
|
||||
pcalau12i $a0, %pc_hi20(x)
|
||||
ld.w $a0, $a0, %pc_lo12(x)
|
||||
|
||||
#--- extreme.s
|
||||
.rodata
|
||||
x:
|
||||
.word 10
|
||||
.text
|
||||
.global _start
|
||||
_start:
|
||||
addi.d $t0, $zero, %pc_lo12(x)
|
||||
pcalau12i $t1, %pc_hi20(x)
|
||||
lu32i.d $t0, %pc64_lo20(x)
|
||||
lu52i.d $t0, $t0, %pc64_hi12(x)
|
||||
60
lld/test/ELF/loongarch-pcala-lo12-jirl-shared.s
Normal file
60
lld/test/ELF/loongarch-pcala-lo12-jirl-shared.s
Normal file
@@ -0,0 +1,60 @@
|
||||
# REQUIRES: loongarch
|
||||
# RUN: rm -rf %t && split-file %s %t
|
||||
|
||||
# RUN: llvm-mc --filetype=obj --triple=loongarch32-unknown-elf %t/a.s -o %t/a.la32.o
|
||||
# RUN: llvm-mc --filetype=obj --triple=loongarch64-unknown-elf %t/a.s -o %t/a.la64.o
|
||||
|
||||
# RUN: ld.lld %t/a.la32.o -shared -T %t/a.t -o %t/a.la32.so
|
||||
# RUN: ld.lld %t/a.la64.o -shared -T %t/a.t -o %t/a.la64.so
|
||||
|
||||
# RUN: llvm-objdump -d --no-show-raw-insn %t/a.la32.so | FileCheck --check-prefixes=DIS,DIS32 %s
|
||||
# RUN: llvm-objdump -d --no-show-raw-insn %t/a.la64.so | FileCheck --check-prefixes=DIS,DIS64 %s
|
||||
|
||||
## PLT should be present in this case.
|
||||
# DIS: Disassembly of section .plt:
|
||||
# DIS: <.plt>:
|
||||
# DIS: 234020: pcaddu12i $t3, 510
|
||||
# DIS32-NEXT: ld.w $t3, $t3, 84
|
||||
# DIS64-NEXT: ld.d $t3, $t3, 184
|
||||
# DIS-NEXT: jirl $t1, $t3, 0
|
||||
# DIS-NEXT: nop
|
||||
|
||||
# DIS: Disassembly of section .text:
|
||||
# DIS: <foo>:
|
||||
# DIS-NEXT: nop
|
||||
# DIS-NEXT: nop
|
||||
# DIS-NEXT: nop
|
||||
# DIS-NEXT: pcalau12i $t0, -510
|
||||
# DIS-NEXT: jirl $zero, $t0, 32
|
||||
|
||||
# RUN: llvm-mc --filetype=obj --triple=loongarch32-unknown-elf %t/error.s -o %t/error.la32.o
|
||||
# RUN: llvm-mc --filetype=obj --triple=loongarch64-unknown-elf %t/error.s -o %t/error.la64.o
|
||||
# RUN: not ld.lld %t/error.la32.o -shared -o %t/error.la32.so 2>&1 | FileCheck --check-prefix=ERR %s
|
||||
# RUN: not ld.lld %t/error.la64.o -shared -o %t/error.la64.so 2>&1 | FileCheck --check-prefix=ERR %s
|
||||
# ERR: error: relocation R_LARCH_PCALA_LO12 cannot be used against symbol 'bar'; recompile with -fPIC
|
||||
|
||||
#--- a.t
|
||||
SECTIONS {
|
||||
.plt 0x234000: { *(.plt) }
|
||||
.text 0x432000: { *(.text) }
|
||||
}
|
||||
|
||||
#--- a.s
|
||||
.p2align 12
|
||||
.global foo
|
||||
foo:
|
||||
## The nops are for pushing the relocs off page boundary, to better see the
|
||||
## page-aligned semantics in action.
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
## The offsets should be -510 (0x234 - 0x432) and 32 (PLT header size + 0)
|
||||
## respectively.
|
||||
pcalau12i $t0, %pc_hi20(bar)
|
||||
jirl $zero, $t0, %pc_lo12(bar)
|
||||
|
||||
#--- error.s
|
||||
.global foo
|
||||
foo:
|
||||
pcalau12i $t0, %pc_hi20(bar)
|
||||
ld.w $t0, $t0, %pc_lo12(bar)
|
||||
42
lld/test/ELF/loongarch-pcala-lo12-jirl.s
Normal file
42
lld/test/ELF/loongarch-pcala-lo12-jirl.s
Normal file
@@ -0,0 +1,42 @@
|
||||
# REQUIRES: loongarch
|
||||
|
||||
# RUN: llvm-mc --filetype=obj --triple=loongarch32-unknown-elf %s -o %t.la32.o
|
||||
# RUN: llvm-mc --filetype=obj --triple=loongarch64-unknown-elf %s -o %t.la64.o
|
||||
|
||||
# RUN: ld.lld %t.la32.o -o %t.la32
|
||||
# RUN: ld.lld %t.la64.o -o %t.la64
|
||||
# RUN: llvm-objdump -d --no-show-raw-insn %t.la32 | FileCheck %s
|
||||
# RUN: llvm-objdump -d --no-show-raw-insn %t.la64 | FileCheck %s
|
||||
# CHECK: pcalau12i $t0, -1
|
||||
# CHECK-NEXT: jirl $ra, $t0, 564
|
||||
# CHECK-NEXT: pcalau12i $t0, 0
|
||||
# CHECK-NEXT: jirl $zero, $t0, -1348
|
||||
|
||||
## PLT shouldn't get generated in this case.
|
||||
# CHECK-NOT: Disassembly of section .plt:
|
||||
|
||||
.p2align 12
|
||||
.org 0x234
|
||||
.global foo
|
||||
foo:
|
||||
li.w $a0, 42
|
||||
ret
|
||||
|
||||
.org 0xabc
|
||||
.global bar
|
||||
bar:
|
||||
li.w $a7, 94
|
||||
syscall 0
|
||||
|
||||
.org 0x1000
|
||||
.global _start
|
||||
_start:
|
||||
## The nops are for pushing the relocs off page boundary, to better see the
|
||||
## page-aligned semantics in action.
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
pcalau12i $t0, %pc_hi20(foo)
|
||||
jirl $ra, $t0, %pc_lo12(foo)
|
||||
pcalau12i $t0, %pc_hi20(bar)
|
||||
jirl $zero, $t0, %pc_lo12(bar)
|
||||
108
lld/test/ELF/loongarch-plt.s
Normal file
108
lld/test/ELF/loongarch-plt.s
Normal file
@@ -0,0 +1,108 @@
|
||||
# REQUIRES: loongarch
|
||||
# RUN: echo '.globl bar, weak; .type bar,@function; .type weak,@function; bar: weak:' > %t1.s
|
||||
|
||||
# RUN: llvm-mc --filetype=obj --triple=loongarch32 %t1.s -o %t1.32.o
|
||||
# RUN: ld.lld -shared %t1.32.o -soname=t1.32.so -o %t1.32.so
|
||||
# RUN: llvm-mc --filetype=obj --triple=loongarch32 %s -o %t.32.o
|
||||
# RUN: ld.lld %t.32.o %t1.32.so -z separate-code -o %t.32
|
||||
# RUN: llvm-readelf -S -s %t.32 | FileCheck --check-prefixes=SEC,NM %s
|
||||
# RUN: llvm-readobj -r %t.32 | FileCheck --check-prefix=RELOC32 %s
|
||||
# RUN: llvm-readelf -x .got.plt %t.32 | FileCheck --check-prefix=GOTPLT32 %s
|
||||
# RUN: llvm-objdump -d --no-show-raw-insn %t.32 | FileCheck --check-prefixes=DIS,DIS32 %s
|
||||
|
||||
# RUN: llvm-mc --filetype=obj --triple=loongarch64 %t1.s -o %t1.64.o
|
||||
# RUN: ld.lld -shared %t1.64.o -soname=t1.64.so -o %t1.64.so
|
||||
# RUN: llvm-mc --filetype=obj --triple=loongarch64 %s -o %t.64.o
|
||||
# RUN: ld.lld %t.64.o %t1.64.so -z separate-code -o %t.64
|
||||
# RUN: llvm-readelf -S -s %t.64 | FileCheck --check-prefixes=SEC,NM %s
|
||||
# RUN: llvm-readobj -r %t.64 | FileCheck --check-prefix=RELOC64 %s
|
||||
# RUN: llvm-readelf -x .got.plt %t.64 | FileCheck --check-prefix=GOTPLT64 %s
|
||||
# RUN: llvm-objdump -d --no-show-raw-insn %t.64 | FileCheck --check-prefixes=DIS,DIS64 %s
|
||||
|
||||
# SEC: .plt PROGBITS {{0*}}00020020
|
||||
|
||||
## 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.
|
||||
# NM: {{0*}}00000000 0 FUNC GLOBAL DEFAULT UND bar
|
||||
# NM: {{0*}}00000000 0 FUNC WEAK DEFAULT UND weak
|
||||
|
||||
## The .got.plt slots relocated by .rela.plt point to .plt
|
||||
## This is required by glibc.
|
||||
# RELOC32: .rela.plt {
|
||||
# RELOC32-NEXT: 0x40070 R_LARCH_JUMP_SLOT bar 0x0
|
||||
# RELOC32-NEXT: 0x40074 R_LARCH_JUMP_SLOT weak 0x0
|
||||
# RELOC32-NEXT: }
|
||||
# GOTPLT32: section '.got.plt'
|
||||
# GOTPLT32-NEXT: 0x00040068 00000000 00000000 20000200 20000200
|
||||
|
||||
# RELOC64: .rela.plt {
|
||||
# RELOC64-NEXT: 0x400E0 R_LARCH_JUMP_SLOT bar 0x0
|
||||
# RELOC64-NEXT: 0x400E8 R_LARCH_JUMP_SLOT weak 0x0
|
||||
# RELOC64-NEXT: }
|
||||
# GOTPLT64: section '.got.plt'
|
||||
# GOTPLT64-NEXT: 0x000400d0 00000000 00000000 00000000 00000000
|
||||
# GOTPLT64-NEXT: 0x000400e0 20000200 00000000 20000200 00000000
|
||||
|
||||
# DIS: <_start>:
|
||||
## Direct call
|
||||
## foo - . = 0x20010-0x20000 = 16
|
||||
# DIS-NEXT: 20000: bl 16
|
||||
## bar@plt - . = 0x20040-0x20004 = 60
|
||||
# DIS-NEXT: 20004: bl 60
|
||||
## bar@plt - . = 0x20040-0x20008 = 56
|
||||
# DIS-NEXT: 20008: bl 56
|
||||
## weak@plt - . = 0x20050-0x2000c = 68
|
||||
# DIS-NEXT: 2000c: bl 68
|
||||
# DIS: <foo>:
|
||||
# DIS-NEXT: 20010:
|
||||
|
||||
# DIS: Disassembly of section .plt:
|
||||
# DIS: <.plt>:
|
||||
## 32-bit: .got.plt - .plt = 0x40068 - 0x20020 = 4096*32+72
|
||||
# DIS32-NEXT: pcaddu12i $t2, 32
|
||||
# DIS32-NEXT: sub.w $t1, $t1, $t3
|
||||
# DIS32-NEXT: ld.w $t3, $t2, 72
|
||||
# DIS32-NEXT: addi.w $t1, $t1, -44
|
||||
# DIS32-NEXT: addi.w $t0, $t2, 72
|
||||
# DIS32-NEXT: srli.w $t1, $t1, 2
|
||||
# DIS32-NEXT: ld.w $t0, $t0, 4
|
||||
# DIS32-NEXT: jr $t3
|
||||
|
||||
## 64-bit: .got.plt - .plt = 0x400d0 - 0x20020 = 4096*32+176
|
||||
# DIS64-NEXT: pcaddu12i $t2, 32
|
||||
# DIS64-NEXT: sub.d $t1, $t1, $t3
|
||||
# DIS64-NEXT: ld.d $t3, $t2, 176
|
||||
# DIS64-NEXT: addi.d $t1, $t1, -44
|
||||
# DIS64-NEXT: addi.d $t0, $t2, 176
|
||||
# DIS64-NEXT: srli.d $t1, $t1, 1
|
||||
# DIS64-NEXT: ld.d $t0, $t0, 8
|
||||
# DIS64-NEXT: jr $t3
|
||||
|
||||
## 32-bit: &.got.plt[bar]-. = 0x40070-0x20040 = 4096*32+48
|
||||
## 64-bit: &.got.plt[bar]-. = 0x400e0-0x20040 = 4096*32+160
|
||||
# DIS: 20040: pcaddu12i $t3, 32
|
||||
# DIS32-NEXT: ld.w $t3, $t3, 48
|
||||
# DIS64-NEXT: ld.d $t3, $t3, 160
|
||||
# DIS-NEXT: jirl $t1, $t3, 0
|
||||
# DIS-NEXT: nop
|
||||
|
||||
## 32-bit: &.got.plt[weak]-. = 0x40074-0x20050 = 4096*32+36
|
||||
## 64-bit: &.got.plt[weak]-. = 0x400e8-0x20050 = 4096*32+152
|
||||
# DIS: 20050: pcaddu12i $t3, 32
|
||||
# DIS32-NEXT: ld.w $t3, $t3, 36
|
||||
# DIS64-NEXT: ld.d $t3, $t3, 152
|
||||
# DIS-NEXT: jirl $t1, $t3, 0
|
||||
# DIS-NEXT: nop
|
||||
|
||||
.global _start, foo, bar
|
||||
.weak weak
|
||||
|
||||
_start:
|
||||
bl foo
|
||||
bl bar
|
||||
bl %plt(bar)
|
||||
bl weak
|
||||
|
||||
## foo is local and non-preemptible, no PLT is generated.
|
||||
foo:
|
||||
ret
|
||||
44
lld/test/ELF/loongarch-reloc-pic.s
Normal file
44
lld/test/ELF/loongarch-reloc-pic.s
Normal file
@@ -0,0 +1,44 @@
|
||||
# REQUIRES: loongarch
|
||||
# RUN: rm -rf %t && split-file %s %t
|
||||
|
||||
# RUN: llvm-mc --filetype=obj --triple=loongarch32 %t/32.s -o %t/32.o
|
||||
# RUN: llvm-mc --filetype=obj --triple=loongarch64 %t/64.s -o %t/64.o
|
||||
# RUN: ld.lld -shared %t/32.o -o %t/32.so
|
||||
# RUN: llvm-nm %t/32.so | FileCheck --check-prefix=NM32 %s
|
||||
# RUN: llvm-readobj -r %t/32.so | FileCheck --check-prefix=RELOC32 %s
|
||||
# RUN: ld.lld -shared %t/64.o -o %t/64.so
|
||||
# RUN: llvm-nm %t/64.so | FileCheck --check-prefix=NM64 %s
|
||||
# RUN: llvm-readobj -r %t/64.so | FileCheck --check-prefix=RELOC64 %s
|
||||
|
||||
## R_LARCH_32 and R_LARCH_64 are absolute relocation types.
|
||||
## In PIC mode, they create relative relocations if the symbol is non-preemptable.
|
||||
|
||||
# NM32: 000301fc d b
|
||||
# NM64: 00030350 d b
|
||||
|
||||
# RELOC32: .rela.dyn {
|
||||
# RELOC32-NEXT: 0x301FC R_LARCH_RELATIVE - 0x301FC
|
||||
# RELOC32-NEXT: 0x301F8 R_LARCH_32 a 0
|
||||
# RELOC32-NEXT: }
|
||||
# RELOC64: .rela.dyn {
|
||||
# RELOC64-NEXT: 0x30350 R_LARCH_RELATIVE - 0x30350
|
||||
# RELOC64-NEXT: 0x30348 R_LARCH_64 a 0
|
||||
# RELOC64-NEXT: }
|
||||
|
||||
#--- 32.s
|
||||
.globl a, b
|
||||
.hidden b
|
||||
|
||||
.data
|
||||
.long a
|
||||
b:
|
||||
.long b
|
||||
|
||||
#--- 64.s
|
||||
.globl a, b
|
||||
.hidden b
|
||||
|
||||
.data
|
||||
.quad a
|
||||
b:
|
||||
.quad b
|
||||
46
lld/test/ELF/loongarch-tls-gd-edge-case.s
Normal file
46
lld/test/ELF/loongarch-tls-gd-edge-case.s
Normal file
@@ -0,0 +1,46 @@
|
||||
# REQUIRES: loongarch
|
||||
|
||||
## Edge case: when a TLS symbol is being accessed in both GD and IE manners,
|
||||
## correct reloc behavior should be preserved for both kinds of accesses.
|
||||
|
||||
# RUN: llvm-mc --filetype=obj --triple=loongarch32 %s -o %t.la32.o
|
||||
# RUN: ld.lld %t.la32.o -shared -o %t.la32
|
||||
# RUN: llvm-mc --filetype=obj --triple=loongarch64 %s -o %t.la64.o
|
||||
# RUN: ld.lld %t.la64.o -shared -o %t.la64
|
||||
|
||||
# RUN: llvm-readelf -Wr %t.la32 | FileCheck --check-prefix=LA32-REL %s
|
||||
# RUN: llvm-objdump -d --no-show-raw-insn %t.la32 | FileCheck --check-prefix=LA32 %s
|
||||
|
||||
# RUN: llvm-readelf -Wr %t.la64 | FileCheck --check-prefix=LA64-REL %s
|
||||
# RUN: llvm-objdump -d --no-show-raw-insn %t.la64 | FileCheck --check-prefix=LA64 %s
|
||||
|
||||
# LA32-REL-NOT: R_LARCH_32
|
||||
# LA32-REL: 0002023c 00000206 R_LARCH_TLS_DTPMOD32 00000000 y + 0
|
||||
# LA32-REL-NEXT: 00020240 00000208 R_LARCH_TLS_DTPREL32 00000000 y + 0
|
||||
# LA32-REL-NEXT: 00020244 0000020a R_LARCH_TLS_TPREL32 00000000 y + 0
|
||||
|
||||
# LA64-REL-NOT: R_LARCH_64
|
||||
# LA64-REL: 00000000000203a0 0000000200000007 R_LARCH_TLS_DTPMOD64 0000000000000000 y + 0
|
||||
# LA64-REL-NEXT: 00000000000203a8 0000000200000009 R_LARCH_TLS_DTPREL64 0000000000000000 y + 0
|
||||
# LA64-REL-NEXT: 00000000000203b0 000000020000000b R_LARCH_TLS_TPREL64 0000000000000000 y + 0
|
||||
|
||||
# LA32: 101d4: pcalau12i $a0, 16
|
||||
# LA32-NEXT: ld.w $a0, $a0, 580
|
||||
# LA32-NEXT: pcalau12i $a1, 16
|
||||
# LA32-NEXT: addi.w $a1, $a1, 572
|
||||
|
||||
# LA64: 102e0: pcalau12i $a0, 16
|
||||
# LA64-NEXT: ld.d $a0, $a0, 944
|
||||
# LA64-NEXT: pcalau12i $a1, 16
|
||||
# LA64-NEXT: addi.d $a1, $a1, 928
|
||||
|
||||
.global _start
|
||||
_start:
|
||||
la.tls.ie $a0, y # should refer to the GOT entry relocated by the R_LARCH_TLS_TPRELnn record
|
||||
la.tls.gd $a1, y # should refer to the GOT entry relocated by the R_LARCH_TLS_DTPMODnn record
|
||||
|
||||
.section .tbss,"awT",@nobits
|
||||
.global y
|
||||
y:
|
||||
.word 0
|
||||
.size y, 4
|
||||
136
lld/test/ELF/loongarch-tls-gd.s
Normal file
136
lld/test/ELF/loongarch-tls-gd.s
Normal file
@@ -0,0 +1,136 @@
|
||||
# REQUIRES: loongarch
|
||||
# RUN: rm -rf %t && split-file %s %t
|
||||
|
||||
## LoongArch psABI doesn't specify TLS relaxation. Though the code sequences are not
|
||||
## relaxed, dynamic relocations can be omitted for GD->LE relaxation.
|
||||
|
||||
# RUN: llvm-mc --filetype=obj --triple=loongarch32 %t/a.s -o %t/a.32.o
|
||||
# RUN: llvm-mc --filetype=obj --triple=loongarch32 %t/bc.s -o %t/bc.32.o
|
||||
# RUN: ld.lld -shared -soname=bc.so %t/bc.32.o -o %t/bc.32.so
|
||||
# RUN: llvm-mc --filetype=obj --triple=loongarch32 %t/tga.s -o %t/tga.32.o
|
||||
# RUN: llvm-mc --filetype=obj --triple=loongarch64 %t/a.s -o %t/a.64.o
|
||||
# RUN: llvm-mc --filetype=obj --triple=loongarch64 %t/bc.s -o %t/bc.64.o
|
||||
# RUN: ld.lld -shared -soname=bc.so %t/bc.64.o -o %t/bc.64.so
|
||||
# RUN: llvm-mc --filetype=obj --triple=loongarch64 %t/tga.s -o %t/tga.64.o
|
||||
|
||||
## LA32 GD
|
||||
# RUN: ld.lld -shared %t/a.32.o %t/bc.32.o -o %t/gd.32.so
|
||||
# RUN: llvm-readobj -r %t/gd.32.so | FileCheck --check-prefix=GD32-REL %s
|
||||
# RUN: llvm-objdump -d --no-show-raw-insn %t/gd.32.so | FileCheck --check-prefix=GD32 %s
|
||||
|
||||
## LA32 GD -> LE
|
||||
# RUN: ld.lld %t/a.32.o %t/bc.32.o %t/tga.32.o -o %t/le.32
|
||||
# RUN: llvm-readelf -r %t/le.32 | FileCheck --check-prefix=NOREL %s
|
||||
# RUN: llvm-readelf -x .got %t/le.32 | FileCheck --check-prefix=LE32-GOT %s
|
||||
# RUN: ld.lld -pie %t/a.32.o %t/bc.32.o %t/tga.32.o -o %t/le-pie.32
|
||||
# RUN: llvm-readelf -r %t/le-pie.32 | FileCheck --check-prefix=NOREL %s
|
||||
# RUN: llvm-readelf -x .got %t/le-pie.32 | FileCheck --check-prefix=LE32-GOT %s
|
||||
|
||||
## LA32 GD -> IE
|
||||
# RUN: ld.lld %t/a.32.o %t/bc.32.so %t/tga.32.o -o %t/ie.32
|
||||
# RUN: llvm-readobj -r %t/ie.32 | FileCheck --check-prefix=IE32-REL %s
|
||||
# RUN: llvm-readelf -x .got %t/ie.32 | FileCheck --check-prefix=IE32-GOT %s
|
||||
|
||||
## LA64 GD
|
||||
# RUN: ld.lld -shared %t/a.64.o %t/bc.64.o -o %t/gd.64.so
|
||||
# RUN: llvm-readobj -r %t/gd.64.so | FileCheck --check-prefix=GD64-REL %s
|
||||
# RUN: llvm-objdump -d --no-show-raw-insn %t/gd.64.so | FileCheck --check-prefix=GD64 %s
|
||||
|
||||
## LA64 GD -> LE
|
||||
# RUN: ld.lld %t/a.64.o %t/bc.64.o %t/tga.64.o -o %t/le.64
|
||||
# RUN: llvm-readelf -r %t/le.64 | FileCheck --check-prefix=NOREL %s
|
||||
# RUN: llvm-readelf -x .got %t/le.64 | FileCheck --check-prefix=LE64-GOT %s
|
||||
# RUN: ld.lld -pie %t/a.64.o %t/bc.64.o %t/tga.64.o -o %t/le-pie.64
|
||||
# RUN: llvm-readelf -r %t/le-pie.64 | FileCheck --check-prefix=NOREL %s
|
||||
# RUN: llvm-readelf -x .got %t/le-pie.64 | FileCheck --check-prefix=LE64-GOT %s
|
||||
|
||||
## LA64 GD -> IE
|
||||
# RUN: ld.lld %t/a.64.o %t/bc.64.so %t/tga.64.o -o %t/ie.64
|
||||
# RUN: llvm-readobj -r %t/ie.64 | FileCheck --check-prefix=IE64-REL %s
|
||||
# RUN: llvm-readelf -x .got %t/ie.64 | FileCheck --check-prefix=IE64-GOT %s
|
||||
|
||||
# GD32-REL: .rela.dyn {
|
||||
# GD32-REL-NEXT: 0x20310 R_LARCH_TLS_DTPMOD32 a 0x0
|
||||
# GD32-REL-NEXT: 0x20314 R_LARCH_TLS_DTPREL32 a 0x0
|
||||
# GD32-REL-NEXT: 0x20318 R_LARCH_TLS_DTPMOD32 b 0x0
|
||||
# GD32-REL-NEXT: 0x2031C R_LARCH_TLS_DTPREL32 b 0x0
|
||||
# GD32-REL-NEXT: }
|
||||
|
||||
## &DTPMOD(a) - . = 0x20310 - 0x10250: 0x10 pages, page offset 0x310
|
||||
# GD32: 10250: pcalau12i $a0, 16
|
||||
# GD32-NEXT: addi.w $a0, $a0, 784
|
||||
# GD32-NEXT: bl 56
|
||||
|
||||
## &DTPMOD(b) - . = 0x20318 - 0x1025c: 0x10 pages, page offset 0x318
|
||||
# GD32: 1025c: pcalau12i $a0, 16
|
||||
# GD32-NEXT: addi.w $a0, $a0, 792
|
||||
# GD32-NEXT: bl 44
|
||||
|
||||
# GD64-REL: .rela.dyn {
|
||||
# GD64-REL-NEXT: 0x204C0 R_LARCH_TLS_DTPMOD64 a 0x0
|
||||
# GD64-REL-NEXT: 0x204C8 R_LARCH_TLS_DTPREL64 a 0x0
|
||||
# GD64-REL-NEXT: 0x204D0 R_LARCH_TLS_DTPMOD64 b 0x0
|
||||
# GD64-REL-NEXT: 0x204D8 R_LARCH_TLS_DTPREL64 b 0x0
|
||||
# GD64-REL-NEXT: }
|
||||
|
||||
## &DTPMOD(a) - . = 0x204c0 - 0x10398: 0x10 pages, page offset 0x4c0
|
||||
# GD64: 10398: pcalau12i $a0, 16
|
||||
# GD64-NEXT: addi.d $a0, $a0, 1216
|
||||
# GD64-NEXT: bl 48
|
||||
|
||||
## &DTPMOD(b) - . = 0x204d0 - 0x103a4: 0x10 pages, page offset 0x4d0
|
||||
# GD64: 103a4: pcalau12i $a0, 16
|
||||
# GD64-NEXT: addi.d $a0, $a0, 1232
|
||||
# GD64-NEXT: bl 36
|
||||
|
||||
# NOREL: no relocations
|
||||
|
||||
## .got contains pre-populated values: [a@dtpmod, a@dtprel, b@dtpmod, b@dtprel]
|
||||
## a@dtprel = st_value(a) = 0x8
|
||||
## b@dtprel = st_value(b) = 0xc
|
||||
# LE32-GOT: section '.got':
|
||||
# LE32-GOT-NEXT: 0x[[#%x,A:]] 01000000 08000000 01000000 0c000000
|
||||
# LE64-GOT: section '.got':
|
||||
# LE64-GOT-NEXT: 0x[[#%x,A:]] 01000000 00000000 08000000 00000000
|
||||
# LE64-GOT-NEXT: 0x[[#%x,A:]] 01000000 00000000 0c000000 00000000
|
||||
|
||||
## a is local - relaxed to LE - its DTPMOD/DTPREL slots are link-time constants.
|
||||
## b is external - DTPMOD/DTPREL dynamic relocations are required.
|
||||
# IE32-REL: .rela.dyn {
|
||||
# IE32-REL-NEXT: 0x30228 R_LARCH_TLS_DTPMOD32 b 0x0
|
||||
# IE32-REL-NEXT: 0x3022C R_LARCH_TLS_DTPREL32 b 0x0
|
||||
# IE32-REL-NEXT: }
|
||||
# IE32-GOT: section '.got':
|
||||
# IE32-GOT-NEXT: 0x00030220 01000000 08000000 00000000 00000000
|
||||
|
||||
# IE64-REL: .rela.dyn {
|
||||
# IE64-REL-NEXT: 0x30388 R_LARCH_TLS_DTPMOD64 b 0x0
|
||||
# IE64-REL-NEXT: 0x30390 R_LARCH_TLS_DTPREL64 b 0x0
|
||||
# IE64-REL-NEXT: }
|
||||
# IE64-GOT: section '.got':
|
||||
# IE64-GOT-NEXT: 0x00030378 01000000 00000000 08000000 00000000
|
||||
# IE64-GOT-NEXT: 0x00030388 00000000 00000000 00000000 00000000
|
||||
|
||||
#--- a.s
|
||||
la.tls.gd $a0, a
|
||||
bl %plt(__tls_get_addr)
|
||||
|
||||
la.tls.gd $a0, b
|
||||
bl %plt(__tls_get_addr)
|
||||
|
||||
.section .tbss,"awT",@nobits
|
||||
.globl a
|
||||
.zero 8
|
||||
a:
|
||||
.zero 4
|
||||
|
||||
#--- bc.s
|
||||
.section .tbss,"awT",@nobits
|
||||
.globl b, c
|
||||
b:
|
||||
.zero 4
|
||||
c:
|
||||
|
||||
#--- tga.s
|
||||
.globl __tls_get_addr
|
||||
__tls_get_addr:
|
||||
114
lld/test/ELF/loongarch-tls-ie.s
Normal file
114
lld/test/ELF/loongarch-tls-ie.s
Normal file
@@ -0,0 +1,114 @@
|
||||
# REQUIRES: loongarch
|
||||
# RUN: rm -rf %t && split-file %s %t
|
||||
|
||||
# RUN: llvm-mc --filetype=obj --triple=loongarch32 %t/32.s -o %t/32.o
|
||||
# RUN: llvm-mc --filetype=obj --triple=loongarch64 %t/64.s -o %t/64.o
|
||||
|
||||
## LA32 IE
|
||||
# RUN: ld.lld -shared %t/32.o -o %t/32.so
|
||||
# RUN: llvm-readobj -r -d %t/32.so | FileCheck --check-prefix=IE32-REL %s
|
||||
# RUN: llvm-objdump -d --no-show-raw-insn %t/32.so | FileCheck --check-prefixes=IE32 %s
|
||||
|
||||
## LA32 IE -> LE
|
||||
# RUN: ld.lld %t/32.o -o %t/32
|
||||
# RUN: llvm-readelf -r %t/32 | FileCheck --check-prefix=NOREL %s
|
||||
# RUN: llvm-readelf -x .got %t/32 | FileCheck --check-prefix=LE32-GOT %s
|
||||
# RUN: llvm-objdump -d --no-show-raw-insn %t/32 | FileCheck --check-prefixes=LE32 %s
|
||||
|
||||
## LA64 IE
|
||||
# RUN: ld.lld -shared %t/64.o -o %t/64.so
|
||||
# RUN: llvm-readobj -r -d %t/64.so | FileCheck --check-prefix=IE64-REL %s
|
||||
# RUN: llvm-objdump -d --no-show-raw-insn %t/64.so | FileCheck --check-prefixes=IE64 %s
|
||||
|
||||
## LA64 IE -> LE
|
||||
# RUN: ld.lld %t/64.o -o %t/64
|
||||
# RUN: llvm-readelf -r %t/64 | FileCheck --check-prefix=NOREL %s
|
||||
# RUN: llvm-readelf -x .got %t/64 | FileCheck --check-prefix=LE64-GOT %s
|
||||
# RUN: llvm-objdump -d --no-show-raw-insn %t/64 | FileCheck --check-prefixes=LE64 %s
|
||||
|
||||
# IE32-REL: FLAGS STATIC_TLS
|
||||
# IE32-REL: .rela.dyn {
|
||||
# IE32-REL-NEXT: 0x20218 R_LARCH_TLS_TPREL32 - 0xC
|
||||
# IE32-REL-NEXT: 0x20214 R_LARCH_TLS_TPREL32 a 0x0
|
||||
# IE32-REL-NEXT: }
|
||||
|
||||
# IE64-REL: FLAGS STATIC_TLS
|
||||
# IE64-REL: .rela.dyn {
|
||||
# IE64-REL-NEXT: 0x20370 R_LARCH_TLS_TPREL64 - 0xC
|
||||
# IE64-REL-NEXT: 0x20368 R_LARCH_TLS_TPREL64 a 0x0
|
||||
# IE64-REL-NEXT: }
|
||||
|
||||
## LA32:
|
||||
## &.got[0] - . = 0x20214 - 0x101a4: 0x10 pages, page offset 0x214
|
||||
## &.got[1] - . = 0x20218 - 0x101b0: 0x10 pages, page offset 0x218
|
||||
# IE32: 101a4: pcalau12i $a4, 16
|
||||
# IE32-NEXT: ld.w $a4, $a4, 532
|
||||
# IE32-NEXT: add.w $a4, $a4, $tp
|
||||
# IE32-NEXT: 101b0: pcalau12i $a5, 16
|
||||
# IE32-NEXT: ld.w $a5, $a5, 536
|
||||
# IE32-NEXT: add.w $a5, $a5, $tp
|
||||
|
||||
## LA64:
|
||||
## &.got[0] - . = 0x20368 - 0x102a0: 0x10 pages, page offset 0x368
|
||||
## &.got[1] - . = 0x20370 - 0x102ac: 0x10 pages, page offset 0x370
|
||||
# IE64: 102a0: pcalau12i $a4, 16
|
||||
# IE64-NEXT: ld.d $a4, $a4, 872
|
||||
# IE64-NEXT: add.d $a4, $a4, $tp
|
||||
# IE64-NEXT: 102ac: pcalau12i $a5, 16
|
||||
# IE64-NEXT: ld.d $a5, $a5, 880
|
||||
# IE64-NEXT: add.d $a5, $a5, $tp
|
||||
|
||||
# NOREL: no relocations
|
||||
|
||||
# a@tprel = st_value(a) = 0x8
|
||||
# b@tprel = st_value(a) = 0xc
|
||||
# LE32-GOT: section '.got':
|
||||
# LE32-GOT-NEXT: 0x0003012c 08000000 0c000000
|
||||
# LE64-GOT: section '.got':
|
||||
# LE64-GOT-NEXT: 0x000301e0 08000000 00000000 0c000000 00000000
|
||||
|
||||
## LA32:
|
||||
## &.got[0] - . = 0x3012c - 0x20114: 0x10 pages, page offset 0x12c
|
||||
## &.got[1] - . = 0x30130 - 0x20120: 0x10 pages, page offset 0x130
|
||||
# LE32: 20114: pcalau12i $a4, 16
|
||||
# LE32-NEXT: ld.w $a4, $a4, 300
|
||||
# LE32-NEXT: add.w $a4, $a4, $tp
|
||||
# LE32-NEXT: 20120: pcalau12i $a5, 16
|
||||
# LE32-NEXT: ld.w $a5, $a5, 304
|
||||
# LE32-NEXT: add.w $a5, $a5, $tp
|
||||
|
||||
## LA64:
|
||||
## &.got[0] - . = 0x301e0 - 0x201c8: 0x10 pages, page offset 0x1e0
|
||||
## &.got[1] - . = 0x301e8 - 0x201d4: 0x10 pages, page offset 0x1e8
|
||||
# LE64: 201c8: pcalau12i $a4, 16
|
||||
# LE64-NEXT: ld.d $a4, $a4, 480
|
||||
# LE64-NEXT: add.d $a4, $a4, $tp
|
||||
# LE64-NEXT: 201d4: pcalau12i $a5, 16
|
||||
# LE64-NEXT: ld.d $a5, $a5, 488
|
||||
# LE64-NEXT: add.d $a5, $a5, $tp
|
||||
|
||||
#--- 32.s
|
||||
la.tls.ie $a4, a
|
||||
add.w $a4, $a4, $tp
|
||||
la.tls.ie $a5, b
|
||||
add.w $a5, $a5, $tp
|
||||
|
||||
.section .tbss,"awT",@nobits
|
||||
.globl a
|
||||
.zero 8
|
||||
a:
|
||||
.zero 4
|
||||
b:
|
||||
|
||||
#--- 64.s
|
||||
la.tls.ie $a4, a
|
||||
add.d $a4, $a4, $tp
|
||||
la.tls.ie $a5, b
|
||||
add.d $a5, $a5, $tp
|
||||
|
||||
.section .tbss,"awT",@nobits
|
||||
.globl a
|
||||
.zero 8
|
||||
a:
|
||||
.zero 4
|
||||
b:
|
||||
89
lld/test/ELF/loongarch-tls-ld.s
Normal file
89
lld/test/ELF/loongarch-tls-ld.s
Normal file
@@ -0,0 +1,89 @@
|
||||
# REQUIRES: loongarch
|
||||
# RUN: rm -rf %t && split-file %s %t
|
||||
|
||||
## LoongArch psABI doesn't specify TLS relaxation. Though the code sequences are not
|
||||
## relaxed, dynamic relocations can be omitted for LD->LE relaxation.
|
||||
|
||||
# RUN: llvm-mc --filetype=obj --triple=loongarch32 --position-independent %t/a.s -o %t/a.32.o
|
||||
# RUN: llvm-mc --filetype=obj --triple=loongarch32 %t/tga.s -o %t/tga.32.o
|
||||
# RUN: llvm-mc --filetype=obj --triple=loongarch64 --position-independent %t/a.s -o %t/a.64.o
|
||||
# RUN: llvm-mc --filetype=obj --triple=loongarch64 %t/tga.s -o %t/tga.64.o
|
||||
|
||||
## LA32 LD
|
||||
# RUN: ld.lld -shared %t/a.32.o -o %t/ld.32.so
|
||||
# RUN: llvm-readobj -r %t/ld.32.so | FileCheck --check-prefix=LD32-REL %s
|
||||
# RUN: llvm-readelf -x .got %t/ld.32.so | FileCheck --check-prefix=LD32-GOT %s
|
||||
# RUN: llvm-objdump -d --no-show-raw-insn %t/ld.32.so | FileCheck --check-prefixes=LD32 %s
|
||||
|
||||
## LA32 LD -> LE
|
||||
# RUN: ld.lld %t/a.32.o %t/tga.32.o -o %t/le.32
|
||||
# RUN: llvm-readelf -r %t/le.32 | FileCheck --check-prefix=NOREL %s
|
||||
# RUN: llvm-readelf -x .got %t/le.32 | FileCheck --check-prefix=LE32-GOT %s
|
||||
# RUN: llvm-objdump -d --no-show-raw-insn %t/le.32 | FileCheck --check-prefixes=LE32 %s
|
||||
|
||||
## LA64 LD
|
||||
# RUN: ld.lld -shared %t/a.64.o -o %t/ld.64.so
|
||||
# RUN: llvm-readobj -r %t/ld.64.so | FileCheck --check-prefix=LD64-REL %s
|
||||
# RUN: llvm-readelf -x .got %t/ld.64.so | FileCheck --check-prefix=LD64-GOT %s
|
||||
# RUN: llvm-objdump -d --no-show-raw-insn %t/ld.64.so | FileCheck --check-prefixes=LD64 %s
|
||||
|
||||
## LA64 LD -> LE
|
||||
# RUN: ld.lld %t/a.64.o %t/tga.64.o -o %t/le.64
|
||||
# RUN: llvm-readelf -r %t/le.64 | FileCheck --check-prefix=NOREL %s
|
||||
# RUN: llvm-readelf -x .got %t/le.64 | FileCheck --check-prefix=LE64-GOT %s
|
||||
# RUN: llvm-objdump -d --no-show-raw-insn %t/le.64 | FileCheck --check-prefixes=LE64 %s
|
||||
|
||||
## a@dtprel = st_value(a) = 0 is a link-time constant.
|
||||
# LD32-REL: .rela.dyn {
|
||||
# LD32-REL-NEXT: 0x20280 R_LARCH_TLS_DTPMOD32 - 0x0
|
||||
# LD32-REL-NEXT: }
|
||||
# LD32-GOT: section '.got':
|
||||
# LD32-GOT-NEXT: 0x00020280 00000000 00000000
|
||||
|
||||
# LD64-REL: .rela.dyn {
|
||||
# LD64-REL-NEXT: 0x20400 R_LARCH_TLS_DTPMOD64 - 0x0
|
||||
# LD64-REL-NEXT: }
|
||||
# LD64-GOT: section '.got':
|
||||
# LD64-GOT-NEXT: 0x00020400 00000000 00000000 00000000 00000000
|
||||
|
||||
## LA32: &DTPMOD(a) - . = 0x20280 - 0x101cc: 0x10 pages, page offset 0x280
|
||||
# LD32: 101cc: pcalau12i $a0, 16
|
||||
# LD32-NEXT: addi.w $a0, $a0, 640
|
||||
# LD32-NEXT: bl 44
|
||||
|
||||
## LA64: &DTPMOD(a) - . = 0x20400 - 0x102e0: 0x10 pages, page offset 0x400
|
||||
# LD64: 102e0: pcalau12i $a0, 16
|
||||
# LD64-NEXT: addi.d $a0, $a0, 1024
|
||||
# LD64-NEXT: bl 40
|
||||
|
||||
# NOREL: no relocations
|
||||
|
||||
## a is local - its DTPMOD/DTPREL slots are link-time constants.
|
||||
## a@dtpmod = 1 (main module)
|
||||
# LE32-GOT: section '.got':
|
||||
# LE32-GOT-NEXT: 0x00030120 01000000 00000000
|
||||
|
||||
# LE64-GOT: section '.got':
|
||||
# LE64-GOT-NEXT: 0x000301d8 01000000 00000000 00000000 00000000
|
||||
|
||||
## LA32: DTPMOD(.LANCHOR0) - . = 0x30120 - 0x20114: 0x10 pages, page offset 0x120
|
||||
# LE32: 20114: pcalau12i $a0, 16
|
||||
# LE32-NEXT: addi.w $a0, $a0, 288
|
||||
# LE32-NEXT: bl 4
|
||||
|
||||
## LA64: DTPMOD(.LANCHOR0) - . = 0x301d8 - 0x201c8: 0x10 pages, page offset 0x1d8
|
||||
# LE64: 201c8: pcalau12i $a0, 16
|
||||
# LE64-NEXT: addi.d $a0, $a0, 472
|
||||
# LE64-NEXT: bl 4
|
||||
|
||||
#--- a.s
|
||||
la.tls.ld $a0, .LANCHOR0
|
||||
bl %plt(__tls_get_addr)
|
||||
|
||||
.section .tbss,"awT",@nobits
|
||||
.set .LANCHOR0, . + 0
|
||||
.zero 8
|
||||
|
||||
#--- tga.s
|
||||
.globl __tls_get_addr
|
||||
__tls_get_addr:
|
||||
42
lld/test/ELF/loongarch-tls-le.s
Normal file
42
lld/test/ELF/loongarch-tls-le.s
Normal file
@@ -0,0 +1,42 @@
|
||||
# REQUIRES: loongarch
|
||||
|
||||
# RUN: llvm-mc --filetype=obj --triple=loongarch32 %s -o %t.32.o
|
||||
# RUN: llvm-mc --filetype=obj --triple=loongarch64 %s -o %t.64.o
|
||||
|
||||
# RUN: ld.lld %t.32.o -o %t.32
|
||||
# RUN: llvm-nm -p %t.32 | FileCheck --check-prefixes=NM %s
|
||||
# RUN: llvm-objdump -d --no-show-raw-insn %t.32 | FileCheck --check-prefixes=LE %s
|
||||
|
||||
# RUN: ld.lld %t.64.o -o %t.64
|
||||
# RUN: llvm-objdump -d --no-show-raw-insn %t.64 | FileCheck --check-prefixes=LE %s
|
||||
|
||||
# RUN: not ld.lld -shared %t.32.o -o /dev/null 2>&1 | FileCheck %s --check-prefix=ERR --implicit-check-not=error:
|
||||
|
||||
# ERR: error: relocation R_LARCH_TLS_LE_HI20 against .LANCHOR0 cannot be used with -shared
|
||||
# ERR: error: relocation R_LARCH_TLS_LE_LO12 against .LANCHOR0 cannot be used with -shared
|
||||
# ERR: error: relocation R_LARCH_TLS_LE_HI20 against a cannot be used with -shared
|
||||
# ERR: error: relocation R_LARCH_TLS_LE_LO12 against a cannot be used with -shared
|
||||
|
||||
# NM: {{0*}}00000008 b .LANCHOR0
|
||||
# NM: {{0*}}00000800 B a
|
||||
|
||||
## .LANCHOR0@tprel = 8
|
||||
## a@tprel = 0x800
|
||||
# LE: lu12i.w $a0, 0
|
||||
# LE-NEXT: ori $a0, $a0, 8
|
||||
# LE-NEXT: lu12i.w $a1, 0
|
||||
# LE-NEXT: ori $a1, $a1, 2048
|
||||
# LE-EMPTY:
|
||||
|
||||
.text
|
||||
_start:
|
||||
la.tls.le $a0, .LANCHOR0
|
||||
la.tls.le $a1, a
|
||||
|
||||
.section .tbss,"awT",@nobits
|
||||
.space 8
|
||||
.LANCHOR0:
|
||||
.space 0x800-8
|
||||
.globl a
|
||||
a:
|
||||
.zero 4
|
||||
@@ -77,6 +77,7 @@ llvm_config.feature_config(
|
||||
"ARM": "arm",
|
||||
"AVR": "avr",
|
||||
"Hexagon": "hexagon",
|
||||
"LoongArch": "loongarch",
|
||||
"Mips": "mips",
|
||||
"MSP430": "msp430",
|
||||
"PowerPC": "ppc",
|
||||
|
||||
Reference in New Issue
Block a user