|
|
1.1 ! root 1: /* ! 2: * n2/i386/outcoff.c ! 3: * C compiler COFF output writer. ! 4: * The first pass writes to a temp file. ! 5: * After the first pass, the compiler knows the sizes of the internal segments. ! 6: * The compiler then maps the internal segments to the actual output segments. ! 7: * The second pass reads the temp file and writes the actual output bits. ! 8: * i386. ! 9: */ ! 10: ! 11: #include <stdio.h> ! 12: #include <time.h> ! 13: #include <string.h> ! 14: #include "cc2.h" ! 15: #include "coff.h" ! 16: ! 17: #define NTXT 256 /* Text buffer size */ ! 18: #define NREL 256 /* Relocation buffer size */ ! 19: ! 20: #define RUP(n) (((n)+3)&(~3)) /* Round n up to dword boundary */ ! 21: ! 22: /* SYM flag tests. */ ! 23: #define isbss(sp) ((sp)->s_seg==SBSS) ! 24: #define isdef(sp) (((sp)->s_flag&S_DEF)!=0) ! 25: #define isglobal(sp) (((sp)->s_flag&S_GBL)!=0) ! 26: #define islabel(sp) (((sp)->s_flag&S_LABNO)!=0) ! 27: ! 28: /* Debugging output. */ ! 29: #if DEBUG ! 30: #define dbprintf(args) printf args ! 31: #else ! 32: #define dbprintf(args) ! 33: #endif ! 34: ! 35: /* ! 36: * COFF output. ! 37: * The structure of the COFF output file is presently as follows: ! 38: * file header ! 39: * [optional header: absent] ! 40: * section headers 1 through n ! 41: * data for sections 1 through n ! 42: * relocs for sections 1 through n ! 43: * [line numbers: absent] ! 44: * symbol table [segment names, then symbols] ! 45: * string table ! 46: * These definitions correspond to the header definitions in scn_hdr[] below. ! 47: * These are used as array indices and as indices into COFF symbol table. ! 48: * Add 1 to get the COFF segment number. ! 49: * They will have to change when full debug info is desired. ! 50: */ ! 51: #define C_CODE_SEG 0 /* Code segment index */ ! 52: #define C_DATA_SEG 1 /* Data segment index */ ! 53: #define C_BSS_SEG 2 /* BSS segment index */ ! 54: #define C_NSEGS 3 /* Number of segments */ ! 55: #define C_UNDEF 0 /* Undefined segment */ ! 56: ! 57: /* ! 58: * Scratch file. ! 59: */ ! 60: #define TTYPE 0x07 /* Type */ ! 61: #define TPCR 0x08 /* PC rel flag, or'ed in */ ! 62: #define TSYM 0x10 /* Symbol based flag, or'ed in */ ! 63: ! 64: #define TEND 0x00 /* End marker */ ! 65: #define TENTER 0x01 /* Enter new segment */ ! 66: #define TBYTE 0x02 /* Byte data */ ! 67: #define TWORD 0x03 /* Word data */ ! 68: #define TLONG 0x04 /* Dword data */ ! 69: ! 70: /* ! 71: * Output writer globals. ! 72: */ ! 73: FILEHDR coff_hdr; /* Header buffer */ ! 74: int coff_seg; /* Current COFF segment */ ! 75: char rel[NREL]; /* Relocation buffer */ ! 76: ADDRESS reldot[C_NSEGS]; /* Relocation offsets */ ! 77: char *relp; /* Relocation pointer */ ! 78: SCNHDR scn_hdr[C_NSEGS] = { /* Section headers */ ! 79: { ".text", 0L, 0L, 0L, 0L, 0L, 0L, 0, 0, STYP_TEXT }, ! 80: { ".data", 0L, 0L, 0L, 0L, 0L, 0L, 0, 0, STYP_DATA }, ! 81: { ".bss", 0L, 0L, 0L, 0L, 0L, 0L, 0, 0, STYP_BSS } ! 82: }; ! 83: char txt[NTXT]; /* Text buffer */ ! 84: ADDRESS txtdot; /* Text offset */ ! 85: char *txtp; /* Text pointer */ ! 86: ! 87: /* ! 88: * Map C compiler internal segment into a COFF output segment. ! 89: * The SSTRN entry gets patched by outinit() if not -VPSTR. ! 90: */ ! 91: char segindex[] = { ! 92: C_CODE_SEG, /* SCODE */ ! 93: C_CODE_SEG, /* SLINK */ ! 94: C_CODE_SEG, /* SPURE */ ! 95: C_CODE_SEG, /* possibly patched */ /* SSTRN */ ! 96: C_DATA_SEG, /* SDATA */ ! 97: C_BSS_SEG /* SBSS */ ! 98: }; ! 99: ! 100: /* First pass routines. */ ! 101: /* ! 102: * Initialize the code writer. ! 103: */ ! 104: outinit() ! 105: { ! 106: #if MONOLITHIC ! 107: memset(&coff_hdr, 0, sizeof coff_hdr); ! 108: coff_seg = 0; ! 109: memset(reldot, 0, sizeof reldot); ! 110: memset(scn_hdr, 0, sizeof scn_hdr); ! 111: strcpy(scn_hdr[C_CODE_SEG].s_name, ".text"); ! 112: scn_hdr[C_CODE_SEG].s_flags = STYP_TEXT; ! 113: strcpy(scn_hdr[C_DATA_SEG].s_name, ".data"); ! 114: scn_hdr[C_DATA_SEG].s_flags = STYP_DATA; ! 115: strcpy(scn_hdr[C_BSS_SEG].s_name, ".bss"); ! 116: scn_hdr[C_BSS_SEG].s_flags = STYP_BSS; ! 117: #endif ! 118: if (notvariant(VPSTR)) ! 119: segindex[SSTRN] = C_DATA_SEG; ! 120: } ! 121: ! 122: /* ! 123: * Output an absolute byte. ! 124: */ ! 125: outab(b) int b; ! 126: { ! 127: bput(TBYTE); ! 128: bput(b); ! 129: ++dot; ! 130: } ! 131: ! 132: /* ! 133: * Output an absolute word. ! 134: */ ! 135: outaw(w) int w; ! 136: { ! 137: bput(TWORD); ! 138: iput((ival_t)w); ! 139: dot += 2; ! 140: } ! 141: ! 142: /* ! 143: * Output an absolute dword. ! 144: */ ! 145: outal(i) ival_t i; ! 146: { ! 147: bput(TLONG); ! 148: iput(i); ! 149: dot += 4; ! 150: } ! 151: ! 152: /* ! 153: * Output a full byte. ! 154: */ ! 155: outxb(sp, b, pcrf) register SYM *sp; ADDRESS b; int pcrf; ! 156: { ! 157: register int opcode; ! 158: ! 159: opcode = TBYTE; ! 160: if (sp != NULL) { ! 161: opcode |= TSYM; ! 162: scn_hdr[coff_seg].s_nreloc++; ! 163: } ! 164: if (pcrf) ! 165: opcode |= TPCR; ! 166: bput(opcode); ! 167: bput(b); ! 168: if (sp != NULL) ! 169: pput(sp); ! 170: ++dot; ! 171: } ! 172: ! 173: /* ! 174: * Output a full word. ! 175: */ ! 176: outxw(sp, w, pcrf) register SYM *sp; ADDRESS w; int pcrf; ! 177: { ! 178: register int opcode; ! 179: ! 180: opcode = TWORD; ! 181: if (sp != NULL) { ! 182: opcode |= TSYM; ! 183: scn_hdr[coff_seg].s_nreloc++; ! 184: } ! 185: if (pcrf) ! 186: opcode |= TPCR; ! 187: bput(opcode); ! 188: iput((ival_t)w); ! 189: if (sp != NULL) ! 190: pput(sp); ! 191: dot += 2; ! 192: } ! 193: ! 194: /* ! 195: * Output a full dword. ! 196: */ ! 197: outxl(sp, i, pcrf) register SYM *sp; ADDRESS i; int pcrf; ! 198: { ! 199: register int opcode; ! 200: ! 201: opcode = TLONG; ! 202: if (sp != NULL) { ! 203: opcode |= TSYM; ! 204: scn_hdr[coff_seg].s_nreloc++; ! 205: } ! 206: if (pcrf) ! 207: opcode |= TPCR; ! 208: bput(opcode); ! 209: iput(i); ! 210: if (sp != NULL) ! 211: pput(sp); ! 212: dot += 4; ! 213: } ! 214: ! 215: /* ! 216: * Output a segment switch. ! 217: */ ! 218: outseg(s) register int s; ! 219: { ! 220: bput(TENTER); ! 221: bput(s); ! 222: coff_seg = segindex[s]; ! 223: } ! 224: ! 225: /* ! 226: * Output n zero bytes. ! 227: * If flag is true, generate NOPs instead. ! 228: */ ! 229: outnzb(n, flag) register sizeof_t n; int flag; ! 230: { ! 231: register int i, val; ! 232: ! 233: val = (flag) ? 0x90 : 0; /* xchg %eax, %eax or 0 */ ! 234: for (i = 1; i <= n; ++i) { ! 235: bput(TBYTE); ! 236: bput(val); ! 237: } ! 238: dot += n; ! 239: } ! 240: ! 241: /* ! 242: * Copy a dlabel record from ifp to nowhere. ! 243: */ ! 244: outdlab(i, n) ! 245: int i; /* Indentation */ ! 246: register int n; /* Class initially */ ! 247: { ! 248: /* Get line number */ ! 249: iget(); ! 250: ! 251: /* Get value */ ! 252: if (n < DC_AUTO) ! 253: ; ! 254: else if (n < DC_MOS) ! 255: iget(); ! 256: else { ! 257: bget(); /* Width */ ! 258: bget(); /* Offset */ ! 259: iget(); /* Value */ ! 260: } ! 261: ! 262: /* Get name */ ! 263: sget(id, NCSYMB); ! 264: ! 265: /* Get type */ ! 266: for (;;) { ! 267: n = bget(); ! 268: if (n < DC_SEX) { ! 269: if (n < DX_MEMBS) ! 270: iget(); ! 271: if (n == DX_MEMBS) { ! 272: ++i; ! 273: n = iget(); ! 274: for ( ; n > 0; n-=1) { ! 275: outdlab(i, bget()); ! 276: } ! 277: --i; ! 278: break; ! 279: } else if (n == DX_NAME) { ! 280: iget(); ! 281: sget(id, NCSYMB); ! 282: break; ! 283: } else if (n < DT_STRUCT) ! 284: break; ! 285: } else ! 286: cbotch("unrecognized type byte: %d", n); ! 287: } ! 288: ! 289: /* Done */ ! 290: } ! 291: ! 292: /* ! 293: * Forget a debug relocation record. ! 294: */ ! 295: outdloc(n) int n; ! 296: { ! 297: } ! 298: ! 299: /* ! 300: * Finish up. ! 301: */ ! 302: outdone() ! 303: { ! 304: if (notvariant(VASM)) ! 305: bput(TEND); ! 306: } ! 307: ! 308: /* Second pass. */ ! 309: copycode() ! 310: { ! 311: register int op, i; ! 312: register SEG *segp; ! 313: register SYM *sp; ! 314: register long dseek, sseek, ssize; ! 315: register ADDRESS mseek, segsize; ! 316: int symnum, nd, len, isbyte, isword, issym, ispcr; ! 317: ival_t data; ! 318: SCNHDR *shp; ! 319: SYMENT sym; ! 320: RELOC *rp; ! 321: ! 322: /* Assign segment base addresses. */ ! 323: coff_seg = -1; ! 324: dseek = sizeof(FILEHDR) + C_NSEGS * sizeof(SCNHDR); ! 325: mseek = 0; ! 326: for (i = SCODE, segp = &seg[SCODE]; i <= SBSS; ++i, ++segp) { ! 327: segsize = RUP(segp->s_dot); ! 328: segp->s_dot = 0; ! 329: if (segindex[i] != coff_seg) { ! 330: /* Begin new COFF segment. */ ! 331: coff_seg = segindex[i]; ! 332: dbprintf(("COFF segment %d\n", coff_seg)); ! 333: shp = &scn_hdr[coff_seg]; ! 334: shp->s_paddr = shp->s_vaddr = mseek; ! 335: if (i != C_BSS_SEG) ! 336: shp->s_scnptr = dseek; ! 337: } ! 338: dbprintf(("segment %d: size=%d dseek=%ld mseek=%ld\n", i, segsize, dseek, mseek)); ! 339: segp->s_dseek = dseek; /* set compiler seg disk seek */ ! 340: segp->s_mseek = mseek; /* and memory seek */ ! 341: scn_hdr[coff_seg].s_size += segsize; /* bump COFF seg size */ ! 342: dseek += segsize; /* bump seek pointer */ ! 343: mseek += segsize; /* bump memory seek */ ! 344: } ! 345: ! 346: /* Fix reloc offsets. */ ! 347: for (shp = &scn_hdr[C_CODE_SEG]; shp < &scn_hdr[C_NSEGS]; ++shp) { ! 348: if (shp->s_nreloc != 0) { ! 349: shp->s_relptr = dseek; ! 350: dseek += shp->s_nreloc * sizeof(RELOC); ! 351: } ! 352: } ! 353: ! 354: /* Write symbols. */ ! 355: coff_hdr.f_symptr = dseek; /* symbol secton base */ ! 356: oseek(dseek); /* seek to symbol section */ ! 357: sym.n_type = 0; /* ignore type */ ! 358: sym.n_numaux = 0; /* no aux entries */ ! 359: for (i = C_CODE_SEG, shp = &scn_hdr[i]; i < C_NSEGS; ++i, ++shp) { ! 360: /* Write segment name symbols. */ ! 361: memset(sym.n_name, 0, sizeof(sym.n_name)); ! 362: strcpy(sym.n_name, shp->s_name); ! 363: sym.n_value = shp->s_vaddr; ! 364: sym.n_scnum = i + 1; ! 365: sym.n_sclass = C_STAT; ! 366: owrite((char *)&sym, sizeof(sym)); ! 367: } ! 368: /* Count symbols so symbol section length is known. */ ! 369: symnum = C_NSEGS; ! 370: for (i=0; i < NSHASH; ++i) { ! 371: for (sp = hash2[i]; sp != NULL; sp = sp->s_fp) { ! 372: if (isglobal(sp) || (!islabel(sp) && !isdef(sp))) ! 373: sp->s_ref = symnum++; ! 374: } ! 375: } ! 376: coff_hdr.f_nsyms = symnum; /* symbol count */ ! 377: ssize = sizeof(long); /* string segment size */ ! 378: sseek = dseek + symnum * sizeof(sym) + ssize; /* first string seek */ ! 379: symnum = C_NSEGS; ! 380: for (i=0; i < NSHASH; ++i) { ! 381: for (sp = hash2[i]; sp != NULL; sp = sp->s_fp) { ! 382: if (isdef(sp) || islabel(sp)) ! 383: sp->s_value += seg[sp->s_seg].s_mseek; ! 384: if (isglobal(sp) || (!islabel(sp) && !isdef(sp))) { ! 385: /* Write global or external symbol. */ ! 386: sp->s_ref = symnum++; ! 387: len = strlen(sp->s_id); ! 388: if (len <= SYMNMLEN) ! 389: strncpy(sym.n_name, sp->s_id, SYMNMLEN); ! 390: else { ! 391: /* Spill long name to string table. */ ! 392: dseek = ftell(ofp); ! 393: sym.n_zeroes = 0L; ! 394: sym.n_offset = ssize; ! 395: oseek(sseek); ! 396: sput(sp->s_id); ! 397: sseek += len + 1; ! 398: ssize += len + 1; ! 399: oseek(dseek); ! 400: } ! 401: sym.n_value = sp->s_value; ! 402: sym.n_sclass = C_EXT; ! 403: if (isdef(sp)) ! 404: sym.n_scnum = segindex[sp->s_seg] + 1; ! 405: else ! 406: sym.n_scnum = C_UNDEF; ! 407: owrite((char *)&sym, sizeof(sym)); ! 408: } ! 409: } ! 410: } ! 411: /* Write string table size if nonempty. */ ! 412: if (ssize != sizeof(long)) ! 413: owrite((char *)&ssize, sizeof(ssize)); ! 414: ! 415: /* Copy out code. */ ! 416: dotseg = SCODE; ! 417: coff_seg = segindex[dotseg]; ! 418: txtdot = dot = 0; ! 419: txtp = &txt[0]; ! 420: relp = &rel[0]; ! 421: while ((op = bget()) != TEND) { ! 422: if (op == TENTER) { ! 423: notenuf(); ! 424: seg[dotseg].s_dot = dot; ! 425: dotseg = bget(); ! 426: coff_seg = segindex[dotseg]; ! 427: txtdot = dot = seg[dotseg].s_dot; ! 428: continue; ! 429: } ! 430: enuf(4, sizeof(RELOC)); /* leave space for next op */ ! 431: if (isbyte = ((op & TTYPE) == TBYTE)) { ! 432: nd = 1; ! 433: data = bget(); ! 434: } else if (isword = ((op & TTYPE) == TWORD)) { ! 435: nd = 2; ! 436: data = iget(); ! 437: } else if ((op & TTYPE) == TLONG) { ! 438: nd = 4; ! 439: data = iget(); ! 440: } else ! 441: cbotch("unrecognized op byte: 0x%x", op); ! 442: if (issym = ((op & TSYM) != 0)) { ! 443: sp = pget(); ! 444: if (isdef(sp) || islabel(sp) || isbss(sp)) ! 445: data += sp->s_value; ! 446: } ! 447: if (ispcr = ((op & TPCR) != 0)) ! 448: data -= dot + nd; ! 449: ! 450: /* Write text. */ ! 451: for (i = 1; i <= nd; i++) { ! 452: *txtp++ = data; ! 453: data >>= 8; ! 454: } ! 455: ! 456: /* Write relocation item if required. */ ! 457: if (issym || ispcr) { ! 458: rp = (RELOC *)relp; ! 459: rp->r_vaddr = dot + seg[dotseg].s_mseek; ! 460: if (issym) { ! 461: if (isdef(sp) || islabel(sp)) ! 462: rp->r_symndx = segindex[sp->s_seg]; ! 463: else ! 464: rp->r_symndx = sp->s_ref; ! 465: } else ! 466: rp->r_symndx = coff_seg; ! 467: if (ispcr) ! 468: rp->r_type = (isbyte) ? R_PCRBYTE ! 469: : (isword) ? R_PCRWORD : R_PCRLONG; ! 470: else ! 471: rp->r_type = (isbyte) ? R_DIR8 ! 472: : (isword) ? R_DIR16 : R_DIR32; ! 473: relp += sizeof(RELOC); ! 474: } ! 475: dot += nd; ! 476: } ! 477: ! 478: /* Flush buffers. */ ! 479: notenuf(); ! 480: ! 481: /* Write COFF header. */ ! 482: coff_hdr.f_magic = C_386_MAGIC; ! 483: coff_hdr.f_nscns = C_NSEGS; ! 484: coff_hdr.f_timdat = time(NULL); ! 485: coff_hdr.f_opthdr = 0; ! 486: coff_hdr.f_flags = F_AR32WR | F_LLNO | L_SYMS; ! 487: oseek(0L); ! 488: owrite((char *)&coff_hdr, sizeof(coff_hdr)); ! 489: ! 490: /* Write section headers. */ ! 491: for (shp = &scn_hdr[C_CODE_SEG]; shp < &scn_hdr[C_NSEGS]; ++shp) ! 492: owrite((char *)shp, sizeof(*shp)); ! 493: } ! 494: ! 495: /* Buffering and output writing routines. */ ! 496: /* ! 497: * Make sure there is enough room in the text and relocation buffers ! 498: * for nt bytes of text and nr bytes of relocation. ! 499: */ ! 500: enuf(nt, nr) ! 501: { ! 502: if (txtp+nt > &txt[NTXT] || relp+nr > &rel[NREL]) ! 503: notenuf(); ! 504: } ! 505: ! 506: /* ! 507: * Flush the text and relocation buffers. ! 508: * Look at the segment table to figure out the exact location ! 509: * of the data in the file, and compute the correct seek ! 510: * address in the image by adding the base address of ! 511: * the text record "txtdot" to that base. ! 512: */ ! 513: notenuf() ! 514: { ! 515: register int n; ! 516: ! 517: if ((n = txtp-txt) != 0) { ! 518: dbprintf(("notenuf: %d text bytes\n", n)); ! 519: dbprintf(("seek to txtdot=%d + seg[%d].s_dseek=%ld\n", txtdot, dotseg, seg[dotseg].s_dseek)); ! 520: oseek(txtdot + seg[dotseg].s_dseek); ! 521: owrite(txt, n); ! 522: if ((n = relp-rel) != 0) { ! 523: dbprintf(("notenuf: %d reloc bytes\n", n)); ! 524: dbprintf(("seek to reldot[%d]=%d + relptr=%ld\n", coff_seg, reldot[coff_seg], scn_hdr[coff_seg].s_relptr)); ! 525: oseek(reldot[coff_seg] + scn_hdr[coff_seg].s_relptr); ! 526: owrite(rel, n); ! 527: reldot[coff_seg] += n; ! 528: relp = rel; ! 529: } ! 530: } ! 531: txtp = txt; ! 532: txtdot = dot; ! 533: } ! 534: ! 535: /* ! 536: * Seek output file, checking for seek error. ! 537: */ ! 538: oseek(l) long l; ! 539: { ! 540: if (fseek(ofp, l, SEEK_SET) == -1L) ! 541: cfatal("seek to %ld failed", l); ! 542: } ! 543: ! 544: /* ! 545: * Write a block of n bytes from p to the output file, ! 546: * checking for write errors. ! 547: */ ! 548: owrite(p, n) char *p; ! 549: { ! 550: if (fwrite(p, sizeof(char), n, ofp) != n) ! 551: cfatal("output write error"); ! 552: } ! 553: ! 554: /* end of n2/i386/outcoff.c */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.