_LOCATION IS EVERYTHING!_ by Mark Nelson [LISTING ONE] /******************************************************************** ** ---- LOCATE.C ----- ** Copyright (C) 1989 by Mark R. Nelson ** Program: LOCATE.C ** Author: Mark R. Nelson ** Summary: LOCATE reads in MS-DOS formate EXE files and writes ** out relocated code in Intel Hex format. The code ** segment is relocated to start at F000:0000. Data ** is relocated to start at 0040:0000. ********************************************************************/ #include #include #define TRUE 1 #define FALSE 0 struct exe_header { unsigned int signature; unsigned int image_length_mod_512; unsigned int file_size_in_pages; unsigned int num_of_relocation_table_items; unsigned int size_of_header_in_paragraphs; unsigned int min_num_of_paragraphs_required; unsigned int max_num_of_paragraphs_required; unsigned int disp_of_stack_in_paragraphs; unsigned int initial_sp; unsigned int word_checksum; unsigned int initial_ip; unsigned int disp_of_code_in_paragraphs; unsigned int disp_of_relocation_table; unsigned int overlay_number; } header; FILE *exe_file; FILE *hex_file; unsigned char *image; unsigned long int image_size; unsigned long int image_offset; unsigned long first_data_segment_in_exe_file; int verbose=TRUE; unsigned int output_base_code_segment=0xF000; unsigned int output_base_data_segment=0x0040; main(int argc,char *argv[]) { printf("Locate 1.0 Copyright (C) 1989 by Mark R. Nelson\n"); open_files(argc,argv); /* Open the input and output files */ read_header_data(); /* Read in the EXE file header */ read_input(); /* Read the code image into a buffer */ process_relocation_table(); /* Relocate all segment references */ dump_output(); /* Write the code image to the HEX file */ output_restart_code(); /* Write the restart code line */ output_intel_hex(0,0,1,NULL); /* Output an EOF record */ Š} /******************************************************************** ** ---- open_files ---- ** This routine opens an EXE file and a HEX file. If they are specified ** on the command line, those names are used. Otherwise the user is ** prompted for file names ********************************************************************/ open_files(int argc,char *argv[]) { char exe_file_name[81]; char hex_file_name[81]; if (argc>1) strcpy(exe_file_name,argv[1]); else { printf("EXE file name? "); scanf("%s",exe_file_name); } exe_file=fopen(exe_file_name,"rb"); if (exe_file==NULL) fatal_error("Had trouble opening the input file!"); if (argc > 2) strcpy(hex_file_name,argv[2]); else { printf("Hex file name? "); scanf("%s",hex_file_name); } hex_file=fopen(hex_file_name,"w"); if (hex_file==NULL) fatal_error("Had trouble opening the output file!"); } /******************************************************************** ** ---- read_header_data ---- ** This routine reads in the EXE header structure and computes both ** the image offset and size. The compuataions are all done using ** numbers found in the header. This program arbitrarily limits ** the code image size to 64K, but could easily be expanded to go ** to larger sizes. ********************************************************************/ read_header_data() { if (fread(&header,sizeof(struct exe_header),1,exe_file) != 1) fatal_error("Couldn't read header from file!"); if (verbose) print_header(); Š image_offset=header.size_of_header_in_paragraphs*16; image_size = (header.file_size_in_pages-1)*512; image_size -= image_offset; image_size += header.image_length_mod_512; if (image_size > 0xFFFFL) fatal_error("The EXE image is larger than I can handle!"); first_data_segment_in_exe_file=header.disp_of_stack_in_paragraphs; } /******************************************************************** ** ---- read_input -- ** This routine reads the code image into a buffer. Any trouble with ** the buffer or the file generates a fatal error. ********************************************************************/ read_input() { image=malloc(image_size); if (image==NULL) fatal_error("Couldn't allocate output image space!"); if (fseek(exe_file,image_offset,SEEK_SET) != 0) fatal_error("Couldn't seek to image in the input file!"); if (fread(image,1,(int)image_size,exe_file) != (int)image_size) fatal_error("Couldn't read in the image!"); } /******************************************************************** ** ---- process_relocation_table ---- ** This routine loops through all of the entries in the relocation ** table. Each entry points to a segment value in the code image. ** That segment value is checked to see if it points to code or ** data. If it points to data, it is relocated to start at the ** output_base_data_segment. Code segments are relocated to start ** at output_base_code_segment. ********************************************************************/ process_relocation_table() { int i; unsigned int reloc[2]; unsigned long int spot; unsigned int *guy; unsigned int old_value; unsigned int new_value; fseek(exe_file,(long)header.disp_of_relocation_table,0); for (i=0;i>8; segment_address[1]=output_base_code_segment & 0xff; output_intel_hex(2,0,2,segment_address); while (output_size > 0) { printf("%04X\r",output_address); record_size=(output_size > 34) ? 34 : output_size; output_intel_hex(record_size,output_address,0,output_pointer); output_pointer += record_size; output_size -= record_size; output_address += record_size; } printf("\n"); } /******************************************************************** ** ---- output_restart_code ---- ** This routine writes a JMP START instruction out at location ** at FFFF:0000. The address of START is contained in the EXE ** header block. ********************************************************************/ output_restart_code() { unsigned char jmp_code[5]; unsigned char segment_address[2]; Š segment_address[0]=0xff; segment_address[1]=0xff; output_intel_hex(2,0,2,segment_address); jmp_code[0]=0xea; /* JMP ????:???? */ jmp_code[1]=header.initial_ip & 0xff; jmp_code[2]=header.initial_ip >> 8; header.disp_of_code_in_paragraphs += output_base_code_segment; jmp_code[3]=header.disp_of_code_in_paragraphs & 0xff; jmp_code[4]=header.disp_of_code_in_paragraphs >> 8; header.disp_of_code_in_paragraphs -= output_base_code_segment; output_intel_hex(5,0,0,jmp_code); } /******************************************************************** ** ---- output_intel_hex ---- ** This routine writes a single record of Intel Hex. ********************************************************************/ output_intel_hex(int size,unsigned int address,int type,unsigned char buffer[]) { int checksum; int i; fprintf(hex_file,":%02X%04X%02X",size,address,type); checksum=size+address+(address>>8)+type; for (i=0;i