summaryrefslogtreecommitdiff
path: root/outbin.c
diff options
context:
space:
mode:
Diffstat (limited to 'outbin.c')
-rw-r--r--outbin.c683
1 files changed, 439 insertions, 244 deletions
diff --git a/outbin.c b/outbin.c
index a3289cfc..95ac5da7 100644
--- a/outbin.c
+++ b/outbin.c
@@ -1,5 +1,5 @@
-/* outbin.c output routines for the Netwide Assembler to produce
- * flat-form binary files
+/* outbin.c output routines for the Netwide Assembler to produce
+ * flat-form binary files
*
* The Netwide Assembler is copyright (C) 1996 Simon Tatham and
* Julian Hall. All rights reserved. The software is
@@ -7,6 +7,13 @@
* distributed in the NASM archive.
*/
+/*
+ * version with multiple sections support
+ *
+ * sections go in order defined by their org's if present
+ * if no org present, sections go in sequence they appear.
+ */
+
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -22,11 +29,16 @@ static FILE *fp;
static efunc error;
static struct Section {
+ struct Section *next;
struct SAA *contents;
long length;
- long index;
-} textsect, datasect;
-static long bsslen, bssindex;
+ long org; /* assigned org */
+ long pos; /* file position of section ?? */
+ long pad; /* padding bytes to next section in file */
+ long index; /* the NASM section id */
+ long align; /* section alignment, cannot be absolute addr */
+ char *name;
+} *sections, **sectail;
static struct Reloc {
struct Reloc *next;
@@ -37,12 +49,10 @@ static struct Reloc {
struct Section *target;
} *relocs, **reloctail;
-static long data_align, bss_align;
-
-static long start_point;
+static long current_section;
static void add_reloc (struct Section *s, long bytes, long secref,
- long secrel)
+ long secrel)
{
struct Reloc *r;
@@ -56,307 +66,491 @@ static void add_reloc (struct Section *s, long bytes, long secref,
r->target = s;
}
-static void bin_init (FILE *afp, efunc errfunc, ldfunc ldef, evalfunc eval)
+static struct Section *find_section_by_name(char *name)
+{
+ struct Section *s;
+
+ for (s = sections; s; s = s->next)
+ if (!strcmp(s->name,name))
+ break;
+
+ return s;
+}
+
+static struct Section *find_section_by_index(long index)
+{
+ struct Section *s;
+
+ for (s = sections; s; s = s->next)
+ if ( s->index == index )
+ break;
+
+ return s;
+}
+
+static struct Section *alloc_section(char *name)
+{
+ struct Section *s;
+
+ s = find_section_by_name(name);
+ if(s)
+ error(ERR_PANIC, "section %s re-defined", name);
+
+ s = nasm_malloc(sizeof(struct Section));
+ *sectail = s;
+ sectail = &s->next;
+ s->next = NULL;
+
+ s->contents = saa_init(1L);
+ s->length = 0;
+ s->pos = 0;
+ s->org = -1; /* default org is -1 because we want
+ * to adjust sections one after another
+ */
+ s->index = seg_alloc();
+ s->align = 4;
+ s->pad = 0;
+ s->name = nasm_strdup(name);
+
+ return s;
+}
+
+static void bin_init (FILE *afp, efunc errfunc, ldfunc ldef, evalfunc eval)
{
fp = afp;
+ error = errfunc;
(void) eval; /* Don't warn that this parameter is unused */
+ (void) ldef; /* placate optimisers */
- error = errfunc;
- (void) ldef; /* placate optimisers */
-
- start_point = 0L; /* default */
- textsect.contents = saa_init(1L);
- datasect.contents = saa_init(1L);
- textsect.length = datasect.length = 0;
- textsect.index = seg_alloc();
- datasect.index = seg_alloc();
- bsslen = 0;
- bssindex = seg_alloc();
- relocs = NULL;
+ current_section = -1L;
+ relocs = NULL;
reloctail = &relocs;
- data_align = bss_align = 4;
+ sections = NULL;
+ sectail = &sections;
}
-static void bin_cleanup (int debuginfo)
+static void bin_cleanup (int debuginfo)
{
- struct Reloc *r;
- long datapos, datagap, bsspos;
-
- (void) debuginfo;
-
- datapos = start_point + textsect.length;
- datapos = (datapos + data_align-1) & ~(data_align-1);
- datagap = datapos - (start_point + textsect.length);
- bsspos = datapos + datasect.length;
- bsspos = (bsspos + bss_align-1) & ~(bss_align-1);
-
- saa_rewind (textsect.contents);
- saa_rewind (datasect.contents);
-
- for (r = relocs; r; r = r->next)
- {
- unsigned char *p, *q, mydata[4];
- long l;
-
- saa_fread (r->target->contents, r->posn, mydata, r->bytes);
- p = q = mydata;
- l = *p++;
- if (r->bytes > 1) {
- l += ((long)*p++) << 8;
- if (r->bytes == 4) {
- l += ((long)*p++) << 16;
- l += ((long)*p++) << 24;
- }
- }
-
- if (r->secref == textsect.index)
- l += start_point;
- else if (r->secref == datasect.index)
- l += datapos;
- else if (r->secref == bssindex)
- l += bsspos;
-
- if (r->secrel == textsect.index)
- l -= start_point;
- else if (r->secrel == datasect.index)
- l -= datapos;
- else if (r->secrel == bssindex)
- l -= bsspos;
-
- if (r->bytes == 4)
- WRITELONG(q, l);
- else if (r->bytes == 2)
- WRITESHORT(q, l);
- else
- *q++ = l & 0xFF;
- saa_fwrite (r->target->contents, r->posn, mydata, r->bytes);
- }
- saa_fpwrite (textsect.contents, fp);
- if (datasect.length > 0) {
- while (datagap--)
- fputc('\0', fp);
- saa_fpwrite (datasect.contents, fp);
- }
- fclose (fp);
- saa_free (textsect.contents);
- saa_free (datasect.contents);
- while (relocs) {
- r = relocs->next;
- nasm_free (relocs);
- relocs = r;
- }
+ struct Section *outsections, **outstail;
+ struct Section *s, *o, *ls, *lo;
+ struct Reloc *r;
+ long least_org;
+
+ (void) debuginfo;
+
+ /* sort sections by their orgs
+ * sections without org follow their natural order
+ * after the org'd sections
+ */
+ outsections = NULL;
+ outstail = &outsections;
+
+ while( 1 )
+ {
+ least_org = 0x7fffffff;
+
+ ls = lo = NULL;
+ for( s = sections, o = NULL; s; o = s, s = s->next )
+ if( s->org != -1 && s->org < least_org )
+ {
+ least_org = s->org;
+ ls = s;
+ lo = o;
+ }
+
+ if(ls) /* relink to outsections */
+ {
+#ifdef DEBUG
+ fprintf(stdout, "bin_cleanup: relinking section %s org %ld\n", ls->name, ls->org);
+#endif
+ /* unlink from sections */
+ if(lo)
+ lo->next = ls->next;
+ else
+ if(ls == sections)
+ sections = ls->next;
+
+ /* link in to outsections */
+ if( ls->length > 0 )
+ {
+ *outstail = ls;
+ outstail = &ls->next;
+ ls->next = NULL;
+ }
+ }
+ else
+ break;
+ }
+
+ /* link outsections at start of sections */
+ *outstail = sections;
+ sections = outsections;
+
+ /* calculate sections positions */
+ for(s = sections, o = NULL; s; s = s->next)
+ {
+ if(!strcmp(s->name,".bss")) continue; /* don't count .bss yet */
+
+ if(o)
+ {
+ /* if section doesn't have its
+ * own org, align from prev section
+ */
+ if( s->org == -1 )
+ s->org = o->org + o->length;
+
+ /* check orgs */
+ if( s->org - o->org < o->length )
+ error( ERR_PANIC, "sections %s and %s overlap!", o->name, s->name );
+
+ /* align previous section */
+ o->pad = ((o->pos + o->length + o->align-1) & ~(o->align-1)) - (o->pos + o->length);
+
+ if( s->org - o->org > o->length )
+ {
+#ifdef DEBUG
+ fprintf(stdout, "forced padding: %ld\n", s->org - o->org - o->length);
+#endif
+ o->pad = s->org - o->org - o->length;
+ }
+
+ s->pos += o->pos + o->length + o->pad;
+ s->org = s->pos + sections->org;
+ }
+
+#ifdef DEBUG
+ fprintf(stdout, "bin_cleanup: section %s at %ld(%lx) org %ld(%lx) prev <pos %ld(%lx)+size %ld(%lx)+pad %ld(%lx)> size %ld(%lx) align %ld(%lx)\n",
+ s->name, s->pos, s->pos, s->org, s->org, o?o->pos:0, o?o->pos:0,
+ o?o->length:0, o?o->length:0, o?o->pad:0, o?o->pad:0, s->length, s->length,
+ s->align, s->align);
+#endif
+
+ /* prepare for relocating by the way */
+ saa_rewind( s->contents );
+
+ o = s;
+ }
+
+ /* adjust .bss */
+ s = find_section_by_name(".bss");
+ if(s)
+ {
+ s->org = o->org + o->length + o->pad;
+
+#ifdef DEBUG
+ fprintf(stdout, "bin_cleanup: section %s at %ld org %ld prev (pos %ld+size %ld+pad %ld) size %ld align %ld\n",
+ s->name, s->pos, s->org, o?o->pos:0, o?o->length:0, o?o->pad:0, s->length, s->align);
+#endif
+ }
+
+ /* apply relocations */
+ for (r = relocs; r; r = r->next)
+ {
+ unsigned char *p, *q, mydata[4];
+ long l;
+
+ saa_fread (r->target->contents, r->posn, mydata, r->bytes);
+ p = q = mydata;
+ l = *p++;
+
+ if (r->bytes > 1) {
+ l += ((long)*p++) << 8;
+ if (r->bytes == 4) {
+ l += ((long)*p++) << 16;
+ l += ((long)*p++) << 24;
+ }
+ }
+
+ s = find_section_by_index(r->secref);
+ if(s)
+ l += s->org;
+
+ s = find_section_by_index(r->secrel);
+ if(s)
+ l -= s->org;
+
+ if (r->bytes == 4)
+ WRITELONG(q, l);
+ else if (r->bytes == 2)
+ WRITESHORT(q, l);
+ else
+ *q++ = l & 0xFF;
+ saa_fwrite (r->target->contents, r->posn, mydata, r->bytes);
+ }
+
+ /* write sections to file */
+ for(s = outsections; s; s = s->next)
+ {
+ if(s->length > 0 && strcmp(s->name,".bss"))
+ {
+#ifdef DEBUG
+ fprintf(stdout, "bin_cleanup: writing section %s\n", s->name);
+#endif
+ saa_fpwrite (s->contents, fp);
+ if( s->next )
+ while( s->pad-- > 0 )
+ fputc('\0', fp);
+ /* could pad with nops, since we don't
+ * know if this is code section or not
+ */
+ }
+ }
+
+ fclose (fp);
+
+ while (relocs) {
+ r = relocs->next;
+ nasm_free (relocs);
+ relocs = r;
+ }
+
+ while (outsections) {
+ s = outsections->next;
+ saa_free (outsections->contents);
+ nasm_free (outsections->name);
+ nasm_free (outsections);
+ outsections = s;
+ }
}
static void bin_out (long segto, void *data, unsigned long type,
- long segment, long wrt)
+ long segment, long wrt)
{
unsigned char *p, mydata[4];
- struct Section *s;
+ struct Section *s, *sec;
long realbytes;
if (wrt != NO_SEG) {
- wrt = NO_SEG; /* continue to do _something_ */
- error (ERR_NONFATAL, "WRT not supported by binary output format");
+ wrt = NO_SEG; /* continue to do _something_ */
+ error (ERR_NONFATAL, "WRT not supported by binary output format");
}
/*
* handle absolute-assembly (structure definitions)
*/
if (segto == NO_SEG) {
- if ((type & OUT_TYPMASK) != OUT_RESERVE)
- error (ERR_NONFATAL, "attempt to assemble code in [ABSOLUTE]"
- " space");
- return;
+ if ((type & OUT_TYPMASK) != OUT_RESERVE)
+ error (ERR_NONFATAL, "attempt to assemble code in [ABSOLUTE]"
+ " space");
+ return;
}
- if (segto == bssindex) { /* BSS */
- if ((type & OUT_TYPMASK) != OUT_RESERVE)
- error(ERR_WARNING, "attempt to initialise memory in the"
- " BSS section: ignored");
- s = NULL;
- } else if (segto == textsect.index) {
- s = &textsect;
- } else if (segto == datasect.index) {
- s = &datasect;
- } else {
- error(ERR_WARNING, "attempt to assemble code in"
- " segment %d: defaulting to `.text'", segto);
- s = &textsect;
+ /*
+ * Find the segment we are targetting.
+ */
+ s = find_section_by_index(segto);
+ if (!s)
+ error (ERR_PANIC, "code directed to nonexistent segment?");
+
+ if (!strcmp(s->name, ".bss")) { /* BSS */
+ if ((type & OUT_TYPMASK) != OUT_RESERVE)
+ error(ERR_WARNING, "attempt to initialise memory in the"
+ " BSS section: ignored");
+ s = NULL;
}
- if ((type & OUT_TYPMASK) == OUT_ADDRESS) {
- if (segment != NO_SEG &&
- segment != textsect.index &&
- segment != datasect.index &&
- segment != bssindex) {
- if (segment % 2)
- error(ERR_NONFATAL, "binary output format does not support"
- " segment base references");
- else
- error(ERR_NONFATAL, "binary output format does not support"
- " external references");
- segment = NO_SEG;
- }
- if (s) {
- if (segment != NO_SEG)
- add_reloc (s, type & OUT_SIZMASK, segment, -1L);
- p = mydata;
- if ((type & OUT_SIZMASK) == 4)
- WRITELONG (p, *(long *)data);
- else
- WRITESHORT (p, *(long *)data);
- saa_wbytes (s->contents, mydata, type & OUT_SIZMASK);
- s->length += type & OUT_SIZMASK;
- } else
- bsslen += type & OUT_SIZMASK;
- } else if ((type & OUT_TYPMASK) == OUT_RAWDATA) {
- type &= OUT_SIZMASK;
- p = data;
- if (s) {
- saa_wbytes (s->contents, data, type);
- s->length += type;
- } else
- bsslen += type;
- } else if ((type & OUT_TYPMASK) == OUT_RESERVE) {
- if (s) {
- error(ERR_WARNING, "uninitialised space declared in"
- " %s section: zeroing",
- (segto == textsect.index ? "code" : "data"));
- }
- type &= OUT_SIZMASK;
- if (s) {
- saa_wbytes (s->contents, NULL, type);
- s->length += type;
- } else
- bsslen += type;
- }
- else if ((type & OUT_TYPMASK) == OUT_REL2ADR ||
- (type & OUT_TYPMASK) == OUT_REL4ADR)
- {
- realbytes = ((type & OUT_TYPMASK) == OUT_REL4ADR ? 4 : 2);
- if (segment != NO_SEG &&
- segment != textsect.index &&
- segment != datasect.index &&
- segment != bssindex) {
- if (segment % 2)
- error(ERR_NONFATAL, "binary output format does not support"
- " segment base references");
- else
- error(ERR_NONFATAL, "binary output format does not support"
- " external references");
- segment = NO_SEG;
- }
- if (s) {
- add_reloc (s, realbytes, segment, segto);
- p = mydata;
- if (realbytes == 4)
- WRITELONG (p, *(long*)data - realbytes - s->length);
- else
- WRITESHORT (p, *(long*)data - realbytes - s->length);
- saa_wbytes (s->contents, mydata, realbytes);
- s->length += realbytes;
- } else
- bsslen += realbytes;
- }
+ if ((type & OUT_TYPMASK) == OUT_ADDRESS) {
+
+ if (segment != NO_SEG && !find_section_by_index(segment)) {
+ if (segment % 2)
+ error(ERR_NONFATAL, "binary output format does not support"
+ " segment base references");
+ else
+ error(ERR_NONFATAL, "binary output format does not support"
+ " external references");
+ segment = NO_SEG;
+ }
+
+ if (s) {
+ if (segment != NO_SEG)
+ add_reloc (s, type & OUT_SIZMASK, segment, -1L);
+ p = mydata;
+ if ((type & OUT_SIZMASK) == 4)
+ WRITELONG (p, *(long *)data);
+ else
+ WRITESHORT (p, *(long *)data);
+ saa_wbytes (s->contents, mydata, type & OUT_SIZMASK);
+ s->length += type & OUT_SIZMASK;
+ } else {
+ sec = find_section_by_name(".bss");
+ if(!sec)
+ error(ERR_PANIC, ".bss section is not present");
+ sec->length += type & OUT_SIZMASK;
+ }
+
+ } else if ((type & OUT_TYPMASK) == OUT_RAWDATA) {
+ type &= OUT_SIZMASK;
+ p = data;
+ if (s) {
+ saa_wbytes (s->contents, data, type);
+ s->length += type;
+ } else {
+ sec = find_section_by_name(".bss");
+ if(!sec)
+ error(ERR_PANIC, ".bss section is not present");
+ sec->length += type;
+ }
+
+ } else if ((type & OUT_TYPMASK) == OUT_RESERVE) {
+ if (s) {
+ error(ERR_WARNING, "uninitialised space declared in"
+ " %s section: zeroing", s->name);
+ }
+ type &= OUT_SIZMASK;
+ if (s) {
+ saa_wbytes (s->contents, NULL, type);
+ s->length += type;
+ } else {
+ sec = find_section_by_name(".bss");
+ if(!sec)
+ error(ERR_PANIC, ".bss section is not present");
+ sec->length += type;
+ }
+ }
+ else if ((type & OUT_TYPMASK) == OUT_REL2ADR ||
+ (type & OUT_TYPMASK) == OUT_REL4ADR)
+ {
+ realbytes = ((type & OUT_TYPMASK) == OUT_REL4ADR ? 4 : 2);
+
+ if (segment != NO_SEG && !find_section_by_index(segment)) {
+ if (segment % 2)
+ error(ERR_NONFATAL, "binary output format does not support"
+ " segment base references");
+ else
+ error(ERR_NONFATAL, "binary output format does not support"
+ " external references");
+ segment = NO_SEG;
+ }
+
+ if (s) {
+ add_reloc (s, realbytes, segment, segto);
+ p = mydata;
+ if (realbytes == 4)
+ WRITELONG (p, *(long*)data - realbytes - s->length);
+ else
+ WRITESHORT (p, *(long*)data - realbytes - s->length);
+ saa_wbytes (s->contents, mydata, realbytes);
+ s->length += realbytes;
+ } else {
+ sec = find_section_by_name(".bss");
+ if(!sec)
+ error(ERR_PANIC, ".bss section is not present");
+ sec->length += realbytes;
+ }
+ }
}
static void bin_deflabel (char *name, long segment, long offset,
- int is_global, char *special)
+ int is_global, char *special)
{
-
(void) segment; /* Don't warn that this parameter is unused */
(void) offset; /* Don't warn that this parameter is unused */
if (special)
- error (ERR_NONFATAL, "binary format does not support any"
- " special symbol types");
+ error (ERR_NONFATAL, "binary format does not support any"
+ " special symbol types");
if (name[0] == '.' && name[1] == '.' && name[2] != '@') {
- error (ERR_NONFATAL, "unrecognised special symbol `%s'", name);
- return;
+ error (ERR_NONFATAL, "unrecognised special symbol `%s'", name);
+ return;
}
if (is_global == 2) {
- error (ERR_NONFATAL, "binary output format does not support common"
- " variables");
+ error (ERR_NONFATAL, "binary output format does not support common"
+ " variables");
}
}
-static long bin_secname (char *name, int pass, int *bits)
+static long bin_secname (char *name, int pass, int *bits)
{
int sec_index;
long *sec_align;
char *p;
+ struct Section *sec;
(void) pass; /* Don't warn that this parameter is unused */
/*
- * Default is 16 bits.
+ * Default is 16 bits .text segment
*/
- if (!name)
- *bits = 16;
-
- if (!name)
- return textsect.index;
-
- p = name;
- while (*p && !isspace(*p)) p++;
- if (*p) *p++ = '\0';
- if (!strcmp(name, ".text")) {
- sec_index = textsect.index;
- sec_align = NULL;
- } else if (!strcmp(name, ".data")) {
- sec_index = datasect.index;
- sec_align = &data_align;
- } else if (!strcmp(name, ".bss")) {
- sec_index = bssindex;
- sec_align = &bss_align;
- } else
- return NO_SEG;
+ if (!name)
+ {
+ *bits = 16;
+ sec = find_section_by_name(".text");
+ if(!sec) sec = alloc_section(".text");
+ sec->org = 0; /* default .text org */
+ current_section = sec->index;
+ return sec->index;
+ }
+
+ p = name;
+ while (*p && !isspace(*p)) p++;
+ if (*p) *p++ = '\0';
+ if (!strcmp(name, ".text")) {
+ sec = find_section_by_name(".text");
+ if(!sec) sec = alloc_section(".text");
+ sec_index = sec->index;
+ sec_align = NULL;
+ } else {
+ sec = find_section_by_name(name);
+ if(!sec) sec = alloc_section(name);
+ sec_index = sec->index;
+ sec_align = &sec->align;
+ }
if (*p) {
- if (!nasm_strnicmp(p,"align=",6)) {
- if (sec_align == NULL)
- error(ERR_NONFATAL, "cannot specify an alignment to"
- " the `.text' section");
- else if (p[6+strspn(p+6,"0123456789")])
- error(ERR_NONFATAL, "argument to `align' is not numeric");
- else {
- unsigned int align = atoi(p+6);
- if (!align || ((align-1) & align))
- error(ERR_NONFATAL, "argument to `align' is not a"
- " power of two");
- else
- *sec_align = align;
- }
- }
+ if (!nasm_strnicmp(p,"align=",6)) {
+ if (sec_align == NULL)
+ error(ERR_NONFATAL, "cannot specify an alignment to"
+ " the .text section");
+ else if (p[6+strspn(p+6,"0123456789")])
+ error(ERR_NONFATAL, "argument to `align' is not numeric");
+ else {
+ unsigned int align = atoi(p+6);
+ if (!align || ((align-1) & align))
+ error(ERR_NONFATAL, "argument to `align' is not a"
+ " power of two");
+ else
+ *sec_align = align;
+ }
}
+ }
- return sec_index;
+ current_section = sec->index;
+ return sec_index;
}
-static long bin_segbase (long segment)
+static long bin_segbase (long segment)
{
return segment;
}
-static int bin_directive (char *directive, char *value, int pass)
+static int bin_directive (char *directive, char *value, int pass)
{
- int rn_error;
+ struct Section *s;
+ int rn_error;
- (void) pass; /* Don't warn that this parameter is unused */
+ (void) pass; /* Don't warn that this parameter is unused */
- if (!strcmp(directive, "org")) {
- start_point = readnum (value, &rn_error);
- if (rn_error)
- error (ERR_NONFATAL, "argument to ORG should be numeric");
- return 1;
- } else
- return 0;
+ if (!nasm_stricmp(directive, "org")) {
+ if(current_section == -1)
+ error(ERR_PANIC, "org of cosmic space specified");
+
+ s = find_section_by_index(current_section);
+ if(!s)
+ error(ERR_PANIC, "current_section points nowhere");
+
+ s->org = readnum (value, &rn_error);
+ if (rn_error)
+ error (ERR_NONFATAL, "argument to ORG should be numeric");
+ return 1;
+ }
+
+ return 0;
}
-static void bin_filename (char *inname, char *outname, efunc error)
+static void bin_filename (char *inname, char *outname, efunc error)
{
standard_extension (inname, outname, "", error);
}
@@ -375,8 +569,9 @@ static int bin_set_info(enum geninfo type, char **val)
{
return 0;
}
+
struct ofmt of_bin = {
- "flat-form binary files (e.g. DOS .COM, .SYS)",
+ "flat-form binary files (e.g. DOS .COM, .SYS) multisection support test",
"bin",
NULL,
null_debug_arr,