[comp.os.minix] dis88 part 1 of 2

ast@cs.vu.nl (Andy Tanenbaum) (10/06/88)

: This is a shar archive.  Extract with sh, not csh.
: This archive ends with exit, so do not worry about trailing junk.
: --------------------------- cut here --------------------------
PATH=/bin:/usr/bin:/usr/ucb
echo Extracting 'dis.h'
sed 's/^X//' > 'dis.h' << '+ END-OF-FILE ''dis.h'
X /*
X ** @(#) dis.h, Ver. 2.1 created 00:00:00 87/09/01
X */
X
X /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
X  *                                                         *
X  *  Copyright (C) 1987 G. M. Harding, all rights reserved  *
X  *                                                         *
X  * Permission to copy and  redistribute is hereby granted, *
X  * provided full source code,  with all copyright notices, *
X  * accompanies any redistribution.                         *
X  *                                                         *
X  * This file contains declarations and definitions used by *
X  * the 8088 disassembler program. The program was designed *
X  * for execution on a machine of its own type (i.e., it is *
X  * not designed as a cross-disassembler);  consequently, A *
X  * SIXTEEN-BIT INTEGER SIZE HAS BEEN ASSUMED. This assump- *
X  * tion is not particularly important,  however, except in *
X  * the machine-specific  portions of the code  (i.e.,  the *
X  * handler  routines and the optab[] array).  It should be *
X  * possible to override this assumption,  for execution on *
X  * 32-bit machines,  by use of a  pre-processor  directive *
X  * (see below); however, this has not been tested.         *
X  *                                                         *
X  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
X
X#include <stdio.h>      /* System standard I/O definitions  */
X
X/* fcntl.h not used in MINIX */
X/* #include <fcntl.h>      /* System file-control definitions  */
X
X#include <a.out.h>      /* Object file format definitions   */
X
X#if i8086 || i8088      /* For CPU's with 16-bit integers   */
X#undef int
X#else                   /* Defaults (for 32-bit CPU types)  */
X#define int short
X#endif
X
X#define MAXSYM 1500     /* Maximum entries in symbol table  */
X
Xextern struct nlist     /* Array to hold the symbol table   */
X   symtab[MAXSYM];
X
Xextern struct reloc     /* Array to hold relocation table   */
X   relo[MAXSYM];
X
Xextern int symptr;      /* Index into the symtab[] array    */
X
Xextern int relptr;      /* Index into the relo[] array      */
X
Xstruct opcode           /* Format for opcode data records   */
X   {
X   char     *text;            /* Pointer to mnemonic text   */
X   void     (*func)();        /* Pointer to handler routine */
X   unsigned min;              /* Minimum # of object bytes  */
X   unsigned max;              /* Maximum # of object bytes  */
X   };
X
Xextern struct opcode    /* Array to hold the opcode table   */
X  optab[256];
X
X /*
X   +---------------------------------------------
X   | The following  functions are the specialized
X   | handlers for each opcode group. They are, of
X   | course, highly MACHINE-SPECIFIC.  Each entry
X   | in the opcode[]  array contains a pointer to
X   | one of these  handlers.  The handlers in the
X   | first group are in  dishand.c;  those in the
X   | second group are in disfp.c.
X   +---------------------------------------------
X */
X
Xextern void dfhand(),   /* Default handler routine          */
X            sbhand(),   /* Single-byte handler              */
X            aohand(),   /* Arithmetic-op handler            */
X            sjhand(),   /* Short-jump handler               */
X            imhand(),   /* Immediate-operand handler        */
X            mvhand(),   /* Simple move handler              */
X            mshand(),   /* Segreg-move handler              */
X            pohand(),   /* Pop memory/reg handler           */
X            cihand(),   /* Intersegment call handler        */
X            mihand(),   /* Immediate-move handler           */
X            mqhand(),   /* Quick-move handler               */
X            tqhand(),   /* Quick-test handler               */
X            rehand(),   /* Return handler                   */
X            mmhand(),   /* Move-to-memory handler           */
X            srhand(),   /* Shift and rotate handler         */
X            aahand(),   /* ASCII-adjust handler             */
X            iohand(),   /* Immediate port I/O handler       */
X            ljhand(),   /* Long-jump handler                */
X            mahand(),   /* Misc. arithmetic handler         */
X            mjhand();   /* Miscellaneous jump handler       */
X
Xextern void eshand(),   /* Bus-escape opcode handler        */
X            fphand(),   /* Floating-point handler           */
X            inhand();   /* Interrupt-opcode handler         */
X
Xextern char *REGS[];    /* Table of register names          */
X
Xextern char *REGS0[];   /* Mode 0 register name table       */
X
Xextern char *REGS1[];   /* Mode 1 register name table       */
X
X#define AL REGS[0]      /* CPU register manifests           */
X#define CL REGS[1]
X#define DL REGS[2]
X#define BL REGS[3]
X#define AH REGS[4]
X#define CH REGS[5]
X#define DH REGS[6]
X#define BH REGS[7]
X#define AX REGS[8]
X#define CX REGS[9]
X#define DX REGS[10]
X#define BX REGS[11]
X#define SP REGS[12]
X#define BP REGS[13]
X#define SI REGS[14]
X#define DI REGS[15]
X#define ES REGS[16]
X#define CS REGS[17]
X#define SS REGS[18]
X#define DS REGS[19]
X#define BX_SI REGS0[0]
X#define BX_DI REGS0[1]
X#define BP_SI REGS0[2]
X#define BP_DI REGS0[3]
X
Xextern int symrank[6][6];     /* Symbol type/rank matrix    */
X
Xextern unsigned long PC;      /* Current program counter    */
X
Xextern int segflg;      /* Flag: segment override in effect */
X
Xextern int objflg;      /* Flag: output object as a comment */
X
X#define OBJMAX 8        /* Size of the object code buffer   */
X
Xextern unsigned char    /* Internal buffer for object code  */
X   objbuf[OBJMAX];
X
Xextern void objini(),   /* Object-buffer init routine       */
X            objout();   /* Object-code output routine       */
X
Xextern int objptr;      /* Index into the objbuf[] array    */
X
Xextern void badseq();   /* Bad-code-sequence function       */
X
Xextern char *getnam();  /* Symbol-name string function      */
X
Xextern char *lookup();  /* Symbol-table lookup function     */
X
Xextern int lookext();   /* Extern-definition lookup routine */
X
Xextern char *mtrans();  /* Interpreter for the mode byte    */
X
Xextern void mtrunc();   /* Mode string truncator function   */
X
Xextern char ADD[],      /* Opcode family mnemonic strings   */
X            OR[],
X            ADC[],
X            SBB[],
X            AND[],
X            SUB[],
X            XOR[],
X            CMP[],
X            NOT[],
X            NEG[],
X            MUL[],
X            DIV[],
X            MOV[],
X            ESC[],
X            TEST[],
X            AMBIG[];
X
Xextern char *OPFAM[];   /* Indexed mnemonic family table    */
X
Xextern struct exec HDR; /* Holds the object file's header   */
X
X#define LOOK_ABS 0      /* Arguments to lookup() function   */
X#define LOOK_REL 1
X#define LOOK_LNG 2
X
X#define TR_STD 0        /* Arguments to mtrans() function   */
X#define TR_SEG 8
X
X                        /* Macro for byte input primitive   */
X#define FETCH(p) \
X   ++PC; p = getchar() & 0xff; objbuf[objptr++] = p
X
Xextern int close();     /* System file-close primitive      */
Xextern int fprintf();   /* Library file-output function     */
Xextern long lseek();    /* System file-position primitive   */
Xextern int open();      /* System file-open primitive       */
Xextern int printf();    /* Library output-format function   */
Xextern int read();      /* System file-read primitive       */
Xextern int sprintf();   /* Library string-output function   */
Xextern char *strcat();  /* Library string-join function     */
Xextern char *strcpy();  /* Library string-copy function     */
Xextern int strlen();    /* Library string-length function   */
X
X /* * * * * * * * * * *  END OF  dis.h  * * * * * * * * * * */
X
X
+ END-OF-FILE dis.h
chmod 'u=rw,g=r,o=r' 'dis.h'
set `wc -c 'dis.h'`
count=$1
case $count in
7600)	:;;
*)	echo 'Bad character count in ''dis.h' >&2
		echo 'Count should be 7600' >&2
