xref: /original-bsd/old/as.vax/assyms.c (revision 23a40993)
1 /*
2  *	Copyright (c) 1982 Regents of the University of California
3  */
4 #ifndef lint
5 static char sccsid[] = "@(#)assyms.c 4.10 06/30/83";
6 #endif not lint
7 
8 #include <stdio.h>
9 #include <ctype.h>
10 #include "as.h"
11 #include "asscan.h"
12 #include "assyms.h"
13 
14 /*
15  *	Managers for chunks of symbols allocated from calloc()
16  *	We maintain a linked list of such chunks.
17  *
18  */
19 struct	allocbox	*allochead;	/*head of chunk list*/
20 struct	allocbox	*alloctail;	/*tail*/
21 struct	allocbox	*newbox;	/*for creating a new chunk*/
22 struct	symtab		*nextsym;	/*next symbol free*/
23 int			symsleft;	/*slots left in current chunk*/
24 
25 struct	symtab		**symptrs;
26 struct	symtab		**symdelim[NLOC + NLOC +1];
27 struct	symtab		**symptrub;
28 /*
29  *	Managers for the dynamically extendable hash table
30  */
31 struct	hashdallop	*htab;
32 
33 Iptr	*itab[NINST];	/*maps opcodes to instructions*/
34 /*
35  *	Counts what went into the symbol table, so that the
36  *	size of the symbol table can be computed.
37  */
38 int	nsyms;		/* total number in the symbol table */
39 int	njxxx;		/* number of jxxx entrys */
40 int	nforgotten;	/* number of symbols erroneously entered */
41 int	nlabels;	/* number of label entries */
42 
43 /*
44  *	Managers of the symbol literal storage.
45  */
46 struct	strpool		*strplhead = 0;
47 
48 symtabinit()
49 {
50 	allochead = 0;
51 	alloctail = 0;
52 	nextsym = 0;
53 	symsleft = 0;
54 	strpoolalloc();		/* get the first strpool storage area */
55 	htab = 0;
56 	htaballoc();		/* get the first part of the hash table */
57 }
58 
59 /*
60  *	Install all known instructions in the symbol table
61  */
62 syminstall()
63 {
64 	register	Iptr	ip;
65 	register	struct	symtab	**hp;
66 	register	char	*p1, *p2;
67 	register	int	i;
68 
69 	for (i = 0; i < NINST; i++)
70 		itab[i] = (Iptr*)BADPOINT;
71 
72 #ifdef FLEXNAMES
73 	for (ip = (Iptr)instab; ip->s_name != 0; ip++) {
74 #else not FLEXNAMES
75 	for (ip = (Iptr)instab; ip->s_name[0] != '\0'; ip++){
76 #endif not FLEXNAMES
77 		p1 = ip->s_name;
78 		p2 = yytext;
79 		while (*p2++ = *p1++);
80 		hp = lookup(0);		/* 0 => don't install this*/
81 		if (*hp==NULL) {
82 			*hp = (struct symtab *)ip;
83 			if (   (ip->s_tag!=INSTn)
84 			    && (ip->s_tag!=INST0)
85 			    && (ip->s_tag!=0))
86 				continue; /* was pseudo-op */
87 			if (itab[ip->i_eopcode] == (Iptr*)BADPOINT){
88 				itab[ip->i_eopcode] =
89 					(Iptr*)ClearCalloc(256, sizeof(Iptr));
90 				for (i = 0; i < 256; i++)
91 					itab[ip->i_eopcode][i] =
92 						(Iptr)BADPOINT;
93 			}
94 			itab[ip->i_eopcode][ip->i_popcode] = ip;
95 		}
96 	}
97 }	/*end of syminstall*/
98 
99 
100 /*
101  *	Assign final values to symbols,
102  *	and overwrite the index field with its relative position in
103  *	the symbol table we give to the loader.
104  */
105 extern struct exec hdr;
106 
107 freezesymtab()
108 {
109 	register	struct	symtab	*sp;
110 				long	bs;
111 	register	int	relpos = 0;
112 	register	struct	symtab		*ubsp;
113 	register	struct	allocbox	*allocwalk;
114 
115 	DECLITERATE(allocwalk, sp, ubsp)
116 	{
117 		if (sp->s_tag >= IGNOREBOUND)
118 			continue; 		/*totally ignore jxxx entries */
119 		/*
120 		 *	Ignore stabs, but give them a symbol table index
121 		 */
122 		if (sp->s_type & STABFLAG)
123 			goto assignindex;
124 		if ((sp->s_type&XTYPE)==XUNDEF)
125 			sp->s_type = XXTRN+XUNDEF;
126 		else if ((sp->s_type&XTYPE)==XDATA)
127 			sp->s_value += usedot[sp->s_index].e_xvalue;
128 		else if ((sp->s_type&XTYPE)==XTEXT)
129 			sp->s_value += usedot[sp->s_index].e_xvalue;
130 		else if ((sp->s_type&XTYPE)==XBSS) {
131 			bs = sp->s_value;
132 			sp->s_value = hdr.a_bss + datbase;
133 			hdr.a_bss += bs;
134 		}
135 	   assignindex:
136 		if (    (sp->s_name[0] != 'L')
137 		     || (sp->s_tag != LABELID)
138 		     || savelabels
139 		     )			/*then, we will write it later on*/
140 				sp->s_index = relpos++;
141 	}
142 }
143 
144 
145 
146 /*
147  *	For all of the stabs that had their final value undefined during pass 1
148  *	and during pass 2 assign a final value.
149  *	We have already given stab entrys a initial approximation
150  *	when we constsructed the sorted symbol table.
151  *	Iteration order doesn't matter.
152  */
153 
154 stabfix()
155 {
156 	register struct symtab *sp, **cosp;
157 	register struct symtab *p;
158 
159 	SYMITERATE(cosp, sp){
160 		if(sp->s_ptype && (sp->s_type & STABFLAG)) {
161 			p = sp->s_dest;
162 /*
163  * STABFLOATING indicates that the offset has been saved in s_desc, s_other
164  */
165 			if(sp->s_tag == STABFLOATING) {
166 			  sp->s_value = ( ( ((unsigned char) sp->s_other) << 16)  					| ( (unsigned short) sp->s_desc )  );
167 			  sp->s_value = sp->s_value + p->s_value;
168 			}
169 			else sp->s_value = p->s_value;
170 			sp->s_index = p->s_index;
171 			sp->s_type = p->s_type;
172 
173 
174 		}
175 	}
176 }
177 
178 char *Calloc(number, size)
179 	int	number, size;
180 {
181 	register	char *newstuff;
182 	char	*sbrk();
183 	newstuff = sbrk(number*size);
184 	if ((int)newstuff == -1){
185 		yyerror("Ran out of Memory");
186 		delexit();
187 	}
188 	return(newstuff);
189 }
190 
191 char *ClearCalloc(number, size)
192 	int	number, size;
193 {
194 	register	char	*newstuff;		/* r11 */
195 	register	int	length = number * size;	/* r10 */
196 #ifdef lint
197 	length = length;
198 #endif length
199 	newstuff = Calloc(number, size);
200 	asm("movc5 $0, (r0), $0, r10, (r11)");
201 	return(newstuff);
202 }
203 
204 struct symtab *symalloc()
205 {
206 	if (symsleft == 0){
207 		newbox = (struct allocbox *)ClearCalloc(1,ALLOCQTY);
208 		symsleft = SYMDALLOP;
209 		nextsym = &newbox->symslots[0];
210 		if (alloctail == 0){
211 			allochead = alloctail = newbox;
212 		} else {
213 			alloctail->nextalloc = newbox;
214 			alloctail = newbox;
215 		}
216 	}
217 	--symsleft;
218 	++nsyms;
219 	return(nextsym++);
220 }
221 
222 strpoolalloc()
223 {
224 	register	struct	strpool	*new;
225 
226 	new = (struct strpool *)Calloc(1, sizeof (struct strpool));
227 	new->str_nalloc = 0;
228 	new->str_next = strplhead;
229 	strplhead = new;
230 }
231 
232 symcmp(Pptr, Qptr)
233 	struct symtab **Pptr, **Qptr;
234 {
235 	register struct symtab *p = *Pptr;
236 	register struct symtab *q = *Qptr;
237 	if (p->s_index < q->s_index)
238 		return(-1);
239 	if (p->s_index > q->s_index)
240 		return(1);
241 	if (p->s_value < q->s_value)
242 		return(-1);
243 	if (p->s_value > q->s_value)
244 		return(1);
245 	/*
246 	 *	Force jxxx entries to virtually preceed labels defined
247 	 *	to follow the jxxxx instruction, so that bumping the
248 	 *	jxxx instruction correctly fixes up the following labels
249 	 */
250 	if (p->s_tag >= IGNOREBOUND)	/*p points to a jxxx*/
251 		return(-1);
252 	if (q->s_tag >= IGNOREBOUND)
253 		return(1);
254 	/*
255 	 *	both are now just plain labels; the relative order doesn't
256 	 *	matter.  Both can't be jxxxes, as they would have different
257 	 *	values.
258 	 */
259 	return(0);
260 }	/*end of symcmp*/
261 
262 /*
263  *	We construct the auxiliary table of pointers, symptrs and
264  *	symdelim
265  *	We also assign preliminary values to stab entries that did not yet
266  *	have an absolute value (because they initially referred to
267  *	forward references). We don't worry about .stabds, as they
268  *	already have an estimated final value
269  */
270 
271 sortsymtab()
272 {
273 	register	struct	symtab	*sp;
274 	register	struct	symtab	**cowalk;
275 	register	struct	allocbox	*allocwalk;
276 			struct	symtab	*ubsp;
277 				int	segno;
278 				int	slotno;
279 				int	symsin;	/*number put into symptrs*/
280 
281 	symptrs =  (struct symtab **)Calloc(nsyms + 2, sizeof *symptrs);
282 	/*
283 	 *	Allocate one word at the beginning of the symptr array
284 	 *	so that backwards scans through the symptr array will
285 	 *	work correctly while scanning through the zeroth segment
286 	 */
287 	*symptrs++ = 0;
288 	cowalk = symptrs;
289 	symsin = 0;
290 	DECLITERATE(allocwalk, sp, ubsp) {
291 		if (sp->s_ptype && (sp->s_type &STABFLAG)){
292 			sp->s_value = sp->s_dest->s_value;
293 			sp->s_index = sp->s_dest->s_index;
294 		}
295 		if (symsin >= nsyms)
296 			yyerror("INTERNAL ERROR: overfilled symbol table indirection table");
297 		*cowalk++ = sp;
298 		symsin++;
299 	}
300 	if (symsin != nsyms)
301 		yyerror("INTERNAL ERROR: installed %d syms, should have installed %d",
302 			symsin, nsyms);
303 	symptrub = &symptrs[nsyms ];
304 	qsort(symptrs, nsyms, sizeof *symptrs, symcmp);
305 	symdelim[0] = symptrs;
306 	for (cowalk = symptrs, sp = *cowalk, segno = 0, slotno = 1;
307 	     segno < NLOC + NLOC;
308 	     segno++, slotno++){
309 		for (; sp && sp->s_index == segno; sp = *++cowalk);
310 		symdelim[slotno] = cowalk;	/*forms the ub delimeter*/
311 	}
312 }	/*end of sortsymtab*/
313 
314 #ifdef DEBUG
315 dumpsymtab()
316 {
317 	register	int	segno;
318 	register	struct symtab *sp, **cosp, *ub;
319 	char		*tagstring();
320 
321 	printf("Symbol Table dump:\n");
322 	for (segno = 0; segno < NLOC + NLOC; segno++){
323 		printf("Segment number: %d\n", segno);
324 		SEGITERATE(segno, 0, 0, cosp, sp, ub, ++){
325 #ifdef FLEXNAMES
326 			printf("\tSeg: %d \"%s\" value: %d index: %d tag %s\n",
327 				segno, sp->s_name,
328 				sp->s_value, sp->s_index,
329 				tagstring(sp->s_tag));
330 #else not FLEXNAMES
331 			printf("\tSeg: %d \"%*.*s\" value: %d index: %d tag %s\n",
332 				segno, NCPName, NCPName, sp->s_name,
333 				sp->s_value, sp->s_index,
334 				tagstring(sp->s_tag));
335 #endif not FLEXNAMES
336 			printf("\t\ttype: %d jxbump %d jxfear: %d\n",
337 				sp->s_type, sp->s_jxbump, sp->s_jxfear);
338 		}
339 		printf("\n\n");
340 	}
341 }
342 
343 static	char tagbuff[4];
344 
345 char *tagstring(tag)
346 	unsigned	char	tag;
347 {
348 	switch(tag){
349 		case JXACTIVE:		return("active");
350 		case JXNOTYET:		return("notyet");
351 		case JXALIGN:		return("align");
352 		case JXQUESTIONABLE:	return("jxquestionable");
353 		case JXINACTIVE:	return("inactive");
354 		case JXTUNNEL:		return("tunnel");
355 		case OBSOLETE:		return("obsolete");
356 		case IGNOREBOUND:	return("ignorebound");
357 		case STABFLOATING:	return("stabfloating");
358 		case STABFIXED:		return("stabfixed");
359 		case LABELID:		return("labelid");
360 		case OKTOBUMP:		return("oktobump");
361 		case ISET:		return("iset");
362 		case ILSYM:		return("ilsym");
363 		default:		sprintf(tagbuff,"%d", tag);
364 					return(tagbuff);
365 	}
366 }
367 #endif DEBUG
368 
369 htaballoc()
370 {
371 	register	struct	hashdallop	*new;
372 	new = (struct hashdallop *)ClearCalloc(1, sizeof (struct hashdallop));
373 	if (htab == 0)
374 		htab = new;
375 	else {		/* add AFTER the 1st slot */
376 		new->h_next = htab->h_next;
377 		htab->h_next = new;
378 	}
379 }
380 
381 #define 	HASHCLOGGED	(NHASH / 2)
382 
383 /*
384  *	Lookup a symbol stored in extern yytext.
385  *	All strings passed in via extern yytext had better have
386  *	a trailing null.  Strings are placed in yytext for hashing by
387  *	syminstall() and by yylex();
388  *
389  *	We take pains to avoid function calls; this functdion
390  *	is called quite frequently, and the calls overhead
391  *	in the vax contributes significantly to the overall
392  *	execution speed of as.
393  */
394 struct symtab **lookup(instflg)
395 	int	instflg;		/* 0: don't install */
396 {
397 	static	 int		initialprobe;
398 	register struct	symtab 	**hp;
399 	register char 		*from;
400 	register char		*to;
401 	register	int	len;
402 	register	int	nprobes;
403 	static	 struct hashdallop *hdallop;
404 	static	 struct symtab	**emptyslot;
405 	static 	 struct hashdallop *emptyhd;
406 	static	 struct	symtab	**hp_ub;
407 
408 	emptyslot = 0;
409 	for (nprobes = 0, from = yytext;
410 	     *from;
411 	     nprobes <<= 2, nprobes += *from++)
412 		continue;
413 	nprobes += from[-1] << 5;
414 	nprobes %= NHASH;
415 	if (nprobes < 0)
416 		nprobes += NHASH;
417 
418 	initialprobe = nprobes;
419 	for (hdallop = htab; hdallop != 0; hdallop = hdallop->h_next){
420 		for (hp = &(hdallop->h_htab[initialprobe]),
421 				nprobes = 1,
422 				hp_ub = &(hdallop->h_htab[NHASH]);
423 		     (*hp) && (nprobes < NHASH);
424 				hp += nprobes,
425 				hp -= (hp >= hp_ub) ? NHASH:0,
426 				nprobes += 2)
427 		{
428 			from = yytext;
429 			to = (*hp)->s_name;
430 #ifndef FLEXNAMES
431 			for (len = 0; (len<NCPName) && *from; len++)
432 				if (*from++ != *to++)
433 					goto nextprobe;
434 			if (len >= NCPName)	/*both are maximal length*/
435 				return(hp);
436 			if (*to == 0)		/*assert *from == 0*/
437 				return(hp);
438 #else FLEXNAMES
439 			while (*from && *to)
440 				if (*from++ != *to++)
441 					goto nextprobe;
442 			if (*to == *from)	/*assert both are == 0*/
443 				return(hp);
444 #endif FLEXNAMES
445 
446 	nextprobe: ;
447 		}
448 		if (*hp == 0 && emptyslot == 0 &&
449 		    hdallop->h_nused < HASHCLOGGED) {
450 			emptyslot = hp;
451 			emptyhd = hdallop;
452 		}
453 	}
454 	if (emptyslot == 0) {
455 		htaballoc();
456 		hdallop = htab->h_next;		/* aren't we smart! */
457 		hp = &hdallop->h_htab[initialprobe];
458 	} else {
459 		hdallop = emptyhd;
460 		hp = emptyslot;
461 	}
462 	if (instflg) {
463 		*hp = symalloc();
464 		hdallop->h_nused++;
465 #ifndef FLEXNAMES
466 		strncpy((*hp)->s_name, yytext, NCPName);
467 #else FLEXNAMES
468 		for (from = yytext, len = 0; *from++; len++)
469 			continue;
470 		/*
471 		 *	save string and trailing null
472 		 */
473 		(*hp)->s_name = savestr(yytext, len + 1);
474 #endif FLEXNAMES
475 	}
476 	return(hp);
477 }	/*end of lookup*/
478 /*
479  *	save a string str, length len in the string pool.
480  *	string known just by its length; can have or not have trailing nulls.
481  *
482  *	The length of the string occurs as a short just before
483  *	the character pointer returned.
484  */
485 char *savestr(str, len)
486 	char	*str;
487 	int	len;
488 {
489 	char	*res;
490 
491 	if (len + sizeof(lgtype) >= (STRPOOLDALLOP - strplhead->str_nalloc))
492 		strpoolalloc();
493 	res = strplhead->str_names + strplhead->str_nalloc;
494 	plgtype(res, len);
495 	movestr(res, str, len);
496 	strplhead->str_nalloc += sizeof(lgtype) + len;
497 	return(res);
498 }
499 
500 /*
501  *	The relocation information is saved internally in an array of
502  *	lists of relocation buffers.  The relocation buffers are
503  *	exactly the same size as a token buffer; if we use VM for the
504  *	temporary file we reclaim this storage, otherwise we create
505  *	them by mallocing.
506  */
507 #define	RELBUFLG	TOKBUFLG
508 #define	NRELOC		((TOKBUFLG - \
509 			  (sizeof (int) + sizeof (struct relbufdesc *)) \
510 			) / (sizeof (struct relocation_info)))
511 
512 struct	relbufdesc{
513 	int	rel_count;
514 	struct	relbufdesc	*rel_next;
515 	struct	relocation_info	rel_reloc[NRELOC];
516 };
517 extern	struct	relbufdesc	*tok_free;
518 #define	rel_free tok_free
519 static	struct	relbufdesc	*rel_temp;
520 struct	relocation_info r_can_1PC;
521 struct	relocation_info	r_can_0PC;
522 
523 initoutrel()
524 {
525 	r_can_0PC.r_address = 0;
526 	r_can_0PC.r_symbolnum = 0;
527 	r_can_0PC.r_pcrel = 0;
528 	r_can_0PC.r_length = 0;
529 	r_can_0PC.r_extern = 0;
530 
531 	r_can_1PC = r_can_0PC;
532 	r_can_1PC.r_pcrel = 1;
533 }
534 
535 outrel(xp, reloc_how)
536 	register	struct	exp	*xp;
537 	int		reloc_how;	/* TYPB..TYPH + (possibly)RELOC_PCREL */
538 {
539 	struct		relocation_info	reloc;
540 	register	int	x_type_mask;
541 			int	pcrel;
542 
543 	x_type_mask = xp->e_xtype & ~XFORW;
544 	pcrel = reloc_how & RELOC_PCREL;
545 	reloc_how &= ~RELOC_PCREL;
546 
547 	if (bitoff&07)
548 		yyerror("Padding error");
549 	if (x_type_mask == XUNDEF)
550 		yyerror("Undefined reference");
551 
552 	if ( (x_type_mask != XABS) || pcrel ) {
553 		if (ty_NORELOC[reloc_how])
554 			yyerror("Illegal Relocation of floating or large int number.");
555 		reloc = pcrel ? r_can_1PC : r_can_0PC;
556 		reloc.r_address = dotp->e_xvalue -
557 		    ( (dotp < &usedot[NLOC] || readonlydata) ? 0 : datbase );
558 		reloc.r_length = ty_nlg[reloc_how];
559 		switch(x_type_mask){
560 			case XXTRN | XUNDEF:
561 				reloc.r_symbolnum = xp->e_xname->s_index;
562 				reloc.r_extern = 1;
563 				break;
564 			default:
565 				if (readonlydata && (x_type_mask&~XXTRN) == XDATA)
566 					x_type_mask = XTEXT | (x_type_mask&XXTRN);
567 				reloc.r_symbolnum = x_type_mask;
568 				break;
569 		}
570 		if ( (relfil == 0) || (relfil->rel_count >= NRELOC) ){
571 			if (rel_free){
572 				rel_temp = rel_free;
573 				rel_free = rel_temp->rel_next;
574 			} else {
575 				rel_temp = (struct relbufdesc *)
576 					Calloc(1,sizeof (struct relbufdesc));
577 			}
578 			rel_temp->rel_count = 0;
579 			rel_temp->rel_next = relfil;
580 			relfil = rusefile[dotp - &usedot[0]] = rel_temp;
581 		}
582 		relfil->rel_reloc[relfil->rel_count++] = reloc;
583 	}
584 	/*
585 	 *	write the unrelocated value to the text file
586 	 */
587 	dotp->e_xvalue += ty_nbyte[reloc_how];
588 	if (pcrel)
589 		xp->e_xvalue -= dotp->e_xvalue;
590 	switch(reloc_how){
591 	case TYPO:
592 	case TYPQ:
593 
594 	case TYPF:
595 	case TYPD:
596 	case TYPG:
597 	case TYPH:
598 		bignumwrite(xp->e_number, reloc_how);
599 		break;
600 
601 	default:
602 		bwrite((char *)&(xp->e_xvalue), ty_nbyte[reloc_how], txtfil);
603 		break;
604 	}
605 }
606 /*
607  *	Flush out all of the relocation information.
608  *	Note that the individual lists of buffers are in
609  *	reverse order, so we must reverse them
610  */
611 off_t closeoutrel(relocfile)
612 	BFILE	*relocfile;
613 {
614 	int	locindex;
615 	u_long	Closeoutrel();
616 
617 	trsize = 0;
618 	for (locindex = 0; locindex < NLOC; locindex++){
619 		trsize += Closeoutrel(rusefile[locindex], relocfile);
620 	}
621 	drsize = 0;
622 	for (locindex = 0; locindex < NLOC; locindex++){
623 		drsize += Closeoutrel(rusefile[NLOC + locindex], relocfile);
624 	}
625 	return(trsize + drsize);
626 }
627 
628 u_long Closeoutrel(relfil, relocfile)
629 	struct	relbufdesc	*relfil;
630 	BFILE	*relocfile;
631 {
632 	u_long	tail;
633 	if (relfil == 0)
634 		return(0L);
635 	tail = Closeoutrel(relfil->rel_next, relocfile);
636 	bwrite((char *)&relfil->rel_reloc[0],
637 		relfil->rel_count * sizeof (struct relocation_info),
638 		relocfile);
639 	return(tail + relfil->rel_count * sizeof (struct relocation_info));
640 }
641 
642 #define NOUTSYMS (nsyms - njxxx - nforgotten - (savelabels ? 0 : nlabels))
643 int sizesymtab()
644 {
645 	return (sizeof (struct nlist) * NOUTSYMS);
646 }
647 
648 #ifdef FLEXNAMES
649 /*
650  *	We write out the flexible length character strings for  names
651  *	in two stages.
652  *	1)	We always! maintain a fixed sized name list entry;
653  *	the string is indexed by a four byte quantity from the beginning
654  *	of the string pool area.  Index 0 is reserved, and indicates
655  *	that there is no associated string. The first valid index is 4.
656  *	2)	 We concatenate together and write all of the strings
657  *	in the string pool at the end of the name list. The first
658  *	four bytes in the string pool are indexed only by 0 (see above);
659  *	they contain the total number of bytes in the string pool.
660  */
661 #endif FLEXNAMES
662 
663 /*
664  *	Write out n symbols to file f, beginning at p
665  *	ignoring symbols that are obsolete, jxxx instructions, and
666  *	possibly, labels
667  */
668 
669 int symwrite(symfile)
670 	BFILE *symfile;
671 {
672 	int	symsout;			/*those actually written*/
673 	int	symsdesired = NOUTSYMS;
674 	register	struct	symtab *sp, *ub;
675 #ifdef FLEXNAMES
676 	char		*name;			/* temp to save the name */
677 	long		stroff	= sizeof (stroff);
678 	/*
679 	 *	We use sp->s_index to hold the length of the
680 	 *	name; it isn't used for anything else
681 	 */
682 #endif FLEXNAMES
683 
684 	register	struct	allocbox	*allocwalk;
685 
686 	symsout = 0;
687 	DECLITERATE(allocwalk, sp, ub)
688 	{
689 		if (sp->s_tag >= IGNOREBOUND)
690 			continue;
691 		if ((sp->s_name[0] == 'L') && (sp->s_tag == LABELID) && !savelabels)
692 			continue;
693 		symsout++;
694 
695 #ifdef FLEXNAMES
696 		name = sp->s_name;		/* save pointer */
697 		/*
698 		 *	the length of the symbol table string
699 		 *	always includes the trailing null
700 		 */
701 		if (sp->s_name && (sp->s_index = STRLEN(sp->s_name))){
702 			sp->s_nmx = stroff;	/* clobber pointer */
703 			stroff += sp->s_index;
704 		} else {
705 			sp->s_nmx = 0;
706 		}
707 #endif
708 		sp->s_type = (sp->s_ptype != 0) ? sp->s_ptype : (sp->s_type & (~XFORW));
709 		if (readonlydata && (sp->s_type&~N_EXT) == N_DATA)
710 			sp->s_type = N_TEXT | (sp->s_type & N_EXT);
711 		bwrite((char *)&sp->s_nm, sizeof (struct nlist), symfile);
712 #ifdef FLEXNAMES
713 		sp->s_name = name;		/* restore pointer */
714 #endif FLEXNAMES
715 	}
716 	if (symsout != symsdesired)
717 		yyerror("INTERNAL ERROR: Wrote %d symbols, wanted to write %d symbols\n",
718 			symsout, symsdesired);
719 #ifdef FLEXNAMES
720 	/*
721 	 *	Pass 2 through the string pool
722 	 */
723 	symsout = 0;
724 	bwrite((char *)&stroff, sizeof (stroff), symfile);
725 	stroff = sizeof (stroff);
726 	symsout = 0;
727 	DECLITERATE(allocwalk, sp, ub)
728 	{
729 		if (sp->s_tag >= IGNOREBOUND)
730 			continue;
731 		if ((sp->s_name[0] == 'L') && (sp->s_tag == LABELID) && !savelabels)
732 			continue;
733 		if (sp->s_name && (sp->s_index = STRLEN(sp->s_name))){
734 			bwrite(sp->s_name, sp->s_index, symfile);
735 		}
736 	}
737 #endif FLEXNAMES
738 }
739