Skip to content

Commit 5f4bf6a

Browse files
committed
[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.)
1 parent 8177965 commit 5f4bf6a

File tree

2 files changed

+65
-2
lines changed

2 files changed

+65
-2
lines changed

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

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,25 @@
2525
#include "llvm/Support/ErrorHandling.h"
2626
using namespace llvm;
2727

28-
static uint64_t adjustFixupValue(unsigned Kind, uint64_t Value) {
28+
static uint64_t adjustFixupValue(MCContext &Ctx, const MCFixup &Fixup,
29+
unsigned Kind, uint64_t Value) {
30+
auto checkBrFixup = [&](unsigned Bits) {
31+
int64_t SVal = int64_t(Value);
32+
if ((Value & 3) != 0) {
33+
Ctx.reportError(Fixup.getLoc(), "branch target not a multiple of four (" +
34+
Twine(SVal) + ")");
35+
return;
36+
}
37+
38+
// Low two bits are not encoded.
39+
if (!isIntN(Bits + 2, Value)) {
40+
Ctx.reportError(Fixup.getLoc(), "branch target out of range (" +
41+
Twine(SVal) + " not between " +
42+
Twine(minIntN(Bits) * 4) + " and " +
43+
Twine(maxIntN(Bits) * 4) + ")");
44+
}
45+
};
46+
2947
switch (Kind) {
3048
default:
3149
llvm_unreachable("Unknown fixup kind!");
@@ -37,10 +55,12 @@ static uint64_t adjustFixupValue(unsigned Kind, uint64_t Value) {
3755
return Value;
3856
case PPC::fixup_ppc_brcond14:
3957
case PPC::fixup_ppc_brcond14abs:
58+
checkBrFixup(14);
4059
return Value & 0xfffc;
4160
case PPC::fixup_ppc_br24:
4261
case PPC::fixup_ppc_br24abs:
4362
case PPC::fixup_ppc_br24_notoc:
63+
checkBrFixup(24);
4464
return Value & 0x3fffffc;
4565
case PPC::fixup_ppc_half16:
4666
return Value & 0xffff;
@@ -202,7 +222,7 @@ void PPCAsmBackend::applyFixup(const MCFragment &F, const MCFixup &Fixup,
202222
MCFixupKind Kind = Fixup.getKind();
203223
if (mc::isRelocation(Kind))
204224
return;
205-
Value = adjustFixupValue(Kind, Value);
225+
Value = adjustFixupValue(getContext(), Fixup, Kind, Value);
206226
if (!Value)
207227
return; // Doesn't change encoding.
208228

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# RUN: not llvm-mc -triple powerpc64le-unknown-unknown -filetype=obj %s 2>&1 >/dev/null | FileCheck %s
2+
3+
# CHECK: error: branch target out of range (32772 not between -32768 and 32764)
4+
brcond14_out_of_range_hi:
5+
beq 0, brcond14_target
6+
.space 0x8000
7+
8+
brcond14_target:
9+
blr
10+
11+
# CHECK: error: branch target out of range (-32772 not between -32768 and 32764)
12+
brcond14_out_of_range_lo:
13+
.space 0x8004
14+
beq 0, brcond14_out_of_range_lo
15+
16+
# CHECK: error: branch target not a multiple of four (5)
17+
brcond14_misaligned:
18+
beq 0, brcond14_misaligned_target
19+
.byte 0
20+
21+
brcond14_misaligned_target:
22+
blr
23+
24+
# CHECK: error: branch target out of range (33554436 not between -33554432 and 33554428)
25+
br24_out_of_range_hi:
26+
b br24_target
27+
.space 0x2000000
28+
29+
br24_target:
30+
blr
31+
32+
# CHECK: error: branch target out of range (-33554436 not between -33554432 and 33554428)
33+
br24_out_of_range_lo:
34+
.space 0x2000004
35+
b br24_out_of_range_lo
36+
37+
# CHECK: error: branch target not a multiple of four (5)
38+
br24_misaligned:
39+
b br24_misaligned_target
40+
.byte 0
41+
42+
br24_misaligned_target:
43+
blr

0 commit comments

Comments
 (0)