Files
Digital-Research-Source-Code/CPM OPERATING SYSTEMS/CPM 68K/1.2 SOURCE/10/RELOC.C
Sepp J Morris 31738079c4 Upload
Digital Research
2020-11-06 18:50:37 +01:00

441 lines
18 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/****************************************************************************/
/* */
/* 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 */
} /****************************/
****************/
****************/
****************/