]>
Commit | Line | Data |
---|---|---|
14c7c974 A |
1 | /* |
2 | * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
4f6e3300 A |
6 | * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights |
7 | * Reserved. This file contains Original Code and/or Modifications of | |
8 | * Original Code as defined in and that are subject to the Apple Public | |
9 | * Source License Version 1.1 (the "License"). You may not use this file | |
10 | * except in compliance with the License. Please obtain a copy of the | |
11 | * License at http://www.apple.com/publicsource and read it before using | |
12 | * this file. | |
14c7c974 A |
13 | * |
14 | * The Original Code and all software distributed under the License are | |
4f6e3300 | 15 | * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER |
14c7c974 A |
16 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
17 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
4f6e3300 A |
18 | * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the |
19 | * License for the specific language governing rights and limitations | |
20 | * under the License. | |
14c7c974 A |
21 | * |
22 | * @APPLE_LICENSE_HEADER_END@ | |
23 | */ | |
24 | /* outcoff.c output routines for the Netwide Assembler to produce | |
25 | * COFF object files (for DJGPP and Win32) | |
26 | * | |
27 | * The Netwide Assembler is copyright (C) 1996 Simon Tatham and | |
28 | * Julian Hall. All rights reserved. The software is | |
29 | * redistributable under the licence given in the file "Licence" | |
30 | * distributed in the NASM archive. | |
31 | */ | |
32 | ||
33 | #include <stdio.h> | |
34 | #include <stdlib.h> | |
35 | #include <string.h> | |
36 | #include <ctype.h> | |
37 | #include <time.h> | |
38 | ||
39 | #include "nasm.h" | |
40 | #include "nasmlib.h" | |
41 | #include "outform.h" | |
42 | ||
43 | #if defined(OF_COFF) || defined(OF_WIN32) | |
44 | ||
45 | /* | |
46 | * Notes on COFF: | |
47 | * | |
48 | * (0) When I say `standard COFF' below, I mean `COFF as output and | |
49 | * used by DJGPP'. I assume DJGPP gets it right. | |
50 | * | |
51 | * (1) Win32 appears to interpret the term `relative relocation' | |
52 | * differently from standard COFF. Standard COFF understands a | |
53 | * relative relocation to mean that during relocation you add the | |
54 | * address of the symbol you're referencing, and subtract the base | |
55 | * address of the section you're in. Win32 COFF, by contrast, seems | |
56 | * to add the address of the symbol and then subtract the address | |
57 | * of THE BYTE AFTER THE RELOCATED DWORD. Hence the two formats are | |
58 | * subtly incompatible. | |
59 | * | |
60 | * (2) Win32 doesn't bother putting any flags in the header flags | |
61 | * field (at offset 0x12 into the file). | |
62 | * | |
63 | * (3) Win32 uses some extra flags into the section header table: | |
64 | * it defines flags 0x80000000 (writable), 0x40000000 (readable) | |
65 | * and 0x20000000 (executable), and uses them in the expected | |
66 | * combinations. It also defines 0x00100000 through 0x00700000 for | |
67 | * section alignments of 1 through 64 bytes. | |
68 | * | |
69 | * (4) Both standard COFF and Win32 COFF seem to use the DWORD | |
70 | * field directly after the section name in the section header | |
71 | * table for something strange: they store what the address of the | |
72 | * section start point _would_ be, if you laid all the sections end | |
73 | * to end starting at zero. Dunno why. Microsoft's documentation | |
74 | * lists this field as "Virtual Size of Section", which doesn't | |
75 | * seem to fit at all. In fact, Win32 even includes non-linked | |
76 | * sections such as .drectve in this calculation. | |
77 | * | |
78 | * (5) Standard COFF does something very strange to common | |
79 | * variables: the relocation point for a common variable is as far | |
80 | * _before_ the variable as its size stretches out _after_ it. So | |
81 | * we must fix up common variable references. Win32 seems to be | |
82 | * sensible on this one. | |
83 | */ | |
84 | ||
85 | /* Flag which version of COFF we are currently outputting. */ | |
86 | static int win32; | |
87 | ||
88 | struct Reloc { | |
89 | struct Reloc *next; | |
90 | long address; /* relative to _start_ of section */ | |
91 | long symbol; /* symbol number */ | |
92 | enum { | |
93 | SECT_SYMBOLS, | |
94 | ABS_SYMBOL, | |
95 | REAL_SYMBOLS | |
96 | } symbase; /* relocation for symbol number :) */ | |
97 | int relative; /* TRUE or FALSE */ | |
98 | }; | |
99 | ||
100 | struct Symbol { | |
101 | char name[9]; | |
102 | long strpos; /* string table position of name */ | |
103 | int section; /* section number where it's defined | |
104 | * - in COFF codes, not NASM codes */ | |
105 | int is_global; /* is it a global symbol or not? */ | |
106 | long value; /* address, or COMMON variable size */ | |
107 | }; | |
108 | ||
109 | static FILE *coffp; | |
110 | static efunc error; | |
111 | static char coff_infile[FILENAME_MAX]; | |
112 | ||
113 | struct Section { | |
114 | struct SAA *data; | |
115 | unsigned long len; | |
116 | int nrelocs; | |
117 | long index; | |
118 | struct Reloc *head, **tail; | |
119 | unsigned long flags; /* section flags */ | |
120 | char name[9]; | |
121 | long pos, relpos; | |
122 | }; | |
123 | ||
124 | #define TEXT_FLAGS (win32 ? 0x60500020L : 0x20L) | |
125 | #define DATA_FLAGS (win32 ? 0xC0300040L : 0x40L) | |
126 | #define BSS_FLAGS (win32 ? 0xC0300080L : 0x80L) | |
127 | #define INFO_FLAGS 0x00100A00L | |
128 | ||
129 | #define SECT_DELTA 32 | |
130 | static struct Section **sects; | |
131 | static int nsects, sectlen; | |
132 | ||
133 | static struct SAA *syms; | |
134 | static unsigned long nsyms; | |
135 | ||
136 | static long def_seg; | |
137 | ||
138 | static int initsym; | |
139 | ||
140 | static struct RAA *bsym, *symval; | |
141 | ||
142 | static struct SAA *strs; | |
143 | static unsigned long strslen; | |
144 | ||
145 | static void coff_gen_init(FILE *, efunc); | |
146 | static void coff_sect_write (struct Section *, unsigned char *, | |
147 | unsigned long); | |
148 | static void coff_write (void); | |
149 | static void coff_section_header (char *, long, long, long, long, int, long); | |
150 | static void coff_write_relocs (struct Section *); | |
151 | static void coff_write_symbols (void); | |
152 | ||
153 | static void coff_win32_init(FILE *fp, efunc errfunc, | |
154 | ldfunc ldef, evalfunc eval) { | |
155 | win32 = TRUE; | |
156 | (void) ldef; /* placate optimisers */ | |
157 | coff_gen_init(fp, errfunc); | |
158 | } | |
159 | ||
160 | static void coff_std_init(FILE *fp, efunc errfunc, | |
161 | ldfunc ldef, evalfunc eval) { | |
162 | win32 = FALSE; | |
163 | (void) ldef; /* placate optimisers */ | |
164 | coff_gen_init(fp, errfunc); | |
165 | } | |
166 | ||
167 | static void coff_gen_init(FILE *fp, efunc errfunc) { | |
168 | coffp = fp; | |
169 | error = errfunc; | |
170 | sects = NULL; | |
171 | nsects = sectlen = 0; | |
172 | syms = saa_init((long)sizeof(struct Symbol)); | |
173 | nsyms = 0; | |
174 | bsym = raa_init(); | |
175 | symval = raa_init(); | |
176 | strs = saa_init(1L); | |
177 | strslen = 0; | |
178 | def_seg = seg_alloc(); | |
179 | } | |
180 | ||
181 | static void coff_cleanup(void) { | |
182 | struct Reloc *r; | |
183 | int i; | |
184 | ||
185 | coff_write(); | |
186 | fclose (coffp); | |
187 | for (i=0; i<nsects; i++) { | |
188 | if (sects[i]->data) | |
189 | saa_free (sects[i]->data); | |
190 | while (sects[i]->head) { | |
191 | r = sects[i]->head; | |
192 | sects[i]->head = sects[i]->head->next; | |
193 | nasm_free (r); | |
194 | } | |
195 | } | |
196 | nasm_free (sects); | |
197 | saa_free (syms); | |
198 | raa_free (bsym); | |
199 | raa_free (symval); | |
200 | saa_free (strs); | |
201 | } | |
202 | ||
203 | static int coff_make_section (char *name, unsigned long flags) { | |
204 | struct Section *s; | |
205 | ||
206 | s = nasm_malloc (sizeof(*s)); | |
207 | ||
208 | if (flags != BSS_FLAGS) | |
209 | s->data = saa_init (1L); | |
210 | else | |
211 | s->data = NULL; | |
212 | s->head = NULL; | |
213 | s->tail = &s->head; | |
214 | s->len = 0; | |
215 | s->nrelocs = 0; | |
216 | if (!strcmp(name, ".text")) | |
217 | s->index = def_seg; | |
218 | else | |
219 | s->index = seg_alloc(); | |
220 | strncpy (s->name, name, 8); | |
221 | s->name[8] = '\0'; | |
222 | s->flags = flags; | |
223 | ||
224 | if (nsects >= sectlen) | |
225 | sects = nasm_realloc (sects, (sectlen += SECT_DELTA)*sizeof(*sects)); | |
226 | sects[nsects++] = s; | |
227 | ||
228 | return nsects-1; | |
229 | } | |
230 | ||
231 | static long coff_section_names (char *name, int pass, int *bits) { | |
232 | char *p; | |
233 | unsigned long flags, align_and = ~0L, align_or = 0L; | |
234 | int i; | |
235 | ||
236 | /* | |
237 | * Default is 32 bits. | |
238 | */ | |
239 | if (!name) | |
240 | *bits = 32; | |
241 | ||
242 | if (!name) | |
243 | return def_seg; | |
244 | ||
245 | p = name; | |
246 | while (*p && !isspace(*p)) p++; | |
247 | if (*p) *p++ = '\0'; | |
248 | if (strlen(name) > 8) { | |
249 | error (ERR_WARNING, "COFF section names limited to 8 characters:" | |
250 | " truncating"); | |
251 | p[8] = '\0'; | |
252 | } | |
253 | flags = 0; | |
254 | ||
255 | while (*p && isspace(*p)) p++; | |
256 | while (*p) { | |
257 | char *q = p; | |
258 | while (*p && !isspace(*p)) p++; | |
259 | if (*p) *p++ = '\0'; | |
260 | while (*p && isspace(*p)) p++; | |
261 | ||
262 | if (!nasm_stricmp(q, "code") || !nasm_stricmp(q, "text")) { | |
263 | flags = TEXT_FLAGS; | |
264 | } else if (!nasm_stricmp(q, "data")) { | |
265 | flags = DATA_FLAGS; | |
266 | } else if (!nasm_stricmp(q, "bss")) { | |
267 | flags = BSS_FLAGS; | |
268 | } else if (!nasm_stricmp(q, "info")) { | |
269 | if (win32) | |
270 | flags = INFO_FLAGS; | |
271 | else { | |
272 | flags = DATA_FLAGS; /* gotta do something */ | |
273 | error (ERR_NONFATAL, "standard COFF does not support" | |
274 | " informational sections"); | |
275 | } | |
276 | } else if (!nasm_strnicmp(q,"align=",6)) { | |
277 | if (!win32) | |
278 | error (ERR_NONFATAL, "standard COFF does not support" | |
279 | " section alignment specification"); | |
280 | else { | |
281 | if (q[6+strspn(q+6,"0123456789")]) | |
282 | error(ERR_NONFATAL, "argument to `align' is not numeric"); | |
283 | else { | |
284 | unsigned int align = atoi(q+6); | |
285 | if (!align || ((align-1) & align)) | |
286 | error(ERR_NONFATAL, "argument to `align' is not a" | |
287 | " power of two"); | |
288 | else if (align > 64) | |
289 | error(ERR_NONFATAL, "Win32 cannot align sections" | |
290 | " to better than 64-byte boundaries"); | |
291 | else { | |
292 | align_and = ~0x00F00000L; | |
293 | align_or = (align == 1 ? 0x00100000L : | |
294 | align == 2 ? 0x00200000L : | |
295 | align == 4 ? 0x00300000L : | |
296 | align == 8 ? 0x00400000L : | |
297 | align == 16 ? 0x00500000L : | |
298 | align == 32 ? 0x00600000L : 0x00700000L); | |
299 | } | |
300 | } | |
301 | } | |
302 | } | |
303 | } | |
304 | ||
305 | for (i=0; i<nsects; i++) | |
306 | if (!strcmp(name, sects[i]->name)) | |
307 | break; | |
308 | if (i == nsects) { | |
309 | if (!flags) { | |
310 | if (!strcmp(name, ".data")) | |
311 | flags = DATA_FLAGS; | |
312 | else if (!strcmp(name, ".bss")) | |
313 | flags = BSS_FLAGS; | |
314 | else | |
315 | flags = TEXT_FLAGS; | |
316 | } | |
317 | i = coff_make_section (name, flags); | |
318 | if (flags) | |
319 | sects[i]->flags = flags; | |
320 | sects[i]->flags &= align_and; | |
321 | sects[i]->flags |= align_or; | |
322 | } else if (pass == 1) { | |
323 | if (flags) | |
324 | error (ERR_WARNING, "section attributes ignored on" | |
325 | " redeclaration of section `%s'", name); | |
326 | } | |
327 | ||
328 | return sects[i]->index; | |
329 | } | |
330 | ||
331 | static void coff_deflabel (char *name, long segment, long offset, | |
332 | int is_global, char *special) { | |
333 | int pos = strslen+4; | |
334 | struct Symbol *sym; | |
335 | ||
336 | if (special) | |
337 | error (ERR_NONFATAL, "binary format does not support any" | |
338 | " special symbol types"); | |
339 | ||
340 | if (name[0] == '.' && name[1] == '.' && name[2] != '@') { | |
341 | error (ERR_NONFATAL, "unrecognised special symbol `%s'", name); | |
342 | return; | |
343 | } | |
344 | ||
345 | if (strlen(name) > 8) { | |
346 | saa_wbytes (strs, name, (long)(1+strlen(name))); | |
347 | strslen += 1+strlen(name); | |
348 | } else | |
349 | pos = -1; | |
350 | ||
351 | sym = saa_wstruct (syms); | |
352 | ||
353 | sym->strpos = pos; | |
354 | if (pos == -1) | |
355 | strcpy (sym->name, name); | |
356 | sym->is_global = !!is_global; | |
357 | if (segment == NO_SEG) | |
358 | sym->section = -1; /* absolute symbol */ | |
359 | else { | |
360 | int i; | |
361 | sym->section = 0; | |
362 | for (i=0; i<nsects; i++) | |
363 | if (segment == sects[i]->index) { | |
364 | sym->section = i+1; | |
365 | break; | |
366 | } | |
367 | if (!sym->section) | |
368 | sym->is_global = TRUE; | |
369 | } | |
370 | if (is_global == 2) | |
371 | sym->value = offset; | |
372 | else | |
373 | sym->value = (sym->section == 0 ? 0 : offset); | |
374 | ||
375 | /* | |
376 | * define the references from external-symbol segment numbers | |
377 | * to these symbol records. | |
378 | */ | |
379 | if (sym->section == 0) | |
380 | bsym = raa_write (bsym, segment, nsyms); | |
381 | ||
382 | if (segment != NO_SEG) | |
383 | symval = raa_write (symval, segment, sym->section ? 0 : sym->value); | |
384 | ||
385 | nsyms++; | |
386 | } | |
387 | ||
388 | static long coff_add_reloc (struct Section *sect, long segment, | |
389 | int relative) { | |
390 | struct Reloc *r; | |
391 | ||
392 | r = *sect->tail = nasm_malloc(sizeof(struct Reloc)); | |
393 | sect->tail = &r->next; | |
394 | r->next = NULL; | |
395 | ||
396 | r->address = sect->len; | |
397 | if (segment == NO_SEG) | |
398 | r->symbol = 0, r->symbase = ABS_SYMBOL; | |
399 | else { | |
400 | int i; | |
401 | r->symbase = REAL_SYMBOLS; | |
402 | for (i=0; i<nsects; i++) | |
403 | if (segment == sects[i]->index) { | |
404 | r->symbol = i*2; | |
405 | r->symbase = SECT_SYMBOLS; | |
406 | break; | |
407 | } | |
408 | if (r->symbase == REAL_SYMBOLS) | |
409 | r->symbol = raa_read (bsym, segment); | |
410 | } | |
411 | r->relative = relative; | |
412 | ||
413 | sect->nrelocs++; | |
414 | ||
415 | /* | |
416 | * Return the fixup for standard COFF common variables. | |
417 | */ | |
418 | if (r->symbase == REAL_SYMBOLS && !win32) | |
419 | return raa_read (symval, segment); | |
420 | else | |
421 | return 0; | |
422 | } | |
423 | ||
424 | static void coff_out (long segto, void *data, unsigned long type, | |
425 | long segment, long wrt) { | |
426 | struct Section *s; | |
427 | long realbytes = type & OUT_SIZMASK; | |
428 | unsigned char mydata[4], *p; | |
429 | int i; | |
430 | ||
431 | if (wrt != NO_SEG) { | |
432 | wrt = NO_SEG; /* continue to do _something_ */ | |
433 | error (ERR_NONFATAL, "WRT not supported by COFF output formats"); | |
434 | } | |
435 | ||
436 | type &= OUT_TYPMASK; | |
437 | ||
438 | /* | |
439 | * handle absolute-assembly (structure definitions) | |
440 | */ | |
441 | if (segto == NO_SEG) { | |
442 | if (type != OUT_RESERVE) | |
443 | error (ERR_NONFATAL, "attempt to assemble code in [ABSOLUTE]" | |
444 | " space"); | |
445 | return; | |
446 | } | |
447 | ||
448 | s = NULL; | |
449 | for (i=0; i<nsects; i++) | |
450 | if (segto == sects[i]->index) { | |
451 | s = sects[i]; | |
452 | break; | |
453 | } | |
454 | if (!s) { | |
455 | int tempint; /* ignored */ | |
456 | if (segto != coff_section_names (".text", 2, &tempint)) | |
457 | error (ERR_PANIC, "strange segment conditions in COFF driver"); | |
458 | else | |
459 | s = sects[nsects-1]; | |
460 | } | |
461 | ||
462 | if (!s->data && type != OUT_RESERVE) { | |
463 | error(ERR_WARNING, "attempt to initialise memory in" | |
464 | " BSS section `%s': ignored", s->name); | |
465 | if (type == OUT_REL2ADR) | |
466 | realbytes = 2; | |
467 | else if (type == OUT_REL4ADR) | |
468 | realbytes = 4; | |
469 | s->len += realbytes; | |
470 | return; | |
471 | } | |
472 | ||
473 | if (type == OUT_RESERVE) { | |
474 | if (s->data) { | |
475 | error(ERR_WARNING, "uninitialised space declared in" | |
476 | " non-BSS section `%s': zeroing", s->name); | |
477 | coff_sect_write (s, NULL, realbytes); | |
478 | } else | |
479 | s->len += realbytes; | |
480 | } else if (type == OUT_RAWDATA) { | |
481 | if (segment != NO_SEG) | |
482 | error(ERR_PANIC, "OUT_RAWDATA with other than NO_SEG"); | |
483 | coff_sect_write (s, data, realbytes); | |
484 | } else if (type == OUT_ADDRESS) { | |
485 | if (realbytes != 4 && (segment != NO_SEG || wrt != NO_SEG)) | |
486 | error(ERR_NONFATAL, "COFF format does not support non-32-bit" | |
487 | " relocations"); | |
488 | else { | |
489 | long fix = 0; | |
490 | if (segment != NO_SEG || wrt != NO_SEG) { | |
491 | if (wrt != NO_SEG) { | |
492 | error(ERR_NONFATAL, "COFF format does not support" | |
493 | " WRT types"); | |
494 | } else if (segment % 2) { | |
495 | error(ERR_NONFATAL, "COFF format does not support" | |
496 | " segment base references"); | |
497 | } else | |
498 | fix = coff_add_reloc (s, segment, FALSE); | |
499 | } | |
500 | p = mydata; | |
501 | WRITELONG (p, *(long *)data + fix); | |
502 | coff_sect_write (s, mydata, realbytes); | |
503 | } | |
504 | } else if (type == OUT_REL2ADR) { | |
505 | error(ERR_NONFATAL, "COFF format does not support 16-bit" | |
506 | " relocations"); | |
507 | } else if (type == OUT_REL4ADR) { | |
508 | if (segment == segto) | |
509 | error(ERR_PANIC, "intra-segment OUT_REL4ADR"); | |
510 | else if (segment == NO_SEG && win32) | |
511 | error(ERR_NONFATAL, "Win32 COFF does not correctly support" | |
512 | " relative references to absolute addresses"); | |
513 | else { | |
514 | long fix = 0; | |
515 | if (segment != NO_SEG && segment % 2) { | |
516 | error(ERR_NONFATAL, "COFF format does not support" | |
517 | " segment base references"); | |
518 | } else | |
519 | fix = coff_add_reloc (s, segment, TRUE); | |
520 | p = mydata; | |
521 | if (win32) { | |
522 | WRITELONG (p, *(long*)data + 4 - realbytes + fix); | |
523 | } else { | |
524 | WRITELONG (p, *(long*)data-(realbytes + s->len) + fix); | |
525 | } | |
526 | coff_sect_write (s, mydata, 4L); | |
527 | } | |
528 | } | |
529 | } | |
530 | ||
531 | static void coff_sect_write (struct Section *sect, | |
532 | unsigned char *data, unsigned long len) { | |
533 | saa_wbytes (sect->data, data, len); | |
534 | sect->len += len; | |
535 | } | |
536 | ||
537 | static int coff_directives (char *directive, char *value, int pass) { | |
538 | return 0; | |
539 | } | |
540 | ||
541 | static void coff_write (void) { | |
542 | long pos, sympos, vsize; | |
543 | int i; | |
544 | ||
545 | /* | |
546 | * Work out how big the file will get. Calculate the start of | |
547 | * the `real' symbols at the same time. | |
548 | */ | |
549 | pos = 0x14 + 0x28 * nsects; | |
550 | initsym = 3; /* two for the file, one absolute */ | |
551 | for (i=0; i<nsects; i++) { | |
552 | if (sects[i]->data) { | |
553 | sects[i]->pos = pos; | |
554 | pos += sects[i]->len; | |
555 | sects[i]->relpos = pos; | |
556 | pos += 10 * sects[i]->nrelocs; | |
557 | } else | |
558 | sects[i]->pos = sects[i]->relpos = 0L; | |
559 | initsym += 2; /* two for each section */ | |
560 | } | |
561 | sympos = pos; | |
562 | ||
563 | /* | |
564 | * Output the COFF header. | |
565 | */ | |
566 | fwriteshort (0x14C, coffp); /* MACHINE_i386 */ | |
567 | fwriteshort (nsects, coffp); /* number of sections */ | |
568 | fwritelong (time(NULL), coffp); /* time stamp */ | |
569 | fwritelong (sympos, coffp); | |
570 | fwritelong (nsyms + initsym, coffp); | |
571 | fwriteshort (0, coffp); /* no optional header */ | |
572 | /* Flags: 32-bit, no line numbers. Win32 doesn't even bother with them. */ | |
573 | fwriteshort (win32 ? 0 : 0x104, coffp); | |
574 | ||
575 | /* | |
576 | * Output the section headers. | |
577 | */ | |
578 | vsize = 0L; | |
579 | for (i=0; i<nsects; i++) { | |
580 | coff_section_header (sects[i]->name, vsize, sects[i]->len, | |
581 | sects[i]->pos, sects[i]->relpos, | |
582 | sects[i]->nrelocs, sects[i]->flags); | |
583 | vsize += sects[i]->len; | |
584 | } | |
585 | ||
586 | /* | |
587 | * Output the sections and their relocations. | |
588 | */ | |
589 | for (i=0; i<nsects; i++) | |
590 | if (sects[i]->data) { | |
591 | saa_fpwrite (sects[i]->data, coffp); | |
592 | coff_write_relocs (sects[i]); | |
593 | } | |
594 | ||
595 | /* | |
596 | * Output the symbol and string tables. | |
597 | */ | |
598 | coff_write_symbols(); | |
599 | fwritelong (strslen+4, coffp); /* length includes length count */ | |
600 | saa_fpwrite (strs, coffp); | |
601 | } | |
602 | ||
603 | static void coff_section_header (char *name, long vsize, | |
604 | long datalen, long datapos, | |
605 | long relpos, int nrelocs, long flags) { | |
606 | char padname[8]; | |
607 | ||
608 | memset (padname, 0, 8); | |
609 | strncpy (padname, name, 8); | |
610 | fwrite (padname, 8, 1, coffp); | |
611 | fwritelong (vsize, coffp); | |
612 | fwritelong (0L, coffp); /* RVA/offset - we ignore */ | |
613 | fwritelong (datalen, coffp); | |
614 | fwritelong (datapos, coffp); | |
615 | fwritelong (relpos, coffp); | |
616 | fwritelong (0L, coffp); /* no line numbers - we don't do 'em */ | |
617 | fwriteshort (nrelocs, coffp); | |
618 | fwriteshort (0, coffp); /* again, no line numbers */ | |
619 | fwritelong (flags, coffp); | |
620 | } | |
621 | ||
622 | static void coff_write_relocs (struct Section *s) { | |
623 | struct Reloc *r; | |
624 | ||
625 | for (r = s->head; r; r = r->next) { | |
626 | fwritelong (r->address, coffp); | |
627 | fwritelong (r->symbol + (r->symbase == REAL_SYMBOLS ? initsym : | |
628 | r->symbase == ABS_SYMBOL ? initsym-1 : | |
629 | r->symbase == SECT_SYMBOLS ? 2 : 0), coffp); | |
630 | /* | |
631 | * Strange: Microsoft's COFF documentation says 0x03 for an | |
632 | * absolute relocation, but both Visual C++ and DJGPP agree | |
633 | * that in fact it's 0x06. I'll use 0x06 until someone | |
634 | * argues. | |
635 | */ | |
636 | fwriteshort (r->relative ? 0x14 : 0x06, coffp); | |
637 | } | |
638 | } | |
639 | ||
640 | static void coff_symbol (char *name, long strpos, long value, | |
641 | int section, int type, int aux) { | |
642 | char padname[8]; | |
643 | ||
644 | if (name) { | |
645 | memset (padname, 0, 8); | |
646 | strncpy (padname, name, 8); | |
647 | fwrite (padname, 8, 1, coffp); | |
648 | } else { | |
649 | fwritelong (0L, coffp); | |
650 | fwritelong (strpos, coffp); | |
651 | } | |
652 | fwritelong (value, coffp); | |
653 | fwriteshort (section, coffp); | |
654 | fwriteshort (0, coffp); | |
655 | fputc (type, coffp); | |
656 | fputc (aux, coffp); | |
657 | } | |
658 | ||
659 | static void coff_write_symbols (void) { | |
660 | char filename[18]; | |
661 | int i; | |
662 | ||
663 | /* | |
664 | * The `.file' record, and the file name auxiliary record. | |
665 | */ | |
666 | coff_symbol (".file", 0L, 0L, -2, 0x67, 1); | |
667 | memset (filename, 0, 18); | |
668 | strncpy (filename, coff_infile, 18); | |
669 | fwrite (filename, 18, 1, coffp); | |
670 | ||
671 | /* | |
672 | * The section records, with their auxiliaries. | |
673 | */ | |
674 | memset (filename, 0, 18); /* useful zeroed buffer */ | |
675 | ||
676 | for (i=0; i<nsects; i++) { | |
677 | coff_symbol (sects[i]->name, 0L, 0L, i+1, 3, 1); | |
678 | fwritelong (sects[i]->len, coffp); | |
679 | fwriteshort (sects[i]->nrelocs, coffp); | |
680 | fwrite (filename, 12, 1, coffp); | |
681 | } | |
682 | ||
683 | /* | |
684 | * The absolute symbol, for relative-to-absolute relocations. | |
685 | */ | |
686 | coff_symbol (".absolut", 0L, 0L, -1, 3, 0); | |
687 | ||
688 | /* | |
689 | * The real symbols. | |
690 | */ | |
691 | saa_rewind (syms); | |
f083c6c3 | 692 | for (i=0; i<(int)nsyms; i++) { |
14c7c974 A |
693 | struct Symbol *sym = saa_rstruct (syms); |
694 | coff_symbol (sym->strpos == -1 ? sym->name : NULL, | |
695 | sym->strpos, sym->value, sym->section, | |
696 | sym->is_global ? 2 : 3, 0); | |
697 | } | |
698 | } | |
699 | ||
700 | static long coff_segbase (long segment) { | |
701 | return segment; | |
702 | } | |
703 | ||
704 | static void coff_std_filename (char *inname, char *outname, efunc error) { | |
705 | strcpy(coff_infile, inname); | |
706 | standard_extension (inname, outname, ".o", error); | |
707 | } | |
708 | ||
709 | static void coff_win32_filename (char *inname, char *outname, efunc error) { | |
710 | strcpy(coff_infile, inname); | |
711 | standard_extension (inname, outname, ".obj", error); | |
712 | } | |
713 | ||
714 | #endif /* defined(OF_COFF) || defined(OF_WIN32) */ | |
715 | ||
716 | static char *coff_stdmac[] = { | |
717 | "%define __SECT__ [section .text]", | |
718 | NULL | |
719 | }; | |
720 | ||
721 | #ifdef OF_COFF | |
722 | ||
723 | struct ofmt of_coff = { | |
724 | "COFF (i386) object files (e.g. DJGPP for DOS)", | |
725 | "coff", | |
726 | coff_stdmac, | |
727 | coff_std_init, | |
728 | coff_out, | |
729 | coff_deflabel, | |
730 | coff_section_names, | |
731 | coff_segbase, | |
732 | coff_directives, | |
733 | coff_std_filename, | |
734 | coff_cleanup | |
735 | }; | |
736 | ||
737 | #endif | |
738 | ||
739 | #ifdef OF_WIN32 | |
740 | ||
741 | struct ofmt of_win32 = { | |
742 | "Microsoft Win32 (i386) object files", | |
743 | "win32", | |
744 | coff_stdmac, | |
745 | coff_win32_init, | |
746 | coff_out, | |
747 | coff_deflabel, | |
748 | coff_section_names, | |
749 | coff_segbase, | |
750 | coff_directives, | |
751 | coff_win32_filename, | |
752 | coff_cleanup | |
753 | }; | |
754 | ||
755 | #endif |