|
|
1.1 root 1: /*
2: * ld/pass1.c
3: *
4: * One Pass Coff Loader.
5: * By Charles Fiterman 3/31/92 for Mark Williams.
6: */
7: #include "ld.h"
8:
9: mod_t *sysHead;
10: static int ifd;
11: static char *fname;
12:
13: /*
14: * Reverse bytes on the 80386 for archive pointers.
15: */
16: #ifdef GEMDOS
17: #include <osbind.h>
18: #define flipbytes(x)
19: #else
20: flipbytes(c)
21: register char *c;
22: {
23: register char t;
24:
25: t = c[0]; c[0] = c[3]; c[3] = t;
26: t = c[1]; c[1] = c[2]; c[2] = t;
27: }
28: #endif
29:
30: /*
31: * Symbol name.
32: */
33: char *
34: symName(sym, work)
35: register SYMENT *sym;
36: register char *work;
37: {
38: if (1 == sym->n_zeroes) { /* pointer to table record */
39: sym_t *s;
40:
41: s = (sym_t *)sym->n_offset;
42: sym = &(s->sym);
43: }
44:
45: if (!sym->n_zeroes) /* pointer to long symbol */
46: return ((char *)sym->n_offset);
47:
48: /*
49: * Name in record may need terminator.
50: * Profiling shows this gets used a lot so do it quick
51: * even at the cost of some readability.
52: */
53: ((long *)work)[0] = sym->n_zeroes;
54: ((long *)work)[1] = sym->n_offset;
55: /* memcpy(work, sym->n_name, SYMNMLEN); */
56: work[SYMNMLEN] = '\0';
57: return (work);
58: }
59:
60: /*
61: * complain about redefined symbol
62: */
63: void
64: symredef(sp, mp)
65: sym_t *sp;
66: mod_t *mp;
67: {
68: /*
69: * Simple module.
70: */
71: if (mp->mname[0] == '\0')
72: spmsg(sp, "redefined in file '%s'", mp->fname);
73: /* A symbol is defined in incompatible ways in different files. */
74:
75: else
76: spmsg(sp, "redefined in file '%s': module '%.*s'",
77: mp->fname, DIRSIZ, mp->mname );
78: /* A symbol is defined in incompatible ways in different files. */
79: }
80:
81: /*
82: * Return undefined reference to given symbol if any.
83: */
84: sym_t *
85: symref(name)
86: char *name;
87: {
88: char work[SYMNMLEN + 1];
89: register sym_t *sp;
90: register SYMENT *sym;
91:
92: /* Scan internal symbol table for undefined reference. */
93: for (sp=symtable[crc16(name) % NHASH]; sp != NULL; sp=sp->next) {
94: sym = &(sp->sym);
95: if (undefined(sym) && !strcmp(symName(sym, work), name))
96: break;
97: }
98: return(sp); /* Return reference, or NULL. */
99: }
100:
101: /*
102: * Read input files.
103: */
104: readFile(fn, loadsw, p)
105: char *fn; /* file name */
106: int loadsw; /* 1 = load this file, 0 = use its symbol table */
107: register char *p;
108: {
109: struct stat st;
110:
111: fname = fn;
112:
113: if (NULL == p) { /* not forced */
114: /*
115: * Look for rename entrys.
116: * con=atcon
117: * is not a filename with an =
118: * it means rename con to atcon.
119: * This is a drvld requirment.
120: */
121: if (NULL != (p = strchr(fname, '='))) {
122: ren_t *new;
123:
124: new = alloc(sizeof(*new));
125: new->next = rhead;
126: rhead = new;
127: new->from = fname;
128: *p = '\0';
129: new->to = p + 1;
130: return;
131: }
132:
133: /* all names must be *.[ao] */
134: if (NULL == (p = strrchr(fname, '.')) || p[2])
135: p = ".?";
136: if (!loadsw) /* drvld's read of the system */
137: p = "_s.o" + 2;
138: #if 0
139: /* This is bogus, e.g. it suppresses the ld of a_s.o in "cc a_s.o". */
140: /* shared libs have names like libc_s.a */
141: if ((p[-2] == '_') && (p[-1] == 's'))
142: loadsw = 0;
143: #endif
144: }
145: #ifdef GEMDOS
146: stat(fname, &st);
147: ifd = qopen(fname, 0);
148: #else
149: ifd = qopen(fname, 0);
150: fstat(ifd, &st);
151: #endif
152: switch(p[1]) {
153: case 'a':
154: archive(loadsw);
155: break;
156: case 'o':
157: object("", st.st_size, loadsw);
158: break;
159: default:
160: message("unlikely input file name '%s'", fname);
161: /* Input file names must end \fB.o\fR for object or \fB.a\fR
162: * for archive. */
163: }
164: close(ifd);
165: }
166:
167: /*
168: * Add item to correct common
169: */
170: static void
171: addComm(v)
172: long v;
173: {
174: switch ((int)v & 3) {
175: case 0:
176: comnl += v; /* Long aligned commons */
177: break;
178: case 2:
179: comns += v; /* Short aligned commons */
180: break;
181: default:
182: comnb += v; /* Byte aligned commons */
183: }
184: }
185:
186: /*
187: * add a symbol to the symbol table.
188: */
189: addsym(s, mp)
190: register SYMENT *s;
191: mod_t *mp;
192: {
193: register sym_t *sp;
194: ren_t *ren;
195: enum state {
196: local, gdef, gref, comm
197: } new, old;
198: int h, sec;
199: char has_fsize, has_fcn, nodata;
200: char *name;
201: char w1[SYMNMLEN + 1], w2[SYMNMLEN + 1];
202:
203: sec = s->n_scnum;
204: switch (s->n_sclass) {
205: case C_EXTDEF:
206: s->n_sclass = C_EXT;
207: sec = s->n_value = s->n_scnum = 0;
208: case C_EXT:
209: if (sec)
210: new = gdef;
211: else if (s->n_value)
212: new = comm;
213: else
214: new = gref;
215: break;
216: case C_STAT:
217: new = local;
218: break;
219: default:
220: if (!debflg)
221: return;
222: new = local;
223: }
224:
225: name = symName(s, w1);
226:
227: /* check rename entrys */
228: for (ren = rhead; NULL != ren; ren = ren->next) {
229: if (!strcmp(ren->from, name)) {
230: s->n_zeroes = 0;
231: name = ren->to;
232: s->n_offset = (long)name;
233: break;
234: }
235: }
236: h = crc16(name) % NHASH;
237:
238: /* Make symbols segment relative, if mp == NULL than sec == 0 */
239: if (sec > 0)
240: s->n_value += secth[sec - 1].s_size - mp->s[sec - 1].s_vaddr;
241:
242: if (local == new &&
243: (nolcl ||
244: (noilcl && (name[0] == '.') && (name[1] == 'L'))))
245: return;
246:
247: for (sp = ((local == new) ? NULL : symtable[h]);
248: sp != NULL;
249: sp = sp->next) {
250: if ((sp->sym.n_sclass != C_EXT) ||
251: (strcmp(symName(&(sp->sym), w2), name)))
252: continue;
253:
254: if (sp->sym.n_scnum)
255: old = gdef;
256: else if (sp->sym.n_value)
257: old = comm;
258: else
259: old = gref;
260:
261: switch (new) {
262: /* case local: can't get here */
263:
264: case gref:
265: s->n_offset = (long)sp;
266: s->n_zeroes = 1;
267: return;
268:
269: case gdef:
270: switch (old) {
271: case comm:
272: spwarn(sp,
273: "symbol defined as a common then a global");
274: /* A symbol was defined as a common and a globl, eg
275: * .DM
276: * int x; // a common in one module
277: * int x = 5; // a globl in another module
278: * .DE
279: * Read your code and think about variable usage.
280: * We redefined the common as an external to match
281: * the UNIX linker, which fails to flag this.
282: */
283: addComm(- sp->sym.n_value); /* zonk common */
284: memcpy(&(sp->sym), s, sizeof(*s));
285: sp->mod = mp;
286: s->n_offset = (long)sp;
287: s->n_zeroes = 1;
288: return;
289:
290: case gref:
291: nundef--;
292: memcpy(&(sp->sym), s, sizeof(*s));
293: sp->mod = mp;
294: s->n_offset = (long)sp;
295: s->n_zeroes = 1;
296: return;
297:
298: default:
299: symredef(sp, mp);
300: return;
301: }
302:
303: case comm:
304: switch (old) {
305: case comm:
306: s->n_offset = (long)sp;
307: s->n_zeroes = 1;
308:
309: if (sp->sym.n_value == s->n_value)
310: return;
311:
312: spwarn(sp, "defined with lengths %ld and %ld",
313: sp->sym.n_value,
314: s->n_value);
315: /* A common was defined with different lengths,
316: * while this is legal it is very unusual in
317: * C programs. This warning may be turned off
318: * with the -q flag */
319:
320: addComm(- sp->sym.n_value);
321: if (sp->sym.n_value < s->n_value) {
322: sp->sym.n_value = s->n_value;
323: sp->mod = mp;
324: }
325: sp->sym.n_value += 3;
326: sp->sym.n_value &= ~3L;
327: addComm(sp->sym.n_value);
328: return;
329:
330: case gref:
331: addComm(s->n_value);
332: nundef--;
333: memcpy(&(sp->sym), s, sizeof(*s));
334: sp->mod = mp;
335: s->n_offset = (long)sp;
336: s->n_zeroes = 1;
337: return;
338:
339: case gdef:
340: spwarn(sp, "Defined as a global then a common");
341: /* NODOC */
342: s->n_offset = (long)sp;
343: s->n_zeroes = 1;
344: return;
345: }
346: }
347: }
348:
349: /* symbol local or not found */
350: sp = alloc(sizeof(*sp));
351: memcpy(&(sp->sym), s, sizeof(*s));
352: sp->next = symtable[h];
353: symtable[h] = sp;
354:
355: switch (new) {
356: case comm:
357: addComm(s->n_value);
358: case local:
359: break;
360: case gref:
361: nundef++;
362: }
363:
364: sp->mod = mp;
365: s->n_offset = (long)sp;
366: s->n_zeroes = 1;
367: }
368:
369: /*
370: * Read input file.
371: */
372: static void
373: xread(loc, size)
374: char *loc;
375: unsigned size;
376: {
377: if (size != read(ifd, loc, size))
378: fatal("error reading '%s'", fname); /**/
379: }
380:
381: /*
382: * Inhale object file.
383: */
384: object(mname, size, loadsw)
385: char *mname;
386: long size;
387: {
388: register SYMENT *sym;
389: register SCNHDR *s;
390: SYMENT *endSym;
391: mod_t *mp;
392: char *endmod;
393: long i, j, k;
394:
395: if (watch) {
396: errCount--;
397: modmsg(fname, mname, "adding"); /* NODOC */
398: }
399: if (size < sizeof(FILEHDR)) {
400: modmsg(fname, mname, "not an object file - length %d", size);
401: /* This cannot be an object file */
402: exit(1);
403: }
404: mp = alloc(sizeof(*mp)); /* allocate our header */
405: mp->f = alloc((int)size); /* allocate space for file */
406: endmod = mp->f + size; /* end of space for file */
407: xread(mp->f, (int)size); /* inhale file */
408:
409: if (mp->f->f_magic != C_386_MAGIC) {
410: modmsg(fname, mname, "not an object file - header starts %x", mp->f->f_magic);
411: /* Coff headers are expected to start 0x14C,
412: * which is called the magic number.
413: * This started with the stated hex number. */
414: exit(1);
415: }
416:
417: mp->fname = newcpy(fname);
418: if (*mname)
419: mp->mname = newcpy(mname);
420: else
421: mp->mname = "";
422:
423: if (loadsw) { /* put modules on load list */
424: if (head == NULL)
425: head = mp;
426: else
427: tail->next = mp;
428: tail = mp;
429: fileh.f_magic = C_386_MAGIC;
430: }
431: else { /* put modules on linkto list */
432: if (xhead == NULL)
433: xhead = mp;
434: else
435: xtail->next = mp;
436: xtail = mp;
437: }
438:
439: /*
440: * Turn disk pointers into ram pointers.
441: */
442: j = ((long)(mp->f));
443: mp->s = (SCNHDR *)(sizeof(FILEHDR) + j + mp->f->f_opthdr);
444: mp->f->f_symptr += j;
445: mp->l = (char *)(mp->f->f_symptr + (mp->f->f_nsyms * sizeof(SYMENT)));
446: if ((mp->f->f_symptr > (long)endmod) ||
447: (mp->l > endmod) ||
448: (mp->f->f_nsyms < 0))
449: corrupt(mp);
450:
451: /* Setup all sections */
452: for (i = 0; i < mp->f->f_nscns; i++) {
453: s = mp->s + i;
454:
455: if (nosym && (STYP_INFO == s->s_flags))
456: continue; /* -s strips comments */
457:
458: /* Test disk pointers for sanity and make them char pointers */
459: #define tst(x) if ((s->x > size) || (s->x < 0)) corrupt(mp); s->x += j;
460: tst(s_scnptr);
461: tst(s_relptr);
462: tst(s_lnnoptr);
463: #undef tst
464:
465: for (k = 0; k < osegs; k++) {
466: if (!strncmp(secth[k].s_name, s->s_name, 8)) {
467: s->s_paddr = k; /* remember outseg number */
468: break;
469: }
470: }
471:
472: if ((k == osegs) && loadsw) { /* New segment */
473: if (++osegs == MAXSEG)
474: fatal("Max segment limit of %s exceeded", MAXSEG);
475: w_message("adding segment '%s'", s->s_name);
476: memcpy(secth + k, s, sizeof(*s));
477: s->s_paddr = k;
478: secth[k].s_size = secth[k].s_nreloc = 0;
479:
480: /* extra segments go to four places */
481: switch(s->s_flags) {
482: case STYP_TEXT:
483: segMap[k] = S_TEXT;
484: break;
485: case STYP_DATA:
486: segMap[k] = S_DATA;
487: break;
488: case STYP_BSS:
489: segMap[k] = S_BSSD;
490: break;
491: case STYP_INFO:
492: segMap[k] = S_COMM;
493: break;
494: default:
495: segMap[k] = S_COMM;
496: fprintf(stderr,
497: "warning: segment '%s' treated as comment\n",
498: s->s_name);
499: }
500: }
501: }
502:
503: /* Do all symbols */
504: sym = (SYMENT *)mp->f->f_symptr;
505: endSym = sym + mp->f->f_nsyms;
506: for (; sym < endSym; sym += sym->n_numaux + 1) {
507: if (sym->n_numaux < 0)
508: corrupt(mp);
509: if (!sym->n_zeroes)
510: sym->n_offset += (long)(mp->l);
511: addsym(sym, mp);
512: }
513:
514: if (loadsw) {
515: /* Add to all sections */
516: for (i = 0; i < mp->f->f_nscns; i++) {
517: s = mp->s + i;
518:
519: if (nosym && (STYP_INFO == s->s_flags))
520: continue; /* -s strips comments */
521:
522: for (k = 0; k < osegs; k++)
523: if (!strncmp(secth[k].s_name, s->s_name, 8))
524: break;
525:
526: secth[k].s_size += s->s_size;
527: secth[k].s_nlnno += s->s_nlnno;
528: if (reloc)
529: secth[k].s_nreloc += s->s_nreloc;
530: }
531: }
532: }
533:
534: /*
535: * Read archive.
536: */
537: archive(loadsw)
538: {
539: struct old_hdr {
540: char ar_name[DIRSIZ]; /* Member name */
541: time_t ar_date; /* Time inserted */
542: short ar_gid; /* Group id */
543: short ar_uid; /* User id */
544: short ar_mode; /* Mode */
545: fsize_t ar_size; /* File size */
546: } arh;
547:
548: struct ar_hdr in_arh;
549: fsize_t count, size, *ptrs;
550: char magic[SARMAG], *p;
551: int found;
552: unsigned i;
553: char *names, *name;
554:
555: xread(magic, sizeof(magic)); /* read archive magic string */
556:
557: if (memcmp(ARMAG, magic, SARMAG))
558: fatal("'%s' is not a COFF archive", fname);
559: /* All files ending \fB.a\fR should be COFF archives. */
560:
561: xread(&in_arh, sizeof(in_arh)); /* read archive header */
562:
563: memset(&arh, '\0', sizeof(arh));
564: memcpy(arh.ar_name, in_arh.ar_name, DIRSIZ);
565: if (NULL != (p = strchr(arh.ar_name, '/')))
566: *p = '\0';
567:
568: sscanf(in_arh.ar_date, "%ld %d %d %o %ld",
569: &arh.ar_date, &arh.ar_uid,
570: &arh.ar_gid, &arh.ar_mode, &arh.ar_size);
571:
572: if (arh.ar_name[0])
573: fatal("Library must be created with ar -s option");
574: /* The \fBar \-s\fR option gives libraries a symbol table
575: * for the use of \fBld\fR. */
576:
577: /*
578: * read random libraries symbol table.
579: */
580: xread(&count, sizeof(count)); /* read pointer count */
581: flipbytes(&count);
582:
583: /* read file pointers */
584: i = size = count * sizeof(count);
585: if (i != size)
586: fatal("archive '%s' is corrupt", fname);
587: /* This file makes no sense as a COFF archive. */
588: ptrs = alloca(i);
589: xread(ptrs, i);
590:
591: /* read symbol names corresponding to pointers */
592: i = size = arh.ar_size - size - sizeof(count);
593: if (i != size)
594: fatal("archive '%s' is corrupt", fname); /* NODOC */
595: names = alloca(i);
596: xread(names, i);
597:
598: w_message("reading archive '%s' nundef %d", fname, nundef);
599:
600: /* search symbol table unitl nothing found */
601: do {
602: for (found = i = 0, name = names;
603: (i < count) && nundef;
604: i++, name = strchr(name, '\0') + 1) {
605: if(!ptrs[i] || symref(name, 0) == NULL)
606: continue;
607:
608: found = 1; /* found something this pass */
609: flipbytes(ptrs + i);
610: lseek(ifd, ptrs[i], 0);
611: xread(&in_arh, sizeof(in_arh));
612:
613: sscanf(in_arh.ar_date,
614: "%ld %d %d %o %ld",
615: &arh.ar_date, &arh.ar_uid,
616: &arh.ar_gid, &arh.ar_mode,
617: &arh.ar_size);
618:
619: in_arh.ar_date[0] = '\0';
620: if (NULL != (p = strchr(in_arh.ar_name,'/')))
621: *p = '\0';
622:
623: object(in_arh.ar_name, arh.ar_size, loadsw);
624:
625: ptrs[i] = 0; /* don't find this again */
626: }
627: } while (found);
628: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.