/* ** OBJASM - Utility to create .ASM files out of .OBJ files. ** Options are: ** ** -r = Create RASM86 compatible output (.A86 instead of .ASM) ** -4 = Make compatible with MASM v4.0 (no retf) ** -a = Add labels for un-named data references ** -h = Hex output as comments ** -v = 486 instructions ** -s# = Minimum string size in data segment ** -c# = Minimum string size in code segment ** -f(filename) = Additional information filename (w/paren.) ** ** Includes 8086/80186/80286/80386/80486 ** and 8087/80287/80387 coprocessor instructions ** See OBJASM.DOC for a more detailed description. ** (C) Copyright 1988,1989,1990,1991 by Robert F. Day, All rights reserved. ** ** Send/phone questions, comments, and bugs to: ** ** Robert F. Day ** 19906 Filbert Dr. ** Bothell, WA 98012 ** (206) 481-8431 */ #include #include #include #include #include "o.h" /*--- Expanded INTEL OMF record types --*/ #define RHEADR 0x6E /* R-Module Header Record */ #define REGINT 0x70 /* Register Initialization Record */ #define REDATA 0x72 /* Relocatable Enumerated Data Record */ #define RIDATA 0x74 /* Relocatable Iterated Data Record */ #define OVLDEF 0x76 /* Overlay Definition Record */ #define ENDREC 0x78 /* End Record */ #define BLKREC 0x7A /* Block Definition Record */ #define BKLEND 0x7C /* Block End Record */ #define DEBSYM 0x7E /* Debug Symbols Record */ #define THEADR 0x80 /* x T-Module Header Record */ #define LHEADR 0x82 /* L-Module Header Record */ #define PEDATA 0x84 /* Physical Enumerated Data (?) */ #define PIDATA 0x86 /* Physical Iterated Data (?) */ #define COMENT 0x88 /* x Comment Record */ #define MODEND 0x8A /* x Module End Record */ #define MODENDL 0x8B /* l Module End Record */ #define EXTDEF 0x8C /* x External Names Definition Record */ #define TYPDEF 0x8E /* Type Definitions Record */ #define PUBDEF 0x90 /* x Public Names Definition Record */ #define PUBDEFL 0x91 /* l Public Names Definition Record */ #define LOCSYM 0x92 /* Local Symbols Record */ #define LINNUM 0x94 /* Line Numbers Record */ #define LNAMES 0x96 /* x List of Names Record */ #define SEGDEF 0x98 /* x Segment Definition Record */ #define SEGDEFL 0x99 /* l Segment Definition Record */ #define GRPDEF 0x9A /* x Group Definition Record */ #define FIXUPP 0x9C /* x Fix-Up Record */ #define FIXUPPL 0x9D /* l Fix-Up Record */ #define LEDATA 0xA0 /* x Logical Enumerated Data */ #define LEDATAL 0xA1 /* l Logical Enumerated Data */ #define LIDATA 0xA2 /* x Logical Iterated Data */ #define LIDATAL 0xA3 /* l Logical Iterated Data */ #define LIBHED 0xA4 /* Library Header Record */ #define LIBNAM 0xA6 /* Library Module Names Record */ #define LIBLOC 0xA8 /* Library Module Locations Record */ #define LIBDIC 0xAA /* Library Dictionary Record */ #define COMDEF 0xB0 /* m Communal Data Definition Record */ #define LEXTDEF 0xB4 /* m Local External Definition */ #define LPUBDEF 0xB6 /* m Local Public Definition */ #define LPUBDF2 0xB7 /* m Local Public Definition (2nd case?)*/ #define LCOMDEF 0xB8 /* m Local Communal Data Definition */ #define LIBHDR 0xF0 /* m Library Header Record */ #define LIBEND 0xF1 /* m Library Trailer Record */ /* x = Intel OMF used by Microsoft */ /* m = Microsoft Additions to Intel OMF */ /* l = Later extensions by Microsoft */ /* ** Local Prototypes */ int main( int, char *[] ); FILE *o_file; /* .OBJ file that we are processing */ long o_position; /* Position in file of current data */ NODE_T *line_tree; NODE_T *arg_scope_tree; NODE_T *loc_scope_tree; NODE_T *end_scope_tree; NODE_T *name_tree; NODE_T *segment_tree; NODE_T *group_tree; NODE_T *public_tree; NODE_T *extern_tree; NODE_T *sex_tree; NODE_T *data_tree; NODE_T *struc_tree; NODE_T *fix_tree; NODE_T *hint_tree; NODE_T *type_tree; NODE_T *block_tree; SEG_T *seg_rec; SEG_T seg_search; GRP_T grp_search; NODE_T *pub_node; PUB_T *pub_rec; PUB_T *last_pub_rec; PUB_T pub_search; NODE_T *hint_node; HINT_T *hint_rec; HINT_T hint_search; THREAD_T threads[2][4] = {0}; NODE_T *fix_node; FIX_T *fix_rec; FIX_T fix_search; NAME_T name_search; int label_count = 0; int segment; dword inst_offset; int processor_mode = 0; int segment_mode; int segment_bytes; char *cseg_name; PUB_T *start_pub = NULL; word code_string = 40; /* Stringizing Limit in Code */ word data_string = 3; /* Stringizing Limit in Data */ int pass; /* 1=Building Labels, 2=Generating Output */ int processor_type_comment_occurred = FALSE; /* No processor spec yet */ int hex_finish; /* For hex comments */ int tab_offset = 0; /* Current tab offset, 0 = none */ int compatibility = 0; /* 0 = MASM 5.0+ (Microsoft) */ /* 1 = MASM 4.0 (Microsoft) */ /* 2 = RASM86 (Digital Research) */ int add_labels = FALSE; /* No, treat as .obj translator */ /* Otherwise, treat as .asm creator */ /* Translator is a strict translation */ int hex_output = FALSE; /* Display hex code as comments? */ char extra_filename[65] = {'\0'};/* Additional information file */ /* ** ------- Exit values -------- ** ** 0 = Successful operation ** ** 1 = Improper Usage ** ** 2 = Unable to open OBJ file ** ** 3 = Premature end of file ** ** 4 = Out of memory ** ** 5 = .OBJ Format error ** ** 6 = Unable to open ADD file ** ** 7 = Syntax error in ADD file ** ** ------- Exit values -------- ** */ int main( argc, argv ) int argc; char *argv[]; { char *argp; int name_arg; int argi; int bad_args; char *fnamep; dword position; int at_eof; int rec_type; word rec_length; char temp_name[50]; char ch; int i486; bad_args = FALSE; argi = 1; name_arg = 0; i486 = FALSE; while ( argi < argc ) { argp = argv[argi]; if ( *argp++ == '-' ) { while ( *argp ) { switch ( *argp ) { case 'a': add_labels = TRUE; break; case '4': compatibility = 1; break; case 'r': compatibility = 2; break; case 'h': hex_output = TRUE; break; case 'v': i486 = TRUE; break; case 'c': code_string = atoi(argp+1); while ( (ch = *(argp+1)) != '\0' ) { if ( ch < '0' || ch > '9' ) { break; } argp++; } break; case 's': code_string = atoi(argp+1); while ( (ch = *(argp+1)) != '\0' ) { if ( ch < '0' || ch > '9' ) { break; } argp++; } break; case 'f': argp++; if ( *argp != '(' ) { bad_args = TRUE; break; } fnamep = extra_filename; while ( (ch = *(argp+1)) != '\0' ) { argp++; if ( ch == ')' ) { *fnamep = '\0'; break; } *fnamep++ = ch; } if ( ch == '\0' ) { bad_args = TRUE; } break; default: bad_args = TRUE; break; } argp++; } } else { if ( name_arg == 0 ) { name_arg = argi; } else { bad_args = TRUE; } } argi++; } if ( name_arg == 0 ) { bad_args = TRUE; } if ( bad_args ) { fprintf( stderr, "Usage: %s [-options] [objfilename]\n", argv[0] ); fprintf( stderr, "where -options are:\n" ); fprintf( stderr, " -4 Make MASM 4.0 compatible (no RETF)\n" ); fprintf( stderr, " -a Add labels for un-named data references\n"); fprintf( stderr, " -h Hex output in comments\n"); fprintf( stderr, " -r Make RASM86 compatible\n" ); fprintf( stderr, " -v Include 486 instructions\n" ); fprintf( stderr, " -c# Minimum string size in a code segment (default=40)\n"); fprintf( stderr, " -s# Mimimum string size in a data segment (default=3)\n"); fprintf( stderr, " -f(filename) Additional information filename (w/paren.)\n"); fprintf( stderr, "\n" ); fprintf( stderr, "Additional information file lines:\n"); fprintf( stderr, "SEG sname CODE named segment is a code segment\n"); fprintf( stderr, "SEG sname DATA named segment is a data segment\n"); fprintf( stderr, "var=sname:#### creates a local label in segment name\n"); fprintf( stderr, "sname:####:DB/DW/DD/DF/DQ/DT directs dis-assembly into data\n"); fprintf( stderr, "... (for more info, read OBJASM.DOC)\n"); exit(1); } switch( compatibility ) { case 0: /* MASM 5.0+ */ if ( i486 ) { ex_instr[0x08].text = "invd"; ex_instr[0x09].text = "wbinvd"; op_grp[6][7] = "invlpg"; ex_instr[0xA6].text = "cmpxchg"; ex_instr[0xA7].text = "cmpxchg"; ex_instr[0xC0].text = "xadd"; ex_instr[0xC1].text = "xadd"; ex_instr[0xC8].text = "bswap"; ex_instr[0xC9].text = "bswap"; ex_instr[0xCA].text = "bswap"; ex_instr[0xCB].text = "bswap"; ex_instr[0xCC].text = "bswap"; ex_instr[0xCD].text = "bswap"; ex_instr[0xCE].text = "bswap"; ex_instr[0xCF].text = "bswap"; } break; case 1: /* MASM 4.0 */ /* ** Make far return only a comment */ instr[0xCB].text = "ret\t; (retf)"; break; case 2: /* RASM86 */ /* ** Make xlat a xlat bx */ instr[0xD7].text = "xlat\tbx"; /* ** Make short jmp a jmps */ instr[0xEB].text = "jmps"; /* ** Make far jmp a jmpf */ op_grp[4][5] = "jmpf"; break; } strcpy( temp_name, argv[name_arg] ); if ( strchr(temp_name,'.') == NULL ) { /* Append ".obj" if no extension */ strcat( temp_name, ".obj" ); /* is supplied */ } o_file = fopen( temp_name, "rb" ); if ( o_file == NULL ) { fprintf( stderr, "%s: Cannot open %s\n", argv[0], temp_name ); exit(2); } /* Print copyright message */ printf("; OBJASM version 2.0 released on Jan 3, 1991\n"); printf("; (C) Copyright 1988,1989,1990,1991 by Robert F. Day. All rights reserved\n\n"); init_trees(); /* Initialize all trees */ at_eof = FALSE; position = 0; while ( !at_eof ) { fseek( o_file, position, L_SET ); rec_type = fgetc( o_file ); if ( rec_type == EOF ) { at_eof = TRUE; } else { rec_length = getw( o_file ); o_position = position + 3; /* (1 rec_type) + (2 rec_length) */ #ifdef DEBUG printf("PROCESSING rec_type [%02X] rec_length [%04X]\n", rec_type, rec_length ); #endif switch( rec_type ) { case THEADR: theadr(); break; case LNAMES: lnames( rec_length ); break; case GRPDEF: grpdef( rec_length ); break; case SEGDEF: segdef(); break; case SEGDEFL: segdef(); break; case PUBDEF: pubdef( rec_length, TRUE ); break; case PUBDEFL: pubdef( rec_length, TRUE ); break; case LPUBDEF: pubdef( rec_length, FALSE ); break; case LPUBDF2: pubdef( rec_length, FALSE ); break; case EXTDEF: extdef( rec_length, TRUE ); break; case LEXTDEF: extdef( rec_length, FALSE ); break; case LEDATA: ledata( rec_length, REGULAR ); break; case LEDATAL: ledata( rec_length, LARGER ); break; case LIDATA: lidata( rec_length, REGULAR ); break; case LIDATAL: lidata( rec_length, LARGER ); break; case FIXUPP: fixupp( rec_length, REGULAR ); break; case FIXUPPL: fixupp( rec_length, LARGER ); break; case COMDEF: comdef( rec_length, TRUE ); break; case LCOMDEF: comdef( rec_length, FALSE ); break; case MODEND: modend( rec_length, REGULAR ); at_eof = TRUE; break; case MODENDL: modend( rec_length, LARGER ); at_eof = TRUE; break; case TYPDEF: break; case COMENT: printf("; [%04X]",position); coment( rec_length ); break; case LINNUM: linnum( rec_length ); break; default: printf( "Bad record type: [%08lX:%02X:%04X]\n", position, rec_type, rec_length ); break; } position += 3 + rec_length; } } #ifdef DEBUG printf("PROCESSING dis-assembly, pass 1\n"); #endif if ( strlen(extra_filename) != 0 ) { load_extra( argv[0], extra_filename ); } pass = 1; process(); /* First pass: Processing */ pass = 2; process(); /* Second pass: Figure out labels */ #ifdef DEBUG printf("PROCESSING listing externals\n"); #endif list_ext(); /* Show EXTERNAL's */ #ifdef DEBUG printf("PROCESSING listing publics and communal definitions\n"); #endif list_pub(); /* Show PUBLIC's */ list_struc(); /* Show STRUC's */ #ifdef DEBUG printf("PROCESSING dis-assembly, pass 2 (last)\n"); #endif pass = 3; process(); /* Third pass: Output */ fclose( o_file ); #ifdef DEBUG printf("END OF RUN\n"); #endif return(0); }