[llvm] [PowerPC][MC] Diagnose out of range branch fixups (PR #165859)

Nikita Popov via llvm-commits llvm-commits at lists.llvm.org
Mon Dec 1 03:16:10 PST 2025


https://github.com/nikic updated https://github.com/llvm/llvm-project/pull/165859

>From 6942aa0cd89522fc00ed5cf7fdf67303b714ad2d Mon Sep 17 00:00:00 2001
From: Nikita Popov <npopov at redhat.com>
Date: Fri, 31 Oct 2025 13:12:48 +0100
Subject: [PATCH 1/2] [PowerPC][MC] Diagnose out of range branch fixups

Currently, out-of-range branch fixups will be silently miscompiled.
GNU as will instead print a message like:

> Error: operand out of range (0x0000000000010004 is not between 0xffffffffffff8000 and 0x0000000000007ffc)

Check that the branch target fixups fit into the proper range and
have low zero bits.

I'm not sure if there is any way to test the absolute cases. It
looks like something like `beqa 0, 0x10000` already gets rejected
during parsing.

(My actual interest here is not actually assembly usage, but LLVM
producing invalid branches for reasons I've not tracked down yet.
Currently this just silently truncates the branch target, and I'd
rather make it produce an error instead.)
---
 .../PowerPC/MCTargetDesc/PPCAsmBackend.cpp    | 24 ++++++++++-
 llvm/test/MC/PowerPC/fixup-out-of-range.s     | 43 +++++++++++++++++++
 2 files changed, 65 insertions(+), 2 deletions(-)
 create mode 100644 llvm/test/MC/PowerPC/fixup-out-of-range.s

diff --git a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCAsmBackend.cpp b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCAsmBackend.cpp
index 558351b515a2e..72a5e60a01d87 100644
--- a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCAsmBackend.cpp
+++ b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCAsmBackend.cpp
@@ -25,7 +25,25 @@
 #include "llvm/Support/ErrorHandling.h"
 using namespace llvm;
 
-static uint64_t adjustFixupValue(unsigned Kind, uint64_t Value) {
+static uint64_t adjustFixupValue(MCContext &Ctx, const MCFixup &Fixup,
+                                 unsigned Kind, uint64_t Value) {
+  auto checkBrFixup = [&](unsigned Bits) {
+    int64_t SVal = int64_t(Value);
+    if ((Value & 3) != 0) {
+      Ctx.reportError(Fixup.getLoc(), "branch target not a multiple of four (" +
+                                          Twine(SVal) + ")");
+      return;
+    }
+
+    // Low two bits are not encoded.
+    if (!isIntN(Bits + 2, Value)) {
+      Ctx.reportError(Fixup.getLoc(), "branch target out of range (" +
+                                          Twine(SVal) + " not between " +
+                                          Twine(minIntN(Bits) * 4) + " and " +
+                                          Twine(maxIntN(Bits) * 4) + ")");
+    }
+  };
+
   switch (Kind) {
   default:
     llvm_unreachable("Unknown fixup kind!");
@@ -37,10 +55,12 @@ static uint64_t adjustFixupValue(unsigned Kind, uint64_t Value) {
     return Value;
   case PPC::fixup_ppc_brcond14:
   case PPC::fixup_ppc_brcond14abs:
+    checkBrFixup(14);
     return Value & 0xfffc;
   case PPC::fixup_ppc_br24:
   case PPC::fixup_ppc_br24abs:
   case PPC::fixup_ppc_br24_notoc:
+    checkBrFixup(24);
     return Value & 0x3fffffc;
   case PPC::fixup_ppc_half16:
     return Value & 0xffff;
@@ -211,7 +231,7 @@ void PPCAsmBackend::applyFixup(const MCFragment &F, const MCFixup &Fixup,
   MCFixupKind Kind = Fixup.getKind();
   if (mc::isRelocation(Kind))
     return;
-  Value = adjustFixupValue(Kind, Value);
+  Value = adjustFixupValue(getContext(), Fixup, Kind, Value);
   if (!Value)
     return; // Doesn't change encoding.
 
diff --git a/llvm/test/MC/PowerPC/fixup-out-of-range.s b/llvm/test/MC/PowerPC/fixup-out-of-range.s
new file mode 100644
index 0000000000000..ccb9f886cae49
--- /dev/null
+++ b/llvm/test/MC/PowerPC/fixup-out-of-range.s
@@ -0,0 +1,43 @@
+# RUN: not llvm-mc -triple powerpc64le-unknown-unknown -filetype=obj %s 2>&1 >/dev/null | FileCheck %s
+
+# CHECK: error: branch target out of range (32772 not between -32768 and 32764)
+brcond14_out_of_range_hi:
+    beq 0, brcond14_target
+    .space 0x8000
+
+brcond14_target:
+    blr
+
+# CHECK: error: branch target out of range (-32772 not between -32768 and 32764)
+brcond14_out_of_range_lo:
+    .space 0x8004
+    beq 0, brcond14_out_of_range_lo
+
+# CHECK: error: branch target not a multiple of four (5)
+brcond14_misaligned:
+    beq 0, brcond14_misaligned_target
+    .byte 0
+
+brcond14_misaligned_target:
+    blr
+
+# CHECK: error: branch target out of range (33554436 not between -33554432 and 33554428)
+br24_out_of_range_hi:
+    b br24_target
+    .space 0x2000000
+
+br24_target:
+    blr
+
+# CHECK: error: branch target out of range (-33554436 not between -33554432 and 33554428)
+br24_out_of_range_lo:
+    .space 0x2000004
+    b br24_out_of_range_lo
+
+# CHECK: error: branch target not a multiple of four (5)
+br24_misaligned:
+    b br24_misaligned_target
+    .byte 0
+
+br24_misaligned_target:
+    blr

>From f4eead4d6e05867b3ce0dad83c7eb8dbf2d6ffb6 Mon Sep 17 00:00:00 2001
From: Nikita Popov <npopov at redhat.com>
Date: Mon, 1 Dec 2025 12:11:21 +0100
Subject: [PATCH 2/2] Add tests for abs case using expression

---
 llvm/test/MC/PowerPC/fixup-out-of-range.s | 48 +++++++++++++++++++++++
 1 file changed, 48 insertions(+)

diff --git a/llvm/test/MC/PowerPC/fixup-out-of-range.s b/llvm/test/MC/PowerPC/fixup-out-of-range.s
index ccb9f886cae49..a036b4e232815 100644
--- a/llvm/test/MC/PowerPC/fixup-out-of-range.s
+++ b/llvm/test/MC/PowerPC/fixup-out-of-range.s
@@ -21,6 +21,31 @@ brcond14_misaligned:
 brcond14_misaligned_target:
     blr
 
+
+
+# CHECK: error: branch target out of range (32772 not between -32768 and 32764)
+brcond14abs_out_of_range_hi:
+    beqa 0, brcond14abs_target-.
+    .space 0x8000
+
+brcond14abs_target:
+    blr
+
+# CHECK: error: branch target out of range (-32772 not between -32768 and 32764)
+brcond14abs_out_of_range_lo:
+    .space 0x8004
+    beqa 0, brcond14abs_out_of_range_lo-.
+
+# CHECK: error: branch target not a multiple of four (5)
+brcond14abs_misaligned:
+    beqa 0, brcond14abs_misaligned_target-.
+    .byte 0
+
+brcond14abs_misaligned_target:
+    blr
+
+
+
 # CHECK: error: branch target out of range (33554436 not between -33554432 and 33554428)
 br24_out_of_range_hi:
     b br24_target
@@ -41,3 +66,26 @@ br24_misaligned:
 
 br24_misaligned_target:
     blr
+
+
+
+# CHECK: error: branch target out of range (33554436 not between -33554432 and 33554428)
+br24abs_out_of_range_hi:
+    ba br24abs_target-.
+    .space 0x2000000
+
+br24abs_target:
+    blr
+
+# CHECK: error: branch target out of range (-33554436 not between -33554432 and 33554428)
+br24abs_out_of_range_lo:
+    .space 0x2000004
+    ba br24abs_out_of_range_lo-.
+
+# CHECK: error: branch target not a multiple of four (5)
+br24abs_misaligned:
+    ba br24abs_misaligned_target-.
+    .byte 0
+
+br24abs_misaligned_target:
+    blr



More information about the llvm-commits mailing list