xref: /csrg-svn/old/ld/ld.c (revision 650)
1*650Sbill static	char sccsid[] = "@(#)ld.c 3.2 08/16/80";
2615Sbill /*
3615Sbill  * VAX VM/UNIX ld - string table version
4615Sbill  */
5615Sbill 
6615Sbill #include <sys/types.h>
7615Sbill #include <signal.h>
8615Sbill #include <stdio.h>
9615Sbill #include <ctype.h>
10*650Sbill #include <ar.h>
11*650Sbill #include <a.out.h>
12615Sbill #include <ranlib.h>
13615Sbill #include <stat.h>
14615Sbill #include <pagsiz.h>
15615Sbill 
16615Sbill /*
17615Sbill  * Basic strategy:
18615Sbill  *
19615Sbill  * The loader takes a number of files and libraries as arguments.
20615Sbill  * A first pass examines each file in turn.  Normal files are
21615Sbill  * unconditionally loaded, and the (external) symbols they define and require
22615Sbill  * are noted in the symbol table.   Libraries are searched, and the
23615Sbill  * library members which define needed symbols are remembered
24615Sbill  * in a special data structure so they can be selected on the second
25615Sbill  * pass.  Symbols defined and required by library members are also
26615Sbill  * recorded.
27615Sbill  *
28615Sbill  * After the first pass, the loader knows the size of the basic text
29615Sbill  * data, and bss segments from the sum of the sizes of the modules which
30615Sbill  * were required.  It has computed, for each ``common'' symbol, the
31615Sbill  * maximum size of any reference to it, and these symbols are then assigned
32615Sbill  * storage locations after their sizes are appropriately rounded.
33615Sbill  * The loader now knows all sizes for the eventual output file, and
34615Sbill  * can determine the final locations of external symbols before it
35615Sbill  * begins a second pass.
36615Sbill  *
37615Sbill  * On the second pass each normal file and required library member
38615Sbill  * is processed again.  The symbol table for each such file is
39615Sbill  * reread and relevant parts of it are placed in the output.  The offsets
40615Sbill  * in the local symbol table for externally defined symbols are recorded
41615Sbill  * since relocation information refers to symbols in this way.
42615Sbill  * Armed with all necessary information, the text and data segments
43615Sbill  * are relocated and the result is placed in the output file, which
44615Sbill  * is pasted together, ``in place'', by writing to it in several
45615Sbill  * different places concurrently.
46615Sbill  */
47615Sbill 
48615Sbill /*
49615Sbill  * Internal data structures
50615Sbill  *
51615Sbill  * All internal data structures are segmented and dynamically extended.
52615Sbill  * The basic structures hold 1103 (NSYM) symbols, ~~200 (NROUT)
53615Sbill  * referenced library members, and 100 (NSYMPR) private (local) symbols
54615Sbill  * per object module.  For large programs and/or modules, these structures
55615Sbill  * expand to be up to 40 (NSEG) times as large as this as necessary.
56615Sbill  */
57615Sbill #define	NSEG	40		/* Number of segments, each data structure */
58615Sbill #define	NSYM	1103		/* Number of symbols per segment */
59615Sbill #define	NROUT	250		/* Number of library references per segment */
60615Sbill #define	NSYMPR	100		/* Number of private symbols per segment */
61615Sbill 
62615Sbill /*
63615Sbill  * Structure describing each symbol table segment.
64615Sbill  * Each segment has its own hash table.  We record the first
65615Sbill  * address in and first address beyond both the symbol and hash
66615Sbill  * tables, for use in the routine symx and the lookup routine respectively.
67615Sbill  * The symfree routine also understands this structure well as it used
68615Sbill  * to back out symbols from modules we decide that we don't need in pass 1.
69615Sbill  *
70615Sbill  * Csymseg points to the current symbol table segment;
71615Sbill  * csymseg->sy_first[csymseg->sy_used] is the next symbol slot to be allocated,
72615Sbill  * (unless csymseg->sy_used == NSYM in which case we will allocate another
73615Sbill  * symbol table segment first.)
74615Sbill  */
75615Sbill struct	symseg {
76615Sbill 	struct	nlist *sy_first;	/* base of this alloc'ed segment */
77615Sbill 	struct	nlist *sy_last;		/* end of this segment, for n_strx */
78615Sbill 	int	sy_used;		/* symbols used in this seg */
79615Sbill 	struct	nlist **sy_hfirst;	/* base of hash table, this seg */
80615Sbill 	struct	nlist **sy_hlast;	/* end of hash table, this seg */
81615Sbill } symseg[NSEG], *csymseg;
82615Sbill 
83615Sbill /*
84615Sbill  * The lookup routine uses quadratic rehash.  Since a quadratic rehash
85615Sbill  * only probes 1/2 of the buckets in the table, and since the hash
86615Sbill  * table is segmented the same way the symbol table is, we make the
87615Sbill  * hash table have twice as many buckets as there are symbol table slots
88615Sbill  * in the segment.  This guarantees that the quadratic rehash will never
89615Sbill  * fail to find an empty bucket if the segment is not full and the
90615Sbill  * symbol is not there.
91615Sbill  */
92615Sbill #define	HSIZE	(NSYM*2)
93615Sbill 
94615Sbill /*
95615Sbill  * Xsym converts symbol table indices (ala x) into symbol table pointers.
96615Sbill  * Symx (harder, but never used in loops) inverts pointers into the symbol
97615Sbill  * table into indices using the symseg[] structure.
98615Sbill  */
99615Sbill #define	xsym(x)	(symseg[(x)/NSYM].sy_first+((x)%NSYM))
100615Sbill /* symx() is a function, defined below */
101615Sbill 
102615Sbill struct	nlist cursym;		/* current symbol */
103615Sbill struct	nlist *lastsym;		/* last symbol entered */
104615Sbill struct	nlist *nextsym;		/* next available symbol table entry */
105615Sbill struct	nlist *addsym;		/* first sym defined during incr load */
106615Sbill int	nsym;			/* pass2: number of local symbols in a.out */
107615Sbill /* nsym + symx(nextsym) is the symbol table size during pass2 */
108615Sbill 
109615Sbill struct	nlist **lookup(), **slookup();
110*650Sbill struct	nlist *p_etext, *p_edata, *p_end, *entrypt;
111615Sbill 
112615Sbill /*
113615Sbill  * Definitions of segmentation for library member table.
114615Sbill  * For each library we encounter on pass 1 we record pointers to all
115615Sbill  * members which we will load on pass 2.  These are recorded as offsets
116615Sbill  * into the archive in the library member table.  Libraries are
117615Sbill  * separated in the table by the special offset value -1.
118615Sbill  */
119615Sbill off_t	li_init[NROUT];
120615Sbill struct	libseg {
121615Sbill 	off_t	*li_first;
122615Sbill 	int	li_used;
123615Sbill 	int	li_used2;
124615Sbill } libseg[NSEG] = {
125615Sbill 	li_init, 0, 0,
126615Sbill }, *clibseg = libseg;
127615Sbill 
128615Sbill /*
129615Sbill  * In processing each module on pass 2 we must relocate references
130615Sbill  * relative to external symbols.  These references are recorded
131615Sbill  * in the relocation information as relative to local symbol numbers
132615Sbill  * assigned to the external symbols when the module was created.
133615Sbill  * Thus before relocating the module in pass 2 we create a table
134615Sbill  * which maps these internal numbers to symbol table entries.
135615Sbill  * A hash table is constructed, based on the local symbol table indices,
136615Sbill  * for quick lookup of these symbols.
137615Sbill  */
138615Sbill #define	LHSIZ	31
139615Sbill struct	local {
140615Sbill 	int	l_index;		/* index to symbol in file */
141615Sbill 	struct	nlist *l_symbol;	/* ptr to symbol table */
142615Sbill 	struct	local *l_link;		/* hash link */
143615Sbill } *lochash[LHSIZ], lhinit[NSYMPR];
144615Sbill struct	locseg {
145615Sbill 	struct	local *lo_first;
146615Sbill 	int	lo_used;
147615Sbill } locseg[NSEG] = {
148615Sbill 	lhinit, 0
149615Sbill }, *clocseg;
150615Sbill 
151615Sbill /*
152615Sbill  * Libraries are typically built with a table of contents,
153615Sbill  * which is the first member of a library with special file
154615Sbill  * name __.SYMDEF and contains a list of symbol names
155615Sbill  * and with each symbol the offset of the library member which defines
156615Sbill  * it.  The loader uses this table to quickly tell which library members
157615Sbill  * are (potentially) useful.  The alternative, examining the symbol
158615Sbill  * table of each library member, is painfully slow for large archives.
159615Sbill  *
160615Sbill  * See <ranlib.h> for the definition of the ranlib structure and an
161615Sbill  * explanation of the __.SYMDEF file format.
162615Sbill  */
163615Sbill int	tnum;		/* number of symbols in table of contents */
164615Sbill int	ssiz;		/* size of string table for table of contents */
165615Sbill struct	ranlib *tab;	/* the table of contents (dynamically allocated) */
166615Sbill char	*tabstr;	/* string table for table of contents */
167615Sbill 
168615Sbill /*
169615Sbill  * We open each input file or library only once, but in pass2 we
170615Sbill  * (historically) read from such a file at 2 different places at the
171615Sbill  * same time.  These structures are remnants from those days,
172*650Sbill  * and now serve only to catch ``Premature EOF''.
173615Sbill  */
174615Sbill typedef struct {
175615Sbill 	short	*fakeptr;
176615Sbill 	int	bno;
177615Sbill 	int	nibuf;
178615Sbill 	int	nuser;
179615Sbill 	char	buff[BSIZE];
180615Sbill } PAGE;
181615Sbill 
182615Sbill PAGE	page[2];
183615Sbill 
184615Sbill struct {
185615Sbill 	short	*fakeptr;
186615Sbill 	int	bno;
187615Sbill 	int	nibuf;
188615Sbill 	int	nuser;
189615Sbill } fpage;
190615Sbill 
191615Sbill typedef struct {
192615Sbill 	char	*ptr;
193615Sbill 	int	bno;
194615Sbill 	int	nibuf;
195615Sbill 	long	size;
196615Sbill 	long	pos;
197615Sbill 	PAGE	*pno;
198615Sbill } STREAM;
199615Sbill 
200615Sbill STREAM	text;
201615Sbill STREAM	reloc;
202615Sbill 
203615Sbill /*
204615Sbill  * Header from the a.out and the archive it is from (if any).
205615Sbill  */
206615Sbill struct	exec filhdr;
207615Sbill struct	ar_hdr archdr;
208615Sbill #define	OARMAG 0177545
209615Sbill 
210615Sbill /*
211615Sbill  * Options.
212615Sbill  */
213615Sbill int	trace;
214615Sbill int	xflag;		/* discard local symbols */
215615Sbill int	Xflag;		/* discard locals starting with 'L' */
216615Sbill int	Sflag;		/* discard all except locals and globals*/
217615Sbill int	rflag;		/* preserve relocation bits, don't define common */
218615Sbill int	arflag;		/* original copy of rflag */
219615Sbill int	sflag;		/* discard all symbols */
220615Sbill int	nflag;		/* pure procedure */
221615Sbill int	dflag;		/* define common even with rflag */
222*650Sbill int	zflag;		/* demand paged  */
223615Sbill long	hsize;		/* size of hole at beginning of data to be squashed */
224615Sbill int	Aflag;		/* doing incremental load */
225*650Sbill int	Nflag;		/* want impure a.out */
226615Sbill int	funding;	/* reading fundamental file for incremental load */
227615Sbill 
228615Sbill /*
229615Sbill  * These are the cumulative sizes, set in pass 1, which
230615Sbill  * appear in the a.out header when the loader is finished.
231615Sbill  */
232615Sbill off_t	tsize, dsize, bsize, trsize, drsize, ssize;
233615Sbill 
234615Sbill /*
235615Sbill  * Symbol relocation: c?rel is a scale factor which is
236615Sbill  * added to an old relocation to convert it to new units;
237615Sbill  * i.e. it is the difference between segment origins.
238*650Sbill  * (Thus if we are loading from a data segment which began at location
239*650Sbill  * 4 in a .o file into an a.out where it will be loaded starting at
240*650Sbill  * 1024, cdrel will be 1020.)
241615Sbill  */
242615Sbill long	ctrel, cdrel, cbrel;
243615Sbill 
244615Sbill /*
245*650Sbill  * Textbase is the start address of all text, 0 unless given by -T.
246615Sbill  * Database is the base of all data, computed before and used during pass2.
247*650Sbill  */
248*650Sbill long	textbase, database;
249*650Sbill 
250*650Sbill /*
251615Sbill  * The base addresses for the loaded text, data and bss from the
252615Sbill  * current module during pass2 are given by torigin, dorigin and borigin.
253615Sbill  */
254615Sbill long	torigin, dorigin, borigin;
255615Sbill 
256615Sbill /*
257615Sbill  * Errlev is nonzero when errors have occured.
258615Sbill  * Delarg is an implicit argument to the routine delexit
259615Sbill  * which is called on error.  We do ``delarg = errlev'' before normal
260615Sbill  * exits, and only if delarg is 0 (i.e. errlev was 0) do we make the
261615Sbill  * result file executable.
262615Sbill  */
263615Sbill int	errlev;
264615Sbill int	delarg	= 4;
265615Sbill 
266615Sbill /*
267615Sbill  * The biobuf structure and associated routines are used to write
268615Sbill  * into one file at several places concurrently.  Calling bopen
269615Sbill  * with a biobuf structure sets it up to write ``biofd'' starting
270615Sbill  * at the specified offset.  You can then use ``bwrite'' and/or ``bputc''
271615Sbill  * to stuff characters in the stream, much like ``fwrite'' and ``fputc''.
272615Sbill  * Calling bflush drains all the buffers and MUST be done before exit.
273615Sbill  */
274615Sbill struct	biobuf {
275615Sbill 	short	b_nleft;		/* Number free spaces left in b_buf */
276615Sbill /* Initialize to be less than BUFSIZ initially, to boundary align in file */
277615Sbill 	char	*b_ptr;			/* Next place to stuff characters */
278615Sbill 	char	b_buf[BUFSIZ];		/* The buffer itself */
279615Sbill 	off_t	b_off;			/* Current file offset */
280615Sbill 	struct	biobuf *b_link;		/* Link in chain for bflush() */
281615Sbill } *biobufs;
282615Sbill #define	bputc(c,b) ((b)->b_nleft ? (--(b)->b_nleft, *(b)->b_ptr++ = (c)) \
283615Sbill 		       : bflushc(b, c))
284615Sbill int	biofd;
285615Sbill off_t	boffset;
286615Sbill struct	biobuf *tout, *dout, *trout, *drout, *sout, *strout;
287615Sbill 
288615Sbill /*
289615Sbill  * Offset is the current offset in the string file.
290615Sbill  * Its initial value reflects the fact that we will
291615Sbill  * eventually stuff the size of the string table at the
292615Sbill  * beginning of the string table (i.e. offset itself!).
293615Sbill  */
294615Sbill off_t	offset = sizeof (off_t);
295615Sbill 
296615Sbill int	ofilfnd;		/* -o given; otherwise move l.out to a.out */
297615Sbill char	*ofilename = "l.out";
298615Sbill int	infil;			/* current input file descriptor */
299615Sbill char	*filname;		/* and its name */
300615Sbill 
301615Sbill /*
302615Sbill  * Base of the string table of the current module (pass1 and pass2).
303615Sbill  */
304615Sbill char	*curstr;
305615Sbill 
306615Sbill char 	get();
307615Sbill int	delexit();
308615Sbill char	*savestr();
309615Sbill 
310615Sbill main(argc, argv)
311615Sbill char **argv;
312615Sbill {
313615Sbill 	register int c, i;
314615Sbill 	int num;
315615Sbill 	register char *ap, **p;
316615Sbill 	char save;
317615Sbill 
318*650Sbill 	if (signal(SIGINT, SIG_IGN) != SIG_IGN) {
319615Sbill 		signal(SIGINT, delexit);
320*650Sbill 		signal(SIGTERM, delexit);
321*650Sbill 	}
322615Sbill 	if (argc == 1)
323615Sbill 		exit(4);
324615Sbill 	p = argv+1;
325615Sbill 
326*650Sbill 	/*
327*650Sbill 	 * Scan files once to find where symbols are defined.
328*650Sbill 	 */
329615Sbill 	for (c=1; c<argc; c++) {
330615Sbill 		if (trace)
331615Sbill 			printf("%s:\n", *p);
332615Sbill 		filname = 0;
333615Sbill 		ap = *p++;
334615Sbill 		if (*ap != '-') {
335615Sbill 			load1arg(ap);
336615Sbill 			continue;
337615Sbill 		}
338615Sbill 		for (i=1; ap[i]; i++) switch (ap[i]) {
339615Sbill 
340615Sbill 		case 'o':
341615Sbill 			if (++c >= argc)
342615Sbill 				error(1, "-o where?");
343615Sbill 			ofilename = *p++;
344615Sbill 			ofilfnd++;
345615Sbill 			continue;
346615Sbill 		case 'u':
347615Sbill 		case 'e':
348615Sbill 			if (++c >= argc)
349615Sbill 				error(1, "-u or -c: arg missing");
350615Sbill 			enter(slookup(*p++));
351615Sbill 			if (ap[i]=='e')
352615Sbill 				entrypt = lastsym;
353615Sbill 			continue;
354615Sbill 		case 'H':
355615Sbill 			if (++c >= argc)
356615Sbill 				error(1, "-H: arg missing");
357615Sbill 			if (tsize!=0)
358615Sbill 				error(1, "-H: too late, some text already loaded");
359615Sbill 			hsize = atoi(*p++);
360615Sbill 			continue;
361615Sbill 		case 'A':
362615Sbill 			if (++c >= argc)
363615Sbill 				error(1, "-A: arg missing");
364615Sbill 			if (Aflag)
365615Sbill 				error(1, "-A: only one base file allowed");
366615Sbill 			Aflag = 1;
367615Sbill 			nflag = 0;
368615Sbill 			funding = 1;
369615Sbill 			load1arg(*p++);
370615Sbill 			trsize = drsize = tsize = dsize = bsize = 0;
371615Sbill 			ctrel = cdrel = cbrel = 0;
372615Sbill 			funding = 0;
373615Sbill 			addsym = nextsym;
374615Sbill 			continue;
375615Sbill 		case 'D':
376615Sbill 			if (++c >= argc)
377615Sbill 				error(1, "-D: arg missing");
378615Sbill 			num = htoi(*p++);
379615Sbill 			if (dsize > num)
380615Sbill 				error(1, "-D: too small");
381615Sbill 			dsize = num;
382615Sbill 			continue;
383615Sbill 		case 'T':
384615Sbill 			if (++c >= argc)
385615Sbill 				error(1, "-T: arg missing");
386615Sbill 			if (tsize!=0)
387615Sbill 				error(1, "-T: too late, some text already loaded");
388615Sbill 			textbase = htoi(*p++);
389615Sbill 			continue;
390615Sbill 		case 'l':
391615Sbill 			save = ap[--i];
392615Sbill 			ap[i]='-';
393615Sbill 			load1arg(&ap[i]);
394615Sbill 			ap[i]=save;
395615Sbill 			goto next;
396615Sbill 		case 'x':
397615Sbill 			xflag++;
398615Sbill 			continue;
399615Sbill 		case 'X':
400615Sbill 			Xflag++;
401615Sbill 			continue;
402615Sbill 		case 'S':
403615Sbill 			Sflag++;
404615Sbill 			continue;
405615Sbill 		case 'r':
406615Sbill 			rflag++;
407615Sbill 			arflag++;
408615Sbill 			continue;
409615Sbill 		case 's':
410615Sbill 			sflag++;
411615Sbill 			xflag++;
412615Sbill 			continue;
413615Sbill 		case 'n':
414615Sbill 			nflag++;
415*650Sbill 			Nflag = zflag = 0;
416615Sbill 			continue;
417615Sbill 		case 'N':
418*650Sbill 			Nflag++;
419*650Sbill 			nflag = zflag = 0;
420615Sbill 			continue;
421615Sbill 		case 'd':
422615Sbill 			dflag++;
423615Sbill 			continue;
424615Sbill 		case 'i':
425615Sbill 			printf("ld: -i ignored\n");
426615Sbill 			continue;
427615Sbill 		case 't':
428615Sbill 			trace++;
429615Sbill 			continue;
430615Sbill 		case 'z':
431615Sbill 			zflag++;
432*650Sbill 			Nflag = nflag = 0;
433615Sbill 			continue;
434615Sbill 		default:
435615Sbill 			filname = savestr("-x");	/* kludge */
436615Sbill 			filname[1] = ap[i];		/* kludge */
437615Sbill 			archdr.ar_name[0] = 0;		/* kludge */
438615Sbill 			error(1, "bad flag");
439615Sbill 		}
440615Sbill next:
441615Sbill 		;
442615Sbill 	}
443*650Sbill 	if (rflag == 0 && Nflag == 0 && nflag == 0)
444*650Sbill 		zflag++;
445615Sbill 	endload(argc, argv);
446615Sbill 	exit(0);
447615Sbill }
448615Sbill 
449615Sbill /*
450615Sbill  * Convert a ascii string which is a hex number.
451615Sbill  * Used by -T and -D options.
452615Sbill  */
453615Sbill htoi(p)
454615Sbill 	register char *p;
455615Sbill {
456615Sbill 	register int c, n;
457615Sbill 
458615Sbill 	n = 0;
459615Sbill 	while (c = *p++) {
460615Sbill 		n <<= 4;
461615Sbill 		if (isdigit(c))
462615Sbill 			n += c - '0';
463615Sbill 		else if (c >= 'a' && c <= 'f')
464615Sbill 			n += 10 + (c - 'a');
465615Sbill 		else if (c >= 'A' && c <= 'F')
466615Sbill 			n += 10 + (c - 'A');
467615Sbill 		else
468615Sbill 			error(1, "badly formed hex number");
469615Sbill 	}
470615Sbill 	return (n);
471615Sbill }
472615Sbill 
473615Sbill delexit()
474615Sbill {
475615Sbill 
476615Sbill 	bflush();
477615Sbill 	unlink("l.out");
478615Sbill 	if (delarg==0 && Aflag==0)
479615Sbill 		chmod(ofilename, 0777 &~ umask(0));
480615Sbill 	exit (delarg);
481615Sbill }
482615Sbill 
483615Sbill endload(argc, argv)
484615Sbill 	int argc;
485615Sbill 	char **argv;
486615Sbill {
487615Sbill 	register int c, i;
488615Sbill 	long dnum;
489615Sbill 	register char *ap, **p;
490615Sbill 
491615Sbill 	clibseg = libseg;
492615Sbill 	filname = 0;
493615Sbill 	middle();
494615Sbill 	setupout();
495615Sbill 	p = argv+1;
496615Sbill 	for (c=1; c<argc; c++) {
497615Sbill 		ap = *p++;
498615Sbill 		if (trace)
499615Sbill 			printf("%s:\n", ap);
500615Sbill 		if (*ap != '-') {
501615Sbill 			load2arg(ap);
502615Sbill 			continue;
503615Sbill 		}
504615Sbill 		for (i=1; ap[i]; i++) switch (ap[i]) {
505615Sbill 
506615Sbill 		case 'D':
507615Sbill 			dnum = htoi(*p);
508615Sbill 			if (dorigin < dnum)
509615Sbill 				while (dorigin < dnum)
510615Sbill 					bputc(0, dout), dorigin++;
511615Sbill 			/* fall into ... */
512615Sbill 		case 'T':
513615Sbill 		case 'u':
514615Sbill 		case 'e':
515615Sbill 		case 'o':
516615Sbill 		case 'H':
517615Sbill 			++c;
518615Sbill 			++p;
519615Sbill 			/* fall into ... */
520615Sbill 		default:
521615Sbill 			continue;
522615Sbill 		case 'A':
523615Sbill 			funding = 1;
524615Sbill 			load2arg(*p++);
525615Sbill 			funding = 0;
526615Sbill 			c++;
527615Sbill 			continue;
528615Sbill 		case 'l':
529615Sbill 			ap[--i]='-';
530615Sbill 			load2arg(&ap[i]);
531615Sbill 			goto next;
532615Sbill 		}
533615Sbill next:
534615Sbill 		;
535615Sbill 	}
536615Sbill 	finishout();
537615Sbill }
538615Sbill 
539615Sbill /*
540615Sbill  * Scan file to find defined symbols.
541615Sbill  */
542615Sbill load1arg(cp)
543615Sbill 	register char *cp;
544615Sbill {
545615Sbill 	register struct ranlib *tp;
546615Sbill 	off_t nloc;
547615Sbill 
548615Sbill 	switch (getfile(cp)) {
549615Sbill 
550615Sbill 	/*
551615Sbill 	 * Plain file.
552615Sbill 	 */
553615Sbill 	case 0:
554615Sbill 		load1(0, 0L);
555615Sbill 		break;
556615Sbill 
557615Sbill 	/*
558615Sbill 	 * Archive without table of contents.
559615Sbill 	 * (Slowly) process each member.
560615Sbill 	 */
561615Sbill 	case 1:
562615Sbill 		error(-1, "warning: archive has no table of contents");
563615Sbill 		nloc = SARMAG;
564615Sbill 		while (step(nloc))
565615Sbill 			nloc += sizeof(archdr) +
566615Sbill 			    round(atol(archdr.ar_size), sizeof (short));
567615Sbill 		break;
568615Sbill 
569615Sbill 	/*
570615Sbill 	 * Archive with table of contents.
571615Sbill 	 * Read the table of contents and its associated string table.
572615Sbill 	 * Pass through the library resolving symbols until nothing changes
573615Sbill 	 * for an entire pass (i.e. you can get away with backward references
574615Sbill 	 * when there is a table of contents!)
575615Sbill 	 */
576615Sbill 	case 2:
577615Sbill 		nloc = SARMAG + sizeof (archdr);
578615Sbill 		dseek(&text, nloc, sizeof (tnum));
579615Sbill 		mget((char *)&tnum, sizeof (tnum), &text);
580615Sbill 		nloc += sizeof (tnum);
581615Sbill 		tab = (struct ranlib *)malloc(tnum);
582615Sbill 		if (tab == 0)
583615Sbill 			error(1, "ran out of memory (toc)");
584615Sbill 		dseek(&text, nloc, tnum);
585615Sbill 		mget((char *)tab, tnum, &text);
586615Sbill 		nloc += tnum;
587615Sbill 		tnum /= sizeof (struct ranlib);
588615Sbill 		dseek(&text, nloc, sizeof (ssiz));
589615Sbill 		mget((char *)&ssiz, sizeof (ssiz), &text);
590615Sbill 		nloc += sizeof (ssiz);
591615Sbill 		tabstr = (char *)malloc(ssiz);
592615Sbill 		if (tabstr == 0)
593615Sbill 			error(1, "ran out of memory (tocstr)");
594615Sbill 		dseek(&text, nloc, ssiz);
595615Sbill 		mget((char *)tabstr, ssiz, &text);
596615Sbill 		for (tp = &tab[tnum]; --tp >= tab;) {
597615Sbill 			if (tp->ran_un.ran_strx < 0 ||
598615Sbill 			    tp->ran_un.ran_strx >= ssiz)
599615Sbill 				error(1, "mangled archive table of contents");
600615Sbill 			tp->ran_un.ran_name = tabstr + tp->ran_un.ran_strx;
601615Sbill 		}
602615Sbill 		while (ldrand())
603615Sbill 			continue;
604615Sbill 		cfree((char *)tab);
605615Sbill 		cfree(tabstr);
606615Sbill 		nextlibp(-1);
607615Sbill 		break;
608615Sbill 
609615Sbill 	/*
610615Sbill 	 * Table of contents is out of date, so search
611615Sbill 	 * as a normal library (but skip the __.SYMDEF file).
612615Sbill 	 */
613615Sbill 	case 3:
614615Sbill 		error(-1, "warning: table of contents is out of date");
615615Sbill 		nloc = SARMAG;
616615Sbill 		do
617615Sbill 			nloc += sizeof(archdr) +
618615Sbill 			    round(atol(archdr.ar_size), sizeof(short));
619615Sbill 		while (step(nloc));
620615Sbill 		break;
621615Sbill 	}
622615Sbill 	close(infil);
623615Sbill }
624615Sbill 
625615Sbill /*
626615Sbill  * Advance to the next archive member, which
627615Sbill  * is at offset nloc in the archive.  If the member
628615Sbill  * is useful, record its location in the liblist structure
629615Sbill  * for use in pass2.  Mark the end of the archive in libilst with a -1.
630615Sbill  */
631615Sbill step(nloc)
632615Sbill 	off_t nloc;
633615Sbill {
634615Sbill 
635615Sbill 	dseek(&text, nloc, (long) sizeof archdr);
636615Sbill 	if (text.size <= 0) {
637615Sbill 		nextlibp(-1);
638615Sbill 		return (0);
639615Sbill 	}
640615Sbill 	getarhdr();
641615Sbill 	if (load1(1, nloc + (sizeof archdr)))
642615Sbill 		nextlibp(nloc);
643615Sbill 	return (1);
644615Sbill }
645615Sbill 
646615Sbill /*
647615Sbill  * Record the location of a useful archive member.
648615Sbill  * Recording -1 marks the end of files from an archive.
649615Sbill  * The liblist data structure is dynamically extended here.
650615Sbill  */
651615Sbill nextlibp(val)
652615Sbill 	off_t val;
653615Sbill {
654615Sbill 
655615Sbill 	if (clibseg->li_used == NROUT) {
656615Sbill 		if (++clibseg == &libseg[NSEG])
657615Sbill 			error(1, "too many files loaded from libraries");
658615Sbill 		clibseg->li_first = (off_t *)malloc(NROUT * sizeof (off_t));
659615Sbill 		if (clibseg->li_first == 0)
660615Sbill 			error(1, "ran out of memory (nextlibp)");
661615Sbill 	}
662615Sbill 	clibseg->li_first[clibseg->li_used++] = val;
663615Sbill }
664615Sbill 
665615Sbill /*
666615Sbill  * One pass over an archive with a table of contents.
667615Sbill  * Remember the number of symbols currently defined,
668615Sbill  * then call step on members which look promising (i.e.
669615Sbill  * that define a symbol which is currently externally undefined).
670615Sbill  * Indicate to our caller whether this process netted any more symbols.
671615Sbill  */
672615Sbill ldrand()
673615Sbill {
674615Sbill 	register struct nlist *sp, **hp;
675615Sbill 	register struct ranlib *tp, *tplast;
676615Sbill 	off_t loc;
677615Sbill 	int nsymt = symx(nextsym);
678615Sbill 
679615Sbill 	tplast = &tab[tnum-1];
680615Sbill 	for (tp = tab; tp <= tplast; tp++) {
681615Sbill 		if ((hp = slookup(tp->ran_un.ran_name)) == 0)
682615Sbill 			continue;
683615Sbill 		sp = *hp;
684615Sbill 		if (sp->n_type != N_EXT+N_UNDF)
685615Sbill 			continue;
686615Sbill 		step(tp->ran_off);
687615Sbill 		loc = tp->ran_off;
688615Sbill 		while (tp < tplast && (tp+1)->ran_off == loc)
689615Sbill 			tp++;
690615Sbill 	}
691615Sbill 	return (symx(nextsym) != nsymt);
692615Sbill }
693615Sbill 
694615Sbill /*
695615Sbill  * Examine a single file or archive member on pass 1.
696615Sbill  */
697615Sbill load1(libflg, loc)
698615Sbill 	off_t loc;
699615Sbill {
700615Sbill 	register struct nlist *sp;
701615Sbill 	struct nlist *savnext;
702615Sbill 	int ndef, nlocal, type, size, nsymt;
703615Sbill 	register int i;
704615Sbill 	off_t maxoff;
705615Sbill 	struct stat stb;
706615Sbill 
707615Sbill 	readhdr(loc);
708615Sbill 	if (filhdr.a_syms == 0) {
709615Sbill 		if (filhdr.a_text+filhdr.a_data == 0)
710615Sbill 			return (0);
711615Sbill 		error(1, "no namelist");
712615Sbill 	}
713615Sbill 	if (libflg)
714615Sbill 		maxoff = atol(archdr.ar_size);
715615Sbill 	else {
716615Sbill 		fstat(infil, &stb);
717615Sbill 		maxoff = stb.st_size;
718615Sbill 	}
719615Sbill 	if (N_STROFF(filhdr) + sizeof (off_t) >= maxoff)
720615Sbill 		error(1, "too small (old format .o?)");
721615Sbill 	ctrel = tsize; cdrel += dsize; cbrel += bsize;
722615Sbill 	ndef = 0;
723615Sbill 	nlocal = sizeof(cursym);
724615Sbill 	savnext = nextsym;
725615Sbill 	loc += N_SYMOFF(filhdr);
726615Sbill 	dseek(&text, loc, filhdr.a_syms);
727615Sbill 	dseek(&reloc, loc + filhdr.a_syms, sizeof(off_t));
728615Sbill 	mget(&size, sizeof (size), &reloc);
729615Sbill 	dseek(&reloc, loc + filhdr.a_syms+sizeof (off_t), size-sizeof (off_t));
730615Sbill 	curstr = (char *)malloc(size);
731615Sbill 	if (curstr == NULL)
732615Sbill 		error(1, "no space for string table");
733615Sbill 	mget(curstr+sizeof(off_t), size-sizeof(off_t), &reloc);
734615Sbill 	while (text.size > 0) {
735615Sbill 		mget((char *)&cursym, sizeof(struct nlist), &text);
736615Sbill 		if (cursym.n_un.n_strx) {
737615Sbill 			if (cursym.n_un.n_strx<sizeof(size) ||
738615Sbill 			    cursym.n_un.n_strx>=size)
739615Sbill 				error(1, "bad string table index (pass 1)");
740615Sbill 			cursym.n_un.n_name = curstr + cursym.n_un.n_strx;
741615Sbill 		}
742615Sbill 		type = cursym.n_type;
743615Sbill 		if ((type&N_EXT)==0) {
744615Sbill 			if (Xflag==0 || cursym.n_un.n_name[0]!='L' ||
745615Sbill 			    type & N_STAB)
746615Sbill 				nlocal += sizeof cursym;
747615Sbill 			continue;
748615Sbill 		}
749615Sbill 		symreloc();
750615Sbill 		if (enter(lookup()))
751615Sbill 			continue;
752615Sbill 		if ((sp = lastsym)->n_type != N_EXT+N_UNDF)
753615Sbill 			continue;
754615Sbill 		if (cursym.n_type == N_EXT+N_UNDF) {
755615Sbill 			if (cursym.n_value > sp->n_value)
756615Sbill 				sp->n_value = cursym.n_value;
757615Sbill 			continue;
758615Sbill 		}
759615Sbill 		if (sp->n_value != 0 && cursym.n_type == N_EXT+N_TEXT)
760615Sbill 			continue;
761615Sbill 		ndef++;
762615Sbill 		sp->n_type = cursym.n_type;
763615Sbill 		sp->n_value = cursym.n_value;
764615Sbill 	}
765615Sbill 	if (libflg==0 || ndef) {
766615Sbill 		tsize += filhdr.a_text;
767615Sbill 		dsize += round(filhdr.a_data, sizeof (long));
768615Sbill 		bsize += round(filhdr.a_bss, sizeof (long));
769615Sbill 		ssize += nlocal;
770615Sbill 		trsize += filhdr.a_trsize;
771615Sbill 		drsize += filhdr.a_drsize;
772615Sbill 		if (funding)
773615Sbill 			textbase = (*slookup("_end"))->n_value;
774615Sbill 		nsymt = symx(nextsym);
775615Sbill 		for (i = symx(savnext); i < nsymt; i++) {
776615Sbill 			sp = xsym(i);
777615Sbill 			sp->n_un.n_name = savestr(sp->n_un.n_name);
778615Sbill 		}
779615Sbill 		free(curstr);
780615Sbill 		return (1);
781615Sbill 	}
782615Sbill 	/*
783615Sbill 	 * No symbols defined by this library member.
784615Sbill 	 * Rip out the hash table entries and reset the symbol table.
785615Sbill 	 */
786615Sbill 	symfree(savnext);
787615Sbill 	free(curstr);
788615Sbill 	return(0);
789615Sbill }
790615Sbill 
791615Sbill middle()
792615Sbill {
793615Sbill 	register struct nlist *sp;
794615Sbill 	long csize, t, corigin, ocsize;
795615Sbill 	int nund, rnd;
796615Sbill 	char s;
797615Sbill 	register int i;
798615Sbill 	int nsymt;
799615Sbill 
800615Sbill 	torigin = 0;
801615Sbill 	dorigin = 0;
802615Sbill 	borigin = 0;
803615Sbill 
804615Sbill 	p_etext = *slookup("_etext");
805615Sbill 	p_edata = *slookup("_edata");
806615Sbill 	p_end = *slookup("_end");
807615Sbill 	/*
808615Sbill 	 * If there are any undefined symbols, save the relocation bits.
809615Sbill 	 */
810615Sbill 	nsymt = symx(nextsym);
811615Sbill 	if (rflag==0) {
812615Sbill 		for (i = 0; i < nsymt; i++) {
813615Sbill 			sp = xsym(i);
814615Sbill 			if (sp->n_type==N_EXT+N_UNDF && sp->n_value==0 &&
815*650Sbill 			    sp!=p_end && sp!=p_edata && sp!=p_etext) {
816615Sbill 				rflag++;
817615Sbill 				dflag = 0;
818615Sbill 				break;
819615Sbill 			}
820615Sbill 		}
821615Sbill 	}
822615Sbill 	if (rflag)
823615Sbill 		sflag = zflag = 0;
824615Sbill 	/*
825615Sbill 	 * Assign common locations.
826615Sbill 	 */
827615Sbill 	csize = 0;
828615Sbill 	if (!Aflag)
829615Sbill 		addsym = symseg[0].sy_first;
830615Sbill 	database = round(tsize+textbase,
831615Sbill 	    (nflag||zflag? PAGSIZ : sizeof (long)));
832615Sbill 	database += hsize;
833615Sbill 	if (dflag || rflag==0) {
834615Sbill 		ldrsym(p_etext, tsize, N_EXT+N_TEXT);
835615Sbill 		ldrsym(p_edata, dsize, N_EXT+N_DATA);
836615Sbill 		ldrsym(p_end, bsize, N_EXT+N_BSS);
837615Sbill 		for (i = symx(addsym); i < nsymt; i++) {
838615Sbill 			sp = xsym(i);
839615Sbill 			if ((s=sp->n_type)==N_EXT+N_UNDF &&
840615Sbill 			    (t = sp->n_value)!=0) {
841615Sbill 				if (t >= sizeof (double))
842615Sbill 					rnd = sizeof (double);
843615Sbill 				else if (t >= sizeof (long))
844615Sbill 					rnd = sizeof (long);
845615Sbill 				else
846615Sbill 					rnd = sizeof (short);
847615Sbill 				csize = round(csize, rnd);
848615Sbill 				sp->n_value = csize;
849615Sbill 				sp->n_type = N_EXT+N_COMM;
850615Sbill 				ocsize = csize;
851615Sbill 				csize += t;
852615Sbill 			}
853615Sbill 			if (s&N_EXT && (s&N_TYPE)==N_UNDF && s&N_STAB) {
854615Sbill 				sp->n_value = ocsize;
855615Sbill 				sp->n_type = (s&N_STAB) | (N_EXT+N_COMM);
856615Sbill 			}
857615Sbill 		}
858615Sbill 	}
859615Sbill 	/*
860615Sbill 	 * Now set symbols to their final value
861615Sbill 	 */
862615Sbill 	csize = round(csize, sizeof (long));
863615Sbill 	torigin = textbase;
864615Sbill 	dorigin = database;
865615Sbill 	corigin = dorigin + dsize;
866615Sbill 	borigin = corigin + csize;
867615Sbill 	nund = 0;
868615Sbill 	nsymt = symx(nextsym);
869615Sbill 	for (i = symx(addsym); i<nsymt; i++) {
870615Sbill 		sp = xsym(i);
871615Sbill 		switch (sp->n_type & (N_TYPE+N_EXT)) {
872615Sbill 
873615Sbill 		case N_EXT+N_UNDF:
874615Sbill 			errlev |= 01;
875615Sbill 			if ((arflag==0 || dflag) && sp->n_value==0) {
876*650Sbill 				if (sp==p_end || sp==p_etext || sp==p_edata)
877*650Sbill 					continue;
878615Sbill 				if (nund==0)
879615Sbill 					printf("Undefined:\n");
880615Sbill 				nund++;
881615Sbill 				printf("%s\n", sp->n_un.n_name);
882615Sbill 			}
883615Sbill 			continue;
884615Sbill 		case N_EXT+N_ABS:
885615Sbill 		default:
886615Sbill 			continue;
887615Sbill 		case N_EXT+N_TEXT:
888615Sbill 			sp->n_value += torigin;
889615Sbill 			continue;
890615Sbill 		case N_EXT+N_DATA:
891615Sbill 			sp->n_value += dorigin;
892615Sbill 			continue;
893615Sbill 		case N_EXT+N_BSS:
894615Sbill 			sp->n_value += borigin;
895615Sbill 			continue;
896615Sbill 		case N_EXT+N_COMM:
897615Sbill 			sp->n_type = (sp->n_type & N_STAB) | (N_EXT+N_BSS);
898615Sbill 			sp->n_value += corigin;
899615Sbill 			continue;
900615Sbill 		}
901615Sbill 	}
902615Sbill 	if (sflag || xflag)
903615Sbill 		ssize = 0;
904615Sbill 	bsize += csize;
905615Sbill 	nsym = ssize / (sizeof cursym);
906615Sbill 	if (Aflag) {
907615Sbill 		fixspec(p_etext,torigin);
908615Sbill 		fixspec(p_edata,dorigin);
909615Sbill 		fixspec(p_end,borigin);
910615Sbill 	}
911615Sbill }
912615Sbill 
913615Sbill fixspec(sym,offset)
914615Sbill 	struct nlist *sym;
915615Sbill 	long offset;
916615Sbill {
917615Sbill 
918615Sbill 	if(symx(sym) < symx(addsym) && sym!=0)
919615Sbill 		sym->n_value += offset;
920615Sbill }
921615Sbill 
922615Sbill ldrsym(sp, val, type)
923615Sbill 	register struct nlist *sp;
924615Sbill 	long val;
925615Sbill {
926615Sbill 
927615Sbill 	if (sp == 0)
928615Sbill 		return;
929615Sbill 	if ((sp->n_type != N_EXT+N_UNDF || sp->n_value) && !Aflag) {
930615Sbill 		printf("%s: ", sp->n_un.n_name);
931615Sbill 		error(0, "user attempt to redfine loader-defined symbol");
932615Sbill 		return;
933615Sbill 	}
934615Sbill 	sp->n_type = type;
935615Sbill 	sp->n_value = val;
936615Sbill }
937615Sbill 
938615Sbill off_t	wroff;
939615Sbill struct	biobuf toutb;
940615Sbill 
941615Sbill setupout()
942615Sbill {
943615Sbill 	int bss;
944615Sbill 
945615Sbill 	biofd = creat(ofilename, 0666);
946615Sbill 	if (biofd < 0)
947615Sbill 		error(1, "cannot create output");
948615Sbill 	tout = &toutb;
949615Sbill 	bopen(tout, 0);
950615Sbill 	filhdr.a_magic = nflag ? NMAGIC : (zflag ? ZMAGIC : OMAGIC);
951615Sbill 	filhdr.a_text = nflag ? tsize :
952615Sbill 	    round(tsize, zflag ? PAGSIZ : sizeof (long));
953615Sbill 	filhdr.a_data = zflag ? round(dsize, PAGSIZ) : dsize;
954615Sbill 	bss = bsize - (filhdr.a_data - dsize);
955615Sbill 	if (bss < 0)
956615Sbill 		bss = 0;
957615Sbill 	filhdr.a_bss = bss;
958615Sbill 	filhdr.a_trsize = trsize;
959615Sbill 	filhdr.a_drsize = drsize;
960615Sbill 	filhdr.a_syms = sflag? 0: (ssize + (sizeof cursym)*symx(nextsym));
961615Sbill 	if (entrypt) {
962615Sbill 		if (entrypt->n_type!=N_EXT+N_TEXT)
963615Sbill 			error(0, "entry point not in text");
964615Sbill 		else
965615Sbill 			filhdr.a_entry = entrypt->n_value;
966615Sbill 	} else
967615Sbill 		filhdr.a_entry = 0;
968615Sbill 	filhdr.a_trsize = (rflag ? trsize:0);
969615Sbill 	filhdr.a_drsize = (rflag ? drsize:0);
970615Sbill 	bwrite((char *)&filhdr, sizeof (filhdr), tout);
971615Sbill 	if (zflag) {
972615Sbill 		bflush1(tout);
973615Sbill 		biobufs = 0;
974615Sbill 		bopen(tout, PAGSIZ);
975615Sbill 	}
976615Sbill 	wroff = N_TXTOFF(filhdr) + filhdr.a_text;
977615Sbill 	outb(&dout, filhdr.a_data);
978615Sbill 	if (rflag) {
979615Sbill 		outb(&trout, filhdr.a_trsize);
980615Sbill 		outb(&drout, filhdr.a_drsize);
981615Sbill 	}
982615Sbill 	if (sflag==0 || xflag==0) {
983615Sbill 		outb(&sout, filhdr.a_syms);
984615Sbill 		wroff += sizeof (offset);
985615Sbill 		outb(&strout, 0);
986615Sbill 	}
987615Sbill }
988615Sbill 
989615Sbill outb(bp, inc)
990615Sbill 	register struct biobuf **bp;
991615Sbill {
992615Sbill 
993615Sbill 	*bp = (struct biobuf *)malloc(sizeof (struct biobuf));
994615Sbill 	if (*bp == 0)
995615Sbill 		error(1, "ran out of memory (outb)");
996615Sbill 	bopen(*bp, wroff);
997615Sbill 	wroff += inc;
998615Sbill }
999615Sbill 
1000615Sbill load2arg(acp)
1001615Sbill char *acp;
1002615Sbill {
1003615Sbill 	register char *cp;
1004615Sbill 	off_t loc;
1005615Sbill 
1006615Sbill 	cp = acp;
1007615Sbill 	if (getfile(cp) == 0) {
1008615Sbill 		while (*cp)
1009615Sbill 			cp++;
1010615Sbill 		while (cp >= acp && *--cp != '/');
1011615Sbill 		mkfsym(++cp);
1012615Sbill 		load2(0L);
1013615Sbill 	} else {	/* scan archive members referenced */
1014615Sbill 		for (;;) {
1015615Sbill 			if (clibseg->li_used2 == clibseg->li_used) {
1016615Sbill 				if (clibseg->li_used < NROUT)
1017615Sbill 					error(1, "libseg botch");
1018615Sbill 				clibseg++;
1019615Sbill 			}
1020615Sbill 			loc = clibseg->li_first[clibseg->li_used2++];
1021615Sbill 			if (loc == -1)
1022615Sbill 				break;
1023615Sbill 			dseek(&text, loc, (long)sizeof(archdr));
1024615Sbill 			getarhdr();
1025615Sbill 			mkfsym(archdr.ar_name);
1026615Sbill 			load2(loc + (long)sizeof(archdr));
1027615Sbill 		}
1028615Sbill 	}
1029615Sbill 	close(infil);
1030615Sbill }
1031615Sbill 
1032615Sbill load2(loc)
1033615Sbill long loc;
1034615Sbill {
1035615Sbill 	int size;
1036615Sbill 	register struct nlist *sp;
1037615Sbill 	register struct local *lp;
1038615Sbill 	register int symno, i;
1039615Sbill 	int type;
1040615Sbill 
1041615Sbill 	readhdr(loc);
1042*650Sbill 	if (!funding) {
1043615Sbill 		ctrel = torigin;
1044615Sbill 		cdrel += dorigin;
1045615Sbill 		cbrel += borigin;
1046615Sbill 	}
1047615Sbill 	/*
1048615Sbill 	 * Reread the symbol table, recording the numbering
1049615Sbill 	 * of symbols for fixing external references.
1050615Sbill 	 */
1051615Sbill 	for (i = 0; i < LHSIZ; i++)
1052615Sbill 		lochash[i] = 0;
1053615Sbill 	clocseg = locseg;
1054615Sbill 	clocseg->lo_used = 0;
1055615Sbill 	symno = -1;
1056615Sbill 	loc += N_TXTOFF(filhdr);
1057615Sbill 	dseek(&text, loc+filhdr.a_text+filhdr.a_data+
1058615Sbill 		filhdr.a_trsize+filhdr.a_drsize+filhdr.a_syms, sizeof(off_t));
1059615Sbill 	mget(&size, sizeof(size), &text);
1060615Sbill 	dseek(&text, loc+filhdr.a_text+filhdr.a_data+
1061615Sbill 		filhdr.a_trsize+filhdr.a_drsize+filhdr.a_syms+sizeof(off_t),
1062615Sbill 		size - sizeof(off_t));
1063615Sbill 	curstr = (char *)malloc(size);
1064615Sbill 	if (curstr == NULL)
1065615Sbill 		error(1, "out of space reading string table (pass 2)");
1066615Sbill 	mget(curstr+sizeof(off_t), size-sizeof(off_t), &text);
1067615Sbill 	dseek(&text, loc+filhdr.a_text+filhdr.a_data+
1068615Sbill 		filhdr.a_trsize+filhdr.a_drsize, filhdr.a_syms);
1069615Sbill 	while (text.size > 0) {
1070615Sbill 		symno++;
1071615Sbill 		mget((char *)&cursym, sizeof(struct nlist), &text);
1072615Sbill 		if (cursym.n_un.n_strx) {
1073615Sbill 			if (cursym.n_un.n_strx<sizeof(size) ||
1074615Sbill 			    cursym.n_un.n_strx>=size)
1075615Sbill 				error(1, "bad string table index (pass 2)");
1076615Sbill 			cursym.n_un.n_name = curstr + cursym.n_un.n_strx;
1077615Sbill 		}
1078615Sbill /* inline expansion of symreloc() */
1079615Sbill 		switch (cursym.n_type & 017) {
1080615Sbill 
1081615Sbill 		case N_TEXT:
1082615Sbill 		case N_EXT+N_TEXT:
1083615Sbill 			cursym.n_value += ctrel;
1084615Sbill 			break;
1085615Sbill 		case N_DATA:
1086615Sbill 		case N_EXT+N_DATA:
1087615Sbill 			cursym.n_value += cdrel;
1088615Sbill 			break;
1089615Sbill 		case N_BSS:
1090615Sbill 		case N_EXT+N_BSS:
1091615Sbill 			cursym.n_value += cbrel;
1092615Sbill 			break;
1093615Sbill 		case N_EXT+N_UNDF:
1094615Sbill 			break;
1095615Sbill 		default:
1096615Sbill 			if (cursym.n_type&N_EXT)
1097615Sbill 				cursym.n_type = N_EXT+N_ABS;
1098615Sbill 		}
1099615Sbill /* end inline expansion of symreloc() */
1100615Sbill 		type = cursym.n_type;
1101615Sbill 		if ((type&N_EXT) == 0) {
1102615Sbill 			if (!sflag&&!xflag&&
1103615Sbill 			    (!Xflag||cursym.n_un.n_name[0]!='L'||type&N_STAB))
1104615Sbill 				symwrite(&cursym, sout);
1105615Sbill 			continue;
1106615Sbill 		}
1107615Sbill 		if (funding)
1108615Sbill 			continue;
1109615Sbill 		if ((sp = *lookup()) == 0)
1110615Sbill 			error(1, "internal error: symbol not found");
1111615Sbill 		if (cursym.n_type == N_EXT+N_UNDF) {
1112615Sbill 			if (clocseg->lo_used == NSYMPR) {
1113615Sbill 				if (++clocseg == &locseg[NSEG])
1114615Sbill 					error(1, "local symbol overflow");
1115615Sbill 				clocseg->lo_used = 0;
1116615Sbill 			}
1117615Sbill 			if (clocseg->lo_first == 0) {
1118615Sbill 				clocseg->lo_first = (struct local *)
1119615Sbill 				    malloc(NSYMPR * sizeof (struct local));
1120615Sbill 				if (clocseg->lo_first == 0)
1121615Sbill 					error(1, "out of memory (clocseg)");
1122615Sbill 			}
1123615Sbill 			lp = &clocseg->lo_first[clocseg->lo_used++];
1124615Sbill 			lp->l_index = symno;
1125615Sbill 			lp->l_symbol = sp;
1126615Sbill 			lp->l_link = lochash[symno % LHSIZ];
1127615Sbill 			lochash[symno % LHSIZ] = lp;
1128615Sbill 			continue;
1129615Sbill 		}
1130615Sbill 		if (cursym.n_type & N_STAB)
1131615Sbill 			continue;
1132615Sbill 		if (cursym.n_type!=sp->n_type || cursym.n_value!=sp->n_value) {
1133615Sbill 			printf("%s: ", cursym.n_un.n_name);
1134615Sbill 			error(0, "multiply defined");
1135615Sbill 		}
1136615Sbill 	}
1137615Sbill 	if (funding)
1138615Sbill 		return;
1139615Sbill 	dseek(&text, loc, filhdr.a_text);
1140615Sbill 	dseek(&reloc, loc+filhdr.a_text+filhdr.a_data, filhdr.a_trsize);
1141*650Sbill 	load2td(ctrel, torigin - textbase, tout, trout);
1142615Sbill 	dseek(&text, loc+filhdr.a_text, filhdr.a_data);
1143615Sbill 	dseek(&reloc, loc+filhdr.a_text+filhdr.a_data+filhdr.a_trsize,
1144615Sbill 	    filhdr.a_drsize);
1145*650Sbill 	load2td(cdrel, dorigin - database, dout, drout);
1146615Sbill 	while (filhdr.a_data & (sizeof(long)-1)) {
1147615Sbill 		bputc(0, dout);
1148615Sbill 		filhdr.a_data++;
1149615Sbill 	}
1150615Sbill 	torigin += filhdr.a_text;
1151615Sbill 	dorigin += filhdr.a_data;
1152615Sbill 	borigin += filhdr.a_bss;
1153615Sbill 	free(curstr);
1154615Sbill }
1155615Sbill 
1156*650Sbill /*
1157*650Sbill  * This routine relocates the single text or data segment argument.
1158*650Sbill  * Offsets from external symbols are resolved by adding the value
1159*650Sbill  * of the external symbols.  Non-external reference are updated to account
1160*650Sbill  * for the relative motion of the segments (ctrel, cdrel, ...).  If
1161*650Sbill  * a relocation was pc-relative, then we update it to reflect the
1162*650Sbill  * change in the positioning of the segments by adding the displacement
1163*650Sbill  * of the referenced segment and subtracting the displacement of the
1164*650Sbill  * current segment (creloc).
1165*650Sbill  *
1166*650Sbill  * If we are saving the relocation information, then we increase
1167*650Sbill  * each relocation datum address by our base position in the new segment.
1168*650Sbill  */
1169*650Sbill load2td(creloc, position, b1, b2)
1170*650Sbill 	long creloc, offset;
1171615Sbill 	struct biobuf *b1, *b2;
1172615Sbill {
1173615Sbill 	register struct nlist *sp;
1174615Sbill 	register struct local *lp;
1175615Sbill 	long tw;
1176615Sbill 	register struct relocation_info *rp, *rpend;
1177615Sbill 	struct relocation_info *relp;
1178615Sbill 	char *codep;
1179615Sbill 	register char *cp;
1180615Sbill 	int relsz, codesz;
1181615Sbill 
1182615Sbill 	relsz = reloc.size;
1183615Sbill 	relp = (struct relocation_info *)malloc(relsz);
1184615Sbill 	codesz = text.size;
1185615Sbill 	codep = (char *)malloc(codesz);
1186615Sbill 	if (relp == 0 || codep == 0)
1187615Sbill 		error(1, "out of memory (load2td)");
1188615Sbill 	mget((char *)relp, relsz, &reloc);
1189615Sbill 	rpend = &relp[relsz / sizeof (struct relocation_info)];
1190615Sbill 	mget(codep, codesz, &text);
1191615Sbill 	for (rp = relp; rp < rpend; rp++) {
1192615Sbill 		cp = codep + rp->r_address;
1193*650Sbill 		/*
1194*650Sbill 		 * Pick up previous value at location to be relocated.
1195*650Sbill 		 */
1196615Sbill 		switch (rp->r_length) {
1197615Sbill 
1198615Sbill 		case 0:		/* byte */
1199615Sbill 			tw = *cp;
1200615Sbill 			break;
1201615Sbill 
1202615Sbill 		case 1:		/* word */
1203615Sbill 			tw = *(short *)cp;
1204615Sbill 			break;
1205615Sbill 
1206615Sbill 		case 2:		/* long */
1207615Sbill 			tw = *(long *)cp;
1208615Sbill 			break;
1209615Sbill 
1210615Sbill 		default:
1211615Sbill 			error(1, "load2td botch: bad length");
1212615Sbill 		}
1213*650Sbill 		/*
1214*650Sbill 		 * If relative to an external which is defined,
1215*650Sbill 		 * resolve to a simpler kind of reference in the
1216*650Sbill 		 * result file.  If the external is undefined, just
1217*650Sbill 		 * convert the symbol number to the number of the
1218*650Sbill 		 * symbol in the result file and leave it undefined.
1219*650Sbill 		 */
1220615Sbill 		if (rp->r_extern) {
1221*650Sbill 			/*
1222*650Sbill 			 * Search the hash table which maps local
1223*650Sbill 			 * symbol numbers to symbol tables entries
1224*650Sbill 			 * in the new a.out file.
1225*650Sbill 			 */
1226615Sbill 			lp = lochash[rp->r_symbolnum % LHSIZ];
1227615Sbill 			while (lp->l_index != rp->r_symbolnum) {
1228615Sbill 				lp = lp->l_link;
1229615Sbill 				if (lp == 0)
1230615Sbill 					error(1, "local symbol botch");
1231615Sbill 			}
1232615Sbill 			sp = lp->l_symbol;
1233615Sbill 			if (sp->n_type == N_EXT+N_UNDF)
1234615Sbill 				rp->r_symbolnum = nsym+symx(sp);
1235615Sbill 			else {
1236615Sbill 				rp->r_symbolnum = sp->n_type & N_TYPE;
1237615Sbill 				tw += sp->n_value;
1238615Sbill 				rp->r_extern = 0;
1239615Sbill 			}
1240615Sbill 		} else switch (rp->r_symbolnum & N_TYPE) {
1241*650Sbill 		/*
1242*650Sbill 		 * Relocation is relative to the loaded position
1243*650Sbill 		 * of another segment.  Update by the change in position
1244*650Sbill 		 * of that segment.
1245*650Sbill 		 */
1246615Sbill 		case N_TEXT:
1247615Sbill 			tw += ctrel;
1248615Sbill 			break;
1249615Sbill 		case N_DATA:
1250615Sbill 			tw += cdrel;
1251615Sbill 			break;
1252615Sbill 		case N_BSS:
1253615Sbill 			tw += cbrel;
1254615Sbill 			break;
1255615Sbill 		case N_ABS:
1256615Sbill 			break;
1257615Sbill 		default:
1258615Sbill 			error(1, "relocation format botch (symbol type))");
1259615Sbill 		}
1260*650Sbill 		/*
1261*650Sbill 		 * Relocation is pc relative, so decrease the relocation
1262*650Sbill 		 * by the amount the current segment is displaced.
1263*650Sbill 		 * (E.g if we are a relative reference to a text location
1264*650Sbill 		 * from data space, we added the increase in the text address
1265*650Sbill 		 * above, and subtract the increase in our (data) address
1266*650Sbill 		 * here, leaving the net change the relative change in the
1267*650Sbill 		 * positioning of our text and data segments.)
1268*650Sbill 		 */
1269615Sbill 		if (rp->r_pcrel)
1270615Sbill 			tw -= creloc;
1271*650Sbill 		/*
1272*650Sbill 		 * Put the value back in the segment,
1273*650Sbill 		 * while checking for overflow.
1274*650Sbill 		 */
1275615Sbill 		switch (rp->r_length) {
1276615Sbill 
1277615Sbill 		case 0:		/* byte */
1278615Sbill 			if (tw < -128 || tw > 127)
1279615Sbill 				error(0, "byte displacement overflow");
1280615Sbill 			*cp = tw;
1281615Sbill 			break;
1282615Sbill 		case 1:		/* word */
1283615Sbill 			if (tw < -32768 || tw > 32767)
1284615Sbill 				error(0, "word displacement overflow");
1285615Sbill 			*(short *)cp = tw;
1286615Sbill 			break;
1287615Sbill 		case 2:		/* long */
1288615Sbill 			*(long *)cp = tw;
1289615Sbill 			break;
1290615Sbill 		}
1291*650Sbill 		/*
1292*650Sbill 		 * If we are saving relocation information,
1293*650Sbill 		 * we must convert the address in the segment from
1294*650Sbill 		 * the old .o file into an address in the segment in
1295*650Sbill 		 * the new a.out, by adding the position of our
1296*650Sbill 		 * segment in the new larger segment.
1297*650Sbill 		 */
1298615Sbill 		if (rflag)
1299*650Sbill 			rp->r_address += position;
1300615Sbill 	}
1301615Sbill 	bwrite(codep, codesz, b1);
1302615Sbill 	if (rflag)
1303615Sbill 		bwrite(relp, relsz, b2);
1304615Sbill 	cfree((char *)relp);
1305615Sbill 	cfree(codep);
1306615Sbill }
1307615Sbill 
1308615Sbill finishout()
1309615Sbill {
1310615Sbill 	register int i;
1311615Sbill 	int nsymt;
1312615Sbill 
1313615Sbill 	if (sflag==0) {
1314615Sbill 		nsymt = symx(nextsym);
1315615Sbill 		for (i = 0; i < nsymt; i++)
1316615Sbill 			symwrite(xsym(i), sout);
1317615Sbill 		bwrite(&offset, sizeof offset, sout);
1318615Sbill 	}
1319615Sbill 	if (!ofilfnd) {
1320615Sbill 		unlink("a.out");
1321615Sbill 		link("l.out", "a.out");
1322615Sbill 		ofilename = "a.out";
1323615Sbill 	}
1324615Sbill 	delarg = errlev;
1325615Sbill 	delexit();
1326615Sbill }
1327615Sbill 
1328615Sbill mkfsym(s)
1329615Sbill char *s;
1330615Sbill {
1331615Sbill 
1332615Sbill 	if (sflag || xflag)
1333615Sbill 		return;
1334615Sbill 	cursym.n_un.n_name = s;
1335615Sbill 	cursym.n_type = N_TEXT;
1336615Sbill 	cursym.n_value = torigin;
1337615Sbill 	symwrite(&cursym, sout);
1338615Sbill }
1339615Sbill 
1340615Sbill getarhdr()
1341615Sbill {
1342615Sbill 	register char *cp;
1343615Sbill 
1344615Sbill 	mget((char *)&archdr, sizeof archdr, &text);
1345615Sbill 	for (cp=archdr.ar_name; cp<&archdr.ar_name[sizeof(archdr.ar_name)];)
1346615Sbill 		if (*cp++ == ' ') {
1347615Sbill 			cp[-1] = 0;
1348615Sbill 			return;
1349615Sbill 		}
1350615Sbill }
1351615Sbill 
1352615Sbill mget(loc, n, sp)
1353615Sbill register STREAM *sp;
1354615Sbill register char *loc;
1355615Sbill {
1356615Sbill 	register char *p;
1357615Sbill 	register int take;
1358615Sbill 
1359615Sbill top:
1360615Sbill 	if (n == 0)
1361615Sbill 		return;
1362615Sbill 	if (sp->size && sp->nibuf) {
1363615Sbill 		p = sp->ptr;
1364615Sbill 		take = sp->size;
1365615Sbill 		if (take > sp->nibuf)
1366615Sbill 			take = sp->nibuf;
1367615Sbill 		if (take > n)
1368615Sbill 			take = n;
1369615Sbill 		n -= take;
1370615Sbill 		sp->size -= take;
1371615Sbill 		sp->nibuf -= take;
1372615Sbill 		sp->pos += take;
1373615Sbill 		do
1374615Sbill 			*loc++ = *p++;
1375615Sbill 		while (--take > 0);
1376615Sbill 		sp->ptr = p;
1377615Sbill 		goto top;
1378615Sbill 	}
1379615Sbill 	if (n > BUFSIZ) {
1380615Sbill 		take = n - n % BSIZE;
1381615Sbill 		lseek(infil, (sp->bno+1)*BSIZE, 0);
1382615Sbill 		if (take > sp->size || read(infil, loc, take) != take)
1383615Sbill 			error(1, "premature EOF");
1384615Sbill 		loc += take;
1385615Sbill 		n -= take;
1386615Sbill 		sp->size -= take;
1387615Sbill 		sp->pos += take;
1388615Sbill 		dseek(sp, (sp->bno+1+take/BSIZE)*BSIZE, -1);
1389615Sbill 		goto top;
1390615Sbill 	}
1391615Sbill 	*loc++ = get(sp);
1392615Sbill 	--n;
1393615Sbill 	goto top;
1394615Sbill }
1395615Sbill 
1396615Sbill symwrite(sp, bp)
1397615Sbill 	struct nlist *sp;
1398615Sbill 	struct biobuf *bp;
1399615Sbill {
1400615Sbill 	register int len;
1401615Sbill 	register char *str;
1402615Sbill 
1403615Sbill 	str = sp->n_un.n_name;
1404615Sbill 	if (str) {
1405615Sbill 		sp->n_un.n_strx = offset;
1406615Sbill 		len = strlen(str) + 1;
1407615Sbill 		bwrite(str, len, strout);
1408615Sbill 		offset += len;
1409615Sbill 	}
1410615Sbill 	bwrite(sp, sizeof (*sp), bp);
1411615Sbill 	sp->n_un.n_name = str;
1412615Sbill }
1413615Sbill 
1414615Sbill dseek(sp, loc, s)
1415615Sbill register STREAM *sp;
1416615Sbill long loc, s;
1417615Sbill {
1418615Sbill 	register PAGE *p;
1419615Sbill 	register b, o;
1420615Sbill 	int n;
1421615Sbill 
1422615Sbill 	b = loc>>BSHIFT;
1423615Sbill 	o = loc&BMASK;
1424615Sbill 	if (o&01)
1425615Sbill 		error(1, "loader error; odd offset");
1426615Sbill 	--sp->pno->nuser;
1427615Sbill 	if ((p = &page[0])->bno!=b && (p = &page[1])->bno!=b)
1428615Sbill 		if (p->nuser==0 || (p = &page[0])->nuser==0) {
1429615Sbill 			if (page[0].nuser==0 && page[1].nuser==0)
1430615Sbill 				if (page[0].bno < page[1].bno)
1431615Sbill 					p = &page[0];
1432615Sbill 			p->bno = b;
1433615Sbill 			lseek(infil, loc & ~(long)BMASK, 0);
1434615Sbill 			if ((n = read(infil, p->buff, sizeof(p->buff))) < 0)
1435615Sbill 				n = 0;
1436615Sbill 			p->nibuf = n;
1437615Sbill 	} else
1438615Sbill 		error(1, "botch: no pages");
1439615Sbill 	++p->nuser;
1440615Sbill 	sp->bno = b;
1441615Sbill 	sp->pno = p;
1442615Sbill 	if (s != -1) {sp->size = s; sp->pos = 0;}
1443615Sbill 	sp->ptr = (char *)(p->buff + o);
1444615Sbill 	if ((sp->nibuf = p->nibuf-o) <= 0)
1445615Sbill 		sp->size = 0;
1446615Sbill }
1447615Sbill 
1448615Sbill char
1449615Sbill get(asp)
1450615Sbill STREAM *asp;
1451615Sbill {
1452615Sbill 	register STREAM *sp;
1453615Sbill 
1454615Sbill 	sp = asp;
1455615Sbill 	if ((sp->nibuf -= sizeof(char)) < 0) {
1456615Sbill 		dseek(sp, ((long)(sp->bno+1)<<BSHIFT), (long)-1);
1457615Sbill 		sp->nibuf -= sizeof(char);
1458615Sbill 	}
1459615Sbill 	if ((sp->size -= sizeof(char)) <= 0) {
1460615Sbill 		if (sp->size < 0)
1461615Sbill 			error(1, "premature EOF");
1462615Sbill 		++fpage.nuser;
1463615Sbill 		--sp->pno->nuser;
1464615Sbill 		sp->pno = (PAGE *) &fpage;
1465615Sbill 	}
1466615Sbill 	sp->pos += sizeof(char);
1467615Sbill 	return(*sp->ptr++);
1468615Sbill }
1469615Sbill 
1470615Sbill getfile(acp)
1471615Sbill char *acp;
1472615Sbill {
1473615Sbill 	register char *cp;
1474615Sbill 	register int c;
1475615Sbill 	char arcmag[SARMAG+1];
1476615Sbill 	struct stat stb;
1477615Sbill 
1478615Sbill 	cp = acp;
1479615Sbill 	infil = -1;
1480615Sbill 	archdr.ar_name[0] = '\0';
1481615Sbill 	filname = cp;
1482615Sbill 	if (cp[0]=='-' && cp[1]=='l') {
1483615Sbill 		char *locfilname = "/usr/local/new/libxxxxxxxxxxxxxxx";
1484615Sbill 		if(cp[2] == '\0')
1485615Sbill 			cp = "-la";
1486615Sbill 		filname = "/usr/new/libxxxxxxxxxxxxxxx";
1487615Sbill 		for(c=0; cp[c+2]; c++) {
1488615Sbill 			filname[c+12] = cp[c+2];
1489615Sbill 			locfilname[c+18] = cp[c+2];
1490615Sbill 		}
1491615Sbill 		filname[c+12] = locfilname[c+18] = '.';
1492615Sbill 		filname[c+13] = locfilname[c+19] = 'a';
1493615Sbill 		filname[c+14] = locfilname[c+20] = '\0';
1494615Sbill 		if ((infil = open(filname+4, 0)) >= 0) {
1495615Sbill 			filname += 4;
1496615Sbill 		} else if ((infil = open(filname, 0)) < 0) {
1497615Sbill 			filname = locfilname;
1498615Sbill 		}
1499615Sbill 	}
1500615Sbill 	if (infil == -1 && (infil = open(filname, 0)) < 0)
1501615Sbill 		error(1, "cannot open");
1502615Sbill 	page[0].bno = page[1].bno = -1;
1503615Sbill 	page[0].nuser = page[1].nuser = 0;
1504615Sbill 	text.pno = reloc.pno = (PAGE *) &fpage;
1505615Sbill 	fpage.nuser = 2;
1506615Sbill 	dseek(&text, 0L, SARMAG);
1507615Sbill 	if (text.size <= 0)
1508615Sbill 		error(1, "premature EOF");
1509615Sbill 	mget((char *)arcmag, SARMAG, &text);
1510615Sbill 	arcmag[SARMAG] = 0;
1511615Sbill 	if (strcmp(arcmag, ARMAG))
1512615Sbill 		return (0);
1513615Sbill 	dseek(&text, SARMAG, sizeof archdr);
1514615Sbill 	if(text.size <= 0)
1515615Sbill 		return (1);
1516615Sbill 	getarhdr();
1517615Sbill 	if (strncmp(archdr.ar_name, "__.SYMDEF", sizeof(archdr.ar_name)) != 0)
1518615Sbill 		return (1);
1519615Sbill 	fstat(infil, &stb);
1520615Sbill 	return (stb.st_mtime > atol(archdr.ar_date) ? 3 : 2);
1521615Sbill }
1522615Sbill 
1523615Sbill struct nlist **
1524615Sbill lookup()
1525615Sbill {
1526615Sbill 	register int sh;
1527615Sbill 	register struct nlist **hp;
1528615Sbill 	register char *cp, *cp1;
1529615Sbill 	register struct symseg *gp;
1530615Sbill 	register int i;
1531615Sbill 
1532615Sbill 	sh = 0;
1533615Sbill 	for (cp = cursym.n_un.n_name; *cp;)
1534615Sbill 		sh = (sh<<1) + *cp++;
1535615Sbill 	sh = (sh & 0x7fffffff) % HSIZE;
1536615Sbill 	for (gp = symseg; gp < &symseg[NSEG]; gp++) {
1537615Sbill 		if (gp->sy_first == 0) {
1538615Sbill 			gp->sy_first = (struct nlist *)
1539615Sbill 			    calloc(NSYM, sizeof (struct nlist));
1540615Sbill 			gp->sy_hfirst = (struct nlist **)
1541615Sbill 			    calloc(HSIZE, sizeof (struct nlist *));
1542615Sbill 			if (gp->sy_first == 0 || gp->sy_hfirst == 0)
1543615Sbill 				error(1, "ran out of space for symbol table");
1544615Sbill 			gp->sy_last = gp->sy_first + NSYM;
1545615Sbill 			gp->sy_hlast = gp->sy_hfirst + HSIZE;
1546615Sbill 		}
1547615Sbill 		if (gp > csymseg)
1548615Sbill 			csymseg = gp;
1549615Sbill 		hp = gp->sy_hfirst + sh;
1550615Sbill 		i = 1;
1551615Sbill 		do {
1552615Sbill 			if (*hp == 0) {
1553615Sbill 				if (gp->sy_used == NSYM)
1554615Sbill 					break;
1555615Sbill 				return (hp);
1556615Sbill 			}
1557615Sbill 			cp1 = (*hp)->n_un.n_name;
1558615Sbill 			for (cp = cursym.n_un.n_name; *cp == *cp1++;)
1559615Sbill 				if (*cp++ == 0)
1560615Sbill 					return (hp);
1561615Sbill 			hp += i;
1562615Sbill 			i += 2;
1563615Sbill 			if (hp >= gp->sy_hlast)
1564615Sbill 				hp -= HSIZE;
1565615Sbill 		} while (i < HSIZE);
1566615Sbill 		if (i > HSIZE)
1567615Sbill 			error(1, "hash table botch");
1568615Sbill 	}
1569615Sbill 	error(1, "symbol table overflow");
1570615Sbill 	/*NOTREACHED*/
1571615Sbill }
1572615Sbill 
1573615Sbill symfree(saved)
1574615Sbill 	struct nlist *saved;
1575615Sbill {
1576615Sbill 	register struct symseg *gp;
1577615Sbill 	register struct nlist *sp;
1578615Sbill 
1579615Sbill 	for (gp = csymseg; gp >= symseg; gp--, csymseg--) {
1580615Sbill 		sp = gp->sy_first + gp->sy_used;
1581615Sbill 		if (sp == saved) {
1582615Sbill 			nextsym = sp;
1583615Sbill 			return;
1584615Sbill 		}
1585615Sbill 		for (sp--; sp >= gp->sy_first; sp--) {
1586615Sbill 			gp->sy_hfirst[sp->n_hash] = 0;
1587615Sbill 			gp->sy_used--;
1588615Sbill 			if (sp == saved) {
1589615Sbill 				nextsym = sp;
1590615Sbill 				return;
1591615Sbill 			}
1592615Sbill 		}
1593615Sbill 	}
1594615Sbill 	if (saved == 0)
1595615Sbill 		return;
1596615Sbill 	error(1, "symfree botch");
1597615Sbill }
1598615Sbill 
1599615Sbill struct nlist **
1600615Sbill slookup(s)
1601615Sbill 	char *s;
1602615Sbill {
1603615Sbill 
1604615Sbill 	cursym.n_un.n_name = s;
1605615Sbill 	cursym.n_type = N_EXT+N_UNDF;
1606615Sbill 	cursym.n_value = 0;
1607615Sbill 	return (lookup());
1608615Sbill }
1609615Sbill 
1610615Sbill enter(hp)
1611615Sbill register struct nlist **hp;
1612615Sbill {
1613615Sbill 	register struct nlist *sp;
1614615Sbill 
1615615Sbill 	if (*hp==0) {
1616615Sbill 		if (hp < csymseg->sy_hfirst || hp >= csymseg->sy_hlast)
1617615Sbill 			error(1, "enter botch");
1618615Sbill 		*hp = lastsym = sp = csymseg->sy_first + csymseg->sy_used;
1619615Sbill 		csymseg->sy_used++;
1620615Sbill 		sp->n_un.n_name = cursym.n_un.n_name;
1621615Sbill 		sp->n_type = cursym.n_type;
1622615Sbill 		sp->n_hash = hp - csymseg->sy_hfirst;
1623615Sbill 		sp->n_value = cursym.n_value;
1624615Sbill 		nextsym = lastsym + 1;
1625615Sbill 		return(1);
1626615Sbill 	} else {
1627615Sbill 		lastsym = *hp;
1628615Sbill 		return(0);
1629615Sbill 	}
1630615Sbill }
1631615Sbill 
1632615Sbill symx(sp)
1633615Sbill 	struct nlist *sp;
1634615Sbill {
1635615Sbill 	register struct symseg *gp;
1636615Sbill 
1637615Sbill 	if (sp == 0)
1638615Sbill 		return (0);
1639615Sbill 	for (gp = csymseg; gp >= symseg; gp--)
1640615Sbill 		/* <= is sloppy so nextsym will always work */
1641615Sbill 		if (sp >= gp->sy_first && sp <= gp->sy_last)
1642615Sbill 			return ((gp - symseg) * NSYM + sp - gp->sy_first);
1643615Sbill 	error(1, "symx botch");
1644615Sbill 	/*NOTREACHED*/
1645615Sbill }
1646615Sbill 
1647615Sbill symreloc()
1648615Sbill {
1649615Sbill 	if(funding) return;
1650615Sbill 	switch (cursym.n_type & 017) {
1651615Sbill 
1652615Sbill 	case N_TEXT:
1653615Sbill 	case N_EXT+N_TEXT:
1654615Sbill 		cursym.n_value += ctrel;
1655615Sbill 		return;
1656615Sbill 
1657615Sbill 	case N_DATA:
1658615Sbill 	case N_EXT+N_DATA:
1659615Sbill 		cursym.n_value += cdrel;
1660615Sbill 		return;
1661615Sbill 
1662615Sbill 	case N_BSS:
1663615Sbill 	case N_EXT+N_BSS:
1664615Sbill 		cursym.n_value += cbrel;
1665615Sbill 		return;
1666615Sbill 
1667615Sbill 	case N_EXT+N_UNDF:
1668615Sbill 		return;
1669615Sbill 
1670615Sbill 	default:
1671615Sbill 		if (cursym.n_type&N_EXT)
1672615Sbill 			cursym.n_type = N_EXT+N_ABS;
1673615Sbill 		return;
1674615Sbill 	}
1675615Sbill }
1676615Sbill 
1677615Sbill error(n, s)
1678615Sbill char *s;
1679615Sbill {
1680615Sbill 	if (errlev==0)
1681615Sbill 		printf("ld:");
1682615Sbill 	if (filname) {
1683615Sbill 		printf("%s", filname);
1684615Sbill 		if (n != -1 && archdr.ar_name[0])
1685615Sbill 			printf("(%s)", archdr.ar_name);
1686615Sbill 		printf(": ");
1687615Sbill 	}
1688615Sbill 	printf("%s\n", s);
1689615Sbill 	if (n == -1)
1690615Sbill 		return;
1691615Sbill 	if (n)
1692615Sbill 		delexit();
1693615Sbill 	errlev = 2;
1694615Sbill }
1695615Sbill 
1696615Sbill readhdr(loc)
1697615Sbill off_t loc;
1698615Sbill {
1699615Sbill 
1700615Sbill 	dseek(&text, loc, (long)sizeof(filhdr));
1701615Sbill 	mget((short *)&filhdr, sizeof(filhdr), &text);
1702615Sbill 	if (N_BADMAG(filhdr)) {
1703615Sbill 		if (filhdr.a_magic == OARMAG)
1704615Sbill 			error(1, "old archive");
1705615Sbill 		error(1, "bad magic number");
1706615Sbill 	}
1707615Sbill 	if (filhdr.a_text&01 || filhdr.a_data&01)
1708615Sbill 		error(1, "text/data size odd");
1709615Sbill 	if (filhdr.a_magic == NMAGIC || filhdr.a_magic == ZMAGIC) {
1710615Sbill 		cdrel = -round(filhdr.a_text, PAGSIZ);
1711615Sbill 		cbrel = cdrel - filhdr.a_data;
1712615Sbill 	} else if (filhdr.a_magic == OMAGIC) {
1713615Sbill 		cdrel = -filhdr.a_text;
1714615Sbill 		cbrel = cdrel - filhdr.a_data;
1715615Sbill 	} else
1716615Sbill 		error(1, "bad format");
1717615Sbill }
1718615Sbill 
1719615Sbill round(v, r)
1720615Sbill 	int v;
1721615Sbill 	u_long r;
1722615Sbill {
1723615Sbill 
1724615Sbill 	r--;
1725615Sbill 	v += r;
1726615Sbill 	v &= ~(long)r;
1727615Sbill 	return(v);
1728615Sbill }
1729615Sbill 
1730615Sbill #define	NSAVETAB	8192
1731615Sbill char	*savetab;
1732615Sbill int	saveleft;
1733615Sbill 
1734615Sbill char *
1735615Sbill savestr(cp)
1736615Sbill 	register char *cp;
1737615Sbill {
1738615Sbill 	register int len;
1739615Sbill 
1740615Sbill 	len = strlen(cp) + 1;
1741615Sbill 	if (len > saveleft) {
1742615Sbill 		saveleft = NSAVETAB;
1743615Sbill 		if (len > saveleft)
1744615Sbill 			saveleft = len;
1745615Sbill 		savetab = (char *)malloc(saveleft);
1746615Sbill 		if (savetab == 0)
1747615Sbill 			error(1, "ran out of memory (savestr)");
1748615Sbill 	}
1749615Sbill 	strncpy(savetab, cp, len);
1750615Sbill 	cp = savetab;
1751615Sbill 	savetab += len;
1752615Sbill 	saveleft -= len;
1753615Sbill 	return (cp);
1754615Sbill }
1755615Sbill 
1756615Sbill bopen(bp, off)
1757615Sbill 	struct biobuf *bp;
1758615Sbill {
1759615Sbill 
1760615Sbill 	bp->b_ptr = bp->b_buf;
1761615Sbill 	bp->b_nleft = BUFSIZ - off % BUFSIZ;
1762615Sbill 	bp->b_off = off;
1763615Sbill 	bp->b_link = biobufs;
1764615Sbill 	biobufs = bp;
1765615Sbill }
1766615Sbill 
1767615Sbill int	bwrerror;
1768615Sbill 
1769615Sbill bwrite(p, cnt, bp)
1770615Sbill 	register char *p;
1771615Sbill 	register int cnt;
1772615Sbill 	register struct biobuf *bp;
1773615Sbill {
1774615Sbill 	register int put;
1775615Sbill 	register char *to;
1776615Sbill 
1777615Sbill top:
1778615Sbill 	if (cnt == 0)
1779615Sbill 		return;
1780615Sbill 	if (bp->b_nleft) {
1781615Sbill 		put = bp->b_nleft;
1782615Sbill 		if (put > cnt)
1783615Sbill 			put = cnt;
1784615Sbill 		bp->b_nleft -= put;
1785615Sbill 		to = bp->b_ptr;
1786615Sbill 		asm("movc3 r8,(r11),(r7)");
1787615Sbill 		bp->b_ptr += put;
1788615Sbill 		p += put;
1789615Sbill 		cnt -= put;
1790615Sbill 		goto top;
1791615Sbill 	}
1792615Sbill 	if (cnt >= BUFSIZ) {
1793615Sbill 		if (bp->b_ptr != bp->b_buf)
1794615Sbill 			bflush1(bp);
1795615Sbill 		put = cnt - cnt % BUFSIZ;
1796615Sbill 		if (boffset != bp->b_off)
1797615Sbill 			lseek(biofd, bp->b_off, 0);
1798615Sbill 		if (write(biofd, p, put) != put) {
1799615Sbill 			bwrerror = 1;
1800615Sbill 			error(1, "output write error");
1801615Sbill 		}
1802615Sbill 		bp->b_off += put;
1803615Sbill 		boffset = bp->b_off;
1804615Sbill 		p += put;
1805615Sbill 		cnt -= put;
1806615Sbill 		goto top;
1807615Sbill 	}
1808615Sbill 	bflush1(bp);
1809615Sbill 	goto top;
1810615Sbill }
1811615Sbill 
1812615Sbill bflush()
1813615Sbill {
1814615Sbill 	register struct biobuf *bp;
1815615Sbill 
1816615Sbill 	if (bwrerror)
1817615Sbill 		return;
1818615Sbill 	for (bp = biobufs; bp; bp = bp->b_link)
1819615Sbill 		bflush1(bp);
1820615Sbill }
1821615Sbill 
1822615Sbill bflush1(bp)
1823615Sbill 	register struct biobuf *bp;
1824615Sbill {
1825615Sbill 	register int cnt = bp->b_ptr - bp->b_buf;
1826615Sbill 
1827615Sbill 	if (cnt == 0)
1828615Sbill 		return;
1829615Sbill 	if (boffset != bp->b_off)
1830615Sbill 		lseek(biofd, bp->b_off, 0);
1831615Sbill 	if (write(biofd, bp->b_buf, cnt) != cnt) {
1832615Sbill 		bwrerror = 1;
1833615Sbill 		error(1, "output write error");
1834615Sbill 	}
1835615Sbill 	bp->b_off += cnt;
1836615Sbill 	boffset = bp->b_off;
1837615Sbill 	bp->b_ptr = bp->b_buf;
1838615Sbill 	bp->b_nleft = BUFSIZ;
1839615Sbill }
1840615Sbill 
1841615Sbill bflushc(bp, c)
1842615Sbill 	register struct biobuf *bp;
1843615Sbill {
1844615Sbill 
1845615Sbill 	bflush1(bp);
1846615Sbill 	bputc(c, bp);
1847615Sbill }
1848