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