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

📄 outobj.c

📁 nasm的全套源代码,有些我做了些修改,以方便您更方便更容易调试成功,方便学习做编译器
💻 C
📖 第 1 页 / 共 5 页
字号:
            loc->name = nasm_strdup(name);
            loc->offset = offset;

            if (special)
                error(ERR_NONFATAL,
                      "OBJ supports no special symbol features"
                      " for this symbol type");
            return;
        }

    /*
     * Case (iii).
     */
    if (is_global) {
        ext = *exttail = nasm_malloc(sizeof(*ext));
        ext->next = NULL;
        exttail = &ext->next;
        ext->name = name;
        /* Place by default all externs into the current segment */
        ext->defwrt_type = DEFWRT_NONE;

/* 28-Apr-2002 - John Coffman
  The following code was introduced on 12-Aug-2000, and breaks fixups
  on code passed thru the MSC 5.1 linker (3.66) and MSC 6.00A linker
  (5.10).  It was introduced after FIXUP32 was added, and may be needed
  for 32-bit segments.  The following will get 16-bit segments working
  again, and maybe someone can correct the 'if' condition which is
  actually needed.
*/
#if 0
        if (current_seg) {
#else
        if (current_seg && current_seg->use32) {
            if (current_seg->grp) {
                ext->defwrt_type = DEFWRT_GROUP;
                ext->defwrt_ptr.grp = current_seg->grp;
            } else {
                ext->defwrt_type = DEFWRT_SEGMENT;
                ext->defwrt_ptr.seg = current_seg;
            }
        }
#endif

        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
     * specifications and common-variable element-size and near/far
     * specifications.
     */
    while (special && *special) {
        used_special = TRUE;

        /*
         * We might have a default-WRT specification.
         */
        if (!nasm_strnicmp(special, "wrt", 3)) {
            char *p;
            int len;
            special += 3;
            special += strspn(special, " \t");
            p = nasm_strndup(special, len = strcspn(special, ":"));
            obj_ext_set_defwrt(ext, p);
            special += len;
            if (*special && *special != ':')
                error(ERR_NONFATAL, "`:' expected in special symbol"
                      " text for `%s'", ext->name);
            else if (*special == ':')
                special++;
        }

        /*
         * The NEAR or FAR keywords specify nearness or
         * farness. FAR gives default element size 1.
         */
        if (!nasm_strnicmp(special, "far", 3)) {
            if (ext->commonsize)
                ext->commonelem = 1;
            else
                error(ERR_NONFATAL,
                      "`%s': `far' keyword may only be applied"
                      " to common variables\n", ext->name);
            special += 3;
            special += strspn(special, " \t");
        } else if (!nasm_strnicmp(special, "near", 4)) {
            if (ext->commonsize)
                ext->commonelem = 0;
            else
                error(ERR_NONFATAL,
                      "`%s': `far' keyword may only be applied"
                      " to common variables\n", ext->name);
            special += 4;
            special += strspn(special, " \t");
        }

        /*
         * If it's a common, and anything else remains on the line
         * before a further colon, evaluate it as an expression and
         * use that as the element size. Forward references aren't
         * allowed.
         */
        if (*special == ':')
            special++;
        else if (*special) {
            if (ext->commonsize) {
                expr *e;
                struct tokenval tokval;

                stdscan_reset();
                stdscan_bufptr = special;
                tokval.t_type = TOKEN_INVALID;
                e = evaluate(stdscan, NULL, &tokval, NULL, 1, error, NULL);
                if (e) {
                    if (!is_simple(e))
                        error(ERR_NONFATAL, "cannot use relocatable"
                              " expression as common-variable element size");
                    else
                        ext->commonelem = reloc_value(e);
                }
                special = stdscan_bufptr;
            } else {
                error(ERR_NONFATAL,
                      "`%s': element-size specifications only"
                      " apply to common variables", ext->name);
                while (*special && *special != ':')
                    special++;
                if (*special == ':')
                    special++;
            }
        }
    }

    i = segment / 2;
    eb = ebhead;
    if (!eb) {
        eb = *ebtail = nasm_malloc(sizeof(*eb));
        eb->next = NULL;
        ebtail = &eb->next;
    }
    while (i >= EXT_BLKSIZ) {
        if (eb && eb->next)
            eb = eb->next;
        else {
            eb = *ebtail = nasm_malloc(sizeof(*eb));
            eb->next = NULL;
            ebtail = &eb->next;
        }
        i -= EXT_BLKSIZ;
    }
    eb->exts[i] = ext;
    ext->index = ++externals;

    if (special && !used_special)
        error(ERR_NONFATAL, "OBJ supports no special symbol features"
              " for this symbol type");
}

/* forward declaration */
static void obj_write_fixup(ObjRecord * orp, int bytes,
                            int segrel, long seg, long wrt,
                            struct Segment *segto);

static void obj_out(long segto, const void *data, unsigned long type,
                    long segment, long wrt)
{
    unsigned long size, realtype;
    const unsigned char *ucdata;
    long ldata;
    struct Segment *seg;
    ObjRecord *orp;

    /*
     * handle absolute-assembly (structure definitions)
     */
    if (segto == NO_SEG) {
        if ((type & OUT_TYPMASK) != OUT_RESERVE)
            error(ERR_NONFATAL, "attempt to assemble code in [ABSOLUTE]"
                  " space");
        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, "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) {
            unsigned int len;
            orp = obj_check(seg->orp, 1);
            len = RECORD_MAX - orp->used;
            if (len > size)
                len = size;
            memcpy(orp->buf + orp->used, ucdata, len);
            orp->committed = orp->used += len;
            orp->parm[0] = seg->currentpos += len;
            ucdata += len;
            size -= len;
        }
    } else if (realtype == OUT_ADDRESS || realtype == OUT_REL2ADR ||
               realtype == OUT_REL4ADR) {
        int rsize;

        if (segment == NO_SEG && realtype != OUT_ADDRESS)
            error(ERR_NONFATAL, "relative call to absolute address not"
                  " supported by OBJ format");
        if (segment >= SEG_ABS)
            error(ERR_NONFATAL, "far-absolute relocations not supported"
                  " by OBJ format");
        ldata = *(long *)data;
        if (realtype == OUT_REL2ADR) {
            ldata += (size - 2);
            size = 2;
        }
        if (realtype == OUT_REL4ADR) {
            ldata += (size - 4);
            size = 4;
        }
        if (size == 2)
            orp = obj_word(orp, ldata);
        else
            orp = obj_dword(orp, ldata);
        rsize = size;
        if (segment < SEG_ABS && (segment != NO_SEG && segment % 2) &&
            size == 4) {
            /*
             * This is a 4-byte segment-base relocation such as
             * `MOV EAX,SEG foo'. OBJ format can't actually handle
             * these, but if the constant term has the 16 low bits
             * zero, we can just apply a 2-byte segment-base
             * relocation to the low word instead.
             */
            rsize = 2;
            if (ldata & 0xFFFF)
                error(ERR_NONFATAL, "OBJ format cannot handle complex"
                      " dword-size segment base references");
        }
        if (segment != NO_SEG)
            obj_write_fixup(orp, rsize,
                            (realtype == OUT_ADDRESS ? 0x4000 : 0),
                            segment, wrt, seg);
        seg->currentpos += size;
    } else if (realtype == OUT_RESERVE) {
        if (orp->committed)
            orp = obj_bump(orp);
        seg->currentpos += size;
    }
    obj_commit(orp);
}

