diff options
Diffstat (limited to 'outobj.c')
-rw-r--r-- | outobj.c | 1608 |
1 files changed, 1163 insertions, 445 deletions
@@ -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, |