diff options
author | somov <somov@yandex-team.ru> | 2022-02-10 16:45:47 +0300 |
---|---|---|
committer | Daniil Cherednik <dcherednik@yandex-team.ru> | 2022-02-10 16:45:47 +0300 |
commit | a5950576e397b1909261050b8c7da16db58f10b1 (patch) | |
tree | 7ba7677f6a4c3e19e2cefab34d16df2c8963b4d4 /contrib/tools/yasm/modules/arch | |
parent | 81eddc8c0b55990194e112b02d127b87d54164a9 (diff) | |
download | ydb-a5950576e397b1909261050b8c7da16db58f10b1.tar.gz |
Restoring authorship annotation for <somov@yandex-team.ru>. Commit 1 of 2.
Diffstat (limited to 'contrib/tools/yasm/modules/arch')
-rw-r--r-- | contrib/tools/yasm/modules/arch/lc3b/lc3barch.c | 424 | ||||
-rw-r--r-- | contrib/tools/yasm/modules/arch/lc3b/lc3barch.h | 140 | ||||
-rw-r--r-- | contrib/tools/yasm/modules/arch/lc3b/lc3bbc.c | 498 | ||||
-rw-r--r-- | contrib/tools/yasm/modules/arch/x86/x86arch.c | 1266 | ||||
-rw-r--r-- | contrib/tools/yasm/modules/arch/x86/x86arch.h | 672 | ||||
-rw-r--r-- | contrib/tools/yasm/modules/arch/x86/x86bc.c | 2124 | ||||
-rw-r--r-- | contrib/tools/yasm/modules/arch/x86/x86expr.c | 2122 | ||||
-rw-r--r-- | contrib/tools/yasm/modules/arch/x86/x86id.c | 3902 |
8 files changed, 5574 insertions, 5574 deletions
diff --git a/contrib/tools/yasm/modules/arch/lc3b/lc3barch.c b/contrib/tools/yasm/modules/arch/lc3b/lc3barch.c index 051452862f..e9b1ce9dde 100644 --- a/contrib/tools/yasm/modules/arch/lc3b/lc3barch.c +++ b/contrib/tools/yasm/modules/arch/lc3b/lc3barch.c @@ -1,212 +1,212 @@ -/* - * LC-3b architecture description - * - * Copyright (C) 2003-2007 Peter Johnson - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ -#include <util.h> - -#include <libyasm.h> - -#include "lc3barch.h" - - -yasm_arch_module yasm_lc3b_LTX_arch; - - -static /*@only@*/ yasm_arch * -lc3b_create(const char *machine, const char *parser, - /*@out@*/ yasm_arch_create_error *error) -{ - yasm_arch_base *arch; - - *error = YASM_ARCH_CREATE_OK; - - if (yasm__strcasecmp(machine, "lc3b") != 0) { - *error = YASM_ARCH_CREATE_BAD_MACHINE; - return NULL; - } - - if (yasm__strcasecmp(parser, "nasm") != 0) { - *error = YASM_ARCH_CREATE_BAD_PARSER; - return NULL; - } - - arch = yasm_xmalloc(sizeof(yasm_arch_base)); - arch->module = &yasm_lc3b_LTX_arch; - return (yasm_arch *)arch; -} - -static void -lc3b_destroy(/*@only@*/ yasm_arch *arch) -{ - yasm_xfree(arch); -} - -static const char * -lc3b_get_machine(/*@unused@*/ const yasm_arch *arch) -{ - return "lc3b"; -} - -static unsigned int -lc3b_get_address_size(/*@unused@*/ const yasm_arch *arch) -{ - return 16; -} - -static int -lc3b_set_var(yasm_arch *arch, const char *var, unsigned long val) -{ - return 1; -} - -static const unsigned char ** -lc3b_get_fill(const yasm_arch *arch) -{ - /* NOP pattern is all 0's per LC-3b Assembler 3.50 output */ - static const unsigned char *fill[16] = { - NULL, /* unused */ - NULL, /* 1 - illegal; all opcodes are 2 bytes long */ - (const unsigned char *) - "\x00\x00", /* 4 */ - NULL, /* 3 - illegal */ - (const unsigned char *) - "\x00\x00\x00\x00", /* 4 */ - NULL, /* 5 - illegal */ - (const unsigned char *) - "\x00\x00\x00\x00\x00\x00", /* 6 */ - NULL, /* 7 - illegal */ - (const unsigned char *) - "\x00\x00\x00\x00\x00\x00" /* 8 */ - "\x00\x00", - NULL, /* 9 - illegal */ - (const unsigned char *) - "\x00\x00\x00\x00\x00\x00" /* 10 */ - "\x00\x00\x00\x00", - NULL, /* 11 - illegal */ - (const unsigned char *) - "\x00\x00\x00\x00\x00\x00" /* 12 */ - "\x00\x00\x00\x00\x00\x00", - NULL, /* 13 - illegal */ - (const unsigned char *) - "\x00\x00\x00\x00\x00\x00" /* 14 */ - "\x00\x00\x00\x00\x00\x00\x00\x00", - NULL /* 15 - illegal */ - }; - return fill; -} - -static unsigned int -lc3b_get_reg_size(/*@unused@*/ yasm_arch *arch, /*@unused@*/ uintptr_t reg) -{ - return 16; -} - -static uintptr_t -lc3b_reggroup_get_reg(/*@unused@*/ yasm_arch *arch, - /*@unused@*/ uintptr_t reggroup, - /*@unused@*/ unsigned long regindex) -{ - return 0; -} - -static void -lc3b_reg_print(/*@unused@*/ yasm_arch *arch, uintptr_t reg, FILE *f) -{ - fprintf(f, "r%u", (unsigned int)(reg&7)); -} - -static int -lc3b_floatnum_tobytes(yasm_arch *arch, const yasm_floatnum *flt, - unsigned char *buf, size_t destsize, size_t valsize, - size_t shift, int warn) -{ - yasm_error_set(YASM_ERROR_FLOATING_POINT, - N_("LC-3b does not support floating point")); - return 1; -} - -static yasm_effaddr * -lc3b_ea_create_expr(yasm_arch *arch, yasm_expr *e) -{ - yasm_effaddr *ea = yasm_xmalloc(sizeof(yasm_effaddr)); - yasm_value_initialize(&ea->disp, e, 0); - ea->need_nonzero_len = 0; - ea->need_disp = 1; - ea->nosplit = 0; - ea->strong = 0; - ea->segreg = 0; - ea->pc_rel = 0; - ea->not_pc_rel = 0; - return ea; -} - -void -yasm_lc3b__ea_destroy(/*@only@*/ yasm_effaddr *ea) -{ - yasm_value_delete(&ea->disp); - yasm_xfree(ea); -} - -static void -lc3b_ea_print(const yasm_effaddr *ea, FILE *f, int indent_level) -{ - fprintf(f, "%*sDisp:\n", indent_level, ""); - yasm_value_print(&ea->disp, f, indent_level+1); -} - -/* Define lc3b machines -- see arch.h for details */ -static yasm_arch_machine lc3b_machines[] = { - { "LC-3b", "lc3b" }, - { NULL, NULL } -}; - -/* Define arch structure -- see arch.h for details */ -yasm_arch_module yasm_lc3b_LTX_arch = { - "LC-3b", - "lc3b", - NULL, - lc3b_create, - lc3b_destroy, - lc3b_get_machine, - lc3b_get_address_size, - lc3b_set_var, - yasm_lc3b__parse_check_insnprefix, - yasm_lc3b__parse_check_regtmod, - lc3b_get_fill, - lc3b_floatnum_tobytes, - yasm_lc3b__intnum_tobytes, - lc3b_get_reg_size, - lc3b_reggroup_get_reg, - lc3b_reg_print, - NULL, /*yasm_lc3b__segreg_print*/ - lc3b_ea_create_expr, - yasm_lc3b__ea_destroy, - lc3b_ea_print, - yasm_lc3b__create_empty_insn, - lc3b_machines, - "lc3b", - 16, - 2 -}; +/* + * LC-3b architecture description + * + * Copyright (C) 2003-2007 Peter Johnson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include <util.h> + +#include <libyasm.h> + +#include "lc3barch.h" + + +yasm_arch_module yasm_lc3b_LTX_arch; + + +static /*@only@*/ yasm_arch * +lc3b_create(const char *machine, const char *parser, + /*@out@*/ yasm_arch_create_error *error) +{ + yasm_arch_base *arch; + + *error = YASM_ARCH_CREATE_OK; + + if (yasm__strcasecmp(machine, "lc3b") != 0) { + *error = YASM_ARCH_CREATE_BAD_MACHINE; + return NULL; + } + + if (yasm__strcasecmp(parser, "nasm") != 0) { + *error = YASM_ARCH_CREATE_BAD_PARSER; + return NULL; + } + + arch = yasm_xmalloc(sizeof(yasm_arch_base)); + arch->module = &yasm_lc3b_LTX_arch; + return (yasm_arch *)arch; +} + +static void +lc3b_destroy(/*@only@*/ yasm_arch *arch) +{ + yasm_xfree(arch); +} + +static const char * +lc3b_get_machine(/*@unused@*/ const yasm_arch *arch) +{ + return "lc3b"; +} + +static unsigned int +lc3b_get_address_size(/*@unused@*/ const yasm_arch *arch) +{ + return 16; +} + +static int +lc3b_set_var(yasm_arch *arch, const char *var, unsigned long val) +{ + return 1; +} + +static const unsigned char ** +lc3b_get_fill(const yasm_arch *arch) +{ + /* NOP pattern is all 0's per LC-3b Assembler 3.50 output */ + static const unsigned char *fill[16] = { + NULL, /* unused */ + NULL, /* 1 - illegal; all opcodes are 2 bytes long */ + (const unsigned char *) + "\x00\x00", /* 4 */ + NULL, /* 3 - illegal */ + (const unsigned char *) + "\x00\x00\x00\x00", /* 4 */ + NULL, /* 5 - illegal */ + (const unsigned char *) + "\x00\x00\x00\x00\x00\x00", /* 6 */ + NULL, /* 7 - illegal */ + (const unsigned char *) + "\x00\x00\x00\x00\x00\x00" /* 8 */ + "\x00\x00", + NULL, /* 9 - illegal */ + (const unsigned char *) + "\x00\x00\x00\x00\x00\x00" /* 10 */ + "\x00\x00\x00\x00", + NULL, /* 11 - illegal */ + (const unsigned char *) + "\x00\x00\x00\x00\x00\x00" /* 12 */ + "\x00\x00\x00\x00\x00\x00", + NULL, /* 13 - illegal */ + (const unsigned char *) + "\x00\x00\x00\x00\x00\x00" /* 14 */ + "\x00\x00\x00\x00\x00\x00\x00\x00", + NULL /* 15 - illegal */ + }; + return fill; +} + +static unsigned int +lc3b_get_reg_size(/*@unused@*/ yasm_arch *arch, /*@unused@*/ uintptr_t reg) +{ + return 16; +} + +static uintptr_t +lc3b_reggroup_get_reg(/*@unused@*/ yasm_arch *arch, + /*@unused@*/ uintptr_t reggroup, + /*@unused@*/ unsigned long regindex) +{ + return 0; +} + +static void +lc3b_reg_print(/*@unused@*/ yasm_arch *arch, uintptr_t reg, FILE *f) +{ + fprintf(f, "r%u", (unsigned int)(reg&7)); +} + +static int +lc3b_floatnum_tobytes(yasm_arch *arch, const yasm_floatnum *flt, + unsigned char *buf, size_t destsize, size_t valsize, + size_t shift, int warn) +{ + yasm_error_set(YASM_ERROR_FLOATING_POINT, + N_("LC-3b does not support floating point")); + return 1; +} + +static yasm_effaddr * +lc3b_ea_create_expr(yasm_arch *arch, yasm_expr *e) +{ + yasm_effaddr *ea = yasm_xmalloc(sizeof(yasm_effaddr)); + yasm_value_initialize(&ea->disp, e, 0); + ea->need_nonzero_len = 0; + ea->need_disp = 1; + ea->nosplit = 0; + ea->strong = 0; + ea->segreg = 0; + ea->pc_rel = 0; + ea->not_pc_rel = 0; + return ea; +} + +void +yasm_lc3b__ea_destroy(/*@only@*/ yasm_effaddr *ea) +{ + yasm_value_delete(&ea->disp); + yasm_xfree(ea); +} + +static void +lc3b_ea_print(const yasm_effaddr *ea, FILE *f, int indent_level) +{ + fprintf(f, "%*sDisp:\n", indent_level, ""); + yasm_value_print(&ea->disp, f, indent_level+1); +} + +/* Define lc3b machines -- see arch.h for details */ +static yasm_arch_machine lc3b_machines[] = { + { "LC-3b", "lc3b" }, + { NULL, NULL } +}; + +/* Define arch structure -- see arch.h for details */ +yasm_arch_module yasm_lc3b_LTX_arch = { + "LC-3b", + "lc3b", + NULL, + lc3b_create, + lc3b_destroy, + lc3b_get_machine, + lc3b_get_address_size, + lc3b_set_var, + yasm_lc3b__parse_check_insnprefix, + yasm_lc3b__parse_check_regtmod, + lc3b_get_fill, + lc3b_floatnum_tobytes, + yasm_lc3b__intnum_tobytes, + lc3b_get_reg_size, + lc3b_reggroup_get_reg, + lc3b_reg_print, + NULL, /*yasm_lc3b__segreg_print*/ + lc3b_ea_create_expr, + yasm_lc3b__ea_destroy, + lc3b_ea_print, + yasm_lc3b__create_empty_insn, + lc3b_machines, + "lc3b", + 16, + 2 +}; diff --git a/contrib/tools/yasm/modules/arch/lc3b/lc3barch.h b/contrib/tools/yasm/modules/arch/lc3b/lc3barch.h index 9ded8cbef7..745dffc335 100644 --- a/contrib/tools/yasm/modules/arch/lc3b/lc3barch.h +++ b/contrib/tools/yasm/modules/arch/lc3b/lc3barch.h @@ -1,70 +1,70 @@ -/* - * LC-3b Architecture header file - * - * Copyright (C) 2003-2007 Peter Johnson - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ -#ifndef YASM_LC3BARCH_H -#define YASM_LC3BARCH_H - -/* Types of immediate. All immediates are stored in the LSBs of the insn. */ -typedef enum lc3b_imm_type { - LC3B_IMM_NONE = 0, /* no immediate */ - LC3B_IMM_4, /* 4-bit */ - LC3B_IMM_5, /* 5-bit */ - LC3B_IMM_6_WORD, /* 6-bit, word-multiple (byte>>1) */ - LC3B_IMM_6_BYTE, /* 6-bit, byte-multiple */ - LC3B_IMM_8, /* 8-bit, word-multiple (byte>>1) */ - LC3B_IMM_9, /* 9-bit, signed, word-multiple (byte>>1) */ - LC3B_IMM_9_PC /* 9-bit, signed, word-multiple, PC relative */ -} lc3b_imm_type; - -/* Bytecode types */ - -typedef struct lc3b_insn { - yasm_value imm; /* immediate or relative value */ - lc3b_imm_type imm_type; /* size of the immediate */ - - unsigned int opcode; /* opcode */ -} lc3b_insn; - -void yasm_lc3b__bc_transform_insn(yasm_bytecode *bc, lc3b_insn *insn); - -yasm_arch_insnprefix yasm_lc3b__parse_check_insnprefix - (yasm_arch *arch, const char *id, size_t id_len, unsigned long line, - /*@out@*/ /*@only@*/ yasm_bytecode **bc, /*@out@*/ uintptr_t *prefix); -yasm_arch_regtmod yasm_lc3b__parse_check_regtmod - (yasm_arch *arch, const char *id, size_t id_len, - /*@out@*/ uintptr_t *data); - -int yasm_lc3b__intnum_tobytes - (yasm_arch *arch, const yasm_intnum *intn, unsigned char *buf, - size_t destsize, size_t valsize, int shift, const yasm_bytecode *bc, - int warn); - -/*@only@*/ yasm_bytecode *yasm_lc3b__create_empty_insn(yasm_arch *arch, - unsigned long line); - -void yasm_lc3b__ea_destroy(/*@only@*/ yasm_effaddr *ea); - -#endif +/* + * LC-3b Architecture header file + * + * Copyright (C) 2003-2007 Peter Johnson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef YASM_LC3BARCH_H +#define YASM_LC3BARCH_H + +/* Types of immediate. All immediates are stored in the LSBs of the insn. */ +typedef enum lc3b_imm_type { + LC3B_IMM_NONE = 0, /* no immediate */ + LC3B_IMM_4, /* 4-bit */ + LC3B_IMM_5, /* 5-bit */ + LC3B_IMM_6_WORD, /* 6-bit, word-multiple (byte>>1) */ + LC3B_IMM_6_BYTE, /* 6-bit, byte-multiple */ + LC3B_IMM_8, /* 8-bit, word-multiple (byte>>1) */ + LC3B_IMM_9, /* 9-bit, signed, word-multiple (byte>>1) */ + LC3B_IMM_9_PC /* 9-bit, signed, word-multiple, PC relative */ +} lc3b_imm_type; + +/* Bytecode types */ + +typedef struct lc3b_insn { + yasm_value imm; /* immediate or relative value */ + lc3b_imm_type imm_type; /* size of the immediate */ + + unsigned int opcode; /* opcode */ +} lc3b_insn; + +void yasm_lc3b__bc_transform_insn(yasm_bytecode *bc, lc3b_insn *insn); + +yasm_arch_insnprefix yasm_lc3b__parse_check_insnprefix + (yasm_arch *arch, const char *id, size_t id_len, unsigned long line, + /*@out@*/ /*@only@*/ yasm_bytecode **bc, /*@out@*/ uintptr_t *prefix); +yasm_arch_regtmod yasm_lc3b__parse_check_regtmod + (yasm_arch *arch, const char *id, size_t id_len, + /*@out@*/ uintptr_t *data); + +int yasm_lc3b__intnum_tobytes + (yasm_arch *arch, const yasm_intnum *intn, unsigned char *buf, + size_t destsize, size_t valsize, int shift, const yasm_bytecode *bc, + int warn); + +/*@only@*/ yasm_bytecode *yasm_lc3b__create_empty_insn(yasm_arch *arch, + unsigned long line); + +void yasm_lc3b__ea_destroy(/*@only@*/ yasm_effaddr *ea); + +#endif diff --git a/contrib/tools/yasm/modules/arch/lc3b/lc3bbc.c b/contrib/tools/yasm/modules/arch/lc3b/lc3bbc.c index d077c7c5fb..fb8a46d100 100644 --- a/contrib/tools/yasm/modules/arch/lc3b/lc3bbc.c +++ b/contrib/tools/yasm/modules/arch/lc3b/lc3bbc.c @@ -1,249 +1,249 @@ -/* - * LC-3b bytecode utility functions - * - * Copyright (C) 2003-2007 Peter Johnson - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ -#include <util.h> - -#include <libyasm.h> - -#include "lc3barch.h" - - -/* Bytecode callback function prototypes */ - -static void lc3b_bc_insn_destroy(void *contents); -static void lc3b_bc_insn_print(const void *contents, FILE *f, - int indent_level); -static int lc3b_bc_insn_calc_len(yasm_bytecode *bc, - yasm_bc_add_span_func add_span, - void *add_span_data); -static int lc3b_bc_insn_expand(yasm_bytecode *bc, int span, long old_val, - long new_val, /*@out@*/ long *neg_thres, - /*@out@*/ long *pos_thres); -static int lc3b_bc_insn_tobytes(yasm_bytecode *bc, unsigned char **bufp, - unsigned char *bufstart, - void *d, yasm_output_value_func output_value, - /*@null@*/ yasm_output_reloc_func output_reloc); - -/* Bytecode callback structures */ - -static const yasm_bytecode_callback lc3b_bc_callback_insn = { - lc3b_bc_insn_destroy, - lc3b_bc_insn_print, - yasm_bc_finalize_common, - NULL, - lc3b_bc_insn_calc_len, - lc3b_bc_insn_expand, - lc3b_bc_insn_tobytes, - 0 -}; - - -void -yasm_lc3b__bc_transform_insn(yasm_bytecode *bc, lc3b_insn *insn) -{ - yasm_bc_transform(bc, &lc3b_bc_callback_insn, insn); -} - -static void -lc3b_bc_insn_destroy(void *contents) -{ - lc3b_insn *insn = (lc3b_insn *)contents; - yasm_value_delete(&insn->imm); - yasm_xfree(contents); -} - -static void -lc3b_bc_insn_print(const void *contents, FILE *f, int indent_level) -{ - const lc3b_insn *insn = (const lc3b_insn *)contents; - - fprintf(f, "%*s_Instruction_\n", indent_level, ""); - fprintf(f, "%*sImmediate Value:", indent_level, ""); - if (!insn->imm.abs) - fprintf(f, " (nil)\n"); - else { - indent_level++; - fprintf(f, "\n"); - yasm_value_print(&insn->imm, f, indent_level); - fprintf(f, "%*sType=", indent_level, ""); - switch (insn->imm_type) { - case LC3B_IMM_NONE: - fprintf(f, "NONE-SHOULDN'T HAPPEN"); - break; - case LC3B_IMM_4: - fprintf(f, "4-bit"); - break; - case LC3B_IMM_5: - fprintf(f, "5-bit"); - break; - case LC3B_IMM_6_WORD: - fprintf(f, "6-bit, word-multiple"); - break; - case LC3B_IMM_6_BYTE: - fprintf(f, "6-bit, byte-multiple"); - break; - case LC3B_IMM_8: - fprintf(f, "8-bit, word-multiple"); - break; - case LC3B_IMM_9: - fprintf(f, "9-bit, signed, word-multiple"); - break; - case LC3B_IMM_9_PC: - fprintf(f, "9-bit, signed, word-multiple, PC-relative"); - break; - } - indent_level--; - } - /* FIXME - fprintf(f, "\n%*sOrigin=", indent_level, ""); - if (insn->origin) { - fprintf(f, "\n"); - yasm_symrec_print(insn->origin, f, indent_level+1); - } else - fprintf(f, "(nil)\n"); - */ - fprintf(f, "%*sOpcode: %04x\n", indent_level, "", - (unsigned int)insn->opcode); -} - -static int -lc3b_bc_insn_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span, - void *add_span_data) -{ - lc3b_insn *insn = (lc3b_insn *)bc->contents; - yasm_bytecode *target_prevbc; - - /* Fixed size instruction length */ - bc->len += 2; - - /* Only need to worry about out-of-range to PC-relative */ - if (insn->imm_type != LC3B_IMM_9_PC) - return 0; - - if (insn->imm.rel - && (!yasm_symrec_get_label(insn->imm.rel, &target_prevbc) - || target_prevbc->section != bc->section)) { - /* External or out of segment, so we can't check distance. */ - return 0; - } - - /* 9-bit signed, word-multiple displacement */ - add_span(add_span_data, bc, 1, &insn->imm, -512+(long)bc->len, - 511+(long)bc->len); - return 0; -} - -static int -lc3b_bc_insn_expand(yasm_bytecode *bc, int span, long old_val, long new_val, - /*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres) -{ - yasm_error_set(YASM_ERROR_VALUE, N_("jump target out of range")); - return -1; -} - -static int -lc3b_bc_insn_tobytes(yasm_bytecode *bc, unsigned char **bufp, - unsigned char *bufstart, void *d, - yasm_output_value_func output_value, - /*@unused@*/ yasm_output_reloc_func output_reloc) -{ - lc3b_insn *insn = (lc3b_insn *)bc->contents; - /*@only@*/ yasm_intnum *delta; - unsigned long buf_off = (unsigned long)(*bufp - bufstart); - - /* Output opcode */ - YASM_SAVE_16_L(*bufp, insn->opcode); - - /* Insert immediate into opcode. */ - switch (insn->imm_type) { - case LC3B_IMM_NONE: - break; - case LC3B_IMM_4: - insn->imm.size = 4; - if (output_value(&insn->imm, *bufp, 2, buf_off, bc, 1, d)) - return 1; - break; - case LC3B_IMM_5: - insn->imm.size = 5; - insn->imm.sign = 1; - if (output_value(&insn->imm, *bufp, 2, buf_off, bc, 1, d)) - return 1; - break; - case LC3B_IMM_6_WORD: - insn->imm.size = 6; - if (output_value(&insn->imm, *bufp, 2, buf_off, bc, 1, d)) - return 1; - break; - case LC3B_IMM_6_BYTE: - insn->imm.size = 6; - insn->imm.sign = 1; - if (output_value(&insn->imm, *bufp, 2, buf_off, bc, 1, d)) - return 1; - break; - case LC3B_IMM_8: - insn->imm.size = 8; - if (output_value(&insn->imm, *bufp, 2, buf_off, bc, 1, d)) - return 1; - break; - case LC3B_IMM_9_PC: - /* Adjust relative displacement to end of bytecode */ - delta = yasm_intnum_create_int(-1); - if (!insn->imm.abs) - insn->imm.abs = yasm_expr_create_ident(yasm_expr_int(delta), - bc->line); - else - insn->imm.abs = - yasm_expr_create(YASM_EXPR_ADD, - yasm_expr_expr(insn->imm.abs), - yasm_expr_int(delta), bc->line); - - insn->imm.size = 9; - insn->imm.sign = 1; - if (output_value(&insn->imm, *bufp, 2, buf_off, bc, 1, d)) - return 1; - break; - case LC3B_IMM_9: - insn->imm.size = 9; - if (output_value(&insn->imm, *bufp, 2, buf_off, bc, 1, d)) - return 1; - break; - default: - yasm_internal_error(N_("Unrecognized immediate type")); - } - - *bufp += 2; /* all instructions are 2 bytes in size */ - return 0; -} - -int -yasm_lc3b__intnum_tobytes(yasm_arch *arch, const yasm_intnum *intn, - unsigned char *buf, size_t destsize, size_t valsize, - int shift, const yasm_bytecode *bc, int warn) -{ - /* Write value out. */ - yasm_intnum_get_sized(intn, buf, destsize, valsize, shift, 0, warn); - return 0; -} +/* + * LC-3b bytecode utility functions + * + * Copyright (C) 2003-2007 Peter Johnson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include <util.h> + +#include <libyasm.h> + +#include "lc3barch.h" + + +/* Bytecode callback function prototypes */ + +static void lc3b_bc_insn_destroy(void *contents); +static void lc3b_bc_insn_print(const void *contents, FILE *f, + int indent_level); +static int lc3b_bc_insn_calc_len(yasm_bytecode *bc, + yasm_bc_add_span_func add_span, + void *add_span_data); +static int lc3b_bc_insn_expand(yasm_bytecode *bc, int span, long old_val, + long new_val, /*@out@*/ long *neg_thres, + /*@out@*/ long *pos_thres); +static int lc3b_bc_insn_tobytes(yasm_bytecode *bc, unsigned char **bufp, + unsigned char *bufstart, + void *d, yasm_output_value_func output_value, + /*@null@*/ yasm_output_reloc_func output_reloc); + +/* Bytecode callback structures */ + +static const yasm_bytecode_callback lc3b_bc_callback_insn = { + lc3b_bc_insn_destroy, + lc3b_bc_insn_print, + yasm_bc_finalize_common, + NULL, + lc3b_bc_insn_calc_len, + lc3b_bc_insn_expand, + lc3b_bc_insn_tobytes, + 0 +}; + + +void +yasm_lc3b__bc_transform_insn(yasm_bytecode *bc, lc3b_insn *insn) +{ + yasm_bc_transform(bc, &lc3b_bc_callback_insn, insn); +} + +static void +lc3b_bc_insn_destroy(void *contents) +{ + lc3b_insn *insn = (lc3b_insn *)contents; + yasm_value_delete(&insn->imm); + yasm_xfree(contents); +} + +static void +lc3b_bc_insn_print(const void *contents, FILE *f, int indent_level) +{ + const lc3b_insn *insn = (const lc3b_insn *)contents; + + fprintf(f, "%*s_Instruction_\n", indent_level, ""); + fprintf(f, "%*sImmediate Value:", indent_level, ""); + if (!insn->imm.abs) + fprintf(f, " (nil)\n"); + else { + indent_level++; + fprintf(f, "\n"); + yasm_value_print(&insn->imm, f, indent_level); + fprintf(f, "%*sType=", indent_level, ""); + switch (insn->imm_type) { + case LC3B_IMM_NONE: + fprintf(f, "NONE-SHOULDN'T HAPPEN"); + break; + case LC3B_IMM_4: + fprintf(f, "4-bit"); + break; + case LC3B_IMM_5: + fprintf(f, "5-bit"); + break; + case LC3B_IMM_6_WORD: + fprintf(f, "6-bit, word-multiple"); + break; + case LC3B_IMM_6_BYTE: + fprintf(f, "6-bit, byte-multiple"); + break; + case LC3B_IMM_8: + fprintf(f, "8-bit, word-multiple"); + break; + case LC3B_IMM_9: + fprintf(f, "9-bit, signed, word-multiple"); + break; + case LC3B_IMM_9_PC: + fprintf(f, "9-bit, signed, word-multiple, PC-relative"); + break; + } + indent_level--; + } + /* FIXME + fprintf(f, "\n%*sOrigin=", indent_level, ""); + if (insn->origin) { + fprintf(f, "\n"); + yasm_symrec_print(insn->origin, f, indent_level+1); + } else + fprintf(f, "(nil)\n"); + */ + fprintf(f, "%*sOpcode: %04x\n", indent_level, "", + (unsigned int)insn->opcode); +} + +static int +lc3b_bc_insn_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span, + void *add_span_data) +{ + lc3b_insn *insn = (lc3b_insn *)bc->contents; + yasm_bytecode *target_prevbc; + + /* Fixed size instruction length */ + bc->len += 2; + + /* Only need to worry about out-of-range to PC-relative */ + if (insn->imm_type != LC3B_IMM_9_PC) + return 0; + + if (insn->imm.rel + && (!yasm_symrec_get_label(insn->imm.rel, &target_prevbc) + || target_prevbc->section != bc->section)) { + /* External or out of segment, so we can't check distance. */ + return 0; + } + + /* 9-bit signed, word-multiple displacement */ + add_span(add_span_data, bc, 1, &insn->imm, -512+(long)bc->len, + 511+(long)bc->len); + return 0; +} + +static int +lc3b_bc_insn_expand(yasm_bytecode *bc, int span, long old_val, long new_val, + /*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres) +{ + yasm_error_set(YASM_ERROR_VALUE, N_("jump target out of range")); + return -1; +} + +static int +lc3b_bc_insn_tobytes(yasm_bytecode *bc, unsigned char **bufp, + unsigned char *bufstart, void *d, + yasm_output_value_func output_value, + /*@unused@*/ yasm_output_reloc_func output_reloc) +{ + lc3b_insn *insn = (lc3b_insn *)bc->contents; + /*@only@*/ yasm_intnum *delta; + unsigned long buf_off = (unsigned long)(*bufp - bufstart); + + /* Output opcode */ + YASM_SAVE_16_L(*bufp, insn->opcode); + + /* Insert immediate into opcode. */ + switch (insn->imm_type) { + case LC3B_IMM_NONE: + break; + case LC3B_IMM_4: + insn->imm.size = 4; + if (output_value(&insn->imm, *bufp, 2, buf_off, bc, 1, d)) + return 1; + break; + case LC3B_IMM_5: + insn->imm.size = 5; + insn->imm.sign = 1; + if (output_value(&insn->imm, *bufp, 2, buf_off, bc, 1, d)) + return 1; + break; + case LC3B_IMM_6_WORD: + insn->imm.size = 6; + if (output_value(&insn->imm, *bufp, 2, buf_off, bc, 1, d)) + return 1; + break; + case LC3B_IMM_6_BYTE: + insn->imm.size = 6; + insn->imm.sign = 1; + if (output_value(&insn->imm, *bufp, 2, buf_off, bc, 1, d)) + return 1; + break; + case LC3B_IMM_8: + insn->imm.size = 8; + if (output_value(&insn->imm, *bufp, 2, buf_off, bc, 1, d)) + return 1; + break; + case LC3B_IMM_9_PC: + /* Adjust relative displacement to end of bytecode */ + delta = yasm_intnum_create_int(-1); + if (!insn->imm.abs) + insn->imm.abs = yasm_expr_create_ident(yasm_expr_int(delta), + bc->line); + else + insn->imm.abs = + yasm_expr_create(YASM_EXPR_ADD, + yasm_expr_expr(insn->imm.abs), + yasm_expr_int(delta), bc->line); + + insn->imm.size = 9; + insn->imm.sign = 1; + if (output_value(&insn->imm, *bufp, 2, buf_off, bc, 1, d)) + return 1; + break; + case LC3B_IMM_9: + insn->imm.size = 9; + if (output_value(&insn->imm, *bufp, 2, buf_off, bc, 1, d)) + return 1; + break; + default: + yasm_internal_error(N_("Unrecognized immediate type")); + } + + *bufp += 2; /* all instructions are 2 bytes in size */ + return 0; +} + +int +yasm_lc3b__intnum_tobytes(yasm_arch *arch, const yasm_intnum *intn, + unsigned char *buf, size_t destsize, size_t valsize, + int shift, const yasm_bytecode *bc, int warn) +{ + /* Write value out. */ + yasm_intnum_get_sized(intn, buf, destsize, valsize, shift, 0, warn); + return 0; +} diff --git a/contrib/tools/yasm/modules/arch/x86/x86arch.c b/contrib/tools/yasm/modules/arch/x86/x86arch.c index bac11774ea..c48eeba388 100644 --- a/contrib/tools/yasm/modules/arch/x86/x86arch.c +++ b/contrib/tools/yasm/modules/arch/x86/x86arch.c @@ -1,633 +1,633 @@ -/* - * x86 architecture description - * - * Copyright (C) 2002-2007 Peter Johnson - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ -#include <util.h> - -#include <libyasm.h> - -#include "x86arch.h" - - -yasm_arch_module yasm_x86_LTX_arch; - - -static /*@only@*/ yasm_arch * -x86_create(const char *machine, const char *parser, - /*@out@*/ yasm_arch_create_error *error) -{ - yasm_arch_x86 *arch_x86; - unsigned int amd64_machine, address_size; - - *error = YASM_ARCH_CREATE_OK; - - if (yasm__strcasecmp(machine, "x86") == 0) { - amd64_machine = 0; - address_size = 32; - } else if (yasm__strcasecmp(machine, "amd64") == 0) { - amd64_machine = 1; - address_size = 64; - } else if (yasm__strcasecmp(machine, "x32") == 0) { - amd64_machine = 1; - address_size = 32; - } - else { - *error = YASM_ARCH_CREATE_BAD_MACHINE; - return NULL; - } - - arch_x86 = yasm_xmalloc(sizeof(yasm_arch_x86)); - - arch_x86->arch.module = &yasm_x86_LTX_arch; - - /* default to all instructions/features enabled */ - arch_x86->active_cpu = 0; - arch_x86->cpu_enables_size = 1; - arch_x86->cpu_enables = yasm_xmalloc(sizeof(wordptr)); - arch_x86->cpu_enables[0] = BitVector_Create(64, FALSE); - BitVector_Fill(arch_x86->cpu_enables[0]); - - arch_x86->amd64_machine = amd64_machine; - arch_x86->mode_bits = 0; - arch_x86->address_size = address_size; - arch_x86->force_strict = 0; - arch_x86->default_rel = 0; - arch_x86->gas_intel_mode = 0; - arch_x86->nop = X86_NOP_BASIC; - - if (yasm__strcasecmp(parser, "nasm") == 0) - arch_x86->parser = X86_PARSER_NASM; - else if (yasm__strcasecmp(parser, "tasm") == 0) - arch_x86->parser = X86_PARSER_TASM; - else if (yasm__strcasecmp(parser, "gas") == 0 - || yasm__strcasecmp(parser, "gnu") == 0) - arch_x86->parser = X86_PARSER_GAS; - else { - yasm_xfree(arch_x86); - *error = YASM_ARCH_CREATE_BAD_PARSER; - return NULL; - } - - return (yasm_arch *)arch_x86; -} - -static void -x86_destroy(/*@only@*/ yasm_arch *arch) -{ - yasm_arch_x86 *arch_x86 = (yasm_arch_x86 *)arch; - unsigned int i; - for (i=0; i<arch_x86->cpu_enables_size; i++) - BitVector_Destroy(arch_x86->cpu_enables[i]); - yasm_xfree(arch_x86->cpu_enables); - yasm_xfree(arch); -} - -static const char * -x86_get_machine(const yasm_arch *arch) -{ - const yasm_arch_x86 *arch_x86 = (const yasm_arch_x86 *)arch; - if (arch_x86->amd64_machine) { - if (arch_x86->address_size == 32) - return "x32"; - else - return "amd64"; - } else - return "x86"; -} - -static unsigned int -x86_get_address_size(const yasm_arch *arch) -{ - const yasm_arch_x86 *arch_x86 = (const yasm_arch_x86 *)arch; - if (arch_x86->mode_bits != 0) - return arch_x86->mode_bits; - return arch_x86->address_size; -} - -static int -x86_set_var(yasm_arch *arch, const char *var, unsigned long val) -{ - yasm_arch_x86 *arch_x86 = (yasm_arch_x86 *)arch; - if (yasm__strcasecmp(var, "mode_bits") == 0) - arch_x86->mode_bits = (unsigned int)val; - else if (yasm__strcasecmp(var, "force_strict") == 0) - arch_x86->force_strict = (unsigned int)val; - else if (yasm__strcasecmp(var, "default_rel") == 0) { - if (arch_x86->mode_bits != 64) - yasm_warn_set(YASM_WARN_GENERAL, - N_("ignoring default rel in non-64-bit mode")); - else - arch_x86->default_rel = (unsigned int)val; - } else if (yasm__strcasecmp(var, "gas_intel_mode") == 0) { - arch_x86->gas_intel_mode = (unsigned int)val; - } else - return 1; - return 0; -} - -static void -x86_dir_cpu(yasm_object *object, yasm_valparamhead *valparams, - yasm_valparamhead *objext_valparams, unsigned long line) -{ - yasm_arch_x86 *arch_x86 = (yasm_arch_x86 *)object->arch; - - yasm_valparam *vp; - yasm_vps_foreach(vp, valparams) { - /*@null@*/ /*@dependent@*/ const char *s = yasm_vp_string(vp); - if (s) - yasm_x86__parse_cpu(arch_x86, s, strlen(s)); - else if (vp->type == YASM_PARAM_EXPR) { - const yasm_intnum *intcpu; - intcpu = yasm_expr_get_intnum(&vp->param.e, 0); - if (!intcpu) - yasm_error_set(YASM_ERROR_SYNTAX, - N_("invalid argument to [%s]"), "CPU"); - else { - char strcpu[16]; - sprintf(strcpu, "%lu", yasm_intnum_get_uint(intcpu)); - yasm_x86__parse_cpu(arch_x86, strcpu, strlen(strcpu)); - } - } else - yasm_error_set(YASM_ERROR_SYNTAX, N_("invalid argument to [%s]"), - "CPU"); - } -} - -static void -x86_dir_bits(yasm_object *object, yasm_valparamhead *valparams, - yasm_valparamhead *objext_valparams, unsigned long line) -{ - yasm_arch_x86 *arch_x86 = (yasm_arch_x86 *)object->arch; - yasm_valparam *vp; - /*@only@*/ /*@null@*/ yasm_expr *e = NULL; - const yasm_intnum *intn; - long lval; - - if ((vp = yasm_vps_first(valparams)) && !vp->val && - (e = yasm_vp_expr(vp, object->symtab, line)) != NULL && - (intn = yasm_expr_get_intnum(&e, 0)) != NULL && - (lval = yasm_intnum_get_int(intn)) && - (lval == 16 || lval == 32 || lval == 64)) - arch_x86->mode_bits = (unsigned char)lval; - else - yasm_error_set(YASM_ERROR_VALUE, N_("invalid argument to [%s]"), - "BITS"); - if (e) - yasm_expr_destroy(e); -} - -static void -x86_dir_code16(yasm_object *object, yasm_valparamhead *valparams, - yasm_valparamhead *objext_valparams, unsigned long line) -{ - yasm_arch_x86 *arch_x86 = (yasm_arch_x86 *)object->arch; - arch_x86->mode_bits = 16; -} - -static void -x86_dir_code32(yasm_object *object, yasm_valparamhead *valparams, - yasm_valparamhead *objext_valparams, unsigned long line) -{ - yasm_arch_x86 *arch_x86 = (yasm_arch_x86 *)object->arch; - arch_x86->mode_bits = 32; -} - -static void -x86_dir_code64(yasm_object *object, yasm_valparamhead *valparams, - yasm_valparamhead *objext_valparams, unsigned long line) -{ - yasm_arch_x86 *arch_x86 = (yasm_arch_x86 *)object->arch; - arch_x86->mode_bits = 64; -} - -static const unsigned char ** -x86_get_fill(const yasm_arch *arch) -{ - const yasm_arch_x86 *arch_x86 = (const yasm_arch_x86 *)arch; - - /* Fill patterns that GAS uses. */ - static const unsigned char fill16_1[1] = - {0x90}; /* 1 - nop */ - static const unsigned char fill16_2[2] = - {0x89, 0xf6}; /* 2 - mov si, si */ - static const unsigned char fill16_3[3] = - {0x8d, 0x74, 0x00}; /* 3 - lea si, [si+byte 0] */ - static const unsigned char fill16_4[4] = - {0x8d, 0xb4, 0x00, 0x00}; /* 4 - lea si, [si+word 0] */ - static const unsigned char fill16_5[5] = - {0x90, /* 5 - nop */ - 0x8d, 0xb4, 0x00, 0x00}; /* lea si, [si+word 0] */ - static const unsigned char fill16_6[6] = - {0x89, 0xf6, /* 6 - mov si, si */ - 0x8d, 0xbd, 0x00, 0x00}; /* lea di, [di+word 0] */ - static const unsigned char fill16_7[7] = - {0x8d, 0x74, 0x00, /* 7 - lea si, [si+byte 0] */ - 0x8d, 0xbd, 0x00, 0x00}; /* lea di, [di+word 0] */ - static const unsigned char fill16_8[8] = - {0x8d, 0xb4, 0x00, 0x00, /* 8 - lea si, [si+word 0] */ - 0x8d, 0xbd, 0x00, 0x00}; /* lea di, [di+word 0] */ - static const unsigned char fill16_9[9] = - {0xeb, 0x07, 0x90, 0x90, 0x90, 0x90, /* 9 - jmp $+9; nop fill */ - 0x90, 0x90, 0x90}; - static const unsigned char fill16_10[10] = - {0xeb, 0x08, 0x90, 0x90, 0x90, 0x90, /* 10 - jmp $+10; nop fill */ - 0x90, 0x90, 0x90, 0x90}; - static const unsigned char fill16_11[11] = - {0xeb, 0x09, 0x90, 0x90, 0x90, 0x90, /* 11 - jmp $+11; nop fill */ - 0x90, 0x90, 0x90, 0x90, 0x90}; - static const unsigned char fill16_12[12] = - {0xeb, 0x0a, 0x90, 0x90, 0x90, 0x90, /* 12 - jmp $+12; nop fill */ - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90}; - static const unsigned char fill16_13[13] = - {0xeb, 0x0b, 0x90, 0x90, 0x90, 0x90, /* 13 - jmp $+13; nop fill */ - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90}; - static const unsigned char fill16_14[14] = - {0xeb, 0x0c, 0x90, 0x90, 0x90, 0x90, /* 14 - jmp $+14; nop fill */ - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90}; - static const unsigned char fill16_15[15] = - {0xeb, 0x0d, 0x90, 0x90, 0x90, 0x90, /* 15 - jmp $+15; nop fill */ - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90}; - static const unsigned char *fill16[16] = - { - NULL, fill16_1, fill16_2, fill16_3, - fill16_4, fill16_5, fill16_6, fill16_7, - fill16_8, fill16_9, fill16_10, fill16_11, - fill16_12, fill16_13, fill16_14, fill16_15 - }; - - static const unsigned char fill32_1[1] = - {0x90}; /* 1 - nop */ - static const unsigned char fill32_2[2] = - {0x66, 0x90}; /* 2 - xchg ax, ax (o16 nop) */ - static const unsigned char fill32_3[3] = - {0x8d, 0x76, 0x00}; /* 3 - lea esi, [esi+byte 0] */ - static const unsigned char fill32_4[4] = - {0x8d, 0x74, 0x26, 0x00}; /* 4 - lea esi, [esi*1+byte 0] */ - static const unsigned char fill32_5[5] = - {0x90, /* 5 - nop */ - 0x8d, 0x74, 0x26, 0x00}; /* lea esi, [esi*1+byte 0] */ - static const unsigned char fill32_6[6] = - {0x8d, 0xb6, 0x00, 0x00, 0x00, 0x00};/* 6 - lea esi, [esi+dword 0] */ - static const unsigned char fill32_7[7] = - {0x8d, 0xb4, 0x26, 0x00, 0x00, 0x00, /* 7 - lea esi, [esi*1+dword 0] */ - 0x00}; - static const unsigned char fill32_8[8] = - {0x90, /* 8 - nop */ - 0x8d, 0xb4, 0x26, 0x00, 0x00, 0x00, /* lea esi, [esi*1+dword 0] */ - 0x00}; -#if 0 - /* GAS uses these */ - static const unsigned char fill32_9[9] = - {0x89, 0xf6, /* 9 - mov esi, esi */ - 0x8d, 0xbc, 0x27, 0x00, 0x00, 0x00, /* lea edi, [edi*1+dword 0] */ - 0x00}; - static const unsigned char fill32_10[10] = - {0x8d, 0x76, 0x00, /* 10 - lea esi, [esi+byte 0] */ - 0x8d, 0xbc, 0x27, 0x00, 0x00, 0x00, /* lea edi, [edi+dword 0] */ - 0x00}; - static const unsigned char fill32_11[11] = - {0x8d, 0x74, 0x26, 0x00, /* 11 - lea esi, [esi*1+byte 0] */ - 0x8d, 0xbc, 0x27, 0x00, 0x00, 0x00, /* lea edi, [edi*1+dword 0] */ - 0x00}; - static const unsigned char fill32_12[12] = - {0x8d, 0xb6, 0x00, 0x00, 0x00, 0x00, /* 12 - lea esi, [esi+dword 0] */ - 0x8d, 0xbf, 0x00, 0x00, 0x00, 0x00};/* lea edi, [edi+dword 0] */ - static const unsigned char fill32_13[13] = - {0x8d, 0xb6, 0x00, 0x00, 0x00, 0x00, /* 13 - lea esi, [esi+dword 0] */ - 0x8d, 0xbc, 0x27, 0x00, 0x00, 0x00, /* lea edi, [edi*1+dword 0] */ - 0x00}; - static const unsigned char fill32_14[14] = - {0x8d, 0xb4, 0x26, 0x00, 0x00, 0x00, /* 14 - lea esi, [esi*1+dword 0] */ - 0x00, - 0x8d, 0xbc, 0x27, 0x00, 0x00, 0x00, /* lea edi, [edi*1+dword 0] */ - 0x00}; -#else - /* But on newer processors, these are recommended */ - static const unsigned char fill32_9[9] = - {0xeb, 0x07, 0x90, 0x90, 0x90, 0x90, /* 9 - jmp $+9; nop fill */ - 0x90, 0x90, 0x90}; - static const unsigned char fill32_10[10] = - {0xeb, 0x08, 0x90, 0x90, 0x90, 0x90, /* 10 - jmp $+10; nop fill */ - 0x90, 0x90, 0x90, 0x90}; - static const unsigned char fill32_11[11] = - {0xeb, 0x09, 0x90, 0x90, 0x90, 0x90, /* 11 - jmp $+11; nop fill */ - 0x90, 0x90, 0x90, 0x90, 0x90}; - static const unsigned char fill32_12[12] = - {0xeb, 0x0a, 0x90, 0x90, 0x90, 0x90, /* 12 - jmp $+12; nop fill */ - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90}; - static const unsigned char fill32_13[13] = - {0xeb, 0x0b, 0x90, 0x90, 0x90, 0x90, /* 13 - jmp $+13; nop fill */ - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90}; - static const unsigned char fill32_14[14] = - {0xeb, 0x0c, 0x90, 0x90, 0x90, 0x90, /* 14 - jmp $+14; nop fill */ - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90}; -#endif - static const unsigned char fill32_15[15] = - {0xeb, 0x0d, 0x90, 0x90, 0x90, 0x90, /* 15 - jmp $+15; nop fill */ - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90}; - static const unsigned char *fill32[16] = - { - NULL, fill32_1, fill32_2, fill32_3, - fill32_4, fill32_5, fill32_6, fill32_7, - fill32_8, fill32_9, fill32_10, fill32_11, - fill32_12, fill32_13, fill32_14, fill32_15 - }; - - /* Long form nops available on more recent Intel and AMD processors */ - static const unsigned char fill32new_3[3] = - {0x0f, 0x1f, 0x00}; /* 3 - nop(3) */ - static const unsigned char fill32new_4[4] = - {0x0f, 0x1f, 0x40, 0x00}; /* 4 - nop(4) */ - static const unsigned char fill32new_5[5] = - {0x0f, 0x1f, 0x44, 0x00, 0x00}; /* 5 - nop(5) */ - static const unsigned char fill32new_6[6] = - {0x66, 0x0f, 0x1f, 0x44, 0x00, 0x00}; /* 6 - nop(6) */ - static const unsigned char fill32new_7[7] = - {0x0f, 0x1f, 0x80, 0x00, 0x00, 0x00, 0x00}; /* 7 - nop(7) */ - static const unsigned char fill32new_8[8] = - {0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, /* 8 - nop(8) */ - 0x00}; - static const unsigned char fill32new_9[9] = - {0x66, 0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, /* 9 - nop(9) */ - 0x00, 0x00}; - - /* Longer forms preferred by Intel use repeated o16 prefixes */ - static const unsigned char fill32intel_10[10] = - {0x66, 0x2e, 0x0f, 0x1f, 0x84, 0x00, 0x00, /* 10 - o16; cs; nop */ - 0x00, 0x00, 0x00}; - static const unsigned char fill32intel_11[11] = - {0x66, 0x66, 0x2e, 0x0f, 0x1f, 0x84, 0x00, /* 11 - 2x o16; cs; nop */ - 0x00, 0x00, 0x00, 0x00}; - static const unsigned char fill32intel_12[12] = - {0x66, 0x66, 0x66, 0x2e, 0x0f, 0x1f, 0x84, /* 12 - 3x o16; cs; nop */ - 0x00, 0x00, 0x00, 0x00, 0x00}; - static const unsigned char fill32intel_13[13] = - {0x66, 0x66, 0x66, 0x66, 0x2e, 0x0f, 0x1f, /* 13 - 4x o16; cs; nop */ - 0x84, 0x00, 0x00, 0x00, 0x00, 0x00}; - static const unsigned char fill32intel_14[14] = - {0x66, 0x66, 0x66, 0x66, 0x66, 0x2e, 0x0f, /* 14 - 5x o16; cs; nop */ - 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00}; - static const unsigned char fill32intel_15[15] = - {0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x2e, /* 15 - 6x o16; cs; nop */ - 0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00}; - - /* Longer forms preferred by AMD use fewer o16 prefixes and no CS prefix; - * Source: Software Optimisation Guide for AMD Family 10h - * Processors 40546 revision 3.10 February 2009 - */ - static const unsigned char fill32amd_10[10] = - {0x66, 0x66, 0x0f, 0x1f, 0x84, 0x00, 0x00, /* 10 - nop(10) */ - 0x00, 0x00, 0x00}; - static const unsigned char fill32amd_11[11] = - {0x0f, 0x1f, 0x44, 0x00, 0x00, /* 11 - nop(5) */ - 0x66, 0x0f, 0x1f, 0x44, 0x00, 0x00}; /* nop(6) */ - static const unsigned char fill32amd_12[12] = - {0x66, 0x0f, 0x1f, 0x44, 0x00, 0x00, /* 12 - nop(6) */ - 0x66, 0x0f, 0x1f, 0x44, 0x00, 0x00}; /* nop(6) */ - static const unsigned char fill32amd_13[13] = - {0x66, 0x0f, 0x1f, 0x44, 0x00, 0x00, /* 13 - nop(6) */ - 0x0f, 0x1f, 0x80, 0x00, 0x00, 0x00, 0x00}; /* nop(7) */ - static const unsigned char fill32amd_14[14] = - {0x0f, 0x1f, 0x80, 0x00, 0x00, 0x00, 0x00, /* 14 - nop(7) */ - 0x0f, 0x1f, 0x80, 0x00, 0x00, 0x00, 0x00}; /* nop(7) */ - static const unsigned char fill32amd_15[15] = - {0x0f, 0x1f, 0x80, 0x00, 0x00, 0x00, 0x00, /* 15 - nop(7) */ - 0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00}; /* nop(8) */ - - static const unsigned char *fill32_intel[16] = - { - NULL, fill32_1, fill32_2, fill32new_3, - fill32new_4, fill32new_5, fill32new_6, fill32new_7, - fill32new_8, fill32new_9, fill32intel_10, fill32intel_11, - fill32intel_12, fill32intel_13, fill32intel_14, fill32intel_15 - }; - static const unsigned char *fill32_amd[16] = - { - NULL, fill32_1, fill32_2, fill32new_3, - fill32new_4, fill32new_5, fill32new_6, fill32new_7, - fill32new_8, fill32new_9, fill32amd_10, fill32amd_11, - fill32amd_12, fill32amd_13, fill32amd_14, fill32amd_15 - }; - - switch (arch_x86->mode_bits) { - case 16: - return fill16; - case 32: - if (arch_x86->nop == X86_NOP_INTEL) - return fill32_intel; - else if (arch_x86->nop == X86_NOP_AMD) - return fill32_amd; - else - return fill32; - case 64: - /* We know long nops are available in 64-bit mode; default to Intel - * ones if unspecified (to match GAS behavior). - */ - if (arch_x86->nop == X86_NOP_AMD) - return fill32_amd; - else - return fill32_intel; - default: - yasm_error_set(YASM_ERROR_VALUE, - N_("Invalid mode_bits in x86_get_fill")); - return NULL; - } -} - -unsigned int -yasm_x86__get_reg_size(uintptr_t reg) -{ - switch ((x86_expritem_reg_size)(reg & ~0xFUL)) { - case X86_REG8: - case X86_REG8X: - return 8; - case X86_REG16: - return 16; - case X86_REG32: - case X86_CRREG: - case X86_DRREG: - case X86_TRREG: - return 32; - case X86_REG64: - case X86_MMXREG: - return 64; - case X86_XMMREG: - return 128; - case X86_YMMREG: - return 256; - case X86_FPUREG: - return 80; - default: - yasm_error_set(YASM_ERROR_VALUE, N_("unknown register size")); - } - return 0; -} - -static unsigned int -x86_get_reg_size(yasm_arch *arch, uintptr_t reg) -{ - return yasm_x86__get_reg_size(reg); -} - -static uintptr_t -x86_reggroup_get_reg(yasm_arch *arch, uintptr_t reggroup, - unsigned long regindex) -{ - yasm_arch_x86 *arch_x86 = (yasm_arch_x86 *)arch; - switch ((x86_expritem_reg_size)(reggroup & ~0xFUL)) { - case X86_XMMREG: - case X86_YMMREG: - if (arch_x86->mode_bits == 64) { - if (regindex > 15) - return 0; - return reggroup | (regindex & 15); - } - /*@fallthrough@*/ - case X86_MMXREG: - case X86_FPUREG: - if (regindex > 7) - return 0; - return reggroup | (regindex & 7); - default: - yasm_error_set(YASM_ERROR_VALUE, N_("bad register group")); - } - return 0; -} - -static void -x86_reg_print(yasm_arch *arch, uintptr_t reg, FILE *f) -{ - static const char *name8[] = {"al","cl","dl","bl","ah","ch","dh","bh"}; - static const char *name8x[] = { - "al", "cl", "dl", "bl", "spl", "bpl", "sil", "dil", - "r8b", "r9b", "r10b", "r11b", "r12b", "r13b", "r14b", "r15b" - }; - static const char *name16[] = { - "ax", "cx", "dx", "bx", "sp", "bp", "si", "di", - "r8w", "r9w", "r10w", "r11w", "r12w", "r13w", "r14w", "r15w" - }; - static const char *name32[] = { - "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi", - "r8d", "r9d", "r10d", "r11d", "r12d", "r13d", "r14d", "r15d" - }; - static const char *name64[] = { - "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi", - "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15" - }; - - switch ((x86_expritem_reg_size)(reg & ~0xFUL)) { - case X86_REG8: - fprintf(f, "%s", name8[reg&0xF]); - break; - case X86_REG8X: - fprintf(f, "%s", name8x[reg&0xF]); - break; - case X86_REG16: - fprintf(f, "%s", name16[reg&0xF]); - break; - case X86_REG32: - fprintf(f, "%s", name32[reg&0xF]); - break; - case X86_REG64: - fprintf(f, "%s", name64[reg&0xF]); - break; - case X86_MMXREG: - fprintf(f, "mm%d", (int)(reg&0xF)); - break; - case X86_XMMREG: - fprintf(f, "xmm%d", (int)(reg&0xF)); - break; - case X86_YMMREG: - fprintf(f, "ymm%d", (int)(reg&0xF)); - break; - case X86_CRREG: - fprintf(f, "cr%d", (int)(reg&0xF)); - break; - case X86_DRREG: - fprintf(f, "dr%d", (int)(reg&0xF)); - break; - case X86_TRREG: - fprintf(f, "tr%d", (int)(reg&0xF)); - break; - case X86_FPUREG: - fprintf(f, "st%d", (int)(reg&0xF)); - break; - default: - yasm_error_set(YASM_ERROR_VALUE, N_("unknown register size")); - } -} - -static void -x86_segreg_print(yasm_arch *arch, uintptr_t segreg, FILE *f) -{ - static const char *name[] = {"es","cs","ss","ds","fs","gs"}; - fprintf(f, "%s", name[segreg&7]); -} - -/* Define x86 machines -- see arch.h for details */ -static const yasm_arch_machine x86_machines[] = { - { "IA-32 and derivatives", "x86" }, - { "AMD64", "amd64" }, - { "X32", "x32" }, - { NULL, NULL } -}; - -static const yasm_directive x86_directives[] = { - { "cpu", "nasm", x86_dir_cpu, YASM_DIR_ARG_REQUIRED }, - { "bits", "nasm", x86_dir_bits, YASM_DIR_ARG_REQUIRED }, - { ".code16", "gas", x86_dir_code16, YASM_DIR_ANY }, - { ".code32", "gas", x86_dir_code32, YASM_DIR_ANY }, - { ".code64", "gas", x86_dir_code64, YASM_DIR_ANY }, - { NULL, NULL, NULL, 0 } -}; - -/* Define arch structure -- see arch.h for details */ -yasm_arch_module yasm_x86_LTX_arch = { - "x86 (IA-32 and derivatives), AMD64", - "x86", - x86_directives, - x86_create, - x86_destroy, - x86_get_machine, - x86_get_address_size, - x86_set_var, - yasm_x86__parse_check_insnprefix, - yasm_x86__parse_check_regtmod, - x86_get_fill, - yasm_x86__floatnum_tobytes, - yasm_x86__intnum_tobytes, - x86_get_reg_size, - x86_reggroup_get_reg, - x86_reg_print, - x86_segreg_print, - yasm_x86__ea_create_expr, - yasm_x86__ea_destroy, - yasm_x86__ea_print, - yasm_x86__create_empty_insn, - x86_machines, - "x86", - 16, - 1 -}; +/* + * x86 architecture description + * + * Copyright (C) 2002-2007 Peter Johnson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include <util.h> + +#include <libyasm.h> + +#include "x86arch.h" + + +yasm_arch_module yasm_x86_LTX_arch; + + +static /*@only@*/ yasm_arch * +x86_create(const char *machine, const char *parser, + /*@out@*/ yasm_arch_create_error *error) +{ + yasm_arch_x86 *arch_x86; + unsigned int amd64_machine, address_size; + + *error = YASM_ARCH_CREATE_OK; + + if (yasm__strcasecmp(machine, "x86") == 0) { + amd64_machine = 0; + address_size = 32; + } else if (yasm__strcasecmp(machine, "amd64") == 0) { + amd64_machine = 1; + address_size = 64; + } else if (yasm__strcasecmp(machine, "x32") == 0) { + amd64_machine = 1; + address_size = 32; + } + else { + *error = YASM_ARCH_CREATE_BAD_MACHINE; + return NULL; + } + + arch_x86 = yasm_xmalloc(sizeof(yasm_arch_x86)); + + arch_x86->arch.module = &yasm_x86_LTX_arch; + + /* default to all instructions/features enabled */ + arch_x86->active_cpu = 0; + arch_x86->cpu_enables_size = 1; + arch_x86->cpu_enables = yasm_xmalloc(sizeof(wordptr)); + arch_x86->cpu_enables[0] = BitVector_Create(64, FALSE); + BitVector_Fill(arch_x86->cpu_enables[0]); + + arch_x86->amd64_machine = amd64_machine; + arch_x86->mode_bits = 0; + arch_x86->address_size = address_size; + arch_x86->force_strict = 0; + arch_x86->default_rel = 0; + arch_x86->gas_intel_mode = 0; + arch_x86->nop = X86_NOP_BASIC; + + if (yasm__strcasecmp(parser, "nasm") == 0) + arch_x86->parser = X86_PARSER_NASM; + else if (yasm__strcasecmp(parser, "tasm") == 0) + arch_x86->parser = X86_PARSER_TASM; + else if (yasm__strcasecmp(parser, "gas") == 0 + || yasm__strcasecmp(parser, "gnu") == 0) + arch_x86->parser = X86_PARSER_GAS; + else { + yasm_xfree(arch_x86); + *error = YASM_ARCH_CREATE_BAD_PARSER; + return NULL; + } + + return (yasm_arch *)arch_x86; +} + +static void +x86_destroy(/*@only@*/ yasm_arch *arch) +{ + yasm_arch_x86 *arch_x86 = (yasm_arch_x86 *)arch; + unsigned int i; + for (i=0; i<arch_x86->cpu_enables_size; i++) + BitVector_Destroy(arch_x86->cpu_enables[i]); + yasm_xfree(arch_x86->cpu_enables); + yasm_xfree(arch); +} + +static const char * +x86_get_machine(const yasm_arch *arch) +{ + const yasm_arch_x86 *arch_x86 = (const yasm_arch_x86 *)arch; + if (arch_x86->amd64_machine) { + if (arch_x86->address_size == 32) + return "x32"; + else + return "amd64"; + } else + return "x86"; +} + +static unsigned int +x86_get_address_size(const yasm_arch *arch) +{ + const yasm_arch_x86 *arch_x86 = (const yasm_arch_x86 *)arch; + if (arch_x86->mode_bits != 0) + return arch_x86->mode_bits; + return arch_x86->address_size; +} + +static int +x86_set_var(yasm_arch *arch, const char *var, unsigned long val) +{ + yasm_arch_x86 *arch_x86 = (yasm_arch_x86 *)arch; + if (yasm__strcasecmp(var, "mode_bits") == 0) + arch_x86->mode_bits = (unsigned int)val; + else if (yasm__strcasecmp(var, "force_strict") == 0) + arch_x86->force_strict = (unsigned int)val; + else if (yasm__strcasecmp(var, "default_rel") == 0) { + if (arch_x86->mode_bits != 64) + yasm_warn_set(YASM_WARN_GENERAL, + N_("ignoring default rel in non-64-bit mode")); + else + arch_x86->default_rel = (unsigned int)val; + } else if (yasm__strcasecmp(var, "gas_intel_mode") == 0) { + arch_x86->gas_intel_mode = (unsigned int)val; + } else + return 1; + return 0; +} + +static void +x86_dir_cpu(yasm_object *object, yasm_valparamhead *valparams, + yasm_valparamhead *objext_valparams, unsigned long line) +{ + yasm_arch_x86 *arch_x86 = (yasm_arch_x86 *)object->arch; + + yasm_valparam *vp; + yasm_vps_foreach(vp, valparams) { + /*@null@*/ /*@dependent@*/ const char *s = yasm_vp_string(vp); + if (s) + yasm_x86__parse_cpu(arch_x86, s, strlen(s)); + else if (vp->type == YASM_PARAM_EXPR) { + const yasm_intnum *intcpu; + intcpu = yasm_expr_get_intnum(&vp->param.e, 0); + if (!intcpu) + yasm_error_set(YASM_ERROR_SYNTAX, + N_("invalid argument to [%s]"), "CPU"); + else { + char strcpu[16]; + sprintf(strcpu, "%lu", yasm_intnum_get_uint(intcpu)); + yasm_x86__parse_cpu(arch_x86, strcpu, strlen(strcpu)); + } + } else + yasm_error_set(YASM_ERROR_SYNTAX, N_("invalid argument to [%s]"), + "CPU"); + } +} + +static void +x86_dir_bits(yasm_object *object, yasm_valparamhead *valparams, + yasm_valparamhead *objext_valparams, unsigned long line) +{ + yasm_arch_x86 *arch_x86 = (yasm_arch_x86 *)object->arch; + yasm_valparam *vp; + /*@only@*/ /*@null@*/ yasm_expr *e = NULL; + const yasm_intnum *intn; + long lval; + + if ((vp = yasm_vps_first(valparams)) && !vp->val && + (e = yasm_vp_expr(vp, object->symtab, line)) != NULL && + (intn = yasm_expr_get_intnum(&e, 0)) != NULL && + (lval = yasm_intnum_get_int(intn)) && + (lval == 16 || lval == 32 || lval == 64)) + arch_x86->mode_bits = (unsigned char)lval; + else + yasm_error_set(YASM_ERROR_VALUE, N_("invalid argument to [%s]"), + "BITS"); + if (e) + yasm_expr_destroy(e); +} + +static void +x86_dir_code16(yasm_object *object, yasm_valparamhead *valparams, + yasm_valparamhead *objext_valparams, unsigned long line) +{ + yasm_arch_x86 *arch_x86 = (yasm_arch_x86 *)object->arch; + arch_x86->mode_bits = 16; +} + +static void +x86_dir_code32(yasm_object *object, yasm_valparamhead *valparams, + yasm_valparamhead *objext_valparams, unsigned long line) +{ + yasm_arch_x86 *arch_x86 = (yasm_arch_x86 *)object->arch; + arch_x86->mode_bits = 32; +} + +static void +x86_dir_code64(yasm_object *object, yasm_valparamhead *valparams, + yasm_valparamhead *objext_valparams, unsigned long line) +{ + yasm_arch_x86 *arch_x86 = (yasm_arch_x86 *)object->arch; + arch_x86->mode_bits = 64; +} + +static const unsigned char ** +x86_get_fill(const yasm_arch *arch) +{ + const yasm_arch_x86 *arch_x86 = (const yasm_arch_x86 *)arch; + + /* Fill patterns that GAS uses. */ + static const unsigned char fill16_1[1] = + {0x90}; /* 1 - nop */ + static const unsigned char fill16_2[2] = + {0x89, 0xf6}; /* 2 - mov si, si */ + static const unsigned char fill16_3[3] = + {0x8d, 0x74, 0x00}; /* 3 - lea si, [si+byte 0] */ + static const unsigned char fill16_4[4] = + {0x8d, 0xb4, 0x00, 0x00}; /* 4 - lea si, [si+word 0] */ + static const unsigned char fill16_5[5] = + {0x90, /* 5 - nop */ + 0x8d, 0xb4, 0x00, 0x00}; /* lea si, [si+word 0] */ + static const unsigned char fill16_6[6] = + {0x89, 0xf6, /* 6 - mov si, si */ + 0x8d, 0xbd, 0x00, 0x00}; /* lea di, [di+word 0] */ + static const unsigned char fill16_7[7] = + {0x8d, 0x74, 0x00, /* 7 - lea si, [si+byte 0] */ + 0x8d, 0xbd, 0x00, 0x00}; /* lea di, [di+word 0] */ + static const unsigned char fill16_8[8] = + {0x8d, 0xb4, 0x00, 0x00, /* 8 - lea si, [si+word 0] */ + 0x8d, 0xbd, 0x00, 0x00}; /* lea di, [di+word 0] */ + static const unsigned char fill16_9[9] = + {0xeb, 0x07, 0x90, 0x90, 0x90, 0x90, /* 9 - jmp $+9; nop fill */ + 0x90, 0x90, 0x90}; + static const unsigned char fill16_10[10] = + {0xeb, 0x08, 0x90, 0x90, 0x90, 0x90, /* 10 - jmp $+10; nop fill */ + 0x90, 0x90, 0x90, 0x90}; + static const unsigned char fill16_11[11] = + {0xeb, 0x09, 0x90, 0x90, 0x90, 0x90, /* 11 - jmp $+11; nop fill */ + 0x90, 0x90, 0x90, 0x90, 0x90}; + static const unsigned char fill16_12[12] = + {0xeb, 0x0a, 0x90, 0x90, 0x90, 0x90, /* 12 - jmp $+12; nop fill */ + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90}; + static const unsigned char fill16_13[13] = + {0xeb, 0x0b, 0x90, 0x90, 0x90, 0x90, /* 13 - jmp $+13; nop fill */ + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90}; + static const unsigned char fill16_14[14] = + {0xeb, 0x0c, 0x90, 0x90, 0x90, 0x90, /* 14 - jmp $+14; nop fill */ + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90}; + static const unsigned char fill16_15[15] = + {0xeb, 0x0d, 0x90, 0x90, 0x90, 0x90, /* 15 - jmp $+15; nop fill */ + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90}; + static const unsigned char *fill16[16] = + { + NULL, fill16_1, fill16_2, fill16_3, + fill16_4, fill16_5, fill16_6, fill16_7, + fill16_8, fill16_9, fill16_10, fill16_11, + fill16_12, fill16_13, fill16_14, fill16_15 + }; + + static const unsigned char fill32_1[1] = + {0x90}; /* 1 - nop */ + static const unsigned char fill32_2[2] = + {0x66, 0x90}; /* 2 - xchg ax, ax (o16 nop) */ + static const unsigned char fill32_3[3] = + {0x8d, 0x76, 0x00}; /* 3 - lea esi, [esi+byte 0] */ + static const unsigned char fill32_4[4] = + {0x8d, 0x74, 0x26, 0x00}; /* 4 - lea esi, [esi*1+byte 0] */ + static const unsigned char fill32_5[5] = + {0x90, /* 5 - nop */ + 0x8d, 0x74, 0x26, 0x00}; /* lea esi, [esi*1+byte 0] */ + static const unsigned char fill32_6[6] = + {0x8d, 0xb6, 0x00, 0x00, 0x00, 0x00};/* 6 - lea esi, [esi+dword 0] */ + static const unsigned char fill32_7[7] = + {0x8d, 0xb4, 0x26, 0x00, 0x00, 0x00, /* 7 - lea esi, [esi*1+dword 0] */ + 0x00}; + static const unsigned char fill32_8[8] = + {0x90, /* 8 - nop */ + 0x8d, 0xb4, 0x26, 0x00, 0x00, 0x00, /* lea esi, [esi*1+dword 0] */ + 0x00}; +#if 0 + /* GAS uses these */ + static const unsigned char fill32_9[9] = + {0x89, 0xf6, /* 9 - mov esi, esi */ + 0x8d, 0xbc, 0x27, 0x00, 0x00, 0x00, /* lea edi, [edi*1+dword 0] */ + 0x00}; + static const unsigned char fill32_10[10] = + {0x8d, 0x76, 0x00, /* 10 - lea esi, [esi+byte 0] */ + 0x8d, 0xbc, 0x27, 0x00, 0x00, 0x00, /* lea edi, [edi+dword 0] */ + 0x00}; + static const unsigned char fill32_11[11] = + {0x8d, 0x74, 0x26, 0x00, /* 11 - lea esi, [esi*1+byte 0] */ + 0x8d, 0xbc, 0x27, 0x00, 0x00, 0x00, /* lea edi, [edi*1+dword 0] */ + 0x00}; + static const unsigned char fill32_12[12] = + {0x8d, 0xb6, 0x00, 0x00, 0x00, 0x00, /* 12 - lea esi, [esi+dword 0] */ + 0x8d, 0xbf, 0x00, 0x00, 0x00, 0x00};/* lea edi, [edi+dword 0] */ + static const unsigned char fill32_13[13] = + {0x8d, 0xb6, 0x00, 0x00, 0x00, 0x00, /* 13 - lea esi, [esi+dword 0] */ + 0x8d, 0xbc, 0x27, 0x00, 0x00, 0x00, /* lea edi, [edi*1+dword 0] */ + 0x00}; + static const unsigned char fill32_14[14] = + {0x8d, 0xb4, 0x26, 0x00, 0x00, 0x00, /* 14 - lea esi, [esi*1+dword 0] */ + 0x00, + 0x8d, 0xbc, 0x27, 0x00, 0x00, 0x00, /* lea edi, [edi*1+dword 0] */ + 0x00}; +#else + /* But on newer processors, these are recommended */ + static const unsigned char fill32_9[9] = + {0xeb, 0x07, 0x90, 0x90, 0x90, 0x90, /* 9 - jmp $+9; nop fill */ + 0x90, 0x90, 0x90}; + static const unsigned char fill32_10[10] = + {0xeb, 0x08, 0x90, 0x90, 0x90, 0x90, /* 10 - jmp $+10; nop fill */ + 0x90, 0x90, 0x90, 0x90}; + static const unsigned char fill32_11[11] = + {0xeb, 0x09, 0x90, 0x90, 0x90, 0x90, /* 11 - jmp $+11; nop fill */ + 0x90, 0x90, 0x90, 0x90, 0x90}; + static const unsigned char fill32_12[12] = + {0xeb, 0x0a, 0x90, 0x90, 0x90, 0x90, /* 12 - jmp $+12; nop fill */ + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90}; + static const unsigned char fill32_13[13] = + {0xeb, 0x0b, 0x90, 0x90, 0x90, 0x90, /* 13 - jmp $+13; nop fill */ + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90}; + static const unsigned char fill32_14[14] = + {0xeb, 0x0c, 0x90, 0x90, 0x90, 0x90, /* 14 - jmp $+14; nop fill */ + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90}; +#endif + static const unsigned char fill32_15[15] = + {0xeb, 0x0d, 0x90, 0x90, 0x90, 0x90, /* 15 - jmp $+15; nop fill */ + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90}; + static const unsigned char *fill32[16] = + { + NULL, fill32_1, fill32_2, fill32_3, + fill32_4, fill32_5, fill32_6, fill32_7, + fill32_8, fill32_9, fill32_10, fill32_11, + fill32_12, fill32_13, fill32_14, fill32_15 + }; + + /* Long form nops available on more recent Intel and AMD processors */ + static const unsigned char fill32new_3[3] = + {0x0f, 0x1f, 0x00}; /* 3 - nop(3) */ + static const unsigned char fill32new_4[4] = + {0x0f, 0x1f, 0x40, 0x00}; /* 4 - nop(4) */ + static const unsigned char fill32new_5[5] = + {0x0f, 0x1f, 0x44, 0x00, 0x00}; /* 5 - nop(5) */ + static const unsigned char fill32new_6[6] = + {0x66, 0x0f, 0x1f, 0x44, 0x00, 0x00}; /* 6 - nop(6) */ + static const unsigned char fill32new_7[7] = + {0x0f, 0x1f, 0x80, 0x00, 0x00, 0x00, 0x00}; /* 7 - nop(7) */ + static const unsigned char fill32new_8[8] = + {0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, /* 8 - nop(8) */ + 0x00}; + static const unsigned char fill32new_9[9] = + {0x66, 0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, /* 9 - nop(9) */ + 0x00, 0x00}; + + /* Longer forms preferred by Intel use repeated o16 prefixes */ + static const unsigned char fill32intel_10[10] = + {0x66, 0x2e, 0x0f, 0x1f, 0x84, 0x00, 0x00, /* 10 - o16; cs; nop */ + 0x00, 0x00, 0x00}; + static const unsigned char fill32intel_11[11] = + {0x66, 0x66, 0x2e, 0x0f, 0x1f, 0x84, 0x00, /* 11 - 2x o16; cs; nop */ + 0x00, 0x00, 0x00, 0x00}; + static const unsigned char fill32intel_12[12] = + {0x66, 0x66, 0x66, 0x2e, 0x0f, 0x1f, 0x84, /* 12 - 3x o16; cs; nop */ + 0x00, 0x00, 0x00, 0x00, 0x00}; + static const unsigned char fill32intel_13[13] = + {0x66, 0x66, 0x66, 0x66, 0x2e, 0x0f, 0x1f, /* 13 - 4x o16; cs; nop */ + 0x84, 0x00, 0x00, 0x00, 0x00, 0x00}; + static const unsigned char fill32intel_14[14] = + {0x66, 0x66, 0x66, 0x66, 0x66, 0x2e, 0x0f, /* 14 - 5x o16; cs; nop */ + 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00}; + static const unsigned char fill32intel_15[15] = + {0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x2e, /* 15 - 6x o16; cs; nop */ + 0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00}; + + /* Longer forms preferred by AMD use fewer o16 prefixes and no CS prefix; + * Source: Software Optimisation Guide for AMD Family 10h + * Processors 40546 revision 3.10 February 2009 + */ + static const unsigned char fill32amd_10[10] = + {0x66, 0x66, 0x0f, 0x1f, 0x84, 0x00, 0x00, /* 10 - nop(10) */ + 0x00, 0x00, 0x00}; + static const unsigned char fill32amd_11[11] = + {0x0f, 0x1f, 0x44, 0x00, 0x00, /* 11 - nop(5) */ + 0x66, 0x0f, 0x1f, 0x44, 0x00, 0x00}; /* nop(6) */ + static const unsigned char fill32amd_12[12] = + {0x66, 0x0f, 0x1f, 0x44, 0x00, 0x00, /* 12 - nop(6) */ + 0x66, 0x0f, 0x1f, 0x44, 0x00, 0x00}; /* nop(6) */ + static const unsigned char fill32amd_13[13] = + {0x66, 0x0f, 0x1f, 0x44, 0x00, 0x00, /* 13 - nop(6) */ + 0x0f, 0x1f, 0x80, 0x00, 0x00, 0x00, 0x00}; /* nop(7) */ + static const unsigned char fill32amd_14[14] = + {0x0f, 0x1f, 0x80, 0x00, 0x00, 0x00, 0x00, /* 14 - nop(7) */ + 0x0f, 0x1f, 0x80, 0x00, 0x00, 0x00, 0x00}; /* nop(7) */ + static const unsigned char fill32amd_15[15] = + {0x0f, 0x1f, 0x80, 0x00, 0x00, 0x00, 0x00, /* 15 - nop(7) */ + 0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00}; /* nop(8) */ + + static const unsigned char *fill32_intel[16] = + { + NULL, fill32_1, fill32_2, fill32new_3, + fill32new_4, fill32new_5, fill32new_6, fill32new_7, + fill32new_8, fill32new_9, fill32intel_10, fill32intel_11, + fill32intel_12, fill32intel_13, fill32intel_14, fill32intel_15 + }; + static const unsigned char *fill32_amd[16] = + { + NULL, fill32_1, fill32_2, fill32new_3, + fill32new_4, fill32new_5, fill32new_6, fill32new_7, + fill32new_8, fill32new_9, fill32amd_10, fill32amd_11, + fill32amd_12, fill32amd_13, fill32amd_14, fill32amd_15 + }; + + switch (arch_x86->mode_bits) { + case 16: + return fill16; + case 32: + if (arch_x86->nop == X86_NOP_INTEL) + return fill32_intel; + else if (arch_x86->nop == X86_NOP_AMD) + return fill32_amd; + else + return fill32; + case 64: + /* We know long nops are available in 64-bit mode; default to Intel + * ones if unspecified (to match GAS behavior). + */ + if (arch_x86->nop == X86_NOP_AMD) + return fill32_amd; + else + return fill32_intel; + default: + yasm_error_set(YASM_ERROR_VALUE, + N_("Invalid mode_bits in x86_get_fill")); + return NULL; + } +} + +unsigned int +yasm_x86__get_reg_size(uintptr_t reg) +{ + switch ((x86_expritem_reg_size)(reg & ~0xFUL)) { + case X86_REG8: + case X86_REG8X: + return 8; + case X86_REG16: + return 16; + case X86_REG32: + case X86_CRREG: + case X86_DRREG: + case X86_TRREG: + return 32; + case X86_REG64: + case X86_MMXREG: + return 64; + case X86_XMMREG: + return 128; + case X86_YMMREG: + return 256; + case X86_FPUREG: + return 80; + default: + yasm_error_set(YASM_ERROR_VALUE, N_("unknown register size")); + } + return 0; +} + +static unsigned int +x86_get_reg_size(yasm_arch *arch, uintptr_t reg) +{ + return yasm_x86__get_reg_size(reg); +} + +static uintptr_t +x86_reggroup_get_reg(yasm_arch *arch, uintptr_t reggroup, + unsigned long regindex) +{ + yasm_arch_x86 *arch_x86 = (yasm_arch_x86 *)arch; + switch ((x86_expritem_reg_size)(reggroup & ~0xFUL)) { + case X86_XMMREG: + case X86_YMMREG: + if (arch_x86->mode_bits == 64) { + if (regindex > 15) + return 0; + return reggroup | (regindex & 15); + } + /*@fallthrough@*/ + case X86_MMXREG: + case X86_FPUREG: + if (regindex > 7) + return 0; + return reggroup | (regindex & 7); + default: + yasm_error_set(YASM_ERROR_VALUE, N_("bad register group")); + } + return 0; +} + +static void +x86_reg_print(yasm_arch *arch, uintptr_t reg, FILE *f) +{ + static const char *name8[] = {"al","cl","dl","bl","ah","ch","dh","bh"}; + static const char *name8x[] = { + "al", "cl", "dl", "bl", "spl", "bpl", "sil", "dil", + "r8b", "r9b", "r10b", "r11b", "r12b", "r13b", "r14b", "r15b" + }; + static const char *name16[] = { + "ax", "cx", "dx", "bx", "sp", "bp", "si", "di", + "r8w", "r9w", "r10w", "r11w", "r12w", "r13w", "r14w", "r15w" + }; + static const char *name32[] = { + "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi", + "r8d", "r9d", "r10d", "r11d", "r12d", "r13d", "r14d", "r15d" + }; + static const char *name64[] = { + "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15" + }; + + switch ((x86_expritem_reg_size)(reg & ~0xFUL)) { + case X86_REG8: + fprintf(f, "%s", name8[reg&0xF]); + break; + case X86_REG8X: + fprintf(f, "%s", name8x[reg&0xF]); + break; + case X86_REG16: + fprintf(f, "%s", name16[reg&0xF]); + break; + case X86_REG32: + fprintf(f, "%s", name32[reg&0xF]); + break; + case X86_REG64: + fprintf(f, "%s", name64[reg&0xF]); + break; + case X86_MMXREG: + fprintf(f, "mm%d", (int)(reg&0xF)); + break; + case X86_XMMREG: + fprintf(f, "xmm%d", (int)(reg&0xF)); + break; + case X86_YMMREG: + fprintf(f, "ymm%d", (int)(reg&0xF)); + break; + case X86_CRREG: + fprintf(f, "cr%d", (int)(reg&0xF)); + break; + case X86_DRREG: + fprintf(f, "dr%d", (int)(reg&0xF)); + break; + case X86_TRREG: + fprintf(f, "tr%d", (int)(reg&0xF)); + break; + case X86_FPUREG: + fprintf(f, "st%d", (int)(reg&0xF)); + break; + default: + yasm_error_set(YASM_ERROR_VALUE, N_("unknown register size")); + } +} + +static void +x86_segreg_print(yasm_arch *arch, uintptr_t segreg, FILE *f) +{ + static const char *name[] = {"es","cs","ss","ds","fs","gs"}; + fprintf(f, "%s", name[segreg&7]); +} + +/* Define x86 machines -- see arch.h for details */ +static const yasm_arch_machine x86_machines[] = { + { "IA-32 and derivatives", "x86" }, + { "AMD64", "amd64" }, + { "X32", "x32" }, + { NULL, NULL } +}; + +static const yasm_directive x86_directives[] = { + { "cpu", "nasm", x86_dir_cpu, YASM_DIR_ARG_REQUIRED }, + { "bits", "nasm", x86_dir_bits, YASM_DIR_ARG_REQUIRED }, + { ".code16", "gas", x86_dir_code16, YASM_DIR_ANY }, + { ".code32", "gas", x86_dir_code32, YASM_DIR_ANY }, + { ".code64", "gas", x86_dir_code64, YASM_DIR_ANY }, + { NULL, NULL, NULL, 0 } +}; + +/* Define arch structure -- see arch.h for details */ +yasm_arch_module yasm_x86_LTX_arch = { + "x86 (IA-32 and derivatives), AMD64", + "x86", + x86_directives, + x86_create, + x86_destroy, + x86_get_machine, + x86_get_address_size, + x86_set_var, + yasm_x86__parse_check_insnprefix, + yasm_x86__parse_check_regtmod, + x86_get_fill, + yasm_x86__floatnum_tobytes, + yasm_x86__intnum_tobytes, + x86_get_reg_size, + x86_reggroup_get_reg, + x86_reg_print, + x86_segreg_print, + yasm_x86__ea_create_expr, + yasm_x86__ea_destroy, + yasm_x86__ea_print, + yasm_x86__create_empty_insn, + x86_machines, + "x86", + 16, + 1 +}; diff --git a/contrib/tools/yasm/modules/arch/x86/x86arch.h b/contrib/tools/yasm/modules/arch/x86/x86arch.h index 78c3d73920..48ad5ad5e7 100644 --- a/contrib/tools/yasm/modules/arch/x86/x86arch.h +++ b/contrib/tools/yasm/modules/arch/x86/x86arch.h @@ -1,336 +1,336 @@ -/* - * x86 Architecture header file - * - * Copyright (C) 2001-2007 Peter Johnson - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ -#ifndef YASM_X86ARCH_H -#define YASM_X86ARCH_H - -#include <libyasm/bitvect.h> - -/* Available CPU feature flags */ -#define CPU_Any 0 /* Any old cpu will do */ -#define CPU_086 CPU_Any -#define CPU_186 1 /* i186 or better required */ -#define CPU_286 2 /* i286 or better required */ -#define CPU_386 3 /* i386 or better required */ -#define CPU_486 4 /* i486 or better required */ -#define CPU_586 5 /* i585 or better required */ -#define CPU_686 6 /* i686 or better required */ -#define CPU_P3 7 /* Pentium3 or better required */ -#define CPU_P4 8 /* Pentium4 or better required */ -#define CPU_IA64 9 /* IA-64 or better required */ -#define CPU_K6 10 /* AMD K6 or better required */ -#define CPU_Athlon 11 /* AMD Athlon or better required */ -#define CPU_Hammer 12 /* AMD Sledgehammer or better required */ -#define CPU_FPU 13 /* FPU support required */ -#define CPU_MMX 14 /* MMX support required */ -#define CPU_SSE 15 /* Streaming SIMD extensions required */ -#define CPU_SSE2 16 /* Streaming SIMD extensions 2 required */ -#define CPU_SSE3 17 /* Streaming SIMD extensions 3 required */ -#define CPU_3DNow 18 /* 3DNow! support required */ -#define CPU_Cyrix 19 /* Cyrix-specific instruction */ -#define CPU_AMD 20 /* AMD-specific inst. (older than K6) */ -#define CPU_SMM 21 /* System Management Mode instruction */ -#define CPU_Prot 22 /* Protected mode only instruction */ -#define CPU_Undoc 23 /* Undocumented instruction */ -#define CPU_Obs 24 /* Obsolete instruction */ -#define CPU_Priv 25 /* Priveleged instruction */ -#define CPU_SVM 26 /* Secure Virtual Machine instruction */ -#define CPU_PadLock 27 /* VIA PadLock instruction */ -#define CPU_EM64T 28 /* Intel EM64T or better */ -#define CPU_SSSE3 29 /* Streaming SIMD extensions 3 required */ -#define CPU_SSE41 30 /* Streaming SIMD extensions 4.1 required */ -#define CPU_SSE42 31 /* Streaming SIMD extensions 4.2 required */ -#define CPU_SSE4a 32 /* AMD Streaming SIMD extensions 4a required */ -#define CPU_XSAVE 33 /* Intel XSAVE instructions */ -#define CPU_AVX 34 /* Intel Advanced Vector Extensions */ -#define CPU_FMA 35 /* Intel Fused-Multiply-Add Extensions */ -#define CPU_AES 36 /* AES instruction */ -#define CPU_CLMUL 37 /* PCLMULQDQ instruction */ -#define CPU_MOVBE 38 /* MOVBE instruction */ -#define CPU_XOP 39 /* AMD XOP extensions */ -#define CPU_FMA4 40 /* AMD Fused-Multiply-Add extensions */ -#define CPU_F16C 41 /* Intel float-16 instructions */ -#define CPU_FSGSBASE 42 /* Intel FSGSBASE instructions */ -#define CPU_RDRAND 43 /* Intel RDRAND instruction */ -#define CPU_XSAVEOPT 44 /* Intel XSAVEOPT instruction */ -#define CPU_EPTVPID 45 /* Intel INVEPT, INVVPID instructions */ -#define CPU_SMX 46 /* Intel SMX instruction (GETSEC) */ -#define CPU_AVX2 47 /* Intel AVX2 instructions */ -#define CPU_BMI1 48 /* Intel BMI1 instructions */ -#define CPU_BMI2 49 /* Intel BMI2 instructions */ -#define CPU_INVPCID 50 /* Intel INVPCID instruction */ -#define CPU_LZCNT 51 /* Intel LZCNT instruction */ -#define CPU_TBM 52 /* AMD TBM instruction */ -#define CPU_TSX 53 /* Intel TSX instructions */ -#define CPU_SHA 54 /* Intel SHA instructions */ -#define CPU_SMAP 55 /* Intel SMAP instructions */ -#define CPU_RDSEED 56 /* Intel RDSEED instruction */ -#define CPU_ADX 57 /* Intel ADCX and ADOX instructions */ -#define CPU_PRFCHW 58 /* Intel/AMD PREFETCHW instruction */ - -enum x86_parser_type { - X86_PARSER_NASM = 0, - X86_PARSER_TASM = 1, - X86_PARSER_GAS = 2 -}; - -#define PARSER(arch) (((arch)->parser == X86_PARSER_GAS && (arch)->gas_intel_mode) ? X86_PARSER_NASM : (arch)->parser) - -typedef struct yasm_arch_x86 { - yasm_arch_base arch; /* base structure */ - - /* What instructions/features are enabled? */ - unsigned int active_cpu; /* active index into cpu_enables table */ - unsigned int cpu_enables_size; /* size of cpu_enables table */ - wordptr *cpu_enables; - - unsigned int amd64_machine; - enum x86_parser_type parser; - unsigned int mode_bits; - unsigned int address_size; - unsigned int force_strict; - unsigned int default_rel; - unsigned int gas_intel_mode; - - enum { - X86_NOP_BASIC = 0, - X86_NOP_INTEL = 1, - X86_NOP_AMD = 2 - } nop; -} yasm_arch_x86; - -/* 0-15 (low 4 bits) used for register number, stored in same data area. - * Note 8-15 are only valid for some registers, and only in 64-bit mode. - */ -typedef enum { - X86_REG8 = 0x1<<4, - X86_REG8X = 0x2<<4, /* 64-bit mode only, REX prefix version of REG8 */ - X86_REG16 = 0x3<<4, - X86_REG32 = 0x4<<4, - X86_REG64 = 0x5<<4, /* 64-bit mode only */ - X86_FPUREG = 0x6<<4, - X86_MMXREG = 0x7<<4, - X86_XMMREG = 0x8<<4, - X86_YMMREG = 0x9<<4, - X86_CRREG = 0xA<<4, - X86_DRREG = 0xB<<4, - X86_TRREG = 0xC<<4, - X86_RIP = 0xD<<4 /* 64-bit mode only, always RIP (regnum ignored) */ -} x86_expritem_reg_size; - -/* Low 8 bits are used for the prefix value, stored in same data area. */ -typedef enum { - X86_LOCKREP = 1<<8, - X86_ADDRSIZE = 2<<8, - X86_OPERSIZE = 3<<8, - X86_SEGREG = 4<<8, - X86_REX = 5<<8, - X86_ACQREL = 6<<8 /*TSX hint prefixes*/ -} x86_parse_insn_prefix; - -typedef enum { - X86_NEAR = 1, - X86_SHORT, - X86_FAR, - X86_TO -} x86_parse_targetmod; - -typedef enum { - JMP_NONE, - JMP_SHORT, - JMP_NEAR, - JMP_SHORT_FORCED, - JMP_NEAR_FORCED -} x86_jmp_opcode_sel; - -typedef enum { - X86_REX_W = 3, - X86_REX_R = 2, - X86_REX_X = 1, - X86_REX_B = 0 -} x86_rex_bit_pos; - -/* Sets REX (4th bit) and 3 LS bits from register size/number. Returns 1 if - * impossible to fit reg into REX, otherwise returns 0. Input parameter rexbit - * indicates bit of REX to use if REX is needed. Will not modify REX if not - * in 64-bit mode or if it wasn't needed to express reg. - */ -int yasm_x86__set_rex_from_reg(unsigned char *rex, unsigned char *low3, - uintptr_t reg, unsigned int bits, - x86_rex_bit_pos rexbit); - -/* Effective address type */ -typedef struct x86_effaddr { - yasm_effaddr ea; /* base structure */ - - /* VSIB uses the normal SIB byte, but this flag enables it. */ - unsigned char vsib_mode; /* 0 if not, 1 if XMM, 2 if YMM */ - - /* How the spare (register) bits in Mod/RM are handled: - * Even if valid_modrm=0, the spare bits are still valid (don't overwrite!) - * They're set in bytecode_create_insn(). - */ - unsigned char modrm; - unsigned char valid_modrm; /* 1 if Mod/RM byte currently valid, 0 if not */ - unsigned char need_modrm; /* 1 if Mod/RM byte needed, 0 if not */ - - unsigned char sib; - unsigned char valid_sib; /* 1 if SIB byte currently valid, 0 if not */ - unsigned char need_sib; /* 1 if SIB byte needed, 0 if not, - 0xff if unknown */ -} x86_effaddr; - -void yasm_x86__ea_init(x86_effaddr *x86_ea, unsigned int spare, - yasm_bytecode *precbc); - -void yasm_x86__ea_set_disponly(x86_effaddr *x86_ea); -x86_effaddr *yasm_x86__ea_create_reg(x86_effaddr *x86_ea, unsigned long reg, - unsigned char *rex, unsigned int bits); -x86_effaddr *yasm_x86__ea_create_imm - (x86_effaddr *x86_ea, /*@keep@*/ yasm_expr *imm, unsigned int im_len); -yasm_effaddr *yasm_x86__ea_create_expr(yasm_arch *arch, - /*@keep@*/ yasm_expr *e); -void yasm_x86__ea_destroy(yasm_effaddr *ea); -void yasm_x86__ea_print(const yasm_effaddr *ea, FILE *f, int indent_level); - -void yasm_x86__bc_insn_opersize_override(yasm_bytecode *bc, - unsigned int opersize); -void yasm_x86__bc_insn_addrsize_override(yasm_bytecode *bc, - unsigned int addrsize); -void yasm_x86__bc_insn_set_lockrep_prefix(yasm_bytecode *bc, - unsigned int prefix); - -/* Bytecode types */ -typedef struct x86_common { - unsigned char addrsize; /* 0 or =mode_bits => no override */ - unsigned char opersize; /* 0 or =mode_bits => no override */ - unsigned char lockrep_pre; /* 0 indicates no prefix */ - unsigned char acqrel_pre; /* 0 indicates no prefix. We need this because - xqcuire/xrelease might require F0 prefix */ - - unsigned char mode_bits; -} x86_common; - -typedef struct x86_opcode { - unsigned char opcode[3]; /* opcode */ - unsigned char len; -} x86_opcode; - -typedef struct x86_insn { - x86_common common; /* common x86 information */ - x86_opcode opcode; - - /*@null@*/ x86_effaddr *x86_ea; /* effective address */ - - /*@null@*/ yasm_value *imm; /* immediate or relative value */ - - unsigned char def_opersize_64; /* default operand size in 64-bit mode */ - unsigned char special_prefix; /* "special" prefix (0=none) */ - - unsigned char rex; /* REX AMD64 extension, 0 if none, - 0xff if not allowed (high 8 bit reg used) */ - - /* Postponed (from parsing to later binding) action options. */ - enum { - /* None */ - X86_POSTOP_NONE = 0, - - /* Instructions that take a sign-extended imm8 as well as imm values - * (eg, the arith instructions and a subset of the imul instructions) - * should set this and put the imm8 form as the "normal" opcode (in - * the first one or two bytes) and non-imm8 form in the second or - * third byte of the opcode. - */ - X86_POSTOP_SIGNEXT_IMM8, - - /* Override any attempt at address-size override to 16 bits, and never - * generate a prefix. This is used for the ENTER opcode. - */ - X86_POSTOP_ADDRESS16 - } postop; -} x86_insn; - -typedef struct x86_jmp { - x86_common common; /* common x86 information */ - x86_opcode shortop, nearop; - - yasm_value target; /* jump target */ - - /* which opcode are we using? */ - /* The *FORCED forms are specified in the source as such */ - x86_jmp_opcode_sel op_sel; -} x86_jmp; - -/* Direct (immediate) FAR jumps ONLY; indirect FAR jumps get turned into - * x86_insn bytecodes; relative jumps turn into x86_jmp bytecodes. - * This bytecode is not legal in 64-bit mode. - */ -typedef struct x86_jmpfar { - x86_common common; /* common x86 information */ - x86_opcode opcode; - - yasm_value segment; /* target segment */ - yasm_value offset; /* target offset */ -} x86_jmpfar; - -void yasm_x86__bc_transform_insn(yasm_bytecode *bc, x86_insn *insn); -void yasm_x86__bc_transform_jmp(yasm_bytecode *bc, x86_jmp *jmp); -void yasm_x86__bc_transform_jmpfar(yasm_bytecode *bc, x86_jmpfar *jmpfar); - -void yasm_x86__bc_apply_prefixes - (x86_common *common, unsigned char *rex, unsigned int def_opersize_64, - unsigned int num_prefixes, uintptr_t *prefixes); - -/* Check an effective address. Returns 0 if EA was successfully determined, - * 1 if invalid EA, or 2 if indeterminate EA. - */ -int yasm_x86__expr_checkea - (x86_effaddr *x86_ea, unsigned char *addrsize, unsigned int bits, - int address16_op, unsigned char *rex, yasm_bytecode *bc); - -void yasm_x86__parse_cpu(yasm_arch_x86 *arch_x86, const char *cpuid, - size_t cpuid_len); - -yasm_arch_insnprefix yasm_x86__parse_check_insnprefix - (yasm_arch *arch, const char *id, size_t id_len, unsigned long line, - /*@out@*/ yasm_bytecode **bc, /*@out@*/ uintptr_t *prefix); -yasm_arch_regtmod yasm_x86__parse_check_regtmod - (yasm_arch *arch, const char *id, size_t id_len, - /*@out@*/ uintptr_t *data); - -int yasm_x86__floatnum_tobytes - (yasm_arch *arch, const yasm_floatnum *flt, unsigned char *buf, - size_t destsize, size_t valsize, size_t shift, int warn); -int yasm_x86__intnum_tobytes - (yasm_arch *arch, const yasm_intnum *intn, unsigned char *buf, - size_t destsize, size_t valsize, int shift, const yasm_bytecode *bc, - int warn); - -unsigned int yasm_x86__get_reg_size(uintptr_t reg); - -/*@only@*/ yasm_bytecode *yasm_x86__create_empty_insn(yasm_arch *arch, - unsigned long line); -#endif +/* + * x86 Architecture header file + * + * Copyright (C) 2001-2007 Peter Johnson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef YASM_X86ARCH_H +#define YASM_X86ARCH_H + +#include <libyasm/bitvect.h> + +/* Available CPU feature flags */ +#define CPU_Any 0 /* Any old cpu will do */ +#define CPU_086 CPU_Any +#define CPU_186 1 /* i186 or better required */ +#define CPU_286 2 /* i286 or better required */ +#define CPU_386 3 /* i386 or better required */ +#define CPU_486 4 /* i486 or better required */ +#define CPU_586 5 /* i585 or better required */ +#define CPU_686 6 /* i686 or better required */ +#define CPU_P3 7 /* Pentium3 or better required */ +#define CPU_P4 8 /* Pentium4 or better required */ +#define CPU_IA64 9 /* IA-64 or better required */ +#define CPU_K6 10 /* AMD K6 or better required */ +#define CPU_Athlon 11 /* AMD Athlon or better required */ +#define CPU_Hammer 12 /* AMD Sledgehammer or better required */ +#define CPU_FPU 13 /* FPU support required */ +#define CPU_MMX 14 /* MMX support required */ +#define CPU_SSE 15 /* Streaming SIMD extensions required */ +#define CPU_SSE2 16 /* Streaming SIMD extensions 2 required */ +#define CPU_SSE3 17 /* Streaming SIMD extensions 3 required */ +#define CPU_3DNow 18 /* 3DNow! support required */ +#define CPU_Cyrix 19 /* Cyrix-specific instruction */ +#define CPU_AMD 20 /* AMD-specific inst. (older than K6) */ +#define CPU_SMM 21 /* System Management Mode instruction */ +#define CPU_Prot 22 /* Protected mode only instruction */ +#define CPU_Undoc 23 /* Undocumented instruction */ +#define CPU_Obs 24 /* Obsolete instruction */ +#define CPU_Priv 25 /* Priveleged instruction */ +#define CPU_SVM 26 /* Secure Virtual Machine instruction */ +#define CPU_PadLock 27 /* VIA PadLock instruction */ +#define CPU_EM64T 28 /* Intel EM64T or better */ +#define CPU_SSSE3 29 /* Streaming SIMD extensions 3 required */ +#define CPU_SSE41 30 /* Streaming SIMD extensions 4.1 required */ +#define CPU_SSE42 31 /* Streaming SIMD extensions 4.2 required */ +#define CPU_SSE4a 32 /* AMD Streaming SIMD extensions 4a required */ +#define CPU_XSAVE 33 /* Intel XSAVE instructions */ +#define CPU_AVX 34 /* Intel Advanced Vector Extensions */ +#define CPU_FMA 35 /* Intel Fused-Multiply-Add Extensions */ +#define CPU_AES 36 /* AES instruction */ +#define CPU_CLMUL 37 /* PCLMULQDQ instruction */ +#define CPU_MOVBE 38 /* MOVBE instruction */ +#define CPU_XOP 39 /* AMD XOP extensions */ +#define CPU_FMA4 40 /* AMD Fused-Multiply-Add extensions */ +#define CPU_F16C 41 /* Intel float-16 instructions */ +#define CPU_FSGSBASE 42 /* Intel FSGSBASE instructions */ +#define CPU_RDRAND 43 /* Intel RDRAND instruction */ +#define CPU_XSAVEOPT 44 /* Intel XSAVEOPT instruction */ +#define CPU_EPTVPID 45 /* Intel INVEPT, INVVPID instructions */ +#define CPU_SMX 46 /* Intel SMX instruction (GETSEC) */ +#define CPU_AVX2 47 /* Intel AVX2 instructions */ +#define CPU_BMI1 48 /* Intel BMI1 instructions */ +#define CPU_BMI2 49 /* Intel BMI2 instructions */ +#define CPU_INVPCID 50 /* Intel INVPCID instruction */ +#define CPU_LZCNT 51 /* Intel LZCNT instruction */ +#define CPU_TBM 52 /* AMD TBM instruction */ +#define CPU_TSX 53 /* Intel TSX instructions */ +#define CPU_SHA 54 /* Intel SHA instructions */ +#define CPU_SMAP 55 /* Intel SMAP instructions */ +#define CPU_RDSEED 56 /* Intel RDSEED instruction */ +#define CPU_ADX 57 /* Intel ADCX and ADOX instructions */ +#define CPU_PRFCHW 58 /* Intel/AMD PREFETCHW instruction */ + +enum x86_parser_type { + X86_PARSER_NASM = 0, + X86_PARSER_TASM = 1, + X86_PARSER_GAS = 2 +}; + +#define PARSER(arch) (((arch)->parser == X86_PARSER_GAS && (arch)->gas_intel_mode) ? X86_PARSER_NASM : (arch)->parser) + +typedef struct yasm_arch_x86 { + yasm_arch_base arch; /* base structure */ + + /* What instructions/features are enabled? */ + unsigned int active_cpu; /* active index into cpu_enables table */ + unsigned int cpu_enables_size; /* size of cpu_enables table */ + wordptr *cpu_enables; + + unsigned int amd64_machine; + enum x86_parser_type parser; + unsigned int mode_bits; + unsigned int address_size; + unsigned int force_strict; + unsigned int default_rel; + unsigned int gas_intel_mode; + + enum { + X86_NOP_BASIC = 0, + X86_NOP_INTEL = 1, + X86_NOP_AMD = 2 + } nop; +} yasm_arch_x86; + +/* 0-15 (low 4 bits) used for register number, stored in same data area. + * Note 8-15 are only valid for some registers, and only in 64-bit mode. + */ +typedef enum { + X86_REG8 = 0x1<<4, + X86_REG8X = 0x2<<4, /* 64-bit mode only, REX prefix version of REG8 */ + X86_REG16 = 0x3<<4, + X86_REG32 = 0x4<<4, + X86_REG64 = 0x5<<4, /* 64-bit mode only */ + X86_FPUREG = 0x6<<4, + X86_MMXREG = 0x7<<4, + X86_XMMREG = 0x8<<4, + X86_YMMREG = 0x9<<4, + X86_CRREG = 0xA<<4, + X86_DRREG = 0xB<<4, + X86_TRREG = 0xC<<4, + X86_RIP = 0xD<<4 /* 64-bit mode only, always RIP (regnum ignored) */ +} x86_expritem_reg_size; + +/* Low 8 bits are used for the prefix value, stored in same data area. */ +typedef enum { + X86_LOCKREP = 1<<8, + X86_ADDRSIZE = 2<<8, + X86_OPERSIZE = 3<<8, + X86_SEGREG = 4<<8, + X86_REX = 5<<8, + X86_ACQREL = 6<<8 /*TSX hint prefixes*/ +} x86_parse_insn_prefix; + +typedef enum { + X86_NEAR = 1, + X86_SHORT, + X86_FAR, + X86_TO +} x86_parse_targetmod; + +typedef enum { + JMP_NONE, + JMP_SHORT, + JMP_NEAR, + JMP_SHORT_FORCED, + JMP_NEAR_FORCED +} x86_jmp_opcode_sel; + +typedef enum { + X86_REX_W = 3, + X86_REX_R = 2, + X86_REX_X = 1, + X86_REX_B = 0 +} x86_rex_bit_pos; + +/* Sets REX (4th bit) and 3 LS bits from register size/number. Returns 1 if + * impossible to fit reg into REX, otherwise returns 0. Input parameter rexbit + * indicates bit of REX to use if REX is needed. Will not modify REX if not + * in 64-bit mode or if it wasn't needed to express reg. + */ +int yasm_x86__set_rex_from_reg(unsigned char *rex, unsigned char *low3, + uintptr_t reg, unsigned int bits, + x86_rex_bit_pos rexbit); + +/* Effective address type */ +typedef struct x86_effaddr { + yasm_effaddr ea; /* base structure */ + + /* VSIB uses the normal SIB byte, but this flag enables it. */ + unsigned char vsib_mode; /* 0 if not, 1 if XMM, 2 if YMM */ + + /* How the spare (register) bits in Mod/RM are handled: + * Even if valid_modrm=0, the spare bits are still valid (don't overwrite!) + * They're set in bytecode_create_insn(). + */ + unsigned char modrm; + unsigned char valid_modrm; /* 1 if Mod/RM byte currently valid, 0 if not */ + unsigned char need_modrm; /* 1 if Mod/RM byte needed, 0 if not */ + + unsigned char sib; + unsigned char valid_sib; /* 1 if SIB byte currently valid, 0 if not */ + unsigned char need_sib; /* 1 if SIB byte needed, 0 if not, + 0xff if unknown */ +} x86_effaddr; + +void yasm_x86__ea_init(x86_effaddr *x86_ea, unsigned int spare, + yasm_bytecode *precbc); + +void yasm_x86__ea_set_disponly(x86_effaddr *x86_ea); +x86_effaddr *yasm_x86__ea_create_reg(x86_effaddr *x86_ea, unsigned long reg, + unsigned char *rex, unsigned int bits); +x86_effaddr *yasm_x86__ea_create_imm + (x86_effaddr *x86_ea, /*@keep@*/ yasm_expr *imm, unsigned int im_len); +yasm_effaddr *yasm_x86__ea_create_expr(yasm_arch *arch, + /*@keep@*/ yasm_expr *e); +void yasm_x86__ea_destroy(yasm_effaddr *ea); +void yasm_x86__ea_print(const yasm_effaddr *ea, FILE *f, int indent_level); + +void yasm_x86__bc_insn_opersize_override(yasm_bytecode *bc, + unsigned int opersize); +void yasm_x86__bc_insn_addrsize_override(yasm_bytecode *bc, + unsigned int addrsize); +void yasm_x86__bc_insn_set_lockrep_prefix(yasm_bytecode *bc, + unsigned int prefix); + +/* Bytecode types */ +typedef struct x86_common { + unsigned char addrsize; /* 0 or =mode_bits => no override */ + unsigned char opersize; /* 0 or =mode_bits => no override */ + unsigned char lockrep_pre; /* 0 indicates no prefix */ + unsigned char acqrel_pre; /* 0 indicates no prefix. We need this because + xqcuire/xrelease might require F0 prefix */ + + unsigned char mode_bits; +} x86_common; + +typedef struct x86_opcode { + unsigned char opcode[3]; /* opcode */ + unsigned char len; +} x86_opcode; + +typedef struct x86_insn { + x86_common common; /* common x86 information */ + x86_opcode opcode; + + /*@null@*/ x86_effaddr *x86_ea; /* effective address */ + + /*@null@*/ yasm_value *imm; /* immediate or relative value */ + + unsigned char def_opersize_64; /* default operand size in 64-bit mode */ + unsigned char special_prefix; /* "special" prefix (0=none) */ + + unsigned char rex; /* REX AMD64 extension, 0 if none, + 0xff if not allowed (high 8 bit reg used) */ + + /* Postponed (from parsing to later binding) action options. */ + enum { + /* None */ + X86_POSTOP_NONE = 0, + + /* Instructions that take a sign-extended imm8 as well as imm values + * (eg, the arith instructions and a subset of the imul instructions) + * should set this and put the imm8 form as the "normal" opcode (in + * the first one or two bytes) and non-imm8 form in the second or + * third byte of the opcode. + */ + X86_POSTOP_SIGNEXT_IMM8, + + /* Override any attempt at address-size override to 16 bits, and never + * generate a prefix. This is used for the ENTER opcode. + */ + X86_POSTOP_ADDRESS16 + } postop; +} x86_insn; + +typedef struct x86_jmp { + x86_common common; /* common x86 information */ + x86_opcode shortop, nearop; + + yasm_value target; /* jump target */ + + /* which opcode are we using? */ + /* The *FORCED forms are specified in the source as such */ + x86_jmp_opcode_sel op_sel; +} x86_jmp; + +/* Direct (immediate) FAR jumps ONLY; indirect FAR jumps get turned into + * x86_insn bytecodes; relative jumps turn into x86_jmp bytecodes. + * This bytecode is not legal in 64-bit mode. + */ +typedef struct x86_jmpfar { + x86_common common; /* common x86 information */ + x86_opcode opcode; + + yasm_value segment; /* target segment */ + yasm_value offset; /* target offset */ +} x86_jmpfar; + +void yasm_x86__bc_transform_insn(yasm_bytecode *bc, x86_insn *insn); +void yasm_x86__bc_transform_jmp(yasm_bytecode *bc, x86_jmp *jmp); +void yasm_x86__bc_transform_jmpfar(yasm_bytecode *bc, x86_jmpfar *jmpfar); + +void yasm_x86__bc_apply_prefixes + (x86_common *common, unsigned char *rex, unsigned int def_opersize_64, + unsigned int num_prefixes, uintptr_t *prefixes); + +/* Check an effective address. Returns 0 if EA was successfully determined, + * 1 if invalid EA, or 2 if indeterminate EA. + */ +int yasm_x86__expr_checkea + (x86_effaddr *x86_ea, unsigned char *addrsize, unsigned int bits, + int address16_op, unsigned char *rex, yasm_bytecode *bc); + +void yasm_x86__parse_cpu(yasm_arch_x86 *arch_x86, const char *cpuid, + size_t cpuid_len); + +yasm_arch_insnprefix yasm_x86__parse_check_insnprefix + (yasm_arch *arch, const char *id, size_t id_len, unsigned long line, + /*@out@*/ yasm_bytecode **bc, /*@out@*/ uintptr_t *prefix); +yasm_arch_regtmod yasm_x86__parse_check_regtmod + (yasm_arch *arch, const char *id, size_t id_len, + /*@out@*/ uintptr_t *data); + +int yasm_x86__floatnum_tobytes + (yasm_arch *arch, const yasm_floatnum *flt, unsigned char *buf, + size_t destsize, size_t valsize, size_t shift, int warn); +int yasm_x86__intnum_tobytes + (yasm_arch *arch, const yasm_intnum *intn, unsigned char *buf, + size_t destsize, size_t valsize, int shift, const yasm_bytecode *bc, + int warn); + +unsigned int yasm_x86__get_reg_size(uintptr_t reg); + +/*@only@*/ yasm_bytecode *yasm_x86__create_empty_insn(yasm_arch *arch, + unsigned long line); +#endif diff --git a/contrib/tools/yasm/modules/arch/x86/x86bc.c b/contrib/tools/yasm/modules/arch/x86/x86bc.c index a6681552dd..2c51169b21 100644 --- a/contrib/tools/yasm/modules/arch/x86/x86bc.c +++ b/contrib/tools/yasm/modules/arch/x86/x86bc.c @@ -1,1062 +1,1062 @@ -/* - * x86 bytecode utility functions - * - * Copyright (C) 2001-2007 Peter Johnson - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ -#include <util.h> - -#include <libyasm.h> - -#include "x86arch.h" - - -/* Bytecode callback function prototypes */ - -static void x86_bc_insn_destroy(void *contents); -static void x86_bc_insn_print(const void *contents, FILE *f, - int indent_level); -static int x86_bc_insn_calc_len(yasm_bytecode *bc, - yasm_bc_add_span_func add_span, - void *add_span_data); -static int x86_bc_insn_expand(yasm_bytecode *bc, int span, long old_val, - long new_val, /*@out@*/ long *neg_thres, - /*@out@*/ long *pos_thres); -static int x86_bc_insn_tobytes(yasm_bytecode *bc, unsigned char **bufp, - unsigned char *bufstart, - void *d, yasm_output_value_func output_value, - /*@null@*/ yasm_output_reloc_func output_reloc); - -static void x86_bc_jmp_destroy(void *contents); -static void x86_bc_jmp_print(const void *contents, FILE *f, int indent_level); -static int x86_bc_jmp_calc_len(yasm_bytecode *bc, - yasm_bc_add_span_func add_span, - void *add_span_data); -static int x86_bc_jmp_expand(yasm_bytecode *bc, int span, long old_val, - long new_val, /*@out@*/ long *neg_thres, - /*@out@*/ long *pos_thres); -static int x86_bc_jmp_tobytes(yasm_bytecode *bc, unsigned char **bufp, - unsigned char *bufstart, - void *d, yasm_output_value_func output_value, - /*@null@*/ yasm_output_reloc_func output_reloc); - -static void x86_bc_jmpfar_destroy(void *contents); -static void x86_bc_jmpfar_print(const void *contents, FILE *f, - int indent_level); -static int x86_bc_jmpfar_calc_len(yasm_bytecode *bc, - yasm_bc_add_span_func add_span, - void *add_span_data); -static int x86_bc_jmpfar_tobytes - (yasm_bytecode *bc, unsigned char **bufp, unsigned char *bufstart, void *d, - yasm_output_value_func output_value, - /*@null@*/ yasm_output_reloc_func output_reloc); - -/* Bytecode callback structures */ - -static const yasm_bytecode_callback x86_bc_callback_insn = { - x86_bc_insn_destroy, - x86_bc_insn_print, - yasm_bc_finalize_common, - NULL, - x86_bc_insn_calc_len, - x86_bc_insn_expand, - x86_bc_insn_tobytes, - 0 -}; - -static const yasm_bytecode_callback x86_bc_callback_jmp = { - x86_bc_jmp_destroy, - x86_bc_jmp_print, - yasm_bc_finalize_common, - NULL, - x86_bc_jmp_calc_len, - x86_bc_jmp_expand, - x86_bc_jmp_tobytes, - 0 -}; - -static const yasm_bytecode_callback x86_bc_callback_jmpfar = { - x86_bc_jmpfar_destroy, - x86_bc_jmpfar_print, - yasm_bc_finalize_common, - NULL, - x86_bc_jmpfar_calc_len, - yasm_bc_expand_common, - x86_bc_jmpfar_tobytes, - 0 -}; - -int -yasm_x86__set_rex_from_reg(unsigned char *rex, unsigned char *low3, - uintptr_t reg, unsigned int bits, - x86_rex_bit_pos rexbit) -{ - *low3 = (unsigned char)(reg&7); - - if (bits == 64) { - x86_expritem_reg_size size = (x86_expritem_reg_size)(reg & ~0xFUL); - - if (size == X86_REG8X || (reg & 0xF) >= 8) { - /* Check to make sure we can set it */ - if (*rex == 0xff) { - yasm_error_set(YASM_ERROR_TYPE, - N_("cannot use A/B/C/DH with instruction needing REX")); - return 1; - } - *rex |= 0x40 | (((reg & 8) >> 3) << rexbit); - } else if (size == X86_REG8 && (reg & 7) >= 4) { - /* AH/BH/CH/DH, so no REX allowed */ - if (*rex != 0 && *rex != 0xff) { - yasm_error_set(YASM_ERROR_TYPE, - N_("cannot use A/B/C/DH with instruction needing REX")); - return 1; - } - *rex = 0xff; /* Flag so we can NEVER set it (see above) */ - } - } - - return 0; -} - -void -yasm_x86__bc_transform_insn(yasm_bytecode *bc, x86_insn *insn) -{ - yasm_bc_transform(bc, &x86_bc_callback_insn, insn); -} - -void -yasm_x86__bc_transform_jmp(yasm_bytecode *bc, x86_jmp *jmp) -{ - yasm_bc_transform(bc, &x86_bc_callback_jmp, jmp); -} - -void -yasm_x86__bc_transform_jmpfar(yasm_bytecode *bc, x86_jmpfar *jmpfar) -{ - yasm_bc_transform(bc, &x86_bc_callback_jmpfar, jmpfar); -} - -void -yasm_x86__ea_init(x86_effaddr *x86_ea, unsigned int spare, - yasm_bytecode *precbc) -{ - if (yasm_value_finalize(&x86_ea->ea.disp, precbc)) - yasm_error_set(YASM_ERROR_TOO_COMPLEX, - N_("effective address too complex")); - x86_ea->modrm &= 0xC7; /* zero spare/reg bits */ - x86_ea->modrm |= (spare << 3) & 0x38; /* plug in provided bits */ -} - -void -yasm_x86__ea_set_disponly(x86_effaddr *x86_ea) -{ - x86_ea->valid_modrm = 0; - x86_ea->need_modrm = 0; - x86_ea->valid_sib = 0; - x86_ea->need_sib = 0; -} - -static x86_effaddr * -ea_create(void) -{ - x86_effaddr *x86_ea = yasm_xmalloc(sizeof(x86_effaddr)); - - yasm_value_initialize(&x86_ea->ea.disp, NULL, 0); - x86_ea->ea.need_nonzero_len = 0; - x86_ea->ea.need_disp = 0; - x86_ea->ea.nosplit = 0; - x86_ea->ea.strong = 0; - x86_ea->ea.segreg = 0; - x86_ea->ea.pc_rel = 0; - x86_ea->ea.not_pc_rel = 0; - x86_ea->ea.data_len = 0; - x86_ea->vsib_mode = 0; - x86_ea->modrm = 0; - x86_ea->valid_modrm = 0; - x86_ea->need_modrm = 0; - x86_ea->sib = 0; - x86_ea->valid_sib = 0; - x86_ea->need_sib = 0; - - return x86_ea; -} - -x86_effaddr * -yasm_x86__ea_create_reg(x86_effaddr *x86_ea, unsigned long reg, - unsigned char *rex, unsigned int bits) -{ - unsigned char rm; - - if (yasm_x86__set_rex_from_reg(rex, &rm, reg, bits, X86_REX_B)) - return NULL; - - if (!x86_ea) - x86_ea = ea_create(); - x86_ea->modrm = 0xC0 | rm; /* Mod=11, R/M=Reg, Reg=0 */ - x86_ea->valid_modrm = 1; - x86_ea->need_modrm = 1; - - return x86_ea; -} - -yasm_effaddr * -yasm_x86__ea_create_expr(yasm_arch *arch, yasm_expr *e) -{ - yasm_arch_x86 *arch_x86 = (yasm_arch_x86 *)arch; - x86_effaddr *x86_ea; - - x86_ea = ea_create(); - - if (arch_x86->parser == X86_PARSER_GAS) { - /* Need to change foo+rip into foo wrt rip (even in .intel_syntax mode). - * Note this assumes a particular ordering coming from the parser - * to work (it's not very smart)! - */ - if (e->op == YASM_EXPR_ADD && e->terms[0].type == YASM_EXPR_REG - && e->terms[0].data.reg == X86_RIP) { - /* replace register with 0 */ - e->terms[0].type = YASM_EXPR_INT; - e->terms[0].data.intn = yasm_intnum_create_uint(0); - /* build new wrt expression */ - e = yasm_expr_create(YASM_EXPR_WRT, yasm_expr_expr(e), - yasm_expr_reg(X86_RIP), e->line); - } - } - yasm_value_initialize(&x86_ea->ea.disp, e, 0); - x86_ea->ea.need_disp = 1; - x86_ea->need_modrm = 1; - /* We won't know whether we need an SIB until we know more about expr and - * the BITS/address override setting. - */ - x86_ea->need_sib = 0xff; - - x86_ea->ea.data_len = 0; - - return (yasm_effaddr *)x86_ea; -} - -/*@-compmempass@*/ -x86_effaddr * -yasm_x86__ea_create_imm(x86_effaddr *x86_ea, yasm_expr *imm, - unsigned int im_len) -{ - if (!x86_ea) - x86_ea = ea_create(); - yasm_value_initialize(&x86_ea->ea.disp, imm, im_len); - x86_ea->ea.need_disp = 1; - - return x86_ea; -} -/*@=compmempass@*/ - -void -yasm_x86__bc_apply_prefixes(x86_common *common, unsigned char *rex, - unsigned int def_opersize_64, - unsigned int num_prefixes, uintptr_t *prefixes) -{ - unsigned int i; - int first = 1; - - for (i=0; i<num_prefixes; i++) { - switch ((x86_parse_insn_prefix)(prefixes[i] & 0xff00)) { - /*To be accurate, we should enforce that TSX hints come only with a - predefined set of instructions, and in most cases only with F0 - prefix. Otherwise they will have completely different semantics. - But F0 prefix can come only with a predefined set of instructions - too. And if it comes with other instructions, CPU will #UD. - Hence, F0-applicability should be enforced too. But it's not - currently. Maybe it is the decision made, that user should know - himself what he is doing with LOCK prefix. In this case, we should - not enforce TSX hints applicability too. And let user take care of - correct usage of TSX hints. - That is what we are going to do.*/ - case X86_ACQREL: - if (common->acqrel_pre != 0) - yasm_warn_set(YASM_WARN_GENERAL, - N_("multiple XACQUIRE/XRELEASE prefixes, " - "using leftmost")); - common->acqrel_pre = (unsigned char)prefixes[i] & 0xff; - break; - case X86_LOCKREP: - if (common->lockrep_pre != 0) - yasm_warn_set(YASM_WARN_GENERAL, - N_("multiple LOCK or REP prefixes, using leftmost")); - common->lockrep_pre = (unsigned char)prefixes[i] & 0xff; - break; - case X86_ADDRSIZE: - common->addrsize = (unsigned char)prefixes[i] & 0xff; - break; - case X86_OPERSIZE: - common->opersize = (unsigned char)prefixes[i] & 0xff; - if (common->mode_bits == 64 && common->opersize == 64 && - def_opersize_64 != 64) { - if (!rex) - yasm_warn_set(YASM_WARN_GENERAL, - N_("ignoring REX prefix on jump")); - else if (*rex == 0xff) - yasm_warn_set(YASM_WARN_GENERAL, - N_("REX prefix not allowed on this instruction, ignoring")); - else - *rex = 0x48; - } - break; - case X86_SEGREG: - /* This is a hack.. we should really be putting this in the - * the effective address! - */ - common->lockrep_pre = (unsigned char)prefixes[i] & 0xff; - break; - case X86_REX: - if (!rex) - yasm_warn_set(YASM_WARN_GENERAL, - N_("ignoring REX prefix on jump")); - else if (*rex == 0xff) - yasm_warn_set(YASM_WARN_GENERAL, - N_("REX prefix not allowed on this instruction, ignoring")); - else { - if (*rex != 0) { - if (first) - yasm_warn_set(YASM_WARN_GENERAL, - N_("overriding generated REX prefix")); - else - yasm_warn_set(YASM_WARN_GENERAL, - N_("multiple REX prefixes, using leftmost")); - } - /* Here we assume that we can't get this prefix in non - * 64 bit mode due to checks in parse_check_prefix(). - */ - common->mode_bits = 64; - *rex = (unsigned char)prefixes[i] & 0xff; - } - first = 0; - break; - } - } -} - -static void -x86_bc_insn_destroy(void *contents) -{ - x86_insn *insn = (x86_insn *)contents; - if (insn->x86_ea) - yasm_x86__ea_destroy((yasm_effaddr *)insn->x86_ea); - if (insn->imm) { - yasm_value_delete(insn->imm); - yasm_xfree(insn->imm); - } - yasm_xfree(contents); -} - -static void -x86_bc_jmp_destroy(void *contents) -{ - x86_jmp *jmp = (x86_jmp *)contents; - yasm_value_delete(&jmp->target); - yasm_xfree(contents); -} - -static void -x86_bc_jmpfar_destroy(void *contents) -{ - x86_jmpfar *jmpfar = (x86_jmpfar *)contents; - yasm_value_delete(&jmpfar->segment); - yasm_value_delete(&jmpfar->offset); - yasm_xfree(contents); -} - -void -yasm_x86__ea_destroy(yasm_effaddr *ea) -{ - yasm_value_delete(&ea->disp); - yasm_xfree(ea); -} - -void -yasm_x86__ea_print(const yasm_effaddr *ea, FILE *f, int indent_level) -{ - const x86_effaddr *x86_ea = (const x86_effaddr *)ea; - fprintf(f, "%*sDisp:\n", indent_level, ""); - yasm_value_print(&ea->disp, f, indent_level+1); - fprintf(f, "%*sNoSplit=%u\n", indent_level, "", (unsigned int)ea->nosplit); - fprintf(f, "%*sSegmentOv=%02x\n", indent_level, "", - (unsigned int)x86_ea->ea.segreg); - fprintf(f, "%*sVSIBMode=%u\n", indent_level, "", - (unsigned int)x86_ea->vsib_mode); - fprintf(f, "%*sModRM=%03o ValidRM=%u NeedRM=%u\n", indent_level, "", - (unsigned int)x86_ea->modrm, (unsigned int)x86_ea->valid_modrm, - (unsigned int)x86_ea->need_modrm); - fprintf(f, "%*sSIB=%03o ValidSIB=%u NeedSIB=%u\n", indent_level, "", - (unsigned int)x86_ea->sib, (unsigned int)x86_ea->valid_sib, - (unsigned int)x86_ea->need_sib); -} - -static void -x86_common_print(const x86_common *common, FILE *f, int indent_level) -{ - fprintf(f, "%*sAddrSize=%u OperSize=%u LockRepPre=%02x " - "ACQREL_Pre=%02x BITS=%u\n", - indent_level, "", - (unsigned int)common->addrsize, - (unsigned int)common->opersize, - (unsigned int)common->lockrep_pre, - (unsigned int)common->acqrel_pre, - (unsigned int)common->mode_bits); -} - -static void -x86_opcode_print(const x86_opcode *opcode, FILE *f, int indent_level) -{ - fprintf(f, "%*sOpcode: %02x %02x %02x OpLen=%u\n", indent_level, "", - (unsigned int)opcode->opcode[0], - (unsigned int)opcode->opcode[1], - (unsigned int)opcode->opcode[2], - (unsigned int)opcode->len); -} - -static void -x86_bc_insn_print(const void *contents, FILE *f, int indent_level) -{ - const x86_insn *insn = (const x86_insn *)contents; - - fprintf(f, "%*s_Instruction_\n", indent_level, ""); - fprintf(f, "%*sEffective Address:", indent_level, ""); - if (insn->x86_ea) { - fprintf(f, "\n"); - yasm_x86__ea_print((yasm_effaddr *)insn->x86_ea, f, indent_level+1); - } else - fprintf(f, " (nil)\n"); - fprintf(f, "%*sImmediate Value:", indent_level, ""); - if (!insn->imm) - fprintf(f, " (nil)\n"); - else { - indent_level++; - fprintf(f, "\n"); - yasm_value_print(insn->imm, f, indent_level); - indent_level--; - } - x86_opcode_print(&insn->opcode, f, indent_level); - x86_common_print(&insn->common, f, indent_level); - fprintf(f, "%*sSpPre=%02x REX=%03o PostOp=%u\n", indent_level, "", - (unsigned int)insn->special_prefix, - (unsigned int)insn->rex, - (unsigned int)insn->postop); -} - -static void -x86_bc_jmp_print(const void *contents, FILE *f, int indent_level) -{ - const x86_jmp *jmp = (const x86_jmp *)contents; - - fprintf(f, "%*s_Jump_\n", indent_level, ""); - fprintf(f, "%*sTarget:\n", indent_level, ""); - yasm_value_print(&jmp->target, f, indent_level+1); - /* FIXME - fprintf(f, "%*sOrigin=\n", indent_level, ""); - yasm_symrec_print(jmp->origin, f, indent_level+1); - */ - fprintf(f, "\n%*sShort Form:\n", indent_level, ""); - if (jmp->shortop.len == 0) - fprintf(f, "%*sNone\n", indent_level+1, ""); - else - x86_opcode_print(&jmp->shortop, f, indent_level+1); - fprintf(f, "%*sNear Form:\n", indent_level, ""); - if (jmp->nearop.len == 0) - fprintf(f, "%*sNone\n", indent_level+1, ""); - else - x86_opcode_print(&jmp->nearop, f, indent_level+1); - fprintf(f, "%*sOpSel=", indent_level, ""); - switch (jmp->op_sel) { - case JMP_NONE: - fprintf(f, "None"); - break; - case JMP_SHORT: - fprintf(f, "Short"); - break; - case JMP_NEAR: - fprintf(f, "Near"); - break; - case JMP_SHORT_FORCED: - fprintf(f, "Forced Short"); - break; - case JMP_NEAR_FORCED: - fprintf(f, "Forced Near"); - break; - default: - fprintf(f, "UNKNOWN!!"); - break; - } - x86_common_print(&jmp->common, f, indent_level); -} - -static void -x86_bc_jmpfar_print(const void *contents, FILE *f, int indent_level) -{ - const x86_jmpfar *jmpfar = (const x86_jmpfar *)contents; - - fprintf(f, "%*s_Far_Jump_\n", indent_level, ""); - fprintf(f, "%*sSegment:\n", indent_level, ""); - yasm_value_print(&jmpfar->segment, f, indent_level+1); - fprintf(f, "%*sOffset:\n", indent_level, ""); - yasm_value_print(&jmpfar->offset, f, indent_level+1); - x86_opcode_print(&jmpfar->opcode, f, indent_level); - x86_common_print(&jmpfar->common, f, indent_level); -} - -static unsigned int -x86_common_calc_len(const x86_common *common) -{ - unsigned int len = 0; - - if (common->addrsize != 0 && common->addrsize != common->mode_bits) - len++; - if (common->opersize != 0 && - ((common->mode_bits != 64 && common->opersize != common->mode_bits) || - (common->mode_bits == 64 && common->opersize == 16))) - len++; - if (common->lockrep_pre != 0) - len++; - if (common->acqrel_pre != 0) - len++; - - - return len; -} - -static int -x86_bc_insn_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span, - void *add_span_data) -{ - x86_insn *insn = (x86_insn *)bc->contents; - x86_effaddr *x86_ea = insn->x86_ea; - yasm_value *imm = insn->imm; - - if (x86_ea) { - /* Check validity of effective address and calc R/M bits of - * Mod/RM byte and SIB byte. We won't know the Mod field - * of the Mod/RM byte until we know more about the - * displacement. - */ - if (yasm_x86__expr_checkea(x86_ea, &insn->common.addrsize, - insn->common.mode_bits, insn->postop == X86_POSTOP_ADDRESS16, - &insn->rex, bc)) - /* failed, don't bother checking rest of insn */ - return -1; - - if (x86_ea->ea.disp.size == 0 && x86_ea->ea.need_nonzero_len) { - /* Handle unknown case, default to byte-sized and set as - * critical expression. - */ - x86_ea->ea.disp.size = 8; - add_span(add_span_data, bc, 1, &x86_ea->ea.disp, -128, 127); - } - bc->len += x86_ea->ea.disp.size/8; - - /* Handle address16 postop case */ - if (insn->postop == X86_POSTOP_ADDRESS16) - insn->common.addrsize = 0; - - /* Compute length of ea and add to total */ - bc->len += x86_ea->need_modrm + (x86_ea->need_sib ? 1:0); - bc->len += (x86_ea->ea.segreg != 0) ? 1 : 0; - } - - if (imm) { - unsigned int immlen = imm->size; - - /* TODO: check imm->len vs. sized len from expr? */ - - /* Handle signext_imm8 postop special-casing */ - if (insn->postop == X86_POSTOP_SIGNEXT_IMM8) { - /*@null@*/ /*@only@*/ yasm_intnum *num; - num = yasm_value_get_intnum(imm, NULL, 0); - - if (!num) { - /* Unknown; default to byte form and set as critical - * expression. - */ - immlen = 8; - add_span(add_span_data, bc, 2, imm, -128, 127); - } else { - if (yasm_intnum_in_range(num, -128, 127)) { - /* We can use the sign-extended byte form: shorten - * the immediate length to 1 and make the byte form - * permanent. - */ - imm->size = 8; - imm->sign = 1; - immlen = 8; - } else { - /* We can't. Copy over the word-sized opcode. */ - insn->opcode.opcode[0] = - insn->opcode.opcode[insn->opcode.len]; - insn->opcode.len = 1; - } - insn->postop = X86_POSTOP_NONE; - yasm_intnum_destroy(num); - } - } - - bc->len += immlen/8; - } - - /* VEX and XOP prefixes never have REX (it's embedded in the opcode). - * For VEX, we can come into this function with the three byte form, - * so we need to see if we can optimize to the two byte form. - * We can't do it earlier, as we don't know all of the REX byte until now. - */ - if (insn->special_prefix == 0xC4) { - /* See if we can shorten the VEX prefix to its two byte form. - * In order to do this, REX.X, REX.B, and REX.W/VEX.W must all be 0, - * and the VEX mmmmm field must be 1. - */ - if ((insn->opcode.opcode[0] & 0x1F) == 1 && - (insn->opcode.opcode[1] & 0x80) == 0 && - (insn->rex == 0xff || (insn->rex & 0x0B) == 0)) { - insn->opcode.opcode[0] = insn->opcode.opcode[1]; - insn->opcode.opcode[1] = insn->opcode.opcode[2]; - insn->opcode.opcode[2] = 0; /* sanity */ - insn->opcode.len = 2; - insn->special_prefix = 0xC5; /* mark as two-byte VEX */ - } - } else if (insn->rex != 0xff && insn->rex != 0 && - insn->special_prefix != 0xC5 && insn->special_prefix != 0x8F) - bc->len++; - - bc->len += insn->opcode.len; - bc->len += x86_common_calc_len(&insn->common); - bc->len += (insn->special_prefix != 0) ? 1:0; - return 0; -} - -static int -x86_bc_insn_expand(yasm_bytecode *bc, int span, long old_val, long new_val, - /*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres) -{ - x86_insn *insn = (x86_insn *)bc->contents; - x86_effaddr *x86_ea = insn->x86_ea; - yasm_effaddr *ea = &x86_ea->ea; - yasm_value *imm = insn->imm; - - if (ea && span == 1) { - /* Change displacement length into word-sized */ - if (ea->disp.size == 8) { - ea->disp.size = (insn->common.addrsize == 16) ? 16 : 32; - x86_ea->modrm &= ~0300; - x86_ea->modrm |= 0200; - bc->len--; - bc->len += ea->disp.size/8; - } - } - - if (imm && span == 2) { - if (insn->postop == X86_POSTOP_SIGNEXT_IMM8) { - /* Update bc->len for new opcode and immediate size */ - bc->len -= insn->opcode.len; - bc->len += imm->size/8; - - /* Change to the word-sized opcode */ - insn->opcode.opcode[0] = insn->opcode.opcode[insn->opcode.len]; - insn->opcode.len = 1; - insn->postop = X86_POSTOP_NONE; - } - } - - return 0; -} - -static int -x86_bc_jmp_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span, - void *add_span_data) -{ - x86_jmp *jmp = (x86_jmp *)bc->contents; - yasm_bytecode *target_prevbc; - unsigned char opersize; - - /* As opersize may be 0, figure out its "real" value. */ - opersize = (jmp->common.opersize == 0) ? - jmp->common.mode_bits : jmp->common.opersize; - - bc->len += x86_common_calc_len(&jmp->common); - - if (jmp->op_sel == JMP_NEAR_FORCED || jmp->shortop.len == 0) { - if (jmp->nearop.len == 0) { - yasm_error_set(YASM_ERROR_TYPE, N_("near jump does not exist")); - return -1; - } - - /* Near jump, no spans needed */ - if (jmp->shortop.len == 0) - jmp->op_sel = JMP_NEAR; - bc->len += jmp->nearop.len; - bc->len += (opersize == 16) ? 2 : 4; - return 0; - } - - if (jmp->op_sel == JMP_SHORT_FORCED || jmp->nearop.len == 0) { - if (jmp->shortop.len == 0) { - yasm_error_set(YASM_ERROR_TYPE, N_("short jump does not exist")); - return -1; - } - - /* We want to be sure to error if we exceed short length, so - * put it in as a dependent expression (falling through). - */ - } - - if (jmp->target.rel - && (!yasm_symrec_get_label(jmp->target.rel, &target_prevbc) - || target_prevbc->section != bc->section)) { - /* External or out of segment, so we can't check distance. - * Allowing short jumps depends on the objfmt supporting - * 8-bit relocs. While most don't, some might, so allow it here. - * Otherwise default to word-sized. - * The objfmt will error if not supported. - */ - if (jmp->op_sel == JMP_SHORT_FORCED || jmp->nearop.len == 0) { - if (jmp->op_sel == JMP_NONE) - jmp->op_sel = JMP_SHORT; - bc->len += jmp->shortop.len + 1; - } else { - jmp->op_sel = JMP_NEAR; - bc->len += jmp->nearop.len; - bc->len += (opersize == 16) ? 2 : 4; - } - return 0; - } - - /* Default to short jump and generate span */ - if (jmp->op_sel == JMP_NONE) - jmp->op_sel = JMP_SHORT; - bc->len += jmp->shortop.len + 1; - add_span(add_span_data, bc, 1, &jmp->target, -128+(long)bc->len, - 127+(long)bc->len); - return 0; -} - -static int -x86_bc_jmp_expand(yasm_bytecode *bc, int span, long old_val, long new_val, - /*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres) -{ - x86_jmp *jmp = (x86_jmp *)bc->contents; - unsigned char opersize; - - if (span != 1) - yasm_internal_error(N_("unrecognized span id")); - - /* As opersize may be 0, figure out its "real" value. */ - opersize = (jmp->common.opersize == 0) ? - jmp->common.mode_bits : jmp->common.opersize; - - if (jmp->op_sel == JMP_SHORT_FORCED || jmp->nearop.len == 0) { - yasm_error_set(YASM_ERROR_VALUE, N_("short jump out of range")); - return -1; - } - - if (jmp->op_sel == JMP_NEAR) - yasm_internal_error(N_("trying to expand an already-near jump")); - - /* Upgrade to a near jump */ - jmp->op_sel = JMP_NEAR; - bc->len -= jmp->shortop.len + 1; - bc->len += jmp->nearop.len; - bc->len += (opersize == 16) ? 2 : 4; - - return 0; -} - -static int -x86_bc_jmpfar_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span, - void *add_span_data) -{ - x86_jmpfar *jmpfar = (x86_jmpfar *)bc->contents; - unsigned char opersize; - - opersize = (jmpfar->common.opersize == 0) ? - jmpfar->common.mode_bits : jmpfar->common.opersize; - - bc->len += jmpfar->opcode.len; - bc->len += 2; /* segment */ - bc->len += (opersize == 16) ? 2 : 4; - bc->len += x86_common_calc_len(&jmpfar->common); - - return 0; -} - -static void -x86_common_tobytes(const x86_common *common, unsigned char **bufp, - unsigned int segreg) -{ - if (segreg != 0) - YASM_WRITE_8(*bufp, (unsigned char)segreg); - if (common->addrsize != 0 && common->addrsize != common->mode_bits) - YASM_WRITE_8(*bufp, 0x67); - if (common->opersize != 0 && - ((common->mode_bits != 64 && common->opersize != common->mode_bits) || - (common->mode_bits == 64 && common->opersize == 16))) - YASM_WRITE_8(*bufp, 0x66); - /*TSX hints come before lock prefix*/ - if (common->acqrel_pre != 0) - YASM_WRITE_8(*bufp, common->acqrel_pre); - if (common->lockrep_pre != 0) - YASM_WRITE_8(*bufp, common->lockrep_pre); -} - -static void -x86_opcode_tobytes(const x86_opcode *opcode, unsigned char **bufp) -{ - unsigned int i; - for (i=0; i<opcode->len; i++) - YASM_WRITE_8(*bufp, opcode->opcode[i]); -} - -static int -x86_bc_insn_tobytes(yasm_bytecode *bc, unsigned char **bufp, - unsigned char *bufstart, void *d, - yasm_output_value_func output_value, - /*@unused@*/ yasm_output_reloc_func output_reloc) -{ - x86_insn *insn = (x86_insn *)bc->contents; - /*@null@*/ x86_effaddr *x86_ea = (x86_effaddr *)insn->x86_ea; - yasm_value *imm = insn->imm; - - /* Prefixes */ - x86_common_tobytes(&insn->common, bufp, - x86_ea ? (unsigned int)(x86_ea->ea.segreg>>8) : 0); - if (insn->special_prefix != 0) - YASM_WRITE_8(*bufp, insn->special_prefix); - if (insn->special_prefix == 0xC4 || insn->special_prefix == 0x8F) { - /* 3-byte VEX/XOP; merge in 1s complement of REX.R, REX.X, REX.B */ - insn->opcode.opcode[0] &= 0x1F; - if (insn->rex != 0xff) - insn->opcode.opcode[0] |= ((~insn->rex) & 0x07) << 5; - /* merge REX.W via ORing; there should never be a case in which REX.W - * is important when VEX.W is already set by the instruction. - */ - if (insn->rex != 0xff && (insn->rex & 0x8) != 0) - insn->opcode.opcode[1] |= 0x80; - } else if (insn->special_prefix == 0xC5) { - /* 2-byte VEX; merge in 1s complement of REX.R */ - insn->opcode.opcode[0] &= 0x7F; - if (insn->rex != 0xff && (insn->rex & 0x4) == 0) - insn->opcode.opcode[0] |= 0x80; - /* No other REX bits should be set */ - if (insn->rex != 0xff && (insn->rex & 0xB) != 0) - yasm_internal_error(N_("x86: REX.WXB set, but 2-byte VEX")); - } else if (insn->rex != 0xff && insn->rex != 0) { - if (insn->common.mode_bits != 64) - yasm_internal_error(N_("x86: got a REX prefix in non-64-bit mode")); - YASM_WRITE_8(*bufp, insn->rex); - } - - /* Opcode */ - x86_opcode_tobytes(&insn->opcode, bufp); - - /* Effective address: ModR/M (if required), SIB (if required), and - * displacement (if required). - */ - if (x86_ea) { - if (x86_ea->need_modrm) { - if (!x86_ea->valid_modrm) - yasm_internal_error(N_("invalid Mod/RM in x86 tobytes_insn")); - YASM_WRITE_8(*bufp, x86_ea->modrm); - } - - if (x86_ea->need_sib) { - if (!x86_ea->valid_sib) - yasm_internal_error(N_("invalid SIB in x86 tobytes_insn")); - YASM_WRITE_8(*bufp, x86_ea->sib); - } - - if (x86_ea->ea.need_disp) { - unsigned int disp_len = x86_ea->ea.disp.size/8; - - if (x86_ea->ea.disp.ip_rel) { - /* Adjust relative displacement to end of bytecode */ - /*@only@*/ yasm_intnum *delta; - delta = yasm_intnum_create_int(-(long)bc->len); - if (!x86_ea->ea.disp.abs) - x86_ea->ea.disp.abs = - yasm_expr_create_ident(yasm_expr_int(delta), bc->line); - else - x86_ea->ea.disp.abs = - yasm_expr_create(YASM_EXPR_ADD, - yasm_expr_expr(x86_ea->ea.disp.abs), - yasm_expr_int(delta), bc->line); - } - if (output_value(&x86_ea->ea.disp, *bufp, disp_len, - (unsigned long)(*bufp-bufstart), bc, 1, d)) - return 1; - *bufp += disp_len; - } - } - - /* Immediate (if required) */ - if (imm) { - unsigned int imm_len; - if (insn->postop == X86_POSTOP_SIGNEXT_IMM8) { - /* If we got here with this postop still set, we need to force - * imm size to 8 here. - */ - imm->size = 8; - imm->sign = 1; - imm_len = 1; - } else - imm_len = imm->size/8; - if (output_value(imm, *bufp, imm_len, (unsigned long)(*bufp-bufstart), - bc, 1, d)) - return 1; - *bufp += imm_len; - } - - return 0; -} - -static int -x86_bc_jmp_tobytes(yasm_bytecode *bc, unsigned char **bufp, - unsigned char *bufstart, void *d, - yasm_output_value_func output_value, - /*@unused@*/ yasm_output_reloc_func output_reloc) -{ - x86_jmp *jmp = (x86_jmp *)bc->contents; - unsigned char opersize; - unsigned int i; - /*@only@*/ yasm_intnum *delta; - - /* Prefixes */ - x86_common_tobytes(&jmp->common, bufp, 0); - - /* As opersize may be 0, figure out its "real" value. */ - opersize = (jmp->common.opersize == 0) ? - jmp->common.mode_bits : jmp->common.opersize; - - /* Check here again to see if forms are actually legal. */ - switch (jmp->op_sel) { - case JMP_SHORT_FORCED: - case JMP_SHORT: - /* 1 byte relative displacement */ - if (jmp->shortop.len == 0) - yasm_internal_error(N_("short jump does not exist")); - - /* Opcode */ - x86_opcode_tobytes(&jmp->shortop, bufp); - - /* Adjust relative displacement to end of bytecode */ - delta = yasm_intnum_create_int(-(long)bc->len); - if (!jmp->target.abs) - jmp->target.abs = yasm_expr_create_ident(yasm_expr_int(delta), - bc->line); - else - jmp->target.abs = - yasm_expr_create(YASM_EXPR_ADD, - yasm_expr_expr(jmp->target.abs), - yasm_expr_int(delta), bc->line); - - jmp->target.size = 8; - jmp->target.sign = 1; - if (output_value(&jmp->target, *bufp, 1, - (unsigned long)(*bufp-bufstart), bc, 1, d)) - return 1; - *bufp += 1; - break; - case JMP_NEAR_FORCED: - case JMP_NEAR: - /* 2/4 byte relative displacement (depending on operand size) */ - if (jmp->nearop.len == 0) { - yasm_error_set(YASM_ERROR_TYPE, - N_("near jump does not exist")); - return 1; - } - - /* Opcode */ - x86_opcode_tobytes(&jmp->nearop, bufp); - - i = (opersize == 16) ? 2 : 4; - - /* Adjust relative displacement to end of bytecode */ - delta = yasm_intnum_create_int(-(long)bc->len); - if (!jmp->target.abs) - jmp->target.abs = yasm_expr_create_ident(yasm_expr_int(delta), - bc->line); - else - jmp->target.abs = - yasm_expr_create(YASM_EXPR_ADD, - yasm_expr_expr(jmp->target.abs), - yasm_expr_int(delta), bc->line); - - jmp->target.size = i*8; - jmp->target.sign = 1; - if (output_value(&jmp->target, *bufp, i, - (unsigned long)(*bufp-bufstart), bc, 1, d)) - return 1; - *bufp += i; - break; - case JMP_NONE: - yasm_internal_error(N_("jump op_sel cannot be JMP_NONE in tobytes")); - default: - yasm_internal_error(N_("unrecognized relative jump op_sel")); - } - return 0; -} - -static int -x86_bc_jmpfar_tobytes(yasm_bytecode *bc, unsigned char **bufp, - unsigned char *bufstart, void *d, - yasm_output_value_func output_value, - /*@unused@*/ yasm_output_reloc_func output_reloc) -{ - x86_jmpfar *jmpfar = (x86_jmpfar *)bc->contents; - unsigned int i; - unsigned char opersize; - - x86_common_tobytes(&jmpfar->common, bufp, 0); - x86_opcode_tobytes(&jmpfar->opcode, bufp); - - /* As opersize may be 0, figure out its "real" value. */ - opersize = (jmpfar->common.opersize == 0) ? - jmpfar->common.mode_bits : jmpfar->common.opersize; - - /* Absolute displacement: segment and offset */ - i = (opersize == 16) ? 2 : 4; - jmpfar->offset.size = i*8; - if (output_value(&jmpfar->offset, *bufp, i, - (unsigned long)(*bufp-bufstart), bc, 1, d)) - return 1; - *bufp += i; - jmpfar->segment.size = 16; - if (output_value(&jmpfar->segment, *bufp, 2, - (unsigned long)(*bufp-bufstart), bc, 1, d)) - return 1; - *bufp += 2; - - return 0; -} - -int -yasm_x86__intnum_tobytes(yasm_arch *arch, const yasm_intnum *intn, - unsigned char *buf, size_t destsize, size_t valsize, - int shift, const yasm_bytecode *bc, int warn) -{ - /* Write value out. */ - yasm_intnum_get_sized(intn, buf, destsize, valsize, shift, 0, warn); - return 0; -} +/* + * x86 bytecode utility functions + * + * Copyright (C) 2001-2007 Peter Johnson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include <util.h> + +#include <libyasm.h> + +#include "x86arch.h" + + +/* Bytecode callback function prototypes */ + +static void x86_bc_insn_destroy(void *contents); +static void x86_bc_insn_print(const void *contents, FILE *f, + int indent_level); +static int x86_bc_insn_calc_len(yasm_bytecode *bc, + yasm_bc_add_span_func add_span, + void *add_span_data); +static int x86_bc_insn_expand(yasm_bytecode *bc, int span, long old_val, + long new_val, /*@out@*/ long *neg_thres, + /*@out@*/ long *pos_thres); +static int x86_bc_insn_tobytes(yasm_bytecode *bc, unsigned char **bufp, + unsigned char *bufstart, + void *d, yasm_output_value_func output_value, + /*@null@*/ yasm_output_reloc_func output_reloc); + +static void x86_bc_jmp_destroy(void *contents); +static void x86_bc_jmp_print(const void *contents, FILE *f, int indent_level); +static int x86_bc_jmp_calc_len(yasm_bytecode *bc, + yasm_bc_add_span_func add_span, + void *add_span_data); +static int x86_bc_jmp_expand(yasm_bytecode *bc, int span, long old_val, + long new_val, /*@out@*/ long *neg_thres, + /*@out@*/ long *pos_thres); +static int x86_bc_jmp_tobytes(yasm_bytecode *bc, unsigned char **bufp, + unsigned char *bufstart, + void *d, yasm_output_value_func output_value, + /*@null@*/ yasm_output_reloc_func output_reloc); + +static void x86_bc_jmpfar_destroy(void *contents); +static void x86_bc_jmpfar_print(const void *contents, FILE *f, + int indent_level); +static int x86_bc_jmpfar_calc_len(yasm_bytecode *bc, + yasm_bc_add_span_func add_span, + void *add_span_data); +static int x86_bc_jmpfar_tobytes + (yasm_bytecode *bc, unsigned char **bufp, unsigned char *bufstart, void *d, + yasm_output_value_func output_value, + /*@null@*/ yasm_output_reloc_func output_reloc); + +/* Bytecode callback structures */ + +static const yasm_bytecode_callback x86_bc_callback_insn = { + x86_bc_insn_destroy, + x86_bc_insn_print, + yasm_bc_finalize_common, + NULL, + x86_bc_insn_calc_len, + x86_bc_insn_expand, + x86_bc_insn_tobytes, + 0 +}; + +static const yasm_bytecode_callback x86_bc_callback_jmp = { + x86_bc_jmp_destroy, + x86_bc_jmp_print, + yasm_bc_finalize_common, + NULL, + x86_bc_jmp_calc_len, + x86_bc_jmp_expand, + x86_bc_jmp_tobytes, + 0 +}; + +static const yasm_bytecode_callback x86_bc_callback_jmpfar = { + x86_bc_jmpfar_destroy, + x86_bc_jmpfar_print, + yasm_bc_finalize_common, + NULL, + x86_bc_jmpfar_calc_len, + yasm_bc_expand_common, + x86_bc_jmpfar_tobytes, + 0 +}; + +int +yasm_x86__set_rex_from_reg(unsigned char *rex, unsigned char *low3, + uintptr_t reg, unsigned int bits, + x86_rex_bit_pos rexbit) +{ + *low3 = (unsigned char)(reg&7); + + if (bits == 64) { + x86_expritem_reg_size size = (x86_expritem_reg_size)(reg & ~0xFUL); + + if (size == X86_REG8X || (reg & 0xF) >= 8) { + /* Check to make sure we can set it */ + if (*rex == 0xff) { + yasm_error_set(YASM_ERROR_TYPE, + N_("cannot use A/B/C/DH with instruction needing REX")); + return 1; + } + *rex |= 0x40 | (((reg & 8) >> 3) << rexbit); + } else if (size == X86_REG8 && (reg & 7) >= 4) { + /* AH/BH/CH/DH, so no REX allowed */ + if (*rex != 0 && *rex != 0xff) { + yasm_error_set(YASM_ERROR_TYPE, + N_("cannot use A/B/C/DH with instruction needing REX")); + return 1; + } + *rex = 0xff; /* Flag so we can NEVER set it (see above) */ + } + } + + return 0; +} + +void +yasm_x86__bc_transform_insn(yasm_bytecode *bc, x86_insn *insn) +{ + yasm_bc_transform(bc, &x86_bc_callback_insn, insn); +} + +void +yasm_x86__bc_transform_jmp(yasm_bytecode *bc, x86_jmp *jmp) +{ + yasm_bc_transform(bc, &x86_bc_callback_jmp, jmp); +} + +void +yasm_x86__bc_transform_jmpfar(yasm_bytecode *bc, x86_jmpfar *jmpfar) +{ + yasm_bc_transform(bc, &x86_bc_callback_jmpfar, jmpfar); +} + +void +yasm_x86__ea_init(x86_effaddr *x86_ea, unsigned int spare, + yasm_bytecode *precbc) +{ + if (yasm_value_finalize(&x86_ea->ea.disp, precbc)) + yasm_error_set(YASM_ERROR_TOO_COMPLEX, + N_("effective address too complex")); + x86_ea->modrm &= 0xC7; /* zero spare/reg bits */ + x86_ea->modrm |= (spare << 3) & 0x38; /* plug in provided bits */ +} + +void +yasm_x86__ea_set_disponly(x86_effaddr *x86_ea) +{ + x86_ea->valid_modrm = 0; + x86_ea->need_modrm = 0; + x86_ea->valid_sib = 0; + x86_ea->need_sib = 0; +} + +static x86_effaddr * +ea_create(void) +{ + x86_effaddr *x86_ea = yasm_xmalloc(sizeof(x86_effaddr)); + + yasm_value_initialize(&x86_ea->ea.disp, NULL, 0); + x86_ea->ea.need_nonzero_len = 0; + x86_ea->ea.need_disp = 0; + x86_ea->ea.nosplit = 0; + x86_ea->ea.strong = 0; + x86_ea->ea.segreg = 0; + x86_ea->ea.pc_rel = 0; + x86_ea->ea.not_pc_rel = 0; + x86_ea->ea.data_len = 0; + x86_ea->vsib_mode = 0; + x86_ea->modrm = 0; + x86_ea->valid_modrm = 0; + x86_ea->need_modrm = 0; + x86_ea->sib = 0; + x86_ea->valid_sib = 0; + x86_ea->need_sib = 0; + + return x86_ea; +} + +x86_effaddr * +yasm_x86__ea_create_reg(x86_effaddr *x86_ea, unsigned long reg, + unsigned char *rex, unsigned int bits) +{ + unsigned char rm; + + if (yasm_x86__set_rex_from_reg(rex, &rm, reg, bits, X86_REX_B)) + return NULL; + + if (!x86_ea) + x86_ea = ea_create(); + x86_ea->modrm = 0xC0 | rm; /* Mod=11, R/M=Reg, Reg=0 */ + x86_ea->valid_modrm = 1; + x86_ea->need_modrm = 1; + + return x86_ea; +} + +yasm_effaddr * +yasm_x86__ea_create_expr(yasm_arch *arch, yasm_expr *e) +{ + yasm_arch_x86 *arch_x86 = (yasm_arch_x86 *)arch; + x86_effaddr *x86_ea; + + x86_ea = ea_create(); + + if (arch_x86->parser == X86_PARSER_GAS) { + /* Need to change foo+rip into foo wrt rip (even in .intel_syntax mode). + * Note this assumes a particular ordering coming from the parser + * to work (it's not very smart)! + */ + if (e->op == YASM_EXPR_ADD && e->terms[0].type == YASM_EXPR_REG + && e->terms[0].data.reg == X86_RIP) { + /* replace register with 0 */ + e->terms[0].type = YASM_EXPR_INT; + e->terms[0].data.intn = yasm_intnum_create_uint(0); + /* build new wrt expression */ + e = yasm_expr_create(YASM_EXPR_WRT, yasm_expr_expr(e), + yasm_expr_reg(X86_RIP), e->line); + } + } + yasm_value_initialize(&x86_ea->ea.disp, e, 0); + x86_ea->ea.need_disp = 1; + x86_ea->need_modrm = 1; + /* We won't know whether we need an SIB until we know more about expr and + * the BITS/address override setting. + */ + x86_ea->need_sib = 0xff; + + x86_ea->ea.data_len = 0; + + return (yasm_effaddr *)x86_ea; +} + +/*@-compmempass@*/ +x86_effaddr * +yasm_x86__ea_create_imm(x86_effaddr *x86_ea, yasm_expr *imm, + unsigned int im_len) +{ + if (!x86_ea) + x86_ea = ea_create(); + yasm_value_initialize(&x86_ea->ea.disp, imm, im_len); + x86_ea->ea.need_disp = 1; + + return x86_ea; +} +/*@=compmempass@*/ + +void +yasm_x86__bc_apply_prefixes(x86_common *common, unsigned char *rex, + unsigned int def_opersize_64, + unsigned int num_prefixes, uintptr_t *prefixes) +{ + unsigned int i; + int first = 1; + + for (i=0; i<num_prefixes; i++) { + switch ((x86_parse_insn_prefix)(prefixes[i] & 0xff00)) { + /*To be accurate, we should enforce that TSX hints come only with a + predefined set of instructions, and in most cases only with F0 + prefix. Otherwise they will have completely different semantics. + But F0 prefix can come only with a predefined set of instructions + too. And if it comes with other instructions, CPU will #UD. + Hence, F0-applicability should be enforced too. But it's not + currently. Maybe it is the decision made, that user should know + himself what he is doing with LOCK prefix. In this case, we should + not enforce TSX hints applicability too. And let user take care of + correct usage of TSX hints. + That is what we are going to do.*/ + case X86_ACQREL: + if (common->acqrel_pre != 0) + yasm_warn_set(YASM_WARN_GENERAL, + N_("multiple XACQUIRE/XRELEASE prefixes, " + "using leftmost")); + common->acqrel_pre = (unsigned char)prefixes[i] & 0xff; + break; + case X86_LOCKREP: + if (common->lockrep_pre != 0) + yasm_warn_set(YASM_WARN_GENERAL, + N_("multiple LOCK or REP prefixes, using leftmost")); + common->lockrep_pre = (unsigned char)prefixes[i] & 0xff; + break; + case X86_ADDRSIZE: + common->addrsize = (unsigned char)prefixes[i] & 0xff; + break; + case X86_OPERSIZE: + common->opersize = (unsigned char)prefixes[i] & 0xff; + if (common->mode_bits == 64 && common->opersize == 64 && + def_opersize_64 != 64) { + if (!rex) + yasm_warn_set(YASM_WARN_GENERAL, + N_("ignoring REX prefix on jump")); + else if (*rex == 0xff) + yasm_warn_set(YASM_WARN_GENERAL, + N_("REX prefix not allowed on this instruction, ignoring")); + else + *rex = 0x48; + } + break; + case X86_SEGREG: + /* This is a hack.. we should really be putting this in the + * the effective address! + */ + common->lockrep_pre = (unsigned char)prefixes[i] & 0xff; + break; + case X86_REX: + if (!rex) + yasm_warn_set(YASM_WARN_GENERAL, + N_("ignoring REX prefix on jump")); + else if (*rex == 0xff) + yasm_warn_set(YASM_WARN_GENERAL, + N_("REX prefix not allowed on this instruction, ignoring")); + else { + if (*rex != 0) { + if (first) + yasm_warn_set(YASM_WARN_GENERAL, + N_("overriding generated REX prefix")); + else + yasm_warn_set(YASM_WARN_GENERAL, + N_("multiple REX prefixes, using leftmost")); + } + /* Here we assume that we can't get this prefix in non + * 64 bit mode due to checks in parse_check_prefix(). + */ + common->mode_bits = 64; + *rex = (unsigned char)prefixes[i] & 0xff; + } + first = 0; + break; + } + } +} + +static void +x86_bc_insn_destroy(void *contents) +{ + x86_insn *insn = (x86_insn *)contents; + if (insn->x86_ea) + yasm_x86__ea_destroy((yasm_effaddr *)insn->x86_ea); + if (insn->imm) { + yasm_value_delete(insn->imm); + yasm_xfree(insn->imm); + } + yasm_xfree(contents); +} + +static void +x86_bc_jmp_destroy(void *contents) +{ + x86_jmp *jmp = (x86_jmp *)contents; + yasm_value_delete(&jmp->target); + yasm_xfree(contents); +} + +static void +x86_bc_jmpfar_destroy(void *contents) +{ + x86_jmpfar *jmpfar = (x86_jmpfar *)contents; + yasm_value_delete(&jmpfar->segment); + yasm_value_delete(&jmpfar->offset); + yasm_xfree(contents); +} + +void +yasm_x86__ea_destroy(yasm_effaddr *ea) +{ + yasm_value_delete(&ea->disp); + yasm_xfree(ea); +} + +void +yasm_x86__ea_print(const yasm_effaddr *ea, FILE *f, int indent_level) +{ + const x86_effaddr *x86_ea = (const x86_effaddr *)ea; + fprintf(f, "%*sDisp:\n", indent_level, ""); + yasm_value_print(&ea->disp, f, indent_level+1); + fprintf(f, "%*sNoSplit=%u\n", indent_level, "", (unsigned int)ea->nosplit); + fprintf(f, "%*sSegmentOv=%02x\n", indent_level, "", + (unsigned int)x86_ea->ea.segreg); + fprintf(f, "%*sVSIBMode=%u\n", indent_level, "", + (unsigned int)x86_ea->vsib_mode); + fprintf(f, "%*sModRM=%03o ValidRM=%u NeedRM=%u\n", indent_level, "", + (unsigned int)x86_ea->modrm, (unsigned int)x86_ea->valid_modrm, + (unsigned int)x86_ea->need_modrm); + fprintf(f, "%*sSIB=%03o ValidSIB=%u NeedSIB=%u\n", indent_level, "", + (unsigned int)x86_ea->sib, (unsigned int)x86_ea->valid_sib, + (unsigned int)x86_ea->need_sib); +} + +static void +x86_common_print(const x86_common *common, FILE *f, int indent_level) +{ + fprintf(f, "%*sAddrSize=%u OperSize=%u LockRepPre=%02x " + "ACQREL_Pre=%02x BITS=%u\n", + indent_level, "", + (unsigned int)common->addrsize, + (unsigned int)common->opersize, + (unsigned int)common->lockrep_pre, + (unsigned int)common->acqrel_pre, + (unsigned int)common->mode_bits); +} + +static void +x86_opcode_print(const x86_opcode *opcode, FILE *f, int indent_level) +{ + fprintf(f, "%*sOpcode: %02x %02x %02x OpLen=%u\n", indent_level, "", + (unsigned int)opcode->opcode[0], + (unsigned int)opcode->opcode[1], + (unsigned int)opcode->opcode[2], + (unsigned int)opcode->len); +} + +static void +x86_bc_insn_print(const void *contents, FILE *f, int indent_level) +{ + const x86_insn *insn = (const x86_insn *)contents; + + fprintf(f, "%*s_Instruction_\n", indent_level, ""); + fprintf(f, "%*sEffective Address:", indent_level, ""); + if (insn->x86_ea) { + fprintf(f, "\n"); + yasm_x86__ea_print((yasm_effaddr *)insn->x86_ea, f, indent_level+1); + } else + fprintf(f, " (nil)\n"); + fprintf(f, "%*sImmediate Value:", indent_level, ""); + if (!insn->imm) + fprintf(f, " (nil)\n"); + else { + indent_level++; + fprintf(f, "\n"); + yasm_value_print(insn->imm, f, indent_level); + indent_level--; + } + x86_opcode_print(&insn->opcode, f, indent_level); + x86_common_print(&insn->common, f, indent_level); + fprintf(f, "%*sSpPre=%02x REX=%03o PostOp=%u\n", indent_level, "", + (unsigned int)insn->special_prefix, + (unsigned int)insn->rex, + (unsigned int)insn->postop); +} + +static void +x86_bc_jmp_print(const void *contents, FILE *f, int indent_level) +{ + const x86_jmp *jmp = (const x86_jmp *)contents; + + fprintf(f, "%*s_Jump_\n", indent_level, ""); + fprintf(f, "%*sTarget:\n", indent_level, ""); + yasm_value_print(&jmp->target, f, indent_level+1); + /* FIXME + fprintf(f, "%*sOrigin=\n", indent_level, ""); + yasm_symrec_print(jmp->origin, f, indent_level+1); + */ + fprintf(f, "\n%*sShort Form:\n", indent_level, ""); + if (jmp->shortop.len == 0) + fprintf(f, "%*sNone\n", indent_level+1, ""); + else + x86_opcode_print(&jmp->shortop, f, indent_level+1); + fprintf(f, "%*sNear Form:\n", indent_level, ""); + if (jmp->nearop.len == 0) + fprintf(f, "%*sNone\n", indent_level+1, ""); + else + x86_opcode_print(&jmp->nearop, f, indent_level+1); + fprintf(f, "%*sOpSel=", indent_level, ""); + switch (jmp->op_sel) { + case JMP_NONE: + fprintf(f, "None"); + break; + case JMP_SHORT: + fprintf(f, "Short"); + break; + case JMP_NEAR: + fprintf(f, "Near"); + break; + case JMP_SHORT_FORCED: + fprintf(f, "Forced Short"); + break; + case JMP_NEAR_FORCED: + fprintf(f, "Forced Near"); + break; + default: + fprintf(f, "UNKNOWN!!"); + break; + } + x86_common_print(&jmp->common, f, indent_level); +} + +static void +x86_bc_jmpfar_print(const void *contents, FILE *f, int indent_level) +{ + const x86_jmpfar *jmpfar = (const x86_jmpfar *)contents; + + fprintf(f, "%*s_Far_Jump_\n", indent_level, ""); + fprintf(f, "%*sSegment:\n", indent_level, ""); + yasm_value_print(&jmpfar->segment, f, indent_level+1); + fprintf(f, "%*sOffset:\n", indent_level, ""); + yasm_value_print(&jmpfar->offset, f, indent_level+1); + x86_opcode_print(&jmpfar->opcode, f, indent_level); + x86_common_print(&jmpfar->common, f, indent_level); +} + +static unsigned int +x86_common_calc_len(const x86_common *common) +{ + unsigned int len = 0; + + if (common->addrsize != 0 && common->addrsize != common->mode_bits) + len++; + if (common->opersize != 0 && + ((common->mode_bits != 64 && common->opersize != common->mode_bits) || + (common->mode_bits == 64 && common->opersize == 16))) + len++; + if (common->lockrep_pre != 0) + len++; + if (common->acqrel_pre != 0) + len++; + + + return len; +} + +static int +x86_bc_insn_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span, + void *add_span_data) +{ + x86_insn *insn = (x86_insn *)bc->contents; + x86_effaddr *x86_ea = insn->x86_ea; + yasm_value *imm = insn->imm; + + if (x86_ea) { + /* Check validity of effective address and calc R/M bits of + * Mod/RM byte and SIB byte. We won't know the Mod field + * of the Mod/RM byte until we know more about the + * displacement. + */ + if (yasm_x86__expr_checkea(x86_ea, &insn->common.addrsize, + insn->common.mode_bits, insn->postop == X86_POSTOP_ADDRESS16, + &insn->rex, bc)) + /* failed, don't bother checking rest of insn */ + return -1; + + if (x86_ea->ea.disp.size == 0 && x86_ea->ea.need_nonzero_len) { + /* Handle unknown case, default to byte-sized and set as + * critical expression. + */ + x86_ea->ea.disp.size = 8; + add_span(add_span_data, bc, 1, &x86_ea->ea.disp, -128, 127); + } + bc->len += x86_ea->ea.disp.size/8; + + /* Handle address16 postop case */ + if (insn->postop == X86_POSTOP_ADDRESS16) + insn->common.addrsize = 0; + + /* Compute length of ea and add to total */ + bc->len += x86_ea->need_modrm + (x86_ea->need_sib ? 1:0); + bc->len += (x86_ea->ea.segreg != 0) ? 1 : 0; + } + + if (imm) { + unsigned int immlen = imm->size; + + /* TODO: check imm->len vs. sized len from expr? */ + + /* Handle signext_imm8 postop special-casing */ + if (insn->postop == X86_POSTOP_SIGNEXT_IMM8) { + /*@null@*/ /*@only@*/ yasm_intnum *num; + num = yasm_value_get_intnum(imm, NULL, 0); + + if (!num) { + /* Unknown; default to byte form and set as critical + * expression. + */ + immlen = 8; + add_span(add_span_data, bc, 2, imm, -128, 127); + } else { + if (yasm_intnum_in_range(num, -128, 127)) { + /* We can use the sign-extended byte form: shorten + * the immediate length to 1 and make the byte form + * permanent. + */ + imm->size = 8; + imm->sign = 1; + immlen = 8; + } else { + /* We can't. Copy over the word-sized opcode. */ + insn->opcode.opcode[0] = + insn->opcode.opcode[insn->opcode.len]; + insn->opcode.len = 1; + } + insn->postop = X86_POSTOP_NONE; + yasm_intnum_destroy(num); + } + } + + bc->len += immlen/8; + } + + /* VEX and XOP prefixes never have REX (it's embedded in the opcode). + * For VEX, we can come into this function with the three byte form, + * so we need to see if we can optimize to the two byte form. + * We can't do it earlier, as we don't know all of the REX byte until now. + */ + if (insn->special_prefix == 0xC4) { + /* See if we can shorten the VEX prefix to its two byte form. + * In order to do this, REX.X, REX.B, and REX.W/VEX.W must all be 0, + * and the VEX mmmmm field must be 1. + */ + if ((insn->opcode.opcode[0] & 0x1F) == 1 && + (insn->opcode.opcode[1] & 0x80) == 0 && + (insn->rex == 0xff || (insn->rex & 0x0B) == 0)) { + insn->opcode.opcode[0] = insn->opcode.opcode[1]; + insn->opcode.opcode[1] = insn->opcode.opcode[2]; + insn->opcode.opcode[2] = 0; /* sanity */ + insn->opcode.len = 2; + insn->special_prefix = 0xC5; /* mark as two-byte VEX */ + } + } else if (insn->rex != 0xff && insn->rex != 0 && + insn->special_prefix != 0xC5 && insn->special_prefix != 0x8F) + bc->len++; + + bc->len += insn->opcode.len; + bc->len += x86_common_calc_len(&insn->common); + bc->len += (insn->special_prefix != 0) ? 1:0; + return 0; +} + +static int +x86_bc_insn_expand(yasm_bytecode *bc, int span, long old_val, long new_val, + /*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres) +{ + x86_insn *insn = (x86_insn *)bc->contents; + x86_effaddr *x86_ea = insn->x86_ea; + yasm_effaddr *ea = &x86_ea->ea; + yasm_value *imm = insn->imm; + + if (ea && span == 1) { + /* Change displacement length into word-sized */ + if (ea->disp.size == 8) { + ea->disp.size = (insn->common.addrsize == 16) ? 16 : 32; + x86_ea->modrm &= ~0300; + x86_ea->modrm |= 0200; + bc->len--; + bc->len += ea->disp.size/8; + } + } + + if (imm && span == 2) { + if (insn->postop == X86_POSTOP_SIGNEXT_IMM8) { + /* Update bc->len for new opcode and immediate size */ + bc->len -= insn->opcode.len; + bc->len += imm->size/8; + + /* Change to the word-sized opcode */ + insn->opcode.opcode[0] = insn->opcode.opcode[insn->opcode.len]; + insn->opcode.len = 1; + insn->postop = X86_POSTOP_NONE; + } + } + + return 0; +} + +static int +x86_bc_jmp_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span, + void *add_span_data) +{ + x86_jmp *jmp = (x86_jmp *)bc->contents; + yasm_bytecode *target_prevbc; + unsigned char opersize; + + /* As opersize may be 0, figure out its "real" value. */ + opersize = (jmp->common.opersize == 0) ? + jmp->common.mode_bits : jmp->common.opersize; + + bc->len += x86_common_calc_len(&jmp->common); + + if (jmp->op_sel == JMP_NEAR_FORCED || jmp->shortop.len == 0) { + if (jmp->nearop.len == 0) { + yasm_error_set(YASM_ERROR_TYPE, N_("near jump does not exist")); + return -1; + } + + /* Near jump, no spans needed */ + if (jmp->shortop.len == 0) + jmp->op_sel = JMP_NEAR; + bc->len += jmp->nearop.len; + bc->len += (opersize == 16) ? 2 : 4; + return 0; + } + + if (jmp->op_sel == JMP_SHORT_FORCED || jmp->nearop.len == 0) { + if (jmp->shortop.len == 0) { + yasm_error_set(YASM_ERROR_TYPE, N_("short jump does not exist")); + return -1; + } + + /* We want to be sure to error if we exceed short length, so + * put it in as a dependent expression (falling through). + */ + } + + if (jmp->target.rel + && (!yasm_symrec_get_label(jmp->target.rel, &target_prevbc) + || target_prevbc->section != bc->section)) { + /* External or out of segment, so we can't check distance. + * Allowing short jumps depends on the objfmt supporting + * 8-bit relocs. While most don't, some might, so allow it here. + * Otherwise default to word-sized. + * The objfmt will error if not supported. + */ + if (jmp->op_sel == JMP_SHORT_FORCED || jmp->nearop.len == 0) { + if (jmp->op_sel == JMP_NONE) + jmp->op_sel = JMP_SHORT; + bc->len += jmp->shortop.len + 1; + } else { + jmp->op_sel = JMP_NEAR; + bc->len += jmp->nearop.len; + bc->len += (opersize == 16) ? 2 : 4; + } + return 0; + } + + /* Default to short jump and generate span */ + if (jmp->op_sel == JMP_NONE) + jmp->op_sel = JMP_SHORT; + bc->len += jmp->shortop.len + 1; + add_span(add_span_data, bc, 1, &jmp->target, -128+(long)bc->len, + 127+(long)bc->len); + return 0; +} + +static int +x86_bc_jmp_expand(yasm_bytecode *bc, int span, long old_val, long new_val, + /*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres) +{ + x86_jmp *jmp = (x86_jmp *)bc->contents; + unsigned char opersize; + + if (span != 1) + yasm_internal_error(N_("unrecognized span id")); + + /* As opersize may be 0, figure out its "real" value. */ + opersize = (jmp->common.opersize == 0) ? + jmp->common.mode_bits : jmp->common.opersize; + + if (jmp->op_sel == JMP_SHORT_FORCED || jmp->nearop.len == 0) { + yasm_error_set(YASM_ERROR_VALUE, N_("short jump out of range")); + return -1; + } + + if (jmp->op_sel == JMP_NEAR) + yasm_internal_error(N_("trying to expand an already-near jump")); + + /* Upgrade to a near jump */ + jmp->op_sel = JMP_NEAR; + bc->len -= jmp->shortop.len + 1; + bc->len += jmp->nearop.len; + bc->len += (opersize == 16) ? 2 : 4; + + return 0; +} + +static int +x86_bc_jmpfar_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span, + void *add_span_data) +{ + x86_jmpfar *jmpfar = (x86_jmpfar *)bc->contents; + unsigned char opersize; + + opersize = (jmpfar->common.opersize == 0) ? + jmpfar->common.mode_bits : jmpfar->common.opersize; + + bc->len += jmpfar->opcode.len; + bc->len += 2; /* segment */ + bc->len += (opersize == 16) ? 2 : 4; + bc->len += x86_common_calc_len(&jmpfar->common); + + return 0; +} + +static void +x86_common_tobytes(const x86_common *common, unsigned char **bufp, + unsigned int segreg) +{ + if (segreg != 0) + YASM_WRITE_8(*bufp, (unsigned char)segreg); + if (common->addrsize != 0 && common->addrsize != common->mode_bits) + YASM_WRITE_8(*bufp, 0x67); + if (common->opersize != 0 && + ((common->mode_bits != 64 && common->opersize != common->mode_bits) || + (common->mode_bits == 64 && common->opersize == 16))) + YASM_WRITE_8(*bufp, 0x66); + /*TSX hints come before lock prefix*/ + if (common->acqrel_pre != 0) + YASM_WRITE_8(*bufp, common->acqrel_pre); + if (common->lockrep_pre != 0) + YASM_WRITE_8(*bufp, common->lockrep_pre); +} + +static void +x86_opcode_tobytes(const x86_opcode *opcode, unsigned char **bufp) +{ + unsigned int i; + for (i=0; i<opcode->len; i++) + YASM_WRITE_8(*bufp, opcode->opcode[i]); +} + +static int +x86_bc_insn_tobytes(yasm_bytecode *bc, unsigned char **bufp, + unsigned char *bufstart, void *d, + yasm_output_value_func output_value, + /*@unused@*/ yasm_output_reloc_func output_reloc) +{ + x86_insn *insn = (x86_insn *)bc->contents; + /*@null@*/ x86_effaddr *x86_ea = (x86_effaddr *)insn->x86_ea; + yasm_value *imm = insn->imm; + + /* Prefixes */ + x86_common_tobytes(&insn->common, bufp, + x86_ea ? (unsigned int)(x86_ea->ea.segreg>>8) : 0); + if (insn->special_prefix != 0) + YASM_WRITE_8(*bufp, insn->special_prefix); + if (insn->special_prefix == 0xC4 || insn->special_prefix == 0x8F) { + /* 3-byte VEX/XOP; merge in 1s complement of REX.R, REX.X, REX.B */ + insn->opcode.opcode[0] &= 0x1F; + if (insn->rex != 0xff) + insn->opcode.opcode[0] |= ((~insn->rex) & 0x07) << 5; + /* merge REX.W via ORing; there should never be a case in which REX.W + * is important when VEX.W is already set by the instruction. + */ + if (insn->rex != 0xff && (insn->rex & 0x8) != 0) + insn->opcode.opcode[1] |= 0x80; + } else if (insn->special_prefix == 0xC5) { + /* 2-byte VEX; merge in 1s complement of REX.R */ + insn->opcode.opcode[0] &= 0x7F; + if (insn->rex != 0xff && (insn->rex & 0x4) == 0) + insn->opcode.opcode[0] |= 0x80; + /* No other REX bits should be set */ + if (insn->rex != 0xff && (insn->rex & 0xB) != 0) + yasm_internal_error(N_("x86: REX.WXB set, but 2-byte VEX")); + } else if (insn->rex != 0xff && insn->rex != 0) { + if (insn->common.mode_bits != 64) + yasm_internal_error(N_("x86: got a REX prefix in non-64-bit mode")); + YASM_WRITE_8(*bufp, insn->rex); + } + + /* Opcode */ + x86_opcode_tobytes(&insn->opcode, bufp); + + /* Effective address: ModR/M (if required), SIB (if required), and + * displacement (if required). + */ + if (x86_ea) { + if (x86_ea->need_modrm) { + if (!x86_ea->valid_modrm) + yasm_internal_error(N_("invalid Mod/RM in x86 tobytes_insn")); + YASM_WRITE_8(*bufp, x86_ea->modrm); + } + + if (x86_ea->need_sib) { + if (!x86_ea->valid_sib) + yasm_internal_error(N_("invalid SIB in x86 tobytes_insn")); + YASM_WRITE_8(*bufp, x86_ea->sib); + } + + if (x86_ea->ea.need_disp) { + unsigned int disp_len = x86_ea->ea.disp.size/8; + + if (x86_ea->ea.disp.ip_rel) { + /* Adjust relative displacement to end of bytecode */ + /*@only@*/ yasm_intnum *delta; + delta = yasm_intnum_create_int(-(long)bc->len); + if (!x86_ea->ea.disp.abs) + x86_ea->ea.disp.abs = + yasm_expr_create_ident(yasm_expr_int(delta), bc->line); + else + x86_ea->ea.disp.abs = + yasm_expr_create(YASM_EXPR_ADD, + yasm_expr_expr(x86_ea->ea.disp.abs), + yasm_expr_int(delta), bc->line); + } + if (output_value(&x86_ea->ea.disp, *bufp, disp_len, + (unsigned long)(*bufp-bufstart), bc, 1, d)) + return 1; + *bufp += disp_len; + } + } + + /* Immediate (if required) */ + if (imm) { + unsigned int imm_len; + if (insn->postop == X86_POSTOP_SIGNEXT_IMM8) { + /* If we got here with this postop still set, we need to force + * imm size to 8 here. + */ + imm->size = 8; + imm->sign = 1; + imm_len = 1; + } else + imm_len = imm->size/8; + if (output_value(imm, *bufp, imm_len, (unsigned long)(*bufp-bufstart), + bc, 1, d)) + return 1; + *bufp += imm_len; + } + + return 0; +} + +static int +x86_bc_jmp_tobytes(yasm_bytecode *bc, unsigned char **bufp, + unsigned char *bufstart, void *d, + yasm_output_value_func output_value, + /*@unused@*/ yasm_output_reloc_func output_reloc) +{ + x86_jmp *jmp = (x86_jmp *)bc->contents; + unsigned char opersize; + unsigned int i; + /*@only@*/ yasm_intnum *delta; + + /* Prefixes */ + x86_common_tobytes(&jmp->common, bufp, 0); + + /* As opersize may be 0, figure out its "real" value. */ + opersize = (jmp->common.opersize == 0) ? + jmp->common.mode_bits : jmp->common.opersize; + + /* Check here again to see if forms are actually legal. */ + switch (jmp->op_sel) { + case JMP_SHORT_FORCED: + case JMP_SHORT: + /* 1 byte relative displacement */ + if (jmp->shortop.len == 0) + yasm_internal_error(N_("short jump does not exist")); + + /* Opcode */ + x86_opcode_tobytes(&jmp->shortop, bufp); + + /* Adjust relative displacement to end of bytecode */ + delta = yasm_intnum_create_int(-(long)bc->len); + if (!jmp->target.abs) + jmp->target.abs = yasm_expr_create_ident(yasm_expr_int(delta), + bc->line); + else + jmp->target.abs = + yasm_expr_create(YASM_EXPR_ADD, + yasm_expr_expr(jmp->target.abs), + yasm_expr_int(delta), bc->line); + + jmp->target.size = 8; + jmp->target.sign = 1; + if (output_value(&jmp->target, *bufp, 1, + (unsigned long)(*bufp-bufstart), bc, 1, d)) + return 1; + *bufp += 1; + break; + case JMP_NEAR_FORCED: + case JMP_NEAR: + /* 2/4 byte relative displacement (depending on operand size) */ + if (jmp->nearop.len == 0) { + yasm_error_set(YASM_ERROR_TYPE, + N_("near jump does not exist")); + return 1; + } + + /* Opcode */ + x86_opcode_tobytes(&jmp->nearop, bufp); + + i = (opersize == 16) ? 2 : 4; + + /* Adjust relative displacement to end of bytecode */ + delta = yasm_intnum_create_int(-(long)bc->len); + if (!jmp->target.abs) + jmp->target.abs = yasm_expr_create_ident(yasm_expr_int(delta), + bc->line); + else + jmp->target.abs = + yasm_expr_create(YASM_EXPR_ADD, + yasm_expr_expr(jmp->target.abs), + yasm_expr_int(delta), bc->line); + + jmp->target.size = i*8; + jmp->target.sign = 1; + if (output_value(&jmp->target, *bufp, i, + (unsigned long)(*bufp-bufstart), bc, 1, d)) + return 1; + *bufp += i; + break; + case JMP_NONE: + yasm_internal_error(N_("jump op_sel cannot be JMP_NONE in tobytes")); + default: + yasm_internal_error(N_("unrecognized relative jump op_sel")); + } + return 0; +} + +static int +x86_bc_jmpfar_tobytes(yasm_bytecode *bc, unsigned char **bufp, + unsigned char *bufstart, void *d, + yasm_output_value_func output_value, + /*@unused@*/ yasm_output_reloc_func output_reloc) +{ + x86_jmpfar *jmpfar = (x86_jmpfar *)bc->contents; + unsigned int i; + unsigned char opersize; + + x86_common_tobytes(&jmpfar->common, bufp, 0); + x86_opcode_tobytes(&jmpfar->opcode, bufp); + + /* As opersize may be 0, figure out its "real" value. */ + opersize = (jmpfar->common.opersize == 0) ? + jmpfar->common.mode_bits : jmpfar->common.opersize; + + /* Absolute displacement: segment and offset */ + i = (opersize == 16) ? 2 : 4; + jmpfar->offset.size = i*8; + if (output_value(&jmpfar->offset, *bufp, i, + (unsigned long)(*bufp-bufstart), bc, 1, d)) + return 1; + *bufp += i; + jmpfar->segment.size = 16; + if (output_value(&jmpfar->segment, *bufp, 2, + (unsigned long)(*bufp-bufstart), bc, 1, d)) + return 1; + *bufp += 2; + + return 0; +} + +int +yasm_x86__intnum_tobytes(yasm_arch *arch, const yasm_intnum *intn, + unsigned char *buf, size_t destsize, size_t valsize, + int shift, const yasm_bytecode *bc, int warn) +{ + /* Write value out. */ + yasm_intnum_get_sized(intn, buf, destsize, valsize, shift, 0, warn); + return 0; +} diff --git a/contrib/tools/yasm/modules/arch/x86/x86expr.c b/contrib/tools/yasm/modules/arch/x86/x86expr.c index e9ddcce57e..141cdec2bf 100644 --- a/contrib/tools/yasm/modules/arch/x86/x86expr.c +++ b/contrib/tools/yasm/modules/arch/x86/x86expr.c @@ -1,1061 +1,1061 @@ -/* - * x86 expression handling - * - * Copyright (C) 2001-2007 Peter Johnson - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ -#include <util.h> - -#include <libyasm.h> - -#include "x86arch.h" - - -typedef struct x86_checkea_reg3264_data { - int *regs; /* total multiplier for each reg */ - unsigned char vsib_mode; - unsigned char bits; - unsigned char addrsize; -} x86_checkea_reg3264_data; - -/* Only works if ei->type == EXPR_REG (doesn't check). - * Overwrites ei with intnum of 0 (to eliminate regs from the final expr). - */ -static /*@null@*/ /*@dependent@*/ int * -x86_expr_checkea_get_reg3264(yasm_expr__item *ei, int *regnum, - /*returned*/ void *d) -{ - x86_checkea_reg3264_data *data = d; - - switch ((x86_expritem_reg_size)(ei->data.reg & ~0xFUL)) { - case X86_REG32: - if (data->addrsize != 32) - return 0; - *regnum = (unsigned int)(ei->data.reg & 0xF); - break; - case X86_REG64: - if (data->addrsize != 64) - return 0; - *regnum = (unsigned int)(ei->data.reg & 0xF); - break; - case X86_XMMREG: - if (data->vsib_mode != 1) - return 0; - if (data->bits != 64 && (ei->data.reg & 0x8) == 0x8) - return 0; - *regnum = 17+(unsigned int)(ei->data.reg & 0xF); - break; - case X86_YMMREG: - if (data->vsib_mode != 2) - return 0; - if (data->bits != 64 && (ei->data.reg & 0x8) == 0x8) - return 0; - *regnum = 17+(unsigned int)(ei->data.reg & 0xF); - break; - case X86_RIP: - if (data->bits != 64) - return 0; - *regnum = 16; - break; - default: - return 0; - } - - /* overwrite with 0 to eliminate register from displacement expr */ - ei->type = YASM_EXPR_INT; - ei->data.intn = yasm_intnum_create_uint(0); - - /* we're okay */ - return &data->regs[*regnum]; -} - -typedef struct x86_checkea_reg16_data { - int bx, si, di, bp; /* total multiplier for each reg */ -} x86_checkea_reg16_data; - -/* Only works if ei->type == EXPR_REG (doesn't check). - * Overwrites ei with intnum of 0 (to eliminate regs from the final expr). - */ -static /*@null@*/ int * -x86_expr_checkea_get_reg16(yasm_expr__item *ei, int *regnum, void *d) -{ - x86_checkea_reg16_data *data = d; - /* in order: ax,cx,dx,bx,sp,bp,si,di */ - /*@-nullassign@*/ - static int *reg16[8] = {0,0,0,0,0,0,0,0}; - /*@=nullassign@*/ - - reg16[3] = &data->bx; - reg16[5] = &data->bp; - reg16[6] = &data->si; - reg16[7] = &data->di; - - /* don't allow 32-bit registers */ - if ((ei->data.reg & ~0xFUL) != X86_REG16) - return 0; - - /* & 7 for sanity check */ - *regnum = (unsigned int)(ei->data.reg & 0x7); - - /* only allow BX, SI, DI, BP */ - if (!reg16[*regnum]) - return 0; - - /* overwrite with 0 to eliminate register from displacement expr */ - ei->type = YASM_EXPR_INT; - ei->data.intn = yasm_intnum_create_uint(0); - - /* we're okay */ - return reg16[*regnum]; -} - -/* Distribute over registers to help bring them to the topmost level of e. - * Also check for illegal operations against registers. - * Returns 0 if something was illegal, 1 if legal and nothing in e changed, - * and 2 if legal and e needs to be simplified. - * - * Only half joking: Someday make this/checkea able to accept crazy things - * like: (bx+di)*(bx+di)-bx*bx-2*bx*di-di*di+di? Probably not: NASM never - * accepted such things, and it's doubtful such an expn is valid anyway - * (even though the above one is). But even macros would be hard-pressed - * to generate something like this. - * - * e must already have been simplified for this function to work properly - * (as it doesn't think things like SUB are valid). - * - * IMPLEMENTATION NOTE: About the only thing this function really needs to - * "distribute" is: (non-float-expn or intnum) * (sum expn of registers). - * - * TODO: Clean up this code, make it easier to understand. - */ -static int -x86_expr_checkea_distcheck_reg(yasm_expr **ep, unsigned int bits) -{ - yasm_expr *e = *ep; - int i; - int havereg = -1, havereg_expr = -1; - int retval = 1; /* default to legal, no changes */ - - for (i=0; i<e->numterms; i++) { - switch (e->terms[i].type) { - case YASM_EXPR_REG: - /* Check op to make sure it's valid to use w/register. */ - switch (e->op) { - case YASM_EXPR_MUL: - /* Check for reg*reg */ - if (havereg != -1) - return 0; - break; - case YASM_EXPR_ADD: - case YASM_EXPR_IDENT: - break; - default: - return 0; - } - havereg = i; - break; - case YASM_EXPR_FLOAT: - /* Floats not allowed. */ - return 0; - case YASM_EXPR_EXPR: - if (yasm_expr__contains(e->terms[i].data.expn, - YASM_EXPR_REG)) { - int ret2; - - /* Check op to make sure it's valid to use w/register. */ - if (e->op != YASM_EXPR_ADD && e->op != YASM_EXPR_MUL) - return 0; - /* Check for reg*reg */ - if (e->op == YASM_EXPR_MUL && havereg != -1) - return 0; - havereg = i; - havereg_expr = i; - /* Recurse to check lower levels */ - ret2 = - x86_expr_checkea_distcheck_reg(&e->terms[i].data.expn, - bits); - if (ret2 == 0) - return 0; - if (ret2 == 2) - retval = 2; - } else if (yasm_expr__contains(e->terms[i].data.expn, - YASM_EXPR_FLOAT)) - return 0; /* Disallow floats */ - break; - default: - break; - } - } - - /* just exit if no registers were used */ - if (havereg == -1) - return retval; - - /* Distribute */ - if (e->op == YASM_EXPR_MUL && havereg_expr != -1) { - yasm_expr *ne; - - retval = 2; /* we're going to change it */ - - /* The reg expn *must* be EXPR_ADD at this point. Sanity check. */ - if (e->terms[havereg_expr].type != YASM_EXPR_EXPR || - e->terms[havereg_expr].data.expn->op != YASM_EXPR_ADD) - yasm_internal_error(N_("Register expression not ADD or EXPN")); - - /* Iterate over each term in reg expn */ - for (i=0; i<e->terms[havereg_expr].data.expn->numterms; i++) { - /* Copy everything EXCEPT havereg_expr term into new expression */ - ne = yasm_expr__copy_except(e, havereg_expr); - assert(ne != NULL); - /* Copy reg expr term into uncopied (empty) term in new expn */ - ne->terms[havereg_expr] = - e->terms[havereg_expr].data.expn->terms[i]; /* struct copy */ - /* Overwrite old reg expr term with new expn */ - e->terms[havereg_expr].data.expn->terms[i].type = YASM_EXPR_EXPR; - e->terms[havereg_expr].data.expn->terms[i].data.expn = ne; - } - - /* Replace e with expanded reg expn */ - ne = e->terms[havereg_expr].data.expn; - e->terms[havereg_expr].type = YASM_EXPR_NONE; /* don't delete it! */ - yasm_expr_destroy(e); /* but everything else */ - e = ne; - /*@-onlytrans@*/ - *ep = ne; - /*@=onlytrans@*/ - } - - return retval; -} - -/* Simplify and determine if expression is superficially valid: - * Valid expr should be [(int-equiv expn)]+[reg*(int-equiv expn)+...] - * where the [...] parts are optional. - * - * Don't simplify out constant identities if we're looking for an indexreg: we - * may need the multiplier for determining what the indexreg is! - * - * Returns 1 if invalid register usage, 2 if unable to determine all values, - * and 0 if all values successfully determined and saved in data. - */ -static int -x86_expr_checkea_getregusage(yasm_expr **ep, /*@null@*/ int *indexreg, - int *pcrel, unsigned int bits, void *data, - int *(*get_reg)(yasm_expr__item *ei, int *regnum, void *d)) -{ - int i; - int *reg; - int regnum; - int indexval = 0; - int indexmult = 0; - yasm_expr *e, *wrt; - - /*@-unqualifiedtrans@*/ - *ep = yasm_expr__level_tree(*ep, 1, 1, indexreg == 0, 0, NULL, NULL); - - /* Check for WRT rip first */ - wrt = yasm_expr_extract_wrt(ep); - if (wrt && wrt->op == YASM_EXPR_IDENT && - wrt->terms[0].type == YASM_EXPR_REG) { - if (bits != 64) { /* only valid in 64-bit mode */ - yasm_expr_destroy(wrt); - return 1; - } - reg = get_reg(&wrt->terms[0], ®num, data); - if (!reg || regnum != 16) { /* only accept rip */ - yasm_expr_destroy(wrt); - return 1; - } - (*reg)++; - - /* Delete WRT. Set pcrel to 1 to indicate to x86 - * bytecode code to do PC-relative displacement transform. - */ - *pcrel = 1; - yasm_expr_destroy(wrt); - } else if (wrt) { - yasm_expr_destroy(wrt); - return 1; - } - - /*@=unqualifiedtrans@*/ - assert(*ep != NULL); - e = *ep; - switch (x86_expr_checkea_distcheck_reg(ep, bits)) { - case 0: - return 1; - case 2: - /* Need to simplify again */ - *ep = yasm_expr__level_tree(*ep, 1, 1, indexreg == 0, 0, NULL, - NULL); - e = *ep; - break; - default: - break; - } - - switch (e->op) { - case YASM_EXPR_ADD: - /* Prescan for non-int multipliers against a reg. - * This is invalid due to the optimizer structure. - */ - for (i=0; i<e->numterms; i++) - if (e->terms[i].type == YASM_EXPR_EXPR) { - yasm_expr__order_terms(e->terms[i].data.expn); - if (e->terms[i].data.expn->terms[0].type == - YASM_EXPR_REG) { - if (e->terms[i].data.expn->numterms > 2) - return 1; - if (e->terms[i].data.expn->terms[1].type != - YASM_EXPR_INT) - return 1; - } - } - - /*@fallthrough@*/ - case YASM_EXPR_IDENT: - /* Check each term for register (and possible multiplier). */ - for (i=0; i<e->numterms; i++) { - if (e->terms[i].type == YASM_EXPR_REG) { - reg = get_reg(&e->terms[i], ®num, data); - if (!reg) - return 1; - (*reg)++; - /* Let last, largest multipler win indexreg */ - if (indexreg && *reg > 0 && indexval <= *reg && - !indexmult) { - *indexreg = regnum; - indexval = *reg; - } - } else if (e->terms[i].type == YASM_EXPR_EXPR) { - /* Already ordered from ADD above, just grab the value. - * Sanity check for EXPR_INT. - */ - if (e->terms[i].data.expn->terms[0].type == - YASM_EXPR_REG) { - long delta; - if (e->terms[i].data.expn->terms[1].type != - YASM_EXPR_INT) - yasm_internal_error( - N_("Non-integer value in reg expn")); - reg = get_reg(&e->terms[i].data.expn->terms[0], - ®num, data); - if (!reg) - return 1; - delta = yasm_intnum_get_int( - e->terms[i].data.expn->terms[1].data.intn); - (*reg) += delta; - /* Let last, largest multipler win indexreg */ - if (indexreg && delta > 0 && indexval <= *reg) { - *indexreg = regnum; - indexval = *reg; - indexmult = 1; - } else if (indexreg && *indexreg == regnum && - delta < 0 && *reg <= 1) { - *indexreg = -1; - indexval = 0; - indexmult = 0; - } - } - } - } - break; - case YASM_EXPR_MUL: - /* Here, too, check for non-int multipliers against a reg. */ - yasm_expr__order_terms(e); - if (e->terms[0].type == YASM_EXPR_REG) { - long delta; - if (e->numterms > 2) - return 1; - if (e->terms[1].type != YASM_EXPR_INT) - return 1; - reg = get_reg(&e->terms[0], ®num, data); - if (!reg) - return 1; - delta = yasm_intnum_get_int(e->terms[1].data.intn); - (*reg) += delta; - if (indexreg) - { - if (delta < 0 && *reg <= 1) - { - *indexreg = -1; - indexval = 0; - indexmult = 0; - } - else - *indexreg = regnum; - } - } - break; - case YASM_EXPR_SEGOFF: - /* No registers are allowed on either side. */ - if (yasm_expr__contains(e, YASM_EXPR_REG)) - return 1; - break; - default: - /* Should never get here! */ - yasm_internal_error(N_("unexpected expr op")); - } - - /* Simplify expr, which is now really just the displacement. This - * should get rid of the 0's we put in for registers in the callback. - */ - *ep = yasm_expr_simplify(*ep, 0); - /* e = *ep; */ - - return 0; -} - -/* Calculate the displacement length, if possible. - * Takes several extra inputs so it can be used by both 32-bit and 16-bit - * expressions: - * wordsize=16 for 16-bit, =32 for 32-bit. - * noreg=1 if the *ModRM byte* has no registers used. - * dispreq=1 if a displacement value is *required* (even if =0). - * Returns 0 if successfully calculated, 1 if not. - */ -/*@-nullstate@*/ -static int -x86_checkea_calc_displen(x86_effaddr *x86_ea, unsigned int wordsize, int noreg, - int dispreq) -{ - /*@null@*/ /*@only@*/ yasm_intnum *num; - - x86_ea->valid_modrm = 0; /* default to not yet valid */ - - switch (x86_ea->ea.disp.size) { - case 0: - break; - /* If not 0, the displacement length was forced; set the Mod bits - * appropriately and we're done with the ModRM byte. - */ - case 8: - /* Byte is only a valid override if there are registers in the - * EA. With no registers, we must have a 16/32 value. - */ - if (noreg) { - yasm_warn_set(YASM_WARN_IMPLICIT_SIZE_OVERRIDE, - N_("invalid displacement size; fixed")); - x86_ea->ea.disp.size = wordsize; - } else - x86_ea->modrm |= 0100; - x86_ea->valid_modrm = 1; - return 0; - case 16: - case 32: - /* Don't allow changing displacement different from BITS setting - * directly; require an address-size override to change it. - */ - if (wordsize != x86_ea->ea.disp.size) { - yasm_error_set(YASM_ERROR_VALUE, - N_("invalid effective address (displacement size)")); - return 1; - } - if (!noreg) - x86_ea->modrm |= 0200; - x86_ea->valid_modrm = 1; - return 0; - default: - /* we shouldn't ever get any other size! */ - yasm_internal_error(N_("strange EA displacement size")); - } - - /* The displacement length hasn't been forced (or the forcing wasn't - * valid), try to determine what it is. - */ - if (noreg) { - /* No register in ModRM expression, so it must be disp16/32, - * and as the Mod bits are set to 0 by the caller, we're done - * with the ModRM byte. - */ - x86_ea->ea.disp.size = wordsize; - x86_ea->valid_modrm = 1; - return 0; - } - - if (dispreq) { - /* for BP/EBP, there *must* be a displacement value, but we - * may not know the size (8 or 16/32) for sure right now. - */ - x86_ea->ea.need_nonzero_len = 1; - } - - if (x86_ea->ea.disp.rel) { - /* Relative displacement; basically all object formats need non-byte - * for relocation here, so just do that. (TODO: handle this - * differently?) - */ - x86_ea->ea.disp.size = wordsize; - x86_ea->modrm |= 0200; - x86_ea->valid_modrm = 1; - return 0; - } - - /* At this point there's 3 possibilities for the displacement: - * - None (if =0) - * - signed 8 bit (if in -128 to 127 range) - * - 16/32 bit (word size) - * For now, check intnum value right now; if it's not 0, - * assume 8 bit and set up for allowing 16 bit later. - * FIXME: The complex expression equaling zero is probably a rare case, - * so we ignore it for now. - */ - num = yasm_value_get_intnum(&x86_ea->ea.disp, NULL, 0); - if (!num) { - /* Still has unknown values. */ - x86_ea->ea.need_nonzero_len = 1; - x86_ea->modrm |= 0100; - x86_ea->valid_modrm = 1; - return 0; - } - - /* Figure out what size displacement we will have. */ - if (yasm_intnum_is_zero(num) && !x86_ea->ea.need_nonzero_len) { - /* If we know that the displacement is 0 right now, - * go ahead and delete the expr and make it so no - * displacement value is included in the output. - * The Mod bits of ModRM are set to 0 above, and - * we're done with the ModRM byte! - */ - yasm_value_delete(&x86_ea->ea.disp); - x86_ea->ea.need_disp = 0; - } else if (yasm_intnum_in_range(num, -128, 127)) { - /* It fits into a signed byte */ - x86_ea->ea.disp.size = 8; - x86_ea->modrm |= 0100; - } else { - /* It's a 16/32-bit displacement */ - x86_ea->ea.disp.size = wordsize; - x86_ea->modrm |= 0200; - } - x86_ea->valid_modrm = 1; /* We're done with ModRM */ - - yasm_intnum_destroy(num); - return 0; -} -/*@=nullstate@*/ - -static int -x86_expr_checkea_getregsize_callback(yasm_expr__item *ei, void *d) -{ - unsigned char *addrsize = (unsigned char *)d; - - if (ei->type == YASM_EXPR_REG) { - switch ((x86_expritem_reg_size)(ei->data.reg & ~0xFUL)) { - case X86_REG16: - *addrsize = 16; - break; - case X86_REG32: - *addrsize = 32; - break; - case X86_REG64: - case X86_RIP: - *addrsize = 64; - break; - default: - return 0; - } - return 1; - } else - return 0; -} - -int -yasm_x86__expr_checkea(x86_effaddr *x86_ea, unsigned char *addrsize, - unsigned int bits, int address16_op, unsigned char *rex, - yasm_bytecode *bc) -{ - int retval; - - if (*addrsize == 0) { - /* we need to figure out the address size from what we know about: - * - the displacement length - * - what registers are used in the expression - * - the bits setting - */ - switch (x86_ea->ea.disp.size) { - case 16: - /* must be 16-bit */ - *addrsize = 16; - break; - case 64: - /* We have to support this for the MemOffs case, but it's - * otherwise illegal. It's also illegal in non-64-bit mode. - */ - if (x86_ea->need_modrm || x86_ea->need_sib) { - yasm_error_set(YASM_ERROR_VALUE, - N_("invalid effective address (displacement size)")); - return 1; - } - *addrsize = 64; - break; - case 32: - /* Must be 32-bit in 16-bit or 32-bit modes. In 64-bit mode, - * we don't know unless we look at the registers, except in the - * MemOffs case (see the end of this function). - */ - if (bits != 64 || (!x86_ea->need_modrm && !x86_ea->need_sib)) { - *addrsize = 32; - break; - } - /*@fallthrough@*/ - default: - /* If SIB is required, but we're in 16-bit mode, set to 32. */ - if (bits == 16 && x86_ea->need_sib == 1) { - *addrsize = 32; - break; - } - /* check for use of 16 or 32-bit registers; if none are used - * default to bits setting. - */ - if (!x86_ea->ea.disp.abs || - !yasm_expr__traverse_leaves_in(x86_ea->ea.disp.abs, - addrsize, x86_expr_checkea_getregsize_callback)) - *addrsize = bits; - /* TODO: Add optional warning here if switched address size - * from bits setting just by register use.. eg [ax] in - * 32-bit mode would generate a warning. - */ - } - } - - if ((*addrsize == 32 || *addrsize == 64) && - ((x86_ea->need_modrm && !x86_ea->valid_modrm) || - (x86_ea->need_sib && !x86_ea->valid_sib))) { - int i; - unsigned char low3; - enum { - REG3264_NONE = -1, - REG3264_EAX = 0, - REG3264_ECX, - REG3264_EDX, - REG3264_EBX, - REG3264_ESP, - REG3264_EBP, - REG3264_ESI, - REG3264_EDI, - REG64_R8, - REG64_R9, - REG64_R10, - REG64_R11, - REG64_R12, - REG64_R13, - REG64_R14, - REG64_R15, - REG64_RIP, - SIMDREGS - }; - int reg3264mult[33] = - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - x86_checkea_reg3264_data reg3264_data; - int basereg = REG3264_NONE; /* "base" register (for SIB) */ - int indexreg = REG3264_NONE; /* "index" register (for SIB) */ - int regcount = 17; /* normally don't check SIMD regs */ - - if (x86_ea->vsib_mode != 0) - regcount = 33; - - /* We can only do 64-bit addresses in 64-bit mode. */ - if (*addrsize == 64 && bits != 64) { - yasm_error_set(YASM_ERROR_TYPE, - N_("invalid effective address (64-bit in non-64-bit mode)")); - return 1; - } - - if (x86_ea->ea.pc_rel && bits != 64) { - yasm_warn_set(YASM_WARN_GENERAL, - N_("RIP-relative directive ignored in non-64-bit mode")); - x86_ea->ea.pc_rel = 0; - } - - reg3264_data.regs = reg3264mult; - reg3264_data.vsib_mode = x86_ea->vsib_mode; - reg3264_data.bits = bits; - reg3264_data.addrsize = *addrsize; - if (x86_ea->ea.disp.abs) { - int pcrel = 0; - switch (x86_expr_checkea_getregusage - (&x86_ea->ea.disp.abs, &indexreg, &pcrel, bits, - ®3264_data, x86_expr_checkea_get_reg3264)) { - case 1: - yasm_error_set(YASM_ERROR_VALUE, - N_("invalid effective address")); - return 1; - case 2: - if (pcrel) - yasm_value_set_curpos_rel(&x86_ea->ea.disp, bc, 1); - return 2; - default: - if (pcrel) - yasm_value_set_curpos_rel(&x86_ea->ea.disp, bc, 1); - break; - } - } - - /* If indexreg mult is 0, discard it. - * This is possible because of the way indexreg is found in - * expr_checkea_getregusage(). - */ - if (indexreg != REG3264_NONE && reg3264mult[indexreg] == 0) - indexreg = REG3264_NONE; - - /* Find a basereg (*1, but not indexreg), if there is one. - * Also, if an indexreg hasn't been assigned, try to find one. - * Meanwhile, check to make sure there's no negative register mults. - */ - for (i=0; i<regcount; i++) { - if (reg3264mult[i] < 0) { - yasm_error_set(YASM_ERROR_VALUE, - N_("invalid effective address")); - return 1; - } - if (i != indexreg && reg3264mult[i] == 1 && - basereg == REG3264_NONE) - basereg = i; - else if (indexreg == REG3264_NONE && reg3264mult[i] > 0) - indexreg = i; - } - - if (x86_ea->vsib_mode != 0) { - /* For VSIB, the SIMD register needs to go into the indexreg. - * Also check basereg (must be a GPR if present) and indexreg - * (must be a SIMD register). - */ - if (basereg >= SIMDREGS && - (indexreg == REG3264_NONE || reg3264mult[indexreg] == 1)) { - int temp = basereg; - basereg = indexreg; - indexreg = temp; - } - if (basereg >= REG64_RIP || indexreg < SIMDREGS) { - yasm_error_set(YASM_ERROR_VALUE, - N_("invalid effective address")); - return 1; - } - } else if (indexreg != REG3264_NONE && basereg == REG3264_NONE) - /* Handle certain special cases of indexreg mults when basereg is - * empty. - */ - switch (reg3264mult[indexreg]) { - case 1: - /* Only optimize this way if nosplit wasn't specified */ - if (!x86_ea->ea.nosplit) { - basereg = indexreg; - indexreg = -1; - } - break; - case 2: - /* Only split if nosplit wasn't specified */ - if (!x86_ea->ea.nosplit) { - basereg = indexreg; - reg3264mult[indexreg] = 1; - } - break; - case 3: - case 5: - case 9: - basereg = indexreg; - reg3264mult[indexreg]--; - break; - } - - /* Make sure there's no other registers than the basereg and indexreg - * we just found. - */ - for (i=0; i<regcount; i++) - if (i != basereg && i != indexreg && reg3264mult[i] != 0) { - yasm_error_set(YASM_ERROR_VALUE, - N_("invalid effective address")); - return 1; - } - - /* Check the index multiplier value for validity if present. */ - if (indexreg != REG3264_NONE && reg3264mult[indexreg] != 1 && - reg3264mult[indexreg] != 2 && reg3264mult[indexreg] != 4 && - reg3264mult[indexreg] != 8) { - yasm_error_set(YASM_ERROR_VALUE, N_("invalid effective address")); - return 1; - } - - /* ESP is not a legal indexreg. */ - if (indexreg == REG3264_ESP) { - /* If mult>1 or basereg is ESP also, there's no way to make it - * legal. - */ - if (reg3264mult[REG3264_ESP] > 1 || basereg == REG3264_ESP) { - yasm_error_set(YASM_ERROR_VALUE, - N_("invalid effective address")); - return 1; - } - /* If mult==1 and basereg is not ESP, swap indexreg w/basereg. */ - indexreg = basereg; - basereg = REG3264_ESP; - } - - /* RIP is only legal if it's the ONLY register used. */ - if (indexreg == REG64_RIP || - (basereg == REG64_RIP && indexreg != REG3264_NONE)) { - yasm_error_set(YASM_ERROR_VALUE, N_("invalid effective address")); - return 1; - } - - /* At this point, we know the base and index registers and that the - * memory expression is (essentially) valid. Now build the ModRM and - * (optional) SIB bytes. - */ - - /* If we're supposed to be RIP-relative and there's no register - * usage, change to RIP-relative. - */ - if (basereg == REG3264_NONE && indexreg == REG3264_NONE && - x86_ea->ea.pc_rel) { - basereg = REG64_RIP; - yasm_value_set_curpos_rel(&x86_ea->ea.disp, bc, 1); - } - - /* First determine R/M (Mod is later determined from disp size) */ - x86_ea->need_modrm = 1; /* we always need ModRM */ - if (basereg == REG3264_NONE && indexreg == REG3264_NONE) { - /* Just a disp32: in 64-bit mode the RM encoding is used for RIP - * offset addressing, so we need to use the SIB form instead. - */ - if (bits == 64) { - x86_ea->modrm |= 4; - x86_ea->need_sib = 1; - } else { - x86_ea->modrm |= 5; - x86_ea->sib = 0; - x86_ea->valid_sib = 0; - x86_ea->need_sib = 0; - } - } else if (basereg == REG64_RIP) { - x86_ea->modrm |= 5; - x86_ea->sib = 0; - x86_ea->valid_sib = 0; - x86_ea->need_sib = 0; - /* RIP always requires a 32-bit displacement */ - x86_ea->valid_modrm = 1; - x86_ea->ea.disp.size = 32; - return 0; - } else if (indexreg == REG3264_NONE) { - /* basereg only */ - /* Don't need to go to the full effort of determining what type - * of register basereg is, as x86_set_rex_from_reg doesn't pay - * much attention. - */ - if (yasm_x86__set_rex_from_reg(rex, &low3, - (unsigned int)(X86_REG64 | basereg), - bits, X86_REX_B)) - return 1; - x86_ea->modrm |= low3; - /* we don't need an SIB *unless* basereg is ESP or R12 */ - if (basereg == REG3264_ESP || basereg == REG64_R12) - x86_ea->need_sib = 1; - else { - x86_ea->sib = 0; - x86_ea->valid_sib = 0; - x86_ea->need_sib = 0; - } - } else { - /* index or both base and index */ - x86_ea->modrm |= 4; - x86_ea->need_sib = 1; - } - - /* Determine SIB if needed */ - if (x86_ea->need_sib == 1) { - x86_ea->sib = 0; /* start with 0 */ - - /* Special case: no basereg */ - if (basereg == REG3264_NONE) - x86_ea->sib |= 5; - else { - if (yasm_x86__set_rex_from_reg(rex, &low3, (unsigned int) - (X86_REG64 | basereg), bits, - X86_REX_B)) - return 1; - x86_ea->sib |= low3; - } - - /* Put in indexreg, checking for none case */ - if (indexreg == REG3264_NONE) - x86_ea->sib |= 040; - /* Any scale field is valid, just leave at 0. */ - else { - if (indexreg >= SIMDREGS) { - if (yasm_x86__set_rex_from_reg(rex, &low3, - (unsigned int)(X86_XMMREG | (indexreg-SIMDREGS)), - bits, X86_REX_X)) - return 1; - } else { - if (yasm_x86__set_rex_from_reg(rex, &low3, - (unsigned int)(X86_REG64 | indexreg), - bits, X86_REX_X)) - return 1; - } - x86_ea->sib |= low3 << 3; - /* Set scale field, 1 case -> 0, so don't bother. */ - switch (reg3264mult[indexreg]) { - case 2: - x86_ea->sib |= 0100; - break; - case 4: - x86_ea->sib |= 0200; - break; - case 8: - x86_ea->sib |= 0300; - break; - } - } - - x86_ea->valid_sib = 1; /* Done with SIB */ - } - - /* Calculate displacement length (if possible) */ - retval = x86_checkea_calc_displen - (x86_ea, 32, basereg == REG3264_NONE, - basereg == REG3264_EBP || basereg == REG64_R13); - return retval; - } else if (*addrsize == 16 && x86_ea->need_modrm && !x86_ea->valid_modrm) { - static const unsigned char modrm16[16] = { - 0006 /* disp16 */, 0007 /* [BX] */, 0004 /* [SI] */, - 0000 /* [BX+SI] */, 0005 /* [DI] */, 0001 /* [BX+DI] */, - 0377 /* invalid */, 0377 /* invalid */, 0006 /* [BP]+d */, - 0377 /* invalid */, 0002 /* [BP+SI] */, 0377 /* invalid */, - 0003 /* [BP+DI] */, 0377 /* invalid */, 0377 /* invalid */, - 0377 /* invalid */ - }; - x86_checkea_reg16_data reg16mult = {0, 0, 0, 0}; - enum { - HAVE_NONE = 0, - HAVE_BX = 1<<0, - HAVE_SI = 1<<1, - HAVE_DI = 1<<2, - HAVE_BP = 1<<3 - } havereg = HAVE_NONE; - - /* 64-bit mode does not allow 16-bit addresses */ - if (bits == 64 && !address16_op) { - yasm_error_set(YASM_ERROR_TYPE, - N_("16-bit addresses not supported in 64-bit mode")); - return 1; - } - - /* 16-bit cannot have SIB */ - x86_ea->sib = 0; - x86_ea->valid_sib = 0; - x86_ea->need_sib = 0; - - if (x86_ea->ea.disp.abs) { - int pcrel = 0; - switch (x86_expr_checkea_getregusage - (&x86_ea->ea.disp.abs, (int *)NULL, &pcrel, bits, - ®16mult, x86_expr_checkea_get_reg16)) { - case 1: - yasm_error_set(YASM_ERROR_VALUE, - N_("invalid effective address")); - return 1; - case 2: - if (pcrel) - yasm_value_set_curpos_rel(&x86_ea->ea.disp, bc, 1); - return 2; - default: - if (pcrel) - yasm_value_set_curpos_rel(&x86_ea->ea.disp, bc, 1); - break; - } - } - - /* reg multipliers not 0 or 1 are illegal. */ - if (reg16mult.bx & ~1 || reg16mult.si & ~1 || reg16mult.di & ~1 || - reg16mult.bp & ~1) { - yasm_error_set(YASM_ERROR_VALUE, N_("invalid effective address")); - return 1; - } - - /* Set havereg appropriately */ - if (reg16mult.bx > 0) - havereg |= HAVE_BX; - if (reg16mult.si > 0) - havereg |= HAVE_SI; - if (reg16mult.di > 0) - havereg |= HAVE_DI; - if (reg16mult.bp > 0) - havereg |= HAVE_BP; - - /* Check the modrm value for invalid combinations. */ - if (modrm16[havereg] & 0070) { - yasm_error_set(YASM_ERROR_VALUE, N_("invalid effective address")); - return 1; - } - - /* Set ModRM byte for registers */ - x86_ea->modrm |= modrm16[havereg]; - - /* Calculate displacement length (if possible) */ - retval = x86_checkea_calc_displen - (x86_ea, 16, havereg == HAVE_NONE, havereg == HAVE_BP); - return retval; - } else if (!x86_ea->need_modrm && !x86_ea->need_sib) { - /* Special case for MOV MemOffs opcode: displacement but no modrm. */ - switch (*addrsize) { - case 64: - if (bits != 64) { - yasm_error_set(YASM_ERROR_TYPE, - N_("invalid effective address (64-bit in non-64-bit mode)")); - return 1; - } - x86_ea->ea.disp.size = 64; - break; - case 32: - x86_ea->ea.disp.size = 32; - break; - case 16: - /* 64-bit mode does not allow 16-bit addresses */ - if (bits == 64 && !address16_op) { - yasm_error_set(YASM_ERROR_TYPE, - N_("16-bit addresses not supported in 64-bit mode")); - return 1; - } - x86_ea->ea.disp.size = 16; - break; - } - } - return 0; -} - -int -yasm_x86__floatnum_tobytes(yasm_arch *arch, const yasm_floatnum *flt, - unsigned char *buf, size_t destsize, size_t valsize, - size_t shift, int warn) -{ - if (!yasm_floatnum_check_size(flt, valsize)) { - yasm_error_set(YASM_ERROR_FLOATING_POINT, - N_("invalid floating point constant size")); - return 1; - } - - yasm_floatnum_get_sized(flt, buf, destsize, valsize, shift, 0, warn); - return 0; -} +/* + * x86 expression handling + * + * Copyright (C) 2001-2007 Peter Johnson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include <util.h> + +#include <libyasm.h> + +#include "x86arch.h" + + +typedef struct x86_checkea_reg3264_data { + int *regs; /* total multiplier for each reg */ + unsigned char vsib_mode; + unsigned char bits; + unsigned char addrsize; +} x86_checkea_reg3264_data; + +/* Only works if ei->type == EXPR_REG (doesn't check). + * Overwrites ei with intnum of 0 (to eliminate regs from the final expr). + */ +static /*@null@*/ /*@dependent@*/ int * +x86_expr_checkea_get_reg3264(yasm_expr__item *ei, int *regnum, + /*returned*/ void *d) +{ + x86_checkea_reg3264_data *data = d; + + switch ((x86_expritem_reg_size)(ei->data.reg & ~0xFUL)) { + case X86_REG32: + if (data->addrsize != 32) + return 0; + *regnum = (unsigned int)(ei->data.reg & 0xF); + break; + case X86_REG64: + if (data->addrsize != 64) + return 0; + *regnum = (unsigned int)(ei->data.reg & 0xF); + break; + case X86_XMMREG: + if (data->vsib_mode != 1) + return 0; + if (data->bits != 64 && (ei->data.reg & 0x8) == 0x8) + return 0; + *regnum = 17+(unsigned int)(ei->data.reg & 0xF); + break; + case X86_YMMREG: + if (data->vsib_mode != 2) + return 0; + if (data->bits != 64 && (ei->data.reg & 0x8) == 0x8) + return 0; + *regnum = 17+(unsigned int)(ei->data.reg & 0xF); + break; + case X86_RIP: + if (data->bits != 64) + return 0; + *regnum = 16; + break; + default: + return 0; + } + + /* overwrite with 0 to eliminate register from displacement expr */ + ei->type = YASM_EXPR_INT; + ei->data.intn = yasm_intnum_create_uint(0); + + /* we're okay */ + return &data->regs[*regnum]; +} + +typedef struct x86_checkea_reg16_data { + int bx, si, di, bp; /* total multiplier for each reg */ +} x86_checkea_reg16_data; + +/* Only works if ei->type == EXPR_REG (doesn't check). + * Overwrites ei with intnum of 0 (to eliminate regs from the final expr). + */ +static /*@null@*/ int * +x86_expr_checkea_get_reg16(yasm_expr__item *ei, int *regnum, void *d) +{ + x86_checkea_reg16_data *data = d; + /* in order: ax,cx,dx,bx,sp,bp,si,di */ + /*@-nullassign@*/ + static int *reg16[8] = {0,0,0,0,0,0,0,0}; + /*@=nullassign@*/ + + reg16[3] = &data->bx; + reg16[5] = &data->bp; + reg16[6] = &data->si; + reg16[7] = &data->di; + + /* don't allow 32-bit registers */ + if ((ei->data.reg & ~0xFUL) != X86_REG16) + return 0; + + /* & 7 for sanity check */ + *regnum = (unsigned int)(ei->data.reg & 0x7); + + /* only allow BX, SI, DI, BP */ + if (!reg16[*regnum]) + return 0; + + /* overwrite with 0 to eliminate register from displacement expr */ + ei->type = YASM_EXPR_INT; + ei->data.intn = yasm_intnum_create_uint(0); + + /* we're okay */ + return reg16[*regnum]; +} + +/* Distribute over registers to help bring them to the topmost level of e. + * Also check for illegal operations against registers. + * Returns 0 if something was illegal, 1 if legal and nothing in e changed, + * and 2 if legal and e needs to be simplified. + * + * Only half joking: Someday make this/checkea able to accept crazy things + * like: (bx+di)*(bx+di)-bx*bx-2*bx*di-di*di+di? Probably not: NASM never + * accepted such things, and it's doubtful such an expn is valid anyway + * (even though the above one is). But even macros would be hard-pressed + * to generate something like this. + * + * e must already have been simplified for this function to work properly + * (as it doesn't think things like SUB are valid). + * + * IMPLEMENTATION NOTE: About the only thing this function really needs to + * "distribute" is: (non-float-expn or intnum) * (sum expn of registers). + * + * TODO: Clean up this code, make it easier to understand. + */ +static int +x86_expr_checkea_distcheck_reg(yasm_expr **ep, unsigned int bits) +{ + yasm_expr *e = *ep; + int i; + int havereg = -1, havereg_expr = -1; + int retval = 1; /* default to legal, no changes */ + + for (i=0; i<e->numterms; i++) { + switch (e->terms[i].type) { + case YASM_EXPR_REG: + /* Check op to make sure it's valid to use w/register. */ + switch (e->op) { + case YASM_EXPR_MUL: + /* Check for reg*reg */ + if (havereg != -1) + return 0; + break; + case YASM_EXPR_ADD: + case YASM_EXPR_IDENT: + break; + default: + return 0; + } + havereg = i; + break; + case YASM_EXPR_FLOAT: + /* Floats not allowed. */ + return 0; + case YASM_EXPR_EXPR: + if (yasm_expr__contains(e->terms[i].data.expn, + YASM_EXPR_REG)) { + int ret2; + + /* Check op to make sure it's valid to use w/register. */ + if (e->op != YASM_EXPR_ADD && e->op != YASM_EXPR_MUL) + return 0; + /* Check for reg*reg */ + if (e->op == YASM_EXPR_MUL && havereg != -1) + return 0; + havereg = i; + havereg_expr = i; + /* Recurse to check lower levels */ + ret2 = + x86_expr_checkea_distcheck_reg(&e->terms[i].data.expn, + bits); + if (ret2 == 0) + return 0; + if (ret2 == 2) + retval = 2; + } else if (yasm_expr__contains(e->terms[i].data.expn, + YASM_EXPR_FLOAT)) + return 0; /* Disallow floats */ + break; + default: + break; + } + } + + /* just exit if no registers were used */ + if (havereg == -1) + return retval; + + /* Distribute */ + if (e->op == YASM_EXPR_MUL && havereg_expr != -1) { + yasm_expr *ne; + + retval = 2; /* we're going to change it */ + + /* The reg expn *must* be EXPR_ADD at this point. Sanity check. */ + if (e->terms[havereg_expr].type != YASM_EXPR_EXPR || + e->terms[havereg_expr].data.expn->op != YASM_EXPR_ADD) + yasm_internal_error(N_("Register expression not ADD or EXPN")); + + /* Iterate over each term in reg expn */ + for (i=0; i<e->terms[havereg_expr].data.expn->numterms; i++) { + /* Copy everything EXCEPT havereg_expr term into new expression */ + ne = yasm_expr__copy_except(e, havereg_expr); + assert(ne != NULL); + /* Copy reg expr term into uncopied (empty) term in new expn */ + ne->terms[havereg_expr] = + e->terms[havereg_expr].data.expn->terms[i]; /* struct copy */ + /* Overwrite old reg expr term with new expn */ + e->terms[havereg_expr].data.expn->terms[i].type = YASM_EXPR_EXPR; + e->terms[havereg_expr].data.expn->terms[i].data.expn = ne; + } + + /* Replace e with expanded reg expn */ + ne = e->terms[havereg_expr].data.expn; + e->terms[havereg_expr].type = YASM_EXPR_NONE; /* don't delete it! */ + yasm_expr_destroy(e); /* but everything else */ + e = ne; + /*@-onlytrans@*/ + *ep = ne; + /*@=onlytrans@*/ + } + + return retval; +} + +/* Simplify and determine if expression is superficially valid: + * Valid expr should be [(int-equiv expn)]+[reg*(int-equiv expn)+...] + * where the [...] parts are optional. + * + * Don't simplify out constant identities if we're looking for an indexreg: we + * may need the multiplier for determining what the indexreg is! + * + * Returns 1 if invalid register usage, 2 if unable to determine all values, + * and 0 if all values successfully determined and saved in data. + */ +static int +x86_expr_checkea_getregusage(yasm_expr **ep, /*@null@*/ int *indexreg, + int *pcrel, unsigned int bits, void *data, + int *(*get_reg)(yasm_expr__item *ei, int *regnum, void *d)) +{ + int i; + int *reg; + int regnum; + int indexval = 0; + int indexmult = 0; + yasm_expr *e, *wrt; + + /*@-unqualifiedtrans@*/ + *ep = yasm_expr__level_tree(*ep, 1, 1, indexreg == 0, 0, NULL, NULL); + + /* Check for WRT rip first */ + wrt = yasm_expr_extract_wrt(ep); + if (wrt && wrt->op == YASM_EXPR_IDENT && + wrt->terms[0].type == YASM_EXPR_REG) { + if (bits != 64) { /* only valid in 64-bit mode */ + yasm_expr_destroy(wrt); + return 1; + } + reg = get_reg(&wrt->terms[0], ®num, data); + if (!reg || regnum != 16) { /* only accept rip */ + yasm_expr_destroy(wrt); + return 1; + } + (*reg)++; + + /* Delete WRT. Set pcrel to 1 to indicate to x86 + * bytecode code to do PC-relative displacement transform. + */ + *pcrel = 1; + yasm_expr_destroy(wrt); + } else if (wrt) { + yasm_expr_destroy(wrt); + return 1; + } + + /*@=unqualifiedtrans@*/ + assert(*ep != NULL); + e = *ep; + switch (x86_expr_checkea_distcheck_reg(ep, bits)) { + case 0: + return 1; + case 2: + /* Need to simplify again */ + *ep = yasm_expr__level_tree(*ep, 1, 1, indexreg == 0, 0, NULL, + NULL); + e = *ep; + break; + default: + break; + } + + switch (e->op) { + case YASM_EXPR_ADD: + /* Prescan for non-int multipliers against a reg. + * This is invalid due to the optimizer structure. + */ + for (i=0; i<e->numterms; i++) + if (e->terms[i].type == YASM_EXPR_EXPR) { + yasm_expr__order_terms(e->terms[i].data.expn); + if (e->terms[i].data.expn->terms[0].type == + YASM_EXPR_REG) { + if (e->terms[i].data.expn->numterms > 2) + return 1; + if (e->terms[i].data.expn->terms[1].type != + YASM_EXPR_INT) + return 1; + } + } + + /*@fallthrough@*/ + case YASM_EXPR_IDENT: + /* Check each term for register (and possible multiplier). */ + for (i=0; i<e->numterms; i++) { + if (e->terms[i].type == YASM_EXPR_REG) { + reg = get_reg(&e->terms[i], ®num, data); + if (!reg) + return 1; + (*reg)++; + /* Let last, largest multipler win indexreg */ + if (indexreg && *reg > 0 && indexval <= *reg && + !indexmult) { + *indexreg = regnum; + indexval = *reg; + } + } else if (e->terms[i].type == YASM_EXPR_EXPR) { + /* Already ordered from ADD above, just grab the value. + * Sanity check for EXPR_INT. + */ + if (e->terms[i].data.expn->terms[0].type == + YASM_EXPR_REG) { + long delta; + if (e->terms[i].data.expn->terms[1].type != + YASM_EXPR_INT) + yasm_internal_error( + N_("Non-integer value in reg expn")); + reg = get_reg(&e->terms[i].data.expn->terms[0], + ®num, data); + if (!reg) + return 1; + delta = yasm_intnum_get_int( + e->terms[i].data.expn->terms[1].data.intn); + (*reg) += delta; + /* Let last, largest multipler win indexreg */ + if (indexreg && delta > 0 && indexval <= *reg) { + *indexreg = regnum; + indexval = *reg; + indexmult = 1; + } else if (indexreg && *indexreg == regnum && + delta < 0 && *reg <= 1) { + *indexreg = -1; + indexval = 0; + indexmult = 0; + } + } + } + } + break; + case YASM_EXPR_MUL: + /* Here, too, check for non-int multipliers against a reg. */ + yasm_expr__order_terms(e); + if (e->terms[0].type == YASM_EXPR_REG) { + long delta; + if (e->numterms > 2) + return 1; + if (e->terms[1].type != YASM_EXPR_INT) + return 1; + reg = get_reg(&e->terms[0], ®num, data); + if (!reg) + return 1; + delta = yasm_intnum_get_int(e->terms[1].data.intn); + (*reg) += delta; + if (indexreg) + { + if (delta < 0 && *reg <= 1) + { + *indexreg = -1; + indexval = 0; + indexmult = 0; + } + else + *indexreg = regnum; + } + } + break; + case YASM_EXPR_SEGOFF: + /* No registers are allowed on either side. */ + if (yasm_expr__contains(e, YASM_EXPR_REG)) + return 1; + break; + default: + /* Should never get here! */ + yasm_internal_error(N_("unexpected expr op")); + } + + /* Simplify expr, which is now really just the displacement. This + * should get rid of the 0's we put in for registers in the callback. + */ + *ep = yasm_expr_simplify(*ep, 0); + /* e = *ep; */ + + return 0; +} + +/* Calculate the displacement length, if possible. + * Takes several extra inputs so it can be used by both 32-bit and 16-bit + * expressions: + * wordsize=16 for 16-bit, =32 for 32-bit. + * noreg=1 if the *ModRM byte* has no registers used. + * dispreq=1 if a displacement value is *required* (even if =0). + * Returns 0 if successfully calculated, 1 if not. + */ +/*@-nullstate@*/ +static int +x86_checkea_calc_displen(x86_effaddr *x86_ea, unsigned int wordsize, int noreg, + int dispreq) +{ + /*@null@*/ /*@only@*/ yasm_intnum *num; + + x86_ea->valid_modrm = 0; /* default to not yet valid */ + + switch (x86_ea->ea.disp.size) { + case 0: + break; + /* If not 0, the displacement length was forced; set the Mod bits + * appropriately and we're done with the ModRM byte. + */ + case 8: + /* Byte is only a valid override if there are registers in the + * EA. With no registers, we must have a 16/32 value. + */ + if (noreg) { + yasm_warn_set(YASM_WARN_IMPLICIT_SIZE_OVERRIDE, + N_("invalid displacement size; fixed")); + x86_ea->ea.disp.size = wordsize; + } else + x86_ea->modrm |= 0100; + x86_ea->valid_modrm = 1; + return 0; + case 16: + case 32: + /* Don't allow changing displacement different from BITS setting + * directly; require an address-size override to change it. + */ + if (wordsize != x86_ea->ea.disp.size) { + yasm_error_set(YASM_ERROR_VALUE, + N_("invalid effective address (displacement size)")); + return 1; + } + if (!noreg) + x86_ea->modrm |= 0200; + x86_ea->valid_modrm = 1; + return 0; + default: + /* we shouldn't ever get any other size! */ + yasm_internal_error(N_("strange EA displacement size")); + } + + /* The displacement length hasn't been forced (or the forcing wasn't + * valid), try to determine what it is. + */ + if (noreg) { + /* No register in ModRM expression, so it must be disp16/32, + * and as the Mod bits are set to 0 by the caller, we're done + * with the ModRM byte. + */ + x86_ea->ea.disp.size = wordsize; + x86_ea->valid_modrm = 1; + return 0; + } + + if (dispreq) { + /* for BP/EBP, there *must* be a displacement value, but we + * may not know the size (8 or 16/32) for sure right now. + */ + x86_ea->ea.need_nonzero_len = 1; + } + + if (x86_ea->ea.disp.rel) { + /* Relative displacement; basically all object formats need non-byte + * for relocation here, so just do that. (TODO: handle this + * differently?) + */ + x86_ea->ea.disp.size = wordsize; + x86_ea->modrm |= 0200; + x86_ea->valid_modrm = 1; + return 0; + } + + /* At this point there's 3 possibilities for the displacement: + * - None (if =0) + * - signed 8 bit (if in -128 to 127 range) + * - 16/32 bit (word size) + * For now, check intnum value right now; if it's not 0, + * assume 8 bit and set up for allowing 16 bit later. + * FIXME: The complex expression equaling zero is probably a rare case, + * so we ignore it for now. + */ + num = yasm_value_get_intnum(&x86_ea->ea.disp, NULL, 0); + if (!num) { + /* Still has unknown values. */ + x86_ea->ea.need_nonzero_len = 1; + x86_ea->modrm |= 0100; + x86_ea->valid_modrm = 1; + return 0; + } + + /* Figure out what size displacement we will have. */ + if (yasm_intnum_is_zero(num) && !x86_ea->ea.need_nonzero_len) { + /* If we know that the displacement is 0 right now, + * go ahead and delete the expr and make it so no + * displacement value is included in the output. + * The Mod bits of ModRM are set to 0 above, and + * we're done with the ModRM byte! + */ + yasm_value_delete(&x86_ea->ea.disp); + x86_ea->ea.need_disp = 0; + } else if (yasm_intnum_in_range(num, -128, 127)) { + /* It fits into a signed byte */ + x86_ea->ea.disp.size = 8; + x86_ea->modrm |= 0100; + } else { + /* It's a 16/32-bit displacement */ + x86_ea->ea.disp.size = wordsize; + x86_ea->modrm |= 0200; + } + x86_ea->valid_modrm = 1; /* We're done with ModRM */ + + yasm_intnum_destroy(num); + return 0; +} +/*@=nullstate@*/ + +static int +x86_expr_checkea_getregsize_callback(yasm_expr__item *ei, void *d) +{ + unsigned char *addrsize = (unsigned char *)d; + + if (ei->type == YASM_EXPR_REG) { + switch ((x86_expritem_reg_size)(ei->data.reg & ~0xFUL)) { + case X86_REG16: + *addrsize = 16; + break; + case X86_REG32: + *addrsize = 32; + break; + case X86_REG64: + case X86_RIP: + *addrsize = 64; + break; + default: + return 0; + } + return 1; + } else + return 0; +} + +int +yasm_x86__expr_checkea(x86_effaddr *x86_ea, unsigned char *addrsize, + unsigned int bits, int address16_op, unsigned char *rex, + yasm_bytecode *bc) +{ + int retval; + + if (*addrsize == 0) { + /* we need to figure out the address size from what we know about: + * - the displacement length + * - what registers are used in the expression + * - the bits setting + */ + switch (x86_ea->ea.disp.size) { + case 16: + /* must be 16-bit */ + *addrsize = 16; + break; + case 64: + /* We have to support this for the MemOffs case, but it's + * otherwise illegal. It's also illegal in non-64-bit mode. + */ + if (x86_ea->need_modrm || x86_ea->need_sib) { + yasm_error_set(YASM_ERROR_VALUE, + N_("invalid effective address (displacement size)")); + return 1; + } + *addrsize = 64; + break; + case 32: + /* Must be 32-bit in 16-bit or 32-bit modes. In 64-bit mode, + * we don't know unless we look at the registers, except in the + * MemOffs case (see the end of this function). + */ + if (bits != 64 || (!x86_ea->need_modrm && !x86_ea->need_sib)) { + *addrsize = 32; + break; + } + /*@fallthrough@*/ + default: + /* If SIB is required, but we're in 16-bit mode, set to 32. */ + if (bits == 16 && x86_ea->need_sib == 1) { + *addrsize = 32; + break; + } + /* check for use of 16 or 32-bit registers; if none are used + * default to bits setting. + */ + if (!x86_ea->ea.disp.abs || + !yasm_expr__traverse_leaves_in(x86_ea->ea.disp.abs, + addrsize, x86_expr_checkea_getregsize_callback)) + *addrsize = bits; + /* TODO: Add optional warning here if switched address size + * from bits setting just by register use.. eg [ax] in + * 32-bit mode would generate a warning. + */ + } + } + + if ((*addrsize == 32 || *addrsize == 64) && + ((x86_ea->need_modrm && !x86_ea->valid_modrm) || + (x86_ea->need_sib && !x86_ea->valid_sib))) { + int i; + unsigned char low3; + enum { + REG3264_NONE = -1, + REG3264_EAX = 0, + REG3264_ECX, + REG3264_EDX, + REG3264_EBX, + REG3264_ESP, + REG3264_EBP, + REG3264_ESI, + REG3264_EDI, + REG64_R8, + REG64_R9, + REG64_R10, + REG64_R11, + REG64_R12, + REG64_R13, + REG64_R14, + REG64_R15, + REG64_RIP, + SIMDREGS + }; + int reg3264mult[33] = + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + x86_checkea_reg3264_data reg3264_data; + int basereg = REG3264_NONE; /* "base" register (for SIB) */ + int indexreg = REG3264_NONE; /* "index" register (for SIB) */ + int regcount = 17; /* normally don't check SIMD regs */ + + if (x86_ea->vsib_mode != 0) + regcount = 33; + + /* We can only do 64-bit addresses in 64-bit mode. */ + if (*addrsize == 64 && bits != 64) { + yasm_error_set(YASM_ERROR_TYPE, + N_("invalid effective address (64-bit in non-64-bit mode)")); + return 1; + } + + if (x86_ea->ea.pc_rel && bits != 64) { + yasm_warn_set(YASM_WARN_GENERAL, + N_("RIP-relative directive ignored in non-64-bit mode")); + x86_ea->ea.pc_rel = 0; + } + + reg3264_data.regs = reg3264mult; + reg3264_data.vsib_mode = x86_ea->vsib_mode; + reg3264_data.bits = bits; + reg3264_data.addrsize = *addrsize; + if (x86_ea->ea.disp.abs) { + int pcrel = 0; + switch (x86_expr_checkea_getregusage + (&x86_ea->ea.disp.abs, &indexreg, &pcrel, bits, + ®3264_data, x86_expr_checkea_get_reg3264)) { + case 1: + yasm_error_set(YASM_ERROR_VALUE, + N_("invalid effective address")); + return 1; + case 2: + if (pcrel) + yasm_value_set_curpos_rel(&x86_ea->ea.disp, bc, 1); + return 2; + default: + if (pcrel) + yasm_value_set_curpos_rel(&x86_ea->ea.disp, bc, 1); + break; + } + } + + /* If indexreg mult is 0, discard it. + * This is possible because of the way indexreg is found in + * expr_checkea_getregusage(). + */ + if (indexreg != REG3264_NONE && reg3264mult[indexreg] == 0) + indexreg = REG3264_NONE; + + /* Find a basereg (*1, but not indexreg), if there is one. + * Also, if an indexreg hasn't been assigned, try to find one. + * Meanwhile, check to make sure there's no negative register mults. + */ + for (i=0; i<regcount; i++) { + if (reg3264mult[i] < 0) { + yasm_error_set(YASM_ERROR_VALUE, + N_("invalid effective address")); + return 1; + } + if (i != indexreg && reg3264mult[i] == 1 && + basereg == REG3264_NONE) + basereg = i; + else if (indexreg == REG3264_NONE && reg3264mult[i] > 0) + indexreg = i; + } + + if (x86_ea->vsib_mode != 0) { + /* For VSIB, the SIMD register needs to go into the indexreg. + * Also check basereg (must be a GPR if present) and indexreg + * (must be a SIMD register). + */ + if (basereg >= SIMDREGS && + (indexreg == REG3264_NONE || reg3264mult[indexreg] == 1)) { + int temp = basereg; + basereg = indexreg; + indexreg = temp; + } + if (basereg >= REG64_RIP || indexreg < SIMDREGS) { + yasm_error_set(YASM_ERROR_VALUE, + N_("invalid effective address")); + return 1; + } + } else if (indexreg != REG3264_NONE && basereg == REG3264_NONE) + /* Handle certain special cases of indexreg mults when basereg is + * empty. + */ + switch (reg3264mult[indexreg]) { + case 1: + /* Only optimize this way if nosplit wasn't specified */ + if (!x86_ea->ea.nosplit) { + basereg = indexreg; + indexreg = -1; + } + break; + case 2: + /* Only split if nosplit wasn't specified */ + if (!x86_ea->ea.nosplit) { + basereg = indexreg; + reg3264mult[indexreg] = 1; + } + break; + case 3: + case 5: + case 9: + basereg = indexreg; + reg3264mult[indexreg]--; + break; + } + + /* Make sure there's no other registers than the basereg and indexreg + * we just found. + */ + for (i=0; i<regcount; i++) + if (i != basereg && i != indexreg && reg3264mult[i] != 0) { + yasm_error_set(YASM_ERROR_VALUE, + N_("invalid effective address")); + return 1; + } + + /* Check the index multiplier value for validity if present. */ + if (indexreg != REG3264_NONE && reg3264mult[indexreg] != 1 && + reg3264mult[indexreg] != 2 && reg3264mult[indexreg] != 4 && + reg3264mult[indexreg] != 8) { + yasm_error_set(YASM_ERROR_VALUE, N_("invalid effective address")); + return 1; + } + + /* ESP is not a legal indexreg. */ + if (indexreg == REG3264_ESP) { + /* If mult>1 or basereg is ESP also, there's no way to make it + * legal. + */ + if (reg3264mult[REG3264_ESP] > 1 || basereg == REG3264_ESP) { + yasm_error_set(YASM_ERROR_VALUE, + N_("invalid effective address")); + return 1; + } + /* If mult==1 and basereg is not ESP, swap indexreg w/basereg. */ + indexreg = basereg; + basereg = REG3264_ESP; + } + + /* RIP is only legal if it's the ONLY register used. */ + if (indexreg == REG64_RIP || + (basereg == REG64_RIP && indexreg != REG3264_NONE)) { + yasm_error_set(YASM_ERROR_VALUE, N_("invalid effective address")); + return 1; + } + + /* At this point, we know the base and index registers and that the + * memory expression is (essentially) valid. Now build the ModRM and + * (optional) SIB bytes. + */ + + /* If we're supposed to be RIP-relative and there's no register + * usage, change to RIP-relative. + */ + if (basereg == REG3264_NONE && indexreg == REG3264_NONE && + x86_ea->ea.pc_rel) { + basereg = REG64_RIP; + yasm_value_set_curpos_rel(&x86_ea->ea.disp, bc, 1); + } + + /* First determine R/M (Mod is later determined from disp size) */ + x86_ea->need_modrm = 1; /* we always need ModRM */ + if (basereg == REG3264_NONE && indexreg == REG3264_NONE) { + /* Just a disp32: in 64-bit mode the RM encoding is used for RIP + * offset addressing, so we need to use the SIB form instead. + */ + if (bits == 64) { + x86_ea->modrm |= 4; + x86_ea->need_sib = 1; + } else { + x86_ea->modrm |= 5; + x86_ea->sib = 0; + x86_ea->valid_sib = 0; + x86_ea->need_sib = 0; + } + } else if (basereg == REG64_RIP) { + x86_ea->modrm |= 5; + x86_ea->sib = 0; + x86_ea->valid_sib = 0; + x86_ea->need_sib = 0; + /* RIP always requires a 32-bit displacement */ + x86_ea->valid_modrm = 1; + x86_ea->ea.disp.size = 32; + return 0; + } else if (indexreg == REG3264_NONE) { + /* basereg only */ + /* Don't need to go to the full effort of determining what type + * of register basereg is, as x86_set_rex_from_reg doesn't pay + * much attention. + */ + if (yasm_x86__set_rex_from_reg(rex, &low3, + (unsigned int)(X86_REG64 | basereg), + bits, X86_REX_B)) + return 1; + x86_ea->modrm |= low3; + /* we don't need an SIB *unless* basereg is ESP or R12 */ + if (basereg == REG3264_ESP || basereg == REG64_R12) + x86_ea->need_sib = 1; + else { + x86_ea->sib = 0; + x86_ea->valid_sib = 0; + x86_ea->need_sib = 0; + } + } else { + /* index or both base and index */ + x86_ea->modrm |= 4; + x86_ea->need_sib = 1; + } + + /* Determine SIB if needed */ + if (x86_ea->need_sib == 1) { + x86_ea->sib = 0; /* start with 0 */ + + /* Special case: no basereg */ + if (basereg == REG3264_NONE) + x86_ea->sib |= 5; + else { + if (yasm_x86__set_rex_from_reg(rex, &low3, (unsigned int) + (X86_REG64 | basereg), bits, + X86_REX_B)) + return 1; + x86_ea->sib |= low3; + } + + /* Put in indexreg, checking for none case */ + if (indexreg == REG3264_NONE) + x86_ea->sib |= 040; + /* Any scale field is valid, just leave at 0. */ + else { + if (indexreg >= SIMDREGS) { + if (yasm_x86__set_rex_from_reg(rex, &low3, + (unsigned int)(X86_XMMREG | (indexreg-SIMDREGS)), + bits, X86_REX_X)) + return 1; + } else { + if (yasm_x86__set_rex_from_reg(rex, &low3, + (unsigned int)(X86_REG64 | indexreg), + bits, X86_REX_X)) + return 1; + } + x86_ea->sib |= low3 << 3; + /* Set scale field, 1 case -> 0, so don't bother. */ + switch (reg3264mult[indexreg]) { + case 2: + x86_ea->sib |= 0100; + break; + case 4: + x86_ea->sib |= 0200; + break; + case 8: + x86_ea->sib |= 0300; + break; + } + } + + x86_ea->valid_sib = 1; /* Done with SIB */ + } + + /* Calculate displacement length (if possible) */ + retval = x86_checkea_calc_displen + (x86_ea, 32, basereg == REG3264_NONE, + basereg == REG3264_EBP || basereg == REG64_R13); + return retval; + } else if (*addrsize == 16 && x86_ea->need_modrm && !x86_ea->valid_modrm) { + static const unsigned char modrm16[16] = { + 0006 /* disp16 */, 0007 /* [BX] */, 0004 /* [SI] */, + 0000 /* [BX+SI] */, 0005 /* [DI] */, 0001 /* [BX+DI] */, + 0377 /* invalid */, 0377 /* invalid */, 0006 /* [BP]+d */, + 0377 /* invalid */, 0002 /* [BP+SI] */, 0377 /* invalid */, + 0003 /* [BP+DI] */, 0377 /* invalid */, 0377 /* invalid */, + 0377 /* invalid */ + }; + x86_checkea_reg16_data reg16mult = {0, 0, 0, 0}; + enum { + HAVE_NONE = 0, + HAVE_BX = 1<<0, + HAVE_SI = 1<<1, + HAVE_DI = 1<<2, + HAVE_BP = 1<<3 + } havereg = HAVE_NONE; + + /* 64-bit mode does not allow 16-bit addresses */ + if (bits == 64 && !address16_op) { + yasm_error_set(YASM_ERROR_TYPE, + N_("16-bit addresses not supported in 64-bit mode")); + return 1; + } + + /* 16-bit cannot have SIB */ + x86_ea->sib = 0; + x86_ea->valid_sib = 0; + x86_ea->need_sib = 0; + + if (x86_ea->ea.disp.abs) { + int pcrel = 0; + switch (x86_expr_checkea_getregusage + (&x86_ea->ea.disp.abs, (int *)NULL, &pcrel, bits, + ®16mult, x86_expr_checkea_get_reg16)) { + case 1: + yasm_error_set(YASM_ERROR_VALUE, + N_("invalid effective address")); + return 1; + case 2: + if (pcrel) + yasm_value_set_curpos_rel(&x86_ea->ea.disp, bc, 1); + return 2; + default: + if (pcrel) + yasm_value_set_curpos_rel(&x86_ea->ea.disp, bc, 1); + break; + } + } + + /* reg multipliers not 0 or 1 are illegal. */ + if (reg16mult.bx & ~1 || reg16mult.si & ~1 || reg16mult.di & ~1 || + reg16mult.bp & ~1) { + yasm_error_set(YASM_ERROR_VALUE, N_("invalid effective address")); + return 1; + } + + /* Set havereg appropriately */ + if (reg16mult.bx > 0) + havereg |= HAVE_BX; + if (reg16mult.si > 0) + havereg |= HAVE_SI; + if (reg16mult.di > 0) + havereg |= HAVE_DI; + if (reg16mult.bp > 0) + havereg |= HAVE_BP; + + /* Check the modrm value for invalid combinations. */ + if (modrm16[havereg] & 0070) { + yasm_error_set(YASM_ERROR_VALUE, N_("invalid effective address")); + return 1; + } + + /* Set ModRM byte for registers */ + x86_ea->modrm |= modrm16[havereg]; + + /* Calculate displacement length (if possible) */ + retval = x86_checkea_calc_displen + (x86_ea, 16, havereg == HAVE_NONE, havereg == HAVE_BP); + return retval; + } else if (!x86_ea->need_modrm && !x86_ea->need_sib) { + /* Special case for MOV MemOffs opcode: displacement but no modrm. */ + switch (*addrsize) { + case 64: + if (bits != 64) { + yasm_error_set(YASM_ERROR_TYPE, + N_("invalid effective address (64-bit in non-64-bit mode)")); + return 1; + } + x86_ea->ea.disp.size = 64; + break; + case 32: + x86_ea->ea.disp.size = 32; + break; + case 16: + /* 64-bit mode does not allow 16-bit addresses */ + if (bits == 64 && !address16_op) { + yasm_error_set(YASM_ERROR_TYPE, + N_("16-bit addresses not supported in 64-bit mode")); + return 1; + } + x86_ea->ea.disp.size = 16; + break; + } + } + return 0; +} + +int +yasm_x86__floatnum_tobytes(yasm_arch *arch, const yasm_floatnum *flt, + unsigned char *buf, size_t destsize, size_t valsize, + size_t shift, int warn) +{ + if (!yasm_floatnum_check_size(flt, valsize)) { + yasm_error_set(YASM_ERROR_FLOATING_POINT, + N_("invalid floating point constant size")); + return 1; + } + + yasm_floatnum_get_sized(flt, buf, destsize, valsize, shift, 0, warn); + return 0; +} diff --git a/contrib/tools/yasm/modules/arch/x86/x86id.c b/contrib/tools/yasm/modules/arch/x86/x86id.c index 6207c2062c..c937b5d637 100644 --- a/contrib/tools/yasm/modules/arch/x86/x86id.c +++ b/contrib/tools/yasm/modules/arch/x86/x86id.c @@ -1,1951 +1,1951 @@ -/* - * x86 identifier recognition and instruction handling - * - * Copyright (C) 2002-2007 Peter Johnson - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ -#include <ctype.h> -#include <util.h> - -#include <libyasm.h> -#include <libyasm/phash.h> - -#include "modules/arch/x86/x86arch.h" - - -static const char *cpu_find_reverse(unsigned int cpu0, unsigned int cpu1, - unsigned int cpu2); - -/* Opcode modifiers. */ -#define MOD_Gap 0 /* Eats a parameter / does nothing */ -#define MOD_PreAdd 1 /* Parameter adds to "special" prefix */ -#define MOD_Op0Add 2 /* Parameter adds to opcode byte 0 */ -#define MOD_Op1Add 3 /* Parameter adds to opcode byte 1 */ -#define MOD_Op2Add 4 /* Parameter adds to opcode byte 2 */ -#define MOD_SpAdd 5 /* Parameter adds to "spare" value */ -#define MOD_OpSizeR 6 /* Parameter replaces opersize */ -#define MOD_Imm8 7 /* Parameter is included as immediate byte */ -#define MOD_AdSizeR 8 /* Parameter replaces addrsize (jmp only) */ -#define MOD_DOpS64R 9 /* Parameter replaces default 64-bit opersize */ -#define MOD_Op1AddSp 10 /* Parameter is added as "spare" to opcode byte 2 */ -#define MOD_SetVEX 11 /* Parameter replaces internal VEX prefix value */ - -/* GAS suffix flags for instructions */ -enum x86_gas_suffix_flags { - SUF_Z = 1<<0, /* no suffix */ - SUF_B = 1<<1, - SUF_W = 1<<2, - SUF_L = 1<<3, - SUF_Q = 1<<4, - SUF_S = 1<<5, - SUF_MASK = SUF_Z|SUF_B|SUF_W|SUF_L|SUF_Q|SUF_S, - - /* Flags only used in x86_insn_info */ - GAS_ONLY = 1<<6, /* Only available in GAS mode */ - GAS_ILLEGAL = 1<<7, /* Illegal in GAS mode */ - GAS_NO_REV = 1<<8 /* Don't reverse operands in GAS mode */ -}; - -/* Miscellaneous flag tests for instructions */ -enum x86_misc_flags { - /* These are tested against BITS==64. */ - ONLY_64 = 1<<0, /* Only available in 64-bit mode */ - NOT_64 = 1<<1, /* Not available (invalid) in 64-bit mode */ - /* These are tested against whether the base instruction is an AVX one. */ - ONLY_AVX = 1<<2, /* Only available in AVX instruction */ - NOT_AVX = 1<<3 /* Not available (invalid) in AVX instruction */ -}; - -enum x86_operand_type { - OPT_Imm = 0, /* immediate */ - OPT_Reg = 1, /* any general purpose or FPU register */ - OPT_Mem = 2, /* memory */ - OPT_RM = 3, /* any general purpose or FPU register OR memory */ - OPT_SIMDReg = 4, /* any MMX or XMM register */ - OPT_SIMDRM = 5, /* any MMX or XMM register OR memory */ - OPT_SegReg = 6, /* any segment register */ - OPT_CRReg = 7, /* any CR register */ - OPT_DRReg = 8, /* any DR register */ - OPT_TRReg = 9, /* any TR register */ - OPT_ST0 = 10, /* ST0 */ - OPT_Areg = 11, /* AL/AX/EAX/RAX (depending on size) */ - OPT_Creg = 12, /* CL/CX/ECX/RCX (depending on size) */ - OPT_Dreg = 13, /* DL/DX/EDX/RDX (depending on size) */ - OPT_CS = 14, /* CS */ - OPT_DS = 15, /* DS */ - OPT_ES = 16, /* ES */ - OPT_FS = 17, /* FS */ - OPT_GS = 18, /* GS */ - OPT_SS = 19, /* SS */ - OPT_CR4 = 20, /* CR4 */ - /* memory offset (an EA, but with no registers allowed) - * [special case for MOV opcode] - */ - OPT_MemOffs = 21, - OPT_Imm1 = 22, /* immediate, value=1 (for special-case shift) */ - /* immediate, does not contain SEG:OFF (for jmp/call) */ - OPT_ImmNotSegOff = 23, - OPT_XMM0 = 24, /* XMM0 */ - /* AX/EAX/RAX memory operand only (EA) [special case for SVM opcodes] - */ - OPT_MemrAX = 25, - /* EAX memory operand only (EA) [special case for SVM skinit opcode] */ - OPT_MemEAX = 26, - /* XMM VSIB memory operand */ - OPT_MemXMMIndex = 27, - /* YMM VSIB memory operand */ - OPT_MemYMMIndex = 28 -}; - -enum x86_operand_size { - /* any size acceptable/no size spec acceptable (dep. on strict) */ - OPS_Any = 0, - /* 8/16/32/64/80/128/256 bits (from user or reg size) */ - OPS_8 = 1, - OPS_16 = 2, - OPS_32 = 3, - OPS_64 = 4, - OPS_80 = 5, - OPS_128 = 6, - OPS_256 = 7, - /* current BITS setting; when this is used the size matched - * gets stored into the opersize as well. - */ - OPS_BITS = 8 -}; - -enum x86_operand_targetmod { - OPTM_None = 0, /* no target mod acceptable */ - OPTM_Near = 1, /* NEAR */ - OPTM_Short = 2, /* SHORT */ - OPTM_Far = 3, /* FAR (or SEG:OFF immediate) */ - OPTM_To = 4 /* TO */ -}; - -enum x86_operand_action { - OPA_None = 0, /* does nothing (operand data is discarded) */ - OPA_EA = 1, /* operand data goes into ea field */ - OPA_Imm = 2, /* operand data goes into imm field */ - OPA_SImm = 3, /* operand data goes into sign-extended imm field */ - OPA_Spare = 4, /* operand data goes into "spare" field */ - OPA_Op0Add = 5, /* operand data is added to opcode byte 0 */ - OPA_Op1Add = 6, /* operand data is added to opcode byte 1 */ - /* operand data goes into BOTH ea and spare - * (special case for imul opcode) - */ - OPA_SpareEA = 7, - /* relative jump (outputs a jmp instead of normal insn) */ - OPA_JmpRel = 8, - /* operand size goes into address size (jmp only) */ - OPA_AdSizeR = 9, - /* far jump (outputs a farjmp instead of normal insn) */ - OPA_JmpFar = 10, - /* ea operand only sets address size (no actual ea field) */ - OPA_AdSizeEA = 11, - OPA_VEX = 12, /* operand data goes into VEX/XOP "vvvv" field */ - /* operand data goes into BOTH VEX/XOP "vvvv" field and ea field */ - OPA_EAVEX = 13, - /* operand data goes into BOTH VEX/XOP "vvvv" field and spare field */ - OPA_SpareVEX = 14, - /* operand data goes into upper 4 bits of immediate byte (VEX is4 field) */ - OPA_VEXImmSrc = 15, - /* operand data goes into bottom 4 bits of immediate byte - * (currently only VEX imz2 field) - */ - OPA_VEXImm = 16 -}; - -enum x86_operand_post_action { - OPAP_None = 0, - /* sign-extended imm8 that could expand to a large imm16/32 */ - OPAP_SImm8 = 1, - /* could become a short opcode mov with bits=64 and a32 prefix */ - OPAP_ShortMov = 2, - /* forced 16-bit address size (override ignored, no prefix) */ - OPAP_A16 = 3, - /* large imm64 that can become a sign-extended imm32 */ - OPAP_SImm32Avail = 4 -}; - -typedef struct x86_info_operand { - /* Operand types. These are more detailed than the "general" types for all - * architectures, as they include the size, for instance. - */ - - /* general type (must be exact match, except for RM types): */ - unsigned int type:5; - - /* size (user-specified, or from register size) */ - unsigned int size:4; - - /* size implicit or explicit ("strictness" of size matching on - * non-registers -- registers are always strictly matched): - * 0 = user size must exactly match size above. - * 1 = user size either unspecified or exactly match size above. - */ - unsigned int relaxed:1; - - /* effective address size - * 0 = any address size allowed except for 64-bit - * 1 = only 64-bit address size allowed - */ - unsigned int eas64:1; - - /* target modification */ - unsigned int targetmod:3; - - /* Actions: what to do with the operand if the instruction matches. - * Essentially describes what part of the output bytecode gets the - * operand. This may require conversion (e.g. a register going into - * an ea field). Naturally, only one of each of these may be contained - * in the operands of a single insn_info structure. - */ - unsigned int action:5; - - /* Postponed actions: actions which can't be completed at - * parse-time due to possibly dependent expressions. For these, some - * additional data (stored in the second byte of the opcode with a - * one-byte opcode) is passed to later stages of the assembler with - * flags set to indicate postponed actions. - */ - unsigned int post_action:3; -} x86_info_operand; - -typedef struct x86_insn_info { - /* GAS suffix flags */ - unsigned int gas_flags:9; /* Enabled for these GAS suffixes */ - - /* Tests against BITS==64, AVX, and XOP */ - unsigned int misc_flags:5; - - /* The CPU feature flags needed to execute this instruction. This is OR'ed - * with arch-specific data[2]. This combined value is compared with - * cpu_enabled to see if all bits set here are set in cpu_enabled--if so, - * the instruction is available on this CPU. - */ - unsigned int cpu0:6; - unsigned int cpu1:6; - unsigned int cpu2:6; - - /* Opcode modifiers for variations of instruction. As each modifier reads - * its parameter in LSB->MSB order from the arch-specific data[1] from the - * lexer data, and the LSB of the arch-specific data[1] is reserved for the - * count of insn_info structures in the instruction grouping, there can - * only be a maximum of 3 modifiers. - */ - unsigned char modifiers[3]; - - /* Operand Size */ - unsigned char opersize; - - /* Default operand size in 64-bit mode (0 = 32-bit for readability). */ - unsigned char def_opersize_64; - - /* A special instruction prefix, used for some of the Intel SSE and SSE2 - * instructions. Intel calls these 3-byte opcodes, but in AMD64's 64-bit - * mode, they're treated like normal prefixes (e.g. the REX prefix needs - * to be *after* the F2/F3/66 "prefix"). - * (0=no special prefix) - * 0xC0 - 0xCF indicate a VEX prefix, with the four LSBs holding "WLpp": - * W: VEX.W field (meaning depends on opcode) - * L: 0=128-bit, 1=256-bit - * pp: SIMD prefix designation: - * 00: None - * 01: 66 - * 10: F3 - * 11: F2 - * 0x80 - 0x8F indicate a XOP prefix, with the four LSBs holding "WLpp": - * same meanings as VEX prefix. - */ - unsigned char special_prefix; - - /* The length of the basic opcode */ - unsigned char opcode_len; - - /* The basic 1-3 byte opcode (not including the special instruction - * prefix). - */ - unsigned char opcode[3]; - - /* The 3-bit "spare" value (extended opcode) for the R/M byte field */ - unsigned char spare; - - /* The number of operands this form of the instruction takes */ - unsigned int num_operands:4; - - /* The index into the insn_operands array which contains the type of each - * operand, see above - */ - unsigned int operands_index:12; -} x86_insn_info; - -typedef struct x86_id_insn { - yasm_insn insn; /* base structure */ - - /* instruction parse group - NULL if empty instruction (just prefixes) */ - /*@null@*/ const x86_insn_info *group; - - /* CPU feature flags enabled at the time of parsing the instruction */ - wordptr cpu_enabled; - - /* Modifier data */ - unsigned char mod_data[3]; - - /* Number of elements in the instruction parse group */ - unsigned int num_info:8; - - /* BITS setting active at the time of parsing the instruction */ - unsigned int mode_bits:8; - - /* Suffix flags */ - unsigned int suffix:9; - - /* Tests against BITS==64 and AVX */ - unsigned int misc_flags:5; - - /* Parser enabled at the time of parsing the instruction */ - unsigned int parser:2; - - /* Strict forced setting at the time of parsing the instruction */ - unsigned int force_strict:1; - - /* Default rel setting at the time of parsing the instruction */ - unsigned int default_rel:1; -} x86_id_insn; - -static void x86_id_insn_destroy(void *contents); -static void x86_id_insn_print(const void *contents, FILE *f, int indent_level); -static void x86_id_insn_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc); - -static const yasm_bytecode_callback x86_id_insn_callback = { - x86_id_insn_destroy, - x86_id_insn_print, - x86_id_insn_finalize, - NULL, - yasm_bc_calc_len_common, - yasm_bc_expand_common, - yasm_bc_tobytes_common, - YASM_BC_SPECIAL_INSN -}; - -#include "x86insns.c" - -/* Looks for the first SIMD register match for the purposes of VSIB matching. - * Full legality checking is performed in EA code. - */ -static int -x86_expr_contains_simd_cb(const yasm_expr__item *ei, void *d) -{ - int ymm = *((int *)d); - if (ei->type != YASM_EXPR_REG) - return 0; - switch ((x86_expritem_reg_size)(ei->data.reg & ~0xFUL)) { - case X86_XMMREG: - if (!ymm) - return 1; - break; - case X86_YMMREG: - if (ymm) - return 1; - break; - default: - break; - } - return 0; -} - -static int -x86_expr_contains_simd(const yasm_expr *e, int ymm) -{ - return yasm_expr__traverse_leaves_in_const(e, &ymm, - x86_expr_contains_simd_cb); -} - -static void -x86_finalize_common(x86_common *common, const x86_insn_info *info, - unsigned int mode_bits) -{ - common->addrsize = 0; - common->opersize = info->opersize; - common->lockrep_pre = 0; - common->acqrel_pre = 0; - common->mode_bits = (unsigned char)mode_bits; -} - -static void -x86_finalize_opcode(x86_opcode *opcode, const x86_insn_info *info) -{ - opcode->len = info->opcode_len; - opcode->opcode[0] = info->opcode[0]; - opcode->opcode[1] = info->opcode[1]; - opcode->opcode[2] = info->opcode[2]; -} - -/* Clear operands so they don't get destroyed after we've copied references. */ -static void -x86_id_insn_clear_operands(x86_id_insn *id_insn) -{ - yasm_insn_operand *op = yasm_insn_ops_first(&id_insn->insn); - while (op) { - op->type = YASM_INSN__OPERAND_REG; - op = yasm_insn_op_next(op); - } -} - -static void -x86_finalize_jmpfar(yasm_bytecode *bc, yasm_bytecode *prev_bc, - const x86_insn_info *info) -{ - x86_id_insn *id_insn = (x86_id_insn *)bc->contents; - unsigned char *mod_data = id_insn->mod_data; - unsigned int mode_bits = id_insn->mode_bits; - x86_jmpfar *jmpfar; - yasm_insn_operand *op; - unsigned int i; - - jmpfar = yasm_xmalloc(sizeof(x86_jmpfar)); - x86_finalize_common(&jmpfar->common, info, mode_bits); - x86_finalize_opcode(&jmpfar->opcode, info); - - op = yasm_insn_ops_first(&id_insn->insn); - - 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, - 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". */ - 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")); - } else if (yasm_insn_op_next(op)) { - /* Two operand form (gas) */ - yasm_insn_operand *op2 = yasm_insn_op_next(op); - if (yasm_value_finalize_expr(&jmpfar->segment, op->data.val, prev_bc, - 16)) - yasm_error_set(YASM_ERROR_TOO_COMPLEX, - N_("jump target segment too complex")); - if (yasm_value_finalize_expr(&jmpfar->offset, op2->data.val, prev_bc, - 0)) - yasm_error_set(YASM_ERROR_TOO_COMPLEX, - N_("jump target offset too complex")); - if (op2->size == OPS_BITS) - jmpfar->common.opersize = (unsigned char)mode_bits; - } else - yasm_internal_error(N_("didn't get FAR expression in jmpfar")); - - /* Apply modifiers */ - for (i=0; i<NELEMS(info->modifiers); i++) { - switch (info->modifiers[i]) { - case MOD_Gap: - break; - case MOD_Op0Add: - jmpfar->opcode.opcode[0] += mod_data[i]; - break; - case MOD_Op1Add: - jmpfar->opcode.opcode[1] += mod_data[i]; - break; - case MOD_Op2Add: - jmpfar->opcode.opcode[2] += mod_data[i]; - break; - case MOD_Op1AddSp: - jmpfar->opcode.opcode[1] += mod_data[i]<<3; - break; - default: - break; - } - } - - yasm_x86__bc_apply_prefixes((x86_common *)jmpfar, NULL, - info->def_opersize_64, - id_insn->insn.num_prefixes, - id_insn->insn.prefixes); - - x86_id_insn_clear_operands(id_insn); - - /* Transform the bytecode */ - yasm_x86__bc_transform_jmpfar(bc, jmpfar); -} - -static void -x86_finalize_jmp(yasm_bytecode *bc, yasm_bytecode *prev_bc, - const x86_insn_info *jinfo) -{ - x86_id_insn *id_insn = (x86_id_insn *)bc->contents; - x86_jmp *jmp; - int num_info = id_insn->num_info; - const x86_insn_info *info = id_insn->group; - unsigned char *mod_data = id_insn->mod_data; - unsigned int mode_bits = id_insn->mode_bits; - /*unsigned char suffix = id_insn->suffix;*/ - yasm_insn_operand *op; - static const unsigned char size_lookup[] = - {0, 8, 16, 32, 64, 80, 128, 0, 0}; /* 256 not needed */ - unsigned int i; - - /* We know the target is in operand 0, but sanity check for Imm. */ - op = yasm_insn_ops_first(&id_insn->insn); - if (op->type != YASM_INSN__OPERAND_IMM) - yasm_internal_error(N_("invalid operand conversion")); - - jmp = yasm_xmalloc(sizeof(x86_jmp)); - x86_finalize_common(&jmp->common, jinfo, mode_bits); - if (yasm_value_finalize_expr(&jmp->target, op->data.val, prev_bc, 0)) - yasm_error_set(YASM_ERROR_TOO_COMPLEX, - 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")); - yasm_value_set_curpos_rel(&jmp->target, bc, 0); - jmp->target.jump_target = 1; - - /* See if the user explicitly specified short/near/far. */ - switch (insn_operands[jinfo->operands_index+0].targetmod) { - case OPTM_Short: - jmp->op_sel = JMP_SHORT_FORCED; - break; - case OPTM_Near: - jmp->op_sel = JMP_NEAR_FORCED; - break; - default: - jmp->op_sel = JMP_NONE; - } - - /* Check for address size setting in second operand, if present */ - if (jinfo->num_operands > 1 && - insn_operands[jinfo->operands_index+1].action == OPA_AdSizeR) - jmp->common.addrsize = (unsigned char) - size_lookup[insn_operands[jinfo->operands_index+1].size]; - - /* Check for address size override */ - for (i=0; i<NELEMS(jinfo->modifiers); i++) { - if (jinfo->modifiers[i] == MOD_AdSizeR) - jmp->common.addrsize = mod_data[i]; - } - - /* Scan through other infos for this insn looking for short/near versions. - * Needs to match opersize and number of operands, also be within CPU. - */ - jmp->shortop.len = 0; - jmp->nearop.len = 0; - for (; num_info>0 && (jmp->shortop.len == 0 || jmp->nearop.len == 0); - num_info--, info++) { - /* Match CPU */ - if (mode_bits != 64 && (info->misc_flags & ONLY_64)) - continue; - if (mode_bits == 64 && (info->misc_flags & NOT_64)) - continue; - - if (!BitVector_bit_test(id_insn->cpu_enabled, info->cpu0) || - !BitVector_bit_test(id_insn->cpu_enabled, info->cpu1) || - !BitVector_bit_test(id_insn->cpu_enabled, info->cpu2)) - continue; - - if (info->num_operands == 0) - continue; - - if (insn_operands[info->operands_index+0].action != OPA_JmpRel) - continue; - - if (info->opersize != jmp->common.opersize) - continue; - - switch (insn_operands[info->operands_index+0].targetmod) { - case OPTM_Short: - x86_finalize_opcode(&jmp->shortop, info); - for (i=0; i<NELEMS(info->modifiers); i++) { - if (info->modifiers[i] == MOD_Op0Add) - jmp->shortop.opcode[0] += mod_data[i]; - } - break; - case OPTM_Near: - x86_finalize_opcode(&jmp->nearop, info); - for (i=0; i<NELEMS(info->modifiers); i++) { - if (info->modifiers[i] == MOD_Op1Add) - jmp->nearop.opcode[1] += mod_data[i]; - } - break; - } - } - - if ((jmp->op_sel == JMP_SHORT_FORCED) && (jmp->shortop.len == 0)) - yasm_error_set(YASM_ERROR_TYPE, - N_("no SHORT form of that jump instruction exists")); - if ((jmp->op_sel == JMP_NEAR_FORCED) && (jmp->nearop.len == 0)) - yasm_error_set(YASM_ERROR_TYPE, - N_("no NEAR form of that jump instruction exists")); - - if (jmp->op_sel == JMP_NONE) { - if (jmp->nearop.len == 0) - jmp->op_sel = JMP_SHORT_FORCED; - if (jmp->shortop.len == 0) - jmp->op_sel = JMP_NEAR_FORCED; - } - - yasm_x86__bc_apply_prefixes((x86_common *)jmp, NULL, - jinfo->def_opersize_64, - id_insn->insn.num_prefixes, - id_insn->insn.prefixes); - - x86_id_insn_clear_operands(id_insn); - - /* Transform the bytecode */ - yasm_x86__bc_transform_jmp(bc, jmp); -} - -static const x86_insn_info * -x86_find_match(x86_id_insn *id_insn, yasm_insn_operand **ops, - yasm_insn_operand **rev_ops, const unsigned int *size_lookup, - int bypass) -{ - const x86_insn_info *info = id_insn->group; - unsigned int num_info = id_insn->num_info; - unsigned int suffix = id_insn->suffix; - unsigned int mode_bits = id_insn->mode_bits; - int found = 0; - - /* Just do a simple linear search through the info array for a match. - * First match wins. - */ - for (; num_info>0 && !found; num_info--, info++) { - yasm_insn_operand *op, **use_ops; - const x86_info_operand *info_ops = - &insn_operands[info->operands_index]; - unsigned int gas_flags = info->gas_flags; - unsigned int misc_flags = info->misc_flags; - unsigned int size; - int mismatch = 0; - unsigned int i; - - /* Match CPU */ - if (mode_bits != 64 && (misc_flags & ONLY_64)) - continue; - if (mode_bits == 64 && (misc_flags & NOT_64)) - continue; - - if (bypass != 8 && - (!BitVector_bit_test(id_insn->cpu_enabled, info->cpu0) || - !BitVector_bit_test(id_insn->cpu_enabled, info->cpu1) || - !BitVector_bit_test(id_insn->cpu_enabled, info->cpu2))) - continue; - - /* Match # of operands */ - if (id_insn->insn.num_operands != info->num_operands) - continue; - - /* Match AVX */ - if (!(id_insn->misc_flags & ONLY_AVX) && (misc_flags & ONLY_AVX)) - continue; - if ((id_insn->misc_flags & ONLY_AVX) && (misc_flags & NOT_AVX)) - continue; - - /* Match parser mode */ - if ((gas_flags & GAS_ONLY) && id_insn->parser != X86_PARSER_GAS) - continue; - if ((gas_flags & GAS_ILLEGAL) && id_insn->parser == X86_PARSER_GAS) - continue; - - /* Match suffix (if required) */ - if (id_insn->parser == X86_PARSER_GAS - && ((suffix & SUF_MASK) & (gas_flags & SUF_MASK)) == 0) - continue; - - /* Use reversed operands in GAS mode if not otherwise specified */ - use_ops = ops; - if (id_insn->parser == X86_PARSER_GAS && !(gas_flags & GAS_NO_REV)) - use_ops = rev_ops; - - if (id_insn->insn.num_operands == 0) { - found = 1; /* no operands -> must have a match here. */ - break; - } - - /* Match each operand type and size */ - for (i = 0, op = use_ops[0]; op && i<info->num_operands && !mismatch; - op = use_ops[++i]) { - /* Check operand type */ - switch (info_ops[i].type) { - case OPT_Imm: - if (op->type != YASM_INSN__OPERAND_IMM) - mismatch = 1; - break; - case OPT_RM: - if (op->type == YASM_INSN__OPERAND_MEMORY) - break; - /*@fallthrough@*/ - case OPT_Reg: - if (op->type != YASM_INSN__OPERAND_REG) - mismatch = 1; - else { - switch ((x86_expritem_reg_size)(op->data.reg&~0xFUL)) { - case X86_REG8: - case X86_REG8X: - case X86_REG16: - case X86_REG32: - case X86_REG64: - case X86_FPUREG: - break; - default: - mismatch = 1; - break; - } - } - break; - case OPT_Mem: - if (op->type != YASM_INSN__OPERAND_MEMORY) - mismatch = 1; - break; - case OPT_SIMDRM: - if (op->type == YASM_INSN__OPERAND_MEMORY) - break; - /*@fallthrough@*/ - case OPT_SIMDReg: - if (op->type != YASM_INSN__OPERAND_REG) - mismatch = 1; - else { - switch ((x86_expritem_reg_size)(op->data.reg&~0xFUL)) { - case X86_MMXREG: - case X86_XMMREG: - case X86_YMMREG: - break; - default: - mismatch = 1; - break; - } - } - break; - case OPT_SegReg: - if (op->type != YASM_INSN__OPERAND_SEGREG) - mismatch = 1; - break; - case OPT_CRReg: - if (op->type != YASM_INSN__OPERAND_REG || - (op->data.reg & ~0xFUL) != X86_CRREG) - mismatch = 1; - break; - case OPT_DRReg: - if (op->type != YASM_INSN__OPERAND_REG || - (op->data.reg & ~0xFUL) != X86_DRREG) - mismatch = 1; - break; - case OPT_TRReg: - if (op->type != YASM_INSN__OPERAND_REG || - (op->data.reg & ~0xFUL) != X86_TRREG) - mismatch = 1; - break; - case OPT_ST0: - if (op->type != YASM_INSN__OPERAND_REG || - op->data.reg != X86_FPUREG) - mismatch = 1; - break; - case OPT_Areg: - if (op->type != YASM_INSN__OPERAND_REG || - (info_ops[i].size == OPS_8 && - op->data.reg != (X86_REG8 | 0) && - op->data.reg != (X86_REG8X | 0)) || - (info_ops[i].size == OPS_16 && - op->data.reg != (X86_REG16 | 0)) || - (info_ops[i].size == OPS_32 && - op->data.reg != (X86_REG32 | 0)) || - (info_ops[i].size == OPS_64 && - op->data.reg != (X86_REG64 | 0))) - mismatch = 1; - break; - case OPT_Creg: - if (op->type != YASM_INSN__OPERAND_REG || - (info_ops[i].size == OPS_8 && - op->data.reg != (X86_REG8 | 1) && - op->data.reg != (X86_REG8X | 1)) || - (info_ops[i].size == OPS_16 && - op->data.reg != (X86_REG16 | 1)) || - (info_ops[i].size == OPS_32 && - op->data.reg != (X86_REG32 | 1)) || - (info_ops[i].size == OPS_64 && - op->data.reg != (X86_REG64 | 1))) - mismatch = 1; - break; - case OPT_Dreg: - if (op->type != YASM_INSN__OPERAND_REG || - (info_ops[i].size == OPS_8 && - op->data.reg != (X86_REG8 | 2) && - op->data.reg != (X86_REG8X | 2)) || - (info_ops[i].size == OPS_16 && - op->data.reg != (X86_REG16 | 2)) || - (info_ops[i].size == OPS_32 && - op->data.reg != (X86_REG32 | 2)) || - (info_ops[i].size == OPS_64 && - op->data.reg != (X86_REG64 | 2))) - mismatch = 1; - break; - case OPT_CS: - if (op->type != YASM_INSN__OPERAND_SEGREG || - (op->data.reg & 0xF) != 1) - mismatch = 1; - break; - case OPT_DS: - if (op->type != YASM_INSN__OPERAND_SEGREG || - (op->data.reg & 0xF) != 3) - mismatch = 1; - break; - case OPT_ES: - if (op->type != YASM_INSN__OPERAND_SEGREG || - (op->data.reg & 0xF) != 0) - mismatch = 1; - break; - case OPT_FS: - if (op->type != YASM_INSN__OPERAND_SEGREG || - (op->data.reg & 0xF) != 4) - mismatch = 1; - break; - case OPT_GS: - if (op->type != YASM_INSN__OPERAND_SEGREG || - (op->data.reg & 0xF) != 5) - mismatch = 1; - break; - case OPT_SS: - if (op->type != YASM_INSN__OPERAND_SEGREG || - (op->data.reg & 0xF) != 2) - mismatch = 1; - break; - case OPT_CR4: - if (op->type != YASM_INSN__OPERAND_REG || - op->data.reg != (X86_CRREG | 4)) - mismatch = 1; - break; - case OPT_MemOffs: - if (op->type != YASM_INSN__OPERAND_MEMORY || - yasm_expr__contains(op->data.ea->disp.abs, - YASM_EXPR_REG) || - op->data.ea->pc_rel || - (!op->data.ea->not_pc_rel && id_insn->default_rel && - op->data.ea->disp.size != 64)) - mismatch = 1; - break; - case OPT_Imm1: - if (op->type == YASM_INSN__OPERAND_IMM) { - const yasm_intnum *num; - num = yasm_expr_get_intnum(&op->data.val, 0); - if (!num || !yasm_intnum_is_pos1(num)) - mismatch = 1; - } else - mismatch = 1; - break; - case OPT_ImmNotSegOff: - if (op->type != YASM_INSN__OPERAND_IMM || - op->targetmod != 0 || op->seg) - mismatch = 1; - break; - case OPT_XMM0: - if (op->type != YASM_INSN__OPERAND_REG || - op->data.reg != X86_XMMREG) - mismatch = 1; - break; - case OPT_MemrAX: { - const uintptr_t *regp; - if (op->type != YASM_INSN__OPERAND_MEMORY || - !(regp = yasm_expr_get_reg(&op->data.ea->disp.abs, 0)) || - (*regp != (X86_REG16 | 0) && - *regp != (X86_REG32 | 0) && - *regp != (X86_REG64 | 0))) - mismatch = 1; - break; - } - case OPT_MemEAX: { - const uintptr_t *regp; - if (op->type != YASM_INSN__OPERAND_MEMORY || - !(regp = yasm_expr_get_reg(&op->data.ea->disp.abs, 0)) || - *regp != (X86_REG32 | 0)) - mismatch = 1; - break; - } - case OPT_MemXMMIndex: - if (op->type != YASM_INSN__OPERAND_MEMORY || - !x86_expr_contains_simd(op->data.ea->disp.abs, 0)) - mismatch = 1; - break; - case OPT_MemYMMIndex: - if (op->type != YASM_INSN__OPERAND_MEMORY || - !x86_expr_contains_simd(op->data.ea->disp.abs, 1)) - mismatch = 1; - break; - default: - yasm_internal_error(N_("invalid operand type")); - } - - if (mismatch) - break; - - /* Check operand size */ - size = size_lookup[info_ops[i].size]; - if (id_insn->parser == X86_PARSER_GAS) { - /* Require relaxed operands for GAS mode (don't allow - * per-operand sizing). - */ - if (op->type == YASM_INSN__OPERAND_REG && op->size == 0) { - /* Register size must exactly match */ - if (yasm_x86__get_reg_size(op->data.reg) != size) - mismatch = 1; - } else if ((info_ops[i].type == OPT_Imm - || info_ops[i].type == OPT_ImmNotSegOff - || info_ops[i].type == OPT_Imm1) - && !info_ops[i].relaxed - && info_ops[i].action != OPA_JmpRel) - mismatch = 1; - } else { - if (op->type == YASM_INSN__OPERAND_REG && op->size == 0) { - /* Register size must exactly match */ - if ((bypass == 4 && i == 0) || (bypass == 5 && i == 1) - || (bypass == 6 && i == 2)) - ; - else if (yasm_x86__get_reg_size(op->data.reg) != size) - mismatch = 1; - } else { - if ((bypass == 1 && i == 0) || (bypass == 2 && i == 1) - || (bypass == 3 && i == 2)) - ; - else if (info_ops[i].relaxed) { - /* Relaxed checking */ - if (size != 0 && op->size != size && op->size != 0) - mismatch = 1; - } else { - /* Strict checking */ - if (op->size != size) - mismatch = 1; - } - } - } - - if (mismatch) - break; - - /* Check for 64-bit effective address size in NASM mode */ - if (id_insn->parser != X86_PARSER_GAS && - op->type == YASM_INSN__OPERAND_MEMORY) { - if (info_ops[i].eas64) { - if (op->data.ea->disp.size != 64) - mismatch = 1; - } else if (op->data.ea->disp.size == 64) - mismatch = 1; - } - - if (mismatch) - break; - - /* Check target modifier */ - switch (info_ops[i].targetmod) { - case OPTM_None: - if (op->targetmod != 0) - mismatch = 1; - break; - case OPTM_Near: - if (op->targetmod != X86_NEAR) - mismatch = 1; - break; - case OPTM_Short: - if (op->targetmod != X86_SHORT) - mismatch = 1; - break; - case OPTM_Far: - if (op->targetmod != X86_FAR) - mismatch = 1; - break; - case OPTM_To: - if (op->targetmod != X86_TO) - mismatch = 1; - break; - default: - yasm_internal_error(N_("invalid target modifier type")); - } - } - - if (!mismatch) { - found = 1; - break; - } - } - - if (!found) - return NULL; - return info; -} - -static void -x86_match_error(x86_id_insn *id_insn, yasm_insn_operand **ops, - yasm_insn_operand **rev_ops, const unsigned int *size_lookup) -{ - const x86_insn_info *i; - int ni; - int found; - int bypass; - - /* Check for matching # of operands */ - found = 0; - for (ni=id_insn->num_info, i=id_insn->group; ni>0; ni--, i++) { - if (id_insn->insn.num_operands == i->num_operands) { - found = 1; - break; - } - } - if (!found) { - yasm_error_set(YASM_ERROR_TYPE, N_("invalid number of operands")); - return; - } - - for (bypass=1; bypass<9; bypass++) { - i = x86_find_match(id_insn, ops, rev_ops, size_lookup, bypass); - if (i) - break; - } - - switch (bypass) { - case 1: - case 4: - yasm_error_set(YASM_ERROR_TYPE, - N_("invalid size for operand %d"), 1); - break; - case 2: - case 5: - yasm_error_set(YASM_ERROR_TYPE, - N_("invalid size for operand %d"), 2); - break; - case 3: - case 6: - yasm_error_set(YASM_ERROR_TYPE, - N_("invalid size for operand %d"), 3); - break; - case 7: - yasm_error_set(YASM_ERROR_TYPE, - N_("one of source operand 1 or 3 must match dest operand")); - break; - case 8: - { - unsigned int cpu0 = i->cpu0, cpu1 = i->cpu1, cpu2 = i->cpu2; - yasm_error_set(YASM_ERROR_TYPE, - N_("requires CPU%s"), - cpu_find_reverse(cpu0, cpu1, cpu2)); - break; - } - default: - yasm_error_set(YASM_ERROR_TYPE, - N_("invalid combination of opcode and operands")); - } -} - -static void -x86_id_insn_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc) -{ - x86_id_insn *id_insn = (x86_id_insn *)bc->contents; - x86_insn *insn; - const x86_insn_info *info = id_insn->group; - unsigned int mode_bits = id_insn->mode_bits; - unsigned char *mod_data = id_insn->mod_data; - yasm_insn_operand *op, *ops[5], *rev_ops[5]; - /*@null@*/ yasm_expr *imm; - unsigned char im_len; - unsigned char im_sign; - unsigned char spare; - unsigned char vexdata, vexreg; - unsigned int i; - unsigned int size_lookup[] = {0, 8, 16, 32, 64, 80, 128, 256, 0}; - unsigned long do_postop = 0; - - size_lookup[OPS_BITS] = mode_bits; - - yasm_insn_finalize(&id_insn->insn); - - /* Build local array of operands from list, since we know we have a max - * of 5 operands. - */ - if (id_insn->insn.num_operands > 5) { - yasm_error_set(YASM_ERROR_TYPE, N_("too many operands")); - return; - } - ops[0] = ops[1] = ops[2] = ops[3] = ops[4] = NULL; - for (i = 0, op = yasm_insn_ops_first(&id_insn->insn); - op && i < id_insn->insn.num_operands; - op = yasm_insn_op_next(op), i++) - ops[i] = op; - - /* If we're running in GAS mode, build a reverse array of the operands - * as most GAS instructions have reversed operands from Intel style. - */ - if (id_insn->parser == X86_PARSER_GAS) { - rev_ops[0] = rev_ops[1] = rev_ops[2] = rev_ops[3] = rev_ops[4] = NULL; - for (i = id_insn->insn.num_operands-1, - op = yasm_insn_ops_first(&id_insn->insn); - op; op = yasm_insn_op_next(op), i--) - rev_ops[i] = op; - } - - /* If we're running in GAS mode, look at the first insn_info to see - * if this is a relative jump (OPA_JmpRel). If so, run through the - * operands and adjust for dereferences / lack thereof. - */ - if (id_insn->parser == X86_PARSER_GAS - && insn_operands[info->operands_index+0].action == OPA_JmpRel) { - for (i = 0, op = ops[0]; op; op = ops[++i]) { - if (!op->deref && (op->type == YASM_INSN__OPERAND_REG - || (op->type == YASM_INSN__OPERAND_MEMORY - && op->data.ea->strong))) - yasm_warn_set(YASM_WARN_GENERAL, - N_("indirect call without `*'")); - if (!op->deref && op->type == YASM_INSN__OPERAND_MEMORY - && !op->data.ea->strong) { - /* Memory that is not dereferenced, and not strong, is - * actually an immediate for the purposes of relative jumps. - */ - if (op->data.ea->segreg != 0) - yasm_warn_set(YASM_WARN_GENERAL, - N_("skipping prefixes on this instruction")); - imm = op->data.ea->disp.abs; - op->data.ea->disp.abs = NULL; - yasm_x86__ea_destroy(op->data.ea); - op->type = YASM_INSN__OPERAND_IMM; - op->data.val = imm; - } - } - } - - info = x86_find_match(id_insn, ops, rev_ops, size_lookup, 0); - - if (!info) { - /* Didn't find a match */ - x86_match_error(id_insn, ops, rev_ops, size_lookup); - return; - } - - if (id_insn->insn.num_operands > 0) { - switch (insn_operands[info->operands_index+0].action) { - case OPA_JmpRel: - /* Shortcut to JmpRel */ - x86_finalize_jmp(bc, prev_bc, info); - return; - case OPA_JmpFar: - /* Shortcut to JmpFar */ - x86_finalize_jmpfar(bc, prev_bc, info); - return; - } - } - - /* Copy what we can from info */ - insn = yasm_xmalloc(sizeof(x86_insn)); - x86_finalize_common(&insn->common, info, mode_bits); - x86_finalize_opcode(&insn->opcode, info); - insn->x86_ea = NULL; - imm = NULL; - insn->def_opersize_64 = info->def_opersize_64; - insn->special_prefix = info->special_prefix; - spare = info->spare; - vexdata = 0; - vexreg = 0; - im_len = 0; - im_sign = 0; - insn->postop = X86_POSTOP_NONE; - insn->rex = 0; - - /* Move VEX/XOP data (stored in special prefix) to separate location to - * allow overriding of special prefix by modifiers. - */ - if ((insn->special_prefix & 0xF0) == 0xC0 || - (insn->special_prefix & 0xF0) == 0x80) { - vexdata = insn->special_prefix; - insn->special_prefix = 0; - } - - /* Apply modifiers */ - for (i=0; i<NELEMS(info->modifiers); i++) { - switch (info->modifiers[i]) { - case MOD_Gap: - break; - case MOD_PreAdd: - insn->special_prefix += mod_data[i]; - break; - case MOD_Op0Add: - insn->opcode.opcode[0] += mod_data[i]; - break; - case MOD_Op1Add: - insn->opcode.opcode[1] += mod_data[i]; - break; - case MOD_Op2Add: - insn->opcode.opcode[2] += mod_data[i]; - break; - case MOD_SpAdd: - spare += mod_data[i]; - break; - case MOD_OpSizeR: - insn->common.opersize = mod_data[i]; - break; - case MOD_Imm8: - imm = yasm_expr_create_ident(yasm_expr_int( - yasm_intnum_create_uint(mod_data[i])), bc->line); - im_len = 8; - break; - case MOD_DOpS64R: - insn->def_opersize_64 = mod_data[i]; - break; - case MOD_Op1AddSp: - insn->opcode.opcode[1] += mod_data[i]<<3; - break; - case MOD_SetVEX: - vexdata = mod_data[i]; - break; - default: - break; - } - } - - /* In 64-bit mode, if opersize is 64 and default is not 64, - * force REX byte. - */ - if (mode_bits == 64 && insn->common.opersize == 64 && - insn->def_opersize_64 != 64) - insn->rex = 0x48; - - /* Go through operands and assign */ - if (id_insn->insn.num_operands > 0) { - yasm_insn_operand **use_ops = ops; - const x86_info_operand *info_ops = - &insn_operands[info->operands_index]; - - /* Use reversed operands in GAS mode if not otherwise specified */ - if (id_insn->parser == X86_PARSER_GAS - && !(info->gas_flags & GAS_NO_REV)) - use_ops = rev_ops; - - for (i = 0, op = use_ops[0]; op && i<info->num_operands; - op = use_ops[++i]) { - switch (info_ops[i].action) { - case OPA_None: - /* Throw away the operand contents */ - switch (op->type) { - case YASM_INSN__OPERAND_REG: - case YASM_INSN__OPERAND_SEGREG: - break; - case YASM_INSN__OPERAND_MEMORY: - yasm_x86__ea_destroy(op->data.ea); - break; - case YASM_INSN__OPERAND_IMM: - yasm_expr_destroy(op->data.val); - break; - } - break; - case OPA_EA: - switch (op->type) { - case YASM_INSN__OPERAND_REG: - insn->x86_ea = - yasm_x86__ea_create_reg(insn->x86_ea, - (unsigned long)op->data.reg, &insn->rex, - mode_bits); - break; - case YASM_INSN__OPERAND_SEGREG: - 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 */ - yasm_x86__ea_set_disponly(insn->x86_ea); - else if (info_ops[i].type == OPT_MemXMMIndex) { - /* Remember VSIB mode */ - insn->x86_ea->vsib_mode = 1; - insn->x86_ea->need_sib = 1; - } else if (info_ops[i].type == OPT_MemYMMIndex) { - /* Remember VSIB mode */ - insn->x86_ea->vsib_mode = 2; - insn->x86_ea->need_sib = 1; - } else if (id_insn->default_rel && - !op->data.ea->not_pc_rel && - op->data.ea->segreg != 0x6404 && - op->data.ea->segreg != 0x6505 && - !yasm_expr__contains( - op->data.ea->disp.abs, YASM_EXPR_REG)) - /* Enable default PC-rel if no regs and segreg - * is not FS or GS. - */ - insn->x86_ea->ea.pc_rel = 1; - break; - case YASM_INSN__OPERAND_IMM: - insn->x86_ea = - yasm_x86__ea_create_imm(insn->x86_ea, - op->data.val, - size_lookup[info_ops[i].size]); - break; - } - break; - case OPA_EAVEX: - if (op->type != YASM_INSN__OPERAND_REG) - yasm_internal_error(N_("invalid operand conversion")); - insn->x86_ea = - yasm_x86__ea_create_reg(insn->x86_ea, - (unsigned long)op->data.reg, &insn->rex, mode_bits); - vexreg = op->data.reg & 0xF; - 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]; - } else - 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]; - im_sign = 1; - } else - yasm_internal_error(N_("invalid operand conversion")); - break; - case OPA_Spare: - if (op->type == YASM_INSN__OPERAND_SEGREG) - spare = (unsigned char)(op->data.reg&7); - else if (op->type == YASM_INSN__OPERAND_REG) { - if (yasm_x86__set_rex_from_reg(&insn->rex, &spare, - op->data.reg, mode_bits, X86_REX_R)) - return; - } else - yasm_internal_error(N_("invalid operand conversion")); - break; - case OPA_SpareVEX: - if (op->type != YASM_INSN__OPERAND_REG) - yasm_internal_error(N_("invalid operand conversion")); - if (yasm_x86__set_rex_from_reg(&insn->rex, &spare, - op->data.reg, mode_bits, X86_REX_R)) - return; - vexreg = op->data.reg & 0xF; - break; - case OPA_Op0Add: - if (op->type == YASM_INSN__OPERAND_REG) { - unsigned char opadd; - if (yasm_x86__set_rex_from_reg(&insn->rex, &opadd, - op->data.reg, mode_bits, X86_REX_B)) - return; - insn->opcode.opcode[0] += opadd; - } else - yasm_internal_error(N_("invalid operand conversion")); - break; - case OPA_Op1Add: - if (op->type == YASM_INSN__OPERAND_REG) { - unsigned char opadd; - if (yasm_x86__set_rex_from_reg(&insn->rex, &opadd, - op->data.reg, mode_bits, X86_REX_B)) - return; - insn->opcode.opcode[1] += opadd; - } else - yasm_internal_error(N_("invalid operand conversion")); - break; - case OPA_SpareEA: - if (op->type == YASM_INSN__OPERAND_REG) { - insn->x86_ea = - yasm_x86__ea_create_reg(insn->x86_ea, - (unsigned long)op->data.reg, &insn->rex, - mode_bits); - if (!insn->x86_ea || - yasm_x86__set_rex_from_reg(&insn->rex, &spare, - op->data.reg, mode_bits, X86_REX_R)) { - if (insn->x86_ea) - yasm_xfree(insn->x86_ea); - yasm_xfree(insn); - return; - } - } else - yasm_internal_error(N_("invalid operand conversion")); - break; - case OPA_AdSizeEA: { - const uintptr_t *regp = NULL; - /* Only implement this for OPT_MemrAX and OPT_MemEAX - * for now. - */ - if (op->type != YASM_INSN__OPERAND_MEMORY || - !(regp = yasm_expr_get_reg(&op->data.ea->disp.abs, 0))) - yasm_internal_error(N_("invalid operand conversion")); - /* 64-bit mode does not allow 16-bit addresses */ - if (mode_bits == 64 && *regp == (X86_REG16 | 0)) - yasm_error_set(YASM_ERROR_TYPE, - N_("16-bit addresses not supported in 64-bit mode")); - else if (*regp == (X86_REG16 | 0)) - insn->common.addrsize = 16; - else if (*regp == (X86_REG32 | 0)) - insn->common.addrsize = 32; - else if (mode_bits == 64 && *regp == (X86_REG64 | 0)) - insn->common.addrsize = 64; - else - yasm_error_set(YASM_ERROR_TYPE, - N_("unsupported address size")); - yasm_x86__ea_destroy(op->data.ea); - break; - } - case OPA_VEX: - if (op->type != YASM_INSN__OPERAND_REG) - yasm_internal_error(N_("invalid operand conversion")); - vexreg = op->data.reg & 0xF; - break; - case OPA_VEXImmSrc: - if (op->type != YASM_INSN__OPERAND_REG) - yasm_internal_error(N_("invalid operand conversion")); - - if (!imm) { - imm = yasm_expr_create_ident( - yasm_expr_int( - yasm_intnum_create_uint((op->data.reg << 4) - & 0xF0)), - bc->line); - } else { - imm = yasm_expr_create( - YASM_EXPR_OR, - yasm_expr_expr(yasm_expr_create( - YASM_EXPR_AND, - yasm_expr_expr(imm), - yasm_expr_int(yasm_intnum_create_uint(0x0F)), - bc->line)), - yasm_expr_int( - yasm_intnum_create_uint((op->data.reg << 4) - & 0xF0)), - bc->line); - } - im_len = 8; - break; - case OPA_VEXImm: - if (op->type != YASM_INSN__OPERAND_IMM) - yasm_internal_error(N_("invalid operand conversion")); - - if (!imm) - imm = op->data.val; - else { - imm = yasm_expr_create( - YASM_EXPR_OR, - yasm_expr_expr(yasm_expr_create( - YASM_EXPR_AND, - yasm_expr_expr(op->data.val), - yasm_expr_int(yasm_intnum_create_uint(0x0F)), - bc->line)), - yasm_expr_expr(yasm_expr_create( - YASM_EXPR_AND, - yasm_expr_expr(imm), - yasm_expr_int(yasm_intnum_create_uint(0xF0)), - bc->line)), - bc->line); - } - im_len = 8; - break; - default: - yasm_internal_error(N_("unknown operand action")); - } - - if (info_ops[i].size == OPS_BITS) - insn->common.opersize = (unsigned char)mode_bits; - - switch (info_ops[i].post_action) { - case OPAP_None: - break; - case OPAP_SImm8: - /* Check operand strictness; if strict and non-8-bit, - * pre-emptively expand to full size. - * For unspecified size case, still optimize. - */ - if (!(id_insn->force_strict || op->strict) - || op->size == 0) - insn->postop = X86_POSTOP_SIGNEXT_IMM8; - else if (op->size != 8) { - insn->opcode.opcode[0] = - insn->opcode.opcode[insn->opcode.len]; - insn->opcode.len = 1; - } - break; - case OPAP_ShortMov: - do_postop = OPAP_ShortMov; - break; - case OPAP_A16: - insn->postop = X86_POSTOP_ADDRESS16; - break; - case OPAP_SImm32Avail: - do_postop = OPAP_SImm32Avail; - break; - default: - yasm_internal_error( - N_("unknown operand postponed action")); - } - } - } - - if (insn->x86_ea) { - yasm_x86__ea_init(insn->x86_ea, spare, prev_bc); - for (i=0; i<id_insn->insn.num_segregs; i++) - yasm_ea_set_segreg(&insn->x86_ea->ea, id_insn->insn.segregs[i]); - } else if (id_insn->insn.num_segregs > 0 && insn->special_prefix == 0) { - if (id_insn->insn.num_segregs > 1) - yasm_warn_set(YASM_WARN_GENERAL, - N_("multiple segment overrides, using leftmost")); - insn->special_prefix = (unsigned char) - (id_insn->insn.segregs[id_insn->insn.num_segregs-1]>>8); - } else if (id_insn->insn.num_segregs > 0) - yasm_internal_error(N_("unhandled segment prefix")); - - if (imm) { - insn->imm = yasm_xmalloc(sizeof(yasm_value)); - if (yasm_value_finalize_expr(insn->imm, imm, prev_bc, im_len)) - yasm_error_set(YASM_ERROR_TOO_COMPLEX, - N_("immediate expression too complex")); - insn->imm->sign = im_sign; - } else - insn->imm = NULL; - - yasm_x86__bc_apply_prefixes((x86_common *)insn, &insn->rex, - insn->def_opersize_64, - id_insn->insn.num_prefixes, - id_insn->insn.prefixes); - - if (insn->postop == X86_POSTOP_ADDRESS16 && insn->common.addrsize) { - yasm_warn_set(YASM_WARN_GENERAL, N_("address size override ignored")); - insn->common.addrsize = 0; - } - - /* Handle non-span-dependent post-ops here */ - switch (do_postop) { - case OPAP_ShortMov: - /* Long (modrm+sib) mov instructions in amd64 can be optimized into - * short mov instructions if a 32-bit address override is applied in - * 64-bit mode to an EA of just an offset (no registers) and the - * target register is al/ax/eax/rax. - * - * We don't want to do this if we're in default rel mode. - */ - if (!id_insn->default_rel && - insn->common.mode_bits == 64 && - insn->common.addrsize == 32 && - (!insn->x86_ea->ea.disp.abs || - !yasm_expr__contains(insn->x86_ea->ea.disp.abs, - YASM_EXPR_REG))) { - yasm_x86__ea_set_disponly(insn->x86_ea); - /* Make the short form permanent. */ - insn->opcode.opcode[0] = insn->opcode.opcode[1]; - } - insn->opcode.opcode[1] = 0; /* avoid possible confusion */ - break; - case OPAP_SImm32Avail: - /* Used for 64-bit mov immediate, which can take a sign-extended - * imm32 as well as imm64 values. The imm32 form is put in the - * second byte of the opcode and its ModRM byte is put in the third - * byte of the opcode. - */ - if (!insn->imm->abs || - (yasm_expr_get_intnum(&insn->imm->abs, 0) && - yasm_intnum_check_size( - yasm_expr_get_intnum(&insn->imm->abs, 0), 32, 0, 1))) { - /* Throwaway REX byte */ - unsigned char rex_temp = 0; - - /* Build ModRM EA - CAUTION: this depends on - * opcode 0 being a mov instruction! - */ - insn->x86_ea = yasm_x86__ea_create_reg(insn->x86_ea, - (unsigned long)insn->opcode.opcode[0]-0xB8, &rex_temp, 64); - - /* Make the imm32s form permanent. */ - insn->opcode.opcode[0] = insn->opcode.opcode[1]; - insn->imm->size = 32; - } - insn->opcode.opcode[1] = 0; /* avoid possible confusion */ - break; - default: - break; - } - - /* Convert to VEX/XOP prefixes if requested. - * To save space in the insn structure, the VEX/XOP prefix is written into - * special_prefix and the first 2 bytes of the instruction are set to - * the second two VEX/XOP bytes. During calc_len() it may be shortened to - * one VEX byte (this can only be done after knowledge of REX value); this - * further optimization is not possible for XOP. - */ - if (vexdata) { - int xop = ((vexdata & 0xF0) == 0x80); - unsigned char vex1 = 0xE0; /* R=X=B=1, mmmmm=0 */ - unsigned char vex2; - - if (xop) { - /* Look at the first bytes of the opcode for the XOP mmmmm field. - * Leave R=X=B=1 for now. - */ - if (insn->opcode.opcode[0] != 0x08 && - insn->opcode.opcode[0] != 0x09 && - insn->opcode.opcode[0] != 0x0A) - yasm_internal_error(N_("first opcode byte of XOP must be 0x08, 0x09, or 0x0A")); - vex1 |= insn->opcode.opcode[0]; - /* Move opcode byte back one byte to make room for XOP prefix. */ - insn->opcode.opcode[2] = insn->opcode.opcode[1]; - } else { - /* Look at the first bytes of the opcode to see what leading bytes - * to encode in the VEX mmmmm field. Leave R=X=B=1 for now. - */ - if (insn->opcode.opcode[0] != 0x0F) - yasm_internal_error(N_("first opcode byte of VEX must be 0x0F")); - - if (insn->opcode.opcode[1] == 0x38) - vex1 |= 0x02; /* implied 0x0F 0x38 */ - else if (insn->opcode.opcode[1] == 0x3A) - vex1 |= 0x03; /* implied 0x0F 0x3A */ - else { - /* Originally a 0F-only opcode; move opcode byte back one - * position to make room for VEX prefix. - */ - insn->opcode.opcode[2] = insn->opcode.opcode[1]; - vex1 |= 0x01; /* implied 0x0F */ - } - } - - /* Check for update of special prefix by modifiers */ - if (insn->special_prefix != 0) { - vexdata &= ~0x03; - switch (insn->special_prefix) { - case 0x66: - vexdata |= 0x01; - break; - case 0xF3: - vexdata |= 0x02; - break; - case 0xF2: - vexdata |= 0x03; - break; - default: - yasm_internal_error(N_("unrecognized special prefix")); - } - } - - /* 2nd VEX byte is WvvvvLpp. - * W, L, pp come from vexdata - * vvvv comes from 1s complement of vexreg - */ - vex2 = (((vexdata & 0x8) << 4) | /* W */ - ((15 - (vexreg & 0xF)) << 3) | /* vvvv */ - (vexdata & 0x7)); /* Lpp */ - - /* Save to special_prefix and opcode */ - insn->special_prefix = xop ? 0x8F : 0xC4; /* VEX/XOP prefix */ - insn->opcode.opcode[0] = vex1; - insn->opcode.opcode[1] = vex2; - insn->opcode.len = 3; /* two prefix bytes and 1 opcode byte */ - } - - x86_id_insn_clear_operands(id_insn); - - /* Transform the bytecode */ - yasm_x86__bc_transform_insn(bc, insn); -} - -/* Static parse data structure for instructions */ -typedef struct insnprefix_parse_data { - const char *name; - - /* instruction parse group - NULL if prefix */ - /*@null@*/ const x86_insn_info *group; - - /* For instruction, number of elements in group. - * For prefix, prefix type shifted right by 8. - */ - unsigned int num_info:8; - - /* For instruction, GAS suffix flags. - * For prefix, prefix value. - */ - unsigned int flags:8; - - /* Instruction modifier data. */ - unsigned int mod_data0:8; - unsigned int mod_data1:8; - unsigned int mod_data2:8; - - /* Tests against BITS==64 and AVX */ - unsigned int misc_flags:6; - - /* CPU flags */ - unsigned int cpu0:6; - unsigned int cpu1:6; - unsigned int cpu2:6; -} insnprefix_parse_data; - -/* Pull in all parse data */ -#include "x86insn_nasm.c" -#include "x86insn_gas.c" - -static const char * -cpu_find_reverse(unsigned int cpu0, unsigned int cpu1, unsigned int cpu2) -{ - static char cpuname[200]; - wordptr cpu = BitVector_Create(128, TRUE); - - if (cpu0 != CPU_Any) - BitVector_Bit_On(cpu, cpu0); - if (cpu1 != CPU_Any) - BitVector_Bit_On(cpu, cpu1); - if (cpu2 != CPU_Any) - BitVector_Bit_On(cpu, cpu2); - - cpuname[0] = '\0'; - - if (BitVector_bit_test(cpu, CPU_Prot)) - strcat(cpuname, " Protected"); - if (BitVector_bit_test(cpu, CPU_Undoc)) - strcat(cpuname, " Undocumented"); - if (BitVector_bit_test(cpu, CPU_Obs)) - strcat(cpuname, " Obsolete"); - if (BitVector_bit_test(cpu, CPU_Priv)) - strcat(cpuname, " Privileged"); - - if (BitVector_bit_test(cpu, CPU_FPU)) - strcat(cpuname, " FPU"); - if (BitVector_bit_test(cpu, CPU_MMX)) - strcat(cpuname, " MMX"); - if (BitVector_bit_test(cpu, CPU_SSE)) - strcat(cpuname, " SSE"); - if (BitVector_bit_test(cpu, CPU_SSE2)) - strcat(cpuname, " SSE2"); - if (BitVector_bit_test(cpu, CPU_SSE3)) - strcat(cpuname, " SSE3"); - if (BitVector_bit_test(cpu, CPU_3DNow)) - strcat(cpuname, " 3DNow"); - if (BitVector_bit_test(cpu, CPU_Cyrix)) - strcat(cpuname, " Cyrix"); - if (BitVector_bit_test(cpu, CPU_AMD)) - strcat(cpuname, " AMD"); - if (BitVector_bit_test(cpu, CPU_SMM)) - strcat(cpuname, " SMM"); - if (BitVector_bit_test(cpu, CPU_SVM)) - strcat(cpuname, " SVM"); - if (BitVector_bit_test(cpu, CPU_PadLock)) - strcat(cpuname, " PadLock"); - if (BitVector_bit_test(cpu, CPU_EM64T)) - strcat(cpuname, " EM64T"); - if (BitVector_bit_test(cpu, CPU_SSSE3)) - strcat(cpuname, " SSSE3"); - if (BitVector_bit_test(cpu, CPU_SSE41)) - strcat(cpuname, " SSE4.1"); - if (BitVector_bit_test(cpu, CPU_SSE42)) - strcat(cpuname, " SSE4.2"); - - if (BitVector_bit_test(cpu, CPU_186)) - strcat(cpuname, " 186"); - if (BitVector_bit_test(cpu, CPU_286)) - strcat(cpuname, " 286"); - if (BitVector_bit_test(cpu, CPU_386)) - strcat(cpuname, " 386"); - if (BitVector_bit_test(cpu, CPU_486)) - strcat(cpuname, " 486"); - if (BitVector_bit_test(cpu, CPU_586)) - strcat(cpuname, " 586"); - if (BitVector_bit_test(cpu, CPU_686)) - strcat(cpuname, " 686"); - if (BitVector_bit_test(cpu, CPU_P3)) - strcat(cpuname, " P3"); - if (BitVector_bit_test(cpu, CPU_P4)) - strcat(cpuname, " P4"); - if (BitVector_bit_test(cpu, CPU_IA64)) - strcat(cpuname, " IA64"); - if (BitVector_bit_test(cpu, CPU_K6)) - strcat(cpuname, " K6"); - if (BitVector_bit_test(cpu, CPU_Athlon)) - strcat(cpuname, " Athlon"); - if (BitVector_bit_test(cpu, CPU_Hammer)) - strcat(cpuname, " Hammer"); - - BitVector_Destroy(cpu); - return cpuname; -} - -yasm_arch_insnprefix -yasm_x86__parse_check_insnprefix(yasm_arch *arch, const char *id, - size_t id_len, unsigned long line, - yasm_bytecode **bc, uintptr_t *prefix) -{ - yasm_arch_x86 *arch_x86 = (yasm_arch_x86 *)arch; - /*@null@*/ const insnprefix_parse_data *pdata; - size_t i; - static char lcaseid[17]; - - *bc = (yasm_bytecode *)NULL; - *prefix = 0; - - if (id_len > 16) - return YASM_ARCH_NOTINSNPREFIX; - for (i=0; i<id_len; i++) - lcaseid[i] = tolower(id[i]); - lcaseid[id_len] = '\0'; - - switch (PARSER(arch_x86)) { - case X86_PARSER_NASM: - pdata = insnprefix_nasm_find(lcaseid, id_len); - break; - case X86_PARSER_TASM: - pdata = insnprefix_nasm_find(lcaseid, id_len); - break; - case X86_PARSER_GAS: - pdata = insnprefix_gas_find(lcaseid, id_len); - break; - default: - pdata = NULL; - } - if (!pdata) - return YASM_ARCH_NOTINSNPREFIX; - - if (pdata->group) { - x86_id_insn *id_insn; - wordptr cpu_enabled = arch_x86->cpu_enables[arch_x86->active_cpu]; - unsigned int cpu0, cpu1, cpu2; - - if (arch_x86->mode_bits != 64 && (pdata->misc_flags & ONLY_64)) { - yasm_warn_set(YASM_WARN_GENERAL, - N_("`%s' is an instruction in 64-bit mode"), id); - return YASM_ARCH_NOTINSNPREFIX; - } - if (arch_x86->mode_bits == 64 && (pdata->misc_flags & NOT_64)) { - yasm_error_set(YASM_ERROR_GENERAL, - N_("`%s' invalid in 64-bit mode"), id); - id_insn = yasm_xmalloc(sizeof(x86_id_insn)); - yasm_insn_initialize(&id_insn->insn); - id_insn->group = not64_insn; - id_insn->cpu_enabled = cpu_enabled; - id_insn->mod_data[0] = 0; - id_insn->mod_data[1] = 0; - id_insn->mod_data[2] = 0; - id_insn->num_info = NELEMS(not64_insn); - id_insn->mode_bits = arch_x86->mode_bits; - id_insn->suffix = 0; - id_insn->misc_flags = 0; - id_insn->parser = PARSER(arch_x86); - - id_insn->force_strict = arch_x86->force_strict != 0; - id_insn->default_rel = arch_x86->default_rel != 0; - *bc = yasm_bc_create_common(&x86_id_insn_callback, id_insn, line); - return YASM_ARCH_INSN; - } - - cpu0 = pdata->cpu0; - cpu1 = pdata->cpu1; - cpu2 = pdata->cpu2; - - if (!BitVector_bit_test(cpu_enabled, cpu0) || - !BitVector_bit_test(cpu_enabled, cpu1) || - !BitVector_bit_test(cpu_enabled, cpu2)) { - yasm_warn_set(YASM_WARN_GENERAL, - N_("`%s' is an instruction in CPU%s"), id, - cpu_find_reverse(cpu0, cpu1, cpu2)); - return YASM_ARCH_NOTINSNPREFIX; - } - - id_insn = yasm_xmalloc(sizeof(x86_id_insn)); - yasm_insn_initialize(&id_insn->insn); - id_insn->group = pdata->group; - id_insn->cpu_enabled = cpu_enabled; - id_insn->mod_data[0] = pdata->mod_data0; - id_insn->mod_data[1] = pdata->mod_data1; - id_insn->mod_data[2] = pdata->mod_data2; - id_insn->num_info = pdata->num_info; - id_insn->mode_bits = arch_x86->mode_bits; - id_insn->suffix = pdata->flags; - id_insn->misc_flags = pdata->misc_flags; - id_insn->parser = PARSER(arch_x86); - id_insn->force_strict = arch_x86->force_strict != 0; - id_insn->default_rel = arch_x86->default_rel != 0; - *bc = yasm_bc_create_common(&x86_id_insn_callback, id_insn, line); - return YASM_ARCH_INSN; - } else { - unsigned long type = pdata->num_info<<8; - unsigned long value = pdata->flags; - - if (arch_x86->mode_bits == 64 && type == X86_OPERSIZE && value == 32) { - yasm_error_set(YASM_ERROR_GENERAL, - N_("Cannot override data size to 32 bits in 64-bit mode")); - return YASM_ARCH_NOTINSNPREFIX; - } - - if (arch_x86->mode_bits == 64 && type == X86_ADDRSIZE && value == 16) { - yasm_error_set(YASM_ERROR_GENERAL, - N_("Cannot override address size to 16 bits in 64-bit mode")); - return YASM_ARCH_NOTINSNPREFIX; - } - - if (arch_x86->mode_bits != 64 && (pdata->misc_flags & ONLY_64)) { - yasm_warn_set(YASM_WARN_GENERAL, - N_("`%s' is a prefix in 64-bit mode"), id); - return YASM_ARCH_NOTINSNPREFIX; - } - *prefix = type|value; - return YASM_ARCH_PREFIX; - } -} - -static void -x86_id_insn_destroy(void *contents) -{ - x86_id_insn *id_insn = (x86_id_insn *)contents; - yasm_insn_delete(&id_insn->insn, yasm_x86__ea_destroy); - yasm_xfree(contents); -} - -static void -x86_id_insn_print(const void *contents, FILE *f, int indent_level) -{ - const x86_id_insn *id_insn = (const x86_id_insn *)contents; - yasm_insn_print(&id_insn->insn, f, indent_level); - /*TODO*/ -} - -/*@only@*/ yasm_bytecode * -yasm_x86__create_empty_insn(yasm_arch *arch, unsigned long line) -{ - yasm_arch_x86 *arch_x86 = (yasm_arch_x86 *)arch; - x86_id_insn *id_insn = yasm_xmalloc(sizeof(x86_id_insn)); - - yasm_insn_initialize(&id_insn->insn); - id_insn->group = empty_insn; - id_insn->cpu_enabled = arch_x86->cpu_enables[arch_x86->active_cpu]; - id_insn->mod_data[0] = 0; - id_insn->mod_data[1] = 0; - id_insn->mod_data[2] = 0; - id_insn->num_info = NELEMS(empty_insn); - id_insn->mode_bits = arch_x86->mode_bits; - id_insn->suffix = (PARSER(arch_x86) == X86_PARSER_GAS) ? SUF_Z : 0; - id_insn->misc_flags = 0; - id_insn->parser = PARSER(arch_x86); - id_insn->force_strict = arch_x86->force_strict != 0; - id_insn->default_rel = arch_x86->default_rel != 0; - - return yasm_bc_create_common(&x86_id_insn_callback, id_insn, line); -} - +/* + * x86 identifier recognition and instruction handling + * + * Copyright (C) 2002-2007 Peter Johnson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include <ctype.h> +#include <util.h> + +#include <libyasm.h> +#include <libyasm/phash.h> + +#include "modules/arch/x86/x86arch.h" + + +static const char *cpu_find_reverse(unsigned int cpu0, unsigned int cpu1, + unsigned int cpu2); + +/* Opcode modifiers. */ +#define MOD_Gap 0 /* Eats a parameter / does nothing */ +#define MOD_PreAdd 1 /* Parameter adds to "special" prefix */ +#define MOD_Op0Add 2 /* Parameter adds to opcode byte 0 */ +#define MOD_Op1Add 3 /* Parameter adds to opcode byte 1 */ +#define MOD_Op2Add 4 /* Parameter adds to opcode byte 2 */ +#define MOD_SpAdd 5 /* Parameter adds to "spare" value */ +#define MOD_OpSizeR 6 /* Parameter replaces opersize */ +#define MOD_Imm8 7 /* Parameter is included as immediate byte */ +#define MOD_AdSizeR 8 /* Parameter replaces addrsize (jmp only) */ +#define MOD_DOpS64R 9 /* Parameter replaces default 64-bit opersize */ +#define MOD_Op1AddSp 10 /* Parameter is added as "spare" to opcode byte 2 */ +#define MOD_SetVEX 11 /* Parameter replaces internal VEX prefix value */ + +/* GAS suffix flags for instructions */ +enum x86_gas_suffix_flags { + SUF_Z = 1<<0, /* no suffix */ + SUF_B = 1<<1, + SUF_W = 1<<2, + SUF_L = 1<<3, + SUF_Q = 1<<4, + SUF_S = 1<<5, + SUF_MASK = SUF_Z|SUF_B|SUF_W|SUF_L|SUF_Q|SUF_S, + + /* Flags only used in x86_insn_info */ + GAS_ONLY = 1<<6, /* Only available in GAS mode */ + GAS_ILLEGAL = 1<<7, /* Illegal in GAS mode */ + GAS_NO_REV = 1<<8 /* Don't reverse operands in GAS mode */ +}; + +/* Miscellaneous flag tests for instructions */ +enum x86_misc_flags { + /* These are tested against BITS==64. */ + ONLY_64 = 1<<0, /* Only available in 64-bit mode */ + NOT_64 = 1<<1, /* Not available (invalid) in 64-bit mode */ + /* These are tested against whether the base instruction is an AVX one. */ + ONLY_AVX = 1<<2, /* Only available in AVX instruction */ + NOT_AVX = 1<<3 /* Not available (invalid) in AVX instruction */ +}; + +enum x86_operand_type { + OPT_Imm = 0, /* immediate */ + OPT_Reg = 1, /* any general purpose or FPU register */ + OPT_Mem = 2, /* memory */ + OPT_RM = 3, /* any general purpose or FPU register OR memory */ + OPT_SIMDReg = 4, /* any MMX or XMM register */ + OPT_SIMDRM = 5, /* any MMX or XMM register OR memory */ + OPT_SegReg = 6, /* any segment register */ + OPT_CRReg = 7, /* any CR register */ + OPT_DRReg = 8, /* any DR register */ + OPT_TRReg = 9, /* any TR register */ + OPT_ST0 = 10, /* ST0 */ + OPT_Areg = 11, /* AL/AX/EAX/RAX (depending on size) */ + OPT_Creg = 12, /* CL/CX/ECX/RCX (depending on size) */ + OPT_Dreg = 13, /* DL/DX/EDX/RDX (depending on size) */ + OPT_CS = 14, /* CS */ + OPT_DS = 15, /* DS */ + OPT_ES = 16, /* ES */ + OPT_FS = 17, /* FS */ + OPT_GS = 18, /* GS */ + OPT_SS = 19, /* SS */ + OPT_CR4 = 20, /* CR4 */ + /* memory offset (an EA, but with no registers allowed) + * [special case for MOV opcode] + */ + OPT_MemOffs = 21, + OPT_Imm1 = 22, /* immediate, value=1 (for special-case shift) */ + /* immediate, does not contain SEG:OFF (for jmp/call) */ + OPT_ImmNotSegOff = 23, + OPT_XMM0 = 24, /* XMM0 */ + /* AX/EAX/RAX memory operand only (EA) [special case for SVM opcodes] + */ + OPT_MemrAX = 25, + /* EAX memory operand only (EA) [special case for SVM skinit opcode] */ + OPT_MemEAX = 26, + /* XMM VSIB memory operand */ + OPT_MemXMMIndex = 27, + /* YMM VSIB memory operand */ + OPT_MemYMMIndex = 28 +}; + +enum x86_operand_size { + /* any size acceptable/no size spec acceptable (dep. on strict) */ + OPS_Any = 0, + /* 8/16/32/64/80/128/256 bits (from user or reg size) */ + OPS_8 = 1, + OPS_16 = 2, + OPS_32 = 3, + OPS_64 = 4, + OPS_80 = 5, + OPS_128 = 6, + OPS_256 = 7, + /* current BITS setting; when this is used the size matched + * gets stored into the opersize as well. + */ + OPS_BITS = 8 +}; + +enum x86_operand_targetmod { + OPTM_None = 0, /* no target mod acceptable */ + OPTM_Near = 1, /* NEAR */ + OPTM_Short = 2, /* SHORT */ + OPTM_Far = 3, /* FAR (or SEG:OFF immediate) */ + OPTM_To = 4 /* TO */ +}; + +enum x86_operand_action { + OPA_None = 0, /* does nothing (operand data is discarded) */ + OPA_EA = 1, /* operand data goes into ea field */ + OPA_Imm = 2, /* operand data goes into imm field */ + OPA_SImm = 3, /* operand data goes into sign-extended imm field */ + OPA_Spare = 4, /* operand data goes into "spare" field */ + OPA_Op0Add = 5, /* operand data is added to opcode byte 0 */ + OPA_Op1Add = 6, /* operand data is added to opcode byte 1 */ + /* operand data goes into BOTH ea and spare + * (special case for imul opcode) + */ + OPA_SpareEA = 7, + /* relative jump (outputs a jmp instead of normal insn) */ + OPA_JmpRel = 8, + /* operand size goes into address size (jmp only) */ + OPA_AdSizeR = 9, + /* far jump (outputs a farjmp instead of normal insn) */ + OPA_JmpFar = 10, + /* ea operand only sets address size (no actual ea field) */ + OPA_AdSizeEA = 11, + OPA_VEX = 12, /* operand data goes into VEX/XOP "vvvv" field */ + /* operand data goes into BOTH VEX/XOP "vvvv" field and ea field */ + OPA_EAVEX = 13, + /* operand data goes into BOTH VEX/XOP "vvvv" field and spare field */ + OPA_SpareVEX = 14, + /* operand data goes into upper 4 bits of immediate byte (VEX is4 field) */ + OPA_VEXImmSrc = 15, + /* operand data goes into bottom 4 bits of immediate byte + * (currently only VEX imz2 field) + */ + OPA_VEXImm = 16 +}; + +enum x86_operand_post_action { + OPAP_None = 0, + /* sign-extended imm8 that could expand to a large imm16/32 */ + OPAP_SImm8 = 1, + /* could become a short opcode mov with bits=64 and a32 prefix */ + OPAP_ShortMov = 2, + /* forced 16-bit address size (override ignored, no prefix) */ + OPAP_A16 = 3, + /* large imm64 that can become a sign-extended imm32 */ + OPAP_SImm32Avail = 4 +}; + +typedef struct x86_info_operand { + /* Operand types. These are more detailed than the "general" types for all + * architectures, as they include the size, for instance. + */ + + /* general type (must be exact match, except for RM types): */ + unsigned int type:5; + + /* size (user-specified, or from register size) */ + unsigned int size:4; + + /* size implicit or explicit ("strictness" of size matching on + * non-registers -- registers are always strictly matched): + * 0 = user size must exactly match size above. + * 1 = user size either unspecified or exactly match size above. + */ + unsigned int relaxed:1; + + /* effective address size + * 0 = any address size allowed except for 64-bit + * 1 = only 64-bit address size allowed + */ + unsigned int eas64:1; + + /* target modification */ + unsigned int targetmod:3; + + /* Actions: what to do with the operand if the instruction matches. + * Essentially describes what part of the output bytecode gets the + * operand. This may require conversion (e.g. a register going into + * an ea field). Naturally, only one of each of these may be contained + * in the operands of a single insn_info structure. + */ + unsigned int action:5; + + /* Postponed actions: actions which can't be completed at + * parse-time due to possibly dependent expressions. For these, some + * additional data (stored in the second byte of the opcode with a + * one-byte opcode) is passed to later stages of the assembler with + * flags set to indicate postponed actions. + */ + unsigned int post_action:3; +} x86_info_operand; + +typedef struct x86_insn_info { + /* GAS suffix flags */ + unsigned int gas_flags:9; /* Enabled for these GAS suffixes */ + + /* Tests against BITS==64, AVX, and XOP */ + unsigned int misc_flags:5; + + /* The CPU feature flags needed to execute this instruction. This is OR'ed + * with arch-specific data[2]. This combined value is compared with + * cpu_enabled to see if all bits set here are set in cpu_enabled--if so, + * the instruction is available on this CPU. + */ + unsigned int cpu0:6; + unsigned int cpu1:6; + unsigned int cpu2:6; + + /* Opcode modifiers for variations of instruction. As each modifier reads + * its parameter in LSB->MSB order from the arch-specific data[1] from the + * lexer data, and the LSB of the arch-specific data[1] is reserved for the + * count of insn_info structures in the instruction grouping, there can + * only be a maximum of 3 modifiers. + */ + unsigned char modifiers[3]; + + /* Operand Size */ + unsigned char opersize; + + /* Default operand size in 64-bit mode (0 = 32-bit for readability). */ + unsigned char def_opersize_64; + + /* A special instruction prefix, used for some of the Intel SSE and SSE2 + * instructions. Intel calls these 3-byte opcodes, but in AMD64's 64-bit + * mode, they're treated like normal prefixes (e.g. the REX prefix needs + * to be *after* the F2/F3/66 "prefix"). + * (0=no special prefix) + * 0xC0 - 0xCF indicate a VEX prefix, with the four LSBs holding "WLpp": + * W: VEX.W field (meaning depends on opcode) + * L: 0=128-bit, 1=256-bit + * pp: SIMD prefix designation: + * 00: None + * 01: 66 + * 10: F3 + * 11: F2 + * 0x80 - 0x8F indicate a XOP prefix, with the four LSBs holding "WLpp": + * same meanings as VEX prefix. + */ + unsigned char special_prefix; + + /* The length of the basic opcode */ + unsigned char opcode_len; + + /* The basic 1-3 byte opcode (not including the special instruction + * prefix). + */ + unsigned char opcode[3]; + + /* The 3-bit "spare" value (extended opcode) for the R/M byte field */ + unsigned char spare; + + /* The number of operands this form of the instruction takes */ + unsigned int num_operands:4; + + /* The index into the insn_operands array which contains the type of each + * operand, see above + */ + unsigned int operands_index:12; +} x86_insn_info; + +typedef struct x86_id_insn { + yasm_insn insn; /* base structure */ + + /* instruction parse group - NULL if empty instruction (just prefixes) */ + /*@null@*/ const x86_insn_info *group; + + /* CPU feature flags enabled at the time of parsing the instruction */ + wordptr cpu_enabled; + + /* Modifier data */ + unsigned char mod_data[3]; + + /* Number of elements in the instruction parse group */ + unsigned int num_info:8; + + /* BITS setting active at the time of parsing the instruction */ + unsigned int mode_bits:8; + + /* Suffix flags */ + unsigned int suffix:9; + + /* Tests against BITS==64 and AVX */ + unsigned int misc_flags:5; + + /* Parser enabled at the time of parsing the instruction */ + unsigned int parser:2; + + /* Strict forced setting at the time of parsing the instruction */ + unsigned int force_strict:1; + + /* Default rel setting at the time of parsing the instruction */ + unsigned int default_rel:1; +} x86_id_insn; + +static void x86_id_insn_destroy(void *contents); +static void x86_id_insn_print(const void *contents, FILE *f, int indent_level); +static void x86_id_insn_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc); + +static const yasm_bytecode_callback x86_id_insn_callback = { + x86_id_insn_destroy, + x86_id_insn_print, + x86_id_insn_finalize, + NULL, + yasm_bc_calc_len_common, + yasm_bc_expand_common, + yasm_bc_tobytes_common, + YASM_BC_SPECIAL_INSN +}; + +#include "x86insns.c" + +/* Looks for the first SIMD register match for the purposes of VSIB matching. + * Full legality checking is performed in EA code. + */ +static int +x86_expr_contains_simd_cb(const yasm_expr__item *ei, void *d) +{ + int ymm = *((int *)d); + if (ei->type != YASM_EXPR_REG) + return 0; + switch ((x86_expritem_reg_size)(ei->data.reg & ~0xFUL)) { + case X86_XMMREG: + if (!ymm) + return 1; + break; + case X86_YMMREG: + if (ymm) + return 1; + break; + default: + break; + } + return 0; +} + +static int +x86_expr_contains_simd(const yasm_expr *e, int ymm) +{ + return yasm_expr__traverse_leaves_in_const(e, &ymm, + x86_expr_contains_simd_cb); +} + +static void +x86_finalize_common(x86_common *common, const x86_insn_info *info, + unsigned int mode_bits) +{ + common->addrsize = 0; + common->opersize = info->opersize; + common->lockrep_pre = 0; + common->acqrel_pre = 0; + common->mode_bits = (unsigned char)mode_bits; +} + +static void +x86_finalize_opcode(x86_opcode *opcode, const x86_insn_info *info) +{ + opcode->len = info->opcode_len; + opcode->opcode[0] = info->opcode[0]; + opcode->opcode[1] = info->opcode[1]; + opcode->opcode[2] = info->opcode[2]; +} + +/* Clear operands so they don't get destroyed after we've copied references. */ +static void +x86_id_insn_clear_operands(x86_id_insn *id_insn) +{ + yasm_insn_operand *op = yasm_insn_ops_first(&id_insn->insn); + while (op) { + op->type = YASM_INSN__OPERAND_REG; + op = yasm_insn_op_next(op); + } +} + +static void +x86_finalize_jmpfar(yasm_bytecode *bc, yasm_bytecode *prev_bc, + const x86_insn_info *info) +{ + x86_id_insn *id_insn = (x86_id_insn *)bc->contents; + unsigned char *mod_data = id_insn->mod_data; + unsigned int mode_bits = id_insn->mode_bits; + x86_jmpfar *jmpfar; + yasm_insn_operand *op; + unsigned int i; + + jmpfar = yasm_xmalloc(sizeof(x86_jmpfar)); + x86_finalize_common(&jmpfar->common, info, mode_bits); + x86_finalize_opcode(&jmpfar->opcode, info); + + op = yasm_insn_ops_first(&id_insn->insn); + + 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, + 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". */ + 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")); + } else if (yasm_insn_op_next(op)) { + /* Two operand form (gas) */ + yasm_insn_operand *op2 = yasm_insn_op_next(op); + if (yasm_value_finalize_expr(&jmpfar->segment, op->data.val, prev_bc, + 16)) + yasm_error_set(YASM_ERROR_TOO_COMPLEX, + N_("jump target segment too complex")); + if (yasm_value_finalize_expr(&jmpfar->offset, op2->data.val, prev_bc, + 0)) + yasm_error_set(YASM_ERROR_TOO_COMPLEX, + N_("jump target offset too complex")); + if (op2->size == OPS_BITS) + jmpfar->common.opersize = (unsigned char)mode_bits; + } else + yasm_internal_error(N_("didn't get FAR expression in jmpfar")); + + /* Apply modifiers */ + for (i=0; i<NELEMS(info->modifiers); i++) { + switch (info->modifiers[i]) { + case MOD_Gap: + break; + case MOD_Op0Add: + jmpfar->opcode.opcode[0] += mod_data[i]; + break; + case MOD_Op1Add: + jmpfar->opcode.opcode[1] += mod_data[i]; + break; + case MOD_Op2Add: + jmpfar->opcode.opcode[2] += mod_data[i]; + break; + case MOD_Op1AddSp: + jmpfar->opcode.opcode[1] += mod_data[i]<<3; + break; + default: + break; + } + } + + yasm_x86__bc_apply_prefixes((x86_common *)jmpfar, NULL, + info->def_opersize_64, + id_insn->insn.num_prefixes, + id_insn->insn.prefixes); + + x86_id_insn_clear_operands(id_insn); + + /* Transform the bytecode */ + yasm_x86__bc_transform_jmpfar(bc, jmpfar); +} + +static void +x86_finalize_jmp(yasm_bytecode *bc, yasm_bytecode *prev_bc, + const x86_insn_info *jinfo) +{ + x86_id_insn *id_insn = (x86_id_insn *)bc->contents; + x86_jmp *jmp; + int num_info = id_insn->num_info; + const x86_insn_info *info = id_insn->group; + unsigned char *mod_data = id_insn->mod_data; + unsigned int mode_bits = id_insn->mode_bits; + /*unsigned char suffix = id_insn->suffix;*/ + yasm_insn_operand *op; + static const unsigned char size_lookup[] = + {0, 8, 16, 32, 64, 80, 128, 0, 0}; /* 256 not needed */ + unsigned int i; + + /* We know the target is in operand 0, but sanity check for Imm. */ + op = yasm_insn_ops_first(&id_insn->insn); + if (op->type != YASM_INSN__OPERAND_IMM) + yasm_internal_error(N_("invalid operand conversion")); + + jmp = yasm_xmalloc(sizeof(x86_jmp)); + x86_finalize_common(&jmp->common, jinfo, mode_bits); + if (yasm_value_finalize_expr(&jmp->target, op->data.val, prev_bc, 0)) + yasm_error_set(YASM_ERROR_TOO_COMPLEX, + 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")); + yasm_value_set_curpos_rel(&jmp->target, bc, 0); + jmp->target.jump_target = 1; + + /* See if the user explicitly specified short/near/far. */ + switch (insn_operands[jinfo->operands_index+0].targetmod) { + case OPTM_Short: + jmp->op_sel = JMP_SHORT_FORCED; + break; + case OPTM_Near: + jmp->op_sel = JMP_NEAR_FORCED; + break; + default: + jmp->op_sel = JMP_NONE; + } + + /* Check for address size setting in second operand, if present */ + if (jinfo->num_operands > 1 && + insn_operands[jinfo->operands_index+1].action == OPA_AdSizeR) + jmp->common.addrsize = (unsigned char) + size_lookup[insn_operands[jinfo->operands_index+1].size]; + + /* Check for address size override */ + for (i=0; i<NELEMS(jinfo->modifiers); i++) { + if (jinfo->modifiers[i] == MOD_AdSizeR) + jmp->common.addrsize = mod_data[i]; + } + + /* Scan through other infos for this insn looking for short/near versions. + * Needs to match opersize and number of operands, also be within CPU. + */ + jmp->shortop.len = 0; + jmp->nearop.len = 0; + for (; num_info>0 && (jmp->shortop.len == 0 || jmp->nearop.len == 0); + num_info--, info++) { + /* Match CPU */ + if (mode_bits != 64 && (info->misc_flags & ONLY_64)) + continue; + if (mode_bits == 64 && (info->misc_flags & NOT_64)) + continue; + + if (!BitVector_bit_test(id_insn->cpu_enabled, info->cpu0) || + !BitVector_bit_test(id_insn->cpu_enabled, info->cpu1) || + !BitVector_bit_test(id_insn->cpu_enabled, info->cpu2)) + continue; + + if (info->num_operands == 0) + continue; + + if (insn_operands[info->operands_index+0].action != OPA_JmpRel) + continue; + + if (info->opersize != jmp->common.opersize) + continue; + + switch (insn_operands[info->operands_index+0].targetmod) { + case OPTM_Short: + x86_finalize_opcode(&jmp->shortop, info); + for (i=0; i<NELEMS(info->modifiers); i++) { + if (info->modifiers[i] == MOD_Op0Add) + jmp->shortop.opcode[0] += mod_data[i]; + } + break; + case OPTM_Near: + x86_finalize_opcode(&jmp->nearop, info); + for (i=0; i<NELEMS(info->modifiers); i++) { + if (info->modifiers[i] == MOD_Op1Add) + jmp->nearop.opcode[1] += mod_data[i]; + } + break; + } + } + + if ((jmp->op_sel == JMP_SHORT_FORCED) && (jmp->shortop.len == 0)) + yasm_error_set(YASM_ERROR_TYPE, + N_("no SHORT form of that jump instruction exists")); + if ((jmp->op_sel == JMP_NEAR_FORCED) && (jmp->nearop.len == 0)) + yasm_error_set(YASM_ERROR_TYPE, + N_("no NEAR form of that jump instruction exists")); + + if (jmp->op_sel == JMP_NONE) { + if (jmp->nearop.len == 0) + jmp->op_sel = JMP_SHORT_FORCED; + if (jmp->shortop.len == 0) + jmp->op_sel = JMP_NEAR_FORCED; + } + + yasm_x86__bc_apply_prefixes((x86_common *)jmp, NULL, + jinfo->def_opersize_64, + id_insn->insn.num_prefixes, + id_insn->insn.prefixes); + + x86_id_insn_clear_operands(id_insn); + + /* Transform the bytecode */ + yasm_x86__bc_transform_jmp(bc, jmp); +} + +static const x86_insn_info * +x86_find_match(x86_id_insn *id_insn, yasm_insn_operand **ops, + yasm_insn_operand **rev_ops, const unsigned int *size_lookup, + int bypass) +{ + const x86_insn_info *info = id_insn->group; + unsigned int num_info = id_insn->num_info; + unsigned int suffix = id_insn->suffix; + unsigned int mode_bits = id_insn->mode_bits; + int found = 0; + + /* Just do a simple linear search through the info array for a match. + * First match wins. + */ + for (; num_info>0 && !found; num_info--, info++) { + yasm_insn_operand *op, **use_ops; + const x86_info_operand *info_ops = + &insn_operands[info->operands_index]; + unsigned int gas_flags = info->gas_flags; + unsigned int misc_flags = info->misc_flags; + unsigned int size; + int mismatch = 0; + unsigned int i; + + /* Match CPU */ + if (mode_bits != 64 && (misc_flags & ONLY_64)) + continue; + if (mode_bits == 64 && (misc_flags & NOT_64)) + continue; + + if (bypass != 8 && + (!BitVector_bit_test(id_insn->cpu_enabled, info->cpu0) || + !BitVector_bit_test(id_insn->cpu_enabled, info->cpu1) || + !BitVector_bit_test(id_insn->cpu_enabled, info->cpu2))) + continue; + + /* Match # of operands */ + if (id_insn->insn.num_operands != info->num_operands) + continue; + + /* Match AVX */ + if (!(id_insn->misc_flags & ONLY_AVX) && (misc_flags & ONLY_AVX)) + continue; + if ((id_insn->misc_flags & ONLY_AVX) && (misc_flags & NOT_AVX)) + continue; + + /* Match parser mode */ + if ((gas_flags & GAS_ONLY) && id_insn->parser != X86_PARSER_GAS) + continue; + if ((gas_flags & GAS_ILLEGAL) && id_insn->parser == X86_PARSER_GAS) + continue; + + /* Match suffix (if required) */ + if (id_insn->parser == X86_PARSER_GAS + && ((suffix & SUF_MASK) & (gas_flags & SUF_MASK)) == 0) + continue; + + /* Use reversed operands in GAS mode if not otherwise specified */ + use_ops = ops; + if (id_insn->parser == X86_PARSER_GAS && !(gas_flags & GAS_NO_REV)) + use_ops = rev_ops; + + if (id_insn->insn.num_operands == 0) { + found = 1; /* no operands -> must have a match here. */ + break; + } + + /* Match each operand type and size */ + for (i = 0, op = use_ops[0]; op && i<info->num_operands && !mismatch; + op = use_ops[++i]) { + /* Check operand type */ + switch (info_ops[i].type) { + case OPT_Imm: + if (op->type != YASM_INSN__OPERAND_IMM) + mismatch = 1; + break; + case OPT_RM: + if (op->type == YASM_INSN__OPERAND_MEMORY) + break; + /*@fallthrough@*/ + case OPT_Reg: + if (op->type != YASM_INSN__OPERAND_REG) + mismatch = 1; + else { + switch ((x86_expritem_reg_size)(op->data.reg&~0xFUL)) { + case X86_REG8: + case X86_REG8X: + case X86_REG16: + case X86_REG32: + case X86_REG64: + case X86_FPUREG: + break; + default: + mismatch = 1; + break; + } + } + break; + case OPT_Mem: + if (op->type != YASM_INSN__OPERAND_MEMORY) + mismatch = 1; + break; + case OPT_SIMDRM: + if (op->type == YASM_INSN__OPERAND_MEMORY) + break; + /*@fallthrough@*/ + case OPT_SIMDReg: + if (op->type != YASM_INSN__OPERAND_REG) + mismatch = 1; + else { + switch ((x86_expritem_reg_size)(op->data.reg&~0xFUL)) { + case X86_MMXREG: + case X86_XMMREG: + case X86_YMMREG: + break; + default: + mismatch = 1; + break; + } + } + break; + case OPT_SegReg: + if (op->type != YASM_INSN__OPERAND_SEGREG) + mismatch = 1; + break; + case OPT_CRReg: + if (op->type != YASM_INSN__OPERAND_REG || + (op->data.reg & ~0xFUL) != X86_CRREG) + mismatch = 1; + break; + case OPT_DRReg: + if (op->type != YASM_INSN__OPERAND_REG || + (op->data.reg & ~0xFUL) != X86_DRREG) + mismatch = 1; + break; + case OPT_TRReg: + if (op->type != YASM_INSN__OPERAND_REG || + (op->data.reg & ~0xFUL) != X86_TRREG) + mismatch = 1; + break; + case OPT_ST0: + if (op->type != YASM_INSN__OPERAND_REG || + op->data.reg != X86_FPUREG) + mismatch = 1; + break; + case OPT_Areg: + if (op->type != YASM_INSN__OPERAND_REG || + (info_ops[i].size == OPS_8 && + op->data.reg != (X86_REG8 | 0) && + op->data.reg != (X86_REG8X | 0)) || + (info_ops[i].size == OPS_16 && + op->data.reg != (X86_REG16 | 0)) || + (info_ops[i].size == OPS_32 && + op->data.reg != (X86_REG32 | 0)) || + (info_ops[i].size == OPS_64 && + op->data.reg != (X86_REG64 | 0))) + mismatch = 1; + break; + case OPT_Creg: + if (op->type != YASM_INSN__OPERAND_REG || + (info_ops[i].size == OPS_8 && + op->data.reg != (X86_REG8 | 1) && + op->data.reg != (X86_REG8X | 1)) || + (info_ops[i].size == OPS_16 && + op->data.reg != (X86_REG16 | 1)) || + (info_ops[i].size == OPS_32 && + op->data.reg != (X86_REG32 | 1)) || + (info_ops[i].size == OPS_64 && + op->data.reg != (X86_REG64 | 1))) + mismatch = 1; + break; + case OPT_Dreg: + if (op->type != YASM_INSN__OPERAND_REG || + (info_ops[i].size == OPS_8 && + op->data.reg != (X86_REG8 | 2) && + op->data.reg != (X86_REG8X | 2)) || + (info_ops[i].size == OPS_16 && + op->data.reg != (X86_REG16 | 2)) || + (info_ops[i].size == OPS_32 && + op->data.reg != (X86_REG32 | 2)) || + (info_ops[i].size == OPS_64 && + op->data.reg != (X86_REG64 | 2))) + mismatch = 1; + break; + case OPT_CS: + if (op->type != YASM_INSN__OPERAND_SEGREG || + (op->data.reg & 0xF) != 1) + mismatch = 1; + break; + case OPT_DS: + if (op->type != YASM_INSN__OPERAND_SEGREG || + (op->data.reg & 0xF) != 3) + mismatch = 1; + break; + case OPT_ES: + if (op->type != YASM_INSN__OPERAND_SEGREG || + (op->data.reg & 0xF) != 0) + mismatch = 1; + break; + case OPT_FS: + if (op->type != YASM_INSN__OPERAND_SEGREG || + (op->data.reg & 0xF) != 4) + mismatch = 1; + break; + case OPT_GS: + if (op->type != YASM_INSN__OPERAND_SEGREG || + (op->data.reg & 0xF) != 5) + mismatch = 1; + break; + case OPT_SS: + if (op->type != YASM_INSN__OPERAND_SEGREG || + (op->data.reg & 0xF) != 2) + mismatch = 1; + break; + case OPT_CR4: + if (op->type != YASM_INSN__OPERAND_REG || + op->data.reg != (X86_CRREG | 4)) + mismatch = 1; + break; + case OPT_MemOffs: + if (op->type != YASM_INSN__OPERAND_MEMORY || + yasm_expr__contains(op->data.ea->disp.abs, + YASM_EXPR_REG) || + op->data.ea->pc_rel || + (!op->data.ea->not_pc_rel && id_insn->default_rel && + op->data.ea->disp.size != 64)) + mismatch = 1; + break; + case OPT_Imm1: + if (op->type == YASM_INSN__OPERAND_IMM) { + const yasm_intnum *num; + num = yasm_expr_get_intnum(&op->data.val, 0); + if (!num || !yasm_intnum_is_pos1(num)) + mismatch = 1; + } else + mismatch = 1; + break; + case OPT_ImmNotSegOff: + if (op->type != YASM_INSN__OPERAND_IMM || + op->targetmod != 0 || op->seg) + mismatch = 1; + break; + case OPT_XMM0: + if (op->type != YASM_INSN__OPERAND_REG || + op->data.reg != X86_XMMREG) + mismatch = 1; + break; + case OPT_MemrAX: { + const uintptr_t *regp; + if (op->type != YASM_INSN__OPERAND_MEMORY || + !(regp = yasm_expr_get_reg(&op->data.ea->disp.abs, 0)) || + (*regp != (X86_REG16 | 0) && + *regp != (X86_REG32 | 0) && + *regp != (X86_REG64 | 0))) + mismatch = 1; + break; + } + case OPT_MemEAX: { + const uintptr_t *regp; + if (op->type != YASM_INSN__OPERAND_MEMORY || + !(regp = yasm_expr_get_reg(&op->data.ea->disp.abs, 0)) || + *regp != (X86_REG32 | 0)) + mismatch = 1; + break; + } + case OPT_MemXMMIndex: + if (op->type != YASM_INSN__OPERAND_MEMORY || + !x86_expr_contains_simd(op->data.ea->disp.abs, 0)) + mismatch = 1; + break; + case OPT_MemYMMIndex: + if (op->type != YASM_INSN__OPERAND_MEMORY || + !x86_expr_contains_simd(op->data.ea->disp.abs, 1)) + mismatch = 1; + break; + default: + yasm_internal_error(N_("invalid operand type")); + } + + if (mismatch) + break; + + /* Check operand size */ + size = size_lookup[info_ops[i].size]; + if (id_insn->parser == X86_PARSER_GAS) { + /* Require relaxed operands for GAS mode (don't allow + * per-operand sizing). + */ + if (op->type == YASM_INSN__OPERAND_REG && op->size == 0) { + /* Register size must exactly match */ + if (yasm_x86__get_reg_size(op->data.reg) != size) + mismatch = 1; + } else if ((info_ops[i].type == OPT_Imm + || info_ops[i].type == OPT_ImmNotSegOff + || info_ops[i].type == OPT_Imm1) + && !info_ops[i].relaxed + && info_ops[i].action != OPA_JmpRel) + mismatch = 1; + } else { + if (op->type == YASM_INSN__OPERAND_REG && op->size == 0) { + /* Register size must exactly match */ + if ((bypass == 4 && i == 0) || (bypass == 5 && i == 1) + || (bypass == 6 && i == 2)) + ; + else if (yasm_x86__get_reg_size(op->data.reg) != size) + mismatch = 1; + } else { + if ((bypass == 1 && i == 0) || (bypass == 2 && i == 1) + || (bypass == 3 && i == 2)) + ; + else if (info_ops[i].relaxed) { + /* Relaxed checking */ + if (size != 0 && op->size != size && op->size != 0) + mismatch = 1; + } else { + /* Strict checking */ + if (op->size != size) + mismatch = 1; + } + } + } + + if (mismatch) + break; + + /* Check for 64-bit effective address size in NASM mode */ + if (id_insn->parser != X86_PARSER_GAS && + op->type == YASM_INSN__OPERAND_MEMORY) { + if (info_ops[i].eas64) { + if (op->data.ea->disp.size != 64) + mismatch = 1; + } else if (op->data.ea->disp.size == 64) + mismatch = 1; + } + + if (mismatch) + break; + + /* Check target modifier */ + switch (info_ops[i].targetmod) { + case OPTM_None: + if (op->targetmod != 0) + mismatch = 1; + break; + case OPTM_Near: + if (op->targetmod != X86_NEAR) + mismatch = 1; + break; + case OPTM_Short: + if (op->targetmod != X86_SHORT) + mismatch = 1; + break; + case OPTM_Far: + if (op->targetmod != X86_FAR) + mismatch = 1; + break; + case OPTM_To: + if (op->targetmod != X86_TO) + mismatch = 1; + break; + default: + yasm_internal_error(N_("invalid target modifier type")); + } + } + + if (!mismatch) { + found = 1; + break; + } + } + + if (!found) + return NULL; + return info; +} + +static void +x86_match_error(x86_id_insn *id_insn, yasm_insn_operand **ops, + yasm_insn_operand **rev_ops, const unsigned int *size_lookup) +{ + const x86_insn_info *i; + int ni; + int found; + int bypass; + + /* Check for matching # of operands */ + found = 0; + for (ni=id_insn->num_info, i=id_insn->group; ni>0; ni--, i++) { + if (id_insn->insn.num_operands == i->num_operands) { + found = 1; + break; + } + } + if (!found) { + yasm_error_set(YASM_ERROR_TYPE, N_("invalid number of operands")); + return; + } + + for (bypass=1; bypass<9; bypass++) { + i = x86_find_match(id_insn, ops, rev_ops, size_lookup, bypass); + if (i) + break; + } + + switch (bypass) { + case 1: + case 4: + yasm_error_set(YASM_ERROR_TYPE, + N_("invalid size for operand %d"), 1); + break; + case 2: + case 5: + yasm_error_set(YASM_ERROR_TYPE, + N_("invalid size for operand %d"), 2); + break; + case 3: + case 6: + yasm_error_set(YASM_ERROR_TYPE, + N_("invalid size for operand %d"), 3); + break; + case 7: + yasm_error_set(YASM_ERROR_TYPE, + N_("one of source operand 1 or 3 must match dest operand")); + break; + case 8: + { + unsigned int cpu0 = i->cpu0, cpu1 = i->cpu1, cpu2 = i->cpu2; + yasm_error_set(YASM_ERROR_TYPE, + N_("requires CPU%s"), + cpu_find_reverse(cpu0, cpu1, cpu2)); + break; + } + default: + yasm_error_set(YASM_ERROR_TYPE, + N_("invalid combination of opcode and operands")); + } +} + +static void +x86_id_insn_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc) +{ + x86_id_insn *id_insn = (x86_id_insn *)bc->contents; + x86_insn *insn; + const x86_insn_info *info = id_insn->group; + unsigned int mode_bits = id_insn->mode_bits; + unsigned char *mod_data = id_insn->mod_data; + yasm_insn_operand *op, *ops[5], *rev_ops[5]; + /*@null@*/ yasm_expr *imm; + unsigned char im_len; + unsigned char im_sign; + unsigned char spare; + unsigned char vexdata, vexreg; + unsigned int i; + unsigned int size_lookup[] = {0, 8, 16, 32, 64, 80, 128, 256, 0}; + unsigned long do_postop = 0; + + size_lookup[OPS_BITS] = mode_bits; + + yasm_insn_finalize(&id_insn->insn); + + /* Build local array of operands from list, since we know we have a max + * of 5 operands. + */ + if (id_insn->insn.num_operands > 5) { + yasm_error_set(YASM_ERROR_TYPE, N_("too many operands")); + return; + } + ops[0] = ops[1] = ops[2] = ops[3] = ops[4] = NULL; + for (i = 0, op = yasm_insn_ops_first(&id_insn->insn); + op && i < id_insn->insn.num_operands; + op = yasm_insn_op_next(op), i++) + ops[i] = op; + + /* If we're running in GAS mode, build a reverse array of the operands + * as most GAS instructions have reversed operands from Intel style. + */ + if (id_insn->parser == X86_PARSER_GAS) { + rev_ops[0] = rev_ops[1] = rev_ops[2] = rev_ops[3] = rev_ops[4] = NULL; + for (i = id_insn->insn.num_operands-1, + op = yasm_insn_ops_first(&id_insn->insn); + op; op = yasm_insn_op_next(op), i--) + rev_ops[i] = op; + } + + /* If we're running in GAS mode, look at the first insn_info to see + * if this is a relative jump (OPA_JmpRel). If so, run through the + * operands and adjust for dereferences / lack thereof. + */ + if (id_insn->parser == X86_PARSER_GAS + && insn_operands[info->operands_index+0].action == OPA_JmpRel) { + for (i = 0, op = ops[0]; op; op = ops[++i]) { + if (!op->deref && (op->type == YASM_INSN__OPERAND_REG + || (op->type == YASM_INSN__OPERAND_MEMORY + && op->data.ea->strong))) + yasm_warn_set(YASM_WARN_GENERAL, + N_("indirect call without `*'")); + if (!op->deref && op->type == YASM_INSN__OPERAND_MEMORY + && !op->data.ea->strong) { + /* Memory that is not dereferenced, and not strong, is + * actually an immediate for the purposes of relative jumps. + */ + if (op->data.ea->segreg != 0) + yasm_warn_set(YASM_WARN_GENERAL, + N_("skipping prefixes on this instruction")); + imm = op->data.ea->disp.abs; + op->data.ea->disp.abs = NULL; + yasm_x86__ea_destroy(op->data.ea); + op->type = YASM_INSN__OPERAND_IMM; + op->data.val = imm; + } + } + } + + info = x86_find_match(id_insn, ops, rev_ops, size_lookup, 0); + + if (!info) { + /* Didn't find a match */ + x86_match_error(id_insn, ops, rev_ops, size_lookup); + return; + } + + if (id_insn->insn.num_operands > 0) { + switch (insn_operands[info->operands_index+0].action) { + case OPA_JmpRel: + /* Shortcut to JmpRel */ + x86_finalize_jmp(bc, prev_bc, info); + return; + case OPA_JmpFar: + /* Shortcut to JmpFar */ + x86_finalize_jmpfar(bc, prev_bc, info); + return; + } + } + + /* Copy what we can from info */ + insn = yasm_xmalloc(sizeof(x86_insn)); + x86_finalize_common(&insn->common, info, mode_bits); + x86_finalize_opcode(&insn->opcode, info); + insn->x86_ea = NULL; + imm = NULL; + insn->def_opersize_64 = info->def_opersize_64; + insn->special_prefix = info->special_prefix; + spare = info->spare; + vexdata = 0; + vexreg = 0; + im_len = 0; + im_sign = 0; + insn->postop = X86_POSTOP_NONE; + insn->rex = 0; + + /* Move VEX/XOP data (stored in special prefix) to separate location to + * allow overriding of special prefix by modifiers. + */ + if ((insn->special_prefix & 0xF0) == 0xC0 || + (insn->special_prefix & 0xF0) == 0x80) { + vexdata = insn->special_prefix; + insn->special_prefix = 0; + } + + /* Apply modifiers */ + for (i=0; i<NELEMS(info->modifiers); i++) { + switch (info->modifiers[i]) { + case MOD_Gap: + break; + case MOD_PreAdd: + insn->special_prefix += mod_data[i]; + break; + case MOD_Op0Add: + insn->opcode.opcode[0] += mod_data[i]; + break; + case MOD_Op1Add: + insn->opcode.opcode[1] += mod_data[i]; + break; + case MOD_Op2Add: + insn->opcode.opcode[2] += mod_data[i]; + break; + case MOD_SpAdd: + spare += mod_data[i]; + break; + case MOD_OpSizeR: + insn->common.opersize = mod_data[i]; + break; + case MOD_Imm8: + imm = yasm_expr_create_ident(yasm_expr_int( + yasm_intnum_create_uint(mod_data[i])), bc->line); + im_len = 8; + break; + case MOD_DOpS64R: + insn->def_opersize_64 = mod_data[i]; + break; + case MOD_Op1AddSp: + insn->opcode.opcode[1] += mod_data[i]<<3; + break; + case MOD_SetVEX: + vexdata = mod_data[i]; + break; + default: + break; + } + } + + /* In 64-bit mode, if opersize is 64 and default is not 64, + * force REX byte. + */ + if (mode_bits == 64 && insn->common.opersize == 64 && + insn->def_opersize_64 != 64) + insn->rex = 0x48; + + /* Go through operands and assign */ + if (id_insn->insn.num_operands > 0) { + yasm_insn_operand **use_ops = ops; + const x86_info_operand *info_ops = + &insn_operands[info->operands_index]; + + /* Use reversed operands in GAS mode if not otherwise specified */ + if (id_insn->parser == X86_PARSER_GAS + && !(info->gas_flags & GAS_NO_REV)) + use_ops = rev_ops; + + for (i = 0, op = use_ops[0]; op && i<info->num_operands; + op = use_ops[++i]) { + switch (info_ops[i].action) { + case OPA_None: + /* Throw away the operand contents */ + switch (op->type) { + case YASM_INSN__OPERAND_REG: + case YASM_INSN__OPERAND_SEGREG: + break; + case YASM_INSN__OPERAND_MEMORY: + yasm_x86__ea_destroy(op->data.ea); + break; + case YASM_INSN__OPERAND_IMM: + yasm_expr_destroy(op->data.val); + break; + } + break; + case OPA_EA: + switch (op->type) { + case YASM_INSN__OPERAND_REG: + insn->x86_ea = + yasm_x86__ea_create_reg(insn->x86_ea, + (unsigned long)op->data.reg, &insn->rex, + mode_bits); + break; + case YASM_INSN__OPERAND_SEGREG: + 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 */ + yasm_x86__ea_set_disponly(insn->x86_ea); + else if (info_ops[i].type == OPT_MemXMMIndex) { + /* Remember VSIB mode */ + insn->x86_ea->vsib_mode = 1; + insn->x86_ea->need_sib = 1; + } else if (info_ops[i].type == OPT_MemYMMIndex) { + /* Remember VSIB mode */ + insn->x86_ea->vsib_mode = 2; + insn->x86_ea->need_sib = 1; + } else if (id_insn->default_rel && + !op->data.ea->not_pc_rel && + op->data.ea->segreg != 0x6404 && + op->data.ea->segreg != 0x6505 && + !yasm_expr__contains( + op->data.ea->disp.abs, YASM_EXPR_REG)) + /* Enable default PC-rel if no regs and segreg + * is not FS or GS. + */ + insn->x86_ea->ea.pc_rel = 1; + break; + case YASM_INSN__OPERAND_IMM: + insn->x86_ea = + yasm_x86__ea_create_imm(insn->x86_ea, + op->data.val, + size_lookup[info_ops[i].size]); + break; + } + break; + case OPA_EAVEX: + if (op->type != YASM_INSN__OPERAND_REG) + yasm_internal_error(N_("invalid operand conversion")); + insn->x86_ea = + yasm_x86__ea_create_reg(insn->x86_ea, + (unsigned long)op->data.reg, &insn->rex, mode_bits); + vexreg = op->data.reg & 0xF; + 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]; + } else + 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]; + im_sign = 1; + } else + yasm_internal_error(N_("invalid operand conversion")); + break; + case OPA_Spare: + if (op->type == YASM_INSN__OPERAND_SEGREG) + spare = (unsigned char)(op->data.reg&7); + else if (op->type == YASM_INSN__OPERAND_REG) { + if (yasm_x86__set_rex_from_reg(&insn->rex, &spare, + op->data.reg, mode_bits, X86_REX_R)) + return; + } else + yasm_internal_error(N_("invalid operand conversion")); + break; + case OPA_SpareVEX: + if (op->type != YASM_INSN__OPERAND_REG) + yasm_internal_error(N_("invalid operand conversion")); + if (yasm_x86__set_rex_from_reg(&insn->rex, &spare, + op->data.reg, mode_bits, X86_REX_R)) + return; + vexreg = op->data.reg & 0xF; + break; + case OPA_Op0Add: + if (op->type == YASM_INSN__OPERAND_REG) { + unsigned char opadd; + if (yasm_x86__set_rex_from_reg(&insn->rex, &opadd, + op->data.reg, mode_bits, X86_REX_B)) + return; + insn->opcode.opcode[0] += opadd; + } else + yasm_internal_error(N_("invalid operand conversion")); + break; + case OPA_Op1Add: + if (op->type == YASM_INSN__OPERAND_REG) { + unsigned char opadd; + if (yasm_x86__set_rex_from_reg(&insn->rex, &opadd, + op->data.reg, mode_bits, X86_REX_B)) + return; + insn->opcode.opcode[1] += opadd; + } else + yasm_internal_error(N_("invalid operand conversion")); + break; + case OPA_SpareEA: + if (op->type == YASM_INSN__OPERAND_REG) { + insn->x86_ea = + yasm_x86__ea_create_reg(insn->x86_ea, + (unsigned long)op->data.reg, &insn->rex, + mode_bits); + if (!insn->x86_ea || + yasm_x86__set_rex_from_reg(&insn->rex, &spare, + op->data.reg, mode_bits, X86_REX_R)) { + if (insn->x86_ea) + yasm_xfree(insn->x86_ea); + yasm_xfree(insn); + return; + } + } else + yasm_internal_error(N_("invalid operand conversion")); + break; + case OPA_AdSizeEA: { + const uintptr_t *regp = NULL; + /* Only implement this for OPT_MemrAX and OPT_MemEAX + * for now. + */ + if (op->type != YASM_INSN__OPERAND_MEMORY || + !(regp = yasm_expr_get_reg(&op->data.ea->disp.abs, 0))) + yasm_internal_error(N_("invalid operand conversion")); + /* 64-bit mode does not allow 16-bit addresses */ + if (mode_bits == 64 && *regp == (X86_REG16 | 0)) + yasm_error_set(YASM_ERROR_TYPE, + N_("16-bit addresses not supported in 64-bit mode")); + else if (*regp == (X86_REG16 | 0)) + insn->common.addrsize = 16; + else if (*regp == (X86_REG32 | 0)) + insn->common.addrsize = 32; + else if (mode_bits == 64 && *regp == (X86_REG64 | 0)) + insn->common.addrsize = 64; + else + yasm_error_set(YASM_ERROR_TYPE, + N_("unsupported address size")); + yasm_x86__ea_destroy(op->data.ea); + break; + } + case OPA_VEX: + if (op->type != YASM_INSN__OPERAND_REG) + yasm_internal_error(N_("invalid operand conversion")); + vexreg = op->data.reg & 0xF; + break; + case OPA_VEXImmSrc: + if (op->type != YASM_INSN__OPERAND_REG) + yasm_internal_error(N_("invalid operand conversion")); + + if (!imm) { + imm = yasm_expr_create_ident( + yasm_expr_int( + yasm_intnum_create_uint((op->data.reg << 4) + & 0xF0)), + bc->line); + } else { + imm = yasm_expr_create( + YASM_EXPR_OR, + yasm_expr_expr(yasm_expr_create( + YASM_EXPR_AND, + yasm_expr_expr(imm), + yasm_expr_int(yasm_intnum_create_uint(0x0F)), + bc->line)), + yasm_expr_int( + yasm_intnum_create_uint((op->data.reg << 4) + & 0xF0)), + bc->line); + } + im_len = 8; + break; + case OPA_VEXImm: + if (op->type != YASM_INSN__OPERAND_IMM) + yasm_internal_error(N_("invalid operand conversion")); + + if (!imm) + imm = op->data.val; + else { + imm = yasm_expr_create( + YASM_EXPR_OR, + yasm_expr_expr(yasm_expr_create( + YASM_EXPR_AND, + yasm_expr_expr(op->data.val), + yasm_expr_int(yasm_intnum_create_uint(0x0F)), + bc->line)), + yasm_expr_expr(yasm_expr_create( + YASM_EXPR_AND, + yasm_expr_expr(imm), + yasm_expr_int(yasm_intnum_create_uint(0xF0)), + bc->line)), + bc->line); + } + im_len = 8; + break; + default: + yasm_internal_error(N_("unknown operand action")); + } + + if (info_ops[i].size == OPS_BITS) + insn->common.opersize = (unsigned char)mode_bits; + + switch (info_ops[i].post_action) { + case OPAP_None: + break; + case OPAP_SImm8: + /* Check operand strictness; if strict and non-8-bit, + * pre-emptively expand to full size. + * For unspecified size case, still optimize. + */ + if (!(id_insn->force_strict || op->strict) + || op->size == 0) + insn->postop = X86_POSTOP_SIGNEXT_IMM8; + else if (op->size != 8) { + insn->opcode.opcode[0] = + insn->opcode.opcode[insn->opcode.len]; + insn->opcode.len = 1; + } + break; + case OPAP_ShortMov: + do_postop = OPAP_ShortMov; + break; + case OPAP_A16: + insn->postop = X86_POSTOP_ADDRESS16; + break; + case OPAP_SImm32Avail: + do_postop = OPAP_SImm32Avail; + break; + default: + yasm_internal_error( + N_("unknown operand postponed action")); + } + } + } + + if (insn->x86_ea) { + yasm_x86__ea_init(insn->x86_ea, spare, prev_bc); + for (i=0; i<id_insn->insn.num_segregs; i++) + yasm_ea_set_segreg(&insn->x86_ea->ea, id_insn->insn.segregs[i]); + } else if (id_insn->insn.num_segregs > 0 && insn->special_prefix == 0) { + if (id_insn->insn.num_segregs > 1) + yasm_warn_set(YASM_WARN_GENERAL, + N_("multiple segment overrides, using leftmost")); + insn->special_prefix = (unsigned char) + (id_insn->insn.segregs[id_insn->insn.num_segregs-1]>>8); + } else if (id_insn->insn.num_segregs > 0) + yasm_internal_error(N_("unhandled segment prefix")); + + if (imm) { + insn->imm = yasm_xmalloc(sizeof(yasm_value)); + if (yasm_value_finalize_expr(insn->imm, imm, prev_bc, im_len)) + yasm_error_set(YASM_ERROR_TOO_COMPLEX, + N_("immediate expression too complex")); + insn->imm->sign = im_sign; + } else + insn->imm = NULL; + + yasm_x86__bc_apply_prefixes((x86_common *)insn, &insn->rex, + insn->def_opersize_64, + id_insn->insn.num_prefixes, + id_insn->insn.prefixes); + + if (insn->postop == X86_POSTOP_ADDRESS16 && insn->common.addrsize) { + yasm_warn_set(YASM_WARN_GENERAL, N_("address size override ignored")); + insn->common.addrsize = 0; + } + + /* Handle non-span-dependent post-ops here */ + switch (do_postop) { + case OPAP_ShortMov: + /* Long (modrm+sib) mov instructions in amd64 can be optimized into + * short mov instructions if a 32-bit address override is applied in + * 64-bit mode to an EA of just an offset (no registers) and the + * target register is al/ax/eax/rax. + * + * We don't want to do this if we're in default rel mode. + */ + if (!id_insn->default_rel && + insn->common.mode_bits == 64 && + insn->common.addrsize == 32 && + (!insn->x86_ea->ea.disp.abs || + !yasm_expr__contains(insn->x86_ea->ea.disp.abs, + YASM_EXPR_REG))) { + yasm_x86__ea_set_disponly(insn->x86_ea); + /* Make the short form permanent. */ + insn->opcode.opcode[0] = insn->opcode.opcode[1]; + } + insn->opcode.opcode[1] = 0; /* avoid possible confusion */ + break; + case OPAP_SImm32Avail: + /* Used for 64-bit mov immediate, which can take a sign-extended + * imm32 as well as imm64 values. The imm32 form is put in the + * second byte of the opcode and its ModRM byte is put in the third + * byte of the opcode. + */ + if (!insn->imm->abs || + (yasm_expr_get_intnum(&insn->imm->abs, 0) && + yasm_intnum_check_size( + yasm_expr_get_intnum(&insn->imm->abs, 0), 32, 0, 1))) { + /* Throwaway REX byte */ + unsigned char rex_temp = 0; + + /* Build ModRM EA - CAUTION: this depends on + * opcode 0 being a mov instruction! + */ + insn->x86_ea = yasm_x86__ea_create_reg(insn->x86_ea, + (unsigned long)insn->opcode.opcode[0]-0xB8, &rex_temp, 64); + + /* Make the imm32s form permanent. */ + insn->opcode.opcode[0] = insn->opcode.opcode[1]; + insn->imm->size = 32; + } + insn->opcode.opcode[1] = 0; /* avoid possible confusion */ + break; + default: + break; + } + + /* Convert to VEX/XOP prefixes if requested. + * To save space in the insn structure, the VEX/XOP prefix is written into + * special_prefix and the first 2 bytes of the instruction are set to + * the second two VEX/XOP bytes. During calc_len() it may be shortened to + * one VEX byte (this can only be done after knowledge of REX value); this + * further optimization is not possible for XOP. + */ + if (vexdata) { + int xop = ((vexdata & 0xF0) == 0x80); + unsigned char vex1 = 0xE0; /* R=X=B=1, mmmmm=0 */ + unsigned char vex2; + + if (xop) { + /* Look at the first bytes of the opcode for the XOP mmmmm field. + * Leave R=X=B=1 for now. + */ + if (insn->opcode.opcode[0] != 0x08 && + insn->opcode.opcode[0] != 0x09 && + insn->opcode.opcode[0] != 0x0A) + yasm_internal_error(N_("first opcode byte of XOP must be 0x08, 0x09, or 0x0A")); + vex1 |= insn->opcode.opcode[0]; + /* Move opcode byte back one byte to make room for XOP prefix. */ + insn->opcode.opcode[2] = insn->opcode.opcode[1]; + } else { + /* Look at the first bytes of the opcode to see what leading bytes + * to encode in the VEX mmmmm field. Leave R=X=B=1 for now. + */ + if (insn->opcode.opcode[0] != 0x0F) + yasm_internal_error(N_("first opcode byte of VEX must be 0x0F")); + + if (insn->opcode.opcode[1] == 0x38) + vex1 |= 0x02; /* implied 0x0F 0x38 */ + else if (insn->opcode.opcode[1] == 0x3A) + vex1 |= 0x03; /* implied 0x0F 0x3A */ + else { + /* Originally a 0F-only opcode; move opcode byte back one + * position to make room for VEX prefix. + */ + insn->opcode.opcode[2] = insn->opcode.opcode[1]; + vex1 |= 0x01; /* implied 0x0F */ + } + } + + /* Check for update of special prefix by modifiers */ + if (insn->special_prefix != 0) { + vexdata &= ~0x03; + switch (insn->special_prefix) { + case 0x66: + vexdata |= 0x01; + break; + case 0xF3: + vexdata |= 0x02; + break; + case 0xF2: + vexdata |= 0x03; + break; + default: + yasm_internal_error(N_("unrecognized special prefix")); + } + } + + /* 2nd VEX byte is WvvvvLpp. + * W, L, pp come from vexdata + * vvvv comes from 1s complement of vexreg + */ + vex2 = (((vexdata & 0x8) << 4) | /* W */ + ((15 - (vexreg & 0xF)) << 3) | /* vvvv */ + (vexdata & 0x7)); /* Lpp */ + + /* Save to special_prefix and opcode */ + insn->special_prefix = xop ? 0x8F : 0xC4; /* VEX/XOP prefix */ + insn->opcode.opcode[0] = vex1; + insn->opcode.opcode[1] = vex2; + insn->opcode.len = 3; /* two prefix bytes and 1 opcode byte */ + } + + x86_id_insn_clear_operands(id_insn); + + /* Transform the bytecode */ + yasm_x86__bc_transform_insn(bc, insn); +} + +/* Static parse data structure for instructions */ +typedef struct insnprefix_parse_data { + const char *name; + + /* instruction parse group - NULL if prefix */ + /*@null@*/ const x86_insn_info *group; + + /* For instruction, number of elements in group. + * For prefix, prefix type shifted right by 8. + */ + unsigned int num_info:8; + + /* For instruction, GAS suffix flags. + * For prefix, prefix value. + */ + unsigned int flags:8; + + /* Instruction modifier data. */ + unsigned int mod_data0:8; + unsigned int mod_data1:8; + unsigned int mod_data2:8; + + /* Tests against BITS==64 and AVX */ + unsigned int misc_flags:6; + + /* CPU flags */ + unsigned int cpu0:6; + unsigned int cpu1:6; + unsigned int cpu2:6; +} insnprefix_parse_data; + +/* Pull in all parse data */ +#include "x86insn_nasm.c" +#include "x86insn_gas.c" + +static const char * +cpu_find_reverse(unsigned int cpu0, unsigned int cpu1, unsigned int cpu2) +{ + static char cpuname[200]; + wordptr cpu = BitVector_Create(128, TRUE); + + if (cpu0 != CPU_Any) + BitVector_Bit_On(cpu, cpu0); + if (cpu1 != CPU_Any) + BitVector_Bit_On(cpu, cpu1); + if (cpu2 != CPU_Any) + BitVector_Bit_On(cpu, cpu2); + + cpuname[0] = '\0'; + + if (BitVector_bit_test(cpu, CPU_Prot)) + strcat(cpuname, " Protected"); + if (BitVector_bit_test(cpu, CPU_Undoc)) + strcat(cpuname, " Undocumented"); + if (BitVector_bit_test(cpu, CPU_Obs)) + strcat(cpuname, " Obsolete"); + if (BitVector_bit_test(cpu, CPU_Priv)) + strcat(cpuname, " Privileged"); + + if (BitVector_bit_test(cpu, CPU_FPU)) + strcat(cpuname, " FPU"); + if (BitVector_bit_test(cpu, CPU_MMX)) + strcat(cpuname, " MMX"); + if (BitVector_bit_test(cpu, CPU_SSE)) + strcat(cpuname, " SSE"); + if (BitVector_bit_test(cpu, CPU_SSE2)) + strcat(cpuname, " SSE2"); + if (BitVector_bit_test(cpu, CPU_SSE3)) + strcat(cpuname, " SSE3"); + if (BitVector_bit_test(cpu, CPU_3DNow)) + strcat(cpuname, " 3DNow"); + if (BitVector_bit_test(cpu, CPU_Cyrix)) + strcat(cpuname, " Cyrix"); + if (BitVector_bit_test(cpu, CPU_AMD)) + strcat(cpuname, " AMD"); + if (BitVector_bit_test(cpu, CPU_SMM)) + strcat(cpuname, " SMM"); + if (BitVector_bit_test(cpu, CPU_SVM)) + strcat(cpuname, " SVM"); + if (BitVector_bit_test(cpu, CPU_PadLock)) + strcat(cpuname, " PadLock"); + if (BitVector_bit_test(cpu, CPU_EM64T)) + strcat(cpuname, " EM64T"); + if (BitVector_bit_test(cpu, CPU_SSSE3)) + strcat(cpuname, " SSSE3"); + if (BitVector_bit_test(cpu, CPU_SSE41)) + strcat(cpuname, " SSE4.1"); + if (BitVector_bit_test(cpu, CPU_SSE42)) + strcat(cpuname, " SSE4.2"); + + if (BitVector_bit_test(cpu, CPU_186)) + strcat(cpuname, " 186"); + if (BitVector_bit_test(cpu, CPU_286)) + strcat(cpuname, " 286"); + if (BitVector_bit_test(cpu, CPU_386)) + strcat(cpuname, " 386"); + if (BitVector_bit_test(cpu, CPU_486)) + strcat(cpuname, " 486"); + if (BitVector_bit_test(cpu, CPU_586)) + strcat(cpuname, " 586"); + if (BitVector_bit_test(cpu, CPU_686)) + strcat(cpuname, " 686"); + if (BitVector_bit_test(cpu, CPU_P3)) + strcat(cpuname, " P3"); + if (BitVector_bit_test(cpu, CPU_P4)) + strcat(cpuname, " P4"); + if (BitVector_bit_test(cpu, CPU_IA64)) + strcat(cpuname, " IA64"); + if (BitVector_bit_test(cpu, CPU_K6)) + strcat(cpuname, " K6"); + if (BitVector_bit_test(cpu, CPU_Athlon)) + strcat(cpuname, " Athlon"); + if (BitVector_bit_test(cpu, CPU_Hammer)) + strcat(cpuname, " Hammer"); + + BitVector_Destroy(cpu); + return cpuname; +} + +yasm_arch_insnprefix +yasm_x86__parse_check_insnprefix(yasm_arch *arch, const char *id, + size_t id_len, unsigned long line, + yasm_bytecode **bc, uintptr_t *prefix) +{ + yasm_arch_x86 *arch_x86 = (yasm_arch_x86 *)arch; + /*@null@*/ const insnprefix_parse_data *pdata; + size_t i; + static char lcaseid[17]; + + *bc = (yasm_bytecode *)NULL; + *prefix = 0; + + if (id_len > 16) + return YASM_ARCH_NOTINSNPREFIX; + for (i=0; i<id_len; i++) + lcaseid[i] = tolower(id[i]); + lcaseid[id_len] = '\0'; + + switch (PARSER(arch_x86)) { + case X86_PARSER_NASM: + pdata = insnprefix_nasm_find(lcaseid, id_len); + break; + case X86_PARSER_TASM: + pdata = insnprefix_nasm_find(lcaseid, id_len); + break; + case X86_PARSER_GAS: + pdata = insnprefix_gas_find(lcaseid, id_len); + break; + default: + pdata = NULL; + } + if (!pdata) + return YASM_ARCH_NOTINSNPREFIX; + + if (pdata->group) { + x86_id_insn *id_insn; + wordptr cpu_enabled = arch_x86->cpu_enables[arch_x86->active_cpu]; + unsigned int cpu0, cpu1, cpu2; + + if (arch_x86->mode_bits != 64 && (pdata->misc_flags & ONLY_64)) { + yasm_warn_set(YASM_WARN_GENERAL, + N_("`%s' is an instruction in 64-bit mode"), id); + return YASM_ARCH_NOTINSNPREFIX; + } + if (arch_x86->mode_bits == 64 && (pdata->misc_flags & NOT_64)) { + yasm_error_set(YASM_ERROR_GENERAL, + N_("`%s' invalid in 64-bit mode"), id); + id_insn = yasm_xmalloc(sizeof(x86_id_insn)); + yasm_insn_initialize(&id_insn->insn); + id_insn->group = not64_insn; + id_insn->cpu_enabled = cpu_enabled; + id_insn->mod_data[0] = 0; + id_insn->mod_data[1] = 0; + id_insn->mod_data[2] = 0; + id_insn->num_info = NELEMS(not64_insn); + id_insn->mode_bits = arch_x86->mode_bits; + id_insn->suffix = 0; + id_insn->misc_flags = 0; + id_insn->parser = PARSER(arch_x86); + + id_insn->force_strict = arch_x86->force_strict != 0; + id_insn->default_rel = arch_x86->default_rel != 0; + *bc = yasm_bc_create_common(&x86_id_insn_callback, id_insn, line); + return YASM_ARCH_INSN; + } + + cpu0 = pdata->cpu0; + cpu1 = pdata->cpu1; + cpu2 = pdata->cpu2; + + if (!BitVector_bit_test(cpu_enabled, cpu0) || + !BitVector_bit_test(cpu_enabled, cpu1) || + !BitVector_bit_test(cpu_enabled, cpu2)) { + yasm_warn_set(YASM_WARN_GENERAL, + N_("`%s' is an instruction in CPU%s"), id, + cpu_find_reverse(cpu0, cpu1, cpu2)); + return YASM_ARCH_NOTINSNPREFIX; + } + + id_insn = yasm_xmalloc(sizeof(x86_id_insn)); + yasm_insn_initialize(&id_insn->insn); + id_insn->group = pdata->group; + id_insn->cpu_enabled = cpu_enabled; + id_insn->mod_data[0] = pdata->mod_data0; + id_insn->mod_data[1] = pdata->mod_data1; + id_insn->mod_data[2] = pdata->mod_data2; + id_insn->num_info = pdata->num_info; + id_insn->mode_bits = arch_x86->mode_bits; + id_insn->suffix = pdata->flags; + id_insn->misc_flags = pdata->misc_flags; + id_insn->parser = PARSER(arch_x86); + id_insn->force_strict = arch_x86->force_strict != 0; + id_insn->default_rel = arch_x86->default_rel != 0; + *bc = yasm_bc_create_common(&x86_id_insn_callback, id_insn, line); + return YASM_ARCH_INSN; + } else { + unsigned long type = pdata->num_info<<8; + unsigned long value = pdata->flags; + + if (arch_x86->mode_bits == 64 && type == X86_OPERSIZE && value == 32) { + yasm_error_set(YASM_ERROR_GENERAL, + N_("Cannot override data size to 32 bits in 64-bit mode")); + return YASM_ARCH_NOTINSNPREFIX; + } + + if (arch_x86->mode_bits == 64 && type == X86_ADDRSIZE && value == 16) { + yasm_error_set(YASM_ERROR_GENERAL, + N_("Cannot override address size to 16 bits in 64-bit mode")); + return YASM_ARCH_NOTINSNPREFIX; + } + + if (arch_x86->mode_bits != 64 && (pdata->misc_flags & ONLY_64)) { + yasm_warn_set(YASM_WARN_GENERAL, + N_("`%s' is a prefix in 64-bit mode"), id); + return YASM_ARCH_NOTINSNPREFIX; + } + *prefix = type|value; + return YASM_ARCH_PREFIX; + } +} + +static void +x86_id_insn_destroy(void *contents) +{ + x86_id_insn *id_insn = (x86_id_insn *)contents; + yasm_insn_delete(&id_insn->insn, yasm_x86__ea_destroy); + yasm_xfree(contents); +} + +static void +x86_id_insn_print(const void *contents, FILE *f, int indent_level) +{ + const x86_id_insn *id_insn = (const x86_id_insn *)contents; + yasm_insn_print(&id_insn->insn, f, indent_level); + /*TODO*/ +} + +/*@only@*/ yasm_bytecode * +yasm_x86__create_empty_insn(yasm_arch *arch, unsigned long line) +{ + yasm_arch_x86 *arch_x86 = (yasm_arch_x86 *)arch; + x86_id_insn *id_insn = yasm_xmalloc(sizeof(x86_id_insn)); + + yasm_insn_initialize(&id_insn->insn); + id_insn->group = empty_insn; + id_insn->cpu_enabled = arch_x86->cpu_enables[arch_x86->active_cpu]; + id_insn->mod_data[0] = 0; + id_insn->mod_data[1] = 0; + id_insn->mod_data[2] = 0; + id_insn->num_info = NELEMS(empty_insn); + id_insn->mode_bits = arch_x86->mode_bits; + id_insn->suffix = (PARSER(arch_x86) == X86_PARSER_GAS) ? SUF_Z : 0; + id_insn->misc_flags = 0; + id_insn->parser = PARSER(arch_x86); + id_insn->force_strict = arch_x86->force_strict != 0; + id_insn->default_rel = arch_x86->default_rel != 0; + + return yasm_bc_create_common(&x86_id_insn_callback, id_insn, line); +} + |