Ultrix-3.1/src/ucb/l11/link.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[] = "@(#)link.c	3.0	4/22/86";
# include	"link.h"
char *sprintf(),*strcpy(), *ctime(), *strsub(), *tack(), *lalloc();
WORD	getword();
#include	<signal.h>

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


struct psect	*Tex_root = NULL;	/* root of ins psects */
struct psect	*Tex_end = NULL;	/* last structure of ins list */
struct psect	*Dat_root = NULL;	/* root of data psects */
struct psect	*Dat_end = NULL;	/* last structure of data list */
struct psect	*Bss_root = NULL;	/* root of bss psects */
struct psect	*Bss_end = NULL;	/* last structure of bss list */
struct objfile	*File_root = NULL;	/* root of object file link-list */
struct symbol	*Sym_root = NULL;	/* root of symbol table */
struct g_sect	*Gsect_root = NULL;	/* root of tree of global psects */
WORD 		Maxabs = 0;		/* maximum size of absolute files,
					** also low limit of relocatable code */
WORD	R_counter;			/* relocation counter, used in 
					** assigning relocation constants,
					** also high limit of relocatable
					** code after relocation */
long		Seekoff;		/* offset for seeking in out file */
char		Do_410 = 0;		/* boolean for out file format */
int		Verbose	=0;		/* Boolean for verbose commentary */
char		Do_411 = 0;		/* boolean for out file format */
char		Do_map = 0;		/* boolean for printing load map */
char		Do_lpr_map = 0;		/* boolean for line printing map */
char		Do_bits = 0;		/* boolean for including relocation 
					** bits in .out file */ 
char		C_rel = 0;		/* boolean for having out file end
					** with '.o' */
char		Do_kludge = 0;		/* boolean for writing global sybmbols
					** in the out file with a preceding
					** underscore character */
char		Do_silent = 0;		/* boolean for not printing zero
					** errors message */
char		Do_table = 1;		/* boolean for including symbol table
					** in out file */
char		No_locals = 0;		/* boolean for not including local
					** symbols in the out table */
char		Do_odt = 0;		/* boolean for including odt module */
WORD		Transadd = 1;		/* transfer address */
struct objfile  *Transfile;		/* object file of transfer address */
char		Transsect[7];		/* program section of trans address */
WORD Tex_size;				/* for out file */
WORD Dat_size;				/* for out file */
WORD Bss_size;				/* for out file */
char		*Outbase;		/* out file name without '.out' */
char		*Outname = NULL;	/* name of out file */
char 		*Mapname;		/* name of map file */
FILE		*Mapp = NULL;		/* pointer for map file */
char		Erstring[80];		/* buffer for error messages */
int		Nerrors = 0;		/* the number of user errors */
char		No_out = 0;		/* boolean for no out file */
char		Scanerr = 0;		/* boolean for error in arguments */

/**********************  main  ********************************************/


main(argc, argv)
int	argc;
char	*argv[];
{
	scanargs(argc, argv);
	pass1();
	relocate();
	relsyms(Sym_root);
	post_bail();
	if (Do_map)
		printmap();
	if (No_out)
		exit(0);
	warmup();
	pass2();
	loose_ends();
}


/*********************  scanargs  ******************************************/


scanargs(argc, argv)
int	argc;
char	*argv[];
{
	register char			*s;
	char				*r;
	register struct objfile		*end;	/* last file in link-list */

	struct objfile			*newfile();	/* allocaters */

	while (--argc)
	{
		s = *++argv;
		if (*s == '-')
		{
			s++;
			if ((r = strsub(s, "na:")) != NULL)
				Outname = tack(r, ".out");
			else if (!strcmp(s, "ls") || !strcmp(s, "mp"))
				Do_map = 1;
			else if (!strcmp(s, "lp"))
				Do_map = Do_lpr_map = 1;
			else if (!strcmp(s, "od"))
				Do_odt = 1;
			else if (!strcmp(s, "r"))
				Do_bits = 1;
			else if (!strcmp(s, "c"))
				Do_bits = C_rel = 1;
			else if (!strcmp(s, "K"))
				Do_bits = C_rel = Do_kludge = 1;
			else if (!strcmp(s, ""))
				Do_silent = 1;
			else if (!strcmp(s, "ns"))
				Do_table = 0;
			else if (!strcmp(s, "go"))
				No_locals = 1;
			else if (!strcmp(s, "no"))
				No_out = 1;
			else if (!strcmp(s, "n"))
				Do_410 = 1;
			else if (!strcmp(s, "i"))
				Do_411 = 1;
			else if(!strcmp(s, "v"))
				Verbose = 1;
			else 
			{
				fprintf(stderr, "Unrecognizable argument: -%s\n", s);
				Scanerr = 1;
			}
		}
		else
		{
			if (File_root == NULL)
				end = File_root = newfile();
			else
			{
				end->nextfile = newfile();
				end = end->nextfile;
			}
			s = tack(s, ".obj");
			end->fname = s;		
		}
	}

	if (File_root == NULL)	
	{
		fprintf(stderr, "Error: no object files given\n");
		exit(1);
	}

	if (Do_odt)
	{
		end->nextfile = newfile();
		end->nextfile->fname = "/usr/lib/odt.obj";
	}

	if (Scanerr)
		exit(1);
	outnames();
}


