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