Fixed c99 support for RDOFF Tools
[nasm.git] / disasm.c
blobc07c7a3b047bbece3a54a6ba3560affc88e78d72
1 /* disasm.c where all the _work_ gets done in the Netwide Disassembler
3 * The Netwide Assembler is copyright (C) 1996 Simon Tatham and
4 * Julian Hall. All rights reserved. The software is
5 * redistributable under the licence given in the file "Licence"
6 * distributed in the NASM archive.
8 * initial version 27/iii/95 by Simon Tatham
9 */
11 #include <stdio.h>
12 #include <string.h>
13 #include <inttypes.h>
15 #include "nasm.h"
16 #include "disasm.h"
17 #include "sync.h"
18 #include "insns.h"
20 #include "names.c"
22 extern struct itemplate **itable[];
25 * Flags that go into the `segment' field of `insn' structures
26 * during disassembly.
28 #define SEG_RELATIVE 1
29 #define SEG_32BIT 2
30 #define SEG_RMREG 4
31 #define SEG_DISP8 8
32 #define SEG_DISP16 16
33 #define SEG_DISP32 32
34 #define SEG_NODISP 64
35 #define SEG_SIGNED 128
37 static int whichreg(int32_t regflags, int regval)
39 #include "regdis.c"
41 if (!(REG_AL & ~regflags))
42 return R_AL;
43 if (!(REG_AX & ~regflags))
44 return R_AX;
45 if (!(REG_EAX & ~regflags))
46 return R_EAX;
47 if (!(REG_DL & ~regflags))
48 return R_DL;
49 if (!(REG_DX & ~regflags))
50 return R_DX;
51 if (!(REG_EDX & ~regflags))
52 return R_EDX;
53 if (!(REG_CL & ~regflags))
54 return R_CL;
55 if (!(REG_CX & ~regflags))
56 return R_CX;
57 if (!(REG_ECX & ~regflags))
58 return R_ECX;
59 if (!(FPU0 & ~regflags))
60 return R_ST0;
61 if (!(REG_CS & ~regflags))
62 return (regval == 1) ? R_CS : 0;
63 if (!(REG_DESS & ~regflags))
64 return (regval == 0 || regval == 2
65 || regval == 3 ? sreg[regval] : 0);
66 if (!(REG_FSGS & ~regflags))
67 return (regval == 4 || regval == 5 ? sreg[regval] : 0);
68 if (!(REG_SEG67 & ~regflags))
69 return (regval == 6 || regval == 7 ? sreg[regval] : 0);
71 /* All the entries below look up regval in an 8-entry array */
72 if (regval < 0 || regval > 7)
73 return 0;
75 if (!((REGMEM | BITS8) & ~regflags))
76 return reg8[regval];
77 if (!((REGMEM | BITS16) & ~regflags))
78 return reg16[regval];
79 if (!((REGMEM | BITS32) & ~regflags))
80 return reg32[regval];
81 if (!(REG_SREG & ~regflags))
82 return sreg[regval];
83 if (!(REG_CREG & ~regflags))
84 return creg[regval];
85 if (!(REG_DREG & ~regflags))
86 return dreg[regval];
87 if (!(REG_TREG & ~regflags))
88 return treg[regval];
89 if (!(FPUREG & ~regflags))
90 return fpureg[regval];
91 if (!(MMXREG & ~regflags))
92 return mmxreg[regval];
93 if (!(XMMREG & ~regflags))
94 return xmmreg[regval];
96 return 0;
99 static const int8_t *whichcond(int condval)
101 static int conds[] = {
102 C_O, C_NO, C_C, C_NC, C_Z, C_NZ, C_NA, C_A,
103 C_S, C_NS, C_PE, C_PO, C_L, C_NL, C_NG, C_G
105 return conditions[conds[condval]];
109 * Process an effective address (ModRM) specification.
111 static uint8_t *do_ea(uint8_t *data, int modrm, int asize,
112 int segsize, operand * op)
114 int mod, rm, scale, index, base;
116 mod = (modrm >> 6) & 03;
117 rm = modrm & 07;
119 if (mod == 3) { /* pure register version */
120 op->basereg = rm;
121 op->segment |= SEG_RMREG;
122 return data;
125 op->addr_size = 0;
127 if (asize == 16) {
129 * <mod> specifies the displacement size (none, byte or
130 * word), and <rm> specifies the register combination.
131 * Exception: mod=0,rm=6 does not specify [BP] as one might
132 * expect, but instead specifies [disp16].
134 op->indexreg = op->basereg = -1;
135 op->scale = 1; /* always, in 16 bits */
136 switch (rm) {
137 case 0:
138 op->basereg = R_BX;
139 op->indexreg = R_SI;
140 break;
141 case 1:
142 op->basereg = R_BX;
143 op->indexreg = R_DI;
144 break;
145 case 2:
146 op->basereg = R_BP;
147 op->indexreg = R_SI;
148 break;
149 case 3:
150 op->basereg = R_BP;
151 op->indexreg = R_DI;
152 break;
153 case 4:
154 op->basereg = R_SI;
155 break;
156 case 5:
157 op->basereg = R_DI;
158 break;
159 case 6:
160 op->basereg = R_BP;
161 break;
162 case 7:
163 op->basereg = R_BX;
164 break;
166 if (rm == 6 && mod == 0) { /* special case */
167 op->basereg = -1;
168 if (segsize != 16)
169 op->addr_size = 16;
170 mod = 2; /* fake disp16 */
172 switch (mod) {
173 case 0:
174 op->segment |= SEG_NODISP;
175 break;
176 case 1:
177 op->segment |= SEG_DISP8;
178 op->offset = (int8_t)*data++;
179 break;
180 case 2:
181 op->segment |= SEG_DISP16;
182 op->offset = *data++;
183 op->offset |= ((unsigned)*data++) << 8;
184 break;
186 return data;
187 } else {
189 * Once again, <mod> specifies displacement size (this time
190 * none, byte or *dword*), while <rm> specifies the base
191 * register. Again, [EBP] is missing, replaced by a pure
192 * disp32 (this time that's mod=0,rm=*5*). However, rm=4
193 * indicates not a single base register, but instead the
194 * presence of a SIB byte...
196 op->indexreg = -1;
197 switch (rm) {
198 case 0:
199 op->basereg = R_EAX;
200 break;
201 case 1:
202 op->basereg = R_ECX;
203 break;
204 case 2:
205 op->basereg = R_EDX;
206 break;
207 case 3:
208 op->basereg = R_EBX;
209 break;
210 case 5:
211 op->basereg = R_EBP;
212 break;
213 case 6:
214 op->basereg = R_ESI;
215 break;
216 case 7:
217 op->basereg = R_EDI;
218 break;
220 if (rm == 5 && mod == 0) {
221 op->basereg = -1;
222 if (segsize != 32)
223 op->addr_size = 32;
224 mod = 2; /* fake disp32 */
226 if (rm == 4) { /* process SIB */
227 scale = (*data >> 6) & 03;
228 index = (*data >> 3) & 07;
229 base = *data & 07;
230 data++;
232 op->scale = 1 << scale;
233 switch (index) {
234 case 0:
235 op->indexreg = R_EAX;
236 break;
237 case 1:
238 op->indexreg = R_ECX;
239 break;
240 case 2:
241 op->indexreg = R_EDX;
242 break;
243 case 3:
244 op->indexreg = R_EBX;
245 break;
246 case 4:
247 op->indexreg = -1;
248 break;
249 case 5:
250 op->indexreg = R_EBP;
251 break;
252 case 6:
253 op->indexreg = R_ESI;
254 break;
255 case 7:
256 op->indexreg = R_EDI;
257 break;
260 switch (base) {
261 case 0:
262 op->basereg = R_EAX;
263 break;
264 case 1:
265 op->basereg = R_ECX;
266 break;
267 case 2:
268 op->basereg = R_EDX;
269 break;
270 case 3:
271 op->basereg = R_EBX;
272 break;
273 case 4:
274 op->basereg = R_ESP;
275 break;
276 case 6:
277 op->basereg = R_ESI;
278 break;
279 case 7:
280 op->basereg = R_EDI;
281 break;
282 case 5:
283 if (mod == 0) {
284 mod = 2;
285 op->basereg = -1;
286 } else
287 op->basereg = R_EBP;
288 break;
291 switch (mod) {
292 case 0:
293 op->segment |= SEG_NODISP;
294 break;
295 case 1:
296 op->segment |= SEG_DISP8;
297 op->offset = (int8_t)*data++;
298 break;
299 case 2:
300 op->segment |= SEG_DISP32;
301 op->offset = *data++;
302 op->offset |= ((unsigned)*data++) << 8;
303 op->offset |= ((int32_t)*data++) << 16;
304 op->offset |= ((int32_t)*data++) << 24;
305 break;
307 return data;
312 * Determine whether the instruction template in t corresponds to the data
313 * stream in data. Return the number of bytes matched if so.
315 static int matches(struct itemplate *t, uint8_t *data, int asize,
316 int osize, int segsize, int rep, insn * ins)
318 uint8_t *r = (uint8_t *)(t->code);
319 uint8_t *origdata = data;
320 int a_used = FALSE, o_used = FALSE;
321 int drep = 0;
323 if (rep == 0xF2)
324 drep = P_REPNE;
325 else if (rep == 0xF3)
326 drep = P_REP;
328 while (*r) {
329 int c = *r++;
330 if (c >= 01 && c <= 03) {
331 while (c--)
332 if (*r++ != *data++)
333 return FALSE;
335 if (c == 04) {
336 switch (*data++) {
337 case 0x07:
338 ins->oprs[0].basereg = 0;
339 break;
340 case 0x17:
341 ins->oprs[0].basereg = 2;
342 break;
343 case 0x1F:
344 ins->oprs[0].basereg = 3;
345 break;
346 default:
347 return FALSE;
350 if (c == 05) {
351 switch (*data++) {
352 case 0xA1:
353 ins->oprs[0].basereg = 4;
354 break;
355 case 0xA9:
356 ins->oprs[0].basereg = 5;
357 break;
358 default:
359 return FALSE;
362 if (c == 06) {
363 switch (*data++) {
364 case 0x06:
365 ins->oprs[0].basereg = 0;
366 break;
367 case 0x0E:
368 ins->oprs[0].basereg = 1;
369 break;
370 case 0x16:
371 ins->oprs[0].basereg = 2;
372 break;
373 case 0x1E:
374 ins->oprs[0].basereg = 3;
375 break;
376 default:
377 return FALSE;
380 if (c == 07) {
381 switch (*data++) {
382 case 0xA0:
383 ins->oprs[0].basereg = 4;
384 break;
385 case 0xA8:
386 ins->oprs[0].basereg = 5;
387 break;
388 default:
389 return FALSE;
392 if (c >= 010 && c <= 012) {
393 int t = *r++, d = *data++;
394 if (d < t || d > t + 7)
395 return FALSE;
396 else {
397 ins->oprs[c - 010].basereg = d - t;
398 ins->oprs[c - 010].segment |= SEG_RMREG;
401 if (c == 017)
402 if (*data++)
403 return FALSE;
404 if (c >= 014 && c <= 016) {
405 ins->oprs[c - 014].offset = (int8_t)*data++;
406 ins->oprs[c - 014].segment |= SEG_SIGNED;
408 if (c >= 020 && c <= 022)
409 ins->oprs[c - 020].offset = *data++;
410 if (c >= 024 && c <= 026)
411 ins->oprs[c - 024].offset = *data++;
412 if (c >= 030 && c <= 032) {
413 ins->oprs[c - 030].offset = *data++;
414 ins->oprs[c - 030].offset |= (((unsigned)*data++) << 8);
416 if (c >= 034 && c <= 036) {
417 ins->oprs[c - 034].offset = *data++;
418 ins->oprs[c - 034].offset |= (((unsigned)*data++) << 8);
419 if (osize == 32) {
420 ins->oprs[c - 034].offset |= (((int32_t)*data++) << 16);
421 ins->oprs[c - 034].offset |= (((int32_t)*data++) << 24);
423 if (segsize != asize)
424 ins->oprs[c - 034].addr_size = asize;
426 if (c >= 040 && c <= 042) {
427 ins->oprs[c - 040].offset = *data++;
428 ins->oprs[c - 040].offset |= (((unsigned)*data++) << 8);
429 ins->oprs[c - 040].offset |= (((int32_t)*data++) << 16);
430 ins->oprs[c - 040].offset |= (((int32_t)*data++) << 24);
432 if (c >= 044 && c <= 046) {
433 ins->oprs[c - 044].offset = *data++;
434 ins->oprs[c - 044].offset |= (((unsigned)*data++) << 8);
435 if (asize == 32) {
436 ins->oprs[c - 044].offset |= (((int32_t)*data++) << 16);
437 ins->oprs[c - 044].offset |= (((int32_t)*data++) << 24);
439 if (segsize != asize)
440 ins->oprs[c - 044].addr_size = asize;
442 if (c >= 050 && c <= 052) {
443 ins->oprs[c - 050].offset = (int8_t)*data++;
444 ins->oprs[c - 050].segment |= SEG_RELATIVE;
446 if (c >= 060 && c <= 062) {
447 ins->oprs[c - 060].offset = *data++;
448 ins->oprs[c - 060].offset |= (((unsigned)*data++) << 8);
449 ins->oprs[c - 060].segment |= SEG_RELATIVE;
450 ins->oprs[c - 060].segment &= ~SEG_32BIT;
452 if (c >= 064 && c <= 066) {
453 ins->oprs[c - 064].offset = *data++;
454 ins->oprs[c - 064].offset |= (((unsigned)*data++) << 8);
455 if (osize == 32) {
456 ins->oprs[c - 064].offset |= (((int32_t)*data++) << 16);
457 ins->oprs[c - 064].offset |= (((int32_t)*data++) << 24);
458 ins->oprs[c - 064].segment |= SEG_32BIT;
459 } else
460 ins->oprs[c - 064].segment &= ~SEG_32BIT;
461 ins->oprs[c - 064].segment |= SEG_RELATIVE;
462 if (segsize != osize) {
463 ins->oprs[c - 064].type =
464 (ins->oprs[c - 064].type & NON_SIZE)
465 | ((osize == 16) ? BITS16 : BITS32);
468 if (c >= 070 && c <= 072) {
469 ins->oprs[c - 070].offset = *data++;
470 ins->oprs[c - 070].offset |= (((unsigned)*data++) << 8);
471 ins->oprs[c - 070].offset |= (((int32_t)*data++) << 16);
472 ins->oprs[c - 070].offset |= (((int32_t)*data++) << 24);
473 ins->oprs[c - 070].segment |= SEG_32BIT | SEG_RELATIVE;
475 if (c >= 0100 && c < 0130) {
476 int modrm = *data++;
477 ins->oprs[c & 07].basereg = (modrm >> 3) & 07;
478 ins->oprs[c & 07].segment |= SEG_RMREG;
479 data = do_ea(data, modrm, asize, segsize,
480 &ins->oprs[(c >> 3) & 07]);
482 if (c >= 0130 && c <= 0132) {
483 ins->oprs[c - 0130].offset = *data++;
484 ins->oprs[c - 0130].offset |= (((unsigned)*data++) << 8);
486 if (c >= 0140 && c <= 0142) {
487 ins->oprs[c - 0140].offset = *data++;
488 ins->oprs[c - 0140].offset |= (((unsigned)*data++) << 8);
489 ins->oprs[c - 0140].offset |= (((int32_t)*data++) << 16);
490 ins->oprs[c - 0140].offset |= (((int32_t)*data++) << 24);
492 if (c >= 0200 && c <= 0277) {
493 int modrm = *data++;
494 if (((modrm >> 3) & 07) != (c & 07))
495 return FALSE; /* spare field doesn't match up */
496 data = do_ea(data, modrm, asize, segsize,
497 &ins->oprs[(c >> 3) & 07]);
499 if (c >= 0300 && c <= 0302) {
500 if (asize)
501 ins->oprs[c - 0300].segment |= SEG_32BIT;
502 else
503 ins->oprs[c - 0300].segment &= ~SEG_32BIT;
504 a_used = TRUE;
506 if (c == 0310) {
507 if (asize == 32)
508 return FALSE;
509 else
510 a_used = TRUE;
512 if (c == 0311) {
513 if (asize == 16)
514 return FALSE;
515 else
516 a_used = TRUE;
518 if (c == 0312) {
519 if (asize != segsize)
520 return FALSE;
521 else
522 a_used = TRUE;
524 if (c == 0320) {
525 if (osize == 32)
526 return FALSE;
527 else
528 o_used = TRUE;
530 if (c == 0321) {
531 if (osize == 16)
532 return FALSE;
533 else
534 o_used = TRUE;
536 if (c == 0322) {
537 if (osize != segsize)
538 return FALSE;
539 else
540 o_used = TRUE;
542 if (c == 0330) {
543 int t = *r++, d = *data++;
544 if (d < t || d > t + 15)
545 return FALSE;
546 else
547 ins->condition = d - t;
549 if (c == 0331) {
550 if (rep)
551 return FALSE;
553 if (c == 0332) {
554 if (drep == P_REP)
555 drep = P_REPE;
557 if (c == 0333) {
558 if (rep != 0xF3)
559 return FALSE;
560 drep = 0;
565 * Check for unused rep or a/o prefixes.
567 ins->nprefix = 0;
568 if (drep)
569 ins->prefixes[ins->nprefix++] = drep;
570 if (!a_used && asize != segsize)
571 ins->prefixes[ins->nprefix++] = (asize == 16 ? P_A16 : P_A32);
572 if (!o_used && osize != segsize)
573 ins->prefixes[ins->nprefix++] = (osize == 16 ? P_O16 : P_O32);
575 return data - origdata;
578 int32_t disasm(uint8_t *data, int8_t *output, int outbufsize, int segsize,
579 int32_t offset, int autosync, uint32_t prefer)
581 struct itemplate **p, **best_p;
582 int length, best_length = 0;
583 int8_t *segover;
584 int rep, lock, asize, osize, i, slen, colon;
585 uint8_t *origdata;
586 int works;
587 insn tmp_ins, ins;
588 uint32_t goodness, best;
591 * Scan for prefixes.
593 asize = osize = segsize;
594 segover = NULL;
595 rep = lock = 0;
596 origdata = data;
597 for (;;) {
598 if (*data == 0xF3 || *data == 0xF2)
599 rep = *data++;
600 else if (*data == 0xF0)
601 lock = *data++;
602 else if (*data == 0x2E || *data == 0x36 || *data == 0x3E ||
603 *data == 0x26 || *data == 0x64 || *data == 0x65) {
604 switch (*data++) {
605 case 0x2E:
606 segover = "cs";
607 break;
608 case 0x36:
609 segover = "ss";
610 break;
611 case 0x3E:
612 segover = "ds";
613 break;
614 case 0x26:
615 segover = "es";
616 break;
617 case 0x64:
618 segover = "fs";
619 break;
620 case 0x65:
621 segover = "gs";
622 break;
624 } else if (*data == 0x66)
625 osize = 48 - segsize, data++;
626 else if (*data == 0x67)
627 asize = 48 - segsize, data++;
628 else
629 break;
632 tmp_ins.oprs[0].segment = tmp_ins.oprs[1].segment =
633 tmp_ins.oprs[2].segment =
634 tmp_ins.oprs[0].addr_size = tmp_ins.oprs[1].addr_size =
635 tmp_ins.oprs[2].addr_size = (segsize == 16 ? 0 : SEG_32BIT);
636 tmp_ins.condition = -1;
637 best = ~0UL; /* Worst possible */
638 best_p = NULL;
639 for (p = itable[*data]; *p; p++) {
640 if ((length = matches(*p, data, asize, osize,
641 segsize, rep, &tmp_ins))) {
642 works = TRUE;
644 * Final check to make sure the types of r/m match up.
646 for (i = 0; i < (*p)->operands; i++) {
647 if (
648 /* If it's a mem-only EA but we have a register, die. */
649 ((tmp_ins.oprs[i].segment & SEG_RMREG) &&
650 !(MEMORY & ~(*p)->opd[i])) ||
651 /* If it's a reg-only EA but we have a memory ref, die. */
652 (!(tmp_ins.oprs[i].segment & SEG_RMREG) &&
653 !(REGNORM & ~(*p)->opd[i]) &&
654 !((*p)->opd[i] & REG_SMASK)) ||
655 /* Register type mismatch (eg FS vs REG_DESS): die. */
656 ((((*p)->opd[i] & (REGISTER | FPUREG)) ||
657 (tmp_ins.oprs[i].segment & SEG_RMREG)) &&
658 !whichreg((*p)->opd[i],
659 tmp_ins.oprs[i].basereg))) {
660 works = FALSE;
661 break;
665 if (works) {
666 goodness = ((*p)->flags & IF_PFMASK) ^ prefer;
667 if (goodness < best) {
668 /* This is the best one found so far */
669 best = goodness;
670 best_p = p;
671 best_length = length;
672 ins = tmp_ins;
678 if (!best_p)
679 return 0; /* no instruction was matched */
681 /* Pick the best match */
682 p = best_p;
683 length = best_length;
685 slen = 0;
687 /* TODO: snprintf returns the value that the string would have if
688 * the buffer were long enough, and not the actual length of
689 * the returned string, so each instance of using the return
690 * value of snprintf should actually be checked to assure that
691 * the return value is "sane." Maybe a macro wrapper could
692 * be used for that purpose.
694 if (lock)
695 slen += snprintf(output + slen, outbufsize - slen, "lock ");
696 for (i = 0; i < ins.nprefix; i++)
697 switch (ins.prefixes[i]) {
698 case P_REP:
699 slen += snprintf(output + slen, outbufsize - slen, "rep ");
700 break;
701 case P_REPE:
702 slen += snprintf(output + slen, outbufsize - slen, "repe ");
703 break;
704 case P_REPNE:
705 slen += snprintf(output + slen, outbufsize - slen, "repne ");
706 break;
707 case P_A16:
708 slen += snprintf(output + slen, outbufsize - slen, "a16 ");
709 break;
710 case P_A32:
711 slen += snprintf(output + slen, outbufsize - slen, "a32 ");
712 break;
713 case P_O16:
714 slen += snprintf(output + slen, outbufsize - slen, "o16 ");
715 break;
716 case P_O32:
717 slen += snprintf(output + slen, outbufsize - slen, "o32 ");
718 break;
721 for (i = 0; i < elements(ico); i++)
722 if ((*p)->opcode == ico[i]) {
723 slen +=
724 snprintf(output + slen, outbufsize - slen, "%s%s", icn[i],
725 whichcond(ins.condition));
726 break;
728 if (i >= elements(ico))
729 slen +=
730 snprintf(output + slen, outbufsize - slen, "%s",
731 insn_names[(*p)->opcode]);
732 colon = FALSE;
733 length += data - origdata; /* fix up for prefixes */
734 for (i = 0; i < (*p)->operands; i++) {
735 output[slen++] = (colon ? ':' : i == 0 ? ' ' : ',');
737 if (ins.oprs[i].segment & SEG_RELATIVE) {
738 ins.oprs[i].offset += offset + length;
740 * sort out wraparound
742 if (!(ins.oprs[i].segment & SEG_32BIT))
743 ins.oprs[i].offset &= 0xFFFF;
745 * add sync marker, if autosync is on
747 if (autosync)
748 add_sync(ins.oprs[i].offset, 0L);
751 if ((*p)->opd[i] & COLON)
752 colon = TRUE;
753 else
754 colon = FALSE;
756 if (((*p)->opd[i] & (REGISTER | FPUREG)) ||
757 (ins.oprs[i].segment & SEG_RMREG)) {
758 ins.oprs[i].basereg = whichreg((*p)->opd[i],
759 ins.oprs[i].basereg);
760 if ((*p)->opd[i] & TO)
761 slen += snprintf(output + slen, outbufsize - slen, "to ");
762 slen += snprintf(output + slen, outbufsize - slen, "%s",
763 reg_names[ins.oprs[i].basereg -
764 EXPR_REG_START]);
765 } else if (!(UNITY & ~(*p)->opd[i])) {
766 output[slen++] = '1';
767 } else if ((*p)->opd[i] & IMMEDIATE) {
768 if ((*p)->opd[i] & BITS8) {
769 slen +=
770 snprintf(output + slen, outbufsize - slen, "byte ");
771 if (ins.oprs[i].segment & SEG_SIGNED) {
772 if (ins.oprs[i].offset < 0) {
773 ins.oprs[i].offset *= -1;
774 output[slen++] = '-';
775 } else
776 output[slen++] = '+';
778 } else if ((*p)->opd[i] & BITS16) {
779 slen +=
780 snprintf(output + slen, outbufsize - slen, "word ");
781 } else if ((*p)->opd[i] & BITS32) {
782 slen +=
783 snprintf(output + slen, outbufsize - slen, "dword ");
784 } else if ((*p)->opd[i] & NEAR) {
785 slen +=
786 snprintf(output + slen, outbufsize - slen, "near ");
787 } else if ((*p)->opd[i] & SHORT) {
788 slen +=
789 snprintf(output + slen, outbufsize - slen, "short ");
791 slen +=
792 snprintf(output + slen, outbufsize - slen, "0x%lx",
793 ins.oprs[i].offset);
794 } else if (!(MEM_OFFS & ~(*p)->opd[i])) {
795 slen +=
796 snprintf(output + slen, outbufsize - slen, "[%s%s%s0x%lx]",
797 ((const char*)segover ? (const char*)segover : ""), /* placate type mistmatch warning */
798 ((const char*)segover ? ":" : ""), /* by using (const char*) instead of uint8_t* */
799 (ins.oprs[i].addr_size ==
800 32 ? "dword " : ins.oprs[i].addr_size ==
801 16 ? "word " : ""), ins.oprs[i].offset);
802 segover = NULL;
803 } else if (!(REGMEM & ~(*p)->opd[i])) {
804 int started = FALSE;
805 if ((*p)->opd[i] & BITS8)
806 slen +=
807 snprintf(output + slen, outbufsize - slen, "byte ");
808 if ((*p)->opd[i] & BITS16)
809 slen +=
810 snprintf(output + slen, outbufsize - slen, "word ");
811 if ((*p)->opd[i] & BITS32)
812 slen +=
813 snprintf(output + slen, outbufsize - slen, "dword ");
814 if ((*p)->opd[i] & BITS64)
815 slen +=
816 snprintf(output + slen, outbufsize - slen, "qword ");
817 if ((*p)->opd[i] & BITS80)
818 slen +=
819 snprintf(output + slen, outbufsize - slen, "tword ");
820 if ((*p)->opd[i] & FAR)
821 slen += snprintf(output + slen, outbufsize - slen, "far ");
822 if ((*p)->opd[i] & NEAR)
823 slen +=
824 snprintf(output + slen, outbufsize - slen, "near ");
825 output[slen++] = '[';
826 if (ins.oprs[i].addr_size)
827 slen += snprintf(output + slen, outbufsize - slen, "%s",
828 (ins.oprs[i].addr_size == 32 ? "dword " :
829 ins.oprs[i].addr_size ==
830 16 ? "word " : ""));
831 if (segover) {
832 slen +=
833 snprintf(output + slen, outbufsize - slen, "%s:",
834 segover);
835 segover = NULL;
837 if (ins.oprs[i].basereg != -1) {
838 slen += snprintf(output + slen, outbufsize - slen, "%s",
839 reg_names[(ins.oprs[i].basereg -
840 EXPR_REG_START)]);
841 started = TRUE;
843 if (ins.oprs[i].indexreg != -1) {
844 if (started)
845 output[slen++] = '+';
846 slen += snprintf(output + slen, outbufsize - slen, "%s",
847 reg_names[(ins.oprs[i].indexreg -
848 EXPR_REG_START)]);
849 if (ins.oprs[i].scale > 1)
850 slen +=
851 snprintf(output + slen, outbufsize - slen, "*%d",
852 ins.oprs[i].scale);
853 started = TRUE;
855 if (ins.oprs[i].segment & SEG_DISP8) {
856 int sign = '+';
857 if (ins.oprs[i].offset & 0x80) {
858 ins.oprs[i].offset = -(int8_t)ins.oprs[i].offset;
859 sign = '-';
861 slen +=
862 snprintf(output + slen, outbufsize - slen, "%c0x%lx",
863 sign, ins.oprs[i].offset);
864 } else if (ins.oprs[i].segment & SEG_DISP16) {
865 if (started)
866 output[slen++] = '+';
867 slen +=
868 snprintf(output + slen, outbufsize - slen, "0x%lx",
869 ins.oprs[i].offset);
870 } else if (ins.oprs[i].segment & SEG_DISP32) {
871 if (started)
872 output[slen++] = '+';
873 slen +=
874 snprintf(output + slen, outbufsize - slen, "0x%lx",
875 ins.oprs[i].offset);
877 output[slen++] = ']';
878 } else {
879 slen +=
880 snprintf(output + slen, outbufsize - slen, "<operand%d>",
884 output[slen] = '\0';
885 if (segover) { /* unused segment override */
886 int8_t *p = output;
887 int count = slen + 1;
888 while (count--)
889 p[count + 3] = p[count];
890 strncpy(output, segover, 2);
891 output[2] = ' ';
893 return length;
896 int32_t eatbyte(uint8_t *data, int8_t *output, int outbufsize)
898 snprintf(output, outbufsize, "db 0x%02X", *data);
899 return 1;