static void obj_write_fixup(ObjRecord * orp, int bytes,
                            int segrel, long seg, long wrt,
                            struct Segment *segto)
{
    unsigned locat;
    int 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"
              " one-byte relocations");
        return;
    }

    forp = orp->child;
    if (forp == NULL) {
        orp->child = forp = obj_new();
        forp->up = &(orp->child);
        /* We should choose between FIXUPP and FIXU32 record type */
        /* If we're targeting a 32-bit segment, use a FIXU32 record */
        if (segto->use32)
            forp->type = FIXU32;
        else
            forp->type = FIXUPP;
    }

    if (seg % 2) {
        base = TRUE;
        locat = FIX_16_SELECTOR;
        seg--;
        if (bytes != 2)
            error(ERR_PANIC, "OBJ: 4-byte segment base fixup got"
                  " through sanity check");
    } else {
        base = FALSE;
        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);
    }

    forp = obj_rword(forp, locat | segrel | (orp->parm[0] - orp->parm[2]));

    tidx = fidx = -1, method = 0;       /* placate optimisers */

    /*
     * See if we can find the segment ID in our segment list. If
     * so, we have a T4 (LSEG) target.
     */
    for (s = seghead; s; s = s->next)
        if (s->index == seg)
            break;
    if (s)
        method = 4, tidx = s->obj_index;
    else {
        for (g = grphead; g; g = g->next)
            if (g->index == seg)
                break;
        if (g)
            method = 5, tidx = g->obj_index;
        else {
            long i = seg / 2;
            struct ExtBack *eb = ebhead;
            while (i > EXT_BLKSIZ) {
                if (eb)
                    eb = eb->next;
                else
                    break;
                i -= EXT_BLKSIZ;
            }
            if (eb)
                method = 6, e = eb->exts[i], tidx = e->index;
            else
                error(ERR_PANIC,
                      "unrecognised segment value in obj_write_fixup");
        }
    }

    /*
     * If no WRT given, assume the natural default, which is method
     * F5 unless:
     *
     * - we are doing an OFFSET fixup for a grouped segment, in
     *   which case we require F1 (group).
     *
     * - we are doing an OFFSET fixup for an external with a
     *   default WRT, in which case we must honour the default WRT.
     */
    if (wrt == NO_SEG) {
        if (!base && s && s->grp)
            method |= 0x10, fidx = s->grp->obj_index;
        else if (!base && e && e->defwrt_type != DEFWRT_NONE) {
            if (e->defwrt_type == DEFWRT_SEGMENT)
                method |= 0x00, fidx = e->defwrt_ptr.seg->obj_index;
            else if (e->defwrt_type == DEFWRT_GROUP)
                method |= 0x10, fidx = e->defwrt_ptr.grp->obj_index;
            else {
                error(ERR_NONFATAL, "default WRT specification for"
                      " external `%s' unresolved", e->name);
                method |= 0x50, fidx = -1;      /* got to do _something_ */
            }
        } else
            method |= 0x50, fidx = -1;
    } else {
        /*
         * See if we can find the WRT-segment ID in our segment
         * list. If so, we have a F0 (LSEG) frame.
         */
        for (s = seghead; s; s = s->next)
            if (s->index == wrt - 1)
                break;
        if (s)
            method |= 0x00, fidx = s->obj_index;
        else {
            for (g = grphead; g; g = g->next)
                if (g->index == wrt - 1)
                    break;
            if (g)
                method |= 0x10, fidx = g->obj_index;
            else {
                long i = wrt / 2;
                struct ExtBack *eb = ebhead;
                while (i > EXT_BLKSIZ) {
                    if (eb)
                        eb = eb->next;
                    else
                        break;
                    i -= EXT_BLKSIZ;

⌨️ 快捷键说明

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