[lld] [lld][Mips] Remove signed range check for R_MICROMIPS_26_S1 (PR #228880)

Jiaxun Yang via llvm-commits llvm-commits at lists.llvm.org
Sun Oct 4 05:36:34 PDT 2026


https://github.com/FlyGoat created https://github.com/llvm/llvm-project/pull/228880

R_MICROMIPS_26_S1 encodes a shifted index within the current PC region,
not a signed absolute address. Applying the PC-relative relocation's
signed 27-bit check rejects valid destinations in higher address regions.

Write the jump index without that check, as for R_MIPS_26, while retaining
the signed range check for R_MICROMIPS_PC26_S1. Cover both jumps and calls
at a high address in little- and big-endian objects.

Assisted-by: OpenAI Codex # Testcases


Validation: `git diff --check` passes. Tests were not rerun for this cherry-pick.


>From edbb8e566acb96caebbb40ab6ed781bbdfbdc32c Mon Sep 17 00:00:00 2001
From: Jiaxun Yang <jiaxun.yang at flygoat.com>
Date: Sun, 4 Oct 2026 12:23:41 +0100
Subject: [PATCH] [lld][Mips] Remove signed range check for R_MICROMIPS_26_S1

R_MICROMIPS_26_S1 encodes a shifted index within the current PC region,
not a signed absolute address. Applying the PC-relative relocation's
signed 27-bit check rejects valid destinations in higher address regions.

Write the jump index without that check, as for R_MIPS_26, while retaining
the signed range check for R_MICROMIPS_PC26_S1. Cover both jumps and calls
at a high address in little- and big-endian objects.

Assisted-by: OpenAI Codex # Testcases
---
 lld/ELF/Arch/Mips.cpp                 |  4 ++++
 lld/test/ELF/mips-micro-jump-region.s | 27 +++++++++++++++++++++++++++
 2 files changed, 31 insertions(+)
 create mode 100644 lld/test/ELF/mips-micro-jump-region.s

diff --git a/lld/ELF/Arch/Mips.cpp b/lld/ELF/Arch/Mips.cpp
index ba751660df1fa..308a0f75e588d 100644
--- a/lld/ELF/Arch/Mips.cpp
+++ b/lld/ELF/Arch/Mips.cpp
@@ -907,6 +907,10 @@ void MIPS<ELFT>::relocate(uint8_t *loc, const Relocation &rel,
     writeValue(ctx, loc, val, 32, 0);
     break;
   case R_MICROMIPS_26_S1:
+    // Like R_MIPS_26, this encodes an index within the current PC region,
+    // not a signed absolute address. The destination need not fit in 27 bits.
+    writeShuffle<e>(ctx, loc, val, 26, 1);
+    break;
   case R_MICROMIPS_PC26_S1:
     checkInt(ctx, loc, val, 27, rel);
     writeShuffle<e>(ctx, loc, val, 26, 1);
diff --git a/lld/test/ELF/mips-micro-jump-region.s b/lld/test/ELF/mips-micro-jump-region.s
new file mode 100644
index 0000000000000..ceb604f561911
--- /dev/null
+++ b/lld/test/ELF/mips-micro-jump-region.s
@@ -0,0 +1,27 @@
+# REQUIRES: mips
+# RUN: llvm-mc -triple=mipsel -mcpu=mips32r2 -mattr=+micromips -filetype=obj %s -o %t.le.o
+# RUN: ld.lld -Ttext=0x80100000 %t.le.o -o %t.le
+# RUN: llvm-objdump -s -j .text %t.le | FileCheck %s --check-prefix=LE
+# RUN: llvm-mc -triple=mips -mcpu=mips32r2 -mattr=+micromips -filetype=obj %s -o %t.be.o
+# RUN: ld.lld -Ttext=0x80100000 %t.be.o -o %t.be
+# RUN: llvm-objdump -s -j .text %t.be | FileCheck %s --check-prefix=BE
+
+## The jump index occupies 26 bits within the current PC region; the full
+## destination address need not fit in a signed 27-bit value.
+## Both a tail jump and a call must retain the low 27 address bits.
+# LE: 80100000 08d40800 00000000 08f40800 00000000
+# BE: 80100000 d4080008 00000000 f4080008 00000000
+
+.set micromips
+.set noreorder
+.globl __start, target
+.type __start, at function
+__start:
+  j target
+  sll $0, $0, 0
+  jal target
+  sll $0, $0, 0
+.type target, at function
+target:
+  jr $ra
+  sll $0, $0, 0



More information about the llvm-commits mailing list