esac
echo Extracting 'disfp.c'
sed 's/^X//' > 'disfp.c' << '+ END-OF-FILE ''disfp.c'
Xstatic char *sccsid =
X   "@(#) disfp.c, Ver. 2.1 created 00:00:00 87/09/01";
X
X /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
X  *                                                         *
X  *  Copyright (C) 1987 G. M. Harding, all rights reserved  *
X  *                                                         *
X  * Permission to copy and  redistribute is hereby granted, *
X  * provided full source code,  with all copyright notices, *
X  * accompanies any redistribution.                         *
X  *                                                         *
X  * This file contains handler routines for the numeric op- *
X  * codes of the 8087 co-processor,  as well as a few other *
X  * opcodes which are related to 8087 emulation.            *
X  *                                                         *
X  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
X
X#include "dis.h"              /* Disassembler declarations  */
X
X#define FPINT0 0xd8           /* Floating-point interrupts  */
X#define FPINT1 0xd9
X#define FPINT2 0xda
X#define FPINT3 0xdb
X#define FPINT4 0xdc
X#define FPINT5 0xdd
X#define FPINT6 0xde
X#define FPINT7 0xdf
X
X                              /* Test for floating opcodes  */
X#define ISFLOP(x) \
X   (((x) >= FPINT0) && ((x) <= FPINT7))
X
X /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
X  *                                                         *
X  * This is the  handler for the escape  family of opcodes. *
X  * These opcodes place the contents of a specified  memory *
X  * location on the system bus,  for access by a peripheral *
X  * or by a co-processor such as the 8087. (The 8087 NDP is *
X  * accessed  only  via bus  escapes.)  Due to a bug in the *
X  * PC/IX assembler,  the "esc" mnemonic is not recognized; *
X  * consequently,  escape opcodes are disassembled as .byte *
X  * directives,  with the appropriate  mnemonic and operand *
X  * included as a comment.  FOR NOW, those escape sequences *
X  * corresponding  to 8087  opcodes  are  treated as simple *
X  * escapes.                                                *
X  *                                                         *
X  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
X
Xvoid
Xeshand(j)
X
X   register int j;            /* Pointer to optab[] entry   */
X
X{/* * * * * * * * * *  START OF eshand()  * * * * * * * * * */
X
X   register char *a;
X   register int k;
X
X   objini(j);
X
X   FETCH(k);
X
X   a = mtrans((j & 0xfd),(k & 0xc7),TR_STD);
X
X   mtrunc(a);
X
X   printf("\t.byte\t0x%02.2x\t\t| esc\t%s\n",j,a);
X
X   for (k = 1; k < objptr; ++k)
X      printf("\t.byte\t0x%02.2x\n",objbuf[k]);
X
X}/* * * * * * * * * * * END OF eshand() * * * * * * * * * * */
X
X /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
X  *                                                         *
X  * This is the handler routine for floating-point opcodes. *
X  * Since PC/IX must  accommodate  systems with and without *
X  * 8087 co-processors, it allows floating-point operations *
X  * to be  initiated  in either of two ways:  by a software *
X  * interrput whose type is in the range 0xd8 through 0xdf, *
X  * or by a CPU escape sequence, which is invoked by an op- *
X  * code in the same range.  In either case, the subsequent *
X  * byte determines the actual numeric operation to be per- *
X  * formed.  However,  depending  on the  method of access, *
X  * either  one or two code bytes will  precede  that byte, *
X  * and the fphand()  routine has no way of knowing whether *
X  * it was invoked by  interrupt or by an escape  sequence. *
X  * Therefore, unlike all of the other handler routines ex- *
X  * cept dfhand(),  fphand() does not initialize the object *
X  * buffer, leaving that chore to the caller.               *
X  *                                                         *
X  * FOR NOW,  fphand()  does not disassemble floating-point *
X  * opcodes to floating  mnemonics,  but simply outputs the *
X  * object code as .byte directives.                        *
X  *                                                         *
X  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
X
Xvoid
Xfphand(j)
X
X   register int j;            /* Pointer to optab[] entry   */
X
X{/* * * * * * * * * *  START OF fphand()  * * * * * * * * * */
X
X   register int k;
X
X   segflg = 0;
X
X   FETCH(k);
X
X   printf("\t.byte\t0x%02.2x\t\t| 8087 code sequence\n",
X    objbuf[0]);
X
X   for (k = 1; k < objptr; ++k)
X      printf("\t.byte\t0x%02.2x\n",objbuf[k]);
X
X/* objout();                                       FOR NOW  */
X
X}/* * * * * * * * * * * END OF fphand() * * * * * * * * * * */
X
X /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
X  *                                                         *
X  * This is the  handler for  variable  software  interrupt *
X  * opcodes.  It is included in this file because PC/IX im- *
X  * plements its software floating-point emulation by means *
X  * of interrupts.  Any interrupt in the range 0xd8 through *
X  * 0xdf is an  NDP-emulation  interrupt,  and is specially *
X  * handled by the assembler.                               *
X  *                                                         *
X  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
X
Xvoid
Xinhand(j)
X
X   register int j;            /* Pointer to optab[] entry   */
X
X{/* * * * * * * * * *  START OF inhand()  * * * * * * * * * */
X
X   register int k;
X
X   objini(j);
X
X   FETCH(k);
X
X   if (ISFLOP(k))
X      {
X      fphand(k);
X      return;
X      }
X
X   printf("%s\t%d\n",optab[j].text,k);
X
X   objout();
X
X}/* * * * * * * * * * * END OF inhand() * * * * * * * * * * */
X
X
+ END-OF-FILE disfp.c
chmod 'u=rw,g=r,o=r' 'disfp.c'
set `wc -c 'disfp.c'`
count=$1
case $count in
5589)	:;;
*)	echo 'Bad character count in ''disfp.c' >&2
		echo 'Count should be 5589' >&2
