Skip to content

Commit 1f5c2f8

Browse files
bmourad01bmourad01
andauthored
Perform naiive branch relaxing (and other fixes to the BIR passes) (#210)
* Collect code addrs for the verifier if `init-mem` is `true` * Fix failing test * Update * Fix use of `init-mem` field Also pretty-print it with the rest of the WP params * Only finalize higher vars at the implicit exit Any explicit exits (blocks that short-circuit the flow of the patch away from the original flow of the program) are assumed to not need the higher vars * Adds the pattern for `ldr rt, [rn, rm, #lsl n]` Where `n` is a power of two. It's common to see this with array accesses. * Adds branch relaxing, splits blocks with conditional jumps 1. We need branch relaxing if the patch needs to perform a conditional branch to some far away region of code. In this case, the assembler will fail because the branch is too far away. We break it apart into a conditional branch to a local block, followed by an unconditional branch to the desired location if the condition is met. 2. The higher vars initialization may clobber the flags if it occurs at the same time as a `cmp x, y; bcc loc`. The scheduler is unaware that on Thumb, many instructions will implicitly set the flags. * Fix tests and break up the spilling pass * Cut down minizinc time on `arm-bounds-check` * Relaxation only applies to Thumb Co-authored-by: bmourad01 <[email protected]>
1 parent 21231f0 commit 1f5c2f8

File tree

11 files changed

+410
-175
lines changed

11 files changed

+410
-175
lines changed

bap-vibes/src/arm_selector.ml

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -478,6 +478,17 @@ module ARM_ops = struct
478478
let sem = {sem with current_data = op::sem.current_data} in
479479
{op_val = Ir.Var res; op_eff = sem}
480480

481+
let quadop o ty arg1 arg2 arg3 arg4 =
482+
let res = create_temp ty in
483+
let {op_val = arg1_val; op_eff = arg1_sem} = arg1 in
484+
let {op_val = arg2_val; op_eff = arg2_sem} = arg2 in
485+
let {op_val = arg3_val; op_eff = arg3_sem} = arg3 in
486+
let {op_val = arg4_val; op_eff = arg4_sem} = arg4 in
487+
let op = Ir.simple_op o (Ir.Var res) [arg1_val; arg2_val; arg3_val; arg4_val] in
488+
let sem = arg1_sem @. arg2_sem @. arg3_sem @. arg4_sem in
489+
let sem = {sem with current_data = op::sem.current_data} in
490+
{op_val = Ir.Var res; op_eff = sem}
491+
481492
let add (arg1 : arm_pure) (arg2 : arm_pure)
482493
~(is_thumb : bool) : arm_pure KB.t =
483494
KB.return @@ binop Ops.(add is_thumb) word_ty arg1 arg2 ~is_thumb
@@ -822,6 +833,19 @@ struct
822833
let exp = select_exp ~patch ~is_thumb ~branch:None ~lhs:None in
823834
let exp_binop_integer = select_exp_binop_integer ~patch ~is_thumb in
824835
match e with
836+
| Load (mem, BinOp (PLUS, a, BinOp (TIMES, Int s, b)), _, size)
837+
when Int.is_pow2 @@ Word.to_int_exn s ->
838+
let* mem = exp mem in
839+
let* ldr = ldr_op @@ Size.in_bits size in
840+
let* a = exp a in
841+
let+ b = exp b in
842+
let width = Word.bitwidth s in
843+
let s =
844+
const @@
845+
Word.of_int ~width @@
846+
Int.ctz @@
847+
Word.to_int_exn s in
848+
quadop ldr word_ty mem a b s
825849
| Load (mem, BinOp (PLUS, a, Int w), _, size) ->
826850
let* mem = exp mem in
827851
let* ldr = ldr_op @@ Size.in_bits size in
@@ -1157,7 +1181,7 @@ module Pretty = struct
11571181

11581182
type bracket = Open | Close | Neither | Both
11591183

1160-
let arm_operand_pretty (op : string) (o : Ir.operand)
1184+
let arm_operand_pretty (op : string) (o : Ir.operand) (i : int)
11611185
~(is_loc : bracket) : (string, Kb_error.t) result =
11621186
let pretty_aux =
11631187
match o with
@@ -1171,11 +1195,12 @@ module Pretty = struct
11711195
let prefix = match op with
11721196
| "ldr" -> begin
11731197
match is_loc with
1174-
| Neither -> '='
1175-
| _ -> '#'
1198+
| Neither -> "="
1199+
| Close when i = 3 -> "lsl #"
1200+
| _ -> "#"
11761201
end
1177-
| _ -> '#' in
1178-
Result.return @@ Format.asprintf "%c%a" prefix Word.pp_dec w
1202+
| _ -> "#" in
1203+
Result.return @@ Format.asprintf "%s%a" prefix Word.pp_dec w
11791204
| Label l -> Result.return @@ tid_to_string l
11801205
| Void _ -> Result.fail @@ Kb_error.Other "Tried printing a Void operand!"
11811206
| Offset c ->
@@ -1215,6 +1240,7 @@ module Pretty = struct
12151240
| "ldr" | "ldrh" | "ldrb" | "str" ->
12161241
if len = 2 then Result.return [Neither; Both]
12171242
else if len = 3 then Result.return [Neither; Open; Close]
1243+
else if len = 4 then Result.return [Neither; Open; Neither; Close]
12181244
else Result.fail @@ Kb_error.Other (
12191245
sprintf "mk_loc_list: expected to receive 2 or 3 arguments, \
12201246
got %d (op = %s)" len op)
@@ -1250,7 +1276,7 @@ module Pretty = struct
12501276
let l = rm_void_args (lhs @ rhs) in
12511277
mk_loc_list op l >>= fun is_loc_list ->
12521278
List.zip_exn is_loc_list l |>
1253-
List.map ~f:(fun (is_loc, o) -> arm_operand_pretty op o ~is_loc) |>
1279+
List.mapi ~f:(fun i (is_loc, o) -> arm_operand_pretty op o i ~is_loc) |>
12541280
Result.all >>| fun all_str ->
12551281
String.concat @@ List.intersperse all_str ~sep:", "
12561282

bap-vibes/src/bir_helpers.ml

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,12 @@ let create_sub (blks : blk term list) : sub term KB.t =
2828
let is_implicit_exit (blk : blk term) : bool =
2929
Seq.is_empty @@ Term.enum jmp_t blk
3030

31+
(* Returns true if the jmp is unconditional. *)
32+
let is_unconditional (jmp : jmp term) : bool =
33+
match Jmp.cond jmp with
34+
| Int w -> Word.(w = b1)
35+
| _ -> false
36+
3137
(* Find the exit nodes of the patch code. They are classified as follows:
3238
- no jmps:
3339
this is implicitly an exit block since it has no successors
@@ -53,19 +59,20 @@ let exit_blks (blks : blk term list) : blk term list KB.t =
5359
let blk = Graphs.Ir.Node.label node in
5460
if Graphs.Ir.Node.degree node cfg ~dir:`Out = 0
5561
then Some blk
56-
else
57-
let jmps = Term.enum jmp_t blk in
58-
if Seq.is_empty jmps then Some blk
59-
else if Seq.exists jmps ~f:(fun jmp ->
60-
match Jmp.kind jmp with
61-
| Call call -> begin
62-
match Call.return call with
63-
| None | Some (Indirect _) -> true
64-
| _ -> false
65-
end
66-
| _ -> false)
67-
then Some blk
68-
else None)
62+
else match Term.enum jmp_t blk |> Seq.to_list with
63+
| [] -> Some blk
64+
| [jmp] when not @@ is_unconditional jmp -> Some blk
65+
| jmps ->
66+
if List.exists jmps ~f:(fun jmp ->
67+
match Jmp.kind jmp with
68+
| Call call -> begin
69+
match Call.return call with
70+
| None | Some (Indirect _) -> true
71+
| _ -> false
72+
end
73+
| _ -> false)
74+
then Some blk
75+
else None)
6976

7077
(* Returns true if the block contains a call to a subroutine. *)
7178
let has_call (blk : blk term) : bool =
@@ -78,9 +85,3 @@ let has_call (blk : blk term) : bool =
7885
let call_blks (blks : blk term list) : tid list =
7986
List.filter_map blks ~f:(fun blk ->
8087
if has_call blk then Some (Term.tid blk) else None)
81-
82-
(* Returns true if the jmp is unconditional. *)
83-
let is_unconditional (jmp : jmp term) : bool =
84-
match Jmp.cond jmp with
85-
| Int w -> Word.(w = b1)
86-
| _ -> false

0 commit comments

Comments
 (0)