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

via llvm-commits llvm-commits at lists.llvm.org
Mon Dec 1 22:04:07 PST 2025


Author: Nikita Popov
Date: 2025-12-02T07:04:03+01:00
New Revision: 4522448cd16489b84c80ec39ae06960b01fd3b59

URL: https://github.com/llvm/llvm-project/commit/4522448cd16489b84c80ec39ae06960b01fd3b59
DIFF: https://github.com/llvm/llvm-project/commit/4522448cd16489b84c80ec39ae06960b01fd3b59.diff

LOG: [PowerPC][MC] Diagnose out of range branch fixups (#165859)

Currently, out-of-range branch fixups will be silently miscompiled. GNU
as will instead print an "operand out of range" error instead.

Check that the branch target fixups fit into the proper range and have
low zero bits. The implementation is inspired by SystemZ:
https://github.com/llvm/llvm-project/blob/0ed8e66f88b689c152245d6b968a06fa8e67b51f/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmBackend.cpp#L31

(My actual interest here is not actually assembly usage, but LLVM
failing to use the correct branch kind for reasons I've not tracked down
yet. Currently this just silently truncates the branch target instead of
producing an error.)

Added: 
    llvm/test/MC/PowerPC/fixup-out-of-range.s

Modified: 
    llvm/lib/Target/PowerPC/MCTargetDesc/PPCAsmBackend.cpp

Removed: 
    


################################################################################
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..a036b4e232815
--- /dev/null
+++ b/llvm/test/MC/PowerPC/fixup-out-of-range.s
@@ -0,0 +1,91 @@
+# 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 (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
+    .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
+
+
+
+# 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