Skip to content

Commit

Permalink
[Thumb] Validate branch target for CBZ/CBNZ instructions.
Browse files Browse the repository at this point in the history
Summary:
The assembler currently does not check the branch target for CBZ/CBNZ
instructions, which only permit branching forwards with a positive offset. This
adds validation for the branch target to ensure negative PC-relative offsets are
not encoded into the instruction, whether specified as a literal or as an
assembler symbol.

Reviewers: rengolin, t.p.northover

Subscribers: llvm-commits, rengolin

Differential Revision: https://reviews.llvm.org/D23312

llvm-svn: 278659
  • Loading branch information
Prakhar Bahuguna committed Aug 15, 2016
1 parent 196ad08 commit a305a43
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 0 deletions.
6 changes: 6 additions & 0 deletions llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6684,6 +6684,12 @@ bool ARMAsmParser::validateInstruction(MCInst &Inst,
return Error(Operands[Op]->getStartLoc(), "branch target out of range");
break;
}
case ARM::tCBZ:
case ARM::tCBNZ: {
if (!static_cast<ARMOperand &>(*Operands[2]).isUnsignedOffset<6, 1>())
return Error(Operands[2]->getStartLoc(), "branch target out of range");
break;
}
case ARM::MOVi16:
case ARM::t2MOVi16:
case ARM::t2MOVTi16:
Expand Down
5 changes: 5 additions & 0 deletions llvm/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -578,6 +578,11 @@ unsigned ARMAsmBackend::adjustFixupValue(const MCFixup &Fixup, uint64_t Value,
// Offset by 4, and don't encode the low two bits.
return ((Value - 4) >> 2) & 0xff;
case ARM::fixup_arm_thumb_cb: {
// CB instructions can only branch to offsets in [0, 126] in multiples of 2
if (Ctx && ((int64_t)Value < 0 || Value > 0x3e || Value & 1)) {
Ctx->reportError(Fixup.getLoc(), "out of range pc-relative fixup value");
return 0;
}
// Offset by 4 and don't encode the lower bit, which is always 0.
// FIXME: diagnose if no Thumb2
uint32_t Binary = (Value - 4) >> 1;
Expand Down
19 changes: 19 additions & 0 deletions llvm/test/MC/ARM/thumb-cb-negative-offsets.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
@ RUN: not llvm-mc -triple thumbv7m-none-eabi -filetype=obj -o /dev/null %s 2>&1 | FileCheck %s
@ RUN: not llvm-mc -triple thumbv8m.base-none-eabi -filetype=obj -o /dev/null %s 2>&1 | FileCheck %s

label0:
.word 4

@ CHECK: out of range pc-relative fixup value
cbz r0, label0
@ CHECK: out of range pc-relative fixup value
cbnz r0, label0

@ CHECK: out of range pc-relative fixup value
cbz r0, label1
@ CHECK: out of range pc-relative fixup value
cbnz r0, label1

.space 1000
label1:
.word 4
17 changes: 17 additions & 0 deletions llvm/test/MC/ARM/thumb-diagnostics.s
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,23 @@ error: invalid operand for instruction
@ CHECK-ERRORS: error: branch target out of range
@ CHECK-ERRORS: error: branch target out of range

@------------------------------------------------------------------------------
@ CBZ/CBNZ - out of range immediates for branches
@------------------------------------------------------------------------------

cbz r0, #-2
cbz r0, #0
cbz r0, #17
cbnz r0, #126
cbnz r0, #128

@ CHECK-ERRORS-V7M: error: branch target out of range
@ CHECK-ERRORS-V7M: error: invalid operand for instruction
@ CHECK-ERRORS-V7M: error: branch target out of range
@ CHECK-ERRORS-V8: error: branch target out of range
@ CHECK-ERRORS-V8: error: invalid operand for instruction
@ CHECK-ERRORS-V8: error: branch target out of range

@------------------------------------------------------------------------------
@ SEV/WFE/WFI/YIELD - are not supported pre v6M or v6T2
@------------------------------------------------------------------------------
Expand Down

0 comments on commit a305a43

Please sign in to comment.