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