⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 outobj.c

📁 开源的nasm编译器源码,研究编译器原理很有帮且
💻 C
📖 第 1 页 / 共 5 页
字号:
/* 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 + -