diff --git a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCAsmBackend.cpp b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCAsmBackend.cpp index 04b886ae74993..5ff5115fcecab 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; @@ -202,7 +222,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