Ultrix-3.1/src/ucb/l11/pass2.c

Compare this file to the similar file:
Show the results in this format:


/**********************************************************************
 *   Copyright (c) Digital Equipment Corporation 1984, 1985, 1986.    *
 *   All Rights Reserved. 					      *
 *   Reference "/usr/src/COPYRIGHT" for applicable restrictions.      *
 **********************************************************************/

static	char Sccsid[] = "@(#)pass2.c	3.0	4/22/86";
# include	"link.h"
#include	<errno.h>
# define	MAXREG		8
WORD	getword();
char *sprintf();


/******************** variables with global scope ************************/


extern struct objfile	*File_root;	/* root of object file link-list */
extern struct symbol	*Sym_root;	/* root of symbol table */
extern struct g_sect	*Gsect_root;	/* root of global psect tree */
WORD	Maxabs;			/* maximum size of absolute files,
					** also low limit of relocatable code */
extern WORD	R_counter;		/* relocation counter, used in 
					** assigning relocation constants,
					** also high limit of relocatable
					** code after relocation */
extern long	Seekoff;		/* offset for seeking in out file */
extern char	Do_410;			/* out file format boolean */
extern char	Do_411;			/* out file format boolean */
extern char	Do_map;			/* boolean for printing load map */
extern char	Do_lpr_map;		/* boolean for line printing map */
extern char	Do_bits;		/* boolean for including relocation 
					** bits in .out file */ 
extern char	Do_kludge;		/* boolean to write global symbols in
					** out file table with underscore */
extern char	Do_silent;		/* boolean for not printing zero
					** errors message */
extern char	Do_table;		/* boolean for including symbol table
					** in out file */
extern char	No_locals;		/* boolean for not including local
					** symbols in out table */
extern WORD	Transadd;		/* transfer address */
int		T_counter;		/* used for assigning numbers to the
					** global symbols so that they may be
					** referenced in relocation bits */
int		Glc;			/* global location counter */
struct outword	Curr;			/* Curr.val is the current relocation
					** constant, and Curr.rbits is the 
					** current relocation bits */
WORD	Tex_size;		/* for out file */
WORD	Dat_size;		/* for out file */
WORD	Bss_size;		/* for out file */
char	*Outname;		/* name of out file */
FILE		*Outp = NULL;		/* pointer for out file */
extern char	Erstring[80];		/* buffer for error messages */
extern int	Nerrors;		/* the number of user errors */
FILE		*Bitp = NULL;		/* temporary file for relocation bits */
char		Bitname[20];		/* name of temporary bit file */
FILE		*Symp = NULL;		/* temporary file for symbol table */
char		Symname[20];		/* name of temporary file for symbol table */
char	*Mapname;		/* name of the map file */
FILE	*Mapp;			/* pointer for map file */
char	No_out;			/* boolean for no out file */
char		Undefineds = 0;		/* boolean, set if there are any 
					** references to undefined global 
					** symbols in the out file */
struct outword	Vreg[MAXREG];		/* virtual registers */
extern int errno;

/**************************  warmup  ****************************************/


warmup()	/* get ready for pass 2: open out file and write header,
		** open temporary file for out file
		** symbol table and write global variables to it */

{
	WORD h[8];

	Outp = fopen(Outname, "w");
	if (Outp == NULL)
	{
		sprintf(Erstring, "%s not accessible\n", Outname);
		lerror(Erstring);
	}
	fseek(Outp, 15L+(long)Tex_size+(long)Dat_size, 0);
	putc(0, Outp);

	/* write header for out file */
	if (Do_410)
		h[0] = 0410;
	else if (Do_411)
		h[0] = 0411;
	else
		h[0] = 0407;
	h[1] = Tex_size;
	h[2] = Dat_size;
	h[3] = Bss_size;
	h[4] = 0;
	h[5] = Transadd;
	h[6] = 0;
	h[7] = Do_bits ? 0 : 1;
	
	fseek(Outp, 0L, 0);
	fwrite(h, 8, 2, Outp);

	if (Do_table)
	{
		sprintf(Symname, "/tmp/l11.sym.%d", getpid());
		Symp = fopen(Symname, "w");
		if (Symp == NULL)
			lerror("can't open symbol table file");
		else
		{
			T_counter = 0;	/* initialize counter for numbering global
					** symbols */
			dump_tree(Sym_root);
		}
	}

	if (Do_bits)
	{
		sprintf(Bitname, "/tmp/l11.bit.%d", getpid());
		Bitp = fopen(Bitname, "w");
		if (Bitp == NULL)
			lerror("can't open relocation bits file");
	}
}


