mirror of
https://github.com/SEPPDROID/Digital-Research-Source-Code.git
synced 2025-10-23 00:14:25 +00:00
436 lines
17 KiB
C
436 lines
17 KiB
C
/****************************************************************************/
|
||
/* */
|
||
/* 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 <stdio.h>
|
||
#include <ctype.h>
|
||
/****************************************************************************/
|
||
/* */
|
||
/* 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 <portab.h>
|
||
#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 */
|
||
} /****************************/
|
||
|
||
|