1
1
use alloc:: { boxed:: Box , string:: String , vec:: Vec } ;
2
2
3
- use anyhow:: { Result , anyhow, bail} ;
3
+ use anyhow:: { Context , Result , anyhow, bail} ;
4
4
use iced_x86:: {
5
5
Decoder , DecoderOptions , DecoratorKind , FormatterOutput , FormatterTextKind , GasFormatter ,
6
6
Instruction , IntelFormatter , MasmFormatter , NasmFormatter , NumberKind , OpKind , Register ,
@@ -10,7 +10,9 @@ use object::{Endian as _, Object as _, ObjectSection as _, pe};
10
10
use crate :: {
11
11
arch:: Arch ,
12
12
diff:: { DiffObjConfig , X86Formatter , display:: InstructionPart } ,
13
- obj:: { InstructionRef , RelocationFlags , ResolvedInstructionRef , ScannedInstruction } ,
13
+ obj:: {
14
+ InstructionRef , Relocation , RelocationFlags , ResolvedInstructionRef , ScannedInstruction ,
15
+ } ,
14
16
} ;
15
17
16
18
#[ derive( Debug ) ]
@@ -80,18 +82,48 @@ impl ArchX86 {
80
82
}
81
83
}
82
84
85
+ const DATA_OPCODE : u16 = u16:: MAX - 1 ;
86
+
83
87
impl Arch for ArchX86 {
84
88
fn scan_instructions (
85
89
& self ,
86
90
address : u64 ,
87
91
code : & [ u8 ] ,
88
92
_section_index : usize ,
93
+ relocations : & [ Relocation ] ,
89
94
_diff_config : & DiffObjConfig ,
90
95
) -> Result < Vec < ScannedInstruction > > {
91
96
let mut out = Vec :: with_capacity ( code. len ( ) / 2 ) ;
92
97
let mut decoder = self . decoder ( code, address) ;
93
98
let mut instruction = Instruction :: default ( ) ;
94
- while decoder. can_decode ( ) {
99
+ let mut reloc_iter = relocations. iter ( ) . peekable ( ) ;
100
+ ' outer: while decoder. can_decode ( ) {
101
+ let address = decoder. ip ( ) ;
102
+ while let Some ( reloc) = reloc_iter. peek ( ) {
103
+ if reloc. address < address {
104
+ reloc_iter. next ( ) ;
105
+ } else if reloc. address == address {
106
+ // If the instruction starts at a relocation, it's inline data
107
+ let size = self . reloc_size ( reloc. flags ) . with_context ( || {
108
+ format ! ( "Unsupported inline x86 relocation {:?}" , reloc. flags)
109
+ } ) ?;
110
+ if decoder. set_position ( decoder. position ( ) + size) . is_ok ( ) {
111
+ decoder. set_ip ( address + size as u64 ) ;
112
+ out. push ( ScannedInstruction {
113
+ ins_ref : InstructionRef {
114
+ address,
115
+ size : size as u8 ,
116
+ opcode : DATA_OPCODE ,
117
+ } ,
118
+ branch_dest : None ,
119
+ } ) ;
120
+ reloc_iter. next ( ) ;
121
+ continue ' outer;
122
+ }
123
+ } else {
124
+ break ;
125
+ }
126
+ }
95
127
decoder. decode_out ( & mut instruction) ;
96
128
let branch_dest = match instruction. op0_kind ( ) {
97
129
OpKind :: NearBranch16 => Some ( instruction. near_branch16 ( ) as u64 ) ,
@@ -101,7 +133,7 @@ impl Arch for ArchX86 {
101
133
} ;
102
134
out. push ( ScannedInstruction {
103
135
ins_ref : InstructionRef {
104
- address : instruction . ip ( ) ,
136
+ address,
105
137
size : instruction. len ( ) as u8 ,
106
138
opcode : instruction. mnemonic ( ) as u16 ,
107
139
} ,
@@ -117,6 +149,21 @@ impl Arch for ArchX86 {
117
149
diff_config : & DiffObjConfig ,
118
150
cb : & mut dyn FnMut ( InstructionPart ) -> Result < ( ) > ,
119
151
) -> Result < ( ) > {
152
+ if resolved. ins_ref . opcode == DATA_OPCODE {
153
+ let ( mnemonic, imm) = match resolved. ins_ref . size {
154
+ 2 => ( ".word" , self . endianness . read_u16_bytes ( resolved. code . try_into ( ) ?) as u64 ) ,
155
+ 4 => ( ".dword" , self . endianness . read_u32_bytes ( resolved. code . try_into ( ) ?) as u64 ) ,
156
+ _ => bail ! ( "Unsupported x86 inline data size {}" , resolved. ins_ref. size) ,
157
+ } ;
158
+ cb ( InstructionPart :: opcode ( mnemonic, DATA_OPCODE ) ) ?;
159
+ if resolved. relocation . is_some ( ) {
160
+ cb ( InstructionPart :: reloc ( ) ) ?;
161
+ } else {
162
+ cb ( InstructionPart :: unsigned ( imm) ) ?;
163
+ }
164
+ return Ok ( ( ) ) ;
165
+ }
166
+
120
167
let mut decoder = self . decoder ( resolved. code , resolved. ins_ref . address ) ;
121
168
let mut formatter = self . formatter ( diff_config) ;
122
169
let mut instruction = Instruction :: default ( ) ;
@@ -406,7 +453,7 @@ mod test {
406
453
0xc7 , 0x85 , 0x68 , 0xff , 0xff , 0xff , 0x00 , 0x00 , 0x00 , 0x00 , 0x8b , 0x04 , 0x85 , 0x00 ,
407
454
0x00 , 0x00 , 0x00 ,
408
455
] ;
409
- let scanned = arch. scan_instructions ( 0 , & code, 0 , & DiffObjConfig :: default ( ) ) . unwrap ( ) ;
456
+ let scanned = arch. scan_instructions ( 0 , & code, 0 , & [ ] , & DiffObjConfig :: default ( ) ) . unwrap ( ) ;
410
457
assert_eq ! ( scanned. len( ) , 2 ) ;
411
458
assert_eq ! ( scanned[ 0 ] . ins_ref. address, 0 ) ;
412
459
assert_eq ! ( scanned[ 0 ] . ins_ref. size, 10 ) ;
0 commit comments