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; }
/* 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; }
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; }
/* 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; }