[llvm-branch-commits] [lld] [lld][LoongArch] Add reloc types for LA32R/LA32S (PR #172618)
via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Wed Dec 17 01:27:39 PST 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-lld-elf
Author: hev (heiher)
<details>
<summary>Changes</summary>
This patch adds support for processing the relocation types introduced in la-abi-specs v2.50.
Link: https://github.com/loongson/la-abi-specs/pull/16
Link: https://sourceware.org/pipermail/binutils/2025-December/146091.html
---
Patch is 33.61 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/172618.diff
13 Files Affected:
- (modified) lld/ELF/Arch/LoongArch.cpp (+62-5)
- (modified) lld/ELF/InputSection.cpp (+62)
- (modified) lld/ELF/Relocations.cpp (+1-1)
- (modified) lld/ELF/Relocations.h (+1)
- (added) lld/test/ELF/loongarch-call30.s (+64)
- (added) lld/test/ELF/loongarch-relax-call30-2.s (+65)
- (added) lld/test/ELF/loongarch-relax-call30.s (+136)
- (modified) lld/test/ELF/loongarch-relax-emit-relocs.s (+70-31)
- (modified) lld/test/ELF/loongarch-tls-gd-edge-case.s (+5-5)
- (modified) lld/test/ELF/loongarch-tls-gd.s (+5-5)
- (modified) lld/test/ELF/loongarch-tls-ie.s (+11-10)
- (modified) lld/test/ELF/loongarch-tls-ld.s (+5-5)
- (modified) lld/test/ELF/loongarch-tlsdesc.s (+27-3)
``````````diff
diff --git a/lld/ELF/Arch/LoongArch.cpp b/lld/ELF/Arch/LoongArch.cpp
index c6cdf05547d3f..1cea0d41bf74c 100644
--- a/lld/ELF/Arch/LoongArch.cpp
+++ b/lld/ELF/Arch/LoongArch.cpp
@@ -184,6 +184,10 @@ static uint32_t setJ5(uint32_t insn, uint32_t imm) {
return (insn & 0xfffffc1f) | (extractBits(imm, 4, 0) << 5);
}
+static uint32_t setK10(uint32_t insn, uint32_t imm) {
+ return (insn & 0xffc003ff) | (extractBits(imm, 9, 0) << 10);
+}
+
static uint32_t setK12(uint32_t insn, uint32_t imm) {
return (insn & 0xffc003ff) | (extractBits(imm, 11, 0) << 10);
}
@@ -439,6 +443,13 @@ RelExpr LoongArch::getRelExpr(const RelType type, const Symbol &s,
// [1]: https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=9f482b73f41a9a1bbfb173aad0733d1c824c788a
// [2]: https://github.com/loongson/la-abi-specs/pull/3
return isJirl(read32le(loc)) ? R_PLT : R_ABS;
+ case R_LARCH_PCADD_LO12:
+ case R_LARCH_GOT_PCADD_LO12:
+ case R_LARCH_TLS_IE_PCADD_LO12:
+ case R_LARCH_TLS_LD_PCADD_LO12:
+ case R_LARCH_TLS_GD_PCADD_LO12:
+ case R_LARCH_TLS_DESC_PCADD_LO12:
+ return RE_LOONGARCH_PC_INDIRECT;
case R_LARCH_TLS_DTPREL32:
case R_LARCH_TLS_DTPREL64:
return R_DTPREL;
@@ -469,10 +480,12 @@ RelExpr LoongArch::getRelExpr(const RelType type, const Symbol &s,
case R_LARCH_32_PCREL:
case R_LARCH_64_PCREL:
case R_LARCH_PCREL20_S2:
+ case R_LARCH_PCADD_HI20:
return R_PC;
case R_LARCH_B16:
case R_LARCH_B21:
case R_LARCH_B26:
+ case R_LARCH_CALL30:
case R_LARCH_CALL36:
return R_PLT_PC;
case R_LARCH_GOT_PC_HI20:
@@ -482,6 +495,9 @@ RelExpr LoongArch::getRelExpr(const RelType type, const Symbol &s,
case R_LARCH_TLS_IE64_PC_LO20:
case R_LARCH_TLS_IE64_PC_HI12:
return RE_LOONGARCH_GOT_PAGE_PC;
+ case R_LARCH_GOT_PCADD_HI20:
+ case R_LARCH_TLS_IE_PCADD_HI20:
+ return R_GOT_PC;
case R_LARCH_GOT_PC_LO12:
case R_LARCH_TLS_IE_PC_LO12:
return RE_LOONGARCH_GOT;
@@ -545,12 +561,15 @@ RelExpr LoongArch::getRelExpr(const RelType type, const Symbol &s,
case R_LARCH_TLS_DESC_LO12:
case R_LARCH_TLS_DESC64_LO20:
case R_LARCH_TLS_DESC64_HI12:
+ case R_LARCH_TLS_DESC_PCADD_HI20:
return R_TLSDESC;
case R_LARCH_TLS_DESC_CALL:
return R_TLSDESC_CALL;
case R_LARCH_TLS_LD_PCREL20_S2:
+ case R_LARCH_TLS_LD_PCADD_HI20:
return R_TLSLD_PC;
case R_LARCH_TLS_GD_PCREL20_S2:
+ case R_LARCH_TLS_GD_PCADD_HI20:
return R_TLSGD_PC;
case R_LARCH_TLS_DESC_PCREL20_S2:
return R_TLSDESC_PC;
@@ -628,6 +647,22 @@ void LoongArch::relocate(uint8_t *loc, const Relocation &rel,
write32le(loc, setD10k16(read32le(loc), val >> 2));
return;
+ case R_LARCH_CALL30: {
+ // This relocation is designed for adjacent pcaddu12i+jirl pairs that
+ // are patched in one time.
+ // The relocation range is [-4G, +4G) (of course must be 4-byte aligned).
+ if ((int64_t)val != llvm::SignExtend64(val, 32))
+ reportRangeError(ctx, loc, rel, Twine(val), llvm::minIntN(32),
+ llvm::maxIntN(32));
+ checkAlignment(ctx, loc, val, 4, rel);
+ uint32_t hi20 = extractBits(val, 31, 12);
+ // Despite the name, the lower part is actually 12 bits with 4-byte aligned.
+ uint32_t lo10 = extractBits(val, 11, 2);
+ write32le(loc, setJ20(read32le(loc), hi20));
+ write32le(loc + 4, setK10(read32le(loc + 4), lo10));
+ return;
+ }
+
case R_LARCH_CALL36: {
// This relocation is designed for adjacent pcaddu18i+jirl pairs that
// are patched in one time. Because of sign extension of these insns'
@@ -671,6 +706,12 @@ void LoongArch::relocate(uint8_t *loc, const Relocation &rel,
case R_LARCH_TLS_LE_LO12_R:
case R_LARCH_TLS_DESC_PC_LO12:
case R_LARCH_TLS_DESC_LO12:
+ case R_LARCH_PCADD_LO12:
+ case R_LARCH_GOT_PCADD_LO12:
+ case R_LARCH_TLS_IE_PCADD_LO12:
+ case R_LARCH_TLS_LD_PCADD_LO12:
+ case R_LARCH_TLS_GD_PCADD_LO12:
+ case R_LARCH_TLS_DESC_PCADD_LO12:
write32le(loc, setK12(read32le(loc), extractBits(val, 11, 0)));
return;
@@ -690,6 +731,17 @@ void LoongArch::relocate(uint8_t *loc, const Relocation &rel,
case R_LARCH_TLS_DESC_HI20:
write32le(loc, setJ20(read32le(loc), extractBits(val, 31, 12)));
return;
+ case R_LARCH_PCADD_HI20:
+ case R_LARCH_GOT_PCADD_HI20:
+ case R_LARCH_TLS_IE_PCADD_HI20:
+ case R_LARCH_TLS_LD_PCADD_HI20:
+ case R_LARCH_TLS_GD_PCADD_HI20:
+ case R_LARCH_TLS_DESC_PCADD_HI20: {
+ uint64_t hi = val + 0x800;
+ checkInt(ctx, loc, SignExtend64(hi, 32) >> 12, 20, rel);
+ write32le(loc, setJ20(read32le(loc), extractBits(hi, 31, 12)));
+ return;
+ }
case R_LARCH_TLS_LE_HI20_R:
write32le(loc, setJ20(read32le(loc), extractBits(val + 0x800, 31, 12)));
return;
@@ -998,12 +1050,16 @@ static void relaxPCHi20Lo12(Ctx &ctx, const InputSection &sec, size_t i,
// Relax code sequence.
// From:
-// pcaddu18i $ra, %call36(foo)
-// jirl $ra, $ra, 0
+// la32r:
+// pcaddu12i $ra, %call30(foo)
+// jirl $ra, $ra, 0
+// la32s/la64:
+// pcaddu18i $ra, %call36(foo)
+// jirl $ra, $ra, 0
// To:
// b/bl foo
-static void relaxCall36(Ctx &ctx, const InputSection &sec, size_t i,
- uint64_t loc, Relocation &r, uint32_t &remove) {
+static void relaxMediumCall(Ctx &ctx, const InputSection &sec, size_t i,
+ uint64_t loc, Relocation &r, uint32_t &remove) {
const uint64_t dest =
(r.expr == R_PLT_PC ? r.sym->getPltVA(ctx) : r.sym->getVA(ctx)) +
r.addend;
@@ -1108,9 +1164,10 @@ static bool relax(Ctx &ctx, InputSection &sec) {
} else if (isPairRelaxable(relocs, i))
relaxPCHi20Lo12(ctx, sec, i, loc, r, relocs[i + 2], remove);
break;
+ case R_LARCH_CALL30:
case R_LARCH_CALL36:
if (relaxable(relocs, i))
- relaxCall36(ctx, sec, i, loc, r, remove);
+ relaxMediumCall(ctx, sec, i, loc, r, remove);
break;
case R_LARCH_TLS_LE_HI20_R:
case R_LARCH_TLS_LE_ADD_R:
diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp
index ff7ef2dce5c79..3b0fab23481c1 100644
--- a/lld/ELF/InputSection.cpp
+++ b/lld/ELF/InputSection.cpp
@@ -714,6 +714,63 @@ static Relocation *getRISCVPCRelHi20(Ctx &ctx, const InputSectionBase *loSec,
return nullptr;
}
+// For RE_LARCH_PC_INDIRECT (R_LARCH_*PCADD_LO12), the symbol actually points
+// the corresponding R_LARCH_*PCADD_HI20 relocation, and the target VA is
+// calculated using PCADD_HI20's symbol.
+//
+// This function returns the R_LARCH_*PCADD_HI20 relocation from the
+// R_LARCH_*PCADD_LO12 relocation.
+static Relocation *getLoongArchPCAddHi20(Ctx &ctx,
+ const InputSectionBase *loSec,
+ const Relocation &loReloc) {
+ int64_t addend = loReloc.addend;
+ Symbol *sym = loReloc.sym;
+
+ const Defined *d = cast<Defined>(sym);
+ if (!d->section) {
+ Err(ctx) << loSec->getLocation(loReloc.offset)
+ << ": R_LARCH_*PCADD_LO12 relocation points to an absolute symbol: "
+ << sym->getName();
+ return nullptr;
+ }
+ InputSection *hiSec = cast<InputSection>(d->section);
+
+ if (hiSec != loSec)
+ Err(ctx) << loSec->getLocation(loReloc.offset)
+ << ": R_LARCH_*PCADD_LO12 relocation points to a symbol '"
+ << sym->getName() << "' in a different section '" << hiSec->name
+ << "'";
+
+ if (addend != 0)
+ Warn(ctx) << loSec->getLocation(loReloc.offset)
+ << ": non-zero addend in R_LARCH_*PCADD_LO12 relocation to "
+ << hiSec->getObjMsg(d->value) << " is ignored";
+
+ // Relocations are sorted by offset, so we can use std::equal_range to do
+ // binary search.
+ Relocation hiReloc;
+ hiReloc.offset = d->value + addend;
+ auto range =
+ std::equal_range(hiSec->relocs().begin(), hiSec->relocs().end(), hiReloc,
+ [](const Relocation &lhs, const Relocation &rhs) {
+ return lhs.offset < rhs.offset;
+ });
+
+ for (auto it = range.first; it != range.second; ++it)
+ if (it->type == R_LARCH_PCADD_HI20 || it->type == R_LARCH_GOT_PCADD_HI20 ||
+ it->type == R_LARCH_TLS_IE_PCADD_HI20 ||
+ it->type == R_LARCH_TLS_LD_PCADD_HI20 ||
+ it->type == R_LARCH_TLS_GD_PCADD_HI20 ||
+ it->type == R_LARCH_TLS_DESC_PCADD_HI20)
+ return &*it;
+
+ Err(ctx) << loSec->getLocation(loReloc.offset)
+ << ": R_LARCH_*PCADD_LO12 relocation points to "
+ << hiSec->getObjMsg(d->value)
+ << " without an associated R_LARCH_*PCADD_HI20 relocation";
+ return nullptr;
+}
+
// A TLS symbol's virtual address is relative to the TLS segment. Add a
// target-specific adjustment to produce a thread-pointer-relative offset.
static int64_t getTlsTpOffset(Ctx &ctx, const Symbol &s) {
@@ -891,6 +948,11 @@ uint64_t InputSectionBase::getRelocTargetVA(Ctx &ctx, const Relocation &r,
return getRelocTargetVA(ctx, *hiRel, r.sym->getVA(ctx));
return 0;
}
+ case RE_LOONGARCH_PC_INDIRECT: {
+ if (const Relocation *hiRel = getLoongArchPCAddHi20(ctx, this, r))
+ return getRelocTargetVA(ctx, *hiRel, r.sym->getVA(ctx, a));
+ return 0;
+ }
case RE_LOONGARCH_PAGE_PC:
return getLoongArchPageDelta(r.sym->getVA(ctx, a), p, r.type);
case R_PC:
diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp
index 59aa43036ce01..ae3578d8e7cb3 100644
--- a/lld/ELF/Relocations.cpp
+++ b/lld/ELF/Relocations.cpp
@@ -148,7 +148,7 @@ static bool isRelExpr(RelExpr expr) {
return oneof<R_PC, R_GOTREL, R_GOTPLTREL, RE_ARM_PCA, RE_MIPS_GOTREL,
RE_PPC64_CALL, RE_PPC64_RELAX_TOC, RE_AARCH64_PAGE_PC,
R_RELAX_GOT_PC, RE_RISCV_PC_INDIRECT, RE_PPC64_RELAX_GOT_PC,
- RE_LOONGARCH_PAGE_PC>(expr);
+ RE_LOONGARCH_PAGE_PC, RE_LOONGARCH_PC_INDIRECT>(expr);
}
static RelExpr toPlt(RelExpr expr) {
diff --git a/lld/ELF/Relocations.h b/lld/ELF/Relocations.h
index 86ca298cd7a56..bff899d5c4d0c 100644
--- a/lld/ELF/Relocations.h
+++ b/lld/ELF/Relocations.h
@@ -132,6 +132,7 @@ enum RelExpr {
// also reused for TLS, making the semantics differ from other architectures.
RE_LOONGARCH_GOT,
RE_LOONGARCH_GOT_PAGE_PC,
+ RE_LOONGARCH_PC_INDIRECT,
RE_LOONGARCH_TLSGD_PAGE_PC,
RE_LOONGARCH_TLSDESC_PAGE_PC,
RE_LOONGARCH_RELAX_TLS_GD_TO_IE_PAGE_PC,
diff --git a/lld/test/ELF/loongarch-call30.s b/lld/test/ELF/loongarch-call30.s
new file mode 100644
index 0000000000000..907e8704e908b
--- /dev/null
+++ b/lld/test/ELF/loongarch-call30.s
@@ -0,0 +1,64 @@
+# REQUIRES: loongarch
+
+# RUN: rm -rf %t && split-file %s %t
+# RUN: llvm-mc --filetype=obj --triple=loongarch32-unknown-elf %t/a.s -o %t/a.o
+
+# RUN: ld.lld %t/a.o --section-start=.text=0x20010 --section-start=.sec.foo=0x21020 -o %t/exe1
+# RUN: llvm-objdump --no-show-raw-insn -d %t/exe1 | FileCheck --match-full-lines %s --check-prefix=EXE1
+## hi20 = target - pc >> 12 = 0x21020 - 0x20010 >> 12 = 1
+## lo12 = target - pc & (1 << 12) - 1 = 0x21020 - 0x20010 & 0xfff = 16
+# EXE1: 20010: pcaddu12i $t0, 1
+# EXE1-NEXT: 20014: jirl $zero, $t0, 16
+
+# RUN: ld.lld %t/a.o --section-start=.text=0x20010 --section-start=.sec.foo=0x21820 -o %t/exe2
+# RUN: llvm-objdump --no-show-raw-insn -d %t/exe2 | FileCheck --match-full-lines %s --check-prefix=EXE2
+## hi20 = target - pc >> 12 = 0x21820 - 0x20010 >> 12 = 1
+## lo12 = target - pc & (1 << 12) - 1 = 0x21820 - 0x20010 & 0xfff = 2064
+# EXE2: 20010: pcaddu12i $t0, 1
+# EXE2-NEXT: 20014: jirl $zero, $t0, 2064
+
+# RUN: ld.lld %t/a.o -shared -T %t/a.t -o %t/a.so
+# RUN: llvm-readelf -x .got.plt %t/a.so | FileCheck --check-prefix=GOTPLT %s
+# RUN: llvm-objdump -d --no-show-raw-insn %t/a.so | FileCheck --check-prefix=SO %s
+## PLT should be present in this case.
+# SO: Disassembly of section .plt:
+# SO: <.plt>:
+## foo at plt:
+# SO: 1234520: pcaddu12i $t3, 64{{$}}
+# SO-NEXT: ld.w $t3, $t3, 444{{$}}
+# SO-NEXT: jirl $t1, $t3, 0
+# SO-NEXT: nop
+
+# SO: Disassembly of section .text:
+# SO: <_start>:
+## hi20 = foo at plt - pc >> 12 = 0x1234520 - 0x1274670 >> 12 = -65
+## lo18 = foo at plt - pc & (1 << 12) - 1 = 0x1234520 - 0x1274670 & 0xfff = 3760
+# SO-NEXT: pcaddu12i $t0, -65{{$}}
+# SO-NEXT: jirl $zero, $t0, 3760{{$}}
+
+# GOTPLT: section '.got.plt':
+# GOTPLT-NEXT: 0x012746d4 00000000 00000000 00452301
+
+## Impossible case in reality becasue all LoongArch instructions are fixed 4-bytes long.
+# RUN: not ld.lld %t/a.o --section-start=.text=0x20000 --section-start=.sec.foo=0x40001 -o /dev/null 2>&1 | \
+# RUN: FileCheck -DFILE=%t/a.o --check-prefix=ERROR-ALIGN %s
+# ERROR-ALIGN: error: [[FILE]]:(.text+0x0): improper alignment for relocation R_LARCH_CALL30: 0x20001 is not aligned to 4 bytes
+
+#--- a.t
+SECTIONS {
+ .plt 0x1234500: { *(.plt) }
+ .text 0x1274670: { *(.text) }
+}
+
+#--- a.s
+.text
+.global _start
+_start:
+ .reloc ., R_LARCH_CALL30, foo
+ pcaddu12i $t0, 0
+ jirl $zero, $t0, 0
+
+.section .sec.foo,"awx"
+.global foo
+foo:
+ ret
diff --git a/lld/test/ELF/loongarch-relax-call30-2.s b/lld/test/ELF/loongarch-relax-call30-2.s
new file mode 100644
index 0000000000000..45584f4e14dc8
--- /dev/null
+++ b/lld/test/ELF/loongarch-relax-call30-2.s
@@ -0,0 +1,65 @@
+# REQUIRES: loongarch
+## Relax R_LARCH_CALL30. This test tests boundary cases and some special symbols.
+
+# RUN: rm -rf %t && split-file %s %t && cd %t
+# RUN: llvm-mc -filetype=obj -triple=loongarch32 -mattr=+relax a.s -o a.o
+
+# RUN: ld.lld -T lds a.o -o a
+# RUN: llvm-objdump -d --no-show-raw-insn a | FileCheck %s --check-prefixes=RELAX,RELAX-MID
+
+## Unsure whether this needs a diagnostic. GNU ld allows this.
+# RUN: ld.lld -T lds -pie a.o -o a.pie
+# RUN: llvm-objdump -d --no-show-raw-insn a.pie | FileCheck %s --check-prefixes=RELAX,RELAX-MID
+
+# RUN: ld.lld -T lds -pie -z notext -z ifunc-noplt a.o -o a.ifunc-noplt
+# RUN: llvm-objdump -d --no-show-raw-insn a.ifunc-noplt | FileCheck %s --check-prefixes=RELAX,NORELAX-MID
+
+# RELAX-LABEL: <_start>:
+## offset = 0x10000000 - 0x8000000 = 0x8000000(134217728), hi=512, lo18=0
+# RELAX-NEXT: 8000000: pcaddu12i $ra, 32768
+# RELAX-NEXT: jirl $ra, $ra, 0
+# RELAX-NEXT: bl 134217720
+# RELAX-NEXT: bl -134217728
+## offset = 12 - 0x8000010 = -0x8000004(-134217732), hi=512, lo18=-4
+# RELAX-NEXT: 8000010: pcaddu12i $ra, -32769
+# RELAX-NEXT: jirl $ra, $ra, 4092
+# RELAX-EMPTY:
+
+# RELAX-MID-LABEL: <.mid>:
+## offset = 0x8010000 - 0x8008000 = 32768
+# RELAX-MID-NEXT: 8008000: bl 32768
+# RELAX-MID-NEXT: b 32764
+# RELAX-MID-EMPTY:
+
+# NORELAX-MID-LABEL: <.mid>:
+# NORELAX-MID-NEXT: 8008000: pcaddu12i $ra, 0
+# NORELAX-MID-NEXT: jirl $ra, $ra, 0
+# NORELAX-MID-NEXT: pcaddu12i $t0, 0
+# NORELAX-MID-NEXT: jr $t0
+# NORELAX-MID-EMPTY:
+
+#--- a.s
+.global _start, ifunc
+_start:
+ call30 pos # exceed positive range (.text+0x7fffffc), not relaxed
+ call30 pos # relaxed
+ call30 neg # relaxed
+ call30 neg # exceed negative range (.text+16-0x8000000), not relaxed
+
+.section .mid,"ax", at progbits
+.balign 16
+ call30 ifunc # enable ifunc, not relaxed
+ tail30 $t0, ifunc # enable ifunc, not relaxed
+
+.type ifunc, @gnu_indirect_function
+ifunc:
+ ret
+
+#--- lds
+SECTIONS {
+ .text 0x8000000 : { *(.text) }
+ .mid 0x8008000 : { *(.mid) }
+ .iplt 0x8010000 : { *(.iplt) }
+}
+neg = 12;
+pos = 0x10000000;
diff --git a/lld/test/ELF/loongarch-relax-call30.s b/lld/test/ELF/loongarch-relax-call30.s
new file mode 100644
index 0000000000000..f3172897f47fb
--- /dev/null
+++ b/lld/test/ELF/loongarch-relax-call30.s
@@ -0,0 +1,136 @@
+# REQUIRES: loongarch
+## Relax R_LARCH_CALL30, which involves the macro instructions call30/tail30.
+
+# RUN: rm -rf %t && split-file %s %t && cd %t
+
+# RUN: llvm-mc -filetype=obj -triple=loongarch32 -mattr=+relax a.s -o a.32.o
+# RUN: llvm-mc -filetype=obj -triple=loongarch32 -mattr=+relax b.s -o b.32.o
+# RUN: ld.lld -shared -soname=b.so b.32.o -o b.32.so
+# RUN: ld.lld -T lds a.32.o b.32.so -o 32
+# RUN: llvm-objdump -td --no-show-raw-insn 32 | FileCheck %s --check-prefix=RELAX
+
+## --no-relax disables relaxation.
+# RUN: ld.lld -T lds a.32.o b.32.so --no-relax -o 32.norelax
+# RUN: llvm-objdump -td --no-show-raw-insn 32.norelax | FileCheck %s --check-prefix=NORELAX
+
+# RELAX: {{0*}}00010000 g .text {{0*}}0000001c _start
+# RELAX: {{0*}}0001001c g .text {{0*}}00000000 _start_end
+# RELAX: {{0*}}00010808 g .mid {{0*}}00000000 mid_end
+# RELAX: {{0*}}10010010 g .high {{0*}}00000000 high_end
+
+# RELAX-LABEL: <_start>:
+## offset = 0x10018 - 0x10000 = 24
+# RELAX-NEXT: 10000: bl 24 <a>
+# RELAX-NEXT: b 20 <a>
+# RELAX-NEXT: nop
+# RELAX-NEXT: nop
+## offset = .plt(0x10400)+32 - 0x10010 = 1040
+# RELAX-NEXT: 10010: bl 1040 <bar+0x10420>
+# RELAX-NEXT: b 1036 <bar+0x10420>
+# RELAX-EMPTY:
+# RELAX-NEXT: <a>:
+# RELAX-NEXT: 10018: ret
+# RELAX-EMPTY:
+
+# RELAX-LABEL: <.mid>:
+## offset = 0x10000 - 0x10800 = -2048
+# RELAX-NEXT: 10800: bl -2048 <_start>
+# RELAX-NEXT: b -2052 <_start>
+# RELAX-EMPTY:
+
+# RELAX-LABEL: <.mid2>:
+## offset = 0x10000 - 0x1010000 = -16777216
+# RELAX-NEXT: 1010000: bl -16777216 <_start>
+# RELAX-NEXT: b -16777220 <_start>
+# RELAX-EMPTY:
+
+# RELAX-LABEL: <.high>:
+## offset = 0x10000 - 0x10010000 = -0x10000000, hi=-1024, lo18=0
+# RELAX-NEXT: 10010000: pcaddu12i $ra, -65536
+# RELAX-NEXT: jirl $ra, $ra, 0
+# RELAX-NEXT: pcaddu12i $t0, -65537
+# RELAX-NEXT: jirl $zero, $t0, 4088
+# RELAX-EMPTY:
+
+
+# NORELAX-LABEL: <_start>:
+## offset = 0x10020 - 0x10000 = 0x20, hi=0, lo18=32
+# NORELAX-NEXT: 10000: pcaddu12i $ra, 0
+# NORELAX-NEXT: jirl $ra, $ra, 32
+## offset = 0x10020 - 0x10008 = 0x18, hi=0, lo18=24
+# NORELAX-NEXT: 10008: pcaddu12i $t0, 0
+# NORELAX-NEXT: jirl $zero, $t0, 24
+## offset = .plt(0x10400)+32 - 0x10010 = 0x410, hi=0, lo18=1040
+# NORELAX-NEXT: 10010: pcaddu12i $ra, 0
+# NORELAX-NEXT: jirl $ra, $ra, 1040
+## offset = .plt(0x10400)+32 - 0x10018 = 0x408, hi=0, lo18=1032
+# NORELAX-NEXT: 10018: pcaddu12i $t0, 0
+# NORELAX-NEXT: jirl $zero, $t0, 1032
+# NORELAX-EMPTY:
+# NORELAX-NEXT: <a>:
+# NORELAX-NEXT: 10020: ret
+# NORELAX-EMPTY:
+
+# NORELAX-LABEL: <.mid>:
+## offset = 0x10000 - 0x10800 = -0x800, hi=0, lo18=-2048
+# NORELAX-NEXT: 10800: pcaddu12i $ra, -1
+# NORELAX-NEXT: jirl $ra, $ra, 2048
+# NORELAX-NEXT: pcaddu12i $t0, -1
+# NORELAX-NEXT: jirl $zero, $t0, 2040
+# NORELAX-EMPTY:
+
+# NORELAX-LABEL: <.mid2>:
+## offset = 0x10000 - 0x1010000 = -0x1000000, hi=-64, lo18=0
+# NORELAX-NEXT: 1010000: pcaddu12i $ra, -4096
+# NORELAX-NEXT: jirl $ra, $ra, 0
+# NORELAX-NEXT: pcaddu12i $t0, -4097
+# NORELAX-NEXT: jirl $zero, $t0, 4088
+# NORELAX-EMPTY:
+
+# NORELAX-LABEL: <.high>:
+## offset = 0x10000 - 0x10010000 = -0x10000000, hi=-1024, lo18=0
+# NORELAX-NEXT: 10010000: pcaddu12i $ra, -65536
+# NORELAX-NEXT: jirl $ra, $ra, 0
+# NORELAX-NEXT: pcaddu12i $t0, -65537
+# NORELAX-NEXT: jirl $zero, $t0, 4088
+# NORELAX-EMPTY:
+
+#--- a.s
+.global _start, _start_end
+_start:
+ call30 a # relaxed. la32: bl
+ tail30 $t0, a # relaxed. la32: b
+.balign 16
+ call30 bar # PLT call30 can be relaxed. la32: bl
+ tail30 $t0, bar # PLT tail30 can be relaxed. la32: bl
+
+a:
+ ret
+.size _start, . - _start
+_start_end:
+
+.section .mid,"ax", at progbits
+ call30 _start # relaxed. la32: bl
+ tail30 $t0, _start # relaxed. la32: b
+
+.section .mid2,"ax", at progbits
+ call30 _start # relaxed. la32: bl
+ tail30 $t0, _start # relaxed. la32: b
+
+.section .high,"ax", at progbits
+ call30 _start # exceed range, not relaxed
+ tail30 $t0, _start # exceed range, not relaxed
+
+#--- b.s
+.globl bar
+bar:
+ ret
+
+#--- lds
+SECTIONS {
+ .text 0x10000 : { *(.text) }
+ .plt 0x10400 : { *(.plt) }
+ .mid 0x10800 : { *(.mid); mid_end = .; }
+ .mid2 0x1010000 : { *(.mid2) }
+ .high 0x100...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/172618
More information about the llvm-branch-commits
mailing list