[Backport][LoongArch] Support relax feature

(cherry picked from commit c2c6c3baaa66ddb005a27824f861acbfa26fd8bd)
This commit is contained in:
Ami-zhang 2024-03-18 15:44:21 +08:00 committed by openeuler-sync-bot
parent 0143bceffa
commit 76fcccd0ef
5 changed files with 1088 additions and 2 deletions

View File

@ -0,0 +1,78 @@
From 7f14e7c1b116fc865ddebb78e67816bfc5216178 Mon Sep 17 00:00:00 2001
From: Jinyang He <hejinyang@loongson.cn>
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

View File

@ -0,0 +1,239 @@
From d53182c7fcc371f575fd71fa74e28220db6e9b82 Mon Sep 17 00:00:00 2001
From: Job Noorman <jnoorman@igalia.com>
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 <class ELFT, class RelTy>
+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<ELFT, RelTy>(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<ELFT> &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<ELFT>(rel), &file.getRelocTargetSym(rel)};
+ }
+ };
+
+ using RawRels = ArrayRef<RelTy>;
+ using MapRelIter =
+ llvm::mapped_iterator<typename RawRels::iterator, MapRel>;
+ auto mapRel = MapRel{*getFile<ELFT>()};
+ RawRels rawRels = getDataAs<RelTy>();
+ auto rels = llvm::make_range(MapRelIter(rawRels.begin(), mapRel),
+ MapRelIter(rawRels.end(), mapRel));
+ copyRelocations<ELFT, RelTy>(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 <class ELFT, class RelTy>
-void InputSection::copyRelocations(uint8_t *buf, ArrayRef<RelTy> rels) {
+template <class ELFT, class RelTy, class RelIt>
+void InputSection::copyRelocations(uint8_t *buf,
+ llvm::iterator_range<RelIt> 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<ELFT> *file = getFile<ELFT>();
- Symbol &sym = file->getRelocTargetSym(rel);
+ Symbol &sym = *rel.sym;
auto *p = reinterpret_cast<typename ELFT::Rela *>(buf);
buf += sizeof(RelTy);
if (RelTy::IsRela)
- p->r_addend = getAddend<ELFT>(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<RelTy> rels) {
continue;
}
- int64_t addend = getAddend<ELFT>(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<RelTy> 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 <class ELFT> 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<ELFT>(buf, getDataAs<typename ELFT::Rela>());
+ copyRelocations<ELFT, typename ELFT::Rela>(buf);
return;
}
if (LLVM_UNLIKELY(type == SHT_REL)) {
- copyRelocations<ELFT>(buf, getDataAs<typename ELFT::Rel>());
+ copyRelocations<ELFT, typename ELFT::Rel>(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 <class ELFT, class RelTy>
- void copyRelocations(uint8_t *buf, llvm::ArrayRef<RelTy> rels);
+ template <class ELFT, class RelTy> void copyRelocations(uint8_t *buf);
+
+ template <class ELFT, class RelTy, class RelIt>
+ void copyRelocations(uint8_t *buf, llvm::iterator_range<RelIt> rels);
template <class ELFT> 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 <f>
+# CHECK-NEXT: R_RISCV_JAL f
+# CHECK-NEXT: R_RISCV_RELAX *ABS*
+# CHECK-NEXT: jal ra, 0x10008 <f>
+# CHECK-NEXT: R_RISCV_JAL f
+# CHECK-NEXT: R_RISCV_RELAX *ABS*
+# CHECK-EMPTY:
+# CHECK-NEXT: <f>:
+# 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: <f>:
+# 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: <f>:
+# 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

View File

@ -0,0 +1,563 @@
From 80c56e85d742bb88533e4789c76ae2b55dc36835 Mon Sep 17 00:00:00 2001
From: Jinyang He <hejinyang@loongson.cn>
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<Relocation> relocs = sec.relocs();
+ auto &aux = *sec.relaxAux;
+ bool changed = false;
+ ArrayRef<SymbolAnchor> 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<int32_t>(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<InputSection *, 0> 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<InputSection *, 0> 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<Relocation> rels = sec->relocs();
+ ArrayRef<uint8_t> old = sec->content();
+ size_t newSize = old.size() - aux.relocDeltas[rels.size() - 1];
+ uint8_t *p = context().bAlloc.Allocate<uint8_t>(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 &target;
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<SymbolAnchor, 0> anchors;
- // For relocations[i], the actual offset is r_offset - (i ? relocDeltas[i-1] :
- // 0).
- std::unique_ptr<uint32_t[]> relocDeltas;
- // For relocations[i], the actual type is relocTypes[i].
- std::unique_ptr<RelType[]> relocTypes;
- SmallVector<uint32_t, 0> writes;
-};
-static void initSymbolAnchors() {
+void elf::initSymbolAnchors() {
SmallVector<InputSection *, 0> storage;
for (OutputSection *osec : outputSections) {
if (!(osec->flags & SHF_EXECINSTR))
continue;
for (InputSection *sec : getInputSections(*osec, storage)) {
- sec->relaxAux = make<RISCVRelaxAux>();
+ sec->relaxAux = make<RelaxAux>();
if (sec->relocs().size()) {
sec->relaxAux->relocDeltas =
std::make_unique<uint32_t[]>(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<InputSection *, 0> 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 <class ELFT, class RelTy>
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<ELFT, RelTy>(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<SymbolAnchor, 0> anchors;
+ // For relocations[i], the actual offset is
+ // r_offset - (i ? relocDeltas[i-1] : 0).
+ std::unique_ptr<uint32_t[]> relocDeltas;
+ // For relocations[i], the actual type is relocTypes[i].
+ std::unique_ptr<RelType[]> relocTypes;
+ SmallVector<uint32_t, 0> 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 <class ELFT> void Writer<ELFT>::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

View File

@ -0,0 +1,199 @@
From a5c1174c902a9dc7fb15aa047ca31e012aea6af9 Mon Sep 17 00:00:00 2001
From: Jinyang He <hejinyang@loongson.cn>
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

View File

@ -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,6 +131,9 @@ rm %{buildroot}%{install_includedir}/mach-o/compact_unwind_encoding.h
%{install_libdir}/liblld*.so.*
%changelog
* Mon Mar 25 2024 zhanglimin <zhanglimin@loongson.cn> - 17.0.6-2
- Supoort `relax` feature on LoongArch
* Fri Dec 1 2023 zhoujing <zhoujing106@huawei.com> - 17.0.6-1
- Update to 17.0.6