/*
    Copyright 1982, 1983
    Alcyon Corporation
    8716 Production Ave.
    San Diego, Ca.  92121
*/

char *version = "@(#)main.c	1.7	12/28/83";

#include "lo68.h"
#ifndef DECC
#	include <signal.h>
#else
#	include "Isignal"
#endif

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

#ifdef MC68000
#	define LIBINDEX	8
	char libname[] = "/lib/lib7.a";   /*default library name*/
	char libxname[] = "/lib/lib       ";   /*library name*/
    char *ofilname = "a.out";
	char shortexit[] = "/lib/exit.o";
#else
#	ifndef VMS
#		define LIBINDEX	18
		char libname[] = "/usr/local/lib/lib7.a";   /*default library name*/
		char libxname[] = "/usr/local/lib/lib       ";   /*library name*/
    	char *ofilname = "c.out";     /*output file name*/
		char shortexit[] = "/usr/local/lib/shortexit.o";
#	else
#		define LIBINDEX	8
		char libname[] = "clib:lib7.a";
		char libxname[] = "clib:lib       ";
    	char *ofilname = "c.out";     /*output file name*/
		char shortexit[] = "clib:exit.o";
#	endif
#endif

#ifndef VMS
#	define FILSEP	'/'
#	define NAMELOC		10	/* location in tfilname where letter is */
	char tfilname[18]  = "/tmp/_ldtmaXXXXX";  /*first temp file name*/
	int shortfildes;	/* file designator for short exit */
#else
#	define FILSEP	']'
#	define NAMELOC		5
	char tfilname[18]  = "wk:tmaXXXXX";

/**
 *	declarations for fix to sbrk problem.  On the vax when files are opened
 *	between calls to sbrk, the allocated memory is not contiguous.  Therefore
 *	all the input files are concatenated into one file which is opened prior
 *	to the calls to sbrk.  This process creates a large overhead in disk I/O,
 *	but the structure of the program requires that the memory for the symbol
 *	table be continuous.  It would be preferable to find a faster solution
 *	to the problem.
**/
	int openfilloc[NFILE];	/* pointers to beginning of the input files */
	int fdp = 0;			/* index to openfilloc */
	char *pt, *lpin;
#endif

long longseek();

char etexstr[]   = "_etext\0\0";
char edatstr[]   = "_edata\0\0";
char eendstr[]   = "_end\0\0\0\0";
int ignflg;
int debug;
int exstat;
int mmuflag;
int errno;		/* system call error number */

