/*@null@*/ void *d,
int (*func) (/*@null@*/ yasm_expr *e,
/*@null@*/ void *d));
+static void expr_delete_term(yasm_expr__item *term, int recurse);
/* Bitmap of used items. We should really never need more than 2 at a time,
* so 31 is pretty much overkill.
return &itempool[z];
}
+yasm_expr__item *
+yasm_expr_precbc(yasm_bytecode *precbc)
+{
+ yasm_expr__item *e = expr_get_item();
+ e->type = YASM_EXPR_PRECBC;
+ e->data.precbc = precbc;
+ return e;
+}
+
yasm_expr__item *
yasm_expr_sym(yasm_symrec *s)
{
/* Transforms instances of symrec-symrec [symrec+(-1*symrec)] into single
* expritems if possible. Uses a simple n^2 algorithm because n is usually
- * quite small.
+ * quite small. Also works for precbc-precbc (or symrec-precbc,
+ * precbc-symrec).
*/
static /*@only@*/ yasm_expr *
expr_xform_bc_dist_base(/*@returned@*/ /*@only@*/ yasm_expr *e,
int j;
yasm_expr *sube;
yasm_intnum *intn;
- yasm_symrec *sym;
+ yasm_symrec *sym = NULL;
/*@dependent@*/ yasm_section *sect2;
/*@dependent@*/ /*@null@*/ yasm_bytecode *precbc2;
if (sube->terms[0].type == YASM_EXPR_INT &&
(sube->terms[1].type == YASM_EXPR_SYM ||
- sube->terms[1].type == YASM_EXPR_SYMEXP)) {
+ sube->terms[1].type == YASM_EXPR_SYMEXP ||
+ sube->terms[1].type == YASM_EXPR_PRECBC)) {
intn = sube->terms[0].data.intn;
- sym = sube->terms[1].data.sym;
+ if (sube->terms[1].type == YASM_EXPR_PRECBC)
+ precbc = sube->terms[1].data.precbc;
+ else
+ sym = sube->terms[1].data.sym;
} else if ((sube->terms[0].type == YASM_EXPR_SYM ||
- sube->terms[0].type == YASM_EXPR_SYMEXP) &&
+ sube->terms[0].type == YASM_EXPR_SYMEXP ||
+ sube->terms[0].type == YASM_EXPR_PRECBC) &&
sube->terms[1].type == YASM_EXPR_INT) {
- sym = sube->terms[0].data.sym;
+ if (sube->terms[0].type == YASM_EXPR_PRECBC)
+ precbc = sube->terms[0].data.precbc;
+ else
+ sym = sube->terms[0].data.sym;
intn = sube->terms[1].data.intn;
} else
continue;
if (!yasm_intnum_is_neg1(intn))
continue;
- if (!yasm_symrec_get_label(sym, &precbc))
+ if (sym && !yasm_symrec_get_label(sym, &precbc))
continue;
sect2 = yasm_bc_get_section(precbc);
/* Now look for a symrec term in the same segment */
for (j=0; j<e->numterms; j++) {
- if ((e->terms[j].type == YASM_EXPR_SYM ||
- e->terms[j].type == YASM_EXPR_SYMEXP) &&
- yasm_symrec_get_label(e->terms[j].data.sym, &precbc2) &&
+ if ((((e->terms[j].type == YASM_EXPR_SYM ||
+ e->terms[j].type == YASM_EXPR_SYMEXP) &&
+ yasm_symrec_get_label(e->terms[j].data.sym, &precbc2)) ||
+ (e->terms[j].type == YASM_EXPR_PRECBC &&
+ (precbc2 = e->terms[j].data.precbc))) &&
(sect = yasm_bc_get_section(precbc2)) &&
sect == sect2 &&
callback(&e->terms[j], precbc, precbc2, cbd)) {
/* Loop through, deleting everything but the integer term */
for (i=0; i<e->numterms; i++)
if (i != int_term)
- switch (e->terms[i].type) {
- case YASM_EXPR_INT:
- yasm_intnum_destroy(e->terms[i].data.intn);
- break;
- case YASM_EXPR_FLOAT:
- yasm_floatnum_destroy(e->terms[i].data.flt);
- break;
- case YASM_EXPR_EXPR:
- yasm_expr_destroy(e->terms[i].data.expn);
- break;
- default:
- break;
- }
+ expr_delete_term(&e->terms[i], 1);
/* Move integer term to the first term (if not already there) */
if (int_term != 0)
/* traverse terms */
for (i=0; i<e->numterms; i++) {
- /* Expansion stage first: expand equ's, and expand symrecs that
- * reference absolute sections into
- * absolute start expr + (symrec - first bc in abs section).
- */
+ /* Expansion stage first: expand equ's. */
if (e->terms[i].type == YASM_EXPR_SYM) {
yasm__exprentry *np;
const yasm_expr *equ_expr =
ee.e = equ_expr;
SLIST_INSERT_HEAD(eh, &ee, next);
- } else if (yasm_symrec_get_label(e->terms[i].data.sym, &precbc) &&
- (sect = yasm_bc_get_section(precbc)) &&
- yasm_section_is_absolute(sect)) {
- const yasm_expr *start = yasm_section_get_start(sect);
- yasm_expr *sube, *sube2;
-
- /* Check for circular reference */
- SLIST_FOREACH(np, eh, next) {
- if (np->e == start) {
- yasm_error_set(YASM_ERROR_TOO_COMPLEX,
- N_("circular reference detected"));
- return e;
- }
- }
-
- sube = yasm_xmalloc(sizeof(yasm_expr));
- sube->op = YASM_EXPR_SUB;
- sube->line = e->line;
- sube->numterms = 2;
- sube->terms[0].type = YASM_EXPR_SYMEXP;
- sube->terms[0].data.sym = e->terms[i].data.sym;
- sube->terms[1].type = YASM_EXPR_SYMEXP;
- sube->terms[1].data.sym = yasm_section_abs_get_sym(sect);
- assert(sube->terms[1].data.sym != NULL);
-
- sube2 = yasm_xmalloc(sizeof(yasm_expr));
- sube2->op = YASM_EXPR_ADD;
- sube2->line = e->line;
- sube2->numterms = 2;
- sube2->terms[0].type = YASM_EXPR_EXPR;
- sube2->terms[0].data.expn = yasm_expr_copy(start);
- sube2->terms[1].type = YASM_EXPR_EXPR;
- sube2->terms[1].data.expn = sube;
-
- e->terms[i].type = YASM_EXPR_EXPR;
- e->terms[i].data.expn = sube2;
-
- ee.e = start;
- SLIST_INSERT_HEAD(eh, &ee, next);
}
}
}
}
+ /* Check for SEG of SEG:OFF, if we match, simplify to just the segment */
+ if (e->op == YASM_EXPR_SEG && e->terms[0].type == YASM_EXPR_EXPR &&
+ e->terms[0].data.expn->op == YASM_EXPR_SEGOFF) {
+ e->op = YASM_EXPR_IDENT;
+ e->terms[0].data.expn->op = YASM_EXPR_IDENT;
+ /* Destroy the second (offset) term */
+ expr_delete_term(&e->terms[1], 1);
+ }
+
/* do callback */
e = expr_level_op(e, fold_const, simplify_ident, simplify_reg_mul);
if (calc_bc_dist || expr_xform_extra) {
/* Symbols don't need to be copied */
dest->data.sym = src->data.sym;
break;
+ case YASM_EXPR_PRECBC:
+ /* Nor do direct bytecode references */
+ dest->data.precbc = src->data.precbc;
+ break;
case YASM_EXPR_EXPR:
dest->data.expn = yasm_expr__copy_except(src->data.expn, -1);
break;
return yasm_expr__copy_except(e, -1);
}
+static void
+expr_delete_term(yasm_expr__item *term, int recurse)
+{
+ switch (term->type) {
+ case YASM_EXPR_INT:
+ yasm_intnum_destroy(term->data.intn);
+ break;
+ case YASM_EXPR_FLOAT:
+ yasm_floatnum_destroy(term->data.flt);
+ break;
+ case YASM_EXPR_EXPR:
+ if (recurse)
+ yasm_expr_destroy(term->data.expn);
+ break;
+ default:
+ break;
+ }
+}
+
static int
expr_destroy_each(/*@only@*/ yasm_expr *e, /*@unused@*/ void *d)
{
int i;
- for (i=0; i<e->numterms; i++) {
- switch (e->terms[i].type) {
- case YASM_EXPR_INT:
- yasm_intnum_destroy(e->terms[i].data.intn);
- break;
- case YASM_EXPR_FLOAT:
- yasm_floatnum_destroy(e->terms[i].data.flt);
- break;
- default:
- break; /* none of the other types needs to be deleted */
- }
- }
+ for (i=0; i<e->numterms; i++)
+ expr_delete_term(&e->terms[i], 0);
yasm_xfree(e); /* free ourselves */
return 0; /* don't stop recursion */
}
return 0;
}
+yasm_expr *
+yasm_expr_extract_deep_segoff(yasm_expr **ep)
+{
+ yasm_expr *retval;
+ yasm_expr *e = *ep;
+ int i;
+
+ /* Try to extract at this level */
+ retval = yasm_expr_extract_segoff(ep);
+ if (retval)
+ return retval;
+
+ /* Not at this level? Search any expr children. */
+ for (i=0; i<e->numterms; i++) {
+ if (e->terms[i].type == YASM_EXPR_EXPR) {
+ retval = yasm_expr_extract_deep_segoff(&e->terms[i].data.expn);
+ if (retval)
+ return retval;
+ }
+ }
+
+ /* Didn't find one */
+ return NULL;
+}
+
yasm_expr *
yasm_expr_extract_segoff(yasm_expr **ep)
{
}
for (i=0; i<e->numterms; i++) {
switch (e->terms[i].type) {
+ case YASM_EXPR_PRECBC:
+ fprintf(f, "{%lx}",
+ yasm_bc_next_offset(e->terms[i].data.precbc));
+ break;
case YASM_EXPR_SYM:
case YASM_EXPR_SYMEXP:
fprintf(f, "%s", yasm_symrec_get_name(e->terms[i].data.sym));
* 15 = memory offset (an EA, but with no registers allowed)
* [special case for MOV opcode]
* 16 = immediate, value=1 (for special-case shift)
+ * 17 = immediate, does not contain SEG:OFF (for jmp/call)
* - 3 bits = size (user-specified, or from register size):
* 0 = any size acceptable/no size spec acceptable (dep. on strict)
* 1/2/3/4 = 8/16/32/64 bits (from user or reg size)
#define OPT_CR4 0x14
#define OPT_MemOffs 0x15
#define OPT_Imm1 0x16
+#define OPT_ImmNotSegOff 0x17
#define OPT_MASK 0x1F
#define OPS_Any (0UL<<5)
/* Control transfer instructions (unconditional) */
static const x86_insn_info call_insn[] = {
{ CPU_Any, 0, 0, 0, 0, 0, {0, 0, 0}, 0, 1,
- {OPT_Imm|OPS_Any|OPA_JmpRel, 0, 0} },
+ {OPT_ImmNotSegOff|OPS_Any|OPA_JmpRel, 0, 0} },
{ CPU_Any, 0, 16, 0, 0, 0, {0, 0, 0}, 0, 1,
- {OPT_Imm|OPS_16|OPA_JmpRel, 0, 0} },
+ {OPT_ImmNotSegOff|OPS_16|OPA_JmpRel, 0, 0} },
{ CPU_386|CPU_Not64, 0, 32, 0, 0, 0, {0, 0, 0}, 0, 1,
- {OPT_Imm|OPS_32|OPA_JmpRel, 0, 0} },
+ {OPT_ImmNotSegOff|OPS_32|OPA_JmpRel, 0, 0} },
{ CPU_Hammer|CPU_64, 0, 64, 0, 0, 0, {0, 0, 0}, 0, 1,
- {OPT_Imm|OPS_32|OPA_JmpRel, 0, 0} },
+ {OPT_ImmNotSegOff|OPS_32|OPA_JmpRel, 0, 0} },
{ CPU_Any, 0, 16, 64, 0, 1, {0xE8, 0, 0}, 0, 1,
{OPT_Imm|OPS_16|OPTM_Near|OPA_JmpRel, 0, 0} },
{ CPU_Any, 0, 0, 64, 0, 1, {0xFF, 0, 0}, 2, 1,
{OPT_Mem|OPS_Any|OPTM_Near|OPA_EA, 0, 0} },
- { CPU_Not64, 0, 16, 0, 0, 1, {0x9A, 0, 0}, 3, 1,
- {OPT_Imm|OPS_16|OPTM_Far|OPA_JmpFar, 0, 0} },
- { CPU_386|CPU_Not64, 0, 32, 0, 0, 1, {0x9A, 0, 0}, 3, 1,
- {OPT_Imm|OPS_32|OPTM_Far|OPA_JmpFar, 0, 0} },
- { CPU_Not64, 0, 0, 0, 0, 1, {0x9A, 0, 0}, 3, 1,
- {OPT_Imm|OPS_Any|OPTM_Far|OPA_JmpFar, 0, 0} },
-
+ /* Far indirect (through memory). Needs explicit FAR override. */
{ CPU_Any, 0, 16, 0, 0, 1, {0xFF, 0, 0}, 3, 1,
{OPT_Mem|OPS_16|OPTM_Far|OPA_EA, 0, 0} },
{ CPU_386, 0, 32, 0, 0, 1, {0xFF, 0, 0}, 3, 1,
{ CPU_EM64T|CPU_64, 0, 64, 0, 0, 1, {0xFF, 0, 0}, 3, 1,
{OPT_Mem|OPS_64|OPTM_Far|OPA_EA, 0, 0} },
{ CPU_Any, 0, 0, 0, 0, 1, {0xFF, 0, 0}, 3, 1,
- {OPT_Mem|OPS_Any|OPTM_Far|OPA_EA, 0, 0} }
+ {OPT_Mem|OPS_Any|OPTM_Far|OPA_EA, 0, 0} },
+
+ /* With explicit FAR override */
+ { CPU_Not64, 0, 16, 0, 0, 1, {0x9A, 0, 0}, 3, 1,
+ {OPT_Imm|OPS_16|OPTM_Far|OPA_JmpFar, 0, 0} },
+ { CPU_386|CPU_Not64, 0, 32, 0, 0, 1, {0x9A, 0, 0}, 3, 1,
+ {OPT_Imm|OPS_32|OPTM_Far|OPA_JmpFar, 0, 0} },
+ { CPU_Not64, 0, 0, 0, 0, 1, {0x9A, 0, 0}, 3, 1,
+ {OPT_Imm|OPS_Any|OPTM_Far|OPA_JmpFar, 0, 0} },
+
+ /* Since not caught by first ImmNotSegOff group, implicitly FAR. */
+ { CPU_Not64, 0, 16, 0, 0, 1, {0x9A, 0, 0}, 3, 1,
+ {OPT_Imm|OPS_16|OPA_JmpFar, 0, 0} },
+ { CPU_386|CPU_Not64, 0, 32, 0, 0, 1, {0x9A, 0, 0}, 3, 1,
+ {OPT_Imm|OPS_32|OPA_JmpFar, 0, 0} },
+ { CPU_Not64, 0, 0, 0, 0, 1, {0x9A, 0, 0}, 3, 1,
+ {OPT_Imm|OPS_Any|OPA_JmpFar, 0, 0} }
};
static const x86_insn_info jmp_insn[] = {
{ CPU_Any, 0, 0, 0, 0, 0, {0, 0, 0}, 0, 1,
- {OPT_Imm|OPS_Any|OPA_JmpRel, 0, 0} },
+ {OPT_ImmNotSegOff|OPS_Any|OPA_JmpRel, 0, 0} },
{ CPU_Any, 0, 16, 0, 0, 0, {0, 0, 0}, 0, 1,
- {OPT_Imm|OPS_16|OPA_JmpRel, 0, 0} },
+ {OPT_ImmNotSegOff|OPS_16|OPA_JmpRel, 0, 0} },
{ CPU_386|CPU_Not64, 0, 32, 0, 0, 1, {0, 0, 0}, 0, 1,
- {OPT_Imm|OPS_32|OPA_JmpRel, 0, 0} },
+ {OPT_ImmNotSegOff|OPS_32|OPA_JmpRel, 0, 0} },
{ CPU_Hammer|CPU_64, 0, 64, 0, 0, 1, {0, 0, 0}, 0, 1,
- {OPT_Imm|OPS_32|OPA_JmpRel, 0, 0} },
+ {OPT_ImmNotSegOff|OPS_32|OPA_JmpRel, 0, 0} },
{ CPU_Any, 0, 0, 64, 0, 1, {0xEB, 0, 0}, 0, 1,
{OPT_Imm|OPS_Any|OPTM_Short|OPA_JmpRel, 0, 0} },
{ CPU_Any, 0, 0, 64, 0, 1, {0xFF, 0, 0}, 4, 1,
{OPT_Mem|OPS_Any|OPTM_Near|OPA_EA, 0, 0} },
- { CPU_Not64, 0, 16, 0, 0, 1, {0xEA, 0, 0}, 3, 1,
- {OPT_Imm|OPS_16|OPTM_Far|OPA_JmpFar, 0, 0} },
- { CPU_386|CPU_Not64, 0, 32, 0, 0, 1, {0xEA, 0, 0}, 3, 1,
- {OPT_Imm|OPS_32|OPTM_Far|OPA_JmpFar, 0, 0} },
- { CPU_Not64, 0, 0, 0, 0, 1, {0xEA, 0, 0}, 3, 1,
- {OPT_Imm|OPS_Any|OPTM_Far|OPA_JmpFar, 0, 0} },
-
+ /* Far indirect (through memory). Needs explicit FAR override. */
{ CPU_Any, 0, 16, 0, 0, 1, {0xFF, 0, 0}, 5, 1,
{OPT_Mem|OPS_16|OPTM_Far|OPA_EA, 0, 0} },
{ CPU_386, 0, 32, 0, 0, 1, {0xFF, 0, 0}, 5, 1,
{ CPU_EM64T|CPU_64, 0, 64, 0, 0, 1, {0xFF, 0, 0}, 5, 1,
{OPT_Mem|OPS_64|OPTM_Far|OPA_EA, 0, 0} },
{ CPU_Any, 0, 0, 0, 0, 1, {0xFF, 0, 0}, 5, 1,
- {OPT_Mem|OPS_Any|OPTM_Far|OPA_EA, 0, 0} }
+ {OPT_Mem|OPS_Any|OPTM_Far|OPA_EA, 0, 0} },
+
+ /* With explicit FAR override */
+ { CPU_Not64, 0, 16, 0, 0, 1, {0xEA, 0, 0}, 3, 1,
+ {OPT_Imm|OPS_16|OPTM_Far|OPA_JmpFar, 0, 0} },
+ { CPU_386|CPU_Not64, 0, 32, 0, 0, 1, {0xEA, 0, 0}, 3, 1,
+ {OPT_Imm|OPS_32|OPTM_Far|OPA_JmpFar, 0, 0} },
+ { CPU_Not64, 0, 0, 0, 0, 1, {0xEA, 0, 0}, 3, 1,
+ {OPT_Imm|OPS_Any|OPTM_Far|OPA_JmpFar, 0, 0} },
+
+ /* Since not caught by first ImmNotSegOff group, implicitly FAR. */
+ { CPU_Not64, 0, 16, 0, 0, 1, {0xEA, 0, 0}, 3, 1,
+ {OPT_Imm|OPS_16|OPA_JmpFar, 0, 0} },
+ { CPU_386|CPU_Not64, 0, 32, 0, 0, 1, {0xEA, 0, 0}, 3, 1,
+ {OPT_Imm|OPS_32|OPA_JmpFar, 0, 0} },
+ { CPU_Not64, 0, 0, 0, 0, 1, {0xEA, 0, 0}, 3, 1,
+ {OPT_Imm|OPS_Any|OPA_JmpFar, 0, 0} }
};
static const x86_insn_info retnf_insn[] = {
{ CPU_Not64, MOD_Op0Add, 0, 0, 0, 1,
op = yasm_ops_first(operands);
- switch (op->targetmod) {
- case X86_FAR:
- /* "FAR imm" target needs to become "seg imm:imm". */
- if (yasm_value_finalize_expr(&jmpfar->offset,
- yasm_expr_copy(op->data.val), 0)
- || yasm_value_finalize_expr(&jmpfar->segment, op->data.val, 16))
- yasm_error_set(YASM_ERROR_TOO_COMPLEX,
- N_("jump target expression too complex"));
- jmpfar->segment.seg_of = 1;
- break;
- case X86_FAR_SEGOFF:
- /* SEG:OFF expression; split it. */
- segment = yasm_expr_extract_segoff(&op->data.val);
- if (!segment)
- yasm_internal_error(N_("didn't get SEG:OFF expression in jmpfar"));
- if (yasm_value_finalize_expr(&jmpfar->segment, segment, 16))
- yasm_error_set(YASM_ERROR_TOO_COMPLEX,
- N_("jump target segment too complex"));
- if (yasm_value_finalize_expr(&jmpfar->offset, op->data.val, 0))
- yasm_error_set(YASM_ERROR_TOO_COMPLEX,
- N_("jump target offset too complex"));
- break;
- default:
- yasm_internal_error(N_("didn't get FAR expression in jmpfar"));
- }
+ if (op->type == YASM_INSN__OPERAND_IMM &&
+ yasm_expr_is_op(op->data.val, YASM_EXPR_SEGOFF)) {
+ /* SEG:OFF expression; split it. */
+ segment = yasm_expr_extract_segoff(&op->data.val);
+ if (!segment)
+ yasm_internal_error(N_("didn't get SEG:OFF expression in jmpfar"));
+ if (yasm_value_finalize_expr(&jmpfar->segment, segment, 16))
+ yasm_error_set(YASM_ERROR_TOO_COMPLEX,
+ N_("jump target segment too complex"));
+ if (yasm_value_finalize_expr(&jmpfar->offset, op->data.val, 0))
+ yasm_error_set(YASM_ERROR_TOO_COMPLEX,
+ N_("jump target offset too complex"));
+ } else if (op->targetmod == X86_FAR) {
+ /* "FAR imm" target needs to become "seg imm:imm". */
+ if (yasm_value_finalize_expr(&jmpfar->offset,
+ yasm_expr_copy(op->data.val), 0)
+ || yasm_value_finalize_expr(&jmpfar->segment, op->data.val, 16))
+ yasm_error_set(YASM_ERROR_TOO_COMPLEX,
+ N_("jump target expression too complex"));
+ jmpfar->segment.seg_of = 1;
+ } else
+ yasm_internal_error(N_("didn't get FAR expression in jmpfar"));
yasm_x86__bc_apply_prefixes((x86_common *)jmpfar, NULL, num_prefixes,
prefixes);
N_("jump target expression too complex"));
if (jmp->target.seg_of || jmp->target.rshift || jmp->target.curpos_rel)
yasm_error_set(YASM_ERROR_VALUE, N_("invalid jump target"));
- jmp->target.curpos_rel = 1;
+ yasm_value_set_curpos_rel(&jmp->target, bc, 0);
/* See if the user explicitly specified short/near/far. */
switch ((int)(jinfo->operands[0] & OPTM_MASK)) {
}
}
- /* Look for SEG:OFF operands and apply X86_FAR_SEGOFF targetmod. */
- for (i = 0, op = ops[0]; op; op = ops[++i]) {
- if (op->type == YASM_INSN__OPERAND_IMM && op->targetmod == 0 &&
- yasm_expr_is_op(op->data.val, YASM_EXPR_SEGOFF))
- op->targetmod = X86_FAR_SEGOFF;
- }
-
/* Just do a simple linear search through the info array for a match.
* First match wins.
*/
} else
mismatch = 1;
break;
+ case OPT_ImmNotSegOff:
+ if (op->type != YASM_INSN__OPERAND_IMM ||
+ op->targetmod != 0 ||
+ yasm_expr_is_op(op->data.val, YASM_EXPR_SEGOFF))
+ mismatch = 1;
+ break;
default:
yasm_internal_error(N_("invalid operand type"));
}
/* Register size must exactly match */
if (yasm_x86__get_reg_size(arch, op->data.reg) != size)
mismatch = 1;
- } else if ((info->operands[i] & OPT_MASK) == OPT_Imm
+ } else if (((info->operands[i] & OPT_MASK) == OPT_Imm
+ || (info->operands[i] & OPT_MASK) == OPT_ImmNotSegOff
+ || (info->operands[i] & OPT_MASK) == OPT_Imm1)
&& (info->operands[i] & OPS_RMASK) != OPS_Relaxed
&& (info->operands[i] & OPA_MASK) != OPA_JmpRel)
mismatch = 1;
mismatch = 1;
break;
case OPTM_Far:
- if (op->targetmod != X86_FAR &&
- op->targetmod != X86_FAR_SEGOFF)
+ if (op->targetmod != X86_FAR)
mismatch = 1;
break;
case OPTM_To: