/* ROMLDR.C EXE locator program
written by: Charles B. Allison
last change: 11-3-93 */
#include <sys\stat.h>
#include <io.h>
#include <dos.h>
#include <stdio.h>
#include <stdlib.h>
#include <alloc.h>
#include <conio.h>
#include <ctype.h>
#include <fcntl.h>
#include <string.h>
#define BC 1
/* BC is Borland c, else assume Microsoft */
typedef struct {
unsigned sig; /* signature = 4d5ah */
unsigned 1st_sec_lng;
/*length of last sector in file modulo 512*/
unsigned file_size;
/* size of file in 512 byte pages includes hdr*/
unsigned num_reloc;
/* number of relocation items */
unsigned hdr_siz;
/* # of 16 byte paragraphs in header */
unsigned min_ld_para;
/* min # of paragraphs above load file */
unsigned max_ld_para;
/* max # of paragraphs requested by file */
unsigned disp_stack_seg;
/* rel displacement of stack segment */
unsigned sp;
/* contents of stack ptr on entry to prog */
unsigned chksm; /* check sum for file */
unsigned ip; /* beginning instruction ptr */
unsigned rel_cs_seg; /* relative cs segment */
unsigned off_reloc;
/* offset to 1st relocation item typ. 1e */
unsigned over_lay; /* overlay number */
unsigned rsrved; /* ?? reserved ?? */
/* relocation item format is seg:off location
relative to the beginning of the code section */
} EXE_HDR;
struct MP_TBL {
long addrs; /* segment beg. address */
long haddrs; /* segment high addrs*/
char class[12]; /* class of object */
} maptable[120];
void sort_table(void);
void gethdr(char *bf);
long hexcvt(char *num);
size_t read_block(char far *segbuf, size_t segsz);
long read_segm(int i);
size_t write_block(char far *segbuf,size_t segsz);
long write_segm(long segsize);
int fix_segm(int i);
int config(char *cfgfile);
void term_error(int numerr);
unsigned (*ch_ptr)[2];/* pointer to translation table
[0] = offset,[1] = segment*/
char mfile[14] = "rom.map"; /* dumy file names */
char bfile[14] = "rom.bin";
char efile[14] = "rom.exe";
/*columns for starting and ending addresses in MAP */
#define LCOL 1
#define HCOL 8
#ifdef BC
#define MAPCOL 41;
/*bc map file class column*/
#else
#define MAPCOL 45;
/*ms map file class column */
#endif
int class_loc = MAPCOL;
FILE *mapfile,*exefile,*binfile;
#define BUF_SIZE 60
char mapstring[BUF_SIZE];
long fsize; /*number of bytes in exe file */
int nsegs; /* number of segments in map */
unsigned romsadr = 0xf000,ramsadr=0x40;
char header[10000];
EXE_HDR *filhdr = (EXE_HDR *)header;
char far *seg_buffer;
int next_fix = 0;
char ram_class[15] = "FAR_DATA";
unsigned ramdata; /* beginning ram segment*/
/* ************ main ************* */
int main(int argc,char *argv[])
{
int r_class_flag=1,i;
long tmp,ssize;
if((seg_buffer = (char far *) farmalloc(0x10000L))
== NULL) term_error(0);
if(argc == 1) term_error(-1); /*any cfg file name? */
config(argv[1]);
i=0;
while (fgets(mapstring,BUF_SIZE,mapfile))
{
/* process map file from mapstring input */
/* maptable[1] - n contains the segments -
class STACK should be last one */
/* ends with i having n+1 segments */
if( (int)strlen(mapstring) > class_loc+1)
{ /* get rid of \n at end of string */
mapstring[(int)strlen(mapstring)-1]='\0';
if((tmp = hexcvt(&mapstring[LCOL])) >= 0)
{
maptable[i].addrs = tmp;
maptable[i].haddrs=hexcvt(&mapstring[HCOL]);
&mapstring[class_loc]);
strcpy(maptabte[i].class,
&mapstring[class_loc]);
if(r_class_flag)
if(strcmp(&mapstring[class_loc],ram_class)==0)
{ /*set it to first class occurance*/
ramdata = (maptable[i].addrs) >>4;
r_class_flag = 0;
}
printf("\n Segment %4.41x Class %s",
maptable[i].addrs/16,maptable[i].class);
i++;
}/* end - if hexcvt */
} /* end if strlen */
if(i>=119) break; /* error too many segments */
} /* end while */
if(feof(mapfile))
printf("\nend of file\n");
else
printf("\nerror reading map file\n");
nsegs = i-1; /* number of segments [1 to nsegs] */
gethdr(header); /* read in the exe header info */
/* size of object section of file */
fsize = (long) ((512L * (filhdr->file_size-1)) +
filhdr->lst_sec_lng - 16L * filhdr->hdr_siz);
printf("\nStartup Address %4.4x:%4.4x\n",romsadr+
filhdr->rel_cs_seg,filhdr->ip);
printf("Rom Size %lx\n",fsize);
/* process the exe file header - sort fix ups */
sort_table();
/* read in exe file by segment
do fixups from map table and
write it to output file */
for(i=0;i < nsegs;i++)
{
if((ssize = read_segm(i)) > 0L )
{ /* ignore 0 length segments */
fix_segm(i);
write_segm(ssize );
}
}
/* done - end the program */
farfree(seg_buffer);
fcloseall();
return 0;
}
/* ****************** */
/* qsort routine for far pointers */
int cmp_ptr(const void *a, const void *b)
{
long vala,valb;
vala=((long)((unsigned *)a)[0])+
(((unsigned *)a)[1]<<4);
valb=((long)((unsigned *)b)[0])+
(((unsigned *)b)[1]<<4);
vala -= valb;
if(vala < 0) return -1;
if(vala > 0) return 1;
return 0;
}
/*------------ sort_table ----------------*/
/* sort header table */
void sort_table(void)
{
qsort((void *)&header[filhdr->off_reloc],
filhdr->num_reloc,4,cmp_ptr);
}
/* -------------- read_block ---------------- */
size_t read_block(char far *segbuf,size_t segsz)
{
if(fread(segbuf,1,segsz,exefile) != segsz)
term_error(-7);
return segsz;
}
/* -------------- read_segm.------------------ */
long read_segm(int i)
{
long segsize;
segsize = maptable[i].haddrs - maptable[i].addrs;
if(!segsize) return 0;
segsize += maptable[i+1].addrs-(maptable[i].haddrs);
if(segsize <= 0x8000)
{ read_block(seg_buffer,(size_t)segsize);
} else {
read_block(seg_buffer,0x8000);
read_block((&seg_buffer[0x8000]),
(size_t)(segsize-0x8000));
}
return segsize;
}
/* ------------------ write_block -------------------- */
size_t write_block(char far *segbuf,size_t segsz)
{
if(fwrite(segbuf,1,segsz,binfile) != segsz)
term_error(-8);
return segsz;
}
/* ---------------- write_segm ------------------ */
long write_segm(long segsize)
{
if(!segsize) return 0;
if(segsize <= 0x8000)
{ write_block(seg_buffer,segsize);
} else {
write_block(seg_buffer,0x8000);
write_block((&seg_buffer[0x8000]),
(size_t)(segsize-0x8000));
}
return segsize;
}
/* ------------ fix_segm -------------- */
int fix_segm(int i)
{
unsigned tmp,cseg,fixup;
unsigned far * fixptr;
cseg = (unsigned)(maptable[i].addrs/16L);
while(next_fix < filhdr->num_reloc)
{
if(ch_ptr[next_fix][1] > cseg) break;
tmp = ch_ptr[next_fix][0]; /*offset into buffer*/
fixptr = (unsigned far *) &seg_buffer[tmp];
fixup = *fixptr;
/* modify segment fixup according to type */
if(fixup >= ramdata)
{/* modify for ram */
fixup -= ramdata;
fixup += ramsadr;
}
else
{/* handle as rom */
fixup += romsadr;
}
*fixptr = fixup;
next_fix++;
} /*end while */
return 0 ;
}
/* ------------ hexcvt -------------- */
/* do hex digits to unsigned long */
long hexcvt(char *num)
{
char *term;
long value;
value = strtoul(num,&term,16);
return value;
}
/* -------------- gethdr ---------------- */
void gethdr(char *buf )
{
int i,j=32; /*index counter */
if(fread(&buf[0],l,32,exefile) < 32)
term_error(-6);
/* have filhdr contents so get size of full header */
if(fread(&buf[j],16,filhdr->hdr_siz-2,exefile)
< filhdr->hdr_siz-2) term_error(-6);
(unsigned *)ch_ptr =
(unsigned *)(&buf[filhdr->off_reloc]);
/* get address of relocation table - ch_ptr [n][m]
m - 0 offset, 1 - seg, n relocation # */
}
/*---------------------- config.------------------------*/
/* get configuration data */
int config(char *cfgfile)
{
FILE *cfg;
char buf[80];
if((cfg = fopen(cfgfile,"r"))==NULL) term_error(-1);
if(fgets(buf,80,cfg) == NULL) term_error(-2);
if(sscanf(buf,"%s %s %s",&mfile,
&efile, &bfile) != 3) term_error(-2);
/* Now try to open input file 1 */
if((mapfile=fopen(mfile,"r"))==NULL) term_error(-3);
if((exefile=fopen(efile,"rb"))==NULL) term_error(-4);
if((binfile=fopen(bfile,"wb"))==NULL) term_error(-5);
if(fgets(buf,80,cfg) == NULL) term_error(-7);
if(sscanf(buf,"%4x %4x",&romsadr,
&ramsadr) != 2) term_error(-7);
if(fgets(buf,80,cfg) == NULL) term_error(-7);
if(sscanf(buf,"%s",&ram_class) != 1) term_error(-7);
return 0;
}
/* error handler */
char *errlist[10] = {
"Memory Allocation Error",
"No configuration file, USAGE:romldr cfgfile.cfg",
"Configuration file error - File names", //-2
"Map File open error", //-3
"Exe File open error", //-4
"Bin File open error", //-5
"Error reading header", //-6
"Error reading exe file", //-7
"Error writing bin file", //-8
" "
};
void term_error(int errnum)
{
errnum = abs(errnum);
if(errnum >= 9) exit(-1);
printf("%s\n",errlist[errnum]);
farfree(seg_buffer);
exit(errnum);
}
/* End of File */