main(argc,argv)
int argc;
char **argv;
{
    register char **p, *pc, *p1;
    register i, j;

	if( signal(SIGINT,SIG_IGN) != SIG_IGN )
		signal(SIGINT,endit);
	if( signal(SIGQUIT,SIG_IGN) != SIG_IGN )
		signal(SIGQUIT,endit);
	if( signal(SIGHUP,SIG_IGN) != SIG_IGN )
		signal(SIGHUP,endit);
	signal(SIGTERM,endit);
#ifdef MC68000
    sysinfo(0,&mmuflag);
#else
	mmuflag = 1;
#endif
#ifndef VMS
	/* init the symbol table after all the files have been opened on the vax */
    intsytab();     /*initialize the symbol table*/
#endif
    firstsym = fsymp;
    libfctr = lbfictr;
    libptr = lbfioff;
    if(argc <= 1) {
usage:
		printf(": Invalid lo68 argument list\n");
		endit(-1);
    }

#ifdef VMS
	/* open all files */
	p = argv+1;
	for (i=1; i < argc; i++) {
		pc = *p++;
		if(*pc == '-') {
			switch(*++pc) {
				case 'l':
					pc--;
					break;
				case 'o':
					p++;
					i++;
				case 'i':
				case 'n':
				case 's':
				case 'X':
				case 'Z':
				case 'I':
				case 'U':
				case 'T':
				case 'D':
				case 'B':
				case 'r':
				case 'v':
					continue;
			}
		}

		pt = pc;
		if (*pt == '-' && *++pt == 'l') {
			if(*++pt) {
				for(lpin = &libxname[LIBINDEX]; *pt; )
					*lpin++ = *pt++;
				*lpin++ = '.';
					*lpin++ = 'a';
				pt = libxname;
			}
			else	/* else default library name -- /lib/lib7.a */
				pt = libname;
		}
		else
			pt = pc;
		if ((openfilloc[fdp++]=open(pt,0)) < 0) {
			printf("unable to open %s\n",pt);
			printf("probably too many simultaneous opens for this system\n");
			endit(-1);
		}
	}
	fdp = 0;
	intsytab();			/* initialize the symbol table */
#endif
    p = argv+1;
    if (!mmuflag) 
		saverbits++;  /* relocation bits forced on nommu sys */
    for(i=1; i<argc; i++) {     /*process each argument*/
		pc = *p++;
		if(*pc == '-') {
	    	switch(*++pc) {
	
				case 'l':       /*library*/
					pc--;
					break;

				case 'o':       /*output file name*/
					ofilname = *p++;/*next arg is file name*/
					i++;
					continue;
		
				case 'n':   /*shared text*/
					shtext = DEFSHTEXT;
					if(*++pc == '2') /* mod 2k on shared text */
						shtext = TWOKSHT;
					else if( *pc == '4' )
						shtext = FOURKSHT;
					continue;
		
				case 'i':       /* i & d split*/
					isplit++;
					continue;

				case 's':   /*don't output symbol table*/
					sflag++;
					continue;
		
				case 'X':   /*keep local symbols except L**/
					Xflag++;
					continue;

				case 'Z':   /*offset the text base for standaone pgm*/
				case 'T':   /*another name for same flag*/
					Zflag++;
					textstart = lgetnum(++pc,16);   /*get a long hex number*/
					textbase = textstart;
					continue;

				case 'D':   /*data segment base*/
					Dflag++;
					datastart = lgetnum(++pc,16);
					continue;

				case 'B':   /*bss segment base*/
					Bflag++;
					bssstart = lgetnum(++pc,16);
					continue;

				case 'I':   /*ignore 16-bit addr overflow*/
					ignflg++;
					continue;
		
				case 'd':
					debug++;    /*[vlh] 4.2 debugging turned on... */
					continue;

				case 'r':
					saverbits++;    /*put relocation bits on c.out*/
					continue;

				case 'U':   /*initial undefined symbol*/
					p1 = lmte;
					pc++;
					for(j=SYNAMLEN; --j != -1; ) {	/* 2 may 83 */
						*p1++ = *pc;
						if(*pc)
							pc++;
					}
					((struct symtab *)lmte)->flags = SYXR; /*extern reference*/
					addsym(0);  /*put into symbol table*/
					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++;
		if(*pc == '-') {
	    	switch(*++pc) {

	    	case 'l':   /*library*/
				pc--;
				break;

	    	case 'o':   /*output file name*/
				p++;    /*skip file name*/
				i++;
				continue;

			case 'i':
			case 'n':
			case 's':   /*don't output symbol table*/
			case 'X':
			case 'Z':
			case 'I':
			case 'U':
			case 'T':
			case 'D':
			case 'B':
			case 'r':
			case 'v':
			continue;

			}
		}
		p2load(pc); /*read file or library*/
    }
    finalwr();      /*finish output file*/
}

/*
 * 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
 */
p1load(ap)
char *ap;
{
#ifndef VMS
    openfile(ap);   /*get the file opened using ibuf*/
#else
	vsetfile(ap);	/* handles combined file */
#endif
#ifdef DEBUG
	printf("Processing [%s]\n",ap);
#endif
    if(couthd.ch_magic == LIBMAGIC) 	/*library*/
		searchlib();
    else {
		do1load(0);     /*load a *.o file*/
		firstsym++;
		addsizes();
    }
    close(ibuf.fd);
}

/**
 *	search a library for files to include.  include an entry only
 *	if it has a global symbol which matches an external.
**/
long lbctr;
long libfilsize;
searchlib()
{
/*	Don't worry about shortsearch on vax/vms */
#ifndef VMS
    if(shortlflg || shortsearch())  /*optimize no lib routines to load*/
		return;
#endif
    lbctr = 2;
    *libfctr = 0;       /*no files from this library yet*/
    while(rdlibhdr()) { /*read library file header*/
		savsymtab();    /*save current state of symbol table*/
		extmatch = 0;
		noload = 0;
		ifilname = libhd.lfname;
		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;
		longseek(lbctr,&ibuf);    /*goto begin of next lib entry*/
    }
    libfctr++;      /*point to next library file counter*/
}

/*read a library file header*/
rdlibhdr()
{
	if (getarhd(&ibuf,&libhd) == -1)	/* 4.1 new library routine */
		return(0);      		/*end of file*/
	libhd.lmodti = 0;			/* provide end of string delim for name */
	libfilsize = libhd.lfsize; 	/* copy out file size */
    return(1);
}

/* open the file pointed to by ap*/
/*  check for the -lx type library spec*/
openfile(ap)
char *ap;
{
    register char *p, *lp;
#ifdef VAX11
	unsigned short omagic;
#else
	int omagic;
#endif

    p = ap;
    if(*p=='-' && *++p=='l') {
		if(*++p) { 		/* 13 apr 83, multi-char libraries */
	    	for (lp = &libxname[LIBINDEX]; *p; )
				*lp++ = *p++;
			*lp++ = '.';
			*lp++ = 'a';
			*lp = 0;
			p = libxname;
		}
		else 	/* else default library name -- /lib/lib7.a */
			p = libname;
    }
    else
		p = ap;
    if((ibuf.fd=open(p,0)) < 0) {
		printf(": unable to open %s\n",p);
		endit(-1);
    }
    ifilname = p;   /*point to current file name for error msgs*/
    if(read(ibuf.fd,&omagic.hibyte,1)!=1 || read(ibuf.fd,&omagic.lobyte,1)!=1) {
		printf(": read error on file: %s\n",ifilname);
		endit(-1);
    }
    couthd.ch_magic = omagic;
	ibuf.cc = 0;
    if (omagic != LIBMAGIC) {
		seek(ibuf.fd,0,0);		/* was lseek(ibuf.fd,0L,0); */
		readhdr();  /*read file header*/
    }
    if(pass2) {     /*need file descrptr for reloc bits*/
		rbuf.fd = open(p,0);
		rbuf.cc = 0;
    }
}

#ifdef VMS
/**
 *	vsetfile - make usable the file pointed to by openfilloc[fdp]
 *		called from p1load only.
**/
vsetfile(ap)
char *ap;
{
	unsigned short omagic;

	ibuf.fd = openfilloc[fdp++];
	ibuf.cc = 0;
	ifilname = ap;	/* point to current file name for error messages */
	if(read(ibuf.fd,&omagic.hibyte,1)!=1 || read(ibuf.fd,&omagic.lobyte,1)!=1) {
		printf(": read error on file: %s\n",ifilname);
		endit(-1);
	}
	couthd.ch_magic = omagic;
	ibuf.cc = 0;
	if (omagic != LIBMAGIC) {
		seek(ibuf.fd,0,0);		/* was lseek(ibuf.fd,0L,0); */
		readhdr();
	}
}
#endif

/* read the header of the input file*/
readhdr()
{
	if (getchd(&ibuf,&couthd) == -1) {	/* 4.1 new library routine */
		printf(": error reading header: %s\n",ifilname);
		endit(-1);
	}
    if(couthd.ch_magic != EX_MAGIC) {
		printf(": file format error: %s %o\n",ifilname,(int)couthd.ch_magic);
		endit(-1);
    }
    if(couthd.ch_rlbflg) {
		printf(": no relocation bits: %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)
int libflg;
{
    register long i, l, ret;

	addfnsym();				/* put file name into symbol table */
    *firstsym = lmte;       /*remember where this symbol table starts*/
    l = couthd.ch_tsize + couthd.ch_dsize + HDSIZE;
    if(libflg)
		l += lbctr + LIBHDSIZE;
	ret = longseek(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;
    }
}

/* put file name into symbol table */

addfnsym()
{

	register char *p,*q;
	register int i;

	p = q = ifilname;
	while(*p) {
		if(*p == FILSEP)	/* directory delimiter */
			q = p+1;
		p++;
	}
	p = lmte;
	for(i=0; i<SYNAMLEN; i++) {
		if(*q) {
			*p++ = *q++;
		}
		else {
			*p++ = '\0';
		}
	}
	lmte->flags = SYFN|SYGL|SYTX;	/* file name bit */
	lmte->vl1 = textbase;
	addmte();
}

/* get a temp file for the intermediate text*/
gettempf()
{
    register short i,j;
	struct stat stbuf;

    while( mktemp(tfilname) ) {
#ifndef VMS
		if( stat(tfilname,&stbuf) >= 0 )
			continue;	/* this file exists */
#endif
		if( (j = creat(tfilname,0600)) >= 0 )
	    	return(j);
		else if (debug)
			printf("couldn't creat, return value %d\n",j);
    }
    printf(": Unable to open temporary file\n");
    endit(-1);
}

/* update the relocation counters with the sizes in the header*/
addsizes()
{
    textbase = textbase + couthd.ch_tsize;
    database = database + couthd.ch_dsize;
    bssbase  = bssbase + couthd.ch_bsize;
}

/* 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*/
		if(((struct symtab *)p1)->flags&SYTX) {    /* linking to text symbol */
	    	printf("text/data symbol name conflict: %s\n",p1);
		}
		((struct symtab *)ap)->vl1 = ((struct symtab *)p1)->vl1;
		return;
    }
    l = 0;
    lemt(eirt);
    do {
		if(((struct symtab *)p)->vl1 > l)
	    	l = ((struct symtab *)p)->vl1;
		((struct symtab *)p)->vl1 = 0;
    } while((p = nextsy(((struct symtab *)p)->tlnk)) != lmte);
	/*now make a global entry for this common block*/
    ((struct symtab *)p)->flags = SYDF|SYGL|SYBS;
    ((struct symtab *)p)->vl1 = bssbase + bsssize;
		/*copy address to first external*/
    ((struct symtab *)ap)->vl1 = ((struct symtab *)p)->vl1;
    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(((struct symtab *)p)->tlnk)) != lmte) {
	    	if(((struct symtab *)p)->vl1) {        /*common*/
				asgncomn(ap);
				return;
	    	}
		}
		if(spendsym(ap))        /*end, etext or edata*/
	   		return;
		if(undflg==0) {
	   	 	printf(": Undefined:\n");
	   	 	undflg++;
	   	 	exstat++;
		}
		prtsym(p);
    }
    else   /*assign symbol value*/
		((struct symtab *)p)->vl1 = ((struct symtab *)pg)->vl1;
    
}

