From c2c6c3baaa66ddb005a27824f861acbfa26fd8bd Mon Sep 17 00:00:00 2001 From: Ami-zhang Date: Mon, 18 Mar 2024 15:44:21 +0800 Subject: [PATCH] [Backport][LoongArch] Support `relax` feature --- ...e-R_LARCH_-ADD-SUB-6-relocation-type.patch | 78 +++ ...mplement-emit-relocs-with-relaxation.patch | 239 ++++++++ ...-lld-ELF-Support-relax-R_LARCH_ALIGN.patch | 563 ++++++++++++++++++ ...H_-ADD-SUB-_ULEB128-relocation-types.patch | 199 +++++++ lld.spec | 11 +- 5 files changed, 1088 insertions(+), 2 deletions(-) create mode 100644 0002-Backport-lld-LoongArch-Support-the-R_LARCH_-ADD-SUB-6-relocation-type.patch create mode 100644 0003-Backport-ELF-RISCV-Implement-emit-relocs-with-relaxation.patch create mode 100644 0004-Backport-lld-ELF-Support-relax-R_LARCH_ALIGN.patch create mode 100644 0005-Backport-lld-LoongArch-Support-the-R_LARCH_-ADD-SUB-_ULEB128-relocation-types.patch diff --git a/0002-Backport-lld-LoongArch-Support-the-R_LARCH_-ADD-SUB-6-relocation-type.patch b/0002-Backport-lld-LoongArch-Support-the-R_LARCH_-ADD-SUB-6-relocation-type.patch new file mode 100644 index 0000000..d467aa2 --- /dev/null +++ b/0002-Backport-lld-LoongArch-Support-the-R_LARCH_-ADD-SUB-6-relocation-type.patch @@ -0,0 +1,78 @@ +From 7f14e7c1b116fc865ddebb78e67816bfc5216178 Mon Sep 17 00:00:00 2001 +From: Jinyang He +Date: Wed, 15 Nov 2023 09:57:45 +0800 +Subject: [PATCH 01/14] [lld][LoongArch] Support the R_LARCH_{ADD,SUB}6 + relocation type (#72190) + +The R_LARCH_{ADD,SUB}6 relocation type are usually used by DwarfCFA to +calculate a tiny offset. They appear after binutils 2.41, with GAS +enabling relaxation by default. + +(cherry picked from commit 72accbfd0a1023b3182202276904120524ff9200) +Change-Id: Iad676e522f11c52e5dc381243f1df60edcef58f5 +--- + lld/ELF/Arch/LoongArch.cpp | 8 ++++++++ + lld/test/ELF/loongarch-add-sub.s | 6 +++++- + 2 files changed, 13 insertions(+), 1 deletion(-) + +diff --git a/lld/ELF/Arch/LoongArch.cpp b/lld/ELF/Arch/LoongArch.cpp +index 04ddb4682917..d3a538577a59 100644 +--- a/lld/ELF/Arch/LoongArch.cpp ++++ b/lld/ELF/Arch/LoongArch.cpp +@@ -444,10 +444,12 @@ RelExpr LoongArch::getRelExpr(const RelType type, const Symbol &s, + case R_LARCH_TLS_LE64_LO20: + case R_LARCH_TLS_LE64_HI12: + return R_TPREL; ++ case R_LARCH_ADD6: + case R_LARCH_ADD8: + case R_LARCH_ADD16: + case R_LARCH_ADD32: + case R_LARCH_ADD64: ++ case R_LARCH_SUB6: + case R_LARCH_SUB8: + case R_LARCH_SUB16: + case R_LARCH_SUB32: +@@ -650,6 +652,9 @@ void LoongArch::relocate(uint8_t *loc, const Relocation &rel, + write32le(loc, setK12(read32le(loc), extractBits(val, 63, 52))); + return; + ++ case R_LARCH_ADD6: ++ *loc = (*loc & 0xc0) | ((*loc + val) & 0x3f); ++ return; + case R_LARCH_ADD8: + *loc += val; + return; +@@ -662,6 +667,9 @@ void LoongArch::relocate(uint8_t *loc, const Relocation &rel, + case R_LARCH_ADD64: + write64le(loc, read64le(loc) + val); + return; ++ case R_LARCH_SUB6: ++ *loc = (*loc & 0xc0) | ((*loc - val) & 0x3f); ++ return; + case R_LARCH_SUB8: + *loc -= val; + return; +diff --git a/lld/test/ELF/loongarch-add-sub.s b/lld/test/ELF/loongarch-add-sub.s +index 63a3f7de179e..35f8a053d69c 100644 +--- a/lld/test/ELF/loongarch-add-sub.s ++++ b/lld/test/ELF/loongarch-add-sub.s +@@ -6,7 +6,7 @@ + # RUN: llvm-readelf -x .rodata %t.la64 | FileCheck --check-prefix=CHECK %s + # CHECK: section '.rodata': + # CHECK-NEXT: 0x9876543210 10325476 98badcfe 804602be 79ffffff +-# CHECK-NEXT: 0x9876543220 804602be 804680 ++# CHECK-NEXT: 0x9876543220 804602be 80468097 + + .text + .global _start +@@ -34,3 +34,7 @@ quux: + .byte 0 + .reloc quux, R_LARCH_ADD8, 1b + .reloc quux, R_LARCH_SUB8, 2b ++qux: ++ .byte 0b10000000 ++ .reloc qux, R_LARCH_ADD6, qux ++ .reloc qux, R_LARCH_SUB6, 2b +-- +2.20.1 + diff --git a/0003-Backport-ELF-RISCV-Implement-emit-relocs-with-relaxation.patch b/0003-Backport-ELF-RISCV-Implement-emit-relocs-with-relaxation.patch new file mode 100644 index 0000000..16ed874 --- /dev/null +++ b/0003-Backport-ELF-RISCV-Implement-emit-relocs-with-relaxation.patch @@ -0,0 +1,239 @@ +From d53182c7fcc371f575fd71fa74e28220db6e9b82 Mon Sep 17 00:00:00 2001 +From: Job Noorman +Date: Sat, 9 Sep 2023 10:24:16 +0200 +Subject: [PATCH 09/14] [ELF][RISCV] Implement --emit-relocs with relaxation + +Linker relaxation may change relocations (offsets and types). However, +when --emit-relocs is used, relocations are simply copied from the input +section causing a mismatch with the corresponding (relaxed) code +section. + +This patch fixes this as follows: for non-relocatable RISC-V binaries, +`InputSection::copyRelocations` reads relocations from the relocated +section's `relocations` array (since this gets updated by the relaxation +code). For all other cases, relocations are read from the input section +directly as before. + +In order to reuse as much code as possible, and to keep the diff small, +the original `InputSection::copyRelocations` is changed to accept the +relocations as a range of `Relocation` objects. This means that, in the +general case when reading from the input section, raw relocations need +to be converted to `Relocation`s first, which introduces quite a bit of +boiler plate. It also means there's a slight code size increase due to +the extra instantiations of `copyRelocations` (for both range types). + +Reviewed By: MaskRay + +Differential Revision: https://reviews.llvm.org/D159082 + +(cherry picked from commit 649cac3b627fa3d466b8807536c8be970cc8c32f) +Change-Id: I53aeeeed4bea0d74c5571bc90405bcbd363781b2 +--- + lld/ELF/InputSection.cpp | 56 ++++++++++++++++----- + lld/ELF/InputSection.h | 6 ++- + lld/test/ELF/riscv-relax-emit-relocs.s | 69 ++++++++++++++++++++++++++ + 3 files changed, 117 insertions(+), 14 deletions(-) + create mode 100644 lld/test/ELF/riscv-relax-emit-relocs.s + +diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp +index 2edaa2b40493..1aff6b968d86 100644 +--- a/lld/ELF/InputSection.cpp ++++ b/lld/ELF/InputSection.cpp +@@ -349,29 +349,61 @@ InputSectionBase *InputSection::getRelocatedSection() const { + return sections[info]; + } + ++template ++void InputSection::copyRelocations(uint8_t *buf) { ++ if (config->relax && !config->relocatable && config->emachine == EM_RISCV) { ++ // On RISC-V, relaxation might change relocations: copy from ++ // internal ones that are updated by relaxation. ++ InputSectionBase *sec = getRelocatedSection(); ++ copyRelocations(buf, llvm::make_range(sec->relocations.begin(), ++ sec->relocations.end())); ++ } else { ++ // Convert the raw relocations in the input section into Relocation objects ++ // suitable to be used by copyRelocations below. ++ struct MapRel { ++ const ObjFile &file; ++ Relocation operator()(const RelTy &rel) const { ++ // RelExpr is not used so set to a dummy value. ++ return Relocation{R_NONE, rel.getType(config->isMips64EL), rel.r_offset, ++ getAddend(rel), &file.getRelocTargetSym(rel)}; ++ } ++ }; ++ ++ using RawRels = ArrayRef; ++ using MapRelIter = ++ llvm::mapped_iterator; ++ auto mapRel = MapRel{*getFile()}; ++ RawRels rawRels = getDataAs(); ++ auto rels = llvm::make_range(MapRelIter(rawRels.begin(), mapRel), ++ MapRelIter(rawRels.end(), mapRel)); ++ copyRelocations(buf, rels); ++ } ++} ++ + // This is used for -r and --emit-relocs. We can't use memcpy to copy + // relocations because we need to update symbol table offset and section index + // for each relocation. So we copy relocations one by one. +-template +-void InputSection::copyRelocations(uint8_t *buf, ArrayRef rels) { ++template ++void InputSection::copyRelocations(uint8_t *buf, ++ llvm::iterator_range rels) { + const TargetInfo &target = *elf::target; + InputSectionBase *sec = getRelocatedSection(); + (void)sec->contentMaybeDecompress(); // uncompress if needed + +- for (const RelTy &rel : rels) { +- RelType type = rel.getType(config->isMips64EL); ++ for (const Relocation &rel : rels) { ++ RelType type = rel.type; + const ObjFile *file = getFile(); +- Symbol &sym = file->getRelocTargetSym(rel); ++ Symbol &sym = *rel.sym; + + auto *p = reinterpret_cast(buf); + buf += sizeof(RelTy); + + if (RelTy::IsRela) +- p->r_addend = getAddend(rel); ++ p->r_addend = rel.addend; + + // Output section VA is zero for -r, so r_offset is an offset within the + // section, but for --emit-relocs it is a virtual address. +- p->r_offset = sec->getVA(rel.r_offset); ++ p->r_offset = sec->getVA(rel.offset); + p->setSymbolAndType(in.symTab->getSymbolIndex(&sym), type, + config->isMips64EL); + +@@ -408,8 +440,8 @@ void InputSection::copyRelocations(uint8_t *buf, ArrayRef rels) { + continue; + } + +- int64_t addend = getAddend(rel); +- const uint8_t *bufLoc = sec->content().begin() + rel.r_offset; ++ int64_t addend = rel.addend; ++ const uint8_t *bufLoc = sec->content().begin() + rel.offset; + if (!RelTy::IsRela) + addend = target.getImplicitAddend(bufLoc, type); + +@@ -432,7 +464,7 @@ void InputSection::copyRelocations(uint8_t *buf, ArrayRef rels) { + if (RelTy::IsRela) + p->r_addend = sym.getVA(addend) - section->getOutputSection()->addr; + else if (config->relocatable && type != target.noneRel) +- sec->addReloc({R_ABS, type, rel.r_offset, addend, &sym}); ++ sec->addReloc({R_ABS, type, rel.offset, addend, &sym}); + } else if (config->emachine == EM_PPC && type == R_PPC_PLTREL24 && + p->r_addend >= 0x8000 && sec->file->ppc32Got2) { + // Similar to R_MIPS_GPREL{16,32}. If the addend of R_PPC_PLTREL24 +@@ -1106,11 +1138,11 @@ template void InputSection::writeTo(uint8_t *buf) { + // If -r or --emit-relocs is given, then an InputSection + // may be a relocation section. + if (LLVM_UNLIKELY(type == SHT_RELA)) { +- copyRelocations(buf, getDataAs()); ++ copyRelocations(buf); + return; + } + if (LLVM_UNLIKELY(type == SHT_REL)) { +- copyRelocations(buf, getDataAs()); ++ copyRelocations(buf); + return; + } + +diff --git a/lld/ELF/InputSection.h b/lld/ELF/InputSection.h +index 15122d6abd6b..2b91711abba3 100644 +--- a/lld/ELF/InputSection.h ++++ b/lld/ELF/InputSection.h +@@ -396,8 +396,10 @@ public: + static InputSection discarded; + + private: +- template +- void copyRelocations(uint8_t *buf, llvm::ArrayRef rels); ++ template void copyRelocations(uint8_t *buf); ++ ++ template ++ void copyRelocations(uint8_t *buf, llvm::iterator_range rels); + + template void copyShtGroup(uint8_t *buf); + }; +diff --git a/lld/test/ELF/riscv-relax-emit-relocs.s b/lld/test/ELF/riscv-relax-emit-relocs.s +new file mode 100644 +index 000000000000..ebd69b742d4f +--- /dev/null ++++ b/lld/test/ELF/riscv-relax-emit-relocs.s +@@ -0,0 +1,69 @@ ++# REQUIRES: riscv ++## Test that we can handle --emit-relocs while relaxing. ++ ++# RUN: rm -rf %t && mkdir %t && cd %t ++ ++# RUN: llvm-mc -filetype=obj -triple=riscv32 -mattr=+relax %s -o 32.o ++# RUN: ld.lld -Ttext=0x10000 --emit-relocs 32.o -o 32 ++# RUN: llvm-objdump -dr --no-show-raw-insn -M no-aliases 32 | FileCheck %s ++ ++# RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+relax %s -o 64.o ++# RUN: ld.lld -Ttext=0x10000 --emit-relocs 64.o -o 64 ++# RUN: llvm-objdump -dr --no-show-raw-insn -M no-aliases 64 | FileCheck %s ++ ++## -r should keep original relocations. ++# RUN: ld.lld -r 64.o -o 64.r ++# RUN: llvm-objdump -dr --no-show-raw-insn -M no-aliases 64.r | FileCheck %s --check-prefix=CHECKR ++ ++## --no-relax should keep original relocations. ++# RUN: ld.lld --emit-relocs --no-relax 64.o -o 64.norelax ++# RUN: llvm-objdump -dr --no-show-raw-insn -M no-aliases 64.norelax | FileCheck %s --check-prefix=CHECKNORELAX ++ ++# CHECK: <_start>: ++# CHECK-NEXT: jal ra, 0x10008 ++# CHECK-NEXT: R_RISCV_JAL f ++# CHECK-NEXT: R_RISCV_RELAX *ABS* ++# CHECK-NEXT: jal ra, 0x10008 ++# CHECK-NEXT: R_RISCV_JAL f ++# CHECK-NEXT: R_RISCV_RELAX *ABS* ++# CHECK-EMPTY: ++# CHECK-NEXT: : ++# CHECK-NEXT: jalr zero, 0(ra) ++# CHECK-NEXT: R_RISCV_ALIGN *ABS*+0x4 ++ ++# CHECKR: <_start>: ++# CHECKR-NEXT: auipc ra, 0 ++# CHECKR-NEXT: R_RISCV_CALL_PLT f ++# CHECKR-NEXT: R_RISCV_RELAX *ABS* ++# CHECKR-NEXT: jalr ra, 0(ra) ++# CHECKR-NEXT: auipc ra, 0 ++# CHECKR-NEXT: R_RISCV_CALL_PLT f ++# CHECKR-NEXT: R_RISCV_RELAX *ABS* ++# CHECKR-NEXT: jalr ra, 0(ra) ++# CHECKR-NEXT: addi zero, zero, 0 ++# CHECKR-NEXT: R_RISCV_ALIGN *ABS*+0x4 ++# CHECKR-EMPTY: ++# CHECKR-NEXT: : ++# CHECKR-NEXT: jalr zero, 0(ra) ++ ++# CHECKNORELAX: <_start>: ++# CHECKNORELAX-NEXT: auipc ra, 0 ++# CHECKNORELAX-NEXT: R_RISCV_CALL_PLT f ++# CHECKNORELAX-NEXT: R_RISCV_RELAX *ABS* ++# CHECKNORELAX-NEXT: jalr ra, 16(ra) ++# CHECKNORELAX-NEXT: auipc ra, 0 ++# CHECKNORELAX-NEXT: R_RISCV_CALL_PLT f ++# CHECKNORELAX-NEXT: R_RISCV_RELAX *ABS* ++# CHECKNORELAX-NEXT: jalr ra, 8(ra) ++# CHECKNORELAX-EMPTY: ++# CHECKNORELAX-NEXT: : ++# CHECKNORELAX-NEXT: jalr zero, 0(ra) ++# CHECKNORELAX-NEXT: R_RISCV_ALIGN *ABS*+0x4 ++ ++.global _start ++_start: ++ call f ++ call f ++ .balign 8 ++f: ++ ret +-- +2.20.1 + diff --git a/0004-Backport-lld-ELF-Support-relax-R_LARCH_ALIGN.patch b/0004-Backport-lld-ELF-Support-relax-R_LARCH_ALIGN.patch new file mode 100644 index 0000000..604fadf --- /dev/null +++ b/0004-Backport-lld-ELF-Support-relax-R_LARCH_ALIGN.patch @@ -0,0 +1,563 @@ +From 80c56e85d742bb88533e4789c76ae2b55dc36835 Mon Sep 17 00:00:00 2001 +From: Jinyang He +Date: Tue, 6 Feb 2024 09:09:13 +0800 +Subject: [PATCH 10/14] [lld][ELF] Support relax R_LARCH_ALIGN (#78692) + +Refer to commit 6611d58f5bbc ("Relax R_RISCV_ALIGN"), we can relax +R_LARCH_ALIGN by same way. Reuse `SymbolAnchor`, `RISCVRelaxAux` and +`initSymbolAnchors` to simplify codes. As `riscvFinalizeRelax` is an +arch-specific function, put it override on `TargetInfo::finalizeRelax`, +so that LoongArch can override it, too. + +The flow of relax R_LARCH_ALIGN is almost consistent with RISCV. The +difference is that LoongArch only has 4-bytes NOP and all executable +insn is 4-bytes aligned. So LoongArch not need rewrite NOP sequence. +Alignment maxBytesEmit parameter is supported in psABI v2.30. + +(cherry picked from commit 06a728f3feab876f9195738b5774e82dadc0f3a7) +(cherry picked from commit 60a8ec3a35c722a9eb8298c215321b89d0faf5b5) +Change-Id: I680e9a44f05fb2cc820736eee63ddd999e689daf +--- + lld/ELF/Arch/LoongArch.cpp | 156 ++++++++++++++++++++- + lld/ELF/Arch/RISCV.cpp | 28 +--- + lld/ELF/InputSection.cpp | 5 +- + lld/ELF/InputSection.h | 24 +++- + lld/ELF/Target.h | 3 + + lld/ELF/Writer.cpp | 4 +- + lld/test/ELF/loongarch-relax-align.s | 126 +++++++++++++++++ + lld/test/ELF/loongarch-relax-emit-relocs.s | 49 +++++++ + 8 files changed, 362 insertions(+), 33 deletions(-) + create mode 100644 lld/test/ELF/loongarch-relax-align.s + create mode 100644 lld/test/ELF/loongarch-relax-emit-relocs.s + +diff --git a/lld/ELF/Arch/LoongArch.cpp b/lld/ELF/Arch/LoongArch.cpp +index d3a538577a59..3f57a76873f9 100644 +--- a/lld/ELF/Arch/LoongArch.cpp ++++ b/lld/ELF/Arch/LoongArch.cpp +@@ -36,6 +36,8 @@ public: + bool usesOnlyLowPageBits(RelType type) const override; + void relocate(uint8_t *loc, const Relocation &rel, + uint64_t val) const override; ++ bool relaxOnce(int pass) const override; ++ void finalizeRelax(int passes) const override; + }; + } // end anonymous namespace + +@@ -521,8 +523,9 @@ RelExpr LoongArch::getRelExpr(const RelType type, const Symbol &s, + case R_LARCH_TLS_GD_HI20: + return R_TLSGD_GOT; + case R_LARCH_RELAX: +- // LoongArch linker relaxation is not implemented yet. +- return R_NONE; ++ return config->relax ? R_RELAX_HINT : R_NONE; ++ case R_LARCH_ALIGN: ++ return R_RELAX_HINT; + + // Other known relocs that are explicitly unimplemented: + // +@@ -696,6 +699,155 @@ void LoongArch::relocate(uint8_t *loc, const Relocation &rel, + } + } + ++static bool relax(InputSection &sec) { ++ const uint64_t secAddr = sec.getVA(); ++ const MutableArrayRef relocs = sec.relocs(); ++ auto &aux = *sec.relaxAux; ++ bool changed = false; ++ ArrayRef sa = ArrayRef(aux.anchors); ++ uint64_t delta = 0; ++ ++ std::fill_n(aux.relocTypes.get(), relocs.size(), R_LARCH_NONE); ++ aux.writes.clear(); ++ for (auto [i, r] : llvm::enumerate(relocs)) { ++ const uint64_t loc = secAddr + r.offset - delta; ++ uint32_t &cur = aux.relocDeltas[i], remove = 0; ++ switch (r.type) { ++ case R_LARCH_ALIGN: { ++ const uint64_t addend = ++ r.sym->isUndefined() ? Log2_64(r.addend) + 1 : r.addend; ++ const uint64_t allBytes = (1 << (addend & 0xff)) - 4; ++ const uint64_t align = 1 << (addend & 0xff); ++ const uint64_t maxBytes = addend >> 8; ++ const uint64_t off = loc & (align - 1); ++ const uint64_t curBytes = off == 0 ? 0 : align - off; ++ // All bytes beyond the alignment boundary should be removed. ++ // If emit bytes more than max bytes to emit, remove all. ++ if (maxBytes != 0 && curBytes > maxBytes) ++ remove = allBytes; ++ else ++ remove = allBytes - curBytes; ++ // If we can't satisfy this alignment, we've found a bad input. ++ if (LLVM_UNLIKELY(static_cast(remove) < 0)) { ++ errorOrWarn(getErrorLocation((const uint8_t *)loc) + ++ "insufficient padding bytes for " + lld::toString(r.type) + ++ ": " + Twine(allBytes) + " bytes available for " + ++ "requested alignment of " + Twine(align) + " bytes"); ++ remove = 0; ++ } ++ break; ++ } ++ } ++ ++ // For all anchors whose offsets are <= r.offset, they are preceded by ++ // the previous relocation whose `relocDeltas` value equals `delta`. ++ // Decrease their st_value and update their st_size. ++ for (; sa.size() && sa[0].offset <= r.offset; sa = sa.slice(1)) { ++ if (sa[0].end) ++ sa[0].d->size = sa[0].offset - delta - sa[0].d->value; ++ else ++ sa[0].d->value = sa[0].offset - delta; ++ } ++ delta += remove; ++ if (delta != cur) { ++ cur = delta; ++ changed = true; ++ } ++ } ++ ++ for (const SymbolAnchor &a : sa) { ++ if (a.end) ++ a.d->size = a.offset - delta - a.d->value; ++ else ++ a.d->value = a.offset - delta; ++ } ++ // Inform assignAddresses that the size has changed. ++ if (!isUInt<32>(delta)) ++ fatal("section size decrease is too large: " + Twine(delta)); ++ sec.bytesDropped = delta; ++ return changed; ++} ++ ++// When relaxing just R_LARCH_ALIGN, relocDeltas is usually changed only once in ++// the absence of a linker script. For call and load/store R_LARCH_RELAX, code ++// shrinkage may reduce displacement and make more relocations eligible for ++// relaxation. Code shrinkage may increase displacement to a call/load/store ++// target at a higher fixed address, invalidating an earlier relaxation. Any ++// change in section sizes can have cascading effect and require another ++// relaxation pass. ++bool LoongArch::relaxOnce(int pass) const { ++ if (config->relocatable) ++ return false; ++ ++ if (pass == 0) ++ initSymbolAnchors(); ++ ++ SmallVector storage; ++ bool changed = false; ++ for (OutputSection *osec : outputSections) { ++ if (!(osec->flags & SHF_EXECINSTR)) ++ continue; ++ for (InputSection *sec : getInputSections(*osec, storage)) ++ changed |= relax(*sec); ++ } ++ return changed; ++} ++ ++void LoongArch::finalizeRelax(int passes) const { ++ log("relaxation passes: " + Twine(passes)); ++ SmallVector storage; ++ for (OutputSection *osec : outputSections) { ++ if (!(osec->flags & SHF_EXECINSTR)) ++ continue; ++ for (InputSection *sec : getInputSections(*osec, storage)) { ++ RelaxAux &aux = *sec->relaxAux; ++ if (!aux.relocDeltas) ++ continue; ++ ++ MutableArrayRef rels = sec->relocs(); ++ ArrayRef old = sec->content(); ++ size_t newSize = old.size() - aux.relocDeltas[rels.size() - 1]; ++ uint8_t *p = context().bAlloc.Allocate(newSize); ++ uint64_t offset = 0; ++ int64_t delta = 0; ++ sec->content_ = p; ++ sec->size = newSize; ++ sec->bytesDropped = 0; ++ ++ // Update section content: remove NOPs for R_LARCH_ALIGN and rewrite ++ // instructions for relaxed relocations. ++ for (size_t i = 0, e = rels.size(); i != e; ++i) { ++ uint32_t remove = aux.relocDeltas[i] - delta; ++ delta = aux.relocDeltas[i]; ++ if (remove == 0 && aux.relocTypes[i] == R_LARCH_NONE) ++ continue; ++ ++ // Copy from last location to the current relocated location. ++ const Relocation &r = rels[i]; ++ uint64_t size = r.offset - offset; ++ memcpy(p, old.data() + offset, size); ++ p += size; ++ offset = r.offset + remove; ++ } ++ memcpy(p, old.data() + offset, old.size() - offset); ++ ++ // Subtract the previous relocDeltas value from the relocation offset. ++ // For a pair of R_LARCH_XXX/R_LARCH_RELAX with the same offset, decrease ++ // their r_offset by the same delta. ++ delta = 0; ++ for (size_t i = 0, e = rels.size(); i != e;) { ++ uint64_t cur = rels[i].offset; ++ do { ++ rels[i].offset -= delta; ++ if (aux.relocTypes[i] != R_LARCH_NONE) ++ rels[i].type = aux.relocTypes[i]; ++ } while (++i != e && rels[i].offset == cur); ++ delta = aux.relocDeltas[i - 1]; ++ } ++ } ++ } ++} ++ + TargetInfo *elf::getLoongArchTargetInfo() { + static LoongArch target; + return ⌖ +diff --git a/lld/ELF/Arch/RISCV.cpp b/lld/ELF/Arch/RISCV.cpp +index d0d75118e30d..06120cabc132 100644 +--- a/lld/ELF/Arch/RISCV.cpp ++++ b/lld/ELF/Arch/RISCV.cpp +@@ -44,6 +44,7 @@ public: + void relocate(uint8_t *loc, const Relocation &rel, + uint64_t val) const override; + bool relaxOnce(int pass) const override; ++ void finalizeRelax(int passes) const override; + }; + + } // end anonymous namespace +@@ -513,33 +514,14 @@ void RISCV::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const { + } + } + +-namespace { +-struct SymbolAnchor { +- uint64_t offset; +- Defined *d; +- bool end; // true for the anchor of st_value+st_size +-}; +-} // namespace +- +-struct elf::RISCVRelaxAux { +- // This records symbol start and end offsets which will be adjusted according +- // to the nearest relocDeltas element. +- SmallVector anchors; +- // For relocations[i], the actual offset is r_offset - (i ? relocDeltas[i-1] : +- // 0). +- std::unique_ptr relocDeltas; +- // For relocations[i], the actual type is relocTypes[i]. +- std::unique_ptr relocTypes; +- SmallVector writes; +-}; + +-static void initSymbolAnchors() { ++void elf::initSymbolAnchors() { + SmallVector storage; + for (OutputSection *osec : outputSections) { + if (!(osec->flags & SHF_EXECINSTR)) + continue; + for (InputSection *sec : getInputSections(*osec, storage)) { +- sec->relaxAux = make(); ++ sec->relaxAux = make(); + if (sec->relocs().size()) { + sec->relaxAux->relocDeltas = + std::make_unique(sec->relocs().size()); +@@ -766,7 +748,7 @@ bool RISCV::relaxOnce(int pass) const { + return changed; + } + +-void elf::riscvFinalizeRelax(int passes) { ++void RISCV::finalizeRelax(int passes) const { + llvm::TimeTraceScope timeScope("Finalize RISC-V relaxation"); + log("relaxation passes: " + Twine(passes)); + SmallVector storage; +@@ -774,7 +756,7 @@ void elf::riscvFinalizeRelax(int passes) { + if (!(osec->flags & SHF_EXECINSTR)) + continue; + for (InputSection *sec : getInputSections(*osec, storage)) { +- RISCVRelaxAux &aux = *sec->relaxAux; ++ RelaxAux &aux = *sec->relaxAux; + if (!aux.relocDeltas) + continue; + +diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp +index 1aff6b968d86..b178d82407e3 100644 +--- a/lld/ELF/InputSection.cpp ++++ b/lld/ELF/InputSection.cpp +@@ -351,8 +351,9 @@ InputSectionBase *InputSection::getRelocatedSection() const { + + template + void InputSection::copyRelocations(uint8_t *buf) { +- if (config->relax && !config->relocatable && config->emachine == EM_RISCV) { +- // On RISC-V, relaxation might change relocations: copy from ++ if (config->relax && !config->relocatable && ++ (config->emachine == EM_RISCV || config->emachine == EM_LOONGARCH)) { ++ // On LoongArch and RISC-V, relaxation might change relocations: copy from + // internal ones that are updated by relaxation. + InputSectionBase *sec = getRelocatedSection(); + copyRelocations(buf, llvm::make_range(sec->relocations.begin(), +diff --git a/lld/ELF/InputSection.h b/lld/ELF/InputSection.h +index 2b91711abba3..842bc369909d 100644 +--- a/lld/ELF/InputSection.h ++++ b/lld/ELF/InputSection.h +@@ -101,7 +101,23 @@ protected: + link(link), info(info) {} + }; + +-struct RISCVRelaxAux; ++struct SymbolAnchor { ++ uint64_t offset; ++ Defined *d; ++ bool end; // true for the anchor of st_value+st_size ++}; ++ ++struct RelaxAux { ++ // This records symbol start and end offsets which will be adjusted according ++ // to the nearest relocDeltas element. ++ SmallVector anchors; ++ // For relocations[i], the actual offset is ++ // r_offset - (i ? relocDeltas[i-1] : 0). ++ std::unique_ptr relocDeltas; ++ // For relocations[i], the actual type is relocTypes[i]. ++ std::unique_ptr relocTypes; ++ SmallVector writes; ++}; + + // This corresponds to a section of an input file. + class InputSectionBase : public SectionBase { +@@ -222,9 +238,9 @@ public: + // basic blocks. + JumpInstrMod *jumpInstrMod = nullptr; + +- // Auxiliary information for RISC-V linker relaxation. RISC-V does not use +- // jumpInstrMod. +- RISCVRelaxAux *relaxAux; ++ // Auxiliary information for RISC-V and LoongArch linker relaxation. ++ // They do not use jumpInstrMod. ++ RelaxAux *relaxAux; + + // The compressed content size when `compressed` is true. + size_t compressedSize; +diff --git a/lld/ELF/Target.h b/lld/ELF/Target.h +index 47dbe6b4d1c6..bf831afa1793 100644 +--- a/lld/ELF/Target.h ++++ b/lld/ELF/Target.h +@@ -94,6 +94,8 @@ public: + + // Do a linker relaxation pass and return true if we changed something. + virtual bool relaxOnce(int pass) const { return false; } ++ // Do finalize relaxation after collecting relaxation infos. ++ virtual void finalizeRelax(int passes) const {} + + virtual void applyJumpInstrMod(uint8_t *loc, JumpModType type, + JumpModType val) const {} +@@ -234,6 +236,7 @@ void addArmInputSectionMappingSymbols(); + void addArmSyntheticSectionMappingSymbol(Defined *); + void sortArmMappingSymbols(); + void convertArmInstructionstoBE8(InputSection *sec, uint8_t *buf); ++void initSymbolAnchors(); + + LLVM_LIBRARY_VISIBILITY extern const TargetInfo *target; + TargetInfo *getTarget(); +diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp +index 368c9aabceae..dd37bbbf76c1 100644 +--- a/lld/ELF/Writer.cpp ++++ b/lld/ELF/Writer.cpp +@@ -1668,8 +1668,8 @@ template void Writer::finalizeAddressDependentContent() { + } + } + } +- if (!config->relocatable && config->emachine == EM_RISCV) +- riscvFinalizeRelax(pass); ++ if (!config->relocatable) ++ target->finalizeRelax(pass); + + if (config->relocatable) + for (OutputSection *sec : outputSections) +diff --git a/lld/test/ELF/loongarch-relax-align.s b/lld/test/ELF/loongarch-relax-align.s +new file mode 100644 +index 000000000000..ab61e15d5cac +--- /dev/null ++++ b/lld/test/ELF/loongarch-relax-align.s +@@ -0,0 +1,126 @@ ++# REQUIRES: loongarch ++ ++# RUN: llvm-mc --filetype=obj --triple=loongarch32 --mattr=+relax %s -o %t.32.o ++# RUN: llvm-mc --filetype=obj --triple=loongarch64 --mattr=+relax %s -o %t.64.o ++# RUN: ld.lld --section-start=.text=0x10000 --section-start=.text2=0x20000 -e 0 %t.32.o -o %t.32 ++# RUN: ld.lld --section-start=.text=0x10000 --section-start=.text2=0x20000 -e 0 %t.64.o -o %t.64 ++# RUN: ld.lld --section-start=.text=0x10000 --section-start=.text2=0x20000 -e 0 %t.32.o --no-relax -o %t.32n ++# RUN: ld.lld --section-start=.text=0x10000 --section-start=.text2=0x20000 -e 0 %t.64.o --no-relax -o %t.64n ++# RUN: llvm-objdump -td --no-show-raw-insn %t.32 | FileCheck %s ++# RUN: llvm-objdump -td --no-show-raw-insn %t.64 | FileCheck %s ++# RUN: llvm-objdump -td --no-show-raw-insn %t.32n | FileCheck %s ++# RUN: llvm-objdump -td --no-show-raw-insn %t.64n | FileCheck %s ++ ++## Test the R_LARCH_ALIGN without symbol index. ++# RUN: llvm-mc --filetype=obj --triple=loongarch64 --mattr=+relax %s -o %t.o64.o --defsym=old=1 ++# RUN: ld.lld --section-start=.text=0x10000 --section-start=.text2=0x20000 -e 0 %t.o64.o -o %t.o64 ++# RUN: ld.lld --section-start=.text=0x10000 --section-start=.text2=0x20000 -e 0 %t.o64.o --no-relax -o %t.o64n ++# RUN: llvm-objdump -td --no-show-raw-insn %t.o64 | FileCheck %s ++# RUN: llvm-objdump -td --no-show-raw-insn %t.o64n | FileCheck %s ++ ++## -r keeps section contents unchanged. ++# RUN: ld.lld -r %t.64.o -o %t.64.r ++# RUN: llvm-objdump -dr --no-show-raw-insn %t.64.r | FileCheck %s --check-prefix=CHECKR ++ ++# CHECK-DAG: {{0*}}10000 l .text {{0*}}44 .Ltext_start ++# CHECK-DAG: {{0*}}10038 l .text {{0*}}0c .L1 ++# CHECK-DAG: {{0*}}10040 l .text {{0*}}04 .L2 ++# CHECK-DAG: {{0*}}20000 l .text2 {{0*}}14 .Ltext2_start ++ ++# CHECK: <.Ltext_start>: ++# CHECK-NEXT: break 1 ++# CHECK-NEXT: break 2 ++# CHECK-NEXT: nop ++# CHECK-NEXT: nop ++# CHECK-NEXT: break 3 ++# CHECK-NEXT: break 4 ++# CHECK-NEXT: nop ++# CHECK-NEXT: nop ++# CHECK-NEXT: pcalau12i $a0, 0 ++# CHECK-NEXT: addi.{{[dw]}} $a0, $a0, 0 ++# CHECK-NEXT: pcalau12i $a0, 0 ++# CHECK-NEXT: addi.{{[dw]}} $a0, $a0, 56 ++# CHECK-NEXT: pcalau12i $a0, 0 ++# CHECK-NEXT: addi.{{[dw]}} $a0, $a0, 64 ++# CHECK-EMPTY: ++# CHECK-NEXT: <.L1>: ++# CHECK-NEXT: nop ++# CHECK-NEXT: nop ++# CHECK-EMPTY: ++# CHECK-NEXT: <.L2>: ++# CHECK-NEXT: break 5 ++ ++# CHECK: <.Ltext2_start>: ++# CHECK-NEXT: pcalau12i $a0, 0 ++# CHECK-NEXT: addi.{{[dw]}} $a0, $a0, 0 ++# CHECK-NEXT: nop ++# CHECK-NEXT: nop ++# CHECK-NEXT: break 6 ++ ++# CHECKR: <.Ltext2_start>: ++# CHECKR-NEXT: pcalau12i $a0, 0 ++# CHECKR-NEXT: {{0*}}00: R_LARCH_PCALA_HI20 .Ltext2_start ++# CHECKR-NEXT: {{0*}}00: R_LARCH_RELAX *ABS* ++# CHECKR-NEXT: addi.d $a0, $a0, 0 ++# CHECKR-NEXT: {{0*}}04: R_LARCH_PCALA_LO12 .Ltext2_start ++# CHECKR-NEXT: {{0*}}04: R_LARCH_RELAX *ABS* ++# CHECKR-NEXT: nop ++# CHECKR-NEXT: {{0*}}08: R_LARCH_ALIGN .Lalign_symbol+0x4 ++# CHECKR-NEXT: nop ++# CHECKR-NEXT: nop ++# CHECKR-NEXT: break 6 ++ ++.macro .fake_p2align_4 max=0 ++ .ifdef old ++ .if \max==0 ++ .reloc ., R_LARCH_ALIGN, 0xc ++ nop; nop; nop ++ .endif ++ .else ++ .reloc ., R_LARCH_ALIGN, .Lalign_symbol + 0x4 + (\max << 8) ++ nop; nop; nop ++ .endif ++.endm ++ ++ .text ++.Lalign_symbol: ++.Ltext_start: ++ break 1 ++ break 2 ++## +0x8: Emit 2 nops, delete 1 nop. ++ .fake_p2align_4 ++ ++ break 3 ++## +0x14: Emit 3 nops > 8 bytes, not emit. ++ .fake_p2align_4 8 ++ ++ break 4 ++ .fake_p2align_4 8 ++## +0x18: Emit 2 nops <= 8 bytes. ++ ++## Compensate ++.ifdef old ++ nop; nop ++.endif ++ ++## +0x20: Test symbol value and symbol size can be handled. ++ la.pcrel $a0, .Ltext_start ++ la.pcrel $a0, .L1 ++ la.pcrel $a0, .L2 ++ ++## +0x38: Emit 2 nops, delete 1 nop. ++.L1: ++ .fake_p2align_4 ++.L2: ++ break 5 ++ .size .L1, . - .L1 ++ .size .L2, . - .L2 ++ .size .Ltext_start, . - .Ltext_start ++ ++## Test another text section. ++ .section .text2,"ax",@progbits ++.Ltext2_start: ++ la.pcrel $a0, .Ltext2_start ++ .fake_p2align_4 ++ break 6 ++ .size .Ltext2_start, . - .Ltext2_start +diff --git a/lld/test/ELF/loongarch-relax-emit-relocs.s b/lld/test/ELF/loongarch-relax-emit-relocs.s +new file mode 100644 +index 000000000000..581fce8c95ca +--- /dev/null ++++ b/lld/test/ELF/loongarch-relax-emit-relocs.s +@@ -0,0 +1,49 @@ ++# REQUIRES: loongarch ++## Test that we can handle --emit-relocs while relaxing. ++ ++# RUN: llvm-mc --filetype=obj --triple=loongarch32 --mattr=+relax %s -o %t.32.o ++# RUN: llvm-mc --filetype=obj --triple=loongarch64 --mattr=+relax %s -o %t.64.o ++# RUN: ld.lld -Ttext=0x10000 --emit-relocs %t.32.o -o %t.32 ++# RUN: ld.lld -Ttext=0x10000 --emit-relocs %t.64.o -o %t.64 ++# RUN: llvm-objdump -dr %t.32 | FileCheck %s ++# RUN: llvm-objdump -dr %t.64 | FileCheck %s ++ ++## -r should keep original relocations. ++# RUN: ld.lld -r %t.64.o -o %t.64.r ++# RUN: llvm-objdump -dr %t.64.r | FileCheck %s --check-prefix=CHECKR ++ ++## --no-relax should keep original relocations. ++## TODO Due to R_LARCH_RELAX is not relaxed, it plays same as --relax now. ++# RUN: ld.lld -Ttext=0x10000 --emit-relocs --no-relax %t.64.o -o %t.64.norelax ++# RUN: llvm-objdump -dr %t.64.norelax | FileCheck %s ++ ++# CHECK: 00010000 <_start>: ++# CHECK-NEXT: pcalau12i $a0, 0 ++# CHECK-NEXT: R_LARCH_PCALA_HI20 _start ++# CHECK-NEXT: R_LARCH_RELAX *ABS* ++# CHECK-NEXT: addi.{{[dw]}} $a0, $a0, 0 ++# CHECK-NEXT: R_LARCH_PCALA_LO12 _start ++# CHECK-NEXT: R_LARCH_RELAX *ABS* ++# CHECK-NEXT: nop ++# CHECK-NEXT: R_LARCH_ALIGN .Lla-relax-align0+0x4 ++# CHECK-NEXT: nop ++# CHECK-NEXT: ret ++ ++# CHECKR: <_start>: ++# CHECKR-NEXT: pcalau12i $a0, 0 ++# CHECKR-NEXT: R_LARCH_PCALA_HI20 _start ++# CHECKR-NEXT: R_LARCH_RELAX *ABS* ++# CHECKR-NEXT: addi.d $a0, $a0, 0 ++# CHECKR-NEXT: R_LARCH_PCALA_LO12 _start ++# CHECKR-NEXT: R_LARCH_RELAX *ABS* ++# CHECKR-NEXT: nop ++# CHECKR-NEXT: R_LARCH_ALIGN .Lla-relax-align0+0x4 ++# CHECKR-NEXT: nop ++# CHECKR-NEXT: nop ++# CHECKR-NEXT: ret ++ ++.global _start ++_start: ++ la.pcrel $a0, _start ++ .p2align 4 ++ ret +-- +2.20.1 + diff --git a/0005-Backport-lld-LoongArch-Support-the-R_LARCH_-ADD-SUB-_ULEB128-relocation-types.patch b/0005-Backport-lld-LoongArch-Support-the-R_LARCH_-ADD-SUB-_ULEB128-relocation-types.patch new file mode 100644 index 0000000..ca71e30 --- /dev/null +++ b/0005-Backport-lld-LoongArch-Support-the-R_LARCH_-ADD-SUB-_ULEB128-relocation-types.patch @@ -0,0 +1,199 @@ +From a5c1174c902a9dc7fb15aa047ca31e012aea6af9 Mon Sep 17 00:00:00 2001 +From: Jinyang He +Date: Tue, 5 Mar 2024 15:50:14 +0800 +Subject: [PATCH 12/14] [lld][LoongArch] Support the R_LARCH_{ADD,SUB}_ULEB128 + relocation types (#81133) + +For a label difference like `.uleb128 A-B`, MC generates a pair of +R_LARCH_{ADD,SUB}_ULEB128 if A-B cannot be folded as a constant. GNU +assembler generates a pair of relocations in more cases (when A or B is +in a code section with linker relaxation). It is similar to RISCV. + +R_LARCH_{ADD,SUB}_ULEB128 relocations are created by Clang and GCC in +`.gcc_except_table` and other debug sections with linker relaxation +enabled. On LoongArch, first read the buf and count the available space. +Then add or sub the value. Finally truncate the expected value and fill +it into the available space. + +(cherry picked from commit eaa9ef678c63bf392ec2d5b736605db7ea7e7338) +Change-Id: Ic49d34146e47eeeabbbba00ef70b76a13322d80e +--- + lld/ELF/Arch/LoongArch.cpp | 19 +++++ + lld/test/ELF/loongarch-reloc-leb128.s | 102 ++++++++++++++++++++++++++ + 2 files changed, 121 insertions(+) + create mode 100644 lld/test/ELF/loongarch-reloc-leb128.s + +diff --git a/lld/ELF/Arch/LoongArch.cpp b/lld/ELF/Arch/LoongArch.cpp +index 3f57a76873f9..160fab4aeba9 100644 +--- a/lld/ELF/Arch/LoongArch.cpp ++++ b/lld/ELF/Arch/LoongArch.cpp +@@ -11,6 +11,7 @@ + #include "Symbols.h" + #include "SyntheticSections.h" + #include "Target.h" ++#include "llvm/Support/LEB128.h" + + using namespace llvm; + using namespace llvm::object; +@@ -210,6 +211,16 @@ static bool isJirl(uint32_t insn) { + return (insn & 0xfc000000) == JIRL; + } + ++static void handleUleb128(uint8_t *loc, uint64_t val) { ++ const uint32_t maxcount = 1 + 64 / 7; ++ uint32_t count; ++ uint64_t orig = decodeULEB128(loc, &count); ++ if (count > maxcount) ++ errorOrWarn(getErrorLocation(loc) + "extra space for uleb128"); ++ uint64_t mask = count < maxcount ? (1ULL << 7 * count) - 1 : -1ULL; ++ encodeULEB128((orig + val) & mask, loc, count); ++} ++ + 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 +@@ -451,11 +462,13 @@ RelExpr LoongArch::getRelExpr(const RelType type, const Symbol &s, + case R_LARCH_ADD16: + case R_LARCH_ADD32: + case R_LARCH_ADD64: ++ case R_LARCH_ADD_ULEB128: + case R_LARCH_SUB6: + case R_LARCH_SUB8: + case R_LARCH_SUB16: + case R_LARCH_SUB32: + case R_LARCH_SUB64: ++ case R_LARCH_SUB_ULEB128: + // The LoongArch add/sub relocs behave like the RISCV counterparts; reuse + // the RelExpr to avoid code duplication. + return R_RISCV_ADD; +@@ -670,6 +683,9 @@ void LoongArch::relocate(uint8_t *loc, const Relocation &rel, + case R_LARCH_ADD64: + write64le(loc, read64le(loc) + val); + return; ++ case R_LARCH_ADD_ULEB128: ++ handleUleb128(loc, val); ++ return; + case R_LARCH_SUB6: + *loc = (*loc & 0xc0) | ((*loc - val) & 0x3f); + return; +@@ -685,6 +701,9 @@ void LoongArch::relocate(uint8_t *loc, const Relocation &rel, + case R_LARCH_SUB64: + write64le(loc, read64le(loc) - val); + return; ++ case R_LARCH_SUB_ULEB128: ++ handleUleb128(loc, -val); ++ return; + + case R_LARCH_MARK_LA: + case R_LARCH_MARK_PCREL: +diff --git a/lld/test/ELF/loongarch-reloc-leb128.s b/lld/test/ELF/loongarch-reloc-leb128.s +new file mode 100644 +index 000000000000..7740ca797fca +--- /dev/null ++++ b/lld/test/ELF/loongarch-reloc-leb128.s +@@ -0,0 +1,102 @@ ++# REQUIRES: loongarch ++# RUN: rm -rf %t && split-file %s %t && cd %t ++ ++# RUN: llvm-mc --filetype=obj --triple=loongarch64 --mattr=+relax a.s -o a.o ++# RUN: llvm-readobj -r -x .gcc_except_table -x .debug_rnglists -x .debug_loclists a.o | FileCheck %s --check-prefix=REL ++# RUN: ld.lld -shared --gc-sections a.o -o a.so ++# RUN: llvm-readelf -x .gcc_except_table -x .debug_rnglists -x .debug_loclists a.so | FileCheck %s ++ ++# RUN: llvm-mc --filetype=obj --triple=loongarch32 --mattr=+relax a.s -o a32.o ++# RUN: llvm-readobj -r -x .gcc_except_table -x .debug_rnglists -x .debug_loclists a32.o | FileCheck %s --check-prefix=REL ++# RUN: ld.lld -shared --gc-sections a32.o -o a32.so ++# RUN: llvm-readelf -x .gcc_except_table -x .debug_rnglists -x .debug_loclists a32.so | FileCheck %s ++ ++# RUN: llvm-mc --filetype=obj --triple=loongarch32 --mattr=+relax extraspace.s -o extraspace32.o ++# RUN: llvm-mc --filetype=obj --triple=loongarch64 --mattr=+relax extraspace.s -o extraspace64.o ++# RUN: not ld.lld -shared extraspace32.o 2>&1 | FileCheck %s --check-prefix=ERROR ++# RUN: not ld.lld -shared extraspace64.o 2>&1 | FileCheck %s --check-prefix=ERROR ++# ERROR: error: extraspace{{.*}}.o:(.rodata+0x0): extra space for uleb128 ++ ++#--- a.s ++.cfi_startproc ++.cfi_lsda 0x1b,.LLSDA0 ++.cfi_endproc ++ ++.section .text.w,"axR" ++break 0; break 0; break 0; w1: ++ .p2align 4 # 4 bytes after relaxation ++w2: break 0 ++ ++.section .text.x,"ax" ++break 0; break 0; break 0; x1: ++ .p2align 4 # 4 bytes after relaxation ++x2: break 0 ++ ++.section .gcc_except_table,"a" ++.LLSDA0: ++.uleb128 w2-w1+116 # initial value: 0x0080 ++.uleb128 w1-w2+141 # initial value: 0x0080 ++.uleb128 w2-w1+16372 # initial value: 0x008080 ++.uleb128 w1-w2+16397 # initial value: 0x008080 ++.uleb128 w2-w1+2097140 # initial value: 0x00808080 ++.uleb128 w1-w2+2097165 # initial value: 0x00808080 ++ ++.section .debug_rnglists ++.uleb128 w2-w1+116 # initial value: 0x0080 ++.uleb128 w1-w2+141 # initial value: 0x0080 ++.uleb128 w2-w1+16372 # initial value: 0x008080 ++.uleb128 w1-w2+16397 # initial value: 0x008080 ++.uleb128 w2-w1+2097140 # initial value: 0x00808080 ++.uleb128 w1-w2+2097165 # initial value: 0x00808080 ++ ++.section .debug_loclists ++.uleb128 x2-x1 # references discarded symbols ++ ++# REL: Section ({{.*}}) .rela.debug_rnglists { ++# REL-NEXT: 0x0 R_LARCH_ADD_ULEB128 w2 0x74 ++# REL-NEXT: 0x0 R_LARCH_SUB_ULEB128 w1 0x0 ++# REL-NEXT: 0x2 R_LARCH_ADD_ULEB128 w1 0x8D ++# REL-NEXT: 0x2 R_LARCH_SUB_ULEB128 w2 0x0 ++# REL-NEXT: 0x4 R_LARCH_ADD_ULEB128 w2 0x3FF4 ++# REL-NEXT: 0x4 R_LARCH_SUB_ULEB128 w1 0x0 ++# REL-NEXT: 0x7 R_LARCH_ADD_ULEB128 w1 0x400D ++# REL-NEXT: 0x7 R_LARCH_SUB_ULEB128 w2 0x0 ++# REL-NEXT: 0xA R_LARCH_ADD_ULEB128 w2 0x1FFFF4 ++# REL-NEXT: 0xA R_LARCH_SUB_ULEB128 w1 0x0 ++# REL-NEXT: 0xE R_LARCH_ADD_ULEB128 w1 0x20000D ++# REL-NEXT: 0xE R_LARCH_SUB_ULEB128 w2 0x0 ++# REL-NEXT: } ++# REL: Section ({{.*}}) .rela.debug_loclists { ++# REL-NEXT: 0x0 R_LARCH_ADD_ULEB128 x2 0x0 ++# REL-NEXT: 0x0 R_LARCH_SUB_ULEB128 x1 0x0 ++# REL-NEXT: } ++ ++# REL: Hex dump of section '.gcc_except_table': ++# REL-NEXT: 0x00000000 80008000 80800080 80008080 80008080 . ++# REL-NEXT: 0x00000010 8000 . ++# REL: Hex dump of section '.debug_rnglists': ++# REL-NEXT: 0x00000000 80008000 80800080 80008080 80008080 . ++# REL-NEXT: 0x00000010 8000 . ++# REL: Hex dump of section '.debug_loclists': ++# REL-NEXT: 0x00000000 00 . ++ ++# CHECK: Hex dump of section '.gcc_except_table': ++# CHECK-NEXT: 0x[[#%x,]] f8008901 f8ff0089 8001f8ff ff008980 . ++# CHECK-NEXT: 0x[[#%x,]] 8001 . ++# CHECK: Hex dump of section '.debug_rnglists': ++# CHECK-NEXT: 0x00000000 f8008901 f8ff0089 8001f8ff ff008980 . ++# CHECK-NEXT: 0x00000010 8001 . ++# CHECK: Hex dump of section '.debug_loclists': ++# CHECK-NEXT: 0x00000000 0c . ++ ++#--- extraspace.s ++.text ++w1: ++ la.pcrel $t0, w1 ++w2: ++ ++.rodata ++.reloc ., R_LARCH_ADD_ULEB128, w2 ++.reloc ., R_LARCH_SUB_ULEB128, w1 ++.fill 10, 1, 0x80 ++.byte 0 +-- +2.20.1 + diff --git a/lld.spec b/lld.spec index 1556adf..f777bdc 100644 --- a/lld.spec +++ b/lld.spec @@ -32,7 +32,7 @@ Name: %{pkg_name} Version: %{maj_ver}.%{min_ver}.%{patch_ver} -Release: 1 +Release: 2 Summary: The LLVM Linker License: NCSA @@ -40,6 +40,10 @@ URL: http://llvm.org Source0: https://github.com/llvm/llvm-project/releases/download/llvmorg-%{version}/lld-%{version}.src.tar.xz Patch1: fedora-PATCH-lld-Import-compact_unwind_encoding.h-from-libu.patch +Patch2: 0002-Backport-lld-LoongArch-Support-the-R_LARCH_-ADD-SUB-6-relocation-type.patch +Patch3: 0003-Backport-ELF-RISCV-Implement-emit-relocs-with-relaxation.patch +Patch4: 0004-Backport-lld-ELF-Support-relax-R_LARCH_ALIGN.patch +Patch5: 0005-Backport-lld-LoongArch-Support-the-R_LARCH_-ADD-SUB-_ULEB128-relocation-types.patch BuildRequires: clang BuildRequires: cmake @@ -127,8 +131,11 @@ rm %{buildroot}%{install_includedir}/mach-o/compact_unwind_encoding.h %{install_libdir}/liblld*.so.* %changelog +* Mon Mar 25 2024 zhanglimin - 17.0.6-2 +- Supoort `relax` feature on LoongArch + * Fri Dec 1 2023 zhoujing - 17.0.6-1 - Update to 17.0.6 * Thu May 25 2023 cf-zhao - 12.0.1-1 -- Package init \ No newline at end of file +- Package init -- Gitee