示例#1
0
static void
elf_x86_amd64_write_secthead_rel(unsigned char *bufp,
                                 elf_secthead *shead,
                                 elf_section_index symtab_idx,
                                 elf_section_index sindex)
{
    yasm_intnum *nreloc;
    yasm_intnum *relocsize;

    YASM_WRITE_32_L(bufp, shead->rel_name ? shead->rel_name->index : 0);
    YASM_WRITE_32_L(bufp, SHT_RELA);
    YASM_WRITE_64Z_L(bufp, 0);
    YASM_WRITE_64Z_L(bufp, 0);
    YASM_WRITE_64Z_L(bufp, shead->rel_offset);

    nreloc = yasm_intnum_create_uint(shead->nreloc);
    relocsize = yasm_intnum_create_uint(RELOC64A_SIZE);
    yasm_intnum_calc(relocsize, YASM_EXPR_MUL, nreloc);
    YASM_WRITE_64I_L(bufp, relocsize);          /* size */
    yasm_intnum_destroy(nreloc);
    yasm_intnum_destroy(relocsize);

    YASM_WRITE_32_L(bufp, symtab_idx);          /* link: symtab index */
    YASM_WRITE_32_L(bufp, shead->index);        /* info: relocated's index */
    YASM_WRITE_64Z_L(bufp, RELOC64_ALIGN);      /* align */
    YASM_WRITE_64Z_L(bufp, RELOC64A_SIZE);      /* entity size */
}
示例#2
0
static void
elf_x86_x86_handle_reloc_addend(yasm_intnum *intn,
                                elf_reloc_entry *reloc,
                                unsigned long offset)
{
    if (!reloc->wrt && reloc->is_GOT_sym && reloc->valsize == 32 && offset != 0)
    {
        yasm_intnum *off_intn = yasm_intnum_create_uint(offset);
        yasm_intnum_calc(intn, YASM_EXPR_ADD, off_intn);
        yasm_intnum_destroy(off_intn);
    }
    return; /* .rel: Leave addend in intn */
}
示例#3
0
static int
run_output_test(Test_Entry *test)
{
    char *valstr = yasm__xstrdup(test->input);
    yasm_intnum *intn = yasm_intnum_create_hex(valstr);
    unsigned long size, i;
    unsigned char out[100];
    int bad;

    yasm_xfree(valstr);

    if (test->negate)
        yasm_intnum_calc(intn, YASM_EXPR_NEG, NULL);

    size = yasm_intnum_size_leb128(intn, test->sign);
    if (size != test->outsize) {
        yasm_intnum_destroy(intn);
        sprintf(failmsg, "%ssigned %s%s size() bad size: expected %lu, got %lu!",
                test->sign?"":"un", test->negate?"-":"", test->input,
                test->outsize, size);
        return 1;
    }

    for (i=0; i<sizeof(out); i++)
        out[i] = 0xFF;
    size = yasm_intnum_get_leb128(intn, out, test->sign);
    if (size != test->outsize) {
        yasm_intnum_destroy(intn);
        sprintf(failmsg, "%ssigned %s%s get() bad size: expected %lu, got %lu!",
                test->sign?"":"un", test->negate?"-":"", test->input,
                test->outsize, size);
        return 1;
    }

    bad = 0;
    for (i=0; i<test->outsize && !bad; i++) {
        if (out[i] != test->result[i])
            bad = 1;
    }
    if (bad) {
        yasm_intnum_destroy(intn);
        sprintf(failmsg, "%ssigned %s%s get() bad output!",
                test->sign?"":"un", test->negate?"-":"", test->input);
        return 1;
    }

    yasm_intnum_destroy(intn);
    return 0;
}
示例#4
0
static int
run_input_test(Test_Entry *test)
{
    char *valstr = yasm__xstrdup(test->input);
    yasm_intnum *intn = yasm_intnum_create_hex(valstr);
    yasm_intnum *testn;
    unsigned long size;

    yasm_xfree(valstr);

    if (test->negate)
        yasm_intnum_calc(intn, YASM_EXPR_NEG, NULL);

    testn = yasm_intnum_create_leb128(test->result, test->sign, &size);
    if (size != test->outsize) {
        yasm_intnum_destroy(testn);
        yasm_intnum_destroy(intn);
        sprintf(failmsg, "%ssigned %s%s create() bad size: expected %lu, got %lu!",
                test->sign?"":"un", test->negate?"-":"", test->input,
                test->outsize, size);
        return 1;
    }

    yasm_intnum_calc(intn, YASM_EXPR_EQ, testn);
    if (!yasm_intnum_is_pos1(intn)) {
        yasm_intnum_destroy(testn);
        yasm_intnum_destroy(intn);
        sprintf(failmsg, "%ssigned %s%s create() bad output!",
                test->sign?"":"un", test->negate?"-":"", test->input);
        return 1;
    }

    yasm_intnum_destroy(testn);
    yasm_intnum_destroy(intn);
    return 0;
}
/*@null@*/ yasm_intnum *
yasm_calc_bc_dist(yasm_bytecode *precbc1, yasm_bytecode *precbc2)
{
    unsigned long dist2, dist1;
    yasm_intnum *intn;

    if (precbc1->section != precbc2->section)
        return NULL;

    dist1 = yasm_bc_next_offset(precbc1);
    dist2 = yasm_bc_next_offset(precbc2);
    if (dist2 < dist1) {
        intn = yasm_intnum_create_uint(dist1 - dist2);
        yasm_intnum_calc(intn, YASM_EXPR_NEG, NULL);
        return intn;
    }
    dist2 -= dist1;
    return yasm_intnum_create_uint(dist2);
}
示例#6
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;
}
示例#7
0
yasm_intnum *
yasm_value_get_intnum(yasm_value *value, yasm_bytecode *bc, int calc_bc_dist)
{
    /*@dependent@*/ /*@null@*/ yasm_intnum *intn = NULL;
    /*@only@*/ yasm_intnum *outval;
    int sym_local;

    if (value->abs) {
        /* Handle integer expressions, if non-integer or too complex, return
         * NULL.
         */
        intn = yasm_expr_get_intnum(&value->abs, calc_bc_dist);
        if (!intn)
            return NULL;
    }

    if (value->rel) {
        /* If relative portion is not in bc section, return NULL.
         * Otherwise get the relative portion's offset.
         */
        /*@dependent@*/ yasm_bytecode *rel_prevbc;
        unsigned long dist;

        if (!bc)
            return NULL;    /* Can't calculate relative value */

        sym_local = yasm_symrec_get_label(value->rel, &rel_prevbc);
        if (value->wrt || value->seg_of || value->section_rel || !sym_local)
            return NULL;    /* we can't handle SEG, WRT, or external symbols */
        if (rel_prevbc->section != bc->section)
            return NULL;    /* not in this section */
        if (!value->curpos_rel)
            return NULL;    /* 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);
        return outval;
    }

    if (intn)
        return yasm_intnum_copy(intn);
    
    /* No absolute or relative portions: output 0 */
    return yasm_intnum_create_uint(0);
}
示例#8
0
int
yasm_value_finalize(yasm_value *value, yasm_bytecode *precbc)
{
    if (!value->abs)
        return 0;

    value->abs = yasm_expr__level_tree(value->abs, 1, 1, 0, 0, NULL, NULL);

    /* quit early if there was an issue in simplify() */
    if (yasm_error_occurred())
        return 1;

    /* Strip top-level AND masking to an all-1s mask the same size
     * of the value size.  This allows forced avoidance of overflow warnings.
     */
    if (value->abs->op == YASM_EXPR_AND) {
        int term;

        /* Calculate 1<<size - 1 value */
        yasm_intnum *mask = yasm_intnum_create_uint(1);
        yasm_intnum *mask_tmp = yasm_intnum_create_uint(value->size);
        yasm_intnum_calc(mask, YASM_EXPR_SHL, mask_tmp);
        yasm_intnum_set_uint(mask_tmp, 1);
        yasm_intnum_calc(mask, YASM_EXPR_SUB, mask_tmp);
        yasm_intnum_destroy(mask_tmp);

        /* Walk terms and delete matching masks */
        for (term=value->abs->numterms-1; term>=0; term--) {
            if (value->abs->terms[term].type == YASM_EXPR_INT &&
                yasm_intnum_compare(value->abs->terms[term].data.intn,
                                    mask) == 0) {
                /* Delete the intnum */
                yasm_intnum_destroy(value->abs->terms[term].data.intn);

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

                /* Update numterms */
                value->abs->numterms--;

                /* Indicate warnings have been disabled */
                value->no_warn = 1;
            }
        }
        if (value->abs->numterms == 1)
            value->abs->op = YASM_EXPR_IDENT;
        yasm_intnum_destroy(mask);
    }

    /* Handle trivial (IDENT) cases immediately */
    if (value->abs->op == YASM_EXPR_IDENT) {
        switch (value->abs->terms[0].type) {
            case YASM_EXPR_INT:
                if (yasm_intnum_is_zero(value->abs->terms[0].data.intn)) {
                    yasm_expr_destroy(value->abs);
                    value->abs = NULL;
                }
                return 0;
            case YASM_EXPR_REG:
            case YASM_EXPR_FLOAT:
                return 0;
            case YASM_EXPR_SYM:
                value->rel = value->abs->terms[0].data.sym;
                yasm_expr_destroy(value->abs);
                value->abs = NULL;
                return 0;
            case YASM_EXPR_EXPR:
                /* Bring up lower values. */
                while (value->abs->op == YASM_EXPR_IDENT
                       && value->abs->terms[0].type == YASM_EXPR_EXPR) {
                    yasm_expr *sube = value->abs->terms[0].data.expn;
                    yasm_xfree(value->abs);
                    value->abs = sube;
                }
                break;
            default:
                yasm_internal_error(N_("unexpected expr term type"));
        }
    }

    if (value_finalize_scan(value, value->abs, precbc, 0))
        return 1;

    value->abs = yasm_expr__level_tree(value->abs, 1, 1, 0, 0, NULL, NULL);

    /* Simplify 0 in abs to NULL */
    if (value->abs->op == YASM_EXPR_IDENT
        && value->abs->terms[0].type == YASM_EXPR_INT
        && yasm_intnum_is_zero(value->abs->terms[0].data.intn)) {
        yasm_expr_destroy(value->abs);
        value->abs = NULL;
    }
    return 0;
}
示例#9
0
static int
xdf_objfmt_output_value(yasm_value *value, unsigned char *buf,
                        unsigned int destsize, unsigned long offset,
                        yasm_bytecode *bc, int warn, /*@null@*/ void *d)
{
    /*@null@*/ xdf_objfmt_output_info *info = (xdf_objfmt_output_info *)d;
    yasm_objfmt_xdf *objfmt_xdf;
    /*@dependent@*/ /*@null@*/ yasm_intnum *intn;
    unsigned long intn_minus;
    int retval;
    unsigned int valsize = value->size;

    assert(info != NULL);
    objfmt_xdf = info->objfmt_xdf;

    if (value->abs)
        value->abs = yasm_expr_simplify(value->abs, 1);

    /* Try to output constant and PC-relative section-local first.
     * Note this does NOT output any value with a SEG, WRT, external,
     * cross-section, or non-PC-relative reference (those are handled below).
     */
    switch (yasm_value_output_basic(value, buf, destsize, bc, warn,
                                    info->object->arch)) {
        case -1:
            return 1;
        case 0:
            break;
        default:
            return 0;
    }

    if (value->section_rel) {
        yasm_error_set(YASM_ERROR_TOO_COMPLEX,
                       N_("xdf: relocation too complex"));
        return 1;
    }

    intn_minus = 0;
    if (value->rel) {
        xdf_reloc *reloc;

        reloc = yasm_xmalloc(sizeof(xdf_reloc));
        reloc->reloc.addr = yasm_intnum_create_uint(bc->offset + offset);
        reloc->reloc.sym = value->rel;
        reloc->base = NULL;
        reloc->size = valsize/8;
        reloc->shift = value->rshift;

        if (value->seg_of)
            reloc->type = XDF_RELOC_SEG;
        else if (value->wrt) {
            reloc->base = value->wrt;
            reloc->type = XDF_RELOC_WRT;
        } else if (value->curpos_rel) {
            reloc->type = XDF_RELOC_RIP;
            /* Adjust to start of section, so subtract out the bytecode
             * offset.
             */
            intn_minus = bc->offset;
        } else
            reloc->type = XDF_RELOC_REL;
        info->xsd->nreloc++;
        yasm_section_add_reloc(info->sect, (yasm_reloc *)reloc, yasm_xfree);
    }

    if (intn_minus > 0) {
        intn = yasm_intnum_create_uint(intn_minus);
        yasm_intnum_calc(intn, YASM_EXPR_NEG, NULL);
    } else
        intn = yasm_intnum_create_uint(0);

    if (value->abs) {
        yasm_intnum *intn2 = yasm_expr_get_intnum(&value->abs, 0);
        if (!intn2) {
            yasm_error_set(YASM_ERROR_TOO_COMPLEX,
                           N_("xdf: relocation too complex"));
            yasm_intnum_destroy(intn);
            return 1;
        }
        yasm_intnum_calc(intn, YASM_EXPR_ADD, intn2);
    }

    retval = yasm_arch_intnum_tobytes(info->object->arch, intn, buf, destsize,
                                      valsize, 0, bc, warn);
    yasm_intnum_destroy(intn);
    return retval;
}
示例#10
0
文件: expr.c 项目: Acidburn0zzz/yasm
/*@-mustfree@*/
static /*@only@*/ yasm_expr *
expr_level_op(/*@returned@*/ /*@only@*/ yasm_expr *e, int fold_const,
              int simplify_ident, int simplify_reg_mul)
{
    int i, j, o, fold_numterms, level_numterms, level_fold_numterms;
    int first_int_term = -1;

    /* Determine how many operands will need to be brought up (for leveling).
     * Go ahead and bring up any IDENT'ed values.
     */
    while (e->op == YASM_EXPR_IDENT && e->terms[0].type == YASM_EXPR_EXPR) {
        yasm_expr *sube = e->terms[0].data.expn;
        yasm_xfree(e);
        e = sube;
    }

    /* If non-numeric expression, don't fold constants. */
    if (e->op > YASM_EXPR_NONNUM)
        fold_const = 0;

    level_numterms = e->numterms;
    level_fold_numterms = 0;
    for (i=0; i<e->numterms; i++) {
        /* Search downward until we find something *other* than an
         * IDENT, then bring it up to the current level.
         */
        while (e->terms[i].type == YASM_EXPR_EXPR &&
               e->terms[i].data.expn->op == YASM_EXPR_IDENT) {
            yasm_expr *sube = e->terms[i].data.expn;
            e->terms[i] = sube->terms[0];
            yasm_xfree(sube);
        }

        if (e->terms[i].type == YASM_EXPR_EXPR &&
            e->terms[i].data.expn->op == e->op) {
                /* It's an expression w/the same operator, add in its numterms.
                 * But don't forget to subtract one for the expr itself!
                 */
                level_numterms += e->terms[i].data.expn->numterms - 1;

                /* If we're folding constants, count up the number of constants
                 * that will be merged in.
                 */
                if (fold_const)
                    for (j=0; j<e->terms[i].data.expn->numterms; j++)
                        if (e->terms[i].data.expn->terms[j].type ==
                            YASM_EXPR_INT)
                            level_fold_numterms++;
        }

        /* Find the first integer term (if one is present) if we're folding
         * constants.
         */
        if (fold_const && first_int_term == -1 &&
            e->terms[i].type == YASM_EXPR_INT)
            first_int_term = i;
    }

    /* Look for other integer terms if there's one and combine.
     * Also eliminate empty spaces when combining and adjust numterms
     * variables.
     */
    fold_numterms = e->numterms;
    if (first_int_term != -1) {
        for (i=first_int_term+1, o=first_int_term+1; i<e->numterms; i++) {
            if (e->terms[i].type == YASM_EXPR_INT) {
                yasm_intnum_calc(e->terms[first_int_term].data.intn, e->op,
                                 e->terms[i].data.intn);
                fold_numterms--;
                level_numterms--;
                /* make sure to delete folded intnum */
                yasm_intnum_destroy(e->terms[i].data.intn);
            } else if (o != i) {
                /* copy term if it changed places */
                e->terms[o++] = e->terms[i];
            } else
                o++;
        }

        if (simplify_ident) {
            int new_fold_numterms;
            /* Simplify identities and make IDENT if possible. */
            new_fold_numterms =
                expr_simplify_identity(e, fold_numterms, &first_int_term,
                                       simplify_reg_mul);
            level_numterms -= fold_numterms-new_fold_numterms;
            fold_numterms = new_fold_numterms;
        }
        if (fold_numterms == 1)
            e->op = YASM_EXPR_IDENT;
    }

    /* Only level operators that allow more than two operand terms.
     * Also don't bother leveling if it's not necessary to bring up any terms.
     */
    if ((e->op != YASM_EXPR_ADD && e->op != YASM_EXPR_MUL &&
         e->op != YASM_EXPR_OR && e->op != YASM_EXPR_AND &&
         e->op != YASM_EXPR_LOR && e->op != YASM_EXPR_LAND &&
         e->op != YASM_EXPR_LXOR && e->op != YASM_EXPR_XOR) ||
        level_numterms <= fold_numterms) {
        /* Downsize e if necessary */
        if (fold_numterms < e->numterms && e->numterms > 2)
            e = yasm_xrealloc(e, sizeof(yasm_expr)+((fold_numterms<2) ? 0 :
                              sizeof(yasm_expr__item)*(fold_numterms-2)));
        /* Update numterms */
        e->numterms = fold_numterms;
        return e;
    }

    /* Adjust numterms for constant folding from terms being "pulled up".
     * Careful: if there's no integer term in e, then save space for it.
     */
    if (fold_const) {
        level_numterms -= level_fold_numterms;
        if (first_int_term == -1 && level_fold_numterms != 0)
            level_numterms++;
    }

    /* Alloc more (or conceivably less, but not usually) space for e */
    e = yasm_xrealloc(e, sizeof(yasm_expr)+((level_numterms<2) ? 0 :
                      sizeof(yasm_expr__item)*(level_numterms-2)));

    /* Copy up ExprItem's.  Iterate from right to left to keep the same
     * ordering as was present originally.
     * Combine integer terms as necessary.
     */
    for (i=fold_numterms-1, o=level_numterms-1; i>=0; i--) {
        if (e->terms[i].type == YASM_EXPR_EXPR &&
            e->terms[i].data.expn->op == e->op) {
            /* bring up subexpression */
            yasm_expr *sube = e->terms[i].data.expn;

            /* copy terms right to left */
            for (j=sube->numterms-1; j>=0; j--) {
                if (fold_const && sube->terms[j].type == YASM_EXPR_INT) {
                    /* Need to fold it in.. but if there's no int term already,
                     * just copy into a new one.
                     */
                    if (first_int_term == -1) {
                        first_int_term = o--;
                        e->terms[first_int_term] = sube->terms[j];  /* struc */
                    } else {
                        yasm_intnum_calc(e->terms[first_int_term].data.intn,
                                         e->op, sube->terms[j].data.intn);
                        /* make sure to delete folded intnum */
                        yasm_intnum_destroy(sube->terms[j].data.intn);
                    }
                } else {
                    if (o == first_int_term)
                        o--;
                    e->terms[o--] = sube->terms[j];     /* structure copy */
                }
            }

            /* delete subexpression, but *don't delete nodes* (as we've just
             * copied them!)
             */
            yasm_xfree(sube);
        } else if (o != i) {
            /* copy operand if it changed places */
            if (o == first_int_term)
                o--;
            e->terms[o] = e->terms[i];
            /* If we moved the first_int_term, change first_int_num too */
            if (i == first_int_term)
                first_int_term = o;
            o--;
        } else
            o--;
    }

    /* Simplify identities, make IDENT if possible, and save to e->numterms. */
    if (simplify_ident && first_int_term != -1) {
        e->numterms = expr_simplify_identity(e, level_numterms,
                                             &first_int_term, simplify_reg_mul);
    } else {
        e->numterms = level_numterms;
        if (level_numterms == 1)
            e->op = YASM_EXPR_IDENT;
    }

    return e;
}
示例#11
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;
}
示例#12
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;
}