/* 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 == LIBMAGIC)
		loadlib();
    else {
		do2load(0);     /*load a *.o file*/
		addsizes();
    }
    close(ibuf.fd);
    close(rbuf.fd);
}

/*make the outut file and write the header*/
makeofile()		/* 4.1 restructured */
{
	register struct hdr2 *lb;
	struct hdr2 olibhd;

    if( (obuf.fd = creat(ofilname,0666)) < 0 ) { /* only make exec if all ok */
		printf(": Unable to create %s\n",ofilname);
		endit(-1);
    }
    obuf.cc = BSIZE;
    obuf.cp = &obuf.cbuf[0];
	lb = &olibhd;
    if(Zflag|Dflag|Bflag) {		/*expanded header: data & bss bases in header*/
		lb->ch_magic = (unsigned short)EX_ABMAGIC;
		lb->ch_dstart = datastart;
		lb->ch_bstart = bssstart;
    }
	else if (isplit)		/* i & d split */
		lb->ch_magic = (unsigned short)EX_IDMAGIC;
    else if(!shtext)		/* standard */
		lb->ch_magic = (unsigned short)EX_MAGIC;
	else if (shtext == -1)	/* 2k boundary */
		lb->ch_magic = (unsigned short)EX_2KSTXT;
	else					/* 4k boundary */
		lb->ch_magic = (unsigned short)EX_4KSTXT;
    lb->ch_tsize = textsize;
    lb->ch_dsize = datasize;
    lb->ch_bsize = bsssize;
    lb->ch_ssize = (long)(lmte - bmte);
    lb->ch_stksize = stacksize;
	lb->ch_entry = textstart;
	if (saverbits)			/* bits present ?? */
		lb->ch_rlbflg = 0;
	else
		lb->ch_rlbflg = -1;
/* printf("tsz %d dsz %d bsz %d ssz %d bits %d\n",lb->ch_tsize,lb->ch_dsize,lb->ch_bsize,lb->ch_ssize,lb->ch_rlbflg); */
	putchd(&obuf,lb);

    tmpbinit(&tbuf);    /*temp for data words*/
    dafnc = tfilname[NAMELOC];
    if(saverbits) {
		tmpbinit(&rtbuf);   /*temp for text relocation bits*/
		rtfnc = tfilname[NAMELOC];
		tmpbinit(&rdbuf);   /*temp for data relocation bits*/
		rdfnc = tfilname[NAMELOC];
    }
}

