int
yasm_bc_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
                 void *add_span_data)
{
    int retval = 0;

    bc->len = 0;

    if (!bc->callback)
        yasm_internal_error(N_("got empty bytecode in yasm_bc_calc_len"));
    else
        retval = bc->callback->calc_len(bc, add_span, add_span_data);

    /* Check for multiples */
    bc->mult_int = 1;
    if (bc->multiple) {
        /*@dependent@*/ /*@null@*/ const yasm_intnum *num;

        num = yasm_expr_get_intnum(&bc->multiple, 0);
        if (num) {
            if (yasm_intnum_sign(num) < 0) {
                yasm_error_set(YASM_ERROR_VALUE, N_("multiple is negative"));
                retval = -1;
            } else
                bc->mult_int = yasm_intnum_get_int(num);
        } else {
            if (yasm_expr__contains(bc->multiple, YASM_EXPR_FLOAT)) {
                yasm_error_set(YASM_ERROR_VALUE,
                    N_("expression must not contain floating point value"));
                retval = -1;
            } else {
                yasm_value value;
                yasm_value_initialize(&value, bc->multiple, 0);
                add_span(add_span_data, bc, 0, &value, 0, 0);
                bc->mult_int = 0;   /* assume 0 to start */
            }
        }
    }

    /* If we got an error somewhere along the line, clear out any calc len */
    if (retval < 0)
        bc->len = 0;

    return retval;
}
示例#2
0
文件: expr.c 项目: Acidburn0zzz/yasm
/* Check for and simplify identities.  Returns new number of expr terms.
 * Sets e->op = EXPR_IDENT if numterms ends up being 1.
 * Uses numterms parameter instead of e->numterms for basis of "new" number
 * of terms.
 * Assumes int_term is *only* integer term in e.
 * NOTE: Really designed to only be used by expr_level_op().
 */
