Files
Digital-Research-Source-Code/CPM OPERATING SYSTEMS/CPM 68K/1.0X SOURCES/v102/link68/link68.c
Sepp J Morris 31738079c4 Upload
Digital Research
2020-11-06 18:50:37 +01:00

2263 lines
55 KiB
C

#include <stdio.h>
#include "cout.h"
#include <ctype.h>
#include "link68.h"
struct symtab *symptr =0;
/* parameters that define the main table*/
#define SZMT 300 /*initial size of the main table*/
/*must be large enough to initialize*/
#define ICRSZMT 100 /*add to main table when run out*/
int cszmt =0; /*current size of main table*/
char *bmte =0; /*beginning of main table*/
char *emte =0; /*end of main table*/
/*initial reference table for externals*/
# define SZIRT 64
char *eirt[SZIRT] ={0};
char *saveirt[SZIRT] ={0};
/*initial reference table for globals*/
char *girt[SZIRT] ={0};
char *savgirt[SZIRT] ={0};
char **pirt =0;
char *lmte =0; /*last entry in main table*/
char *savlmte =0;
#define AREGLO 8
#define AREGHI 15
/* relocation bit definitions:*/
#define RBMASK 07 /*tells type of relocation*/
#define INSABS 7 /*first word of instr -- absolute*/
#define DABS 0 /*data word absolute*/
#define TRELOC 2 /* TEXT relocatable*/
#define DRELOC 1 /* DATA relocatable*/
#define BRELOC 3 /* BSS relocatable*/
#define EXTVAR 4 /* ref to external variable*/
#define LUPPER 5 /* upper word of long*/
#define EXTREL 6 /* relative mode on external variable*/
FILE *ibuf =NULL;
FILE *tbuf =NULL;
FILE *obuf =NULL;
FILE *rbuf =NULL;
FILE *rtbuf =NULL;
FILE *rdbuf =NULL;
long textbase =0;
long database =0;
long bssbase =0;
long textsize =0;
long datasize =0;
long bsssize =0;
long stacksize =0;
long textstart =0;
long datastart =0;
long bssstart =0;
char *ifilname =0; /*points to name of current input file */
char *outfname =0; /*points to name of current output file */
#define NFILE 256 /*max # files we can process*/
char *fsymp[NFILE] ={0}; /*points to first symbol for each .o file*/
char **firstsym =0; /*points to entry in fsymp*/
int extmatch =0; /*matched an external in a library entry*/
int noload =0; /*dont load this lib file flag*/
#define NLIB 16 /*max # libraries to process*/
int lbfictr[NLIB] ={0}; /*counts files loaded from one library*/
int *libfctr =0; /*points to lbfictr*/
long lbfioff[NFILE] ={0}; /*each file offset in library*/
long *libptr =0; /*points to lbfioff*/
#define LIB1MAGIC 0177555
#define LIB2MAGIC 0xffffff65
#define LIB1HDSIZE 16
#define LIB2HDSIZE 26
struct libhdr {
char l1fname[8];
long l1modti;
char l1userid;
char l1fimode;
short l1fsize;
};
struct lib2hdr {
char l2fname[14];
long l2modti;
char l2userid;
char l2gid;
short l2fimode;
long l2fsize;
short l2junk;
} *lib2hd =0;
#define ARMAG "!<arch>\n"
#define SARMAG 8
#define ARFMAG "`\n"
struct ar_hdr {
char ar_name[16];
char ar_date[12];
char ar_uid[6];
char ar_gid[6];
char ar_mode[8];
char ar_size[10];
char ar_fmag[2];
} lib3_hdr ={0};
#define LIB3MAGIC 0x3c21
#define LIB3HDSIZE (sizeof lib3_hdr)
int libhdsize =0;
long libhd[20] ={0}; /*length is max lib head size*/
int umesflg =0;
char dafnc =0;
int pass2 =0;
long stlen =0;
int Xflag =0;
int Dflag =0;
int Bflag =0;
int Zflag =0;
int sflag =0; /* if set, keep symbol table*/
struct symtab *etextptr =0;
struct symtab *edataptr =0;
struct symtab *erootptr =0;
struct symtab *endptr =0;
char *lastdup =0;
char rtfnc =0;
char rdfnc =0;
int saverbits =0;
struct ovtab ovtab1 = {0};
/* 68000 linking loader -- adapted from */
/* Bill Allen's to handle overlays */
/* This loader is a two pass operation. The first pass*/
/* reads all the relocatable object files including any libraries.*/
/* It builds the full symbol table, resolves all external symbol*/
/* references if possible, and calculates the total size of the*/
/* text, data, and bss segements. Pass 2 then does the binding,*/
/* the relocation, and produces the final output file.*/
#define MAGIC1 MAGIC+1 /*magic # for data & bss base specified*/
#ifdef VMS
char libname[] = "lib:lib6.a"; /*default library name*/
#define LIBCHAR libname[7] /* Character to be modified */
#endif
#ifdef CPM
char libname[] = "lib6.a";
#define LIBCHAR libname[3] /* Character to be modified */
#endif
#ifdef UNIX
char libname[] = "/lib/lib6.a"; /* Default library name */
#define LIBCHAR libname[8] /* Character to be modified */
#endif
#ifdef UNIX /************************/
char *tfbase = "loXXXXXX"; /* Temp base name */
char tdisk[DRIVELEN] = "/tmp/"; /* Temp disk name */
#else /* CP/M and VMS */
char *tfbase = "loXXXXXA"; /* Temp base name */
char tdisk[DRIVELEN] = ""; /* Temp disk name */
#endif /************************/
char *tfchar = 0; /* -> changeable character */
char tfilname[80] = {0}; /*first temp file name*/
#define TFCHAR *tfchar /* Name to simplify assignments */
char etexstr[] = "_etext\0\0";
char edatstr[] = "_edata\0\0";
char erootstr[]= "_eroot\0\0";
char eendstr[] = "_end\0\0\0\0";
char ovhstr[] = "_ovhdlr\0";
int endit();
char *lemt();
char *nextsy();
char *sbrk();
int readshort();
int ignflg =0;
int debug =0;
int exstat =0;
int ovflag =0;
#ifdef VAX
struct { char lobyte; char hibyte; };
#endif
#ifdef PDP11
struct { char lobyte; char hibyte; };
#endif
#ifdef MC68000
struct { char hibyte; char lobyte; };
#endif
long fseek();
long rtxsize = 0; /* size of root's text */
long rdtsize = 0; /* size of root's data */
long hihiaddr = 0; /* first even word above whole program */
long ovtable = 0; /* address of overlay table start */
struct ovcalblk ovcall = {0};
char cmdline[LINELEN] = "";
int mapflg = FALSE;
int absflg = FALSE;
int libflg = FALSE; /* set if an input file to be searched */
int symflg = FALSE; /* set if symbol table to be saved */
int udfflg = FALSE; /* set if undefined symbols allowed */
int chnflg = FALSE; /* set if linking chained program */
int dmpflg = FALSE; /* set for dumping symbol table */
struct ovtrnode *ovtree[MAXOVLS+1] = {NULL}; /* command tree */
int ovpath[MAXOVDEP+1] = {0}; /* current path in ovtree walk */
int ovpathtp = -1; /* current end of path */
extern usage();
VOID dopass1();
VOID ovexts();
VOID dopass2();
/************************************************************************/
/* */
/* main() -- driver routine for entire linker. */
/* */
/* */
/* */
/* */
/************************************************************************/
VOID
main(argc,argv)
int argc;
char **argv;
{
register int i;
struct symtab *pt;
banner(); /* print the sign-on message */
if (argc == 1) /* no command line */
{
usage();
exit(-1);
}
for (i = 1; i < argc; i++) /* assemble command line */
{
if ((strlen(cmdline) + strlen(argv[i])) > (LINELEN - 2))
errorx(CMDLONG, ""); /* command line too long */
else
{
strcat(cmdline, argv[i]); /* put in the command */
strcat(cmdline, " "); /* leave blank between */
}
}
printf("%s\n", cmdline); /* echo command line */
preproc(); /* build command tree */
ovflag = (numovls > 0); /* are there overlays? */
buildf(); /* construct temp. names */
/* Open and then close a file in ibuf to allocate its buffer */
/* area under the symbol table. Otherwise the buffer ends up */
/* on top of any additions to the symbol table. */
openfile((ovtree[ROOT]->ovflist)->fnfname); /* first input file */
fclose(ibuf); /* will open again later */
intsytab(); /* init. symbol table */
firstsym = fsymp;
libfctr = lbfictr;
libptr = lbfioff;
saverbits = !absflg; /* keep relocation bits */
if (ovflag && !chnflg) /* put _ovhdlr in symbol*/
{ /* table */
pack(ovhstr,lmte);
lmte->flags = SYXR; /* make it external */
lmte->ovlnum= ROOT; /* belongs to root */
addsym();
}
walktree(ROOT, dopass1, POSTORDER); /* pass1 on each node */
if (ovflag && !chnflg)
{ /* add room for overlay table in root's data segment*/
ovtable = ovtree[ROOT]->ovbsbase; /* changes in ovexts */
ovtree[ROOT]->ovbsbase += numovls*sizeof(ovtab1);
ovtree[ROOT]->ovcap += numovls*sizeof(ovtab1);
rdtsize += numovls*sizeof(ovtab1);
}
fixcoms(); /* allocate common and global static space */
hihiaddr = ovtree[ROOT]->ovcap; /* current top of bss */
if (ovflag) /* resolve calls to overlayed routines */
walktree(ROOT,ovexts,PREORDER);
resolve(); /* resolve externals, assign addresses */
if (exstat) /* quit if there are errors */
endit(exstat);
pass2++; /* now in pass two */
firstsym = fsymp;
libfctr = lbfictr;
libptr = lbfioff;
Xflag = TRUE; /* print all locals entered by pass 1 */
if (ovflag && !chnflg) /* set up template overlay call block */
{
pack(ovhstr,lmte); /* get overlay handler address */
pt = lemt(girt);
ovcall.ovhandlr = pt->vl1;
ovcall.jsrovh = JSRL;
ovcall.jmprout = JMPL;
}
walktree(ROOT, dopass2, POSTORDER); /* pass2 on each node */
}
/************************************************************************/
/* */
/* dopass1(*ovnode) -- do pass one processing on a given node */
/* */
/* */
/************************************************************************/
VOID
dopass1(opt)
REG struct ovtrnode *opt; /* pointer to node in command tree */
{
REG struct filenode *fpt, *tfpt;
opt->ovfsym = lmte; /* start of this modules symbols */
if (ovpath[ovpathtp] == ROOT)
textbase = textstart;
else
textbase = 0;
opt->ovtxbase = textbase;
database = 0;
bssbase = 0;
fpt = opt->ovflist; /* get first input file */
while (fpt != NULL) /* process each file */
{
if (fpt->fnflags & FNINCL) /* next name is a symbol*/
{
tfpt = fpt->fnnext; /* get the include symbols */
while ((tfpt != NULL) && (tfpt->fnflags & FNSYM))
{ /* put in symbol table */
pack(tfpt->fnfname, lmte); /* copy name */
lmte->flags = SYXR; /* external */
lmte->ovlnum = ovpath[ovpathtp];/* mark which module*/
addsym(); /* regular symbol */
tfpt = tfpt->fnnext; /* get the next node */
}
fpt->fnnext = tfpt; /* skip to real file node */
}
libflg = !(fpt->fnflags & FNALL); /* search if lib? */
Xflag = (fpt->fnflags & FNLOCS); /* ommit locals? */
p1load(fpt->fnfname); /* process the file */
fpt = fpt->fnnext; /* get the next file */
}
opt->ovdtbase = (Dflag)? datastart : (textbase+1)&~1;
opt->ovbsbase = (Bflag)? bssstart : (opt->ovdtbase+database+1)&~1;
opt->ovcap = (opt->ovbsbase+bssbase+1)&~1;
if (ovpath[ovpathtp] == ROOT)
{
rtxsize = textbase - textstart;
rdtsize = database;
}
}
/************************************************************************/
/* */
/* ovexts(ovtreenode) -- resolve references to overlayed routines */
/* */
/* This routine looks through all of the symbols for a module, */
/* and checks each external reference. If the matching global */
/* is in a child overlay, an ovcall block is built containing the */
/* appropriate information. The external is resolved to that */
/* ovcall block, which is placed at the end of the current */
/* module's text segment. */
/* */
/* All overlay references are assumed to be jumps or subroutine */
/* calls. References to non-text-based addresses in overlays */
/* result in an error message. */
/* */
/* For chained programs, the routine only adjusts the bases. */
/* */
/************************************************************************/
VOID
ovexts(ovpt)
REG struct ovtrnode *ovpt; /* points to node in command tree */
{
REG struct symtab *cursym; /* current symbol being examined*/
int ovrefs; /* count overlay references */
REG long newbase; /* use for adjusting seg. bases */
REG short onum; /* this module's number */
onum = ovpath[ovpathtp];
if (onum != ROOT) /* adjust textbase to above parent*/
{
newbase = ovtree[ovpt->ovparent]->ovcap;
ovpt->ovtxbase = newbase;
ovpt->ovdtbase += newbase;
ovpt->ovbsbase += newbase;
ovpt->ovcap += newbase;
}
ovrefs = 0;
cursym = ovpt->ovfsym; /* first sy tab entry for module*/
if (!chnflg) /* no ovr tabs in chined program*/
while ((cursym->ovlnum == onum) && (cursym != lmte))
{
if (cursym->flags & SYXR)
ovrefs += chkovext(cursym); /* check ext ref */
cursym++; /* get the next symbol */
}
newbase = ovrefs * sizeof(ovcall); /* size of extra code */
ovpt->ovbsbase += newbase; /* add in space for ovcalls */
ovpt->ovcap += newbase; /* ovdtbase adjusted in chkovext*/
if (onum == ROOT)
{
rtxsize += newbase;
ovtable += newbase; /* final relocatable address */
}
hihiaddr = max(hihiaddr,ovpt->ovcap); /* might be new top */
}
/************************************************************************/
/* */
/* dopass2(*ovnode) -- do pass two processing on a given node */
/* */
/* Drives the pass 2 routines. If it is processing the root, */
/* the symbol table is also written to the output file if */
/* specified. This routine depends on the root being the first */
/* module processed in order to do the symbol table right. */
/* */
/************************************************************************/
VOID
dopass2(opt)
REG struct ovtrnode *opt; /* pointer to node in command tree */
{
REG struct filenode *fpt;
/* set up sizes and bases for building load file */
if (opt == ovtree[ROOT])
{
textsize = rtxsize;
datasize = rdtsize;
bsssize = hihiaddr - opt->ovbsbase; /* for overlay area */
}
else
{
textsize = opt->ovdtbase - opt->ovtxbase;
datasize = opt->ovbsbase - opt->ovdtbase;
bsssize = opt->ovcap - opt->ovbsbase;
}
textstart = opt->ovtxbase;
textbase = opt->ovtxbase;
database = opt->ovdtbase;
bssbase = opt->ovbsbase;
sflag =((opt == ovtree[ROOT]) && symflg);/* only root module */
makeofile(opt->ovfname); /* set up output file for node */
fpt = opt->ovflist; /* get first input file */
while (fpt != NULL) /* go through whole list */
{
if (!(fpt->fnflags & FNSYM)) /* file, not symbol */
p2load(fpt->fnfname); /* load the file */
fpt = fpt->fnnext; /* get the next file */
}
/* has symbol table */
finalwr(); /* finish the output file */
}
/************************************************************************/
/* */
/* walktree(node, visit, order) -- ordered walk of overlay tree. */
/* */
/* Processes each node in the overlay tree in a pre-order or */
/* post-order walk, starting at the specified node. */
/* At each node, the routine pointed to by visit is called */
/* to work at that node. */
/* */
/* The routine pointed to by visit must take a single parameter, */
/* which is a pointer to a filenode. The routine should not */
/* return a value. */
/* */
/************************************************************************/
VOID
walktree(index, visit, order)
register int index; /* index into overlay tree */
int (*visit)(); /* routine to process node */
int order; /* specifies which order walk */
{
register int kidpt;
ovpath[++ovpathtp] = index; /* put node in path list*/
if (order == PREORDER)
(*visit)(ovtree[index]); /* process the node */
kidpt = ovtree[index]->ovfstkid; /* get first descendant */
while (kidpt != NULL) /* visit each descendant */
{
walktree(kidpt, visit, order); /* depth-first call */
kidpt = ovtree[kidpt]->ovnxtsib; /* next descendant */
}
if (order != PREORDER)
(*visit)(ovtree[index]); /* process the node */
ovpathtp--; /* take node out of list */
}
buildf()
{
tfilname[0]=0; /* Null out present filename */
strcat (tfilname,tdisk); /* Put disk name in first */
strcat (tfilname,tfbase); /* Put in filename now */
/******************************/
#ifdef UNIX /* On UNIX, */
mktemp (tfilname); /* Make a temp filename */
#endif /******************************/
tfchar = &tfilname[strlen(tfilname)-1]; /* Set pointer */
}
/* pass 1 load routine:*/
/* read the file or library and build the symbol table*/
/* symbols are organized on the initial reference tables*/
/* with externals on eirt and globals on girt*/
int ii=0;
p1load(ap)
char *ap;
{
ii = 0;
openfile(ap); /*get the file opened using ibuf*/
if(couthd.ch_magic == LIB1MAGIC) { /*library*/
libhdsize = LIB1HDSIZE; /*old ar header size*/
searchlib();
}
else if(couthd.ch_magic == LIB2MAGIC) { /*library*/
libhdsize = sizeof *lib2hd; /*new ar header size*/
searchlib();
}
else if(couthd.ch_magic == LIB3MAGIC) {
getw(ibuf);
getw(ibuf);
getw(ibuf);
libhdsize = LIB3HDSIZE;
searchlib();
}
else {
libflg = FALSE; /* set to TRUE by dopass1 */
do1load(0); /* load a regular file */
firstsym++;
addsizes();
}
fclose(ibuf);
}
/* search a library for files to include. include an entry only*/
/* if it has a global symbol which matches an external.*/
long lbctr =0;
long libfilsize =0;
searchlib()
{
*libfctr = 0; /*no files from this library yet*/
lbctr = sizeof(short); /*current library position - skip magic*/
while(rdlibhdr()) { /*read library file header*/
savsymtab(); /*save current state of symbol table*/
extmatch = 0;
noload = 0;
ifilname = libhd;
readhdr(); /*read the file header*/
do1load(1); /*load this lib file */
if(extmatch > noload) { /*found a match*/
if(noload)
prdup(lastdup); /*print dup defn*/
addsizes(); /*add this file's sizes*/
firstsym++;
*libfctr += 1; /*count files loaded from this library*/
*libptr++ = lbctr; /*remember offset in library*/
}
else { /*dont need this file*/
restsymtab(); /*restore symbol table*/
}
if(libfilsize&1) { /*one byte of padding*/
getc(ibuf);
lbctr++;
}
lbctr += libfilsize + libhdsize;
lbseek(lbctr,ibuf); /*goto begin of next lib entry*/
}
libfctr++; /*point to next library file counter*/
}
/*read a library file header*/
rdlibhdr()
{
register char *p;
register int i;
register char *pc;
p = libhd;
for( i = 0; i < sizeof *lib2hd; i++ )
*p++ = getc(ibuf);
libhd->l2modti = 0;
libfilsize = libhd->l2fsize;
if( libhd->l2fname[0] == '\0' )
return(0);
return(1);
}
/* open the file pointed to by ap*/
/* check for the -lx type library spec*/
openfile(ap)
char *ap;
{
register char *p;
register short i;
char tempname[FNAMELEN];
p = ap;
if(*p=='-' && *++p=='l') {
if(*++p)
LIBCHAR = *p;
else
LIBCHAR = '6'; /*default library name*/
p = libname;
}
else
p = ap;
if((ibuf = fopenb(p,"r")) == 0)
{
strncpy(tempname,p,FNAMELEN-DEFLEN);
strcat(tempname,DEFTYPE);
if((ibuf = fopenb(tempname,"r")) == 0)
errorx(BADINFIL, p);
strcpy(p,tempname);
}
ifilname = p; /*point to current file name for error msgs*/
if( readshort(ibuf, &couthd.ch_magic) )
errorx(READERR, ifilname);
if( couthd.ch_magic != LIB2MAGIC ) {
fseek(ibuf,0L,0);
readhdr(); /*read file header*/
}
if(pass2) { /*need file descrptr for reloc bits*/
rbuf = fopenb(p, "r");
}
}
/* read the header of the input file*/
int readshort(fp,s)
FILE *fp;
short *s;
{
short ts;
if( fread(&ts,sizeof(short),1,fp) != 1 )
return(1);
*s = ts;
return(0);
}
readhdr()
{
register int i;
register short *p;
p = &couthd;
for( i = 0; i < (sizeof couthd)/2; i++ )
*p++ = getw(ibuf);
if(couthd.ch_magic != MAGIC)
errorx( FORMATERR, ifilname);
if(couthd.ch_rlbflg)
errorx(NORELOC, ifilname);
}
/* load one *.o format file using ibuf*/
/* put the symbols into the symbol table relocating each one*/
/* and finally add this files sizes into running totals*/
/* libflg is set if we are in a library*/
do1load(lflg)
int lflg; /* set if file is in a library */
{
register long i;
register long l;
*firstsym = lmte; /*remember where this symbol table starts*/
l = couthd.ch_tsize + couthd.ch_dsize + sizeof couthd;
if( lflg )
l += lbctr + sizeof *lib2hd;
lbseek(l,ibuf);
i = couthd.ch_ssize; /*size of symbol table*/
while(i > 0) {
getsym(); /*read one symbol entry*/
relocsym(); /*fix its address*/
addsym(); /*add to symbol table*/
i -= OSTSIZE;
}
}
/************************************************************************/
/* */
/* getsym() */
/* */
/* Get one symbol entry from the input file and put it into the symbol */
/* table entry pointed to by lmte. */
/* */
/* If the program is being linked for chaining (CBASIC) and the symbol */
/* name is __cbmain, the name is changed to reflect the specific */
/* overlay, since each overlay and the root has its own definition for */
/* __cbmain. */
/* */
/************************************************************************/
getsym()
{
register int i;
register short *stpt;
stpt = lmte;
for(i=0; i<SYNAMLEN/(sizeof *stpt); i++)
*stpt++ = getw(ibuf);
lmte->ovlnum = ovpath[ovpathtp]; /* mark which module it's in */
if (chnflg && (strncmp(lmte,CBMAIN,8)==0))/* main CBASIC entry point?*/
sprintf(lmte, "main.%03d", lmte->ovlnum);/* make name unique*/
*stpt++ = getw(ibuf); /* flags */
/* *stpt++=0; */ /* skip upper half of internal flags on VAX */
stpt->hiword = getw(ibuf); /* sym value high word */
stpt->loword = getw(ibuf); /* sym vaue low word */
}
/* relocate the symbol value pointed to by lmte according to*/
/* symbol type and corresponding relocation base*/
relocsym()
{
register long l;
l = 0;
if(lmte->flags&SYXR) /*external*/
return;
if(lmte->flags&SYTX)
l = textbase;
else if(lmte->flags&SYDA)
l = database;
else if(lmte->flags&SYBS)
l = bssbase;
else {
if(lmte->flags&SYEQ) /*equated*/
return; /* abs*/
errst1 = lmte->name;
errorx(BADSYMFLG, ifilname);
}
lmte->vl1 += l;
}
/* add a symbol to the symbol table*/
/* if symbol is an external, put it on eirt even if it does*/
/* already exist*/
/* if symbol is a global, put it on girt and error if it exists*/
/* in any case, add it to the end of the symbol table*/
/* if libflg is set, we are searching a library. In this case, when*/
/* a global is encountered, search the external symbols and set*/
/* extmatch if a match is found. When loading a library without searching */
/* it, return as if the symbol matches, to make sure the library file loads. */
addsym()
{
register char *p;
/* if(debug) {*/
/* printf("addsym: file=%s symbol=%s flags=%x\n",ifilname,lmte,(int)lmte->flags);*/
/* }*/
if(lmte->flags&SYXR) { /*external*/
p = lemt(eirt);
mmte();
}
else if(lmte->flags&SYGL) { /*global*/
if(libflg) { /*global in a library*/
p = lemt(eirt); /*look up in externals*/
if(p != lmte) { /*found a match*/
extmatch++;
}
}
else
extmatch = 1; /* trick searchlib to load lib file */
p = lemt(girt);
addtry2: if(p == lmte)
mmte();
else {
dupdef: if (chnflg && (p->ovlnum != ROOT) &&
(lmte->ovlnum != ROOT) &&
(p->ovlnum != lmte->ovlnum))
{
p = nextsy(p->tlnk); /* try again */
goto addtry2;
}
if(libflg) {
noload++;
lastdup = p;
}
else if( (p->ovlnum != lmte->ovlnum) ||
(p->flags != lmte->flags) ||
(p->vl1 != lmte->vl1))
prdup(p); /*dup defn msg*/
}
}
else { /*normal symbol*/
if(lmte->name[0] == 'L') /*compiler label*/
return;
if(Xflag==0) /*dont save local symbols*/
return;
addmte();
}
}
prdup(p)
char *p;
{
errst1 = p;
errorx(DUPDEF, ifilname); /* returns */
exstat++;
}
/************************************************************************/
/* */
/* intsytab() -- initialize the symbol table and the heads of the */
/* hash lists */
/* */
/* Uses sbrk to guarantee continuity of symbol table. */
/* */
/************************************************************************/
intsytab()
{
register char **p1, **p2;
register i;
bmte = (sbrk((sizeof *symptr)*SZMT+2));
emte = bmte + (sizeof *symptr)*SZMT; /*end of main table*/
if((long)bmte&1)
bmte++;
lmte=bmte; /*beginning main table*/
cszmt = SZMT; /*current size of main table*/
p1 = eirt;
p2 = girt;
for(i=0; i<32; i++) {
*p1++ = p1;
*p1++ = 0;
*p2++ = p2;
*p2++ = 0;
}
}
/* method for looking up entries in the main table*/
/**/
/* Note: The entry to be looked up must be placed at the end*/
/* of the main table. The global cell 'lmte'(last main*/
/* entry) points to the next available entry in the main*/
/* table. The address of an initial reference table must*/
/* also be provided.*/
/* 1) Compute the hash code for the symbol and add it to the base address*/
/* of the initial reference table given as input. Thus, two words are*/
/* accessed which define the chain on which the symbol must be if it is*/
/* in the table at all.*/
/* 2) Alter the table link of the last symbol in the chain so that it */
/* points to the symbol being looked up. Note that the symbol to be */
/* looked up is always placed at the end of the main table before */
/* calling the lookup routine. This essentially adds one more element*/
/* to the end of the chain, namely the symbol to be looked up.*/
/* 3) Now start at the first symbol in the chain and follow the chain*/
/* looking for a symbol equal to the smbol being looked up. It is*/
/* quaranteed that such a symbol will be found because it is always */
/* the last symbol on the chain.*/
/* 4) When the symbol is found, check to see if it is the last symbol*/
/* on the chain. If not, the symbol being looked for is in the table*/
/* and has been found. If it is the last symbol, the symbol being */
/* looked up is not in the table.*/
/* 5) In the case the looked up symbol is not found, it is usually added*/
/* to the end of the table. This is done simply b changing the */
/* initial reference table entry which points to the previous*/
/* last symbol on the chain so that is now points to the symbol at the*/
/* end of the main table. In case the symbol just looked up is not to*/
/* be added to the main table then no action is needed . This means*/
/* that the table link of the last symbol on a chain may point any-*/
/* where.*/
/* look up entry in the main table*/
/* call with:*/
/* address of initial reference table*/
/* entry to be looked up at the end of the main table*/
/* returns:*/
/* a pointer to the entry. if this pointer is equal to*/
/* lmte then the symbol was not previously in the table.*/
char *lemt(airt)
char **airt;
{
register char *mtpt;
pirt = airt + hash(); /*pointer to entry in irt*/
mtpt = pirt->irfe; /*pointer to first entry in chain*/
if(mtpt==0) /*empty chain*/
mtpt = lmte; /*start at end of main table*/
else
(pirt->irle)->tlnk = lmte;/*last entry in chain is new symbol*/
return(nextsy(mtpt)); /*return next match on chain*/
}
char *nextsy(amtpt)
char *amtpt;
{
register char *mtpt;
register int *p1, *p2;
register int i;
mtpt = amtpt;
/*loop to locate entry in main table*/
lemtl:
p1 = &mtpt->name[0];
p2 = &lmte->name[0];
for(i=0; i<SYNAMLEN/(sizeof i); i++) {
if(*p1++ != *p2++) {
mtpt = mtpt->tlnk; /*go to next entry in chain*/
goto lemtl;
}
}
return(mtpt);
}
/*make an entry in the main table*/
/* assumes:*/
/* entry to be made is pointed at by lmte*/
/* pirt points to the correct initial reference table entry*/
mmte()
{
pirt->irle = lmte; /*pointer to last entry in chain*/
if(pirt->irfe == 0) /*first entry in chain*/
pirt->irfe = lmte;
addmte();
}
/************************************************************************/
/* */
/* addmte() -- add the symbol pointed to by lmte to symbol table */
/* */
/* Uses sbrk (vs. malloc) to guarantee continuity with rest of */
/* symbol table. */
/* */
/************************************************************************/
addmte()
{
lmte += (sizeof *symptr); /*bump last main table entry pointer*/
if(lmte>=emte) { /*main table overflow*/
if(sbrk((sizeof *symptr)*ICRSZMT) == -1)
errorx(SYMOFL, ""); /* could not get more memory*/
else
{ /*move end of main table*/
emte += (sizeof *symptr)*ICRSZMT;
cszmt += ICRSZMT;
}
}
}
/* compute a hash code for the last entry in the main table*/
/* returns the hash code*/
hash()
{
register ht1, i; /*temps*/
register char *p;
ht1 = 0;
p = &lmte->name[0];
for(i=0; i<SYNAMLEN; i++)
ht1 += *p++;
return(ht1&076); /*make hash code even and between 0 and 62*/
}
/* pack a string into an entry in the main table*/
/* call with:*/
/* pointer to the string*/
/* pointer to desired entry in the main table*/
pack(apkstr,apkptr)
int *apkstr;
int *apkptr;
{
register int i;
register int *pkstr, *pkptr;
pkstr = apkstr;
pkptr = apkptr;
for(i=0; i<SYNAMLEN/(sizeof i); i++)
*pkptr++ = *pkstr++;
}
/* get a temp file for the intermediate text*/
gettempf(fp)
FILE **fp;
{
register i,j;
(TFCHAR)++;
if((*fp = fopenb(tfilname, "w")) == 0)
{
errorx(BADTEMP, tfilname);
endit(-1);
}
}
/* update the relocation counters with the sizes in the header*/
addsizes()
{
textbase += ((couthd.ch_tsize + 1)&~1);
database += ((couthd.ch_dsize + 1)&~1);
bssbase += ((couthd.ch_bsize + 1)&~1);
}
/*save the current state of the symbol table -- it may be restored later*/
savsymtab()
{
register char **p1, **p2;
register i;
savlmte = lmte;
p2 = eirt;
p1 = saveirt;
for(i=0; i<SZIRT; i++)
*p1++ = *p2++;
p2 = girt;
p1 = savgirt;
for(i=0; i<SZIRT; i++)
*p1++ = *p2++;
}
/*restore the symbol table as it was when we last saved it*/
restsymtab()
{
register char **p1, **p2;
register i;
lmte = savlmte;
p1 = eirt;
p2 = saveirt;
for(i=0; i<SZIRT; i++)
*p1++ = *p2++;
p1 = girt;
p2 = savgirt;
for(i=0; i<SZIRT; i++)
*p1++ = *p2++;
}
/************************************************************************/
/* */
/* resolve() -- resolve the external variable addresses and set the */
/* base address of the data and bss segments. */
/* */
/* On entry, all the final base addresses are in the overlay tree. */
/* If an external symbol has a value, it points to a jump block. */
/* External references to common areas have been set to zero */
/* when this routine is called. */
/* */
/************************************************************************/
resolve()
{
register char *p;
fixsyms(); /*relocate symbols with addresses*/
fixexts(); /*fix external addresses & commons*/
if(etextptr) {
pack(etexstr,lmte);
p=lemt(eirt);
do {
p->vl1 = ovtree[ROOT]->ovtxbase + rtxsize;
p->flags &= ~SYXR; /*no longer external*/
p->flags |= SYDF|SYGL|SYTX;
} while((p=nextsy(p->tlnk)) != lmte);
}
if(edataptr) {
pack(edatstr,lmte);
p=lemt(eirt);
do {
p->vl1 = ovtree[ROOT]->ovdtbase + rdtsize;
p->flags &= ~SYXR; /*no longer external*/
p->flags |= SYDF|SYGL|SYDA;
} while((p=nextsy(p->tlnk)) != lmte);
}
if(erootptr) {
pack(erootstr,lmte);
p=lemt(eirt);
do {
p->vl1 = ovtree[ROOT]->ovcap;
p->flags &= ~SYXR; /*no longer external*/
p->flags |= SYDF|SYGL|SYDA;
} while((p=nextsy(p->tlnk)) != lmte);
}
if(endptr) {
pack(eendstr,lmte);
p=lemt(eirt);
do {
p->vl1 = hihiaddr;
p->flags &= ~SYXR; /*no longer external*/
p->flags |= SYDF|SYGL|SYBS;
} while((p=nextsy(p->tlnk)) != lmte);
}
}
/************************************************************************/
/* */
/* fixsyms() --fix symbol addresses that have been assigned by adding */
/* in textbase, database, or bssbase for symbol's overlay. */
/* */
/* Text-based in root are already correct from pass 1. */
/* */
/************************************************************************/
fixsyms()
{
register struct symtab *p;
for(p=bmte; p<lmte; p++) { /*look at each symbol*/
if(p->flags&SYXR)
continue;
if(p->flags&SYTX) /*text symbol*/
{
if (p->ovlnum != ROOT)
p->vl1 += ovtree[p->ovlnum]->ovtxbase;
}
else if(p->flags&SYDA) /*data symbol*/
p->vl1 += ovtree[p->ovlnum]->ovdtbase;
else if(p->flags&SYBS) /* bss symbol*/
p->vl1 += ovtree[p->ovlnum]->ovbsbase;
}
}
/************************************************************************/
/* */
/* fixcoms() -- allocate the bss space for common areas and global */
/* static data. */
/* */
/************************************************************************/
long bsscomm = 0; /* use only in fixcoms and asgncomn */
fixcoms()
{
register char *p;
register char **sx1, **sx2;
long oldtop;
oldtop = ovtree[ROOT]->ovcap - ovtree[ROOT]->ovbsbase;
bsscomm = oldtop; /* current free bss */
for(sx1=eirt; sx1<&eirt[63]; sx1 += 2) { /*go thru externals*/
if(*(sx2 = sx1+1)==0) /*this chain empty*/
continue;
/* go thru symbols on chain*/
sx2 = *sx2; /*first entry on this chain*/
while(1) {
if(sx2->vl1)
asgncomn(sx2); /*assign a common address*/
p = sx2;
if(p == *sx1) /*end of chain*/
break;
sx2 = sx2->tlnk; /*next entry in chain*/
}
}
ovtree[ROOT]->ovcap += (bsscomm-oldtop); /* adjust for common */
}
/************************************************************************/
/* */
/* asgncomn(*symbol) -- assign an address for a block of bss common */
/* */
/* The address of the block is zero-based in the root's bss. It */
/* will be relocated later when all the globals are adjusted. */
/* */
/************************************************************************/
asgncomn(ap)
char *ap;
{
register char *p, *p1;
register long l;
p = ap;
pack(p,lmte);
p1 = lemt(girt);
if(p1 != lmte) { /*matches a global entry*/
ap->vl1 = 0; /* set once globals resolved*/
return;
}
l = 0;
lemt(eirt); /* set up pointer to proper chains */
do {
if(p->vl1 > l)
l = p->vl1;
p->vl1 = 0;
} while((p=nextsy(p->tlnk)) != lmte);
/*now make a global entry for this common block*/
p->flags = SYDF|SYGL|SYBS;
p->vl1 = bsscomm;
p->ovlnum = ROOT; /* the global goes in the root */
bsscomm += (l+1)&~1; /* always start at even address */
lemt(girt); /* set ptrs for global chain */
mmte(); /* add to global chain */
}
/************************************************************************/
/* */
/* fixexts() -- get addresses for all external symbols */
/* */
/* On entry, any externals with values have been resolved to a */
/* jump block. */
/* */
/************************************************************************/
fixexts()
{
register char *p;
register char **sx1, **sx2;
for(sx1=eirt; sx1<&eirt[63]; sx1 += 2) { /*go thru externals*/
if(*(sx2 = sx1+1)==0) /*this chain empty*/
continue;
/* go thru symbols on chain*/
sx2 = *sx2; /*first entry on this chain*/
while(1) {
if (!(sx2->vl1)) /* skip overlay calls */
asgnext(sx2); /* match to a global */
p = sx2;
if(p == *sx1) /*end of chain*/
break;
sx2 = sx2->tlnk; /*next entry in chain*/
}
}
}
/* assign an address to an external by matching it with a global*/
/* print an error message if no match*/
asgnext(ap)
char *ap;
{
register char *p, *pg;
p = ap;
pack(p,lmte); /*copy current symbol name*/
pg = lemt(girt);
astry2: if(pg == lmte) { /*no match in global symbols*/
pg=lemt(eirt); /*set ptrs for external chains*/
if(pg==lmte)
errorx(INTERR, "asgnext");
if(spendsym(ap)) /*end, etext, errot, or edata*/
return;
if(umesflg==0) {
errorx(UNDEF, "");
umesflg++;
if (!udfflg) /* undefined allowed? */
exstat++; /* no, set for exit */
}
prtsym(p);
}
else {
if (chnflg && (pg->ovlnum != ROOT) &&
(pg->ovlnum != p->ovlnum))
{
pg = nextsy(pg->tlnk); /* must be in right module */
goto astry2;
}
p->vl1 = pg->vl1; /*assign symbol value*/
}
}
/************************************************************************/
/* */
/* newjblk() -- allocate a new jump block and put it in the command tree*/
/* */
/************************************************************************/
struct jmpblock *
newjblk()
{
REG struct jmpblock *npt, *tpt;
REG struct ovtrnode *opt;
if ((npt = sbrk(sizeof(*npt))) <= 0) /* get a piece of memory */
errorx(NOROOM, "");
opt = ovtree[ovpath[ovpathtp]]; /* get current command tree node */
if ((tpt = opt->ovjblck) == NULL) /* empty list? */
opt->ovjblck = npt;
else
{
while (tpt->nxtjbl != NULL) /* find end of list */
tpt = tpt->nxtjbl;
tpt->nxtjbl = npt; /* put at end of list */
}
npt->nxtjbl = NULL;
return(npt);
}
/************************************************************************/
/* */
/* inkid(num,node) -- is num in command tree node's kidlist? */
/* */
/************************************************************************/
BOOLEAN
inkid(num,node)
REG int num, node;
{
node = ovtree[node]->ovfstkid; /* get index of first kid */
while (node != NULL)
{
if (node == num) /* same node? */
return(TRUE);
node = ovtree[node]->ovnxtsib; /* get the next kid */
}
return(FALSE); /* didn't find it */
}
/************************************************************************/
/* */
/* chkovext -- check an external symbol for possible overlay reference */
/* */
/* Returns 1 if a ovcall block is built. */
/* */
/* */
/************************************************************************/
int
chkovext(spt)
REG struct symtab *spt;
{
REG struct symtab *gpt;
REG int i;
REG struct jmpblock *jpt;
REG struct ovtrnode *ovpt;
REG long cbadd;
if (spt->vl1) /* already been processed */
return(0);
pack(spt->name,lmte); /* set up for search */
gpt = lemt(girt); /* look for global match */
if (gpt == lmte) /* no match? -- return and let */
return(0); /* fixexts handle unresolved */
/* validate global -- must be either non-overlayed (relative to */
/* module) or in child module and text-based */
for (i = 0; i <= ovpathtp; i++) /* non-overlayed? */
if (gpt->ovlnum == ovpath[i])
return(0); /* no jump block */
if (!(gpt->flags & SYTX))
{
errst1 = ovtree[spt->ovlnum]->ovfname;
errorx(BADOVREF, spt->name); /* returns */
return(0);
}
i = ovpath[ovpathtp]; /*current overlay number*/
ovpt = ovtree[i];
if (!(inkid(gpt->ovlnum, i)))
{
errst1 = ovtree[spt->ovlnum]->ovfname;
errorx(BADOVREF, spt->name);
return(0);
}
jpt = newjblk(); /* put a new jump block in */
jpt->globref = gpt; /* ovtree, remember symbol */
cbadd = ovpt->ovdtbase; /* get address of new code */
if (i != ROOT) /* non-root text-based globals */
cbadd -= ovpt->ovtxbase; /* are relocated later */
ovpt->ovdtbase += sizeof(ovcall); /* bump size up for new code*/
lemt(eirt); /* get pointers right */
while(1)
{
spt->vl1 = cbadd; /* actual address of call block */
spt->flags |= SYTX; /* text-based relocatable */
spt->flags &= ~SYXR; /* no longer external */
spt = nextsy(spt->tlnk); /* get all references */
if ((spt == lmte) || (spt->ovlnum != i))
return(1); /* done with this symbol */
}
}
/************************************************************************/
/* */
/* prtsym(sym) -- print a symbol name for an error message */
/* */
/************************************************************************/
prtsym(ap)
char *ap;
{
register i;
register char *p;
p = ap;
for(i=0; i<SYNAMLEN; i++) {
if(*p)
putchar(*p++);
else
break;
}
putchar('\n');
}
/************************************************************************/
/* */
/* p2load(fname) -- pass 2 load routine */
/* */
/* Read the file or library and do relocation */
/* */
/************************************************************************/
p2load(ap)
char *ap;
{
openfile(ap); /*get the file opened using ibuf*/
if(couthd.ch_magic == LIB1MAGIC) {
libhdsize = LIB1HDSIZE;
loadlib();
}
else if(couthd.ch_magic == LIB2MAGIC) {
libhdsize = sizeof *lib2hd;
loadlib();
}
else if(couthd.ch_magic == LIB3MAGIC) {
libhdsize = LIB3HDSIZE;
loadlib();
}
else {
do2load(0); /*load a *.o file*/
addsizes();
}
fclose(ibuf);
fclose(rbuf);
}
/*make the outut file and write the header*/
makeofile(ofilname)
char *ofilname;
{
long l;
outfname = ofilname; /* save name in case of error */
if((obuf = fopenb(ofilname, "w")) == 0)
errorx(BADOUT, ofilname);
if(Dflag|Bflag)
putw(MAGIC1,obuf); /*data & bss bases in header*/
else
putw(MAGIC,obuf); /*normal header*/
/* putw(0,obuf);*/ /* pad for VAX header */
#ifdef VAX
putw(textsize.loword,obuf);
putw(textsize.hiword,obuf);
putw(datasize.loword,obuf);
putw(datasize.hiword,obuf);
putw(bsssize.loword,obuf);
putw(bsssize.hiword,obuf);
l = (sflag)? lmte - bmte : 0;
putw(l.loword,obuf);
putw(l.hiword,obuf);
putw(stacksize.loword,obuf);
putw(stacksize.hiword,obuf);
putw(textstart.loword,obuf);
putw(textstart.hiword,obuf);
if(saverbits) {
putw(0,obuf); /*relocation bits present*/
/* putw(0,obuf); */
}
else {
putw(-1,obuf); /*relocation bits removed*/
/* putw(0,obuf);*/ /*pad for VAX header */
}
if(Dflag|Bflag) { /*output expanded header*/
putw(datastart.loword,obuf);
putw(datastart.hiword,obuf);
putw(bssstart.loword,obuf);
putw(bssstart.hiword,obuf);
}
#endif
#ifdef PDP11
putw(textsize.loword,obuf);
putw(textsize.hiword,obuf);
putw(datasize.loword,obuf);
putw(datasize.hiword,obuf);
putw(bsssize.loword,obuf);
putw(bsssize.hiword,obuf);
l = (sflag)? lmte - bmte : 0;
putw(l.loword,obuf);
putw(l.hiword,obuf);
putw(stacksize.loword,obuf);
putw(stacksize.hiword,obuf);
putw(textstart.loword,obuf);
putw(textstart.hiword,obuf);
if(saverbits) {
putw(0,obuf); /*relocation bits present*/
/* putw(0,obuf); */
}
else {
putw(-1,obuf); /*relocation bits removed*/
/* putw(0,obuf);*/ /*pad for VAX header */
}
if(Dflag|Bflag) { /*output expanded header*/
putw(datastart.loword,obuf);
putw(datastart.hiword,obuf);
putw(bssstart.loword,obuf);
putw(bssstart.hiword,obuf);
}
#endif
#ifdef MC68000
putw(textsize.hiword,obuf);
putw(textsize.loword,obuf);
putw(datasize.hiword,obuf);
putw(datasize.loword,obuf);
putw(bsssize.hiword,obuf);
putw(bsssize.loword,obuf);
l = (sflag)? lmte - bmte : 0;
putw(l.hiword,obuf);
putw(l.loword,obuf);
putw(stacksize.hiword,obuf);
putw(stacksize.loword,obuf);
putw(textstart.hiword,obuf);
putw(textstart.loword,obuf);
if(saverbits) {
putw(0,obuf); /*relocation bits present*/
/* putw(0,obuf); */
}
else {
putw(-1,obuf); /*relocation bits removed*/
/* putw(0,obuf);*/ /*pad for VAX header */
}
if(Dflag|Bflag) { /*output expanded header*/
putw(datastart.hiword,obuf);
putw(datastart.loword,obuf);
putw(bssstart.hiword,obuf);
putw(bssstart.loword,obuf);
}
#endif
gettempf(&tbuf); /*temp for data words*/
dafnc = TFCHAR;
if(saverbits) {
gettempf(&rtbuf); /*temp for text relocatin bits*/
rtfnc = TFCHAR;
gettempf(&rdbuf); /*temp for data relocation bits*/
rdfnc = TFCHAR;
}
}
endit(stat)
{
if (stat == 0)
fclose(obuf);
if(dafnc) {
TFCHAR = dafnc;
unlink(tfilname);
}
if(saverbits) {
TFCHAR = rtfnc;
unlink(tfilname);
TFCHAR = rdfnc;
unlink(tfilname);
}
if (dmpflg)
dumpsyms();
if (stat != 0)
exit(stat);
}
/* load files from a library. the library is open in ibuf, the*/
/* count of files to load is pointed to by libfctr, and the offset*/
/* of each file is pointed to by libptr.*/
loadlib()
{
register i,j;
register long l;
i = *libfctr++; /*# files to load from this library*/
if(i==0)
return; /*none to load*/
while(i--) { /*load the files*/
l = *libptr++; /*library offset for this file*/
lbseek(l,ibuf); /*seek to beginning of file*/
lbseek(l,rbuf);
rdlibhdr(); /*read the library header*/
readhdr(); /*read the file header*/
lbctr = l;
do2load(1); /*load it*/
addsizes();
}
}
/* do a long seek on buffer bp given a long file offset*/
/* last argument indicates relative or absolute seek*/
lbseek(al,bp)
long al;
FILE *bp;
{
if(fseek(bp,al,0) < 0)
errorx(SEEKERR, ifilname);
}
/************************************************************************/
/* */
/* extval(snum) -- look up the value of an external symbol given */
/* the external symbol number. */
/* */
/* Since externals are duplicated on the hash chains, */
/* all externals don't have values assigned in the symbol table, */
/* so the external name must be looked on the global chains and */
/* the value of the matching symbol used. symptr points to the */
/* first symbol for the current file's symbol table */
/* */
/************************************************************************/
long extval(extno)
{
register struct symtab *p;
register char *pg;
p = symptr + extno; /* symptr + extno*sizeof(symbol)*/
if((p->flags&SYXR)==0) {
return(p->vl1);
}
pack(p,lmte);
pg = lemt(girt);
if(pg == lmte)
pg = lemt(eirt); /*may be common*/
return(pg->vl1); /*return globals address*/
}
/* look up the relocation base for an external symbol. must use same*/
/* method as in extval for the same reasons (see comment above)*/
extbase(extno)
{
register struct symtab *p;
register char *pg;
register int i;
p = symptr + extno;
if((p->flags&SYXR)==0) {
pg = p;
}
else {
pack(p,lmte);
pg = lemt(girt);
if(pg == lmte)
pg = lemt(eirt); /*may be common*/
}
i = pg->flags;
if(i&SYDA)
return(DRELOC);
else if(i&SYTX)
return(TRELOC);
else if(i&SYBS)
return(BRELOC);
return(DABS);
}
/* load a file doing relocation and external resolution*/
/* lflg is set if we are loading from a library*/
do2load(lflg)
{
register i,j;
int longf;
register FILE *p;
register FILE *pr;
int saof;
register long tpc;
register long l;
long l1;
int wasext;
tpc = 0;
p = obuf;
pr = rtbuf;
saof = -1;
symptr = *firstsym++; /*beginning of this symbol table*/
l = couthd.ch_tsize + couthd.ch_dsize + couthd.ch_ssize + HDSIZE;
if(lflg)
l += lbctr + sizeof *lib2hd;
lbseek(l,rbuf); /*long seek */
l = couthd.ch_tsize;
do2l1:
while((l-= 2) >= 0) { /*relocate the text*/
longf = 0;
i = getw(ibuf);
j = getw(rbuf);
tpc += 2; /*keep pc in this file*/
wasext = 0;
switch(j&7) { /*relocation bits*/
case INSABS: /*first word of instr*/
case DABS: /*data absolute*/
putw(i,p);
if(saverbits)
putw(j,pr); /*relocation bits*/
break;
case LUPPER: /*high word of long*/
l1.hiword = i;
if(saverbits)
putw(j,pr); /*upper word relocation bits*/
l1.loword = getw(ibuf);
j = getw(rbuf);
tpc += 2;
longf++; /*doing two words*/
l -= 2; /*count lower half*/
dorelc:
switch(j&7) {
case DABS:
if(saverbits)
putw(j,pr);
break;
case INSABS:
case LUPPER:
default:
goto do2199;
case TRELOC:
l1 += textbase;
if(saverbits)
putw(j,pr);
break;
case DRELOC:
l1 += database;
if(saverbits)
putw(j,pr);
break;
case BRELOC:
l1 += bssbase;
if(saverbits)
putw(j,pr);
break;
case EXTVAR:
wasext++;
l1 += extval(j>>3);
if(saverbits)
putw(extbase(j>>3),pr);
break;
case EXTREL:
l1 = l1+extval(j>>3)-textbase-tpc+2;
if(l1< (-32768L) || l1>0x7fff) {
errnum1 = tpc-2;
errorx(RELADROFL, ifilname);
prextname(j>>3); /*give name referenced*/
exstat++;
}
l1.hiword = 0;
if(saverbits)
putw(DABS,pr);
goto outlowd;
}
if(ignflg==0 && longf==0 && l1&0xffff8000 && saof) {
errnum1 = tpc-2;
errorx(SHRTOFL, ifilname);
if(wasext)
prextname(j>>3);
exstat++;
if(lflg) {
l1 = *(libptr-1);
printf("library offset = %x\n",(int)l1.loword);
l1 = 0;
}
saof = 0;
}
if(longf)
putw(l1.hiword,p);
outlowd:
putw(l1.loword,p);
break;
case TRELOC:
case DRELOC:
case BRELOC:
case EXTVAR:
case EXTREL:
#ifdef NOMMU
l1 = *(libptr-1);
printf("library offset = %u\n",l1.loword);
printf("16-bit reloc in %s\n",ifilname);
#endif
l1 = i; /*sign extend to long like 68000*/
goto dorelc;
default:
do2199:
errorx(BADRELOC, ifilname);
}
}
if(p == obuf) {
p = tbuf; /*place to put data*/
pr = rdbuf; /*file for data relocatin bits*/
l = couthd.ch_dsize;
goto do2l1; /*now do the data*/
}
}
/************************************************************************/
/* */
/* wrjumps() -- write the overlay call blocks in the text segment */
/* */
/************************************************************************/
VOID
wrjumps()
{
REG int onum;
REG struct jmpblock *jpt;
onum = ovpath[ovpathtp];
jpt = ovtree[onum]->ovjblck;
while (jpt != NULL)
{
onum = (jpt->globref)->ovlnum; /* where is global? */
ovcall.ovtabad = ovtable + ((onum-1) * sizeof(ovcall));
ovcall.routaddr = (jpt->globref)->vl1;
putw(ovcall.jsrovh,obuf); /* jsr _ovhdlr */
putw((ovcall.ovhandlr).hiword, obuf);
putw((ovcall.ovhandlr).loword, obuf);
putw((ovcall.ovtabad).hiword, obuf); /* .dc.l ovtab */
putw((ovcall.ovtabad).loword, obuf);
putw(ovcall.jmprout, obuf); /* jmp routine */
putw((ovcall.routaddr).hiword, obuf);
putw((ovcall.routaddr).loword, obuf);
textbase += sizeof(ovcall); /* bump for block size */
if (saverbits)
{
putw(INSABS,rtbuf); /* jsr */
putw(LUPPER,rtbuf); /* address of ovhandler */
putw(TRELOC,rtbuf);
putw(LUPPER,rtbuf); /* address of ovtable */
putw(DRELOC,rtbuf);
putw(INSABS,rtbuf); /* jmp */
putw(LUPPER,rtbuf); /* address of routine */
putw(TRELOC,rtbuf);
}
jpt = jpt->nxtjbl; /* next block in list */
}
}
/************************************************************************/
/* */
/* wrovtab() -- write overlay table to root's data segment */
/* */
/************************************************************************/
VOID
wrovtab()
{
REG int i, j;
REG struct ovtrnode *opt;
REG short *pt;
for (i = 1; i <= numovls; i++)
{
opt = ovtree[i];
fixname(opt); /* put name in ovtab1 */
ovtab1.tbldpt = opt->ovtxbase; /* load point for module*/
pt = (&ovtab1); /* first word of ovtab1 */
for (j=1; j <= 6; j++, pt++) /* write filename */
{
#ifdef MC68000
putw(*pt,tbuf);
#endif
#ifdef VAX
putc(pt->hibyte,tbuf);
putc(pt->lobyte,tbuf);
#endif
#ifdef PDP11
putc(pt->hibyte,tbuf);
putc(pt->lobyte,tbuf);
#endif
if (saverbits)
putw(DABS,rdbuf);
}
putw((ovtab1.tbldpt).hiword,tbuf); /* write loadpt */
putw((ovtab1.tbldpt).loword,tbuf);
if (saverbits)
{
putw(LUPPER,rdbuf);
putw(TRELOC,rdbuf);
}
}
}
/************************************************************************/
/* */
/* fixname(trnode) -- put an output file name into ovtab1 */
/* */
/* The name must be in the proper form for direct BDOS calls. */
/* The filename is padded with blanks, and the type is left- */
/* justified in its field. There is no punctuation between */
/* the two parts. */
/* */
/************************************************************************/
VOID
fixname(opt)
REG struct ovtrnode *opt;
{
REG int i, j;
for (i = 0; i < 8 ; i++) /* sizeof(ovtab1.tbname) */
if (!isalnum(ovtab1.tbname[i] = opt->ovfname[i]))
break; /* found end of name */
for ( ;i < 8; i++) /* sizeof(ovtab1.tbname) */
ovtab1.tbname[i] = ' '; /* blank out rest of name */
for (i = 0; i < FNAMELEN; i++)
if (opt->ovfname[i] == '.') /* find file type */
break;
i++; /* skip dot, if there */
for (j = 0; (j < 3) && (i < FNAMELEN); i++, j++)
if (!isalnum(ovtab1.tbext[j] = opt->ovfname[i]))
break; /* copy only letters and digits */
for ( ;j < 3; j++)
ovtab1.tbext[j] = ' '; /* blank fill rest of type field*/
ovtab1.tbext[3] = '\0'; /* zero for overlay handler */
}
/************************************************************************/
/* */
/* finalwr() -- do the final writting to the output file */
/* */
/* copy the initialized data from the temp file to the output file */
/* write the symbol table to the output file */
/* */
/************************************************************************/
finalwr()
{
if (ovflag && !chnflg)
wrjumps();
if((textsize+textstart) != textbase) {
errorx(TSZERR, outfname);
exstat++;
}
if (ovflag && !chnflg && (ovpath[ovpathtp] == ROOT))
wrovtab();
cpdata(tbuf,dafnc,datasize);
osymt(); /*write the symbol table*/
if(saverbits) {
cpdata(rtbuf,rtfnc,textsize);
cpdata(rdbuf,rdfnc,datasize);
}
fflush(obuf);
if(fseek(obuf,14L,0)<0 || fwrite(&stlen,4,1,obuf)!=1) {
errorx(OWRTERR, outfname);
exstat++;
}
endit(exstat);
}
/* copy the initialized data words from temp file to output file*/
cpdata(pb,fnc,size)
register FILE *pb;
long size;
{
register j;
fflush(pb);
fclose(pb);
TFCHAR = fnc;
if((pb = fopenb(tfilname, "r")) == 0)
errorx(REOPNERR, tfilname);
while (size > 0)
{
j = getw(pb); /* Fetch word from source buffer */
putw(j,obuf);
size -= 2; /* Down by 2 bytes */
}
fclose(pb);
}
/* output symbol table to file*/
osymt()
{
register struct symtab *p;
stlen = 0;
if(!sflag) /*no symbol table desired*/
return;
/* now output the symbols deleting externals*/
for(p=bmte; p<lmte; p++) {
if(p->flags&SYXR) /*external symbol*/
continue;
if((p->flags&SYGL)==0 && (p->name[0]=='L' || Xflag==0))
continue;
osyme(p);
}
}
/* output symbols in a form to be read by a debugger*/
/* call with pointer to symbol table entry*/
long ll =0;
osyme(aosypt)
struct symtab *aosypt;
{
register struct symtab *osypt;
register short *p1;
register int i;
osypt = aosypt; /*pointer to symbol table entry*/
p1 = &(osypt->name[0]);
stlen += OSTSIZE; /*one more symbol out*/
/*output symbol to loader file*/
p1 = &(osypt->name[0]);
for(i=0; i<SYNAMLEN/2; i++) { /*output symbol name*/
putw(*p1++,obuf);
}
putw(osypt->flags,obuf); /*output symbol flags*/
ll = osypt->vl1;
putw(ll.hiword,obuf); /*output symbol value*/
putw(ll.loword,obuf);
}
/* look for and define if found etext, edata, eroot, and end*/
spendsym(ap)
struct symtab *ap;
{
register struct symtab *p;
p = ap;
if(eqstr(etexstr,&p->name[0])) {
etextptr = p;
return(1);
}
if(eqstr(edatstr,&p->name[0])) {
edataptr = p;
return(1);
}
if(eqstr(erootstr,&p->name[0])) {
erootptr = p;
return(1);
}
if(eqstr(eendstr,&p->name[0])) {
endptr = p;
return(1);
}
return(0);
}
/* test two symbol names for equality*/
eqstr(ap1,ap2)
char *ap1, *ap2;
{
register char *p1, *p2;
register int i;
p1 = ap1;
p2 = ap2;
for(i=0; i<SYNAMLEN; i++) {
if(*p1++ != *p2++) {
return(0);
}
}
return(1);
}
/* print an error message giving an external name*/
prextname(extno)
{
register struct symtab *p;
register char *pc;
p = symptr + extno;
printf(": external name: ");
for(pc = &p->name[0]; pc < &p->name[SYNAMLEN]; pc++) {
if(*pc == 0)
break;
putchar(*pc);
}
putchar('\n');
}
/************************************************************************/
/* */
/* dumpsyms() -- dump symbol table. Undocumented debugging aid */
/* */
/* */
/************************************************************************/
dumpsyms()
{
struct symtab *p;
printf("\nDUMP OF INTERNAL SYMBOL TABLE\n");
printf("BMTE = %lx, LMTE = %lx\n\n", bmte, lmte);
for (p=bmte;p<lmte;p++)
{
printf("NAME: %s\n", p->name);
printf("FLAGS: ");
if (p->flags & SYDF) printf("DEF ");
if (p->flags & SYEQ) printf("EQU ");
if (p->flags & SYGL) printf("GLB ");
if (p->flags & SYER) printf("REG ");
if (p->flags & SYXR) printf("EXT ");
if (p->flags & SYDA) printf("DAT ");
if (p->flags & SYTX) printf("TEX ");
if (p->flags & SYBS) printf("BSS");
printf("\n");
printf("VALUE: %lx\n", p->vl1);
printf("OVERLAY: %d\n", p->ovlnum);
printf("INTERNAL ADDRESS = %lx, LINK = %lx\n\n",
p, p->tlnk);
}
dmpflg = FALSE;
}