home *** CD-ROM | disk | FTP | other *** search
- /*
- * Xenix disassembly program by P.Garbha (pgd@compuram.bbt.se)
- *
- * 80386 instruction printer by Pace Willisson (pace@prep.ai.mit.edu)
- * July 1988
- * Copyright (C) 1988 Free Software Foundation, Inc.
- */
-
-
- #include <stdio.h>
- #include <ctype.h>
- #include <a.out.h>
- #include <sys/relsym.h>
- #include <string.h>
-
- #include "386opcodes.h"
-
- #define MAXSEG 20
- #define THRESHOLD 0x100
-
- static int prefixes;
-
- static char obuf[100];
- static char *obufp;
- static char scratchbuf[1000];
- static unsigned char *start_codep;
- static unsigned char *codep;
- static int mod;
- static int rm;
- static int reg;
-
- struct xexec xoutx;
- struct xext xoutxe;
- struct xseg xoutxs[MAXSEG];
- struct {
- short signature;
- short lengthb; /* length of file, lsb */
- short lengthp; /* length of file in 512-byte pages */
- short relitems; /* number of relocation table items */
- short hdrsize; /* size of header in 16-byte paragraphs */
- short maxparas1;
- short maxparas2;
- short stackoff; /* Offset of stack segment in load module */
- short initsp; /* Initial sp */
- short checksum; /* Word checksum */
- short initip; /* Initial ip */
- short csoff; /* Offset of code segment */
- short reloff; /* Offset of the first relocation item */
- short ovlno; /* Overlay number */
- } exehdr;
-
- int segcount = 0;
- struct xseg *textsegp = 0, *datasegp = 0, *symsegp = 0;
- int textseg = -1, dataseg = -1;
- unsigned char *textp, *datap, *xtextp;
-
- int textsize, datasize, database;
-
- struct symtab {
- char *symstring;
- unsigned int symval;
- short symrefcount;
- short symflags;
- };
-
- #define TEXTSEG 0000001
- #define DATASEG 0000002
- #define GENERATED 0000004
- #define BYTEREF 0000010
- #define WORDREF 0000020
- #define DWORDREF 0000040
- #define JUMPREF 0000100
- #define CALLREF 0000200
- #define DEFINED 0000400
- #define PUSHLIMMED 0001000
- #define ASCIZ 0002000
- #define ADDRREF 0004000
-
- #define NOENTER 0100000
-
- struct symtab *lookup(), *enter();
- char *symname(), *getimmed(), *datasymbol(), *ascizdata();
-
- #define SYMHS 20033
- struct symtab *symhash[SYMHS];
- int symcount = 0;
-
- int pass2 = 0;
-
- init()
- {
- register int i;
-
- for (i = 0; i < SYMHS; i++) {
- symhash[i] = NULL;
- }
- }
-
- main(argc, argv)
- char **argv;
- {
- init();
- if (argc < 2) fatal("No input file");
- loadaout(argv[1]);
- dopass1();
- symtabpass();
- dopass2();
- dodata();
- exit(0);
- }
-
- dopass1()
- {
- int ipc;
- char buf[200];
- int len;
-
- ipc = 0;
- while (ipc < textsize) {
- len = i386dis(ipc, textp+ipc, buf);
- ipc += len;
- }
- }
-
- dopass2()
- {
- int ipc;
- int oipc = 0;
- char buf[200];
- int len;
- register struct symtab *lbp;
- int i, mode;
- int unreachable = 0, firsttime = 0;
-
- pass2 = 1;
- ipc = 0;
- while (ipc < textsize) {
- if (textp != xtextp) abort();
- lbp = lookup(ipc, TEXTSEG);
- if (lbp && lbp->symrefcount == 1 && lbp->symflags & (WORDREF|DWORDREF) && !(lbp->symflags & (CALLREF|JUMPREF))) {
- mode = lbp->symflags;
- printf("%s:\t\t; %0x (%d)\n", symname(lbp), ipc, lbp->symrefcount);
- for (;;) {
- register unsigned int addr;
- register struct symtab *symp;
- codep = textp+ipc;
- addr = *(unsigned int *)codep;
- symp = lookup(addr, TEXTSEG|JUMPREF);
- if (symp)
- printf("\t.dword\t%s\n", symname(symp));
- else
- printf("\t.dword\t%#x\n", addr);
- len = 4;
- ++ipc;
- for (i = 1; i < len; i++) {
- if (lbp = lookup(ipc, TEXTSEG)) {
- /*
- * This is a hack, just to
- * void breaking a jump table
- * by a garbage label.
- * We assume no code segment
- * starts with the 0 opcode
- */
- if (textp[ipc] < 0xf) {
- ipc++;
- continue;
- }
- printf("Code overlapping, backing up\n");
- oipc = ipc + len;
- break;
- }
- ipc++;
- }
- if (i < len || i == len && lookup(ipc, TEXTSEG))
- break;
- }
- } else {
- register int opcode;
-
- opcode = *(textp+ipc);
- if (lbp) {
- printf("%s:\t\t; %0x (%d)\n", symname(lbp), ipc, lbp->symrefcount);
- unreachable = 0;
- }
- if (unreachable && opcode == 0) {
- printf("\t.byte\t0\t\t; unreachable");
- len = 1;
- } else if (unreachable && opcode == 0x90) {
- printf("\tnop\t\t\t; unreachable");
- len = 1;
- } else {
- if (unreachable && firsttime) {
- printf("Warning: Unreachable code\n");
- firsttime = 0;
- }
- len = i386dis(ipc, textp+ipc, buf);
- putchar('\t');
- fputs(buf, stdout);
- }
- /*
- * Check for moving into unreachable code
- */
- if (opcode==0xeb||opcode==0xe9||opcode==0xc3||opcode==0xc2||opcode==0xa||opcode==0xcb) {
- unreachable = firsttime = 1;
- }
- /* printf("\t\t; %#x", *start_codep); */
- putchar('\n');
- ++ipc;
- for (i = 1; i < len; i++) {
- register struct symtab *symp;
- if (symp = lookup(ipc, TEXTSEG)) {
- if (unreachable) {
- printf("Code overlapping, backing up\n");
- break;
- }
- printf("Warning: Hidden label: %s\n", symname(symp));
- }
- ipc++;
- }
- }
- }
- }
-
- /*
- * Print out data area
- */
- dodata()
- {
- int dpc;
- register struct symtab *lbp;
- register int c;
-
- dpc = 0;
- while (dpc < datasize) {
- lbp = lookup(dpc+database, DATASEG);
- while (lbp && (lbp->symflags & ASCIZ)) {
- for (;;) {
- dpc++;
- if (dpc >= datasize)
- return;
- if (lbp = lookup(dpc+database, DATASEG))
- break;
- }
- }
- if (lbp) {
- printf("%s:\t\t; %0x (%d)", symname(lbp), dpc+database, lbp->symrefcount);
- if (lbp->symflags & BYTEREF) printf(" BYTE ");
- if (lbp->symflags & WORDREF) printf(" WORD ");
- if (lbp->symflags & DWORDREF) printf(" DWORD ");
- if (lbp->symflags & ASCIZ) printf(" ASCIZ ");
- if (lbp->symflags & ADDRREF) printf(" ADDR ");
- putchar('\n');
- }
- if (!pass2) {
- dpc++;
- continue;
- }
-
- switch (lbp ? lbp->symflags & (BYTEREF|WORDREF|DWORDREF|ADDRREF) : BYTEREF) {
- case BYTEREF:
- default:
- deflt:
- c = datap[dpc];
- printf("\t.byte\t%#x\t;", c);
- if (c>=' ' && c < 127)
- printf("'%c'", c);
- else
- printf(" ");
- printf(" %#x\n", dpc /*+database */);
- dpc++;
- break;
-
- case WORDREF:
- if (dpc+1 < datasize
- && !lookup(dpc+database+1, DATASEG)) {
- printf("\t.word\t%#x\t; %d\t%#x\n",
- *((unsigned short *)(datap+dpc)), dpc);
- dpc += 2;
- break;
- }
- goto deflt;
-
- case DWORDREF:
- if (dpc+3 < datasize
- && !lookup(dpc+database+1, DATASEG)
- && !lookup(dpc+database+2, DATASEG)
- && !lookup(dpc+database+3, DATASEG)) {
- printf("\t.dword\t%#x\t; %d\t%#x\n",
- *((unsigned long *)(datap+dpc)), dpc);
- dpc += 4;
- break;
- }
- goto deflt;
- }
- }
-
- }
-
- ckprefix ()
- {
- prefixes = 0;
- while (1) {
- switch (*codep) {
- case 0xf3:
- prefixes |= PREFIX_REPZ;
- break;
- case 0xf2:
- prefixes |= PREFIX_REPNZ;
- break;
- case 0xf0:
- prefixes |= PREFIX_LOCK;
- break;
- case 0x2e:
- prefixes |= PREFIX_CS;
- break;
- case 0x36:
- prefixes |= PREFIX_SS;
- break;
- case 0x3e:
- prefixes |= PREFIX_DS;
- break;
- case 0x26:
- prefixes |= PREFIX_ES;
- break;
- case 0x64:
- prefixes |= PREFIX_FS;
- break;
- case 0x65:
- prefixes |= PREFIX_GS;
- break;
- case 0x66:
- prefixes |= PREFIX_DATA;
- break;
- case 0x67:
- prefixes |= PREFIX_ADR;
- break;
- case 0x9b:
- prefixes |= PREFIX_FWAIT;
- break;
- default:
- return;
- }
- codep++;
- }
- }
-
- static int dflag;
- static int aflag;
- static int Sflag;
-
- static char op1out[100], op2out[100], op3out[100];
- static int start_pc;
-
- /*
- * disassemble the first instruction in 'inbuf'. You have to make
- * sure all of the bytes of the instruction are filled in.
- * On the 386's of 1988, the maximum length of an instruction is 15 bytes.
- * (see topic "Redundant prefixes" in the "Differences from 8086"
- * section of the "Virtual 8086 Mode" chapter.)
- * 'pc' should be the address of this instruction, it will
- * be used to print the target address if this is a relative jump or call
- * 'outbuf' gets filled in with the disassembled instruction. it should
- * be long enough to hold the longest disassembled instruction.
- * 100 bytes is certainly enough, unless symbol printing is added later
- * The function returns the length of this instruction in bytes.
- */
- i386dis (pc, inbuf, outbuf)
- int pc;
- unsigned char *inbuf;
- char *outbuf;
- {
- struct dis386 *dp;
- char *p;
- int i;
- int enter_instruction;
- char *first, *second, *third;
- int needcomma;
-
- obuf[0] = 0;
- op1out[0] = 0;
- op2out[0] = 0;
- op3out[0] = 0;
-
- start_pc = pc;
- start_codep = inbuf;
- codep = inbuf;
-
- ckprefix ();
-
- if (*codep == 0xc8)
- enter_instruction = 1;
- else
- enter_instruction = 0;
-
- obufp = obuf;
-
- if (prefixes & PREFIX_REPZ)
- oappend ("repz ");
- if (prefixes & PREFIX_REPNZ)
- oappend ("repnz ");
- if (prefixes & PREFIX_LOCK)
- oappend ("lock ");
-
- if ((prefixes & PREFIX_FWAIT) && ((*codep < 0xd8) || (*codep > 0xdf))) {
- /* fwait not followed by floating point instruction */
- oappend ("fwait");
- strcpy (outbuf, obuf);
- return (1);
- }
-
- /* these would be initialized to 0 if disassembling for 8086 or 286 */
- dflag = aflag = Sflag = 0;
- if ((xoutx.x_cpu & XC_CPU) == XC_386) {
- dflag = aflag = 1;
- }
-
- if (prefixes & PREFIX_DATA)
- dflag ^= 1;
-
- if (prefixes & PREFIX_ADR) {
- aflag ^= 1;
- oappend ("addr16 ");
- }
-
- if (*codep == 0x0f)
- dp = &dis386_twobyte[*++codep];
- else
- dp = &dis386[*codep];
- codep++;
- mod = (*codep >> 6) & 3;
- reg = (*codep >> 3) & 7;
- rm = *codep & 7;
-
- if (dp->name == NULL && dp->bytemode1 == FLOATCODE) {
- dofloat ();
- } else {
- if (dp->name == NULL)
- dp = &grps[dp->bytemode1][reg];
-
- putop (dp->name);
-
- obufp = op1out;
- if (dp->op1)
- (*dp->op1)(dp->bytemode1);
-
- obufp = op2out;
- if (dp->op2)
- (*dp->op2)(dp->bytemode2);
-
- obufp = op3out;
- if (dp->op3)
- (*dp->op3)(dp->bytemode3);
- }
-
- obufp = obuf + strlen (obuf);
- /* for (i = strlen (obuf); i < 6; i++)
- oappend (" ");
- oappend (" "); */
- oappend ("\t");
-
- /* enter instruction is printed with operands in the
- * same order as the intel book; everything else
- * is printed in reverse order
- */
- if (enter_instruction) {
- first = op1out;
- second = op2out;
- third = op3out;
- } else {
- first = op3out;
- second = op2out;
- third = op1out;
- }
- needcomma = 0;
- if (*first) {
- oappend (first);
- needcomma = 1;
- }
- if (*second) {
- if (needcomma)
- oappend (",");
- oappend (second);
- needcomma = 1;
- }
- if (*third) {
- if (needcomma)
- oappend (",");
- oappend (third);
- }
- strcpy (outbuf, obuf);
- return (codep - inbuf);
- }
-
- #include "387opcodes.h"
-
- dofloat ()
- {
- struct dis386 *dp;
- unsigned char floatop;
-
- floatop = codep[-1];
-
- if (mod != 3) {
- putop (float_mem[(floatop - 0xd8) * 8 + reg]);
- obufp = op1out;
- OP_E (v_mode);
- return;
- }
- codep++;
-
- dp = &float_reg[floatop - 0xd8][reg];
- if (dp->name == NULL) {
- putop (fgrps[dp->bytemode1][rm]);
- /* instruction fnstsw is only one with strange arg */
- if (floatop == 0xdf && *codep == 0xe0)
- strcpy (op1out, "%eax");
- } else {
- putop (dp->name);
- obufp = op1out;
- if (dp->op1)
- (*dp->op1)(dp->bytemode1);
- obufp = op2out;
- if (dp->op2)
- (*dp->op2)(dp->bytemode2);
- }
- }
-
- /* ARGSUSED */
- OP_ST (ignore)
- {
- oappend ("%st");
- }
-
- /* ARGSUSED */
- OP_STi (ignore)
- {
- sprintf (scratchbuf, "%%st(%d)", rm);
- oappend (scratchbuf);
- }
-
-
- /* capital letters in template are macros */
- putop (template)
- char *template;
- {
- char *p;
-
- for (p = template; *p; p++) {
- switch (*p) {
- default:
- *obufp++ = *p;
- break;
- case 'C': /* For jcxz/jecxz */
- if (aflag == 0)
- *obufp++ = 'e';
- break;
- case 'N':
- if ((prefixes & PREFIX_FWAIT) == 0)
- *obufp++ = 'n';
- break;
- case 'S':
- /* operand size flag */
- Sflag = 1;
- if (dflag)
- *obufp++ = 'l';
- else
- *obufp++ = 'w';
- break;
- }
- }
- *obufp = 0;
- }
-
- oappend (s)
- char *s;
- {
- strcpy (obufp, s);
- obufp += strlen (s);
- *obufp = 0;
- }
-
- append_prefix ()
- {
- if (prefixes & PREFIX_CS)
- oappend ("%cs:");
- if (prefixes & PREFIX_DS)
- oappend ("%ds:");
- if (prefixes & PREFIX_SS)
- oappend ("%ss:");
- if (prefixes & PREFIX_ES)
- oappend ("%es:");
- if (prefixes & PREFIX_FS)
- oappend ("%fs:");
- if (prefixes & PREFIX_GS)
- oappend ("%gs:");
- }
-
- OP_indirE (bytemode)
- {
- oappend ("*");
- OP_E (bytemode);
- }
-
- OP_E (bytemode)
- {
- int disp;
- int havesib; /* have "scaled index base" byte */
- int didoutput = 0;
- int base;
- int index;
- int scale;
- int havebase;
-
- /* skip mod/rm byte */
- codep++;
-
- havesib = 0;
- havebase = 0;
- disp = 0;
-
- if (mod == 3) { /* Register mod's */
- switch (bytemode) {
- case b_mode:
- oappend (names8[rm]);
- break;
- case w_mode:
- oappend (names16[rm]);
- break;
- case v_mode:
- if (dflag)
- oappend (names32[rm]);
- else
- oappend (names16[rm]);
- break;
- default:
- oappend ("<bad dis table>");
- break;
- }
- return;
- }
-
- append_prefix();
-
- if (rm == 4 && aflag) {
- havesib = 1;
- havebase = 1;
- scale = (*codep >> 6) & 3;
- index = (*codep >> 3) & 7;
- base = *codep & 7;
- codep++;
- }
-
- if (!aflag && mod < 3) {
- switch (mod) {
- case 0:
- if (rm == 6) {
- disp = get16();
- oappend(datasymbol(disp, WORDREF, 1));
- return;
- }
- break;
-
- case 1:
- sprintf(scratchbuf, "%#x", *codep++);
- oappend(scratchbuf);
- break;
-
- case 2:
- disp = get16();
- oappend(datasymbol(disp, WORDREF, 1));
- break;
- }
-
- switch (rm) {
- case 0: oappend("(%bx,%si)"); return;
- case 1: oappend("(%bx,%di)"); return;
- case 2: oappend("(%bp,%si)"); return;
- case 3: oappend("(%bp,%di)"); return;
- case 4: oappend("(%si)"); return;
- case 5: oappend("(%di)"); return;
- case 6: oappend("(%bp)"); return;
- case 7: oappend("(%bx)"); return;
- }
- }
- switch (mod) {
- case 0:
- switch (rm) {
- case 4: /* DS:[d32+(scaled index)] */
- if (!aflag)
- break;
- /* implies havesib and havebase */
- if (base == 5) {
- havebase = 0;
- disp = get32 ();
- }
- break;
- case 5: /* DS:d32 */
- if (!aflag)
- break;
- disp = get32 ();
- break;
- case 6: /* DS:d16 */
- if (aflag)
- break;
- disp = get16 ();
- break;
- default: /* DS:[Ereg] */
- havebase = 1;
- base = rm;
- break;
- }
- break;
-
- case 1: /* DS:[Ereg+d8] */
- disp = *(char *)codep++;
- if (rm != 4) {
- havebase = 1;
- base = rm;
- }
- break;
-
- case 2: /* DS:[Ereg+d32] */
- if (aflag) {
- disp = get32 ();
- if (rm != 4) {
- havebase = 1;
- base = rm;
- }
- } else {
- disp = get16();
- }
- break;
- }
-
- /* if (mod < 3) { */
- if (havesib) {
- if (mod == 0) {
- if (base == 5) { /* DS:[d32+(scaled index)] */
- if (prefixes & PREFIX_CS) {
- register struct symtab *symp;
- int mode = scale==2 ? WORDREF
- : scale==3 ? DWORDREF
- : 0;
- symp = lookup(disp, TEXTSEG|mode);
- if (pass2)
- if (symp)
- sprintf (scratchbuf, "%s", symname(symp));
- else
- sprintf (scratchbuf, "%s", datasymbol(disp, mode, 1));
- oappend(scratchbuf);
- } else
- oappend(datasymbol(disp, 0, 1));
- }
- } else if (base == 5) { /* SS:[EBP+...] */
- sprintf (scratchbuf, "%d", disp);
- oappend(scratchbuf);
- } else if (base == 4) { /* SS:[ESP+...] */
- sprintf(scratchbuf, "%d", disp);
- oappend(scratchbuf);
- } else { /* DS:[...] */
- if (mod == 1) { /* Byte offset */
- sprintf (scratchbuf, "%d", disp);
- oappend(scratchbuf);
- } else { /* Longword offset */
- oappend(datasymbol(disp, 0, 1));
- }
- }
- } else if (aflag && rm == 5 || /* DS:d32 or SS:[EBP...] */
- !aflag && rm == 6) { /* DS:d16 */
- if (mod == 0) { /* DS:d32 or DS:d16 */
- /* Normal "direct" data address */
- oappend(datasymbol(/* Sflag && !dflag ? disp + database : */ disp,
- bytemode==b_mode ? BYTEREF :
- bytemode==w_mode ? WORDREF :
- Sflag ? dflag ? DWORDREF
- : WORDREF : 0, 1));
- } else {
- sprintf(scratchbuf, "%d", disp);
- oappend(scratchbuf);
- }
- #if 0
- } else if (mod == 2) { /* DS:[ereg+d8] */
- sprintf(scratchbuf, "%d", disp);
- oappend(scratchbuf);
- #endif
- } else { /* DS:[ereg+d32] */
- oappend(datasymbol(disp, 0, 1));
- }
- /* } */
-
- if (havebase || havesib) {
- oappend ("(");
- if (!havebase && !havesib) oappend("????");
- if (havebase)
- oappend ((aflag ? names32 : names16_OP_E)[base]);
- if (havesib) {
- if (index != 4) {
- sprintf (scratchbuf, ",%s", names32[index]);
- oappend (scratchbuf);
- sprintf (scratchbuf, ",%d", 1 << scale);
- oappend (scratchbuf);
- }
- }
- oappend (")");
- }
- }
-
- OP_G (bytemode)
- {
- switch (bytemode) {
- case b_mode:
- oappend (names8[reg]);
- break;
- case w_mode:
- oappend (names16[reg]);
- break;
- case d_mode:
- oappend (names32[reg]);
- break;
- case v_mode:
- if (dflag)
- oappend (names32[reg]);
- else
- oappend (names16[reg]);
- break;
- default:
- oappend ("<internal disassembler error>");
- break;
- }
- }
-
- get32 ()
- {
- int x = 0;
-
- x = *codep++ & 0xff;
- x |= (*codep++ & 0xff) << 8;
- x |= (*codep++ & 0xff) << 16;
- x |= (*codep++ & 0xff) << 24;
- return (x);
- }
-
- get16 ()
- {
- int x = 0;
-
- x = *codep++ & 0xff;
- x |= (*codep++ & 0xff) << 8;
- return (x);
- }
-
- OP_REG (code)
- {
- char *s;
-
- switch (code) {
- case indir_dx_reg:
- s = "(%dx)";
- break;
- case ax_reg:
- case cx_reg:
- case dx_reg:
- case bx_reg:
- case sp_reg:
- case bp_reg:
- case si_reg:
- case di_reg:
- s = names16[code - ax_reg];
- break;
- case es_reg:
- case ss_reg:
- case cs_reg:
- case ds_reg:
- case fs_reg:
- case gs_reg:
- s = names_seg[code - es_reg];
- break;
- case al_reg:
- case ah_reg:
- case cl_reg:
- case ch_reg:
- case dl_reg:
- case dh_reg:
- case bl_reg:
- case bh_reg:
- s = names8[code - al_reg];
- break;
- case eAX_reg:
- case eCX_reg:
- case eDX_reg:
- case eBX_reg:
- case eSP_reg:
- case eBP_reg:
- case eSI_reg:
- case eDI_reg:
- if (dflag)
- s = names32[code - eAX_reg];
- else
- s = names16[code - eAX_reg];
- break;
- default:
- s = "<internal disassembler error>";
- break;
- }
- oappend (s);
- }
-
- OP_I (bytemode)
- {
- int op;
-
- switch (bytemode) {
- case b_mode:
- op = *codep++ & 0xff;
- break;
- case v_mode:
- if (dflag)
- op = get32 ();
- else
- op = get16 ();
- break;
- case w_mode:
- op = get16 ();
- break;
- default:
- oappend ("<internal disassembler error>");
- return;
- }
- oappend (getimmed(op));
- }
-
- OP_sI (bytemode)
- {
- int op;
-
- switch (bytemode) {
- case b_mode:
- op = *(char *)codep++;
- break;
- case v_mode:
- if (dflag)
- op = get32 ();
- else
- op = (short)get16();
- break;
- case w_mode:
- op = (short)get16 ();
- break;
- default:
- oappend ("<internal disassembler error>");
- return;
- }
- oappend (getimmed(op));
- }
-
- /*
- * Jump opcodes
- */
- OP_J (bytemode)
- {
- int disp, addr;
- int mask = -1;
- register struct symtab *symp;
-
- switch (bytemode) {
- case b_mode:
- disp = *(char *)codep++;
- break;
- case v_mode:
- if (dflag)
- disp = get32 ();
- else {
- disp = (short)get16 ();
- /* for some reason, a data16 prefix on a jump instruction
- means that the pc is masked to 16 bits after the
- displacement is added! */
- mask = 0xffff;
- }
- break;
- default:
- oappend ("<internal disassembler error>");
- return;
- }
-
- addr = (start_pc + codep - start_codep + disp) & mask;
- symp = lookup(addr, TEXTSEG|JUMPREF);
- if (pass2) {
- if (symp)
- sprintf (scratchbuf, "%s", symname(symp));
- else
- sprintf (scratchbuf, "%s", datasymbol(addr, 0, 1));
- oappend (scratchbuf);
- }
- }
-
- /* ARGSUSED */
- OP_SEG (dummy)
- {
- static char *sreg[] = {
- "%es","%cs","%ss","%ds","%fs","%gs","%?","%?",
- };
-
- oappend (sreg[reg]);
- }
-
- /*
- * A subroutine address, or a jump/call far destination
- */
- OP_DIR (size)
- {
- int seg, offset, addr;
- register struct symtab *symp;
-
- switch (size) {
- case lptr:
- if (aflag) {
- offset = get32 ();
- seg = get16 ();
- } else {
- offset = get16 ();
- seg = get16 ();
- }
- sprintf (scratchbuf, "0x%x,0x%x", seg, offset);
- oappend (scratchbuf);
- break;
-
- case v_mode: /* Call instruction destination */
- if (aflag)
- offset = get32 ();
- else
- offset = (short)get16 ();
-
- addr = start_pc + codep - start_codep + offset;
- symp = lookup(addr, TEXTSEG|CALLREF);
- if (pass2)
- if (symp)
- oappend(symname(symp));
- else
- oappend(datasymbol(addr, 0, 1));
-
- break;
- default:
- oappend ("<internal disassembler error>");
- break;
- }
- }
-
- /* ARGSUSED */
- OP_OFF (bytemode)
- {
- int off;
-
- if (aflag)
- off = get32 ();
- else
- off = get16 ();
-
- oappend(datasymbol(off, 0, 0));
- }
-
- /* ARGSUSED */
- OP_ESDI (dummy)
- {
- oappend ("%es:(");
- oappend (aflag ? "%edi" : "%di");
- oappend (")");
- }
-
- /* ARGSUSED */
- OP_DSSI (dummy)
- {
- oappend ("%ds:(");
- oappend (aflag ? "%esi" : "%si");
- oappend (")");
- }
-
- /* ARGSUSED */
- OP_ONE (dummy)
- {
- oappend ("1");
- }
-
- /* ARGSUSED */
- OP_C (dummy)
- {
- codep++; /* skip mod/rm */
- sprintf (scratchbuf, "%%cr%d", reg);
- oappend (scratchbuf);
- }
-
- /* ARGSUSED */
- OP_D (dummy)
- {
- codep++; /* skip mod/rm */
- sprintf (scratchbuf, "%%db%d", reg);
- oappend (scratchbuf);
- }
-
- /* ARGSUSED */
- OP_T (dummy)
- {
- codep++; /* skip mod/rm */
- sprintf (scratchbuf, "%%tr%d", reg);
- oappend (scratchbuf);
- }
-
- OP_rm (bytemode)
- {
- switch (bytemode) {
- case d_mode:
- oappend (names32[rm]);
- break;
- case w_mode:
- oappend (names16[rm]);
- break;
- }
- }
-
- /*
- * Load the file to disassemble, into memory
- * Decoding the Xenix a.out header
- */
- loadaout(fname)
- {
- int fd;
- register int i;
- short magic;
-
- fd = open(fname, 0);
- if (fd == 0) {
- perror(fname); exit(1);
- }
- if (read(fd, &magic, 2) != 2) {
- perror(fname); exit(1);
- }
- lseek(fd, 0L, 0);
- if (magic == X_MAGIC) {
- if (read(fd, &xoutx, sizeof xoutx) != sizeof xoutx) {
- perror(fname); exit(1);
- }
- /* if ((xoutx.x_cpu & XC_CPU) != XC_386)
- fatal("Not a 80386 executable file - %s\n", fname); */
- if (read(fd, &xoutxe, sizeof xoutxe) != sizeof xoutxe) {
- perror(fname); exit(1);
- }
- if (!(xoutx.x_renv & XE_SEG))
- fatal("Not a Xenix segmented file - %s\n", fname);
- lseek(fd, xoutxe.xe_segpos, 0);
- segcount = xoutxe.xe_segsize / sizeof(struct xseg);
- if (segcount > MAXSEG)
- fatal("Too many segments (%d)", segcount);
- if (read(fd, xoutxs, segcount * sizeof(struct xseg)) != segcount * sizeof(struct xseg)) {
- perror(fname); exit(1);
- }
- for (i = 0; i < segcount; i++) {
- switch (xoutxs[i].xs_type) {
- case XS_TTEXT:
- if (textsegp) fatal("Multiple text segments");
- textsegp = &xoutxs[i];
- textseg = textsegp->xs_seg;
- break;
-
- case XS_TDATA:
- if (datasegp) fatal("Multiple data segments");
- datasegp = &xoutxs[i];
- dataseg = datasegp->xs_seg;
- break;
-
- case XS_TSYMS:
- if (xoutxs[i].xs_attr != XS_SXSEG)
- continue;
- if (symsegp) fatal("Multiple symbol segments");
- symsegp = &xoutxs[i];
- break;
-
- case XS_TREL:
- break;
- default:
- fatal("Unknown segment: %x", xoutxs[i].xs_type);
- }
- }
- if (textsegp == NULL) fatal("Undefined text segment");
- if (datasegp == NULL) fatal("Undefined data segment");
- if (symsegp != NULL)
- readsymbols(fd);
- textp = (unsigned char *)malloc(textsegp->xs_psize);
- if (textp == NULL) fatal("Out of memory");
- xtextp = textp;
- datap = (unsigned char *)malloc(datasegp->xs_psize);
- if (datap == NULL) fatal("Out of memory");
- lseek(fd, textsegp->xs_filpos, 0);
- if (read(fd, textp, textsegp->xs_psize) != textsegp->xs_psize) {
- perror(fname); fatal("File read error (text segment)");
- }
- lseek(fd, datasegp->xs_filpos, 0);
- if (read(fd, datap, datasegp->xs_psize) != datasegp->xs_psize) {
- perror(fname);
- fatal("File read error (data segment)");
- }
- textsize = textsegp->xs_vsize;
- datasize = datasegp->xs_vsize;
- database = datasegp->xs_rbase;
- } else if (magic == 0x5a4d) {
- /* msdos .exe file */
- if (read(fd, &exehdr, sizeof exehdr) != sizeof exehdr) {
- perror(fname); exit(1);
- }
- datasize = exehdr.csoff * 16;
- textsize = exehdr.lengthp * 512 - datasize - exehdr.hdrsize*16;
- if (exehdr.lengthb)
- textsize += exehdr.lengthb - 512;
- database = 0;
- textp = (unsigned char *)malloc(textsize);
- if (textp == NULL) fatal("Out of memory");
- xtextp = textp;
- datap = (unsigned char *)malloc(datasize);
- if (datap == NULL) fatal("Out of memory");
- lseek(fd, exehdr.hdrsize * 16, 0);
- if (read(fd, datap, datasize) != datasize) {
- perror(fname);
- fatal("File read error (data segment)");
- }
- if (read(fd, textp, textsize) != textsize) {
- perror(fname); fatal("File read error (text segment)");
- }
- } else
- fatal("Not a recognized executable file - %s\n", fname);
- close(fd);
- }
-
- readsymbols(fd)
- {
- register char *symp;
- char *symendp;
- int type, seg, value;
- char *name;
- int i;
-
- symp = (char *)malloc(symsegp->xs_psize);
- if (symp == NULL) fatal("Out of memory");
- lseek(fd, symsegp->xs_filpos, 0);
- if ((i = read(fd, symp, symsegp->xs_psize)) != symsegp->xs_psize)
- fatal("Symbol Table read error");
- symendp = symp + symsegp->xs_psize;
- while (symp < symendp) {
- type = ((struct sym *)symp)->s_type;
- seg = ((struct sym *)symp)->s_seg;
- value = ((struct sym *)symp)->s_value;
- name = symp + sizeof(struct sym);
- symp += sizeof(struct sym) + strlen(name) + 1;
- if (seg == textseg)
- enter(name, value, TEXTSEG|DEFINED);
- else if (seg == dataseg)
- enter(name, value, DATASEG|DEFINED);
- }
- }
-
- fatal(f, args)
- {
- vfprintf(stderr, f, &args);
- fprintf(stderr, "\n");
- exit(1);
- }
-
- /*
- * Look up a symbol in symboltable.
- * Enter it as undefined if not
- * already there.
- */
- struct symtab *lookup(addr, ref)
- unsigned int addr;
- {
- register struct symtab *symtp,**symhp;
- int seg = ref & (TEXTSEG|DATASEG);
-
- symhp = &symhash[addr % SYMHS];
- while (symtp = *symhp) {
- if (addr == symtp->symval && (seg & symtp->symflags)) {
- if (!pass2) {
- symtp->symflags |= ref;
- symtp->symrefcount++;
- }
- return symtp;
- }
- if ((++symhp) >= &symhash[SYMHS])
- symhp = symhash;
- }
- if (pass2 || ref & NOENTER || !aflag && addr < THRESHOLD)
- return NULL;
- symtp = enter(NULL, addr, ref|GENERATED);
- symtp->symrefcount++;
- return symtp;
- }
-
- /*
- * enter a symbol into symboltable.
- */
- struct symtab *enter(id, addr, ref)
- char *id;
- unsigned addr;
- {
- register struct symtab *symtp, **symhp, **osymhp;
- int seg = ref & (DATASEG|TEXTSEG);
-
- symcount++;
- osymhp = symhp = &symhash[addr % SYMHS];
- while (symtp = *symhp) {
- if (++symhp >= &symhash[SYMHS])
- symhp = symhash;
- if (symhp == osymhp)
- fatal("Symbol table overflow");
- if (addr == symtp->symval && (seg & symtp->symflags))
- return symtp;
- /* fprintf(stderr, "Multiple definitions of symbol %s addr=%x, seg=%d, ref=%d\n", id ? id : "", addr, seg, ref); */
- }
- symtp = (struct symtab *)malloc(sizeof(struct symtab));
- *symhp = symtp;
- symtp->symflags = ref;
- symtp->symval = addr;
- symtp->symrefcount = 0;
- if (id)
- symtp->symstring = strdup(id);
- else {
- symtp->symstring = NULL;
- symtp->symflags |= GENERATED;
- }
- return symtp;
- }
-
- char *
- symname(symp)
- struct symtab *symp;
- {
- static char id[20];
-
- if (symp->symstring)
- return symp->symstring;
- sprintf(id, "%s0%x", symp->symflags & TEXTSEG ?
- (symp->symflags & CALLREF ? "P_" : "L") :
- symp->symflags & DATASEG ? "D" : "X", symp->symval);
- return id;
- }
-
- char *
- getimmed(val)
- unsigned int val;
- {
- static char scratch[20];
- register struct symtab *symp;
-
- if (*start_codep == 0x68)
- sprintf(scratch, "$%s", datasymbol(val, PUSHLIMMED, 0));
- else
- sprintf(scratch, "$%s", datasymbol(val, 0, 0));
- return scratch;
- }
-
-
- char *
- datasymbol(addr, ref, hexdef)
- unsigned int addr;
- {
- register struct symtab *symp;
- static char scratch[20];
-
- if (addr == 0) {
- return "0";
- }
- if (addr >= database && addr < database + xoutx.x_data + xoutx.x_bss) {
- symp = lookup(addr, DATASEG|ref);
- if (pass2) {
- if (symp != NULL) {
- if (symp->symflags & ASCIZ)
- return ascizdata(addr);
- if (symp->symstring)
- return symp->symstring;
- }
- sprintf(scratch, "D_0%x", addr);
- return scratch;
- }
- }
- if (addr < 10 /* || !hexdef */)
- sprintf(scratch, "%d", addr);
- else
- sprintf(scratch, "%#x", addr);
- return scratch;
- }
-
- scomp(syp1, syp2)
- register struct symtab **syp1, **syp2;
- {
- if ((*syp1)->symval < (*syp2)->symval)
- return -1;
- else if ((*syp1)->symval > (*syp2)->symval)
- return 1;
- return 0;
- }
-
- symtabpass()
- {
- struct symtab *symarr[SYMHS];
- register int i, j;
- int labno;
- register struct symtab *symp;
- char id[20];
- int syc;
-
- /*
- * Look for "case" jump tables
- */
- for (i = 0; i < SYMHS; i++) {
- if ((symp = symhash[i]) && symp->symrefcount == 1 && symp->symflags & (WORDREF|DWORDREF) && !(symp->symflags & (CALLREF|JUMPREF))) {
- unsigned int addr = symp->symval;
- unsigned int disp;
- register struct symtab *labp;
- while (addr < textsize) {
- register int j;
- for (j = 1; j < 4; j++)
- if (lookup(addr+j, NOENTER))
- goto bloop;
- disp = *(unsigned int *)(textp+addr);
- if (disp > 0 && disp < textsize)
- labp = lookup(disp, TEXTSEG|JUMPREF);
- addr += 4;
- }
- bloop: ;
- }
- }
-
- syc = 0;
- for (i = 0; i < SYMHS; i++)
- if (symarr[syc] = symhash[i])
- syc++;
- qsort(symarr, syc, sizeof(struct symtab *), scomp);
- printf("%d symbols defined\n", syc);
-
- /*
- * Assign label names for code labels
- */
- labno = 0;
- for (i = 0; i < syc; i++) {
- if ((symp = symarr[i]) && symp->symstring == NULL
- && symp->symflags & TEXTSEG) {
-
- sprintf(id, "L%d", ++labno);
- symp->symstring = strdup(id);
- }
- }
-
- /*
- * Look for asciz strings
- */
- for (i = 0; i < syc; i++) {
- unsigned addr1, addr2;
- if ((symp = symarr[i]) == NULL)
- continue;
- if (symp->symflags & DATASEG && symp->symflags & PUSHLIMMED
- && symp->symrefcount == 1) {
- for (j = i+1; j < syc; j++)
- if (symarr[j] && symarr[j]->symflags & DATASEG)
- break;
- if (j == syc)
- break;
- addr1 = symp->symval;
- addr2 = symarr[j]->symval;
- if (addr2 > database + xoutx.x_data
- || addr1 < database)
- continue;
- for (j = addr1; j < addr2; j++)
- if (datap[j - database] == '\0')
- break;
- dummy();
- if (j < addr2 && ((j + 4) & ~3) == addr2)
- /* if (j == addr2-1 || j == addr2-2 || j == addr2-3) */
- symarr[i]->symflags |= ASCIZ;
-
- }
- }
-
- /*
- * Assign label names for data labels
- */
- labno = 0;
- for (i = 0; i < syc; i++) {
- if ((symp = symarr[i]) && symp->symstring == NULL
- && symp->symflags & DATASEG) {
-
- sprintf(id, "D%d", ++labno);
- symp->symstring = strdup(id);
- }
- }
- }
-
- dummy() {}
-
- char *
- ascizdata(addr)
- {
- register unsigned char *cp1 = datap + addr - database;
- static char buf[1000];
- register unsigned char *cp2 = buf;
- register c;
-
- *cp2++ = '"';
- while (c = *cp1++) {
- switch (c) {
- case '\n': *cp2++ = '\\'; *cp2++ = 'n'; break;
- case '\t': *cp2++ = '\\'; *cp2++ = 't'; break;
- case '\r': *cp2++ = '\\'; *cp2++ = 'r'; break;
- default:
- if (c >= ' ' && c < 127)
- *cp2++ = c;
- else {
- *cp2++ = '\\';
- if (c & 0300) *cp2++ = (c >> 6) + '0';
- if (c & 0070) *cp2++ = ((c >> 3) & 7) + '0';
- *cp2++ = (c & 7) + '\0';
- }
- }
- if (cp2 >= buf+sizeof(buf)-2)
- fatal("Too long asciz string");
- }
- *cp2++ = '"';
- *cp2++ = '\0';
- return buf;
- }
-