| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639 |
- /* ----------------------------------------------------------------------- *
- *
- * Copyright 1996-2017 The NASM Authors - All Rights Reserved
- * See the file AUTHORS included with the NASM distribution for
- * the specific copyright holders.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following
- * conditions are met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials provided
- * with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
- * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
- * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * ----------------------------------------------------------------------- */
- /*
- * outas86.c output routines for the Netwide Assembler to produce
- * Linux as86 (bin86-0.3) object files
- */
- #include "compiler.h"
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <ctype.h>
- #include "nasm.h"
- #include "nasmlib.h"
- #include "error.h"
- #include "saa.h"
- #include "raa.h"
- #include "outform.h"
- #include "outlib.h"
- #ifdef OF_AS86
- struct Piece {
- struct Piece *next;
- int type; /* 0 = absolute, 1 = seg, 2 = sym */
- int32_t offset; /* relative offset */
- int number; /* symbol/segment number (4=bss) */
- int32_t bytes; /* size of reloc or of absolute data */
- bool relative; /* relative address? */
- };
- struct Symbol {
- int32_t strpos; /* string table position of name */
- int flags; /* symbol flags */
- int segment; /* 4=bss at this point */
- int32_t value; /* address, or COMMON variable size */
- };
- /*
- * Section IDs - used in Piece.number and Symbol.segment.
- */
- #define SECT_TEXT 0 /* text section */
- #define SECT_DATA 3 /* data section */
- #define SECT_BSS 4 /* bss section */
- /*
- * Flags used in Symbol.flags.
- */
- #define SYM_ENTRY (1<<8)
- #define SYM_EXPORT (1<<7)
- #define SYM_IMPORT (1<<6)
- #define SYM_ABSOLUTE (1<<4)
- struct Section {
- struct SAA *data;
- uint32_t datalen, size, len;
- int32_t index;
- struct Piece *head, *last, **tail;
- };
- static struct Section stext, sdata;
- static uint32_t bsslen;
- static int32_t bssindex;
- static struct SAA *syms;
- static uint32_t nsyms;
- static struct RAA *bsym;
- static struct SAA *strs;
- static size_t strslen;
- static int as86_reloc_size;
- static void as86_write(void);
- static void as86_write_section(struct Section *, int);
- static size_t as86_add_string(const char *name);
- static void as86_sect_write(struct Section *, const uint8_t *,
- uint32_t);
- static void as86_init(void)
- {
- stext.data = saa_init(1L);
- stext.datalen = 0L;
- stext.head = stext.last = NULL;
- stext.tail = &stext.head;
- sdata.data = saa_init(1L);
- sdata.datalen = 0L;
- sdata.head = sdata.last = NULL;
- sdata.tail = &sdata.head;
- bsslen =
- stext.len = stext.datalen = stext.size =
- sdata.len = sdata.datalen = sdata.size = 0;
- stext.index = seg_alloc();
- sdata.index = seg_alloc();
- bssindex = seg_alloc();
- syms = saa_init((int32_t)sizeof(struct Symbol));
- nsyms = 0;
- bsym = raa_init();
- strs = saa_init(1L);
- strslen = 0;
- /* as86 module name = input file minus extension */
- as86_add_string(filename_set_extension(inname, ""));
- }
- static void as86_cleanup(void)
- {
- struct Piece *p;
- as86_write();
- saa_free(stext.data);
- while (stext.head) {
- p = stext.head;
- stext.head = stext.head->next;
- nasm_free(p);
- }
- saa_free(sdata.data);
- while (sdata.head) {
- p = sdata.head;
- sdata.head = sdata.head->next;
- nasm_free(p);
- }
- saa_free(syms);
- raa_free(bsym);
- saa_free(strs);
- }
- static int32_t as86_section_names(char *name, int pass, int *bits)
- {
- (void)pass;
- /*
- * Default is 16 bits.
- */
- if (!name) {
- *bits = 16;
- return stext.index;
- }
- if (!strcmp(name, ".text"))
- return stext.index;
- else if (!strcmp(name, ".data"))
- return sdata.index;
- else if (!strcmp(name, ".bss"))
- return bssindex;
- else
- return NO_SEG;
- }
- static size_t as86_add_string(const char *name)
- {
- size_t pos = strslen;
- size_t length = strlen(name);
- saa_wbytes(strs, name, length + 1);
- strslen += 1 + length;
- return pos;
- }
- static void as86_deflabel(char *name, int32_t segment, int64_t offset,
- int is_global, char *special)
- {
- bool is_start = false;
- struct Symbol *sym;
- if (special)
- nasm_error(ERR_NONFATAL, "as86 format does not support any"
- " special symbol types");
- if (name[0] == '.' && name[1] == '.' && name[2] != '@') {
- if (strcmp(name, "..start")) {
- nasm_error(ERR_NONFATAL, "unrecognised special symbol `%s'", name);
- return;
- } else {
- is_start = true;
- }
- }
- sym = saa_wstruct(syms);
- sym->strpos = as86_add_string(name);
- sym->flags = 0;
- if (is_start)
- sym->flags = SYM_ENTRY;
- if (segment == NO_SEG)
- sym->flags |= SYM_ABSOLUTE, sym->segment = 0;
- else if (segment == stext.index)
- sym->segment = SECT_TEXT;
- else if (segment == sdata.index)
- sym->segment = SECT_DATA;
- else if (segment == bssindex)
- sym->segment = SECT_BSS;
- else {
- sym->flags |= SYM_IMPORT;
- sym->segment = 15;
- }
- if (is_global == 2)
- sym->segment = 3; /* already have IMPORT */
- if (is_global && !(sym->flags & SYM_IMPORT))
- sym->flags |= SYM_EXPORT;
- sym->value = offset;
- /*
- * define the references from external-symbol segment numbers
- * to these symbol records.
- */
- if (segment != NO_SEG && segment != stext.index &&
- segment != sdata.index && segment != bssindex)
- bsym = raa_write(bsym, segment, nsyms);
- nsyms++;
- }
- static void as86_add_piece(struct Section *sect, int type, int32_t offset,
- int32_t segment, int32_t bytes, int relative)
- {
- struct Piece *p;
- sect->len += bytes;
- if (type == 0 && sect->last && sect->last->type == 0) {
- sect->last->bytes += bytes;
- return;
- }
- p = sect->last = *sect->tail = nasm_malloc(sizeof(struct Piece));
- sect->tail = &p->next;
- p->next = NULL;
- p->type = type;
- p->offset = offset;
- p->bytes = bytes;
- p->relative = relative;
- if (type == 1 && segment == stext.index)
- p->number = SECT_TEXT;
- else if (type == 1 && segment == sdata.index)
- p->number = SECT_DATA;
- else if (type == 1 && segment == bssindex)
- p->number = SECT_BSS;
- else if (type == 1)
- p->number = raa_read(bsym, segment), p->type = 2;
- }
- static void as86_out(int32_t segto, const void *data,
- enum out_type type, uint64_t size,
- int32_t segment, int32_t wrt)
- {
- struct Section *s;
- int32_t offset;
- uint8_t mydata[4], *p;
- if (wrt != NO_SEG) {
- wrt = NO_SEG; /* continue to do _something_ */
- nasm_error(ERR_NONFATAL, "WRT not supported by as86 output format");
- }
- /*
- * handle absolute-assembly (structure definitions)
- */
- if (segto == NO_SEG) {
- if (type != OUT_RESERVE)
- nasm_error(ERR_NONFATAL, "attempt to assemble code in [ABSOLUTE]"
- " space");
- return;
- }
- if (segto == stext.index)
- s = &stext;
- else if (segto == sdata.index)
- s = &sdata;
- else if (segto == bssindex)
- s = NULL;
- else {
- nasm_error(ERR_WARNING, "attempt to assemble code in"
- " segment %d: defaulting to `.text'", segto);
- s = &stext;
- }
- if (!s && type != OUT_RESERVE) {
- nasm_error(ERR_WARNING, "attempt to initialize memory in the"
- " BSS section: ignored");
- bsslen += realsize(type, size);
- return;
- }
- memset(mydata, 0, sizeof(mydata));
- if (type == OUT_RESERVE) {
- if (s) {
- nasm_error(ERR_WARNING, "uninitialized space declared in"
- " %s section: zeroing",
- (segto == stext.index ? "code" : "data"));
- as86_sect_write(s, NULL, size);
- as86_add_piece(s, 0, 0L, 0L, size, 0);
- } else
- bsslen += size;
- } else if (type == OUT_RAWDATA) {
- if (segment != NO_SEG)
- nasm_panic(0, "OUT_RAWDATA with other than NO_SEG");
- as86_sect_write(s, data, size);
- as86_add_piece(s, 0, 0L, 0L, size, 0);
- } else if (type == OUT_ADDRESS) {
- int asize = abs((int)size);
- if (segment != NO_SEG) {
- if (segment % 2) {
- nasm_error(ERR_NONFATAL, "as86 format does not support"
- " segment base references");
- } else {
- offset = *(int64_t *)data;
- as86_add_piece(s, 1, offset, segment, asize, 0);
- }
- } else {
- p = mydata;
- WRITELONG(p, *(int64_t *)data);
- as86_sect_write(s, data, asize);
- as86_add_piece(s, 0, 0L, 0L, asize, 0);
- }
- } else if (type == OUT_REL2ADR) {
- if (segment == segto)
- nasm_panic(0, "intra-segment OUT_REL2ADR");
- if (segment != NO_SEG) {
- if (segment % 2) {
- nasm_error(ERR_NONFATAL, "as86 format does not support"
- " segment base references");
- } else {
- offset = *(int64_t *)data;
- as86_add_piece(s, 1, offset - size + 2, segment, 2L,
- 1);
- }
- }
- } else if (type == OUT_REL4ADR) {
- if (segment == segto)
- nasm_panic(0, "intra-segment OUT_REL4ADR");
- if (segment != NO_SEG) {
- if (segment % 2) {
- nasm_error(ERR_NONFATAL, "as86 format does not support"
- " segment base references");
- } else {
- offset = *(int64_t *)data;
- as86_add_piece(s, 1, offset - size + 4, segment, 4L,
- 1);
- }
- }
- }
- }
- static void as86_write(void)
- {
- uint32_t i;
- int32_t symlen, seglen, segsize;
- /*
- * First, go through the symbol records working out how big
- * each will be. Also fix up BSS references at this time, and
- * set the flags words up completely.
- */
- symlen = 0;
- saa_rewind(syms);
- for (i = 0; i < nsyms; i++) {
- struct Symbol *sym = saa_rstruct(syms);
- if (sym->segment == SECT_BSS)
- sym->segment = SECT_DATA, sym->value += sdata.len;
- sym->flags |= sym->segment;
- if (sym->value == 0)
- sym->flags |= 0 << 14, symlen += 4;
- else if (sym->value >= 0 && sym->value <= 255)
- sym->flags |= 1 << 14, symlen += 5;
- else if (sym->value >= 0 && sym->value <= 65535L)
- sym->flags |= 2 << 14, symlen += 6;
- else
- sym->flags |= 3 << 14, symlen += 8;
- }
- /*
- * Now do the same for the segments, and get the segment size
- * descriptor word at the same time.
- */
- seglen = segsize = 0;
- if ((uint32_t)stext.len > 65535L)
- segsize |= 0x03000000L, seglen += 4;
- else
- segsize |= 0x02000000L, seglen += 2;
- if ((uint32_t)sdata.len > 65535L)
- segsize |= 0xC0000000L, seglen += 4;
- else
- segsize |= 0x80000000L, seglen += 2;
- /*
- * Emit the as86 header.
- */
- fwriteint32_t(0x000186A3L, ofile);
- fputc(0x2A, ofile);
- fwriteint32_t(27 + symlen + seglen + strslen, ofile); /* header length */
- fwriteint32_t(stext.len + sdata.len + bsslen, ofile);
- fwriteint16_t(strslen, ofile);
- fwriteint16_t(0, ofile); /* class = revision = 0 */
- fwriteint32_t(0x55555555L, ofile); /* segment max sizes: always this */
- fwriteint32_t(segsize, ofile); /* segment size descriptors */
- if (segsize & 0x01000000L)
- fwriteint32_t(stext.len, ofile);
- else
- fwriteint16_t(stext.len, ofile);
- if (segsize & 0x40000000L)
- fwriteint32_t(sdata.len + bsslen, ofile);
- else
- fwriteint16_t(sdata.len + bsslen, ofile);
- fwriteint16_t(nsyms, ofile);
- /*
- * Write the symbol table.
- */
- saa_rewind(syms);
- for (i = 0; i < nsyms; i++) {
- struct Symbol *sym = saa_rstruct(syms);
- fwriteint16_t(sym->strpos, ofile);
- fwriteint16_t(sym->flags, ofile);
- switch (sym->flags & (3 << 14)) {
- case 0 << 14:
- break;
- case 1 << 14:
- fputc(sym->value, ofile);
- break;
- case 2 << 14:
- fwriteint16_t(sym->value, ofile);
- break;
- case 3 << 14:
- fwriteint32_t(sym->value, ofile);
- break;
- }
- }
- /*
- * Write out the string table.
- */
- saa_fpwrite(strs, ofile);
- /*
- * Write the program text.
- */
- as86_reloc_size = -1;
- as86_write_section(&stext, SECT_TEXT);
- as86_write_section(&sdata, SECT_DATA);
- /*
- * Append the BSS section to the .data section
- */
- if (bsslen > 65535L) {
- fputc(0x13, ofile);
- fwriteint32_t(bsslen, ofile);
- } else if (bsslen > 255) {
- fputc(0x12, ofile);
- fwriteint16_t(bsslen, ofile);
- } else if (bsslen) {
- fputc(0x11, ofile);
- fputc(bsslen, ofile);
- }
- fputc(0, ofile); /* termination */
- }
- static void as86_set_rsize(int size)
- {
- if (as86_reloc_size != size) {
- switch (as86_reloc_size = size) {
- case 1:
- fputc(0x01, ofile);
- break;
- case 2:
- fputc(0x02, ofile);
- break;
- case 4:
- fputc(0x03, ofile);
- break;
- default:
- nasm_panic(0, "bizarre relocation size %d", size);
- break;
- }
- }
- }
- static void as86_write_section(struct Section *sect, int index)
- {
- struct Piece *p;
- uint32_t s;
- int32_t length;
- fputc(0x20 + index, ofile); /* select the right section */
- saa_rewind(sect->data);
- for (p = sect->head; p; p = p->next)
- switch (p->type) {
- case 0:
- /*
- * Absolute data. Emit it in chunks of at most 64
- * bytes.
- */
- length = p->bytes;
- do {
- char buf[64];
- int32_t tmplen = (length > 64 ? 64 : length);
- fputc(0x40 | (tmplen & 0x3F), ofile);
- saa_rnbytes(sect->data, buf, tmplen);
- nasm_write(buf, tmplen, ofile);
- length -= tmplen;
- } while (length > 0);
- break;
- case 1:
- /*
- * A segment-type relocation. First fix up the BSS.
- */
- if (p->number == SECT_BSS)
- p->number = SECT_DATA, p->offset += sdata.len;
- as86_set_rsize(p->bytes);
- fputc(0x80 | (p->relative ? 0x20 : 0) | p->number, ofile);
- if (as86_reloc_size == 2)
- fwriteint16_t(p->offset, ofile);
- else
- fwriteint32_t(p->offset, ofile);
- break;
- case 2:
- /*
- * A symbol-type relocation.
- */
- as86_set_rsize(p->bytes);
- s = p->offset;
- if (s > 65535L)
- s = 3;
- else if (s > 255)
- s = 2;
- else if (s > 0)
- s = 1;
- else
- s = 0;
- fputc(0xC0 |
- (p->relative ? 0x20 : 0) |
- (p->number > 255 ? 0x04 : 0) | s, ofile);
- if (p->number > 255)
- fwriteint16_t(p->number, ofile);
- else
- fputc(p->number, ofile);
- switch (s) {
- case 0:
- break;
- case 1:
- fputc(p->offset, ofile);
- break;
- case 2:
- fwriteint16_t(p->offset, ofile);
- break;
- case 3:
- fwriteint32_t(p->offset, ofile);
- break;
- }
- break;
- }
- }
- static void as86_sect_write(struct Section *sect,
- const uint8_t *data, uint32_t len)
- {
- saa_wbytes(sect->data, data, len);
- sect->datalen += len;
- }
- static int32_t as86_segbase(int32_t segment)
- {
- return segment;
- }
- extern macros_t as86_stdmac[];
- const struct ofmt of_as86 = {
- "Linux as86 (bin86 version 0.3) object files",
- "as86",
- ".o",
- 0,
- 32,
- null_debug_arr,
- &null_debug_form,
- as86_stdmac,
- as86_init,
- null_reset,
- nasm_do_legacy_output,
- as86_out,
- as86_deflabel,
- as86_section_names,
- NULL,
- null_sectalign,
- as86_segbase,
- null_directive,
- as86_cleanup,
- NULL /* pragma list */
- };
- #endif /* OF_AS86 */
|