@@ -84,18 +84,11 @@ impl ArchArm {
84
84
. filter_map ( |s| DisasmMode :: from_symbol ( & s) )
85
85
. collect ( ) ;
86
86
mapping_symbols. sort_unstable_by_key ( |x| x. address ) ;
87
- ( s. index ( ) . 0 , mapping_symbols)
87
+ ( s. index ( ) . 0 - 1 , mapping_symbols)
88
88
} )
89
89
. collect ( )
90
90
}
91
91
92
- fn endian ( & self ) -> unarm:: Endian {
93
- match self . endianness {
94
- object:: Endianness :: Little => unarm:: Endian :: Little ,
95
- object:: Endianness :: Big => unarm:: Endian :: Big ,
96
- }
97
- }
98
-
99
92
fn parse_flags ( & self , diff_config : & DiffObjConfig ) -> unarm:: ParseFlags {
100
93
unarm:: ParseFlags {
101
94
ual : diff_config. arm_unified_syntax ,
@@ -130,6 +123,31 @@ impl ArchArm {
130
123
code : & [ u8 ] ,
131
124
diff_config : & DiffObjConfig ,
132
125
) -> Result < ( unarm:: Ins , unarm:: ParsedIns ) > {
126
+ if ins_ref. opcode == thumb:: Opcode :: BlH as u16 && ins_ref. size == 4 {
127
+ // Special case: combined thumb BL instruction
128
+ let parse_flags = self . parse_flags ( diff_config) ;
129
+ let first_ins = thumb:: Ins {
130
+ code : match self . endianness {
131
+ object:: Endianness :: Little => u16:: from_le_bytes ( [ code[ 0 ] , code[ 1 ] ] ) ,
132
+ object:: Endianness :: Big => u16:: from_be_bytes ( [ code[ 0 ] , code[ 1 ] ] ) ,
133
+ } as u32 ,
134
+ op : thumb:: Opcode :: BlH ,
135
+ } ;
136
+ let second_ins = thumb:: Ins :: new (
137
+ match self . endianness {
138
+ object:: Endianness :: Little => u16:: from_le_bytes ( [ code[ 2 ] , code[ 3 ] ] ) ,
139
+ object:: Endianness :: Big => u16:: from_be_bytes ( [ code[ 2 ] , code[ 3 ] ] ) ,
140
+ } as u32 ,
141
+ & parse_flags,
142
+ ) ;
143
+ let first_parsed = first_ins. parse ( & parse_flags) ;
144
+ let second_parsed = second_ins. parse ( & parse_flags) ;
145
+ return Ok ( (
146
+ unarm:: Ins :: Thumb ( first_ins) ,
147
+ first_parsed. combine_thumb_bl ( & second_parsed) ,
148
+ ) ) ;
149
+ }
150
+
133
151
let code = match ( self . endianness , ins_ref. size ) {
134
152
( object:: Endianness :: Little , 2 ) => u16:: from_le_bytes ( [ code[ 0 ] , code[ 1 ] ] ) as u32 ,
135
153
( object:: Endianness :: Little , 4 ) => {
@@ -153,11 +171,7 @@ impl ArchArm {
153
171
} else {
154
172
let ins = thumb:: Ins { code, op : thumb:: Opcode :: from ( ins_ref. opcode as u8 ) } ;
155
173
let parsed = ins. parse ( & self . parse_flags ( diff_config) ) ;
156
- if ins. is_half_bl ( ) {
157
- todo ! ( "Combine thumb BL instructions" ) ;
158
- } else {
159
- ( unarm:: Ins :: Thumb ( ins) , parsed)
160
- }
174
+ ( unarm:: Ins :: Thumb ( ins) , parsed)
161
175
} ;
162
176
Ok ( ( ins, parsed_ins) )
163
177
}
@@ -185,60 +199,127 @@ impl Arch for ArchArm {
185
199
let first_mapping_idx = mapping_symbols
186
200
. binary_search_by_key ( & start_addr, |x| x. address )
187
201
. unwrap_or_else ( |idx| idx - 1 ) ;
188
- let first_mapping = mapping_symbols[ first_mapping_idx] . mapping ;
202
+ let mut mode = mapping_symbols[ first_mapping_idx] . mapping ;
189
203
190
- let mut mappings_iter =
191
- mapping_symbols. iter ( ) . skip ( first_mapping_idx + 1 ) . take_while ( |x| x. address < end_addr) ;
204
+ let mut mappings_iter = mapping_symbols
205
+ . iter ( )
206
+ . copied ( )
207
+ . skip ( first_mapping_idx + 1 )
208
+ . take_while ( |x| x. address < end_addr) ;
192
209
let mut next_mapping = mappings_iter. next ( ) ;
193
210
194
- let ins_count = code. len ( ) / first_mapping . instruction_size ( start_addr) ;
211
+ let ins_count = code. len ( ) / mode . instruction_size ( start_addr) ;
195
212
let mut ops = Vec :: < ScannedInstruction > :: with_capacity ( ins_count) ;
196
213
197
- let endian = self . endian ( ) ;
198
214
let parse_flags = self . parse_flags ( diff_config) ;
199
- let mut parser = unarm:: Parser :: new ( first_mapping, start_addr, endian, parse_flags, code) ;
200
-
201
- while let Some ( ( address, ins, _parsed_ins) ) = parser. next ( ) {
202
- let size = parser. mode . instruction_size ( address) ;
203
- if let Some ( next) = next_mapping {
204
- let next_address = parser. address ;
205
- if next_address >= next. address {
206
- // Change mapping
207
- parser. mode = next. mapping ;
208
- next_mapping = mappings_iter. next ( ) ;
209
- }
215
+
216
+ let mut address = start_addr;
217
+ while address < end_addr {
218
+ while let Some ( next) = next_mapping. take_if ( |x| address >= x. address ) {
219
+ // Change mapping
220
+ mode = next. mapping ;
221
+ next_mapping = mappings_iter. next ( ) ;
210
222
}
211
- let ( opcode, branch_dest) = match ins {
212
- unarm:: Ins :: Arm ( x) => {
213
- let opcode = x. op as u16 | ( 1 << 15 ) ;
214
- let branch_dest = match x. op {
223
+
224
+ let mut ins_size = mode. instruction_size ( address) ;
225
+ let data = & code[ ( address - start_addr) as usize ..] ;
226
+ if data. len ( ) < ins_size {
227
+ // Push the remainder as data
228
+ ops. push ( ScannedInstruction {
229
+ ins_ref : InstructionRef {
230
+ address : address as u64 ,
231
+ size : data. len ( ) as u8 ,
232
+ opcode : u16:: MAX ,
233
+ } ,
234
+ branch_dest : None ,
235
+ } ) ;
236
+ break ;
237
+ }
238
+ let code = match ( self . endianness , ins_size) {
239
+ ( object:: Endianness :: Little , 2 ) => u16:: from_le_bytes ( [ data[ 0 ] , data[ 1 ] ] ) as u32 ,
240
+ ( object:: Endianness :: Little , 4 ) => {
241
+ u32:: from_le_bytes ( [ data[ 0 ] , data[ 1 ] , data[ 2 ] , data[ 3 ] ] )
242
+ }
243
+ ( object:: Endianness :: Big , 2 ) => u16:: from_be_bytes ( [ data[ 0 ] , data[ 1 ] ] ) as u32 ,
244
+ ( object:: Endianness :: Big , 4 ) => {
245
+ u32:: from_be_bytes ( [ data[ 0 ] , data[ 1 ] , data[ 2 ] , data[ 3 ] ] )
246
+ }
247
+ _ => {
248
+ // Invalid instruction size
249
+ ops. push ( ScannedInstruction {
250
+ ins_ref : InstructionRef {
251
+ address : address as u64 ,
252
+ size : ins_size as u8 ,
253
+ opcode : u16:: MAX ,
254
+ } ,
255
+ branch_dest : None ,
256
+ } ) ;
257
+ address += ins_size as u32 ;
258
+ continue ;
259
+ }
260
+ } ;
261
+
262
+ let ( opcode, branch_dest) = match mode {
263
+ unarm:: ParseMode :: Arm => {
264
+ let ins = arm:: Ins :: new ( code, & parse_flags) ;
265
+ let opcode = ins. op as u16 | ( 1 << 15 ) ;
266
+ let branch_dest = match ins. op {
215
267
arm:: Opcode :: B | arm:: Opcode :: Bl => {
216
- address. checked_add_signed ( x . field_branch_offset ( ) )
268
+ address. checked_add_signed ( ins . field_branch_offset ( ) )
217
269
}
218
- arm:: Opcode :: BlxI => address. checked_add_signed ( x . field_blx_offset ( ) ) ,
270
+ arm:: Opcode :: BlxI => address. checked_add_signed ( ins . field_blx_offset ( ) ) ,
219
271
_ => None ,
220
272
} ;
221
273
( opcode, branch_dest)
222
274
}
223
- unarm:: Ins :: Thumb ( x) => {
224
- let opcode = x. op as u16 ;
225
- let branch_dest = match x. op {
275
+ unarm:: ParseMode :: Thumb => {
276
+ let ins = thumb:: Ins :: new ( code, & parse_flags) ;
277
+ let opcode = ins. op as u16 ;
278
+ let branch_dest = match ins. op {
226
279
thumb:: Opcode :: B | thumb:: Opcode :: Bl => {
227
- address. checked_add_signed ( x. field_branch_offset_8 ( ) )
280
+ address. checked_add_signed ( ins. field_branch_offset_8 ( ) )
281
+ }
282
+ thumb:: Opcode :: BlH if data. len ( ) >= 4 => {
283
+ // Combine BL instructions
284
+ let second_ins = thumb:: Ins :: new (
285
+ match self . endianness {
286
+ object:: Endianness :: Little => {
287
+ u16:: from_le_bytes ( [ data[ 2 ] , data[ 3 ] ] ) as u32
288
+ }
289
+ object:: Endianness :: Big => {
290
+ u16:: from_be_bytes ( [ data[ 2 ] , data[ 3 ] ] ) as u32
291
+ }
292
+ } ,
293
+ & parse_flags,
294
+ ) ;
295
+ if let Some ( low) = match second_ins. op {
296
+ thumb:: Opcode :: Bl => Some ( second_ins. field_low_branch_offset_11 ( ) ) ,
297
+ thumb:: Opcode :: BlxI => Some ( second_ins. field_low_blx_offset_11 ( ) ) ,
298
+ _ => None ,
299
+ } {
300
+ ins_size = 4 ;
301
+ address. checked_add_signed (
302
+ ( ins. field_high_branch_offset_11 ( ) + ( low as i32 ) ) << 9 >> 9 ,
303
+ )
304
+ } else {
305
+ None
306
+ }
228
307
}
229
308
thumb:: Opcode :: BLong => {
230
- address. checked_add_signed ( x . field_branch_offset_11 ( ) )
309
+ address. checked_add_signed ( ins . field_branch_offset_11 ( ) )
231
310
}
232
311
_ => None ,
233
312
} ;
234
313
( opcode, branch_dest)
235
314
}
236
- unarm:: Ins :: Data => ( u16:: MAX , None ) ,
315
+ unarm:: ParseMode :: Data => ( u16:: MAX , None ) ,
237
316
} ;
317
+
238
318
ops. push ( ScannedInstruction {
239
- ins_ref : InstructionRef { address : address as u64 , size : size as u8 , opcode } ,
319
+ ins_ref : InstructionRef { address : address as u64 , size : ins_size as u8 , opcode } ,
240
320
branch_dest : branch_dest. map ( |x| x as u64 ) ,
241
321
} ) ;
322
+ address += ins_size as u32 ;
242
323
}
243
324
244
325
Ok ( ops)
@@ -391,7 +472,7 @@ fn push_args(
391
472
let reloc_arg = find_reloc_arg ( parsed_ins, relocation) ;
392
473
let mut writeback = false ;
393
474
let mut deref = false ;
394
- for ( i, arg) in parsed_ins. args_iter ( ) . enumerate ( ) {
475
+ for ( i, & arg) in parsed_ins. args_iter ( ) . enumerate ( ) {
395
476
// Emit punctuation before separator
396
477
if deref {
397
478
match arg {
@@ -463,19 +544,19 @@ fn push_args(
463
544
| args:: Argument :: CoOpcode ( value)
464
545
| args:: Argument :: SatImm ( value) => {
465
546
arg_cb ( InstructionPart :: basic ( "#" ) ) ?;
466
- arg_cb ( InstructionPart :: unsigned ( * value) ) ?;
547
+ arg_cb ( InstructionPart :: unsigned ( value) ) ?;
467
548
}
468
549
args:: Argument :: SImm ( value)
469
550
| args:: Argument :: OffsetImm ( args:: OffsetImm { post_indexed : _, value } ) => {
470
551
arg_cb ( InstructionPart :: basic ( "#" ) ) ?;
471
- arg_cb ( InstructionPart :: signed ( * value) ) ?;
552
+ arg_cb ( InstructionPart :: signed ( value) ) ?;
472
553
}
473
554
args:: Argument :: BranchDest ( value) => {
474
- arg_cb ( InstructionPart :: branch_dest ( cur_addr. wrapping_add_signed ( * value) ) ) ?;
555
+ arg_cb ( InstructionPart :: branch_dest ( cur_addr. wrapping_add_signed ( value) ) ) ?;
475
556
}
476
557
args:: Argument :: CoOption ( value) => {
477
558
arg_cb ( InstructionPart :: basic ( "{" ) ) ?;
478
- arg_cb ( InstructionPart :: unsigned ( * value) ) ?;
559
+ arg_cb ( InstructionPart :: unsigned ( value) ) ?;
479
560
arg_cb ( InstructionPart :: basic ( "}" ) ) ?;
480
561
}
481
562
args:: Argument :: CoprocNum ( value) => {
0 commit comments