NASM 0.95
[platform/upstream/nasm.git] / disasm.c
1 /* disasm.c   where all the _work_ gets done in the Netwide Disassembler
2  *
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.
7  *
8  * initial version 27/iii/95 by Simon Tatham
9  */
10
11 #include <stdio.h>
12 #include <string.h>
13
14 #include "nasm.h"
15 #include "disasm.h"
16 #include "sync.h"
17 #include "insns.h"
18
19 #include "names.c"
20
21 extern struct itemplate **itable[];
22
23 /*
24  * Flags that go into the `segment' field of `insn' structures
25  * during disassembly.
26  */
27 #define SEG_RELATIVE 1
28 #define SEG_32BIT 2
29 #define SEG_RMREG 4
30 #define SEG_DISP8 8
31 #define SEG_DISP16 16
32 #define SEG_DISP32 32
33 #define SEG_NODISP 64
34 #define SEG_SIGNED 128
35
36 static int whichreg(long regflags, int regval) {
37     static int reg32[] = {
38         R_EAX, R_ECX, R_EDX, R_EBX, R_ESP, R_EBP, R_ESI, R_EDI };
39     static int reg16[] = {
40         R_AX, R_CX, R_DX, R_BX, R_SP, R_BP, R_SI, R_DI };
41     static int reg8[] = {
42         R_AL, R_CL, R_DL, R_BL, R_AH, R_CH, R_DH, R_BH };
43     static int sreg[] = {
44         R_ES, R_CS, R_SS, R_DS, R_FS, R_GS, 0, 0 };
45     static int creg[] = {
46         R_CR0, 0, R_CR2, R_CR3, R_CR4, 0, 0, 0 };
47     static int dreg[] = {
48         R_DR0, R_DR1, R_DR2, R_DR3, 0, 0, R_DR6, R_DR7 };
49     static int treg[] = {
50         0, 0, 0, R_TR3, R_TR4, R_TR5, R_TR6, R_TR7 };
51     static int fpureg[] = {
52         R_ST0, R_ST1, R_ST2, R_ST3, R_ST4, R_ST5, R_ST6, R_ST7 };
53     static int mmxreg[] = {
54         R_MM0, R_MM1, R_MM2, R_MM3, R_MM4, R_MM5, R_MM6, R_MM7 };
55
56     if (!(REG_AL & ~regflags))
57         return R_AL;
58     if (!(REG_AX & ~regflags))
59         return R_AX;
60     if (!(REG_EAX & ~regflags))
61         return R_EAX;
62     if (!(REG_DX & ~regflags))
63         return R_DX;
64     if (!(REG_CL & ~regflags))
65         return R_CL;
66     if (!(REG_CX & ~regflags))
67         return R_CX;
68     if (!(REG_ECX & ~regflags))
69         return R_ECX;
70     if (!(REG_CR4 & ~regflags))
71         return R_CR4;
72     if (!(FPU0 & ~regflags))
73         return R_ST0;
74     if (!(REG_CS & ~regflags))
75         return R_CS;
76     if (!((REGMEM|BITS8) & ~regflags))
77         return reg8[regval];
78     if (!((REGMEM|BITS16) & ~regflags))
79         return reg16[regval];
80     if (!((REGMEM|BITS32) & ~regflags))
81         return reg32[regval];
82     if (!(REG_SREG & ~regflags))
83         return sreg[regval];
84     if (!(REG_CREG & ~regflags))
85         return creg[regval];
86     if (!(REG_DREG & ~regflags))
87         return dreg[regval];
88     if (!(REG_TREG & ~regflags))
89         return treg[regval];
90     if (!(FPUREG & ~regflags))
91         return fpureg[regval];
92     if (!(MMXREG & ~regflags))
93         return mmxreg[regval];
94     return 0;
95 }
96
97 static char *whichcond(int condval) {
98     static int conds[] = {
99         C_O, C_NO, C_C, C_NC, C_Z, C_NZ, C_NA, C_A,
100         C_S, C_NS, C_PE, C_PO, C_L, C_NL, C_NG, C_G
101     };
102     return conditions[conds[condval]];
103 }
104
105 /*
106  * Process an effective address (ModRM) specification.
107  */
108 static unsigned char *do_ea (unsigned char *data, int modrm, int asize,
109                              int segsize, operand *op) {
110     int mod, rm, scale, index, base;
111
112     mod = (modrm >> 6) & 03;
113     rm = modrm & 07;
114
115     if (mod == 3) {                    /* pure register version */
116         op->basereg = rm;
117         op->segment |= SEG_RMREG;
118         return data;
119     }
120
121     op->addr_size = 0;
122
123     if (asize == 16) {
124         /*
125          * <mod> specifies the displacement size (none, byte or
126          * word), and <rm> specifies the register combination.
127          * Exception: mod=0,rm=6 does not specify [BP] as one might
128          * expect, but instead specifies [disp16].
129          */
130         op->indexreg = op->basereg = -1;
131         op->scale = 1;                 /* always, in 16 bits */
132         switch (rm) {
133           case 0: op->basereg = R_BX; op->indexreg = R_SI; break;
134           case 1: op->basereg = R_BX; op->indexreg = R_DI; break;
135           case 2: op->basereg = R_BP; op->indexreg = R_SI; break;
136           case 3: op->basereg = R_BP; op->indexreg = R_DI; break;
137           case 4: op->basereg = R_SI; break;
138           case 5: op->basereg = R_DI; break;
139           case 6: op->basereg = R_BP; break;
140           case 7: op->basereg = R_BX; break;
141         }
142         if (rm == 6 && mod == 0) {     /* special case */
143             op->basereg = -1;
144             if (segsize != 16)
145                 op->addr_size = 16;
146             mod = 2;                   /* fake disp16 */
147         }
148         switch (mod) {
149           case 0:
150             op->segment |= SEG_NODISP;
151             break;
152           case 1:
153             op->segment |= SEG_DISP8;
154             op->offset = (signed char) *data++;
155             break;
156           case 2:
157             op->segment |= SEG_DISP16;
158             op->offset = *data++;
159             op->offset |= (*data++) << 8;
160             break;
161         }
162         return data;
163     } else {
164         /*
165          * Once again, <mod> specifies displacement size (this time
166          * none, byte or *dword*), while <rm> specifies the base
167          * register. Again, [EBP] is missing, replaced by a pure
168          * disp32 (this time that's mod=0,rm=*5*). However, rm=4
169          * indicates not a single base register, but instead the
170          * presence of a SIB byte...
171          */
172         op->indexreg = -1;
173         switch (rm) {
174           case 0: op->basereg = R_EAX; break;
175           case 1: op->basereg = R_ECX; break;
176           case 2: op->basereg = R_EDX; break;
177           case 3: op->basereg = R_EBX; break;
178           case 5: op->basereg = R_EBP; break;
179           case 6: op->basereg = R_ESI; break;
180           case 7: op->basereg = R_EDI; break;
181         }
182         if (rm == 5 && mod == 0) {
183             op->basereg = -1;
184             if (segsize != 32)
185                 op->addr_size = 32;
186             mod = 2;                   /* fake disp32 */
187         }
188         if (rm == 4) {                 /* process SIB */
189             scale = (*data >> 6) & 03;
190             index = (*data >> 3) & 07;
191             base = *data & 07;
192             data++;
193
194             op->scale = 1 << scale;
195             switch (index) {
196               case 0: op->indexreg = R_EAX; break;
197               case 1: op->indexreg = R_ECX; break;
198               case 2: op->indexreg = R_EDX; break;
199               case 3: op->indexreg = R_EBX; break;
200               case 4: op->indexreg = -1; break;
201               case 5: op->indexreg = R_EBP; break;
202               case 6: op->indexreg = R_ESI; break;
203               case 7: op->indexreg = R_EDI; break;
204             }
205
206             switch (base) {
207               case 0: op->basereg = R_EAX; break;
208               case 1: op->basereg = R_ECX; break;
209               case 2: op->basereg = R_EDX; break;
210               case 3: op->basereg = R_EBX; break;
211               case 4: op->basereg = R_ESP; break;
212               case 6: op->basereg = R_ESI; break;
213               case 7: op->basereg = R_EDI; break;
214               case 5:
215                 if (mod == 0) {
216                     mod = 2;
217                     op->basereg = -1;
218                 } else
219                     op->basereg = R_EBP;
220                 break;
221             }
222         }
223         switch (mod) {
224           case 0:
225             op->segment |= SEG_NODISP;
226             break;
227           case 1:
228             op->segment |= SEG_DISP8;
229             op->offset = (signed char) *data++;
230             break;
231           case 2:
232             op->segment |= SEG_DISP32;
233             op->offset = *data++;
234             op->offset |= (*data++) << 8;
235             op->offset |= ((long) *data++) << 16;
236             op->offset |= ((long) *data++) << 24;
237             break;
238         }
239         return data;
240     }
241 }
242
243 /*
244  * Determine whether the code string in r corresponds to the data
245  * stream in data. Return the number of bytes matched if so.
246  */
247 static int matches (unsigned char *r, unsigned char *data, int asize,
248                     int osize, int segsize, insn *ins) {
249     unsigned char *origdata = data;
250     int a_used = FALSE, o_used = FALSE;
251
252     while (*r) {
253         int c = *r++;
254         if (c >= 01 && c <= 03) {
255             while (c--)
256                 if (*r++ != *data++)
257                     return FALSE;
258         }
259         if (c == 04) {
260             switch (*data++) {
261               case 0x07: ins->oprs[0].basereg = 0; break;
262               case 0x17: ins->oprs[0].basereg = 2; break;
263               case 0x1F: ins->oprs[0].basereg = 3; break;
264               default: return FALSE;
265             }
266         }
267         if (c == 05) {
268             switch (*data++) {
269               case 0xA1: ins->oprs[0].basereg = 4; break;
270               case 0xA9: ins->oprs[0].basereg = 5; break;
271               default: return FALSE;
272             }
273         }
274         if (c == 06) {
275             switch (*data++) {
276               case 0x06: ins->oprs[0].basereg = 0; break;
277               case 0x0E: ins->oprs[0].basereg = 1; break;
278               case 0x16: ins->oprs[0].basereg = 2; break;
279               case 0x1E: ins->oprs[0].basereg = 3; break;
280               default: return FALSE;
281             }
282         }
283         if (c == 07) {
284             switch (*data++) {
285               case 0xA0: ins->oprs[0].basereg = 4; break;
286               case 0xA8: ins->oprs[0].basereg = 5; break;
287               default: return FALSE;
288             }
289         }
290         if (c >= 010 && c <= 012) {
291             int t = *r++, d = *data++;
292             if (d < t || d > t+7)
293                 return FALSE;
294             else {
295                 ins->oprs[c-010].basereg = d-t;
296                 ins->oprs[c-010].segment |= SEG_RMREG;
297             }
298         }
299         if (c == 017)
300             if (*data++)
301                 return FALSE;
302         if (c >= 014 && c <= 016) {
303             ins->oprs[c-014].offset = (signed char) *data++;
304             ins->oprs[c-014].segment |= SEG_SIGNED;
305         }
306         if (c >= 020 && c <= 022)
307             ins->oprs[c-020].offset = *data++;
308         if (c >= 024 && c <= 026)
309             ins->oprs[c-024].offset = *data++;
310         if (c >= 030 && c <= 032) {
311             ins->oprs[c-030].offset = *data++;
312             ins->oprs[c-030].offset |= (*data++ << 8);
313         }
314         if (c >= 034 && c <= 036) {
315             ins->oprs[c-034].offset = *data++;
316             ins->oprs[c-034].offset |= (*data++ << 8);
317             if (asize == 32) {
318                 ins->oprs[c-034].offset |= (((long) *data++) << 16);
319                 ins->oprs[c-034].offset |= (((long) *data++) << 24);
320             }
321             if (segsize != asize)
322                 ins->oprs[c-034].addr_size = asize;
323         }
324         if (c >= 040 && c <= 042) {
325             ins->oprs[c-040].offset = *data++;
326             ins->oprs[c-040].offset |= (*data++ << 8);
327             ins->oprs[c-040].offset |= (((long) *data++) << 16);
328             ins->oprs[c-040].offset |= (((long) *data++) << 24);
329         }
330         if (c >= 050 && c <= 052) {
331             ins->oprs[c-050].offset = (signed char) *data++;
332             ins->oprs[c-050].segment |= SEG_RELATIVE;
333         }
334         if (c >= 060 && c <= 062) {
335             ins->oprs[c-060].offset = *data++;
336             ins->oprs[c-060].offset |= (*data++ << 8);
337             ins->oprs[c-060].segment |= SEG_RELATIVE;
338             ins->oprs[c-060].segment &= ~SEG_32BIT;
339         }
340         if (c >= 064 && c <= 066) {
341             ins->oprs[c-064].offset = *data++;
342             ins->oprs[c-064].offset |= (*data++ << 8);
343             if (asize == 32) {
344                 ins->oprs[c-064].offset |= (((long) *data++) << 16);
345                 ins->oprs[c-064].offset |= (((long) *data++) << 24);
346                 ins->oprs[c-064].segment |= SEG_32BIT;
347             } else
348                 ins->oprs[c-064].segment &= ~SEG_32BIT;
349             ins->oprs[c-064].segment |= SEG_RELATIVE;
350             if (segsize != asize)
351                 ins->oprs[c-064].addr_size = asize;
352         }
353         if (c >= 070 && c <= 072) {
354             ins->oprs[c-070].offset = *data++;
355             ins->oprs[c-070].offset |= (*data++ << 8);
356             ins->oprs[c-070].offset |= (((long) *data++) << 16);
357             ins->oprs[c-070].offset |= (((long) *data++) << 24);
358             ins->oprs[c-070].segment |= SEG_32BIT | SEG_RELATIVE;
359         }
360         if (c >= 0100 && c <= 0177) {
361             int modrm = *data++;
362             ins->oprs[c & 07].basereg = (modrm >> 3) & 07;
363             ins->oprs[c & 07].segment |= SEG_RMREG;
364             data = do_ea (data, modrm, asize, segsize,
365                           &ins->oprs[(c >> 3) & 07]);
366         }
367         if (c >= 0200 && c <= 0277) {
368             int modrm = *data++;
369             if (((modrm >> 3) & 07) != (c & 07))
370                 return FALSE;          /* spare field doesn't match up */
371             data = do_ea (data, modrm, asize, segsize,
372                           &ins->oprs[(c >> 3) & 07]);
373         }
374         if (c >= 0300 && c <= 0302) {
375             if (asize)
376                 ins->oprs[c-0300].segment |= SEG_32BIT;
377             else
378                 ins->oprs[c-0300].segment &= ~SEG_32BIT;
379             a_used = TRUE;
380         }
381         if (c == 0310) {
382             if (asize == 32)
383                 return FALSE;
384             else
385                 a_used = TRUE;
386         }
387         if (c == 0311) {
388             if (asize == 16)
389                 return FALSE;
390             else
391                 a_used = TRUE;
392         }
393         if (c == 0312) {
394             if (asize != segsize)
395                 return FALSE;
396             else
397                 a_used = TRUE;
398         }
399         if (c == 0320) {
400             if (osize == 32)
401                 return FALSE;
402             else
403                 o_used = TRUE;
404         }
405         if (c == 0321) {
406             if (osize == 16)
407                 return FALSE;
408             else
409                 o_used = TRUE;
410         }
411         if (c == 0322) {
412             if (osize != segsize)
413                 return FALSE;
414             else
415                 o_used = TRUE;
416         }
417         if (c == 0330) {
418             int t = *r++, d = *data++;
419             if (d < t || d > t+15)
420                 return FALSE;
421             else
422                 ins->condition = d - t;
423         }
424     }
425
426     /*
427      * Check for unused a/o prefixes.
428      */
429     ins->nprefix = 0;
430     if (!a_used && asize != segsize)
431         ins->prefixes[ins->nprefix++] = (asize == 16 ? P_A16 : P_A32);
432     if (!o_used && osize != segsize)
433         ins->prefixes[ins->nprefix++] = (osize == 16 ? P_O16 : P_O32);
434
435     return data - origdata;
436 }
437
438 long disasm (unsigned char *data, char *output, int segsize, long offset,
439              int autosync) {
440     struct itemplate **p;
441     int length = 0;
442     char *segover;
443     int rep, lock, asize, osize, i, slen, colon;
444     unsigned char *origdata;
445     int works;
446     insn ins;
447
448     /*
449      * Scan for prefixes.
450      */
451     asize = osize = segsize;
452     segover = NULL;
453     rep = lock = 0;
454     origdata = data;
455     for (;;) {
456         if (*data == 0xF3 || *data == 0xF2)
457             rep = *data++;
458         else if (*data == 0xF0)
459             lock = *data++;
460         else if (*data == 0x2E || *data == 0x36 || *data == 0x3E ||
461                  *data == 0x26 || *data == 0x64 || *data == 0x65) {
462             switch (*data++) {
463               case 0x2E: segover = "cs"; break;
464               case 0x36: segover = "ss"; break;
465               case 0x3E: segover = "ds"; break;
466               case 0x26: segover = "es"; break;
467               case 0x64: segover = "fs"; break;
468               case 0x65: segover = "gs"; break;
469             }
470         } else if (*data == 0x66)
471             osize = 48 - segsize, data++;
472         else if (*data == 0x67)
473             asize = 48 - segsize, data++;
474         else
475             break;
476     }
477
478     ins.oprs[0].segment = ins.oprs[1].segment = ins.oprs[2].segment =
479     ins.oprs[0].addr_size = ins.oprs[1].addr_size = ins.oprs[2].addr_size =
480         (segsize == 16 ? 0 : SEG_32BIT);
481     ins.condition = -1;
482     works = TRUE;
483     for (p = itable[*data]; *p; p++)
484         if ( (length = matches((unsigned char *)((*p)->code), data,
485                                asize, osize, segsize, &ins)) ) {
486             works = TRUE;
487             /*
488              * Final check to make sure the types of r/m match up.
489              */
490             for (i = 0; i < (*p)->operands; i++)
491                 if (((ins.oprs[i].segment & SEG_RMREG) &&
492                      !(MEMORY & ~(*p)->opd[i])) ||
493                     (!(ins.oprs[i].segment & SEG_RMREG) &&
494                      !(REGNORM & ~(*p)->opd[i]) &&
495                      !((*p)->opd[i] & REG_SMASK)))
496                     works = FALSE;
497             if (works)
498                 break;
499         }
500     if (!length || !works)
501         return 0;                      /* no instruction was matched */
502
503     slen = 0;
504
505     if (rep) {
506         slen += sprintf(output+slen, "rep%s ",
507                         (rep == 0xF2 ? "ne" :
508                          (*p)->opcode == I_CMPSB ||
509                          (*p)->opcode == I_CMPSW ||
510                          (*p)->opcode == I_CMPSD ||
511                          (*p)->opcode == I_SCASB ||
512                          (*p)->opcode == I_SCASW ||
513                          (*p)->opcode == I_SCASD ? "e" : ""));
514     }
515     if (lock)
516         slen += sprintf(output+slen, "lock ");
517     for (i = 0; i < ins.nprefix; i++)
518         switch (ins.prefixes[i]) {
519           case P_A16: slen += sprintf(output+slen, "a16 "); break;
520           case P_A32: slen += sprintf(output+slen, "a32 "); break;
521           case P_O16: slen += sprintf(output+slen, "o16 "); break;
522           case P_O32: slen += sprintf(output+slen, "o32 "); break;
523         }
524
525     for (i = 0; i < elements(ico); i++)
526         if ((*p)->opcode == ico[i]) {
527             slen += sprintf(output+slen, "%s%s", icn[i],
528                             whichcond(ins.condition));
529             break;
530         }
531     if (i >= elements(ico))
532         slen += sprintf(output+slen, "%s", insn_names[(*p)->opcode]);
533     colon = FALSE;
534     length += data - origdata;         /* fix up for prefixes */
535     for (i=0; i<(*p)->operands; i++) {
536         output[slen++] = (colon ? ':' : i==0 ? ' ' : ',');
537
538         if (ins.oprs[i].segment & SEG_RELATIVE) {
539             ins.oprs[i].offset += offset + length;
540             /*
541              * sort out wraparound
542              */
543             if (!(ins.oprs[i].segment & SEG_32BIT))
544                 ins.oprs[i].offset &= 0xFFFF;
545             /*
546              * add sync marker, if autosync is on
547              */
548             if (autosync)
549                 add_sync (ins.oprs[i].offset, 0L);
550         }
551
552         if ((*p)->opd[i] & COLON)
553             colon = TRUE;
554         else
555             colon = FALSE;
556
557         if (((*p)->opd[i] & (REGISTER | FPUREG)) ||
558             (ins.oprs[i].segment & SEG_RMREG)) {
559             ins.oprs[i].basereg = whichreg ((*p)->opd[i],
560                                             ins.oprs[i].basereg);
561             slen += sprintf(output+slen, "%s",
562                             reg_names[ins.oprs[i].basereg]);
563         } else if (!(UNITY & ~(*p)->opd[i])) {
564             output[slen++] = '1';
565         } else if ( (*p)->opd[i] & IMMEDIATE ) {
566             if ( (*p)->opd[i] & BITS8 ) {
567                 slen += sprintf(output+slen, "byte ");
568                 if (ins.oprs[i].segment & SEG_SIGNED) {
569                     if (ins.oprs[i].offset < 0) {
570                         ins.oprs[i].offset *= -1;
571                         output[slen++] = '-';
572                     } else
573                         output[slen++] = '+';
574                 }
575             } else if ( (*p)->opd[i] & BITS16 ) {
576                 slen += sprintf(output+slen, "word ");
577             } else if ( (*p)->opd[i] & BITS32 ) {
578                 slen += sprintf(output+slen, "dword ");
579             } else if ( (*p)->opd[i] & NEAR ) {
580                 slen += sprintf(output+slen, "near ");
581             } else if ( (*p)->opd[i] & SHORT ) {
582                 slen += sprintf(output+slen, "short ");
583             }
584             slen += sprintf(output+slen, "0x%lx", ins.oprs[i].offset);
585         } else if ( !(MEM_OFFS & ~(*p)->opd[i]) ) {
586             slen += sprintf(output+slen, "[%s%s%s0x%lx]",
587                             (segover ? segover : ""),
588                             (segover ? ":" : ""),
589                             (ins.oprs[i].addr_size == 32 ? "dword " :
590                              ins.oprs[i].addr_size == 16 ? "word " : ""),
591                             ins.oprs[i].offset);
592             segover = NULL;
593         } else if ( !(REGMEM & ~(*p)->opd[i]) ) {
594             int started = FALSE;
595             if ( (*p)->opd[i] & BITS8 )
596                 slen += sprintf(output+slen, "byte ");
597             if ( (*p)->opd[i] & BITS16 )
598                 slen += sprintf(output+slen, "word ");
599             if ( (*p)->opd[i] & BITS32 )
600                 slen += sprintf(output+slen, "dword ");
601             if ( (*p)->opd[i] & BITS64 )
602                 slen += sprintf(output+slen, "qword ");
603             if ( (*p)->opd[i] & BITS80 )
604                 slen += sprintf(output+slen, "tword ");
605             if ( (*p)->opd[i] & FAR )
606                 slen += sprintf(output+slen, "far ");
607             if ( (*p)->opd[i] & NEAR )
608                 slen += sprintf(output+slen, "near ");
609             output[slen++] = '[';
610             if (ins.oprs[i].addr_size)
611                 slen += sprintf(output+slen, "%s",
612                                 (ins.oprs[i].addr_size == 32 ? "dword " :
613                                  ins.oprs[i].addr_size == 16 ? "word " : ""));
614             if (segover) {
615                 slen += sprintf(output+slen, "%s:", segover);
616                 segover = NULL;
617             }
618             if (ins.oprs[i].basereg != -1) {
619                 slen += sprintf(output+slen, "%s",
620                                 reg_names[ins.oprs[i].basereg]);
621                 started = TRUE;
622             }
623             if (ins.oprs[i].indexreg != -1) {
624                 if (started)
625                     output[slen++] = '+';
626                 slen += sprintf(output+slen, "%s",
627                                 reg_names[ins.oprs[i].indexreg]);
628                 if (ins.oprs[i].scale > 1)
629                     slen += sprintf(output+slen, "*%d", ins.oprs[i].scale);
630                 started = TRUE;
631             }
632             if (ins.oprs[i].segment & SEG_DISP8) {
633                 int sign = '+';
634                 if (ins.oprs[i].offset & 0x80) {
635                     ins.oprs[i].offset = - (signed char) ins.oprs[i].offset;
636                     sign = '-';
637                 }
638                 slen += sprintf(output+slen, "%c0x%lx", sign,
639                                 ins.oprs[i].offset);
640             } else if (ins.oprs[i].segment & SEG_DISP16) {
641                 if (started)
642                     output[slen++] = '+';
643                 slen += sprintf(output+slen, "0x%lx", ins.oprs[i].offset);
644             } else if (ins.oprs[i].segment & SEG_DISP32) {
645                 if (started)
646                     output[slen++] = '+';
647                 slen += sprintf(output+slen, "0x%lx", ins.oprs[i].offset);
648             }
649             output[slen++] = ']';
650         } else {
651             slen += sprintf(output+slen, "<operand%d>", i);
652         }
653     }
654     output[slen] = '\0';
655     if (segover) {                     /* unused segment override */
656         char *p = output;
657         int count = slen+1;
658         while (count--)
659             p[count+3] = p[count];
660         strncpy (output, segover, 2);
661         output[2] = ' ';
662     }
663     return length;
664 }
665
666 long eatbyte (unsigned char *data, char *output) {
667     sprintf(output, "db 0x%02X", *data);
668     return 1;
669 }