summaryrefslogtreecommitdiff
path: root/vere/ext/nasm/output/outieee.c
diff options
context:
space:
mode:
Diffstat (limited to 'vere/ext/nasm/output/outieee.c')
-rw-r--r--vere/ext/nasm/output/outieee.c1521
1 files changed, 1521 insertions, 0 deletions
diff --git a/vere/ext/nasm/output/outieee.c b/vere/ext/nasm/output/outieee.c
new file mode 100644
index 0000000..7ba9036
--- /dev/null
+++ b/vere/ext/nasm/output/outieee.c
@@ -0,0 +1,1521 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 1996-2022 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * outieee.c output routines for the Netwide Assembler to produce
+ * IEEE-std object files
+ */
+
+/* notes: I have tried to make this correspond to the IEEE version
+ * of the standard, specifically the primary ASCII version. It should
+ * be trivial to create the binary version given this source (which is
+ * one of MANY things that have to be done to make this correspond to
+ * the hp-microtek version of the standard).
+ *
+ * 16-bit support is assumed to use 24-bit addresses
+ * The linker can sort out segmentation-specific stuff
+ * if it keeps track of externals
+ * in terms of being relative to section bases
+ *
+ * A non-standard variable type, the 'Yn' variable, has been introduced.
+ * Basically it is a reference to extern 'n'- denoting the low limit
+ * (L-variable) of the section that extern 'n' is defined in. Like the
+ * x variable, there may be no explicit assignment to it, it is derived
+ * from the public definition corresponding to the extern name. This
+ * is required because the one thing the mufom guys forgot to do well was
+ * take into account segmented architectures.
+ *
+ * I use comment classes for various things and these are undefined by
+ * the standard.
+ *
+ * Debug info should be considered totally non-standard (local labels are
+ * standard but linenum records are not covered by the standard.
+ * Type defs have the standard format but absolute meanings for ordinal
+ * types are not covered by the standard.)
+ *
+ * David Lindauer, LADsoft
+ */
+#include "compiler.h"
+
+#include <time.h>
+#include <ctype.h> /* For toupper() */
+#include "nctype.h"
+
+#include "nasm.h"
+#include "nasmlib.h"
+#include "error.h"
+#include "ver.h"
+
+#include "outform.h"
+#include "outlib.h"
+
+#ifdef OF_IEEE
+
+#define ARRAY_BOT 0x1
+
+static char ieee_infile[FILENAME_MAX];
+static int ieee_uppercase;
+
+static bool any_segs;
+static int arrindex;
+
+#define HUNKSIZE 1024 /* Size of the data hunk */
+#define EXT_BLKSIZ 512
+#define LDPERLINE 32 /* bytes per line in output */
+
+struct ieeeSection;
+
+struct LineNumber {
+ struct LineNumber *next;
+ struct ieeeSection *segment;
+ int32_t offset;
+ int32_t lineno;
+};
+
+static struct FileName {
+ struct FileName *next;
+ char *name;
+ int32_t index;
+} *fnhead, **fntail;
+
+static struct Array {
+ struct Array *next;
+ unsigned size;
+ int basetype;
+} *arrhead, **arrtail;
+
+static struct ieeePublic {
+ struct ieeePublic *next;
+ char *name;
+ int32_t offset;
+ int32_t segment; /* only if it's far-absolute */
+ int32_t index;
+ int type; /* for debug purposes */
+} *fpubhead, **fpubtail, *last_defined;
+
+static struct ieeeExternal {
+ struct ieeeExternal *next;
+ char *name;
+ int32_t commonsize;
+} *exthead, **exttail;
+
+static int externals;
+
+static struct ExtBack {
+ struct ExtBack *next;
+ int index[EXT_BLKSIZ];
+} *ebhead, **ebtail;
+
+/* NOTE: the first segment MUST be the lineno segment */
+static struct ieeeSection {
+ struct ieeeSection *next;
+ char *name;
+ struct ieeeObjData *data, *datacurr;
+ struct ieeeFixupp *fptr, *flptr;
+ int32_t index; /* the NASM segment id */
+ int32_t ieee_index; /* the IEEE-file segment index */
+ int32_t currentpos;
+ int32_t align; /* can be SEG_ABS + absolute addr */
+ int32_t startpos;
+ int32_t use32; /* is this segment 32-bit? */
+ int64_t pass_last_seen;
+ struct ieeePublic *pubhead, **pubtail, *lochead, **loctail;
+ enum {
+ CMB_PRIVATE = 0,
+ CMB_PUBLIC = 2,
+ CMB_COMMON = 6
+ } combine;
+} *seghead, **segtail, *ieee_seg_needs_update;
+
+struct ieeeObjData {
+ struct ieeeObjData *next;
+ uint8_t data[HUNKSIZE];
+};
+
+struct ieeeFixupp {
+ struct ieeeFixupp *next;
+ enum {
+ FT_SEG = 0,
+ FT_REL = 1,
+ FT_OFS = 2,
+ FT_EXT = 3,
+ FT_WRT = 4,
+ FT_EXTREL = 5,
+ FT_EXTWRT = 6,
+ FT_EXTSEG = 7
+ } ftype;
+ int16_t size;
+ int32_t id1;
+ int32_t id2;
+ int32_t offset;
+ int32_t addend;
+};
+
+static int32_t ieee_entry_seg, ieee_entry_ofs;
+static int checksum;
+
+extern const struct ofmt of_ieee;
+static const struct dfmt ladsoft_debug_form;
+
+static void ieee_data_new(struct ieeeSection *);
+static void ieee_write_fixup(int32_t, int32_t, struct ieeeSection *,
+ int, uint64_t, int32_t);
+static void ieee_install_fixup(struct ieeeSection *, struct ieeeFixupp *);
+static int32_t ieee_segment(char *, int *);
+static void ieee_write_file(void);
+static void ieee_write_byte(struct ieeeSection *, int);
+static void ieee_write_word(struct ieeeSection *, int);
+static void ieee_write_dword(struct ieeeSection *, int32_t);
+static void ieee_putascii(char *, ...);
+static void ieee_putcs(int);
+static int32_t ieee_putld(int32_t, int32_t, uint8_t *);
+static int32_t ieee_putlr(struct ieeeFixupp *);
+static void ieee_unqualified_name(char *, char *);
+
+/*
+ * pup init
+ */
+static void ieee_init(void)
+{
+ strlcpy(ieee_infile, inname, sizeof(ieee_infile));
+ any_segs = false;
+ fpubhead = NULL;
+ fpubtail = &fpubhead;
+ exthead = NULL;
+ exttail = &exthead;
+ externals = 1;
+ ebhead = NULL;
+ ebtail = &ebhead;
+ seghead = ieee_seg_needs_update = NULL;
+ segtail = &seghead;
+ ieee_entry_seg = NO_SEG;
+ ieee_uppercase = false;
+ checksum = 0;
+}
+
+/*
+ * Rundown
+ */
+static void ieee_cleanup(void)
+{
+ ieee_write_file();
+ dfmt->cleanup();
+ while (seghead) {
+ struct ieeeSection *segtmp = seghead;
+ seghead = seghead->next;
+ while (segtmp->pubhead) {
+ struct ieeePublic *pubtmp = segtmp->pubhead;
+ segtmp->pubhead = pubtmp->next;
+ nasm_free(pubtmp);
+ }
+ while (segtmp->fptr) {
+ struct ieeeFixupp *fixtmp = segtmp->fptr;
+ segtmp->fptr = fixtmp->next;
+ nasm_free(fixtmp);
+ }
+ while (segtmp->data) {
+ struct ieeeObjData *dattmp = segtmp->data;
+ segtmp->data = dattmp->next;
+ nasm_free(dattmp);
+ }
+ nasm_free(segtmp);
+ }
+ while (fpubhead) {
+ struct ieeePublic *pubtmp = fpubhead;
+ fpubhead = fpubhead->next;
+ nasm_free(pubtmp);
+ }
+ while (exthead) {
+ struct ieeeExternal *exttmp = exthead;
+ exthead = exthead->next;
+ nasm_free(exttmp);
+ }
+ while (ebhead) {
+ struct ExtBack *ebtmp = ebhead;
+ ebhead = ebhead->next;
+ nasm_free(ebtmp);
+ }
+}
+
+/*
+ * callback for labels
+ */
+static void ieee_deflabel(char *name, int32_t segment,
+ int64_t offset, int is_global, char *special)
+{
+ /*
+ * We have three cases:
+ *
+ * (i) `segment' is a segment-base. If so, set the name field
+ * for the segment structure it refers to, and then
+ * return.
+ *
+ * (ii) `segment' is one of our segments, or a SEG_ABS segment.
+ * Save the label position for later output of a PUBDEF record.
+ *
+ *
+ * (iii) `segment' is not one of our segments. Save the label
+ * position for later output of an EXTDEF.
+ */
+ struct ieeeExternal *ext;
+ struct ExtBack *eb;
+ struct ieeeSection *seg;
+ int i;
+
+ if (special)
+ nasm_nonfatal("unrecognised symbol type `%s'", special);
+ /*
+ * First check for the double-period, signifying something
+ * unusual.
+ */
+ if (name[0] == '.' && name[1] == '.' && name[2] != '@') {
+ if (!strcmp(name, "..start")) {
+ ieee_entry_seg = segment;
+ ieee_entry_ofs = offset;
+ }
+ return;
+ }
+
+ /*
+ * Case (i):
+ */
+ if (ieee_seg_needs_update) {
+ ieee_seg_needs_update->name = name;
+ return;
+ }
+ if (segment < SEG_ABS && segment != NO_SEG && segment % 2)
+ return;
+
+ /*
+ * case (ii)
+ */
+ if (segment >= SEG_ABS) {
+ /*
+ * SEG_ABS subcase of (ii).
+ */
+ if (is_global) {
+ struct ieeePublic *pub;
+
+ pub = *fpubtail = nasm_malloc(sizeof(*pub));
+ fpubtail = &pub->next;
+ pub->next = NULL;
+ pub->name = name;
+ pub->offset = offset;
+ pub->segment = segment & ~SEG_ABS;
+ }
+ return;
+ }
+
+ for (seg = seghead; seg && is_global; seg = seg->next)
+ if (seg->index == segment) {
+ struct ieeePublic *pub;
+
+ last_defined = pub = *seg->pubtail = nasm_malloc(sizeof(*pub));
+ seg->pubtail = &pub->next;
+ pub->next = NULL;
+ pub->name = name;
+ pub->offset = offset;
+ pub->index = seg->ieee_index;
+ pub->segment = -1;
+ return;
+ }
+
+ /*
+ * Case (iii).
+ */
+ if (is_global) {
+ ext = *exttail = nasm_malloc(sizeof(*ext));
+ ext->next = NULL;
+ exttail = &ext->next;
+ ext->name = name;
+ if (is_global == 2)
+ ext->commonsize = offset;
+ else
+ ext->commonsize = 0;
+ i = segment / 2;
+ eb = ebhead;
+ if (!eb) {
+ eb = *ebtail = nasm_zalloc(sizeof(*eb));
+ eb->next = NULL;
+ ebtail = &eb->next;
+ }
+ while (i > EXT_BLKSIZ) {
+ if (eb && eb->next)
+ eb = eb->next;
+ else {
+ eb = *ebtail = nasm_zalloc(sizeof(*eb));
+ eb->next = NULL;
+ ebtail = &eb->next;
+ }
+ i -= EXT_BLKSIZ;
+ }
+ eb->index[i] = externals++;
+ }
+
+}
+
+/*
+ * Put data out
+ */
+static void ieee_out(int32_t segto, const void *data,
+ enum out_type type, uint64_t size,
+ int32_t segment, int32_t wrt)
+{
+ const uint8_t *ucdata;
+ int32_t ldata;
+ struct ieeeSection *seg;
+
+ /*
+ * If `any_segs' is still false, we must define a default
+ * segment.
+ */
+ if (!any_segs) {
+ int tempint; /* ignored */
+ if (segto != ieee_segment("__NASMDEFSEG", &tempint))
+ nasm_panic("strange segment conditions in IEEE driver");
+ }
+
+ /*
+ * Find the segment we are targeting.
+ */
+ for (seg = seghead; seg; seg = seg->next)
+ if (seg->index == segto)
+ break;
+ if (!seg)
+ nasm_panic("code directed to nonexistent segment?");
+
+ if (type == OUT_RAWDATA) {
+ ucdata = data;
+ while (size--)
+ ieee_write_byte(seg, *ucdata++);
+ } else if (type == OUT_ADDRESS || type == OUT_REL2ADR ||
+ type == OUT_REL4ADR) {
+ if (type == OUT_ADDRESS)
+ size = abs((int)size);
+ else if (segment == NO_SEG)
+ nasm_nonfatal("relative call to absolute address not"
+ " supported by IEEE format");
+ ldata = *(int64_t *)data;
+ if (type == OUT_REL2ADR)
+ ldata += (size - 2);
+ if (type == OUT_REL4ADR)
+ ldata += (size - 4);
+ ieee_write_fixup(segment, wrt, seg, size, type, ldata);
+ if (size == 2)
+ ieee_write_word(seg, ldata);
+ else
+ ieee_write_dword(seg, ldata);
+ } else if (type == OUT_RESERVE) {
+ while (size--)
+ ieee_write_byte(seg, 0);
+ }
+}
+
+static void ieee_data_new(struct ieeeSection *segto)
+{
+
+ if (!segto->data)
+ segto->data = segto->datacurr =
+ nasm_malloc(sizeof(*(segto->datacurr)));
+ else
+ segto->datacurr = segto->datacurr->next =
+ nasm_malloc(sizeof(*(segto->datacurr)));
+ segto->datacurr->next = NULL;
+}
+
+/*
+ * this routine is unalduterated bloatware. I usually don't do this
+ * but I might as well see what it is like on a harmless program.
+ * If anyone wants to optimize this is a good canditate!
+ */
+static void ieee_write_fixup(int32_t segment, int32_t wrt,
+ struct ieeeSection *segto, int size,
+ uint64_t realtype, int32_t offset)
+{
+ struct ieeeSection *target;
+ struct ieeeFixupp s;
+
+ /* Don't put a fixup for things NASM can calculate */
+ if (wrt == NO_SEG && segment == NO_SEG)
+ return;
+
+ s.ftype = -1;
+ /* if it is a WRT offset */
+ if (wrt != NO_SEG) {
+ s.ftype = FT_WRT;
+ s.addend = offset;
+ if (wrt >= SEG_ABS)
+ s.id1 = -(wrt - SEG_ABS);
+ else {
+ if (wrt % 2 && realtype != OUT_REL2ADR
+ && realtype != OUT_REL4ADR) {
+ wrt--;
+
+ for (target = seghead; target; target = target->next)
+ if (target->index == wrt)
+ break;
+ if (target) {
+ s.id1 = target->ieee_index;
+ for (target = seghead; target; target = target->next)
+ if (target->index == segment)
+ break;
+
+ if (target)
+ s.id2 = target->ieee_index;
+ else {
+ /*
+ * Now we assume the segment field is being used
+ * to hold an extern index
+ */
+ int32_t i = segment / 2;
+ struct ExtBack *eb = ebhead;
+ while (i > EXT_BLKSIZ) {
+ if (eb)
+ eb = eb->next;
+ else
+ break;
+ i -= EXT_BLKSIZ;
+ }
+ /* if we have an extern decide the type and make a record
+ */
+ if (eb) {
+ s.ftype = FT_EXTWRT;
+ s.addend = 0;
+ s.id2 = eb->index[i];
+ } else
+ nasm_nonfatal("source of WRT must be an offset");
+ }
+
+ } else
+ nasm_panic("unrecognised WRT value in ieee_write_fixup");
+ } else
+ nasm_nonfatal("target of WRT must be a section");
+ }
+ s.size = size;
+ ieee_install_fixup(segto, &s);
+ return;
+ }
+ /* Pure segment fixup ? */
+ if (segment != NO_SEG) {
+ s.ftype = FT_SEG;
+ s.id1 = 0;
+ if (segment >= SEG_ABS) {
+ /* absolute far segment fixup */
+ s.id1 = -(segment - ~SEG_ABS);
+ } else if (segment % 2) {
+ /* fixup to named segment */
+ /* look it up */
+ for (target = seghead; target; target = target->next)
+ if (target->index == segment - 1)
+ break;
+ if (target)
+ s.id1 = target->ieee_index;
+ else {
+ /*
+ * Now we assume the segment field is being used
+ * to hold an extern index
+ */
+ int32_t i = segment / 2;
+ struct ExtBack *eb = ebhead;
+ while (i > EXT_BLKSIZ) {
+ if (eb)
+ eb = eb->next;
+ else
+ break;
+ i -= EXT_BLKSIZ;
+ }
+ /* if we have an extern decide the type and make a record
+ */
+ if (eb) {
+ if (realtype == OUT_REL2ADR || realtype == OUT_REL4ADR) {
+ nasm_panic("Segment of a rel not supported in ieee_write_fixup");
+ } else {
+ /* If we want the segment */
+ s.ftype = FT_EXTSEG;
+ s.addend = 0;
+ s.id1 = eb->index[i];
+ }
+
+ } else
+ /* If we get here the seg value doesn't make sense */
+ nasm_panic("unrecognised segment value in ieee_write_fixup");
+ }
+
+ } else {
+ /* Assume we are offsetting directly from a section
+ * So look up the target segment
+ */
+ for (target = seghead; target; target = target->next)
+ if (target->index == segment)
+ break;
+ if (target) {
+ if (realtype == OUT_REL2ADR || realtype == OUT_REL4ADR) {
+ /* PC rel to a known offset */
+ s.id1 = target->ieee_index;
+ s.ftype = FT_REL;
+ s.size = size;
+ s.addend = offset;
+ } else {
+ /* We were offsetting from a seg */
+ s.id1 = target->ieee_index;
+ s.ftype = FT_OFS;
+ s.size = size;
+ s.addend = offset;
+ }
+ } else {
+ /*
+ * Now we assume the segment field is being used
+ * to hold an extern index
+ */
+ int32_t i = segment / 2;
+ struct ExtBack *eb = ebhead;
+ while (i > EXT_BLKSIZ) {
+ if (eb)
+ eb = eb->next;
+ else
+ break;
+ i -= EXT_BLKSIZ;
+ }
+ /* if we have an extern decide the type and make a record
+ */
+ if (eb) {
+ if (realtype == OUT_REL2ADR || realtype == OUT_REL4ADR) {
+ s.ftype = FT_EXTREL;
+ s.addend = 0;
+ s.id1 = eb->index[i];
+ } else {
+ /* else we want the external offset */
+ s.ftype = FT_EXT;
+ s.addend = 0;
+ s.id1 = eb->index[i];
+ }
+
+ } else
+ /* If we get here the seg value doesn't make sense */
+ nasm_panic("unrecognised segment value in ieee_write_fixup");
+ }
+ }
+ if (size != 2 && s.ftype == FT_SEG)
+ nasm_nonfatal("IEEE format can only handle 2-byte"
+ " segment base references");
+ s.size = size;
+ ieee_install_fixup(segto, &s);
+ return;
+ }
+ /* should never get here */
+}
+static void ieee_install_fixup(struct ieeeSection *seg,
+ struct ieeeFixupp *fix)
+{
+ struct ieeeFixupp *f;
+ f = nasm_malloc(sizeof(struct ieeeFixupp));
+ memcpy(f, fix, sizeof(struct ieeeFixupp));
+ f->offset = seg->currentpos;
+ seg->currentpos += fix->size;
+ f->next = NULL;
+ if (seg->fptr)
+ seg->flptr = seg->flptr->next = f;
+ else
+ seg->fptr = seg->flptr = f;
+
+}
+
+/*
+ * segment registry
+ */
+static int32_t ieee_segment(char *name, int *bits)
+{
+ /*
+ * We call the label manager here to define a name for the new
+ * segment, and when our _own_ label-definition stub gets
+ * called in return, it should register the new segment name
+ * using the pointer it gets passed. That way we save memory,
+ * by sponging off the label manager.
+ */
+ if (!name) {
+ *bits = 16;
+ if (!any_segs)
+ return 0;
+ return seghead->index;
+ } else {
+ struct ieeeSection *seg;
+ int ieee_idx, attrs;
+ bool rn_error;
+ char *p;
+
+ /*
+ * Look for segment attributes.
+ */
+ attrs = 0;
+ while (*name == '.')
+ name++; /* hack, but a documented one */
+ p = name;
+ while (*p && !nasm_isspace(*p))
+ p++;
+ if (*p) {
+ *p++ = '\0';
+ while (*p && nasm_isspace(*p))
+ *p++ = '\0';
+ }
+ while (*p) {
+ while (*p && !nasm_isspace(*p))
+ p++;
+ if (*p) {
+ *p++ = '\0';
+ while (*p && nasm_isspace(*p))
+ *p++ = '\0';
+ }
+
+ attrs++;
+ }
+
+ ieee_idx = 1;
+ for (seg = seghead; seg; seg = seg->next) {
+ ieee_idx++;
+ if (!strcmp(seg->name, name)) {
+ if (attrs > 0 && seg->pass_last_seen == pass_count())
+ nasm_warn(WARN_OTHER, "segment attributes specified on"
+ " redeclaration of segment: ignoring");
+ if (seg->use32)
+ *bits = 32;
+ else
+ *bits = 16;
+
+ seg->pass_last_seen = pass_count();
+ return seg->index;
+ }
+ }
+
+ *segtail = seg = nasm_malloc(sizeof(*seg));
+ seg->next = NULL;
+ segtail = &seg->next;
+ seg->index = seg_alloc();
+ seg->ieee_index = ieee_idx;
+ any_segs = true;
+ seg->name = NULL;
+ seg->currentpos = 0;
+ seg->align = 1; /* default */
+ seg->use32 = *bits == 32; /* default to user spec */
+ seg->combine = CMB_PUBLIC; /* default */
+ seg->pubhead = NULL;
+ seg->pubtail = &seg->pubhead;
+ seg->data = NULL;
+ seg->fptr = NULL;
+ seg->lochead = NULL;
+ seg->loctail = &seg->lochead;
+
+ /*
+ * Process the segment attributes.
+ */
+ p = name;
+ while (attrs--) {
+ p += strlen(p);
+ while (!*p)
+ p++;
+
+ /*
+ * `p' contains a segment attribute.
+ */
+ if (!nasm_stricmp(p, "private"))
+ seg->combine = CMB_PRIVATE;
+ else if (!nasm_stricmp(p, "public"))
+ seg->combine = CMB_PUBLIC;
+ else if (!nasm_stricmp(p, "common"))
+ seg->combine = CMB_COMMON;
+ else if (!nasm_stricmp(p, "use16"))
+ seg->use32 = false;
+ else if (!nasm_stricmp(p, "use32"))
+ seg->use32 = true;
+ else if (!nasm_strnicmp(p, "align=", 6)) {
+ seg->align = readnum(p + 6, &rn_error);
+ if (seg->align == 0)
+ seg->align = 1;
+ if (rn_error) {
+ seg->align = 1;
+ nasm_nonfatal("segment alignment should be numeric");
+ }
+ switch (seg->align) {
+ case 1: /* BYTE */
+ case 2: /* WORD */
+ case 4: /* DWORD */
+ case 16: /* PARA */
+ case 256: /* PAGE */
+ case 8:
+ case 32:
+ case 64:
+ case 128:
+ break;
+ default:
+ nasm_nonfatal("invalid alignment value %d", seg->align);
+ seg->align = 1;
+ break;
+ }
+ } else if (!nasm_strnicmp(p, "absolute=", 9)) {
+ seg->align = SEG_ABS + readnum(p + 9, &rn_error);
+ if (rn_error)
+ nasm_nonfatal("argument to `absolute' segment"
+ " attribute should be numeric");
+ }
+ }
+
+ ieee_seg_needs_update = seg;
+ if (seg->align >= SEG_ABS)
+ define_label(name, NO_SEG, seg->align - SEG_ABS, false);
+ else
+ define_label(name, seg->index + 1, 0L, false);
+ ieee_seg_needs_update = NULL;
+
+ /*
+ * In commit 98578071b9d71ecaa2344dd9c185237c1765041e
+ * we reworked labels significantly which in turn lead
+ * to the case where seg->name = NULL here and we get
+ * nil dereference in next segments definitions.
+ *
+ * Lets placate this case with explicit name setting
+ * if labels engine didn't set it yet.
+ *
+ * FIXME: Need to revisit this moment if such fix doesn't
+ * break anything but since IEEE 695 format is veeery
+ * old I don't expect there are many users left. In worst
+ * case this should only lead to a memory leak.
+ */
+ if (!seg->name)
+ seg->name = nasm_strdup(name);
+
+ if (seg->use32)
+ *bits = 32;
+ else
+ *bits = 16;
+ return seg->index;
+ }
+}
+
+/*
+ * directives supported
+ */
+static enum directive_result
+ieee_directive(enum directive directive, char *value)
+{
+ (void)value;
+
+ switch (directive) {
+ case D_UPPERCASE:
+ ieee_uppercase = true;
+ return DIRR_OK;
+
+ default:
+ return DIRR_UNKNOWN;
+ }
+}
+
+static void ieee_sectalign(int32_t seg, unsigned int value)
+{
+ struct ieeeSection *s;
+
+ list_for_each(s, seghead) {
+ if (s->index == seg)
+ break;
+ }
+
+ /*
+ * 256 is maximum there, note it may happen
+ * that align is issued on "absolute" segment
+ * it's fine since SEG_ABS > 256 and we never
+ * get escape this test
+ */
+ if (!s || !is_power2(value) || value > 256)
+ return;
+
+ if ((unsigned int)s->align < value)
+ s->align = value;
+}
+
+/*
+ * Return segment data
+ */
+static int32_t ieee_segbase(int32_t segment)
+{
+ struct ieeeSection *seg;
+
+ /*
+ * Find the segment in our list.
+ */
+ for (seg = seghead; seg; seg = seg->next)
+ if (seg->index == segment - 1)
+ break;
+
+ if (!seg)
+ return segment; /* not one of ours - leave it alone */
+
+ if (seg->align >= SEG_ABS)
+ return seg->align; /* absolute segment */
+
+ return segment; /* no special treatment */
+}
+
+static void ieee_write_file(void)
+{
+ const struct tm * const thetime = &official_compile_time.local;
+ struct FileName *fn;
+ struct ieeeSection *seg;
+ struct ieeePublic *pub, *loc;
+ struct ieeeExternal *ext;
+ struct ieeeObjData *data;
+ struct ieeeFixupp *fix;
+ struct Array *arr;
+ int i;
+ const bool debuginfo = (dfmt == &ladsoft_debug_form);
+
+ /*
+ * Write the module header
+ */
+ ieee_putascii("MBFNASM,%02X%s.\n", strlen(ieee_infile), ieee_infile);
+
+ /*
+ * Write the NASM boast comment.
+ */
+ ieee_putascii("CO0,%02X%s.\n", nasm_comment_len(), nasm_comment());
+
+ /*
+ * write processor-specific information
+ */
+ ieee_putascii("AD8,4,L.\n");
+
+ /*
+ * date and time
+ */
+ ieee_putascii("DT%04d%02d%02d%02d%02d%02d.\n",
+ 1900 + thetime->tm_year, thetime->tm_mon + 1,
+ thetime->tm_mday, thetime->tm_hour, thetime->tm_min,
+ thetime->tm_sec);
+ /*
+ * if debugging, dump file names
+ */
+ for (fn = fnhead; fn && debuginfo; fn = fn->next) {
+ ieee_putascii("C0105,%02X%s.\n", strlen(fn->name), fn->name);
+ }
+
+ ieee_putascii("CO101,07ENDHEAD.\n");
+ /*
+ * the standard doesn't specify when to put checksums,
+ * we'll just do it periodically.
+ */
+ ieee_putcs(false);
+
+ /*
+ * Write the section headers
+ */
+ seg = seghead;
+ if (!debuginfo && seg && !strcmp(seg->name, "??LINE"))
+ seg = seg->next;
+ while (seg) {
+ char buf[256];
+ char attrib;
+ switch (seg->combine) {
+ case CMB_PUBLIC:
+ default:
+ attrib = 'C';
+ break;
+ case CMB_PRIVATE:
+ attrib = 'S';
+ break;
+ case CMB_COMMON:
+ attrib = 'M';
+ break;
+ }
+ ieee_unqualified_name(buf, seg->name);
+ if (seg->align >= SEG_ABS) {
+ ieee_putascii("ST%X,A,%02X%s.\n", seg->ieee_index,
+ strlen(buf), buf);
+ ieee_putascii("ASL%X,%lX.\n", seg->ieee_index,
+ (seg->align - SEG_ABS) * 16);
+ } else {
+ ieee_putascii("ST%X,%c,%02X%s.\n", seg->ieee_index, attrib,
+ strlen(buf), buf);
+ ieee_putascii("SA%X,%lX.\n", seg->ieee_index, seg->align);
+ ieee_putascii("ASS%X,%X.\n", seg->ieee_index,
+ seg->currentpos);
+ }
+ seg = seg->next;
+ }
+ /*
+ * write the start address if there is one
+ */
+ if (ieee_entry_seg && seghead) {
+ for (seg = seghead; seg; seg = seg->next)
+ if (seg->index == ieee_entry_seg)
+ break;
+ if (!seg)
+ nasm_panic("Start address records are incorrect");
+ else
+ ieee_putascii("ASG,R%X,%lX,+.\n", seg->ieee_index,
+ ieee_entry_ofs);
+ }
+
+ ieee_putcs(false);
+ /*
+ * Write the publics
+ */
+ i = 1;
+ for (seg = seghead; seg; seg = seg->next) {
+ for (pub = seg->pubhead; pub; pub = pub->next) {
+ char buf[256];
+ ieee_unqualified_name(buf, pub->name);
+ ieee_putascii("NI%X,%02X%s.\n", i, strlen(buf), buf);
+ if (pub->segment == -1)
+ ieee_putascii("ASI%X,R%X,%lX,+.\n", i, pub->index,
+ pub->offset);
+ else
+ ieee_putascii("ASI%X,%lX,%lX,+.\n", i, pub->segment * 16,
+ pub->offset);
+ if (debuginfo) {
+ if (pub->type >= 0x100)
+ ieee_putascii("ATI%X,T%X.\n", i, pub->type - 0x100);
+ else
+ ieee_putascii("ATI%X,%X.\n", i, pub->type);
+ }
+ i++;
+ }
+ }
+ pub = fpubhead;
+ i = 1;
+ while (pub) {
+ char buf[256];
+ ieee_unqualified_name(buf, pub->name);
+ ieee_putascii("NI%X,%02X%s.\n", i, strlen(buf), buf);
+ if (pub->segment == -1)
+ ieee_putascii("ASI%X,R%X,%lX,+.\n", i, pub->index,
+ pub->offset);
+ else
+ ieee_putascii("ASI%X,%lX,%lX,+.\n", i, pub->segment * 16,
+ pub->offset);
+ if (debuginfo) {
+ if (pub->type >= 0x100)
+ ieee_putascii("ATI%X,T%X.\n", i, pub->type - 0x100);
+ else
+ ieee_putascii("ATI%X,%X.\n", i, pub->type);
+ }
+ i++;
+ pub = pub->next;
+ }
+ /*
+ * Write the externals
+ */
+ ext = exthead;
+ i = 1;
+ while (ext) {
+ char buf[256];
+ ieee_unqualified_name(buf, ext->name);
+ ieee_putascii("NX%X,%02X%s.\n", i++, strlen(buf), buf);
+ ext = ext->next;
+ }
+ ieee_putcs(false);
+
+ /*
+ * IEEE doesn't have a standard pass break record
+ * so use the ladsoft variant
+ */
+ ieee_putascii("CO100,06ENDSYM.\n");
+
+ /*
+ * now put types
+ */
+ i = ARRAY_BOT;
+ for (arr = arrhead; arr && debuginfo; arr = arr->next) {
+ ieee_putascii("TY%X,20,%X,%lX.\n", i++, arr->basetype,
+ arr->size);
+ }
+ /*
+ * now put locals
+ */
+ i = 1;
+ for (seg = seghead; seg && debuginfo; seg = seg->next) {
+ for (loc = seg->lochead; loc; loc = loc->next) {
+ char buf[256];
+ ieee_unqualified_name(buf, loc->name);
+ ieee_putascii("NN%X,%02X%s.\n", i, strlen(buf), buf);
+ if (loc->segment == -1)
+ ieee_putascii("ASN%X,R%X,%lX,+.\n", i, loc->index,
+ loc->offset);
+ else
+ ieee_putascii("ASN%X,%lX,%lX,+.\n", i, loc->segment * 16,
+ loc->offset);
+ if (debuginfo) {
+ if (loc->type >= 0x100)
+ ieee_putascii("ATN%X,T%X.\n", i, loc->type - 0x100);
+ else
+ ieee_putascii("ATN%X,%X.\n", i, loc->type);
+ }
+ i++;
+ }
+ }
+
+ /*
+ * put out section data;
+ */
+ seg = seghead;
+ if (!debuginfo && seg && !strcmp(seg->name, "??LINE"))
+ seg = seg->next;
+ while (seg) {
+ if (seg->currentpos) {
+ int32_t size, org = 0;
+ data = seg->data;
+ ieee_putascii("SB%X.\n", seg->ieee_index);
+ fix = seg->fptr;
+ while (fix) {
+ size = HUNKSIZE - (org % HUNKSIZE);
+ size =
+ size + org >
+ seg->currentpos ? seg->currentpos - org : size;
+ size = fix->offset - org > size ? size : fix->offset - org;
+ org = ieee_putld(org, org + size, data->data);
+ if (org % HUNKSIZE == 0)
+ data = data->next;
+ if (org == fix->offset) {
+ org += ieee_putlr(fix);
+ fix = fix->next;
+ }
+ }
+ while (org < seg->currentpos && data) {
+ size =
+ seg->currentpos - org >
+ HUNKSIZE ? HUNKSIZE : seg->currentpos - org;
+ org = ieee_putld(org, org + size, data->data);
+ data = data->next;
+ }
+ ieee_putcs(false);
+
+ }
+ seg = seg->next;
+ }
+ /*
+ * module end record
+ */
+ ieee_putascii("ME.\n");
+}
+
+static void ieee_write_byte(struct ieeeSection *seg, int data)
+{
+ int temp;
+ if (!(temp = seg->currentpos++ % HUNKSIZE))
+ ieee_data_new(seg);
+ seg->datacurr->data[temp] = data;
+}
+
+static void ieee_write_word(struct ieeeSection *seg, int data)
+{
+ ieee_write_byte(seg, data & 0xFF);
+ ieee_write_byte(seg, (data >> 8) & 0xFF);
+}
+
+static void ieee_write_dword(struct ieeeSection *seg, int32_t data)
+{
+ ieee_write_byte(seg, data & 0xFF);
+ ieee_write_byte(seg, (data >> 8) & 0xFF);
+ ieee_write_byte(seg, (data >> 16) & 0xFF);
+ ieee_write_byte(seg, (data >> 24) & 0xFF);
+}
+static void printf_func(1, 2) ieee_putascii(char *format, ...)
+{
+ char buffer[256];
+ size_t i, l;
+ va_list ap;
+
+ va_start(ap, format);
+ l = vsnprintf(buffer, sizeof(buffer), format, ap);
+ nasm_assert(l < sizeof(buffer));
+ for (i = 0; i < l; i++)
+ if ((uint8_t)buffer[i] > 31)
+ checksum += buffer[i];
+ va_end(ap);
+ fputs(buffer, ofile);
+}
+
+/*
+ * put out a checksum record */
+static void ieee_putcs(int toclear)
+{
+ if (toclear) {
+ ieee_putascii("CS.\n");
+ } else {
+ checksum += 'C';
+ checksum += 'S';
+ ieee_putascii("CS%02X.\n", checksum & 127);
+ }
+ checksum = 0;
+}
+
+static int32_t ieee_putld(int32_t start, int32_t end, uint8_t *buf)
+{
+ int32_t val;
+ if (start == end)
+ return (start);
+ val = start % HUNKSIZE;
+ /* fill up multiple lines */
+ while (end - start >= LDPERLINE) {
+ int i;
+ ieee_putascii("LD");
+ for (i = 0; i < LDPERLINE; i++) {
+ ieee_putascii("%02X", buf[val++]);
+ start++;
+ }
+ ieee_putascii(".\n");
+ }
+ /* if no partial lines */
+ if (start == end)
+ return (start);
+ /* make a partial line */
+ ieee_putascii("LD");
+ while (start < end) {
+ ieee_putascii("%02X", buf[val++]);
+ start++;
+ }
+ ieee_putascii(".\n");
+ return (start);
+}
+static int32_t ieee_putlr(struct ieeeFixupp *p)
+{
+/*
+ * To deal with the vagaries of segmentation the LADsoft linker
+ * defines two types of segments: absolute and virtual. Note that
+ * 'absolute' in this context is a different thing from the IEEE
+ * definition of an absolute segment type, which is also supported. If a
+ * segment is linked in virtual mode the low limit (L-var) is
+ * subtracted from each R,X, and P variable which appears in an
+ * expression, so that we can have relative offsets. Meanwhile
+ * in the ABSOLUTE mode this subtraction is not done and
+ * so we can use absolute offsets from 0. In the LADsoft linker
+ * this configuration is not done in the assemblker source but in
+ * a source the linker reads. Generally this type of thing only
+ * becomes an issue if real mode code is used. A pure 32-bit linker could
+ * get away without defining the virtual mode...
+ */
+ char buf[40];
+ int32_t size = p->size;
+ switch (p->ftype) {
+ case FT_SEG:
+ if (p->id1 < 0)
+ sprintf(buf, "%"PRIX32"", -p->id1);
+ else
+ sprintf(buf, "L%"PRIX32",10,/", p->id1);
+ break;
+ case FT_OFS:
+ sprintf(buf, "R%"PRIX32",%"PRIX32",+", p->id1, p->addend);
+ break;
+ case FT_REL:
+ sprintf(buf, "R%"PRIX32",%"PRIX32",+,P,-,%X,-", p->id1, p->addend, p->size);
+ break;
+
+ case FT_WRT:
+ if (p->id2 < 0)
+ sprintf(buf, "R%"PRIX32",%"PRIX32",+,L%"PRIX32",+,%"PRIX32",-", p->id2, p->addend,
+ p->id2, -p->id1 * 16);
+ else
+ sprintf(buf, "R%"PRIX32",%"PRIX32",+,L%"PRIX32",+,L%"PRIX32",-", p->id2, p->addend,
+ p->id2, p->id1);
+ break;
+ case FT_EXT:
+ sprintf(buf, "X%"PRIX32"", p->id1);
+ break;
+ case FT_EXTREL:
+ sprintf(buf, "X%"PRIX32",P,-,%"PRIX32",-", p->id1, size);
+ break;
+ case FT_EXTSEG:
+ /* We needed a non-ieee hack here.
+ * We introduce the Y variable, which is the low
+ * limit of the native segment the extern resides in
+ */
+ sprintf(buf, "Y%"PRIX32",10,/", p->id1);
+ break;
+ case FT_EXTWRT:
+ if (p->id2 < 0)
+ sprintf(buf, "X%"PRIX32",Y%"PRIX32",+,%"PRIX32",-", p->id2, p->id2,
+ -p->id1 * 16);
+ else
+ sprintf(buf, "X%"PRIX32",Y%"PRIX32",+,L%"PRIX32",-", p->id2, p->id2, p->id1);
+ break;
+ }
+ ieee_putascii("LR(%s,%"PRIX32").\n", buf, size);
+
+ return (size);
+}
+
+/* Dump all segment data (text and fixups )*/
+
+static void ieee_unqualified_name(char *dest, char *source)
+{
+ if (ieee_uppercase) {
+ while (*source)
+ *dest++ = toupper(*source++);
+ *dest = 0;
+ } else
+ strcpy(dest, source);
+}
+static void dbgls_init(void)
+{
+ int tempint;
+
+ fnhead = NULL;
+ fntail = &fnhead;
+ arrindex = ARRAY_BOT;
+ arrhead = NULL;
+ arrtail = &arrhead;
+ ieee_segment("??LINE", &tempint);
+ any_segs = false;
+}
+static void dbgls_cleanup(void)
+{
+ struct ieeeSection *segtmp;
+ while (fnhead) {
+ struct FileName *fntemp = fnhead;
+ fnhead = fnhead->next;
+ nasm_free(fntemp->name);
+ nasm_free(fntemp);
+ }
+ for (segtmp = seghead; segtmp; segtmp = segtmp->next) {
+ while (segtmp->lochead) {
+ struct ieeePublic *loctmp = segtmp->lochead;
+ segtmp->lochead = loctmp->next;
+ nasm_free(loctmp->name);
+ nasm_free(loctmp);
+ }
+ }
+ while (arrhead) {
+ struct Array *arrtmp = arrhead;
+ arrhead = arrhead->next;
+ nasm_free(arrtmp);
+ }
+}
+
+/*
+ * because this routine is not bracketed in
+ * the main program, this routine will be called even if there
+ * is no request for debug info
+ * so, we have to make sure the ??LINE segment is available
+ * as the first segment when this debug format is selected
+ */
+static void dbgls_linnum(const char *lnfname, int32_t lineno, int32_t segto)
+{
+ struct FileName *fn;
+ struct ieeeSection *seg;
+ int i = 0;
+ if (segto == NO_SEG)
+ return;
+
+ /*
+ * If `any_segs' is still false, we must define a default
+ * segment.
+ */
+ if (!any_segs) {
+ int tempint; /* ignored */
+ if (segto != ieee_segment("__NASMDEFSEG", &tempint))
+ nasm_panic("strange segment conditions in IEEE driver");
+ }
+
+ /*
+ * Find the segment we are targeting.
+ */
+ for (seg = seghead; seg; seg = seg->next)
+ if (seg->index == segto)
+ break;
+ if (!seg)
+ nasm_panic("lineno directed to nonexistent segment?");
+
+ for (fn = fnhead; fn; fn = fn->next) {
+ if (!nasm_stricmp(lnfname, fn->name))
+ break;
+ i++;
+ }
+ if (!fn) {
+ fn = nasm_malloc(sizeof(*fn));
+ fn->name = nasm_malloc(strlen(lnfname) + 1);
+ fn->index = i;
+ strcpy(fn->name, lnfname);
+ fn->next = NULL;
+ *fntail = fn;
+ fntail = &fn->next;
+ }
+ ieee_write_byte(seghead, fn->index);
+ ieee_write_word(seghead, lineno);
+ ieee_write_fixup(segto, NO_SEG, seghead, 4, OUT_ADDRESS,
+ seg->currentpos);
+
+}
+static void dbgls_deflabel(char *name, int32_t segment,
+ int64_t offset, int is_global, char *special)
+{
+ struct ieeeSection *seg;
+
+ /* Keep compiler from warning about special */
+ (void)special;
+
+ /*
+ * Note: ..[^@] special symbols are filtered in labels.c
+ */
+
+ /*
+ * If it's a special-retry from pass two, discard it.
+ */
+ if (is_global == 3)
+ return;
+
+ /*
+ * Case (i):
+ */
+ if (ieee_seg_needs_update)
+ return;
+ if (segment < SEG_ABS && segment != NO_SEG && segment % 2)
+ return;
+
+ if (segment >= SEG_ABS || segment == NO_SEG) {
+ return;
+ }
+
+ /*
+ * If `any_segs' is still false, we might need to define a
+ * default segment, if they're trying to declare a label in
+ * `first_seg'. But the label should exist due to a prior
+ * call to ieee_deflabel so we can skip that.
+ */
+
+ for (seg = seghead; seg; seg = seg->next)
+ if (seg->index == segment) {
+ struct ieeePublic *loc;
+ /*
+ * Case (ii). Maybe MODPUB someday?
+ */
+ if (!is_global) {
+ last_defined = loc = nasm_malloc(sizeof(*loc));
+ *seg->loctail = loc;
+ seg->loctail = &loc->next;
+ loc->next = NULL;
+ loc->name = nasm_strdup(name);
+ loc->offset = offset;
+ loc->segment = -1;
+ loc->index = seg->ieee_index;
+ }
+ }
+}
+static void dbgls_typevalue(int32_t type)
+{
+ int elem = TYM_ELEMENTS(type);
+ type = TYM_TYPE(type);
+
+ if (!last_defined)
+ return;
+
+ switch (type) {
+ case TY_BYTE:
+ last_defined->type = 1; /* uint8_t */
+ break;
+ case TY_WORD:
+ last_defined->type = 3; /* unsigned word */
+ break;
+ case TY_DWORD:
+ last_defined->type = 5; /* unsigned dword */
+ break;
+ case TY_FLOAT:
+ last_defined->type = 9; /* float */
+ break;
+ case TY_QWORD:
+ last_defined->type = 10; /* qword */
+ break;
+ case TY_TBYTE:
+ last_defined->type = 11; /* TBYTE */
+ break;
+ default:
+ last_defined->type = 0x10; /* near label */
+ break;
+ }
+
+ if (elem > 1) {
+ struct Array *arrtmp = nasm_malloc(sizeof(*arrtmp));
+ int vtype = last_defined->type;
+ arrtmp->size = elem;
+ arrtmp->basetype = vtype;
+ arrtmp->next = NULL;
+ last_defined->type = arrindex++ + 0x100;
+ *arrtail = arrtmp;
+ arrtail = &(arrtmp->next);
+ }
+ last_defined = NULL;
+}
+static void dbgls_output(int output_type, void *param)
+{
+ (void)output_type;
+ (void)param;
+}
+static const struct dfmt ladsoft_debug_form = {
+ "LADsoft Debug Records",
+ "ladsoft",
+ dbgls_init,
+ dbgls_linnum,
+ dbgls_deflabel,
+ NULL, /* .debug_smacros */
+ NULL, /* .debug_include */
+ NULL, /* .debug_mmacros */
+ null_debug_directive,
+ dbgls_typevalue,
+ dbgls_output,
+ dbgls_cleanup,
+ NULL /* pragma list */
+};
+static const struct dfmt * const ladsoft_debug_arr[3] = {
+ &ladsoft_debug_form,
+ &null_debug_form,
+ NULL
+};
+const struct ofmt of_ieee = {
+ "IEEE-695 (LADsoft variant) object file format",
+ "ieee",
+ ".o",
+ OFMT_TEXT,
+ 32,
+ ladsoft_debug_arr,
+ &ladsoft_debug_form,
+ NULL,
+ ieee_init,
+ null_reset,
+ nasm_do_legacy_output,
+ ieee_out,
+ ieee_deflabel,
+ ieee_segment,
+ NULL,
+ ieee_sectalign,
+ ieee_segbase,
+ ieee_directive,
+ ieee_cleanup,
+ NULL /* pragma list */
+};
+
+#endif /* OF_IEEE */