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