/***************************  strsub  ***************************************/


char	*strsub(s, t)	/* if t is the initial part of s then return a pointer
			** to the rest of s, else return NULL */
register char 	*s;
register char	*t;
{
	register char *q;
	
	q = t;
	while (*t)
		if (*s++ != *t++)
			return (NULL);

	if (*s == '\0')	/* check for no filename */
	{
		fprintf(stderr, "Argument error: a filename should be contiguous with -%s\n", q);
		Scanerr = 1;
		return(NULL);
	}
	else
		return (s);
}


/****************************  outnames  ************************************/


outnames()	/* determine names of output files */

{
	if (Outname == NULL)
	{
		Outbase = lalloc(strlen(File_root->fname) + 1);
		strcpy(Outbase, File_root->fname);
		strip(Outbase, ".obj");
	}
	else
	{
		Outbase = lalloc(strlen(Outname) + 5);
		strcpy(Outbase, Outname);
		strip(Outbase, ".out");
		strip(Outbase, ".o");
	}

	if (C_rel)
		Outname = tack(Outbase, ".o");
	else
		Outname = tack(Outbase, ".out");

	if (Do_map)
		Mapname = tack(Outbase, ".map");
}


/***************************  newpsect  ************************************/


struct psect	*newpsect()	/* allocate and initialize a new psect
				** structure */
{
	register struct psect	*p;

	p = (struct psect *) lalloc(sizeof (struct psect));
	p->next = p->pssame = p->obsame = NULL;
	p->slist = NULL;
	return (p);
}


/***********************  newsymbol  ***************************************/


struct symbol	*newsymbol()	/* allocate and initialize new symbol 
				** structure */
{
	register struct symbol	*p;

	p = (struct symbol *) lalloc(sizeof (struct symbol));
	p->prsect = (struct psect *)NULL;
	p->right = p->left = (struct symbol *)NULL;
	return (p);
}


/**********************  newfile  ******************************************/


struct objfile	*newfile()	/* allocate and initialize new psect 
				** structure */
{
	register struct objfile		*p;

	p = (struct objfile *) lalloc(sizeof (struct objfile));
	p->nextfile = NULL;
	p->psect_list = NULL;
	p->ver_id = NULL;
	return (p);
}


/****************************  new_gsect  ***********************************/


struct g_sect	*new_gsect()

{
	register struct g_sect	*p;

	p = (struct g_sect *) lalloc(sizeof(struct g_sect));
	p->leftt = p->rightt = NULL;
	return (p);
}


/*********************  pass1  *********************************************/


pass1()

