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