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