/****************************************************************************/ /* */ /* R e l o c P r o g r a m */ /* ------------------------- */ /* */ /* This program is used to relocate an Alcyon format load module into */ /* an absolute module using the minimum disk space possible. The */ /* relocation information, symbol table, and trailing zeros in the */ /* data segment are deleted. */ /* */ /* Invokation: */ /* */ /* A>reloc -bhhhhhh in.68k out.68k */ /* */ /* Where: */ /* hhhhhh Is the desired new base address (TPA + 100) in hex */ /* in.68k Is the input file */ /* out.68k Is the output file */ /* */ /****************************************************************************/ #include #include /****************************************************************************/ /* */ /* The following code defines the organization of a "long" variable on */ /* either the VAX (11) or 68000. This allows us to use "getw" on the */ /* separate parts of the long and to recombine them for 32-bit */ /* arithmetic operations. */ /* */ /****************************************************************************/ #include "machine.h" #ifdef UNIX #include #endif #ifdef VAX /****************************/ struct { /* low word first on VAX */ WORD loword; /* */ WORD hiword; /* */ }; /****************************/ #endif #ifdef PDP11 /****************************/ struct { /* low word first on PDP11 */ WORD loword; /* */ WORD hiword; /* */ }; /****************************/ #endif #ifdef MC68000 /****************************/ struct { /* */ WORD hiword; /* High word first on 68K */ WORD loword; /* */ }; /****************************/ #endif #ifdef UNIX /****************************/ #define fopenb fopen /* Not in UNIX library */ #endif /****************************/ /****************************************************************************/ /* */ /* Relocation bit definitions */ /* */ /* Note that this program is intended only for load module files. Any */ /* references to external symbols or relative references are illegal. */ /* */ /****************************************************************************/ /* */ #define DABS 0 /* Data absolute */ #define DRELOC 1 /* Data segment relative */ #define TRELOC 2 /* Text segment relative */ #define BRELOC 3 /* BSS segment relative */ #define EXTVAL 4 /* External variable */ #define LUPPER 5 /* Upper word of long */ #define EXTREL 6 /* External relative symbol */ #define INSABS 7 /* 1st word of instruction */ /****************************/ /****************************************************************************/ /* */ /* G l o b a l D a t a */ /* */ /****************************************************************************/ /* */ BYTE *ifname=0; /* -> Input filename */ BYTE *ofname=0; /* -> Output filename */ LONG base=0; /* New relocation base */ FILE *fopenb(); /* File open procedure */ LONG ftell(); /* File offset procedure */ #ifdef CPM /* Only defined with CP/M */ EXTERN BYTE _start; /* Start of program */ #endif /* */ /****************************/ #include "cout.h" /* Output header area */ /****************************/ /****************************************************************************/ /* */ /* M a i n P r o c e d u r e */ /* --------------------------- */ /* */ /* Here we get things started: */ /* */ /* 1). Get relocation base */ /* 2). Open input and output files */ /* 3). Determine data area (new) size */ /* */ /* Any errors here are fatal, and cause program termination. */ /* */ /****************************************************************************/ VOID main(argc,argv) /****************************/ DEFAULT argc; /* Int var from RTL startup */ BYTE **argv; /* -> Arg strings */ { /****************************/ REG LONG i,l; /* Temps */ REG FILE *ifp,*ofp,*rfp; /* File pointers */ /* */ if(argc != 4 && argc != 3) /* Gotta have right format */ usage(); /* Print out nasty message */ /****************************/ if(argc == 4) /* "-bxxxx" form */ { /****************************/ if(decode(argv[1], &base) == FAILURE) /* Convert to binary */ { /* */ printf("Illegal option: %s\n", /* Print offending option */ argv[1]); /* */ usage(); /* Print reminder messages */ } /****************************/ ifname = argv[2]; /* -> Input file name */ ofname = argv[3]; /* -> Output file name */ } else /* Default form */ { /* */ #ifdef CPM /* On CP/M, */ base = &_start; /* Use start of reloc itself*/ #else /****************************/ base = 0x500; /* 500H is default */ #endif /* */ ifname = argv[1]; /* -> Input filename */ ofname = argv[2]; /* -> Output filename */ } /****************************/ /* */ if((base & 1) != 0) /* In range? */ { /* no */ printf("Illegal base address=%lx\n", /* print */ base); /* message */ exit(-1); /* And quit */ } /****************************/ /* */ if((ifp=fopenb(ifname,"r")) == NULL) /* Try to open input */ { /* */ printf("Cannot open %s\n",ifname); /* Complain */ exit(-1); /* & quit */ } /****************************/ /* */ if((ofp=fopenb(ofname,"w")) == NULL) /* Try to create output */ { /* */ printf("Cannot create %s\n",ifname); /* Complain */ exit(-1); /* & quit */ } /****************************/ /****************************************************************************/ /* */ /* Now read the file header and compute the new data segment size ... */ /* */ /****************************************************************************/ /* */ i = fread(&couthd,1,(sizeof couthd), /* Do the read */ ifp); /* */ if(i != (sizeof couthd)) /* Did it work?? */ { /* */ printf("Read error on %s\n",ifname); /* No, complain */ exit(-1); /* and quit */ } /****************************/ /* */ if(couthd.ch_magic != MAGIC) /* Valid file? */ { /* */ printf("File format error: %s\n", /* Print nasty message */ ifname); /* */ exit(-1); /* Quit */ } /****************************/ /* */ l = couthd.ch_tsize + sizeof couthd; /* Seek address for data */ fseek(ifp,l,0); /* Seek to data start */ /* */ i = couthd.ch_dsize; /* Fetch data size */ l = ftell(ifp); /* l <= new data end addr */ /* */ while (i > 0) /* Until all data examined */ { /* */ if(getw(ifp) != 0) /* This data word = 0? */ l = ftell(ifp); /* No, record seek address */ i -= 2; /* Down count */ } /****************************/ /****************************************************************************/ /* */ /* Open the file a second time, and perform the proper seeks to align */ /* one copy of the open file to the beginning of the text segment, and */ /* the other copy to the beginning of the relocation information */ /* */ /****************************************************************************/ /* */ if((rfp=fopenb(ifname,"r")) == NULL) /* Try to open again */ { /* */ printf("Cannot re-open %s\n",ifname); /* Print nasty message */ exit(-1); /* and quit */ } /****************************/ fseek(ifp,(LONG)(sizeof couthd),0); /* Seek to text beginning */ fseek(rfp,(LONG)(sizeof couthd) + /* Seek to */ couthd.ch_tsize+couthd.ch_dsize + /* relocation */ couthd.ch_ssize, 0); /* info*/ /****************************/ reloc(ifp,rfp,ofp,l); /* Do relocation */ } /****************************/ /****************************************************************************/ /* */ /* U s a g e F u n c t i o n */ /* --------------------------- */ /* */ /* Routine "usage" is used to print out an error message when the */ /* program is invoked in an improper manner. */ /* */ /* Calling Sequence: */ /* */ /* usage(); */ /* */ /* No return is made, "exit()" is called to go back to the O/S. */ /* */ /****************************************************************************/ VOID usage() { printf("Usage: reloc [-bhhhhhh] input output\n"); printf(" where: hhhhhh is new base address\n"); printf(" (TPA+100 is default base address)\n"); printf(" input is relocatable file\n"); printf(" output is absolute file\n"); exit(-1); } /****************************************************************************/ /* */ /* D e c o d e F u n c t i o n */ /* ------------------------------ */ /* */ /* Routine "decode" is called to process the relocation base argument */ /* from the command line. */ /* */ /* Calling sequence: */ /* */ /* ret = decode(string,&address); */ /* */ /* Where: */ /* string -> argument string (usually argv[1]) */ /* &address -> long word to receive converted value */ /* */ /* ret = 0 if successful conversion */ /* = -1 if anything amiss */ /* */ /****************************************************************************/ WORD decode(string,addr) /* */ /* */ REG BYTE *string; /* -> Command argument */ LONG *addr; /* = return value */ { /****************************/ REG LONG a; /* Temp return value */ REG BYTE c; /* Temp character */ /* */ if(*string++ != '-' || *string++ != 'b')/* Check for valid switch */ return(FAILURE); /* quit if NFG */ /* */ a = 0; /* Zero out accumulator */ /* */ while(*string) /* Until no more chars */ { /* */ c = *string & 0177; /* Pick up next char */ if (c >= '0' && c <= '9') /* Digit */ a = (a << 4) + c - '0'; /* Un-ASCIIfy */ else if (c >= 'A' && c <= 'F') /* Hex */ a = (a << 4) + c - 'A'+ 10; /* Un-ASCIIfy */ else if (c >= 'a' && c <= 'f') /* Lower case hex */ a = (a << 4) + c - 'a'+ 10; /* Un-ASCII it */ else /* Bad character */ return(FAILURE); /* So long, sucker!! */ string++; /* Increment pointer */ } /* */ *addr = a; /* Store result */ return(SUCCESS); /* Return all ok */ } /****************************/ /****************************************************************************/ /* */ /* R e l o c F u n c t i o n */ /* --------------------------- */ /* */ /* Function "reloc" is called to perform the relocation operation and */ /* write the output file simultaneously. */ /* */ /* Calling Sequence: */ /* */ /* reloc(ifp,rfp,ofp,length); */ /* */ /* Where: */ /* */ /* ifp Is the input stream pointer (positioned at text) */ /* rfp Is a stream pointer positioned at relocation bits */ /* ofp Is a stream pointer for the output file */ /* length Is the total length of the output file */ /* */ /****************************************************************************/ VOID reloc(ifp,rfp,ofp,length) /* */ /* */ REG FILE *ifp; /* -> Text information */ REG FILE *rfp; /* -> Relocation info */ REG FILE *ofp; /* -> Output file */ LONG length; /* = # bytes in the file */ { /****************************/ struct hdr x; /* Duplicate header */ REG LONG bytes; /* File offset */ LONG j; /* Temp for long relocation */ REG WORD r; /* Relocation word */ REG WORD k; /* Temp data word */ WORD longf; /* Long relocation flag */ WORD z; /* Temp for error codes */ LONG bias; /* Relocation bias */ /* */ bias = base - couthd.ch_entry; /* Compute relocation bias */ /* */ /************************************************* */ /* */ /* Prepare and write the new file header in structure "x". */ /* */ /************************************************* */ /* */ x.ch_magic = MAGIC; /* Magic word */ x.ch_tsize = couthd.ch_tsize; /* Text size */ j = sizeof couthd + couthd.ch_tsize + /* Compute number of bytes */ couthd.ch_dsize - length; /* moved from data to bss */ x.ch_dsize = couthd.ch_dsize - j; /* New data size */ x.ch_bsize = couthd.ch_bsize + j; /* New bss size */ x.ch_ssize = 0; /* No symbols */ x.ch_stksize = 0; /* No stack */ x.ch_entry = base; /* New base address */ x.ch_rlbflg = -1; /* No relocation bits */ /****************************/ if(fwrite(&x,1,sizeof x,ofp) != /* Do the write */ sizeof x) /* */ { /* Here if failed */ printf("Write error on %s\n",ofname); /* print message */ exit(-1); /* Quit */ } /****************************/ /****************************************************************************/ /* */ /* Here begins the actual file relocation procedure. Read a word */ /* from the relocation bits and from the file together. If long, */ /* read another word from each. Perform indicated relocation. */ /* */ /****************************************************************************/ /* */ bytes = 0; /* No bytes written yet ... */ length -= sizeof(couthd); /* Just program, please... */ while (bytes < length) /* until we are done */ { /****************************/ k = getw(ifp); /* get next text/data word */ r = getw(rfp); /* get next relocation word */ /****************************/ if ((r & ~7) != 0) /* Check for validity */ badrel(r,bytes); /* Not valid, quit */ /* */ if(r == LUPPER) /* Doing a long? */ { /* */ j.hiword = k; /* Yes, get another word */ j.loword = getw(ifp); /* From both */ r = getw(rfp); /* streams */ longf = 2; /* Set flag */ } /****************************/ else /* Not a long */ { /* */ j.loword = k; /* Put in low order word */ j.hiword = 0; /* Make top part 0 */ longf = 0; /* Clear flag */ } /****************************/ switch (r) /* Now do indicated reloc */ { /* */ case TRELOC: /* If relocatable, */ case DRELOC: /* relocate */ case BRELOC: /* */ j += bias; /* Add in bias */ case DABS: /* If not relocatable, */ case INSABS: /* don't */ break; /****************************/ default: /* Any others illegal */ badrel(r,bytes); /* Print message */ } /****************************/ if(longf == 0 && j.hiword !=0) /* 16-bit overflow? */ { /* */ printf("16-bit overflow at %ld\n", /* Print out message */ bytes); /* with offset */ exit(-1); /* */ } /****************************/ if(longf != 0) /* Long? */ putw(j.hiword,ofp); /* yes, output high */ #ifndef UNIX /* A bug in UNIX RTL!! */ if((z=putw(j.loword,ofp)) != j.loword) /* Check for write error */ { /* */ printf("Write error on %s ",ofname); /* Had one, */ printf("Offset = %lx data= %x err =%x\n", /* */ bytes,j.loword,z); /* Print out message */ exit(-1); /* & quit */ } /****************************/ #else /* Just output and pray... */ putw(j.loword,ofp); /* Output low word */ #endif /****************************/ bytes += 2 + longf; /* Increment byte count */ /* */ } /* End while loop */ } /* End reloc procedure */ /****************************/ VOID badrel(r,offset) /* Print bad reloc message */ /* */ WORD r; /* Relocation bits */ LONG offset; /* File offset */ { /****************************/ printf("Illegal reloc = %x at %lx\n", /* Print error message */ r,offset); /* */ exit(-1); /* quit */ } /****************************/ ****************/ ****************/ ****************/