/*************************  dump_tree  **************************************/


dump_tree(sym)		/* dump the sub-tree of symbols pointed to by *sym and
			** number its contents for future reference to
			** undefined symbols */

register struct symbol	*sym;
{
	if (sym == NULL)
		return;
	
	dump_tree(sym->left);

	write_sym(sym->name, Do_kludge);
	if (sym->type & DEF)	/* if the symbol is defined */
		Putw(040 | get_type(sym->prsect->type), Symp);
	else			/* undefined */
		Putw(040, Symp);
	Putw(sym->value, Symp);
	sym->t_numb = T_counter++;

	dump_tree(sym->right);
}


/**************************  write_sym  ***********************************/


write_sym(sname, flag)	/* write the given symbol as 8 bytes (null padded)
			** in the symbol file , if flag then write the symbol
			** with an underscore */
register char	*sname;
register int	flag;
{
	if (flag)
		putc('_', Symp);
	while (*sname)
	{
		if (*sname == ' ')
			putc(0, Symp);
		else
			putc(*sname, Symp);
		sname++;
	}
	putc(0, Symp);
	if (!flag)
		putc(0, Symp);
}


/****************************  pass2  ****************************************/


pass2()		/* translate code and write local symbols */

{
	struct objfile	*obj;	/* which object file */

	obj = File_root;
	while (obj != NULL)
	{
		transcode(obj);
		if (Do_table && !No_locals)
			dump_locals(obj);
		obj = obj->nextfile;
	}
}


/************************  transcode  ****************************************/


transcode(obj)		/* translate code */

struct objfile	*obj;		/* object file to translate code from */
{
	register int	drctv;		/* directive from obj file */
	register int	value;		/* temporary variable */
	int		vrd;		/* possible virtual register directive */
	static struct outword	wbuff;


