📄 outobj.c
字号:
/* outobj.c output routines for the Netwide Assembler to produce * .OBJ object files * * The Netwide Assembler is copyright (C) 1996 Simon Tatham and * Julian Hall. All rights reserved. The software is * redistributable under the licence given in the file "Licence" * distributed in the NASM archive. */#include <stdio.h>#include <stdlib.h>#include <string.h>#include <ctype.h>#include "nasm.h"#include "nasmlib.h"#include "outform.h"#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-3) /* maximal size of any record except type+reclen */#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 0xAC00enum 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) */ FIXU32 = 0x9D, /* 32-bit fixups (relocations) */ MODEND = 0x8A, /* module end */ MODE32 = 0x8B /* module end for 32-bit objects */};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+3];};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 int obj_uppercase; /* Flag: all names in uppercase */static int obj_use32; /* Flag: at least one segment is 32-bit *//* * 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 efunc error;static evalfunc evaluate;static ldfunc deflabel;static FILE *ofp;static long first_seg;static int any_segs;static int passtwo;static int arrindex;#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 */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 */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -