home *** CD-ROM | disk | FTP | other *** search
- /************************************************************************
- * exehex.c - This program converts Microsoft .EXE files to Intel *
- * HEX files suitable for burning into EPROM. Like the *
- * loader in MSDOS, exehex performs any necessary *
- * relocation of segments in the .EXE file. *
- ************************************************************************/
-
- /************************************************************************
- * Copyright 1991, Charles F. Harris, C.F. Harris - Consulting. *
- * *
- * You may use this program for any purpose Commercial or Private with *
- * following exceptions: *
- * *
- * 1) You may not sell this program without my written permission. *
- * 2) You must leave this header comment unmodified, and intact. *
- * 3) You must clearly identify any modifications that you make. *
- * *
- * This program is provided without any warantees or support, and is *
- * to be used at your own risk. *
- ************************************************************************/
-
- /************************************************************************
- * This program was designed to run on 80x86 type machines, and to be *
- * compiled with TURBO C++ V1.00. (that is not to say that it is *
- * written in C++) *
- * I can be reached at: chuck@eng.umd.edu *
- * or at: Chuck Harris *
- * C.F. Harris - Consulting *
- * 9308 Canterbury Riding *
- * Laurel, Maryland 20723 *
- ************************************************************************/
-
- #include <dir.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <stdarg.h>
- #include <string.h>
- #include <io.h>
-
- #define ERR(s, c) if(opterr){\
- char errbuf[2];\
- errbuf[0] = c; errbuf[1] = '\n';\
- (void) write(2, argv[0], (unsigned)strlen(argv[0]));\
- (void) write(2, s, (unsigned)strlen(s));\
- (void) write(2, errbuf, 2);}
-
- #define DATAREC 0
- #define EXADDR 2
- #define ENDREC 1
-
-
- struct EXEHDR {
- unsigned signature; /* linker signature */
- unsigned image_rsize; /* length of image mod 512 */
- unsigned file_nblks; /* number of 512 byte blocks in file */
- unsigned num_rels; /* number of relocation items */
- unsigned header_size; /* size in paragraphs */
- unsigned minheap_size; /* min num paragraphs in heap */
- unsigned maxheap_size; /* max num paragraphs in heap */
- unsigned stackseg_offset; /* offset of stack seg in load module */
- unsigned initial_SP; /* initial value of stack register */
- unsigned checksum; /* neg sum of all words in file */
- unsigned initial_IP; /* initial value of instruction ptr */
- unsigned codeseg_offset; /* offset of code seg in load module */
- unsigned reltbl_offset; /* offset of first relocation item */
- unsigned overlay_num; /* overlay number (0 == resident part) */
- } exehdr;
-
- typedef struct RELTBL {
- unsigned rel_offset;
- unsigned rel_segment;
- } RELTBL;
-
- int opterr = 1;
- int optind = 1;
- int optopt;
- char *optarg;
-
- char *tempfile = "exehexXXXXXX"; /* template for mktemp() */
- char *tmpfname = 0; /* name of temp file */
-
- FILE *fopen(),*fpi,*fpo,*fpt;
- int ABORT(char *reason, ...);
-
- unsigned char intelstring[100];
- unsigned segment = 0, offset = 0;
- unsigned imagelen = 0;
- unsigned debug = 0;
- unsigned no_end_record = 0;
-
- RELTBL *reloc_tbl;
-
- main(argc,argv)
- int argc;
- char **argv;
- {
- discover_options(argc,argv);
- open_files(argc,argv);
- read_exe_header();
- read_relocation_table();
- copy_image_to_temp();
- relocate_image();
- write_hex_file();
- remove_temp_file();
- }
-
- discover_options(argc,argv)
- int argc;
- char **argv;
- {
- char *ourargs = "o:O:s:S:dDN?Hh";
- int opt;
-
- while((opt=getopt(argc,argv,ourargs)) != EOF){
- switch(opt){
- case 'd':
- case 'D':
- fprintf(stderr,"DEBUG level is: %d\n",++debug);
- break;
- case 's':
- case 'S':
- sscanf(optarg,"%x",&segment);
- if(debug>=1){
- fprintf(stderr,"Segment= 0x%X\n",segment);
- }
- break;
- case 'o':
- case 'O':
- sscanf(optarg,"%x",&offset);
- if(debug>=1){
- fprintf(stderr,"Offset= 0x%X\n",offset);
- }
- break;
- case 'N':
- no_end_record++;
- if(debug>=1){
- fprintf(stderr,"No End Record\n");
- }
- break;
- case '?':
- case 'h':
- case 'H':
- how_to_use_message();
- break;
- default:
- ABORT("Unknown argument");
- }
- }
- }
-
- /*
- * getopt a wonderful little function that handles the command line.
- * available courtesy of AT&T.
- */
-
- int
- getopt(argc, argv, opts)
- int argc;
- char **argv, *opts;
- {
- static int sp = 1;
- register int c;
- register char *cp;
-
- if(sp == 1)
- if(optind >= argc ||
- argv[optind][0] != '-' || argv[optind][1] == '\0')
- return(EOF);
- else if(strcmp(argv[optind], "--") == NULL) {
- optind++;
- return(EOF);
- }
- optopt = c = argv[optind][sp];
- if(c == ':' || (cp=strchr(opts, c)) == NULL) {
- ERR(": illegal option -- ", c);
- if(argv[optind][++sp] == '\0') {
- optind++;
- sp = 1;
- }
- return('?');
- }
- if(*++cp == ':') {
- if(argv[optind][sp+1] != '\0')
- optarg = &argv[optind++][sp+1];
- else if(++optind >= argc) {
- ERR(": option requires an argument -- ", c);
- sp = 1;
- return('?');
- } else
- optarg = argv[optind++];
- sp = 1;
- } else {
- if(argv[optind][++sp] == '\0') {
- sp = 1;
- optind++;
- }
- optarg = NULL;
- }
- return(c);
- }
-
- open_files(argc,argv)
- int argc;
- char **argv;
- {
- int argind, files_found;
-
- argc--,argv++; /* skip the program name */
- for(argind=0,files_found=0; argind<argc; argind++){
- if(argv[argind][0] == '-') continue;
- if(debug>=1){
- fprintf(stderr,"Argument is: %s\n",argv[argind]);
- }
- files_found++;
-
- if(files_found==1 && !(fpi=fopen(argv[argind],"rb"))){
- ABORT("opening %s",argv[argind]);
- }
- else if(files_found==2 && !(fpo=fopen(argv[argind],"wb"))){
- ABORT("opening %s",argv[argind]);
- }
- else if(files_found > 2){
- ABORT("too many file arguments\n");
- }
- }
- if(files_found == 0){
- ABORT("need a file to work on!");
- }
- else if(files_found == 1){
- fpo = stdout;
- }
- tmpfname = mktemp(tempfile);
- if(!(fpt=fopen(tmpfname,"wb+"))){
- ABORT("can't open temporary file: %s",tmpfname);
- }
- }
-
- read_exe_header()
- {
- if(fread(&exehdr,sizeof(struct EXEHDR),1,fpi) != 1){
- ABORT("couldn't read exe header");
- }
- if(debug>=1){
- print_exe_header();
- }
- if(exehdr.signature != 0x5a4d){
- ABORT("bad exe signature:[0x%X]",exehdr.signature);
- }
- imagelen = exehdr.file_nblks*512 - exehdr.header_size*16;
- imagelen -= (exehdr.image_rsize == 4) ? 0 : exehdr.image_rsize;
- if(debug>=1){
- fprintf(stderr,"binary image length is: 0x%X,(%dd)\n",imagelen,imagelen);
- }
- }
-
- print_exe_header()
- {
- fprintf(stderr,"EXE HEADER:\n");
- fprintf(stderr,"->signature = 0x%X\n",exehdr.signature);
- fprintf(stderr,"->image_rsize = 0x%X\n",exehdr.image_rsize);
- fprintf(stderr,"->file_nblks = 0x%X\n",exehdr.file_nblks);
- fprintf(stderr,"->num_rels = 0x%X\n",exehdr.num_rels);
- fprintf(stderr,"->header_size = 0x%X\n",exehdr.header_size);
- fprintf(stderr,"->minheap_size = 0x%X\n",exehdr.minheap_size);
- fprintf(stderr,"->maxheap_size = 0x%X\n",exehdr.maxheap_size);
- fprintf(stderr,"->stackseg_offset = 0x%X\n",exehdr.stackseg_offset);
- fprintf(stderr,"->initial_SP = 0x%X\n",exehdr.initial_SP);
- fprintf(stderr,"->checksum = 0x%X\n",exehdr.checksum);
- fprintf(stderr,"->initial_IP = 0x%X\n",exehdr.initial_IP);
- fprintf(stderr,"->codeseg_offset = 0x%X\n",exehdr.codeseg_offset);
- fprintf(stderr,"->reltbl_offset = 0x%X\n",exehdr.reltbl_offset);
- fprintf(stderr,"->overlay_num = 0x%X\n",exehdr.overlay_num);
- }
-
- read_relocation_table()
- {
- int i;
-
- if(exehdr.num_rels == 0) return; /* can't do much here */
-
- reloc_tbl = (RELTBL *)malloc(exehdr.num_rels * sizeof(RELTBL));
- if(!reloc_tbl){
- ABORT("can't malloc reloc_tbl");
- }
- if(fseek(fpi,(long)exehdr.reltbl_offset,SEEK_SET) != 0){
- ABORT("couldn't fseek to relocation tbl");
- }
- if(fread(reloc_tbl, sizeof(RELTBL) * exehdr.num_rels, 1, fpi) != 1){
- ABORT("couldn't read relocation table");
- }
- if(debug>=1){
- fprintf(stderr,"RELOCATION TABLE\n");
- for(i=0;i<exehdr.num_rels;i++){
- fprintf(stderr,"seg= 0x%X, off= 0x%X\n",reloc_tbl[i].rel_segment, reloc_tbl[i].rel_offset);
- }
- }
- }
-
- copy_image_to_temp()
- {
- unsigned char bytes;
- unsigned char data[32];
-
- if(fseek(fpi, (long)exehdr.header_size * 16, SEEK_SET) != 0){
- ABORT("couldn't fseek() to data image");
- }
- while((bytes = fread(data,1,32,fpi)) == 32){
- if(fwrite(data,1,32,fpt) != 32){
- ABORT("couldn't write temp file");
- }
- bytes = 0;
- }
- if(bytes > 0){ /* any fraction remaining? */
- if(fwrite(data,1,bytes,fpt) != bytes){
- ABORT("couldn't write temp file");
- }
- }
- }
-
- relocate_image()
- {
- long iptr; /* image pointer */
- int i;
- unsigned rel_word;
-
- for(i=0; i<exehdr.num_rels; i++){
- iptr = reloc_tbl[i].rel_segment*16 + reloc_tbl[i].rel_offset;
- if(fseek(fpt, iptr, SEEK_SET) != 0){
- ABORT("couldn't fseek() to rel item");
- }
- if(fread(&rel_word,sizeof(unsigned),1,fpt) != 1){
- ABORT("couldn't read rel item");
- }
- rel_word += segment; /* relocate rel_word */
- if(fseek(fpt, iptr, SEEK_SET) != 0){
- ABORT("couldn't fseek() to rel item");
- }
- if(fwrite(&rel_word,sizeof(unsigned),1,fpt) != 1){
- ABORT("couldn't write back rel item");
- }
- }
- }
-
- write_hex_file()
- {
- unsigned data[32];
- unsigned char bytes;
- unsigned address = offset;
-
- if(fseek(fpt, (long)0, SEEK_SET) != 0){
- ABORT("couldn't fseek() to data image 0");
- }
- write_extended_address_record(segment);
- while((bytes = fread(data,1,32,fpt)) == 32){
- write_data_record(address,bytes,data);
- address += bytes;
- bytes = 0;
- }
- if(bytes > 0){ /* any fraction remaining? */
- write_data_record(address,bytes,data);
- }
- if(!no_end_record){
- write_end_record(0);
- }
- }
-
- write_data_record(address,datalen,data)
- unsigned address;
- unsigned char datalen;
- unsigned char data[];
- {
- build_hex_record(DATAREC,address,datalen,data);
- fputs(intelstring,fpo);
- }
-
- write_extended_address_record(usba)
- unsigned usba;
- {
- unsigned char data[2];
-
- data[0] = hi_byte(usba);
- data[1] = lo_byte(usba);
- build_hex_record(EXADDR,0,2,data);
- fputs(intelstring,fpo);
- }
-
- write_end_record(start)
- unsigned start;
- {
- build_hex_record(ENDREC,start,0,(char *)0);
- fputs(intelstring,fpo);
- }
-
- build_hex_record(type,loadaddress,datalen,data)
- unsigned char type;
- unsigned loadaddress;
- unsigned char datalen;
- unsigned char data[];
- {
- int checksum = 0;
- int i,j;
-
- intelstring[0] = ':';
- intelstring[1] = hex_lo_hi(datalen);
- intelstring[2] = hex_lo_lo(datalen);
- checksum += datalen;
-
- intelstring[3] = hex_hi_hi(loadaddress);
- intelstring[4] = hex_hi_lo(loadaddress);
- intelstring[5] = hex_lo_hi(loadaddress);
- intelstring[6] = hex_lo_lo(loadaddress);
- checksum += hi_byte(loadaddress);
- checksum += lo_byte(loadaddress);
-
- intelstring[7] = hex_lo_hi(type);
- intelstring[8] = hex_lo_lo(type);
- checksum += type;
-
- for(i=9,j=0; j<datalen; i+=2,j++){
- intelstring[i] = hex_lo_hi(data[j]);
- intelstring[i+1] = hex_lo_lo(data[j]);
- checksum += data[j];
- }
- checksum = -checksum;
- intelstring[i+0] = hex_lo_hi(checksum);
- intelstring[i+1] = hex_lo_lo(checksum);
- intelstring[i+2] = '\r';
- intelstring[i+3] = '\n';
- intelstring[i+4] = '\0';
- }
-
- static char hextable[] = "0123456789ABCDEF";
-
- hex_hi_hi(n)
- unsigned n;
- {
- return hextable[ (hi_byte(n)>>4)&0xf ];
- }
-
- hex_hi_lo(n)
- unsigned n;
- {
- return hextable[ hi_byte(n)&0xf ];
- }
-
- hex_lo_hi(n)
- unsigned n;
- {
- return hextable[ (lo_byte(n)>>4)&0xf ];
- }
-
- hex_lo_lo(n)
- unsigned n;
- {
- return hextable[ lo_byte(n)&0xf ];
- }
-
- hi_byte(n)
- unsigned n;
- {
- return ((n>>8) & 0xff);
- }
-
- lo_byte(n)
- unsigned n;
- {
- return (n & 0xff);
- }
-
- ABORT(char *reason, ...)
- {
- va_list argptr;
-
- va_start(argptr, reason);
- fputs("ERROR: ",stderr);
- vfprintf(stderr, reason, argptr);
- va_end(argptr);
-
- remove_temp_file();
- how_to_use_message(); /* which also exits program */
- }
-
- remove_temp_file()
- {
- if(tmpfname){
- fclose(fpt);
- remove(tmpfname);
- }
- }
-
- how_to_use_message()
- {
- fprintf(stderr,"\n");
- fprintf(stderr,"EXEHEX - This program converts Microsoft .EXE files\n");
- fprintf(stderr," into Intel HEX files suitable for burning\n");
- fprintf(stderr," into EPROM.\n\n");
- fprintf(stderr,"EXEHEX: [-D][-Sxxxx][-Oxxxx][-N][-H][-?] infile [outfile]\n");
- fprintf(stderr,"where -Sxxxx sets the start segment to xxxx.\n");
- fprintf(stderr," -Oxxxx sets the start offset to xxxx.\n");
- fprintf(stderr," -N prevents the sending of an end record\n");
- fprintf(stderr," (useful when making the jump vector)\n");
- fprintf(stderr," -D turns on some debugging messages (should be first).\n");
- fprintf(stderr," -? sends this message\n");
- fprintf(stderr," -H sends this message\n\n");
- fprintf(stderr,"the default options are -S0000 -O00000\n");
- fprintf(stderr,"(All numbers must be in hex, segments in paragraphs)\n");
- exit(1);
- }
-