	ch_input(obj->fname, CODE);
	while (morebytes())	/* continue reading code section until
				** empty */
	{
	    switch (drctv = getbyte())
	    {
		case 000:
			abswrite((WORD)0, (WORD)0);
			break;

		case 002:
			relwrite((WORD)0, (WORD)0);
			break;

		case 004:
			abswrite(getword(), (WORD)0);
			break;

		case 006:
			relwrite(getword(), (WORD)0);
			break;

		case 010:
			abswrite(Curr.val, Curr.rbits);
			break;

		case 014:
			abswrite(Curr.val + getword(), Curr.rbits);
			break;

		case 020:
			get_sym(&wbuff);
			abswrite(wbuff.val, wbuff.rbits);
			break;

		case 022:
			get_sym(&wbuff);
			relwrite(wbuff.val, wbuff.rbits);
			break;

		case 030:
			get_rc(&wbuff, obj, (char *)NULL);
			abswrite(wbuff.val, wbuff.rbits);
			break;

		case 032:
			get_rc(&wbuff, obj, (char *)NULL);
			relwrite(wbuff.val, wbuff.rbits);
			break;

		case 034:
			get_rc(&wbuff, obj, (char *)NULL);
			abswrite(wbuff.val + getword(), wbuff.rbits);
			break;

		case 036:
			get_rc(&wbuff, obj, (char *)NULL);
			relwrite(wbuff.val + getword(), wbuff.rbits);
			break;

		case 040:
			do040(obj);
			break;

		case 044:
			wbuff.val = getword();
			wbuff.rbits = 0;
			vreg_oper(getbyte(), &wbuff);
			break;

		case 050:
			if ((vrd = getbyte()) == 0)
				linkseek(Curr.val, Curr.rbits);
			else
				vreg_oper(vrd, &Curr);
			break;

		case 054:
			value = getword();
			if ((vrd = getbyte()) == 0)
				linkseek(Curr.val + value, Curr.rbits);
			else
			{
				wbuff.val = Curr.val + value;
				wbuff.rbits = Curr.rbits;
				vreg_oper(vrd, &wbuff);
			}
			break;

		case 060:
			get_sym(&wbuff);
			vreg_oper(getbyte(), &wbuff);
			break;

		case 070:
			get_rc(&wbuff, obj, (char *)NULL);
			if ((vrd = getbyte()) == 0)
			{
				linkseek(wbuff.val, wbuff.rbits);
				Curr.val = wbuff.val;
				Curr.rbits = wbuff.rbits;
			}
			else
				vreg_oper(vrd, &wbuff);
			break;

		case 074:
			get_rc(&wbuff, obj, (char *)NULL);
			value = getword();
			if ((vrd = getbyte()) == 0)
			{
				linkseek(wbuff.val + value, wbuff.rbits);
				Curr.val = wbuff.val;
				Curr.rbits = wbuff.rbits;
			}
			else
			{
				wbuff.val += value;
				vreg_oper(vrd, &wbuff);
			}
			break;

		case 0200:
			bytewrite((char)0);
			break;

		case 0204:
			bytewrite((char)getbyte());
			break;

		case 0220:
			get_sym(&wbuff);
			if (Do_bits && wbuff.rbits != 0)
				uerror("unrelocatable byte expression");
			bytewrite((char)(0377 & wbuff.val));
			break;

		default:
			sprintf(Erstring, "bad code directive %03o", drctv);
			lerror(Erstring);
	    }
	}
}


/*************************  abswrite  *****************************************/


abswrite(value, rbits)	/* write value in the out file */
register WORD	value;
register WORD	rbits;	/* relocation bits */
{
	Putw(value, Outp);
	Glc += 2;
	if (Do_bits)
		Putw(rbits, Bitp);
}


/************************  relwrite  ****************************************/


relwrite(value, rbits)	/* write value in out file relative to 
			** global location counter */
register WORD	value;
register WORD	rbits;
{
	Putw(value - Glc - 2, Outp);
	Glc += 2;
	if (Do_bits)
		Putw((rbits == Curr.rbits) ? 0 : (rbits | 01), Bitp);
			/* if the relocation bits for the word being written are 
			** the same as the current psect's then the word is an 
			** absolute offset, otherwise add 1 to the relocation
			** bits to indicate relativity to the PC */
}


/*************************  bytewrite  *************************************/


bytewrite(value)	/* write the byte in the out file */
	char value;
{
	putc(0377&value, Outp);
	Glc++ ;
}


/*************************  get_rc  *****************************************/


get_rc(wbuff, obj, psname)	/* place in wbuff the relocation constant and
				** relocation bits of psname
				** or if psname is NULL the psect whose
				** name is in the input stream, and whose object
				** file is pointed to by 'obj'. */

register struct outword		*wbuff;
struct objfile			*obj;
register char			*psname;

{
	char			name[7];	/* the name of the psect */
	register struct psect	*ps;

	/* if psname is NULL get name from input stream */
	if (psname == NULL)
	{
		psname = name;
		dc_symbol(psname);
	}

	ps = obj->psect_list;

	while (strcmp(ps->name, psname))	/* while the strings are
						** not equal */
	{
		ps = ps->obsame;
		if (ps == NULL)
		{
			sprintf(Erstring, "rc not found for %s", psname);
			lerror(Erstring);
		}
	}
	wbuff->val = ps->rc;
	wbuff->rbits = get_bits(ps->type);
}


/*****************************  get_bits  **********************************/


get_bits(attributes)	/* get the out file symbol table bits and convert
			** to relocation table bits */

register int 	attributes;	/* the M11 attributes of a psect */
{
	return (2 * (get_type(attributes) - 1));
}


