summaryrefslogtreecommitdiff
path: root/output
diff options
context:
space:
mode:
authorFrank Kotler <fbkotler@users.sourceforge.net>2003-02-04 07:11:20 +0000
committerFrank Kotler <fbkotler@users.sourceforge.net>2003-02-04 07:11:20 +0000
commit6b8350cdea1465456fc733923a38c9531ae4eea0 (patch)
tree0288e825eaa0b50a161e0018a14bba54305a2cfb /output
parente5ffcb333a008eafb435d37361ca8079f9cbfb67 (diff)
downloadnasm-6b8350cdea1465456fc733923a38c9531ae4eea0.tar.gz
Mike's multisection outbin.c "align bug fix"
Diffstat (limited to 'output')
-rw-r--r--output/outbin.c1543
1 files changed, 1134 insertions, 409 deletions
diff --git a/output/outbin.c b/output/outbin.c
index d5b0df77..a16268ef 100644
--- a/output/outbin.c
+++ b/output/outbin.c
@@ -7,13 +7,43 @@
* distributed in the NASM archive.
*/
-/*
- * version with multiple sections support
+/* This is the extended version of NASM's original binary output
+ * format. It is backward compatible with the original BIN format,
+ * and contains support for multiple sections and advanced section
+ * ordering.
+ *
+ * Feature summary:
+ *
+ * - Users can create an arbitrary number of sections; they are not
+ * limited to just ".text", ".data", and ".bss".
+ *
+ * - Sections can be either progbits or nobits type.
+ *
+ * - You can specify that they be aligned at a certian boundary
+ * following the previous section ("align="), or positioned at an
+ * arbitrary byte-granular location ("start=").
+ *
+ * - You can specify a "virtual" start address for a section, which
+ * will be used for the calculation for all address references
+ * with respect to that section ("vstart=").
+ *
+ * - The ORG directive, as well as the section/segment directive
+ * arguments ("align=", "start=", "vstart="), can take a critical
+ * expression as their value. For example: "align=(1 << 12)".
+ *
+ * - You can generate map files using the 'map' directive.
*
- * sections go in order defined by their org's if present
- * if no org present, sections go in sequence they appear.
*/
+/* Uncomment the following define if you want sections to adapt
+ * their PROGBITS/NOBITS state depending on what type of
+ * instructions are issued, rather than defaulting to PROGBITS.
+ * Note that this behavior violates the specification.
+
+#define ABIN_SMART_ADAPT
+
+*/
+
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -21,24 +51,64 @@
#include "nasm.h"
#include "nasmlib.h"
+#include "labels.h"
+#include "eval.h"
#include "outform.h"
#ifdef OF_BIN
-static FILE *fp;
+struct ofmt *bin_get_ofmt(); /* Prototype goes here since no header file. */
+
+static FILE *fp, *rf = NULL;
static efunc error;
-static struct Section {
- struct Section *next;
- struct SAA *contents;
- long length;
- 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;
+/* Section flags keep track of which attributes the user has defined. */
+#define START_DEFINED 0x001
+#define ALIGN_DEFINED 0x002
+#define FOLLOWS_DEFINED 0x004
+#define VSTART_DEFINED 0x008
+#define VALIGN_DEFINED 0x010
+#define VFOLLOWS_DEFINED 0x020
+#define TYPE_DEFINED 0x040
+#define TYPE_PROGBITS 0x080
+#define TYPE_NOBITS 0x100
+
+/* This struct is used to keep track of symbols for map-file generation. */
+static struct bin_label
+{ char * name;
+ struct bin_label *next;
+} *no_seg_labels, **nsl_tail;
+
+static struct Section
+{ char *name;
+ struct SAA * contents;
+ long length; /* section length in bytes */
+
+/* Section attributes */
+ int flags; /* see flag definitions above */
+ long align; /* section alignment */
+ long valign; /* notional section alignment */
+ long start; /* section start address */
+ long vstart; /* section virtual start address */
+ char *follows; /* the section that this one will follow */
+ char *vfollows; /* the section that this one will notionally follow */
+ long start_index; /* NASM section id for non-relocated version */
+ long vstart_index; /* the NASM section id */
+
+ struct bin_label *labels; /* linked-list of label handles for map output. */
+ struct bin_label **labels_end; /* Holds address of end of labels list. */
+ struct Section *ifollows; /* Points to previous section (implicit follows). */
+ struct Section *next; /* This links sections with a defined start address. */
+
+/* The extended bin format allows for sections to have a "virtual"
+ * start address. This is accomplished by creating two sections:
+ * one beginning at the Load Memory Address and the other beginning
+ * at the Virtual Memory Address. The LMA section is only used to
+ * define the section.<section_name>.start label, but there isn't
+ * any other good way for us to handle that label.
+ */
+
+} *sections, *last_section;
static struct Reloc {
struct Reloc *next;
@@ -49,12 +119,34 @@ static struct Reloc {
struct Section *target;
} *relocs, **reloctail;
-static long current_section;
+extern char *stdscan_bufptr;
+extern int lookup_label (char *label, long *segment, long *offset);
-static void add_reloc (struct Section *s, long bytes, long secref,
- long secrel)
-{
- struct Reloc *r;
+static unsigned char format_mode; /* 0 = original bin, 1 = extended bin */
+static long current_section; /* only really needed if format_mode = 0 */
+static long origin;
+static int origin_defined;
+
+/* Stuff we need for map-file generation. */
+#define MAP_ORIGIN 1
+#define MAP_SUMMARY 2
+#define MAP_SECTIONS 4
+#define MAP_SYMBOLS 8
+static int map_control = 0;
+static char *infile, *outfile;
+
+static const char *bin_stdmac[] = {
+ "%define __SECT__ [section .text]",
+ "%imacro org 1+.nolist",
+ "[org %1]",
+ "%endmacro",
+ "%macro __NASM_CDecl__ 1",
+ "%endmacro",
+ NULL
+};
+
+static void add_reloc(struct Section *s, long bytes, long secref, long secrel)
+{ struct Reloc *r;
r = *reloctail = nasm_malloc(sizeof(struct Reloc));
reloctail = &r->next;
@@ -67,510 +159,1138 @@ static void add_reloc (struct Section *s, long bytes, long secref,
}
static struct Section *find_section_by_name(const char *name)
-{
- struct Section *s;
+{ struct Section *s;
for (s = sections; s; s = s->next)
- if (!strcmp(s->name,name))
- break;
-
+ if (!strcmp(s->name,name)) break;
return s;
}
static struct Section *find_section_by_index(long index)
-{
- struct Section *s;
+{ 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);
-
+ if ((index == s->vstart_index) || (index == s->start_index))
+ break;
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 */
-
- current_section = -1L;
- relocs = NULL;
- reloctail = &relocs;
- sections = NULL;
- sectail = &sections;
+static struct Section * create_section(char *name)
+{ /* Create a new section. */
+ last_section->next = nasm_malloc(sizeof(struct Section));
+ last_section->next->ifollows = last_section;
+ last_section = last_section->next;
+ last_section->labels = NULL;
+ last_section->labels_end = &(last_section->labels);
+
+ /* Initialize section attributes. */
+ last_section->name = nasm_strdup(name);
+ last_section->contents = saa_init(1L);
+ last_section->follows = last_section->vfollows = 0;
+ last_section->length = 0;
+ last_section->flags = 0;
+ last_section->next = NULL;
+
+ /* Register our sections with NASM. */
+ last_section->vstart_index = seg_alloc();
+ last_section->start_index = seg_alloc();
+ return last_section;
}
static void bin_cleanup (int debuginfo)
-{
- struct Section *outsections, **outstail;
- struct Section *s, *o, *ls, *lo;
+{ struct Section *g, **gp;
+ struct Section *gs, **gsp;
+ struct Section *s, **sp;
+ struct Section *nobits = NULL, **nt;
+ struct Section * last_progbits;
+ struct bin_label *l;
struct Reloc *r;
- long least_org;
+ int h, pend;
+
+ /* Assembly has completed, so now we need to generate the output file.
+ * Step 1: Separate progbits and nobits sections into separate lists.
+ * Step 2: Sort the progbits sections into their output order.
+ * Step 3: Compute start addresses for all progbits sections.
+ * Step 4: Compute vstart addresses for all sections.
+ * Step 5: Apply relocations.
+ * Step 6: Write the section data to the output file.
+ * Step 7: Generate the map file.
+ * Step 8: Release all allocated memory.
+ */
- (void) debuginfo;
+ /* To do: Smart section-type adaptation could leave some empty sections
+ * without a defined type (progbits/nobits). Won't fix now since this
+ * feature will be disabled. */
- /* 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;
- }
+ /* Step 1: Separate progbits and nobits sections into separate lists. */
+
+ /* For anyone attempting to read this code:
+ * g (group) points to a group of sections, the first one of which has
+ * a user-defined start address or follows section.
+ * gp (g previous) holds the location of the pointer to g
+ * gs (g scan) is a temp variable that we use to scan to the end of the group
+ * gsp (gs previous) holds the location of the pointer to gs
+ * nt (nobits tail) points to the nobits section-list tail
+ */
- if(ls) /* relink to outsections */
- {
#ifdef DEBUG
- fprintf(stdout, "bin_cleanup: relinking section %s org %ld\n", ls->name, ls->org);
+ fprintf(stdout, "bin_cleanup: Sections were initially referenced in this order:\n");
+ for (h = 0, s = sections; s; h++, s = s->next)
+ fprintf(stdout, "%i. %s\n", h, s->name);
#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;
+
+ nt = &nobits;
+ /* Move nobits sections into a separate list. Also pre-process nobits
+ * sections' attributes. */
+ for (sp = &sections->next, s = sections->next; s; s = *sp)
+ { /* Skip progbits sections. */
+ if (s->flags & TYPE_PROGBITS)
+ { sp = &s->next; continue;
+ }
+ /* Do some special pre-processing on nobits sections' attributes. */
+ if (s->flags & (START_DEFINED | ALIGN_DEFINED | FOLLOWS_DEFINED))
+ { /* Check for a mixture of real and virtual section attributes. */
+ if (s->flags & (VSTART_DEFINED | VALIGN_DEFINED | VFOLLOWS_DEFINED))
+ error(ERR_FATAL, "cannot mix real and virtual attributes"
+ " in nobits section (%s)", s->name);
+ /* Real and virtual attributes mean the same thing for nobits sections. */
+ if (s->flags & START_DEFINED)
+ { s->vstart = s->start; s->flags |= VSTART_DEFINED;
+ }
+ if (s->flags & ALIGN_DEFINED)
+ { s->valign = s->align; s->flags |= VALIGN_DEFINED;
+ }
+ if (s->flags & FOLLOWS_DEFINED)
+ { s->vfollows = s->follows; s->flags |= VFOLLOWS_DEFINED;
+ s->flags &= ~FOLLOWS_DEFINED;
}
}
- else
- break;
+ /* Every section must have a start address. */
+ if (s->flags & VSTART_DEFINED)
+ { s->start = s->vstart; s->flags |= START_DEFINED;
+ }
+ /* Move the section into the nobits list. */
+ *sp = s->next; s->next = NULL;
+ *nt = s; nt = &s->next;
}
- /* 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;
+ /* Step 2: Sort the progbits sections into their output order. */
+
+ /* In Step 2 we move around sections in groups. A group
+ * begins with a section (group leader) that has a user-
+ * defined start address or follows section. The remainder
+ * of the group is made up of the sections that implicitly
+ * follow the group leader (i.e., they were defined after
+ * the group leader and were not given an explicit start
+ * address or follows section by the user). */
+
+ /* Link all 'follows' groups to their proper position. To do
+ * this we need to know three things: the start of the group
+ * to relocate (g), the section it is following (s), and the
+ * end of the group we're relocating (gs). */
+ for (gp = &sections, g = sections; g; g = gs)
+ { /* Find the next follows group that is out of place (g). */
+ if (!(g->flags & FOLLOWS_DEFINED))
+ { while (g->next)
+ { if ((g->next->flags & FOLLOWS_DEFINED) &&
+ strcmp(g->name, g->next->follows)) break;
+ g = g->next;
+ }
+ if (!g->next) break;
+ gp = &g->next; g = g->next;
+ }
+ /* Find the section that this group follows (s). */
+ for (sp = &sections, s = sections;
+ s && strcmp(s->name, g->follows);
+ sp = &s->next, s = s->next);
+ if (!s) error(ERR_FATAL, "section %s follows an invalid or"
+ " unknown section (%s)", g->name, g->follows);
+ if (s->next && (s->next->flags & FOLLOWS_DEFINED) &&
+ !strcmp(s->name, s->next->follows))
+ error(ERR_FATAL, "sections %s and %s can't both follow"
+ " section %s", g->name, s->next->name, s->name);
+ /* Find the end of the current follows group (gs). */
+ for (gsp = &g->next, gs = g->next;
+ gs && (gs != s) && !(gs->flags & START_DEFINED);
+ gsp = &gs->next, gs = gs->next)
+ { if (gs->next && (gs->next->flags & FOLLOWS_DEFINED) &&
+ strcmp(gs->name, gs->next->follows))
+ { gsp = &gs->next; gs = gs->next; break;
+ }
+ }
+ /* Re-link the group after its follows section. */
+ *gsp = s->next; s->next = g;
+ *gp = gs;
+ }
- /* check orgs */
- if( s->org - o->org < o->length )
- error( ERR_PANIC, "sections %s and %s overlap!", o->name, s->name );
+ /* Link all 'start' groups to their proper position. Once
+ * again we need to know g, s, and gs (see above). The main
+ * difference is we already know g since we sort by moving
+ * groups from the 'unsorted' list into a 'sorted' list (g
+ * will always be the first section in the unsorted list). */
+ for (g = sections, sections = NULL; g; g = gs)
+ { /* Find the section that we will insert this group before (s). */
+ for (sp = &sections, s = sections; s; sp = &s->next, s = s->next)
+ if ((s->flags & START_DEFINED) && (g->start < s->start)) break;
+ /* Find the end of the group (gs). */
+ for (gs = g->next, gsp = &g->next;
+ gs && !(gs->flags & START_DEFINED);
+ gsp = &gs->next, gs = gs->next);
+ /* Re-link the group before the target section. */
+ *sp = g; *gsp = s;
+ }
- /* 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;
+ /* Step 3: Compute start addresses for all progbits sections. */
+
+ /* Make sure we have an origin and a start address for the first section. */
+ if (origin_defined)
+ switch (sections->flags & (START_DEFINED | ALIGN_DEFINED))
+ { case START_DEFINED | ALIGN_DEFINED:
+ case START_DEFINED:
+ /* Make sure this section doesn't begin before the origin. */
+ if (sections->start < origin) error(ERR_FATAL, "section %s begins"
+ " before program origin", sections->name);
+ break;
+ case ALIGN_DEFINED:
+ sections->start = ((origin + sections->align - 1) &
+ ~(sections->align - 1)); break;
+ case 0:
+ sections->start = origin;
+ }
+ else
+ { if (!(sections->flags & START_DEFINED))
+ sections->start = 0;
+ origin = sections->start;
+ }
+ sections->flags |= START_DEFINED;
+
+ /* Make sure each section has an explicit start address. If it
+ * doesn't, then compute one based its alignment and the end of
+ * the previous section. */
+ for (pend = sections->start, g = s = sections; g; g = g->next)
+ { /* Find the next section that could cause an overlap situation
+ * (has a defined start address, and is not zero length). */
+ if (g == s)
+ for (s = g->next;
+ s && ((s->length == 0) || !(s->flags & START_DEFINED));
+ s = s->next);
+ /* Compute the start address of this section, if necessary. */
+ if (!(g->flags & START_DEFINED))
+ { /* Default to an alignment of 4 if unspecified. */
+ if (!(g->flags & ALIGN_DEFINED))
+ { g->align = 4; g->flags |= ALIGN_DEFINED;
}
+ /* Set the section start address. */
+ g->start = (pend + g->align - 1) & ~(g->align - 1);
+ g->flags |= START_DEFINED;
+ }
+ /* Ugly special case for progbits sections' virtual attributes:
+ * If there is a defined valign, but no vstart and no vfollows, then
+ * we valign after the previous progbits section. This case doesn't
+ * really make much sense for progbits sections with a defined start
+ * address, but it is possible and we must do *something*.
+ * Not-so-ugly special case:
+ * If a progbits section has no virtual attributes, we set the
+ * vstart equal to the start address. */
+ if (!(g->flags & (VSTART_DEFINED | VFOLLOWS_DEFINED)))
+ { if (g->flags & VALIGN_DEFINED)
+ g->vstart = (pend + g->valign - 1) & ~(g->valign - 1);
+ else g->vstart = g->start;
+ g->flags |= VSTART_DEFINED;
+ }
+ /* Ignore zero-length sections. */
+ if (g->start < pend) continue;
+ /* Compute the span of this section. */
+ pend = g->start + g->length;
+ /* Check for section overlap. */
+ if (s)
+ { if (g->start > s->start)
+ error(ERR_FATAL, "sections %s ~ %s and %s overlap!",
+ gs->name, g->name, s->name);
+ if (pend > s->start)
+ error(ERR_FATAL, "sections %s and %s overlap!",
+ g->name, s->name);
+ }
+ /* Remember this section as the latest >0 length section. */
+ gs = g;
+ }
- s->pos += o->pos + o->length + o->pad;
- s->org = s->pos + sections->org;
+ /* Step 4: Compute vstart addresses for all sections. */
+
+ /* Attach the nobits sections to the end of the progbits sections. */
+ for (s = sections; s->next; s = s->next); s->next = nobits;
+ last_progbits = s;
+ /* Scan for sections that don't have a vstart address. If we find one we'll
+ * attempt to compute its vstart. If we can't compute the vstart, we leave
+ * it alone and come back to it in a subsequent scan. We continue scanning
+ * and re-scanning until we've gone one full cycle without computing any
+ * vstarts. */
+ do
+ { /* Do one full scan of the sections list. */
+ for (h = 0, g = sections; g; g = g->next)
+ { if (g->flags & VSTART_DEFINED) continue;
+ /* Find the section that this one virtually follows. */
+ if (g->flags & VFOLLOWS_DEFINED)
+ { for (s = sections; s && strcmp(g->vfollows, s->name); s = s->next);
+ if (!s) error(ERR_FATAL, "section %s vfollows unknown section (%s)",
+ g->name, g->vfollows);
+ }
+ else if (g->ifollows != NULL)
+ for (s = sections; s && (s != g->ifollows); s = s->next);
+ /* The .bss section is the only one with ifollows = NULL. In this case we
+ * implicitly follow the last progbits section. */
+ else s = last_progbits;
+
+ /* If the section we're following has a vstart, we can proceed. */
+ if (s->flags & VSTART_DEFINED)
+ { /* Default to virtual alignment of four. */
+ if (!(g->flags & VALIGN_DEFINED))
+ { g->valign = 4; g->flags |= VALIGN_DEFINED;
+ }
+ /* Compute the vstart address. */
+ g->vstart = (s->vstart + s->length + g->valign - 1) & ~(g->valign - 1);
+ g->flags |= VSTART_DEFINED; h++;
+ /* Start and vstart mean the same thing for nobits sections. */
+ if (g->flags & TYPE_NOBITS) g->start = g->vstart;
+ }
}
+ } while (h);
+
+ /* Now check for any circular vfollows references, which will manifest
+ * themselves as sections without a defined vstart. */
+ for (s = sections; s && (s->flags & VSTART_DEFINED); s = s->next);
+ if (s) error(ERR_FATAL, "cannot compute vstart for section %s"
+ " (circular vfollows path)", s->name);
#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);
+ fprintf(stdout, "bin_cleanup: Confirm final section order for output file:\n");
+ for (h = 0, s = sections; s && (s->flags & TYPE_PROGBITS); h++, s = s->next)
+ fprintf(stdout, "%i. %s\n", h, s->name);
#endif
- /* prepare for relocating by the way */
- saa_rewind( s->contents );
- o = s;
- }
+ /* Step 5: Apply relocations. */
- /* 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 */
+ /* Prepare the sections for relocating. */
+ for (s = sections; s; s = s->next) saa_rewind(s->contents);
+ /* Apply relocations. */
for (r = relocs; r; r = r->next)
- {
- unsigned char *p, *q, mydata[4];
+ { 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;
+ 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;
-
+ if (s)
+ { if (r->secref == s->start_index) l += s->start;
+ else l += s->vstart;
+ }
s = find_section_by_index(r->secrel);
- if(s)
- l -= s->org;
+ if (s)
+ { if (r->secrel == s->start_index) l -= s->start;
+ else l -= s->vstart;
+ }
- 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);
+ if (r->bytes == 4) WRITELONG(q, l);
+ else if (r->bytes == 2) WRITESHORT(q, l);
+ else *q++ = (unsigned char) (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
- */
+
+ /* Step 6: Write the section data to the output file. */
+
+ /* Write the progbits sections to the output file. */
+ for(pend = origin, s = sections; s && (s->flags & TYPE_PROGBITS); s = s->next)
+ { /* Skip zero-length sections. */
+ if (s->length == 0) continue;
+ /* Pad the space between sections. */
+ for (h = s->start - pend; h; h--)
+ fputc('\0', fp);
+ /* Write the section to the output file. */
+ if (s->length > 0) saa_fpwrite(s->contents, fp);
+ pend = s->start + s->length;
+ }
+ /* Done writing the file, so close it. */
+ fclose(fp);
+
+
+ /* Step 7: Generate the map file. */
+
+ if (map_control)
+ { const char *not_defined = { "not defined" };
+
+ /* Display input and output file names. */
+ fprintf(rf, "\n- NASM Map file ");
+ for (h = 63; h; h--) fputc('-', rf);
+ fprintf(rf, "\n\nSource file: %s\nOutput file: %s\n\n",
+ infile, outfile);
+
+ if (map_control & MAP_ORIGIN)
+ { /* Display program origin. */
+ fprintf(rf, "-- Program origin ");
+ for (h = 61; h; h--) fputc('-', rf);
+ fprintf(rf, "\n\n%08lX\n\n", origin);
+ }
+ /* Display sections summary. */
+ if (map_control & MAP_SUMMARY)
+ { fprintf(rf, "-- Sections (summary) ");
+ for (h = 57; h; h--) fputc('-', rf);
+ fprintf(rf, "\n\nVstart Start Stop "
+ "Length Class Name\n");
+ for (s = sections; s; s = s->next)
+ { fprintf(rf, "%08lX %08lX %08lX %08lX ",
+ s->vstart, s->start, s->start + s->length, s->length);
+ if (s->flags & TYPE_PROGBITS) fprintf(rf, "progbits ");
+ else fprintf(rf, "nobits ");
+ fprintf(rf, "%s\n", s->name);
+ }
+ fprintf(rf, "\n");
+ }
+ /* Display detailed section information. */
+ if (map_control & MAP_SECTIONS)
+ { fprintf(rf, "-- Sections (detailed) ");
+ for (h = 56; h; h--) fputc('-', rf);
+ fprintf(rf, "\n\n");
+ for (s = sections; s; s = s->next)
+ { fprintf(rf, "---- Section %s ", s->name);
+ for (h = 65 - strlen(s->name); h; h--) fputc('-', rf);
+ fprintf(rf, "\n\nclass: ");
+ if (s->flags & TYPE_PROGBITS) fprintf(rf, "progbits");
+ else fprintf(rf, "nobits");
+ fprintf(rf, "\nlength: %08lX\nstart: %08lX"
+ "\nalign: ", s->length, s->start);
+ if (s->flags & ALIGN_DEFINED) fprintf(rf, "%08lX", s->align);
+ else fprintf(rf, not_defined);
+ fprintf(rf, "\nfollows: ");
+ if (s->flags & FOLLOWS_DEFINED) fprintf(rf, "%s", s->follows);
+ else fprintf(rf, not_defined);
+ fprintf(rf, "\nvstart: %08lX\nvalign: ", s->vstart);
+ if (s->flags & VALIGN_DEFINED) fprintf(rf, "%08lX", s->valign);
+ else fprintf(rf, not_defined);
+ fprintf(rf, "\nvfollows: ");
+ if (s->flags & VFOLLOWS_DEFINED) fprintf(rf, "%s", s->vfollows);
+ else fprintf(rf, not_defined);
+ fprintf(rf, "\n\n");
+ }
+ }
+ /* Display symbols information. */
+ if (map_control & MAP_SYMBOLS)
+ { long segment, offset;
+
+ fprintf(rf, "-- Symbols ");
+ for (h = 68; h; h--) fputc('-', rf);
+ fprintf(rf, "\n\n");
+ if (no_seg_labels)
+ { fprintf(rf, "---- No Section ");
+ for (h = 63; h; h--) fputc('-', rf);
+ fprintf(rf, "\n\nValue Name\n");
+ for (l = no_seg_labels; l; l = l->next)
+ { lookup_label(l->name, &segment, &offset);
+ fprintf(rf, "%08lX %s\n", offset, l->name);
+ }
+ fprintf(rf, "\n\n");
+ }
+ for (s = sections; s; s = s->next)
+ { if (s->labels)
+ { fprintf(rf, "---- Section %s ", s->name);
+ for (h = 65 - strlen(s->name); h; h--) fputc('-', rf);
+ fprintf(rf, "\n\nReal Virtual Name\n");
+ for (l = s->labels; l; l = l->next)
+ { lookup_label(l->name, &segment, &offset);
+ fprintf(rf, "%08lX %08lX %s\n", s->start + offset,
+ s->vstart + offset, l->name);
+ }
+ fprintf(rf, "\n");
+ }
+ }
}
}
- fclose (fp);
+ /* Close the report file. */
+ if (map_control && (rf != stdout) && (rf != stderr))
+ fclose(rf);
+
+
+ /* Step 8: Release all allocated memory. */
+
+ /* Free sections, label pointer structs, etc.. */
+ while (sections)
+ { s = sections; sections = s->next;
+ saa_free(s->contents);
+ nasm_free(s->name);
+ if (s->flags & FOLLOWS_DEFINED) nasm_free(s->follows);
+ if (s->flags & VFOLLOWS_DEFINED) nasm_free(s->vfollows);
+ while (s->labels)
+ { l = s->labels; s->labels = l->next;
+ nasm_free(l);
+ }
+ nasm_free(s);
+ }
- while (relocs) {
- r = relocs->next;
- nasm_free (relocs);
- relocs = r;
+ /* Free no-section labels. */
+ while (no_seg_labels)
+ { l = no_seg_labels; no_seg_labels = l->next;
+ nasm_free(l);
}
- while (outsections) {
- s = outsections->next;
- saa_free (outsections->contents);
- nasm_free (outsections->name);
- nasm_free (outsections);
- outsections = s;
+ /* Free relocation structures. */
+ while (relocs)
+ { r = relocs->next;
+ nasm_free(relocs);
+ relocs = r;
}
}
static void bin_out (long segto, const void *data, unsigned long type,
long segment, long wrt)
-{
- unsigned char *p, mydata[4];
- 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");
- }
-
- /*
- * 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;
- }
-
- /*
- * 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 && !find_section_by_index(segment)) {
- if (segment % 2)
- error(ERR_NONFATAL, "binary output format does not support"
+{ unsigned char *p, mydata[4];
+ struct Section *s;
+ long realbytes;
+
+ if (wrt != NO_SEG)
+ { 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;
+ }
+
+ /* Find the segment we are targeting. */
+ s = find_section_by_index(segto);
+ if (!s)
+ error (ERR_PANIC, "code directed to nonexistent segment?");
+
+ /* "Smart" section-type adaptation code. */
+ if (!(s->flags & TYPE_DEFINED))
+ { if ((type & OUT_TYPMASK) == OUT_RESERVE)
+ s->flags |= TYPE_DEFINED | TYPE_NOBITS;
+ else s->flags |= TYPE_DEFINED | TYPE_PROGBITS;
+ }
+
+ if ((s->flags & TYPE_NOBITS) && ((type & OUT_TYPMASK) != OUT_RESERVE))
+ error(ERR_WARNING, "attempt to initialise memory in a"
+ " nobits section: ignored");
+
+ 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"
+ else
+ error(ERR_NONFATAL, "binary output format does not support"
" external references");
- segment = NO_SEG;
+ segment = NO_SEG;
}
-
- if (s) {
- if (segment != NO_SEG)
- add_reloc (s, type & OUT_SIZMASK, segment, -1L);
+ if (s->flags & TYPE_PROGBITS)
+ { if (segment != NO_SEG)
+ add_reloc(s, type & OUT_SIZMASK, segment, -1L);
p = mydata;
if ((type & OUT_SIZMASK) == 4)
- WRITELONG (p, *(long *)data);
+ 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;
- 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;
+ WRITESHORT(p, *(long *)data);
+ saa_wbytes(s->contents, mydata, type & OUT_SIZMASK);
+ }
+ s->length += type & OUT_SIZMASK;
+ }
+ else if ((type & OUT_TYPMASK) == OUT_RAWDATA)
+ { type &= OUT_SIZMASK;
+ if (s->flags & TYPE_PROGBITS) saa_wbytes(s->contents, data, type);
+ s->length += type;
+ }
+ else if ((type & OUT_TYPMASK) == OUT_RESERVE)
+ { type &= OUT_SIZMASK;
+ if (s->flags & TYPE_PROGBITS)
+ { error(ERR_WARNING, "uninitialised space declared in"
+ " %s section: zeroing", s->name);
+ saa_wbytes (s->contents, NULL, type);
}
+ s->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"
+ (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"
+ else
+ error(ERR_NONFATAL, "binary output format does not support"
" external references");
- segment = NO_SEG;
+ segment = NO_SEG;
}
-
- if (s) {
- add_reloc (s, realbytes, segment, segto);
+ if (s->flags & TYPE_PROGBITS)
+ { add_reloc(s, realbytes, segment, segto);
p = mydata;
if (realbytes == 4)
- WRITELONG (p, *(long*)data - realbytes - s->length);
+ 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;
+ WRITESHORT(p, *(long*)data - realbytes - s->length);
+ saa_wbytes(s->contents, mydata, realbytes);
}
+ s->length += realbytes;
}
}
static void bin_deflabel (char *name, long segment, long offset,
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");
-
- if (name[0] == '.' && name[1] == '.' && name[2] != '@') {
- error (ERR_NONFATAL, "unrecognised special symbol `%s'", name);
- return;
- }
-
- if (is_global == 2) {
- error (ERR_NONFATAL, "binary output format does not support common"
- " variables");
- }
+{ (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");
+ else if (name[0] == '.' && name[1] == '.' && name[2] != '@')
+ error (ERR_NONFATAL, "unrecognised special symbol `%s'", name);
+ else if (is_global == 2)
+ error (ERR_NONFATAL, "binary output format does not support common"
+ " variables");
+ else
+ { struct Section *s;
+ struct bin_label ***ltp;
+
+ /* Remember label definition so we can look it up later when
+ * creating the map file. */
+ s = find_section_by_index(segment);
+ if (s) ltp = &(s->labels_end);
+ else ltp = &nsl_tail;
+ (**ltp) = nasm_malloc(sizeof(struct bin_label));
+ (**ltp)->name = name;
+ (**ltp)->next = NULL;
+ *ltp = &((**ltp)->next);
+ }
+
}
-static long bin_secname (char *name, int pass, int *bits)
-{
- int sec_index;
- long *sec_align;
- char *p;
- struct Section *sec;
+/* These constants and the following function are used
+ * by bin_secname() to parse attribute assignments. */
- (void) pass; /* Don't warn that this parameter is unused */
+enum { ATTRIB_START, ATTRIB_ALIGN, ATTRIB_FOLLOWS,
+ ATTRIB_VSTART, ATTRIB_VALIGN, ATTRIB_VFOLLOWS,
+ ATTRIB_NOBITS, ATTRIB_PROGBITS };
- /*
- * Default is 16 bits .text segment
- */
- if (!name)
+static int bin_read_attribute(char **line, int *attribute, long *value)
+{ expr *e;
+ int attrib_name_size;
+ struct tokenval tokval;
+ char *exp;
+
+ /* Skip whitespace. */
+ while (**line && isspace(**line)) (*line)++;
+ if (!**line) return 0;
+
+ /* Figure out what attribute we're reading. */
+ if (!nasm_strnicmp(*line,"align=", 6))
+ { *attribute = ATTRIB_ALIGN;
+ attrib_name_size = 6;
+ }
+ else if (format_mode)
+ { if (!nasm_strnicmp(*line,"start=", 6))
+ { *attribute = ATTRIB_START;
+ attrib_name_size = 6;
+ }
+ else if (!nasm_strnicmp(*line,"follows=", 8))
+ { *attribute = ATTRIB_FOLLOWS;
+ *line += 8; return 1;
+ }
+ else if (!nasm_strnicmp(*line,"vstart=", 7))
+ { *attribute = ATTRIB_VSTART;
+ attrib_name_size = 7;
+ }
+ else if (!nasm_strnicmp(*line,"valign=", 7))
+ { *attribute = ATTRIB_VALIGN;
+ attrib_name_size = 7;
+ }
+ else if (!nasm_strnicmp(*line,"vfollows=", 9))
+ { *attribute = ATTRIB_VFOLLOWS;
+ *line += 9; return 1;
+ }
+ else if (!nasm_strnicmp(*line,"nobits", 6) &&
+ (isspace((*line)[6]) || ((*line)[6] == '\0')))
+ { *attribute = ATTRIB_NOBITS;
+ *line += 6; return 1;
+ }
+ else if (!nasm_strnicmp(*line,"progbits", 8) &&
+ (isspace((*line)[8]) || ((*line)[8] == '\0')))
+ { *attribute = ATTRIB_PROGBITS;
+ *line += 8; return 1;
+ }
+ else return 0;
+ }
+ else return 0;
+
+ /* Find the end of the expression. */
+ if ((*line)[attrib_name_size] != '(')
{
+ /* Single term (no parenthesis). */
+ exp = *line += attrib_name_size;
+ while (**line && !isspace(**line)) (*line)++;
+ if (**line)
+ { **line = '\0'; (*line)++;
+ }
+ }
+ else
+ { char c;
+ int pcount = 1;
+
+ /* Full expression (delimited by parenthesis) */
+ exp = *line += attrib_name_size + 1;
+ while (1)
+ { (*line) += strcspn(*line, "()'\"");
+ if (**line == '(')
+ { ++(*line); ++pcount;
+ }
+ if (**line == ')')
+ { ++(*line); --pcount;
+ if (!pcount) break;
+ }
+ if ((**line == '"') || (**line == '\''))
+ { c = **line;
+ while (**line)
+ { ++(*line);
+ if (**line == c) break;
+ }
+ if (!**line)
+ { error(ERR_NONFATAL, "invalid syntax in `section' directive");
+ return -1;
+ }
+ ++(*line);
+ }
+ if (!**line)
+ { error(ERR_NONFATAL, "expecting `)'");
+ return -1;
+ }
+ }
+ *(*line - 1) = '\0'; /* Terminate the expression. */
+ }
+
+ /* Check for no value given. */
+ if (!*exp)
+ { error(ERR_WARNING, "No value given to attribute in"
+ " `section' directive");
+ return -1;
+ }
+
+ /* Read and evaluate the expression. */
+ stdscan_reset();
+ stdscan_bufptr = exp;
+ tokval.t_type = TOKEN_INVALID;
+ e = evaluate(stdscan, NULL, &tokval, NULL, 1, error, NULL);
+ if (e)
+ { if (!is_really_simple(e))
+ { error(ERR_NONFATAL, "section attribute value must be"
+ " a critical expression");
+ return -1;
+ }
+ }
+ else
+ { error(ERR_NONFATAL, "Invalid attribute value"
+ " specified in `section' directive.");
+ return -1;
+ }
+ *value = reloc_value(e);
+ return 1;
+}
+
+static void bin_assign_attributes(struct Section *sec, char *astring)
+{ int attribute, check;
+ long value;
+ char *p;
+
+ while (1)
+ { /* Get the next attribute. */
+ check = bin_read_attribute(&astring, &attribute, &value);
+ /* Skip bad attribute. */
+ if (check == -1) continue;
+ /* Unknown section attribute, so skip it and warn the user. */
+ if (!check)
+ { if (!*astring) break; /* End of line. */
+ else
+ { p = astring; while (*astring && !isspace(*astring)) astring++;
+ if (*astring)
+ { *astring = '\0'; astring++;
+ }
+ error(ERR_WARNING, "ignoring unknown section attribute:"
+ " \"%s\"", p);
+ }
+ continue;
+ }
+
+ switch (attribute)
+ { /* Handle nobits attribute. */
+ case ATTRIB_NOBITS:
+ if ((sec->flags & TYPE_DEFINED) && (sec->flags & TYPE_PROGBITS))
+ error(ERR_NONFATAL, "attempt to change section type"
+ " from progbits to nobits");
+ else sec->flags |= TYPE_DEFINED | TYPE_NOBITS;
+ continue;
+
+ /* Handle progbits attribute. */
+ case ATTRIB_PROGBITS:
+ if ((sec->flags & TYPE_DEFINED) && (sec->flags & TYPE_NOBITS))
+ error(ERR_NONFATAL, "attempt to change section type"
+ " from nobits to progbits");
+ else sec->flags |= TYPE_DEFINED | TYPE_PROGBITS;
+ continue;
+
+ /* Handle align attribute. */
+ case ATTRIB_ALIGN:
+ if (!format_mode && (!strcmp(sec->name, ".text")))
+ error(ERR_NONFATAL, "cannot specify an alignment"
+ " to the .text section");
+ else
+ { if (!value || ((value - 1) & value))
+ error(ERR_NONFATAL, "argument to `align' is not a"
+ " power of two");
+ else
+ { /* Alignment is already satisfied if the previous
+ * align value is greater. */
+ if ((sec->flags & ALIGN_DEFINED) && (value < sec->align))
+ value = sec->align;
+
+ /* Don't allow a conflicting align value. */
+ if ((sec->flags & START_DEFINED) && (sec->start & (value - 1)))
+ error(ERR_NONFATAL, "`align' value conflicts "
+ "with section start address");
+ else
+ { sec->align = value; sec->flags |= ALIGN_DEFINED;
+ }
+ }
+ }
+ continue;
+
+ /* Handle valign attribute. */
+ case ATTRIB_VALIGN:
+ if (!value || ((value - 1) & value))
+ error(ERR_NONFATAL, "argument to `valign' is not a"
+ " power of two");
+ else
+ { /* Alignment is already satisfied if the previous
+ * align value is greater. */
+ if ((sec->flags & VALIGN_DEFINED) && (value < sec->valign))
+ value = sec->valign;
+
+ /* Don't allow a conflicting valign value. */
+ if ((sec->flags & VSTART_DEFINED) && (sec->vstart & (value - 1)))
+ error(ERR_NONFATAL, "`valign' value conflicts "
+ "with `vstart' address");
+ else
+ { sec->valign = value; sec->flags |= VALIGN_DEFINED;
+ }
+ }
+ continue;
+
+ /* Handle start attribute. */
+ case ATTRIB_START:
+ if (sec->flags & FOLLOWS_DEFINED)
+ error(ERR_NONFATAL, "cannot combine `start' and `follows'"
+ " section attributes");
+ else if (value < 0)
+ error(ERR_NONFATAL, "attempt to specify a negative"
+ " section start address");
+ else if ((sec->flags & START_DEFINED) && (value != sec->start))
+ error(ERR_NONFATAL, "section start address redefined");
+ else
+ { sec->start = value; sec->flags |= START_DEFINED;
+ if (sec->flags & ALIGN_DEFINED)
+ { if (sec->start & (sec->align - 1))
+ error (ERR_NONFATAL, "`start' address conflicts"
+ " with section alignment");
+ sec->flags ^= ALIGN_DEFINED;
+ }
+ }
+ continue;
+
+ /* Handle vstart attribute. */
+ case ATTRIB_VSTART:
+ if (sec->flags & VFOLLOWS_DEFINED)
+ error(ERR_NONFATAL, "cannot combine `vstart' and `vfollows'"
+ " section attributes");
+ else if ((sec->flags & VSTART_DEFINED) && (value != sec->vstart))
+ error(ERR_NONFATAL, "section virtual start address"
+ " (vstart) redefined");
+ else
+ { sec->vstart = value; sec->flags |= VSTART_DEFINED;
+ if (sec->flags & VALIGN_DEFINED)
+ { if (sec->vstart & (sec->valign - 1))
+ error (ERR_NONFATAL, "`vstart' address conflicts"
+ " with `valign' value");
+ sec->flags ^= VALIGN_DEFINED;
+ }
+ }
+ continue;
+
+ /* Handle follows attribute. */
+ case ATTRIB_FOLLOWS:
+ p = astring; astring += strcspn(astring, " \t");
+ if (astring == p)
+ error(ERR_NONFATAL, "expecting section name for `follows'"
+ " attribute");
+ else
+ { *(astring++) = '\0';
+ if (sec->flags & START_DEFINED)
+ error(ERR_NONFATAL, "cannot combine `start' and `follows'"
+ " section attributes");
+ sec->follows = nasm_strdup(p);
+ sec->flags |= FOLLOWS_DEFINED;
+ }
+ continue;
+
+ /* Handle vfollows attribute. */
+ case ATTRIB_VFOLLOWS:
+ if (sec->flags & VSTART_DEFINED)
+ error(ERR_NONFATAL, "cannot combine `vstart' and `vfollows'"
+ " section attributes");
+ else
+ { p = astring; astring += strcspn(astring, " \t");
+ if (astring == p)
+ error(ERR_NONFATAL, "expecting section name for `vfollows'"
+ " attribute");
+ else
+ { *(astring++) = '\0';
+ sec->vfollows = nasm_strdup(p);
+ sec->flags |= VFOLLOWS_DEFINED;
+ }
+ }
+ continue;
+ }
+ }
+}
+
+static void bin_define_section_labels()
+{ static int labels_defined = 0;
+ struct Section * sec;
+ char * label_name;
+ size_t base_len;
+
+ if (labels_defined) return;
+ for (sec = sections; sec; sec = sec->next)
+ { base_len = strlen(sec->name) + 8;
+ label_name = nasm_malloc(base_len + 8);
+ strcpy(label_name, "section.");
+ strcpy(label_name + 8, sec->name);
+
+ /* section.<name>.start */
+ strcpy(label_name + base_len, ".start");
+ define_label(label_name, sec->start_index, 0L,
+ NULL, 0, 0, bin_get_ofmt(), error);
+
+ /* section.<name>.vstart */
+ strcpy(label_name + base_len, ".vstart");
+ define_label(label_name, sec->vstart_index, 0L,
+ NULL, 0, 0, bin_get_ofmt(), error);
+
+ nasm_free(label_name);
+ }
+ labels_defined = 1;
+}
+
+static long bin_secname(char *name, int pass, int *bits)
+{ char *p;
+ struct Section *sec;
+
+ /* bin_secname is called with *name = NULL at the start of each
+ * pass. Use this opportunity to establish the default section
+ * (default is BITS-16 ".text" segment).
+ */
+ if (!name)
+ { /* Reset ORG and section attributes at the start of each pass. */
+ origin_defined = 0;
+ for (sec = sections; sec; sec = sec->next)
+ sec->flags &= ~(START_DEFINED | VSTART_DEFINED |
+ ALIGN_DEFINED | VALIGN_DEFINED);
+
+ /* Define section start and vstart labels. */
+ if (format_mode && (pass != 1)) bin_define_section_labels();
+
+ /* Establish the default (.text) section. */
*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;
+ sec->flags |= TYPE_DEFINED | TYPE_PROGBITS;
+ current_section = sec->vstart_index;
+ return current_section;
}
+ /* Attempt to find the requested section. If it does not
+ * exist, create it. */
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;
- }
- }
+ sec = find_section_by_name(name);
+ if(!sec)
+ { sec = create_section(name);
+ if (!strcmp(name, ".data"))
+ sec->flags |= TYPE_DEFINED | TYPE_PROGBITS;
+ else if (!strcmp(name, ".bss"))
+ { sec->flags |= TYPE_DEFINED | TYPE_NOBITS;
+ sec->ifollows = NULL;
+ }
+ else if (!format_mode)
+ { error(ERR_NONFATAL, "section name must be "
+ ".text, .data, or .bss");
+ return current_section;
+ }
}
- current_section = sec->index;
- return sec_index;
-}
+ /* Handle attribute assignments. */
+ if (pass != 1) bin_assign_attributes(sec, p);
-static long bin_segbase (long segment)
-{
- return segment;
+#ifndef ABIN_SMART_ADAPT
+ /* The following line disables smart adaptation of
+ * PROGBITS/NOBITS section types (it forces sections to
+ * default to PROGBITS). */
+ if ((pass != 1) && !(sec->flags & TYPE_DEFINED))
+ sec->flags |= TYPE_DEFINED | TYPE_PROGBITS;
+#endif
+
+ /* Set the current section and return. */
+ current_section = sec->vstart_index;
+ return current_section;
}
-static int bin_directive (char *directive, char *value, int pass)
+static int bin_directive (char *directive, char *args, int pass)
{
- struct Section *s;
- int rn_error;
-
- (void) pass; /* Don't warn that this parameter is unused */
-
- 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");
+ /* Handle ORG directive */
+ if (!nasm_stricmp(directive, "org"))
+ { struct tokenval tokval;
+ long value;
+ expr *e;
+
+ stdscan_reset();
+ stdscan_bufptr = args;
+ tokval.t_type = TOKEN_INVALID;
+ e = evaluate(stdscan, NULL, &tokval, NULL, 1, error, NULL);
+ if (e)
+ { if (!is_really_simple(e))
+ error(ERR_NONFATAL, "org value must be a critical"
+ " expression");
+ else
+ { value = reloc_value(e);
+ if (value < 0)
+ error(ERR_NONFATAL, "attempt to set a negative program origin");
+ /* Check for ORG redefinition. */
+ else if (origin_defined && (value != origin))
+ error(ERR_NONFATAL, "program origin redefined");
+ else
+ { origin = value;
+ origin_defined = 1;
+ }
+ }
+ }
+ else
+ error(ERR_NONFATAL, "No or invalid offset specified"
+ " in ORG directive.");
return 1;
}
+ /* The 'map' directive allows the user to generate section
+ * and symbol information to stdout, stderr, or to a file. */
+ else if (format_mode && !nasm_stricmp(directive, "map"))
+ { char *p;
+
+ if (pass != 1) return 1;
+ args += strspn(args, " \t");
+ while (*args)
+ { p = args; args += strcspn(args, " \t");
+ if (*args != '\0') *(args++) = '\0';
+ if (!nasm_stricmp(p, "all"))
+ map_control |= MAP_ORIGIN | MAP_SUMMARY | MAP_SECTIONS | MAP_SYMBOLS;
+ else if (!nasm_stricmp(p, "brief"))
+ map_control |= MAP_ORIGIN | MAP_SUMMARY;
+ else if (!nasm_stricmp(p, "sections"))
+ map_control |= MAP_ORIGIN | MAP_SUMMARY | MAP_SECTIONS;
+ else if (!nasm_stricmp(p, "segments"))
+ map_control |= MAP_ORIGIN | MAP_SUMMARY | MAP_SECTIONS;
+ else if (!nasm_stricmp(p, "symbols"))
+ map_control |= MAP_SYMBOLS;
+ else if (!rf)
+ { if (!nasm_stricmp(p, "stdout"))
+ rf = stdout;
+ else if (!nasm_stricmp(p, "stderr"))
+ rf = stderr;
+ else
+ { /* Must be a filename. */
+ rf = fopen(p, "wt");
+ if (!rf)
+ { error(ERR_WARNING, "unable to open map file `%s'", p);
+ map_control = 0;
+ return 1;
+ }
+ }
+ }
+ else error(ERR_WARNING, "map file already specified");
+ }
+ if (map_control == 0) map_control |= MAP_ORIGIN | MAP_SUMMARY;
+ if (!rf) rf = stdout;
+ return 1;
+ }
return 0;
}
static void bin_filename (char *inname, char *outname, efunc error)
-{
- standard_extension (inname, outname, "", error);
+{ standard_extension(inname, outname, "", error);
+ infile = inname; outfile = outname;
}
-static const char *bin_stdmac[] = {
- "%define __SECT__ [section .text]",
- "%imacro org 1+.nolist",
- "[org %1]",
- "%endmacro",
- "%macro __NASM_CDecl__ 1",
- "%endmacro",
- NULL
-};
+static long bin_segbase (long segment)
+{ return segment;
+}
static int bin_set_info(enum geninfo type, char **val)
-{
- return 0;
+{ return 0;
+}
+
+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 optimizers. */
+
+ relocs = NULL;
+ reloctail = &relocs;
+ origin_defined = 0;
+ no_seg_labels = NULL;
+ nsl_tail = &no_seg_labels;
+ format_mode = 1; /* Extended bin format
+ * (set this to zero for old bin format). */
+
+ /* Create default section (.text). */
+ sections = last_section = nasm_malloc(sizeof(struct Section));
+ last_section->next = NULL;
+ last_section->name = nasm_strdup(".text");
+ last_section->contents = saa_init(1L);
+ last_section->follows = last_section->vfollows = 0;
+ last_section->ifollows = NULL;
+ last_section->length = 0;
+ last_section->flags = TYPE_DEFINED | TYPE_PROGBITS;
+ last_section->labels = NULL;
+ last_section->labels_end = &(last_section->labels);
+ last_section->start_index = seg_alloc();
+ last_section->vstart_index = current_section = seg_alloc();
}
struct ofmt of_bin = {
- "flat-form binary files (e.g. DOS .COM, .SYS) multisection support test",
+ "flat-form binary files (e.g. DOS .COM, .SYS)",
"bin",
NULL,
null_debug_arr,
@@ -587,4 +1307,9 @@ struct ofmt of_bin = {
bin_cleanup
};
-#endif /* OF_BIN */
+/* This is needed for bin_define_section_labels() */
+struct ofmt *bin_get_ofmt()
+{ return &of_bin;
+}
+
+#endif /* #ifdef OF_BIN */