{
	char			name[7];	/* string from M11 */
	char			attr;		/* attribute from M11 */
	register int		type;		/* type of string */
	int			value;		/* from M11 */
	register struct objfile *of;		/* current object file */
	register struct psect	*ps;		/* current psect */
	struct symbol		*sym;		/* current and last symbol
						** in symbol list */
	struct symbol		**nextsym;	/* pointer to pointer which
						** should point to next symbol
						** in the psect list */
	struct psect		*newpsect();
	struct symbol		*newsymbol();

	of = File_root;
	while (of != NULL)
	{
		ch_input(of->fname, HEADER);	/* change input */

		while(morebytes())
		{
			dc_symbol(name);
			attr = getbyte();
			type = getbyte();
			value = getword();
			switch(type)
			{
			  case 0:	/* program name */
				strcpy(of->pname, name);
				break;

			  case 1:	/* program section */
			  case 5:	/* program section */
			  if(Verbose)
				fprintf(stderr,"gsd%d <%6s> %o\n",
					type, name, attr);

				/* increment size if odd */
				value += (value % 2) ? 1 : 0;
				/* place psect at end of link-list for objfile */
				if (of->psect_list == NULL)
					ps = of->psect_list = newpsect();
				else
				{
					ps->obsame = newpsect();
					ps = ps->obsame;
				}
				strcpy(ps->name, name);
				if (Do_410)
					/* if the psect is sharable and data
					** make it instruction, this is an old
					** L11 kludge. */
					{
					if ((attr & SHR) && !(attr & (INS | BSS)))
						ps->type = attr | INS;
					else
						ps->type = attr;
					}
				else
					ps->type = attr;
				ps->nbytes = value;
				nextsym = &(ps->slist);

				if (!(attr & REL))	/* if psect is absolute */
				{
					ps->rc = 0;
					Maxabs = (value > Maxabs) ? value : Maxabs;
				}
					/* else put psect in proper ins-dat-bss
					** link-list */
				else
					place_global(ps);
				break;

			  case 2:	/* this case has not been observed
					** and is assumed to be un-used */
				lerror("internal symbol table");
				break;

			  case 3:	/* transfer address */
				if (value == 1)		/* if 1 bogus */
					break;
				if (Transadd != 1)	/* transfer address
							** already specified */
					fprintf(stderr, "Warning: more than \
						one transfer address specified\n");
				Transadd = value;
				Transfile = of;
				strcpy(Transsect, name);
				break;

			  case 4:	/* global symbol */
				/* make structure and place in obj file list */
				sym = newsymbol();
				sym->prsect = ps;
				strcpy(sym->name, name);
				sym->type = attr;
				sym->value = value;
				if (attr & DEF)	/* if the symbol is defined, 
						** place in link-list of
						** symbols */
				{
					*nextsym = sym;
					nextsym = &(sym->symlist);
				}
				/* place in symbol table */
				table(&Sym_root, sym);
				break;

			  case 6:	/* version identification */
				of->ver_id = lalloc(7);
				strcpy(of->ver_id, name);
				break;

			  default:
				lerror("header type out of range");
			}
		}
		of = of->nextfile;
	}
}


/*****************************  place_global  ******************************/


place_global(ps)		/* try to place the given program section
				** in proper ins - dat - bss link-list by
				** finding it in the global psect tree. if 
				** it is not there then add to tree and place
				** it through place_local */
register struct psect	*ps;
{
	register struct	g_sect 	**ptr;
	register int		cond;

	ptr = &Gsect_root;
	while (*ptr != NULL)
	{
		if ( !(cond = strcmp(ps->name, (*ptr)->name)))
		{
			if (ps->type != (*ptr)->type)
			{
				fprintf(stderr, "psect <%6s> attribute clash: ", ps->name);
				fprintf(stderr, " already has %3o, now declared %3o.  Using %3o\n", 0377 & (*ptr)->type, 0377 & ps->type, 0377 & (*ptr)->type);
				ps->type = (*ptr)->type;
			}
			/* place psect in list of sames */
			(*ptr)->last_sect->pssame = ps;
			(*ptr)->last_sect = ps;
			return;
		}
		else if (cond < 0)
			ptr = &((*ptr)->leftt);
		else
			ptr = &((*ptr)->rightt);
	}

	/* global section cannot be found in tree so make a new node for
	** it and place it as a local */

	*ptr = new_gsect();
	strcpy((*ptr)->name, ps->name);
	(*ptr)->type = ps->type;
	(*ptr)->last_sect = ps;
	place_local(ps);
}


/*************************  place_local  *******************************/


place_local(ps)			/* place psect at end of its UNIX section
				** type link-list */
register struct psect	*ps;
{
	register type = ps->type;
	
	if( !(type & REL))		/* asect */
	{
		fprintf(stderr, "Don't know what to do with .asect yet\n");
	}
	if (type & INS)	/* instruction psect */
	{
		if (Tex_root == NULL)
			Tex_root = Tex_end = ps;
		else
		{
			Tex_end->next = ps;
			Tex_end = ps;
		}
	}
	else if (type & BSS)	/* bss psect */
	{
		if (Bss_root == NULL)
			Bss_root = Bss_end = ps;
		else 
		{
			Bss_end->next = ps;
			Bss_end = ps;
		}
	}
	else				/* data psect */
	{
		if (Dat_root == NULL)
			Dat_root = Dat_end = ps;
		else
		{
			Dat_end->next = ps;
			Dat_end = ps;
		}
	}
}


/*************************  table  **************************************/


table(root, new)	/* place new symbol structure in symbol table tree */

