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