Skip to content

Commit 4aea677

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 4aea677

File tree

2 files changed

+66
-2
lines changed

2 files changed

+66
-2
lines changed

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

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,26 @@
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+
Bits += 2;
40+
if (!isIntN(Bits, Value)) {
41+
Ctx.reportError(Fixup.getLoc(), "branch target out of range (" +
42+
Twine(SVal) + " not between " +
43+
Twine(minIntN(Bits)) + " and " +
44+
Twine(maxIntN(Bits)) + ")");
45+
}
46+
};
47+
2948
switch (Kind) {
3049
default:
3150
llvm_unreachable("Unknown fixup kind!");
@@ -37,10 +56,12 @@ static uint64_t adjustFixupValue(unsigned Kind, uint64_t Value) {
3756
return Value;
3857
case PPC::fixup_ppc_brcond14:
3958
case PPC::fixup_ppc_brcond14abs:
59+
checkBrFixup(14);
4060
return Value & 0xfffc;
4161
case PPC::fixup_ppc_br24:
4262
case PPC::fixup_ppc_br24abs:
4363
case PPC::fixup_ppc_br24_notoc:
64+
checkBrFixup(24);
4465
return Value & 0x3fffffc;
4566
case PPC::fixup_ppc_half16:
4667
return Value & 0xffff;
@@ -202,7 +223,7 @@ void PPCAsmBackend::applyFixup(const MCFragment &F, const MCFixup &Fixup,
202223
MCFixupKind Kind = Fixup.getKind();
203224
if (mc::isRelocation(Kind))
204225
return;
205-
Value = adjustFixupValue(Kind, Value);
226+
Value = adjustFixupValue(getContext(), Fixup, Kind, Value);
206227
if (!Value)
207228
return; // Doesn't change encoding.
208229

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 32767)
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 32767)
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 33554431)
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 33554431)
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)