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

📄 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  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]);
}

⌨️ 快捷键说明

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