Skip to content

Commit 4e64750

Browse files
committed
CHB:ARM: add ADDLS PC, PC jumptable
1 parent 153fa9c commit 4e64750

File tree

8 files changed

+175
-19
lines changed

8 files changed

+175
-19
lines changed

CodeHawk/CHB/bchlibarm32/bCHARMAssemblyInstructions.ml

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -382,17 +382,18 @@ object (self)
382382
let saddr = jumptable#get_start_address in
383383
let eaddr = jumptable#get_end_address in
384384
let len = saddr#value - eaddr#value in
385-
let startinstr =
386-
make_arm_assembly_instruction
387-
saddr true (NotCode (Some (JumpTable jumptable))) "" in
388-
begin
389-
set_instruction saddr startinstr;
390-
for i = 1 to (len - 1) do
391-
let va = saddr#add_int i in
392-
set_instruction
393-
va (make_arm_assembly_instruction va true (NotCode None) "")
394-
done
395-
end
385+
if len > 0 then
386+
let startinstr =
387+
make_arm_assembly_instruction
388+
saddr true (NotCode (Some (JumpTable jumptable))) "" in
389+
begin
390+
set_instruction saddr startinstr;
391+
for i = 1 to (len - 1) do
392+
let va = saddr#add_int i in
393+
set_instruction
394+
va (make_arm_assembly_instruction va true (NotCode None) "")
395+
done
396+
end
396397

397398
method get_next_valid_instruction_address
398399
(va: doubleword_int): doubleword_int TR.traceresult =

