@@ -240,6 +240,40 @@ let ldrtest
240240 | _ -> false
241241
242242
243+ let ldrs2test
244+ (tmpreg : arm_reg_t )
245+ (basereg : arm_reg_t )
246+ (indexreg : arm_reg_t )
247+ (instr : arm_assembly_instruction_int ) =
248+ match instr#get_opcode with
249+ | LoadRegister (ACCAlways, rt , rn , rm , mem , false ) ->
250+ let _ =
251+ chlog#add " ldrs2-test"
252+ (LBLOCK [instr#get_address#toPretty;
253+ STR " : " ;
254+ STR (BCHARMOpcodeRecords. arm_opcode_to_string instr#get_opcode);
255+ STR " with " ;
256+ STR (BCHCPURegisters. armreg_to_string tmpreg);
257+ STR " , " ;
258+ STR (BCHCPURegisters. armreg_to_string basereg);
259+ STR " , " ;
260+ STR (BCHCPURegisters. armreg_to_string indexreg)
261+ ]) in
262+ rt#is_register
263+ && rt#get_register = tmpreg
264+ && rn#is_register
265+ && rn#get_register = basereg
266+ && rm#is_register
267+ && rm#get_register = indexreg
268+ && (match mem#get_kind with
269+ | ARMOffsetAddress (_ , _ , offset , _ , _ , _ , _ ) ->
270+ (match offset with
271+ | ARMShiftedIndexOffset (_ , ARMImmSRT (SRType_LSL, 2 ), _ ) -> true
272+ | _ -> false )
273+ | _ -> false )
274+ | _ -> false
275+
276+
243277let ldrbtest
244278 (basereg : arm_reg_t )
245279 (indexreg : arm_reg_t )
@@ -899,6 +933,140 @@ let create_arm_add_pc_jumptable
899933 create_arm_add_pc_h_jumptable ch addpcinstr
900934
901935
936+ (* ADD-PC-LDR patterns (in ARM)
937+
938+ size is obtained from CMP instruction's immediate value
939+ table start address is obtained from the ADR instruction
940+
941+ [4 bytes] CMP indexreg, maxcase
942+ [4 bytes] BHI default address
943+ [4 bytes] ADR basereg, start_address
944+ [4 bytes] LDR scindexreg, [basereg, indexreg, LSL#2]
945+ [4 bytes] ADD PC, basereg, scindexreg
946+
947+ Notes: These instructions always appear in the same order, but they may
948+ be arbitrarily interleaved with other instructions, hence the large number
949+ of offsets in finding the various instructions below.
950+
951+ Notes: encountered in a binary compiled with clang 18.1.3 on an arm64 host,
952+ cross-compiled to arm32.
953+ *)
954+ let is_arm_add_pc_adr_jumptable
955+ (addpcinstr : arm_assembly_instruction_int ):
956+ (arm_assembly_instruction_int (* CMP instr *)
957+ * arm_assembly_instruction_int (* BHI instr *)
958+ * arm_assembly_instruction_int (* ADR instr *)
959+ * arm_assembly_instruction_int ) option = (* LDR instr *)
960+ match addpcinstr#get_opcode with
961+ | Add (_, ACCAlways , rd, baseregop, scindexregop, false )
962+ when rd#is_pc_register
963+ && baseregop#is_register
964+ && scindexregop#is_register ->
965+ let addr = addpcinstr#get_address in
966+ let basereg = baseregop#get_register in
967+ let scindexreg = scindexregop#get_register in (* scaled index register *)
968+ let cmptestf (instr : arm_assembly_instruction_int ) =
969+ match instr#get_opcode with
970+ | Compare (_ , rn , imm , _ ) -> rn#is_register && imm#is_immediate
971+ | _ -> false in
972+ let cmpinstr_o =
973+ find_instr cmptestf [(- 16 ); (- 20 ); (- 24 ); (- 28 ); (- 32 ); (- 36 )] addr in
974+ (match cmpinstr_o with
975+ | Some cmpinstr ->
976+ (match cmpinstr#get_opcode with
977+ | Compare (_ , indexregop , _imm , _ ) ->
978+ let indexreg = indexregop#get_register in
979+ let adrtestf = adr_reg_test basereg in
980+ let ldrs2testf = ldrs2test scindexreg basereg indexreg in
981+ let adrinstr_o = find_instr adrtestf [(- 8 ); (- 12 )] addr in
982+ let bhiinstr_o = find_instr bhi_test [(- 12 ); (- 16 )] addr in
983+ let ldrs2instr_o = find_instr ldrs2testf [(- 4 ); (- 8 )] addr in
984+ let _ =
985+ if Option. is_none adrinstr_o then
986+ chlog#add " adr-jump table failure"
987+ (LBLOCK [addpcinstr#get_address#toPretty; STR " : adrinstr" ]) in
988+ let _ =
989+ if Option. is_none bhiinstr_o then
990+ chlog#add " adr-jump table failure"
991+ (LBLOCK [addpcinstr#get_address#toPretty; STR " : bhiinstr" ]) in
992+ let _ =
993+ if Option. is_none ldrs2instr_o then
994+ chlog#add " adr-jump table failure"
995+ (LBLOCK [addpcinstr#get_address#toPretty; STR " : ldrs2instr" ]) in
996+ (match (bhiinstr_o, adrinstr_o, ldrs2instr_o) with
997+ | (Some bhiinstr , Some adrinstr , Some ldrs2instr ) ->
998+ Some (cmpinstr, bhiinstr, adrinstr, ldrs2instr)
999+ | _ -> None )
1000+ | _ ->
1001+ let _ =
1002+ chlog#add " arm-jumptable cmpinstr failure"
1003+ (LBLOCK [addpcinstr#get_address#toPretty]) in
1004+ None )
1005+ | _ ->
1006+ let _ =
1007+ chlog#add " arm-jumptable cmpinstr failure (not found)"
1008+ (LBLOCK [addpcinstr#get_address#toPretty]) in
1009+ None )
1010+ | _ -> None
1011+
1012+
1013+ let create_arm_add_pc_adr_jumptable
1014+ (ch : pushback_stream_int )
1015+ (addpcinstr : arm_assembly_instruction_int ):
1016+ (arm_assembly_instruction_int list * arm_jumptable_int ) option =
1017+ match is_arm_add_pc_adr_jumptable addpcinstr with
1018+ | None ->
1019+ begin
1020+ chlog#add " arm-jumptable: add-pc-addr (None)"
1021+ (LBLOCK [addpcinstr#get_address#toPretty]);
1022+ None
1023+ end
1024+ | Some (cmpinstr , bhiinstr , adrinstr , ldrinstr ) ->
1025+ match (cmpinstr#get_opcode,
1026+ bhiinstr#get_opcode,
1027+ adrinstr#get_opcode,
1028+ ldrinstr#get_opcode) with
1029+ | (Compare (_, _, imm, _),
1030+ Branch (_, tgtop, _),
1031+ Adr (_, _, adrop),
1032+ LoadRegister (_, dstregop, _, _, _, _))
1033+ when tgtop#is_absolute_address && adrop#is_absolute_address ->
1034+ let iaddr = addpcinstr#get_address in
1035+ let defaulttgt = tgtop#get_absolute_address in
1036+ let size = imm#to_numerical#toInt in
1037+ let jtaddr = adrop#get_absolute_address in
1038+ let targets = ref [] in
1039+ let _ =
1040+ for i = 0 to size do
1041+ let offset = ch#read_num_signed_doubleword in
1042+ targets := (iaddr#add_int (4 + offset#toInt), i) :: ! targets
1043+ done in
1044+ let endaddr = jtaddr#add_int (4 + (4 * size)) in
1045+ let jt:arm_jumptable_int =
1046+ make_arm_jumptable
1047+ ~end_address: endaddr
1048+ ~start_address: jtaddr
1049+ ~default_target: defaulttgt
1050+ ~targets: (List. rev ! targets)
1051+ ~index_operand: dstregop
1052+ () in
1053+ let instrs =
1054+ [cmpinstr; bhiinstr; adrinstr; ldrinstr; addpcinstr] in
1055+ begin
1056+ chlog#add " arm-jumptable: add_pc_addr"
1057+ (LBLOCK [addpcinstr#get_address#toPretty;
1058+ STR " : of size: " ;
1059+ INT size]);
1060+ Some (instrs, jt)
1061+ end
1062+ | _ ->
1063+ begin
1064+ chlog#add " arm-jumptable: add_pc_addr"
1065+ (LBLOCK [addpcinstr#get_address#toPretty;
1066+ STR " : unsuccesful" ]);
1067+ None
1068+ end
1069+
9021070(* format of BX-based jumptable (in Thumb-22):
9031071
9041072 Type 1
0 commit comments