tmpbinit(abufp)
struct iob *abufp;
{
    register struct iob *bufp;

    bufp = abufp;
    bufp->fd = gettempf();
    bufp->cc = BSIZE;
    bufp->cp = &bufp->cbuf[0];
}

endit(xstat)
int xstat;
{
    if(dafnc) {
		tfilname[NAMELOC] = dafnc;
		unlink(tfilname);
    }
    if(saverbits) {
		tfilname[NAMELOC] = rtfnc;
		unlink(tfilname);
		tfilname[NAMELOC] = rdfnc;
		unlink(tfilname);
    }
	if( xstat == 0 )
		chmod(ofilname,0777);	/* if all ok, make it executable [jws] */
#ifdef VMS
	else
		printf("load failed - status = %x\n",xstat);
#endif
    exit(xstat);
}

/*
 * 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 int i,j;
    register long l;

#ifndef VMS
	/* don't short load on a vms vax */
    if(shortlflg) {
		if(shortlflg == 1)  /*need to load short exit*/
	    	shortload();
		shortlflg++;
		return;
    }
#endif
    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*/
		longseek(l,&ibuf);        /*seek to beginning of file*/
		longseek(l,&rbuf);
		if (!rdlibhdr())         /*read the library header*/
			printf("Bad Library Header....\n");
		readhdr();          /*read the file header*/
		lbctr = l;
		do2load(1);         /*load it*/
		addsizes();
    }
}