CodeHawk/CHB/bchlibarm32/bCHARMInstructionAggregate.ml

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
(* =============================================================================
2-
CodeHawk Binary Analyzer
2+
CodeHawk Binary Analyzer
33
Author: Henny Sipma
44
------------------------------------------------------------------------------
55
The MIT License (MIT)
6-
6+
77
Copyright (c) 2022-2024 Aarno Labs, LLC
88
99
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -12,10 +12,10 @@
1212
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1313
copies of the Software, and to permit persons to whom the Software is
1414
furnished to do so, subject to the following conditions:
15-
15+
1616
The above copyright notice and this permission notice shall be included in all
1717
copies or substantial portions of the Software.
18-
18+
1919
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2020
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2121
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@@ -117,7 +117,9 @@ object (self)
117117
LBLOCK [
118118
STR "Aggregate of ";
119119
INT (List.length self#instrs);
120-
STR " instructions: ";
120+
STR " with anchor ";
121+
self#anchor#toPretty;
122+
STR " and instructions: ";
121123
STR (arm_aggregate_kind_to_string self#kind)]
122124

123125
end
@@ -203,6 +205,9 @@ let identify_jumptable
203205
| Add (_, ACCAlways, rd, rn, _, false)
204206
when rd#is_pc_register && rn#is_pc_register ->
205207
create_arm_add_pc_jumptable ch instr
208+
| Add (_, ACCNotUnsignedHigher, rd, rn, _, false)
209+
when rd#is_pc_register && rn#is_pc_register ->
210+
create_addls_pc_jumptable ch instr
206211
| BranchExchange (ACCAlways, regop) when regop#is_register ->
207212
create_arm_bx_jumptable ch instr
208213
| _ -> None
@@ -225,7 +230,7 @@ let identify_ldmstm_sequence
225230
when List.length rl#get_register_list > 1 ->
226231
create_ldm_stm_sequence ch instr
227232
| _ -> None
228-
233+
229234

230235
let identify_arm_aggregate
231236
(ch: pushback_stream_int)

CodeHawk/CHB/bchlibarm32/bCHARMJumptable.ml

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -586,6 +586,74 @@ let create_arm_ldrls_jumptable
586586
| _ -> None)
587587

588588

589+
(* ADDLS pattern (in ARM)
590+
591+
[4 bytes] CMP indexreg, maxcase
592+
[4 bytes] ADDLS PC, PC, indexreg, LSL#2
593+
[4 bytes] B default case
594+
[4 bytes] B case 0
595+
[...] B
596+
[4 bytes] B case maxcase
597+
*)
598+
let is_addls_pc_jumptable
599+
(addpcinstr: arm_assembly_instruction_int):
600+
(arm_assembly_instruction_int (* CMP instr *)
601+
* arm_assembly_instruction_int) option = (* ADDLS instr *)
602+
match addpcinstr#get_opcode with
603+
| Add (_, ACCNotUnsignedHigher, rd, rn, baseregop, false)
604+
when rd#is_pc_register
605+
&& rn#is_pc_register
606+
&& baseregop#is_shifted_register ->
607+
let addr = addpcinstr#get_address in
608+
let cmptestf (instr: arm_assembly_instruction_int) =
609+
match instr#get_opcode with
610+
| Compare (_, rn, imm, _) -> rn#is_register && imm#is_immediate
611+
| _ -> false in
612+
let optcmpinstr = find_instr cmptestf [(-4)] addr in
613+
(match optcmpinstr with
614+
| Some cmpinstr ->
615+
(match cmpinstr#get_opcode with
616+
| Compare (_, indexregop, _, _) ->
617+
let indexreg = indexregop#get_register in
618+
(match baseregop#get_kind with
619+
| ARMShiftedReg (basereg, ARMImmSRT (SRType_LSL, 2)) ->
620+
if basereg = indexreg then
621+
Some (cmpinstr, addpcinstr)
622+
else
623+
None
624+
| _ -> None)
625+
| _ -> None)
626+
| _ -> None)
627+
| _ -> None
628+
629+
630+
let create_addls_pc_jumptable
631+
(ch: pushback_stream_int)
632+
(addpcinstr: arm_assembly_instruction_int):
633+
(arm_assembly_instruction_int list * arm_jumptable_int) option =
634+
match is_addls_pc_jumptable addpcinstr with
635+
| None -> None
636+
| Some (cmpinstr, addlspcinstr) ->
637+
match cmpinstr#get_opcode with
638+
| Compare (_, index_operand, imm, _) ->
639+
let maxcase = imm#to_numerical#toInt in
640+
let iaddr = addlspcinstr#get_address in
641+
let default_target = iaddr#add_int 4 in
642+
let start_address = default_target in
643+
let end_address = default_target in
644+
let targets =
645+
List.init (maxcase + 1) (fun i -> (iaddr#add_int (8 + (4 * i)), i)) in
646+
let jt =
647+
make_arm_jumptable
648+
~end_address
649+
~start_address
650+
~default_target
651+
~targets
652+
~index_operand () in
653+
Some ([cmpinstr; addlspcinstr], jt)
654+
| _ -> None
655+
656+
589657
(* ADD-PC-LDRB patterns (in Thumb-2)
590658
591659
size is obtained from CMP instruction's immediate value

CodeHawk/CHB/bchlibarm32/bCHARMJumptable.mli

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,15 @@ val create_arm_ldrls_jumptable:
6262
-> (arm_assembly_instruction_int list * arm_jumptable_int) option
6363

6464

65+
(** [create_addls_pc_jumptable ch instr] creates a jump table targeted by an
66+
ADDLS instruction [instr] by processing the associated list of branch
67+
instructions from stream [ch] (ARM pattern).*)
68+
val create_addls_pc_jumptable:
69+
pushback_stream_int
70+
-> arm_assembly_instruction_int
71+
-> (arm_assembly_instruction_int list * arm_jumptable_int) option
72+
73+
6574
(** [create_arm_add_pc_jumptable ch instr] creates a jump table targeted by
6675
an ADD PC, PC, _ instruction [instr] by processing the associated list of
6776
(byte-sized or halfword-sized) offsets from stream [ch] (Thumb-2 pattern).*)

CodeHawk/CHB/bchlibarm32/bCHARMOperand.ml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -760,6 +760,11 @@ object (self:'a)
760760
| ARMShiftedReg (_, ARMImmSRT (SRType_LSL, 0)) -> true
761761
| _ -> false
762762

763+
method is_shifted_register =
764+
match kind with
765+
| ARMShiftedReg _ -> true
766+
| _ -> false
767+
763768
method is_pc_register =
764769
match kind with ARMReg ARPC -> true | _ -> false
765770

CodeHawk/CHB/bchlibarm32/bCHARMTypes.mli

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,7 @@ class type arm_operand_int =
200200
method is_immediate: bool
201201
method is_small_immediate: bool
202202
method is_register: bool
203+
method is_shifted_register: bool
203204
method is_pc_register: bool
204205
method is_double_register: bool
205206
method is_extension_register: bool

CodeHawk/CHB/bchlibarm32/bCHConstructARMFunction.ml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -472,6 +472,15 @@ let construct_arm_assembly_block
472472
(* aggregate is linear unit *)
473473
find_last_instruction (nextva ()) va
474474

475+
else if Option.is_some instr#is_in_aggregate
476+
&& instr#is_aggregate_exit
477+
&& (match instr#get_opcode with
478+
| Add (_, ACCNotUnsignedHigher, _, _, _, _) -> true
479+
| _ -> false) then
480+
(* the ADDLS aggregate must be forced to appear at the end of a block
481+
to ensure successors are connected.*)
482+
(None, va, [])
483+
475484
else if has_next_instr va then
476485
(* continue tracing the block *)
477486
find_last_instruction (nextva ()) va

CodeHawk/CHT/CHB_tests/bchlibarm32_tests/txbchlibarm32/bCHARMJumptableTest.ml

Lines changed: 60 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ open BCHARMInstructionAggregate
6161

6262

6363
let testname = "bCHARMJumptableTest"
64-
let lastupdated = "2024-01-02"
64+
let lastupdated = "2024-10-24"
6565

6666

6767
let make_dw (s: string) = TR.tget_ok (string_to_doubleword s)
@@ -136,6 +136,7 @@ let jt_setup_arm hexbase bytes: arm_jumptable_int TR.traceresult =
136136
let instrlen = currentpos - prevpos in
137137
let instrbytes = String.sub bytestring prevpos instrlen in
138138
let instr = add_instruction prevpos iaddr opcode instrbytes in
139+
(* let _ = CHPretty.pr_debug [instr#toPretty; NL; NL] in *)
139140
let optagg = identify_arm_aggregate ch instr in
140141
match optagg with
141142
| Some agg -> aggregate := Some agg
@@ -144,7 +145,9 @@ let jt_setup_arm hexbase bytes: arm_jumptable_int TR.traceresult =
144145
match !aggregate with
145146
| Some agg ->
146147
(match agg#kind with
147-
| ARMJumptable jt -> Ok jt
148+
| ARMJumptable jt ->
149+
(* let _ = CHPretty.pr_debug [jt#toPretty; NL; NL] in *)
150+
Ok jt
148151
| _ -> Error ["other aggregate found"])
149152
| _ ->
150153
Error ["no aggregate found:" ^ (string_of_int ch#pos)]
@@ -292,6 +295,60 @@ let ldrls_jumptable () =
292295
end
293296

294297

298+
(*
299+
0xa0132664 05 00 55 e3 CMP R5, #5
300+
0xa0132668 05 f1 8f 90 ADDLS PC, PC, R5,LSL#2
301+
0xa013266c 20 00 00 ea B 0xa01326f4
302+
B 0xa0132670 04 00 00 ea B 0xa0132688
303+
B 0xa0132674 09 00 00 ea B 0xa01326a0
304+
B 0xa0132678 0e 00 00 ea B 0xa01326b8
305+
B 0xa013267c 13 00 00 ea B 0xa01326d0
306+
B 0xa0132680 18 00 00 ea B 0xa01326e8
307+
B 0xa0132684 19 00 00 ea B 0xa01326f0
308+
*)
309+
let addls_pc_jumptable () =
310+
let tests = [
311+
("addls", "0xa0132664", "0xa013266c",
312+
"050055e305f18f90200000ea040000ea090000ea0e0000ea130000ea180000ea190000ea",
313+
[("0xa0132670", [0]);
314+
("0xa0132674", [1]);
315+
("0xa0132678", [2]);
316+
("0xa013267c", [3]);
317+
("0xa0132680", [4]);
318+
("0xa0132684", [5])])
319+
] in
320+
begin
321+
TS.new_testsuite (testname ^ "_ldrls_jumptable") lastupdated;
322+
323+
system_info#set_elf_is_code_address wordzero codemax;
324+
ARMU.arm_instructions_setup (make_dw "0xa0132000") 0x10000;
325+
List.iter (fun (title, hexbase, expecteddefault, bytes, expectedtargets) ->
326+
let jtresult = jt_setup_arm hexbase bytes in
327+
328+
TS.add_simple_test
329+
~title:(title ^ "-targets")
330+
(fun () ->
331+
match jtresult with
332+
| Ok jt ->
333+
ARMA.equal_jumptable_targets
334+
~msg:"" ~expected:expectedtargets ~received:jt ()
335+
| Error e ->
336+
A.fail_msg (String.concat "; " e));
337+
338+
TS.add_simple_test
339+
~title:(title ^ "-default")
340+
(fun () ->
341+
match jtresult with
342+
| Ok jt ->
343+
A.equal_string expecteddefault jt#default_target#to_hex_string
344+
| Error e ->
345+
A.fail_msg (String.concat "; " e))
346+
) tests;
347+
348+
TS.launch_tests ()
349+
end
350+
351+
295352
let bx_table_branch () =
296353
let tests = [
297354
("bx-w", "0x6c0d0", "0x6c080",
@@ -350,6 +407,7 @@ let () =
350407
tb_table_branch ();
351408
ldr_table_branch ();
352409
ldrls_jumptable ();
410+
addls_pc_jumptable ();
353411
bx_table_branch ();
354412
TS.exit_file ()
355413
end

0 commit comments

Comments
 (0)