/*****************************  get_type  ***********************************/


get_type(attr)		/* decode the psect type into out file symbol table
			** attribute word format */
register int	attr;
{
	if (!(attr & REL))	/* absolute */
		return (01);
	else if (attr & INS)	/* text */
		return (02);
	else if (attr & BSS)	/* bss */
		return (04);
	else			/* data */
		return (03);
}


/***************************  get_sym  ***************************************/


get_sym(wbuff)		/* get the value of the symbol in the input stream */
register struct outword	*wbuff;

{
	char			sname[7];	/* the name of the symbol */
	register struct symbol  *sym;
	register int		cond;		/* used for branching left
						** or right */
	int			index;		/* virtual register index */

	dc_symbol(sname);
	if (*sname != ' ')
	{
		sym = Sym_root;
		while (sym != NULL)
		{
			if ((cond = strcmp(sname, sym->name)) == 0)
			{
				if (sym->type & DEF)	/* if defined */
				{
					wbuff->val = sym->value;
					wbuff->rbits = get_bits(sym->prsect->type);
					return;
				}
				else if (Do_bits)	/* set relocation bits
							** for undefined symbol
							** and return zero */
				{
					Undefineds = 1;
					wbuff->val = 0;
					wbuff->rbits = 020 * sym->t_numb + 010;
					return;
				}
				else
				{
					sprintf(Erstring, "undefined symbol: %s", sname);
					uerror(Erstring);
					wbuff->val = 0;
					wbuff->rbits = 0;
					return;
				}
			}
			else if (cond < 0)
				sym = sym->left;
			else
				sym = sym->right;
		}
		/* symbol has not been found */
		sprintf(Erstring, "%s not found", sname);
		lerror(Erstring);
		wbuff->val = 0;
		wbuff->rbits = 0;
	}
	else	/* virtual register */
	{
		index = sname[5] - 'a';
		wbuff->val = Vreg[index].val;
		wbuff->rbits = Vreg[index].rbits;
	}
}


/***************************  vreg_oper  *************************************/

vreg_oper(drctv, wbuff)		/* preform an operation on a virtual register */

register int		drctv;		/* directive (operation) */
register struct outword *wbuff;		/* source value and relocation bits */
{
	register int	index;		/* index of destination register */
	static char	mess[] = "unrelocatable arithmetic expression";

	index = getbyte() - 1;
	if (index >= MAXREG)
	{
		uerror("expression involving global symbols too large");
		index %= MAXREG;
	}

	switch(drctv)
	{
		case 0200:
			Vreg[index].val = wbuff->val;
			Vreg[index].rbits = wbuff->rbits;
			break;

		case 0201:
			Vreg[index].val += wbuff->val;
			if (Do_bits && Vreg[index].rbits && wbuff->rbits)
				uerror(mess);
			else
				Vreg[index].rbits |= wbuff->rbits;
			break;

		case 0202:
			Vreg[index].val -= wbuff->val;
			if (Do_bits && wbuff->rbits)
				if (Vreg[index].rbits == wbuff->rbits)
					Vreg[index].rbits = 0;
				else
					uerror(mess);
			break;

		case 0203:
			Vreg[index].val *= wbuff->val;
			if (Do_bits)
				uerror(mess);
			break;

		case 0204:
			Vreg[index].val /= wbuff->val;
			if (Do_bits)
				uerror(mess);
			break;

		case 0205:
			Vreg[index].val &= wbuff->val;
			if (Do_bits)
				uerror(mess);
			break;

		case 0206:
			Vreg[index].val |= wbuff->val;
			if (Do_bits)
				uerror(mess);
			break;

		default:
			sprintf(Erstring, "bad v.r. directive: %03o", drctv);
			lerror(Erstring);
	}
}


/**************************  do040  ***************************************/


do040(obj)	/* do 040 code directive */

