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