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

📄 assemble.c

📁 汇编编译器的最新版本的源码.买了自己动手写操作系统这本书的人一定要下
💻 C
📖 第 1 页 / 共 5 页
字号:

                if (c <= 0177) {
		    /* pick rfield from operand b */
		    rflags = regflag(&ins->oprs[c & 7]);
                    rfield = nasm_regvals[ins->oprs[c & 7].basereg];
		} else {
		    /* rfield is constant */
		    rflags = 0;
                    rfield = c & 7;
		}

                if (!process_ea
                    (&ins->oprs[(c >> 3) & 7], &ea_data, bits,
		     ins->addr_size, rfield, rflags)) {
                    errfunc(ERR_NONFATAL, "invalid effective address");
                }


                p = bytes;
                *p++ = ea_data.modrm;
                if (ea_data.sib_present)
                    *p++ = ea_data.sib;

		/* DREX suffixes come between the SIB and the displacement */
		if (ins->rex & REX_D) {
		    *p++ =
			(ins->drexdst << 4) |
			(ins->rex & REX_OC ? 0x08 : 0) |
			(ins->rex & (REX_R|REX_X|REX_B));
		    ins->rex = 0;
		}

                s = p - bytes;
                out(offset, segment, bytes, OUT_RAWDATA, s, NO_SEG, NO_SEG);

                /*
                 * Make sure the address gets the right offset in case
                 * the line breaks in the .lst file (BR 1197827)
                 */
                offset += s;
                s = 0;

                switch (ea_data.bytes) {
                case 0:
                    break;
                case 1:
                    if (ins->oprs[(c >> 3) & 7].segment != NO_SEG) {
                        data = ins->oprs[(c >> 3) & 7].offset;
                        out(offset, segment, &data, OUT_ADDRESS, 1,
                            ins->oprs[(c >> 3) & 7].segment,
                            ins->oprs[(c >> 3) & 7].wrt);
                    } else {
                        *bytes = ins->oprs[(c >> 3) & 7].offset;
                        out(offset, segment, bytes, OUT_RAWDATA, 1,
                            NO_SEG, NO_SEG);
                    }
                    s++;
                    break;
                case 8:
                case 2:
                case 4:
                    data = ins->oprs[(c >> 3) & 7].offset;
		    warn_overflow(ea_data.bytes, opx);
                    s += ea_data.bytes;
		    if (ea_data.rip) {
			out(offset, segment, &data,
			    OUT_REL4ADR, insn_end - offset,
			    ins->oprs[(c >> 3) & 7].segment,
			    ins->oprs[(c >> 3) & 7].wrt);
		    } else {
			type = OUT_ADDRESS;
			out(offset, segment, &data,
			    OUT_ADDRESS, ea_data.bytes,
			    ins->oprs[(c >> 3) & 7].segment,
			    ins->oprs[(c >> 3) & 7].wrt);
		    }
                    break;
                }
                offset += s;
	    }
	    break;

	default:
	    errfunc(ERR_PANIC, "internal instruction table corrupt"
		    ": instruction code 0x%02X given", c);
	    break;
        }
    }
}

static int32_t regflag(const operand * o)
{
    if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
        errfunc(ERR_PANIC, "invalid operand passed to regflag()");
    }
    return nasm_reg_flags[o->basereg];
}

static int32_t regval(const operand * o)
{
    if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
        errfunc(ERR_PANIC, "invalid operand passed to regval()");
    }
    return nasm_regvals[o->basereg];
}

static int op_rexflags(const operand * o, int mask)
{
    int32_t flags;
    int val;

    if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
        errfunc(ERR_PANIC, "invalid operand passed to op_rexflags()");
    }

    flags = nasm_reg_flags[o->basereg];
    val = nasm_regvals[o->basereg];

    return rexflags(val, flags, mask);
}

static int rexflags(int val, int32_t flags, int mask)
{
    int rex = 0;

    if (val >= 8)
	rex |= REX_B|REX_X|REX_R;
    if (flags & BITS64)
	rex |= REX_W;
    if (!(REG_HIGH & ~flags))	/* AH, CH, DH, BH */
	rex |= REX_H;
    else if (!(REG8 & ~flags) && val >= 4) /* SPL, BPL, SIL, DIL */
	rex |= REX_P;

    return rex & mask;
}