esac
echo Extracting 'dishand.c'
sed 's/^X//' > 'dishand.c' << '+ END-OF-FILE ''dishand.c'
Xstatic char *sccsid =
X   "@(#) dishand.c, Ver. 2.1 created 00:00:00 87/09/01";
X
X /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
X  *                                                         *
X  *  Copyright (C) 1987 G. M. Harding, all rights reserved  *
X  *                                                         *
X  * Permission to copy and  redistribute is hereby granted, *
X  * provided full source code,  with all copyright notices, *
X  * accompanies any redistribution.                         *
X  *                                                         *
X  * This file contains the source code for most of the spe- *
X  * cialized handler routines of the disassembler  program. *
X  * (The file disfp.c contains handler routines specific to *
X  * the 8087 numeric  co-processor.)  Each handler  routine *
X  * interprets the opcode byte  (and subsequent data bytes, *
X  * if any)  of a particular family of opcodes,  and is re- *
X  * sponsible for generating appropriate output. All of the *
X  * code in this file is highly MACHINE-SPECIFIC, and would *
X  * have to be rewritten for a different  CPU.  The handler *
X  * routines are accessed  only via pointers in the optab[] *
X  * array, however, so machine dependencies are confined to *
X  * this file, its sister file "disfp.c", and the data file *
X  * "distabs.c".                                            *
X  *                                                         *
X  * All of the code in this file is based on the assumption *
X  * of sixteen-bit integers.                                *
X  *                                                         *
X  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
X
X#include "dis.h"              /* Disassembler declarations  */
X
Xint segflg;                   /* Segment-override flag      */
X
Xunsigned char objbuf[OBJMAX]; /* Buffer for object code     */
X
Xint objptr;                   /* Index into objbuf[]        */
X
Xunsigned long PC;             /* Current program counter    */
X
X /* * * * * *  MISCELLANEOUS SUPPORTING ROUTINES  * * * * * */
X
X
Xvoid
Xobjini(j)                     /* Object code init routine   */
X
X   register int j;
X
X{
X   if ((segflg == 1) || (segflg == 2))
X      segflg *= 3;
X   else
X      segflg = 0;
X   objptr = 0;
X   objbuf[objptr++] = (unsigned char)(j);
X}
X
X
Xvoid
Xobjout()                      /* Object-code output routine */
X
X{
X    register int k;
X
X   if ( ! objflg )
X      return;
X   else
X      {
X      printf("\t|");
X      if (symptr >= 0)
X         printf(" %05.5lx:",(PC + 1L - (long)(objptr)));
X      for (k = 0; k < objptr; ++k)
X         printf(" %02.2x",objbuf[k]);
X      putchar('\n');
X      }
X}
X
X
Xvoid
Xbadseq(j,k)                   /* Invalid-sequence routine   */
X
X   register int j, k;
X
X{
X   printf("\t.byte\t0x%02.2x\t\t| invalid code sequence\n",j);
X   printf("\t.byte\t0x%02.2x\n",k);
X}
X
X /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
X  *                                                         *
X  * This  routine  is the first of several  opcode-specific *
X  * handlers,  each of which is  dedicated  to a particular *
X  * opcode family.  A pointer to a handler  routine is con- *
X  * tained in the second field of each optab[]  entry.  The *
X  * dfhand()  routine is the default handler,  invoked when *
X  * no other handler is appropriate (generally, when an in- *
X  * valid opcode is encountered).                           *
X  *                                                         *
X  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
X
Xvoid
Xdfhand(j)
X
X   register int j;            /* Pointer to optab[] entry   */
X
X{/* * * * * * * * * *  START OF dfhand()  * * * * * * * * * */
X
X   segflg = 0;
X
X   printf("\t.byte\t0x%02.2x",j);
X
X   if (optab[j].min || optab[j].max)
X      putchar('\n');
X   else
X      printf("\t\t| unimplemented opcode\n");
X
X}/* * * * * * * * * * * END OF dfhand() * * * * * * * * * * */
X
X /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
X  *                                                         *
X  * This is the  single-byte  handler,  invoked  whenever a *
X  * one-byte opcode is encountered.                         *
X  *                                                         *
X  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
X
Xvoid
Xsbhand(j)
X
X   register int j;            /* Pointer to optab[] entry   */
X
X{/* * * * * * * * * *  START OF sbhand()  * * * * * * * * * */
X
X   objini(j);
X
X   if (j == 0x2e)                               /* seg cs   */
X      segflg = 1;
X
X   if ((j == 0x26)                              /* seg es   */
X    || (j == 0x36)                              /* seg ss   */
X    || (j == 0x3e))                             /* seg ds   */
X      segflg = 2;
X
X   printf("%s\n",optab[j].text);
X
X   objout();
X
X}/* * * * * * * * * * * END OF sbhand() * * * * * * * * * * */
X
X /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
X  *                                                         *
X  * This is the handler for most of the processor's regular *
X  * arithmetic operations.                                  *
X  *                                                         *
X  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
X
Xvoid
Xaohand(j)
X
X   register int j;            /* Pointer to optab[] entry   */
X
X{/* * * * * * * * * *  START OF aohand()  * * * * * * * * * */
X
X   register int k;
X   int m, n;
X   char b[64];
X
X   objini(j);
X
X   switch (j & 7)
X      {
X      case 0 :
X      case 1 :
X      case 2 :
X      case 3 :
X         printf("%s\t",optab[j].text);
X         FETCH(k);
X         printf("%s\n",mtrans(j,k,TR_STD));
X         break;
X      case 4 :
X         FETCH(k);
X         printf("%s\tal,*0x%02.2x\n",optab[j].text,k);
X         break;
X      case 5 :
X         FETCH(m);
X         FETCH(n);
X         k = (n << 8) | m;
X         if (lookext((long)(k),(PC - 1),b))
X            printf("%s\tax,#%s\n",optab[j].text,b);
X         else
X            printf("%s\tax,#0x%04.4x\n",optab[j].text,k);
X         break;
X      default :
X         dfhand(j);
X         break;
X      }
X
X   objout();
X
X}/* * * * * * * * * * * END OF aohand() * * * * * * * * * * */
X
X /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
X  *                                                         *
X  * This is the  handler for opcodes  which  perform  short *
X  * (eight-bit) relative jumps.                             *
X  *                                                         *
X  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
X
Xvoid
Xsjhand(j)
X
X   register int j;            /* Pointer to optab[] entry   */
X
X{/* * * * * * * * * *  START OF sjhand()  * * * * * * * * * */
X
X   register int k;
X   int m;
X
X   objini(j);
X
X   FETCH(m);
X
X   if (m & 0x80)
X      k = 0xff00;
X   else
X      k = 0;
X
X   k |= m;
X
X   printf("%s\t%s\t\t| loc %05.5lx\n",optab[j].text,
X    lookup((PC + k + 1L),N_TEXT,LOOK_REL,-1L),
X    (PC + k + 1L));
X
X   objout();
X
X}/* * * * * * * * * * * END OF sjhand() * * * * * * * * * * */
X
X /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
X  *                                                         *
X  * This is the  handler for a  loosely-knit  family of op- *
X  * codes which perform  arithmetic and logical operations, *
X  * and which take immediate  data.  The routine's logic is *
X  * rather complex,  so,  in an effort to avoid  additional *
X  * complexity,  the search for external  references in the *
X  * relocation table has been dispensed with. Eager hackers *
X  * can try their hand at coding such a search.             *
X  *                                                         *
X  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
X
Xvoid
Ximhand(j)
X
X   register int j;            /* Pointer to optab[] entry   */
X
X{/* * * * * * * * * *  START OF imhand()  * * * * * * * * * */
X
X   unsigned long pc;
X   register int k;
X   int offset, oflag, immed, iflag, mod, opi, w, rm;
X   int m, n;
X   static char a[100], b[30];
X
X   objini(j);
X
X   FETCH(k);
X
X   pc = PC + 1;
X
X   offset = 0;
X   mod = (k & 0xc0) >> 6;
X   opi = (k & 0x38) >> 3;
X   w = j & 1;
X   rm = k & 7;
X
X   if ((j & 2)
X    && ((opi == 1)
X     || (opi == 4)
X     || (opi == 6)))
X      {
X      badseq(j,k);
X      return;
X      }
X
X   strcpy(a,OPFAM[opi]);
X
X   if ( ! w )
X      strcat(a,"b");
X
X   if ((oflag = mod) > 2)
X      oflag = 0;
X
X   if ((mod == 0) && (rm == 6))
X      {
X      FETCH(m);
X      FETCH(n);
X      offset = (n << 8) | m;
X      }
X   else if (oflag)
X      if (oflag == 2)
X         {
X         FETCH(m);
X         FETCH(n);
X         offset = (n << 8) | m;
X         }
X      else
X         {
X         FETCH(m);
X         if (m & 0x80)
X            n = 0xff00;
X         else
X            n = 0;
X         offset = n | m;
X         }
X
X   switch (j & 3)
X      {
X      case 0 :
X      case 2 :
X         FETCH(immed);
X         iflag = 0;
X         break;
X      case 1 :
X         FETCH(m);
X         FETCH(n);
X         immed = (n << 8) | m;
X         iflag = 1;
X         break;
X      case 3 :
X         FETCH(immed);
X         if (immed & 0x80)
X            immed &= 0xff00;
X         iflag = 0;
X         break;
X      }
X
X   strcat(a,"\t");
X
X   switch (mod)
X      {
X      case 0 :
X         if (rm == 6)
X            strcat(a,
X             lookup((long)(offset),N_DATA,LOOK_ABS,pc));
X         else
X            {
X            sprintf(b,"(%s)",REGS0[rm]);
X            strcat(a,b);
X            }
X         break;
X      case 1 :
X      case 2 :
X         if (mod == 1)
X            strcat(a,"*");
X         else
X            strcat(a,"#");
X         sprintf(b,"%d(",offset);
X         strcat(a,b);
X         strcat(a,REGS1[rm]);
X         strcat(a,")");
X         break;
X      case 3 :
X         strcat(a,REGS[(w << 3) | rm]);
X         break;
X      }
X
X   strcat(a,",");
X   if (iflag)
X      strcat(a,"#");
X   else
X      strcat(a,"*");
X   sprintf(b,"%d",immed);
X   strcat(a,b);
X
X   printf("%s\n",a);
X
X   objout();
X
X}/* * * * * * * * * * * END OF imhand() * * * * * * * * * * */
X
X /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
X  *                                                         *
X  * This is the  handler  for  various  "mov"-type  opcodes *
X  * which use the mod,  reg,  and r/m  fields of the second *
X  * code byte in a standard, straightforward way.           *
X  *                                                         *
X  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
X
Xvoid
Xmvhand(j)
X
X   int j;                     /* Pointer to optab[] entry   */
X
X{/* * * * * * * * * *  START OF mvhand()  * * * * * * * * * */
X
X   register int k, m = j;
X
X   objini(j);
X
X   FETCH(k);
X
X   if ((m == 0x84) || (m == 0x85)      /* Kind of kludgey   */
X    || (m == 0xc4) || (m == 0xc5)
X    || (m == 0x8d))
X      if (m & 0x40)
X         m |= 0x03;
X      else
X         m |= 0x02;
X
X   printf("%s\t%s\n",optab[j].text,mtrans(m,k,TR_STD));
X
X   objout();
X
X}/* * * * * * * * * * * END OF mvhand() * * * * * * * * * * */
X
X /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
X  *                                                         *
X  * This is the handler for segment-register "mov" opcodes. *
X  *                                                         *
X  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
X
Xvoid
Xmshand(j)
X
X   register int j;            /* Pointer to optab[] entry   */
X
X{/* * * * * * * * * *  START OF mshand()  * * * * * * * * * */
X
X   register int k;
X
X   objini(j);
X
X   FETCH(k);
X
X   if (k & 0x20)
X      {
X      badseq(j,k);
X      return;
X      }
X
X   printf("%s\t%s\n",optab[j].text,mtrans(j,k,TR_SEG));
X
X   objout();
X
X}/* * * * * * * * * * * END OF mshand() * * * * * * * * * * */
X
X /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
X  *                                                         *
X  * This is the  handler for pops,  other than  single-byte *
X  * pops.  (The 8088 allows  popping into any register,  or *
X  * directly into memory,  accessed  either  immediately or *
X  * through a register and an index.)                       *
X  *                                                         *
X  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
X
Xvoid
Xpohand(j)
X
X   register int j;            /* Pointer to optab[] entry   */
X
X{/* * * * * * * * * *  START OF pohand()  * * * * * * * * * */
X
X   char *a;
X   register int k;
X
X   objini(j);
X
X   FETCH(k);
X
X   if (k & 0x38)
X      {
X      badseq(j,k);
X      return;
X      }
X
X   printf("%s\t",optab[j].text);
X
X   a = mtrans((j & 0xfd),k,TR_STD);
X
X   mtrunc(a);
X
X   printf("%s\n",a);
X
X   objout();
X
X}/* * * * * * * * * * * END OF pohand() * * * * * * * * * * */
X
X /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
X  *                                                         *
X  * This is the handler routine for intersegment  calls and *
X  * jumps.  Its output is never symbolic,  because the host *
X  * linker  does not allow  symbolic  intersegment  address *
X  * references except by means of symbolic  constants,  and *
X  * any such  constants in the symbol  table,  even if they *
X  * are of the  appropriate  value,  may be misleading.  In *
X  * compiled code,  intersegment  references  should not be *
X  * encountered,  and even in assembled  code,  they should *
X  * occur infrequently. If and when they do occur, however, *
X  * they will be disassembled in absolute form.             *
X  *                                                         *
X  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
X
Xvoid
Xcihand(j)
X
X   int j;                     /* Pointer to optab[] entry   */
X
X{/* * * * * * * * * *  START OF cihand()  * * * * * * * * * */
X
X   register int m, n;
X
X   objini(j);
X
X   printf("%s\t",optab[j].text);
X
X   FETCH(m);
X   FETCH(n);
X
X   printf("#0x%04.4x,",((n << 8) | m));
X
X   FETCH(m);
X   FETCH(n);
X
X   printf("#0x%04.4x\n",((n << 8) | m));
X
X   objout();
X
X}/* * * * * * * * * * * END OF cihand() * * * * * * * * * * */
X
X /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
X  *                                                         *
X  * This is the handler for  "mov"  opcodes with  immediate *
X  * data.                                                   *
X  *                                                         *
X  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
X
Xvoid
Xmihand(j)
X
X   register int j;            /* Pointer to optab[] entry   */
X
X{/* * * * * * * * * *  START OF mihand()  * * * * * * * * * */
X
X   register int k;
X   int m, n;
X   char b[64];
X
X   objini(j);
X
X   printf("%s",optab[j].text);
X
X   if (j & 8)
X      {
X      FETCH(m);
X      FETCH(n);
X      k = ((n << 8) | m);
X      if (lookext((long)(k),(PC - 1),b))
X         printf("#%s\n",b);
X      else
X         printf("#%d\n",k);
X      }
X   else
X      {
X      FETCH(m);
X      printf("*%d\n",m);
X      }
X
X   objout();
X
X}/* * * * * * * * * * * END OF mihand() * * * * * * * * * * */
X
X /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
X  *                                                         *
X  * This is the handler for a family of quick-move opcodes. *
X  *                                                         *
X  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
X
Xvoid
Xmqhand(j)
X
X   int j;                     /* Pointer to optab[] entry   */
X
X{/* * * * * * * * * *  START OF mqhand()  * * * * * * * * * */
X
X   unsigned long pc;
X   register int m, n;
X
X   objini(j);
X
X   pc = PC + 1;
X
X   FETCH(m);
X   FETCH(n);
X
X   m = (n << 8) | m;
X
X   printf("%s\t",optab[j].text);
X
X   if (j & 2)
X      printf("%s,%s\n",
X       lookup((long)(m),N_DATA,LOOK_ABS,pc),
X       REGS[(j & 1) << 3]);
X   else
X      printf("%s,%s\n",
X       REGS[(j & 1) << 3],
X       lookup((long)(m),N_DATA,LOOK_ABS,pc));
X
X   objout();
X
X}/* * * * * * * * * * * END OF mqhand() * * * * * * * * * * */
X
X /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
X  *                                                         *
X  * This is the handler for a family of quick-test opcodes. *
X  *                                                         *
X  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
X
Xvoid
Xtqhand(j)
X
X   int j;                     /* Pointer to optab[] entry   */
X
X{/* * * * * * * * * *  START OF tqhand()  * * * * * * * * * */
X
X   register int m, n;
X   int k;
X   char b[64];
X
X   objini(j);
X
X   printf("%s\t%s,",optab[j].text,REGS[(j & 1) << 3]);
X
X   FETCH(m);
X
X   if (j & 1)
X      {
X      FETCH(n);
X      k = ((n << 8) | m);
X      if (lookext((long)(k),(PC - 1),b))
X         printf("#%s\n",b);
X      else
X         printf("#%d\n",k);
X      }
X   else
X      {
X      if (m & 80)
X         m |= 0xff00;
X      printf("*%d\n",m);
X      }
X
X   objout();
X
X}/* * * * * * * * * * * END OF tqhand() * * * * * * * * * * */
X
X /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
X  *                                                         *
X  * This is the handler for multiple-byte "return" opcodes. *
X  * The 8088 allows returns to take an optional  16-bit ar- *
X  * gument,  which  reflects  the  amount to be added to SP *
X  * after  the pop of the  return  address.  The idea is to *
X  * facilitate  the use of local  parameters  on the stack. *
X  * After some  rumination,  it was decided to  disassemble *
X  * any such arguments as absolute quantities,  rather than *
X  * rummaging  through the symbol table for possible corre- *
X  * sponding constants.                                     *
X  *                                                         *
X  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
X
Xvoid
Xrehand(j)
X
X   int j;                     /* Pointer to optab[] entry   */
X
X{/* * * * * * * * * *  START OF rehand()  * * * * * * * * * */
X
X   register int m, n;
X
X   objini(j);
X
X   FETCH(m);
X   FETCH(n);
X
X   m = (n << 8) | m;
X
X   printf("%s\t#0x%04.4x\n",optab[j].text,m);
X
X   objout();
X
X}/* * * * * * * * * * * END OF rehand() * * * * * * * * * * */
X
X /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
X  *                                                         *
X  * This is the handler for "mov"  opcodes involving memory *
X  * and immediate data.                                     *
X  *                                                         *
X  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
X
Xvoid
Xmmhand(j)
X
X   register int j;            /* Pointer to optab[] entry   */
X
X{/* * * * * * * * * *  START OF mmhand()  * * * * * * * * * */
X
X   char *a;
X   register int k;
X   char b[64];
X
X   objini(j);
X
X   FETCH(k);
X
X   if (k & 0x38)
X      {
X      badseq(j,k);
X      return;
X      }
X
X   printf("%s",optab[j].text);
X
X   if ( ! (j & 1) )
X      putchar('b');
X
X   a = mtrans((j & 0xfd),(k & 0xc7),TR_STD);
X
X   mtrunc(a);
X
X   printf("\t%s,",a);
X
X   if (j & 1)
X      {
X      FETCH(j);
X      FETCH(k);
X      k = (k << 8) | j;
X      if (lookext((long)(k),(PC - 1),b))
X         printf("#%s\n",b);
X      else
X         printf("#%d\n",k);
X      }
X   else
X      {
X      FETCH(k);
X      printf("*%d\n",k);
X      }
X
X   objout();
X
X}/* * * * * * * * * * * END OF mmhand() * * * * * * * * * * */
X
X /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
X  *                                                         *
X  * This is the  handler  for the 8088  family of shift and *
X  * rotate instructions.                                    *
X  *                                                         *
X  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
X
Xvoid
Xsrhand(j)
X
X   register int j;            /* Pointer to optab[] entry   */
X
X{/* * * * * * * * * *  START OF srhand()  * * * * * * * * * */
X
X   char *a;
X   register int k;
X
X   objini(j);
X
X   FETCH(k);
X
X   if ((k & 0x38) == 0x30)
X      {
X      badseq(j,k);
X      return;
X      }
X
X   printf("%s",OPFAM[((k & 0x38) >> 3) + 16]);
X
X   if ( ! (j & 1) )
X      putchar('b');
X
X   a = mtrans((j & 0xfd),(k & 0xc7),TR_STD);
X
X   mtrunc(a);
X
X   printf("\t%s",a);
X
X   if (j & 2)
X      printf(",cl\n");
X   else
X      printf(",*1\n");
X
X   objout();
X
X}/* * * * * * * * * * * END OF srhand() * * * * * * * * * * */
X
X /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
X  *                                                         *
X  * This is the handler for the ASCII-adjust opcodes.       *
X  *                                                         *
X  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
X
Xvoid
Xaahand(j)
X
X   register int j;            /* Pointer to optab[] entry   */
X
X{/* * * * * * * * * *  START OF aahand()  * * * * * * * * * */
X
X   register int k;
X
X   objini(j);
X
X   FETCH(k);
X
X   if (k != 0x0a)
X      {
X      badseq(j,k);
X      return;
X      }
X
X   printf("%s\n",optab[j].text);
X
X   objout();
X
X}/* * * * * * * * * * * END OF aahand() * * * * * * * * * * */
X
X /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
X  *                                                         *
X  * This is the handler for port I/O opcodes  which specify *
X  * the port address as an immediate operand.               *
X  *                                                         *
X  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
X
Xvoid
Xiohand(j)
X
X   register int j;            /* Pointer to optab[] entry   */
X
X{/* * * * * * * * * *  START OF iohand()  * * * * * * * * * */
X
X   register int k;
X
X   objini(j);
X
X   FETCH(k);
X
X   printf("%s\t0x%02.2x\n",optab[j].text,k);
X
X   objout();
X
X}/* * * * * * * * * * * END OF iohand() * * * * * * * * * * */
X
X /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
X  *                                                         *
X  * This is the  handler  for opcodes  which  perform  long *
X  * (sixteen-bit) relative jumps and calls.                 *
X  *                                                         *
X  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
X
Xvoid
Xljhand(j)
X
X   register int j;            /* Pointer to optab[] entry   */
X
X{/* * * * * * * * * *  START OF ljhand()  * * * * * * * * * */
X
X   register int k;
X   int m, n;
X
X   objini(j);
X
X   FETCH(m);
X   FETCH(n);
X
X   k = (n << 8) | m;
X
X   printf("%s\t%s\t\t| loc %05.5lx\n",optab[j].text,
X    lookup((PC + k + 1L),N_TEXT,LOOK_LNG,(PC - 1L)),
X    (PC + k + 1L));
X
X   objout();
X
X}/* * * * * * * * * * * END OF ljhand() * * * * * * * * * * */
X
X /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
X  *                                                         *
X  * This is the handler for a pair of oddball opcodes (0xf6 *
X  * and 0xf7) which perform miscellaneous arithmetic opera- *
X  * tions not dealt with elsewhere.                         *
X  *                                                         *
X  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
X
Xvoid
Xmahand(j)
X
X   register int j;            /* Pointer to optab[] entry   */
X
X{/* * * * * * * * * *  START OF mahand()  * * * * * * * * * */
X
X   char *a;
X   register int k;
X   char b[64];
X
X   objini(j);
X
X   FETCH(k);
X
X   a = mtrans((j & 0xfd),(k & 0xc7),TR_STD);
X
X   mtrunc(a);
X
X   switch (((k = objbuf[1]) & 0x38) >> 3)
X      {
X      case 0 :
X         printf("\ttest");
X         break;
X      case 1 :
X         badseq(j,k);
X         return;
X      case 2 :
X         printf("\tnot");
X         break;
X      case 3 :
X         printf("\tneg");
X         break;
X      case 4 :
X         printf("\tmul");
X         break;
X      case 5 :
X         printf("\timul");
X         break;
X      case 6 :
X         printf("\tdiv");
X         break;
X      case 7 :
X         printf("\tidiv");
X         break;
X      }
X
X   if ( ! (j & 1) )
X      putchar('b');
X
X   printf("\t%s",a);
X
X   if (k & 0x38)
X      putchar('\n');
X   else
X      if (j & 1)
X         {
X         FETCH(j);
X         FETCH(k);
X         k = (k << 8) | j;
X         if (lookext((long)(k),(PC - 1),b))
X            printf(",#%s\n",b);
X         else
X            printf(",#%d\n",k);
X         }
X      else
X         {
X         FETCH(k);
X         printf(",*%d\n",k);
X         }
X
X   objout();
X
X}/* * * * * * * * * * * END OF mahand() * * * * * * * * * * */
X
X /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
X  *                                                         *
X  * This is the handler for miscellaneous jump, call, push, *
X  * and increment/decrement opcodes  (0xfe and 0xff)  which *
X  * are not dealt with elsewhere.                           *
X  *                                                         *
X  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
X
Xvoid
Xmjhand(j)
X
X   register int j;            /* Pointer to optab[] entry   */
X
X{/* * * * * * * * * *  START OF mjhand()  * * * * * * * * * */
X
X   char *a;
X   register int k;
X
X   objini(j);
X
X   FETCH(k);
X
X   a = mtrans((j & 0xfd),(k & 0xc7),TR_STD);
X
X   mtrunc(a);
X
X   switch (((k = objbuf[1]) & 0x38) >> 3)
X      {
X      case 0 :
X         printf("\tinc");
X         if ( ! (j & 1) )
X            putchar('b');
X         putchar('\t');
X         break;
X      case 1 :
X         printf("\tdec");
X         if ( ! (j & 1) )
X            putchar('b');
X         putchar('\t');
X         break;
X      case 2 :
X         if (j & 1)
X            printf("\tcall\t@");
X         else
X            goto BAD;
X         break;
X      case 3 :
X         if (j & 1)
X            printf("\tcalli\t@");
X         else
X            goto BAD;
X         break;
X      case 4 :
X         if (j & 1)
X            printf("\tjmp\t@");
X         else
X            goto BAD;
X         break;
X      case 5 :
X         if (j & 1)
X            printf("\tjmpi\t@");
X         else
X            goto BAD;
X         break;
X      case 6 :
X         if (j & 1)
X            printf("\tpush\t");
X         else
X            goto BAD;
X         break;
X      case 7 :
X BAD :
X         badseq(j,k);
X         return;
X      }
X
X   printf("%s\n",a);
X
X   objout();
X
X}/* * * * * * * * * * * END OF mjhand() * * * * * * * * * * */
X
X
+ END-OF-FILE dishand.c
chmod 'u=rw,g=r,o=r' 'dishand.c'
set `wc -c 'dishand.c'`
count=$1
case $count in
25688)	:;;
*)	echo 'Bad character count in ''dishand.c' >&2
		echo 'Count should be 25688' >&2