#ifndef PDP11
/* do a long seek on buffer bp  given a long file offset*/
long
longseek(al,bp)
long al;
struct iob *bp;
{
	long ret;

	ret = lseek(bp->fd,al,0);
    bp->cc = 0;     			/*input buffer empty*/
	bp->cp = &bp->cbuf;
	return(ret);
}
#endif

/*
 * look up the value of an external symbol given the external symbol
 *  number.  Since externals are duplicated on the external hash chains,
 *  all external entries 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)
int 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(((struct symtab *)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)
int extno;
{
    register struct symtab *p;
    register char *pg;
    register int i;

    p = symptr + extno;
    if((p->flags&SYXR)==0)
		pg = (char *)p;
    else {
		pack(p,lmte);
		pg = lemt(girt);
		if(pg == lmte)
	    	pg = lemt(eirt);    /*may be common*/
    }
    i = ((struct symtab *)pg)->flags;
    return((i&SYDA)? DRELOC : (i&SYTX)? TRELOC : (i&SYBS)? BRELOC : DABS);
}

/* load a file doing relocation and external resolution*/
/*  libflg is set if we are loading from a library*/
do2load(libflg)
int libflg;
{
    int longf;
	short i, j;
    register struct iob *p;
    register struct iob *pr;
    int saof, wasext;
	short word;
    register long tpc, l;
    long l1;

    tpc = 0;
    p = &obuf;
    pr = &rtbuf;
    saof = -1;
    symptr = (struct symtab *)*firstsym++;   /*beginning of this symbol table*/
    l = couthd.ch_tsize + couthd.ch_dsize + couthd.ch_ssize + HDSIZE;
    if(libflg)
		l += lbctr+LIBHDSIZE;
    longseek(l,&rbuf);    /*long seek */
    l = couthd.ch_tsize;
do2l1:
    while((l -= 2) >= 0) {   /*relocate the text*/
		longf = 0;
		lgetw(&i,&ibuf);    /*text or data word */
		lgetw(&j,&rbuf);    /*relocation word*/
		tpc += 2;       	/*keep pc in this file*/
		wasext = 0;
		switch(j&7) {       /*relocation bits*/
	
	    	case INSABS:    /*first word of instr*/
	    	case DABS:      /*data absolute*/
				lputw(&i,p);
				if(saverbits)
		    		lputw(&j,pr);     /*relocation bits*/
				break;

	    	case LUPPER:    /*high word of long*/
				l1.hiword = i;
				if(saverbits)
		    		lputw(&j,pr);     /*upper word relocation bits*/
				lgetw(&l1.loword,&ibuf);
				lgetw(&j,&rbuf);
				tpc += 2;
				longf++;    /*doing two words*/
				l -= 2;     /*count lower half*/
dorelc:
				switch(j&7) {

				case DABS:
					if(saverbits)
						lputw(&j,pr);
					break;

				case INSABS:
				case LUPPER:
				default:
					goto do2l99;

				case TRELOC:
					l1 += textbase;
					if(saverbits)
						lputw(&j,pr);
					break;

				case DRELOC:
					l1 += database;
					if(saverbits)
						lputw(&j,pr);
					break;
	
				case BRELOC:
					l1 += bssbase;
					if(saverbits)
						lputw(&j,pr);
					break;

				case EXTVAR:
					wasext++;
					l1 += extval((int)j>>3);
					if(saverbits) {
						word = extbase((int)j>>3);
						lputw(&word,pr);
					}
					break;
	
				case EXTREL:
					l1 = l1+extval((int)j>>3)-textbase-tpc+2;
					if(l1<0xffff8000 || l1>0x7fff) {
						printf(": relative address overflow at %lx in %s\n",
								tpc,ifilname);
						prextname((int)j>>3);    /*give name referenced*/
						exstat++;
					}
					l1.hiword = 0;
					if(saverbits) {
						word = DABS;
						lputw(&word,pr);
					}
					goto outlowd;
	
				}
				if(ignflg==0 && longf==0 && l1&0xffff8000 && saof) {
					printf(": short address overflow in %s\n",ifilname);
					if(wasext)
						prextname((int)j>>3);
					exstat++;
					if(libflg) {
						l1 = *(libptr-1);
						printf("library offset = %u\n",(int)l1.loword);
						l1 = 0;
					}
					saof = 0;
				}
				if(longf)
					lputw(&l1.hiword,p);
outlowd:
				lputw(&l1.loword,p);
				break;
		
			case TRELOC:
			case DRELOC:
			case BRELOC:
	    	case EXTVAR:
	    	case EXTREL:
				l1 = *(libptr-1);
				if (!mmuflag) {
		    		printf("library offset = %u\n",(int)l1.loword);
		    		printf("16-bit reloc in %s\n",ifilname);
				}
				l1 = i;     /*sign extend to long like 68000*/
				goto dorelc;
	
	    	default:
			do2l99:
				printf(": lo68: invalid relocation flag in %s\n",ifilname);
				endit(-1);
		
		}
    }
    if(p == &obuf) {
		p = &tbuf;      /*place to put data*/
		pr = &rdbuf;    /*file for data relocation 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);
    osymt();        /*write the symbol table*/
    if(saverbits) {
		cpdata(&rtbuf,rtfnc);
		cpdata(&rdbuf,rdfnc);
    }
    fflush(&obuf);
/* longseek was: lseek(obuf.fd,14L,0); */
    if( longseek(14L,&obuf) < 0 || lwritel(obuf.fd,&stlen) == -1 ) {
		printf(": output file write error\n");
		exstat++;
    }
    endit(exstat);
}

/* copy the initialized data words from temp file to output file*/
cpdata(pb,fnc)
struct iob *pb;
char fnc;
{
    register int i,cfn;

    fflush(&obuf);
    fflush(pb);
    close(pb->fd);
    tfilname[NAMELOC] = fnc;
    if((cfn=open(tfilname,0)) < 0) {
		printf(": unable to reopen %s\n",tfilname);
#ifdef DEBUG
		printf(": errno=%o\n",errno);
#endif
		endit(-1);
    }
    while((i=read(cfn,&pb->cbuf[0],BSIZE)) > 0) {
		if(write(obuf.fd,&pb->cbuf[0],i) != i) {
	    	printf(": output file write error\n");
	    	endit(-1);
		}
    }
}

/*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 = SYNAMLEN; --i != -1; )	/* 2 may 83 */
		if(*p1++ != *p2++)
		    return(0);
    return(1);
}

