| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522 |
- /* ----------------------------------------------------------------------- *
- *
- * Copyright 1996-2016 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 <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <time.h>
- #include <stdarg.h> /* Note: we need the ANSI version of stdarg.h */
- #include <ctype.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 OBJ-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? */
- 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, 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_error(ERR_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;
- /*
- * handle absolute-assembly (structure definitions)
- */
- if (segto == NO_SEG) {
- if (type != OUT_RESERVE)
- nasm_error(ERR_NONFATAL, "attempt to assemble code in [ABSOLUTE]"
- " space");
- return;
- }
- /*
- * If `any_segs' is still false, we must define a default
- * segment.
- */
- if (!any_segs) {
- int tempint; /* ignored */
- if (segto != ieee_segment("__NASMDEFSEG", 2, &tempint))
- nasm_panic(0, "strange segment conditions in IEEE driver");
- }
- /*
- * Find the segment we are targetting.
- */
- for (seg = seghead; seg; seg = seg->next)
- if (seg->index == segto)
- break;
- if (!seg)
- nasm_panic(0, "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_error(ERR_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_error(ERR_NONFATAL,
- "Source of WRT must be an offset");
- }
- } else
- nasm_panic(0,
- "unrecognised WRT value in ieee_write_fixup");
- } else
- nasm_error(ERR_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(0,
- "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(0,
- "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(0,
- "unrecognised segment value in ieee_write_fixup");
- }
- }
- if (size != 2 && s.ftype == FT_SEG)
- nasm_error(ERR_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 pass, 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 && pass == 1)
- nasm_error(ERR_WARNING, "segment attributes specified on"
- " redeclaration of segment: ignoring");
- if (seg->use32)
- *bits = 32;
- else
- *bits = 16;
- 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_error(ERR_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_error(ERR_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_error(ERR_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;
- if (seg->use32)
- *bits = 32;
- else
- *bits = 16;
- return seg->index;
- }
- }
- /*
- * directives supported
- */
- static enum directive_result
- ieee_directive(enum directive directive, char *value, int pass)
- {
- (void)value;
- (void)pass;
- 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", strlen(nasm_comment), 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 && !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) {
- for (seg = seghead; seg; seg = seg->next)
- if (seg->index == ieee_entry_seg)
- break;
- if (!seg)
- nasm_panic(0, "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 && !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 ieee_putascii(char *format, ...)
- {
- char buffer[256];
- int i, l;
- va_list ap;
- va_start(ap, format);
- vsnprintf(buffer, sizeof(buffer), format, ap);
- l = strlen(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
- * sement 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", 2, &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 avaialbe
- * 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", 2, &tempint))
- nasm_panic(0, "strange segment conditions in OBJ driver");
- }
- /*
- * Find the segment we are targetting.
- */
- for (seg = seghead; seg; seg = seg->next)
- if (seg->index == segto)
- break;
- if (!seg)
- nasm_panic(0, "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_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 */
|