doc: fix formatting of the bin multisection header
[nasm/sigaren-mirror.git] / output / outas86.c
blob2fa4efcae9c984534d34d72cd6cb5d55fafba562
1 /* ----------------------------------------------------------------------- *
2 *
3 * Copyright 1996-2009 The NASM Authors - All Rights Reserved
4 * See the file AUTHORS included with the NASM distribution for
5 * the specific copyright holders.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following
9 * conditions are met:
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
19 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
20 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 * ----------------------------------------------------------------------- */
34 /*
35 * outas86.c output routines for the Netwide Assembler to produce
36 * Linux as86 (bin86-0.3) object files
39 #include "compiler.h"
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <ctype.h>
45 #include <inttypes.h>
47 #include "nasm.h"
48 #include "nasmlib.h"
49 #include "saa.h"
50 #include "raa.h"
51 #include "output/outform.h"
52 #include "output/outlib.h"
54 #ifdef OF_AS86
56 struct Piece {
57 struct Piece *next;
58 int type; /* 0 = absolute, 1 = seg, 2 = sym */
59 int32_t offset; /* relative offset */
60 int number; /* symbol/segment number (4=bss) */
61 int32_t bytes; /* size of reloc or of absolute data */
62 bool relative; /* relative address? */
65 struct Symbol {
66 int32_t strpos; /* string table position of name */
67 int flags; /* symbol flags */
68 int segment; /* 4=bss at this point */
69 int32_t value; /* address, or COMMON variable size */
73 * Section IDs - used in Piece.number and Symbol.segment.
75 #define SECT_TEXT 0 /* text section */
76 #define SECT_DATA 3 /* data section */
77 #define SECT_BSS 4 /* bss section */
80 * Flags used in Symbol.flags.
82 #define SYM_ENTRY (1<<8)
83 #define SYM_EXPORT (1<<7)
84 #define SYM_IMPORT (1<<6)
85 #define SYM_ABSOLUTE (1<<4)
87 struct Section {
88 struct SAA *data;
89 uint32_t datalen, size, len;
90 int32_t index;
91 struct Piece *head, *last, **tail;
94 static char as86_module[FILENAME_MAX];
96 static struct Section stext, sdata;
97 static uint32_t bsslen;
98 static int32_t bssindex;
100 static struct SAA *syms;
101 static uint32_t nsyms;
103 static struct RAA *bsym;
105 static struct SAA *strs;
106 static uint32_t strslen;
108 static int as86_reloc_size;
110 static FILE *as86fp;
111 static efunc error;
113 static void as86_write(void);
114 static void as86_write_section(struct Section *, int);
115 static int as86_add_string(char *name);
116 static void as86_sect_write(struct Section *, const uint8_t *,
117 uint32_t);
119 static void as86_init(FILE * fp, efunc errfunc, ldfunc ldef, evalfunc eval)
121 as86fp = fp;
122 error = errfunc;
123 (void)ldef; /* placate optimisers */
124 (void)eval;
125 stext.data = saa_init(1L);
126 stext.datalen = 0L;
127 stext.head = stext.last = NULL;
128 stext.tail = &stext.head;
129 sdata.data = saa_init(1L);
130 sdata.datalen = 0L;
131 sdata.head = sdata.last = NULL;
132 sdata.tail = &sdata.head;
133 bsslen =
134 stext.len = stext.datalen = stext.size =
135 sdata.len = sdata.datalen = sdata.size = 0;
136 stext.index = seg_alloc();
137 sdata.index = seg_alloc();
138 bssindex = seg_alloc();
139 syms = saa_init((int32_t)sizeof(struct Symbol));
140 nsyms = 0;
141 bsym = raa_init();
142 strs = saa_init(1L);
143 strslen = 0;
145 as86_add_string(as86_module);
148 static void as86_cleanup(int debuginfo)
150 struct Piece *p;
152 (void)debuginfo;
154 as86_write();
155 fclose(as86fp);
156 saa_free(stext.data);
157 while (stext.head) {
158 p = stext.head;
159 stext.head = stext.head->next;
160 nasm_free(p);
162 saa_free(sdata.data);
163 while (sdata.head) {
164 p = sdata.head;
165 sdata.head = sdata.head->next;
166 nasm_free(p);
168 saa_free(syms);
169 raa_free(bsym);
170 saa_free(strs);
173 static int32_t as86_section_names(char *name, int pass, int *bits)
176 (void)pass;
179 * Default is 16 bits.
181 if (!name)
182 *bits = 16;
184 if (!name)
185 return stext.index;
187 if (!strcmp(name, ".text"))
188 return stext.index;
189 else if (!strcmp(name, ".data"))
190 return sdata.index;
191 else if (!strcmp(name, ".bss"))
192 return bssindex;
193 else
194 return NO_SEG;
197 static int as86_add_string(char *name)
199 int pos = strslen;
200 int length = strlen(name);
202 saa_wbytes(strs, name, (int32_t)(length + 1));
203 strslen += 1 + length;
205 return pos;
208 static void as86_deflabel(char *name, int32_t segment, int64_t offset,
209 int is_global, char *special)
211 bool is_start = false;
212 struct Symbol *sym;
214 if (special)
215 error(ERR_NONFATAL, "as86 format does not support any"
216 " special symbol types");
219 if (name[0] == '.' && name[1] == '.' && name[2] != '@') {
220 if (strcmp(name, "..start")) {
221 error(ERR_NONFATAL, "unrecognised special symbol `%s'", name);
222 return;
223 } else {
224 is_start = true;
228 sym = saa_wstruct(syms);
230 sym->strpos = as86_add_string(name);
231 sym->flags = 0;
233 if (is_start)
234 sym->flags = SYM_ENTRY;
236 if (segment == NO_SEG)
237 sym->flags |= SYM_ABSOLUTE, sym->segment = 0;
238 else if (segment == stext.index)
239 sym->segment = SECT_TEXT;
240 else if (segment == sdata.index)
241 sym->segment = SECT_DATA;
242 else if (segment == bssindex)
243 sym->segment = SECT_BSS;
244 else {
245 sym->flags |= SYM_IMPORT;
246 sym->segment = 15;
249 if (is_global == 2)
250 sym->segment = 3; /* already have IMPORT */
252 if (is_global && !(sym->flags & SYM_IMPORT))
253 sym->flags |= SYM_EXPORT;
255 sym->value = offset;
258 * define the references from external-symbol segment numbers
259 * to these symbol records.
261 if (segment != NO_SEG && segment != stext.index &&
262 segment != sdata.index && segment != bssindex)
263 bsym = raa_write(bsym, segment, nsyms);
265 nsyms++;
268 static void as86_add_piece(struct Section *sect, int type, int32_t offset,
269 int32_t segment, int32_t bytes, int relative)
271 struct Piece *p;
273 sect->len += bytes;
275 if (type == 0 && sect->last && sect->last->type == 0) {
276 sect->last->bytes += bytes;
277 return;
280 p = sect->last = *sect->tail = nasm_malloc(sizeof(struct Piece));
281 sect->tail = &p->next;
282 p->next = NULL;
284 p->type = type;
285 p->offset = offset;
286 p->bytes = bytes;
287 p->relative = relative;
289 if (type == 1 && segment == stext.index)
290 p->number = SECT_TEXT;
291 else if (type == 1 && segment == sdata.index)
292 p->number = SECT_DATA;
293 else if (type == 1 && segment == bssindex)
294 p->number = SECT_BSS;
295 else if (type == 1)
296 p->number = raa_read(bsym, segment), p->type = 2;
299 static void as86_out(int32_t segto, const void *data,
300 enum out_type type, uint64_t size,
301 int32_t segment, int32_t wrt)
303 struct Section *s;
304 int32_t offset;
305 uint8_t mydata[4], *p;
307 if (wrt != NO_SEG) {
308 wrt = NO_SEG; /* continue to do _something_ */
309 error(ERR_NONFATAL, "WRT not supported by as86 output format");
313 * handle absolute-assembly (structure definitions)
315 if (segto == NO_SEG) {
316 if (type != OUT_RESERVE)
317 error(ERR_NONFATAL, "attempt to assemble code in [ABSOLUTE]"
318 " space");
319 return;
322 if (segto == stext.index)
323 s = &stext;
324 else if (segto == sdata.index)
325 s = &sdata;
326 else if (segto == bssindex)
327 s = NULL;
328 else {
329 error(ERR_WARNING, "attempt to assemble code in"
330 " segment %d: defaulting to `.text'", segto);
331 s = &stext;
334 if (!s && type != OUT_RESERVE) {
335 error(ERR_WARNING, "attempt to initialize memory in the"
336 " BSS section: ignored");
337 bsslen += realsize(type, size);
338 return;
341 if (type == OUT_RESERVE) {
342 if (s) {
343 error(ERR_WARNING, "uninitialized space declared in"
344 " %s section: zeroing",
345 (segto == stext.index ? "code" : "data"));
346 as86_sect_write(s, NULL, size);
347 as86_add_piece(s, 0, 0L, 0L, size, 0);
348 } else
349 bsslen += size;
350 } else if (type == OUT_RAWDATA) {
351 if (segment != NO_SEG)
352 error(ERR_PANIC, "OUT_RAWDATA with other than NO_SEG");
353 as86_sect_write(s, data, size);
354 as86_add_piece(s, 0, 0L, 0L, size, 0);
355 } else if (type == OUT_ADDRESS) {
356 if (segment != NO_SEG) {
357 if (segment % 2) {
358 error(ERR_NONFATAL, "as86 format does not support"
359 " segment base references");
360 } else {
361 offset = *(int64_t *)data;
362 as86_add_piece(s, 1, offset, segment, size, 0);
364 } else {
365 p = mydata;
366 WRITELONG(p, *(int64_t *)data);
367 as86_sect_write(s, data, size);
368 as86_add_piece(s, 0, 0L, 0L, size, 0);
370 } else if (type == OUT_REL2ADR) {
371 if (segment == segto)
372 error(ERR_PANIC, "intra-segment OUT_REL2ADR");
373 if (segment != NO_SEG) {
374 if (segment % 2) {
375 error(ERR_NONFATAL, "as86 format does not support"
376 " segment base references");
377 } else {
378 offset = *(int64_t *)data;
379 as86_add_piece(s, 1, offset - size + 2, segment, 2L,
383 } else if (type == OUT_REL4ADR) {
384 if (segment == segto)
385 error(ERR_PANIC, "intra-segment OUT_REL4ADR");
386 if (segment != NO_SEG) {
387 if (segment % 2) {
388 error(ERR_NONFATAL, "as86 format does not support"
389 " segment base references");
390 } else {
391 offset = *(int64_t *)data;
392 as86_add_piece(s, 1, offset - size + 4, segment, 4L,
399 static void as86_write(void)
401 uint32_t i;
402 int32_t symlen, seglen, segsize;
405 * First, go through the symbol records working out how big
406 * each will be. Also fix up BSS references at this time, and
407 * set the flags words up completely.
409 symlen = 0;
410 saa_rewind(syms);
411 for (i = 0; i < nsyms; i++) {
412 struct Symbol *sym = saa_rstruct(syms);
413 if (sym->segment == SECT_BSS)
414 sym->segment = SECT_DATA, sym->value += sdata.len;
415 sym->flags |= sym->segment;
416 if (sym->value == 0)
417 sym->flags |= 0 << 14, symlen += 4;
418 else if (sym->value >= 0 && sym->value <= 255)
419 sym->flags |= 1 << 14, symlen += 5;
420 else if (sym->value >= 0 && sym->value <= 65535L)
421 sym->flags |= 2 << 14, symlen += 6;
422 else
423 sym->flags |= 3 << 14, symlen += 8;
427 * Now do the same for the segments, and get the segment size
428 * descriptor word at the same time.
430 seglen = segsize = 0;
431 if ((uint32_t)stext.len > 65535L)
432 segsize |= 0x03000000L, seglen += 4;
433 else
434 segsize |= 0x02000000L, seglen += 2;
435 if ((uint32_t)sdata.len > 65535L)
436 segsize |= 0xC0000000L, seglen += 4;
437 else
438 segsize |= 0x80000000L, seglen += 2;
441 * Emit the as86 header.
443 fwriteint32_t(0x000186A3L, as86fp);
444 fputc(0x2A, as86fp);
445 fwriteint32_t(27 + symlen + seglen + strslen, as86fp); /* header length */
446 fwriteint32_t(stext.len + sdata.len + bsslen, as86fp);
447 fwriteint16_t(strslen, as86fp);
448 fwriteint16_t(0, as86fp); /* class = revision = 0 */
449 fwriteint32_t(0x55555555L, as86fp); /* segment max sizes: always this */
450 fwriteint32_t(segsize, as86fp); /* segment size descriptors */
451 if (segsize & 0x01000000L)
452 fwriteint32_t(stext.len, as86fp);
453 else
454 fwriteint16_t(stext.len, as86fp);
455 if (segsize & 0x40000000L)
456 fwriteint32_t(sdata.len + bsslen, as86fp);
457 else
458 fwriteint16_t(sdata.len + bsslen, as86fp);
459 fwriteint16_t(nsyms, as86fp);
462 * Write the symbol table.
464 saa_rewind(syms);
465 for (i = 0; i < nsyms; i++) {
466 struct Symbol *sym = saa_rstruct(syms);
467 fwriteint16_t(sym->strpos, as86fp);
468 fwriteint16_t(sym->flags, as86fp);
469 switch (sym->flags & (3 << 14)) {
470 case 0 << 14:
471 break;
472 case 1 << 14:
473 fputc(sym->value, as86fp);
474 break;
475 case 2 << 14:
476 fwriteint16_t(sym->value, as86fp);
477 break;
478 case 3 << 14:
479 fwriteint32_t(sym->value, as86fp);
480 break;
485 * Write out the string table.
487 saa_fpwrite(strs, as86fp);
490 * Write the program text.
492 as86_reloc_size = -1;
493 as86_write_section(&stext, SECT_TEXT);
494 as86_write_section(&sdata, SECT_DATA);
496 * Append the BSS section to the .data section
498 if (bsslen > 65535L) {
499 fputc(0x13, as86fp);
500 fwriteint32_t(bsslen, as86fp);
501 } else if (bsslen > 255) {
502 fputc(0x12, as86fp);
503 fwriteint16_t(bsslen, as86fp);
504 } else if (bsslen) {
505 fputc(0x11, as86fp);
506 fputc(bsslen, as86fp);
509 fputc(0, as86fp); /* termination */
512 static void as86_set_rsize(int size)
514 if (as86_reloc_size != size) {
515 switch (as86_reloc_size = size) {
516 case 1:
517 fputc(0x01, as86fp);
518 break;
519 case 2:
520 fputc(0x02, as86fp);
521 break;
522 case 4:
523 fputc(0x03, as86fp);
524 break;
525 default:
526 error(ERR_PANIC, "bizarre relocation size %d", size);
531 static void as86_write_section(struct Section *sect, int index)
533 struct Piece *p;
534 uint32_t s;
535 int32_t length;
537 fputc(0x20 + index, as86fp); /* select the right section */
539 saa_rewind(sect->data);
541 for (p = sect->head; p; p = p->next)
542 switch (p->type) {
543 case 0:
545 * Absolute data. Emit it in chunks of at most 64
546 * bytes.
548 length = p->bytes;
549 do {
550 char buf[64];
551 int32_t tmplen = (length > 64 ? 64 : length);
552 fputc(0x40 | (tmplen & 0x3F), as86fp);
553 saa_rnbytes(sect->data, buf, tmplen);
554 fwrite(buf, 1, tmplen, as86fp);
555 length -= tmplen;
556 } while (length > 0);
557 break;
558 case 1:
560 * A segment-type relocation. First fix up the BSS.
562 if (p->number == SECT_BSS)
563 p->number = SECT_DATA, p->offset += sdata.len;
564 as86_set_rsize(p->bytes);
565 fputc(0x80 | (p->relative ? 0x20 : 0) | p->number, as86fp);
566 if (as86_reloc_size == 2)
567 fwriteint16_t(p->offset, as86fp);
568 else
569 fwriteint32_t(p->offset, as86fp);
570 break;
571 case 2:
573 * A symbol-type relocation.
575 as86_set_rsize(p->bytes);
576 s = p->offset;
577 if (s > 65535L)
578 s = 3;
579 else if (s > 255)
580 s = 2;
581 else if (s > 0)
582 s = 1;
583 else
584 s = 0;
585 fputc(0xC0 |
586 (p->relative ? 0x20 : 0) |
587 (p->number > 255 ? 0x04 : 0) | s, as86fp);
588 if (p->number > 255)
589 fwriteint16_t(p->number, as86fp);
590 else
591 fputc(p->number, as86fp);
592 switch ((int)s) {
593 case 0:
594 break;
595 case 1:
596 fputc(p->offset, as86fp);
597 break;
598 case 2:
599 fwriteint16_t(p->offset, as86fp);
600 break;
601 case 3:
602 fwriteint32_t(p->offset, as86fp);
603 break;
605 break;
609 static void as86_sect_write(struct Section *sect,
610 const uint8_t *data, uint32_t len)
612 saa_wbytes(sect->data, data, len);
613 sect->datalen += len;
616 static int32_t as86_segbase(int32_t segment)
618 return segment;
621 static int as86_directive(char *directive, char *value, int pass)
623 (void)directive;
624 (void)value;
625 (void)pass;
626 return 0;
629 static void as86_filename(char *inname, char *outname, efunc error)
631 char *p;
633 if ((p = strrchr(inname, '.')) != NULL) {
634 strncpy(as86_module, inname, p - inname);
635 as86_module[p - inname] = '\0';
636 } else
637 strcpy(as86_module, inname);
639 standard_extension(inname, outname, ".o", error);
642 extern macros_t as86_stdmac[];
644 static int as86_set_info(enum geninfo type, char **val)
646 (void)type;
647 (void)val;
648 return 0;
650 void as86_linenumber(char *name, int32_t segment, int32_t offset, int is_main,
651 int lineno)
653 (void)name;
654 (void)segment;
655 (void)offset;
656 (void)is_main;
657 (void)lineno;
659 struct ofmt of_as86 = {
660 "Linux as86 (bin86 version 0.3) object files",
661 "as86",
663 null_debug_arr,
664 &null_debug_form,
665 as86_stdmac,
666 as86_init,
667 as86_set_info,
668 as86_out,
669 as86_deflabel,
670 as86_section_names,
671 as86_segbase,
672 as86_directive,
673 as86_filename,
674 as86_cleanup
677 #endif /* OF_AS86 */