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