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