summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert de Bath <rdebath@poboxes.com>1998-05-24 18:43:39 +0200
committerLubomir Rintel <lkundrak@v3.sk>2013-10-23 23:21:21 +0200
commit8b494f241f2abfc0f869ab42c1601ea5027d3477 (patch)
treeb45660ee4ef2c94fa1c8f27018b141ea9bf7266a
downloaddev86-8b494f241f2abfc0f869ab42c1601ea5027d3477.tar.gz
Import dis88-pcix
-rw-r--r--MANIFEST12
-rw-r--r--Makefile45
-rw-r--r--README91
-rw-r--r--dis.h203
-rw-r--r--dis88.1147
-rw-r--r--disfp.c157
-rw-r--r--dishand.c1049
-rw-r--r--dismain.c624
-rw-r--r--disrel.c28
-rw-r--r--distabs.c708
-rw-r--r--part011448
-rw-r--r--part021812
12 files changed, 6324 insertions, 0 deletions
diff --git a/MANIFEST b/MANIFEST
new file mode 100644
index 0000000..f6b6e33
--- /dev/null
+++ b/MANIFEST
@@ -0,0 +1,12 @@
+ File Name Archive # Description
+-----------------------------------------------------------
+ MANIFEST 1
+ Makefile 1
+ README 1
+ dis.h 1
+ dis88.1 1
+ disfp.c 1
+ dishand.c 2
+ dismain.c 1
+ disrel.c 1
+ distabs.c 2
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..c1352f0
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,45 @@
+# @(#) Makefile, Ver. 2.1 created 00:00:00 87/09/01
+# Makefile for 8088 symbolic disassembler
+
+# Copyright (C) 1987 G. M. Harding, all rights reserved.
+# Permission to copy and redistribute is hereby granted,
+# provided full source code, with all copyright notices,
+# accompanies any redistribution.
+
+# This Makefile automates the process of compiling and linking
+# a symbolic object-file disassembler program for the Intel
+# 8088 CPU. Relatively machine-independent code is contained in
+# the file dismain.c; lookup tables and handler routines, which
+# are by their nature machine-specific, are contained in two
+# files named distabs.c and dishand.c, respectively. (A third
+# machine-specific file, disfp.c, contains handler routines for
+# floating-point coprocessor opcodes.) A header file, dis.h,
+# attempts to mediate between the machine-specific and machine-
+# independent portions of the code. An attempt has been made to
+# isolate machine dependencies and to deal with them in fairly
+# straightforward ways. Thus, it should be possible to target a
+# different CPU by rewriting the handler routines and changing
+# the initialization data in the lookup tables. It should not
+# be necessary to alter the formats of the tables.
+
+OBJ = disrel.o dismain.o distabs.o dishand.o disfp.o
+
+dis88 : $(OBJ)
+ ld -i -s -o dis88 /lib/crt0.o $(OBJ) -lc
+ size dis88
+ @echo "\07Build of 'dis88' complete." > /dev/tty
+
+.c.o :
+ cc -O -c $<
+ chmod 600 $*.o
+
+disrel.o : disrel.c
+
+dismain.o : dismain.c dis.h
+
+distabs.o : distabs.c dis.h
+
+dishand.o : dishand.c dis.h
+
+disfp.o : disfp.c dis.h
+
diff --git a/README b/README
new file mode 100644
index 0000000..d0c80dc
--- /dev/null
+++ b/README
@@ -0,0 +1,91 @@
+ dis88
+ Beta Release
+ 87/09/01
+ ---
+ G. M. HARDING
+ POB 4142
+ Santa Clara CA 95054-0142
+
+
+ "Dis88" is a symbolic disassembler for the Intel 8088 CPU,
+ designed to run under the PC/IX operating system on an IBM XT
+ or fully-compatible clone. Its output is in the format of, and
+ is completely compatible with, the PC/IX assembler, "as". The
+ program is copyrighted by its author, but may be copied and re-
+ distributed freely provided that complete source code, with all
+ copyright notices, accompanies any distribution. This provision
+ also applies to any modifications you may make. You are urged
+ to comment such changes, giving, as a miminum, your name and
+ complete address.
+
+ This release of the program is a beta release, which means
+ that it has been extensively, but not exhaustively, tested.
+ User comments, recommendations, and bug fixes are welcome. The
+ principal features of the current release are:
+
+ (a) The ability to disassemble any file in PC/IX object
+ format, making full use of symbol and relocation information if
+ it is present, regardless of whether the file is executable or
+ linkable, and regardless of whether it has continuous or split
+ I/D space;
+
+ (b) Automatic generation of synthetic labels when no sym-
+ bol table is available; and
+
+ (c) Optional output of address and object-code informa-
+ tion as assembler comment text.
+
+ Limitations of the current release are:
+
+ (a) Numeric co-processor (i.e., 8087) mnemonics are not
+ supported. Instructions for the co-processor are disassembled
+ as CPU escape sequences, or as interrupts, depending on how
+ they were assembled in the first place. This limitation will be
+ addressed in a future release.
+
+ (b) Symbolic references within the object file's data
+ segment are not supported. Thus, for example, if a data segment
+ location is initialized to point to a text segment address, no
+ reference to a text segment symbol will be detected. This limi-
+ tation is likely to remain in future releases, because object
+ code does not, in most cases, contain sufficient information to
+ allow meaningful interpretation of pure data. (Note, however,
+ that symbolic references to the data segment from within the
+ text segment are always supported.)
+
+ As a final caveat, be aware that the PC/IX assembler does
+ not recognize the "esc" mnemonic, even though it refers to a
+ completely valid CPU operation which is documented in all the
+ Intel literature. Thus, the corresponding opcodes (0xd8 through
+ 0xdf) are disassembled as .byte directives. For reference, how-
+ ever, the syntactically-correct "esc" instruction is output as
+ a comment.
+
+ To build the disassembler program, transfer all the source
+ files, together with the Makefile, to a suitable (preferably
+ empty) PC/IX directory. Then, simply type "make".
+
+ To use dis88, place it in a directory which appears in
+ your $PATH list. It may then be invoked by name from whatever
+ directory you happen to be in. As a minimum, the program must
+ be invoked with one command-line argument: the name of the ob-
+ ject file to be disassembled. (Dis88 will complain if the file
+ specified is not an object file.) Optionally, you may specify
+ an output file; stdout is the default. One command-line switch
+ is available: "-o", which makes the program display addresses
+ and object code along with its mnemonic disassembly.
+
+ The "-o" option is useful primarily for verifying the cor-
+ rectness of the program's output. In particular, it may be used
+ to check the accuracy of local relative jump opcodes. These
+ jumps often target local labels, which are lost at assembly
+ time; thus, the disassembly may contain cryptic instructions
+ like "jnz .+39". As a user convenience, all relative jump and
+ call opcodes are output with a comment which identifies the
+ physical target address.
+
+ By convention, the release level of the program as a whole
+ is the SID of the file disrel.c, and this SID string appears in
+ each disassembly. Release 2.1 of the program is the first beta
+ release to be distributed on Usenet.
+
diff --git a/dis.h b/dis.h
new file mode 100644
index 0000000..9f93b38
--- /dev/null
+++ b/dis.h
@@ -0,0 +1,203 @@
+ /*
+ ** @(#) dis.h, Ver. 2.1 created 00:00:00 87/09/01
+ */
+
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * *
+ * Copyright (C) 1987 G. M. Harding, all rights reserved *
+ * *
+ * Permission to copy and redistribute is hereby granted, *
+ * provided full source code, with all copyright notices, *
+ * accompanies any redistribution. *
+ * *
+ * This file contains declarations and definitions used by *
+ * the 8088 disassembler program. The program was designed *
+ * for execution on a machine of its own type (i.e., it is *
+ * not designed as a cross-disassembler); consequently, A *
+ * SIXTEEN-BIT INTEGER SIZE HAS BEEN ASSUMED. This assump- *
+ * tion is not particularly important, however, except in *
+ * the machine-specific portions of the code (i.e., the *
+ * handler routines and the optab[] array). It should be *
+ * possible to override this assumption, for execution on *
+ * 32-bit machines, by use of a pre-processor directive *
+ * (see below); however, this has not been tested. *
+ * *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#include <stdio.h> /* System standard I/O definitions */
+#include <fcntl.h> /* System file-control definitions */
+#include <a.out.h> /* Object file format definitions */
+
+#if i8086 || i8088 /* For CPU's with 16-bit integers */
+#undef int
+#else /* Defaults (for 32-bit CPU types) */
+#define int short
+#endif
+
+#define MAXSYM 1500 /* Maximum entries in symbol table */
+
+extern struct nlist /* Array to hold the symbol table */
+ symtab[MAXSYM];
+
+extern struct reloc /* Array to hold relocation table */
+ relo[MAXSYM];
+
+extern int symptr; /* Index into the symtab[] array */
+
+extern int relptr; /* Index into the relo[] array */
+
+struct opcode /* Format for opcode data records */
+ {
+ char *text; /* Pointer to mnemonic text */
+ void (*func)(); /* Pointer to handler routine */
+ unsigned min; /* Minimum # of object bytes */
+ unsigned max; /* Maximum # of object bytes */
+ };
+
+extern struct opcode /* Array to hold the opcode table */
+ optab[256];
+
+ /*
+ +---------------------------------------------
+ | The following functions are the specialized
+ | handlers for each opcode group. They are, of
+ | course, highly MACHINE-SPECIFIC. Each entry
+ | in the opcode[] array contains a pointer to
+ | one of these handlers. The handlers in the
+ | first group are in dishand.c; those in the
+ | second group are in disfp.c.
+ +---------------------------------------------
+ */
+
+extern void dfhand(), /* Default handler routine */
+ sbhand(), /* Single-byte handler */
+ aohand(), /* Arithmetic-op handler */
+ sjhand(), /* Short-jump handler */
+ imhand(), /* Immediate-operand handler */
+ mvhand(), /* Simple move handler */
+ mshand(), /* Segreg-move handler */
+ pohand(), /* Pop memory/reg handler */
+ cihand(), /* Intersegment call handler */
+ mihand(), /* Immediate-move handler */
+ mqhand(), /* Quick-move handler */
+ tqhand(), /* Quick-test handler */
+ rehand(), /* Return handler */
+ mmhand(), /* Move-to-memory handler */
+ srhand(), /* Shift and rotate handler */
+ aahand(), /* ASCII-adjust handler */
+ iohand(), /* Immediate port I/O handler */
+ ljhand(), /* Long-jump handler */
+ mahand(), /* Misc. arithmetic handler */
+ mjhand(); /* Miscellaneous jump handler */
+
+extern void eshand(), /* Bus-escape opcode handler */
+ fphand(), /* Floating-point handler */
+ inhand(); /* Interrupt-opcode handler */
+
+extern char *REGS[]; /* Table of register names */
+
+extern char *REGS0[]; /* Mode 0 register name table */
+
+extern char *REGS1[]; /* Mode 1 register name table */
+
+#define AL REGS[0] /* CPU register manifests */
+#define CL REGS[1]
+#define DL REGS[2]
+#define BL REGS[3]
+#define AH REGS[4]
+#define CH REGS[5]
+#define DH REGS[6]
+#define BH REGS[7]
+#define AX REGS[8]
+#define CX REGS[9]
+#define DX REGS[10]
+#define BX REGS[11]
+#define SP REGS[12]
+#define BP REGS[13]
+#define SI REGS[14]
+#define DI REGS[15]
+#define ES REGS[16]
+#define CS REGS[17]
+#define SS REGS[18]
+#define DS REGS[19]
+#define BX_SI REGS0[0]
+#define BX_DI REGS0[1]
+#define BP_SI REGS0[2]
+#define BP_DI REGS0[3]
+
+extern int symrank[6][6]; /* Symbol type/rank matrix */
+
+extern unsigned long PC; /* Current program counter */
+
+extern int segflg; /* Flag: segment override in effect */
+
+extern int objflg; /* Flag: output object as a comment */
+
+#define OBJMAX 8 /* Size of the object code buffer */
+
+extern unsigned char /* Internal buffer for object code */
+ objbuf[OBJMAX];
+
+extern void objini(), /* Object-buffer init routine */
+ objout(); /* Object-code output routine */
+
+extern int objptr; /* Index into the objbuf[] array */
+
+extern void badseq(); /* Bad-code-sequence function */
+
+extern char *getnam(); /* Symbol-name string function */
+
+extern char *lookup(); /* Symbol-table lookup function */
+
+extern int lookext(); /* Extern-definition lookup routine */
+
+extern char *mtrans(); /* Interpreter for the mode byte */
+
+extern void mtrunc(); /* Mode string truncator function */
+
+extern char ADD[], /* Opcode family mnemonic strings */
+ OR[],
+ ADC[],
+ SBB[],
+ AND[],
+ SUB[],
+ XOR[],
+ CMP[],
+ NOT[],
+ NEG[],
+ MUL[],
+ DIV[],
+ MOV[],
+ ESC[],
+ TEST[],
+ AMBIG[];
+
+extern char *OPFAM[]; /* Indexed mnemonic family table */
+
+extern struct exec HDR; /* Holds the object file's header */
+
+#define LOOK_ABS 0 /* Arguments to lookup() function */
+#define LOOK_REL 1
+#define LOOK_LNG 2
+
+#define TR_STD 0 /* Arguments to mtrans() function */
+#define TR_SEG 8
+
+ /* Macro for byte input primitive */
+#define FETCH(p) \
+ ++PC; p = getchar() & 0xff; objbuf[objptr++] = p
+
+extern int close(); /* System file-close primitive */
+extern int fprintf(); /* Library file-output function */
+extern long lseek(); /* System file-position primitive */
+extern int open(); /* System file-open primitive */
+extern int printf(); /* Library output-format function */
+extern int read(); /* System file-read primitive */
+extern int sprintf(); /* Library string-output function */
+extern char *strcat(); /* Library string-join function */
+extern char *strcpy(); /* Library string-copy function */
+extern int strlen(); /* Library string-length function */
+
+ /* * * * * * * * * * * END OF dis.h * * * * * * * * * * */
+
+
diff --git a/dis88.1 b/dis88.1
new file mode 100644
index 0000000..c991ad7
--- /dev/null
+++ b/dis88.1
@@ -0,0 +1,147 @@
+.TH dis88 1 LOCAL
+.SH "NAME"
+dis88 \- 8088 symbolic disassembler
+.SH "SYNOPSIS"
+\fBdis88\fP [ -o ] ifile [ ofile ]
+.SH "DESCRIPTION"
+Dis88 reads ifile, which must be in PC/IX a.out format.
+It interprets the binary opcodes and data locations, and
+writes corresponding assembler source code to stdout, or
+to ofile if specified. The program's output is in the
+format of, and fully compatible with, the PC/IX assembler,
+as(1). If a symbol table is present in ifile, labels and
+references will be symbolic in the output. If the input
+file lacks a symbol table, the fact will be noted, and the
+disassembly will proceed, with the disassembler generating
+synthetic labels as needed. If the input file has split
+I/D space, or if it is executable, the disassembler will
+make all necessary adjustments in address-reference calculations.
+.PP
+If the "-o" option appears, object code will be included
+in comments during disassembly of the text segment. This
+feature is used primarily for debugging the disassembler
+itself, but may provide information of passing interest
+to users.
+.PP
+The program always outputs the current machine address
+before disassembling an opcode. If a symbol table is
+present, this address is output as an assembler comment;
+otherwise, it is incorporated into the synthetic label
+which is generated internally. Since relative jumps,
+especially short ones, may target unlabelled locations,
+the program always outputs the physical target address
+as a comment, to assist the user in following the code.
+.PP
+The text segment of an object file is always padded to
+an even machine address. In addition, if the file has
+split I/D space, the text segment will be padded to a
+paragraph boundary (i.e., an address divisible by 16).
+As a result of this padding, the disassembler may produce
+a few spurious, but harmless, instructions at the
+end of the text segment.
+.PP
+Disassembly of the data segment is a difficult matter.
+The information to which initialized data refers cannot
+be inferred from context, except in the special case
+of an external data or address reference, which will be
+reflected in the relocation table. Internal data and
+address references will already be resolved in the object file,
+and cannot be recreated. Therefore, the data
+segment is disassembled as a byte stream, with long
+stretches of null data represented by an appropriate
+".zerow" pseudo-op. This limitation notwithstanding,
+labels (as opposed to symbolic references) are always
+output at appropriate points within the data segment.
+.PP
+If disassembly of the data segment is difficult, disassembly of the
+bss segment is quite easy, because uninitialized data is all
+zero by definition. No data
+is output in the bss segment, but symbolic labels are
+output as appropriate.
+.PP
+For each opcode which takes an operand, a particular
+symbol type (text, data, or bss) is appropriate. This
+tidy correspondence is complicated somewhat, however,
+by the existence of assembler symbolic constants and
+segment override opcodes. Therefore, the disassembler's
+symbol lookup routine attempts to apply a certain amount
+of intelligence when it is asked to find a symbol. If
+it cannot match on a symbol of the preferred type, it
+may return a symbol of some other type, depending on
+preassigned (and somewhat arbitrary) rankings within
+each type. Finally, if all else fails, it returns a
+string containing the address sought as a hex constant;
+this behavior allows calling routines to use the output
+of the lookup function regardless of the success of its
+search.
+.PP
+It is worth noting, at this point, that the symbol lookup
+routine operates linearly, and has not been optimized in
+any way. Execution time is thus likely to increase
+geometrically with input file size. The disassembler is
+internally limited to 1500 symbol table entries and 1500
+relocation table entries; while these limits are generous
+(/unix, itself, has fewer than 800 symbols), they are not
+guaranteed to be adequate in all cases. If the symbol
+table or the relocation table overflows, the disassembly
+aborts.
+.PP
+Finally, users should be aware of a bug in the assembler,
+which causes it not to parse the "esc" mnemonic, even
+though "esc" is a completely legitimate opcode which is
+documented in all the Intel literature. To accommodate
+this deficiency, the disassembler translates opcodes of
+the "esc" family to .byte directives, but notes the
+correct mnemonic in a comment for reference.
+.PP
+In all cases, it should be possible to submit the output
+of the disassembler program to the assembler, and assemble
+it without error. In most cases, the resulting object
+code will be identical to the original; in any event, it
+will be functionally equivalent.
+.SH "SEE ALSO"
+adb(1), as(1), cc(1), ld(1).
+.br
+"Assembler Reference Manual" in the PC/IX Programmer's
+Guide.
+.SH "DIAGNOSTICS"
+"can't access input file" if the input file cannot be
+found, opened, or read.
+.sp
+"can't open output file" if the output file cannot be
+created.
+.sp
+"warning: host/cpu clash" if the program is run on a
+machine with a different CPU.
+.sp
+"input file not in object format" if the magic number
+does not correspond to that of a PC/IX object file.
+.sp
+"not an 8086/8088 object file" if the CPU ID of the
+file header is incorrect.
+.sp
+"reloc table overflow" if there are more than 1500
+entries in the relocation table.
+.sp
+"symbol table overflow" if there are more than 1500
+entries in the symbol table.
+.sp
+"lseek error" if the input file is corrupted (should
+never happen).
+.sp
+"warning: no symbols" if the symbol table is missing.
+.sp
+"can't reopen input file" if the input file is removed
+or altered during program execution (should never happen).
+.SH "BUGS"
+Numeric co-processor (i.e., 8087) mnemonics are not currently supported.
+Instructions for the co-processor are
+disassembled as CPU escape sequences, or as interrupts,
+depending on how they were assembled in the first place.
+.sp
+Despite the program's best efforts, a symbol retrieved
+from the symbol table may sometimes be different from
+the symbol used in the original assembly.
+.sp
+The disassembler's internal tables are of fixed size,
+and the program aborts if they overflow.
diff --git a/disfp.c b/disfp.c
new file mode 100644
index 0000000..c6dc0da
--- /dev/null
+++ b/disfp.c
@@ -0,0 +1,157 @@
+static char *sccsid =
+ "@(#) disfp.c, Ver. 2.1 created 00:00:00 87/09/01";
+
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * *
+ * Copyright (C) 1987 G. M. Harding, all rights reserved *
+ * *
+ * Permission to copy and redistribute is hereby granted, *
+ * provided full source code, with all copyright notices, *
+ * accompanies any redistribution. *
+ * *
+ * This file contains handler routines for the numeric op- *
+ * codes of the 8087 co-processor, as well as a few other *
+ * opcodes which are related to 8087 emulation. *
+ * *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#include "dis.h" /* Disassembler declarations */
+
+#define FPINT0 0xd8 /* Floating-point interrupts */
+#define FPINT1 0xd9
+#define FPINT2 0xda
+#define FPINT3 0xdb
+#define FPINT4 0xdc
+#define FPINT5 0xdd
+#define FPINT6 0xde
+#define FPINT7 0xdf
+
+ /* Test for floating opcodes */
+#define ISFLOP(x) \
+ (((x) >= FPINT0) && ((x) <= FPINT7))
+
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * *
+ * This is the handler for the escape family of opcodes. *
+ * These opcodes place the contents of a specified memory *
+ * location on the system bus, for access by a peripheral *
+ * or by a co-processor such as the 8087. (The 8087 NDP is *
+ * accessed only via bus escapes.) Due to a bug in the *
+ * PC/IX assembler, the "esc" mnemonic is not recognized; *
+ * consequently, escape opcodes are disassembled as .byte *
+ * directives, with the appropriate mnemonic and operand *
+ * included as a comment. FOR NOW, those escape sequences *
+ * corresponding to 8087 opcodes are treated as simple *
+ * escapes. *
+ * *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+void
+eshand(j)
+
+ register int j; /* Pointer to optab[] entry */
+
+{/* * * * * * * * * * START OF eshand() * * * * * * * * * */
+
+ register char *a;
+ register int k;
+
+ objini(j);
+
+ FETCH(k);
+
+ a = mtrans((j & 0xfd),(k & 0xc7),TR_STD);
+
+ mtrunc(a);
+
+ printf("\t.byte\t0x%02.2x\t\t| esc\t%s\n",j,a);
+
+ for (k = 1; k < objptr; ++k)
+ printf("\t.byte\t0x%02.2x\n",objbuf[k]);
+
+}/* * * * * * * * * * * END OF eshand() * * * * * * * * * * */
+
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * *
+ * This is the handler routine for floating-point opcodes. *
+ * Since PC/IX must accommodate systems with and without *
+ * 8087 co-processors, it allows floating-point operations *
+ * to be initiated in either of two ways: by a software *
+ * interrput whose type is in the range 0xd8 through 0xdf, *
+ * or by a CPU escape sequence, which is invoked by an op- *
+ * code in the same range. In either case, the subsequent *
+ * byte determines the actual numeric operation to be per- *
+ * formed. However, depending on the method of access, *
+ * either one or two code bytes will precede that byte, *
+ * and the fphand() routine has no way of knowing whether *
+ * it was invoked by interrupt or by an escape sequence. *
+ * Therefore, unlike all of the other handler routines ex- *
+ * cept dfhand(), fphand() does not initialize the object *
+ * buffer, leaving that chore to the caller. *
+ * *
+ * FOR NOW, fphand() does not disassemble floating-point *
+ * opcodes to floating mnemonics, but simply outputs the *
+ * object code as .byte directives. *
+ * *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+void
+fphand(j)
+
+ register int j; /* Pointer to optab[] entry */
+
+{/* * * * * * * * * * START OF fphand() * * * * * * * * * */
+
+ register int k;
+
+ segflg = 0;
+
+ FETCH(k);
+
+ printf("\t.byte\t0x%02.2x\t\t| 8087 code sequence\n",
+ objbuf[0]);
+
+ for (k = 1; k < objptr; ++k)
+ printf("\t.byte\t0x%02.2x\n",objbuf[k]);
+
+/* objout(); FOR NOW */
+
+}/* * * * * * * * * * * END OF fphand() * * * * * * * * * * */
+
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * *
+ * This is the handler for variable software interrupt *
+ * opcodes. It is included in this file because PC/IX im- *
+ * plements its software floating-point emulation by means *
+ * of interrupts. Any interrupt in the range 0xd8 through *
+ * 0xdf is an NDP-emulation interrupt, and is specially *
+ * handled by the assembler. *
+ * *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+void
+inhand(j)
+
+ register int j; /* Pointer to optab[] entry */
+
+{/* * * * * * * * * * START OF inhand() * * * * * * * * * */
+
+ register int k;
+
+ objini(j);
+
+ FETCH(k);
+
+ if (ISFLOP(k))
+ {
+ fphand(k);
+ return;
+ }
+
+ printf("%s\t%d\n",optab[j].text,k);
+
+ objout();
+
+}/* * * * * * * * * * * END OF inhand() * * * * * * * * * * */
+
+
diff --git a/dishand.c b/dishand.c
new file mode 100644
index 0000000..56c6321
--- /dev/null
+++ b/dishand.c
@@ -0,0 +1,1049 @@
+static char *sccsid =
+ "@(#) dishand.c, Ver. 2.1 created 00:00:00 87/09/01";
+
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * *
+ * Copyright (C) 1987 G. M. Harding, all rights reserved *
+ * *
+ * Permission to copy and redistribute is hereby granted, *
+ * provided full source code, with all copyright notices, *
+ * accompanies any redistribution. *
+ * *
+ * This file contains the source code for most of the spe- *
+ * cialized handler routines of the disassembler program. *
+ * (The file disfp.c contains handler routines specific to *
+ * the 8087 numeric co-processor.) Each handler routine *
+ * interprets the opcode byte (and subsequent data bytes, *
+ * if any) of a particular family of opcodes, and is re- *
+ * sponsible for generating appropriate output. All of the *
+ * code in this file is highly MACHINE-SPECIFIC, and would *
+ * have to be rewritten for a different CPU. The handler *
+ * routines are accessed only via pointers in the optab[] *
+ * array, however, so machine dependencies are confined to *
+ * this file, its sister file "disfp.c", and the data file *
+ * "distabs.c". *
+ * *
+ * All of the code in this file is based on the assumption *
+ * of sixteen-bit integers. *
+ * *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#include "dis.h" /* Disassembler declarations */
+
+int segflg; /* Segment-override flag */
+
+unsigned char objbuf[OBJMAX]; /* Buffer for object code */
+
+int objptr; /* Index into objbuf[] */
+
+unsigned long PC; /* Current program counter */
+
+ /* * * * * * MISCELLANEOUS SUPPORTING ROUTINES * * * * * */
+
+
+void
+objini(j) /* Object code init routine */
+
+ register int j;
+
+{
+ if ((segflg == 1) || (segflg == 2))
+ segflg *= 3;
+ else
+ segflg = 0;
+ objptr = 0;
+ objbuf[objptr++] = (unsigned char)(j);
+}
+
+
+void
+objout() /* Object-code output routine */
+
+{
+ register int k;
+
+ if ( ! objflg )
+ return;
+ else
+ {
+ printf("\t|");
+ if (symptr >= 0)
+ printf(" %05.5lx:",(PC + 1L - (long)(objptr)));
+ for (k = 0; k < objptr; ++k)
+ printf(" %02.2x",objbuf[k]);
+ putchar('\n');
+ }
+}
+
+
+void
+badseq(j,k) /* Invalid-sequence routine */
+
+ register int j, k;
+
+{
+ printf("\t.byte\t0x%02.2x\t\t| invalid code sequence\n",j);
+ printf("\t.byte\t0x%02.2x\n",k);
+}
+
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * *
+ * This routine is the first of several opcode-specific *
+ * handlers, each of which is dedicated to a particular *
+ * opcode family. A pointer to a handler routine is con- *
+ * tained in the second field of each optab[] entry. The *
+ * dfhand() routine is the default handler, invoked when *
+ * no other handler is appropriate (generally, when an in- *
+ * valid opcode is encountered). *
+ * *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+void
+dfhand(j)
+
+ register int j; /* Pointer to optab[] entry */
+
+{/* * * * * * * * * * START OF dfhand() * * * * * * * * * */
+
+ segflg = 0;
+
+ printf("\t.byte\t0x%02.2x",j);
+
+ if (optab[j].min || optab[j].max)
+ putchar('\n');
+ else
+ printf("\t\t| unimplemented opcode\n");
+
+}/* * * * * * * * * * * END OF dfhand() * * * * * * * * * * */
+
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * *
+ * This is the single-byte handler, invoked whenever a *
+ * one-byte opcode is encountered. *
+ * *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+void
+sbhand(j)
+
+ register int j; /* Pointer to optab[] entry */
+
+{/* * * * * * * * * * START OF sbhand() * * * * * * * * * */
+
+ objini(j);
+
+ if (j == 0x2e) /* seg cs */
+ segflg = 1;
+
+ if ((j == 0x26) /* seg es */
+ || (j == 0x36) /* seg ss */
+ || (j == 0x3e)) /* seg ds */
+ segflg = 2;
+
+ printf("%s\n",optab[j].text);
+
+ objout();
+
+}/* * * * * * * * * * * END OF sbhand() * * * * * * * * * * */
+
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * *
+ * This is the handler for most of the processor's regular *
+ * arithmetic operations. *
+ * *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+void
+aohand(j)
+
+ register int j; /* Pointer to optab[] entry */
+
+{/* * * * * * * * * * START OF aohand() * * * * * * * * * */
+
+ register int k;
+ int m, n;
+ char b[64];
+
+ objini(j);
+
+ switch (j & 7)
+ {
+ case 0 :
+ case 1 :
+ case 2 :
+ case 3 :
+ printf("%s\t",optab[j].text);
+ FETCH(k);
+ printf("%s\n",mtrans(j,k,TR_STD));
+ break;
+ case 4 :
+ FETCH(k);
+ printf("%s\tal,*0x%02.2x\n",optab[j].text,k);
+ break;
+ case 5 :
+ FETCH(m);
+ FETCH(n);
+ k = (n << 8) | m;
+ if (lookext((long)(k),(PC - 1),b))
+ printf("%s\tax,#%s\n",optab[j].text,b);
+ else
+ printf("%s\tax,#0x%04.4x\n",optab[j].text,k);
+ break;
+ default :
+ dfhand(j);
+ break;
+ }
+
+ objout();
+
+}/* * * * * * * * * * * END OF aohand() * * * * * * * * * * */
+
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * *
+ * This is the handler for opcodes which perform short *
+ * (eight-bit) relative jumps. *
+ * *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+void
+sjhand(j)
+
+ register int j; /* Pointer to optab[] entry */
+
+{/* * * * * * * * * * START OF sjhand() * * * * * * * * * */
+
+ register int k;
+ int m;
+
+ objini(j);
+
+ FETCH(m);
+
+ if (m & 0x80)
+ k = 0xff00;
+ else
+ k = 0;
+
+ k |= m;
+
+ printf("%s\t%s\t\t| loc %05.5lx\n",optab[j].text,
+ lookup((PC + k + 1L),N_TEXT,LOOK_REL,-1L),
+ (PC + k + 1L));
+
+ objout();
+
+}/* * * * * * * * * * * END OF sjhand() * * * * * * * * * * */
+
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * *
+ * This is the handler for a loosely-knit family of op- *
+ * codes which perform arithmetic and logical operations, *
+ * and which take immediate data. The routine's logic is *
+ * rather complex, so, in an effort to avoid additional *
+ * complexity, the search for external references in the *
+ * relocation table has been dispensed with. Eager hackers *
+ * can try their hand at coding such a search. *
+ * *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+void
+imhand(j)
+
+ register int j; /* Pointer to optab[] entry */
+
+{/* * * * * * * * * * START OF imhand() * * * * * * * * * */
+
+ unsigned long pc;
+ register int k;
+ int offset, oflag, immed, iflag, mod, opi, w, rm;
+ int m, n;
+ static char a[100], b[30];
+
+ objini(j);
+
+ FETCH(k);
+
+ pc = PC + 1;
+
+ offset = 0;
+ mod = (k & 0xc0) >> 6;
+ opi = (k & 0x38) >> 3;
+ w = j & 1;
+ rm = k & 7;
+
+ if ((j & 2)
+ && ((opi == 1)
+ || (opi == 4)
+ || (opi == 6)))
+ {
+ badseq(j,k);
+ return;
+ }
+
+ strcpy(a,OPFAM[opi]);
+
+ if ( ! w )
+ strcat(a,"b");
+
+ if ((oflag = mod) > 2)
+ oflag = 0;
+
+ if ((mod == 0) && (rm == 6))
+ {
+ FETCH(m);
+ FETCH(n);
+ offset = (n << 8) | m;
+ }
+ else if (oflag)
+ if (oflag == 2)
+ {
+ FETCH(m);
+ FETCH(n);
+ offset = (n << 8) | m;
+ }
+ else
+ {
+ FETCH(m);
+ if (m & 0x80)
+ n = 0xff00;
+ else
+ n = 0;
+ offset = n | m;
+ }
+
+ switch (j & 3)
+ {
+ case 0 :
+ case 2 :
+ FETCH(immed);
+ iflag = 0;
+ break;
+ case 1 :
+ FETCH(m);
+ FETCH(n);
+ immed = (n << 8) | m;
+ iflag = 1;
+ break;
+ case 3 :
+ FETCH(immed);
+ if (immed & 0x80)
+ immed &= 0xff00;
+ iflag = 0;
+ break;
+ }
+
+ strcat(a,"\t");
+
+ switch (mod)
+ {
+ case 0 :
+ if (rm == 6)
+ strcat(a,
+ lookup((long)(offset),N_DATA,LOOK_ABS,pc));
+ else
+ {
+ sprintf(b,"(%s)",REGS0[rm]);
+ strcat(a,b);
+ }
+ break;
+ case 1 :
+ case 2 :
+ if (mod == 1)
+ strcat(a,"*");
+ else
+ strcat(a,"#");
+ sprintf(b,"%d(",offset);
+ strcat(a,b);
+ strcat(a,REGS1[rm]);
+ strcat(a,")");
+ break;
+ case 3 :
+ strcat(a,REGS[(w << 3) | rm]);
+ break;
+ }
+
+ strcat(a,",");
+ if (iflag)
+ strcat(a,"#");
+ else
+ strcat(a,"*");
+ sprintf(b,"%d",immed);
+ strcat(a,b);
+
+ printf("%s\n",a);
+
+ objout();
+
+}/* * * * * * * * * * * END OF imhand() * * * * * * * * * * */
+
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * *
+ * This is the handler for various "mov"-type opcodes *
+ * which use the mod, reg, and r/m fields of the second *
+ * code byte in a standard, straightforward way. *
+ * *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+void
+mvhand(j)
+
+ int j; /* Pointer to optab[] entry */
+
+{/* * * * * * * * * * START OF mvhand() * * * * * * * * * */
+
+ register int k, m = j;
+
+ objini(j);
+
+ FETCH(k);
+
+ if ((m == 0x84) || (m == 0x85) /* Kind of kludgey */
+ || (m == 0xc4) || (m == 0xc5)
+ || (m == 0x8d))
+ if (m & 0x40)
+ m |= 0x03;
+ else
+ m |= 0x02;
+
+ printf("%s\t%s\n",optab[j].text,mtrans(m,k,TR_STD));
+
+ objout();
+
+}/* * * * * * * * * * * END OF mvhand() * * * * * * * * * * */
+
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * *
+ * This is the handler for segment-register "mov" opcodes. *
+ * *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+void
+mshand(j)
+
+ register int j; /* Pointer to optab[] entry */
+
+{/* * * * * * * * * * START OF mshand() * * * * * * * * * */
+
+ register int k;
+
+ objini(j);
+
+ FETCH(k);
+
+ if (k & 0x20)
+ {
+ badseq(j,k);
+ return;
+ }
+
+ printf("%s\t%s\n",optab[j].text,mtrans(j,k,TR_SEG));
+
+ objout();
+
+}/* * * * * * * * * * * END OF mshand() * * * * * * * * * * */
+
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * *
+ * This is the handler for pops, other than single-byte *
+ * pops. (The 8088 allows popping into any register, or *
+ * directly into memory, accessed either immediately or *
+ * through a register and an index.) *
+ * *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+void
+pohand(j)
+
+ register int j; /* Pointer to optab[] entry */
+
+{/* * * * * * * * * * START OF pohand() * * * * * * * * * */
+
+ char *a;
+ register int k;
+
+ objini(j);
+
+ FETCH(k);
+
+ if (k & 0x38)
+ {
+ badseq(j,k);
+ return;
+ }
+
+ printf("%s\t",optab[j].text);
+
+ a = mtrans((j & 0xfd),k,TR_STD);
+
+ mtrunc(a);
+
+ printf("%s\n",a);
+
+ objout();
+
+}/* * * * * * * * * * * END OF pohand() * * * * * * * * * * */
+
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * *
+ * This is the handler routine for intersegment calls and *
+ * jumps. Its output is never symbolic, because the host *
+ * linker does not allow symbolic intersegment address *
+ * references except by means of symbolic constants, and *
+ * any such constants in the symbol table, even if they *
+ * are of the appropriate value, may be misleading. In *
+ * compiled code, intersegment references should not be *
+ * encountered, and even in assembled code, they should *
+ * occur infrequently. If and when they do occur, however, *
+ * they will be disassembled in absolute form. *
+ * *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+void
+cihand(j)
+
+ int j; /* Pointer to optab[] entry */
+
+{/* * * * * * * * * * START OF cihand() * * * * * * * * * */
+
+ register int m, n;
+
+ objini(j);
+
+ printf("%s\t",optab[j].text);
+
+ FETCH(m);
+ FETCH(n);
+
+ printf("#0x%04.4x,",((n << 8) | m));
+
+ FETCH(m);
+ FETCH(n);
+
+ printf("#0x%04.4x\n",((n << 8) | m));
+
+ objout();
+
+}/* * * * * * * * * * * END OF cihand() * * * * * * * * * * */
+
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * *
+ * This is the handler for "mov" opcodes with immediate *
+ * data. *
+ * *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+void
+mihand(j)
+
+ register int j; /* Pointer to optab[] entry */
+
+{/* * * * * * * * * * START OF mihand() * * * * * * * * * */
+
+ register int k;
+ int m, n;
+ char b[64];
+
+ objini(j);
+
+ printf("%s",optab[j].text);
+
+ if (j & 8)
+ {
+ FETCH(m);
+ FETCH(n);
+ k = ((n << 8) | m);
+ if (lookext((long)(k),(PC - 1),b))
+ printf("#%s\n",b);
+ else
+ printf("#%d\n",k);
+ }
+ else
+ {
+ FETCH(m);
+ printf("*%d\n",m);
+ }
+
+ objout();
+
+}/* * * * * * * * * * * END OF mihand() * * * * * * * * * * */
+
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * *
+ * This is the handler for a family of quick-move opcodes. *
+ * *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+void
+mqhand(j)
+
+ int j; /* Pointer to optab[] entry */
+
+{/* * * * * * * * * * START OF mqhand() * * * * * * * * * */
+
+ unsigned long pc;
+ register int m, n;
+
+ objini(j);
+
+ pc = PC + 1;
+
+ FETCH(m);
+ FETCH(n);
+
+ m = (n << 8) | m;
+
+ printf("%s\t",optab[j].text);
+
+ if (j & 2)
+ printf("%s,%s\n",
+ lookup((long)(m),N_DATA,LOOK_ABS,pc),
+ REGS[(j & 1) << 3]);
+ else
+ printf("%s,%s\n",
+ REGS[(j & 1) << 3],
+ lookup((long)(m),N_DATA,LOOK_ABS,pc));
+
+ objout();
+
+}/* * * * * * * * * * * END OF mqhand() * * * * * * * * * * */
+
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * *
+ * This is the handler for a family of quick-test opcodes. *
+ * *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+void
+tqhand(j)
+
+ int j; /* Pointer to optab[] entry */
+
+{/* * * * * * * * * * START OF tqhand() * * * * * * * * * */
+
+ register int m, n;
+ int k;
+ char b[64];
+
+ objini(j);
+
+ printf("%s\t%s,",optab[j].text,REGS[(j & 1) << 3]);
+
+ FETCH(m);
+
+ if (j & 1)
+ {
+ FETCH(n);
+ k = ((n << 8) | m);
+ if (lookext((long)(k),(PC - 1),b))
+ printf("#%s\n",b);
+ else
+ printf("#%d\n",k);
+ }
+ else
+ {
+ if (m & 80)
+ m |= 0xff00;
+ printf("*%d\n",m);
+ }
+
+ objout();
+
+}/* * * * * * * * * * * END OF tqhand() * * * * * * * * * * */
+
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * *
+ * This is the handler for multiple-byte "return" opcodes. *
+ * The 8088 allows returns to take an optional 16-bit ar- *
+ * gument, which reflects the amount to be added to SP *
+ * after the pop of the return address. The idea is to *
+ * facilitate the use of local parameters on the stack. *
+ * After some rumination, it was decided to disassemble *
+ * any such arguments as absolute quantities, rather than *
+ * rummaging through the symbol table for possible corre- *
+ * sponding constants. *
+ * *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+void
+rehand(j)
+
+ int j; /* Pointer to optab[] entry */
+
+{/* * * * * * * * * * START OF rehand() * * * * * * * * * */
+
+ register int m, n;
+
+ objini(j);
+
+ FETCH(m);
+ FETCH(n);
+
+ m = (n << 8) | m;
+
+ printf("%s\t#0x%04.4x\n",optab[j].text,m);
+
+ objout();
+
+}/* * * * * * * * * * * END OF rehand() * * * * * * * * * * */
+
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * *
+ * This is the handler for "mov" opcodes involving memory *
+ * and immediate data. *
+ * *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+void
+mmhand(j)
+
+ register int j; /* Pointer to optab[] entry */
+
+{/* * * * * * * * * * START OF mmhand() * * * * * * * * * */
+
+ char *a;
+ register int k;
+ char b[64];
+
+ objini(j);
+
+ FETCH(k);
+
+ if (k & 0x38)
+ {
+ badseq(j,k);
+ return;
+ }
+
+ printf("%s",optab[j].text);
+
+ if ( ! (j & 1) )
+ putchar('b');
+
+ a = mtrans((j & 0xfd),(k & 0xc7),TR_STD);
+
+ mtrunc(a);
+
+ printf("\t%s,",a);
+
+ if (j & 1)
+ {
+ FETCH(j);
+ FETCH(k);
+ k = (k << 8) | j;
+ if (lookext((long)(k),(PC - 1),b))
+ printf("#%s\n",b);
+ else
+ printf("#%d\n",k);
+ }
+ else
+ {
+ FETCH(k);
+ printf("*%d\n",k);
+ }
+
+ objout();
+
+}/* * * * * * * * * * * END OF mmhand() * * * * * * * * * * */
+
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * *
+ * This is the handler for the 8088 family of shift and *
+ * rotate instructions. *
+ * *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+void
+srhand(j)
+
+ register int j; /* Pointer to optab[] entry */
+
+{/* * * * * * * * * * START OF srhand() * * * * * * * * * */
+
+ char *a;
+ register int k;
+
+ objini(j);
+
+ FETCH(k);
+
+ if ((k & 0x38) == 0x30)
+ {
+ badseq(j,k);
+ return;
+ }
+
+ printf("%s",OPFAM[((k & 0x38) >> 3) + 16]);
+
+ if ( ! (j & 1) )
+ putchar('b');
+
+ a = mtrans((j & 0xfd),(k & 0xc7),TR_STD);
+
+ mtrunc(a);
+
+ printf("\t%s",a);
+
+ if (j & 2)
+ printf(",cl\n");
+ else
+ printf(",*1\n");
+
+ objout();
+
+}/* * * * * * * * * * * END OF srhand() * * * * * * * * * * */
+
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * *
+ * This is the handler for the ASCII-adjust opcodes. *
+ * *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+void
+aahand(j)
+
+ register int j; /* Pointer to optab[] entry */
+
+{/* * * * * * * * * * START OF aahand() * * * * * * * * * */
+
+ register int k;
+
+ objini(j);
+
+ FETCH(k);
+
+ if (k != 0x0a)
+ {
+ badseq(j,k);
+ return;
+ }
+
+ printf("%s\n",optab[j].text);
+
+ objout();
+
+}/* * * * * * * * * * * END OF aahand() * * * * * * * * * * */
+
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * *
+ * This is the handler for port I/O opcodes which specify *
+ * the port address as an immediate operand. *
+ * *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+void
+iohand(j)
+
+ register int j; /* Pointer to optab[] entry */
+
+{/* * * * * * * * * * START OF iohand() * * * * * * * * * */
+
+ register int k;
+
+ objini(j);
+
+ FETCH(k);
+
+ printf("%s\t0x%02.2x\n",optab[j].text,k);
+
+ objout();
+
+}/* * * * * * * * * * * END OF iohand() * * * * * * * * * * */
+
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * *
+ * This is the handler for opcodes which perform long *
+ * (sixteen-bit) relative jumps and calls. *
+ * *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+void
+ljhand(j)
+
+ register int j; /* Pointer to optab[] entry */
+
+{/* * * * * * * * * * START OF ljhand() * * * * * * * * * */
+
+ register int k;
+ int m, n;
+
+ objini(j);
+
+ FETCH(m);
+ FETCH(n);
+
+ k = (n << 8) | m;
+
+ printf("%s\t%s\t\t| loc %05.5lx\n",optab[j].text,
+ lookup((PC + k + 1L),N_TEXT,LOOK_LNG,(PC - 1L)),
+ (PC + k + 1L));
+
+ objout();
+
+}/* * * * * * * * * * * END OF ljhand() * * * * * * * * * * */
+
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * *
+ * This is the handler for a pair of oddball opcodes (0xf6 *
+ * and 0xf7) which perform miscellaneous arithmetic opera- *
+ * tions not dealt with elsewhere. *
+ * *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+void
+mahand(j)
+
+ register int j; /* Pointer to optab[] entry */
+
+{/* * * * * * * * * * START OF mahand() * * * * * * * * * */
+
+ char *a;
+ register int k;
+ char b[64];
+
+ objini(j);
+
+ FETCH(k);
+
+ a = mtrans((j & 0xfd),(k & 0xc7),TR_STD);
+
+ mtrunc(a);
+
+ switch (((k = objbuf[1]) & 0x38) >> 3)
+ {
+ case 0 :
+ printf("\ttest");
+ break;
+ case 1 :
+ badseq(j,k);
+ return;
+ case 2 :
+ printf("\tnot");
+ break;
+ case 3 :
+ printf("\tneg");
+ break;
+ case 4 :
+ printf("\tmul");
+ break;
+ case 5 :
+ printf("\timul");
+ break;
+ case 6 :
+ printf("\tdiv");
+ break;
+ case 7 :
+ printf("\tidiv");
+ break;
+ }
+
+ if ( ! (j & 1) )
+ putchar('b');
+
+ printf("\t%s",a);
+
+ if (k & 0x38)
+ putchar('\n');
+ else
+ if (j & 1)
+ {
+ FETCH(j);
+ FETCH(k);
+ k = (k << 8) | j;
+ if (lookext((long)(k),(PC - 1),b))
+ printf(",#%s\n",b);
+ else
+ printf(",#%d\n",k);
+ }
+ else
+ {
+ FETCH(k);
+ printf(",*%d\n",k);
+ }
+
+ objout();
+
+}/* * * * * * * * * * * END OF mahand() * * * * * * * * * * */
+
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * *
+ * This is the handler for miscellaneous jump, call, push, *
+ * and increment/decrement opcodes (0xfe and 0xff) which *
+ * are not dealt with elsewhere. *
+ * *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+void
+mjhand(j)
+
+ register int j; /* Pointer to optab[] entry */
+
+{/* * * * * * * * * * START OF mjhand() * * * * * * * * * */
+
+ char *a;
+ register int k;
+
+ objini(j);
+
+ FETCH(k);
+
+ a = mtrans((j & 0xfd),(k & 0xc7),TR_STD);
+
+ mtrunc(a);
+
+ switch (((k = objbuf[1]) & 0x38) >> 3)
+ {
+ case 0 :
+ printf("\tinc");
+ if ( ! (j & 1) )
+ putchar('b');
+ putchar('\t');
+ break;
+ case 1 :
+ printf("\tdec");
+ if ( ! (j & 1) )
+ putchar('b');
+ putchar('\t');
+ break;
+ case 2 :
+ if (j & 1)
+ printf("\tcall\t@");
+ else
+ goto BAD;
+ break;
+ case 3 :
+ if (j & 1)
+ printf("\tcalli\t@");
+ else
+ goto BAD;
+ break;
+ case 4 :
+ if (j & 1)
+ printf("\tjmp\t@");
+ else
+ goto BAD;
+ break;
+ case 5 :
+ if (j & 1)
+ printf("\tjmpi\t@");
+ else
+ goto BAD;
+ break;
+ case 6 :
+ if (j & 1)
+ printf("\tpush\t");
+ else
+ goto BAD;
+ break;
+ case 7 :
+ BAD :
+ badseq(j,k);
+ return;
+ }
+
+ printf("%s\n",a);
+
+ objout();
+
+}/* * * * * * * * * * * END OF mjhand() * * * * * * * * * * */
+
+
diff --git a/dismain.c b/dismain.c
new file mode 100644
index 0000000..b511785
--- /dev/null
+++ b/dismain.c
@@ -0,0 +1,624 @@
+static char *sccsid =
+ "@(#) dismain.c, Ver. 2.1 created 00:00:00 87/09/01";
+
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * *
+ * Copyright (C) 1987 G. M. Harding, all rights reserved *
+ * *
+ * Permission to copy and redistribute is hereby granted, *
+ * provided full source code, with all copyright notices, *
+ * accompanies any redistribution. *
+ * *
+ * This file contains the source code for the machine- *
+ * independent portions of a disassembler program to run *
+ * in a Unix (System III) environment. It expects, as its *
+ * input, a file in standard a.out format, optionally con- *
+ * taining symbol table information. If a symbol table is *
+ * present, it will be used in the disassembly; otherwise, *
+ * all address references will be literal (absolute). *
+ * *
+ * The disassembler program was originally written for an *
+ * Intel 8088 CPU. However, all details of the actual CPU *
+ * architecture are hidden in three machine-specific files *
+ * named distabs.c, dishand.c, and disfp.c (the latter *
+ * file is specific to the 8087 numeric co-processor). The *
+ * code in this file is generic, and should require mini- *
+ * mal revision if a different CPU is to be targeted. If a *
+ * different version of Unix is to be targeted, changes to *
+ * this file may be necessary, and if a completely differ- *
+ * ent OS is to be targeted, all bets are off. *
+ * *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#include "dis.h" /* Disassembler declarations */
+
+extern char *release; /* Contains release string */
+
+static char *IFILE = NULL; /* Points to input file name */
+
+static char *OFILE = NULL; /* Points to output file name */
+
+static char *PRG; /* Name of invoking program */
+
+static unsigned long zcount; /* Consecutive "0" byte count */
+
+int objflg = 0; /* Flag: output object bytes */
+
+#if unix && i8086 && ibmpc /* Set the CPU identifier */
+static int cpuid = 1;
+#else
+static int cpuid = 0;
+#endif
+
+ /* * * * * * * MISCELLANEOUS UTILITY FUNCTIONS * * * * * * */
+
+static void
+usage(s)
+ register char *s;
+{
+ fprintf(stderr,"\07usage: %s [-o] ifile [ofile]\n",s);
+ exit(-1);
+}
+
+static void
+fatal(s,t)
+ register char *s, *t;
+{
+ fprintf(stderr,"\07%s: %s\n",s,t);
+ exit(-1);
+}
+
+static void
+zdump(beg)
+ unsigned long beg;
+{
+ beg = PC - beg;
+ if (beg > 1L)
+ printf("\t.zerow\t%ld\n",(beg >> 1));
+ if (beg & 1L)
+ printf("\t.byte\t0\n");
+}
+
+static char *
+invoker(s)
+ register char *s;
+{
+ extern int strlen();
+ register int k;
+
+ k = strlen(s);
+
+ while (k--)
+ if (s[k] == '/')
+ {
+ s += k;
+ ++s;
+ break;
+ }
+
+ return (s);
+}
+
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * *
+ * This rather tricky routine supports the disdata() func- *
+ * tion. Its job is to output the code for a sequence of *
+ * data bytes whenever the object buffer is full, or when *
+ * a symbolic label is to be output. However, it must also *
+ * keep track of consecutive zero words so that lengthy *
+ * stretches of null data can be compressed by the use of *
+ * an appropriate assembler pseudo-op. It does this by *
+ * setting and testing a file-wide flag which counts suc- *
+ * cessive full buffers of null data. The function returns *
+ * a logical TRUE value if it outputs anything, logical *
+ * FALSE otherwise. (This enables disdata() to determine *
+ * whether to output a new synthetic label when there is *
+ * no symbol table.) *
+ * *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+static int
+objdump(c)
+
+ register char *c;
+
+{/* * * * * * * * * * START OF objdump() * * * * * * * * * */
+
+ register int k;
+ int retval = 0;
+
+ if (objptr == OBJMAX)
+ {
+ for (k = 0; k < OBJMAX; ++k)
+ if (objbuf[k])
+ break;
+ if (k == OBJMAX)
+ {
+ zcount += k;
+ objptr = 0;
+ if (c == NULL)
+ return (retval);
+ }
+ }
+
+ if (zcount)
+ {
+ printf("\t.zerow\t%ld\n",(zcount >> 1));
+ ++retval;
+ zcount = 0L;
+ }
+
+ if (objptr)
+ {
+ printf("\t.byte\t");
+ ++retval;
+ }
+ else
+ return (retval);
+
+ for (k = 0; k < objptr; ++k)
+ {
+ printf("0x%02.2x",objbuf[k]);
+ if (k < (objptr - 1))
+ putchar(',');
+ else
+ putchar('\n');
+ }
+
+ objptr = 0;
+
+ return (retval);
+
+}/* * * * * * * * * * END OF objdump() * * * * * * * * * */
+
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * *
+ * This routine, called at the beginning of the input *
+ * cycle for each object byte, and before any interpreta- *
+ * tion is attempted, searches the symbol table for any *
+ * symbolic name with a value corresponding to the cur- *
+ * rent PC and a type corresponding to the segment type *
+ * (i.e., text, data, or bss) specified by the function's *
+ * argument. If any such name is found, a pointer to it is *
+ * returned; otherwise, a NULL pointer is returned. *
+ * *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+static char *
+getlab(type)
+
+ register int type;
+
+{/* * * * * * * * * * START OF getlab() * * * * * * * * * */
+
+ register int k;
+ static char b[32], c[10];
+
+ if (symptr < 0)
+ if ((type == N_TEXT)
+ || ((type == N_DATA) && ( ! objptr ) && ( ! zcount )))
+ {
+ if (type == N_TEXT)
+ sprintf(b,"T%05.5lx:",PC);
+ else
+ sprintf(b,"D%05.5lx:",PC);
+ return (b);
+ }
+ else
+ return (NULL);
+
+ for (k = 0; k <= symptr; ++k)
+ if ((symtab[k].n_value == PC)
+ && ((symtab[k].n_sclass & N_SECT) == type))
+ {
+ sprintf(b,"%s:\n",getnam(k));
+ if (objflg && (type != N_TEXT))
+ sprintf(c,"| %05.5lx\n",PC);
+ strcat(b,c);
+ return (b);
+ }
+
+ return (NULL);
+
+}/* * * * * * * * * * * END OF getlab() * * * * * * * * * * */
+
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * *
+ * This routine performs a preliminary scan of the symbol *
+ * table, before disassembly begins, and outputs declara- *
+ * tions of globals and constants. *
+ * *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+static void
+prolog()
+
+{/* * * * * * * * * * START OF prolog() * * * * * * * * * */
+
+ register int j, flag;
+
+ if (symptr < 0)
+ return;
+
+ for (j = flag = 0; j <= symptr; ++j)
+ if ((symtab[j].n_sclass & N_CLASS) == C_EXT)
+ if (((symtab[j].n_sclass & N_SECT) > N_UNDF)
+ && ((symtab[j].n_sclass & N_SECT) < N_COMM))
+ {
+ char *c = getnam(j);
+ printf("\t.globl\t%s",c);
+ if (++flag == 1)
+ {
+ putchar('\t');
+ if (strlen(c) < 8)
+ putchar('\t');
+ printf("| Internal global\n");
+ }
+ else
+ putchar('\n');
+ }
+ else
+ if (symtab[j].n_value)
+ {
+ char *c = getnam(j);
+ printf("\t.comm\t%s,0x%08.8lx",c,
+ symtab[j].n_value);
+ if (++flag == 1)
+ printf("\t| Internal global\n");
+ else
+ putchar('\n');
+ }
+
+ if (flag)
+ putchar('\n');
+
+ for (j = flag = 0; j <= relptr; ++j)
+ if (relo[j].r_symndx < S_BSS)
+ {
+ char *c = getnam(relo[j].r_symndx);
+ ++flag;
+ printf("\t.globl\t%s",c);
+ putchar('\t');
+ if (strlen(c) < 8)
+ putchar('\t');
+ printf("| Undef: %05.5lx\n",relo[j].r_vaddr);
+ }
+
+ if (flag)
+ putchar('\n');
+
+ for (j = flag = 0; j <= symptr; ++j)
+ if ((symtab[j].n_sclass & N_SECT) == N_ABS)
+ {
+ char *c = getnam(j);
+ printf("%s=0x%08.8lx",c,symtab[j].n_value);
+ if (++flag == 1)
+ {
+ printf("\t\t");
+ if (strlen(c) < 5)
+ putchar('\t');
+ printf("| Literal\n");
+ }
+ else
+ putchar('\n');
+ }
+
+ if (flag)
+ putchar('\n');
+
+}/* * * * * * * * * * * END OF prolog() * * * * * * * * * * */
+
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * *
+ * This function is responsible for disassembly of the *
+ * object file's text segment. *
+ * *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+static void
+distext()
+
+{/* * * * * * * * * * START OF distext() * * * * * * * * * */
+
+ char *c;
+ register int j;
+ register void (*f)();
+
+ for (j = 0; j < (int)(HDR.a_hdrlen); ++j)
+ getchar();
+
+ printf("| %s, %s\n\n",PRG,release);
+
+ printf("| @(");
+
+ printf("#)\tDisassembly of %s",IFILE);
+
+ if (symptr < 0)
+ printf(" (no symbols)\n\n");
+ else
+ printf("\n\n");
+
+ if (HDR.a_flags & A_EXEC)
+ printf("| File is executable\n\n");
+
+ if (HDR.a_flags & A_SEP)
+ {
+ printf("| File has split I/D space, and may have\n");
+ printf("| extraneous instructions in text segment\n\n");
+ }
+
+ prolog();
+
+ printf("\t.text\t\t\t| loc = %05.5lx, size = %05.5lx\n\n",
+ PC,HDR.a_text);
+
+ segflg = 0;
+
+ for (PC = 0L; PC < HDR.a_text; ++PC)
+ {
+ j = getchar() & 0xff;
+ if ((j == 0) && ((PC + 1L) == HDR.a_text))
+ {
+ ++PC;
+ break;
+ }
+ if ((c = getlab(N_TEXT)) != NULL)
+ printf("%s",c);
+ f = optab[j].func;
+ (*f)(j);
+ }
+
+}/* * * * * * * * * * END OF distext() * * * * * * * * * */
+
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * *
+ * This function handles the object file's data segment. *
+ * There is no good way to disassemble a data segment, be- *
+ * cause it is impossible to tell, from the object code *
+ * alone, what each data byte refers to. If it refers to *
+ * an external symbol, the reference can be resolved from *
+ * the relocation table, if there is one. However, if it *
+ * refers to a static symbol, it cannot be distinguished *
+ * from numeric, character, or other pointer data. In some *
+ * cases, one might make a semi-educated guess as to the *
+ * nature of the data, but such guesses are inherently *
+ * haphazard, and they are bound to be wrong a good por- *
+ * tion of the time. Consequently, the data segment is *
+ * disassembled as a byte stream, which will satisfy no *
+ * one but which, at least, will never mislead anyone. *
+ * *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+static void
+disdata()
+
+{/* * * * * * * * * * START OF disdata() * * * * * * * * * */
+
+ register char *c;
+ register int j;
+ unsigned long end;
+
+ putchar('\n');
+
+ if (HDR.a_flags & A_SEP)
+ {
+ PC = 0L;
+ end = HDR.a_data;
+ }
+ else
+ end = HDR.a_text + HDR.a_data;
+
+ printf("\t.data\t\t\t| loc = %05.5lx, size = %05.5lx\n\n",
+ PC,HDR.a_data);
+
+ segflg = 0;
+
+ for (objptr = 0, zcount = 0L; PC < end; ++PC)
+ {
+ if ((c = getlab(N_DATA)) != NULL)
+ {
+ objdump(c);
+ printf("%s",c);
+ }
+ if (objptr >= OBJMAX)
+ if (objdump(NULL) && (symptr < 0))
+ printf("D%05.5lx:",PC);
+ j = getchar() & 0xff;
+ objbuf[objptr++] = j;
+ }
+
+ objdump("");
+
+}/* * * * * * * * * * END OF disdata() * * * * * * * * * */
+
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * *
+ * This function handles the object file's bss segment. *
+ * Disassembly of the bss segment is easy, because every- *
+ * thing in it is zero by definition. *
+ * *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+static void
+disbss()
+
+{/* * * * * * * * * * START OF disbss() * * * * * * * * * */
+
+ register int j;
+ register char *c;
+ unsigned long beg, end;
+
+ putchar('\n');
+
+ if (HDR.a_flags & A_SEP)
+ end = HDR.a_data + HDR.a_bss;
+ else
+ end = HDR.a_text + HDR.a_data + HDR.a_bss;
+
+ printf("\t.bss\t\t\t| loc = %05.5lx, size = %05.5lx\n\n",
+ PC,HDR.a_bss);
+
+ segflg = 0;
+
+ for (beg = PC; PC < end; ++PC)
+ if ((c = getlab(N_BSS)) != NULL)
+ {
+ if (PC > beg)
+ {
+ zdump(beg);
+ beg = PC;
+ }
+ printf("%s",c);
+ }
+
+ if (PC > beg)
+ zdump(beg);
+
+}/* * * * * * * * * * * END OF disbss() * * * * * * * * * * */
+
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * *
+ * This is the program entry point. The command line is *
+ * searched for an input file name, which must be present. *
+ * An optional output file name is also permitted; if none *
+ * is found, standard output is the default. One command- *
+ * line option is available: "-o", which causes the pro- *
+ * gram to include object code in comments along with its *
+ * mnemonic output. *
+ * *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+void
+main(argc,argv)
+
+ int argc; /* Command-line args from OS */
+ register char **argv;
+
+{/* * * * * * * * * * * START OF main() * * * * * * * * * * */
+
+ char a[1024];
+ register int fd;
+ long taboff, tabnum;
+ long reloff, relnum;
+
+ PRG = invoker(*argv);
+
+ while (*++argv != NULL) /* Process command-line args */
+ if (**argv == '-')
+ switch (*++*argv)
+ {
+ case 'o' :
+ if (*++*argv)
+ usage(PRG);
+ else
+ ++objflg;
+ break;
+ default :
+ usage(PRG);
+ }
+ else
+ if (IFILE == NULL)
+ IFILE = *argv;
+ else if (OFILE == NULL)
+ OFILE = *argv;
+ else
+ usage(PRG);
+
+ if (IFILE == NULL)
+ usage(PRG);
+ else
+ if ((fd = open(IFILE,O_RDONLY)) < 0)
+ {
+ sprintf(a,"can't access input file %s",IFILE);
+ fatal(PRG,a);
+ }
+
+ if (OFILE != NULL)
+ if (freopen(OFILE,"w",stdout) == NULL)
+ {
+ sprintf(a,"can't open output file %s",OFILE);
+ fatal(PRG,a);
+ }
+
+ if ( ! cpuid )
+ fprintf(stderr,"\07%s: warning: host/cpu clash\n",PRG);
+
+ read(fd,&HDR,sizeof(struct exec));
+
+ if (BADMAG(HDR))
+ {
+ sprintf(a,"input file %s not in object format",IFILE);
+ fatal(PRG,a);
+ }
+
+ if (HDR.a_cpu != A_I8086)
+ {
+ sprintf(a,"%s is not an 8086/8088 object file",IFILE);
+ fatal(PRG,a);
+ }
+
+ if (HDR.a_hdrlen <= A_MINHDR)
+ HDR.a_trsize = HDR.a_drsize =
+ HDR.a_tbase = HDR.a_dbase =
+ HDR.a_lnums = HDR.a_toffs = 0L;
+
+ reloff = HDR.a_text /* Compute reloc data offset */
+ + HDR.a_data
+ + (long)(HDR.a_hdrlen);
+
+ relnum =
+ (HDR.a_trsize + HDR.a_drsize) / sizeof(struct reloc);
+
+ taboff = reloff /* Compute name table offset */
+ + HDR.a_trsize
+ + HDR.a_drsize;
+
+ tabnum = HDR.a_syms / sizeof(struct nlist);
+
+ if (relnum > MAXSYM)
+ fatal(PRG,"reloc table overflow");
+
+ if (tabnum > MAXSYM)
+ fatal(PRG,"symbol table overflow");
+
+ if (relnum) /* Get reloc data */
+ if (lseek(fd,reloff,0) != reloff)
+ fatal(PRG,"lseek error");
+ else
+ {
+ for (relptr = 0; relptr < relnum; ++relptr)
+ read(fd,&relo[relptr],sizeof(struct reloc));
+ relptr--;
+ }
+
+ if (tabnum) /* Read in symtab */
+ if (lseek(fd,taboff,0) != taboff)
+ fatal(PRG,"lseek error");
+ else
+ {
+ for (symptr = 0; symptr < tabnum; ++symptr)
+ read(fd,&symtab[symptr],sizeof(struct nlist));
+ symptr--;
+ }
+ else
+ fprintf(stderr,"\07%s: warning: no symbols\n",PRG);
+
+ close(fd);
+
+ if (freopen(IFILE,"r",stdin) == NULL)
+ {
+ sprintf(a,"can't reopen input file %s",IFILE);
+ fatal(PRG,a);
+ }
+
+ distext();
+
+ disdata();
+
+ disbss();
+
+ exit(0);
+
+}/* * * * * * * * * * * END OF main() * * * * * * * * * * */
+
+
diff --git a/disrel.c b/disrel.c
new file mode 100644
index 0000000..1e28155
--- /dev/null
+++ b/disrel.c
@@ -0,0 +1,28 @@
+static char *copyright =
+ "@(#) Copyright (C) 1987 G. M. Harding, all rights reserved";
+
+static char *sccsid =
+ "@(#) disrel.c, Ver. 2.1 created 00:00:00 87/09/01";
+
+char *release =
+ "release 2.1 (PC/IX)";
+
+ /*
+ **
+ ** This file documents the major revisions to the 8088 sym-
+ ** bolic disassembler. It also contains the release string
+ ** which is output at the head of each disassembly, and the
+ ** copyright string which must be incorporated in any code
+ ** distribution.
+ **
+ ** Permission to copy and redistribute is hereby granted,
+ ** provided full source code, with all copyright notices,
+ ** accompanies any redistribution.
+ **
+ ** REVISION HISTORY:
+ **
+ ** SEP 87:
+ ** After internal shakeout, released on Usenet.
+ **
+ */
+
diff --git a/distabs.c b/distabs.c
new file mode 100644
index 0000000..6390cec
--- /dev/null
+++ b/distabs.c
@@ -0,0 +1,708 @@
+static char *sccsid =
+ "@(#) distabs.c, Ver. 2.1 created 00:00:00 87/09/01";
+
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * *
+ * Copyright (C) 1987 G. M. Harding, all rights reserved *
+ * *
+ * Permission to copy and redistribute is hereby granted, *
+ * provided full source code, with all copyright notices, *
+ * accompanies any redistribution. *
+ * *
+ * This file contains the lookup tables and other data *
+ * structures for the Intel 8088 symbolic disassembler. It *
+ * also contains a few global routines which facilitate *
+ * access to the tables, for use primarily by the handler *
+ * functions. *
+ * *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#include "dis.h" /* Disassembler declarations */
+
+struct exec HDR; /* Used to hold header info */
+
+struct nlist symtab[MAXSYM]; /* Array of symbol table info */
+
+struct reloc relo[MAXSYM]; /* Array of relocation info */
+
+int symptr = -1, /* Index into symtab[] */
+ relptr = -1; /* Index into relo[] */
+
+char *REGS[] = /* Table of register names */
+ {
+ "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh",
+ "ax", "cx", "dx", "bx", "sp", "bp", "si", "di",
+ "es", "cs", "ss", "ds"
+ };
+
+char *REGS0[] = /* Mode 0 register name table */
+ {
+ "bx_si", "bx_di", "bp_si", "bp_di", "si", "di", "", "bx"
+ };
+
+char *REGS1[] = /* Mode 1 register name table */
+ {
+ "bx_si", "bx_di", "bp_si", "bp_di", "si", "di", "bp", "bx"
+ };
+
+int symrank[6][6] = /* Symbol type/rank matrix */
+ {
+ /* UND ABS TXT DAT BSS COM */
+ /* UND */ 5, 4, 1, 2, 3, 0,
+ /* ABS */ 1, 5, 4, 3, 2, 0,
+ /* TXT */ 4, 1, 5, 3, 2, 0,
+ /* DAT */ 3, 1, 2, 5, 4, 0,
+ /* BSS */ 3, 1, 2, 4, 5, 0,
+ /* COM */ 2, 0, 1, 3, 4, 5
+ };
+
+ /* * * * * * * * * * * * OPCODE DATA * * * * * * * * * * * */
+
+char ADD[] = "\tadd", /* Mnemonics by family */
+ OR[] = "\tor",
+ ADC[] = "\tadc",
+ SBB[] = "\tsbb",
+ AND[] = "\tand",
+ SUB[] = "\tsub",
+ XOR[] = "\txor",
+ CMP[] = "\tcmp",
+ NOT[] = "\tnot",
+ NEG[] = "\tneg",
+ MUL[] = "\tmul",
+ DIV[] = "\tdiv",
+ MOV[] = "\tmov",
+ ESC[] = "\tesc",
+ TEST[] = "\ttest",
+ AMBIG[] = "",
+ ROL[] = "\trol",
+ ROR[] = "\tror",
+ RCL[] = "\trcl",
+ RCR[] = "\trcr",
+ SAL[] = "\tsal",
+ SHR[] = "\tshr",
+ SHL[] = "\tshl",
+ SAR[] = "\tsar";
+
+char *OPFAM[] = /* Family lookup table */
+ {
+ ADD, OR, ADC, SBB, AND, SUB, XOR, CMP,
+ NOT, NEG, MUL, DIV, MOV, ESC, TEST, AMBIG,
+ ROL, ROR, RCL, RCR, SAL, SHR, SHL, SAR
+ };
+
+struct opcode optab[] = /* Table of opcode data */
+ {
+ ADD, aohand, 2, 4, /* 0x00 */
+ ADD, aohand, 2, 4, /* 0x01 */
+ ADD, aohand, 2, 4, /* 0x02 */
+ ADD, aohand, 2, 4, /* 0x03 */
+ ADD, aohand, 2, 2, /* 0x04 */
+ ADD, aohand, 3, 3, /* 0x05 */
+ "\tpush\tes", sbhand, 1, 1, /* 0x06 */
+ "\tpop\tes", sbhand, 1, 1, /* 0x07 */
+ OR, aohand, 2, 4, /* 0x08 */
+ OR, aohand, 2, 4, /* 0x09 */
+ OR, aohand, 2, 4, /* 0x0a */
+ OR, aohand, 2, 4, /* 0x0b */
+ OR, aohand, 2, 2, /* 0x0c */
+ OR, aohand, 3, 3, /* 0x0d */
+ "\tpush\tcs", sbhand, 1, 1, /* 0x0e */
+ NULL, dfhand, 0, 0, /* 0x0f */
+ ADC, aohand, 2, 4, /* 0x10 */
+ ADC, aohand, 2, 4, /* 0x11 */
+ ADC, aohand, 2, 4, /* 0x12 */
+ ADC, aohand, 2, 4, /* 0x13 */
+ ADC, aohand, 2, 2, /* 0x14 */
+ ADC, aohand, 3, 3, /* 0x15 */
+ "\tpush\tss", sbhand, 1, 1, /* 0x16 */
+ "\tpop\tss", sbhand, 1, 1, /* 0x17 */
+ SBB, aohand, 2, 4, /* 0x18 */
+ SBB, aohand, 2, 4, /* 0x19 */
+ SBB, aohand, 2, 4, /* 0x1a */
+ SBB, aohand, 2, 4, /* 0x1b */
+ SBB, aohand, 2, 2, /* 0x1c */
+ SBB, aohand, 3, 3, /* 0x1d */
+ "\tpush\tds", sbhand, 1, 1, /* 0x1e */
+ "\tpop\tds", sbhand, 1, 1, /* 0x1f */
+ AND, aohand, 2, 4, /* 0x20 */
+ AND, aohand, 2, 4, /* 0x21 */
+ AND, aohand, 2, 4, /* 0x22 */
+ AND, aohand, 2, 4, /* 0x23 */
+ AND, aohand, 2, 2, /* 0x24 */
+ AND, aohand, 3, 3, /* 0x25 */
+ "\tseg\tes", sbhand, 1, 1, /* 0x26 */
+ "\tdaa", sbhand, 1, 1, /* 0x27 */
+ SUB, aohand, 2, 4, /* 0x28 */
+ SUB, aohand, 2, 4, /* 0x29 */
+ SUB, aohand, 2, 4, /* 0x2a */
+ SUB, aohand, 2, 4, /* 0x2b */
+ SUB, aohand, 2, 2, /* 0x2c */
+ SUB, aohand, 3, 3, /* 0x2d */
+ "\tseg\tcs", sbhand, 1, 1, /* 0x2e */
+ "\tdas", sbhand, 1, 1, /* 0x2f */
+ XOR, aohand, 2, 4, /* 0x30 */
+ XOR, aohand, 2, 4, /* 0x31 */
+ XOR, aohand, 2, 4, /* 0x32 */
+ XOR, aohand, 2, 4, /* 0x33 */
+ XOR, aohand, 2, 2, /* 0x34 */
+ XOR, aohand, 3, 3, /* 0x35 */
+ "\tseg\tss", sbhand, 1, 1, /* 0x36 */
+ "\taaa", sbhand, 1, 1, /* 0x37 */
+ CMP, aohand, 2, 4, /* 0x38 */
+ CMP, aohand, 2, 4, /* 0x39 */
+ CMP, aohand, 2, 4, /* 0x3a */
+ CMP, aohand, 2, 4, /* 0x3b */
+ CMP, aohand, 2, 2, /* 0x3c */
+ CMP, aohand, 3, 3, /* 0x3d */
+ "\tseg\tds", sbhand, 1, 1, /* 0x3e */
+ "\taas", sbhand, 1, 1, /* 0x3f */
+ "\tinc\tax", sbhand, 1, 1, /* 0x40 */
+ "\tinc\tcx", sbhand, 1, 1, /* 0x41 */
+ "\tinc\tdx", sbhand, 1, 1, /* 0x42 */
+ "\tinc\tbx", sbhand, 1, 1, /* 0x43 */
+ "\tinc\tsp", sbhand, 1, 1, /* 0x44 */
+ "\tinc\tbp", sbhand, 1, 1, /* 0x45 */
+ "\tinc\tsi", sbhand, 1, 1, /* 0x46 */
+ "\tinc\tdi", sbhand, 1, 1, /* 0x47 */
+ "\tdec\tax", sbhand, 1, 1, /* 0x48 */
+ "\tdec\tcx", sbhand, 1, 1, /* 0x49 */
+ "\tdec\tdx", sbhand, 1, 1, /* 0x4a */
+ "\tdec\tbx", sbhand, 1, 1, /* 0x4b */
+ "\tdec\tsp", sbhand, 1, 1, /* 0x4c */
+ "\tdec\tbp", sbhand, 1, 1, /* 0x4d */
+ "\tdec\tsi", sbhand, 1, 1, /* 0x4e */
+ "\tdec\tdi", sbhand, 1, 1, /* 0x4f */
+ "\tpush\tax", sbhand, 1, 1, /* 0x50 */
+ "\tpush\tcx", sbhand, 1, 1, /* 0x51 */
+ "\tpush\tdx", sbhand, 1, 1, /* 0x52 */
+ "\tpush\tbx", sbhand, 1, 1, /* 0x53 */
+ "\tpush\tsp", sbhand, 1, 1, /* 0x54 */
+ "\tpush\tbp", sbhand, 1, 1, /* 0x55 */
+ "\tpush\tsi", sbhand, 1, 1, /* 0x56 */
+ "\tpush\tdi", sbhand, 1, 1, /* 0x57 */
+ "\tpop\tax", sbhand, 1, 1, /* 0x58 */
+ "\tpop\tcx", sbhand, 1, 1, /* 0x59 */
+ "\tpop\tdx", sbhand, 1, 1, /* 0x5a */
+ "\tpop\tbx", sbhand, 1, 1, /* 0x5b */
+ "\tpop\tsp", sbhand, 1, 1, /* 0x5c */
+ "\tpop\tbp", sbhand, 1, 1, /* 0x5d */
+ "\tpop\tsi", sbhand, 1, 1, /* 0x5e */
+ "\tpop\tdi", sbhand, 1, 1, /* 0x5f */
+ NULL, dfhand, 0, 0, /* 0x60 */
+ NULL, dfhand, 0, 0, /* 0x61 */
+ NULL, dfhand, 0, 0, /* 0x62 */
+ NULL, dfhand, 0, 0, /* 0x63 */
+ NULL, dfhand, 0, 0, /* 0x64 */
+ NULL, dfhand, 0, 0, /* 0x65 */
+ NULL, dfhand, 0, 0, /* 0x66 */
+ NULL, dfhand, 0, 0, /* 0x67 */
+ NULL, dfhand, 0, 0, /* 0x68 */
+ NULL, dfhand, 0, 0, /* 0x69 */
+ NULL, dfhand, 0, 0, /* 0x6a */
+ NULL, dfhand, 0, 0, /* 0x6b */
+ NULL, dfhand, 0, 0, /* 0x6c */
+ NULL, dfhand, 0, 0, /* 0x6d */
+ NULL, dfhand, 0, 0, /* 0x6e */
+ NULL, dfhand, 0, 0, /* 0x6f */
+ "\tjo", sjhand, 2, 2, /* 0x70 */
+ "\tjno", sjhand, 2, 2, /* 0x71 */
+ "\tjc", sjhand, 2, 2, /* 0x72 */
+ "\tjnc", sjhand, 2, 2, /* 0x73 */
+ "\tjz", sjhand, 2, 2, /* 0x74 */
+ "\tjnz", sjhand, 2, 2, /* 0x75 */
+ "\tjna", sjhand, 2, 2, /* 0x76 */
+ "\tja", sjhand, 2, 2, /* 0x77 */
+ "\tjs", sjhand, 2, 2, /* 0x78 */
+ "\tjns", sjhand, 2, 2, /* 0x79 */
+ "\tjp", sjhand, 2, 2, /* 0x7a */
+ "\tjnp", sjhand, 2, 2, /* 0x7b */
+ "\tjl", sjhand, 2, 2, /* 0x7c */
+ "\tjnl", sjhand, 2, 2, /* 0x7d */
+ "\tjng", sjhand, 2, 2, /* 0x7e */
+ "\tjg", sjhand, 2, 2, /* 0x7f */
+ AMBIG, imhand, 3, 5, /* 0x80 */
+ AMBIG, imhand, 4, 6, /* 0x81 */
+ AMBIG, imhand, 3, 5, /* 0x82 */
+ AMBIG, imhand, 3, 5, /* 0x83 */
+ TEST, mvhand, 2, 4, /* 0x84 */
+ TEST, mvhand, 2, 4, /* 0x85 */
+ "\txchg", mvhand, 2, 4, /* 0x86 */
+ "\txchg", mvhand, 2, 4, /* 0x87 */
+ MOV, mvhand, 2, 4, /* 0x88 */
+ MOV, mvhand, 2, 4, /* 0x89 */
+ MOV, mvhand, 2, 4, /* 0x8a */
+ MOV, mvhand, 2, 4, /* 0x8b */
+ MOV, mshand, 2, 4, /* 0x8c */
+ "\tlea", mvhand, 2, 4, /* 0x8d */
+ MOV, mshand, 2, 4, /* 0x8e */
+ "\tpop", pohand, 2, 4, /* 0x8f */
+ "\tnop", sbhand, 1, 1, /* 0x90 */
+ "\txchg\tax,cx", sbhand, 1, 1, /* 0x91 */
+ "\txchg\tax,dx", sbhand, 1, 1, /* 0x92 */
+ "\txchg\tax,bx", sbhand, 1, 1, /* 0x93 */
+ "\txchg\tax,sp", sbhand, 1, 1, /* 0x94 */
+ "\txchg\tax,bp", sbhand, 1, 1, /* 0x95 */
+ "\txchg\tax,si", sbhand, 1, 1, /* 0x96 */
+ "\txchg\tax,di", sbhand, 1, 1, /* 0x97 */
+ "\tcbw", sbhand, 1, 1, /* 0x98 */
+ "\tcwd", sbhand, 1, 1, /* 0x99 */
+ "\tcalli", cihand, 5, 5, /* 0x9a */
+ "\twait", sbhand, 1, 1, /* 0x9b */
+ "\tpushf", sbhand, 1, 1, /* 0x9c */
+ "\tpopf", sbhand, 1, 1, /* 0x9d */
+ "\tsahf", sbhand, 1, 1, /* 0x9e */
+ "\tlahf", sbhand, 1, 1, /* 0x9f */
+ MOV, mqhand, 3, 3, /* 0xa0 */
+ MOV, mqhand, 3, 3, /* 0xa1 */
+ MOV, mqhand, 3, 3, /* 0xa2 */
+ MOV, mqhand, 3, 3, /* 0xa3 */
+ "\tmovb", sbhand, 1, 1, /* 0xa4 */
+ "\tmovw", sbhand, 1, 1, /* 0xa5 */
+ "\tcmpb", sbhand, 1, 1, /* 0xa6 */
+ "\tcmpw", sbhand, 1, 1, /* 0xa7 */
+ TEST, tqhand, 2, 2, /* 0xa8 */
+ TEST, tqhand, 3, 3, /* 0xa9 */
+ "\tstob", sbhand, 1, 1, /* 0xaa */
+ "\tstow", sbhand, 1, 1, /* 0xab */
+ "\tlodb", sbhand, 1, 1, /* 0xac */
+ "\tlodw", sbhand, 1, 1, /* 0xad */
+ "\tscab", sbhand, 1, 1, /* 0xae */
+ "\tscaw", sbhand, 1, 1, /* 0xaf */
+ "\tmov\tal,", mihand, 2, 2, /* 0xb0 */
+ "\tmov\tcl,", mihand, 2, 2, /* 0xb1 */
+ "\tmov\tdl,", mihand, 2, 2, /* 0xb2 */
+ "\tmov\tbl,", mihand, 2, 2, /* 0xb3 */
+ "\tmov\tah,", mihand, 2, 2, /* 0xb4 */
+ "\tmov\tch,", mihand, 2, 2, /* 0xb5 */
+ "\tmov\tdh,", mihand, 2, 2, /* 0xb6 */
+ "\tmov\tbh,", mihand, 2, 2, /* 0xb7 */
+ "\tmov\tax,", mihand, 3, 3, /* 0xb8 */
+ "\tmov\tcx,", mihand, 3, 3, /* 0xb9 */
+ "\tmov\tdx,", mihand, 3, 3, /* 0xba */
+ "\tmov\tbx,", mihand, 3, 3, /* 0xbb */
+ "\tmov\tsp,", mihand, 3, 3, /* 0xbc */
+ "\tmov\tbp,", mihand, 3, 3, /* 0xbd */
+ "\tmov\tsi,", mihand, 3, 3, /* 0xbe */
+ "\tmov\tdi,", mihand, 3, 3, /* 0xbf */
+ NULL, dfhand, 0, 0, /* 0xc0 */
+ NULL, dfhand, 0, 0, /* 0xc1 */
+ "\tret", rehand, 3, 3, /* 0xc2 */
+ "\tret", sbhand, 1, 1, /* 0xc3 */
+ "\tles", mvhand, 2, 4, /* 0xc4 */
+ "\tlds", mvhand, 2, 4, /* 0xc5 */
+ MOV, mmhand, 3, 5, /* 0xc6 */
+ MOV, mmhand, 4, 6, /* 0xc7 */
+ NULL, dfhand, 0, 0, /* 0xc8 */
+ NULL, dfhand, 0, 0, /* 0xc9 */
+ "\treti", rehand, 3, 3, /* 0xca */
+ "\treti", sbhand, 1, 1, /* 0xcb */
+ "\tint", sbhand, 1, 1, /* 0xcc */
+ "\tint", inhand, 2, 2, /* 0xcd */
+ "\tinto", sbhand, 1, 1, /* 0xce */
+ "\tiret", sbhand, 1, 1, /* 0xcf */
+ AMBIG, srhand, 2, 4, /* 0xd0 */
+ AMBIG, srhand, 2, 4, /* 0xd1 */
+ AMBIG, srhand, 2, 4, /* 0xd2 */
+ AMBIG, srhand, 2, 4, /* 0xd3 */
+ "\taam", aahand, 2, 2, /* 0xd4 */
+ "\taad", aahand, 2, 2, /* 0xd5 */
+ NULL, dfhand, 0, 0, /* 0xd6 */
+ "\txlat", sbhand, 1, 1, /* 0xd7 */
+ ESC, eshand, 2, 2, /* 0xd8 */
+ ESC, eshand, 2, 2, /* 0xd9 */
+ ESC, eshand, 2, 2, /* 0xda */
+ ESC, eshand, 2, 2, /* 0xdb */
+ ESC, eshand, 2, 2, /* 0xdc */
+ ESC, eshand, 2, 2, /* 0xdd */
+ ESC, eshand, 2, 2, /* 0xde */
+ ESC, eshand, 2, 2, /* 0xdf */
+ "\tloopne", sjhand, 2, 2, /* 0xe0 */
+ "\tloope", sjhand, 2, 2, /* 0xe1 */
+ "\tloop", sjhand, 2, 2, /* 0xe2 */
+ "\tjcxz", sjhand, 2, 2, /* 0xe3 */
+ "\tin", iohand, 2, 2, /* 0xe4 */
+ "\tinw", iohand, 2, 2, /* 0xe5 */
+ "\tout", iohand, 2, 2, /* 0xe6 */
+ "\toutw", iohand, 2, 2, /* 0xe7 */
+ "\tcall", ljhand, 3, 3, /* 0xe8 */
+ "\tjmp", ljhand, 3, 3, /* 0xe9 */
+ "\tjmpi", cihand, 5, 5, /* 0xea */
+ "\tj", sjhand, 2, 2, /* 0xeb */
+ "\tin", sbhand, 1, 1, /* 0xec */
+ "\tinw", sbhand, 1, 1, /* 0xed */
+ "\tout", sbhand, 1, 1, /* 0xee */
+ "\toutw", sbhand, 1, 1, /* 0xef */
+ "\tlock", sbhand, 1, 1, /* 0xf0 */
+ NULL, dfhand, 0, 0, /* 0xf1 */
+ "\trepnz", sbhand, 1, 1, /* 0xf2 */
+ "\trepz", sbhand, 1, 1, /* 0xf3 */
+ "\thlt", sbhand, 1, 1, /* 0xf4 */
+ "\tcmc", sbhand, 1, 1, /* 0xf5 */
+ AMBIG, mahand, 2, 5, /* 0xf6 */
+ AMBIG, mahand, 2, 6, /* 0xf7 */
+ "\tclc", sbhand, 1, 1, /* 0xf8 */
+ "\tstc", sbhand, 1, 1, /* 0xf9 */
+ "\tcli", sbhand, 1, 1, /* 0xfa */
+ "\tsti", sbhand, 1, 1, /* 0xfb */
+ "\tcld", sbhand, 1, 1, /* 0xfc */
+ "\tstd", sbhand, 1, 1, /* 0xfd */
+ AMBIG, mjhand, 2, 4, /* 0xfe */
+ AMBIG, mjhand, 2, 4 /* 0xff */
+ };
+
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * *
+ * This simple routine returns the name field of a symbol *
+ * table entry as a printable string. *
+ * *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+char *
+getnam(k)
+
+ register int k;
+
+{/* * * * * * * * * * START OF getnam() * * * * * * * * * */
+
+ register int j;
+ static char a[9];
+
+ for (j = 0; j < 8; ++j)
+ if ( ! symtab[k].n_name[j] )
+ break;
+ else
+ a[j] = symtab[k].n_name[j];
+
+ a[j] = '\0';
+
+ return (a);
+
+}/* * * * * * * * * * * END OF getnam() * * * * * * * * * * */
+
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * *
+ * This function is responsible for mucking through the *
+ * relocation table in search of externally referenced *
+ * symbols to be output as operands. It accepts two long *
+ * arguments: the code-segment location at which an extern *
+ * reference is expected, and the offset value which is *
+ * embedded in the object code and used at link time to *
+ * bias the external value. In the most typical case, the *
+ * function will be called by lookup(), which always makes *
+ * a check for external names before searching the symbol *
+ * table proper. However, it may also be called directly *
+ * by any function (such as the move-immediate handler) *
+ * which wants to make an independent check for externals. *
+ * The caller is expected to supply, as the third argument *
+ * to the function, a pointer to a character buffer large *
+ * enough to hold any possible output string. Lookext() *
+ * will fill this buffer and return a logical TRUE if it *
+ * finds an extern reference; otherwise, it will return a *
+ * logical FALSE, leaving the buffer undisturbed. *
+ * *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+int
+lookext(off,loc,buf)
+
+ long off, loc;
+ char *buf;
+
+{/* * * * * * * * * * START OF lookext() * * * * * * * * * */
+
+ register int k;
+ char c[16];
+
+ if ((loc != -1L) && (relptr >= 0))
+ for (k = 0; k <= relptr; ++k)
+ if ((relo[k].r_vaddr == loc)
+ && (relo[k].r_symndx < S_BSS))
+ {
+ strcpy(buf,getnam(relo[k].r_symndx));
+ if (off)
+ {
+ if (off < 0)
+ sprintf(c,"%ld",off);
+ else
+ sprintf(c,"+%ld",off);
+ strcat(buf,c);
+ }
+ return (1);
+ }
+
+ return (0);
+
+}/* * * * * * * * * * END OF lookext() * * * * * * * * * */
+
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * *
+ * This function finds an entry in the symbol table by *
+ * value. Its input is a (long) machine address, and its *
+ * output is a pointer to a string containing the corre- *
+ * sponding symbolic name. The function first searches the *
+ * relocation table for a possible external reference; if *
+ * none is found, a linear search of the symbol table is *
+ * undertaken. If no matching symbol has been found at the *
+ * end of these searches, the function returns a pointer *
+ * to a string containing the ASCII equivalent of the ad- *
+ * dress which was to be located, so that, regardless of *
+ * the success of the search, the function's return value *
+ * is suitable for use as a memory-reference operand. The *
+ * caller specifies the type of symbol to be found (text, *
+ * data, bss, undefined, absolute, or common) by means of *
+ * the function's second parameter. The third parameter *
+ * specifies the format to be used in the event of a nu- *
+ * meric output: zero for absolute format, one for short *
+ * relative format, two for long relative format. The *
+ * fourth parameter is the address which would appear in *
+ * the relocation table for the reference in question, or *
+ * -1 if the relocation table is not to be searched. The *
+ * function attempts to apply a certain amount of intelli- *
+ * gence in its selection of symbols, so it is possible *
+ * that, in the absence of a type match, a symbol of the *
+ * correct value but different type will be returned. *
+ * *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+char *
+lookup(addr,type,kind,ext)
+
+ long addr; /* Machine address to be located */
+
+ int type, /* Type of symbol to be matched */
+ kind; /* Addressing output mode to use */
+
+ long ext; /* Value for extern ref, if any */
+
+{/* * * * * * * * * * START OF lookup() * * * * * * * * * */
+
+ register int j, k;
+ static char b[64];
+
+ struct
+ {
+ int i;
+ int t;
+ }
+ best;
+
+ if (lookext(addr,ext,b))
+ return (b);
+
+ if (segflg)
+ if (segflg & 1)
+ type = N_TEXT;
+ else
+ type = N_DATA;
+
+ for (k = 0, best.i = -1; k <= symptr; ++k)
+ if (symtab[k].n_value == addr)
+ if ((j = symtab[k].n_sclass & N_SECT) == type)
+ {
+ best.t = j;
+ best.i = k;
+ break;
+ }
+ else if (segflg || (HDR.a_flags & A_SEP))
+ continue;
+ else if (best.i < 0)
+ best.t = j, best.i = k;
+ else if (symrank[type][j] > symrank[type][best.t])
+ best.t = j, best.i = k;
+
+ if (best.i >= 0)
+ return (getnam(best.i));
+
+ if (kind == LOOK_ABS)
+ sprintf(b,"0x%05.5x",addr);
+ else
+ {
+ long x = addr - (PC - kind);
+ if (x < 0)
+ sprintf(b,".%ld",x);
+ else
+ sprintf(b,".+%ld",x);
+ }
+
+ return (b);
+
+}/* * * * * * * * * * * END OF lookup() * * * * * * * * * * */
+
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * *
+ * This function translates an 8088 addressing mode byte *
+ * to an equivalent assembler string, returning a pointer *
+ * thereto. If necessary, it performs successive inputs *
+ * of bytes from the object file in order to obtain offset *
+ * data, adjusting PC accordingly. (The addressing mode *
+ * byte appears in several 8088 opcodes; it is used to *
+ * specify source and destination operand locations.) The *
+ * third argument to the function is zero if the standard *
+ * registers are to be used, or eight if the segment reg- *
+ * isters are to be used; these constants are defined sym- *
+ * bolically in dis.h. NOTE: The mtrans() function must *
+ * NEVER be called except immediately after fetching the *
+ * mode byte. If any additional object bytes are fetched *
+ * after the fetch of the mode byte, mtrans() will not *
+ * produce correct output! *
+ * *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+char *
+mtrans(c,m,type)
+
+ register int c; /* Primary instruction byte */
+ register int m; /* Addressing mode byte */
+
+ int type; /* Type code: standard or seg */
+
+{/* * * * * * * * * * START OF mtrans() * * * * * * * * * */
+
+ unsigned long pc;
+ int offset, oflag, dir, w, mod, reg, rm;
+ static char a[100];
+ static char b[30];
+
+ offset = 0;
+ dir = c & 2;
+ w = c & 1;
+ mod = (m & 0xc0) >> 6;
+ reg = (m & 0x38) >> 3;
+ rm = m & 7;
+ pc = PC + 1;
+
+ if (type)
+ w = 1;
+
+ if ((oflag = mod) > 2)
+ oflag = 0;
+
+ if (oflag)
+ {
+ int j, k;
+ if (oflag == 2)
+ {
+ FETCH(j);
+ FETCH(k);
+ offset = (k << 8) | j;
+ }
+ else
+ {
+ FETCH(j);
+ if (j & 0x80)
+ k = 0xff00;
+ else
+ k = 0;
+ offset = k | j;
+ }
+ }
+
+ if (dir)
+ {
+ strcpy(a,REGS[type + ((w << 3) | reg)]);
+ strcat(a,",");
+ switch (mod)
+ {
+ case 0 :
+ if (rm == 6)
+ {
+ int j, k;
+ FETCH(j);
+ FETCH(k);
+ offset = (k << 8) | j;
+ strcat(a,
+ lookup((long)(offset),N_DATA,LOOK_ABS,pc));
+ }
+ else
+ {
+ sprintf(b,"(%s)",REGS0[rm]);
+ strcat(a,b);
+ }
+ break;
+ case 1 :
+ case 2 :
+ if (mod == 1)
+ strcat(a,"*");
+ else
+ strcat(a,"#");
+ sprintf(b,"%d(",offset);
+ strcat(a,b);
+ strcat(a,REGS1[rm]);
+ strcat(a,")");
+ break;
+ case 3 :
+ strcat(a,REGS[(w << 3) | rm]);
+ break;
+ }
+ }
+ else
+ {
+ switch (mod)
+ {
+ case 0 :
+ if (rm == 6)
+ {
+ int j, k;
+ FETCH(j);
+ FETCH(k);
+ offset = (k << 8) | j;
+ strcpy(a,
+ lookup((long)(offset),N_DATA,LOOK_ABS,pc));
+ }
+ else
+ {
+ sprintf(b,"(%s)",REGS0[rm]);
+ strcpy(a,b);
+ }
+ break;
+ case 1 :
+ case 2 :
+ if (mod == 1)
+ strcpy(a,"*");
+ else
+ strcpy(a,"#");
+ sprintf(b,"%d(",offset);
+ strcat(a,b);
+ strcat(a,REGS1[rm]);
+ strcat(a,")");
+ break;
+ case 3 :
+ strcpy(a,REGS[(w << 3) | rm]);
+ break;
+ }
+ strcat(a,",");
+ strcat(a,REGS[type + ((w << 3) | reg)]);
+ }
+
+ return (a);
+
+}/* * * * * * * * * * * END OF mtrans() * * * * * * * * * * */
+
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * *
+ * This simple routine truncates a string returned by the *
+ * mtrans() function, removing its source operand. This is *
+ * useful in handlers which ignore the "reg" field of the *
+ * mode byte. *
+ * *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+void
+mtrunc(a)
+
+ register char *a; /* Ptr. to string to truncate */
+
+{/* * * * * * * * * * START OF mtrunc() * * * * * * * * * */
+
+ register int k;
+
+ for (k = strlen(a) - 1; k >= 0; --k)
+ if (a[k] == ',')
+ {
+ a[k] = '\0';
+ break;
+ }
+
+}/* * * * * * * * * * * END OF mtrunc() * * * * * * * * * * */
+
+
diff --git a/part01 b/part01
new file mode 100644
index 0000000..f78b652
--- /dev/null
+++ b/part01
@@ -0,0 +1,1448 @@
+Subject: v15i006: Symbolic disassembler for PC/IX, Part01/02
+Newsgroups: comp.sources.unix
+Sender: sources
+Approved: rsalz@uunet.UU.NET
+
+Submitted-by: "G. M. Harding" <gm@uts.amdahl.com>
+Posting-number: Volume 15, Issue 6
+Archive-name: dis88/part01
+
+[ I packed up the archives and turned the formatted manpage
+ into an unformatted one. --r$ ]
+
+ "Dis88" is a symbolic disassembler for the Intel 8088 CPU,
+ designed to run under the PC/IX operating system on an IBM XT
+ or fully-compatible clone. Its output is in the format of, and
+ is completely compatible with, the PC/IX assembler, "as". The
+ program is copyrighted by its author, but may be copied and re-
+ distributed freely provided that complete source code, with all
+ copyright notices, accompanies any distribution. This provision
+ also applies to any modifications you may make. You are urged
+ to comment such changes, giving, as a miminum, your name and
+ complete address.
+
+ ---
+ G. M. HARDING
+ POB 4142
+ Santa Clara CA 95054-0142
+
+#! /bin/sh
+# This is a shell archive. Remove anything before this line, then unpack
+# it by saving it into a file and typing "sh file". To overwrite existing
+# files, type "sh file -c". You can also feed this as standard input via
+# unshar, or by typing "sh <file", e.g.. If this archive is complete, you
+# will see the following message at the end:
+# "End of archive 1 (of 2)."
+PATH=/bin:/usr/bin:/usr/ucb ; export PATH
+if test -f 'MANIFEST' -a "${1}" != "-c" ; then
+ echo shar: Will not clobber existing file \"'MANIFEST'\"
+else
+echo shar: Extracting \"'MANIFEST'\" \(406 characters\)
+sed "s/^X//" >'MANIFEST' <<'END_OF_FILE'
+X File Name Archive # Description
+X-----------------------------------------------------------
+X MANIFEST 1
+X Makefile 1
+X README 1
+X dis.h 1
+X dis88.1 1
+X disfp.c 1
+X dishand.c 2
+X dismain.c 1
+X disrel.c 1
+X distabs.c 2
+END_OF_FILE
+if test 406 -ne `wc -c <'MANIFEST'`; then
+ echo shar: \"'MANIFEST'\" unpacked with wrong size!
+fi
+# end of 'MANIFEST'
+fi
+if test -f 'Makefile' -a "${1}" != "-c" ; then
+ echo shar: Will not clobber existing file \"'Makefile'\"
+else
+echo shar: Extracting \"'Makefile'\" \(1593 characters\)
+sed "s/^X//" >'Makefile' <<'END_OF_FILE'
+X# @(#) Makefile, Ver. 2.1 created 00:00:00 87/09/01
+X# Makefile for 8088 symbolic disassembler
+X
+X# Copyright (C) 1987 G. M. Harding, all rights reserved.
+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 Makefile automates the process of compiling and linking
+X# a symbolic object-file disassembler program for the Intel
+X# 8088 CPU. Relatively machine-independent code is contained in
+X# the file dismain.c; lookup tables and handler routines, which
+X# are by their nature machine-specific, are contained in two
+X# files named distabs.c and dishand.c, respectively. (A third
+X# machine-specific file, disfp.c, contains handler routines for
+X# floating-point coprocessor opcodes.) A header file, dis.h,
+X# attempts to mediate between the machine-specific and machine-
+X# independent portions of the code. An attempt has been made to
+X# isolate machine dependencies and to deal with them in fairly
+X# straightforward ways. Thus, it should be possible to target a
+X# different CPU by rewriting the handler routines and changing
+X# the initialization data in the lookup tables. It should not
+X# be necessary to alter the formats of the tables.
+X
+OBJ = disrel.o dismain.o distabs.o dishand.o disfp.o
+X
+dis88 : $(OBJ)
+X ld -i -s -o dis88 /lib/crt0.o $(OBJ) -lc
+X size dis88
+X @echo "\07Build of 'dis88' complete." > /dev/tty
+X
+X.c.o :
+X cc -O -c $<
+X chmod 600 $*.o
+X
+disrel.o : disrel.c
+X
+dismain.o : dismain.c dis.h
+X
+distabs.o : distabs.c dis.h
+X
+dishand.o : dishand.c dis.h
+X
+disfp.o : disfp.c dis.h
+X
+END_OF_FILE
+if test 1593 -ne `wc -c <'Makefile'`; then
+ echo shar: \"'Makefile'\" unpacked with wrong size!
+fi
+# end of 'Makefile'
+fi
+if test -f 'README' -a "${1}" != "-c" ; then
+ echo shar: Will not clobber existing file \"'README'\"
+else
+echo shar: Extracting \"'README'\" \(4898 characters\)
+sed "s/^X//" >'README' <<'END_OF_FILE'
+X dis88
+X Beta Release
+X 87/09/01
+X ---
+X G. M. HARDING
+X POB 4142
+X Santa Clara CA 95054-0142
+X
+X
+X "Dis88" is a symbolic disassembler for the Intel 8088 CPU,
+X designed to run under the PC/IX operating system on an IBM XT
+X or fully-compatible clone. Its output is in the format of, and
+X is completely compatible with, the PC/IX assembler, "as". The
+X program is copyrighted by its author, but may be copied and re-
+X distributed freely provided that complete source code, with all
+X copyright notices, accompanies any distribution. This provision
+X also applies to any modifications you may make. You are urged
+X to comment such changes, giving, as a miminum, your name and
+X complete address.
+X
+X This release of the program is a beta release, which means
+X that it has been extensively, but not exhaustively, tested.
+X User comments, recommendations, and bug fixes are welcome. The
+X principal features of the current release are:
+X
+X (a) The ability to disassemble any file in PC/IX object
+X format, making full use of symbol and relocation information if
+X it is present, regardless of whether the file is executable or
+X linkable, and regardless of whether it has continuous or split
+X I/D space;
+X
+X (b) Automatic generation of synthetic labels when no sym-
+X bol table is available; and
+X
+X (c) Optional output of address and object-code informa-
+X tion as assembler comment text.
+X
+X Limitations of the current release are:
+X
+X (a) Numeric co-processor (i.e., 8087) mnemonics are not
+X supported. Instructions for the co-processor are disassembled
+X as CPU escape sequences, or as interrupts, depending on how
+X they were assembled in the first place. This limitation will be
+X addressed in a future release.
+X
+X (b) Symbolic references within the object file's data
+X segment are not supported. Thus, for example, if a data segment
+X location is initialized to point to a text segment address, no
+X reference to a text segment symbol will be detected. This limi-
+X tation is likely to remain in future releases, because object
+X code does not, in most cases, contain sufficient information to
+X allow meaningful interpretation of pure data. (Note, however,
+X that symbolic references to the data segment from within the
+X text segment are always supported.)
+X
+X As a final caveat, be aware that the PC/IX assembler does
+X not recognize the "esc" mnemonic, even though it refers to a
+X completely valid CPU operation which is documented in all the
+X Intel literature. Thus, the corresponding opcodes (0xd8 through
+X 0xdf) are disassembled as .byte directives. For reference, how-
+X ever, the syntactically-correct "esc" instruction is output as
+X a comment.
+X
+X To build the disassembler program, transfer all the source
+X files, together with the Makefile, to a suitable (preferably
+X empty) PC/IX directory. Then, simply type "make".
+X
+X To use dis88, place it in a directory which appears in
+X your $PATH list. It may then be invoked by name from whatever
+X directory you happen to be in. As a minimum, the program must
+X be invoked with one command-line argument: the name of the ob-
+X ject file to be disassembled. (Dis88 will complain if the file
+X specified is not an object file.) Optionally, you may specify
+X an output file; stdout is the default. One command-line switch
+X is available: "-o", which makes the program display addresses
+X and object code along with its mnemonic disassembly.
+X
+X The "-o" option is useful primarily for verifying the cor-
+X rectness of the program's output. In particular, it may be used
+X to check the accuracy of local relative jump opcodes. These
+X jumps often target local labels, which are lost at assembly
+X time; thus, the disassembly may contain cryptic instructions
+X like "jnz .+39". As a user convenience, all relative jump and
+X call opcodes are output with a comment which identifies the
+X physical target address.
+X
+X By convention, the release level of the program as a whole
+X is the SID of the file disrel.c, and this SID string appears in
+X each disassembly. Release 2.1 of the program is the first beta
+X release to be distributed on Usenet.
+X
+END_OF_FILE
+if test 4898 -ne `wc -c <'README'`; then
+ echo shar: \"'README'\" unpacked with wrong size!
+fi
+# end of 'README'
+fi
+if test -f 'dis.h' -a "${1}" != "-c" ; then
+ echo shar: Will not clobber existing file \"'dis.h'\"
+else
+echo shar: Extracting \"'dis.h'\" \(7563 characters\)
+sed "s/^X//" >'dis.h' <<'END_OF_FILE'
+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#include <fcntl.h> /* System file-control definitions */
+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
+extern struct nlist /* Array to hold the symbol table */
+X symtab[MAXSYM];
+X
+extern struct reloc /* Array to hold relocation table */
+X relo[MAXSYM];
+X
+extern int symptr; /* Index into the symtab[] array */
+X
+extern int relptr; /* Index into the relo[] array */
+X
+struct 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
+extern 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
+extern 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
+extern void eshand(), /* Bus-escape opcode handler */
+X fphand(), /* Floating-point handler */
+X inhand(); /* Interrupt-opcode handler */
+X
+extern char *REGS[]; /* Table of register names */
+X
+extern char *REGS0[]; /* Mode 0 register name table */
+X
+extern 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
+extern int symrank[6][6]; /* Symbol type/rank matrix */
+X
+extern unsigned long PC; /* Current program counter */
+X
+extern int segflg; /* Flag: segment override in effect */
+X
+extern int objflg; /* Flag: output object as a comment */
+X
+X#define OBJMAX 8 /* Size of the object code buffer */
+X
+extern unsigned char /* Internal buffer for object code */
+X objbuf[OBJMAX];
+X
+extern void objini(), /* Object-buffer init routine */
+X objout(); /* Object-code output routine */
+X
+extern int objptr; /* Index into the objbuf[] array */
+X
+extern void badseq(); /* Bad-code-sequence function */
+X
+extern char *getnam(); /* Symbol-name string function */
+X
+extern char *lookup(); /* Symbol-table lookup function */
+X
+extern int lookext(); /* Extern-definition lookup routine */
+X
+extern char *mtrans(); /* Interpreter for the mode byte */
+X
+extern void mtrunc(); /* Mode string truncator function */
+X
+extern 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
+extern char *OPFAM[]; /* Indexed mnemonic family table */
+X
+extern 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
+extern int close(); /* System file-close primitive */
+extern int fprintf(); /* Library file-output function */
+extern long lseek(); /* System file-position primitive */
+extern int open(); /* System file-open primitive */
+extern int printf(); /* Library output-format function */
+extern int read(); /* System file-read primitive */
+extern int sprintf(); /* Library string-output function */
+extern char *strcat(); /* Library string-join function */
+extern char *strcpy(); /* Library string-copy function */
+extern int strlen(); /* Library string-length function */
+X
+X /* * * * * * * * * * * END OF dis.h * * * * * * * * * * */
+X
+X
+END_OF_FILE
+if test 7563 -ne `wc -c <'dis.h'`; then
+ echo shar: \"'dis.h'\" unpacked with wrong size!
+fi
+# end of 'dis.h'
+fi
+if test -f 'dis88.1' -a "${1}" != "-c" ; then
+ echo shar: Will not clobber existing file \"'dis88.1'\"
+else
+echo shar: Extracting \"'dis88.1'\" \(6174 characters\)
+sed "s/^X//" >'dis88.1' <<'END_OF_FILE'
+X.TH dis88 1 LOCAL
+X.SH "NAME"
+dis88 \- 8088 symbolic disassembler
+X.SH "SYNOPSIS"
+X\fBdis88\fP [ -o ] ifile [ ofile ]
+X.SH "DESCRIPTION"
+Dis88 reads ifile, which must be in PC/IX a.out format.
+It interprets the binary opcodes and data locations, and
+writes corresponding assembler source code to stdout, or
+to ofile if specified. The program's output is in the
+format of, and fully compatible with, the PC/IX assembler,
+as(1). If a symbol table is present in ifile, labels and
+references will be symbolic in the output. If the input
+file lacks a symbol table, the fact will be noted, and the
+disassembly will proceed, with the disassembler generating
+synthetic labels as needed. If the input file has split
+I/D space, or if it is executable, the disassembler will
+make all necessary adjustments in address-reference calculations.
+X.PP
+If the "-o" option appears, object code will be included
+in comments during disassembly of the text segment. This
+feature is used primarily for debugging the disassembler
+itself, but may provide information of passing interest
+to users.
+X.PP
+The program always outputs the current machine address
+before disassembling an opcode. If a symbol table is
+present, this address is output as an assembler comment;
+otherwise, it is incorporated into the synthetic label
+which is generated internally. Since relative jumps,
+especially short ones, may target unlabelled locations,
+the program always outputs the physical target address
+as a comment, to assist the user in following the code.
+X.PP
+The text segment of an object file is always padded to
+an even machine address. In addition, if the file has
+split I/D space, the text segment will be padded to a
+paragraph boundary (i.e., an address divisible by 16).
+As a result of this padding, the disassembler may produce
+a few spurious, but harmless, instructions at the
+end of the text segment.
+X.PP
+Disassembly of the data segment is a difficult matter.
+The information to which initialized data refers cannot
+be inferred from context, except in the special case
+of an external data or address reference, which will be
+reflected in the relocation table. Internal data and
+address references will already be resolved in the object file,
+and cannot be recreated. Therefore, the data
+segment is disassembled as a byte stream, with long
+stretches of null data represented by an appropriate
+X".zerow" pseudo-op. This limitation notwithstanding,
+labels (as opposed to symbolic references) are always
+output at appropriate points within the data segment.
+X.PP
+If disassembly of the data segment is difficult, disassembly of the
+bss segment is quite easy, because uninitialized data is all
+zero by definition. No data
+is output in the bss segment, but symbolic labels are
+output as appropriate.
+X.PP
+XFor each opcode which takes an operand, a particular
+symbol type (text, data, or bss) is appropriate. This
+tidy correspondence is complicated somewhat, however,
+by the existence of assembler symbolic constants and
+segment override opcodes. Therefore, the disassembler's
+symbol lookup routine attempts to apply a certain amount
+of intelligence when it is asked to find a symbol. If
+it cannot match on a symbol of the preferred type, it
+may return a symbol of some other type, depending on
+preassigned (and somewhat arbitrary) rankings within
+each type. Finally, if all else fails, it returns a
+string containing the address sought as a hex constant;
+this behavior allows calling routines to use the output
+of the lookup function regardless of the success of its
+search.
+X.PP
+It is worth noting, at this point, that the symbol lookup
+routine operates linearly, and has not been optimized in
+any way. Execution time is thus likely to increase
+geometrically with input file size. The disassembler is
+internally limited to 1500 symbol table entries and 1500
+relocation table entries; while these limits are generous
+X(/unix, itself, has fewer than 800 symbols), they are not
+guaranteed to be adequate in all cases. If the symbol
+table or the relocation table overflows, the disassembly
+aborts.
+X.PP
+XFinally, users should be aware of a bug in the assembler,
+which causes it not to parse the "esc" mnemonic, even
+though "esc" is a completely legitimate opcode which is
+documented in all the Intel literature. To accommodate
+this deficiency, the disassembler translates opcodes of
+the "esc" family to .byte directives, but notes the
+correct mnemonic in a comment for reference.
+X.PP
+In all cases, it should be possible to submit the output
+of the disassembler program to the assembler, and assemble
+it without error. In most cases, the resulting object
+code will be identical to the original; in any event, it
+will be functionally equivalent.
+X.SH "SEE ALSO"
+adb(1), as(1), cc(1), ld(1).
+X.br
+X"Assembler Reference Manual" in the PC/IX Programmer's
+Guide.
+X.SH "DIAGNOSTICS"
+X"can't access input file" if the input file cannot be
+found, opened, or read.
+X.sp
+X"can't open output file" if the output file cannot be
+created.
+X.sp
+X"warning: host/cpu clash" if the program is run on a
+machine with a different CPU.
+X.sp
+X"input file not in object format" if the magic number
+does not correspond to that of a PC/IX object file.
+X.sp
+X"not an 8086/8088 object file" if the CPU ID of the
+file header is incorrect.
+X.sp
+X"reloc table overflow" if there are more than 1500
+entries in the relocation table.
+X.sp
+X"symbol table overflow" if there are more than 1500
+entries in the symbol table.
+X.sp
+X"lseek error" if the input file is corrupted (should
+never happen).
+X.sp
+X"warning: no symbols" if the symbol table is missing.
+X.sp
+X"can't reopen input file" if the input file is removed
+or altered during program execution (should never happen).
+X.SH "BUGS"
+Numeric co-processor (i.e., 8087) mnemonics are not currently supported.
+Instructions for the co-processor are
+disassembled as CPU escape sequences, or as interrupts,
+depending on how they were assembled in the first place.
+X.sp
+Despite the program's best efforts, a symbol retrieved
+from the symbol table may sometimes be different from
+the symbol used in the original assembly.
+X.sp
+The disassembler's internal tables are of fixed size,
+and the program aborts if they overflow.
+END_OF_FILE
+if test 6174 -ne `wc -c <'dis88.1'`; then
+ echo shar: \"'dis88.1'\" unpacked with wrong size!
+fi
+# end of 'dis88.1'
+fi
+if test -f 'disfp.c' -a "${1}" != "-c" ; then
+ echo shar: Will not clobber existing file \"'disfp.c'\"
+else
+echo shar: Extracting \"'disfp.c'\" \(5589 characters\)
+sed "s/^X//" >'disfp.c' <<'END_OF_FILE'
+static 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
+void
+eshand(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
+void
+fphand(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
+void
+inhand(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
+if test 5589 -ne `wc -c <'disfp.c'`; then
+ echo shar: \"'disfp.c'\" unpacked with wrong size!
+fi
+# end of 'disfp.c'
+fi
+if test -f 'dismain.c' -a "${1}" != "-c" ; then
+ echo shar: Will not clobber existing file \"'dismain.c'\"
+else
+echo shar: Extracting \"'dismain.c'\" \(17384 characters\)
+sed "s/^X//" >'dismain.c' <<'END_OF_FILE'
+static 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
+extern char *release; /* Contains release string */
+X
+static char *IFILE = NULL; /* Points to input file name */
+X
+static char *OFILE = NULL; /* Points to output file name */
+X
+static char *PRG; /* Name of invoking program */
+X
+static unsigned long zcount; /* Consecutive "0" byte count */
+X
+int objflg = 0; /* Flag: output object bytes */
+X
+X#if unix && i8086 && ibmpc /* Set the CPU identifier */
+static int cpuid = 1;
+X#else
+static int cpuid = 0;
+X#endif
+X
+X /* * * * * * * MISCELLANEOUS UTILITY FUNCTIONS * * * * * * */
+X
+static void
+usage(s)
+X register char *s;
+X{
+X fprintf(stderr,"\07usage: %s [-o] ifile [ofile]\n",s);
+X exit(-1);
+X}
+X
+static void
+fatal(s,t)
+X register char *s, *t;
+X{
+X fprintf(stderr,"\07%s: %s\n",s,t);
+X exit(-1);
+X}
+X
+static void
+zdump(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
+static char *
+invoker(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
+static int
+objdump(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
+static char *
+getlab(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
+static void
+prolog()
+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
+static void
+distext()
+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
+static void
+disdata()
+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
+static void
+disbss()
+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
+void
+main(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,O_RDONLY)) < 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 =
+X HDR.a_tbase = HDR.a_dbase =
+X HDR.a_lnums = HDR.a_toffs = 0L;
+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
+if test 17384 -ne `wc -c <'dismain.c'`; then
+ echo shar: \"'dismain.c'\" unpacked with wrong size!
+fi
+# end of 'dismain.c'
+fi
+if test -f 'disrel.c' -a "${1}" != "-c" ; then
+ echo shar: Will not clobber existing file \"'disrel.c'\"
+else
+echo shar: Extracting \"'disrel.c'\" \(742 characters\)
+sed "s/^X//" >'disrel.c' <<'END_OF_FILE'
+static char *copyright =
+X "@(#) Copyright (C) 1987 G. M. Harding, all rights reserved";
+X
+static char *sccsid =
+X "@(#) disrel.c, Ver. 2.1 created 00:00:00 87/09/01";
+X
+char *release =
+X "release 2.1 (PC/IX)";
+X
+X /*
+X **
+X ** This file documents the major revisions to the 8088 sym-
+X ** bolic disassembler. It also contains the release string
+X ** which is output at the head of each disassembly, and the
+X ** copyright string which must be incorporated in any code
+X ** distribution.
+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 ** REVISION HISTORY:
+X **
+X ** SEP 87:
+X ** After internal shakeout, released on Usenet.
+X **
+X */
+X
+END_OF_FILE
+if test 742 -ne `wc -c <'disrel.c'`; then
+ echo shar: \"'disrel.c'\" unpacked with wrong size!
+fi
+# end of 'disrel.c'
+fi
+echo shar: End of archive 1 \(of 2\).
+cp /dev/null ark1isdone
+MISSING=""
+for I in 1 2 ; do
+ if test ! -f ark${I}isdone ; then
+ MISSING="${MISSING} ${I}"
+ fi
+done
+if test "${MISSING}" = "" ; then
+ echo You have unpacked both archives.
+ rm -f ark[1-9]isdone
+else
+ echo You still need to unpack the following archives:
+ echo " " ${MISSING}
+fi
+## End of shell archive.
+exit 0
diff --git a/part02 b/part02
new file mode 100644
index 0000000..34ca663
--- /dev/null
+++ b/part02
@@ -0,0 +1,1812 @@
+Subject: v15i007: Symbolic disassembler for PC/IX, Part02/02
+Newsgroups: comp.sources.unix
+Approved: rsalz@uunet.UU.NET
+
+Submitted-by: "G. M. Harding" <gm@uts.amdahl.com>
+Posting-number: Volume 15, Issue 7
+Archive-name: dis88/part02
+
+#! /bin/sh
+# This is a shell archive. Remove anything before this line, then unpack
+# it by saving it into a file and typing "sh file". To overwrite existing
+# files, type "sh file -c". You can also feed this as standard input via
+# unshar, or by typing "sh <file", e.g.. If this archive is complete, you
+# will see the following message at the end:
+# "End of archive 2 (of 2)."
+PATH=/bin:/usr/bin:/usr/ucb ; export PATH
+if test -f 'dishand.c' -a "${1}" != "-c" ; then
+ echo shar: Will not clobber existing file \"'dishand.c'\"
+else
+echo shar: Extracting \"'dishand.c'\" \(25688 characters\)
+sed "s/^X//" >'dishand.c' <<'END_OF_FILE'
+static 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
+int segflg; /* Segment-override flag */
+X
+unsigned char objbuf[OBJMAX]; /* Buffer for object code */
+X
+int objptr; /* Index into objbuf[] */
+X
+unsigned long PC; /* Current program counter */
+X
+X /* * * * * * MISCELLANEOUS SUPPORTING ROUTINES * * * * * */
+X
+X
+void
+objini(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
+void
+objout() /* 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
+void
+badseq(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
+void
+dfhand(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
+void
+sbhand(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
+void
+aohand(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
+void
+sjhand(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
+void
+imhand(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
+void
+mvhand(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
+void
+mshand(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
+void
+pohand(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
+void
+cihand(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
+void
+mihand(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
+void
+mqhand(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
+void
+tqhand(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
+void
+rehand(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
+void
+mmhand(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
+void
+srhand(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
+void
+aahand(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
+void
+iohand(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
+void
+ljhand(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
+void
+mahand(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
+void
+mjhand(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
+if test 25688 -ne `wc -c <'dishand.c'`; then
+ echo shar: \"'dishand.c'\" unpacked with wrong size!
+fi
+# end of 'dishand.c'
+fi
+if test -f 'distabs.c' -a "${1}" != "-c" ; then
+ echo shar: Will not clobber existing file \"'distabs.c'\"
+else
+echo shar: Extracting \"'distabs.c'\" \(30238 characters\)
+sed "s/^X//" >'distabs.c' <<'END_OF_FILE'
+static char *sccsid =
+X "@(#) distabs.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 lookup tables and other data *
+X * structures for the Intel 8088 symbolic disassembler. It *
+X * also contains a few global routines which facilitate *
+X * access to the tables, for use primarily by the handler *
+X * functions. *
+X * *
+X * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+X
+X#include "dis.h" /* Disassembler declarations */
+X
+struct exec HDR; /* Used to hold header info */
+X
+struct nlist symtab[MAXSYM]; /* Array of symbol table info */
+X
+struct reloc relo[MAXSYM]; /* Array of relocation info */
+X
+int symptr = -1, /* Index into symtab[] */
+X relptr = -1; /* Index into relo[] */
+X
+char *REGS[] = /* Table of register names */
+X {
+X "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh",
+X "ax", "cx", "dx", "bx", "sp", "bp", "si", "di",
+X "es", "cs", "ss", "ds"
+X };
+X
+char *REGS0[] = /* Mode 0 register name table */
+X {
+X "bx_si", "bx_di", "bp_si", "bp_di", "si", "di", "", "bx"
+X };
+X
+char *REGS1[] = /* Mode 1 register name table */
+X {
+X "bx_si", "bx_di", "bp_si", "bp_di", "si", "di", "bp", "bx"
+X };
+X
+int symrank[6][6] = /* Symbol type/rank matrix */
+X {
+X /* UND ABS TXT DAT BSS COM */
+X /* UND */ 5, 4, 1, 2, 3, 0,
+X /* ABS */ 1, 5, 4, 3, 2, 0,
+X /* TXT */ 4, 1, 5, 3, 2, 0,
+X /* DAT */ 3, 1, 2, 5, 4, 0,
+X /* BSS */ 3, 1, 2, 4, 5, 0,
+X /* COM */ 2, 0, 1, 3, 4, 5
+X };
+X
+X /* * * * * * * * * * * * OPCODE DATA * * * * * * * * * * * */
+X
+char ADD[] = "\tadd", /* Mnemonics by family */
+X OR[] = "\tor",
+X ADC[] = "\tadc",
+X SBB[] = "\tsbb",
+X AND[] = "\tand",
+X SUB[] = "\tsub",
+X XOR[] = "\txor",
+X CMP[] = "\tcmp",
+X NOT[] = "\tnot",
+X NEG[] = "\tneg",
+X MUL[] = "\tmul",
+X DIV[] = "\tdiv",
+X MOV[] = "\tmov",
+X ESC[] = "\tesc",
+X TEST[] = "\ttest",
+X AMBIG[] = "",
+X ROL[] = "\trol",
+X ROR[] = "\tror",
+X RCL[] = "\trcl",
+X RCR[] = "\trcr",
+X SAL[] = "\tsal",
+X SHR[] = "\tshr",
+X SHL[] = "\tshl",
+X SAR[] = "\tsar";
+X
+char *OPFAM[] = /* Family lookup table */
+X {
+X ADD, OR, ADC, SBB, AND, SUB, XOR, CMP,
+X NOT, NEG, MUL, DIV, MOV, ESC, TEST, AMBIG,
+X ROL, ROR, RCL, RCR, SAL, SHR, SHL, SAR
+X };
+X
+struct opcode optab[] = /* Table of opcode data */
+X {
+X ADD, aohand, 2, 4, /* 0x00 */
+X ADD, aohand, 2, 4, /* 0x01 */
+X ADD, aohand, 2, 4, /* 0x02 */
+X ADD, aohand, 2, 4, /* 0x03 */
+X ADD, aohand, 2, 2, /* 0x04 */
+X ADD, aohand, 3, 3, /* 0x05 */
+X "\tpush\tes", sbhand, 1, 1, /* 0x06 */
+X "\tpop\tes", sbhand, 1, 1, /* 0x07 */
+X OR, aohand, 2, 4, /* 0x08 */
+X OR, aohand, 2, 4, /* 0x09 */
+X OR, aohand, 2, 4, /* 0x0a */
+X OR, aohand, 2, 4, /* 0x0b */
+X OR, aohand, 2, 2, /* 0x0c */
+X OR, aohand, 3, 3, /* 0x0d */
+X "\tpush\tcs", sbhand, 1, 1, /* 0x0e */
+X NULL, dfhand, 0, 0, /* 0x0f */
+X ADC, aohand, 2, 4, /* 0x10 */
+X ADC, aohand, 2, 4, /* 0x11 */
+X ADC, aohand, 2, 4, /* 0x12 */
+X ADC, aohand, 2, 4, /* 0x13 */
+X ADC, aohand, 2, 2, /* 0x14 */
+X ADC, aohand, 3, 3, /* 0x15 */
+X "\tpush\tss", sbhand, 1, 1, /* 0x16 */
+X "\tpop\tss", sbhand, 1, 1, /* 0x17 */
+X SBB, aohand, 2, 4, /* 0x18 */
+X SBB, aohand, 2, 4, /* 0x19 */
+X SBB, aohand, 2, 4, /* 0x1a */
+X SBB, aohand, 2, 4, /* 0x1b */
+X SBB, aohand, 2, 2, /* 0x1c */
+X SBB, aohand, 3, 3, /* 0x1d */
+X "\tpush\tds", sbhand, 1, 1, /* 0x1e */
+X "\tpop\tds", sbhand, 1, 1, /* 0x1f */
+X AND, aohand, 2, 4, /* 0x20 */
+X AND, aohand, 2, 4, /* 0x21 */
+X AND, aohand, 2, 4, /* 0x22 */
+X AND, aohand, 2, 4, /* 0x23 */
+X AND, aohand, 2, 2, /* 0x24 */
+X AND, aohand, 3, 3, /* 0x25 */
+X "\tseg\tes", sbhand, 1, 1, /* 0x26 */
+X "\tdaa", sbhand, 1, 1, /* 0x27 */
+X SUB, aohand, 2, 4, /* 0x28 */
+X SUB, aohand, 2, 4, /* 0x29 */
+X SUB, aohand, 2, 4, /* 0x2a */
+X SUB, aohand, 2, 4, /* 0x2b */
+X SUB, aohand, 2, 2, /* 0x2c */
+X SUB, aohand, 3, 3, /* 0x2d */
+X "\tseg\tcs", sbhand, 1, 1, /* 0x2e */
+X "\tdas", sbhand, 1, 1, /* 0x2f */
+X XOR, aohand, 2, 4, /* 0x30 */
+X XOR, aohand, 2, 4, /* 0x31 */
+X XOR, aohand, 2, 4, /* 0x32 */
+X XOR, aohand, 2, 4, /* 0x33 */
+X XOR, aohand, 2, 2, /* 0x34 */
+X XOR, aohand, 3, 3, /* 0x35 */
+X "\tseg\tss", sbhand, 1, 1, /* 0x36 */
+X "\taaa", sbhand, 1, 1, /* 0x37 */
+X CMP, aohand, 2, 4, /* 0x38 */
+X CMP, aohand, 2, 4, /* 0x39 */
+X CMP, aohand, 2, 4, /* 0x3a */
+X CMP, aohand, 2, 4, /* 0x3b */
+X CMP, aohand, 2, 2, /* 0x3c */
+X CMP, aohand, 3, 3, /* 0x3d */
+X "\tseg\tds", sbhand, 1, 1, /* 0x3e */
+X "\taas", sbhand, 1, 1, /* 0x3f */
+X "\tinc\tax", sbhand, 1, 1, /* 0x40 */
+X "\tinc\tcx", sbhand, 1, 1, /* 0x41 */
+X "\tinc\tdx", sbhand, 1, 1, /* 0x42 */
+X "\tinc\tbx", sbhand, 1, 1, /* 0x43 */
+X "\tinc\tsp", sbhand, 1, 1, /* 0x44 */
+X "\tinc\tbp", sbhand, 1, 1, /* 0x45 */
+X "\tinc\tsi", sbhand, 1, 1, /* 0x46 */
+X "\tinc\tdi", sbhand, 1, 1, /* 0x47 */
+X "\tdec\tax", sbhand, 1, 1, /* 0x48 */
+X "\tdec\tcx", sbhand, 1, 1, /* 0x49 */
+X "\tdec\tdx", sbhand, 1, 1, /* 0x4a */
+X "\tdec\tbx", sbhand, 1, 1, /* 0x4b */
+X "\tdec\tsp", sbhand, 1, 1, /* 0x4c */
+X "\tdec\tbp", sbhand, 1, 1, /* 0x4d */
+X "\tdec\tsi", sbhand, 1, 1, /* 0x4e */
+X "\tdec\tdi", sbhand, 1, 1, /* 0x4f */
+X "\tpush\tax", sbhand, 1, 1, /* 0x50 */
+X "\tpush\tcx", sbhand, 1, 1, /* 0x51 */
+X "\tpush\tdx", sbhand, 1, 1, /* 0x52 */
+X "\tpush\tbx", sbhand, 1, 1, /* 0x53 */
+X "\tpush\tsp", sbhand, 1, 1, /* 0x54 */
+X "\tpush\tbp", sbhand, 1, 1, /* 0x55 */
+X "\tpush\tsi", sbhand, 1, 1, /* 0x56 */
+X "\tpush\tdi", sbhand, 1, 1, /* 0x57 */
+X "\tpop\tax", sbhand, 1, 1, /* 0x58 */
+X "\tpop\tcx", sbhand, 1, 1, /* 0x59 */
+X "\tpop\tdx", sbhand, 1, 1, /* 0x5a */
+X "\tpop\tbx", sbhand, 1, 1, /* 0x5b */
+X "\tpop\tsp", sbhand, 1, 1, /* 0x5c */
+X "\tpop\tbp", sbhand, 1, 1, /* 0x5d */
+X "\tpop\tsi", sbhand, 1, 1, /* 0x5e */
+X "\tpop\tdi", sbhand, 1, 1, /* 0x5f */
+X NULL, dfhand, 0, 0, /* 0x60 */
+X NULL, dfhand, 0, 0, /* 0x61 */
+X NULL, dfhand, 0, 0, /* 0x62 */
+X NULL, dfhand, 0, 0, /* 0x63 */
+X NULL, dfhand, 0, 0, /* 0x64 */
+X NULL, dfhand, 0, 0, /* 0x65 */
+X NULL, dfhand, 0, 0, /* 0x66 */
+X NULL, dfhand, 0, 0, /* 0x67 */
+X NULL, dfhand, 0, 0, /* 0x68 */
+X NULL, dfhand, 0, 0, /* 0x69 */
+X NULL, dfhand, 0, 0, /* 0x6a */
+X NULL, dfhand, 0, 0, /* 0x6b */
+X NULL, dfhand, 0, 0, /* 0x6c */
+X NULL, dfhand, 0, 0, /* 0x6d */
+X NULL, dfhand, 0, 0, /* 0x6e */
+X NULL, dfhand, 0, 0, /* 0x6f */
+X "\tjo", sjhand, 2, 2, /* 0x70 */
+X "\tjno", sjhand, 2, 2, /* 0x71 */
+X "\tjc", sjhand, 2, 2, /* 0x72 */
+X "\tjnc", sjhand, 2, 2, /* 0x73 */
+X "\tjz", sjhand, 2, 2, /* 0x74 */
+X "\tjnz", sjhand, 2, 2, /* 0x75 */
+X "\tjna", sjhand, 2, 2, /* 0x76 */
+X "\tja", sjhand, 2, 2, /* 0x77 */
+X "\tjs", sjhand, 2, 2, /* 0x78 */
+X "\tjns", sjhand, 2, 2, /* 0x79 */
+X "\tjp", sjhand, 2, 2, /* 0x7a */
+X "\tjnp", sjhand, 2, 2, /* 0x7b */
+X "\tjl", sjhand, 2, 2, /* 0x7c */
+X "\tjnl", sjhand, 2, 2, /* 0x7d */
+X "\tjng", sjhand, 2, 2, /* 0x7e */
+X "\tjg", sjhand, 2, 2, /* 0x7f */
+X AMBIG, imhand, 3, 5, /* 0x80 */
+X AMBIG, imhand, 4, 6, /* 0x81 */
+X AMBIG, imhand, 3, 5, /* 0x82 */
+X AMBIG, imhand, 3, 5, /* 0x83 */
+X TEST, mvhand, 2, 4, /* 0x84 */
+X TEST, mvhand, 2, 4, /* 0x85 */
+X "\txchg", mvhand, 2, 4, /* 0x86 */
+X "\txchg", mvhand, 2, 4, /* 0x87 */
+X MOV, mvhand, 2, 4, /* 0x88 */
+X MOV, mvhand, 2, 4, /* 0x89 */
+X MOV, mvhand, 2, 4, /* 0x8a */
+X MOV, mvhand, 2, 4, /* 0x8b */
+X MOV, mshand, 2, 4, /* 0x8c */
+X "\tlea", mvhand, 2, 4, /* 0x8d */
+X MOV, mshand, 2, 4, /* 0x8e */
+X "\tpop", pohand, 2, 4, /* 0x8f */
+X "\tnop", sbhand, 1, 1, /* 0x90 */
+X "\txchg\tax,cx", sbhand, 1, 1, /* 0x91 */
+X "\txchg\tax,dx", sbhand, 1, 1, /* 0x92 */
+X "\txchg\tax,bx", sbhand, 1, 1, /* 0x93 */
+X "\txchg\tax,sp", sbhand, 1, 1, /* 0x94 */
+X "\txchg\tax,bp", sbhand, 1, 1, /* 0x95 */
+X "\txchg\tax,si", sbhand, 1, 1, /* 0x96 */
+X "\txchg\tax,di", sbhand, 1, 1, /* 0x97 */
+X "\tcbw", sbhand, 1, 1, /* 0x98 */
+X "\tcwd", sbhand, 1, 1, /* 0x99 */
+X "\tcalli", cihand, 5, 5, /* 0x9a */
+X "\twait", sbhand, 1, 1, /* 0x9b */
+X "\tpushf", sbhand, 1, 1, /* 0x9c */
+X "\tpopf", sbhand, 1, 1, /* 0x9d */
+X "\tsahf", sbhand, 1, 1, /* 0x9e */
+X "\tlahf", sbhand, 1, 1, /* 0x9f */
+X MOV, mqhand, 3, 3, /* 0xa0 */
+X MOV, mqhand, 3, 3, /* 0xa1 */
+X MOV, mqhand, 3, 3, /* 0xa2 */
+X MOV, mqhand, 3, 3, /* 0xa3 */
+X "\tmovb", sbhand, 1, 1, /* 0xa4 */
+X "\tmovw", sbhand, 1, 1, /* 0xa5 */
+X "\tcmpb", sbhand, 1, 1, /* 0xa6 */
+X "\tcmpw", sbhand, 1, 1, /* 0xa7 */
+X TEST, tqhand, 2, 2, /* 0xa8 */
+X TEST, tqhand, 3, 3, /* 0xa9 */
+X "\tstob", sbhand, 1, 1, /* 0xaa */
+X "\tstow", sbhand, 1, 1, /* 0xab */
+X "\tlodb", sbhand, 1, 1, /* 0xac */
+X "\tlodw", sbhand, 1, 1, /* 0xad */
+X "\tscab", sbhand, 1, 1, /* 0xae */
+X "\tscaw", sbhand, 1, 1, /* 0xaf */
+X "\tmov\tal,", mihand, 2, 2, /* 0xb0 */
+X "\tmov\tcl,", mihand, 2, 2, /* 0xb1 */
+X "\tmov\tdl,", mihand, 2, 2, /* 0xb2 */
+X "\tmov\tbl,", mihand, 2, 2, /* 0xb3 */
+X "\tmov\tah,", mihand, 2, 2, /* 0xb4 */
+X "\tmov\tch,", mihand, 2, 2, /* 0xb5 */
+X "\tmov\tdh,", mihand, 2, 2, /* 0xb6 */
+X "\tmov\tbh,", mihand, 2, 2, /* 0xb7 */
+X "\tmov\tax,", mihand, 3, 3, /* 0xb8 */
+X "\tmov\tcx,", mihand, 3, 3, /* 0xb9 */
+X "\tmov\tdx,", mihand, 3, 3, /* 0xba */
+X "\tmov\tbx,", mihand, 3, 3, /* 0xbb */
+X "\tmov\tsp,", mihand, 3, 3, /* 0xbc */
+X "\tmov\tbp,", mihand, 3, 3, /* 0xbd */
+X "\tmov\tsi,", mihand, 3, 3, /* 0xbe */
+X "\tmov\tdi,", mihand, 3, 3, /* 0xbf */
+X NULL, dfhand, 0, 0, /* 0xc0 */
+X NULL, dfhand, 0, 0, /* 0xc1 */
+X "\tret", rehand, 3, 3, /* 0xc2 */
+X "\tret", sbhand, 1, 1, /* 0xc3 */
+X "\tles", mvhand, 2, 4, /* 0xc4 */
+X "\tlds", mvhand, 2, 4, /* 0xc5 */
+X MOV, mmhand, 3, 5, /* 0xc6 */
+X MOV, mmhand, 4, 6, /* 0xc7 */
+X NULL, dfhand, 0, 0, /* 0xc8 */
+X NULL, dfhand, 0, 0, /* 0xc9 */
+X "\treti", rehand, 3, 3, /* 0xca */
+X "\treti", sbhand, 1, 1, /* 0xcb */
+X "\tint", sbhand, 1, 1, /* 0xcc */
+X "\tint", inhand, 2, 2, /* 0xcd */
+X "\tinto", sbhand, 1, 1, /* 0xce */
+X "\tiret", sbhand, 1, 1, /* 0xcf */
+X AMBIG, srhand, 2, 4, /* 0xd0 */
+X AMBIG, srhand, 2, 4, /* 0xd1 */
+X AMBIG, srhand, 2, 4, /* 0xd2 */
+X AMBIG, srhand, 2, 4, /* 0xd3 */
+X "\taam", aahand, 2, 2, /* 0xd4 */
+X "\taad", aahand, 2, 2, /* 0xd5 */
+X NULL, dfhand, 0, 0, /* 0xd6 */
+X "\txlat", sbhand, 1, 1, /* 0xd7 */
+X ESC, eshand, 2, 2, /* 0xd8 */
+X ESC, eshand, 2, 2, /* 0xd9 */
+X ESC, eshand, 2, 2, /* 0xda */
+X ESC, eshand, 2, 2, /* 0xdb */
+X ESC, eshand, 2, 2, /* 0xdc */
+X ESC, eshand, 2, 2, /* 0xdd */
+X ESC, eshand, 2, 2, /* 0xde */
+X ESC, eshand, 2, 2, /* 0xdf */
+X "\tloopne", sjhand, 2, 2, /* 0xe0 */
+X "\tloope", sjhand, 2, 2, /* 0xe1 */
+X "\tloop", sjhand, 2, 2, /* 0xe2 */
+X "\tjcxz", sjhand, 2, 2, /* 0xe3 */
+X "\tin", iohand, 2, 2, /* 0xe4 */
+X "\tinw", iohand, 2, 2, /* 0xe5 */
+X "\tout", iohand, 2, 2, /* 0xe6 */
+X "\toutw", iohand, 2, 2, /* 0xe7 */
+X "\tcall", ljhand, 3, 3, /* 0xe8 */
+X "\tjmp", ljhand, 3, 3, /* 0xe9 */
+X "\tjmpi", cihand, 5, 5, /* 0xea */
+X "\tj", sjhand, 2, 2, /* 0xeb */
+X "\tin", sbhand, 1, 1, /* 0xec */
+X "\tinw", sbhand, 1, 1, /* 0xed */
+X "\tout", sbhand, 1, 1, /* 0xee */
+X "\toutw", sbhand, 1, 1, /* 0xef */
+X "\tlock", sbhand, 1, 1, /* 0xf0 */
+X NULL, dfhand, 0, 0, /* 0xf1 */
+X "\trepnz", sbhand, 1, 1, /* 0xf2 */
+X "\trepz", sbhand, 1, 1, /* 0xf3 */
+X "\thlt", sbhand, 1, 1, /* 0xf4 */
+X "\tcmc", sbhand, 1, 1, /* 0xf5 */
+X AMBIG, mahand, 2, 5, /* 0xf6 */
+X AMBIG, mahand, 2, 6, /* 0xf7 */
+X "\tclc", sbhand, 1, 1, /* 0xf8 */
+X "\tstc", sbhand, 1, 1, /* 0xf9 */
+X "\tcli", sbhand, 1, 1, /* 0xfa */
+X "\tsti", sbhand, 1, 1, /* 0xfb */
+X "\tcld", sbhand, 1, 1, /* 0xfc */
+X "\tstd", sbhand, 1, 1, /* 0xfd */
+X AMBIG, mjhand, 2, 4, /* 0xfe */
+X AMBIG, mjhand, 2, 4 /* 0xff */
+X };
+X
+X /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+X * *
+X * This simple routine returns the name field of a symbol *
+X * table entry as a printable string. *
+X * *
+X * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+X
+char *
+getnam(k)
+X
+X register int k;
+X
+X{/* * * * * * * * * * START OF getnam() * * * * * * * * * */
+X
+X register int j;
+X static char a[9];
+X
+X for (j = 0; j < 8; ++j)
+X if ( ! symtab[k].n_name[j] )
+X break;
+X else
+X a[j] = symtab[k].n_name[j];
+X
+X a[j] = '\0';
+X
+X return (a);
+X
+X}/* * * * * * * * * * * END OF getnam() * * * * * * * * * * */
+X
+X /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+X * *
+X * This function is responsible for mucking through the *
+X * relocation table in search of externally referenced *
+X * symbols to be output as operands. It accepts two long *
+X * arguments: the code-segment location at which an extern *
+X * reference is expected, and the offset value which is *
+X * embedded in the object code and used at link time to *
+X * bias the external value. In the most typical case, the *
+X * function will be called by lookup(), which always makes *
+X * a check for external names before searching the symbol *
+X * table proper. However, it may also be called directly *
+X * by any function (such as the move-immediate handler) *
+X * which wants to make an independent check for externals. *
+X * The caller is expected to supply, as the third argument *
+X * to the function, a pointer to a character buffer large *
+X * enough to hold any possible output string. Lookext() *
+X * will fill this buffer and return a logical TRUE if it *
+X * finds an extern reference; otherwise, it will return a *
+X * logical FALSE, leaving the buffer undisturbed. *
+X * *
+X * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+X
+int
+lookext(off,loc,buf)
+X
+X long off, loc;
+X char *buf;
+X
+X{/* * * * * * * * * * START OF lookext() * * * * * * * * * */
+X
+X register int k;
+X char c[16];
+X
+X if ((loc != -1L) && (relptr >= 0))
+X for (k = 0; k <= relptr; ++k)
+X if ((relo[k].r_vaddr == loc)
+X && (relo[k].r_symndx < S_BSS))
+X {
+X strcpy(buf,getnam(relo[k].r_symndx));
+X if (off)
+X {
+X if (off < 0)
+X sprintf(c,"%ld",off);
+X else
+X sprintf(c,"+%ld",off);
+X strcat(buf,c);
+X }
+X return (1);
+X }
+X
+X return (0);
+X
+X}/* * * * * * * * * * END OF lookext() * * * * * * * * * */
+X
+X /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+X * *
+X * This function finds an entry in the symbol table by *
+X * value. Its input is a (long) machine address, and its *
+X * output is a pointer to a string containing the corre- *
+X * sponding symbolic name. The function first searches the *
+X * relocation table for a possible external reference; if *
+X * none is found, a linear search of the symbol table is *
+X * undertaken. If no matching symbol has been found at the *
+X * end of these searches, the function returns a pointer *
+X * to a string containing the ASCII equivalent of the ad- *
+X * dress which was to be located, so that, regardless of *
+X * the success of the search, the function's return value *
+X * is suitable for use as a memory-reference operand. The *
+X * caller specifies the type of symbol to be found (text, *
+X * data, bss, undefined, absolute, or common) by means of *
+X * the function's second parameter. The third parameter *
+X * specifies the format to be used in the event of a nu- *
+X * meric output: zero for absolute format, one for short *
+X * relative format, two for long relative format. The *
+X * fourth parameter is the address which would appear in *
+X * the relocation table for the reference in question, or *
+X * -1 if the relocation table is not to be searched. The *
+X * function attempts to apply a certain amount of intelli- *
+X * gence in its selection of symbols, so it is possible *
+X * that, in the absence of a type match, a symbol of the *
+X * correct value but different type will be returned. *
+X * *
+X * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+X
+char *
+lookup(addr,type,kind,ext)
+X
+X long addr; /* Machine address to be located */
+X
+X int type, /* Type of symbol to be matched */
+X kind; /* Addressing output mode to use */
+X
+X long ext; /* Value for extern ref, if any */
+X
+X{/* * * * * * * * * * START OF lookup() * * * * * * * * * */
+X
+X register int j, k;
+X static char b[64];
+X
+X struct
+X {
+X int i;
+X int t;
+X }
+X best;
+X
+X if (lookext(addr,ext,b))
+X return (b);
+X
+X if (segflg)
+X if (segflg & 1)
+X type = N_TEXT;
+X else
+X type = N_DATA;
+X
+X for (k = 0, best.i = -1; k <= symptr; ++k)
+X if (symtab[k].n_value == addr)
+X if ((j = symtab[k].n_sclass & N_SECT) == type)
+X {
+X best.t = j;
+X best.i = k;
+X break;
+X }
+X else if (segflg || (HDR.a_flags & A_SEP))
+X continue;
+X else if (best.i < 0)
+X best.t = j, best.i = k;
+X else if (symrank[type][j] > symrank[type][best.t])
+X best.t = j, best.i = k;
+X
+X if (best.i >= 0)
+X return (getnam(best.i));
+X
+X if (kind == LOOK_ABS)
+X sprintf(b,"0x%05.5x",addr);
+X else
+X {
+X long x = addr - (PC - kind);
+X if (x < 0)
+X sprintf(b,".%ld",x);
+X else
+X sprintf(b,".+%ld",x);
+X }
+X
+X return (b);
+X
+X}/* * * * * * * * * * * END OF lookup() * * * * * * * * * * */
+X
+X /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+X * *
+X * This function translates an 8088 addressing mode byte *
+X * to an equivalent assembler string, returning a pointer *
+X * thereto. If necessary, it performs successive inputs *
+X * of bytes from the object file in order to obtain offset *
+X * data, adjusting PC accordingly. (The addressing mode *
+X * byte appears in several 8088 opcodes; it is used to *
+X * specify source and destination operand locations.) The *
+X * third argument to the function is zero if the standard *
+X * registers are to be used, or eight if the segment reg- *
+X * isters are to be used; these constants are defined sym- *
+X * bolically in dis.h. NOTE: The mtrans() function must *
+X * NEVER be called except immediately after fetching the *
+X * mode byte. If any additional object bytes are fetched *
+X * after the fetch of the mode byte, mtrans() will not *
+X * produce correct output! *
+X * *
+X * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+X
+char *
+mtrans(c,m,type)
+X
+X register int c; /* Primary instruction byte */
+X register int m; /* Addressing mode byte */
+X
+X int type; /* Type code: standard or seg */
+X
+X{/* * * * * * * * * * START OF mtrans() * * * * * * * * * */
+X
+X unsigned long pc;
+X int offset, oflag, dir, w, mod, reg, rm;
+X static char a[100];
+X static char b[30];
+X
+X offset = 0;
+X dir = c & 2;
+X w = c & 1;
+X mod = (m & 0xc0) >> 6;
+X reg = (m & 0x38) >> 3;
+X rm = m & 7;
+X pc = PC + 1;
+X
+X if (type)
+X w = 1;
+X
+X if ((oflag = mod) > 2)
+X oflag = 0;
+X
+X if (oflag)
+X {
+X int j, k;
+X if (oflag == 2)
+X {
+X FETCH(j);
+X FETCH(k);
+X offset = (k << 8) | j;
+X }
+X else
+X {
+X FETCH(j);
+X if (j & 0x80)
+X k = 0xff00;
+X else
+X k = 0;
+X offset = k | j;
+X }
+X }
+X
+X if (dir)
+X {
+X strcpy(a,REGS[type + ((w << 3) | reg)]);
+X strcat(a,",");
+X switch (mod)
+X {
+X case 0 :
+X if (rm == 6)
+X {
+X int j, k;
+X FETCH(j);
+X FETCH(k);
+X offset = (k << 8) | j;
+X strcat(a,
+X lookup((long)(offset),N_DATA,LOOK_ABS,pc));
+X }
+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 else
+X {
+X switch (mod)
+X {
+X case 0 :
+X if (rm == 6)
+X {
+X int j, k;
+X FETCH(j);
+X FETCH(k);
+X offset = (k << 8) | j;
+X strcpy(a,
+X lookup((long)(offset),N_DATA,LOOK_ABS,pc));
+X }
+X else
+X {
+X sprintf(b,"(%s)",REGS0[rm]);
+X strcpy(a,b);
+X }
+X break;
+X case 1 :
+X case 2 :
+X if (mod == 1)
+X strcpy(a,"*");
+X else
+X strcpy(a,"#");
+X sprintf(b,"%d(",offset);
+X strcat(a,b);
+X strcat(a,REGS1[rm]);
+X strcat(a,")");
+X break;
+X case 3 :
+X strcpy(a,REGS[(w << 3) | rm]);
+X break;
+X }
+X strcat(a,",");
+X strcat(a,REGS[type + ((w << 3) | reg)]);
+X }
+X
+X return (a);
+X
+X}/* * * * * * * * * * * END OF mtrans() * * * * * * * * * * */
+X
+X /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+X * *
+X * This simple routine truncates a string returned by the *
+X * mtrans() function, removing its source operand. This is *
+X * useful in handlers which ignore the "reg" field of the *
+X * mode byte. *
+X * *
+X * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+X
+void
+mtrunc(a)
+X
+X register char *a; /* Ptr. to string to truncate */
+X
+X{/* * * * * * * * * * START OF mtrunc() * * * * * * * * * */
+X
+X register int k;
+X
+X for (k = strlen(a) - 1; k >= 0; --k)
+X if (a[k] == ',')
+X {
+X a[k] = '\0';
+X break;
+X }
+X
+X}/* * * * * * * * * * * END OF mtrunc() * * * * * * * * * * */
+X
+X
+END_OF_FILE
+if test 30238 -ne `wc -c <'distabs.c'`; then
+ echo shar: \"'distabs.c'\" unpacked with wrong size!
+fi
+# end of 'distabs.c'
+fi
+echo shar: End of archive 2 \(of 2\).
+cp /dev/null ark2isdone
+MISSING=""
+for I in 1 2 ; do
+ if test ! -f ark${I}isdone ; then
+ MISSING="${MISSING} ${I}"
+ fi
+done
+if test "${MISSING}" = "" ; then
+ echo You have unpacked both archives.
+ rm -f ark[1-9]isdone
+else
+ echo You still need to unpack the following archives:
+ echo " " ${MISSING}
+fi
+## End of shell archive.
+exit 0