static int matches(const struct itemplate *itemp, insn * instruction, int bits)
{
    int i, size[MAX_OPERANDS], asize, oprs, ret;

    ret = 100;

    /*
     * Check the opcode
     */
    if (itemp->opcode != instruction->opcode)
        return 0;

    /*
     * Count the operands
     */
    if (itemp->operands != instruction->operands)
        return 0;

    /*
     * Check that no spurious colons or TOs are present
     */
    for (i = 0; i < itemp->operands; i++)
        if (instruction->oprs[i].type & ~itemp->opd[i] & (COLON | TO))
            return 0;

    /*
     * Process size flags
     */
    if (itemp->flags & IF_ARMASK) {
	memset(size, 0, sizeof size);

	i = ((itemp->flags & IF_ARMASK) >> IF_ARSHFT) - 1;

	switch (itemp->flags & IF_SMASK) {
	case IF_SB:
            size[i] = BITS8;
	    break;
	case IF_SW:
            size[i] = BITS16;
	    break;
	case IF_SD:
            size[i] = BITS32;
	    break;
	case IF_SQ:
            size[i] = BITS64;
	    break;
	case IF_SO:
	    size[i] = BITS128;
	    break;
	case IF_SY:
	    size[i] = BITS256;
	    break;
	case IF_SZ:
	    switch (bits) {
	    case 16:
		size[i] = BITS16;
		break;
	    case 32:
		size[i] = BITS32;
		break;
	    case 64:
		size[i] = BITS64;
		break;
	    }
	    break;
	default:
	    break;
        }
    } else {
        asize = 0;
	switch (itemp->flags & IF_SMASK) {
	case IF_SB:
            asize = BITS8;
	    break;
	case IF_SW:
            asize = BITS16;
	    break;
	case IF_SD:
            asize = BITS32;
	    break;
	case IF_SQ:
            asize = BITS64;
	    break;
	case IF_SO:
            asize = BITS128;
	    break;
	case IF_SY:
            asize = BITS256;
	    break;
	case IF_SZ:
	    switch (bits) {
	    case 16:
		asize = BITS16;
		break;
	    case 32:
		asize = BITS32;
		break;
	    case 64:
		asize = BITS64;
		break;
	    }
	    break;
	default:
	    break;
        }
	for (i = 0; i < MAX_OPERANDS; i++)
	    size[i] = asize;
    }

    /*
     * Check that the operand flags all match up
     */
    for (i = 0; i < itemp->operands; i++) {
	int32_t type = instruction->oprs[i].type;
	if (!(type & SIZE_MASK))
	    type |= size[i];

	if (itemp->opd[i] & SAME_AS) {
	    int j = itemp->opd[i] & ~SAME_AS;
	    if (type != instruction->oprs[j].type ||
		instruction->oprs[i].basereg != instruction->oprs[j].basereg)
		return 0;
	} else if (itemp->opd[i] & ~type ||
            ((itemp->opd[i] & SIZE_MASK) &&
             ((itemp->opd[i] ^ type) & SIZE_MASK))) {
            if ((itemp->opd[i] & ~type & ~SIZE_MASK) ||
                (type & SIZE_MASK))
                return 0;
            else
                return 1;
        }
    }

    /*
     * Check operand sizes
     */
    if (itemp->flags & (IF_SM | IF_SM2)) {
        oprs = (itemp->flags & IF_SM2 ? 2 : itemp->operands);
        asize = 0;
        for (i = 0; i < oprs; i++) {
            if ((asize = itemp->opd[i] & SIZE_MASK) != 0) {
                int j;
                for (j = 0; j < oprs; j++)
                    size[j] = asize;
                break;
            }
        }
    } else {
        oprs = itemp->operands;
    }

    for (i = 0; i < itemp->operands; i++) {
        if (!(itemp->opd[i] & SIZE_MASK) &&
            (instruction->oprs[i].type & SIZE_MASK & ~size[i]))
            return 2;
    }

    /*
     * Check template is okay at the set cpu level
     */
    if (((itemp->flags & IF_PLEVEL) > cpu))
        return 3;

    /*
     * Check if instruction is available in long mode
     */
    if ((itemp->flags & IF_NOLONG) && (bits == 64))
        return 4;

    /*
     * Check if special handling needed for Jumps
     */
    if ((uint8_t)(itemp->code[0]) >= 0370)
        return 99;

    return ret;
}