esac
echo Extracting 'dismain.c'
sed 's/^X//' > 'dismain.c' << '+ END-OF-FILE ''dismain.c'
Xstatic char *sccsid =
X   "@(#) dismain.c, Ver. 2.1 created 00:00:00 87/09/01";
X
X /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
X  *                                                         *
X  *  Copyright (C) 1987 G. M. Harding, all rights reserved  *
X  *                                                         *
X  * Permission to copy and  redistribute is hereby granted, *
X  * provided full source code,  with all copyright notices, *
X  * accompanies any redistribution.                         *
X  *                                                         *
X  * This file  contains  the source  code for the  machine- *
X  * independent  portions of a disassembler  program to run *
X  * in a Unix (System III) environment.  It expects, as its *
X  * input, a file in standard a.out format, optionally con- *
X  * taining symbol table information.  If a symbol table is *
X  * present, it will be used in the disassembly; otherwise, *
X  * all address references will be literal (absolute).      *
X  *                                                         *
X  * The disassembler  program was originally written for an *
X  * Intel 8088 CPU.  However, all details of the actual CPU *
X  * architecture are hidden in three machine-specific files *
X  * named  distabs.c,  dishand.c,  and disfp.c  (the latter *
X  * file is specific to the 8087 numeric co-processor). The *
X  * code in this file is generic,  and should require mini- *
X  * mal revision if a different CPU is to be targeted. If a *
X  * different version of Unix is to be targeted, changes to *
X  * this file may be necessary, and if a completely differ- *
X  * ent OS is to be targeted, all bets are off.             *
X  *                                                         *
X  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
X
X#include "dis.h"              /* Disassembler declarations  */
X
Xextern char *release;         /* Contains release string    */
X
Xstatic char *IFILE = NULL;    /* Points to input file name  */
X
Xstatic char *OFILE = NULL;    /* Points to output file name */
X
Xstatic char *PRG;             /* Name of invoking program   */
X
Xstatic unsigned long zcount;  /* Consecutive "0" byte count */
X
Xint objflg = 0;               /* Flag: output object bytes  */
X
X#define unix 1
X#define i8086 1
X#define ibmpc 1
X
X#if unix && i8086 && ibmpc    /* Set the CPU identifier     */
Xstatic int cpuid = 1;
X#else
Xstatic int cpuid = 0;
X#endif
X
X /* * * * * * * MISCELLANEOUS UTILITY FUNCTIONS * * * * * * */
X
Xstatic void
Xusage(s)
X   register char *s;
X{
X   fprintf(stderr,"Usage: %s [-o] ifile [ofile]\n",s);
X   exit(-1);
X}
X
Xstatic void
Xfatal(s,t)
X   register char *s, *t;
X{
X   fprintf(stderr,"\07%s: %s\n",s,t);
X   exit(-1);
X}
X
Xstatic void
Xzdump(beg)
X   unsigned long beg;
X{
X   beg = PC - beg;
X   if (beg > 1L)
X      printf("\t.zerow\t%ld\n",(beg >> 1));
X   if (beg & 1L)
X      printf("\t.byte\t0\n");
X}
X
Xstatic char *
Xinvoker(s)
X   register char *s;
X{
X   extern int strlen();
X   register int k;
X
X   k = strlen(s);
X
X   while (k--)
X      if (s[k] == '/')
X         {
X         s += k;
X         ++s;
X         break;
X         }
X
X   return (s);
X}
X
X /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
X  *                                                         *
X  * This rather tricky routine supports the disdata() func- *
X  * tion.  Its job is to output the code for a sequence  of *
X  * data bytes whenever the object buffer is full,  or when *
X  * a symbolic label is to be output. However, it must also *
X  * keep track of  consecutive  zero words so that  lengthy *
X  * stretches of null data can be  compressed by the use of *
X  * an  appropriate  assembler  pseudo-op.  It does this by *
X  * setting and testing a file-wide  flag which counts suc- *
X  * cessive full buffers of null data. The function returns *
X  * a logical  TRUE value if it outputs  anything,  logical *
X  * FALSE otherwise.  (This enables disdata()  to determine *
X  * whether to output a new  synthetic  label when there is *
X  * no symbol table.)                                       *
X  *                                                         *
X  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
X
Xstatic int
Xobjdump(c)
X
X   register char *c;
X
X{/* * * * * * * * * * START OF  objdump() * * * * * * * * * */
X
X   register int k;
X   int retval = 0;
X
X   if (objptr == OBJMAX)
X      {
X      for (k = 0; k < OBJMAX; ++k)
X         if (objbuf[k])
X            break;
X      if (k == OBJMAX)
X         {
X         zcount += k;
X         objptr = 0;
X         if (c == NULL)
X            return (retval);
X         }
X      }
X
X   if (zcount)
X      {
X      printf("\t.zerow\t%ld\n",(zcount >> 1));
X      ++retval;
X      zcount = 0L;
X      }
X
X   if (objptr)
X      {
X      printf("\t.byte\t");
X      ++retval;
X      }
X   else
X      return (retval);
X
X   for (k = 0; k < objptr; ++k)
X      {
X      printf("0x%02.2x",objbuf[k]);
X      if (k < (objptr - 1))
X         putchar(',');
X      else
X         putchar('\n');
X      }
X
X   objptr = 0;
X
X   return (retval);
X
X}/* * * * * * * * * *  END OF  objdump()  * * * * * * * * * */
X
X /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
X  *                                                         *
X  * This  routine,  called  at the  beginning  of the input *
X  * cycle for each object byte,  and before any interpreta- *
X  * tion is  attempted,  searches  the symbol table for any *
X  * symbolic  name with a value  corresponding  to the cur- *
X  * rent PC and a type  corresponding  to the segment  type *
X  * (i.e.,  text, data, or bss) specified by the function's *
X  * argument. If any such name is found, a pointer to it is *
X  * returned; otherwise, a NULL pointer is returned.        *
X  *                                                         *
X  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
X
Xstatic char *
Xgetlab(type)
X
X   register int type;
X
X{/* * * * * * * * * *  START OF getlab()  * * * * * * * * * */
X
X   register int k;
X   static char b[32], c[10];
X
X   if (symptr < 0)
X      if ((type == N_TEXT)
X       || ((type == N_DATA) && ( ! objptr ) && ( ! zcount )))
X         {
X         if (type == N_TEXT)
X            sprintf(b,"T%05.5lx:",PC);
X         else
X            sprintf(b,"D%05.5lx:",PC);
X         return (b);
X         }
X      else
X         return (NULL);
X
X   for (k = 0; k <= symptr; ++k)
X      if ((symtab[k].n_value == PC)
X       && ((symtab[k].n_sclass & N_SECT) == type))
X         {
X         sprintf(b,"%s:\n",getnam(k));
X         if (objflg && (type != N_TEXT))
X            sprintf(c,"| %05.5lx\n",PC);
X         strcat(b,c);
X         return (b);
X         }
X
X   return (NULL);
X
X}/* * * * * * * * * * * END OF getlab() * * * * * * * * * * */
X
X /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
X  *                                                         *
X  * This routine  performs a preliminary scan of the symbol *
X  * table,  before disassembly begins, and outputs declara- *
X  * tions of globals and constants.                         *
X  *                                                         *
X  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
X
Xstatic void
Xprolog()
X
X{/* * * * * * * * * *  START OF prolog()  * * * * * * * * * */
X
X   register int j, flag;
X
X   if (symptr < 0)
X      return;
X
X   for (j = flag = 0; j <= symptr; ++j)
X      if ((symtab[j].n_sclass & N_CLASS) == C_EXT)
X         if (((symtab[j].n_sclass & N_SECT) > N_UNDF)
X          && ((symtab[j].n_sclass & N_SECT) < N_COMM))
X            {
X            char *c = getnam(j);
X            printf("\t.globl\t%s",c);
X            if (++flag == 1)
X               {
X               putchar('\t');
X               if (strlen(c) < 8)
X                  putchar('\t');
X               printf("| Internal global\n");
X               }
X            else
X               putchar('\n');
X            }
X         else
X            if (symtab[j].n_value)
X               {
X               char *c = getnam(j);
X               printf("\t.comm\t%s,0x%08.8lx",c,
X                symtab[j].n_value);
X               if (++flag == 1)
X                  printf("\t| Internal global\n");
X               else
X                  putchar('\n');
X               }
X
X   if (flag)
X      putchar('\n');
X
X   for (j = flag = 0; j <= relptr; ++j)
X      if (relo[j].r_symndx < S_BSS)
X         {
X         char *c = getnam(relo[j].r_symndx);
X         ++flag;
X         printf("\t.globl\t%s",c);
X         putchar('\t');
X         if (strlen(c) < 8)
X            putchar('\t');
X         printf("| Undef: %05.5lx\n",relo[j].r_vaddr);
X         }
X
X   if (flag)
X      putchar('\n');
X
X   for (j = flag = 0; j <= symptr; ++j)
X      if ((symtab[j].n_sclass & N_SECT) == N_ABS)
X         {
X         char *c = getnam(j);
X         printf("%s=0x%08.8lx",c,symtab[j].n_value);
X         if (++flag == 1)
X            {
X            printf("\t\t");
X            if (strlen(c) < 5)
X               putchar('\t');
X            printf("| Literal\n");
X            }
X         else
X            putchar('\n');
X         }
X
X   if (flag)
X      putchar('\n');
X
X}/* * * * * * * * * * * END OF prolog() * * * * * * * * * * */
X
X /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
X  *                                                         *
X  * This function is  responsible  for  disassembly  of the *
X  * object file's text segment.                             *
X  *                                                         *
X  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
X
Xstatic void
Xdistext()
X
X{/* * * * * * * * * * START OF  distext() * * * * * * * * * */
X
X   char *c;
X   register int j;
X   register void (*f)();
X
X   for (j = 0; j < (int)(HDR.a_hdrlen); ++j)
X      getchar();
X
X   printf("| %s, %s\n\n",PRG,release);
X
X   printf("| @(");
X
X   printf("#)\tDisassembly of %s",IFILE);
X
X   if (symptr < 0)
X      printf(" (no symbols)\n\n");
X   else
X      printf("\n\n");
X
X   if (HDR.a_flags & A_EXEC)
X      printf("| File is executable\n\n");
X
X   if (HDR.a_flags & A_SEP)
X      {
X      printf("| File has split I/D space, and may have\n");
X      printf("| extraneous instructions in text segment\n\n");
X      }
X
X   prolog();
X
X   printf("\t.text\t\t\t| loc = %05.5lx, size = %05.5lx\n\n",
X    PC,HDR.a_text);
X
X   segflg = 0;
X
X   for (PC = 0L; PC < HDR.a_text; ++PC)
X      {
X      j = getchar() & 0xff;
X      if ((j == 0) && ((PC + 1L) == HDR.a_text))
X         {
X         ++PC;
X         break;
X         }
X      if ((c = getlab(N_TEXT)) != NULL)
X         printf("%s",c);
X      f = optab[j].func;
X      (*f)(j);
X      }
X
X}/* * * * * * * * * *  END OF  distext()  * * * * * * * * * */
X
X /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
X  *                                                         *
X  * This  function  handles the object file's data segment. *
X  * There is no good way to disassemble a data segment, be- *
X  * cause it is  impossible  to tell,  from the object code *
X  * alone,  what each data byte refers to.  If it refers to *
X  * an external symbol,  the reference can be resolved from *
X  * the relocation table, if there is one.  However,  if it *
X  * refers to a static symbol,  it cannot be  distinguished *
X  * from numeric, character, or other pointer data. In some *
X  * cases,  one might make a semi-educated  guess as to the *
X  * nature of the data,  but such  guesses  are  inherently *
X  * haphazard,  and they are  bound to be wrong a good por- *
X  * tion of the time.  Consequently,  the data  segment  is *
X  * disassembled  as a byte  stream,  which will satisfy no *
X  * one but which, at least, will never mislead anyone.     *
X  *                                                         *
X  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
X
Xstatic void
Xdisdata()
X
X{/* * * * * * * * * * START OF  disdata() * * * * * * * * * */
X
X   register char *c;
X   register int j;
X   unsigned long end;
X
X   putchar('\n');
X
X   if (HDR.a_flags & A_SEP)
X      {
X      PC = 0L;
X      end = HDR.a_data;
X      }
X   else
X      end = HDR.a_text + HDR.a_data;
X
X   printf("\t.data\t\t\t| loc = %05.5lx, size = %05.5lx\n\n",
X    PC,HDR.a_data);
X
X   segflg = 0;
X
X   for (objptr = 0, zcount = 0L; PC < end; ++PC)
X      {
X      if ((c = getlab(N_DATA)) != NULL)
X         {
X         objdump(c);
X         printf("%s",c);
X         }
X      if (objptr >= OBJMAX)
X         if (objdump(NULL) && (symptr < 0))
X            printf("D%05.5lx:",PC);
X      j = getchar() & 0xff;
X      objbuf[objptr++] = j;
X      }
X
X   objdump("");
X
X}/* * * * * * * * * *  END OF  disdata()  * * * * * * * * * */
X
X /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
X  *                                                         *
X  * This  function  handles the object  file's bss segment. *
X  * Disassembly of the bss segment is easy,  because every- *
X  * thing in it is zero by definition.                      *
X  *                                                         *
X  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
X
Xstatic void
Xdisbss()
X
X{/* * * * * * * * * *  START OF disbss()  * * * * * * * * * */
X
X   register int j;
X   register char *c;
X   unsigned long beg, end;
X
X   putchar('\n');
X
X   if (HDR.a_flags & A_SEP)
X      end = HDR.a_data + HDR.a_bss;
X   else
X      end = HDR.a_text + HDR.a_data + HDR.a_bss;
X
X   printf("\t.bss\t\t\t| loc = %05.5lx, size = %05.5lx\n\n",
X    PC,HDR.a_bss);
X
X   segflg = 0;
X
X   for (beg = PC; PC < end; ++PC)
X      if ((c = getlab(N_BSS)) != NULL)
X         {
X         if (PC > beg)
X            {
X            zdump(beg);
X            beg = PC;
X            }
X         printf("%s",c);
X         }
X
X   if (PC > beg)
X      zdump(beg);
X
X}/* * * * * * * * * * * END OF disbss() * * * * * * * * * * */
X
X /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
X  *                                                         *
X  * This is the program  entry  point.  The command line is *
X  * searched for an input file name, which must be present. *
X  * An optional output file name is also permitted; if none *
X  * is found, standard output is the default.  One command- *
X  * line option is available:  "-o",  which causes the pro- *
X  * gram to include  object code in comments along with its *
X  * mnemonic output.                                        *
X  *                                                         *
X  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
X
Xvoid
Xmain(argc,argv)
X
X   int argc;                  /* Command-line args from OS  */
X   register char **argv;
X
X{/* * * * * * * * * * * START OF main() * * * * * * * * * * */
X
X   char a[1024];
X   register int fd;
X   long taboff, tabnum;
X   long reloff, relnum;
X
X   PRG = invoker(*argv);
X
X   while (*++argv != NULL)    /* Process command-line args  */
X      if (**argv == '-')
X         switch (*++*argv)
X            {
X            case 'o' :
X               if (*++*argv)
X                  usage(PRG);
X               else
X                  ++objflg;
X               break;
X            default :
X               usage(PRG);
X            }
X      else
X         if (IFILE == NULL)
X            IFILE = *argv;
X         else if (OFILE == NULL)
X            OFILE = *argv;
X         else
X            usage(PRG);
X
X   if (IFILE == NULL)
X      usage(PRG);
X   else
X      if ((fd = open(IFILE,0)) < 0)
X         {
X         sprintf(a,"can't access input file %s",IFILE);
X         fatal(PRG,a);
X         }
X
X   if (OFILE != NULL)
X      if (freopen(OFILE,"w",stdout) == NULL)
X         {
X         sprintf(a,"can't open output file %s",OFILE);
X         fatal(PRG,a);
X         }
X
X   if ( ! cpuid )
X      fprintf(stderr,"\07%s: warning: host/cpu clash\n",PRG);
X
X   read(fd,&HDR,sizeof(struct exec));
X
X   if (BADMAG(HDR))
X      {
X      sprintf(a,"input file %s not in object format",IFILE);
X      fatal(PRG,a);
X      }
X
X   if (HDR.a_cpu != A_I8086)
X      {
X      sprintf(a,"%s is not an 8086/8088 object file",IFILE);
X      fatal(PRG,a);
X      }
X
X   if (HDR.a_hdrlen <= A_MINHDR)
X      HDR.a_trsize = HDR.a_drsize = 0L;
X      HDR.a_tbase = HDR.a_dbase = 0L;
X/*   AST emergency patch
X      HDR.a_lnums = HDR.a_toffs = 0L;
X*/
X
X   reloff = HDR.a_text        /* Compute reloc data offset  */
X          + HDR.a_data
X          + (long)(HDR.a_hdrlen);
X
X   relnum =
X      (HDR.a_trsize + HDR.a_drsize) / sizeof(struct reloc);
X
X   taboff = reloff            /* Compute name table offset  */
X          + HDR.a_trsize
X          + HDR.a_drsize;
X
X   tabnum = HDR.a_syms / sizeof(struct nlist);
X
X   if (relnum > MAXSYM)
X      fatal(PRG,"reloc table overflow");
X
X   if (tabnum > MAXSYM)
X      fatal(PRG,"symbol table overflow");
X
X   if (relnum)                            /* Get reloc data */
X      if (lseek(fd,reloff,0) != reloff)
X         fatal(PRG,"lseek error");
X      else
X         {
X         for (relptr = 0; relptr < relnum; ++relptr)
X            read(fd,&relo[relptr],sizeof(struct reloc));
X         relptr--;
X         }
X
X   if (tabnum)                            /* Read in symtab */
X      if (lseek(fd,taboff,0) != taboff)
X         fatal(PRG,"lseek error");
X      else
X         {
X         for (symptr = 0; symptr < tabnum; ++symptr)
X            read(fd,&symtab[symptr],sizeof(struct nlist));
X         symptr--;
X         }
X   else
X      fprintf(stderr,"\07%s: warning: no symbols\n",PRG);
X
X   close(fd);
X
X   if (freopen(IFILE,"r",stdin) == NULL)
X      {
X      sprintf(a,"can't reopen input file %s",IFILE);
X      fatal(PRG,a);
X      }
X
X   distext();
X
X   disdata();
X
X   disbss();
X
X   exit(0);
X
X}/* * * * * * * * * * *  END OF main()  * * * * * * * * * * */
X
X
+ END-OF-FILE dismain.c
chmod 'u=rw,g=r,o=r' 'dismain.c'
set `wc -c 'dismain.c'`
count=$1
case $count in
17458)	:;;
*)	echo 'Bad character count in ''dismain.c' >&2
		echo 'Count should be 17458' >&2
esac
exit 0