register struct objfile	*obj;
{
	register int	drctv;
	register int	index;

	switch (drctv = getbyte())
	{
		case 001:	/* low limit */
			index = getbyte() - 1;
			Vreg[index].val = Maxabs;
			Vreg[index].rbits = 0;
			if (Do_bits)
				uerror("'.limit' directive not relocatable");
			break;

		case 002:	/* high limit */
			index = getbyte() - 1;
			Vreg[index].val = R_counter;
			Vreg[index].rbits = 0;
			break;

		case 003:	/* ^pl */
		case 004:	/* ^ph */
			p_limit(obj, drctv);
			break;

		case 0200:	/* clear */
			index = getbyte() - 1;
			Vreg[index].val = Vreg[index].rbits = 0;
			break;

		case 0201:	/* add zero */
			index = getbyte();
			break;

		default:
			sprintf(Erstring, "bad 040 directive %03o", drctv);
			lerror(Erstring);
	}
}


/*************************  p_limit  **************************************/


p_limit(obj, drctv)	/* find the low or high limit of a psect */
	struct objfile		*obj;
	int			drctv;
{
	register struct psect	*ps;
	register struct g_sect	*gptr;
	int			cond;
	register int		index;
	char			pname[7];

	dc_symbol(pname);
	index = getbyte() - 1;

	ps = obj->psect_list;

	while (ps != NULL)	/* try to find the psect in local link-list */
	{
		if ( !strcmp(pname, ps->name))
			break;
		ps = ps->obsame;
	}

	if (ps != NULL)		/* if it was found in the local list */
	{
		while (ps->pssame != NULL)	/* find bottom of sames, if any.
					 	** see relocate() */
			ps = ps->pssame;
	}
	else	/* psect not a local so check global tree */
	{
		gptr = Gsect_root;
		while (gptr != NULL)
		{
			if ( !(cond = strcmp(pname, gptr->name)))
			{
				if (gptr->last_sect->pssame == NULL)
					/* the psect is solitary */
					ps = gptr->last_sect;
				else
					/* last_psect points to the last psect
					** in a plural link-list of sames.
					** there is a psect after last_sect
					** which contains the conglomeration
					** of all the sames.
					** see relocate() */
					ps = gptr->last_sect->pssame;
				break;
			}
			else if (cond < 0)
				gptr = gptr->leftt;
			else
				gptr = gptr->rightt;
		}

		if (ps == NULL)		/* psect not found */
		{
			sprintf(Erstring, "%s not found in ^p reference", pname);
			uerror(Erstring);
			Vreg[index].val = Vreg[index].rbits = 0;
			return;
		}
	}

	if (drctv == 003)	/* low */
		Vreg[index].val = ps->rc;
	else			/* high */
		Vreg[index].val = ps->rc + ps->nbytes;

	Vreg[index].rbits = get_bits(ps->type);
}


/***************************  linkseek  *************************************/


linkseek(nlc, nrbits)

register WORD nlc;	/* new location counter */
register WORD nrbits;	/* new relocation bits */
{
	long	where;

	Glc = nlc;

	if (nrbits == 04)	/* if data section add offset */
		where = nlc + Seekoff + 020;
	else
		where = nlc + 020;

	if (fseek(Outp, where, 0) == -1)
	{
skerr:		fprintf(stderr, "Fseek error\n");
		bail_out();
	}
	if (Do_bits)
		if (fseek(Bitp, where - 020L, 0) == -1)
			goto skerr;

	if (nrbits == 06)	/* bss section about to be writen */
		uerror("error: initialized data in bss psect");
}


/****************************  dump_locals  ********************************/


# define	MAXCONSTS	10


dump_locals(obj)	/* dump local symbols */

struct objfile	*obj;
{
	int		rconst[MAXCONSTS];	/* relocation constants */
	int		segment[MAXCONSTS];	/* segment type for out file */
	struct psect	*last;			
	struct psect	*temp;
	char		sname[7];		/* symbol name */
	char		index;
	char		type;
	int		value;
	int		i;

	/* fill rconst and segment arrays from the first MAXCONSTS psects */
	temp = obj->psect_list;
	i = 0;
	while (temp != NULL && i < MAXCONSTS)
	{
		rconst[i] = temp->rc;
		segment[i++] = get_type(temp->type);
		temp = temp->obsame;
	}
	last = temp; 	/* (in case there are more psects than MAXCONSTS) */

