summaryrefslogtreecommitdiff
path: root/outobj.c
diff options
context:
space:
mode:
Diffstat (limited to 'outobj.c')
-rw-r--r--outobj.c1608
1 files changed, 1163 insertions, 445 deletions
diff --git a/outobj.c b/outobj.c
index f54d297..0a7544d 100644
--- a/outobj.c
+++ b/outobj.c
@@ -1,5 +1,5 @@
/* outobj.c output routines for the Netwide Assembler to produce
- * Microsoft 16-bit .OBJ object files
+ * .OBJ object files
*
* The Netwide Assembler is copyright (C) 1996 Simon Tatham and
* Julian Hall. All rights reserved. The software is
@@ -18,8 +18,446 @@
#ifdef OF_OBJ
+/*
+ * outobj.c is divided into two sections. The first section is low level
+ * routines for creating obj records; It has nearly zero NASM specific
+ * code. The second section is high level routines for processing calls and
+ * data structures from the rest of NASM into obj format.
+ *
+ * It should be easy (though not zero work) to lift the first section out for
+ * use as an obj file writer for some other assembler or compiler.
+ */
+
+/*
+ * These routines are built around the ObjRecord data struture. An ObjRecord
+ * holds an object file record that may be under construction or complete.
+ *
+ * A major function of these routines is to support continuation of an obj
+ * record into the next record when the maximum record size is exceeded. The
+ * high level code does not need to worry about where the record breaks occur.
+ * It does need to do some minor extra steps to make the automatic continuation
+ * work. Those steps may be skipped for records where the high level knows no
+ * continuation could be required.
+ *
+ * 1) An ObjRecord is allocated and cleared by obj_new, or an existing ObjRecord
+ * is cleared by obj_clear.
+ *
+ * 2) The caller should fill in .type.
+ *
+ * 3) If the record is continuable and there is processing that must be done at
+ * the start of each record then the caller should fill in .ori with the
+ * address of the record initializer routine.
+ *
+ * 4) If the record is continuable and it should be saved (rather than emitted
+ * immediately) as each record is done, the caller should set .up to be a
+ * pointer to a location in which the caller keeps the master pointer to the
+ * ObjRecord. When the record is continued, the obj_bump routine will then
+ * allocate a new ObjRecord structure and update the master pointer.
+ *
+ * 5) If the .ori field was used then the caller should fill in the .parm with
+ * any data required by the initializer.
+ *
+ * 6) The caller uses the routines: obj_byte, obj_word, obj_rword, obj_dword,
+ * obj_x, obj_index, obj_value and obj_name to fill in the various kinds of
+ * data required for this record.
+ *
+ * 7) If the record is continuable, the caller should call obj_commit at each
+ * point where breaking the record is permitted.
+ *
+ * 8) To write out the record, the caller should call obj_emit2. If the
+ * caller has called obj_commit for all data written then he can get slightly
+ * faster code by calling obj_emit instead of obj_emit2.
+ *
+ * Most of these routines return an ObjRecord pointer. This will be the input
+ * pointer most of the time and will be the new location if the ObjRecord
+ * moved as a result of the call. The caller may ignore the return value in
+ * three cases: It is a "Never Reallocates" routine; or The caller knows
+ * continuation is not possible; or The caller uses the master pointer for the
+ * next operation.
+ */
+
+#define RECORD_MAX 1024 /* maximum size of _any_ record */
+#define OBJ_PARMS 3 /* maximum .parm used by any .ori routine */
+
+#define FIX_08_LOW 0x8000 /* location type for various fixup subrecords */
+#define FIX_16_OFFSET 0x8400
+#define FIX_16_SELECTOR 0x8800
+#define FIX_32_POINTER 0x8C00
+#define FIX_08_HIGH 0x9000
+#define FIX_32_OFFSET 0xA400
+#define FIX_48_POINTER 0xAC00
+
+enum RecordID { /* record ID codes */
+
+ THEADR = 0x80, /* module header */
+ COMENT = 0x88, /* comment record */
+
+ LINNUM = 0x94, /* line number record */
+ LNAMES = 0x96, /* list of names */
+
+ SEGDEF = 0x98, /* segment definition */
+ GRPDEF = 0x9A, /* group definition */
+ EXTDEF = 0x8C, /* external definition */
+ PUBDEF = 0x90, /* public definition */
+ COMDEF = 0xB0, /* common definition */
+
+ LEDATA = 0xA0, /* logical enumerated data */
+ FIXUPP = 0x9C, /* fixups (relocations) */
+
+ MODEND = 0x8A /* module end */
+};
+
+enum ComentID { /* ID codes for comment records */
+
+ dEXTENDED = 0xA1, /* tells that we are using translator-specific extensions */
+ dLINKPASS = 0xA2, /* link pass 2 marker */
+ dTYPEDEF = 0xE3, /* define a type */
+ dSYM = 0xE6, /* symbol debug record */
+ dFILNAME = 0xE8, /* file name record */
+ dCOMPDEF = 0xEA /* compiler type info */
+
+};
+
+typedef struct ObjRecord ObjRecord;
+typedef void ORI(ObjRecord *orp);
+
+struct ObjRecord {
+ ORI *ori; /* Initialization routine */
+ int used; /* Current data size */
+ int committed; /* Data size at last boundary */
+ int x_size; /* (see obj_x) */
+ unsigned int type; /* Record type */
+ ObjRecord *child; /* Associated record below this one */
+ ObjRecord **up; /* Master pointer to this ObjRecord */
+ ObjRecord *back; /* Previous part of this record */
+ unsigned long parm[OBJ_PARMS]; /* Parameters for ori routine */
+ unsigned char buf[RECORD_MAX];
+};
+
+static void obj_fwrite(ObjRecord *orp);
+static void ori_ledata(ObjRecord *orp);
+static void ori_pubdef(ObjRecord *orp);
+static void ori_null(ObjRecord *orp);
+static ObjRecord *obj_commit(ObjRecord *orp);
+static void obj_write_fixup (ObjRecord *orp, int bytes,
+ int segrel, long seg, long wrt);
+
+static int obj_uppercase; /* Flag: all names in uppercase */
+
+/*
+ * Clear an ObjRecord structure. (Never reallocates).
+ * To simplify reuse of ObjRecord's, .type, .ori and .parm are not cleared.
+ */
+static ObjRecord *obj_clear(ObjRecord *orp)
+{
+ orp->used = 0;
+ orp->committed = 0;
+ orp->x_size = 0;
+ orp->child = NULL;
+ orp->up = NULL;
+ orp->back = NULL;
+ return (orp);
+}
+
+/*
+ * Emit an ObjRecord structure. (Never reallocates).
+ * The record is written out preceeded (recursively) by its previous part (if
+ * any) and followed (recursively) by its child (if any).
+ * The previous part and the child are freed. The main ObjRecord is cleared,
+ * not freed.
+ */
+static ObjRecord *obj_emit(ObjRecord *orp)
+{
+ if (orp->back) {
+ obj_emit(orp->back);
+ nasm_free(orp->back);
+ }
+
+ if (orp->committed)
+ obj_fwrite(orp);
+
+ if (orp->child) {
+ obj_emit(orp->child);
+ nasm_free(orp->child);
+ }
+
+ return (obj_clear(orp));
+}
+
+/*
+ * Commit and Emit a record. (Never reallocates).
+ */
+static ObjRecord *obj_emit2(ObjRecord *orp)
+{
+ obj_commit(orp);
+ return (obj_emit(orp));
+}
+
+/*
+ * Allocate and clear a new ObjRecord; Also sets .ori to ori_null
+ */
+static ObjRecord *obj_new(void)
+{
+ ObjRecord *orp;
+
+ orp = obj_clear( nasm_malloc(sizeof(ObjRecord)) );
+ orp->ori = ori_null;
+ return (orp);
+}
+
+/*
+ * Advance to the next record because the existing one is full or its x_size
+ * is incompatible.
+ * Any uncommited data is moved into the next record.
+ */
+static ObjRecord *obj_bump(ObjRecord *orp)
+{
+ ObjRecord *nxt;
+ int used = orp->used;
+ int committed = orp->committed;
+
+ if (orp->up) {
+ *orp->up = nxt = obj_new();
+ nxt->ori = orp->ori;
+ nxt->type = orp->type;
+ nxt->up = orp->up;
+ nxt->back = orp;
+ memcpy( nxt->parm, orp->parm, sizeof(orp->parm));
+ } else
+ nxt = obj_emit(orp);
+
+ used -= committed;
+ if (used) {
+ nxt->committed = 1;
+ nxt->ori (nxt);
+ nxt->committed = nxt->used;
+ memcpy( nxt->buf + nxt->committed, orp->buf + committed, used);
+ nxt->used = nxt->committed + used;
+ }
+
+ return (nxt);
+}
+
+/*
+ * Advance to the next record if necessary to allow the next field to fit.
+ */
+static ObjRecord *obj_check(ObjRecord *orp, int size)
+{
+ if (orp->used + size > RECORD_MAX)
+ orp = obj_bump(orp);
+
+ if (!orp->committed) {
+ orp->committed = 1;
+ orp->ori (orp);
+ orp->committed = orp->used;
+ }
+
+ return (orp);
+}
+
+/*
+ * All data written so far is commited to the current record (won't be moved to
+ * the next record in case of continuation).
+ */
+static ObjRecord *obj_commit(ObjRecord *orp)
+{
+ orp->committed = orp->used;
+ return (orp);
+}
+
+/*
+ * Write a byte
+ */
+static ObjRecord *obj_byte(ObjRecord *orp, unsigned char val)
+{
+ orp = obj_check(orp, 1);
+ orp->buf[orp->used] = val;
+ orp->used++;
+ return (orp);
+}
+
+/*
+ * Write a word
+ */
+static ObjRecord *obj_word(ObjRecord *orp, unsigned int val)
+{
+ orp = obj_check(orp, 2);
+ orp->buf[orp->used] = val;
+ orp->buf[orp->used+1] = val >> 8;
+ orp->used += 2;
+ return (orp);
+}
+
+/*
+ * Write a reversed word
+ */
+static ObjRecord *obj_rword(ObjRecord *orp, unsigned int val)
+{
+ orp = obj_check(orp, 2);
+ orp->buf[orp->used] = val >> 8;
+ orp->buf[orp->used+1] = val;
+ orp->used += 2;
+ return (orp);
+}
+
+/*
+ * Write a dword
+ */
+static ObjRecord *obj_dword(ObjRecord *orp, unsigned long val)
+{
+ orp = obj_check(orp, 4);
+ orp->buf[orp->used] = val;
+ orp->buf[orp->used+1] = val >> 8;
+ orp->buf[orp->used+2] = val >> 16;
+ orp->buf[orp->used+3] = val >> 24;
+ orp->used += 4;
+ return (orp);
+}
+
+/*
+ * All fields of "size x" in one obj record must be the same size (either 16
+ * bits or 32 bits). There is a one bit flag in each record which specifies
+ * which.
+ * This routine is used to force the current record to have the desired
+ * x_size. x_size is normally automatic (using obj_x), so that this
+ * routine should be used outside obj_x, only to provide compatibility with
+ * linkers that have bugs in their processing of the size bit.
+ */
+
+static ObjRecord *obj_force(ObjRecord *orp, int x)
+{
+ if (orp->x_size == (x^48))
+ orp = obj_bump(orp);
+ orp->x_size = x;
+ return (orp);
+}
+
+/*
+ * This routine writes a field of size x. The caller does not need to worry at
+ * all about whether 16-bits or 32-bits are required.
+ */
+static ObjRecord *obj_x(ObjRecord *orp, unsigned long val)
+{
+ if (orp->type & 1)
+ orp->x_size = 32;
+ if (val > 0xFFFF)
+ orp = obj_force(orp, 32);
+ if (orp->x_size == 32)
+ return (obj_dword(orp, val));
+ orp->x_size = 16;
+ return (obj_word(orp, val));
+}
+
+/*
+ * Writes an index
+ */
+static ObjRecord *obj_index(ObjRecord *orp, unsigned int val)
+{
+ if (val < 128)
+ return ( obj_byte(orp, val) );
+ return (obj_word(orp, (val>>8) | (val<<8) | 0x80));
+}
+
+/*
+ * Writes a variable length value
+ */
+static ObjRecord *obj_value(ObjRecord *orp, unsigned long val)
+{
+ if (val <= 128)
+ return ( obj_byte(orp, val) );
+ if (val <= 0xFFFF) {
+ orp = obj_byte(orp, 129);
+ return ( obj_word(orp, val) );
+ }
+ if (val <= 0xFFFFFF)
+ return ( obj_dword(orp, (val<<8) + 132 ) );
+ orp = obj_byte(orp, 136);
+ return ( obj_dword(orp, val) );
+}
+
+/*
+ * Writes a counted string
+ */
+static ObjRecord *obj_name(ObjRecord *orp, char *name)
+{
+ int len = strlen(name);
+ unsigned char *ptr;
+
+ orp = obj_check(orp, len+1);
+ ptr = orp->buf + orp->used;
+ *ptr++ = len;
+ orp->used += len+1;
+ if (obj_uppercase)
+ while (--len >= 0) {
+ *ptr++ = toupper(*name);
+ name++;
+ } else
+ memcpy(ptr, name, len);
+ return (orp);
+}
+
+/*
+ * Initializer for an LEDATA record.
+ * parm[0] = offset
+ * parm[1] = segment index
+ * During the use of a LEDATA ObjRecord, parm[0] is constantly updated to
+ * represent the offset that would be required if the record were split at the
+ * last commit point.
+ * parm[2] is a copy of parm[0] as it was when the current record was initted.
+ */
+static void ori_ledata(ObjRecord *orp)
+{
+ obj_index (orp, orp->parm[1]);
+ orp->parm[2] = orp->parm[0];
+ obj_x (orp, orp->parm[0]);
+}
+
+/*
+ * Initializer for a PUBDEF record.
+ * parm[0] = group index
+ * parm[1] = segment index
+ * parm[2] = frame (only used when both indexes are zero)
+ */
+static void ori_pubdef(ObjRecord *orp)
+{
+ obj_index (orp, orp->parm[0]);
+ obj_index (orp, orp->parm[1]);
+ if ( !(orp->parm[0] | orp->parm[1]) )
+ obj_word (orp, orp->parm[2]);
+}
+
+/*
+ * Initializer for a LINNUM record.
+ * parm[0] = group index
+ * parm[1] = segment index
+ */
+static void ori_linnum(ObjRecord *orp)
+{
+ obj_index (orp, orp->parm[0]);
+ obj_index (orp, orp->parm[1]);
+}
+/*
+ * Initializer for a local vars record.
+ */
+static void ori_local(ObjRecord *orp)
+{
+ obj_byte (orp, 0x40);
+ obj_byte (orp, dSYM);
+}
+
+/*
+ * Null initializer for records that continue without any header info
+ */
+static void ori_null(ObjRecord *orp)
+{
+ (void) orp; /* Do nothing */
+}
+
+/*
+ * This concludes the low level section of outobj.c
+ */
+
static char obj_infile[FILENAME_MAX];
-static int obj_uppercase;
static efunc error;
static evalfunc evaluate;
@@ -27,24 +465,46 @@ static ldfunc deflabel;
static FILE *ofp;
static long first_seg;
static int any_segs;
+static int passtwo;
+static int arrindex;
-#define LEDATA_MAX 1024 /* maximum size of LEDATA record */
-#define RECORD_MAX 1024 /* maximum size of _any_ record */
#define GROUP_MAX 256 /* we won't _realistically_ have more
* than this many segs in a group */
#define EXT_BLKSIZ 256 /* block size for externals list */
-static unsigned char record[RECORD_MAX], *recptr;
-
struct Segment; /* need to know these structs exist */
struct Group;
+struct LineNumber {
+ struct LineNumber *next;
+ struct Segment *segment;
+ long offset;
+ long lineno;
+};
+
+static struct FileName {
+ struct FileName *next;
+ char *name;
+ struct LineNumber *lnhead, **lntail;
+ int index;
+} *fnhead, **fntail;
+
+static struct Array {
+ struct Array *next;
+ unsigned size;
+ int basetype;
+} *arrhead, **arrtail;
+
+#define ARRAYBOT 31 /* magic number for first array index */
+
+
static struct Public {
struct Public *next;
char *name;
long offset;
long segment; /* only if it's far-absolute */
-} *fpubhead, **fpubtail;
+ int type; /* only for local debug syms */
+} *fpubhead, **fpubtail, *last_defined;
static struct External {
struct External *next;
@@ -78,7 +538,7 @@ static struct Segment {
long index; /* the NASM segment id */
long obj_index; /* the OBJ-file segment index */
struct Group *grp; /* the group it belongs to */
- long currentpos;
+ unsigned long currentpos;
long align; /* can be SEG_ABS + absolute addr */
enum {
CMB_PRIVATE = 0,
@@ -87,9 +547,10 @@ static struct Segment {
CMB_COMMON = 6
} combine;
long use32; /* is this segment 32-bit? */
- struct Public *pubhead, **pubtail;
+ struct Public *pubhead, **pubtail, *lochead, **loctail;
char *name;
char *segclass, *overlay; /* `class' is a C++ keyword :-) */
+ ObjRecord *orp;
} *seghead, **segtail, *obj_seg_needs_update;
static struct Group {
@@ -105,16 +566,6 @@ static struct Group {
} segs[GROUP_MAX]; /* ...in this */
} *grphead, **grptail, *obj_grp_needs_update;
-static struct ObjData {
- struct ObjData *next;
- int nonempty;
- struct Segment *seg;
- long startpos;
- int letype, ftype;
- unsigned char ledata[LEDATA_MAX], *lptr;
- unsigned char fixupp[RECORD_MAX], *fptr;
-} *datahead, *datacurr, **datatail;
-
static struct ImpDef {
struct ImpDef *next;
char *extname;
@@ -138,46 +589,14 @@ static struct ExpDef {
static long obj_entry_seg, obj_entry_ofs;
-enum RecordID { /* record ID codes */
-
- THEADR = 0x80, /* module header */
- COMENT = 0x88, /* comment record */
-
- LNAMES = 0x96, /* list of names */
-
- SEGDEF = 0x98, /* segment definition */
- GRPDEF = 0x9A, /* group definition */
- EXTDEF = 0x8C, /* external definition */
- PUBDEF = 0x90, /* public definition */
- COMDEF = 0xB0, /* common definition */
+struct ofmt of_obj;
- LEDATA = 0xA0, /* logical enumerated data */
- FIXUPP = 0x9C, /* fixups (relocations) */
-
- MODEND = 0x8A /* module end */
-};
-
-extern struct ofmt of_obj;
-
-static long obj_ledata_space(struct Segment *);
-static int obj_fixup_free(struct Segment *);
-static void obj_ledata_new(struct Segment *);
-static void obj_ledata_commit(void);
-static void obj_write_fixup (struct ObjData *, int, int, long, long, long);
static long obj_segment (char *, int, int *);
-static void obj_write_file(void);
-static unsigned char *obj_write_data(unsigned char *, unsigned char *, int);
-static unsigned char *obj_write_byte(unsigned char *, int);
-static unsigned char *obj_write_word(unsigned char *, int);
-static unsigned char *obj_write_dword(unsigned char *, long);
-static unsigned char *obj_write_rword(unsigned char *, int);
-static unsigned char *obj_write_name(unsigned char *, char *);
-static unsigned char *obj_write_index(unsigned char *, int);
-static unsigned char *obj_write_value(unsigned char *, unsigned long);
-static void obj_record(int, unsigned char *, unsigned char *);
+static void obj_write_file(int debuginfo);
static int obj_directive (char *, char *, int);
-static void obj_init (FILE *fp, efunc errfunc, ldfunc ldef, evalfunc eval) {
+static void obj_init (FILE *fp, efunc errfunc, ldfunc ldef, evalfunc eval)
+{
ofp = fp;
error = errfunc;
evaluate = eval;
@@ -200,14 +619,24 @@ static void obj_init (FILE *fp, efunc errfunc, ldfunc ldef, evalfunc eval) {
segtail = &seghead;
grphead = obj_grp_needs_update = NULL;
grptail = &grphead;
- datahead = datacurr = NULL;
- datatail = &datahead;
obj_entry_seg = NO_SEG;
obj_uppercase = FALSE;
+ passtwo = 0;
+
+ of_obj.current_dfmt->init (&of_obj,NULL,fp,errfunc);
}
-static void obj_cleanup (void) {
- obj_write_file();
+static int obj_set_info(enum geninfo type, char **val)
+{
+ (void) type;
+ (void) val;
+
+ return 0;
+}
+static void obj_cleanup (int debuginfo)
+{
+ obj_write_file(debuginfo);
+ of_obj.current_dfmt->cleanup();
fclose (ofp);
while (seghead) {
struct Segment *segtmp = seghead;
@@ -218,6 +647,8 @@ static void obj_cleanup (void) {
nasm_free (pubtmp->name);
nasm_free (pubtmp);
}
+ nasm_free (segtmp->segclass);
+ nasm_free (segtmp->overlay);
nasm_free (segtmp);
}
while (fpubhead) {
@@ -256,14 +687,10 @@ static void obj_cleanup (void) {
grphead = grphead->next;
nasm_free (grptmp);
}
- while (datahead) {
- struct ObjData *datatmp = datahead;
- datahead = datahead->next;
- nasm_free (datatmp);
- }
}
-static void obj_ext_set_defwrt (struct External *ext, char *id) {
+static void obj_ext_set_defwrt (struct External *ext, char *id)
+{
struct Segment *seg;
struct Group *grp;
@@ -290,7 +717,8 @@ static void obj_ext_set_defwrt (struct External *ext, char *id) {
}
static void obj_deflabel (char *name, long segment,
- long offset, int is_global, char *special) {
+ long offset, int is_global, char *special)
+{
/*
* We have three cases:
*
@@ -376,19 +804,18 @@ static void obj_deflabel (char *name, long segment,
error (ERR_PANIC, "strange segment conditions in OBJ driver");
}
- for (seg = seghead; seg; seg = seg->next)
+ for (seg = seghead; seg && is_global; seg = seg->next)
if (seg->index == segment) {
+ struct Public *loc = nasm_malloc (sizeof(*loc));
/*
* Case (ii). Maybe MODPUB someday?
*/
- if (is_global) {
- struct Public *pub;
- pub = *seg->pubtail = nasm_malloc(sizeof(*pub));
- seg->pubtail = &pub->next;
- pub->next = NULL;
- pub->name = nasm_strdup(name);
- pub->offset = offset;
- }
+ *seg->pubtail = loc;
+ seg->pubtail = &loc->next;
+ loc->next = NULL;
+ loc->name = nasm_strdup(name);
+ loc->offset = offset;
+
if (special)
error(ERR_NONFATAL, "OBJ supports no special symbol features"
" for this symbol type");
@@ -398,16 +825,20 @@ static void obj_deflabel (char *name, long segment,
/*
* Case (iii).
*/
- ext = *exttail = nasm_malloc(sizeof(*ext));
- ext->next = NULL;
- exttail = &ext->next;
- ext->name = name;
- ext->defwrt_type = DEFWRT_NONE;
- if (is_global == 2) {
- ext->commonsize = offset;
- ext->commonelem = 1; /* default FAR */
- } else
- ext->commonsize = 0;
+ if (is_global) {
+ ext = *exttail = nasm_malloc(sizeof(*ext));
+ ext->next = NULL;
+ exttail = &ext->next;
+ ext->name = name;
+ ext->defwrt_type = DEFWRT_NONE;
+ if (is_global == 2) {
+ ext->commonsize = offset;
+ ext->commonelem = 1; /* default FAR */
+ } else
+ ext->commonsize = 0;
+ }
+ else
+ return;
/*
* Now process the special text, if any, to find default-WRT
@@ -519,11 +950,13 @@ static void obj_deflabel (char *name, long segment,
}
static void obj_out (long segto, void *data, unsigned long type,
- long segment, long wrt) {
+ long segment, long wrt)
+{
long size, realtype;
unsigned char *ucdata;
long ldata;
struct Segment *seg;
+ ObjRecord *orp;
/*
* handle absolute-assembly (structure definitions)
@@ -554,26 +987,29 @@ static void obj_out (long segto, void *data, unsigned long type,
if (!seg)
error (ERR_PANIC, "code directed to nonexistent segment?");
+ orp = seg->orp;
+ orp->parm[0] = seg->currentpos;
+
size = type & OUT_SIZMASK;
realtype = type & OUT_TYPMASK;
if (realtype == OUT_RAWDATA) {
ucdata = data;
while (size > 0) {
- long len = obj_ledata_space(seg);
- if (len == 0) {
- obj_ledata_new(seg);
- len = obj_ledata_space(seg);
- }
+ unsigned int len;
+ orp = obj_check(seg->orp, 1);
+ len = RECORD_MAX - orp->used;
if (len > size)
len = size;
- datacurr->lptr = obj_write_data (datacurr->lptr, ucdata, len);
- datacurr->nonempty = TRUE;
+ memcpy (orp->buf+orp->used, ucdata, len);
+ orp->committed = orp->used += len;
+ orp->parm[0] = seg->currentpos += len;
ucdata += len;
size -= len;
- seg->currentpos += len;
}
- } else if (realtype == OUT_ADDRESS || realtype == OUT_REL2ADR ||
- realtype == OUT_REL4ADR) {
+ }
+ else if (realtype == OUT_ADDRESS || realtype == OUT_REL2ADR ||
+ realtype == OUT_REL4ADR)
+ {
int rsize;
if (segment == NO_SEG && realtype != OUT_ADDRESS)
@@ -591,13 +1027,10 @@ static void obj_out (long segto, void *data, unsigned long type,
ldata += (size-4);
size = 4;
}
- if (obj_ledata_space(seg) < 4 || !obj_fixup_free(seg))
- obj_ledata_new(seg);
if (size == 2)
- datacurr->lptr = obj_write_word (datacurr->lptr, ldata);
+ orp = obj_word (orp, ldata);
else
- datacurr->lptr = obj_write_dword (datacurr->lptr, ldata);
- datacurr->nonempty = TRUE;
+ orp = obj_dword (orp, ldata);
rsize = size;
if (segment < SEG_ABS && (segment != NO_SEG && segment % 2) &&
size == 4) {
@@ -614,67 +1047,28 @@ static void obj_out (long segto, void *data, unsigned long type,
" dword-size segment base references");
}
if (segment != NO_SEG)
- obj_write_fixup (datacurr, rsize,
- (realtype == OUT_REL2ADR ||
- realtype == OUT_REL4ADR ? 0 : 0x4000),
- segment, wrt,
- (seg->currentpos - datacurr->startpos));
+ obj_write_fixup (orp, rsize,
+ (realtype == OUT_ADDRESS ? 0x4000 : 0),
+ segment, wrt);
seg->currentpos += size;
} else if (realtype == OUT_RESERVE) {
- obj_ledata_commit();
+ if (orp->committed)
+ orp = obj_bump(orp);
seg->currentpos += size;
}
+ obj_commit(orp);
}
-static long obj_ledata_space(struct Segment *segto) {
- if (datacurr && datacurr->seg == segto)
- return datacurr->ledata + LEDATA_MAX - datacurr->lptr;
- else
- return 0;
-}
-
-static int obj_fixup_free(struct Segment *segto) {
- if (datacurr && datacurr->seg == segto)
- return (datacurr->fixupp + RECORD_MAX - datacurr->fptr) > 8;
- else
- return 0;
-}
-
-static void obj_ledata_new(struct Segment *segto) {
- datacurr = *datatail = nasm_malloc(sizeof(*datacurr));
- datacurr->next = NULL;
- datatail = &datacurr->next;
- datacurr->nonempty = FALSE;
- datacurr->lptr = datacurr->ledata;
- datacurr->fptr = datacurr->fixupp;
- datacurr->seg = segto;
- if (segto->use32)
- datacurr->letype = LEDATA+1;
- else
- datacurr->letype = LEDATA;
- datacurr->startpos = segto->currentpos;
- datacurr->ftype = FIXUPP;
-
- datacurr->lptr = obj_write_index (datacurr->lptr, segto->obj_index);
- if (datacurr->letype == LEDATA)
- datacurr->lptr = obj_write_word (datacurr->lptr, segto->currentpos);
- else
- datacurr->lptr = obj_write_dword (datacurr->lptr, segto->currentpos);
-}
-
-static void obj_ledata_commit(void) {
- datacurr = NULL;
-}
-
-static void obj_write_fixup (struct ObjData *data, int bytes,
- int segrel, long seg, long wrt,
- long offset) {
+static void obj_write_fixup (ObjRecord *orp, int bytes,
+ int segrel, long seg, long wrt)
+{
int locat, method;
int base;
long tidx, fidx;
struct Segment *s = NULL;
struct Group *g = NULL;
struct External *e = NULL;
+ ObjRecord *forp;
if (bytes == 1) {
error(ERR_NONFATAL, "`obj' output driver does not support"
@@ -682,24 +1076,34 @@ static void obj_write_fixup (struct ObjData *data, int bytes,
return;
}
- locat = 0x8000 | segrel | offset;
+ forp = orp->child;
+ if (forp == NULL) {
+ orp->child = forp = obj_new();
+ forp->up = &(orp->child);
+ forp->type = FIXUPP;
+ }
+
if (seg % 2) {
base = TRUE;
- locat |= 0x800;
+ locat = FIX_16_SELECTOR;
seg--;
if (bytes != 2)
error(ERR_PANIC, "OBJ: 4-byte segment base fixup got"
" through sanity check");
- } else {
+ }
+ else {
base = FALSE;
- if (bytes == 2)
- locat |= 0x400;
- else {
- locat |= 0x2400;
- data->ftype = FIXUPP+1; /* need new-style FIXUPP record */
- }
+ locat = (bytes == 2) ? FIX_16_OFFSET : FIX_32_OFFSET;
+ if (!segrel)
+ /*
+ * There is a bug in tlink that makes it process self relative
+ * fixups incorrectly if the x_size doesn't match the location
+ * size.
+ */
+ forp = obj_force(forp, bytes<<3);
}
- data->fptr = obj_write_rword (data->fptr, locat);
+
+ forp = obj_rword (forp, locat | segrel | (orp->parm[0]-orp->parm[2]));
tidx = fidx = -1, method = 0; /* placate optimisers */
@@ -796,13 +1200,15 @@ static void obj_write_fixup (struct ObjData *data, int bytes,
}
}
- data->fptr = obj_write_byte (data->fptr, method);
+ forp = obj_byte (forp, method);
if (fidx != -1)
- data->fptr = obj_write_index (data->fptr, fidx);
- data->fptr = obj_write_index (data->fptr, tidx);
+ forp = obj_index (forp, fidx);
+ forp = obj_index (forp, tidx);
+ obj_commit (forp);
}
-static long obj_segment (char *name, int pass, int *bits) {
+static long obj_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
@@ -876,6 +1282,13 @@ static long obj_segment (char *name, int pass, int *bits) {
seg->segclass = seg->overlay = NULL;
seg->pubhead = NULL;
seg->pubtail = &seg->pubhead;
+ seg->lochead = NULL;
+ seg->loctail = &seg->lochead;
+ seg->orp = obj_new();
+ seg->orp->up = &(seg->orp);
+ seg->orp->ori = ori_ledata;
+ seg->orp->type = LEDATA;
+ seg->orp->parm[1] = obj_idx;
/*
* Process the segment attributes.
@@ -1014,6 +1427,7 @@ static long obj_segment (char *name, int pass, int *bits) {
while (*extp) {
if ((*extp)->defwrt_type == DEFWRT_STRING &&
!strcmp((*extp)->defwrt_ptr.string, seg->name)) {
+ nasm_free((*extp)->defwrt_ptr.string);
(*extp)->defwrt_type = DEFWRT_SEGMENT;
(*extp)->defwrt_ptr.seg = seg;
*extp = (*extp)->next_dws;
@@ -1029,7 +1443,8 @@ static long obj_segment (char *name, int pass, int *bits) {
}
}
-static int obj_directive (char *directive, char *value, int pass) {
+static int obj_directive (char *directive, char *value, int pass)
+{
if (!strcmp(directive, "group")) {
char *p, *q, *v;
if (pass == 1) {
@@ -1129,6 +1544,7 @@ static int obj_directive (char *directive, char *value, int pass) {
while (*extp) {
if ((*extp)->defwrt_type == DEFWRT_STRING &&
!strcmp((*extp)->defwrt_ptr.string, grp->name)) {
+ nasm_free((*extp)->defwrt_ptr.string);
(*extp)->defwrt_type = DEFWRT_GROUP;
(*extp)->defwrt_ptr.grp = grp;
*extp = (*extp)->next_dws;
@@ -1268,7 +1684,8 @@ static int obj_directive (char *directive, char *value, int pass) {
return 0;
}
-static long obj_segbase (long segment) {
+static long obj_segbase (long segment)
+{
struct Segment *seg;
/*
@@ -1301,7 +1718,7 @@ static long obj_segbase (long segment) {
return e->defwrt_ptr.seg->index+1;
else if (e->defwrt_type == DEFWRT_GROUP)
return e->defwrt_ptr.grp->index+1;
- else if (e->defwrt_type == DEFWRT_STRING)
+ else
return NO_SEG; /* can't tell what it is */
}
@@ -1316,121 +1733,133 @@ static long obj_segbase (long segment) {
return segment; /* no special treatment */
}
-static void obj_filename (char *inname, char *outname, efunc error) {
+static void obj_filename (char *inname, char *outname, efunc error)
+{
strcpy(obj_infile, inname);
standard_extension (inname, outname, ".obj", error);
}
-static void obj_write_file (void) {
- struct Segment *seg;
+static void obj_write_file (int debuginfo)
+{
+ struct Segment *seg, *entry_seg_ptr = 0;
+ struct FileName *fn;
+ struct LineNumber *ln;
struct Group *grp;
- struct Public *pub;
+ struct Public *pub, *loc;
struct External *ext;
- struct ObjData *data;
struct ImpDef *imp;
struct ExpDef *export;
static char boast[] = "The Netwide Assembler " NASM_VER;
- int lname_idx, rectype;
+ int lname_idx;
+ ObjRecord *orp;
/*
* Write the THEADR module header.
*/
- recptr = record;
- recptr = obj_write_name (recptr, obj_infile);
- obj_record (THEADR, record, recptr);
+ orp = obj_new();
+ orp->type = THEADR;
+ obj_name (orp, obj_infile);
+ obj_emit2 (orp);
/*
* Write the NASM boast comment.
*/
- recptr = record;
- recptr = obj_write_rword (recptr, 0); /* comment type zero */
- recptr = obj_write_name (recptr, boast);
- obj_record (COMENT, record, recptr);
+ orp->type = COMENT;
+ obj_rword (orp, 0); /* comment type zero */
+ obj_name (orp, boast);
+ obj_emit2 (orp);
+ orp->type = COMENT;
/*
* Write the IMPDEF records, if any.
*/
for (imp = imphead; imp; imp = imp->next) {
- recptr = record;
- recptr = obj_write_rword (recptr, 0xA0); /* comment class A0 */
- recptr = obj_write_byte (recptr, 1); /* subfunction 1: IMPDEF */
+ obj_rword (orp, 0xA0); /* comment class A0 */
+ obj_byte (orp, 1); /* subfunction 1: IMPDEF */
if (imp->impname)
- recptr = obj_write_byte (recptr, 0); /* import by name */
+ obj_byte (orp, 0); /* import by name */
else
- recptr = obj_write_byte (recptr, 1); /* import by ordinal */
- recptr = obj_write_name (recptr, imp->extname);
- recptr = obj_write_name (recptr, imp->libname);
+ obj_byte (orp, 1); /* import by ordinal */
+ obj_name (orp, imp->extname);
+ obj_name (orp, imp->libname);
if (imp->impname)
- recptr = obj_write_name (recptr, imp->impname);
+ obj_name (orp, imp->impname);
else
- recptr = obj_write_word (recptr, imp->impindex);
- obj_record (COMENT, record, recptr);
+ obj_word (orp, imp->impindex);
+ obj_emit2 (orp);
}
/*
* Write the EXPDEF records, if any.
*/
for (export = exphead; export; export = export->next) {
- recptr = record;
- recptr = obj_write_rword (recptr, 0xA0); /* comment class A0 */
- recptr = obj_write_byte (recptr, 2); /* subfunction 1: EXPDEF */
- recptr = obj_write_byte (recptr, export->flags);
- recptr = obj_write_name (recptr, export->extname);
- recptr = obj_write_name (recptr, export->intname);
+ obj_rword (orp, 0xA0); /* comment class A0 */
+ obj_byte (orp, 2); /* subfunction 2: EXPDEF */
+ obj_byte (orp, export->flags);
+ obj_name (orp, export->extname);
+ obj_name (orp, export->intname);
if (export->flags & EXPDEF_FLAG_ORDINAL)
- recptr = obj_write_word (recptr, export->ordinal);
- obj_record (COMENT, record, recptr);
+ obj_word (orp, export->ordinal);
+ obj_emit2 (orp);
+ }
+
+ /* we're using extended OMF if we put in debug info*/
+ if (debuginfo) {
+ orp->type = COMENT;
+ obj_byte (orp, 0x40);
+ obj_byte (orp, dEXTENDED);
+ obj_emit2 (orp);
}
/*
* Write the first LNAMES record, containing LNAME one, which
* is null. Also initialise the LNAME counter.
*/
- recptr = record;
- recptr = obj_write_name (recptr, "");
- obj_record (LNAMES, record, recptr);
- lname_idx = 2;
+ orp->type = LNAMES;
+ obj_byte (orp, 0);
+ lname_idx = 1;
+ /*
+ * Write some LNAMES for the segment names
+ */
+ for (seg = seghead; seg; seg = seg->next) {
+ orp = obj_name (orp, seg->name);
+ if (seg->segclass)
+ orp = obj_name (orp, seg->segclass);
+ if (seg->overlay)
+ orp = obj_name (orp, seg->overlay);
+ obj_commit (orp);
+ }
+ /*
+ * Write some LNAMES for the group names
+ */
+ for (grp = grphead; grp; grp = grp->next) {
+ orp = obj_name (orp, grp->name);
+ obj_commit (orp);
+ }
+ obj_emit (orp);
+
/*
- * Write the SEGDEF records. Each has an associated LNAMES
- * record.
+ * Write the SEGDEF records.
*/
+ orp->type = SEGDEF;
for (seg = seghead; seg; seg = seg->next) {
- int new_segdef; /* do we use the newer record type? */
int acbp;
- int sn, cn, on; /* seg, class, overlay LNAME idx */
-
- if (seg->use32 || seg->currentpos >= 0x10000L)
- new_segdef = TRUE;
- else
- new_segdef = FALSE;
-
- recptr = record;
- recptr = obj_write_name (recptr, seg->name);
- sn = lname_idx++;
- if (seg->segclass) {
- recptr = obj_write_name (recptr, seg->segclass);
- cn = lname_idx++;
- } else
- cn = 1;
- if (seg->overlay) {
- recptr = obj_write_name (recptr, seg->overlay);
- on = lname_idx++;
- } else
- on = 1;
- obj_record (LNAMES, record, recptr);
+ unsigned long seglen = seg->currentpos;
acbp = (seg->combine << 2); /* C field */
- if (seg->currentpos >= 0x10000L && !new_segdef)
- acbp |= 0x02; /* B bit */
-
if (seg->use32)
acbp |= 0x01; /* P bit is Use32 flag */
+ else if (seglen == 0x10000L) {
+ seglen = 0; /* This special case may be needed for old linkers */
+ acbp |= 0x02; /* B bit */
+ }
+
/* A field */
if (seg->align >= SEG_ABS)
- acbp |= 0x00;
+ /* acbp |= 0x00 */;
else if (seg->align >= 4096) {
if (seg->align > 4096)
error(ERR_NONFATAL, "segment `%s' requires more alignment"
@@ -1447,43 +1876,22 @@ static void obj_write_file (void) {
} else
acbp |= 0x20;
- recptr = record;
- recptr = obj_write_byte (recptr, acbp);
+ obj_byte (orp, acbp);
if (seg->align & SEG_ABS) {
- recptr = obj_write_word (recptr, seg->align - SEG_ABS);
- recptr = obj_write_byte (recptr, 0);
- }
- if (new_segdef)
- recptr = obj_write_dword (recptr, seg->currentpos);
- else
- recptr = obj_write_word (recptr, seg->currentpos & 0xFFFF);
- recptr = obj_write_index (recptr, sn);
- recptr = obj_write_index (recptr, cn);
- recptr = obj_write_index (recptr, on);
- if (new_segdef)
- obj_record (SEGDEF+1, record, recptr);
- else
- obj_record (SEGDEF, record, recptr);
- }
-
- /*
- * Write some LNAMES for the group names. lname_idx is left
- * alone here - it will catch up when we write the GRPDEFs.
- */
- recptr = record;
- for (grp = grphead; grp; grp = grp->next) {
- if (recptr - record + strlen(grp->name)+2 > 1024) {
- obj_record (LNAMES, record, recptr);
- recptr = record;
+ obj_x (orp, seg->align - SEG_ABS); /* Frame */
+ obj_byte (orp, 0); /* Offset */
}
- recptr = obj_write_name (recptr, grp->name);
+ obj_x (orp, seglen);
+ obj_index (orp, ++lname_idx);
+ obj_index (orp, seg->segclass ? ++lname_idx : 1);
+ obj_index (orp, seg->overlay ? ++lname_idx : 1);
+ obj_emit2 (orp);
}
- if (recptr > record)
- obj_record (LNAMES, record, recptr);
/*
* Write the GRPDEF records.
*/
+ orp->type = GRPDEF;
for (grp = grphead; grp; grp = grp->next) {
int i;
@@ -1495,96 +1903,76 @@ static void obj_write_file (void) {
grp->segs[i].name = NULL;
}
}
- recptr = record;
- recptr = obj_write_index (recptr, lname_idx++);
+ obj_index (orp, ++lname_idx);
for (i = 0; i < grp->nindices; i++) {
- recptr = obj_write_byte (recptr, 0xFF);
- recptr = obj_write_index (recptr, grp->segs[i].index);
+ obj_byte (orp, 0xFF);
+ obj_index (orp, grp->segs[i].index);
}
- obj_record (GRPDEF, record, recptr);
+ obj_emit2 (orp);
}
/*
* Write the PUBDEF records: first the ones in the segments,
* then the far-absolutes.
*/
+ orp->type = PUBDEF;
+ orp->ori = ori_pubdef;
for (seg = seghead; seg; seg = seg->next) {
- int any;
-
- recptr = record;
- recptr = obj_write_index (recptr, seg->grp ? seg->grp->obj_index : 0);
- recptr = obj_write_index (recptr, seg->obj_index);
- any = FALSE;
- if (seg->use32)
- rectype = PUBDEF+1;
- else
- rectype = PUBDEF;
+ orp->parm[0] = seg->grp ? seg->grp->obj_index : 0;
+ orp->parm[1] = seg->obj_index;
for (pub = seg->pubhead; pub; pub = pub->next) {
- if (recptr - record + strlen(pub->name) + 7 > 1024) {
- if (any)
- obj_record (rectype, record, recptr);
- recptr = record;
- recptr = obj_write_index (recptr, 0);
- recptr = obj_write_index (recptr, seg->obj_index);
- }
- recptr = obj_write_name (recptr, pub->name);
- if (seg->use32)
- recptr = obj_write_dword (recptr, pub->offset);
- else
- recptr = obj_write_word (recptr, pub->offset);
- recptr = obj_write_index (recptr, 0);
- any = TRUE;
+ orp = obj_name (orp, pub->name);
+ orp = obj_x (orp, pub->offset);
+ orp = obj_byte (orp, 0); /* type index */
+ obj_commit (orp);
}
- if (any)
- obj_record (rectype, record, recptr);
+ obj_emit (orp);
}
+ orp->parm[0] = 0;
+ orp->parm[1] = 0;
for (pub = fpubhead; pub; pub = pub->next) { /* pub-crawl :-) */
- recptr = record;
- recptr = obj_write_index (recptr, 0); /* no group */
- recptr = obj_write_index (recptr, 0); /* no segment either */
- recptr = obj_write_word (recptr, pub->segment);
- recptr = obj_write_name (recptr, pub->name);
- recptr = obj_write_word (recptr, pub->offset);
- recptr = obj_write_index (recptr, 0);
- obj_record (PUBDEF, record, recptr);
+ if (orp->parm[2] != pub->segment) {
+ obj_emit (orp);
+ orp->parm[2] = pub->segment;
+ }
+ orp = obj_name (orp, pub->name);
+ orp = obj_x (orp, pub->offset);
+ orp = obj_byte (orp, 0); /* type index */
+ obj_commit (orp);
}
+ obj_emit (orp);
/*
* Write the EXTDEF and COMDEF records, in order.
*/
- recptr = record;
+ orp->ori = ori_null;
for (ext = exthead; ext; ext = ext->next) {
if (ext->commonsize == 0) {
- /* dj@delorie.com: check for buffer overrun before we overrun it */
- if (recptr - record + strlen(ext->name)+2 > RECORD_MAX) {
- obj_record (EXTDEF, record, recptr);
- recptr = record;
+ if (orp->type != EXTDEF) {
+ obj_emit (orp);
+ orp->type = EXTDEF;
}
- recptr = obj_write_name (recptr, ext->name);
- recptr = obj_write_index (recptr, 0);
+ orp = obj_name (orp, ext->name);
+ orp = obj_index (orp, 0);
} else {
- if (recptr > record)
- obj_record (EXTDEF, record, recptr);
- recptr = record;
- if (ext->commonsize) {
- recptr = obj_write_name (recptr, ext->name);
- recptr = obj_write_index (recptr, 0);
- if (ext->commonelem) {
- recptr = obj_write_byte (recptr, 0x61);/* far communal */
- recptr = obj_write_value (recptr, (ext->commonsize /
- ext->commonelem));
- recptr = obj_write_value (recptr, ext->commonelem);
- } else {
- recptr = obj_write_byte (recptr, 0x62);/* near communal */
- recptr = obj_write_value (recptr, ext->commonsize);
- }
- obj_record (COMDEF, record, recptr);
+ if (orp->type != COMDEF) {
+ obj_emit (orp);
+ orp->type = COMDEF;
+ }
+ orp = obj_name (orp, ext->name);
+ orp = obj_index (orp, 0);
+ if (ext->commonelem) {
+ orp = obj_byte (orp, 0x61);/* far communal */
+ orp = obj_value (orp, (ext->commonsize / ext->commonelem));
+ orp = obj_value (orp, ext->commonelem);
+ } else {
+ orp = obj_byte (orp, 0x62);/* near communal */
+ orp = obj_value (orp, ext->commonsize);
}
- recptr = record;
}
+ obj_commit (orp);
}
- if (recptr > record)
- obj_record (EXTDEF, record, recptr);
+ obj_emit (orp);
/*
* Write a COMENT record stating that the linker's first pass
@@ -1592,150 +1980,251 @@ static void obj_write_file (void) {
* MODEND record specifies a start point, in which case,
* according to some variants of the documentation, this COMENT
* should be omitted. So we'll omit it just in case.
+ * But, TASM puts it in all the time so if we are using
+ * TASM debug stuff we are putting it in
*/
- if (obj_entry_seg == NO_SEG) {
- recptr = record;
- recptr = obj_write_rword (recptr, 0x40A2);
- recptr = obj_write_byte (recptr, 1);
- obj_record (COMENT, record, recptr);
- }
+ if (debuginfo || obj_entry_seg == NO_SEG) {
+ orp->type = COMENT;
+ obj_byte (orp, 0x40);
+ obj_byte (orp, dLINKPASS);
+ obj_byte (orp, 1);
+ obj_emit2 (orp);
+ }
/*
- * Write the LEDATA/FIXUPP pairs.
+ * 1) put out the compiler type
+ * 2) Put out the type info. The only type we are using is near label #19
+ */
+ if (debuginfo) {
+ int i;
+ struct Array *arrtmp = arrhead;
+ orp->type = COMENT;
+ obj_byte (orp, 0x40);
+ obj_byte (orp, dCOMPDEF);
+ obj_byte (orp, 4);
+ obj_byte (orp, 0);
+ obj_emit2 (orp);
+
+ obj_byte (orp, 0x40);
+ obj_byte (orp, dTYPEDEF);
+ obj_word (orp, 0x18); /* type # for linking */
+ obj_word (orp, 6); /* size of type */
+ obj_byte (orp, 0x2a); /* absolute type for debugging */
+ obj_emit2 (orp);
+ obj_byte (orp, 0x40);
+ obj_byte (orp, dTYPEDEF);
+ obj_word (orp, 0x19); /* type # for linking */
+ obj_word (orp, 0); /* size of type */
+ obj_byte (orp, 0x24); /* absolute type for debugging */
+ obj_byte (orp, 0); /* near/far specifier */
+ obj_emit2 (orp);
+ obj_byte (orp, 0x40);
+ obj_byte (orp, dTYPEDEF);
+ obj_word (orp, 0x1A); /* type # for linking */
+ obj_word (orp, 0); /* size of type */
+ obj_byte (orp, 0x24); /* absolute type for debugging */
+ obj_byte (orp, 1); /* near/far specifier */
+ obj_emit2 (orp);
+ obj_byte (orp, 0x40);
+ obj_byte (orp, dTYPEDEF);
+ obj_word (orp, 0x1b); /* type # for linking */
+ obj_word (orp, 0); /* size of type */
+ obj_byte (orp, 0x23); /* absolute type for debugging */
+ obj_byte (orp, 0);
+ obj_byte (orp, 0);
+ obj_byte (orp, 0);
+ obj_emit2 (orp);
+ obj_byte (orp, 0x40);
+ obj_byte (orp, dTYPEDEF);
+ obj_word (orp, 0x1c); /* type # for linking */
+ obj_word (orp, 0); /* size of type */
+ obj_byte (orp, 0x23); /* absolute type for debugging */
+ obj_byte (orp, 0);
+ obj_byte (orp, 4);
+ obj_byte (orp, 0);
+ obj_emit2 (orp);
+ obj_byte (orp, 0x40);
+ obj_byte (orp, dTYPEDEF);
+ obj_word (orp, 0x1d); /* type # for linking */
+ obj_word (orp, 0); /* size of type */
+ obj_byte (orp, 0x23); /* absolute type for debugging */
+ obj_byte (orp, 0);
+ obj_byte (orp, 1);
+ obj_byte (orp, 0);
+ obj_emit2 (orp);
+ obj_byte (orp, 0x40);
+ obj_byte (orp, dTYPEDEF);
+ obj_word (orp, 0x1e); /* type # for linking */
+ obj_word (orp, 0); /* size of type */
+ obj_byte (orp, 0x23); /* absolute type for debugging */
+ obj_byte (orp, 0);
+ obj_byte (orp, 5);
+ obj_byte (orp, 0);
+ obj_emit2 (orp);
+
+ /* put out the array types */
+ for (i= ARRAYBOT; i < arrindex; i++) {
+ obj_byte (orp, 0x40);
+ obj_byte (orp, dTYPEDEF);
+ obj_word (orp, i ); /* type # for linking */
+ obj_word (orp, arrtmp->size); /* size of type */
+ obj_byte (orp, 0x1A); /* absolute type for debugging (array)*/
+ obj_byte (orp, arrtmp->basetype ); /* base type */
+ obj_emit2 (orp);
+ arrtmp = arrtmp->next ;
+ }
+ }
+ /*
+ * write out line number info with a LINNUM record
+ * switch records when we switch segments, and output the
+ * file in a pseudo-TASM fashion. The record switch is naive; that
+ * is that one file may have many records for the same segment
+ * if there are lots of segment switches
*/
- for (data = datahead; data; data = data->next) {
- if (data->nonempty) {
- obj_record (data->letype, data->ledata, data->lptr);
- if (data->fptr != data->fixupp)
- obj_record (data->ftype, data->fixupp, data->fptr);
+ if (fnhead && debuginfo) {
+ seg = fnhead->lnhead->segment;
+
+ for (fn = fnhead; fn; fn = fn->next) {
+ /* write out current file name */
+ orp->type = COMENT;
+ orp->ori = ori_null;
+ obj_byte (orp, 0x40);
+ obj_byte (orp, dFILNAME);
+ obj_byte( orp,0);
+ obj_name( orp,fn->name);
+ obj_dword(orp, 0);
+ obj_emit2 (orp);
+
+ /* write out line numbers this file */
+
+ orp->type = LINNUM;
+ orp->ori = ori_linnum;
+ for (ln = fn->lnhead; ln; ln = ln->next) {
+ if (seg != ln->segment) {
+ /* if we get here have to flush the buffer and start
+ * a new record for a new segment
+ */
+ seg = ln->segment;
+ obj_emit ( orp );
+ }
+ orp->parm[0] = seg->grp ? seg->grp->obj_index : 0;
+ orp->parm[1] = seg->obj_index;
+ orp = obj_word(orp, ln->lineno);
+ orp = obj_x(orp, ln->offset);
+ obj_commit (orp);
+ }
+ obj_emit (orp);
}
}
-
/*
- * Write the MODEND module end marker.
+ * we are going to locate the entry point segment now
+ * rather than wait until the MODEND record, because,
+ * then we can output a special symbol to tell where the
+ * entry point is.
+ *
*/
- recptr = record;
- rectype = MODEND;
if (obj_entry_seg != NO_SEG) {
- recptr = obj_write_byte (recptr, 0xC1);
- /*
- * Find the segment in the segment list.
- */
for (seg = seghead; seg; seg = seg->next) {
if (seg->index == obj_entry_seg) {
- if (seg->grp) {
- recptr = obj_write_byte (recptr, 0x10);
- recptr = obj_write_index (recptr, seg->grp->obj_index);
- } else {
- recptr = obj_write_byte (recptr, 0x50);
- }
- recptr = obj_write_index (recptr, seg->obj_index);
- if (seg->use32) {
- rectype = MODEND+1;
- recptr = obj_write_dword (recptr, obj_entry_ofs);
- } else
- recptr = obj_write_word (recptr, obj_entry_ofs);
+ entry_seg_ptr = seg;
break;
}
}
if (!seg)
error(ERR_NONFATAL, "entry point is not in this module");
- } else
- recptr = obj_write_byte (recptr, 0);
- obj_record (rectype, record, recptr);
-}
-
-static unsigned char *obj_write_data(unsigned char *ptr,
- unsigned char *data, int len) {
- while (len--)
- *ptr++ = *data++;
- return ptr;
-}
-
-static unsigned char *obj_write_byte(unsigned char *ptr, int data) {
- *ptr++ = data;
- return ptr;
-}
-
-static unsigned char *obj_write_word(unsigned char *ptr, int data) {
- *ptr++ = data & 0xFF;
- *ptr++ = (data >> 8) & 0xFF;
- return ptr;
-}
-
-static unsigned char *obj_write_dword(unsigned char *ptr, long data) {
- *ptr++ = data & 0xFF;
- *ptr++ = (data >> 8) & 0xFF;
- *ptr++ = (data >> 16) & 0xFF;
- *ptr++ = (data >> 24) & 0xFF;
- return ptr;
-}
-
-static unsigned char *obj_write_rword(unsigned char *ptr, int data) {
- *ptr++ = (data >> 8) & 0xFF;
- *ptr++ = data & 0xFF;
- return ptr;
-}
-
-static unsigned char *obj_write_name(unsigned char *ptr, char *data) {
- *ptr++ = strlen(data);
- if (obj_uppercase) {
- while (*data) {
- *ptr++ = (unsigned char) toupper(*data);
- data++;
- }
- } else {
- while (*data)
- *ptr++ = (unsigned char) *data++;
}
- return ptr;
-}
-static unsigned char *obj_write_index(unsigned char *ptr, int data) {
- if (data < 128)
- *ptr++ = data;
- else {
- *ptr++ = 0x80 | ((data >> 8) & 0x7F);
- *ptr++ = data & 0xFF;
+ /*
+ * get ready to put out symbol records
+ */
+ orp->type = COMENT;
+ orp->ori = ori_local;
+
+ /*
+ * put out a symbol for the entry point
+ * no dots in this symbol, because, borland does
+ * not (officially) support dots in label names
+ * and I don't know what various versions of TLINK will do
+ */
+ if (debuginfo && obj_entry_seg != NO_SEG) {
+ orp = obj_name (orp,"start_of_program");
+ orp = obj_word (orp,0x19); /* type: near label */
+ orp = obj_index (orp, seg->grp ? seg->grp->obj_index : 0);
+ orp = obj_index (orp, seg->obj_index);
+ orp = obj_x (orp, obj_entry_ofs);
+ obj_commit (orp);
+ }
+
+ /*
+ * put out the local labels
+ */
+ for (seg = seghead; seg && debuginfo; seg = seg->next) {
+ /* labels this seg */
+ for (loc = seg->lochead; loc; loc = loc->next) {
+ orp = obj_name (orp,loc->name);
+ orp = obj_word (orp, loc->type);
+ orp = obj_index (orp, seg->grp ? seg->grp->obj_index : 0);
+ orp = obj_index (orp, seg->obj_index);
+ orp = obj_x (orp,loc->offset);
+ obj_commit (orp);
+ }
}
- return ptr;
-}
+ if (orp->used)
+ obj_emit (orp);
-static unsigned char *obj_write_value(unsigned char *ptr,
- unsigned long data) {
- if (data <= 128)
- *ptr++ = data;
- else if (data <= 0xFFFF) {
- *ptr++ = 129;
- *ptr++ = data & 0xFF;
- *ptr++ = (data >> 8) & 0xFF;
- } else if (data <= 0xFFFFFFL) {
- *ptr++ = 132;
- *ptr++ = data & 0xFF;
- *ptr++ = (data >> 8) & 0xFF;
- *ptr++ = (data >> 16) & 0xFF;
- } else {
- *ptr++ = 136;
- *ptr++ = data & 0xFF;
- *ptr++ = (data >> 8) & 0xFF;
- *ptr++ = (data >> 16) & 0xFF;
- *ptr++ = (data >> 24) & 0xFF;
+ /*
+ * Write the LEDATA/FIXUPP pairs.
+ */
+ for (seg = seghead; seg; seg = seg->next) {
+ obj_emit (seg->orp);
+ nasm_free (seg->orp);
}
- return ptr;
+
+ /*
+ * Write the MODEND module end marker.
+ */
+ orp->type = MODEND;
+ orp->ori = ori_null;
+ if (entry_seg_ptr) {
+ obj_byte (orp, 0xC1);
+ seg = entry_seg_ptr;
+ if (seg->grp) {
+ obj_byte (orp, 0x10);
+ obj_index (orp, seg->grp->obj_index);
+ } else {
+ /*
+ * the below changed to prevent TLINK crashing.
+ * Previous more efficient version read:
+ *
+ * obj_byte (orp, 0x50);
+ */
+ obj_byte (orp, 0x00);
+ obj_index (orp, seg->obj_index);
+ }
+ obj_index (orp, seg->obj_index);
+ obj_x (orp, obj_entry_ofs);
+ } else
+ obj_byte (orp, 0);
+ obj_emit2 (orp);
+ nasm_free (orp);
}
-static void obj_record(int type, unsigned char *start, unsigned char *end) {
- unsigned long cksum, len;
+void obj_fwrite(ObjRecord *orp)
+{
+ unsigned int cksum, len;
+ unsigned char *ptr;
- cksum = type;
- fputc (type, ofp);
- len = end-start+1;
+ cksum = orp->type;
+ if (orp->x_size == 32)
+ cksum |= 1;
+ fputc (cksum, ofp);
+ len = orp->committed+1;
cksum += (len & 0xFF) + ((len>>8) & 0xFF);
fwriteshort (len, ofp);
- fwrite (start, 1, end-start, ofp);
- while (start < end)
- cksum += *start++;
- fputc ( (-(long)cksum) & 0xFF, ofp);
+ fwrite (orp->buf, 1, len-1, ofp);
+ for (ptr=orp->buf; --len; ptr++)
+ cksum += *ptr;
+ fputc ( (-cksum) & 0xFF, ofp);
}
static char *obj_stdmac[] = {
@@ -1743,7 +2232,7 @@ static char *obj_stdmac[] = {
"%imacro group 1+.nolist",
"[group %1]",
"%endmacro",
- "%imacro uppercase 1+.nolist",
+ "%imacro uppercase 0+.nolist",
"[uppercase %1]",
"%endmacro",
"%imacro export 1+.nolist",
@@ -1752,14 +2241,243 @@ static char *obj_stdmac[] = {
"%imacro import 1+.nolist",
"[import %1]",
"%endmacro",
+ "%macro __NASM_CDecl__ 1",
+ "%endmacro",
NULL
};
+void dbgbi_init(struct ofmt * of, void * id, FILE * fp, efunc error)
+{
+ (void) of;
+ (void) id;
+ (void) fp;
+ (void) error;
+
+ fnhead = NULL;
+ fntail = &fnhead;
+ arrindex = ARRAYBOT ;
+ arrhead = NULL;
+ arrtail = &arrhead;
+}
+static void dbgbi_cleanup(void)
+{
+ struct Segment *segtmp;
+ while (fnhead) {
+ struct FileName *fntemp = fnhead;
+ while (fnhead->lnhead) {
+ struct LineNumber *lntemp = fnhead->lnhead;
+ fnhead->lnhead = lntemp->next;
+ nasm_free( lntemp);
+ }
+ fnhead = fnhead->next;
+ nasm_free (fntemp->name);
+ nasm_free (fntemp);
+ }
+ for (segtmp=seghead; segtmp; segtmp=segtmp->next) {
+ while (segtmp->lochead) {
+ struct Public *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);
+ }
+}
+
+static void dbgbi_linnum (const char *lnfname, long lineno, long segto)
+{
+ struct FileName *fn;
+ struct LineNumber *ln;
+ struct Segment *seg;
+
+ 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 != obj_segment("__NASMDEFSEG", 2, &tempint))
+ error (ERR_PANIC, "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)
+ error (ERR_PANIC, "lineno directed to nonexistent segment?");
+
+ for (fn = fnhead; fn; fn = fnhead->next)
+ if (!nasm_stricmp(lnfname,fn->name))
+ break;
+ if (!fn) {
+ fn = nasm_malloc ( sizeof( *fn));
+ fn->name = nasm_malloc ( strlen(lnfname) + 1) ;
+ strcpy (fn->name,lnfname);
+ fn->lnhead = NULL;
+ fn->lntail = & fn->lnhead;
+ fn->next = NULL;
+ *fntail = fn;
+ fntail = &fn->next;
+ }
+ ln = nasm_malloc ( sizeof( *ln));
+ ln->segment = seg;
+ ln->offset = seg->currentpos;
+ ln->lineno = lineno;
+ ln->next = NULL;
+ *fn->lntail = ln;
+ fn->lntail = &ln->next;
+
+}
+static void dbgbi_deflabel (char *name, long segment,
+ long offset, int is_global, char *special)
+{
+ struct Segment *seg;
+
+ (void) special;
+
+ /*
+ * If it's a special-retry from pass two, discard it.
+ */
+ if (is_global == 3)
+ return;
+
+ /*
+ * First check for the double-period, signifying something
+ * unusual.
+ */
+ if (name[0] == '.' && name[1] == '.' && name[2] != '@') {
+ return;
+ }
+
+ /*
+ * Case (i):
+ */
+ if (obj_seg_needs_update) {
+ return;
+ } else if (obj_grp_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 obj_deflabel so we can skip that.
+ */
+
+ for (seg = seghead; seg; seg = seg->next)
+ if (seg->index == segment) {
+ struct Public *loc = nasm_malloc (sizeof(*loc));
+ /*
+ * Case (ii). Maybe MODPUB someday?
+ */
+ last_defined = *seg->loctail = loc;
+ seg->loctail = &loc->next;
+ loc->next = NULL;
+ loc->name = nasm_strdup(name);
+ loc->offset = offset;
+ }
+}
+static void dbgbi_typevalue (long type)
+{
+ int vsize;
+ int elem = TYM_ELEMENTS(type);
+ type = TYM_TYPE(type);
+
+ if (!last_defined)
+ return;
+
+ switch (type) {
+ case TY_BYTE:
+ last_defined->type = 8; /* unsigned char */
+ vsize = 1;
+ break;
+ case TY_WORD:
+ last_defined->type = 10; /* unsigned word */
+ vsize = 2;
+ break;
+ case TY_DWORD:
+ last_defined->type = 12; /* unsigned dword */
+ vsize = 4;
+ break;
+ case TY_FLOAT:
+ last_defined->type = 14; /* float */
+ vsize = 4;
+ break;
+ case TY_QWORD:
+ last_defined->type = 15; /* qword */
+ vsize = 8;
+ break;
+ case TY_TBYTE:
+ last_defined->type = 16; /* TBYTE */
+ vsize = 10;
+ break;
+ default:
+ last_defined->type = 0x19; /*label */
+ vsize = 0;
+ break;
+ }
+
+ if (elem > 1) {
+ struct Array *arrtmp = nasm_malloc (sizeof(*arrtmp));
+ int vtype = last_defined->type;
+ arrtmp->size = vsize * elem;
+ arrtmp->basetype = vtype;
+ arrtmp->next = NULL;
+ last_defined->type = arrindex++;
+ *arrtail = arrtmp;
+ arrtail = & (arrtmp->next);
+ }
+ last_defined = NULL;
+}
+static void dbgbi_output (int output_type, void *param)
+{
+ (void) output_type;
+ (void) param;
+}
+static struct dfmt borland_debug_form = {
+ "Borland Debug Records",
+ "borland",
+ dbgbi_init,
+ dbgbi_linnum,
+ dbgbi_deflabel,
+ null_debug_routine,
+ dbgbi_typevalue,
+ dbgbi_output,
+ dbgbi_cleanup,
+};
+
+static struct dfmt *borland_debug_arr[3] = {
+ &borland_debug_form,
+ &null_debug_form,
+ NULL
+};
+
struct ofmt of_obj = {
- "Microsoft MS-DOS 16-bit OMF object files",
+ "MS-DOS 16-bit/32-bit OMF object files",
"obj",
+ NULL,
+ borland_debug_arr,
+ &null_debug_form,
obj_stdmac,
obj_init,
+ obj_set_info,
obj_out,
obj_deflabel,
obj_segment,