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  */

ImgHeader 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  */
    "\t.code\t386", sbhand, 1, 1,	/* 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  */
    "\tseg\tfs", sbhand, 1, 1,	/* 0x64  */
    "\tseg\tgs", sbhand, 1, 1,	/* 0x65  */
    "\tuse\top32", sbhand, 1, 1,	/* 0x66  */
    "\tuse\tadr32", sbhand, 1, 1,	/* 0x67  */
    "\tpush\t", mihand, 3, 3,	/* 0x68  */
#if 0
    NULL, dfhand, 0, 0,		/* 0x68  */
#endif
    NULL, dfhand, 0, 0,		/* 0x69  */
    "\tpush\t", mihand, 2, 2,	/* 0x6a  */
#if 0
    NULL, dfhand, 0, 0,		/* 0x6a  */
#endif
    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  */
#if 0
    /* MJG: this should be retf */
    "\treti", rehand, 3, 3,	/* 0xca  */
#endif
    "\tretf", rehand, 3, 3,	/* 0xca  */
    "\tretf", 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(register int k)
{				/* * * * * * * * * *  START OF getnam()  * * * * * * * * * */

    static char a[sizeof(symtab->n_name) + 1];
    register int j;

    for (j = 0; j < sizeof(symtab[k].n_name); ++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(long off, long loc, char *buf)
{				/* * * * * * * * * * START OF  lookext() * * * * * * * * * */

    char c[32];
    register int k;

    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(long addr,		/* Machine address to be located */
	     int type,		/* Type of symbol to be matched  */
	     int kind,		/* Addressing output mode to use */
	     long ext)
{				/* Value for extern ref, if any  *//* * * * * * * * * *  START OF lookup()  * * * * * * * * * */

    static char b[80];
    register int j, k;

    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)) */
	    else if (segflg)	/* Assume (HDR.a_flags & A_SEP)) true */
		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, "$%04lx", 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!                                 *
  *                                                         *
  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

#undef FRV
#define FRV ""

char *mtrans(register int c,	/* Primary instruction byte   */
	     register int m,	/* Addressing mode byte       */
	     int type)
{				/* Type code: standard or seg *//* * * * * * * * * *  START OF mtrans()  * * * * * * * * * */

    static char a[128], b[32];
    unsigned long pc;
    int offset, oflag, dir, w, mod, reg, rm;

    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(", (short) 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(", (short) 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(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() * * * * * * * * * * */