	/* write 'em */

	ch_input(obj->fname, SYMBOLS);
	while (morebytes())
	{
		dc_symbol(sname);
		type = getbyte();
		index = getbyte();
		value = getword();
		
		if (type & 001)		/* if internal m11 symbol, forget it */
			continue;

		write_sym(sname, 0);
		if (index >= MAXCONSTS)
		{
			temp = last;
			for (i = MAXCONSTS; i < index; i++)
				temp = temp->obsame;
			Putw(get_type(temp->type), Symp);
			Putw(value + temp->rc, Symp);
		}
		else 
		{
			Putw(segment[index], Symp);
			Putw(value + rconst[index], Symp);
		}
	}
}


/************************  uerror  ******************************************/


uerror(mess)	/* print user error message and increment Nerrors */

register char	*mess;
{
	Nerrors++;
	fprintf(stderr, "%s\n", mess);
	if (Do_map)
		fprintf(Mapp, "%s\n", mess);
}


/**************************  loose_ends  ************************************/


loose_ends()
{
	register c;
	register int	nbytes;	/* number of bytes in out file symbol table */


	if (Do_bits)
	{
		if (ferror(Bitp))
			werror(Bitname);
		
		Bitp = freopen(Bitname, "r", Bitp);
		if (Bitp == NULL)
			lerror("can't reopen relocation bits file");

		fseek(Outp, (long) (Tex_size + Dat_size + 020L), 0);

		while ((c = getc(Bitp)) != EOF)
			putc(0377&c, Outp);

		unlink(Bitname);
	}

	if (Do_table)
	{
		if (ferror(Symp))
			werror(Symname);

		Symp = freopen(Symname, "r", Symp);
		if (Symp == NULL)
			lerror("can't reopen symbol table file");

		/* send r/w head to end of rbits or code section in out file */
			
		fseek(Outp, (long) ((Tex_size + Dat_size) * (Do_bits + 1) + 020L), 0);

		nbytes = 0;
		while ((c = getc(Symp)) != EOF)
		{
			nbytes++;
			putc(0377&c, Outp);
		}

		/* write size of symbol table */
		fseek(Outp, 010L, 0);
		Putw(nbytes, Outp);

		unlink(Symname);
	}

	if (Do_map)
	{
		fprintf(Mapp, "errors detected:  %d\n", Nerrors);
		if (ferror(Mapp))
			werror(Mapname);
		fclose(Mapp);
		if (Do_lpr_map)
			execl("/usr/bin/lpr", "lpr", Mapname, 0);
	}

	if (ferror(Outp))
		werror(Outname);

	/* change out file to be executable if no errors */
	chmod(Outname, Nerrors ? 0644 : 0755);

	if (Nerrors || !Do_silent)
		fprintf(stderr, "errors detected:  %d\n", Nerrors);

	exit(Nerrors ? 1 : 0);
}


/****************************  bail_out  ***********************************/


bail_out()	/* unlink any opened output file then exit */

{
	if (Outp != NULL)
		unlink(Outname);
	if (Mapp != NULL)
		unlink(Mapname);
	if (Symp != NULL)
		unlink(Symname);
	if (Bitp != NULL)
		unlink(Bitname);
	exit(1);
}


/********************************  werror  **********************************/


werror(fname)		/* write error handler */
char	*fname;

{
	switch(errno) {
		case ENOSPC: printf("No space left on device");
			break;
		case ENOENT: printf("No such file or directory");
			break;
		default:
			break;
	}
	printf("file: %s (errno = %d)\n",fname,errno);
	/* perror(fname); */
	if (Symp != NULL)
		unlink(Symname);
	if (Bitp != NULL)
		unlink(Bitname);
	exit(1);
}
Putw(x, p)
	FILE *p;
{
	putc(x & 0377, p);
	x >>= 8;
	putc(x & 0377, p);
}