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