register struct symbol	*root[];	/* pointer to root pointer of tree */
register struct symbol	*new;		/* pointer to symbol (structure) to
					** be added */
{
	register int	cond;

	for (;;)	/* repeat until break */
	{
		if (*root == NULL)	/* empty tree */
		{
			/* set root, return */
			*root = new;
			return;
		}
		/* check for same name */
		else if ((cond = strcmp(new->name, (*root)->name)) == 0)
		{
			/* new symbol and one in table have same name */
			if (new->type & DEF)	/* ignore new if undefined */
			{
				if (isdef(*root))    /* both defined */
				{
					if(isabs(*root) && (new->value ==
						(*root)->value))
						fprintf(stderr, "Warning: abs sym %s defined as %06o twice\n", new->name, new->value);
					else {

					sprintf(Erstring, "%s defined twice", new->name);
					uerror(Erstring);
					}
				}
				/* else	/* get rid of old undefined symbol */
				{
					new->left = (*root)->left;
					new->right = (*root)->right;
					*root = new;
				}
			}
			return;
		}
		/* else branch */
		else if (cond < 0)
			root = &((*root)->left);
		else
			root = &((*root)->right);
	}
}


/*****************************  relocate  ********************************/


# define	_8K	020000


relocate()	/* assign relocation constants for all relocatable psects */

{
	register unsigned temp;
	struct outword	trans_rc;

	R_counter = Maxabs;	/* set relocation counter to follow
				** absolute sections */
	asgn_rcs(Tex_root);
	/* text size = absolute and ins psects */
	Tex_size = R_counter;

	if (Do_410)
	{
		temp = Tex_size + _8K;
		temp &= ~(_8K - 1);
		R_counter = temp;

		Seekoff = (long) Tex_size - (long )R_counter;
	}
	else if (Do_411)
	{
		R_counter = temp = 0;
		Seekoff = Tex_size;
	}
	else
	{
		temp = Tex_size;
		Seekoff = 0;
	}

	asgn_rcs(Dat_root);
	Dat_size = (int)R_counter - (int)temp;
	temp = R_counter;

	asgn_rcs(Bss_root);
	Bss_size = (int)R_counter - (int)temp;

	/* relocate transfer address if defined */
	if (Transadd != 1)	/* if defined */
	{
		get_rc(&trans_rc, Transfile, Transsect);
		Transadd += trans_rc.val;
	}

	if (Do_bits && Maxabs)
	{
		uerror("absolute section present - relocation bits suppressed");
		Do_bits = 0;
	}
}


/***************************  asgn_rcs  ************************************/



asgn_rcs(p)	/* assign relocation constants to
		** the psects pointed to.  this routine uses the
		** variable R_counter which contains the address of the 
		** next available space in memory */
register struct psect 	*p;	/* called with ins-dat-bss root */

{
	register int		size;	/* addendum to R_counter */
	register struct psect 	*d;	/* temporary pointer used to access
					** same psects */
	for (;;)	/* repeat until break */
	{
		if (p == NULL)	/* end of list, break */
			break;

		/* set relocation constant to R_counter */
		p->rc = R_counter;

		/* set size initially to size of psect.  size is not added
		** to R_counter at this point because of the possibility
		** that the psect is part of a group of overlaid psects */

		size = p->nbytes;

		/* check for same psect(s) */
		if (p->pssame != NULL)
		{
			/* set d to same psect */
			d = p;

			if (p->type & OVR)	/* if the sames are overlaid */
				/* travel through sames.
				** set the rc's of all sames to R_counter.
				** size equals maximum psect size */
				do
				{
					d = d->pssame;
					d->rc = R_counter;
					size = (size > d->nbytes) ? size : d->nbytes;
				} while (d->pssame != NULL);

			else		/* sames are concatenated */
				/* travel through sames 
				** add size to R_counter before assigning
				** to rc for each psect.
				** redefine size as number of bytes in psect */
				do
				{
					d = d->pssame;
					d->rc = (R_counter += size);
					size = d->nbytes;
				} while (d->pssame != NULL);

			R_counter += size;

			/* insert a psect structure at bottom of sames list to
			** to facilitate '^p' M11 directives */

			d->pssame = newpsect();
			d = d->pssame;
			d->rc = p->rc;
			d->type = p->type;
			d->nbytes = R_counter - p->rc;
		}
		else
			R_counter += size;
		p = p->next;
	}
}


/*************************  relsyms  **************************************/


relsyms(sym)		/* relocate global symbols */

register struct symbol	*sym;	
{
	if (sym == NULL)
		return;
	sym->value += sym->prsect->rc;
	relsyms(sym->left);
	relsyms(sym->right);
}


