diff --git a/0001-Support-LoongArch.patch b/0001-Support-LoongArch.patch deleted file mode 100644 index 86c3f43977882ed89fec4ff7af8f9a9bcd084b27..0000000000000000000000000000000000000000 --- a/0001-Support-LoongArch.patch +++ /dev/null @@ -1,1559 +0,0 @@ -diff --git a/lld/ELF/Arch/LoongArch.cpp b/lld/ELF/Arch/LoongArch.cpp -new file mode 100644 -index 000000000..185a8fa67 ---- /dev/null -+++ b/lld/ELF/Arch/LoongArch.cpp -@@ -0,0 +1,454 @@ -+//===- LoongArch.cpp -+//--------------------------------------------------------===// -+// -+// The LLVM Linker -+// -+// This file is distributed under the University of Illinois Open Source -+// License. See LICENSE.TXT for details. -+// -+//===----------------------------------------------------------------------===// -+ -+#include "InputFiles.h" -+#include "OutputSections.h" -+#include "Symbols.h" -+#include "SyntheticSections.h" -+#include "Target.h" -+#include "Thunks.h" -+#include "lld/Common/ErrorHandler.h" -+#include "llvm/Object/ELF.h" -+#include "llvm/Support/Endian.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 { -+#define REL_STACK_MAX_SIZE 16 -+struct RelStack { -+ uint64_t stack[REL_STACK_MAX_SIZE] = {}; -+ int top = -1; -+ void push_back(uint64_t e) { -+ if (top < REL_STACK_MAX_SIZE) { -+ top++; -+ stack[top] = e; -+ } else { -+ report_fatal_error("stack is overflow, top = " + Twine(top)); -+ } -+ } -+ -+ uint64_t pop_back_val() { -+ uint64_t e; -+ if (top >= 0) { -+ e = stack[top]; -+ top--; -+ } else { -+ report_fatal_error("stack is empty, top = " + Twine(top)); -+ } -+ return e; -+ } -+}; -+// The lld multi-thread is used to speed up link procedure. The lld will -+// create a thread for every input section to handle relocation. So we -+// must use thread-safe stack for every work thread. -+__thread RelStack relStack; -+ -+template class LoongArch final : public TargetInfo { -+public: -+ LoongArch(); -+ uint32_t calcEFlags() const override; -+ RelExpr getRelExpr(RelType type, const Symbol &s, -+ const uint8_t *loc) const override; -+ RelType getDynRel(RelType type) const override; -+ void writeGotHeader(uint8_t *buf) const override; -+ void writeGotPlt(uint8_t *buf, const Symbol &s) const override; -+ void writePltHeader(uint8_t *buf) const override; -+ void writePlt(uint8_t *buf, const Symbol &sym, -+ uint64_t pltEntryAddr) const override; -+ void relocate(uint8_t *loc, const Relocation &rel, -+ uint64_t val) const override; -+}; -+} // namespace -+ -+template LoongArch::LoongArch() { -+ // .got[0] = _DYNAMIC -+ gotHeaderEntriesNum = 1; -+ // .got.plt[0] = _dl_runtime_resolve, .got.plt[1] = link_map -+ gotPltHeaderEntriesNum = 2; -+ defaultMaxPageSize = 65536; -+ gotEntrySize = sizeof(typename ELFT::uint); -+ pltEntrySize = 16; -+ pltHeaderSize = 32; -+ copyRel = R_LARCH_COPY; -+ pltRel = R_LARCH_JUMP_SLOT; -+ relativeRel = R_LARCH_RELATIVE; -+ // _GLOBAL_OFFSET_TABLE_ is relative to .got -+ gotBaseSymInGotPlt = false; -+ -+ if (ELFT::Is64Bits) { -+ symbolicRel = R_LARCH_64; -+ tlsGotRel = R_LARCH_TLS_TPREL64; -+ tlsModuleIndexRel = R_LARCH_TLS_DTPMOD64; -+ tlsOffsetRel = R_LARCH_TLS_DTPREL64; -+ defaultImageBase = 0x120000000; -+ } else { -+ symbolicRel = R_LARCH_32; -+ tlsGotRel = R_LARCH_TLS_TPREL32; -+ tlsModuleIndexRel = R_LARCH_TLS_DTPMOD32; -+ tlsOffsetRel = R_LARCH_TLS_DTPREL32; -+ } -+ gotRel = symbolicRel; -+} -+ -+template static TargetInfo *getTargetInfo() { -+ static LoongArch target; -+ return ⌖ -+} -+ -+TargetInfo *elf::getLoongArch32TargetInfo() { return getTargetInfo(); } -+TargetInfo *elf::getLoongArch64TargetInfo() { return getTargetInfo(); } -+ -+template -+RelExpr LoongArch::getRelExpr(RelType type, const Symbol &s, -+ const uint8_t *loc) const { -+ switch (type) { -+ case R_LARCH_64: -+ case R_LARCH_32: -+ return R_ABS; -+ case R_LARCH_SOP_PUSH_PCREL: -+ return R_PC; -+ case R_LARCH_SOP_PUSH_TLS_GOT: -+ return R_GOT_OFF; -+ case R_LARCH_SOP_PUSH_TLS_GD: -+ return R_TLSGD_GOT; -+ case R_LARCH_SOP_PUSH_TLS_TPREL: -+ return R_TPREL; -+ case R_LARCH_SOP_PUSH_GPREL: -+ return R_LARCH_GOTREL; -+ case R_LARCH_SOP_PUSH_PLT_PCREL: -+ return R_PLT_PC; -+ case R_LARCH_ADD8: -+ case R_LARCH_ADD16: -+ case R_LARCH_ADD32: -+ case R_LARCH_ADD64: -+ return R_LARCH_PC; -+ default: -+ return R_LARCH_ABS; -+ } -+} -+ -+template static uint32_t getEFlags(InputFile *F) { -+ return cast>(F)->getObj().getHeader().e_flags; -+} -+ -+static Twine getAbiName(uint32_t eflags) { -+ switch (eflags) { -+ case EF_LARCH_ABI_LP64: -+ return Twine("LP64"); -+ case EF_LARCH_ABI_LP32: -+ return Twine("LP32"); -+ case EF_LARCH_ABI_LPX32: -+ return Twine("LPX32"); -+ default: -+ return Twine("Unknown ABI"); -+ } -+} -+ -+template uint32_t LoongArch::calcEFlags() const { -+ assert(!objectFiles.empty()); -+ -+ uint32_t target = getEFlags(objectFiles.front()); -+ -+ for (InputFile *f : objectFiles) { -+ uint32_t eflags = getEFlags(f); -+ if (eflags != EF_LARCH_ABI_LP64 && eflags != EF_LARCH_ABI_LP32 && -+ eflags != EF_LARCH_ABI_LPX32) -+ error(toString(f) + ": unrecognized e_flags: " + Twine(eflags)); -+ if (eflags != target) -+ error(toString(f) + ": ABI '" + getAbiName(eflags) + -+ "' is incompatible with target ABI '" + getAbiName(target) + "'"); -+ } -+ -+ return target; -+} -+ -+template RelType LoongArch::getDynRel(RelType type) const { -+ if (type == R_LARCH_32 || type == R_LARCH_64) -+ return type; -+ return R_LARCH_NONE; -+} -+ -+template void LoongArch::writeGotHeader(uint8_t *buf) const { -+ if (ELFT::Is64Bits) -+ write64le(buf, mainPart->dynamic->getVA()); -+ else -+ write32le(buf, mainPart->dynamic->getVA()); -+} -+ -+template -+void LoongArch::writeGotPlt(uint8_t *buf, const Symbol &s) const { -+ if (ELFT::Is64Bits) -+ write64le(buf, in.plt->getVA()); -+ else -+ write32le(buf, in.plt->getVA()); -+} -+ -+/* Add 0x800 to maintain the sign bit */ -+static uint32_t hi20(uint32_t val) { return (val + 0x800) >> 12; } -+static uint32_t lo12(uint32_t val) { return val & 0xfff; } -+ -+template void LoongArch::writePltHeader(uint8_t *buf) const { -+ uint32_t offset = in.gotPlt->getVA() - in.plt->getVA(); -+ -+ /* pcaddu12i $t2, %hi(%pcrel(.got.plt)) -+ sub.[wd] $t1, $t1, $t3 -+ ld.[wd] $t3, $t2, %lo(%pcrel(.got.plt)) # _dl_runtime_resolve -+ addi.[wd] $t1, $t1, -(PLT_HEADER_SIZE + 12) + 4 -+ addi.[wd] $t0, $t2, %lo(%pcrel(.got.plt)) -+ srli.[wd] $t1, $t1, log2(16 / GOT_ENTRY_SIZE) -+ ld.[wd] $t0, $t0, GOT_ENTRY_SIZE -+ jirl $r0, $t3, 0 */ -+ -+ if (ELFT::Is64Bits) { -+ write32le(buf + 0, 0x1c00000e | hi20(offset) << 5); -+ write32le(buf + 4, 0x0011bdad); -+ write32le(buf + 8, 0x28c001cf | lo12(offset) << 10); -+ write32le(buf + 12, 0x02c001ad | ((-(pltHeaderSize + 12) + 4) & 0xfff) -+ << 10); -+ write32le(buf + 16, 0x02c001cc | lo12(offset) << 10); -+ write32le(buf + 20, 0x004501ad | 0x400); -+ write32le(buf + 24, 0x28c0018c | gotEntrySize << 10); -+ write32le(buf + 28, 0x4c0001e0); -+ } else { -+ write32le(buf + 0, 0x1c00000e | hi20(offset) << 5); -+ write32le(buf + 4, 0x00113dad); -+ write32le(buf + 8, 0x288001cf | lo12(offset) << 10); -+ write32le(buf + 12, 0x028001ad | ((-(pltHeaderSize + 12)) & 0xfff) << 10); -+ write32le(buf + 16, 0x028001cc | lo12(offset) << 10); -+ write32le(buf + 20, 0x004481ad | 0x800); -+ write32le(buf + 24, 0x2880018c | gotEntrySize << 10); -+ write32le(buf + 28, 0x4c0001e0); -+ } -+ -+ return; -+} -+ -+template -+void LoongArch::writePlt(uint8_t *buf, const Symbol &sym, -+ uint64_t pltEntryAddr) const { -+ uint32_t offset = sym.getGotPltVA() - pltEntryAddr; -+ -+ /* pcaddu12i $t3, %hi(%pcrel(.got.plt entry)) -+ ld.[wd] $t3, $t3, %lo(%pcrel(.got.plt entry)) -+ pcaddu12i $t1, 0 -+ jirl $r0, $t3, 0 */ -+ -+ write32le(buf, 0x1c00000f | hi20(offset) << 5); -+ if (ELFT::Is64Bits) -+ write32le(buf + 4, 0x28c001ef | lo12(offset) << 10); -+ else -+ write32le(buf + 4, 0x288001ef | lo12(offset) << 10); -+ write32le(buf + 8, 0x1c00000d); -+ write32le(buf + 12, 0x4c0001e0); -+ -+ return; -+} -+ -+// Extract bits v[hi:lo], where range is inclusive, and hi must be < 63. -+static uint32_t extractBits(uint64_t v, uint32_t hi, uint32_t lo) { -+ return (v & ((1ULL << (hi + 1)) - 1)) >> lo; -+} -+ -+// Clean bits v[hi:lo] to 0, where range is inclusive, and hi must be -+// < 32. -+static uint32_t cleanInstrImm(uint32_t v, uint32_t hi, uint32_t lo) { -+ return v & ~((((1ULL << (hi + 1)) - 1) >> lo) << lo); -+} -+ -+template -+void LoongArch::relocate(uint8_t *loc, const Relocation &rel, -+ uint64_t val) const { -+ switch (rel.type) { -+ case R_LARCH_32: -+ write32le(loc, val); -+ break; -+ case R_LARCH_TLS_DTPREL32: -+ write32le(loc, val); -+ break; -+ case R_LARCH_64: -+ write64le(loc, val); -+ return; -+ case R_LARCH_TLS_DTPREL64: -+ write64le(loc, val); -+ break; -+ case R_LARCH_TLS_DTPMOD32: -+ write32le(loc, val); -+ break; -+ case R_LARCH_TLS_DTPMOD64: -+ write64le(loc, val); -+ break; -+ case R_LARCH_MARK_LA: -+ case R_LARCH_MARK_PCREL: -+ case R_LARCH_NONE: -+ break; -+ case R_LARCH_SOP_PUSH_PCREL: -+ case R_LARCH_SOP_PUSH_ABSOLUTE: -+ case R_LARCH_SOP_PUSH_GPREL: -+ case R_LARCH_SOP_PUSH_TLS_TPREL: -+ case R_LARCH_SOP_PUSH_TLS_GOT: -+ case R_LARCH_SOP_PUSH_TLS_GD: -+ case R_LARCH_SOP_PUSH_PLT_PCREL: -+ relStack.push_back(val); -+ break; -+ case R_LARCH_SOP_PUSH_DUP: { -+ uint64_t opr1 = relStack.pop_back_val(); -+ relStack.push_back(opr1); -+ relStack.push_back(opr1); -+ } break; -+ case R_LARCH_SOP_ASSERT: { -+ uint64_t opr1 = relStack.pop_back_val(); -+ assert(opr1 == 0 && "R_LARCH_SOP_ASSERT relocation type assert fail."); -+ } break; -+ case R_LARCH_SOP_NOT: { -+ uint64_t opr1 = relStack.pop_back_val(); -+ relStack.push_back(!opr1); -+ } break; -+ case R_LARCH_SOP_SUB: { -+ uint64_t opr2 = relStack.pop_back_val(); -+ uint64_t opr1 = relStack.pop_back_val(); -+ relStack.push_back(opr1 - opr2); -+ } break; -+ case R_LARCH_SOP_SL: { -+ uint64_t opr2 = relStack.pop_back_val(); -+ uint64_t opr1 = relStack.pop_back_val(); -+ relStack.push_back(opr1 << opr2); -+ } break; -+ case R_LARCH_SOP_SR: { -+ uint64_t opr2 = relStack.pop_back_val(); -+ uint64_t opr1 = relStack.pop_back_val(); -+ relStack.push_back((int64_t)opr1 >> opr2); -+ } break; -+ case R_LARCH_SOP_ADD: { -+ uint64_t opr2 = relStack.pop_back_val(); -+ uint64_t opr1 = relStack.pop_back_val(); -+ relStack.push_back(opr1 + opr2); -+ } break; -+ case R_LARCH_SOP_AND: { -+ uint64_t opr2 = relStack.pop_back_val(); -+ uint64_t opr1 = relStack.pop_back_val(); -+ relStack.push_back(opr1 & opr2); -+ } break; -+ case R_LARCH_SOP_IF_ELSE: { -+ uint64_t opr3 = relStack.pop_back_val(); -+ uint64_t opr2 = relStack.pop_back_val(); -+ uint64_t opr1 = relStack.pop_back_val(); -+ relStack.push_back(opr1 ? opr2 : opr3); -+ } break; -+ case R_LARCH_SOP_POP_32_S_10_5: { -+ uint64_t opr1 = relStack.pop_back_val(); -+ checkInt(loc, static_cast(opr1), 5, rel); -+ uint32_t imm10_5 = extractBits(opr1, 4, 0) << 10; -+ uint32_t ins = cleanInstrImm(read32le(loc), 14, 10); -+ write32le(loc, ins | imm10_5); -+ } break; -+ case R_LARCH_SOP_POP_32_S_10_12: { -+ uint64_t opr1 = relStack.pop_back_val(); -+ checkInt(loc, static_cast(opr1), 12, rel); -+ uint32_t imm10_12 = extractBits(opr1, 11, 0) << 10; -+ uint32_t ins = cleanInstrImm(read32le(loc), 21, 10); -+ write32le(loc, ins | imm10_12); -+ } break; -+ case R_LARCH_SOP_POP_32_S_10_16: { -+ uint64_t opr1 = relStack.pop_back_val(); -+ checkInt(loc, static_cast(opr1), 16, rel); -+ uint32_t imm10_16 = extractBits(opr1, 15, 0) << 10; -+ uint32_t ins = cleanInstrImm(read32le(loc), 25, 10); -+ write32le(loc, ins | imm10_16); -+ } break; -+ case R_LARCH_SOP_POP_32_S_10_16_S2: { -+ int64_t opr1 = (int64_t)relStack.pop_back_val(); -+ checkInt(loc, static_cast(opr1), 18, rel); -+ checkAlignment(loc, opr1, 4, rel); -+ uint32_t imm10_16 = extractBits(opr1, 17, 2) << 10; -+ uint32_t ins = cleanInstrImm(read32le(loc), 25, 10); -+ write32le(loc, ins | imm10_16); -+ } break; -+ case R_LARCH_SOP_POP_32_U_10_12: { -+ uint64_t opr1 = relStack.pop_back_val(); -+ checkUInt(loc, opr1, 12, rel); -+ uint32_t imm10_12 = extractBits(opr1, 11, 0) << 10; -+ uint32_t ins = cleanInstrImm(read32le(loc), 21, 10); -+ write32le(loc, ins | imm10_12); -+ } break; -+ case R_LARCH_SOP_POP_32_S_5_20: { -+ uint64_t opr1 = relStack.pop_back_val(); -+ checkInt(loc, static_cast(opr1), 20, rel); -+ uint32_t imm5_20 = extractBits(opr1, 19, 0) << 5; -+ uint32_t ins = cleanInstrImm(read32le(loc), 24, 5); -+ write32le(loc, ins | imm5_20); -+ } break; -+ case R_LARCH_SOP_POP_32_S_0_5_10_16_S2: { -+ uint64_t opr1 = relStack.pop_back_val(); -+ checkInt(loc, static_cast(opr1), 23, rel); -+ checkAlignment(loc, opr1, 4, rel); -+ uint32_t imm0_5 = extractBits(opr1, 22, 18); -+ uint32_t imm10_16 = extractBits(opr1, 17, 2) << 10; -+ uint32_t ins = cleanInstrImm(read32le(loc), 4, 0); -+ ins = cleanInstrImm(ins, 25, 10); -+ write32le(loc, ins | imm0_5 | imm10_16); -+ } break; -+ case R_LARCH_SOP_POP_32_S_0_10_10_16_S2: { -+ uint64_t opr1 = relStack.pop_back_val(); -+ checkInt(loc, static_cast(opr1), 28, rel); -+ checkAlignment(loc, opr1, 4, rel); -+ uint32_t imm0_10 = extractBits(opr1, 27, 18); -+ uint32_t imm10_16 = extractBits(opr1, 17, 2) << 10; -+ uint32_t ins = cleanInstrImm(read32le(loc), 25, 0); -+ write32le(loc, ins | imm0_10 | imm10_16); -+ } break; -+ case R_LARCH_SOP_POP_32_U: { -+ uint64_t opr1 = relStack.pop_back_val(); -+ checkUInt(loc, opr1, 32, rel); -+ write32le(loc, (uint32_t)opr1); -+ } break; -+ case R_LARCH_ADD8: -+ *loc += val; -+ break; -+ case R_LARCH_ADD16: -+ write16le(loc, read16le(loc) + val); -+ break; -+ case R_LARCH_ADD24: -+ write32le(loc, (read32le(loc) | *(loc + 2) << 16) + val); -+ break; -+ case R_LARCH_ADD32: -+ write32le(loc, read32le(loc) + val); -+ break; -+ case R_LARCH_ADD64: -+ write64le(loc, read64le(loc) + val); -+ break; -+ case R_LARCH_SUB8: -+ *loc -= val; -+ break; -+ case R_LARCH_SUB16: -+ write16le(loc, read16le(loc) - val); -+ break; -+ case R_LARCH_SUB24: -+ write16le(loc, (read16le(loc) | *(loc + 2) << 16) - val); -+ break; -+ case R_LARCH_SUB32: -+ write32le(loc, read32le(loc) - val); -+ break; -+ case R_LARCH_SUB64: -+ write64le(loc, read64le(loc) - val); -+ break; -+ // GNU C++ vtable hierarchy -+ case R_LARCH_GNU_VTINHERIT: -+ // GNU C++ vtable member usage -+ case R_LARCH_GNU_VTENTRY: -+ break; -+ default: -+ error(getErrorLocation(loc) + "unrecognized reloc " + Twine(rel.type)); -+ } -+} -diff --git a/lld/ELF/CMakeLists.txt b/lld/ELF/CMakeLists.txt -index f85d0fb9f..5d1021c3a 100644 ---- a/lld/ELF/CMakeLists.txt -+++ b/lld/ELF/CMakeLists.txt -@@ -9,6 +9,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 -diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp -index 594c20016..441a659c7 100644 ---- a/lld/ELF/Driver.cpp -+++ b/lld/ELF/Driver.cpp -@@ -163,6 +163,7 @@ static std::tuple parseEmulation(StringRef emul) { - .Case("elf_iamcu", {ELF32LEKind, EM_IAMCU}) - .Case("elf64_sparc", {ELF64BEKind, EM_SPARCV9}) - .Case("msp430elf", {ELF32LEKind, EM_MSP430}) -+ .Case("elf64loongarch", {ELF64LEKind, EM_LOONGARCH}) - .Default({ELFNoneKind, EM_NONE}); - - if (ret.first == ELFNoneKind) -@@ -979,7 +980,7 @@ 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; -+ m == EM_PPC64 || m == EM_RISCV || m == EM_X86_64 || m == EM_LOONGARCH; - } - - static void parseClangOption(StringRef opt, const Twine &msg) { -diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp -index 7d952e903..6fa5f02e9 100644 ---- a/lld/ELF/InputSection.cpp -+++ b/lld/ELF/InputSection.cpp -@@ -661,6 +661,7 @@ static int64_t getTlsTpOffset(const Symbol &s) { - // data and 0xf000 of the program's TLS segment. - return s.getVA(0) + (tls->p_vaddr & (tls->p_align - 1)) - 0x7000; - case EM_RISCV: -+ case EM_LOONGARCH: - return s.getVA(0) + (tls->p_vaddr & (tls->p_align - 1)); - - // Variant 2. -@@ -680,6 +681,8 @@ uint64_t InputSectionBase::getRelocTargetVA(const InputFile *file, RelType type, - const Symbol &sym, RelExpr expr) { - switch (expr) { - case R_ABS: -+ case R_LARCH_ABS: -+ case R_LARCH_PC: - case R_DTPREL: - case R_RELAX_TLS_LD_TO_LE_ABS: - case R_RELAX_GOT_PC_NOPIC: -@@ -699,6 +702,8 @@ uint64_t InputSectionBase::getRelocTargetVA(const InputFile *file, RelType type, - case R_GOTREL: - case R_PPC64_RELAX_TOC: - return sym.getVA(a) - in.got->getVA(); -+ case R_LARCH_GOTREL: -+ return sym.getGotVA() - in.got->getVA(); - case R_GOTPLTREL: - return sym.getVA(a) - in.gotPlt->getVA(); - case R_GOTPLT: -@@ -914,7 +919,7 @@ void InputSection::relocateNonAlloc(uint8_t *buf, ArrayRef rels) { - // R_ABS/R_DTPREL and some other relocations can be used from non-SHF_ALLOC - // sections. - if (expr != R_ABS && expr != R_DTPREL && expr != R_GOTPLTREL && -- expr != R_RISCV_ADD) { -+ expr != R_RISCV_ADD && expr != R_LARCH_ABS && expr != R_LARCH_PC) { - std::string msg = getLocation(offset) + - ": has non-ABS relocation " + toString(type) + - " against symbol '" + toString(sym) + "'"; -diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp -index 71249188a..bfa7893bb 100644 ---- a/lld/ELF/Relocations.cpp -+++ b/lld/ELF/Relocations.cpp -@@ -124,36 +124,27 @@ void elf::reportRangeError(uint8_t *loc, int64_t v, int n, const Symbol &sym, - Twine(llvm::maxIntN(n)) + "]" + hint); - } - --namespace { --// Build a bitmask with one bit set for each RelExpr. --// --// Constexpr function arguments can't be used in static asserts, so we --// use template arguments to build the mask. --// But function template partial specializations don't exist (needed --// for base case of the recursion), so we need a dummy struct. --template struct RelExprMaskBuilder { -- static inline uint64_t build() { return 0; } --}; -+// Build a bitmask with one bit set for each 64 subset of RelExpr. -+static constexpr uint64_t buildMask() { return 0; } - --// Specialization for recursive case. --template --struct RelExprMaskBuilder { -- static inline uint64_t build() { -- static_assert(0 <= Head && Head < 64, -- "RelExpr is too large for 64-bit mask!"); -- return (uint64_t(1) << Head) | RelExprMaskBuilder::build(); -- } --}; --} // namespace -+template -+static constexpr uint64_t buildMask(int head, Tails... tails) { -+ return (0 <= head && head < 64 ? uint64_t(1) << head : 0) | -+ buildMask(tails...); -+} - - // Return true if `Expr` is one of `Exprs`. --// There are fewer than 64 RelExpr's, so we can represent any set of --// RelExpr's as a constant bit mask and test for membership with a --// couple cheap bitwise operations. --template bool oneof(RelExpr expr) { -- assert(0 <= expr && (int)expr < 64 && -- "RelExpr is too large for 64-bit mask!"); -- return (uint64_t(1) << expr) & RelExprMaskBuilder::build(); -+// There are more than 64 but less than 128 RelExprs, so we divide the set of -+// exprs into [0, 64) and [64, 128) and represent each range as a constant -+// 64-bit mask. Then we decide which mask to test depending on the value of -+// expr and use a simple shift and bitwise-and to test for membership. -+template static bool oneof(RelExpr expr) { -+ assert(0 <= expr && (int)expr < 128 && -+ "RelExpr is too large for 128-bit mask!"); -+ -+ if (expr >= 64) -+ return (uint64_t(1) << (expr - 64)) & buildMask((Exprs - 64)...); -+ return (uint64_t(1) << expr) & buildMask(Exprs...); - } - - // This function is similar to the `handleTlsRelocation`. MIPS does not -@@ -208,13 +199,13 @@ handleTlsRelocation(RelType type, Symbol &sym, InputSectionBase &c, - 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 -- // relaxation as well. -- bool toExecRelax = !config->shared && config->emachine != EM_ARM && -- config->emachine != EM_HEXAGON && -- config->emachine != EM_RISCV && -- !c.file->ppc64DisableTLSRelax; -+ // 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; - - // If we are producing an executable and the symbol is non-preemptable, it - // must be defined and the code sequence can be relaxed to use Local-Exec. -@@ -229,8 +220,7 @@ handleTlsRelocation(RelType type, Symbol &sym, InputSectionBase &c, - // 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( -- expr)) { -+ if (oneof(expr)) { - // Local-Dynamic relocs can be relaxed to Local-Exec. - if (toExecRelax) { - c.relocations.push_back( -@@ -383,7 +373,7 @@ static bool needsPlt(RelExpr expr) { - static bool needsGot(RelExpr expr) { - return oneof(expr); -+ R_AARCH64_GOT_PAGE, R_LARCH_GOTREL>(expr); - } - - // True if this expression is of the form Sym - X, where X is a position in the -@@ -413,8 +403,7 @@ static bool isStaticLinkTimeConstant(RelExpr e, RelType type, const Symbol &sym, - R_PLT_PC, R_TLSGD_GOT, R_TLSGD_GOTPLT, R_TLSGD_PC, R_PPC32_PLTREL, - R_PPC64_CALL_PLT, R_PPC64_RELAX_TOC, R_RISCV_ADD, R_TLSDESC_CALL, - R_TLSDESC_PC, R_AARCH64_TLSDESC_PAGE, R_TLSLD_HINT, R_TLSIE_HINT, -- R_AARCH64_GOT_PAGE>( -- e)) -+ R_AARCH64_GOT_PAGE, R_LARCH_GOTREL, R_LARCH_ABS>(e)) - return true; - - // These never do, except if the entire file is position dependent or if -@@ -455,7 +444,7 @@ static bool isStaticLinkTimeConstant(RelExpr e, RelType type, const Symbol &sym, - // We set the final symbols values for linker script defined symbols later. - // They always can be computed as a link time constant. - if (sym.scriptDefined) -- return true; -+ return true; - - error("relocation " + toString(type) + " cannot refer to absolute symbol: " + - toString(sym) + getLocation(s, sym, relOff)); -@@ -691,8 +680,7 @@ static int64_t computeAddend(const RelTy &rel, const RelTy *end, - } - - // Custom error message if Sym is defined in a discarded section. --template --static std::string maybeReportDiscarded(Undefined &sym) { -+template static std::string maybeReportDiscarded(Undefined &sym) { - auto *file = dyn_cast_or_null>(sym.file); - if (!file || !sym.discardedSecIdx || - file->getSections()[sym.discardedSecIdx] != &InputSection::discarded) -@@ -1004,7 +992,8 @@ static bool maybeReportUndefined(Symbol &sym, InputSectionBase &sec, - // packs all relocations into the single relocation record. Here we emulate - // this for the N32 ABI. Iterate over relocation with the same offset and put - // theirs types into the single bit-set. --template static RelType getMipsN32RelType(RelTy *&rel, RelTy *end) { -+template -+static RelType getMipsN32RelType(RelTy *&rel, RelTy *end) { - RelType type = 0; - uint64_t offset = rel->r_offset; - -@@ -1285,8 +1274,15 @@ static void processRelocAux(InputSectionBase &sec, RelExpr expr, RelType type, - return; - } - } -+ if (config->emachine == EM_LOONGARCH && -+ (type == R_LARCH_32 || type == R_LARCH_64)) -+ return; - - if (config->isPic) { -+ if (config->emachine == EM_LOONGARCH && oneof(expr)) { -+ sec.relocations.push_back({expr, type, offset, addend, &sym}); -+ return; -+ } - if (!canWrite && !isRelExpr(expr)) - errorOrWarn( - "can't create dynamic relocation " + toString(type) + " against " + -@@ -1394,10 +1390,10 @@ static void scanReloc(InputSectionBase &sec, OffsetGetter &getOffset, RelTy *&i, - // R_HEX_GD_PLT_B22_PCREL (call a@GDPLT) is transformed into - // call __tls_get_addr even if the symbol is non-preemptible. - if (!(config->emachine == EM_HEXAGON && -- (type == R_HEX_GD_PLT_B22_PCREL || -- type == R_HEX_GD_PLT_B22_PCREL_X || -- type == R_HEX_GD_PLT_B32_PCREL_X))) -- expr = fromPlt(expr); -+ (type == R_HEX_GD_PLT_B22_PCREL || -+ type == R_HEX_GD_PLT_B22_PCREL_X || -+ type == R_HEX_GD_PLT_B32_PCREL_X))) -+ expr = fromPlt(expr); - } else if (!isAbsoluteValue(sym)) { - expr = target->adjustGotPcExpr(type, addend, relocatedAddr); - } -@@ -1410,7 +1406,7 @@ static void scanReloc(InputSectionBase &sec, OffsetGetter &getOffset, RelTy *&i, - if (oneof(expr)) { - in.gotPlt->hasGotPltOffRel = true; - } else if (oneof( expr)) { -+ R_PPC64_RELAX_TOC>(expr)) { - in.got->hasGotOffRel = true; - } - -diff --git a/lld/ELF/Relocations.h b/lld/ELF/Relocations.h -index a702aac18..d91b35705 100644 ---- a/lld/ELF/Relocations.h -+++ b/lld/ELF/Relocations.h -@@ -84,6 +84,9 @@ enum RelExpr { - R_AARCH64_TLSDESC_PAGE, - R_ARM_PCA, - R_ARM_SBREL, -+ R_LARCH_ABS, -+ R_LARCH_PC, -+ R_LARCH_GOTREL, - R_MIPS_GOTREL, - R_MIPS_GOT_GP, - R_MIPS_GOT_GP_PC, -diff --git a/lld/ELF/ScriptParser.cpp b/lld/ELF/ScriptParser.cpp -index 1c743fd47..2711a9deb 100644 ---- a/lld/ELF/ScriptParser.cpp -+++ b/lld/ELF/ScriptParser.cpp -@@ -432,6 +432,7 @@ static std::pair parseBfdName(StringRef s) { - .Case("elf64-littleriscv", {ELF64LEKind, EM_RISCV}) - .Case("elf64-sparc", {ELF64BEKind, EM_SPARCV9}) - .Case("elf32-msp430", {ELF32LEKind, EM_MSP430}) -+ .Case("elf64-loongarch", {ELF64LEKind, EM_LOONGARCH}) - .Default({ELFNoneKind, EM_NONE}); - } - -diff --git a/lld/ELF/Target.cpp b/lld/ELF/Target.cpp -index d3e54f738..59921ba19 100644 ---- a/lld/ELF/Target.cpp -+++ b/lld/ELF/Target.cpp -@@ -62,6 +62,10 @@ TargetInfo *elf::getTarget() { - return getAVRTargetInfo(); - case EM_HEXAGON: - return getHexagonTargetInfo(); -+ case EM_LOONGARCH: -+ if (config->ekind == ELF32LEKind) -+ return getLoongArch32TargetInfo(); -+ return getLoongArch64TargetInfo(); - case EM_MIPS: - switch (config->ekind) { - case ELF32LEKind: -diff --git a/lld/ELF/Target.h b/lld/ELF/Target.h -index 1fe3217c6..eccc2b197 100644 ---- a/lld/ELF/Target.h -+++ b/lld/ELF/Target.h -@@ -79,8 +79,7 @@ public: - uint8_t stOther) const; - - // Return true if we can reach dst from src with RelType type. -- virtual bool inBranchRange(RelType type, uint64_t src, -- uint64_t dst) const; -+ virtual bool inBranchRange(RelType type, uint64_t src, uint64_t dst) const; - - virtual void relocate(uint8_t *loc, const Relocation &rel, - uint64_t val) const = 0; -@@ -176,6 +175,8 @@ TargetInfo *getAMDGPUTargetInfo(); - TargetInfo *getARMTargetInfo(); - TargetInfo *getAVRTargetInfo(); - TargetInfo *getHexagonTargetInfo(); -+TargetInfo *getLoongArch32TargetInfo(); -+TargetInfo *getLoongArch64TargetInfo(); - TargetInfo *getMSP430TargetInfo(); - TargetInfo *getPPC64TargetInfo(); - TargetInfo *getPPCTargetInfo(); -diff --git a/lld/test/ELF/Inputs/loongarch.s b/lld/test/ELF/Inputs/loongarch.s -new file mode 100644 -index 000000000..7ba110fbd ---- /dev/null -+++ b/lld/test/ELF/Inputs/loongarch.s -@@ -0,0 +1,3 @@ -+.global _start -+_start: -+ nop -diff --git a/lld/test/ELF/loongarch-branch.s b/lld/test/ELF/loongarch-branch.s -new file mode 100644 -index 000000000..7c27b9c4e ---- /dev/null -+++ b/lld/test/ELF/loongarch-branch.s -@@ -0,0 +1,42 @@ -+# REQUIRES: loongarch -+ -+# RUN: llvm-mc -filetype=obj -triple=loongarch64 %s -o %t.o -+# RUN: obj2yaml %t.o | FileCheck %s --check-prefix=CHECK-RELOC -+ -+# CHECK-RELOC: Relocations: -+# CHECK-RELOC: - Symbol: foo -+# CHECK-RELOC: Type: R_LARCH_SOP_PUSH_PCREL -+# CHECK-RELOC: - Type: R_LARCH_SOP_POP_32_S_10_16_S2 -+# CHECK-RELOC: - Offset: 0x4 -+# CHECK-RELOC: Symbol: bar -+# CHECK-RELOC: Type: R_LARCH_SOP_PUSH_PCREL -+# CHECK-RELOC: - Offset: 0x4 -+# CHECK-RELOC: Type: R_LARCH_SOP_POP_32_S_10_16_S2 -+ -+# RUN: ld.lld %t.o --defsym foo=_start+0x4 --defsym bar=_start -o %t -+# RUN: llvm-objdump -d %t | FileCheck %s --check-prefix=OBJ -+ -+# OBJ: 00 04 00 58 beq $zero, $zero, 4 -+# OBJ: 00 fc ff 5f bne $zero, $zero, -4 -+ -+# RUN: ld.lld %t.o --defsym foo=_start+0x1FFFC --defsym bar=_start+4-0x20000 \ -+# RUN: -o %t.limits -+# RUN: llvm-objdump -d %t.limits | FileCheck --check-prefix=LIMITS %s -+# LIMITS: 00 fc ff 59 beq $zero, $zero, 131068 -+# LIMITS-NEXT: 00 00 00 5e bne $zero, $zero, -131072 -+ -+# RUN: not ld.lld %t.o --defsym foo=_start+0x20000 \ -+# RUN: --defsym bar=_start+4-0x20004 -o /dev/null 2>&1 \ -+# RUN: | FileCheck --check-prefix=ERROR-RANGE %s -+# ERROR-RANGE: relocation R_LARCH_SOP_POP_32_S_10_16_S2 out of range: 131072 is not in [-131072, 131071] -+# ERROR-RANGE: relocation R_LARCH_SOP_POP_32_S_10_16_S2 out of range: -131076 is not in [-131072, 131071] -+ -+# RUN: not ld.lld %t.o --defsym foo=_start+1 --defsym bar=_start-1 \ -+# RUN: -o /dev/null 2>&1 | FileCheck --check-prefix=ERROR-ALIGN %s -+# ERROR-ALIGN: improper alignment for relocation R_LARCH_SOP_POP_32_S_10_16_S2: 0x1 is not aligned to 4 bytes -+# ERROR-ALIGN-NEXT: improper alignment for relocation R_LARCH_SOP_POP_32_S_10_16_S2: 0xFFFFFFFFFFFFFFFB is not aligned to 4 bytes -+ -+.global _start -+_start: -+ beq $r0, $r0, foo -+ bne $r0, $r0, bar -diff --git a/lld/test/ELF/loongarch-eflags-diff-abi-err.test b/lld/test/ELF/loongarch-eflags-diff-abi-err.test -new file mode 100644 -index 000000000..bae0f3085 ---- /dev/null -+++ b/lld/test/ELF/loongarch-eflags-diff-abi-err.test -@@ -0,0 +1,24 @@ -+# REQUIRES: loongarch -+ -+# RUN: yaml2obj --docnum 1 %s -o %t1.o -+# RUN: yaml2obj --docnum 2 %s -o %t2.o -+# RUN: not ld.lld %t1.o %t2.o -o %t 2>&1 | FileCheck %s -+# -+# CHECK: {{.*}}: ABI 'LPX32' is incompatible with target ABI 'LP32' -+# -+#t1.o -+--- !ELF -+FileHeader: -+ Class: ELFCLASS32 -+ Data: ELFDATA2LSB -+ Type: ET_REL -+ Machine: EM_LOONGARCH -+ Flags: [ EF_LARCH_ABI_LP32 ] -+# t2.o -+--- !ELF -+FileHeader: -+ Class: ELFCLASS32 -+ Data: ELFDATA2LSB -+ Type: ET_REL -+ Machine: EM_LOONGARCH -+ Flags: [ EF_LARCH_ABI_LPX32 ] -diff --git a/lld/test/ELF/loongarch-eflags-lp32.test b/lld/test/ELF/loongarch-eflags-lp32.test -new file mode 100644 -index 000000000..d081e7fb0 ---- /dev/null -+++ b/lld/test/ELF/loongarch-eflags-lp32.test -@@ -0,0 +1,29 @@ -+#.global _start -+#_start: -+# nop -+# -+# REQUIRES: loongarch -+# RUN: yaml2obj %s -o %t.o -+# RUN: ld.lld %t.o -o %t -+# RUN: llvm-readelf -h %t | FileCheck %s -+# Verify the LoongArch LP32 ABI. -+# CHECK: Flags: 0x1 -+# -+--- !ELF -+FileHeader: -+ Class: ELFCLASS32 -+ Data: ELFDATA2LSB -+ Type: ET_REL -+ Machine: EM_LOONGARCH -+ Flags: [ EF_LARCH_ABI_LP32 ] -+Sections: -+ - Name: .text -+ Type: SHT_PROGBITS -+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ] -+ AddressAlign: 0x0000000000000010 -+ Content: '00004003' -+Symbols: -+ - Name: _start -+ Section: .text -+ Binding: STB_GLOBAL -+... -diff --git a/lld/test/ELF/loongarch-eflags-lp64.s b/lld/test/ELF/loongarch-eflags-lp64.s -new file mode 100644 -index 000000000..0775feeb4 ---- /dev/null -+++ b/lld/test/ELF/loongarch-eflags-lp64.s -@@ -0,0 +1,8 @@ -+# REQUIRES: loongarch -+ -+# RUN: llvm-mc -filetype=obj -triple=loongarch64 %s -o %t -+# RUN: llvm-mc -filetype=obj -triple=loongarch64 %S/Inputs/loongarch.s -o %t2 -+# RUN: ld.lld %t2 %t -o %t3 -+# RUN: llvm-readelf -h %t3 | FileCheck %s -+# Verify the LoongArch LP64 ABI. -+# CHECK: Flags: 0x3, LP64 -diff --git a/lld/test/ELF/loongarch-eflags-lpx32.test b/lld/test/ELF/loongarch-eflags-lpx32.test -new file mode 100644 -index 000000000..27b2fc20f ---- /dev/null -+++ b/lld/test/ELF/loongarch-eflags-lpx32.test -@@ -0,0 +1,29 @@ -+#.global _start -+#_start: -+# nop -+# -+# REQUIRES: loongarch -+# RUN: yaml2obj %s -o %t.o -+# RUN: ld.lld %t.o -o %t -+# RUN: llvm-readelf -h %t | FileCheck %s -+# Verify the LoongArch LPX32 ABI. -+# CHECK: Flags: 0x2 -+# -+--- !ELF -+FileHeader: -+ Class: ELFCLASS32 -+ Data: ELFDATA2LSB -+ Type: ET_REL -+ Machine: EM_LOONGARCH -+ Flags: [ EF_LARCH_ABI_LPX32 ] -+Sections: -+ - Name: .text -+ Type: SHT_PROGBITS -+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ] -+ AddressAlign: 0x0000000000000010 -+ Content: '00004003' -+Symbols: -+ - Name: _start -+ Section: .text -+ Binding: STB_GLOBAL -+... -diff --git a/lld/test/ELF/loongarch-got-reloc.s b/lld/test/ELF/loongarch-got-reloc.s -new file mode 100644 -index 000000000..a1df5c876 ---- /dev/null -+++ b/lld/test/ELF/loongarch-got-reloc.s -@@ -0,0 +1,67 @@ -+# REQUIRES: loongarch -+# Check la.got relocation calculation. In this case, la.global will be expanded to la.got. -+ -+# RUN: llvm-mc -filetype=obj -triple=loongarch64 %s -o %t.o -+# RUN: llvm-readobj --relocations %t.o | FileCheck -check-prefix=RELOC %s -+# RUN: ld.lld %t.o -o %t.exe -+# RUN: llvm-objdump --section-headers -t %t.exe | FileCheck -check-prefix=EXE_SYM %s -+# RUN: llvm-objdump -s --section=.got %t.exe | FileCheck -check-prefix=EXE_GOT %s -+# RUN: llvm-objdump -d %t.exe | FileCheck -check-prefix=EXE_DIS %s -+# RUN: llvm-readobj --relocations %t.exe | FileCheck -check-prefix=NORELOC %s -+ -+.text -+.globl _start -+_start: -+ la.global $r12, value -+ -+.data -+value: -+ .word 1 -+ -+# RELOC: Relocations [ -+# RELOC-NEXT: Section (3) .rela.text { -+# RELOC-NEXT: 0x0 R_LARCH_SOP_PUSH_PCREL _GLOBAL_OFFSET_TABLE_ 0x800 -+# RELOC-NEXT: 0x0 R_LARCH_SOP_PUSH_GPREL value 0x0 -+# RELOC-NEXT: 0x0 R_LARCH_SOP_ADD - 0x0 -+# RELOC-NEXT: 0x0 R_LARCH_SOP_PUSH_ABSOLUTE - 0xC -+# RELOC-NEXT: 0x0 R_LARCH_SOP_SR - 0x0 -+# RELOC-NEXT: 0x0 R_LARCH_SOP_POP_32_S_5_20 - 0x0 -+# RELOC-NEXT: 0x4 R_LARCH_SOP_PUSH_PCREL _GLOBAL_OFFSET_TABLE_ 0x4 -+# RELOC-NEXT: 0x4 R_LARCH_SOP_PUSH_GPREL value 0x0 -+# RELOC-NEXT: 0x4 R_LARCH_SOP_ADD - 0x0 -+# RELOC-NEXT: 0x4 R_LARCH_SOP_PUSH_PCREL _GLOBAL_OFFSET_TABLE_ 0x804 -+# RELOC-NEXT: 0x4 R_LARCH_SOP_PUSH_GPREL value 0x0 -+# RELOC-NEXT: 0x4 R_LARCH_SOP_ADD - 0x0 -+# RELOC-NEXT: 0x4 R_LARCH_SOP_PUSH_ABSOLUTE - 0xC -+# RELOC-NEXT: 0x4 R_LARCH_SOP_SR - 0x0 -+# RELOC-NEXT: 0x4 R_LARCH_SOP_PUSH_ABSOLUTE - 0xC -+# RELOC-NEXT: 0x4 R_LARCH_SOP_SL - 0x0 -+# RELOC-NEXT: 0x4 R_LARCH_SOP_SUB - 0x0 -+# RELOC-NEXT: 0x4 R_LARCH_SOP_POP_32_S_10_12 - 0x0 -+# RELOC-NEXT: } -+# RELOC-NEXT: ] -+ -+# EXE_SYM: Sections: -+# EXE_SYM: Idx Name Size VMA Type -+# EXE_SYM: 2 .got 00000010 00000001200201d8 DATA -+# EXE_SYM: SYMBOL TABLE: -+# EXE_SYM: 00000001200201d8 l .got 0000000000000000 .hidden _GLOBAL_OFFSET_TABLE_ -+# ^---- .got -+ -+# EXE_GOT: Contents of section .got: -+# EXE_GOT-NEXT: 1200201d8 00000000 00000000 f0010320 01000000 -+# ^ ^---------value -+# +-- .dynamic address (if exist) -+ -+# pcaddu12i rd,(%pcrel(_GLOBAL_OFFSET_TABLE_+0x800)+%gprel(symbol))>>12 -+# value_GotAddr=%gprel(synbol) = 0x1200201e0-0x1200201d8 = 8 -+# (0x1200201d8+0x800-0x1200101d0+8)>>12 = 16 -+# EXE_DIS: 1200101d0: 0c 02 00 1c pcaddu12i $r12, 16 -+ -+# ld.d rd,rd,%pcrel(_GLOBAL_OFFSET_TABLE_+4)+%gprel(symbol)-((%pcrel( -+# _GLOBAL_OFFSET_TABLE_+4+0x800)+%gprel(symbol))>>12<<12) -+# (0x1200201d8+4-0x1200101d4)+8-((0x1200201d8+4+0x800-0x1200101d4)+8)>>12<<12 = 8 -+# EXE_DIS-NEXT: 1200101d4: 8c 41 c0 28 ld.d $r12, $r12, 16 -+ -+# NORELOC: Relocations [ -+# NORELOC-NEXT: ] -diff --git a/lld/test/ELF/loongarch-plt.s b/lld/test/ELF/loongarch-plt.s -new file mode 100644 -index 000000000..f8cbf35e6 ---- /dev/null -+++ b/lld/test/ELF/loongarch-plt.s -@@ -0,0 +1,83 @@ -+# REQUIRES: loongarch -+# RUN: echo '.globl bar, weak; .type bar,@function; .type weak,@function; bar: weak:' > %t1.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 -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*}}1200102f0 -+ -+## 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. -+# RELOC64: .rela.plt { -+# RELOC64-NEXT: 0x120030410 R_LARCH_JUMP_SLOT bar 0x0 -+# RELOC64-NEXT: 0x120030418 R_LARCH_JUMP_SLOT weak 0x0 -+# RELOC64-NEXT: } -+# GOTPLT64: section '.got.plt' -+# GOTPLT64-NEXT: 0x120030400 00000000 00000000 00000000 00000000 -+# GOTPLT64-NEXT: 0x120030410 f0020120 01000000 f0020120 01000000 -+ -+# DIS: <_start>: -+## foo - . = 0x1200102e0-0x1200102d0 = 16 -+# DIS-NEXT: 1200102d0: bl 16 -+## bar@plt - . = 0x120010310-0x1200102d4 = 60 -+# DIS-NEXT: 1200102d4: bl 60 -+## bar@plt - . = 0x120010310-0x1200102d8 = 56 -+# DIS-NEXT: 1200102d8: bl 56 -+## weak@plt - . = 0x120010320-0x1200102dc = 68 -+# DIS-NEXT: 1200102dc: bl 68 -+# DIS: : -+# DIS-NEXT: 1200102e0: jirl $zero, $ra, 0 -+ -+## 120030400 .got.plt -+## 1200102f0 .plt -+# DIS: Disassembly of section .plt: -+# DIS: <.plt>: -+## hi20(.got.plt - .plt + 0x800) = (0x120030400 - 0x1200102f0 + 0x800)>>12 = 0x20910 >> 12 = 0x20 -+# DIS-NEXT: pcaddu12i $r14, 32 -+# DIS-NEXT: sub.d $r13, $r13, $r15 -+## lo12(.got.plt - .plt) = (0x120030400 - 0x1200102f0) & 0xfff = 0x20110 & 0xfff = 0x110 -+# DIS64-NEXT: ld.d $r15, $r14, 272 -+# DIS64-NEXT: addi.d $r13, $r13, -40 -+## lo12(.got.plt - .plt) = (0x120030400 - 0x1200102f0) & 0xfff = 0x20110 & 0xfff = 0x110 -+# DIS64-NEXT: addi.d $r12, $r14, 272 -+# DIS64-NEXT: srli.d $r13, $r13, 1 -+# DIS64-NEXT: ld.d $r12, $r12, 8 -+# DIS-NEXT: jirl $zero, $r15, 0 -+ -+## hi20(&.got.plt[bar]-.) = (0x120030410 - 0x120010310 + 0x800) >> 12 = 0x20900 >> 12 = 0x20 -+# DIS: 120010310: pcaddu12i $r15, 32 -+## lo12(&.got.plt[bar]-.) = (0x120030410 - 0x120010310) & 0xfff = 0x20100 & 0xfff = 0x100 -+# DIS64-NEXT: ld.d $r15, $r15, 256 -+# DIS-NEXT: pcaddu12i $r13, 0 -+# DIS-NEXT: jirl $zero, $r15, 0 -+ -+## hi20(&.got.plt[weak]-.) = (0x120030418 - 0x120010320 + 0x800) >> 12 = 0x208f8 >> 12 = 0x20 -+# DIS: 120010320: pcaddu12i $r15, 32 -+## lo12(&.got.plt[weak]-.) = (0x120030418 - 0x120010320) & 0xfff = 0x200f8 & 0xfff = 0xf8 -+# DIS64-NEXT: ld.d $r15, $r15, 248 -+# DIS-NEXT: pcaddu12i $r13, 0 -+# DIS-NEXT: jirl $zero, $r15, 0 -+ -+.global _start, foo, bar -+.weak weak -+ -+_start: -+ bl foo -+ bl bar -+ bl bar@plt -+ bl weak -+ -+## foo is local and non-preemptale, no PLT is generated. -+foo: -+ jr $ra -diff --git a/lld/test/ELF/loongarch-relative.s b/lld/test/ELF/loongarch-relative.s -new file mode 100644 -index 000000000..cb1456054 ---- /dev/null -+++ b/lld/test/ELF/loongarch-relative.s -@@ -0,0 +1,59 @@ -+// XFAIL: loongarch -+// REQUIRES: loongarch -+// Test that we create R_LARCH_RELATIVE relocations for the dynamic linker -+// but don't put any symbols in the dynamic symbol table. -+ -+// RUN: llvm-mc -filetype=obj -triple=loongarch64 %s -o %t.o -+// RUN: ld.lld -shared %t.o -o %t.so -+// RUN: llvm-readobj -t -r -dyn-symbols %t.so | FileCheck %s -+ -+// CHECK: Relocations [ -+// CHECK-NEXT: Section ({{.*}}) .rela.dyn { -+// CHECK-NEXT: 0x[[FOO_ADDR:.*]] R_LARCH_RELATIVE - 0x[[FOO_ADDR]] -+// CHECK-NEXT: 0x[[BAR_ADDR:.*]] R_LARCH_RELATIVE - 0x[[BAR_ADDR]] -+// CHECK-NEXT: 0x10008 R_LARCH_RELATIVE - 0x10005 -+// CHECK-NEXT: 0x{{.*}} R_LARCH_RELATIVE - 0x[[FOO_ADDR]] -+// CHECK-NEXT: 0x{{.*}} R_LARCH_32 external 0x0 -+// CHECK-NEXT: } -+// CHECK-NEXT: ] -+ -+// CHECK: Symbols [ -+// CHECK: Name: foo -+// CHECK-NEXT: Value: 0x[[FOO_ADDR]] -+// CHECK: Name: bar -+// CHECK-NEXT: Value: 0x[[BAR_ADDR]] -+// CHECK: ] -+ -+// CHECK: DynamicSymbols [ -+// CHECK-NEXT: Symbol { -+// CHECK-NEXT: Name: -+// CHECK-NEXT: Value: 0x0 -+// CHECK-NEXT: Size: 0 -+// CHECK-NEXT: Binding: Local -+// CHECK-NEXT: Type: None -+// CHECK-NEXT: Other: 0 -+// CHECK-NEXT: Section: Undefined -+// CHECK-NEXT: } -+// CHECK-NEXT: Symbol { -+// CHECK-NEXT: Name: external -+// CHECK-NEXT: Value: 0x0 -+// CHECK-NEXT: Size: 0 -+// CHECK-NEXT: Binding: Global -+// CHECK-NEXT: Type: None -+// CHECK-NEXT: Other: 0 -+// CHECK-NEXT: Section: Undefined -+// CHECK-NEXT: } -+// CHECK-NEXT: ] -+ -+ .data -+foo: -+ .long foo -+ -+ .hidden bar -+ .globl bar -+bar: -+ .long bar -+ .long bar + 1 -+ .long foo -+ -+ .long external -diff --git a/lld/test/ELF/loongarch-tls-gd.s b/lld/test/ELF/loongarch-tls-gd.s -new file mode 100644 -index 000000000..7c55c4749 ---- /dev/null -+++ b/lld/test/ELF/loongarch-tls-gd.s -@@ -0,0 +1,137 @@ -+# REQUIRES: loongarch -+ -+# RUN: llvm-mc -filetype=obj -triple=loongarch64-unknown-linux %s -o %t.o -+# RUN: llvm-readobj --relocations %t.o | FileCheck -check-prefix=InputRelocs %s -+# RUN: ld.lld %t.o -o %t -+# RUN: llvm-objdump -s --section=.got %t | FileCheck -check-prefix=GOT %s -+# RUN: ld.lld -shared %t.o -o %t.so -+# RUN: llvm-readobj --relocations %t.so | FileCheck -check-prefix=OutputRelocs %s -+# RUN: llvm-objdump --section-headers -t %t.so | FileCheck -check-prefix=SO_SYM %s -+# RUN: llvm-objdump -s --section=.got %t.so | FileCheck -check-prefix=SO_GOT %s -+# RUN: llvm-objdump -d %t.so | FileCheck --check-prefixes=DIS %s -+ -+# Test the handling of the global-dynamic TLS model. Dynamic Loader finds -+# module index R_LARCH_TLS_DTPMODNN. For an executable we write the module -+# index 1 and the offset into the TLS directly into the GOT. For a shared -+# library we can only write the offset into the TLS directly if the symbol -+# is non-preemptible -+ -+# la.tls.ld alias for la.tls.gd, So we only check la.tls.gd. -+ -+.globl _start -+_start: -+ la.tls.gd $r12, x -+ la.tls.gd $r15, z -+ -+.section .tdata -+.local x -+x: -+.byte 10 -+ -+.global z -+z: -+.long 10 -+ -+# InputRelocs: Relocations [ -+# InputRelocs-NEXT: Section (3) .rela.text { -+# InputRelocs-NEXT: 0x0 R_LARCH_SOP_PUSH_PCREL _GLOBAL_OFFSET_TABLE_ 0x800 -+# InputRelocs-NEXT: 0x0 R_LARCH_SOP_PUSH_TLS_GD x 0x0 -+# InputRelocs-NEXT: 0x0 R_LARCH_SOP_ADD - 0x0 -+# InputRelocs-NEXT: 0x0 R_LARCH_SOP_PUSH_ABSOLUTE - 0xC -+# InputRelocs-NEXT: 0x0 R_LARCH_SOP_SR - 0x0 -+# InputRelocs-NEXT: 0x0 R_LARCH_SOP_POP_32_S_5_20 - 0x0 -+# InputRelocs-NEXT: 0x4 R_LARCH_SOP_PUSH_PCREL _GLOBAL_OFFSET_TABLE_ 0x4 -+# InputRelocs-NEXT: 0x4 R_LARCH_SOP_PUSH_TLS_GD x 0x0 -+# InputRelocs-NEXT: 0x4 R_LARCH_SOP_ADD - 0x0 -+# InputRelocs-NEXT: 0x4 R_LARCH_SOP_PUSH_PCREL _GLOBAL_OFFSET_TABLE_ 0x804 -+# InputRelocs-NEXT: 0x4 R_LARCH_SOP_PUSH_TLS_GD x 0x0 -+# InputRelocs-NEXT: 0x4 R_LARCH_SOP_ADD - 0x0 -+# InputRelocs-NEXT: 0x4 R_LARCH_SOP_PUSH_ABSOLUTE - 0xC -+# InputRelocs-NEXT: 0x4 R_LARCH_SOP_SR - 0x0 -+# InputRelocs-NEXT: 0x4 R_LARCH_SOP_PUSH_ABSOLUTE - 0xC -+# InputRelocs-NEXT: 0x4 R_LARCH_SOP_SL - 0x0 -+# InputRelocs-NEXT: 0x4 R_LARCH_SOP_SUB - 0x0 -+# InputRelocs-NEXT: 0x4 R_LARCH_SOP_POP_32_S_10_12 - 0x0 -+# InputRelocs-NEXT: 0x8 R_LARCH_SOP_PUSH_PCREL _GLOBAL_OFFSET_TABLE_ 0x800 -+# InputRelocs-NEXT: 0x8 R_LARCH_SOP_PUSH_TLS_GD z 0x0 -+# InputRelocs-NEXT: 0x8 R_LARCH_SOP_ADD - 0x0 -+# InputRelocs-NEXT: 0x8 R_LARCH_SOP_PUSH_ABSOLUTE - 0xC -+# InputRelocs-NEXT: 0x8 R_LARCH_SOP_SR - 0x0 -+# InputRelocs-NEXT: 0x8 R_LARCH_SOP_POP_32_S_5_20 - 0x0 -+# InputRelocs-NEXT: 0xC R_LARCH_SOP_PUSH_PCREL _GLOBAL_OFFSET_TABLE_ 0x4 -+# InputRelocs-NEXT: 0xC R_LARCH_SOP_PUSH_TLS_GD z 0x0 -+# InputRelocs-NEXT: 0xC R_LARCH_SOP_ADD - 0x0 -+# InputRelocs-NEXT: 0xC R_LARCH_SOP_PUSH_PCREL _GLOBAL_OFFSET_TABLE_ 0x804 -+# InputRelocs-NEXT: 0xC R_LARCH_SOP_PUSH_TLS_GD z 0x0 -+# InputRelocs-NEXT: 0xC R_LARCH_SOP_ADD - 0x0 -+# InputRelocs-NEXT: 0xC R_LARCH_SOP_PUSH_ABSOLUTE - 0xC -+# InputRelocs-NEXT: 0xC R_LARCH_SOP_SR - 0x0 -+# InputRelocs-NEXT: 0xC R_LARCH_SOP_PUSH_ABSOLUTE - 0xC -+# InputRelocs-NEXT: 0xC R_LARCH_SOP_SL - 0x0 -+# InputRelocs-NEXT: 0xC R_LARCH_SOP_SUB - 0x0 -+# InputRelocs-NEXT: 0xC R_LARCH_SOP_POP_32_S_10_12 - 0x0 -+# InputRelocs-NEXT: } -+# InputRelocs-NEXT: ] -+ -+ -+# For an executable we write the module index 1 and the offset -+# into the TLS directly into the GOT. -+ -+# GOT: Contents of section .got: -+# GOT-NEXT: 120020218 00000000 00000000 01000000 00000000 {{.*}} -+# ^ ^-----x-module-id -+# +-.dynamic address(not exist) -+# GOT-NEXT: 120020228 00000000 00000000 01000000 00000000 {{.*}} -+# ^--x-offset ^-----z-module-id -+# GOT-NEXT: 120020238 01000000 00000000 {{.*}} -+# ^--z-offset -+ -+# OutputRelocs: Relocations [ -+# OutputRelocs-NEXT: Section (5) .rela.dyn { -+# OutputRelocs-NEXT: 0x203E0 R_LARCH_TLS_DTPMOD64 - 0x0 -+# OutputRelocs-NEXT: 0x203F0 R_LARCH_TLS_DTPMOD64 z 0x0 -+# OutputRelocs-NEXT: 0x203F8 R_LARCH_TLS_DTPREL64 z 0x0 -+# OutputRelocs-NEXT: } -+# OutputRelocs-NEXT: ] -+ -+# SO_SYM: Sections: -+# SO_SYM: Idx Name Size VMA Type -+# SO_SYM: 7 .tdata 00000005 0000000000020330 DATA -+# SO_SYM: 8 .dynamic 000000a0 0000000000020338 -+# SO_SYM: 9 .got 00000028 00000000000203d8 DATA -+# SO_SYM: SYMBOL TABLE: -+# SO_SYM: {{0*}} l .tdata {{0*}} x -+# _GLOBAL_OFFSET_TABLE_ 0x203d8 -+# SO_SYM: 00000000000203d8 l .got {{0*}} .hidden _GLOBAL_OFFSET_TABLE_ -+# SO_SYM: 0000000000020338 l .dynamic {{0*}} .hidden _DYNAMIC -+# SO_SYM: 0000000000000001 g .tdata {{0*}} z -+ -+# For a shared library we can only write the offset into the TLS directly -+ -+# SO_GOT: Contents of section .got: -+# SO_GOT-NEXT: 203d8 38030200 00000000 00000000 00000000 -+# ^ ^-----x-module-id -+# +---.dynamic address -+# SO_GOT-NEXT: 203e8 00000000 00000000 00000000 00000000 -+# ^---x-offset ^-----z-module-id -+# SO_GOT-NEXT: 203f8 00000000 00000000 -+# ^---z-offset -+ -+# %tlsgd(x)=8; %tlsgd(z)=24 -+ -+# la.tls.gd rd, symbol will be expanded to such instructions: -+# pcaddu12i rd,(%pcrel(_GLOBAL_OFFSET_TABLE_+0x800)+%tlsgd(symbol))>>12 -+# addi.d rd,rd,%pcrel(_GLOBAL_OFFSET_TABLE_+4)+%tlsgd(symbol) - \ -+# ((%pcrel(_GLOBAL_OFFSET_TABLE_+4+0x800)+%tlsgd(symbol))>>12<<12) -+ -+# la.tls.gd $r12, x -+# (0x203d8+0x800-0x10320+8)>>12 = 16 -+# DIS: 10320: 0c 02 00 1c pcaddu12i $r12, 16 -+# (0x203d8+4-0x10324+8)-((0x203d8+4+0x800-0x10324)+8)>>12<<12 = 0xC0 = 192 -+# DIS-NEXT: 10324: 8c 01 c3 02 addi.d $r12, $r12, 192 -+ -+# la.tls.gd $r15, z -+# (0x203d8+0x800-0x10328+8)>>12 = 16 -+# DIS-NEXT: 10328: 0f 02 00 1c pcaddu12i $r15, 16 -+# (0x203d8+4-0x1032c+24)-((0x203d8+4+0x800-0x1032c)+24)>>12<<12 = 0xC8 = 200 -+# DIS-NEXT: 1032c: ef 21 c3 02 addi.d $r15, $r15, 200 -diff --git a/lld/test/ELF/loongarch-tls-ie.s b/lld/test/ELF/loongarch-tls-ie.s -new file mode 100644 -index 000000000..a0037b958 ---- /dev/null -+++ b/lld/test/ELF/loongarch-tls-ie.s -@@ -0,0 +1,61 @@ -+# REQUIRES: loongarch -+ -+# RUN: llvm-mc -filetype=obj -triple=loongarch64 %s -o %t.64.o -+# RUN: llvm-objdump -r %t.64.o | FileCheck --check-prefix=RELOCS %s -+## loongarch64 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=IE,IE64 %s -+ -+# RELOCS: RELOCATION RECORDS FOR [.text]: -+# RELOCS-NEXT: OFFSET TYPE VALUE -+# RELOCS-NEXT: {{[0-9abcdef]*}} R_LARCH_SOP_PUSH_PCREL _GLOBAL_OFFSET_TABLE_+0x800 -+# RELOCS-NEXT: {{[0-9abcdef]*}} R_LARCH_SOP_PUSH_TLS_GOT y -+# RELOCS-NEXT: {{[0-9abcdef]*}} R_LARCH_SOP_ADD *ABS* -+# RELOCS-NEXT: {{[0-9abcdef]*}} R_LARCH_SOP_PUSH_ABSOLUTE *ABS*+0xc -+# RELOCS-NEXT: {{[0-9abcdef]*}} R_LARCH_SOP_SR *ABS* -+# RELOCS-NEXT: {{[0-9abcdef]*}} R_LARCH_SOP_POP_32_S_5_20 *ABS* -+# RELOCS-NEXT: {{[0-9abcdef]*}} R_LARCH_SOP_PUSH_PCREL _GLOBAL_OFFSET_TABLE_+0x4 -+# RELOCS-NEXT: {{[0-9abcdef]*}} R_LARCH_SOP_PUSH_TLS_GOT y -+# RELOCS-NEXT: {{[0-9abcdef]*}} R_LARCH_SOP_ADD *ABS* -+# RELOCS-NEXT: {{[0-9abcdef]*}} R_LARCH_SOP_PUSH_PCREL _GLOBAL_OFFSET_TABLE_+0x804 -+# RELOCS-NEXT: {{[0-9abcdef]*}} R_LARCH_SOP_PUSH_TLS_GOT y -+# RELOCS-NEXT: {{[0-9abcdef]*}} R_LARCH_SOP_ADD *ABS* -+# RELOCS-NEXT: {{[0-9abcdef]*}} R_LARCH_SOP_PUSH_ABSOLUTE *ABS*+0xc -+# RELOCS-NEXT: {{[0-9abcdef]*}} R_LARCH_SOP_SR *ABS* -+# RELOCS-NEXT: {{[0-9abcdef]*}} R_LARCH_SOP_PUSH_ABSOLUTE *ABS*+0xc -+# RELOCS-NEXT: {{[0-9abcdef]*}} R_LARCH_SOP_SL *ABS* -+# RELOCS-NEXT: {{[0-9abcdef]*}} R_LARCH_SOP_SUB *ABS* -+# RELOCS-NEXT: {{[0-9abcdef]*}} R_LARCH_SOP_POP_32_S_10_12 *ABS* -+ -+# IE64-REL: .rela.dyn { -+# IE64-REL-NEXT: 0x203B0 R_LARCH_TLS_TPREL64 - 0x4 -+# IE64-REL-NEXT: 0x203A8 R_LARCH_TLS_TPREL64 y 0x0 -+# IE64-REL-NEXT: } -+ -+## loongarch64: &.got[y] - . = 0x203A8 - . = 0x100C8 = 4096*16+200 -+# IE: 102e0: pcaddu12i $r4, 16 -+# IE64-NEXT: ld.d $r4, $r4, 200 -+# IE-NEXT: addi.w $r5, $zero, 10 -+# IE-NEXT: stx.w $r5, $tp, $r4 -+## loongarch64: &.got[z] - . = 0x203B0 - . = 0x100C0 = 4096*16+192 -+# IE: 102f0: pcaddu12i $r6, 16 -+# IE64-NEXT: ld.d $r6, $r6, 192 -+# IE-NEXT: addi.w $r7, $zero, 100 -+# IE-NEXT: stx.w $r7, $tp, $r6 -+ -+la.tls.ie $r4, y -+addi.w $r5, $zero, 10 -+stx.w $r5, $tp, $r4 -+la.tls.ie $r6, z -+addi.w $r7, $zero, 100 -+stx.w $r7, $tp, $r6 -+ -+.section .tbss -+.globl y -+y: -+.word 0 -+.size y, 4 -+z: -+.word 0 -+.size z, 4 -diff --git a/lld/test/ELF/loongarch-tls-le.s b/lld/test/ELF/loongarch-tls-le.s -new file mode 100644 -index 000000000..cdd6bcd7c ---- /dev/null -+++ b/lld/test/ELF/loongarch-tls-le.s -@@ -0,0 +1,130 @@ -+# REQUIRES: loongarch -+ -+# RUN: llvm-mc -filetype=obj -triple=loongarch64 %s -o %t.o -+# RUN: llvm-readobj --relocations %t.o | FileCheck -check-prefix=InputRelocs %s -+# RUN: ld.lld %t.o -o %t -+# RUN: llvm-readobj --relocations %t | FileCheck -check-prefix=OutputRelocs %s -+# RUN: llvm-objdump --section-headers -t %t | FileCheck -check-prefix=SO_SYM %s -+# RUN: llvm-objdump -d %t | FileCheck --check-prefixes=DIS %s -+ -+# Test the handling of the Local-Exec TLS model. TLS can be resolved -+# statically for an application. -+ -+.globl _start -+_start: -+ la.tls.le $r12, x -+ la.tls.le $r13, y -+ la.tls.le $r15, z + 0x100 -+ -+.section .tdata -+.local x -+x: -+.byte 10 -+ -+.globl y -+y: -+.word 10 -+ -+.local z -+z: -+.long 10 -+ -+# InputRelocs: Relocations [ -+# InputRelocs-NEXT: Section (3) .rela.text { -+# InputRelocs-NEXT: 0x0 R_LARCH_SOP_PUSH_TLS_TPREL x 0x0 -+# InputRelocs-NEXT: 0x0 R_LARCH_SOP_PUSH_ABSOLUTE - 0x20 -+# InputRelocs-NEXT: 0x0 R_LARCH_SOP_SL - 0x0 -+# InputRelocs-NEXT: 0x0 R_LARCH_SOP_PUSH_ABSOLUTE - 0x2C -+# InputRelocs-NEXT: 0x0 R_LARCH_SOP_SR - 0x0 -+# InputRelocs-NEXT: 0x0 R_LARCH_SOP_POP_32_S_5_20 - 0x0 -+# InputRelocs-NEXT: 0x4 R_LARCH_SOP_PUSH_TLS_TPREL x 0x0 -+# InputRelocs-NEXT: 0x4 R_LARCH_SOP_PUSH_ABSOLUTE - 0xFFF -+# InputRelocs-NEXT: 0x4 R_LARCH_SOP_AND - 0x0 -+# InputRelocs-NEXT: 0x4 R_LARCH_SOP_POP_32_U_10_12 - 0x0 -+# InputRelocs-NEXT: 0x8 R_LARCH_SOP_PUSH_TLS_TPREL x 0x0 -+# InputRelocs-NEXT: 0x8 R_LARCH_SOP_PUSH_ABSOLUTE - 0xC -+# InputRelocs-NEXT: 0x8 R_LARCH_SOP_SL - 0x0 -+# InputRelocs-NEXT: 0x8 R_LARCH_SOP_PUSH_ABSOLUTE - 0x2C -+# InputRelocs-NEXT: 0x8 R_LARCH_SOP_SR - 0x0 -+# InputRelocs-NEXT: 0x8 R_LARCH_SOP_POP_32_S_5_20 - 0x0 -+# InputRelocs-NEXT: 0xC R_LARCH_SOP_PUSH_TLS_TPREL x 0x0 -+# InputRelocs-NEXT: 0xC R_LARCH_SOP_PUSH_ABSOLUTE - 0x34 -+# InputRelocs-NEXT: 0xC R_LARCH_SOP_SR - 0x0 -+# InputRelocs-NEXT: 0xC R_LARCH_SOP_POP_32_S_10_12 - 0x0 -+# InputRelocs-NEXT: 0x10 R_LARCH_SOP_PUSH_TLS_TPREL y 0x0 -+# InputRelocs-NEXT: 0x10 R_LARCH_SOP_PUSH_ABSOLUTE - 0x20 -+# InputRelocs-NEXT: 0x10 R_LARCH_SOP_SL - 0x0 -+# InputRelocs-NEXT: 0x10 R_LARCH_SOP_PUSH_ABSOLUTE - 0x2C -+# InputRelocs-NEXT: 0x10 R_LARCH_SOP_SR - 0x0 -+# InputRelocs-NEXT: 0x10 R_LARCH_SOP_POP_32_S_5_20 - 0x0 -+# InputRelocs-NEXT: 0x14 R_LARCH_SOP_PUSH_TLS_TPREL y 0x0 -+# InputRelocs-NEXT: 0x14 R_LARCH_SOP_PUSH_ABSOLUTE - 0xFFF -+# InputRelocs-NEXT: 0x14 R_LARCH_SOP_AND - 0x0 -+# InputRelocs-NEXT: 0x14 R_LARCH_SOP_POP_32_U_10_12 - 0x0 -+# InputRelocs-NEXT: 0x18 R_LARCH_SOP_PUSH_TLS_TPREL y 0x0 -+# InputRelocs-NEXT: 0x18 R_LARCH_SOP_PUSH_ABSOLUTE - 0xC -+# InputRelocs-NEXT: 0x18 R_LARCH_SOP_SL - 0x0 -+# InputRelocs-NEXT: 0x18 R_LARCH_SOP_PUSH_ABSOLUTE - 0x2C -+# InputRelocs-NEXT: 0x18 R_LARCH_SOP_SR - 0x0 -+# InputRelocs-NEXT: 0x18 R_LARCH_SOP_POP_32_S_5_20 - 0x0 -+# InputRelocs-NEXT: 0x1C R_LARCH_SOP_PUSH_TLS_TPREL y 0x0 -+# InputRelocs-NEXT: 0x1C R_LARCH_SOP_PUSH_ABSOLUTE - 0x34 -+# InputRelocs-NEXT: 0x1C R_LARCH_SOP_SR - 0x0 -+# InputRelocs-NEXT: 0x1C R_LARCH_SOP_POP_32_S_10_12 - 0x0 -+# InputRelocs-NEXT: 0x20 R_LARCH_SOP_PUSH_TLS_TPREL z 0x100 -+# InputRelocs-NEXT: 0x20 R_LARCH_SOP_PUSH_ABSOLUTE - 0x20 -+# InputRelocs-NEXT: 0x20 R_LARCH_SOP_SL - 0x0 -+# InputRelocs-NEXT: 0x20 R_LARCH_SOP_PUSH_ABSOLUTE - 0x2C -+# InputRelocs-NEXT: 0x20 R_LARCH_SOP_SR - 0x0 -+# InputRelocs-NEXT: 0x20 R_LARCH_SOP_POP_32_S_5_20 - 0x0 -+# InputRelocs-NEXT: 0x24 R_LARCH_SOP_PUSH_TLS_TPREL z 0x100 -+# InputRelocs-NEXT: 0x24 R_LARCH_SOP_PUSH_ABSOLUTE - 0xFFF -+# InputRelocs-NEXT: 0x24 R_LARCH_SOP_AND - 0x0 -+# InputRelocs-NEXT: 0x24 R_LARCH_SOP_POP_32_U_10_12 - 0x0 -+# InputRelocs-NEXT: 0x28 R_LARCH_SOP_PUSH_TLS_TPREL z 0x100 -+# InputRelocs-NEXT: 0x28 R_LARCH_SOP_PUSH_ABSOLUTE - 0xC -+# InputRelocs-NEXT: 0x28 R_LARCH_SOP_SL - 0x0 -+# InputRelocs-NEXT: 0x28 R_LARCH_SOP_PUSH_ABSOLUTE - 0x2C -+# InputRelocs-NEXT: 0x28 R_LARCH_SOP_SR - 0x0 -+# InputRelocs-NEXT: 0x28 R_LARCH_SOP_POP_32_S_5_20 - 0x0 -+# InputRelocs-NEXT: 0x2C R_LARCH_SOP_PUSH_TLS_TPREL z 0x100 -+# InputRelocs-NEXT: 0x2C R_LARCH_SOP_PUSH_ABSOLUTE - 0x34 -+# InputRelocs-NEXT: 0x2C R_LARCH_SOP_SR - 0x0 -+# InputRelocs-NEXT: 0x2C R_LARCH_SOP_POP_32_S_10_12 - 0x0 -+# InputRelocs-NEXT: } -+# InputRelocs-NEXT: ] -+ -+# Local-Exec creates no -+# OutputRelocs: Relocations [ -+# OutputRelocs-NEXT: ] -+ -+# SO_SYM: Sections: -+# SO_SYM: Idx Name Size VMA Type -+# SO_SYM: 2 .tdata 00000009 0000000120020230 DATA -+# SO_SYM: SYMBOL TABLE: -+# SO_SYM: 0000000000000000 l .tdata {{0*}} x -+# SO_SYM: 0000000000000005 l .tdata {{0*}} z -+# SO_SYM: 0000000000000001 g .tdata {{0*}} y -+ -+# %tprel(x+addend)=0 ; %tprel(y+addend)=1 ; %tprel(z+0x100)=0x105=261 -+ -+# la.tls.le rd, symbol + addend -+# Load $tp-relative offset of TLS symbol -+# will be expanded to such instructions: -+# lu12i.w rd,%tprel(symbol + addend)<<32>>44 -+# ori rd,rd,%tprel(symbol + addend)&0xfff -+# lu32i.d rd,%tprel(symbol + addend)<<12>>44 -+# lu52i.d rd,rd,%tprel(symbol + addend)>>52 -+ -+# DIS: 120010200: 0c 00 00 14 lu12i.w $r12, 0 -+# DIS-NEXT: 120010204: 8c 01 80 03 ori $r12, $r12, 0 -+# DIS-NEXT: 120010208: 0c 00 00 16 lu32i.d $r12, 0 -+# DIS-NEXT: 12001020c: 8c 01 00 03 lu52i.d $r12, $r12, 0 -+# DIS-NEXT: 120010210: 0d 00 00 14 lu12i.w $r13, 0 -+# DIS-NEXT: 120010214: ad 05 80 03 ori $r13, $r13, 1 -+# DIS-NEXT: 120010218: 0d 00 00 16 lu32i.d $r13, 0 -+# DIS-NEXT: 12001021c: ad 01 00 03 lu52i.d $r13, $r13, 0 -+# DIS-NEXT: 120010220: 0f 00 00 14 lu12i.w $r15, 0 -+# DIS-NEXT: 120010224: ef 15 84 03 ori $r15, $r15, 261 -+# DIS-NEXT: 120010228: 0f 00 00 16 lu32i.d $r15, 0 -+# DIS-NEXT: 12001022c: ef 01 00 03 lu52i.d $r15, $r15, 0 -diff --git a/lld/test/ELF/loongarch_eh_frame.s b/lld/test/ELF/loongarch_eh_frame.s -new file mode 100644 -index 000000000..6e9769ffe ---- /dev/null -+++ b/lld/test/ELF/loongarch_eh_frame.s -@@ -0,0 +1,23 @@ -+# REQUIRES: loongarch -+ -+# RUN: llvm-mc -filetype=obj -triple=loongarch64 %s -o %t.o -+# RUN: ld.lld -shared %t.o -o %t.so -+ -+.globl _start -+_start: -+ nop -+ -+.section foo,"ax",@progbits -+.cfi_startproc -+ nop -+.cfi_endproc -+ -+.section bar,"ax",@progbits -+.cfi_startproc -+ nop -+.cfi_endproc -+ -+.section dah,"ax",@progbits -+.cfi_startproc -+ nop -+.cfi_endproc -diff --git a/lld/test/lit.cfg.py b/lld/test/lit.cfg.py -index 225104243..c1da1b54e 100644 ---- a/lld/test/lit.cfg.py -+++ b/lld/test/lit.cfg.py -@@ -70,6 +70,7 @@ llvm_config.feature_config( - 'ARM': 'arm', - 'AVR': 'avr', - 'Hexagon': 'hexagon', -+ 'LoongArch': 'loongarch', - 'Mips': 'mips', - 'MSP430': 'msp430', - 'PowerPC': 'ppc', diff --git a/download b/download index 226f310a5352b0d86d4863497fd87f0c85136427..af17c7fb98b6e725b2929efd376acaa7b9e9520d 100644 --- a/download +++ b/download @@ -1,2 +1,2 @@ -a33aa45465a1ba896f55e87c0b0f4189 lld-13.0.1.src.tar.xz -6ea9a0b83148d1fd0d1a053c80f560c8 lld-13.0.1.src.tar.xz.sig +606743c854cbc9d9c61aa6f480c6d9e4 lld-14.0.6.src.tar.xz +e3335369091801a6bd4affb34b3f8cfe lld-14.0.6.src.tar.xz.sig diff --git a/lld.spec b/lld.spec index cf4e04bb0e781b3e31372d8b48ccda5232558758..e4a08b38ca2672b2fbd7cb8d760bc18016bf68ef 100644 --- a/lld.spec +++ b/lld.spec @@ -1,28 +1,27 @@ -%define anolis_release .0.1 %bcond_without check -#global rc_ver 4 +#global rc_ver 1 %global lld_srcdir lld-%{maj_ver}.%{min_ver}.%{patch_ver}%{?rc_ver:rc%{rc_ver}}.src -%global baserelease 2 -%global maj_ver 13 +%global maj_ver 14 %global min_ver 0 -%global patch_ver 1 +%global patch_ver 6 # Don't include unittests in automatic generation of provides or requires. %global __provides_exclude_from ^%{_libdir}/lld/.*$ %global __requires_exclude ^libgtest.*$ %bcond_with ld_alternative +%bcond_with testpkg Name: lld Version: %{maj_ver}.%{min_ver}.%{patch_ver}%{?rc_ver:~rc%{rc_ver}} -Release: %{baserelease}%{anolis_release}%{?rc_ver:.rc%{rc_ver}}%{?dist} +Release: 1%{?rc_ver:.rc%{rc_ver}}%{?dist} Summary: The LLVM Linker License: NCSA URL: http://llvm.org -Source0: https://github.com/llvm/llvm-project/releases/download/llvmorg-%{version}%{?rc_ver:-rc%{rc_ver}}/%{lld_srcdir}.tar.xz -Source1: https://github.com/llvm/llvm-project/releases/download/llvmorg-%{version}%{?rc_ver:-rc%{rc_ver}}/%{lld_srcdir}.tar.xz.sig +Source0: https://github.com/llvm/llvm-project/releases/download/llvmorg-%{maj_ver}.%{min_ver}.%{patch_ver}%{?rc_ver:-rc%{rc_ver}}/%{lld_srcdir}.tar.xz +Source1: https://github.com/llvm/llvm-project/releases/download/llvmorg-%{maj_ver}.%{min_ver}.%{patch_ver}%{?rc_ver:-rc%{rc_ver}}/%{lld_srcdir}.tar.xz.sig Source2: tstellar-gpg-key.asc Source3: run-lit-tests Source4: lit.lld-test.cfg.py @@ -34,9 +33,6 @@ Patch0: 0001-PATCH-lld-CMake-Check-for-gtest-headers-even-if-lit..patch # Bundle libunwind header need during build for MachO support Patch1: 0002-PATCH-lld-Import-compact_unwind_encoding.h-from-libu.patch -# Patches for LoongArch -Patch2: 0001-Support-LoongArch.patch - BuildRequires: gcc BuildRequires: gcc-c++ BuildRequires: cmake @@ -52,6 +48,9 @@ BuildRequires: python3-rpm-macros BuildRequires: python3-lit BuildRequires: llvm-googletest = %{version} +# For gpg source verification +BuildRequires: gnupg2 + %if %{with ld_alternative} Requires(post): %{_sbindir}/alternatives Requires(preun): %{_sbindir}/alternatives @@ -79,7 +78,20 @@ Summary: LLD shared libraries %description libs Shared libraries for LLD. +%if %{with testpkg} +%package test +Summary: LLD regression tests +Requires: %{name}%{?_isa} = %{version}-%{release} +Requires: python3-lit +Requires: llvm-test(major) = %{maj_ver} +Requires: lld-libs = %{version}-%{release} + +%description test +LLVM regression tests. +%endif + %prep +%{gpgverify} --keyring='%{SOURCE2}' --signature='%{SOURCE1}' --data='%{SOURCE0}' %autosetup -n %{lld_srcdir} -p2 @@ -110,11 +122,55 @@ cd %{_vpath_builddir} %cmake_build +%if %{with testpkg} +# Build the unittests so we can install them. +%cmake_build --target lld-test-depends +%endif + %install -# Install libraries and binaries -cd %{_target_platform} +%if %{with testpkg} +%global lit_cfg test/%{_arch}.site.cfg.py +%global lit_unit_cfg test/Unit/%{_arch}.site.cfg.py +%global lit_lld_test_cfg_install_path %{_datadir}/lld/lit.lld-test.cfg.py + +# Generate lit config files. Strip off the last line that initiates the +# test run, so we can customize the configuration. +head -n -1 %{__cmake_builddir}/test/lit.site.cfg.py >> %{lit_cfg} +head -n -1 %{__cmake_builddir}/test/Unit/lit.site.cfg.py >> %{lit_unit_cfg} + +# Patch lit config files to load custom config: +for f in %{lit_cfg} %{lit_unit_cfg}; do + echo "lit_config.load_config(config, '%{lit_lld_test_cfg_install_path}')" >> $f +done + +# Install test files +install -d %{buildroot}%{_datadir}/lld/src +cp %{SOURCE4} %{buildroot}%{_datadir}/lld/ + +# The various tar options are there to make sur the archive is the same on 32 and 64 bit arch, i.e. +# the archive creation is reproducible. Move arch-specific content out of the tarball +mv %{lit_cfg} %{buildroot}%{_datadir}/lld/src/%{_arch}.site.cfg.py +mv %{lit_unit_cfg} %{buildroot}%{_datadir}/lld/src/%{_arch}.Unit.site.cfg.py +tar --sort=name --mtime='UTC 2020-01-01' -c test/ | gzip -n > %{buildroot}%{_datadir}/lld/src/test.tar.gz + +install -d %{buildroot}%{_libexecdir}/tests/lld +install -m 0755 %{SOURCE3} %{buildroot}%{_libexecdir}/tests/lld +# Install unit test binaries +install -d %{buildroot}%{_libdir}/lld/ + +rm -rf `find %{buildroot}%{_libdir}/lld/ -iname '*make*'` + +# Install gtest libraries +cp %{__cmake_builddir}/%{_lib}/libgtest*so* %{buildroot}%{_libdir}/lld/ +%endif + +# Install libraries and binaries +pushd %{_vpath_builddir} %cmake_install +popd + + # This is generated by Patch1 during build and (probably) must be removed afterward rm %{buildroot}%{_includedir}/mach-o/compact_unwind_encoding.h @@ -133,13 +189,14 @@ fi %endif %check - cd %{_vpath_builddir} # armv7lhl tests disabled because of arm issue, see https://koji.fedoraproject.org/koji/taskinfo?taskID=33660162 %ifnarch %{arm} +%if %{with check} %cmake_build --target check-lld %endif +%endif %ldconfig_scriptlets libs @@ -151,8 +208,6 @@ cd %{_vpath_builddir} %{_bindir}/lld* %{_bindir}/ld.lld %{_bindir}/ld64.lld -%{_bindir}/ld64.lld.darwinnew -%{_bindir}/ld64.lld.darwinold %{_bindir}/wasm-ld %files devel @@ -163,9 +218,25 @@ cd %{_vpath_builddir} %files libs %{_libdir}/liblld*.so.* +%if %{with testpkg} +%files test +%{_libexecdir}/tests/lld/ +%{_libdir}/lld/ +%{_datadir}/lld/src/test.tar.gz +%{_datadir}/lld/src/%{_arch}.site.cfg.py +%{_datadir}/lld/src/%{_arch}.Unit.site.cfg.py +%{_datadir}/lld/lit.lld-test.cfg.py +%endif + %changelog -* Tue Nov 08 2022 chenli - 13.0.1-2.0.1 -- Support LoongArch +* Tue Jun 28 2022 Tom Stellard - 14.0.6-1 +- 14.0.6 Release + +* Fri May 06 2022 Timm Bäder - 14.0.0-2 +- Backport ignoring --no-add-needed + +* Thu Apr 07 2022 Timm Bäder - 14.0.0-1 +- Update to 14.0.0 * Thu Feb 03 2022 Tom Stellard - 13.0.1-1 - 13.0.1 Release