aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/tools/yasm/modules/arch
diff options
context:
space:
mode:
authorsomov <somov@yandex-team.ru>2022-02-10 16:45:47 +0300
committerDaniil Cherednik <dcherednik@yandex-team.ru>2022-02-10 16:45:47 +0300
commita5950576e397b1909261050b8c7da16db58f10b1 (patch)
tree7ba7677f6a4c3e19e2cefab34d16df2c8963b4d4 /contrib/tools/yasm/modules/arch
parent81eddc8c0b55990194e112b02d127b87d54164a9 (diff)
downloadydb-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.c424
-rw-r--r--contrib/tools/yasm/modules/arch/lc3b/lc3barch.h140
-rw-r--r--contrib/tools/yasm/modules/arch/lc3b/lc3bbc.c498
-rw-r--r--contrib/tools/yasm/modules/arch/x86/x86arch.c1266
-rw-r--r--contrib/tools/yasm/modules/arch/x86/x86arch.h672
-rw-r--r--contrib/tools/yasm/modules/arch/x86/x86bc.c2124
-rw-r--r--contrib/tools/yasm/modules/arch/x86/x86expr.c2122
-rw-r--r--contrib/tools/yasm/modules/arch/x86/x86id.c3902
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], &regnum, 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], &regnum, 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],
- &regnum, 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], &regnum, 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,
- &reg3264_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,
- &reg16mult, 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], &regnum, 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], &regnum, 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],
+ &regnum, 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], &regnum, 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,
+ &reg3264_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,
+ &reg16mult, 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);
+}
+