/* print an error message giving an external name*/
prextname(extno)
int 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');
}

#ifndef VMS
/**
 * check to see if we only need to load exit -- no other
 * library routines needed.  if so, load exit only and
 * return 1 else return 0.
**/
shortsearch()
{
    register char *p;
    register char **sx1, **sx2;
    register int i;

    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 = (char **)*sx2;     /*first entry on this chain*/
		while(1) {
	    	if(((struct symtab *)sx2)->vl1 == 0)
				if(eqstr("_exit\0\0\0",sx2)==0&&eqstr("_main\0\0\0",sx2)==0)
		    		return(0);
	    	p = (char *)sx2;
	    	if(p == *sx1)       /*end of chain*/
				break;
	    	sx2 = (char **)((struct symtab *)sx2)->tlnk; /*next entry in chain*/
		}
    }
/* found only exit undefined*/
    if((i=open(shortexit,0)) < 0)
	return(0);      /*cant open short exit file*/
    close(i);
    close(ibuf.fd); /*close library -- dont need to scan it*/
    openfile(shortexit);
    do1load(0);         /*load short exit*/
    firstsym++;
    addsizes();
    shortlflg++;
    return(1);
}

/* load the short exit routine*/
shortload()
{
    close(ibuf.fd);     /*dont need library*/
    close(rbuf.fd);
    openfile(shortexit);
    do2load(0);
    addsizes();
}
#endif

