|
|
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.