ast@cs.vu.nl (Andy Tanenbaum) (06/11/88)
Here is a dissassembler for MINIX. It was posted to comp.sources.unix by G.M. Harding a week ago. It was intended as a disassembler for PC-IX, but since the MINIX assembly language was copied from the PC-IX assembly language, it worked for MINIX with only a few minutes work! The best way to use it is with Dick van Veen's symbol table package, e.g. cc -s -o prog prog.c >symbol.out ast prog symbol.out disass prog >assembly_file It also works without the symbol table, but the output is a lot more readable with the symbol table. I am not exactly sure if anybody is interested in a disassembler, but who knows. The source is quite large. I have asked the author for permission to include it in 1.3. If he agrees, I may do so. Does this seem like a useful thing to do? The source is kind of large... Andy Tanenbaum (ast@cs.vu.nl) : This is a shar archive. Extract with sh, not csh. : This archive ends with exit, so do not worry about trailing junk. : --------------------------- cut here -------------------------- PATH=/bin:/usr/bin:/usr/ucb echo Extracting 'Makefile' sed 's/^X//' > 'Makefile' << '+ END-OF-FILE ''Makefile' 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 XOBJ = disrel.s dismain.s distabs.s dishand.s disfp.s X Xdis88 : $(OBJ) X cc $(OBJ) X size dis88 X @echo "\07Build of 'dis88' complete." > /dev/tty X X Xdisrel.s : disrel.c X Xdismain.s : dismain.c dis.h X Xdistabs.s : distabs.c dis.h X Xdishand.s : dishand.c dis.h X Xdisfp.s : disfp.c dis.h X + END-OF-FILE Makefile chmod 'u=rw,g=r,o=r' 'Makefile' set `wc -c 'Makefile'` count=$1 case $count in 1526) :;; *) echo 'Bad character count in ''Makefile' >&2 echo 'Count should be 1526' >&2 esac echo Extracting 'dis.h' sed 's/^X//' > 'dis.h' << '+ END-OF-FILE ''dis.h' X /* X ** @(#) dis.h, Ver. 2.1 created 00:00:00 87/09/01 X */ X X /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * X * * X * Copyright (C) 1987 G. M. Harding, all rights reserved * X * * X * Permission to copy and redistribute is hereby granted, * X * provided full source code, with all copyright notices, * X * accompanies any redistribution. * X * * X * This file contains declarations and definitions used by * X * the 8088 disassembler program. The program was designed * X * for execution on a machine of its own type (i.e., it is * X * not designed as a cross-disassembler); consequently, A * X * SIXTEEN-BIT INTEGER SIZE HAS BEEN ASSUMED. This assump- * X * tion is not particularly important, however, except in * X * the machine-specific portions of the code (i.e., the * X * handler routines and the optab[] array). It should be * X * possible to override this assumption, for execution on * X * 32-bit machines, by use of a pre-processor directive * X * (see below); however, this has not been tested. * X * * X * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ X X#include <stdio.h> /* System standard I/O definitions */ X#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 Xextern struct nlist /* Array to hold the symbol table */ X symtab[MAXSYM]; X Xextern struct reloc /* Array to hold relocation table */ X relo[MAXSYM]; X Xextern int symptr; /* Index into the symtab[] array */ X Xextern int relptr; /* Index into the relo[] array */ X Xstruct opcode /* Format for opcode data records */ X { X char *text; /* Pointer to mnemonic text */ X void (*func)(); /* Pointer to handler routine */ X unsigned min; /* Minimum # of object bytes */ X unsigned max; /* Maximum # of object bytes */ X }; X Xextern struct opcode /* Array to hold the opcode table */ X optab[256]; X X /* X +--------------------------------------------- X | The following functions are the specialized X | handlers for each opcode group. They are, of X | course, highly MACHINE-SPECIFIC. Each entry X | in the opcode[] array contains a pointer to X | one of these handlers. The handlers in the X | first group are in dishand.c; those in the X | second group are in disfp.c. X +--------------------------------------------- X */ X Xextern void dfhand(), /* Default handler routine */ X sbhand(), /* Single-byte handler */ X aohand(), /* Arithmetic-op handler */ X sjhand(), /* Short-jump handler */ X imhand(), /* Immediate-operand handler */ X mvhand(), /* Simple move handler */ X mshand(), /* Segreg-move handler */ X pohand(), /* Pop memory/reg handler */ X cihand(), /* Intersegment call handler */ X mihand(), /* Immediate-move handler */ X mqhand(), /* Quick-move handler */ X tqhand(), /* Quick-test handler */ X rehand(), /* Return handler */ X mmhand(), /* Move-to-memory handler */ X srhand(), /* Shift and rotate handler */ X aahand(), /* ASCII-adjust handler */ X iohand(), /* Immediate port I/O handler */ X ljhand(), /* Long-jump handler */ X mahand(), /* Misc. arithmetic handler */ X mjhand(); /* Miscellaneous jump handler */ X Xextern void eshand(), /* Bus-escape opcode handler */ X fphand(), /* Floating-point handler */ X inhand(); /* Interrupt-opcode handler */ X Xextern char *REGS[]; /* Table of register names */ X Xextern char *REGS0[]; /* Mode 0 register name table */ X Xextern char *REGS1[]; /* Mode 1 register name table */ X X#define AL REGS[0] /* CPU register manifests */ X#define CL REGS[1] X#define DL REGS[2] X#define BL REGS[3] X#define AH REGS[4] X#define CH REGS[5] X#define DH REGS[6] X#define BH REGS[7] X#define AX REGS[8] X#define CX REGS[9] X#define DX REGS[10] X#define BX REGS[11] X#define SP REGS[12] X#define BP REGS[13] X#define SI REGS[14] X#define DI REGS[15] X#define ES REGS[16] X#define CS REGS[17] X#define SS REGS[18] X#define DS REGS[19] X#define BX_SI REGS0[0] X#define BX_DI REGS0[1] X#define BP_SI REGS0[2] X#define BP_DI REGS0[3] X Xextern int symrank[6][6]; /* Symbol type/rank matrix */ X Xextern unsigned long PC; /* Current program counter */ X Xextern int segflg; /* Flag: segment override in effect */ X Xextern int objflg; /* Flag: output object as a comment */ X X#define OBJMAX 8 /* Size of the object code buffer */ X Xextern unsigned char /* Internal buffer for object code */ X objbuf[OBJMAX]; X Xextern void objini(), /* Object-buffer init routine */ X objout(); /* Object-code output routine */ X Xextern int objptr; /* Index into the objbuf[] array */ X Xextern void badseq(); /* Bad-code-sequence function */ X Xextern char *getnam(); /* Symbol-name string function */ X Xextern char *lookup(); /* Symbol-table lookup function */ X Xextern int lookext(); /* Extern-definition lookup routine */ X Xextern char *mtrans(); /* Interpreter for the mode byte */ X Xextern void mtrunc(); /* Mode string truncator function */ X Xextern char ADD[], /* Opcode family mnemonic strings */ X OR[], X ADC[], X SBB[], X AND[], X SUB[], X XOR[], X CMP[], X NOT[], X NEG[], X MUL[], X DIV[], X MOV[], X ESC[], X TEST[], X AMBIG[]; X Xextern char *OPFAM[]; /* Indexed mnemonic family table */ X Xextern struct exec HDR; /* Holds the object file's header */ X X#define LOOK_ABS 0 /* Arguments to lookup() function */ X#define LOOK_REL 1 X#define LOOK_LNG 2 X X#define TR_STD 0 /* Arguments to mtrans() function */ X#define TR_SEG 8 X X /* Macro for byte input primitive */ X#define FETCH(p) \ X ++PC; p = getchar() & 0xff; objbuf[objptr++] = p X Xextern int close(); /* System file-close primitive */ Xextern int fprintf(); /* Library file-output function */ Xextern long lseek(); /* System file-position primitive */ Xextern int open(); /* System file-open primitive */ Xextern int printf(); /* Library output-format function */ Xextern int read(); /* System file-read primitive */ Xextern int sprintf(); /* Library string-output function */ Xextern char *strcat(); /* Library string-join function */ Xextern char *strcpy(); /* Library string-copy function */ Xextern int strlen(); /* Library string-length function */ X X /* * * * * * * * * * * END OF dis.h * * * * * * * * * * */ X X + END-OF-FILE dis.h chmod 'u=rw,g=r,o=r' 'dis.h' set `wc -c 'dis.h'` count=$1 case $count in 7563) :;; *) echo 'Bad character count in ''dis.h' >&2 echo 'Count should be 7563' >&2 esac echo Extracting 'disfp.c' sed 's/^X//' > 'disfp.c' << '+ END-OF-FILE ''disfp.c' Xstatic char *sccsid = X "@(#) disfp.c, Ver. 2.1 created 00:00:00 87/09/01"; X X /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * X * * X * Copyright (C) 1987 G. M. Harding, all rights reserved * X * * X * Permission to copy and redistribute is hereby granted, * X * provided full source code, with all copyright notices, * X * accompanies any redistribution. * X * * X * This file contains handler routines for the numeric op- * X * codes of the 8087 co-processor, as well as a few other * X * opcodes which are related to 8087 emulation. * X * * X * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ X X#include "dis.h" /* Disassembler declarations */ X X#define FPINT0 0xd8 /* Floating-point interrupts */ X#define FPINT1 0xd9 X#define FPINT2 0xda X#define FPINT3 0xdb X#define FPINT4 0xdc X#define FPINT5 0xdd X#define FPINT6 0xde X#define FPINT7 0xdf X X /* Test for floating opcodes */ X#define ISFLOP(x) \ X (((x) >= FPINT0) && ((x) <= FPINT7)) X X /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * X * * X * This is the handler for the escape family of opcodes. * X * These opcodes place the contents of a specified memory * X * location on the system bus, for access by a peripheral * X * or by a co-processor such as the 8087. (The 8087 NDP is * X * accessed only via bus escapes.) Due to a bug in the * X * PC/IX assembler, the "esc" mnemonic is not recognized; * X * consequently, escape opcodes are disassembled as .byte * X * directives, with the appropriate mnemonic and operand * X * included as a comment. FOR NOW, those escape sequences * X * corresponding to 8087 opcodes are treated as simple * X * escapes. * X * * X * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ X Xvoid Xeshand(j) X X register int j; /* Pointer to optab[] entry */ X X{/* * * * * * * * * * START OF eshand() * * * * * * * * * */ X X register char *a; X register int k; X X objini(j); X X FETCH(k); X X a = mtrans((j & 0xfd),(k & 0xc7),TR_STD); X X mtrunc(a); X X printf("\t.byte\t0x%02.2x\t\t| esc\t%s\n",j,a); X X for (k = 1; k < objptr; ++k) X printf("\t.byte\t0x%02.2x\n",objbuf[k]); X X}/* * * * * * * * * * * END OF eshand() * * * * * * * * * * */ X X /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * X * * X * This is the handler routine for floating-point opcodes. * X * Since PC/IX must accommodate systems with and without * X * 8087 co-processors, it allows floating-point operations * X * to be initiated in either of two ways: by a software * X * interrput whose type is in the range 0xd8 through 0xdf, * X * or by a CPU escape sequence, which is invoked by an op- * X * code in the same range. In either case, the subsequent * X * byte determines the actual numeric operation to be per- * X * formed. However, depending on the method of access, * X * either one or two code bytes will precede that byte, * X * and the fphand() routine has no way of knowing whether * X * it was invoked by interrupt or by an escape sequence. * X * Therefore, unlike all of the other handler routines ex- * X * cept dfhand(), fphand() does not initialize the object * X * buffer, leaving that chore to the caller. * X * * X * FOR NOW, fphand() does not disassemble floating-point * X * opcodes to floating mnemonics, but simply outputs the * X * object code as .byte directives. * X * * X * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ X Xvoid Xfphand(j) X X register int j; /* Pointer to optab[] entry */ X X{/* * * * * * * * * * START OF fphand() * * * * * * * * * */ X X register int k; X X segflg = 0; X X FETCH(k); X X printf("\t.byte\t0x%02.2x\t\t| 8087 code sequence\n", X objbuf[0]); X X for (k = 1; k < objptr; ++k) X printf("\t.byte\t0x%02.2x\n",objbuf[k]); X X/* objout(); FOR NOW */ X X}/* * * * * * * * * * * END OF fphand() * * * * * * * * * * */ X X /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * X * * X * This is the handler for variable software interrupt * X * opcodes. It is included in this file because PC/IX im- * X * plements its software floating-point emulation by means * X * of interrupts. Any interrupt in the range 0xd8 through * X * 0xdf is an NDP-emulation interrupt, and is specially * X * handled by the assembler. * X * * X * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ X Xvoid Xinhand(j) X X register int j; /* Pointer to optab[] entry */ X X{/* * * * * * * * * * START OF inhand() * * * * * * * * * */ X X register int k; X X objini(j); X X FETCH(k); X X if (ISFLOP(k)) X { X fphand(k); X return; X } X X printf("%s\t%d\n",optab[j].text,k); X X objout(); X X}/* * * * * * * * * * * END OF inhand() * * * * * * * * * * */ X X + END-OF-FILE disfp.c chmod 'u=rw,g=r,o=r' 'disfp.c' set `wc -c 'disfp.c'` count=$1 case $count in 5589) :;; *) echo 'Bad character count in ''disfp.c' >&2 echo 'Count should be 5589' >&2 esac echo Extracting 'dismain.c' sed 's/^X//' > 'dismain.c' << '+ END-OF-FILE ''dismain.c' Xstatic char *sccsid = X "@(#) dismain.c, Ver. 2.1 created 00:00:00 87/09/01"; X X /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * X * * X * Copyright (C) 1987 G. M. Harding, all rights reserved * X * * X * Permission to copy and redistribute is hereby granted, * X * provided full source code, with all copyright notices, * X * accompanies any redistribution. * X * * X * This file contains the source code for the machine- * X * independent portions of a disassembler program to run * X * in a Unix (System III) environment. It expects, as its * X * input, a file in standard a.out format, optionally con- * X * taining symbol table information. If a symbol table is * X * present, it will be used in the disassembly; otherwise, * X * all address references will be literal (absolute). * X * * X * The disassembler program was originally written for an * X * Intel 8088 CPU. However, all details of the actual CPU * X * architecture are hidden in three machine-specific files * X * named distabs.c, dishand.c, and disfp.c (the latter * X * file is specific to the 8087 numeric co-processor). The * X * code in this file is generic, and should require mini- * X * mal revision if a different CPU is to be targeted. If a * X * different version of Unix is to be targeted, changes to * X * this file may be necessary, and if a completely differ- * X * ent OS is to be targeted, all bets are off. * X * * X * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ X X#include "dis.h" /* Disassembler declarations */ X Xextern char *release; /* Contains release string */ X Xstatic char *IFILE = NULL; /* Points to input file name */ X Xstatic char *OFILE = NULL; /* Points to output file name */ X Xstatic char *PRG; /* Name of invoking program */ X Xstatic unsigned long zcount; /* Consecutive "0" byte count */ X Xint objflg = 0; /* Flag: output object bytes */ X X#define unix 1 X#define i8086 1 X#define ibmpc 1 X X#if unix && i8086 && ibmpc /* Set the CPU identifier */ Xstatic int cpuid = 1; X#else Xstatic int cpuid = 0; X#endif X X /* * * * * * * MISCELLANEOUS UTILITY FUNCTIONS * * * * * * */ X Xstatic void Xusage(s) X register char *s; X{ X fprintf(stderr,"\07usage: %s [-o] ifile [ofile]\n",s); X exit(-1); X} X Xstatic void Xfatal(s,t) X register char *s, *t; X{ X fprintf(stderr,"\07%s: %s\n",s,t); X exit(-1); X} X Xstatic void Xzdump(beg) X unsigned long beg; X{ X beg = PC - beg; X if (beg > 1L) X printf("\t.zerow\t%ld\n",(beg >> 1)); X if (beg & 1L) X printf("\t.byte\t0\n"); X} X Xstatic char * Xinvoker(s) X register char *s; X{ X extern int strlen(); X register int k; X X k = strlen(s); X X while (k--) X if (s[k] == '/') X { X s += k; X ++s; X break; X } X X return (s); X} X X /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * X * * X * This rather tricky routine supports the disdata() func- * X * tion. Its job is to output the code for a sequence of * X * data bytes whenever the object buffer is full, or when * X * a symbolic label is to be output. However, it must also * X * keep track of consecutive zero words so that lengthy * X * stretches of null data can be compressed by the use of * X * an appropriate assembler pseudo-op. It does this by * X * setting and testing a file-wide flag which counts suc- * X * cessive full buffers of null data. The function returns * X * a logical TRUE value if it outputs anything, logical * X * FALSE otherwise. (This enables disdata() to determine * X * whether to output a new synthetic label when there is * X * no symbol table.) * X * * X * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ X Xstatic int Xobjdump(c) X X register char *c; X X{/* * * * * * * * * * START OF objdump() * * * * * * * * * */ X X register int k; X int retval = 0; X X if (objptr == OBJMAX) X { X for (k = 0; k < OBJMAX; ++k) X if (objbuf[k]) X break; X if (k == OBJMAX) X { X zcount += k; X objptr = 0; X if (c == NULL) X return (retval); X } X } X X if (zcount) X { X printf("\t.zerow\t%ld\n",(zcount >> 1)); X ++retval; X zcount = 0L; X } X X if (objptr) X { X printf("\t.byte\t"); X ++retval; X } X else X return (retval); X X for (k = 0; k < objptr; ++k) X { X printf("0x%02.2x",objbuf[k]); X if (k < (objptr - 1)) X putchar(','); X else X putchar('\n'); X } X X objptr = 0; X X return (retval); X X}/* * * * * * * * * * END OF objdump() * * * * * * * * * */ X X /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * X * * X * This routine, called at the beginning of the input * X * cycle for each object byte, and before any interpreta- * X * tion is attempted, searches the symbol table for any * X * symbolic name with a value corresponding to the cur- * X * rent PC and a type corresponding to the segment type * X * (i.e., text, data, or bss) specified by the function's * X * argument. If any such name is found, a pointer to it is * X * returned; otherwise, a NULL pointer is returned. * X * * X * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ X Xstatic char * Xgetlab(type) X X register int type; X X{/* * * * * * * * * * START OF getlab() * * * * * * * * * */ X X register int k; X static char b[32], c[10]; X X if (symptr < 0) X if ((type == N_TEXT) X || ((type == N_DATA) && ( ! objptr ) && ( ! zcount ))) X { X if (type == N_TEXT) X sprintf(b,"T%05.5lx:",PC); X else X sprintf(b,"D%05.5lx:",PC); X return (b); X } X else X return (NULL); X X for (k = 0; k <= symptr; ++k) X if ((symtab[k].n_value == PC) X && ((symtab[k].n_sclass & N_SECT) == type)) X { X sprintf(b,"%s:\n",getnam(k)); X if (objflg && (type != N_TEXT)) X sprintf(c,"| %05.5lx\n",PC); X strcat(b,c); X return (b); X } X X return (NULL); X X}/* * * * * * * * * * * END OF getlab() * * * * * * * * * * */ X X /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * X * * X * This routine performs a preliminary scan of the symbol * X * table, before disassembly begins, and outputs declara- * X * tions of globals and constants. * X * * X * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ X Xstatic void Xprolog() X X{/* * * * * * * * * * START OF prolog() * * * * * * * * * */ X X register int j, flag; X X if (symptr < 0) X return; X X for (j = flag = 0; j <= symptr; ++j) X if ((symtab[j].n_sclass & N_CLASS) == C_EXT) X if (((symtab[j].n_sclass & N_SECT) > N_UNDF) X && ((symtab[j].n_sclass & N_SECT) < N_COMM)) X { X char *c = getnam(j); X printf("\t.globl\t%s",c); X if (++flag == 1) X { X putchar('\t'); X if (strlen(c) < 8) X putchar('\t'); X printf("| Internal global\n"); X } X else X putchar('\n'); X } X else X if (symtab[j].n_value) X { X char *c = getnam(j); X printf("\t.comm\t%s,0x%08.8lx",c, X symtab[j].n_value); X if (++flag == 1) X printf("\t| Internal global\n"); X else X putchar('\n'); X } X X if (flag) X putchar('\n'); X X for (j = flag = 0; j <= relptr; ++j) X if (relo[j].r_symndx < S_BSS) X { X char *c = getnam(relo[j].r_symndx); X ++flag; X printf("\t.globl\t%s",c); X putchar('\t'); X if (strlen(c) < 8) X putchar('\t'); X printf("| Undef: %05.5lx\n",relo[j].r_vaddr); X } X X if (flag) X putchar('\n'); X X for (j = flag = 0; j <= symptr; ++j) X if ((symtab[j].n_sclass & N_SECT) == N_ABS) X { X char *c = getnam(j); X printf("%s=0x%08.8lx",c,symtab[j].n_value); X if (++flag == 1) X { X printf("\t\t"); X if (strlen(c) < 5) X putchar('\t'); X printf("| Literal\n"); X } X else X putchar('\n'); X } X X if (flag) X putchar('\n'); X X}/* * * * * * * * * * * END OF prolog() * * * * * * * * * * */ X X /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * X * * X * This function is responsible for disassembly of the * X * object file's text segment. * X * * X * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ X Xstatic void Xdistext() X X{/* * * * * * * * * * START OF distext() * * * * * * * * * */ X X char *c; X register int j; X register void (*f)(); X X for (j = 0; j < (int)(HDR.a_hdrlen); ++j) X getchar(); X X printf("| %s, %s\n\n",PRG,release); X X printf("| @("); X X printf("#)\tDisassembly of %s",IFILE); X X if (symptr < 0) X printf(" (no symbols)\n\n"); X else X printf("\n\n"); X X if (HDR.a_flags & A_EXEC) X printf("| File is executable\n\n"); X X if (HDR.a_flags & A_SEP) X { X printf("| File has split I/D space, and may have\n"); X printf("| extraneous instructions in text segment\n\n"); X } X X prolog(); X X printf("\t.text\t\t\t| loc = %05.5lx, size = %05.5lx\n\n", X PC,HDR.a_text); X X segflg = 0; X X for (PC = 0L; PC < HDR.a_text; ++PC) X { X j = getchar() & 0xff; X if ((j == 0) && ((PC + 1L) == HDR.a_text)) X { X ++PC; X break; X } X if ((c = getlab(N_TEXT)) != NULL) X printf("%s",c); X f = optab[j].func; X (*f)(j); X } X X}/* * * * * * * * * * END OF distext() * * * * * * * * * */ X X /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * X * * X * This function handles the object file's data segment. * X * There is no good way to disassemble a data segment, be- * X * cause it is impossible to tell, from the object code * X * alone, what each data byte refers to. If it refers to * X * an external symbol, the reference can be resolved from * X * the relocation table, if there is one. However, if it * X * refers to a static symbol, it cannot be distinguished * X * from numeric, character, or other pointer data. In some * X * cases, one might make a semi-educated guess as to the * X * nature of the data, but such guesses are inherently * X * haphazard, and they are bound to be wrong a good por- * X * tion of the time. Consequently, the data segment is * X * disassembled as a byte stream, which will satisfy no * X * one but which, at least, will never mislead anyone. * X * * X * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ X Xstatic void Xdisdata() X X{/* * * * * * * * * * START OF disdata() * * * * * * * * * */ X X register char *c; X register int j; X unsigned long end; X X putchar('\n'); X X if (HDR.a_flags & A_SEP) X { X PC = 0L; X end = HDR.a_data; X } X else X end = HDR.a_text + HDR.a_data; X X printf("\t.data\t\t\t| loc = %05.5lx, size = %05.5lx\n\n", X PC,HDR.a_data); X X segflg = 0; X X for (objptr = 0, zcount = 0L; PC < end; ++PC) X { X if ((c = getlab(N_DATA)) != NULL) X { X objdump(c); X printf("%s",c); X } X if (objptr >= OBJMAX) X if (objdump(NULL) && (symptr < 0)) X printf("D%05.5lx:",PC); X j = getchar() & 0xff; X objbuf[objptr++] = j; X } X X objdump(""); X X}/* * * * * * * * * * END OF disdata() * * * * * * * * * */ X X /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * X * * X * This function handles the object file's bss segment. * X * Disassembly of the bss segment is easy, because every- * X * thing in it is zero by definition. * X * * X * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ X Xstatic void Xdisbss() X X{/* * * * * * * * * * START OF disbss() * * * * * * * * * */ X X register int j; X register char *c; X unsigned long beg, end; X X putchar('\n'); X X if (HDR.a_flags & A_SEP) X end = HDR.a_data + HDR.a_bss; X else X end = HDR.a_text + HDR.a_data + HDR.a_bss; X X printf("\t.bss\t\t\t| loc = %05.5lx, size = %05.5lx\n\n", X PC,HDR.a_bss); X X segflg = 0; X X for (beg = PC; PC < end; ++PC) X if ((c = getlab(N_BSS)) != NULL) X { X if (PC > beg) X { X zdump(beg); X beg = PC; X } X printf("%s",c); X } X X if (PC > beg) X zdump(beg); X X}/* * * * * * * * * * * END OF disbss() * * * * * * * * * * */ X X /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * X * * X * This is the program entry point. The command line is * X * searched for an input file name, which must be present. * X * An optional output file name is also permitted; if none * X * is found, standard output is the default. One command- * X * line option is available: "-o", which causes the pro- * X * gram to include object code in comments along with its * X * mnemonic output. * X * * X * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ X Xvoid Xmain(argc,argv) X X int argc; /* Command-line args from OS */ X register char **argv; X X{/* * * * * * * * * * * START OF main() * * * * * * * * * * */ X X char a[1024]; X register int fd; X long taboff, tabnum; X long reloff, relnum; X X PRG = invoker(*argv); X X while (*++argv != NULL) /* Process command-line args */ X if (**argv == '-') X switch (*++*argv) X { X case 'o' : X if (*++*argv) X usage(PRG); X else X ++objflg; X break; X default : X usage(PRG); X } X else X if (IFILE == NULL) X IFILE = *argv; X else if (OFILE == NULL) X OFILE = *argv; X else X usage(PRG); X X if (IFILE == NULL) X usage(PRG); X else X if ((fd = open(IFILE,0)) < 0) X { X sprintf(a,"can't access input file %s",IFILE); X fatal(PRG,a); X } X X if (OFILE != NULL) X if (freopen(OFILE,"w",stdout) == NULL) X { X sprintf(a,"can't open output file %s",OFILE); X fatal(PRG,a); X } X X if ( ! cpuid ) X fprintf(stderr,"\07%s: warning: host/cpu clash\n",PRG); X X read(fd,&HDR,sizeof(struct exec)); X X if (BADMAG(HDR)) X { X sprintf(a,"input file %s not in object format",IFILE); X fatal(PRG,a); X } X X if (HDR.a_cpu != A_I8086) X { X sprintf(a,"%s is not an 8086/8088 object file",IFILE); X fatal(PRG,a); X } X X if (HDR.a_hdrlen <= A_MINHDR) X HDR.a_trsize = HDR.a_drsize = 0L; X HDR.a_tbase = HDR.a_dbase = 0L; X/* AST emergency patch X HDR.a_lnums = HDR.a_toffs = 0L; X*/ X X reloff = HDR.a_text /* Compute reloc data offset */ X + HDR.a_data X + (long)(HDR.a_hdrlen); X X relnum = X (HDR.a_trsize + HDR.a_drsize) / sizeof(struct reloc); X X taboff = reloff /* Compute name table offset */ X + HDR.a_trsize X + HDR.a_drsize; X X tabnum = HDR.a_syms / sizeof(struct nlist); X X if (relnum > MAXSYM) X fatal(PRG,"reloc table overflow"); X X if (tabnum > MAXSYM) X fatal(PRG,"symbol table overflow"); X X if (relnum) /* Get reloc data */ X if (lseek(fd,reloff,0) != reloff) X fatal(PRG,"lseek error"); X else X { X for (relptr = 0; relptr < relnum; ++relptr) X read(fd,&relo[relptr],sizeof(struct reloc)); X relptr--; X } X X if (tabnum) /* Read in symtab */ X if (lseek(fd,taboff,0) != taboff) X fatal(PRG,"lseek error"); X else X { X for (symptr = 0; symptr < tabnum; ++symptr) X read(fd,&symtab[symptr],sizeof(struct nlist)); X symptr--; X } X else X fprintf(stderr,"\07%s: warning: no symbols\n",PRG); X X close(fd); X X if (freopen(IFILE,"r",stdin) == NULL) X { X sprintf(a,"can't reopen input file %s",IFILE); X fatal(PRG,a); X } X X distext(); X X disdata(); X X disbss(); X X exit(0); X X}/* * * * * * * * * * * END OF main() * * * * * * * * * * */ X X + END-OF-FILE dismain.c chmod 'u=rw,g=r,o=r' 'dismain.c' set `wc -c 'dismain.c'` count=$1 case $count in 17461) :;; *) echo 'Bad character count in ''dismain.c' >&2 echo 'Count should be 17461' >&2 esac exit 0