#ifndef MC68000
static char _uniqlet = 'a';

char *
mktemp(ap)
char *ap;
{
	register char *p;
	register int i,j;

	p = ap;
	i = getpid();		/* process id */

	while( *p )
		p++;

	for(j = 5; --j != -1; ) {
		*--p = ((i&7) + '0');
		i =>> 3;
	}
	*--p = _uniqlet;

	_uniqlet++;
	if( _uniqlet > 'z' )
		_uniqlet = 'A';
	if( _uniqlet == 'Z' )
		return(0);
	return(ap);
}
#endif

#ifdef PDP11
/**
 *	longseek - do a long seek on buffer bp, given a long
 *		file offset.
**/
long
longseek(al,bp)
long al;
struct buf *bp;
{
	long l, ret;
	register short b,o;

	l = al>>9;
	b = l.loword;		/* block # */
	o = al.loword&0777;	/* offset in block */
	if((ret=seek(bp->fd,b,3)) < 0) {	/* seek to block */
		printf(": seek error on file %s\n",ifilname);
		endit(-1);
	}
	if((l=seek(bp->fd,o,1)) < 0) {		/* do offset */
		printf(": seek error on file %s\n",ifilname);
		endit(-1);
	}
 	bp->cc = 0;			/* input buff empty */
	bp->cp = &bp->cbuf;
	ret = (b*512) + o;
	return(ret);
}
#endif
