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