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