static int
expr_simplify_identity(yasm_expr *e, int numterms, int *int_term,
                       int simplify_reg_mul)
{
    int i;
    int save_numterms;

    /* Don't do this step if it's 1*REG.  Save and restore numterms so
     * yasm_expr__contains() works correctly.
     */
    save_numterms = e->numterms;
    e->numterms = numterms;
    if (simplify_reg_mul || e->op != YASM_EXPR_MUL
        || !yasm_intnum_is_pos1(e->terms[*int_term].data.intn)
        || !yasm_expr__contains(e, YASM_EXPR_REG)) {
        /* Check for simple identities that delete the intnum.
         * Don't delete if the intnum is the only thing in the expn.
         */
        if ((*int_term == 0 && numterms > 1 &&
             expr_can_destroy_int_left(e->op, e->terms[0].data.intn)) ||
            (*int_term > 0 &&
             expr_can_destroy_int_right(e->op,
                                        e->terms[*int_term].data.intn))) {
            /* Delete the intnum */
            yasm_intnum_destroy(e->terms[*int_term].data.intn);

            /* Slide everything to its right over by 1 */
            if (*int_term != numterms-1) /* if it wasn't last.. */
                memmove(&e->terms[*int_term], &e->terms[*int_term+1],
                        (numterms-1-*int_term)*sizeof(yasm_expr__item));

            /* Update numterms */
            numterms--;
            *int_term = -1;     /* no longer an int term */
        }
    }
    e->numterms = save_numterms;

    /* Check for simple identites that delete everything BUT the intnum.
     * Don't bother if the intnum is the only thing in the expn.
     */
    if (numterms > 1 && *int_term != -1 &&
        expr_is_constant(e->op, e->terms[*int_term].data.intn)) {
        /* Loop through, deleting everything but the integer term */
        for (i=0; i<e->numterms; i++)
            if (i != *int_term)
                expr_delete_term(&e->terms[i], 1);

        /* Move integer term to the first term (if not already there) */
        if (*int_term != 0)
            e->terms[0] = e->terms[*int_term];  /* structure copy */

        /* Set numterms to 1 */
        numterms = 1;
    }

    /* Compute NOT, NEG, and LNOT on single intnum. */
    if (numterms == 1 && *int_term == 0 &&
        (e->op == YASM_EXPR_NOT || e->op == YASM_EXPR_NEG ||
         e->op == YASM_EXPR_LNOT))
        yasm_intnum_calc(e->terms[0].data.intn, e->op, NULL);

    /* Change expression to IDENT if possible. */
    if (numterms == 1)
        e->op = YASM_EXPR_IDENT;

    /* Return the updated numterms */
    return numterms;
}
示例#3
0
int
yasm_value_output_basic(yasm_value *value, /*@out@*/ unsigned char *buf,
                        size_t destsize, yasm_bytecode *bc, int warn,
                        yasm_arch *arch)
{
    /*@dependent@*/ /*@null@*/ yasm_intnum *intn = NULL;
    /*@only@*/ yasm_intnum *outval;
    int sym_local;
    int retval = 1;
    unsigned int valsize = value->size;

    if (value->no_warn)
        warn = 0;

    if (value->abs) {
        /* Handle floating point expressions */
        if (!value->rel && value->abs->op == YASM_EXPR_IDENT
            && value->abs->terms[0].type == YASM_EXPR_FLOAT) {
            if (yasm_arch_floatnum_tobytes(arch, value->abs->terms[0].data.flt,
                                           buf, destsize, valsize, 0, warn))
                return -1;
            else
                return 1;
        }

        /* Check for complex float expressions */
        if (yasm_expr__contains(value->abs, YASM_EXPR_FLOAT)) {
            yasm_error_set(YASM_ERROR_FLOATING_POINT,
                           N_("floating point expression too complex"));
            return -1;
        }

        /* Handle normal integer expressions */
        intn = yasm_expr_get_intnum(&value->abs, 1);

        if (!intn) {
            /* Second try before erroring: yasm_expr_get_intnum doesn't handle
             * SEG:OFF, so try simplifying out any to just the OFF portion,
             * then getting the intnum again.
             */
            yasm_expr *seg = yasm_expr_extract_deep_segoff(&value->abs);
            if (seg)
                yasm_expr_destroy(seg);
            intn = yasm_expr_get_intnum(&value->abs, 1);
        }

        if (!intn) {
            /* Still don't have an integer! */
            yasm_error_set(YASM_ERROR_TOO_COMPLEX,
                           N_("expression too complex"));
            return -1;
        }
    }

    /* Adjust warn for signed/unsigned integer warnings */
    if (warn != 0)
        warn = value->sign ? -1 : 1;

    if (value->rel) {
        /* If relative portion is not in bc section, don't try to handle it
         * here.  Otherwise get the relative portion's offset.
         */
        /*@dependent@*/ yasm_bytecode *rel_prevbc;
        unsigned long dist;

        sym_local = yasm_symrec_get_label(value->rel, &rel_prevbc);
        if (value->wrt || value->seg_of || value->section_rel || !sym_local)
            return 0;       /* we can't handle SEG, WRT, or external symbols */
        if (rel_prevbc->section != bc->section)
            return 0;       /* not in this section */
        if (!value->curpos_rel)
            return 0;       /* not PC-relative */

        /* Calculate value relative to current assembly position */
        dist = yasm_bc_next_offset(rel_prevbc);
        if (dist < bc->offset) {
            outval = yasm_intnum_create_uint(bc->offset - dist);
            yasm_intnum_calc(outval, YASM_EXPR_NEG, NULL);
        } else {
            dist -= bc->offset;
            outval = yasm_intnum_create_uint(dist);
        }

        if (value->rshift > 0) {
            /*@only@*/ yasm_intnum *shamt =
                yasm_intnum_create_uint((unsigned long)value->rshift);
            yasm_intnum_calc(outval, YASM_EXPR_SHR, shamt);
            yasm_intnum_destroy(shamt);
        }
        /* Add in absolute portion */
        if (intn)
            yasm_intnum_calc(outval, YASM_EXPR_ADD, intn);
        /* Output! */
        if (yasm_arch_intnum_tobytes(arch, outval, buf, destsize, valsize, 0,
                                     bc, warn))
            retval = -1;
        yasm_intnum_destroy(outval);
        return retval;
    }

    if (value->seg_of || value->rshift || value->curpos_rel || value->ip_rel
        || value->section_rel)
        return 0;   /* We can't handle this with just an absolute */

    if (intn) {
        /* Output just absolute portion */
        if (yasm_arch_intnum_tobytes(arch, intn, buf, destsize, valsize, 0, bc,
                                     warn))
            retval = -1;
    } else {
        /* No absolute or relative portions: output 0 */
        outval = yasm_intnum_create_uint(0);
        if (yasm_arch_intnum_tobytes(arch, outval, buf, destsize, valsize, 0,
                                     bc, warn))
            retval = -1;
        yasm_intnum_destroy(outval);
    }
    return retval;
}
示例#4
0
文件: expr.c 项目: Acidburn0zzz/yasm
/* Negates e by multiplying by -1, with distribution over lower-precedence
 * operators (eg ADD) and special handling to simplify result w/ADD, NEG, and
 * others.
 *
 * Returns a possibly reallocated e.
 */
