xref: /csrg-svn/old/ld/ld.c (revision 47961)
1*47961Sbostic /*-
2*47961Sbostic  * Copyright (c) 1980, 1990 The Regents of the University of California.
3*47961Sbostic  * All rights reserved.
4*47961Sbostic  *
5*47961Sbostic  * %sccs.include.proprietary.c%
619842Sdist  */
719842Sdist 
812671Ssam #ifndef lint
919842Sdist char copyright[] =
10*47961Sbostic "@(#) Copyright (c) 1980, 1990 The Regents of the University of California.\n\
1119842Sdist  All rights reserved.\n";
12*47961Sbostic #endif /* not lint */
136414Smckusic 
1419842Sdist #ifndef lint
15*47961Sbostic static char sccsid[] = "@(#)ld.c	5.19 (Berkeley) 04/12/91";
16*47961Sbostic #endif /* not lint */
1719842Sdist 
1817133Ssam #include <sys/param.h>
1942415Sbostic #include <sys/stat.h>
2046696Sbostic #include <fcntl.h>
2146696Sbostic #include <signal.h>
22650Sbill #include <ar.h>
23650Sbill #include <a.out.h>
24615Sbill #include <ranlib.h>
2546696Sbostic #include <unistd.h>
2642415Sbostic #include <stdio.h>
2742415Sbostic #include <ctype.h>
2846696Sbostic #include <stdlib.h>
2942415Sbostic #include <string.h>
3037031Sbostic #include "pathnames.h"
31615Sbill 
32615Sbill /*
33615Sbill  * Basic strategy:
34615Sbill  *
35615Sbill  * The loader takes a number of files and libraries as arguments.
36615Sbill  * A first pass examines each file in turn.  Normal files are
37615Sbill  * unconditionally loaded, and the (external) symbols they define and require
38615Sbill  * are noted in the symbol table.   Libraries are searched, and the
39615Sbill  * library members which define needed symbols are remembered
40615Sbill  * in a special data structure so they can be selected on the second
41615Sbill  * pass.  Symbols defined and required by library members are also
42615Sbill  * recorded.
43615Sbill  *
44615Sbill  * After the first pass, the loader knows the size of the basic text
45615Sbill  * data, and bss segments from the sum of the sizes of the modules which
46615Sbill  * were required.  It has computed, for each ``common'' symbol, the
47615Sbill  * maximum size of any reference to it, and these symbols are then assigned
48615Sbill  * storage locations after their sizes are appropriately rounded.
49615Sbill  * The loader now knows all sizes for the eventual output file, and
50615Sbill  * can determine the final locations of external symbols before it
51615Sbill  * begins a second pass.
52615Sbill  *
53615Sbill  * On the second pass each normal file and required library member
54615Sbill  * is processed again.  The symbol table for each such file is
55615Sbill  * reread and relevant parts of it are placed in the output.  The offsets
56615Sbill  * in the local symbol table for externally defined symbols are recorded
57615Sbill  * since relocation information refers to symbols in this way.
58615Sbill  * Armed with all necessary information, the text and data segments
59615Sbill  * are relocated and the result is placed in the output file, which
60615Sbill  * is pasted together, ``in place'', by writing to it in several
61615Sbill  * different places concurrently.
62615Sbill  */
63615Sbill 
64615Sbill /*
65615Sbill  * Internal data structures
66615Sbill  *
67615Sbill  * All internal data structures are segmented and dynamically extended.
68615Sbill  * The basic structures hold 1103 (NSYM) symbols, ~~200 (NROUT)
69615Sbill  * referenced library members, and 100 (NSYMPR) private (local) symbols
70615Sbill  * per object module.  For large programs and/or modules, these structures
71615Sbill  * expand to be up to 40 (NSEG) times as large as this as necessary.
72615Sbill  */
73615Sbill #define	NSEG	40		/* Number of segments, each data structure */
74615Sbill #define	NSYM	1103		/* Number of symbols per segment */
75615Sbill #define	NROUT	250		/* Number of library references per segment */
76615Sbill #define	NSYMPR	100		/* Number of private symbols per segment */
77615Sbill 
78615Sbill /*
79615Sbill  * Structure describing each symbol table segment.
80615Sbill  * Each segment has its own hash table.  We record the first
81615Sbill  * address in and first address beyond both the symbol and hash
82615Sbill  * tables, for use in the routine symx and the lookup routine respectively.
83615Sbill  * The symfree routine also understands this structure well as it used
84615Sbill  * to back out symbols from modules we decide that we don't need in pass 1.
85615Sbill  *
86615Sbill  * Csymseg points to the current symbol table segment;
87615Sbill  * csymseg->sy_first[csymseg->sy_used] is the next symbol slot to be allocated,
88615Sbill  * (unless csymseg->sy_used == NSYM in which case we will allocate another
89615Sbill  * symbol table segment first.)
90615Sbill  */
91615Sbill struct	symseg {
92615Sbill 	struct	nlist *sy_first;	/* base of this alloc'ed segment */
93615Sbill 	struct	nlist *sy_last;		/* end of this segment, for n_strx */
94615Sbill 	int	sy_used;		/* symbols used in this seg */
95615Sbill 	struct	nlist **sy_hfirst;	/* base of hash table, this seg */
96615Sbill 	struct	nlist **sy_hlast;	/* end of hash table, this seg */
97615Sbill } symseg[NSEG], *csymseg;
98615Sbill 
99615Sbill /*
100615Sbill  * The lookup routine uses quadratic rehash.  Since a quadratic rehash
101615Sbill  * only probes 1/2 of the buckets in the table, and since the hash
102615Sbill  * table is segmented the same way the symbol table is, we make the
103615Sbill  * hash table have twice as many buckets as there are symbol table slots
104615Sbill  * in the segment.  This guarantees that the quadratic rehash will never
105615Sbill  * fail to find an empty bucket if the segment is not full and the
106615Sbill  * symbol is not there.
107615Sbill  */
108615Sbill #define	HSIZE	(NSYM*2)
109615Sbill 
110615Sbill /*
111615Sbill  * Xsym converts symbol table indices (ala x) into symbol table pointers.
112615Sbill  * Symx (harder, but never used in loops) inverts pointers into the symbol
113615Sbill  * table into indices using the symseg[] structure.
114615Sbill  */
115615Sbill #define	xsym(x)	(symseg[(x)/NSYM].sy_first+((x)%NSYM))
116615Sbill /* symx() is a function, defined below */
117615Sbill 
118615Sbill struct	nlist cursym;		/* current symbol */
119615Sbill struct	nlist *lastsym;		/* last symbol entered */
120615Sbill struct	nlist *nextsym;		/* next available symbol table entry */
121615Sbill struct	nlist *addsym;		/* first sym defined during incr load */
122615Sbill int	nsym;			/* pass2: number of local symbols in a.out */
123615Sbill /* nsym + symx(nextsym) is the symbol table size during pass2 */
124615Sbill 
125615Sbill struct	nlist **lookup(), **slookup();
126650Sbill struct	nlist *p_etext, *p_edata, *p_end, *entrypt;
127615Sbill 
128615Sbill /*
129615Sbill  * Definitions of segmentation for library member table.
130615Sbill  * For each library we encounter on pass 1 we record pointers to all
131615Sbill  * members which we will load on pass 2.  These are recorded as offsets
132615Sbill  * into the archive in the library member table.  Libraries are
133615Sbill  * separated in the table by the special offset value -1.
134615Sbill  */
135615Sbill off_t	li_init[NROUT];
136615Sbill struct	libseg {
137615Sbill 	off_t	*li_first;
138615Sbill 	int	li_used;
139615Sbill 	int	li_used2;
140615Sbill } libseg[NSEG] = {
141615Sbill 	li_init, 0, 0,
142615Sbill }, *clibseg = libseg;
143615Sbill 
144615Sbill /*
145615Sbill  * In processing each module on pass 2 we must relocate references
146615Sbill  * relative to external symbols.  These references are recorded
147615Sbill  * in the relocation information as relative to local symbol numbers
148615Sbill  * assigned to the external symbols when the module was created.
149615Sbill  * Thus before relocating the module in pass 2 we create a table
150615Sbill  * which maps these internal numbers to symbol table entries.
151615Sbill  * A hash table is constructed, based on the local symbol table indices,
152615Sbill  * for quick lookup of these symbols.
153615Sbill  */
154615Sbill #define	LHSIZ	31
155615Sbill struct	local {
156615Sbill 	int	l_index;		/* index to symbol in file */
157615Sbill 	struct	nlist *l_symbol;	/* ptr to symbol table */
158615Sbill 	struct	local *l_link;		/* hash link */
159615Sbill } *lochash[LHSIZ], lhinit[NSYMPR];
160615Sbill struct	locseg {
161615Sbill 	struct	local *lo_first;
162615Sbill 	int	lo_used;
163615Sbill } locseg[NSEG] = {
164615Sbill 	lhinit, 0
165615Sbill }, *clocseg;
166615Sbill 
167615Sbill /*
168615Sbill  * Libraries are typically built with a table of contents,
169615Sbill  * which is the first member of a library with special file
170615Sbill  * name __.SYMDEF and contains a list of symbol names
171615Sbill  * and with each symbol the offset of the library member which defines
172615Sbill  * it.  The loader uses this table to quickly tell which library members
173615Sbill  * are (potentially) useful.  The alternative, examining the symbol
174615Sbill  * table of each library member, is painfully slow for large archives.
175615Sbill  *
176615Sbill  * See <ranlib.h> for the definition of the ranlib structure and an
177615Sbill  * explanation of the __.SYMDEF file format.
178615Sbill  */
179615Sbill int	tnum;		/* number of symbols in table of contents */
180615Sbill int	ssiz;		/* size of string table for table of contents */
181615Sbill struct	ranlib *tab;	/* the table of contents (dynamically allocated) */
182615Sbill char	*tabstr;	/* string table for table of contents */
183615Sbill 
184615Sbill /*
185615Sbill  * We open each input file or library only once, but in pass2 we
186615Sbill  * (historically) read from such a file at 2 different places at the
187615Sbill  * same time.  These structures are remnants from those days,
188650Sbill  * and now serve only to catch ``Premature EOF''.
1896414Smckusic  * In order to make I/O more efficient, we provide routines which
19016068Sralph  * use the optimal block size returned by stat().
191615Sbill  */
1926414Smckusic #define BLKSIZE 1024
193615Sbill typedef struct {
194615Sbill 	short	*fakeptr;
195615Sbill 	int	bno;
196615Sbill 	int	nibuf;
197615Sbill 	int	nuser;
19816068Sralph 	char	*buff;
19916068Sralph 	int	bufsize;
200615Sbill } PAGE;
201615Sbill 
202615Sbill PAGE	page[2];
20316068Sralph int	p_blksize;
20416068Sralph int	p_blkshift;
20516068Sralph int	p_blkmask;
206615Sbill 
207615Sbill struct {
208615Sbill 	short	*fakeptr;
209615Sbill 	int	bno;
210615Sbill 	int	nibuf;
211615Sbill 	int	nuser;
212615Sbill } fpage;
213615Sbill 
214615Sbill typedef struct {
215615Sbill 	char	*ptr;
216615Sbill 	int	bno;
217615Sbill 	int	nibuf;
218615Sbill 	long	size;
219615Sbill 	long	pos;
220615Sbill 	PAGE	*pno;
221615Sbill } STREAM;
222615Sbill 
223615Sbill STREAM	text;
224615Sbill STREAM	reloc;
225615Sbill 
226615Sbill /*
227615Sbill  * Header from the a.out and the archive it is from (if any).
228615Sbill  */
229615Sbill struct	exec filhdr;
230615Sbill struct	ar_hdr archdr;
231615Sbill #define	OARMAG 0177545
232615Sbill 
233615Sbill /*
234615Sbill  * Options.
235615Sbill  */
236615Sbill int	trace;
237615Sbill int	xflag;		/* discard local symbols */
238615Sbill int	Xflag;		/* discard locals starting with 'L' */
239615Sbill int	Sflag;		/* discard all except locals and globals*/
240615Sbill int	rflag;		/* preserve relocation bits, don't define common */
241615Sbill int	arflag;		/* original copy of rflag */
242615Sbill int	sflag;		/* discard all symbols */
243898Sbill int	Mflag;		/* print rudimentary load map */
244615Sbill int	nflag;		/* pure procedure */
245615Sbill int	dflag;		/* define common even with rflag */
246650Sbill int	zflag;		/* demand paged  */
247615Sbill long	hsize;		/* size of hole at beginning of data to be squashed */
248615Sbill int	Aflag;		/* doing incremental load */
249650Sbill int	Nflag;		/* want impure a.out */
250615Sbill int	funding;	/* reading fundamental file for incremental load */
251898Sbill int	yflag;		/* number of symbols to be traced */
252898Sbill char	**ytab;		/* the symbols */
253615Sbill 
254615Sbill /*
255615Sbill  * These are the cumulative sizes, set in pass 1, which
256615Sbill  * appear in the a.out header when the loader is finished.
257615Sbill  */
258615Sbill off_t	tsize, dsize, bsize, trsize, drsize, ssize;
259615Sbill 
260615Sbill /*
261615Sbill  * Symbol relocation: c?rel is a scale factor which is
262615Sbill  * added to an old relocation to convert it to new units;
263615Sbill  * i.e. it is the difference between segment origins.
264650Sbill  * (Thus if we are loading from a data segment which began at location
265650Sbill  * 4 in a .o file into an a.out where it will be loaded starting at
266650Sbill  * 1024, cdrel will be 1020.)
267615Sbill  */
268615Sbill long	ctrel, cdrel, cbrel;
269615Sbill 
270615Sbill /*
271650Sbill  * Textbase is the start address of all text, 0 unless given by -T.
272615Sbill  * Database is the base of all data, computed before and used during pass2.
273650Sbill  */
274650Sbill long	textbase, database;
275650Sbill 
276650Sbill /*
277615Sbill  * The base addresses for the loaded text, data and bss from the
278615Sbill  * current module during pass2 are given by torigin, dorigin and borigin.
279615Sbill  */
280615Sbill long	torigin, dorigin, borigin;
281615Sbill 
282615Sbill /*
283615Sbill  * Errlev is nonzero when errors have occured.
284615Sbill  * Delarg is an implicit argument to the routine delexit
285615Sbill  * which is called on error.  We do ``delarg = errlev'' before normal
286615Sbill  * exits, and only if delarg is 0 (i.e. errlev was 0) do we make the
287615Sbill  * result file executable.
288615Sbill  */
289615Sbill int	errlev;
290615Sbill int	delarg	= 4;
291615Sbill 
292615Sbill /*
293615Sbill  * The biobuf structure and associated routines are used to write
294615Sbill  * into one file at several places concurrently.  Calling bopen
295615Sbill  * with a biobuf structure sets it up to write ``biofd'' starting
296615Sbill  * at the specified offset.  You can then use ``bwrite'' and/or ``bputc''
297615Sbill  * to stuff characters in the stream, much like ``fwrite'' and ``fputc''.
298615Sbill  * Calling bflush drains all the buffers and MUST be done before exit.
299615Sbill  */
300615Sbill struct	biobuf {
301615Sbill 	short	b_nleft;		/* Number free spaces left in b_buf */
30216068Sralph /* Initialize to be less than b_bufsize initially, to boundary align in file */
303615Sbill 	char	*b_ptr;			/* Next place to stuff characters */
30416068Sralph 	char	*b_buf;			/* Pointer to the buffer */
30516068Sralph 	int	b_bufsize;		/* Size of the buffer */
306615Sbill 	off_t	b_off;			/* Current file offset */
307615Sbill 	struct	biobuf *b_link;		/* Link in chain for bflush() */
308615Sbill } *biobufs;
309615Sbill #define	bputc(c,b) ((b)->b_nleft ? (--(b)->b_nleft, *(b)->b_ptr++ = (c)) \
310615Sbill 		       : bflushc(b, c))
311615Sbill int	biofd;
312615Sbill off_t	boffset;
313615Sbill struct	biobuf *tout, *dout, *trout, *drout, *sout, *strout;
314615Sbill 
315615Sbill /*
316615Sbill  * Offset is the current offset in the string file.
317615Sbill  * Its initial value reflects the fact that we will
318615Sbill  * eventually stuff the size of the string table at the
319615Sbill  * beginning of the string table (i.e. offset itself!).
320615Sbill  */
321615Sbill off_t	offset = sizeof (off_t);
322615Sbill 
323615Sbill int	ofilfnd;		/* -o given; otherwise move l.out to a.out */
32444768Sbostic char	*ofilename = "l.out";
3253606Ssklower int	ofilemode;		/* respect umask even for unsucessful ld's */
326615Sbill int	infil;			/* current input file descriptor */
327615Sbill char	*filname;		/* and its name */
328615Sbill 
32917133Ssam #define	NDIRS	25
33025533Sbloom #define NDEFDIRS 3		/* number of default directories in dirs[] */
33117133Ssam char	*dirs[NDIRS];		/* directories for library search */
33217133Ssam int	ndir;			/* number of directories */
33317133Ssam 
334615Sbill /*
335615Sbill  * Base of the string table of the current module (pass1 and pass2).
336615Sbill  */
337615Sbill char	*curstr;
338615Sbill 
33912671Ssam /*
34012671Ssam  * System software page size, as returned by getpagesize.
34112671Ssam  */
34212671Ssam int	pagesize;
34312671Ssam 
344615Sbill char 	get();
34546696Sbostic void	delexit();
346615Sbill char	*savestr();
347615Sbill 
main(argc,argv)348615Sbill main(argc, argv)
34946696Sbostic 	int argc;
35046696Sbostic 	char **argv;
351615Sbill {
352615Sbill 	register int c, i;
353615Sbill 	int num;
354615Sbill 	register char *ap, **p;
355615Sbill 	char save;
356615Sbill 
357650Sbill 	if (signal(SIGINT, SIG_IGN) != SIG_IGN) {
358615Sbill 		signal(SIGINT, delexit);
359650Sbill 		signal(SIGTERM, delexit);
360650Sbill 	}
361615Sbill 	if (argc == 1)
362615Sbill 		exit(4);
36312671Ssam 	pagesize = getpagesize();
364615Sbill 
36517133Ssam 	/*
36617133Ssam 	 * Pull out search directories.
36717133Ssam 	 */
36817133Ssam 	for (c = 1; c < argc; c++) {
36917133Ssam 		ap = argv[c];
37017133Ssam 		if (ap[0] == '-' && ap[1] == 'L') {
37117133Ssam 			if (ap[2] == 0)
37217133Ssam 				error(1, "-L: pathname missing");
37325533Sbloom 			if (ndir >= NDIRS - NDEFDIRS)
37417133Ssam 				error(1, "-L: too many directories");
37517133Ssam 			dirs[ndir++] = &ap[2];
37617133Ssam 		}
37717133Ssam 	}
37817133Ssam 	/* add default search directories */
37937031Sbostic 	dirs[ndir++] = _PATH_USRLIB;
38037031Sbostic 	dirs[ndir++] = _PATH_LOCALLIB;
38117133Ssam 
38217133Ssam 	p = argv+1;
383650Sbill 	/*
384650Sbill 	 * Scan files once to find where symbols are defined.
385650Sbill 	 */
386615Sbill 	for (c=1; c<argc; c++) {
387615Sbill 		if (trace)
388615Sbill 			printf("%s:\n", *p);
389615Sbill 		filname = 0;
390615Sbill 		ap = *p++;
391615Sbill 		if (*ap != '-') {
392615Sbill 			load1arg(ap);
393615Sbill 			continue;
394615Sbill 		}
395615Sbill 		for (i=1; ap[i]; i++) switch (ap[i]) {
396615Sbill 
397615Sbill 		case 'o':
398615Sbill 			if (++c >= argc)
399615Sbill 				error(1, "-o where?");
40044768Sbostic 			ofilename = *p++;
401615Sbill 			ofilfnd++;
402615Sbill 			continue;
403615Sbill 		case 'u':
404615Sbill 		case 'e':
405615Sbill 			if (++c >= argc)
40633997Sbostic 				error(1, " -u or -e: arg missing");
407615Sbill 			enter(slookup(*p++));
408615Sbill 			if (ap[i]=='e')
409615Sbill 				entrypt = lastsym;
410615Sbill 			continue;
411615Sbill 		case 'H':
412615Sbill 			if (++c >= argc)
413615Sbill 				error(1, "-H: arg missing");
414615Sbill 			if (tsize!=0)
415615Sbill 				error(1, "-H: too late, some text already loaded");
416615Sbill 			hsize = atoi(*p++);
417615Sbill 			continue;
418615Sbill 		case 'A':
419615Sbill 			if (++c >= argc)
420615Sbill 				error(1, "-A: arg missing");
421615Sbill 			if (Aflag)
422615Sbill 				error(1, "-A: only one base file allowed");
423615Sbill 			Aflag = 1;
424615Sbill 			nflag = 0;
425615Sbill 			funding = 1;
426615Sbill 			load1arg(*p++);
427615Sbill 			trsize = drsize = tsize = dsize = bsize = 0;
428615Sbill 			ctrel = cdrel = cbrel = 0;
429615Sbill 			funding = 0;
430615Sbill 			addsym = nextsym;
431615Sbill 			continue;
432615Sbill 		case 'D':
433615Sbill 			if (++c >= argc)
434615Sbill 				error(1, "-D: arg missing");
435615Sbill 			num = htoi(*p++);
436615Sbill 			if (dsize > num)
437615Sbill 				error(1, "-D: too small");
438615Sbill 			dsize = num;
439615Sbill 			continue;
440615Sbill 		case 'T':
441615Sbill 			if (++c >= argc)
442615Sbill 				error(1, "-T: arg missing");
443615Sbill 			if (tsize!=0)
444615Sbill 				error(1, "-T: too late, some text already loaded");
445615Sbill 			textbase = htoi(*p++);
446615Sbill 			continue;
447615Sbill 		case 'l':
448615Sbill 			save = ap[--i];
449615Sbill 			ap[i]='-';
450615Sbill 			load1arg(&ap[i]);
451615Sbill 			ap[i]=save;
452615Sbill 			goto next;
453898Sbill 		case 'M':
454898Sbill 			Mflag++;
455898Sbill 			continue;
456615Sbill 		case 'x':
457615Sbill 			xflag++;
458615Sbill 			continue;
459615Sbill 		case 'X':
460615Sbill 			Xflag++;
461615Sbill 			continue;
462615Sbill 		case 'S':
463615Sbill 			Sflag++;
464615Sbill 			continue;
465615Sbill 		case 'r':
466615Sbill 			rflag++;
467615Sbill 			arflag++;
468615Sbill 			continue;
469615Sbill 		case 's':
470615Sbill 			sflag++;
471615Sbill 			xflag++;
472615Sbill 			continue;
473615Sbill 		case 'n':
474615Sbill 			nflag++;
475650Sbill 			Nflag = zflag = 0;
476615Sbill 			continue;
477615Sbill 		case 'N':
478650Sbill 			Nflag++;
479650Sbill 			nflag = zflag = 0;
480615Sbill 			continue;
481615Sbill 		case 'd':
482615Sbill 			dflag++;
483615Sbill 			continue;
484615Sbill 		case 'i':
485615Sbill 			printf("ld: -i ignored\n");
486615Sbill 			continue;
487615Sbill 		case 't':
488615Sbill 			trace++;
489615Sbill 			continue;
490898Sbill 		case 'y':
491898Sbill 			if (ap[i+1] == 0)
492898Sbill 				error(1, "-y: symbol name missing");
493898Sbill 			if (yflag == 0) {
494898Sbill 				ytab = (char **)calloc(argc, sizeof (char **));
495898Sbill 				if (ytab == 0)
496898Sbill 					error(1, "ran out of memory (-y)");
497898Sbill 			}
498898Sbill 			ytab[yflag++] = &ap[i+1];
499898Sbill 			goto next;
500615Sbill 		case 'z':
501615Sbill 			zflag++;
502650Sbill 			Nflag = nflag = 0;
503615Sbill 			continue;
50417133Ssam 		case 'L':
50517133Ssam 			goto next;
506615Sbill 		default:
507615Sbill 			filname = savestr("-x");	/* kludge */
508615Sbill 			filname[1] = ap[i];		/* kludge */
509615Sbill 			archdr.ar_name[0] = 0;		/* kludge */
510615Sbill 			error(1, "bad flag");
511615Sbill 		}
512615Sbill next:
513615Sbill 		;
514615Sbill 	}
515650Sbill 	if (rflag == 0 && Nflag == 0 && nflag == 0)
516650Sbill 		zflag++;
517615Sbill 	endload(argc, argv);
518615Sbill 	exit(0);
519615Sbill }
520615Sbill 
521615Sbill /*
522615Sbill  * Convert a ascii string which is a hex number.
523615Sbill  * Used by -T and -D options.
524615Sbill  */
htoi(p)525615Sbill htoi(p)
526615Sbill 	register char *p;
527615Sbill {
528615Sbill 	register int c, n;
529615Sbill 
530615Sbill 	n = 0;
531615Sbill 	while (c = *p++) {
532615Sbill 		n <<= 4;
533615Sbill 		if (isdigit(c))
534615Sbill 			n += c - '0';
535615Sbill 		else if (c >= 'a' && c <= 'f')
536615Sbill 			n += 10 + (c - 'a');
537615Sbill 		else if (c >= 'A' && c <= 'F')
538615Sbill 			n += 10 + (c - 'A');
539615Sbill 		else
540615Sbill 			error(1, "badly formed hex number");
541615Sbill 	}
542615Sbill 	return (n);
543615Sbill }
544615Sbill 
54546696Sbostic void
delexit()546615Sbill delexit()
547615Sbill {
5489332Smckusick 	struct stat stbuf;
5499332Smckusick 	long size;
5509332Smckusick 	char c = 0;
551615Sbill 
552615Sbill 	bflush();
55344768Sbostic 	unlink("l.out");
5549332Smckusick 	/*
5559332Smckusick 	 * We have to insure that the last block of the data segment
55616068Sralph 	 * is allocated a full pagesize block. If the underlying
55716068Sralph 	 * file system allocates frags that are smaller than pagesize,
55816068Sralph 	 * a full zero filled pagesize block needs to be allocated so
5599332Smckusick 	 * that when it is demand paged, the paged in block will be
5609332Smckusick 	 * appropriately filled with zeros.
5619332Smckusick 	 */
5629332Smckusick 	fstat(biofd, &stbuf);
56316068Sralph 	size = round(stbuf.st_size, pagesize);
56410640Smckusick 	if (!rflag && size > stbuf.st_size) {
5659332Smckusick 		lseek(biofd, size - 1, 0);
56625419Sbloom 		if (write(biofd, &c, 1) != 1)
56725419Sbloom 			delarg |= 4;
5689332Smckusick 	}
56925419Sbloom 	if (delarg==0 && Aflag==0)
57025419Sbloom 		(void) chmod(ofilename, ofilemode);
571615Sbill 	exit (delarg);
572615Sbill }
573615Sbill 
endload(argc,argv)574615Sbill endload(argc, argv)
575615Sbill 	int argc;
576615Sbill 	char **argv;
577615Sbill {
578615Sbill 	register int c, i;
579615Sbill 	long dnum;
580615Sbill 	register char *ap, **p;
581615Sbill 
582615Sbill 	clibseg = libseg;
583615Sbill 	filname = 0;
584615Sbill 	middle();
585615Sbill 	setupout();
586615Sbill 	p = argv+1;
587615Sbill 	for (c=1; c<argc; c++) {
588615Sbill 		ap = *p++;
589615Sbill 		if (trace)
590615Sbill 			printf("%s:\n", ap);
591615Sbill 		if (*ap != '-') {
592615Sbill 			load2arg(ap);
593615Sbill 			continue;
594615Sbill 		}
595615Sbill 		for (i=1; ap[i]; i++) switch (ap[i]) {
596615Sbill 
597615Sbill 		case 'D':
598615Sbill 			dnum = htoi(*p);
599615Sbill 			if (dorigin < dnum)
600615Sbill 				while (dorigin < dnum)
601615Sbill 					bputc(0, dout), dorigin++;
602615Sbill 			/* fall into ... */
603615Sbill 		case 'T':
604615Sbill 		case 'u':
605615Sbill 		case 'e':
606615Sbill 		case 'o':
607615Sbill 		case 'H':
608615Sbill 			++c;
609615Sbill 			++p;
610615Sbill 			/* fall into ... */
611615Sbill 		default:
612615Sbill 			continue;
613615Sbill 		case 'A':
614615Sbill 			funding = 1;
615615Sbill 			load2arg(*p++);
616615Sbill 			funding = 0;
617615Sbill 			c++;
618615Sbill 			continue;
619898Sbill 		case 'y':
62017133Ssam 		case 'L':
621898Sbill 			goto next;
622615Sbill 		case 'l':
623615Sbill 			ap[--i]='-';
624615Sbill 			load2arg(&ap[i]);
625615Sbill 			goto next;
626615Sbill 		}
627615Sbill next:
628615Sbill 		;
629615Sbill 	}
630615Sbill 	finishout();
631615Sbill }
632615Sbill 
633615Sbill /*
634615Sbill  * Scan file to find defined symbols.
635615Sbill  */
load1arg(cp)636615Sbill load1arg(cp)
637615Sbill 	register char *cp;
638615Sbill {
639615Sbill 	register struct ranlib *tp;
640615Sbill 	off_t nloc;
641898Sbill 	int kind;
642615Sbill 
643898Sbill 	kind = getfile(cp);
644898Sbill 	if (Mflag)
645898Sbill 		printf("%s\n", filname);
646898Sbill 	switch (kind) {
647615Sbill 
648615Sbill 	/*
649615Sbill 	 * Plain file.
650615Sbill 	 */
651615Sbill 	case 0:
652615Sbill 		load1(0, 0L);
653615Sbill 		break;
654615Sbill 
655615Sbill 	/*
656615Sbill 	 * Archive without table of contents.
657615Sbill 	 * (Slowly) process each member.
658615Sbill 	 */
659615Sbill 	case 1:
660898Sbill 		error(-1,
661898Sbill "warning: archive has no table of contents; add one using ranlib(1)");
662615Sbill 		nloc = SARMAG;
663615Sbill 		while (step(nloc))
664615Sbill 			nloc += sizeof(archdr) +
665615Sbill 			    round(atol(archdr.ar_size), sizeof (short));
666615Sbill 		break;
667615Sbill 
668615Sbill 	/*
669615Sbill 	 * Archive with table of contents.
670615Sbill 	 * Read the table of contents and its associated string table.
671615Sbill 	 * Pass through the library resolving symbols until nothing changes
672615Sbill 	 * for an entire pass (i.e. you can get away with backward references
673615Sbill 	 * when there is a table of contents!)
674615Sbill 	 */
675615Sbill 	case 2:
676615Sbill 		nloc = SARMAG + sizeof (archdr);
677615Sbill 		dseek(&text, nloc, sizeof (tnum));
678615Sbill 		mget((char *)&tnum, sizeof (tnum), &text);
679615Sbill 		nloc += sizeof (tnum);
680615Sbill 		tab = (struct ranlib *)malloc(tnum);
681615Sbill 		if (tab == 0)
682615Sbill 			error(1, "ran out of memory (toc)");
683615Sbill 		dseek(&text, nloc, tnum);
684615Sbill 		mget((char *)tab, tnum, &text);
685615Sbill 		nloc += tnum;
686615Sbill 		tnum /= sizeof (struct ranlib);
687615Sbill 		dseek(&text, nloc, sizeof (ssiz));
688615Sbill 		mget((char *)&ssiz, sizeof (ssiz), &text);
689615Sbill 		nloc += sizeof (ssiz);
690615Sbill 		tabstr = (char *)malloc(ssiz);
691615Sbill 		if (tabstr == 0)
692615Sbill 			error(1, "ran out of memory (tocstr)");
693615Sbill 		dseek(&text, nloc, ssiz);
694615Sbill 		mget((char *)tabstr, ssiz, &text);
695615Sbill 		for (tp = &tab[tnum]; --tp >= tab;) {
696615Sbill 			if (tp->ran_un.ran_strx < 0 ||
697615Sbill 			    tp->ran_un.ran_strx >= ssiz)
698615Sbill 				error(1, "mangled archive table of contents");
699615Sbill 			tp->ran_un.ran_name = tabstr + tp->ran_un.ran_strx;
700615Sbill 		}
701615Sbill 		while (ldrand())
702615Sbill 			continue;
70325483Slepreau 		free((char *)tab);
70425483Slepreau 		free(tabstr);
705615Sbill 		nextlibp(-1);
706615Sbill 		break;
707615Sbill 
708615Sbill 	/*
709615Sbill 	 * Table of contents is out of date, so search
710615Sbill 	 * as a normal library (but skip the __.SYMDEF file).
711615Sbill 	 */
712615Sbill 	case 3:
713898Sbill 		error(-1,
714898Sbill "warning: table of contents for archive is out of date; rerun ranlib(1)");
715615Sbill 		nloc = SARMAG;
716615Sbill 		do
717615Sbill 			nloc += sizeof(archdr) +
718615Sbill 			    round(atol(archdr.ar_size), sizeof(short));
719615Sbill 		while (step(nloc));
720615Sbill 		break;
721615Sbill 	}
722615Sbill 	close(infil);
723615Sbill }
724615Sbill 
725615Sbill /*
726615Sbill  * Advance to the next archive member, which
727615Sbill  * is at offset nloc in the archive.  If the member
728615Sbill  * is useful, record its location in the liblist structure
729615Sbill  * for use in pass2.  Mark the end of the archive in libilst with a -1.
730615Sbill  */
step(nloc)731615Sbill step(nloc)
732615Sbill 	off_t nloc;
733615Sbill {
734615Sbill 
735615Sbill 	dseek(&text, nloc, (long) sizeof archdr);
736615Sbill 	if (text.size <= 0) {
737615Sbill 		nextlibp(-1);
738615Sbill 		return (0);
739615Sbill 	}
740615Sbill 	getarhdr();
741615Sbill 	if (load1(1, nloc + (sizeof archdr)))
742615Sbill 		nextlibp(nloc);
743615Sbill 	return (1);
744615Sbill }
745615Sbill 
746615Sbill /*
747615Sbill  * Record the location of a useful archive member.
748615Sbill  * Recording -1 marks the end of files from an archive.
749615Sbill  * The liblist data structure is dynamically extended here.
750615Sbill  */
nextlibp(val)751615Sbill nextlibp(val)
752615Sbill 	off_t val;
753615Sbill {
754615Sbill 
755615Sbill 	if (clibseg->li_used == NROUT) {
756615Sbill 		if (++clibseg == &libseg[NSEG])
757615Sbill 			error(1, "too many files loaded from libraries");
758615Sbill 		clibseg->li_first = (off_t *)malloc(NROUT * sizeof (off_t));
759615Sbill 		if (clibseg->li_first == 0)
760615Sbill 			error(1, "ran out of memory (nextlibp)");
761615Sbill 	}
762615Sbill 	clibseg->li_first[clibseg->li_used++] = val;
763898Sbill 	if (val != -1 && Mflag)
764898Sbill 		printf("\t%s\n", archdr.ar_name);
765615Sbill }
766615Sbill 
767615Sbill /*
768615Sbill  * One pass over an archive with a table of contents.
769615Sbill  * Remember the number of symbols currently defined,
770615Sbill  * then call step on members which look promising (i.e.
771615Sbill  * that define a symbol which is currently externally undefined).
772615Sbill  * Indicate to our caller whether this process netted any more symbols.
773615Sbill  */
ldrand()774615Sbill ldrand()
775615Sbill {
776615Sbill 	register struct nlist *sp, **hp;
777615Sbill 	register struct ranlib *tp, *tplast;
778615Sbill 	off_t loc;
779615Sbill 	int nsymt = symx(nextsym);
780615Sbill 
781615Sbill 	tplast = &tab[tnum-1];
782615Sbill 	for (tp = tab; tp <= tplast; tp++) {
78325483Slepreau 		if ((hp = slookup(tp->ran_un.ran_name)) == 0 || *hp == 0)
784615Sbill 			continue;
785615Sbill 		sp = *hp;
786615Sbill 		if (sp->n_type != N_EXT+N_UNDF)
787615Sbill 			continue;
788615Sbill 		step(tp->ran_off);
789615Sbill 		loc = tp->ran_off;
790615Sbill 		while (tp < tplast && (tp+1)->ran_off == loc)
791615Sbill 			tp++;
792615Sbill 	}
793615Sbill 	return (symx(nextsym) != nsymt);
794615Sbill }
795615Sbill 
796615Sbill /*
797615Sbill  * Examine a single file or archive member on pass 1.
798615Sbill  */
load1(libflg,loc)799615Sbill load1(libflg, loc)
800615Sbill 	off_t loc;
801615Sbill {
802615Sbill 	register struct nlist *sp;
803615Sbill 	struct nlist *savnext;
804615Sbill 	int ndef, nlocal, type, size, nsymt;
805615Sbill 	register int i;
806615Sbill 	off_t maxoff;
807615Sbill 	struct stat stb;
808615Sbill 
809615Sbill 	readhdr(loc);
810615Sbill 	if (filhdr.a_syms == 0) {
81129999Sbostic 		if (filhdr.a_text+filhdr.a_data == 0) {
81229999Sbostic 			/* load2() adds a symbol for the file name */
81329999Sbostic 			if (!libflg)
81429999Sbostic 				ssize += sizeof (cursym);
815615Sbill 			return (0);
81629999Sbostic 		}
817615Sbill 		error(1, "no namelist");
818615Sbill 	}
819615Sbill 	if (libflg)
820615Sbill 		maxoff = atol(archdr.ar_size);
821615Sbill 	else {
822615Sbill 		fstat(infil, &stb);
823615Sbill 		maxoff = stb.st_size;
824615Sbill 	}
825615Sbill 	if (N_STROFF(filhdr) + sizeof (off_t) >= maxoff)
826615Sbill 		error(1, "too small (old format .o?)");
827615Sbill 	ctrel = tsize; cdrel += dsize; cbrel += bsize;
828615Sbill 	ndef = 0;
829615Sbill 	nlocal = sizeof(cursym);
830615Sbill 	savnext = nextsym;
831615Sbill 	loc += N_SYMOFF(filhdr);
832615Sbill 	dseek(&text, loc, filhdr.a_syms);
833615Sbill 	dseek(&reloc, loc + filhdr.a_syms, sizeof(off_t));
834615Sbill 	mget(&size, sizeof (size), &reloc);
835615Sbill 	dseek(&reloc, loc + filhdr.a_syms+sizeof (off_t), size-sizeof (off_t));
836615Sbill 	curstr = (char *)malloc(size);
837615Sbill 	if (curstr == NULL)
838615Sbill 		error(1, "no space for string table");
839615Sbill 	mget(curstr+sizeof(off_t), size-sizeof(off_t), &reloc);
840615Sbill 	while (text.size > 0) {
841615Sbill 		mget((char *)&cursym, sizeof(struct nlist), &text);
842615Sbill 		if (cursym.n_un.n_strx) {
843615Sbill 			if (cursym.n_un.n_strx<sizeof(size) ||
844615Sbill 			    cursym.n_un.n_strx>=size)
845615Sbill 				error(1, "bad string table index (pass 1)");
846615Sbill 			cursym.n_un.n_name = curstr + cursym.n_un.n_strx;
847615Sbill 		}
848615Sbill 		type = cursym.n_type;
849615Sbill 		if ((type&N_EXT)==0) {
850615Sbill 			if (Xflag==0 || cursym.n_un.n_name[0]!='L' ||
851615Sbill 			    type & N_STAB)
852615Sbill 				nlocal += sizeof cursym;
853615Sbill 			continue;
854615Sbill 		}
855615Sbill 		symreloc();
856615Sbill 		if (enter(lookup()))
857615Sbill 			continue;
858615Sbill 		if ((sp = lastsym)->n_type != N_EXT+N_UNDF)
859615Sbill 			continue;
860615Sbill 		if (cursym.n_type == N_EXT+N_UNDF) {
861615Sbill 			if (cursym.n_value > sp->n_value)
862615Sbill 				sp->n_value = cursym.n_value;
863615Sbill 			continue;
864615Sbill 		}
865615Sbill 		if (sp->n_value != 0 && cursym.n_type == N_EXT+N_TEXT)
866615Sbill 			continue;
867615Sbill 		ndef++;
868615Sbill 		sp->n_type = cursym.n_type;
869615Sbill 		sp->n_value = cursym.n_value;
870615Sbill 	}
871615Sbill 	if (libflg==0 || ndef) {
872615Sbill 		tsize += filhdr.a_text;
873615Sbill 		dsize += round(filhdr.a_data, sizeof (long));
874615Sbill 		bsize += round(filhdr.a_bss, sizeof (long));
875615Sbill 		ssize += nlocal;
876615Sbill 		trsize += filhdr.a_trsize;
877615Sbill 		drsize += filhdr.a_drsize;
878615Sbill 		if (funding)
879615Sbill 			textbase = (*slookup("_end"))->n_value;
880615Sbill 		nsymt = symx(nextsym);
881615Sbill 		for (i = symx(savnext); i < nsymt; i++) {
882615Sbill 			sp = xsym(i);
883615Sbill 			sp->n_un.n_name = savestr(sp->n_un.n_name);
884615Sbill 		}
885615Sbill 		free(curstr);
886615Sbill 		return (1);
887615Sbill 	}
888615Sbill 	/*
889615Sbill 	 * No symbols defined by this library member.
890615Sbill 	 * Rip out the hash table entries and reset the symbol table.
891615Sbill 	 */
892615Sbill 	symfree(savnext);
893615Sbill 	free(curstr);
894615Sbill 	return(0);
895615Sbill }
896615Sbill 
middle()897615Sbill middle()
898615Sbill {
899615Sbill 	register struct nlist *sp;
900615Sbill 	long csize, t, corigin, ocsize;
901615Sbill 	int nund, rnd;
902615Sbill 	char s;
903615Sbill 	register int i;
904615Sbill 	int nsymt;
905615Sbill 
906615Sbill 	torigin = 0;
907615Sbill 	dorigin = 0;
908615Sbill 	borigin = 0;
909615Sbill 
910615Sbill 	p_etext = *slookup("_etext");
911615Sbill 	p_edata = *slookup("_edata");
912615Sbill 	p_end = *slookup("_end");
913615Sbill 	/*
914615Sbill 	 * If there are any undefined symbols, save the relocation bits.
915615Sbill 	 */
916615Sbill 	nsymt = symx(nextsym);
917615Sbill 	if (rflag==0) {
918615Sbill 		for (i = 0; i < nsymt; i++) {
919615Sbill 			sp = xsym(i);
920615Sbill 			if (sp->n_type==N_EXT+N_UNDF && sp->n_value==0 &&
921650Sbill 			    sp!=p_end && sp!=p_edata && sp!=p_etext) {
922615Sbill 				rflag++;
923615Sbill 				dflag = 0;
924615Sbill 				break;
925615Sbill 			}
926615Sbill 		}
927615Sbill 	}
928615Sbill 	if (rflag)
929615Sbill 		sflag = zflag = 0;
930615Sbill 	/*
931615Sbill 	 * Assign common locations.
932615Sbill 	 */
933615Sbill 	csize = 0;
934615Sbill 	if (!Aflag)
935615Sbill 		addsym = symseg[0].sy_first;
936615Sbill 	database = round(tsize+textbase,
93712671Ssam 	    (nflag||zflag? pagesize : sizeof (long)));
938615Sbill 	database += hsize;
939615Sbill 	if (dflag || rflag==0) {
940615Sbill 		ldrsym(p_etext, tsize, N_EXT+N_TEXT);
941615Sbill 		ldrsym(p_edata, dsize, N_EXT+N_DATA);
942615Sbill 		ldrsym(p_end, bsize, N_EXT+N_BSS);
943615Sbill 		for (i = symx(addsym); i < nsymt; i++) {
944615Sbill 			sp = xsym(i);
945615Sbill 			if ((s=sp->n_type)==N_EXT+N_UNDF &&
946615Sbill 			    (t = sp->n_value)!=0) {
947615Sbill 				if (t >= sizeof (double))
948615Sbill 					rnd = sizeof (double);
949615Sbill 				else if (t >= sizeof (long))
950615Sbill 					rnd = sizeof (long);
951615Sbill 				else
952615Sbill 					rnd = sizeof (short);
953615Sbill 				csize = round(csize, rnd);
954615Sbill 				sp->n_value = csize;
955615Sbill 				sp->n_type = N_EXT+N_COMM;
956615Sbill 				ocsize = csize;
957615Sbill 				csize += t;
958615Sbill 			}
959615Sbill 			if (s&N_EXT && (s&N_TYPE)==N_UNDF && s&N_STAB) {
960615Sbill 				sp->n_value = ocsize;
961615Sbill 				sp->n_type = (s&N_STAB) | (N_EXT+N_COMM);
962615Sbill 			}
963615Sbill 		}
964615Sbill 	}
965615Sbill 	/*
966615Sbill 	 * Now set symbols to their final value
967615Sbill 	 */
968615Sbill 	csize = round(csize, sizeof (long));
969615Sbill 	torigin = textbase;
970615Sbill 	dorigin = database;
971615Sbill 	corigin = dorigin + dsize;
972615Sbill 	borigin = corigin + csize;
973615Sbill 	nund = 0;
974615Sbill 	nsymt = symx(nextsym);
975615Sbill 	for (i = symx(addsym); i<nsymt; i++) {
976615Sbill 		sp = xsym(i);
977615Sbill 		switch (sp->n_type & (N_TYPE+N_EXT)) {
978615Sbill 
979615Sbill 		case N_EXT+N_UNDF:
9802369Skre 			if (arflag == 0)
9812369Skre 				errlev |= 01;
982615Sbill 			if ((arflag==0 || dflag) && sp->n_value==0) {
983650Sbill 				if (sp==p_end || sp==p_etext || sp==p_edata)
984650Sbill 					continue;
985615Sbill 				if (nund==0)
986615Sbill 					printf("Undefined:\n");
987615Sbill 				nund++;
988615Sbill 				printf("%s\n", sp->n_un.n_name);
989615Sbill 			}
990615Sbill 			continue;
991615Sbill 		case N_EXT+N_ABS:
992615Sbill 		default:
993615Sbill 			continue;
994615Sbill 		case N_EXT+N_TEXT:
995615Sbill 			sp->n_value += torigin;
996615Sbill 			continue;
997615Sbill 		case N_EXT+N_DATA:
998615Sbill 			sp->n_value += dorigin;
999615Sbill 			continue;
1000615Sbill 		case N_EXT+N_BSS:
1001615Sbill 			sp->n_value += borigin;
1002615Sbill 			continue;
1003615Sbill 		case N_EXT+N_COMM:
1004615Sbill 			sp->n_type = (sp->n_type & N_STAB) | (N_EXT+N_BSS);
1005615Sbill 			sp->n_value += corigin;
1006615Sbill 			continue;
1007615Sbill 		}
1008615Sbill 	}
1009615Sbill 	if (sflag || xflag)
1010615Sbill 		ssize = 0;
1011615Sbill 	bsize += csize;
1012615Sbill 	nsym = ssize / (sizeof cursym);
1013615Sbill 	if (Aflag) {
1014615Sbill 		fixspec(p_etext,torigin);
1015615Sbill 		fixspec(p_edata,dorigin);
1016615Sbill 		fixspec(p_end,borigin);
1017615Sbill 	}
1018615Sbill }
1019615Sbill 
1020615Sbill fixspec(sym,offset)
1021615Sbill 	struct nlist *sym;
1022615Sbill 	long offset;
1023615Sbill {
1024615Sbill 
1025615Sbill 	if(symx(sym) < symx(addsym) && sym!=0)
1026615Sbill 		sym->n_value += offset;
1027615Sbill }
1028615Sbill 
ldrsym(sp,val,type)1029615Sbill ldrsym(sp, val, type)
1030615Sbill 	register struct nlist *sp;
1031615Sbill 	long val;
1032615Sbill {
1033615Sbill 
1034615Sbill 	if (sp == 0)
1035615Sbill 		return;
1036615Sbill 	if ((sp->n_type != N_EXT+N_UNDF || sp->n_value) && !Aflag) {
1037615Sbill 		printf("%s: ", sp->n_un.n_name);
1038615Sbill 		error(0, "user attempt to redfine loader-defined symbol");
1039615Sbill 		return;
1040615Sbill 	}
1041615Sbill 	sp->n_type = type;
1042615Sbill 	sp->n_value = val;
1043615Sbill }
1044615Sbill 
1045615Sbill off_t	wroff;
1046615Sbill struct	biobuf toutb;
1047615Sbill 
setupout()1048615Sbill setupout()
1049615Sbill {
105042415Sbostic 	extern int errno;
1051615Sbill 	int bss;
105216068Sralph 	struct stat stbuf;
1053615Sbill 
10543606Ssklower 	ofilemode = 0777 & ~umask(0);
10553606Ssklower 	biofd = creat(ofilename, 0666 & ofilemode);
1056898Sbill 	if (biofd < 0) {
1057898Sbill 		filname = ofilename;		/* kludge */
1058898Sbill 		archdr.ar_name[0] = 0;		/* kludge */
105942415Sbostic 		error(1, strerror(errno));	/* kludge */
1060898Sbill 	}
106116068Sralph 	fstat(biofd, &stbuf);		/* suppose file exists, wrong*/
106216068Sralph 	if (stbuf.st_mode & 0111) {	/* mode, ld fails? */
106316068Sralph 		chmod(ofilename, stbuf.st_mode & 0666);
106416068Sralph 		ofilemode = stbuf.st_mode;
106516068Sralph 	}
106644293Sbostic #ifdef hp300
106744293Sbostic 	filhdr.a_mid = (rflag ? MID_ZERO : MID_HP300);
106844293Sbostic #endif
1069615Sbill 	filhdr.a_magic = nflag ? NMAGIC : (zflag ? ZMAGIC : OMAGIC);
1070615Sbill 	filhdr.a_text = nflag ? tsize :
107112671Ssam 	    round(tsize, zflag ? pagesize : sizeof (long));
107212671Ssam 	filhdr.a_data = zflag ? round(dsize, pagesize) : dsize;
1073615Sbill 	bss = bsize - (filhdr.a_data - dsize);
1074615Sbill 	if (bss < 0)
1075615Sbill 		bss = 0;
1076615Sbill 	filhdr.a_bss = bss;
1077615Sbill 	filhdr.a_trsize = trsize;
1078615Sbill 	filhdr.a_drsize = drsize;
1079615Sbill 	filhdr.a_syms = sflag? 0: (ssize + (sizeof cursym)*symx(nextsym));
1080615Sbill 	if (entrypt) {
1081615Sbill 		if (entrypt->n_type!=N_EXT+N_TEXT)
1082615Sbill 			error(0, "entry point not in text");
1083615Sbill 		else
1084615Sbill 			filhdr.a_entry = entrypt->n_value;
1085615Sbill 	} else
1086615Sbill 		filhdr.a_entry = 0;
1087615Sbill 	filhdr.a_trsize = (rflag ? trsize:0);
1088615Sbill 	filhdr.a_drsize = (rflag ? drsize:0);
108916068Sralph 	tout = &toutb;
109016068Sralph 	bopen(tout, 0, stbuf.st_blksize);
1091615Sbill 	bwrite((char *)&filhdr, sizeof (filhdr), tout);
109216068Sralph 	if (zflag)
109316068Sralph 		bseek(tout, pagesize);
1094615Sbill 	wroff = N_TXTOFF(filhdr) + filhdr.a_text;
109516068Sralph 	outb(&dout, filhdr.a_data, stbuf.st_blksize);
1096615Sbill 	if (rflag) {
109716068Sralph 		outb(&trout, filhdr.a_trsize, stbuf.st_blksize);
109816068Sralph 		outb(&drout, filhdr.a_drsize, stbuf.st_blksize);
1099615Sbill 	}
1100615Sbill 	if (sflag==0 || xflag==0) {
110116068Sralph 		outb(&sout, filhdr.a_syms, stbuf.st_blksize);
1102615Sbill 		wroff += sizeof (offset);
110316068Sralph 		outb(&strout, 0, stbuf.st_blksize);
1104615Sbill 	}
1105615Sbill }
1106615Sbill 
outb(bp,inc,bufsize)110716068Sralph outb(bp, inc, bufsize)
1108615Sbill 	register struct biobuf **bp;
1109615Sbill {
1110615Sbill 
1111615Sbill 	*bp = (struct biobuf *)malloc(sizeof (struct biobuf));
1112615Sbill 	if (*bp == 0)
1113615Sbill 		error(1, "ran out of memory (outb)");
111416068Sralph 	bopen(*bp, wroff, bufsize);
1115615Sbill 	wroff += inc;
1116615Sbill }
1117615Sbill 
load2arg(acp)1118615Sbill load2arg(acp)
1119615Sbill char *acp;
1120615Sbill {
1121615Sbill 	register char *cp;
1122615Sbill 	off_t loc;
1123615Sbill 
1124615Sbill 	cp = acp;
1125615Sbill 	if (getfile(cp) == 0) {
1126615Sbill 		while (*cp)
1127615Sbill 			cp++;
1128615Sbill 		while (cp >= acp && *--cp != '/');
1129615Sbill 		mkfsym(++cp);
1130615Sbill 		load2(0L);
1131615Sbill 	} else {	/* scan archive members referenced */
1132615Sbill 		for (;;) {
1133615Sbill 			if (clibseg->li_used2 == clibseg->li_used) {
1134615Sbill 				if (clibseg->li_used < NROUT)
1135615Sbill 					error(1, "libseg botch");
1136615Sbill 				clibseg++;
1137615Sbill 			}
1138615Sbill 			loc = clibseg->li_first[clibseg->li_used2++];
1139615Sbill 			if (loc == -1)
1140615Sbill 				break;
1141615Sbill 			dseek(&text, loc, (long)sizeof(archdr));
1142615Sbill 			getarhdr();
1143615Sbill 			mkfsym(archdr.ar_name);
1144615Sbill 			load2(loc + (long)sizeof(archdr));
1145615Sbill 		}
1146615Sbill 	}
1147615Sbill 	close(infil);
1148615Sbill }
1149615Sbill 
load2(loc)1150615Sbill load2(loc)
1151615Sbill long loc;
1152615Sbill {
1153615Sbill 	int size;
1154615Sbill 	register struct nlist *sp;
1155615Sbill 	register struct local *lp;
1156615Sbill 	register int symno, i;
1157615Sbill 	int type;
1158615Sbill 
1159615Sbill 	readhdr(loc);
1160650Sbill 	if (!funding) {
1161615Sbill 		ctrel = torigin;
1162615Sbill 		cdrel += dorigin;
1163615Sbill 		cbrel += borigin;
1164615Sbill 	}
1165615Sbill 	/*
1166615Sbill 	 * Reread the symbol table, recording the numbering
1167615Sbill 	 * of symbols for fixing external references.
1168615Sbill 	 */
1169615Sbill 	for (i = 0; i < LHSIZ; i++)
1170615Sbill 		lochash[i] = 0;
1171615Sbill 	clocseg = locseg;
1172615Sbill 	clocseg->lo_used = 0;
1173615Sbill 	symno = -1;
1174615Sbill 	loc += N_TXTOFF(filhdr);
1175615Sbill 	dseek(&text, loc+filhdr.a_text+filhdr.a_data+
1176615Sbill 		filhdr.a_trsize+filhdr.a_drsize+filhdr.a_syms, sizeof(off_t));
1177615Sbill 	mget(&size, sizeof(size), &text);
1178615Sbill 	dseek(&text, loc+filhdr.a_text+filhdr.a_data+
1179615Sbill 		filhdr.a_trsize+filhdr.a_drsize+filhdr.a_syms+sizeof(off_t),
1180615Sbill 		size - sizeof(off_t));
1181615Sbill 	curstr = (char *)malloc(size);
1182615Sbill 	if (curstr == NULL)
1183615Sbill 		error(1, "out of space reading string table (pass 2)");
1184615Sbill 	mget(curstr+sizeof(off_t), size-sizeof(off_t), &text);
1185615Sbill 	dseek(&text, loc+filhdr.a_text+filhdr.a_data+
1186615Sbill 		filhdr.a_trsize+filhdr.a_drsize, filhdr.a_syms);
1187615Sbill 	while (text.size > 0) {
1188615Sbill 		symno++;
1189615Sbill 		mget((char *)&cursym, sizeof(struct nlist), &text);
1190615Sbill 		if (cursym.n_un.n_strx) {
1191615Sbill 			if (cursym.n_un.n_strx<sizeof(size) ||
1192615Sbill 			    cursym.n_un.n_strx>=size)
1193615Sbill 				error(1, "bad string table index (pass 2)");
1194615Sbill 			cursym.n_un.n_name = curstr + cursym.n_un.n_strx;
1195615Sbill 		}
1196615Sbill /* inline expansion of symreloc() */
1197615Sbill 		switch (cursym.n_type & 017) {
1198615Sbill 
1199615Sbill 		case N_TEXT:
1200615Sbill 		case N_EXT+N_TEXT:
1201615Sbill 			cursym.n_value += ctrel;
1202615Sbill 			break;
1203615Sbill 		case N_DATA:
1204615Sbill 		case N_EXT+N_DATA:
1205615Sbill 			cursym.n_value += cdrel;
1206615Sbill 			break;
1207615Sbill 		case N_BSS:
1208615Sbill 		case N_EXT+N_BSS:
1209615Sbill 			cursym.n_value += cbrel;
1210615Sbill 			break;
1211615Sbill 		case N_EXT+N_UNDF:
1212615Sbill 			break;
1213615Sbill 		default:
1214615Sbill 			if (cursym.n_type&N_EXT)
1215615Sbill 				cursym.n_type = N_EXT+N_ABS;
1216615Sbill 		}
1217615Sbill /* end inline expansion of symreloc() */
1218615Sbill 		type = cursym.n_type;
1219898Sbill 		if (yflag && cursym.n_un.n_name)
1220898Sbill 			for (i = 0; i < yflag; i++)
1221898Sbill 				/* fast check for 2d character! */
1222898Sbill 				if (ytab[i][1] == cursym.n_un.n_name[1] &&
1223898Sbill 				    !strcmp(ytab[i], cursym.n_un.n_name)) {
1224898Sbill 					tracesym();
1225898Sbill 					break;
1226898Sbill 				}
1227615Sbill 		if ((type&N_EXT) == 0) {
1228615Sbill 			if (!sflag&&!xflag&&
1229615Sbill 			    (!Xflag||cursym.n_un.n_name[0]!='L'||type&N_STAB))
1230615Sbill 				symwrite(&cursym, sout);
1231615Sbill 			continue;
1232615Sbill 		}
1233615Sbill 		if (funding)
1234615Sbill 			continue;
1235615Sbill 		if ((sp = *lookup()) == 0)
1236615Sbill 			error(1, "internal error: symbol not found");
1237615Sbill 		if (cursym.n_type == N_EXT+N_UNDF) {
1238615Sbill 			if (clocseg->lo_used == NSYMPR) {
1239615Sbill 				if (++clocseg == &locseg[NSEG])
1240615Sbill 					error(1, "local symbol overflow");
1241615Sbill 				clocseg->lo_used = 0;
1242615Sbill 			}
1243615Sbill 			if (clocseg->lo_first == 0) {
1244615Sbill 				clocseg->lo_first = (struct local *)
1245615Sbill 				    malloc(NSYMPR * sizeof (struct local));
1246615Sbill 				if (clocseg->lo_first == 0)
1247615Sbill 					error(1, "out of memory (clocseg)");
1248615Sbill 			}
1249615Sbill 			lp = &clocseg->lo_first[clocseg->lo_used++];
1250615Sbill 			lp->l_index = symno;
1251615Sbill 			lp->l_symbol = sp;
1252615Sbill 			lp->l_link = lochash[symno % LHSIZ];
1253615Sbill 			lochash[symno % LHSIZ] = lp;
1254615Sbill 			continue;
1255615Sbill 		}
1256615Sbill 		if (cursym.n_type & N_STAB)
1257615Sbill 			continue;
1258615Sbill 		if (cursym.n_type!=sp->n_type || cursym.n_value!=sp->n_value) {
1259615Sbill 			printf("%s: ", cursym.n_un.n_name);
1260615Sbill 			error(0, "multiply defined");
1261615Sbill 		}
1262615Sbill 	}
1263615Sbill 	if (funding)
1264615Sbill 		return;
1265615Sbill 	dseek(&text, loc, filhdr.a_text);
1266615Sbill 	dseek(&reloc, loc+filhdr.a_text+filhdr.a_data, filhdr.a_trsize);
1267650Sbill 	load2td(ctrel, torigin - textbase, tout, trout);
1268615Sbill 	dseek(&text, loc+filhdr.a_text, filhdr.a_data);
1269615Sbill 	dseek(&reloc, loc+filhdr.a_text+filhdr.a_data+filhdr.a_trsize,
1270615Sbill 	    filhdr.a_drsize);
1271650Sbill 	load2td(cdrel, dorigin - database, dout, drout);
1272615Sbill 	while (filhdr.a_data & (sizeof(long)-1)) {
1273615Sbill 		bputc(0, dout);
1274615Sbill 		filhdr.a_data++;
1275615Sbill 	}
1276615Sbill 	torigin += filhdr.a_text;
12771752Sbill 	dorigin += round(filhdr.a_data, sizeof (long));
12781752Sbill 	borigin += round(filhdr.a_bss, sizeof (long));
1279615Sbill 	free(curstr);
1280615Sbill }
1281615Sbill 
1282898Sbill struct tynames {
1283898Sbill 	int	ty_value;
1284898Sbill 	char	*ty_name;
1285898Sbill } tynames[] = {
1286898Sbill 	N_UNDF,	"undefined",
1287898Sbill 	N_ABS,	"absolute",
1288898Sbill 	N_TEXT,	"text",
1289898Sbill 	N_DATA,	"data",
1290898Sbill 	N_BSS,	"bss",
1291898Sbill 	N_COMM,	"common",
1292898Sbill 	0,	0,
1293898Sbill };
1294898Sbill 
tracesym()1295898Sbill tracesym()
1296898Sbill {
1297898Sbill 	register struct tynames *tp;
1298898Sbill 
1299898Sbill 	if (cursym.n_type & N_STAB)
1300898Sbill 		return;
1301898Sbill 	printf("%s", filname);
1302898Sbill 	if (archdr.ar_name[0])
1303898Sbill 		printf("(%s)", archdr.ar_name);
1304898Sbill 	printf(": ");
1305898Sbill 	if ((cursym.n_type&N_TYPE) == N_UNDF && cursym.n_value) {
1306898Sbill 		printf("definition of common %s size %d\n",
1307898Sbill 		    cursym.n_un.n_name, cursym.n_value);
1308898Sbill 		return;
1309898Sbill 	}
1310898Sbill 	for (tp = tynames; tp->ty_name; tp++)
1311898Sbill 		if (tp->ty_value == (cursym.n_type&N_TYPE))
1312898Sbill 			break;
1313898Sbill 	printf((cursym.n_type&N_TYPE) ? "definition of" : "reference to");
1314898Sbill 	if (cursym.n_type&N_EXT)
1315898Sbill 		printf(" external");
1316898Sbill 	if (tp->ty_name)
1317898Sbill 		printf(" %s", tp->ty_name);
1318898Sbill 	printf(" %s\n", cursym.n_un.n_name);
1319898Sbill }
1320898Sbill 
132129845Ssam #if !defined(tahoe)
132229845Ssam /* for machines which allow arbitrarily aligned word and longword accesses */
132346419Sbostic #define	getword(cp)	(*(short *)(cp))
132429845Ssam #define	getl(cp)	(*(long *)(cp))
132529845Ssam #define	putw(cp, w)	(*(short *)(cp) = (w))
132629845Ssam #define	putl(cp, l)	(*(long *)(cp) = (l))
132729845Ssam #else
132829845Ssam short
getword(cp)132946419Sbostic getword(cp)
133029845Ssam 	char *cp;
133129845Ssam {
133229845Ssam 	union {
133329845Ssam 		short	w;
133429845Ssam 		char	c[2];
133529845Ssam 	} w;
133629845Ssam 
133729845Ssam 	w.c[0] = *cp++;
133829845Ssam 	w.c[1] = *cp++;
133929845Ssam 	return (w.w);
134029845Ssam }
134129845Ssam 
getl(cp)134229845Ssam getl(cp)
134329845Ssam 	char *cp;
134429845Ssam {
134529845Ssam 	union {
134629845Ssam 		long	l;
134729845Ssam 		char	c[4];
134829845Ssam 	} l;
134929845Ssam 
135029845Ssam 	l.c[0] = *cp++;
135129845Ssam 	l.c[1] = *cp++;
135229845Ssam 	l.c[2] = *cp++;
135329845Ssam 	l.c[3] = *cp++;
135429845Ssam 	return (l.l);
135529845Ssam }
135629845Ssam 
putw(cp,v)135729845Ssam putw(cp, v)
135829845Ssam 	char *cp;
135929845Ssam 	short v;
136029845Ssam {
136129845Ssam 	union {
136229845Ssam 		short	w;
136329845Ssam 		char	c[2];
136429845Ssam 	} w;
136529845Ssam 
136629845Ssam 	w.w = v;
136729845Ssam 	*cp++ = w.c[0];
136829845Ssam 	*cp++ = w.c[1];
136929845Ssam }
137029845Ssam 
putl(cp,v)137129845Ssam putl(cp, v)
137229845Ssam 	char *cp;
137329845Ssam 	long v;
137429845Ssam {
137529845Ssam 	union {
137629845Ssam 		long	l;
137729845Ssam 		char	c[4];
137829845Ssam 	} l;
137929845Ssam 
138029845Ssam 	l.l = v;
138129845Ssam 	*cp++ = l.c[0];
138229845Ssam 	*cp++ = l.c[1];
138329845Ssam 	*cp++ = l.c[2];
138429845Ssam 	*cp++ = l.c[3];
138529845Ssam }
138629845Ssam #endif
138729845Ssam 
1388650Sbill /*
1389650Sbill  * This routine relocates the single text or data segment argument.
1390650Sbill  * Offsets from external symbols are resolved by adding the value
1391650Sbill  * of the external symbols.  Non-external reference are updated to account
1392650Sbill  * for the relative motion of the segments (ctrel, cdrel, ...).  If
1393650Sbill  * a relocation was pc-relative, then we update it to reflect the
1394650Sbill  * change in the positioning of the segments by adding the displacement
1395650Sbill  * of the referenced segment and subtracting the displacement of the
1396650Sbill  * current segment (creloc).
1397650Sbill  *
1398650Sbill  * If we are saving the relocation information, then we increase
1399650Sbill  * each relocation datum address by our base position in the new segment.
1400650Sbill  */
load2td(creloc,position,b1,b2)1401650Sbill load2td(creloc, position, b1, b2)
140230647Slepreau 	long creloc, position;
1403615Sbill 	struct biobuf *b1, *b2;
1404615Sbill {
1405615Sbill 	register struct nlist *sp;
1406615Sbill 	register struct local *lp;
1407615Sbill 	long tw;
1408615Sbill 	register struct relocation_info *rp, *rpend;
1409615Sbill 	struct relocation_info *relp;
1410615Sbill 	char *codep;
1411615Sbill 	register char *cp;
1412615Sbill 	int relsz, codesz;
1413615Sbill 
1414615Sbill 	relsz = reloc.size;
1415615Sbill 	relp = (struct relocation_info *)malloc(relsz);
1416615Sbill 	codesz = text.size;
1417615Sbill 	codep = (char *)malloc(codesz);
1418615Sbill 	if (relp == 0 || codep == 0)
1419615Sbill 		error(1, "out of memory (load2td)");
1420615Sbill 	mget((char *)relp, relsz, &reloc);
1421615Sbill 	rpend = &relp[relsz / sizeof (struct relocation_info)];
1422615Sbill 	mget(codep, codesz, &text);
1423615Sbill 	for (rp = relp; rp < rpend; rp++) {
1424615Sbill 		cp = codep + rp->r_address;
1425650Sbill 		/*
1426650Sbill 		 * Pick up previous value at location to be relocated.
1427650Sbill 		 */
1428615Sbill 		switch (rp->r_length) {
1429615Sbill 
1430615Sbill 		case 0:		/* byte */
1431615Sbill 			tw = *cp;
1432615Sbill 			break;
1433615Sbill 
1434615Sbill 		case 1:		/* word */
143546419Sbostic 			tw = getword(cp);
1436615Sbill 			break;
1437615Sbill 
1438615Sbill 		case 2:		/* long */
143929845Ssam 			tw = getl(cp);
1440615Sbill 			break;
1441615Sbill 
1442615Sbill 		default:
1443615Sbill 			error(1, "load2td botch: bad length");
1444615Sbill 		}
1445650Sbill 		/*
1446650Sbill 		 * If relative to an external which is defined,
1447650Sbill 		 * resolve to a simpler kind of reference in the
1448650Sbill 		 * result file.  If the external is undefined, just
1449650Sbill 		 * convert the symbol number to the number of the
1450650Sbill 		 * symbol in the result file and leave it undefined.
1451650Sbill 		 */
1452615Sbill 		if (rp->r_extern) {
1453650Sbill 			/*
1454650Sbill 			 * Search the hash table which maps local
1455650Sbill 			 * symbol numbers to symbol tables entries
1456650Sbill 			 * in the new a.out file.
1457650Sbill 			 */
1458615Sbill 			lp = lochash[rp->r_symbolnum % LHSIZ];
1459615Sbill 			while (lp->l_index != rp->r_symbolnum) {
1460615Sbill 				lp = lp->l_link;
1461615Sbill 				if (lp == 0)
1462615Sbill 					error(1, "local symbol botch");
1463615Sbill 			}
1464615Sbill 			sp = lp->l_symbol;
1465615Sbill 			if (sp->n_type == N_EXT+N_UNDF)
1466615Sbill 				rp->r_symbolnum = nsym+symx(sp);
1467615Sbill 			else {
1468615Sbill 				rp->r_symbolnum = sp->n_type & N_TYPE;
1469615Sbill 				tw += sp->n_value;
1470615Sbill 				rp->r_extern = 0;
1471615Sbill 			}
1472615Sbill 		} else switch (rp->r_symbolnum & N_TYPE) {
1473650Sbill 		/*
1474650Sbill 		 * Relocation is relative to the loaded position
1475650Sbill 		 * of another segment.  Update by the change in position
1476650Sbill 		 * of that segment.
1477650Sbill 		 */
1478615Sbill 		case N_TEXT:
1479615Sbill 			tw += ctrel;
1480615Sbill 			break;
1481615Sbill 		case N_DATA:
1482615Sbill 			tw += cdrel;
1483615Sbill 			break;
1484615Sbill 		case N_BSS:
1485615Sbill 			tw += cbrel;
1486615Sbill 			break;
1487615Sbill 		case N_ABS:
1488615Sbill 			break;
1489615Sbill 		default:
1490615Sbill 			error(1, "relocation format botch (symbol type))");
1491615Sbill 		}
1492650Sbill 		/*
1493650Sbill 		 * Relocation is pc relative, so decrease the relocation
1494650Sbill 		 * by the amount the current segment is displaced.
1495650Sbill 		 * (E.g if we are a relative reference to a text location
1496650Sbill 		 * from data space, we added the increase in the text address
1497650Sbill 		 * above, and subtract the increase in our (data) address
1498650Sbill 		 * here, leaving the net change the relative change in the
1499650Sbill 		 * positioning of our text and data segments.)
1500650Sbill 		 */
1501615Sbill 		if (rp->r_pcrel)
1502615Sbill 			tw -= creloc;
1503650Sbill 		/*
1504650Sbill 		 * Put the value back in the segment,
1505650Sbill 		 * while checking for overflow.
1506650Sbill 		 */
1507615Sbill 		switch (rp->r_length) {
1508615Sbill 
1509615Sbill 		case 0:		/* byte */
1510615Sbill 			if (tw < -128 || tw > 127)
1511615Sbill 				error(0, "byte displacement overflow");
1512615Sbill 			*cp = tw;
1513615Sbill 			break;
1514615Sbill 		case 1:		/* word */
1515615Sbill 			if (tw < -32768 || tw > 32767)
1516615Sbill 				error(0, "word displacement overflow");
151729845Ssam 			putw(cp, tw);
1518615Sbill 			break;
1519615Sbill 		case 2:		/* long */
152029845Ssam 			putl(cp, tw);
1521615Sbill 			break;
1522615Sbill 		}
1523650Sbill 		/*
1524650Sbill 		 * If we are saving relocation information,
1525650Sbill 		 * we must convert the address in the segment from
1526650Sbill 		 * the old .o file into an address in the segment in
1527650Sbill 		 * the new a.out, by adding the position of our
1528650Sbill 		 * segment in the new larger segment.
1529650Sbill 		 */
1530615Sbill 		if (rflag)
1531650Sbill 			rp->r_address += position;
1532615Sbill 	}
1533615Sbill 	bwrite(codep, codesz, b1);
1534615Sbill 	if (rflag)
1535615Sbill 		bwrite(relp, relsz, b2);
153625483Slepreau 	free((char *)relp);
153725483Slepreau 	free(codep);
1538615Sbill }
1539615Sbill 
finishout()1540615Sbill finishout()
1541615Sbill {
1542615Sbill 	register int i;
1543615Sbill 	int nsymt;
1544615Sbill 
1545615Sbill 	if (sflag==0) {
1546615Sbill 		nsymt = symx(nextsym);
1547615Sbill 		for (i = 0; i < nsymt; i++)
1548615Sbill 			symwrite(xsym(i), sout);
1549615Sbill 		bwrite(&offset, sizeof offset, sout);
1550615Sbill 	}
1551615Sbill 	if (!ofilfnd) {
155244768Sbostic 		unlink("a.out");
155344768Sbostic 		if (link("l.out", "a.out") < 0)
1554898Sbill 			error(1, "cannot move l.out to a.out");
155544768Sbostic 		ofilename = "a.out";
1556615Sbill 	}
1557615Sbill 	delarg = errlev;
1558615Sbill 	delexit();
1559615Sbill }
1560615Sbill 
mkfsym(s)1561615Sbill mkfsym(s)
1562615Sbill char *s;
1563615Sbill {
1564615Sbill 
1565615Sbill 	if (sflag || xflag)
1566615Sbill 		return;
1567615Sbill 	cursym.n_un.n_name = s;
156830836Sbostic 	cursym.n_type = N_EXT | N_FN;
1569615Sbill 	cursym.n_value = torigin;
1570615Sbill 	symwrite(&cursym, sout);
1571615Sbill }
1572615Sbill 
getarhdr()1573615Sbill getarhdr()
1574615Sbill {
1575615Sbill 	register char *cp;
1576615Sbill 
1577615Sbill 	mget((char *)&archdr, sizeof archdr, &text);
1578615Sbill 	for (cp=archdr.ar_name; cp<&archdr.ar_name[sizeof(archdr.ar_name)];)
1579615Sbill 		if (*cp++ == ' ') {
1580615Sbill 			cp[-1] = 0;
1581615Sbill 			return;
1582615Sbill 		}
1583615Sbill }
1584615Sbill 
mget(loc,n,sp)1585615Sbill mget(loc, n, sp)
1586615Sbill register STREAM *sp;
1587615Sbill register char *loc;
1588615Sbill {
1589615Sbill 	register char *p;
1590615Sbill 	register int take;
1591615Sbill 
1592615Sbill top:
1593615Sbill 	if (n == 0)
1594615Sbill 		return;
1595615Sbill 	if (sp->size && sp->nibuf) {
1596615Sbill 		p = sp->ptr;
1597615Sbill 		take = sp->size;
1598615Sbill 		if (take > sp->nibuf)
1599615Sbill 			take = sp->nibuf;
1600615Sbill 		if (take > n)
1601615Sbill 			take = n;
1602615Sbill 		n -= take;
1603615Sbill 		sp->size -= take;
1604615Sbill 		sp->nibuf -= take;
1605615Sbill 		sp->pos += take;
1606615Sbill 		do
1607615Sbill 			*loc++ = *p++;
1608615Sbill 		while (--take > 0);
1609615Sbill 		sp->ptr = p;
1610615Sbill 		goto top;
1611615Sbill 	}
161216068Sralph 	if (n > p_blksize) {
161316068Sralph 		take = n - n % p_blksize;
161416068Sralph 		lseek(infil, (sp->bno+1)<<p_blkshift, 0);
1615615Sbill 		if (take > sp->size || read(infil, loc, take) != take)
1616615Sbill 			error(1, "premature EOF");
1617615Sbill 		loc += take;
1618615Sbill 		n -= take;
1619615Sbill 		sp->size -= take;
1620615Sbill 		sp->pos += take;
162116068Sralph 		dseek(sp, (sp->bno+1+(take>>p_blkshift))<<p_blkshift, -1);
1622615Sbill 		goto top;
1623615Sbill 	}
1624615Sbill 	*loc++ = get(sp);
1625615Sbill 	--n;
1626615Sbill 	goto top;
1627615Sbill }
1628615Sbill 
1629615Sbill symwrite(sp, bp)
1630615Sbill 	struct nlist *sp;
1631615Sbill 	struct biobuf *bp;
1632615Sbill {
1633615Sbill 	register int len;
1634615Sbill 	register char *str;
1635615Sbill 
1636615Sbill 	str = sp->n_un.n_name;
1637615Sbill 	if (str) {
1638615Sbill 		sp->n_un.n_strx = offset;
1639615Sbill 		len = strlen(str) + 1;
1640615Sbill 		bwrite(str, len, strout);
1641615Sbill 		offset += len;
1642615Sbill 	}
1643615Sbill 	bwrite(sp, sizeof (*sp), bp);
1644615Sbill 	sp->n_un.n_name = str;
1645615Sbill }
1646615Sbill 
dseek(sp,loc,s)1647615Sbill dseek(sp, loc, s)
1648615Sbill register STREAM *sp;
1649615Sbill long loc, s;
1650615Sbill {
1651615Sbill 	register PAGE *p;
1652615Sbill 	register b, o;
1653615Sbill 	int n;
1654615Sbill 
165516068Sralph 	b = loc>>p_blkshift;
165616068Sralph 	o = loc&p_blkmask;
1657615Sbill 	if (o&01)
1658615Sbill 		error(1, "loader error; odd offset");
1659615Sbill 	--sp->pno->nuser;
1660615Sbill 	if ((p = &page[0])->bno!=b && (p = &page[1])->bno!=b)
1661615Sbill 		if (p->nuser==0 || (p = &page[0])->nuser==0) {
1662615Sbill 			if (page[0].nuser==0 && page[1].nuser==0)
1663615Sbill 				if (page[0].bno < page[1].bno)
1664615Sbill 					p = &page[0];
1665615Sbill 			p->bno = b;
166616068Sralph 			lseek(infil, loc & ~(long)p_blkmask, 0);
166716068Sralph 			if ((n = read(infil, p->buff, p_blksize)) < 0)
1668615Sbill 				n = 0;
1669615Sbill 			p->nibuf = n;
167016068Sralph 		} else
167116068Sralph 			error(1, "botch: no pages");
1672615Sbill 	++p->nuser;
1673615Sbill 	sp->bno = b;
1674615Sbill 	sp->pno = p;
1675615Sbill 	if (s != -1) {sp->size = s; sp->pos = 0;}
1676615Sbill 	sp->ptr = (char *)(p->buff + o);
1677615Sbill 	if ((sp->nibuf = p->nibuf-o) <= 0)
1678615Sbill 		sp->size = 0;
1679615Sbill }
1680615Sbill 
1681615Sbill char
get(asp)1682615Sbill get(asp)
1683615Sbill STREAM *asp;
1684615Sbill {
1685615Sbill 	register STREAM *sp;
1686615Sbill 
1687615Sbill 	sp = asp;
1688615Sbill 	if ((sp->nibuf -= sizeof(char)) < 0) {
168916068Sralph 		dseek(sp, ((long)(sp->bno+1)<<p_blkshift), (long)-1);
1690615Sbill 		sp->nibuf -= sizeof(char);
1691615Sbill 	}
1692615Sbill 	if ((sp->size -= sizeof(char)) <= 0) {
1693615Sbill 		if (sp->size < 0)
1694615Sbill 			error(1, "premature EOF");
1695615Sbill 		++fpage.nuser;
1696615Sbill 		--sp->pno->nuser;
1697615Sbill 		sp->pno = (PAGE *) &fpage;
1698615Sbill 	}
1699615Sbill 	sp->pos += sizeof(char);
1700615Sbill 	return(*sp->ptr++);
1701615Sbill }
1702615Sbill 
getfile(acp)1703615Sbill getfile(acp)
1704615Sbill char *acp;
1705615Sbill {
1706615Sbill 	register int c;
1707615Sbill 	char arcmag[SARMAG+1];
1708615Sbill 	struct stat stb;
1709615Sbill 
1710615Sbill 	archdr.ar_name[0] = '\0';
171117133Ssam 	filname = acp;
171217133Ssam 	if (filname[0] == '-' && filname[1] == 'l')
171317133Ssam 		infil = libopen(filname + 2, O_RDONLY);
171417133Ssam 	else
171544768Sbostic 		infil = open(filname, O_RDONLY);
171617133Ssam 	if (infil < 0)
1717615Sbill 		error(1, "cannot open");
171816068Sralph 	fstat(infil, &stb);
1719615Sbill 	page[0].bno = page[1].bno = -1;
1720615Sbill 	page[0].nuser = page[1].nuser = 0;
172116068Sralph 	c = stb.st_blksize;
172216068Sralph 	if (c == 0 || (c & (c - 1)) != 0) {
172316068Sralph 		/* use default size if not a power of two */
172416068Sralph 		c = BLKSIZE;
172516068Sralph 	}
172616068Sralph 	if (p_blksize != c) {
172716068Sralph 		p_blksize = c;
172816068Sralph 		p_blkmask = c - 1;
172916068Sralph 		for (p_blkshift = 0; c > 1 ; p_blkshift++)
173016068Sralph 			c >>= 1;
173116068Sralph 		if (page[0].buff != NULL)
173216068Sralph 			free(page[0].buff);
173316068Sralph 		page[0].buff = (char *)malloc(p_blksize);
173416068Sralph 		if (page[0].buff == NULL)
173516068Sralph 			error(1, "ran out of memory (getfile)");
173616068Sralph 		if (page[1].buff != NULL)
173716068Sralph 			free(page[1].buff);
173816068Sralph 		page[1].buff = (char *)malloc(p_blksize);
173916068Sralph 		if (page[1].buff == NULL)
174016068Sralph 			error(1, "ran out of memory (getfile)");
174116068Sralph 	}
1742615Sbill 	text.pno = reloc.pno = (PAGE *) &fpage;
1743615Sbill 	fpage.nuser = 2;
1744615Sbill 	dseek(&text, 0L, SARMAG);
1745615Sbill 	if (text.size <= 0)
1746615Sbill 		error(1, "premature EOF");
1747615Sbill 	mget((char *)arcmag, SARMAG, &text);
1748615Sbill 	arcmag[SARMAG] = 0;
1749615Sbill 	if (strcmp(arcmag, ARMAG))
1750615Sbill 		return (0);
1751615Sbill 	dseek(&text, SARMAG, sizeof archdr);
175217133Ssam 	if (text.size <= 0)
1753615Sbill 		return (1);
1754615Sbill 	getarhdr();
175530828Sbostic 	if (strncmp(archdr.ar_name, RANLIBMAG, sizeof(archdr.ar_name)) != 0)
1756615Sbill 		return (1);
1757615Sbill 	return (stb.st_mtime > atol(archdr.ar_date) ? 3 : 2);
1758615Sbill }
1759615Sbill 
176017133Ssam /*
176117133Ssam  * Search for a library with given name
176217133Ssam  * using the directory search array.
176317133Ssam  */
libopen(name,oflags)176417133Ssam libopen(name, oflags)
176517133Ssam 	char *name;
176617133Ssam 	int oflags;
176717133Ssam {
176817133Ssam 	register char *p, *cp;
176917133Ssam 	register int i;
177017133Ssam 	static char buf[MAXPATHLEN+1];
177117133Ssam 	int fd = -1;
177217133Ssam 
177317133Ssam 	if (*name == '\0')			/* backwards compat */
177417133Ssam 		name = "a";
177517133Ssam 	for (i = 0; i < ndir && fd == -1; i++) {
177617133Ssam 		p = buf;
177717133Ssam 		for (cp = dirs[i]; *cp; *p++ = *cp++)
177817133Ssam 			;
177917133Ssam 		*p++ = '/';
178017133Ssam 		for (cp = "lib"; *cp; *p++ = *cp++)
178117133Ssam 			;
178217133Ssam 		for (cp = name; *cp; *p++ = *cp++)
178317133Ssam 			;
178417133Ssam 		cp = ".a";
178517133Ssam 		while (*p++ = *cp++)
178617133Ssam 			;
178717133Ssam 		fd = open(buf, oflags);
178817133Ssam 	}
178917133Ssam 	if (fd != -1)
179017133Ssam 		filname = buf;
179117133Ssam 	return (fd);
179217133Ssam }
179317133Ssam 
1794615Sbill struct nlist **
lookup()1795615Sbill lookup()
1796615Sbill {
1797615Sbill 	register int sh;
1798615Sbill 	register struct nlist **hp;
1799615Sbill 	register char *cp, *cp1;
1800615Sbill 	register struct symseg *gp;
1801615Sbill 	register int i;
1802615Sbill 
1803615Sbill 	sh = 0;
1804615Sbill 	for (cp = cursym.n_un.n_name; *cp;)
1805615Sbill 		sh = (sh<<1) + *cp++;
1806615Sbill 	sh = (sh & 0x7fffffff) % HSIZE;
1807615Sbill 	for (gp = symseg; gp < &symseg[NSEG]; gp++) {
1808615Sbill 		if (gp->sy_first == 0) {
1809615Sbill 			gp->sy_first = (struct nlist *)
1810615Sbill 			    calloc(NSYM, sizeof (struct nlist));
1811615Sbill 			gp->sy_hfirst = (struct nlist **)
1812615Sbill 			    calloc(HSIZE, sizeof (struct nlist *));
1813615Sbill 			if (gp->sy_first == 0 || gp->sy_hfirst == 0)
1814615Sbill 				error(1, "ran out of space for symbol table");
1815615Sbill 			gp->sy_last = gp->sy_first + NSYM;
1816615Sbill 			gp->sy_hlast = gp->sy_hfirst + HSIZE;
1817615Sbill 		}
1818615Sbill 		if (gp > csymseg)
1819615Sbill 			csymseg = gp;
1820615Sbill 		hp = gp->sy_hfirst + sh;
1821615Sbill 		i = 1;
1822615Sbill 		do {
1823615Sbill 			if (*hp == 0) {
1824615Sbill 				if (gp->sy_used == NSYM)
1825615Sbill 					break;
1826615Sbill 				return (hp);
1827615Sbill 			}
1828615Sbill 			cp1 = (*hp)->n_un.n_name;
1829615Sbill 			for (cp = cursym.n_un.n_name; *cp == *cp1++;)
1830615Sbill 				if (*cp++ == 0)
1831615Sbill 					return (hp);
1832615Sbill 			hp += i;
1833615Sbill 			i += 2;
1834615Sbill 			if (hp >= gp->sy_hlast)
1835615Sbill 				hp -= HSIZE;
1836615Sbill 		} while (i < HSIZE);
1837615Sbill 		if (i > HSIZE)
1838615Sbill 			error(1, "hash table botch");
1839615Sbill 	}
1840615Sbill 	error(1, "symbol table overflow");
1841615Sbill 	/*NOTREACHED*/
1842615Sbill }
1843615Sbill 
1844615Sbill symfree(saved)
1845615Sbill 	struct nlist *saved;
1846615Sbill {
1847615Sbill 	register struct symseg *gp;
1848615Sbill 	register struct nlist *sp;
1849615Sbill 
1850615Sbill 	for (gp = csymseg; gp >= symseg; gp--, csymseg--) {
1851615Sbill 		sp = gp->sy_first + gp->sy_used;
1852615Sbill 		if (sp == saved) {
1853615Sbill 			nextsym = sp;
1854615Sbill 			return;
1855615Sbill 		}
1856615Sbill 		for (sp--; sp >= gp->sy_first; sp--) {
1857615Sbill 			gp->sy_hfirst[sp->n_hash] = 0;
1858615Sbill 			gp->sy_used--;
1859615Sbill 			if (sp == saved) {
1860615Sbill 				nextsym = sp;
1861615Sbill 				return;
1862615Sbill 			}
1863615Sbill 		}
1864615Sbill 	}
1865615Sbill 	if (saved == 0)
1866615Sbill 		return;
1867615Sbill 	error(1, "symfree botch");
1868615Sbill }
1869615Sbill 
1870615Sbill struct nlist **
slookup(s)1871615Sbill slookup(s)
1872615Sbill 	char *s;
1873615Sbill {
1874615Sbill 
1875615Sbill 	cursym.n_un.n_name = s;
1876615Sbill 	cursym.n_type = N_EXT+N_UNDF;
1877615Sbill 	cursym.n_value = 0;
1878615Sbill 	return (lookup());
1879615Sbill }
1880615Sbill 
enter(hp)1881615Sbill enter(hp)
1882615Sbill register struct nlist **hp;
1883615Sbill {
1884615Sbill 	register struct nlist *sp;
1885615Sbill 
1886615Sbill 	if (*hp==0) {
1887615Sbill 		if (hp < csymseg->sy_hfirst || hp >= csymseg->sy_hlast)
1888615Sbill 			error(1, "enter botch");
1889615Sbill 		*hp = lastsym = sp = csymseg->sy_first + csymseg->sy_used;
1890615Sbill 		csymseg->sy_used++;
1891615Sbill 		sp->n_un.n_name = cursym.n_un.n_name;
1892615Sbill 		sp->n_type = cursym.n_type;
1893615Sbill 		sp->n_hash = hp - csymseg->sy_hfirst;
1894615Sbill 		sp->n_value = cursym.n_value;
1895615Sbill 		nextsym = lastsym + 1;
1896615Sbill 		return(1);
1897615Sbill 	} else {
1898615Sbill 		lastsym = *hp;
1899615Sbill 		return(0);
1900615Sbill 	}
1901615Sbill }
1902615Sbill 
1903615Sbill symx(sp)
1904615Sbill 	struct nlist *sp;
1905615Sbill {
1906615Sbill 	register struct symseg *gp;
1907615Sbill 
1908615Sbill 	if (sp == 0)
1909615Sbill 		return (0);
1910615Sbill 	for (gp = csymseg; gp >= symseg; gp--)
1911615Sbill 		/* <= is sloppy so nextsym will always work */
1912615Sbill 		if (sp >= gp->sy_first && sp <= gp->sy_last)
1913615Sbill 			return ((gp - symseg) * NSYM + sp - gp->sy_first);
1914615Sbill 	error(1, "symx botch");
1915615Sbill 	/*NOTREACHED*/
1916615Sbill }
1917615Sbill 
symreloc()1918615Sbill symreloc()
1919615Sbill {
1920615Sbill 	if(funding) return;
1921615Sbill 	switch (cursym.n_type & 017) {
1922615Sbill 
1923615Sbill 	case N_TEXT:
1924615Sbill 	case N_EXT+N_TEXT:
1925615Sbill 		cursym.n_value += ctrel;
1926615Sbill 		return;
1927615Sbill 
1928615Sbill 	case N_DATA:
1929615Sbill 	case N_EXT+N_DATA:
1930615Sbill 		cursym.n_value += cdrel;
1931615Sbill 		return;
1932615Sbill 
1933615Sbill 	case N_BSS:
1934615Sbill 	case N_EXT+N_BSS:
1935615Sbill 		cursym.n_value += cbrel;
1936615Sbill 		return;
1937615Sbill 
1938615Sbill 	case N_EXT+N_UNDF:
1939615Sbill 		return;
1940615Sbill 
1941615Sbill 	default:
1942615Sbill 		if (cursym.n_type&N_EXT)
1943615Sbill 			cursym.n_type = N_EXT+N_ABS;
1944615Sbill 		return;
1945615Sbill 	}
1946615Sbill }
1947615Sbill 
error(n,s)1948615Sbill error(n, s)
1949615Sbill char *s;
1950615Sbill {
1951898Sbill 
1952615Sbill 	if (errlev==0)
1953615Sbill 		printf("ld:");
1954615Sbill 	if (filname) {
1955615Sbill 		printf("%s", filname);
1956615Sbill 		if (n != -1 && archdr.ar_name[0])
1957615Sbill 			printf("(%s)", archdr.ar_name);
1958615Sbill 		printf(": ");
1959615Sbill 	}
1960615Sbill 	printf("%s\n", s);
1961615Sbill 	if (n == -1)
1962615Sbill 		return;
1963615Sbill 	if (n)
1964615Sbill 		delexit();
1965615Sbill 	errlev = 2;
1966615Sbill }
1967615Sbill 
readhdr(loc)1968615Sbill readhdr(loc)
1969615Sbill off_t loc;
1970615Sbill {
1971615Sbill 
1972615Sbill 	dseek(&text, loc, (long)sizeof(filhdr));
1973615Sbill 	mget((short *)&filhdr, sizeof(filhdr), &text);
1974615Sbill 	if (N_BADMAG(filhdr)) {
1975615Sbill 		if (filhdr.a_magic == OARMAG)
1976615Sbill 			error(1, "old archive");
1977615Sbill 		error(1, "bad magic number");
1978615Sbill 	}
1979615Sbill 	if (filhdr.a_text&01 || filhdr.a_data&01)
1980615Sbill 		error(1, "text/data size odd");
1981615Sbill 	if (filhdr.a_magic == NMAGIC || filhdr.a_magic == ZMAGIC) {
198212671Ssam 		cdrel = -round(filhdr.a_text, pagesize);
1983615Sbill 		cbrel = cdrel - filhdr.a_data;
1984615Sbill 	} else if (filhdr.a_magic == OMAGIC) {
1985615Sbill 		cdrel = -filhdr.a_text;
1986615Sbill 		cbrel = cdrel - filhdr.a_data;
1987615Sbill 	} else
1988615Sbill 		error(1, "bad format");
1989615Sbill }
1990615Sbill 
round(v,r)1991615Sbill round(v, r)
1992615Sbill 	int v;
1993615Sbill 	u_long r;
1994615Sbill {
1995615Sbill 
1996615Sbill 	r--;
1997615Sbill 	v += r;
1998615Sbill 	v &= ~(long)r;
1999615Sbill 	return(v);
2000615Sbill }
2001615Sbill 
2002615Sbill #define	NSAVETAB	8192
2003615Sbill char	*savetab;
2004615Sbill int	saveleft;
2005615Sbill 
2006615Sbill char *
savestr(cp)2007615Sbill savestr(cp)
2008615Sbill 	register char *cp;
2009615Sbill {
2010615Sbill 	register int len;
2011615Sbill 
2012615Sbill 	len = strlen(cp) + 1;
2013615Sbill 	if (len > saveleft) {
2014615Sbill 		saveleft = NSAVETAB;
2015615Sbill 		if (len > saveleft)
2016615Sbill 			saveleft = len;
201717133Ssam 		savetab = malloc(saveleft);
2018615Sbill 		if (savetab == 0)
2019615Sbill 			error(1, "ran out of memory (savestr)");
2020615Sbill 	}
2021615Sbill 	strncpy(savetab, cp, len);
2022615Sbill 	cp = savetab;
2023615Sbill 	savetab += len;
2024615Sbill 	saveleft -= len;
2025615Sbill 	return (cp);
2026615Sbill }
2027615Sbill 
bopen(bp,off,bufsize)202816068Sralph bopen(bp, off, bufsize)
202916068Sralph 	register struct biobuf *bp;
2030615Sbill {
2031615Sbill 
203217133Ssam 	bp->b_ptr = bp->b_buf = malloc(bufsize);
203316068Sralph 	if (bp->b_ptr == (char *)0)
203416068Sralph 		error(1, "ran out of memory (bopen)");
203516068Sralph 	bp->b_bufsize = bufsize;
203616068Sralph 	bp->b_nleft = bufsize - (off % bufsize);
2037615Sbill 	bp->b_off = off;
2038615Sbill 	bp->b_link = biobufs;
2039615Sbill 	biobufs = bp;
2040615Sbill }
2041615Sbill 
2042615Sbill int	bwrerror;
2043615Sbill 
bwrite(p,cnt,bp)2044615Sbill bwrite(p, cnt, bp)
2045615Sbill 	register char *p;
2046615Sbill 	register int cnt;
2047615Sbill 	register struct biobuf *bp;
2048615Sbill {
2049615Sbill 	register int put;
2050615Sbill 	register char *to;
2051615Sbill 
2052615Sbill top:
2053615Sbill 	if (cnt == 0)
2054615Sbill 		return;
2055615Sbill 	if (bp->b_nleft) {
2056615Sbill 		put = bp->b_nleft;
2057615Sbill 		if (put > cnt)
2058615Sbill 			put = cnt;
2059615Sbill 		bp->b_nleft -= put;
2060615Sbill 		to = bp->b_ptr;
206125419Sbloom 		bcopy(p, to, put);
2062615Sbill 		bp->b_ptr += put;
2063615Sbill 		p += put;
2064615Sbill 		cnt -= put;
2065615Sbill 		goto top;
2066615Sbill 	}
206716068Sralph 	if (cnt >= bp->b_bufsize) {
2068615Sbill 		if (bp->b_ptr != bp->b_buf)
2069615Sbill 			bflush1(bp);
207016068Sralph 		put = cnt - cnt % bp->b_bufsize;
2071615Sbill 		if (boffset != bp->b_off)
2072615Sbill 			lseek(biofd, bp->b_off, 0);
2073615Sbill 		if (write(biofd, p, put) != put) {
2074615Sbill 			bwrerror = 1;
2075615Sbill 			error(1, "output write error");
2076615Sbill 		}
2077615Sbill 		bp->b_off += put;
2078615Sbill 		boffset = bp->b_off;
2079615Sbill 		p += put;
2080615Sbill 		cnt -= put;
2081615Sbill 		goto top;
2082615Sbill 	}
2083615Sbill 	bflush1(bp);
2084615Sbill 	goto top;
2085615Sbill }
2086615Sbill 
bflush()2087615Sbill bflush()
2088615Sbill {
2089615Sbill 	register struct biobuf *bp;
2090615Sbill 
2091615Sbill 	if (bwrerror)
2092615Sbill 		return;
2093615Sbill 	for (bp = biobufs; bp; bp = bp->b_link)
2094615Sbill 		bflush1(bp);
2095615Sbill }
2096615Sbill 
bflush1(bp)2097615Sbill bflush1(bp)
2098615Sbill 	register struct biobuf *bp;
2099615Sbill {
2100615Sbill 	register int cnt = bp->b_ptr - bp->b_buf;
2101615Sbill 
2102615Sbill 	if (cnt == 0)
2103615Sbill 		return;
2104615Sbill 	if (boffset != bp->b_off)
2105615Sbill 		lseek(biofd, bp->b_off, 0);
2106615Sbill 	if (write(biofd, bp->b_buf, cnt) != cnt) {
2107615Sbill 		bwrerror = 1;
2108615Sbill 		error(1, "output write error");
2109615Sbill 	}
2110615Sbill 	bp->b_off += cnt;
2111615Sbill 	boffset = bp->b_off;
2112615Sbill 	bp->b_ptr = bp->b_buf;
211316068Sralph 	bp->b_nleft = bp->b_bufsize;
2114615Sbill }
2115615Sbill 
bflushc(bp,c)2116615Sbill bflushc(bp, c)
2117615Sbill 	register struct biobuf *bp;
2118615Sbill {
2119615Sbill 
2120615Sbill 	bflush1(bp);
2121615Sbill 	bputc(c, bp);
2122615Sbill }
212316068Sralph 
bseek(bp,off)212416068Sralph bseek(bp, off)
212516068Sralph 	register struct biobuf *bp;
212616068Sralph 	register off_t off;
212716068Sralph {
212816068Sralph 	bflush1(bp);
212916068Sralph 
213016068Sralph 	bp->b_nleft = bp->b_bufsize - (off % bp->b_bufsize);
213116068Sralph 	bp->b_off = off;
213216068Sralph }
2133