📄 outieee.c
字号:
/* outieee.c output routines for the Netwide Assembler to produce
* IEEE-std object files
*
* The Netwide Assembler is copyright (C) 1996 Simon Tatham and
* Julian Hall. All rights reserved. The software is
* redistributable under the licence given in the file "Licence"
* distributed in the NASM archive.
*/
/* 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 <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 "outform.h"
#ifdef OF_IEEE
#define ARRAY_BOT 0x1
static char ieee_infile[FILENAME_MAX];
static int ieee_uppercase;
static efunc error;
static ldfunc deflabel;
static FILE *ofp;
static int 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;
long offset;
long lineno;
};
static struct FileName {
struct FileName *next;
char *name;
long index;
} *fnhead, **fntail;
static struct Array {
struct Array *next;
unsigned size;
int basetype;
} *arrhead, **arrtail;
static struct ieeePublic {
struct ieeePublic *next;
char *name;
long offset;
long segment; /* only if it's far-absolute */
long index;
int type; /* for debug purposes */
} *fpubhead, **fpubtail, *last_defined;
static struct ieeeExternal {
struct ieeeExternal *next;
char *name;
long 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 ieeeObjData *data,*datacurr;
struct ieeeSection *next;
struct ieeeFixupp *fptr, * flptr;
long index; /* the NASM segment id */
long ieee_index; /* the OBJ-file segment index */
long currentpos;
long align; /* can be SEG_ABS + absolute addr */
long startpos;
enum {
CMB_PRIVATE = 0,
CMB_PUBLIC = 2,
CMB_COMMON = 6
} combine;
long use32; /* is this segment 32-bit? */
struct ieeePublic *pubhead, **pubtail, *lochead, **loctail;
char *name;
} *seghead, **segtail, *ieee_seg_needs_update;
struct ieeeObjData {
struct ieeeObjData *next;
unsigned char 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;
short size;
long id1;
long id2;
long offset;
long addend;
};
static long ieee_entry_seg, ieee_entry_ofs;
static int checksum;
extern struct ofmt of_ieee;
static void ieee_data_new(struct ieeeSection *);
static void ieee_write_fixup (long, long, struct ieeeSection *,
int, unsigned long, long);
static void ieee_install_fixup(struct ieeeSection *, struct ieeeFixupp *);
static long ieee_segment (char *, int, int *);
static void ieee_write_file(int debuginfo);
static void ieee_write_byte(struct ieeeSection *, int);
static void ieee_write_word(struct ieeeSection *, int);
static void ieee_write_dword(struct ieeeSection *, long);
static void ieee_putascii(char *, ...);
static void ieee_putcs(int);
static long ieee_putld(long, long, unsigned char *);
static long ieee_putlr(struct ieeeFixupp *);
static void ieee_unqualified_name(char *, char *);
/*
* pup init
*/
static void ieee_init (FILE *fp, efunc errfunc, ldfunc ldef, evalfunc eval)
{
(void) eval;
ofp = fp;
error = errfunc;
deflabel = ldef;
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;
of_ieee.current_dfmt->init (&of_ieee,NULL,fp,errfunc);
}
static int ieee_set_info(enum geninfo type, char **val)
{
(void) type;
(void) val;
return 0;
}
/*
* Rundown
*/
static void ieee_cleanup (int debuginfo)
{
ieee_write_file(debuginfo);
of_ieee.current_dfmt->cleanup ();
fclose (ofp);
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, long segment,
long 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) {
error(ERR_NONFATAL, "unrecognised symbol type `%s'", special);
}
/*
* First check for the double-period, signifying something
* unusual.
*/
if (name[0] == '.' && name[1] == '.') {
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_malloc(sizeof(*eb));
eb->next = NULL;
ebtail = &eb->next;
}
while (i > EXT_BLKSIZ) {
if (eb && eb->next)
eb = eb->next;
else {
eb = *ebtail = nasm_malloc(sizeof(*eb));
eb->next = NULL;
ebtail = &eb->next;
}
i -= EXT_BLKSIZ;
}
eb->index[i] = externals++;
}
}
/*
* Put data out
*/
static void ieee_out (long segto, const void *data, unsigned long type,
long segment, long wrt) {
unsigned long size, realtype;
const unsigned char *ucdata;
long ldata;
struct ieeeSection *seg;
/*
* handle absolute-assembly (structure definitions)
*/
if (segto == NO_SEG) {
if ((type & OUT_TYPMASK) != OUT_RESERVE)
error (ERR_NONFATAL, "attempt to assemble code in [ABSOLUTE]"
" space");
return;
}
/*
* If `any_segs' is still FALSE, we must define a default
* segment.
*/
if (!any_segs) {
int tempint; /* ignored */
if (segto != ieee_segment("__NASMDEFSEG", 2, &tempint))
error (ERR_PANIC, "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)
error (ERR_PANIC, "code directed to nonexistent segment?");
size = type & OUT_SIZMASK;
realtype = type & OUT_TYPMASK;
if (realtype == OUT_RAWDATA) {
ucdata = data;
while (size--)
ieee_write_byte(seg,*ucdata++);
} else if (realtype == OUT_ADDRESS || realtype == OUT_REL2ADR ||
realtype == OUT_REL4ADR) {
if (segment == NO_SEG && realtype != OUT_ADDRESS)
error(ERR_NONFATAL, "relative call to absolute address not"
" supported by IEEE format");
ldata = *(long *)data;
if (realtype == OUT_REL2ADR)
ldata += (size-2);
if (realtype == OUT_REL4ADR)
ldata += (size-4);
ieee_write_fixup (segment, wrt, seg, size, realtype,ldata);
if (size == 2)
ieee_write_word (seg, ldata);
else
ieee_write_dword (seg, ldata);
}
else if (realtype == 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 (long segment, long wrt, struct ieeeSection * segto,
int size, unsigned long realtype, long 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
*/
long i = segment/2;
struct ExtBack *eb = ebhead;
while (i > EXT_BLKSIZ) {
if (eb)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -