macho: Improve macho_calculate_sizes
[nasm.git] / output / outas86.c
blob3079bc8245a1a2dba95c7f77877735cb6efba334
1 /* ----------------------------------------------------------------------- *
2 *
3 * Copyright 1996-2013 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>
46 #include "nasm.h"
47 #include "nasmlib.h"
48 #include "saa.h"
49 #include "raa.h"
50 #include "outform.h"
51 #include "outlib.h"
53 #ifdef OF_AS86
55 struct Piece {
56 struct Piece *next;
57 int type; /* 0 = absolute, 1 = seg, 2 = sym */
58 int32_t offset; /* relative offset */
59 int number; /* symbol/segment number (4=bss) */
60 int32_t bytes; /* size of reloc or of absolute data */
61 bool relative; /* relative address? */
64 struct Symbol {
65 int32_t strpos; /* string table position of name */
66 int flags; /* symbol flags */
67 int segment; /* 4=bss at this point */
68 int32_t value; /* address, or COMMON variable size */
72 * Section IDs - used in Piece.number and Symbol.segment.
74 #define SECT_TEXT 0 /* text section */
75 #define SECT_DATA 3 /* data section */
76 #define SECT_BSS 4 /* bss section */
79 * Flags used in Symbol.flags.
81 #define SYM_ENTRY (1<<8)
82 #define SYM_EXPORT (1<<7)
83 #define SYM_IMPORT (1<<6)
84 #define SYM_ABSOLUTE (1<<4)
86 struct Section {
87 struct SAA *data;
88 uint32_t datalen, size, len;
89 int32_t index;
90 struct Piece *head, *last, **tail;
93 static char as86_module[FILENAME_MAX];
95 static struct Section stext, sdata;
96 static uint32_t bsslen;
97 static int32_t bssindex;
99 static struct SAA *syms;
100 static uint32_t nsyms;
102 static struct RAA *bsym;
104 static struct SAA *strs;
105 static uint32_t strslen;
107 static int as86_reloc_size;
109 static void as86_write(void);
110 static void as86_write_section(struct Section *, int);
111 static int as86_add_string(char *name);
112 static void as86_sect_write(struct Section *, const uint8_t *,
113 uint32_t);
115 static void as86_init(void)
117 stext.data = saa_init(1L);
118 stext.datalen = 0L;
119 stext.head = stext.last = NULL;
120 stext.tail = &stext.head;
121 sdata.data = saa_init(1L);
122 sdata.datalen = 0L;
123 sdata.head = sdata.last = NULL;
124 sdata.tail = &sdata.head;
125 bsslen =
126 stext.len = stext.datalen = stext.size =
127 sdata.len = sdata.datalen = sdata.size = 0;
128 stext.index = seg_alloc();
129 sdata.index = seg_alloc();
130 bssindex = seg_alloc();
131 syms = saa_init((int32_t)sizeof(struct Symbol));
132 nsyms = 0;
133 bsym = raa_init();
134 strs = saa_init(1L);
135 strslen = 0;
137 as86_add_string(as86_module);
140 static void as86_cleanup(void)
142 struct Piece *p;
144 as86_write();
145 saa_free(stext.data);
146 while (stext.head) {
147 p = stext.head;
148 stext.head = stext.head->next;
149 nasm_free(p);
151 saa_free(sdata.data);
152 while (sdata.head) {
153 p = sdata.head;
154 sdata.head = sdata.head->next;
155 nasm_free(p);
157 saa_free(syms);
158 raa_free(bsym);
159 saa_free(strs);
162 static int32_t as86_section_names(char *name, int pass, int *bits)
165 (void)pass;
168 * Default is 16 bits.
170 if (!name) {
171 *bits = 16;
172 return stext.index;
175 if (!strcmp(name, ".text"))
176 return stext.index;
177 else if (!strcmp(name, ".data"))
178 return sdata.index;
179 else if (!strcmp(name, ".bss"))
180 return bssindex;
181 else
182 return NO_SEG;
185 static int as86_add_string(char *name)
187 int pos = strslen;
188 int length = strlen(name);
190 saa_wbytes(strs, name, (int32_t)(length + 1));
191 strslen += 1 + length;
193 return pos;
196 static void as86_deflabel(char *name, int32_t segment, int64_t offset,
197 int is_global, char *special)
199 bool is_start = false;
200 struct Symbol *sym;
202 if (special)
203 nasm_error(ERR_NONFATAL, "as86 format does not support any"
204 " special symbol types");
207 if (name[0] == '.' && name[1] == '.' && name[2] != '@') {
208 if (strcmp(name, "..start")) {
209 nasm_error(ERR_NONFATAL, "unrecognised special symbol `%s'", name);
210 return;
211 } else {
212 is_start = true;
216 sym = saa_wstruct(syms);
218 sym->strpos = as86_add_string(name);
219 sym->flags = 0;
221 if (is_start)
222 sym->flags = SYM_ENTRY;
224 if (segment == NO_SEG)
225 sym->flags |= SYM_ABSOLUTE, sym->segment = 0;
226 else if (segment == stext.index)
227 sym->segment = SECT_TEXT;
228 else if (segment == sdata.index)
229 sym->segment = SECT_DATA;
230 else if (segment == bssindex)
231 sym->segment = SECT_BSS;
232 else {
233 sym->flags |= SYM_IMPORT;
234 sym->segment = 15;
237 if (is_global == 2)
238 sym->segment = 3; /* already have IMPORT */
240 if (is_global && !(sym->flags & SYM_IMPORT))
241 sym->flags |= SYM_EXPORT;
243 sym->value = offset;
246 * define the references from external-symbol segment numbers
247 * to these symbol records.
249 if (segment != NO_SEG && segment != stext.index &&
250 segment != sdata.index && segment != bssindex)
251 bsym = raa_write(bsym, segment, nsyms);
253 nsyms++;
256 static void as86_add_piece(struct Section *sect, int type, int32_t offset,
257 int32_t segment, int32_t bytes, int relative)
259 struct Piece *p;
261 sect->len += bytes;
263 if (type == 0 && sect->last && sect->last->type == 0) {
264 sect->last->bytes += bytes;
265 return;
268 p = sect->last = *sect->tail = nasm_malloc(sizeof(struct Piece));
269 sect->tail = &p->next;
270 p->next = NULL;
272 p->type = type;
273 p->offset = offset;
274 p->bytes = bytes;
275 p->relative = relative;
277 if (type == 1 && segment == stext.index)
278 p->number = SECT_TEXT;
279 else if (type == 1 && segment == sdata.index)
280 p->number = SECT_DATA;
281 else if (type == 1 && segment == bssindex)
282 p->number = SECT_BSS;
283 else if (type == 1)
284 p->number = raa_read(bsym, segment), p->type = 2;
287 static void as86_out(int32_t segto, const void *data,
288 enum out_type type, uint64_t size,
289 int32_t segment, int32_t wrt)
291 struct Section *s;
292 int32_t offset;
293 uint8_t mydata[4], *p;
295 if (wrt != NO_SEG) {
296 wrt = NO_SEG; /* continue to do _something_ */
297 nasm_error(ERR_NONFATAL, "WRT not supported by as86 output format");
301 * handle absolute-assembly (structure definitions)
303 if (segto == NO_SEG) {
304 if (type != OUT_RESERVE)
305 nasm_error(ERR_NONFATAL, "attempt to assemble code in [ABSOLUTE]"
306 " space");
307 return;
310 if (segto == stext.index)
311 s = &stext;
312 else if (segto == sdata.index)
313 s = &sdata;
314 else if (segto == bssindex)
315 s = NULL;
316 else {
317 nasm_error(ERR_WARNING, "attempt to assemble code in"
318 " segment %d: defaulting to `.text'", segto);
319 s = &stext;
322 if (!s && type != OUT_RESERVE) {
323 nasm_error(ERR_WARNING, "attempt to initialize memory in the"
324 " BSS section: ignored");
325 bsslen += realsize(type, size);
326 return;
329 memset(mydata, 0, sizeof(mydata));
331 if (type == OUT_RESERVE) {
332 if (s) {
333 nasm_error(ERR_WARNING, "uninitialized space declared in"
334 " %s section: zeroing",
335 (segto == stext.index ? "code" : "data"));
336 as86_sect_write(s, NULL, size);
337 as86_add_piece(s, 0, 0L, 0L, size, 0);
338 } else
339 bsslen += size;
340 } else if (type == OUT_RAWDATA) {
341 if (segment != NO_SEG)
342 nasm_panic(0, "OUT_RAWDATA with other than NO_SEG");
343 as86_sect_write(s, data, size);
344 as86_add_piece(s, 0, 0L, 0L, size, 0);
345 } else if (type == OUT_ADDRESS) {
346 int asize = abs((int)size);
347 if (segment != NO_SEG) {
348 if (segment % 2) {
349 nasm_error(ERR_NONFATAL, "as86 format does not support"
350 " segment base references");
351 } else {
352 offset = *(int64_t *)data;
353 as86_add_piece(s, 1, offset, segment, asize, 0);
355 } else {
356 p = mydata;
357 WRITELONG(p, *(int64_t *)data);
358 as86_sect_write(s, data, asize);
359 as86_add_piece(s, 0, 0L, 0L, asize, 0);
361 } else if (type == OUT_REL2ADR) {
362 if (segment == segto)
363 nasm_panic(0, "intra-segment OUT_REL2ADR");
364 if (segment != NO_SEG) {
365 if (segment % 2) {
366 nasm_error(ERR_NONFATAL, "as86 format does not support"
367 " segment base references");
368 } else {
369 offset = *(int64_t *)data;
370 as86_add_piece(s, 1, offset - size + 2, segment, 2L,
374 } else if (type == OUT_REL4ADR) {
375 if (segment == segto)
376 nasm_panic(0, "intra-segment OUT_REL4ADR");
377 if (segment != NO_SEG) {
378 if (segment % 2) {
379 nasm_error(ERR_NONFATAL, "as86 format does not support"
380 " segment base references");
381 } else {
382 offset = *(int64_t *)data;
383 as86_add_piece(s, 1, offset - size + 4, segment, 4L,
390 static void as86_write(void)
392 uint32_t i;
393 int32_t symlen, seglen, segsize;
396 * First, go through the symbol records working out how big
397 * each will be. Also fix up BSS references at this time, and
398 * set the flags words up completely.
400 symlen = 0;
401 saa_rewind(syms);
402 for (i = 0; i < nsyms; i++) {
403 struct Symbol *sym = saa_rstruct(syms);
404 if (sym->segment == SECT_BSS)
405 sym->segment = SECT_DATA, sym->value += sdata.len;
406 sym->flags |= sym->segment;
407 if (sym->value == 0)
408 sym->flags |= 0 << 14, symlen += 4;
409 else if (sym->value >= 0 && sym->value <= 255)
410 sym->flags |= 1 << 14, symlen += 5;
411 else if (sym->value >= 0 && sym->value <= 65535L)
412 sym->flags |= 2 << 14, symlen += 6;
413 else
414 sym->flags |= 3 << 14, symlen += 8;
418 * Now do the same for the segments, and get the segment size
419 * descriptor word at the same time.
421 seglen = segsize = 0;
422 if ((uint32_t)stext.len > 65535L)
423 segsize |= 0x03000000L, seglen += 4;
424 else
425 segsize |= 0x02000000L, seglen += 2;
426 if ((uint32_t)sdata.len > 65535L)
427 segsize |= 0xC0000000L, seglen += 4;
428 else
429 segsize |= 0x80000000L, seglen += 2;
432 * Emit the as86 header.
434 fwriteint32_t(0x000186A3L, ofile);
435 fputc(0x2A, ofile);
436 fwriteint32_t(27 + symlen + seglen + strslen, ofile); /* header length */
437 fwriteint32_t(stext.len + sdata.len + bsslen, ofile);
438 fwriteint16_t(strslen, ofile);
439 fwriteint16_t(0, ofile); /* class = revision = 0 */
440 fwriteint32_t(0x55555555L, ofile); /* segment max sizes: always this */
441 fwriteint32_t(segsize, ofile); /* segment size descriptors */
442 if (segsize & 0x01000000L)
443 fwriteint32_t(stext.len, ofile);
444 else
445 fwriteint16_t(stext.len, ofile);
446 if (segsize & 0x40000000L)
447 fwriteint32_t(sdata.len + bsslen, ofile);
448 else
449 fwriteint16_t(sdata.len + bsslen, ofile);
450 fwriteint16_t(nsyms, ofile);
453 * Write the symbol table.
455 saa_rewind(syms);
456 for (i = 0; i < nsyms; i++) {
457 struct Symbol *sym = saa_rstruct(syms);
458 fwriteint16_t(sym->strpos, ofile);
459 fwriteint16_t(sym->flags, ofile);
460 switch (sym->flags & (3 << 14)) {
461 case 0 << 14:
462 break;
463 case 1 << 14:
464 fputc(sym->value, ofile);
465 break;
466 case 2 << 14:
467 fwriteint16_t(sym->value, ofile);
468 break;
469 case 3 << 14:
470 fwriteint32_t(sym->value, ofile);
471 break;
476 * Write out the string table.
478 saa_fpwrite(strs, ofile);
481 * Write the program text.
483 as86_reloc_size = -1;
484 as86_write_section(&stext, SECT_TEXT);
485 as86_write_section(&sdata, SECT_DATA);
487 * Append the BSS section to the .data section
489 if (bsslen > 65535L) {
490 fputc(0x13, ofile);
491 fwriteint32_t(bsslen, ofile);
492 } else if (bsslen > 255) {
493 fputc(0x12, ofile);
494 fwriteint16_t(bsslen, ofile);
495 } else if (bsslen) {
496 fputc(0x11, ofile);
497 fputc(bsslen, ofile);
500 fputc(0, ofile); /* termination */
503 static void as86_set_rsize(int size)
505 if (as86_reloc_size != size) {
506 switch (as86_reloc_size = size) {
507 case 1:
508 fputc(0x01, ofile);
509 break;
510 case 2:
511 fputc(0x02, ofile);
512 break;
513 case 4:
514 fputc(0x03, ofile);
515 break;
516 default:
517 nasm_panic(0, "bizarre relocation size %d", size);
518 break;
523 static void as86_write_section(struct Section *sect, int index)
525 struct Piece *p;
526 uint32_t s;
527 int32_t length;
529 fputc(0x20 + index, ofile); /* select the right section */
531 saa_rewind(sect->data);
533 for (p = sect->head; p; p = p->next)
534 switch (p->type) {
535 case 0:
537 * Absolute data. Emit it in chunks of at most 64
538 * bytes.
540 length = p->bytes;
541 do {
542 char buf[64];
543 int32_t tmplen = (length > 64 ? 64 : length);
544 fputc(0x40 | (tmplen & 0x3F), ofile);
545 saa_rnbytes(sect->data, buf, tmplen);
546 nasm_write(buf, tmplen, ofile);
547 length -= tmplen;
548 } while (length > 0);
549 break;
550 case 1:
552 * A segment-type relocation. First fix up the BSS.
554 if (p->number == SECT_BSS)
555 p->number = SECT_DATA, p->offset += sdata.len;
556 as86_set_rsize(p->bytes);
557 fputc(0x80 | (p->relative ? 0x20 : 0) | p->number, ofile);
558 if (as86_reloc_size == 2)
559 fwriteint16_t(p->offset, ofile);
560 else
561 fwriteint32_t(p->offset, ofile);
562 break;
563 case 2:
565 * A symbol-type relocation.
567 as86_set_rsize(p->bytes);
568 s = p->offset;
569 if (s > 65535L)
570 s = 3;
571 else if (s > 255)
572 s = 2;
573 else if (s > 0)
574 s = 1;
575 else
576 s = 0;
577 fputc(0xC0 |
578 (p->relative ? 0x20 : 0) |
579 (p->number > 255 ? 0x04 : 0) | s, ofile);
580 if (p->number > 255)
581 fwriteint16_t(p->number, ofile);
582 else
583 fputc(p->number, ofile);
584 switch ((int)s) {
585 case 0:
586 break;
587 case 1:
588 fputc(p->offset, ofile);
589 break;
590 case 2:
591 fwriteint16_t(p->offset, ofile);
592 break;
593 case 3:
594 fwriteint32_t(p->offset, ofile);
595 break;
597 break;
601 static void as86_sect_write(struct Section *sect,
602 const uint8_t *data, uint32_t len)
604 saa_wbytes(sect->data, data, len);
605 sect->datalen += len;
608 static int32_t as86_segbase(int32_t segment)
610 return segment;
613 static void as86_filename(char *inname, char *outname)
615 char *p;
617 if ((p = strrchr(inname, '.')) != NULL) {
618 strncpy(as86_module, inname, p - inname);
619 as86_module[p - inname] = '\0';
620 } else
621 strcpy(as86_module, inname);
623 standard_extension(inname, outname, ".o");
626 extern macros_t as86_stdmac[];
628 const struct ofmt of_as86 = {
629 "Linux as86 (bin86 version 0.3) object files",
630 "as86",
633 null_debug_arr,
634 &null_debug_form,
635 as86_stdmac,
636 as86_init,
637 null_setinfo,
638 nasm_do_legacy_output,
639 as86_out,
640 as86_deflabel,
641 as86_section_names,
642 null_sectalign,
643 as86_segbase,
644 null_directive,
645 as86_filename,
646 as86_cleanup
649 #endif /* OF_AS86 */