retval->type = YASM_INSN__OPERAND_REG;
retval->data.reg = reg;
+ retval->seg = 0;
retval->targetmod = 0;
retval->size = 0;
retval->deref = 0;
retval->type = YASM_INSN__OPERAND_SEGREG;
retval->data.reg = segreg;
+ retval->seg = 0;
retval->targetmod = 0;
retval->size = 0;
retval->deref = 0;
retval->type = YASM_INSN__OPERAND_MEMORY;
retval->data.ea = ea;
+ retval->seg = 0;
retval->targetmod = 0;
retval->size = 0;
retval->deref = 0;
retval = yasm_xmalloc(sizeof(yasm_insn_operand));
retval->type = YASM_INSN__OPERAND_IMM;
retval->data.val = val;
+ retval->seg = 0;
retval->targetmod = 0;
retval->size = 0;
retval->deref = 0;
/** An instruction operand (opaque type). */
typedef struct yasm_insn_operand yasm_insn_operand;
+/** The type of an instruction operand. */
+typedef enum yasm_insn_operand_type {
+ YASM_INSN__OPERAND_REG = 1, /**< A register. */
+ YASM_INSN__OPERAND_SEGREG, /**< A segment register. */
+ YASM_INSN__OPERAND_MEMORY, /**< An effective address
+ * (memory reference). */
+ YASM_INSN__OPERAND_IMM /**< An immediate or jump target. */
+} yasm_insn_operand_type;
+
/** An instruction operand. */
struct yasm_insn_operand {
/** Link for building linked list of operands. \internal */
/*@reldef@*/ STAILQ_ENTRY(yasm_insn_operand) link;
- /** Operand type. */
- enum yasm_insn_operand_type {
- YASM_INSN__OPERAND_REG = 1, /**< A register. */
- YASM_INSN__OPERAND_SEGREG, /**< A segment register. */
- YASM_INSN__OPERAND_MEMORY, /**< An effective address
- * (memory reference). */
- YASM_INSN__OPERAND_IMM /**< An immediate or jump target. */
- } type;
-
/** Operand data. */
union {
uintptr_t reg; /**< Arch data for reg/segreg. */
yasm_expr *val; /**< Value of immediate or jump target. */
} data;
+ yasm_expr *seg; /**< Segment expression */
+
uintptr_t targetmod; /**< Arch target modifier, 0 if none. */
/** Specified size of the operand, in bits. 0 if not user-specified. */
* "push strict dword 4", which sets this flag.
*/
unsigned int strict:1;
+
+ /** Operand type. */
+ unsigned int type:4;
};
/** Base structure for "instruction" bytecodes. These are the mnenomic
EXTRA_DIST += modules/arch/x86/tests/jmp64-5.hex
EXTRA_DIST += modules/arch/x86/tests/jmp64-6.asm
EXTRA_DIST += modules/arch/x86/tests/jmp64-6.hex
+EXTRA_DIST += modules/arch/x86/tests/jmpfar.asm
+EXTRA_DIST += modules/arch/x86/tests/jmpfar.hex
EXTRA_DIST += modules/arch/x86/tests/lds-err.asm
EXTRA_DIST += modules/arch/x86/tests/lds-err.errwarn
EXTRA_DIST += modules/arch/x86/tests/loopadsz.asm
EXTRA_DIST += modules/arch/x86/tests/segmov.hex
EXTRA_DIST += modules/arch/x86/tests/segoff.asm
EXTRA_DIST += modules/arch/x86/tests/segoff.hex
+EXTRA_DIST += modules/arch/x86/tests/segoff-err.asm
+EXTRA_DIST += modules/arch/x86/tests/segoff-err.errwarn
EXTRA_DIST += modules/arch/x86/tests/shift.asm
EXTRA_DIST += modules/arch/x86/tests/shift.hex
EXTRA_DIST += modules/arch/x86/tests/simd-1.asm
jmp 5:4
-jmp equval
+jmp far equval
equval equ 6:7
--- /dev/null
+jmp 1234:5678 ; YASM: far jump
+jmp near 1234:5678 ; YASM: near jump; NASM: mismatch in operand sizes
+jmp far 1234:5678 ; YASM: far jump; NASM: mismatch in operand sizes
+;dw seg (1234:5678)
+far1 equ 1234:5678
+jmp far1 ; both: near jump
+jmp near far1 ; both: near jump
+jmp far far1 ; YASM: far jump; NASM: value referenced by FAR is not relocatable
+dw seg far1
+jmp far2 ; both: near jump
+jmp near far2 ; both: near jump
+jmp far far2 ; YASM: far jump; NASM: value referenced by FAR is not relocatable
+dw seg far2
+far2 equ 1234:5678
+;mov ax, [1234:5678] ; YASM: invalid segment in effective address; NASM: invalid segment override
+;mov ax, 1234:5678 ; YASM: immediate does not support segment; NASM: invalid combination of opcode and operands
--- /dev/null
+ea
+2e
+16
+d2
+04
+e9
+26
+16
+ea
+2e
+16
+d2
+04
+e9
+1e
+16
+e9
+1b
+16
+ea
+2e
+16
+d2
+04
+d2
+04
+e9
+11
+16
+e9
+0e
+16
+ea
+2e
+16
+d2
+04
+d2
+04
--- /dev/null
+; all of these should be illegal
+
+jmp far[1:2]
+mov ax,[1:2]
+push dword [1:2]
+mov ax,1:2
--- /dev/null
+-:3: error: invalid segment in effective address
+-:4: error: invalid segment in effective address
+-:5: error: invalid segment in effective address
+-:6: error: immediate does not support segment
; all of these should be legal and should just result in the offset portion
-jmp far[1:2]
-mov ax,[1:2]
-push dword [1:2]
-mov ax,1:2
-
foo equ 1:2
jmp far[foo]
mov ax,[foo]
b8
02
00
-ff
-2e
-02
-00
-a1
-02
-00
-66
-ff
-36
-02
-00
-b8
-02
-00
unsigned int mode_bits = id_insn->mode_bits;
x86_jmpfar *jmpfar;
yasm_insn_operand *op;
- /*@only@*/ yasm_expr *segment;
jmpfar = yasm_xmalloc(sizeof(x86_jmpfar));
x86_finalize_common(&jmpfar->common, info, mode_bits);
op = yasm_insn_ops_first(&id_insn->insn);
- 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, prev_bc, 16))
+ if (op->type == YASM_INSN__OPERAND_IMM && op->seg) {
+ /* SEG:OFF */
+ if (yasm_value_finalize_expr(&jmpfar->segment, op->seg, prev_bc, 16))
yasm_error_set(YASM_ERROR_TOO_COMPLEX,
N_("jump target segment too complex"));
if (yasm_value_finalize_expr(&jmpfar->offset, op->data.val, prev_bc,
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), prev_bc, 0)
- || yasm_value_finalize_expr(&jmpfar->segment, op->data.val,
- prev_bc, 16))
+ yasm_expr *e = yasm_expr_create_branch(YASM_EXPR_SEG,
+ yasm_expr_copy(op->data.val),
+ op->data.val->line);
+ if (yasm_value_finalize_expr(&jmpfar->offset, op->data.val, prev_bc, 0)
+ || yasm_value_finalize_expr(&jmpfar->segment, e, prev_bc, 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"));
break;
case OPT_ImmNotSegOff:
if (op->type != YASM_INSN__OPERAND_IMM ||
- op->targetmod != 0 ||
- yasm_expr_is_op(op->data.val, YASM_EXPR_SEGOFF))
+ op->targetmod != 0 || op->seg)
mismatch = 1;
break;
case OPT_XMM0:
yasm_internal_error(
N_("invalid operand conversion"));
case YASM_INSN__OPERAND_MEMORY:
+ if (op->seg)
+ yasm_error_set(YASM_ERROR_VALUE,
+ N_("invalid segment in effective address"));
insn->x86_ea = (x86_effaddr *)op->data.ea;
if (info_ops[i].type == OPT_MemOffs)
/* Special-case for MOV MemOffs instruction */
}
break;
case OPA_Imm:
+ if (op->seg)
+ yasm_error_set(YASM_ERROR_VALUE,
+ N_("immediate does not support segment"));
if (op->type == YASM_INSN__OPERAND_IMM) {
imm = op->data.val;
im_len = size_lookup[info_ops[i].size];
yasm_internal_error(N_("invalid operand conversion"));
break;
case OPA_SImm:
+ if (op->seg)
+ yasm_error_set(YASM_ERROR_VALUE,
+ N_("immediate does not support segment"));
if (op->type == YASM_INSN__OPERAND_IMM) {
imm = op->data.val;
im_len = size_lookup[info_ops[i].size];
; Use without seg should yield just the offset part.
mov bx, keybuf
-mov bx, 0040h:001Eh ; Illegal in NASM ("invalid combination...")
+;mov bx, 0040h:001Eh ; Illegal
; Each of the below pairs should be equivalent (and legal) in Yasm.
; There are some differences from NASM here!
+; Defaults to near jump (on both NASM and Yasm)
+jmp keybuf
+
; Direct far jump.
-jmp keybuf ; Results in a near jump in NASM
-jmp 0040h:001Eh ; But Yasm sees the equ value as equivalent to this
+jmp 0040h:001Eh
; Force near (non-far) jump (just offset, no segment).
jmp near keybuf
bb
1e
00
-bb
-1e
-00
-ea
-1e
-00
-40
-00
+e9
+10
+ff
ea
1e
00
40
00
e9
-03
+08
ff
e9
-00
+05
ff
e9
-fd
-fe
+02
+ff
e9
-dc
+e1
fe
e9
-d9
+de
0e
e9
-d6
+db
4e
eb
fe
typedef enum {
NORM_EXPR,
- DIR_EXPR,
- DV_EXPR
+ DIR_EXPR, /* Can't have seg:off or WRT anywhere */
+ DV_EXPR /* Can't have registers anywhere */
} expr_type;
static yasm_bytecode *parse_line(yasm_parser_nasm *parser_nasm);
static yasm_bytecode *parse_exp(yasm_parser_nasm *parser_nasm);
static yasm_bytecode *parse_instr(yasm_parser_nasm *parser_nasm);
static yasm_insn_operand *parse_operand(yasm_parser_nasm *parser_nasm);
-static yasm_effaddr *parse_memaddr(yasm_parser_nasm *parser_nasm);
+static yasm_insn_operand *parse_memaddr(yasm_parser_nasm *parser_nasm);
static yasm_expr *parse_expr(yasm_parser_nasm *parser_nasm, expr_type type);
static yasm_expr *parse_bexpr(yasm_parser_nasm *parser_nasm, expr_type type);
static yasm_expr *parse_expr0(yasm_parser_nasm *parser_nasm, expr_type type);
yasm_expr *multiple;
yasm_bytecode *bc;
- multiple = parse_expr(parser_nasm, DV_EXPR);
+ multiple = parse_bexpr(parser_nasm, DV_EXPR);
if (!multiple) {
yasm_error_set(YASM_ERROR_SYNTAX, N_("expression expected after %s"),
"TIMES");
goto dv_done;
}
}
- if ((e = parse_expr(parser_nasm, DV_EXPR)))
+ if ((e = parse_bexpr(parser_nasm, DV_EXPR)))
dv = yasm_dv_create_expr(e);
else {
yasm_error_set(YASM_ERROR_SYNTAX,
unsigned int size = RESERVE_SPACE_val/8;
yasm_expr *e;
get_next_token();
- e = parse_expr(parser_nasm, DV_EXPR);
+ e = parse_bexpr(parser_nasm, DV_EXPR);
if (!e) {
yasm_error_set(YASM_ERROR_SYNTAX,
N_("expression expected after %s"), "RESx");
get_next_token();
if (is_eol())
goto incbin_done;
- start = parse_expr(parser_nasm, DV_EXPR);
+ start = parse_bexpr(parser_nasm, DV_EXPR);
if (!start) {
yasm_error_set(YASM_ERROR_SYNTAX,
N_("expression expected for INCBIN start"));
get_next_token();
if (is_eol())
goto incbin_done;
- maxlen = parse_expr(parser_nasm, DV_EXPR);
+ maxlen = parse_bexpr(parser_nasm, DV_EXPR);
if (!maxlen) {
yasm_error_set(YASM_ERROR_SYNTAX,
N_("expression expected for INCBIN maximum length"));
switch (curtok) {
case '[':
{
- yasm_effaddr *ea;
get_next_token();
- ea = parse_memaddr(parser_nasm);
+ op = parse_memaddr(parser_nasm);
expect(']');
get_next_token();
- if (!ea) {
+ if (!op) {
yasm_error_set(YASM_ERROR_SYNTAX,
N_("memory address expected"));
return NULL;
}
- return yasm_operand_create_mem(ea);
+ return op;
}
case SEGREG:
op = yasm_operand_create_segreg(SEGREG_val);
}
default:
{
- yasm_expr *e = parse_expr(parser_nasm, NORM_EXPR);
+ yasm_expr *e = parse_bexpr(parser_nasm, NORM_EXPR);
if (!e)
return NULL;
- return yasm_operand_create_imm(e);
+ if (curtok != ':')
+ return yasm_operand_create_imm(e);
+ else {
+ yasm_expr *off;
+ get_next_token();
+ off = parse_bexpr(parser_nasm, NORM_EXPR);
+ if (!off) {
+ yasm_expr_destroy(e);
+ return NULL;
+ }
+ op = yasm_operand_create_imm(off);
+ op->seg = e;
+ return op;
+ }
}
}
}
/* memory addresses */
-static yasm_effaddr *
+static yasm_insn_operand *
parse_memaddr(yasm_parser_nasm *parser_nasm)
{
- yasm_effaddr *ea;
+ yasm_insn_operand *op;
switch (curtok) {
case SEGREG:
{
return NULL;
}
get_next_token();
- ea = parse_memaddr(parser_nasm);
- if (ea)
- yasm_ea_set_segreg(ea, segreg);
- return ea;
+ op = parse_memaddr(parser_nasm);
+ if (op)
+ yasm_ea_set_segreg(op->data.ea, segreg);
+ return op;
}
case SIZE_OVERRIDE:
{
unsigned int size = SIZE_OVERRIDE_val;
get_next_token();
- ea = parse_memaddr(parser_nasm);
- if (ea)
- ea->disp.size = size;
- return ea;
+ op = parse_memaddr(parser_nasm);
+ if (op)
+ op->data.ea->disp.size = size;
+ return op;
}
case NOSPLIT:
get_next_token();
- ea = parse_memaddr(parser_nasm);
- if (ea)
- ea->nosplit = 1;
- return ea;
+ op = parse_memaddr(parser_nasm);
+ if (op)
+ op->data.ea->nosplit = 1;
+ return op;
case REL:
get_next_token();
- ea = parse_memaddr(parser_nasm);
- if (ea) {
- ea->pc_rel = 1;
- ea->not_pc_rel = 0;
+ op = parse_memaddr(parser_nasm);
+ if (op) {
+ op->data.ea->pc_rel = 1;
+ op->data.ea->not_pc_rel = 0;
}
- return ea;
+ return op;
case ABS:
get_next_token();
- ea = parse_memaddr(parser_nasm);
- if (ea) {
- ea->pc_rel = 0;
- ea->not_pc_rel = 1;
+ op = parse_memaddr(parser_nasm);
+ if (op) {
+ op->data.ea->pc_rel = 0;
+ op->data.ea->not_pc_rel = 1;
}
- return ea;
+ return op;
default:
{
- yasm_expr *e = parse_expr(parser_nasm, NORM_EXPR);
+ yasm_expr *e = parse_bexpr(parser_nasm, NORM_EXPR);
if (!e)
return NULL;
- return yasm_arch_ea_create(p_object->arch, e);
+ if (curtok != ':')
+ return yasm_operand_create_mem(
+ yasm_arch_ea_create(p_object->arch, e));
+ else {
+ yasm_expr *off;
+ get_next_token();
+ off = parse_bexpr(parser_nasm, NORM_EXPR);
+ if (!off) {
+ yasm_expr_destroy(e);
+ return NULL;
+ }
+ op = yasm_operand_create_mem(
+ yasm_arch_ea_create(p_object->arch, off));
+ op->seg = e;
+ return op;
+ }
}
}
}
parse_expr(yasm_parser_nasm *parser_nasm, expr_type type)
{
switch (type) {
- case NORM_EXPR:
- parse_expr_common(parse_bexpr, ':', parse_bexpr, YASM_EXPR_SEGOFF);
- case DV_EXPR:
- /* dataval expressions can't handle seg:off */
- return parse_bexpr(parser_nasm, type);
case DIR_EXPR:
/* directive expressions can't handle seg:off or WRT */
return parse_expr0(parser_nasm, type);
+ default:
+ parse_expr_common(parse_bexpr, ':', parse_bexpr, YASM_EXPR_SEGOFF);
}
/*@notreached@*/
return NULL;