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

1604 lines
33 KiB
C

/*
Copyright 1981
Alcyon Corporation
8474 Commerce Av.
San Diego, Ca. 92121
*/
#include "cout.h"
#include "lo68.h"
struct lib2hdr *lib2hd = 0;
#define BLKSIZE 512
/* 68000 linking loader*/
/* Bill Allen*/
/* This loader is basically 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
char *ofilname "c.out"; /*output file name*/
#ifdef UNIX /************************/
char *tfbase = "loXXXXXX"; /* Temp base name */
char *tdisk = "/tmp/"; /* Temp disk name */
#else /* CP/M and VMS */
char *tfbase = "loXXXXXA"; /* Temp base name */
char *tdisk = ""; /* 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 eendstr[] "_end\0\0\0\0";
int endit();
long lgetnum();
char *lemt();
char *nextsy();
char *sbrk();
int readshort();
int ignflg =0;
int debug 0;
int exstat =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 lseek();
main(argc,argv)
char **argv;
{
register char **p;
register char *pc;
register i;
register char *p1;
register int j;
/* signal(2,endit);*/ /*catch rubout*/
buildf(); /* Construct temp file names */
intsytab(); /*initialize the symbol table*/
firstsym = fsymp;
libfctr = lbfictr;
libptr = lbfioff;
if(argc <= 1) {
usage:
printf(": Invalid lo68 argument list\n");
endit(-1);
}
p = argv+1;
for(i=1; i<argc; i++) { /*process each argument*/
pc = *p++;
/*
* Compare for a file named ".o" and skip it for CP/M and VAX
* command file operation.
*/
if(_strcmp (pc,".o") == 0)
continue; /* Just skip this one */
if(*pc == '-') {
switch(*++pc) {
case 'l': /*library*/
pc--;
break;
case 'o': /*output file name*/
if(*(pc+1) != '\0') /* No space? */
{
printf(": Illegal option %s\n",*(--p));
exit(-1);
}
ofilname = *p++; /*next arg is file name*/
i++;
continue;
case 's': /*don't output symbol table*/
sflag++;
continue;
case 'X': /*keep local symbols except L**/
case 'x':
Xflag++;
continue;
case 'Z': /*offset the text base for standaone pgm*/
case 'z':
case 'T': /*another name for same flag*/
case 't':
Zflag++;
textstart = lgetnum(++pc,16); /*get a long hex number*/
textbase = textstart;
continue;
case 'D': /*data segment base*/
case 'd':
Dflag++;
datastart = lgetnum(++pc,16);
continue;
case 'B': /*bss segment base*/
case 'b':
Bflag++;
bssstart = lgetnum(++pc,16);
continue;
case 'I': /*ignore 16-bit addr overflow*/
case 'i':
ignflg++;
continue;
case 'r':
saverbits++; /*put relocation bits on c.out*/
continue;
case 'U': /*initial undefined symbol*/
case 'u':
p1 = lmte;
pc++;
for(j=0; j<SYNAMLEN; j++) {
*p1++ = *pc;
if(*pc)
pc++;
}
lmte->flags = SYXR; /*external reference*/
addsym(0); /*put into symbol table*/
continue;
case 'f': /* Temp file prefix */
tdisk = *p++; /* Prefix */
i++;
buildf(); /* build file names */
continue;
}
}
p1load(pc); /*read file or library*/
}
resolve(); /*resolve externals and assign addresses*/
pass2++; /*now in pass 2*/
p = argv+1;
firstsym = fsymp;
libfctr = lbfictr;
libptr = lbfioff;
makeofile(); /*make the output file*/
for(i=1; i<argc; i++) { /*process each argument*/
pc = *p++;
/*
* Skip files named ".o" again ...
*/
if(_strcmp(pc,".o") == 0)
continue;
if(*pc == '-') {
switch(*++pc) {
case 'l': /*library*/
pc--;
break;
case 'f': /* Temp file name */
case 'o': /*output file name*/
p++; /*skip file name*/
i++;
continue;
case 's': /*don't output symbol table*/
case 'X':
case 'x':
case 'Z':
case 'z':
case 'I':
case 'i':
case 'U':
case 'u':
case 'T':
case 't':
case 'D':
case 'd':
case 'B':
case 'b':
case 'r':
continue;
}
}
p2load(pc); /*read file or library*/
}
finalwr(); /*finish output file*/
}
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 {
do1load(0); /*load a *.o file*/
firstsym++;
addsizes();
}
close(ibuf.fildes);
}
/* 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 files symbol table & try match*/
if(extmatch > noload) { /*found a match*/
if(noload)
prdup(lastdup); /*print dup defn*/
addsizes(); /*add this files 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;
p = ap;
if(*p=='-' && *++p=='l') {
if(*++p)
LIBCHAR = *p;
else
LIBCHAR = '6'; /*default library name*/
p = libname;
}
else
p = ap;
if((ibuf.fildes=fopen(p,&ibuf,1)) < 0) {
printf(": unable to open %s\n",p);
endit(-1);
}
ifilname = p; /*point to current file name for error msgs*/
if( readshort(ibuf.fildes,&couthd.ch_magic) ) {
printf(": read error on file: %s\n",ifilname);
endit(-1);
}
ibuf.nunused = 0;
if( couthd.ch_magic != LIB2MAGIC ) {
lseek(ibuf.fildes,0L,0);
readhdr(); /*read file header*/
}
if(pass2) { /*need file descrptr for reloc bits*/
fopen(p,&rbuf,1);
}
}
/* read the header of the input file*/
int readshort(fd,s)
int fd;
short *s;
{
short ts;
if( read(fd,&ts,sizeof(short)) != sizeof(short) )
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) {
printf(": file format error: %s\n",ifilname);
endit(-1);
}
if(couthd.ch_rlbflg) {
printf(": File format error");
printf(": no relocation bits in %s\n",ifilname);
endit(-1);
}
}
/* 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(libflg)
{
register long i;
register long l;
*firstsym = lmte; /*remember where this symbol table starts*/
l = couthd.ch_tsize + couthd.ch_dsize + sizeof couthd;
if( libflg )
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(libflg); /*add to symbol table*/
i =- OSTSIZE;
}
}
/* get one symbol entry from the input file and put it into*/
/* the symbol table entry pointed to by lmte*/
getsym()
{
register int i;
register short *p;
p = lmte;
for(i=0; i<SYNAMLEN/(sizeof *p); i++)
*p++ = getw(&ibuf);
*p++ = getw(&ibuf); /* flags */
/* *p++=0; */ /* skip upp half of internal flags on VAX */
p->hiword = getw(&ibuf); /* sym value high word */
p->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*/
printf(": File Format error: Invalid symbol flags = %o\n",
(int)lmte->flags);
endit(-1);
}
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.*/
addsym(libflg)
{
register char *p;
/* if(debug) {*/
/* printf("addsym: file=%s symbol=%s flags=%o\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++;
}
}
p = lemt(girt);
if(p == lmte)
mmte();
else {
dupdef:
if(libflg) {
noload++;
lastdup = p;
}
else if(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;
{
printf(": %s duplicate definition in %s\n",p,ifilname);
exstat++;
}
/* initialize the symbol table and the heads of the hash lists*/
intsytab()
{
register char **p1, **p2;
register i;
bmte = (sbrk((sizeof *symptr)*SZMT+2));
if((long)bmte&1)
bmte++;
emte = bmte + (sizeof *symptr)*SZMT; /*end of main table*/
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();
}
/* add the symbol pointed to by lmte to symbol table*/
addmte()
{
lmte =+ (sizeof *symptr); /*bump last main table entry pointer*/
if(lmte>=emte) { /*main table overflow*/
if(sbrk((sizeof *symptr)*ICRSZMT) == -1){ /*get more memory*/
printf(": symbol table overflow\n");
exit(-1);
}
else {
emte =+ (sizeof *symptr)*ICRSZMT; /*move end of main table*/
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()
{
register i,j;
/* while(tfilname[10] <= 'z') {
if((j=creat(tfilname,0600))>=0)
return(j);
tfilname[10]++;
}
printf(": Unable to open temporary file: %s\n",tfilname);
endit(-1);
}*/
(TFCHAR)++;
if((j=creat(tfilname,0600,1)) >= 0)
{
return(j);
}
printf(": Unable to open temporary file: %s\n",tfilname);
endit(-1);
}
/* update the relocation counters with the sizes in the header*/
addsizes()
{
textbase =+ couthd.ch_tsize;
database =+ couthd.ch_dsize;
bssbase =+ couthd.ch_bsize;
}
/*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 the external variable addresses and set the*/
/* base address of the data and bss segments.*/
/* also allocate storage for the common variables.*/
resolve()
{
register char *p;
textsize = textbase - textstart;
datasize = database;
bsssize = bssbase;
if(Dflag)
database = datastart;
else {
database = (textbase+1)&~1;
datastart = database;
}
if(Bflag)
bssbase = bssstart;
else {
bssbase = (database+datasize+1)&~1;
bssstart = bssbase;
}
textbase = textstart;
fixsyms(); /*relocate symbols with addresses*/
fixexts(); /*fix external addresses & commons*/
if(etextptr) {
pack(etexstr,lmte);
p=lemt(eirt);
do {
p->vl1 = textsize;
p->flags =& ~SYXR; /*no longer external*/
p->flags =| SYDF|SYGL;
} while((p=nextsy(p->tlnk)) != lmte);
}
if(edataptr) {
pack(edatstr,lmte);
p=lemt(eirt);
do {
p->vl1 = textsize+datasize;
p->flags =& ~SYXR; /*no longer external*/
p->flags =| SYDF|SYGL;
} while((p=nextsy(p->tlnk)) != lmte);
}
if(endptr) {
pack(eendstr,lmte);
p=lemt(eirt);
do {
p->vl1 = textsize+datasize+bsssize;
p->flags =& ~SYXR; /*no longer external*/
p->flags =| SYDF|SYGL;
} while((p=nextsy(p->tlnk)) != lmte);
}
}
/* fix symbol addresses that have been assigned by adding in*/
/* database and bssbase*/
fixsyms()
{
register struct symtab *p;
for(p=bmte; p<lmte; p++) { /*look at each symbol*/
if(p->flags&SYXR)
continue;
if(p->flags&SYDA) /*data symbol*/
p->vl1 =+ database;
else if(p->flags&SYBS) /* bss symbol*/
p->vl1 =+ bssbase;
}
}
/* get addresses for all external symbols and common symbols*/
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)
asgncomn(sx2); /*assign a common address*/
else
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 for a block of bss common*/
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 = p1->vl1;
return;
}
l = 0;
lemt(eirt);
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 = bssbase + bsssize;
ap->vl1 = p->vl1; /*copy address to first external*/
bsssize =+ l;
lemt(girt); /*set ptrs for global chain*/
mmte(); /*add to global 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);
if(pg == lmte) { /*no match in global symbols*/
pg=lemt(eirt); /*set ptrs for external chains*/
if(pg==lmte) {
printf(": asgnext botch\n");
endit(-1);
}
while((p=nextsy(p->tlnk)) != lmte) {
if(p->vl1) { /*common*/
asgncomn(ap);
return;
}
}
if(spendsym(ap)) /*end, etext or edata*/
return;
if(undflg==0) {
printf(": Undefined symbol(s)\n");
undflg++;
exstat++;
}
prtsym(p);
}
else {
p->vl1 = pg->vl1; /*assign symbol value*/
}
}
/* 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');
}
/* 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();
}
close(ibuf.fildes);
close(rbuf.fildes);
}
/*make the outut file and write the header*/
makeofile()
{
long l;
if((obuf.fildes=creat(ofilname,0666)) < 0) {
printf(": Unable to create %s\n",ofilname);
endit(-1);
}
obuf.nunused = 512;
obuf.xfree = &obuf.buff[0];
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 = lmte - bmte;
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 = lmte - bmte;
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 = lmte - bmte;
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
tmpbinit(&tbuf); /*temp for data words*/
dafnc = TFCHAR;
if(saverbits) {
tmpbinit(&rtbuf); /*temp for text relocatin bits*/
rtfnc = TFCHAR;
tmpbinit(&rdbuf); /*temp for data relocation bits*/
rdfnc = TFCHAR;
}
}
tmpbinit(abufp)
struct buf *abufp;
{
register struct buf *bufp;
bufp = abufp;
bufp->fildes = gettempf();
bufp->nunused = BUFSIZE;
bufp->xfree = &bufp->buff[0];
}
endit(stat)
{
if(dafnc) {
TFCHAR = dafnc;
unlink(tfilname);
}
if(saverbits) {
TFCHAR = rtfnc;
unlink(tfilname);
TFCHAR = rdfnc;
unlink(tfilname);
}
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;
struct buf *bp;
{
register long bn;
bn = (al/BLKSIZE)*BLKSIZE;
if(lseek(bp->fildes,bn,0) < 0) {
printf(": seek error on file %s\n",ifilname);
endit();
}
bp->nunused = 0; /*input buff empty*/
bp->xfree = &bp->buff[0];
for( ; bn < al; bn++ )
getc(bp);
}
/* look up the value of an external symbol given the external symbol*/
/* number. Since externals are not 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;
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*/
/* libflg is set if we are loading from a library*/
do2load(libflg)
{
register i,j;
int longf;
register struct buf *p;
register struct buf *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(libflg)
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) {
printf(": relative address overflow at %lx in %s\n",
tpc,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) {
printf(": short address overflow in %s\n",ifilname);
if(wasext)
prextname(j>>3);
exstat++;
if(libflg) {
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:
printf(": File format error: invalid relocation flag in %s\n",ifilname);
endit(-1);
}
}
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*/
}
}
/* 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((textsize+textstart) != textbase) {
printf(": finalwr: text size error\n");
exstat++;
}
cpdata(&tbuf,dafnc,datasize);
osymt(); /*write the symbol table*/
if(saverbits) {
cpdata(&rtbuf,rtfnc,textsize);
cpdata(&rdbuf,rdfnc,datasize);
}
myfflush(&obuf);
if(lseek(obuf.fildes,14L,0)<0 || write(obuf.fildes,&stlen,4)!=4) {
printf(": output file write error\n");
exstat++;
}
endit(exstat);
}
/* copy the initialized data words from temp file to output file*/
cpdata(pb,fnc,size)
register struct buf *pb;
long size;
{
register j;
myfflush(pb);
close(pb->fildes);
TFCHAR = fnc;
if((fopen(tfilname,pb,1)) < 0) {
printf(": unable to reopen %s\n",tfilname);
endit(-1);
}
while (size > 0)
{
j = getw(pb); /* Fetch word from source buffer */
putw(j,&obuf);
size -= 2; /* Down by 2 bytes */
}
}
/* 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);
}
/*get constant given radix*/
/* this routine only works for radixes of 2, 8, 16*/
/* so as to avoid lmul because of floating point*/
long lgetnum(apc,ardx)
char *apc;
int ardx;
{
register trdx,j;
register char *pc;
register long i;
pc = apc;
if(ardx==16)
trdx = 4; /*radix as power of 2*/
else if(ardx==8)
trdx = 3;
else if(ardx==2)
trdx = 1;
else
return(0);
i=0;
while(1) {
j = *pc++;
if(j>='0' && j<='9')
j =- '0';
else
if(j>='a' && j<='f')
j = j-'a'+10;
else if(j>='A' && j<='F')
j = j-'A'+10;
else
break; /*not valid numeric char*/
if(j>=0 && j<ardx)
i = (i<<trdx)+j;
else
break;
}
return(i);
}
/* look for and define if found etext, edata, 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(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');
}