static /*@only@*/ yasm_expr *
expr_xform_neg_helper(/*@returned@*/ /*@only@*/ yasm_expr *e)
{
    yasm_expr *ne;
    int i;

    switch (e->op) {
        case YASM_EXPR_ADD:
            /* distribute (recursively if expr) over terms */
            for (i=0; i<e->numterms; i++) {
                if (e->terms[i].type == YASM_EXPR_EXPR)
                    e->terms[i].data.expn =
                        expr_xform_neg_helper(e->terms[i].data.expn);
                else
                    expr_xform_neg_item(e, &e->terms[i]);
            }
            break;
        case YASM_EXPR_SUB:
            /* change op to ADD, and recursively negate left side (if expr) */
            e->op = YASM_EXPR_ADD;
            if (e->terms[0].type == YASM_EXPR_EXPR)
                e->terms[0].data.expn =
                    expr_xform_neg_helper(e->terms[0].data.expn);
            else
                expr_xform_neg_item(e, &e->terms[0]);
            break;
        case YASM_EXPR_NEG:
            /* Negating a negated value?  Make it an IDENT. */
            e->op = YASM_EXPR_IDENT;
            break;
        case YASM_EXPR_IDENT:
            /* Negating an ident?  Change it into a MUL w/ -1 if there's no
             * floatnums present below; if there ARE floatnums, recurse.
             */
            if (e->terms[0].type == YASM_EXPR_FLOAT)
                yasm_floatnum_calc(e->terms[0].data.flt, YASM_EXPR_NEG, NULL);
            else if (e->terms[0].type == YASM_EXPR_INT)
                yasm_intnum_calc(e->terms[0].data.intn, YASM_EXPR_NEG, NULL);
            else if (e->terms[0].type == YASM_EXPR_EXPR &&
                yasm_expr__contains(e->terms[0].data.expn, YASM_EXPR_FLOAT))
                    expr_xform_neg_helper(e->terms[0].data.expn);
            else {
                e->op = YASM_EXPR_MUL;
                e->numterms = 2;
                e->terms[1].type = YASM_EXPR_INT;
                e->terms[1].data.intn = yasm_intnum_create_int(-1);
            }
            break;
        default:
            /* Everything else.  MUL will be combined when it's leveled.
             * Make a new expr (to replace e) with -1*e.
             */
            ne = yasm_xmalloc(sizeof(yasm_expr));
            ne->op = YASM_EXPR_MUL;
            ne->line = e->line;
            ne->numterms = 2;
            ne->terms[0].type = YASM_EXPR_INT;
            ne->terms[0].data.intn = yasm_intnum_create_int(-1);
            ne->terms[1].type = YASM_EXPR_EXPR;
            ne->terms[1].data.expn = e;
            return ne;
    }
    return e;
}