/*************************  printmap  ***********************************/


printmap()
{
	register struct objfile	*op;
	register struct psect 	*pp;
	int			tvec[2];	/* time vector */
	static char		dashes[] = "----------------";

	Mapp = fopen(Mapname, "w");
	if (Mapp == NULL)
		fprintf(stderr, "%s not accessible\n", Mapname);
	else
	{
		long datstart = Tex_size;
		
		if(Do_411) datstart = 0L;
		
		/* print map header */
		time(tvec);
		fprintf(Mapp, "%s    Linker-11 version 22may79    %s\n", Outname, ctime(tvec));
		fprintf(Mapp, "Magic number:     %o\t",
				Do_410 ? 0410 : ( Do_411 ? 0411 : 0407) );
		if(Do_410) fprintf(Mapp, "(Shared text)\n");
		else if (Do_411) fprintf(Mapp,"(Separate I & D)\n");
		else fprintf(Mapp, "(Executable)\n");
		fprintf(Mapp, "\tStart\tLimit\tLength\n");
		brag("Text", 0L, (long)Tex_size, (Do_410 || Do_411)?"Shareable" : "");
		brag("Data", datstart, (long)Dat_size,  "");
		brag("Bss", (long)(datstart+Dat_size), (long)Bss_size,  "");
		fprintf(Mapp, "transfer address: %06o\n", Transadd);

		for (op = File_root; op != NULL; op = op->nextfile)
		{
			fprintf(Mapp, "%s\n", dashes);
			fprintf(Mapp, "module:  %s", op->pname);
			if (op->ver_id != NULL)
				fprintf(Mapp, "    %s", op->ver_id);
			fprintf(Mapp, "\nsection          orgin      size\n");
			pp = op->psect_list;
			while (pp != NULL)
			{
				fprintf(Mapp, "<%s>        ", pp->name);
				fprintf(Mapp, "%06o     %06o", pp->rc, pp->nbytes);
				prattr(pp->type);
				dump_symlist(pp->slist);
				pp = pp->obsame;
			}
		}
		fprintf(Mapp, "%s", dashes);	
		if (dump_undefs(Sym_root, 0))
			fprintf(Mapp, "\n%s\n", dashes);
		else
			fprintf(Mapp, "\n");
	}
}

brag(s, start, size, tag)
	char *s;
	long start, size;
	char *tag;
{
	long stop = 0177777 & (size + start);

	fprintf(Mapp, "%s:\t%06O\t%06O\t%06O\t%s\n", s, start, stop, size, tag);
}

prattr(x)
{
	fprintf(Mapp, "\t");
	attr(x&SHR, "shr, ", "prv, ");
	attr(x&INS, "ins, ", "");
	attr(x&BSS, "bss, ", "");
	attr( !((x&BSS) || (x&INS)), "dat,", "");
	attr(x&REL, "rel, ", "abs, ");
	attr(x&OVR,"ovr, ", "con, ");
	attr(x&GBL,"gbl", "loc");
}
attr(x, s, t)
	register x;
	register char *s, *t;
{
	if(x) fprintf(Mapp, s);
	else  fprintf(Mapp, t);
}
/*****************************  dump_symlist  *******************************/


dump_symlist(sym)	/* write to the map file the symbol list for a psect */
register struct symbol	*sym;
{
	register int	i;

	for (i = 0; sym != NULL; sym = sym->symlist)
	{
		fprintf(Mapp, "%s     ", (i++ % 3) ? "" : "\n     ");
		fprintf(Mapp, "%s %06o", sym->name, sym->value);
		fprintf(Mapp, " %c", (sym->type & REL) ? 'r' :'a');
	}
	fprintf(Mapp, "\n");
}


/*****************************  dump_undefs  *******************************/


dump_undefs(sym, n)	/* dump into map file all undefined global symbols */
struct symbol	*sym;
int		n;
{
	if (sym == NULL)
		return (n);
	n = dump_undefs(sym->left, n);
	if ( !(sym->type & DEF))
	{
		fprintf(Mapp, "%s     ", (n++ % 3) ? "" : "\n     ");
		fprintf(Mapp, "%s ****** u", sym->name);
	}
	n = dump_undefs(sym->right, n);
	return (n);
}


/**************************  post_bail  *************************************/

extern	bail_out();

post_bail()	/* set interrupt routine to bail_out */

{
	sigx(1);
	sigx(2);
	sigx(3);
	sigx(15);
}
sigx(n)
{
	if(signal(n, SIG_IGN) != SIG_IGN)
		signal(n, bail_out);
}