xref: /csrg-svn/old/as.vax/assyms.c (revision 12592)
15828Srrh /*
25828Srrh  *	Copyright (c) 1982 Regents of the University of California
35828Srrh  */
45828Srrh #ifndef lint
5*12592Scsvaf static char sccsid[] = "@(#)assyms.c 4.8 05/19/83";
65828Srrh #endif not lint
75828Srrh 
8600Sbill #include <stdio.h>
9600Sbill #include <ctype.h>
10600Sbill #include "as.h"
11600Sbill #include "asscan.h"
12600Sbill #include "assyms.h"
13600Sbill 
14600Sbill /*
15600Sbill  *	Managers for chunks of symbols allocated from calloc()
16600Sbill  *	We maintain a linked list of such chunks.
17600Sbill  *
18600Sbill  */
19600Sbill struct	allocbox	*allochead;	/*head of chunk list*/
20600Sbill struct	allocbox	*alloctail;	/*tail*/
21600Sbill struct	allocbox	*newbox;	/*for creating a new chunk*/
22600Sbill struct	symtab		*nextsym;	/*next symbol free*/
23600Sbill int			symsleft;	/*slots left in current chunk*/
24600Sbill 
25600Sbill struct	symtab		**symptrs;
26600Sbill struct	symtab		**symdelim[NLOC + NLOC +1];
27600Sbill struct	symtab		**symptrub;
28600Sbill /*
29600Sbill  *	Managers for the dynamically extendable hash table
30600Sbill  */
31600Sbill struct	hashdallop	*htab;
32600Sbill 
335828Srrh Iptr	*itab[NINST];	/*maps opcodes to instructions*/
34600Sbill /*
35600Sbill  *	Counts what went into the symbol table, so that the
36600Sbill  *	size of the symbol table can be computed.
37600Sbill  */
38600Sbill int	nsyms;		/* total number in the symbol table */
39600Sbill int	njxxx;		/* number of jxxx entrys */
40600Sbill int	nforgotten;	/* number of symbols erroneously entered */
41600Sbill int	nlabels;	/* number of label entries */
42600Sbill 
43600Sbill /*
44600Sbill  *	Managers of the symbol literal storage.
45600Sbill  *	If we have flexible names, then we allocate BUFSIZ long
46600Sbill  *	string, and pack strings into that.  Otherwise, we allocate
47600Sbill  *	symbol storage in fixed hunks NCPS long when we allocate space
48600Sbill  *	for other symbol attributes.
49600Sbill  */
50600Sbill #ifdef	FLEXNAMES
51600Sbill struct	strpool		*strplhead = 0;
52634Shenry #endif	FLEXNAMES
53600Sbill 
54600Sbill symtabinit()
55600Sbill {
56600Sbill 	allochead = 0;
57600Sbill 	alloctail = 0;
58600Sbill 	nextsym = 0;
59600Sbill 	symsleft = 0;
60600Sbill #ifdef FLEXNAMES
61600Sbill 	strpoolalloc();		/* get the first strpool storage area */
62600Sbill #endif FLEXNAMES
63600Sbill 	htab = 0;
64600Sbill 	htaballoc();		/* get the first part of the hash table */
65600Sbill }
66600Sbill 
67600Sbill /*
68600Sbill  *	Install all known instructions in the symbol table
69600Sbill  */
70600Sbill syminstall()
71600Sbill {
725828Srrh 	register	Iptr	ip;
73600Sbill 	register	struct	symtab	**hp;
74600Sbill 	register	char	*p1, *p2;
755828Srrh 	register	int	i;
76600Sbill 
775828Srrh 	for (i = 0; i < NINST; i++)
785828Srrh 		itab[i] = (Iptr*)BADPOINT;
795828Srrh 
80634Shenry #ifdef FLEXNAMES
815828Srrh 	for (ip = (Iptr)instab; ip->s_name != 0; ip++) {
82634Shenry #else not FLEXNAMES
835828Srrh 	for (ip = (Iptr)instab; ip->s_name[0] != '\0'; ip++){
84634Shenry #endif not FLEXNAMES
85634Shenry 		p1 = ip->s_name;
86600Sbill 		p2 = yytext;
87600Sbill 		while (*p2++ = *p1++);
88600Sbill 		hp = lookup(0);		/* 0 => don't install this*/
89600Sbill 		if (*hp==NULL) {
90600Sbill 			*hp = (struct symtab *)ip;
91634Shenry 			if (   (ip->s_tag!=INSTn)
92634Shenry 			    && (ip->s_tag!=INST0)
93634Shenry 			    && (ip->s_tag!=0))
94600Sbill 				continue; /* was pseudo-op */
955828Srrh 			if (itab[ip->i_eopcode] == (Iptr*)BADPOINT){
965828Srrh 				itab[ip->i_eopcode] =
975828Srrh 					(Iptr*)ClearCalloc(256, sizeof(Iptr));
985828Srrh 				for (i = 0; i < 256; i++)
995828Srrh 					itab[ip->i_eopcode][i] =
1005828Srrh 						(Iptr)BADPOINT;
1015828Srrh 			}
1025828Srrh 			itab[ip->i_eopcode][ip->i_popcode] = ip;
103600Sbill 		}
104600Sbill 	}
105600Sbill }	/*end of syminstall*/
106600Sbill 
107600Sbill 
108600Sbill /*
109600Sbill  *	Assign final values to symbols,
110600Sbill  *	and overwrite the index field with its relative position in
111600Sbill  *	the symbol table we give to the loader.
112600Sbill  */
113600Sbill extern struct exec hdr;
114600Sbill 
115600Sbill freezesymtab()
116600Sbill {
117600Sbill 	register	struct	symtab	*sp;
118600Sbill 				long	bs;
119600Sbill 	register	int	relpos = 0;
120600Sbill 	register	struct	symtab		*ubsp;
121600Sbill 	register	struct	allocbox	*allocwalk;
122600Sbill 
123600Sbill 	DECLITERATE(allocwalk, sp, ubsp)
124600Sbill 	{
125634Shenry 		if (sp->s_tag >= IGNOREBOUND)
126600Sbill 			continue; 		/*totally ignore jxxx entries */
127600Sbill 		/*
128600Sbill 		 *	Ignore stabs, but give them a symbol table index
129600Sbill 		 */
130634Shenry 		if (sp->s_type & STABFLAG)
131600Sbill 			goto assignindex;
132634Shenry 		if ((sp->s_type&XTYPE)==XUNDEF)
133634Shenry 			sp->s_type = XXTRN+XUNDEF;
134634Shenry 		else if ((sp->s_type&XTYPE)==XDATA)
135634Shenry 			sp->s_value += usedot[sp->s_index].e_xvalue;
136634Shenry 		else if ((sp->s_type&XTYPE)==XTEXT)
137634Shenry 			sp->s_value += usedot[sp->s_index].e_xvalue;
138634Shenry 		else if ((sp->s_type&XTYPE)==XBSS) {
139634Shenry 			bs = sp->s_value;
140634Shenry 			sp->s_value = hdr.a_bss + datbase;
141600Sbill 			hdr.a_bss += bs;
142600Sbill 		}
143600Sbill 	   assignindex:
144634Shenry 		if (    (sp->s_name[0] != 'L')
145634Shenry 		     || (sp->s_tag != LABELID)
146600Sbill 		     || savelabels
147600Sbill 		     )			/*then, we will write it later on*/
148634Shenry 				sp->s_index = relpos++;
149600Sbill 	}
150600Sbill }
151600Sbill 
152600Sbill 
153600Sbill 
154600Sbill /*
155600Sbill  *	For all of the stabs that had their final value undefined during pass 1
156600Sbill  *	and during pass 2 assign a final value.
157600Sbill  *	We have already given stab entrys a initial approximation
158600Sbill  *	when we constsructed the sorted symbol table.
159600Sbill  *	Iteration order doesn't matter.
160600Sbill  */
161*12592Scsvaf 
162*12592Scsvaf stabfix()
163*12592Scsvaf {
164600Sbill 	register struct symtab *sp, **cosp;
165600Sbill 	register struct symtab *p;
166600Sbill 
167600Sbill 	SYMITERATE(cosp, sp){
168634Shenry 		if(sp->s_ptype && (sp->s_type & STABFLAG)) {
169634Shenry 			p = sp->s_dest;
170*12592Scsvaf /*
171*12592Scsvaf  * STABFLOATING indicates that the offset has been saved in s_desc, s_other
172*12592Scsvaf  */
173*12592Scsvaf 			if(sp->s_tag == STABFLOATING) {
174*12592Scsvaf 			  sp->s_value = ( ( ((unsigned char) sp->s_other) << 16)  					| ( (unsigned short) sp->s_desc )  );
175*12592Scsvaf 			  sp->s_value = sp->s_value + p->s_value;
176*12592Scsvaf 			}
177*12592Scsvaf 			else sp->s_value = p->s_value;
178634Shenry 			sp->s_index = p->s_index;
179634Shenry 			sp->s_type = p->s_type;
180*12592Scsvaf 
181*12592Scsvaf 
182600Sbill 		}
183600Sbill 	}
184600Sbill }
185600Sbill 
186600Sbill char *Calloc(number, size)
187600Sbill 	int	number, size;
188600Sbill {
189600Sbill 	register	char *newstuff;
1905828Srrh 	char	*sbrk();
1915828Srrh 	newstuff = sbrk(number*size);
192600Sbill 	if ((int)newstuff == -1){
193600Sbill 		yyerror("Ran out of Memory");
194600Sbill 		delexit();
195600Sbill 	}
196600Sbill 	return(newstuff);
197600Sbill }
198600Sbill 
199600Sbill char *ClearCalloc(number, size)
200600Sbill 	int	number, size;
201600Sbill {
202600Sbill 	register	char	*newstuff;		/* r11 */
203600Sbill 	register	int	length = number * size;	/* r10 */
2045828Srrh #ifdef lint
2055828Srrh 	length = length;
2065828Srrh #endif length
207600Sbill 	newstuff = Calloc(number, size);
208600Sbill 	asm("movc5 $0, (r0), $0, r10, (r11)");
209600Sbill 	return(newstuff);
210600Sbill }
211600Sbill 
212600Sbill struct symtab *symalloc()
213600Sbill {
214600Sbill 	if (symsleft == 0){
215600Sbill 		newbox = (struct allocbox *)ClearCalloc(1,ALLOCQTY);
216600Sbill 		symsleft = SYMDALLOP;
217600Sbill 		nextsym = &newbox->symslots[0];
218600Sbill 		if (alloctail == 0){
219600Sbill 			allochead = alloctail = newbox;
220600Sbill 		} else {
221600Sbill 			alloctail->nextalloc = newbox;
222600Sbill 			alloctail = newbox;
223600Sbill 		}
224600Sbill 	}
225600Sbill 	--symsleft;
226600Sbill 	++nsyms;
227600Sbill 	return(nextsym++);
228600Sbill }
229600Sbill 
230600Sbill #ifdef FLEXNAMES
231600Sbill strpoolalloc()
232600Sbill {
233600Sbill 	register	struct	strpool	*new;
234600Sbill 
235600Sbill 	new = (struct strpool *)Calloc(1, sizeof (struct strpool));
236600Sbill 	new->str_nalloc = 0;
237600Sbill 	new->str_next = strplhead;
238600Sbill 	strplhead = new;
239600Sbill }
240600Sbill #endif FLEXNAMES
241600Sbill 
242600Sbill symcmp(Pptr, Qptr)
243600Sbill 	struct symtab **Pptr, **Qptr;
244600Sbill {
245600Sbill 	register struct symtab *p = *Pptr;
246600Sbill 	register struct symtab *q = *Qptr;
247634Shenry 	if (p->s_index < q->s_index)
248600Sbill 		return(-1);
249634Shenry 	if (p->s_index > q->s_index)
250600Sbill 		return(1);
251634Shenry 	if (p->s_value < q->s_value)
252600Sbill 		return(-1);
253634Shenry 	if (p->s_value > q->s_value)
254600Sbill 		return(1);
255600Sbill 	/*
256600Sbill 	 *	Force jxxx entries to virtually preceed labels defined
257600Sbill 	 *	to follow the jxxxx instruction, so that bumping the
258600Sbill 	 *	jxxx instruction correctly fixes up the following labels
259600Sbill 	 */
260634Shenry 	if (p->s_tag >= IGNOREBOUND)	/*p points to a jxxx*/
261600Sbill 		return(-1);
262634Shenry 	if (q->s_tag >= IGNOREBOUND)
263600Sbill 		return(1);
264600Sbill 	/*
265600Sbill 	 *	both are now just plain labels; the relative order doesn't
266600Sbill 	 *	matter.  Both can't be jxxxes, as they would have different
267600Sbill 	 *	values.
268600Sbill 	 */
269600Sbill 	return(0);
270600Sbill }	/*end of symcmp*/
271600Sbill 
272600Sbill /*
273600Sbill  *	We construct the auxiliary table of pointers, symptrs and
274600Sbill  *	symdelim
275600Sbill  *	We also assign preliminary values to stab entries that did not yet
276600Sbill  *	have an absolute value (because they initially referred to
277600Sbill  *	forward references). We don't worry about .stabds, as they
278600Sbill  *	already have an estimated final value
279600Sbill  */
280600Sbill 
281600Sbill sortsymtab()
282600Sbill {
283600Sbill 	register	struct	symtab	*sp;
284600Sbill 	register	struct	symtab	**cowalk;
285600Sbill 	register	struct	allocbox	*allocwalk;
286600Sbill 			struct	symtab	*ubsp;
287600Sbill 				int	segno;
288600Sbill 				int	slotno;
289600Sbill 				int	symsin;	/*number put into symptrs*/
290600Sbill 
291600Sbill 	symptrs =  (struct symtab **)Calloc(nsyms + 2, sizeof *symptrs);
292600Sbill 	/*
293600Sbill 	 *	Allocate one word at the beginning of the symptr array
294600Sbill 	 *	so that backwards scans through the symptr array will
295600Sbill 	 *	work correctly while scanning through the zeroth segment
296600Sbill 	 */
297600Sbill 	*symptrs++ = 0;
298600Sbill 	cowalk = symptrs;
299600Sbill 	symsin = 0;
300600Sbill 	DECLITERATE(allocwalk, sp, ubsp) {
301634Shenry 		if (sp->s_ptype && (sp->s_type &STABFLAG)){
302634Shenry 			sp->s_value = sp->s_dest->s_value;
303634Shenry 			sp->s_index = sp->s_dest->s_index;
304600Sbill 		}
305600Sbill 		if (symsin >= nsyms)
306600Sbill 			yyerror("INTERNAL ERROR: overfilled symbol table indirection table");
307600Sbill 		*cowalk++ = sp;
308600Sbill 		symsin++;
309600Sbill 	}
310600Sbill 	if (symsin != nsyms)
311600Sbill 		yyerror("INTERNAL ERROR: installed %d syms, should have installed %d",
312600Sbill 			symsin, nsyms);
313600Sbill 	symptrub = &symptrs[nsyms ];
314600Sbill 	qsort(symptrs, nsyms, sizeof *symptrs, symcmp);
315600Sbill 	symdelim[0] = symptrs;
316600Sbill 	for (cowalk = symptrs, sp = *cowalk, segno = 0, slotno = 1;
317600Sbill 	     segno < NLOC + NLOC;
318600Sbill 	     segno++, slotno++){
319634Shenry 		for (; sp && sp->s_index == segno; sp = *++cowalk);
320600Sbill 		symdelim[slotno] = cowalk;	/*forms the ub delimeter*/
321600Sbill 	}
322600Sbill }	/*end of sortsymtab*/
323600Sbill 
324600Sbill #ifdef DEBUG
325600Sbill dumpsymtab()
326600Sbill {
327600Sbill 	register	int	segno;
328600Sbill 	register	struct symtab *sp, **cosp, *ub;
329600Sbill 	char		*tagstring();
330600Sbill 
331600Sbill 	printf("Symbol Table dump:\n");
332600Sbill 	for (segno = 0; segno < NLOC + NLOC; segno++){
333600Sbill 		printf("Segment number: %d\n", segno);
334600Sbill 		SEGITERATE(segno, 0, 0, cosp, sp, ub, ++){
335600Sbill #ifdef FLEXNAMES
336600Sbill 			printf("\tSeg: %d \"%s\" value: %d index: %d tag %s\n",
337634Shenry 				segno, sp->s_name,
338634Shenry 				sp->s_value, sp->s_index,
339634Shenry 				tagstring(sp->s_tag));
340600Sbill #else not FLEXNAMES
341600Sbill 			printf("\tSeg: %d \"%*.*s\" value: %d index: %d tag %s\n",
342634Shenry 				segno, NCPS, NCPS, sp->s_name,
343634Shenry 				sp->s_value, sp->s_index,
344634Shenry 				tagstring(sp->s_tag));
345600Sbill #endif not FLEXNAMES
346600Sbill 			printf("\t\ttype: %d jxbump %d jxfear: %d\n",
347634Shenry 				sp->s_type, sp->s_jxbump, sp->s_jxfear);
348600Sbill 		}
349600Sbill 		printf("\n\n");
350600Sbill 	}
351600Sbill }
352600Sbill 
353600Sbill static	char tagbuff[4];
354600Sbill 
355600Sbill char *tagstring(tag)
356600Sbill 	unsigned	char	tag;
357600Sbill {
358600Sbill 	switch(tag){
359600Sbill 		case JXACTIVE:		return("active");
360600Sbill 		case JXNOTYET:		return("notyet");
361600Sbill 		case JXALIGN:		return("align");
362600Sbill 		case JXQUESTIONABLE:	return("jxquestionable");
363600Sbill 		case JXINACTIVE:	return("inactive");
364600Sbill 		case JXTUNNEL:		return("tunnel");
365600Sbill 		case OBSOLETE:		return("obsolete");
366600Sbill 		case IGNOREBOUND:	return("ignorebound");
367600Sbill 		case STABFLOATING:	return("stabfloating");
368600Sbill 		case STABFIXED:		return("stabfixed");
369600Sbill 		case LABELID:		return("labelid");
370600Sbill 		case OKTOBUMP:		return("oktobump");
371600Sbill 		case ISET:		return("iset");
372600Sbill 		case ILSYM:		return("ilsym");
373600Sbill 		default:		sprintf(tagbuff,"%d", tag);
374600Sbill 					return(tagbuff);
375600Sbill 	}
376600Sbill }
377600Sbill #endif DEBUG
378600Sbill 
379600Sbill htaballoc()
380600Sbill {
381600Sbill 	register	struct	hashdallop	*new;
382600Sbill 	new = (struct hashdallop *)ClearCalloc(1, sizeof (struct hashdallop));
383600Sbill 	if (htab == 0)
384600Sbill 		htab = new;
385600Sbill 	else {		/* add AFTER the 1st slot */
386600Sbill 		new->h_next = htab->h_next;
387600Sbill 		htab->h_next = new;
388600Sbill 	}
389600Sbill }
390600Sbill 
391600Sbill #define 	HASHCLOGGED	(NHASH / 2)
392600Sbill 
393600Sbill /*
394600Sbill  *	Lookup a symbol stored in extern yytext.
395600Sbill  *	All strings passed in via extern yytext had better have
396600Sbill  *	a trailing null.  Strings are placed in yytext for hashing by
397600Sbill  *	syminstall() and by yylex();
398600Sbill  *
399600Sbill  *	We take pains to avoid function calls; this functdion
400600Sbill  *	is called quite frequently, and the calls overhead
401600Sbill  *	in the vax contributes significantly to the overall
402600Sbill  *	execution speed of as.
403600Sbill  */
404600Sbill struct symtab **lookup(instflg)
405600Sbill 	int	instflg;		/* 0: don't install */
406600Sbill {
407600Sbill 	static	 int		initialprobe;
408600Sbill 	register struct	symtab 	**hp;
409600Sbill 	register char 		*from;
410600Sbill 	register char		*to;
411600Sbill 	register	int	len;
412600Sbill 	register	int	nprobes;
413600Sbill 	static	 struct hashdallop *hdallop;
414600Sbill 	static	 struct symtab	**emptyslot;
415600Sbill 	static 	 struct hashdallop *emptyhd;
416600Sbill 	static	 struct	symtab	**hp_ub;
417600Sbill 
418600Sbill 	emptyslot = 0;
419600Sbill 	for (nprobes = 0, from = yytext;
420600Sbill 	     *from;
421600Sbill 	     nprobes <<= 2, nprobes += *from++)
422600Sbill 		continue;
423600Sbill 	nprobes += from[-1] << 5;
424600Sbill 	nprobes %= NHASH;
425600Sbill 	if (nprobes < 0)
426600Sbill 		nprobes += NHASH;
427600Sbill 
428600Sbill 	initialprobe = nprobes;
429600Sbill 	for (hdallop = htab; hdallop != 0; hdallop = hdallop->h_next){
430600Sbill 		for (hp = &(hdallop->h_htab[initialprobe]),
431600Sbill 				nprobes = 1,
432600Sbill 				hp_ub = &(hdallop->h_htab[NHASH]);
433600Sbill 		     (*hp) && (nprobes < NHASH);
434600Sbill 				hp += nprobes,
435600Sbill 				hp -= (hp >= hp_ub) ? NHASH:0,
436600Sbill 				nprobes += 2)
437600Sbill 		{
438600Sbill 			from = yytext;
439634Shenry 			to = (*hp)->s_name;
440600Sbill #ifndef FLEXNAMES
441600Sbill 			for (len = 0; (len<NCPS) && *from; len++)
442600Sbill 				if (*from++ != *to++)
443600Sbill 					goto nextprobe;
444600Sbill 			if (len >= NCPS)	/*both are maximal length*/
445600Sbill 				return(hp);
446600Sbill 			if (*to == 0)		/*assert *from == 0*/
447600Sbill 				return(hp);
448600Sbill #else FLEXNAMES
449600Sbill 			while (*from && *to)
450600Sbill 				if (*from++ != *to++)
451600Sbill 					goto nextprobe;
452600Sbill 			if (*to == *from)	/*assert both are == 0*/
453600Sbill 				return(hp);
454600Sbill #endif FLEXNAMES
455600Sbill 
456600Sbill 	nextprobe: ;
457600Sbill 		}
458600Sbill 		if (*hp == 0 && emptyslot == 0 &&
459600Sbill 		    hdallop->h_nused < HASHCLOGGED) {
460600Sbill 			emptyslot = hp;
461600Sbill 			emptyhd = hdallop;
462600Sbill 		}
463600Sbill 	}
464600Sbill 	if (emptyslot == 0) {
465600Sbill 		htaballoc();
466600Sbill 		hdallop = htab->h_next;		/* aren't we smart! */
467600Sbill 		hp = &hdallop->h_htab[initialprobe];
468600Sbill 	} else {
469600Sbill 		hdallop = emptyhd;
470600Sbill 		hp = emptyslot;
471600Sbill 	}
472600Sbill 	if (instflg) {
473600Sbill 		*hp = symalloc();
474600Sbill 		hdallop->h_nused++;
475600Sbill #ifndef FLEXNAMES
476634Shenry 		for(len = 0, from = yytext, to = (*hp)->s_name; (len<NCPS); len++)
477600Sbill  			if ((*to++ = *from++) == '\0')
478600Sbill  				break;
479600Sbill #else FLEXNAMES
480600Sbill 		for (from = yytext, len = 1; *from++; len++)
481600Sbill 			continue;
482600Sbill 		if (len >= (STRPOOLDALLOP - strplhead->str_nalloc))
483600Sbill 			strpoolalloc();
484634Shenry 		for ( (*hp)->s_name = to = strplhead->str_names + strplhead->str_nalloc, from = yytext;
485600Sbill 		     ( (*to++ = *from++) != '\0'); )
486600Sbill 			continue;
487600Sbill 		strplhead->str_nalloc += len;
488600Sbill #endif FLEXNAMES
489600Sbill 	}
490600Sbill 	return(hp);
491600Sbill }	/*end of lookup*/
492600Sbill 
4931744Shenry #ifdef FLEXNAMES
494600Sbill char *savestr(str)
495600Sbill 	char *str;
496600Sbill {
497600Sbill 	register int len;
498600Sbill 	register char *from, *to;
499600Sbill 	char *res;
500600Sbill 
501600Sbill 	for (from = str, len = 1; *from++; len++)
502600Sbill 		continue;
503600Sbill 	if (len >= (STRPOOLDALLOP - strplhead->str_nalloc))
504600Sbill 		strpoolalloc();
505600Sbill 	for ( res = to = strplhead->str_names + strplhead->str_nalloc, from = str;
506600Sbill 		     ( (*to++ = *from++) != '\0'); )
507600Sbill 			continue;
508600Sbill 	strplhead->str_nalloc += len;
509600Sbill 	return (res);
510600Sbill }
5111744Shenry #endif FLEXNAMES
512600Sbill 
513600Sbill /*
514600Sbill  *	The relocation information is saved internally in an array of
515600Sbill  *	lists of relocation buffers.  The relocation buffers are
516600Sbill  *	exactly the same size as a token buffer; if we use VM for the
517600Sbill  *	temporary file we reclaim this storage, otherwise we create
518600Sbill  *	them by mallocing.
519600Sbill  */
520600Sbill #define	RELBUFLG	TOKBUFLG
521600Sbill #define	NRELOC		((TOKBUFLG - \
522600Sbill 			  (sizeof (int) + sizeof (struct relbufdesc *)) \
523600Sbill 			) / (sizeof (struct relocation_info)))
524600Sbill 
525600Sbill struct	relbufdesc{
526600Sbill 	int	rel_count;
527600Sbill 	struct	relbufdesc	*rel_next;
528600Sbill 	struct	relocation_info	rel_reloc[NRELOC];
529600Sbill };
530600Sbill extern	struct	relbufdesc	*tok_free;
531600Sbill #define	rel_free tok_free
532600Sbill static	struct	relbufdesc	*rel_temp;
533634Shenry struct	relocation_info r_can_1PC;
534634Shenry struct	relocation_info	r_can_0PC;
535600Sbill 
536600Sbill initoutrel()
537600Sbill {
538634Shenry 	r_can_0PC.r_address = 0;
539634Shenry 	r_can_0PC.r_symbolnum = 0;
540634Shenry 	r_can_0PC.r_pcrel = 0;
541634Shenry 	r_can_0PC.r_length = 0;
542634Shenry 	r_can_0PC.r_extern = 0;
543634Shenry 
544634Shenry 	r_can_1PC = r_can_0PC;
545600Sbill 	r_can_1PC.r_pcrel = 1;
546600Sbill }
547600Sbill 
548675Shenry outrel(xp, reloc_how)
549675Shenry 	register	struct	exp	*xp;
5505828Srrh 	int		reloc_how;	/* TYPB..TYPH + (possibly)RELOC_PCREL */
551600Sbill {
552675Shenry 	struct		relocation_info	reloc;
553675Shenry 	register	int	x_type_mask;
554675Shenry 	int		pcrel;
555600Sbill 
556675Shenry 	x_type_mask = xp->e_xtype & ~XFORW;
557675Shenry 	pcrel = reloc_how & RELOC_PCREL;
558675Shenry 	reloc_how &= ~RELOC_PCREL;
559675Shenry 
560600Sbill 	if (bitoff&07)
561600Sbill 		yyerror("Padding error");
562675Shenry 	if (x_type_mask == XUNDEF)
563600Sbill 		yyerror("Undefined reference");
564600Sbill 
565675Shenry 	if ( (x_type_mask != XABS) || pcrel ) {
566675Shenry 		if (ty_NORELOC[reloc_how])
5675828Srrh 			yyerror("Illegal Relocation of floating or large int number.");
568675Shenry 		reloc = pcrel ? r_can_1PC : r_can_0PC;
569634Shenry 		reloc.r_address = dotp->e_xvalue -
570640Sbill 		    ( (dotp < &usedot[NLOC] || readonlydata) ? 0 : datbase );
571675Shenry 		reloc.r_length = ty_nlg[reloc_how];
572675Shenry 		switch(x_type_mask){
573600Sbill 			case XXTRN | XUNDEF:
574675Shenry 				reloc.r_symbolnum = xp->e_xname->s_index;
575600Sbill 				reloc.r_extern = 1;
576600Sbill 				break;
577600Sbill 			default:
578675Shenry 				if (readonlydata && (x_type_mask&~XXTRN) == XDATA)
579675Shenry 					x_type_mask = XTEXT | (x_type_mask&XXTRN);
580675Shenry 				reloc.r_symbolnum = x_type_mask;
581600Sbill 				break;
582600Sbill 		}
583600Sbill 		if ( (relfil == 0) || (relfil->rel_count >= NRELOC) ){
584600Sbill 			if (rel_free){
585600Sbill 				rel_temp = rel_free;
586600Sbill 				rel_free = rel_temp->rel_next;
587600Sbill 			} else {
588600Sbill 				rel_temp = (struct relbufdesc *)
589600Sbill 					Calloc(1,sizeof (struct relbufdesc));
590600Sbill 			}
591600Sbill 			rel_temp->rel_count = 0;
592600Sbill 			rel_temp->rel_next = relfil;
593600Sbill 			relfil = rusefile[dotp - &usedot[0]] = rel_temp;
594600Sbill 		}
595600Sbill 		relfil->rel_reloc[relfil->rel_count++] = reloc;
596600Sbill 	}
597600Sbill 	/*
598600Sbill 	 *	write the unrelocated value to the text file
599600Sbill 	 */
600675Shenry 	dotp->e_xvalue += ty_nbyte[reloc_how];
601675Shenry 	if (pcrel)
602675Shenry 		xp->e_xvalue -= dotp->e_xvalue;
6035828Srrh 	switch(reloc_how){
6045828Srrh 	case TYPO:
6055828Srrh 	case TYPQ:
6065828Srrh 
6075828Srrh 	case TYPF:
6085828Srrh 	case TYPD:
6095828Srrh 	case TYPG:
6105828Srrh 	case TYPH:
6115828Srrh 		bignumwrite(xp->e_number, reloc_how);
6125828Srrh 		break;
6135828Srrh 
6145828Srrh 	default:
6155828Srrh 		bwrite((char *)&(xp->e_xvalue), ty_nbyte[reloc_how], txtfil);
6165828Srrh 		break;
6175828Srrh 	}
618600Sbill }
619600Sbill /*
620600Sbill  *	Flush out all of the relocation information.
621600Sbill  *	Note that the individual lists of buffers are in
622600Sbill  *	reverse order, so we must reverse them
623600Sbill  */
624600Sbill off_t closeoutrel(relocfile)
625600Sbill 	BFILE	*relocfile;
626600Sbill {
627600Sbill 	int	locindex;
628600Sbill 	u_long	Closeoutrel();
629600Sbill 
630600Sbill 	trsize = 0;
631600Sbill 	for (locindex = 0; locindex < NLOC; locindex++){
632600Sbill 		trsize += Closeoutrel(rusefile[locindex], relocfile);
633600Sbill 	}
634600Sbill 	drsize = 0;
635600Sbill 	for (locindex = 0; locindex < NLOC; locindex++){
636600Sbill 		drsize += Closeoutrel(rusefile[NLOC + locindex], relocfile);
637600Sbill 	}
638600Sbill 	return(trsize + drsize);
639600Sbill }
640600Sbill 
641600Sbill u_long Closeoutrel(relfil, relocfile)
642600Sbill 	struct	relbufdesc	*relfil;
643600Sbill 	BFILE	*relocfile;
644600Sbill {
645600Sbill 	u_long	tail;
646600Sbill 	if (relfil == 0)
647600Sbill 		return(0L);
648600Sbill 	tail = Closeoutrel(relfil->rel_next, relocfile);
649600Sbill 	bwrite((char *)&relfil->rel_reloc[0],
650600Sbill 		relfil->rel_count * sizeof (struct relocation_info),
651600Sbill 		relocfile);
652600Sbill 	return(tail + relfil->rel_count * sizeof (struct relocation_info));
653600Sbill }
654600Sbill 
655634Shenry #define NOUTSYMS (nsyms - njxxx - nforgotten - (savelabels ? 0 : nlabels))
656600Sbill int sizesymtab()
657600Sbill {
658634Shenry 	return (sizeof (struct nlist) * NOUTSYMS);
659600Sbill }
660600Sbill 
661600Sbill #ifdef FLEXNAMES
662600Sbill /*
663600Sbill  *	We write out the flexible length character strings for  names
664600Sbill  *	in two stages.
665600Sbill  *	1)	We have always! maintain a fixed sized name list entry;
666600Sbill  *	the string is indexed by a four byte quantity from the beginning
667600Sbill  *	of the string pool area.  Index 0 is reserved, and indicates
668600Sbill  *	that there is no associated string. The first valid index is 4.
669600Sbill  *	2)	 We concatenate together and write all of the strings
670600Sbill  *	in the string pool at the end of the name list. The first
671600Sbill  *	four bytes in the string pool are indexed only by 0 (see above);
672600Sbill  *	they contain the total number of bytes in the string pool.
673600Sbill  */
674600Sbill #endif FLEXNAMES
675600Sbill 
676600Sbill /*
677600Sbill  *	Write out n symbols to file f, beginning at p
678600Sbill  *	ignoring symbols that are obsolete, jxxx instructions, and
679600Sbill  *	possibly, labels
680600Sbill  */
681600Sbill 
682600Sbill int symwrite(symfile)
683600Sbill 	BFILE *symfile;
684600Sbill {
685600Sbill 	int	symsout;			/*those actually written*/
686600Sbill 	int	symsdesired = NOUTSYMS;
687600Sbill 	register	struct	symtab *sp, *ub;
688600Sbill #ifdef FLEXNAMES
689634Shenry 	char		*name;			/* temp to save the name */
690600Sbill 	long		stroff	= sizeof (stroff);
691634Shenry 	/*
692634Shenry 	 *	We use sp->s_index to hold the length of the
693634Shenry 	 *	name; it isn't used for anything else
694634Shenry 	 */
695600Sbill #endif FLEXNAMES
696600Sbill 
697600Sbill 	register	struct	allocbox	*allocwalk;
698600Sbill 
699600Sbill 	symsout = 0;
700600Sbill 	DECLITERATE(allocwalk, sp, ub)
701600Sbill 	{
702634Shenry 		if (sp->s_tag >= IGNOREBOUND)
703600Sbill 			continue;
704634Shenry 		if ((sp->s_name[0] == 'L') && (sp->s_tag == LABELID) && !savelabels)
705600Sbill 			continue;
706600Sbill 		symsout++;
707634Shenry 
708634Shenry #ifdef FLEXNAMES
709634Shenry 		name = sp->s_name;		/* save pointer */
710634Shenry 		if ( (sp->s_index = strlen(sp->s_name)) != 0){
711634Shenry 			sp->s_nmx = stroff;	/* clobber pointer */
712634Shenry 			stroff += sp->s_index + 1;
713634Shenry 		} else {
714634Shenry 			sp->s_nmx = 0;		/* clobber pointer */
715634Shenry 		}
716634Shenry #endif
717634Shenry 		sp->s_type = (sp->s_ptype != 0) ? sp->s_ptype : (sp->s_type & (~XFORW));
718640Sbill 		if (readonlydata && (sp->s_type&~N_EXT) == N_DATA)
719640Sbill 			sp->s_type = N_TEXT | (sp->s_type & N_EXT);
7205828Srrh 		bwrite((char *)&sp->s_nm, sizeof (struct nlist), symfile);
721634Shenry #ifdef FLEXNAMES
722634Shenry 		sp->s_name = name;		/* restore pointer */
723600Sbill #endif FLEXNAMES
724600Sbill 	}
725600Sbill 	if (symsout != symsdesired)
726600Sbill 		yyerror("INTERNAL ERROR: Wrote %d symbols, wanted to write %d symbols\n",
727600Sbill 			symsout, symsdesired);
728600Sbill #ifdef FLEXNAMES
729600Sbill 	/*
730600Sbill 	 *	Pass 2 through the string pool
731600Sbill 	 */
732600Sbill 	symsout = 0;
7335828Srrh 	bwrite((char *)&stroff, sizeof (stroff), symfile);
734600Sbill 	stroff = sizeof (stroff);
735600Sbill 	symsout = 0;
736600Sbill 	DECLITERATE(allocwalk, sp, ub)
737600Sbill 	{
738634Shenry 		if (sp->s_tag >= IGNOREBOUND)
739600Sbill 			continue;
740634Shenry 		if ((sp->s_name[0] == 'L') && (sp->s_tag == LABELID) && !savelabels)
741600Sbill 			continue;
742634Shenry 		sp->s_index = strlen(sp->s_name);
743634Shenry 		if (sp->s_index)
744634Shenry 			bwrite(sp->s_name, sp->s_index + 1, symfile);
745600Sbill 	}
746600Sbill #endif FLEXNAMES
747600Sbill }
748