Skip to content

Commit b90c64a

Browse files
nikickcloudy0717
authored andcommitted
[PowerPC][MC] Diagnose out of range branch fixups (llvm#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.)
1 parent f57e90a commit b90c64a

File tree

2 files changed

+113
-2
lines changed

2 files changed

+113
-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;
@@ -211,7 +231,7 @@ void PPCAsmBackend::applyFixup(const MCFragment &F, const MCFixup &Fixup,
211231
MCFixupKind Kind = Fixup.getKind();
212232
if (mc::isRelocation(Kind))
213233
return;
214-
Value = adjustFixupValue(Kind, Value);
234+
Value = adjustFixupValue(getContext(), Fixup, Kind, Value);
215235
if (!Value)
216236
return; // Doesn't change encoding.
217237

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
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+
25+
26+
# CHECK: error: branch target out of range (32772 not between -32768 and 32764)
27+
brcond14abs_out_of_range_hi:
28+
beqa 0, brcond14abs_target-.
29+
.space 0x8000
30+
31+
brcond14abs_target:
32+
blr
33+
34+
# CHECK: error: branch target out of range (-32772 not between -32768 and 32764)
35+
brcond14abs_out_of_range_lo:
36+
.space 0x8004
37+
beqa 0, brcond14abs_out_of_range_lo-.
38+
39+
# CHECK: error: branch target not a multiple of four (5)
40+
brcond14abs_misaligned:
41+
beqa 0, brcond14abs_misaligned_target-.
42+
.byte 0
43+
44+
brcond14abs_misaligned_target:
45+
blr
46+
47+
48+
49+
# CHECK: error: branch target out of range (33554436 not between -33554432 and 33554428)
50+
br24_out_of_range_hi:
51+
b br24_target
52+
.space 0x2000000
53+
54+
br24_target:
55+
blr
56+
57+
# CHECK: error: branch target out of range (-33554436 not between -33554432 and 33554428)
58+
br24_out_of_range_lo:
59+
.space 0x2000004
60+
b br24_out_of_range_lo
61+
62+
# CHECK: error: branch target not a multiple of four (5)
63+
br24_misaligned:
64+
b br24_misaligned_target
65+
.byte 0
66+
67+
br24_misaligned_target:
68+
blr
69+
70+
71+
72+
# CHECK: error: branch target out of range (33554436 not between -33554432 and 33554428)
73+
br24abs_out_of_range_hi:
74+
ba br24abs_target-.
75+
.space 0x2000000
76+
77+
br24abs_target:
78+
blr
79+
80+
# CHECK: error: branch target out of range (-33554436 not between -33554432 and 33554428)
81+
br24abs_out_of_range_lo:
82+
.space 0x2000004
83+
ba br24abs_out_of_range_lo-.
84+
85+
# CHECK: error: branch target not a multiple of four (5)
86+
br24abs_misaligned:
87+
ba br24abs_misaligned_target-.
88+
.byte 0
89+
90+
br24abs_misaligned_target:
91+
blr

0 commit comments

Comments
 (0)