diff options
Diffstat (limited to 'dis88/dishand.c')
-rw-r--r-- | dis88/dishand.c | 1049 |
1 files changed, 1049 insertions, 0 deletions
diff --git a/dis88/dishand.c b/dis88/dishand.c new file mode 100644 index 0000000..5983972 --- /dev/null +++ b/dis88/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[80]; + + 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[80]; + + 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[80]; + + 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[80]; + + 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[80]; + + 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() * * * * * * * * * * */ + + |