static ea *process_ea(operand * input, ea * output, int bits,
		      int addrbits, int rfield, int32_t rflags)
{
    bool forw_ref = !!(input->opflags & OPFLAG_FORWARD);

    output->rip = false;

    /* REX flags for the rfield operand */
    output->rex |= rexflags(rfield, rflags, REX_R|REX_P|REX_W|REX_H);

    if (!(REGISTER & ~input->type)) {   /* register direct */
        int i;
	int32_t f;

        if (input->basereg < EXPR_REG_START /* Verify as Register */
            || input->basereg >= REG_ENUM_LIMIT)
            return NULL;
	f = regflag(input);
        i = nasm_regvals[input->basereg];

	if (REG_EA & ~f)
	    return NULL;	/* Invalid EA register */

	output->rex |= op_rexflags(input, REX_B|REX_P|REX_W|REX_H);

        output->sib_present = false;             /* no SIB necessary */
        output->bytes = 0;  /* no offset necessary either */
        output->modrm = 0xC0 | ((rfield & 7) << 3) | (i & 7);
    } else {                    /* it's a memory reference */
        if (input->basereg == -1
            && (input->indexreg == -1 || input->scale == 0)) {
            /* it's a pure offset */
            if (bits == 64 && (~input->type & IP_REL)) {
              int scale, index, base;
              output->sib_present = true;
              scale = 0;
              index = 4;
              base = 5;
              output->sib = (scale << 6) | (index << 3) | base;
              output->bytes = 4;
              output->modrm = 4 | ((rfield & 7) << 3);
	      output->rip = false;
            } else {
              output->sib_present = false;
              output->bytes = (addrbits != 16 ? 4 : 2);
              output->modrm = (addrbits != 16 ? 5 : 6) | ((rfield & 7) << 3);
	      output->rip = bits == 64;
            }
        } else {                /* it's an indirection */
            int i = input->indexreg, b = input->basereg, s = input->scale;
            int32_t o = input->offset, seg = input->segment;
            int hb = input->hintbase, ht = input->hinttype;
            int t;
            int it, bt;
	    int32_t ix, bx;	/* register flags */

            if (s == 0)
                i = -1;         /* make this easy, at least */

            if (i >= EXPR_REG_START && i < REG_ENUM_LIMIT) {
                it = nasm_regvals[i];
		ix = nasm_reg_flags[i];
	    } else {
                it = -1;
		ix = 0;
	    }

	    if (b >= EXPR_REG_START && b < REG_ENUM_LIMIT) {
                bt = nasm_regvals[b];
		bx = nasm_reg_flags[b];
	    } else {
                bt = -1;
		bx = 0;
	    }

	    /* check for a 32/64-bit memory reference... */
	    if ((ix|bx) & (BITS32|BITS64)) {
                /* it must be a 32/64-bit memory reference. Firstly we have
                 * to check that all registers involved are type E/Rxx. */
		int32_t sok = BITS32|BITS64;

                if (it != -1) {
		    if (!(REG64 & ~ix) || !(REG32 & ~ix))
			sok &= ix;
		    else
			return NULL;
		}

		if (bt != -1) {
		    if (REG_GPR & ~bx)
			return NULL; /* Invalid register */
		    if (~sok & bx & SIZE_MASK)
			return NULL; /* Invalid size */
		    sok &= bx;
		}

                /* While we're here, ensure the user didn't specify
		   WORD or QWORD. */
                if (input->disp_size == 16 || input->disp_size == 64)
		    return NULL;

		if (addrbits == 16 ||
		    (addrbits == 32 && !(sok & BITS32)) ||
		    (addrbits == 64 && !(sok & BITS64)))
		    return NULL;

                /* now reorganize base/index */
                if (s == 1 && bt != it && bt != -1 && it != -1 &&
                    ((hb == b && ht == EAH_NOTBASE)
                     || (hb == i && ht == EAH_MAKEBASE))) {
		    /* swap if hints say so */
                    t = bt, bt = it, it = t;
		    t = bx, bx = ix, ix = t;
		}
                if (bt == it)     /* convert EAX+2*EAX to 3*EAX */
                    bt = -1, bx = 0, s++;
                if (bt == -1 && s == 1 && !(hb == it && ht == EAH_NOTBASE)) {
		    /* make single reg ba

⌨️ 快捷键说明

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