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

📄 outobj.c

📁 一个免费的汇编语言编译器的源代码
💻 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  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) */
    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;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -