2 * mdbdis86.c for mdb.c - 8086-386 and 8087 disassembler
19 static struct address_s uptr
;
21 static u8_t
get8(void);
22 static u16_t
get16(void);
23 static u32_t
get32(void);
24 static u8_t
peek_byte(off_t addr
);
25 static u16_t
peek_word(off_t addr
);
26 static int puti(void);
27 static int outsegaddr(struct address_s
*addr
);
28 static int outssegaddr(struct address_s
*addr
);
29 static int show1instruction(void);
31 /************************* UNASM ******************************/
37 #define BASE_MASK 0x07
38 #define INDEX_MASK 0x38
40 #define MOD_MASK 0xC0 /* mod reg r/m is mmrrrRRR */
52 #define SIGNBIT 0x02 /* opcode bits xxxxxxsw for immediates */
54 #define TOREGBIT 0x02 /* opcode bit for non-immediates */
56 #define MAX_SIGNED_CHAR 0x7F /* will assume 2's complement */
57 #define MAX_UNSIGNED_CHAR 0xFF
59 typedef unsigned opcode_pt
; /* promote to unsigned and not int */
65 static su8_pt
get8s(void);
66 static void getmodregrm(void);
67 static void i_00_to_3f(opcode_pt opc
);
68 static void i_40_to_5f(opcode_pt opc
);
69 static void i_60_to_6f(opcode_pt opc
);
70 static void i_70_to_7f(opcode_pt opc
);
71 static void i_80(opcode_pt opc
);
72 static void i_88(opcode_pt opc
);
73 static void i_90(opcode_pt opc
);
74 static void i_98(opcode_pt opc
);
75 static void i_a0(opcode_pt opc
);
76 static void i_a8(opcode_pt opc
);
77 static void i_b0(opcode_pt opc
);
78 static void i_b8(opcode_pt opc
);
79 static void i_c0(opcode_pt opc
);
80 static void i_c8(opcode_pt opc
);
81 static void i_d0(opcode_pt opc
);
82 static void i_d8(opcode_pt opc
);
83 static void i_e0(opcode_pt opc
);
84 static void i_e8(opcode_pt opc
);
85 static void i_f0(opcode_pt opc
);
86 static void i_f8(opcode_pt opc
);
87 static void outad(opcode_pt opc
);
88 static void outad1(opcode_pt opc
);
89 static void outalorx(opcode_pt opc
);
90 static void outax(void);
91 static void outbptr(void);
92 static void outbwptr(opcode_pt opc
);
93 static void outea(opcode_pt wordflags
);
94 static void outf1(void);
95 static void out32offset(void);
96 static void outfishy(void);
97 static void outgetaddr(void);
98 static void outimmed(opcode_pt signwordflag
);
99 static void outpc(off_t pc
);
100 static void outsegpc(void);
101 static void oututstr(char *s
);
102 static void outword(void);
103 static void outwptr(void);
104 static void outwsize(void);
105 static void pagef(void);
106 static void shift(opcode_pt opc
);
107 static void checkmemory(void);
108 static void CL(void);
109 static void Eb(void);
110 static void Ev(void);
111 static void EvGv(void);
112 static void EvIb(void);
113 static void Ew(void);
114 static void EwRw(void);
115 static void Gv(void);
116 static void Gv1(void);
117 static void GvEv(void);
118 static void GvEw(void);
119 static void GvM(void);
120 static void GvMa(void);
121 static void GvMp(void);
122 static void Ib(void);
123 static void Iw(void);
124 static void Iv(void);
125 static void Jb(void);
126 static void Jv(void);
127 static void Ms(void);
129 typedef void(*pfv_t
) (opcode_pt opc
);
131 static pfv_t optable
[] =
167 static char fishy
[] = "???";
168 static char movtab
[] = "mov\t";
170 static char *genreg
[] =
172 "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh",
173 "ax", "cx", "dx", "bx", "sp", "bp", "si", "di",
174 "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi",
177 static char *segreg
[] =
179 "es", "cs", "ss", "ds", "fs", "gs", "?s", "?s",
182 static char *indreg
[] =
184 "bx+si", "bx+di", "bp+si", "bp+di", "si", "di", "bp", "bx",
187 static char *str_00_to_3f
[] =
189 /* index by (opcode >> 3) & 7 */
190 "add", "or", "adc", "sbb", "and", "sub", "xor", "cmp",
193 static char *sstr_00_to_3f
[] =
195 /* index ((opc>>2) & 0x0E) + (opc & 7) - 6 */
196 "push\tes", "pop\tes", "push\tcs", "pop\tcs",
197 "push\tss", "pop\tss", "push\tds", "pop\tds",
198 "es:", "daa", "cs:", "das", "ss:", "aaa", "ds:", "aas",
201 static char *sstr_0f
[] =
203 "push\tfs", "pop\tfs", fishy
, "bt\t", "shld\t", "shld\t", fishy
, fishy
,
204 "push\tgs", "pop\tgs", fishy
, "bts\t", "shrd\t", "shrd\t", fishy
, "imul\t",
205 fishy
, fishy
, "lss\t", "btr\t", "lfs\t", "lgs\t", "movzx\t", "movzx\t",
206 fishy
, fishy
, "", "btc\t", "bsf\t", "bsr\t", "movsx\t", "movsx\t",
209 static char *ssstr_0f
[] =
211 "sldt\t", "str\t", "lldt\t", "ltr\t", "verr\t", "verw\t", fishy
, fishy
,
212 "sgdt\t", "sidt\t", "lgdt\t", "lidt\t", "smsw\t", fishy
, "lmsw\t", fishy
,
213 fishy
, fishy
, fishy
, fishy
, "bt\t", "bts\t", "btr\t", "btc\t",
216 static char *str_40_to_5f
[] =
218 /* index by (opcode >> 3) & 3 */
219 "inc\t", "dec\t", "push\t", "pop\t",
222 static char *str_60_to_6f
[] =
224 "pusha", "popa", "bound\t", "arpl\t", "fs:", "gs:", "os:", "as:",
225 "push\t", "imul\t", "push\t", "imul\t", "insb", "ins", "outsb", "outs",
228 static char *str_flags
[] =
230 /* opcodes 0x70 to 0x7F, and 0x0F80 to 0x0F9F */
231 "o", "no", "b", "nb", "z", "nz", "be", "a",
232 "s", "ns", "pe", "po", "l", "ge", "le", "g",
235 static char *str_98
[] =
237 "cbw", "cwd", "call\t", "wait", "pushf", "popf", "sahf", "lahf",
238 "cwde", "cdq", "call\t", "wait", "pushfd", "popfd", "sahf", "lahf",
241 static char *str_a0
[] =
243 movtab
, movtab
, movtab
, movtab
, "movsb", "movs", "cmpsb", "cmps",
246 static char *str_a8
[] =
248 "test\t", "test\t", "stosb", "stos", "lodsb", "lods", "scasb", "scas",
251 static char *str_c0
[] =
253 "", "", "ret\t", "ret", "les\t", "lds\t", movtab
, movtab
,
256 static char *str_c8
[] =
258 "enter\t", "leave", "retf\t", "retf", "int\t3", "int\t", "into", "iret",
261 static char *str_d0
[] =
263 "aam", "aad", "db\td6", "xlat",
266 static char *sstr_d0
[] =
268 "rol", "ror", "rcl", "rcr", "shl", "shr", fishy
, "sar",
271 static char *str_d8
[] =
273 "fadd", "fmul", "fcom", "fcomp", "fsub", "fsubr", "fdiv", "fdivr",
274 "fld", NULL
, "fst", "fstp", "fldenv", "fldcw", "fstenv", "fstcw",
275 "fiadd", "fimul", "ficom", "ficomp", "fisub", "fisubr", "fidiv", "fidivr",
276 "fild", NULL
, "fist", "fistp", NULL
, "fld", NULL
, "fstp",
277 "fadd", "fmul", "fcom", "fcomp", "fsub", "fsubr", "fdiv", "fdivr",
278 "fld", NULL
, "fst", "fstp", "frstor", NULL
, "fsave", "fstsw",
279 "fiadd", "fimul", "ficom", "ficomp", "fisub", "fisubr", "fidiv", "fidivr",
280 "fild", NULL
, "fist", "fistp", "fbld", "fild", "fbstp", "fistp",
283 static char *str1_d8
[] =
285 "fadd", "fmul", "fcom", "fcomp", "fsub", "fsubr", "fdiv", "fdivr",
286 "fld", "fxch", "\0\0", NULL
, "\0\10", "\0\20", "\0\30", "\0\40",
287 NULL
, NULL
, NULL
, NULL
, NULL
, "\0\50", NULL
, NULL
,
288 NULL
, NULL
, NULL
, NULL
, "\0\60", NULL
, NULL
, NULL
,
289 "fadd", "fmul", NULL
, NULL
, "fsubr", "fsub", "fdivr", "fdiv",
290 "ffree", NULL
, "fst", "fstp", "fucom", "fucomp", NULL
, NULL
,
291 "faddp", "fmulp", NULL
, "\0\70", "fsubrp", "fsubp", "fdivrp", "fdivp",
292 NULL
, NULL
, NULL
, NULL
, "\0\100", NULL
, NULL
, NULL
,
295 static unsigned char size_d8
[] =
297 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 4, 4, 14-28, 2, 14-28, 2,
298 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 4, 4, 0, 10, 0, 10,
299 8, 8, 8, 8, 8, 8, 8, 8, 8, 0, 8, 8, 94-108, 0, 94-108, 2,
300 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 10, 8, 10, 8,
303 static char *sstr_d8
[] =
305 "fnop", NULL
, NULL
, NULL
, /* D9D0 */
306 NULL
, NULL
, NULL
, NULL
,
307 "fchs", "fabs", NULL
, NULL
, /* D9E0 */
308 "ftst", "fxam", NULL
, NULL
,
309 "fld1", "fldl2t", "fldl2e", "fldpi", /* D9E8 */
310 "fldlg2", "fldln2", "fldz", NULL
,
311 "f2xm1", "fyl2x", "fptan", "fpatan", /* D9F0 */
312 "fxtract", "fprem1", "fdecstp", "fincstp",
313 "fprem", "fyl2xp1", "fsqrt", "fsincos", /* D9F8 */
314 "frndint", "fscale", "fsin", "fcos",
315 NULL
, "fucompp", NULL
, NULL
, /* DAE8 */
316 NULL
, NULL
, NULL
, NULL
,
317 "feni", "fdisi", "fclex", "finit", /* DBE0 */
318 "fsetpm", NULL
, NULL
, NULL
,
319 NULL
, "fcompp", NULL
, NULL
, /* DED8 */
320 NULL
, NULL
, NULL
, NULL
,
321 NULL
, NULL
, NULL
, NULL
, /* DFE0 */
322 "fstsw\tax", NULL
, NULL
, NULL
,
325 static char *str_e0
[] =
327 "loopnz\t", "loopz\t", "loop\t", "jcxz\t",
328 "in\t", "in\t", "out\t", "out\t",
331 static char *str_e8
[] =
333 "call\t", "jmp\t", "jmp\t", "jmp\t",
334 "in\t", "in\t", "out\t", "out\t",
337 static char *str_f0
[] =
339 "lock\t", "db\tf1", "repnz\t", "repz\t",
341 /* other 2 from sstr_f0 */
344 static char *sstr_f0
[] =
346 "test\t", fishy
, "not\t", "neg\t",
347 "mul\t", "imul\t", "div\t", "idiv\t",
350 static char *str_f8
[] =
352 "clc", "stc", "cli", "sti",
354 /* other 2 from sstr_f8 */
357 static char *sstr_f8
[] =
359 "inc\t", "dec\t", "call\t", "call\tfar ",
360 "jmp\t", "jmp\tfar ", "push\t", "???\t",
363 static int data_seg
; /* data segment (munged name for asld) */
364 static unsigned hasize
; /* half address size in bits */
365 static unsigned hdefsize
;
366 static unsigned hosize
; /* half operand size in bits */
367 /* for easy index into reg tables */
368 static opcode_pt mod
;
369 static off_t offtable
[2];
370 static off_t
*offptr
;
371 static off_t
*off1ptr
;
372 static opcode_pt reg
;
375 static su8_pt
get8s()
379 if ((got
= get8()) > MAX_SIGNED_CHAR
)
380 got
-= (MAX_UNSIGNED_CHAR
+ 1);
384 static void getmodregrm()
389 mod
= modregrm
& MOD_MASK
;
390 reg
= (modregrm
& REG_MASK
) >> REG_SHIFT
;
391 rm
= (modregrm
& RM_MASK
) >> RM_SHIFT
;
394 static void i_00_to_3f(opc
)
401 else if ((sub
= opc
& 7) >= 6)
403 outustr((sstr_00_to_3f
- 6)[((opc
>> 2) & 0x0E) + sub
]);
409 oututstr(str_00_to_3f
[(opc
>> 3) & 7]);
427 static void i_40_to_5f(opc
)
430 outustr(str_40_to_5f
[(opc
>> 3) & 3]);
431 outustr(genreg
[hosize
+ (opc
& 7)]);
434 static void i_60_to_6f(opc
)
437 /* most for 386, some for 286 */
439 outustr((str_60_to_6f
- 0x60)[opc
]);
458 hosize
= (16 + 8) - hdefsize
;
461 hasize
= (16 + 8) - hdefsize
;
469 outimmed(SIGNBIT
| WORDBIT
);
479 outimmed(SIGNBIT
| WORDBIT
);
488 static void i_70_to_7f(opc
)
492 oututstr((str_flags
- 0x70)[opc
]);
496 static void i_80(opc
)
501 outustr(opc
>= 6 ? "xchg\t" : "test\t");
507 oututstr(str_00_to_3f
[reg
]);
512 #ifdef SIGNED_LOGICALS
513 if (opc
& SIGNBIT
&& (reg
== 1 || reg
== 4 || reg
== 6))
514 /* and, or and xor with signe extension are not documented in some
515 * 8086 and 80286 manuals, but make sense and work
522 static void i_88(opc
)
548 if (!(opc
& TOREGBIT
))
553 outustr(segreg
[reg
]);
562 static void i_90(opc
)
572 outustr(genreg
[hosize
+ opc
]);
576 static void i_98(opc
)
579 outustr((str_98
- 8)[opc
+ hosize
]);
584 static void i_a0(opc
)
587 outustr(str_a0
[opc
]);
590 mod
= MEM0_MOD
; /* fake */
591 reg
= 0; /* fake ax */
593 rm
= 5; /* fake [d16] */
595 rm
= 6; /* fake [d32] */
596 outad1(opc
^ TOREGBIT
);
602 static void i_a8(opc
)
605 outustr(str_a8
[opc
]);
616 static void i_b0(opc
)
620 outustr(genreg
[opc
]);
625 static void i_b8(opc
)
629 outustr(genreg
[hosize
+ opc
]);
634 static void i_c0(opc
)
637 outustr(str_c0
[opc
]);
644 outimmed(opc
& WORDBIT
);
646 /* not completely decoded (like DEBUG) */
657 static void i_c8(opc
)
660 outustr(str_c8
[opc
]);
671 else if (opc
== 7 && hosize
== 16)
675 static void i_d0(opc
)
684 outustr((str_d0
- 4)[opc
]);
685 if (opc
< 6 && (aabyte
= get8()) != 0x0A)
694 static void i_d8(opc
)
701 esc
= (opc
<< 3) | reg
;
702 if ((str
= (mod
== REG_MOD
? str1_d8
: str_d8
)[esc
]) == NULL
)
713 str
= sstr_d8
[str
[1] + rm
];
723 if (opc
== 0 && reg
!= 2 && reg
!= 3)
726 if (opc
== 4 || opc
== 6)
749 static void i_e0(opc
)
752 outustr(str_e0
[opc
]);
769 static void i_e8(opc
)
772 outustr(str_e8
[opc
]);
796 static void i_f0(opc
)
800 outustr(str_f0
[opc
]);
804 outustr(sstr_f0
[reg
]);
810 outimmed(opc
& WORDBIT
);
815 static void i_f8(opc
)
819 outustr(str_f8
[opc
]);
823 if (opc
== 6 && reg
>= 2)
826 outustr(sstr_f8
[reg
]);
832 static void outad(opc
)
839 static void outad1(opc
)
842 if (!(opc
& TOREGBIT
))
850 outustr(genreg
[reg
]);
858 static void outalorx(opc
)
869 outustr(genreg
[hosize
]);
872 static void outbptr()
874 outustr("byte ptr ");
877 static void outbwptr(opc
)
889 static void outea(wordflags
)
895 opcode_pt ssindexbase
;
898 outustr(genreg
[hosize
* (wordflags
& WORDBIT
) + rm
]);
906 base
= (ssindexbase
= get8()) & BASE_MASK
;
907 if (mod
== MEM0_MOD
&& base
== 5)
910 outustr((genreg
+ 16)[base
]);
911 ss
= (ssindexbase
& SS_MASK
) >> SS_SHIFT
;
912 if ((index
= (ssindexbase
& INDEX_MASK
) >> INDEX_SHIFT
) != 4)
915 outustr((genreg
+ 16)[index
]);
916 outstr("\0\0\0*2\0*4\0*8\0" + (3 * ss
));
919 else if (mod
== MEM0_MOD
&& rm
== 5)
922 outustr((genreg
+ 16)[rm
]);
924 else if (mod
== MEM0_MOD
&& rm
== 6)
929 /* fake sign extension to get +- */
930 outimmed(SIGNBIT
| WORDBIT
);
931 else if (mod
== MEM2_MOD
)
937 if (hasize
== 16 && rm
== 4 && index
== 4 && ss
!= 0)
945 outbyte((int) (rm
+ '0'));
949 static void out32offset()
961 static void outfishy()
966 static void outgetaddr()
975 if ( finds_data(off
,data_seg
) )
977 else if (hasize
== 16)
983 static void outimmed(signwordflag
)
984 opcode_pt signwordflag
;
988 if (signwordflag
& WORDBIT
)
990 if (signwordflag
& SIGNBIT
)
992 if ((byte
= get8s()) < 0)
1008 static void outpc(pc
)
1016 else if (hosize
== 16)
1022 static void outsegpc()
1031 oldbase
= uptr
.base
;
1032 outh16((u16_t
) (uptr
.base
= get16())); /* fake seg for lookup of pc */
1033 /* TODO - convert to offset in protected mode */
1036 uptr
.base
= oldbase
;
1039 static void oututstr(s
)
1046 static void outword()
1048 outustr("dword " + ((16 - hosize
) >> 3));
1051 static void outwptr()
1057 static void outwsize()
1070 if ((opc
= get8()) <= 1 || opc
== 0xBA)
1077 outustr(ssstr_0f
[opc
+= reg
]);
1078 if (opc
< 6 || opc
== 12 || opc
== 14)
1080 else if (opc
>= 8 && opc
< 13)
1090 oututstr("lar\0lsl" + 4 * (opc
- 2));
1100 else if (opc
< 0x20)
1102 else if (opc
< 0x27 && opc
!= 0x25)
1107 if (!(opc
& TOREGBIT
))
1109 Ev(); /* Rd() since hosize is 16 */
1116 if (reg
== 4 || reg
== 5)
1119 else if (opc
< 0x24)
1122 if (reg
>= 4 || reg
== 1)
1131 outbyte((int) (reg
+ '0'));
1137 if (regbad
|| mod
!= REG_MOD
)
1140 else if (opc
< 0x80)
1142 else if (opc
< 0x90)
1145 oututstr((str_flags
- 0x80)[opc
]);
1148 else if (opc
< 0xA0)
1151 oututstr((str_flags
- 0x90)[opc
]);
1156 else if (opc
< 0xC0)
1158 outustr((sstr_0f
- 0xA0)[opc
]);
1200 hosize
= 8; /* done in Ew(), but too late */
1212 static int hadprefix
;
1227 (*optable
[opcode
>> 3])(opcode
< 0x80 ? opcode
: opcode
& 7);
1228 if (offptr
> offtable
)
1230 if (stringtab() >= 31)
1236 while (stringtab() < 32)
1239 for (off1ptr
= offtable
; off1ptr
< offptr
; ++off1ptr
)
1242 if (*off1ptr
< 0x10000)
1243 outh16((u16_t
) *off1ptr
);
1249 if ((opcode
& 0xE7) == 0x26 ||
1250 opcode
>= 0x64 && opcode
< 0x68 ||
1251 opcode
== 0xF0 || opcode
== 0xF2 || opcode
== 0xF3)
1252 /* not finished instruction for 0x26, 0x2E, 0x36, 0x3E seg overrides
1253 * and 0x64, 0x65 386 seg overrides
1254 * and 0x66, 0x67 386 size prefixes
1255 * and 0xF0 lock, 0xF2 repne, 0xF3 rep
1259 goto more
; /* TODO - print prefixes better */
1266 static void shift(opc
)
1270 oututstr(sstr_d0
[reg
]);
1282 static void checkmemory()
1338 outustr(genreg
[hosize
+ reg
]);
1394 outpc(pcjump
+ uptr
.off
);
1404 pcjump
= (su16_t
) get16();
1405 outpc(pcjump
+ uptr
.off
);
1414 /********************* DASM ******************************/
1416 long dasm( addr
, count
, symflg
)
1421 bits32
= TRUE
; /* Set mode */
1423 uptr
.base
= 0; /* not known */
1424 while ( count
-- != 0 && show1instruction() )
1429 static int show1instruction()
1431 register int column
;
1433 static char line
[81];
1435 struct address_s newuptr
;
1436 struct address_s olduptr
;
1441 if ( text_symbol(uptr
.off
) ) {
1448 line
[stringpos()] = 0;
1452 column
= outssegaddr(&uptr
);
1453 while (uptr
.off
!= newuptr
.off
)
1458 maxcol
= bits32
? 24 : 16;
1459 while (column
< maxcol
)
1468 while (!idone
); /* eat all prefixes */
1475 /* get 8 bits current instruction pointer and advance pointer */
1479 temp
= peek_byte(uptr
.off
+ uptr
.base
);
1484 static u16_t
get16()
1486 /* get 16 bits from current instruction pointer and advance pointer */
1490 temp
= peek_word(uptr
.off
+ uptr
.base
);
1495 static u32_t
get32()
1497 /* get 32 bits from current instruction pointer and advance pointer */
1501 temp
= peek_dword(uptr
.off
+ uptr
.base
);
1507 static int outsegaddr(addr
)
1508 struct address_s
*addr
;
1510 /* print segmented address */
1515 bytes_printed
= outsegreg(addr
->base
);
1516 if (bytes_printed
> 4)
1521 if (addr
->off
>= 0x10000)
1524 return bytes_printed
+ 8;
1526 outh16((u16_t
) addr
->off
);
1527 return bytes_printed
+ 4;
1530 static int outssegaddr(addr
)
1531 struct address_s
*addr
;
1533 /* print 32 bit segmented address and 2 spaces */
1537 bytes_printed
= outsegaddr(addr
);
1540 return bytes_printed
+ 2;
1543 static u8_t
peek_byte(addr
)
1546 return (u8_t
) peek_dword(addr
) & 0xFF; /* 8 bits only */
1549 static u16_t
peek_word(addr
)
1552 return (u16_t
) peek_dword(addr
);