OLD | NEW |
| (Empty) |
1 #include <stdio.h> | |
2 #include <stdlib.h> | |
3 #include <string.h> | |
4 | |
5 #include "libdis.h" | |
6 #include "ia32_insn.h" | |
7 #include "ia32_operand.h" | |
8 #include "ia32_modrm.h" | |
9 #include "ia32_reg.h" | |
10 #include "x86_imm.h" | |
11 #include "x86_operand_list.h" | |
12 | |
13 | |
14 | |
15 /* apply segment override to memory operand in insn */ | |
16 static void apply_seg( x86_op_t *op, unsigned int prefixes ) { | |
17 if (! prefixes ) return; | |
18 | |
19 /* apply overrides from prefix */ | |
20 switch ( prefixes & PREFIX_REG_MASK ) { | |
21 case PREFIX_CS: | |
22 op->flags |= op_cs_seg; break; | |
23 case PREFIX_SS: | |
24 op->flags |= op_ss_seg; break; | |
25 case PREFIX_DS: | |
26 op->flags |= op_ds_seg; break; | |
27 case PREFIX_ES: | |
28 op->flags |= op_es_seg; break; | |
29 case PREFIX_FS: | |
30 op->flags |= op_fs_seg; break; | |
31 case PREFIX_GS: | |
32 op->flags |= op_gs_seg; break; | |
33 } | |
34 | |
35 return; | |
36 } | |
37 | |
38 static size_t decode_operand_value( unsigned char *buf, size_t buf_len, | |
39 x86_op_t *op, x86_insn_t *insn, | |
40 unsigned int addr_meth, size_t op_size, | |
41 unsigned int op_value, unsigned char modrm, | |
42 size_t gen_regs ) { | |
43 size_t size = 0; | |
44 | |
45 /* ++ Do Operand Addressing Method / Decode operand ++ */ | |
46 switch (addr_meth) { | |
47 /* This sets the operand Size based on the Intel Opcode Map | |
48 * (Vol 2, Appendix A). Letter encodings are from section | |
49 * A.1.1, 'Codes for Addressing Method' */ | |
50 | |
51 /* ---------------------- Addressing Method -------------- */ | |
52 /* Note that decoding mod ModR/M operand adjusts the size of | |
53 * the instruction, but decoding the reg operand does not. | |
54 * This should not cause any problems, as every 'reg' operand | |
55 * has an associated 'mod' operand. | |
56 * Goddamn-Intel-Note: | |
57 * Some Intel addressing methods [M, R] specify that modR/M | |
58 * byte may only refer to a memory address/may only refer to | |
59 * a register -- however Intel provides no clues on what to do | |
60 * if, say, the modR/M for an M opcode decodes to a register | |
61 * rather than a memory address ... returning 0 is out of the | |
62 * question, as this would be an Immediate or a RelOffset, so | |
63 * instead these modR/Ms are decoded with total disregard to | |
64 * the M, R constraints. */ | |
65 | |
66 /* MODRM -- mod operand. sets size to at least 1! */ | |
67 case ADDRMETH_E: /* ModR/M present, Gen reg or memory */ | |
68 size = ia32_modrm_decode( buf, buf_len, op, insn, | |
69 gen_regs ); | |
70 break; | |
71 case ADDRMETH_M: /* ModR/M only refers to memory */ | |
72 size = ia32_modrm_decode( buf, buf_len, op, insn, | |
73 gen_regs ); | |
74 break; | |
75 case ADDRMETH_Q: /* ModR/M present, MMX or Memory */ | |
76 size = ia32_modrm_decode( buf, buf_len, op, insn, | |
77 REG_MMX_OFFSET ); | |
78 break; | |
79 case ADDRMETH_R: /* ModR/M mod == gen reg */ | |
80 size = ia32_modrm_decode( buf, buf_len, op, insn, | |
81 gen_regs ); | |
82 break; | |
83 case ADDRMETH_W: /* ModR/M present, mem or SIMD reg */ | |
84 size = ia32_modrm_decode( buf, buf_len, op, insn, | |
85 REG_SIMD_OFFSET ); | |
86 break; | |
87 | |
88 /* MODRM -- reg operand. does not effect size! */ | |
89 case ADDRMETH_C: /* ModR/M reg == control reg */ | |
90 ia32_reg_decode( modrm, op, REG_CTRL_OFFSET ); | |
91 break; | |
92 case ADDRMETH_D: /* ModR/M reg == debug reg */ | |
93 ia32_reg_decode( modrm, op, REG_DEBUG_OFFSET ); | |
94 break; | |
95 case ADDRMETH_G: /* ModR/M reg == gen-purpose reg */ | |
96 ia32_reg_decode( modrm, op, gen_regs ); | |
97 break; | |
98 case ADDRMETH_P: /* ModR/M reg == qword MMX reg */ | |
99 ia32_reg_decode( modrm, op, REG_MMX_OFFSET ); | |
100 break; | |
101 case ADDRMETH_S: /* ModR/M reg == segment reg */ | |
102 ia32_reg_decode( modrm, op, REG_SEG_OFFSET ); | |
103 break; | |
104 case ADDRMETH_T: /* ModR/M reg == test reg */ | |
105 ia32_reg_decode( modrm, op, REG_TEST_OFFSET ); | |
106 break; | |
107 case ADDRMETH_V: /* ModR/M reg == SIMD reg */ | |
108 ia32_reg_decode( modrm, op, REG_SIMD_OFFSET ); | |
109 break; | |
110 | |
111 /* No MODRM : note these set operand type explicitly */ | |
112 case ADDRMETH_A: /* No modR/M -- direct addr */ | |
113 op->type = op_absolute; | |
114 | |
115 /* segment:offset address used in far calls */ | |
116 x86_imm_sized( buf, buf_len, | |
117 &op->data.absolute.segment, 2 ); | |
118 if ( insn->addr_size == 4 ) { | |
119 x86_imm_sized( buf, buf_len, | |
120 &op->data.absolute.offset.off32, 4 ); | |
121 size = 6; | |
122 } else { | |
123 x86_imm_sized( buf, buf_len, | |
124 &op->data.absolute.offset.off16, 2 ); | |
125 size = 4; | |
126 } | |
127 | |
128 break; | |
129 case ADDRMETH_I: /* Immediate val */ | |
130 op->type = op_immediate; | |
131 /* if it ever becomes legal to have imm as dest and | |
132 * there is a src ModR/M operand, we are screwed! */ | |
133 if ( op->flags & op_signed ) { | |
134 x86_imm_signsized(buf, buf_len, &op->data.byte, | |
135 op_size); | |
136 } else { | |
137 x86_imm_sized(buf, buf_len, &op->data.byte, | |
138 op_size); | |
139 } | |
140 size = op_size; | |
141 break; | |
142 case ADDRMETH_J: /* Rel offset to add to IP [jmp] */ | |
143 /* this fills op->data.near_offset or | |
144 op->data.far_offset depending on the size of | |
145 the operand */ | |
146 op->flags |= op_signed; | |
147 if ( op_size == 1 ) { | |
148 /* one-byte near offset */ | |
149 op->type = op_relative_near; | |
150 x86_imm_signsized(buf, buf_len, | |
151 &op->data.relative_near, 1); | |
152 } else { | |
153 /* far offset...is this truly signed? */ | |
154 op->type = op_relative_far; | |
155 x86_imm_signsized(buf, buf_len, | |
156 &op->data.relative_far, op_size ); | |
157 } | |
158 size = op_size; | |
159 break; | |
160 case ADDRMETH_O: /* No ModR/M; op is word/dword offset */ | |
161 /* NOTE: these are actually RVAs not offsets to seg!! */ | |
162 /* note bene: 'O' ADDR_METH uses addr_size to | |
163 determine operand size */ | |
164 op->type = op_offset; | |
165 op->flags |= op_pointer; | |
166 x86_imm_sized( buf, buf_len, &op->data.offset, | |
167 insn->addr_size ); | |
168 | |
169 size = insn->addr_size; | |
170 break; | |
171 | |
172 /* Hard-coded: these are specified in the insn definition */ | |
173 case ADDRMETH_F: /* EFLAGS register */ | |
174 op->type = op_register; | |
175 op->flags |= op_hardcode; | |
176 ia32_handle_register( &op->data.reg, REG_FLAGS_INDEX ); | |
177 break; | |
178 case ADDRMETH_X: /* Memory addressed by DS:SI [string] */ | |
179 op->type = op_expression; | |
180 op->flags |= op_hardcode; | |
181 op->flags |= op_ds_seg | op_pointer | op_string; | |
182 ia32_handle_register( &op->data.expression.base, | |
183 REG_DWORD_OFFSET + 6 ); | |
184 break; | |
185 case ADDRMETH_Y: /* Memory addressed by ES:DI [string] */ | |
186 op->type = op_expression; | |
187 op->flags |= op_hardcode; | |
188 op->flags |= op_es_seg | op_pointer | op_string; | |
189 ia32_handle_register( &op->data.expression.base, | |
190 REG_DWORD_OFFSET + 7 ); | |
191 break; | |
192 case ADDRMETH_RR: /* Gen Register hard-coded in opcode */ | |
193 op->type = op_register; | |
194 op->flags |= op_hardcode; | |
195 ia32_handle_register( &op->data.reg, | |
196 op_value + gen_regs ); | |
197 break; | |
198 case ADDRMETH_RS: /* Seg Register hard-coded in opcode */ | |
199 op->type = op_register; | |
200 op->flags |= op_hardcode; | |
201 ia32_handle_register( &op->data.reg, | |
202 op_value + REG_SEG_OFFSET ); | |
203 break; | |
204 case ADDRMETH_RF: /* FPU Register hard-coded in opcode */ | |
205 op->type = op_register; | |
206 op->flags |= op_hardcode; | |
207 ia32_handle_register( &op->data.reg, | |
208 op_value + REG_FPU_OFFSET ); | |
209 break; | |
210 case ADDRMETH_RT: /* TST Register hard-coded in opcode */ | |
211 op->type = op_register; | |
212 op->flags |= op_hardcode; | |
213 ia32_handle_register( &op->data.reg, | |
214 op_value + REG_TEST_OFFSET ); | |
215 break; | |
216 case ADDRMETH_II: /* Immediate hard-coded in opcode */ | |
217 op->type = op_immediate; | |
218 op->data.dword = op_value; | |
219 op->flags |= op_hardcode; | |
220 break; | |
221 | |
222 case 0: /* Operand is not used */ | |
223 default: | |
224 /* ignore -- operand not used in this insn */ | |
225 op->type = op_unused; /* this shouldn't happen! */ | |
226 break; | |
227 } | |
228 | |
229 return size; | |
230 } | |
231 | |
232 static size_t decode_operand_size( unsigned int op_type, x86_insn_t *insn, | |
233 x86_op_t *op ){ | |
234 size_t size; | |
235 | |
236 /* ++ Do Operand Type ++ */ | |
237 switch (op_type) { | |
238 /* This sets the operand Size based on the Intel Opcode Map | |
239 * (Vol 2, Appendix A). Letter encodings are from section | |
240 * A.1.2, 'Codes for Operand Type' */ | |
241 /* NOTE: in this routines, 'size' refers to the size | |
242 * of the operand in the raw (encoded) instruction; | |
243 * 'datatype' stores the actual size and datatype | |
244 * of the operand */ | |
245 | |
246 /* ------------------------ Operand Type ----------------- */ | |
247 case OPTYPE_c: /* byte or word [op size attr] */ | |
248 size = (insn->op_size == 4) ? 2 : 1; | |
249 op->datatype = (size == 4) ? op_word : op_byte; | |
250 break; | |
251 case OPTYPE_a: /* 2 word or 2 dword [op size attr] */ | |
252 /* pointer to a 16:16 or 32:32 BOUNDS operand */ | |
253 size = (insn->op_size == 4) ? 8 : 4; | |
254 op->datatype = (size == 4) ? op_bounds32 : op_bounds16; | |
255 break; | |
256 case OPTYPE_v: /* word or dword [op size attr] */ | |
257 size = (insn->op_size == 4) ? 4 : 2; | |
258 op->datatype = (size == 4) ? op_dword : op_word; | |
259 break; | |
260 case OPTYPE_p: /* 32/48-bit ptr [op size attr] */ | |
261 /* technically these flags are not accurate: the | |
262 * value s a 16:16 pointer or a 16:32 pointer, where | |
263 * the first '16' is a segment */ | |
264 size = (insn->addr_size == 4) ? 6 : 4; | |
265 op->datatype = (size == 4) ? op_descr32 : op_descr16; | |
266 break; | |
267 case OPTYPE_b: /* byte, ignore op-size */ | |
268 size = 1; | |
269 op->datatype = op_byte; | |
270 break; | |
271 case OPTYPE_w: /* word, ignore op-size */ | |
272 size = 2; | |
273 op->datatype = op_word; | |
274 break; | |
275 case OPTYPE_d: /* dword , ignore op-size */ | |
276 size = 4; | |
277 op->datatype = op_dword; | |
278 break; | |
279 case OPTYPE_s: /* 6-byte psuedo-descriptor */ | |
280 /* ptr to 6-byte value which is 32:16 in 32-bit | |
281 * mode, or 8:24:16 in 16-bit mode. The high byte | |
282 * is ignored in 16-bit mode. */ | |
283 size = 6; | |
284 op->datatype = (insn->addr_size == 4) ? | |
285 op_pdescr32 : op_pdescr16; | |
286 break; | |
287 case OPTYPE_q: /* qword, ignore op-size */ | |
288 size = 8; | |
289 op->datatype = op_qword; | |
290 break; | |
291 case OPTYPE_dq: /* d-qword, ignore op-size */ | |
292 size = 16; | |
293 op->datatype = op_dqword; | |
294 break; | |
295 case OPTYPE_ps: /* 128-bit FP data */ | |
296 size = 16; | |
297 /* really this is 4 packed SP FP values */ | |
298 op->datatype = op_ssimd; | |
299 break; | |
300 case OPTYPE_pd: /* 128-bit FP data */ | |
301 size = 16; | |
302 /* really this is 2 packed DP FP values */ | |
303 op->datatype = op_dsimd; | |
304 break; | |
305 case OPTYPE_ss: /* Scalar elem of 128-bit FP data */ | |
306 size = 16; | |
307 /* this only looks at the low dword (4 bytes) | |
308 * of the xmmm register passed as a param. | |
309 * This is a 16-byte register where only 4 bytes | |
310 * are used in the insn. Painful, ain't it? */ | |
311 op->datatype = op_sssimd; | |
312 break; | |
313 case OPTYPE_sd: /* Scalar elem of 128-bit FP data */ | |
314 size = 16; | |
315 /* this only looks at the low qword (8 bytes) | |
316 * of the xmmm register passed as a param. | |
317 * This is a 16-byte register where only 8 bytes | |
318 * are used in the insn. Painful, again... */ | |
319 op->datatype = op_sdsimd; | |
320 break; | |
321 case OPTYPE_pi: /* qword mmx register */ | |
322 size = 8; | |
323 op->datatype = op_qword; | |
324 break; | |
325 case OPTYPE_si: /* dword integer register */ | |
326 size = 4; | |
327 op->datatype = op_dword; | |
328 break; | |
329 case OPTYPE_fs: /* single-real */ | |
330 size = 4; | |
331 op->datatype = op_sreal; | |
332 break; | |
333 case OPTYPE_fd: /* double real */ | |
334 size = 8; | |
335 op->datatype = op_dreal; | |
336 break; | |
337 case OPTYPE_fe: /* extended real */ | |
338 size = 10; | |
339 op->datatype = op_extreal; | |
340 break; | |
341 case OPTYPE_fb: /* packed BCD */ | |
342 size = 10; | |
343 op->datatype = op_bcd; | |
344 break; | |
345 case OPTYPE_fv: /* pointer to FPU env: 14 or 28-bytes */ | |
346 size = (insn->addr_size == 4)? 28 : 14; | |
347 op->datatype = (size == 28)? op_fpuenv32: op_fpuenv16; | |
348 break; | |
349 case OPTYPE_ft: /* pointer to FPU env: 94 or 108 bytes */ | |
350 size = (insn->addr_size == 4)? 108 : 94; | |
351 op->datatype = (size == 108)? | |
352 op_fpustate32: op_fpustate16; | |
353 break; | |
354 case OPTYPE_fx: /* 512-byte register stack */ | |
355 size = 512; | |
356 op->datatype = op_fpregset; | |
357 break; | |
358 case OPTYPE_fp: /* floating point register */ | |
359 size = 10; /* double extended precision */ | |
360 op->datatype = op_fpreg; | |
361 break; | |
362 case OPTYPE_m: /* fake operand type used for "lea Gv, M" */ | |
363 size = insn->addr_size; | |
364 op->datatype = (size == 4) ? op_dword : op_word; | |
365 break; | |
366 case OPTYPE_none: /* handle weird instructions that have no enco
ding but use a dword datatype, like invlpg */ | |
367 size = 0; | |
368 op->datatype = op_none; | |
369 break; | |
370 case 0: | |
371 default: | |
372 size = insn->op_size; | |
373 op->datatype = (size == 4) ? op_dword : op_word; | |
374 break; | |
375 } | |
376 return size; | |
377 } | |
378 | |
379 size_t ia32_decode_operand( unsigned char *buf, size_t buf_len, | |
380 x86_insn_t *insn, unsigned int raw_op, | |
381 unsigned int raw_flags, unsigned int prefixes, | |
382 unsigned char modrm ) { | |
383 unsigned int addr_meth, op_type, op_size, gen_regs; | |
384 x86_op_t *op; | |
385 size_t size; | |
386 | |
387 /* ++ Yank optype and addr mode out of operand flags */ | |
388 addr_meth = raw_flags & ADDRMETH_MASK; | |
389 op_type = raw_flags & OPTYPE_MASK; | |
390 | |
391 if ( raw_flags == ARG_NONE ) { | |
392 /* operand is not used in this instruction */ | |
393 return 0; | |
394 } | |
395 | |
396 /* allocate a new operand */ | |
397 op = x86_operand_new( insn ); | |
398 | |
399 /* ++ Copy flags from opcode table to x86_insn_t */ | |
400 op->access = (enum x86_op_access) OP_PERM(raw_flags); | |
401 op->flags = (enum x86_op_flags) (OP_FLAGS(raw_flags) >> 12); | |
402 | |
403 /* Get size (for decoding) and datatype of operand */ | |
404 op_size = decode_operand_size(op_type, insn, op); | |
405 | |
406 /* override default register set based on Operand Type */ | |
407 /* this allows mixing of 8, 16, and 32 bit regs in insn */ | |
408 if (op_size == 1) { | |
409 gen_regs = REG_BYTE_OFFSET; | |
410 } else if (op_size == 2) { | |
411 gen_regs = REG_WORD_OFFSET; | |
412 } else { | |
413 gen_regs = REG_DWORD_OFFSET; | |
414 } | |
415 | |
416 size = decode_operand_value( buf, buf_len, op, insn, addr_meth, | |
417 op_size, raw_op, modrm, gen_regs ); | |
418 | |
419 /* if operand is an address, apply any segment override prefixes */ | |
420 if ( op->type == op_expression || op->type == op_offset ) { | |
421 apply_seg(op, prefixes); | |
422 } | |
423 | |
424 return size; /* return number of bytes in instruction */ | |
425 } | |
OLD | NEW |