xref: /original-bsd/old/ld/ld.c (revision 6c57d260)
1 static	char sccsid[] = "@(#)ld.c 4.4 04/26/81";
2 /*
3  * ld - string table version for VAX
4  */
5 
6 #include <sys/types.h>
7 #include <signal.h>
8 #include <stdio.h>
9 #include <ctype.h>
10 #include <ar.h>
11 #include <a.out.h>
12 #include <ranlib.h>
13 #include <stat.h>
14 #include <pagsiz.h>
15 
16 /*
17  * Basic strategy:
18  *
19  * The loader takes a number of files and libraries as arguments.
20  * A first pass examines each file in turn.  Normal files are
21  * unconditionally loaded, and the (external) symbols they define and require
22  * are noted in the symbol table.   Libraries are searched, and the
23  * library members which define needed symbols are remembered
24  * in a special data structure so they can be selected on the second
25  * pass.  Symbols defined and required by library members are also
26  * recorded.
27  *
28  * After the first pass, the loader knows the size of the basic text
29  * data, and bss segments from the sum of the sizes of the modules which
30  * were required.  It has computed, for each ``common'' symbol, the
31  * maximum size of any reference to it, and these symbols are then assigned
32  * storage locations after their sizes are appropriately rounded.
33  * The loader now knows all sizes for the eventual output file, and
34  * can determine the final locations of external symbols before it
35  * begins a second pass.
36  *
37  * On the second pass each normal file and required library member
38  * is processed again.  The symbol table for each such file is
39  * reread and relevant parts of it are placed in the output.  The offsets
40  * in the local symbol table for externally defined symbols are recorded
41  * since relocation information refers to symbols in this way.
42  * Armed with all necessary information, the text and data segments
43  * are relocated and the result is placed in the output file, which
44  * is pasted together, ``in place'', by writing to it in several
45  * different places concurrently.
46  */
47 
48 /*
49  * Internal data structures
50  *
51  * All internal data structures are segmented and dynamically extended.
52  * The basic structures hold 1103 (NSYM) symbols, ~~200 (NROUT)
53  * referenced library members, and 100 (NSYMPR) private (local) symbols
54  * per object module.  For large programs and/or modules, these structures
55  * expand to be up to 40 (NSEG) times as large as this as necessary.
56  */
57 #define	NSEG	40		/* Number of segments, each data structure */
58 #define	NSYM	1103		/* Number of symbols per segment */
59 #define	NROUT	250		/* Number of library references per segment */
60 #define	NSYMPR	100		/* Number of private symbols per segment */
61 
62 /*
63  * Structure describing each symbol table segment.
64  * Each segment has its own hash table.  We record the first
65  * address in and first address beyond both the symbol and hash
66  * tables, for use in the routine symx and the lookup routine respectively.
67  * The symfree routine also understands this structure well as it used
68  * to back out symbols from modules we decide that we don't need in pass 1.
69  *
70  * Csymseg points to the current symbol table segment;
71  * csymseg->sy_first[csymseg->sy_used] is the next symbol slot to be allocated,
72  * (unless csymseg->sy_used == NSYM in which case we will allocate another
73  * symbol table segment first.)
74  */
75 struct	symseg {
76 	struct	nlist *sy_first;	/* base of this alloc'ed segment */
77 	struct	nlist *sy_last;		/* end of this segment, for n_strx */
78 	int	sy_used;		/* symbols used in this seg */
79 	struct	nlist **sy_hfirst;	/* base of hash table, this seg */
80 	struct	nlist **sy_hlast;	/* end of hash table, this seg */
81 } symseg[NSEG], *csymseg;
82 
83 /*
84  * The lookup routine uses quadratic rehash.  Since a quadratic rehash
85  * only probes 1/2 of the buckets in the table, and since the hash
86  * table is segmented the same way the symbol table is, we make the
87  * hash table have twice as many buckets as there are symbol table slots
88  * in the segment.  This guarantees that the quadratic rehash will never
89  * fail to find an empty bucket if the segment is not full and the
90  * symbol is not there.
91  */
92 #define	HSIZE	(NSYM*2)
93 
94 /*
95  * Xsym converts symbol table indices (ala x) into symbol table pointers.
96  * Symx (harder, but never used in loops) inverts pointers into the symbol
97  * table into indices using the symseg[] structure.
98  */
99 #define	xsym(x)	(symseg[(x)/NSYM].sy_first+((x)%NSYM))
100 /* symx() is a function, defined below */
101 
102 struct	nlist cursym;		/* current symbol */
103 struct	nlist *lastsym;		/* last symbol entered */
104 struct	nlist *nextsym;		/* next available symbol table entry */
105 struct	nlist *addsym;		/* first sym defined during incr load */
106 int	nsym;			/* pass2: number of local symbols in a.out */
107 /* nsym + symx(nextsym) is the symbol table size during pass2 */
108 
109 struct	nlist **lookup(), **slookup();
110 struct	nlist *p_etext, *p_edata, *p_end, *entrypt;
111 
112 /*
113  * Definitions of segmentation for library member table.
114  * For each library we encounter on pass 1 we record pointers to all
115  * members which we will load on pass 2.  These are recorded as offsets
116  * into the archive in the library member table.  Libraries are
117  * separated in the table by the special offset value -1.
118  */
119 off_t	li_init[NROUT];
120 struct	libseg {
121 	off_t	*li_first;
122 	int	li_used;
123 	int	li_used2;
124 } libseg[NSEG] = {
125 	li_init, 0, 0,
126 }, *clibseg = libseg;
127 
128 /*
129  * In processing each module on pass 2 we must relocate references
130  * relative to external symbols.  These references are recorded
131  * in the relocation information as relative to local symbol numbers
132  * assigned to the external symbols when the module was created.
133  * Thus before relocating the module in pass 2 we create a table
134  * which maps these internal numbers to symbol table entries.
135  * A hash table is constructed, based on the local symbol table indices,
136  * for quick lookup of these symbols.
137  */
138 #define	LHSIZ	31
139 struct	local {
140 	int	l_index;		/* index to symbol in file */
141 	struct	nlist *l_symbol;	/* ptr to symbol table */
142 	struct	local *l_link;		/* hash link */
143 } *lochash[LHSIZ], lhinit[NSYMPR];
144 struct	locseg {
145 	struct	local *lo_first;
146 	int	lo_used;
147 } locseg[NSEG] = {
148 	lhinit, 0
149 }, *clocseg;
150 
151 /*
152  * Libraries are typically built with a table of contents,
153  * which is the first member of a library with special file
154  * name __.SYMDEF and contains a list of symbol names
155  * and with each symbol the offset of the library member which defines
156  * it.  The loader uses this table to quickly tell which library members
157  * are (potentially) useful.  The alternative, examining the symbol
158  * table of each library member, is painfully slow for large archives.
159  *
160  * See <ranlib.h> for the definition of the ranlib structure and an
161  * explanation of the __.SYMDEF file format.
162  */
163 int	tnum;		/* number of symbols in table of contents */
164 int	ssiz;		/* size of string table for table of contents */
165 struct	ranlib *tab;	/* the table of contents (dynamically allocated) */
166 char	*tabstr;	/* string table for table of contents */
167 
168 /*
169  * We open each input file or library only once, but in pass2 we
170  * (historically) read from such a file at 2 different places at the
171  * same time.  These structures are remnants from those days,
172  * and now serve only to catch ``Premature EOF''.
173  */
174 typedef struct {
175 	short	*fakeptr;
176 	int	bno;
177 	int	nibuf;
178 	int	nuser;
179 	char	buff[BSIZE];
180 } PAGE;
181 
182 PAGE	page[2];
183 
184 struct {
185 	short	*fakeptr;
186 	int	bno;
187 	int	nibuf;
188 	int	nuser;
189 } fpage;
190 
191 typedef struct {
192 	char	*ptr;
193 	int	bno;
194 	int	nibuf;
195 	long	size;
196 	long	pos;
197 	PAGE	*pno;
198 } STREAM;
199 
200 STREAM	text;
201 STREAM	reloc;
202 
203 /*
204  * Header from the a.out and the archive it is from (if any).
205  */
206 struct	exec filhdr;
207 struct	ar_hdr archdr;
208 #define	OARMAG 0177545
209 
210 /*
211  * Options.
212  */
213 int	trace;
214 int	xflag;		/* discard local symbols */
215 int	Xflag;		/* discard locals starting with 'L' */
216 int	Sflag;		/* discard all except locals and globals*/
217 int	rflag;		/* preserve relocation bits, don't define common */
218 int	arflag;		/* original copy of rflag */
219 int	sflag;		/* discard all symbols */
220 int	Mflag;		/* print rudimentary load map */
221 int	nflag;		/* pure procedure */
222 int	dflag;		/* define common even with rflag */
223 int	zflag;		/* demand paged  */
224 long	hsize;		/* size of hole at beginning of data to be squashed */
225 int	Aflag;		/* doing incremental load */
226 int	Nflag;		/* want impure a.out */
227 int	funding;	/* reading fundamental file for incremental load */
228 int	yflag;		/* number of symbols to be traced */
229 char	**ytab;		/* the symbols */
230 
231 /*
232  * These are the cumulative sizes, set in pass 1, which
233  * appear in the a.out header when the loader is finished.
234  */
235 off_t	tsize, dsize, bsize, trsize, drsize, ssize;
236 
237 /*
238  * Symbol relocation: c?rel is a scale factor which is
239  * added to an old relocation to convert it to new units;
240  * i.e. it is the difference between segment origins.
241  * (Thus if we are loading from a data segment which began at location
242  * 4 in a .o file into an a.out where it will be loaded starting at
243  * 1024, cdrel will be 1020.)
244  */
245 long	ctrel, cdrel, cbrel;
246 
247 /*
248  * Textbase is the start address of all text, 0 unless given by -T.
249  * Database is the base of all data, computed before and used during pass2.
250  */
251 long	textbase, database;
252 
253 /*
254  * The base addresses for the loaded text, data and bss from the
255  * current module during pass2 are given by torigin, dorigin and borigin.
256  */
257 long	torigin, dorigin, borigin;
258 
259 /*
260  * Errlev is nonzero when errors have occured.
261  * Delarg is an implicit argument to the routine delexit
262  * which is called on error.  We do ``delarg = errlev'' before normal
263  * exits, and only if delarg is 0 (i.e. errlev was 0) do we make the
264  * result file executable.
265  */
266 int	errlev;
267 int	delarg	= 4;
268 
269 /*
270  * The biobuf structure and associated routines are used to write
271  * into one file at several places concurrently.  Calling bopen
272  * with a biobuf structure sets it up to write ``biofd'' starting
273  * at the specified offset.  You can then use ``bwrite'' and/or ``bputc''
274  * to stuff characters in the stream, much like ``fwrite'' and ``fputc''.
275  * Calling bflush drains all the buffers and MUST be done before exit.
276  */
277 struct	biobuf {
278 	short	b_nleft;		/* Number free spaces left in b_buf */
279 /* Initialize to be less than BUFSIZ initially, to boundary align in file */
280 	char	*b_ptr;			/* Next place to stuff characters */
281 	char	b_buf[BUFSIZ];		/* The buffer itself */
282 	off_t	b_off;			/* Current file offset */
283 	struct	biobuf *b_link;		/* Link in chain for bflush() */
284 } *biobufs;
285 #define	bputc(c,b) ((b)->b_nleft ? (--(b)->b_nleft, *(b)->b_ptr++ = (c)) \
286 		       : bflushc(b, c))
287 int	biofd;
288 off_t	boffset;
289 struct	biobuf *tout, *dout, *trout, *drout, *sout, *strout;
290 
291 /*
292  * Offset is the current offset in the string file.
293  * Its initial value reflects the fact that we will
294  * eventually stuff the size of the string table at the
295  * beginning of the string table (i.e. offset itself!).
296  */
297 off_t	offset = sizeof (off_t);
298 
299 int	ofilfnd;		/* -o given; otherwise move l.out to a.out */
300 char	*ofilename = "l.out";
301 int	ofilemode;		/* respect umask even for unsucessful ld's */
302 int	infil;			/* current input file descriptor */
303 char	*filname;		/* and its name */
304 
305 /*
306  * Base of the string table of the current module (pass1 and pass2).
307  */
308 char	*curstr;
309 
310 char 	get();
311 int	delexit();
312 char	*savestr();
313 
314 main(argc, argv)
315 char **argv;
316 {
317 	register int c, i;
318 	int num;
319 	register char *ap, **p;
320 	char save;
321 
322 	if (signal(SIGINT, SIG_IGN) != SIG_IGN) {
323 		signal(SIGINT, delexit);
324 		signal(SIGTERM, delexit);
325 	}
326 	if (argc == 1)
327 		exit(4);
328 	p = argv+1;
329 
330 	/*
331 	 * Scan files once to find where symbols are defined.
332 	 */
333 	for (c=1; c<argc; c++) {
334 		if (trace)
335 			printf("%s:\n", *p);
336 		filname = 0;
337 		ap = *p++;
338 		if (*ap != '-') {
339 			load1arg(ap);
340 			continue;
341 		}
342 		for (i=1; ap[i]; i++) switch (ap[i]) {
343 
344 		case 'o':
345 			if (++c >= argc)
346 				error(1, "-o where?");
347 			ofilename = *p++;
348 			ofilfnd++;
349 			continue;
350 		case 'u':
351 		case 'e':
352 			if (++c >= argc)
353 				error(1, "-u or -c: arg missing");
354 			enter(slookup(*p++));
355 			if (ap[i]=='e')
356 				entrypt = lastsym;
357 			continue;
358 		case 'H':
359 			if (++c >= argc)
360 				error(1, "-H: arg missing");
361 			if (tsize!=0)
362 				error(1, "-H: too late, some text already loaded");
363 			hsize = atoi(*p++);
364 			continue;
365 		case 'A':
366 			if (++c >= argc)
367 				error(1, "-A: arg missing");
368 			if (Aflag)
369 				error(1, "-A: only one base file allowed");
370 			Aflag = 1;
371 			nflag = 0;
372 			funding = 1;
373 			load1arg(*p++);
374 			trsize = drsize = tsize = dsize = bsize = 0;
375 			ctrel = cdrel = cbrel = 0;
376 			funding = 0;
377 			addsym = nextsym;
378 			continue;
379 		case 'D':
380 			if (++c >= argc)
381 				error(1, "-D: arg missing");
382 			num = htoi(*p++);
383 			if (dsize > num)
384 				error(1, "-D: too small");
385 			dsize = num;
386 			continue;
387 		case 'T':
388 			if (++c >= argc)
389 				error(1, "-T: arg missing");
390 			if (tsize!=0)
391 				error(1, "-T: too late, some text already loaded");
392 			textbase = htoi(*p++);
393 			continue;
394 		case 'l':
395 			save = ap[--i];
396 			ap[i]='-';
397 			load1arg(&ap[i]);
398 			ap[i]=save;
399 			goto next;
400 		case 'M':
401 			Mflag++;
402 			continue;
403 		case 'x':
404 			xflag++;
405 			continue;
406 		case 'X':
407 			Xflag++;
408 			continue;
409 		case 'S':
410 			Sflag++;
411 			continue;
412 		case 'r':
413 			rflag++;
414 			arflag++;
415 			continue;
416 		case 's':
417 			sflag++;
418 			xflag++;
419 			continue;
420 		case 'n':
421 			nflag++;
422 			Nflag = zflag = 0;
423 			continue;
424 		case 'N':
425 			Nflag++;
426 			nflag = zflag = 0;
427 			continue;
428 		case 'd':
429 			dflag++;
430 			continue;
431 		case 'i':
432 			printf("ld: -i ignored\n");
433 			continue;
434 		case 't':
435 			trace++;
436 			continue;
437 		case 'y':
438 			if (ap[i+1] == 0)
439 				error(1, "-y: symbol name missing");
440 			if (yflag == 0) {
441 				ytab = (char **)calloc(argc, sizeof (char **));
442 				if (ytab == 0)
443 					error(1, "ran out of memory (-y)");
444 			}
445 			ytab[yflag++] = &ap[i+1];
446 			goto next;
447 		case 'z':
448 			zflag++;
449 			Nflag = nflag = 0;
450 			continue;
451 		default:
452 			filname = savestr("-x");	/* kludge */
453 			filname[1] = ap[i];		/* kludge */
454 			archdr.ar_name[0] = 0;		/* kludge */
455 			error(1, "bad flag");
456 		}
457 next:
458 		;
459 	}
460 	if (rflag == 0 && Nflag == 0 && nflag == 0)
461 		zflag++;
462 	endload(argc, argv);
463 	exit(0);
464 }
465 
466 /*
467  * Convert a ascii string which is a hex number.
468  * Used by -T and -D options.
469  */
470 htoi(p)
471 	register char *p;
472 {
473 	register int c, n;
474 
475 	n = 0;
476 	while (c = *p++) {
477 		n <<= 4;
478 		if (isdigit(c))
479 			n += c - '0';
480 		else if (c >= 'a' && c <= 'f')
481 			n += 10 + (c - 'a');
482 		else if (c >= 'A' && c <= 'F')
483 			n += 10 + (c - 'A');
484 		else
485 			error(1, "badly formed hex number");
486 	}
487 	return (n);
488 }
489 
490 delexit()
491 {
492 
493 	bflush();
494 	unlink("l.out");
495 	if (delarg==0 && Aflag==0)
496 		chmod(ofilename, ofilemode);
497 	exit (delarg);
498 }
499 
500 endload(argc, argv)
501 	int argc;
502 	char **argv;
503 {
504 	register int c, i;
505 	long dnum;
506 	register char *ap, **p;
507 
508 	clibseg = libseg;
509 	filname = 0;
510 	middle();
511 	setupout();
512 	p = argv+1;
513 	for (c=1; c<argc; c++) {
514 		ap = *p++;
515 		if (trace)
516 			printf("%s:\n", ap);
517 		if (*ap != '-') {
518 			load2arg(ap);
519 			continue;
520 		}
521 		for (i=1; ap[i]; i++) switch (ap[i]) {
522 
523 		case 'D':
524 			dnum = htoi(*p);
525 			if (dorigin < dnum)
526 				while (dorigin < dnum)
527 					bputc(0, dout), dorigin++;
528 			/* fall into ... */
529 		case 'T':
530 		case 'u':
531 		case 'e':
532 		case 'o':
533 		case 'H':
534 			++c;
535 			++p;
536 			/* fall into ... */
537 		default:
538 			continue;
539 		case 'A':
540 			funding = 1;
541 			load2arg(*p++);
542 			funding = 0;
543 			c++;
544 			continue;
545 		case 'y':
546 			goto next;
547 		case 'l':
548 			ap[--i]='-';
549 			load2arg(&ap[i]);
550 			goto next;
551 		}
552 next:
553 		;
554 	}
555 	finishout();
556 }
557 
558 /*
559  * Scan file to find defined symbols.
560  */
561 load1arg(cp)
562 	register char *cp;
563 {
564 	register struct ranlib *tp;
565 	off_t nloc;
566 	int kind;
567 
568 	kind = getfile(cp);
569 	if (Mflag)
570 		printf("%s\n", filname);
571 	switch (kind) {
572 
573 	/*
574 	 * Plain file.
575 	 */
576 	case 0:
577 		load1(0, 0L);
578 		break;
579 
580 	/*
581 	 * Archive without table of contents.
582 	 * (Slowly) process each member.
583 	 */
584 	case 1:
585 		error(-1,
586 "warning: archive has no table of contents; add one using ranlib(1)");
587 		nloc = SARMAG;
588 		while (step(nloc))
589 			nloc += sizeof(archdr) +
590 			    round(atol(archdr.ar_size), sizeof (short));
591 		break;
592 
593 	/*
594 	 * Archive with table of contents.
595 	 * Read the table of contents and its associated string table.
596 	 * Pass through the library resolving symbols until nothing changes
597 	 * for an entire pass (i.e. you can get away with backward references
598 	 * when there is a table of contents!)
599 	 */
600 	case 2:
601 		nloc = SARMAG + sizeof (archdr);
602 		dseek(&text, nloc, sizeof (tnum));
603 		mget((char *)&tnum, sizeof (tnum), &text);
604 		nloc += sizeof (tnum);
605 		tab = (struct ranlib *)malloc(tnum);
606 		if (tab == 0)
607 			error(1, "ran out of memory (toc)");
608 		dseek(&text, nloc, tnum);
609 		mget((char *)tab, tnum, &text);
610 		nloc += tnum;
611 		tnum /= sizeof (struct ranlib);
612 		dseek(&text, nloc, sizeof (ssiz));
613 		mget((char *)&ssiz, sizeof (ssiz), &text);
614 		nloc += sizeof (ssiz);
615 		tabstr = (char *)malloc(ssiz);
616 		if (tabstr == 0)
617 			error(1, "ran out of memory (tocstr)");
618 		dseek(&text, nloc, ssiz);
619 		mget((char *)tabstr, ssiz, &text);
620 		for (tp = &tab[tnum]; --tp >= tab;) {
621 			if (tp->ran_un.ran_strx < 0 ||
622 			    tp->ran_un.ran_strx >= ssiz)
623 				error(1, "mangled archive table of contents");
624 			tp->ran_un.ran_name = tabstr + tp->ran_un.ran_strx;
625 		}
626 		while (ldrand())
627 			continue;
628 		cfree((char *)tab);
629 		cfree(tabstr);
630 		nextlibp(-1);
631 		break;
632 
633 	/*
634 	 * Table of contents is out of date, so search
635 	 * as a normal library (but skip the __.SYMDEF file).
636 	 */
637 	case 3:
638 		error(-1,
639 "warning: table of contents for archive is out of date; rerun ranlib(1)");
640 		nloc = SARMAG;
641 		do
642 			nloc += sizeof(archdr) +
643 			    round(atol(archdr.ar_size), sizeof(short));
644 		while (step(nloc));
645 		break;
646 	}
647 	close(infil);
648 }
649 
650 /*
651  * Advance to the next archive member, which
652  * is at offset nloc in the archive.  If the member
653  * is useful, record its location in the liblist structure
654  * for use in pass2.  Mark the end of the archive in libilst with a -1.
655  */
656 step(nloc)
657 	off_t nloc;
658 {
659 
660 	dseek(&text, nloc, (long) sizeof archdr);
661 	if (text.size <= 0) {
662 		nextlibp(-1);
663 		return (0);
664 	}
665 	getarhdr();
666 	if (load1(1, nloc + (sizeof archdr)))
667 		nextlibp(nloc);
668 	return (1);
669 }
670 
671 /*
672  * Record the location of a useful archive member.
673  * Recording -1 marks the end of files from an archive.
674  * The liblist data structure is dynamically extended here.
675  */
676 nextlibp(val)
677 	off_t val;
678 {
679 
680 	if (clibseg->li_used == NROUT) {
681 		if (++clibseg == &libseg[NSEG])
682 			error(1, "too many files loaded from libraries");
683 		clibseg->li_first = (off_t *)malloc(NROUT * sizeof (off_t));
684 		if (clibseg->li_first == 0)
685 			error(1, "ran out of memory (nextlibp)");
686 	}
687 	clibseg->li_first[clibseg->li_used++] = val;
688 	if (val != -1 && Mflag)
689 		printf("\t%s\n", archdr.ar_name);
690 }
691 
692 /*
693  * One pass over an archive with a table of contents.
694  * Remember the number of symbols currently defined,
695  * then call step on members which look promising (i.e.
696  * that define a symbol which is currently externally undefined).
697  * Indicate to our caller whether this process netted any more symbols.
698  */
699 ldrand()
700 {
701 	register struct nlist *sp, **hp;
702 	register struct ranlib *tp, *tplast;
703 	off_t loc;
704 	int nsymt = symx(nextsym);
705 
706 	tplast = &tab[tnum-1];
707 	for (tp = tab; tp <= tplast; tp++) {
708 		if ((hp = slookup(tp->ran_un.ran_name)) == 0)
709 			continue;
710 		sp = *hp;
711 		if (sp->n_type != N_EXT+N_UNDF)
712 			continue;
713 		step(tp->ran_off);
714 		loc = tp->ran_off;
715 		while (tp < tplast && (tp+1)->ran_off == loc)
716 			tp++;
717 	}
718 	return (symx(nextsym) != nsymt);
719 }
720 
721 /*
722  * Examine a single file or archive member on pass 1.
723  */
724 load1(libflg, loc)
725 	off_t loc;
726 {
727 	register struct nlist *sp;
728 	struct nlist *savnext;
729 	int ndef, nlocal, type, size, nsymt;
730 	register int i;
731 	off_t maxoff;
732 	struct stat stb;
733 
734 	readhdr(loc);
735 	if (filhdr.a_syms == 0) {
736 		if (filhdr.a_text+filhdr.a_data == 0)
737 			return (0);
738 		error(1, "no namelist");
739 	}
740 	if (libflg)
741 		maxoff = atol(archdr.ar_size);
742 	else {
743 		fstat(infil, &stb);
744 		maxoff = stb.st_size;
745 	}
746 	if (N_STROFF(filhdr) + sizeof (off_t) >= maxoff)
747 		error(1, "too small (old format .o?)");
748 	ctrel = tsize; cdrel += dsize; cbrel += bsize;
749 	ndef = 0;
750 	nlocal = sizeof(cursym);
751 	savnext = nextsym;
752 	loc += N_SYMOFF(filhdr);
753 	dseek(&text, loc, filhdr.a_syms);
754 	dseek(&reloc, loc + filhdr.a_syms, sizeof(off_t));
755 	mget(&size, sizeof (size), &reloc);
756 	dseek(&reloc, loc + filhdr.a_syms+sizeof (off_t), size-sizeof (off_t));
757 	curstr = (char *)malloc(size);
758 	if (curstr == NULL)
759 		error(1, "no space for string table");
760 	mget(curstr+sizeof(off_t), size-sizeof(off_t), &reloc);
761 	while (text.size > 0) {
762 		mget((char *)&cursym, sizeof(struct nlist), &text);
763 		if (cursym.n_un.n_strx) {
764 			if (cursym.n_un.n_strx<sizeof(size) ||
765 			    cursym.n_un.n_strx>=size)
766 				error(1, "bad string table index (pass 1)");
767 			cursym.n_un.n_name = curstr + cursym.n_un.n_strx;
768 		}
769 		type = cursym.n_type;
770 		if ((type&N_EXT)==0) {
771 			if (Xflag==0 || cursym.n_un.n_name[0]!='L' ||
772 			    type & N_STAB)
773 				nlocal += sizeof cursym;
774 			continue;
775 		}
776 		symreloc();
777 		if (enter(lookup()))
778 			continue;
779 		if ((sp = lastsym)->n_type != N_EXT+N_UNDF)
780 			continue;
781 		if (cursym.n_type == N_EXT+N_UNDF) {
782 			if (cursym.n_value > sp->n_value)
783 				sp->n_value = cursym.n_value;
784 			continue;
785 		}
786 		if (sp->n_value != 0 && cursym.n_type == N_EXT+N_TEXT)
787 			continue;
788 		ndef++;
789 		sp->n_type = cursym.n_type;
790 		sp->n_value = cursym.n_value;
791 	}
792 	if (libflg==0 || ndef) {
793 		tsize += filhdr.a_text;
794 		dsize += round(filhdr.a_data, sizeof (long));
795 		bsize += round(filhdr.a_bss, sizeof (long));
796 		ssize += nlocal;
797 		trsize += filhdr.a_trsize;
798 		drsize += filhdr.a_drsize;
799 		if (funding)
800 			textbase = (*slookup("_end"))->n_value;
801 		nsymt = symx(nextsym);
802 		for (i = symx(savnext); i < nsymt; i++) {
803 			sp = xsym(i);
804 			sp->n_un.n_name = savestr(sp->n_un.n_name);
805 		}
806 		free(curstr);
807 		return (1);
808 	}
809 	/*
810 	 * No symbols defined by this library member.
811 	 * Rip out the hash table entries and reset the symbol table.
812 	 */
813 	symfree(savnext);
814 	free(curstr);
815 	return(0);
816 }
817 
818 middle()
819 {
820 	register struct nlist *sp;
821 	long csize, t, corigin, ocsize;
822 	int nund, rnd;
823 	char s;
824 	register int i;
825 	int nsymt;
826 
827 	torigin = 0;
828 	dorigin = 0;
829 	borigin = 0;
830 
831 	p_etext = *slookup("_etext");
832 	p_edata = *slookup("_edata");
833 	p_end = *slookup("_end");
834 	/*
835 	 * If there are any undefined symbols, save the relocation bits.
836 	 */
837 	nsymt = symx(nextsym);
838 	if (rflag==0) {
839 		for (i = 0; i < nsymt; i++) {
840 			sp = xsym(i);
841 			if (sp->n_type==N_EXT+N_UNDF && sp->n_value==0 &&
842 			    sp!=p_end && sp!=p_edata && sp!=p_etext) {
843 				rflag++;
844 				dflag = 0;
845 				break;
846 			}
847 		}
848 	}
849 	if (rflag)
850 		sflag = zflag = 0;
851 	/*
852 	 * Assign common locations.
853 	 */
854 	csize = 0;
855 	if (!Aflag)
856 		addsym = symseg[0].sy_first;
857 	database = round(tsize+textbase,
858 	    (nflag||zflag? PAGSIZ : sizeof (long)));
859 	database += hsize;
860 	if (dflag || rflag==0) {
861 		ldrsym(p_etext, tsize, N_EXT+N_TEXT);
862 		ldrsym(p_edata, dsize, N_EXT+N_DATA);
863 		ldrsym(p_end, bsize, N_EXT+N_BSS);
864 		for (i = symx(addsym); i < nsymt; i++) {
865 			sp = xsym(i);
866 			if ((s=sp->n_type)==N_EXT+N_UNDF &&
867 			    (t = sp->n_value)!=0) {
868 				if (t >= sizeof (double))
869 					rnd = sizeof (double);
870 				else if (t >= sizeof (long))
871 					rnd = sizeof (long);
872 				else
873 					rnd = sizeof (short);
874 				csize = round(csize, rnd);
875 				sp->n_value = csize;
876 				sp->n_type = N_EXT+N_COMM;
877 				ocsize = csize;
878 				csize += t;
879 			}
880 			if (s&N_EXT && (s&N_TYPE)==N_UNDF && s&N_STAB) {
881 				sp->n_value = ocsize;
882 				sp->n_type = (s&N_STAB) | (N_EXT+N_COMM);
883 			}
884 		}
885 	}
886 	/*
887 	 * Now set symbols to their final value
888 	 */
889 	csize = round(csize, sizeof (long));
890 	torigin = textbase;
891 	dorigin = database;
892 	corigin = dorigin + dsize;
893 	borigin = corigin + csize;
894 	nund = 0;
895 	nsymt = symx(nextsym);
896 	for (i = symx(addsym); i<nsymt; i++) {
897 		sp = xsym(i);
898 		switch (sp->n_type & (N_TYPE+N_EXT)) {
899 
900 		case N_EXT+N_UNDF:
901 			if (arflag == 0)
902 				errlev |= 01;
903 			if ((arflag==0 || dflag) && sp->n_value==0) {
904 				if (sp==p_end || sp==p_etext || sp==p_edata)
905 					continue;
906 				if (nund==0)
907 					printf("Undefined:\n");
908 				nund++;
909 				printf("%s\n", sp->n_un.n_name);
910 			}
911 			continue;
912 		case N_EXT+N_ABS:
913 		default:
914 			continue;
915 		case N_EXT+N_TEXT:
916 			sp->n_value += torigin;
917 			continue;
918 		case N_EXT+N_DATA:
919 			sp->n_value += dorigin;
920 			continue;
921 		case N_EXT+N_BSS:
922 			sp->n_value += borigin;
923 			continue;
924 		case N_EXT+N_COMM:
925 			sp->n_type = (sp->n_type & N_STAB) | (N_EXT+N_BSS);
926 			sp->n_value += corigin;
927 			continue;
928 		}
929 	}
930 	if (sflag || xflag)
931 		ssize = 0;
932 	bsize += csize;
933 	nsym = ssize / (sizeof cursym);
934 	if (Aflag) {
935 		fixspec(p_etext,torigin);
936 		fixspec(p_edata,dorigin);
937 		fixspec(p_end,borigin);
938 	}
939 }
940 
941 fixspec(sym,offset)
942 	struct nlist *sym;
943 	long offset;
944 {
945 
946 	if(symx(sym) < symx(addsym) && sym!=0)
947 		sym->n_value += offset;
948 }
949 
950 ldrsym(sp, val, type)
951 	register struct nlist *sp;
952 	long val;
953 {
954 
955 	if (sp == 0)
956 		return;
957 	if ((sp->n_type != N_EXT+N_UNDF || sp->n_value) && !Aflag) {
958 		printf("%s: ", sp->n_un.n_name);
959 		error(0, "user attempt to redfine loader-defined symbol");
960 		return;
961 	}
962 	sp->n_type = type;
963 	sp->n_value = val;
964 }
965 
966 off_t	wroff;
967 struct	biobuf toutb;
968 
969 setupout()
970 {
971 	int bss;
972 	extern char *sys_errlist[];
973 	extern int errno;
974 
975 	ofilemode = 0777 & ~umask(0);
976 	biofd = creat(ofilename, 0666 & ofilemode);
977 	if (biofd < 0) {
978 		filname = ofilename;		/* kludge */
979 		archdr.ar_name[0] = 0;		/* kludge */
980 		error(1, sys_errlist[errno]);	/* kludge */
981 	} else {
982 		struct stat mybuf;		/* kls kludge */
983 		fstat(biofd, &mybuf);		/* suppose file exists, wrong*/
984 		if(mybuf.st_mode & 0111) {	/* mode, ld fails? */
985 			chmod(ofilename, mybuf.st_mode & 0666);
986 			ofilemode = mybuf.st_mode;
987 		}
988 	}
989 	tout = &toutb;
990 	bopen(tout, 0);
991 	filhdr.a_magic = nflag ? NMAGIC : (zflag ? ZMAGIC : OMAGIC);
992 	filhdr.a_text = nflag ? tsize :
993 	    round(tsize, zflag ? PAGSIZ : sizeof (long));
994 	filhdr.a_data = zflag ? round(dsize, PAGSIZ) : dsize;
995 	bss = bsize - (filhdr.a_data - dsize);
996 	if (bss < 0)
997 		bss = 0;
998 	filhdr.a_bss = bss;
999 	filhdr.a_trsize = trsize;
1000 	filhdr.a_drsize = drsize;
1001 	filhdr.a_syms = sflag? 0: (ssize + (sizeof cursym)*symx(nextsym));
1002 	if (entrypt) {
1003 		if (entrypt->n_type!=N_EXT+N_TEXT)
1004 			error(0, "entry point not in text");
1005 		else
1006 			filhdr.a_entry = entrypt->n_value;
1007 	} else
1008 		filhdr.a_entry = 0;
1009 	filhdr.a_trsize = (rflag ? trsize:0);
1010 	filhdr.a_drsize = (rflag ? drsize:0);
1011 	bwrite((char *)&filhdr, sizeof (filhdr), tout);
1012 	if (zflag) {
1013 		bflush1(tout);
1014 		biobufs = 0;
1015 		bopen(tout, PAGSIZ);
1016 	}
1017 	wroff = N_TXTOFF(filhdr) + filhdr.a_text;
1018 	outb(&dout, filhdr.a_data);
1019 	if (rflag) {
1020 		outb(&trout, filhdr.a_trsize);
1021 		outb(&drout, filhdr.a_drsize);
1022 	}
1023 	if (sflag==0 || xflag==0) {
1024 		outb(&sout, filhdr.a_syms);
1025 		wroff += sizeof (offset);
1026 		outb(&strout, 0);
1027 	}
1028 }
1029 
1030 outb(bp, inc)
1031 	register struct biobuf **bp;
1032 {
1033 
1034 	*bp = (struct biobuf *)malloc(sizeof (struct biobuf));
1035 	if (*bp == 0)
1036 		error(1, "ran out of memory (outb)");
1037 	bopen(*bp, wroff);
1038 	wroff += inc;
1039 }
1040 
1041 load2arg(acp)
1042 char *acp;
1043 {
1044 	register char *cp;
1045 	off_t loc;
1046 
1047 	cp = acp;
1048 	if (getfile(cp) == 0) {
1049 		while (*cp)
1050 			cp++;
1051 		while (cp >= acp && *--cp != '/');
1052 		mkfsym(++cp);
1053 		load2(0L);
1054 	} else {	/* scan archive members referenced */
1055 		for (;;) {
1056 			if (clibseg->li_used2 == clibseg->li_used) {
1057 				if (clibseg->li_used < NROUT)
1058 					error(1, "libseg botch");
1059 				clibseg++;
1060 			}
1061 			loc = clibseg->li_first[clibseg->li_used2++];
1062 			if (loc == -1)
1063 				break;
1064 			dseek(&text, loc, (long)sizeof(archdr));
1065 			getarhdr();
1066 			mkfsym(archdr.ar_name);
1067 			load2(loc + (long)sizeof(archdr));
1068 		}
1069 	}
1070 	close(infil);
1071 }
1072 
1073 load2(loc)
1074 long loc;
1075 {
1076 	int size;
1077 	register struct nlist *sp;
1078 	register struct local *lp;
1079 	register int symno, i;
1080 	int type;
1081 
1082 	readhdr(loc);
1083 	if (!funding) {
1084 		ctrel = torigin;
1085 		cdrel += dorigin;
1086 		cbrel += borigin;
1087 	}
1088 	/*
1089 	 * Reread the symbol table, recording the numbering
1090 	 * of symbols for fixing external references.
1091 	 */
1092 	for (i = 0; i < LHSIZ; i++)
1093 		lochash[i] = 0;
1094 	clocseg = locseg;
1095 	clocseg->lo_used = 0;
1096 	symno = -1;
1097 	loc += N_TXTOFF(filhdr);
1098 	dseek(&text, loc+filhdr.a_text+filhdr.a_data+
1099 		filhdr.a_trsize+filhdr.a_drsize+filhdr.a_syms, sizeof(off_t));
1100 	mget(&size, sizeof(size), &text);
1101 	dseek(&text, loc+filhdr.a_text+filhdr.a_data+
1102 		filhdr.a_trsize+filhdr.a_drsize+filhdr.a_syms+sizeof(off_t),
1103 		size - sizeof(off_t));
1104 	curstr = (char *)malloc(size);
1105 	if (curstr == NULL)
1106 		error(1, "out of space reading string table (pass 2)");
1107 	mget(curstr+sizeof(off_t), size-sizeof(off_t), &text);
1108 	dseek(&text, loc+filhdr.a_text+filhdr.a_data+
1109 		filhdr.a_trsize+filhdr.a_drsize, filhdr.a_syms);
1110 	while (text.size > 0) {
1111 		symno++;
1112 		mget((char *)&cursym, sizeof(struct nlist), &text);
1113 		if (cursym.n_un.n_strx) {
1114 			if (cursym.n_un.n_strx<sizeof(size) ||
1115 			    cursym.n_un.n_strx>=size)
1116 				error(1, "bad string table index (pass 2)");
1117 			cursym.n_un.n_name = curstr + cursym.n_un.n_strx;
1118 		}
1119 /* inline expansion of symreloc() */
1120 		switch (cursym.n_type & 017) {
1121 
1122 		case N_TEXT:
1123 		case N_EXT+N_TEXT:
1124 			cursym.n_value += ctrel;
1125 			break;
1126 		case N_DATA:
1127 		case N_EXT+N_DATA:
1128 			cursym.n_value += cdrel;
1129 			break;
1130 		case N_BSS:
1131 		case N_EXT+N_BSS:
1132 			cursym.n_value += cbrel;
1133 			break;
1134 		case N_EXT+N_UNDF:
1135 			break;
1136 		default:
1137 			if (cursym.n_type&N_EXT)
1138 				cursym.n_type = N_EXT+N_ABS;
1139 		}
1140 /* end inline expansion of symreloc() */
1141 		type = cursym.n_type;
1142 		if (yflag && cursym.n_un.n_name)
1143 			for (i = 0; i < yflag; i++)
1144 				/* fast check for 2d character! */
1145 				if (ytab[i][1] == cursym.n_un.n_name[1] &&
1146 				    !strcmp(ytab[i], cursym.n_un.n_name)) {
1147 					tracesym();
1148 					break;
1149 				}
1150 		if ((type&N_EXT) == 0) {
1151 			if (!sflag&&!xflag&&
1152 			    (!Xflag||cursym.n_un.n_name[0]!='L'||type&N_STAB))
1153 				symwrite(&cursym, sout);
1154 			continue;
1155 		}
1156 		if (funding)
1157 			continue;
1158 		if ((sp = *lookup()) == 0)
1159 			error(1, "internal error: symbol not found");
1160 		if (cursym.n_type == N_EXT+N_UNDF) {
1161 			if (clocseg->lo_used == NSYMPR) {
1162 				if (++clocseg == &locseg[NSEG])
1163 					error(1, "local symbol overflow");
1164 				clocseg->lo_used = 0;
1165 			}
1166 			if (clocseg->lo_first == 0) {
1167 				clocseg->lo_first = (struct local *)
1168 				    malloc(NSYMPR * sizeof (struct local));
1169 				if (clocseg->lo_first == 0)
1170 					error(1, "out of memory (clocseg)");
1171 			}
1172 			lp = &clocseg->lo_first[clocseg->lo_used++];
1173 			lp->l_index = symno;
1174 			lp->l_symbol = sp;
1175 			lp->l_link = lochash[symno % LHSIZ];
1176 			lochash[symno % LHSIZ] = lp;
1177 			continue;
1178 		}
1179 		if (cursym.n_type & N_STAB)
1180 			continue;
1181 		if (cursym.n_type!=sp->n_type || cursym.n_value!=sp->n_value) {
1182 			printf("%s: ", cursym.n_un.n_name);
1183 			error(0, "multiply defined");
1184 		}
1185 	}
1186 	if (funding)
1187 		return;
1188 	dseek(&text, loc, filhdr.a_text);
1189 	dseek(&reloc, loc+filhdr.a_text+filhdr.a_data, filhdr.a_trsize);
1190 	load2td(ctrel, torigin - textbase, tout, trout);
1191 	dseek(&text, loc+filhdr.a_text, filhdr.a_data);
1192 	dseek(&reloc, loc+filhdr.a_text+filhdr.a_data+filhdr.a_trsize,
1193 	    filhdr.a_drsize);
1194 	load2td(cdrel, dorigin - database, dout, drout);
1195 	while (filhdr.a_data & (sizeof(long)-1)) {
1196 		bputc(0, dout);
1197 		filhdr.a_data++;
1198 	}
1199 	torigin += filhdr.a_text;
1200 	dorigin += round(filhdr.a_data, sizeof (long));
1201 	borigin += round(filhdr.a_bss, sizeof (long));
1202 	free(curstr);
1203 }
1204 
1205 struct tynames {
1206 	int	ty_value;
1207 	char	*ty_name;
1208 } tynames[] = {
1209 	N_UNDF,	"undefined",
1210 	N_ABS,	"absolute",
1211 	N_TEXT,	"text",
1212 	N_DATA,	"data",
1213 	N_BSS,	"bss",
1214 	N_COMM,	"common",
1215 	0,	0,
1216 };
1217 
1218 tracesym()
1219 {
1220 	register struct tynames *tp;
1221 
1222 	if (cursym.n_type & N_STAB)
1223 		return;
1224 	printf("%s", filname);
1225 	if (archdr.ar_name[0])
1226 		printf("(%s)", archdr.ar_name);
1227 	printf(": ");
1228 	if ((cursym.n_type&N_TYPE) == N_UNDF && cursym.n_value) {
1229 		printf("definition of common %s size %d\n",
1230 		    cursym.n_un.n_name, cursym.n_value);
1231 		return;
1232 	}
1233 	for (tp = tynames; tp->ty_name; tp++)
1234 		if (tp->ty_value == (cursym.n_type&N_TYPE))
1235 			break;
1236 	printf((cursym.n_type&N_TYPE) ? "definition of" : "reference to");
1237 	if (cursym.n_type&N_EXT)
1238 		printf(" external");
1239 	if (tp->ty_name)
1240 		printf(" %s", tp->ty_name);
1241 	printf(" %s\n", cursym.n_un.n_name);
1242 }
1243 
1244 /*
1245  * This routine relocates the single text or data segment argument.
1246  * Offsets from external symbols are resolved by adding the value
1247  * of the external symbols.  Non-external reference are updated to account
1248  * for the relative motion of the segments (ctrel, cdrel, ...).  If
1249  * a relocation was pc-relative, then we update it to reflect the
1250  * change in the positioning of the segments by adding the displacement
1251  * of the referenced segment and subtracting the displacement of the
1252  * current segment (creloc).
1253  *
1254  * If we are saving the relocation information, then we increase
1255  * each relocation datum address by our base position in the new segment.
1256  */
1257 load2td(creloc, position, b1, b2)
1258 	long creloc, offset;
1259 	struct biobuf *b1, *b2;
1260 {
1261 	register struct nlist *sp;
1262 	register struct local *lp;
1263 	long tw;
1264 	register struct relocation_info *rp, *rpend;
1265 	struct relocation_info *relp;
1266 	char *codep;
1267 	register char *cp;
1268 	int relsz, codesz;
1269 
1270 	relsz = reloc.size;
1271 	relp = (struct relocation_info *)malloc(relsz);
1272 	codesz = text.size;
1273 	codep = (char *)malloc(codesz);
1274 	if (relp == 0 || codep == 0)
1275 		error(1, "out of memory (load2td)");
1276 	mget((char *)relp, relsz, &reloc);
1277 	rpend = &relp[relsz / sizeof (struct relocation_info)];
1278 	mget(codep, codesz, &text);
1279 	for (rp = relp; rp < rpend; rp++) {
1280 		cp = codep + rp->r_address;
1281 		/*
1282 		 * Pick up previous value at location to be relocated.
1283 		 */
1284 		switch (rp->r_length) {
1285 
1286 		case 0:		/* byte */
1287 			tw = *cp;
1288 			break;
1289 
1290 		case 1:		/* word */
1291 			tw = *(short *)cp;
1292 			break;
1293 
1294 		case 2:		/* long */
1295 			tw = *(long *)cp;
1296 			break;
1297 
1298 		default:
1299 			error(1, "load2td botch: bad length");
1300 		}
1301 		/*
1302 		 * If relative to an external which is defined,
1303 		 * resolve to a simpler kind of reference in the
1304 		 * result file.  If the external is undefined, just
1305 		 * convert the symbol number to the number of the
1306 		 * symbol in the result file and leave it undefined.
1307 		 */
1308 		if (rp->r_extern) {
1309 			/*
1310 			 * Search the hash table which maps local
1311 			 * symbol numbers to symbol tables entries
1312 			 * in the new a.out file.
1313 			 */
1314 			lp = lochash[rp->r_symbolnum % LHSIZ];
1315 			while (lp->l_index != rp->r_symbolnum) {
1316 				lp = lp->l_link;
1317 				if (lp == 0)
1318 					error(1, "local symbol botch");
1319 			}
1320 			sp = lp->l_symbol;
1321 			if (sp->n_type == N_EXT+N_UNDF)
1322 				rp->r_symbolnum = nsym+symx(sp);
1323 			else {
1324 				rp->r_symbolnum = sp->n_type & N_TYPE;
1325 				tw += sp->n_value;
1326 				rp->r_extern = 0;
1327 			}
1328 		} else switch (rp->r_symbolnum & N_TYPE) {
1329 		/*
1330 		 * Relocation is relative to the loaded position
1331 		 * of another segment.  Update by the change in position
1332 		 * of that segment.
1333 		 */
1334 		case N_TEXT:
1335 			tw += ctrel;
1336 			break;
1337 		case N_DATA:
1338 			tw += cdrel;
1339 			break;
1340 		case N_BSS:
1341 			tw += cbrel;
1342 			break;
1343 		case N_ABS:
1344 			break;
1345 		default:
1346 			error(1, "relocation format botch (symbol type))");
1347 		}
1348 		/*
1349 		 * Relocation is pc relative, so decrease the relocation
1350 		 * by the amount the current segment is displaced.
1351 		 * (E.g if we are a relative reference to a text location
1352 		 * from data space, we added the increase in the text address
1353 		 * above, and subtract the increase in our (data) address
1354 		 * here, leaving the net change the relative change in the
1355 		 * positioning of our text and data segments.)
1356 		 */
1357 		if (rp->r_pcrel)
1358 			tw -= creloc;
1359 		/*
1360 		 * Put the value back in the segment,
1361 		 * while checking for overflow.
1362 		 */
1363 		switch (rp->r_length) {
1364 
1365 		case 0:		/* byte */
1366 			if (tw < -128 || tw > 127)
1367 				error(0, "byte displacement overflow");
1368 			*cp = tw;
1369 			break;
1370 		case 1:		/* word */
1371 			if (tw < -32768 || tw > 32767)
1372 				error(0, "word displacement overflow");
1373 			*(short *)cp = tw;
1374 			break;
1375 		case 2:		/* long */
1376 			*(long *)cp = tw;
1377 			break;
1378 		}
1379 		/*
1380 		 * If we are saving relocation information,
1381 		 * we must convert the address in the segment from
1382 		 * the old .o file into an address in the segment in
1383 		 * the new a.out, by adding the position of our
1384 		 * segment in the new larger segment.
1385 		 */
1386 		if (rflag)
1387 			rp->r_address += position;
1388 	}
1389 	bwrite(codep, codesz, b1);
1390 	if (rflag)
1391 		bwrite(relp, relsz, b2);
1392 	cfree((char *)relp);
1393 	cfree(codep);
1394 }
1395 
1396 finishout()
1397 {
1398 	register int i;
1399 	int nsymt;
1400 
1401 	if (sflag==0) {
1402 		nsymt = symx(nextsym);
1403 		for (i = 0; i < nsymt; i++)
1404 			symwrite(xsym(i), sout);
1405 		bwrite(&offset, sizeof offset, sout);
1406 	}
1407 	if (!ofilfnd) {
1408 		unlink("a.out");
1409 		if (link("l.out", "a.out") < 0)
1410 			error(1, "cannot move l.out to a.out");
1411 		ofilename = "a.out";
1412 	}
1413 	delarg = errlev;
1414 	delexit();
1415 }
1416 
1417 mkfsym(s)
1418 char *s;
1419 {
1420 
1421 	if (sflag || xflag)
1422 		return;
1423 	cursym.n_un.n_name = s;
1424 	cursym.n_type = N_TEXT;
1425 	cursym.n_value = torigin;
1426 	symwrite(&cursym, sout);
1427 }
1428 
1429 getarhdr()
1430 {
1431 	register char *cp;
1432 
1433 	mget((char *)&archdr, sizeof archdr, &text);
1434 	for (cp=archdr.ar_name; cp<&archdr.ar_name[sizeof(archdr.ar_name)];)
1435 		if (*cp++ == ' ') {
1436 			cp[-1] = 0;
1437 			return;
1438 		}
1439 }
1440 
1441 mget(loc, n, sp)
1442 register STREAM *sp;
1443 register char *loc;
1444 {
1445 	register char *p;
1446 	register int take;
1447 
1448 top:
1449 	if (n == 0)
1450 		return;
1451 	if (sp->size && sp->nibuf) {
1452 		p = sp->ptr;
1453 		take = sp->size;
1454 		if (take > sp->nibuf)
1455 			take = sp->nibuf;
1456 		if (take > n)
1457 			take = n;
1458 		n -= take;
1459 		sp->size -= take;
1460 		sp->nibuf -= take;
1461 		sp->pos += take;
1462 		do
1463 			*loc++ = *p++;
1464 		while (--take > 0);
1465 		sp->ptr = p;
1466 		goto top;
1467 	}
1468 	if (n > BUFSIZ) {
1469 		take = n - n % BSIZE;
1470 		lseek(infil, (sp->bno+1)*BSIZE, 0);
1471 		if (take > sp->size || read(infil, loc, take) != take)
1472 			error(1, "premature EOF");
1473 		loc += take;
1474 		n -= take;
1475 		sp->size -= take;
1476 		sp->pos += take;
1477 		dseek(sp, (sp->bno+1+take/BSIZE)*BSIZE, -1);
1478 		goto top;
1479 	}
1480 	*loc++ = get(sp);
1481 	--n;
1482 	goto top;
1483 }
1484 
1485 symwrite(sp, bp)
1486 	struct nlist *sp;
1487 	struct biobuf *bp;
1488 {
1489 	register int len;
1490 	register char *str;
1491 
1492 	str = sp->n_un.n_name;
1493 	if (str) {
1494 		sp->n_un.n_strx = offset;
1495 		len = strlen(str) + 1;
1496 		bwrite(str, len, strout);
1497 		offset += len;
1498 	}
1499 	bwrite(sp, sizeof (*sp), bp);
1500 	sp->n_un.n_name = str;
1501 }
1502 
1503 dseek(sp, loc, s)
1504 register STREAM *sp;
1505 long loc, s;
1506 {
1507 	register PAGE *p;
1508 	register b, o;
1509 	int n;
1510 
1511 	b = loc>>BSHIFT;
1512 	o = loc&BMASK;
1513 	if (o&01)
1514 		error(1, "loader error; odd offset");
1515 	--sp->pno->nuser;
1516 	if ((p = &page[0])->bno!=b && (p = &page[1])->bno!=b)
1517 		if (p->nuser==0 || (p = &page[0])->nuser==0) {
1518 			if (page[0].nuser==0 && page[1].nuser==0)
1519 				if (page[0].bno < page[1].bno)
1520 					p = &page[0];
1521 			p->bno = b;
1522 			lseek(infil, loc & ~(long)BMASK, 0);
1523 			if ((n = read(infil, p->buff, sizeof(p->buff))) < 0)
1524 				n = 0;
1525 			p->nibuf = n;
1526 	} else
1527 		error(1, "botch: no pages");
1528 	++p->nuser;
1529 	sp->bno = b;
1530 	sp->pno = p;
1531 	if (s != -1) {sp->size = s; sp->pos = 0;}
1532 	sp->ptr = (char *)(p->buff + o);
1533 	if ((sp->nibuf = p->nibuf-o) <= 0)
1534 		sp->size = 0;
1535 }
1536 
1537 char
1538 get(asp)
1539 STREAM *asp;
1540 {
1541 	register STREAM *sp;
1542 
1543 	sp = asp;
1544 	if ((sp->nibuf -= sizeof(char)) < 0) {
1545 		dseek(sp, ((long)(sp->bno+1)<<BSHIFT), (long)-1);
1546 		sp->nibuf -= sizeof(char);
1547 	}
1548 	if ((sp->size -= sizeof(char)) <= 0) {
1549 		if (sp->size < 0)
1550 			error(1, "premature EOF");
1551 		++fpage.nuser;
1552 		--sp->pno->nuser;
1553 		sp->pno = (PAGE *) &fpage;
1554 	}
1555 	sp->pos += sizeof(char);
1556 	return(*sp->ptr++);
1557 }
1558 
1559 getfile(acp)
1560 char *acp;
1561 {
1562 	register char *cp;
1563 	register int c;
1564 	char arcmag[SARMAG+1];
1565 	struct stat stb;
1566 
1567 	cp = acp;
1568 	infil = -1;
1569 	archdr.ar_name[0] = '\0';
1570 	filname = cp;
1571 	if (cp[0]=='-' && cp[1]=='l') {
1572 		char *locfilname = "/usr/local/lib/libxxxxxxxxxxxxxxx";
1573 		if(cp[2] == '\0')
1574 			cp = "-la";
1575 		filname = "/usr/lib/libxxxxxxxxxxxxxxx";
1576 		for(c=0; cp[c+2]; c++) {
1577 			filname[c+12] = cp[c+2];
1578 			locfilname[c+18] = cp[c+2];
1579 		}
1580 		filname[c+12] = locfilname[c+18] = '.';
1581 		filname[c+13] = locfilname[c+19] = 'a';
1582 		filname[c+14] = locfilname[c+20] = '\0';
1583 		if ((infil = open(filname+4, 0)) >= 0) {
1584 			filname += 4;
1585 		} else if ((infil = open(filname, 0)) < 0) {
1586 			filname = locfilname;
1587 		}
1588 	}
1589 	if (infil == -1 && (infil = open(filname, 0)) < 0)
1590 		error(1, "cannot open");
1591 	page[0].bno = page[1].bno = -1;
1592 	page[0].nuser = page[1].nuser = 0;
1593 	text.pno = reloc.pno = (PAGE *) &fpage;
1594 	fpage.nuser = 2;
1595 	dseek(&text, 0L, SARMAG);
1596 	if (text.size <= 0)
1597 		error(1, "premature EOF");
1598 	mget((char *)arcmag, SARMAG, &text);
1599 	arcmag[SARMAG] = 0;
1600 	if (strcmp(arcmag, ARMAG))
1601 		return (0);
1602 	dseek(&text, SARMAG, sizeof archdr);
1603 	if(text.size <= 0)
1604 		return (1);
1605 	getarhdr();
1606 	if (strncmp(archdr.ar_name, "__.SYMDEF", sizeof(archdr.ar_name)) != 0)
1607 		return (1);
1608 	fstat(infil, &stb);
1609 	return (stb.st_mtime > atol(archdr.ar_date) ? 3 : 2);
1610 }
1611 
1612 struct nlist **
1613 lookup()
1614 {
1615 	register int sh;
1616 	register struct nlist **hp;
1617 	register char *cp, *cp1;
1618 	register struct symseg *gp;
1619 	register int i;
1620 
1621 	sh = 0;
1622 	for (cp = cursym.n_un.n_name; *cp;)
1623 		sh = (sh<<1) + *cp++;
1624 	sh = (sh & 0x7fffffff) % HSIZE;
1625 	for (gp = symseg; gp < &symseg[NSEG]; gp++) {
1626 		if (gp->sy_first == 0) {
1627 			gp->sy_first = (struct nlist *)
1628 			    calloc(NSYM, sizeof (struct nlist));
1629 			gp->sy_hfirst = (struct nlist **)
1630 			    calloc(HSIZE, sizeof (struct nlist *));
1631 			if (gp->sy_first == 0 || gp->sy_hfirst == 0)
1632 				error(1, "ran out of space for symbol table");
1633 			gp->sy_last = gp->sy_first + NSYM;
1634 			gp->sy_hlast = gp->sy_hfirst + HSIZE;
1635 		}
1636 		if (gp > csymseg)
1637 			csymseg = gp;
1638 		hp = gp->sy_hfirst + sh;
1639 		i = 1;
1640 		do {
1641 			if (*hp == 0) {
1642 				if (gp->sy_used == NSYM)
1643 					break;
1644 				return (hp);
1645 			}
1646 			cp1 = (*hp)->n_un.n_name;
1647 			for (cp = cursym.n_un.n_name; *cp == *cp1++;)
1648 				if (*cp++ == 0)
1649 					return (hp);
1650 			hp += i;
1651 			i += 2;
1652 			if (hp >= gp->sy_hlast)
1653 				hp -= HSIZE;
1654 		} while (i < HSIZE);
1655 		if (i > HSIZE)
1656 			error(1, "hash table botch");
1657 	}
1658 	error(1, "symbol table overflow");
1659 	/*NOTREACHED*/
1660 }
1661 
1662 symfree(saved)
1663 	struct nlist *saved;
1664 {
1665 	register struct symseg *gp;
1666 	register struct nlist *sp;
1667 
1668 	for (gp = csymseg; gp >= symseg; gp--, csymseg--) {
1669 		sp = gp->sy_first + gp->sy_used;
1670 		if (sp == saved) {
1671 			nextsym = sp;
1672 			return;
1673 		}
1674 		for (sp--; sp >= gp->sy_first; sp--) {
1675 			gp->sy_hfirst[sp->n_hash] = 0;
1676 			gp->sy_used--;
1677 			if (sp == saved) {
1678 				nextsym = sp;
1679 				return;
1680 			}
1681 		}
1682 	}
1683 	if (saved == 0)
1684 		return;
1685 	error(1, "symfree botch");
1686 }
1687 
1688 struct nlist **
1689 slookup(s)
1690 	char *s;
1691 {
1692 
1693 	cursym.n_un.n_name = s;
1694 	cursym.n_type = N_EXT+N_UNDF;
1695 	cursym.n_value = 0;
1696 	return (lookup());
1697 }
1698 
1699 enter(hp)
1700 register struct nlist **hp;
1701 {
1702 	register struct nlist *sp;
1703 
1704 	if (*hp==0) {
1705 		if (hp < csymseg->sy_hfirst || hp >= csymseg->sy_hlast)
1706 			error(1, "enter botch");
1707 		*hp = lastsym = sp = csymseg->sy_first + csymseg->sy_used;
1708 		csymseg->sy_used++;
1709 		sp->n_un.n_name = cursym.n_un.n_name;
1710 		sp->n_type = cursym.n_type;
1711 		sp->n_hash = hp - csymseg->sy_hfirst;
1712 		sp->n_value = cursym.n_value;
1713 		nextsym = lastsym + 1;
1714 		return(1);
1715 	} else {
1716 		lastsym = *hp;
1717 		return(0);
1718 	}
1719 }
1720 
1721 symx(sp)
1722 	struct nlist *sp;
1723 {
1724 	register struct symseg *gp;
1725 
1726 	if (sp == 0)
1727 		return (0);
1728 	for (gp = csymseg; gp >= symseg; gp--)
1729 		/* <= is sloppy so nextsym will always work */
1730 		if (sp >= gp->sy_first && sp <= gp->sy_last)
1731 			return ((gp - symseg) * NSYM + sp - gp->sy_first);
1732 	error(1, "symx botch");
1733 	/*NOTREACHED*/
1734 }
1735 
1736 symreloc()
1737 {
1738 	if(funding) return;
1739 	switch (cursym.n_type & 017) {
1740 
1741 	case N_TEXT:
1742 	case N_EXT+N_TEXT:
1743 		cursym.n_value += ctrel;
1744 		return;
1745 
1746 	case N_DATA:
1747 	case N_EXT+N_DATA:
1748 		cursym.n_value += cdrel;
1749 		return;
1750 
1751 	case N_BSS:
1752 	case N_EXT+N_BSS:
1753 		cursym.n_value += cbrel;
1754 		return;
1755 
1756 	case N_EXT+N_UNDF:
1757 		return;
1758 
1759 	default:
1760 		if (cursym.n_type&N_EXT)
1761 			cursym.n_type = N_EXT+N_ABS;
1762 		return;
1763 	}
1764 }
1765 
1766 error(n, s)
1767 char *s;
1768 {
1769 
1770 	if (errlev==0)
1771 		printf("ld:");
1772 	if (filname) {
1773 		printf("%s", filname);
1774 		if (n != -1 && archdr.ar_name[0])
1775 			printf("(%s)", archdr.ar_name);
1776 		printf(": ");
1777 	}
1778 	printf("%s\n", s);
1779 	if (n == -1)
1780 		return;
1781 	if (n)
1782 		delexit();
1783 	errlev = 2;
1784 }
1785 
1786 readhdr(loc)
1787 off_t loc;
1788 {
1789 
1790 	dseek(&text, loc, (long)sizeof(filhdr));
1791 	mget((short *)&filhdr, sizeof(filhdr), &text);
1792 	if (N_BADMAG(filhdr)) {
1793 		if (filhdr.a_magic == OARMAG)
1794 			error(1, "old archive");
1795 		error(1, "bad magic number");
1796 	}
1797 	if (filhdr.a_text&01 || filhdr.a_data&01)
1798 		error(1, "text/data size odd");
1799 	if (filhdr.a_magic == NMAGIC || filhdr.a_magic == ZMAGIC) {
1800 		cdrel = -round(filhdr.a_text, PAGSIZ);
1801 		cbrel = cdrel - filhdr.a_data;
1802 	} else if (filhdr.a_magic == OMAGIC) {
1803 		cdrel = -filhdr.a_text;
1804 		cbrel = cdrel - filhdr.a_data;
1805 	} else
1806 		error(1, "bad format");
1807 }
1808 
1809 round(v, r)
1810 	int v;
1811 	u_long r;
1812 {
1813 
1814 	r--;
1815 	v += r;
1816 	v &= ~(long)r;
1817 	return(v);
1818 }
1819 
1820 #define	NSAVETAB	8192
1821 char	*savetab;
1822 int	saveleft;
1823 
1824 char *
1825 savestr(cp)
1826 	register char *cp;
1827 {
1828 	register int len;
1829 
1830 	len = strlen(cp) + 1;
1831 	if (len > saveleft) {
1832 		saveleft = NSAVETAB;
1833 		if (len > saveleft)
1834 			saveleft = len;
1835 		savetab = (char *)malloc(saveleft);
1836 		if (savetab == 0)
1837 			error(1, "ran out of memory (savestr)");
1838 	}
1839 	strncpy(savetab, cp, len);
1840 	cp = savetab;
1841 	savetab += len;
1842 	saveleft -= len;
1843 	return (cp);
1844 }
1845 
1846 bopen(bp, off)
1847 	struct biobuf *bp;
1848 {
1849 
1850 	bp->b_ptr = bp->b_buf;
1851 	bp->b_nleft = BUFSIZ - off % BUFSIZ;
1852 	bp->b_off = off;
1853 	bp->b_link = biobufs;
1854 	biobufs = bp;
1855 }
1856 
1857 int	bwrerror;
1858 
1859 bwrite(p, cnt, bp)
1860 	register char *p;
1861 	register int cnt;
1862 	register struct biobuf *bp;
1863 {
1864 	register int put;
1865 	register char *to;
1866 
1867 top:
1868 	if (cnt == 0)
1869 		return;
1870 	if (bp->b_nleft) {
1871 		put = bp->b_nleft;
1872 		if (put > cnt)
1873 			put = cnt;
1874 		bp->b_nleft -= put;
1875 		to = bp->b_ptr;
1876 		asm("movc3 r8,(r11),(r7)");
1877 		bp->b_ptr += put;
1878 		p += put;
1879 		cnt -= put;
1880 		goto top;
1881 	}
1882 	if (cnt >= BUFSIZ) {
1883 		if (bp->b_ptr != bp->b_buf)
1884 			bflush1(bp);
1885 		put = cnt - cnt % BUFSIZ;
1886 		if (boffset != bp->b_off)
1887 			lseek(biofd, bp->b_off, 0);
1888 		if (write(biofd, p, put) != put) {
1889 			bwrerror = 1;
1890 			error(1, "output write error");
1891 		}
1892 		bp->b_off += put;
1893 		boffset = bp->b_off;
1894 		p += put;
1895 		cnt -= put;
1896 		goto top;
1897 	}
1898 	bflush1(bp);
1899 	goto top;
1900 }
1901 
1902 bflush()
1903 {
1904 	register struct biobuf *bp;
1905 
1906 	if (bwrerror)
1907 		return;
1908 	for (bp = biobufs; bp; bp = bp->b_link)
1909 		bflush1(bp);
1910 }
1911 
1912 bflush1(bp)
1913 	register struct biobuf *bp;
1914 {
1915 	register int cnt = bp->b_ptr - bp->b_buf;
1916 
1917 	if (cnt == 0)
1918 		return;
1919 	if (boffset != bp->b_off)
1920 		lseek(biofd, bp->b_off, 0);
1921 	if (write(biofd, bp->b_buf, cnt) != cnt) {
1922 		bwrerror = 1;
1923 		error(1, "output write error");
1924 	}
1925 	bp->b_off += cnt;
1926 	boffset = bp->b_off;
1927 	bp->b_ptr = bp->b_buf;
1928 	bp->b_nleft = BUFSIZ;
1929 }
1930 
1931 bflushc(bp, c)
1932 	register struct biobuf *bp;
1933 {
1934 
1935 	bflush1(bp);
1936 	bputc(c, bp);
1937 }
1938