|
1 #include <stdlib.h> |
|
2 |
|
3 #include "ia32_implicit.h" |
|
4 #include "ia32_insn.h" |
|
5 #include "ia32_reg.h" |
|
6 #include "x86_operand_list.h" |
|
7 |
|
8 /* Conventions: Register operands which are aliases of another register |
|
9 * operand (e.g. AX in one operand and AL in another) assume that the |
|
10 * operands are different registers and that alias tracking will resolve |
|
11 * data flow. This means that something like |
|
12 * mov ax, al |
|
13 * would have 'write only' access for AX and 'read only' access for AL, |
|
14 * even though both AL and AX are read and written */ |
|
15 typedef struct { |
|
16 uint32_t type; |
|
17 uint32_t operand; |
|
18 } op_implicit_list_t; |
|
19 |
|
20 static op_implicit_list_t list_aaa[] = |
|
21 /* 37 : AAA : rw AL */ |
|
22 /* 3F : AAS : rw AL */ |
|
23 {{ OP_R | OP_W, REG_BYTE_OFFSET }, {0}}; /* aaa */ |
|
24 |
|
25 static op_implicit_list_t list_aad[] = |
|
26 /* D5 0A, D5 (ib) : AAD : rw AX */ |
|
27 /* D4 0A, D4 (ib) : AAM : rw AX */ |
|
28 {{ OP_R | OP_W, REG_WORD_OFFSET }, {0}}; /* aad */ |
|
29 |
|
30 static op_implicit_list_t list_call[] = |
|
31 /* E8, FF, 9A, FF : CALL : rw ESP, rw EIP */ |
|
32 /* C2, C3, CA, CB : RET : rw ESP, rw EIP */ |
|
33 {{ OP_R | OP_W, REG_EIP_INDEX }, |
|
34 { OP_R | OP_W, REG_ESP_INDEX }, {0}}; /* call, ret */ |
|
35 |
|
36 static op_implicit_list_t list_cbw[] = |
|
37 /* 98 : CBW : r AL, rw AX */ |
|
38 {{ OP_R | OP_W, REG_WORD_OFFSET }, |
|
39 { OP_R, REG_BYTE_OFFSET}, {0}}; /* cbw */ |
|
40 |
|
41 static op_implicit_list_t list_cwde[] = |
|
42 /* 98 : CWDE : r AX, rw EAX */ |
|
43 {{ OP_R | OP_W, REG_DWORD_OFFSET }, |
|
44 { OP_R, REG_WORD_OFFSET }, {0}}; /* cwde */ |
|
45 |
|
46 static op_implicit_list_t list_clts[] = |
|
47 /* 0F 06 : CLTS : rw CR0 */ |
|
48 {{ OP_R | OP_W, REG_CTRL_OFFSET}, {0}}; /* clts */ |
|
49 |
|
50 static op_implicit_list_t list_cmpxchg[] = |
|
51 /* 0F B0 : CMPXCHG : rw AL */ |
|
52 {{ OP_R | OP_W, REG_BYTE_OFFSET }, {0}}; /* cmpxchg */ |
|
53 |
|
54 static op_implicit_list_t list_cmpxchgb[] = |
|
55 /* 0F B1 : CMPXCHG : rw EAX */ |
|
56 {{ OP_R | OP_W, REG_DWORD_OFFSET }, {0}}; /* cmpxchg */ |
|
57 |
|
58 static op_implicit_list_t list_cmpxchg8b[] = |
|
59 /* 0F C7 : CMPXCHG8B : rw EDX, rw EAX, r ECX, r EBX */ |
|
60 {{ OP_R | OP_W, REG_DWORD_OFFSET }, |
|
61 { OP_R | OP_W, REG_DWORD_OFFSET + 2 }, |
|
62 { OP_R, REG_DWORD_OFFSET + 1 }, |
|
63 { OP_R, REG_DWORD_OFFSET + 3 }, {0}}; /* cmpxchg8b */ |
|
64 |
|
65 static op_implicit_list_t list_cpuid[] = |
|
66 /* 0F A2 : CPUID : rw EAX, w EBX, w ECX, w EDX */ |
|
67 {{ OP_R | OP_W, REG_DWORD_OFFSET }, |
|
68 { OP_W, REG_DWORD_OFFSET + 1 }, |
|
69 { OP_W, REG_DWORD_OFFSET + 2 }, |
|
70 { OP_W, REG_DWORD_OFFSET + 3 }, {0}}; /* cpuid */ |
|
71 |
|
72 static op_implicit_list_t list_cwd[] = |
|
73 /* 99 : CWD/CWQ : rw EAX, w EDX */ |
|
74 {{ OP_R | OP_W, REG_DWORD_OFFSET }, |
|
75 { OP_W, REG_DWORD_OFFSET + 2 }, {0}}; /* cwd */ |
|
76 |
|
77 static op_implicit_list_t list_daa[] = |
|
78 /* 27 : DAA : rw AL */ |
|
79 /* 2F : DAS : rw AL */ |
|
80 {{ OP_R | OP_W, REG_BYTE_OFFSET }, {0}}; /* daa */ |
|
81 |
|
82 static op_implicit_list_t list_idiv[] = |
|
83 /* F6 : DIV, IDIV : r AX, w AL, w AH */ |
|
84 /* FIXED: first op was EAX, not Aw. TODO: verify! */ |
|
85 {{ OP_R, REG_WORD_OFFSET }, |
|
86 { OP_W, REG_BYTE_OFFSET }, |
|
87 { OP_W, REG_BYTE_OFFSET + 4 }, {0}}; /* div */ |
|
88 |
|
89 static op_implicit_list_t list_div[] = |
|
90 /* F7 : DIV, IDIV : rw EDX, rw EAX */ |
|
91 {{ OP_R | OP_W, REG_DWORD_OFFSET + 2 }, |
|
92 { OP_R | OP_W, REG_DWORD_OFFSET }, {0}}; /* div */ |
|
93 |
|
94 static op_implicit_list_t list_enter[] = |
|
95 /* C8 : ENTER : rw ESP w EBP */ |
|
96 {{ OP_R | OP_W, REG_DWORD_OFFSET + 4 }, |
|
97 { OP_R, REG_DWORD_OFFSET + 5 }, {0}}; /* enter */ |
|
98 |
|
99 static op_implicit_list_t list_f2xm1[] = |
|
100 /* D9 F0 : F2XM1 : rw ST(0) */ |
|
101 /* D9 E1 : FABS : rw ST(0) */ |
|
102 /* D9 E0 : FCHS : rw ST(0) */ |
|
103 /* D9 FF : FCOS : rw ST(0)*/ |
|
104 /* D8, DA : FDIV : rw ST(0) */ |
|
105 /* D8, DA : FDIVR : rw ST(0) */ |
|
106 /* D9 F2 : FPTAN : rw ST(0) */ |
|
107 /* D9 FC : FRNDINT : rw ST(0) */ |
|
108 /* D9 FB : FSINCOS : rw ST(0) */ |
|
109 /* D9 FE : FSIN : rw ST(0) */ |
|
110 /* D9 FA : FSQRT : rw ST(0) */ |
|
111 /* D9 F4 : FXTRACT : rw ST(0) */ |
|
112 {{ OP_R | OP_W, REG_FPU_OFFSET }, {0}}; /* f2xm1 */ |
|
113 |
|
114 static op_implicit_list_t list_fcom[] = |
|
115 /* D8, DC, DE D9 : FCOM : r ST(0) */ |
|
116 /* DE, DA : FICOM : r ST(0) */ |
|
117 /* DF, D8 : FIST : r ST(0) */ |
|
118 /* D9 E4 : FTST : r ST(0) */ |
|
119 /* D9 E5 : FXAM : r ST(0) */ |
|
120 {{ OP_R, REG_FPU_OFFSET }, {0}}; /* fcom */ |
|
121 |
|
122 static op_implicit_list_t list_fpatan[] = |
|
123 /* D9 F3 : FPATAN : r ST(0), rw ST(1) */ |
|
124 {{ OP_R, REG_FPU_OFFSET }, {0}}; /* fpatan */ |
|
125 |
|
126 static op_implicit_list_t list_fprem[] = |
|
127 /* D9 F8, D9 F5 : FPREM : rw ST(0) r ST(1) */ |
|
128 /* D9 FD : FSCALE : rw ST(0), r ST(1) */ |
|
129 {{ OP_R | OP_W, REG_FPU_OFFSET }, |
|
130 { OP_R, REG_FPU_OFFSET + 1 }, {0}}; /* fprem */ |
|
131 |
|
132 static op_implicit_list_t list_faddp[] = |
|
133 /* DE C1 : FADDP : r ST(0), rw ST(1) */ |
|
134 /* DE E9 : FSUBP : r ST(0), rw ST(1) */ |
|
135 /* D9 F1 : FYL2X : r ST(0), rw ST(1) */ |
|
136 /* D9 F9 : FYL2XP1 : r ST(0), rw ST(1) */ |
|
137 {{ OP_R, REG_FPU_OFFSET }, |
|
138 { OP_R | OP_W, REG_FPU_OFFSET + 1 }, {0}}; /* faddp */ |
|
139 |
|
140 static op_implicit_list_t list_fucompp[] = |
|
141 /* DA E9 : FUCOMPP : r ST(0), r ST(1) */ |
|
142 {{ OP_R, REG_FPU_OFFSET }, |
|
143 { OP_R, REG_FPU_OFFSET + 1 }, {0}}; /* fucompp */ |
|
144 |
|
145 static op_implicit_list_t list_imul[] = |
|
146 /* F6 : IMUL : r AL, w AX */ |
|
147 /* F6 : MUL : r AL, w AX */ |
|
148 {{ OP_R, REG_BYTE_OFFSET }, |
|
149 { OP_W, REG_WORD_OFFSET }, {0}}; /* imul */ |
|
150 |
|
151 static op_implicit_list_t list_mul[] = |
|
152 /* F7 : IMUL : rw EAX, w EDX */ |
|
153 /* F7 : MUL : rw EAX, w EDX */ |
|
154 {{ OP_R | OP_W, REG_DWORD_OFFSET }, |
|
155 { OP_W, REG_DWORD_OFFSET + 2 }, {0}}; /* imul */ |
|
156 |
|
157 static op_implicit_list_t list_lahf[] = |
|
158 /* 9F : LAHF : r EFLAGS, w AH */ |
|
159 {{ OP_R, REG_FLAGS_INDEX }, |
|
160 { OP_W, REG_BYTE_OFFSET + 4 }, {0}}; /* lahf */ |
|
161 |
|
162 static op_implicit_list_t list_ldmxcsr[] = |
|
163 /* 0F AE : LDMXCSR : w MXCSR SSE Control Status Reg */ |
|
164 {{ OP_W, REG_MXCSG_INDEX }, {0}}; /* ldmxcsr */ |
|
165 |
|
166 static op_implicit_list_t list_leave[] = |
|
167 /* C9 : LEAVE : rw ESP, w EBP */ |
|
168 {{ OP_R | OP_W, REG_ESP_INDEX }, |
|
169 { OP_W, REG_DWORD_OFFSET + 5 }, {0}}; /* leave */ |
|
170 |
|
171 static op_implicit_list_t list_lgdt[] = |
|
172 /* 0F 01 : LGDT : w GDTR */ |
|
173 {{ OP_W, REG_GDTR_INDEX }, {0}}; /* lgdt */ |
|
174 |
|
175 static op_implicit_list_t list_lidt[] = |
|
176 /* 0F 01 : LIDT : w IDTR */ |
|
177 {{ OP_W, REG_IDTR_INDEX }, {0}}; /* lidt */ |
|
178 |
|
179 static op_implicit_list_t list_lldt[] = |
|
180 /* 0F 00 : LLDT : w LDTR */ |
|
181 {{ OP_W, REG_LDTR_INDEX }, {0}}; /* lldt */ |
|
182 |
|
183 static op_implicit_list_t list_lmsw[] = |
|
184 /* 0F 01 : LMSW : w CR0 */ |
|
185 {{ OP_W, REG_CTRL_OFFSET }, {0}}; /* lmsw */ |
|
186 |
|
187 static op_implicit_list_t list_loop[] = |
|
188 /* E0, E1, E2 : LOOP : rw ECX */ |
|
189 {{ OP_R | OP_W, REG_DWORD_OFFSET + 1 }, {0}};/* loop */ |
|
190 |
|
191 static op_implicit_list_t list_ltr[] = |
|
192 /* 0F 00 : LTR : w Task Register */ |
|
193 {{ OP_W, REG_TR_INDEX }, {0}}; /* ltr */ |
|
194 |
|
195 static op_implicit_list_t list_pop[] = |
|
196 /* 8F, 58, 1F, 07, 17, 0F A1, 0F A9 : POP : rw ESP */ |
|
197 /* FF, 50, 6A, 68, 0E, 16, 1E, 06, 0F A0, 0F A8 : PUSH : rw ESP */ |
|
198 {{ OP_R | OP_W, REG_ESP_INDEX }, {0}}; /* pop, push */ |
|
199 |
|
200 static op_implicit_list_t list_popad[] = |
|
201 /* 61 : POPAD : rw esp, w edi esi ebp ebx edx ecx eax */ |
|
202 {{ OP_R | OP_W, REG_ESP_INDEX }, |
|
203 { OP_W, REG_DWORD_OFFSET + 7 }, |
|
204 { OP_W, REG_DWORD_OFFSET + 6 }, |
|
205 { OP_W, REG_DWORD_OFFSET + 5 }, |
|
206 { OP_W, REG_DWORD_OFFSET + 3 }, |
|
207 { OP_W, REG_DWORD_OFFSET + 2 }, |
|
208 { OP_W, REG_DWORD_OFFSET + 1 }, |
|
209 { OP_W, REG_DWORD_OFFSET }, {0}}; /* popad */ |
|
210 |
|
211 static op_implicit_list_t list_popfd[] = |
|
212 /* 9D : POPFD : rw esp, w eflags */ |
|
213 {{ OP_R | OP_W, REG_ESP_INDEX }, |
|
214 { OP_W, REG_FLAGS_INDEX }, {0}}; /* popfd */ |
|
215 |
|
216 static op_implicit_list_t list_pushad[] = |
|
217 /* FF, 50, 6A, 68, 0E, 16, 1E, 06, 0F A0, 0F A8 : PUSH : rw ESP */ |
|
218 /* 60 : PUSHAD : rw esp, r eax ecx edx ebx esp ebp esi edi */ |
|
219 {{ OP_R | OP_W, REG_ESP_INDEX }, |
|
220 { OP_R, REG_DWORD_OFFSET }, |
|
221 { OP_R, REG_DWORD_OFFSET + 1 }, |
|
222 { OP_R, REG_DWORD_OFFSET + 2 }, |
|
223 { OP_R, REG_DWORD_OFFSET + 3 }, |
|
224 { OP_R, REG_DWORD_OFFSET + 5 }, |
|
225 { OP_R, REG_DWORD_OFFSET + 6 }, |
|
226 { OP_R, REG_DWORD_OFFSET + 7 }, {0}}; /* pushad */ |
|
227 |
|
228 static op_implicit_list_t list_pushfd[] = |
|
229 /* 9C : PUSHFD : rw esp, r eflags */ |
|
230 {{ OP_R | OP_W, REG_ESP_INDEX }, |
|
231 { OP_R, REG_FLAGS_INDEX }, {0}}; /* pushfd */ |
|
232 |
|
233 static op_implicit_list_t list_rdmsr[] = |
|
234 /* 0F 32 : RDMSR : r ECX, w EDX, w EAX */ |
|
235 {{ OP_R, REG_DWORD_OFFSET + 1 }, |
|
236 { OP_W, REG_DWORD_OFFSET + 2 }, |
|
237 { OP_W, REG_DWORD_OFFSET }, {0}}; /* rdmsr */ |
|
238 |
|
239 static op_implicit_list_t list_rdpmc[] = |
|
240 /* 0F 33 : RDPMC : r ECX, w EDX, w EAX */ |
|
241 {{ OP_R, REG_DWORD_OFFSET + 1 }, |
|
242 { OP_W, REG_DWORD_OFFSET + 2 }, |
|
243 { OP_W, REG_DWORD_OFFSET }, {0}}; /* rdpmc */ |
|
244 |
|
245 static op_implicit_list_t list_rdtsc[] = |
|
246 /* 0F 31 : RDTSC : rw EDX, rw EAX */ |
|
247 {{ OP_R | OP_W, REG_DWORD_OFFSET + 2 }, |
|
248 { OP_R | OP_W, REG_DWORD_OFFSET }, {0}}; /* rdtsc */ |
|
249 |
|
250 static op_implicit_list_t list_rep[] = |
|
251 /* F3, F2 ... : REP : rw ECX */ |
|
252 {{ OP_R | OP_W, REG_DWORD_OFFSET + 1 }, {0}};/* rep */ |
|
253 |
|
254 static op_implicit_list_t list_rsm[] = |
|
255 /* 0F AA : RSM : r CR4, r CR0 */ |
|
256 {{ OP_R, REG_CTRL_OFFSET + 4 }, |
|
257 { OP_R, REG_CTRL_OFFSET }, {0}}; /* rsm */ |
|
258 |
|
259 static op_implicit_list_t list_sahf[] = |
|
260 /* 9E : SAHF : r ah, rw eflags (set SF ZF AF PF CF) */ |
|
261 {{ OP_R, REG_DWORD_OFFSET }, {0}}; /* sahf */ |
|
262 |
|
263 static op_implicit_list_t list_sgdt[] = |
|
264 /* 0F : SGDT : r gdtr */ |
|
265 /* TODO: finish this! */ |
|
266 {{ OP_R, REG_DWORD_OFFSET }, {0}}; /* sgdt */ |
|
267 |
|
268 static op_implicit_list_t list_sidt[] = |
|
269 /* 0F : SIDT : r idtr */ |
|
270 /* TODO: finish this! */ |
|
271 {{ OP_R, REG_DWORD_OFFSET }, {0}}; /* sidt */ |
|
272 |
|
273 static op_implicit_list_t list_sldt[] = |
|
274 /* 0F : SLDT : r ldtr */ |
|
275 /* TODO: finish this! */ |
|
276 {{ OP_R, REG_DWORD_OFFSET }, {0}}; /* sldt */ |
|
277 |
|
278 static op_implicit_list_t list_smsw[] = |
|
279 /* 0F : SMSW : r CR0 */ |
|
280 /* TODO: finish this! */ |
|
281 {{ OP_R, REG_DWORD_OFFSET }, {0}}; /* smsw */ |
|
282 |
|
283 static op_implicit_list_t list_stmxcsr[] = |
|
284 /* 0F AE : STMXCSR : r MXCSR */ |
|
285 /* TODO: finish this! */ |
|
286 {{ OP_R, REG_DWORD_OFFSET }, {0}}; /* stmxcsr */ |
|
287 |
|
288 static op_implicit_list_t list_str[] = |
|
289 /* 0F 00 : STR : r TR (task register) */ |
|
290 /* TODO: finish this! */ |
|
291 {{ OP_R, REG_DWORD_OFFSET }, {0}}; /* str */ |
|
292 |
|
293 static op_implicit_list_t list_sysenter[] = |
|
294 /* 0F 34 : SYSENTER : w cs, w eip, w ss, w esp, r CR0, w eflags |
|
295 * r sysenter_cs_msr, sysenter_esp_msr, sysenter_eip_msr */ |
|
296 /* TODO: finish this! */ |
|
297 {{ OP_R, REG_DWORD_OFFSET }, {0}}; /* sysenter */ |
|
298 |
|
299 static op_implicit_list_t list_sysexit[] = |
|
300 /* 0F 35 : SYSEXIT : r edx, r ecx, w cs, w eip, w ss, w esp |
|
301 * r sysenter_cs_msr */ |
|
302 /* TODO: finish this! */ |
|
303 {{ OP_R, REG_DWORD_OFFSET }, {0}}; /* sysexit */ |
|
304 |
|
305 static op_implicit_list_t list_wrmsr[] = |
|
306 /* 0F 30 : WRMST : r edx, r eax, r ecx */ |
|
307 /* TODO: finish this! */ |
|
308 {{ OP_R, REG_DWORD_OFFSET }, {0}}; /* wrmsr */ |
|
309 |
|
310 static op_implicit_list_t list_xlat[] = |
|
311 /* D7 : XLAT : rw al r ebx (ptr) */ |
|
312 /* TODO: finish this! */ |
|
313 {{ OP_R, REG_DWORD_OFFSET }, {0}}; /* xlat */ |
|
314 /* TODO: |
|
315 * monitor 0f 01 c8 eax OP_R ecx OP_R edx OP_R |
|
316 * mwait 0f 01 c9 eax OP_R ecx OP_R |
|
317 */ |
|
318 static op_implicit_list_t list_monitor[] = |
|
319 {{ OP_R, REG_DWORD_OFFSET }, {0}}; /* monitor */ |
|
320 static op_implicit_list_t list_mwait[] = |
|
321 {{ OP_R, REG_DWORD_OFFSET }, {0}}; /* mwait */ |
|
322 |
|
323 op_implicit_list_t *op_implicit_list[] = { |
|
324 /* This is a list of implicit operands which are read/written by |
|
325 * various x86 instructions. Note that modifications to the stack |
|
326 * register are mentioned here, but that additional information on |
|
327 * the effect an instruction has on the stack is contained in the |
|
328 * x86_insn_t 'stack_mod' and 'stack_mod_val' fields. Use of the |
|
329 * eflags register, i.e. setting, clearing, and testing flags, is |
|
330 * not recorded here but rather in the flags_set and flags_tested |
|
331 * fields of the x86_insn_t.*/ |
|
332 NULL, |
|
333 list_aaa, list_aad, list_call, list_cbw, /* 1 - 4 */ |
|
334 list_cwde, list_clts, list_cmpxchg, list_cmpxchgb, /* 5 - 8 */ |
|
335 list_cmpxchg8b, list_cpuid, list_cwd, list_daa, /* 9 - 12 */ |
|
336 list_idiv, list_div, list_enter, list_f2xm1, /* 13 - 16 */ |
|
337 list_fcom, list_fpatan, list_fprem, list_faddp, /* 17 - 20 */ |
|
338 list_fucompp, list_imul, list_mul, list_lahf, /* 21 - 24 */ |
|
339 list_ldmxcsr, list_leave, list_lgdt, list_lidt, /* 25 - 28 */ |
|
340 list_lldt, list_lmsw, list_loop, list_ltr, /* 29 - 32 */ |
|
341 list_pop, list_popad, list_popfd, list_pushad, /* 33 - 36 */ |
|
342 list_pushfd, list_rdmsr, list_rdpmc, list_rdtsc, /* 37 - 40 */ |
|
343 /* NOTE: 'REP' is a hack since it is a prefix: if its position |
|
344 * in the table changes, then change IDX_IMPLICIT_REP in the .h */ |
|
345 list_rep, list_rsm, list_sahf, list_sgdt, /* 41 - 44 */ |
|
346 list_sidt, list_sldt, list_smsw, list_stmxcsr, /* 45 - 48 */ |
|
347 list_str, list_sysenter, list_sysexit, list_wrmsr, /* 49 - 52 */ |
|
348 list_xlat, list_monitor, list_mwait, /* 53 - 55*/ |
|
349 NULL /* end of list */ |
|
350 }; |
|
351 |
|
352 #define LAST_IMPL_IDX 55 |
|
353 |
|
354 static void handle_impl_reg( x86_op_t *op, uint32_t val ) { |
|
355 x86_reg_t *reg = &op->data.reg; |
|
356 op->type = op_register; |
|
357 ia32_handle_register( reg, (unsigned int) val ); |
|
358 switch (reg->size) { |
|
359 case 1: |
|
360 op->datatype = op_byte; break; |
|
361 case 2: |
|
362 op->datatype = op_word; break; |
|
363 case 4: |
|
364 op->datatype = op_dword; break; |
|
365 case 8: |
|
366 op->datatype = op_qword; break; |
|
367 case 10: |
|
368 op->datatype = op_extreal; break; |
|
369 case 16: |
|
370 op->datatype = op_dqword; break; |
|
371 } |
|
372 return; |
|
373 } |
|
374 |
|
375 /* 'impl_idx' is the value from the opcode table: between 1 and LAST_IMPL_IDX */ |
|
376 /* returns number of operands added */ |
|
377 unsigned int ia32_insn_implicit_ops( x86_insn_t *insn, unsigned int impl_idx ) { |
|
378 op_implicit_list_t *list; |
|
379 x86_op_t *op; |
|
380 unsigned int num = 0; |
|
381 |
|
382 if (! impl_idx || impl_idx > LAST_IMPL_IDX ) { |
|
383 return 0; |
|
384 } |
|
385 |
|
386 for ( list = op_implicit_list[impl_idx]; list->type; list++, num++ ) { |
|
387 enum x86_op_access access = (enum x86_op_access) OP_PERM(list->type); |
|
388 enum x86_op_flags flags = (enum x86_op_flags) (OP_FLAGS(list->type) >> 12); |
|
389 |
|
390 op = NULL; |
|
391 /* In some cases (MUL), EAX is an implicit operand hardcoded in |
|
392 * the instruction without being explicitly listed in assembly. |
|
393 * For this situation, find the hardcoded operand and add the |
|
394 * implied flag rather than adding a new implicit operand. */ |
|
395 x86_oplist_t * existing; |
|
396 if (ia32_true_register_id(list->operand) == REG_DWORD_OFFSET) { |
|
397 for ( existing = insn->operands; existing; existing = existing->next ) { |
|
398 if (existing->op.type == op_register && |
|
399 existing->op.data.reg.id == list->operand) { |
|
400 op = &existing->op; |
|
401 break; |
|
402 } |
|
403 } |
|
404 } |
|
405 if (!op) { |
|
406 op = x86_operand_new( insn ); |
|
407 /* all implicit operands are registers */ |
|
408 handle_impl_reg( op, list->operand ); |
|
409 /* decrement the 'explicit count' incremented by default in |
|
410 * x86_operand_new */ |
|
411 insn->explicit_count = insn->explicit_count -1; |
|
412 } |
|
413 if (!op) { |
|
414 return num; /* gah! return early */ |
|
415 } |
|
416 op->access |= access; |
|
417 op->flags |= flags; |
|
418 op->flags |= op_implied; |
|
419 } |
|
420 |
|
421 return num; |
|
422 } |