Commit | Line | Data |
---|---|---|
196ba1fc PH |
1 | /* disasm.c where all the _work_ gets done in the Netwide Disassembler\r |
2 | *\r | |
3 | * The Netwide Assembler is copyright (C) 1996 Simon Tatham and\r | |
4 | * Julian Hall. All rights reserved. The software is\r | |
5 | * redistributable under the licence given in the file "Licence"\r | |
6 | * distributed in the NASM archive.\r | |
7 | *\r | |
8 | * initial version 27/iii/95 by Simon Tatham\r | |
9 | */\r | |
10 | \r | |
11 | #include <stdio.h>\r | |
12 | #include <string.h>\r | |
13 | \r | |
14 | #include "nasm.h"\r | |
15 | #include "insns.h"\r | |
16 | \r | |
17 | /* names.c included source file defining instruction and register\r | |
18 | * names for the Netwide [Dis]Assembler\r | |
19 | *\r | |
20 | * The Netwide Assembler is copyright (C) 1996 Simon Tatham and\r | |
21 | * Julian Hall. All rights reserved. The software is\r | |
22 | * redistributable under the licence given in the file "Licence"\r | |
23 | * distributed in the NASM archive.\r | |
24 | */\r | |
25 | \r | |
26 | static const char *conditions[] = { /* condition code names */\r | |
27 | "a", "ae", "b", "be", "c", "e", "g", "ge", "l", "le", "na", "nae",\r | |
28 | "nb", "nbe", "nc", "ne", "ng", "nge", "nl", "nle", "no", "np",\r | |
29 | "ns", "nz", "o", "p", "pe", "po", "s", "z"\r | |
30 | };\r | |
31 | \r | |
32 | /* Register names automatically generated from regs.dat */\r | |
33 | /* automatically generated from ./regs.dat - do not edit */\r | |
34 | static const char *reg_names[] = {\r | |
35 | "ah",\r | |
36 | "al",\r | |
37 | "ax",\r | |
38 | "bh",\r | |
39 | "bl",\r | |
40 | "bp",\r | |
41 | "bx",\r | |
42 | "ch",\r | |
43 | "cl",\r | |
44 | "cr0",\r | |
45 | "cr1",\r | |
46 | "cr2",\r | |
47 | "cr3",\r | |
48 | "cr4",\r | |
49 | "cr5",\r | |
50 | "cr6",\r | |
51 | "cr7",\r | |
52 | "cs",\r | |
53 | "cx",\r | |
54 | "dh",\r | |
55 | "di",\r | |
56 | "dl",\r | |
57 | "dr0",\r | |
58 | "dr1",\r | |
59 | "dr2",\r | |
60 | "dr3",\r | |
61 | "dr4",\r | |
62 | "dr5",\r | |
63 | "dr6",\r | |
64 | "dr7",\r | |
65 | "ds",\r | |
66 | "dx",\r | |
67 | "eax",\r | |
68 | "ebp",\r | |
69 | "ebx",\r | |
70 | "ecx",\r | |
71 | "edi",\r | |
72 | "edx",\r | |
73 | "es",\r | |
74 | "esi",\r | |
75 | "esp",\r | |
76 | "fs",\r | |
77 | "gs",\r | |
78 | "mm0",\r | |
79 | "mm1",\r | |
80 | "mm2",\r | |
81 | "mm3",\r | |
82 | "mm4",\r | |
83 | "mm5",\r | |
84 | "mm6",\r | |
85 | "mm7",\r | |
86 | "segr6",\r | |
87 | "segr7",\r | |
88 | "si",\r | |
89 | "sp",\r | |
90 | "ss",\r | |
91 | "st0",\r | |
92 | "st1",\r | |
93 | "st2",\r | |
94 | "st3",\r | |
95 | "st4",\r | |
96 | "st5",\r | |
97 | "st6",\r | |
98 | "st7",\r | |
99 | "tr0",\r | |
100 | "tr1",\r | |
101 | "tr2",\r | |
102 | "tr3",\r | |
103 | "tr4",\r | |
104 | "tr5",\r | |
105 | "tr6",\r | |
106 | "tr7",\r | |
107 | "xmm0",\r | |
108 | "xmm1",\r | |
109 | "xmm2",\r | |
110 | "xmm3",\r | |
111 | "xmm4",\r | |
112 | "xmm5",\r | |
113 | "xmm6",\r | |
114 | "xmm7"\r | |
115 | };\r | |
116 | \r | |
117 | /* Instruction names automatically generated from insns.dat */\r | |
118 | /* This file is auto-generated from insns.dat by insns.pl - don't edit it */\r | |
119 | /* This file in included by names.c */\r | |
120 | static const char *insn_names[] = {\r | |
121 | "aaa",\r | |
122 | "aad",\r | |
123 | "aam",\r | |
124 | "aas",\r | |
125 | "adc",\r | |
126 | "add",\r | |
127 | "addpd",\r | |
128 | "addps",\r | |
129 | "addsd",\r | |
130 | "addss",\r | |
131 | "addsubpd",\r | |
132 | "addsubps",\r | |
133 | "and",\r | |
134 | "andnpd",\r | |
135 | "andnps",\r | |
136 | "andpd",\r | |
137 | "andps",\r | |
138 | "arpl",\r | |
139 | "bound",\r | |
140 | "bsf",\r | |
141 | "bsr",\r | |
142 | "bswap",\r | |
143 | "bt",\r | |
144 | "btc",\r | |
145 | "btr",\r | |
146 | "bts",\r | |
147 | "call",\r | |
148 | "cbw",\r | |
149 | "cdq",\r | |
150 | "clc",\r | |
151 | "cld",\r | |
152 | "clflush",\r | |
153 | "cli",\r | |
154 | "clts",\r | |
155 | "cmc",\r | |
156 | "cmp",\r | |
157 | "cmpeqpd",\r | |
158 | "cmpeqps",\r | |
159 | "cmpeqsd",\r | |
160 | "cmpeqss",\r | |
161 | "cmplepd",\r | |
162 | "cmpleps",\r | |
163 | "cmplesd",\r | |
164 | "cmpless",\r | |
165 | "cmpltpd",\r | |
166 | "cmpltps",\r | |
167 | "cmpltsd",\r | |
168 | "cmpltss",\r | |
169 | "cmpneqpd",\r | |
170 | "cmpneqps",\r | |
171 | "cmpneqsd",\r | |
172 | "cmpneqss",\r | |
173 | "cmpnlepd",\r | |
174 | "cmpnleps",\r | |
175 | "cmpnlesd",\r | |
176 | "cmpnless",\r | |
177 | "cmpnltpd",\r | |
178 | "cmpnltps",\r | |
179 | "cmpnltsd",\r | |
180 | "cmpnltss",\r | |
181 | "cmpordpd",\r | |
182 | "cmpordps",\r | |
183 | "cmpordsd",\r | |
184 | "cmpordss",\r | |
185 | "cmppd",\r | |
186 | "cmpps",\r | |
187 | "cmpsb",\r | |
188 | "cmpsd",\r | |
189 | "cmpss",\r | |
190 | "cmpsw",\r | |
191 | "cmpunordpd",\r | |
192 | "cmpunordps",\r | |
193 | "cmpunordsd",\r | |
194 | "cmpunordss",\r | |
195 | "cmpxchg",\r | |
196 | "cmpxchg486",\r | |
197 | "cmpxchg8b",\r | |
198 | "comisd",\r | |
199 | "comiss",\r | |
200 | "cpuid",\r | |
201 | "cvtdq2pd",\r | |
202 | "cvtdq2ps",\r | |
203 | "cvtpd2dq",\r | |
204 | "cvtpd2pi",\r | |
205 | "cvtpd2ps",\r | |
206 | "cvtpi2pd",\r | |
207 | "cvtpi2ps",\r | |
208 | "cvtps2dq",\r | |
209 | "cvtps2pd",\r | |
210 | "cvtps2pi",\r | |
211 | "cvtsd2si",\r | |
212 | "cvtsd2ss",\r | |
213 | "cvtsi2sd",\r | |
214 | "cvtsi2ss",\r | |
215 | "cvtss2sd",\r | |
216 | "cvtss2si",\r | |
217 | "cvttpd2dq",\r | |
218 | "cvttpd2pi",\r | |
219 | "cvttps2dq",\r | |
220 | "cvttps2pi",\r | |
221 | "cvttsd2si",\r | |
222 | "cvttss2si",\r | |
223 | "cwd",\r | |
224 | "cwde",\r | |
225 | "daa",\r | |
226 | "das",\r | |
227 | "db",\r | |
228 | "dd",\r | |
229 | "dec",\r | |
230 | "div",\r | |
231 | "divpd",\r | |
232 | "divps",\r | |
233 | "divsd",\r | |
234 | "divss",\r | |
235 | "dq",\r | |
236 | "dt",\r | |
237 | "dw",\r | |
238 | "emms",\r | |
239 | "enter",\r | |
240 | "equ",\r | |
241 | "f2xm1",\r | |
242 | "fabs",\r | |
243 | "fadd",\r | |
244 | "faddp",\r | |
245 | "fbld",\r | |
246 | "fbstp",\r | |
247 | "fchs",\r | |
248 | "fclex",\r | |
249 | "fcmovb",\r | |
250 | "fcmovbe",\r | |
251 | "fcmove",\r | |
252 | "fcmovnb",\r | |
253 | "fcmovnbe",\r | |
254 | "fcmovne",\r | |
255 | "fcmovnu",\r | |
256 | "fcmovu",\r | |
257 | "fcom",\r | |
258 | "fcomi",\r | |
259 | "fcomip",\r | |
260 | "fcomp",\r | |
261 | "fcompp",\r | |
262 | "fcos",\r | |
263 | "fdecstp",\r | |
264 | "fdisi",\r | |
265 | "fdiv",\r | |
266 | "fdivp",\r | |
267 | "fdivr",\r | |
268 | "fdivrp",\r | |
269 | "femms",\r | |
270 | "feni",\r | |
271 | "ffree",\r | |
272 | "ffreep",\r | |
273 | "fiadd",\r | |
274 | "ficom",\r | |
275 | "ficomp",\r | |
276 | "fidiv",\r | |
277 | "fidivr",\r | |
278 | "fild",\r | |
279 | "fimul",\r | |
280 | "fincstp",\r | |
281 | "finit",\r | |
282 | "fist",\r | |
283 | "fistp",\r | |
284 | "fisttp",\r | |
285 | "fisub",\r | |
286 | "fisubr",\r | |
287 | "fld",\r | |
288 | "fld1",\r | |
289 | "fldcw",\r | |
290 | "fldenv",\r | |
291 | "fldl2e",\r | |
292 | "fldl2t",\r | |
293 | "fldlg2",\r | |
294 | "fldln2",\r | |
295 | "fldpi",\r | |
296 | "fldz",\r | |
297 | "fmul",\r | |
298 | "fmulp",\r | |
299 | "fnclex",\r | |
300 | "fndisi",\r | |
301 | "fneni",\r | |
302 | "fninit",\r | |
303 | "fnop",\r | |
304 | "fnsave",\r | |
305 | "fnstcw",\r | |
306 | "fnstenv",\r | |
307 | "fnstsw",\r | |
308 | "fpatan",\r | |
309 | "fprem",\r | |
310 | "fprem1",\r | |
311 | "fptan",\r | |
312 | "frndint",\r | |
313 | "frstor",\r | |
314 | "fsave",\r | |
315 | "fscale",\r | |
316 | "fsetpm",\r | |
317 | "fsin",\r | |
318 | "fsincos",\r | |
319 | "fsqrt",\r | |
320 | "fst",\r | |
321 | "fstcw",\r | |
322 | "fstenv",\r | |
323 | "fstp",\r | |
324 | "fstsw",\r | |
325 | "fsub",\r | |
326 | "fsubp",\r | |
327 | "fsubr",\r | |
328 | "fsubrp",\r | |
329 | "ftst",\r | |
330 | "fucom",\r | |
331 | "fucomi",\r | |
332 | "fucomip",\r | |
333 | "fucomp",\r | |
334 | "fucompp",\r | |
335 | "fwait",\r | |
336 | "fxam",\r | |
337 | "fxch",\r | |
338 | "fxrstor",\r | |
339 | "fxsave",\r | |
340 | "fxtract",\r | |
341 | "fyl2x",\r | |
342 | "fyl2xp1",\r | |
343 | "haddpd",\r | |
344 | "haddps",\r | |
345 | "hlt",\r | |
346 | "hsubpd",\r | |
347 | "hsubps",\r | |
348 | "ibts",\r | |
349 | "icebp",\r | |
350 | "idiv",\r | |
351 | "imul",\r | |
352 | "in",\r | |
353 | "inc",\r | |
354 | "incbin",\r | |
355 | "insb",\r | |
356 | "insd",\r | |
357 | "insw",\r | |
358 | "int",\r | |
359 | "int01",\r | |
360 | "int03",\r | |
361 | "int1",\r | |
362 | "int3",\r | |
363 | "into",\r | |
364 | "invd",\r | |
365 | "invlpg",\r | |
366 | "iret",\r | |
367 | "iretd",\r | |
368 | "iretw",\r | |
369 | "jcxz",\r | |
370 | "jecxz",\r | |
371 | "jmp",\r | |
372 | "jmpe",\r | |
373 | "lahf",\r | |
374 | "lar",\r | |
375 | "lddqu",\r | |
376 | "ldmxcsr",\r | |
377 | "lds",\r | |
378 | "lea",\r | |
379 | "leave",\r | |
380 | "les",\r | |
381 | "lfence",\r | |
382 | "lfs",\r | |
383 | "lgdt",\r | |
384 | "lgs",\r | |
385 | "lidt",\r | |
386 | "lldt",\r | |
387 | "lmsw",\r | |
388 | "loadall",\r | |
389 | "loadall286",\r | |
390 | "lodsb",\r | |
391 | "lodsd",\r | |
392 | "lodsw",\r | |
393 | "loop",\r | |
394 | "loope",\r | |
395 | "loopne",\r | |
396 | "loopnz",\r | |
397 | "loopz",\r | |
398 | "lsl",\r | |
399 | "lss",\r | |
400 | "ltr",\r | |
401 | "maskmovdqu",\r | |
402 | "maskmovq",\r | |
403 | "maxpd",\r | |
404 | "maxps",\r | |
405 | "maxsd",\r | |
406 | "maxss",\r | |
407 | "mfence",\r | |
408 | "minpd",\r | |
409 | "minps",\r | |
410 | "minsd",\r | |
411 | "minss",\r | |
412 | "monitor",\r | |
413 | "mov",\r | |
414 | "movapd",\r | |
415 | "movaps",\r | |
416 | "movd",\r | |
417 | "movddup",\r | |
418 | "movdq2q",\r | |
419 | "movdqa",\r | |
420 | "movdqu",\r | |
421 | "movhlps",\r | |
422 | "movhpd",\r | |
423 | "movhps",\r | |
424 | "movlhps",\r | |
425 | "movlpd",\r | |
426 | "movlps",\r | |
427 | "movmskpd",\r | |
428 | "movmskps",\r | |
429 | "movntdq",\r | |
430 | "movnti",\r | |
431 | "movntpd",\r | |
432 | "movntps",\r | |
433 | "movntq",\r | |
434 | "movq",\r | |
435 | "movq2dq",\r | |
436 | "movsb",\r | |
437 | "movsd",\r | |
438 | "movshdup",\r | |
439 | "movsldup",\r | |
440 | "movss",\r | |
441 | "movsw",\r | |
442 | "movsx",\r | |
443 | "movupd",\r | |
444 | "movups",\r | |
445 | "movzx",\r | |
446 | "mul",\r | |
447 | "mulpd",\r | |
448 | "mulps",\r | |
449 | "mulsd",\r | |
450 | "mulss",\r | |
451 | "mwait",\r | |
452 | "neg",\r | |
453 | "nop",\r | |
454 | "not",\r | |
455 | "or",\r | |
456 | "orpd",\r | |
457 | "orps",\r | |
458 | "out",\r | |
459 | "outsb",\r | |
460 | "outsd",\r | |
461 | "outsw",\r | |
462 | "packssdw",\r | |
463 | "packsswb",\r | |
464 | "packuswb",\r | |
465 | "paddb",\r | |
466 | "paddd",\r | |
467 | "paddq",\r | |
468 | "paddsb",\r | |
469 | "paddsiw",\r | |
470 | "paddsw",\r | |
471 | "paddusb",\r | |
472 | "paddusw",\r | |
473 | "paddw",\r | |
474 | "pand",\r | |
475 | "pandn",\r | |
476 | "pause",\r | |
477 | "paveb",\r | |
478 | "pavgb",\r | |
479 | "pavgusb",\r | |
480 | "pavgw",\r | |
481 | "pcmpeqb",\r | |
482 | "pcmpeqd",\r | |
483 | "pcmpeqw",\r | |
484 | "pcmpgtb",\r | |
485 | "pcmpgtd",\r | |
486 | "pcmpgtw",\r | |
487 | "pdistib",\r | |
488 | "pextrw",\r | |
489 | "pf2id",\r | |
490 | "pf2iw",\r | |
491 | "pfacc",\r | |
492 | "pfadd",\r | |
493 | "pfcmpeq",\r | |
494 | "pfcmpge",\r | |
495 | "pfcmpgt",\r | |
496 | "pfmax",\r | |
497 | "pfmin",\r | |
498 | "pfmul",\r | |
499 | "pfnacc",\r | |
500 | "pfpnacc",\r | |
501 | "pfrcp",\r | |
502 | "pfrcpit1",\r | |
503 | "pfrcpit2",\r | |
504 | "pfrsqit1",\r | |
505 | "pfrsqrt",\r | |
506 | "pfsub",\r | |
507 | "pfsubr",\r | |
508 | "pi2fd",\r | |
509 | "pi2fw",\r | |
510 | "pinsrw",\r | |
511 | "pmachriw",\r | |
512 | "pmaddwd",\r | |
513 | "pmagw",\r | |
514 | "pmaxsw",\r | |
515 | "pmaxub",\r | |
516 | "pminsw",\r | |
517 | "pminub",\r | |
518 | "pmovmskb",\r | |
519 | "pmulhriw",\r | |
520 | "pmulhrwa",\r | |
521 | "pmulhrwc",\r | |
522 | "pmulhuw",\r | |
523 | "pmulhw",\r | |
524 | "pmullw",\r | |
525 | "pmuludq",\r | |
526 | "pmvgezb",\r | |
527 | "pmvlzb",\r | |
528 | "pmvnzb",\r | |
529 | "pmvzb",\r | |
530 | "pop",\r | |
531 | "popa",\r | |
532 | "popad",\r | |
533 | "popaw",\r | |
534 | "popf",\r | |
535 | "popfd",\r | |
536 | "popfw",\r | |
537 | "por",\r | |
538 | "prefetch",\r | |
539 | "prefetchnta",\r | |
540 | "prefetcht0",\r | |
541 | "prefetcht1",\r | |
542 | "prefetcht2",\r | |
543 | "prefetchw",\r | |
544 | "psadbw",\r | |
545 | "pshufd",\r | |
546 | "pshufhw",\r | |
547 | "pshuflw",\r | |
548 | "pshufw",\r | |
549 | "pslld",\r | |
550 | "pslldq",\r | |
551 | "psllq",\r | |
552 | "psllw",\r | |
553 | "psrad",\r | |
554 | "psraw",\r | |
555 | "psrld",\r | |
556 | "psrldq",\r | |
557 | "psrlq",\r | |
558 | "psrlw",\r | |
559 | "psubb",\r | |
560 | "psubd",\r | |
561 | "psubq",\r | |
562 | "psubsb",\r | |
563 | "psubsiw",\r | |
564 | "psubsw",\r | |
565 | "psubusb",\r | |
566 | "psubusw",\r | |
567 | "psubw",\r | |
568 | "pswapd",\r | |
569 | "punpckhbw",\r | |
570 | "punpckhdq",\r | |
571 | "punpckhqdq",\r | |
572 | "punpckhwd",\r | |
573 | "punpcklbw",\r | |
574 | "punpckldq",\r | |
575 | "punpcklqdq",\r | |
576 | "punpcklwd",\r | |
577 | "push",\r | |
578 | "pusha",\r | |
579 | "pushad",\r | |
580 | "pushaw",\r | |
581 | "pushf",\r | |
582 | "pushfd",\r | |
583 | "pushfw",\r | |
584 | "pxor",\r | |
585 | "rcl",\r | |
586 | "rcpps",\r | |
587 | "rcpss",\r | |
588 | "rcr",\r | |
589 | "rdmsr",\r | |
590 | "rdpmc",\r | |
591 | "rdshr",\r | |
592 | "rdtsc",\r | |
593 | "resb",\r | |
594 | "resd",\r | |
595 | "resq",\r | |
596 | "rest",\r | |
597 | "resw",\r | |
598 | "ret",\r | |
599 | "retf",\r | |
600 | "retn",\r | |
601 | "rol",\r | |
602 | "ror",\r | |
603 | "rsdc",\r | |
604 | "rsldt",\r | |
605 | "rsm",\r | |
606 | "rsqrtps",\r | |
607 | "rsqrtss",\r | |
608 | "rsts",\r | |
609 | "sahf",\r | |
610 | "sal",\r | |
611 | "salc",\r | |
612 | "sar",\r | |
613 | "sbb",\r | |
614 | "scasb",\r | |
615 | "scasd",\r | |
616 | "scasw",\r | |
617 | "sfence",\r | |
618 | "sgdt",\r | |
619 | "shl",\r | |
620 | "shld",\r | |
621 | "shr",\r | |
622 | "shrd",\r | |
623 | "shufpd",\r | |
624 | "shufps",\r | |
625 | "sidt",\r | |
626 | "sldt",\r | |
627 | "smi",\r | |
628 | "smint",\r | |
629 | "smintold",\r | |
630 | "smsw",\r | |
631 | "sqrtpd",\r | |
632 | "sqrtps",\r | |
633 | "sqrtsd",\r | |
634 | "sqrtss",\r | |
635 | "stc",\r | |
636 | "std",\r | |
637 | "sti",\r | |
638 | "stmxcsr",\r | |
639 | "stosb",\r | |
640 | "stosd",\r | |
641 | "stosw",\r | |
642 | "str",\r | |
643 | "sub",\r | |
644 | "subpd",\r | |
645 | "subps",\r | |
646 | "subsd",\r | |
647 | "subss",\r | |
648 | "svdc",\r | |
649 | "svldt",\r | |
650 | "svts",\r | |
651 | "syscall",\r | |
652 | "sysenter",\r | |
653 | "sysexit",\r | |
654 | "sysret",\r | |
655 | "test",\r | |
656 | "ucomisd",\r | |
657 | "ucomiss",\r | |
658 | "ud0",\r | |
659 | "ud1",\r | |
660 | "ud2",\r | |
661 | "umov",\r | |
662 | "unpckhpd",\r | |
663 | "unpckhps",\r | |
664 | "unpcklpd",\r | |
665 | "unpcklps",\r | |
666 | "verr",\r | |
667 | "verw",\r | |
668 | "wait",\r | |
669 | "wbinvd",\r | |
670 | "wrmsr",\r | |
671 | "wrshr",\r | |
672 | "xadd",\r | |
673 | "xbts",\r | |
674 | "xchg",\r | |
675 | "xlat",\r | |
676 | "xlatb",\r | |
677 | "xor",\r | |
678 | "xorpd",\r | |
679 | "xorps",\r | |
680 | "xstore"\r | |
681 | };\r | |
682 | \r | |
683 | /* Conditional instructions */\r | |
684 | static const char *icn[] = {\r | |
685 | "cmov",\r | |
686 | "j",\r | |
687 | "set"\r | |
688 | };\r | |
689 | \r | |
690 | /* and the corresponding opcodes */\r | |
691 | static int ico[] = {\r | |
692 | I_CMOVcc,\r | |
693 | I_Jcc,\r | |
694 | I_SETcc\r | |
695 | };\r | |
696 | \r | |
697 | #define INSN_MAX 32 /* one instruction can't be longer than this */\r | |
698 | long disasm (unsigned char *data, char *output, int segsize, long offset);\r | |
699 | extern struct itemplate **itable[];\r | |
700 | \r | |
701 | /*\r | |
702 | * Flags that go into the `segment' field of `insn' structures\r | |
703 | * during disassembly.\r | |
704 | */\r | |
705 | #define SEG_RELATIVE 1\r | |
706 | #define SEG_32BIT 2\r | |
707 | #define SEG_RMREG 4\r | |
708 | #define SEG_DISP8 8\r | |
709 | #define SEG_DISP16 16\r | |
710 | #define SEG_DISP32 32\r | |
711 | #define SEG_NODISP 64\r | |
712 | #define SEG_SIGNED 128\r | |
713 | \r | |
714 | static int whichreg(long regflags, int regval)\r | |
715 | {\r | |
716 | /* automatically generated from ./regs.dat - do not edit */\r | |
717 | static const int creg [] = {R_CR0,R_CR1,R_CR2,R_CR3,R_CR4,R_CR5,R_CR6,R_CR7};\r | |
718 | static const int dreg [] = {R_DR0,R_DR1,R_DR2,R_DR3,R_DR4,R_DR5,R_DR6,R_DR7};\r | |
719 | static const int fpureg [] = {R_ST0,R_ST1,R_ST2,R_ST3,R_ST4,R_ST5,R_ST6,R_ST7};\r | |
720 | static const int mmxreg [] = {R_MM0,R_MM1,R_MM2,R_MM3,R_MM4,R_MM5,R_MM6,R_MM7};\r | |
721 | static const int reg16 [] = {R_AX,R_CX,R_DX,R_BX,R_SP,R_BP,R_SI,R_DI};\r | |
722 | static const int reg32 [] = {R_EAX,R_ECX,R_EDX,R_EBX,R_ESP,R_EBP,R_ESI,R_EDI};\r | |
723 | static const int reg8 [] = {R_AL,R_CL,R_DL,R_BL,R_AH,R_CH,R_DH,R_BH};\r | |
724 | static const int sreg [] = {R_ES,R_CS,R_SS,R_DS,R_FS,R_GS,R_SEGR6,R_SEGR7};\r | |
725 | static const int treg [] = {R_TR0,R_TR1,R_TR2,R_TR3,R_TR4,R_TR5,R_TR6,R_TR7};\r | |
726 | static const int xmmreg [] = {R_XMM0,R_XMM1,R_XMM2,R_XMM3,R_XMM4,R_XMM5,R_XMM6,R_XMM7};\r | |
727 | \r | |
728 | if (!(REG_AL & ~regflags))\r | |
729 | return R_AL;\r | |
730 | if (!(REG_AX & ~regflags))\r | |
731 | return R_AX;\r | |
732 | if (!(REG_EAX & ~regflags))\r | |
733 | return R_EAX;\r | |
734 | if (!(REG_DL & ~regflags))\r | |
735 | return R_DL;\r | |
736 | if (!(REG_DX & ~regflags))\r | |
737 | return R_DX;\r | |
738 | if (!(REG_EDX & ~regflags))\r | |
739 | return R_EDX;\r | |
740 | if (!(REG_CL & ~regflags))\r | |
741 | return R_CL;\r | |
742 | if (!(REG_CX & ~regflags))\r | |
743 | return R_CX;\r | |
744 | if (!(REG_ECX & ~regflags))\r | |
745 | return R_ECX;\r | |
746 | if (!(FPU0 & ~regflags))\r | |
747 | return R_ST0;\r | |
748 | if (!(REG_CS & ~regflags))\r | |
749 | return (regval == 1) ? R_CS : 0;\r | |
750 | if (!(REG_DESS & ~regflags))\r | |
751 | return (regval == 0 || regval == 2 || regval == 3 ? sreg[regval] : 0);\r | |
752 | if (!(REG_FSGS & ~regflags))\r | |
753 | return (regval == 4 || regval == 5 ? sreg[regval] : 0);\r | |
754 | if (!(REG_SEG67 & ~regflags))\r | |
755 | return (regval == 6 || regval == 7 ? sreg[regval] : 0);\r | |
756 | \r | |
757 | /* All the entries below look up regval in an 8-entry array */\r | |
758 | if (regval < 0 || regval > 7)\r | |
759 | return 0;\r | |
760 | \r | |
761 | if (!((REGMEM|BITS8) & ~regflags))\r | |
762 | return reg8[regval];\r | |
763 | if (!((REGMEM|BITS16) & ~regflags))\r | |
764 | return reg16[regval];\r | |
765 | if (!((REGMEM|BITS32) & ~regflags))\r | |
766 | return reg32[regval];\r | |
767 | if (!(REG_SREG & ~regflags))\r | |
768 | return sreg[regval];\r | |
769 | if (!(REG_CREG & ~regflags))\r | |
770 | return creg[regval];\r | |
771 | if (!(REG_DREG & ~regflags))\r | |
772 | return dreg[regval];\r | |
773 | if (!(REG_TREG & ~regflags))\r | |
774 | return treg[regval];\r | |
775 | if (!(FPUREG & ~regflags))\r | |
776 | return fpureg[regval];\r | |
777 | if (!(MMXREG & ~regflags))\r | |
778 | return mmxreg[regval];\r | |
779 | if (!(XMMREG & ~regflags))\r | |
780 | return xmmreg[regval];\r | |
781 | \r | |
782 | return 0;\r | |
783 | }\r | |
784 | \r | |
785 | static const char *whichcond(int condval)\r | |
786 | {\r | |
787 | static int conds[] = {\r | |
788 | C_O, C_NO, C_C, C_NC, C_Z, C_NZ, C_NA, C_A,\r | |
789 | C_S, C_NS, C_PE, C_PO, C_L, C_NL, C_NG, C_G\r | |
790 | };\r | |
791 | return conditions[conds[condval]];\r | |
792 | }\r | |
793 | \r | |
794 | /*\r | |
795 | * Process an effective address (ModRM) specification.\r | |
796 | */\r | |
797 | static unsigned char *do_ea (unsigned char *data, int modrm, int asize,\r | |
798 | int segsize, operand *op)\r | |
799 | {\r | |
800 | int mod, rm, scale, index, base;\r | |
801 | \r | |
802 | mod = (modrm >> 6) & 03;\r | |
803 | rm = modrm & 07;\r | |
804 | \r | |
805 | if (mod == 3) { /* pure register version */\r | |
806 | op->basereg = rm;\r | |
807 | op->segment |= SEG_RMREG;\r | |
808 | return data;\r | |
809 | }\r | |
810 | \r | |
811 | op->addr_size = 0;\r | |
812 | \r | |
813 | if (asize == 16) {\r | |
814 | /*\r | |
815 | * <mod> specifies the displacement size (none, byte or\r | |
816 | * word), and <rm> specifies the register combination.\r | |
817 | * Exception: mod=0,rm=6 does not specify [BP] as one might\r | |
818 | * expect, but instead specifies [disp16].\r | |
819 | */\r | |
820 | op->indexreg = op->basereg = -1;\r | |
821 | op->scale = 1; /* always, in 16 bits */\r | |
822 | switch (rm) {\r | |
823 | case 0: op->basereg = R_BX; op->indexreg = R_SI; break;\r | |
824 | case 1: op->basereg = R_BX; op->indexreg = R_DI; break;\r | |
825 | case 2: op->basereg = R_BP; op->indexreg = R_SI; break;\r | |
826 | case 3: op->basereg = R_BP; op->indexreg = R_DI; break;\r | |
827 | case 4: op->basereg = R_SI; break;\r | |
828 | case 5: op->basereg = R_DI; break;\r | |
829 | case 6: op->basereg = R_BP; break;\r | |
830 | case 7: op->basereg = R_BX; break;\r | |
831 | }\r | |
832 | if (rm == 6 && mod == 0) { /* special case */\r | |
833 | op->basereg = -1;\r | |
834 | if (segsize != 16)\r | |
835 | op->addr_size = 16;\r | |
836 | mod = 2; /* fake disp16 */\r | |
837 | }\r | |
838 | switch (mod) {\r | |
839 | case 0:\r | |
840 | op->segment |= SEG_NODISP;\r | |
841 | break;\r | |
842 | case 1:\r | |
843 | op->segment |= SEG_DISP8;\r | |
844 | op->offset = (signed char) *data++;\r | |
845 | break;\r | |
846 | case 2:\r | |
847 | op->segment |= SEG_DISP16;\r | |
848 | op->offset = *data++;\r | |
849 | op->offset |= ((unsigned) *data++) << 8;\r | |
850 | break;\r | |
851 | }\r | |
852 | return data;\r | |
853 | } else {\r | |
854 | /*\r | |
855 | * Once again, <mod> specifies displacement size (this time\r | |
856 | * none, byte or *dword*), while <rm> specifies the base\r | |
857 | * register. Again, [EBP] is missing, replaced by a pure\r | |
858 | * disp32 (this time that's mod=0,rm=*5*). However, rm=4\r | |
859 | * indicates not a single base register, but instead the\r | |
860 | * presence of a SIB byte...\r | |
861 | */\r | |
862 | op->indexreg = -1;\r | |
863 | switch (rm) {\r | |
864 | case 0: op->basereg = R_EAX; break;\r | |
865 | case 1: op->basereg = R_ECX; break;\r | |
866 | case 2: op->basereg = R_EDX; break;\r | |
867 | case 3: op->basereg = R_EBX; break;\r | |
868 | case 5: op->basereg = R_EBP; break;\r | |
869 | case 6: op->basereg = R_ESI; break;\r | |
870 | case 7: op->basereg = R_EDI; break;\r | |
871 | }\r | |
872 | if (rm == 5 && mod == 0) {\r | |
873 | op->basereg = -1;\r | |
874 | if (segsize != 32)\r | |
875 | op->addr_size = 32;\r | |
876 | mod = 2; /* fake disp32 */\r | |
877 | }\r | |
878 | if (rm == 4) { /* process SIB */\r | |
879 | scale = (*data >> 6) & 03;\r | |
880 | index = (*data >> 3) & 07;\r | |
881 | base = *data & 07;\r | |
882 | data++;\r | |
883 | \r | |
884 | op->scale = 1 << scale;\r | |
885 | switch (index) {\r | |
886 | case 0: op->indexreg = R_EAX; break;\r | |
887 | case 1: op->indexreg = R_ECX; break;\r | |
888 | case 2: op->indexreg = R_EDX; break;\r | |
889 | case 3: op->indexreg = R_EBX; break;\r | |
890 | case 4: op->indexreg = -1; break;\r | |
891 | case 5: op->indexreg = R_EBP; break;\r | |
892 | case 6: op->indexreg = R_ESI; break;\r | |
893 | case 7: op->indexreg = R_EDI; break;\r | |
894 | }\r | |
895 | \r | |
896 | switch (base) {\r | |
897 | case 0: op->basereg = R_EAX; break;\r | |
898 | case 1: op->basereg = R_ECX; break;\r | |
899 | case 2: op->basereg = R_EDX; break;\r | |
900 | case 3: op->basereg = R_EBX; break;\r | |
901 | case 4: op->basereg = R_ESP; break;\r | |
902 | case 6: op->basereg = R_ESI; break;\r | |
903 | case 7: op->basereg = R_EDI; break;\r | |
904 | case 5:\r | |
905 | if (mod == 0) {\r | |
906 | mod = 2;\r | |
907 | op->basereg = -1;\r | |
908 | } else\r | |
909 | op->basereg = R_EBP;\r | |
910 | break;\r | |
911 | }\r | |
912 | }\r | |
913 | switch (mod) {\r | |
914 | case 0:\r | |
915 | op->segment |= SEG_NODISP;\r | |
916 | break;\r | |
917 | case 1:\r | |
918 | op->segment |= SEG_DISP8;\r | |
919 | op->offset = (signed char) *data++;\r | |
920 | break;\r | |
921 | case 2:\r | |
922 | op->segment |= SEG_DISP32;\r | |
923 | op->offset = *data++;\r | |
924 | op->offset |= ((unsigned) *data++) << 8;\r | |
925 | op->offset |= ((long) *data++) << 16;\r | |
926 | op->offset |= ((long) *data++) << 24;\r | |
927 | break;\r | |
928 | }\r | |
929 | return data;\r | |
930 | }\r | |
931 | }\r | |
932 | \r | |
933 | /*\r | |
934 | * Determine whether the instruction template in t corresponds to the data\r | |
935 | * stream in data. Return the number of bytes matched if so.\r | |
936 | */\r | |
937 | static int matches (struct itemplate *t, unsigned char *data, int asize,\r | |
938 | int osize, int segsize, int rep, insn *ins)\r | |
939 | {\r | |
940 | unsigned char * r = (unsigned char *)(t->code);\r | |
941 | unsigned char * origdata = data;\r | |
942 | int a_used = FALSE, o_used = FALSE;\r | |
943 | int drep = 0;\r | |
944 | \r | |
945 | if ( rep == 0xF2 )\r | |
946 | drep = P_REPNE;\r | |
947 | else if ( rep == 0xF3 )\r | |
948 | drep = P_REP;\r | |
949 | \r | |
950 | while (*r)\r | |
951 | {\r | |
952 | int c = *r++;\r | |
953 | if (c >= 01 && c <= 03) {\r | |
954 | while (c--)\r | |
955 | if (*r++ != *data++)\r | |
956 | return FALSE;\r | |
957 | }\r | |
958 | if (c == 04) {\r | |
959 | switch (*data++) {\r | |
960 | case 0x07: ins->oprs[0].basereg = 0; break;\r | |
961 | case 0x17: ins->oprs[0].basereg = 2; break;\r | |
962 | case 0x1F: ins->oprs[0].basereg = 3; break;\r | |
963 | default: return FALSE;\r | |
964 | }\r | |
965 | }\r | |
966 | if (c == 05) {\r | |
967 | switch (*data++) {\r | |
968 | case 0xA1: ins->oprs[0].basereg = 4; break;\r | |
969 | case 0xA9: ins->oprs[0].basereg = 5; break;\r | |
970 | default: return FALSE;\r | |
971 | }\r | |
972 | }\r | |
973 | if (c == 06) {\r | |
974 | switch (*data++) {\r | |
975 | case 0x06: ins->oprs[0].basereg = 0; break;\r | |
976 | case 0x0E: ins->oprs[0].basereg = 1; break;\r | |
977 | case 0x16: ins->oprs[0].basereg = 2; break;\r | |
978 | case 0x1E: ins->oprs[0].basereg = 3; break;\r | |
979 | default: return FALSE;\r | |
980 | }\r | |
981 | }\r | |
982 | if (c == 07) {\r | |
983 | switch (*data++) {\r | |
984 | case 0xA0: ins->oprs[0].basereg = 4; break;\r | |
985 | case 0xA8: ins->oprs[0].basereg = 5; break;\r | |
986 | default: return FALSE;\r | |
987 | }\r | |
988 | }\r | |
989 | if (c >= 010 && c <= 012) {\r | |
990 | int t = *r++, d = *data++;\r | |
991 | if (d < t || d > t+7)\r | |
992 | return FALSE;\r | |
993 | else {\r | |
994 | ins->oprs[c-010].basereg = d-t;\r | |
995 | ins->oprs[c-010].segment |= SEG_RMREG;\r | |
996 | }\r | |
997 | }\r | |
998 | if (c == 017)\r | |
999 | if (*data++)\r | |
1000 | return FALSE;\r | |
1001 | if (c >= 014 && c <= 016) {\r | |
1002 | ins->oprs[c-014].offset = (signed char) *data++;\r | |
1003 | ins->oprs[c-014].segment |= SEG_SIGNED;\r | |
1004 | }\r | |
1005 | if (c >= 020 && c <= 022)\r | |
1006 | ins->oprs[c-020].offset = *data++;\r | |
1007 | if (c >= 024 && c <= 026)\r | |
1008 | ins->oprs[c-024].offset = *data++;\r | |
1009 | if (c >= 030 && c <= 032) {\r | |
1010 | ins->oprs[c-030].offset = *data++;\r | |
1011 | ins->oprs[c-030].offset |= (((unsigned) *data++) << 8);\r | |
1012 | }\r | |
1013 | if (c >= 034 && c <= 036) {\r | |
1014 | ins->oprs[c-034].offset = *data++;\r | |
1015 | ins->oprs[c-034].offset |= (((unsigned) *data++) << 8);\r | |
1016 | if (osize == 32) {\r | |
1017 | ins->oprs[c-034].offset |= (((long) *data++) << 16);\r | |
1018 | ins->oprs[c-034].offset |= (((long) *data++) << 24);\r | |
1019 | }\r | |
1020 | if (segsize != asize)\r | |
1021 | ins->oprs[c-034].addr_size = asize;\r | |
1022 | }\r | |
1023 | if (c >= 040 && c <= 042) {\r | |
1024 | ins->oprs[c-040].offset = *data++;\r | |
1025 | ins->oprs[c-040].offset |= (((unsigned) *data++) << 8);\r | |
1026 | ins->oprs[c-040].offset |= (((long) *data++) << 16);\r | |
1027 | ins->oprs[c-040].offset |= (((long) *data++) << 24);\r | |
1028 | }\r | |
1029 | if (c >= 044 && c <= 046) {\r | |
1030 | ins->oprs[c-044].offset = *data++;\r | |
1031 | ins->oprs[c-044].offset |= (((unsigned) *data++) << 8);\r | |
1032 | if (asize == 32) {\r | |
1033 | ins->oprs[c-044].offset |= (((long) *data++) << 16);\r | |
1034 | ins->oprs[c-044].offset |= (((long) *data++) << 24);\r | |
1035 | }\r | |
1036 | if (segsize != asize)\r | |
1037 | ins->oprs[c-044].addr_size = asize;\r | |
1038 | }\r | |
1039 | if (c >= 050 && c <= 052) {\r | |
1040 | ins->oprs[c-050].offset = (signed char) *data++;\r | |
1041 | ins->oprs[c-050].segment |= SEG_RELATIVE;\r | |
1042 | }\r | |
1043 | if (c >= 060 && c <= 062) {\r | |
1044 | ins->oprs[c-060].offset = *data++;\r | |
1045 | ins->oprs[c-060].offset |= (((unsigned) *data++) << 8);\r | |
1046 | ins->oprs[c-060].segment |= SEG_RELATIVE;\r | |
1047 | ins->oprs[c-060].segment &= ~SEG_32BIT;\r | |
1048 | }\r | |
1049 | if (c >= 064 && c <= 066) {\r | |
1050 | ins->oprs[c-064].offset = *data++;\r | |
1051 | ins->oprs[c-064].offset |= (((unsigned) *data++) << 8);\r | |
1052 | if (osize == 32) {\r | |
1053 | ins->oprs[c-064].offset |= (((long) *data++) << 16);\r | |
1054 | ins->oprs[c-064].offset |= (((long) *data++) << 24);\r | |
1055 | ins->oprs[c-064].segment |= SEG_32BIT;\r | |
1056 | } else\r | |
1057 | ins->oprs[c-064].segment &= ~SEG_32BIT;\r | |
1058 | ins->oprs[c-064].segment |= SEG_RELATIVE;\r | |
1059 | if (segsize != osize) {\r | |
1060 | ins->oprs[c-064].type =\r | |
1061 | (ins->oprs[c-064].type & NON_SIZE)\r | |
1062 | | ((osize == 16) ? BITS16 : BITS32);\r | |
1063 | }\r | |
1064 | }\r | |
1065 | if (c >= 070 && c <= 072) {\r | |
1066 | ins->oprs[c-070].offset = *data++;\r | |
1067 | ins->oprs[c-070].offset |= (((unsigned) *data++) << 8);\r | |
1068 | ins->oprs[c-070].offset |= (((long) *data++) << 16);\r | |
1069 | ins->oprs[c-070].offset |= (((long) *data++) << 24);\r | |
1070 | ins->oprs[c-070].segment |= SEG_32BIT | SEG_RELATIVE;\r | |
1071 | }\r | |
1072 | if (c >= 0100 && c < 0130) {\r | |
1073 | int modrm = *data++;\r | |
1074 | ins->oprs[c & 07].basereg = (modrm >> 3) & 07;\r | |
1075 | ins->oprs[c & 07].segment |= SEG_RMREG;\r | |
1076 | data = do_ea (data, modrm, asize, segsize,\r | |
1077 | &ins->oprs[(c >> 3) & 07]);\r | |
1078 | }\r | |
1079 | if (c >= 0130 && c <= 0132) {\r | |
1080 | ins->oprs[c-0130].offset = *data++;\r | |
1081 | ins->oprs[c-0130].offset |= (((unsigned) *data++) << 8);\r | |
1082 | }\r | |
1083 | if (c >= 0140 && c <= 0142) {\r | |
1084 | ins->oprs[c-0140].offset = *data++;\r | |
1085 | ins->oprs[c-0140].offset |= (((unsigned) *data++) << 8);\r | |
1086 | ins->oprs[c-0140].offset |= (((long) *data++) << 16);\r | |
1087 | ins->oprs[c-0140].offset |= (((long) *data++) << 24);\r | |
1088 | }\r | |
1089 | if (c >= 0200 && c <= 0277) {\r | |
1090 | int modrm = *data++;\r | |
1091 | if (((modrm >> 3) & 07) != (c & 07))\r | |
1092 | return FALSE; /* spare field doesn't match up */\r | |
1093 | data = do_ea (data, modrm, asize, segsize,\r | |
1094 | &ins->oprs[(c >> 3) & 07]);\r | |
1095 | }\r | |
1096 | if (c >= 0300 && c <= 0302) {\r | |
1097 | if (asize)\r | |
1098 | ins->oprs[c-0300].segment |= SEG_32BIT;\r | |
1099 | else\r | |
1100 | ins->oprs[c-0300].segment &= ~SEG_32BIT;\r | |
1101 | a_used = TRUE;\r | |
1102 | }\r | |
1103 | if (c == 0310) {\r | |
1104 | if (asize == 32)\r | |
1105 | return FALSE;\r | |
1106 | else\r | |
1107 | a_used = TRUE;\r | |
1108 | }\r | |
1109 | if (c == 0311) {\r | |
1110 | if (asize == 16)\r | |
1111 | return FALSE;\r | |
1112 | else\r | |
1113 | a_used = TRUE;\r | |
1114 | }\r | |
1115 | if (c == 0312) {\r | |
1116 | if (asize != segsize)\r | |
1117 | return FALSE;\r | |
1118 | else\r | |
1119 | a_used = TRUE;\r | |
1120 | }\r | |
1121 | if (c == 0320) {\r | |
1122 | if (osize == 32)\r | |
1123 | return FALSE;\r | |
1124 | else\r | |
1125 | o_used = TRUE;\r | |
1126 | }\r | |
1127 | if (c == 0321) {\r | |
1128 | if (osize == 16)\r | |
1129 | return FALSE;\r | |
1130 | else\r | |
1131 | o_used = TRUE;\r | |
1132 | }\r | |
1133 | if (c == 0322) {\r | |
1134 | if (osize != segsize)\r | |
1135 | return FALSE;\r | |
1136 | else\r | |
1137 | o_used = TRUE;\r | |
1138 | }\r | |
1139 | if (c == 0330) {\r | |
1140 | int t = *r++, d = *data++;\r | |
1141 | if (d < t || d > t+15)\r | |
1142 | return FALSE;\r | |
1143 | else\r | |
1144 | ins->condition = d - t;\r | |
1145 | }\r | |
1146 | if (c == 0331) {\r | |
1147 | if ( rep )\r | |
1148 | return FALSE;\r | |
1149 | }\r | |
1150 | if (c == 0332) {\r | |
1151 | if (drep == P_REP)\r | |
1152 | drep = P_REPE;\r | |
1153 | }\r | |
1154 | if (c == 0333) {\r | |
1155 | if ( rep != 0xF3 )\r | |
1156 | return FALSE;\r | |
1157 | drep = 0;\r | |
1158 | }\r | |
1159 | }\r | |
1160 | \r | |
1161 | /*\r | |
1162 | * Check for unused rep or a/o prefixes.\r | |
1163 | */\r | |
1164 | ins->nprefix = 0;\r | |
1165 | if (drep)\r | |
1166 | ins->prefixes[ins->nprefix++] = drep;\r | |
1167 | if (!a_used && asize != segsize)\r | |
1168 | ins->prefixes[ins->nprefix++] = (asize == 16 ? P_A16 : P_A32);\r | |
1169 | if (!o_used && osize != segsize)\r | |
1170 | ins->prefixes[ins->nprefix++] = (osize == 16 ? P_O16 : P_O32);\r | |
1171 | \r | |
1172 | return data - origdata;\r | |
1173 | }\r | |
1174 | \r | |
1175 | long disasm (unsigned char *data, char *output, int segsize, long offset)\r | |
1176 | {\r | |
1177 | struct itemplate **p, **best_p;\r | |
1178 | int length, best_length = 0;\r | |
1179 | char *segover;\r | |
1180 | int rep, lock, asize, osize, i, slen, colon;\r | |
1181 | unsigned char *origdata;\r | |
1182 | int works;\r | |
1183 | insn tmp_ins, ins;\r | |
1184 | unsigned long goodness, best;\r | |
1185 | \r | |
1186 | /*\r | |
1187 | * Scan for prefixes.\r | |
1188 | */\r | |
1189 | asize = osize = segsize;\r | |
1190 | segover = NULL;\r | |
1191 | ins.condition = ins.nprefix = rep = lock = 0;\r | |
1192 | origdata = data;\r | |
1193 | for (;;) {\r | |
1194 | if (*data == 0xF3 || *data == 0xF2)\r | |
1195 | rep = *data++;\r | |
1196 | else if (*data == 0xF0)\r | |
1197 | lock = *data++;\r | |
1198 | else if (*data == 0x2E || *data == 0x36 || *data == 0x3E ||\r | |
1199 | *data == 0x26 || *data == 0x64 || *data == 0x65) {\r | |
1200 | switch (*data++) {\r | |
1201 | case 0x2E: segover = "cs"; break;\r | |
1202 | case 0x36: segover = "ss"; break;\r | |
1203 | case 0x3E: segover = "ds"; break;\r | |
1204 | case 0x26: segover = "es"; break;\r | |
1205 | case 0x64: segover = "fs"; break;\r | |
1206 | case 0x65: segover = "gs"; break;\r | |
1207 | }\r | |
1208 | } else if (*data == 0x66)\r | |
1209 | osize = 48 - segsize, data++;\r | |
1210 | else if (*data == 0x67)\r | |
1211 | asize = 48 - segsize, data++;\r | |
1212 | else\r | |
1213 | break;\r | |
1214 | }\r | |
1215 | \r | |
1216 | tmp_ins.oprs[0].segment = tmp_ins.oprs[1].segment =\r | |
1217 | tmp_ins.oprs[2].segment =\r | |
1218 | tmp_ins.oprs[0].addr_size = tmp_ins.oprs[1].addr_size =\r | |
1219 | tmp_ins.oprs[2].addr_size = (segsize == 16 ? 0 : SEG_32BIT);\r | |
1220 | tmp_ins.condition = -1;\r | |
1221 | best = ~0UL; /* Worst possible */\r | |
1222 | best_p = NULL;\r | |
1223 | for (p = itable[*data]; *p; p++) {\r | |
1224 | if ( (length = matches(*p, data, asize, osize,\r | |
1225 | segsize, rep, &tmp_ins)) ) {\r | |
1226 | works = TRUE;\r | |
1227 | /*\r | |
1228 | * Final check to make sure the types of r/m match up.\r | |
1229 | */\r | |
1230 | for (i = 0; i < (*p)->operands; i++) {\r | |
1231 | if (\r | |
1232 | /* If it's a mem-only EA but we have a register, die. */\r | |
1233 | ((tmp_ins.oprs[i].segment & SEG_RMREG) &&\r | |
1234 | !(MEMORY & ~(*p)->opd[i])) ||\r | |
1235 | \r | |
1236 | /* If it's a reg-only EA but we have a memory ref, die. */\r | |
1237 | (!(tmp_ins.oprs[i].segment & SEG_RMREG) &&\r | |
1238 | !(REGNORM & ~(*p)->opd[i]) &&\r | |
1239 | !((*p)->opd[i] & REG_SMASK)) ||\r | |
1240 | \r | |
1241 | /* Register type mismatch (eg FS vs REG_DESS): die. */\r | |
1242 | ((((*p)->opd[i] & (REGISTER | FPUREG)) ||\r | |
1243 | (tmp_ins.oprs[i].segment & SEG_RMREG)) &&\r | |
1244 | !whichreg ((*p)->opd[i], tmp_ins.oprs[i].basereg))) {\r | |
1245 | works = FALSE;\r | |
1246 | break;\r | |
1247 | }\r | |
1248 | }\r | |
1249 | \r | |
1250 | if (works) {\r | |
1251 | goodness = (*p)->flags & IF_PFMASK;\r | |
1252 | if ( goodness < best ) {\r | |
1253 | /* This is the best one found so far */\r | |
1254 | best = goodness;\r | |
1255 | best_p = p;\r | |
1256 | best_length = length;\r | |
1257 | ins = tmp_ins;\r | |
1258 | }\r | |
1259 | }\r | |
1260 | }\r | |
1261 | }\r | |
1262 | \r | |
1263 | if (!best_p)\r | |
1264 | return 0; /* no instruction was matched */\r | |
1265 | \r | |
1266 | /* Pick the best match */\r | |
1267 | p = best_p;\r | |
1268 | length = best_length;\r | |
1269 | \r | |
1270 | slen = 0;\r | |
1271 | \r | |
1272 | if (lock)\r | |
1273 | slen += sprintf(output+slen, "lock ");\r | |
1274 | for (i = 0; i < ins.nprefix; i++)\r | |
1275 | switch (ins.prefixes[i]) {\r | |
1276 | case P_REP: slen += sprintf(output+slen, "rep "); break;\r | |
1277 | case P_REPE: slen += sprintf(output+slen, "repe "); break;\r | |
1278 | case P_REPNE: slen += sprintf(output+slen, "repne "); break;\r | |
1279 | case P_A16: slen += sprintf(output+slen, "a16 "); break;\r | |
1280 | case P_A32: slen += sprintf(output+slen, "a32 "); break;\r | |
1281 | case P_O16: slen += sprintf(output+slen, "o16 "); break;\r | |
1282 | case P_O32: slen += sprintf(output+slen, "o32 "); break;\r | |
1283 | }\r | |
1284 | \r | |
1285 | for (i = 0; i < elements(ico); i++)\r | |
1286 | if ((*p)->opcode == ico[i]) {\r | |
1287 | slen += sprintf(output+slen, "%s%s", icn[i],\r | |
1288 | whichcond(ins.condition));\r | |
1289 | break;\r | |
1290 | }\r | |
1291 | if (i >= elements(ico))\r | |
1292 | slen += sprintf(output+slen, "%s", insn_names[(*p)->opcode]);\r | |
1293 | colon = FALSE;\r | |
1294 | length += data - origdata; /* fix up for prefixes */\r | |
1295 | for (i=0; i<(*p)->operands; i++) {\r | |
1296 | output[slen++] = (colon ? ':' : i==0 ? ' ' : ',');\r | |
1297 | \r | |
1298 | if (ins.oprs[i].segment & SEG_RELATIVE) {\r | |
1299 | ins.oprs[i].offset += offset + length;\r | |
1300 | /*\r | |
1301 | * sort out wraparound\r | |
1302 | */\r | |
1303 | if (!(ins.oprs[i].segment & SEG_32BIT))\r | |
1304 | ins.oprs[i].offset &= 0xFFFF;\r | |
1305 | }\r | |
1306 | \r | |
1307 | if ((*p)->opd[i] & COLON)\r | |
1308 | colon = TRUE;\r | |
1309 | else\r | |
1310 | colon = FALSE;\r | |
1311 | \r | |
1312 | if (((*p)->opd[i] & (REGISTER | FPUREG)) ||\r | |
1313 | (ins.oprs[i].segment & SEG_RMREG))\r | |
1314 | {\r | |
1315 | ins.oprs[i].basereg = whichreg ((*p)->opd[i],\r | |
1316 | ins.oprs[i].basereg);\r | |
1317 | if ( (*p)->opd[i] & TO )\r | |
1318 | slen += sprintf(output+slen, "to ");\r | |
1319 | slen += sprintf(output+slen, "%s",\r | |
1320 | reg_names[ins.oprs[i].basereg-EXPR_REG_START]);\r | |
1321 | } else if (!(UNITY & ~(*p)->opd[i])) {\r | |
1322 | output[slen++] = '1';\r | |
1323 | } else if ( (*p)->opd[i] & IMMEDIATE ) {\r | |
1324 | if ( (*p)->opd[i] & BITS8 ) {\r | |
1325 | slen += sprintf(output+slen, "byte ");\r | |
1326 | if (ins.oprs[i].segment & SEG_SIGNED) {\r | |
1327 | if (ins.oprs[i].offset < 0) {\r | |
1328 | ins.oprs[i].offset *= -1;\r | |
1329 | output[slen++] = '-';\r | |
1330 | } else\r | |
1331 | output[slen++] = '+';\r | |
1332 | }\r | |
1333 | } else if ( (*p)->opd[i] & BITS16 ) {\r | |
1334 | slen += sprintf(output+slen, "word ");\r | |
1335 | } else if ( (*p)->opd[i] & BITS32 ) {\r | |
1336 | slen += sprintf(output+slen, "dword ");\r | |
1337 | } else if ( (*p)->opd[i] & NEAR ) {\r | |
1338 | slen += sprintf(output+slen, "near ");\r | |
1339 | } else if ( (*p)->opd[i] & SHORT ) {\r | |
1340 | slen += sprintf(output+slen, "short ");\r | |
1341 | }\r | |
1342 | slen += sprintf(output+slen, "0x%lx", ins.oprs[i].offset);\r | |
1343 | } else if ( !(MEM_OFFS & ~(*p)->opd[i]) ) {\r | |
1344 | slen += sprintf(output+slen, "[%s%s%s0x%lx]",\r | |
1345 | (segover ? segover : ""),\r | |
1346 | (segover ? ":" : ""),\r | |
1347 | (ins.oprs[i].addr_size == 32 ? "dword " :\r | |
1348 | ins.oprs[i].addr_size == 16 ? "word " : ""),\r | |
1349 | ins.oprs[i].offset);\r | |
1350 | segover = NULL;\r | |
1351 | } else if ( !(REGMEM & ~(*p)->opd[i]) ) {\r | |
1352 | int started = FALSE;\r | |
1353 | if ( (*p)->opd[i] & BITS8 )\r | |
1354 | slen += sprintf(output+slen, "byte ");\r | |
1355 | if ( (*p)->opd[i] & BITS16 )\r | |
1356 | slen += sprintf(output+slen, "word ");\r | |
1357 | if ( (*p)->opd[i] & BITS32 )\r | |
1358 | slen += sprintf(output+slen, "dword ");\r | |
1359 | if ( (*p)->opd[i] & BITS64 )\r | |
1360 | slen += sprintf(output+slen, "qword ");\r | |
1361 | if ( (*p)->opd[i] & BITS80 )\r | |
1362 | slen += sprintf(output+slen, "tword ");\r | |
1363 | if ( (*p)->opd[i] & FAR )\r | |
1364 | slen += sprintf(output+slen, "far ");\r | |
1365 | if ( (*p)->opd[i] & NEAR )\r | |
1366 | slen += sprintf(output+slen, "near ");\r | |
1367 | output[slen++] = '[';\r | |
1368 | if (ins.oprs[i].addr_size)\r | |
1369 | slen += sprintf(output+slen, "%s",\r | |
1370 | (ins.oprs[i].addr_size == 32 ? "dword " :\r | |
1371 | ins.oprs[i].addr_size == 16 ? "word " : ""));\r | |
1372 | if (segover) {\r | |
1373 | slen += sprintf(output+slen, "%s:", segover);\r | |
1374 | segover = NULL;\r | |
1375 | }\r | |
1376 | if (ins.oprs[i].basereg != -1) {\r | |
1377 | slen += sprintf(output+slen, "%s",\r | |
1378 | reg_names[(ins.oprs[i].basereg -\r | |
1379 | EXPR_REG_START)]);\r | |
1380 | started = TRUE;\r | |
1381 | }\r | |
1382 | if (ins.oprs[i].indexreg != -1) {\r | |
1383 | if (started)\r | |
1384 | output[slen++] = '+';\r | |
1385 | slen += sprintf(output+slen, "%s",\r | |
1386 | reg_names[(ins.oprs[i].indexreg -\r | |
1387 | EXPR_REG_START)]);\r | |
1388 | if (ins.oprs[i].scale > 1)\r | |
1389 | slen += sprintf(output+slen, "*%d", ins.oprs[i].scale);\r | |
1390 | started = TRUE;\r | |
1391 | }\r | |
1392 | if (ins.oprs[i].segment & SEG_DISP8) {\r | |
1393 | int sign = '+';\r | |
1394 | if (ins.oprs[i].offset & 0x80) {\r | |
1395 | ins.oprs[i].offset = - (signed char) ins.oprs[i].offset;\r | |
1396 | sign = '-';\r | |
1397 | }\r | |
1398 | slen += sprintf(output+slen, "%c0x%lx", sign,\r | |
1399 | ins.oprs[i].offset);\r | |
1400 | } else if (ins.oprs[i].segment & SEG_DISP16) {\r | |
1401 | if (started)\r | |
1402 | output[slen++] = '+';\r | |
1403 | slen += sprintf(output+slen, "0x%lx", ins.oprs[i].offset);\r | |
1404 | } else if (ins.oprs[i].segment & SEG_DISP32) {\r | |
1405 | if (started)\r | |
1406 | output[slen++] = '+';\r | |
1407 | slen += sprintf(output+slen, "0x%lx", ins.oprs[i].offset);\r | |
1408 | }\r | |
1409 | output[slen++] = ']';\r | |
1410 | } else {\r | |
1411 | slen += sprintf(output+slen, "<operand%d>", i);\r | |
1412 | }\r | |
1413 | }\r | |
1414 | output[slen] = '\0';\r | |
1415 | if (segover) { /* unused segment override */\r | |
1416 | char *p = output;\r | |
1417 | int count = slen+1;\r | |
1418 | while (count--)\r | |
1419 | p[count+3] = p[count];\r | |
1420 | strncpy (output, segover, 2);\r | |
1421 | output[2] = ' ';\r | |
1422 | }\r | |
1423 | return length;\r | |
1424 | }\r |