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