diff options
author | Devtools Arcadia <arcadia-devtools@yandex-team.ru> | 2022-02-07 18:08:42 +0300 |
---|---|---|
committer | Devtools Arcadia <arcadia-devtools@mous.vla.yp-c.yandex.net> | 2022-02-07 18:08:42 +0300 |
commit | 1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch) | |
tree | e26c9fed0de5d9873cce7e00bc214573dc2195b7 /contrib/tools/yasm | |
download | ydb-1110808a9d39d4b808aef724c861a2e1a38d2a69.tar.gz |
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'contrib/tools/yasm')
148 files changed, 79730 insertions, 0 deletions
diff --git a/contrib/tools/yasm/bin/ya.make b/contrib/tools/yasm/bin/ya.make new file mode 100644 index 0000000000..96ca75c53e --- /dev/null +++ b/contrib/tools/yasm/bin/ya.make @@ -0,0 +1,120 @@ +OWNER( + somov + g:contrib + g:ymake +) + +PROGRAM(yasm) + +IF (MUSL) + PEERDIR(contrib/libs/musl_extra) + PEERDIR(contrib/libs/jemalloc) + DISABLE(USE_ASMLIB) + NO_RUNTIME() + ENABLE(MUSL_LITE) +ELSE() + NO_PLATFORM() +ENDIF() + +NO_CLANG_COVERAGE() +NO_COMPILER_WARNINGS() +NO_UTIL() + +ALLOCATOR(FAKE) + +ADDINCL( + contrib/tools/yasm + contrib/tools/yasm/frontends/yasm + contrib/tools/yasm/modules +) + +CFLAGS( + -DHAVE_CONFIG_H + -DYASM_LIB_SOURCE +) + +SRCDIR(contrib/tools/yasm) + +SRCS( + frontends/yasm/yasm-options.c + frontends/yasm/yasm.c + libyasm/assocdat.c + libyasm/bc-align.c + libyasm/bc-data.c + libyasm/bc-incbin.c + libyasm/bc-org.c + libyasm/bc-reserve.c + libyasm/bitvect.c + libyasm/bytecode.c + libyasm/cmake-module.c + libyasm/errwarn.c + libyasm/expr.c + libyasm/file.c + libyasm/floatnum.c + libyasm/hamt.c + libyasm/insn.c + libyasm/intnum.c + libyasm/inttree.c + libyasm/linemap.c + libyasm/md5.c + libyasm/mergesort.c + libyasm/phash.c + libyasm/replace_path.c + libyasm/section.c + libyasm/strcasecmp.c + libyasm/strsep.c + libyasm/symrec.c + libyasm/valparam.c + libyasm/value.c + libyasm/xmalloc.c + libyasm/xstrdup.c + modules/arch/lc3b/lc3barch.c + modules/arch/lc3b/lc3bbc.c + modules/arch/x86/x86arch.c + modules/arch/x86/x86bc.c + modules/arch/x86/x86expr.c + modules/arch/x86/x86id.c + modules/dbgfmts/codeview/cv-dbgfmt.c + modules/dbgfmts/codeview/cv-symline.c + modules/dbgfmts/codeview/cv-type.c + modules/dbgfmts/dwarf2/dwarf2-aranges.c + modules/dbgfmts/dwarf2/dwarf2-dbgfmt.c + modules/dbgfmts/dwarf2/dwarf2-info.c + modules/dbgfmts/dwarf2/dwarf2-line.c + modules/dbgfmts/null/null-dbgfmt.c + modules/dbgfmts/stabs/stabs-dbgfmt.c + modules/gas-token.c + modules/init_plugin.c + modules/lc3bid.c + modules/listfmts/nasm/nasm-listfmt.c + modules/nasm-token.c + modules/objfmts/bin/bin-objfmt.c + modules/objfmts/coff/coff-objfmt.c + modules/objfmts/coff/win64-except.c + modules/objfmts/dbg/dbg-objfmt.c + modules/objfmts/elf/elf-objfmt.c + modules/objfmts/elf/elf-x86-amd64.c + modules/objfmts/elf/elf-x86-x32.c + modules/objfmts/elf/elf-x86-x86.c + modules/objfmts/elf/elf.c + modules/objfmts/macho/macho-objfmt.c + modules/objfmts/rdf/rdf-objfmt.c + modules/objfmts/xdf/xdf-objfmt.c + modules/parsers/gas/gas-parse-intel.c + modules/parsers/gas/gas-parse.c + modules/parsers/gas/gas-parser.c + modules/parsers/nasm/nasm-parse.c + modules/parsers/nasm/nasm-parser.c + modules/preprocs/cpp/cpp-preproc.c + modules/preprocs/gas/gas-eval.c + modules/preprocs/gas/gas-preproc.c + modules/preprocs/nasm/nasm-eval.c + modules/preprocs/nasm/nasm-pp.c + modules/preprocs/nasm/nasm-preproc.c + modules/preprocs/nasm/nasmlib.c + modules/preprocs/raw/raw-preproc.c + modules/x86cpu.c + modules/x86regtmod.c +) + +END() diff --git a/contrib/tools/yasm/config-osx-linux.h b/contrib/tools/yasm/config-osx-linux.h new file mode 100644 index 0000000000..7096e2a4c9 --- /dev/null +++ b/contrib/tools/yasm/config-osx-linux.h @@ -0,0 +1,48 @@ +/* config.h. Generated by cmake from config.h.cmake */ + +#define CMAKE_BUILD 1 + +/* Define if shared libs are being built */ +/* #undef BUILD_SHARED_LIBS */ + +/* Define if messsage translations are enabled */ +/* #undef ENABLE_NLS */ + +/* */ +#undef HAVE_GETTEXT + +/* Define to 1 if you have the <libgen.h> header file. */ +#define HAVE_LIBGEN_H 1 + +/* Define to 1 if you have the <unistd.h> header file. */ +#define HAVE_UNISTD_H 1 + +/* Define to 1 if you have the <direct.h> header file. */ +/* #undef HAVE_DIRECT_H */ + +/* Define to 1 if you have the `getcwd' function. */ +#define HAVE_GETCWD 1 + +/* Define to 1 if you have the `toascii' function. */ +#define HAVE_TOASCII 1 + +/* Name of package */ +#define PACKAGE "yasm" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "bug-yasm@tortall.net" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "yasm" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "yasm 1.3.0" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "1.3.0" + +#define VERSION PACKAGE_VERSION + +/* Command name to run C preprocessor */ +#define CPP_PROG "/usr/bin/cpp" + diff --git a/contrib/tools/yasm/config-win.h b/contrib/tools/yasm/config-win.h new file mode 100644 index 0000000000..b924e3ebfd --- /dev/null +++ b/contrib/tools/yasm/config-win.h @@ -0,0 +1,48 @@ +/* config.h. Generated by cmake from config.h.cmake */ + +#define CMAKE_BUILD 1 + +/* Define if shared libs are being built */ +/* #undef BUILD_SHARED_LIBS */ + +/* Define if messsage translations are enabled */ +/* #undef ENABLE_NLS */ + +/* */ +#undef HAVE_GETTEXT + +/* Define to 1 if you have the <libgen.h> header file. */ +/* #undef HAVE_LIBGEN_H */ + +/* Define to 1 if you have the <unistd.h> header file. */ +/* #undef HAVE_UNISTD_H */ + +/* Define to 1 if you have the <direct.h> header file. */ +#define HAVE_DIRECT_H 1 + +/* Define to 1 if you have the `getcwd' function. */ +#define HAVE_GETCWD 1 + +/* Define to 1 if you have the `toascii' function. */ +/* #undef HAVE_TOASCII */ + +/* Name of package */ +#define PACKAGE "yasm" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "bug-yasm@tortall.net" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "yasm" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "yasm 1.3.0" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "1.3.0" + +#define VERSION PACKAGE_VERSION + +/* Command name to run C preprocessor */ +#define CPP_PROG "CPP_PROG-NOTFOUND" + diff --git a/contrib/tools/yasm/config.h b/contrib/tools/yasm/config.h new file mode 100644 index 0000000000..862e891cbd --- /dev/null +++ b/contrib/tools/yasm/config.h @@ -0,0 +1,7 @@ +#if defined(__APPLE__) && defined(__x86_64__) +# include "config-osx-linux.h" +#elif defined(_MSC_VER) && defined(_M_X64) +# include "config-win.h" +#else +# include "config-osx-linux.h" +#endif diff --git a/contrib/tools/yasm/frontends/tasm/license.c b/contrib/tools/yasm/frontends/tasm/license.c new file mode 100644 index 0000000000..35c5a04137 --- /dev/null +++ b/contrib/tools/yasm/frontends/tasm/license.c @@ -0,0 +1,65 @@ +/* This file auto-generated from COPYING by genstring.py - don't edit it */ + +static const char* license_msg[] = { + "Yasm is Copyright (c) 2001-2014 Peter Johnson and other Yasm developers.", + "", + "Yasm developers and/or contributors include:", + "Peter Johnson", + "Michael Urman", + "Brian Gladman (Visual Studio build files, other fixes)", + "Stanislav Karchebny (options parser)", + "Mathieu Monnier (SSE4 instruction patches, NASM preprocessor additions)", + "Anonymous \"NASM64\" developer (NASM preprocessor fixes)", + "Stephen Polkowski (x86 instruction patches)", + "Henryk Richter (Mach-O object format)", + "Ben Skeggs (patches, bug reports)", + "Alexei Svitkine (GAS preprocessor)", + "Samuel Thibault (TASM parser and frontend)", + "", + "-----------------------------------", + "Yasm licensing overview and summary", + "-----------------------------------", + "", + "Note: This document does not provide legal advice nor is it the actual", + "license of any part of Yasm. See the individual licenses for complete", + "details. Consult a lawyer for legal advice.", + "", + "The primary license of Yasm is the 2-clause BSD license. Please use this", + "license if you plan on submitting code to the project.", + "", + "Yasm has absolutely no warranty; not even for merchantibility or fitness", + "for a particular purpose.", + "", + "-------", + "Libyasm", + "-------", + "Libyasm is 2-clause or 3-clause BSD licensed, with the exception of", + "bitvect, which is triple-licensed under the Artistic license, GPL, and", + "LGPL. Libyasm is thus GPL and LGPL compatible. In addition, this also", + "means that libyasm is free for binary-only distribution as long as the", + "terms of the 3-clause BSD license and Artistic license (as it applies to", + "bitvect) are fulfilled.", + "", + "-------", + "Modules", + "-------", + "The modules are 2-clause or 3-clause BSD licensed.", + "", + "---------", + "Frontends", + "---------", + "The frontends are 2-clause BSD licensed.", + "", + "-------------", + "License Texts", + "-------------", + "The full text of all licenses are provided in separate files in the source", + "distribution. Each source file may include the entire license (in the case", + "of the BSD and Artistic licenses), or may reference the GPL or LGPL license", + "file.", + "", + "BSD.txt - 2-clause and 3-clause BSD licenses", + "Artistic.txt - Artistic license", + "GNU_GPL-2.0 - GNU General Public License", + "GNU_LGPL-2.0 - GNU Library General Public License", +}; diff --git a/contrib/tools/yasm/frontends/tasm/tasm-options.c b/contrib/tools/yasm/frontends/tasm/tasm-options.c new file mode 100644 index 0000000000..57c3bdfd15 --- /dev/null +++ b/contrib/tools/yasm/frontends/tasm/tasm-options.c @@ -0,0 +1,127 @@ +/* + * Generic Options Support Header File + * + * Copyright (c) 2001 Stanislav Karchebny <berk@madfire.net> + * + * 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. + * 3. Neither the name of the author nor the names of other contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 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 <ctype.h> + +#include "tasm-options.h" + + +#ifdef __DEBUG__ +#define DEBUG(x) fprintf ## x ; +#else +#define DEBUG(x) +#endif + + +/* Options Parser */ +int +parse_cmdline(int argc, char **argv, opt_option *options, size_t nopts, + void (*print_error) (const char *fmt, ...)) +{ + int errors = 0, warnings = 0; + size_t i; + int got_it; + + DEBUG((stderr, "parse_cmdline: entered\n")); + + fail: + while (--argc) { + argv++; + + if (argv[0][0] == '/' && argv[0][1]) { /* opt */ + got_it = 0; + for (i = 0; i < nopts; i++) { + char *cmd = &argv[0][1]; + size_t len = strlen(options[i].opt); + if (yasm__strncasecmp(cmd, options[i].opt, len) == 0) { + char *param; + + param = &argv[0][1+len]; + if (options[i].takes_param) { + if (param[0] == '\0') { + print_error( + _("option `-%c' needs an argument!"), + options[i].opt); + errors++; + goto fail; + } else { + argc--; + argv++; + } + } else + param = NULL; + + if (!options[i].handler(cmd, param, options[i].extra)) + got_it = 1; + break; + } + } + if (!got_it) { + print_error(_("warning: unrecognized option `%s'"), + argv[0]); + warnings++; + } + } else { /* not an option, then it should be a file or something */ + + if (not_an_option_handler(argv[0])) + errors++; + } + } + + DEBUG((stderr, "parse_cmdline: finished\n")); + return errors; +} + +void +help_msg(const char *msg, const char *tail, opt_option *options, size_t nopts) +{ + char optbuf[100]; + size_t i; + + printf("%s", gettext(msg)); + + for (i = 0; i < nopts; i++) { + optbuf[0] = 0; + + if (options[i].takes_param) { + if (options[i].opt) + sprintf(optbuf, "/%s <%s>", options[i].opt, + options[i].param_desc ? options[i]. + param_desc : _("param")); + } else { + if (options[i].opt) + sprintf(optbuf, "/%s", options[i].opt); + } + + printf(" %-22s %s\n", optbuf, gettext(options[i].description)); + } + + printf("%s", gettext(tail)); +} diff --git a/contrib/tools/yasm/frontends/tasm/tasm-options.h b/contrib/tools/yasm/frontends/tasm/tasm-options.h new file mode 100644 index 0000000000..082409fc24 --- /dev/null +++ b/contrib/tools/yasm/frontends/tasm/tasm-options.h @@ -0,0 +1,69 @@ +/* + * Generic Options Support Header File + * + * Copyright (c) 2001 Stanislav Karchebny <berk@madfire.net> + * + * 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 TASM_OPTIONS_H +#define TASM_OPTIONS_H + +/* an option structure + * operate on either -sopt, --lopt, -sopt <val> or --lopt=<val> + */ +typedef struct opt_option_s +{ + /* option */ + const char *opt; + + /* !=0 if option requires parameter, 0 if not */ + int takes_param; + + int (*handler) (char *cmd, /*@null@*/ char *param, int extra); + int extra; /* extra value for handler */ + + /* description to use in help_msg() */ + /*@observer@*/ const char *description; + + /* optional description for the param taken (NULL if not present) */ + /* (short - will be printed after option sopt/lopt) */ + /*@observer@*/ /*@null@*/ const char *param_desc; +} opt_option; + +/* handle everything that is not an option */ +int not_an_option_handler(char *param); + +/* parse command line calling handlers when appropriate + * argc, argv - pass directly from main(argc,argv) + * options - array of options + * nopts - options count + */ +int parse_cmdline(int argc, char **argv, opt_option *options, size_t nopts, + void (*print_error) (const char *fmt, ...)); + +/* display help message msg followed by list of options in options and followed + * by tail + */ +void help_msg(const char *msg, const char *tail, opt_option *options, + size_t nopts); + +#endif diff --git a/contrib/tools/yasm/frontends/tasm/tasm.c b/contrib/tools/yasm/frontends/tasm/tasm.c new file mode 100644 index 0000000000..58954b6457 --- /dev/null +++ b/contrib/tools/yasm/frontends/tasm/tasm.c @@ -0,0 +1,1009 @@ +/* + * Program entry point, command line parsing + * + * Copyright (C) 2001-2008 Peter Johnson + * Copyright (C) 2007-2008 Samuel Thibault + * + * 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 <ctype.h> +#include <libyasm/compat-queue.h> +#include <libyasm/bitvect.h> +#include <libyasm.h> + +#ifdef HAVE_LIBGEN_H +#include <libgen.h> +#endif + +#include "tasm-options.h" + +#if defined(CMAKE_BUILD) && defined(BUILD_SHARED_LIBS) +#include "yasm-plugin.h" +#endif + +#include "license.c" + +#define DEFAULT_OBJFMT_MODULE "bin" + +#if defined(CMAKE_BUILD) && !defined(BUILD_SHARED_LIBS) +void yasm_init_plugin(void); +#endif + +/*@null@*/ /*@only@*/ static char *obj_filename = NULL, *in_filename = NULL; +/*@null@*/ /*@only@*/ static char *list_filename = NULL, *xref_filename = NULL; +/*@null@*/ /*@only@*/ static char *machine_name = NULL; +static int special_options = 0; +static int segment_ordering = 0; +static int cross_reference = 0; +static int floating_point = 0; +static int listing = 0; +static int expanded_listing = 0; +static int case_sensitivity = 0; +static int valid_length = -1; +/*@null@*/ /*@dependent@*/ static yasm_arch *cur_arch = NULL; +/*@null@*/ /*@dependent@*/ static const yasm_arch_module * + cur_arch_module = NULL; +/*@null@*/ /*@dependent@*/ static const yasm_parser_module * + cur_parser_module = NULL; +/*@null@*/ /*@dependent@*/ static yasm_preproc *cur_preproc = NULL; +/*@null@*/ /*@dependent@*/ static const yasm_preproc_module * + cur_preproc_module = NULL; +/*@null@*/ static char *objfmt_keyword = NULL; +/*@null@*/ /*@dependent@*/ static const yasm_objfmt_module * + cur_objfmt_module = NULL; +/*@null@*/ /*@dependent@*/ static const yasm_dbgfmt_module * + cur_dbgfmt_module = NULL; +/*@null@*/ /*@dependent@*/ static yasm_listfmt *cur_listfmt = NULL; +/*@null@*/ /*@dependent@*/ static const yasm_listfmt_module * + cur_listfmt_module = NULL; +static int warning_error = 0; /* warnings being treated as errors */ +static FILE *errfile; +/*@null@*/ /*@only@*/ static char *error_filename = NULL; + +/*@null@*/ /*@dependent@*/ static FILE *open_file(const char *filename, + const char *mode); +static void check_errors(/*@only@*/ yasm_errwarns *errwarns, + /*@only@*/ yasm_object *object, + /*@only@*/ yasm_linemap *linemap); +static void cleanup(/*@null@*/ /*@only@*/ yasm_object *object); + +/* Forward declarations: cmd line parser handlers */ +static int opt_special_handler(char *cmd, /*@null@*/ char *param, int extra); +static int opt_segment_ordering_handler(char *cmd, /*@null@*/ char *param, int extra); +static int opt_cross_reference_handler(char *cmd, /*@null@*/ char *param, int extra); +static int opt_floating_point_handler(char *cmd, /*@null@*/ char *param, int extra); +static int opt_ignore(char *cmd, /*@null@*/ char *param, int extra); +static int opt_listing_handler(char *cmd, /*@null@*/ char *param, int extra); +static int opt_case_handler(char *cmd, /*@null@*/ char *param, int extra); +static int opt_valid_length_handler(char *cmd, /*@null@*/ char *param, int extra); + +static int opt_warning_handler(char *cmd, /*@null@*/ char *param, int extra); +static int opt_preproc_option(char *cmd, /*@null@*/ char *param, int extra); +static int opt_exe_handler(char *cmd, /*@null@*/ char *param, int extra); + +static /*@only@*/ char *replace_extension(const char *orig, /*@null@*/ + const char *ext, const char *def); +static void print_error(const char *fmt, ...); + +static /*@exits@*/ void handle_yasm_int_error(const char *file, + unsigned int line, + const char *message); +static /*@exits@*/ void handle_yasm_fatal(const char *message, va_list va); +static const char *handle_yasm_gettext(const char *msgid); +static void print_yasm_error(const char *filename, unsigned long line, + const char *msg, /*@null@*/ const char *xref_fn, + unsigned long xref_line, + /*@null@*/ const char *xref_msg); +static void print_yasm_warning(const char *filename, unsigned long line, + const char *msg); + +static void apply_preproc_builtins(void); +static void apply_preproc_standard_macros(const yasm_stdmac *stdmacs); +static void apply_preproc_saved_options(void); +static void print_list_keyword_desc(const char *name, const char *keyword); + +/* values for special_options */ +#define SPECIAL_SHOW_HELP 0x01 +#define SPECIAL_SHOW_VERSION 0x02 +#define SPECIAL_SHOW_LICENSE 0x04 + +#define SEGMENT_ORDERING_ALPHABETIC 0x01 +#define SEGMENT_ORDERING_SOURCE 0x02 + +#define FP_EMULATED 0x01 +#define FP_REAL 0x02 + +#define CASE_ALL 0x01 +#define CASE_GLOBALS 0x02 +#define CASE_NONE 0x04 + +#define DEBUG_FULL 0x01 +#define DEBUG_LINES 0x02 +#define DEBUG_NONE 0x04 + +/* command line options */ +static opt_option options[] = +{ + { "version", 0, opt_special_handler, SPECIAL_SHOW_VERSION, + N_("show version text"), NULL }, + { "license", 0, opt_special_handler, SPECIAL_SHOW_LICENSE, + N_("show license text"), NULL }, + { "a", 0, opt_segment_ordering_handler, SEGMENT_ORDERING_ALPHABETIC, + N_("Alphabetic segment ordering"), NULL }, + { "s", 0, opt_segment_ordering_handler, SEGMENT_ORDERING_SOURCE, + N_("Source segment ordering"), NULL }, + + { "c", 0, opt_cross_reference_handler, 0, + N_("Generate cross-reference in listing"), NULL }, + + { "d", 1, opt_preproc_option, 2, + N_("pre-define a macro, optionally to value"), N_("macro[=value]") }, + + { "e", 0, opt_floating_point_handler, FP_EMULATED, + N_("Emulated floating-point instructions (not supported)"), NULL }, + { "r", 0, opt_floating_point_handler, FP_REAL, + N_("Real floating-point instructions"), NULL }, + + { "h", 0, opt_special_handler, SPECIAL_SHOW_HELP, + N_("show help text"), NULL }, + { "?", 0, opt_special_handler, SPECIAL_SHOW_HELP, + N_("show help text"), NULL }, + + { "i", 1, opt_preproc_option, 0, + N_("add include path"), N_("path") }, + + { "j", 1, opt_ignore, 0, + N_("Jam in an assemble directive CMD (eg. /jIDEAL) (not supported)"), NULL }, + + { "k", 1, opt_ignore, 0, + N_("Hash table capacity (ignored)"), N_("# symbols") }, + + { "l", 0, opt_listing_handler, 0, + N_("Generate listing"), N_("l=normal listing, la=expanded listing") }, + + { "ml", 0, opt_case_handler, CASE_ALL, + N_("Case sensitivity on all symbols"), NULL }, + { "mx", 0, opt_case_handler, CASE_GLOBALS, + N_("Case sensitivity on global symbols"), NULL }, + { "mu", 0, opt_case_handler, CASE_NONE, + N_("No case sensitivity on symbols"), NULL }, + { "mv", 0, opt_valid_length_handler, 0, + N_("Set maximum valid length for symbols"), N_("length") }, + + { "m", 1, opt_ignore, 0, + N_("Allow multiple passes to resolve forward reference (ignored)"), N_("number of passes") }, + + { "n", 0, opt_ignore, 0, + N_("Suppress symbol tables in listing"), NULL }, + + { "o", 0, opt_ignore, 0, + N_("Object code"), N_("os: standard, o: standard w/overlays, op: Phar Lap, oi: IBM") }, + + { "p", 0, opt_ignore, 0, + N_("Check for code segment overrides in protected mode"), NULL }, + { "q", 0, opt_ignore, 0, + N_("Suppress OBJ records not needed for linking (ignored)"), NULL }, + { "t", 0, opt_ignore, 0, + N_("Suppress messages if successful assembly"), NULL }, + { "u", 0, opt_ignore, 0, + N_("Set version emulation"), N_("Version") }, + { "w", 1, opt_warning_handler, 0, + N_("Set warning level"), N_("w0=none, w1=w2=warnings on, w-xxx/w+xxx=disable/enable warning xxx") }, + { "x", 0, opt_ignore, 0, + N_("Include false conditionals in listing"), NULL }, + { "zi", 0, opt_ignore, DEBUG_FULL, + N_("Full debug info"), NULL }, + { "zd", 0, opt_ignore, DEBUG_LINES, + N_("Line numbers debug info"), NULL }, + { "zn", 0, opt_ignore, DEBUG_NONE, + N_("No debug info"), NULL }, + { "z", 0, opt_ignore, 0, + N_("Display source line with error message (ignored)"), NULL }, + + { "b", 0, opt_exe_handler, 0, + N_("Build a (very) basic .exe file"), NULL }, +}; + +/* version message */ +/*@observer@*/ static const char *version_msg[] = { + PACKAGE_STRING, + "Compiled on " __DATE__ ".", + "Copyright (c) 2001-2010 Peter Johnson and other Yasm developers.", + "Run yasm --license for licensing overview and summary." +}; + +/* help messages */ +/*@observer@*/ static const char *help_head = N_( + "usage: tasm [option]* source [,object] [,listing] [,xref] \n" + "Options:\n"); +/*@observer@*/ static const char *help_tail = N_( + "\n" + "source is asm source to be assembled.\n" + "\n" + "Sample invocation:\n" + " tasm /zi source.asm\n" + "\n" + "Report bugs to bug-yasm@tortall.net\n"); + +/* parsed command line storage until appropriate modules have been loaded */ +typedef STAILQ_HEAD(constcharparam_head, constcharparam) constcharparam_head; + +typedef struct constcharparam { + STAILQ_ENTRY(constcharparam) link; + const char *param; + int id; +} constcharparam; + +static constcharparam_head preproc_options; + +static int +do_assemble(void) +{ + yasm_object *object; + const char *base_filename; + /*@null@*/ FILE *obj = NULL; + yasm_arch_create_error arch_error; + yasm_linemap *linemap; + yasm_errwarns *errwarns = yasm_errwarns_create(); + int i, matched; + + /* Initialize line map */ + linemap = yasm_linemap_create(); + yasm_linemap_set(linemap, in_filename, 0, 1, 1); + + /* determine the object filename if not specified */ + if (!obj_filename) { + if (in_filename == NULL) + /* Default to yasm.out if no obj filename specified */ + obj_filename = yasm__xstrdup("yasm.out"); + else { + /* replace (or add) extension to base filename */ + yasm__splitpath(in_filename, &base_filename); + if (base_filename[0] == '\0') + obj_filename = yasm__xstrdup("yasm.out"); + else + obj_filename = replace_extension(base_filename, + "obj", + "yasm.out"); + } + } + + cur_arch = yasm_arch_create(cur_arch_module, machine_name, + cur_parser_module->keyword, &arch_error); + if (!cur_arch) { + switch (arch_error) { + case YASM_ARCH_CREATE_BAD_MACHINE: + print_error(_("%s: `%s' is not a valid %s for %s `%s'"), + _("FATAL"), machine_name, _("machine"), + _("architecture"), cur_arch_module->keyword); + break; + case YASM_ARCH_CREATE_BAD_PARSER: + print_error(_("%s: `%s' is not a valid %s for %s `%s'"), + _("FATAL"), cur_parser_module->keyword, + _("parser"), _("architecture"), + cur_arch_module->keyword); + break; + default: + print_error(_("%s: unknown architecture error"), _("FATAL")); + } + + return EXIT_FAILURE; + } + + /* Create object */ + object = yasm_object_create(in_filename, obj_filename, cur_arch, + cur_objfmt_module, cur_dbgfmt_module); + if (!object) { + yasm_error_class eclass; + unsigned long xrefline; + /*@only@*/ /*@null@*/ char *estr, *xrefstr; + + yasm_error_fetch(&eclass, &estr, &xrefline, &xrefstr); + print_error("%s: %s", _("FATAL"), estr); + yasm_xfree(estr); + yasm_xfree(xrefstr); + + cleanup(object); + return EXIT_FAILURE; + } + + /* Get a fresh copy of objfmt_module as it may have changed. */ + cur_objfmt_module = ((yasm_objfmt_base *)object->objfmt)->module; + + /* Check to see if the requested preprocessor is in the allowed list + * for the active parser. + */ + matched = 0; + for (i=0; cur_parser_module->preproc_keywords[i]; i++) + if (yasm__strcasecmp(cur_parser_module->preproc_keywords[i], + cur_preproc_module->keyword) == 0) + matched = 1; + if (!matched) { + print_error(_("%s: `%s' is not a valid %s for %s `%s'"), _("FATAL"), + cur_preproc_module->keyword, _("preprocessor"), + _("parser"), cur_parser_module->keyword); + cleanup(object); + return EXIT_FAILURE; + } + + cur_preproc = yasm_preproc_create(cur_preproc_module, in_filename, + object->symtab, linemap, errwarns); + + apply_preproc_builtins(); + apply_preproc_standard_macros(cur_parser_module->stdmacs); + apply_preproc_standard_macros(cur_objfmt_module->stdmacs); + apply_preproc_saved_options(); + + /* Get initial x86 BITS setting from object format */ + if (strcmp(cur_arch_module->keyword, "x86") == 0) { + yasm_arch_set_var(cur_arch, "mode_bits", + cur_objfmt_module->default_x86_mode_bits); + } + + /* Parse! */ + cur_parser_module->do_parse(object, cur_preproc, list_filename != NULL, + linemap, errwarns); + + check_errors(errwarns, object, linemap); + + /* Finalize parse */ + yasm_object_finalize(object, errwarns); + check_errors(errwarns, object, linemap); + + /* Optimize */ + yasm_object_optimize(object, errwarns); + check_errors(errwarns, object, linemap); + + /* generate any debugging information */ + yasm_dbgfmt_generate(object, linemap, errwarns); + check_errors(errwarns, object, linemap); + + /* open the object file for output (if not already opened by dbg objfmt) */ + if (!obj && strcmp(cur_objfmt_module->keyword, "dbg") != 0) { + obj = open_file(obj_filename, "wb"); + if (!obj) { + cleanup(object); + return EXIT_FAILURE; + } + } + + /* Write the object file */ + yasm_objfmt_output(object, obj?obj:stderr, + strcmp(cur_dbgfmt_module->keyword, "null"), errwarns); + + /* Close object file */ + if (obj) + fclose(obj); + + /* If we had an error at this point, we also need to delete the output + * object file (to make sure it's not left newer than the source). + */ + if (yasm_errwarns_num_errors(errwarns, warning_error) > 0) + remove(obj_filename); + check_errors(errwarns, object, linemap); + + /* Open and write the list file */ + if (list_filename) { + FILE *list = open_file(list_filename, "wt"); + if (!list) { + cleanup(object); + return EXIT_FAILURE; + } + /* Initialize the list format */ + cur_listfmt = yasm_listfmt_create(cur_listfmt_module, in_filename, + obj_filename); + yasm_listfmt_output(cur_listfmt, list, linemap, cur_arch); + fclose(list); + } + + yasm_errwarns_output_all(errwarns, linemap, warning_error, + print_yasm_error, print_yasm_warning); + + yasm_linemap_destroy(linemap); + yasm_errwarns_destroy(errwarns); + cleanup(object); + return EXIT_SUCCESS; +} + +/* main function */ +/*@-globstate -unrecog@*/ +int +main(int argc, char *argv[]) +{ + size_t i; + + errfile = stderr; + +#if defined(HAVE_SETLOCALE) && defined(HAVE_LC_MESSAGES) + setlocale(LC_MESSAGES, ""); +#endif +#if defined(LOCALEDIR) + bindtextdomain(PACKAGE, LOCALEDIR); +#endif + textdomain(PACKAGE); + + /* Initialize errwarn handling */ + yasm_internal_error_ = handle_yasm_int_error; + yasm_fatal = handle_yasm_fatal; + yasm_gettext_hook = handle_yasm_gettext; + yasm_errwarn_initialize(); + + /* Initialize BitVector (needed for intnum/floatnum). */ + if (BitVector_Boot() != ErrCode_Ok) { + print_error(_("%s: could not initialize BitVector"), _("FATAL")); + return EXIT_FAILURE; + } + + /* Initialize intnum and floatnum */ + yasm_intnum_initialize(); + yasm_floatnum_initialize(); + +#ifdef CMAKE_BUILD + /* Load standard modules */ +#ifdef BUILD_SHARED_LIBS + if (!load_plugin("yasmstd")) { + print_error(_("%s: could not load standard modules"), _("FATAL")); + return EXIT_FAILURE; + } +#else + yasm_init_plugin(); +#endif +#endif + + /* Initialize parameter storage */ + STAILQ_INIT(&preproc_options); + + if (parse_cmdline(argc, argv, options, NELEMS(options), print_error)) + return EXIT_FAILURE; + + switch (special_options) { + case SPECIAL_SHOW_HELP: + /* Does gettext calls internally */ + help_msg(help_head, help_tail, options, NELEMS(options)); + return EXIT_SUCCESS; + case SPECIAL_SHOW_VERSION: + for (i=0; i<NELEMS(version_msg); i++) + printf("%s\n", version_msg[i]); + return EXIT_SUCCESS; + case SPECIAL_SHOW_LICENSE: + for (i=0; i<NELEMS(license_msg); i++) + printf("%s\n", license_msg[i]); + return EXIT_SUCCESS; + } + + /* Open error file if specified. */ + if (error_filename) { + errfile = open_file(error_filename, "wt"); + if (!errfile) + return EXIT_FAILURE; + } + + /* If not already specified, default to bin as the object format. */ + if (!cur_objfmt_module) { + if (!objfmt_keyword) + objfmt_keyword = yasm__xstrdup(DEFAULT_OBJFMT_MODULE); + cur_objfmt_module = yasm_load_objfmt(objfmt_keyword); + if (!cur_objfmt_module) { + print_error(_("%s: could not load default %s"), _("FATAL"), + _("object format")); + return EXIT_FAILURE; + } + } + + /* TASM's architecture is x86 */ + cur_arch_module = yasm_load_arch("x86"); + if (!cur_arch_module) { + print_error(_("%s: could not load %s"), _("FATAL"), + _("architecture")); + return EXIT_FAILURE; + } + machine_name = + yasm__xstrdup(cur_arch_module->default_machine_keyword); + + /* Check for arch help */ + if (machine_name && strcmp(machine_name, "help") == 0) { + const yasm_arch_machine *m = cur_arch_module->machines; + printf(_("Available %s for %s `%s':\n"), _("machines"), + _("architecture"), cur_arch_module->keyword); + while (m->keyword && m->name) { + print_list_keyword_desc(m->name, m->keyword); + m++; + } + return EXIT_SUCCESS; + } + + cur_parser_module = yasm_load_parser("tasm"); + if (!cur_parser_module) { + print_error(_("%s: could not load %s"), _("FATAL"), + _("parser")); + cleanup(NULL); + return EXIT_FAILURE; + } + + /* If not already specified, default to the parser's default preproc. */ + if (!cur_preproc_module) { + cur_preproc_module = + yasm_load_preproc(cur_parser_module->default_preproc_keyword); + if (!cur_preproc_module) { + print_error(_("%s: could not load default %s"), _("FATAL"), + _("preprocessor")); + cleanup(NULL); + return EXIT_FAILURE; + } + } + + /* Determine input filename and open input file. */ + if (!in_filename) { + print_error(_("No input files specified")); + return EXIT_FAILURE; + } + + /* If list file enabled, make sure we have a list format loaded. */ + if (list_filename) { + /* use nasm as the list format. */ + cur_listfmt_module = yasm_load_listfmt("nasm"); + } + + /* If not already specified, default to null as the debug format. */ + if (!cur_dbgfmt_module) { + cur_dbgfmt_module = yasm_load_dbgfmt("null"); + if (!cur_dbgfmt_module) { + print_error(_("%s: could not load default %s"), _("FATAL"), + _("debug format")); + return EXIT_FAILURE; + } + } + + return do_assemble(); +} +/*@=globstate =unrecog@*/ + +/* Open the object file. Returns 0 on failure. */ +static FILE * +open_file(const char *filename, const char *mode) +{ + FILE *f; + + f = fopen(filename, mode); + if (!f) + print_error(_("could not open file `%s'"), filename); + return f; +} + +static void +check_errors(yasm_errwarns *errwarns, yasm_object *object, + yasm_linemap *linemap) +{ + if (yasm_errwarns_num_errors(errwarns, warning_error) > 0) { + yasm_errwarns_output_all(errwarns, linemap, warning_error, + print_yasm_error, print_yasm_warning); + yasm_linemap_destroy(linemap); + yasm_errwarns_destroy(errwarns); + cleanup(object); + exit(EXIT_FAILURE); + } +} + +/* Define DO_FREE to 1 to enable deallocation of all data structures. + * Useful for detecting memory leaks, but slows down execution unnecessarily + * (as the OS will free everything we miss here). + */ +#define DO_FREE 1 + +/* Cleans up all allocated structures. */ +static void +cleanup(yasm_object *object) +{ + if (DO_FREE) { + if (cur_listfmt) + yasm_listfmt_destroy(cur_listfmt); + if (cur_preproc) + yasm_preproc_destroy(cur_preproc); + if (object) + yasm_object_destroy(object); + + yasm_floatnum_cleanup(); + yasm_intnum_cleanup(); + + yasm_errwarn_cleanup(); + + BitVector_Shutdown(); + } + + if (DO_FREE) { + if (in_filename) + yasm_xfree(in_filename); + if (obj_filename) + yasm_xfree(obj_filename); + if (list_filename) + yasm_xfree(list_filename); + if (xref_filename) + yasm_xfree(xref_filename); + if (machine_name) + yasm_xfree(machine_name); + if (objfmt_keyword) + yasm_xfree(objfmt_keyword); + } + + if (errfile != stderr && errfile != stdout) + fclose(errfile); +#if defined(CMAKE_BUILD) && defined(BUILD_SHARED_LIBS) + unload_plugins(); +#endif +} + +/* + * Command line options handlers + */ +static char ** const filenames[] = { + &in_filename, &obj_filename, &list_filename, &xref_filename, NULL +}, ** const * cur_filename = &filenames[0]; + +static int filename_handler(char *param) { + if (!*cur_filename) { + print_error(_("error: too many files on command line.")); + return 1; + } + + if (*param) + **cur_filename = yasm__xstrdup(param); + + return 0; +} +int +not_an_option_handler(char *param) { + char *c, *d = param; + + while ((c = strchr(d, ','))) { + *c = '\0'; + if (filename_handler(d)) + return 1; + d = c + 1; + cur_filename++; + } + filename_handler(d); + return 0; +} + +static int +opt_special_handler(/*@unused@*/ char *cmd, /*@unused@*/ char *param, int extra) +{ + if (special_options == 0) + special_options = extra; + return 0; +} + +static int +opt_segment_ordering_handler(/*@unused@*/ char *cmd, /*@unused@*/ char *param, int extra) +{ + segment_ordering = extra; + return 0; +} + +static int +opt_cross_reference_handler(/*@unused@*/ char *cmd, /*@unused@*/ char *param, int extra) +{ + cross_reference = 1; + return 0; +} + +static int +opt_floating_point_handler(/*@unused@*/ char *cmd, /*@unused@*/ char *param, int extra) +{ + floating_point = extra; + return 0; +} + +static int +opt_ignore(/*@unused@*/ char *cmd, /*@unused@*/ char *param, int extra) +{ + return 0; +} + +static int +opt_listing_handler(/*@unused@*/ char *cmd, /*@unused@*/ char *param, int extra) +{ + if (param && param[0]) { + if (param[0] != 'a') + return 1; + expanded_listing = 1; + } + listing = 1; + return 0; +} + +static int +opt_case_handler(/*@unused@*/ char *cmd, /*@unused@*/ char *param, int extra) +{ + case_sensitivity = extra; + return 0; +} + +static int +opt_valid_length_handler(/*@unused@*/ char *cmd, /*@unused@*/ char *param, int extra) +{ + valid_length = atoi(param); + return 0; +} + +static int +opt_warning_handler(char *cmd, /*@unused@*/ char *param, int extra) +{ + /* is it disabling the warning instead of enabling? */ + void (*action)(yasm_warn_class wclass) = NULL; + + if (cmd[0] == '0') { + /* /w0, disable warnings */ + yasm_warn_disable_all(); + return 0; + } + + if (cmd[0] == '1' || cmd[0] == '2') { + /* /w[12], enable warnings */ + yasm_warn_enable(YASM_WARN_UNREC_CHAR); + yasm_warn_enable(YASM_WARN_ORPHAN_LABEL); + yasm_warn_enable(YASM_WARN_UNINIT_CONTENTS); + return 0; + } + + /* detect no- prefix to disable the warning */ + if (cmd[0] == '-') { + action = yasm_warn_disable; + } else if (cmd[0] == '+') { + action = yasm_warn_enable; + } else return 1; + + /* skip past '+/-' */ + cmd++; + + if (cmd[0] == '\0') + /* just /w- or /w+, so definitely not valid */ + return 1; + else if (strcmp(cmd, "error") == 0) + warning_error = (action == yasm_warn_enable); + else if (strcmp(cmd, "unrecognized-char") == 0) + action(YASM_WARN_UNREC_CHAR); + else if (strcmp(cmd, "orphan-labels") == 0) + action(YASM_WARN_ORPHAN_LABEL); + else if (strcmp(cmd, "uninit-contents") == 0) + action(YASM_WARN_UNINIT_CONTENTS); + else if (strcmp(cmd, "size-override") == 0) + action(YASM_WARN_SIZE_OVERRIDE); + else + return 1; + + return 0; +} + +static int +opt_preproc_option(/*@unused@*/ char *cmd, char *param, int extra) +{ + constcharparam *cp; + cp = yasm_xmalloc(sizeof(constcharparam)); + cp->param = param; + cp->id = extra; + STAILQ_INSERT_TAIL(&preproc_options, cp, link); + return 0; +} + +static int +opt_exe_handler(char *cmd, /*@unused@*/ char *param, int extra) +{ + objfmt_keyword = yasm__xstrdup("dosexe"); + return 0; +} + +static void +apply_preproc_builtins() +{ + char *predef; + + if (!objfmt_keyword) + objfmt_keyword = yasm__xstrdup(DEFAULT_OBJFMT_MODULE); + + /* Define standard YASM assembly-time macro constants */ + predef = yasm_xmalloc(strlen("__YASM_OBJFMT__=") + + strlen(objfmt_keyword) + 1); + strcpy(predef, "__YASM_OBJFMT__="); + strcat(predef, objfmt_keyword); + yasm_preproc_define_builtin(cur_preproc, predef); + yasm_xfree(predef); +} + +static void +apply_preproc_standard_macros(const yasm_stdmac *stdmacs) +{ + int i, matched; + + if (!stdmacs) + return; + + matched = -1; + for (i=0; stdmacs[i].parser; i++) + if (yasm__strcasecmp(stdmacs[i].parser, + cur_parser_module->keyword) == 0 && + yasm__strcasecmp(stdmacs[i].preproc, + cur_preproc_module->keyword) == 0) + matched = i; + if (matched >= 0 && stdmacs[matched].macros) + yasm_preproc_add_standard(cur_preproc, stdmacs[matched].macros); +} + +static void +apply_preproc_saved_options() +{ + constcharparam *cp, *cpnext; + + void (*funcs[3])(yasm_preproc *, const char *); + funcs[0] = cur_preproc_module->add_include_file; + funcs[1] = cur_preproc_module->predefine_macro; + funcs[2] = cur_preproc_module->undefine_macro; + + STAILQ_FOREACH(cp, &preproc_options, link) { + if (0 <= cp->id && cp->id < 3 && funcs[cp->id]) + funcs[cp->id](cur_preproc, cp->param); + } + + cp = STAILQ_FIRST(&preproc_options); + while (cp != NULL) { + cpnext = STAILQ_NEXT(cp, link); + yasm_xfree(cp); + cp = cpnext; + } + STAILQ_INIT(&preproc_options); +} + +/* Replace extension on a filename (or append one if none is present). + * If output filename would be identical to input (same extension out as in), + * returns (copy of) def. + * A NULL ext means the trailing '.' should NOT be included, whereas a "" ext + * means the trailing '.' should be included. + */ +static char * +replace_extension(const char *orig, /*@null@*/ const char *ext, + const char *def) +{ + char *out, *outext; + size_t deflen, outlen; + + /* allocate enough space for full existing name + extension */ + outlen = strlen(orig) + 2; + if (ext) + outlen += strlen(ext) + 1; + deflen = strlen(def) + 1; + if (outlen < deflen) + outlen = deflen; + out = yasm_xmalloc(outlen); + + strcpy(out, orig); + outext = strrchr(out, '.'); + if (outext) { + /* Existing extension: make sure it's not the same as the replacement + * (as we don't want to overwrite the source file). + */ + outext++; /* advance past '.' */ + if (ext && strcmp(outext, ext) == 0) { + outext = NULL; /* indicate default should be used */ + print_error( + _("file name already ends in `.%s': output will be in `%s'"), + ext, def); + } + } else { + /* No extension: make sure the output extension is not empty + * (again, we don't want to overwrite the source file). + */ + if (!ext) + print_error( + _("file name already has no extension: output will be in `%s'"), + def); + else { + outext = strrchr(out, '\0'); /* point to end of the string */ + *outext++ = '.'; /* append '.' */ + } + } + + /* replace extension or use default name */ + if (outext) { + if (!ext) { + /* Back up and replace '.' with string terminator */ + outext--; + *outext = '\0'; + } else + strcpy(outext, ext); + } else + strcpy(out, def); + + return out; +} + +void +print_list_keyword_desc(const char *name, const char *keyword) +{ + printf("%4s%-12s%s\n", "", keyword, name); +} + +static void +print_error(const char *fmt, ...) +{ + va_list va; + fprintf(errfile, "tasm: "); + va_start(va, fmt); + vfprintf(errfile, fmt, va); + va_end(va); + fputc('\n', errfile); +} + +static /*@exits@*/ void +handle_yasm_int_error(const char *file, unsigned int line, const char *message) +{ + fprintf(stderr, _("INTERNAL ERROR at %s, line %u: %s\n"), file, line, + gettext(message)); +#ifdef HAVE_ABORT + abort(); +#else + exit(EXIT_FAILURE); +#endif +} + +static /*@exits@*/ void +handle_yasm_fatal(const char *fmt, va_list va) +{ + fprintf(errfile, "**%s**: ", _("Fatal")); + vfprintf(errfile, gettext(fmt), va); + fputc('\n', errfile); + exit(EXIT_FAILURE); +} + +static const char * +handle_yasm_gettext(const char *msgid) +{ + return gettext(msgid); +} + +static void +print_yasm_error(const char *filename, unsigned long line, const char *msg, + const char *xref_fn, unsigned long xref_line, + const char *xref_msg) +{ + if (line) + fprintf(errfile, "**%s** %s(%lu) %s\n", _("Error"), filename, line, msg); + else + fprintf(errfile, "**%s** %s %s\n", _("Error"), filename, msg); + + if (/* xref_fn && */ xref_msg) { + if (xref_line) + fprintf(errfile, "**%s** %s(%lu) %s\n", _("Error"), filename, xref_line, xref_msg); + else + fprintf(errfile, "**%s** %s %s\n", _("Error"), filename, xref_msg); + } +} + +static void +print_yasm_warning(const char *filename, unsigned long line, const char *msg) +{ + if (line) + fprintf(errfile, "*%s* %s(%lu) %s\n", _("Warning"), filename, line, msg); + else + fprintf(errfile, "*%s* %s %s\n", _("Warning"), filename, msg); +} diff --git a/contrib/tools/yasm/frontends/vsyasm/license.c b/contrib/tools/yasm/frontends/vsyasm/license.c new file mode 100644 index 0000000000..35c5a04137 --- /dev/null +++ b/contrib/tools/yasm/frontends/vsyasm/license.c @@ -0,0 +1,65 @@ +/* This file auto-generated from COPYING by genstring.py - don't edit it */ + +static const char* license_msg[] = { + "Yasm is Copyright (c) 2001-2014 Peter Johnson and other Yasm developers.", + "", + "Yasm developers and/or contributors include:", + "Peter Johnson", + "Michael Urman", + "Brian Gladman (Visual Studio build files, other fixes)", + "Stanislav Karchebny (options parser)", + "Mathieu Monnier (SSE4 instruction patches, NASM preprocessor additions)", + "Anonymous \"NASM64\" developer (NASM preprocessor fixes)", + "Stephen Polkowski (x86 instruction patches)", + "Henryk Richter (Mach-O object format)", + "Ben Skeggs (patches, bug reports)", + "Alexei Svitkine (GAS preprocessor)", + "Samuel Thibault (TASM parser and frontend)", + "", + "-----------------------------------", + "Yasm licensing overview and summary", + "-----------------------------------", + "", + "Note: This document does not provide legal advice nor is it the actual", + "license of any part of Yasm. See the individual licenses for complete", + "details. Consult a lawyer for legal advice.", + "", + "The primary license of Yasm is the 2-clause BSD license. Please use this", + "license if you plan on submitting code to the project.", + "", + "Yasm has absolutely no warranty; not even for merchantibility or fitness", + "for a particular purpose.", + "", + "-------", + "Libyasm", + "-------", + "Libyasm is 2-clause or 3-clause BSD licensed, with the exception of", + "bitvect, which is triple-licensed under the Artistic license, GPL, and", + "LGPL. Libyasm is thus GPL and LGPL compatible. In addition, this also", + "means that libyasm is free for binary-only distribution as long as the", + "terms of the 3-clause BSD license and Artistic license (as it applies to", + "bitvect) are fulfilled.", + "", + "-------", + "Modules", + "-------", + "The modules are 2-clause or 3-clause BSD licensed.", + "", + "---------", + "Frontends", + "---------", + "The frontends are 2-clause BSD licensed.", + "", + "-------------", + "License Texts", + "-------------", + "The full text of all licenses are provided in separate files in the source", + "distribution. Each source file may include the entire license (in the case", + "of the BSD and Artistic licenses), or may reference the GPL or LGPL license", + "file.", + "", + "BSD.txt - 2-clause and 3-clause BSD licenses", + "Artistic.txt - Artistic license", + "GNU_GPL-2.0 - GNU General Public License", + "GNU_LGPL-2.0 - GNU Library General Public License", +}; diff --git a/contrib/tools/yasm/frontends/vsyasm/vsyasm.c b/contrib/tools/yasm/frontends/vsyasm/vsyasm.c new file mode 100644 index 0000000000..905145fa15 --- /dev/null +++ b/contrib/tools/yasm/frontends/vsyasm/vsyasm.c @@ -0,0 +1,1424 @@ +/* + * Program entry point, command line parsing + * + * 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 <ctype.h> +#include <libyasm/compat-queue.h> +#include <libyasm/bitvect.h> +#include <libyasm.h> + +#ifdef HAVE_LIBGEN_H +#include <libgen.h> +#endif + +#include "frontends/yasm/yasm-options.h" + +#if defined(CMAKE_BUILD) && defined(BUILD_SHARED_LIBS) +#include "frontends/yasm/yasm-plugin.h" +#endif + +#include "license.c" + +#if defined(CMAKE_BUILD) && !defined(BUILD_SHARED_LIBS) +void yasm_init_plugin(void); +#endif + +/*@null@*/ /*@only@*/ static char *objdir_pathname = NULL; +/*@null@*/ /*@only@*/ static char *global_prefix = NULL, *global_suffix = NULL; +/*@null@*/ /*@only@*/ static char *listdir_pathname = NULL; +/*@null@*/ /*@only@*/ static char *mapdir_pathname = NULL; +/*@null@*/ /*@only@*/ static char *objext = NULL; +/*@null@*/ /*@only@*/ static char *listext = NULL, *mapext = NULL; +/*@null@*/ /*@only@*/ static char *machine_name = NULL; +static int special_options = 0; +/*@null@*/ /*@dependent@*/ static const yasm_arch_module * + cur_arch_module = NULL; +/*@null@*/ /*@dependent@*/ static const yasm_parser_module * + cur_parser_module = NULL; +/*@null@*/ /*@dependent@*/ static const yasm_preproc_module * + cur_preproc_module = NULL; +/*@null@*/ static char *objfmt_keyword = NULL; +/*@null@*/ /*@dependent@*/ static const yasm_objfmt_module * + cur_objfmt_module = NULL; +/*@null@*/ /*@dependent@*/ static const yasm_dbgfmt_module * + cur_dbgfmt_module = NULL; +/*@null@*/ /*@dependent@*/ static const yasm_listfmt_module * + cur_listfmt_module = NULL; +static unsigned int force_strict = 0; +static int warning_error = 0; /* warnings being treated as errors */ +static FILE *errfile; +/*@null@*/ /*@only@*/ static char *error_filename = NULL; +static enum { + EWSTYLE_GNU = 0, + EWSTYLE_VC +} ewmsg_style = EWSTYLE_GNU; + +/*@null@*/ /*@dependent@*/ static FILE *open_file(const char *filename, + const char *mode); +static int check_errors(/*@only@*/ yasm_errwarns *errwarns, + /*@only@*/ yasm_object *object, + /*@only@*/ yasm_linemap *linemap, + /*@only@*/ yasm_preproc *preproc, + /*@only@*/ yasm_arch *arch); +static void cleanup(void); +static void free_input_filenames(void); + +/* Forward declarations: cmd line parser handlers */ +static int opt_special_handler(char *cmd, /*@null@*/ char *param, int extra); +static int opt_arch_handler(char *cmd, /*@null@*/ char *param, int extra); +static int opt_parser_handler(char *cmd, /*@null@*/ char *param, int extra); +static int opt_preproc_handler(char *cmd, /*@null@*/ char *param, int extra); +static int opt_objfmt_handler(char *cmd, /*@null@*/ char *param, int extra); +static int opt_dbgfmt_handler(char *cmd, /*@null@*/ char *param, int extra); +static int opt_listfmt_handler(char *cmd, /*@null@*/ char *param, int extra); +static int opt_listdir_handler(char *cmd, /*@null@*/ char *param, int extra); +static int opt_objdir_handler(char *cmd, /*@null@*/ char *param, int extra); +static int opt_mapdir_handler(char *cmd, /*@null@*/ char *param, int extra); +static int opt_listext_handler(char *cmd, /*@null@*/ char *param, int extra); +static int opt_objext_handler(char *cmd, /*@null@*/ char *param, int extra); +static int opt_mapext_handler(char *cmd, /*@null@*/ char *param, int extra); +static int opt_machine_handler(char *cmd, /*@null@*/ char *param, int extra); +static int opt_strict_handler(char *cmd, /*@null@*/ char *param, int extra); +static int opt_warning_handler(char *cmd, /*@null@*/ char *param, int extra); +static int opt_error_file(char *cmd, /*@null@*/ char *param, int extra); +static int opt_error_stdout(char *cmd, /*@null@*/ char *param, int extra); +static int opt_include_option(char *cmd, /*@null@*/ char *param, int extra); +static int opt_preproc_option(char *cmd, /*@null@*/ char *param, int extra); +static int opt_ewmsg_handler(char *cmd, /*@null@*/ char *param, int extra); +static int opt_prefix_handler(char *cmd, /*@null@*/ char *param, int extra); +static int opt_suffix_handler(char *cmd, /*@null@*/ char *param, int extra); +#if defined(CMAKE_BUILD) && defined(BUILD_SHARED_LIBS) +static int opt_plugin_handler(char *cmd, /*@null@*/ char *param, int extra); +#endif + +static /*@only@*/ char *replace_extension(const char *orig, /*@null@*/ + const char *ext); +static void print_error(const char *fmt, ...); + +static /*@exits@*/ void handle_yasm_int_error(const char *file, + unsigned int line, + const char *message); +static /*@exits@*/ void handle_yasm_fatal(const char *message, va_list va); +static const char *handle_yasm_gettext(const char *msgid); +static void print_yasm_error(const char *filename, unsigned long line, + const char *msg, /*@null@*/ const char *xref_fn, + unsigned long xref_line, + /*@null@*/ const char *xref_msg); +static void print_yasm_warning(const char *filename, unsigned long line, + const char *msg); + +static void apply_preproc_builtins(yasm_preproc *preproc); +static void apply_preproc_standard_macros(yasm_preproc *preproc, + const yasm_stdmac *stdmacs); +static void apply_preproc_saved_options(yasm_preproc *preproc); +static void free_preproc_saved_options(void); +static void print_list_keyword_desc(const char *name, const char *keyword); + +/* values for special_options */ +#define SPECIAL_SHOW_HELP 0x01 +#define SPECIAL_SHOW_VERSION 0x02 +#define SPECIAL_SHOW_LICENSE 0x04 +#define SPECIAL_LISTED 0x08 + +/* command line options */ +static opt_option options[] = +{ + { 0, "version", 0, opt_special_handler, SPECIAL_SHOW_VERSION, + N_("show version text"), NULL }, + { 0, "license", 0, opt_special_handler, SPECIAL_SHOW_LICENSE, + N_("show license text"), NULL }, + { 'h', "help", 0, opt_special_handler, SPECIAL_SHOW_HELP, + N_("show help text"), NULL }, + { 'a', "arch", 1, opt_arch_handler, 0, + N_("select architecture (list with -a help)"), N_("arch") }, + { 'p', "parser", 1, opt_parser_handler, 0, + N_("select parser (list with -p help)"), N_("parser") }, + { 'r', "preproc", 1, opt_preproc_handler, 0, + N_("select preprocessor (list with -r help)"), N_("preproc") }, + { 'f', "oformat", 1, opt_objfmt_handler, 0, + N_("select object format (list with -f help)"), N_("format") }, + { 'g', "dformat", 1, opt_dbgfmt_handler, 0, + N_("select debugging format (list with -g help)"), N_("debug") }, + { 'L', "lformat", 1, opt_listfmt_handler, 0, + N_("select list format (list with -L help)"), N_("list") }, + { 'l', "list", 1, opt_listdir_handler, 0, + N_("name of list-file output directory"), N_("pathname") }, + { 'o', "objdir", 1, opt_objdir_handler, 0, + N_("name of object-file output directory"), N_("pathname") }, + { 0, "mapdir", 1, opt_mapdir_handler, 0, + N_("name of map-file output directory"), N_("pathname") }, + { 0, "listext", 1, opt_listext_handler, 0, + N_("list-file extension (default `lst')"), N_("ext") }, + { 0, "objext", 1, opt_objext_handler, 0, + N_("object-file extension (default is by object format)"), N_("ext") }, + { 0, "mapext", 1, opt_mapext_handler, 0, + N_("map-file extension (default `map')"), N_("ext") }, + { 'm', "machine", 1, opt_machine_handler, 0, + N_("select machine (list with -m help)"), N_("machine") }, + { 0, "force-strict", 0, opt_strict_handler, 0, + N_("treat all sized operands as if `strict' was used"), NULL }, + { 'w', NULL, 0, opt_warning_handler, 1, + N_("inhibits warning messages"), NULL }, + { 'W', NULL, 0, opt_warning_handler, 0, + N_("enables/disables warning"), NULL }, + { 'E', NULL, 1, opt_error_file, 0, + N_("redirect error messages to file"), N_("file") }, + { 's', NULL, 0, opt_error_stdout, 0, + N_("redirect error messages to stdout"), NULL }, + { 'i', NULL, 1, opt_include_option, 0, + N_("add include path"), N_("path") }, + { 'I', NULL, 1, opt_include_option, 0, + N_("add include path"), N_("path") }, + { 'P', NULL, 1, opt_preproc_option, 0, + N_("pre-include file"), N_("filename") }, + { 'd', NULL, 1, opt_preproc_option, 1, + N_("pre-define a macro, optionally to value"), N_("macro[=value]") }, + { 'D', NULL, 1, opt_preproc_option, 1, + N_("pre-define a macro, optionally to value"), N_("macro[=value]") }, + { 'u', NULL, 1, opt_preproc_option, 2, + N_("undefine a macro"), N_("macro") }, + { 'U', NULL, 1, opt_preproc_option, 2, + N_("undefine a macro"), N_("macro") }, + { 'X', NULL, 1, opt_ewmsg_handler, 0, + N_("select error/warning message style (`gnu' or `vc')"), N_("style") }, + { 0, "prefix", 1, opt_prefix_handler, 0, + N_("prepend argument to name of all external symbols"), N_("prefix") }, + { 0, "suffix", 1, opt_suffix_handler, 0, + N_("append argument to name of all external symbols"), N_("suffix") }, + { 0, "postfix", 1, opt_suffix_handler, 0, + N_("append argument to name of all external symbols"), N_("suffix") }, +#if defined(CMAKE_BUILD) && defined(BUILD_SHARED_LIBS) + { 'N', "plugin", 1, opt_plugin_handler, 0, + N_("load plugin module"), N_("plugin") }, +#endif +}; + +/* version message */ +/*@observer@*/ static const char *version_msg[] = { + PACKAGE_STRING, + "Compiled on " __DATE__ ".", + "Copyright (c) 2001-2010 Peter Johnson and other Yasm developers.", + "Run yasm --license for licensing overview and summary." +}; + +/* help messages */ +/*@observer@*/ static const char *help_head = N_( + "usage: vsyasm [option]* file...\n" + "Options:\n"); +/*@observer@*/ static const char *help_tail = N_( + "\n" + "Files are asm sources to be assembled.\n" + "\n" + "Sample invocation:\n" + " vsyasm -f win64 -o objdir source1.asm source2.asm\n" + "\n" + "All options apply to all files.\n" + "\n" + "Report bugs to bug-yasm@tortall.net\n"); + +/* parsed command line storage until appropriate modules have been loaded */ +typedef STAILQ_HEAD(constcharparam_head, constcharparam) constcharparam_head; + +typedef struct constcharparam { + STAILQ_ENTRY(constcharparam) link; + const char *param; + int id; +} constcharparam; + +static constcharparam_head preproc_options; +static constcharparam_head input_files; +static int num_input_files = 0; + +static int +do_assemble(const char *in_filename) +{ + yasm_object *object; + const char *base_filename; + char *fn = NULL; + char *obj_filename, *list_filename = NULL, *map_filename = NULL; + /*@null@*/ FILE *obj = NULL; + yasm_arch_create_error arch_error; + yasm_linemap *linemap; + yasm_arch *arch = NULL; + yasm_preproc *preproc = NULL; + yasm_errwarns *errwarns = yasm_errwarns_create(); + int i, matched; + + /* Initialize line map */ + linemap = yasm_linemap_create(); + yasm_linemap_set(linemap, in_filename, 0, 1, 1); + + /* determine the output filenames */ + /* replace (or add) extension to base filename */ + yasm__splitpath(in_filename, &base_filename); + if (base_filename[0] != '\0') + fn = replace_extension(base_filename, objext); + if (!fn) + { + print_error(_("could not determine output filename for `%s'"), + in_filename); + return EXIT_FAILURE; + } + obj_filename = yasm__combpath(objdir_pathname, fn); + yasm_xfree(fn); + + if (listdir_pathname) { + fn = replace_extension(base_filename, listext); + if (!fn) + { + print_error(_("could not determine list filename for `%s'"), + in_filename); + return EXIT_FAILURE; + } + list_filename = yasm__combpath(listdir_pathname, fn); + yasm_xfree(fn); + } + + if (mapdir_pathname) { + fn = replace_extension(base_filename, mapext); + if (!fn) + { + print_error(_("could not determine map filename for `%s'"), + in_filename); + return EXIT_FAILURE; + } + map_filename = yasm__combpath(mapdir_pathname, fn); + yasm_xfree(fn); + } + + /* Set up architecture using machine and parser. */ + if (!machine_name) { + /* If we're using x86 and the default objfmt bits is 64, default the + * machine to amd64. When we get more arches with multiple machines, + * we should do this in a more modular fashion. + */ + if (strcmp(cur_arch_module->keyword, "x86") == 0 && + cur_objfmt_module->default_x86_mode_bits == 64) + machine_name = yasm__xstrdup("amd64"); + else + machine_name = + yasm__xstrdup(cur_arch_module->default_machine_keyword); + } + + arch = yasm_arch_create(cur_arch_module, machine_name, + cur_parser_module->keyword, &arch_error); + if (!arch) { + switch (arch_error) { + case YASM_ARCH_CREATE_BAD_MACHINE: + print_error(_("%s: `%s' is not a valid %s for %s `%s'"), + _("FATAL"), machine_name, _("machine"), + _("architecture"), cur_arch_module->keyword); + break; + case YASM_ARCH_CREATE_BAD_PARSER: + print_error(_("%s: `%s' is not a valid %s for %s `%s'"), + _("FATAL"), cur_parser_module->keyword, + _("parser"), _("architecture"), + cur_arch_module->keyword); + break; + default: + print_error(_("%s: unknown architecture error"), _("FATAL")); + } + + return EXIT_FAILURE; + } + + /* Create object */ + object = yasm_object_create(in_filename, obj_filename, arch, + cur_objfmt_module, cur_dbgfmt_module); + if (!object) { + yasm_error_class eclass; + unsigned long xrefline; + /*@only@*/ /*@null@*/ char *estr, *xrefstr; + + yasm_error_fetch(&eclass, &estr, &xrefline, &xrefstr); + print_error("%s: %s", _("FATAL"), estr); + yasm_xfree(estr); + yasm_xfree(xrefstr); + return EXIT_FAILURE; + } + + /* Get a fresh copy of objfmt_module as it may have changed. */ + cur_objfmt_module = ((yasm_objfmt_base *)object->objfmt)->module; + + /* Check to see if the requested preprocessor is in the allowed list + * for the active parser. + */ + matched = 0; + for (i=0; cur_parser_module->preproc_keywords[i]; i++) + if (yasm__strcasecmp(cur_parser_module->preproc_keywords[i], + cur_preproc_module->keyword) == 0) + matched = 1; + if (!matched) { + print_error(_("%s: `%s' is not a valid %s for %s `%s'"), _("FATAL"), + cur_preproc_module->keyword, _("preprocessor"), + _("parser"), cur_parser_module->keyword); + yasm_object_destroy(object); + return EXIT_FAILURE; + } + + if (global_prefix) + yasm_object_set_global_prefix(object, global_prefix); + if (global_suffix) + yasm_object_set_global_suffix(object, global_suffix); + + preproc = yasm_preproc_create(cur_preproc_module, in_filename, + object->symtab, linemap, errwarns); + + apply_preproc_builtins(preproc); + apply_preproc_standard_macros(preproc, cur_parser_module->stdmacs); + apply_preproc_standard_macros(preproc, cur_objfmt_module->stdmacs); + apply_preproc_saved_options(preproc); + + /* Get initial x86 BITS setting from object format */ + if (strcmp(cur_arch_module->keyword, "x86") == 0) { + yasm_arch_set_var(arch, "mode_bits", + cur_objfmt_module->default_x86_mode_bits); + } + + yasm_arch_set_var(arch, "force_strict", force_strict); + + /* Try to enable the map file via a map NASM directive. This is + * somewhat of a hack. + */ + if (map_filename) { + const yasm_directive *dir = &cur_objfmt_module->directives[0]; + matched = 0; + for (; dir && dir->name; dir++) { + if (yasm__strcasecmp(dir->name, "map") == 0 && + yasm__strcasecmp(dir->parser, "nasm") == 0) { + yasm_valparamhead vps; + yasm_valparam *vp; + matched = 1; + yasm_vps_initialize(&vps); + vp = yasm_vp_create_string(NULL, yasm__xstrdup(map_filename)); + yasm_vps_append(&vps, vp); + dir->handler(object, &vps, NULL, 0); + yasm_vps_delete(&vps); + } + } + if (!matched) { + print_error( + _("warning: object format `%s' does not support map files"), + cur_objfmt_module->keyword); + } + } + + /* Parse! */ + cur_parser_module->do_parse(object, preproc, list_filename != NULL, + linemap, errwarns); + + if (check_errors(errwarns, object, linemap, preproc, arch) == EXIT_FAILURE) + return EXIT_FAILURE; + + /* Finalize parse */ + yasm_object_finalize(object, errwarns); + if (check_errors(errwarns, object, linemap, preproc, arch) == EXIT_FAILURE) + return EXIT_FAILURE; + + /* Optimize */ + yasm_object_optimize(object, errwarns); + if (check_errors(errwarns, object, linemap, preproc, arch) == EXIT_FAILURE) + return EXIT_FAILURE; + + /* generate any debugging information */ + yasm_dbgfmt_generate(object, linemap, errwarns); + if (check_errors(errwarns, object, linemap, preproc, arch) == EXIT_FAILURE) + return EXIT_FAILURE; + + /* open the object file for output (if not already opened by dbg objfmt) */ + if (!obj && strcmp(cur_objfmt_module->keyword, "dbg") != 0) { + obj = open_file(obj_filename, "wb"); + if (!obj) { + yasm_preproc_destroy(preproc); + yasm_object_destroy(object); + yasm_linemap_destroy(linemap); + yasm_errwarns_destroy(errwarns); + return EXIT_FAILURE; + } + } + + /* Write the object file */ + yasm_objfmt_output(object, obj?obj:stderr, + strcmp(cur_dbgfmt_module->keyword, "null"), errwarns); + + /* Close object file */ + if (obj) + fclose(obj); + + /* If we had an error at this point, we also need to delete the output + * object file (to make sure it's not left newer than the source). + */ + if (yasm_errwarns_num_errors(errwarns, warning_error) > 0) + remove(obj_filename); + if (check_errors(errwarns, object, linemap, preproc, arch) == EXIT_FAILURE) + return EXIT_FAILURE; + + /* Open and write the list file */ + if (list_filename) { + yasm_listfmt *cur_listfmt; + FILE *list = open_file(list_filename, "wt"); + if (!list) { + yasm_preproc_destroy(preproc); + yasm_object_destroy(object); + yasm_linemap_destroy(linemap); + yasm_errwarns_destroy(errwarns); + return EXIT_FAILURE; + } + /* Initialize the list format */ + cur_listfmt = yasm_listfmt_create(cur_listfmt_module, in_filename, + obj_filename); + yasm_listfmt_output(cur_listfmt, list, linemap, arch); + yasm_listfmt_destroy(cur_listfmt); + fclose(list); + } + + yasm_errwarns_output_all(errwarns, linemap, warning_error, + print_yasm_error, print_yasm_warning); + + yasm_preproc_destroy(preproc); + yasm_object_destroy(object); + yasm_linemap_destroy(linemap); + yasm_errwarns_destroy(errwarns); + + yasm_xfree(obj_filename); + yasm_xfree(map_filename); + yasm_xfree(list_filename); + return EXIT_SUCCESS; +} + +/* main function */ +/*@-globstate -unrecog@*/ +int +main(int argc, char *argv[]) +{ + size_t i; + constcharparam *infile; + + errfile = stderr; + +#if defined(HAVE_SETLOCALE) && defined(HAVE_LC_MESSAGES) + setlocale(LC_MESSAGES, ""); +#endif +#if defined(LOCALEDIR) + bindtextdomain(PACKAGE, LOCALEDIR); +#endif + textdomain(PACKAGE); + + /* Initialize errwarn handling */ + yasm_internal_error_ = handle_yasm_int_error; + yasm_fatal = handle_yasm_fatal; + yasm_gettext_hook = handle_yasm_gettext; + yasm_errwarn_initialize(); + + /* Initialize BitVector (needed for intnum/floatnum). */ + if (BitVector_Boot() != ErrCode_Ok) { + print_error(_("%s: could not initialize BitVector"), _("FATAL")); + return EXIT_FAILURE; + } + + /* Initialize intnum and floatnum */ + yasm_intnum_initialize(); + yasm_floatnum_initialize(); + +#ifdef CMAKE_BUILD + /* Load standard modules */ +#ifdef BUILD_SHARED_LIBS + if (!load_plugin("yasmstd")) { + print_error(_("%s: could not load standard modules"), _("FATAL")); + return EXIT_FAILURE; + } +#else + yasm_init_plugin(); +#endif +#endif + + /* Initialize parameter storage */ + STAILQ_INIT(&preproc_options); + STAILQ_INIT(&input_files); + + if (parse_cmdline(argc, argv, options, NELEMS(options), print_error)) + return EXIT_FAILURE; + + switch (special_options) { + case SPECIAL_SHOW_HELP: + /* Does gettext calls internally */ + help_msg(help_head, help_tail, options, NELEMS(options)); + return EXIT_SUCCESS; + case SPECIAL_SHOW_VERSION: + for (i=0; i<NELEMS(version_msg); i++) + printf("%s\n", version_msg[i]); + return EXIT_SUCCESS; + case SPECIAL_SHOW_LICENSE: + for (i=0; i<NELEMS(license_msg); i++) + printf("%s\n", license_msg[i]); + return EXIT_SUCCESS; + case SPECIAL_LISTED: + /* Printed out earlier */ + return EXIT_SUCCESS; + } + + /* Open error file if specified. */ + if (error_filename) { + int j; + errfile = open_file(error_filename, "wt"); + if (!errfile) + return EXIT_FAILURE; + + /* Print command line as first line in error file. */ + for (j=0; j<argc; j++) + fprintf(errfile, "%s%c", argv[j], (j==argc-1) ? '\n' : ' '); + } + + /* If not already specified, default to win32 as the object format. */ + if (!cur_objfmt_module) { + if (!objfmt_keyword) + objfmt_keyword = yasm__xstrdup("win32"); + cur_objfmt_module = yasm_load_objfmt(objfmt_keyword); + if (!cur_objfmt_module) { + print_error(_("%s: could not load default %s"), _("FATAL"), + _("object format")); + return EXIT_FAILURE; + } + } + + /* Default to x86 as the architecture */ + if (!cur_arch_module) { + cur_arch_module = yasm_load_arch("x86"); + if (!cur_arch_module) { + print_error(_("%s: could not load default %s"), _("FATAL"), + _("architecture")); + return EXIT_FAILURE; + } + } + + /* Check for arch help */ + if (machine_name && strcmp(machine_name, "help") == 0) { + const yasm_arch_machine *m = cur_arch_module->machines; + printf(_("Available %s for %s `%s':\n"), _("machines"), + _("architecture"), cur_arch_module->keyword); + while (m->keyword && m->name) { + print_list_keyword_desc(m->name, m->keyword); + m++; + } + return EXIT_SUCCESS; + } + + /* Default to NASM as the parser */ + if (!cur_parser_module) { + cur_parser_module = yasm_load_parser("nasm"); + if (!cur_parser_module) { + print_error(_("%s: could not load default %s"), _("FATAL"), + _("parser")); + cleanup(); + return EXIT_FAILURE; + } + } + + /* If not already specified, default to the parser's default preproc. */ + if (!cur_preproc_module) { + cur_preproc_module = + yasm_load_preproc(cur_parser_module->default_preproc_keyword); + if (!cur_preproc_module) { + print_error(_("%s: could not load default %s"), _("FATAL"), + _("preprocessor")); + cleanup(); + return EXIT_FAILURE; + } + } + + /* Determine input filenames. */ + if (STAILQ_EMPTY(&input_files)) { + print_error(_("No input files specified")); + return EXIT_FAILURE; + } + + /* If list file enabled, make sure we have a list format loaded. */ + if (listdir_pathname) { + /* If not already specified, default to nasm as the list format. */ + if (!cur_listfmt_module) { + cur_listfmt_module = yasm_load_listfmt("nasm"); + if (!cur_listfmt_module) { + print_error(_("%s: could not load default %s"), _("FATAL"), + _("list format")); + return EXIT_FAILURE; + } + } + } + + /* If not already specified, default to null as the debug format. */ + if (!cur_dbgfmt_module) { + cur_dbgfmt_module = yasm_load_dbgfmt("null"); + if (!cur_dbgfmt_module) { + print_error(_("%s: could not load default %s"), _("FATAL"), + _("debug format")); + return EXIT_FAILURE; + } + } + + /* If not already specified, output to the current directory. */ + if (!objdir_pathname) + objdir_pathname = yasm__xstrdup("./"); + else if ((i = yasm__createpath(objdir_pathname)) > 0 && + num_input_files > 1) { + objdir_pathname[i] = '/'; + objdir_pathname[i+1] = '\0'; + } + + /* Create other output directories if necessary */ + if (listdir_pathname && (i = yasm__createpath(listdir_pathname)) > 0 && + num_input_files > 1) { + listdir_pathname[i] = '/'; + listdir_pathname[i+1] = '\0'; + } + if (mapdir_pathname && (i = yasm__createpath(mapdir_pathname)) > 0 && + num_input_files > 1) { + mapdir_pathname[i] = '/'; + mapdir_pathname[i+1] = '\0'; + } + + /* If not already specified, set file extensions */ + if (!objext && cur_objfmt_module->extension) + objext = yasm__xstrdup(cur_objfmt_module->extension); + if (!listext) + listext = yasm__xstrdup("lst"); + if (!mapext) + mapext = yasm__xstrdup("map"); + + /* Assemble each input file. Terminate on first error. */ + STAILQ_FOREACH(infile, &input_files, link) + { + if (do_assemble(infile->param) == EXIT_FAILURE) { + cleanup(); + return EXIT_FAILURE; + } + } + cleanup(); + return EXIT_SUCCESS; +} +/*@=globstate =unrecog@*/ + +/* Open the object file. Returns 0 on failure. */ +static FILE * +open_file(const char *filename, const char *mode) +{ + FILE *f; + + f = fopen(filename, mode); + if (!f) + print_error(_("could not open file `%s'"), filename); + return f; +} + +static int +check_errors(yasm_errwarns *errwarns, yasm_object *object, + yasm_linemap *linemap, yasm_preproc *preproc, yasm_arch *arch) +{ + if (yasm_errwarns_num_errors(errwarns, warning_error) > 0) { + yasm_errwarns_output_all(errwarns, linemap, warning_error, + print_yasm_error, print_yasm_warning); + yasm_preproc_destroy(preproc); + yasm_object_destroy(object); + yasm_linemap_destroy(linemap); + yasm_errwarns_destroy(errwarns); + return EXIT_FAILURE; + } + return EXIT_SUCCESS; +} + +/* Define DO_FREE to 1 to enable deallocation of all data structures. + * Useful for detecting memory leaks, but slows down execution unnecessarily + * (as the OS will free everything we miss here). + */ +#define DO_FREE 1 + +/* Cleans up all allocated structures. */ +static void +cleanup(void) +{ + if (DO_FREE) { + yasm_floatnum_cleanup(); + yasm_intnum_cleanup(); + + yasm_errwarn_cleanup(); + + BitVector_Shutdown(); + } + + if (DO_FREE) { + free_input_filenames(); + if (objdir_pathname) + yasm_xfree(objdir_pathname); + if (listdir_pathname) + yasm_xfree(listdir_pathname); + if (mapdir_pathname) + yasm_xfree(mapdir_pathname); + if (objext) + yasm_xfree(objext); + if (listext) + yasm_xfree(listext); + if (mapext) + yasm_xfree(mapext); + if (machine_name) + yasm_xfree(machine_name); + if (objfmt_keyword) + yasm_xfree(objfmt_keyword); + free_preproc_saved_options(); + } + + if (errfile != stderr && errfile != stdout) + fclose(errfile); +#if defined(CMAKE_BUILD) && defined(BUILD_SHARED_LIBS) + unload_plugins(); +#endif +} + +static void +free_input_filenames(void) +{ + constcharparam *cp, *cpnext; + cp = STAILQ_FIRST(&input_files); + while (cp != NULL) { + cpnext = STAILQ_NEXT(cp, link); + yasm_xfree(cp); + cp = cpnext; + } + STAILQ_INIT(&input_files); +} + +/* + * Command line options handlers + */ +int +not_an_option_handler(char *param) +{ + constcharparam *cp; + cp = yasm_xmalloc(sizeof(constcharparam)); + cp->param = param; + cp->id = 0; + STAILQ_INSERT_TAIL(&input_files, cp, link); + ++num_input_files; + return 0; +} + +int +other_option_handler(char *option) +{ + /* Accept, but ignore, -O and -Onnn, for compatibility with NASM. */ + if (option[0] == '-' && option[1] == 'O') { + int n = 2; + for (;;) { + if (option[n] == '\0') + return 0; + if (!isdigit(option[n])) + return 1; + n++; + } + } + return 1; +} + +static int +opt_special_handler(/*@unused@*/ char *cmd, /*@unused@*/ char *param, int extra) +{ + if (special_options == 0) + special_options = extra; + return 0; +} + +static int +opt_arch_handler(/*@unused@*/ char *cmd, char *param, /*@unused@*/ int extra) +{ + assert(param != NULL); + cur_arch_module = yasm_load_arch(param); + if (!cur_arch_module) { + if (!strcmp("help", param)) { + printf(_("Available yasm %s:\n"), _("architectures")); + yasm_list_arch(print_list_keyword_desc); + special_options = SPECIAL_LISTED; + return 0; + } + print_error(_("%s: unrecognized %s `%s'"), _("FATAL"), + _("architecture"), param); + exit(EXIT_FAILURE); + } + return 0; +} + +static int +opt_parser_handler(/*@unused@*/ char *cmd, char *param, /*@unused@*/ int extra) +{ + assert(param != NULL); + cur_parser_module = yasm_load_parser(param); + if (!cur_parser_module) { + if (!strcmp("help", param)) { + printf(_("Available yasm %s:\n"), _("parsers")); + yasm_list_parser(print_list_keyword_desc); + special_options = SPECIAL_LISTED; + return 0; + } + print_error(_("%s: unrecognized %s `%s'"), _("FATAL"), _("parser"), + param); + exit(EXIT_FAILURE); + } + return 0; +} + +static int +opt_preproc_handler(/*@unused@*/ char *cmd, char *param, /*@unused@*/ int extra) +{ + assert(param != NULL); + cur_preproc_module = yasm_load_preproc(param); + if (!cur_preproc_module) { + if (!strcmp("help", param)) { + printf(_("Available yasm %s:\n"), _("preprocessors")); + yasm_list_preproc(print_list_keyword_desc); + special_options = SPECIAL_LISTED; + return 0; + } + print_error(_("%s: unrecognized %s `%s'"), _("FATAL"), + _("preprocessor"), param); + exit(EXIT_FAILURE); + } + return 0; +} + +static int +opt_objfmt_handler(/*@unused@*/ char *cmd, char *param, /*@unused@*/ int extra) +{ + size_t i; + assert(param != NULL); + cur_objfmt_module = yasm_load_objfmt(param); + if (!cur_objfmt_module) { + if (!strcmp("help", param)) { + printf(_("Available yasm %s:\n"), _("object formats")); + yasm_list_objfmt(print_list_keyword_desc); + special_options = SPECIAL_LISTED; + return 0; + } + print_error(_("%s: unrecognized %s `%s'"), _("FATAL"), + _("object format"), param); + exit(EXIT_FAILURE); + } + if (objfmt_keyword) + yasm_xfree(objfmt_keyword); + objfmt_keyword = yasm__xstrdup(param); + for (i=0; i<strlen(objfmt_keyword); i++) + objfmt_keyword[i] = tolower(objfmt_keyword[i]); + return 0; +} + +static int +opt_dbgfmt_handler(/*@unused@*/ char *cmd, char *param, /*@unused@*/ int extra) +{ + assert(param != NULL); + cur_dbgfmt_module = yasm_load_dbgfmt(param); + if (!cur_dbgfmt_module) { + if (!strcmp("help", param)) { + printf(_("Available yasm %s:\n"), _("debug formats")); + yasm_list_dbgfmt(print_list_keyword_desc); + special_options = SPECIAL_LISTED; + return 0; + } + print_error(_("%s: unrecognized %s `%s'"), _("FATAL"), + _("debug format"), param); + exit(EXIT_FAILURE); + } + return 0; +} + +static int +opt_listfmt_handler(/*@unused@*/ char *cmd, char *param, + /*@unused@*/ int extra) +{ + assert(param != NULL); + cur_listfmt_module = yasm_load_listfmt(param); + if (!cur_listfmt_module) { + if (!strcmp("help", param)) { + printf(_("Available yasm %s:\n"), _("list formats")); + yasm_list_listfmt(print_list_keyword_desc); + special_options = SPECIAL_LISTED; + return 0; + } + print_error(_("%s: unrecognized %s `%s'"), _("FATAL"), + _("list format"), param); + exit(EXIT_FAILURE); + } + return 0; +} + +static int +opt_listdir_handler(/*@unused@*/ char *cmd, char *param, + /*@unused@*/ int extra) +{ + if (listdir_pathname) { + print_error( + _("warning: can output to only one list dir, last specified used")); + yasm_xfree(listdir_pathname); + } + + assert(param != NULL); + listdir_pathname = yasm_xmalloc(strlen(param)+2); + strcpy(listdir_pathname, param); + + return 0; +} + +static int +opt_objdir_handler(/*@unused@*/ char *cmd, char *param, + /*@unused@*/ int extra) +{ + if (objdir_pathname) { + print_error( + _("warning: can output to only one object dir, last specified used")); + yasm_xfree(objdir_pathname); + } + + assert(param != NULL); + objdir_pathname = yasm_xmalloc(strlen(param)+2); + strcpy(objdir_pathname, param); + + return 0; +} + +static int +opt_mapdir_handler(/*@unused@*/ char *cmd, char *param, + /*@unused@*/ int extra) +{ + if (mapdir_pathname) { + print_error( + _("warning: can output to only one map file, last specified used")); + yasm_xfree(mapdir_pathname); + } + + assert(param != NULL); + mapdir_pathname = yasm_xmalloc(strlen(param)+2); + strcpy(mapdir_pathname, param); + + return 0; +} + +static int +opt_listext_handler(/*@unused@*/ char *cmd, char *param, + /*@unused@*/ int extra) +{ + if (listext) { + print_error( + _("warning: can set only one list extension, last specified used")); + yasm_xfree(listext); + } + assert(param != NULL); + listext = yasm__xstrdup(param); + return 0; +} + +static int +opt_objext_handler(/*@unused@*/ char *cmd, char *param, + /*@unused@*/ int extra) +{ + if (objext) { + print_error( + _("warning: can set only one object extension, last specified used")); + yasm_xfree(objext); + } + assert(param != NULL); + objext = yasm__xstrdup(param); + return 0; +} + +static int +opt_mapext_handler(/*@unused@*/ char *cmd, char *param, + /*@unused@*/ int extra) +{ + if (mapext) { + print_error( + _("warning: can set only one map extension, last specified used")); + yasm_xfree(mapext); + } + assert(param != NULL); + mapext = yasm__xstrdup(param); + return 0; +} + +static int +opt_machine_handler(/*@unused@*/ char *cmd, char *param, + /*@unused@*/ int extra) +{ + if (machine_name) + yasm_xfree(machine_name); + + assert(param != NULL); + machine_name = yasm__xstrdup(param); + + return 0; +} + +static int +opt_strict_handler(/*@unused@*/ char *cmd, + /*@unused@*/ /*@null@*/ char *param, + /*@unused@*/ int extra) +{ + force_strict = 1; + return 0; +} + +static int +opt_warning_handler(char *cmd, /*@unused@*/ char *param, int extra) +{ + /* is it disabling the warning instead of enabling? */ + void (*action)(yasm_warn_class wclass) = yasm_warn_enable; + + if (extra == 1) { + /* -w, disable warnings */ + yasm_warn_disable_all(); + return 0; + } + + /* skip past 'W' */ + cmd++; + + /* detect no- prefix to disable the warning */ + if (cmd[0] == 'n' && cmd[1] == 'o' && cmd[2] == '-') { + action = yasm_warn_disable; + cmd += 3; /* skip past it to get to the warning name */ + } + + if (cmd[0] == '\0') + /* just -W or -Wno-, so definitely not valid */ + return 1; + else if (strcmp(cmd, "error") == 0) + warning_error = (action == yasm_warn_enable); + else if (strcmp(cmd, "unrecognized-char") == 0) + action(YASM_WARN_UNREC_CHAR); + else if (strcmp(cmd, "orphan-labels") == 0) + action(YASM_WARN_ORPHAN_LABEL); + else if (strcmp(cmd, "uninit-contents") == 0) + action(YASM_WARN_UNINIT_CONTENTS); + else if (strcmp(cmd, "size-override") == 0) + action(YASM_WARN_SIZE_OVERRIDE); + else + return 1; + + return 0; +} + +static int +opt_error_file(/*@unused@*/ char *cmd, char *param, /*@unused@*/ int extra) +{ + if (error_filename) { + print_error( + _("warning: can output to only one error file, last specified used")); + yasm_xfree(error_filename); + } + + assert(param != NULL); + error_filename = yasm__xstrdup(param); + + return 0; +} + +static int +opt_error_stdout(/*@unused@*/ char *cmd, /*@unused@*/ char *param, + /*@unused@*/ int extra) +{ + /* Clear any specified error filename */ + if (error_filename) { + yasm_xfree(error_filename); + error_filename = NULL; + } + errfile = stdout; + return 0; +} + +static int +opt_include_option(/*@unused@*/ char *cmd, char *param, /*@unused@*/ int extra) +{ + yasm_add_include_path(param); + return 0; +} + +static int +opt_preproc_option(/*@unused@*/ char *cmd, char *param, int extra) +{ + constcharparam *cp; + cp = yasm_xmalloc(sizeof(constcharparam)); + cp->param = param; + cp->id = extra; + STAILQ_INSERT_TAIL(&preproc_options, cp, link); + return 0; +} + +static int +opt_ewmsg_handler(/*@unused@*/ char *cmd, char *param, /*@unused@*/ int extra) +{ + if (yasm__strcasecmp(param, "gnu") == 0 || + yasm__strcasecmp(param, "gcc") == 0) { + ewmsg_style = EWSTYLE_GNU; + } else if (yasm__strcasecmp(param, "vc") == 0) { + ewmsg_style = EWSTYLE_VC; + } else + print_error(_("warning: unrecognized message style `%s'"), param); + + return 0; +} + +static int +opt_prefix_handler(/*@unused@*/ char *cmd, char *param, /*@unused@*/ int extra) +{ + if (global_prefix) + yasm_xfree(global_prefix); + + assert(param != NULL); + global_prefix = yasm__xstrdup(param); + + return 0; +} + +static int +opt_suffix_handler(/*@unused@*/ char *cmd, char *param, /*@unused@*/ int extra) +{ + if (global_suffix) + yasm_xfree(global_suffix); + + assert(param != NULL); + global_suffix = yasm__xstrdup(param); + + return 0; +} + +#if defined(CMAKE_BUILD) && defined(BUILD_SHARED_LIBS) +static int +opt_plugin_handler(/*@unused@*/ char *cmd, char *param, + /*@unused@*/ int extra) +{ + if (!load_plugin(param)) + print_error(_("warning: could not load plugin `%s'"), param); + return 0; +} +#endif + +static void +apply_preproc_builtins(yasm_preproc *preproc) +{ + char *predef; + + /* Define standard YASM assembly-time macro constants */ + predef = yasm_xmalloc(strlen("__YASM_OBJFMT__=") + + strlen(objfmt_keyword) + 1); + strcpy(predef, "__YASM_OBJFMT__="); + strcat(predef, objfmt_keyword); + yasm_preproc_define_builtin(preproc, predef); + yasm_xfree(predef); +} + +static void +apply_preproc_standard_macros(yasm_preproc *preproc, const yasm_stdmac *stdmacs) +{ + int i, matched; + + if (!stdmacs) + return; + + matched = -1; + for (i=0; stdmacs[i].parser; i++) + if (yasm__strcasecmp(stdmacs[i].parser, + cur_parser_module->keyword) == 0 && + yasm__strcasecmp(stdmacs[i].preproc, + cur_preproc_module->keyword) == 0) + matched = i; + if (matched >= 0 && stdmacs[matched].macros) + yasm_preproc_add_standard(preproc, stdmacs[matched].macros); +} + +static void +apply_preproc_saved_options(yasm_preproc *preproc) +{ + constcharparam *cp; + + void (*funcs[3])(yasm_preproc *, const char *); + funcs[0] = cur_preproc_module->add_include_file; + funcs[1] = cur_preproc_module->predefine_macro; + funcs[2] = cur_preproc_module->undefine_macro; + + STAILQ_FOREACH(cp, &preproc_options, link) { + if (0 <= cp->id && cp->id < 3 && funcs[cp->id]) + funcs[cp->id](preproc, cp->param); + } +} + +static void +free_preproc_saved_options(void) +{ + constcharparam *cp, *cpnext; + cp = STAILQ_FIRST(&preproc_options); + while (cp != NULL) { + cpnext = STAILQ_NEXT(cp, link); + yasm_xfree(cp); + cp = cpnext; + } + STAILQ_INIT(&preproc_options); +} + +/* Replace extension on a filename (or append one if none is present). + * If output filename would be identical to input (same extension out as in), + * returns NULL. + * A NULL ext means the trailing '.' should NOT be included, whereas a "" ext + * means the trailing '.' should be included. + */ +static char * +replace_extension(const char *orig, /*@null@*/ const char *ext) +{ + char *out, *outext; + size_t outlen; + + /* allocate enough space for full existing name + extension */ + outlen = strlen(orig) + 2; + if (ext) + outlen += strlen(ext) + 1; + out = yasm_xmalloc(outlen); + + strcpy(out, orig); + outext = strrchr(out, '.'); + if (outext) { + /* Existing extension: make sure it's not the same as the replacement + * (as we don't want to overwrite the source file). + */ + outext++; /* advance past '.' */ + if (ext && strcmp(outext, ext) == 0) { + outext = NULL; /* indicate default should be used */ + print_error(_("file name already ends in `.%s'"), ext); + } + } else { + /* No extension: make sure the output extension is not empty + * (again, we don't want to overwrite the source file). + */ + if (!ext) { + outext = NULL; + print_error(_("file name already has no extension")); + } else { + outext = strrchr(out, '\0'); /* point to end of the string */ + *outext++ = '.'; /* append '.' */ + } + } + + /* replace extension or use default name */ + if (outext) { + if (!ext) { + /* Back up and replace '.' with string terminator */ + outext--; + *outext = '\0'; + } else + strcpy(outext, ext); + } else + return NULL; + + return out; +} + +void +print_list_keyword_desc(const char *name, const char *keyword) +{ + printf("%4s%-12s%s\n", "", keyword, name); +} + +static void +print_error(const char *fmt, ...) +{ + va_list va; + fprintf(errfile, "vsyasm: "); + va_start(va, fmt); + vfprintf(errfile, fmt, va); + va_end(va); + fputc('\n', errfile); +} + +static /*@exits@*/ void +handle_yasm_int_error(const char *file, unsigned int line, const char *message) +{ + fprintf(stderr, _("INTERNAL ERROR at %s, line %u: %s\n"), file, line, + gettext(message)); +#ifdef HAVE_ABORT + abort(); +#else + exit(EXIT_FAILURE); +#endif +} + +static /*@exits@*/ void +handle_yasm_fatal(const char *fmt, va_list va) +{ + fprintf(errfile, "vsyasm: %s: ", _("FATAL")); + vfprintf(errfile, gettext(fmt), va); + fputc('\n', errfile); + exit(EXIT_FAILURE); +} + +static const char * +handle_yasm_gettext(const char *msgid) +{ + return gettext(msgid); +} + +static const char *fmt[2] = { + "%s:%lu: %s%s\n", /* GNU */ + "%s(%lu) : %s%s\n" /* VC */ +}; + +static const char *fmt_noline[2] = { + "%s: %s%s\n", /* GNU */ + "%s : %s%s\n" /* VC */ +}; + +static void +print_yasm_error(const char *filename, unsigned long line, const char *msg, + const char *xref_fn, unsigned long xref_line, + const char *xref_msg) +{ + if (line) + fprintf(errfile, fmt[ewmsg_style], filename, line, _("error: "), msg); + else + fprintf(errfile, fmt_noline[ewmsg_style], filename, _("error: "), msg); + + if (xref_fn && xref_msg) { + if (xref_line) + fprintf(errfile, fmt[ewmsg_style], xref_fn, xref_line, _("error: "), + xref_msg); + else + fprintf(errfile, fmt_noline[ewmsg_style], xref_fn, _("error: "), + xref_msg); + } +} + +static void +print_yasm_warning(const char *filename, unsigned long line, const char *msg) +{ + if (line) + fprintf(errfile, fmt[ewmsg_style], filename, line, _("warning: "), + msg); + else + fprintf(errfile, fmt_noline[ewmsg_style], filename, _("warning: "), + msg); +} diff --git a/contrib/tools/yasm/frontends/yasm/license.c b/contrib/tools/yasm/frontends/yasm/license.c new file mode 100644 index 0000000000..35c5a04137 --- /dev/null +++ b/contrib/tools/yasm/frontends/yasm/license.c @@ -0,0 +1,65 @@ +/* This file auto-generated from COPYING by genstring.py - don't edit it */ + +static const char* license_msg[] = { + "Yasm is Copyright (c) 2001-2014 Peter Johnson and other Yasm developers.", + "", + "Yasm developers and/or contributors include:", + "Peter Johnson", + "Michael Urman", + "Brian Gladman (Visual Studio build files, other fixes)", + "Stanislav Karchebny (options parser)", + "Mathieu Monnier (SSE4 instruction patches, NASM preprocessor additions)", + "Anonymous \"NASM64\" developer (NASM preprocessor fixes)", + "Stephen Polkowski (x86 instruction patches)", + "Henryk Richter (Mach-O object format)", + "Ben Skeggs (patches, bug reports)", + "Alexei Svitkine (GAS preprocessor)", + "Samuel Thibault (TASM parser and frontend)", + "", + "-----------------------------------", + "Yasm licensing overview and summary", + "-----------------------------------", + "", + "Note: This document does not provide legal advice nor is it the actual", + "license of any part of Yasm. See the individual licenses for complete", + "details. Consult a lawyer for legal advice.", + "", + "The primary license of Yasm is the 2-clause BSD license. Please use this", + "license if you plan on submitting code to the project.", + "", + "Yasm has absolutely no warranty; not even for merchantibility or fitness", + "for a particular purpose.", + "", + "-------", + "Libyasm", + "-------", + "Libyasm is 2-clause or 3-clause BSD licensed, with the exception of", + "bitvect, which is triple-licensed under the Artistic license, GPL, and", + "LGPL. Libyasm is thus GPL and LGPL compatible. In addition, this also", + "means that libyasm is free for binary-only distribution as long as the", + "terms of the 3-clause BSD license and Artistic license (as it applies to", + "bitvect) are fulfilled.", + "", + "-------", + "Modules", + "-------", + "The modules are 2-clause or 3-clause BSD licensed.", + "", + "---------", + "Frontends", + "---------", + "The frontends are 2-clause BSD licensed.", + "", + "-------------", + "License Texts", + "-------------", + "The full text of all licenses are provided in separate files in the source", + "distribution. Each source file may include the entire license (in the case", + "of the BSD and Artistic licenses), or may reference the GPL or LGPL license", + "file.", + "", + "BSD.txt - 2-clause and 3-clause BSD licenses", + "Artistic.txt - Artistic license", + "GNU_GPL-2.0 - GNU General Public License", + "GNU_LGPL-2.0 - GNU Library General Public License", +}; diff --git a/contrib/tools/yasm/frontends/yasm/yasm-options.c b/contrib/tools/yasm/frontends/yasm/yasm-options.c new file mode 100644 index 0000000000..eff6ba9a00 --- /dev/null +++ b/contrib/tools/yasm/frontends/yasm/yasm-options.c @@ -0,0 +1,216 @@ +/* + * Generic Options Support Header File + * + * Copyright (c) 2001 Stanislav Karchebny <berk@madfire.net> + * + * 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. + * 3. Neither the name of the author nor the names of other contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 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 <ctype.h> + +#include "yasm-options.h" + + +#ifdef __DEBUG__ +#define DEBUG(x) fprintf ## x ; +#else +#define DEBUG(x) +#endif + + +/* Options Parser */ +int +parse_cmdline(int argc, char **argv, opt_option *options, size_t nopts, + void (*print_error) (const char *fmt, ...)) +{ + int errors = 0, warnings = 0; + size_t i; + int got_it; + + DEBUG((stderr, "parse_cmdline: entered\n")); + + fail: + while (--argc) { + argv++; + + if (argv[0][0] == '-') { /* opt */ + got_it = 0; + if (argv[0][1] == '-') { /* lopt */ + if (argv[0][2] == '\0') { /* --, end of options */ + /* Handle rest of args as non-options */ + while (--argc) { + argv++; + if (not_an_option_handler(argv[0])) + errors++; + } + return errors; + } + + for (i = 0; i < nopts; i++) { + size_t optlen; + if (options[i].lopt && + strncmp(&argv[0][2], options[i].lopt, + (optlen = strlen(options[i].lopt))) == 0) { + char *param; + char c = argv[0][2 + optlen]; + + if (c != '\0' && c != '=' && !isspace(c)) + continue; + + if (options[i].takes_param) { + param = strchr(&argv[0][2], '='); + if (!param) { + print_error( + _("option `--%s' needs an argument!"), + options[i].lopt); + errors++; + goto fail; + } else { + *param = '\0'; + param++; + } + } else + param = NULL; + + if (!options[i]. + handler(&argv[0][2], param, options[i].extra)) + got_it = 1; + break; + } + } + if (!got_it && !other_option_handler(argv[0])) + got_it = 1; + if (!got_it) { + print_error(_("warning: unrecognized option `%s'"), + argv[0]); + warnings++; + } + } else if (argv[0][1] == '\0') { /* just -, is non-option */ + if (not_an_option_handler(argv[0])) + errors++; + } else { /* sopt */ + for (i = 0; i < nopts; i++) { + if (argv[0][1] == options[i].sopt) { + char *cmd = &argv[0][1]; + char *param; + + if (options[i].takes_param) { + param = argv[1]; + if (argv[0][2] != '\0') + param = &argv[0][2]; + else if (param == NULL || *param == '-') { + print_error( + _("option `-%c' needs an argument!"), + options[i].sopt); + errors++; + goto fail; + } else { + argc--; + argv++; + } + } else + param = NULL; + + if (!options[i].handler(cmd, param, options[i].extra)) + got_it = 1; + break; + } + } + if (!got_it && !other_option_handler(argv[0])) + got_it = 1; + if (!got_it) { + print_error(_("warning: unrecognized option `%s'"), + argv[0]); + warnings++; + } + } + } else { /* not an option, then it should be a file or something */ + + if (not_an_option_handler(argv[0])) + errors++; + } + } + + DEBUG((stderr, "parse_cmdline: finished\n")); + return errors; +} + +void +help_msg(const char *msg, const char *tail, opt_option *options, size_t nopts) +{ + char optbuf[100], optopt[100]; + size_t i; + + printf("%s", gettext(msg)); + + for (i = 0; i < nopts; i++) { + size_t shortopt_len = 0; + size_t longopt_len = 0; + + optbuf[0] = 0; + optopt[0] = 0; + + if (options[i].takes_param) { + if (options[i].sopt) { + sprintf(optbuf, "-%c <%s>", options[i].sopt, + options[i].param_desc ? options[i]. + param_desc : _("param")); + shortopt_len = strlen(optbuf); + } + if (options[i].sopt && options[i].lopt) + strcat(optbuf, ", "); + if (options[i].lopt) { + sprintf(optopt, "--%s=<%s>", options[i].lopt, + options[i].param_desc ? options[i]. + param_desc : _("param")); + strcat(optbuf, optopt); + longopt_len = strlen(optbuf); + } + } else { + if (options[i].sopt) { + sprintf(optbuf, "-%c", options[i].sopt); + shortopt_len = strlen(optbuf); + } + if (options[i].sopt && options[i].lopt) + strcat(optbuf, ", "); + if (options[i].lopt) { + sprintf(optopt, "--%s", options[i].lopt); + strcat(optbuf, optopt); + longopt_len = strlen(optbuf); + } + } + + /* split [-s <desc>], [--long <desc>] if it destroys columns */ + if (shortopt_len && longopt_len && longopt_len > 22) { + optbuf[shortopt_len] = '\0'; + printf(" %-22s %s\n", optopt, gettext(options[i].description)); + printf(" %s\n", optbuf); + } + else + printf(" %-22s %s\n", optbuf, gettext(options[i].description)); + } + + printf("%s", gettext(tail)); +} diff --git a/contrib/tools/yasm/frontends/yasm/yasm-options.h b/contrib/tools/yasm/frontends/yasm/yasm-options.h new file mode 100644 index 0000000000..63c4fbeae1 --- /dev/null +++ b/contrib/tools/yasm/frontends/yasm/yasm-options.h @@ -0,0 +1,75 @@ +/* + * Generic Options Support Header File + * + * Copyright (c) 2001 Stanislav Karchebny <berk@madfire.net> + * + * 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_OPTIONS_H +#define YASM_OPTIONS_H + +/* an option structure + * operate on either -sopt, --lopt, -sopt <val> or --lopt=<val> + */ +typedef struct opt_option_s +{ + /* short option letter if present, 0 otherwise */ + char sopt; + + /* long option name if present, NULL otherwise */ + /*@null@*/ const char *lopt; + + /* !=0 if option requires parameter, 0 if not */ + int takes_param; + + int (*handler) (char *cmd, /*@null@*/ char *param, int extra); + int extra; /* extra value for handler */ + + /* description to use in help_msg() */ + /*@observer@*/ const char *description; + + /* optional description for the param taken (NULL if not present) */ + /* (short - will be printed after option sopt/lopt) */ + /*@observer@*/ /*@null@*/ const char *param_desc; +} opt_option; + +/* handle everything that is not an option */ +int not_an_option_handler(char *param); + +/* handle possibly other special-case options; no parameters allowed */ +int other_option_handler(char *option); + +/* parse command line calling handlers when appropriate + * argc, argv - pass directly from main(argc,argv) + * options - array of options + * nopts - options count + */ +int parse_cmdline(int argc, char **argv, opt_option *options, size_t nopts, + void (*print_error) (const char *fmt, ...)); + +/* display help message msg followed by list of options in options and followed + * by tail + */ +void help_msg(const char *msg, const char *tail, opt_option *options, + size_t nopts); + +#endif diff --git a/contrib/tools/yasm/frontends/yasm/yasm-plugin.c b/contrib/tools/yasm/frontends/yasm/yasm-plugin.c new file mode 100644 index 0000000000..c64edc32f0 --- /dev/null +++ b/contrib/tools/yasm/frontends/yasm/yasm-plugin.c @@ -0,0 +1,126 @@ +/* + * Semi-portable (Windows and Unix) plugin loading + * + * Copyright (C) 2008 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 <string.h> + +#include "libyasm-stdint.h" +#include "yasm-plugin.h" + +#if defined(_MSC_VER) +#include <windows.h> +#elif defined(__GNUC__) +#include <dlfcn.h> +#endif + +static void **loaded_plugins = NULL; +static int num_loaded_plugins = 0; + +static void * +load_dll(const char *name) +{ +#if defined(_MSC_VER) + return LoadLibrary(name); +#elif defined(__GNUC__) + return dlopen(name, RTLD_NOW); +#else + return NULL; +#endif +} + +int +load_plugin(const char *name) +{ + char *path; + void *lib = NULL; + void (*init_plugin) (void) = NULL; + + /* Load library */ + + path = yasm_xmalloc(strlen(name)+10); +#if defined(_MSC_VER) + strcpy(path, name); + strcat(path, ".dll"); + lib = load_dll(path); +#elif defined(__GNUC__) + strcpy(path, "lib"); + strcat(path, name); + strcat(path, ".so"); + lib = load_dll(path); + if (!lib) { + strcpy(path, name); + strcat(path, ".so"); + lib = load_dll(path); + } +#endif + yasm_xfree(path); + if (!lib) + lib = load_dll(name); + + if (!lib) + return 0; /* Didn't load successfully */ + + /* Add to array of loaded plugins */ + loaded_plugins = + yasm_xrealloc(loaded_plugins, (num_loaded_plugins+1)*sizeof(void *)); + loaded_plugins[num_loaded_plugins] = lib; + num_loaded_plugins++; + + /* Get yasm_init_plugin() function and run it */ + +#if defined(_MSC_VER) + init_plugin = + (void (*)(void))GetProcAddress((HINSTANCE)lib, "yasm_init_plugin"); +#elif defined(__GNUC__) + init_plugin = (void (*)(void))(uintptr_t)dlsym(lib, "yasm_init_plugin"); +#endif + + if (!init_plugin) + return 0; /* Didn't load successfully */ + + init_plugin(); + return 1; +} + +void +unload_plugins(void) +{ + int i; + + if (!loaded_plugins) + return; + + for (i = 0; i < num_loaded_plugins; i++) { +#if defined(_MSC_VER) + FreeLibrary((HINSTANCE)loaded_plugins[i]); +#elif defined(__GNUC__) + dlclose(loaded_plugins[i]); +#endif + } + yasm_xfree(loaded_plugins); + num_loaded_plugins = 0; +} diff --git a/contrib/tools/yasm/frontends/yasm/yasm-plugin.h b/contrib/tools/yasm/frontends/yasm/yasm-plugin.h new file mode 100644 index 0000000000..efb1bf513a --- /dev/null +++ b/contrib/tools/yasm/frontends/yasm/yasm-plugin.h @@ -0,0 +1,34 @@ +/* + * Semi-portable (Windows and Unix) plugin loading + * + * Copyright (C) 2008 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_PLUGIN_H +#define YASM_PLUGIN_H + +/* Load a plugin. Returns 0 on failure. */ +int load_plugin(const char *name); +void unload_plugins(void); + +#endif diff --git a/contrib/tools/yasm/frontends/yasm/yasm.c b/contrib/tools/yasm/frontends/yasm/yasm.c new file mode 100644 index 0000000000..2bd08890df --- /dev/null +++ b/contrib/tools/yasm/frontends/yasm/yasm.c @@ -0,0 +1,1454 @@ +/* + * Program entry point, command line parsing + * + * 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 <ctype.h> +#include <libyasm/compat-queue.h> +#include <libyasm/bitvect.h> +#include <libyasm.h> + +#ifdef HAVE_LIBGEN_H +#include <libgen.h> +#endif + +#include "yasm-options.h" + +#if defined(CMAKE_BUILD) && defined(BUILD_SHARED_LIBS) +#include "yasm-plugin.h" +#endif + +#include "license.c" + +/* Preprocess-only buffer size */ +#define PREPROC_BUF_SIZE 16384 + +/*@null@*/ /*@only@*/ static char *obj_filename = NULL, *in_filename = NULL; +/*@null@*/ /*@only@*/ static char *global_prefix = NULL, *global_suffix = NULL; +/*@null@*/ /*@only@*/ static char *list_filename = NULL, *map_filename = NULL; +/*@null@*/ /*@only@*/ static char *machine_name = NULL; +static char **replace_params; +static int replace_size = 0; +static int replace_capacity = 0; +static int special_options = 0; +/*@null@*/ /*@dependent@*/ static yasm_arch *cur_arch = NULL; +/*@null@*/ /*@dependent@*/ static const yasm_arch_module * + cur_arch_module = NULL; +/*@null@*/ /*@dependent@*/ static const yasm_parser_module * + cur_parser_module = NULL; +/*@null@*/ /*@dependent@*/ static yasm_preproc *cur_preproc = NULL; +/*@null@*/ /*@dependent@*/ static const yasm_preproc_module * + cur_preproc_module = NULL; +/*@null@*/ static char *objfmt_keyword = NULL; +/*@null@*/ /*@dependent@*/ static const yasm_objfmt_module * + cur_objfmt_module = NULL; +/*@null@*/ /*@dependent@*/ static const yasm_dbgfmt_module * + cur_dbgfmt_module = NULL; +/*@null@*/ /*@dependent@*/ static yasm_listfmt *cur_listfmt = NULL; +/*@null@*/ /*@dependent@*/ static const yasm_listfmt_module * + cur_listfmt_module = NULL; +static int preproc_only = 0; +static unsigned int force_strict = 0; +static int generate_make_dependencies = 0; +static int warning_error = 0; /* warnings being treated as errors */ +static FILE *errfile; +/*@null@*/ /*@only@*/ static char *error_filename = NULL; +static enum { + EWSTYLE_GNU = 0, + EWSTYLE_VC +} ewmsg_style = EWSTYLE_GNU; + +/*@null@*/ /*@dependent@*/ static FILE *open_file(const char *filename, + const char *mode); +static void check_errors(/*@only@*/ yasm_errwarns *errwarns, + /*@only@*/ yasm_object *object, + /*@only@*/ yasm_linemap *linemap); +static void cleanup(/*@null@*/ /*@only@*/ yasm_object *object); + +/* Forward declarations: cmd line parser handlers */ +static int opt_special_handler(char *cmd, /*@null@*/ char *param, int extra); +static int opt_arch_handler(char *cmd, /*@null@*/ char *param, int extra); +static int opt_parser_handler(char *cmd, /*@null@*/ char *param, int extra); +static int opt_preproc_handler(char *cmd, /*@null@*/ char *param, int extra); +static int opt_objfmt_handler(char *cmd, /*@null@*/ char *param, int extra); +static int opt_dbgfmt_handler(char *cmd, /*@null@*/ char *param, int extra); +static int opt_listfmt_handler(char *cmd, /*@null@*/ char *param, int extra); +static int opt_listfile_handler(char *cmd, /*@null@*/ char *param, int extra); +static int opt_objfile_handler(char *cmd, /*@null@*/ char *param, int extra); +static int opt_mapfile_handler(char *cmd, /*@null@*/ char *param, int extra); +static int opt_machine_handler(char *cmd, /*@null@*/ char *param, int extra); +static int opt_strict_handler(char *cmd, /*@null@*/ char *param, int extra); +static int opt_warning_handler(char *cmd, /*@null@*/ char *param, int extra); +static int opt_error_file(char *cmd, /*@null@*/ char *param, int extra); +static int opt_error_stdout(char *cmd, /*@null@*/ char *param, int extra); +static int preproc_only_handler(char *cmd, /*@null@*/ char *param, int extra); +static int opt_include_option(char *cmd, /*@null@*/ char *param, int extra); +static int opt_preproc_option(char *cmd, /*@null@*/ char *param, int extra); +static int opt_ewmsg_handler(char *cmd, /*@null@*/ char *param, int extra); +static int opt_makedep_handler(char *cmd, /*@null@*/ char *param, int extra); +static int opt_prefix_handler(char *cmd, /*@null@*/ char *param, int extra); +static int opt_replace_handler(char *cmd, /*@null@*/ char *param, int extra); +static int opt_suffix_handler(char *cmd, /*@null@*/ char *param, int extra); +#if defined(CMAKE_BUILD) && defined(BUILD_SHARED_LIBS) +static int opt_plugin_handler(char *cmd, /*@null@*/ char *param, int extra); +#endif + +#if defined(CMAKE_BUILD) && !defined(BUILD_SHARED_LIBS) +void yasm_init_plugin(void); +void yasm_plugin_set_replace(const char* replace[], int size); +#endif + +static /*@only@*/ char *replace_extension(const char *orig, /*@null@*/ + const char *ext, const char *def); +static void print_error(const char *fmt, ...); + +static /*@exits@*/ void handle_yasm_int_error(const char *file, + unsigned int line, + const char *message); +static /*@exits@*/ void handle_yasm_fatal(const char *message, va_list va); +static const char *handle_yasm_gettext(const char *msgid); +static void print_yasm_error(const char *filename, unsigned long line, + const char *msg, /*@null@*/ const char *xref_fn, + unsigned long xref_line, + /*@null@*/ const char *xref_msg); +static void print_yasm_warning(const char *filename, unsigned long line, + const char *msg); + +static void apply_preproc_builtins(void); +static void apply_preproc_standard_macros(const yasm_stdmac *stdmacs); +static void apply_preproc_saved_options(void); +static void print_list_keyword_desc(const char *name, const char *keyword); + +/* values for special_options */ +#define SPECIAL_SHOW_HELP 0x01 +#define SPECIAL_SHOW_VERSION 0x02 +#define SPECIAL_SHOW_LICENSE 0x04 +#define SPECIAL_LISTED 0x08 + +/* command line options */ +static opt_option options[] = +{ + { 0, "version", 0, opt_special_handler, SPECIAL_SHOW_VERSION, + N_("show version text"), NULL }, + { 0, "license", 0, opt_special_handler, SPECIAL_SHOW_LICENSE, + N_("show license text"), NULL }, + { 'h', "help", 0, opt_special_handler, SPECIAL_SHOW_HELP, + N_("show help text"), NULL }, + { 'a', "arch", 1, opt_arch_handler, 0, + N_("select architecture (list with -a help)"), N_("arch") }, + { 'p', "parser", 1, opt_parser_handler, 0, + N_("select parser (list with -p help)"), N_("parser") }, + { 'r', "preproc", 1, opt_preproc_handler, 0, + N_("select preprocessor (list with -r help)"), N_("preproc") }, + { 'f', "oformat", 1, opt_objfmt_handler, 0, + N_("select object format (list with -f help)"), N_("format") }, + { 'g', "dformat", 1, opt_dbgfmt_handler, 0, + N_("select debugging format (list with -g help)"), N_("debug") }, + { 'L', "lformat", 1, opt_listfmt_handler, 0, + N_("select list format (list with -L help)"), N_("list") }, + { 'l', "list", 1, opt_listfile_handler, 0, + N_("name of list-file output"), N_("listfile") }, + { 'o', "objfile", 1, opt_objfile_handler, 0, + N_("name of object-file output"), N_("filename") }, + { 0, "mapfile", 1, opt_mapfile_handler, 0, + N_("name of map-file output"), N_("filename") }, + { 'm', "machine", 1, opt_machine_handler, 0, + N_("select machine (list with -m help)"), N_("machine") }, + { 0, "force-strict", 0, opt_strict_handler, 0, + N_("treat all sized operands as if `strict' was used"), NULL }, + { 'w', NULL, 0, opt_warning_handler, 1, + N_("inhibits warning messages"), NULL }, + { 'W', NULL, 0, opt_warning_handler, 0, + N_("enables/disables warning"), NULL }, + { 'M', NULL, 0, opt_makedep_handler, 0, + N_("generate Makefile dependencies on stdout"), NULL }, + { 'E', NULL, 1, opt_error_file, 0, + N_("redirect error messages to file"), N_("file") }, + { 's', NULL, 0, opt_error_stdout, 0, + N_("redirect error messages to stdout"), NULL }, + { 'e', "preproc-only", 0, preproc_only_handler, 0, + N_("preprocess only (writes output to stdout by default)"), NULL }, + { 'i', NULL, 1, opt_include_option, 0, + N_("add include path"), N_("path") }, + { 'I', NULL, 1, opt_include_option, 0, + N_("add include path"), N_("path") }, + { 'P', NULL, 1, opt_preproc_option, 0, + N_("pre-include file"), N_("filename") }, + { 'd', NULL, 1, opt_preproc_option, 1, + N_("pre-define a macro, optionally to value"), N_("macro[=value]") }, + { 'D', NULL, 1, opt_preproc_option, 1, + N_("pre-define a macro, optionally to value"), N_("macro[=value]") }, + { 'u', NULL, 1, opt_preproc_option, 2, + N_("undefine a macro"), N_("macro") }, + { 'U', NULL, 1, opt_preproc_option, 2, + N_("undefine a macro"), N_("macro") }, + { 'X', NULL, 1, opt_ewmsg_handler, 0, + N_("select error/warning message style (`gnu' or `vc')"), N_("style") }, + { 0, "prefix", 1, opt_prefix_handler, 0, + N_("prepend argument to name of all external symbols"), N_("prefix") }, + { 0, "suffix", 1, opt_suffix_handler, 0, + N_("append argument to name of all external symbols"), N_("suffix") }, + { 0, "postfix", 1, opt_suffix_handler, 0, + N_("append argument to name of all external symbols"), N_("suffix") }, +#if defined(CMAKE_BUILD) && defined(BUILD_SHARED_LIBS) + { 'N', "plugin", 1, opt_plugin_handler, 0, + N_("load plugin module"), N_("plugin") }, +#endif + { 0, "replace", 1, opt_replace_handler, 0, + N_("replace names"), N_("replace") }, +}; + +/* version message */ +/*@observer@*/ static const char *version_msg[] = { + PACKAGE_STRING, + "Compiled on " __DATE__ ".", + "Copyright (c) 2001-2014 Peter Johnson and other Yasm developers.", + "Run yasm --license for licensing overview and summary." +}; + +/* help messages */ +/*@observer@*/ static const char *help_head = N_( + "usage: yasm [option]* file\n" + "Options:\n"); +/*@observer@*/ static const char *help_tail = N_( + "\n" + "Files are asm sources to be assembled.\n" + "\n" + "Sample invocation:\n" + " yasm -f elf -o object.o source.asm\n" + "\n" + "Report bugs to bug-yasm@tortall.net\n"); + +/* parsed command line storage until appropriate modules have been loaded */ +typedef STAILQ_HEAD(constcharparam_head, constcharparam) constcharparam_head; + +typedef struct constcharparam { + STAILQ_ENTRY(constcharparam) link; + const char *param; + int id; +} constcharparam; + +static constcharparam_head preproc_options; + +static int +do_preproc_only(void) +{ + yasm_linemap *linemap; + char *preproc_buf; + size_t got; + const char *base_filename; + FILE *out = NULL; + yasm_errwarns *errwarns = yasm_errwarns_create(); + + /* Initialize line map */ + linemap = yasm_linemap_create(); + yasm_linemap_set(linemap, in_filename, 0, 1, 1); + + /* Default output to stdout if not specified or generating dependency + makefiles */ + if (!obj_filename || generate_make_dependencies) { + out = stdout; + + /* determine the object filename if not specified, but we need a + file name for the makefile rule */ + if (generate_make_dependencies && !obj_filename) { + if (in_filename == NULL) + /* Default to yasm.out if no obj filename specified */ + obj_filename = yasm__xstrdup("yasm.out"); + else { + /* replace (or add) extension to base filename */ + yasm__splitpath(in_filename, &base_filename); + if (base_filename[0] == '\0') + obj_filename = yasm__xstrdup("yasm.out"); + else + obj_filename = replace_extension(base_filename, + cur_objfmt_module->extension, "yasm.out"); + } + } + } else { + /* Open output (object) file */ + out = open_file(obj_filename, "wt"); + if (!out) + return EXIT_FAILURE; + } + + /* Create preprocessor */ + cur_preproc = yasm_preproc_create(cur_preproc_module, in_filename, NULL, + linemap, errwarns); + + /* Apply macros */ + apply_preproc_builtins(); + apply_preproc_standard_macros(cur_parser_module->stdmacs); + apply_preproc_standard_macros(cur_objfmt_module->stdmacs); + apply_preproc_saved_options(); + + /* Pre-process until done */ + if (generate_make_dependencies) { + size_t totlen; + + preproc_buf = yasm_xmalloc(PREPROC_BUF_SIZE); + + fprintf(stdout, "%s: %s", obj_filename, in_filename); + totlen = strlen(obj_filename)+2+strlen(in_filename); + + while ((got = yasm_preproc_get_included_file(cur_preproc, preproc_buf, + PREPROC_BUF_SIZE)) != 0) { + totlen += got; + if (totlen > 72) { + fputs(" \\\n ", stdout); + totlen = 2; + } + fputc(' ', stdout); + fwrite(preproc_buf, got, 1, stdout); + } + fputc('\n', stdout); + yasm_xfree(preproc_buf); + } else { + while ((preproc_buf = yasm_preproc_get_line(cur_preproc)) != NULL) { + fputs(preproc_buf, out); + fputc('\n', out); + yasm_xfree(preproc_buf); + } + } + + if (out != stdout) + fclose(out); + + if (yasm_errwarns_num_errors(errwarns, warning_error) > 0) { + yasm_errwarns_output_all(errwarns, linemap, warning_error, + print_yasm_error, print_yasm_warning); + if (out != stdout) + remove(obj_filename); + yasm_linemap_destroy(linemap); + yasm_errwarns_destroy(errwarns); + cleanup(NULL); + return EXIT_FAILURE; + } + + yasm_errwarns_output_all(errwarns, linemap, warning_error, + print_yasm_error, print_yasm_warning); + yasm_linemap_destroy(linemap); + yasm_errwarns_destroy(errwarns); + cleanup(NULL); + return EXIT_SUCCESS; +} + +static int +do_assemble(void) +{ + yasm_object *object; + const char *base_filename; + /*@null@*/ FILE *obj = NULL; + yasm_arch_create_error arch_error; + yasm_linemap *linemap; + yasm_errwarns *errwarns = yasm_errwarns_create(); + int i, matched; + const char *machine; + + /* Initialize line map */ + linemap = yasm_linemap_create(); + yasm_linemap_set(linemap, in_filename, 0, 1, 1); + + /* determine the object filename if not specified */ + if (!obj_filename) { + if (in_filename == NULL) + /* Default to yasm.out if no obj filename specified */ + obj_filename = yasm__xstrdup("yasm.out"); + else { + /* replace (or add) extension to base filename */ + yasm__splitpath(in_filename, &base_filename); + if (base_filename[0] == '\0') + obj_filename = yasm__xstrdup("yasm.out"); + else + obj_filename = replace_extension(base_filename, + cur_objfmt_module->extension, + "yasm.out"); + } + } + + /* Set up architecture using machine and parser. */ + if (!machine_name) { + /* If we're using x86 and the default objfmt bits is 64, default the + * machine to amd64. When we get more arches with multiple machines, + * we should do this in a more modular fashion. + */ + if (strcmp(cur_arch_module->keyword, "x86") == 0 && + cur_objfmt_module->default_x86_mode_bits == 64) + machine_name = yasm__xstrdup("amd64"); + else + machine_name = + yasm__xstrdup(cur_arch_module->default_machine_keyword); + } + + /* If we're using amd64 and the default objfmt is elfx32, change the + * machine to "x32". + */ + if (strcmp(machine_name, "amd64") == 0 && + strcmp(cur_objfmt_module->keyword, "elfx32") == 0) + machine = "x32"; + else + machine = machine_name; + + cur_arch = yasm_arch_create(cur_arch_module, machine, + cur_parser_module->keyword, &arch_error); + if (!cur_arch) { + switch (arch_error) { + case YASM_ARCH_CREATE_BAD_MACHINE: + print_error(_("%s: `%s' is not a valid %s for %s `%s'"), + _("FATAL"), machine_name, _("machine"), + _("architecture"), cur_arch_module->keyword); + break; + case YASM_ARCH_CREATE_BAD_PARSER: + print_error(_("%s: `%s' is not a valid %s for %s `%s'"), + _("FATAL"), cur_parser_module->keyword, + _("parser"), _("architecture"), + cur_arch_module->keyword); + break; + default: + print_error(_("%s: unknown architecture error"), _("FATAL")); + } + + return EXIT_FAILURE; + } + + /* Create object */ + object = yasm_object_create(in_filename, obj_filename, cur_arch, + cur_objfmt_module, cur_dbgfmt_module); + if (!object) { + yasm_error_class eclass; + unsigned long xrefline; + /*@only@*/ /*@null@*/ char *estr, *xrefstr; + + yasm_error_fetch(&eclass, &estr, &xrefline, &xrefstr); + print_error("%s: %s", _("FATAL"), estr); + yasm_xfree(estr); + yasm_xfree(xrefstr); + + cleanup(object); + return EXIT_FAILURE; + } + + /* Get a fresh copy of objfmt_module as it may have changed. */ + cur_objfmt_module = ((yasm_objfmt_base *)object->objfmt)->module; + + /* Check to see if the requested preprocessor is in the allowed list + * for the active parser. + */ + matched = 0; + for (i=0; cur_parser_module->preproc_keywords[i]; i++) + { + if (yasm__strcasecmp(cur_parser_module->preproc_keywords[i], + cur_preproc_module->keyword) == 0) { + matched = 1; + break; + } + } + + if (!matched) { + print_error(_("%s: `%s' is not a valid %s for %s `%s'"), _("FATAL"), + cur_preproc_module->keyword, _("preprocessor"), + _("parser"), cur_parser_module->keyword); + cleanup(object); + return EXIT_FAILURE; + } + + if (global_prefix) + yasm_object_set_global_prefix(object, global_prefix); + if (global_suffix) + yasm_object_set_global_suffix(object, global_suffix); + + cur_preproc = yasm_preproc_create(cur_preproc_module, in_filename, + object->symtab, linemap, errwarns); + + apply_preproc_builtins(); + apply_preproc_standard_macros(cur_parser_module->stdmacs); + apply_preproc_standard_macros(cur_objfmt_module->stdmacs); + apply_preproc_saved_options(); + + /* Get initial x86 BITS setting from object format */ + if (strcmp(cur_arch_module->keyword, "x86") == 0) { + yasm_arch_set_var(cur_arch, "mode_bits", + cur_objfmt_module->default_x86_mode_bits); + } + + yasm_arch_set_var(cur_arch, "force_strict", force_strict); + + /* Try to enable the map file via a map NASM directive. This is + * somewhat of a hack. + */ + if (map_filename) { + const yasm_directive *dir = &cur_objfmt_module->directives[0]; + matched = 0; + for (; dir && dir->name; dir++) { + if (yasm__strcasecmp(dir->name, "map") == 0 && + yasm__strcasecmp(dir->parser, "nasm") == 0) { + yasm_valparamhead vps; + yasm_valparam *vp; + matched = 1; + yasm_vps_initialize(&vps); + vp = yasm_vp_create_string(NULL, yasm__xstrdup(map_filename)); + yasm_vps_append(&vps, vp); + dir->handler(object, &vps, NULL, 0); + yasm_vps_delete(&vps); + } + } + if (!matched) { + print_error( + _("warning: object format `%s' does not support map files"), + cur_objfmt_module->keyword); + } + } + + /* Parse! */ + cur_parser_module->do_parse(object, cur_preproc, list_filename != NULL, + linemap, errwarns); + + check_errors(errwarns, object, linemap); + + /* Finalize parse */ + yasm_object_finalize(object, errwarns); + check_errors(errwarns, object, linemap); + + /* Optimize */ + yasm_object_optimize(object, errwarns); + check_errors(errwarns, object, linemap); + + /* generate any debugging information */ + yasm_dbgfmt_generate(object, linemap, errwarns); + check_errors(errwarns, object, linemap); + + /* open the object file for output (if not already opened by dbg objfmt) */ + if (!obj && strcmp(cur_objfmt_module->keyword, "dbg") != 0) { + obj = open_file(obj_filename, "wb"); + if (!obj) { + cleanup(object); + return EXIT_FAILURE; + } + } + + /* Write the object file */ + yasm_objfmt_output(object, obj?obj:stderr, + strcmp(cur_dbgfmt_module->keyword, "null"), errwarns); + + /* Close object file */ + if (obj) + fclose(obj); + + /* If we had an error at this point, we also need to delete the output + * object file (to make sure it's not left newer than the source). + */ + if (yasm_errwarns_num_errors(errwarns, warning_error) > 0) + remove(obj_filename); + check_errors(errwarns, object, linemap); + + /* Open and write the list file */ + if (list_filename) { + FILE *list = open_file(list_filename, "wt"); + if (!list) { + cleanup(object); + return EXIT_FAILURE; + } + /* Initialize the list format */ + cur_listfmt = yasm_listfmt_create(cur_listfmt_module, in_filename, + obj_filename); + yasm_listfmt_output(cur_listfmt, list, linemap, cur_arch); + fclose(list); + } + + yasm_errwarns_output_all(errwarns, linemap, warning_error, + print_yasm_error, print_yasm_warning); + + yasm_linemap_destroy(linemap); + yasm_errwarns_destroy(errwarns); + cleanup(object); + return EXIT_SUCCESS; +} + +/* main function */ +/*@-globstate -unrecog@*/ +int +main(int argc, char *argv[]) +{ + size_t i; + + errfile = stderr; + +#if defined(HAVE_SETLOCALE) && defined(HAVE_LC_MESSAGES) + setlocale(LC_MESSAGES, ""); +#endif +#if defined(LOCALEDIR) + bindtextdomain(PACKAGE, LOCALEDIR); +#endif + textdomain(PACKAGE); + + /* Initialize errwarn handling */ + yasm_internal_error_ = handle_yasm_int_error; + yasm_fatal = handle_yasm_fatal; + yasm_gettext_hook = handle_yasm_gettext; + yasm_errwarn_initialize(); + + /* Initialize BitVector (needed for intnum/floatnum). */ + if (BitVector_Boot() != ErrCode_Ok) { + print_error(_("%s: could not initialize BitVector"), _("FATAL")); + return EXIT_FAILURE; + } + + /* Initialize intnum and floatnum */ + yasm_intnum_initialize(); + yasm_floatnum_initialize(); + +#ifdef CMAKE_BUILD + /* Load standard modules */ +#ifdef BUILD_SHARED_LIBS + if (!load_plugin("yasmstd")) { + print_error(_("%s: could not load standard modules"), _("FATAL")); + return EXIT_FAILURE; + } +#else + yasm_init_plugin(); +#endif +#endif + + /* Initialize parameter storage */ + STAILQ_INIT(&preproc_options); + + if (parse_cmdline(argc, argv, options, NELEMS(options), print_error)) + return EXIT_FAILURE; + + switch (special_options) { + case SPECIAL_SHOW_HELP: + /* Does gettext calls internally */ + help_msg(help_head, help_tail, options, NELEMS(options)); + return EXIT_SUCCESS; + case SPECIAL_SHOW_VERSION: + for (i=0; i<NELEMS(version_msg); i++) + printf("%s\n", version_msg[i]); + return EXIT_SUCCESS; + case SPECIAL_SHOW_LICENSE: + for (i=0; i<NELEMS(license_msg); i++) + printf("%s\n", license_msg[i]); + return EXIT_SUCCESS; + case SPECIAL_LISTED: + /* Printed out earlier */ + return EXIT_SUCCESS; + } + + /* Open error file if specified. */ + if (error_filename) { + errfile = open_file(error_filename, "wt"); + if (!errfile) + return EXIT_FAILURE; + } + +#if defined(CMAKE_BUILD) && !defined(BUILD_SHARED_LIBS) + yasm_plugin_set_replace(replace_params, replace_size); +#endif + + /* If not already specified, default to bin as the object format. */ + if (!cur_objfmt_module) { + if (!objfmt_keyword) + objfmt_keyword = yasm__xstrdup("bin"); + cur_objfmt_module = yasm_load_objfmt(objfmt_keyword); + if (!cur_objfmt_module) { + print_error(_("%s: could not load default %s"), _("FATAL"), + _("object format")); + return EXIT_FAILURE; + } + } + + /* Default to x86 as the architecture */ + if (!cur_arch_module) { + cur_arch_module = yasm_load_arch("x86"); + if (!cur_arch_module) { + print_error(_("%s: could not load default %s"), _("FATAL"), + _("architecture")); + return EXIT_FAILURE; + } + } + + /* Check for arch help */ + if (machine_name && strcmp(machine_name, "help") == 0) { + const yasm_arch_machine *m = cur_arch_module->machines; + printf(_("Available %s for %s `%s':\n"), _("machines"), + _("architecture"), cur_arch_module->keyword); + while (m->keyword && m->name) { + print_list_keyword_desc(m->name, m->keyword); + m++; + } + return EXIT_SUCCESS; + } + + /* Default to NASM as the parser */ + if (!cur_parser_module) { + cur_parser_module = yasm_load_parser("nasm"); + if (!cur_parser_module) { + print_error(_("%s: could not load default %s"), _("FATAL"), + _("parser")); + cleanup(NULL); + return EXIT_FAILURE; + } + } + + /* If not already specified, default to the parser's default preproc. */ + if (!cur_preproc_module) { + cur_preproc_module = + yasm_load_preproc(cur_parser_module->default_preproc_keyword); + if (!cur_preproc_module) { + print_error(_("%s: could not load default %s"), _("FATAL"), + _("preprocessor")); + cleanup(NULL); + return EXIT_FAILURE; + } + } + + /* Determine input filename and open input file. */ + if (!in_filename) { + print_error(_("No input files specified")); + return EXIT_FAILURE; + } + + /* handle preproc-only case here */ + if (preproc_only) + return do_preproc_only(); + + /* If list file enabled, make sure we have a list format loaded. */ + if (list_filename) { + /* If not already specified, default to nasm as the list format. */ + if (!cur_listfmt_module) { + cur_listfmt_module = yasm_load_listfmt("nasm"); + if (!cur_listfmt_module) { + print_error(_("%s: could not load default %s"), _("FATAL"), + _("list format")); + return EXIT_FAILURE; + } + } + } + + /* If not already specified, default to null as the debug format. */ + if (!cur_dbgfmt_module) { + cur_dbgfmt_module = yasm_load_dbgfmt("null"); + if (!cur_dbgfmt_module) { + print_error(_("%s: could not load default %s"), _("FATAL"), + _("debug format")); + return EXIT_FAILURE; + } + } + + return do_assemble(); +} +/*@=globstate =unrecog@*/ + +/* Open the object file. Returns 0 on failure. */ +static FILE * +open_file(const char *filename, const char *mode) +{ + FILE *f; + + f = fopen(filename, mode); + if (!f) + print_error(_("could not open file `%s'"), filename); + return f; +} + +static void +check_errors(yasm_errwarns *errwarns, yasm_object *object, + yasm_linemap *linemap) +{ + if (yasm_errwarns_num_errors(errwarns, warning_error) > 0) { + yasm_errwarns_output_all(errwarns, linemap, warning_error, + print_yasm_error, print_yasm_warning); + yasm_linemap_destroy(linemap); + yasm_errwarns_destroy(errwarns); + cleanup(object); + exit(EXIT_FAILURE); + } +} + +/* Define DO_FREE to 1 to enable deallocation of all data structures. + * Useful for detecting memory leaks, but slows down execution unnecessarily + * (as the OS will free everything we miss here). + */ +#define DO_FREE 1 + +/* Cleans up all allocated structures. */ +static void +cleanup(yasm_object *object) +{ + if (DO_FREE) { + if (cur_listfmt) + yasm_listfmt_destroy(cur_listfmt); + if (cur_preproc) + yasm_preproc_destroy(cur_preproc); + if (object) + yasm_object_destroy(object); + + yasm_floatnum_cleanup(); + yasm_intnum_cleanup(); + + yasm_errwarn_cleanup(); + + BitVector_Shutdown(); + } + + if (DO_FREE) { + if (in_filename) + yasm_xfree(in_filename); + if (obj_filename) + yasm_xfree(obj_filename); + if (list_filename) + yasm_xfree(list_filename); + if (map_filename) + yasm_xfree(map_filename); + if (machine_name) + yasm_xfree(machine_name); + if (objfmt_keyword) + yasm_xfree(objfmt_keyword); + } + + if (errfile != stderr && errfile != stdout) + fclose(errfile); +#if defined(CMAKE_BUILD) && defined(BUILD_SHARED_LIBS) + unload_plugins(); +#endif +} + +/* + * Command line options handlers + */ +int +not_an_option_handler(char *param) +{ + if (in_filename) { + print_error( + _("warning: can open only one input file, only the last file will be processed")); + yasm_xfree(in_filename); + } + + in_filename = yasm__xstrdup(param); + + return 0; +} + +int +other_option_handler(char *option) +{ + /* Accept, but ignore, -O and -Onnn, for compatibility with NASM. */ + if (option[0] == '-' && option[1] == 'O') { + int n = 2; + for (;;) { + if (option[n] == '\0') + return 0; + if (!isdigit(option[n])) + return 1; + n++; + } + } + return 1; +} + +static int +opt_special_handler(/*@unused@*/ char *cmd, /*@unused@*/ char *param, int extra) +{ + if (special_options == 0) + special_options = extra; + return 0; +} + +static int +opt_arch_handler(/*@unused@*/ char *cmd, char *param, /*@unused@*/ int extra) +{ + assert(param != NULL); + cur_arch_module = yasm_load_arch(param); + if (!cur_arch_module) { + if (!strcmp("help", param)) { + printf(_("Available yasm %s:\n"), _("architectures")); + yasm_list_arch(print_list_keyword_desc); + special_options = SPECIAL_LISTED; + return 0; + } + print_error(_("%s: unrecognized %s `%s'"), _("FATAL"), + _("architecture"), param); + exit(EXIT_FAILURE); + } + return 0; +} + +static int +opt_parser_handler(/*@unused@*/ char *cmd, char *param, /*@unused@*/ int extra) +{ + assert(param != NULL); + cur_parser_module = yasm_load_parser(param); + if (!cur_parser_module) { + if (!strcmp("help", param)) { + printf(_("Available yasm %s:\n"), _("parsers")); + yasm_list_parser(print_list_keyword_desc); + special_options = SPECIAL_LISTED; + return 0; + } + print_error(_("%s: unrecognized %s `%s'"), _("FATAL"), _("parser"), + param); + exit(EXIT_FAILURE); + } + return 0; +} + +static int +opt_preproc_handler(/*@unused@*/ char *cmd, char *param, /*@unused@*/ int extra) +{ + assert(param != NULL); + cur_preproc_module = yasm_load_preproc(param); + if (!cur_preproc_module) { + if (!strcmp("help", param)) { + printf(_("Available yasm %s:\n"), _("preprocessors")); + yasm_list_preproc(print_list_keyword_desc); + special_options = SPECIAL_LISTED; + return 0; + } + print_error(_("%s: unrecognized %s `%s'"), _("FATAL"), + _("preprocessor"), param); + exit(EXIT_FAILURE); + } + return 0; +} + +static int +opt_objfmt_handler(/*@unused@*/ char *cmd, char *param, /*@unused@*/ int extra) +{ + size_t i; + assert(param != NULL); + cur_objfmt_module = yasm_load_objfmt(param); + if (!cur_objfmt_module) { + if (!strcmp("help", param)) { + printf(_("Available yasm %s:\n"), _("object formats")); + yasm_list_objfmt(print_list_keyword_desc); + special_options = SPECIAL_LISTED; + return 0; + } + print_error(_("%s: unrecognized %s `%s'"), _("FATAL"), + _("object format"), param); + exit(EXIT_FAILURE); + } + if (objfmt_keyword) + yasm_xfree(objfmt_keyword); + objfmt_keyword = yasm__xstrdup(param); + for (i=0; i<strlen(objfmt_keyword); i++) + objfmt_keyword[i] = tolower(objfmt_keyword[i]); + return 0; +} + +static int +opt_dbgfmt_handler(/*@unused@*/ char *cmd, char *param, /*@unused@*/ int extra) +{ + assert(param != NULL); + cur_dbgfmt_module = yasm_load_dbgfmt(param); + if (!cur_dbgfmt_module) { + if (!strcmp("help", param)) { + printf(_("Available yasm %s:\n"), _("debug formats")); + yasm_list_dbgfmt(print_list_keyword_desc); + special_options = SPECIAL_LISTED; + return 0; + } + print_error(_("%s: unrecognized %s `%s'"), _("FATAL"), + _("debug format"), param); + exit(EXIT_FAILURE); + } + return 0; +} + +static int +opt_listfmt_handler(/*@unused@*/ char *cmd, char *param, + /*@unused@*/ int extra) +{ + assert(param != NULL); + cur_listfmt_module = yasm_load_listfmt(param); + if (!cur_listfmt_module) { + if (!strcmp("help", param)) { + printf(_("Available yasm %s:\n"), _("list formats")); + yasm_list_listfmt(print_list_keyword_desc); + special_options = SPECIAL_LISTED; + return 0; + } + print_error(_("%s: unrecognized %s `%s'"), _("FATAL"), + _("list format"), param); + exit(EXIT_FAILURE); + } + return 0; +} + +static int +opt_listfile_handler(/*@unused@*/ char *cmd, char *param, + /*@unused@*/ int extra) +{ + if (list_filename) { + print_error( + _("warning: can output to only one list file, last specified used")); + yasm_xfree(list_filename); + } + + assert(param != NULL); + list_filename = yasm__xstrdup(param); + + return 0; +} + +static int +opt_objfile_handler(/*@unused@*/ char *cmd, char *param, + /*@unused@*/ int extra) +{ + if (obj_filename) { + print_error( + _("warning: can output to only one object file, last specified used")); + yasm_xfree(obj_filename); + } + + assert(param != NULL); + obj_filename = yasm__xstrdup(param); + + return 0; +} + +static int +opt_mapfile_handler(/*@unused@*/ char *cmd, char *param, + /*@unused@*/ int extra) +{ + if (map_filename) { + print_error( + _("warning: can output to only one map file, last specified used")); + yasm_xfree(map_filename); + } + + assert(param != NULL); + map_filename = yasm__xstrdup(param); + + return 0; +} + +static int +opt_machine_handler(/*@unused@*/ char *cmd, char *param, + /*@unused@*/ int extra) +{ + if (machine_name) + yasm_xfree(machine_name); + + assert(param != NULL); + machine_name = yasm__xstrdup(param); + + return 0; +} + +static int +opt_strict_handler(/*@unused@*/ char *cmd, + /*@unused@*/ /*@null@*/ char *param, + /*@unused@*/ int extra) +{ + force_strict = 1; + return 0; +} + +static int +opt_warning_handler(char *cmd, /*@unused@*/ char *param, int extra) +{ + /* is it disabling the warning instead of enabling? */ + void (*action)(yasm_warn_class wclass) = yasm_warn_enable; + + if (extra == 1) { + /* -w, disable warnings */ + yasm_warn_disable_all(); + return 0; + } + + /* skip past 'W' */ + cmd++; + + /* detect no- prefix to disable the warning */ + if (cmd[0] == 'n' && cmd[1] == 'o' && cmd[2] == '-') { + action = yasm_warn_disable; + cmd += 3; /* skip past it to get to the warning name */ + } + + if (cmd[0] == '\0') + /* just -W or -Wno-, so definitely not valid */ + return 1; + else if (strcmp(cmd, "error") == 0) + warning_error = (action == yasm_warn_enable); + else if (strcmp(cmd, "unrecognized-char") == 0) + action(YASM_WARN_UNREC_CHAR); + else if (strcmp(cmd, "orphan-labels") == 0) + action(YASM_WARN_ORPHAN_LABEL); + else if (strcmp(cmd, "uninit-contents") == 0) + action(YASM_WARN_UNINIT_CONTENTS); + else if (strcmp(cmd, "size-override") == 0) + action(YASM_WARN_SIZE_OVERRIDE); + else + return 1; + + return 0; +} + +static int +opt_error_file(/*@unused@*/ char *cmd, char *param, /*@unused@*/ int extra) +{ + if (error_filename) { + print_error( + _("warning: can output to only one error file, last specified used")); + yasm_xfree(error_filename); + } + + assert(param != NULL); + error_filename = yasm__xstrdup(param); + + return 0; +} + +static int +opt_error_stdout(/*@unused@*/ char *cmd, /*@unused@*/ char *param, + /*@unused@*/ int extra) +{ + /* Clear any specified error filename */ + if (error_filename) { + yasm_xfree(error_filename); + error_filename = NULL; + } + errfile = stdout; + return 0; +} + +static int +preproc_only_handler(/*@unused@*/ char *cmd, /*@unused@*/ char *param, + /*@unused@*/ int extra) +{ + preproc_only = 1; + return 0; +} + +static int +opt_include_option(/*@unused@*/ char *cmd, char *param, /*@unused@*/ int extra) +{ + yasm_add_include_path(param); + return 0; +} + +static int +opt_preproc_option(/*@unused@*/ char *cmd, char *param, int extra) +{ + constcharparam *cp; + cp = yasm_xmalloc(sizeof(constcharparam)); + cp->param = param; + cp->id = extra; + STAILQ_INSERT_TAIL(&preproc_options, cp, link); + return 0; +} + +static int +opt_ewmsg_handler(/*@unused@*/ char *cmd, char *param, /*@unused@*/ int extra) +{ + if (yasm__strcasecmp(param, "gnu") == 0 || + yasm__strcasecmp(param, "gcc") == 0) { + ewmsg_style = EWSTYLE_GNU; + } else if (yasm__strcasecmp(param, "vc") == 0) { + ewmsg_style = EWSTYLE_VC; + } else + print_error(_("warning: unrecognized message style `%s'"), param); + + return 0; +} + +static int +opt_makedep_handler(/*@unused@*/ char *cmd, /*@unused@*/ char *param, + /*@unused@*/ int extra) +{ + /* Also set preproc_only to 1, we don't want to generate code */ + preproc_only = 1; + generate_make_dependencies = 1; + + return 0; +} + +static int +opt_prefix_handler(/*@unused@*/ char *cmd, char *param, /*@unused@*/ int extra) +{ + if (global_prefix) + yasm_xfree(global_prefix); + + assert(param != NULL); + global_prefix = yasm__xstrdup(param); + + return 0; +} + +static void +opt_free_replace(void) +{ + yasm_xfree(replace_params); + replace_capacity = 0; + replace_size = 0; +} + +static int +opt_replace_handler(/*@unused@*/ char *cmd, char *param, /*@unused@*/ int extra) +{ + if (replace_capacity == 0) { + atexit(opt_free_replace); + } + if (replace_size == replace_capacity) { + replace_capacity += 10; + replace_params = yasm_xrealloc(replace_params, replace_capacity); + } + + assert(param != NULL); + replace_params[replace_size] = yasm__xstrdup(param); + ++replace_size; + + return 0; +} + +static int +opt_suffix_handler(/*@unused@*/ char *cmd, char *param, /*@unused@*/ int extra) +{ + if (global_suffix) + yasm_xfree(global_suffix); + + assert(param != NULL); + global_suffix = yasm__xstrdup(param); + + return 0; +} + +#if defined(CMAKE_BUILD) && defined(BUILD_SHARED_LIBS) +static int +opt_plugin_handler(/*@unused@*/ char *cmd, char *param, + /*@unused@*/ int extra) +{ + if (!load_plugin(param)) + print_error(_("warning: could not load plugin `%s'"), param); + return 0; +} +#endif + +static void +apply_preproc_builtins() +{ + char *predef; + + /* Define standard YASM assembly-time macro constants */ + predef = yasm_xmalloc(strlen("__YASM_OBJFMT__=") + + strlen(objfmt_keyword) + 1); + strcpy(predef, "__YASM_OBJFMT__="); + strcat(predef, objfmt_keyword); + yasm_preproc_define_builtin(cur_preproc, predef); + yasm_xfree(predef); +} + +static void +apply_preproc_standard_macros(const yasm_stdmac *stdmacs) +{ + int i, matched; + + if (!stdmacs) + return; + + matched = -1; + for (i=0; stdmacs[i].parser; i++) + if (yasm__strcasecmp(stdmacs[i].parser, + cur_parser_module->keyword) == 0 && + yasm__strcasecmp(stdmacs[i].preproc, + cur_preproc_module->keyword) == 0) + matched = i; + if (matched >= 0 && stdmacs[matched].macros) + yasm_preproc_add_standard(cur_preproc, stdmacs[matched].macros); +} + +static void +apply_preproc_saved_options() +{ + constcharparam *cp, *cpnext; + + void (*funcs[3])(yasm_preproc *, const char *); + funcs[0] = cur_preproc_module->add_include_file; + funcs[1] = cur_preproc_module->predefine_macro; + funcs[2] = cur_preproc_module->undefine_macro; + + STAILQ_FOREACH(cp, &preproc_options, link) { + if (0 <= cp->id && cp->id < 3 && funcs[cp->id]) + funcs[cp->id](cur_preproc, cp->param); + } + + cp = STAILQ_FIRST(&preproc_options); + while (cp != NULL) { + cpnext = STAILQ_NEXT(cp, link); + yasm_xfree(cp); + cp = cpnext; + } + STAILQ_INIT(&preproc_options); +} + +/* Replace extension on a filename (or append one if none is present). + * If output filename would be identical to input (same extension out as in), + * returns (copy of) def. + * A NULL ext means the trailing '.' should NOT be included, whereas a "" ext + * means the trailing '.' should be included. + */ +static char * +replace_extension(const char *orig, /*@null@*/ const char *ext, + const char *def) +{ + char *out, *outext; + size_t deflen, outlen; + + /* allocate enough space for full existing name + extension */ + outlen = strlen(orig) + 2; + if (ext) + outlen += strlen(ext) + 1; + deflen = strlen(def) + 1; + if (outlen < deflen) + outlen = deflen; + out = yasm_xmalloc(outlen); + + strcpy(out, orig); + outext = strrchr(out, '.'); + if (outext) { + /* Existing extension: make sure it's not the same as the replacement + * (as we don't want to overwrite the source file). + */ + outext++; /* advance past '.' */ + if (ext && strcmp(outext, ext) == 0) { + outext = NULL; /* indicate default should be used */ + print_error( + _("file name already ends in `.%s': output will be in `%s'"), + ext, def); + } + } else { + /* No extension: make sure the output extension is not empty + * (again, we don't want to overwrite the source file). + */ + if (!ext) + print_error( + _("file name already has no extension: output will be in `%s'"), + def); + else { + outext = strrchr(out, '\0'); /* point to end of the string */ + *outext++ = '.'; /* append '.' */ + } + } + + /* replace extension or use default name */ + if (outext) { + if (!ext) { + /* Back up and replace '.' with string terminator */ + outext--; + *outext = '\0'; + } else + strcpy(outext, ext); + } else + strcpy(out, def); + + return out; +} + +void +print_list_keyword_desc(const char *name, const char *keyword) +{ + printf("%4s%-12s%s\n", "", keyword, name); +} + +static void +print_error(const char *fmt, ...) +{ + va_list va; + fprintf(errfile, "yasm: "); + va_start(va, fmt); + vfprintf(errfile, fmt, va); + va_end(va); + fputc('\n', errfile); +} + +static /*@exits@*/ void +handle_yasm_int_error(const char *file, unsigned int line, const char *message) +{ + fprintf(stderr, _("INTERNAL ERROR at %s, line %u: %s\n"), file, line, + gettext(message)); +#ifdef HAVE_ABORT + abort(); +#else + exit(EXIT_FAILURE); +#endif +} + +static /*@exits@*/ void +handle_yasm_fatal(const char *fmt, va_list va) +{ + fprintf(errfile, "yasm: %s: ", _("FATAL")); + vfprintf(errfile, gettext(fmt), va); + fputc('\n', errfile); + exit(EXIT_FAILURE); +} + +static const char * +handle_yasm_gettext(const char *msgid) +{ + return gettext(msgid); +} + +static const char *fmt[2] = { + "%s:%lu: %s%s\n", /* GNU */ + "%s(%lu) : %s%s\n" /* VC */ +}; + +static const char *fmt_noline[2] = { + "%s: %s%s\n", /* GNU */ + "%s : %s%s\n" /* VC */ +}; + +static void +print_yasm_error(const char *filename, unsigned long line, const char *msg, + const char *xref_fn, unsigned long xref_line, + const char *xref_msg) +{ + if (line) + fprintf(errfile, fmt[ewmsg_style], filename, line, _("error: "), msg); + else + fprintf(errfile, fmt_noline[ewmsg_style], filename, _("error: "), msg); + + if (xref_fn && xref_msg) { + if (xref_line) + fprintf(errfile, fmt[ewmsg_style], xref_fn, xref_line, _("error: "), + xref_msg); + else + fprintf(errfile, fmt_noline[ewmsg_style], xref_fn, _("error: "), + xref_msg); + } +} + +static void +print_yasm_warning(const char *filename, unsigned long line, const char *msg) +{ + if (line) + fprintf(errfile, fmt[ewmsg_style], filename, line, _("warning: "), + msg); + else + fprintf(errfile, fmt_noline[ewmsg_style], filename, _("warning: "), + msg); +} diff --git a/contrib/tools/yasm/libyasm-stdint.h b/contrib/tools/yasm/libyasm-stdint.h new file mode 100644 index 0000000000..a2a08a9417 --- /dev/null +++ b/contrib/tools/yasm/libyasm-stdint.h @@ -0,0 +1,46 @@ +#ifndef YASM_STDINT_H +#define YASM_STDINT_H + +#define HAVE_STDINT_H + +#ifdef HAVE_STDINT_H +#include <stdint.h> +#elif defined(_MSC_VER) + +#ifndef _UINTPTR_T_DEFINED +#ifdef _WIN64 +#include <vadefs.h> +#else +typedef unsigned long uintptr_t; +#endif +#define _UINTPTR_T_DEFINED +#endif + +#else +typedef unsigned long uintptr_t; +#endif + +#ifndef BUILD_SHARED_LIBS +/* #undef BUILD_SHARED_LIBS */ +#define BUILD_SHARED_LIBS_UNDEF +#endif + +#ifndef YASM_LIB_DECL +# if defined(BUILD_SHARED_LIBS) && defined(_MSC_VER) +# ifdef YASM_LIB_SOURCE +# define YASM_LIB_DECL __declspec(dllexport) +# else +# define YASM_LIB_DECL __declspec(dllimport) +# endif +# else +# define YASM_LIB_DECL +# endif +#endif + +#undef HAVE_STDINT_H +#ifdef BUILD_SHARED_LIBS_UNDEF +#undef BUILD_SHARED_LIBS +#undef BUILD_SHARED_LIBS_UNDEF +#endif + +#endif diff --git a/contrib/tools/yasm/libyasm.h b/contrib/tools/yasm/libyasm.h new file mode 100644 index 0000000000..f52c133b39 --- /dev/null +++ b/contrib/tools/yasm/libyasm.h @@ -0,0 +1,75 @@ +/** + * \file libyasm.h + * \brief YASM library primary header file. + * + * \license + * 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: + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - 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. + * \endlicense + */ +#ifndef YASM_LIB_H +#define YASM_LIB_H + +#ifdef YASM_PYXELATOR +typedef struct __FILE FILE; +typedef struct __va_list va_list; +typedef unsigned long size_t; +typedef unsigned long uintptr_t; +#else +#include <stdio.h> +#include <stdarg.h> +#include <libyasm-stdint.h> +#endif + +#include <libyasm/compat-queue.h> + +#include <libyasm/coretype.h> +#include <libyasm/valparam.h> + +#include <libyasm/linemap.h> + +#include <libyasm/errwarn.h> +#include <libyasm/intnum.h> +#include <libyasm/floatnum.h> +#include <libyasm/expr.h> +#include <libyasm/value.h> +#include <libyasm/symrec.h> + +#include <libyasm/bytecode.h> +#include <libyasm/section.h> +#include <libyasm/insn.h> + +#include <libyasm/arch.h> +#include <libyasm/dbgfmt.h> +#include <libyasm/objfmt.h> +#include <libyasm/listfmt.h> +#include <libyasm/parser.h> +#include <libyasm/preproc.h> + +#include <libyasm/file.h> +#include <libyasm/module.h> + +#include <libyasm/hamt.h> +#include <libyasm/md5.h> + +#endif diff --git a/contrib/tools/yasm/libyasm/arch.h b/contrib/tools/yasm/libyasm/arch.h new file mode 100644 index 0000000000..3da9f9fca3 --- /dev/null +++ b/contrib/tools/yasm/libyasm/arch.h @@ -0,0 +1,495 @@ +/** + * \file libyasm/arch.h + * \brief YASM architecture interface. + * + * \license + * 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: + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - 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. + * \endlicense + */ +#ifndef YASM_ARCH_H +#define YASM_ARCH_H + +/** Errors that may be returned by yasm_arch_module::create(). */ +typedef enum yasm_arch_create_error { + YASM_ARCH_CREATE_OK = 0, /**< No error. */ + YASM_ARCH_CREATE_BAD_MACHINE, /**< Unrecognized machine name. */ + YASM_ARCH_CREATE_BAD_PARSER /**< Unrecognized parser name. */ +} yasm_arch_create_error; + +/** Return values for yasm_arch_module::parse_check_insnprefix(). */ +typedef enum yasm_arch_insnprefix { + YASM_ARCH_NOTINSNPREFIX = 0, /**< Unrecognized */ + YASM_ARCH_INSN, /**< An instruction */ + YASM_ARCH_PREFIX /**< An instruction prefix */ +} yasm_arch_insnprefix; + +/** Types of registers / target modifiers that may be returned by + * yasm_arch_module::parse_check_regtmod(). + */ +typedef enum yasm_arch_regtmod { + YASM_ARCH_NOTREGTMOD = 0, /**< Unrecognized */ + YASM_ARCH_REG, /**< A "normal" register */ + YASM_ARCH_REGGROUP, /**< A group of indexable registers */ + YASM_ARCH_SEGREG, /**< A segment register */ + YASM_ARCH_TARGETMOD /**< A target modifier (for jumps) */ +} yasm_arch_regtmod; + +#ifndef YASM_DOXYGEN +/** Base #yasm_arch structure. Must be present as the first element in any + * #yasm_arch implementation. + */ +typedef struct yasm_arch_base { + /** #yasm_arch_module implementation for this architecture. */ + const struct yasm_arch_module *module; +} yasm_arch_base; +#endif + +/** YASM machine subtype. A number of different machine types may be + * associated with a single architecture. These may be specific CPU's, but + * the ABI used to interface with the architecture should be the primary + * differentiator between machines. Some object formats (ELF) use the machine + * to determine parameters within the generated output. + */ +typedef struct yasm_arch_machine { + /** One-line description of the machine. */ + const char *name; + + /** Keyword used to select machine. */ + const char *keyword; +} yasm_arch_machine; + +/** YASM architecture module interface. + * \note All "data" in parser-related functions (yasm_arch_parse_*) needs to + * start the parse initialized to 0 to make it okay for a parser-related + * function to use/check previously stored data to see if it's been + * called before on the same piece of data. + */ +typedef struct yasm_arch_module { + /** One-line description of the architecture. + * Call yasm_arch_name() to get the name of a particular #yasm_arch. + */ + const char *name; + + /** Keyword used to select architecture. + * Call yasm_arch_keyword() to get the keyword of a particular #yasm_arch. + */ + const char *keyword; + + /** NULL-terminated list of directives. NULL if none. */ + /*@null@*/ const yasm_directive *directives; + + /** Create architecture. + * Module-level implementation of yasm_arch_create(). + * Call yasm_arch_create() instead of calling this function. + */ + /*@only@*/ yasm_arch * (*create) (const char *machine, const char *parser, + /*@out@*/ yasm_arch_create_error *error); + + /** Module-level implementation of yasm_arch_destroy(). + * Call yasm_arch_destroy() instead of calling this function. + */ + void (*destroy) (/*@only@*/ yasm_arch *arch); + + /** Module-level implementation of yasm_arch_get_machine(). + * Call yasm_arch_get_machine() instead of calling this function. + */ + const char * (*get_machine) (const yasm_arch *arch); + + /** Module-level implementation of yasm_arch_get_address_size(). + * Call yasm_arch_get_address_size() instead of calling this function. + */ + unsigned int (*get_address_size) (const yasm_arch *arch); + + /** Module-level implementation of yasm_arch_set_var(). + * Call yasm_arch_set_var() instead of calling this function. + */ + int (*set_var) (yasm_arch *arch, const char *var, unsigned long val); + + /** Module-level implementation of yasm_arch_parse_check_insnprefix(). + * Call yasm_arch_parse_check_insnprefix() instead of calling this function. + */ + yasm_arch_insnprefix (*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); + + /** Module-level implementation of yasm_arch_parse_check_regtmod(). + * Call yasm_arch_parse_check_regtmod() instead of calling this function. + */ + yasm_arch_regtmod (*parse_check_regtmod) + (yasm_arch *arch, const char *id, size_t id_len, + /*@out@*/ uintptr_t *data); + + /** Module-level implementation of yasm_arch_get_fill(). + * Call yasm_arch_get_fill() instead of calling this function. + */ + const unsigned char ** (*get_fill) (const yasm_arch *arch); + + /** Module-level implementation of yasm_arch_floatnum_tobytes(). + * Call yasm_arch_floatnum_tobytes() instead of calling this function. + */ + int (*floatnum_tobytes) (yasm_arch *arch, const yasm_floatnum *flt, + unsigned char *buf, size_t destsize, + size_t valsize, size_t shift, int warn); + + /** Module-level implementation of yasm_arch_intnum_tobytes(). + * Call yasm_arch_intnum_tobytes() instead of calling this function. + */ + int (*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); + + /** Module-level implementation of yasm_arch_get_reg_size(). + * Call yasm_arch_get_reg_size() instead of calling this function. + */ + unsigned int (*get_reg_size) (yasm_arch *arch, uintptr_t reg); + + /** Module-level implementation of yasm_arch_reggroup_get_reg(). + * Call yasm_arch_reggroup_get_reg() instead of calling this function. + */ + uintptr_t (*reggroup_get_reg) (yasm_arch *arch, uintptr_t reggroup, + unsigned long regindex); + + /** Module-level implementation of yasm_arch_reg_print(). + * Call yasm_arch_reg_print() instead of calling this function. + */ + void (*reg_print) (yasm_arch *arch, uintptr_t reg, FILE *f); + + /** Module-level implementation of yasm_arch_segreg_print(). + * Call yasm_arch_segreg_print() instead of calling this function. + */ + void (*segreg_print) (yasm_arch *arch, uintptr_t segreg, FILE *f); + + /** Module-level implementation of yasm_arch_ea_create(). + * Call yasm_arch_ea_create() instead of calling this function. + */ + yasm_effaddr * (*ea_create) (yasm_arch *arch, /*@keep@*/ yasm_expr *e); + + /** Module-level implementation of yasm_arch_ea_destroy(). + * Call yasm_arch_ea_destroy() instead of calling this function. + */ + void (*ea_destroy) (/*@only@*/ yasm_effaddr *ea); + + /** Module-level implementation of yasm_arch_ea_print(). + * Call yasm_arch_ea_print() instead of calling this function. + */ + void (*ea_print) (const yasm_effaddr *ea, FILE *f, int indent_level); + + /** Module-level implementation of yasm_arch_create_empty_insn(). + * Call yasm_arch_create_empty_insn() instead of calling this function. + */ + /*@only@*/ yasm_bytecode * (*create_empty_insn) (yasm_arch *arch, + unsigned long line); + + /** NULL-terminated list of machines for this architecture. + * Call yasm_arch_get_machine() to get the active machine of a particular + * #yasm_arch. + */ + const yasm_arch_machine *machines; + + /** Default machine keyword. + * Call yasm_arch_get_machine() to get the active machine of a particular + * #yasm_arch. + */ + const char *default_machine_keyword; + + /** Canonical "word" size in bits. + * Call yasm_arch_wordsize() to get the word size of a particular + * #yasm_arch. + */ + unsigned int wordsize; + + /** Worst case minimum instruction length in bytes. + * Call yasm_arch_min_insn_len() to get the minimum instruction length of + * a particular #yasm_arch. + */ + unsigned int min_insn_len; +} yasm_arch_module; + +/** Get the one-line description of an architecture. + * \param arch architecture + * \return One-line description of architecture. + */ +const char *yasm_arch_name(const yasm_arch *arch); + +/** Get the keyword used to select an architecture. + * \param arch architecture + * \return Architecture keyword. + */ +const char *yasm_arch_keyword(const yasm_arch *arch); + +/** Get the word size of an architecture. + * \param arch architecture + * \return Word size (in bits). + */ +unsigned int yasm_arch_wordsize(const yasm_arch *arch); + +/** Get the minimum instruction length of an architecture. + * \param arch architecture + * \return Minimum instruction length (in bytes). + */ +unsigned int yasm_arch_min_insn_len(const yasm_arch *arch); + +/** Create architecture. + * \param module architecture module + * \param machine keyword of machine in use (must be one listed in + * #yasm_arch_module.machines) + * \param parser keyword of parser in use + * \param error error return value + * \return NULL on error (error returned in error parameter), otherwise new + * architecture. + */ +/*@only@*/ yasm_arch *yasm_arch_create(const yasm_arch_module *module, + const char *machine, const char *parser, + /*@out@*/ yasm_arch_create_error *error); + +/** Clean up, free any architecture-allocated memory. + * \param arch architecture + */ +void yasm_arch_destroy(/*@only@*/ yasm_arch *arch); + +/** Get architecture's active machine name. + * \param arch architecture + * \return Active machine name. + */ +const char *yasm_arch_get_machine(const yasm_arch *arch); + +/** Get architecture's active address size, in bits. + * \param arch architecture + * \return Active address size (in bits). + */ +unsigned int yasm_arch_get_address_size(const yasm_arch *arch); + +/** Set any arch-specific variables. For example, "mode_bits" in x86. + * \param arch architecture + * \param var variable name + * \param val value to set + * \return Zero on success, non-zero on failure (variable does not exist). + */ +int yasm_arch_set_var(yasm_arch *arch, const char *var, unsigned long val); + +/** Check an generic identifier to see if it matches architecture specific + * names for instructions or instruction prefixes. Unrecognized identifiers + * should return #YASM_ARCH_NOTINSNPREFIX so they can be treated as normal + * symbols. Any additional data beyond just the type (almost always necessary) + * should be returned into the space provided by the data parameter. + * \param arch architecture + * \param id identifier as in the input file + * \param id_len length of id string + * \param line virtual line + * \param bc for instructions, yasm_insn-based bytecode is returned + * (and NULL otherwise) + * \param prefix for prefixes, yasm_arch-specific value is returned + * (and 0 otherwise) + * \return Identifier type (#YASM_ARCH_NOTINSNPREFIX if unrecognized) + */ +yasm_arch_insnprefix yasm_arch_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); + +/** Check an generic identifier to see if it matches architecture specific + * names for registers or target modifiers. Unrecognized identifiers should + * return #YASM_ARCH_NOTREGTMOD. Any additional data beyond just the type + * (almost always necessary) should be returned into the space provided by the + * data parameter. + * \param arch architecture + * \param id identifier as in the input file + * \param id_len length of id string + * \param data extra identification information (yasm_arch-specific) + * [output] + * \return Identifier type (#YASM_ARCH_NOTREGTMOD if unrecognized) + */ +yasm_arch_regtmod yasm_arch_parse_check_regtmod + (yasm_arch *arch, const char *id, size_t id_len, + /*@out@*/ uintptr_t *data); + +/** Get NOP fill patterns for 1-15 bytes of fill. + * \param arch architecture + * \return 16-entry array of arrays; [0] is unused, [1] - [15] point to arrays + * of 1-15 bytes (respectively) in length. + */ +const unsigned char **yasm_arch_get_fill(const yasm_arch *arch); + +/** Output #yasm_floatnum to buffer. Puts the value into the least + * significant bits of the destination, or may be shifted into more + * significant bits by the shift parameter. The destination bits are + * cleared before being set. + * Architecture-specific because of endianness. + * \param arch architecture + * \param flt floating point value + * \param buf buffer to write into + * \param destsize destination size (in bytes) + * \param valsize size (in bits) + * \param shift left shift (in bits) + * \param warn enables standard overflow/underflow warnings + * \return Nonzero on error. + */ +int yasm_arch_floatnum_tobytes(yasm_arch *arch, const yasm_floatnum *flt, + unsigned char *buf, size_t destsize, + size_t valsize, size_t shift, int warn); + +/** Output #yasm_intnum to buffer. Puts the value into the least + * significant bits of the destination, or may be shifted into more + * significant bits by the shift parameter. The destination bits are + * cleared before being set. + * \param arch architecture + * \param intn integer value + * \param buf buffer to write into + * \param destsize destination size (in bytes) + * \param valsize size (in bits) + * \param shift left shift (in bits); may be negative to specify right + * shift (standard warnings include truncation to boundary) + * \param bc bytecode being output ("parent" of value) + * \param warn enables standard warnings (value doesn't fit into + * valsize bits) + * \return Nonzero on error. + */ +int yasm_arch_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); + +/** Get the equivalent size of a register in bits. + * \param arch architecture + * \param reg register + * \return 0 if there is no suitable equivalent size, otherwise the size. + */ +unsigned int yasm_arch_get_reg_size(yasm_arch *arch, uintptr_t reg); + +/** Get a specific register of a register group, based on the register + * group and the index within the group. + * \param arch architecture + * \param reggroup register group + * \param regindex register index + * \return 0 if regindex is not valid for that register group, otherwise the + * specific register value. + */ +uintptr_t yasm_arch_reggroup_get_reg(yasm_arch *arch, uintptr_t reggroup, + unsigned long regindex); + +/** Print a register. For debugging purposes. + * \param arch architecture + * \param reg register + * \param f file + */ +void yasm_arch_reg_print(yasm_arch *arch, uintptr_t reg, FILE *f); + +/** Print a segment register. For debugging purposes. + * \param arch architecture + * \param segreg segment register + * \param f file + */ +void yasm_arch_segreg_print(yasm_arch *arch, uintptr_t segreg, FILE *f); + +/** Create an effective address from an expression. + * \param arch architecture + * \param e expression (kept, do not delete) + * \return Newly allocated effective address. + */ +yasm_effaddr *yasm_arch_ea_create(yasm_arch *arch, /*@keep@*/ yasm_expr *e); + +/** Delete (free allocated memory for) an effective address. + * \param arch architecture + * \param ea effective address (only pointer to it). + */ +void yasm_arch_ea_destroy(yasm_arch *arch, /*@only@*/ yasm_effaddr *ea); + +/** Print an effective address. For debugging purposes. + * \param arch architecture + * \param ea effective address + * \param f file + * \param indent_level indentation level + */ +void yasm_arch_ea_print(const yasm_arch *arch, const yasm_effaddr *ea, + FILE *f, int indent_level); + +/** Create a bytecode that represents a single empty (0 length) instruction. + * This is used for handling solitary prefixes. + * \param arch architecture + * \param line virtual line (from yasm_linemap) + * \return Newly allocated bytecode. + */ +/*@only@*/ yasm_bytecode *yasm_arch_create_empty_insn(yasm_arch *arch, + unsigned long line); + +#ifndef YASM_DOXYGEN + +/* Inline macro implementations for arch functions */ + +#define yasm_arch_name(arch) \ + (((yasm_arch_base *)arch)->module->name) +#define yasm_arch_keyword(arch) \ + (((yasm_arch_base *)arch)->module->keyword) +#define yasm_arch_wordsize(arch) \ + (((yasm_arch_base *)arch)->module->wordsize) +#define yasm_arch_min_insn_len(arch) \ + (((yasm_arch_base *)arch)->module->min_insn_len) + +#define yasm_arch_create(module, machine, parser, error) \ + module->create(machine, parser, error) + +#define yasm_arch_destroy(arch) \ + ((yasm_arch_base *)arch)->module->destroy(arch) +#define yasm_arch_get_machine(arch) \ + ((yasm_arch_base *)arch)->module->get_machine(arch) +#define yasm_arch_get_address_size(arch) \ + ((yasm_arch_base *)arch)->module->get_address_size(arch) +#define yasm_arch_set_var(arch, var, val) \ + ((yasm_arch_base *)arch)->module->set_var(arch, var, val) +#define yasm_arch_parse_check_insnprefix(arch, id, id_len, line, bc, prefix) \ + ((yasm_arch_base *)arch)->module->parse_check_insnprefix \ + (arch, id, id_len, line, bc, prefix) +#define yasm_arch_parse_check_regtmod(arch, id, id_len, data) \ + ((yasm_arch_base *)arch)->module->parse_check_regtmod \ + (arch, id, id_len, data) +#define yasm_arch_get_fill(arch) \ + ((yasm_arch_base *)arch)->module->get_fill(arch) +#define yasm_arch_floatnum_tobytes(arch, flt, buf, destsize, valsize, shift, \ + warn) \ + ((yasm_arch_base *)arch)->module->floatnum_tobytes \ + (arch, flt, buf, destsize, valsize, shift, warn) +#define yasm_arch_intnum_tobytes(arch, intn, buf, destsize, valsize, shift, \ + bc, warn) \ + ((yasm_arch_base *)arch)->module->intnum_tobytes \ + (arch, intn, buf, destsize, valsize, shift, bc, warn) +#define yasm_arch_get_reg_size(arch, reg) \ + ((yasm_arch_base *)arch)->module->get_reg_size(arch, reg) +#define yasm_arch_reggroup_get_reg(arch, regg, regi) \ + ((yasm_arch_base *)arch)->module->reggroup_get_reg(arch, regg, regi) +#define yasm_arch_reg_print(arch, reg, f) \ + ((yasm_arch_base *)arch)->module->reg_print(arch, reg, f) +#define yasm_arch_segreg_print(arch, segreg, f) \ + ((yasm_arch_base *)arch)->module->segreg_print(arch, segreg, f) +#define yasm_arch_ea_create(arch, e) \ + ((yasm_arch_base *)arch)->module->ea_create(arch, e) +#define yasm_arch_ea_destroy(arch, ea) \ + ((yasm_arch_base *)arch)->module->ea_destroy(ea) +#define yasm_arch_ea_print(arch, ea, f, i) \ + ((yasm_arch_base *)arch)->module->ea_print(ea, f, i) +#define yasm_arch_create_empty_insn(arch, line) \ + ((yasm_arch_base *)arch)->module->create_empty_insn(arch, line) + +#endif + +#endif diff --git a/contrib/tools/yasm/libyasm/assocdat.c b/contrib/tools/yasm/libyasm/assocdat.c new file mode 100644 index 0000000000..560093685e --- /dev/null +++ b/contrib/tools/yasm/libyasm/assocdat.c @@ -0,0 +1,138 @@ +/* + * YASM associated data storage (libyasm internal use) + * + * 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 "coretype.h" +#include "assocdat.h" + + +typedef struct assoc_data_item { + const yasm_assoc_data_callback *callback; + void *data; +} assoc_data_item; + +struct yasm__assoc_data { + assoc_data_item *vector; + size_t size; + size_t alloc; +}; + + +yasm__assoc_data * +yasm__assoc_data_create(void) +{ + yasm__assoc_data *assoc_data = yasm_xmalloc(sizeof(yasm__assoc_data)); + + assoc_data->size = 0; + assoc_data->alloc = 2; + assoc_data->vector = yasm_xmalloc(assoc_data->alloc * + sizeof(assoc_data_item)); + + return assoc_data; +} + +void * +yasm__assoc_data_get(yasm__assoc_data *assoc_data, + const yasm_assoc_data_callback *callback) +{ + size_t i; + + if (!assoc_data) + return NULL; + + for (i=0; i<assoc_data->size; i++) { + if (assoc_data->vector[i].callback == callback) + return assoc_data->vector[i].data; + } + return NULL; +} + +yasm__assoc_data * +yasm__assoc_data_add(yasm__assoc_data *assoc_data_arg, + const yasm_assoc_data_callback *callback, void *data) +{ + yasm__assoc_data *assoc_data; + assoc_data_item *item = NULL; + size_t i; + + /* Create a new assoc_data if necessary */ + if (assoc_data_arg) + assoc_data = assoc_data_arg; + else + assoc_data = yasm__assoc_data_create(); + + /* See if there's already assocated data for this callback */ + for (i=0; i<assoc_data->size; i++) { + if (assoc_data->vector[i].callback == callback) { + item = &assoc_data->vector[i]; + break; + } + } + + /* No? Then append a new one */ + if (!item) { + assoc_data->size++; + if (assoc_data->size > assoc_data->alloc) { + assoc_data->alloc *= 2; + assoc_data->vector = + yasm_xrealloc(assoc_data->vector, + assoc_data->alloc * sizeof(assoc_data_item)); + } + item = &assoc_data->vector[assoc_data->size-1]; + item->callback = callback; + item->data = NULL; + } + + /* Delete existing data (if any) */ + if (item->data && item->data != data) + item->callback->destroy(item->data); + + item->data = data; + + return assoc_data; +} + +void +yasm__assoc_data_destroy(yasm__assoc_data *assoc_data) +{ + size_t i; + + if (!assoc_data) + return; + + for (i=0; i<assoc_data->size; i++) + assoc_data->vector[i].callback->destroy(assoc_data->vector[i].data); + yasm_xfree(assoc_data->vector); + yasm_xfree(assoc_data); +} + +void +yasm__assoc_data_print(const yasm__assoc_data *assoc_data, FILE *f, + int indent_level) +{ + /*TODO*/ +} diff --git a/contrib/tools/yasm/libyasm/assocdat.h b/contrib/tools/yasm/libyasm/assocdat.h new file mode 100644 index 0000000000..cf42386775 --- /dev/null +++ b/contrib/tools/yasm/libyasm/assocdat.h @@ -0,0 +1,76 @@ +/** + * \file assocdat.h + * \brief YASM associated data storage (libyasm internal use) + * + * \license + * 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: + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - 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. + * \endlicense + */ +#ifndef YASM_ASSOCDAT_H +#define YASM_ASSOCDAT_H + +#ifndef YASM_LIB_DECL +#define YASM_LIB_DECL +#endif + +/** Associated data container. */ +typedef struct yasm__assoc_data yasm__assoc_data; + +/** Create an associated data container. */ +YASM_LIB_DECL +/*@only@*/ yasm__assoc_data *yasm__assoc_data_create(void); + +/** Get associated data for a data callback. + * \param assoc_data container of associated data + * \param callback callback used when adding data + * \return Associated data (NULL if none). + */ +YASM_LIB_DECL +/*@dependent@*/ /*@null@*/ void *yasm__assoc_data_get + (/*@null@*/ yasm__assoc_data *assoc_data, + const yasm_assoc_data_callback *callback); + +/** Add associated data to a associated data container. + * \attention Deletes any existing associated data for that data callback. + * \param assoc_data container of associated data + * \param callback callback + * \param data data to associate + */ +YASM_LIB_DECL +/*@only@*/ yasm__assoc_data *yasm__assoc_data_add + (/*@null@*/ /*@only@*/ yasm__assoc_data *assoc_data, + const yasm_assoc_data_callback *callback, + /*@only@*/ /*@null@*/ void *data); + +/** Destroy all associated data in a container. */ +YASM_LIB_DECL +void yasm__assoc_data_destroy + (/*@null@*/ /*@only@*/ yasm__assoc_data *assoc_data); + +/** Print all associated data in a container. */ +YASM_LIB_DECL +void yasm__assoc_data_print(const yasm__assoc_data *assoc_data, FILE *f, + int indent_level); + +#endif diff --git a/contrib/tools/yasm/libyasm/bc-align.c b/contrib/tools/yasm/libyasm/bc-align.c new file mode 100644 index 0000000000..2a47882ef0 --- /dev/null +++ b/contrib/tools/yasm/libyasm/bc-align.c @@ -0,0 +1,245 @@ +/* + * Align bytecode + * + * Copyright (C) 2005-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-stdint.h" +#include "coretype.h" + +#include "errwarn.h" +#include "intnum.h" +#include "expr.h" + +#include "bytecode.h" + + +typedef struct bytecode_align { + /*@only@*/ yasm_expr *boundary; /* alignment boundary */ + + /* What to fill intervening locations with, NULL if using code_fill */ + /*@only@*/ /*@null@*/ yasm_expr *fill; + + /* Maximum number of bytes to skip, NULL if no maximum. */ + /*@only@*/ /*@null@*/ yasm_expr *maxskip; + + /* Code fill, NULL if using 0 fill */ + /*@null@*/ const unsigned char **code_fill; +} bytecode_align; + +static void bc_align_destroy(void *contents); +static void bc_align_print(const void *contents, FILE *f, int indent_level); +static void bc_align_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc); +static int bc_align_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span, + void *add_span_data); +static int bc_align_expand(yasm_bytecode *bc, int span, long old_val, + long new_val, /*@out@*/ long *neg_thres, + /*@out@*/ long *pos_thres); +static int bc_align_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 const yasm_bytecode_callback bc_align_callback = { + bc_align_destroy, + bc_align_print, + bc_align_finalize, + NULL, + bc_align_calc_len, + bc_align_expand, + bc_align_tobytes, + YASM_BC_SPECIAL_OFFSET +}; + + +static void +bc_align_destroy(void *contents) +{ + bytecode_align *align = (bytecode_align *)contents; + if (align->boundary) + yasm_expr_destroy(align->boundary); + if (align->fill) + yasm_expr_destroy(align->fill); + if (align->maxskip) + yasm_expr_destroy(align->maxskip); + yasm_xfree(contents); +} + +static void +bc_align_print(const void *contents, FILE *f, int indent_level) +{ + const bytecode_align *align = (const bytecode_align *)contents; + fprintf(f, "%*s_Align_\n", indent_level, ""); + fprintf(f, "%*sBoundary=", indent_level, ""); + yasm_expr_print(align->boundary, f); + fprintf(f, "\n%*sFill=", indent_level, ""); + yasm_expr_print(align->fill, f); + fprintf(f, "\n%*sMax Skip=", indent_level, ""); + yasm_expr_print(align->maxskip, f); + fprintf(f, "\n"); +} + +static void +bc_align_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc) +{ + bytecode_align *align = (bytecode_align *)bc->contents; + if (!yasm_expr_get_intnum(&align->boundary, 0)) + yasm_error_set(YASM_ERROR_NOT_CONSTANT, + N_("align boundary must be a constant")); + if (align->fill && !yasm_expr_get_intnum(&align->fill, 0)) + yasm_error_set(YASM_ERROR_NOT_CONSTANT, + N_("align fill must be a constant")); + if (align->maxskip && !yasm_expr_get_intnum(&align->maxskip, 0)) + yasm_error_set(YASM_ERROR_NOT_CONSTANT, + N_("align maximum skip must be a constant")); +} + +static int +bc_align_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span, + void *add_span_data) +{ + long neg_thres = 0; + long pos_thres = 0; + + if (bc_align_expand(bc, 0, 0, (long)bc->offset, &neg_thres, + &pos_thres) < 0) + return -1; + + return 0; +} + +static int +bc_align_expand(yasm_bytecode *bc, int span, long old_val, long new_val, + /*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres) +{ + bytecode_align *align = (bytecode_align *)bc->contents; + unsigned long end; + unsigned long boundary = + yasm_intnum_get_uint(yasm_expr_get_intnum(&align->boundary, 0)); + + if (boundary == 0) { + bc->len = 0; + *pos_thres = new_val; + return 0; + } + + end = (unsigned long)new_val; + if ((unsigned long)new_val & (boundary-1)) + end = ((unsigned long)new_val & ~(boundary-1)) + boundary; + + *pos_thres = (long)end; + bc->len = end - (unsigned long)new_val; + + if (align->maxskip) { + unsigned long maxskip = + yasm_intnum_get_uint(yasm_expr_get_intnum(&align->maxskip, 0)); + if (bc->len > maxskip) { + *pos_thres = (long)end-maxskip-1; + bc->len = 0; + } + } + return 1; +} + +static int +bc_align_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) +{ + bytecode_align *align = (bytecode_align *)bc->contents; + unsigned long len; + unsigned long boundary = + yasm_intnum_get_uint(yasm_expr_get_intnum(&align->boundary, 0)); + + if (boundary == 0) + return 0; + else { + unsigned long end = bc->offset; + if (bc->offset & (boundary-1)) + end = (bc->offset & ~(boundary-1)) + boundary; + len = end - bc->offset; + if (len == 0) + return 0; + if (align->maxskip) { + unsigned long maxskip = + yasm_intnum_get_uint(yasm_expr_get_intnum(&align->maxskip, 0)); + if (len > maxskip) + return 0; + } + } + + if (align->fill) { + unsigned long v; + v = yasm_intnum_get_uint(yasm_expr_get_intnum(&align->fill, 0)); + memset(*bufp, (int)v, len); + *bufp += len; + } else if (align->code_fill) { + unsigned long maxlen = 15; + while (!align->code_fill[maxlen] && maxlen>0) + maxlen--; + if (maxlen == 0) { + yasm_error_set(YASM_ERROR_GENERAL, + N_("could not find any code alignment size")); + return 1; + } + + /* Fill with maximum code fill as much as possible */ + while (len > maxlen) { + memcpy(*bufp, align->code_fill[maxlen], maxlen); + *bufp += maxlen; + len -= maxlen; + } + + if (!align->code_fill[len]) { + yasm_error_set(YASM_ERROR_VALUE, + N_("invalid alignment size %d"), len); + return 1; + } + /* Handle rest of code fill */ + memcpy(*bufp, align->code_fill[len], len); + *bufp += len; + } else { + /* Just fill with 0 */ + memset(*bufp, 0, len); + *bufp += len; + } + return 0; +} + +yasm_bytecode * +yasm_bc_create_align(yasm_expr *boundary, yasm_expr *fill, + yasm_expr *maxskip, const unsigned char **code_fill, + unsigned long line) +{ + bytecode_align *align = yasm_xmalloc(sizeof(bytecode_align)); + + align->boundary = boundary; + align->fill = fill; + align->maxskip = maxskip; + align->code_fill = code_fill; + + return yasm_bc_create_common(&bc_align_callback, align, line); +} diff --git a/contrib/tools/yasm/libyasm/bc-data.c b/contrib/tools/yasm/libyasm/bc-data.c new file mode 100644 index 0000000000..ebbdd6f97d --- /dev/null +++ b/contrib/tools/yasm/libyasm/bc-data.c @@ -0,0 +1,600 @@ +/* + * Data (and LEB128) bytecode + * + * 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-stdint.h" +#include "coretype.h" + +#include "errwarn.h" +#include "intnum.h" +#include "expr.h" +#include "value.h" + +#include "bytecode.h" +#include "arch.h" + + +struct yasm_dataval { + /*@reldef@*/ STAILQ_ENTRY(yasm_dataval) link; + + enum { DV_EMPTY, DV_VALUE, DV_RAW, DV_ULEB128, DV_SLEB128, DV_RESERVE } + type; + + union { + yasm_value val; + struct { + /*@only@*/ unsigned char *contents; + unsigned long len; + } raw; + } data; + + /* number of times data is repeated, NULL=1. */ + /*@only@*/ /*@null@*/ yasm_expr *multiple; +}; + +typedef struct bytecode_data { + /* converted data (linked list) */ + yasm_datavalhead datahead; + + int item_size; +} bytecode_data; + +static void bc_data_destroy(void *contents); +static void bc_data_print(const void *contents, FILE *f, int indent_level); +static void bc_data_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc); +static int bc_data_item_size(yasm_bytecode *bc); +static int bc_data_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span, + void *add_span_data); +static int bc_data_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 const yasm_bytecode_callback bc_data_callback = { + bc_data_destroy, + bc_data_print, + bc_data_finalize, + bc_data_item_size, + bc_data_calc_len, + yasm_bc_expand_common, + bc_data_tobytes, + 0 +}; + + +static void +bc_data_destroy(void *contents) +{ + bytecode_data *bc_data = (bytecode_data *)contents; + yasm_dvs_delete(&bc_data->datahead); + yasm_xfree(contents); +} + +static void +bc_data_print(const void *contents, FILE *f, int indent_level) +{ + const bytecode_data *bc_data = (const bytecode_data *)contents; + fprintf(f, "%*s_Data_\n", indent_level, ""); + fprintf(f, "%*sElements:\n", indent_level+1, ""); + yasm_dvs_print(&bc_data->datahead, f, indent_level+2); +} + +static void +bc_data_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc) +{ + bytecode_data *bc_data = (bytecode_data *)bc->contents; + yasm_dataval *dv; + yasm_intnum *intn; + + /* Convert values from simple expr to value. */ + STAILQ_FOREACH(dv, &bc_data->datahead, link) { + switch (dv->type) { + case DV_VALUE: + if (yasm_value_finalize(&dv->data.val, prev_bc)) { + yasm_error_set(YASM_ERROR_TOO_COMPLEX, + N_("data expression too complex")); + return; + } + break; + case DV_ULEB128: + case DV_SLEB128: + intn = yasm_expr_get_intnum(&dv->data.val.abs, 0); + if (!intn) { + yasm_error_set(YASM_ERROR_NOT_CONSTANT, + N_("LEB128 requires constant values")); + return; + } + /* Warn for negative values in unsigned environment. + * This could be an error instead: the likelihood this is + * desired is very low! + */ + if (yasm_intnum_sign(intn) == -1 && dv->type == DV_ULEB128) + yasm_warn_set(YASM_WARN_GENERAL, + N_("negative value in unsigned LEB128")); + break; + default: + break; + } + if (dv->multiple) { + yasm_value val; + if (yasm_value_finalize_expr(&val, dv->multiple, prev_bc, 0)) + yasm_error_set(YASM_ERROR_TOO_COMPLEX, + N_("multiple expression too complex")); + else if (val.rel) + yasm_error_set(YASM_ERROR_NOT_ABSOLUTE, + N_("multiple expression not absolute")); + dv->multiple = val.abs; + } + } +} + +static int +bc_data_item_size(yasm_bytecode *bc) +{ + bytecode_data *bc_data = (bytecode_data *)bc->contents; + return bc_data->item_size; +} + +static int +bc_data_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span, + void *add_span_data) +{ + bytecode_data *bc_data = (bytecode_data *)bc->contents; + yasm_dataval *dv; + yasm_intnum *intn; + unsigned long len = 0; + unsigned long multiple; + + /* Count up element sizes, rounding up string length. */ + STAILQ_FOREACH(dv, &bc_data->datahead, link) { + switch (dv->type) { + case DV_EMPTY: + len = 0; + break; + case DV_VALUE: + len = dv->data.val.size/8; + break; + case DV_RAW: + len = dv->data.raw.len; + break; + case DV_ULEB128: + case DV_SLEB128: + intn = yasm_expr_get_intnum(&dv->data.val.abs, 0); + if (!intn) + yasm_internal_error(N_("non-constant in data_tobytes")); + len = yasm_intnum_size_leb128(intn, dv->type == DV_SLEB128); + break; + case DV_RESERVE: + len = dv->data.val.size/8; + break; + } + + if (!yasm_dv_get_multiple(dv, &multiple)) + len *= multiple; + + bc->len += len; + } + + return 0; +} + +static int +bc_data_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) +{ + bytecode_data *bc_data = (bytecode_data *)bc->contents; + yasm_dataval *dv; + yasm_intnum *intn; + unsigned int val_len; + unsigned long multiple, i; + + STAILQ_FOREACH(dv, &bc_data->datahead, link) { + if (yasm_dv_get_multiple(dv, &multiple) || multiple == 0) + continue; + switch (dv->type) { + case DV_EMPTY: + break; + case DV_VALUE: + val_len = dv->data.val.size/8; + for (i=0; i<multiple; i++) { + if (output_value(&dv->data.val, *bufp, val_len, + (unsigned long)(*bufp-bufstart), bc, 1, + d)) + return 1; + *bufp += val_len; + } + break; + case DV_RAW: + for (i=0; i<multiple; i++) { + memcpy(*bufp, dv->data.raw.contents, dv->data.raw.len); + *bufp += dv->data.raw.len; + } + break; + case DV_ULEB128: + case DV_SLEB128: + intn = yasm_expr_get_intnum(&dv->data.val.abs, 234); + if (!intn) + yasm_internal_error(N_("non-constant in data_tobytes")); + for (i=0; i<multiple; i++) { + *bufp += + yasm_intnum_get_leb128(intn, *bufp, + dv->type == DV_SLEB128); + } + case DV_RESERVE: + val_len = dv->data.val.size/8; + for (i=0; i<multiple; i++) { + memset(*bufp, 0, val_len); + *bufp += val_len; + } + break; + } + } + + return 0; +} + +yasm_bytecode * +yasm_bc_create_data(yasm_datavalhead *datahead, unsigned int size, + int append_zero, yasm_arch *arch, unsigned long line) +{ + bytecode_data *data = yasm_xmalloc(sizeof(bytecode_data)); + yasm_bytecode *bc = yasm_bc_create_common(&bc_data_callback, data, line); + yasm_dataval *dv, *dv2, *dvo; + yasm_intnum *intn; + unsigned long len = 0, rlen, i; + + + yasm_dvs_initialize(&data->datahead); + data->item_size = size; + + /* Prescan input data for length, etc. Careful: this needs to be + * precisely paired with the second loop. + */ + STAILQ_FOREACH(dv, datahead, link) { + if (dv->multiple && dv->type != DV_EMPTY && len > 0) { + /* Flush previous data */ + dvo = yasm_dv_create_raw(yasm_xmalloc(len), len); + STAILQ_INSERT_TAIL(&data->datahead, dvo, link); + len = 0; + } + switch (dv->type) { + case DV_EMPTY: + break; + case DV_VALUE: + case DV_ULEB128: + case DV_SLEB128: + intn = yasm_expr_get_intnum(&dv->data.val.abs, 0); + if (intn && dv->type == DV_VALUE && (arch || size == 1)) + len += size; + else if (intn && dv->type == DV_ULEB128) + len += yasm_intnum_size_leb128(intn, 0); + else if (intn && dv->type == DV_SLEB128) + len += yasm_intnum_size_leb128(intn, 1); + else { + if (len > 0) { + /* Create bytecode for all previous len */ + dvo = yasm_dv_create_raw(yasm_xmalloc(len), len); + STAILQ_INSERT_TAIL(&data->datahead, dvo, link); + len = 0; + } + + /* Create bytecode for this value */ + dvo = yasm_xmalloc(sizeof(yasm_dataval)); + STAILQ_INSERT_TAIL(&data->datahead, dvo, link); + dvo->multiple = dv->multiple; + } + break; + case DV_RAW: + rlen = dv->data.raw.len; + /* find count, rounding up to nearest multiple of size */ + rlen = (rlen + size - 1) / size; + len += rlen*size; + break; + case DV_RESERVE: + len += size; + break; + } + + if (dv->multiple && dv->type != DV_EMPTY && len > 0) { + /* Flush this data */ + dvo = yasm_dv_create_raw(yasm_xmalloc(len), len); + STAILQ_INSERT_TAIL(&data->datahead, dvo, link); + dvo->multiple = dv->multiple; + len = 0; + } + + if (append_zero) + len++; + } + + /* Create final dataval for any trailing length */ + if (len > 0) { + dvo = yasm_dv_create_raw(yasm_xmalloc(len), len); + STAILQ_INSERT_TAIL(&data->datahead, dvo, link); + } + + /* Second iteration: copy data and delete input datavals. */ + dv = STAILQ_FIRST(datahead); + dvo = STAILQ_FIRST(&data->datahead); + len = 0; + while (dv && dvo) { + if (dv->multiple && dv->type != DV_EMPTY && len > 0) { + dvo = STAILQ_NEXT(dvo, link); + len = 0; + } + switch (dv->type) { + case DV_EMPTY: + break; + case DV_VALUE: + case DV_ULEB128: + case DV_SLEB128: + intn = yasm_expr_get_intnum(&dv->data.val.abs, 0); + if (intn && dv->type == DV_VALUE && (arch || size == 1)) { + if (size == 1) + yasm_intnum_get_sized(intn, + &dvo->data.raw.contents[len], + 1, 8, 0, 0, 1); + else + yasm_arch_intnum_tobytes(arch, intn, + &dvo->data.raw.contents[len], + size, size*8, 0, bc, 1); + yasm_value_delete(&dv->data.val); + len += size; + } else if (intn && dv->type == DV_ULEB128) { + len += yasm_intnum_get_leb128(intn, + &dvo->data.raw.contents[len], + 0); + yasm_value_delete(&dv->data.val); + } else if (intn && dv->type == DV_SLEB128) { + len += yasm_intnum_get_leb128(intn, + &dvo->data.raw.contents[len], + 1); + yasm_value_delete(&dv->data.val); + } else { + if (len > 0) + dvo = STAILQ_NEXT(dvo, link); + dvo->type = dv->type; + dvo->data.val = dv->data.val; /* structure copy */ + dvo->data.val.size = size*8; /* remember size */ + dvo = STAILQ_NEXT(dvo, link); + len = 0; + } + break; + case DV_RAW: + rlen = dv->data.raw.len; + memcpy(&dvo->data.raw.contents[len], dv->data.raw.contents, + rlen); + yasm_xfree(dv->data.raw.contents); + len += rlen; + /* pad with 0's to nearest multiple of size */ + rlen %= size; + if (rlen > 0) { + rlen = size-rlen; + for (i=0; i<rlen; i++) + dvo->data.raw.contents[len++] = 0; + } + break; + case DV_RESERVE: + memset(&dvo->data.raw.contents[len], 0, size); + len += size; + break; + } + + if (dv->multiple && dv->type != DV_EMPTY && len > 0) { + dvo = STAILQ_NEXT(dvo, link); + len = 0; + } + + if (append_zero) + dvo->data.raw.contents[len++] = 0; + dv2 = STAILQ_NEXT(dv, link); + yasm_xfree(dv); + dv = dv2; + } + + return bc; +} + +yasm_bytecode * +yasm_bc_create_leb128(yasm_datavalhead *datahead, int sign, unsigned long line) +{ + yasm_dataval *dv; + + /* Convert all values into LEB type, error on strings/raws */ + STAILQ_FOREACH(dv, datahead, link) { + switch (dv->type) { + case DV_VALUE: + dv->type = sign ? DV_SLEB128 : DV_ULEB128; + break; + case DV_RAW: + yasm_error_set(YASM_ERROR_VALUE, + N_("LEB128 does not allow string constants")); + break; + default: + break; + } + } + + return yasm_bc_create_data(datahead, 0, 0, 0, line); +} + +yasm_dataval * +yasm_dv_create_expr(yasm_expr *e) +{ + yasm_dataval *retval = yasm_xmalloc(sizeof(yasm_dataval)); + + retval->type = DV_VALUE; + yasm_value_initialize(&retval->data.val, e, 0); + retval->multiple = NULL; + + return retval; +} + +yasm_dataval * +yasm_dv_create_raw(unsigned char *contents, unsigned long len) +{ + yasm_dataval *retval = yasm_xmalloc(sizeof(yasm_dataval)); + + retval->type = DV_RAW; + retval->data.raw.contents = contents; + retval->data.raw.len = len; + retval->multiple = NULL; + + return retval; +} + +yasm_dataval * +yasm_dv_create_reserve(void) +{ + yasm_dataval *retval = yasm_xmalloc(sizeof(yasm_dataval)); + + retval->type = DV_RESERVE; + retval->multiple = NULL; + + return retval; +} + +yasm_value * +yasm_dv_get_value(yasm_dataval *dv) +{ + if (dv->type != DV_VALUE) + return NULL; + return &dv->data.val; +} + +void +yasm_dv_set_multiple(yasm_dataval *dv, yasm_expr *e) +{ + if (dv->multiple) + dv->multiple = yasm_expr_create_tree( dv->multiple, YASM_EXPR_MUL, e, + e->line); + else + dv->multiple = e; +} + +int +yasm_dv_get_multiple(yasm_dataval *dv, unsigned long *multiple) +{ + /*@dependent@*/ /*@null@*/ const yasm_intnum *num; + + *multiple = 1; + if (dv->multiple) { + num = yasm_expr_get_intnum(&dv->multiple, 0); + if (!num) { + yasm_error_set(YASM_ERROR_VALUE, + N_("could not determine multiple")); + return 1; + } + if (yasm_intnum_sign(num) < 0) { + yasm_error_set(YASM_ERROR_VALUE, N_("multiple is negative")); + return 1; + } + *multiple = yasm_intnum_get_uint(num); + } + return 0; +} + +void +yasm_dvs_delete(yasm_datavalhead *headp) +{ + yasm_dataval *cur, *next; + + cur = STAILQ_FIRST(headp); + while (cur) { + next = STAILQ_NEXT(cur, link); + switch (cur->type) { + case DV_VALUE: + yasm_value_delete(&cur->data.val); + break; + case DV_RAW: + yasm_xfree(cur->data.raw.contents); + break; + default: + break; + } + if (cur->multiple) + yasm_expr_destroy(cur->multiple); + yasm_xfree(cur); + cur = next; + } + STAILQ_INIT(headp); +} + +yasm_dataval * +yasm_dvs_append(yasm_datavalhead *headp, yasm_dataval *dv) +{ + if (dv) { + STAILQ_INSERT_TAIL(headp, dv, link); + return dv; + } + return (yasm_dataval *)NULL; +} + +void +yasm_dvs_print(const yasm_datavalhead *head, FILE *f, int indent_level) +{ + yasm_dataval *cur; + unsigned long i; + + STAILQ_FOREACH(cur, head, link) { + fprintf(f, "%*sMultiple=", indent_level, ""); + if (!cur->multiple) + fprintf(f, "nil (1)"); + else + yasm_expr_print(cur->multiple, f); + switch (cur->type) { + case DV_EMPTY: + fprintf(f, "%*sEmpty\n", indent_level, ""); + break; + case DV_VALUE: + fprintf(f, "%*sValue:\n", indent_level, ""); + yasm_value_print(&cur->data.val, f, indent_level+1); + break; + case DV_RAW: + fprintf(f, "%*sLength=%lu\n", indent_level, "", + cur->data.raw.len); + fprintf(f, "%*sBytes=[", indent_level, ""); + for (i=0; i<cur->data.raw.len; i++) + fprintf(f, "0x%02x, ", cur->data.raw.contents[i]); + fprintf(f, "]\n"); + break; + case DV_ULEB128: + fprintf(f, "%*sULEB128 value:\n", indent_level, ""); + yasm_value_print(&cur->data.val, f, indent_level+1); + break; + case DV_SLEB128: + fprintf(f, "%*sSLEB128 value:\n", indent_level, ""); + yasm_value_print(&cur->data.val, f, indent_level+1); + break; + case DV_RESERVE: + fprintf(f, "%*sReserved\n", indent_level, ""); + break; + } + } +} diff --git a/contrib/tools/yasm/libyasm/bc-incbin.c b/contrib/tools/yasm/libyasm/bc-incbin.c new file mode 100644 index 0000000000..a8fec7d6ce --- /dev/null +++ b/contrib/tools/yasm/libyasm/bc-incbin.c @@ -0,0 +1,265 @@ +/* + * Incbin bytecode + * + * 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-stdint.h" +#include "coretype.h" + +#include "linemap.h" + +#include "errwarn.h" +#include "intnum.h" +#include "expr.h" +#include "value.h" + +#include "bytecode.h" + +#include "file.h" + + +typedef struct bytecode_incbin { + /*@only@*/ char *filename; /* file to include data from */ + const char *from; /* filename of what contained incbin */ + + /* starting offset to read from (NULL=0) */ + /*@only@*/ /*@null@*/ yasm_expr *start; + + /* maximum number of bytes to read (NULL=no limit) */ + /*@only@*/ /*@null@*/ yasm_expr *maxlen; +} bytecode_incbin; + +static void bc_incbin_destroy(void *contents); +static void bc_incbin_print(const void *contents, FILE *f, int indent_level); +static void bc_incbin_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc); +static int bc_incbin_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span, + void *add_span_data); +static int bc_incbin_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 const yasm_bytecode_callback bc_incbin_callback = { + bc_incbin_destroy, + bc_incbin_print, + bc_incbin_finalize, + NULL, + bc_incbin_calc_len, + yasm_bc_expand_common, + bc_incbin_tobytes, + 0 +}; + + +static void +bc_incbin_destroy(void *contents) +{ + bytecode_incbin *incbin = (bytecode_incbin *)contents; + yasm_xfree(incbin->filename); + yasm_expr_destroy(incbin->start); + yasm_expr_destroy(incbin->maxlen); + yasm_xfree(contents); +} + +static void +bc_incbin_print(const void *contents, FILE *f, int indent_level) +{ + const bytecode_incbin *incbin = (const bytecode_incbin *)contents; + fprintf(f, "%*s_IncBin_\n", indent_level, ""); + fprintf(f, "%*sFilename=`%s'\n", indent_level, "", + incbin->filename); + fprintf(f, "%*sStart=", indent_level, ""); + if (!incbin->start) + fprintf(f, "nil (0)"); + else + yasm_expr_print(incbin->start, f); + fprintf(f, "%*sMax Len=", indent_level, ""); + if (!incbin->maxlen) + fprintf(f, "nil (unlimited)"); + else + yasm_expr_print(incbin->maxlen, f); + fprintf(f, "\n"); +} + +static void +bc_incbin_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc) +{ + bytecode_incbin *incbin = (bytecode_incbin *)bc->contents; + yasm_value val; + + if (yasm_value_finalize_expr(&val, incbin->start, prev_bc, 0)) + yasm_error_set(YASM_ERROR_TOO_COMPLEX, + N_("start expression too complex")); + else if (val.rel) + yasm_error_set(YASM_ERROR_NOT_ABSOLUTE, + N_("start expression not absolute")); + incbin->start = val.abs; + + if (yasm_value_finalize_expr(&val, incbin->maxlen, prev_bc, 0)) + yasm_error_set(YASM_ERROR_TOO_COMPLEX, + N_("maximum length expression too complex")); + else if (val.rel) + yasm_error_set(YASM_ERROR_NOT_ABSOLUTE, + N_("maximum length expression not absolute")); + incbin->maxlen = val.abs; +} + +static int +bc_incbin_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span, + void *add_span_data) +{ + bytecode_incbin *incbin = (bytecode_incbin *)bc->contents; + FILE *f; + /*@dependent@*/ /*@null@*/ const yasm_intnum *num; + unsigned long start = 0, maxlen = 0xFFFFFFFFUL, flen; + + /* Try to convert start to integer value */ + if (incbin->start) { + num = yasm_expr_get_intnum(&incbin->start, 0); + if (num) + start = yasm_intnum_get_uint(num); + if (!num) { + /* FIXME */ + yasm_error_set(YASM_ERROR_NOT_IMPLEMENTED, + N_("incbin does not yet understand non-constant")); + return -1; + } + } + + /* Try to convert maxlen to integer value */ + if (incbin->maxlen) { + num = yasm_expr_get_intnum(&incbin->maxlen, 0); + if (num) + maxlen = yasm_intnum_get_uint(num); + if (!num) { + /* FIXME */ + yasm_error_set(YASM_ERROR_NOT_IMPLEMENTED, + N_("incbin does not yet understand non-constant")); + return -1; + } + } + + /* Open file and determine its length */ + f = yasm_fopen_include(incbin->filename, incbin->from, "rb", NULL); + if (!f) { + yasm_error_set(YASM_ERROR_IO, + N_("`incbin': unable to open file `%s'"), + incbin->filename); + return -1; + } + if (fseek(f, 0L, SEEK_END) < 0) { + yasm_error_set(YASM_ERROR_IO, + N_("`incbin': unable to seek on file `%s'"), + incbin->filename); + return -1; + } + flen = (unsigned long)ftell(f); + fclose(f); + + /* Compute length of incbin from start, maxlen, and len */ + if (start > flen) { + yasm_warn_set(YASM_WARN_GENERAL, + N_("`incbin': start past end of file `%s'"), + incbin->filename); + start = flen; + } + flen -= start; + if (incbin->maxlen) + if (maxlen < flen) + flen = maxlen; + bc->len += flen; + return 0; +} + +static int +bc_incbin_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) +{ + bytecode_incbin *incbin = (bytecode_incbin *)bc->contents; + FILE *f; + /*@dependent@*/ /*@null@*/ const yasm_intnum *num; + unsigned long start = 0; + + /* Convert start to integer value */ + if (incbin->start) { + num = yasm_expr_get_intnum(&incbin->start, 0); + if (!num) + yasm_internal_error( + N_("could not determine start in bc_tobytes_incbin")); + start = yasm_intnum_get_uint(num); + } + + /* Open file */ + f = yasm_fopen_include(incbin->filename, incbin->from, "rb", NULL); + if (!f) { + yasm_error_set(YASM_ERROR_IO, N_("`incbin': unable to open file `%s'"), + incbin->filename); + return 1; + } + + /* Seek to start of data */ + if (fseek(f, (long)start, SEEK_SET) < 0) { + yasm_error_set(YASM_ERROR_IO, + N_("`incbin': unable to seek on file `%s'"), + incbin->filename); + fclose(f); + return 1; + } + + /* Read len bytes */ + if (fread(*bufp, 1, (size_t)bc->len, f) < (size_t)bc->len) { + yasm_error_set(YASM_ERROR_IO, + N_("`incbin': unable to read %lu bytes from file `%s'"), + bc->len, incbin->filename); + fclose(f); + return 1; + } + + *bufp += bc->len; + fclose(f); + return 0; +} + +yasm_bytecode * +yasm_bc_create_incbin(char *filename, yasm_expr *start, yasm_expr *maxlen, + yasm_linemap *linemap, unsigned long line) +{ + bytecode_incbin *incbin = yasm_xmalloc(sizeof(bytecode_incbin)); + unsigned long xline; + + /* Find from filename based on line number */ + yasm_linemap_lookup(linemap, line, &incbin->from, &xline); + + /*@-mustfree@*/ + incbin->filename = filename; + incbin->start = start; + incbin->maxlen = maxlen; + /*@=mustfree@*/ + + return yasm_bc_create_common(&bc_incbin_callback, incbin, line); +} diff --git a/contrib/tools/yasm/libyasm/bc-org.c b/contrib/tools/yasm/libyasm/bc-org.c new file mode 100644 index 0000000000..7ef96c8412 --- /dev/null +++ b/contrib/tools/yasm/libyasm/bc-org.c @@ -0,0 +1,152 @@ +/* + * ORG bytecode + * + * Copyright (C) 2005-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-stdint.h" +#include "coretype.h" +#include "file.h" + +#include "errwarn.h" +#include "intnum.h" +#include "expr.h" +#include "value.h" + +#include "bytecode.h" + + +typedef struct bytecode_org { + unsigned long start; /* target starting offset within section */ + unsigned long fill; /* fill value */ +} bytecode_org; + +static void bc_org_destroy(void *contents); +static void bc_org_print(const void *contents, FILE *f, int indent_level); +static void bc_org_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc); +static int bc_org_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span, + void *add_span_data); +static int bc_org_expand(yasm_bytecode *bc, int span, long old_val, + long new_val, /*@out@*/ long *neg_thres, + /*@out@*/ long *pos_thres); +static int bc_org_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 const yasm_bytecode_callback bc_org_callback = { + bc_org_destroy, + bc_org_print, + bc_org_finalize, + NULL, + bc_org_calc_len, + bc_org_expand, + bc_org_tobytes, + YASM_BC_SPECIAL_OFFSET +}; + + +static void +bc_org_destroy(void *contents) +{ + yasm_xfree(contents); +} + +static void +bc_org_print(const void *contents, FILE *f, int indent_level) +{ + const bytecode_org *org = (const bytecode_org *)contents; + fprintf(f, "%*s_Org_\n", indent_level, ""); + fprintf(f, "%*sStart=%lu\n", indent_level, "", org->start); +} + +static void +bc_org_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc) +{ +} + +static int +bc_org_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span, + void *add_span_data) +{ + bytecode_org *org = (bytecode_org *)bc->contents; + long neg_thres = 0; + long pos_thres = org->start; + + if (bc_org_expand(bc, 0, 0, (long)bc->offset, &neg_thres, &pos_thres) < 0) + return -1; + + return 0; +} + +static int +bc_org_expand(yasm_bytecode *bc, int span, long old_val, long new_val, + /*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres) +{ + bytecode_org *org = (bytecode_org *)bc->contents; + + /* Check for overrun */ + if ((unsigned long)new_val > org->start) { + yasm_error_set(YASM_ERROR_GENERAL, + N_("ORG overlap with already existing data")); + return -1; + } + + /* Generate space to start offset */ + bc->len = org->start - new_val; + return 1; +} + +static int +bc_org_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) +{ + bytecode_org *org = (bytecode_org *)bc->contents; + unsigned long len, i; + + /* Sanity check for overrun */ + if (bc->offset > org->start) { + yasm_error_set(YASM_ERROR_GENERAL, + N_("ORG overlap with already existing data")); + return 1; + } + len = org->start - bc->offset; + for (i=0; i<len; i++) + YASM_WRITE_8(*bufp, org->fill); /* XXX: handle more than 8 bit? */ + return 0; +} + +yasm_bytecode * +yasm_bc_create_org(unsigned long start, unsigned long fill, unsigned long line) +{ + bytecode_org *org = yasm_xmalloc(sizeof(bytecode_org)); + + org->start = start; + org->fill = fill; + + return yasm_bc_create_common(&bc_org_callback, org, line); +} diff --git a/contrib/tools/yasm/libyasm/bc-reserve.c b/contrib/tools/yasm/libyasm/bc-reserve.c new file mode 100644 index 0000000000..197175b4e5 --- /dev/null +++ b/contrib/tools/yasm/libyasm/bc-reserve.c @@ -0,0 +1,152 @@ +/* + * 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-stdint.h" +#include "coretype.h" + +#include "errwarn.h" +#include "intnum.h" +#include "expr.h" +#include "value.h" + +#include "bytecode.h" + + +typedef struct bytecode_reserve { + /*@only@*/ /*@null@*/ yasm_expr *numitems; /* number of items to reserve */ + unsigned int itemsize; /* size of each item (in bytes) */ +} bytecode_reserve; + +static void bc_reserve_destroy(void *contents); +static void bc_reserve_print(const void *contents, FILE *f, int indent_level); +static void bc_reserve_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc); +static int bc_reserve_elem_size(yasm_bytecode *bc); +static int bc_reserve_calc_len(yasm_bytecode *bc, + yasm_bc_add_span_func add_span, + void *add_span_data); +static int bc_reserve_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 const yasm_bytecode_callback bc_reserve_callback = { + bc_reserve_destroy, + bc_reserve_print, + bc_reserve_finalize, + bc_reserve_elem_size, + bc_reserve_calc_len, + yasm_bc_expand_common, + bc_reserve_tobytes, + YASM_BC_SPECIAL_RESERVE +}; + + +static void +bc_reserve_destroy(void *contents) +{ + bytecode_reserve *reserve = (bytecode_reserve *)contents; + yasm_expr_destroy(reserve->numitems); + yasm_xfree(contents); +} + +static void +bc_reserve_print(const void *contents, FILE *f, int indent_level) +{ + const bytecode_reserve *reserve = (const bytecode_reserve *)contents; + fprintf(f, "%*s_Reserve_\n", indent_level, ""); + fprintf(f, "%*sNum Items=", indent_level, ""); + yasm_expr_print(reserve->numitems, f); + fprintf(f, "\n%*sItem Size=%u\n", indent_level, "", reserve->itemsize); +} + +static void +bc_reserve_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc) +{ + bytecode_reserve *reserve = (bytecode_reserve *)bc->contents; + /* multiply reserve expression into multiple */ + if (!bc->multiple) + bc->multiple = reserve->numitems; + else + bc->multiple = yasm_expr_create_tree(bc->multiple, YASM_EXPR_MUL, + reserve->numitems, bc->line); + reserve->numitems = NULL; +} + +static int +bc_reserve_elem_size(yasm_bytecode *bc) +{ + bytecode_reserve *reserve = (bytecode_reserve *)bc->contents; + return reserve->itemsize; +} + +static int +bc_reserve_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span, + void *add_span_data) +{ + bytecode_reserve *reserve = (bytecode_reserve *)bc->contents; + bc->len += reserve->itemsize; + return 0; +} + +static int +bc_reserve_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) +{ + yasm_internal_error(N_("bc_reserve_tobytes called")); + /*@notreached@*/ + return 1; +} + +yasm_bytecode * +yasm_bc_create_reserve(yasm_expr *numitems, unsigned int itemsize, + unsigned long line) +{ + bytecode_reserve *reserve = yasm_xmalloc(sizeof(bytecode_reserve)); + + /*@-mustfree@*/ + reserve->numitems = numitems; + /*@=mustfree@*/ + reserve->itemsize = itemsize; + + return yasm_bc_create_common(&bc_reserve_callback, reserve, line); +} + +const yasm_expr * +yasm_bc_reserve_numitems(yasm_bytecode *bc, unsigned int *itemsize) +{ + bytecode_reserve *reserve; + + if (bc->callback != &bc_reserve_callback) + return NULL; + + reserve = (bytecode_reserve *)bc->contents; + *itemsize = reserve->itemsize; + return reserve->numitems; +} diff --git a/contrib/tools/yasm/libyasm/bitvect.c b/contrib/tools/yasm/libyasm/bitvect.c new file mode 100644 index 0000000000..dfb08252b0 --- /dev/null +++ b/contrib/tools/yasm/libyasm/bitvect.c @@ -0,0 +1,4045 @@ +#include "util.h" + +#include "coretype.h" + +/*****************************************************************************/ +/* MODULE NAME: BitVector.c MODULE TYPE: (adt) */ +/*****************************************************************************/ +/* MODULE IMPORTS: */ +/*****************************************************************************/ +#include <ctype.h> /* MODULE TYPE: (sys) */ +#include <limits.h> /* MODULE TYPE: (sys) */ +#include <string.h> /* MODULE TYPE: (sys) */ +/*****************************************************************************/ +/* MODULE INTERFACE: */ +/*****************************************************************************/ +#include "bitvect.h" + +/* ToolBox.h */ +#define and && /* logical (boolean) operators: lower case */ +#define or || +#define not ! + +#define AND & /* binary (bitwise) operators: UPPER CASE */ +#define OR | +#define XOR ^ +#define NOT ~ +#define SHL << +#define SHR >> + +#ifdef ENABLE_MODULO +#define mod % /* arithmetic operators */ +#endif + +#define blockdef(name,size) unsigned char name[size] +#define blocktypedef(name,size) typedef unsigned char name[size] + +/*****************************************************************************/ +/* MODULE RESOURCES: */ +/*****************************************************************************/ + +#define bits_(BitVector) *(BitVector-3) +#define size_(BitVector) *(BitVector-2) +#define mask_(BitVector) *(BitVector-1) + +#define ERRCODE_TYPE "sizeof(word) > sizeof(size_t)" +#define ERRCODE_BITS "bits(word) != sizeof(word)*8" +#define ERRCODE_WORD "bits(word) < 16" +#define ERRCODE_LONG "bits(word) > bits(long)" +#define ERRCODE_POWR "bits(word) != 2^x" +#define ERRCODE_LOGA "bits(word) != 2^ld(bits(word))" +#define ERRCODE_NULL "unable to allocate memory" +#define ERRCODE_INDX "index out of range" +#define ERRCODE_ORDR "minimum > maximum index" +#define ERRCODE_SIZE "bit vector size mismatch" +#define ERRCODE_PARS "input string syntax error" +#define ERRCODE_OVFL "numeric overflow error" +#define ERRCODE_SAME "result vector(s) must be distinct" +#define ERRCODE_EXPO "exponent must be positive" +#define ERRCODE_ZERO "division by zero error" +#define ERRCODE_OOPS "unexpected internal error - please contact author" + +const N_int BitVector_BYTENORM[256] = +{ + 0x00, 0x01, 0x01, 0x02, 0x01, 0x02, 0x02, 0x03, + 0x01, 0x02, 0x02, 0x03, 0x02, 0x03, 0x03, 0x04, /* 0x00 */ + 0x01, 0x02, 0x02, 0x03, 0x02, 0x03, 0x03, 0x04, + 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05, /* 0x10 */ + 0x01, 0x02, 0x02, 0x03, 0x02, 0x03, 0x03, 0x04, + 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05, /* 0x20 */ + 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05, + 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06, /* 0x30 */ + 0x01, 0x02, 0x02, 0x03, 0x02, 0x03, 0x03, 0x04, + 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05, /* 0x40 */ + 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05, + 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06, /* 0x50 */ + 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05, + 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06, /* 0x60 */ + 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06, + 0x04, 0x05, 0x05, 0x06, 0x05, 0x06, 0x06, 0x07, /* 0x70 */ + 0x01, 0x02, 0x02, 0x03, 0x02, 0x03, 0x03, 0x04, + 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05, /* 0x80 */ + 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05, + 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06, /* 0x90 */ + 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05, + 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06, /* 0xA0 */ + 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06, + 0x04, 0x05, 0x05, 0x06, 0x05, 0x06, 0x06, 0x07, /* 0xB0 */ + 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05, + 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06, /* 0xC0 */ + 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06, + 0x04, 0x05, 0x05, 0x06, 0x05, 0x06, 0x06, 0x07, /* 0xD0 */ + 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06, + 0x04, 0x05, 0x05, 0x06, 0x05, 0x06, 0x06, 0x07, /* 0xE0 */ + 0x04, 0x05, 0x05, 0x06, 0x05, 0x06, 0x06, 0x07, + 0x05, 0x06, 0x06, 0x07, 0x06, 0x07, 0x07, 0x08 /* 0xF0 */ +}; + +/*****************************************************************************/ +/* MODULE IMPLEMENTATION: */ +/*****************************************************************************/ + + /**********************************************/ + /* global implementation-intrinsic constants: */ + /**********************************************/ + +#define BIT_VECTOR_HIDDEN_WORDS 3 + + /*****************************************************************/ + /* global machine-dependent constants (set by "BitVector_Boot"): */ + /*****************************************************************/ + +static N_word BITS; /* = # of bits in machine word (must be power of 2) */ +static N_word MODMASK; /* = BITS - 1 (mask for calculating modulo BITS) */ +static N_word LOGBITS; /* = ld(BITS) (logarithmus dualis) */ +static N_word FACTOR; /* = ld(BITS / 8) (ld of # of bytes) */ + +static N_word LSB = 1; /* = mask for least significant bit */ +static N_word MSB; /* = mask for most significant bit */ + +static N_word LONGBITS; /* = # of bits in unsigned long */ + +static N_word LOG10; /* = logarithm to base 10 of BITS - 1 */ +static N_word EXP10; /* = largest possible power of 10 in signed int */ + + /********************************************************************/ + /* global bit mask table for fast access (set by "BitVector_Boot"): */ + /********************************************************************/ + +static wordptr BITMASKTAB; + + /*****************************/ + /* global macro definitions: */ + /*****************************/ + +#define BIT_VECTOR_ZERO_WORDS(target,count) \ + while (count-- > 0) *target++ = 0; + +#define BIT_VECTOR_FILL_WORDS(target,fill,count) \ + while (count-- > 0) *target++ = fill; + +#define BIT_VECTOR_FLIP_WORDS(target,flip,count) \ + while (count-- > 0) *target++ ^= flip; + +#define BIT_VECTOR_COPY_WORDS(target,source,count) \ + while (count-- > 0) *target++ = *source++; + +#define BIT_VECTOR_BACK_WORDS(target,source,count) \ + { target += count; source += count; while (count-- > 0) *--target = *--source; } + +#define BIT_VECTOR_CLR_BIT(address,index) \ + *(address+(index>>LOGBITS)) &= NOT BITMASKTAB[index AND MODMASK]; + +#define BIT_VECTOR_SET_BIT(address,index) \ + *(address+(index>>LOGBITS)) |= BITMASKTAB[index AND MODMASK]; + +#define BIT_VECTOR_TST_BIT(address,index) \ + ((*(address+(index>>LOGBITS)) AND BITMASKTAB[index AND MODMASK]) != 0) + +#define BIT_VECTOR_FLP_BIT(address,index,mask) \ + (mask = BITMASKTAB[index AND MODMASK]), \ + (((*(addr+(index>>LOGBITS)) ^= mask) AND mask) != 0) + +#define BIT_VECTOR_DIGITIZE(type,value,digit) \ + value = (type) ((digit = value) / 10); \ + digit -= value * 10; \ + digit += (type) '0'; + + /*********************************************************/ + /* private low-level functions (potentially dangerous!): */ + /*********************************************************/ + +static N_word power10(N_word x) +{ + N_word y = 1; + + while (x-- > 0) y *= 10; + return(y); +} + +static void BIT_VECTOR_zro_words(wordptr addr, N_word count) +{ + BIT_VECTOR_ZERO_WORDS(addr,count) +} + +static void BIT_VECTOR_cpy_words(wordptr target, wordptr source, N_word count) +{ + BIT_VECTOR_COPY_WORDS(target,source,count) +} + +static void BIT_VECTOR_mov_words(wordptr target, wordptr source, N_word count) +{ + if (target != source) + { + if (target < source) BIT_VECTOR_COPY_WORDS(target,source,count) + else BIT_VECTOR_BACK_WORDS(target,source,count) + } +} + +static void BIT_VECTOR_ins_words(wordptr addr, N_word total, N_word count, + boolean clear) +{ + N_word length; + + if ((total > 0) and (count > 0)) + { + if (count > total) count = total; + length = total - count; + if (length > 0) BIT_VECTOR_mov_words(addr+count,addr,length); + if (clear) BIT_VECTOR_zro_words(addr,count); + } +} + +static void BIT_VECTOR_del_words(wordptr addr, N_word total, N_word count, + boolean clear) +{ + N_word length; + + if ((total > 0) and (count > 0)) + { + if (count > total) count = total; + length = total - count; + if (length > 0) BIT_VECTOR_mov_words(addr,addr+count,length); + if (clear) BIT_VECTOR_zro_words(addr+length,count); + } +} + +static void BIT_VECTOR_reverse(charptr string, N_word length) +{ + charptr last; + N_char temp; + + if (length > 1) + { + last = string + length - 1; + while (string < last) + { + temp = *string; + *string = *last; + *last = temp; + string++; + last--; + } + } +} + +static N_word BIT_VECTOR_int2str(charptr string, N_word value) +{ + N_word length; + N_word digit; + charptr work; + + work = string; + if (value > 0) + { + length = 0; + while (value > 0) + { + BIT_VECTOR_DIGITIZE(N_word,value,digit) + *work++ = (N_char) digit; + length++; + } + BIT_VECTOR_reverse(string,length); + } + else + { + length = 1; + *work++ = (N_char) '0'; + } + return(length); +} + +static N_word BIT_VECTOR_str2int(charptr string, N_word *value) +{ + N_word length; + N_word digit; + + *value = 0; + length = 0; + digit = (N_word) *string++; + /* separate because isdigit() is likely a macro! */ + while (isdigit((int)digit) != 0) + { + length++; + digit -= (N_word) '0'; + if (*value) *value *= 10; + *value += digit; + digit = (N_word) *string++; + } + return(length); +} + + /********************************************/ + /* routine to convert error code to string: */ + /********************************************/ + +const char * BitVector_Error(ErrCode error) +{ + switch (error) + { + case ErrCode_Ok: return( NULL ); break; + case ErrCode_Type: return( ERRCODE_TYPE ); break; + case ErrCode_Bits: return( ERRCODE_BITS ); break; + case ErrCode_Word: return( ERRCODE_WORD ); break; + case ErrCode_Long: return( ERRCODE_LONG ); break; + case ErrCode_Powr: return( ERRCODE_POWR ); break; + case ErrCode_Loga: return( ERRCODE_LOGA ); break; + case ErrCode_Null: return( ERRCODE_NULL ); break; + case ErrCode_Indx: return( ERRCODE_INDX ); break; + case ErrCode_Ordr: return( ERRCODE_ORDR ); break; + case ErrCode_Size: return( ERRCODE_SIZE ); break; + case ErrCode_Pars: return( ERRCODE_PARS ); break; + case ErrCode_Ovfl: return( ERRCODE_OVFL ); break; + case ErrCode_Same: return( ERRCODE_SAME ); break; + case ErrCode_Expo: return( ERRCODE_EXPO ); break; + case ErrCode_Zero: return( ERRCODE_ZERO ); break; + default: return( ERRCODE_OOPS ); break; + } +} + + /*****************************************/ + /* automatic self-configuration routine: */ + /*****************************************/ + + /*******************************************************/ + /* */ + /* MUST be called once prior to any other function */ + /* to initialize the machine dependent constants */ + /* of this package! (But call only ONCE, or you */ + /* will suffer memory leaks!) */ + /* */ + /*******************************************************/ + +ErrCode BitVector_Boot(void) +{ + N_long longsample = 1L; + N_word sample = LSB; + N_word lsb; + + if (sizeof(N_word) > sizeof(size_t)) return(ErrCode_Type); + + BITS = 1; + while (sample <<= 1) BITS++; /* determine # of bits in a machine word */ + + if (BITS != (sizeof(N_word) << 3)) return(ErrCode_Bits); + + if (BITS < 16) return(ErrCode_Word); + + LONGBITS = 1; + while (longsample <<= 1) LONGBITS++; /* = # of bits in an unsigned long */ + + if (BITS > LONGBITS) return(ErrCode_Long); + + LOGBITS = 0; + sample = BITS; + lsb = (sample AND LSB); + while ((sample >>= 1) and (not lsb)) + { + LOGBITS++; + lsb = (sample AND LSB); + } + + if (sample) return(ErrCode_Powr); /* # of bits is not a power of 2! */ + + if (BITS != (LSB << LOGBITS)) return(ErrCode_Loga); + + MODMASK = BITS - 1; + FACTOR = LOGBITS - 3; /* ld(BITS / 8) = ld(BITS) - ld(8) = ld(BITS) - 3 */ + MSB = (LSB << MODMASK); + + BITMASKTAB = (wordptr) yasm_xmalloc((size_t) (BITS << FACTOR)); + + if (BITMASKTAB == NULL) return(ErrCode_Null); + + for ( sample = 0; sample < BITS; sample++ ) + { + BITMASKTAB[sample] = (LSB << sample); + } + + LOG10 = (N_word) (MODMASK * 0.30103); /* = (BITS - 1) * ( ln 2 / ln 10 ) */ + EXP10 = power10(LOG10); + + return(ErrCode_Ok); +} + +void BitVector_Shutdown(void) +{ + if (BITMASKTAB) yasm_xfree(BITMASKTAB); +} + +N_word BitVector_Size(N_int bits) /* bit vector size (# of words) */ +{ + N_word size; + + size = bits >> LOGBITS; + if (bits AND MODMASK) size++; + return(size); +} + +N_word BitVector_Mask(N_int bits) /* bit vector mask (unused bits) */ +{ + N_word mask; + + mask = bits AND MODMASK; + if (mask) mask = (N_word) ~(~0L << mask); else mask = (N_word) ~0L; + return(mask); +} + +const char * BitVector_Version(void) +{ + return("6.4"); +} + +N_int BitVector_Word_Bits(void) +{ + return(BITS); +} + +N_int BitVector_Long_Bits(void) +{ + return(LONGBITS); +} + +/********************************************************************/ +/* */ +/* WARNING: Do not "free()" constant character strings, i.e., */ +/* don't call "BitVector_Dispose()" for strings returned */ +/* by "BitVector_Error()" or "BitVector_Version()"! */ +/* */ +/* ONLY call this function for strings allocated with "malloc()", */ +/* i.e., the strings returned by the functions "BitVector_to_*()" */ +/* and "BitVector_Block_Read()"! */ +/* */ +/********************************************************************/ + +void BitVector_Dispose(charptr string) /* free string */ +{ + if (string != NULL) yasm_xfree((voidptr) string); +} + +void BitVector_Destroy(wordptr addr) /* free bitvec */ +{ + if (addr != NULL) + { + addr -= BIT_VECTOR_HIDDEN_WORDS; + yasm_xfree((voidptr) addr); + } +} + +void BitVector_Destroy_List(listptr list, N_int count) /* free list */ +{ + listptr slot; + + if (list != NULL) + { + slot = list; + while (count-- > 0) + { + BitVector_Destroy(*slot++); + } + free((voidptr) list); + } +} + +wordptr BitVector_Create(N_int bits, boolean clear) /* malloc */ +{ + N_word size; + N_word mask; + N_word bytes; + wordptr addr; + wordptr zero; + + size = BitVector_Size(bits); + mask = BitVector_Mask(bits); + bytes = (size + BIT_VECTOR_HIDDEN_WORDS) << FACTOR; + addr = (wordptr) yasm_xmalloc((size_t) bytes); + if (addr != NULL) + { + *addr++ = bits; + *addr++ = size; + *addr++ = mask; + if (clear) + { + zero = addr; + BIT_VECTOR_ZERO_WORDS(zero,size) + } + } + return(addr); +} + +listptr BitVector_Create_List(N_int bits, boolean clear, N_int count) +{ + listptr list = NULL; + listptr slot; + wordptr addr; + N_int i; + + if (count > 0) + { + list = (listptr) malloc(sizeof(wordptr) * count); + if (list != NULL) + { + slot = list; + for ( i = 0; i < count; i++ ) + { + addr = BitVector_Create(bits,clear); + if (addr == NULL) + { + BitVector_Destroy_List(list,i); + return(NULL); + } + *slot++ = addr; + } + } + } + return(list); +} + +wordptr BitVector_Resize(wordptr oldaddr, N_int bits) /* realloc */ +{ + N_word bytes; + N_word oldsize; + N_word oldmask; + N_word newsize; + N_word newmask; + wordptr newaddr; + wordptr source; + wordptr target; + + oldsize = size_(oldaddr); + oldmask = mask_(oldaddr); + newsize = BitVector_Size(bits); + newmask = BitVector_Mask(bits); + if (oldsize > 0) *(oldaddr+oldsize-1) &= oldmask; + if (newsize <= oldsize) + { + newaddr = oldaddr; + bits_(newaddr) = bits; + size_(newaddr) = newsize; + mask_(newaddr) = newmask; + if (newsize > 0) *(newaddr+newsize-1) &= newmask; + } + else + { + bytes = (newsize + BIT_VECTOR_HIDDEN_WORDS) << FACTOR; + newaddr = (wordptr) yasm_xmalloc((size_t) bytes); + if (newaddr != NULL) + { + *newaddr++ = bits; + *newaddr++ = newsize; + *newaddr++ = newmask; + target = newaddr; + source = oldaddr; + newsize -= oldsize; + BIT_VECTOR_COPY_WORDS(target,source,oldsize) + BIT_VECTOR_ZERO_WORDS(target,newsize) + } + BitVector_Destroy(oldaddr); + } + return(newaddr); +} + +wordptr BitVector_Shadow(wordptr addr) /* makes new, same size but empty */ +{ + return( BitVector_Create(bits_(addr),true) ); +} + +wordptr BitVector_Clone(wordptr addr) /* makes exact duplicate */ +{ + N_word bits; + wordptr twin; + + bits = bits_(addr); + twin = BitVector_Create(bits,false); + if ((twin != NULL) and (bits > 0)) + BIT_VECTOR_cpy_words(twin,addr,size_(addr)); + return(twin); +} + +wordptr BitVector_Concat(wordptr X, wordptr Y) /* returns concatenation */ +{ + /* BEWARE that X = most significant part, Y = least significant part! */ + + N_word bitsX; + N_word bitsY; + N_word bitsZ; + wordptr Z; + + bitsX = bits_(X); + bitsY = bits_(Y); + bitsZ = bitsX + bitsY; + Z = BitVector_Create(bitsZ,false); + if ((Z != NULL) and (bitsZ > 0)) + { + BIT_VECTOR_cpy_words(Z,Y,size_(Y)); + BitVector_Interval_Copy(Z,X,bitsY,0,bitsX); + *(Z+size_(Z)-1) &= mask_(Z); + } + return(Z); +} + +void BitVector_Copy(wordptr X, wordptr Y) /* X = Y */ +{ + N_word sizeX = size_(X); + N_word sizeY = size_(Y); + N_word maskX = mask_(X); + N_word maskY = mask_(Y); + N_word fill = 0; + wordptr lastX; + wordptr lastY; + + if ((X != Y) and (sizeX > 0)) + { + lastX = X + sizeX - 1; + if (sizeY > 0) + { + lastY = Y + sizeY - 1; + if ( (*lastY AND (maskY AND NOT (maskY >> 1))) == 0 ) *lastY &= maskY; + else + { + fill = (N_word) ~0L; + *lastY |= NOT maskY; + } + while ((sizeX > 0) and (sizeY > 0)) + { + *X++ = *Y++; + sizeX--; + sizeY--; + } + *lastY &= maskY; + } + while (sizeX-- > 0) *X++ = fill; + *lastX &= maskX; + } +} + +void BitVector_Empty(wordptr addr) /* X = {} clr all */ +{ + N_word size = size_(addr); + + BIT_VECTOR_ZERO_WORDS(addr,size) +} + +void BitVector_Fill(wordptr addr) /* X = ~{} set all */ +{ + N_word size = size_(addr); + N_word mask = mask_(addr); + N_word fill = (N_word) ~0L; + + if (size > 0) + { + BIT_VECTOR_FILL_WORDS(addr,fill,size) + *(--addr) &= mask; + } +} + +void BitVector_Flip(wordptr addr) /* X = ~X flip all */ +{ + N_word size = size_(addr); + N_word mask = mask_(addr); + N_word flip = (N_word) ~0L; + + if (size > 0) + { + BIT_VECTOR_FLIP_WORDS(addr,flip,size) + *(--addr) &= mask; + } +} + +void BitVector_Primes(wordptr addr) +{ + N_word bits = bits_(addr); + N_word size = size_(addr); + wordptr work; + N_word temp; + N_word i,j; + + if (size > 0) + { + temp = 0xAAAA; + i = BITS >> 4; + while (--i > 0) + { + temp <<= 16; + temp |= 0xAAAA; + } + i = size; + work = addr; + *work++ = temp XOR 0x0006; + while (--i > 0) *work++ = temp; + for ( i = 3; (j = i * i) < bits; i += 2 ) + { + for ( ; j < bits; j += i ) BIT_VECTOR_CLR_BIT(addr,j) + } + *(addr+size-1) &= mask_(addr); + } +} + +void BitVector_Reverse(wordptr X, wordptr Y) +{ + N_word bits = bits_(X); + N_word mask; + N_word bit; + N_word value; + + if (bits > 0) + { + if (X == Y) BitVector_Interval_Reverse(X,0,bits-1); + else if (bits == bits_(Y)) + { +/* mask = mask_(Y); */ +/* mask &= NOT (mask >> 1); */ + mask = BITMASKTAB[(bits-1) AND MODMASK]; + Y += size_(Y) - 1; + value = 0; + bit = LSB; + while (bits-- > 0) + { + if ((*Y AND mask) != 0) + { + value |= bit; + } + if (not (mask >>= 1)) + { + Y--; + mask = MSB; + } + if (not (bit <<= 1)) + { + *X++ = value; + value = 0; + bit = LSB; + } + } + if (bit > LSB) *X = value; + } + } +} + +void BitVector_Interval_Empty(wordptr addr, N_int lower, N_int upper) +{ /* X = X \ [lower..upper] */ + N_word bits = bits_(addr); + N_word size = size_(addr); + wordptr loaddr; + wordptr hiaddr; + N_word lobase; + N_word hibase; + N_word lomask; + N_word himask; + N_word diff; + + if ((size > 0) and (lower < bits) and (upper < bits) and (lower <= upper)) + { + lobase = lower >> LOGBITS; + hibase = upper >> LOGBITS; + diff = hibase - lobase; + loaddr = addr + lobase; + hiaddr = addr + hibase; + + lomask = (N_word) (~0L << (lower AND MODMASK)); + himask = (N_word) ~((~0L << (upper AND MODMASK)) << 1); + + if (diff == 0) + { + *loaddr &= NOT (lomask AND himask); + } + else + { + *loaddr++ &= NOT lomask; + while (--diff > 0) + { + *loaddr++ = 0; + } + *hiaddr &= NOT himask; + } + } +} + +void BitVector_Interval_Fill(wordptr addr, N_int lower, N_int upper) +{ /* X = X + [lower..upper] */ + N_word bits = bits_(addr); + N_word size = size_(addr); + N_word fill = (N_word) ~0L; + wordptr loaddr; + wordptr hiaddr; + N_word lobase; + N_word hibase; + N_word lomask; + N_word himask; + N_word diff; + + if ((size > 0) and (lower < bits) and (upper < bits) and (lower <= upper)) + { + lobase = lower >> LOGBITS; + hibase = upper >> LOGBITS; + diff = hibase - lobase; + loaddr = addr + lobase; + hiaddr = addr + hibase; + + lomask = (N_word) (~0L << (lower AND MODMASK)); + himask = (N_word) ~((~0L << (upper AND MODMASK)) << 1); + + if (diff == 0) + { + *loaddr |= (lomask AND himask); + } + else + { + *loaddr++ |= lomask; + while (--diff > 0) + { + *loaddr++ = fill; + } + *hiaddr |= himask; + } + *(addr+size-1) &= mask_(addr); + } +} + +void BitVector_Interval_Flip(wordptr addr, N_int lower, N_int upper) +{ /* X = X ^ [lower..upper] */ + N_word bits = bits_(addr); + N_word size = size_(addr); + N_word flip = (N_word) ~0L; + wordptr loaddr; + wordptr hiaddr; + N_word lobase; + N_word hibase; + N_word lomask; + N_word himask; + N_word diff; + + if ((size > 0) and (lower < bits) and (upper < bits) and (lower <= upper)) + { + lobase = lower >> LOGBITS; + hibase = upper >> LOGBITS; + diff = hibase - lobase; + loaddr = addr + lobase; + hiaddr = addr + hibase; + + lomask = (N_word) (~0L << (lower AND MODMASK)); + himask = (N_word) ~((~0L << (upper AND MODMASK)) << 1); + + if (diff == 0) + { + *loaddr ^= (lomask AND himask); + } + else + { + *loaddr++ ^= lomask; + while (--diff > 0) + { + *loaddr++ ^= flip; + } + *hiaddr ^= himask; + } + *(addr+size-1) &= mask_(addr); + } +} + +void BitVector_Interval_Reverse(wordptr addr, N_int lower, N_int upper) +{ + N_word bits = bits_(addr); + wordptr loaddr; + wordptr hiaddr; + N_word lomask; + N_word himask; + + if ((bits > 0) and (lower < bits) and (upper < bits) and (lower < upper)) + { + loaddr = addr + (lower >> LOGBITS); + hiaddr = addr + (upper >> LOGBITS); + lomask = BITMASKTAB[lower AND MODMASK]; + himask = BITMASKTAB[upper AND MODMASK]; + for ( bits = upper - lower + 1; bits > 1; bits -= 2 ) + { + if (((*loaddr AND lomask) != 0) XOR ((*hiaddr AND himask) != 0)) + { + *loaddr ^= lomask; /* swap bits only if they differ! */ + *hiaddr ^= himask; + } + if (not (lomask <<= 1)) + { + lomask = LSB; + loaddr++; + } + if (not (himask >>= 1)) + { + himask = MSB; + hiaddr--; + } + } + } +} + +boolean BitVector_interval_scan_inc(wordptr addr, N_int start, + N_intptr min, N_intptr max) +{ + N_word size = size_(addr); + N_word mask = mask_(addr); + N_word offset; + N_word bitmask; + N_word value; + boolean empty; + + if ((size == 0) or (start >= bits_(addr))) return(FALSE); + + *min = start; + *max = start; + + offset = start >> LOGBITS; + + *(addr+size-1) &= mask; + + addr += offset; + size -= offset; + + bitmask = BITMASKTAB[start AND MODMASK]; + mask = NOT (bitmask OR (bitmask - 1)); + + value = *addr++; + if ((value AND bitmask) == 0) + { + value &= mask; + if (value == 0) + { + offset++; + empty = TRUE; + while (empty and (--size > 0)) + { + if ((value = *addr++)) empty = false; else offset++; + } + if (empty) return(FALSE); + } + start = offset << LOGBITS; + bitmask = LSB; + mask = value; + while (not (mask AND LSB)) + { + bitmask <<= 1; + mask >>= 1; + start++; + } + mask = NOT (bitmask OR (bitmask - 1)); + *min = start; + *max = start; + } + value = NOT value; + value &= mask; + if (value == 0) + { + offset++; + empty = TRUE; + while (empty and (--size > 0)) + { + if ((value = NOT *addr++)) empty = false; else offset++; + } + if (empty) value = LSB; + } + start = offset << LOGBITS; + while (not (value AND LSB)) + { + value >>= 1; + start++; + } + *max = --start; + return(TRUE); +} + +boolean BitVector_interval_scan_dec(wordptr addr, N_int start, + N_intptr min, N_intptr max) +{ + N_word size = size_(addr); + N_word mask = mask_(addr); + N_word offset; + N_word bitmask; + N_word value; + boolean empty; + + if ((size == 0) or (start >= bits_(addr))) return(FALSE); + + *min = start; + *max = start; + + offset = start >> LOGBITS; + + if (offset >= size) return(FALSE); + + *(addr+size-1) &= mask; + + addr += offset; + size = ++offset; + + bitmask = BITMASKTAB[start AND MODMASK]; + mask = (bitmask - 1); + + value = *addr--; + if ((value AND bitmask) == 0) + { + value &= mask; + if (value == 0) + { + offset--; + empty = TRUE; + while (empty and (--size > 0)) + { + if ((value = *addr--)) empty = false; else offset--; + } + if (empty) return(FALSE); + } + start = offset << LOGBITS; + bitmask = MSB; + mask = value; + while (not (mask AND MSB)) + { + bitmask >>= 1; + mask <<= 1; + start--; + } + mask = (bitmask - 1); + *max = --start; + *min = start; + } + value = NOT value; + value &= mask; + if (value == 0) + { + offset--; + empty = TRUE; + while (empty and (--size > 0)) + { + if ((value = NOT *addr--)) empty = false; else offset--; + } + if (empty) value = MSB; + } + start = offset << LOGBITS; + while (not (value AND MSB)) + { + value <<= 1; + start--; + } + *min = start; + return(TRUE); +} + +void BitVector_Interval_Copy(wordptr X, wordptr Y, N_int Xoffset, + N_int Yoffset, N_int length) +{ + N_word bitsX = bits_(X); + N_word bitsY = bits_(Y); + N_word source = 0; /* silence compiler warning */ + N_word target = 0; /* silence compiler warning */ + N_word s_lo_base; + N_word s_hi_base; + N_word s_lo_bit; + N_word s_hi_bit; + N_word s_base; + N_word s_lower = 0; /* silence compiler warning */ + N_word s_upper = 0; /* silence compiler warning */ + N_word s_bits; + N_word s_min; + N_word s_max; + N_word t_lo_base; + N_word t_hi_base; + N_word t_lo_bit; + N_word t_hi_bit; + N_word t_base; + N_word t_lower = 0; /* silence compiler warning */ + N_word t_upper = 0; /* silence compiler warning */ + N_word t_bits; + N_word t_min; + N_word mask; + N_word bits; + N_word sel; + boolean ascending; + boolean notfirst; + wordptr Z = X; + + if ((length > 0) and (Xoffset < bitsX) and (Yoffset < bitsY)) + { + if ((Xoffset + length) > bitsX) length = bitsX - Xoffset; + if ((Yoffset + length) > bitsY) length = bitsY - Yoffset; + + ascending = (Xoffset <= Yoffset); + + s_lo_base = Yoffset >> LOGBITS; + s_lo_bit = Yoffset AND MODMASK; + Yoffset += --length; + s_hi_base = Yoffset >> LOGBITS; + s_hi_bit = Yoffset AND MODMASK; + + t_lo_base = Xoffset >> LOGBITS; + t_lo_bit = Xoffset AND MODMASK; + Xoffset += length; + t_hi_base = Xoffset >> LOGBITS; + t_hi_bit = Xoffset AND MODMASK; + + if (ascending) + { + s_base = s_lo_base; + t_base = t_lo_base; + } + else + { + s_base = s_hi_base; + t_base = t_hi_base; + } + s_bits = 0; + t_bits = 0; + Y += s_base; + X += t_base; + notfirst = FALSE; + while (TRUE) + { + if (t_bits == 0) + { + if (notfirst) + { + *X = target; + if (ascending) + { + if (t_base == t_hi_base) break; + t_base++; + X++; + } + else + { + if (t_base == t_lo_base) break; + t_base--; + X--; + } + } + sel = ((t_base == t_hi_base) << 1) OR (t_base == t_lo_base); + switch (sel) + { + case 0: + t_lower = 0; + t_upper = BITS - 1; + t_bits = BITS; + target = 0; + break; + case 1: + t_lower = t_lo_bit; + t_upper = BITS - 1; + t_bits = BITS - t_lo_bit; + mask = (N_word) (~0L << t_lower); + target = *X AND NOT mask; + break; + case 2: + t_lower = 0; + t_upper = t_hi_bit; + t_bits = t_hi_bit + 1; + mask = (N_word) ((~0L << t_upper) << 1); + target = *X AND mask; + break; + case 3: + t_lower = t_lo_bit; + t_upper = t_hi_bit; + t_bits = t_hi_bit - t_lo_bit + 1; + mask = (N_word) (~0L << t_lower); + mask &= (N_word) ~((~0L << t_upper) << 1); + target = *X AND NOT mask; + break; + } + } + if (s_bits == 0) + { + if (notfirst) + { + if (ascending) + { + if (s_base == s_hi_base) break; + s_base++; + Y++; + } + else + { + if (s_base == s_lo_base) break; + s_base--; + Y--; + } + } + source = *Y; + sel = ((s_base == s_hi_base) << 1) OR (s_base == s_lo_base); + switch (sel) + { + case 0: + s_lower = 0; + s_upper = BITS - 1; + s_bits = BITS; + break; + case 1: + s_lower = s_lo_bit; + s_upper = BITS - 1; + s_bits = BITS - s_lo_bit; + break; + case 2: + s_lower = 0; + s_upper = s_hi_bit; + s_bits = s_hi_bit + 1; + break; + case 3: + s_lower = s_lo_bit; + s_upper = s_hi_bit; + s_bits = s_hi_bit - s_lo_bit + 1; + break; + } + } + notfirst = TRUE; + if (s_bits > t_bits) + { + bits = t_bits - 1; + if (ascending) + { + s_min = s_lower; + s_max = s_lower + bits; + } + else + { + s_max = s_upper; + s_min = s_upper - bits; + } + t_min = t_lower; + } + else + { + bits = s_bits - 1; + if (ascending) t_min = t_lower; + else t_min = t_upper - bits; + s_min = s_lower; + s_max = s_upper; + } + bits++; + mask = (N_word) (~0L << s_min); + mask &= (N_word) ~((~0L << s_max) << 1); + if (s_min == t_min) target |= (source AND mask); + else + { + if (s_min < t_min) target |= (source AND mask) << (t_min-s_min); + else target |= (source AND mask) >> (s_min-t_min); + } + if (ascending) + { + s_lower += bits; + t_lower += bits; + } + else + { + s_upper -= bits; + t_upper -= bits; + } + s_bits -= bits; + t_bits -= bits; + } + *(Z+size_(Z)-1) &= mask_(Z); + } +} + + +wordptr BitVector_Interval_Substitute(wordptr X, wordptr Y, + N_int Xoffset, N_int Xlength, + N_int Yoffset, N_int Ylength) +{ + N_word Xbits = bits_(X); + N_word Ybits = bits_(Y); + N_word limit; + N_word diff; + + if ((Xoffset <= Xbits) and (Yoffset <= Ybits)) + { + limit = Xoffset + Xlength; + if (limit > Xbits) + { + limit = Xbits; + Xlength = Xbits - Xoffset; + } + if ((Yoffset + Ylength) > Ybits) + { + Ylength = Ybits - Yoffset; + } + if (Xlength == Ylength) + { + if ((Ylength > 0) and ((X != Y) or (Xoffset != Yoffset))) + { + BitVector_Interval_Copy(X,Y,Xoffset,Yoffset,Ylength); + } + } + else /* Xlength != Ylength */ + { + if (Xlength > Ylength) + { + diff = Xlength - Ylength; + if (Ylength > 0) BitVector_Interval_Copy(X,Y,Xoffset,Yoffset,Ylength); + if (limit < Xbits) BitVector_Delete(X,Xoffset+Ylength,diff,FALSE); + if ((X = BitVector_Resize(X,Xbits-diff)) == NULL) return(NULL); + } + else /* Ylength > Xlength ==> Ylength > 0 */ + { + diff = Ylength - Xlength; + if (X != Y) + { + if ((X = BitVector_Resize(X,Xbits+diff)) == NULL) return(NULL); + if (limit < Xbits) BitVector_Insert(X,limit,diff,FALSE); + BitVector_Interval_Copy(X,Y,Xoffset,Yoffset,Ylength); + } + else /* in-place */ + { + if ((Y = X = BitVector_Resize(X,Xbits+diff)) == NULL) return(NULL); + if (limit >= Xbits) + { + BitVector_Interval_Copy(X,Y,Xoffset,Yoffset,Ylength); + } + else /* limit < Xbits */ + { + BitVector_Insert(X,limit,diff,FALSE); + if ((Yoffset+Ylength) <= limit) + { + BitVector_Interval_Copy(X,Y,Xoffset,Yoffset,Ylength); + } + else /* overlaps or lies above critical area */ + { + if (limit <= Yoffset) + { + Yoffset += diff; + BitVector_Interval_Copy(X,Y,Xoffset,Yoffset,Ylength); + } + else /* Yoffset < limit */ + { + Xlength = limit - Yoffset; + BitVector_Interval_Copy(X,Y,Xoffset,Yoffset,Xlength); + Yoffset = Xoffset + Ylength; /* = limit + diff */ + Xoffset += Xlength; + Ylength -= Xlength; + BitVector_Interval_Copy(X,Y,Xoffset,Yoffset,Ylength); + } + } + } + } + } + } + } + return(X); +} + +boolean BitVector_is_empty(wordptr addr) /* X == {} ? */ +{ + N_word size = size_(addr); + boolean r = TRUE; + + if (size > 0) + { + *(addr+size-1) &= mask_(addr); + while (r and (size-- > 0)) r = ( *addr++ == 0 ); + } + return(r); +} + +boolean BitVector_is_full(wordptr addr) /* X == ~{} ? */ +{ + N_word size = size_(addr); + N_word mask = mask_(addr); + boolean r = FALSE; + wordptr last; + + if (size > 0) + { + r = TRUE; + last = addr + size - 1; + *last |= NOT mask; + while (r and (size-- > 0)) r = ( NOT *addr++ == 0 ); + *last &= mask; + } + return(r); +} + +boolean BitVector_equal(wordptr X, wordptr Y) /* X == Y ? */ +{ + N_word size = size_(X); + N_word mask = mask_(X); + boolean r = FALSE; + + if (bits_(X) == bits_(Y)) + { + r = TRUE; + if (size > 0) + { + *(X+size-1) &= mask; + *(Y+size-1) &= mask; + while (r and (size-- > 0)) r = (*X++ == *Y++); + } + } + return(r); +} + +Z_int BitVector_Lexicompare(wordptr X, wordptr Y) /* X <,=,> Y ? */ +{ /* unsigned */ + N_word bitsX = bits_(X); + N_word bitsY = bits_(Y); + N_word size = size_(X); + boolean r = TRUE; + + if (bitsX == bitsY) + { + if (size > 0) + { + X += size; + Y += size; + while (r and (size-- > 0)) r = (*(--X) == *(--Y)); + } + if (r) return((Z_int) 0); + else + { + if (*X < *Y) return((Z_int) -1); else return((Z_int) 1); + } + } + else + { + if (bitsX < bitsY) return((Z_int) -1); else return((Z_int) 1); + } +} + +Z_int BitVector_Compare(wordptr X, wordptr Y) /* X <,=,> Y ? */ +{ /* signed */ + N_word bitsX = bits_(X); + N_word bitsY = bits_(Y); + N_word size = size_(X); + N_word mask = mask_(X); + N_word sign; + boolean r = TRUE; + + if (bitsX == bitsY) + { + if (size > 0) + { + X += size; + Y += size; + mask &= NOT (mask >> 1); + if ((sign = (*(X-1) AND mask)) != (*(Y-1) AND mask)) + { + if (sign) return((Z_int) -1); else return((Z_int) 1); + } + while (r and (size-- > 0)) r = (*(--X) == *(--Y)); + } + if (r) return((Z_int) 0); + else + { + if (*X < *Y) return((Z_int) -1); else return((Z_int) 1); + } + } + else + { + if (bitsX < bitsY) return((Z_int) -1); else return((Z_int) 1); + } +} + +charptr BitVector_to_Hex(wordptr addr) +{ + N_word bits = bits_(addr); + N_word size = size_(addr); + N_word value; + N_word count; + N_word digit; + N_word length; + charptr string; + + length = bits >> 2; + if (bits AND 0x0003) length++; + string = (charptr) yasm_xmalloc((size_t) (length+1)); + if (string == NULL) return(NULL); + string += length; + *string = (N_char) '\0'; + if (size > 0) + { + *(addr+size-1) &= mask_(addr); + while ((size-- > 0) and (length > 0)) + { + value = *addr++; + count = BITS >> 2; + while ((count-- > 0) and (length > 0)) + { + digit = value AND 0x000F; + if (digit > 9) digit += (N_word) 'A' - 10; + else digit += (N_word) '0'; + *(--string) = (N_char) digit; length--; + if ((count > 0) and (length > 0)) value >>= 4; + } + } + } + return(string); +} + +ErrCode BitVector_from_Hex(wordptr addr, charptr string) +{ + N_word size = size_(addr); + N_word mask = mask_(addr); + boolean ok = TRUE; + size_t length; + N_word value; + N_word count; + int digit; + + if (size > 0) + { + length = strlen((char *) string); + string += length; + while (size-- > 0) + { + value = 0; + for ( count = 0; (ok and (length > 0) and (count < BITS)); count += 4 ) + { + digit = (int) *(--string); length--; + /* separate because toupper() is likely a macro! */ + digit = toupper(digit); + if (digit == '_') + count -= 4; + else if ((ok = (isxdigit(digit) != 0))) + { + if (digit >= (int) 'A') digit -= (int) 'A' - 10; + else digit -= (int) '0'; + value |= (((N_word) digit) << count); + } + } + *addr++ = value; + } + *(--addr) &= mask; + } + if (ok) return(ErrCode_Ok); + else return(ErrCode_Pars); +} + +ErrCode BitVector_from_Oct(wordptr addr, charptr string) +{ + N_word size = size_(addr); + N_word mask = mask_(addr); + boolean ok = TRUE; + size_t length; + N_word value; + N_word value_fill = 0; + N_word count; + Z_word count_fill = 0; + int digit = 0; + + if (size > 0) + { + length = strlen((char *) string); + string += length; + while (size-- > 0) + { + value = value_fill; + for ( count = count_fill; (ok and (length > 0) and (count < BITS)); count += 3 ) + { + digit = (int) *(--string); length--; + if (digit == '_') + count -= 3; + else if ((ok = (isdigit(digit) && digit != '8' && digit != '9')) != 0) + { + digit -= (int) '0'; + value |= (((N_word) digit) << count); + } + } + count_fill = (Z_word)count-(Z_word)BITS; + if (count_fill > 0) + value_fill = (((N_word) digit) >> (3-count_fill)); + else + value_fill = 0; + *addr++ = value; + } + *(--addr) &= mask; + } + if (ok) return(ErrCode_Ok); + else return(ErrCode_Pars); +} + +charptr BitVector_to_Bin(wordptr addr) +{ + N_word size = size_(addr); + N_word value; + N_word count; + N_word digit; + N_word length; + charptr string; + + length = bits_(addr); + string = (charptr) yasm_xmalloc((size_t) (length+1)); + if (string == NULL) return(NULL); + string += length; + *string = (N_char) '\0'; + if (size > 0) + { + *(addr+size-1) &= mask_(addr); + while (size-- > 0) + { + value = *addr++; + count = BITS; + if (count > length) count = length; + while (count-- > 0) + { + digit = value AND 0x0001; + digit += (N_word) '0'; + *(--string) = (N_char) digit; length--; + if (count > 0) value >>= 1; + } + } + } + return(string); +} + +ErrCode BitVector_from_Bin(wordptr addr, charptr string) +{ + N_word size = size_(addr); + N_word mask = mask_(addr); + boolean ok = TRUE; + size_t length; + N_word value; + N_word count; + int digit; + + if (size > 0) + { + length = strlen((char *) string); + string += length; + while (size-- > 0) + { + value = 0; + for ( count = 0; (ok and (length > 0) and (count < BITS)); count++ ) + { + digit = (int) *(--string); length--; + switch (digit) + { + case (int) '0': + break; + case (int) '1': + value |= BITMASKTAB[count]; + break; + case (int) '_': + count--; + break; + default: + ok = FALSE; + break; + } + } + *addr++ = value; + } + *(--addr) &= mask; + } + if (ok) return(ErrCode_Ok); + else return(ErrCode_Pars); +} + +charptr BitVector_to_Dec(wordptr addr) +{ + N_word bits = bits_(addr); + N_word length; + N_word digits; + N_word count; + N_word q; + N_word r; + boolean loop; + charptr result; + charptr string; + wordptr quot; + wordptr rest; + wordptr temp; + wordptr base; + Z_int sign; + + length = (N_word) (bits / 3.3); /* digits = bits * ln(2) / ln(10) */ + length += 2; /* compensate for truncating & provide space for minus sign */ + result = (charptr) yasm_xmalloc((size_t) (length+1)); /* remember the '\0'! */ + if (result == NULL) return(NULL); + string = result; + sign = BitVector_Sign(addr); + if ((bits < 4) or (sign == 0)) + { + if (bits > 0) digits = *addr; else digits = (N_word) 0; + if (sign < 0) digits = ((N_word)(-((Z_word)digits))) AND mask_(addr); + *string++ = (N_char) digits + (N_char) '0'; + digits = 1; + } + else + { + quot = BitVector_Create(bits,FALSE); + if (quot == NULL) + { + BitVector_Dispose(result); + return(NULL); + } + rest = BitVector_Create(bits,FALSE); + if (rest == NULL) + { + BitVector_Dispose(result); + BitVector_Destroy(quot); + return(NULL); + } + temp = BitVector_Create(bits,FALSE); + if (temp == NULL) + { + BitVector_Dispose(result); + BitVector_Destroy(quot); + BitVector_Destroy(rest); + return(NULL); + } + base = BitVector_Create(bits,TRUE); + if (base == NULL) + { + BitVector_Dispose(result); + BitVector_Destroy(quot); + BitVector_Destroy(rest); + BitVector_Destroy(temp); + return(NULL); + } + if (sign < 0) BitVector_Negate(quot,addr); + else BitVector_Copy(quot,addr); + digits = 0; + *base = EXP10; + loop = (bits >= BITS); + do + { + if (loop) + { + BitVector_Copy(temp,quot); + if (BitVector_Div_Pos(quot,temp,base,rest)) + { + BitVector_Dispose(result); /* emergency exit */ + BitVector_Destroy(quot); + BitVector_Destroy(rest); /* should never occur */ + BitVector_Destroy(temp); /* under normal operation */ + BitVector_Destroy(base); + return(NULL); + } + loop = not BitVector_is_empty(quot); + q = *rest; + } + else q = *quot; + count = LOG10; + while (((loop and (count-- > 0)) or ((not loop) and (q != 0))) and + (digits < length)) + { + if (q != 0) + { + BIT_VECTOR_DIGITIZE(N_word,q,r) + } + else r = (N_word) '0'; + *string++ = (N_char) r; + digits++; + } + } + while (loop and (digits < length)); + BitVector_Destroy(quot); + BitVector_Destroy(rest); + BitVector_Destroy(temp); + BitVector_Destroy(base); + } + if ((sign < 0) and (digits < length)) + { + *string++ = (N_char) '-'; + digits++; + } + *string = (N_char) '\0'; + BIT_VECTOR_reverse(result,digits); + return(result); +} + +struct BitVector_from_Dec_static_data { + wordptr term; + wordptr base; + wordptr prod; + wordptr rank; + wordptr temp; +}; + +BitVector_from_Dec_static_data *BitVector_from_Dec_static_Boot(N_word bits) +{ + BitVector_from_Dec_static_data *data; + + data = yasm_xmalloc(sizeof(BitVector_from_Dec_static_data)); + + if (bits > 0) + { + data->term = BitVector_Create(BITS,FALSE); + data->base = BitVector_Create(BITS,FALSE); + data->prod = BitVector_Create(bits,FALSE); + data->rank = BitVector_Create(bits,FALSE); + data->temp = BitVector_Create(bits,FALSE); + } else { + data->term = NULL; + data->base = NULL; + data->prod = NULL; + data->rank = NULL; + data->temp = NULL; + } + return data; +} + +void BitVector_from_Dec_static_Shutdown(BitVector_from_Dec_static_data *data) +{ + if (data) { + BitVector_Destroy(data->term); + BitVector_Destroy(data->base); + BitVector_Destroy(data->prod); + BitVector_Destroy(data->rank); + BitVector_Destroy(data->temp); + } + yasm_xfree(data); +} + +ErrCode BitVector_from_Dec_static(BitVector_from_Dec_static_data *data, + wordptr addr, charptr string) +{ + ErrCode error = ErrCode_Ok; + N_word bits = bits_(addr); + N_word mask = mask_(addr); + boolean init = (bits > BITS); + boolean minus; + boolean shift; + boolean carry; + wordptr term; + wordptr base; + wordptr prod; + wordptr rank; + wordptr temp; + N_word accu; + N_word powr; + N_word count; + size_t length; + int digit; + + if (bits > 0) + { + term = data->term; + base = data->base; + prod = data->prod; + rank = data->rank; + temp = data->temp; + + length = strlen((char *) string); + if (length == 0) return(ErrCode_Pars); + digit = (int) *string; + if ((minus = (digit == (int) '-')) or + (digit == (int) '+')) + { + string++; + if (--length == 0) return(ErrCode_Pars); + } + string += length; + if (init) + { + BitVector_Empty(prod); + BitVector_Empty(rank); + } + BitVector_Empty(addr); + *base = EXP10; + shift = FALSE; + while ((not error) and (length > 0)) + { + accu = 0; + powr = 1; + count = LOG10; + while ((not error) and (length > 0) and (count-- > 0)) + { + digit = (int) *(--string); length--; + /* separate because isdigit() is likely a macro! */ + if (isdigit(digit) != 0) + { + accu += ((N_word) digit - (N_word) '0') * powr; + powr *= 10; + } + else error = ErrCode_Pars; + } + if (not error) + { + if (shift) + { + *term = accu; + BitVector_Copy(temp,rank); + error = BitVector_Mul_Pos(prod,temp,term,FALSE); + } + else + { + *prod = accu; + if ((not init) and ((accu AND NOT mask) != 0)) error = ErrCode_Ovfl; + } + if (not error) + { + carry = FALSE; + BitVector_compute(addr,addr,prod,FALSE,&carry); + /* ignores sign change (= overflow) but not */ + /* numbers too large (= carry) for resulting bit vector */ + if (carry) error = ErrCode_Ovfl; + else + { + if (length > 0) + { + if (shift) + { + BitVector_Copy(temp,rank); + error = BitVector_Mul_Pos(rank,temp,base,FALSE); + } + else + { + *rank = *base; + shift = TRUE; + } + } + } + } + } + } + if (not error and minus) + { + BitVector_Negate(addr,addr); + if ((*(addr + size_(addr) - 1) AND mask AND NOT (mask >> 1)) == 0) + error = ErrCode_Ovfl; + } + } + return(error); +} + +ErrCode BitVector_from_Dec(wordptr addr, charptr string) +{ + ErrCode error = ErrCode_Ok; + N_word bits = bits_(addr); + N_word mask = mask_(addr); + boolean init = (bits > BITS); + boolean minus; + boolean shift; + boolean carry; + wordptr term; + wordptr base; + wordptr prod; + wordptr rank; + wordptr temp; + N_word accu; + N_word powr; + N_word count; + size_t length; + int digit; + + if (bits > 0) + { + length = strlen((char *) string); + if (length == 0) return(ErrCode_Pars); + digit = (int) *string; + if ((minus = (digit == (int) '-')) or + (digit == (int) '+')) + { + string++; + if (--length == 0) return(ErrCode_Pars); + } + string += length; + term = BitVector_Create(BITS,FALSE); + if (term == NULL) + { + return(ErrCode_Null); + } + base = BitVector_Create(BITS,FALSE); + if (base == NULL) + { + BitVector_Destroy(term); + return(ErrCode_Null); + } + prod = BitVector_Create(bits,init); + if (prod == NULL) + { + BitVector_Destroy(term); + BitVector_Destroy(base); + return(ErrCode_Null); + } + rank = BitVector_Create(bits,init); + if (rank == NULL) + { + BitVector_Destroy(term); + BitVector_Destroy(base); + BitVector_Destroy(prod); + return(ErrCode_Null); + } + temp = BitVector_Create(bits,FALSE); + if (temp == NULL) + { + BitVector_Destroy(term); + BitVector_Destroy(base); + BitVector_Destroy(prod); + BitVector_Destroy(rank); + return(ErrCode_Null); + } + BitVector_Empty(addr); + *base = EXP10; + shift = FALSE; + while ((not error) and (length > 0)) + { + accu = 0; + powr = 1; + count = LOG10; + while ((not error) and (length > 0) and (count-- > 0)) + { + digit = (int) *(--string); length--; + /* separate because isdigit() is likely a macro! */ + if (isdigit(digit) != 0) + { + accu += ((N_word) digit - (N_word) '0') * powr; + powr *= 10; + } + else error = ErrCode_Pars; + } + if (not error) + { + if (shift) + { + *term = accu; + BitVector_Copy(temp,rank); + error = BitVector_Mul_Pos(prod,temp,term,FALSE); + } + else + { + *prod = accu; + if ((not init) and ((accu AND NOT mask) != 0)) error = ErrCode_Ovfl; + } + if (not error) + { + carry = FALSE; + BitVector_compute(addr,addr,prod,FALSE,&carry); + /* ignores sign change (= overflow) but not */ + /* numbers too large (= carry) for resulting bit vector */ + if (carry) error = ErrCode_Ovfl; + else + { + if (length > 0) + { + if (shift) + { + BitVector_Copy(temp,rank); + error = BitVector_Mul_Pos(rank,temp,base,FALSE); + } + else + { + *rank = *base; + shift = TRUE; + } + } + } + } + } + } + BitVector_Destroy(term); + BitVector_Destroy(base); + BitVector_Destroy(prod); + BitVector_Destroy(rank); + BitVector_Destroy(temp); + if (not error and minus) + { + BitVector_Negate(addr,addr); + if ((*(addr + size_(addr) - 1) AND mask AND NOT (mask >> 1)) == 0) + error = ErrCode_Ovfl; + } + } + return(error); +} + +charptr BitVector_to_Enum(wordptr addr) +{ + N_word bits = bits_(addr); + N_word sample; + N_word length; + N_word digits; + N_word factor; + N_word power; + N_word start; + N_word min; + N_word max; + charptr string; + charptr target; + boolean comma; + + if (bits > 0) + { + sample = bits - 1; /* greatest possible index */ + length = 2; /* account for index 0 and terminating '\0' */ + digits = 1; /* account for intervening dashes and commas */ + factor = 1; + power = 10; + while (sample >= (power-1)) + { + length += ++digits * factor * 6; /* 9,90,900,9000,... (9*2/3 = 6) */ + factor = power; + power *= 10; + } + if (sample > --factor) + { + sample -= factor; + factor = (N_word) ( sample / 3 ); + factor = (factor << 1) + (sample - (factor * 3)); + length += ++digits * factor; + } + } + else length = 1; + string = (charptr) yasm_xmalloc((size_t) length); + if (string == NULL) return(NULL); + start = 0; + comma = FALSE; + target = string; + while ((start < bits) and BitVector_interval_scan_inc(addr,start,&min,&max)) + { + start = max + 2; + if (comma) *target++ = (N_char) ','; + if (min == max) + { + target += BIT_VECTOR_int2str(target,min); + } + else + { + if (min+1 == max) + { + target += BIT_VECTOR_int2str(target,min); + *target++ = (N_char) ','; + target += BIT_VECTOR_int2str(target,max); + } + else + { + target += BIT_VECTOR_int2str(target,min); + *target++ = (N_char) '-'; + target += BIT_VECTOR_int2str(target,max); + } + } + comma = TRUE; + } + *target = (N_char) '\0'; + return(string); +} + +ErrCode BitVector_from_Enum(wordptr addr, charptr string) +{ + ErrCode error = ErrCode_Ok; + N_word bits = bits_(addr); + N_word state = 1; + N_word token; + N_word indx = 0; /* silence compiler warning */ + N_word start = 0; /* silence compiler warning */ + + if (bits > 0) + { + BitVector_Empty(addr); + while ((not error) and (state != 0)) + { + token = (N_word) *string; + /* separate because isdigit() is likely a macro! */ + if (isdigit((int)token) != 0) + { + string += BIT_VECTOR_str2int(string,&indx); + if (indx < bits) token = (N_word) '0'; + else error = ErrCode_Indx; + } + else string++; + if (not error) + switch (state) + { + case 1: + switch (token) + { + case (N_word) '0': + state = 2; + break; + case (N_word) '\0': + state = 0; + break; + default: + error = ErrCode_Pars; + break; + } + break; + case 2: + switch (token) + { + case (N_word) '-': + start = indx; + state = 3; + break; + case (N_word) ',': + BIT_VECTOR_SET_BIT(addr,indx) + state = 5; + break; + case (N_word) '\0': + BIT_VECTOR_SET_BIT(addr,indx) + state = 0; + break; + default: + error = ErrCode_Pars; + break; + } + break; + case 3: + switch (token) + { + case (N_word) '0': + if (start < indx) + BitVector_Interval_Fill(addr,start,indx); + else if (start == indx) + BIT_VECTOR_SET_BIT(addr,indx) + else error = ErrCode_Ordr; + state = 4; + break; + default: + error = ErrCode_Pars; + break; + } + break; + case 4: + switch (token) + { + case (N_word) ',': + state = 5; + break; + case (N_word) '\0': + state = 0; + break; + default: + error = ErrCode_Pars; + break; + } + break; + case 5: + switch (token) + { + case (N_word) '0': + state = 2; + break; + default: + error = ErrCode_Pars; + break; + } + break; + } + } + } + return(error); +} + +void BitVector_Bit_Off(wordptr addr, N_int indx) /* X = X \ {x} */ +{ + if (indx < bits_(addr)) BIT_VECTOR_CLR_BIT(addr,indx) +} + +void BitVector_Bit_On(wordptr addr, N_int indx) /* X = X + {x} */ +{ + if (indx < bits_(addr)) BIT_VECTOR_SET_BIT(addr,indx) +} + +boolean BitVector_bit_flip(wordptr addr, N_int indx) /* X=(X+{x})\(X*{x}) */ +{ + N_word mask; + + if (indx < bits_(addr)) return( BIT_VECTOR_FLP_BIT(addr,indx,mask) ); + else return( FALSE ); +} + +boolean BitVector_bit_test(wordptr addr, N_int indx) /* {x} in X ? */ +{ + if (indx < bits_(addr)) return( BIT_VECTOR_TST_BIT(addr,indx) ); + else return( FALSE ); +} + +void BitVector_Bit_Copy(wordptr addr, N_int indx, boolean bit) +{ + if (indx < bits_(addr)) + { + if (bit) BIT_VECTOR_SET_BIT(addr,indx) + else BIT_VECTOR_CLR_BIT(addr,indx) + } +} + +void BitVector_LSB(wordptr addr, boolean bit) +{ + if (bits_(addr) > 0) + { + if (bit) *addr |= LSB; + else *addr &= NOT LSB; + } +} + +void BitVector_MSB(wordptr addr, boolean bit) +{ + N_word size = size_(addr); + N_word mask = mask_(addr); + + if (size-- > 0) + { + if (bit) *(addr+size) |= mask AND NOT (mask >> 1); + else *(addr+size) &= NOT mask OR (mask >> 1); + } +} + +boolean BitVector_lsb_(wordptr addr) +{ + if (size_(addr) > 0) return( (*addr AND LSB) != 0 ); + else return( FALSE ); +} + +boolean BitVector_msb_(wordptr addr) +{ + N_word size = size_(addr); + N_word mask = mask_(addr); + + if (size-- > 0) + return( (*(addr+size) AND (mask AND NOT (mask >> 1))) != 0 ); + else + return( FALSE ); +} + +boolean BitVector_rotate_left(wordptr addr) +{ + N_word size = size_(addr); + N_word mask = mask_(addr); + N_word msb; + boolean carry_in; + boolean carry_out = FALSE; + + if (size > 0) + { + msb = mask AND NOT (mask >> 1); + carry_in = ((*(addr+size-1) AND msb) != 0); + while (size-- > 1) + { + carry_out = ((*addr AND MSB) != 0); + *addr <<= 1; + if (carry_in) *addr |= LSB; + carry_in = carry_out; + addr++; + } + carry_out = ((*addr AND msb) != 0); + *addr <<= 1; + if (carry_in) *addr |= LSB; + *addr &= mask; + } + return(carry_out); +} + +boolean BitVector_rotate_right(wordptr addr) +{ + N_word size = size_(addr); + N_word mask = mask_(addr); + N_word msb; + boolean carry_in; + boolean carry_out = FALSE; + + if (size > 0) + { + msb = mask AND NOT (mask >> 1); + carry_in = ((*addr AND LSB) != 0); + addr += size-1; + *addr &= mask; + carry_out = ((*addr AND LSB) != 0); + *addr >>= 1; + if (carry_in) *addr |= msb; + carry_in = carry_out; + addr--; + size--; + while (size-- > 0) + { + carry_out = ((*addr AND LSB) != 0); + *addr >>= 1; + if (carry_in) *addr |= MSB; + carry_in = carry_out; + addr--; + } + } + return(carry_out); +} + +boolean BitVector_shift_left(wordptr addr, boolean carry_in) +{ + N_word size = size_(addr); + N_word mask = mask_(addr); + N_word msb; + boolean carry_out = carry_in; + + if (size > 0) + { + msb = mask AND NOT (mask >> 1); + while (size-- > 1) + { + carry_out = ((*addr AND MSB) != 0); + *addr <<= 1; + if (carry_in) *addr |= LSB; + carry_in = carry_out; + addr++; + } + carry_out = ((*addr AND msb) != 0); + *addr <<= 1; + if (carry_in) *addr |= LSB; + *addr &= mask; + } + return(carry_out); +} + +boolean BitVector_shift_right(wordptr addr, boolean carry_in) +{ + N_word size = size_(addr); + N_word mask = mask_(addr); + N_word msb; + boolean carry_out = carry_in; + + if (size > 0) + { + msb = mask AND NOT (mask >> 1); + addr += size-1; + *addr &= mask; + carry_out = ((*addr AND LSB) != 0); + *addr >>= 1; + if (carry_in) *addr |= msb; + carry_in = carry_out; + addr--; + size--; + while (size-- > 0) + { + carry_out = ((*addr AND LSB) != 0); + *addr >>= 1; + if (carry_in) *addr |= MSB; + carry_in = carry_out; + addr--; + } + } + return(carry_out); +} + +void BitVector_Move_Left(wordptr addr, N_int bits) +{ + N_word count; + N_word words; + + if (bits > 0) + { + count = bits AND MODMASK; + words = bits >> LOGBITS; + if (bits >= bits_(addr)) BitVector_Empty(addr); + else + { + while (count-- > 0) BitVector_shift_left(addr,0); + BitVector_Word_Insert(addr,0,words,TRUE); + } + } +} + +void BitVector_Move_Right(wordptr addr, N_int bits) +{ + N_word count; + N_word words; + + if (bits > 0) + { + count = bits AND MODMASK; + words = bits >> LOGBITS; + if (bits >= bits_(addr)) BitVector_Empty(addr); + else + { + while (count-- > 0) BitVector_shift_right(addr,0); + BitVector_Word_Delete(addr,0,words,TRUE); + } + } +} + +void BitVector_Insert(wordptr addr, N_int offset, N_int count, boolean clear) +{ + N_word bits = bits_(addr); + N_word last; + + if ((count > 0) and (offset < bits)) + { + last = offset + count; + if (last < bits) + { + BitVector_Interval_Copy(addr,addr,last,offset,(bits-last)); + } + else last = bits; + if (clear) BitVector_Interval_Empty(addr,offset,(last-1)); + } +} + +void BitVector_Delete(wordptr addr, N_int offset, N_int count, boolean clear) +{ + N_word bits = bits_(addr); + N_word last; + + if ((count > 0) and (offset < bits)) + { + last = offset + count; + if (last < bits) + { + BitVector_Interval_Copy(addr,addr,offset,last,(bits-last)); + } + else count = bits - offset; + if (clear) BitVector_Interval_Empty(addr,(bits-count),(bits-1)); + } +} + +boolean BitVector_increment(wordptr addr) /* X++ */ +{ + N_word size = size_(addr); + N_word mask = mask_(addr); + wordptr last = addr + size - 1; + boolean carry = TRUE; + + if (size > 0) + { + *last |= NOT mask; + while (carry and (size-- > 0)) + { + carry = (++(*addr++) == 0); + } + *last &= mask; + } + return(carry); +} + +boolean BitVector_decrement(wordptr addr) /* X-- */ +{ + N_word size = size_(addr); + N_word mask = mask_(addr); + wordptr last = addr + size - 1; + boolean carry = TRUE; + + if (size > 0) + { + *last &= mask; + while (carry and (size-- > 0)) + { + carry = (*addr == 0); + --(*addr++); + } + *last &= mask; + } + return(carry); +} + +boolean BitVector_compute(wordptr X, wordptr Y, wordptr Z, boolean minus, boolean *carry) +{ + N_word size = size_(X); + N_word mask = mask_(X); + N_word vv = 0; + N_word cc; + N_word mm; + N_word yy; + N_word zz; + N_word lo; + N_word hi; + + if (size > 0) + { + if (minus) cc = (*carry == 0); + else cc = (*carry != 0); + /* deal with (size-1) least significant full words first: */ + while (--size > 0) + { + yy = *Y++; + if (minus) zz = (N_word) NOT ( Z ? *Z++ : 0 ); + else zz = (N_word) ( Z ? *Z++ : 0 ); + lo = (yy AND LSB) + (zz AND LSB) + cc; + hi = (yy >> 1) + (zz >> 1) + (lo >> 1); + cc = ((hi AND MSB) != 0); + *X++ = (hi << 1) OR (lo AND LSB); + } + /* deal with most significant word (may be used only partially): */ + yy = *Y AND mask; + if (minus) zz = (N_word) NOT ( Z ? *Z : 0 ); + else zz = (N_word) ( Z ? *Z : 0 ); + zz &= mask; + if (mask == LSB) /* special case, only one bit used */ + { + vv = cc; + lo = yy + zz + cc; + cc = (lo >> 1); + vv ^= cc; + *X = lo AND LSB; + } + else + { + if (NOT mask) /* not all bits are used, but more than one */ + { + mm = (mask >> 1); + vv = (yy AND mm) + (zz AND mm) + cc; + mm = mask AND NOT mm; + lo = yy + zz + cc; + cc = (lo >> 1); + vv ^= cc; + vv &= mm; + cc &= mm; + *X = lo AND mask; + } + else /* other special case, all bits are used */ + { + mm = NOT MSB; + lo = (yy AND mm) + (zz AND mm) + cc; + vv = lo AND MSB; + hi = ((yy AND MSB) >> 1) + ((zz AND MSB) >> 1) + (vv >> 1); + cc = hi AND MSB; + vv ^= cc; + *X = (hi << 1) OR (lo AND mm); + } + } + if (minus) *carry = (cc == 0); + else *carry = (cc != 0); + } + return(vv != 0); +} + +boolean BitVector_add(wordptr X, wordptr Y, wordptr Z, boolean *carry) +{ + return(BitVector_compute(X,Y,Z,FALSE,carry)); +} + +boolean BitVector_sub(wordptr X, wordptr Y, wordptr Z, boolean *carry) +{ + return(BitVector_compute(X,Y,Z,TRUE,carry)); +} + +boolean BitVector_inc(wordptr X, wordptr Y) +{ + boolean carry = TRUE; + + return(BitVector_compute(X,Y,NULL,FALSE,&carry)); +} + +boolean BitVector_dec(wordptr X, wordptr Y) +{ + boolean carry = TRUE; + + return(BitVector_compute(X,Y,NULL,TRUE,&carry)); +} + +void BitVector_Negate(wordptr X, wordptr Y) +{ + N_word size = size_(X); + N_word mask = mask_(X); + boolean carry = TRUE; + + if (size > 0) + { + while (size-- > 0) + { + *X = NOT *Y++; + if (carry) + { + carry = (++(*X) == 0); + } + X++; + } + *(--X) &= mask; + } +} + +void BitVector_Absolute(wordptr X, wordptr Y) +{ + N_word size = size_(Y); + N_word mask = mask_(Y); + + if (size > 0) + { + if (*(Y+size-1) AND (mask AND NOT (mask >> 1))) BitVector_Negate(X,Y); + else BitVector_Copy(X,Y); + } +} + +Z_int BitVector_Sign(wordptr addr) +{ + N_word size = size_(addr); + N_word mask = mask_(addr); + wordptr last = addr + size - 1; + boolean r = TRUE; + + if (size > 0) + { + *last &= mask; + while (r and (size-- > 0)) r = ( *addr++ == 0 ); + } + if (r) return((Z_int) 0); + else + { + if (*last AND (mask AND NOT (mask >> 1))) return((Z_int) -1); + else return((Z_int) 1); + } +} + +ErrCode BitVector_Mul_Pos(wordptr X, wordptr Y, wordptr Z, boolean strict) +{ + N_word mask; + N_word limit; + N_word count; + Z_long last; + wordptr sign; + boolean carry; + boolean overflow; + boolean ok = TRUE; + + /* + Requirements: + - X, Y and Z must be distinct + - X and Y must have equal sizes (whereas Z may be any size!) + - Z should always contain the SMALLER of the two factors Y and Z + Constraints: + - The contents of Y (and of X, of course) are destroyed + (only Z is preserved!) + */ + + if ((X == Y) or (X == Z) or (Y == Z)) return(ErrCode_Same); + if (bits_(X) != bits_(Y)) return(ErrCode_Size); + BitVector_Empty(X); + if (BitVector_is_empty(Y)) return(ErrCode_Ok); /* exit also taken if bits_(Y)==0 */ + if ((last = Set_Max(Z)) < 0L) return(ErrCode_Ok); + limit = (N_word) last; + sign = Y + size_(Y) - 1; + mask = mask_(Y); + *sign &= mask; + mask &= NOT (mask >> 1); + for ( count = 0; (ok and (count <= limit)); count++ ) + { + if ( BIT_VECTOR_TST_BIT(Z,count) ) + { + carry = false; + overflow = BitVector_compute(X,X,Y,false,&carry); + if (strict) ok = not (carry or overflow); + else ok = not carry; + } + if (ok and (count < limit)) + { + carry = BitVector_shift_left(Y,0); + if (strict) + { + overflow = ((*sign AND mask) != 0); + ok = not (carry or overflow); + } + else ok = not carry; + } + } + if (ok) return(ErrCode_Ok); else return(ErrCode_Ovfl); +} + +ErrCode BitVector_Multiply(wordptr X, wordptr Y, wordptr Z) +{ + ErrCode error = ErrCode_Ok; + N_word bit_x = bits_(X); + N_word bit_y = bits_(Y); + N_word bit_z = bits_(Z); + N_word size; + N_word mask; + N_word msb; + wordptr ptr_y; + wordptr ptr_z; + boolean sgn_x; + boolean sgn_y; + boolean sgn_z; + boolean zero; + wordptr A; + wordptr B; + + /* + Requirements: + - Y and Z must have equal sizes + - X must have at least the same size as Y and Z but may be larger (!) + Features: + - The contents of Y and Z are preserved + - X may be identical with Y or Z (or both!) + (in-place multiplication is possible!) + */ + + if ((bit_y != bit_z) or (bit_x < bit_y)) return(ErrCode_Size); + if (BitVector_is_empty(Y) or BitVector_is_empty(Z)) + { + BitVector_Empty(X); + } + else + { + A = BitVector_Create(bit_y,FALSE); + if (A == NULL) return(ErrCode_Null); + B = BitVector_Create(bit_z,FALSE); + if (B == NULL) { BitVector_Destroy(A); return(ErrCode_Null); } + size = size_(Y); + mask = mask_(Y); + msb = (mask AND NOT (mask >> 1)); + sgn_y = (((*(Y+size-1) &= mask) AND msb) != 0); + sgn_z = (((*(Z+size-1) &= mask) AND msb) != 0); + sgn_x = sgn_y XOR sgn_z; + if (sgn_y) BitVector_Negate(A,Y); else BitVector_Copy(A,Y); + if (sgn_z) BitVector_Negate(B,Z); else BitVector_Copy(B,Z); + ptr_y = A + size; + ptr_z = B + size; + zero = TRUE; + while (zero and (size-- > 0)) + { + zero &= (*(--ptr_y) == 0); + zero &= (*(--ptr_z) == 0); + } + if (*ptr_y > *ptr_z) + { + if (bit_x > bit_y) + { + A = BitVector_Resize(A,bit_x); + if (A == NULL) { BitVector_Destroy(B); return(ErrCode_Null); } + } + error = BitVector_Mul_Pos(X,A,B,TRUE); + } + else + { + if (bit_x > bit_z) + { + B = BitVector_Resize(B,bit_x); + if (B == NULL) { BitVector_Destroy(A); return(ErrCode_Null); } + } + error = BitVector_Mul_Pos(X,B,A,TRUE); + } + if ((not error) and sgn_x) BitVector_Negate(X,X); + BitVector_Destroy(A); + BitVector_Destroy(B); + } + return(error); +} + +ErrCode BitVector_Div_Pos(wordptr Q, wordptr X, wordptr Y, wordptr R) +{ + N_word bits = bits_(Q); + N_word mask; + wordptr addr; + Z_long last; + boolean flag; + boolean copy = FALSE; /* flags whether valid rest is in R (0) or X (1) */ + + /* + Requirements: + - All bit vectors must have equal sizes + - Q, X, Y and R must all be distinct bit vectors + - Y must be non-zero (of course!) + Constraints: + - The contents of X (and Q and R, of course) are destroyed + (only Y is preserved!) + */ + + if ((bits != bits_(X)) or (bits != bits_(Y)) or (bits != bits_(R))) + return(ErrCode_Size); + if ((Q == X) or (Q == Y) or (Q == R) or (X == Y) or (X == R) or (Y == R)) + return(ErrCode_Same); + if (BitVector_is_empty(Y)) + return(ErrCode_Zero); + + BitVector_Empty(R); + BitVector_Copy(Q,X); + if ((last = Set_Max(Q)) < 0L) return(ErrCode_Ok); + bits = (N_word) ++last; + while (bits-- > 0) + { + addr = Q + (bits >> LOGBITS); + mask = BITMASKTAB[bits AND MODMASK]; + flag = ((*addr AND mask) != 0); + if (copy) + { + BitVector_shift_left(X,flag); + flag = FALSE; + BitVector_compute(R,X,Y,TRUE,&flag); + } + else + { + BitVector_shift_left(R,flag); + flag = FALSE; + BitVector_compute(X,R,Y,TRUE,&flag); + } + if (flag) *addr &= NOT mask; + else + { + *addr |= mask; + copy = not copy; + } + } + if (copy) BitVector_Copy(R,X); + return(ErrCode_Ok); +} + +ErrCode BitVector_Divide(wordptr Q, wordptr X, wordptr Y, wordptr R) +{ + ErrCode error = ErrCode_Ok; + N_word bits = bits_(Q); + N_word size = size_(Q); + N_word mask = mask_(Q); + N_word msb = (mask AND NOT (mask >> 1)); + boolean sgn_q; + boolean sgn_x; + boolean sgn_y; + wordptr A; + wordptr B; + + /* + Requirements: + - All bit vectors must have equal sizes + - Q and R must be two distinct bit vectors + - Y must be non-zero (of course!) + Features: + - The contents of X and Y are preserved + - Q may be identical with X or Y (or both) + (in-place division is possible!) + - R may be identical with X or Y (or both) + (but not identical with Q!) + */ + + if ((bits != bits_(X)) or (bits != bits_(Y)) or (bits != bits_(R))) + return(ErrCode_Size); + if (Q == R) + return(ErrCode_Same); + if (BitVector_is_empty(Y)) + return(ErrCode_Zero); + + if (BitVector_is_empty(X)) + { + BitVector_Empty(Q); + BitVector_Empty(R); + } + else + { + A = BitVector_Create(bits,FALSE); + if (A == NULL) return(ErrCode_Null); + B = BitVector_Create(bits,FALSE); + if (B == NULL) { BitVector_Destroy(A); return(ErrCode_Null); } + size--; + sgn_x = (((*(X+size) &= mask) AND msb) != 0); + sgn_y = (((*(Y+size) &= mask) AND msb) != 0); + sgn_q = sgn_x XOR sgn_y; + if (sgn_x) BitVector_Negate(A,X); else BitVector_Copy(A,X); + if (sgn_y) BitVector_Negate(B,Y); else BitVector_Copy(B,Y); + if (not (error = BitVector_Div_Pos(Q,A,B,R))) + { + if (sgn_q) BitVector_Negate(Q,Q); + if (sgn_x) BitVector_Negate(R,R); + } + BitVector_Destroy(A); + BitVector_Destroy(B); + } + return(error); +} + +ErrCode BitVector_GCD(wordptr X, wordptr Y, wordptr Z) +{ + ErrCode error = ErrCode_Ok; + N_word bits = bits_(X); + N_word size = size_(X); + N_word mask = mask_(X); + N_word msb = (mask AND NOT (mask >> 1)); + boolean sgn_a; + boolean sgn_b; + boolean sgn_r; + wordptr Q; + wordptr R; + wordptr A; + wordptr B; + wordptr T; + + /* + Requirements: + - All bit vectors must have equal sizes + Features: + - The contents of Y and Z are preserved + - X may be identical with Y or Z (or both) + (in-place is possible!) + - GCD(0,z) == GCD(z,0) == z + - negative values are handled correctly + */ + + if ((bits != bits_(Y)) or (bits != bits_(Z))) return(ErrCode_Size); + if (BitVector_is_empty(Y)) + { + if (X != Z) BitVector_Copy(X,Z); + return(ErrCode_Ok); + } + if (BitVector_is_empty(Z)) + { + if (X != Y) BitVector_Copy(X,Y); + return(ErrCode_Ok); + } + Q = BitVector_Create(bits,false); + if (Q == NULL) + { + return(ErrCode_Null); + } + R = BitVector_Create(bits,FALSE); + if (R == NULL) + { + BitVector_Destroy(Q); + return(ErrCode_Null); + } + A = BitVector_Create(bits,FALSE); + if (A == NULL) + { + BitVector_Destroy(Q); + BitVector_Destroy(R); + return(ErrCode_Null); + } + B = BitVector_Create(bits,FALSE); + if (B == NULL) + { + BitVector_Destroy(Q); + BitVector_Destroy(R); + BitVector_Destroy(A); + return(ErrCode_Null); + } + size--; + sgn_a = (((*(Y+size) &= mask) AND msb) != 0); + sgn_b = (((*(Z+size) &= mask) AND msb) != 0); + if (sgn_a) BitVector_Negate(A,Y); else BitVector_Copy(A,Y); + if (sgn_b) BitVector_Negate(B,Z); else BitVector_Copy(B,Z); + while (not error) + { + if (not (error = BitVector_Div_Pos(Q,A,B,R))) + { + if (BitVector_is_empty(R)) break; + T = A; sgn_r = sgn_a; + A = B; sgn_a = sgn_b; + B = R; sgn_b = sgn_r; + R = T; + } + } + if (not error) + { + if (sgn_b) BitVector_Negate(X,B); else BitVector_Copy(X,B); + } + BitVector_Destroy(Q); + BitVector_Destroy(R); + BitVector_Destroy(A); + BitVector_Destroy(B); + return(error); +} + +ErrCode BitVector_GCD2(wordptr U, wordptr V, wordptr W, wordptr X, wordptr Y) +{ + ErrCode error = ErrCode_Ok; + N_word bits = bits_(U); + N_word size = size_(U); + N_word mask = mask_(U); + N_word msb = (mask AND NOT (mask >> 1)); + boolean minus; + boolean carry; + boolean sgn_q; + boolean sgn_r; + boolean sgn_a; + boolean sgn_b; + boolean sgn_x; + boolean sgn_y; + listptr L; + wordptr Q; + wordptr R; + wordptr A; + wordptr B; + wordptr T; + wordptr X1; + wordptr X2; + wordptr X3; + wordptr Y1; + wordptr Y2; + wordptr Y3; + wordptr Z; + + /* + Requirements: + - All bit vectors must have equal sizes + - U, V, and W must all be distinct bit vectors + Features: + - The contents of X and Y are preserved + - U, V and W may be identical with X or Y (or both, + provided that U, V and W are mutually distinct) + (i.e., in-place is possible!) + - GCD(0,z) == GCD(z,0) == z + - negative values are handled correctly + */ + + if ((bits != bits_(V)) or + (bits != bits_(W)) or + (bits != bits_(X)) or + (bits != bits_(Y))) + { + return(ErrCode_Size); + } + if ((U == V) or (U == W) or (V == W)) + { + return(ErrCode_Same); + } + if (BitVector_is_empty(X)) + { + if (U != Y) BitVector_Copy(U,Y); + BitVector_Empty(V); + BitVector_Empty(W); + *W = 1; + return(ErrCode_Ok); + } + if (BitVector_is_empty(Y)) + { + if (U != X) BitVector_Copy(U,X); + BitVector_Empty(V); + BitVector_Empty(W); + *V = 1; + return(ErrCode_Ok); + } + if ((L = BitVector_Create_List(bits,false,11)) == NULL) + { + return(ErrCode_Null); + } + Q = L[0]; + R = L[1]; + A = L[2]; + B = L[3]; + X1 = L[4]; + X2 = L[5]; + X3 = L[6]; + Y1 = L[7]; + Y2 = L[8]; + Y3 = L[9]; + Z = L[10]; + size--; + sgn_a = (((*(X+size) &= mask) AND msb) != 0); + sgn_b = (((*(Y+size) &= mask) AND msb) != 0); + if (sgn_a) BitVector_Negate(A,X); else BitVector_Copy(A,X); + if (sgn_b) BitVector_Negate(B,Y); else BitVector_Copy(B,Y); + BitVector_Empty(X1); + BitVector_Empty(X2); + *X1 = 1; + BitVector_Empty(Y1); + BitVector_Empty(Y2); + *Y2 = 1; + sgn_x = false; + sgn_y = false; + while (not error) + { + if ((error = BitVector_Div_Pos(Q,A,B,R))) + { + break; + } + if (BitVector_is_empty(R)) + { + break; + } + sgn_q = sgn_a XOR sgn_b; + + if (sgn_x) BitVector_Negate(Z,X2); else BitVector_Copy(Z,X2); + if ((error = BitVector_Mul_Pos(X3,Z,Q,true))) + { + break; + } + minus = not (sgn_x XOR sgn_q); + carry = 0; + if (BitVector_compute(X3,X1,X3,minus,&carry)) + { + error = ErrCode_Ovfl; + break; + } + sgn_x = (((*(X3+size) &= mask) AND msb) != 0); + + if (sgn_y) BitVector_Negate(Z,Y2); else BitVector_Copy(Z,Y2); + if ((error = BitVector_Mul_Pos(Y3,Z,Q,true))) + { + break; + } + minus = not (sgn_y XOR sgn_q); + carry = 0; + if (BitVector_compute(Y3,Y1,Y3,minus,&carry)) + { + error = ErrCode_Ovfl; + break; + } + sgn_y = (((*(Y3+size) &= mask) AND msb) != 0); + + T = A; sgn_r = sgn_a; + A = B; sgn_a = sgn_b; + B = R; sgn_b = sgn_r; + R = T; + + T = X1; + X1 = X2; + X2 = X3; + X3 = T; + + T = Y1; + Y1 = Y2; + Y2 = Y3; + Y3 = T; + } + if (not error) + { + if (sgn_b) BitVector_Negate(U,B); else BitVector_Copy(U,B); + BitVector_Copy(V,X2); + BitVector_Copy(W,Y2); + } + BitVector_Destroy_List(L,11); + return(error); +} + +ErrCode BitVector_Power(wordptr X, wordptr Y, wordptr Z) +{ + ErrCode error = ErrCode_Ok; + N_word bits = bits_(X); + boolean first = TRUE; + Z_long last; + N_word limit; + N_word count; + wordptr T; + + /* + Requirements: + - X must have at least the same size as Y but may be larger (!) + - X may not be identical with Z + - Z must be positive + Features: + - The contents of Y and Z are preserved + */ + + if (X == Z) return(ErrCode_Same); + if (bits < bits_(Y)) return(ErrCode_Size); + if (BitVector_msb_(Z)) return(ErrCode_Expo); + if ((last = Set_Max(Z)) < 0L) + { + if (bits < 2) return(ErrCode_Ovfl); + BitVector_Empty(X); + *X |= LSB; + return(ErrCode_Ok); /* anything ^ 0 == 1 */ + } + if (BitVector_is_empty(Y)) + { + if (X != Y) BitVector_Empty(X); + return(ErrCode_Ok); /* 0 ^ anything not zero == 0 */ + } + T = BitVector_Create(bits,FALSE); + if (T == NULL) return(ErrCode_Null); + limit = (N_word) last; + for ( count = 0; ((!error) and (count <= limit)); count++ ) + { + if ( BIT_VECTOR_TST_BIT(Z,count) ) + { + if (first) + { + first = FALSE; + if (count) { BitVector_Copy(X,T); } + else { if (X != Y) BitVector_Copy(X,Y); } + } + else error = BitVector_Multiply(X,T,X); /* order important because T > X */ + } + if ((!error) and (count < limit)) + { + if (count) error = BitVector_Multiply(T,T,T); + else error = BitVector_Multiply(T,Y,Y); + } + } + BitVector_Destroy(T); + return(error); +} + +void BitVector_Block_Store(wordptr addr, charptr buffer, N_int length) +{ + N_word size = size_(addr); + N_word mask = mask_(addr); + N_word value; + N_word count; + + /* provide translation for independence of endian-ness: */ + if (size > 0) + { + while (size-- > 0) + { + value = 0; + for ( count = 0; (length > 0) and (count < BITS); count += 8 ) + { + value |= (((N_word) *buffer++) << count); length--; + } + *addr++ = value; + } + *(--addr) &= mask; + } +} + +charptr BitVector_Block_Read(wordptr addr, N_intptr length) +{ + N_word size = size_(addr); + N_word value; + N_word count; + charptr buffer; + charptr target; + + /* provide translation for independence of endian-ness: */ + *length = size << FACTOR; + buffer = (charptr) yasm_xmalloc((size_t) ((*length)+1)); + if (buffer == NULL) return(NULL); + target = buffer; + if (size > 0) + { + *(addr+size-1) &= mask_(addr); + while (size-- > 0) + { + value = *addr++; + count = BITS >> 3; + while (count-- > 0) + { + *target++ = (N_char) (value AND 0x00FF); + if (count > 0) value >>= 8; + } + } + } + *target = (N_char) '\0'; + return(buffer); +} + +void BitVector_Word_Store(wordptr addr, N_int offset, N_int value) +{ + N_word size = size_(addr); + + if (size > 0) + { + if (offset < size) *(addr+offset) = value; + *(addr+size-1) &= mask_(addr); + } +} + +N_int BitVector_Word_Read(wordptr addr, N_int offset) +{ + N_word size = size_(addr); + + if (size > 0) + { + *(addr+size-1) &= mask_(addr); + if (offset < size) return( *(addr+offset) ); + } + return( (N_int) 0 ); +} + +void BitVector_Word_Insert(wordptr addr, N_int offset, N_int count, + boolean clear) +{ + N_word size = size_(addr); + N_word mask = mask_(addr); + wordptr last = addr+size-1; + + if (size > 0) + { + *last &= mask; + if (offset > size) offset = size; + BIT_VECTOR_ins_words(addr+offset,size-offset,count,clear); + *last &= mask; + } +} + +void BitVector_Word_Delete(wordptr addr, N_int offset, N_int count, + boolean clear) +{ + N_word size = size_(addr); + N_word mask = mask_(addr); + wordptr last = addr+size-1; + + if (size > 0) + { + *last &= mask; + if (offset > size) offset = size; + BIT_VECTOR_del_words(addr+offset,size-offset,count,clear); + *last &= mask; + } +} + +void BitVector_Chunk_Store(wordptr addr, N_int chunksize, N_int offset, + N_long value) +{ + N_word bits = bits_(addr); + N_word mask; + N_word temp; + + if ((chunksize > 0) and (offset < bits)) + { + if (chunksize > LONGBITS) chunksize = LONGBITS; + if ((offset + chunksize) > bits) chunksize = bits - offset; + addr += offset >> LOGBITS; + offset &= MODMASK; + while (chunksize > 0) + { + mask = (N_word) (~0L << offset); + bits = offset + chunksize; + if (bits < BITS) + { + mask &= (N_word) ~(~0L << bits); + bits = chunksize; + } + else bits = BITS - offset; + temp = (N_word) (value << offset); + temp &= mask; + *addr &= NOT mask; + *addr++ |= temp; + value >>= bits; + chunksize -= bits; + offset = 0; + } + } +} + +N_long BitVector_Chunk_Read(wordptr addr, N_int chunksize, N_int offset) +{ + N_word bits = bits_(addr); + N_word chunkbits = 0; + N_long value = 0L; + N_long temp; + N_word mask; + + if ((chunksize > 0) and (offset < bits)) + { + if (chunksize > LONGBITS) chunksize = LONGBITS; + if ((offset + chunksize) > bits) chunksize = bits - offset; + addr += offset >> LOGBITS; + offset &= MODMASK; + while (chunksize > 0) + { + bits = offset + chunksize; + if (bits < BITS) + { + mask = (N_word) ~(~0L << bits); + bits = chunksize; + } + else + { + mask = (N_word) ~0L; + bits = BITS - offset; + } + temp = (N_long) ((*addr++ AND mask) >> offset); + value |= temp << chunkbits; + chunkbits += bits; + chunksize -= bits; + offset = 0; + } + } + return(value); +} + + /*******************/ + /* set operations: */ + /*******************/ + +void Set_Union(wordptr X, wordptr Y, wordptr Z) /* X = Y + Z */ +{ + N_word bits = bits_(X); + N_word size = size_(X); + N_word mask = mask_(X); + + if ((size > 0) and (bits == bits_(Y)) and (bits == bits_(Z))) + { + while (size-- > 0) *X++ = *Y++ OR *Z++; + *(--X) &= mask; + } +} + +void Set_Intersection(wordptr X, wordptr Y, wordptr Z) /* X = Y * Z */ +{ + N_word bits = bits_(X); + N_word size = size_(X); + N_word mask = mask_(X); + + if ((size > 0) and (bits == bits_(Y)) and (bits == bits_(Z))) + { + while (size-- > 0) *X++ = *Y++ AND *Z++; + *(--X) &= mask; + } +} + +void Set_Difference(wordptr X, wordptr Y, wordptr Z) /* X = Y \ Z */ +{ + N_word bits = bits_(X); + N_word size = size_(X); + N_word mask = mask_(X); + + if ((size > 0) and (bits == bits_(Y)) and (bits == bits_(Z))) + { + while (size-- > 0) *X++ = *Y++ AND NOT *Z++; + *(--X) &= mask; + } +} + +void Set_ExclusiveOr(wordptr X, wordptr Y, wordptr Z) /* X=(Y+Z)\(Y*Z) */ +{ + N_word bits = bits_(X); + N_word size = size_(X); + N_word mask = mask_(X); + + if ((size > 0) and (bits == bits_(Y)) and (bits == bits_(Z))) + { + while (size-- > 0) *X++ = *Y++ XOR *Z++; + *(--X) &= mask; + } +} + +void Set_Complement(wordptr X, wordptr Y) /* X = ~Y */ +{ + N_word size = size_(X); + N_word mask = mask_(X); + + if ((size > 0) and (bits_(X) == bits_(Y))) + { + while (size-- > 0) *X++ = NOT *Y++; + *(--X) &= mask; + } +} + + /******************/ + /* set functions: */ + /******************/ + +boolean Set_subset(wordptr X, wordptr Y) /* X subset Y ? */ +{ + N_word size = size_(X); + boolean r = FALSE; + + if ((size > 0) and (bits_(X) == bits_(Y))) + { + r = TRUE; + while (r and (size-- > 0)) r = ((*X++ AND NOT *Y++) == 0); + } + return(r); +} + +N_int Set_Norm(wordptr addr) /* = | X | */ +{ + byteptr byte; + N_word bytes; + N_int n; + + byte = (byteptr) addr; + bytes = size_(addr) << FACTOR; + n = 0; + while (bytes-- > 0) + { + n += BitVector_BYTENORM[*byte++]; + } + return(n); +} + +N_int Set_Norm2(wordptr addr) /* = | X | */ +{ + N_word size = size_(addr); + N_word w0,w1; + N_int n,k; + + n = 0; + while (size-- > 0) + { + k = 0; + w1 = NOT (w0 = *addr++); + while (w0 and w1) + { + w0 &= w0 - 1; + w1 &= w1 - 1; + k++; + } + if (w0 == 0) n += k; + else n += BITS - k; + } + return(n); +} + +N_int Set_Norm3(wordptr addr) /* = | X | */ +{ + N_word size = size_(addr); + N_int count = 0; + N_word c; + + while (size-- > 0) + { + c = *addr++; + while (c) + { + c &= c - 1; + count++; + } + } + return(count); +} + +Z_long Set_Min(wordptr addr) /* = min(X) */ +{ + boolean empty = TRUE; + N_word size = size_(addr); + N_word i = 0; + N_word c = 0; /* silence compiler warning */ + + while (empty and (size-- > 0)) + { + if ((c = *addr++)) empty = false; else i++; + } + if (empty) return((Z_long) LONG_MAX); /* plus infinity */ + i <<= LOGBITS; + while (not (c AND LSB)) + { + c >>= 1; + i++; + } + return((Z_long) i); +} + +Z_long Set_Max(wordptr addr) /* = max(X) */ +{ + boolean empty = TRUE; + N_word size = size_(addr); + N_word i = size; + N_word c = 0; /* silence compiler warning */ + + addr += size-1; + while (empty and (size-- > 0)) + { + if ((c = *addr--)) empty = false; else i--; + } + if (empty) return((Z_long) LONG_MIN); /* minus infinity */ + i <<= LOGBITS; + while (not (c AND MSB)) + { + c <<= 1; + i--; + } + return((Z_long) --i); +} + + /**********************************/ + /* matrix-of-booleans operations: */ + /**********************************/ + +void Matrix_Multiplication(wordptr X, N_int rowsX, N_int colsX, + wordptr Y, N_int rowsY, N_int colsY, + wordptr Z, N_int rowsZ, N_int colsZ) +{ + N_word i; + N_word j; + N_word k; + N_word indxX; + N_word indxY; + N_word indxZ; + N_word termX; + N_word termY; + N_word sum; + + if ((colsY == rowsZ) and (rowsX == rowsY) and (colsX == colsZ) and + (bits_(X) == rowsX*colsX) and + (bits_(Y) == rowsY*colsY) and + (bits_(Z) == rowsZ*colsZ)) + { + for ( i = 0; i < rowsY; i++ ) + { + termX = i * colsX; + termY = i * colsY; + for ( j = 0; j < colsZ; j++ ) + { + indxX = termX + j; + sum = 0; + for ( k = 0; k < colsY; k++ ) + { + indxY = termY + k; + indxZ = k * colsZ + j; + if ( BIT_VECTOR_TST_BIT(Y,indxY) && + BIT_VECTOR_TST_BIT(Z,indxZ) ) sum ^= 1; + } + if (sum) BIT_VECTOR_SET_BIT(X,indxX) + else BIT_VECTOR_CLR_BIT(X,indxX) + } + } + } +} + +void Matrix_Product(wordptr X, N_int rowsX, N_int colsX, + wordptr Y, N_int rowsY, N_int colsY, + wordptr Z, N_int rowsZ, N_int colsZ) +{ + N_word i; + N_word j; + N_word k; + N_word indxX; + N_word indxY; + N_word indxZ; + N_word termX; + N_word termY; + N_word sum; + + if ((colsY == rowsZ) and (rowsX == rowsY) and (colsX == colsZ) and + (bits_(X) == rowsX*colsX) and + (bits_(Y) == rowsY*colsY) and + (bits_(Z) == rowsZ*colsZ)) + { + for ( i = 0; i < rowsY; i++ ) + { + termX = i * colsX; + termY = i * colsY; + for ( j = 0; j < colsZ; j++ ) + { + indxX = termX + j; + sum = 0; + for ( k = 0; k < colsY; k++ ) + { + indxY = termY + k; + indxZ = k * colsZ + j; + if ( BIT_VECTOR_TST_BIT(Y,indxY) && + BIT_VECTOR_TST_BIT(Z,indxZ) ) sum |= 1; + } + if (sum) BIT_VECTOR_SET_BIT(X,indxX) + else BIT_VECTOR_CLR_BIT(X,indxX) + } + } + } +} + +void Matrix_Closure(wordptr addr, N_int rows, N_int cols) +{ + N_word i; + N_word j; + N_word k; + N_word ii; + N_word ij; + N_word ik; + N_word kj; + N_word termi; + N_word termk; + + if ((rows == cols) and (bits_(addr) == rows*cols)) + { + for ( i = 0; i < rows; i++ ) + { + ii = i * cols + i; + BIT_VECTOR_SET_BIT(addr,ii) + } + for ( k = 0; k < rows; k++ ) + { + termk = k * cols; + for ( i = 0; i < rows; i++ ) + { + termi = i * cols; + ik = termi + k; + for ( j = 0; j < rows; j++ ) + { + ij = termi + j; + kj = termk + j; + if ( BIT_VECTOR_TST_BIT(addr,ik) && + BIT_VECTOR_TST_BIT(addr,kj) ) + BIT_VECTOR_SET_BIT(addr,ij) + } + } + } + } +} + +void Matrix_Transpose(wordptr X, N_int rowsX, N_int colsX, + wordptr Y, N_int rowsY, N_int colsY) +{ + N_word i; + N_word j; + N_word ii; + N_word ij; + N_word ji; + N_word addii; + N_word addij; + N_word addji; + N_word bitii; + N_word bitij; + N_word bitji; + N_word termi; + N_word termj; + boolean swap; + + /* BEWARE that "in-place" is ONLY possible if the matrix is quadratic!! */ + + if ((rowsX == colsY) and (colsX == rowsY) and + (bits_(X) == rowsX*colsX) and + (bits_(Y) == rowsY*colsY)) + { + if (rowsY == colsY) /* in-place is possible! */ + { + for ( i = 0; i < rowsY; i++ ) + { + termi = i * colsY; + for ( j = 0; j < i; j++ ) + { + termj = j * colsX; + ij = termi + j; + ji = termj + i; + addij = ij >> LOGBITS; + addji = ji >> LOGBITS; + bitij = BITMASKTAB[ij AND MODMASK]; + bitji = BITMASKTAB[ji AND MODMASK]; + swap = ((*(Y+addij) AND bitij) != 0); + if ((*(Y+addji) AND bitji) != 0) + *(X+addij) |= bitij; + else + *(X+addij) &= NOT bitij; + if (swap) + *(X+addji) |= bitji; + else + *(X+addji) &= NOT bitji; + } + ii = termi + i; + addii = ii >> LOGBITS; + bitii = BITMASKTAB[ii AND MODMASK]; + if ((*(Y+addii) AND bitii) != 0) + *(X+addii) |= bitii; + else + *(X+addii) &= NOT bitii; + } + } + else /* rowsX != colsX, in-place is NOT possible! */ + { + for ( i = 0; i < rowsY; i++ ) + { + termi = i * colsY; + for ( j = 0; j < colsY; j++ ) + { + termj = j * colsX; + ij = termi + j; + ji = termj + i; + addij = ij >> LOGBITS; + addji = ji >> LOGBITS; + bitij = BITMASKTAB[ij AND MODMASK]; + bitji = BITMASKTAB[ji AND MODMASK]; + if ((*(Y+addij) AND bitij) != 0) + *(X+addji) |= bitji; + else + *(X+addji) &= NOT bitji; + } + } + } + } +} + +/*****************************************************************************/ +/* VERSION: 6.4 */ +/*****************************************************************************/ +/* VERSION HISTORY: */ +/*****************************************************************************/ +/* */ +/* Version 6.4 03.10.04 Added C++ comp. directives. Improved "Norm()". */ +/* Version 6.3 28.09.02 Added "Create_List()" and "GCD2()". */ +/* Version 6.2 15.09.02 Overhauled error handling. Fixed "GCD()". */ +/* Version 6.1 08.10.01 Make VMS linker happy: _lsb,_msb => _lsb_,_msb_ */ +/* Version 6.0 08.10.00 Corrected overflow handling. */ +/* Version 5.8 14.07.00 Added "Power()". Changed "Copy()". */ +/* Version 5.7 19.05.99 Quickened "Div_Pos()". Added "Product()". */ +/* Version 5.6 02.11.98 Leading zeros eliminated in "to_Hex()". */ +/* Version 5.5 21.09.98 Fixed bug of uninitialized "error" in Multiply. */ +/* Version 5.4 07.09.98 Fixed bug of uninitialized "error" in Divide. */ +/* Version 5.3 12.05.98 Improved Norm. Completed history. */ +/* Version 5.2 31.03.98 Improved Norm. */ +/* Version 5.1 09.03.98 No changes. */ +/* Version 5.0 01.03.98 Major additions and rewrite. */ +/* Version 4.2 16.07.97 Added is_empty, is_full. */ +/* Version 4.1 30.06.97 Added word-ins/del, move-left/right, inc/dec. */ +/* Version 4.0 23.04.97 Rewrite. Added bit shift and bool. matrix ops. */ +/* Version 3.2 04.02.97 Added interval methods. */ +/* Version 3.1 21.01.97 Fixed bug on 64 bit machines. */ +/* Version 3.0 12.01.97 Added flip. */ +/* Version 2.0 14.12.96 Efficiency and consistency improvements. */ +/* Version 1.1 08.01.96 Added Resize and ExclusiveOr. */ +/* Version 1.0 14.12.95 First version under UNIX (with Perl module). */ +/* Version 0.9 01.11.93 First version of C library under MS-DOS. */ +/* Version 0.1 ??.??.89 First version in Turbo Pascal under CP/M. */ +/* */ +/*****************************************************************************/ +/* AUTHOR: */ +/*****************************************************************************/ +/* */ +/* Steffen Beyer */ +/* mailto:sb@engelschall.com */ +/* http://www.engelschall.com/u/sb/download/ */ +/* */ +/*****************************************************************************/ +/* COPYRIGHT: */ +/*****************************************************************************/ +/* */ +/* Copyright (c) 1995 - 2004 by Steffen Beyer. */ +/* All rights reserved. */ +/* */ +/*****************************************************************************/ +/* LICENSE: */ +/*****************************************************************************/ +/* This package is free software; you can use, modify and redistribute */ +/* it under the same terms as Perl itself, i.e., under the terms of */ +/* the "Artistic License" or the "GNU General Public License". */ +/* */ +/* The C library at the core of this Perl module can additionally */ +/* be used, modified and redistributed under the terms of the */ +/* "GNU Library General Public License". */ +/* */ +/*****************************************************************************/ +/* ARTISTIC LICENSE: */ +/*****************************************************************************/ +/* + The "Artistic License" + + Preamble + +The intent of this document is to state the conditions under which a +Package may be copied, such that the Copyright Holder maintains some +semblance of artistic control over the development of the package, +while giving the users of the package the right to use and distribute +the Package in a more-or-less customary fashion, plus the right to make +reasonable modifications. + +Definitions: + + "Package" refers to the collection of files distributed by the + Copyright Holder, and derivatives of that collection of files + created through textual modification. + + "Standard Version" refers to such a Package if it has not been + modified, or has been modified in accordance with the wishes + of the Copyright Holder as specified below. + + "Copyright Holder" is whoever is named in the copyright or + copyrights for the package. + + "You" is you, if you're thinking about copying or distributing + this Package. + + "Reasonable copying fee" is whatever you can justify on the + basis of media cost, duplication charges, time of people involved, + and so on. (You will not be required to justify it to the + Copyright Holder, but only to the computing community at large + as a market that must bear the fee.) + + "Freely Available" means that no fee is charged for the item + itself, though there may be fees involved in handling the item. + It also means that recipients of the item may redistribute it + under the same conditions they received it. + +1. You may make and give away verbatim copies of the source form of the +Standard Version of this Package without restriction, provided that you +duplicate all of the original copyright notices and associated disclaimers. + +2. You may apply bug fixes, portability fixes and other modifications +derived from the Public Domain or from the Copyright Holder. A Package +modified in such a way shall still be considered the Standard Version. + +3. You may otherwise modify your copy of this Package in any way, provided +that you insert a prominent notice in each changed file stating how and +when you changed that file, and provided that you do at least ONE of the +following: + + a) place your modifications in the Public Domain or otherwise make them + Freely Available, such as by posting said modifications to Usenet or + an equivalent medium, or placing the modifications on a major archive + site such as uunet.uu.net, or by allowing the Copyright Holder to include + your modifications in the Standard Version of the Package. + + b) use the modified Package only within your corporation or organization. + + c) rename any non-standard executables so the names do not conflict + with standard executables, which must also be provided, and provide + a separate manual page for each non-standard executable that clearly + documents how it differs from the Standard Version. + + d) make other distribution arrangements with the Copyright Holder. + +4. You may distribute the programs of this Package in object code or +executable form, provided that you do at least ONE of the following: + + a) distribute a Standard Version of the executables and library files, + together with instructions (in the manual page or equivalent) on where + to get the Standard Version. + + b) accompany the distribution with the machine-readable source of + the Package with your modifications. + + c) give non-standard executables non-standard names, and clearly + document the differences in manual pages (or equivalent), together + with instructions on where to get the Standard Version. + + d) make other distribution arrangements with the Copyright Holder. + +5. You may charge a reasonable copying fee for any distribution of this +Package. You may charge any fee you choose for support of this +Package. You may not charge a fee for this Package itself. However, +you may distribute this Package in aggregate with other (possibly +commercial) programs as part of a larger (possibly commercial) software +distribution provided that you do not advertise this Package as a +product of your own. You may embed this Package's interpreter within +an executable of yours (by linking); this shall be construed as a mere +form of aggregation, provided that the complete Standard Version of the +interpreter is so embedded. + +6. The scripts and library files supplied as input to or produced as +output from the programs of this Package do not automatically fall +under the copyright of this Package, but belong to whoever generated +them, and may be sold commercially, and may be aggregated with this +Package. If such scripts or library files are aggregated with this +Package via the so-called "undump" or "unexec" methods of producing a +binary executable image, then distribution of such an image shall +neither be construed as a distribution of this Package nor shall it +fall under the restrictions of Paragraphs 3 and 4, provided that you do +not represent such an executable image as a Standard Version of this +Package. + +7. C subroutines (or comparably compiled subroutines in other +languages) supplied by you and linked into this Package in order to +emulate subroutines and variables of the language defined by this +Package shall not be considered part of this Package, but are the +equivalent of input as in Paragraph 6, provided these subroutines do +not change the language in any way that would cause it to fail the +regression tests for the language. + +8. Aggregation of this Package with a commercial distribution is always +permitted provided that the use of this Package is embedded; that is, +when no overt attempt is made to make this Package's interfaces visible +to the end user of the commercial distribution. Such use shall not be +construed as a distribution of this Package. + +9. The name of the Copyright Holder may not be used to endorse or promote +products derived from this software without specific prior written permission. + +10. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED +WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + + The End +*/ +/*****************************************************************************/ +/* GNU GENERAL PUBLIC LICENSE: */ +/*****************************************************************************/ +/* This program is free software; you can redistribute it and/or */ +/* modify it under the terms of the GNU General Public License */ +/* as published by the Free Software Foundation; either version 2 */ +/* of the License, or (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU General Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License */ +/* along with this program; if not, write to the */ +/* Free Software Foundation, Inc., */ +/* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* */ +/*****************************************************************************/ +/* GNU LIBRARY GENERAL PUBLIC LICENSE: */ +/*****************************************************************************/ +/* This library is free software; you can redistribute it and/or */ +/* modify it under the terms of the GNU Library General Public */ +/* License as published by the Free Software Foundation; either */ +/* version 2 of the License, or (at your option) any later version. */ +/* */ +/* This library is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU */ +/* Library General Public License for more details. */ +/* */ +/* You should have received a copy of the GNU Library General Public */ +/* License along with this library; if not, write to the */ +/* Free Software Foundation, Inc., */ +/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* */ +/* or download a copy from ftp://ftp.gnu.org/pub/gnu/COPYING.LIB-2.0 */ +/* */ +/*****************************************************************************/ diff --git a/contrib/tools/yasm/libyasm/bitvect.h b/contrib/tools/yasm/libyasm/bitvect.h new file mode 100644 index 0000000000..3aee3a5319 --- /dev/null +++ b/contrib/tools/yasm/libyasm/bitvect.h @@ -0,0 +1,666 @@ +#ifndef YASM_BITVECT_H +#define YASM_BITVECT_H +/*****************************************************************************/ +/* MODULE NAME: BitVector.h MODULE TYPE: (adt) */ +/*****************************************************************************/ +/* MODULE IMPORTS: */ +/*****************************************************************************/ + +/* ToolBox.h */ +/*****************************************************************************/ +/* NOTE: The type names that have been chosen here are somewhat weird on */ +/* purpose, in order to avoid name clashes with system header files */ +/* and your own application(s) which might - directly or indirectly - */ +/* include this definitions file. */ +/*****************************************************************************/ +#ifndef YASM_LIB_DECL +#define YASM_LIB_DECL +#endif + +typedef unsigned char N_char; +typedef unsigned char N_byte; +typedef unsigned short N_short; +typedef unsigned short N_shortword; +typedef unsigned int N_int; +typedef unsigned int N_word; +typedef unsigned long N_long; +typedef unsigned long N_longword; + +/* Mnemonic 1: The natural numbers, N = { 0, 1, 2, 3, ... } */ +/* Mnemonic 2: Nnnn = u_N_signed, _N_ot signed */ + +typedef signed char Z_char; +typedef signed char Z_byte; +typedef signed short Z_short; +typedef signed short Z_shortword; +typedef signed int Z_int; +typedef signed int Z_word; +typedef signed long Z_long; +typedef signed long Z_longword; + +/* Mnemonic 1: The whole numbers, Z = { 0, -1, 1, -2, 2, -3, 3, ... } */ +/* Mnemonic 2: Zzzz = Ssss_igned */ + +typedef void *voidptr; +typedef N_char *charptr; +typedef N_byte *byteptr; +typedef N_short *shortptr; +typedef N_shortword *shortwordptr; +typedef N_int *intptr; +typedef N_word *wordptr; +typedef N_long *longptr; +typedef N_longword *longwordptr; + +typedef N_char *N_charptr; +typedef N_byte *N_byteptr; +typedef N_short *N_shortptr; +typedef N_shortword *N_shortwordptr; +typedef N_int *N_intptr; +typedef N_word *N_wordptr; +typedef N_long *N_longptr; +typedef N_longword *N_longwordptr; + +typedef Z_char *Z_charptr; +typedef Z_byte *Z_byteptr; +typedef Z_short *Z_shortptr; +typedef Z_shortword *Z_shortwordptr; +typedef Z_int *Z_intptr; +typedef Z_word *Z_wordptr; +typedef Z_long *Z_longptr; +typedef Z_longword *Z_longwordptr; + +#ifndef FALSE +#define FALSE (0!=0) +#endif + +#ifndef TRUE +#define TRUE (0==0) +#endif + +#ifdef __cplusplus + typedef bool boolean; +#else + #ifdef MACOS_TRADITIONAL + #define boolean Boolean + #else + typedef enum boolean { false = FALSE, true = TRUE } boolean; + #endif +#endif + +/*****************************************************************************/ +/* MODULE INTERFACE: */ +/*****************************************************************************/ + +typedef enum ErrCode + { + ErrCode_Ok = 0, /* everything went allright */ + + ErrCode_Type, /* types word and size_t have incompatible sizes */ + ErrCode_Bits, /* bits of word and sizeof(word) are inconsistent */ + ErrCode_Word, /* size of word is less than 16 bits */ + ErrCode_Long, /* size of word is greater than size of long */ + ErrCode_Powr, /* number of bits of word is not a power of two */ + ErrCode_Loga, /* error in calculation of logarithm */ + + ErrCode_Null, /* unable to allocate memory */ + + ErrCode_Indx, /* index out of range */ + ErrCode_Ordr, /* minimum > maximum index */ + ErrCode_Size, /* bit vector size mismatch */ + ErrCode_Pars, /* input string syntax error */ + ErrCode_Ovfl, /* numeric overflow error */ + ErrCode_Same, /* operands must be distinct */ + ErrCode_Expo, /* exponent must be positive */ + ErrCode_Zero /* division by zero error */ + } ErrCode; + +typedef wordptr *listptr; + +/* ===> MISCELLANEOUS BASIC FUNCTIONS: <=== */ + +YASM_LIB_DECL +const char * BitVector_Error (ErrCode error); /* return string for err code */ + +YASM_LIB_DECL +ErrCode BitVector_Boot (void); /* 0 = ok, 1..7 = error */ +YASM_LIB_DECL +void BitVector_Shutdown (void); /* undo Boot */ + +YASM_LIB_DECL +N_word BitVector_Size (N_int bits); /* bit vector size (# of words) */ +YASM_LIB_DECL +N_word BitVector_Mask (N_int bits); /* bit vector mask (unused bits) */ + +/* ===> CLASS METHODS: <=== */ + +YASM_LIB_DECL +const char * BitVector_Version (void); /* returns version string */ + +YASM_LIB_DECL +N_int BitVector_Word_Bits (void); /* return # of bits in machine word */ +YASM_LIB_DECL +N_int BitVector_Long_Bits (void); /* return # of bits in unsigned long */ + +/* ===> CONSTRUCTOR METHODS: <=== */ + +YASM_LIB_DECL +/*@only@*/ wordptr BitVector_Create (N_int bits, boolean clear); /* malloc */ +YASM_LIB_DECL +listptr BitVector_Create_List(N_int bits, boolean clear, N_int count); + +YASM_LIB_DECL +wordptr BitVector_Resize (wordptr oldaddr, N_int bits); /* realloc */ + +YASM_LIB_DECL +wordptr BitVector_Shadow (wordptr addr); /* make new same size but empty */ +YASM_LIB_DECL +wordptr BitVector_Clone (wordptr addr); /* make exact duplicate */ + +YASM_LIB_DECL +wordptr BitVector_Concat (wordptr X, wordptr Y); /* return concatenation */ + +/* ===> DESTRUCTOR METHODS: <=== */ + +YASM_LIB_DECL +void BitVector_Dispose (/*@only@*/ /*@out@*/ charptr string); /* string */ +YASM_LIB_DECL +void BitVector_Destroy (/*@only@*/ wordptr addr); /* bitvec */ +YASM_LIB_DECL +void BitVector_Destroy_List (listptr list, N_int count); /* list */ + +/* ===> OBJECT METHODS: <=== */ + +/* ===> bit vector copy function: */ + +YASM_LIB_DECL +void BitVector_Copy (wordptr X, wordptr Y); /* X = Y */ + +/* ===> bit vector initialization: */ + +YASM_LIB_DECL +void BitVector_Empty (wordptr addr); /* X = {} */ +YASM_LIB_DECL +void BitVector_Fill (wordptr addr); /* X = ~{} */ +YASM_LIB_DECL +void BitVector_Flip (wordptr addr); /* X = ~X */ + +YASM_LIB_DECL +void BitVector_Primes (wordptr addr); + +/* ===> miscellaneous functions: */ + +YASM_LIB_DECL +void BitVector_Reverse (wordptr X, wordptr Y); + +/* ===> bit vector interval operations and functions: */ + +YASM_LIB_DECL +void BitVector_Interval_Empty (/*@out@*/ wordptr addr, N_int lower, N_int upper); +YASM_LIB_DECL +void BitVector_Interval_Fill (/*@out@*/ wordptr addr, N_int lower, N_int upper); +YASM_LIB_DECL +void BitVector_Interval_Flip (/*@out@*/ wordptr addr, N_int lower, N_int upper); +YASM_LIB_DECL +void BitVector_Interval_Reverse (/*@out@*/ wordptr addr, N_int lower, N_int upper); + +YASM_LIB_DECL +boolean BitVector_interval_scan_inc (wordptr addr, N_int start, + N_intptr min, N_intptr max); +YASM_LIB_DECL +boolean BitVector_interval_scan_dec (wordptr addr, N_int start, + N_intptr min, N_intptr max); + +YASM_LIB_DECL +void BitVector_Interval_Copy (/*@out@*/ wordptr X, wordptr Y, N_int Xoffset, + N_int Yoffset, N_int length); + +YASM_LIB_DECL +wordptr BitVector_Interval_Substitute(/*@out@*/ wordptr X, wordptr Y, + N_int Xoffset, N_int Xlength, + N_int Yoffset, N_int Ylength); + +/* ===> bit vector test functions: */ + +YASM_LIB_DECL +boolean BitVector_is_empty (wordptr addr); /* X == {} ? */ +YASM_LIB_DECL +boolean BitVector_is_full (wordptr addr); /* X == ~{} ? */ + +YASM_LIB_DECL +boolean BitVector_equal (wordptr X, wordptr Y); /* X == Y ? */ +YASM_LIB_DECL +Z_int BitVector_Lexicompare(wordptr X, wordptr Y); /* X <,=,> Y ? */ +YASM_LIB_DECL +Z_int BitVector_Compare (wordptr X, wordptr Y); /* X <,=,> Y ? */ + +/* ===> bit vector string conversion functions: */ + +YASM_LIB_DECL +/*@only@*/ charptr BitVector_to_Hex (wordptr addr); +YASM_LIB_DECL +ErrCode BitVector_from_Hex (/*@out@*/wordptr addr, charptr string); + +YASM_LIB_DECL +ErrCode BitVector_from_Oct(/*@out@*/ wordptr addr, charptr string); + +YASM_LIB_DECL +/*@only@*/ charptr BitVector_to_Bin (wordptr addr); +YASM_LIB_DECL +ErrCode BitVector_from_Bin (/*@out@*/ wordptr addr, charptr string); + +YASM_LIB_DECL +/*@only@*/ charptr BitVector_to_Dec (wordptr addr); +YASM_LIB_DECL +ErrCode BitVector_from_Dec (/*@out@*/ wordptr addr, charptr string); + +typedef struct BitVector_from_Dec_static_data BitVector_from_Dec_static_data; +YASM_LIB_DECL +BitVector_from_Dec_static_data *BitVector_from_Dec_static_Boot(N_word bits); +YASM_LIB_DECL +void BitVector_from_Dec_static_Shutdown(/*@null@*/ BitVector_from_Dec_static_data *data); +YASM_LIB_DECL +ErrCode BitVector_from_Dec_static(BitVector_from_Dec_static_data *data, + /*@out@*/ wordptr addr, charptr string); + +YASM_LIB_DECL +/*@only@*/ charptr BitVector_to_Enum (wordptr addr); +YASM_LIB_DECL +ErrCode BitVector_from_Enum (/*@out@*/ wordptr addr, charptr string); + +/* ===> bit vector bit operations, functions & tests: */ + +YASM_LIB_DECL +void BitVector_Bit_Off (/*@out@*/ wordptr addr, N_int indx); /* X = X \ {x} */ +YASM_LIB_DECL +void BitVector_Bit_On (/*@out@*/ wordptr addr, N_int indx); /* X = X + {x} */ +YASM_LIB_DECL +boolean BitVector_bit_flip (/*@out@*/ wordptr addr, N_int indx); /* (X+{x})\(X*{x}) */ + +YASM_LIB_DECL +boolean BitVector_bit_test (wordptr addr, N_int indx); /* {x} in X ? */ + +YASM_LIB_DECL +void BitVector_Bit_Copy (/*@out@*/ wordptr addr, N_int indx, boolean bit); + +/* ===> bit vector bit shift & rotate functions: */ + +YASM_LIB_DECL +void BitVector_LSB (/*@out@*/ wordptr addr, boolean bit); +YASM_LIB_DECL +void BitVector_MSB (/*@out@*/ wordptr addr, boolean bit); +YASM_LIB_DECL +boolean BitVector_lsb_ (wordptr addr); +YASM_LIB_DECL +boolean BitVector_msb_ (wordptr addr); +YASM_LIB_DECL +boolean /*@alt void@*/ BitVector_rotate_left (wordptr addr); +YASM_LIB_DECL +boolean /*@alt void@*/ BitVector_rotate_right (wordptr addr); +YASM_LIB_DECL +boolean /*@alt void@*/ BitVector_shift_left (wordptr addr, boolean carry_in); +YASM_LIB_DECL +boolean /*@alt void@*/ BitVector_shift_right (wordptr addr, boolean carry_in); +YASM_LIB_DECL +void BitVector_Move_Left (wordptr addr, N_int bits); +YASM_LIB_DECL +void BitVector_Move_Right (wordptr addr, N_int bits); + +/* ===> bit vector insert/delete bits: */ + +YASM_LIB_DECL +void BitVector_Insert (wordptr addr, N_int offset, N_int count, + boolean clear); +YASM_LIB_DECL +void BitVector_Delete (wordptr addr, N_int offset, N_int count, + boolean clear); + +/* ===> bit vector arithmetic: */ + +YASM_LIB_DECL +boolean /*@alt void@*/ BitVector_increment (wordptr addr); /* X++ */ +YASM_LIB_DECL +boolean /*@alt void@*/ BitVector_decrement (wordptr addr); /* X-- */ + +YASM_LIB_DECL +boolean /*@alt void@*/ BitVector_compute (wordptr X, wordptr Y, wordptr Z, boolean minus, + boolean *carry); +YASM_LIB_DECL +boolean /*@alt void@*/ BitVector_add (wordptr X, wordptr Y, wordptr Z, boolean *carry); +YASM_LIB_DECL +boolean /*@alt void@*/ BitVector_sub (wordptr X, wordptr Y, wordptr Z, boolean *carry); +YASM_LIB_DECL +boolean /*@alt void@*/ BitVector_inc (wordptr X, wordptr Y); +YASM_LIB_DECL +boolean /*@alt void@*/ BitVector_dec (wordptr X, wordptr Y); + +YASM_LIB_DECL +void BitVector_Negate (wordptr X, wordptr Y); +YASM_LIB_DECL +void BitVector_Absolute (wordptr X, wordptr Y); +YASM_LIB_DECL +Z_int BitVector_Sign (wordptr addr); +YASM_LIB_DECL +ErrCode BitVector_Mul_Pos (wordptr X, wordptr Y, wordptr Z, boolean strict); +YASM_LIB_DECL +ErrCode BitVector_Multiply (wordptr X, wordptr Y, wordptr Z); +YASM_LIB_DECL +ErrCode BitVector_Div_Pos (wordptr Q, wordptr X, wordptr Y, wordptr R); +YASM_LIB_DECL +ErrCode BitVector_Divide (wordptr Q, wordptr X, wordptr Y, wordptr R); +YASM_LIB_DECL +ErrCode BitVector_GCD (wordptr X, wordptr Y, wordptr Z); +YASM_LIB_DECL +ErrCode BitVector_GCD2 (wordptr U, wordptr V, wordptr W, /* O */ + wordptr X, wordptr Y); /* I */ +YASM_LIB_DECL +ErrCode BitVector_Power (wordptr X, wordptr Y, wordptr Z); + +/* ===> direct memory access functions: */ + +YASM_LIB_DECL +void BitVector_Block_Store(wordptr addr, charptr buffer, N_int length); +YASM_LIB_DECL +charptr BitVector_Block_Read (wordptr addr, /*@out@*/ N_intptr length); + +/* ===> word array functions: */ + +YASM_LIB_DECL +void BitVector_Word_Store (wordptr addr, N_int offset, N_int value); +YASM_LIB_DECL +N_int BitVector_Word_Read (wordptr addr, N_int offset); + +YASM_LIB_DECL +void BitVector_Word_Insert(wordptr addr, N_int offset, N_int count, + boolean clear); +YASM_LIB_DECL +void BitVector_Word_Delete(wordptr addr, N_int offset, N_int count, + boolean clear); + +/* ===> arbitrary size chunk functions: */ + +YASM_LIB_DECL +void BitVector_Chunk_Store(wordptr addr, N_int chunksize, + N_int offset, N_long value); +YASM_LIB_DECL +N_long BitVector_Chunk_Read (wordptr addr, N_int chunksize, + N_int offset); + +/* ===> set operations: */ + +YASM_LIB_DECL +void Set_Union (wordptr X, wordptr Y, wordptr Z); /* X = Y + Z */ +YASM_LIB_DECL +void Set_Intersection (wordptr X, wordptr Y, wordptr Z); /* X = Y * Z */ +YASM_LIB_DECL +void Set_Difference (wordptr X, wordptr Y, wordptr Z); /* X = Y \ Z */ +YASM_LIB_DECL +void Set_ExclusiveOr (wordptr X, wordptr Y, wordptr Z); /*(Y+Z)\(Y*Z)*/ +YASM_LIB_DECL +void Set_Complement (wordptr X, wordptr Y); /* X = ~Y */ + +/* ===> set functions: */ + +YASM_LIB_DECL +boolean Set_subset (wordptr X, wordptr Y); /* X in Y ? */ + +YASM_LIB_DECL +N_int Set_Norm (wordptr addr); /* = | X | */ +YASM_LIB_DECL +N_int Set_Norm2 (wordptr addr); /* = | X | */ +YASM_LIB_DECL +N_int Set_Norm3 (wordptr addr); /* = | X | */ +YASM_LIB_DECL +Z_long Set_Min (wordptr addr); /* = min(X) */ +YASM_LIB_DECL +Z_long Set_Max (wordptr addr); /* = max(X) */ + +/* ===> matrix-of-booleans operations: */ + +YASM_LIB_DECL +void Matrix_Multiplication(wordptr X, N_int rowsX, N_int colsX, + wordptr Y, N_int rowsY, N_int colsY, + wordptr Z, N_int rowsZ, N_int colsZ); + +YASM_LIB_DECL +void Matrix_Product (wordptr X, N_int rowsX, N_int colsX, + wordptr Y, N_int rowsY, N_int colsY, + wordptr Z, N_int rowsZ, N_int colsZ); + +YASM_LIB_DECL +void Matrix_Closure (wordptr addr, N_int rows, N_int cols); + +YASM_LIB_DECL +void Matrix_Transpose (wordptr X, N_int rowsX, N_int colsX, + wordptr Y, N_int rowsY, N_int colsY); + +/*****************************************************************************/ +/* VERSION: 6.4 */ +/*****************************************************************************/ +/* VERSION HISTORY: */ +/*****************************************************************************/ +/* */ +/* Version 6.4 03.10.04 Added C++ comp. directives. Improved "Norm()". */ +/* Version 6.3 28.09.02 Added "Create_List()" and "GCD2()". */ +/* Version 6.2 15.09.02 Overhauled error handling. Fixed "GCD()". */ +/* Version 6.1 08.10.01 Make VMS linker happy: _lsb,_msb => _lsb_,_msb_ */ +/* Version 6.0 08.10.00 Corrected overflow handling. */ +/* Version 5.8 14.07.00 Added "Power()". Changed "Copy()". */ +/* Version 5.7 19.05.99 Quickened "Div_Pos()". Added "Product()". */ +/* Version 5.6 02.11.98 Leading zeros eliminated in "to_Hex()". */ +/* Version 5.5 21.09.98 Fixed bug of uninitialized "error" in Multiply. */ +/* Version 5.4 07.09.98 Fixed bug of uninitialized "error" in Divide. */ +/* Version 5.3 12.05.98 Improved Norm. Completed history. */ +/* Version 5.2 31.03.98 Improved Norm. */ +/* Version 5.1 09.03.98 No changes. */ +/* Version 5.0 01.03.98 Major additions and rewrite. */ +/* Version 4.2 16.07.97 Added is_empty, is_full. */ +/* Version 4.1 30.06.97 Added word-ins/del, move-left/right, inc/dec. */ +/* Version 4.0 23.04.97 Rewrite. Added bit shift and bool. matrix ops. */ +/* Version 3.2 04.02.97 Added interval methods. */ +/* Version 3.1 21.01.97 Fixed bug on 64 bit machines. */ +/* Version 3.0 12.01.97 Added flip. */ +/* Version 2.0 14.12.96 Efficiency and consistency improvements. */ +/* Version 1.1 08.01.96 Added Resize and ExclusiveOr. */ +/* Version 1.0 14.12.95 First version under UNIX (with Perl module). */ +/* Version 0.9 01.11.93 First version of C library under MS-DOS. */ +/* Version 0.1 ??.??.89 First version in Turbo Pascal under CP/M. */ +/* */ +/*****************************************************************************/ +/* AUTHOR: */ +/*****************************************************************************/ +/* */ +/* Steffen Beyer */ +/* mailto:sb@engelschall.com */ +/* http://www.engelschall.com/u/sb/download/ */ +/* */ +/*****************************************************************************/ +/* COPYRIGHT: */ +/*****************************************************************************/ +/* */ +/* Copyright (c) 1995 - 2004 by Steffen Beyer. */ +/* All rights reserved. */ +/* */ +/*****************************************************************************/ +/* LICENSE: */ +/*****************************************************************************/ +/* This package is free software; you can use, modify and redistribute */ +/* it under the same terms as Perl itself, i.e., under the terms of */ +/* the "Artistic License" or the "GNU General Public License". */ +/* */ +/* The C library at the core of this Perl module can additionally */ +/* be used, modified and redistributed under the terms of the */ +/* "GNU Library General Public License". */ +/* */ +/*****************************************************************************/ +/* ARTISTIC LICENSE: */ +/*****************************************************************************/ +/* + The "Artistic License" + + Preamble + +The intent of this document is to state the conditions under which a +Package may be copied, such that the Copyright Holder maintains some +semblance of artistic control over the development of the package, +while giving the users of the package the right to use and distribute +the Package in a more-or-less customary fashion, plus the right to make +reasonable modifications. + +Definitions: + + "Package" refers to the collection of files distributed by the + Copyright Holder, and derivatives of that collection of files + created through textual modification. + + "Standard Version" refers to such a Package if it has not been + modified, or has been modified in accordance with the wishes + of the Copyright Holder as specified below. + + "Copyright Holder" is whoever is named in the copyright or + copyrights for the package. + + "You" is you, if you're thinking about copying or distributing + this Package. + + "Reasonable copying fee" is whatever you can justify on the + basis of media cost, duplication charges, time of people involved, + and so on. (You will not be required to justify it to the + Copyright Holder, but only to the computing community at large + as a market that must bear the fee.) + + "Freely Available" means that no fee is charged for the item + itself, though there may be fees involved in handling the item. + It also means that recipients of the item may redistribute it + under the same conditions they received it. + +1. You may make and give away verbatim copies of the source form of the +Standard Version of this Package without restriction, provided that you +duplicate all of the original copyright notices and associated disclaimers. + +2. You may apply bug fixes, portability fixes and other modifications +derived from the Public Domain or from the Copyright Holder. A Package +modified in such a way shall still be considered the Standard Version. + +3. You may otherwise modify your copy of this Package in any way, provided +that you insert a prominent notice in each changed file stating how and +when you changed that file, and provided that you do at least ONE of the +following: + + a) place your modifications in the Public Domain or otherwise make them + Freely Available, such as by posting said modifications to Usenet or + an equivalent medium, or placing the modifications on a major archive + site such as uunet.uu.net, or by allowing the Copyright Holder to include + your modifications in the Standard Version of the Package. + + b) use the modified Package only within your corporation or organization. + + c) rename any non-standard executables so the names do not conflict + with standard executables, which must also be provided, and provide + a separate manual page for each non-standard executable that clearly + documents how it differs from the Standard Version. + + d) make other distribution arrangements with the Copyright Holder. + +4. You may distribute the programs of this Package in object code or +executable form, provided that you do at least ONE of the following: + + a) distribute a Standard Version of the executables and library files, + together with instructions (in the manual page or equivalent) on where + to get the Standard Version. + + b) accompany the distribution with the machine-readable source of + the Package with your modifications. + + c) give non-standard executables non-standard names, and clearly + document the differences in manual pages (or equivalent), together + with instructions on where to get the Standard Version. + + d) make other distribution arrangements with the Copyright Holder. + +5. You may charge a reasonable copying fee for any distribution of this +Package. You may charge any fee you choose for support of this +Package. You may not charge a fee for this Package itself. However, +you may distribute this Package in aggregate with other (possibly +commercial) programs as part of a larger (possibly commercial) software +distribution provided that you do not advertise this Package as a +product of your own. You may embed this Package's interpreter within +an executable of yours (by linking); this shall be construed as a mere +form of aggregation, provided that the complete Standard Version of the +interpreter is so embedded. + +6. The scripts and library files supplied as input to or produced as +output from the programs of this Package do not automatically fall +under the copyright of this Package, but belong to whoever generated +them, and may be sold commercially, and may be aggregated with this +Package. If such scripts or library files are aggregated with this +Package via the so-called "undump" or "unexec" methods of producing a +binary executable image, then distribution of such an image shall +neither be construed as a distribution of this Package nor shall it +fall under the restrictions of Paragraphs 3 and 4, provided that you do +not represent such an executable image as a Standard Version of this +Package. + +7. C subroutines (or comparably compiled subroutines in other +languages) supplied by you and linked into this Package in order to +emulate subroutines and variables of the language defined by this +Package shall not be considered part of this Package, but are the +equivalent of input as in Paragraph 6, provided these subroutines do +not change the language in any way that would cause it to fail the +regression tests for the language. + +8. Aggregation of this Package with a commercial distribution is always +permitted provided that the use of this Package is embedded; that is, +when no overt attempt is made to make this Package's interfaces visible +to the end user of the commercial distribution. Such use shall not be +construed as a distribution of this Package. + +9. The name of the Copyright Holder may not be used to endorse or promote +products derived from this software without specific prior written permission. + +10. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED +WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + + The End +*/ +/*****************************************************************************/ +/* GNU GENERAL PUBLIC LICENSE: */ +/*****************************************************************************/ +/* This program is free software; you can redistribute it and/or */ +/* modify it under the terms of the GNU General Public License */ +/* as published by the Free Software Foundation; either version 2 */ +/* of the License, or (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU General Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License */ +/* along with this program; if not, write to the */ +/* Free Software Foundation, Inc., */ +/* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* */ +/*****************************************************************************/ +/* GNU LIBRARY GENERAL PUBLIC LICENSE: */ +/*****************************************************************************/ +/* */ +/* This library is free software; you can redistribute it and/or */ +/* modify it under the terms of the GNU Library General Public */ +/* License as published by the Free Software Foundation; either */ +/* version 2 of the License, or (at your option) any later version. */ +/* */ +/* This library is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU */ +/* Library General Public License for more details. */ +/* */ +/* You should have received a copy of the GNU Library General Public */ +/* License along with this library; if not, write to the */ +/* Free Software Foundation, Inc., */ +/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* */ +/* or download a copy from ftp://ftp.gnu.org/pub/gnu/COPYING.LIB-2.0 */ +/* */ +/*****************************************************************************/ +#endif diff --git a/contrib/tools/yasm/libyasm/bytecode.c b/contrib/tools/yasm/libyasm/bytecode.c new file mode 100644 index 0000000000..f864bae0aa --- /dev/null +++ b/contrib/tools/yasm/libyasm/bytecode.c @@ -0,0 +1,386 @@ +/* + * 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-stdint.h" +#include "coretype.h" + +#include "errwarn.h" +#include "intnum.h" +#include "expr.h" +#include "value.h" +#include "symrec.h" + +#include "bytecode.h" + + +void +yasm_bc_set_multiple(yasm_bytecode *bc, yasm_expr *e) +{ + if (bc->multiple) + bc->multiple = yasm_expr_create_tree(bc->multiple, YASM_EXPR_MUL, e, + e->line); + else + bc->multiple = e; +} + +void +yasm_bc_finalize_common(yasm_bytecode *bc, yasm_bytecode *prev_bc) +{ +} + +int +yasm_bc_calc_len_common(yasm_bytecode *bc, yasm_bc_add_span_func add_span, + void *add_span_data) +{ + yasm_internal_error(N_("bytecode length cannot be calculated")); + /*@unreached@*/ + return 0; +} + +int +yasm_bc_expand_common(yasm_bytecode *bc, int span, long old_val, long new_val, + /*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres) +{ + yasm_internal_error(N_("bytecode does not have any dependent spans")); + /*@unreached@*/ + return 0; +} + +int +yasm_bc_tobytes_common(yasm_bytecode *bc, unsigned char **buf, + unsigned char *bufstart, void *d, + yasm_output_value_func output_value, + /*@null@*/ yasm_output_reloc_func output_reloc) +{ + yasm_internal_error(N_("bytecode cannot be converted to bytes")); + /*@unreached@*/ + return 0; +} + +void +yasm_bc_transform(yasm_bytecode *bc, const yasm_bytecode_callback *callback, + void *contents) +{ + if (bc->callback) + bc->callback->destroy(bc->contents); + bc->callback = callback; + bc->contents = contents; +} + +yasm_bytecode * +yasm_bc_create_common(const yasm_bytecode_callback *callback, void *contents, + unsigned long line) +{ + yasm_bytecode *bc = yasm_xmalloc(sizeof(yasm_bytecode)); + + bc->callback = callback; + bc->section = NULL; + bc->multiple = (yasm_expr *)NULL; + bc->len = 0; + bc->mult_int = 1; + bc->line = line; + bc->offset = ~0UL; /* obviously incorrect / uninitialized value */ + bc->symrecs = NULL; + bc->contents = contents; + + return bc; +} + +yasm_section * +yasm_bc_get_section(yasm_bytecode *bc) +{ + return bc->section; +} + +void +yasm_bc__add_symrec(yasm_bytecode *bc, yasm_symrec *sym) +{ + if (!bc->symrecs) { + bc->symrecs = yasm_xmalloc(2*sizeof(yasm_symrec *)); + bc->symrecs[0] = sym; + bc->symrecs[1] = NULL; + } else { + /* Very inefficient implementation for large numbers of symbols. But + * that would be very unusual, so use the simple algorithm instead. + */ + size_t count = 1; + while (bc->symrecs[count]) + count++; + bc->symrecs = yasm_xrealloc(bc->symrecs, + (count+2)*sizeof(yasm_symrec *)); + bc->symrecs[count] = sym; + bc->symrecs[count+1] = NULL; + } +} + +void +yasm_bc_destroy(yasm_bytecode *bc) +{ + if (!bc) + return; + + if (bc->callback) + bc->callback->destroy(bc->contents); + yasm_expr_destroy(bc->multiple); + if (bc->symrecs) + yasm_xfree(bc->symrecs); + yasm_xfree(bc); +} + +void +yasm_bc_print(const yasm_bytecode *bc, FILE *f, int indent_level) +{ + if (!bc->callback) + fprintf(f, "%*s_Empty_\n", indent_level, ""); + else + bc->callback->print(bc->contents, f, indent_level); + fprintf(f, "%*sMultiple=", indent_level, ""); + if (!bc->multiple) + fprintf(f, "nil (1)"); + else + yasm_expr_print(bc->multiple, f); + fprintf(f, "\n%*sLength=%lu\n", indent_level, "", bc->len); + fprintf(f, "%*sLine Index=%lu\n", indent_level, "", bc->line); + fprintf(f, "%*sOffset=%lx\n", indent_level, "", bc->offset); +} + +void +yasm_bc_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc) +{ + if (bc->callback) + bc->callback->finalize(bc, prev_bc); + if (bc->multiple) { + yasm_value val; + + if (yasm_value_finalize_expr(&val, bc->multiple, prev_bc, 0)) + yasm_error_set(YASM_ERROR_TOO_COMPLEX, + N_("multiple expression too complex")); + else if (val.rel) + yasm_error_set(YASM_ERROR_NOT_ABSOLUTE, + N_("multiple expression not absolute")); + /* Finalize creates NULL output if value=0, but bc->multiple is NULL + * if value=1 (this difference is to make the common case small). + * However, this means we need to set bc->multiple explicitly to 0 + * here if val.abs is NULL. + */ + if (val.abs) + bc->multiple = val.abs; + else + bc->multiple = yasm_expr_create_ident( + yasm_expr_int(yasm_intnum_create_uint(0)), bc->line); + } +} + +/*@null@*/ yasm_intnum * +yasm_calc_bc_dist(yasm_bytecode *precbc1, yasm_bytecode *precbc2) +{ + unsigned long dist2, dist1; + yasm_intnum *intn; + + if (precbc1->section != precbc2->section) + return NULL; + + dist1 = yasm_bc_next_offset(precbc1); + dist2 = yasm_bc_next_offset(precbc2); + if (dist2 < dist1) { + intn = yasm_intnum_create_uint(dist1 - dist2); + yasm_intnum_calc(intn, YASM_EXPR_NEG, NULL); + return intn; + } + dist2 -= dist1; + return yasm_intnum_create_uint(dist2); +} + +unsigned long +yasm_bc_next_offset(yasm_bytecode *precbc) +{ + return precbc->offset + precbc->len*precbc->mult_int; +} + +int +yasm_bc_elem_size(yasm_bytecode *bc) +{ + if (!bc->callback) { + yasm_internal_error(N_("got empty bytecode in yasm_bc_elem_size")); + return 0; + } else if (!bc->callback->elem_size) + return 0; + else + return bc->callback->elem_size(bc); +} + +int +yasm_bc_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span, + void *add_span_data) +{ + int retval = 0; + + bc->len = 0; + + if (!bc->callback) + yasm_internal_error(N_("got empty bytecode in yasm_bc_calc_len")); + else + retval = bc->callback->calc_len(bc, add_span, add_span_data); + + /* Check for multiples */ + bc->mult_int = 1; + if (bc->multiple) { + /*@dependent@*/ /*@null@*/ const yasm_intnum *num; + + num = yasm_expr_get_intnum(&bc->multiple, 0); + if (num) { + if (yasm_intnum_sign(num) < 0) { + yasm_error_set(YASM_ERROR_VALUE, N_("multiple is negative")); + retval = -1; + } else + bc->mult_int = yasm_intnum_get_int(num); + } else { + if (yasm_expr__contains(bc->multiple, YASM_EXPR_FLOAT)) { + yasm_error_set(YASM_ERROR_VALUE, + N_("expression must not contain floating point value")); + retval = -1; + } else { + yasm_value value; + yasm_value_initialize(&value, bc->multiple, 0); + add_span(add_span_data, bc, 0, &value, 0, 0); + bc->mult_int = 0; /* assume 0 to start */ + } + } + } + + /* If we got an error somewhere along the line, clear out any calc len */ + if (retval < 0) + bc->len = 0; + + return retval; +} + +int +yasm_bc_expand(yasm_bytecode *bc, int span, long old_val, long new_val, + /*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres) +{ + if (span == 0) { + bc->mult_int = new_val; + return 1; + } + if (!bc->callback) { + yasm_internal_error(N_("got empty bytecode in yasm_bc_expand")); + /*@unreached@*/ + return -1; + } else + return bc->callback->expand(bc, span, old_val, new_val, neg_thres, + pos_thres); +} + +/*@null@*/ /*@only@*/ unsigned char * +yasm_bc_tobytes(yasm_bytecode *bc, unsigned char *buf, unsigned long *bufsize, + /*@out@*/ int *gap, void *d, + yasm_output_value_func output_value, + /*@null@*/ yasm_output_reloc_func output_reloc) + /*@sets *buf@*/ +{ + /*@only@*/ /*@null@*/ unsigned char *mybuf = NULL; + unsigned char *bufstart; + unsigned char *origbuf, *destbuf; + long i; + int error = 0; + + long mult; + if (yasm_bc_get_multiple(bc, &mult, 1) || mult == 0) { + *bufsize = 0; + return NULL; + } + bc->mult_int = mult; + + /* special case for reserve bytecodes */ + if (bc->callback->special == YASM_BC_SPECIAL_RESERVE) { + *bufsize = bc->len*bc->mult_int; + *gap = 1; + return NULL; /* we didn't allocate a buffer */ + } + *gap = 0; + + if (*bufsize < bc->len*bc->mult_int) { + mybuf = yasm_xmalloc(bc->len*bc->mult_int); + destbuf = mybuf; + } else + destbuf = buf; + bufstart = destbuf; + + *bufsize = bc->len*bc->mult_int; + + if (!bc->callback) + yasm_internal_error(N_("got empty bytecode in bc_tobytes")); + else for (i=0; i<bc->mult_int; i++) { + origbuf = destbuf; + error = bc->callback->tobytes(bc, &destbuf, bufstart, d, output_value, + output_reloc); + + if (!error && ((unsigned long)(destbuf - origbuf) != bc->len)) + yasm_internal_error( + N_("written length does not match optimized length")); + } + + return mybuf; +} + +int +yasm_bc_get_multiple(yasm_bytecode *bc, long *multiple, int calc_bc_dist) +{ + /*@dependent@*/ /*@null@*/ const yasm_intnum *num; + + *multiple = 1; + if (bc->multiple) { + num = yasm_expr_get_intnum(&bc->multiple, calc_bc_dist); + if (!num) { + yasm_error_set(YASM_ERROR_VALUE, + N_("could not determine multiple")); + return 1; + } + if (yasm_intnum_sign(num) < 0) { + yasm_error_set(YASM_ERROR_VALUE, N_("multiple is negative")); + return 1; + } + *multiple = yasm_intnum_get_int(num); + } + return 0; +} + +const yasm_expr * +yasm_bc_get_multiple_expr(const yasm_bytecode *bc) +{ + return bc->multiple; +} + +yasm_insn * +yasm_bc_get_insn(yasm_bytecode *bc) +{ + if (bc->callback->special != YASM_BC_SPECIAL_INSN) + return NULL; + return (yasm_insn *)bc->contents; +} diff --git a/contrib/tools/yasm/libyasm/bytecode.h b/contrib/tools/yasm/libyasm/bytecode.h new file mode 100644 index 0000000000..47cd26244b --- /dev/null +++ b/contrib/tools/yasm/libyasm/bytecode.h @@ -0,0 +1,638 @@ +/** + * \file libyasm/bytecode.h + * \brief YASM bytecode interface. + * + * \license + * 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: + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - 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. + * \endlicense + */ +#ifndef YASM_BYTECODE_H +#define YASM_BYTECODE_H + +#ifndef YASM_LIB_DECL +#define YASM_LIB_DECL +#endif + +/** A data value (opaque type). */ +typedef struct yasm_dataval yasm_dataval; +/** A list of data values. */ +typedef struct yasm_datavalhead yasm_datavalhead; + +/** Linked list of data values. */ +/*@reldef@*/ STAILQ_HEAD(yasm_datavalhead, yasm_dataval); + +/** Add a dependent span for a bytecode. + * \param add_span_data add_span_data passed into bc_calc_len() + * \param bc bytecode containing span + * \param id non-zero identifier for span; may be any non-zero value + * if <0, expand is called for any change; + * if >0, expand is only called when exceeds threshold + * \param value dependent value for bytecode expansion + * \param neg_thres negative threshold for long/short decision + * \param pos_thres positive threshold for long/short decision + */ +typedef void (*yasm_bc_add_span_func) + (void *add_span_data, yasm_bytecode *bc, int id, const yasm_value *value, + long neg_thres, long pos_thres); + +/** Bytecode callback structure. Any implementation of a specific bytecode + * must implement these functions and this callback structure. The bytecode + * implementation-specific data is stored in #yasm_bytecode.contents. + */ +typedef struct yasm_bytecode_callback { + /** Destroys the implementation-specific data. + * Called from yasm_bc_destroy(). + * \param contents #yasm_bytecode.contents + */ + void (*destroy) (/*@only@*/ void *contents); + + /** Prints the implementation-specific data (for debugging purposes). + * Called from yasm_bc_print(). + * \param contents #yasm_bytecode.contents + * \param f file + * \param indent_level indentation level + */ + void (*print) (const void *contents, FILE *f, int indent_level); + + /** Finalizes the bytecode after parsing. Called from yasm_bc_finalize(). + * A generic fill-in for this is yasm_bc_finalize_common(). + * \param bc bytecode + * \param prev_bc bytecode directly preceding bc + */ + void (*finalize) (yasm_bytecode *bc, yasm_bytecode *prev_bc); + + /** Return elements size of a data bytecode. + * This function should return the size of each elements of a data + * bytecode, for proper dereference of symbols attached to it. + * \param bc bytecode + * \return 0 if element size is unknown. + */ + int (*elem_size) (yasm_bytecode *bc); + + /** Calculates the minimum size of a bytecode. + * Called from yasm_bc_calc_len(). + * A generic fill-in for this is yasm_bc_calc_len_common(), but as this + * function internal errors when called, be very careful when using it! + * This function should simply add to bc->len and not set it directly + * (it's initialized by yasm_bc_calc_len() prior to passing control to + * this function). + * + * \param bc bytecode + * \param add_span function to call to add a span + * \param add_span_data extra data to be passed to add_span function + * \return 0 if no error occurred, nonzero if there was an error + * recognized (and output) during execution. + * \note May store to bytecode updated expressions. + */ + int (*calc_len) (yasm_bytecode *bc, yasm_bc_add_span_func add_span, + void *add_span_data); + + /** Recalculates the bytecode's length based on an expanded span length. + * Called from yasm_bc_expand(). + * A generic fill-in for this is yasm_bc_expand_common(), but as this + * function internal errors when called, if used, ensure that calc_len() + * never adds a span. + * This function should simply add to bc->len to increase the length by + * a delta amount. + * \param bc bytecode + * \param span span ID (as given to add_span in calc_len) + * \param old_val previous span value + * \param new_val new span value + * \param neg_thres negative threshold for long/short decision + * (returned) + * \param pos_thres positive threshold for long/short decision + * (returned) + * \return 0 if bc no longer dependent on this span's length, negative if + * there was an error recognized (and output) during execution, + * and positive if bc size may increase for this span further + * based on the new negative and positive thresholds returned. + * \note May store to bytecode updated expressions. + */ + int (*expand) (yasm_bytecode *bc, int span, long old_val, long new_val, + /*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres); + + /** Convert a bytecode into its byte representation. + * Called from yasm_bc_tobytes(). + * A generic fill-in for this is yasm_bc_tobytes_common(), but as this + * function internal errors when called, be very careful when using it! + * \param bc bytecode + * \param bufp byte representation destination buffer; + * should be incremented as it's written to, + * so that on return its delta from the + * passed-in buf matches the bytecode length + * (it's okay not to do this if an error + * indication is returned) + * \param bufstart For calculating the correct offset parameter for + * the \a output_value calls: *bufp - bufstart. + * \param d data to pass to each call to + * output_value/output_reloc + * \param output_value function to call to convert values into their byte + * representation + * \param output_reloc function to call to output relocation entries + * for a single sym + * \return Nonzero on error, 0 on success. + * \note May result in non-reversible changes to the bytecode, but it's + * preferable if calling this function twice would result in the + * same output. + */ + int (*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); + + /** Special bytecode classifications. Most bytecode types should use + * #YASM_BC_SPECIAL_NONE. Others cause special handling to kick in + * in various parts of yasm. + */ + enum yasm_bytecode_special_type { + YASM_BC_SPECIAL_NONE = 0, + + /** Bytecode reserves space instead of outputting data. */ + YASM_BC_SPECIAL_RESERVE, + + /** Adjusts offset instead of calculating len. */ + YASM_BC_SPECIAL_OFFSET, + + /** Instruction bytecode. */ + YASM_BC_SPECIAL_INSN + } special; +} yasm_bytecode_callback; + +/** A bytecode. */ +struct yasm_bytecode { + /** Bytecodes are stored as a singly linked list, with tail insertion. + * \see section.h (#yasm_section). + */ + /*@reldef@*/ STAILQ_ENTRY(yasm_bytecode) link; + + /** The bytecode callback structure for this bytecode. May be NULL + * during partial initialization. + */ + /*@null@*/ const yasm_bytecode_callback *callback; + + /** Pointer to section containing bytecode; NULL if not part of a + * section. + */ + /*@dependent@*/ /*@null@*/ yasm_section *section; + + /** Number of times bytecode is repeated. + * NULL=1 (to save space in the common case). + */ + /*@only@*/ /*@null@*/ yasm_expr *multiple; + + /** Total length of entire bytecode (not including multiple copies). */ + unsigned long len; + + /** Number of copies, integer version. */ + long mult_int; + + /** Line number where bytecode was defined. */ + unsigned long line; + + /** Offset of bytecode from beginning of its section. + * 0-based, ~0UL (e.g. all 1 bits) if unknown. + */ + unsigned long offset; + + /** Unique integer index of bytecode. Used during optimization. */ + unsigned long bc_index; + + /** NULL-terminated array of labels that point to this bytecode (as the + * bytecode previous to the label). NULL if no labels point here. + */ + /*@null@*/ yasm_symrec **symrecs; + + /** Implementation-specific data (type identified by callback). */ + void *contents; +}; + +/** Create a bytecode of any specified type. + * \param callback bytecode callback functions, if NULL, creates empty + * bytecode (may not be resolved or output) + * \param contents type-specific data + * \param line virtual line (from yasm_linemap) + * \return Newly allocated bytecode of the specified type. + */ +YASM_LIB_DECL +/*@only@*/ yasm_bytecode *yasm_bc_create_common + (/*@null@*/ const yasm_bytecode_callback *callback, + /*@only@*/ /*@null@*/ void *contents, unsigned long line); + +/** Transform a bytecode of any type into a different type. + * \param bc bytecode to transform + * \param callback new bytecode callback function + * \param contents new type-specific data + */ +YASM_LIB_DECL +void yasm_bc_transform(yasm_bytecode *bc, + const yasm_bytecode_callback *callback, + void *contents); + +/** Common bytecode callback finalize function, for where no finalization + * is ever required for this type of bytecode. + */ +YASM_LIB_DECL +void yasm_bc_finalize_common(yasm_bytecode *bc, yasm_bytecode *prev_bc); + +/** Common bytecode callback calc_len function, for where the bytecode has + * no calculatable length. Causes an internal error if called. + */ +YASM_LIB_DECL +int yasm_bc_calc_len_common(yasm_bytecode *bc, yasm_bc_add_span_func add_span, + void *add_span_data); + +/** Common bytecode callback expand function, for where the bytecode is + * always short (calc_len never calls add_span). Causes an internal + * error if called. + */ +YASM_LIB_DECL +int yasm_bc_expand_common + (yasm_bytecode *bc, int span, long old_val, long new_val, + /*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres); + +/** Common bytecode callback tobytes function, for where the bytecode + * cannot be converted to bytes. Causes an internal error if called. + */ +YASM_LIB_DECL +int yasm_bc_tobytes_common + (yasm_bytecode *bc, unsigned char **bufp, unsigned char *bufstart, void *d, + yasm_output_value_func output_value, + /*@null@*/ yasm_output_reloc_func output_reloc); + +/** Get the next bytecode in a linked list of bytecodes. + * \param bc bytecode + * \return Next bytecode. + */ +#define yasm_bc__next(bc) STAILQ_NEXT(bc, link) + +/** Set multiple field of a bytecode. + * A bytecode can be repeated a number of times when output. This function + * sets that multiple. + * \param bc bytecode + * \param e multiple (kept, do not free) + */ +YASM_LIB_DECL +void yasm_bc_set_multiple(yasm_bytecode *bc, /*@keep@*/ yasm_expr *e); + +/** Create a bytecode containing data value(s). + * \param datahead list of data values (kept, do not free) + * \param size storage size (in bytes) for each data value + * \param append_zero append a single zero byte after each data value + * (if non-zero) + * \param arch architecture (optional); if provided, data items + * are directly simplified to bytes if possible + * \param line virtual line (from yasm_linemap) + * \return Newly allocated bytecode. + */ +YASM_LIB_DECL +/*@only@*/ yasm_bytecode *yasm_bc_create_data + (yasm_datavalhead *datahead, unsigned int size, int append_zero, + /*@null@*/ yasm_arch *arch, unsigned long line); + +/** Create a bytecode containing LEB128-encoded data value(s). + * \param datahead list of data values (kept, do not free) + * \param sign signedness (1=signed, 0=unsigned) of each data value + * \param line virtual line (from yasm_linemap) + * \return Newly allocated bytecode. + */ +YASM_LIB_DECL +/*@only@*/ yasm_bytecode *yasm_bc_create_leb128 + (yasm_datavalhead *datahead, int sign, unsigned long line); + +/** Create a bytecode reserving space. + * \param numitems number of reserve "items" (kept, do not free) + * \param itemsize reserved size (in bytes) for each item + * \param line virtual line (from yasm_linemap) + * \return Newly allocated bytecode. + */ +YASM_LIB_DECL +/*@only@*/ yasm_bytecode *yasm_bc_create_reserve + (/*@only@*/ yasm_expr *numitems, unsigned int itemsize, + unsigned long line); + +/** Get the number of items and itemsize for a reserve bytecode. If bc + * is not a reserve bytecode, returns NULL. + * \param bc bytecode + * \param itemsize reserved size (in bytes) for each item (returned) + * \return NULL if bc is not a reserve bytecode, otherwise an expression + * for the number of items to reserve. + */ +YASM_LIB_DECL +/*@null@*/ const yasm_expr *yasm_bc_reserve_numitems + (yasm_bytecode *bc, /*@out@*/ unsigned int *itemsize); + +/** Create a bytecode that includes a binary file verbatim. + * \param filename path to binary file (kept, do not free) + * \param start starting location in file (in bytes) to read data from + * (kept, do not free); may be NULL to indicate 0 + * \param maxlen maximum number of bytes to read from the file (kept, do + * do not free); may be NULL to indicate no maximum + * \param linemap line mapping repository + * \param line virtual line (from yasm_linemap) for the bytecode + * \return Newly allocated bytecode. + */ +YASM_LIB_DECL +/*@only@*/ yasm_bytecode *yasm_bc_create_incbin + (/*@only@*/ char *filename, /*@only@*/ /*@null@*/ yasm_expr *start, + /*@only@*/ /*@null@*/ yasm_expr *maxlen, yasm_linemap *linemap, + unsigned long line); + +/** Create a bytecode that aligns the following bytecode to a boundary. + * \param boundary byte alignment (must be a power of two) + * \param fill fill data (if NULL, code_fill or 0 is used) + * \param maxskip maximum number of bytes to skip + * \param code_fill code fill data (if NULL, 0 is used) + * \param line virtual line (from yasm_linemap) + * \return Newly allocated bytecode. + * \note The precedence on generated fill is as follows: + * - from fill parameter (if not NULL) + * - from code_fill parameter (if not NULL) + * - 0 + */ +YASM_LIB_DECL +/*@only@*/ yasm_bytecode *yasm_bc_create_align + (/*@keep@*/ yasm_expr *boundary, /*@keep@*/ /*@null@*/ yasm_expr *fill, + /*@keep@*/ /*@null@*/ yasm_expr *maxskip, + /*@null@*/ const unsigned char **code_fill, unsigned long line); + +/** Create a bytecode that puts the following bytecode at a fixed section + * offset. + * \param start section offset of following bytecode + * \param fill fill value + * \param line virtual line (from yasm_linemap) + * \return Newly allocated bytecode. + */ +YASM_LIB_DECL +/*@only@*/ yasm_bytecode *yasm_bc_create_org + (unsigned long start, unsigned long fill, unsigned long line); + +/** Get the section that contains a particular bytecode. + * \param bc bytecode + * \return Section containing bc (can be NULL if bytecode is not part of a + * section). + */ +YASM_LIB_DECL +/*@dependent@*/ /*@null@*/ yasm_section *yasm_bc_get_section + (yasm_bytecode *bc); + +/** Add to the list of symrecs that reference a bytecode. For symrec use + * only. + * \param bc bytecode + * \param sym symbol + */ +YASM_LIB_DECL +void yasm_bc__add_symrec(yasm_bytecode *bc, /*@dependent@*/ yasm_symrec *sym); + +/** Delete (free allocated memory for) a bytecode. + * \param bc bytecode (only pointer to it); may be NULL + */ +YASM_LIB_DECL +void yasm_bc_destroy(/*@only@*/ /*@null@*/ yasm_bytecode *bc); + +/** Print a bytecode. For debugging purposes. + * \param f file + * \param indent_level indentation level + * \param bc bytecode + */ +YASM_LIB_DECL +void yasm_bc_print(const yasm_bytecode *bc, FILE *f, int indent_level); + +/** Finalize a bytecode after parsing. + * \param bc bytecode + * \param prev_bc bytecode directly preceding bc in a list of bytecodes + */ +YASM_LIB_DECL +void yasm_bc_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc); + +/** Determine the distance between the starting offsets of two bytecodes. + * \param precbc1 preceding bytecode to the first bytecode + * \param precbc2 preceding bytecode to the second bytecode + * \return Distance in bytes between the two bytecodes (bc2-bc1), or NULL if + * the distance was indeterminate. + * \warning Only valid /after/ optimization. + */ +YASM_LIB_DECL +/*@null@*/ /*@only@*/ yasm_intnum *yasm_calc_bc_dist + (yasm_bytecode *precbc1, yasm_bytecode *precbc2); + +/** Get the offset of the next bytecode (the next bytecode doesn't have to + * actually exist). + * \param precbc preceding bytecode + * \return Offset of the next bytecode in bytes. + * \warning Only valid /after/ optimization. + */ +YASM_LIB_DECL +unsigned long yasm_bc_next_offset(yasm_bytecode *precbc); + +/** Return elemens size of a data bytecode. + * Returns the size of each elements of a data bytecode, for proper dereference + * of symbols attached to it. + * \param bc bytecode + * \return 0 if element size is unknown + */ +YASM_LIB_DECL +int yasm_bc_elem_size(yasm_bytecode *bc); + +/** Resolve EQUs in a bytecode and calculate its minimum size. + * Generates dependent bytecode spans for cases where, if the length spanned + * increases, it could cause the bytecode size to increase. + * Any bytecode multiple is NOT included in the length or spans generation; + * this must be handled at a higher level. + * \param bc bytecode + * \param add_span function to call to add a span + * \param add_span_data extra data to be passed to add_span function + * \return 0 if no error occurred, nonzero if there was an error recognized + * (and output) during execution. + * \note May store to bytecode updated expressions and the short length. + */ +YASM_LIB_DECL +int yasm_bc_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span, + void *add_span_data); + +/** Recalculate a bytecode's length based on an expanded span length. + * \param bc bytecode + * \param span span ID (as given to yasm_bc_add_span_func in + * yasm_bc_calc_len) + * \param old_val previous span value + * \param new_val new span value + * \param neg_thres negative threshold for long/short decision (returned) + * \param pos_thres positive threshold for long/short decision (returned) + * \return 0 if bc no longer dependent on this span's length, negative if + * there was an error recognized (and output) during execution, and + * positive if bc size may increase for this span further based on the + * new negative and positive thresholds returned. + * \note May store to bytecode updated expressions and the updated length. + */ +YASM_LIB_DECL +int yasm_bc_expand(yasm_bytecode *bc, int span, long old_val, long new_val, + /*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres); + +/** Convert a bytecode into its byte representation. + * \param bc bytecode + * \param buf byte representation destination buffer + * \param bufsize size of buf (in bytes) prior to call; size of the + * generated data after call + * \param gap if nonzero, indicates the data does not really need to + * exist in the object file; if nonzero, contents of buf + * are undefined [output] + * \param d data to pass to each call to output_value/output_reloc + * \param output_value function to call to convert values into their byte + * representation + * \param output_reloc function to call to output relocation entries + * for a single sym + * \return Newly allocated buffer that should be used instead of buf for + * reading the byte representation, or NULL if buf was big enough to + * hold the entire byte representation. + * \note Calling twice on the same bytecode may \em not produce the same + * results on the second call, as calling this function may result in + * non-reversible changes to the bytecode. + */ +YASM_LIB_DECL +/*@null@*/ /*@only@*/ unsigned char *yasm_bc_tobytes + (yasm_bytecode *bc, unsigned char *buf, unsigned long *bufsize, + /*@out@*/ int *gap, void *d, yasm_output_value_func output_value, + /*@null@*/ yasm_output_reloc_func output_reloc) + /*@sets *buf@*/; + +/** Get the bytecode multiple value as an integer. + * \param bc bytecode + * \param multiple multiple value (output) + * \param calc_bc_dist nonzero if distances between bytecodes should be + * calculated, 0 if error should be returned in this case + * \return 1 on error (set with yasm_error_set), 0 on success. + */ +YASM_LIB_DECL +int yasm_bc_get_multiple(yasm_bytecode *bc, /*@out@*/ long *multiple, + int calc_bc_dist); + +/** Get the bytecode multiple value as an expression. + * \param bc bytecode + * \return Bytecode multiple, NULL if =1. + */ +YASM_LIB_DECL +const yasm_expr *yasm_bc_get_multiple_expr(const yasm_bytecode *bc); + +/** Get a #yasm_insn structure from an instruction bytecode (if possible). + * \param bc bytecode + * \return Instruction details if bytecode is an instruction bytecode, + * otherwise NULL. + */ +YASM_LIB_DECL +/*@dependent@*/ /*@null@*/ yasm_insn *yasm_bc_get_insn(yasm_bytecode *bc); + +/** Create a new data value from an expression. + * \param expn expression + * \return Newly allocated data value. + */ +YASM_LIB_DECL +yasm_dataval *yasm_dv_create_expr(/*@keep@*/ yasm_expr *expn); + +/** Create a new data value from a string. + * \param contents string (may contain NULs) + * \param len length of string + * \return Newly allocated data value. + */ +YASM_LIB_DECL +yasm_dataval *yasm_dv_create_string(/*@keep@*/ char *contents, size_t len); + +/** Create a new data value from raw bytes data. + * \param contents raw data (may contain NULs) + * \param len length + * \return Newly allocated data value. + */ +YASM_LIB_DECL +yasm_dataval *yasm_dv_create_raw(/*@keep@*/ unsigned char *contents, + unsigned long len); + +/** Create a new uninitialized data value. + * \return Newly allocated data value. + */ +YASM_LIB_DECL +yasm_dataval *yasm_dv_create_reserve(void); + +#ifndef YASM_DOXYGEN +#define yasm_dv_create_string(s, l) yasm_dv_create_raw((unsigned char *)(s), \ + (unsigned long)(l)) +#endif + +/** Get the underlying value of a data value. + * \param dv data value + * \return Value, or null if non-value (e.g. string or raw). + */ +YASM_LIB_DECL +yasm_value *yasm_dv_get_value(yasm_dataval *dv); + +/** Set multiple field of a data value. + * A data value can be repeated a number of times when output. This function + * sets that multiple. + * \param dv data value + * \param e multiple (kept, do not free) + */ +YASM_LIB_DECL +void yasm_dv_set_multiple(yasm_dataval *dv, /*@keep@*/ yasm_expr *e); + +/** Get the data value multiple value as an unsigned long integer. + * \param dv data value + * \param multiple multiple value (output) + * \return 1 on error (set with yasm_error_set), 0 on success. + */ +YASM_LIB_DECL +int yasm_dv_get_multiple(yasm_dataval *dv, /*@out@*/ unsigned long *multiple); + +/** Initialize a list of data values. + * \param headp list of data values + */ +void yasm_dvs_initialize(yasm_datavalhead *headp); +#ifndef YASM_DOXYGEN +#define yasm_dvs_initialize(headp) STAILQ_INIT(headp) +#endif + +/** Delete (free allocated memory for) a list of data values. + * \param headp list of data values + */ +YASM_LIB_DECL +void yasm_dvs_delete(yasm_datavalhead *headp); + +/** Add data value to the end of a list of data values. + * \note Does not make a copy of the data value; so don't pass this function + * static or local variables, and discard the dv pointer after calling + * this function. + * \param headp data value list + * \param dv data value (may be NULL) + * \return If data value was actually appended (it wasn't NULL), the data + * value; otherwise NULL. + */ +YASM_LIB_DECL +/*@null@*/ yasm_dataval *yasm_dvs_append + (yasm_datavalhead *headp, /*@returned@*/ /*@null@*/ yasm_dataval *dv); + +/** Print a data value list. For debugging purposes. + * \param f file + * \param indent_level indentation level + * \param headp data value list + */ +YASM_LIB_DECL +void yasm_dvs_print(const yasm_datavalhead *headp, FILE *f, int indent_level); + +#endif diff --git a/contrib/tools/yasm/libyasm/cmake-module.c b/contrib/tools/yasm/libyasm/cmake-module.c new file mode 100644 index 0000000000..2ee39ca88f --- /dev/null +++ b/contrib/tools/yasm/libyasm/cmake-module.c @@ -0,0 +1,126 @@ +/* + * YASM module loader + * + * Copyright (C) 2004-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> + + +typedef struct loaded_module { + const char *keyword; /* module keyword */ + void *data; /* associated data */ +} loaded_module; + +static HAMT *loaded_modules[] = {NULL, NULL, NULL, NULL, NULL, NULL}; + +static void +load_module_destroy(/*@only@*/ void *data) +{ + /* do nothing */ +} + +void * +yasm_load_module(yasm_module_type type, const char *keyword) +{ + if (!loaded_modules[type]) + return NULL; + return HAMT_search(loaded_modules[type], keyword); +} + +void +yasm_register_module(yasm_module_type type, const char *keyword, void *data) +{ + int replace = 1; + + assert(type < sizeof(loaded_modules)); + + if (!loaded_modules[type]) + loaded_modules[type] = HAMT_create(0, yasm_internal_error_); + + HAMT_insert(loaded_modules[type], keyword, data, &replace, + load_module_destroy); +} + +typedef struct { + yasm_module_type type; + void (*printfunc) (const char *name, const char *keyword); +} list_one_data; + +static int +yasm_list_one_module(void *node, void *d) +{ + list_one_data *data = (list_one_data *)d; + yasm_arch_module *arch; + yasm_dbgfmt_module *dbgfmt; + yasm_objfmt_module *objfmt; + yasm_listfmt_module *listfmt; + yasm_parser_module *parser; + yasm_preproc_module *preproc; + + switch (data->type) { + case YASM_MODULE_ARCH: + arch = node; + data->printfunc(arch->name, arch->keyword); + break; + case YASM_MODULE_DBGFMT: + dbgfmt = node; + data->printfunc(dbgfmt->name, dbgfmt->keyword); + break; + case YASM_MODULE_OBJFMT: + objfmt = node; + data->printfunc(objfmt->name, objfmt->keyword); + break; + case YASM_MODULE_LISTFMT: + listfmt = node; + data->printfunc(listfmt->name, listfmt->keyword); + break; + case YASM_MODULE_PARSER: + parser = node; + data->printfunc(parser->name, parser->keyword); + break; + case YASM_MODULE_PREPROC: + preproc = node; + data->printfunc(preproc->name, preproc->keyword); + break; + } + return 0; +} + +void +yasm_list_modules(yasm_module_type type, + void (*printfunc) (const char *name, const char *keyword)) +{ + list_one_data data; + + /* Go through available list, and try to load each one */ + if (!loaded_modules[type]) + return; + + data.type = type; + data.printfunc = printfunc; + + HAMT_traverse(loaded_modules[type], &data, yasm_list_one_module); +} diff --git a/contrib/tools/yasm/libyasm/compat-queue.h b/contrib/tools/yasm/libyasm/compat-queue.h new file mode 100644 index 0000000000..da9eff4694 --- /dev/null +++ b/contrib/tools/yasm/libyasm/compat-queue.h @@ -0,0 +1,456 @@ +/* + * <sys/queue.h> implementation for systems that don't have it. + * + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * 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. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND 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 REGENTS OR 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. + * + * @(#)queue.h 8.5 (Berkeley) 8/20/94 + * $FreeBSD: src/sys/sys/queue.h,v 1.32.2.4 2001/03/31 03:33:39 hsu Exp $ + */ + +#ifndef SYS_QUEUE_H +#define SYS_QUEUE_H + +/* + * This file defines four types of data structures: singly-linked lists, + * singly-linked tail queues, lists and tail queues. + * + * A singly-linked list is headed by a single forward pointer. The elements + * are singly linked for minimum space and pointer manipulation overhead at + * the expense of O(n) removal for arbitrary elements. New elements can be + * added to the list after an existing element or at the head of the list. + * Elements being removed from the head of the list should use the explicit + * macro for this purpose for optimum efficiency. A singly-linked list may + * only be traversed in the forward direction. Singly-linked lists are ideal + * for applications with large datasets and few or no removals or for + * implementing a LIFO queue. + * + * A singly-linked tail queue is headed by a pair of pointers, one to the + * head of the list and the other to the tail of the list. The elements are + * singly linked for minimum space and pointer manipulation overhead at the + * expense of O(n) removal for arbitrary elements. New elements can be added + * to the list after an existing element, at the head of the list, or at the + * end of the list. Elements being removed from the head of the tail queue + * should use the explicit macro for this purpose for optimum efficiency. + * A singly-linked tail queue may only be traversed in the forward direction. + * Singly-linked tail queues are ideal for applications with large datasets + * and few or no removals or for implementing a FIFO queue. + * + * A list is headed by a single forward pointer (or an array of forward + * pointers for a hash table header). The elements are doubly linked + * so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before + * or after an existing element or at the head of the list. A list + * may only be traversed in the forward direction. + * + * A tail queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or + * after an existing element, at the head of the list, or at the end of + * the list. A tail queue may be traversed in either direction. + * + * For details on the use of these macros, see the queue(3) manual page. + * + * + * SLIST LIST STAILQ TAILQ + * _HEAD + + + + + * _HEAD_INITIALIZER + + + + + * _ENTRY + + + + + * _INIT + + + + + * _EMPTY + + + + + * _FIRST + + + + + * _NEXT + + + + + * _PREV - - - + + * _LAST - - + + + * _FOREACH + + + + + * _FOREACH_SAFE + + + + + * _FOREACH_REVERSE - - - + + * _FOREACH_REVERSE_SAFE - - - + + * _INSERT_HEAD + + + + + * _INSERT_BEFORE - + - + + * _INSERT_AFTER + + + + + * _INSERT_TAIL - - + + + * _CONCAT - - + + + * _REMOVE_HEAD + - + - + * _REMOVE + + + + + * + */ + +/* + * Singly-linked List declarations. + */ +#define SLIST_HEAD(name, type) \ +struct name { \ + struct type *slh_first; /* first element */ \ +} + +#define SLIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define SLIST_ENTRY(type) \ +struct { \ + struct type *sle_next; /* next element */ \ +} + +/* + * Singly-linked List functions. + */ +#define SLIST_EMPTY(head) ((head)->slh_first == NULL) + +#define SLIST_FIRST(head) ((head)->slh_first) + +#define SLIST_FOREACH(var, head, field) \ + for ((var) = SLIST_FIRST((head)); \ + (var); \ + (var) = SLIST_NEXT((var), field)) + +#define SLIST_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = SLIST_FIRST((head)); \ + (var) && ((tvar) = SLIST_NEXT((var), field), 1); \ + (var) = (tvar)) + +#define SLIST_FOREACH_PREVPTR(var, varp, head, field) \ + for ((varp) = &SLIST_FIRST((head)); \ + ((var) = *(varp)) != NULL; \ + (varp) = &SLIST_NEXT((var), field)) + +#define SLIST_INIT(head) do { \ + SLIST_FIRST((head)) = NULL; \ +} while (0) + +#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ + SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field); \ + SLIST_NEXT((slistelm), field) = (elm); \ +} while (0) + +#define SLIST_INSERT_HEAD(head, elm, field) do { \ + SLIST_NEXT((elm), field) = SLIST_FIRST((head)); \ + SLIST_FIRST((head)) = (elm); \ +} while (0) + +#define SLIST_NEXT(elm, field) ((elm)->field.sle_next) + +#define SLIST_REMOVE(head, elm, type, field) do { \ + if (SLIST_FIRST((head)) == (elm)) { \ + SLIST_REMOVE_HEAD((head), field); \ + } \ + else { \ + struct type *curelm = SLIST_FIRST((head)); \ + while (SLIST_NEXT(curelm, field) != (elm)) \ + curelm = SLIST_NEXT(curelm, field); \ + SLIST_NEXT(curelm, field) = \ + SLIST_NEXT(SLIST_NEXT(curelm, field), field); \ + } \ +} while (0) + +#define SLIST_REMOVE_HEAD(head, field) do { \ + SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field); \ +} while (0) + +/* + * Singly-linked Tail queue declarations. + */ +#define STAILQ_HEAD(name, type) \ +struct name { \ + struct type *stqh_first;/* first element */ \ + struct type **stqh_last;/* addr of last next element */ \ +} + +#define STAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).stqh_first } + +#define STAILQ_ENTRY(type) \ +struct { \ + struct type *stqe_next; /* next element */ \ +} + +/* + * Singly-linked Tail queue functions. + */ +#define STAILQ_CONCAT(head1, head2) do { \ + if (!STAILQ_EMPTY((head2))) { \ + *(head1)->stqh_last = (head2)->stqh_first; \ + (head1)->stqh_last = (head2)->stqh_last; \ + STAILQ_INIT((head2)); \ + } \ +} while (0) + +#define STAILQ_EMPTY(head) ((head)->stqh_first == NULL) + +#define STAILQ_FIRST(head) ((head)->stqh_first) + +#define STAILQ_FOREACH(var, head, field) \ + for((var) = STAILQ_FIRST((head)); \ + (var); \ + (var) = STAILQ_NEXT((var), field)) + + +#define STAILQ_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = STAILQ_FIRST((head)); \ + (var) && ((tvar) = STAILQ_NEXT((var), field), 1); \ + (var) = (tvar)) + +#define STAILQ_INIT(head) do { \ + STAILQ_FIRST((head)) = NULL; \ + (head)->stqh_last = &STAILQ_FIRST((head)); \ +} while (0) + +#define STAILQ_INSERT_AFTER(head, tqelm, elm, field) do { \ + if ((STAILQ_NEXT((elm), field) = STAILQ_NEXT((tqelm), field)) == NULL)\ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ + STAILQ_NEXT((tqelm), field) = (elm); \ +} while (0) + +#define STAILQ_INSERT_HEAD(head, elm, field) do { \ + if ((STAILQ_NEXT((elm), field) = STAILQ_FIRST((head))) == NULL) \ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ + STAILQ_FIRST((head)) = (elm); \ +} while (0) + +#define STAILQ_INSERT_TAIL(head, elm, field) do { \ + STAILQ_NEXT((elm), field) = NULL; \ + *(head)->stqh_last = (elm); \ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ +} while (0) + +#define STAILQ_LAST(head, type, field) \ + (STAILQ_EMPTY((head)) ? \ + NULL : \ + ((struct type *) \ + ((char *)((head)->stqh_last) - offsetof(struct type, field)))) + +#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next) + +#define STAILQ_REMOVE(head, elm, type, field) do { \ + if (STAILQ_FIRST((head)) == (elm)) { \ + STAILQ_REMOVE_HEAD((head), field); \ + } \ + else { \ + struct type *curelm = STAILQ_FIRST((head)); \ + while (STAILQ_NEXT(curelm, field) != (elm)) \ + curelm = STAILQ_NEXT(curelm, field); \ + if ((STAILQ_NEXT(curelm, field) = \ + STAILQ_NEXT(STAILQ_NEXT(curelm, field), field)) == NULL)\ + (head)->stqh_last = &STAILQ_NEXT((curelm), field);\ + } \ +} while (0) + +#define STAILQ_REMOVE_HEAD(head, field) do { \ + if ((STAILQ_FIRST((head)) = \ + STAILQ_NEXT(STAILQ_FIRST((head)), field)) == NULL) \ + (head)->stqh_last = &STAILQ_FIRST((head)); \ +} while (0) + +#define STAILQ_REMOVE_HEAD_UNTIL(head, elm, field) do { \ + if ((STAILQ_FIRST((head)) = STAILQ_NEXT((elm), field)) == NULL) \ + (head)->stqh_last = &STAILQ_FIRST((head)); \ +} while (0) + +/* + * List declarations. + */ +#define LIST_HEAD(name, type) \ +struct name { \ + struct type *lh_first; /* first element */ \ +} + +#define LIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define LIST_ENTRY(type) \ +struct { \ + struct type *le_next; /* next element */ \ + struct type **le_prev; /* address of previous next element */ \ +} + +/* + * List functions. + */ + +#define LIST_EMPTY(head) ((head)->lh_first == NULL) + +#define LIST_FIRST(head) ((head)->lh_first) + +#define LIST_FOREACH(var, head, field) \ + for ((var) = LIST_FIRST((head)); \ + (var); \ + (var) = LIST_NEXT((var), field)) + +#define LIST_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = LIST_FIRST((head)); \ + (var) && ((tvar) = LIST_NEXT((var), field), 1); \ + (var) = (tvar)) + +#define LIST_INIT(head) do { \ + LIST_FIRST((head)) = NULL; \ +} while (0) + +#define LIST_INSERT_AFTER(listelm, elm, field) do { \ + if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) != NULL)\ + LIST_NEXT((listelm), field)->field.le_prev = \ + &LIST_NEXT((elm), field); \ + LIST_NEXT((listelm), field) = (elm); \ + (elm)->field.le_prev = &LIST_NEXT((listelm), field); \ +} while (0) + +#define LIST_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.le_prev = (listelm)->field.le_prev; \ + LIST_NEXT((elm), field) = (listelm); \ + *(listelm)->field.le_prev = (elm); \ + (listelm)->field.le_prev = &LIST_NEXT((elm), field); \ +} while (0) + +#define LIST_INSERT_HEAD(head, elm, field) do { \ + if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL) \ + LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field);\ + LIST_FIRST((head)) = (elm); \ + (elm)->field.le_prev = &LIST_FIRST((head)); \ +} while (0) + +#define LIST_NEXT(elm, field) ((elm)->field.le_next) + +#define LIST_REMOVE(elm, field) do { \ + if (LIST_NEXT((elm), field) != NULL) \ + LIST_NEXT((elm), field)->field.le_prev = \ + (elm)->field.le_prev; \ + *(elm)->field.le_prev = LIST_NEXT((elm), field); \ +} while (0) + +/* + * Tail queue declarations. + */ +#define TAILQ_HEAD(name, type) \ +struct name { \ + struct type *tqh_first; /* first element */ \ + struct type **tqh_last; /* addr of last next element */ \ +} + +#define TAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).tqh_first } + +#define TAILQ_ENTRY(type) \ +struct { \ + struct type *tqe_next; /* next element */ \ + struct type **tqe_prev; /* address of previous next element */ \ +} + +/* + * Tail queue functions. + */ +#define TAILQ_CONCAT(head1, head2, field) do { \ + if (!TAILQ_EMPTY(head2)) { \ + *(head1)->tqh_last = (head2)->tqh_first; \ + (head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \ + (head1)->tqh_last = (head2)->tqh_last; \ + TAILQ_INIT((head2)); \ + } \ +} while (0) + +#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL) + +#define TAILQ_FIRST(head) ((head)->tqh_first) + +#define TAILQ_FOREACH(var, head, field) \ + for ((var) = TAILQ_FIRST((head)); \ + (var); \ + (var) = TAILQ_NEXT((var), field)) + +#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = TAILQ_FIRST((head)); \ + (var) && ((tvar) = TAILQ_NEXT((var), field), 1); \ + (var) = (tvar)) + +#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ + for ((var) = TAILQ_LAST((head), headname); \ + (var); \ + (var) = TAILQ_PREV((var), headname, field)) + +#define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \ + for ((var) = TAILQ_LAST((head), headname); \ + (var) && ((tvar) = TAILQ_PREV((var), headname, field), 1); \ + (var) = (tvar)) + +#define TAILQ_INIT(head) do { \ + TAILQ_FIRST((head)) = NULL; \ + (head)->tqh_last = &TAILQ_FIRST((head)); \ +} while (0) + +#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) != NULL)\ + TAILQ_NEXT((elm), field)->field.tqe_prev = \ + &TAILQ_NEXT((elm), field); \ + else { \ + (head)->tqh_last = &TAILQ_NEXT((elm), field); \ + } \ + TAILQ_NEXT((listelm), field) = (elm); \ + (elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field); \ +} while (0) + +#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ + TAILQ_NEXT((elm), field) = (listelm); \ + *(listelm)->field.tqe_prev = (elm); \ + (listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field); \ +} while (0) + +#define TAILQ_INSERT_HEAD(head, elm, field) do { \ + if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL) \ + TAILQ_FIRST((head))->field.tqe_prev = \ + &TAILQ_NEXT((elm), field); \ + else \ + (head)->tqh_last = &TAILQ_NEXT((elm), field); \ + TAILQ_FIRST((head)) = (elm); \ + (elm)->field.tqe_prev = &TAILQ_FIRST((head)); \ +} while (0) + +#define TAILQ_INSERT_TAIL(head, elm, field) do { \ + TAILQ_NEXT((elm), field) = NULL; \ + (elm)->field.tqe_prev = (head)->tqh_last; \ + *(head)->tqh_last = (elm); \ + (head)->tqh_last = &TAILQ_NEXT((elm), field); \ +} while (0) + +#define TAILQ_LAST(head, headname) \ + (*(((struct headname *)((head)->tqh_last))->tqh_last)) + +#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) + +#define TAILQ_PREV(elm, headname, field) \ + (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) + +#define TAILQ_REMOVE(head, elm, field) do { \ + if ((TAILQ_NEXT((elm), field)) != NULL) \ + TAILQ_NEXT((elm), field)->field.tqe_prev = \ + (elm)->field.tqe_prev; \ + else { \ + (head)->tqh_last = (elm)->field.tqe_prev; \ + } \ + *(elm)->field.tqe_prev = TAILQ_NEXT((elm), field); \ +} while (0) + +#endif /* !SYS_QUEUE_H */ diff --git a/contrib/tools/yasm/libyasm/coretype.h b/contrib/tools/yasm/libyasm/coretype.h new file mode 100644 index 0000000000..624e3c445c --- /dev/null +++ b/contrib/tools/yasm/libyasm/coretype.h @@ -0,0 +1,393 @@ +/** + * \file libyasm/coretype.h + * \brief YASM core types and utility functions. + * + * \license + * 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: + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - 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. + * \endlicense + */ +#ifndef YASM_CORETYPE_H +#define YASM_CORETYPE_H + +#ifndef YASM_LIB_DECL +#define YASM_LIB_DECL +#endif + +/** Architecture instance (mostly opaque type). \see arch.h for details. */ +typedef struct yasm_arch yasm_arch; +/** Preprocessor interface. \see preproc.h for details. */ +typedef struct yasm_preproc yasm_preproc; +/** Parser instance (mostly opaque type). \see parser.h for details. */ +typedef struct yasm_parser yasm_parser; +/** Object format interface. \see objfmt.h for details. */ +typedef struct yasm_objfmt yasm_objfmt; +/** Debug format interface. \see dbgfmt.h for details. */ +typedef struct yasm_dbgfmt yasm_dbgfmt; +/** List format interface. \see listfmt.h for details. */ +typedef struct yasm_listfmt yasm_listfmt; + +/** Object format module interface. \see objfmt.h for details. */ +typedef struct yasm_objfmt_module yasm_objfmt_module; +/** Debug format module interface. \see dbgfmt.h for details. */ +typedef struct yasm_dbgfmt_module yasm_dbgfmt_module; + +/** Standard macro structure for modules that allows association of a set of + * standard macros with a parser/preprocessor combination. + * A NULL-terminated array of these structures is used in a number of module + * interfaces. + */ +typedef struct yasm_stdmac { + const char *parser; /**< Parser keyword */ + const char *preproc; /**< Preprocessor keyword */ + + /** NULL-terminated array of standard macros. May be NULL if no standard + * macros should be added for this preprocessor. + */ + const char **macros; +} yasm_stdmac; + +/** YASM associated data callback structure. Many data structures can have + * arbitrary data associated with them. + */ +typedef struct yasm_assoc_data_callback { + /** Free memory allocated for associated data. + * \param data associated data + */ + void (*destroy) (/*@only@*/ void *data); + + /** Print a description of allocated data. For debugging purposes. + * \param data associated data + * \param f output file + * \param indent_level indentation level + */ + void (*print) (void *data, FILE *f, int indent_level); +} yasm_assoc_data_callback; + +/** Set of collected error/warnings (opaque type). + * \see errwarn.h for details. + */ +typedef struct yasm_errwarns yasm_errwarns; + +/** Bytecode. \see bytecode.h for details and related functions. */ +typedef struct yasm_bytecode yasm_bytecode; + +/** Object. \see section.h for details and related functions. */ +typedef struct yasm_object yasm_object; + +/** Section (opaque type). \see section.h for related functions. */ +typedef struct yasm_section yasm_section; + +/** Symbol table (opaque type). \see symrec.h for related functions. */ +typedef struct yasm_symtab yasm_symtab; + +/** Symbol record (opaque type). \see symrec.h for related functions. */ +typedef struct yasm_symrec yasm_symrec; + +/** Expression. \see expr.h for details and related functions. */ +typedef struct yasm_expr yasm_expr; +/** Integer value (opaque type). \see intnum.h for related functions. */ +typedef struct yasm_intnum yasm_intnum; +/** Floating point value (opaque type). + * \see floatnum.h for related functions. + */ +typedef struct yasm_floatnum yasm_floatnum; + +/** A value. May be absolute or relative. Outside the parser, yasm_expr + * should only be used for absolute exprs. Anything that could contain + * a relocatable value should use this structure instead. + * \see value.h for related functions. + */ +typedef struct yasm_value { + /** The absolute portion of the value. May contain *differences* between + * symrecs but not standalone symrecs. May be NULL if there is no + * absolute portion (e.g. the absolute portion is 0). + */ + /*@null@*/ /*@only@*/ yasm_expr *abs; + + /** The relative portion of the value. This is the portion that may + * need to generate a relocation. May be NULL if no relative portion. + */ + /*@null@*/ /*@dependent@*/ yasm_symrec *rel; + + /** What the relative portion is in reference to. NULL if the default. */ + /*@null@*/ /*@dependent@*/ yasm_symrec *wrt; + + /** If the segment of the relative portion should be used, not the + * relative portion itself. Boolean. + */ + unsigned int seg_of : 1; + + /** If the relative portion of the value should be shifted right + * (supported only by a few object formats). If just the absolute portion + * should be shifted, that must be in the abs expr, not here! + */ + unsigned int rshift : 7; + + /** Indicates the relative portion of the value should be relocated + * relative to the current assembly position rather than relative to the + * section start. "Current assembly position" here refers to the starting + * address of the bytecode containing this value. Boolean. + */ + unsigned int curpos_rel : 1; + + /** Indicates that curpos_rel was set due to IP-relative relocation; + * in some objfmt/arch combinations (e.g. win64/x86-amd64) this info + * is needed to generate special relocations. + */ + unsigned int ip_rel : 1; + + /** Indicates the value is a jump target address (rather than a simple + * data address). In some objfmt/arch combinations (e.g. macho/amd64) + * this info is needed to generate special relocations. + */ + unsigned int jump_target : 1; + + /** Indicates the relative portion of the value should be relocated + * relative to its own section start rather than relative to the + * section start of the bytecode containing this value. E.g. the value + * resulting from the relative portion should be the offset from its + * section start. Boolean. + */ + unsigned int section_rel : 1; + + /** Indicates overflow warnings have been disabled for this value. */ + unsigned int no_warn : 1; + + /** Sign of the value. Nonzero if the final value should be treated as + * signed, 0 if it should be treated as signed. + */ + unsigned int sign : 1; + + /** Size of the value, in bits. */ + unsigned int size : 8; +} yasm_value; + +/** Maximum value of #yasm_value.rshift */ +#define YASM_VALUE_RSHIFT_MAX 127 + +/** Line number mapping repository (opaque type). \see linemap.h for related + * functions. + */ +typedef struct yasm_linemap yasm_linemap; + +/** Value/parameter pair (opaque type). + * \see valparam.h for related functions. + */ +typedef struct yasm_valparam yasm_valparam; +/** List of value/parameters (opaque type). + * \see valparam.h for related functions. + */ +typedef struct yasm_valparamhead yasm_valparamhead; +/** Directive list entry. + * \see valparam.h for details and related functions. + */ +typedef struct yasm_directive yasm_directive; + +/** An effective address. + * \see insn.h for related functions. + */ +typedef struct yasm_effaddr yasm_effaddr; + +/** An instruction. + * \see insn.h for related functions. + */ +typedef struct yasm_insn yasm_insn; + +/** Expression operators usable in #yasm_expr expressions. */ +typedef enum yasm_expr_op { + YASM_EXPR_IDENT, /**< No operation, just a value. */ + YASM_EXPR_ADD, /**< Arithmetic addition (+). */ + YASM_EXPR_SUB, /**< Arithmetic subtraction (-). */ + YASM_EXPR_MUL, /**< Arithmetic multiplication (*). */ + YASM_EXPR_DIV, /**< Arithmetic unsigned division. */ + YASM_EXPR_SIGNDIV, /**< Arithmetic signed division. */ + YASM_EXPR_MOD, /**< Arithmetic unsigned modulus. */ + YASM_EXPR_SIGNMOD, /**< Arithmetic signed modulus. */ + YASM_EXPR_NEG, /**< Arithmetic negation (-). */ + YASM_EXPR_NOT, /**< Bitwise negation. */ + YASM_EXPR_OR, /**< Bitwise OR. */ + YASM_EXPR_AND, /**< Bitwise AND. */ + YASM_EXPR_XOR, /**< Bitwise XOR. */ + YASM_EXPR_XNOR, /**< Bitwise XNOR. */ + YASM_EXPR_NOR, /**< Bitwise NOR. */ + YASM_EXPR_SHL, /**< Shift left (logical). */ + YASM_EXPR_SHR, /**< Shift right (logical). */ + YASM_EXPR_LOR, /**< Logical OR. */ + YASM_EXPR_LAND, /**< Logical AND. */ + YASM_EXPR_LNOT, /**< Logical negation. */ + YASM_EXPR_LXOR, /**< Logical XOR. */ + YASM_EXPR_LXNOR, /**< Logical XNOR. */ + YASM_EXPR_LNOR, /**< Logical NOR. */ + YASM_EXPR_LT, /**< Less than comparison. */ + YASM_EXPR_GT, /**< Greater than comparison. */ + YASM_EXPR_EQ, /**< Equality comparison. */ + YASM_EXPR_LE, /**< Less than or equal to comparison. */ + YASM_EXPR_GE, /**< Greater than or equal to comparison. */ + YASM_EXPR_NE, /**< Not equal comparison. */ + YASM_EXPR_NONNUM, /**< Start of non-numeric operations (not an op). */ + YASM_EXPR_SEG, /**< SEG operator (gets segment portion of address). */ + YASM_EXPR_WRT, /**< WRT operator (gets offset of address relative to + * some other segment). */ + YASM_EXPR_SEGOFF /**< The ':' in segment:offset. */ +} yasm_expr_op; + +/** Convert yasm_value to its byte representation. Usually implemented by + * object formats to keep track of relocations and verify legal expressions. + * Must put the value into the least significant bits of the destination, + * unless shifted into more significant bits by the shift parameter. The + * destination bits must be cleared before being set. + * \param value value + * \param buf buffer for byte representation + * \param destsize destination size (in bytes) + * \param offset offset (in bytes) of the expr contents from the start + * of the bytecode (needed for relative) + * \param bc current bytecode (usually passed into higher-level + * calling function) + * \param warn enables standard warnings: zero for none; + * nonzero for overflow/underflow floating point warnings + * \param d objfmt-specific data (passed into higher-level calling + * function) + * \return Nonzero if an error occurred, 0 otherwise. + */ +typedef int (*yasm_output_value_func) + (yasm_value *value, /*@out@*/ unsigned char *buf, unsigned int destsize, + unsigned long offset, yasm_bytecode *bc, int warn, /*@null@*/ void *d); + +/** Convert a symbol reference to its byte representation. Usually implemented + * by object formats and debug formats to keep track of relocations generated + * by themselves. + * \param sym symbol + * \param bc current bytecode (usually passed into higher-level + * calling function) + * \param buf buffer for byte representation + * \param destsize destination size (in bytes) + * \param valsize size (in bits) + * \param warn enables standard warnings: zero for none; + * nonzero for overflow/underflow floating point warnings; + * negative for signed integer warnings, + * positive for unsigned integer warnings + * \param d objfmt-specific data (passed into higher-level calling + * function) + * \return Nonzero if an error occurred, 0 otherwise. + */ +typedef int (*yasm_output_reloc_func) + (yasm_symrec *sym, yasm_bytecode *bc, unsigned char *buf, + unsigned int destsize, unsigned int valsize, int warn, void *d); + +/** Sort an array using merge sort algorithm. + * \internal + * \param base base of array + * \param nmemb number of elements in array + * \param size size of each array element + * \param compar element comparison function + */ +YASM_LIB_DECL +int yasm__mergesort(void *base, size_t nmemb, size_t size, + int (*compar)(const void *, const void *)); + +/** Separate string by delimiters. + * \internal + * \param stringp string + * \param delim set of 1 or more delimiters + * \return First/next substring. + */ +YASM_LIB_DECL +/*@null@*/ char *yasm__strsep(char **stringp, const char *delim); + +/** Compare two strings, ignoring case differences. + * \internal + * \param s1 string 1 + * \param s2 string 2 + * \return 0 if strings are equal, -1 if s1<s2, 1 if s1>s2. + */ +YASM_LIB_DECL +int yasm__strcasecmp(const char *s1, const char *s2); + +/** Compare portion of two strings, ignoring case differences. + * \internal + * \param s1 string 1 + * \param s2 string 2 + * \param n maximum number of characters to compare + * \return 0 if strings are equal, -1 if s1<s2, 1 if s1>s2. + */ +YASM_LIB_DECL +int yasm__strncasecmp(const char *s1, const char *s2, size_t n); + +/** strdup() implementation using yasm_xmalloc(). + * \internal + * \param str string + * \return Newly allocated duplicate string. + */ +YASM_LIB_DECL +/*@only@*/ char *yasm__xstrdup(const char *str); + +/** strndup() implementation using yasm_xmalloc(). + * \internal + * \param str string + * \param max maximum number of characters to copy + * \return Newly allocated duplicate string. + */ +YASM_LIB_DECL +/*@only@*/ char *yasm__xstrndup(const char *str, size_t max); + +/** Error-checking memory allocation. A default implementation is provided + * that calls yasm_fatal() on allocation errors. + * A replacement should \em never return NULL. + * \param size number of bytes to allocate + * \return Allocated memory block. + */ +YASM_LIB_DECL +extern /*@only@*/ /*@out@*/ void * (*yasm_xmalloc) (size_t size); + +/** Error-checking memory allocation (with clear-to-0). A default + * implementation is provided that calls yasm_fatal() on allocation errors. + * A replacement should \em never return NULL. + * \param size number of elements to allocate + * \param elsize size (in bytes) of each element + * \return Allocated and cleared memory block. + */ +YASM_LIB_DECL +extern /*@only@*/ void * (*yasm_xcalloc) (size_t nelem, size_t elsize); + +/** Error-checking memory reallocation. A default implementation is provided + * that calls yasm_fatal() on allocation errors. A replacement should + * \em never return NULL. + * \param oldmem memory block to resize + * \param elsize new size, in bytes + * \return Re-allocated memory block. + */ +YASM_LIB_DECL +extern /*@only@*/ void * (*yasm_xrealloc) + (/*@only@*/ /*@out@*/ /*@returned@*/ /*@null@*/ void *oldmem, size_t size) + /*@modifies oldmem@*/; + +/** Error-checking memory deallocation. A default implementation is provided + * that calls yasm_fatal() on allocation errors. + * \param p memory block to free + */ +YASM_LIB_DECL +extern void (*yasm_xfree) (/*@only@*/ /*@out@*/ /*@null@*/ void *p) + /*@modifies p@*/; + +#endif diff --git a/contrib/tools/yasm/libyasm/dbgfmt.h b/contrib/tools/yasm/libyasm/dbgfmt.h new file mode 100644 index 0000000000..2e5ea867ee --- /dev/null +++ b/contrib/tools/yasm/libyasm/dbgfmt.h @@ -0,0 +1,131 @@ +/** + * \file libyasm/dbgfmt.h + * \brief YASM debug format interface. + * + * \license + * 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: + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - 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. + * \endlicense + */ +#ifndef YASM_DBGFMT_H +#define YASM_DBGFMT_H + +#ifndef YASM_DOXYGEN +/** Base #yasm_dbgfmt structure. Must be present as the first element in any + * #yasm_dbgfmt implementation. + */ +typedef struct yasm_dbgfmt_base { + /** #yasm_dbgfmt_module implementation for this debug format. */ + const struct yasm_dbgfmt_module *module; +} yasm_dbgfmt_base; +#endif + +/** Debug format module interface. */ +struct yasm_dbgfmt_module { + /** One-line description of the debug format. */ + const char *name; + + /** Keyword used to select debug format. */ + const char *keyword; + + /** NULL-terminated list of directives. NULL if none. */ + /*@null@*/ const yasm_directive *directives; + + /** Create debug format. + * Module-level implementation of yasm_dbgfmt_create(). + * The filenames are provided solely for informational purposes. + * \param object object + * \return NULL if object format does not provide needed support. + */ + /*@null@*/ /*@only@*/ yasm_dbgfmt * (*create) (yasm_object *object); + + /** Module-level implementation of yasm_dbgfmt_destroy(). + * Call yasm_dbgfmt_destroy() instead of calling this function. + */ + void (*destroy) (/*@only@*/ yasm_dbgfmt *dbgfmt); + + /** Module-level implementation of yasm_dbgfmt_generate(). + * Call yasm_dbgfmt_generate() instead of calling this function. + */ + void (*generate) (yasm_object *object, yasm_linemap *linemap, + yasm_errwarns *errwarns); + + /** + * --replace params + */ + const char** replace_map; + /** + * Number of elements in replace_map + */ + int replace_map_size; +}; + +/** Get the keyword used to select a debug format. + * \param dbgfmt debug format + * \return keyword + */ +const char *yasm_dbgfmt_keyword(const yasm_dbgfmt *dbgfmt); + +/** Initialize debug output for use. Must call before any other debug + * format functions. The filenames are provided solely for informational + * purposes. + * \param module debug format module + * \param object object to generate debugging information for + * \return NULL if object format does not provide needed support. + */ +/*@null@*/ /*@only@*/ yasm_dbgfmt *yasm_dbgfmt_create + (const yasm_dbgfmt_module *module, yasm_object *object); + +/** Cleans up any allocated debug format memory. + * \param dbgfmt debug format + */ +void yasm_dbgfmt_destroy(/*@only@*/ yasm_dbgfmt *dbgfmt); + +/** Generate debugging information bytecodes. + * \param object object + * \param linemap virtual/physical line mapping + * \param errwarns error/warning set + * \note Errors and warnings are stored into errwarns. + */ +void yasm_dbgfmt_generate(yasm_object *object, yasm_linemap *linemap, + yasm_errwarns *errwarns); + +#ifndef YASM_DOXYGEN + +/* Inline macro implementations for dbgfmt functions */ + +#define yasm_dbgfmt_keyword(dbgfmt) \ + (((yasm_dbgfmt_base *)dbgfmt)->module->keyword) + +#define yasm_dbgfmt_create(module, object) \ + module->create(object) + +#define yasm_dbgfmt_destroy(dbgfmt) \ + ((yasm_dbgfmt_base *)dbgfmt)->module->destroy(dbgfmt) +#define yasm_dbgfmt_generate(object, linemap, ews) \ + ((yasm_dbgfmt_base *)((object)->dbgfmt))->module->generate \ + (object, linemap, ews) + +#endif + +#endif diff --git a/contrib/tools/yasm/libyasm/errwarn.c b/contrib/tools/yasm/libyasm/errwarn.c new file mode 100644 index 0000000000..f759cf8f71 --- /dev/null +++ b/contrib/tools/yasm/libyasm/errwarn.c @@ -0,0 +1,537 @@ +/* + * Error and warning reporting and related 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 <ctype.h> +#include <errno.h> +#include <stdarg.h> + +#include "coretype.h" + +#include "linemap.h" +#include "errwarn.h" + + +#define MSG_MAXSIZE 1024 + +#if !defined(HAVE_TOASCII) || defined(lint) +# define toascii(c) ((c) & 0x7F) +#endif + +/* Default handlers for replacable functions */ +static /*@exits@*/ void def_internal_error_ + (const char *file, unsigned int line, const char *message); +static /*@exits@*/ void def_fatal(const char *message, va_list va); +static const char *def_gettext_hook(const char *msgid); + +/* Storage for errwarn's "extern" functions */ +/*@exits@*/ void (*yasm_internal_error_) + (const char *file, unsigned int line, const char *message) + = def_internal_error_; +/*@exits@*/ void (*yasm_fatal) (const char *message, va_list va) = def_fatal; +const char * (*yasm_gettext_hook) (const char *msgid) = def_gettext_hook; + +/* Error indicator */ +/* yasm_eclass is not static so that yasm_error_occurred macro can access it */ +yasm_error_class yasm_eclass; +static /*@only@*/ /*@null@*/ char *yasm_estr; +static unsigned long yasm_exrefline; +static /*@only@*/ /*@null@*/ char *yasm_exrefstr; + +/* Warning indicator */ +typedef struct warn { + /*@reldef@*/ STAILQ_ENTRY(warn) link; + + yasm_warn_class wclass; + /*@owned@*/ /*@null@*/ char *wstr; +} warn; +static STAILQ_HEAD(warn_head, warn) yasm_warns; + +/* Enabled warnings. See errwarn.h for a list. */ +static unsigned long warn_class_enabled; + +typedef struct errwarn_data { + /*@reldef@*/ SLIST_ENTRY(errwarn_data) link; + + enum { WE_UNKNOWN, WE_ERROR, WE_WARNING, WE_PARSERERROR } type; + + unsigned long line; + unsigned long xrefline; + /*@owned@*/ char *msg; + /*@owned@*/ char *xrefmsg; +} errwarn_data; + +struct yasm_errwarns { + /*@reldef@*/ SLIST_HEAD(errwarn_head, errwarn_data) errwarns; + + /* Total error count */ + unsigned int ecount; + + /* Total warning count */ + unsigned int wcount; + + /* Last inserted error/warning. Used to speed up insertions. */ + /*@null@*/ errwarn_data *previous_we; +}; + +/* Static buffer for use by conv_unprint(). */ +static char unprint[5]; + + +static const char * +def_gettext_hook(const char *msgid) +{ + return msgid; +} + +void +yasm_errwarn_initialize(void) +{ + /* Default enabled warnings. See errwarn.h for a list. */ + warn_class_enabled = + (1UL<<YASM_WARN_GENERAL) | (1UL<<YASM_WARN_UNREC_CHAR) | + (1UL<<YASM_WARN_PREPROC) | (0UL<<YASM_WARN_ORPHAN_LABEL) | + (1UL<<YASM_WARN_UNINIT_CONTENTS) | (0UL<<YASM_WARN_SIZE_OVERRIDE) | + (1UL<<YASM_WARN_IMPLICIT_SIZE_OVERRIDE); + + yasm_eclass = YASM_ERROR_NONE; + yasm_estr = NULL; + yasm_exrefline = 0; + yasm_exrefstr = NULL; + + STAILQ_INIT(&yasm_warns); +} + +void +yasm_errwarn_cleanup(void) +{ + yasm_error_clear(); + yasm_warn_clear(); +} + +/* Convert a possibly unprintable character into a printable string, using + * standard cat(1) convention for unprintable characters. + */ +char * +yasm__conv_unprint(int ch) +{ + int pos = 0; + + if (((ch & ~0x7F) != 0) /*!isascii(ch)*/ && !isprint(ch)) { + unprint[pos++] = 'M'; + unprint[pos++] = '-'; + ch &= toascii(ch); + } + if (iscntrl(ch)) { + unprint[pos++] = '^'; + unprint[pos++] = (ch == '\177') ? '?' : ch | 0100; + } else + unprint[pos++] = ch; + unprint[pos] = '\0'; + + return unprint; +} + +/* Report an internal error. Essentially a fatal error with trace info. + * Exit immediately because it's essentially an assert() trap. + */ +static void +def_internal_error_(const char *file, unsigned int line, const char *message) +{ + fprintf(stderr, + yasm_gettext_hook(N_("INTERNAL ERROR at %s, line %u: %s\n")), + file, line, yasm_gettext_hook(message)); +#ifdef HAVE_ABORT + abort(); +#else + exit(EXIT_FAILURE); +#endif +} + +/* Report a fatal error. These are unrecoverable (such as running out of + * memory), so just exit immediately. + */ +static void +def_fatal(const char *fmt, va_list va) +{ + fprintf(stderr, "%s: ", yasm_gettext_hook(N_("FATAL"))); + vfprintf(stderr, yasm_gettext_hook(fmt), va); + fputc('\n', stderr); + exit(EXIT_FAILURE); +} + +/* Create an errwarn structure in the correct linked list location. + * If replace_parser_error is nonzero, overwrites the last error if its + * type is WE_PARSERERROR. + */ +static errwarn_data * +errwarn_data_new(yasm_errwarns *errwarns, unsigned long line, + int replace_parser_error) +{ + errwarn_data *first, *next, *ins_we, *we; + enum { INS_NONE, INS_HEAD, INS_AFTER } action = INS_NONE; + + /* Find the entry with either line=line or the last one with line<line. + * Start with the last entry added to speed the search. + */ + ins_we = errwarns->previous_we; + first = SLIST_FIRST(&errwarns->errwarns); + if (!ins_we || !first) + action = INS_HEAD; + while (action == INS_NONE) { + next = SLIST_NEXT(ins_we, link); + if (line < ins_we->line) { + if (ins_we == first) + action = INS_HEAD; + else + ins_we = first; + } else if (!next) + action = INS_AFTER; + else if (line >= ins_we->line && line < next->line) + action = INS_AFTER; + else + ins_we = next; + } + + if (replace_parser_error && ins_we && ins_we->type == WE_PARSERERROR) { + /* overwrite last error */ + we = ins_we; + } else { + /* add a new error */ + we = yasm_xmalloc(sizeof(errwarn_data)); + + we->type = WE_UNKNOWN; + we->line = line; + we->xrefline = 0; + we->msg = NULL; + we->xrefmsg = NULL; + + if (action == INS_HEAD) + SLIST_INSERT_HEAD(&errwarns->errwarns, we, link); + else if (action == INS_AFTER) { + assert(ins_we != NULL); + SLIST_INSERT_AFTER(ins_we, we, link); + } else + yasm_internal_error(N_("Unexpected errwarn insert action")); + } + + /* Remember previous err/warn */ + errwarns->previous_we = we; + + return we; +} + +void +yasm_error_clear(void) +{ + if (yasm_estr) + yasm_xfree(yasm_estr); + if (yasm_exrefstr) + yasm_xfree(yasm_exrefstr); + yasm_eclass = YASM_ERROR_NONE; + yasm_estr = NULL; + yasm_exrefline = 0; + yasm_exrefstr = NULL; +} + +int +yasm_error_matches(yasm_error_class eclass) +{ + if (yasm_eclass == YASM_ERROR_NONE) + return eclass == YASM_ERROR_NONE; + if (yasm_eclass == YASM_ERROR_GENERAL) + return eclass == YASM_ERROR_GENERAL; + return (yasm_eclass & eclass) == eclass; +} + +void +yasm_error_set_va(yasm_error_class eclass, const char *format, va_list va) +{ + if (yasm_eclass != YASM_ERROR_NONE) + return; + + yasm_eclass = eclass; + yasm_estr = yasm_xmalloc(MSG_MAXSIZE+1); +#ifdef HAVE_VSNPRINTF + vsnprintf(yasm_estr, MSG_MAXSIZE, yasm_gettext_hook(format), va); +#else + vsprintf(yasm_estr, yasm_gettext_hook(format), va); +#endif +} + +void +yasm_error_set(yasm_error_class eclass, const char *format, ...) +{ + va_list va; + va_start(va, format); + yasm_error_set_va(eclass, format, va); + va_end(va); +} + +void +yasm_error_set_xref_va(unsigned long xrefline, const char *format, va_list va) +{ + if (yasm_eclass != YASM_ERROR_NONE) + return; + + yasm_exrefline = xrefline; + + yasm_exrefstr = yasm_xmalloc(MSG_MAXSIZE+1); +#ifdef HAVE_VSNPRINTF + vsnprintf(yasm_exrefstr, MSG_MAXSIZE, yasm_gettext_hook(format), va); +#else + vsprintf(yasm_exrefstr, yasm_gettext_hook(format), va); +#endif +} + +void +yasm_error_set_xref(unsigned long xrefline, const char *format, ...) +{ + va_list va; + va_start(va, format); + yasm_error_set_xref_va(xrefline, format, va); + va_end(va); +} + +void +yasm_error_fetch(yasm_error_class *eclass, char **str, unsigned long *xrefline, + char **xrefstr) +{ + *eclass = yasm_eclass; + *str = yasm_estr; + *xrefline = yasm_exrefline; + *xrefstr = yasm_exrefstr; + yasm_eclass = YASM_ERROR_NONE; + yasm_estr = NULL; + yasm_exrefline = 0; + yasm_exrefstr = NULL; +} + +void yasm_warn_clear(void) +{ + /* Delete all error/warnings */ + while (!STAILQ_EMPTY(&yasm_warns)) { + warn *w = STAILQ_FIRST(&yasm_warns); + + if (w->wstr) + yasm_xfree(w->wstr); + + STAILQ_REMOVE_HEAD(&yasm_warns, link); + yasm_xfree(w); + } +} + +yasm_warn_class +yasm_warn_occurred(void) +{ + if (STAILQ_EMPTY(&yasm_warns)) + return YASM_WARN_NONE; + return STAILQ_FIRST(&yasm_warns)->wclass; +} + +void +yasm_warn_set_va(yasm_warn_class wclass, const char *format, va_list va) +{ + warn *w; + + if (!(warn_class_enabled & (1UL<<wclass))) + return; /* warning is part of disabled class */ + + w = yasm_xmalloc(sizeof(warn)); + w->wclass = wclass; + w->wstr = yasm_xmalloc(MSG_MAXSIZE+1); +#ifdef HAVE_VSNPRINTF + vsnprintf(w->wstr, MSG_MAXSIZE, yasm_gettext_hook(format), va); +#else + vsprintf(w->wstr, yasm_gettext_hook(format), va); +#endif + STAILQ_INSERT_TAIL(&yasm_warns, w, link); +} + +void +yasm_warn_set(yasm_warn_class wclass, const char *format, ...) +{ + va_list va; + va_start(va, format); + yasm_warn_set_va(wclass, format, va); + va_end(va); +} + +void +yasm_warn_fetch(yasm_warn_class *wclass, char **str) +{ + warn *w = STAILQ_FIRST(&yasm_warns); + + if (!w) { + *wclass = YASM_WARN_NONE; + *str = NULL; + return; + } + + *wclass = w->wclass; + *str = w->wstr; + + STAILQ_REMOVE_HEAD(&yasm_warns, link); + yasm_xfree(w); +} + +void +yasm_warn_enable(yasm_warn_class num) +{ + warn_class_enabled |= (1UL<<num); +} + +void +yasm_warn_disable(yasm_warn_class num) +{ + warn_class_enabled &= ~(1UL<<num); +} + +void +yasm_warn_disable_all(void) +{ + warn_class_enabled = 0; +} + +yasm_errwarns * +yasm_errwarns_create(void) +{ + yasm_errwarns *errwarns = yasm_xmalloc(sizeof(yasm_errwarns)); + SLIST_INIT(&errwarns->errwarns); + errwarns->ecount = 0; + errwarns->wcount = 0; + errwarns->previous_we = NULL; + return errwarns; +} + +void +yasm_errwarns_destroy(yasm_errwarns *errwarns) +{ + errwarn_data *we; + + /* Delete all error/warnings */ + while (!SLIST_EMPTY(&errwarns->errwarns)) { + we = SLIST_FIRST(&errwarns->errwarns); + if (we->msg) + yasm_xfree(we->msg); + if (we->xrefmsg) + yasm_xfree(we->xrefmsg); + + SLIST_REMOVE_HEAD(&errwarns->errwarns, link); + yasm_xfree(we); + } + + yasm_xfree(errwarns); +} + +void +yasm_errwarn_propagate(yasm_errwarns *errwarns, unsigned long line) +{ + if (yasm_eclass != YASM_ERROR_NONE) { + errwarn_data *we = errwarn_data_new(errwarns, line, 1); + yasm_error_class eclass; + + yasm_error_fetch(&eclass, &we->msg, &we->xrefline, &we->xrefmsg); + if (eclass != YASM_ERROR_GENERAL + && (eclass & YASM_ERROR_PARSE) == YASM_ERROR_PARSE) + we->type = WE_PARSERERROR; + else + we->type = WE_ERROR; + errwarns->ecount++; + } + + while (!STAILQ_EMPTY(&yasm_warns)) { + errwarn_data *we = errwarn_data_new(errwarns, line, 0); + yasm_warn_class wclass; + + yasm_warn_fetch(&wclass, &we->msg); + we->type = WE_WARNING; + errwarns->wcount++; + } +} + +unsigned int +yasm_errwarns_num_errors(yasm_errwarns *errwarns, int warning_as_error) +{ + if (warning_as_error) + return errwarns->ecount+errwarns->wcount; + else + return errwarns->ecount; +} + +void +yasm_errwarns_output_all(yasm_errwarns *errwarns, yasm_linemap *lm, + int warning_as_error, + yasm_print_error_func print_error, + yasm_print_warning_func print_warning) +{ + errwarn_data *we; + const char *filename, *xref_filename; + unsigned long line, xref_line; + + /* If we're treating warnings as errors, tell the user about it. */ + if (warning_as_error && warning_as_error != 2) { + print_error("", 0, + yasm_gettext_hook(N_("warnings being treated as errors")), + NULL, 0, NULL); + warning_as_error = 2; + } + + /* Output error/warnings. */ + SLIST_FOREACH(we, &errwarns->errwarns, link) { + /* Output error/warning */ + yasm_linemap_lookup(lm, we->line, &filename, &line); + if (we->xrefline) + yasm_linemap_lookup(lm, we->xrefline, &xref_filename, &xref_line); + else { + xref_filename = NULL; + xref_line = 0; + } + if (we->type == WE_ERROR || we->type == WE_PARSERERROR) + print_error(filename, line, we->msg, xref_filename, xref_line, + we->xrefmsg); + else + print_warning(filename, line, we->msg); + } +} + +void +yasm__fatal(const char *message, ...) +{ + va_list va; + va_start(va, message); + yasm_fatal(message, va); + /*@notreached@*/ + va_end(va); +} + +void +yasm__fatal_missing_input_file(const char *message, const char *filename) +{ + fprintf(stderr, "%s: %s %s (%s)\n", yasm_gettext_hook(N_("FATAL")), yasm_gettext_hook(message), strerror(errno), yasm_gettext_hook(filename)); + exit(EXIT_FAILURE); +} diff --git a/contrib/tools/yasm/libyasm/errwarn.h b/contrib/tools/yasm/libyasm/errwarn.h new file mode 100644 index 0000000000..f8e4f10ec3 --- /dev/null +++ b/contrib/tools/yasm/libyasm/errwarn.h @@ -0,0 +1,351 @@ +/** + * \file libyasm/errwarn.h + * \brief YASM error and warning reporting interface. + * + * \license + * 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: + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - 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. + * \endlicense + */ +#ifndef YASM_ERRWARN_H +#define YASM_ERRWARN_H + +#ifndef YASM_LIB_DECL +#define YASM_LIB_DECL +#endif + +/** Warning classes (that may be enabled/disabled). */ +typedef enum yasm_warn_class { + YASM_WARN_NONE = 0, /**< No warning */ + YASM_WARN_GENERAL, /**< Non-specific warnings */ + YASM_WARN_UNREC_CHAR, /**< Unrecognized characters (while tokenizing) */ + YASM_WARN_PREPROC, /**< Preprocessor warnings */ + YASM_WARN_ORPHAN_LABEL, /**< Label alone on a line without a colon */ + YASM_WARN_UNINIT_CONTENTS, /**< Uninitialized space in code/data section */ + YASM_WARN_SIZE_OVERRIDE,/**< Double size override */ + YASM_WARN_IMPLICIT_SIZE_OVERRIDE /**< Implicit size override */ +} yasm_warn_class; + +/** Error classes. Bitmask-based to support limited subclassing. */ +typedef enum yasm_error_class { + YASM_ERROR_NONE = 0x0000, /**< No error */ + YASM_ERROR_GENERAL = 0xFFFF, /**< Non-specific */ + YASM_ERROR_ARITHMETIC = 0x0001, /**< Arithmetic error (general) */ + YASM_ERROR_OVERFLOW = 0x8001, /**< Arithmetic overflow */ + YASM_ERROR_FLOATING_POINT = 0x4001, /**< Floating point error */ + YASM_ERROR_ZERO_DIVISION = 0x2001, /**< Divide-by-zero */ + YASM_ERROR_ASSERTION = 0x0002, /**< Assertion error */ + YASM_ERROR_VALUE = 0x0004, /**< Value inappropriate + * (e.g. not in range) */ + YASM_ERROR_NOT_ABSOLUTE = 0x8004, /**< Absolute expression required */ + YASM_ERROR_TOO_COMPLEX = 0x4004, /**< Expression too complex */ + YASM_ERROR_NOT_CONSTANT = 0x2004, /**< Constant expression required */ + YASM_ERROR_IO = 0x0008, /**< I/O error */ + YASM_ERROR_NOT_IMPLEMENTED = 0x0010, /**< Not implemented error */ + YASM_ERROR_TYPE = 0x0020, /**< Type error */ + YASM_ERROR_SYNTAX = 0x0040, /**< Syntax error */ + YASM_ERROR_PARSE = 0x8040 /**< Parser error */ +} yasm_error_class; + +/** Initialize any internal data structures. */ +YASM_LIB_DECL +void yasm_errwarn_initialize(void); + +/** Clean up any memory allocated by yasm_errwarn_initialize() or other + * functions. + */ +YASM_LIB_DECL +void yasm_errwarn_cleanup(void); + +/** Reporting point of internal errors. These are usually due to sanity + * check failures in the code. + * \warning This function must NOT return to calling code; exit or longjmp + * instead. + * \param file source file (ala __FILE__) + * \param line source line (ala __LINE__) + * \param message internal error message + */ +YASM_LIB_DECL +extern /*@exits@*/ void (*yasm_internal_error_) + (const char *file, unsigned int line, const char *message); + +/** Easily-callable version of yasm_internal_error_(). Automatically uses + * __FILE__ and __LINE__ as the file and line. + * \param message internal error message + */ +#define yasm_internal_error(message) \ + yasm_internal_error_(__FILE__, __LINE__, message) + +/** Reporting point of fatal errors. + * \warning This function must NOT return to calling code; exit or longjmp + * instead. + * \param message fatal error message + * \param va va_list argument list for message + */ +YASM_LIB_DECL +extern /*@exits@*/ void (*yasm_fatal) (const char *message, va_list va); + +/** Reporting point of fatal errors, with variable arguments (internal only). + * \warning This function calls #yasm_fatal, and thus does not return to the + * calling code. + * \param message fatal error message + * \param ... argument list for message + */ +YASM_LIB_DECL +/*@exits@*/ void yasm__fatal(const char *message, ...); + +YASM_LIB_DECL +/*@exits@*/ void yasm__fatal_missing_input_file(const char *message, const char *filename); + +/** Unconditionally clear the error indicator, freeing any associated data. + * Has no effect if the error indicator is not set. + */ +YASM_LIB_DECL +void yasm_error_clear(void); + +/** Get the error indicator. YASM_ERROR_NONE is returned if no error has + * been set. Note that as YASM_ERROR_NONE is 0, the return value can also + * be treated as a boolean value. + * \return Current error indicator. + */ +yasm_error_class yasm_error_occurred(void); + +/** Check the error indicator against an error class. To check if any error + * has been set, check against the YASM_ERROR_GENERAL class. This function + * properly checks error subclasses. + * \param eclass base error class to check against + * \return Nonzero if error indicator is set and a subclass of eclass, 0 + * otherwise. + */ +YASM_LIB_DECL +int yasm_error_matches(yasm_error_class eclass); + +#ifndef YASM_DOXYGEN +YASM_LIB_DECL +extern yasm_error_class yasm_eclass; +#define yasm_error_occurred() yasm_eclass +#endif + +/** Set the error indicator (va_list version). Has no effect if the error + * indicator is already set. + * \param eclass error class + * \param format printf format string + * \param va argument list for format + */ +YASM_LIB_DECL +void yasm_error_set_va(yasm_error_class eclass, const char *format, va_list va); + +/** Set the error indicator. Has no effect if the error indicator is already + * set. + * \param eclass error class + * \param format printf format string + * \param ... argument list for format + */ +YASM_LIB_DECL +void yasm_error_set(yasm_error_class eclass, const char *format, ...) + /*@printflike@*/; + +/** Set a cross-reference for a new error (va_list version). Has no effect + * if the error indicator is already set (e.g. with yasm_error_set()). This + * function must be called prior to its corresponding yasm_error_set() call. + * \param xrefline virtual line to cross-reference to (should not be 0) + * \param format printf format string + * \param va argument list for format + */ +YASM_LIB_DECL +void yasm_error_set_xref_va(unsigned long xrefline, const char *format, + va_list va); + +/** Set a cross-reference for a new error. Has no effect if the error + * indicator is already set (e.g. with yasm_error_set()). This function + * must be called prior to its corresponding yasm_error_set() call. + * \param xrefline virtual line to cross-reference to (should not be 0) + * \param format printf format string + * \param ... argument list for format + */ +YASM_LIB_DECL +void yasm_error_set_xref(unsigned long xrefline, const char *format, ...) + /*@printflike@*/; + +/** Fetch the error indicator and all associated data. If the error + * indicator is set, the output pointers are set to the current error + * indicator values, and the error indicator is cleared. + * The code using this function is then responsible for yasm_xfree()'ing + * str and xrefstr (if non-NULL). If the error indicator is not set, + * all output values are set to 0 (including eclass, which is set to + * YASM_ERROR_NONE). + * \param eclass error class (output) + * \param str error message + * \param xrefline virtual line used for cross-referencing (0 if no xref) + * \param xrefstr cross-reference error message (NULL if no xref) + */ +YASM_LIB_DECL +void yasm_error_fetch(/*@out@*/ yasm_error_class *eclass, + /*@out@*/ /*@only@*/ /*@null@*/ char **str, + /*@out@*/ unsigned long *xrefline, + /*@out@*/ /*@only@*/ /*@null@*/ char **xrefstr); + +/** Unconditionally clear all warning indicators, freeing any associated data. + * Has no effect if no warning indicators have been set. + */ +YASM_LIB_DECL +void yasm_warn_clear(void); + +/** Get the first warning indicator. YASM_WARN_NONE is returned if no warning + * has been set. Note that as YASM_WARN_NONE is 0, the return value can also + * be treated as a boolean value. + * \return First warning indicator. + */ +YASM_LIB_DECL +yasm_warn_class yasm_warn_occurred(void); + +/** Add a warning indicator (va_list version). + * \param wclass warning class + * \param format printf format string + * \param va argument list for format + */ +YASM_LIB_DECL +void yasm_warn_set_va(yasm_warn_class wclass, const char *format, va_list va); + +/** Add a warning indicator. + * \param wclass warning class + * \param format printf format string + * \param ... argument list for format + */ +YASM_LIB_DECL +void yasm_warn_set(yasm_warn_class wclass, const char *format, ...) + /*@printflike@*/; + +/** Fetch the first warning indicator and all associated data. If there + * is at least one warning indicator, the output pointers are set to the + * first warning indicator values, and first warning indicator is removed. + * The code using this function is then responsible for yasm_xfree()'ing + * str and xrefstr (if non-NULL). If there is no warning indicator set, + * all output values are set to 0 (including wclass, which is set to + * YASM_WARN_NONE). + * \param wclass warning class (output) + * \param str warning message + */ +YASM_LIB_DECL +void yasm_warn_fetch(/*@out@*/ yasm_warn_class *wclass, + /*@out@*/ /*@only@*/ char **str); + +/** Enable a class of warnings. + * \param wclass warning class + */ +YASM_LIB_DECL +void yasm_warn_enable(yasm_warn_class wclass); + +/** Disable a class of warnings. + * \param wclass warning class + */ +YASM_LIB_DECL +void yasm_warn_disable(yasm_warn_class wclass); + +/** Disable all classes of warnings. */ +YASM_LIB_DECL +void yasm_warn_disable_all(void); + +/** Create an error/warning set for collection of multiple error/warnings. + * \return Newly allocated set. + */ +YASM_LIB_DECL +/*@only@*/ yasm_errwarns *yasm_errwarns_create(void); + +/** Destroy an error/warning set. + * \param errwarns error/warning set + */ +YASM_LIB_DECL +void yasm_errwarns_destroy(/*@only@*/ yasm_errwarns *errwarns); + +/** Propagate error indicator and warning indicator(s) to an error/warning set. + * Has no effect if the error indicator and warning indicator are not set. + * Does not print immediately; yasm_errwarn_output_all() outputs + * accumulated errors and warnings. + * Generally multiple errors on the same line will be reported, but errors + * of class YASM_ERROR_PARSE will get overwritten by any other class on the + * same line. + * \param errwarns error/warning set + * \param line virtual line + */ +YASM_LIB_DECL +void yasm_errwarn_propagate(yasm_errwarns *errwarns, unsigned long line); + +/** Get total number of errors logged. + * \param errwarns error/warning set + * \param warning_as_error if nonzero, warnings are treated as errors. + * \return Number of errors. + */ +YASM_LIB_DECL +unsigned int yasm_errwarns_num_errors(yasm_errwarns *errwarns, + int warning_as_error); + +/** Print out an error. + * \param fn filename of source file + * \param line line number + * \param msg error message + * \param xref_fn cross-referenced source filename + * \param xref_line cross-referenced line number + * \param xref_msg cross-referenced error message + */ +typedef void (*yasm_print_error_func) + (const char *fn, unsigned long line, const char *msg, + /*@null@*/ const char *xref_fn, unsigned long xref_line, + /*@null@*/ const char *xref_msg); + +/** Print out a warning. + * \param fn filename of source file + * \param line line number + * \param msg warning message + */ +typedef void (*yasm_print_warning_func) + (const char *fn, unsigned long line, const char *msg); + +/** Outputs error/warning set in sorted order (sorted by virtual line number). + * \param errwarns error/warning set + * \param lm line map (to convert virtual lines into filename/line pairs) + * \param warning_as_error if nonzero, treat warnings as errors. + * \param print_error function called to print out errors + * \param print_warning function called to print out warnings + */ +YASM_LIB_DECL +void yasm_errwarns_output_all + (yasm_errwarns *errwarns, yasm_linemap *lm, int warning_as_error, + yasm_print_error_func print_error, yasm_print_warning_func print_warning); + +/** Convert a possibly unprintable character into a printable string. + * \internal + * \param ch possibly unprintable character + * \return Printable string representation (static buffer). + */ +YASM_LIB_DECL +char *yasm__conv_unprint(int ch); + +/** Hook for library users to map to gettext() if GNU gettext is being used. + * \param msgid message catalog identifier + * \return Translated message. + */ +YASM_LIB_DECL +extern const char * (*yasm_gettext_hook) (const char *msgid); + +#endif diff --git a/contrib/tools/yasm/libyasm/expr.c b/contrib/tools/yasm/libyasm/expr.c new file mode 100644 index 0000000000..c2c868ede2 --- /dev/null +++ b/contrib/tools/yasm/libyasm/expr.c @@ -0,0 +1,1516 @@ +/* + * Expression handling + * + * Copyright (C) 2001-2007 Michael Urman, 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-stdint.h" +#include "coretype.h" +#include "bitvect.h" + +#include "errwarn.h" +#include "intnum.h" +#include "floatnum.h" +#include "expr.h" +#include "symrec.h" + +#include "bytecode.h" +#include "section.h" + +#include "arch.h" + + +static /*@only@*/ yasm_expr *expr_level_op + (/*@returned@*/ /*@only@*/ yasm_expr *e, int fold_const, + int simplify_ident, int simplify_reg_mul); +static int expr_traverse_nodes_post(/*@null@*/ yasm_expr *e, + /*@null@*/ void *d, + int (*func) (/*@null@*/ yasm_expr *e, + /*@null@*/ void *d)); +static void expr_delete_term(yasm_expr__item *term, int recurse); + +/* Bitmap of used items. We should really never need more than 2 at a time, + * so 31 is pretty much overkill. + */ +static unsigned long itempool_used = 0; +static yasm_expr__item itempool[31]; + +/* allocate a new expression node, with children as defined. + * If it's a unary operator, put the element in left and set right=NULL. */ +/*@-compmempass@*/ +yasm_expr * +yasm_expr_create(yasm_expr_op op, yasm_expr__item *left, + yasm_expr__item *right, unsigned long line) +{ + yasm_expr *ptr, *sube; + unsigned long z; + ptr = yasm_xmalloc(sizeof(yasm_expr)); + + ptr->op = op; + ptr->numterms = 0; + ptr->terms[0].type = YASM_EXPR_NONE; + ptr->terms[1].type = YASM_EXPR_NONE; + if (left) { + ptr->terms[0] = *left; /* structure copy */ + z = (unsigned long)(left-itempool); + if (z>=31) + yasm_internal_error(N_("could not find expritem in pool")); + itempool_used &= ~(1<<z); + ptr->numterms++; + + /* Search downward until we find something *other* than an + * IDENT, then bring it up to the current level. + */ + while (ptr->terms[0].type == YASM_EXPR_EXPR && + ptr->terms[0].data.expn->op == YASM_EXPR_IDENT) { + sube = ptr->terms[0].data.expn; + ptr->terms[0] = sube->terms[0]; /* structure copy */ + /*@-usereleased@*/ + yasm_xfree(sube); + /*@=usereleased@*/ + } + } else { + yasm_internal_error(N_("Right side of expression must exist")); + } + + if (right) { + ptr->terms[1] = *right; /* structure copy */ + z = (unsigned long)(right-itempool); + if (z>=31) + yasm_internal_error(N_("could not find expritem in pool")); + itempool_used &= ~(1<<z); + ptr->numterms++; + + /* Search downward until we find something *other* than an + * IDENT, then bring it up to the current level. + */ + while (ptr->terms[1].type == YASM_EXPR_EXPR && + ptr->terms[1].data.expn->op == YASM_EXPR_IDENT) { + sube = ptr->terms[1].data.expn; + ptr->terms[1] = sube->terms[0]; /* structure copy */ + /*@-usereleased@*/ + yasm_xfree(sube); + /*@=usereleased@*/ + } + } + + ptr->line = line; + + return expr_level_op(ptr, 1, 1, 0); +} +/*@=compmempass@*/ + +/* helpers */ +static yasm_expr__item * +expr_get_item(void) +{ + int z = 0; + unsigned long v = itempool_used & 0x7fffffff; + + while (v & 1) { + v >>= 1; + z++; + } + if (z>=31) + yasm_internal_error(N_("too many expritems")); + itempool_used |= 1<<z; + return &itempool[z]; +} + +yasm_expr__item * +yasm_expr_precbc(yasm_bytecode *precbc) +{ + yasm_expr__item *e = expr_get_item(); + e->type = YASM_EXPR_PRECBC; + e->data.precbc = precbc; + return e; +} + +yasm_expr__item * +yasm_expr_sym(yasm_symrec *s) +{ + yasm_expr__item *e = expr_get_item(); + e->type = YASM_EXPR_SYM; + e->data.sym = s; + return e; +} + +yasm_expr__item * +yasm_expr_expr(yasm_expr *x) +{ + yasm_expr__item *e = expr_get_item(); + e->type = YASM_EXPR_EXPR; + e->data.expn = x; + return e; +} + +yasm_expr__item * +yasm_expr_int(yasm_intnum *i) +{ + yasm_expr__item *e = expr_get_item(); + e->type = YASM_EXPR_INT; + e->data.intn = i; + return e; +} + +yasm_expr__item * +yasm_expr_float(yasm_floatnum *f) +{ + yasm_expr__item *e = expr_get_item(); + e->type = YASM_EXPR_FLOAT; + e->data.flt = f; + return e; +} + +yasm_expr__item * +yasm_expr_reg(uintptr_t reg) +{ + yasm_expr__item *e = expr_get_item(); + e->type = YASM_EXPR_REG; + e->data.reg = reg; + return e; +} + +/* Transforms instances of symrec-symrec [symrec+(-1*symrec)] into single + * expritems if possible. Uses a simple n^2 algorithm because n is usually + * quite small. Also works for precbc-precbc (or symrec-precbc, + * precbc-symrec). + */ +static /*@only@*/ yasm_expr * +expr_xform_bc_dist_base(/*@returned@*/ /*@only@*/ yasm_expr *e, + /*@null@*/ void *cbd, + int (*callback) (yasm_expr__item *ei, + yasm_bytecode *precbc, + yasm_bytecode *precbc2, + void *cbd)) +{ + int i; + /*@dependent@*/ yasm_section *sect; + /*@dependent@*/ /*@null@*/ yasm_bytecode *precbc; + int numterms; + + /* Handle symrec-symrec in ADD exprs by looking for (-1*symrec) and + * symrec term pairs (where both symrecs are in the same segment). + */ + if (e->op != YASM_EXPR_ADD) + return e; + + for (i=0; i<e->numterms; i++) { + int j; + yasm_expr *sube; + yasm_intnum *intn; + yasm_symrec *sym = NULL; + /*@dependent@*/ yasm_section *sect2; + /*@dependent@*/ /*@null@*/ yasm_bytecode *precbc2; + + /* First look for an (-1*symrec) term */ + if (e->terms[i].type != YASM_EXPR_EXPR) + continue; + sube = e->terms[i].data.expn; + if (sube->op != YASM_EXPR_MUL || sube->numterms != 2) + continue; + + if (sube->terms[0].type == YASM_EXPR_INT && + (sube->terms[1].type == YASM_EXPR_SYM || + sube->terms[1].type == YASM_EXPR_PRECBC)) { + intn = sube->terms[0].data.intn; + if (sube->terms[1].type == YASM_EXPR_PRECBC) + precbc = sube->terms[1].data.precbc; + else + sym = sube->terms[1].data.sym; + } else if ((sube->terms[0].type == YASM_EXPR_SYM || + sube->terms[0].type == YASM_EXPR_PRECBC) && + sube->terms[1].type == YASM_EXPR_INT) { + if (sube->terms[0].type == YASM_EXPR_PRECBC) + precbc = sube->terms[0].data.precbc; + else + sym = sube->terms[0].data.sym; + intn = sube->terms[1].data.intn; + } else + continue; + + if (!yasm_intnum_is_neg1(intn)) + continue; + + if (sym && !yasm_symrec_get_label(sym, &precbc)) + continue; + sect2 = yasm_bc_get_section(precbc); + + /* Now look for a symrec term in the same segment */ + for (j=0; j<e->numterms; j++) { + if (((e->terms[j].type == YASM_EXPR_SYM && + yasm_symrec_get_label(e->terms[j].data.sym, &precbc2)) || + (e->terms[j].type == YASM_EXPR_PRECBC && + (precbc2 = e->terms[j].data.precbc))) && + (sect = yasm_bc_get_section(precbc2)) && + sect == sect2 && + callback(&e->terms[j], precbc, precbc2, cbd)) { + /* Delete the matching (-1*symrec) term */ + yasm_expr_destroy(sube); + e->terms[i].type = YASM_EXPR_NONE; + break; /* stop looking for matching symrec term */ + } + } + } + + /* Clean up any deleted (EXPR_NONE) terms */ + numterms = 0; + for (i=0; i<e->numterms; i++) { + if (e->terms[i].type != YASM_EXPR_NONE) + e->terms[numterms++] = e->terms[i]; /* structure copy */ + } + if (e->numterms != numterms) { + e->numterms = numterms; + e = yasm_xrealloc(e, sizeof(yasm_expr)+((numterms<2) ? 0 : + sizeof(yasm_expr__item)*(numterms-2))); + if (numterms == 1) + e->op = YASM_EXPR_IDENT; + } + + return e; +} + +static int +expr_xform_bc_dist_cb(yasm_expr__item *ei, yasm_bytecode *precbc, + yasm_bytecode *precbc2, /*@null@*/ void *d) +{ + yasm_intnum *dist = yasm_calc_bc_dist(precbc, precbc2); + if (!dist) + return 0; + /* Change the term to an integer */ + ei->type = YASM_EXPR_INT; + ei->data.intn = dist; + return 1; +} + +/* Transforms instances of symrec-symrec [symrec+(-1*symrec)] into integers if + * possible. + */ +static /*@only@*/ yasm_expr * +expr_xform_bc_dist(/*@returned@*/ /*@only@*/ yasm_expr *e) +{ + return expr_xform_bc_dist_base(e, NULL, expr_xform_bc_dist_cb); +} + +typedef struct bc_dist_subst_cbd { + void (*callback) (unsigned int subst, yasm_bytecode *precbc, + yasm_bytecode *precbc2, void *cbd); + void *cbd; + unsigned int subst; +} bc_dist_subst_cbd; + +static int +expr_bc_dist_subst_cb(yasm_expr__item *ei, yasm_bytecode *precbc, + yasm_bytecode *precbc2, /*@null@*/ void *d) +{ + bc_dist_subst_cbd *my_cbd = d; + assert(my_cbd != NULL); + /* Call higher-level callback */ + my_cbd->callback(my_cbd->subst, precbc, precbc2, my_cbd->cbd); + /* Change the term to an subst */ + ei->type = YASM_EXPR_SUBST; + ei->data.subst = my_cbd->subst; + my_cbd->subst++; + return 1; +} + +static yasm_expr * +expr_xform_bc_dist_subst(yasm_expr *e, void *d) +{ + return expr_xform_bc_dist_base(e, d, expr_bc_dist_subst_cb); +} + +int +yasm_expr__bc_dist_subst(yasm_expr **ep, void *cbd, + void (*callback) (unsigned int subst, + yasm_bytecode *precbc, + yasm_bytecode *precbc2, + void *cbd)) +{ + bc_dist_subst_cbd my_cbd; /* callback info for low-level callback */ + my_cbd.callback = callback; + my_cbd.cbd = cbd; + my_cbd.subst = 0; + *ep = yasm_expr__level_tree(*ep, 1, 1, 1, 0, &expr_xform_bc_dist_subst, + &my_cbd); + return my_cbd.subst; +} + +/* Negate just a single ExprItem by building a -1*ei subexpression */ +static void +expr_xform_neg_item(yasm_expr *e, yasm_expr__item *ei) +{ + yasm_expr *sube = yasm_xmalloc(sizeof(yasm_expr)); + + /* Build -1*ei subexpression */ + sube->op = YASM_EXPR_MUL; + sube->line = e->line; + sube->numterms = 2; + sube->terms[0].type = YASM_EXPR_INT; + sube->terms[0].data.intn = yasm_intnum_create_int(-1); + sube->terms[1] = *ei; /* structure copy */ + + /* Replace original ExprItem with subexp */ + ei->type = YASM_EXPR_EXPR; + ei->data.expn = sube; +} + +/* Negates e by multiplying by -1, with distribution over lower-precedence + * operators (eg ADD) and special handling to simplify result w/ADD, NEG, and + * others. + * + * Returns a possibly reallocated e. + */ +static /*@only@*/ yasm_expr * +expr_xform_neg_helper(/*@returned@*/ /*@only@*/ yasm_expr *e) +{ + yasm_expr *ne; + int i; + + switch (e->op) { + case YASM_EXPR_ADD: + /* distribute (recursively if expr) over terms */ + for (i=0; i<e->numterms; i++) { + if (e->terms[i].type == YASM_EXPR_EXPR) + e->terms[i].data.expn = + expr_xform_neg_helper(e->terms[i].data.expn); + else + expr_xform_neg_item(e, &e->terms[i]); + } + break; + case YASM_EXPR_SUB: + /* change op to ADD, and recursively negate left side (if expr) */ + e->op = YASM_EXPR_ADD; + if (e->terms[0].type == YASM_EXPR_EXPR) + e->terms[0].data.expn = + expr_xform_neg_helper(e->terms[0].data.expn); + else + expr_xform_neg_item(e, &e->terms[0]); + break; + case YASM_EXPR_NEG: + /* Negating a negated value? Make it an IDENT. */ + e->op = YASM_EXPR_IDENT; + break; + case YASM_EXPR_IDENT: + /* Negating an ident? Change it into a MUL w/ -1 if there's no + * floatnums present below; if there ARE floatnums, recurse. + */ + if (e->terms[0].type == YASM_EXPR_FLOAT) + yasm_floatnum_calc(e->terms[0].data.flt, YASM_EXPR_NEG, NULL); + else if (e->terms[0].type == YASM_EXPR_INT) + yasm_intnum_calc(e->terms[0].data.intn, YASM_EXPR_NEG, NULL); + else if (e->terms[0].type == YASM_EXPR_EXPR && + yasm_expr__contains(e->terms[0].data.expn, YASM_EXPR_FLOAT)) + expr_xform_neg_helper(e->terms[0].data.expn); + else { + e->op = YASM_EXPR_MUL; + e->numterms = 2; + e->terms[1].type = YASM_EXPR_INT; + e->terms[1].data.intn = yasm_intnum_create_int(-1); + } + break; + default: + /* Everything else. MUL will be combined when it's leveled. + * Make a new expr (to replace e) with -1*e. + */ + ne = yasm_xmalloc(sizeof(yasm_expr)); + ne->op = YASM_EXPR_MUL; + ne->line = e->line; + ne->numterms = 2; + ne->terms[0].type = YASM_EXPR_INT; + ne->terms[0].data.intn = yasm_intnum_create_int(-1); + ne->terms[1].type = YASM_EXPR_EXPR; + ne->terms[1].data.expn = e; + return ne; + } + return e; +} + +/* Transforms negatives into expressions that are easier to combine: + * -x -> -1*x + * a-b -> a+(-1*b) + * + * Call post-order on an expression tree to transform the entire tree. + * + * Returns a possibly reallocated e. + */ +static /*@only@*/ yasm_expr * +expr_xform_neg(/*@returned@*/ /*@only@*/ yasm_expr *e) +{ + switch (e->op) { + case YASM_EXPR_NEG: + /* Turn -x into -1*x */ + e->op = YASM_EXPR_IDENT; + return expr_xform_neg_helper(e); + case YASM_EXPR_SUB: + /* Turn a-b into a+(-1*b) */ + + /* change op to ADD, and recursively negate right side (if expr) */ + e->op = YASM_EXPR_ADD; + if (e->terms[1].type == YASM_EXPR_EXPR) + e->terms[1].data.expn = + expr_xform_neg_helper(e->terms[1].data.expn); + else + expr_xform_neg_item(e, &e->terms[1]); + break; + default: + break; + } + + return e; +} + +/* Look for simple identities that make the entire result constant: + * 0*&x, -1|x, etc. + */ +static int +expr_is_constant(yasm_expr_op op, yasm_intnum *intn) +{ + int iszero = yasm_intnum_is_zero(intn); + return ((iszero && op == YASM_EXPR_MUL) || + (iszero && op == YASM_EXPR_AND) || + (iszero && op == YASM_EXPR_LAND) || + (yasm_intnum_is_neg1(intn) && op == YASM_EXPR_OR)); +} + +/* Look for simple "left" identities like 0+x, 1*x, etc. */ +static int +expr_can_destroy_int_left(yasm_expr_op op, yasm_intnum *intn) +{ + int iszero = yasm_intnum_is_zero(intn); + return ((yasm_intnum_is_pos1(intn) && op == YASM_EXPR_MUL) || + (iszero && op == YASM_EXPR_ADD) || + (yasm_intnum_is_neg1(intn) && op == YASM_EXPR_AND) || + (!iszero && op == YASM_EXPR_LAND) || + (iszero && op == YASM_EXPR_OR) || + (iszero && op == YASM_EXPR_LOR)); +} + +/* Look for simple "right" identities like x+|-0, x*&/1 */ +static int +expr_can_destroy_int_right(yasm_expr_op op, yasm_intnum *intn) +{ + int iszero = yasm_intnum_is_zero(intn); + int ispos1 = yasm_intnum_is_pos1(intn); + return ((ispos1 && op == YASM_EXPR_MUL) || + (ispos1 && op == YASM_EXPR_DIV) || + (iszero && op == YASM_EXPR_ADD) || + (iszero && op == YASM_EXPR_SUB) || + (yasm_intnum_is_neg1(intn) && op == YASM_EXPR_AND) || + (!iszero && op == YASM_EXPR_LAND) || + (iszero && op == YASM_EXPR_OR) || + (iszero && op == YASM_EXPR_LOR) || + (iszero && op == YASM_EXPR_SHL) || + (iszero && op == YASM_EXPR_SHR)); +} + +/* Check for and simplify identities. Returns new number of expr terms. + * Sets e->op = EXPR_IDENT if numterms ends up being 1. + * Uses numterms parameter instead of e->numterms for basis of "new" number + * of terms. + * Assumes int_term is *only* integer term in e. + * NOTE: Really designed to only be used by expr_level_op(). + */ +static int +expr_simplify_identity(yasm_expr *e, int numterms, int *int_term, + int simplify_reg_mul) +{ + int i; + int save_numterms; + + /* Don't do this step if it's 1*REG. Save and restore numterms so + * yasm_expr__contains() works correctly. + */ + save_numterms = e->numterms; + e->numterms = numterms; + if (simplify_reg_mul || e->op != YASM_EXPR_MUL + || !yasm_intnum_is_pos1(e->terms[*int_term].data.intn) + || !yasm_expr__contains(e, YASM_EXPR_REG)) { + /* Check for simple identities that delete the intnum. + * Don't delete if the intnum is the only thing in the expn. + */ + if ((*int_term == 0 && numterms > 1 && + expr_can_destroy_int_left(e->op, e->terms[0].data.intn)) || + (*int_term > 0 && + expr_can_destroy_int_right(e->op, + e->terms[*int_term].data.intn))) { + /* Delete the intnum */ + yasm_intnum_destroy(e->terms[*int_term].data.intn); + + /* Slide everything to its right over by 1 */ + if (*int_term != numterms-1) /* if it wasn't last.. */ + memmove(&e->terms[*int_term], &e->terms[*int_term+1], + (numterms-1-*int_term)*sizeof(yasm_expr__item)); + + /* Update numterms */ + numterms--; + *int_term = -1; /* no longer an int term */ + } + } + e->numterms = save_numterms; + + /* Check for simple identites that delete everything BUT the intnum. + * Don't bother if the intnum is the only thing in the expn. + */ + if (numterms > 1 && *int_term != -1 && + expr_is_constant(e->op, e->terms[*int_term].data.intn)) { + /* Loop through, deleting everything but the integer term */ + for (i=0; i<e->numterms; i++) + if (i != *int_term) + expr_delete_term(&e->terms[i], 1); + + /* Move integer term to the first term (if not already there) */ + if (*int_term != 0) + e->terms[0] = e->terms[*int_term]; /* structure copy */ + + /* Set numterms to 1 */ + numterms = 1; + } + + /* Compute NOT, NEG, and LNOT on single intnum. */ + if (numterms == 1 && *int_term == 0 && + (e->op == YASM_EXPR_NOT || e->op == YASM_EXPR_NEG || + e->op == YASM_EXPR_LNOT)) + yasm_intnum_calc(e->terms[0].data.intn, e->op, NULL); + + /* Change expression to IDENT if possible. */ + if (numterms == 1) + e->op = YASM_EXPR_IDENT; + + /* Return the updated numterms */ + return numterms; +} + +/* Levels the expression tree starting at e. Eg: + * a+(b+c) -> a+b+c + * (a+b)+(c+d) -> a+b+c+d + * Naturally, only levels operators that allow more than two operand terms. + * NOTE: only does *one* level of leveling (no recursion). Should be called + * post-order on a tree to combine deeper levels. + * Also brings up any IDENT values into the current level (for ALL operators). + * Folds (combines by evaluation) *integer* constant values if fold_const != 0. + * + * Returns a possibly reallocated e. + */ +/*@-mustfree@*/ +static /*@only@*/ yasm_expr * +expr_level_op(/*@returned@*/ /*@only@*/ yasm_expr *e, int fold_const, + int simplify_ident, int simplify_reg_mul) +{ + int i, j, o, fold_numterms, level_numterms, level_fold_numterms; + int first_int_term = -1; + + /* Determine how many operands will need to be brought up (for leveling). + * Go ahead and bring up any IDENT'ed values. + */ + while (e->op == YASM_EXPR_IDENT && e->terms[0].type == YASM_EXPR_EXPR) { + yasm_expr *sube = e->terms[0].data.expn; + yasm_xfree(e); + e = sube; + } + + /* If non-numeric expression, don't fold constants. */ + if (e->op > YASM_EXPR_NONNUM) + fold_const = 0; + + level_numterms = e->numterms; + level_fold_numterms = 0; + for (i=0; i<e->numterms; i++) { + /* Search downward until we find something *other* than an + * IDENT, then bring it up to the current level. + */ + while (e->terms[i].type == YASM_EXPR_EXPR && + e->terms[i].data.expn->op == YASM_EXPR_IDENT) { + yasm_expr *sube = e->terms[i].data.expn; + e->terms[i] = sube->terms[0]; + yasm_xfree(sube); + } + + if (e->terms[i].type == YASM_EXPR_EXPR && + e->terms[i].data.expn->op == e->op) { + /* It's an expression w/the same operator, add in its numterms. + * But don't forget to subtract one for the expr itself! + */ + level_numterms += e->terms[i].data.expn->numterms - 1; + + /* If we're folding constants, count up the number of constants + * that will be merged in. + */ + if (fold_const) + for (j=0; j<e->terms[i].data.expn->numterms; j++) + if (e->terms[i].data.expn->terms[j].type == + YASM_EXPR_INT) + level_fold_numterms++; + } + + /* Find the first integer term (if one is present) if we're folding + * constants. + */ + if (fold_const && first_int_term == -1 && + e->terms[i].type == YASM_EXPR_INT) + first_int_term = i; + } + + /* Look for other integer terms if there's one and combine. + * Also eliminate empty spaces when combining and adjust numterms + * variables. + */ + fold_numterms = e->numterms; + if (first_int_term != -1) { + for (i=first_int_term+1, o=first_int_term+1; i<e->numterms; i++) { + if (e->terms[i].type == YASM_EXPR_INT) { + yasm_intnum_calc(e->terms[first_int_term].data.intn, e->op, + e->terms[i].data.intn); + fold_numterms--; + level_numterms--; + /* make sure to delete folded intnum */ + yasm_intnum_destroy(e->terms[i].data.intn); + } else if (o != i) { + /* copy term if it changed places */ + e->terms[o++] = e->terms[i]; + } else + o++; + } + + if (simplify_ident) { + int new_fold_numterms; + /* Simplify identities and make IDENT if possible. */ + new_fold_numterms = + expr_simplify_identity(e, fold_numterms, &first_int_term, + simplify_reg_mul); + level_numterms -= fold_numterms-new_fold_numterms; + fold_numterms = new_fold_numterms; + } + if (fold_numterms == 1) + e->op = YASM_EXPR_IDENT; + } + + /* Only level operators that allow more than two operand terms. + * Also don't bother leveling if it's not necessary to bring up any terms. + */ + if ((e->op != YASM_EXPR_ADD && e->op != YASM_EXPR_MUL && + e->op != YASM_EXPR_OR && e->op != YASM_EXPR_AND && + e->op != YASM_EXPR_LOR && e->op != YASM_EXPR_LAND && + e->op != YASM_EXPR_LXOR && e->op != YASM_EXPR_XOR) || + level_numterms <= fold_numterms) { + /* Downsize e if necessary */ + if (fold_numterms < e->numterms && e->numterms > 2) + e = yasm_xrealloc(e, sizeof(yasm_expr)+((fold_numterms<2) ? 0 : + sizeof(yasm_expr__item)*(fold_numterms-2))); + /* Update numterms */ + e->numterms = fold_numterms; + return e; + } + + /* Adjust numterms for constant folding from terms being "pulled up". + * Careful: if there's no integer term in e, then save space for it. + */ + if (fold_const) { + level_numterms -= level_fold_numterms; + if (first_int_term == -1 && level_fold_numterms != 0) + level_numterms++; + } + + /* Alloc more (or conceivably less, but not usually) space for e */ + e = yasm_xrealloc(e, sizeof(yasm_expr)+((level_numterms<2) ? 0 : + sizeof(yasm_expr__item)*(level_numterms-2))); + + /* Copy up ExprItem's. Iterate from right to left to keep the same + * ordering as was present originally. + * Combine integer terms as necessary. + */ + for (i=fold_numterms-1, o=level_numterms-1; i>=0; i--) { + if (e->terms[i].type == YASM_EXPR_EXPR && + e->terms[i].data.expn->op == e->op) { + /* bring up subexpression */ + yasm_expr *sube = e->terms[i].data.expn; + + /* copy terms right to left */ + for (j=sube->numterms-1; j>=0; j--) { + if (fold_const && sube->terms[j].type == YASM_EXPR_INT) { + /* Need to fold it in.. but if there's no int term already, + * just copy into a new one. + */ + if (first_int_term == -1) { + first_int_term = o--; + e->terms[first_int_term] = sube->terms[j]; /* struc */ + } else { + yasm_intnum_calc(e->terms[first_int_term].data.intn, + e->op, sube->terms[j].data.intn); + /* make sure to delete folded intnum */ + yasm_intnum_destroy(sube->terms[j].data.intn); + } + } else { + if (o == first_int_term) + o--; + e->terms[o--] = sube->terms[j]; /* structure copy */ + } + } + + /* delete subexpression, but *don't delete nodes* (as we've just + * copied them!) + */ + yasm_xfree(sube); + } else if (o != i) { + /* copy operand if it changed places */ + if (o == first_int_term) + o--; + e->terms[o] = e->terms[i]; + /* If we moved the first_int_term, change first_int_num too */ + if (i == first_int_term) + first_int_term = o; + o--; + } else + o--; + } + + /* Simplify identities, make IDENT if possible, and save to e->numterms. */ + if (simplify_ident && first_int_term != -1) { + e->numterms = expr_simplify_identity(e, level_numterms, + &first_int_term, simplify_reg_mul); + } else { + e->numterms = level_numterms; + if (level_numterms == 1) + e->op = YASM_EXPR_IDENT; + } + + return e; +} +/*@=mustfree@*/ + +typedef SLIST_HEAD(yasm__exprhead, yasm__exprentry) yasm__exprhead; +typedef struct yasm__exprentry { + /*@reldef@*/ SLIST_ENTRY(yasm__exprentry) next; + /*@null@*/ const yasm_expr *e; +} yasm__exprentry; + +static yasm_expr * +expr_expand_equ(yasm_expr *e, yasm__exprhead *eh) +{ + int i; + yasm__exprentry ee; + + /* traverse terms */ + for (i=0; i<e->numterms; i++) { + const yasm_expr *equ_expr; + + /* Expand equ's. */ + if (e->terms[i].type == YASM_EXPR_SYM && + (equ_expr = yasm_symrec_get_equ(e->terms[i].data.sym))) { + yasm__exprentry *np; + + /* Check for circular reference */ + SLIST_FOREACH(np, eh, next) { + if (np->e == equ_expr) { + yasm_error_set(YASM_ERROR_TOO_COMPLEX, + N_("circular reference detected")); + return e; + } + } + + e->terms[i].type = YASM_EXPR_EXPR; + e->terms[i].data.expn = yasm_expr_copy(equ_expr); + + /* Remember we saw this equ and recurse */ + ee.e = equ_expr; + SLIST_INSERT_HEAD(eh, &ee, next); + e->terms[i].data.expn = expr_expand_equ(e->terms[i].data.expn, eh); + SLIST_REMOVE_HEAD(eh, next); + } else if (e->terms[i].type == YASM_EXPR_EXPR) + /* Recurse */ + e->terms[i].data.expn = expr_expand_equ(e->terms[i].data.expn, eh); + } + + return e; +} + +static yasm_expr * +expr_level_tree(yasm_expr *e, int fold_const, int simplify_ident, + int simplify_reg_mul, int calc_bc_dist, + yasm_expr_xform_func expr_xform_extra, + void *expr_xform_extra_data) +{ + int i; + + e = expr_xform_neg(e); + + /* traverse terms */ + for (i=0; i<e->numterms; i++) { + /* Recurse */ + if (e->terms[i].type == YASM_EXPR_EXPR) + e->terms[i].data.expn = + expr_level_tree(e->terms[i].data.expn, fold_const, + simplify_ident, simplify_reg_mul, calc_bc_dist, + expr_xform_extra, expr_xform_extra_data); + } + + /* Check for SEG of SEG:OFF, if we match, simplify to just the segment */ + if (e->op == YASM_EXPR_SEG && e->terms[0].type == YASM_EXPR_EXPR && + e->terms[0].data.expn->op == YASM_EXPR_SEGOFF) { + e->op = YASM_EXPR_IDENT; + e->terms[0].data.expn->op = YASM_EXPR_IDENT; + /* Destroy the second (offset) term */ + e->terms[0].data.expn->numterms = 1; + expr_delete_term(&e->terms[0].data.expn->terms[1], 1); + } + + /* do callback */ + e = expr_level_op(e, fold_const, simplify_ident, simplify_reg_mul); + if (calc_bc_dist || expr_xform_extra) { + if (calc_bc_dist) + e = expr_xform_bc_dist(e); + if (expr_xform_extra) + e = expr_xform_extra(e, expr_xform_extra_data); + e = expr_level_tree(e, fold_const, simplify_ident, simplify_reg_mul, + 0, NULL, NULL); + } + return e; +} + +/* Level an entire expn tree, expanding equ's as we go */ +yasm_expr * +yasm_expr__level_tree(yasm_expr *e, int fold_const, int simplify_ident, + int simplify_reg_mul, int calc_bc_dist, + yasm_expr_xform_func expr_xform_extra, + void *expr_xform_extra_data) +{ + yasm__exprhead eh; + SLIST_INIT(&eh); + + if (!e) + return 0; + + e = expr_expand_equ(e, &eh); + e = expr_level_tree(e, fold_const, simplify_ident, simplify_reg_mul, + calc_bc_dist, expr_xform_extra, expr_xform_extra_data); + + return e; +} + +/* Comparison function for expr_order_terms(). + * Assumes ExprType enum is in canonical order. + */ +static int +expr_order_terms_compare(const void *va, const void *vb) +{ + const yasm_expr__item *a = va, *b = vb; + return (a->type - b->type); +} + +/* Reorder terms of e into canonical order. Only reorders if reordering + * doesn't change meaning of expression. (eg, doesn't reorder SUB). + * Canonical order: REG, INT, FLOAT, SYM, EXPR. + * Multiple terms of a single type are kept in the same order as in + * the original expression. + * NOTE: Only performs reordering on *one* level (no recursion). + */ +void +yasm_expr__order_terms(yasm_expr *e) +{ + /* don't bother reordering if only one element */ + if (e->numterms == 1) + return; + + /* only reorder some types of operations */ + switch (e->op) { + case YASM_EXPR_ADD: + case YASM_EXPR_MUL: + case YASM_EXPR_OR: + case YASM_EXPR_AND: + case YASM_EXPR_XOR: + case YASM_EXPR_LOR: + case YASM_EXPR_LAND: + case YASM_EXPR_LXOR: + /* Use mergesort to sort. It's fast on already sorted values and a + * stable sort (multiple terms of same type are kept in the same + * order). + */ + yasm__mergesort(e->terms, (size_t)e->numterms, + sizeof(yasm_expr__item), expr_order_terms_compare); + break; + default: + break; + } +} + +static void +expr_item_copy(yasm_expr__item *dest, const yasm_expr__item *src) +{ + dest->type = src->type; + switch (src->type) { + case YASM_EXPR_SYM: + /* Symbols don't need to be copied */ + dest->data.sym = src->data.sym; + break; + case YASM_EXPR_PRECBC: + /* Nor do direct bytecode references */ + dest->data.precbc = src->data.precbc; + break; + case YASM_EXPR_EXPR: + dest->data.expn = yasm_expr__copy_except(src->data.expn, -1); + break; + case YASM_EXPR_INT: + dest->data.intn = yasm_intnum_copy(src->data.intn); + break; + case YASM_EXPR_FLOAT: + dest->data.flt = yasm_floatnum_copy(src->data.flt); + break; + case YASM_EXPR_REG: + dest->data.reg = src->data.reg; + break; + case YASM_EXPR_SUBST: + dest->data.subst = src->data.subst; + break; + default: + break; + } +} + +/* Copy entire expression EXCEPT for index "except" at *top level only*. */ +yasm_expr * +yasm_expr__copy_except(const yasm_expr *e, int except) +{ + yasm_expr *n; + int i; + + n = yasm_xmalloc(sizeof(yasm_expr) + + sizeof(yasm_expr__item)*(e->numterms<2?0:e->numterms-2)); + + n->op = e->op; + n->line = e->line; + n->numterms = e->numterms; + for (i=0; i<e->numterms; i++) { + if (i != except) + expr_item_copy(&n->terms[i], &e->terms[i]); + } + + return n; +} + +static void +expr_delete_term(yasm_expr__item *term, int recurse) +{ + switch (term->type) { + case YASM_EXPR_INT: + yasm_intnum_destroy(term->data.intn); + break; + case YASM_EXPR_FLOAT: + yasm_floatnum_destroy(term->data.flt); + break; + case YASM_EXPR_EXPR: + if (recurse) + yasm_expr_destroy(term->data.expn); + break; + default: + break; + } +} + +static int +expr_destroy_each(/*@only@*/ yasm_expr *e, /*@unused@*/ void *d) +{ + int i; + for (i=0; i<e->numterms; i++) + expr_delete_term(&e->terms[i], 0); + yasm_xfree(e); /* free ourselves */ + return 0; /* don't stop recursion */ +} + +/*@-mustfree@*/ +void +yasm_expr_destroy(yasm_expr *e) +{ + expr_traverse_nodes_post(e, NULL, expr_destroy_each); +} +/*@=mustfree@*/ + +int +yasm_expr_is_op(const yasm_expr *e, yasm_expr_op op) +{ + return (e->op == op); +} + +static int +expr_contains_callback(const yasm_expr__item *ei, void *d) +{ + yasm_expr__type *t = d; + return (ei->type & *t); +} + +int +yasm_expr__contains(const yasm_expr *e, yasm_expr__type t) +{ + return yasm_expr__traverse_leaves_in_const(e, &t, expr_contains_callback); +} + +typedef struct subst_cbd { + unsigned int num_items; + const yasm_expr__item *items; +} subst_cbd; + +static int +expr_subst_callback(yasm_expr__item *ei, void *d) +{ + subst_cbd *cbd = d; + if (ei->type != YASM_EXPR_SUBST) + return 0; + if (ei->data.subst >= cbd->num_items) + return 1; /* error */ + expr_item_copy(ei, &cbd->items[ei->data.subst]); + return 0; +} + +int +yasm_expr__subst(yasm_expr *e, unsigned int num_items, + const yasm_expr__item *items) +{ + subst_cbd cbd; + cbd.num_items = num_items; + cbd.items = items; + return yasm_expr__traverse_leaves_in(e, &cbd, expr_subst_callback); +} + +/* Traverse over expression tree, calling func for each operation AFTER the + * branches (if expressions) have been traversed (eg, postorder + * traversal). The data pointer d is passed to each func call. + * + * Stops early (and returns 1) if func returns 1. Otherwise returns 0. + */ +static int +expr_traverse_nodes_post(yasm_expr *e, void *d, + int (*func) (/*@null@*/ yasm_expr *e, + /*@null@*/ void *d)) +{ + int i; + + if (!e) + return 0; + + /* traverse terms */ + for (i=0; i<e->numterms; i++) { + if (e->terms[i].type == YASM_EXPR_EXPR && + expr_traverse_nodes_post(e->terms[i].data.expn, d, func)) + return 1; + } + + /* do callback */ + return func(e, d); +} + +/* Traverse over expression tree in order, calling func for each leaf + * (non-operation). The data pointer d is passed to each func call. + * + * Stops early (and returns 1) if func returns 1. Otherwise returns 0. + */ +int +yasm_expr__traverse_leaves_in_const(const yasm_expr *e, void *d, + int (*func) (/*@null@*/ const yasm_expr__item *ei, /*@null@*/ void *d)) +{ + int i; + + if (!e) + return 0; + + for (i=0; i<e->numterms; i++) { + if (e->terms[i].type == YASM_EXPR_EXPR) { + if (yasm_expr__traverse_leaves_in_const(e->terms[i].data.expn, d, + func)) + return 1; + } else { + if (func(&e->terms[i], d)) + return 1; + } + } + return 0; +} + +/* Traverse over expression tree in order, calling func for each leaf + * (non-operation). The data pointer d is passed to each func call. + * + * Stops early (and returns 1) if func returns 1. Otherwise returns 0. + */ +int +yasm_expr__traverse_leaves_in(yasm_expr *e, void *d, + int (*func) (/*@null@*/ yasm_expr__item *ei, /*@null@*/ void *d)) +{ + int i; + + if (!e) + return 0; + + for (i=0; i<e->numterms; i++) { + if (e->terms[i].type == YASM_EXPR_EXPR) { + if (yasm_expr__traverse_leaves_in(e->terms[i].data.expn, d, func)) + return 1; + } else { + if (func(&e->terms[i], d)) + return 1; + } + } + return 0; +} + +yasm_expr * +yasm_expr_extract_deep_segoff(yasm_expr **ep) +{ + yasm_expr *retval; + yasm_expr *e = *ep; + int i; + + /* Try to extract at this level */ + retval = yasm_expr_extract_segoff(ep); + if (retval) + return retval; + + /* Not at this level? Search any expr children. */ + for (i=0; i<e->numterms; i++) { + if (e->terms[i].type == YASM_EXPR_EXPR) { + retval = yasm_expr_extract_deep_segoff(&e->terms[i].data.expn); + if (retval) + return retval; + } + } + + /* Didn't find one */ + return NULL; +} + +yasm_expr * +yasm_expr_extract_segoff(yasm_expr **ep) +{ + yasm_expr *retval; + yasm_expr *e = *ep; + + /* If not SEG:OFF, we can't do this transformation */ + if (e->op != YASM_EXPR_SEGOFF) + return NULL; + + /* Extract the SEG portion out to its own expression */ + if (e->terms[0].type == YASM_EXPR_EXPR) + retval = e->terms[0].data.expn; + else { + /* Need to build IDENT expression to hold non-expression contents */ + retval = yasm_xmalloc(sizeof(yasm_expr)); + retval->op = YASM_EXPR_IDENT; + retval->numterms = 1; + retval->terms[0] = e->terms[0]; /* structure copy */ + } + + /* Delete the SEG: portion by changing the expression into an IDENT */ + e->op = YASM_EXPR_IDENT; + e->numterms = 1; + e->terms[0] = e->terms[1]; /* structure copy */ + + return retval; +} + +yasm_expr * +yasm_expr_extract_wrt(yasm_expr **ep) +{ + yasm_expr *retval; + yasm_expr *e = *ep; + + /* If not WRT, we can't do this transformation */ + if (e->op != YASM_EXPR_WRT) + return NULL; + + /* Extract the right side portion out to its own expression */ + if (e->terms[1].type == YASM_EXPR_EXPR) + retval = e->terms[1].data.expn; + else { + /* Need to build IDENT expression to hold non-expression contents */ + retval = yasm_xmalloc(sizeof(yasm_expr)); + retval->op = YASM_EXPR_IDENT; + retval->numterms = 1; + retval->terms[0] = e->terms[1]; /* structure copy */ + } + + /* Delete the right side portion by changing the expr into an IDENT */ + e->op = YASM_EXPR_IDENT; + e->numterms = 1; + + return retval; +} + +/*@-unqualifiedtrans -nullderef -nullstate -onlytrans@*/ +yasm_intnum * +yasm_expr_get_intnum(yasm_expr **ep, int calc_bc_dist) +{ + *ep = yasm_expr_simplify(*ep, calc_bc_dist); + + if ((*ep)->op == YASM_EXPR_IDENT && (*ep)->terms[0].type == YASM_EXPR_INT) + return (*ep)->terms[0].data.intn; + else + return (yasm_intnum *)NULL; +} +/*@=unqualifiedtrans =nullderef -nullstate -onlytrans@*/ + +/*@-unqualifiedtrans -nullderef -nullstate -onlytrans@*/ +const yasm_symrec * +yasm_expr_get_symrec(yasm_expr **ep, int simplify) +{ + if (simplify) + *ep = yasm_expr_simplify(*ep, 0); + + if ((*ep)->op == YASM_EXPR_IDENT && (*ep)->terms[0].type == YASM_EXPR_SYM) + return (*ep)->terms[0].data.sym; + else + return (yasm_symrec *)NULL; +} +/*@=unqualifiedtrans =nullderef -nullstate -onlytrans@*/ + +/*@-unqualifiedtrans -nullderef -nullstate -onlytrans@*/ +const uintptr_t * +yasm_expr_get_reg(yasm_expr **ep, int simplify) +{ + if (simplify) + *ep = yasm_expr_simplify(*ep, 0); + + if ((*ep)->op == YASM_EXPR_IDENT && (*ep)->terms[0].type == YASM_EXPR_REG) + return &((*ep)->terms[0].data.reg); + else + return NULL; +} +/*@=unqualifiedtrans =nullderef -nullstate -onlytrans@*/ + +void +yasm_expr_print(const yasm_expr *e, FILE *f) +{ + char opstr[8]; + int i; + + if (!e) { + fprintf(f, "(nil)"); + return; + } + + switch (e->op) { + case YASM_EXPR_ADD: + strcpy(opstr, "+"); + break; + case YASM_EXPR_SUB: + strcpy(opstr, "-"); + break; + case YASM_EXPR_MUL: + strcpy(opstr, "*"); + break; + case YASM_EXPR_DIV: + strcpy(opstr, "/"); + break; + case YASM_EXPR_SIGNDIV: + strcpy(opstr, "//"); + break; + case YASM_EXPR_MOD: + strcpy(opstr, "%"); + break; + case YASM_EXPR_SIGNMOD: + strcpy(opstr, "%%"); + break; + case YASM_EXPR_NEG: + fprintf(f, "-"); + opstr[0] = 0; + break; + case YASM_EXPR_NOT: + fprintf(f, "~"); + opstr[0] = 0; + break; + case YASM_EXPR_OR: + strcpy(opstr, "|"); + break; + case YASM_EXPR_AND: + strcpy(opstr, "&"); + break; + case YASM_EXPR_XOR: + strcpy(opstr, "^"); + break; + case YASM_EXPR_XNOR: + strcpy(opstr, "XNOR"); + break; + case YASM_EXPR_NOR: + strcpy(opstr, "NOR"); + break; + case YASM_EXPR_SHL: + strcpy(opstr, "<<"); + break; + case YASM_EXPR_SHR: + strcpy(opstr, ">>"); + break; + case YASM_EXPR_LOR: + strcpy(opstr, "||"); + break; + case YASM_EXPR_LAND: + strcpy(opstr, "&&"); + break; + case YASM_EXPR_LNOT: + strcpy(opstr, "!"); + break; + case YASM_EXPR_LXOR: + strcpy(opstr, "^^"); + break; + case YASM_EXPR_LXNOR: + strcpy(opstr, "LXNOR"); + break; + case YASM_EXPR_LNOR: + strcpy(opstr, "LNOR"); + break; + case YASM_EXPR_LT: + strcpy(opstr, "<"); + break; + case YASM_EXPR_GT: + strcpy(opstr, ">"); + break; + case YASM_EXPR_LE: + strcpy(opstr, "<="); + break; + case YASM_EXPR_GE: + strcpy(opstr, ">="); + break; + case YASM_EXPR_NE: + strcpy(opstr, "!="); + break; + case YASM_EXPR_EQ: + strcpy(opstr, "=="); + break; + case YASM_EXPR_SEG: + fprintf(f, "SEG "); + opstr[0] = 0; + break; + case YASM_EXPR_WRT: + strcpy(opstr, " WRT "); + break; + case YASM_EXPR_SEGOFF: + strcpy(opstr, ":"); + break; + case YASM_EXPR_IDENT: + opstr[0] = 0; + break; + default: + strcpy(opstr, " !UNK! "); + break; + } + for (i=0; i<e->numterms; i++) { + switch (e->terms[i].type) { + case YASM_EXPR_PRECBC: + fprintf(f, "{%lx}", + yasm_bc_next_offset(e->terms[i].data.precbc)); + break; + case YASM_EXPR_SYM: + fprintf(f, "%s", yasm_symrec_get_name(e->terms[i].data.sym)); + break; + case YASM_EXPR_EXPR: + fprintf(f, "("); + yasm_expr_print(e->terms[i].data.expn, f); + fprintf(f, ")"); + break; + case YASM_EXPR_INT: + yasm_intnum_print(e->terms[i].data.intn, f); + break; + case YASM_EXPR_FLOAT: + yasm_floatnum_print(e->terms[i].data.flt, f); + break; + case YASM_EXPR_REG: + /* FIXME */ + /*yasm_arch_reg_print(arch, e->terms[i].data.reg, f);*/ + break; + case YASM_EXPR_SUBST: + fprintf(f, "[%u]", e->terms[i].data.subst); + break; + case YASM_EXPR_NONE: + break; + } + if (i < e->numterms-1) + fprintf(f, "%s", opstr); + } +} + +unsigned int +yasm_expr_size(const yasm_expr *e) +{ + int i; + int seen = 0; + unsigned int size = 0, newsize; + + if (e->op == YASM_EXPR_IDENT) { + if (e->terms[0].type == YASM_EXPR_SYM) + return yasm_symrec_get_size(e->terms[0].data.sym); + return 0; + } + if (e->op != YASM_EXPR_ADD && e->op != YASM_EXPR_SUB) + return 0; + + for (i=0; i<e->numterms; i++) { + newsize = 0; + switch (e->terms[i].type) { + case YASM_EXPR_EXPR: + newsize = yasm_expr_size(e->terms[i].data.expn); + break; + case YASM_EXPR_SYM: + newsize = yasm_symrec_get_size(e->terms[i].data.sym); + break; + default: + break; + } + if (newsize) { + size = newsize; + if (seen) + /* either sum of idents (?!) or substract of idents */ + return 0; + seen = 1; + } + } + /* exactly one offset */ + return size; +} + +const char * +yasm_expr_segment(const yasm_expr *e) +{ + int i; + int seen = 0; + const char *segment = NULL; + + if (e->op == YASM_EXPR_IDENT) { + if (e->terms[0].type == YASM_EXPR_SYM) + return yasm_symrec_get_segment(e->terms[0].data.sym); + return NULL; + } + if (e->op != YASM_EXPR_ADD && e->op != YASM_EXPR_SUB) + return NULL; + + for (i=0; i<e->numterms; i++) { + if ((e->op == YASM_EXPR_ADD || !i) && + e->terms[i].type == YASM_EXPR_EXPR) { + if ((segment = yasm_expr_segment(e->terms[i].data.expn))) { + if (seen) { + /* either sum of idents (?!) or substract of idents */ + return NULL; + } + seen = 1; + } + } + } + /* exactly one offset */ + return segment; +} diff --git a/contrib/tools/yasm/libyasm/expr.h b/contrib/tools/yasm/libyasm/expr.h new file mode 100644 index 0000000000..0de62dfed7 --- /dev/null +++ b/contrib/tools/yasm/libyasm/expr.h @@ -0,0 +1,388 @@ +/** + * \file libyasm/expr.h + * \brief YASM expression interface. + * + * \license + * Copyright (C) 2001-2007 Michael Urman, Peter Johnson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - 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. + * \endlicense + */ +#ifndef YASM_EXPR_H +#define YASM_EXPR_H + +#ifndef YASM_LIB_DECL +#define YASM_LIB_DECL +#endif + +/** Type of an expression item. Types are listed in canonical sorting order. + * See expr_order_terms(). + * Note #YASM_EXPR_PRECBC must be used carefully (in a-b pairs), as only + * symrecs can become the relative term in a #yasm_value. + */ +typedef enum yasm_expr__type { + YASM_EXPR_NONE = 0, /**< Nothing */ + YASM_EXPR_REG = 1<<0, /**< Register */ + YASM_EXPR_INT = 1<<1, /**< Integer value */ + YASM_EXPR_SUBST = 1<<2, /**< Substitution placeholder */ + YASM_EXPR_FLOAT = 1<<3, /**< Floating point value */ + YASM_EXPR_SYM = 1<<4, /**< Symbol */ + YASM_EXPR_PRECBC = 1<<5,/**< Direct bytecode ref (rather than via sym) */ + YASM_EXPR_EXPR = 1<<6 /**< Subexpression */ +} yasm_expr__type; + +/** Expression item. */ +typedef struct yasm_expr__item { + yasm_expr__type type; /**< Type */ + + /** Expression item data. Correct value depends on type. */ + union { + yasm_bytecode *precbc; /**< Direct bytecode ref (YASM_EXPR_PRECBC) */ + yasm_symrec *sym; /**< Symbol (YASM_EXPR_SYM) */ + yasm_expr *expn; /**< Subexpression (YASM_EXPR_EXPR) */ + yasm_intnum *intn; /**< Integer value (YASM_EXPR_INT) */ + yasm_floatnum *flt; /**< Floating point value (YASM_EXPR_FLOAT) */ + uintptr_t reg; /**< Register (YASM_EXPR_REG) */ + unsigned int subst; /**< Subst placeholder (YASM_EXPR_SUBST) */ + } data; +} yasm_expr__item; + +/** Expression. */ +struct yasm_expr { + yasm_expr_op op; /**< Operation. */ + unsigned long line; /**< Line number where expression was defined. */ + int numterms; /**< Number of terms in the expression. */ + + /** Terms of the expression. Structure may be extended to include more + * terms, as some operations may allow more than two operand terms + * (ADD, MUL, OR, AND, XOR). + */ + yasm_expr__item terms[2]; +}; + +/** Create a new expression e=a op b. + * \param op operation + * \param a expression item a + * \param b expression item b (optional depending on op) + * \param line virtual line (where expression defined) + * \return Newly allocated expression. + */ +YASM_LIB_DECL +/*@only@*/ yasm_expr *yasm_expr_create + (yasm_expr_op op, /*@only@*/ yasm_expr__item *a, + /*@only@*/ /*@null@*/ yasm_expr__item *b, unsigned long line); + +/** Create a new preceding-bytecode expression item. + * \param precbc preceding bytecode + * \return Newly allocated expression item. + */ +YASM_LIB_DECL +/*@only@*/ yasm_expr__item *yasm_expr_precbc(/*@keep@*/ yasm_bytecode *precbc); + +/** Create a new symbol expression item. + * \param sym symbol + * \return Newly allocated expression item. + */ +YASM_LIB_DECL +/*@only@*/ yasm_expr__item *yasm_expr_sym(/*@keep@*/ yasm_symrec *sym); + +/** Create a new expression expression item. + * \param e expression + * \return Newly allocated expression item. + */ +YASM_LIB_DECL +/*@only@*/ yasm_expr__item *yasm_expr_expr(/*@keep@*/ yasm_expr *e); + +/** Create a new intnum expression item. + * \param intn intnum + * \return Newly allocated expression item. + */ +YASM_LIB_DECL +/*@only@*/ yasm_expr__item *yasm_expr_int(/*@keep@*/ yasm_intnum *intn); + +/** Create a new floatnum expression item. + * \param flt floatnum + * \return Newly allocated expression item. + */ +YASM_LIB_DECL +/*@only@*/ yasm_expr__item *yasm_expr_float(/*@keep@*/ yasm_floatnum *flt); + +/** Create a new register expression item. + * \param reg register + * \return Newly allocated expression item. + */ +YASM_LIB_DECL +/*@only@*/ yasm_expr__item *yasm_expr_reg(uintptr_t reg); + +/** Create a new expression tree e=l op r. + * \param l expression for left side of new expression + * \param o operation + * \param r expression for right side of new expression + * \param i line index + * \return Newly allocated expression. + */ +#define yasm_expr_create_tree(l,o,r,i) \ + yasm_expr_create ((o), yasm_expr_expr(l), yasm_expr_expr(r), i) + +/** Create a new expression branch e=op r. + * \param o operation + * \param r expression for right side of new expression + * \param i line index + * \return Newly allocated expression. + */ +#define yasm_expr_create_branch(o,r,i) \ + yasm_expr_create ((o), yasm_expr_expr(r), (yasm_expr__item *)NULL, i) + +/** Create a new expression identity e=r. + * \param r expression for identity within new expression + * \param i line index + * \return Newly allocated expression. + */ +#define yasm_expr_create_ident(r,i) \ + yasm_expr_create (YASM_EXPR_IDENT, (r), (yasm_expr__item *)NULL, i) + +/** Duplicate an expression. + * \param e expression + * \return Newly allocated expression identical to e. + */ +yasm_expr *yasm_expr_copy(const yasm_expr *e); +#ifndef YASM_DOXYGEN +#define yasm_expr_copy(e) yasm_expr__copy_except(e, -1) +#endif + +/** Destroy (free allocated memory for) an expression. + * \param e expression + */ +YASM_LIB_DECL +void yasm_expr_destroy(/*@only@*/ /*@null@*/ yasm_expr *e); + +/** Determine if an expression is a specified operation (at the top level). + * \param e expression + * \param op operator + * \return Nonzero if the expression was the specified operation at the top + * level, zero otherwise. + */ +YASM_LIB_DECL +int yasm_expr_is_op(const yasm_expr *e, yasm_expr_op op); + +/** Extra transformation function for yasm_expr__level_tree(). + * \param e expression being simplified + * \param d data provided as expr_xform_extra_data to + * yasm_expr__level_tree() + * \return Transformed e. + */ +typedef /*@only@*/ yasm_expr * (*yasm_expr_xform_func) + (/*@returned@*/ /*@only@*/ yasm_expr *e, /*@null@*/ void *d); + +/** Level an entire expression tree. + * \internal + * \param e expression + * \param fold_const enable constant folding if nonzero + * \param simplify_ident simplify identities + * \param simplify_reg_mul simplify REG*1 identities + * \param calc_bc_dist nonzero if distances between bytecodes should be + * calculated, 0 if they should be left intact + * \param expr_xform_extra extra transformation function + * \param expr_xform_extra_data data to pass to expr_xform_extra + * \return Leveled expression. + */ +YASM_LIB_DECL +/*@only@*/ /*@null@*/ yasm_expr *yasm_expr__level_tree + (/*@returned@*/ /*@only@*/ /*@null@*/ yasm_expr *e, int fold_const, + int simplify_ident, int simplify_reg_mul, int calc_bc_dist, + /*@null@*/ yasm_expr_xform_func expr_xform_extra, + /*@null@*/ void *expr_xform_extra_data); + +/** Simplify an expression as much as possible. Eliminates extraneous + * branches and simplifies integer-only subexpressions. Simplified version + * of yasm_expr__level_tree(). + * \param e expression + * \param cbd if distance between bytecodes should be calculated + * \return Simplified expression. + */ +#define yasm_expr_simplify(e, cbd) \ + yasm_expr__level_tree(e, 1, 1, 1, cbd, NULL, NULL) + +/** Extract the segment portion of an expression containing SEG:OFF, leaving + * the offset. + * \param ep expression (pointer to) + * \return NULL if unable to extract a segment (expr does not contain a + * YASM_EXPR_SEGOFF operator), otherwise the segment expression. + * The input expression is modified such that on return, it's the + * offset expression. + */ +YASM_LIB_DECL +/*@only@*/ /*@null@*/ yasm_expr *yasm_expr_extract_deep_segoff(yasm_expr **ep); + +/** Extract the segment portion of a SEG:OFF expression, leaving the offset. + * \param ep expression (pointer to) + * \return NULL if unable to extract a segment (YASM_EXPR_SEGOFF not the + * top-level operator), otherwise the segment expression. The input + * expression is modified such that on return, it's the offset + * expression. + */ +YASM_LIB_DECL +/*@only@*/ /*@null@*/ yasm_expr *yasm_expr_extract_segoff(yasm_expr **ep); + +/** Extract the right portion (y) of a x WRT y expression, leaving the left + * portion (x). + * \param ep expression (pointer to) + * \return NULL if unable to extract (YASM_EXPR_WRT not the top-level + * operator), otherwise the right side of the WRT expression. The + * input expression is modified such that on return, it's the left side + * of the WRT expression. + */ +YASM_LIB_DECL +/*@only@*/ /*@null@*/ yasm_expr *yasm_expr_extract_wrt(yasm_expr **ep); + +/** Get the integer value of an expression if it's just an integer. + * \param ep expression (pointer to) + * \param calc_bc_dist nonzero if distances between bytecodes should be + * calculated, 0 if NULL should be returned in this case + * \return NULL if the expression is too complex (contains anything other than + * integers, ie floats, non-valued labels, registers); otherwise the + * intnum value of the expression. + */ +YASM_LIB_DECL +/*@dependent@*/ /*@null@*/ yasm_intnum *yasm_expr_get_intnum + (yasm_expr **ep, int calc_bc_dist); + +/** Get the symbol value of an expression if it's just a symbol. + * \param ep expression (pointer to) + * \param simplify if nonzero, simplify the expression first + * \return NULL if the expression is too complex; otherwise the symbol value of + * the expression. + */ +YASM_LIB_DECL +/*@dependent@*/ /*@null@*/ const yasm_symrec *yasm_expr_get_symrec + (yasm_expr **ep, int simplify); + +/** Get the register value of an expression if it's just a register. + * \param ep expression (pointer to) + * \param simplify if nonzero, simplify the expression first + * \return NULL if the expression is too complex; otherwise the register value + * of the expression. + */ +YASM_LIB_DECL +/*@dependent@*/ /*@null@*/ const uintptr_t *yasm_expr_get_reg + (yasm_expr **ep, int simplify); + +/** Print an expression. For debugging purposes. + * \param e expression + * \param f file + */ +YASM_LIB_DECL +void yasm_expr_print(/*@null@*/ const yasm_expr *e, FILE *f); + +/** Return the size of an expression, if the user provided it + * \param e expression + */ +YASM_LIB_DECL +unsigned int yasm_expr_size(const yasm_expr *e); + +/** Return the segment of an expression, if the user provided it + * \param e expression + */ +YASM_LIB_DECL +const char *yasm_expr_segment(const yasm_expr *e); + +/** Traverse over expression tree in order (const version). + * Calls func for each leaf (non-operation). + * \param e expression + * \param d data passed to each call to func + * \param func callback function + * \return Stops early (and returns 1) if func returns 1. + * Otherwise returns 0. + */ +YASM_LIB_DECL +int yasm_expr__traverse_leaves_in_const + (const yasm_expr *e, /*@null@*/ void *d, + int (*func) (/*@null@*/ const yasm_expr__item *ei, /*@null@*/ void *d)); + +/** Traverse over expression tree in order. + * Calls func for each leaf (non-operation). + * \param e expression + * \param d data passed to each call to func + * \param func callback function + * \return Stops early (and returns 1) if func returns 1. + * Otherwise returns 0. + */ +YASM_LIB_DECL +int yasm_expr__traverse_leaves_in + (yasm_expr *e, /*@null@*/ void *d, + int (*func) (/*@null@*/ yasm_expr__item *ei, /*@null@*/ void *d)); + +/** Reorder terms of e into canonical order. Only reorders if reordering + * doesn't change meaning of expression. (eg, doesn't reorder SUB). + * Canonical order: REG, INT, FLOAT, SYM, EXPR. + * Multiple terms of a single type are kept in the same order as in + * the original expression. + * \param e expression + * \note Only performs reordering on *one* level (no recursion). + */ +YASM_LIB_DECL +void yasm_expr__order_terms(yasm_expr *e); + +/** Copy entire expression EXCEPT for index "except" at *top level only*. + * \param e expression + * \param except term index not to copy; -1 to copy all terms + * \return Newly allocated copy of expression. + */ +YASM_LIB_DECL +yasm_expr *yasm_expr__copy_except(const yasm_expr *e, int except); + +/** Test if expression contains an item. Searches recursively into + * subexpressions. + * \param e expression + * \param t type of item to look for + * \return Nonzero if expression contains an item of type t, zero if not. + */ +YASM_LIB_DECL +int yasm_expr__contains(const yasm_expr *e, yasm_expr__type t); + +/** Transform symrec-symrec terms in expression into #YASM_EXPR_SUBST items. + * Calls the callback function for each symrec-symrec term. + * \param ep expression (pointer to) + * \param cbd callback data passed to callback function + * \param callback callback function: given subst index for bytecode + * pair, bytecode pair (bc2-bc1), and cbd (callback data) + * \return Number of transformations made. + */ +YASM_LIB_DECL +int yasm_expr__bc_dist_subst(yasm_expr **ep, void *cbd, + void (*callback) (unsigned int subst, + yasm_bytecode *precbc, + yasm_bytecode *precbc2, + void *cbd)); + +/** Substitute items into expr YASM_EXPR_SUBST items (by index). Items are + * copied, so caller is responsible for freeing array of items. + * \param e expression + * \param num_items number of items in items array + * \param items items array + * \return 1 on error (index out of range). + */ +YASM_LIB_DECL +int yasm_expr__subst(yasm_expr *e, unsigned int num_items, + const yasm_expr__item *items); + +#endif diff --git a/contrib/tools/yasm/libyasm/file.c b/contrib/tools/yasm/libyasm/file.c new file mode 100644 index 0000000000..fc7dab6c17 --- /dev/null +++ b/contrib/tools/yasm/libyasm/file.c @@ -0,0 +1,672 @@ +/* + * File helper 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> + +/* Need either unistd.h or direct.h to prototype getcwd() and mkdir() */ +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + +#ifdef HAVE_DIRECT_H +#include <direct.h> +#endif + +#ifdef _WIN32 +#include <io.h> +#endif + +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif + +#include <ctype.h> +#include <errno.h> + +#include "errwarn.h" +#include "file.h" + +#define BSIZE 8192 /* Fill block size */ + + +void +yasm_scanner_initialize(yasm_scanner *s) +{ + s->bot = NULL; + s->tok = NULL; + s->ptr = NULL; + s->cur = NULL; + s->lim = NULL; + s->top = NULL; + s->eof = NULL; +} + +void +yasm_scanner_delete(yasm_scanner *s) +{ + if (s->bot) { + yasm_xfree(s->bot); + s->bot = NULL; + } +} + +int +yasm_fill_helper(yasm_scanner *s, unsigned char **cursor, + size_t (*input_func) (void *d, unsigned char *buf, + size_t max), + void *input_func_data) +{ + size_t cnt; + int first = 0; + + if (s->eof) + return 0; + + cnt = s->tok - s->bot; + if (cnt > 0) { + memmove(s->bot, s->tok, (size_t)(s->lim - s->tok)); + s->tok = s->bot; + s->ptr -= cnt; + *cursor -= cnt; + s->lim -= cnt; + } + if (!s->bot) + first = 1; + if ((s->top - s->lim) < BSIZE) { + unsigned char *buf = yasm_xmalloc((size_t)(s->lim - s->bot) + BSIZE); + memcpy(buf, s->tok, (size_t)(s->lim - s->tok)); + s->tok = buf; + s->ptr = &buf[s->ptr - s->bot]; + *cursor = &buf[*cursor - s->bot]; + s->lim = &buf[s->lim - s->bot]; + s->top = &s->lim[BSIZE]; + if (s->bot) + yasm_xfree(s->bot); + s->bot = buf; + } + if ((cnt = input_func(input_func_data, s->lim, BSIZE)) == 0) { + s->eof = &s->lim[cnt]; + *s->eof++ = '\n'; + } + s->lim += cnt; + return first; +} + +void +yasm_unescape_cstring(unsigned char *str, size_t *len) +{ + unsigned char *s = str; + unsigned char *o = str; + unsigned char t[4]; + + while ((size_t)(s-str)<*len) { + if (*s == '\\' && (size_t)(&s[1]-str)<*len) { + s++; + switch (*s) { + case 'b': *o = '\b'; s++; break; + case 'f': *o = '\f'; s++; break; + case 'n': *o = '\n'; s++; break; + case 'r': *o = '\r'; s++; break; + case 't': *o = '\t'; s++; break; + case 'x': + /* hex escape; grab last two digits */ + s++; + while ((size_t)(&s[2]-str)<*len && isxdigit(s[0]) + && isxdigit(s[1]) && isxdigit(s[2])) + s++; + if ((size_t)(s-str)<*len && isxdigit(*s)) { + t[0] = *s++; + t[1] = '\0'; + t[2] = '\0'; + if ((size_t)(s-str)<*len && isxdigit(*s)) + t[1] = *s++; + *o = (unsigned char)strtoul((char *)t, NULL, 16); + } else + *o = '\0'; + break; + default: + if (isdigit(*s)) { + int warn = 0; + /* octal escape */ + if (*s > '7') + warn = 1; + *o = *s++ - '0'; + if ((size_t)(s-str)<*len && isdigit(*s)) { + if (*s > '7') + warn = 1; + *o <<= 3; + *o += *s++ - '0'; + if ((size_t)(s-str)<*len && isdigit(*s)) { + if (*s > '7') + warn = 1; + *o <<= 3; + *o += *s++ - '0'; + } + } + if (warn) + yasm_warn_set(YASM_WARN_GENERAL, + N_("octal value out of range")); + } else + *o = *s++; + break; + } + o++; + } else + *o++ = *s++; + } + *len = o-str; +} + +size_t +yasm__splitpath_unix(const char *path, /*@out@*/ const char **tail) +{ + const char *s; + s = strrchr(path, '/'); + if (!s) { + /* No head */ + *tail = path; + return 0; + } + *tail = s+1; + /* Strip trailing ./ on path */ + while ((s-1)>=path && *(s-1) == '.' && *s == '/' + && !((s-2)>=path && *(s-2) == '.')) + s -= 2; + /* Strip trailing slashes on path (except leading) */ + while (s>path && *s == '/') + s--; + /* Return length of head */ + return s-path+1; +} + +size_t +yasm__splitpath_win(const char *path, /*@out@*/ const char **tail) +{ + const char *basepath = path; + const char *s; + + /* split off drive letter first, if any */ + if (isalpha(path[0]) && path[1] == ':') + basepath += 2; + + s = basepath; + while (*s != '\0') + s++; + while (s >= basepath && *s != '\\' && *s != '/') + s--; + if (s < basepath) { + *tail = basepath; + if (path == basepath) + return 0; /* No head */ + else + return 2; /* Drive letter is head */ + } + *tail = s+1; + /* Strip trailing .\ or ./ on path */ + while ((s-1)>=basepath && *(s-1) == '.' && (*s == '/' || *s == '\\') + && !((s-2)>=basepath && *(s-2) == '.')) + s -= 2; + /* Strip trailing slashes on path (except leading) */ + while (s>basepath && (*s == '/' || *s == '\\')) + s--; + /* Return length of head */ + return s-path+1; +} + +char * +yasm__getcwd(void) +{ + char *buf; + size_t size; + + size = 1024; + buf = yasm_xmalloc(size); + + if (getenv("YASM_TEST_SUITE")) { + strcpy(buf, "./"); + return buf; + } + + while (getcwd(buf, size-1) == NULL) { + if (errno != ERANGE) { + yasm__fatal(N_("could not determine current working directory")); + yasm_xfree(buf); + return NULL; + } + size *= 2; + buf = yasm_xrealloc(buf, size); + } + + /* append a '/' if not already present */ + size = strlen(buf); + if (buf[size-1] != '\\' && buf[size-1] != '/') { + buf[size] = '/'; + buf[size+1] = '\0'; + } + return buf; +} + +char * +yasm__abspath(const char *path) +{ + char *curdir, *abspath; + + curdir = yasm__getcwd(); + abspath = yasm__combpath(curdir, path); + yasm_xfree(curdir); + + return abspath; +} + +char * +yasm__combpath_unix(const char *from, const char *to) +{ + const char *tail; + size_t pathlen, i, j; + char *out; + + if (to[0] == '/') { + /* absolute "to" */ + out = yasm_xmalloc(strlen(to)+1); + /* Combine any double slashes when copying */ + for (j=0; *to; to++) { + if (*to == '/' && *(to+1) == '/') + continue; + out[j++] = *to; + } + out[j++] = '\0'; + return out; + } + + /* Get path component; note this strips trailing slash */ + pathlen = yasm__splitpath_unix(from, &tail); + + out = yasm_xmalloc(pathlen+strlen(to)+2); /* worst case maximum len */ + + /* Combine any double slashes when copying */ + for (i=0, j=0; i<pathlen; i++) { + if (i<pathlen-1 && from[i] == '/' && from[i+1] == '/') + continue; + out[j++] = from[i]; + } + pathlen = j; + + /* Add trailing slash back in */ + if (pathlen > 0 && out[pathlen-1] != '/') + out[pathlen++] = '/'; + + /* Now scan from left to right through "to", stripping off "." and ".."; + * if we see "..", back up one directory in out unless last directory in + * out is also "..". + * + * Note this does NOT back through ..'s in the "from" path; this is just + * as well as that could skip symlinks (e.g. "foo/bar/.." might not be + * the same as "foo"). + */ + for (;;) { + if (to[0] == '.' && to[1] == '/') { + to += 2; /* current directory */ + while (*to == '/') + to++; /* strip off any additional slashes */ + } else if (pathlen == 0) + break; /* no more "from" path left, we're done */ + else if (to[0] == '.' && to[1] == '.' && to[2] == '/') { + if (pathlen >= 3 && out[pathlen-1] == '/' && out[pathlen-2] == '.' + && out[pathlen-3] == '.') { + /* can't ".." against a "..", so we're done. */ + break; + } + + to += 3; /* throw away "../" */ + while (*to == '/') + to++; /* strip off any additional slashes */ + + /* and back out last directory in "out" if not already at root */ + if (pathlen > 1) { + pathlen--; /* strip off trailing '/' */ + while (pathlen > 0 && out[pathlen-1] != '/') + pathlen--; + } + } else + break; + } + + /* Copy "to" to tail of output, and we're done */ + /* Combine any double slashes when copying */ + for (j=pathlen; *to; to++) { + if (*to == '/' && *(to+1) == '/') + continue; + out[j++] = *to; + } + out[j++] = '\0'; + + return out; +} + +char * +yasm__combpath_win(const char *from, const char *to) +{ + const char *tail; + size_t pathlen, i, j; + char *out; + + if ((isalpha(to[0]) && to[1] == ':') || (to[0] == '/' || to[0] == '\\')) { + /* absolute or drive letter "to" */ + out = yasm_xmalloc(strlen(to)+1); + /* Combine any double slashes when copying */ + for (j=0; *to; to++) { + if ((*to == '/' || *to == '\\') + && (*(to+1) == '/' || *(to+1) == '\\')) + continue; + if (*to == '/') + out[j++] = '\\'; + else + out[j++] = *to; + } + out[j++] = '\0'; + return out; + } + + /* Get path component; note this strips trailing slash */ + pathlen = yasm__splitpath_win(from, &tail); + + out = yasm_xmalloc(pathlen+strlen(to)+2); /* worst case maximum len */ + + /* Combine any double slashes when copying */ + for (i=0, j=0; i<pathlen; i++) { + if (i<pathlen-1 && (from[i] == '/' || from[i] == '\\') + && (from[i+1] == '/' || from[i+1] == '\\')) + continue; + if (from[i] == '/') + out[j++] = '\\'; + else + out[j++] = from[i]; + } + pathlen = j; + + /* Add trailing slash back in, unless it's only a raw drive letter */ + if (pathlen > 0 && out[pathlen-1] != '\\' + && !(pathlen == 2 && isalpha(out[0]) && out[1] == ':')) + out[pathlen++] = '\\'; + + /* Now scan from left to right through "to", stripping off "." and ".."; + * if we see "..", back up one directory in out unless last directory in + * out is also "..". + * + * Note this does NOT back through ..'s in the "from" path; this is just + * as well as that could skip symlinks (e.g. "foo/bar/.." might not be + * the same as "foo"). + */ + for (;;) { + if (to[0] == '.' && (to[1] == '/' || to[1] == '\\')) { + to += 2; /* current directory */ + while (*to == '/' || *to == '\\') + to++; /* strip off any additional slashes */ + } else if (pathlen == 0 + || (pathlen == 2 && isalpha(out[0]) && out[1] == ':')) + break; /* no more "from" path left, we're done */ + else if (to[0] == '.' && to[1] == '.' + && (to[2] == '/' || to[2] == '\\')) { + if (pathlen >= 3 && out[pathlen-1] == '\\' + && out[pathlen-2] == '.' && out[pathlen-3] == '.') { + /* can't ".." against a "..", so we're done. */ + break; + } + + to += 3; /* throw away "../" (or "..\") */ + while (*to == '/' || *to == '\\') + to++; /* strip off any additional slashes */ + + /* and back out last directory in "out" if not already at root */ + if (pathlen > 1) { + pathlen--; /* strip off trailing '/' */ + while (pathlen > 0 && out[pathlen-1] != '\\') + pathlen--; + } + } else + break; + } + + /* Copy "to" to tail of output, and we're done */ + /* Combine any double slashes when copying */ + for (j=pathlen; *to; to++) { + if ((*to == '/' || *to == '\\') && (*(to+1) == '/' || *(to+1) == '\\')) + continue; + if (*to == '/') + out[j++] = '\\'; + else + out[j++] = *to; + } + out[j++] = '\0'; + + return out; +} + +size_t +yasm__createpath_common(const char *path, int win) +{ + const char *pp = path, *pe; + char *ts, *tp; + size_t len, lth; + + lth = len = strlen(path); + ts = tp = (char *) malloc(len + 1); + pe = pp + len; + while (pe > pp) { + if ((win && *pe == '\\') || *pe == '/') + break; + --pe; + --lth; + } + + while (pp <= pe) { + if (pp == pe || (win && *pp == '\\') || *pp == '/') { +#ifdef _WIN32 + struct _finddata_t fi; + intptr_t h; +#elif defined(HAVE_SYS_STAT_H) + struct stat fi; +#endif + *tp = '\0'; + +#ifdef _WIN32 + h = _findfirst(ts, &fi); + if (h != -1) { + if (fi.attrib != _A_SUBDIR) { + _findclose(h); + break; + } + } else if (errno == ENOENT) { + if (_mkdir(ts) == -1) { + _findclose(h); + lth = -1; + break; + } + } + _findclose(h); +#elif defined(HAVE_SYS_STAT_H) + if (stat(ts, &fi) != -1) { + if (!S_ISDIR(fi.st_mode)) + break; + } else if (errno == ENOENT) { + if (mkdir(ts, 0755) == -1) { + lth = 0; + break; + } + } +#else + break; +#endif + } + *tp++ = *pp++; + } + free(ts); + return lth; +} + +typedef struct incpath { + STAILQ_ENTRY(incpath) link; + /*@owned@*/ char *path; +} incpath; + +STAILQ_HEAD(incpath_head, incpath) incpaths = STAILQ_HEAD_INITIALIZER(incpaths); + +FILE * +yasm_fopen_include(const char *iname, const char *from, const char *mode, + char **oname) +{ + FILE *f; + char *combine; + incpath *np; + + /* Try directly relative to from first, then each of the include paths */ + if (from) { + combine = yasm__combpath(from, iname); + f = fopen(combine, mode); + if (f) { + if (oname) + *oname = combine; + else + yasm_xfree(combine); + return f; + } + yasm_xfree(combine); + } + + STAILQ_FOREACH(np, &incpaths, link) { + combine = yasm__combpath(np->path, iname); + f = fopen(combine, mode); + if (f) { + if (oname) + *oname = combine; + else + yasm_xfree(combine); + return f; + } + yasm_xfree(combine); + } + + if (oname) + *oname = NULL; + return NULL; +} + +void +yasm_delete_include_paths(void) +{ + incpath *n1, *n2; + + n1 = STAILQ_FIRST(&incpaths); + while (n1) { + n2 = STAILQ_NEXT(n1, link); + yasm_xfree(n1->path); + yasm_xfree(n1); + n1 = n2; + } + STAILQ_INIT(&incpaths); +} + +const char * +yasm_get_include_dir(void **iter) +{ + incpath *p = (incpath *)*iter; + + if (!p) + p = STAILQ_FIRST(&incpaths); + else + p = STAILQ_NEXT(p, link); + + *iter = p; + if (p) + return p->path; + else + return NULL; +} + +void +yasm_add_include_path(const char *path) +{ + incpath *np = yasm_xmalloc(sizeof(incpath)); + size_t len = strlen(path); + + np->path = yasm_xmalloc(len+2); + memcpy(np->path, path, len+1); + /* Add trailing slash if it is missing */ + if (path[len-1] != '\\' && path[len-1] != '/') { + np->path[len] = '/'; + np->path[len+1] = '\0'; + } + + STAILQ_INSERT_TAIL(&incpaths, np, link); +} + +size_t +yasm_fwrite_16_l(unsigned short val, FILE *f) +{ + if (fputc(val & 0xFF, f) == EOF) + return 0; + if (fputc((val >> 8) & 0xFF, f) == EOF) + return 0; + return 1; +} + +size_t +yasm_fwrite_32_l(unsigned long val, FILE *f) +{ + if (fputc((int)(val & 0xFF), f) == EOF) + return 0; + if (fputc((int)((val >> 8) & 0xFF), f) == EOF) + return 0; + if (fputc((int)((val >> 16) & 0xFF), f) == EOF) + return 0; + if (fputc((int)((val >> 24) & 0xFF), f) == EOF) + return 0; + return 1; +} + +size_t +yasm_fwrite_16_b(unsigned short val, FILE *f) +{ + if (fputc((val >> 8) & 0xFF, f) == EOF) + return 0; + if (fputc(val & 0xFF, f) == EOF) + return 0; + return 1; +} + +size_t +yasm_fwrite_32_b(unsigned long val, FILE *f) +{ + if (fputc((int)((val >> 24) & 0xFF), f) == EOF) + return 0; + if (fputc((int)((val >> 16) & 0xFF), f) == EOF) + return 0; + if (fputc((int)((val >> 8) & 0xFF), f) == EOF) + return 0; + if (fputc((int)(val & 0xFF), f) == EOF) + return 0; + return 1; +} diff --git a/contrib/tools/yasm/libyasm/file.h b/contrib/tools/yasm/libyasm/file.h new file mode 100644 index 0000000000..1e9b87b0d5 --- /dev/null +++ b/contrib/tools/yasm/libyasm/file.h @@ -0,0 +1,525 @@ +/** + * \file libyasm/file.h + * \brief YASM file helpers. + * + * \license + * 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: + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - 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. + * \endlicense + */ +#ifndef YASM_FILE_H +#define YASM_FILE_H + +#ifndef YASM_LIB_DECL +#define YASM_LIB_DECL +#endif + +/** Re2c scanner state. */ +typedef struct yasm_scanner { + unsigned char *bot; /**< Bottom of scan buffer */ + unsigned char *tok; /**< Start of token */ + unsigned char *ptr; /**< Scan marker */ + unsigned char *cur; /**< Cursor (1 past end of token) */ + unsigned char *lim; /**< Limit of good data */ + unsigned char *top; /**< Top of scan buffer */ + unsigned char *eof; /**< End of file */ +} yasm_scanner; + +/** Initialize scanner state. + * \param scanner Re2c scanner state + */ +YASM_LIB_DECL +void yasm_scanner_initialize(yasm_scanner *scanner); + +/** Frees any memory used by scanner state; does not free state itself. + * \param scanner Re2c scanner state + */ +YASM_LIB_DECL +void yasm_scanner_delete(yasm_scanner *scanner); + +/** Fill a scanner state structure with data coming from an input function. + * \param scanner Re2c scanner state + * \param cursor Re2c scan cursor + * \param input_func Input function to read data; takes buffer and maximum + * number of bytes, returns number of bytes read. + * \param input_func_data Data to pass as the first parameter to input_func + * \return 1 if this was the first time this function was called on this + * scanner state, 0 otherwise. + */ +YASM_LIB_DECL +int yasm_fill_helper + (yasm_scanner *scanner, unsigned char **cursor, + size_t (*input_func) (void *d, unsigned char *buf, size_t max), + void *input_func_data); + +/** Unescape a string with C-style escapes. Handles b, f, n, r, t, and hex + * and octal escapes. String is updated in-place. + * Edge cases: + * - hex escapes: reads as many hex digits as possible, takes last 2 as value. + * - oct escapes: takes up to 3 digits 0-9 and scales appropriately, with + * warning. + * \param str C-style string (updated in place) + * \param len length of string (updated with new length) + */ +YASM_LIB_DECL +void yasm_unescape_cstring(unsigned char *str, size_t *len); + +/** Split a UNIX pathname into head (directory) and tail (base filename) + * portions. + * \internal + * \param path pathname + * \param tail (returned) base filename + * \return Length of head (directory). + */ +YASM_LIB_DECL +size_t yasm__splitpath_unix(const char *path, /*@out@*/ const char **tail); + +/** Split a Windows pathname into head (directory) and tail (base filename) + * portions. + * \internal + * \param path pathname + * \param tail (returned) base filename + * \return Length of head (directory). + */ +YASM_LIB_DECL +size_t yasm__splitpath_win(const char *path, /*@out@*/ const char **tail); + +/** Split a pathname into head (directory) and tail (base filename) portions. + * Unless otherwise defined, defaults to yasm__splitpath_unix(). + * \internal + * \param path pathname + * \param tail (returned) base filename + * \return Length of head (directory). + */ +#ifndef yasm__splitpath +# if defined (_WIN32) || defined (WIN32) || defined (__MSDOS__) || \ + defined (__DJGPP__) || defined (__OS2__) +# define yasm__splitpath(path, tail) yasm__splitpath_win(path, tail) +# else +# define yasm__splitpath(path, tail) yasm__splitpath_unix(path, tail) +# endif +#endif + +/** Get the current working directory. + * \internal + * \return Current working directory pathname (newly allocated). + */ +YASM_LIB_DECL +/*@only@*/ char *yasm__getcwd(void); + +/** Convert a relative or absolute pathname into an absolute pathname. + * \internal + * \param path pathname + * \return Absolute version of path (newly allocated). + */ +YASM_LIB_DECL +/*@only@*/ char *yasm__abspath(const char *path); + +/** Build a UNIX pathname that is equivalent to accessing the "to" pathname + * when you're in the directory containing "from". Result is relative if both + * from and to are relative. + * \internal + * \param from from pathname + * \param to to pathname + * \return Combined path (newly allocated). + */ +YASM_LIB_DECL +char *yasm__combpath_unix(const char *from, const char *to); + +/** Build a Windows pathname that is equivalent to accessing the "to" pathname + * when you're in the directory containing "from". Result is relative if both + * from and to are relative. + * \internal + * \param from from pathname + * \param to to pathname + * \return Combined path (newly allocated). + */ +YASM_LIB_DECL +char *yasm__combpath_win(const char *from, const char *to); + +/** Build a pathname that is equivalent to accessing the "to" pathname + * when you're in the directory containing "from". Result is relative if both + * from and to are relative. + * Unless otherwise defined, defaults to yasm__combpath_unix(). + * \internal + * \param from from pathname + * \param to to pathname + * \return Combined path (newly allocated). + */ +#ifndef yasm__combpath +# if defined (_WIN32) || defined (WIN32) || defined (__MSDOS__) || \ + defined (__DJGPP__) || defined (__OS2__) +# define yasm__combpath(from, to) yasm__combpath_win(from, to) +# else +# define yasm__combpath(from, to) yasm__combpath_unix(from, to) +# endif +#endif + +/** Recursively create tree of directories needed for pathname. + * \internal + * \param path pathname + * \param win handle windows paths + * \return Length of directory portion of pathname. + */ +YASM_LIB_DECL +size_t yasm__createpath_common(const char *path, int win); + +/** Recursively create tree of directories needed for pathname. + * Unless otherwise defined, defaults to yasm__createpath_unix(). + * \internal + * \param path pathname + * \return Length of directory portion of pathname. + */ +#ifndef yasm__createpath +# if defined (_WIN32) || defined (WIN32) || defined (__MSDOS__) || \ + defined (__DJGPP__) || defined (__OS2__) +# define yasm__createpath(path) yasm__createpath_common(path, 1) +# else +# define yasm__createpath(path) yasm__createpath_common(path, 0) +# endif +#endif + +/** Try to find and open an include file, searching through include paths. + * First iname is looked for relative to the directory containing "from", then + * it's looked for relative to each of the include paths. + * + * All pathnames may be either absolute or relative; from, oname, and + * include paths, if relative, are relative from the current working directory. + * + * First match wins; the full pathname (newly allocated) to the opened file + * is saved into oname, and the fopen'ed FILE * is returned. If not found, + * NULL is returned. + * + * \param iname file to include + * \param from file doing the including + * \param mode fopen mode string + * \param oname full pathname of included file (may be relative). NULL + * may be passed if this is unwanted. + * \return fopen'ed include file, or NULL if not found. + */ +YASM_LIB_DECL +/*@null@*/ FILE *yasm_fopen_include + (const char *iname, const char *from, const char *mode, + /*@null@*/ /*@out@*/ /*@only@*/ char **oname); + +/** Delete any stored include paths added by yasm_add_include_path(). + */ +YASM_LIB_DECL +void yasm_delete_include_paths(void); + +/** Iterate through include paths. +*/ +YASM_LIB_DECL +const char * yasm_get_include_dir(void **iter); + +/** Add an include path for use by yasm_fopen_include(). + * If path is relative, it is treated by yasm_fopen_include() as relative to + * the current working directory. + * + * \param path path to add + */ +YASM_LIB_DECL +void yasm_add_include_path(const char *path); + +/** Write an 8-bit value to a buffer, incrementing buffer pointer. + * \note Only works properly if ptr is an (unsigned char *). + * \param ptr buffer + * \param val 8-bit value + */ +#define YASM_WRITE_8(ptr, val) \ + *((ptr)++) = (unsigned char)((val) & 0xFF) + +/** Write a 16-bit value to a buffer in little endian, incrementing buffer + * pointer. + * \note Only works properly if ptr is an (unsigned char *). + * \param ptr buffer + * \param val 16-bit value + */ +#define YASM_WRITE_16_L(ptr, val) \ + do { \ + *((ptr)++) = (unsigned char)((val) & 0xFF); \ + *((ptr)++) = (unsigned char)(((val) >> 8) & 0xFF); \ + } while (0) + +/** Write a 32-bit value to a buffer in little endian, incrementing buffer + * pointer. + * \note Only works properly if ptr is an (unsigned char *). + * \param ptr buffer + * \param val 32-bit value + */ +#define YASM_WRITE_32_L(ptr, val) \ + do { \ + *((ptr)++) = (unsigned char)((val) & 0xFF); \ + *((ptr)++) = (unsigned char)(((val) >> 8) & 0xFF); \ + *((ptr)++) = (unsigned char)(((val) >> 16) & 0xFF); \ + *((ptr)++) = (unsigned char)(((val) >> 24) & 0xFF); \ + } while (0) + +/** Write a 16-bit value to a buffer in big endian, incrementing buffer + * pointer. + * \note Only works properly if ptr is an (unsigned char *). + * \param ptr buffer + * \param val 16-bit value + */ +#define YASM_WRITE_16_B(ptr, val) \ + do { \ + *((ptr)++) = (unsigned char)(((val) >> 8) & 0xFF); \ + *((ptr)++) = (unsigned char)((val) & 0xFF); \ + } while (0) + +/** Write a 32-bit value to a buffer in big endian, incrementing buffer + * pointer. + * \note Only works properly if ptr is an (unsigned char *). + * \param ptr buffer + * \param val 32-bit value + */ +#define YASM_WRITE_32_B(ptr, val) \ + do { \ + *((ptr)++) = (unsigned char)(((val) >> 24) & 0xFF); \ + *((ptr)++) = (unsigned char)(((val) >> 16) & 0xFF); \ + *((ptr)++) = (unsigned char)(((val) >> 8) & 0xFF); \ + *((ptr)++) = (unsigned char)((val) & 0xFF); \ + } while (0) + + +/** Write an 8-bit value to a buffer. Does not increment buffer pointer. + * \note Only works properly if ptr is an (unsigned char *). + * \param ptr buffer + * \param val 8-bit value + */ +#define YASM_SAVE_8(ptr, val) \ + *(ptr) = (unsigned char)((val) & 0xFF) + +/** Write a 16-bit value to a buffer in little endian. Does not increment + * buffer pointer. + * \note Only works properly if ptr is an (unsigned char *). + * \param ptr buffer + * \param val 16-bit value + */ +#define YASM_SAVE_16_L(ptr, val) \ + do { \ + *(ptr) = (unsigned char)((val) & 0xFF); \ + *((ptr)+1) = (unsigned char)(((val) >> 8) & 0xFF); \ + } while (0) + +/** Write a 32-bit value to a buffer in little endian. Does not increment + * buffer pointer. + * \note Only works properly if ptr is an (unsigned char *). + * \param ptr buffer + * \param val 32-bit value + */ +#define YASM_SAVE_32_L(ptr, val) \ + do { \ + *(ptr) = (unsigned char)((val) & 0xFF); \ + *((ptr)+1) = (unsigned char)(((val) >> 8) & 0xFF); \ + *((ptr)+2) = (unsigned char)(((val) >> 16) & 0xFF); \ + *((ptr)+3) = (unsigned char)(((val) >> 24) & 0xFF); \ + } while (0) + +/** Write a 16-bit value to a buffer in big endian. Does not increment buffer + * pointer. + * \note Only works properly if ptr is an (unsigned char *). + * \param ptr buffer + * \param val 16-bit value + */ +#define YASM_SAVE_16_B(ptr, val) \ + do { \ + *(ptr) = (unsigned char)(((val) >> 8) & 0xFF); \ + *((ptr)+1) = (unsigned char)((val) & 0xFF); \ + } while (0) + +/** Write a 32-bit value to a buffer in big endian. Does not increment buffer + * pointer. + * \note Only works properly if ptr is an (unsigned char *). + * \param ptr buffer + * \param val 32-bit value + */ +#define YASM_SAVE_32_B(ptr, val) \ + do { \ + *(ptr) = (unsigned char)(((val) >> 24) & 0xFF); \ + *((ptr)+1) = (unsigned char)(((val) >> 16) & 0xFF); \ + *((ptr)+2) = (unsigned char)(((val) >> 8) & 0xFF); \ + *((ptr)+3) = (unsigned char)((val) & 0xFF); \ + } while (0) + +/** Direct-to-file version of YASM_SAVE_16_L(). + * \note Using the macro multiple times with a single fwrite() call will + * probably be faster than calling this function many times. + * \param val 16-bit value + * \param f file + * \return 1 if the write was successful, 0 if not (just like fwrite()). + */ +YASM_LIB_DECL +size_t yasm_fwrite_16_l(unsigned short val, FILE *f); + +/** Direct-to-file version of YASM_SAVE_32_L(). + * \note Using the macro multiple times with a single fwrite() call will + * probably be faster than calling this function many times. + * \param val 32-bit value + * \param f file + * \return 1 if the write was successful, 0 if not (just like fwrite()). + */ +YASM_LIB_DECL +size_t yasm_fwrite_32_l(unsigned long val, FILE *f); + +/** Direct-to-file version of YASM_SAVE_16_B(). + * \note Using the macro multiple times with a single fwrite() call will + * probably be faster than calling this function many times. + * \param val 16-bit value + * \param f file + * \return 1 if the write was successful, 0 if not (just like fwrite()). + */ +YASM_LIB_DECL +size_t yasm_fwrite_16_b(unsigned short val, FILE *f); + +/** Direct-to-file version of YASM_SAVE_32_B(). + * \note Using the macro multiple times with a single fwrite() call will + * probably be faster than calling this function many times. + * \param val 32-bit value + * \param f file + * \return 1 if the write was successful, 0 if not (just like fwrite()). + */ +YASM_LIB_DECL +size_t yasm_fwrite_32_b(unsigned long val, FILE *f); + +/** Read an 8-bit value from a buffer, incrementing buffer pointer. + * \note Only works properly if ptr is an (unsigned char *). + * \param ptr buffer + * \param val 8-bit value + */ +#define YASM_READ_8(val, ptr) \ + (val) = *((ptr)++) & 0xFF + +/** Read a 16-bit value from a buffer in little endian, incrementing buffer + * pointer. + * \note Only works properly if ptr is an (unsigned char *). + * \param ptr buffer + * \param val 16-bit value + */ +#define YASM_READ_16_L(val, ptr) \ + do { \ + (val) = *((ptr)++) & 0xFF; \ + (val) |= (*((ptr)++) & 0xFF) << 8; \ + } while (0) + +/** Read a 32-bit value from a buffer in little endian, incrementing buffer + * pointer. + * \note Only works properly if ptr is an (unsigned char *). + * \param ptr buffer + * \param val 32-bit value + */ +#define YASM_READ_32_L(val, ptr) \ + do { \ + (val) = *((ptr)++) & 0xFF; \ + (val) |= (*((ptr)++) & 0xFF) << 8; \ + (val) |= (*((ptr)++) & 0xFF) << 16; \ + (val) |= (*((ptr)++) & 0xFF) << 24; \ + } while (0) + +/** Read a 16-bit value from a buffer in big endian, incrementing buffer + * pointer. + * \note Only works properly if ptr is an (unsigned char *). + * \param ptr buffer + * \param val 16-bit value + */ +#define YASM_READ_16_B(val, ptr) \ + do { \ + (val) = (*((ptr)++) & 0xFF) << 8; \ + (val) |= *((ptr)++) & 0xFF; \ + } while (0) + +/** Read a 32-bit value from a buffer in big endian, incrementing buffer + * pointer. + * \note Only works properly if ptr is an (unsigned char *). + * \param ptr buffer + * \param val 32-bit value + */ +#define YASM_READ_32_B(val, ptr) \ + do { \ + (val) = (*((ptr)++) & 0xFF) << 24; \ + (val) |= (*((ptr)++) & 0xFF) << 16; \ + (val) |= (*((ptr)++) & 0xFF) << 8; \ + (val) |= *((ptr)++) & 0xFF; \ + } while (0) + +/** Read an 8-bit value from a buffer. Does not increment buffer pointer. + * \note Only works properly if ptr is an (unsigned char *). + * \param ptr buffer + * \param val 8-bit value + */ +#define YASM_LOAD_8(val, ptr) \ + (val) = *(ptr) & 0xFF + +/** Read a 16-bit value from a buffer in little endian. Does not increment + * buffer pointer. + * \note Only works properly if ptr is an (unsigned char *). + * \param ptr buffer + * \param val 16-bit value + */ +#define YASM_LOAD_16_L(val, ptr) \ + do { \ + (val) = *(ptr) & 0xFF; \ + (val) |= (*((ptr)+1) & 0xFF) << 8; \ + } while (0) + +/** Read a 32-bit value from a buffer in little endian. Does not increment + * buffer pointer. + * \note Only works properly if ptr is an (unsigned char *). + * \param ptr buffer + * \param val 32-bit value + */ +#define YASM_LOAD_32_L(val, ptr) \ + do { \ + (val) = (unsigned long)(*(ptr) & 0xFF); \ + (val) |= (unsigned long)((*((ptr)+1) & 0xFF) << 8); \ + (val) |= (unsigned long)((*((ptr)+2) & 0xFF) << 16); \ + (val) |= (unsigned long)((*((ptr)+3) & 0xFF) << 24); \ + } while (0) + +/** Read a 16-bit value from a buffer in big endian. Does not increment buffer + * pointer. + * \note Only works properly if ptr is an (unsigned char *). + * \param ptr buffer + * \param val 16-bit value + */ +#define YASM_LOAD_16_B(val, ptr) \ + do { \ + (val) = (*(ptr) & 0xFF) << 8; \ + (val) |= *((ptr)+1) & 0xFF; \ + } while (0) + +/** Read a 32-bit value from a buffer in big endian. Does not increment buffer + * pointer. + * \note Only works properly if ptr is an (unsigned char *). + * \param ptr buffer + * \param val 32-bit value + */ +#define YASM_LOAD_32_B(val, ptr) \ + do { \ + (val) = (unsigned long)((*(ptr) & 0xFF) << 24); \ + (val) |= (unsigned long)((*((ptr)+1) & 0xFF) << 16); \ + (val) |= (unsigned long)((*((ptr)+2) & 0xFF) << 8); \ + (val) |= (unsigned long)(*((ptr)+3) & 0xFF); \ + } while (0) + +#endif diff --git a/contrib/tools/yasm/libyasm/floatnum.c b/contrib/tools/yasm/libyasm/floatnum.c new file mode 100644 index 0000000000..ab67c2b2e4 --- /dev/null +++ b/contrib/tools/yasm/libyasm/floatnum.c @@ -0,0 +1,760 @@ +/* + * Floating point number functions. + * + * Copyright (C) 2001-2007 Peter Johnson + * + * Based on public-domain x86 assembly code by Randall Hyde (8/28/91). + * + * 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 <ctype.h> + +#include "coretype.h" +#include "bitvect.h" +#include "file.h" + +#include "errwarn.h" +#include "floatnum.h" + + +/* 97-bit internal floating point format: + * 0000000s eeeeeeee eeeeeeee m.....................................m + * Sign exponent mantissa (80 bits) + * 79 0 + * + * Only L.O. bit of Sign byte is significant. The rest is zero. + * Exponent is bias 32767. + * Mantissa does NOT have an implied one bit (it's explicit). + */ +struct yasm_floatnum { + /*@only@*/ wordptr mantissa; /* Allocated to MANT_BITS bits */ + unsigned short exponent; + unsigned char sign; + unsigned char flags; +}; + +/* constants describing parameters of internal floating point format */ +#define MANT_BITS 80 +#define MANT_BYTES 10 +#define MANT_SIGDIGITS 24 +#define EXP_BIAS 0x7FFF +#define EXP_INF 0xFFFF +#define EXP_MAX 0xFFFE +#define EXP_MIN 1 +#define EXP_ZERO 0 + +/* Flag settings for flags field */ +#define FLAG_ISZERO 1<<0 + +/* Note this structure integrates the floatnum structure */ +typedef struct POT_Entry_s { + yasm_floatnum f; + int dec_exponent; +} POT_Entry; + +/* "Source" for POT_Entry. */ +typedef struct POT_Entry_Source_s { + unsigned char mantissa[MANT_BYTES]; /* little endian mantissa */ + unsigned short exponent; /* Bias 32767 exponent */ +} POT_Entry_Source; + +/* Power of ten tables used by the floating point I/O routines. + * The POT_Table? arrays are built from the POT_Table?_Source arrays at + * runtime by POT_Table_Init(). + */ + +/* This table contains the powers of ten raised to negative powers of two: + * + * entry[12-n] = 10 ** (-2 ** n) for 0 <= n <= 12. + * entry[13] = 1.0 + */ +static /*@only@*/ POT_Entry *POT_TableN; +static POT_Entry_Source POT_TableN_Source[] = { + {{0xe3,0x2d,0xde,0x9f,0xce,0xd2,0xc8,0x04,0xdd,0xa6},0x4ad8}, /* 1e-4096 */ + {{0x25,0x49,0xe4,0x2d,0x36,0x34,0x4f,0x53,0xae,0xce},0x656b}, /* 1e-2048 */ + {{0xa6,0x87,0xbd,0xc0,0x57,0xda,0xa5,0x82,0xa6,0xa2},0x72b5}, /* 1e-1024 */ + {{0x33,0x71,0x1c,0xd2,0x23,0xdb,0x32,0xee,0x49,0x90},0x795a}, /* 1e-512 */ + {{0x91,0xfa,0x39,0x19,0x7a,0x63,0x25,0x43,0x31,0xc0},0x7cac}, /* 1e-256 */ + {{0x7d,0xac,0xa0,0xe4,0xbc,0x64,0x7c,0x46,0xd0,0xdd},0x7e55}, /* 1e-128 */ + {{0x24,0x3f,0xa5,0xe9,0x39,0xa5,0x27,0xea,0x7f,0xa8},0x7f2a}, /* 1e-64 */ + {{0xde,0x67,0xba,0x94,0x39,0x45,0xad,0x1e,0xb1,0xcf},0x7f94}, /* 1e-32 */ + {{0x2f,0x4c,0x5b,0xe1,0x4d,0xc4,0xbe,0x94,0x95,0xe6},0x7fc9}, /* 1e-16 */ + {{0xc2,0xfd,0xfc,0xce,0x61,0x84,0x11,0x77,0xcc,0xab},0x7fe4}, /* 1e-8 */ + {{0xc3,0xd3,0x2b,0x65,0x19,0xe2,0x58,0x17,0xb7,0xd1},0x7ff1}, /* 1e-4 */ + {{0x71,0x3d,0x0a,0xd7,0xa3,0x70,0x3d,0x0a,0xd7,0xa3},0x7ff8}, /* 1e-2 */ + {{0xcd,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc},0x7ffb}, /* 1e-1 */ + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80},0x7fff}, /* 1e-0 */ +}; + +/* This table contains the powers of ten raised to positive powers of two: + * + * entry[12-n] = 10 ** (2 ** n) for 0 <= n <= 12. + * entry[13] = 1.0 + * entry[-1] = entry[0]; + * + * There is a -1 entry since it is possible for the algorithm to back up + * before the table. This -1 entry is created at runtime by duplicating the + * 0 entry. + */ +static /*@only@*/ POT_Entry *POT_TableP; +static POT_Entry_Source POT_TableP_Source[] = { + {{0x4c,0xc9,0x9a,0x97,0x20,0x8a,0x02,0x52,0x60,0xc4},0xb525}, /* 1e+4096 */ + {{0x4d,0xa7,0xe4,0x5d,0x3d,0xc5,0x5d,0x3b,0x8b,0x9e},0x9a92}, /* 1e+2048 */ + {{0x0d,0x65,0x17,0x0c,0x75,0x81,0x86,0x75,0x76,0xc9},0x8d48}, /* 1e+1024 */ + {{0x65,0xcc,0xc6,0x91,0x0e,0xa6,0xae,0xa0,0x19,0xe3},0x86a3}, /* 1e+512 */ + {{0xbc,0xdd,0x8d,0xde,0xf9,0x9d,0xfb,0xeb,0x7e,0xaa},0x8351}, /* 1e+256 */ + {{0x6f,0xc6,0xdf,0x8c,0xe9,0x80,0xc9,0x47,0xba,0x93},0x81a8}, /* 1e+128 */ + {{0xbf,0x3c,0xd5,0xa6,0xcf,0xff,0x49,0x1f,0x78,0xc2},0x80d3}, /* 1e+64 */ + {{0x20,0xf0,0x9d,0xb5,0x70,0x2b,0xa8,0xad,0xc5,0x9d},0x8069}, /* 1e+32 */ + {{0x00,0x00,0x00,0x00,0x00,0x04,0xbf,0xc9,0x1b,0x8e},0x8034}, /* 1e+16 */ + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0xbc,0xbe},0x8019}, /* 1e+8 */ + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x9c},0x800c}, /* 1e+4 */ + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc8},0x8005}, /* 1e+2 */ + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0},0x8002}, /* 1e+1 */ + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80},0x7fff}, /* 1e+0 */ +}; + + +static void +POT_Table_Init_Entry(/*@out@*/ POT_Entry *e, POT_Entry_Source *s, int dec_exp) +{ + /* Save decimal exponent */ + e->dec_exponent = dec_exp; + + /* Initialize mantissa */ + e->f.mantissa = BitVector_Create(MANT_BITS, FALSE); + BitVector_Block_Store(e->f.mantissa, s->mantissa, MANT_BYTES); + + /* Initialize exponent */ + e->f.exponent = s->exponent; + + /* Set sign to 0 (positive) */ + e->f.sign = 0; + + /* Clear flags */ + e->f.flags = 0; +} + +/*@-compdef@*/ +void +yasm_floatnum_initialize(void) +/*@globals undef POT_TableN, undef POT_TableP, POT_TableP_Source, + POT_TableN_Source @*/ +{ + int dec_exp = 1; + int i; + + /* Allocate space for two POT tables */ + POT_TableN = yasm_xmalloc(14*sizeof(POT_Entry)); + POT_TableP = yasm_xmalloc(15*sizeof(POT_Entry)); /* note 1 extra for -1 */ + + /* Initialize entry[0..12] */ + for (i=12; i>=0; i--) { + POT_Table_Init_Entry(&POT_TableN[i], &POT_TableN_Source[i], 0-dec_exp); + POT_Table_Init_Entry(&POT_TableP[i+1], &POT_TableP_Source[i], dec_exp); + dec_exp *= 2; /* Update decimal exponent */ + } + + /* Initialize entry[13] */ + POT_Table_Init_Entry(&POT_TableN[13], &POT_TableN_Source[13], 0); + POT_Table_Init_Entry(&POT_TableP[14], &POT_TableP_Source[13], 0); + + /* Initialize entry[-1] for POT_TableP */ + POT_Table_Init_Entry(&POT_TableP[0], &POT_TableP_Source[0], 4096); + + /* Offset POT_TableP so that [0] becomes [-1] */ + POT_TableP++; +} +/*@=compdef@*/ + +/*@-globstate@*/ +void +yasm_floatnum_cleanup(void) +{ + int i; + + /* Un-offset POT_TableP */ + POT_TableP--; + + for (i=0; i<14; i++) { + BitVector_Destroy(POT_TableN[i].f.mantissa); + BitVector_Destroy(POT_TableP[i].f.mantissa); + } + BitVector_Destroy(POT_TableP[14].f.mantissa); + + yasm_xfree(POT_TableN); + yasm_xfree(POT_TableP); +} +/*@=globstate@*/ + +static void +floatnum_normalize(yasm_floatnum *flt) +{ + long norm_amt; + + if (BitVector_is_empty(flt->mantissa)) { + flt->exponent = 0; + return; + } + + /* Look for the highest set bit, shift to make it the MSB, and adjust + * exponent. Don't let exponent go negative. */ + norm_amt = (MANT_BITS-1)-Set_Max(flt->mantissa); + if (norm_amt > (long)flt->exponent) + norm_amt = (long)flt->exponent; + BitVector_Move_Left(flt->mantissa, (N_int)norm_amt); + flt->exponent -= (unsigned short)norm_amt; +} + +/* acc *= op */ +static void +floatnum_mul(yasm_floatnum *acc, const yasm_floatnum *op) +{ + long expon; + wordptr product, op1, op2; + long norm_amt; + + /* Compute the new sign */ + acc->sign ^= op->sign; + + /* Check for multiply by 0 */ + if (BitVector_is_empty(acc->mantissa) || BitVector_is_empty(op->mantissa)) { + BitVector_Empty(acc->mantissa); + acc->exponent = EXP_ZERO; + return; + } + + /* Add exponents, checking for overflow/underflow. */ + expon = (((int)acc->exponent)-EXP_BIAS) + (((int)op->exponent)-EXP_BIAS); + expon += EXP_BIAS; + if (expon > EXP_MAX) { + /* Overflow; return infinity. */ + BitVector_Empty(acc->mantissa); + acc->exponent = EXP_INF; + return; + } else if (expon < EXP_MIN) { + /* Underflow; return zero. */ + BitVector_Empty(acc->mantissa); + acc->exponent = EXP_ZERO; + return; + } + + /* Add one to the final exponent, as the multiply shifts one extra time. */ + acc->exponent = (unsigned short)(expon+1); + + /* Allocate space for the multiply result */ + product = BitVector_Create((N_int)((MANT_BITS+1)*2), FALSE); + + /* Allocate 1-bit-longer fields to force the operands to be unsigned */ + op1 = BitVector_Create((N_int)(MANT_BITS+1), FALSE); + op2 = BitVector_Create((N_int)(MANT_BITS+1), FALSE); + + /* Make the operands unsigned after copying from original operands */ + BitVector_Copy(op1, acc->mantissa); + BitVector_MSB(op1, 0); + BitVector_Copy(op2, op->mantissa); + BitVector_MSB(op2, 0); + + /* Compute the product of the mantissas */ + BitVector_Multiply(product, op1, op2); + + /* Normalize the product. Note: we know the product is non-zero because + * both of the original operands were non-zero. + * + * Look for the highest set bit, shift to make it the MSB, and adjust + * exponent. Don't let exponent go negative. + */ + norm_amt = (MANT_BITS*2-1)-Set_Max(product); + if (norm_amt > (long)acc->exponent) + norm_amt = (long)acc->exponent; + BitVector_Move_Left(product, (N_int)norm_amt); + acc->exponent -= (unsigned short)norm_amt; + + /* Store the highest bits of the result */ + BitVector_Interval_Copy(acc->mantissa, product, 0, MANT_BITS, MANT_BITS); + + /* Free allocated variables */ + BitVector_Destroy(product); + BitVector_Destroy(op1); + BitVector_Destroy(op2); +} + +yasm_floatnum * +yasm_floatnum_create(const char *str) +{ + yasm_floatnum *flt; + int dec_exponent, dec_exp_add; /* decimal (powers of 10) exponent */ + int POT_index; + wordptr operand[2]; + int sig_digits; + int decimal_pt; + boolean carry; + + flt = yasm_xmalloc(sizeof(yasm_floatnum)); + + flt->mantissa = BitVector_Create(MANT_BITS, TRUE); + + /* allocate and initialize calculation variables */ + operand[0] = BitVector_Create(MANT_BITS, TRUE); + operand[1] = BitVector_Create(MANT_BITS, TRUE); + dec_exponent = 0; + sig_digits = 0; + decimal_pt = 1; + + /* set initial flags to 0 */ + flt->flags = 0; + + /* check for + or - character and skip */ + if (*str == '-') { + flt->sign = 1; + str++; + } else if (*str == '+') { + flt->sign = 0; + str++; + } else + flt->sign = 0; + + /* eliminate any leading zeros (which do not count as significant digits) */ + while (*str == '0') + str++; + + /* When we reach the end of the leading zeros, first check for a decimal + * point. If the number is of the form "0---0.0000" we need to get rid + * of the zeros after the decimal point and not count them as significant + * digits. + */ + if (*str == '.') { + str++; + while (*str == '0') { + str++; + dec_exponent--; + } + } else { + /* The number is of the form "yyy.xxxx" (where y <> 0). */ + while (isdigit(*str)) { + /* See if we've processed more than the max significant digits: */ + if (sig_digits < MANT_SIGDIGITS) { + /* Multiply mantissa by 10 [x = (x<<1)+(x<<3)] */ + BitVector_shift_left(flt->mantissa, 0); + BitVector_Copy(operand[0], flt->mantissa); + BitVector_Move_Left(flt->mantissa, 2); + carry = 0; + BitVector_add(operand[1], operand[0], flt->mantissa, &carry); + + /* Add in current digit */ + BitVector_Empty(operand[0]); + BitVector_Chunk_Store(operand[0], 4, 0, (N_long)(*str-'0')); + carry = 0; + BitVector_add(flt->mantissa, operand[1], operand[0], &carry); + } else { + /* Can't integrate more digits with mantissa, so instead just + * raise by a power of ten. + */ + dec_exponent++; + } + sig_digits++; + str++; + } + + if (*str == '.') + str++; + else + decimal_pt = 0; + } + + if (decimal_pt) { + /* Process the digits to the right of the decimal point. */ + while (isdigit(*str)) { + /* See if we've processed more than 19 significant digits: */ + if (sig_digits < 19) { + /* Raise by a power of ten */ + dec_exponent--; + + /* Multiply mantissa by 10 [x = (x<<1)+(x<<3)] */ + BitVector_shift_left(flt->mantissa, 0); + BitVector_Copy(operand[0], flt->mantissa); + BitVector_Move_Left(flt->mantissa, 2); + carry = 0; + BitVector_add(operand[1], operand[0], flt->mantissa, &carry); + + /* Add in current digit */ + BitVector_Empty(operand[0]); + BitVector_Chunk_Store(operand[0], 4, 0, (N_long)(*str-'0')); + carry = 0; + BitVector_add(flt->mantissa, operand[1], operand[0], &carry); + } + sig_digits++; + str++; + } + } + + if (*str == 'e' || *str == 'E') { + str++; + /* We just saw the "E" character, now read in the exponent value and + * add it into dec_exponent. + */ + dec_exp_add = 0; + sscanf(str, "%d", &dec_exp_add); + dec_exponent += dec_exp_add; + } + + /* Free calculation variables. */ + BitVector_Destroy(operand[1]); + BitVector_Destroy(operand[0]); + + /* Normalize the number, checking for 0 first. */ + if (BitVector_is_empty(flt->mantissa)) { + /* Mantissa is 0, zero exponent too. */ + flt->exponent = 0; + /* Set zero flag so output functions don't see 0 value as underflow. */ + flt->flags |= FLAG_ISZERO; + /* Return 0 value. */ + return flt; + } + /* Exponent if already norm. */ + flt->exponent = (unsigned short)(0x7FFF+(MANT_BITS-1)); + floatnum_normalize(flt); + + /* The number is normalized. Now multiply by 10 the number of times + * specified in DecExponent. This uses the power of ten tables to speed + * up this operation (and make it more accurate). + */ + if (dec_exponent > 0) { + POT_index = 0; + /* Until we hit 1.0 or finish exponent or overflow */ + while ((POT_index < 14) && (dec_exponent != 0) && + (flt->exponent != EXP_INF)) { + /* Find the first power of ten in the table which is just less than + * the exponent. + */ + while (dec_exponent < POT_TableP[POT_index].dec_exponent) + POT_index++; + + if (POT_index < 14) { + /* Subtract out what we're multiplying in from exponent */ + dec_exponent -= POT_TableP[POT_index].dec_exponent; + + /* Multiply by current power of 10 */ + floatnum_mul(flt, &POT_TableP[POT_index].f); + } + } + } else if (dec_exponent < 0) { + POT_index = 0; + /* Until we hit 1.0 or finish exponent or underflow */ + while ((POT_index < 14) && (dec_exponent != 0) && + (flt->exponent != EXP_ZERO)) { + /* Find the first power of ten in the table which is just less than + * the exponent. + */ + while (dec_exponent > POT_TableN[POT_index].dec_exponent) + POT_index++; + + if (POT_index < 14) { + /* Subtract out what we're multiplying in from exponent */ + dec_exponent -= POT_TableN[POT_index].dec_exponent; + + /* Multiply by current power of 10 */ + floatnum_mul(flt, &POT_TableN[POT_index].f); + } + } + } + + /* Round the result. (Don't round underflow or overflow). Also don't + * increment if this would cause the mantissa to wrap. + */ + if ((flt->exponent != EXP_INF) && (flt->exponent != EXP_ZERO) && + !BitVector_is_full(flt->mantissa)) + BitVector_increment(flt->mantissa); + + return flt; +} + +yasm_floatnum * +yasm_floatnum_copy(const yasm_floatnum *flt) +{ + yasm_floatnum *f = yasm_xmalloc(sizeof(yasm_floatnum)); + + f->mantissa = BitVector_Clone(flt->mantissa); + f->exponent = flt->exponent; + f->sign = flt->sign; + f->flags = flt->flags; + + return f; +} + +void +yasm_floatnum_destroy(yasm_floatnum *flt) +{ + BitVector_Destroy(flt->mantissa); + yasm_xfree(flt); +} + +int +yasm_floatnum_calc(yasm_floatnum *acc, yasm_expr_op op, + /*@unused@*/ yasm_floatnum *operand) +{ + if (op != YASM_EXPR_NEG) { + yasm_error_set(YASM_ERROR_FLOATING_POINT, + N_("Unsupported floating-point arithmetic operation")); + return 1; + } + acc->sign ^= 1; + return 0; +} + +int +yasm_floatnum_get_int(const yasm_floatnum *flt, unsigned long *ret_val) +{ + unsigned char t[4]; + + if (yasm_floatnum_get_sized(flt, t, 4, 32, 0, 0, 0)) { + *ret_val = 0xDEADBEEFUL; /* Obviously incorrect return value */ + return 1; + } + + YASM_LOAD_32_L(*ret_val, &t[0]); + return 0; +} + +/* Function used by conversion routines to actually perform the conversion. + * + * ptr -> the array to return the little-endian floating point value into. + * flt -> the floating point value to convert. + * byte_size -> the size in bytes of the output format. + * mant_bits -> the size in bits of the output mantissa. + * implicit1 -> does the output format have an implicit 1? 1=yes, 0=no. + * exp_bits -> the size in bits of the output exponent. + * + * Returns 0 on success, 1 if overflow, -1 if underflow. + */ +static int +floatnum_get_common(const yasm_floatnum *flt, /*@out@*/ unsigned char *ptr, + N_int byte_size, N_int mant_bits, int implicit1, + N_int exp_bits) +{ + long exponent = (long)flt->exponent; + wordptr output; + charptr buf; + unsigned int len; + unsigned int overflow = 0, underflow = 0; + int retval = 0; + long exp_bias = (1<<(exp_bits-1))-1; + long exp_inf = (1<<exp_bits)-1; + + output = BitVector_Create(byte_size*8, TRUE); + + /* copy mantissa */ + BitVector_Interval_Copy(output, flt->mantissa, 0, + (N_int)((MANT_BITS-implicit1)-mant_bits), + mant_bits); + + /* round mantissa */ + if (BitVector_bit_test(flt->mantissa, (MANT_BITS-implicit1)-(mant_bits+1))) + BitVector_increment(output); + + if (BitVector_bit_test(output, mant_bits)) { + /* overflowed, so zero mantissa (and set explicit bit if necessary) */ + BitVector_Empty(output); + BitVector_Bit_Copy(output, mant_bits-1, !implicit1); + /* and up the exponent (checking for overflow) */ + if (exponent+1 >= EXP_INF) + overflow = 1; + else + exponent++; + } + + /* adjust the exponent to the output bias, checking for overflow */ + exponent -= EXP_BIAS-exp_bias; + if (exponent >= exp_inf) + overflow = 1; + else if (exponent <= 0) + underflow = 1; + + /* underflow and overflow both set!? */ + if (underflow && overflow) + yasm_internal_error(N_("Both underflow and overflow set")); + + /* check for underflow or overflow and set up appropriate output */ + if (underflow) { + BitVector_Empty(output); + exponent = 0; + if (!(flt->flags & FLAG_ISZERO)) + retval = -1; + } else if (overflow) { + BitVector_Empty(output); + exponent = exp_inf; + retval = 1; + } + + /* move exponent into place */ + BitVector_Chunk_Store(output, exp_bits, mant_bits, (N_long)exponent); + + /* merge in sign bit */ + BitVector_Bit_Copy(output, byte_size*8-1, flt->sign); + + /* get little-endian bytes */ + buf = BitVector_Block_Read(output, &len); + if (len < byte_size) + yasm_internal_error( + N_("Byte length of BitVector does not match bit length")); + + /* copy to output */ + memcpy(ptr, buf, byte_size*sizeof(unsigned char)); + + /* free allocated resources */ + yasm_xfree(buf); + + BitVector_Destroy(output); + + return retval; +} + +/* IEEE-754r "half precision" format: + * 16 bits: + * 15 9 Bit 0 + * | | | + * seee eemm mmmm mmmm + * + * e = bias 15 exponent + * s = sign bit + * m = mantissa bits, bit 10 is an implied one bit. + * + * IEEE-754 (Intel) "single precision" format: + * 32 bits: + * Bit 31 Bit 22 Bit 0 + * | | | + * seeeeeee emmmmmmm mmmmmmmm mmmmmmmm + * + * e = bias 127 exponent + * s = sign bit + * m = mantissa bits, bit 23 is an implied one bit. + * + * IEEE-754 (Intel) "double precision" format: + * 64 bits: + * bit 63 bit 51 bit 0 + * | | | + * seeeeeee eeeemmmm mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm + * + * e = bias 1023 exponent. + * s = sign bit. + * m = mantissa bits. Bit 52 is an implied one bit. + * + * IEEE-754 (Intel) "extended precision" format: + * 80 bits: + * bit 79 bit 63 bit 0 + * | | | + * seeeeeee eeeeeeee mmmmmmmm m...m m...m m...m m...m m...m + * + * e = bias 16383 exponent + * m = 64 bit mantissa with NO implied bit! + * s = sign (for mantissa) + */ +int +yasm_floatnum_get_sized(const yasm_floatnum *flt, unsigned char *ptr, + size_t destsize, size_t valsize, size_t shift, + int bigendian, int warn) +{ + int retval; + if (destsize*8 != valsize || shift>0 || bigendian) { + /* TODO */ + yasm_internal_error(N_("unsupported floatnum functionality")); + } + switch (destsize) { + case 2: + retval = floatnum_get_common(flt, ptr, 2, 10, 1, 5); + break; + case 4: + retval = floatnum_get_common(flt, ptr, 4, 23, 1, 8); + break; + case 8: + retval = floatnum_get_common(flt, ptr, 8, 52, 1, 11); + break; + case 10: + retval = floatnum_get_common(flt, ptr, 10, 64, 0, 15); + break; + default: + yasm_internal_error(N_("Invalid float conversion size")); + /*@notreached@*/ + return 1; + } + if (warn) { + if (retval < 0) + yasm_warn_set(YASM_WARN_GENERAL, + N_("underflow in floating point expression")); + else if (retval > 0) + yasm_warn_set(YASM_WARN_GENERAL, + N_("overflow in floating point expression")); + } + return retval; +} + +/* 1 if the size is valid, 0 if it isn't */ +int +yasm_floatnum_check_size(/*@unused@*/ const yasm_floatnum *flt, size_t size) +{ + switch (size) { + case 16: + case 32: + case 64: + case 80: + return 1; + default: + return 0; + } +} + +void +yasm_floatnum_print(const yasm_floatnum *flt, FILE *f) +{ + unsigned char out[10]; + unsigned char *str; + int i; + + /* Internal format */ + str = BitVector_to_Hex(flt->mantissa); + fprintf(f, "%c %s *2^%04x\n", flt->sign?'-':'+', (char *)str, + flt->exponent); + yasm_xfree(str); + + /* 32-bit (single precision) format */ + fprintf(f, "32-bit: %d: ", + yasm_floatnum_get_sized(flt, out, 4, 32, 0, 0, 0)); + for (i=0; i<4; i++) + fprintf(f, "%02x ", out[i]); + fprintf(f, "\n"); + + /* 64-bit (double precision) format */ + fprintf(f, "64-bit: %d: ", + yasm_floatnum_get_sized(flt, out, 8, 64, 0, 0, 0)); + for (i=0; i<8; i++) + fprintf(f, "%02x ", out[i]); + fprintf(f, "\n"); + + /* 80-bit (extended precision) format */ + fprintf(f, "80-bit: %d: ", + yasm_floatnum_get_sized(flt, out, 10, 80, 0, 0, 0)); + for (i=0; i<10; i++) + fprintf(f, "%02x ", out[i]); + fprintf(f, "\n"); +} diff --git a/contrib/tools/yasm/libyasm/floatnum.h b/contrib/tools/yasm/libyasm/floatnum.h new file mode 100644 index 0000000000..d2c7042097 --- /dev/null +++ b/contrib/tools/yasm/libyasm/floatnum.h @@ -0,0 +1,131 @@ +/** + * \file libyasm/floatnum.h + * \brief YASM floating point (IEEE) interface. + * + * \license + * Copyright (C) 2001-2007 Peter Johnson + * + * Based on public-domain x86 assembly code by Randall Hyde (8/28/91). + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - 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. + * \endlicense + */ +#ifndef YASM_FLOATNUM_H +#define YASM_FLOATNUM_H + +#ifndef YASM_LIB_DECL +#define YASM_LIB_DECL +#endif + +/** Initialize floatnum internal data structures. */ +YASM_LIB_DECL +void yasm_floatnum_initialize(void); + +/** Clean up internal floatnum allocations. */ +YASM_LIB_DECL +void yasm_floatnum_cleanup(void); + +/** Create a new floatnum from a decimal string. The input string must be in + * standard C representation ([+-]123.456e[-+]789). + * \param str floating point decimal string + * \return Newly allocated floatnum. + */ +YASM_LIB_DECL +/*@only@*/ yasm_floatnum *yasm_floatnum_create(const char *str); + +/** Duplicate a floatnum. + * \param flt floatnum + * \return Newly allocated floatnum with the same value as flt. + */ +YASM_LIB_DECL +/*@only@*/ yasm_floatnum *yasm_floatnum_copy(const yasm_floatnum *flt); + +/** Destroy (free allocated memory for) a floatnum. + * \param flt floatnum + */ +YASM_LIB_DECL +void yasm_floatnum_destroy(/*@only@*/ yasm_floatnum *flt); + +/** Floating point calculation function: acc = acc op operand. + * \note Not all operations in yasm_expr_op may be supported; unsupported + * operations will result in an error. + * \param acc floatnum accumulator + * \param op operation + * \param operand floatnum operand + * \return Nonzero on error. + */ +YASM_LIB_DECL +int yasm_floatnum_calc(yasm_floatnum *acc, yasm_expr_op op, + yasm_floatnum *operand); + +/** Convert a floatnum to single-precision and return as 32-bit value. + * The 32-bit value is a "standard" C value (eg, of unknown endian). + * \param flt floatnum + * \param ret_val pointer to storage for 32-bit output + * \return Nonzero if flt can't fit into single precision: -1 if underflow + * occurred, 1 if overflow occurred. + */ +YASM_LIB_DECL +int yasm_floatnum_get_int(const yasm_floatnum *flt, + /*@out@*/ unsigned long *ret_val); + +/** Output a #yasm_floatnum to buffer in little-endian or big-endian. Puts the + * value into the least significant bits of the destination, or may be shifted + * into more significant bits by the shift parameter. The destination bits are + * cleared before being set. [0] should be the first byte output to the file. + * \note Not all sizes are valid. Currently, only 32 (single-precision), 64 + * (double-precision), and 80 (extended-precision) are valid sizes. + * Use yasm_floatnum_check_size() to check for supported sizes. + * \param flt floatnum + * \param ptr pointer to storage for size bytes of output + * \param destsize destination size (in bytes) + * \param valsize size (in bits) + * \param shift left shift (in bits) + * \param bigendian endianness (nonzero=big, zero=little) + * \param warn enables standard overflow/underflow warnings + * \return Nonzero if flt can't fit into the specified precision: -1 if + * underflow occurred, 1 if overflow occurred. + */ +YASM_LIB_DECL +int yasm_floatnum_get_sized(const yasm_floatnum *flt, unsigned char *ptr, + size_t destsize, size_t valsize, size_t shift, + int bigendian, int warn); + +/** Basic check to see if size is valid for flt conversion (using + * yasm_floatnum_get_sized()). Doesn't actually check for underflow/overflow + * but rather checks for size=32,64,80 + * (at present). + * \param flt floatnum + * \param size number of bits of output space + * \return 1 if valid size, 0 if invalid size. + */ +YASM_LIB_DECL +int yasm_floatnum_check_size(const yasm_floatnum *flt, size_t size); + +/** Print various representations of a floatnum. For debugging purposes only. + * \param f file + * \param flt floatnum + */ +YASM_LIB_DECL +void yasm_floatnum_print(const yasm_floatnum *flt, FILE *f); + +#endif diff --git a/contrib/tools/yasm/libyasm/genmodule.c b/contrib/tools/yasm/libyasm/genmodule.c new file mode 100644 index 0000000000..867d93a5b2 --- /dev/null +++ b/contrib/tools/yasm/libyasm/genmodule.c @@ -0,0 +1,228 @@ +/* + * + * Generate module.c from module.in and Makefile.am or Makefile. + * + * Copyright (C) 2004-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 <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> + +#include "compat-queue.h" + +#define OUTPUT "module.c" +#define MAXNAME 128 +#define MAXLINE 1024 +#define MAXMODULES 128 +#define MAXINCLUDES 256 + +typedef struct include { + STAILQ_ENTRY(include) link; + char *filename; +} include; + +int +main(int argc, char *argv[]) +{ + FILE *in, *out; + char *str; + int i; + size_t len; + char *strp; + char *modules[MAXMODULES]; + int num_modules = 0; + STAILQ_HEAD(includehead, include) includes = + STAILQ_HEAD_INITIALIZER(includes); + include *inc; + int isam = 0; + int linecont = 0; + + if (argc != 3) { + fprintf(stderr, "Usage: %s <module.in> <Makefile[.am]>\n", argv[0]); + return EXIT_FAILURE; + } + + str = malloc(MAXLINE); + + /* Starting with initial input Makefile, look for include <file> or + * YASM_MODULES += <module>. Note this currently doesn't handle + * a relative starting path. + */ + len = strlen(argv[2]); + inc = malloc(sizeof(include)); + inc->filename = malloc(len+1); + strcpy(inc->filename, argv[2]); + STAILQ_INSERT_TAIL(&includes, inc, link); + + isam = argv[2][len-2] == 'a' && argv[2][len-1] == 'm'; + + while (!STAILQ_EMPTY(&includes)) { + inc = STAILQ_FIRST(&includes); + STAILQ_REMOVE_HEAD(&includes, link); + in = fopen(inc->filename, "rt"); + if (!in) { + fprintf(stderr, "Could not open `%s'.\n", inc->filename); + return EXIT_FAILURE; + } + free(inc->filename); + free(inc); + + while (fgets(str, MAXLINE, in)) { + /* Strip off any trailing whitespace */ + len = strlen(str); + if (len > 0) { + strp = &str[len-1]; + while (len > 0 && isspace(*strp)) { + *strp-- = '\0'; + len--; + } + } + + strp = str; + + /* Skip whitespace */ + while (isspace(*strp)) + strp++; + + /* Skip comments */ + if (*strp == '#') + continue; + + /* If line continuation, skip to continue copy */ + if (linecont) + goto keepgoing; + + /* Check for include if original input is .am file */ + if (isam && strncmp(strp, "include", 7) == 0 && isspace(strp[7])) { + strp += 7; + while (isspace(*strp)) + strp++; + /* Build new include and add to end of list */ + inc = malloc(sizeof(include)); + inc->filename = malloc(strlen(strp)+1); + strcpy(inc->filename, strp); + STAILQ_INSERT_TAIL(&includes, inc, link); + continue; + } + + /* Check for YASM_MODULES = or += */ + if (strncmp(strp, "YASM_MODULES", 12) != 0) + continue; + strp += 12; + while (isspace(*strp)) + strp++; + if (strncmp(strp, "+=", 2) != 0 && *strp != '=') + continue; + if (*strp == '+') + strp++; + strp++; + while (isspace(*strp)) + strp++; + +keepgoing: + /* Check for continuation */ + if (len > 0 && str[len-1] == '\\') { + str[len-1] = '\0'; + while (isspace(*strp)) + *strp-- = '\0'; + linecont = 1; + } else + linecont = 0; + + while (*strp != '\0') { + /* Copy module name */ + modules[num_modules] = malloc(MAXNAME); + len = 0; + while (*strp != '\0' && !isspace(*strp)) + modules[num_modules][len++] = *strp++; + modules[num_modules][len] = '\0'; + num_modules++; + + while (isspace(*strp)) + strp++; + } + } + fclose(in); + } + + out = fopen(OUTPUT, "wt"); + + if (!out) { + fprintf(stderr, "Could not open `%s'.\n", OUTPUT); + return EXIT_FAILURE; + } + + fprintf(out, "/* This file auto-generated by genmodule.c" + " - don't edit it */\n\n"); + + in = fopen(argv[1], "rt"); + if (!in) { + fprintf(stderr, "Could not open `%s'.\n", argv[1]); + fclose(out); + remove(OUTPUT); + return EXIT_FAILURE; + } + + len = 0; + while (fgets(str, MAXLINE, in)) { + if (strncmp(str, "MODULES_", 8) == 0) { + len = 0; + strp = str+8; + while (*strp != '\0' && *strp != '_') { + len++; + strp++; + } + *strp = '\0'; + + for (i=0; i<num_modules; i++) { + if (strncmp(modules[i], str+8, len) == 0) { + fprintf(out, " {\"%s\", &yasm_%s_LTX_%s},\n", + modules[i]+len+1, modules[i]+len+1, str+8); + } + } + } else if (strncmp(str, "EXTERN_LIST", 11) == 0) { + for (i=0; i<num_modules; i++) { + strcpy(str, modules[i]); + strp = str; + while (*strp != '\0' && *strp != '_') + strp++; + *strp++ = '\0'; + + fprintf(out, "extern yasm_%s_module yasm_%s_LTX_%s;\n", + str, strp, str); + } + } else + fputs(str, out); + } + + fclose(in); + fclose(out); + + for (i=0; i<num_modules; i++) + free(modules[i]); + free(str); + + return EXIT_SUCCESS; +} diff --git a/contrib/tools/yasm/libyasm/hamt.c b/contrib/tools/yasm/libyasm/hamt.c new file mode 100644 index 0000000000..59b7592109 --- /dev/null +++ b/contrib/tools/yasm/libyasm/hamt.c @@ -0,0 +1,421 @@ +/* + * Hash Array Mapped Trie (HAMT) implementation + * + * Copyright (C) 2001-2007 Peter Johnson + * + * Based on the paper "Ideal Hash Tries" by Phil Bagwell [2000]. + * One algorithmic change from that described in the paper: we use the LSB's + * of the key to index the root table and move upward in the key rather than + * use the MSBs as described in the paper. The LSBs have more entropy. + * + * 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 <ctype.h> + +#include "libyasm-stdint.h" +#include "coretype.h" +#include "hamt.h" + +struct HAMTEntry { + STAILQ_ENTRY(HAMTEntry) next; /* next hash table entry */ + /*@dependent@*/ const char *str; /* string being hashed */ + /*@owned@*/ void *data; /* data pointer being stored */ +}; + +typedef struct HAMTNode { + unsigned long BitMapKey; /* 32 bits, bitmap or hash key */ + uintptr_t BaseValue; /* Base of HAMTNode list or value */ +} HAMTNode; + +struct HAMT { + STAILQ_HEAD(HAMTEntryHead, HAMTEntry) entries; + HAMTNode *root; + /*@exits@*/ void (*error_func) (const char *file, unsigned int line, + const char *message); + unsigned long (*HashKey) (const char *key); + unsigned long (*ReHashKey) (const char *key, int Level); + int (*CmpKey) (const char *s1, const char *s2); +}; + +/* XXX make a portable version of this. This depends on the pointer being + * 4 or 2-byte aligned (as it uses the LSB of the pointer variable to store + * the subtrie flag! + */ +#define IsSubTrie(n) ((n)->BaseValue & 1) +#define SetSubTrie(h, n, v) do { \ + if ((uintptr_t)(v) & 1) \ + h->error_func(__FILE__, __LINE__, \ + N_("Subtrie is seen as subtrie before flag is set (misaligned?)")); \ + (n)->BaseValue = (uintptr_t)(v) | 1; \ + } while (0) +#define SetValue(h, n, v) do { \ + if ((uintptr_t)(v) & 1) \ + h->error_func(__FILE__, __LINE__, \ + N_("Value is seen as subtrie (misaligned?)")); \ + (n)->BaseValue = (uintptr_t)(v); \ + } while (0) +#define GetSubTrie(n) (HAMTNode *)(((n)->BaseValue | 1) ^ 1) + +static unsigned long +HashKey(const char *key) +{ + unsigned long a=31415, b=27183, vHash; + for (vHash=0; *key; key++, a*=b) + vHash = a*vHash + *key; + return vHash; +} + +static unsigned long +ReHashKey(const char *key, int Level) +{ + unsigned long a=31415, b=27183, vHash; + for (vHash=0; *key; key++, a*=b) + vHash = a*vHash*(unsigned long)Level + *key; + return vHash; +} + +static unsigned long +HashKey_nocase(const char *key) +{ + unsigned long a=31415, b=27183, vHash; + for (vHash=0; *key; key++, a*=b) + vHash = a*vHash + tolower(*key); + return vHash; +} + +static unsigned long +ReHashKey_nocase(const char *key, int Level) +{ + unsigned long a=31415, b=27183, vHash; + for (vHash=0; *key; key++, a*=b) + vHash = a*vHash*(unsigned long)Level + tolower(*key); + return vHash; +} + +HAMT * +HAMT_create(int nocase, /*@exits@*/ void (*error_func) + (const char *file, unsigned int line, const char *message)) +{ + /*@out@*/ HAMT *hamt = yasm_xmalloc(sizeof(HAMT)); + int i; + + STAILQ_INIT(&hamt->entries); + hamt->root = yasm_xmalloc(32*sizeof(HAMTNode)); + + for (i=0; i<32; i++) { + hamt->root[i].BitMapKey = 0; + hamt->root[i].BaseValue = 0; + } + + hamt->error_func = error_func; + if (nocase) { + hamt->HashKey = HashKey_nocase; + hamt->ReHashKey = ReHashKey_nocase; + hamt->CmpKey = yasm__strcasecmp; + } else { + hamt->HashKey = HashKey; + hamt->ReHashKey = ReHashKey; + hamt->CmpKey = strcmp; + } + + return hamt; +} + +static void +HAMT_delete_trie(HAMTNode *node) +{ + if (IsSubTrie(node)) { + unsigned long i, Size; + + /* Count total number of bits in bitmap to determine size */ + BitCount(Size, node->BitMapKey); + Size &= 0x1F; + if (Size == 0) + Size = 32; + + for (i=0; i<Size; i++) + HAMT_delete_trie(&(GetSubTrie(node))[i]); + yasm_xfree(GetSubTrie(node)); + } +} + +void +HAMT_destroy(HAMT *hamt, void (*deletefunc) (/*@only@*/ void *data)) +{ + int i; + + /* delete entries */ + while (!STAILQ_EMPTY(&hamt->entries)) { + HAMTEntry *entry; + entry = STAILQ_FIRST(&hamt->entries); + STAILQ_REMOVE_HEAD(&hamt->entries, next); + deletefunc(entry->data); + yasm_xfree(entry); + } + + /* delete trie */ + for (i=0; i<32; i++) + HAMT_delete_trie(&hamt->root[i]); + + yasm_xfree(hamt->root); + yasm_xfree(hamt); +} + +int +HAMT_traverse(HAMT *hamt, void *d, + int (*func) (/*@dependent@*/ /*@null@*/ void *node, + /*@null@*/ void *d)) +{ + HAMTEntry *entry; + STAILQ_FOREACH(entry, &hamt->entries, next) { + int retval = func(entry->data, d); + if (retval != 0) + return retval; + } + return 0; +} + +const HAMTEntry * +HAMT_first(const HAMT *hamt) +{ + return STAILQ_FIRST(&hamt->entries); +} + +const HAMTEntry * +HAMT_next(const HAMTEntry *prev) +{ + return STAILQ_NEXT(prev, next); +} + +void * +HAMTEntry_get_data(const HAMTEntry *entry) +{ + return entry->data; +} + +/*@-temptrans -kepttrans -mustfree@*/ +void * +HAMT_insert(HAMT *hamt, const char *str, void *data, int *replace, + void (*deletefunc) (/*@only@*/ void *data)) +{ + HAMTNode *node, *newnodes; + HAMTEntry *entry; + unsigned long key, keypart, Map; + int keypartbits = 0; + int level = 0; + + key = hamt->HashKey(str); + keypart = key & 0x1F; + node = &hamt->root[keypart]; + + if (!node->BaseValue) { + node->BitMapKey = key; + entry = yasm_xmalloc(sizeof(HAMTEntry)); + entry->str = str; + entry->data = data; + STAILQ_INSERT_TAIL(&hamt->entries, entry, next); + SetValue(hamt, node, entry); + if (IsSubTrie(node)) + hamt->error_func(__FILE__, __LINE__, + N_("Data is seen as subtrie (misaligned?)")); + *replace = 1; + return data; + } + + for (;;) { + if (!(IsSubTrie(node))) { + if (node->BitMapKey == key + && hamt->CmpKey(((HAMTEntry *)(node->BaseValue))->str, + str) == 0) { + /*@-branchstate@*/ + if (*replace) { + deletefunc(((HAMTEntry *)(node->BaseValue))->data); + ((HAMTEntry *)(node->BaseValue))->str = str; + ((HAMTEntry *)(node->BaseValue))->data = data; + } else + deletefunc(data); + /*@=branchstate@*/ + return ((HAMTEntry *)(node->BaseValue))->data; + } else { + unsigned long key2 = node->BitMapKey; + /* build tree downward until keys differ */ + for (;;) { + unsigned long keypart2; + + /* replace node with subtrie */ + keypartbits += 5; + if (keypartbits > 30) { + /* Exceeded 32 bits: rehash */ + key = hamt->ReHashKey(str, level); + key2 = hamt->ReHashKey( + ((HAMTEntry *)(node->BaseValue))->str, level); + keypartbits = 0; + } + keypart = (key >> keypartbits) & 0x1F; + keypart2 = (key2 >> keypartbits) & 0x1F; + + if (keypart == keypart2) { + /* Still equal, build one-node subtrie and continue + * downward. + */ + newnodes = yasm_xmalloc(sizeof(HAMTNode)); + newnodes[0].BitMapKey = key2; + newnodes[0].BaseValue = node->BaseValue; + node->BitMapKey = 1<<keypart; + SetSubTrie(hamt, node, newnodes); + node = &newnodes[0]; + level++; + } else { + /* partitioned: allocate two-node subtrie */ + newnodes = yasm_xmalloc(2*sizeof(HAMTNode)); + + entry = yasm_xmalloc(sizeof(HAMTEntry)); + entry->str = str; + entry->data = data; + STAILQ_INSERT_TAIL(&hamt->entries, entry, next); + + /* Copy nodes into subtrie based on order */ + if (keypart2 < keypart) { + newnodes[0].BitMapKey = key2; + newnodes[0].BaseValue = node->BaseValue; + newnodes[1].BitMapKey = key; + SetValue(hamt, &newnodes[1], entry); + } else { + newnodes[0].BitMapKey = key; + SetValue(hamt, &newnodes[0], entry); + newnodes[1].BitMapKey = key2; + newnodes[1].BaseValue = node->BaseValue; + } + + /* Set bits in bitmap corresponding to keys */ + node->BitMapKey = (1UL<<keypart) | (1UL<<keypart2); + SetSubTrie(hamt, node, newnodes); + *replace = 1; + return data; + } + } + } + } + + /* Subtrie: look up in bitmap */ + keypartbits += 5; + if (keypartbits > 30) { + /* Exceeded 32 bits of current key: rehash */ + key = hamt->ReHashKey(str, level); + keypartbits = 0; + } + keypart = (key >> keypartbits) & 0x1F; + if (!(node->BitMapKey & (1<<keypart))) { + /* bit is 0 in bitmap -> add node to table */ + unsigned long Size; + + /* set bit to 1 */ + node->BitMapKey |= 1<<keypart; + + /* Count total number of bits in bitmap to determine new size */ + BitCount(Size, node->BitMapKey); + Size &= 0x1F; + if (Size == 0) + Size = 32; + newnodes = yasm_xmalloc(Size*sizeof(HAMTNode)); + + /* Count bits below to find where to insert new node at */ + BitCount(Map, node->BitMapKey & ~((~0UL)<<keypart)); + Map &= 0x1F; /* Clamp to <32 */ + /* Copy existing nodes leaving gap for new node */ + memcpy(newnodes, GetSubTrie(node), Map*sizeof(HAMTNode)); + memcpy(&newnodes[Map+1], &(GetSubTrie(node))[Map], + (Size-Map-1)*sizeof(HAMTNode)); + /* Delete old subtrie */ + yasm_xfree(GetSubTrie(node)); + /* Set up new node */ + newnodes[Map].BitMapKey = key; + entry = yasm_xmalloc(sizeof(HAMTEntry)); + entry->str = str; + entry->data = data; + STAILQ_INSERT_TAIL(&hamt->entries, entry, next); + SetValue(hamt, &newnodes[Map], entry); + SetSubTrie(hamt, node, newnodes); + + *replace = 1; + return data; + } + + /* Count bits below */ + BitCount(Map, node->BitMapKey & ~((~0UL)<<keypart)); + Map &= 0x1F; /* Clamp to <32 */ + + /* Go down a level */ + level++; + node = &(GetSubTrie(node))[Map]; + } +} +/*@=temptrans =kepttrans =mustfree@*/ + +void * +HAMT_search(HAMT *hamt, const char *str) +{ + HAMTNode *node; + unsigned long key, keypart, Map; + int keypartbits = 0; + int level = 0; + + key = hamt->HashKey(str); + keypart = key & 0x1F; + node = &hamt->root[keypart]; + + if (!node->BaseValue) + return NULL; + + for (;;) { + if (!(IsSubTrie(node))) { + if (node->BitMapKey == key + && hamt->CmpKey(((HAMTEntry *)(node->BaseValue))->str, + str) == 0) + return ((HAMTEntry *)(node->BaseValue))->data; + else + return NULL; + } + + /* Subtree: look up in bitmap */ + keypartbits += 5; + if (keypartbits > 30) { + /* Exceeded 32 bits of current key: rehash */ + key = hamt->ReHashKey(str, level); + keypartbits = 0; + } + keypart = (key >> keypartbits) & 0x1F; + if (!(node->BitMapKey & (1<<keypart))) + return NULL; /* bit is 0 in bitmap -> no match */ + + /* Count bits below */ + BitCount(Map, node->BitMapKey & ~((~0UL)<<keypart)); + Map &= 0x1F; /* Clamp to <32 */ + + /* Go down a level */ + level++; + node = &(GetSubTrie(node))[Map]; + } +} + diff --git a/contrib/tools/yasm/libyasm/hamt.h b/contrib/tools/yasm/libyasm/hamt.h new file mode 100644 index 0000000000..1ce9b77536 --- /dev/null +++ b/contrib/tools/yasm/libyasm/hamt.h @@ -0,0 +1,123 @@ +/** + * \file libyasm/hamt.h + * \brief Hash Array Mapped Trie (HAMT) functions. + * + * \license + * 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. + * \endlicense + */ +#ifndef YASM_HAMT_H +#define YASM_HAMT_H + +#ifndef YASM_LIB_DECL +#define YASM_LIB_DECL +#endif + +/** Hash array mapped trie data structure (opaque type). */ +typedef struct HAMT HAMT; +/** Hash array mapped trie entry (opaque type). */ +typedef struct HAMTEntry HAMTEntry; + +/** Create new, empty, HAMT. error_func() is called when an internal error is + * encountered--it should NOT return to the calling function. + * \param nocase nonzero if HAMT should be case-insensitive + * \param error_func function called on internal error + * \return New, empty, hash array mapped trie. + */ +YASM_LIB_DECL +HAMT *HAMT_create(int nocase, /*@exits@*/ void (*error_func) + (const char *file, unsigned int line, const char *message)); + +/** Delete HAMT and all data associated with it. Uses deletefunc() to delete + * each data item. + * \param hamt Hash array mapped trie + * \param deletefunc Data deletion function + */ +YASM_LIB_DECL +void HAMT_destroy(/*@only@*/ HAMT *hamt, + void (*deletefunc) (/*@only@*/ void *data)); + +/** Insert key into HAMT, associating it with data. + * If the key is not present in the HAMT, inserts it, sets *replace to 1, and + * returns the data passed in. + * If the key is already present and *replace is 0, deletes the data passed + * in using deletefunc() and returns the data currently associated with the + * key. + * If the key is already present and *replace is 1, deletes the data currently + * associated with the key using deletefunc() and replaces it with the data + * passed in. + * \param hamt Hash array mapped trie + * \param str Key + * \param data Data to associate with key + * \param replace See above description + * \param deletefunc Data deletion function if data is replaced + * \return Data now associated with key. + */ +YASM_LIB_DECL +/*@dependent@*/ void *HAMT_insert(HAMT *hamt, /*@dependent@*/ const char *str, + /*@only@*/ void *data, int *replace, + void (*deletefunc) (/*@only@*/ void *data)); + +/** Search for the data associated with a key in the HAMT. + * \param hamt Hash array mapped trie + * \param str Key + * \return NULL if key/data not present in HAMT, otherwise associated data. + */ +YASM_LIB_DECL +/*@dependent@*/ /*@null@*/ void *HAMT_search(HAMT *hamt, const char *str); + +/** Traverse over all keys in HAMT, calling function on each data item. + * \param hamt Hash array mapped trie + * \param d Data to pass to each call to func. + * \param func Function to call + * \return Stops early (and returns func's return value) if func returns a + * nonzero value; otherwise 0. + */ +YASM_LIB_DECL +int HAMT_traverse(HAMT *hamt, /*@null@*/ void *d, + int (*func) (/*@dependent@*/ /*@null@*/ void *node, + /*@null@*/ void *d)); + +/** Get the first entry in a HAMT. + * \param hamt Hash array mapped trie + * \return First entry in HAMT, or NULL if HAMT is empty. + */ +YASM_LIB_DECL +const HAMTEntry *HAMT_first(const HAMT *hamt); + +/** Get the next entry in a HAMT. + * \param prev Previous entry in HAMT + * \return Next entry in HAMT, or NULL if no more entries. + */ +YASM_LIB_DECL +/*@null@*/ const HAMTEntry *HAMT_next(const HAMTEntry *prev); + +/** Get the corresponding data for a HAMT entry. + * \param entry HAMT entry (as returned by HAMT_first() and HAMT_next()) + * \return Corresponding data item. + */ +YASM_LIB_DECL +void *HAMTEntry_get_data(const HAMTEntry *entry); + +#endif diff --git a/contrib/tools/yasm/libyasm/insn.c b/contrib/tools/yasm/libyasm/insn.c new file mode 100644 index 0000000000..8f7a4c1978 --- /dev/null +++ b/contrib/tools/yasm/libyasm/insn.c @@ -0,0 +1,295 @@ +/* + * Mnemonic instruction bytecode + * + * Copyright (C) 2005-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-stdint.h" +#include "coretype.h" + +#include "errwarn.h" +#include "expr.h" +#include "value.h" + +#include "bytecode.h" +#include "insn.h" +#include "arch.h" + + +void +yasm_ea_set_segreg(yasm_effaddr *ea, uintptr_t segreg) +{ + if (!ea) + return; + + if (segreg != 0 && ea->segreg != 0) + yasm_warn_set(YASM_WARN_GENERAL, + N_("multiple segment overrides, using leftmost")); + + ea->segreg = segreg; +} + +yasm_insn_operand * +yasm_operand_create_reg(uintptr_t reg) +{ + yasm_insn_operand *retval = yasm_xmalloc(sizeof(yasm_insn_operand)); + + retval->type = YASM_INSN__OPERAND_REG; + retval->data.reg = reg; + retval->seg = 0; + retval->targetmod = 0; + retval->size = 0; + retval->deref = 0; + retval->strict = 0; + + return retval; +} + +yasm_insn_operand * +yasm_operand_create_segreg(uintptr_t segreg) +{ + yasm_insn_operand *retval = yasm_xmalloc(sizeof(yasm_insn_operand)); + + retval->type = YASM_INSN__OPERAND_SEGREG; + retval->data.reg = segreg; + retval->seg = 0; + retval->targetmod = 0; + retval->size = 0; + retval->deref = 0; + retval->strict = 0; + + return retval; +} + +yasm_insn_operand * +yasm_operand_create_mem(/*@only@*/ yasm_effaddr *ea) +{ + yasm_insn_operand *retval = yasm_xmalloc(sizeof(yasm_insn_operand)); + + retval->type = YASM_INSN__OPERAND_MEMORY; + retval->data.ea = ea; + retval->seg = 0; + retval->targetmod = 0; + retval->size = 0; + retval->deref = 0; + retval->strict = 0; + retval->size = ea->data_len * 8; + + return retval; +} + +yasm_insn_operand * +yasm_operand_create_imm(/*@only@*/ yasm_expr *val) +{ + yasm_insn_operand *retval; + const uintptr_t *reg; + + reg = yasm_expr_get_reg(&val, 0); + if (reg) { + retval = yasm_operand_create_reg(*reg); + yasm_expr_destroy(val); + } else { + retval = yasm_xmalloc(sizeof(yasm_insn_operand)); + retval->type = YASM_INSN__OPERAND_IMM; + retval->data.val = val; + retval->seg = 0; + retval->targetmod = 0; + retval->size = 0; + retval->deref = 0; + retval->strict = 0; + } + + return retval; +} + +yasm_insn_operand * +yasm_insn_ops_append(yasm_insn *insn, yasm_insn_operand *op) +{ + if (op) { + insn->num_operands++; + STAILQ_INSERT_TAIL(&insn->operands, op, link); + return op; + } + return (yasm_insn_operand *)NULL; +} + +void +yasm_insn_add_prefix(yasm_insn *insn, uintptr_t prefix) +{ + insn->prefixes = + yasm_xrealloc(insn->prefixes, + (insn->num_prefixes+1)*sizeof(uintptr_t)); + insn->prefixes[insn->num_prefixes] = prefix; + insn->num_prefixes++; +} + +void +yasm_insn_add_seg_prefix(yasm_insn *insn, uintptr_t segreg) +{ + insn->segregs = + yasm_xrealloc(insn->segregs, (insn->num_segregs+1)*sizeof(uintptr_t)); + insn->segregs[insn->num_segregs] = segreg; + insn->num_segregs++; +} + +void +yasm_insn_initialize(yasm_insn *insn) +{ + STAILQ_INIT(&insn->operands); + + insn->prefixes = NULL; + insn->segregs = NULL; + + insn->num_operands = 0; + insn->num_prefixes = 0; + insn->num_segregs = 0; +} + +void +yasm_insn_delete(yasm_insn *insn, + void (*ea_destroy) (/*@only@*/ yasm_effaddr *)) +{ + if (insn->num_operands > 0) { + yasm_insn_operand *cur, *next; + + cur = STAILQ_FIRST(&insn->operands); + while (cur) { + next = STAILQ_NEXT(cur, link); + switch (cur->type) { + case YASM_INSN__OPERAND_MEMORY: + ea_destroy(cur->data.ea); + break; + case YASM_INSN__OPERAND_IMM: + yasm_expr_destroy(cur->data.val); + break; + default: + break; + } + yasm_xfree(cur); + cur = next; + } + } + if (insn->num_prefixes > 0) + yasm_xfree(insn->prefixes); + if (insn->num_segregs > 0) + yasm_xfree(insn->segregs); +} + +void +yasm_insn_print(const yasm_insn *insn, FILE *f, int indent_level) +{ + const yasm_insn_operand *op; + + STAILQ_FOREACH (op, &insn->operands, link) { + switch (op->type) { + case YASM_INSN__OPERAND_REG: + fprintf(f, "%*sReg=", indent_level, ""); + /*yasm_arch_reg_print(arch, op->data.reg, f);*/ + fprintf(f, "\n"); + break; + case YASM_INSN__OPERAND_SEGREG: + fprintf(f, "%*sSegReg=", indent_level, ""); + /*yasm_arch_segreg_print(arch, op->data.reg, f);*/ + fprintf(f, "\n"); + break; + case YASM_INSN__OPERAND_MEMORY: + fprintf(f, "%*sMemory=\n", indent_level, ""); + /*yasm_arch_ea_print(arch, op->data.ea, f, indent_level);*/ + break; + case YASM_INSN__OPERAND_IMM: + fprintf(f, "%*sImm=", indent_level, ""); + yasm_expr_print(op->data.val, f); + fprintf(f, "\n"); + break; + } + fprintf(f, "%*sTargetMod=%lx\n", indent_level+1, "", + (unsigned long)op->targetmod); + fprintf(f, "%*sSize=%u\n", indent_level+1, "", op->size); + fprintf(f, "%*sDeref=%d, Strict=%d\n", indent_level+1, "", + (int)op->deref, (int)op->strict); + } +} + +void +yasm_insn_finalize(yasm_insn *insn) +{ + unsigned int i; + yasm_insn_operand *op; + yasm_error_class eclass; + char *str, *xrefstr; + unsigned long xrefline; + + /* Simplify the operands' expressions first. */ + for (i = 0, op = yasm_insn_ops_first(insn); + op && i<insn->num_operands; op = yasm_insn_op_next(op), i++) { + /* Check operand type */ + switch (op->type) { + case YASM_INSN__OPERAND_MEMORY: + /* Don't get over-ambitious here; some archs' memory expr + * parser are sensitive to the presence of *1, etc, so don't + * simplify reg*1 identities. + */ + if (op->data.ea) + op->data.ea->disp.abs = + yasm_expr__level_tree(op->data.ea->disp.abs, 1, 1, 0, + 0, NULL, NULL); + if (yasm_error_occurred()) { + /* Add a pointer to where it was used to the error */ + yasm_error_fetch(&eclass, &str, &xrefline, &xrefstr); + if (xrefstr) { + yasm_error_set_xref(xrefline, "%s", xrefstr); + yasm_xfree(xrefstr); + } + if (str) { + yasm_error_set(eclass, "%s in memory expression", str); + yasm_xfree(str); + } + return; + } + break; + case YASM_INSN__OPERAND_IMM: + op->data.val = + yasm_expr__level_tree(op->data.val, 1, 1, 1, 0, NULL, + NULL); + if (yasm_error_occurred()) { + /* Add a pointer to where it was used to the error */ + yasm_error_fetch(&eclass, &str, &xrefline, &xrefstr); + if (xrefstr) { + yasm_error_set_xref(xrefline, "%s", xrefstr); + yasm_xfree(xrefstr); + } + if (str) { + yasm_error_set(eclass, "%s in immediate expression", + str); + yasm_xfree(str); + } + return; + } + break; + default: + break; + } + } +} diff --git a/contrib/tools/yasm/libyasm/insn.h b/contrib/tools/yasm/libyasm/insn.h new file mode 100644 index 0000000000..d2d175d039 --- /dev/null +++ b/contrib/tools/yasm/libyasm/insn.h @@ -0,0 +1,269 @@ +/** + * \file libyasm/insn.h + * \brief YASM mnenomic instruction. + * + * \license + * 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: + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - 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. + * \endlicense + */ +#ifndef YASM_INSN_H +#define YASM_INSN_H + +#ifndef YASM_LIB_DECL +#define YASM_LIB_DECL +#endif + +/** Base structure for an effective address. As with all base + * structures, must be present as the first element in any + * #yasm_arch implementation of an effective address. + */ +struct yasm_effaddr { + yasm_value disp; /**< address displacement */ + + /** Segment register override (0 if none). */ + uintptr_t segreg; + + /** 1 if length of disp must be >0. */ + unsigned int need_nonzero_len:1; + + /** 1 if a displacement should be present in the output. */ + unsigned int need_disp:1; + + /** 1 if reg*2 should not be split into reg+reg. (0 if not). + * This flag indicates (for architectures that support complex effective + * addresses such as x86) if various types of complex effective addresses + * can be split into different forms in order to minimize instruction + * length. + */ + unsigned int nosplit:1; + + /** 1 if effective address is /definitely/ an effective address. + * This is used in e.g. the GAS parser to differentiate + * between "expr" (which might or might not be an effective address) and + * "expr(,1)" (which is definitely an effective address). + */ + unsigned int strong:1; + + /** 1 if effective address is forced PC-relative. */ + unsigned int pc_rel:1; + + /** 1 if effective address is forced non-PC-relative. */ + unsigned int not_pc_rel:1; + + /** length of pointed data (in bytes), 0 if unknown. */ + unsigned int data_len; +}; + +/** An instruction operand (opaque type). */ +typedef struct yasm_insn_operand yasm_insn_operand; + +/** The type of an instruction operand. */ +typedef enum yasm_insn_operand_type { + YASM_INSN__OPERAND_REG = 1, /**< A register. */ + YASM_INSN__OPERAND_SEGREG, /**< A segment register. */ + YASM_INSN__OPERAND_MEMORY, /**< An effective address + * (memory reference). */ + YASM_INSN__OPERAND_IMM /**< An immediate or jump target. */ +} yasm_insn_operand_type; + +/** An instruction operand. */ +struct yasm_insn_operand { + /** Link for building linked list of operands. \internal */ + /*@reldef@*/ STAILQ_ENTRY(yasm_insn_operand) link; + + /** Operand data. */ + union { + uintptr_t reg; /**< Arch data for reg/segreg. */ + yasm_effaddr *ea; /**< Effective address for memory references. */ + yasm_expr *val; /**< Value of immediate or jump target. */ + } data; + + yasm_expr *seg; /**< Segment expression */ + + uintptr_t targetmod; /**< Arch target modifier, 0 if none. */ + + /** Specified size of the operand, in bits. 0 if not user-specified. */ + unsigned int size:16; + + /** Nonzero if dereference. Used for "*foo" in GAS. + * The reason for this is that by default in GAS, an unprefixed value + * is a memory address, except for jumps/calls, in which case it needs a + * "*" prefix to become a memory address (otherwise it's an immediate). + * This isn't knowable in the parser stage, so the parser sets this flag + * to indicate the "*" prefix has been used, and the arch needs to adjust + * the operand type appropriately depending on the instruction type. + */ + unsigned int deref:1; + + /** Nonzero if strict. Used for "strict foo" in NASM. + * This is used to inhibit optimization on otherwise "sized" values. + * For example, the user may just want to be explicit with the size on + * "push dword 4", but not actually want to force the immediate size to + * 4 bytes (rather wanting the optimizer to optimize it down to 1 byte as + * though "dword" was not specified). To indicate the immediate should + * actually be forced to 4 bytes, the user needs to write + * "push strict dword 4", which sets this flag. + */ + unsigned int strict:1; + + /** Operand type. */ + unsigned int type:4; +}; + +/** Base structure for "instruction" bytecodes. These are the mnenomic + * (rather than raw) representation of instructions. As with all base + * structures, must be present as the first element in any + * #yasm_arch implementation of mnenomic instruction bytecodes. + */ +struct yasm_insn { + /** Linked list of operands. */ + /*@reldef@*/ STAILQ_HEAD(yasm_insn_operands, yasm_insn_operand) operands; + + /** Array of prefixes. */ + /*@null@*/ uintptr_t *prefixes; + + /** Array of segment prefixes. */ + /*@null@*/ uintptr_t *segregs; + + unsigned int num_operands; /**< Number of operands. */ + unsigned int num_prefixes; /**< Number of prefixes. */ + unsigned int num_segregs; /**< Number of segment prefixes. */ +}; + +/** Set segment override for an effective address. + * Some architectures (such as x86) support segment overrides on effective + * addresses. A override of an override will result in a warning. + * \param ea effective address + * \param segreg segment register (0 if none) + */ +YASM_LIB_DECL +void yasm_ea_set_segreg(yasm_effaddr *ea, uintptr_t segreg); + +/** Create an instruction operand from a register. + * \param reg register + * \return Newly allocated operand. + */ +YASM_LIB_DECL +yasm_insn_operand *yasm_operand_create_reg(uintptr_t reg); + +/** Create an instruction operand from a segment register. + * \param segreg segment register + * \return Newly allocated operand. + */ +YASM_LIB_DECL +yasm_insn_operand *yasm_operand_create_segreg(uintptr_t segreg); + +/** Create an instruction operand from an effective address. + * \param ea effective address + * \return Newly allocated operand. + */ +YASM_LIB_DECL +yasm_insn_operand *yasm_operand_create_mem(/*@only@*/ yasm_effaddr *ea); + +/** Create an instruction operand from an immediate expression. + * Looks for cases of a single register and creates a register variant of + * #yasm_insn_operand. + * \param val immediate expression + * \return Newly allocated operand. + */ +YASM_LIB_DECL +yasm_insn_operand *yasm_operand_create_imm(/*@only@*/ yasm_expr *val); + +/** Get the first operand in an instruction. + * \param insn instruction + * \return First operand (NULL if no operands). + */ +yasm_insn_operand *yasm_insn_ops_first(yasm_insn *insn); +#define yasm_insn_ops_first(insn) STAILQ_FIRST(&((insn)->operands)) + +/** Get the next operand in an instruction. + * \param op previous operand + * \return Next operand (NULL if op was the last operand). + */ +yasm_insn_operand *yasm_insn_op_next(yasm_insn_operand *op); +#define yasm_insn_op_next(cur) STAILQ_NEXT(cur, link) + +/** Add operand to the end of an instruction. + * \note Does not make a copy of the operand; so don't pass this function + * static or local variables, and discard the op pointer after calling + * this function. + * \param insn instruction + * \param op operand (may be NULL) + * \return If operand was actually appended (it wasn't NULL), the operand; + * otherwise NULL. + */ +YASM_LIB_DECL +/*@null@*/ yasm_insn_operand *yasm_insn_ops_append + (yasm_insn *insn, + /*@returned@*/ /*@null@*/ yasm_insn_operand *op); + +/** Associate a prefix with an instruction. + * \param insn instruction + * \param prefix data that identifies the prefix + */ +YASM_LIB_DECL +void yasm_insn_add_prefix(yasm_insn *insn, uintptr_t prefix); + +/** Associate a segment prefix with an instruction. + * \param insn instruction + * \param segreg data that identifies the segment register + */ +YASM_LIB_DECL +void yasm_insn_add_seg_prefix(yasm_insn *insn, uintptr_t segreg); + +/** Initialize the common parts of an instruction. + * \internal For use by yasm_arch implementations only. + * \param insn instruction + */ +YASM_LIB_DECL +void yasm_insn_initialize(/*@out@*/ yasm_insn *insn); + +/** Delete the common parts of an instruction. + * \internal For use by yasm_arch implementations only. + * \param insn instruction + * \param content if nonzero, deletes content of each operand + * \param arch architecture + */ +YASM_LIB_DECL +void yasm_insn_delete(yasm_insn *insn, + void (*ea_destroy) (/*@only@*/ yasm_effaddr *)); + +/** Print a list of instruction operands. For debugging purposes. + * \internal For use by yasm_arch implementations only. + * \param insn instruction + * \param f file + * \param indent_level indentation level + * \param arch architecture + */ +YASM_LIB_DECL +void yasm_insn_print(const yasm_insn *insn, FILE *f, int indent_level); + +/** Finalize the common parts of an instruction. + * \internal For use by yasm_arch implementations only. + * \param insn instruction + */ +YASM_LIB_DECL +void yasm_insn_finalize(yasm_insn *insn); + +#endif diff --git a/contrib/tools/yasm/libyasm/intnum.c b/contrib/tools/yasm/libyasm/intnum.c new file mode 100644 index 0000000000..6feba33481 --- /dev/null +++ b/contrib/tools/yasm/libyasm/intnum.c @@ -0,0 +1,1096 @@ +/* + * Integer number 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 <ctype.h> +#include <limits.h> + +#include "coretype.h" +#include "bitvect.h" +#include "file.h" + +#include "errwarn.h" +#include "intnum.h" + + +/* "Native" "word" size for intnum calculations. */ +#define BITVECT_NATIVE_SIZE 256 + +struct yasm_intnum { + union val { + long l; /* integer value (for integers <32 bits) */ + wordptr bv; /* bit vector (for integers >=32 bits) */ + } val; + enum { INTNUM_L, INTNUM_BV } type; +}; + +/* static bitvect used for conversions */ +static /*@only@*/ wordptr conv_bv; + +/* static bitvects used for computation */ +static /*@only@*/ wordptr result, spare, op1static, op2static; + +static /*@only@*/ BitVector_from_Dec_static_data *from_dec_data; + + +void +yasm_intnum_initialize(void) +{ + conv_bv = BitVector_Create(BITVECT_NATIVE_SIZE, FALSE); + result = BitVector_Create(BITVECT_NATIVE_SIZE, FALSE); + spare = BitVector_Create(BITVECT_NATIVE_SIZE, FALSE); + op1static = BitVector_Create(BITVECT_NATIVE_SIZE, FALSE); + op2static = BitVector_Create(BITVECT_NATIVE_SIZE, FALSE); + from_dec_data = BitVector_from_Dec_static_Boot(BITVECT_NATIVE_SIZE); +} + +void +yasm_intnum_cleanup(void) +{ + BitVector_from_Dec_static_Shutdown(from_dec_data); + BitVector_Destroy(op2static); + BitVector_Destroy(op1static); + BitVector_Destroy(spare); + BitVector_Destroy(result); + BitVector_Destroy(conv_bv); +} + +/* Compress a bitvector into intnum storage. + * If saved as a bitvector, clones the passed bitvector. + * Can modify the passed bitvector. + */ +static void +intnum_frombv(/*@out@*/ yasm_intnum *intn, wordptr bv) +{ + if (Set_Max(bv) < 31) { + intn->type = INTNUM_L; + intn->val.l = (long)BitVector_Chunk_Read(bv, 31, 0); + } else if (BitVector_msb_(bv)) { + /* Negative, negate and see if we'll fit into a long. */ + unsigned long ul; + BitVector_Negate(bv, bv); + if (Set_Max(bv) >= 32 || + ((ul = BitVector_Chunk_Read(bv, 32, 0)) & 0x80000000)) { + /* too negative */ + BitVector_Negate(bv, bv); + intn->type = INTNUM_BV; + intn->val.bv = BitVector_Clone(bv); + } else { + intn->type = INTNUM_L; + intn->val.l = -((long)ul); + } + } else { + intn->type = INTNUM_BV; + intn->val.bv = BitVector_Clone(bv); + } +} + +/* If intnum is a BV, returns its bitvector directly. + * If not, converts into passed bv and returns that instead. + */ +static wordptr +intnum_tobv(/*@returned@*/ wordptr bv, const yasm_intnum *intn) +{ + if (intn->type == INTNUM_BV) + return intn->val.bv; + + BitVector_Empty(bv); + if (intn->val.l >= 0) + BitVector_Chunk_Store(bv, 32, 0, (unsigned long)intn->val.l); + else { + BitVector_Chunk_Store(bv, 32, 0, (unsigned long)-intn->val.l); + BitVector_Negate(bv, bv); + } + return bv; +} + +yasm_intnum * +yasm_intnum_create_dec(char *str) +{ + yasm_intnum *intn = yasm_xmalloc(sizeof(yasm_intnum)); + + switch (BitVector_from_Dec_static(from_dec_data, conv_bv, + (unsigned char *)str)) { + case ErrCode_Pars: + yasm_error_set(YASM_ERROR_VALUE, N_("invalid decimal literal")); + break; + case ErrCode_Ovfl: + yasm_error_set(YASM_ERROR_OVERFLOW, + N_("Numeric constant too large for internal format")); + break; + default: + break; + } + intnum_frombv(intn, conv_bv); + return intn; +} + +yasm_intnum * +yasm_intnum_create_bin(char *str) +{ + yasm_intnum *intn = yasm_xmalloc(sizeof(yasm_intnum)); + + switch (BitVector_from_Bin(conv_bv, (unsigned char *)str)) { + case ErrCode_Pars: + yasm_error_set(YASM_ERROR_VALUE, N_("invalid binary literal")); + break; + case ErrCode_Ovfl: + yasm_error_set(YASM_ERROR_OVERFLOW, + N_("Numeric constant too large for internal format")); + break; + default: + break; + } + intnum_frombv(intn, conv_bv); + return intn; +} + +yasm_intnum * +yasm_intnum_create_oct(char *str) +{ + yasm_intnum *intn = yasm_xmalloc(sizeof(yasm_intnum)); + + switch (BitVector_from_Oct(conv_bv, (unsigned char *)str)) { + case ErrCode_Pars: + yasm_error_set(YASM_ERROR_VALUE, N_("invalid octal literal")); + break; + case ErrCode_Ovfl: + yasm_error_set(YASM_ERROR_OVERFLOW, + N_("Numeric constant too large for internal format")); + break; + default: + break; + } + intnum_frombv(intn, conv_bv); + return intn; +} + +yasm_intnum * +yasm_intnum_create_hex(char *str) +{ + yasm_intnum *intn = yasm_xmalloc(sizeof(yasm_intnum)); + + switch (BitVector_from_Hex(conv_bv, (unsigned char *)str)) { + case ErrCode_Pars: + yasm_error_set(YASM_ERROR_VALUE, N_("invalid hex literal")); + break; + case ErrCode_Ovfl: + yasm_error_set(YASM_ERROR_OVERFLOW, + N_("Numeric constant too large for internal format")); + break; + default: + break; + } + intnum_frombv(intn, conv_bv); + return intn; +} + +/*@-usedef -compdef -uniondef@*/ +yasm_intnum * +yasm_intnum_create_charconst_nasm(const char *str) +{ + yasm_intnum *intn = yasm_xmalloc(sizeof(yasm_intnum)); + size_t len = strlen(str); + + if(len*8 > BITVECT_NATIVE_SIZE) + yasm_error_set(YASM_ERROR_OVERFLOW, + N_("Character constant too large for internal format")); + + /* be conservative in choosing bitvect in case MSB is set */ + if (len > 3) { + BitVector_Empty(conv_bv); + intn->type = INTNUM_BV; + } else { + intn->val.l = 0; + intn->type = INTNUM_L; + } + + switch (len) { + case 3: + intn->val.l |= ((unsigned long)str[2]) & 0xff; + intn->val.l <<= 8; + /*@fallthrough@*/ + case 2: + intn->val.l |= ((unsigned long)str[1]) & 0xff; + intn->val.l <<= 8; + /*@fallthrough@*/ + case 1: + intn->val.l |= ((unsigned long)str[0]) & 0xff; + case 0: + break; + default: + /* >=32 bit conversion */ + while (len) { + BitVector_Move_Left(conv_bv, 8); + BitVector_Chunk_Store(conv_bv, 8, 0, + ((unsigned long)str[--len]) & 0xff); + } + intn->val.bv = BitVector_Clone(conv_bv); + } + + return intn; +} + +yasm_intnum * +yasm_intnum_create_charconst_tasm(const char *str) +{ + yasm_intnum *intn = yasm_xmalloc(sizeof(yasm_intnum)); + size_t len = strlen(str); + size_t i; + + if(len*8 > BITVECT_NATIVE_SIZE) + yasm_error_set(YASM_ERROR_OVERFLOW, + N_("Character constant too large for internal format")); + + /* be conservative in choosing bitvect in case MSB is set */ + if (len > 3) { + BitVector_Empty(conv_bv); + intn->type = INTNUM_BV; + } else { + intn->val.l = 0; + intn->type = INTNUM_L; + } + + /* tasm uses big endian notation */ + i = 0; + switch (len) { + case 3: + intn->val.l |= ((unsigned long)str[i++]) & 0xff; + intn->val.l <<= 8; + /*@fallthrough@*/ + case 2: + intn->val.l |= ((unsigned long)str[i++]) & 0xff; + intn->val.l <<= 8; + /*@fallthrough@*/ + case 1: + intn->val.l |= ((unsigned long)str[i++]) & 0xff; + case 0: + break; + default: + /* >=32 bit conversion */ + while (i < len) { + BitVector_Chunk_Store(conv_bv, 8, (len-i-1)*8, + ((unsigned long)str[i]) & 0xff); + i++; + } + intn->val.bv = BitVector_Clone(conv_bv); + } + + return intn; +} +/*@=usedef =compdef =uniondef@*/ + +yasm_intnum * +yasm_intnum_create_uint(unsigned long i) +{ + yasm_intnum *intn = yasm_xmalloc(sizeof(yasm_intnum)); + + if (i > LONG_MAX) { + /* Too big, store as bitvector */ + intn->val.bv = BitVector_Create(BITVECT_NATIVE_SIZE, TRUE); + intn->type = INTNUM_BV; + BitVector_Chunk_Store(intn->val.bv, 32, 0, i); + } else { + intn->val.l = (long)i; + intn->type = INTNUM_L; + } + + return intn; +} + +yasm_intnum * +yasm_intnum_create_int(long i) +{ + yasm_intnum *intn = yasm_xmalloc(sizeof(yasm_intnum)); + + intn->val.l = i; + intn->type = INTNUM_L; + + return intn; +} + +yasm_intnum * +yasm_intnum_create_leb128(const unsigned char *ptr, int sign, + unsigned long *size) +{ + yasm_intnum *intn = yasm_xmalloc(sizeof(yasm_intnum)); + const unsigned char *ptr_orig = ptr; + unsigned long i = 0; + + BitVector_Empty(conv_bv); + for (;;) { + BitVector_Chunk_Store(conv_bv, 7, i, *ptr); + i += 7; + if ((*ptr & 0x80) != 0x80) + break; + ptr++; + } + + *size = (unsigned long)(ptr-ptr_orig)+1; + + if(i > BITVECT_NATIVE_SIZE) + yasm_error_set(YASM_ERROR_OVERFLOW, + N_("Numeric constant too large for internal format")); + else if (sign && (*ptr & 0x40) == 0x40) + BitVector_Interval_Fill(conv_bv, i, BITVECT_NATIVE_SIZE-1); + + intnum_frombv(intn, conv_bv); + return intn; +} + +yasm_intnum * +yasm_intnum_create_sized(unsigned char *ptr, int sign, size_t srcsize, + int bigendian) +{ + yasm_intnum *intn = yasm_xmalloc(sizeof(yasm_intnum)); + unsigned long i = 0; + + if (srcsize*8 > BITVECT_NATIVE_SIZE) + yasm_error_set(YASM_ERROR_OVERFLOW, + N_("Numeric constant too large for internal format")); + + /* Read the buffer into a bitvect */ + BitVector_Empty(conv_bv); + if (bigendian) { + /* TODO */ + yasm_internal_error(N_("big endian not implemented")); + } else { + for (i = 0; i < srcsize; i++) + BitVector_Chunk_Store(conv_bv, 8, i*8, ptr[i]); + } + + /* Sign extend if needed */ + if (srcsize*8 < BITVECT_NATIVE_SIZE && sign && (ptr[i-1] & 0x80) == 0x80) + BitVector_Interval_Fill(conv_bv, i*8, BITVECT_NATIVE_SIZE-1); + + intnum_frombv(intn, conv_bv); + return intn; +} + +yasm_intnum * +yasm_intnum_copy(const yasm_intnum *intn) +{ + yasm_intnum *n = yasm_xmalloc(sizeof(yasm_intnum)); + + switch (intn->type) { + case INTNUM_L: + n->val.l = intn->val.l; + break; + case INTNUM_BV: + n->val.bv = BitVector_Clone(intn->val.bv); + break; + } + n->type = intn->type; + + return n; +} + +void +yasm_intnum_destroy(yasm_intnum *intn) +{ + if (intn->type == INTNUM_BV) + BitVector_Destroy(intn->val.bv); + yasm_xfree(intn); +} + +/*@-nullderef -nullpass -branchstate@*/ +int +yasm_intnum_calc(yasm_intnum *acc, yasm_expr_op op, yasm_intnum *operand) +{ + boolean carry = 0; + wordptr op1, op2 = NULL; + N_int count; + + /* Always do computations with in full bit vector. + * Bit vector results must be calculated through intermediate storage. + */ + op1 = intnum_tobv(op1static, acc); + if (operand) + op2 = intnum_tobv(op2static, operand); + + if (!operand && op != YASM_EXPR_NEG && op != YASM_EXPR_NOT && + op != YASM_EXPR_LNOT) { + yasm_error_set(YASM_ERROR_ARITHMETIC, + N_("operation needs an operand")); + BitVector_Empty(result); + return 1; + } + + /* A operation does a bitvector computation if result is allocated. */ + switch (op) { + case YASM_EXPR_ADD: + BitVector_add(result, op1, op2, &carry); + break; + case YASM_EXPR_SUB: + BitVector_sub(result, op1, op2, &carry); + break; + case YASM_EXPR_MUL: + BitVector_Multiply(result, op1, op2); + break; + case YASM_EXPR_DIV: + /* TODO: make sure op1 and op2 are unsigned */ + if (BitVector_is_empty(op2)) { + yasm_error_set(YASM_ERROR_ZERO_DIVISION, N_("divide by zero")); + BitVector_Empty(result); + return 1; + } else + BitVector_Divide(result, op1, op2, spare); + break; + case YASM_EXPR_SIGNDIV: + if (BitVector_is_empty(op2)) { + yasm_error_set(YASM_ERROR_ZERO_DIVISION, N_("divide by zero")); + BitVector_Empty(result); + return 1; + } else + BitVector_Divide(result, op1, op2, spare); + break; + case YASM_EXPR_MOD: + /* TODO: make sure op1 and op2 are unsigned */ + if (BitVector_is_empty(op2)) { + yasm_error_set(YASM_ERROR_ZERO_DIVISION, N_("divide by zero")); + BitVector_Empty(result); + return 1; + } else + BitVector_Divide(spare, op1, op2, result); + break; + case YASM_EXPR_SIGNMOD: + if (BitVector_is_empty(op2)) { + yasm_error_set(YASM_ERROR_ZERO_DIVISION, N_("divide by zero")); + BitVector_Empty(result); + return 1; + } else + BitVector_Divide(spare, op1, op2, result); + break; + case YASM_EXPR_NEG: + BitVector_Negate(result, op1); + break; + case YASM_EXPR_NOT: + Set_Complement(result, op1); + break; + case YASM_EXPR_OR: + Set_Union(result, op1, op2); + break; + case YASM_EXPR_AND: + Set_Intersection(result, op1, op2); + break; + case YASM_EXPR_XOR: + Set_ExclusiveOr(result, op1, op2); + break; + case YASM_EXPR_XNOR: + Set_ExclusiveOr(result, op1, op2); + Set_Complement(result, result); + break; + case YASM_EXPR_NOR: + Set_Union(result, op1, op2); + Set_Complement(result, result); + break; + case YASM_EXPR_SHL: + if (operand->type == INTNUM_L && operand->val.l >= 0) { + BitVector_Copy(result, op1); + BitVector_Move_Left(result, (N_int)operand->val.l); + } else /* don't even bother, just zero result */ + BitVector_Empty(result); + break; + case YASM_EXPR_SHR: + if (operand->type == INTNUM_L && operand->val.l >= 0) { + BitVector_Copy(result, op1); + carry = BitVector_msb_(op1); + count = (N_int)operand->val.l; + while (count-- > 0) + BitVector_shift_right(result, carry); + } else /* don't even bother, just zero result */ + BitVector_Empty(result); + break; + case YASM_EXPR_LOR: + BitVector_Empty(result); + BitVector_LSB(result, !BitVector_is_empty(op1) || + !BitVector_is_empty(op2)); + break; + case YASM_EXPR_LAND: + BitVector_Empty(result); + BitVector_LSB(result, !BitVector_is_empty(op1) && + !BitVector_is_empty(op2)); + break; + case YASM_EXPR_LNOT: + BitVector_Empty(result); + BitVector_LSB(result, BitVector_is_empty(op1)); + break; + case YASM_EXPR_LXOR: + BitVector_Empty(result); + BitVector_LSB(result, !BitVector_is_empty(op1) ^ + !BitVector_is_empty(op2)); + break; + case YASM_EXPR_LXNOR: + BitVector_Empty(result); + BitVector_LSB(result, !(!BitVector_is_empty(op1) ^ + !BitVector_is_empty(op2))); + break; + case YASM_EXPR_LNOR: + BitVector_Empty(result); + BitVector_LSB(result, !(!BitVector_is_empty(op1) || + !BitVector_is_empty(op2))); + break; + case YASM_EXPR_EQ: + BitVector_Empty(result); + BitVector_LSB(result, BitVector_equal(op1, op2)); + break; + case YASM_EXPR_LT: + BitVector_Empty(result); + BitVector_LSB(result, BitVector_Compare(op1, op2) < 0); + break; + case YASM_EXPR_GT: + BitVector_Empty(result); + BitVector_LSB(result, BitVector_Compare(op1, op2) > 0); + break; + case YASM_EXPR_LE: + BitVector_Empty(result); + BitVector_LSB(result, BitVector_Compare(op1, op2) <= 0); + break; + case YASM_EXPR_GE: + BitVector_Empty(result); + BitVector_LSB(result, BitVector_Compare(op1, op2) >= 0); + break; + case YASM_EXPR_NE: + BitVector_Empty(result); + BitVector_LSB(result, !BitVector_equal(op1, op2)); + break; + case YASM_EXPR_SEG: + yasm_error_set(YASM_ERROR_ARITHMETIC, N_("invalid use of '%s'"), + "SEG"); + break; + case YASM_EXPR_WRT: + yasm_error_set(YASM_ERROR_ARITHMETIC, N_("invalid use of '%s'"), + "WRT"); + break; + case YASM_EXPR_SEGOFF: + yasm_error_set(YASM_ERROR_ARITHMETIC, N_("invalid use of '%s'"), + ":"); + break; + case YASM_EXPR_IDENT: + if (result) + BitVector_Copy(result, op1); + break; + default: + yasm_error_set(YASM_ERROR_ARITHMETIC, + N_("invalid operation in intnum calculation")); + BitVector_Empty(result); + return 1; + } + + /* Try to fit the result into 32 bits if possible */ + if (acc->type == INTNUM_BV) + BitVector_Destroy(acc->val.bv); + intnum_frombv(acc, result); + return 0; +} +/*@=nullderef =nullpass =branchstate@*/ + +int +yasm_intnum_compare(const yasm_intnum *intn1, const yasm_intnum *intn2) +{ + wordptr op1, op2; + + if (intn1->type == INTNUM_L && intn2->type == INTNUM_L) { + if (intn1->val.l < intn2->val.l) + return -1; + if (intn1->val.l > intn2->val.l) + return 1; + return 0; + } + + op1 = intnum_tobv(op1static, intn1); + op2 = intnum_tobv(op2static, intn2); + return BitVector_Compare(op1, op2); +} + +void +yasm_intnum_zero(yasm_intnum *intn) +{ + yasm_intnum_set_int(intn, 0); +} + +void +yasm_intnum_set(yasm_intnum *intn, const yasm_intnum *val) +{ + if (intn->type == val->type) { + switch (val->type) { + case INTNUM_L: + intn->val.l = val->val.l; + break; + case INTNUM_BV: + BitVector_Copy(intn->val.bv, val->val.bv); + break; + } + } else { + switch (val->type) { + case INTNUM_L: + BitVector_Destroy(intn->val.bv); + intn->val.l = val->val.l; + break; + case INTNUM_BV: + intn->val.bv = BitVector_Clone(val->val.bv); + break; + } + intn->type = val->type; + } +} + +void +yasm_intnum_set_uint(yasm_intnum *intn, unsigned long val) +{ + if (val > LONG_MAX) { + if (intn->type != INTNUM_BV) { + intn->val.bv = BitVector_Create(BITVECT_NATIVE_SIZE, TRUE); + intn->type = INTNUM_BV; + } + BitVector_Chunk_Store(intn->val.bv, 32, 0, val); + } else { + if (intn->type == INTNUM_BV) { + BitVector_Destroy(intn->val.bv); + intn->type = INTNUM_L; + } + intn->val.l = (long)val; + } +} + +void +yasm_intnum_set_int(yasm_intnum *intn, long val) +{ + if (intn->type == INTNUM_BV) + BitVector_Destroy(intn->val.bv); + intn->type = INTNUM_L; + intn->val.l = val; +} + +int +yasm_intnum_is_zero(const yasm_intnum *intn) +{ + return (intn->type == INTNUM_L && intn->val.l == 0); +} + +int +yasm_intnum_is_pos1(const yasm_intnum *intn) +{ + return (intn->type == INTNUM_L && intn->val.l == 1); +} + +int +yasm_intnum_is_neg1(const yasm_intnum *intn) +{ + return (intn->type == INTNUM_L && intn->val.l == -1); +} + +int +yasm_intnum_sign(const yasm_intnum *intn) +{ + if (intn->type == INTNUM_L) { + if (intn->val.l == 0) + return 0; + else if (intn->val.l < 0) + return -1; + else + return 1; + } else + return BitVector_Sign(intn->val.bv); +} + +unsigned long +yasm_intnum_get_uint(const yasm_intnum *intn) +{ + switch (intn->type) { + case INTNUM_L: + if (intn->val.l < 0) + return 0; + return (unsigned long)intn->val.l; + case INTNUM_BV: + if (BitVector_msb_(intn->val.bv)) + return 0; + if (Set_Max(intn->val.bv) > 32) + return ULONG_MAX; + return BitVector_Chunk_Read(intn->val.bv, 32, 0); + default: + yasm_internal_error(N_("unknown intnum type")); + /*@notreached@*/ + return 0; + } +} + +long +yasm_intnum_get_int(const yasm_intnum *intn) +{ + switch (intn->type) { + case INTNUM_L: + return intn->val.l; + case INTNUM_BV: + if (BitVector_msb_(intn->val.bv)) { + /* it's negative: negate the bitvector to get a positive + * number, then negate the positive number. + */ + unsigned long ul; + + BitVector_Negate(conv_bv, intn->val.bv); + if (Set_Max(conv_bv) >= 32) { + /* too negative */ + return LONG_MIN; + } + ul = BitVector_Chunk_Read(conv_bv, 32, 0); + /* check for too negative */ + return (ul & 0x80000000) ? LONG_MIN : -((long)ul); + } + + /* it's positive, and since it's a BV, it must be >0x7FFFFFFF */ + return LONG_MAX; + default: + yasm_internal_error(N_("unknown intnum type")); + /*@notreached@*/ + return 0; + } +} + +void +yasm_intnum_get_sized(const yasm_intnum *intn, unsigned char *ptr, + size_t destsize, size_t valsize, int shift, + int bigendian, int warn) +{ + wordptr op1 = op1static, op2; + unsigned char *buf; + unsigned int len; + size_t rshift = shift < 0 ? (size_t)(-shift) : 0; + int carry_in; + + /* Currently don't support destinations larger than our native size */ + if (destsize*8 > BITVECT_NATIVE_SIZE) + yasm_internal_error(N_("destination too large")); + + /* General size warnings */ + if (warn<0 && !yasm_intnum_check_size(intn, valsize, rshift, 1)) + yasm_warn_set(YASM_WARN_GENERAL, + N_("value does not fit in signed %d bit field"), + valsize); + if (warn>0 && !yasm_intnum_check_size(intn, valsize, rshift, 2)) + yasm_warn_set(YASM_WARN_GENERAL, + N_("value does not fit in %d bit field"), valsize); + + /* Read the original data into a bitvect */ + if (bigendian) { + /* TODO */ + yasm_internal_error(N_("big endian not implemented")); + } else + BitVector_Block_Store(op1, ptr, (N_int)destsize); + + /* If not already a bitvect, convert value to be written to a bitvect */ + op2 = intnum_tobv(op2static, intn); + + /* Check low bits if right shifting and warnings enabled */ + if (warn && rshift > 0) { + BitVector_Copy(conv_bv, op2); + BitVector_Move_Left(conv_bv, (N_int)(BITVECT_NATIVE_SIZE-rshift)); + if (!BitVector_is_empty(conv_bv)) + yasm_warn_set(YASM_WARN_GENERAL, + N_("misaligned value, truncating to boundary")); + } + + /* Shift right if needed */ + if (rshift > 0) { + carry_in = BitVector_msb_(op2); + while (rshift-- > 0) + BitVector_shift_right(op2, carry_in); + shift = 0; + } + + /* Write the new value into the destination bitvect */ + BitVector_Interval_Copy(op1, op2, (unsigned int)shift, 0, (N_int)valsize); + + /* Write out the new data */ + buf = BitVector_Block_Read(op1, &len); + if (bigendian) { + /* TODO */ + yasm_internal_error(N_("big endian not implemented")); + } else + memcpy(ptr, buf, destsize); + yasm_xfree(buf); +} + +/* Return 1 if okay size, 0 if not */ +int +yasm_intnum_check_size(const yasm_intnum *intn, size_t size, size_t rshift, + int rangetype) +{ + wordptr val; + + /* If not already a bitvect, convert value to a bitvect */ + if (intn->type == INTNUM_BV) { + if (rshift > 0) { + val = conv_bv; + BitVector_Copy(val, intn->val.bv); + } else + val = intn->val.bv; + } else + val = intnum_tobv(conv_bv, intn); + + if (size >= BITVECT_NATIVE_SIZE) + return 1; + + if (rshift > 0) { + int carry_in = BitVector_msb_(val); + while (rshift-- > 0) + BitVector_shift_right(val, carry_in); + } + + if (rangetype > 0) { + if (BitVector_msb_(val)) { + /* it's negative */ + int retval; + + BitVector_Negate(conv_bv, val); + BitVector_dec(conv_bv, conv_bv); + retval = Set_Max(conv_bv) < (long)size-1; + + return retval; + } + + if (rangetype == 1) + size--; + } + return (Set_Max(val) < (long)size); +} + +int +yasm_intnum_in_range(const yasm_intnum *intn, long low, long high) +{ + wordptr val = intnum_tobv(result, intn); + wordptr lval = op1static; + wordptr hval = op2static; + + /* Convert high and low to bitvects */ + BitVector_Empty(lval); + if (low >= 0) + BitVector_Chunk_Store(lval, 32, 0, (unsigned long)low); + else { + BitVector_Chunk_Store(lval, 32, 0, (unsigned long)(-low)); + BitVector_Negate(lval, lval); + } + + BitVector_Empty(hval); + if (high >= 0) + BitVector_Chunk_Store(hval, 32, 0, (unsigned long)high); + else { + BitVector_Chunk_Store(hval, 32, 0, (unsigned long)(-high)); + BitVector_Negate(hval, hval); + } + + /* Compare! */ + return (BitVector_Compare(val, lval) >= 0 + && BitVector_Compare(val, hval) <= 0); +} + +static unsigned long +get_leb128(wordptr val, unsigned char *ptr, int sign) +{ + unsigned long i, size; + unsigned char *ptr_orig = ptr; + + if (sign) { + /* Signed mode */ + if (BitVector_msb_(val)) { + /* Negative */ + BitVector_Negate(conv_bv, val); + size = Set_Max(conv_bv)+2; + } else { + /* Positive */ + size = Set_Max(val)+2; + } + } else { + /* Unsigned mode */ + size = Set_Max(val)+1; + } + + /* Positive/Unsigned write */ + for (i=0; i<size; i += 7) { + *ptr = (unsigned char)BitVector_Chunk_Read(val, 7, i); + *ptr |= 0x80; + ptr++; + } + *(ptr-1) &= 0x7F; /* Clear MSB of last byte */ + return (unsigned long)(ptr-ptr_orig); +} + +static unsigned long +size_leb128(wordptr val, int sign) +{ + if (sign) { + /* Signed mode */ + if (BitVector_msb_(val)) { + /* Negative */ + BitVector_Negate(conv_bv, val); + return (Set_Max(conv_bv)+8)/7; + } else { + /* Positive */ + return (Set_Max(val)+8)/7; + } + } else { + /* Unsigned mode */ + return (Set_Max(val)+7)/7; + } +} + +unsigned long +yasm_intnum_get_leb128(const yasm_intnum *intn, unsigned char *ptr, int sign) +{ + wordptr val; + + /* Shortcut 0 */ + if (intn->type == INTNUM_L && intn->val.l == 0) { + *ptr = 0; + return 1; + } + + /* If not already a bitvect, convert value to be written to a bitvect */ + val = intnum_tobv(op1static, intn); + + return get_leb128(val, ptr, sign); +} + +unsigned long +yasm_intnum_size_leb128(const yasm_intnum *intn, int sign) +{ + wordptr val; + + /* Shortcut 0 */ + if (intn->type == INTNUM_L && intn->val.l == 0) { + return 1; + } + + /* If not already a bitvect, convert value to a bitvect */ + val = intnum_tobv(op1static, intn); + + return size_leb128(val, sign); +} + +unsigned long +yasm_get_sleb128(long v, unsigned char *ptr) +{ + wordptr val = op1static; + + /* Shortcut 0 */ + if (v == 0) { + *ptr = 0; + return 1; + } + + BitVector_Empty(val); + if (v >= 0) + BitVector_Chunk_Store(val, 32, 0, (unsigned long)v); + else { + BitVector_Chunk_Store(val, 32, 0, (unsigned long)(-v)); + BitVector_Negate(val, val); + } + return get_leb128(val, ptr, 1); +} + +unsigned long +yasm_size_sleb128(long v) +{ + wordptr val = op1static; + + if (v == 0) + return 1; + + BitVector_Empty(val); + if (v >= 0) + BitVector_Chunk_Store(val, 32, 0, (unsigned long)v); + else { + BitVector_Chunk_Store(val, 32, 0, (unsigned long)(-v)); + BitVector_Negate(val, val); + } + return size_leb128(val, 1); +} + +unsigned long +yasm_get_uleb128(unsigned long v, unsigned char *ptr) +{ + wordptr val = op1static; + + /* Shortcut 0 */ + if (v == 0) { + *ptr = 0; + return 1; + } + + BitVector_Empty(val); + BitVector_Chunk_Store(val, 32, 0, v); + return get_leb128(val, ptr, 0); +} + +unsigned long +yasm_size_uleb128(unsigned long v) +{ + wordptr val = op1static; + + if (v == 0) + return 1; + + BitVector_Empty(val); + BitVector_Chunk_Store(val, 32, 0, v); + return size_leb128(val, 0); +} + +char * +yasm_intnum_get_str(const yasm_intnum *intn) +{ + unsigned char *s; + + switch (intn->type) { + case INTNUM_L: + s = yasm_xmalloc(16); + sprintf((char *)s, "%ld", intn->val.l); + return (char *)s; + break; + case INTNUM_BV: + return (char *)BitVector_to_Dec(intn->val.bv); + break; + } + /*@notreached@*/ + return NULL; +} + +void +yasm_intnum_print(const yasm_intnum *intn, FILE *f) +{ + unsigned char *s; + + switch (intn->type) { + case INTNUM_L: + fprintf(f, "0x%lx", intn->val.l); + break; + case INTNUM_BV: + s = BitVector_to_Hex(intn->val.bv); + fprintf(f, "0x%s", (char *)s); + yasm_xfree(s); + break; + } +} diff --git a/contrib/tools/yasm/libyasm/intnum.h b/contrib/tools/yasm/libyasm/intnum.h new file mode 100644 index 0000000000..bec832cf31 --- /dev/null +++ b/contrib/tools/yasm/libyasm/intnum.h @@ -0,0 +1,340 @@ +/** + * \file libyasm/intnum.h + * \brief YASM integer number interface. + * + * \license + * 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: + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - 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. + * \endlicense + */ +#ifndef YASM_INTNUM_H +#define YASM_INTNUM_H + +#ifndef YASM_LIB_DECL +#define YASM_LIB_DECL +#endif + +/** Initialize intnum internal data structures. */ +YASM_LIB_DECL +void yasm_intnum_initialize(void); + +/** Clean up internal intnum allocations. */ +YASM_LIB_DECL +void yasm_intnum_cleanup(void); + +/** Create a new intnum from a decimal string. + * \param str decimal string + * \return Newly allocated intnum. + */ +YASM_LIB_DECL +/*@only@*/ yasm_intnum *yasm_intnum_create_dec(char *str); + +/** Create a new intnum from a binary string. + * \param str binary string + * \return Newly allocated intnum. + */ +YASM_LIB_DECL +/*@only@*/ yasm_intnum *yasm_intnum_create_bin(char *str); + +/** Create a new intnum from an octal string. + * \param str octal string + * \return Newly allocated intnum. + */ +YASM_LIB_DECL +/*@only@*/ yasm_intnum *yasm_intnum_create_oct(char *str); + +/** Create a new intnum from a hexidecimal string. + * \param str hexidecimal string + * \return Newly allocated intnum. + */ +YASM_LIB_DECL +/*@only@*/ yasm_intnum *yasm_intnum_create_hex(char *str); + +/** Convert character constant to integer value, using NASM rules. NASM syntax + * supports automatic conversion from strings such as 'abcd' to a 32-bit + * integer value (little endian order). This function performs those conversions. + * \param str character constant string + * \return Newly allocated intnum. + */ +YASM_LIB_DECL +/*@only@*/ yasm_intnum *yasm_intnum_create_charconst_nasm(const char *str); + +/** Convert character constant to integer value, using TASM rules. TASM syntax + * supports automatic conversion from strings such as 'abcd' to a 32-bit + * integer value (big endian order). This function performs those conversions. + * \param str character constant string + * \return Newly allocated intnum. + */ +YASM_LIB_DECL +/*@only@*/ yasm_intnum *yasm_intnum_create_charconst_tasm(const char *str); + +/** Create a new intnum from an unsigned integer value. + * \param i unsigned integer value + * \return Newly allocated intnum. + */ +YASM_LIB_DECL +/*@only@*/ yasm_intnum *yasm_intnum_create_uint(unsigned long i); + +/** Create a new intnum from an signed integer value. + * \param i signed integer value + * \return Newly allocated intnum. + */ +YASM_LIB_DECL +/*@only@*/ yasm_intnum *yasm_intnum_create_int(long i); + +/** Create a new intnum from LEB128-encoded form. + * \param ptr pointer to start of LEB128 encoded form + * \param sign signed (1) or unsigned (0) LEB128 format + * \param size number of bytes read from ptr (output) + * \return Newly allocated intnum. Number of bytes read returned into + * bytes_read parameter. + */ +YASM_LIB_DECL +/*@only@*/ yasm_intnum *yasm_intnum_create_leb128 + (const unsigned char *ptr, int sign, /*@out@*/ unsigned long *size); + +/** Create a new intnum from a little-endian or big-endian buffer. + * In little endian, the LSB is in ptr[0]. + * \param ptr pointer to start of buffer + * \param sign signed (1) or unsigned (0) source + * \param srcsize source buffer size (in bytes) + * \param bigendian endianness (nonzero=big, zero=little) + */ +YASM_LIB_DECL +/*@only@*/ yasm_intnum *yasm_intnum_create_sized + (unsigned char *ptr, int sign, size_t srcsize, int bigendian); + +/** Duplicate an intnum. + * \param intn intnum + * \return Newly allocated intnum with the same value as intn. + */ +YASM_LIB_DECL +/*@only@*/ yasm_intnum *yasm_intnum_copy(const yasm_intnum *intn); + +/** Destroy (free allocated memory for) an intnum. + * \param intn intnum + */ +YASM_LIB_DECL +void yasm_intnum_destroy(/*@only@*/ yasm_intnum *intn); + +/** Floating point calculation function: acc = acc op operand. + * \note Not all operations in yasm_expr_op may be supported; unsupported + * operations will result in an error. + * \param acc intnum accumulator + * \param op operation + * \param operand intnum operand + * \return Nonzero if error occurred. + */ +YASM_LIB_DECL +int yasm_intnum_calc(yasm_intnum *acc, yasm_expr_op op, yasm_intnum *operand); + +/** Compare two intnums. + * \param intn1 first intnum + * \param intn2 second intnum + * \return -1 if intn1 < intn2, 0 if intn1 == intn2, 1 if intn1 > intn2. + */ +YASM_LIB_DECL +int yasm_intnum_compare(const yasm_intnum *intn1, const yasm_intnum *intn2); + +/** Zero an intnum. + * \param intn intnum + */ +YASM_LIB_DECL +void yasm_intnum_zero(yasm_intnum *intn); + +/** Set an intnum to the value of another intnum. + * \param intn intnum + * \param val intnum to get value from + */ +YASM_LIB_DECL +void yasm_intnum_set(yasm_intnum *intn, const yasm_intnum *val); + +/** Set an intnum to an unsigned integer. + * \param intn intnum + * \param val integer value + */ +YASM_LIB_DECL +void yasm_intnum_set_uint(yasm_intnum *intn, unsigned long val); + +/** Set an intnum to an signed integer. + * \param intn intnum + * \param val integer value + */ +YASM_LIB_DECL +void yasm_intnum_set_int(yasm_intnum *intn, long val); + +/** Simple value check for 0. + * \param acc intnum + * \return Nonzero if acc==0. + */ +YASM_LIB_DECL +int yasm_intnum_is_zero(const yasm_intnum *acc); + +/** Simple value check for 1. + * \param acc intnum + * \return Nonzero if acc==1. + */ +YASM_LIB_DECL +int yasm_intnum_is_pos1(const yasm_intnum *acc); + +/** Simple value check for -1. + * \param acc intnum + * \return Nonzero if acc==-1. + */ +YASM_LIB_DECL +int yasm_intnum_is_neg1(const yasm_intnum *acc); + +/** Simple sign check. + * \param acc intnum + * \return -1 if negative, 0 if zero, +1 if positive + */ +YASM_LIB_DECL +int yasm_intnum_sign(const yasm_intnum *acc); + +/** Convert an intnum to an unsigned 32-bit value. The value is in "standard" + * C format (eg, of unknown endian). + * \note Parameter intnum is truncated to fit into 32 bits. Use + * intnum_check_size() to check for overflow. + * \param intn intnum + * \return Unsigned 32-bit value of intn. + */ +YASM_LIB_DECL +unsigned long yasm_intnum_get_uint(const yasm_intnum *intn); + +/** Convert an intnum to a signed 32-bit value. The value is in "standard" C + * format (eg, of unknown endian). + * \note Parameter intnum is truncated to fit into 32 bits. Use + * intnum_check_size() to check for overflow. + * \param intn intnum + * \return Signed 32-bit value of intn. + */ +YASM_LIB_DECL +long yasm_intnum_get_int(const yasm_intnum *intn); + +/** Output #yasm_intnum to buffer in little-endian or big-endian. Puts the + * value into the least significant bits of the destination, or may be shifted + * into more significant bits by the shift parameter. The destination bits are + * cleared before being set. [0] should be the first byte output to the file. + * \param intn intnum + * \param ptr pointer to storage for size bytes of output + * \param destsize destination size (in bytes) + * \param valsize size (in bits) + * \param shift left shift (in bits); may be negative to specify right + * shift (standard warnings include truncation to boundary) + * \param bigendian endianness (nonzero=big, zero=little) + * \param warn enables standard warnings (value doesn't fit into valsize + * bits): <0=signed warnings, >0=unsigned warnings, 0=no warn + */ +YASM_LIB_DECL +void yasm_intnum_get_sized(const yasm_intnum *intn, unsigned char *ptr, + size_t destsize, size_t valsize, int shift, + int bigendian, int warn); + +/** Check to see if intnum will fit without overflow into size bits. + * \param intn intnum + * \param size number of bits of output space + * \param rshift right shift + * \param rangetype signed/unsigned range selection: + * 0 => (0, unsigned max); + * 1 => (signed min, signed max); + * 2 => (signed min, unsigned max) + * \return Nonzero if intnum will fit. + */ +YASM_LIB_DECL +int yasm_intnum_check_size(const yasm_intnum *intn, size_t size, + size_t rshift, int rangetype); + +/** Check to see if intnum will fit into a particular numeric range. + * \param intn intnum + * \param low low end of range (inclusive) + * \param high high end of range (inclusive) + * \return Nonzero if intnum is within range. + */ +YASM_LIB_DECL +int yasm_intnum_in_range(const yasm_intnum *intn, long low, long high); + +/** Output #yasm_intnum to buffer in LEB128-encoded form. + * \param intn intnum + * \param ptr pointer to storage for output bytes + * \param sign signedness of LEB128 encoding (0=unsigned, 1=signed) + * \return Number of bytes generated. + */ +YASM_LIB_DECL +unsigned long yasm_intnum_get_leb128(const yasm_intnum *intn, + unsigned char *ptr, int sign); + +/** Calculate number of bytes LEB128-encoded form of #yasm_intnum will take. + * \param intn intnum + * \param sign signedness of LEB128 encoding (0=unsigned, 1=signed) + * \return Number of bytes. + */ +YASM_LIB_DECL +unsigned long yasm_intnum_size_leb128(const yasm_intnum *intn, int sign); + +/** Output integer to buffer in signed LEB128-encoded form. + * \param v integer + * \param ptr pointer to storage for output bytes + * \return Number of bytes generated. + */ +YASM_LIB_DECL +unsigned long yasm_get_sleb128(long v, unsigned char *ptr); + +/** Calculate number of bytes signed LEB128-encoded form of integer will take. + * \param v integer + * \return Number of bytes. + */ +YASM_LIB_DECL +unsigned long yasm_size_sleb128(long v); + +/** Output integer to buffer in unsigned LEB128-encoded form. + * \param v integer + * \param ptr pointer to storage for output bytes + * \return Number of bytes generated. + */ +YASM_LIB_DECL +unsigned long yasm_get_uleb128(unsigned long v, unsigned char *ptr); + +/** Calculate number of bytes unsigned LEB128-encoded form of integer will take. + * \param v integer + * \return Number of bytes. + */ +YASM_LIB_DECL +unsigned long yasm_size_uleb128(unsigned long v); + +/** Get an intnum as a signed decimal string. The returned string will + * contain a leading '-' if the intnum is negative. + * \param intn intnum + * \return Newly allocated string containing the decimal representation of + * the intnum. + */ +YASM_LIB_DECL +/*@only@*/ char *yasm_intnum_get_str(const yasm_intnum *intn); + +/** Print an intnum. For debugging purposes. + * \param f file + * \param intn intnum + */ +YASM_LIB_DECL +void yasm_intnum_print(const yasm_intnum *intn, FILE *f); + +#endif diff --git a/contrib/tools/yasm/libyasm/inttree.c b/contrib/tools/yasm/libyasm/inttree.c new file mode 100644 index 0000000000..2ae10e9b9c --- /dev/null +++ b/contrib/tools/yasm/libyasm/inttree.c @@ -0,0 +1,891 @@ +#include "util.h" + +#include <stdlib.h> +#include <stdio.h> +#include <limits.h> +#include <math.h> +#include "coretype.h" +#include "inttree.h" + +#define VERIFY(condition) \ +if (!(condition)) { \ +fprintf(stderr, "Assumption \"%s\"\nFailed in file %s: at line:%i\n", \ +#condition,__FILE__,__LINE__); \ +abort();} + +/*#define DEBUG_ASSERT 1*/ + +#ifdef DEBUG_ASSERT +static void Assert(int assertion, const char *error) +{ + if (!assertion) { + fprintf(stderr, "Assertion Failed: %s\n", error); + abort(); + } +} +#endif + +/* If the symbol CHECK_INTERVAL_TREE_ASSUMPTIONS is defined then the + * code does a lot of extra checking to make sure certain assumptions + * are satisfied. This only needs to be done if you suspect bugs are + * present or if you make significant changes and want to make sure + * your changes didn't mess anything up. + */ +/*#define CHECK_INTERVAL_TREE_ASSUMPTIONS 1*/ + +static IntervalTreeNode *ITN_create(long low, long high, void *data); + +static void LeftRotate(IntervalTree *, IntervalTreeNode *); +static void RightRotate(IntervalTree *, IntervalTreeNode *); +static void TreeInsertHelp(IntervalTree *, IntervalTreeNode *); +static void TreePrintHelper(const IntervalTree *, IntervalTreeNode *); +static void FixUpMaxHigh(IntervalTree *, IntervalTreeNode *); +static void DeleteFixUp(IntervalTree *, IntervalTreeNode *); +#ifdef CHECK_INTERVAL_TREE_ASSUMPTIONS +static void CheckMaxHighFields(const IntervalTree *, IntervalTreeNode *); +static int CheckMaxHighFieldsHelper(const IntervalTree *, IntervalTreeNode *y, + const int currentHigh, int match); +static void IT_CheckAssumptions(const IntervalTree *); +#endif + +/* define a function to find the maximum of two objects. */ +#define ITMax(a, b) ( (a > b) ? a : b ) + +IntervalTreeNode * +ITN_create(long low, long high, void *data) +{ + IntervalTreeNode *itn = yasm_xmalloc(sizeof(IntervalTreeNode)); + itn->data = data; + if (low < high) { + itn->low = low; + itn->high = high; + } else { + itn->low = high; + itn->high = low; + } + itn->maxHigh = high; + return itn; +} + +IntervalTree * +IT_create(void) +{ + IntervalTree *it = yasm_xmalloc(sizeof(IntervalTree)); + + it->nil = ITN_create(LONG_MIN, LONG_MIN, NULL); + it->nil->left = it->nil; + it->nil->right = it->nil; + it->nil->parent = it->nil; + it->nil->red = 0; + + it->root = ITN_create(LONG_MAX, LONG_MAX, NULL); + it->root->left = it->nil; + it->root->right = it->nil; + it->root->parent = it->nil; + it->root->red = 0; + + /* the following are used for the Enumerate function */ + it->recursionNodeStackSize = 128; + it->recursionNodeStack = (it_recursion_node *) + yasm_xmalloc(it->recursionNodeStackSize*sizeof(it_recursion_node)); + it->recursionNodeStackTop = 1; + it->recursionNodeStack[0].start_node = NULL; + + return it; +} + +/***********************************************************************/ +/* FUNCTION: LeftRotate */ +/**/ +/* INPUTS: the node to rotate on */ +/**/ +/* OUTPUT: None */ +/**/ +/* Modifies Input: this, x */ +/**/ +/* EFFECTS: Rotates as described in _Introduction_To_Algorithms by */ +/* Cormen, Leiserson, Rivest (Chapter 14). Basically this */ +/* makes the parent of x be to the left of x, x the parent of */ +/* its parent before the rotation and fixes other pointers */ +/* accordingly. Also updates the maxHigh fields of x and y */ +/* after rotation. */ +/***********************************************************************/ + +static void +LeftRotate(IntervalTree *it, IntervalTreeNode *x) +{ + IntervalTreeNode *y; + + /* I originally wrote this function to use the sentinel for + * nil to avoid checking for nil. However this introduces a + * very subtle bug because sometimes this function modifies + * the parent pointer of nil. This can be a problem if a + * function which calls LeftRotate also uses the nil sentinel + * and expects the nil sentinel's parent pointer to be unchanged + * after calling this function. For example, when DeleteFixUP + * calls LeftRotate it expects the parent pointer of nil to be + * unchanged. + */ + + y=x->right; + x->right=y->left; + + if (y->left != it->nil) + y->left->parent=x; /* used to use sentinel here */ + /* and do an unconditional assignment instead of testing for nil */ + + y->parent=x->parent; + + /* Instead of checking if x->parent is the root as in the book, we + * count on the root sentinel to implicitly take care of this case + */ + if (x == x->parent->left) + x->parent->left=y; + else + x->parent->right=y; + y->left=x; + x->parent=y; + + x->maxHigh=ITMax(x->left->maxHigh,ITMax(x->right->maxHigh,x->high)); + y->maxHigh=ITMax(x->maxHigh,ITMax(y->right->maxHigh,y->high)); +#ifdef CHECK_INTERVAL_TREE_ASSUMPTIONS + IT_CheckAssumptions(it); +#elif defined(DEBUG_ASSERT) + Assert(!it->nil->red,"nil not red in ITLeftRotate"); + Assert((it->nil->maxHigh=LONG_MIN), + "nil->maxHigh != LONG_MIN in ITLeftRotate"); +#endif +} + + +/***********************************************************************/ +/* FUNCTION: RightRotate */ +/**/ +/* INPUTS: node to rotate on */ +/**/ +/* OUTPUT: None */ +/**/ +/* Modifies Input?: this, y */ +/**/ +/* EFFECTS: Rotates as described in _Introduction_To_Algorithms by */ +/* Cormen, Leiserson, Rivest (Chapter 14). Basically this */ +/* makes the parent of x be to the left of x, x the parent of */ +/* its parent before the rotation and fixes other pointers */ +/* accordingly. Also updates the maxHigh fields of x and y */ +/* after rotation. */ +/***********************************************************************/ + + +static void +RightRotate(IntervalTree *it, IntervalTreeNode *y) +{ + IntervalTreeNode *x; + + /* I originally wrote this function to use the sentinel for + * nil to avoid checking for nil. However this introduces a + * very subtle bug because sometimes this function modifies + * the parent pointer of nil. This can be a problem if a + * function which calls LeftRotate also uses the nil sentinel + * and expects the nil sentinel's parent pointer to be unchanged + * after calling this function. For example, when DeleteFixUP + * calls LeftRotate it expects the parent pointer of nil to be + * unchanged. + */ + + x=y->left; + y->left=x->right; + + if (it->nil != x->right) + x->right->parent=y; /*used to use sentinel here */ + /* and do an unconditional assignment instead of testing for nil */ + + /* Instead of checking if x->parent is the root as in the book, we + * count on the root sentinel to implicitly take care of this case + */ + x->parent=y->parent; + if (y == y->parent->left) + y->parent->left=x; + else + y->parent->right=x; + x->right=y; + y->parent=x; + + y->maxHigh=ITMax(y->left->maxHigh,ITMax(y->right->maxHigh,y->high)); + x->maxHigh=ITMax(x->left->maxHigh,ITMax(y->maxHigh,x->high)); +#ifdef CHECK_INTERVAL_TREE_ASSUMPTIONS + IT_CheckAssumptions(it); +#elif defined(DEBUG_ASSERT) + Assert(!it->nil->red,"nil not red in ITRightRotate"); + Assert((it->nil->maxHigh=LONG_MIN), + "nil->maxHigh != LONG_MIN in ITRightRotate"); +#endif +} + +/***********************************************************************/ +/* FUNCTION: TreeInsertHelp */ +/**/ +/* INPUTS: z is the node to insert */ +/**/ +/* OUTPUT: none */ +/**/ +/* Modifies Input: this, z */ +/**/ +/* EFFECTS: Inserts z into the tree as if it were a regular binary tree */ +/* using the algorithm described in _Introduction_To_Algorithms_ */ +/* by Cormen et al. This funciton is only intended to be called */ +/* by the InsertTree function and not by the user */ +/***********************************************************************/ + +static void +TreeInsertHelp(IntervalTree *it, IntervalTreeNode *z) +{ + /* This function should only be called by InsertITTree (see above) */ + IntervalTreeNode* x; + IntervalTreeNode* y; + + z->left=z->right=it->nil; + y=it->root; + x=it->root->left; + while( x != it->nil) { + y=x; + if (x->low > z->low) + x=x->left; + else /* x->low <= z->low */ + x=x->right; + } + z->parent=y; + if ((y == it->root) || (y->low > z->low)) + y->left=z; + else + y->right=z; + +#if defined(DEBUG_ASSERT) + Assert(!it->nil->red,"nil not red in ITTreeInsertHelp"); + Assert((it->nil->maxHigh=INT_MIN), + "nil->maxHigh != INT_MIN in ITTreeInsertHelp"); +#endif +} + + +/***********************************************************************/ +/* FUNCTION: FixUpMaxHigh */ +/**/ +/* INPUTS: x is the node to start from*/ +/**/ +/* OUTPUT: none */ +/**/ +/* Modifies Input: this */ +/**/ +/* EFFECTS: Travels up to the root fixing the maxHigh fields after */ +/* an insertion or deletion */ +/***********************************************************************/ + +static void +FixUpMaxHigh(IntervalTree *it, IntervalTreeNode *x) +{ + while(x != it->root) { + x->maxHigh=ITMax(x->high,ITMax(x->left->maxHigh,x->right->maxHigh)); + x=x->parent; + } +#ifdef CHECK_INTERVAL_TREE_ASSUMPTIONS + IT_CheckAssumptions(it); +#endif +} + +/* Before calling InsertNode the node x should have its key set */ + +/***********************************************************************/ +/* FUNCTION: InsertNode */ +/**/ +/* INPUTS: newInterval is the interval to insert*/ +/**/ +/* OUTPUT: This function returns a pointer to the newly inserted node */ +/* which is guarunteed to be valid until this node is deleted. */ +/* What this means is if another data structure stores this */ +/* pointer then the tree does not need to be searched when this */ +/* is to be deleted. */ +/**/ +/* Modifies Input: tree */ +/**/ +/* EFFECTS: Creates a node node which contains the appropriate key and */ +/* info pointers and inserts it into the tree. */ +/***********************************************************************/ + +IntervalTreeNode * +IT_insert(IntervalTree *it, long low, long high, void *data) +{ + IntervalTreeNode *x, *y, *newNode; + + x = ITN_create(low, high, data); + TreeInsertHelp(it, x); + FixUpMaxHigh(it, x->parent); + newNode = x; + x->red=1; + while(x->parent->red) { /* use sentinel instead of checking for root */ + if (x->parent == x->parent->parent->left) { + y=x->parent->parent->right; + if (y->red) { + x->parent->red=0; + y->red=0; + x->parent->parent->red=1; + x=x->parent->parent; + } else { + if (x == x->parent->right) { + x=x->parent; + LeftRotate(it, x); + } + x->parent->red=0; + x->parent->parent->red=1; + RightRotate(it, x->parent->parent); + } + } else { /* case for x->parent == x->parent->parent->right */ + /* this part is just like the section above with */ + /* left and right interchanged */ + y=x->parent->parent->left; + if (y->red) { + x->parent->red=0; + y->red=0; + x->parent->parent->red=1; + x=x->parent->parent; + } else { + if (x == x->parent->left) { + x=x->parent; + RightRotate(it, x); + } + x->parent->red=0; + x->parent->parent->red=1; + LeftRotate(it, x->parent->parent); + } + } + } + it->root->left->red=0; + +#ifdef CHECK_INTERVAL_TREE_ASSUMPTIONS + IT_CheckAssumptions(it); +#elif defined(DEBUG_ASSERT) + Assert(!it->nil->red,"nil not red in ITTreeInsert"); + Assert(!it->root->red,"root not red in ITTreeInsert"); + Assert((it->nil->maxHigh=LONG_MIN), + "nil->maxHigh != LONG_MIN in ITTreeInsert"); +#endif + return newNode; +} + +/***********************************************************************/ +/* FUNCTION: GetSuccessorOf */ +/**/ +/* INPUTS: x is the node we want the succesor of */ +/**/ +/* OUTPUT: This function returns the successor of x or NULL if no */ +/* successor exists. */ +/**/ +/* Modifies Input: none */ +/**/ +/* Note: uses the algorithm in _Introduction_To_Algorithms_ */ +/***********************************************************************/ + +IntervalTreeNode * +IT_get_successor(const IntervalTree *it, IntervalTreeNode *x) +{ + IntervalTreeNode *y; + + if (it->nil != (y = x->right)) { /* assignment to y is intentional */ + while(y->left != it->nil) /* returns the minium of the right subtree of x */ + y=y->left; + return y; + } else { + y=x->parent; + while(x == y->right) { /* sentinel used instead of checking for nil */ + x=y; + y=y->parent; + } + if (y == it->root) + return(it->nil); + return y; + } +} + +/***********************************************************************/ +/* FUNCTION: GetPredecessorOf */ +/**/ +/* INPUTS: x is the node to get predecessor of */ +/**/ +/* OUTPUT: This function returns the predecessor of x or NULL if no */ +/* predecessor exists. */ +/**/ +/* Modifies Input: none */ +/**/ +/* Note: uses the algorithm in _Introduction_To_Algorithms_ */ +/***********************************************************************/ + +IntervalTreeNode * +IT_get_predecessor(const IntervalTree *it, IntervalTreeNode *x) +{ + IntervalTreeNode *y; + + if (it->nil != (y = x->left)) { /* assignment to y is intentional */ + while(y->right != it->nil) /* returns the maximum of the left subtree of x */ + y=y->right; + return y; + } else { + y=x->parent; + while(x == y->left) { + if (y == it->root) + return(it->nil); + x=y; + y=y->parent; + } + return y; + } +} + +/***********************************************************************/ +/* FUNCTION: Print */ +/**/ +/* INPUTS: none */ +/**/ +/* OUTPUT: none */ +/**/ +/* EFFECTS: This function recursively prints the nodes of the tree */ +/* inorder. */ +/**/ +/* Modifies Input: none */ +/**/ +/* Note: This function should only be called from ITTreePrint */ +/***********************************************************************/ + +static void +ITN_print(const IntervalTreeNode *itn, IntervalTreeNode *nil, + IntervalTreeNode *root) +{ + printf(", l=%li, h=%li, mH=%li", itn->low, itn->high, itn->maxHigh); + printf(" l->low="); + if (itn->left == nil) + printf("NULL"); + else + printf("%li", itn->left->low); + printf(" r->low="); + if (itn->right == nil) + printf("NULL"); + else + printf("%li", itn->right->low); + printf(" p->low="); + if (itn->parent == root) + printf("NULL"); + else + printf("%li", itn->parent->low); + printf(" red=%i\n", itn->red); +} + +static void +TreePrintHelper(const IntervalTree *it, IntervalTreeNode *x) +{ + if (x != it->nil) { + TreePrintHelper(it, x->left); + ITN_print(x, it->nil, it->root); + TreePrintHelper(it, x->right); + } +} + +void +IT_destroy(IntervalTree *it) +{ + IntervalTreeNode *x = it->root->left; + SLIST_HEAD(node_head, nodeent) + stuffToFree = SLIST_HEAD_INITIALIZER(stuffToFree); + struct nodeent { + SLIST_ENTRY(nodeent) link; + struct IntervalTreeNode *node; + } *np; + + if (x != it->nil) { + if (x->left != it->nil) { + np = yasm_xmalloc(sizeof(struct nodeent)); + np->node = x->left; + SLIST_INSERT_HEAD(&stuffToFree, np, link); + } + if (x->right != it->nil) { + np = yasm_xmalloc(sizeof(struct nodeent)); + np->node = x->right; + SLIST_INSERT_HEAD(&stuffToFree, np, link); + } + yasm_xfree(x); + while (!SLIST_EMPTY(&stuffToFree)) { + np = SLIST_FIRST(&stuffToFree); + x = np->node; + SLIST_REMOVE_HEAD(&stuffToFree, link); + yasm_xfree(np); + + if (x->left != it->nil) { + np = yasm_xmalloc(sizeof(struct nodeent)); + np->node = x->left; + SLIST_INSERT_HEAD(&stuffToFree, np, link); + } + if (x->right != it->nil) { + np = yasm_xmalloc(sizeof(struct nodeent)); + np->node = x->right; + SLIST_INSERT_HEAD(&stuffToFree, np, link); + } + yasm_xfree(x); + } + } + + yasm_xfree(it->nil); + yasm_xfree(it->root); + yasm_xfree(it->recursionNodeStack); + yasm_xfree(it); +} + + +/***********************************************************************/ +/* FUNCTION: Print */ +/**/ +/* INPUTS: none */ +/**/ +/* OUTPUT: none */ +/**/ +/* EFFECT: This function recursively prints the nodes of the tree */ +/* inorder. */ +/**/ +/* Modifies Input: none */ +/**/ +/***********************************************************************/ + +void +IT_print(const IntervalTree *it) +{ + TreePrintHelper(it, it->root->left); +} + +/***********************************************************************/ +/* FUNCTION: DeleteFixUp */ +/**/ +/* INPUTS: x is the child of the spliced */ +/* out node in DeleteNode. */ +/**/ +/* OUTPUT: none */ +/**/ +/* EFFECT: Performs rotations and changes colors to restore red-black */ +/* properties after a node is deleted */ +/**/ +/* Modifies Input: this, x */ +/**/ +/* The algorithm from this function is from _Introduction_To_Algorithms_ */ +/***********************************************************************/ + +static void +DeleteFixUp(IntervalTree *it, IntervalTreeNode *x) +{ + IntervalTreeNode *w; + IntervalTreeNode *rootLeft = it->root->left; + + while ((!x->red) && (rootLeft != x)) { + if (x == x->parent->left) { + w=x->parent->right; + if (w->red) { + w->red=0; + x->parent->red=1; + LeftRotate(it, x->parent); + w=x->parent->right; + } + if ( (!w->right->red) && (!w->left->red) ) { + w->red=1; + x=x->parent; + } else { + if (!w->right->red) { + w->left->red=0; + w->red=1; + RightRotate(it, w); + w=x->parent->right; + } + w->red=x->parent->red; + x->parent->red=0; + w->right->red=0; + LeftRotate(it, x->parent); + x=rootLeft; /* this is to exit while loop */ + } + } else { /* the code below is has left and right switched from above */ + w=x->parent->left; + if (w->red) { + w->red=0; + x->parent->red=1; + RightRotate(it, x->parent); + w=x->parent->left; + } + if ((!w->right->red) && (!w->left->red)) { + w->red=1; + x=x->parent; + } else { + if (!w->left->red) { + w->right->red=0; + w->red=1; + LeftRotate(it, w); + w=x->parent->left; + } + w->red=x->parent->red; + x->parent->red=0; + w->left->red=0; + RightRotate(it, x->parent); + x=rootLeft; /* this is to exit while loop */ + } + } + } + x->red=0; + +#ifdef CHECK_INTERVAL_TREE_ASSUMPTIONS + IT_CheckAssumptions(it); +#elif defined(DEBUG_ASSERT) + Assert(!it->nil->red,"nil not black in ITDeleteFixUp"); + Assert((it->nil->maxHigh=LONG_MIN), + "nil->maxHigh != LONG_MIN in ITDeleteFixUp"); +#endif +} + + +/***********************************************************************/ +/* FUNCTION: DeleteNode */ +/**/ +/* INPUTS: tree is the tree to delete node z from */ +/**/ +/* OUTPUT: returns the Interval stored at deleted node */ +/**/ +/* EFFECT: Deletes z from tree and but don't call destructor */ +/* Then calls FixUpMaxHigh to fix maxHigh fields then calls */ +/* ITDeleteFixUp to restore red-black properties */ +/**/ +/* Modifies Input: z */ +/**/ +/* The algorithm from this function is from _Introduction_To_Algorithms_ */ +/***********************************************************************/ + +void * +IT_delete_node(IntervalTree *it, IntervalTreeNode *z, long *low, long *high) +{ + IntervalTreeNode *x, *y; + void *returnValue = z->data; + if (low) + *low = z->low; + if (high) + *high = z->high; + + y= ((z->left == it->nil) || (z->right == it->nil)) ? + z : IT_get_successor(it, z); + x= (y->left == it->nil) ? y->right : y->left; + if (it->root == (x->parent = y->parent)) + /* assignment of y->p to x->p is intentional */ + it->root->left=x; + else { + if (y == y->parent->left) + y->parent->left=x; + else + y->parent->right=x; + } + if (y != z) { /* y should not be nil in this case */ + +#ifdef DEBUG_ASSERT + Assert( (y!=it->nil),"y is nil in DeleteNode \n"); +#endif + /* y is the node to splice out and x is its child */ + + y->maxHigh = INT_MIN; + y->left=z->left; + y->right=z->right; + y->parent=z->parent; + z->left->parent=z->right->parent=y; + if (z == z->parent->left) + z->parent->left=y; + else + z->parent->right=y; + FixUpMaxHigh(it, x->parent); + if (!(y->red)) { + y->red = z->red; + DeleteFixUp(it, x); + } else + y->red = z->red; + yasm_xfree(z); +#ifdef CHECK_INTERVAL_TREE_ASSUMPTIONS + IT_CheckAssumptions(it); +#elif defined(DEBUG_ASSERT) + Assert(!it->nil->red,"nil not black in ITDelete"); + Assert((it->nil->maxHigh=LONG_MIN),"nil->maxHigh != LONG_MIN in ITDelete"); +#endif + } else { + FixUpMaxHigh(it, x->parent); + if (!(y->red)) + DeleteFixUp(it, x); + yasm_xfree(y); +#ifdef CHECK_INTERVAL_TREE_ASSUMPTIONS + IT_CheckAssumptions(it); +#elif defined(DEBUG_ASSERT) + Assert(!it->nil->red,"nil not black in ITDelete"); + Assert((it->nil->maxHigh=LONG_MIN),"nil->maxHigh != LONG_MIN in ITDelete"); +#endif + } + return returnValue; +} + + +/***********************************************************************/ +/* FUNCTION: Overlap */ +/**/ +/* INPUTS: [a1,a2] and [b1,b2] are the low and high endpoints of two */ +/* closed intervals. */ +/**/ +/* OUTPUT: stack containing pointers to the nodes between [low,high] */ +/**/ +/* Modifies Input: none */ +/**/ +/* EFFECT: returns 1 if the intervals overlap, and 0 otherwise */ +/***********************************************************************/ + +static int +Overlap(int a1, int a2, int b1, int b2) +{ + if (a1 <= b1) + return (b1 <= a2); + else + return (a1 <= b2); +} + + +/***********************************************************************/ +/* FUNCTION: Enumerate */ +/**/ +/* INPUTS: tree is the tree to look for intervals overlapping the */ +/* closed interval [low,high] */ +/**/ +/* OUTPUT: stack containing pointers to the nodes overlapping */ +/* [low,high] */ +/**/ +/* Modifies Input: none */ +/**/ +/* EFFECT: Returns a stack containing pointers to nodes containing */ +/* intervals which overlap [low,high] in O(max(N,k*log(N))) */ +/* where N is the number of intervals in the tree and k is */ +/* the number of overlapping intervals */ +/**/ +/* Note: This basic idea for this function comes from the */ +/* _Introduction_To_Algorithms_ book by Cormen et al, but */ +/* modifications were made to return all overlapping intervals */ +/* instead of just the first overlapping interval as in the */ +/* book. The natural way to do this would require recursive */ +/* calls of a basic search function. I translated the */ +/* recursive version into an interative version with a stack */ +/* as described below. */ +/***********************************************************************/ + + + +/* The basic idea for the function below is to take the IntervalSearch + * function from the book and modify to find all overlapping intervals + * instead of just one. This means that any time we take the left + * branch down the tree we must also check the right branch if and only if + * we find an overlapping interval in that left branch. Note this is a + * recursive condition because if we go left at the root then go left + * again at the first left child and find an overlap in the left subtree + * of the left child of root we must recursively check the right subtree + * of the left child of root as well as the right child of root. + */ +void +IT_enumerate(IntervalTree *it, long low, long high, void *cbd, + void (*callback) (IntervalTreeNode *node, void *cbd)) +{ + IntervalTreeNode *x=it->root->left; + int stuffToDo = (x != it->nil); + + /* Possible speed up: add min field to prune right searches */ + +#ifdef DEBUG_ASSERT + Assert((it->recursionNodeStackTop == 1), + "recursionStack not empty when entering IntervalTree::Enumerate"); +#endif + it->currentParent = 0; + + while (stuffToDo) { + if (Overlap(low,high,x->low,x->high) ) { + callback(x, cbd); + it->recursionNodeStack[it->currentParent].tryRightBranch=1; + } + if(x->left->maxHigh >= low) { /* implies x != nil */ + if (it->recursionNodeStackTop == it->recursionNodeStackSize) { + it->recursionNodeStackSize *= 2; + it->recursionNodeStack = (it_recursion_node *) + yasm_xrealloc(it->recursionNodeStack, + it->recursionNodeStackSize * sizeof(it_recursion_node)); + } + it->recursionNodeStack[it->recursionNodeStackTop].start_node = x; + it->recursionNodeStack[it->recursionNodeStackTop].tryRightBranch = 0; + it->recursionNodeStack[it->recursionNodeStackTop].parentIndex = it->currentParent; + it->currentParent = it->recursionNodeStackTop++; + x = x->left; + } else { + x = x->right; + } + stuffToDo = (x != it->nil); + while (!stuffToDo && (it->recursionNodeStackTop > 1)) { + if (it->recursionNodeStack[--it->recursionNodeStackTop].tryRightBranch) { + x=it->recursionNodeStack[it->recursionNodeStackTop].start_node->right; + it->currentParent=it->recursionNodeStack[it->recursionNodeStackTop].parentIndex; + it->recursionNodeStack[it->currentParent].tryRightBranch=1; + stuffToDo = (x != it->nil); + } + } + } +#ifdef DEBUG_ASSERT + Assert((it->recursionNodeStackTop == 1), + "recursionStack not empty when exiting IntervalTree::Enumerate"); +#endif +} + +#ifdef CHECK_INTERVAL_TREE_ASSUMPTIONS + +static int +CheckMaxHighFieldsHelper(const IntervalTree *it, IntervalTreeNode *y, + int currentHigh, int match) +{ + if (y != it->nil) { + match = CheckMaxHighFieldsHelper(it, y->left, currentHigh, match) ? + 1 : match; + VERIFY(y->high <= currentHigh); + if (y->high == currentHigh) + match = 1; + match = CheckMaxHighFieldsHelper(it, y->right, currentHigh, match) ? + 1 : match; + } + return match; +} + + + +/* Make sure the maxHigh fields for everything makes sense. * + * If something is wrong, print a warning and exit */ +static void +CheckMaxHighFields(const IntervalTree *it, IntervalTreeNode *x) +{ + if (x != it->nil) { + CheckMaxHighFields(it, x->left); + if(!(CheckMaxHighFieldsHelper(it, x, x->maxHigh, 0) > 0)) { + fprintf(stderr, "error found in CheckMaxHighFields.\n"); + abort(); + } + CheckMaxHighFields(it, x->right); + } +} + +static void +IT_CheckAssumptions(const IntervalTree *it) +{ + VERIFY(it->nil->low == INT_MIN); + VERIFY(it->nil->high == INT_MIN); + VERIFY(it->nil->maxHigh == INT_MIN); + VERIFY(it->root->low == INT_MAX); + VERIFY(it->root->high == INT_MAX); + VERIFY(it->root->maxHigh == INT_MAX); + VERIFY(it->nil->data == NULL); + VERIFY(it->root->data == NULL); + VERIFY(it->nil->red == 0); + VERIFY(it->root->red == 0); + CheckMaxHighFields(it, it->root->left); +} +#endif + diff --git a/contrib/tools/yasm/libyasm/inttree.h b/contrib/tools/yasm/libyasm/inttree.h new file mode 100644 index 0000000000..f7a7651512 --- /dev/null +++ b/contrib/tools/yasm/libyasm/inttree.h @@ -0,0 +1,70 @@ +#ifndef YASM_INTTREE_H +#define YASM_INTTREE_H + +#ifndef YASM_LIB_DECL +#define YASM_LIB_DECL +#endif + +/* The interval_tree.h and interval_tree.cc files contain code for + * interval trees implemented using red-black-trees as described in + * the book _Introduction_To_Algorithms_ by Cormen, Leisserson, + * and Rivest. + */ + +typedef struct IntervalTreeNode { + struct IntervalTreeNode *left, *right, *parent; + void *data; + long low; + long high; + long maxHigh; + int red; /* if red=0 then the node is black */ +} IntervalTreeNode; + +typedef struct it_recursion_node { + /* This structure stores the information needed when we take the + * right branch in searching for intervals but possibly come back + * and check the left branch as well. + */ + IntervalTreeNode *start_node; + unsigned int parentIndex; + int tryRightBranch; +} it_recursion_node; + +typedef struct IntervalTree { + /* A sentinel is used for root and for nil. These sentinels are + * created when ITTreeCreate is called. root->left should always + * point to the node which is the root of the tree. nil points to a + * node which should always be black but has aribtrary children and + * parent and no key or info. The point of using these sentinels is so + * that the root and nil nodes do not require special cases in the code + */ + IntervalTreeNode *root; + IntervalTreeNode *nil; + +/*private:*/ + unsigned int recursionNodeStackSize; + it_recursion_node * recursionNodeStack; + unsigned int currentParent; + unsigned int recursionNodeStackTop; +} IntervalTree; + +YASM_LIB_DECL +IntervalTree *IT_create(void); +YASM_LIB_DECL +void IT_destroy(IntervalTree *); +YASM_LIB_DECL +void IT_print(const IntervalTree *); +YASM_LIB_DECL +void *IT_delete_node(IntervalTree *, IntervalTreeNode *, long *low, + long *high); +YASM_LIB_DECL +IntervalTreeNode *IT_insert(IntervalTree *, long low, long high, void *data); +YASM_LIB_DECL +IntervalTreeNode *IT_get_predecessor(const IntervalTree *, IntervalTreeNode *); +YASM_LIB_DECL +IntervalTreeNode *IT_get_successor(const IntervalTree *, IntervalTreeNode *); +YASM_LIB_DECL +void IT_enumerate(IntervalTree *, long low, long high, void *cbd, + void (*callback) (IntervalTreeNode *node, void *cbd)); + +#endif diff --git a/contrib/tools/yasm/libyasm/linemap.c b/contrib/tools/yasm/libyasm/linemap.c new file mode 100644 index 0000000000..42201d3c07 --- /dev/null +++ b/contrib/tools/yasm/libyasm/linemap.c @@ -0,0 +1,293 @@ +/* + * YASM assembler virtual line mapping handling (for parse stage) + * + * 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 "coretype.h" +#include "hamt.h" + +#include "errwarn.h" +#include "linemap.h" + + +typedef struct line_mapping { + /* monotonically increasing virtual line */ + unsigned long line; + + /* related info */ + /* "original" source filename */ + /*@null@*/ /*@dependent@*/ const char *filename; + /* "original" source base line number */ + unsigned long file_line; + /* "original" source line number increment (for following lines) */ + unsigned long line_inc; +} line_mapping; + +typedef struct line_source_info { + /* first bytecode on line; NULL if no bytecodes on line */ + /*@null@*/ /*@dependent@*/ yasm_bytecode *bc; + + /* source code line */ + /*@owned@*/ char *source; +} line_source_info; + +struct yasm_linemap { + /* Shared storage for filenames */ + /*@only@*/ /*@null@*/ HAMT *filenames; + + /* Current virtual line number. */ + unsigned long current; + + /* Mappings from virtual to physical line numbers */ + struct line_mapping *map_vector; + unsigned long map_size; + unsigned long map_allocated; + + /* Bytecode and source line information */ + /*@only@*/ line_source_info *source_info; + size_t source_info_size; +}; + +static void +filename_delete_one(/*@only@*/ void *d) +{ + yasm_xfree(d); +} + +void +yasm_linemap_set(yasm_linemap *linemap, const char *filename, + unsigned long virtual_line, unsigned long file_line, + unsigned long line_inc) +{ + char *copy; + unsigned long i; + int replace = 0; + line_mapping *mapping = NULL; + + if (virtual_line == 0) { + virtual_line = linemap->current; + } + + /* Replace all existing mappings that have line numbers >= this one. */ + for (i = linemap->map_size; i > 0; i--) { + if (linemap->map_vector[i-1].line < virtual_line) { + if (i < linemap->map_size) { + mapping = &linemap->map_vector[i]; + linemap->map_size = i + 1; + } + break; + } + } + + if (mapping == NULL) { + /* Create a new mapping in the map */ + if (linemap->map_size >= linemap->map_allocated) { + /* allocate another size bins when full for 2x space */ + linemap->map_vector = yasm_xrealloc(linemap->map_vector, + 2*linemap->map_allocated*sizeof(line_mapping)); + linemap->map_allocated *= 2; + } + mapping = &linemap->map_vector[linemap->map_size]; + linemap->map_size++; + } + + /* Fill it */ + + if (!filename) { + if (linemap->map_size >= 2) + mapping->filename = + linemap->map_vector[linemap->map_size-2].filename; + else + filename = "unknown"; + } + if (filename) { + /* Copy the filename (via shared storage) */ + copy = yasm__xstrdup(filename); + /*@-aliasunique@*/ + mapping->filename = HAMT_insert(linemap->filenames, copy, copy, + &replace, filename_delete_one); + /*@=aliasunique@*/ + } + + mapping->line = virtual_line; + mapping->file_line = file_line; + mapping->line_inc = line_inc; +} + +unsigned long +yasm_linemap_poke(yasm_linemap *linemap, const char *filename, + unsigned long file_line) +{ + unsigned long line; + line_mapping *mapping; + + linemap->current++; + yasm_linemap_set(linemap, filename, 0, file_line, 0); + + mapping = &linemap->map_vector[linemap->map_size-1]; + + line = linemap->current; + + linemap->current++; + yasm_linemap_set(linemap, mapping->filename, 0, + mapping->file_line + + mapping->line_inc*(linemap->current-2-mapping->line), + mapping->line_inc); + + return line; +} + +yasm_linemap * +yasm_linemap_create(void) +{ + size_t i; + yasm_linemap *linemap = yasm_xmalloc(sizeof(yasm_linemap)); + + linemap->filenames = HAMT_create(0, yasm_internal_error_); + + linemap->current = 1; + + /* initialize mapping vector */ + linemap->map_vector = yasm_xmalloc(8*sizeof(line_mapping)); + linemap->map_size = 0; + linemap->map_allocated = 8; + + /* initialize source line information array */ + linemap->source_info_size = 2; + linemap->source_info = yasm_xmalloc(linemap->source_info_size * + sizeof(line_source_info)); + for (i=0; i<linemap->source_info_size; i++) { + linemap->source_info[i].bc = NULL; + linemap->source_info[i].source = NULL; + } + + return linemap; +} + +void +yasm_linemap_destroy(yasm_linemap *linemap) +{ + size_t i; + for (i=0; i<linemap->source_info_size; i++) { + if (linemap->source_info[i].source) + yasm_xfree(linemap->source_info[i].source); + } + yasm_xfree(linemap->source_info); + + yasm_xfree(linemap->map_vector); + + if (linemap->filenames) + HAMT_destroy(linemap->filenames, filename_delete_one); + + yasm_xfree(linemap); +} + +unsigned long +yasm_linemap_get_current(yasm_linemap *linemap) +{ + return linemap->current; +} + +void +yasm_linemap_add_source(yasm_linemap *linemap, yasm_bytecode *bc, + const char *source) +{ + size_t i; + + while (linemap->current > linemap->source_info_size) { + /* allocate another size bins when full for 2x space */ + linemap->source_info = yasm_xrealloc(linemap->source_info, + 2*linemap->source_info_size*sizeof(line_source_info)); + for (i=linemap->source_info_size; i<linemap->source_info_size*2; i++) { + linemap->source_info[i].bc = NULL; + linemap->source_info[i].source = NULL; + } + linemap->source_info_size *= 2; + } + + /* Delete existing info for that line (if any) */ + if (linemap->source_info[linemap->current-1].source) + yasm_xfree(linemap->source_info[linemap->current-1].source); + + linemap->source_info[linemap->current-1].bc = bc; + linemap->source_info[linemap->current-1].source = yasm__xstrdup(source); +} + +unsigned long +yasm_linemap_goto_next(yasm_linemap *linemap) +{ + return ++(linemap->current); +} + +void +yasm_linemap_lookup(yasm_linemap *linemap, unsigned long line, + const char **filename, unsigned long *file_line) +{ + line_mapping *mapping; + unsigned long vindex, step; + + assert(line <= linemap->current); + + /* Binary search through map to find highest line_index <= index */ + vindex = 0; + /* start step as the greatest power of 2 <= size */ + step = 1; + while (step*2<=linemap->map_size) + step*=2; + while (step>0) { + if (vindex+step < linemap->map_size + && linemap->map_vector[vindex+step].line <= line) + vindex += step; + step /= 2; + } + mapping = &linemap->map_vector[vindex]; + + *filename = mapping->filename; + *file_line = (line ? mapping->file_line + mapping->line_inc*(line-mapping->line) : 0); +} + +int +yasm_linemap_traverse_filenames(yasm_linemap *linemap, /*@null@*/ void *d, + int (*func) (const char *filename, void *d)) +{ + return HAMT_traverse(linemap->filenames, d, (int (*) (void *, void *))func); +} + +int +yasm_linemap_get_source(yasm_linemap *linemap, unsigned long line, + yasm_bytecode **bcp, const char **sourcep) +{ + if (line > linemap->source_info_size) { + *bcp = NULL; + *sourcep = NULL; + return 1; + } + + *bcp = linemap->source_info[line-1].bc; + *sourcep = linemap->source_info[line-1].source; + + return (!(*sourcep)); +} diff --git a/contrib/tools/yasm/libyasm/linemap.h b/contrib/tools/yasm/libyasm/linemap.h new file mode 100644 index 0000000000..1c5aa4626a --- /dev/null +++ b/contrib/tools/yasm/libyasm/linemap.h @@ -0,0 +1,141 @@ +/** + * \file libyasm/linemap.h + * \brief YASM virtual line mapping interface. + * + * \license + * 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. + * \endlicense + */ +#ifndef YASM_LINEMAP_H +#define YASM_LINEMAP_H + +#ifndef YASM_LIB_DECL +#define YASM_LIB_DECL +#endif + +/** Create a new line mapping repository. + * \return New repository. + */ +YASM_LIB_DECL +yasm_linemap *yasm_linemap_create(void); + +/** Clean up any memory allocated for a repository. + * \param linemap line mapping repository + */ +YASM_LIB_DECL +void yasm_linemap_destroy(yasm_linemap *linemap); + +/** Get the current line position in a repository. + * \param linemap line mapping repository + * \return Current virtual line. + */ +YASM_LIB_DECL +unsigned long yasm_linemap_get_current(yasm_linemap *linemap); + +/** Get bytecode and source line information, if any, for a virtual line. + * \param linemap line mapping repository + * \param line virtual line + * \param bcp pointer to return bytecode into + * \param sourcep pointer to return source code line pointer into + * \return Zero if source line information available for line, nonzero if not. + * \note If source line information is not available, bcp and sourcep targets + * are set to NULL. + */ +YASM_LIB_DECL +int yasm_linemap_get_source(yasm_linemap *linemap, unsigned long line, + /*@null@*/ yasm_bytecode **bcp, + const char **sourcep); + +/** Add bytecode and source line information to the current virtual line. + * \attention Deletes any existing bytecode and source line information for + * the current virtual line. + * \param linemap line mapping repository + * \param bc bytecode (if any) + * \param source source code line + * \note The source code line pointer is NOT kept, it is strdup'ed. + */ +YASM_LIB_DECL +void yasm_linemap_add_source(yasm_linemap *linemap, + /*@null@*/ yasm_bytecode *bc, + const char *source); + +/** Go to the next line (increments the current virtual line). + * \param linemap line mapping repository + * \return The current (new) virtual line. + */ +YASM_LIB_DECL +unsigned long yasm_linemap_goto_next(yasm_linemap *linemap); + +/** Set a new file/line physical association starting point at the specified + * virtual line. line_inc indicates how much the "real" line is incremented + * by for each virtual line increment (0 is perfectly legal). + * \param linemap line mapping repository + * \param filename physical file name (if NULL, not changed) + * \param virtual_line virtual line number (if 0, linemap->current is used) + * \param file_line physical line number + * \param line_inc line increment + */ +YASM_LIB_DECL +void yasm_linemap_set(yasm_linemap *linemap, /*@null@*/ const char *filename, + unsigned long virtual_line, unsigned long file_line, + unsigned long line_inc); + +/** Poke a single file/line association, restoring the original physical + * association starting point. Caution: increments the current virtual line + * twice. + * \param linemap line mapping repository + * \param filename physical file name (if NULL, not changed) + * \param file_line physical line number + * \return The virtual line number of the poked association. + */ +YASM_LIB_DECL +unsigned long yasm_linemap_poke(yasm_linemap *linemap, + /*@null@*/ const char *filename, + unsigned long file_line); + +/** Look up the associated physical file and line for a virtual line. + * \param linemap line mapping repository + * \param line virtual line + * \param filename physical file name (output) + * \param file_line physical line number (output) + */ +YASM_LIB_DECL +void yasm_linemap_lookup(yasm_linemap *linemap, unsigned long line, + /*@out@*/ const char **filename, + /*@out@*/ unsigned long *file_line); + +/** Traverses all filenames used in a linemap, calling a function on each + * filename. + * \param linemap line mapping repository + * \param d data pointer passed to func on each call + * \param func function + * \return Stops early (and returns func's return value) if func returns a + * nonzero value; otherwise 0. + */ +YASM_LIB_DECL +int yasm_linemap_traverse_filenames + (yasm_linemap *linemap, /*@null@*/ void *d, + int (*func) (const char *filename, void *d)); + +#endif diff --git a/contrib/tools/yasm/libyasm/listfmt.h b/contrib/tools/yasm/libyasm/listfmt.h new file mode 100644 index 0000000000..945f28e58b --- /dev/null +++ b/contrib/tools/yasm/libyasm/listfmt.h @@ -0,0 +1,124 @@ +/** + * \file libyasm/listfmt.h + * \brief YASM list format interface. + * + * \license + * Copyright (C) 2004-2007 Peter Johnson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - 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. + * \endlicense + */ +#ifndef YASM_LISTFMT_H +#define YASM_LISTFMT_H + +#ifndef YASM_DOXYGEN +/** Base #yasm_listfmt structure. Must be present as the first element in any + * #yasm_listfmt implementation. + */ +typedef struct yasm_listfmt_base { + /** #yasm_listfmt_module implementation for this list format. */ + const struct yasm_listfmt_module *module; +} yasm_listfmt_base; +#endif + +/** YASM list format module interface. */ +typedef struct yasm_listfmt_module { + /** One-line description of the list format. */ + const char *name; + + /** Keyword used to select list format. */ + const char *keyword; + + /** Create list format. + * Module-level implementation of yasm_listfmt_create(). + * The filenames are provided solely for informational purposes. + * \param in_filename primary input filename + * \param obj_filename object filename + * \return NULL if unable to initialize. + */ + /*@null@*/ /*@only@*/ yasm_listfmt * (*create) + (const char *in_filename, const char *obj_filename); + + /** Module-level implementation of yasm_listfmt_destroy(). + * Call yasm_listfmt_destroy() instead of calling this function. + */ + void (*destroy) (/*@only@*/ yasm_listfmt *listfmt); + + /** Module-level implementation of yasm_listfmt_output(). + * Call yasm_listfmt_output() instead of calling this function. + */ + void (*output) (yasm_listfmt *listfmt, FILE *f, yasm_linemap *linemap, + yasm_arch *arch); +} yasm_listfmt_module; + +/** Get the keyword used to select a list format. + * \param listfmt list format + * \return keyword + */ +const char *yasm_listfmt_keyword(const yasm_listfmt *listfmt); + +/** Initialize list format for use. Must call before any other list + * format functions. The filenames are provided solely for informational + * purposes. + * \param module list format module + * \param in_filename primary input filename + * \param obj_filename object filename + * \return NULL if object format does not provide needed support. + */ +/*@null@*/ /*@only@*/ yasm_listfmt *yasm_listfmt_create + (const yasm_listfmt_module *module, const char *in_filename, + const char *obj_filename); + +/** Cleans up any allocated list format memory. + * \param listfmt list format + */ +void yasm_listfmt_destroy(/*@only@*/ yasm_listfmt *listfmt); + +/** Write out list to the list file. + * This function may call all read-only yasm_* functions as necessary. + * \param listfmt list format + * \param f output list file + * \param linemap line mapping repository + * \param arch architecture + */ +void yasm_listfmt_output(yasm_listfmt *listfmt, FILE *f, + yasm_linemap *linemap, yasm_arch *arch); + +#ifndef YASM_DOXYGEN + +/* Inline macro implementations for listfmt functions */ + +#define yasm_listfmt_keyword(listfmt) \ + (((yasm_listfmt_base *)listfmt)->module->keyword) + +#define yasm_listfmt_create(module, in_filename, obj_filename) \ + module->create(in_filename, obj_filename) + +#define yasm_listfmt_destroy(listfmt) \ + ((yasm_listfmt_base *)listfmt)->module->destroy(listfmt) + +#define yasm_listfmt_output(listfmt, f, linemap, a) \ + ((yasm_listfmt_base *)listfmt)->module->output(listfmt, f, linemap, a) + +#endif + +#endif diff --git a/contrib/tools/yasm/libyasm/md5.c b/contrib/tools/yasm/libyasm/md5.c new file mode 100644 index 0000000000..b009842f5c --- /dev/null +++ b/contrib/tools/yasm/libyasm/md5.c @@ -0,0 +1,309 @@ +/* + * This code implements the MD5 message-digest algorithm. + * The algorithm is due to Ron Rivest. This code was + * written by Colin Plumb in 1993, no copyright is claimed. + * This code is in the public domain; do with it what you wish. + * + * Equivalent code is available from RSA Data Security, Inc. + * This code has been tested against that, and is equivalent, + * except that you don't need to include two pages of legalese + * with every copy. + * + * To compute the message digest of a chunk of bytes, declare an + * MD5Context structure, pass it to MD5Init, call MD5Update as + * needed on buffers full of bytes, and then call MD5Final, which + * will fill a supplied 16-byte array with the digest. + */ + +/* This code was modified in 1997 by Jim Kingdon of Cyclic Software to + not require an integer type which is exactly 32 bits. This work + draws on the changes for the same purpose by Tatu Ylonen + <ylo@cs.hut.fi> as part of SSH, but since I didn't actually use + that code, there is no copyright issue. I hereby disclaim + copyright in any changes I have made; this code remains in the + public domain. */ + +/* Note regarding cvs_* namespace: this avoids potential conflicts + with libraries such as some versions of Kerberos. No particular + need to worry about whether the system supplies an MD5 library, as + this file is only about 3k of object code. */ + +#include <util.h> + +#include "md5.h" + +/* Little-endian byte-swapping routines. Note that these do not + depend on the size of datatypes such as cvs_uint32, nor do they require + us to detect the endianness of the machine we are running on. It + is possible they should be macros for speed, but I would be + surprised if they were a performance bottleneck for MD5. */ + +static unsigned long +getu32(const unsigned char *addr) +{ + return (((((unsigned long)addr[3] << 8) | addr[2]) << 8) + | addr[1]) << 8 | addr[0]; +} + +static void +putu32(unsigned long data, unsigned char *addr) +{ + addr[0] = (unsigned char)data; + addr[1] = (unsigned char)(data >> 8); + addr[2] = (unsigned char)(data >> 16); + addr[3] = (unsigned char)(data >> 24); +} + +/* + * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious + * initialization constants. + */ +void +yasm_md5_init(yasm_md5_context *ctx) +{ + ctx->buf[0] = 0x67452301; + ctx->buf[1] = 0xefcdab89; + ctx->buf[2] = 0x98badcfe; + ctx->buf[3] = 0x10325476; + + ctx->bits[0] = 0; + ctx->bits[1] = 0; +} + +/* + * Update context to reflect the concatenation of another buffer full + * of bytes. + */ +void +yasm_md5_update(yasm_md5_context *ctx, unsigned char const *buf, + unsigned long len) +{ + unsigned long t; + + /* Update bitcount */ + + t = ctx->bits[0]; + if ((ctx->bits[0] = (t + ((unsigned long)len << 3)) & 0xffffffff) < t) + ctx->bits[1]++; /* Carry from low to high */ + ctx->bits[1] += len >> 29; + + t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ + + /* Handle any leading odd-sized chunks */ + + if ( t ) { + unsigned char *p = ctx->in + t; + + t = 64-t; + if (len < t) { + memcpy(p, buf, len); + return; + } + memcpy(p, buf, t); + yasm_md5_transform (ctx->buf, ctx->in); + buf += t; + len -= t; + } + + /* Process data in 64-byte chunks */ + + while (len >= 64) { + memcpy(ctx->in, buf, 64); + yasm_md5_transform (ctx->buf, ctx->in); + buf += 64; + len -= 64; + } + + /* Handle any remaining bytes of data. */ + + memcpy(ctx->in, buf, len); +} + +/* + * Final wrapup - pad to 64-byte boundary with the bit pattern + * 1 0* (64-bit count of bits processed, MSB-first) + */ +void +yasm_md5_final(unsigned char digest[16], yasm_md5_context *ctx) +{ + unsigned count; + unsigned char *p; + + /* Compute number of bytes mod 64 */ + count = (ctx->bits[0] >> 3) & 0x3F; + + /* Set the first char of padding to 0x80. This is safe since there is + always at least one byte free */ + p = ctx->in + count; + *p++ = 0x80; + + /* Bytes of padding needed to make 64 bytes */ + count = 64 - 1 - count; + + /* Pad out to 56 mod 64 */ + if (count < 8) { + /* Two lots of padding: Pad the first block to 64 bytes */ + memset(p, 0, count); + yasm_md5_transform (ctx->buf, ctx->in); + + /* Now fill the next block with 56 bytes */ + memset(ctx->in, 0, 56); + } else { + /* Pad block to 56 bytes */ + memset(p, 0, count-8); + } + + /* Append length in bits and transform */ + putu32(ctx->bits[0], ctx->in + 56); + putu32(ctx->bits[1], ctx->in + 60); + + yasm_md5_transform (ctx->buf, ctx->in); + putu32(ctx->buf[0], digest); + putu32(ctx->buf[1], digest + 4); + putu32(ctx->buf[2], digest + 8); + putu32(ctx->buf[3], digest + 12); + memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */ +} + +#ifndef ASM_MD5 + +/* The four core functions - F1 is optimized somewhat */ + +/* #define F1(x, y, z) (x & y | ~x & z) */ +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + +/* This is the central step in the MD5 algorithm. */ +#define MD5STEP(f, w, x, y, z, data, s) \ + ( w += f(x, y, z) + data, w &= 0xffffffff, w = w<<s | w>>(32-s), w += x ) + +/* + * The core of the MD5 algorithm, this alters an existing MD5 hash to + * reflect the addition of 16 longwords of new data. MD5Update blocks + * the data and converts bytes into longwords for this routine. + */ +void +yasm_md5_transform(unsigned long buf[4], const unsigned char inraw[64]) +{ + unsigned long a, b, c, d; + unsigned long in[16]; + int i; + + for (i = 0; i < 16; ++i) + in[i] = getu32 (inraw + 4 * i); + + a = buf[0]; + b = buf[1]; + c = buf[2]; + d = buf[3]; + + MD5STEP(F1, a, b, c, d, in[ 0]+0xd76aa478, 7); + MD5STEP(F1, d, a, b, c, in[ 1]+0xe8c7b756, 12); + MD5STEP(F1, c, d, a, b, in[ 2]+0x242070db, 17); + MD5STEP(F1, b, c, d, a, in[ 3]+0xc1bdceee, 22); + MD5STEP(F1, a, b, c, d, in[ 4]+0xf57c0faf, 7); + MD5STEP(F1, d, a, b, c, in[ 5]+0x4787c62a, 12); + MD5STEP(F1, c, d, a, b, in[ 6]+0xa8304613, 17); + MD5STEP(F1, b, c, d, a, in[ 7]+0xfd469501, 22); + MD5STEP(F1, a, b, c, d, in[ 8]+0x698098d8, 7); + MD5STEP(F1, d, a, b, c, in[ 9]+0x8b44f7af, 12); + MD5STEP(F1, c, d, a, b, in[10]+0xffff5bb1, 17); + MD5STEP(F1, b, c, d, a, in[11]+0x895cd7be, 22); + MD5STEP(F1, a, b, c, d, in[12]+0x6b901122, 7); + MD5STEP(F1, d, a, b, c, in[13]+0xfd987193, 12); + MD5STEP(F1, c, d, a, b, in[14]+0xa679438e, 17); + MD5STEP(F1, b, c, d, a, in[15]+0x49b40821, 22); + + MD5STEP(F2, a, b, c, d, in[ 1]+0xf61e2562, 5); + MD5STEP(F2, d, a, b, c, in[ 6]+0xc040b340, 9); + MD5STEP(F2, c, d, a, b, in[11]+0x265e5a51, 14); + MD5STEP(F2, b, c, d, a, in[ 0]+0xe9b6c7aa, 20); + MD5STEP(F2, a, b, c, d, in[ 5]+0xd62f105d, 5); + MD5STEP(F2, d, a, b, c, in[10]+0x02441453, 9); + MD5STEP(F2, c, d, a, b, in[15]+0xd8a1e681, 14); + MD5STEP(F2, b, c, d, a, in[ 4]+0xe7d3fbc8, 20); + MD5STEP(F2, a, b, c, d, in[ 9]+0x21e1cde6, 5); + MD5STEP(F2, d, a, b, c, in[14]+0xc33707d6, 9); + MD5STEP(F2, c, d, a, b, in[ 3]+0xf4d50d87, 14); + MD5STEP(F2, b, c, d, a, in[ 8]+0x455a14ed, 20); + MD5STEP(F2, a, b, c, d, in[13]+0xa9e3e905, 5); + MD5STEP(F2, d, a, b, c, in[ 2]+0xfcefa3f8, 9); + MD5STEP(F2, c, d, a, b, in[ 7]+0x676f02d9, 14); + MD5STEP(F2, b, c, d, a, in[12]+0x8d2a4c8a, 20); + + MD5STEP(F3, a, b, c, d, in[ 5]+0xfffa3942, 4); + MD5STEP(F3, d, a, b, c, in[ 8]+0x8771f681, 11); + MD5STEP(F3, c, d, a, b, in[11]+0x6d9d6122, 16); + MD5STEP(F3, b, c, d, a, in[14]+0xfde5380c, 23); + MD5STEP(F3, a, b, c, d, in[ 1]+0xa4beea44, 4); + MD5STEP(F3, d, a, b, c, in[ 4]+0x4bdecfa9, 11); + MD5STEP(F3, c, d, a, b, in[ 7]+0xf6bb4b60, 16); + MD5STEP(F3, b, c, d, a, in[10]+0xbebfbc70, 23); + MD5STEP(F3, a, b, c, d, in[13]+0x289b7ec6, 4); + MD5STEP(F3, d, a, b, c, in[ 0]+0xeaa127fa, 11); + MD5STEP(F3, c, d, a, b, in[ 3]+0xd4ef3085, 16); + MD5STEP(F3, b, c, d, a, in[ 6]+0x04881d05, 23); + MD5STEP(F3, a, b, c, d, in[ 9]+0xd9d4d039, 4); + MD5STEP(F3, d, a, b, c, in[12]+0xe6db99e5, 11); + MD5STEP(F3, c, d, a, b, in[15]+0x1fa27cf8, 16); + MD5STEP(F3, b, c, d, a, in[ 2]+0xc4ac5665, 23); + + MD5STEP(F4, a, b, c, d, in[ 0]+0xf4292244, 6); + MD5STEP(F4, d, a, b, c, in[ 7]+0x432aff97, 10); + MD5STEP(F4, c, d, a, b, in[14]+0xab9423a7, 15); + MD5STEP(F4, b, c, d, a, in[ 5]+0xfc93a039, 21); + MD5STEP(F4, a, b, c, d, in[12]+0x655b59c3, 6); + MD5STEP(F4, d, a, b, c, in[ 3]+0x8f0ccc92, 10); + MD5STEP(F4, c, d, a, b, in[10]+0xffeff47d, 15); + MD5STEP(F4, b, c, d, a, in[ 1]+0x85845dd1, 21); + MD5STEP(F4, a, b, c, d, in[ 8]+0x6fa87e4f, 6); + MD5STEP(F4, d, a, b, c, in[15]+0xfe2ce6e0, 10); + MD5STEP(F4, c, d, a, b, in[ 6]+0xa3014314, 15); + MD5STEP(F4, b, c, d, a, in[13]+0x4e0811a1, 21); + MD5STEP(F4, a, b, c, d, in[ 4]+0xf7537e82, 6); + MD5STEP(F4, d, a, b, c, in[11]+0xbd3af235, 10); + MD5STEP(F4, c, d, a, b, in[ 2]+0x2ad7d2bb, 15); + MD5STEP(F4, b, c, d, a, in[ 9]+0xeb86d391, 21); + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} +#endif + +#ifdef TEST +/* Simple test program. Can use it to manually run the tests from + RFC1321 for example. */ +#include <stdio.h> + +int +main (int argc, char **argv) +{ + yasm_md5_context context; + unsigned char checksum[16]; + int i; + int j; + + if (argc < 2) + { + fprintf (stderr, "usage: %s string-to-hash\n", argv[0]); + exit (1); + } + for (j = 1; j < argc; ++j) + { + printf ("MD5 (\"%s\") = ", argv[j]); + yasm_md5_init (&context); + yasm_md5_update (&context, argv[j], strlen (argv[j])); + yasm_md5_final (checksum, &context); + for (i = 0; i < 16; i++) + { + printf ("%02x", (unsigned int) checksum[i]); + } + printf ("\n"); + } + return 0; +} +#endif /* TEST */ diff --git a/contrib/tools/yasm/libyasm/md5.h b/contrib/tools/yasm/libyasm/md5.h new file mode 100644 index 0000000000..7872fda7a1 --- /dev/null +++ b/contrib/tools/yasm/libyasm/md5.h @@ -0,0 +1,32 @@ +/* See md5.c for explanation and copyright information. */ + +#ifndef YASM_MD5_H +#define YASM_MD5_H + +#ifndef YASM_LIB_DECL +#define YASM_LIB_DECL +#endif + +/* Unlike previous versions of this code, uint32 need not be exactly + 32 bits, merely 32 bits or more. Choosing a data type which is 32 + bits instead of 64 is not important; speed is considerably more + important. ANSI guarantees that "unsigned long" will be big enough, + and always using it seems to have few disadvantages. */ + +typedef struct yasm_md5_context { + unsigned long buf[4]; + unsigned long bits[2]; + unsigned char in[64]; +} yasm_md5_context; + +YASM_LIB_DECL +void yasm_md5_init(yasm_md5_context *context); +YASM_LIB_DECL +void yasm_md5_update(yasm_md5_context *context, unsigned char const *buf, + unsigned long len); +YASM_LIB_DECL +void yasm_md5_final(unsigned char digest[16], yasm_md5_context *context); +YASM_LIB_DECL +void yasm_md5_transform(unsigned long buf[4], const unsigned char in[64]); + +#endif /* !YASM_MD5_H */ diff --git a/contrib/tools/yasm/libyasm/mergesort.c b/contrib/tools/yasm/libyasm/mergesort.c new file mode 100644 index 0000000000..3eeaa8273b --- /dev/null +++ b/contrib/tools/yasm/libyasm/mergesort.c @@ -0,0 +1,361 @@ +/* + * mergesort() implementation for systems that don't have it. + * + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Peter McIlroy. + * + * 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. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND 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 REGENTS OR 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" + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)merge.c 8.2 (Berkeley) 2/14/94"; +#endif /* LIBC_SCCS and not lint */ + +#ifdef HAVE_MERGESORT +#undef yasm__mergesort +#endif + +#ifndef HAVE_MERGESORT +/* + * Hybrid exponential search/linear search merge sort with hybrid + * natural/pairwise first pass. Requires about .3% more comparisons + * for random data than LSMS with pairwise first pass alone. + * It works for objects as small as two bytes. + */ + +#define NATURAL +#define THRESHOLD 16 /* Best choice for natural merge cut-off. */ + +/* #define NATURAL to get hybrid natural merge. + * (The default is pairwise merging.) + */ + +#include <errno.h> +#include <string.h> + +static void setup(unsigned char *, unsigned char *, size_t, size_t, + int (*)(const void *, const void *)); +static void insertionsort(unsigned char *, size_t, size_t, + int (*)(const void *, const void *)); + +#define ISIZE sizeof(int) +#define PSIZE sizeof(unsigned char *) +#define ICOPY_LIST(src, dst, last) \ + do \ + *(int*)dst = *(int*)src, src += ISIZE, dst += ISIZE; \ + while(src < last) +#define ICOPY_ELT(src, dst, i) \ + do \ + *(int*) dst = *(int*) src, src += ISIZE, dst += ISIZE; \ + while (i -= ISIZE) + +#define CCOPY_LIST(src, dst, last) \ + do \ + *dst++ = *src++; \ + while (src < last) +#define CCOPY_ELT(src, dst, i) \ + do \ + *dst++ = *src++; \ + while (i -= 1) + +/* + * Find the next possible pointer head. (Trickery for forcing an array + * to do double duty as a linked list when objects do not align with word + * boundaries. + */ +/* Assumption: PSIZE is a power of 2. */ +#define EVAL(p) (unsigned char **) \ + ((unsigned char *)0 + \ + (((unsigned char *)p + PSIZE - 1 - (unsigned char *) 0) & ~(PSIZE - 1))) +#endif /*HAVE_MERGESORT*/ + +/* + * Arguments are as for qsort. + */ +int +yasm__mergesort(void *base, size_t nmemb, size_t size, + int (*cmp)(const void *, const void *)) +{ +#ifdef HAVE_MERGESORT + return mergesort(base, nmemb, size, cmp); +#else + size_t i; + int sense; + int big, iflag; + unsigned char *f1, *f2, *t, *b, *tp2, *q, *l1, *l2; + unsigned char *list2, *list1, *p2, *p, *last, **p1; + + if (size < PSIZE / 2) { /* Pointers must fit into 2 * size. */ +#ifdef EINVAL + errno = EINVAL; +#endif + return (-1); + } + + if (nmemb == 0) + return (0); + + /* + * XXX + * Stupid subtraction for the Cray. + */ + iflag = 0; + if (!(size % ISIZE) && !(((char *)base - (char *)0) % ISIZE)) + iflag = 1; + + if ((list2 = yasm_xmalloc(nmemb * size + PSIZE)) == NULL) + return (-1); + + list1 = base; + setup(list1, list2, nmemb, size, cmp); + last = list2 + nmemb * size; + i = 0; + big = 0; + while (*EVAL(list2) != last) { + l2 = list1; + p1 = EVAL(list1); + for (tp2 = p2 = list2; p2 != last; p1 = EVAL(l2)) { + p2 = *EVAL(p2); + f1 = l2; + f2 = l1 = list1 + (p2 - list2); + if (p2 != last) + p2 = *EVAL(p2); + l2 = list1 + (p2 - list2); + while (f1 < l1 && f2 < l2) { + if ((*cmp)(f1, f2) <= 0) { + q = f2; + b = f1, t = l1; + sense = -1; + } else { + q = f1; + b = f2, t = l2; + sense = 0; + } + if (!big) { /* here i = 0 */ + while ((b += size) < t && cmp(q, b) >sense) + if (++i == 6) { + big = 1; + goto EXPONENTIAL; + } + } else { +EXPONENTIAL: for (i = size; ; i <<= 1) + if ((p = (b + i)) >= t) { + if ((p = t - size) > b && + (*cmp)(q, p) <= sense) + t = p; + else + b = p; + break; + } else if ((*cmp)(q, p) <= sense) { + t = p; + if (i == size) + big = 0; + goto FASTCASE; + } else + b = p; + while (t > b+size) { + i = (((t - b) / size) >> 1) * size; + if ((*cmp)(q, p = b + i) <= sense) + t = p; + else + b = p; + } + goto COPY; +FASTCASE: while (i > size) + if ((*cmp)(q, + p = b + (i >>= 1)) <= sense) + t = p; + else + b = p; +COPY: b = t; + } + i = size; + if (q == f1) { + if (iflag) { + ICOPY_LIST(f2, tp2, b); + ICOPY_ELT(f1, tp2, i); + } else { + CCOPY_LIST(f2, tp2, b); + CCOPY_ELT(f1, tp2, i); + } + } else { + if (iflag) { + ICOPY_LIST(f1, tp2, b); + ICOPY_ELT(f2, tp2, i); + } else { + CCOPY_LIST(f1, tp2, b); + CCOPY_ELT(f2, tp2, i); + } + } + } + if (f2 < l2) { + if (iflag) + ICOPY_LIST(f2, tp2, l2); + else + CCOPY_LIST(f2, tp2, l2); + } else if (f1 < l1) { + if (iflag) + ICOPY_LIST(f1, tp2, l1); + else + CCOPY_LIST(f1, tp2, l1); + } + *p1 = l2; + } + tp2 = list1; /* swap list1, list2 */ + list1 = list2; + list2 = tp2; + last = list2 + nmemb*size; + } + if (base == list2) { + memmove(list2, list1, nmemb*size); + list2 = list1; + } + yasm_xfree(list2); + return (0); +#endif /*HAVE_MERGESORT*/ +} + +#ifndef HAVE_MERGESORT + +#define swap(a, b) { \ + s = b; \ + i = size; \ + do { \ + tmp = *a; *a++ = *s; *s++ = tmp; \ + } while (--i); \ + a -= size; \ + } +#define reverse(bot, top) { \ + s = top; \ + do { \ + i = size; \ + do { \ + tmp = *bot; *bot++ = *s; *s++ = tmp; \ + } while (--i); \ + s -= size2; \ + } while(bot < s); \ +} + +/* + * Optional hybrid natural/pairwise first pass. Eats up list1 in runs of + * increasing order, list2 in a corresponding linked list. Checks for runs + * when THRESHOLD/2 pairs compare with same sense. (Only used when NATURAL + * is defined. Otherwise simple pairwise merging is used.) + */ +void +setup(unsigned char *list1, unsigned char *list2, size_t n, size_t size, + int (*cmp)(const void *, const void *)) +{ + size_t i; + unsigned int tmp; + int length, sense; + size_t size2; + unsigned char *f1, *f2, *s, *l2, *last, *p2; + + size2 = size*2; + if (n <= 5) { + insertionsort(list1, n, size, cmp); + *EVAL(list2) = (unsigned char*) list2 + n*size; + return; + } + /* + * Avoid running pointers out of bounds; limit n to evens + * for simplicity. + */ + i = 4 + (n & 1); + insertionsort(list1 + (n - i) * size, i, size, cmp); + last = list1 + size * (n - i); + *EVAL(list2 + (last - list1)) = list2 + n * size; + +#ifdef NATURAL + p2 = list2; + f1 = list1; + sense = (cmp(f1, f1 + size) > 0); + for (; f1 < last; sense = !sense) { + length = 2; + /* Find pairs with same sense. */ + for (f2 = f1 + size2; f2 < last; f2 += size2) { + if ((cmp(f2, f2+ size) > 0) != sense) + break; + length += 2; + } + if (length < THRESHOLD) { /* Pairwise merge */ + do { + p2 = *EVAL(p2) = f1 + size2 - list1 + list2; + if (sense > 0) + swap (f1, f1 + size); + } while ((f1 += size2) < f2); + } else { /* Natural merge */ + l2 = f2; + for (f2 = f1 + size2; f2 < l2; f2 += size2) { + if ((cmp(f2-size, f2) > 0) != sense) { + p2 = *EVAL(p2) = f2 - list1 + list2; + if (sense > 0) + reverse(f1, f2-size); + f1 = f2; + } + } + if (sense > 0) + reverse (f1, f2-size); + f1 = f2; + if (f2 < last || cmp(f2 - size, f2) > 0) + p2 = *EVAL(p2) = f2 - list1 + list2; + else + p2 = *EVAL(p2) = list2 + n*size; + } + } +#else /* pairwise merge only. */ + for (f1 = list1, p2 = list2; f1 < last; f1 += size2) { + p2 = *EVAL(p2) = p2 + size2; + if (cmp (f1, f1 + size) > 0) + swap(f1, f1 + size); + } +#endif /* NATURAL */ +} + +/* + * This is to avoid out-of-bounds addresses in sorting the + * last 4 elements. + */ +static void +insertionsort(unsigned char *a, size_t n, size_t size, + int (*cmp)(const void *, const void *)) +{ + unsigned char *ai, *s, *t, *u, tmp; + size_t i; + + for (ai = a+size; --n >= 1; ai += size) + for (t = ai; t > a; t -= size) { + u = t - size; + if (cmp(u, t) <= 0) + break; + swap(u, t); + } +} +#endif /*HAVE_MERGESORT*/ diff --git a/contrib/tools/yasm/libyasm/module.h b/contrib/tools/yasm/libyasm/module.h new file mode 100644 index 0000000000..220017deec --- /dev/null +++ b/contrib/tools/yasm/libyasm/module.h @@ -0,0 +1,82 @@ +/* + * YASM module loader header file + * + * 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. + */ +#ifndef YASM_MODULE_H +#define YASM_MODULE_H + +#ifndef YASM_LIB_DECL +#define YASM_LIB_DECL +#endif + +typedef enum yasm_module_type { + YASM_MODULE_ARCH = 0, + YASM_MODULE_DBGFMT, + YASM_MODULE_OBJFMT, + YASM_MODULE_LISTFMT, + YASM_MODULE_PARSER, + YASM_MODULE_PREPROC +} yasm_module_type; + +YASM_LIB_DECL +/*@dependent@*/ /*@null@*/ void *yasm_load_module + (yasm_module_type type, const char *keyword); + +#define yasm_load_arch(keyword) \ + yasm_load_module(YASM_MODULE_ARCH, keyword) +#define yasm_load_dbgfmt(keyword) \ + yasm_load_module(YASM_MODULE_DBGFMT, keyword) +#define yasm_load_objfmt(keyword) \ + yasm_load_module(YASM_MODULE_OBJFMT, keyword) +#define yasm_load_listfmt(keyword) \ + yasm_load_module(YASM_MODULE_LISTFMT, keyword) +#define yasm_load_parser(keyword) \ + yasm_load_module(YASM_MODULE_PARSER, keyword) +#define yasm_load_preproc(keyword) \ + yasm_load_module(YASM_MODULE_PREPROC, keyword) + +YASM_LIB_DECL +void yasm_list_modules + (yasm_module_type type, + void (*printfunc) (const char *name, const char *keyword)); + +#define yasm_list_arch(func) \ + yasm_list_modules(YASM_MODULE_ARCH, func) +#define yasm_list_dbgfmt(func) \ + yasm_list_modules(YASM_MODULE_DBGFMT, func) +#define yasm_list_objfmt(func) \ + yasm_list_modules(YASM_MODULE_OBJFMT, func) +#define yasm_list_listfmt(func) \ + yasm_list_modules(YASM_MODULE_LISTFMT, func) +#define yasm_list_parser(func) \ + yasm_list_modules(YASM_MODULE_PARSER, func) +#define yasm_list_preproc(func) \ + yasm_list_modules(YASM_MODULE_PREPROC, func) + +YASM_LIB_DECL +void yasm_register_module(yasm_module_type type, const char *keyword, + void *data); + +#endif diff --git a/contrib/tools/yasm/libyasm/objfmt.h b/contrib/tools/yasm/libyasm/objfmt.h new file mode 100644 index 0000000000..a8b5f8a161 --- /dev/null +++ b/contrib/tools/yasm/libyasm/objfmt.h @@ -0,0 +1,225 @@ +/** + * \file libyasm/objfmt.h + * \brief YASM object format module interface. + * + * \license + * 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: + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - 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. + * \endlicense + */ +#ifndef YASM_OBJFMT_H +#define YASM_OBJFMT_H + +#ifndef YASM_DOXYGEN +/** Base #yasm_objfmt structure. Must be present as the first element in any + * #yasm_objfmt implementation. + */ +typedef struct yasm_objfmt_base { + /** #yasm_objfmt_module implementation for this object format. */ + const struct yasm_objfmt_module *module; +} yasm_objfmt_base; +#endif + +/** Object format module interface. */ +struct yasm_objfmt_module { + /** One-line description of the object format. */ + const char *name; + + /** Keyword used to select object format. */ + const char *keyword; + + /** Default output file extension (without the '.'). + * NULL means no extension, with no '.', while "" includes the '.'. + */ + /*@null@*/ const char *extension; + + /** Default (starting) x86 BITS setting. This only appies to the x86 + * architecture; other architectures ignore this setting. + */ + const unsigned char default_x86_mode_bits; + + /** If @ signs should be legal in identifiers. */ + const unsigned char id_at_ok; + + /** NULL-terminated list of debug format (yasm_dbgfmt) keywords that are + * valid to use with this object format. The null debug format + * (null_dbgfmt, "null") should always be in this list so it's possible to + * have no debug output. + */ + const char **dbgfmt_keywords; + + /** Default debug format keyword (set even if there's only one available to + * use). + */ + const char *default_dbgfmt_keyword; + + /** NULL-terminated list of directives. NULL if none. */ + /*@null@*/ const yasm_directive *directives; + + /** NULL-terminated list of standard macro lookups. NULL if none. */ + const yasm_stdmac *stdmacs; + + /** Create object format. + * Module-level implementation of yasm_objfmt_create(). + * Call yasm_objfmt_create() instead of calling this function. + * \param object object + * \param a architecture in use + * \return NULL if architecture/machine combination not supported. + */ + /*@null@*/ /*@only@*/ yasm_objfmt * (*create) (yasm_object *object); + + /** Module-level implementation of yasm_objfmt_output(). + * Call yasm_objfmt_output() instead of calling this function. + */ + void (*output) (yasm_object *o, FILE *f, int all_syms, + yasm_errwarns *errwarns); + + /** Module-level implementation of yasm_objfmt_destroy(). + * Call yasm_objfmt_destroy() instead of calling this function. + */ + void (*destroy) (/*@only@*/ yasm_objfmt *objfmt); + + /** Module-level implementation of yasm_objfmt_add_default_section(). + * Call yasm_objfmt_add_default_section() instead of calling this function. + */ + yasm_section * (*add_default_section) (yasm_object *object); + + /** Module-level implementation of yasm_objfmt_init_new_section(). + * Call yasm_objfmt_init_new_section() instead of calling this function. + */ + void (*init_new_section) (yasm_section *section, unsigned long line); + + /** Module-level implementation of yasm_objfmt_section_switch(). + * Call yasm_objfmt_section_switch() instead of calling this function. + */ + /*@observer@*/ /*@null@*/ yasm_section * + (*section_switch)(yasm_object *object, yasm_valparamhead *valparams, + /*@null@*/ yasm_valparamhead *objext_valparams, + unsigned long line); + + /** Module-level implementation of yasm_objfmt_get_special_sym(). + * Call yasm_objfmt_get_special_sym() instead of calling this function. + */ + /*@observer@*/ /*@null@*/ yasm_symrec * + (*get_special_sym)(yasm_object *object, const char *name, + const char *parser); + + /** + * --replace params + */ + const char** replace_map; + /** + * Number of elements in replace_map + */ + int replace_map_size; +}; + +/** Create object format. + * \param module object format module + * \param object object + * \return NULL if architecture/machine combination not supported. + */ +/*@null@*/ /*@only@*/ yasm_objfmt *yasm_objfmt_create + (const yasm_objfmt_module *module, yasm_object *object); + +/** Write out (post-optimized) sections to the object file. + * This function may call yasm_symrec_* functions as necessary (including + * yasm_symrec_traverse()) to retrieve symbolic information. + * \param object object + * \param f output object file + * \param all_syms if nonzero, all symbols should be included in + * the object file + * \param errwarns error/warning set + * \note Errors and warnings are stored into errwarns. + */ +void yasm_objfmt_output(yasm_object *object, FILE *f, int all_syms, + yasm_errwarns *errwarns); + +/** Cleans up any allocated object format memory. + * \param objfmt object format + */ +void yasm_objfmt_destroy(/*@only@*/ yasm_objfmt *objfmt); + +/** Add a default section to an object. + * \param object object + * \return Default section. + */ +yasm_section *yasm_objfmt_add_default_section(yasm_object *object); + +/** Initialize the object-format specific portion of a section. Called + * by yasm_object_get_general(); in general should not be directly called. + * \param section section + * \param line virtual line (from yasm_linemap) + */ +void yasm_objfmt_init_new_section(yasm_object *object, unsigned long line); + +/** Switch object file sections. The first val of the valparams should + * be the section name. Calls yasm_object_get_general() to actually get + * the section. + * \param object object + * \param valparams value/parameters + * \param objext_valparams object format-specific value/parameters + * \param line virtual line (from yasm_linemap) + * \return NULL on error, otherwise new section. + */ +/*@observer@*/ /*@null@*/ yasm_section *yasm_objfmt_section_switch + (yasm_object *object, yasm_valparamhead *valparams, + /*@null@*/ yasm_valparamhead *objext_valparams, unsigned long line); + +/** Get a special symbol. Special symbols are generally used to generate + * special relocation types via the WRT mechanism. + * \param object object + * \param name symbol name (not including any parser-specific prefix) + * \param parser parser keyword + * \return NULL if unrecognized, otherwise special symbol. + */ +/*@observer@*/ /*@null@*/ yasm_symrec *yasm_objfmt_get_special_sym + (yasm_object *object, const char *name, const char *parser); + +#ifndef YASM_DOXYGEN + +/* Inline macro implementations for objfmt functions */ + +#define yasm_objfmt_create(module, object) module->create(object) + +#define yasm_objfmt_output(object, f, all_syms, ews) \ + ((yasm_objfmt_base *)((object)->objfmt))->module->output \ + (object, f, all_syms, ews) +#define yasm_objfmt_destroy(objfmt) \ + ((yasm_objfmt_base *)objfmt)->module->destroy(objfmt) +#define yasm_objfmt_section_switch(object, vpms, oe_vpms, line) \ + ((yasm_objfmt_base *)((object)->objfmt))->module->section_switch \ + (object, vpms, oe_vpms, line) +#define yasm_objfmt_add_default_section(object) \ + ((yasm_objfmt_base *)((object)->objfmt))->module->add_default_section \ + (object) +#define yasm_objfmt_init_new_section(section, line) \ + ((yasm_objfmt_base *)((object)->objfmt))->module->init_new_section \ + (section, line) +#define yasm_objfmt_get_special_sym(object, name, parser) \ + ((yasm_objfmt_base *)((object)->objfmt))->module->get_special_sym \ + (object, name, parser) + +#endif + +#endif diff --git a/contrib/tools/yasm/libyasm/parser.h b/contrib/tools/yasm/libyasm/parser.h new file mode 100644 index 0000000000..93d4d33232 --- /dev/null +++ b/contrib/tools/yasm/libyasm/parser.h @@ -0,0 +1,67 @@ +/** + * \file libyasm/parser.h + * \brief YASM parser module interface. + * + * \license + * 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. + * \endlicense + */ +#ifndef YASM_PARSER_H +#define YASM_PARSER_H + +/** YASM parser module interface. The "front end" of the assembler. */ +typedef struct yasm_parser_module { + /** One-line description of the parser */ + const char *name; + + /** Keyword used to select parser on the command line */ + const char *keyword; + + /** NULL-terminated list of preprocessors that are valid to use with this + * parser. The raw preprocessor (raw_preproc) should always be in this + * list so it's always possible to have no preprocessing done. + */ + const char **preproc_keywords; + + /** Default preprocessor. */ + const char *default_preproc_keyword; + + /** NULL-terminated list of standard macro lookups. NULL if none. */ + const yasm_stdmac *stdmacs; + + /** Parse a source file into an object. + * \param object object to parse into (already created) + * \param pp preprocessor + * \param save_input nonzero if the parser should save the original + * lines of source into the object's linemap (via + * yasm_linemap_add_data()). + * \param errwarns error/warning set + * \note Parse errors and warnings are stored into errwarns. + */ + void (*do_parse) + (yasm_object *object, yasm_preproc *pp, int save_input, + yasm_linemap *linemap, yasm_errwarns *errwarns); +} yasm_parser_module; + +#endif diff --git a/contrib/tools/yasm/libyasm/phash.c b/contrib/tools/yasm/libyasm/phash.c new file mode 100644 index 0000000000..29e073aae1 --- /dev/null +++ b/contrib/tools/yasm/libyasm/phash.c @@ -0,0 +1,268 @@ +/* Modified for use with yasm by Peter Johnson. */ +#include "util.h" + +/* +-------------------------------------------------------------------- +lookupa.c, by Bob Jenkins, December 1996. Same as lookup2.c +Use this code however you wish. Public Domain. No warranty. +Source is http://burtleburtle.net/bob/c/lookupa.c +-------------------------------------------------------------------- +*/ +#include "phash.h" + +#define ub4 unsigned long + +#define hashsize(n) ((ub4)1<<(n)) +#define hashmask(n) (hashsize(n)-1) + +/* +-------------------------------------------------------------------- +mix -- mix 3 32-bit values reversibly. +For every delta with one or two bit set, and the deltas of all three + high bits or all three low bits, whether the original value of a,b,c + is almost all zero or is uniformly distributed, +* If mix() is run forward or backward, at least 32 bits in a,b,c + have at least 1/4 probability of changing. +* If mix() is run forward, every bit of c will change between 1/3 and + 2/3 of the time. (Well, 22/100 and 78/100 for some 2-bit deltas.) +mix() was built out of 36 single-cycle latency instructions in a + structure that could supported 2x parallelism, like so: + a -= b; + a -= c; x = (c>>13); + b -= c; a ^= x; + b -= a; x = (a<<8); + c -= a; b ^= x; + c -= b; x = (b>>13); + ... + Unfortunately, superscalar Pentiums and Sparcs can't take advantage + of that parallelism. They've also turned some of those single-cycle + latency instructions into multi-cycle latency instructions. Still, + this is the fastest good hash I could find. There were about 2^^68 + to choose from. I only looked at a billion or so. +-------------------------------------------------------------------- +*/ +#define mix(a,b,c) \ +{ \ + a -= b; a -= c; a ^= (c>>13); \ + a &= 0xffffffff; \ + b -= c; b -= a; b ^= (a<<8); \ + b &= 0xffffffff; \ + c -= a; c -= b; c ^= (b>>13); \ + c &= 0xffffffff; \ + a -= b; a -= c; a ^= (c>>12); \ + a &= 0xffffffff; \ + b -= c; b -= a; b ^= (a<<16); \ + b &= 0xffffffff; \ + c -= a; c -= b; c ^= (b>>5); \ + c &= 0xffffffff; \ + a -= b; a -= c; a ^= (c>>3); \ + a &= 0xffffffff; \ + b -= c; b -= a; b ^= (a<<10); \ + b &= 0xffffffff; \ + c -= a; c -= b; c ^= (b>>15); \ + c &= 0xffffffff; \ +} + +/* +-------------------------------------------------------------------- +lookup() -- hash a variable-length key into a 32-bit value + k : the key (the unaligned variable-length array of bytes) + len : the length of the key, counting by bytes + level : can be any 4-byte value +Returns a 32-bit value. Every bit of the key affects every bit of +the return value. Every 1-bit and 2-bit delta achieves avalanche. +About 6len+35 instructions. + +The best hash table sizes are powers of 2. There is no need to do +mod a prime (mod is sooo slow!). If you need less than 32 bits, +use a bitmask. For example, if you need only 10 bits, do + h = (h & hashmask(10)); +In which case, the hash table should have hashsize(10) elements. + +If you are hashing n strings (ub1 **)k, do it like this: + for (i=0, h=0; i<n; ++i) h = lookup( k[i], len[i], h); + +By Bob Jenkins, 1996. bob_jenkins@burtleburtle.net. You may use this +code any way you wish, private, educational, or commercial. + +See http://burtleburtle.net/bob/hash/evahash.html +Use for hash table lookup, or anything where one collision in 2^32 is +acceptable. Do NOT use for cryptographic purposes. +-------------------------------------------------------------------- +*/ + +unsigned long +phash_lookup( + register const char *sk, /* the key */ + register size_t length, /* the length of the key */ + register unsigned long level) /* the previous hash, or an arbitrary value */ +{ + unsigned long a,b,c; + size_t len; + const unsigned char *k = (const unsigned char *)sk; + + /* Set up the internal state */ + len = length; + a = b = 0x9e3779b9; /* the golden ratio; an arbitrary value */ + c = level; /* the previous hash value */ + + /*---------------------------------------- handle most of the key */ + while (len >= 12) + { + a += (k[0] +((ub4)k[1]<<8) +((ub4)k[2]<<16) +((ub4)k[3]<<24)); + a &= 0xffffffff; + b += (k[4] +((ub4)k[5]<<8) +((ub4)k[6]<<16) +((ub4)k[7]<<24)); + b &= 0xffffffff; + c += (k[8] +((ub4)k[9]<<8) +((ub4)k[10]<<16)+((ub4)k[11]<<24)); + c &= 0xffffffff; + mix(a,b,c); + k += 12; len -= 12; + } + + /*------------------------------------- handle the last 11 bytes */ + c += (ub4)length; + switch(len) /* all the case statements fall through */ + { + case 11: c+=((ub4)k[10]<<24); + case 10: c+=((ub4)k[9]<<16); + case 9 : c+=((ub4)k[8]<<8); + c &= 0xffffffff; + /* the first byte of c is reserved for the length */ + case 8 : b+=((ub4)k[7]<<24); + case 7 : b+=((ub4)k[6]<<16); + case 6 : b+=((ub4)k[5]<<8); + case 5 : b+=k[4]; + b &= 0xffffffff; + case 4 : a+=((ub4)k[3]<<24); + case 3 : a+=((ub4)k[2]<<16); + case 2 : a+=((ub4)k[1]<<8); + case 1 : a+=k[0]; + a &= 0xffffffff; + /* case 0: nothing left to add */ + } + mix(a,b,c); + /*-------------------------------------------- report the result */ + return c; +} + + +/* +-------------------------------------------------------------------- +mixc -- mixc 8 4-bit values as quickly and thoroughly as possible. +Repeating mix() three times achieves avalanche. +Repeating mix() four times eliminates all funnels and all + characteristics stronger than 2^{-11}. +-------------------------------------------------------------------- +*/ +#define mixc(a,b,c,d,e,f,g,h) \ +{ \ + a^=b<<11; d+=a; b+=c; \ + b^=c>>2; e+=b; c+=d; \ + c^=d<<8; f+=c; d+=e; \ + d^=e>>16; g+=d; e+=f; \ + e^=f<<10; h+=e; f+=g; \ + f^=g>>4; a+=f; g+=h; \ + g^=h<<8; b+=g; h+=a; \ + h^=a>>9; c+=h; a+=b; \ +} + +/* +-------------------------------------------------------------------- +checksum() -- hash a variable-length key into a 256-bit value + k : the key (the unaligned variable-length array of bytes) + len : the length of the key, counting by bytes + state : an array of CHECKSTATE 4-byte values (256 bits) +The state is the checksum. Every bit of the key affects every bit of +the state. There are no funnels. About 112+6.875len instructions. + +If you are hashing n strings (ub1 **)k, do it like this: + for (i=0; i<8; ++i) state[i] = 0x9e3779b9; + for (i=0, h=0; i<n; ++i) checksum( k[i], len[i], state); + +(c) Bob Jenkins, 1996. bob_jenkins@burtleburtle.net. You may use this +code any way you wish, private, educational, or commercial, as long +as this whole comment accompanies it. + +See http://burtleburtle.net/bob/hash/evahash.html +Use to detect changes between revisions of documents, assuming nobody +is trying to cause collisions. Do NOT use for cryptography. +-------------------------------------------------------------------- +*/ +void +phash_checksum( + register const char *sk, + register size_t len, + register unsigned long *state) +{ + unsigned long a,b,c,d,e,f,g,h; + size_t length; + const unsigned char *k = (const unsigned char *)sk; + + /* Use the length and level; add in the golden ratio. */ + length = len; + a=state[0]; b=state[1]; c=state[2]; d=state[3]; + e=state[4]; f=state[5]; g=state[6]; h=state[7]; + + /*---------------------------------------- handle most of the key */ + while (len >= 32) + { + a += (k[0] +(k[1]<<8) +(k[2]<<16) +(k[3]<<24)); + b += (k[4] +(k[5]<<8) +(k[6]<<16) +(k[7]<<24)); + c += (k[8] +(k[9]<<8) +(k[10]<<16)+(k[11]<<24)); + d += (k[12]+(k[13]<<8)+(k[14]<<16)+(k[15]<<24)); + e += (k[16]+(k[17]<<8)+(k[18]<<16)+(k[19]<<24)); + f += (k[20]+(k[21]<<8)+(k[22]<<16)+(k[23]<<24)); + g += (k[24]+(k[25]<<8)+(k[26]<<16)+(k[27]<<24)); + h += (k[28]+(k[29]<<8)+(k[30]<<16)+(k[31]<<24)); + mixc(a,b,c,d,e,f,g,h); + mixc(a,b,c,d,e,f,g,h); + mixc(a,b,c,d,e,f,g,h); + mixc(a,b,c,d,e,f,g,h); + k += 32; len -= 32; + } + + /*------------------------------------- handle the last 31 bytes */ + h += (ub4)length; + switch(len) + { + case 31: h+=(k[30]<<24); + case 30: h+=(k[29]<<16); + case 29: h+=(k[28]<<8); + case 28: g+=(k[27]<<24); + case 27: g+=(k[26]<<16); + case 26: g+=(k[25]<<8); + case 25: g+=k[24]; + case 24: f+=(k[23]<<24); + case 23: f+=(k[22]<<16); + case 22: f+=(k[21]<<8); + case 21: f+=k[20]; + case 20: e+=(k[19]<<24); + case 19: e+=(k[18]<<16); + case 18: e+=(k[17]<<8); + case 17: e+=k[16]; + case 16: d+=(k[15]<<24); + case 15: d+=(k[14]<<16); + case 14: d+=(k[13]<<8); + case 13: d+=k[12]; + case 12: c+=(k[11]<<24); + case 11: c+=(k[10]<<16); + case 10: c+=(k[9]<<8); + case 9 : c+=k[8]; + case 8 : b+=(k[7]<<24); + case 7 : b+=(k[6]<<16); + case 6 : b+=(k[5]<<8); + case 5 : b+=k[4]; + case 4 : a+=(k[3]<<24); + case 3 : a+=(k[2]<<16); + case 2 : a+=(k[1]<<8); + case 1 : a+=k[0]; + } + mixc(a,b,c,d,e,f,g,h); + mixc(a,b,c,d,e,f,g,h); + mixc(a,b,c,d,e,f,g,h); + mixc(a,b,c,d,e,f,g,h); + + /*-------------------------------------------- report the result */ + state[0]=a; state[1]=b; state[2]=c; state[3]=d; + state[4]=e; state[5]=f; state[6]=g; state[7]=h; +} diff --git a/contrib/tools/yasm/libyasm/phash.h b/contrib/tools/yasm/libyasm/phash.h new file mode 100644 index 0000000000..2273a5df20 --- /dev/null +++ b/contrib/tools/yasm/libyasm/phash.h @@ -0,0 +1,19 @@ +/* Modified for use with yasm by Peter Johnson. */ +/* +------------------------------------------------------------------------------ +By Bob Jenkins, September 1996. +lookupa.h, a hash function for table lookup, same function as lookup.c. +Use this code in any way you wish. Public Domain. It has no warranty. +Source is http://burtleburtle.net/bob/c/lookupa.h +------------------------------------------------------------------------------ +*/ + +#ifndef YASM_LIB_DECL +#define YASM_LIB_DECL +#endif + +YASM_LIB_DECL +unsigned long phash_lookup(const char *k, size_t length, + unsigned long level); +YASM_LIB_DECL +void phash_checksum(const char *k, size_t length, unsigned long *state); diff --git a/contrib/tools/yasm/libyasm/preproc.h b/contrib/tools/yasm/libyasm/preproc.h new file mode 100644 index 0000000000..751b19e4b0 --- /dev/null +++ b/contrib/tools/yasm/libyasm/preproc.h @@ -0,0 +1,210 @@ +/** + * \file libyasm/preproc.h + * \brief YASM preprocessor module interface. + * + * \license + * 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. + * \endlicense + */ +#ifndef YASM_PREPROC_H +#define YASM_PREPROC_H + +#ifndef YASM_DOXYGEN +/** Base #yasm_preproc structure. Must be present as the first element in any + * #yasm_preproc implementation. + */ +typedef struct yasm_preproc_base { + /** #yasm_preproc_module implementation for this preprocessor. */ + const struct yasm_preproc_module *module; +} yasm_preproc_base; +#endif + +/** YASM preprocesor module interface. */ +typedef struct yasm_preproc_module { + /** One-line description of the preprocessor. */ + const char *name; + + /** Keyword used to select preprocessor on the command line. */ + const char *keyword; + + /** Create preprocessor. + * Module-level implementation of yasm_preproc_create(). + * Call yasm_preproc_create() instead of calling this function. + * + * \param in_filename initial starting filename, or "-" to read from + * stdin + * \param symtab symbol table (may be NULL if none) + * \param lm line mapping repository + * \param errwarns error/warnning set. + * \return New preprocessor. + * + * \note Any preprocessor errors and warnings are stored into errwarns. + */ + /*@only@*/ yasm_preproc * (*create) (const char *in_filename, + yasm_symtab *symtab, + yasm_linemap *lm, + yasm_errwarns *errwarns); + + /** Module-level implementation of yasm_preproc_destroy(). + * Call yasm_preproc_destroy() instead of calling this function. + */ + void (*destroy) (/*@only@*/ yasm_preproc *preproc); + + /** Module-level implementation of yasm_preproc_get_line(). + * Call yasm_preproc_get_line() instead of calling this function. + */ + char * (*get_line) (yasm_preproc *preproc); + + /** Module-level implementation of yasm_preproc_get_included_file(). + * Call yasm_preproc_get_included_file() instead of calling this function. + */ + size_t (*get_included_file) (yasm_preproc *preproc, /*@out@*/ char *buf, + size_t max_size); + + /** Module-level implementation of yasm_preproc_add_include_file(). + * Call yasm_preproc_add_include_file() instead of calling this function. + */ + void (*add_include_file) (yasm_preproc *preproc, const char *filename); + + /** Module-level implementation of yasm_preproc_predefine_macro(). + * Call yasm_preproc_predefine_macro() instead of calling this function. + */ + void (*predefine_macro) (yasm_preproc *preproc, const char *macronameval); + + /** Module-level implementation of yasm_preproc_undefine_macro(). + * Call yasm_preproc_undefine_macro() instead of calling this function. + */ + void (*undefine_macro) (yasm_preproc *preproc, const char *macroname); + + /** Module-level implementation of yasm_preproc_builtin_define(). + * Call yasm_preproc_builtin_define() instead of calling this function. + */ + void (*define_builtin) (yasm_preproc *preproc, const char *macronameval); + + /** Module-level implementation of yasm_preproc_add_standard(). + * Call yasm_preproc_add_standard() instead of calling this function. + */ + void (*add_standard) (yasm_preproc *preproc, const char **macros); +} yasm_preproc_module; + +/** Initialize preprocessor. + * The preprocessor needs access to the object format module to find out + * any output format specific macros. + * \param module preprocessor module + * \param in_filename initial starting filename, or "-" to read from stdin + * \param symtab symbol table (may be NULL if none) + * \param lm line mapping repository + * \param errwarns error/warning set + * \return New preprocessor. + * \note Errors/warnings are stored into errwarns. + */ +/*@only@*/ yasm_preproc *yasm_preproc_create + (yasm_preproc_module *module, const char *in_filename, + yasm_symtab *symtab, yasm_linemap *lm, yasm_errwarns *errwarns); + +/** Cleans up any allocated preproc memory. + * \param preproc preprocessor + */ +void yasm_preproc_destroy(/*@only@*/ yasm_preproc *preproc); + +/** Gets a single line of preprocessed source code. + * \param preproc preprocessor + * \return Allocated line of code, without the trailing \n. + */ +char *yasm_preproc_get_line(yasm_preproc *preproc); + +/** Get the next filename included by the source code. + * \param preproc preprocessor + * \param buf destination buffer for filename + * \param max_size maximum number of bytes that can be returned in buf + * \return Actual number of bytes returned in buf. + */ +size_t yasm_preproc_get_included_file(yasm_preproc *preproc, + /*@out@*/ char *buf, size_t max_size); + +/** Pre-include a file. + * \param preproc preprocessor + * \param filename filename + */ +void yasm_preproc_add_include_file(yasm_preproc *preproc, + const char *filename); + +/** Pre-define a macro. + * \param preproc preprocessor + * \param macronameval "name=value" string + */ +void yasm_preproc_predefine_macro(yasm_preproc *preproc, + const char *macronameval); + +/** Un-define a macro. + * \param preproc preprocessor + * \param macroname macro name + */ +void yasm_preproc_undefine_macro(yasm_preproc *preproc, const char *macroname); + +/** Define a builtin macro, preprocessed before the "standard" macros. + * \param preproc preprocessor + * \param macronameval "name=value" string + */ +void yasm_preproc_define_builtin(yasm_preproc *preproc, + const char *macronameval); + +/** Define additional standard macros, preprocessed after the builtins but + * prior to any user-defined macros. + * \param preproc preprocessor + * \param macros NULL-terminated array of macro strings + */ +void yasm_preproc_add_standard(yasm_preproc *preproc, + const char **macros); + +#ifndef YASM_DOXYGEN + +/* Inline macro implementations for preproc functions */ + +#define yasm_preproc_create(module, in_filename, symtab, lm, ews) \ + module->create(in_filename, symtab, lm, ews) + +#define yasm_preproc_destroy(preproc) \ + ((yasm_preproc_base *)preproc)->module->destroy(preproc) +#define yasm_preproc_get_line(preproc) \ + ((yasm_preproc_base *)preproc)->module->get_line(preproc) +#define yasm_preproc_get_included_file(preproc, buf, max_size) \ + ((yasm_preproc_base *)preproc)->module->get_included_file(preproc, buf, max_size) +#define yasm_preproc_add_include_file(preproc, filename) \ + ((yasm_preproc_base *)preproc)->module->add_include_file(preproc, filename) +#define yasm_preproc_predefine_macro(preproc, macronameval) \ + ((yasm_preproc_base *)preproc)->module->predefine_macro(preproc, \ + macronameval) +#define yasm_preproc_undefine_macro(preproc, macroname) \ + ((yasm_preproc_base *)preproc)->module->undefine_macro(preproc, macroname) +#define yasm_preproc_define_builtin(preproc, macronameval) \ + ((yasm_preproc_base *)preproc)->module->define_builtin(preproc, \ + macronameval) +#define yasm_preproc_add_standard(preproc, macros) \ + ((yasm_preproc_base *)preproc)->module->add_standard(preproc, \ + macros) + +#endif + +#endif diff --git a/contrib/tools/yasm/libyasm/replace_path.c b/contrib/tools/yasm/libyasm/replace_path.c new file mode 100644 index 0000000000..0deba70a6b --- /dev/null +++ b/contrib/tools/yasm/libyasm/replace_path.c @@ -0,0 +1,54 @@ +/* + * Copyright (c) 1988, 1993, 2019 + * The Regents of the University of California. All rights reserved. + * + * 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. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND 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 REGENTS OR 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" + +char * yasm_replace_path(const char* replace_map[], int size, const char* str, int pref_len) { + int i; + for (i=0; i<size; i++) { + const char* pos = strchr(replace_map[i], '='); + if (!pos) { + continue; + } + int repl_size = pos - replace_map[i]; + if (pref_len < repl_size) { + continue; + } + if (strncmp(replace_map[i], str, repl_size)) { + continue; + } + int subs_size = strlen(replace_map[i]) - (repl_size + 1); + int size = subs_size + pref_len - repl_size + 1; + char* out = yasm_xmalloc(size); + strncpy(out, pos + 1, subs_size); + strncpy(out + subs_size, str + repl_size, pref_len - repl_size); + out[size - 1] = '\0'; + return out; + } + return yasm__xstrndup(str, pref_len); +} diff --git a/contrib/tools/yasm/libyasm/section.c b/contrib/tools/yasm/libyasm/section.c new file mode 100644 index 0000000000..729d7770a4 --- /dev/null +++ b/contrib/tools/yasm/libyasm/section.c @@ -0,0 +1,1585 @@ +/* + * Section 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 <limits.h> + +#include "libyasm-stdint.h" +#include "coretype.h" +#include "hamt.h" +#include "valparam.h" +#include "assocdat.h" + +#include "linemap.h" +#include "errwarn.h" +#include "intnum.h" +#include "expr.h" +#include "value.h" +#include "symrec.h" + +#include "bytecode.h" +#include "arch.h" +#include "section.h" + +#include "dbgfmt.h" +#include "objfmt.h" + +#include "inttree.h" + + +struct yasm_section { + /*@reldef@*/ STAILQ_ENTRY(yasm_section) link; + + /*@dependent@*/ yasm_object *object; /* Pointer to parent object */ + + /*@owned@*/ char *name; /* strdup()'ed name (given by user) */ + + /* associated data; NULL if none */ + /*@null@*/ /*@only@*/ yasm__assoc_data *assoc_data; + + unsigned long align; /* Section alignment */ + + unsigned long opt_flags; /* storage for optimizer flags */ + + int code; /* section contains code (instructions) */ + int res_only; /* allow only resb family of bytecodes? */ + int def; /* "default" section, e.g. not specified by + using section directive */ + + /* the bytecodes for the section's contents */ + /*@reldef@*/ STAILQ_HEAD(yasm_bytecodehead, yasm_bytecode) bcs; + + /* the relocations for the section */ + /*@reldef@*/ STAILQ_HEAD(yasm_relochead, yasm_reloc) relocs; + + void (*destroy_reloc) (/*@only@*/ void *reloc); +}; + +static void yasm_section_destroy(/*@only@*/ yasm_section *sect); + +/* Wrapper around directive for HAMT insertion */ +typedef struct yasm_directive_wrap { + const yasm_directive *directive; +} yasm_directive_wrap; + +/* + * Standard "builtin" object directives. + */ + +static void +dir_extern(yasm_object *object, yasm_valparamhead *valparams, + yasm_valparamhead *objext_valparams, unsigned long line) +{ + yasm_valparam *vp = yasm_vps_first(valparams); + yasm_symrec *sym; + sym = yasm_symtab_declare(object->symtab, yasm_vp_id(vp), YASM_SYM_EXTERN, + line); + if (objext_valparams) { + yasm_valparamhead *vps = yasm_vps_create(); + *vps = *objext_valparams; /* structure copy */ + yasm_vps_initialize(objext_valparams); /* don't double-free */ + yasm_symrec_set_objext_valparams(sym, vps); + } +} + +static void +dir_global(yasm_object *object, yasm_valparamhead *valparams, + yasm_valparamhead *objext_valparams, unsigned long line) +{ + yasm_valparam *vp = yasm_vps_first(valparams); + yasm_symrec *sym; + sym = yasm_symtab_declare(object->symtab, yasm_vp_id(vp), YASM_SYM_GLOBAL, + line); + if (objext_valparams) { + yasm_valparamhead *vps = yasm_vps_create(); + *vps = *objext_valparams; /* structure copy */ + yasm_vps_initialize(objext_valparams); /* don't double-free */ + yasm_symrec_set_objext_valparams(sym, vps); + } +} + +static void +dir_common(yasm_object *object, yasm_valparamhead *valparams, + yasm_valparamhead *objext_valparams, unsigned long line) +{ + yasm_valparam *vp = yasm_vps_first(valparams); + yasm_valparam *vp2 = yasm_vps_next(vp); + yasm_expr *size = yasm_vp_expr(vp2, object->symtab, line); + yasm_symrec *sym; + + if (!size) { + yasm_error_set(YASM_ERROR_SYNTAX, + N_("no size specified in %s declaration"), "COMMON"); + return; + } + sym = yasm_symtab_declare(object->symtab, yasm_vp_id(vp), YASM_SYM_COMMON, + line); + yasm_symrec_set_common_size(sym, size); + if (objext_valparams) { + yasm_valparamhead *vps = yasm_vps_create(); + *vps = *objext_valparams; /* structure copy */ + yasm_vps_initialize(objext_valparams); /* don't double-free */ + yasm_symrec_set_objext_valparams(sym, vps); + } +} + +static void +dir_section(yasm_object *object, yasm_valparamhead *valparams, + yasm_valparamhead *objext_valparams, unsigned long line) +{ + yasm_section *new_section = + yasm_objfmt_section_switch(object, valparams, objext_valparams, line); + if (new_section) + object->cur_section = new_section; + else + yasm_error_set(YASM_ERROR_SYNTAX, + N_("invalid argument to directive `%s'"), "SECTION"); +} + +static const yasm_directive object_directives[] = { + { ".extern", "gas", dir_extern, YASM_DIR_ID_REQUIRED }, + { ".global", "gas", dir_global, YASM_DIR_ID_REQUIRED }, + { ".globl", "gas", dir_global, YASM_DIR_ID_REQUIRED }, + { "extern", "nasm", dir_extern, YASM_DIR_ID_REQUIRED }, + { "global", "nasm", dir_global, YASM_DIR_ID_REQUIRED }, + { "common", "nasm", dir_common, YASM_DIR_ID_REQUIRED }, + { "section", "nasm", dir_section, YASM_DIR_ARG_REQUIRED }, + { "segment", "nasm", dir_section, YASM_DIR_ARG_REQUIRED }, + { NULL, NULL, NULL, 0 } +}; + +static void +directive_level2_delete(/*@only@*/ void *data) +{ + yasm_xfree(data); +} + +static void +directive_level1_delete(/*@only@*/ void *data) +{ + HAMT_destroy(data, directive_level2_delete); +} + +static void +directives_add(yasm_object *object, /*@null@*/ const yasm_directive *dir) +{ + if (!dir) + return; + + while (dir->name) { + HAMT *level2 = HAMT_search(object->directives, dir->parser); + int replace; + yasm_directive_wrap *wrap = yasm_xmalloc(sizeof(yasm_directive_wrap)); + + if (!level2) { + replace = 0; + level2 = HAMT_insert(object->directives, dir->parser, + HAMT_create(1, yasm_internal_error_), + &replace, directive_level1_delete); + } + replace = 0; + wrap->directive = dir; + HAMT_insert(level2, dir->name, wrap, &replace, + directive_level2_delete); + dir++; + } +} + +/*@-compdestroy@*/ +yasm_object * +yasm_object_create(const char *src_filename, const char *obj_filename, + /*@kept@*/ yasm_arch *arch, + const yasm_objfmt_module *objfmt_module, + const yasm_dbgfmt_module *dbgfmt_module) +{ + yasm_object *object = yasm_xmalloc(sizeof(yasm_object)); + int matched, i; + + object->src_filename = yasm__xstrdup(src_filename); + object->deb_filename = NULL; + object->obj_filename = yasm__xstrdup(obj_filename); + + /* No prefix/suffix */ + object->global_prefix = yasm__xstrdup(""); + object->global_suffix = yasm__xstrdup(""); + + /* Create empty symbol table */ + object->symtab = yasm_symtab_create(); + + /* Initialize sections linked list */ + STAILQ_INIT(&object->sections); + + /* Create directives HAMT */ + object->directives = HAMT_create(1, yasm_internal_error_); + + /* Initialize the target architecture */ + object->arch = arch; + + /* Initialize things to NULL in case of error */ + object->dbgfmt = NULL; + + /* Initialize the object format */ + object->objfmt = yasm_objfmt_create(objfmt_module, object); + if (!object->objfmt) { + yasm_error_set(YASM_ERROR_GENERAL, + N_("object format `%s' does not support architecture `%s' machine `%s'"), + objfmt_module->keyword, ((yasm_arch_base *)arch)->module->keyword, + yasm_arch_get_machine(arch)); + goto error; + } + + /* Get a fresh copy of objfmt_module as it may have changed. */ + objfmt_module = ((yasm_objfmt_base *)object->objfmt)->module; + + /* Add an initial "default" section to object */ + object->cur_section = yasm_objfmt_add_default_section(object); + + /* Check to see if the requested debug format is in the allowed list + * for the active object format. + */ + matched = 0; + for (i=0; objfmt_module->dbgfmt_keywords[i]; i++) { + if (yasm__strcasecmp(objfmt_module->dbgfmt_keywords[i], + dbgfmt_module->keyword) == 0) { + matched = 1; + break; + } + } + + if (!matched) { + yasm_error_set(YASM_ERROR_GENERAL, + N_("`%s' is not a valid debug format for object format `%s'"), + dbgfmt_module->keyword, objfmt_module->keyword); + goto error; + } + + /* Initialize the debug format */ + object->dbgfmt = yasm_dbgfmt_create(dbgfmt_module, object); + if (!object->dbgfmt) { + yasm_error_set(YASM_ERROR_GENERAL, + N_("debug format `%s' does not work with object format `%s'"), + dbgfmt_module->keyword, objfmt_module->keyword); + goto error; + } + + /* Add directives to HAMT. Note ordering here determines priority. */ + directives_add(object, + ((yasm_objfmt_base *)object->objfmt)->module->directives); + directives_add(object, + ((yasm_dbgfmt_base *)object->dbgfmt)->module->directives); + directives_add(object, + ((yasm_arch_base *)object->arch)->module->directives); + directives_add(object, object_directives); + + return object; + +error: + yasm_object_destroy(object); + return NULL; +} +/*@=compdestroy@*/ + +/*@-onlytrans@*/ +yasm_section * +yasm_object_get_general(yasm_object *object, const char *name, + unsigned long align, int code, int res_only, + int *isnew, unsigned long line) +{ + yasm_section *s; + yasm_bytecode *bc; + + /* Search through current sections to see if we already have one with + * that name. + */ + STAILQ_FOREACH(s, &object->sections, link) { + if (strcmp(s->name, name) == 0) { + *isnew = 0; + return s; + } + } + + /* No: we have to allocate and create a new one. */ + + /* Okay, the name is valid; now allocate and initialize */ + s = yasm_xcalloc(1, sizeof(yasm_section)); + STAILQ_INSERT_TAIL(&object->sections, s, link); + + s->object = object; + s->name = yasm__xstrdup(name); + s->assoc_data = NULL; + s->align = align; + + /* Initialize bytecodes with one empty bytecode (acts as "prior" for first + * real bytecode in section. + */ + STAILQ_INIT(&s->bcs); + bc = yasm_bc_create_common(NULL, NULL, 0); + bc->section = s; + bc->offset = 0; + STAILQ_INSERT_TAIL(&s->bcs, bc, link); + + /* Initialize relocs */ + STAILQ_INIT(&s->relocs); + s->destroy_reloc = NULL; + + s->code = code; + s->res_only = res_only; + s->def = 0; + + /* Initialize object format specific data */ + yasm_objfmt_init_new_section(s, line); + + *isnew = 1; + return s; +} +/*@=onlytrans@*/ + +int +yasm_object_directive(yasm_object *object, const char *name, + const char *parser, yasm_valparamhead *valparams, + yasm_valparamhead *objext_valparams, + unsigned long line) +{ + HAMT *level2; + yasm_directive_wrap *wrap; + + level2 = HAMT_search(object->directives, parser); + if (!level2) + return 1; + + wrap = HAMT_search(level2, name); + if (!wrap) + return 1; + + yasm_call_directive(wrap->directive, object, valparams, objext_valparams, + line); + return 0; +} + +void +yasm_object_set_source_fn(yasm_object *object, const char *src_filename) +{ + yasm_xfree(object->src_filename); + object->src_filename = yasm__xstrdup(src_filename); + yasm_xfree(object->deb_filename); + object->deb_filename = NULL; +} + +void +yasm_object_set_global_prefix(yasm_object *object, const char *prefix) +{ + yasm_xfree(object->global_prefix); + object->global_prefix = yasm__xstrdup(prefix); +} + +void +yasm_object_set_global_suffix(yasm_object *object, const char *suffix) +{ + yasm_xfree(object->global_suffix); + object->global_suffix = yasm__xstrdup(suffix); +} + +int +yasm_section_is_code(yasm_section *sect) +{ + return sect->code; +} + +unsigned long +yasm_section_get_opt_flags(const yasm_section *sect) +{ + return sect->opt_flags; +} + +void +yasm_section_set_opt_flags(yasm_section *sect, unsigned long opt_flags) +{ + sect->opt_flags = opt_flags; +} + +int +yasm_section_is_default(const yasm_section *sect) +{ + return sect->def; +} + +void +yasm_section_set_default(yasm_section *sect, int def) +{ + sect->def = def; +} + +yasm_object * +yasm_section_get_object(const yasm_section *sect) +{ + return sect->object; +} + +void * +yasm_section_get_data(yasm_section *sect, + const yasm_assoc_data_callback *callback) +{ + return yasm__assoc_data_get(sect->assoc_data, callback); +} + +void +yasm_section_add_data(yasm_section *sect, + const yasm_assoc_data_callback *callback, void *data) +{ + sect->assoc_data = yasm__assoc_data_add(sect->assoc_data, callback, data); +} + +void +yasm_object_destroy(yasm_object *object) +{ + yasm_section *cur, *next; + + /* Delete object format, debug format, and arch. This can be called + * due to an error in yasm_object_create(), so look out for NULLs. + */ + if (object->objfmt) + yasm_objfmt_destroy(object->objfmt); + if (object->dbgfmt) + yasm_dbgfmt_destroy(object->dbgfmt); + + /* Delete sections */ + cur = STAILQ_FIRST(&object->sections); + while (cur) { + next = STAILQ_NEXT(cur, link); + yasm_section_destroy(cur); + cur = next; + } + + /* Delete directives HAMT */ + HAMT_destroy(object->directives, directive_level1_delete); + + /* Delete prefix/suffix */ + yasm_xfree(object->global_prefix); + yasm_xfree(object->global_suffix); + + /* Delete associated filenames */ + yasm_xfree(object->src_filename); + yasm_xfree(object->deb_filename); + yasm_xfree(object->obj_filename); + + /* Delete symbol table */ + yasm_symtab_destroy(object->symtab); + + /* Delete architecture */ + if (object->arch) + yasm_arch_destroy(object->arch); + + yasm_xfree(object); +} + +void +yasm_object_print(const yasm_object *object, FILE *f, int indent_level) +{ + yasm_section *cur; + + /* Print symbol table */ + fprintf(f, "%*sSymbol Table:\n", indent_level, ""); + yasm_symtab_print(object->symtab, f, indent_level+1); + + /* Print sections and bytecodes */ + STAILQ_FOREACH(cur, &object->sections, link) { + fprintf(f, "%*sSection:\n", indent_level, ""); + yasm_section_print(cur, f, indent_level+1, 1); + } +} + +void +yasm_object_finalize(yasm_object *object, yasm_errwarns *errwarns) +{ + yasm_section *sect; + + /* Iterate through sections */ + STAILQ_FOREACH(sect, &object->sections, link) { + yasm_bytecode *cur = STAILQ_FIRST(§->bcs); + yasm_bytecode *prev; + + /* Skip our locally created empty bytecode first. */ + prev = cur; + cur = STAILQ_NEXT(cur, link); + + /* Iterate through the remainder, if any. */ + while (cur) { + /* Finalize */ + yasm_bc_finalize(cur, prev); + yasm_errwarn_propagate(errwarns, cur->line); + prev = cur; + cur = STAILQ_NEXT(cur, link); + } + } +} + +int +yasm_object_sections_traverse(yasm_object *object, /*@null@*/ void *d, + int (*func) (yasm_section *sect, + /*@null@*/ void *d)) +{ + yasm_section *cur; + + STAILQ_FOREACH(cur, &object->sections, link) { + int retval = func(cur, d); + if (retval != 0) + return retval; + } + return 0; +} + +/*@-onlytrans@*/ +yasm_section * +yasm_object_find_general(yasm_object *object, const char *name) +{ + yasm_section *cur; + + STAILQ_FOREACH(cur, &object->sections, link) { + if (strcmp(cur->name, name) == 0) + return cur; + } + return NULL; +} +/*@=onlytrans@*/ + +void +yasm_section_add_reloc(yasm_section *sect, yasm_reloc *reloc, + void (*destroy_func) (/*@only@*/ void *reloc)) +{ + STAILQ_INSERT_TAIL(§->relocs, reloc, link); + if (!destroy_func) + yasm_internal_error(N_("NULL destroy function given to add_reloc")); + else if (sect->destroy_reloc && destroy_func != sect->destroy_reloc) + yasm_internal_error(N_("different destroy function given to add_reloc")); + sect->destroy_reloc = destroy_func; +} + +/*@null@*/ yasm_reloc * +yasm_section_relocs_first(yasm_section *sect) +{ + return STAILQ_FIRST(§->relocs); +} + +#undef yasm_section_reloc_next +/*@null@*/ yasm_reloc * +yasm_section_reloc_next(yasm_reloc *reloc) +{ + return STAILQ_NEXT(reloc, link); +} + +void +yasm_reloc_get(yasm_reloc *reloc, yasm_intnum **addrp, yasm_symrec **symp) +{ + *addrp = reloc->addr; + *symp = reloc->sym; +} + + +yasm_bytecode * +yasm_section_bcs_first(yasm_section *sect) +{ + return STAILQ_FIRST(§->bcs); +} + +yasm_bytecode * +yasm_section_bcs_last(yasm_section *sect) +{ + return STAILQ_LAST(§->bcs, yasm_bytecode, link); +} + +yasm_bytecode * +yasm_section_bcs_append(yasm_section *sect, yasm_bytecode *bc) +{ + if (bc) { + if (bc->callback) { + bc->section = sect; /* record parent section */ + STAILQ_INSERT_TAIL(§->bcs, bc, link); + return bc; + } else + yasm_xfree(bc); + } + return (yasm_bytecode *)NULL; +} + +int +yasm_section_bcs_traverse(yasm_section *sect, + /*@null@*/ yasm_errwarns *errwarns, + /*@null@*/ void *d, + int (*func) (yasm_bytecode *bc, /*@null@*/ void *d)) +{ + yasm_bytecode *cur = STAILQ_FIRST(§->bcs); + + /* Skip our locally created empty bytecode first. */ + cur = STAILQ_NEXT(cur, link); + + /* Iterate through the remainder, if any. */ + while (cur) { + int retval = func(cur, d); + if (errwarns) + yasm_errwarn_propagate(errwarns, cur->line); + if (retval != 0) + return retval; + cur = STAILQ_NEXT(cur, link); + } + return 0; +} + +const char * +yasm_section_get_name(const yasm_section *sect) +{ + return sect->name; +} + +void +yasm_section_set_align(yasm_section *sect, unsigned long align, + unsigned long line) +{ + sect->align = align; +} + +unsigned long +yasm_section_get_align(const yasm_section *sect) +{ + return sect->align; +} + +static void +yasm_section_destroy(yasm_section *sect) +{ + yasm_bytecode *cur, *next; + yasm_reloc *r_cur, *r_next; + + if (!sect) + return; + + yasm_xfree(sect->name); + yasm__assoc_data_destroy(sect->assoc_data); + + /* Delete bytecodes */ + cur = STAILQ_FIRST(§->bcs); + while (cur) { + next = STAILQ_NEXT(cur, link); + yasm_bc_destroy(cur); + cur = next; + } + + /* Delete relocations */ + r_cur = STAILQ_FIRST(§->relocs); + while (r_cur) { + r_next = STAILQ_NEXT(r_cur, link); + yasm_intnum_destroy(r_cur->addr); + sect->destroy_reloc(r_cur); + r_cur = r_next; + } + + yasm_xfree(sect); +} + +void +yasm_section_print(const yasm_section *sect, FILE *f, int indent_level, + int print_bcs) +{ + if (!sect) { + fprintf(f, "%*s(none)\n", indent_level, ""); + return; + } + + fprintf(f, "%*sname=%s\n", indent_level, "", sect->name); + + if (sect->assoc_data) { + fprintf(f, "%*sAssociated data:\n", indent_level, ""); + yasm__assoc_data_print(sect->assoc_data, f, indent_level+1); + } + + if (print_bcs) { + yasm_bytecode *cur; + + fprintf(f, "%*sBytecodes:\n", indent_level, ""); + + STAILQ_FOREACH(cur, §->bcs, link) { + fprintf(f, "%*sNext Bytecode:\n", indent_level+1, ""); + yasm_bc_print(cur, f, indent_level+2); + } + } +} + +/* + * Robertson (1977) optimizer + * Based (somewhat loosely) on the algorithm given in: + * MRC Technical Summary Report # 1779 + * CODE GENERATION FOR SHORT/LONG ADDRESS MACHINES + * Edward L. Robertson + * Mathematics Research Center + * University of Wisconsin-Madison + * 610 Walnut Street + * Madison, Wisconsin 53706 + * August 1977 + * + * Key components of algorithm: + * - start assuming all short forms + * - build spans for short->long transition dependencies + * - if a long form is needed, walk the dependencies and update + * Major differences from Robertson's algorithm: + * - detection of cycles + * - any difference of two locations is allowed + * - handling of alignment/org gaps (offset setting) + * - handling of multiples + * + * Data structures: + * - Interval tree to store spans and associated data + * - Queues QA and QB + * + * Each span keeps track of: + * - Associated bytecode (bytecode that depends on the span length) + * - Active/inactive state (starts out active) + * - Sign (negative/positive; negative being "backwards" in address) + * - Current length in bytes + * - New length in bytes + * - Negative/Positive thresholds + * - Span ID (unique within each bytecode) + * + * How org and align and any other offset-based bytecodes are handled: + * + * Some portions are critical values that must not depend on any bytecode + * offset (either relative or absolute). + * + * All offset-setters (ORG and ALIGN) are put into a linked list in section + * order (e.g. increasing offset order). Each span keeps track of the next + * offset-setter following the span's associated bytecode. + * + * When a bytecode is expanded, the next offset-setter is examined. The + * offset-setter may be able to absorb the expansion (e.g. any offset + * following it would not change), or it may have to move forward (in the + * case of align) or error (in the case of org). If it has to move forward, + * following offset-setters must also be examined for absorption or moving + * forward. In either case, the ongoing offset is updated as well as the + * lengths of any spans dependent on the offset-setter. + * + * Alignment/ORG value is critical value. + * Cannot be combined with TIMES. + * + * How times is handled: + * + * TIMES: Handled separately from bytecode "raw" size. If not span-dependent, + * trivial (just multiplied in at any bytecode size increase). Span + * dependent times update on any change (span ID 0). If the resultant + * next bytecode offset would be less than the old next bytecode offset, + * error. Otherwise increase offset and update dependent spans. + * + * To reduce interval tree size, a first expansion pass is performed + * before the spans are added to the tree. + * + * Basic algorithm outline: + * + * 1. Initialization: + * a. Number bytecodes sequentially (via bc_index) and calculate offsets + * of all bytecodes assuming minimum length, building a list of all + * dependent spans as we go. + * "minimum" here means absolute minimum: + * - align/org (offset-based) bumps offset as normal + * - times values (with span-dependent values) assumed to be 0 + * b. Iterate over spans. Set span length based on bytecode offsets + * determined in 1a. If span is "certainly" long because the span + * is an absolute reference to another section (or external) or the + * distance calculated based on the minimum length is greater than the + * span's threshold, expand the span's bytecode, and if no further + * expansion can result, mark span as inactive. + * c. Iterate over bytecodes to update all bytecode offsets based on new + * (expanded) lengths calculated in 1b. + * d. Iterate over active spans. Add span to interval tree. Update span's + * length based on new bytecode offsets determined in 1c. If span's + * length exceeds long threshold, add that span to Q. + * 2. Main loop: + * While Q not empty: + * Expand BC dependent on span at head of Q (and remove span from Q). + * Update span: + * If BC no longer dependent on span, mark span as inactive. + * If BC has new thresholds for span, update span. + * If BC increased in size, for each active span that contains BC: + * Increase span length by difference between short and long BC length. + * If span exceeds long threshold (or is flagged to recalculate on any + * change), add it to tail of Q. + * 3. Final pass over bytecodes to generate final offsets. + */ + +typedef struct yasm_span yasm_span; + +typedef struct yasm_offset_setter { + /* Linked list in section order (e.g. offset order) */ + /*@reldef@*/ STAILQ_ENTRY(yasm_offset_setter) link; + + /*@dependent@*/ yasm_bytecode *bc; + + unsigned long cur_val, new_val; + unsigned long thres; +} yasm_offset_setter; + +typedef struct yasm_span_term { + yasm_bytecode *precbc, *precbc2; + yasm_span *span; /* span this term is a member of */ + long cur_val, new_val; + unsigned int subst; +} yasm_span_term; + +struct yasm_span { + /*@reldef@*/ TAILQ_ENTRY(yasm_span) link; /* for allocation tracking */ + /*@reldef@*/ STAILQ_ENTRY(yasm_span) linkq; /* for Q */ + + /*@dependent@*/ yasm_bytecode *bc; + + yasm_value depval; + + /* span term for relative portion of value */ + yasm_span_term *rel_term; + /* span terms in absolute portion of value */ + yasm_span_term *terms; + yasm_expr__item *items; + unsigned int num_terms; + + long cur_val; + long new_val; + + long neg_thres; + long pos_thres; + + int id; + + int active; + + /* NULL-terminated array of spans that led to this span. Used only for + * checking for circular references (cycles) with id=0 spans. + */ + yasm_span **backtrace; + int backtrace_size; + + /* First offset setter following this span's bytecode */ + yasm_offset_setter *os; +}; + +typedef struct optimize_data { + /*@reldef@*/ TAILQ_HEAD(yasm_span_head, yasm_span) spans; + /*@reldef@*/ STAILQ_HEAD(yasm_span_shead, yasm_span) QA, QB; + /*@only@*/ IntervalTree *itree; + /*@reldef@*/ STAILQ_HEAD(offset_setters_head, yasm_offset_setter) + offset_setters; + long len_diff; /* used only for optimize_term_expand */ + yasm_span *span; /* used only for check_cycle */ + yasm_offset_setter *os; +} optimize_data; + +static yasm_span * +create_span(yasm_bytecode *bc, int id, /*@null@*/ const yasm_value *value, + long neg_thres, long pos_thres, yasm_offset_setter *os) +{ + yasm_span *span = yasm_xmalloc(sizeof(yasm_span)); + + span->bc = bc; + if (value) + yasm_value_init_copy(&span->depval, value); + else + yasm_value_initialize(&span->depval, NULL, 0); + span->rel_term = NULL; + span->terms = NULL; + span->items = NULL; + span->num_terms = 0; + span->cur_val = 0; + span->new_val = 0; + span->neg_thres = neg_thres; + span->pos_thres = pos_thres; + span->id = id; + span->active = 1; + span->backtrace = NULL; + span->backtrace_size = 0; + span->os = os; + + return span; +} + +static void +optimize_add_span(void *add_span_data, yasm_bytecode *bc, int id, + const yasm_value *value, long neg_thres, long pos_thres) +{ + optimize_data *optd = (optimize_data *)add_span_data; + yasm_span *span; + span = create_span(bc, id, value, neg_thres, pos_thres, optd->os); + TAILQ_INSERT_TAIL(&optd->spans, span, link); +} + +static void +add_span_term(unsigned int subst, yasm_bytecode *precbc, + yasm_bytecode *precbc2, void *d) +{ + yasm_span *span = d; + yasm_intnum *intn; + + if (subst >= span->num_terms) { + /* Linear expansion since total number is essentially always small */ + span->num_terms = subst+1; + span->terms = yasm_xrealloc(span->terms, + span->num_terms*sizeof(yasm_span_term)); + } + span->terms[subst].precbc = precbc; + span->terms[subst].precbc2 = precbc2; + span->terms[subst].span = span; + span->terms[subst].subst = subst; + + intn = yasm_calc_bc_dist(precbc, precbc2); + if (!intn) + yasm_internal_error(N_("could not calculate bc distance")); + span->terms[subst].cur_val = 0; + span->terms[subst].new_val = yasm_intnum_get_int(intn); + yasm_intnum_destroy(intn); +} + +static void +span_create_terms(yasm_span *span) +{ + unsigned int i; + + /* Split out sym-sym terms in absolute portion of dependent value */ + if (span->depval.abs) { + span->num_terms = yasm_expr__bc_dist_subst(&span->depval.abs, span, + add_span_term); + if (span->num_terms > 0) { + span->items = yasm_xmalloc(span->num_terms*sizeof(yasm_expr__item)); + for (i=0; i<span->num_terms; i++) { + /* Create items with dummy value */ + span->items[i].type = YASM_EXPR_INT; + span->items[i].data.intn = yasm_intnum_create_int(0); + + /* Check for circular references */ + if (span->id <= 0 && + ((span->bc->bc_index > span->terms[i].precbc->bc_index && + span->bc->bc_index <= span->terms[i].precbc2->bc_index) || + (span->bc->bc_index > span->terms[i].precbc2->bc_index && + span->bc->bc_index <= span->terms[i].precbc->bc_index))) + yasm_error_set(YASM_ERROR_VALUE, + N_("circular reference detected")); + } + } + } + + /* Create term for relative portion of dependent value */ + if (span->depval.rel) { + yasm_bytecode *rel_precbc; + int sym_local; + + sym_local = yasm_symrec_get_label(span->depval.rel, &rel_precbc); + if (span->depval.wrt || span->depval.seg_of || span->depval.section_rel + || !sym_local) + return; /* we can't handle SEG, WRT, or external symbols */ + if (rel_precbc->section != span->bc->section) + return; /* not in this section */ + if (!span->depval.curpos_rel) + return; /* not PC-relative */ + + span->rel_term = yasm_xmalloc(sizeof(yasm_span_term)); + span->rel_term->precbc = NULL; + span->rel_term->precbc2 = rel_precbc; + span->rel_term->span = span; + span->rel_term->subst = ~0U; + + span->rel_term->cur_val = 0; + span->rel_term->new_val = yasm_bc_next_offset(rel_precbc) - + span->bc->offset; + } +} + +/* Recalculate span value based on current span replacement values. + * Returns 1 if span needs expansion (e.g. exceeded thresholds). + */ +static int +recalc_normal_span(yasm_span *span) +{ + span->new_val = 0; + + if (span->depval.abs) { + yasm_expr *abs_copy = yasm_expr_copy(span->depval.abs); + /*@null@*/ /*@dependent@*/ yasm_intnum *num; + + /* Update sym-sym terms and substitute back into expr */ + unsigned int i; + for (i=0; i<span->num_terms; i++) + yasm_intnum_set_int(span->items[i].data.intn, + span->terms[i].new_val); + yasm_expr__subst(abs_copy, span->num_terms, span->items); + num = yasm_expr_get_intnum(&abs_copy, 0); + if (num) + span->new_val = yasm_intnum_get_int(num); + else + span->new_val = LONG_MAX; /* too complex; force to longest form */ + yasm_expr_destroy(abs_copy); + } + + if (span->rel_term) { + if (span->new_val != LONG_MAX && span->rel_term->new_val != LONG_MAX) + span->new_val += span->rel_term->new_val >> span->depval.rshift; + else + span->new_val = LONG_MAX; /* too complex; force to longest form */ + } else if (span->depval.rel) + span->new_val = LONG_MAX; /* too complex; force to longest form */ + + if (span->new_val == LONG_MAX) + span->active = 0; + + /* If id<=0, flag update on any change */ + if (span->id <= 0) + return (span->new_val != span->cur_val); + + return (span->new_val < span->neg_thres + || span->new_val > span->pos_thres); +} + +/* Updates all bytecode offsets. For offset-based bytecodes, calls expand + * to determine new length. + */ +static int +update_all_bc_offsets(yasm_object *object, yasm_errwarns *errwarns) +{ + yasm_section *sect; + int saw_error = 0; + + STAILQ_FOREACH(sect, &object->sections, link) { + unsigned long offset = 0; + + yasm_bytecode *bc = STAILQ_FIRST(§->bcs); + yasm_bytecode *prevbc; + + /* Skip our locally created empty bytecode first. */ + prevbc = bc; + bc = STAILQ_NEXT(bc, link); + + /* Iterate through the remainder, if any. */ + while (bc) { + if (bc->callback->special == YASM_BC_SPECIAL_OFFSET) { + /* Recalculate/adjust len of offset-based bytecodes here */ + long neg_thres = 0; + long pos_thres = (long)yasm_bc_next_offset(bc); + int retval = yasm_bc_expand(bc, 1, 0, + (long)yasm_bc_next_offset(prevbc), + &neg_thres, &pos_thres); + yasm_errwarn_propagate(errwarns, bc->line); + if (retval < 0) + saw_error = 1; + } + bc->offset = offset; + offset += bc->len*bc->mult_int; + prevbc = bc; + bc = STAILQ_NEXT(bc, link); + } + } + return saw_error; +} + +static void +span_destroy(/*@only@*/ yasm_span *span) +{ + unsigned int i; + + yasm_value_delete(&span->depval); + if (span->rel_term) + yasm_xfree(span->rel_term); + if (span->terms) + yasm_xfree(span->terms); + if (span->items) { + for (i=0; i<span->num_terms; i++) + yasm_intnum_destroy(span->items[i].data.intn); + yasm_xfree(span->items); + } + if (span->backtrace) + yasm_xfree(span->backtrace); + yasm_xfree(span); +} + +static void +optimize_cleanup(optimize_data *optd) +{ + yasm_span *s1, *s2; + yasm_offset_setter *os1, *os2; + + IT_destroy(optd->itree); + + s1 = TAILQ_FIRST(&optd->spans); + while (s1) { + s2 = TAILQ_NEXT(s1, link); + span_destroy(s1); + s1 = s2; + } + + os1 = STAILQ_FIRST(&optd->offset_setters); + while (os1) { + os2 = STAILQ_NEXT(os1, link); + yasm_xfree(os1); + os1 = os2; + } +} + +static void +optimize_itree_add(IntervalTree *itree, yasm_span *span, yasm_span_term *term) +{ + long precbc_index, precbc2_index; + unsigned long low, high; + + /* Update term length */ + if (term->precbc) + precbc_index = term->precbc->bc_index; + else + precbc_index = span->bc->bc_index-1; + + if (term->precbc2) + precbc2_index = term->precbc2->bc_index; + else + precbc2_index = span->bc->bc_index-1; + + if (precbc_index < precbc2_index) { + low = precbc_index+1; + high = precbc2_index; + } else if (precbc_index > precbc2_index) { + low = precbc2_index+1; + high = precbc_index; + } else + return; /* difference is same bc - always 0! */ + + IT_insert(itree, (long)low, (long)high, term); +} + +static void +check_cycle(IntervalTreeNode *node, void *d) +{ + optimize_data *optd = d; + yasm_span_term *term = node->data; + yasm_span *depspan = term->span; + int i; + int depspan_bt_alloc; + + /* Only check for cycles in id=0 spans */ + if (depspan->id > 0) + return; + + /* Check for a circular reference by looking to see if this dependent + * span is in our backtrace. + */ + if (optd->span->backtrace) { + for (i=0; i<optd->span->backtrace_size; i++) { + if (optd->span->backtrace[i] == depspan) + yasm_error_set(YASM_ERROR_VALUE, + N_("circular reference detected")); + } + } + + /* Add our complete backtrace and ourselves to backtrace of dependent + * span. + */ + if (!depspan->backtrace) { + depspan->backtrace = yasm_xmalloc((optd->span->backtrace_size+1)* + sizeof(yasm_span *)); + if (optd->span->backtrace_size > 0) + memcpy(depspan->backtrace, optd->span->backtrace, + optd->span->backtrace_size*sizeof(yasm_span *)); + depspan->backtrace[optd->span->backtrace_size] = optd->span; + depspan->backtrace_size = optd->span->backtrace_size+1; + return; + } + + /* Add our complete backtrace, checking for duplicates */ + depspan_bt_alloc = depspan->backtrace_size; + for (i=0; i<optd->span->backtrace_size; i++) { + int present = 0; + int j; + for (j=0; j<depspan->backtrace_size; j++) { + if (optd->span->backtrace[i] == optd->span->backtrace[j]) { + present = 1; + break; + } + } + if (present) + continue; + /* Not already in array; add it. */ + if (depspan->backtrace_size >= depspan_bt_alloc) + { + depspan_bt_alloc *= 2; + depspan->backtrace = + yasm_xrealloc(depspan->backtrace, + depspan_bt_alloc*sizeof(yasm_span *)); + } + depspan->backtrace[depspan->backtrace_size] = optd->span->backtrace[i]; + depspan->backtrace_size++; + } + + /* Add ourselves. */ + if (depspan->backtrace_size >= depspan_bt_alloc) + { + depspan_bt_alloc++; + depspan->backtrace = + yasm_xrealloc(depspan->backtrace, + depspan_bt_alloc*sizeof(yasm_span *)); + } + depspan->backtrace[depspan->backtrace_size] = optd->span; + depspan->backtrace_size++; +} + +static void +optimize_term_expand(IntervalTreeNode *node, void *d) +{ + optimize_data *optd = d; + yasm_span_term *term = node->data; + yasm_span *span = term->span; + long len_diff = optd->len_diff; + long precbc_index, precbc2_index; + + /* Don't expand inactive spans */ + if (!span->active) + return; + + /* Update term length */ + if (term->precbc) + precbc_index = term->precbc->bc_index; + else + precbc_index = span->bc->bc_index-1; + + if (term->precbc2) + precbc2_index = term->precbc2->bc_index; + else + precbc2_index = span->bc->bc_index-1; + + if (precbc_index < precbc2_index) + term->new_val += len_diff; + else + term->new_val -= len_diff; + + /* If already on Q, don't re-add */ + if (span->active == 2) + return; + + /* Update term and check against thresholds */ + if (!recalc_normal_span(span)) + return; /* didn't exceed thresholds, we're done */ + + /* Exceeded thresholds, need to add to Q for expansion */ + if (span->id <= 0) + STAILQ_INSERT_TAIL(&optd->QA, span, linkq); + else + STAILQ_INSERT_TAIL(&optd->QB, span, linkq); + span->active = 2; /* Mark as being in Q */ +} + +void +yasm_object_optimize(yasm_object *object, yasm_errwarns *errwarns) +{ + yasm_section *sect; + unsigned long bc_index = 0; + int saw_error = 0; + optimize_data optd; + yasm_span *span, *span_temp; + yasm_offset_setter *os; + int retval; + unsigned int i; + + TAILQ_INIT(&optd.spans); + STAILQ_INIT(&optd.offset_setters); + optd.itree = IT_create(); + + /* Create an placeholder offset setter for spans to point to; this will + * get updated if/when we actually run into one. + */ + os = yasm_xmalloc(sizeof(yasm_offset_setter)); + os->bc = NULL; + os->cur_val = 0; + os->new_val = 0; + os->thres = 0; + STAILQ_INSERT_TAIL(&optd.offset_setters, os, link); + optd.os = os; + + /* Step 1a */ + STAILQ_FOREACH(sect, &object->sections, link) { + unsigned long offset = 0; + + yasm_bytecode *bc = STAILQ_FIRST(§->bcs); + + bc->bc_index = bc_index++; + + /* Skip our locally created empty bytecode first. */ + bc = STAILQ_NEXT(bc, link); + + /* Iterate through the remainder, if any. */ + while (bc) { + bc->bc_index = bc_index++; + bc->offset = offset; + + retval = yasm_bc_calc_len(bc, optimize_add_span, &optd); + yasm_errwarn_propagate(errwarns, bc->line); + if (retval) + saw_error = 1; + else { + if (bc->callback->special == YASM_BC_SPECIAL_OFFSET) { + /* Remember it as offset setter */ + os->bc = bc; + os->thres = yasm_bc_next_offset(bc); + + /* Create new placeholder */ + os = yasm_xmalloc(sizeof(yasm_offset_setter)); + os->bc = NULL; + os->cur_val = 0; + os->new_val = 0; + os->thres = 0; + STAILQ_INSERT_TAIL(&optd.offset_setters, os, link); + optd.os = os; + + if (bc->multiple) { + yasm_error_set(YASM_ERROR_VALUE, + N_("cannot combine multiples and setting assembly position")); + yasm_errwarn_propagate(errwarns, bc->line); + saw_error = 1; + } + } + + offset += bc->len*bc->mult_int; + } + + bc = STAILQ_NEXT(bc, link); + } + } + + if (saw_error) { + optimize_cleanup(&optd); + return; + } + + /* Step 1b */ + TAILQ_FOREACH_SAFE(span, &optd.spans, link, span_temp) { + span_create_terms(span); + if (yasm_error_occurred()) { + yasm_errwarn_propagate(errwarns, span->bc->line); + saw_error = 1; + } else if (recalc_normal_span(span)) { + retval = yasm_bc_expand(span->bc, span->id, span->cur_val, + span->new_val, &span->neg_thres, + &span->pos_thres); + yasm_errwarn_propagate(errwarns, span->bc->line); + if (retval < 0) + saw_error = 1; + else if (retval > 0) { + if (!span->active) { + yasm_error_set(YASM_ERROR_VALUE, + N_("secondary expansion of an external/complex value")); + yasm_errwarn_propagate(errwarns, span->bc->line); + saw_error = 1; + } + } else { + TAILQ_REMOVE(&optd.spans, span, link); + span_destroy(span); + continue; + } + } + span->cur_val = span->new_val; + } + + if (saw_error) { + optimize_cleanup(&optd); + return; + } + + /* Step 1c */ + if (update_all_bc_offsets(object, errwarns)) { + optimize_cleanup(&optd); + return; + } + + /* Step 1d */ + STAILQ_INIT(&optd.QB); + TAILQ_FOREACH(span, &optd.spans, link) { + yasm_intnum *intn; + + /* Update span terms based on new bc offsets */ + for (i=0; i<span->num_terms; i++) { + intn = yasm_calc_bc_dist(span->terms[i].precbc, + span->terms[i].precbc2); + if (!intn) + yasm_internal_error(N_("could not calculate bc distance")); + span->terms[i].cur_val = span->terms[i].new_val; + span->terms[i].new_val = yasm_intnum_get_int(intn); + yasm_intnum_destroy(intn); + } + if (span->rel_term) { + span->rel_term->cur_val = span->rel_term->new_val; + if (span->rel_term->precbc2) + span->rel_term->new_val = + yasm_bc_next_offset(span->rel_term->precbc2) - + span->bc->offset; + else + span->rel_term->new_val = span->bc->offset - + yasm_bc_next_offset(span->rel_term->precbc); + } + + if (recalc_normal_span(span)) { + /* Exceeded threshold, add span to QB */ + STAILQ_INSERT_TAIL(&optd.QB, span, linkq); + span->active = 2; + } + } + + /* Do we need step 2? If not, go ahead and exit. */ + if (STAILQ_EMPTY(&optd.QB)) { + optimize_cleanup(&optd); + return; + } + + /* Update offset-setters values */ + STAILQ_FOREACH(os, &optd.offset_setters, link) { + if (!os->bc) + continue; + os->thres = yasm_bc_next_offset(os->bc); + os->new_val = os->bc->offset; + os->cur_val = os->new_val; + } + + /* Build up interval tree */ + TAILQ_FOREACH(span, &optd.spans, link) { + for (i=0; i<span->num_terms; i++) + optimize_itree_add(optd.itree, span, &span->terms[i]); + if (span->rel_term) + optimize_itree_add(optd.itree, span, span->rel_term); + } + + /* Look for cycles in times expansion (span.id==0) */ + TAILQ_FOREACH(span, &optd.spans, link) { + if (span->id > 0) + continue; + optd.span = span; + IT_enumerate(optd.itree, (long)span->bc->bc_index, + (long)span->bc->bc_index, &optd, check_cycle); + if (yasm_error_occurred()) { + yasm_errwarn_propagate(errwarns, span->bc->line); + saw_error = 1; + } + } + + if (saw_error) { + optimize_cleanup(&optd); + return; + } + + /* Step 2 */ + STAILQ_INIT(&optd.QA); + while (!STAILQ_EMPTY(&optd.QA) || !(STAILQ_EMPTY(&optd.QB))) { + unsigned long orig_len; + long offset_diff; + + /* QA is for TIMES, update those first, then update non-TIMES. + * This is so that TIMES can absorb increases before we look at + * expanding non-TIMES BCs. + */ + if (!STAILQ_EMPTY(&optd.QA)) { + span = STAILQ_FIRST(&optd.QA); + STAILQ_REMOVE_HEAD(&optd.QA, linkq); + } else { + span = STAILQ_FIRST(&optd.QB); + STAILQ_REMOVE_HEAD(&optd.QB, linkq); + } + + if (!span->active) + continue; + span->active = 1; /* no longer in Q */ + + /* Make sure we ended up ultimately exceeding thresholds; due to + * offset BCs we may have been placed on Q and then reduced in size + * again. + */ + if (!recalc_normal_span(span)) + continue; + + orig_len = span->bc->len * span->bc->mult_int; + + retval = yasm_bc_expand(span->bc, span->id, span->cur_val, + span->new_val, &span->neg_thres, + &span->pos_thres); + yasm_errwarn_propagate(errwarns, span->bc->line); + + if (retval < 0) { + /* error */ + saw_error = 1; + continue; + } else if (retval > 0) { + /* another threshold, keep active */ + for (i=0; i<span->num_terms; i++) + span->terms[i].cur_val = span->terms[i].new_val; + if (span->rel_term) + span->rel_term->cur_val = span->rel_term->new_val; + span->cur_val = span->new_val; + } else + span->active = 0; /* we're done with this span */ + + optd.len_diff = span->bc->len * span->bc->mult_int - orig_len; + if (optd.len_diff == 0) + continue; /* didn't increase in size */ + + /* Iterate over all spans dependent across the bc just expanded */ + IT_enumerate(optd.itree, (long)span->bc->bc_index, + (long)span->bc->bc_index, &optd, optimize_term_expand); + + /* Iterate over offset-setters that follow the bc just expanded. + * Stop iteration if: + * - no more offset-setters in this section + * - offset-setter didn't move its following offset + */ + os = span->os; + offset_diff = optd.len_diff; + while (os->bc && os->bc->section == span->bc->section + && offset_diff != 0) { + unsigned long old_next_offset = os->cur_val + os->bc->len; + long neg_thres_temp; + + if (offset_diff < 0 && (unsigned long)(-offset_diff) > os->new_val) + yasm_internal_error(N_("org/align went to negative offset")); + os->new_val += offset_diff; + + orig_len = os->bc->len; + retval = yasm_bc_expand(os->bc, 1, (long)os->cur_val, + (long)os->new_val, &neg_thres_temp, + (long *)&os->thres); + yasm_errwarn_propagate(errwarns, os->bc->line); + + offset_diff = os->new_val + os->bc->len - old_next_offset; + optd.len_diff = os->bc->len - orig_len; + if (optd.len_diff != 0) + IT_enumerate(optd.itree, (long)os->bc->bc_index, + (long)os->bc->bc_index, &optd, optimize_term_expand); + + os->cur_val = os->new_val; + os = STAILQ_NEXT(os, link); + } + } + + if (saw_error) { + optimize_cleanup(&optd); + return; + } + + /* Step 3 */ + update_all_bc_offsets(object, errwarns); + optimize_cleanup(&optd); +} diff --git a/contrib/tools/yasm/libyasm/section.h b/contrib/tools/yasm/libyasm/section.h new file mode 100644 index 0000000000..521031f3a5 --- /dev/null +++ b/contrib/tools/yasm/libyasm/section.h @@ -0,0 +1,384 @@ +/** + * \file libyasm/section.h + * \brief YASM section interface. + * + * \license + * 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: + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - 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. + * \endlicense + */ +#ifndef YASM_SECTION_H +#define YASM_SECTION_H + +#ifndef YASM_LIB_DECL +#define YASM_LIB_DECL +#endif + +/** Basic YASM relocation. Object formats will need to extend this + * structure with additional fields for relocation type, etc. + */ +typedef struct yasm_reloc yasm_reloc; + +struct yasm_reloc { + /*@reldef@*/ STAILQ_ENTRY(yasm_reloc) link; /**< Link to next reloc */ + yasm_intnum *addr; /**< Offset (address) within section */ + /*@dependent@*/ yasm_symrec *sym; /**< Relocated symbol */ +}; + +/** An object. This is the internal representation of an object file. */ +struct yasm_object { + /*@owned@*/ char *src_filename; /**< Source filename */ + /*@owned@*/ char *deb_filename; /**< Debug filename */ + /*@owned@*/ char *obj_filename; /**< Object filename */ + + /*@owned@*/ yasm_symtab *symtab; /**< Symbol table */ + /*@owned@*/ yasm_arch *arch; /**< Target architecture */ + /*@owned@*/ yasm_objfmt *objfmt; /**< Object format */ + /*@owned@*/ yasm_dbgfmt *dbgfmt; /**< Debug format */ + + /** Currently active section. Used by some directives. NULL if no + * section active. + */ + /*@dependent@*/ /*@null@*/ yasm_section *cur_section; + + /** Linked list of sections. */ + /*@reldef@*/ STAILQ_HEAD(yasm_sectionhead, yasm_section) sections; + + /** Directives, organized as two level HAMT; first level is parser, + * second level is directive name. + */ + /*@owned@*/ struct HAMT *directives; + + /** Prefix prepended to externally-visible symbols (empty string if none) */ + /*@owned@*/ char *global_prefix; + + /** Suffix appended to externally-visible symbols (empty string if none) */ + /*@owned@*/ char *global_suffix; +}; + +/** Create a new object. A default section is created as the first section. + * An empty symbol table (yasm_symtab) and line mapping (yasm_linemap) are + * automatically created. + * \param src_filename source filename (e.g. "file.asm") + * \param obj_filename object filename (e.g. "file.o") + * \param arch architecture + * \param objfmt_module object format module + * \param dbgfmt_module debug format module + * \return Newly allocated object, or NULL on error. + */ +YASM_LIB_DECL +/*@null@*/ /*@only@*/ yasm_object *yasm_object_create + (const char *src_filename, const char *obj_filename, + /*@kept@*/ yasm_arch *arch, + const yasm_objfmt_module *objfmt_module, + const yasm_dbgfmt_module *dbgfmt_module); + +/** Create a new, or continue an existing, general section. The section is + * added to the object if there's not already a section by that name. + * \param object object + * \param name section name + * \param align alignment in bytes (0 if none) + * \param code if nonzero, section is intended to contain code + * (e.g. alignment should be made with NOP instructions, not 0) + * \param res_only if nonzero, only space-reserving bytecodes are allowed in + * the section (ignored if section already exists) + * \param isnew output; set to nonzero if section did not already exist + * \param line virtual line of section declaration (ignored if section + * already exists) + * \return New section. + */ +YASM_LIB_DECL +/*@dependent@*/ yasm_section *yasm_object_get_general + (yasm_object *object, const char *name, unsigned long align, int code, + int res_only, /*@out@*/ int *isnew, unsigned long line); + +/** Handle a directive. Passed down to object format, debug format, or + * architecture as appropriate. + * \param object object + * \param name directive name + * \param parser parser keyword + * \param valparams value/parameters + * \param objext_valparams "object format-specific" value/parameters + * \param line virtual line (from yasm_linemap) + * \return 0 if directive recognized, nonzero if unrecognized. + */ +YASM_LIB_DECL +int yasm_object_directive(yasm_object *object, const char *name, + const char *parser, yasm_valparamhead *valparams, + yasm_valparamhead *objext_valparams, + unsigned long line); + +/** Delete (free allocated memory for) an object. All sections in the + * object and all bytecodes within those sections are also deleted. + * \param object object + */ +YASM_LIB_DECL +void yasm_object_destroy(/*@only@*/ yasm_object *object); + +/** Print an object. For debugging purposes. + * \param object object + * \param f file + * \param indent_level indentation level + */ +YASM_LIB_DECL +void yasm_object_print(const yasm_object *object, FILE *f, int indent_level); + +/** Finalize an object after parsing. + * \param object object + * \param errwarns error/warning set + * \note Errors/warnings are stored into errwarns. + */ +YASM_LIB_DECL +void yasm_object_finalize(yasm_object *object, yasm_errwarns *errwarns); + +/** Traverses all sections in an object, calling a function on each section. + * \param object object + * \param d data pointer passed to func on each call + * \param func function + * \return Stops early (and returns func's return value) if func returns a + * nonzero value; otherwise 0. + */ +YASM_LIB_DECL +int yasm_object_sections_traverse + (yasm_object *object, /*@null@*/ void *d, + int (*func) (yasm_section *sect, /*@null@*/ void *d)); + +/** Find a general section in an object, based on its name. + * \param object object + * \param name section name + * \return Section matching name, or NULL if no match found. + */ +YASM_LIB_DECL +/*@dependent@*/ /*@null@*/ yasm_section *yasm_object_find_general + (yasm_object *object, const char *name); + +/** Change the source filename for an object. + * \param object object + * \param src_filename new source filename (e.g. "file.asm") + */ +YASM_LIB_DECL +void yasm_object_set_source_fn(yasm_object *object, const char *src_filename); + +/** Change the prefix used for externally-visible symbols. + * \param object object + * \param prefix new prefix + */ +YASM_LIB_DECL +void yasm_object_set_global_prefix(yasm_object *object, const char *prefix); + +/** Change the suffix used for externally-visible symbols. + * \param object object + * \param suffix new suffix + */ +YASM_LIB_DECL +void yasm_object_set_global_suffix(yasm_object *object, const char *suffix); + +/** Optimize an object. Takes the unoptimized object and optimizes it. + * If successful, the object is ready for output to an object file. + * \param object object + * \param errwarns error/warning set + * \note Optimization failures are stored into errwarns. + */ +YASM_LIB_DECL +void yasm_object_optimize(yasm_object *object, yasm_errwarns *errwarns); + +/** Determine if a section is flagged to contain code. + * \param sect section + * \return Nonzero if section is flagged to contain code. + */ +YASM_LIB_DECL +int yasm_section_is_code(yasm_section *sect); + +/** Get yasm_optimizer-specific flags. For yasm_optimizer use only. + * \param sect section + * \return Optimizer-specific flags. + */ +YASM_LIB_DECL +unsigned long yasm_section_get_opt_flags(const yasm_section *sect); + +/** Set yasm_optimizer-specific flags. For yasm_optimizer use only. + * \param sect section + * \param opt_flags optimizer-specific flags. + */ +YASM_LIB_DECL +void yasm_section_set_opt_flags(yasm_section *sect, unsigned long opt_flags); + +/** Determine if a section was declared as the "default" section (e.g. not + * created through a section directive). + * \param sect section + * \return Nonzero if section was declared as default. + */ +YASM_LIB_DECL +int yasm_section_is_default(const yasm_section *sect); + +/** Set section "default" flag to a new value. + * \param sect section + * \param def new value of default flag + */ +YASM_LIB_DECL +void yasm_section_set_default(yasm_section *sect, int def); + +/** Get object owner of a section. + * \param sect section + * \return Object this section is a part of. + */ +YASM_LIB_DECL +yasm_object *yasm_section_get_object(const yasm_section *sect); + +/** Get assocated data for a section and data callback. + * \param sect section + * \param callback callback used when adding data + * \return Associated data (NULL if none). + */ +YASM_LIB_DECL +/*@dependent@*/ /*@null@*/ void *yasm_section_get_data + (yasm_section *sect, const yasm_assoc_data_callback *callback); + +/** Add associated data to a section. + * \attention Deletes any existing associated data for that data callback. + * \param sect section + * \param callback callback + * \param data data to associate + */ +YASM_LIB_DECL +void yasm_section_add_data(yasm_section *sect, + const yasm_assoc_data_callback *callback, + /*@null@*/ /*@only@*/ void *data); + +/** Add a relocation to a section. + * \param sect section + * \param reloc relocation + * \param destroy_func function that can destroy the relocation + * \note Does not make a copy of reloc. The same destroy_func must be + * used for all relocations in a section or an internal error will occur. + * The section will destroy the relocation address; it is the caller's + * responsibility to destroy any other allocated data. + */ +YASM_LIB_DECL +void yasm_section_add_reloc(yasm_section *sect, yasm_reloc *reloc, + void (*destroy_func) (/*@only@*/ void *reloc)); + +/** Get the first relocation for a section. + * \param sect section + * \return First relocation for section. NULL if no relocations. + */ +YASM_LIB_DECL +/*@null@*/ yasm_reloc *yasm_section_relocs_first(yasm_section *sect); + +/** Get the next relocation for a section. + * \param reloc previous relocation + * \return Next relocation for section. NULL if no more relocations. + */ +/*@null@*/ yasm_reloc *yasm_section_reloc_next(yasm_reloc *reloc); +#ifndef YASM_DOXYGEN +#define yasm_section_reloc_next(x) STAILQ_NEXT((x), link) +#endif + +/** Get the basic relocation information for a relocation. + * \param reloc relocation + * \param addrp address of relocation within section (returned) + * \param symp relocated symbol (returned) + */ +YASM_LIB_DECL +void yasm_reloc_get(yasm_reloc *reloc, yasm_intnum **addrp, + /*@dependent@*/ yasm_symrec **symp); + +/** Get the first bytecode in a section. + * \param sect section + * \return First bytecode in section (at least one empty bytecode is always + * present). + */ +YASM_LIB_DECL +yasm_bytecode *yasm_section_bcs_first(yasm_section *sect); + +/** Get the last bytecode in a section. + * \param sect section + * \return Last bytecode in section (at least one empty bytecode is always + * present). + */ +YASM_LIB_DECL +yasm_bytecode *yasm_section_bcs_last(yasm_section *sect); + +/** Add bytecode to the end of a section. + * \note Does not make a copy of bc; so don't pass this function static or + * local variables, and discard the bc pointer after calling this + * function. + * \param sect section + * \param bc bytecode (may be NULL) + * \return If bytecode was actually appended (it wasn't NULL or empty), the + * bytecode; otherwise NULL. + */ +YASM_LIB_DECL +/*@only@*/ /*@null@*/ yasm_bytecode *yasm_section_bcs_append + (yasm_section *sect, + /*@returned@*/ /*@only@*/ /*@null@*/ yasm_bytecode *bc); + +/** Traverses all bytecodes in a section, calling a function on each bytecode. + * \param sect section + * \param errwarns error/warning set (may be NULL) + * \param d data pointer passed to func on each call (may be NULL) + * \param func function + * \return Stops early (and returns func's return value) if func returns a + * nonzero value; otherwise 0. + * \note If errwarns is non-NULL, yasm_errwarn_propagate() is called after + * each call to func (with the bytecode's line number). + */ +YASM_LIB_DECL +int yasm_section_bcs_traverse + (yasm_section *sect, /*@null@*/ yasm_errwarns *errwarns, + /*@null@*/ void *d, int (*func) (yasm_bytecode *bc, /*@null@*/ void *d)); + +/** Get name of a section. + * \param sect section + * \return Section name. + */ +YASM_LIB_DECL +/*@observer@*/ const char *yasm_section_get_name(const yasm_section *sect); + +/** Change alignment of a section. + * \param sect section + * \param align alignment in bytes + * \param line virtual line + */ +YASM_LIB_DECL +void yasm_section_set_align(yasm_section *sect, unsigned long align, + unsigned long line); + +/** Get alignment of a section. + * \param sect section + * \return Alignment in bytes (0 if none). + */ +YASM_LIB_DECL +unsigned long yasm_section_get_align(const yasm_section *sect); + +/** Print a section. For debugging purposes. + * \param f file + * \param indent_level indentation level + * \param sect section + * \param print_bcs if nonzero, print bytecodes within section + */ +YASM_LIB_DECL +void yasm_section_print(/*@null@*/ const yasm_section *sect, FILE *f, + int indent_level, int print_bcs); + +#endif diff --git a/contrib/tools/yasm/libyasm/strcasecmp.c b/contrib/tools/yasm/libyasm/strcasecmp.c new file mode 100644 index 0000000000..a87bd88bc9 --- /dev/null +++ b/contrib/tools/yasm/libyasm/strcasecmp.c @@ -0,0 +1,94 @@ +/* + * strcasecmp() implementation for systems that don't have it or stricmp() + * or strcmpi(). + * + * Copyright (c) 1987, 1993 + * The Regents of the University of California. All rights reserved. + * + * 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. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND 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 REGENTS OR 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" + +#ifndef USE_OUR_OWN_STRCASECMP +#undef yasm__strcasecmp +#undef yasm__strncasecmp +#endif + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)strcasecmp.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ + +#include <ctype.h> + +int +yasm__strcasecmp(const char *s1, const char *s2) +{ +#ifdef HAVE_STRCASECMP + return strcasecmp(s1, s2); +#elif HAVE_STRICMP + return stricmp(s1, s2); +#elif HAVE__STRICMP + return _stricmp(s1, s2); +#elif HAVE_STRCMPI + return strcmpi(s1, s2); +#else + const unsigned char + *us1 = (const unsigned char *)s1, + *us2 = (const unsigned char *)s2; + + while (tolower(*us1) == tolower(*us2++)) + if (*us1++ == '\0') + return (0); + return (tolower(*us1) - tolower(*--us2)); +#endif +} + +int +yasm__strncasecmp(const char *s1, const char *s2, size_t n) +{ +#ifdef HAVE_STRCASECMP + return strncasecmp(s1, s2, n); +#elif HAVE_STRICMP + return strnicmp(s1, s2, n); +#elif HAVE__STRNICMP + return _strnicmp(s1, s2, n); +#elif HAVE_STRCMPI + return strncmpi(s1, s2, n); +#else + const unsigned char + *us1 = (const unsigned char *)s1, + *us2 = (const unsigned char *)s2; + + if (n != 0) { + do { + if (tolower(*us1) != tolower(*us2++)) + return (tolower(*us1) - tolower(*--us2)); + if (*us1++ == '\0') + break; + } while (--n != 0); + } + return (0); +#endif +} diff --git a/contrib/tools/yasm/libyasm/strsep.c b/contrib/tools/yasm/libyasm/strsep.c new file mode 100644 index 0000000000..5688a60879 --- /dev/null +++ b/contrib/tools/yasm/libyasm/strsep.c @@ -0,0 +1,85 @@ +/* + * strsep() implementation for systems that don't have it. + * + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * 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. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND 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 REGENTS OR 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. + */ +#define NO_STRING_INLINES +#include "util.h" + + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)strsep.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ + +#ifdef HAVE_STRSEP +#undef yasm__strsep +#endif + +/* + * Get next token from string *stringp, where tokens are possibly-empty + * strings separated by characters from delim. + * + * Writes NULs into the string at *stringp to end tokens. + * delim need not remain constant from call to call. + * On return, *stringp points past the last NUL written (if there might + * be further tokens), or is NULL (if there are definitely no more tokens). + * + * If *stringp is NULL, strsep returns NULL. + */ +/*@-nullstate@*/ +char * +yasm__strsep(char **stringp, const char *delim) +{ +#ifdef HAVE_STRSEP + return strsep(stringp, delim); +#else + char *s; + const char *spanp; + int c, sc; + char *tok; + + if ((s = *stringp) == NULL) + return (NULL); + for (tok = s;;) { + c = *s++; + spanp = delim; + do { + if ((sc = *spanp++) == c) { + if (c == 0) + s = NULL; + else + s[-1] = 0; + *stringp = s; + return (tok); + } + } while (sc != 0); + } + /* NOTREACHED */ +#endif +} +/*@=nullstate@*/ diff --git a/contrib/tools/yasm/libyasm/symrec.c b/contrib/tools/yasm/libyasm/symrec.c new file mode 100644 index 0000000000..694f0c6768 --- /dev/null +++ b/contrib/tools/yasm/libyasm/symrec.c @@ -0,0 +1,714 @@ +/* + * Symbol table handling + * + * Copyright (C) 2001-2007 Michael Urman, 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 <limits.h> +#include <ctype.h> + +#include "libyasm-stdint.h" +#include "coretype.h" +#include "valparam.h" +#include "hamt.h" +#include "assocdat.h" + +#include "errwarn.h" +#include "intnum.h" +#include "floatnum.h" +#include "expr.h" +#include "symrec.h" + +#include "bytecode.h" +#include "section.h" +#include "objfmt.h" + + +typedef enum { + SYM_UNKNOWN, /* for unknown type (COMMON/EXTERN) */ + SYM_EQU, /* for EQU defined symbols (expressions) */ + SYM_LABEL, /* for labels */ + SYM_CURPOS, /* for labels representing the current + assembly position */ + SYM_SPECIAL /* for special symbols that need to be in + the symbol table but otherwise have no + purpose */ +} sym_type; + +struct yasm_symrec { + char *name; + sym_type type; + yasm_sym_status status; + yasm_sym_vis visibility; + unsigned long def_line; /* line where symbol was first defined */ + unsigned long decl_line; /* line where symbol was first declared */ + unsigned long use_line; /* line where symbol was first used */ + union { + yasm_expr *expn; /* equ value */ + + /* bytecode immediately preceding a label */ + /*@dependent@*/ yasm_bytecode *precbc; + } value; + unsigned int size; /* 0 if not user-defined */ + const char *segment; /* for segmented systems like DOS */ + + /* associated data; NULL if none */ + /*@null@*/ /*@only@*/ yasm__assoc_data *assoc_data; +}; + +/* Linked list of symbols not in the symbol table. */ +typedef struct non_table_symrec_s { + /*@reldef@*/ SLIST_ENTRY(non_table_symrec_s) link; + /*@owned@*/ yasm_symrec *rec; +} non_table_symrec; + +struct yasm_symtab { + /* The symbol table: a hash array mapped trie (HAMT). */ + /*@only@*/ HAMT *sym_table; + /* Symbols not in the table */ + SLIST_HEAD(nontablesymhead_s, non_table_symrec_s) non_table_syms; + + int case_sensitive; +}; + +static void +objext_valparams_destroy(void *data) +{ + yasm_vps_destroy((yasm_valparamhead *)data); +} + +static void +objext_valparams_print(void *data, FILE *f, int indent_level) +{ + yasm_vps_print((yasm_valparamhead *)data, f); +} + +static yasm_assoc_data_callback objext_valparams_cb = { + objext_valparams_destroy, + objext_valparams_print +}; + +static void +common_size_destroy(void *data) +{ + yasm_expr **e = (yasm_expr **)data; + yasm_expr_destroy(*e); + yasm_xfree(data); +} + +static void +common_size_print(void *data, FILE *f, int indent_level) +{ + yasm_expr **e = (yasm_expr **)data; + yasm_expr_print(*e, f); +} + +static yasm_assoc_data_callback common_size_cb = { + common_size_destroy, + common_size_print +}; + +yasm_symtab * +yasm_symtab_create(void) +{ + yasm_symtab *symtab = yasm_xmalloc(sizeof(yasm_symtab)); + symtab->sym_table = HAMT_create(0, yasm_internal_error_); + SLIST_INIT(&symtab->non_table_syms); + symtab->case_sensitive = 1; + return symtab; +} + +void +yasm_symtab_set_case_sensitive(yasm_symtab *symtab, int sensitive) +{ + symtab->case_sensitive = sensitive; +} + +static void +symrec_destroy_one(/*@only@*/ void *d) +{ + yasm_symrec *sym = d; + yasm_xfree(sym->name); + if (sym->type == SYM_EQU && (sym->status & YASM_SYM_VALUED)) + yasm_expr_destroy(sym->value.expn); + yasm__assoc_data_destroy(sym->assoc_data); + yasm_xfree(sym); +} + +static /*@partial@*/ yasm_symrec * +symrec_new_common(/*@keep@*/ char *name, int case_sensitive) +{ + yasm_symrec *rec = yasm_xmalloc(sizeof(yasm_symrec)); + + if (!case_sensitive) { + char *c; + for (c=name; *c; c++) + *c = tolower(*c); + } + + rec->name = name; + rec->type = SYM_UNKNOWN; + rec->def_line = 0; + rec->decl_line = 0; + rec->use_line = 0; + rec->visibility = YASM_SYM_LOCAL; + rec->size = 0; + rec->segment = NULL; + rec->assoc_data = NULL; + return rec; +} + +static /*@partial@*/ /*@dependent@*/ yasm_symrec * +symtab_get_or_new_in_table(yasm_symtab *symtab, /*@only@*/ char *name) +{ + yasm_symrec *rec = symrec_new_common(name, symtab->case_sensitive); + int replace = 0; + + rec->status = YASM_SYM_NOSTATUS; + + if (!symtab->case_sensitive) { + char *c; + for (c=name; *c; c++) + *c = tolower(*c); + } + + return HAMT_insert(symtab->sym_table, name, rec, &replace, + symrec_destroy_one); +} + +static /*@partial@*/ /*@dependent@*/ yasm_symrec * +symtab_get_or_new_not_in_table(yasm_symtab *symtab, /*@only@*/ char *name) +{ + non_table_symrec *sym = yasm_xmalloc(sizeof(non_table_symrec)); + sym->rec = symrec_new_common(name, symtab->case_sensitive); + + sym->rec->status = YASM_SYM_NOTINTABLE; + + SLIST_INSERT_HEAD(&symtab->non_table_syms, sym, link); + + return sym->rec; +} + +/* create a new symrec */ +/*@-freshtrans -mustfree@*/ +static /*@partial@*/ /*@dependent@*/ yasm_symrec * +symtab_get_or_new(yasm_symtab *symtab, const char *name, int in_table) +{ + char *symname = yasm__xstrdup(name); + + if (in_table) + return symtab_get_or_new_in_table(symtab, symname); + else + return symtab_get_or_new_not_in_table(symtab, symname); +} +/*@=freshtrans =mustfree@*/ + +int +yasm_symtab_traverse(yasm_symtab *symtab, void *d, + int (*func) (yasm_symrec *sym, void *d)) +{ + return HAMT_traverse(symtab->sym_table, d, (int (*) (void *, void *))func); +} + +const yasm_symtab_iter * +yasm_symtab_first(const yasm_symtab *symtab) +{ + return (const yasm_symtab_iter *)HAMT_first(symtab->sym_table); +} + +/*@null@*/ const yasm_symtab_iter * +yasm_symtab_next(const yasm_symtab_iter *prev) +{ + return (const yasm_symtab_iter *)HAMT_next((const HAMTEntry *)prev); +} + +yasm_symrec * +yasm_symtab_iter_value(const yasm_symtab_iter *cur) +{ + return (yasm_symrec *)HAMTEntry_get_data((const HAMTEntry *)cur); +} + +yasm_symrec * +yasm_symtab_abs_sym(yasm_symtab *symtab) +{ + yasm_symrec *rec = symtab_get_or_new(symtab, "", 1); + rec->def_line = 0; + rec->decl_line = 0; + rec->use_line = 0; + rec->type = SYM_EQU; + rec->value.expn = + yasm_expr_create_ident(yasm_expr_int(yasm_intnum_create_uint(0)), 0); + rec->status |= YASM_SYM_DEFINED|YASM_SYM_VALUED|YASM_SYM_USED; + return rec; +} + +yasm_symrec * +yasm_symtab_use(yasm_symtab *symtab, const char *name, unsigned long line) +{ + yasm_symrec *rec = symtab_get_or_new(symtab, name, 1); + if (rec->use_line == 0) + rec->use_line = line; /* set line number of first use */ + rec->status |= YASM_SYM_USED; + return rec; +} + +yasm_symrec * +yasm_symtab_get(yasm_symtab *symtab, const char *name) +{ + if (!symtab->case_sensitive) { + char *_name = yasm__xstrdup(name); + char *c; + yasm_symrec *ret; + for (c=_name; *c; c++) + *c = tolower(*c); + ret = HAMT_search(symtab->sym_table, _name); + yasm_xfree(_name); + return ret; + } else + return HAMT_search(symtab->sym_table, name); +} + +static /*@dependent@*/ yasm_symrec * +symtab_define(yasm_symtab *symtab, const char *name, sym_type type, + int in_table, unsigned long line) +{ + yasm_symrec *rec = symtab_get_or_new(symtab, name, in_table); + + /* Has it been defined before (either by DEFINED or COMMON/EXTERN)? */ + if (rec->status & YASM_SYM_DEFINED) { + yasm_error_set_xref(rec->def_line!=0 ? rec->def_line : rec->decl_line, + N_("`%s' previously defined here"), name); + yasm_error_set(YASM_ERROR_GENERAL, N_("redefinition of `%s'"), + name); + } else { + if (rec->visibility & YASM_SYM_EXTERN) + yasm_warn_set(YASM_WARN_GENERAL, + N_("`%s' both defined and declared extern"), name); + rec->def_line = line; /* set line number of definition */ + rec->type = type; + rec->status |= YASM_SYM_DEFINED; + rec->size = 0; + rec->segment = NULL; + } + return rec; +} + +yasm_symrec * +yasm_symtab_define_equ(yasm_symtab *symtab, const char *name, yasm_expr *e, + unsigned long line) +{ + yasm_symrec *rec = symtab_define(symtab, name, SYM_EQU, 1, line); + if (yasm_error_occurred()) + return rec; + rec->value.expn = e; + rec->status |= YASM_SYM_VALUED; + return rec; +} + +yasm_symrec * +yasm_symtab_define_label(yasm_symtab *symtab, const char *name, + yasm_bytecode *precbc, int in_table, + unsigned long line) +{ + yasm_symrec *rec = symtab_define(symtab, name, SYM_LABEL, in_table, line); + if (yasm_error_occurred()) + return rec; + rec->value.precbc = precbc; + if (in_table && precbc) + yasm_bc__add_symrec(precbc, rec); + return rec; +} + +yasm_symrec * +yasm_symtab_define_curpos(yasm_symtab *symtab, const char *name, + yasm_bytecode *precbc, unsigned long line) +{ + yasm_symrec *rec = symtab_define(symtab, name, SYM_CURPOS, 0, line); + if (yasm_error_occurred()) + return rec; + rec->value.precbc = precbc; + return rec; +} + +yasm_symrec * +yasm_symtab_define_special(yasm_symtab *symtab, const char *name, + yasm_sym_vis vis) +{ + yasm_symrec *rec = symtab_define(symtab, name, SYM_SPECIAL, 1, 0); + if (yasm_error_occurred()) + return rec; + rec->status |= YASM_SYM_VALUED; + rec->visibility = vis; + return rec; +} + +yasm_symrec * +yasm_symtab_declare(yasm_symtab *symtab, const char *name, yasm_sym_vis vis, + unsigned long line) +{ + yasm_symrec *rec = symtab_get_or_new(symtab, name, 1); + yasm_symrec_declare(rec, vis, line); + return rec; +} + +void +yasm_symrec_declare(yasm_symrec *rec, yasm_sym_vis vis, unsigned long line) +{ + /* Allowable combinations: + * Existing State-------------- vis New State------------------- + * DEFINED GLOBAL COMMON EXTERN GCE DEFINED GLOBAL COMMON EXTERN + * 0 - 0 0 GCE 0 G C E + * 0 - 0 1 GE 0 G 0 E + * 0 - 1 0 GC 0 G C 0 + * X 0 - 1 1 + * 1 - 0 0 G 1 G 0 0 + * X 1 - - 1 + * X 1 - 1 - + */ + if ((vis == YASM_SYM_GLOBAL) || + (!(rec->status & YASM_SYM_DEFINED) && + (!(rec->visibility & (YASM_SYM_COMMON | YASM_SYM_EXTERN)) || + ((rec->visibility & YASM_SYM_COMMON) && (vis == YASM_SYM_COMMON)) || + ((rec->visibility & YASM_SYM_EXTERN) && (vis == YASM_SYM_EXTERN))))) { + rec->decl_line = line; + rec->visibility |= vis; + } else + yasm_error_set(YASM_ERROR_GENERAL, + N_("duplicate definition of `%s'; first defined on line %lu"), + rec->name, rec->def_line!=0 ? rec->def_line : rec->decl_line); +} + +typedef struct symtab_finalize_info { + unsigned long firstundef_line; + int undef_extern; + yasm_errwarns *errwarns; +} symtab_finalize_info; + +static int +symtab_parser_finalize_checksym(yasm_symrec *sym, /*@null@*/ void *d) +{ + symtab_finalize_info *info = (symtab_finalize_info *)d; + + /* error if a symbol is used but never defined or extern/common declared */ + if ((sym->status & YASM_SYM_USED) && !(sym->status & YASM_SYM_DEFINED) && + !(sym->visibility & (YASM_SYM_EXTERN | YASM_SYM_COMMON))) { + if (info->undef_extern) + sym->visibility |= YASM_SYM_EXTERN; + else { + yasm_error_set(YASM_ERROR_GENERAL, + N_("undefined symbol `%s' (first use)"), sym->name); + yasm_errwarn_propagate(info->errwarns, sym->use_line); + if (sym->use_line < info->firstundef_line) + info->firstundef_line = sym->use_line; + } + } + + return 0; +} + +void +yasm_symtab_parser_finalize(yasm_symtab *symtab, int undef_extern, + yasm_errwarns *errwarns) +{ + symtab_finalize_info info; + info.firstundef_line = ULONG_MAX; + info.undef_extern = undef_extern; + info.errwarns = errwarns; + yasm_symtab_traverse(symtab, &info, symtab_parser_finalize_checksym); + if (info.firstundef_line < ULONG_MAX) { + yasm_error_set(YASM_ERROR_GENERAL, + N_(" (Each undefined symbol is reported only once.)")); + yasm_errwarn_propagate(errwarns, info.firstundef_line); + } +} + +void +yasm_symtab_destroy(yasm_symtab *symtab) +{ + HAMT_destroy(symtab->sym_table, symrec_destroy_one); + + while (!SLIST_EMPTY(&symtab->non_table_syms)) { + non_table_symrec *sym = SLIST_FIRST(&symtab->non_table_syms); + SLIST_REMOVE_HEAD(&symtab->non_table_syms, link); + symrec_destroy_one(sym->rec); + yasm_xfree(sym); + } + + yasm_xfree(symtab); +} + +typedef struct symrec_print_data { + FILE *f; + int indent_level; +} symrec_print_data; + +/*@+voidabstract@*/ +static int +symrec_print_wrapper(yasm_symrec *sym, /*@null@*/ void *d) +{ + symrec_print_data *data = (symrec_print_data *)d; + assert(data != NULL); + fprintf(data->f, "%*sSymbol `%s'\n", data->indent_level, "", sym->name); + yasm_symrec_print(sym, data->f, data->indent_level+1); + return 0; +} + +void +yasm_symtab_print(yasm_symtab *symtab, FILE *f, int indent_level) +{ + symrec_print_data data; + data.f = f; + data.indent_level = indent_level; + yasm_symtab_traverse(symtab, &data, symrec_print_wrapper); +} +/*@=voidabstract@*/ + +const char * +yasm_symrec_get_name(const yasm_symrec *sym) +{ + return sym->name; +} + +char * +yasm_symrec_get_global_name(const yasm_symrec *sym, const yasm_object *object) +{ + if (sym->visibility & (YASM_SYM_GLOBAL|YASM_SYM_COMMON|YASM_SYM_EXTERN)) { + char *name = yasm_xmalloc(strlen(object->global_prefix) + + strlen(sym->name) + + strlen(object->global_suffix) + 1); + strcpy(name, object->global_prefix); + strcat(name, sym->name); + strcat(name, object->global_suffix); + return name; + } + return yasm__xstrdup(sym->name); +} + +yasm_sym_vis +yasm_symrec_get_visibility(const yasm_symrec *sym) +{ + return sym->visibility; +} + +yasm_sym_status +yasm_symrec_get_status(const yasm_symrec *sym) +{ + return sym->status; +} + +unsigned long +yasm_symrec_get_def_line(const yasm_symrec *sym) +{ + return sym->def_line; +} + +unsigned long +yasm_symrec_get_decl_line(const yasm_symrec *sym) +{ + return sym->decl_line; +} + +unsigned long +yasm_symrec_get_use_line(const yasm_symrec *sym) +{ + return sym->use_line; +} + +const yasm_expr * +yasm_symrec_get_equ(const yasm_symrec *sym) +{ + if (sym->type == SYM_EQU && (sym->status & YASM_SYM_VALUED)) + return sym->value.expn; + return (const yasm_expr *)NULL; +} + +int +yasm_symrec_get_label(const yasm_symrec *sym, + yasm_symrec_get_label_bytecodep *precbc) +{ + if (!(sym->type == SYM_LABEL || sym->type == SYM_CURPOS) + || !sym->value.precbc) { + *precbc = (yasm_symrec_get_label_bytecodep)0xDEADBEEF; + return 0; + } + *precbc = sym->value.precbc; + return 1; +} + +void +yasm_symrec_set_size(yasm_symrec *sym, int size) +{ + sym->size = size; +} + +int +yasm_symrec_get_size(const yasm_symrec *sym) +{ + return sym->size; +} + +void +yasm_symrec_set_segment(yasm_symrec *sym, const char *segment) +{ + sym->segment = segment; +} + +const char * +yasm_symrec_get_segment(const yasm_symrec *sym) +{ + return sym->segment; +} + +int +yasm_symrec_is_abs(const yasm_symrec *sym) +{ + return (sym->def_line == 0 && sym->type == SYM_EQU && + sym->name[0] == '\0'); +} + +int +yasm_symrec_is_special(const yasm_symrec *sym) +{ + return (sym->type == SYM_SPECIAL); +} + +int +yasm_symrec_is_curpos(const yasm_symrec *sym) +{ + return (sym->type == SYM_CURPOS); +} + +void +yasm_symrec_set_objext_valparams(yasm_symrec *sym, + /*@only@*/ yasm_valparamhead *objext_valparams) +{ + yasm_symrec_add_data(sym, &objext_valparams_cb, objext_valparams); +} + +yasm_valparamhead * +yasm_symrec_get_objext_valparams(yasm_symrec *sym) +{ + return yasm_symrec_get_data(sym, &objext_valparams_cb); +} + +void +yasm_symrec_set_common_size(yasm_symrec *sym, + /*@only@*/ yasm_expr *common_size) +{ + yasm_expr **ep = yasm_xmalloc(sizeof(yasm_expr *)); + *ep = common_size; + yasm_symrec_add_data(sym, &common_size_cb, ep); +} + +yasm_expr ** +yasm_symrec_get_common_size(yasm_symrec *sym) +{ + return (yasm_expr **)yasm_symrec_get_data(sym, &common_size_cb); +} + +void * +yasm_symrec_get_data(yasm_symrec *sym, + const yasm_assoc_data_callback *callback) +{ + return yasm__assoc_data_get(sym->assoc_data, callback); +} + +void +yasm_symrec_add_data(yasm_symrec *sym, + const yasm_assoc_data_callback *callback, void *data) +{ + sym->assoc_data = yasm__assoc_data_add(sym->assoc_data, callback, data); +} + +void +yasm_symrec_print(const yasm_symrec *sym, FILE *f, int indent_level) +{ + switch (sym->type) { + case SYM_UNKNOWN: + fprintf(f, "%*s-Unknown (Common/Extern)-\n", indent_level, ""); + break; + case SYM_EQU: + fprintf(f, "%*s_EQU_\n", indent_level, ""); + fprintf(f, "%*sExpn=", indent_level, ""); + if (sym->status & YASM_SYM_VALUED) + yasm_expr_print(sym->value.expn, f); + else + fprintf(f, "***UNVALUED***"); + fprintf(f, "\n"); + break; + case SYM_LABEL: + case SYM_CURPOS: + fprintf(f, "%*s_%s_\n%*sSection:\n", indent_level, "", + sym->type == SYM_LABEL ? "Label" : "CurPos", + indent_level, ""); + yasm_section_print(yasm_bc_get_section(sym->value.precbc), f, + indent_level+1, 0); + fprintf(f, "%*sPreceding bytecode:\n", indent_level, ""); + yasm_bc_print(sym->value.precbc, f, indent_level+1); + break; + case SYM_SPECIAL: + fprintf(f, "%*s-Special-\n", indent_level, ""); + break; + } + + fprintf(f, "%*sStatus=", indent_level, ""); + if (sym->status == YASM_SYM_NOSTATUS) + fprintf(f, "None\n"); + else { + if (sym->status & YASM_SYM_USED) + fprintf(f, "Used,"); + if (sym->status & YASM_SYM_DEFINED) + fprintf(f, "Defined,"); + if (sym->status & YASM_SYM_VALUED) + fprintf(f, "Valued,"); + if (sym->status & YASM_SYM_NOTINTABLE) + fprintf(f, "Not in Table,"); + fprintf(f, "\n"); + } + + fprintf(f, "%*sVisibility=", indent_level, ""); + if (sym->visibility == YASM_SYM_LOCAL) + fprintf(f, "Local\n"); + else { + if (sym->visibility & YASM_SYM_GLOBAL) + fprintf(f, "Global,"); + if (sym->visibility & YASM_SYM_COMMON) + fprintf(f, "Common,"); + if (sym->visibility & YASM_SYM_EXTERN) + fprintf(f, "Extern,"); + fprintf(f, "\n"); + } + + if (sym->assoc_data) { + fprintf(f, "%*sAssociated data:\n", indent_level, ""); + yasm__assoc_data_print(sym->assoc_data, f, indent_level+1); + } + + fprintf(f, "%*sLine Index (Defined)=%lu\n", indent_level, "", + sym->def_line); + fprintf(f, "%*sLine Index (Declared)=%lu\n", indent_level, "", + sym->decl_line); + fprintf(f, "%*sLine Index (Used)=%lu\n", indent_level, "", sym->use_line); +} diff --git a/contrib/tools/yasm/libyasm/symrec.h b/contrib/tools/yasm/libyasm/symrec.h new file mode 100644 index 0000000000..b1f797c647 --- /dev/null +++ b/contrib/tools/yasm/libyasm/symrec.h @@ -0,0 +1,437 @@ +/** + * \file libyasm/symrec.h + * \brief YASM symbol table interface. + * + * \license + * Copyright (C) 2001-2007 Michael Urman, Peter Johnson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - 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. + * \endlicense + */ +#ifndef YASM_SYMREC_H +#define YASM_SYMREC_H + +#ifndef YASM_LIB_DECL +#define YASM_LIB_DECL +#endif + +/** Symbol status. YASM_SYM_DEFINED is set by yasm_symtab_define_label(), + * yasm_symtab_define_equ(), or yasm_symtab_declare()/yasm_symrec_declare() + * with a visibility of #YASM_SYM_EXTERN or #YASM_SYM_COMMON. + */ +typedef enum yasm_sym_status { + YASM_SYM_NOSTATUS = 0, /**< no status */ + YASM_SYM_USED = 1 << 0, /**< for use before definition */ + YASM_SYM_DEFINED = 1 << 1, /**< once it's been defined in the file */ + YASM_SYM_VALUED = 1 << 2, /**< once its value has been determined */ + YASM_SYM_NOTINTABLE = 1 << 3 /**< if it's not in sym_table (ex. '$') */ +} yasm_sym_status; + +/** Symbol record visibility. + * \note YASM_SYM_EXTERN and YASM_SYM_COMMON are mutually exclusive. + */ +typedef enum yasm_sym_vis { + YASM_SYM_LOCAL = 0, /**< Default, local only */ + YASM_SYM_GLOBAL = 1 << 0, /**< If symbol is declared GLOBAL */ + YASM_SYM_COMMON = 1 << 1, /**< If symbol is declared COMMON */ + YASM_SYM_EXTERN = 1 << 2, /**< If symbol is declared EXTERN */ + YASM_SYM_DLOCAL = 1 << 3 /**< If symbol is explicitly declared LOCAL */ +} yasm_sym_vis; + +/** Create a new symbol table. */ +YASM_LIB_DECL +yasm_symtab *yasm_symtab_create(void); + +/** Destroy a symbol table and all internal symbols. + * \param symtab symbol table + * \warning All yasm_symrec *'s into this symbol table become invalid after + * this is called! + */ +YASM_LIB_DECL +void yasm_symtab_destroy(/*@only@*/ yasm_symtab *symtab); + +/** Set the symbol table to be case sensitive or not. + * Should be called before adding any symbol. + * \param symtab symbol table + * \param sensitive whether the symbol table should be case sensitive. + */ +YASM_LIB_DECL +void yasm_symtab_set_case_sensitive(yasm_symtab *symtab, int sensitive); + +/** Get a reference to the symbol table's "absolute" symbol. This is + * essentially an EQU with no name and value 0, and is used for relocating + * absolute current-position-relative values. + * \see yasm_value_set_curpos_rel(). + * \param symtab symbol table + * \return Absolute symbol (dependent pointer, do not free). + */ +YASM_LIB_DECL +/*@dependent@*/ yasm_symrec *yasm_symtab_abs_sym(yasm_symtab *symtab); + +/** Get a reference to (use) a symbol. The symbol does not necessarily need to + * be defined before it is used. + * \param symtab symbol table + * \param name symbol name + * \param line virtual line where referenced + * \return Symbol (dependent pointer, do not free). + */ +YASM_LIB_DECL +/*@dependent@*/ yasm_symrec *yasm_symtab_use + (yasm_symtab *symtab, const char *name, unsigned long line); + +/** Get a reference to a symbol, without "using" it. Should be used for cases + * when an internal assembler usage of a symbol shouldn't be treated like a + * normal user symbol usage. + * \param symtab symbol table + * \param name symbol name + * \return Symbol (dependent pointer, do not free). May be NULL if symbol + * doesn't exist. + */ +YASM_LIB_DECL +/*@null@*/ /*@dependent@*/ yasm_symrec *yasm_symtab_get + (yasm_symtab *symtab, const char *name); + +/** Define a symbol as an EQU value. + * \param symtab symbol table + * \param name symbol (EQU) name + * \param e EQU value (expression) + * \param line virtual line of EQU + * \return Symbol (dependent pointer, do not free). + */ +YASM_LIB_DECL +/*@dependent@*/ yasm_symrec *yasm_symtab_define_equ + (yasm_symtab *symtab, const char *name, /*@keep@*/ yasm_expr *e, + unsigned long line); + +/** Define a symbol as a label. + * \param symtab symbol table + * \param name symbol (label) name + * \param precbc bytecode preceding label + * \param in_table nonzero if the label should be inserted into the symbol + * table (some specially-generated ones should not be) + * \param line virtual line of label + * \return Symbol (dependent pointer, do not free). + */ +YASM_LIB_DECL +/*@dependent@*/ yasm_symrec *yasm_symtab_define_label + (yasm_symtab *symtab, const char *name, + /*@dependent@*/ yasm_bytecode *precbc, int in_table, unsigned long line); + +/** Define a symbol as a label representing the current assembly position. + * This should be used for this purpose instead of yasm_symtab_define_label() + * as value_finalize_scan() looks for usage of this symbol type for special + * handling. The symbol created is not inserted into the symbol table. + * \param symtab symbol table + * \param name symbol (label) name + * \param precbc bytecode preceding label + * \param line virtual line of label + * \return Symbol (dependent pointer, do not free). + */ +YASM_LIB_DECL +/*@dependent@*/ yasm_symrec *yasm_symtab_define_curpos + (yasm_symtab *symtab, const char *name, + /*@dependent@*/ yasm_bytecode *precbc, unsigned long line); + +/** Define a special symbol that will appear in the symbol table and have a + * defined name, but have no other data associated with it within the + * standard symrec. + * \param symtab symbol table + * \param name symbol name + * \param vis symbol visibility + * \return Symbol (dependent pointer, do not free). + */ +YASM_LIB_DECL +/*@dependent@*/ yasm_symrec *yasm_symtab_define_special + (yasm_symtab *symtab, const char *name, yasm_sym_vis vis); + +/** Declare external visibility of a symbol. + * \note Not all visibility combinations are allowed. + * \param symtab symbol table + * \param name symbol name + * \param vis visibility + * \param line virtual line of visibility-setting + * \return Symbol (dependent pointer, do not free). + */ +YASM_LIB_DECL +/*@dependent@*/ yasm_symrec *yasm_symtab_declare + (yasm_symtab *symtab, const char *name, yasm_sym_vis vis, + unsigned long line); + +/** Declare external visibility of a symbol. + * \note Not all visibility combinations are allowed. + * \param symrec symbol + * \param vis visibility + * \param line virtual line of visibility-setting + */ +YASM_LIB_DECL +void yasm_symrec_declare(yasm_symrec *symrec, yasm_sym_vis vis, + unsigned long line); + +/** Callback function for yasm_symrec_traverse(). + * \param sym symbol + * \param d data passed into yasm_symrec_traverse() + * \return Nonzero to stop symbol traversal. + */ +typedef int (*yasm_symtab_traverse_callback) + (yasm_symrec *sym, /*@null@*/ void *d); + +/** Traverse all symbols in the symbol table. + * \param symtab symbol table + * \param d data to pass to each call of callback function + * \param func callback function called on each symbol + * \return Nonzero value returned by callback function if it ever returned + * nonzero. + */ +YASM_LIB_DECL +int /*@alt void@*/ yasm_symtab_traverse + (yasm_symtab *symtab, /*@null@*/ void *d, + yasm_symtab_traverse_callback func); + +/** Symbol table iterator (opaque type). */ +typedef struct yasm_symtab_iter yasm_symtab_iter; + +/** Get an iterator pointing to the first symbol in the symbol table. + * \param symtab symbol table + * \return Iterator for the symbol table. + */ +YASM_LIB_DECL +const yasm_symtab_iter *yasm_symtab_first(const yasm_symtab *symtab); + +/** Move a symbol table iterator to the next symbol in the symbol table. + * \param prev Previous iterator value + * \return Next iterator value, or NULL if no more symbols in the table. + */ +YASM_LIB_DECL +/*@null@*/ const yasm_symtab_iter *yasm_symtab_next + (const yasm_symtab_iter *prev); + +/** Get the symbol corresponding to the current symbol table iterator value. + * \param cur iterator value + * \return Corresponding symbol. + */ +YASM_LIB_DECL +yasm_symrec *yasm_symtab_iter_value(const yasm_symtab_iter *cur); + +/** Finalize symbol table after parsing stage. Checks for symbols that are + * used but never defined or declared #YASM_SYM_EXTERN or #YASM_SYM_COMMON. + * \param symtab symbol table + * \param undef_extern if nonzero, all undef syms should be declared extern + * \param errwarns error/warning set + * \note Errors/warnings are stored into errwarns. + */ +YASM_LIB_DECL +void yasm_symtab_parser_finalize(yasm_symtab *symtab, int undef_extern, + yasm_errwarns *errwarns); + +/** Print the symbol table. For debugging purposes. + * \param symtab symbol table + * \param f file + * \param indent_level indentation level + */ +YASM_LIB_DECL +void yasm_symtab_print(yasm_symtab *symtab, FILE *f, int indent_level); + +/** Get the name of a symbol. + * \param sym symbol + * \return Symbol name. + */ +YASM_LIB_DECL +/*@observer@*/ const char *yasm_symrec_get_name(const yasm_symrec *sym); + +/** Get the externally-visible (global) name of a symbol. + * \param sym symbol + * \param object object + * \return Externally-visible symbol name (allocated, caller must free). + */ +YASM_LIB_DECL +/*@only@*/ char *yasm_symrec_get_global_name(const yasm_symrec *sym, + const yasm_object *object); + +/** Get the visibility of a symbol. + * \param sym symbol + * \return Symbol visibility. + */ +YASM_LIB_DECL +yasm_sym_vis yasm_symrec_get_visibility(const yasm_symrec *sym); + +/** Get the status of a symbol. + * \param sym symbol + * \return Symbol status. + */ +YASM_LIB_DECL +yasm_sym_status yasm_symrec_get_status(const yasm_symrec *sym); + +/** Get the virtual line of where a symbol was first defined. + * \param sym symbol + * \return line virtual line + */ +YASM_LIB_DECL +unsigned long yasm_symrec_get_def_line(const yasm_symrec *sym); + +/** Get the virtual line of where a symbol was first declared. + * \param sym symbol + * \return line virtual line + */ +YASM_LIB_DECL +unsigned long yasm_symrec_get_decl_line(const yasm_symrec *sym); + +/** Get the virtual line of where a symbol was first used. + * \param sym symbol + * \return line virtual line + */ +YASM_LIB_DECL +unsigned long yasm_symrec_get_use_line(const yasm_symrec *sym); + +/** Get EQU value of a symbol. + * \param sym symbol + * \return EQU value, or NULL if symbol is not an EQU or is not defined. + */ +YASM_LIB_DECL +/*@observer@*/ /*@null@*/ const yasm_expr *yasm_symrec_get_equ + (const yasm_symrec *sym); + +/** Dependent pointer to a bytecode. */ +typedef /*@dependent@*/ yasm_bytecode *yasm_symrec_get_label_bytecodep; + +/** Get the label location of a symbol. + * \param sym symbol + * \param precbc bytecode preceding label (output) + * \return 0 if not symbol is not a label or if the symbol's visibility is + * #YASM_SYM_EXTERN or #YASM_SYM_COMMON (not defined in the file). + */ +YASM_LIB_DECL +int yasm_symrec_get_label(const yasm_symrec *sym, + /*@out@*/ yasm_symrec_get_label_bytecodep *precbc); + +/** Set the size of a symbol. + * \param sym symbol + * \param size size to be set + */ +YASM_LIB_DECL +void yasm_symrec_set_size(yasm_symrec *sym, int size); + +/** Get the size of a symbol. + * \param sym symbol + * \return size of the symbol, 0 if none specified by the user. + */ +YASM_LIB_DECL +int yasm_symrec_get_size(const yasm_symrec *sym); + +/** Set the segment of a symbol. + * \param sym symbol + * \param segment segment to be set + */ +YASM_LIB_DECL +void yasm_symrec_set_segment(yasm_symrec *sym, const char *segment); + +/** Get the segment of a symbol. + * \param sym symbol + * \return segment of the symbol, NULL if none specified by the user. + */ +YASM_LIB_DECL +const char *yasm_symrec_get_segment(const yasm_symrec *sym); + +/** Determine if symbol is the "absolute" symbol created by + * yasm_symtab_abs_sym(). + * \param sym symbol + * \return 0 if symbol is not the "absolute" symbol, nonzero otherwise. + */ +YASM_LIB_DECL +int yasm_symrec_is_abs(const yasm_symrec *sym); + +/** Determine if symbol is a special symbol. + * \param sym symbol + * \return 0 if symbol is not a special symbol, nonzero otherwise. + */ +YASM_LIB_DECL +int yasm_symrec_is_special(const yasm_symrec *sym); + +/** Determine if symbol is a label representing the current assembly position. + * \param sym symbol + * \return 0 if symbol is not a current position label, nonzero otherwise. + */ +YASM_LIB_DECL +int yasm_symrec_is_curpos(const yasm_symrec *sym); + +/** Set object-extended valparams. + * \param sym symbol + * \param objext_valparams object-extended valparams + */ +YASM_LIB_DECL +void yasm_symrec_set_objext_valparams + (yasm_symrec *sym, /*@only@*/ yasm_valparamhead *objext_valparams); + +/** Get object-extended valparams, if any, associated with symbol's + * declaration. + * \param sym symbol + * \return Object-extended valparams (NULL if none). + */ +YASM_LIB_DECL +/*@null@*/ /*@dependent@*/ yasm_valparamhead *yasm_symrec_get_objext_valparams + (yasm_symrec *sym); + +/** Set common size of symbol. + * \param sym symbol + * \param common_size common size expression + */ +YASM_LIB_DECL +void yasm_symrec_set_common_size + (yasm_symrec *sym, /*@only@*/ yasm_expr *common_size); + +/** Get common size of symbol, if symbol is declared COMMON and a size was set + * for it. + * \param sym symbol + * \return Common size (NULL if none). + */ +YASM_LIB_DECL +/*@dependent@*/ /*@null@*/ yasm_expr **yasm_symrec_get_common_size + (yasm_symrec *sym); + +/** Get associated data for a symbol and data callback. + * \param sym symbol + * \param callback callback used when adding data + * \return Associated data (NULL if none). + */ +YASM_LIB_DECL +/*@dependent@*/ /*@null@*/ void *yasm_symrec_get_data + (yasm_symrec *sym, const yasm_assoc_data_callback *callback); + +/** Add associated data to a symbol. + * \attention Deletes any existing associated data for that data callback. + * \param sym symbol + * \param callback callback + * \param data data to associate + */ +YASM_LIB_DECL +void yasm_symrec_add_data(yasm_symrec *sym, + const yasm_assoc_data_callback *callback, + /*@only@*/ /*@null@*/ void *data); + +/** Print a symbol. For debugging purposes. + * \param f file + * \param indent_level indentation level + * \param sym symbol + */ +YASM_LIB_DECL +void yasm_symrec_print(const yasm_symrec *sym, FILE *f, int indent_level); + +#endif diff --git a/contrib/tools/yasm/libyasm/valparam.c b/contrib/tools/yasm/libyasm/valparam.c new file mode 100644 index 0000000000..88e41a7c5d --- /dev/null +++ b/contrib/tools/yasm/libyasm/valparam.c @@ -0,0 +1,385 @@ +/* + * Value/Parameter type 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-stdint.h" +#include "coretype.h" +#include "valparam.h" + +#include "errwarn.h" +#include "intnum.h" +#include "expr.h" +#include "symrec.h" + +#include "section.h" + +void +yasm_call_directive(const yasm_directive *directive, yasm_object *object, + yasm_valparamhead *valparams, + yasm_valparamhead *objext_valparams, unsigned long line) +{ + yasm_valparam *vp; + + if ((directive->flags & (YASM_DIR_ARG_REQUIRED|YASM_DIR_ID_REQUIRED)) && + (!valparams || !yasm_vps_first(valparams))) { + yasm_error_set(YASM_ERROR_SYNTAX, + N_("directive `%s' requires an argument"), + directive->name); + return; + } + if (valparams) { + vp = yasm_vps_first(valparams); + if ((directive->flags & YASM_DIR_ID_REQUIRED) && + vp->type != YASM_PARAM_ID) { + yasm_error_set(YASM_ERROR_SYNTAX, + N_("directive `%s' requires an identifier parameter"), + directive->name); + return; + } + } + directive->handler(object, valparams, objext_valparams, line); +} + +yasm_valparam * +yasm_vp_create_id(/*@keep@*/ char *v, /*@keep@*/ char *p, int id_prefix) +{ + yasm_valparam *r = yasm_xmalloc(sizeof(yasm_valparam)); + r->val = v; + r->type = YASM_PARAM_ID; + r->param.id = p; + r->id_prefix = (char)id_prefix; + return r; +} + +yasm_valparam * +yasm_vp_create_string(/*@keep@*/ char *v, /*@keep@*/ char *p) +{ + yasm_valparam *r = yasm_xmalloc(sizeof(yasm_valparam)); + r->val = v; + r->type = YASM_PARAM_STRING; + r->param.str = p; + r->id_prefix = '\0'; + return r; +} + +yasm_valparam * +yasm_vp_create_expr(/*@keep@*/ char *v, /*@keep@*/ yasm_expr *p) +{ + yasm_valparam *r = yasm_xmalloc(sizeof(yasm_valparam)); + r->val = v; + r->type = YASM_PARAM_EXPR; + r->param.e = p; + r->id_prefix = '\0'; + return r; +} + +/*@null@*/ /*@only@*/ yasm_expr * +yasm_vp_expr(const yasm_valparam *vp, yasm_symtab *symtab, unsigned long line) +{ + if (!vp) + return NULL; + switch (vp->type) { + case YASM_PARAM_ID: + return yasm_expr_create_ident(yasm_expr_sym( + yasm_symtab_use(symtab, yasm_vp_id(vp), line)), line); + case YASM_PARAM_EXPR: + return yasm_expr_copy(vp->param.e); + default: + return NULL; + } +} + +/*@null@*/ /*@dependent@*/ const char * +yasm_vp_string(const yasm_valparam *vp) +{ + if (!vp) + return NULL; + switch (vp->type) { + case YASM_PARAM_ID: + return vp->param.id; + case YASM_PARAM_STRING: + return vp->param.str; + default: + return NULL; + } +} + +/*@null@*/ /*@dependent@*/ const char * +yasm_vp_id(const yasm_valparam *vp) +{ + if (!vp) + return NULL; + if (vp->type == YASM_PARAM_ID) { + if (vp->param.id[0] == vp->id_prefix) + return &vp->param.id[1]; + else + return vp->param.id; + } + return NULL; +} + +void +yasm_vps_delete(yasm_valparamhead *headp) +{ + yasm_valparam *cur, *next; + + cur = STAILQ_FIRST(headp); + while (cur) { + next = STAILQ_NEXT(cur, link); + if (cur->val) + yasm_xfree(cur->val); + switch (cur->type) { + case YASM_PARAM_ID: + yasm_xfree(cur->param.id); + break; + case YASM_PARAM_STRING: + yasm_xfree(cur->param.str); + break; + case YASM_PARAM_EXPR: + yasm_expr_destroy(cur->param.e); + break; + } + yasm_xfree(cur); + cur = next; + } + STAILQ_INIT(headp); +} + +void +yasm_vps_print(const yasm_valparamhead *headp, FILE *f) +{ + const yasm_valparam *vp; + + if(!headp) { + fprintf(f, "(none)"); + return; + } + + yasm_vps_foreach(vp, headp) { + if (vp->val) + fprintf(f, "(\"%s\",", vp->val); + else + fprintf(f, "((nil),"); + switch (vp->type) { + case YASM_PARAM_ID: + fprintf(f, "%s", vp->param.id); + break; + case YASM_PARAM_STRING: + fprintf(f, "\"%s\"", vp->param.str); + break; + case YASM_PARAM_EXPR: + yasm_expr_print(vp->param.e, f); + break; + } + fprintf(f, ")"); + if (yasm_vps_next(vp)) + fprintf(f, ","); + } +} + +yasm_valparamhead * +yasm_vps_create(void) +{ + yasm_valparamhead *headp = yasm_xmalloc(sizeof(yasm_valparamhead)); + yasm_vps_initialize(headp); + return headp; +} + +void +yasm_vps_destroy(yasm_valparamhead *headp) +{ + yasm_vps_delete(headp); + yasm_xfree(headp); +} + +int +yasm_dir_helper(void *obj, yasm_valparam *vp_first, unsigned long line, + const yasm_dir_help *help, size_t nhelp, void *data, + int (*helper_valparam) (void *obj, yasm_valparam *vp, + unsigned long line, void *data)) +{ + yasm_valparam *vp = vp_first; + int anymatched = 0; + int matched; + + if (!vp) + return 0; + + do { + const char *s; + size_t i; + + matched = 0; + if (!vp->val && (s = yasm_vp_id(vp))) { + for (i=0; i<nhelp; i++) { + if (help[i].needsparam == 0 && + yasm__strcasecmp(s, help[i].name) == 0) { + if (help[i].helper(obj, vp, line, + ((char *)data)+help[i].off, + help[i].arg) != 0) + return -1; + matched = 1; + anymatched = 1; + break; + } + } + } else if (vp->val) { + for (i=0; i<nhelp; i++) { + if (help[i].needsparam == 1 && + yasm__strcasecmp(vp->val, help[i].name) == 0) { + if (help[i].helper(obj, vp, line, + ((char *)data)+help[i].off, + help[i].arg) != 0) + return -1; + matched = 1; + anymatched = 1; + break; + } + } + } + + if (!matched) { + int final = helper_valparam(obj, vp, line, data); + if (final < 0) + return -1; + if (final > 0) + anymatched = 1; + } + } while((vp = yasm_vps_next(vp))); + + return anymatched; +} + +int +yasm_dir_helper_flag_or(void *obj, yasm_valparam *vp, unsigned long line, + void *d, uintptr_t flag) +{ + unsigned long *flags = (unsigned long *)d; + *flags |= flag; + return 0; +} + +int +yasm_dir_helper_flag_and(void *obj, yasm_valparam *vp, unsigned long line, + void *d, uintptr_t flag) +{ + unsigned long *flags = (unsigned long *)d; + *flags &= ~flag; + return 0; +} + +int +yasm_dir_helper_flag_set(void *obj, yasm_valparam *vp, unsigned long line, + void *d, uintptr_t flag) +{ + unsigned long *flags = (unsigned long *)d; + *flags = flag; + return 0; +} + +int +yasm_dir_helper_expr(void *obj, yasm_valparam *vp, unsigned long line, + void *data, uintptr_t arg) +{ + yasm_object *object = (yasm_object *)obj; + yasm_expr **expr = (yasm_expr **)data; + + if (*expr) + yasm_expr_destroy(*expr); + if (!(*expr = yasm_vp_expr(vp, object->symtab, line))) { + yasm_error_set(YASM_ERROR_VALUE, N_("argument to `%s' is not an expression"), + vp->val); + return -1; + } + return 0; +} + +int +yasm_dir_helper_intn(void *obj, yasm_valparam *vp, unsigned long line, + void *data, uintptr_t arg) +{ + yasm_object *object = (yasm_object *)obj; + /*@only@*/ /*@null@*/ yasm_expr *e; + /*@dependent@*/ /*@null@*/ yasm_intnum *local; + yasm_intnum **intn = (yasm_intnum **)data; + + if (*intn) + yasm_intnum_destroy(*intn); + if (!(e = yasm_vp_expr(vp, object->symtab, line)) || + !(local = yasm_expr_get_intnum(&e, 0))) { + yasm_error_set(YASM_ERROR_NOT_CONSTANT, + N_("argument to `%s' is not an integer"), + vp->val); + if (e) + yasm_expr_destroy(e); + return -1; + } + *intn = yasm_intnum_copy(local); + yasm_expr_destroy(e); + return 0; +} + +int +yasm_dir_helper_string(void *obj, yasm_valparam *vp, unsigned long line, + void *data, uintptr_t arg) +{ + /*@dependent@*/ /*@null@*/ const char *local; + char **s = (char **)data; + + if (*s) + yasm_xfree(*s); + if (!(local = yasm_vp_string(vp))) { + yasm_error_set(YASM_ERROR_VALUE, + N_("argument to `%s' is not a string or identifier"), + vp->val); + return -1; + } + *s = yasm__xstrdup(local); + return 0; +} + +int +yasm_dir_helper_valparam_warn(void *obj, yasm_valparam *vp, + unsigned long line, void *data) +{ + const char *s; + + if (vp->val) { + yasm_warn_set(YASM_WARN_GENERAL, N_("Unrecognized qualifier `%s'"), + vp->val); + return 0; + } + + if ((s = yasm_vp_id(vp))) + yasm_warn_set(YASM_WARN_GENERAL, N_("Unrecognized qualifier `%s'"), s); + else if (vp->type == YASM_PARAM_STRING) + yasm_warn_set(YASM_WARN_GENERAL, N_("Unrecognized string qualifier")); + else + yasm_warn_set(YASM_WARN_GENERAL, N_("Unrecognized numeric qualifier")); + + return 0; +} diff --git a/contrib/tools/yasm/libyasm/valparam.h b/contrib/tools/yasm/libyasm/valparam.h new file mode 100644 index 0000000000..d7343d4955 --- /dev/null +++ b/contrib/tools/yasm/libyasm/valparam.h @@ -0,0 +1,408 @@ +/** + * \file libyasm/valparam.h + * \brief YASM value/parameter interface. + * + * \license + * 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: + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - 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. + * \endlicense + */ +#ifndef YASM_VALPARAM_H +#define YASM_VALPARAM_H + +#ifndef YASM_LIB_DECL +#define YASM_LIB_DECL +#endif + +/** Value/parameter pair. \internal */ +struct yasm_valparam { + /*@reldef@*/ STAILQ_ENTRY(yasm_valparam) link; /**< Next pair in list */ + /*@owned@*/ /*@null@*/ char *val; /**< Value */ + + /** Parameter type. */ + enum yasm_param_type { + YASM_PARAM_ID, /**< Identifier */ + YASM_PARAM_STRING, /**< String */ + YASM_PARAM_EXPR /**< Expression */ + } type; /**< Parameter type */ + + /** Parameter value. */ + union yasm_param { + /*@owned@*/ char *id; /**< Identifier */ + /*@owned@*/ char *str; /**< String */ + /*@owned@*/ yasm_expr *e; /**< Expression */ + } param; /**< Parameter */ + + /** Prefix character that indicates a raw identifier. When + * yasm_vp_string() is called on a #YASM_PARAM_ID, all characters are + * returned. When yasm_vp_id() is called on a #YASM_PARAM_ID, if the + * identifier begins with this character, this character is stripped + * from the returned value. + */ + char id_prefix; +}; + +/** Linked list of value/parameter pairs. \internal */ +/*@reldef@*/ STAILQ_HEAD(yasm_valparamhead, yasm_valparam); + +/** Directive list entry structure. */ +struct yasm_directive { + /** Directive name. GAS directives should include the ".", NASM + * directives should just be the raw name (not including the []). + * NULL entry required to terminate list of directives. + */ + /*@null@*/ const char *name; + + const char *parser; /**< Parser keyword */ + + /** Handler callback function for the directive. + * \param object object + * \param valparams value/parameters + * \param objext_valparams object format-specific value/parameters + * \param line virtual line (from yasm_linemap) + */ + void (*handler) (yasm_object *object, yasm_valparamhead *valparams, + yasm_valparamhead *objext_valparams, unsigned long line); + + /** Flags for pre-handler parameter checking. */ + enum yasm_directive_flags { + YASM_DIR_ANY = 0, /**< Any valparams accepted */ + YASM_DIR_ARG_REQUIRED = 1, /**< Require at least 1 valparam */ + YASM_DIR_ID_REQUIRED = 2 /**< First valparam must be ID */ + } flags; +}; + +/** Call a directive. Performs any valparam checks asked for by the + * directive prior to call. Note that for a variety of reasons, a directive + * can generate an error. + * \param directive directive + * \param object object + * \param valparams value/parameters + * \param objext_valparams object format-specific value/parameters + * \param line virtual line (from yasm_linemap) + */ +YASM_LIB_DECL +void yasm_call_directive(const yasm_directive *directive, yasm_object *object, + yasm_valparamhead *valparams, + yasm_valparamhead *objext_valparams, + unsigned long line); + +/** Create a new valparam with identifier parameter. + * \param v value + * \param p parameter + * \param id_prefix identifier prefix for raw identifiers + * \return Newly allocated valparam. + */ +YASM_LIB_DECL +yasm_valparam *yasm_vp_create_id(/*@keep@*/ char *v, /*@keep@*/ char *p, + int id_prefix); + +/** Create a new valparam with string parameter. + * \param v value + * \param p parameter + * \return Newly allocated valparam. + */ +YASM_LIB_DECL +yasm_valparam *yasm_vp_create_string(/*@keep@*/ char *v, /*@keep@*/ char *p); + +/** Create a new valparam with expression parameter. + * \param v value + * \param p parameter + * \return Newly allocated valparam. + */ +YASM_LIB_DECL +yasm_valparam *yasm_vp_create_expr(/*@keep@*/ char *v, + /*@keep@*/ yasm_expr *p); + +/** Get a valparam parameter as an expr. If the parameter is an identifier, + * it's treated as a symbol (yasm_symtab_use() is called to convert it). + * \param vp valparam + * \param symtab symbol table + * \param line virtual line + * \return Expression, or NULL if vp is NULL or the parameter cannot be + * converted to an expression. + */ +YASM_LIB_DECL +/*@null@*/ /*@only@*/ yasm_expr *yasm_vp_expr + (const yasm_valparam *vp, yasm_symtab *symtab, unsigned long line); + +/** Get a valparam parameter as a string. If the parameter is an identifier, + * it's treated as a string. + * \param vp valparam + * \return String, or NULL if vp is NULL or the parameter cannot be realized + * as a string. + */ +YASM_LIB_DECL +/*@null@*/ /*@dependent@*/ const char *yasm_vp_string(const yasm_valparam *vp); + +/** Get a valparam parameter as an identifier. + * \param vp valparam + * \return Identifier (string), or NULL if vp is NULL or the parameter is not + * an identifier. + */ +YASM_LIB_DECL +/*@null@*/ /*@dependent@*/ const char *yasm_vp_id(const yasm_valparam *vp); + +/** Create a new linked list of valparams. + * \return Newly allocated valparam list. + */ +YASM_LIB_DECL +yasm_valparamhead *yasm_vps_create(void); + +/** Destroy a list of valparams (created with yasm_vps_create). + * \param headp list of valparams + */ +YASM_LIB_DECL +void yasm_vps_destroy(yasm_valparamhead *headp); + +/** Initialize linked list of valparams. + * \param headp linked list + */ +void yasm_vps_initialize(/*@out@*/ yasm_valparamhead *headp); +#ifndef YASM_DOXYGEN +#define yasm_vps_initialize(headp) STAILQ_INIT(headp) +#endif + +/** Destroy (free allocated memory for) linked list of valparams (created with + * yasm_vps_initialize). + * \warning Deletes val/params. + * \param headp linked list + */ +YASM_LIB_DECL +void yasm_vps_delete(yasm_valparamhead *headp); + +/** Append valparam to tail of linked list. + * \param headp linked list + * \param vp valparam + */ +void yasm_vps_append(yasm_valparamhead *headp, /*@keep@*/ yasm_valparam *vp); +#ifndef YASM_DOXYGEN +#define yasm_vps_append(headp, vp) do { \ + if (vp) \ + STAILQ_INSERT_TAIL(headp, vp, link); \ + } while(0) +#endif + +/** Get first valparam in linked list. + * \param headp linked list + * \return First valparam in linked list. + */ +/*@null@*/ /*@dependent@*/ yasm_valparam *yasm_vps_first + (yasm_valparamhead *headp); +#ifndef YASM_DOXYGEN +#define yasm_vps_first(headp) STAILQ_FIRST(headp) +#endif + +/** Get next valparam in linked list. + * \param cur previous valparam in linked list + * \return Next valparam in linked list. + */ +/*@null@*/ /*@dependent@*/ yasm_valparam *yasm_vps_next(yasm_valparam *cur); +#ifndef YASM_DOXYGEN +#define yasm_vps_next(cur) STAILQ_NEXT(cur, link) +#endif + +/** Iterate through linked list of valparams. + * \internal + * \param iter iterator variable + * \param headp linked list + */ +#ifndef YASM_DOXYGEN +#define yasm_vps_foreach(iter, headp) STAILQ_FOREACH(iter, headp, link) +#endif + +/** Print linked list of valparams. For debugging purposes. + * \param f file + * \param headp linked list + */ +YASM_LIB_DECL +void yasm_vps_print(/*@null@*/ const yasm_valparamhead *headp, FILE *f); + +/** Directive valparam parse helper structure. */ +typedef struct yasm_dir_help { + /** Value portion of val=param (if needsparam=1), or standalone identifier + * (if needsparam=0). + */ + const char *name; + + /** 1 if value requires parameter, 0 if it must not have a parameter. */ + int needsparam; + + /** Helper callback function if name and parameter existence match. + * \param obj obj passed into yasm_dir_helper() + * \param vp value/parameter + * \param line line passed into yasm_dir_helper() + * \param data data passed into yasm_dir_helper() plus + #yasm_dir_help.off offset + * \param arg #yasm_dir_help.arg argument + * \return -1 on error, 0 otherwise. + */ + int (*helper) (void *obj, yasm_valparam *vp, unsigned long line, + void *data, uintptr_t arg); + + /** Offset added to data pointer passed into yasm_dir_helper() before + * data pointer is given to #yasm_dir_help.helper(). This is so that + * a structure can be passed into yasm_dir_helper() and this can be an + * offsetof() to point the helper function to a specific structure + * member. + */ + size_t off; + + /** Argument to pass in as the arg parameter to #yasm_dir_help.helper(). + */ + uintptr_t arg; +} yasm_dir_help; + +/** Help parse a list of directive value/parameters. Takes an array of + * #yasm_dir_help structures and tries to match val=param (or just val) + * against the passed value/parameters. When no match is found in the + * array of help structures, calls helper_valparam. + * \param obj object to be passed to yasm_dir_help.helper() or + * helper_valparam() callback + * \param vp_first first value/parameter to examine + * \param line virtual line number; passed down to helper callback + * \param help array of #yasm_dir_help structures + * \param nhelp number of array elements + * \param data base data pointer; if a match is found, + * the respective #yasm_dir_help.off is added to this + * prior to it being passed to the helper callback + * \param helper_valparam catch-all callback; should return -1 on error, + * 0 if not matched, 1 if matched. + * \return -1 on error, 1 if any arguments matched (including via + * catch-all callback), 0 if no match. + */ +YASM_LIB_DECL +int yasm_dir_helper(void *obj, yasm_valparam *vp_first, unsigned long line, + const yasm_dir_help *help, size_t nhelp, void *data, + int (*helper_valparam) (void *object, + yasm_valparam *vp, + unsigned long line, + void *data)); + +/** Standard helper for yasm_dir_helper() that simply sets a flag when called. + * It does not look at the vp; rather, it uses the value of the arg parameter, + * and stores an unsigned long value to data. + * \param obj unused + * \param vp unused + * \param line unused + * \param data pointer to an unsigned long + * \param arg flag to set + * \return 0 + */ +YASM_LIB_DECL +int yasm_dir_helper_flag_set(void *obj, yasm_valparam *vp, unsigned long line, + void *data, uintptr_t arg); + +/** Standard helper for yasm_dir_helper() that simply ORs a flag when called. + * It does not look at the vp; rather, it uses the value of the arg parameter, + * and ORs it with the unsigned long value in data. + * \param obj unused + * \param vp unused + * \param line unused + * \param data pointer to an unsigned long + * \param arg flag to OR + * \return 0 + */ +YASM_LIB_DECL +int yasm_dir_helper_flag_or(void *obj, yasm_valparam *vp, unsigned long line, + void *data, uintptr_t arg); + +/** Standard helper for yasm_dir_helper() that simply ANDs a flag when called. + * It does not look at the vp; rather, it uses the value of the arg parameter, + * and ANDs its inverse (~) with the unsigned long value in data. + * \param obj unused + * \param vp unused + * \param line unused + * \param data pointer to an unsigned long + * \param arg flag to AND + * \return 0 + */ +YASM_LIB_DECL +int yasm_dir_helper_flag_and(void *obj, yasm_valparam *vp, unsigned long line, + void *data, uintptr_t arg); + +/** Standard helper for yasm_dir_helper() that parses an expr parameter. + * The #yasm_dir_help structure that uses this function should have + * needsparam=1. The obj parameter to yasm_dir_helper() when this helper + * is used MUST point to a #yasm_object. In addition, the data parameter + * that is ultimately passed to this function (e.g. yasm_dir_helper() data + * parameter plus #yasm_dir_help.off) must point to a #yasm_expr * + * initialized to NULL. + * \param obj object; must be #yasm_object + * \param vp valparam + * \param line virtual line number + * \param data pointer to #yasm_expr * + * \param arg unused argument + * \return -1 on error, 0 otherwise. + */ +YASM_LIB_DECL +int yasm_dir_helper_expr(void *obj, yasm_valparam *vp, unsigned long line, + void *data, uintptr_t arg); + +/** Standard helper for yasm_dir_helper() that parses an intnum parameter. + * The #yasm_dir_help structure that uses this function should have + * needsparam=1. The obj parameter to yasm_dir_helper() when this helper + * is used MUST point to a #yasm_object. In addition, the data parameter + * that is ultimately passed to this function (e.g. yasm_dir_helper() data + * parameter plus #yasm_dir_help.off) must point to a #yasm_intnum * + * initialized to NULL. + * \param obj object; must be #yasm_object + * \param vp valparam + * \param line virtual line number + * \param data pointer to #yasm_intnum * + * \param arg unused argument + * \return -1 on error, 0 otherwise. + */ +YASM_LIB_DECL +int yasm_dir_helper_intn(void *obj, yasm_valparam *vp, unsigned long line, + void *data, uintptr_t arg); + +/** Standard helper for yasm_dir_helper() that parses an string (or + * standalone identifier) parameter. + * The #yasm_dir_help structure that uses this function should have + * needsparam=1. The data parameter that is ultimately passed to this + * function (e.g. yasm_dir_helper() data parameter plus #yasm_dir_help.off) + * must point to a char * initialized to NULL. + * \param obj unused + * \param vp valparam + * \param line unused + * \param data pointer to char * + * \param arg unused + * \return -1 on error, 0 otherwise. + */ +YASM_LIB_DECL +int yasm_dir_helper_string(void *obj, yasm_valparam *vp, unsigned long line, + void *data, uintptr_t arg); + +/** Standard catch-all callback fro yasm_dir_helper(). Generates standard + * warning for all valparams. + * \param obj unused + * \param vp valparam + * \param line unused + * \param data unused + * \return 0 + */ +YASM_LIB_DECL +int yasm_dir_helper_valparam_warn(void *obj, yasm_valparam *vp, + unsigned long line, void *data); +#endif diff --git a/contrib/tools/yasm/libyasm/value.c b/contrib/tools/yasm/libyasm/value.c new file mode 100644 index 0000000000..3ab73c1cec --- /dev/null +++ b/contrib/tools/yasm/libyasm/value.c @@ -0,0 +1,771 @@ +/* + * Value handling + * + * Copyright (C) 2006-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-stdint.h" +#include "coretype.h" +#include "bitvect.h" + +#include "errwarn.h" +#include "intnum.h" +#include "floatnum.h" +#include "expr.h" +#include "value.h" +#include "symrec.h" + +#include "bytecode.h" +#include "section.h" + +#include "arch.h" + + +void +yasm_value_initialize(/*@out@*/ yasm_value *value, + /*@null@*/ /*@kept@*/ yasm_expr *e, unsigned int size) +{ + value->abs = e; + value->rel = NULL; + value->wrt = NULL; + value->seg_of = 0; + value->rshift = 0; + value->curpos_rel = 0; + value->ip_rel = 0; + value->jump_target = 0; + value->section_rel = 0; + value->no_warn = 0; + value->sign = 0; + value->size = size; +} + +void +yasm_value_init_sym(/*@out@*/ yasm_value *value, /*@null@*/ yasm_symrec *sym, + unsigned int size) +{ + value->abs = NULL; + value->rel = sym; + value->wrt = NULL; + value->seg_of = 0; + value->rshift = 0; + value->curpos_rel = 0; + value->ip_rel = 0; + value->jump_target = 0; + value->section_rel = 0; + value->no_warn = 0; + value->sign = 0; + value->size = size; +} + +void +yasm_value_init_copy(yasm_value *value, const yasm_value *orig) +{ + value->abs = orig->abs ? yasm_expr_copy(orig->abs) : NULL; + value->rel = orig->rel; + value->wrt = orig->wrt; + value->seg_of = orig->seg_of; + value->rshift = orig->rshift; + value->curpos_rel = orig->curpos_rel; + value->ip_rel = orig->ip_rel; + value->jump_target = orig->jump_target; + value->section_rel = orig->section_rel; + value->no_warn = orig->no_warn; + value->sign = orig->sign; + value->size = orig->size; +} + +void +yasm_value_delete(yasm_value *value) +{ + if (value->abs) + yasm_expr_destroy(value->abs); + value->abs = NULL; + value->rel = NULL; +} + +void +yasm_value_set_curpos_rel(yasm_value *value, yasm_bytecode *bc, + unsigned int ip_rel) +{ + value->curpos_rel = 1; + value->ip_rel = ip_rel; + /* In order for us to correctly output curpos-relative values, we must + * have a relative portion of the value. If one doesn't exist, point + * to a custom absolute symbol. + */ + if (!value->rel) { + yasm_object *object = yasm_section_get_object(yasm_bc_get_section(bc)); + value->rel = yasm_symtab_abs_sym(object->symtab); + } +} + +static int +value_finalize_scan(yasm_value *value, yasm_expr *e, + /*@null@*/ yasm_bytecode *expr_precbc, int ssym_not_ok) +{ + int i; + /*@dependent@*/ yasm_section *sect; + /*@dependent@*/ /*@null@*/ yasm_bytecode *precbc; + + unsigned long shamt; /* for SHR */ + + /* Yes, this has a maximum upper bound on 32 terms, based on an + * "insane number of terms" (and ease of implementation) WAG. + * The right way to do this would be a stack-based alloca, but that's + * not ISO C. We really don't want to malloc here as this function is + * hit a lot! + * + * This is a bitmask to keep things small, as this is a recursive + * routine and we don't want to eat up stack space. + */ + unsigned long used; /* for ADD */ + + /* Thanks to this running after a simplify, we don't need to iterate + * down through IDENTs or handle SUB. + * + * We scan for a single symrec, gathering info along the way. After + * we've found the symrec, we keep scanning but error if we find + * another one. We pull out the single symrec and any legal operations + * performed on it. + * + * Also, if we find a float anywhere, we don't allow mixing of a single + * symrec with it. + */ + switch (e->op) { + case YASM_EXPR_ADD: + /* Okay for single symrec anywhere in expr. + * Check for single symrec anywhere. + * Handle symrec-symrec by checking for (-1*symrec) + * and symrec term pairs (where both symrecs are in the same + * segment). + */ + if (e->numterms > 32) + yasm__fatal(N_("expression on line %d has too many add terms;" + " internal limit of 32"), e->line); + + used = 0; + + for (i=0; i<e->numterms; i++) { + int j; + yasm_expr *sube; + yasm_intnum *intn; + yasm_symrec *sym; + /*@dependent@*/ yasm_section *sect2; + /*@dependent@*/ /*@null@*/ yasm_bytecode *precbc2; + + /* First look for an (-1*symrec) term */ + if (e->terms[i].type != YASM_EXPR_EXPR) + continue; + sube = e->terms[i].data.expn; + + if (sube->op != YASM_EXPR_MUL || sube->numterms != 2) { + /* recurse instead */ + if (value_finalize_scan(value, sube, expr_precbc, + ssym_not_ok)) + return 1; + continue; + } + + if (sube->terms[0].type == YASM_EXPR_INT && + sube->terms[1].type == YASM_EXPR_SYM) { + intn = sube->terms[0].data.intn; + sym = sube->terms[1].data.sym; + } else if (sube->terms[0].type == YASM_EXPR_SYM && + sube->terms[1].type == YASM_EXPR_INT) { + sym = sube->terms[0].data.sym; + intn = sube->terms[1].data.intn; + } else { + if (value_finalize_scan(value, sube, expr_precbc, + ssym_not_ok)) + return 1; + continue; + } + + if (!yasm_intnum_is_neg1(intn)) { + if (value_finalize_scan(value, sube, expr_precbc, + ssym_not_ok)) + return 1; + continue; + } + + /* Look for the same symrec term; even if both are external, + * they should cancel out. + */ + for (j=0; j<e->numterms; j++) { + if (e->terms[j].type == YASM_EXPR_SYM + && e->terms[j].data.sym == sym + && (used & (1<<j)) == 0) { + /* Mark as used */ + used |= 1<<j; + + /* Replace both symrec portions with 0 */ + yasm_expr_destroy(sube); + e->terms[i].type = YASM_EXPR_INT; + e->terms[i].data.intn = yasm_intnum_create_uint(0); + e->terms[j].type = YASM_EXPR_INT; + e->terms[j].data.intn = yasm_intnum_create_uint(0); + + break; /* stop looking */ + } + } + if (j != e->numterms) + continue; + + if (!yasm_symrec_get_label(sym, &precbc)) { + if (value_finalize_scan(value, sube, expr_precbc, + ssym_not_ok)) + return 1; + continue; + } + sect2 = yasm_bc_get_section(precbc); + + /* Now look for a unused symrec term in the same segment */ + for (j=0; j<e->numterms; j++) { + if (e->terms[j].type == YASM_EXPR_SYM + && yasm_symrec_get_label(e->terms[j].data.sym, + &precbc2) + && (sect = yasm_bc_get_section(precbc2)) + && sect == sect2 + && (used & (1<<j)) == 0) { + /* Mark as used */ + used |= 1<<j; + break; /* stop looking */ + } + } + + /* We didn't match in the same segment. If the + * -1*symrec is actually -1*curpos, we can match + * unused symrec terms in other segments and generate + * a curpos-relative reloc. + * + * Similarly, handle -1*symrec in other segment via the + * following transformation: + * other-this = (other-.)+(.-this) + * We can only do this transformation if "this" is in + * this expr's segment. + * + * Don't do this if we've already become curpos-relative. + * The unmatched symrec will be caught below. + */ + if (j == e->numterms && !value->curpos_rel + && (yasm_symrec_is_curpos(sym) + || (expr_precbc + && sect2 == yasm_bc_get_section(expr_precbc)))) { + for (j=0; j<e->numterms; j++) { + if (e->terms[j].type == YASM_EXPR_SYM + && !yasm_symrec_get_equ(e->terms[j].data.sym) + && !yasm_symrec_is_special(e->terms[j].data.sym) + && (used & (1<<j)) == 0) { + /* Mark as used */ + used |= 1<<j; + /* Mark value as curpos-relative */ + if (value->rel || ssym_not_ok) + return 1; + value->rel = e->terms[j].data.sym; + value->curpos_rel = 1; + if (yasm_symrec_is_curpos(sym)) { + /* Replace both symrec portions with 0 */ + yasm_expr_destroy(sube); + e->terms[i].type = YASM_EXPR_INT; + e->terms[i].data.intn = + yasm_intnum_create_uint(0); + e->terms[j].type = YASM_EXPR_INT; + e->terms[j].data.intn = + yasm_intnum_create_uint(0); + } else { + /* Replace positive portion with curpos */ + yasm_object *object = + yasm_section_get_object(sect2); + yasm_symtab *symtab = object->symtab; + e->terms[j].data.sym = + yasm_symtab_define_curpos + (symtab, ".", expr_precbc, e->line); + } + break; /* stop looking */ + } + } + } + + + if (j == e->numterms) + return 1; /* We didn't find a match! */ + } + + /* Look for unmatched symrecs. If we've already found one or + * we don't WANT to find one, error out. + */ + for (i=0; i<e->numterms; i++) { + if (e->terms[i].type == YASM_EXPR_SYM + && (used & (1<<i)) == 0) { + if (value->rel || ssym_not_ok) + return 1; + value->rel = e->terms[i].data.sym; + /* and replace with 0 */ + e->terms[i].type = YASM_EXPR_INT; + e->terms[i].data.intn = yasm_intnum_create_uint(0); + } + } + break; + case YASM_EXPR_SHR: + /* Okay for single symrec in LHS and constant on RHS. + * Single symrecs are not okay on RHS. + * If RHS is non-constant, don't allow single symrec on LHS. + * XXX: should rshift be an expr instead?? + */ + + /* Check for single sym on LHS */ + if (e->terms[0].type != YASM_EXPR_SYM) + break; + + /* If we already have a sym, we can't take another one */ + if (value->rel || ssym_not_ok) + return 1; + + /* RHS must be a positive integer */ + if (e->terms[1].type != YASM_EXPR_INT) + return 1; /* can't shift sym by non-constant integer */ + shamt = yasm_intnum_get_uint(e->terms[1].data.intn); + if ((shamt + value->rshift) > YASM_VALUE_RSHIFT_MAX) + return 1; /* total shift would be too large */ + + /* Update value */ + value->rshift += shamt; + value->rel = e->terms[0].data.sym; + + /* Replace symbol with 0 */ + e->terms[0].type = YASM_EXPR_INT; + e->terms[0].data.intn = yasm_intnum_create_uint(0); + + /* Just leave SHR in place */ + break; + case YASM_EXPR_SEG: + /* Okay for single symrec (can only be done once). + * Not okay for anything BUT a single symrec as an immediate + * child. + */ + if (e->terms[0].type != YASM_EXPR_SYM) + return 1; + + if (value->seg_of) + return 1; /* multiple SEG not legal */ + value->seg_of = 1; + + if (value->rel || ssym_not_ok) + return 1; /* got a relative portion somewhere else? */ + value->rel = e->terms[0].data.sym; + + /* replace with ident'ed 0 */ + e->op = YASM_EXPR_IDENT; + e->terms[0].type = YASM_EXPR_INT; + e->terms[0].data.intn = yasm_intnum_create_uint(0); + break; + case YASM_EXPR_WRT: + /* Okay for single symrec in LHS and either a register or single + * symrec (as an immediate child) on RHS. + * If a single symrec on RHS, can only be done once. + * WRT reg is left in expr for arch to look at. + */ + + /* Handle RHS */ + switch (e->terms[1].type) { + case YASM_EXPR_SYM: + if (value->wrt) + return 1; + value->wrt = e->terms[1].data.sym; + /* and drop the WRT portion */ + e->op = YASM_EXPR_IDENT; + e->numterms = 1; + break; + case YASM_EXPR_REG: + break; /* ignore */ + default: + return 1; + } + + /* Handle LHS */ + switch (e->terms[0].type) { + case YASM_EXPR_SYM: + if (value->rel || ssym_not_ok) + return 1; + value->rel = e->terms[0].data.sym; + /* and replace with 0 */ + e->terms[0].type = YASM_EXPR_INT; + e->terms[0].data.intn = yasm_intnum_create_uint(0); + break; + case YASM_EXPR_EXPR: + /* recurse */ + return value_finalize_scan(value, e->terms[0].data.expn, + expr_precbc, ssym_not_ok); + default: + break; /* ignore */ + } + + break; + default: + /* Single symrec not allowed anywhere */ + for (i=0; i<e->numterms; i++) { + switch (e->terms[i].type) { + case YASM_EXPR_SYM: + return 1; + case YASM_EXPR_EXPR: + /* recurse */ + return value_finalize_scan(value, + e->terms[i].data.expn, + expr_precbc, 1); + default: + break; + } + } + break; + } + + return 0; +} + +int +yasm_value_finalize_expr(yasm_value *value, yasm_expr *e, + yasm_bytecode *precbc, unsigned int size) +{ + if (!e) { + yasm_value_initialize(value, NULL, size); + return 0; + } + yasm_value_initialize(value, e, size); + return yasm_value_finalize(value, precbc); +} + +int +yasm_value_finalize(yasm_value *value, yasm_bytecode *precbc) +{ + if (!value->abs) + return 0; + + value->abs = yasm_expr__level_tree(value->abs, 1, 1, 0, 0, NULL, NULL); + + /* quit early if there was an issue in simplify() */ + if (yasm_error_occurred()) + return 1; + + /* Strip top-level AND masking to an all-1s mask the same size + * of the value size. This allows forced avoidance of overflow warnings. + */ + if (value->abs->op == YASM_EXPR_AND) { + int term; + + /* Calculate 1<<size - 1 value */ + yasm_intnum *mask = yasm_intnum_create_uint(1); + yasm_intnum *mask_tmp = yasm_intnum_create_uint(value->size); + yasm_intnum_calc(mask, YASM_EXPR_SHL, mask_tmp); + yasm_intnum_set_uint(mask_tmp, 1); + yasm_intnum_calc(mask, YASM_EXPR_SUB, mask_tmp); + yasm_intnum_destroy(mask_tmp); + + /* Walk terms and delete matching masks */ + for (term=value->abs->numterms-1; term>=0; term--) { + if (value->abs->terms[term].type == YASM_EXPR_INT && + yasm_intnum_compare(value->abs->terms[term].data.intn, + mask) == 0) { + /* Delete the intnum */ + yasm_intnum_destroy(value->abs->terms[term].data.intn); + + /* Slide everything to its right over by 1 */ + if (term != value->abs->numterms-1) /* if it wasn't last.. */ + memmove(&value->abs->terms[term], + &value->abs->terms[term+1], + (value->abs->numterms-1-term)* + sizeof(yasm_expr__item)); + + /* Update numterms */ + value->abs->numterms--; + + /* Indicate warnings have been disabled */ + value->no_warn = 1; + } + } + if (value->abs->numterms == 1) + value->abs->op = YASM_EXPR_IDENT; + yasm_intnum_destroy(mask); + } + + /* Handle trivial (IDENT) cases immediately */ + if (value->abs->op == YASM_EXPR_IDENT) { + switch (value->abs->terms[0].type) { + case YASM_EXPR_INT: + if (yasm_intnum_is_zero(value->abs->terms[0].data.intn)) { + yasm_expr_destroy(value->abs); + value->abs = NULL; + } + return 0; + case YASM_EXPR_REG: + case YASM_EXPR_FLOAT: + return 0; + case YASM_EXPR_SYM: + value->rel = value->abs->terms[0].data.sym; + yasm_expr_destroy(value->abs); + value->abs = NULL; + return 0; + case YASM_EXPR_EXPR: + /* Bring up lower values. */ + while (value->abs->op == YASM_EXPR_IDENT + && value->abs->terms[0].type == YASM_EXPR_EXPR) { + yasm_expr *sube = value->abs->terms[0].data.expn; + yasm_xfree(value->abs); + value->abs = sube; + } + break; + default: + yasm_internal_error(N_("unexpected expr term type")); + } + } + + if (value_finalize_scan(value, value->abs, precbc, 0)) + return 1; + + value->abs = yasm_expr__level_tree(value->abs, 1, 1, 0, 0, NULL, NULL); + + /* Simplify 0 in abs to NULL */ + if (value->abs->op == YASM_EXPR_IDENT + && value->abs->terms[0].type == YASM_EXPR_INT + && yasm_intnum_is_zero(value->abs->terms[0].data.intn)) { + yasm_expr_destroy(value->abs); + value->abs = NULL; + } + return 0; +} + +yasm_intnum * +yasm_value_get_intnum(yasm_value *value, yasm_bytecode *bc, int calc_bc_dist) +{ + /*@dependent@*/ /*@null@*/ yasm_intnum *intn = NULL; + /*@only@*/ yasm_intnum *outval; + int sym_local; + + if (value->abs) { + /* Handle integer expressions, if non-integer or too complex, return + * NULL. + */ + intn = yasm_expr_get_intnum(&value->abs, calc_bc_dist); + if (!intn) + return NULL; + } + + if (value->rel) { + /* If relative portion is not in bc section, return NULL. + * Otherwise get the relative portion's offset. + */ + /*@dependent@*/ yasm_bytecode *rel_prevbc; + unsigned long dist; + + if (!bc) + return NULL; /* Can't calculate relative value */ + + sym_local = yasm_symrec_get_label(value->rel, &rel_prevbc); + if (value->wrt || value->seg_of || value->section_rel || !sym_local) + return NULL; /* we can't handle SEG, WRT, or external symbols */ + if (rel_prevbc->section != bc->section) + return NULL; /* not in this section */ + if (!value->curpos_rel) + return NULL; /* not PC-relative */ + + /* Calculate value relative to current assembly position */ + dist = yasm_bc_next_offset(rel_prevbc); + if (dist < bc->offset) { + outval = yasm_intnum_create_uint(bc->offset - dist); + yasm_intnum_calc(outval, YASM_EXPR_NEG, NULL); + } else { + dist -= bc->offset; + outval = yasm_intnum_create_uint(dist); + } + + if (value->rshift > 0) { + /*@only@*/ yasm_intnum *shamt = + yasm_intnum_create_uint((unsigned long)value->rshift); + yasm_intnum_calc(outval, YASM_EXPR_SHR, shamt); + yasm_intnum_destroy(shamt); + } + /* Add in absolute portion */ + if (intn) + yasm_intnum_calc(outval, YASM_EXPR_ADD, intn); + return outval; + } + + if (intn) + return yasm_intnum_copy(intn); + + /* No absolute or relative portions: output 0 */ + return yasm_intnum_create_uint(0); +} + +int +yasm_value_output_basic(yasm_value *value, /*@out@*/ unsigned char *buf, + size_t destsize, yasm_bytecode *bc, int warn, + yasm_arch *arch) +{ + /*@dependent@*/ /*@null@*/ yasm_intnum *intn = NULL; + /*@only@*/ yasm_intnum *outval; + int sym_local; + int retval = 1; + unsigned int valsize = value->size; + + if (value->no_warn) + warn = 0; + + if (value->abs) { + /* Handle floating point expressions */ + if (!value->rel && value->abs->op == YASM_EXPR_IDENT + && value->abs->terms[0].type == YASM_EXPR_FLOAT) { + if (yasm_arch_floatnum_tobytes(arch, value->abs->terms[0].data.flt, + buf, destsize, valsize, 0, warn)) + return -1; + else + return 1; + } + + /* Check for complex float expressions */ + if (yasm_expr__contains(value->abs, YASM_EXPR_FLOAT)) { + yasm_error_set(YASM_ERROR_FLOATING_POINT, + N_("floating point expression too complex")); + return -1; + } + + /* Handle normal integer expressions */ + intn = yasm_expr_get_intnum(&value->abs, 1); + + if (!intn) { + /* Second try before erroring: yasm_expr_get_intnum doesn't handle + * SEG:OFF, so try simplifying out any to just the OFF portion, + * then getting the intnum again. + */ + yasm_expr *seg = yasm_expr_extract_deep_segoff(&value->abs); + if (seg) + yasm_expr_destroy(seg); + intn = yasm_expr_get_intnum(&value->abs, 1); + } + + if (!intn) { + /* Still don't have an integer! */ + yasm_error_set(YASM_ERROR_TOO_COMPLEX, + N_("expression too complex")); + return -1; + } + } + + /* Adjust warn for signed/unsigned integer warnings */ + if (warn != 0) + warn = value->sign ? -1 : 1; + + if (value->rel) { + /* If relative portion is not in bc section, don't try to handle it + * here. Otherwise get the relative portion's offset. + */ + /*@dependent@*/ yasm_bytecode *rel_prevbc; + unsigned long dist; + + sym_local = yasm_symrec_get_label(value->rel, &rel_prevbc); + if (value->wrt || value->seg_of || value->section_rel || !sym_local) + return 0; /* we can't handle SEG, WRT, or external symbols */ + if (rel_prevbc->section != bc->section) + return 0; /* not in this section */ + if (!value->curpos_rel) + return 0; /* not PC-relative */ + + /* Calculate value relative to current assembly position */ + dist = yasm_bc_next_offset(rel_prevbc); + if (dist < bc->offset) { + outval = yasm_intnum_create_uint(bc->offset - dist); + yasm_intnum_calc(outval, YASM_EXPR_NEG, NULL); + } else { + dist -= bc->offset; + outval = yasm_intnum_create_uint(dist); + } + + if (value->rshift > 0) { + /*@only@*/ yasm_intnum *shamt = + yasm_intnum_create_uint((unsigned long)value->rshift); + yasm_intnum_calc(outval, YASM_EXPR_SHR, shamt); + yasm_intnum_destroy(shamt); + } + /* Add in absolute portion */ + if (intn) + yasm_intnum_calc(outval, YASM_EXPR_ADD, intn); + /* Output! */ + if (yasm_arch_intnum_tobytes(arch, outval, buf, destsize, valsize, 0, + bc, warn)) + retval = -1; + yasm_intnum_destroy(outval); + return retval; + } + + if (value->seg_of || value->rshift || value->curpos_rel || value->ip_rel + || value->section_rel) + return 0; /* We can't handle this with just an absolute */ + + if (intn) { + /* Output just absolute portion */ + if (yasm_arch_intnum_tobytes(arch, intn, buf, destsize, valsize, 0, bc, + warn)) + retval = -1; + } else { + /* No absolute or relative portions: output 0 */ + outval = yasm_intnum_create_uint(0); + if (yasm_arch_intnum_tobytes(arch, outval, buf, destsize, valsize, 0, + bc, warn)) + retval = -1; + yasm_intnum_destroy(outval); + } + return retval; +} + +void +yasm_value_print(const yasm_value *value, FILE *f, int indent_level) +{ + fprintf(f, "%*s%u-bit, %ssigned", indent_level, "", value->size, + value->sign ? "" : "un"); + fprintf(f, "%*sAbsolute portion=", indent_level, ""); + yasm_expr_print(value->abs, f); + fprintf(f, "\n"); + if (value->rel) { + fprintf(f, "%*sRelative to=%s%s\n", indent_level, "", + value->seg_of ? "SEG " : "", + yasm_symrec_get_name(value->rel)); + if (value->wrt) + fprintf(f, "%*s(With respect to=%s)\n", indent_level, "", + yasm_symrec_get_name(value->wrt)); + if (value->rshift > 0) + fprintf(f, "%*s(Right shifted by=%u)\n", indent_level, "", + value->rshift); + if (value->curpos_rel) + fprintf(f, "%*s(Relative to current position)\n", indent_level, + ""); + if (value->ip_rel) + fprintf(f, "%*s(IP-relative)\n", indent_level, ""); + if (value->jump_target) + fprintf(f, "%*s(Jump target)\n", indent_level, ""); + if (value->section_rel) + fprintf(f, "%*s(Section-relative)\n", indent_level, ""); + if (value->no_warn) + fprintf(f, "%*s(Overflow warnings disabled)\n", indent_level, ""); + } +} diff --git a/contrib/tools/yasm/libyasm/value.h b/contrib/tools/yasm/libyasm/value.h new file mode 100644 index 0000000000..4dc294bcc3 --- /dev/null +++ b/contrib/tools/yasm/libyasm/value.h @@ -0,0 +1,172 @@ +/** + * \file libyasm/value.h + * \brief YASM value interface. + * + * \license + * Copyright (C) 2006-2007 Peter Johnson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - 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. + * \endlicense + */ +#ifndef YASM_VALUE_H +#define YASM_VALUE_H + +#ifndef YASM_LIB_DECL +#define YASM_LIB_DECL +#endif + +/** Initialize a #yasm_value with just an expression. No processing is + * performed, the expression is simply stuck into value.abs and the other + * fields are initialized. Use yasm_expr_extract_value() to perform "smart" + * processing into a #yasm_value. This function is intended for use during + * parsing simply to ensure all fields of the value are initialized; after + * the parse is complete, yasm_value_extract() should be called to finalize + * the value. The value defaults to unsigned. + * \param value value to be initialized + * \param e expression (kept) + * \param size value size (in bits) + */ +YASM_LIB_DECL +void yasm_value_initialize(/*@out@*/ yasm_value *value, + /*@null@*/ /*@kept@*/ yasm_expr *e, + unsigned int size); + +/** Initialize a #yasm_value with just a symrec. No processing is performed, + * the symrec is simply stuck into value.rel and the other fields are + * initialized. + * \param value value to be initialized + * \param sym symrec + * \param size value size (in bits) + */ +YASM_LIB_DECL +void yasm_value_init_sym(/*@out@*/ yasm_value *value, + /*@null@*/ yasm_symrec *sym, unsigned int size); + +/** Initialize a #yasm_value as a copy of another yasm_value. Any expressions + * within orig are copied, so it's safe to delete the copy. + * \param value value (copy to create) + * \param orig original value + */ +YASM_LIB_DECL +void yasm_value_init_copy(yasm_value *value, const yasm_value *orig); + +/** Frees any memory inside value; does not free value itself. + * \param value value + */ +YASM_LIB_DECL +void yasm_value_delete(yasm_value *value); + +/** Set a value to be relative to the current assembly position rather than + * relative to the section start. + * \param value value + * \param bc bytecode containing value + * \param ip_rel if nonzero, indicates IP-relative data relocation, + * sometimes used to generate special relocations + * \note If value is just an absolute value, will get an absolute symrec to + * reference to (via bc's symbol table). + */ +YASM_LIB_DECL +void yasm_value_set_curpos_rel(yasm_value *value, yasm_bytecode *bc, + unsigned int ip_rel); + +/** Perform yasm_value_finalize_expr() on a value that already exists from + * being initialized with yasm_value_initialize(). + * \param value value + * \param precbc previous bytecode to bytecode containing value + * \return Nonzero if value could not be split. + */ +YASM_LIB_DECL +int yasm_value_finalize(yasm_value *value, /*@null@*/ yasm_bytecode *precbc); + +/** Break a #yasm_expr into a #yasm_value constituent parts. Extracts + * the relative portion of the value, SEG and WRT portions, and top-level + * right shift, if any. Places the remaining expr into the absolute + * portion of the value. Essentially a combination of yasm_value_initialize() + * and yasm_value_finalize(). First expands references to symrecs in + * absolute sections by expanding with the absolute section start plus the + * symrec offset within the absolute section. + * \param value value to store split portions into + * \param e expression input + * \param precbc previous bytecode to bytecode containing expression + * \param size value size (in bits) + * \return Nonzero if the expr could not be split into a value for some + * reason (e.g. the relative portion was not added, but multiplied, + * etc). + * \warning Do not use e after this call. Even if an error is returned, e + * is stored into value. + * \note This should only be called after the parse is complete. Calling + * before the parse is complete will usually result in an error return. + */ +YASM_LIB_DECL +int yasm_value_finalize_expr(/*@out@*/ yasm_value *value, + /*@null@*/ /*@kept@*/ yasm_expr *e, + /*@null@*/ yasm_bytecode *precbc, + unsigned int size); + +/** Get value if absolute or PC-relative section-local relative. Returns NULL + * otherwise. + * \param value value + * \param bc current bytecode (for PC-relative calculation); if + * NULL, NULL is returned for PC-relative values. + * \param calc_bc_dist if nonzero, calculates bytecode distances in absolute + * portion of value + * \note Adds in value.rel (correctly) if PC-relative and in the same section + * as bc (and there is no WRT or SEG). + * \return Intnum if can be resolved to integer value, otherwise NULL. + */ +YASM_LIB_DECL +/*@null@*/ /*@only@*/ yasm_intnum *yasm_value_get_intnum + (yasm_value *value, /*@null@*/ yasm_bytecode *bc, int calc_bc_dist); + +/** Output value if constant or PC-relative section-local. This should be + * used from objfmt yasm_output_value_func() functions. + * functions. + * \param value value + * \param buf buffer for byte representation + * \param destsize destination size (in bytes) + * \param bc current bytecode (usually passed into higher-level + * calling function) + * \param warn enables standard warnings: zero for none; + * nonzero for overflow/underflow floating point and + * integer warnings + * \param arch architecture + * \note Adds in value.rel (correctly) if PC-relative and in the same section + * as bc (and there is no WRT or SEG); if this is not the desired + * behavior, e.g. a reloc is needed in this case, don't use this + * function! + * \return 0 if no value output due to value needing relocation; + * 1 if value output; -1 if error. + */ +YASM_LIB_DECL +int yasm_value_output_basic + (yasm_value *value, /*@out@*/ unsigned char *buf, size_t destsize, + yasm_bytecode *bc, int warn, yasm_arch *arch); + +/** Print a value. For debugging purposes. + * \param value value + * \param indent_level indentation level + * \param f file + */ +YASM_LIB_DECL +void yasm_value_print(const yasm_value *value, FILE *f, int indent_level); + +#endif diff --git a/contrib/tools/yasm/libyasm/xmalloc.c b/contrib/tools/yasm/libyasm/xmalloc.c new file mode 100644 index 0000000000..81b608c078 --- /dev/null +++ b/contrib/tools/yasm/libyasm/xmalloc.c @@ -0,0 +1,114 @@ +/* + * Memory allocation routines with error checking. Idea from GNU libiberty. + * + * 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 "coretype.h" +#include "errwarn.h" + + +#ifdef WITH_DMALLOC +#undef yasm_xmalloc +#undef yasm_xcalloc +#undef yasm_xrealloc +#undef yasm_xfree +#endif + +static /*@only@*/ /*@out@*/ void *def_xmalloc(size_t size); +static /*@only@*/ void *def_xcalloc(size_t nelem, size_t elsize); +static /*@only@*/ void *def_xrealloc + (/*@only@*/ /*@out@*/ /*@returned@*/ /*@null@*/ void *oldmem, size_t size) + /*@modifies oldmem@*/; +static void def_xfree(/*@only@*/ /*@out@*/ /*@null@*/ void *p) + /*@modifies p@*/; + +/* storage for global function pointers */ +YASM_LIB_DECL +/*@only@*/ /*@out@*/ void * (*yasm_xmalloc) (size_t size) = def_xmalloc; +YASM_LIB_DECL +/*@only@*/ void * (*yasm_xcalloc) (size_t nelem, size_t elsize) = def_xcalloc; +YASM_LIB_DECL +/*@only@*/ void * (*yasm_xrealloc) + (/*@only@*/ /*@out@*/ /*@returned@*/ /*@null@*/ void *oldmem, size_t size) + /*@modifies oldmem@*/ = def_xrealloc; +YASM_LIB_DECL +void (*yasm_xfree) (/*@only@*/ /*@out@*/ /*@null@*/ void *p) + /*@modifies p@*/ = def_xfree; + + +static void * +def_xmalloc(size_t size) +{ + void *newmem; + + if (size == 0) + size = 1; + newmem = malloc(size); + if (!newmem) + yasm__fatal(N_("out of memory")); + + return newmem; +} + +static void * +def_xcalloc(size_t nelem, size_t elsize) +{ + void *newmem; + + if (nelem == 0 || elsize == 0) + nelem = elsize = 1; + + newmem = calloc(nelem, elsize); + if (!newmem) + yasm__fatal(N_("out of memory")); + + return newmem; +} + +static void * +def_xrealloc(void *oldmem, size_t size) +{ + void *newmem; + + if (size == 0) + size = 1; + if (!oldmem) + newmem = malloc(size); + else + newmem = realloc(oldmem, size); + if (!newmem) + yasm__fatal(N_("out of memory")); + + return newmem; +} + +static void +def_xfree(void *p) +{ + if (!p) + return; + free(p); +} diff --git a/contrib/tools/yasm/libyasm/xstrdup.c b/contrib/tools/yasm/libyasm/xstrdup.c new file mode 100644 index 0000000000..b187704f0e --- /dev/null +++ b/contrib/tools/yasm/libyasm/xstrdup.c @@ -0,0 +1,68 @@ +/* + * strdup() implementation with error checking (using xmalloc). + * + * Copyright (c) 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * 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. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND 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 REGENTS OR 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 "coretype.h" + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)strdup.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ + + +#ifdef WITH_DMALLOC +#undef yasm__xstrdup +#endif + +char * +yasm__xstrdup(const char *str) +{ + size_t len; + char *copy; + + len = strlen(str) + 1; + copy = yasm_xmalloc(len); + memcpy(copy, str, len); + return (copy); +} + +char * +yasm__xstrndup(const char *str, size_t max) +{ + size_t len = 0; + char *copy; + + while (len < max && str[len] != '\0') + len++; + copy = yasm_xmalloc(len+1); + memcpy(copy, str, len); + copy[len] = '\0'; + return (copy); +} diff --git a/contrib/tools/yasm/modules/arch/lc3b/lc3barch.c b/contrib/tools/yasm/modules/arch/lc3b/lc3barch.c new file mode 100644 index 0000000000..051452862f --- /dev/null +++ b/contrib/tools/yasm/modules/arch/lc3b/lc3barch.c @@ -0,0 +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 +}; diff --git a/contrib/tools/yasm/modules/arch/lc3b/lc3barch.h b/contrib/tools/yasm/modules/arch/lc3b/lc3barch.h new file mode 100644 index 0000000000..9ded8cbef7 --- /dev/null +++ b/contrib/tools/yasm/modules/arch/lc3b/lc3barch.h @@ -0,0 +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 diff --git a/contrib/tools/yasm/modules/arch/lc3b/lc3bbc.c b/contrib/tools/yasm/modules/arch/lc3b/lc3bbc.c new file mode 100644 index 0000000000..d077c7c5fb --- /dev/null +++ b/contrib/tools/yasm/modules/arch/lc3b/lc3bbc.c @@ -0,0 +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; +} diff --git a/contrib/tools/yasm/modules/arch/x86/x86arch.c b/contrib/tools/yasm/modules/arch/x86/x86arch.c new file mode 100644 index 0000000000..bac11774ea --- /dev/null +++ b/contrib/tools/yasm/modules/arch/x86/x86arch.c @@ -0,0 +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 +}; diff --git a/contrib/tools/yasm/modules/arch/x86/x86arch.h b/contrib/tools/yasm/modules/arch/x86/x86arch.h new file mode 100644 index 0000000000..78c3d73920 --- /dev/null +++ b/contrib/tools/yasm/modules/arch/x86/x86arch.h @@ -0,0 +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 diff --git a/contrib/tools/yasm/modules/arch/x86/x86bc.c b/contrib/tools/yasm/modules/arch/x86/x86bc.c new file mode 100644 index 0000000000..a6681552dd --- /dev/null +++ b/contrib/tools/yasm/modules/arch/x86/x86bc.c @@ -0,0 +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; +} diff --git a/contrib/tools/yasm/modules/arch/x86/x86expr.c b/contrib/tools/yasm/modules/arch/x86/x86expr.c new file mode 100644 index 0000000000..e9ddcce57e --- /dev/null +++ b/contrib/tools/yasm/modules/arch/x86/x86expr.c @@ -0,0 +1,1061 @@ +/* + * x86 expression handling + * + * Copyright (C) 2001-2007 Peter Johnson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include <util.h> + +#include <libyasm.h> + +#include "x86arch.h" + + +typedef struct x86_checkea_reg3264_data { + int *regs; /* total multiplier for each reg */ + unsigned char vsib_mode; + unsigned char bits; + unsigned char addrsize; +} x86_checkea_reg3264_data; + +/* Only works if ei->type == EXPR_REG (doesn't check). + * Overwrites ei with intnum of 0 (to eliminate regs from the final expr). + */ +static /*@null@*/ /*@dependent@*/ int * +x86_expr_checkea_get_reg3264(yasm_expr__item *ei, int *regnum, + /*returned*/ void *d) +{ + x86_checkea_reg3264_data *data = d; + + switch ((x86_expritem_reg_size)(ei->data.reg & ~0xFUL)) { + case X86_REG32: + if (data->addrsize != 32) + return 0; + *regnum = (unsigned int)(ei->data.reg & 0xF); + break; + case X86_REG64: + if (data->addrsize != 64) + return 0; + *regnum = (unsigned int)(ei->data.reg & 0xF); + break; + case X86_XMMREG: + if (data->vsib_mode != 1) + return 0; + if (data->bits != 64 && (ei->data.reg & 0x8) == 0x8) + return 0; + *regnum = 17+(unsigned int)(ei->data.reg & 0xF); + break; + case X86_YMMREG: + if (data->vsib_mode != 2) + return 0; + if (data->bits != 64 && (ei->data.reg & 0x8) == 0x8) + return 0; + *regnum = 17+(unsigned int)(ei->data.reg & 0xF); + break; + case X86_RIP: + if (data->bits != 64) + return 0; + *regnum = 16; + break; + default: + return 0; + } + + /* overwrite with 0 to eliminate register from displacement expr */ + ei->type = YASM_EXPR_INT; + ei->data.intn = yasm_intnum_create_uint(0); + + /* we're okay */ + return &data->regs[*regnum]; +} + +typedef struct x86_checkea_reg16_data { + int bx, si, di, bp; /* total multiplier for each reg */ +} x86_checkea_reg16_data; + +/* Only works if ei->type == EXPR_REG (doesn't check). + * Overwrites ei with intnum of 0 (to eliminate regs from the final expr). + */ +static /*@null@*/ int * +x86_expr_checkea_get_reg16(yasm_expr__item *ei, int *regnum, void *d) +{ + x86_checkea_reg16_data *data = d; + /* in order: ax,cx,dx,bx,sp,bp,si,di */ + /*@-nullassign@*/ + static int *reg16[8] = {0,0,0,0,0,0,0,0}; + /*@=nullassign@*/ + + reg16[3] = &data->bx; + reg16[5] = &data->bp; + reg16[6] = &data->si; + reg16[7] = &data->di; + + /* don't allow 32-bit registers */ + if ((ei->data.reg & ~0xFUL) != X86_REG16) + return 0; + + /* & 7 for sanity check */ + *regnum = (unsigned int)(ei->data.reg & 0x7); + + /* only allow BX, SI, DI, BP */ + if (!reg16[*regnum]) + return 0; + + /* overwrite with 0 to eliminate register from displacement expr */ + ei->type = YASM_EXPR_INT; + ei->data.intn = yasm_intnum_create_uint(0); + + /* we're okay */ + return reg16[*regnum]; +} + +/* Distribute over registers to help bring them to the topmost level of e. + * Also check for illegal operations against registers. + * Returns 0 if something was illegal, 1 if legal and nothing in e changed, + * and 2 if legal and e needs to be simplified. + * + * Only half joking: Someday make this/checkea able to accept crazy things + * like: (bx+di)*(bx+di)-bx*bx-2*bx*di-di*di+di? Probably not: NASM never + * accepted such things, and it's doubtful such an expn is valid anyway + * (even though the above one is). But even macros would be hard-pressed + * to generate something like this. + * + * e must already have been simplified for this function to work properly + * (as it doesn't think things like SUB are valid). + * + * IMPLEMENTATION NOTE: About the only thing this function really needs to + * "distribute" is: (non-float-expn or intnum) * (sum expn of registers). + * + * TODO: Clean up this code, make it easier to understand. + */ +static int +x86_expr_checkea_distcheck_reg(yasm_expr **ep, unsigned int bits) +{ + yasm_expr *e = *ep; + int i; + int havereg = -1, havereg_expr = -1; + int retval = 1; /* default to legal, no changes */ + + for (i=0; i<e->numterms; i++) { + switch (e->terms[i].type) { + case YASM_EXPR_REG: + /* Check op to make sure it's valid to use w/register. */ + switch (e->op) { + case YASM_EXPR_MUL: + /* Check for reg*reg */ + if (havereg != -1) + return 0; + break; + case YASM_EXPR_ADD: + case YASM_EXPR_IDENT: + break; + default: + return 0; + } + havereg = i; + break; + case YASM_EXPR_FLOAT: + /* Floats not allowed. */ + return 0; + case YASM_EXPR_EXPR: + if (yasm_expr__contains(e->terms[i].data.expn, + YASM_EXPR_REG)) { + int ret2; + + /* Check op to make sure it's valid to use w/register. */ + if (e->op != YASM_EXPR_ADD && e->op != YASM_EXPR_MUL) + return 0; + /* Check for reg*reg */ + if (e->op == YASM_EXPR_MUL && havereg != -1) + return 0; + havereg = i; + havereg_expr = i; + /* Recurse to check lower levels */ + ret2 = + x86_expr_checkea_distcheck_reg(&e->terms[i].data.expn, + bits); + if (ret2 == 0) + return 0; + if (ret2 == 2) + retval = 2; + } else if (yasm_expr__contains(e->terms[i].data.expn, + YASM_EXPR_FLOAT)) + return 0; /* Disallow floats */ + break; + default: + break; + } + } + + /* just exit if no registers were used */ + if (havereg == -1) + return retval; + + /* Distribute */ + if (e->op == YASM_EXPR_MUL && havereg_expr != -1) { + yasm_expr *ne; + + retval = 2; /* we're going to change it */ + + /* The reg expn *must* be EXPR_ADD at this point. Sanity check. */ + if (e->terms[havereg_expr].type != YASM_EXPR_EXPR || + e->terms[havereg_expr].data.expn->op != YASM_EXPR_ADD) + yasm_internal_error(N_("Register expression not ADD or EXPN")); + + /* Iterate over each term in reg expn */ + for (i=0; i<e->terms[havereg_expr].data.expn->numterms; i++) { + /* Copy everything EXCEPT havereg_expr term into new expression */ + ne = yasm_expr__copy_except(e, havereg_expr); + assert(ne != NULL); + /* Copy reg expr term into uncopied (empty) term in new expn */ + ne->terms[havereg_expr] = + e->terms[havereg_expr].data.expn->terms[i]; /* struct copy */ + /* Overwrite old reg expr term with new expn */ + e->terms[havereg_expr].data.expn->terms[i].type = YASM_EXPR_EXPR; + e->terms[havereg_expr].data.expn->terms[i].data.expn = ne; + } + + /* Replace e with expanded reg expn */ + ne = e->terms[havereg_expr].data.expn; + e->terms[havereg_expr].type = YASM_EXPR_NONE; /* don't delete it! */ + yasm_expr_destroy(e); /* but everything else */ + e = ne; + /*@-onlytrans@*/ + *ep = ne; + /*@=onlytrans@*/ + } + + return retval; +} + +/* Simplify and determine if expression is superficially valid: + * Valid expr should be [(int-equiv expn)]+[reg*(int-equiv expn)+...] + * where the [...] parts are optional. + * + * Don't simplify out constant identities if we're looking for an indexreg: we + * may need the multiplier for determining what the indexreg is! + * + * Returns 1 if invalid register usage, 2 if unable to determine all values, + * and 0 if all values successfully determined and saved in data. + */ +static int +x86_expr_checkea_getregusage(yasm_expr **ep, /*@null@*/ int *indexreg, + int *pcrel, unsigned int bits, void *data, + int *(*get_reg)(yasm_expr__item *ei, int *regnum, void *d)) +{ + int i; + int *reg; + int regnum; + int indexval = 0; + int indexmult = 0; + yasm_expr *e, *wrt; + + /*@-unqualifiedtrans@*/ + *ep = yasm_expr__level_tree(*ep, 1, 1, indexreg == 0, 0, NULL, NULL); + + /* Check for WRT rip first */ + wrt = yasm_expr_extract_wrt(ep); + if (wrt && wrt->op == YASM_EXPR_IDENT && + wrt->terms[0].type == YASM_EXPR_REG) { + if (bits != 64) { /* only valid in 64-bit mode */ + yasm_expr_destroy(wrt); + return 1; + } + reg = get_reg(&wrt->terms[0], ®num, data); + if (!reg || regnum != 16) { /* only accept rip */ + yasm_expr_destroy(wrt); + return 1; + } + (*reg)++; + + /* Delete WRT. Set pcrel to 1 to indicate to x86 + * bytecode code to do PC-relative displacement transform. + */ + *pcrel = 1; + yasm_expr_destroy(wrt); + } else if (wrt) { + yasm_expr_destroy(wrt); + return 1; + } + + /*@=unqualifiedtrans@*/ + assert(*ep != NULL); + e = *ep; + switch (x86_expr_checkea_distcheck_reg(ep, bits)) { + case 0: + return 1; + case 2: + /* Need to simplify again */ + *ep = yasm_expr__level_tree(*ep, 1, 1, indexreg == 0, 0, NULL, + NULL); + e = *ep; + break; + default: + break; + } + + switch (e->op) { + case YASM_EXPR_ADD: + /* Prescan for non-int multipliers against a reg. + * This is invalid due to the optimizer structure. + */ + for (i=0; i<e->numterms; i++) + if (e->terms[i].type == YASM_EXPR_EXPR) { + yasm_expr__order_terms(e->terms[i].data.expn); + if (e->terms[i].data.expn->terms[0].type == + YASM_EXPR_REG) { + if (e->terms[i].data.expn->numterms > 2) + return 1; + if (e->terms[i].data.expn->terms[1].type != + YASM_EXPR_INT) + return 1; + } + } + + /*@fallthrough@*/ + case YASM_EXPR_IDENT: + /* Check each term for register (and possible multiplier). */ + for (i=0; i<e->numterms; i++) { + if (e->terms[i].type == YASM_EXPR_REG) { + reg = get_reg(&e->terms[i], ®num, data); + if (!reg) + return 1; + (*reg)++; + /* Let last, largest multipler win indexreg */ + if (indexreg && *reg > 0 && indexval <= *reg && + !indexmult) { + *indexreg = regnum; + indexval = *reg; + } + } else if (e->terms[i].type == YASM_EXPR_EXPR) { + /* Already ordered from ADD above, just grab the value. + * Sanity check for EXPR_INT. + */ + if (e->terms[i].data.expn->terms[0].type == + YASM_EXPR_REG) { + long delta; + if (e->terms[i].data.expn->terms[1].type != + YASM_EXPR_INT) + yasm_internal_error( + N_("Non-integer value in reg expn")); + reg = get_reg(&e->terms[i].data.expn->terms[0], + ®num, data); + if (!reg) + return 1; + delta = yasm_intnum_get_int( + e->terms[i].data.expn->terms[1].data.intn); + (*reg) += delta; + /* Let last, largest multipler win indexreg */ + if (indexreg && delta > 0 && indexval <= *reg) { + *indexreg = regnum; + indexval = *reg; + indexmult = 1; + } else if (indexreg && *indexreg == regnum && + delta < 0 && *reg <= 1) { + *indexreg = -1; + indexval = 0; + indexmult = 0; + } + } + } + } + break; + case YASM_EXPR_MUL: + /* Here, too, check for non-int multipliers against a reg. */ + yasm_expr__order_terms(e); + if (e->terms[0].type == YASM_EXPR_REG) { + long delta; + if (e->numterms > 2) + return 1; + if (e->terms[1].type != YASM_EXPR_INT) + return 1; + reg = get_reg(&e->terms[0], ®num, data); + if (!reg) + return 1; + delta = yasm_intnum_get_int(e->terms[1].data.intn); + (*reg) += delta; + if (indexreg) + { + if (delta < 0 && *reg <= 1) + { + *indexreg = -1; + indexval = 0; + indexmult = 0; + } + else + *indexreg = regnum; + } + } + break; + case YASM_EXPR_SEGOFF: + /* No registers are allowed on either side. */ + if (yasm_expr__contains(e, YASM_EXPR_REG)) + return 1; + break; + default: + /* Should never get here! */ + yasm_internal_error(N_("unexpected expr op")); + } + + /* Simplify expr, which is now really just the displacement. This + * should get rid of the 0's we put in for registers in the callback. + */ + *ep = yasm_expr_simplify(*ep, 0); + /* e = *ep; */ + + return 0; +} + +/* Calculate the displacement length, if possible. + * Takes several extra inputs so it can be used by both 32-bit and 16-bit + * expressions: + * wordsize=16 for 16-bit, =32 for 32-bit. + * noreg=1 if the *ModRM byte* has no registers used. + * dispreq=1 if a displacement value is *required* (even if =0). + * Returns 0 if successfully calculated, 1 if not. + */ +/*@-nullstate@*/ +static int +x86_checkea_calc_displen(x86_effaddr *x86_ea, unsigned int wordsize, int noreg, + int dispreq) +{ + /*@null@*/ /*@only@*/ yasm_intnum *num; + + x86_ea->valid_modrm = 0; /* default to not yet valid */ + + switch (x86_ea->ea.disp.size) { + case 0: + break; + /* If not 0, the displacement length was forced; set the Mod bits + * appropriately and we're done with the ModRM byte. + */ + case 8: + /* Byte is only a valid override if there are registers in the + * EA. With no registers, we must have a 16/32 value. + */ + if (noreg) { + yasm_warn_set(YASM_WARN_IMPLICIT_SIZE_OVERRIDE, + N_("invalid displacement size; fixed")); + x86_ea->ea.disp.size = wordsize; + } else + x86_ea->modrm |= 0100; + x86_ea->valid_modrm = 1; + return 0; + case 16: + case 32: + /* Don't allow changing displacement different from BITS setting + * directly; require an address-size override to change it. + */ + if (wordsize != x86_ea->ea.disp.size) { + yasm_error_set(YASM_ERROR_VALUE, + N_("invalid effective address (displacement size)")); + return 1; + } + if (!noreg) + x86_ea->modrm |= 0200; + x86_ea->valid_modrm = 1; + return 0; + default: + /* we shouldn't ever get any other size! */ + yasm_internal_error(N_("strange EA displacement size")); + } + + /* The displacement length hasn't been forced (or the forcing wasn't + * valid), try to determine what it is. + */ + if (noreg) { + /* No register in ModRM expression, so it must be disp16/32, + * and as the Mod bits are set to 0 by the caller, we're done + * with the ModRM byte. + */ + x86_ea->ea.disp.size = wordsize; + x86_ea->valid_modrm = 1; + return 0; + } + + if (dispreq) { + /* for BP/EBP, there *must* be a displacement value, but we + * may not know the size (8 or 16/32) for sure right now. + */ + x86_ea->ea.need_nonzero_len = 1; + } + + if (x86_ea->ea.disp.rel) { + /* Relative displacement; basically all object formats need non-byte + * for relocation here, so just do that. (TODO: handle this + * differently?) + */ + x86_ea->ea.disp.size = wordsize; + x86_ea->modrm |= 0200; + x86_ea->valid_modrm = 1; + return 0; + } + + /* At this point there's 3 possibilities for the displacement: + * - None (if =0) + * - signed 8 bit (if in -128 to 127 range) + * - 16/32 bit (word size) + * For now, check intnum value right now; if it's not 0, + * assume 8 bit and set up for allowing 16 bit later. + * FIXME: The complex expression equaling zero is probably a rare case, + * so we ignore it for now. + */ + num = yasm_value_get_intnum(&x86_ea->ea.disp, NULL, 0); + if (!num) { + /* Still has unknown values. */ + x86_ea->ea.need_nonzero_len = 1; + x86_ea->modrm |= 0100; + x86_ea->valid_modrm = 1; + return 0; + } + + /* Figure out what size displacement we will have. */ + if (yasm_intnum_is_zero(num) && !x86_ea->ea.need_nonzero_len) { + /* If we know that the displacement is 0 right now, + * go ahead and delete the expr and make it so no + * displacement value is included in the output. + * The Mod bits of ModRM are set to 0 above, and + * we're done with the ModRM byte! + */ + yasm_value_delete(&x86_ea->ea.disp); + x86_ea->ea.need_disp = 0; + } else if (yasm_intnum_in_range(num, -128, 127)) { + /* It fits into a signed byte */ + x86_ea->ea.disp.size = 8; + x86_ea->modrm |= 0100; + } else { + /* It's a 16/32-bit displacement */ + x86_ea->ea.disp.size = wordsize; + x86_ea->modrm |= 0200; + } + x86_ea->valid_modrm = 1; /* We're done with ModRM */ + + yasm_intnum_destroy(num); + return 0; +} +/*@=nullstate@*/ + +static int +x86_expr_checkea_getregsize_callback(yasm_expr__item *ei, void *d) +{ + unsigned char *addrsize = (unsigned char *)d; + + if (ei->type == YASM_EXPR_REG) { + switch ((x86_expritem_reg_size)(ei->data.reg & ~0xFUL)) { + case X86_REG16: + *addrsize = 16; + break; + case X86_REG32: + *addrsize = 32; + break; + case X86_REG64: + case X86_RIP: + *addrsize = 64; + break; + default: + return 0; + } + return 1; + } else + return 0; +} + +int +yasm_x86__expr_checkea(x86_effaddr *x86_ea, unsigned char *addrsize, + unsigned int bits, int address16_op, unsigned char *rex, + yasm_bytecode *bc) +{ + int retval; + + if (*addrsize == 0) { + /* we need to figure out the address size from what we know about: + * - the displacement length + * - what registers are used in the expression + * - the bits setting + */ + switch (x86_ea->ea.disp.size) { + case 16: + /* must be 16-bit */ + *addrsize = 16; + break; + case 64: + /* We have to support this for the MemOffs case, but it's + * otherwise illegal. It's also illegal in non-64-bit mode. + */ + if (x86_ea->need_modrm || x86_ea->need_sib) { + yasm_error_set(YASM_ERROR_VALUE, + N_("invalid effective address (displacement size)")); + return 1; + } + *addrsize = 64; + break; + case 32: + /* Must be 32-bit in 16-bit or 32-bit modes. In 64-bit mode, + * we don't know unless we look at the registers, except in the + * MemOffs case (see the end of this function). + */ + if (bits != 64 || (!x86_ea->need_modrm && !x86_ea->need_sib)) { + *addrsize = 32; + break; + } + /*@fallthrough@*/ + default: + /* If SIB is required, but we're in 16-bit mode, set to 32. */ + if (bits == 16 && x86_ea->need_sib == 1) { + *addrsize = 32; + break; + } + /* check for use of 16 or 32-bit registers; if none are used + * default to bits setting. + */ + if (!x86_ea->ea.disp.abs || + !yasm_expr__traverse_leaves_in(x86_ea->ea.disp.abs, + addrsize, x86_expr_checkea_getregsize_callback)) + *addrsize = bits; + /* TODO: Add optional warning here if switched address size + * from bits setting just by register use.. eg [ax] in + * 32-bit mode would generate a warning. + */ + } + } + + if ((*addrsize == 32 || *addrsize == 64) && + ((x86_ea->need_modrm && !x86_ea->valid_modrm) || + (x86_ea->need_sib && !x86_ea->valid_sib))) { + int i; + unsigned char low3; + enum { + REG3264_NONE = -1, + REG3264_EAX = 0, + REG3264_ECX, + REG3264_EDX, + REG3264_EBX, + REG3264_ESP, + REG3264_EBP, + REG3264_ESI, + REG3264_EDI, + REG64_R8, + REG64_R9, + REG64_R10, + REG64_R11, + REG64_R12, + REG64_R13, + REG64_R14, + REG64_R15, + REG64_RIP, + SIMDREGS + }; + int reg3264mult[33] = + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + x86_checkea_reg3264_data reg3264_data; + int basereg = REG3264_NONE; /* "base" register (for SIB) */ + int indexreg = REG3264_NONE; /* "index" register (for SIB) */ + int regcount = 17; /* normally don't check SIMD regs */ + + if (x86_ea->vsib_mode != 0) + regcount = 33; + + /* We can only do 64-bit addresses in 64-bit mode. */ + if (*addrsize == 64 && bits != 64) { + yasm_error_set(YASM_ERROR_TYPE, + N_("invalid effective address (64-bit in non-64-bit mode)")); + return 1; + } + + if (x86_ea->ea.pc_rel && bits != 64) { + yasm_warn_set(YASM_WARN_GENERAL, + N_("RIP-relative directive ignored in non-64-bit mode")); + x86_ea->ea.pc_rel = 0; + } + + reg3264_data.regs = reg3264mult; + reg3264_data.vsib_mode = x86_ea->vsib_mode; + reg3264_data.bits = bits; + reg3264_data.addrsize = *addrsize; + if (x86_ea->ea.disp.abs) { + int pcrel = 0; + switch (x86_expr_checkea_getregusage + (&x86_ea->ea.disp.abs, &indexreg, &pcrel, bits, + ®3264_data, x86_expr_checkea_get_reg3264)) { + case 1: + yasm_error_set(YASM_ERROR_VALUE, + N_("invalid effective address")); + return 1; + case 2: + if (pcrel) + yasm_value_set_curpos_rel(&x86_ea->ea.disp, bc, 1); + return 2; + default: + if (pcrel) + yasm_value_set_curpos_rel(&x86_ea->ea.disp, bc, 1); + break; + } + } + + /* If indexreg mult is 0, discard it. + * This is possible because of the way indexreg is found in + * expr_checkea_getregusage(). + */ + if (indexreg != REG3264_NONE && reg3264mult[indexreg] == 0) + indexreg = REG3264_NONE; + + /* Find a basereg (*1, but not indexreg), if there is one. + * Also, if an indexreg hasn't been assigned, try to find one. + * Meanwhile, check to make sure there's no negative register mults. + */ + for (i=0; i<regcount; i++) { + if (reg3264mult[i] < 0) { + yasm_error_set(YASM_ERROR_VALUE, + N_("invalid effective address")); + return 1; + } + if (i != indexreg && reg3264mult[i] == 1 && + basereg == REG3264_NONE) + basereg = i; + else if (indexreg == REG3264_NONE && reg3264mult[i] > 0) + indexreg = i; + } + + if (x86_ea->vsib_mode != 0) { + /* For VSIB, the SIMD register needs to go into the indexreg. + * Also check basereg (must be a GPR if present) and indexreg + * (must be a SIMD register). + */ + if (basereg >= SIMDREGS && + (indexreg == REG3264_NONE || reg3264mult[indexreg] == 1)) { + int temp = basereg; + basereg = indexreg; + indexreg = temp; + } + if (basereg >= REG64_RIP || indexreg < SIMDREGS) { + yasm_error_set(YASM_ERROR_VALUE, + N_("invalid effective address")); + return 1; + } + } else if (indexreg != REG3264_NONE && basereg == REG3264_NONE) + /* Handle certain special cases of indexreg mults when basereg is + * empty. + */ + switch (reg3264mult[indexreg]) { + case 1: + /* Only optimize this way if nosplit wasn't specified */ + if (!x86_ea->ea.nosplit) { + basereg = indexreg; + indexreg = -1; + } + break; + case 2: + /* Only split if nosplit wasn't specified */ + if (!x86_ea->ea.nosplit) { + basereg = indexreg; + reg3264mult[indexreg] = 1; + } + break; + case 3: + case 5: + case 9: + basereg = indexreg; + reg3264mult[indexreg]--; + break; + } + + /* Make sure there's no other registers than the basereg and indexreg + * we just found. + */ + for (i=0; i<regcount; i++) + if (i != basereg && i != indexreg && reg3264mult[i] != 0) { + yasm_error_set(YASM_ERROR_VALUE, + N_("invalid effective address")); + return 1; + } + + /* Check the index multiplier value for validity if present. */ + if (indexreg != REG3264_NONE && reg3264mult[indexreg] != 1 && + reg3264mult[indexreg] != 2 && reg3264mult[indexreg] != 4 && + reg3264mult[indexreg] != 8) { + yasm_error_set(YASM_ERROR_VALUE, N_("invalid effective address")); + return 1; + } + + /* ESP is not a legal indexreg. */ + if (indexreg == REG3264_ESP) { + /* If mult>1 or basereg is ESP also, there's no way to make it + * legal. + */ + if (reg3264mult[REG3264_ESP] > 1 || basereg == REG3264_ESP) { + yasm_error_set(YASM_ERROR_VALUE, + N_("invalid effective address")); + return 1; + } + /* If mult==1 and basereg is not ESP, swap indexreg w/basereg. */ + indexreg = basereg; + basereg = REG3264_ESP; + } + + /* RIP is only legal if it's the ONLY register used. */ + if (indexreg == REG64_RIP || + (basereg == REG64_RIP && indexreg != REG3264_NONE)) { + yasm_error_set(YASM_ERROR_VALUE, N_("invalid effective address")); + return 1; + } + + /* At this point, we know the base and index registers and that the + * memory expression is (essentially) valid. Now build the ModRM and + * (optional) SIB bytes. + */ + + /* If we're supposed to be RIP-relative and there's no register + * usage, change to RIP-relative. + */ + if (basereg == REG3264_NONE && indexreg == REG3264_NONE && + x86_ea->ea.pc_rel) { + basereg = REG64_RIP; + yasm_value_set_curpos_rel(&x86_ea->ea.disp, bc, 1); + } + + /* First determine R/M (Mod is later determined from disp size) */ + x86_ea->need_modrm = 1; /* we always need ModRM */ + if (basereg == REG3264_NONE && indexreg == REG3264_NONE) { + /* Just a disp32: in 64-bit mode the RM encoding is used for RIP + * offset addressing, so we need to use the SIB form instead. + */ + if (bits == 64) { + x86_ea->modrm |= 4; + x86_ea->need_sib = 1; + } else { + x86_ea->modrm |= 5; + x86_ea->sib = 0; + x86_ea->valid_sib = 0; + x86_ea->need_sib = 0; + } + } else if (basereg == REG64_RIP) { + x86_ea->modrm |= 5; + x86_ea->sib = 0; + x86_ea->valid_sib = 0; + x86_ea->need_sib = 0; + /* RIP always requires a 32-bit displacement */ + x86_ea->valid_modrm = 1; + x86_ea->ea.disp.size = 32; + return 0; + } else if (indexreg == REG3264_NONE) { + /* basereg only */ + /* Don't need to go to the full effort of determining what type + * of register basereg is, as x86_set_rex_from_reg doesn't pay + * much attention. + */ + if (yasm_x86__set_rex_from_reg(rex, &low3, + (unsigned int)(X86_REG64 | basereg), + bits, X86_REX_B)) + return 1; + x86_ea->modrm |= low3; + /* we don't need an SIB *unless* basereg is ESP or R12 */ + if (basereg == REG3264_ESP || basereg == REG64_R12) + x86_ea->need_sib = 1; + else { + x86_ea->sib = 0; + x86_ea->valid_sib = 0; + x86_ea->need_sib = 0; + } + } else { + /* index or both base and index */ + x86_ea->modrm |= 4; + x86_ea->need_sib = 1; + } + + /* Determine SIB if needed */ + if (x86_ea->need_sib == 1) { + x86_ea->sib = 0; /* start with 0 */ + + /* Special case: no basereg */ + if (basereg == REG3264_NONE) + x86_ea->sib |= 5; + else { + if (yasm_x86__set_rex_from_reg(rex, &low3, (unsigned int) + (X86_REG64 | basereg), bits, + X86_REX_B)) + return 1; + x86_ea->sib |= low3; + } + + /* Put in indexreg, checking for none case */ + if (indexreg == REG3264_NONE) + x86_ea->sib |= 040; + /* Any scale field is valid, just leave at 0. */ + else { + if (indexreg >= SIMDREGS) { + if (yasm_x86__set_rex_from_reg(rex, &low3, + (unsigned int)(X86_XMMREG | (indexreg-SIMDREGS)), + bits, X86_REX_X)) + return 1; + } else { + if (yasm_x86__set_rex_from_reg(rex, &low3, + (unsigned int)(X86_REG64 | indexreg), + bits, X86_REX_X)) + return 1; + } + x86_ea->sib |= low3 << 3; + /* Set scale field, 1 case -> 0, so don't bother. */ + switch (reg3264mult[indexreg]) { + case 2: + x86_ea->sib |= 0100; + break; + case 4: + x86_ea->sib |= 0200; + break; + case 8: + x86_ea->sib |= 0300; + break; + } + } + + x86_ea->valid_sib = 1; /* Done with SIB */ + } + + /* Calculate displacement length (if possible) */ + retval = x86_checkea_calc_displen + (x86_ea, 32, basereg == REG3264_NONE, + basereg == REG3264_EBP || basereg == REG64_R13); + return retval; + } else if (*addrsize == 16 && x86_ea->need_modrm && !x86_ea->valid_modrm) { + static const unsigned char modrm16[16] = { + 0006 /* disp16 */, 0007 /* [BX] */, 0004 /* [SI] */, + 0000 /* [BX+SI] */, 0005 /* [DI] */, 0001 /* [BX+DI] */, + 0377 /* invalid */, 0377 /* invalid */, 0006 /* [BP]+d */, + 0377 /* invalid */, 0002 /* [BP+SI] */, 0377 /* invalid */, + 0003 /* [BP+DI] */, 0377 /* invalid */, 0377 /* invalid */, + 0377 /* invalid */ + }; + x86_checkea_reg16_data reg16mult = {0, 0, 0, 0}; + enum { + HAVE_NONE = 0, + HAVE_BX = 1<<0, + HAVE_SI = 1<<1, + HAVE_DI = 1<<2, + HAVE_BP = 1<<3 + } havereg = HAVE_NONE; + + /* 64-bit mode does not allow 16-bit addresses */ + if (bits == 64 && !address16_op) { + yasm_error_set(YASM_ERROR_TYPE, + N_("16-bit addresses not supported in 64-bit mode")); + return 1; + } + + /* 16-bit cannot have SIB */ + x86_ea->sib = 0; + x86_ea->valid_sib = 0; + x86_ea->need_sib = 0; + + if (x86_ea->ea.disp.abs) { + int pcrel = 0; + switch (x86_expr_checkea_getregusage + (&x86_ea->ea.disp.abs, (int *)NULL, &pcrel, bits, + ®16mult, x86_expr_checkea_get_reg16)) { + case 1: + yasm_error_set(YASM_ERROR_VALUE, + N_("invalid effective address")); + return 1; + case 2: + if (pcrel) + yasm_value_set_curpos_rel(&x86_ea->ea.disp, bc, 1); + return 2; + default: + if (pcrel) + yasm_value_set_curpos_rel(&x86_ea->ea.disp, bc, 1); + break; + } + } + + /* reg multipliers not 0 or 1 are illegal. */ + if (reg16mult.bx & ~1 || reg16mult.si & ~1 || reg16mult.di & ~1 || + reg16mult.bp & ~1) { + yasm_error_set(YASM_ERROR_VALUE, N_("invalid effective address")); + return 1; + } + + /* Set havereg appropriately */ + if (reg16mult.bx > 0) + havereg |= HAVE_BX; + if (reg16mult.si > 0) + havereg |= HAVE_SI; + if (reg16mult.di > 0) + havereg |= HAVE_DI; + if (reg16mult.bp > 0) + havereg |= HAVE_BP; + + /* Check the modrm value for invalid combinations. */ + if (modrm16[havereg] & 0070) { + yasm_error_set(YASM_ERROR_VALUE, N_("invalid effective address")); + return 1; + } + + /* Set ModRM byte for registers */ + x86_ea->modrm |= modrm16[havereg]; + + /* Calculate displacement length (if possible) */ + retval = x86_checkea_calc_displen + (x86_ea, 16, havereg == HAVE_NONE, havereg == HAVE_BP); + return retval; + } else if (!x86_ea->need_modrm && !x86_ea->need_sib) { + /* Special case for MOV MemOffs opcode: displacement but no modrm. */ + switch (*addrsize) { + case 64: + if (bits != 64) { + yasm_error_set(YASM_ERROR_TYPE, + N_("invalid effective address (64-bit in non-64-bit mode)")); + return 1; + } + x86_ea->ea.disp.size = 64; + break; + case 32: + x86_ea->ea.disp.size = 32; + break; + case 16: + /* 64-bit mode does not allow 16-bit addresses */ + if (bits == 64 && !address16_op) { + yasm_error_set(YASM_ERROR_TYPE, + N_("16-bit addresses not supported in 64-bit mode")); + return 1; + } + x86_ea->ea.disp.size = 16; + break; + } + } + return 0; +} + +int +yasm_x86__floatnum_tobytes(yasm_arch *arch, const yasm_floatnum *flt, + unsigned char *buf, size_t destsize, size_t valsize, + size_t shift, int warn) +{ + if (!yasm_floatnum_check_size(flt, valsize)) { + yasm_error_set(YASM_ERROR_FLOATING_POINT, + N_("invalid floating point constant size")); + return 1; + } + + yasm_floatnum_get_sized(flt, buf, destsize, valsize, shift, 0, warn); + return 0; +} diff --git a/contrib/tools/yasm/modules/arch/x86/x86id.c b/contrib/tools/yasm/modules/arch/x86/x86id.c new file mode 100644 index 0000000000..6207c2062c --- /dev/null +++ b/contrib/tools/yasm/modules/arch/x86/x86id.c @@ -0,0 +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); +} + diff --git a/contrib/tools/yasm/modules/dbgfmts/codeview/cv-dbgfmt.c b/contrib/tools/yasm/modules/dbgfmts/codeview/cv-dbgfmt.c new file mode 100644 index 0000000000..9b06fe3495 --- /dev/null +++ b/contrib/tools/yasm/modules/dbgfmts/codeview/cv-dbgfmt.c @@ -0,0 +1,107 @@ +/* + * CodeView debugging formats implementation for Yasm + * + * Copyright (C) 2006-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 "cv-dbgfmt.h" + +yasm_dbgfmt_module yasm_cv8_LTX_dbgfmt; + + +static /*@null@*/ /*@only@*/ yasm_dbgfmt * +cv_dbgfmt_create(yasm_object *object, yasm_dbgfmt_module *module, int version) +{ + yasm_dbgfmt_cv *dbgfmt_cv = yasm_xmalloc(sizeof(yasm_dbgfmt_cv)); + size_t i; + + dbgfmt_cv->dbgfmt.module = module; + + dbgfmt_cv->filenames_allocated = 32; + dbgfmt_cv->filenames_size = 0; + dbgfmt_cv->filenames = + yasm_xmalloc(sizeof(cv_filename)*dbgfmt_cv->filenames_allocated); + for (i=0; i<dbgfmt_cv->filenames_allocated; i++) { + dbgfmt_cv->filenames[i].pathname = NULL; + dbgfmt_cv->filenames[i].filename = NULL; + dbgfmt_cv->filenames[i].str_off = 0; + dbgfmt_cv->filenames[i].info_off = 0; + } + + dbgfmt_cv->version = version; + + return (yasm_dbgfmt *)dbgfmt_cv; +} + +static /*@null@*/ /*@only@*/ yasm_dbgfmt * +cv8_dbgfmt_create(yasm_object *object) +{ + return cv_dbgfmt_create(object, &yasm_cv8_LTX_dbgfmt, 8); +} + +static void +cv_dbgfmt_destroy(/*@only@*/ yasm_dbgfmt *dbgfmt) +{ + yasm_dbgfmt_cv *dbgfmt_cv = (yasm_dbgfmt_cv *)dbgfmt; + size_t i; + for (i=0; i<dbgfmt_cv->filenames_size; i++) { + if (dbgfmt_cv->filenames[i].pathname) + yasm_xfree(dbgfmt_cv->filenames[i].pathname); + } + yasm_xfree(dbgfmt_cv->filenames); + yasm_xfree(dbgfmt); +} + +/* Add a bytecode to a section, updating offset on insertion; + * no optimization necessary. + */ +yasm_bytecode * +yasm_cv__append_bc(yasm_section *sect, yasm_bytecode *bc) +{ + yasm_bytecode *precbc = yasm_section_bcs_last(sect); + bc->offset = yasm_bc_next_offset(precbc); + yasm_section_bcs_append(sect, bc); + return precbc; +} + +static void +cv_dbgfmt_generate(yasm_object *object, yasm_linemap *linemap, + yasm_errwarns *errwarns) +{ + yasm_cv__generate_symline(object, linemap, errwarns); + yasm_cv__generate_type(object); +} + +/* Define dbgfmt structure -- see dbgfmt.h for details */ +yasm_dbgfmt_module yasm_cv8_LTX_dbgfmt = { + "CodeView debugging format for VC8", + "cv8", + NULL, /* no directives */ + cv8_dbgfmt_create, + cv_dbgfmt_destroy, + cv_dbgfmt_generate +}; diff --git a/contrib/tools/yasm/modules/dbgfmts/codeview/cv-dbgfmt.h b/contrib/tools/yasm/modules/dbgfmts/codeview/cv-dbgfmt.h new file mode 100644 index 0000000000..134b0b885b --- /dev/null +++ b/contrib/tools/yasm/modules/dbgfmts/codeview/cv-dbgfmt.h @@ -0,0 +1,58 @@ +/* + * CodeView debugging formats implementation for Yasm + * + * Copyright (C) 2006-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_CV_DBGFMT_H +#define YASM_CV_DBGFMT_H + +typedef struct { + char *pathname; /* full pathname (drive+basepath+filename) */ + char *filename; /* filename as yasm knows it internally */ + unsigned long str_off; /* offset into pathname string table */ + unsigned long info_off; /* offset into source info table */ + unsigned char digest[16]; /* MD5 digest of source file */ +} cv_filename; + +/* Global data */ +typedef struct yasm_dbgfmt_cv { + yasm_dbgfmt_base dbgfmt; /* base structure */ + + cv_filename *filenames; + size_t filenames_size; + size_t filenames_allocated; + + int version; +} yasm_dbgfmt_cv; + +yasm_bytecode *yasm_cv__append_bc(yasm_section *sect, yasm_bytecode *bc); + +/* Symbol/Line number functions */ +yasm_section *yasm_cv__generate_symline + (yasm_object *object, yasm_linemap *linemap, yasm_errwarns *errwarns); + +/* Type functions */ +yasm_section *yasm_cv__generate_type(yasm_object *object); + +#endif diff --git a/contrib/tools/yasm/modules/dbgfmts/codeview/cv-symline.c b/contrib/tools/yasm/modules/dbgfmts/codeview/cv-symline.c new file mode 100644 index 0000000000..8d7030221f --- /dev/null +++ b/contrib/tools/yasm/modules/dbgfmts/codeview/cv-symline.c @@ -0,0 +1,1102 @@ +/* + * CodeView debugging format - symbol and line information + * + * Copyright (C) 2006-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. + * 3. Neither the name of the author nor the names of other contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 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 "cv-dbgfmt.h" + +enum cv8_symheadtype { + CV8_DEBUG_SYMS = 0xF1, /* CV5 symbol information */ + CV8_LINE_NUMS = 0xF2, /* line numbers for a section */ + CV8_FILE_STRTAB = 0xF3, /* filename string table */ + CV8_FILE_INFO = 0xF4 /* source file info */ +}; + +enum cv_symtype { + /* Non-modal Symbols */ + CV_S_COMPILE = 0x0001, /* Compile Flag */ + CV_S_REGISTER = 0x0002, /* Register */ + CV_S_CONSTANT = 0x0003, /* Constant */ + CV_S_UDT = 0x0004, /* User-defined Type */ + CV_S_SSEARCH = 0x0005, /* Start Search */ + CV_S_END = 0x0006, /* End of Block */ + CV_S_SKIP = 0x0007, /* Skip Record */ + CV_S_OBJNAME = 0x0009, /* Object File Name */ + CV_S_ENDARG = 0x000a, /* End of Arguments */ + CV_S_COBOLUDT = 0x000b, /* COBOL User-defined Type */ + CV_S_MANYREG = 0x000c, /* Many Registers */ + CV_S_RETURN = 0x000d, /* Function Return */ + CV_S_ENTRYTHIS = 0x000e, /* "this" at Method Entry */ + + /* Symbols for 16:16 Segmented Architectures */ + CV_S_BPREL16 = 0x0100, /* BP Relative 16:16 */ + CV_S_LDATA16 = 0x0101, /* Local Data 16:16 */ + CV_S_GDATA16 = 0x0102, /* Global Data Symbol 16:16 */ + CV_S_PUB16 = 0x0103, /* Public Symbol 16:16 */ + CV_S_LPROC16 = 0x0104, /* Local Start 16:16 */ + CV_S_GPROC16 = 0x0105, /* Global Start 16:16 */ + CV_S_THUNK16 = 0x0106, /* Thunk Start 16:16 */ + CV_S_BLOCK16 = 0x0107, /* Block Start 16:16 */ + CV_S_WITH16 = 0x0108, /* With Start 16:16 */ + CV_S_LABEL16 = 0x0109, /* Code Label 16:16 */ + CV_S_CEXMODEL16 = 0x0110, /* Change Execution Model 16:16 */ + CV_S_VFTPATH16 = 0x010b, /* Virtual Function Table Path 16:16 */ + CV_S_REGREL16 = 0x010c, /* Register Relative 16:16 */ + + /* Symbols for 16:32 Segmented Architectures */ + CV_S_BPREL32 = 0x0200, /* BP Relative 16:32 */ + CV_S_LDATA32 = 0x0201, /* Local Data 16:32 */ + CV_S_GDATA32 = 0x0202, /* Global Data Symbol 16:32 */ + CV_S_PUB32 = 0x0203, /* Public Symbol 16:32 */ + CV_S_LPROC32 = 0x0204, /* Local Start 16:32 */ + CV_S_GPROC32 = 0x0205, /* Global Start 16:32 */ + CV_S_THUNK32 = 0x0206, /* Thunk Start 16:32 */ + CV_S_BLOCK32 = 0x0207, /* Block Start 16:32 */ + CV_S_WITH32 = 0x0208, /* With Start 16:32 */ + CV_S_LABEL32 = 0x0209, /* Code Label 16:32 */ + CV_S_CEXMODEL32 = 0x0210, /* Change Execution Model 16:32 */ + CV_S_VFTPATH32 = 0x020b, /* Virtual Function Table Path 16:32 */ + CV_S_REGREL32 = 0x020c, /* Register Relative 16:32 */ + CV_S_LTHREAD32 = 0x020d, /* Local Thread Storage 16:32 */ + CV_S_GTHREAD32 = 0x020e, /* Global Thread Storage 16:32 */ + + /* Symbols for MIPS */ + CV_S_LPROCMIPS = 0x0300, /* Local procedure start MIPS */ + CV_S_GPROCMIPS = 0x0301, /* Global procedure start MIPS */ + + /* Symbols for CV8 - strings are 0 terminated rather than length-prefix. + * Incomplete and unofficial. + */ + CV8_S_OBJNAME = 0x1101, /* Object File Name */ + CV8_S_LABEL32 = 0x1105, /* Code Label 16:32 */ + CV8_S_LDATA32 = 0x110c, /* Local Data 16:32 */ + CV8_S_GDATA32 = 0x110d, /* Global Data 16:32 */ + CV8_S_LPROC32 = 0x1110, /* Local Start 16:32 */ + CV8_S_COMPILE = 0x1116 /* Compile Flag */ +}; + +typedef struct cv8_symhead { + enum cv8_symheadtype type; + yasm_bytecode *start_prevbc; + yasm_bytecode *end_prevbc; + int first; /* nonzero if first symhead in section */ +} cv8_symhead; + +typedef struct cv8_fileinfo { + const cv_filename *fn; +} cv8_fileinfo; + +/* Note: each line number group is associated with a file AND a section */ +typedef struct cv8_linepair { + unsigned long offset; + unsigned long line; +} cv8_linepair; + +/* Decrease linked list overhead a bit doing it this way */ +typedef struct cv8_lineset { + STAILQ_ENTRY(cv8_lineset) link; + cv8_linepair pairs[126]; + size_t num_pairs; +} cv8_lineset; + +/* Note: Due to line number sorting requirements (by section offset it seems) + * one file may need more than one record per section. */ +typedef struct cv8_lineinfo { + STAILQ_ENTRY(cv8_lineinfo) link; + const cv_filename *fn; /* filename associated with line numbers */ + yasm_section *sect; /* section line numbers are for */ + yasm_symrec *sectsym; /* symbol for beginning of sect */ + unsigned long num_linenums; + int first_in_sect; /* First lineinfo for this section. */ + STAILQ_HEAD(cv8_lineset_head, cv8_lineset) linesets; +} cv8_lineinfo; + +/* Symbols use a bit of meta-programming to encode formats: each character + * of format represents the output generated, as follows: + * 'b' : 1 byte value (integer) + * 'h' : 2 byte value (integer) + * 'w' : 4 byte value (integer) + * 'Y' : symrec SECREL+SECTION (pointer) + * 'T' : type index (integer) + * 'S' : length-prefixed string (pointer) + * 'Z' : 0-terminated string (pointer) + */ +typedef struct cv_sym { + enum cv_symtype type; + const char *format; + union { + unsigned long i; + void *p; + } args[10]; +} cv_sym; + +/* Bytecode callback function prototypes */ +static void cv8_symhead_bc_destroy(void *contents); +static void cv8_symhead_bc_print(const void *contents, FILE *f, + int indent_level); +static int cv8_symhead_bc_calc_len + (yasm_bytecode *bc, yasm_bc_add_span_func add_span, void *add_span_data); +static int cv8_symhead_bc_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 cv8_fileinfo_bc_destroy(void *contents); +static void cv8_fileinfo_bc_print(const void *contents, FILE *f, + int indent_level); +static int cv8_fileinfo_bc_calc_len + (yasm_bytecode *bc, yasm_bc_add_span_func add_span, void *add_span_data); +static int cv8_fileinfo_bc_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 cv8_lineinfo_bc_destroy(void *contents); +static void cv8_lineinfo_bc_print(const void *contents, FILE *f, + int indent_level); +static int cv8_lineinfo_bc_calc_len + (yasm_bytecode *bc, yasm_bc_add_span_func add_span, void *add_span_data); +static int cv8_lineinfo_bc_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 cv_sym_bc_destroy(void *contents); +static void cv_sym_bc_print(const void *contents, FILE *f, int indent_level); +static int cv_sym_bc_calc_len + (yasm_bytecode *bc, yasm_bc_add_span_func add_span, void *add_span_data); +static int cv_sym_bc_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 cv8_symhead_bc_callback = { + cv8_symhead_bc_destroy, + cv8_symhead_bc_print, + yasm_bc_finalize_common, + NULL, + cv8_symhead_bc_calc_len, + yasm_bc_expand_common, + cv8_symhead_bc_tobytes, + 0 +}; + +static const yasm_bytecode_callback cv8_fileinfo_bc_callback = { + cv8_fileinfo_bc_destroy, + cv8_fileinfo_bc_print, + yasm_bc_finalize_common, + NULL, + cv8_fileinfo_bc_calc_len, + yasm_bc_expand_common, + cv8_fileinfo_bc_tobytes, + 0 +}; + +static const yasm_bytecode_callback cv8_lineinfo_bc_callback = { + cv8_lineinfo_bc_destroy, + cv8_lineinfo_bc_print, + yasm_bc_finalize_common, + NULL, + cv8_lineinfo_bc_calc_len, + yasm_bc_expand_common, + cv8_lineinfo_bc_tobytes, + 0 +}; + +static const yasm_bytecode_callback cv_sym_bc_callback = { + cv_sym_bc_destroy, + cv_sym_bc_print, + yasm_bc_finalize_common, + NULL, + cv_sym_bc_calc_len, + yasm_bc_expand_common, + cv_sym_bc_tobytes, + 0 +}; + +static cv8_symhead *cv8_add_symhead(yasm_section *sect, unsigned long type, + int first); +static void cv8_set_symhead_end(cv8_symhead *head, yasm_bytecode *end_prevbc); + +static yasm_bytecode *cv8_add_fileinfo + (yasm_section *sect, const cv_filename *fn); + +static unsigned long cv_sym_size(const cv_sym *cvs); + + +static cv_sym * +cv8_add_sym_objname(yasm_section *sect, /*@keep@*/ char *objname) +{ + yasm_bytecode *bc; + cv_sym *cvs = yasm_xmalloc(sizeof(cv_sym)); + cvs->type = CV8_S_OBJNAME; + cvs->format = "wZ"; + cvs->args[0].i = 0; /* signature (0=asm) */ + cvs->args[1].p = objname; /* object filename */ + + bc = yasm_bc_create_common(&cv_sym_bc_callback, cvs, 0); + bc->len = cv_sym_size(cvs); + yasm_cv__append_bc(sect, bc); + return cvs; +} + +static cv_sym * +cv8_add_sym_compile(yasm_object *object, yasm_section *sect, + /*@keep@*/ char *creator) +{ + yasm_bytecode *bc; + cv_sym *cvs = yasm_xmalloc(sizeof(cv_sym)); + cvs->type = CV8_S_COMPILE; + cvs->format = "wwwwZh"; + cvs->args[0].i = 3; /* language (3=Masm) */ + + /* target processor; 0xD0 = AMD64 */ + if (strcmp(yasm_arch_keyword(object->arch), "x86") == 0) { + if (strcmp(yasm_arch_get_machine(object->arch), "amd64") == 0) + cvs->args[1].i = 0xD0; + else + cvs->args[1].i = 0x6; /* 686, FIXME */ + } else + cvs->args[1].i = 0; /* XXX: unknown */ + + cvs->args[2].i = 0; /* flags (assume 0 for now) */ + cvs->args[3].i = 0; /* creator version number (assume 0 for now) */ + cvs->args[4].p = creator; /* creator string */ + cvs->args[5].i = 0; /* no pairs of key/value */ + + bc = yasm_bc_create_common(&cv_sym_bc_callback, cvs, 0); + bc->len = cv_sym_size(cvs); + yasm_cv__append_bc(sect, bc); + return cvs; +} + +static cv_sym * +cv8_add_sym_label(yasm_section *sect, yasm_symrec *sym) +{ + yasm_bytecode *bc; + cv_sym *cvs = yasm_xmalloc(sizeof(cv_sym)); + cvs->type = CV8_S_LABEL32; + cvs->format = "YbZ"; + cvs->args[0].p = sym; /* symrec for label */ + cvs->args[1].i = 0; /* flags (assume 0 for now) */ + cvs->args[2].p = yasm__xstrdup(yasm_symrec_get_name(sym)); + + bc = yasm_bc_create_common(&cv_sym_bc_callback, cvs, 0); + bc->len = cv_sym_size(cvs); + yasm_cv__append_bc(sect, bc); + return cvs; +} + +static cv_sym * +cv8_add_sym_data(yasm_section *sect, unsigned long type, yasm_symrec *sym, + int is_global) +{ + yasm_bytecode *bc; + cv_sym *cvs = yasm_xmalloc(sizeof(cv_sym)); + cvs->type = is_global ? CV8_S_GDATA32 : CV8_S_LDATA32; + cvs->format = "wYZ"; + cvs->args[0].i = type; /* type index */ + cvs->args[1].p = sym; /* symrec for label */ + cvs->args[2].p = yasm__xstrdup(yasm_symrec_get_name(sym)); + + bc = yasm_bc_create_common(&cv_sym_bc_callback, cvs, 0); + bc->len = cv_sym_size(cvs); + yasm_cv__append_bc(sect, bc); + return cvs; +} + +static size_t +cv_dbgfmt_add_file(yasm_dbgfmt_cv *dbgfmt_cv, size_t filenum, + const char *filename) +{ + char *pathname; + size_t i; + yasm_md5_context context; + FILE *f; + unsigned char *buf; + size_t len; + + /* Put the filename into the filename table */ + if (filenum == 0) { + /* Look to see if we already have that filename in the table */ + for (; filenum<dbgfmt_cv->filenames_size; filenum++) { + if (!dbgfmt_cv->filenames[filenum].filename || + strcmp(dbgfmt_cv->filenames[filenum].filename, filename) == 0) + break; + } + } else + filenum--; /* array index is 0-based */ + + /* Realloc table if necessary */ + if (filenum >= dbgfmt_cv->filenames_allocated) { + size_t old_allocated = dbgfmt_cv->filenames_allocated; + dbgfmt_cv->filenames_allocated = filenum+32; + dbgfmt_cv->filenames = yasm_xrealloc(dbgfmt_cv->filenames, + sizeof(cv_filename)*dbgfmt_cv->filenames_allocated); + for (i=old_allocated; i<dbgfmt_cv->filenames_allocated; i++) { + dbgfmt_cv->filenames[i].pathname = NULL; + dbgfmt_cv->filenames[i].filename = NULL; + dbgfmt_cv->filenames[i].str_off = 0; + dbgfmt_cv->filenames[i].info_off = 0; + } + } + + /* Calculate MD5 checksum of file */ + buf = yasm_xmalloc(1024); + yasm_md5_init(&context); + f = fopen(filename, "rb"); + if (!f) + yasm__fatal(N_("codeview: could not open source file")); + while ((len = fread(buf, 1, 1024, f)) > 0) + yasm_md5_update(&context, buf, (unsigned long)len); + yasm_md5_final(dbgfmt_cv->filenames[filenum].digest, &context); + fclose(f); + yasm_xfree(buf); + + /* Actually save in table */ + if (dbgfmt_cv->filenames[filenum].pathname) + yasm_xfree(dbgfmt_cv->filenames[filenum].pathname); + if (dbgfmt_cv->filenames[filenum].filename) + yasm_xfree(dbgfmt_cv->filenames[filenum].filename); + + pathname = yasm__abspath(filename); + dbgfmt_cv->filenames[filenum].pathname = pathname; + dbgfmt_cv->filenames[filenum].filename = yasm__xstrdup(filename); + + /* Update table size */ + if (filenum >= dbgfmt_cv->filenames_size) + dbgfmt_cv->filenames_size = filenum + 1; + + return filenum; +} + +static yasm_bytecode * +cv_append_str(yasm_section *sect, const char *str) +{ + yasm_datavalhead dvs; + yasm_bytecode *bc; + + yasm_dvs_initialize(&dvs); + yasm_dvs_append(&dvs, yasm_dv_create_string(yasm__xstrdup(str), + strlen(str))); + bc = yasm_bc_create_data(&dvs, 1, 1, NULL, 0); + yasm_bc_finalize(bc, yasm_cv__append_bc(sect, bc)); + yasm_bc_calc_len(bc, NULL, NULL); + return bc; +} + +typedef struct cv_line_info { + yasm_section *debug_symline; + yasm_object *object; + yasm_dbgfmt_cv *dbgfmt_cv; + yasm_linemap *linemap; + yasm_errwarns *errwarns; + unsigned int num_lineinfos; + STAILQ_HEAD(cv8_lineinfo_head, cv8_lineinfo) cv8_lineinfos; + /*@null@*/ cv8_lineinfo *cv8_cur_li; + /*@null@*/ cv8_lineset *cv8_cur_ls; +} cv_line_info; + +static int +cv_generate_line_bc(yasm_bytecode *bc, /*@null@*/ void *d) +{ + cv_line_info *info = (cv_line_info *)d; + yasm_dbgfmt_cv *dbgfmt_cv = info->dbgfmt_cv; + size_t i; + const char *filename; + unsigned long line; + /*@null@*/ yasm_bytecode *nextbc = yasm_bc__next(bc); + yasm_section *sect = yasm_bc_get_section(bc); + + if (nextbc && bc->offset == nextbc->offset) + return 0; + + yasm_linemap_lookup(info->linemap, bc->line, &filename, &line); + + if (!info->cv8_cur_li + || strcmp(filename, info->cv8_cur_li->fn->filename) != 0) { + yasm_bytecode *sectbc; + char symname[8]; + int first_in_sect = !info->cv8_cur_li; + + /* Find file */ + for (i=0; i<dbgfmt_cv->filenames_size; i++) { + if (strcmp(filename, dbgfmt_cv->filenames[i].filename) == 0) + break; + } + if (i >= dbgfmt_cv->filenames_size) + yasm_internal_error(N_("could not find filename in table")); + + /* and create new lineinfo structure */ + info->cv8_cur_li = yasm_xmalloc(sizeof(cv8_lineinfo)); + info->cv8_cur_li->fn = &dbgfmt_cv->filenames[i]; + info->cv8_cur_li->sect = sect; + info->cv8_cur_li->first_in_sect = first_in_sect; + sectbc = yasm_section_bcs_first(sect); + if (sectbc->symrecs && sectbc->symrecs[0]) + info->cv8_cur_li->sectsym = sectbc->symrecs[0]; + else { + sprintf(symname, ".%06u", info->num_lineinfos++); + info->cv8_cur_li->sectsym = + yasm_symtab_define_label(info->object->symtab, symname, sectbc, + 1, 0); + } + info->cv8_cur_li->num_linenums = 0; + STAILQ_INIT(&info->cv8_cur_li->linesets); + STAILQ_INSERT_TAIL(&info->cv8_lineinfos, info->cv8_cur_li, link); + info->cv8_cur_ls = NULL; + } + + /* build new lineset if necessary */ + if (!info->cv8_cur_ls || info->cv8_cur_ls->num_pairs >= 126) { + info->cv8_cur_ls = yasm_xmalloc(sizeof(cv8_lineset)); + info->cv8_cur_ls->num_pairs = 0; + STAILQ_INSERT_TAIL(&info->cv8_cur_li->linesets, info->cv8_cur_ls, link); + } + + /* add linepair for this bytecode */ + info->cv8_cur_ls->pairs[info->cv8_cur_ls->num_pairs].offset = bc->offset; + info->cv8_cur_ls->pairs[info->cv8_cur_ls->num_pairs].line = + 0x80000000 | line; + info->cv8_cur_ls->num_pairs++; + info->cv8_cur_li->num_linenums++; + + return 0; +} + +static int +cv_generate_line_section(yasm_section *sect, /*@null@*/ void *d) +{ + cv_line_info *info = (cv_line_info *)d; + + if (!yasm_section_is_code(sect)) + return 0; /* not code, so no line data for this section */ + + info->cv8_cur_li = NULL; + info->cv8_cur_ls = NULL; + + yasm_section_bcs_traverse(sect, info->errwarns, info, cv_generate_line_bc); + + return 0; +} + +static int +cv_generate_filename(const char *filename, void *d) +{ + cv_dbgfmt_add_file((yasm_dbgfmt_cv *)d, 0, filename); + return 0; +} + +static int +cv_generate_sym(yasm_symrec *sym, void *d) +{ + cv_line_info *info = (cv_line_info *)d; + yasm_bytecode *precbc; + const char *name = yasm_symrec_get_name(sym); + + /* only care about labels (for now). Don't put in symbols starting with + * ".", as these are typically internally generated ones (like section + * symbols). + */ + if (name[0] == '.' || !yasm_symrec_get_label(sym, &precbc)) + return 0; + + /* TODO: add data types; until then, just mark everything as UBYTE */ + if (yasm_section_is_code(yasm_bc_get_section(precbc))) + cv8_add_sym_label(info->debug_symline, sym); + else + cv8_add_sym_data(info->debug_symline, 0x20, sym, + yasm_symrec_get_visibility(sym) & YASM_SYM_GLOBAL?1:0); + return 0; +} + +yasm_section * +yasm_cv__generate_symline(yasm_object *object, yasm_linemap *linemap, + yasm_errwarns *errwarns) +{ + yasm_dbgfmt_cv *dbgfmt_cv = (yasm_dbgfmt_cv *)object->dbgfmt; + cv_line_info info; + int new; + size_t i; + cv8_symhead *head; + cv8_lineinfo *li; + yasm_bytecode *bc; + unsigned long off; + + /* Generate filenames based on linemap */ + yasm_linemap_traverse_filenames(linemap, dbgfmt_cv, + cv_generate_filename); + + info.object = object; + info.dbgfmt_cv = dbgfmt_cv; + info.linemap = linemap; + info.errwarns = errwarns; + info.debug_symline = + yasm_object_get_general(object, ".debug$S", 1, 0, 0, &new, 0); + info.num_lineinfos = 0; + STAILQ_INIT(&info.cv8_lineinfos); + info.cv8_cur_li = NULL; + info.cv8_cur_ls = NULL; + + /* source filenames string table */ + head = cv8_add_symhead(info.debug_symline, CV8_FILE_STRTAB, 1); + cv_append_str(info.debug_symline, ""); + off = 1; + for (i=0; i<dbgfmt_cv->filenames_size; i++) { + if (!dbgfmt_cv->filenames[i].pathname) { + yasm_error_set(YASM_ERROR_GENERAL, + N_("codeview file number %d unassigned"), i+1); + yasm_errwarn_propagate(errwarns, 0); + continue; + } + bc = cv_append_str(info.debug_symline, + dbgfmt_cv->filenames[i].pathname); + dbgfmt_cv->filenames[i].str_off = off; + off += bc->len; + } + cv8_set_symhead_end(head, yasm_section_bcs_last(info.debug_symline)); + + /* Align 4 */ + bc = yasm_bc_create_align + (yasm_expr_create_ident(yasm_expr_int(yasm_intnum_create_uint(4)), 0), + NULL, NULL, NULL, 0); + yasm_bc_finalize(bc, yasm_cv__append_bc(info.debug_symline, bc)); + yasm_bc_calc_len(bc, NULL, NULL); + + /* source file info table */ + head = cv8_add_symhead(info.debug_symline, CV8_FILE_INFO, 0); + off = 0; + for (i=0; i<dbgfmt_cv->filenames_size; i++) { + if (!dbgfmt_cv->filenames[i].pathname) + continue; + bc = cv8_add_fileinfo(info.debug_symline, &dbgfmt_cv->filenames[i]); + dbgfmt_cv->filenames[i].info_off = off; + off += bc->len; + } + cv8_set_symhead_end(head, yasm_section_bcs_last(info.debug_symline)); + + /* Already aligned 4 */ + + /* Generate line numbers for sections */ + yasm_object_sections_traverse(object, (void *)&info, + cv_generate_line_section); + + /* Output line numbers for sections */ + head = NULL; + STAILQ_FOREACH(li, &info.cv8_lineinfos, link) { + if (li->first_in_sect) { + if (head) + cv8_set_symhead_end(head, yasm_section_bcs_last(info.debug_symline)); + head = cv8_add_symhead(info.debug_symline, CV8_LINE_NUMS, 0); + } + bc = yasm_bc_create_common(&cv8_lineinfo_bc_callback, li, 0); + bc->len = (li->first_in_sect ? 24 : 12) + li->num_linenums*8; + yasm_cv__append_bc(info.debug_symline, bc); + } + if (head) + cv8_set_symhead_end(head, yasm_section_bcs_last(info.debug_symline)); + + /* Already aligned 4 */ + + /* Output debugging symbols */ + head = cv8_add_symhead(info.debug_symline, CV8_DEBUG_SYMS, 0); + /* add object and compile flag first */ + cv8_add_sym_objname(info.debug_symline, + yasm__abspath(object->obj_filename)); + if (getenv("YASM_TEST_SUITE")) + cv8_add_sym_compile(object, info.debug_symline, + yasm__xstrdup("yasm HEAD")); + else + cv8_add_sym_compile(object, info.debug_symline, + yasm__xstrdup(PACKAGE_STRING)); + /* then iterate through symbol table */ + yasm_symtab_traverse(object->symtab, &info, cv_generate_sym); + cv8_set_symhead_end(head, yasm_section_bcs_last(info.debug_symline)); + + /* Align 4 at end */ + bc = yasm_bc_create_align + (yasm_expr_create_ident(yasm_expr_int(yasm_intnum_create_uint(4)), 0), + NULL, NULL, NULL, 0); + yasm_bc_finalize(bc, yasm_cv__append_bc(info.debug_symline, bc)); + yasm_bc_calc_len(bc, NULL, NULL); + + return info.debug_symline; +} + +static void +cv_out_sym(yasm_symrec *sym, unsigned long off, yasm_bytecode *bc, + unsigned char **bufp, void *d, yasm_output_value_func output_value) +{ + yasm_value val; + + /* sym in its section */ + yasm_value_init_sym(&val, sym, 32); + val.section_rel = 1; + output_value(&val, *bufp, 4, off, bc, 0, d); + *bufp += 4; + + /* section index */ + yasm_value_init_sym(&val, sym, 16); + val.seg_of = 1; + output_value(&val, *bufp, 2, off+4, bc, 0, d); + *bufp += 2; +} + +static cv8_symhead * +cv8_add_symhead(yasm_section *sect, unsigned long type, int first) +{ + cv8_symhead *head; + yasm_bytecode *bc; + + head = yasm_xmalloc(sizeof(cv8_symhead)); + head->type = type; + head->first = first; + head->start_prevbc = yasm_section_bcs_last(sect); + + bc = yasm_bc_create_common(&cv8_symhead_bc_callback, head, 0); + if (first) + bc->len = 12; + else + bc->len = 8; + + head->end_prevbc = bc; + yasm_cv__append_bc(sect, bc); + return head; +} + +static void +cv8_set_symhead_end(cv8_symhead *head, yasm_bytecode *end_prevbc) +{ + head->end_prevbc = end_prevbc; +} + +static void +cv8_symhead_bc_destroy(void *contents) +{ + yasm_xfree(contents); +} + +static void +cv8_symhead_bc_print(const void *contents, FILE *f, int indent_level) +{ + /* TODO */ +} + +static int +cv8_symhead_bc_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span, + void *add_span_data) +{ + yasm_internal_error(N_("tried to calc_len a codeview symhead bytecode")); + /*@notreached@*/ + return 0; +} + +static int +cv8_symhead_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp, + unsigned char *bufstart, void *d, + yasm_output_value_func output_value, + yasm_output_reloc_func output_reloc) +{ + yasm_object *object = yasm_section_get_object(bc->section); + cv8_symhead *head = (cv8_symhead *)bc->contents; + unsigned char *buf = *bufp; + yasm_intnum *intn, *cval; + + cval = yasm_intnum_create_uint(4); + /* Output "version" if first */ + if (head->first) { + yasm_arch_intnum_tobytes(object->arch, cval, buf, 4, 32, 0, bc, 0); + buf += 4; + } + + /* Type contained - 4 bytes */ + yasm_intnum_set_uint(cval, head->type); + yasm_arch_intnum_tobytes(object->arch, cval, buf, 4, 32, 0, bc, 0); + buf += 4; + + /* Total length of info (following this field) - 4 bytes */ + yasm_intnum_set_uint(cval, bc->len); + intn = yasm_calc_bc_dist(head->start_prevbc, head->end_prevbc); + yasm_intnum_calc(intn, YASM_EXPR_SUB, cval); + yasm_arch_intnum_tobytes(object->arch, intn, buf, 4, 32, 0, bc, 0); + buf += 4; + yasm_intnum_destroy(intn); + + *bufp = buf; + + yasm_intnum_destroy(cval); + return 0; +} + +static yasm_bytecode * +cv8_add_fileinfo(yasm_section *sect, const cv_filename *fn) +{ + cv8_fileinfo *fi; + yasm_bytecode *bc; + + fi = yasm_xmalloc(sizeof(cv8_fileinfo)); + fi->fn = fn; + + bc = yasm_bc_create_common(&cv8_fileinfo_bc_callback, fi, 0); + bc->len = 24; + + yasm_cv__append_bc(sect, bc); + return bc; +} + +static void +cv8_fileinfo_bc_destroy(void *contents) +{ + yasm_xfree(contents); +} + +static void +cv8_fileinfo_bc_print(const void *contents, FILE *f, int indent_level) +{ + /* TODO */ +} + +static int +cv8_fileinfo_bc_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span, + void *add_span_data) +{ + yasm_internal_error(N_("tried to calc_len a codeview fileinfo bytecode")); + /*@notreached@*/ + return 0; +} + +static int +cv8_fileinfo_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp, + unsigned char *bufstart, void *d, + yasm_output_value_func output_value, + yasm_output_reloc_func output_reloc) +{ + yasm_object *object = yasm_section_get_object(bc->section); + cv8_fileinfo *fi = (cv8_fileinfo *)bc->contents; + unsigned char *buf = *bufp; + yasm_intnum *cval; + int i; + + /* Offset in filename string table */ + cval = yasm_intnum_create_uint(fi->fn->str_off); + yasm_arch_intnum_tobytes(object->arch, cval, buf, 4, 32, 0, bc, 0); + buf += 4; + + /* Checksum type/length */ + yasm_intnum_set_uint(cval, 0x0110); + yasm_arch_intnum_tobytes(object->arch, cval, buf, 2, 16, 0, bc, 0); + buf += 2; + + /* Checksum */ + for (i=0; i<16; i++) + YASM_WRITE_8(buf, fi->fn->digest[i]); + + /* Pad */ + YASM_WRITE_8(buf, 0); + YASM_WRITE_8(buf, 0); + + *bufp = buf; + + yasm_intnum_destroy(cval); + return 0; +} + +static void +cv8_lineinfo_bc_destroy(void *contents) +{ + cv8_lineinfo *li = (cv8_lineinfo *)contents; + cv8_lineset *ls1, *ls2; + + /* delete line sets */ + ls1 = STAILQ_FIRST(&li->linesets); + while (ls1) { + ls2 = STAILQ_NEXT(ls1, link); + yasm_xfree(ls1); + ls1 = ls2; + } + + yasm_xfree(contents); +} + +static void +cv8_lineinfo_bc_print(const void *contents, FILE *f, int indent_level) +{ + /* TODO */ +} + +static int +cv8_lineinfo_bc_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span, + void *add_span_data) +{ + yasm_internal_error(N_("tried to calc_len a codeview linehead bytecode")); + /*@notreached@*/ + return 0; +} + +static int +cv8_lineinfo_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp, + unsigned char *bufstart, void *d, + yasm_output_value_func output_value, + yasm_output_reloc_func output_reloc) +{ + yasm_object *object = yasm_section_get_object(bc->section); + cv8_lineinfo *li = (cv8_lineinfo *)bc->contents; + unsigned char *buf = *bufp; + yasm_intnum *cval; + unsigned long i; + cv8_lineset *ls; + + if (li->first_in_sect) { + /* start offset and section */ + cv_out_sym(li->sectsym, (unsigned long)(buf - bufstart), bc, &buf, + d, output_value); + + /* Two bytes of pad/alignment */ + YASM_WRITE_8(buf, 0); + YASM_WRITE_8(buf, 0); + + /* Section length covered by line number info */ + cval = yasm_calc_bc_dist(yasm_section_bcs_first(li->sect), + yasm_section_bcs_last(li->sect)); + yasm_arch_intnum_tobytes(object->arch, cval, buf, 4, 32, 0, bc, 0); + yasm_intnum_destroy(cval); + buf += 4; + } + + /* Offset of source file in info table */ + cval = yasm_intnum_create_uint(li->fn->info_off); + yasm_arch_intnum_tobytes(object->arch, cval, buf, 4, 32, 0, bc, 0); + buf += 4; + + /* Number of line number pairs */ + yasm_intnum_set_uint(cval, li->num_linenums); + yasm_arch_intnum_tobytes(object->arch, cval, buf, 4, 32, 0, bc, 0); + buf += 4; + + /* Number of bytes of line number pairs + 12 (no, I don't know why) */ + yasm_intnum_set_uint(cval, li->num_linenums*8+12); + yasm_arch_intnum_tobytes(object->arch, cval, buf, 4, 32, 0, bc, 0); + buf += 4; + + /* Offset / line number pairs */ + i = 0; + STAILQ_FOREACH(ls, &li->linesets, link) { + unsigned long j; + for (j=0; i<li->num_linenums && j<126; i++, j++) { + /* offset in section */ + yasm_intnum_set_uint(cval, ls->pairs[j].offset); + yasm_arch_intnum_tobytes(object->arch, cval, buf, 4, 32, 0, bc, 0); + buf += 4; + + /* line number in file */ + yasm_intnum_set_uint(cval, ls->pairs[j].line); + yasm_arch_intnum_tobytes(object->arch, cval, buf, 4, 32, 0, bc, 0); + buf += 4; + } + } + + *bufp = buf; + + yasm_intnum_destroy(cval); + return 0; +} + +static unsigned long +cv_sym_size(const cv_sym *cvs) +{ + const char *ch = cvs->format; + unsigned long len = 4; /* sym length and type */ + unsigned long slen; + int arg = 0; + + while (*ch) { + switch (*ch) { + case 'b': + len++; + arg++; + break; + case 'h': + len += 2; + arg++; + break; + case 'w': + len += 4; + arg++; + break; + case 'Y': + len += 6; /* XXX: will be 4 in 16-bit version */ + arg++; + break; + case 'T': + len += 4; /* XXX: will be 2 in CV4 */ + arg++; + break; + case 'S': + len += 1; /* XXX: is this 1 or 2? */ + slen = (unsigned long)strlen((const char *)cvs->args[arg++].p); + len += slen <= 0xff ? slen : 0xff; + break; + case 'Z': + len += + (unsigned long)strlen((const char *)cvs->args[arg++].p) + 1; + break; + default: + yasm_internal_error(N_("unknown sym format character")); + } + ch++; + } + + return len; +} + +static void +cv_sym_bc_destroy(void *contents) +{ + cv_sym *cvs = (cv_sym *)contents; + const char *ch = cvs->format; + int arg = 0; + + while (*ch) { + switch (*ch) { + case 'b': + case 'h': + case 'w': + case 'Y': + case 'T': + arg++; + break; /* nothing to destroy */ + case 'S': + case 'Z': + yasm_xfree(cvs->args[arg++].p); + break; + default: + yasm_internal_error(N_("unknown sym format character")); + } + ch++; + } + + yasm_xfree(contents); +} + +static void +cv_sym_bc_print(const void *contents, FILE *f, int indent_level) +{ + /* TODO */ +} + +static int +cv_sym_bc_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span, + void *add_span_data) +{ + yasm_internal_error(N_("tried to calc_len a codeview sym bytecode")); + /*@notreached@*/ + return 0; +} + +static int +cv_sym_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp, + unsigned char *bufstart, void *d, + yasm_output_value_func output_value, + yasm_output_reloc_func output_reloc) +{ + yasm_object *object = yasm_section_get_object(bc->section); + cv_sym *cvs = (cv_sym *)bc->contents; + unsigned char *buf = *bufp; + yasm_intnum *cval; + const char *ch = cvs->format; + size_t len; + int arg = 0; + + /* Total length of record (following this field) - 2 bytes */ + cval = yasm_intnum_create_uint(bc->len-2); + yasm_arch_intnum_tobytes(object->arch, cval, buf, 2, 16, 0, bc, 1); + buf += 2; + + /* Type contained - 2 bytes */ + yasm_intnum_set_uint(cval, cvs->type); + yasm_arch_intnum_tobytes(object->arch, cval, buf, 2, 16, 0, bc, 0); + buf += 2; + + while (*ch) { + switch (*ch) { + case 'b': + YASM_WRITE_8(buf, cvs->args[arg].i); + arg++; + break; + case 'h': + yasm_intnum_set_uint(cval, cvs->args[arg++].i); + yasm_arch_intnum_tobytes(object->arch, cval, buf, 2, 16, 0, + bc, 0); + buf += 2; + break; + case 'w': + yasm_intnum_set_uint(cval, cvs->args[arg++].i); + yasm_arch_intnum_tobytes(object->arch, cval, buf, 4, 32, 0, + bc, 0); + buf += 4; + break; + case 'Y': + cv_out_sym((yasm_symrec *)cvs->args[arg++].p, + (unsigned long)(buf-bufstart), bc, &buf, d, + output_value); + break; + case 'T': + yasm_intnum_set_uint(cval, cvs->args[arg++].i); + yasm_arch_intnum_tobytes(object->arch, cval, buf, 4, 32, 0, + bc, 0); + buf += 4; /* XXX: will be 2 in CV4 */ + break; + case 'S': + len = strlen((char *)cvs->args[arg].p); + len = len <= 0xff ? len : 0xff; + YASM_WRITE_8(buf, len); + memcpy(buf, (char *)cvs->args[arg].p, len); + buf += len; + arg++; + break; + case 'Z': + len = strlen((char *)cvs->args[arg].p)+1; + memcpy(buf, (char *)cvs->args[arg].p, len); + buf += len; + arg++; + break; + default: + yasm_internal_error(N_("unknown leaf format character")); + } + ch++; + } + + *bufp = buf; + + yasm_intnum_destroy(cval); + return 0; +} diff --git a/contrib/tools/yasm/modules/dbgfmts/codeview/cv-type.c b/contrib/tools/yasm/modules/dbgfmts/codeview/cv-type.c new file mode 100644 index 0000000000..2a52f18436 --- /dev/null +++ b/contrib/tools/yasm/modules/dbgfmts/codeview/cv-type.c @@ -0,0 +1,778 @@ +/* + * CodeView debugging format - type information + * + * Copyright (C) 2006-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. + * 3. Neither the name of the author nor the names of other contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 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 "cv-dbgfmt.h" + +enum cv_reservedtype { + /* Bitfields representation - type */ + CV_TYPE_SPECIAL = 0x00<<4, /* Special */ + CV_TYPE_SIGNED = 0x01<<4, /* Signed integral value */ + CV_TYPE_UNSIGNED = 0x02<<4, /* Unsigned integral value */ + CV_TYPE_BOOLEAN = 0x03<<4, /* Boolean */ + CV_TYPE_REAL = 0x04<<4, /* Real */ + CV_TYPE_COMPLEX = 0x05<<4, /* Complex */ + CV_TYPE_SPECIAL2 = 0x06<<4, /* Special2 */ + CV_TYPE_REALINT = 0x07<<4, /* Really int value */ + + /* "size" of CV_TYPE_SPECIAL */ + CV_SPECIAL_NOTYPE = 0x00<<0, /* No type */ + CV_SPECIAL_ABS = 0x01<<0, /* Absolute symbol */ + CV_SPECIAL_SEG = 0x02<<0, /* Segment */ + CV_SPECIAL_VOID = 0x03<<0, /* Void */ + CV_SPECIAL_CURRENCY = 0x04<<0, /* Basic 8-byte currency value */ + CV_SPECIAL_NEARBSTR = 0x05<<0, /* Near Basic string */ + CV_SPECIAL_FARBSTR = 0x06<<0, /* Far Basic string */ + + /* Size of CV_TYPE_SIGNED, CV_TYPE_UNSIGNED, and CV_TYPE_BOOLEAN */ + CV_INTEGER_1BYTE = 0x00<<0, /* 1 byte */ + CV_INTEGER_2BYTE = 0x01<<0, /* 2 byte */ + CV_INTEGER_4BYTE = 0x02<<0, /* 4 byte */ + CV_INTEGER_8BYTE = 0x03<<0, /* 8 byte */ + + /* Size of CV_TYPE_REAL and CV_TYPE_COMPLEX */ + CV_REAL_32BIT = 0x00<<0, /* 32 bit */ + CV_REAL_64BIT = 0x01<<0, /* 64 bit */ + CV_REAL_80BIT = 0x02<<0, /* 80 bit */ + CV_REAL_128BIT = 0x03<<0, /* 128 bit */ + CV_REAL_48BIT = 0x04<<0, /* 48 bit */ + + /* "size" of CV_TYPE_SPECIAL2 */ + CV_SPECIAL2_BIT = 0x00<<0, /* Bit */ + CV_SPECIAL2_PASCHAR = 0x01<<0, /* Pascal CHAR */ + + /* Size of CV_TYPE_REALINT */ + CV_REALINT_CHAR = 0x00<<0, /* Char */ + CV_REALINT_WCHAR = 0x01<<0, /* Wide character */ + CV_REALINT_S2BYTE = 0x02<<0, /* 2-byte signed integer */ + CV_REALINT_U2BYTE = 0x03<<0, /* 2-byte unsigned integer */ + CV_REALINT_S4BYTE = 0x04<<0, /* 4-byte signed integer */ + CV_REALINT_U4BYTE = 0x05<<0, /* 4-byte unsigned integer */ + CV_REALINT_S8BYTE = 0x06<<0, /* 8-byte signed integer */ + CV_REALINT_U8BYTE = 0x07<<0, /* 8-byte unsigned integer */ + + /* Mode */ + CV_MODE_DIRECT = 0x00<<8, /* Direct; not a pointer */ + CV_MODE_NEAR = 0x01<<8, /* Near pointer */ + CV_MODE_FAR = 0x02<<8, /* Far pointer */ + CV_MODE_HUGE = 0x03<<8, /* Huge pointer */ + CV_MODE_NEAR32 = 0x04<<8, /* 32-bit near pointer */ + CV_MODE_FAR32 = 0x05<<8, /* 32-bit far pointer */ + CV_MODE_NEAR64 = 0x06<<8, /* 64-bit near pointer */ + + /* Pure primitive type listing - based on above bitfields */ + + /* Special Types */ + CV_T_NOTYPE = 0x0000, /* Uncharacterized type (no type) */ + CV_T_ABS = 0x0001, /* Absolute symbol */ + CV_T_SEGMENT = 0x0002, /* Segment type */ + CV_T_VOID = 0x0003, /* Void */ + CV_T_PVOID = 0x0103, /* Near pointer to void */ + CV_T_PFVOID = 0x0203, /* Far pointer to void */ + CV_T_PHVOID = 0x0303, /* Huge pointer to void */ + CV_T_32PVOID = 0x0403, /* 32-bit near pointer to void */ + CV_T_32PFVOID = 0x0503, /* 32-bit far pointer to void */ + CV_T_CURRENCY = 0x0004, /* Basic 8-byte currency value */ + CV_T_NBASICSTR = 0x0005, /* Near Basic string */ + CV_T_FBASICSTR = 0x0006, /* Far Basic string */ + CV_T_BIT = 0x0060, /* Bit */ + CV_T_PASCHAR = 0x0061, /* Pascal CHAR */ + /* Character Types */ + CV_T_CHAR = 0x0010, /* 8-bit signed */ + CV_T_UCHAR = 0x0020, /* 8-bit unsigned */ + CV_T_PCHAR = 0x0110, /* Near pointer to 8-bit signed */ + CV_T_PUCHAR = 0x0120, /* Near pointer to 8-bit unsigned */ + CV_T_PFCHAR = 0x0210, /* Far pointer to 8-bit signed */ + CV_T_PFUCHAR = 0x0220, /* Far pointer to 8-bit unsigned */ + CV_T_PHCHAR = 0x0310, /* Huge pointer to 8-bit signed */ + CV_T_PHUCHAR = 0x0320, /* Huge pointer to 8-bit unsigned */ + CV_T_32PCHAR = 0x0410, /* 16:32 near pointer to 8-bit signed */ + CV_T_32PUCHAR = 0x0420, /* 16:32 near pointer to 8-bit unsigned */ + CV_T_32PFCHAR = 0x0510, /* 16:32 far pointer to 8-bit signed */ + CV_T_32PFUCHAR = 0x0520, /* 16:32 far pointer to 8-bit unsigned */ + /* Real Character Types */ + CV_T_RCHAR = 0x0070, /* Real char */ + CV_T_PRCHAR = 0x0170, /* Near pointer to a real char */ + CV_T_PFRCHAR = 0x0270, /* Far pointer to a real char */ + CV_T_PHRCHAR = 0x0370, /* Huge pointer to a real char */ + CV_T_32PRCHAR = 0x0470, /* 16:32 near pointer to a real char */ + CV_T_32PFRCHAR = 0x0570, /* 16:32 far pointer to a real char */ + /* Wide Character Types */ + CV_T_WCHAR = 0x0071, /* Wide char */ + CV_T_PWCHAR = 0x0171, /* Near pointer to a wide char */ + CV_T_PFWCHAR = 0x0271, /* Far pointer to a wide char */ + CV_T_PHWCHAR = 0x0371, /* Huge pointer to a wide char */ + CV_T_32PWCHAR = 0x0471, /* 16:32 near pointer to a wide char */ + CV_T_32PFWCHAR = 0x0571, /* 16:32 far pointer to a wide char */ + /* Real 16-bit Integer Types */ + CV_T_INT2 = 0x0072, /* Real 16-bit signed int */ + CV_T_UINT2 = 0x0073, /* Real 16-bit unsigned int */ + CV_T_PINT2 = 0x0172, /* Near pointer to 16-bit signed int */ + CV_T_PUINT2 = 0x0173, /* Near pointer to 16-bit unsigned int */ + CV_T_PFINT2 = 0x0272, /* Far pointer to 16-bit signed int */ + CV_T_PFUINT2 = 0x0273, /* Far pointer to 16-bit unsigned int */ + CV_T_PHINT2 = 0x0372, /* Huge pointer to 16-bit signed int */ + CV_T_PHUINT2 = 0x0373, /* Huge pointer to 16-bit unsigned int */ + CV_T_32PINT2 = 0x0472, /* 16:32 near pointer to 16-bit signed int */ + CV_T_32PUINT2 = 0x0473, /* 16:32 near pointer to 16-bit unsigned int */ + CV_T_32PFINT2 = 0x0572, /* 16:32 far pointer to 16-bit signed int */ + CV_T_32PFUINT2 = 0x0573, /* 16:32 far pointer to 16-bit unsigned int */ + /* 16-bit Short Types */ + CV_T_SHORT = 0x0011, /* 16-bit signed */ + CV_T_USHORT = 0x0021, /* 16-bit unsigned */ + CV_T_PSHORT = 0x0111, /* Near pointer to 16-bit signed */ + CV_T_PUSHORT = 0x0121, /* Near pointer to 16-bit unsigned */ + CV_T_PFSHORT = 0x0211, /* Far pointer to 16-bit signed */ + CV_T_PFUSHORT = 0x0221, /* Far pointer to 16-bit unsigned */ + CV_T_PHSHORT = 0x0311, /* Huge pointer to 16-bit signed */ + CV_T_PHUSHORT = 0x0321, /* Huge pointer to 16-bit unsigned */ + CV_T_32PSHORT = 0x0411, /* 16:32 near pointer to 16-bit signed */ + CV_T_32PUSHORT = 0x0421, /* 16:32 near pointer to 16-bit unsigned */ + CV_T_32PFSHORT = 0x0511, /* 16:32 far pointer to 16-bit signed */ + CV_T_32PFUSHORT = 0x0521, /* 16:32 far pointer to 16-bit unsigned */ + /* Real 32-bit Integer Types */ + CV_T_INT4 = 0x0074, /* Real 32-bit signed int */ + CV_T_UINT4 = 0x0075, /* Real 32-bit unsigned int */ + CV_T_PINT4 = 0x0174, /* Near pointer to 32-bit signed int */ + CV_T_PUINT4 = 0x0175, /* Near pointer to 32-bit unsigned int */ + CV_T_PFINT4 = 0x0274, /* Far pointer to 32-bit signed int */ + CV_T_PFUINT4 = 0x0275, /* Far pointer to 32-bit unsigned int */ + CV_T_PHINT4 = 0x0374, /* Huge pointer to 32-bit signed int */ + CV_T_PHUINT4 = 0x0375, /* Huge pointer to 32-bit unsigned int */ + CV_T_32PINT4 = 0x0474, /* 16:32 near pointer to 32-bit signed int */ + CV_T_32PUINT4 = 0x0475, /* 16:32 near pointer to 32-bit unsigned int */ + CV_T_32PFINT4 = 0x0574, /* 16:32 far pointer to 32-bit signed int */ + CV_T_32PFUINT4 = 0x0575, /* 16:32 far pointer to 32-bit unsigned int */ + /* 32-bit Long Types */ + CV_T_LONG = 0x0012, /* 32-bit signed */ + CV_T_ULONG = 0x0022, /* 32-bit unsigned */ + CV_T_PLONG = 0x0112, /* Near pointer to 32-bit signed */ + CV_T_PULONG = 0x0122, /* Near pointer to 32-bit unsigned */ + CV_T_PFLONG = 0x0212, /* Far pointer to 32-bit signed */ + CV_T_PFULONG = 0x0222, /* Far pointer to 32-bit unsigned */ + CV_T_PHLONG = 0x0312, /* Huge pointer to 32-bit signed */ + CV_T_PHULONG = 0x0322, /* Huge pointer to 32-bit unsigned */ + CV_T_32PLONG = 0x0412, /* 16:32 near pointer to 32-bit signed */ + CV_T_32PULONG = 0x0422, /* 16:32 near pointer to 32-bit unsigned */ + CV_T_32PFLONG = 0x0512, /* 16:32 far pointer to 32-bit signed */ + CV_T_32PFULONG = 0x0522, /* 16:32 far pointer to 32-bit unsigned */ + /* Real 64-bit int Types */ + CV_T_INT8 = 0x0076, /* 64-bit signed int */ + CV_T_UINT8 = 0x0077, /* 64-bit unsigned int */ + CV_T_PINT8 = 0x0176, /* Near pointer to 64-bit signed int */ + CV_T_PUINT8 = 0x0177, /* Near pointer to 64-bit unsigned int */ + CV_T_PFINT8 = 0x0276, /* Far pointer to 64-bit signed int */ + CV_T_PFUINT8 = 0x0277, /* Far pointer to 64-bit unsigned int */ + CV_T_PHINT8 = 0x0376, /* Huge pointer to 64-bit signed int */ + CV_T_PHUINT8 = 0x0377, /* Huge pointer to 64-bit unsigned int */ + CV_T_32PINT8 = 0x0476, /* 16:32 near pointer to 64-bit signed int */ + CV_T_32PUINT8 = 0x0477, /* 16:32 near pointer to 64-bit unsigned int */ + CV_T_32PFINT8 = 0x0576, /* 16:32 far pointer to 64-bit signed int */ + CV_T_32PFUINT8 = 0x0577, /* 16:32 far pointer to 64-bit unsigned int */ + /* 64-bit Integral Types */ + CV_T_QUAD = 0x0013, /* 64-bit signed */ + CV_T_UQUAD = 0x0023, /* 64-bit unsigned */ + CV_T_PQUAD = 0x0113, /* Near pointer to 64-bit signed */ + CV_T_PUQUAD = 0x0123, /* Near pointer to 64-bit unsigned */ + CV_T_PFQUAD = 0x0213, /* Far pointer to 64-bit signed */ + CV_T_PFUQUAD = 0x0223, /* Far pointer to 64-bit unsigned */ + CV_T_PHQUAD = 0x0313, /* Huge pointer to 64-bit signed */ + CV_T_PHUQUAD = 0x0323, /* Huge pointer to 64-bit unsigned */ + CV_T_32PQUAD = 0x0413, /* 16:32 near pointer to 64-bit signed */ + CV_T_32PUQUAD = 0x0423, /* 16:32 near pointer to 64-bit unsigned */ + CV_T_32PFQUAD = 0x0513, /* 16:32 far pointer to 64-bit signed */ + CV_T_32PFUQUAD = 0x0523, /* 16:32 far pointer to 64-bit unsigned */ + /* 32-bit Real Types */ + CV_T_REAL32 = 0x0040, /* 32-bit real */ + CV_T_PREAL32 = 0x0140, /* Near pointer to 32-bit real */ + CV_T_PFREAL32 = 0x0240, /* Far pointer to 32-bit real */ + CV_T_PHREAL32 = 0x0340, /* Huge pointer to 32-bit real */ + CV_T_32PREAL32 = 0x0440, /* 16:32 near pointer to 32-bit real */ + CV_T_32PFREAL32 = 0x0540, /* 16:32 far pointer to 32-bit real */ + /* 48-bit Real Types */ + CV_T_REAL48 = 0x0044, /* 48-bit real */ + CV_T_PREAL48 = 0x0144, /* Near pointer to 48-bit real */ + CV_T_PFREAL48 = 0x0244, /* Far pointer to 48-bit real */ + CV_T_PHREAL48 = 0x0344, /* Huge pointer to 48-bit real */ + CV_T_32PREAL48 = 0x0444, /* 16:32 near pointer to 48-bit real */ + CV_T_32PFREAL48 = 0x0544, /* 16:32 far pointer to 48-bit real */ + /* 64-bit Real Types */ + CV_T_REAL64 = 0x0041, /* 64-bit real */ + CV_T_PREAL64 = 0x0141, /* Near pointer to 64-bit real */ + CV_T_PFREAL64 = 0x0241, /* Far pointer to 64-bit real */ + CV_T_PHREAL64 = 0x0341, /* Huge pointer to 64-bit real */ + CV_T_32PREAL64 = 0x0441, /* 16:32 near pointer to 64-bit real */ + CV_T_32PFREAL64 = 0x0541, /* 16:32 far pointer to 64-bit real */ + /* 80-bit Real Types */ + CV_T_REAL80 = 0x0042, /* 80-bit real */ + CV_T_PREAL80 = 0x0142, /* Near pointer to 80-bit real */ + CV_T_PFREAL80 = 0x0242, /* Far pointer to 80-bit real */ + CV_T_PHREAL80 = 0x0342, /* Huge pointer to 80-bit real */ + CV_T_32PREAL80 = 0x0442, /* 16:32 near pointer to 80-bit real */ + CV_T_32PFREAL80 = 0x0542, /* 16:32 far pointer to 80-bit real */ + /* 128-bit Real Types */ + CV_T_REAL128 = 0x0043, /* 128-bit real */ + CV_T_PREAL128 = 0x0143, /* Near pointer to 128-bit real */ + CV_T_PFREAL128 = 0x0243, /* Far pointer to 128-bit real */ + CV_T_PHREAL128 = 0x0343, /* Huge pointer to 128-bit real */ + CV_T_32PREAL128 = 0x0443, /* 16:32 near pointer to 128-bit real */ + CV_T_32PFREAL128 = 0x0543, /* 16:32 far pointer to 128-bit real */ + /* 32-bit Complex Types */ + CV_T_CPLX32 = 0x0050, /* 32-bit complex */ + CV_T_PCPLX32 = 0x0150, /* Near pointer to 32-bit complex */ + CV_T_PFCPLX32 = 0x0250, /* Far pointer to 32-bit complex */ + CV_T_PHCPLX32 = 0x0350, /* Huge pointer to 32-bit complex */ + CV_T_32PCPLX32 = 0x0450, /* 16:32 near pointer to 32-bit complex */ + CV_T_32PFCPLX32 = 0x0550, /* 16:32 far pointer to 32-bit complex */ + /* 64-bit Complex Types */ + CV_T_CPLX64 = 0x0051, /* 64-bit complex */ + CV_T_PCPLX64 = 0x0151, /* Near pointer to 64-bit complex */ + CV_T_PFCPLX64 = 0x0251, /* Far pointer to 64-bit complex */ + CV_T_PHCPLX64 = 0x0351, /* Huge pointer to 64-bit complex */ + CV_T_32PCPLX64 = 0x0451, /* 16:32 near pointer to 64-bit complex */ + CV_T_32PFCPLX64 = 0x0551, /* 16:32 far pointer to 64-bit complex */ + /* 80-bit Complex Types */ + CV_T_CPLX80 = 0x0052, /* 80-bit complex */ + CV_T_PCPLX80 = 0x0152, /* Near pointer to 80-bit complex */ + CV_T_PFCPLX80 = 0x0252, /* Far pointer to 80-bit complex */ + CV_T_PHCPLX80 = 0x0352, /* Huge pointer to 80-bit complex */ + CV_T_32PCPLX80 = 0x0452, /* 16:32 near pointer to 80-bit complex */ + CV_T_32PFCPLX80 = 0x0552, /* 16:32 far pointer to 80-bit complex */ + /* 128-bit Complex Types */ + CV_T_CPLX128 = 0x0053, /* 128-bit complex */ + CV_T_PCPLX128 = 0x0153, /* Near pointer to 128-bit complex */ + CV_T_PFCPLX128 = 0x0253, /* Far pointer to 128-bit complex */ + CV_T_PHCPLX128 = 0x0353, /* Huge pointer to 128-bit real */ + CV_T_32PCPLX128 = 0x0453, /* 16:32 near pointer to 128-bit complex */ + CV_T_32PFCPLX128 = 0x0553, /* 16:32 far pointer to 128-bit complex */ + /* Boolean Types */ + CV_T_BOOL08 = 0x0030, /* 8-bit Boolean */ + CV_T_BOOL16 = 0x0031, /* 16-bit Boolean */ + CV_T_BOOL32 = 0x0032, /* 32-bit Boolean */ + CV_T_BOOL64 = 0x0033, /* 64-bit Boolean */ + CV_T_PBOOL08 = 0x0130, /* Near pointer to 8-bit Boolean */ + CV_T_PBOOL16 = 0x0131, /* Near pointer to 16-bit Boolean */ + CV_T_PBOOL32 = 0x0132, /* Near pointer to 32-bit Boolean */ + CV_T_PBOOL64 = 0x0133, /* Near pointer to 64-bit Boolean */ + CV_T_PFBOOL08 = 0x0230, /* Far pointer to 8-bit Boolean */ + CV_T_PFBOOL16 = 0x0231, /* Far pointer to 16-bit Boolean */ + CV_T_PFBOOL32 = 0x0232, /* Far pointer to 32-bit Boolean */ + CV_T_PFBOOL64 = 0x0233, /* Far pointer to 64-bit Boolean */ + CV_T_PHBOOL08 = 0x0330, /* Huge pointer to 8-bit Boolean */ + CV_T_PHBOOL16 = 0x0331, /* Huge pointer to 16-bit Boolean */ + CV_T_PHBOOL32 = 0x0332, /* Huge pointer to 32-bit Boolean */ + CV_T_PHBOOL64 = 0x0333, /* Huge pointer to 64-bit Boolean */ + CV_T_32PBOOL08 = 0x0430, /* 16:32 near pointer to 8-bit Boolean */ + CV_T_32PBOOL16 = 0x0431, /* 16:32 near pointer to 16-bit Boolean */ + CV_T_32PBOOL32 = 0x0432, /* 16:32 near pointer to 32-bit Boolean */ + CV_T_32PBOOL64 = 0x0433, /* 16:32 near pointer to 64-bit Boolean */ + CV_T_32PFBOOL08 = 0x0530, /* 16:32 far pointer to 8-bit Boolean */ + CV_T_32PFBOOL16 = 0x0531, /* 16:32 far pointer to 16-bit Boolean */ + CV_T_32PFBOOL32 = 0x0532, /* 16:32 far pointer to 32-bit Boolean */ + CV_T_32PFBOOL64 = 0x0533, /* 16:32 far pointer to 64-bit Boolean */ + + /* Non-primitive types are stored in the TYPES section (generated in + * cv-type.c) and start at this index (e.g. 0x1000 is the first type + * in TYPES, 0x1001 the second, etc. + */ + CV_FIRST_NONPRIM = 0x1000 +}; + +enum cv_leaftype { + /* Leaf indices for type records that can be referenced from symbols */ + CV4_LF_MODIFIER = 0x0001, /* Type Modifier */ + CV4_LF_POINTER = 0x0002, /* Pointer */ + CV4_LF_ARRAY = 0x0003, /* Simple Array */ + CV4_LF_CLASS = 0x0004, /* Classes */ + CV4_LF_STRUCTURE = 0x0005, /* Structures */ + CV4_LF_UNION = 0x0006, /* Unions */ + CV4_LF_ENUM = 0x0007, /* Enumeration */ + CV4_LF_PROCEDURE = 0x0008, /* Procedure */ + CV4_LF_MFUNCTION = 0x0009, /* Member Function */ + CV4_LF_VTSHAPE = 0x000a, /* Virtual Function Table Shape */ + CV4_LF_BARRAY = 0x000d, /* Basic Array */ + CV4_LF_LABEL = 0x000e, /* Label */ + CV4_LF_NULL = 0x000f, /* Null */ + CV4_LF_DIMARRAY = 0x0011, /* Multiply Dimensioned Array */ + CV4_LF_VFTPATH = 0x0012, /* Path to Virtual Function Table */ + CV4_LF_PRECOMP = 0x0013, /* Reference Precompiled Types */ + CV4_LF_ENDPRECOMP = 0x0014, /* End of Precompiled Types */ + + /* CodeView 5.0 version */ + CV5_LF_MODIFIER = 0x1001, /* Type Modifier */ + CV5_LF_POINTER = 0x1002, /* Pointer */ + CV5_LF_ARRAY = 0x1003, /* Simple Array */ + CV5_LF_CLASS = 0x1004, /* Classes */ + CV5_LF_STRUCTURE = 0x1005, /* Structures */ + CV5_LF_UNION = 0x1006, /* Unions */ + CV5_LF_ENUM = 0x1007, /* Enumeration */ + CV5_LF_PROCEDURE = 0x1008, /* Procedure */ + CV5_LF_MFUNCTION = 0x1009, /* Member Function */ + CV5_LF_VTSHAPE = 0x000a, /* Virtual Function Table Shape */ + CV5_LF_BARRAY = 0x100d, /* Basic Array */ + CV5_LF_LABEL = 0x000e, /* Label */ + CV5_LF_NULL = 0x000f, /* Null */ + CV5_LF_DIMARRAY = 0x100c, /* Multiply Dimensioned Array */ + CV5_LF_VFTPATH = 0x100d, /* Path to Virtual Function Table */ + CV5_LF_PRECOMP = 0x100e, /* Reference Precompiled Types */ + CV5_LF_ENDPRECOMP = 0x0014, /* End of Precompiled Types */ + CV5_LF_TYPESERVER = 0x0016, /* Reference Typeserver */ + + /* Leaf indices for type records that can be referenced from other type + * records + */ + CV4_LF_SKIP = 0x0200, /* Skip */ + CV4_LF_ARGLIST = 0x0201, /* Argument List */ + CV4_LF_DEFARG = 0x0202, /* Default Argument */ + CV4_LF_LIST = 0x0203, /* Arbitrary List */ + CV4_LF_FIELDLIST = 0x0204, /* Field List */ + CV4_LF_DERIVED = 0x0205, /* Derived Classes */ + CV4_LF_BITFIELD = 0x0206, /* Bit Fields */ + CV4_LF_METHODLIST = 0x0207, /* Method List */ + CV4_LF_DIMCONU = 0x0208, /* Dimensioned Array with Constant Upper Bound */ + CV4_LF_DIMCONLU = 0x0209, /* Dimensioned Array with Constant Lower and Upper Bounds */ + CV4_LF_DIMVARU = 0x020a, /* Dimensioned Array with Variable Upper Bound */ + CV4_LF_DIMVARLU = 0x020b, /* Dimensioned Array with Variable Lower and Upper Bounds */ + CV4_LF_REFSYM = 0x020c, /* Referenced Symbol */ + + /* CodeView 5.0 version */ + CV5_LF_SKIP = 0x1200, /* Skip */ + CV5_LF_ARGLIST = 0x1201, /* Argument List */ + CV5_LF_DEFARG = 0x1202, /* Default Argument */ + CV5_LF_FIELDLIST = 0x1203, /* Field List */ + CV5_LF_DERIVED = 0x1204, /* Derived Classes */ + CV5_LF_BITFIELD = 0x1205, /* Bit Fields */ + CV5_LF_METHODLIST = 0x1206, /* Method List */ + CV5_LF_DIMCONU = 0x1207, /* Dimensioned Array with Constant Upper Bound */ + CV5_LF_DIMCONLU = 0x1208, /* Dimensioned Array with Constant Lower and Upper Bounds */ + CV5_LF_DIMVARU = 0x1209, /* Dimensioned Array with Variable Upper Bound */ + CV5_LF_DIMVARLU = 0x120a, /* Dimensioned Array with Variable Lower and Upper Bounds */ + CV5_LF_REFSYM = 0x020c, /* Referenced Symbol */ + + /* Leaf indices for fields of complex lists */ + CV4_LF_BCLASS = 0x0400, /* Real Base Class */ + CV4_LF_VBCLASS = 0x0401, /* Direct Virtual Base Class */ + CV4_LF_IVBCLASS = 0x0402, /* Indirect Virtual Base Class */ + CV4_LF_ENUMERATE = 0x0403, /* Enumeration Name and Value */ + CV4_LF_FRIENDFCN = 0x0404, /* Friend Function */ + CV4_LF_INDEX = 0x0405, /* Index To Another Type Record */ + CV4_LF_MEMBER = 0x0406, /* Data Member */ + CV4_LF_STMEMBER = 0x0407, /* Static Data Member */ + CV4_LF_METHOD = 0x0408, /* Method */ + CV4_LF_NESTTYPE = 0x0409, /* Nested Type Definition */ + CV4_LF_VFUNCTAB = 0x040a, /* Virtual Function Table Pointer */ + CV4_LF_FRIENDCLS = 0x040b, /* Friend Class */ + CV4_LF_ONEMETHOD = 0x040c, /* One Method */ + CV4_LF_VFUNCOFF = 0x040d, /* Virtual Function Offset */ + + /* CodeView 5.0 version */ + CV5_LF_BCLASS = 0x1400, /* Real Base Class */ + CV5_LF_VBCLASS = 0x1401, /* Direct Virtual Base Class */ + CV5_LF_IVBCLASS = 0x1402, /* Indirect Virtual Base Class */ + CV5_LF_ENUMERATE = 0x0403, /* Enumeration Name and Value */ + CV5_LF_FRIENDFCN = 0x1403, /* Friend Function */ + CV5_LF_INDEX = 0x1404, /* Index To Another Type Record */ + CV5_LF_MEMBER = 0x1405, /* Data Member */ + CV5_LF_STMEMBER = 0x1406, /* Static Data Member */ + CV5_LF_METHOD = 0x1407, /* Method */ + CV5_LF_NESTTYPE = 0x1408, /* Nested Type Definition */ + CV5_LF_VFUNCTAB = 0x1409, /* Virtual Function Table Pointer */ + CV5_LF_FRIENDCLS = 0x140a, /* Friend Class */ + CV5_LF_ONEMETHOD = 0x140b, /* One Method */ + CV5_LF_VFUNCOFF = 0x140c, /* Virtual Function Offset */ + CV5_LF_NESTTYPEEX = 0x140d, /* Nested Type Extended Definition */ + CV5_LF_MEMBERMODIFY = 0x140e, /* Member Modification */ + /* XXX: CodeView 5.0 spec also lists 0x040f as LF_MEMBERMODIFY? */ + + /* Leaf indices for numeric fields of symbols and type records */ + CV_LF_NUMERIC = 0x8000, + CV_LF_CHAR = 0x8000, /* Signed Char (8-bit) */ + CV_LF_SHORT = 0x8001, /* Signed Short (16-bit) */ + CV_LF_USHORT = 0x8002, /* Unsigned Short (16-bit) */ + CV_LF_LONG = 0x8003, /* Signed Long (32-bit) */ + CV_LF_ULONG = 0x8004, /* Unsigned Long (32-bit) */ + CV_LF_REAL32 = 0x8005, /* 32-bit Float */ + CV_LF_REAL64 = 0x8006, /* 64-bit Float */ + CV_LF_REAL80 = 0x8007, /* 80-bit Float */ + CV_LF_REAL128 = 0x8008, /* 128-bit Float */ + CV_LF_QUADWORD = 0x8009, /* Signed Quad Word (64-bit) */ + CV_LF_UQUADWORD = 0x800a, /* Unsigned Quad Word (64-bit) */ + CV_LF_REAL48 = 0x800b, /* 48-bit Float */ + CV_LF_COMPLEX32 = 0x800c, /* 32-bit Complex */ + CV_LF_COMPLEX64 = 0x800d, /* 64-bit Complex */ + CV_LF_COMPLEX80 = 0x800e, /* 80-bit Complex */ + CV_LF_COMPLEX128 = 0x800f, /* 128-bit Complex */ + CV_LF_VARSTRING = 0x8010, /* Variable-length String */ + + /* Leaf padding bytes */ + CV_LF_PAD0 = 0xf0, + CV_LF_PAD1 = 0xf1, + CV_LF_PAD2 = 0xf2, + CV_LF_PAD3 = 0xf3, + CV_LF_PAD4 = 0xf4, + CV_LF_PAD5 = 0xf5, + CV_LF_PAD6 = 0xf6, + CV_LF_PAD7 = 0xf7, + CV_LF_PAD8 = 0xf8, + CV_LF_PAD9 = 0xf9, + CV_LF_PAD10 = 0xfa, + CV_LF_PAD11 = 0xfb, + CV_LF_PAD12 = 0xfc, + CV_LF_PAD13 = 0xfc, + CV_LF_PAD14 = 0xfe, + CV_LF_PAD15 = 0xff +}; + +/* Leaves use a bit of meta-programming to encode formats: each character + * of format represents the output generated, as follows: + * 'b' : 1 byte value (integer) + * 'h' : 2 byte value (integer) + * 'w' : 4 byte value (integer) + * 'L' : subleaf, recurses into cv_leaf (pointer) + * 'T' : 4 byte type index, pulls cv_type.index from cv_type (pointer) + * 'S' : length-prefixed string (pointer) + */ +typedef struct cv_leaf { + enum cv_leaftype type; + const char *format; /* format of args */ + union { + unsigned long i; + void *p; + } args[6]; +} cv_leaf; + +typedef struct cv_type { + unsigned long indx; /* type # (must be same as output order) */ + size_t num_leaves; + /*@null@*/ /*@only@*/ cv_leaf **leaves; +} cv_type; + +/* Bytecode callback function prototypes */ +static void cv_type_bc_destroy(void *contents); +static void cv_type_bc_print(const void *contents, FILE *f, int indent_level); +static int cv_type_bc_calc_len + (yasm_bytecode *bc, yasm_bc_add_span_func add_span, void *add_span_data); +static int cv_type_bc_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 cv_type_bc_callback = { + cv_type_bc_destroy, + cv_type_bc_print, + yasm_bc_finalize_common, + NULL, + cv_type_bc_calc_len, + yasm_bc_expand_common, + cv_type_bc_tobytes, + 0 +}; + +static cv_type *cv_type_create(unsigned long indx); +static void cv_type_append_leaf(cv_type *type, /*@keep@*/ cv_leaf *leaf); + + +static cv_leaf * +cv_leaf_create_label(int is_far) +{ + cv_leaf *leaf = yasm_xmalloc(sizeof(cv_leaf)); + leaf->type = CV5_LF_LABEL; + leaf->format = "h"; + leaf->args[0].i = is_far ? 4 : 0; + return leaf; +} + +yasm_section * +yasm_cv__generate_type(yasm_object *object) +{ + int new; + unsigned long indx = CV_FIRST_NONPRIM; + yasm_section *debug_type; + yasm_bytecode *bc; + cv_type *type; + + debug_type = + yasm_object_get_general(object, ".debug$T", 1, 0, 0, &new, 0); + + /* Add label type */ + type = cv_type_create(indx++); + cv_type_append_leaf(type, cv_leaf_create_label(0)); + bc = yasm_bc_create_common(&cv_type_bc_callback, type, 0); + yasm_bc_finalize(bc, yasm_cv__append_bc(debug_type, bc)); + yasm_bc_calc_len(bc, NULL, NULL); + + return debug_type; +} + +static void +cv_leaf_destroy(cv_leaf *leaf) +{ + const char *ch = leaf->format; + int arg = 0; + + while (*ch) { + switch (*ch) { + case 'b': + case 'h': + case 'w': + arg++; + break; /* nothing to destroy */ + case 'L': + cv_leaf_destroy((cv_leaf *)leaf->args[arg++].p); + break; + case 'T': + arg++; /* nothing to destroy */ + break; + case 'S': + yasm_xfree(leaf->args[arg++].p); + break; + default: + yasm_internal_error(N_("unknown leaf format character")); + } + ch++; + } +} + +static unsigned long +cv_leaf_size(const cv_leaf *leaf) +{ + const char *ch = leaf->format; + unsigned long len = 2; /* leaf type */ + unsigned long slen; + int arg = 0; + + while (*ch) { + switch (*ch) { + case 'b': + len++; + arg++; + break; + case 'h': + len += 2; + arg++; + break; + case 'w': + len += 4; + arg++; + break; + case 'L': + len += cv_leaf_size((const cv_leaf *)leaf->args[arg++].p); + break; + case 'T': + len += 4; /* XXX: will be 2 in CV4 */ + arg++; + break; + case 'S': + len += 1; /* XXX: is this 1 or 2? */ + slen = (unsigned long)strlen((const char *)leaf->args[arg++].p); + len += slen <= 0xff ? slen : 0xff; + break; + default: + yasm_internal_error(N_("unknown leaf format character")); + } + ch++; + } + + return len; +} + +static void +cv_leaf_tobytes(const cv_leaf *leaf, yasm_bytecode *bc, yasm_arch *arch, + unsigned char **bufp, yasm_intnum *cval) +{ + unsigned char *buf = *bufp; + const char *ch = leaf->format; + size_t len; + int arg = 0; + + /* leaf type */ + yasm_intnum_set_uint(cval, leaf->type); + yasm_arch_intnum_tobytes(arch, cval, buf, 2, 16, 0, bc, 0); + buf += 2; + + while (*ch) { + switch (*ch) { + case 'b': + YASM_WRITE_8(buf, leaf->args[arg].i); + arg++; + break; + case 'h': + yasm_intnum_set_uint(cval, leaf->args[arg++].i); + yasm_arch_intnum_tobytes(arch, cval, buf, 2, 16, 0, bc, 0); + buf += 2; + break; + case 'w': + yasm_intnum_set_uint(cval, leaf->args[arg++].i); + yasm_arch_intnum_tobytes(arch, cval, buf, 4, 32, 0, bc, 0); + buf += 4; + break; + case 'L': + cv_leaf_tobytes((const cv_leaf *)leaf->args[arg++].p, bc, arch, + &buf, cval); + break; + case 'T': + yasm_intnum_set_uint(cval, + ((const cv_type *)leaf->args[arg++].p)->indx); + yasm_arch_intnum_tobytes(arch, cval, buf, 4, 32, 0, bc, 0); + buf += 4; /* XXX: will be 2 in CV4 */ + break; + case 'S': + len = strlen((const char *)leaf->args[arg].p); + len = len <= 0xff ? len : 0xff; + YASM_WRITE_8(buf, len); + memcpy(buf, (const char *)leaf->args[arg].p, len); + buf += len; + arg++; + break; + default: + yasm_internal_error(N_("unknown leaf format character")); + } + ch++; + } + + *bufp = buf; +} + +static cv_type * +cv_type_create(unsigned long indx) +{ + cv_type *type = yasm_xmalloc(sizeof(cv_type)); + + type->indx = indx; + type->num_leaves = 0; + type->leaves = NULL; + + return type; +} + +static void +cv_type_append_leaf(cv_type *type, /*@keep@*/ cv_leaf *leaf) +{ + type->num_leaves++; + + /* This is inefficient for large numbers of leaves, but that won't happen + * until we add structure support. + */ + type->leaves = yasm_xrealloc(type->leaves, + type->num_leaves*sizeof(cv_leaf *)); + + type->leaves[type->num_leaves-1] = leaf; +} + +static void +cv_type_bc_destroy(void *contents) +{ + cv_type *type = (cv_type *)contents; + size_t i; + + for (i=0; i<type->num_leaves; i++) + cv_leaf_destroy(type->leaves[i]); + if (type->leaves) + yasm_xfree(type->leaves); + yasm_xfree(contents); +} + +static void +cv_type_bc_print(const void *contents, FILE *f, int indent_level) +{ + /* TODO */ +} + +static int +cv_type_bc_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span, + void *add_span_data) +{ + cv_type *type = (cv_type *)bc->contents; + size_t i; + + if (type->indx == CV_FIRST_NONPRIM) + bc->len = 4+2; + else + bc->len = 2; + + for (i=0; i<type->num_leaves; i++) + bc->len += cv_leaf_size(type->leaves[i]); + + /* Pad to multiple of 4 */ + if (bc->len & 0x3) + bc->len += 4-(bc->len & 0x3); + + return 0; +} + +static int +cv_type_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp, + unsigned char *bufstart, void *d, + yasm_output_value_func output_value, + yasm_output_reloc_func output_reloc) +{ + yasm_object *object = yasm_section_get_object(bc->section); + cv_type *type = (cv_type *)bc->contents; + unsigned char *buf = *bufp; + yasm_intnum *cval; + size_t i; + unsigned long reclen = bc->len - 2; + + cval = yasm_intnum_create_uint(4); /* version */ + if (type->indx == CV_FIRST_NONPRIM) { + yasm_arch_intnum_tobytes(object->arch, cval, buf, 4, 32, 0, bc, 1); + buf += 4; + reclen -= 4; + } + + /* Total length of record (following this field) - 2 bytes */ + yasm_intnum_set_uint(cval, reclen); + yasm_arch_intnum_tobytes(object->arch, cval, buf, 2, 16, 0, bc, 1); + buf += 2; + + /* Leaves */ + for (i=0; i<type->num_leaves; i++) + cv_leaf_tobytes(type->leaves[i], bc, object->arch, &buf, cval); + + /* Pad to multiple of 4 */ + switch ((buf-(*bufp)) & 0x3) { + case 3: + YASM_WRITE_8(buf, CV_LF_PAD3); + case 2: + YASM_WRITE_8(buf, CV_LF_PAD2); + case 1: + YASM_WRITE_8(buf, CV_LF_PAD1); + case 0: + break; + } + + *bufp = buf; + + yasm_intnum_destroy(cval); + return 0; +} diff --git a/contrib/tools/yasm/modules/dbgfmts/dwarf2/dwarf2-aranges.c b/contrib/tools/yasm/modules/dbgfmts/dwarf2/dwarf2-aranges.c new file mode 100644 index 0000000000..f398b7fa72 --- /dev/null +++ b/contrib/tools/yasm/modules/dbgfmts/dwarf2/dwarf2-aranges.c @@ -0,0 +1,125 @@ +/* + * DWARF2 debugging format - address range table + * + * Copyright (C) 2006-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 "dwarf2-dbgfmt.h" + + +static void +dwarf2_append_arange(yasm_section *debug_aranges, /*@only@*/ yasm_expr *start, + /*@only@*/ yasm_expr *length, unsigned int sizeof_address) +{ + yasm_datavalhead dvs; + yasm_bytecode *bc; + + yasm_dvs_initialize(&dvs); + yasm_dvs_append(&dvs, yasm_dv_create_expr(start)); + yasm_dvs_append(&dvs, yasm_dv_create_expr(length)); + bc = yasm_bc_create_data(&dvs, sizeof_address, 0, NULL, 0); + yasm_bc_finalize(bc, yasm_dwarf2__append_bc(debug_aranges, bc)); + yasm_bc_calc_len(bc, NULL, NULL); +} + +typedef struct dwarf2_aranges_info { + yasm_section *debug_aranges; /* section to which address ranges go */ + yasm_object *object; + yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2; +} dwarf2_aranges_info; + +static int +dwarf2_generate_aranges_section(yasm_section *sect, /*@null@*/ void *d) +{ + dwarf2_aranges_info *info = (dwarf2_aranges_info *)d; + yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2 = info->dbgfmt_dwarf2; + /*@null@*/ dwarf2_section_data *dsd; + /*@only@*/ yasm_expr *start, *length; + + dsd = yasm_section_get_data(sect, &yasm_dwarf2__section_data_cb); + if (!dsd) + return 0; /* no line data for this section */ + + /* Create address range descriptor */ + start = yasm_expr_create_ident( + yasm_expr_sym(yasm_dwarf2__bc_sym(info->object->symtab, + yasm_section_bcs_first(sect))), 0); + length = yasm_expr_create_ident( + yasm_expr_int(yasm_calc_bc_dist(yasm_section_bcs_first(sect), + yasm_section_bcs_last(sect))), 0); + dwarf2_append_arange(info->debug_aranges, start, length, + dbgfmt_dwarf2->sizeof_address); + + return 0; +} + +yasm_section * +yasm_dwarf2__generate_aranges(yasm_object *object, yasm_section *debug_info) +{ + yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2 = (yasm_dbgfmt_dwarf2 *)object->dbgfmt; + int new; + yasm_section *debug_aranges; + yasm_bytecode *bc; + dwarf2_head *head; + dwarf2_aranges_info info; + + debug_aranges = + yasm_object_get_general(object, ".debug_aranges", + 2*dbgfmt_dwarf2->sizeof_address, 0, 0, &new, + 0); + + /* header */ + head = yasm_dwarf2__add_head(dbgfmt_dwarf2, debug_aranges, debug_info, 1, + 1); + + /* align ranges to 2x address size (range size) */ + bc = yasm_bc_create_align( + yasm_expr_create_ident(yasm_expr_int( + yasm_intnum_create_uint(dbgfmt_dwarf2->sizeof_address*2)), 0), + NULL, NULL, NULL, 0); + yasm_bc_finalize(bc, yasm_dwarf2__append_bc(debug_aranges, bc)); + yasm_bc_calc_len(bc, NULL, NULL); + + info.debug_aranges = debug_aranges; + info.object = object; + info.dbgfmt_dwarf2 = dbgfmt_dwarf2; + + yasm_object_sections_traverse(object, (void *)&info, + dwarf2_generate_aranges_section); + + /* Terminate with empty address range descriptor */ + dwarf2_append_arange(debug_aranges, + yasm_expr_create_ident(yasm_expr_int(yasm_intnum_create_uint(0)), 0), + yasm_expr_create_ident(yasm_expr_int(yasm_intnum_create_uint(0)), 0), + dbgfmt_dwarf2->sizeof_address); + + /* mark end of aranges information */ + yasm_dwarf2__set_head_end(head, yasm_section_bcs_last(debug_aranges)); + + return debug_aranges; +} + diff --git a/contrib/tools/yasm/modules/dbgfmts/dwarf2/dwarf2-dbgfmt.c b/contrib/tools/yasm/modules/dbgfmts/dwarf2/dwarf2-dbgfmt.c new file mode 100644 index 0000000000..5b66f8a70f --- /dev/null +++ b/contrib/tools/yasm/modules/dbgfmts/dwarf2/dwarf2-dbgfmt.c @@ -0,0 +1,348 @@ +/* + * DWARF2 debugging format + * + * Copyright (C) 2006-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 "dwarf2-dbgfmt.h" + +struct dwarf2_head { + yasm_bytecode *start_prevbc; + yasm_bytecode *end_prevbc; + /*@null@*/ yasm_section *debug_ptr; + int with_address; + int with_segment; +}; + +/* Bytecode callback function prototypes */ +static void dwarf2_head_bc_destroy(void *contents); +static void dwarf2_head_bc_print(const void *contents, FILE *f, + int indent_level); +static int dwarf2_head_bc_calc_len + (yasm_bytecode *bc, yasm_bc_add_span_func add_span, void *add_span_data); +static int dwarf2_head_bc_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 dwarf2_head_bc_callback = { + dwarf2_head_bc_destroy, + dwarf2_head_bc_print, + yasm_bc_finalize_common, + NULL, + dwarf2_head_bc_calc_len, + yasm_bc_expand_common, + dwarf2_head_bc_tobytes, + 0 +}; + +/* Section data callback function prototypes */ +static void dwarf2_section_data_destroy(void *data); +static void dwarf2_section_data_print(void *data, FILE *f, int indent_level); + +/* Section data callback */ +const yasm_assoc_data_callback yasm_dwarf2__section_data_cb = { + dwarf2_section_data_destroy, + dwarf2_section_data_print +}; + +yasm_dbgfmt_module yasm_dwarf2_LTX_dbgfmt; + + +static /*@null@*/ /*@only@*/ yasm_dbgfmt * +dwarf2_dbgfmt_create(yasm_object *object) +{ + yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2 = + yasm_xmalloc(sizeof(yasm_dbgfmt_dwarf2)); + size_t i; + + dbgfmt_dwarf2->dbgfmt.module = &yasm_dwarf2_LTX_dbgfmt; + + dbgfmt_dwarf2->dirs_allocated = 32; + dbgfmt_dwarf2->dirs_size = 0; + dbgfmt_dwarf2->dirs = + yasm_xmalloc(sizeof(char *)*dbgfmt_dwarf2->dirs_allocated); + + dbgfmt_dwarf2->filenames_allocated = 32; + dbgfmt_dwarf2->filenames_size = 0; + dbgfmt_dwarf2->filenames = + yasm_xmalloc(sizeof(dwarf2_filename)*dbgfmt_dwarf2->filenames_allocated); + for (i=0; i<dbgfmt_dwarf2->filenames_allocated; i++) { + dbgfmt_dwarf2->filenames[i].pathname = NULL; + dbgfmt_dwarf2->filenames[i].filename = NULL; + dbgfmt_dwarf2->filenames[i].dir = 0; + } + + dbgfmt_dwarf2->format = DWARF2_FORMAT_32BIT; /* TODO: flexible? */ + + dbgfmt_dwarf2->sizeof_address = yasm_arch_get_address_size(object->arch)/8; + switch (dbgfmt_dwarf2->format) { + case DWARF2_FORMAT_32BIT: + dbgfmt_dwarf2->sizeof_offset = 4; + break; + case DWARF2_FORMAT_64BIT: + dbgfmt_dwarf2->sizeof_offset = 8; + break; + } + dbgfmt_dwarf2->min_insn_len = yasm_arch_min_insn_len(object->arch); + + return (yasm_dbgfmt *)dbgfmt_dwarf2; +} + +static void +dwarf2_dbgfmt_destroy(/*@only@*/ yasm_dbgfmt *dbgfmt) +{ + yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2 = (yasm_dbgfmt_dwarf2 *)dbgfmt; + size_t i; + for (i=0; i<dbgfmt_dwarf2->dirs_size; i++) + if (dbgfmt_dwarf2->dirs[i]) + yasm_xfree(dbgfmt_dwarf2->dirs[i]); + yasm_xfree(dbgfmt_dwarf2->dirs); + for (i=0; i<dbgfmt_dwarf2->filenames_size; i++) { + if (dbgfmt_dwarf2->filenames[i].pathname) + yasm_xfree(dbgfmt_dwarf2->filenames[i].pathname); + if (dbgfmt_dwarf2->filenames[i].filename) + yasm_xfree(dbgfmt_dwarf2->filenames[i].filename); + } + yasm_xfree(dbgfmt_dwarf2->filenames); + yasm_xfree(dbgfmt); +} + +/* Add a bytecode to a section, updating offset on insertion; + * no optimization necessary. + */ +yasm_bytecode * +yasm_dwarf2__append_bc(yasm_section *sect, yasm_bytecode *bc) +{ + yasm_bytecode *precbc = yasm_section_bcs_last(sect); + bc->offset = yasm_bc_next_offset(precbc); + yasm_section_bcs_append(sect, bc); + return precbc; +} + +static void +dwarf2_dbgfmt_generate(yasm_object *object, yasm_linemap *linemap, + yasm_errwarns *errwarns) +{ + yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2 = (yasm_dbgfmt_dwarf2 *)object->dbgfmt; + size_t num_line_sections; + /*@null@*/ yasm_section *debug_info, *debug_line, *main_code; + + /* If we don't have any .file directives, generate line information + * based on the asm source. + */ + debug_line = yasm_dwarf2__generate_line(object, linemap, errwarns, + dbgfmt_dwarf2->filenames_size == 0, + &main_code, &num_line_sections); + + /* If we don't have a .debug_info (or it's empty), generate the minimal + * set of .debug_info, .debug_aranges, and .debug_abbrev so that the + * .debug_line we're generating is actually useful. + */ + debug_info = yasm_object_find_general(object, ".debug_info"); + if (num_line_sections > 0 && + (!debug_info || yasm_section_bcs_first(debug_info) + == yasm_section_bcs_last(debug_info))) { + debug_info = yasm_dwarf2__generate_info(object, debug_line, main_code); + yasm_dwarf2__generate_aranges(object, debug_info); + /*yasm_dwarf2__generate_pubnames(object, debug_info);*/ + } +} + +yasm_symrec * +yasm_dwarf2__bc_sym(yasm_symtab *symtab, yasm_bytecode *bc) +{ + /*@dependent@*/ yasm_symrec *sym; + if (bc->symrecs && bc->symrecs[0]) + sym = bc->symrecs[0]; + else + sym = yasm_symtab_define_label(symtab, ".bcsym", bc, 0, 0); + return sym; +} + +dwarf2_head * +yasm_dwarf2__add_head + (yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2, yasm_section *sect, + /*@null@*/ yasm_section *debug_ptr, int with_address, int with_segment) +{ + dwarf2_head *head; + yasm_bytecode *bc; + + head = yasm_xmalloc(sizeof(dwarf2_head)); + head->start_prevbc = yasm_section_bcs_last(sect); + + bc = yasm_bc_create_common(&dwarf2_head_bc_callback, head, 0); + bc->len = dbgfmt_dwarf2->sizeof_offset + 2; + if (dbgfmt_dwarf2->format == DWARF2_FORMAT_64BIT) + bc->len += 4; + + if (debug_ptr) { + head->debug_ptr = debug_ptr; + bc->len += dbgfmt_dwarf2->sizeof_offset; + } else + head->debug_ptr = NULL; + + head->with_address = with_address; + head->with_segment = with_segment; + if (with_address) + bc->len++; + if (with_segment) + bc->len++; + + head->end_prevbc = bc; + yasm_dwarf2__append_bc(sect, bc); + return head; +} + +void +yasm_dwarf2__set_head_end(dwarf2_head *head, yasm_bytecode *end_prevbc) +{ + head->end_prevbc = end_prevbc; +} + +static void +dwarf2_head_bc_destroy(void *contents) +{ + yasm_xfree(contents); +} + +static void +dwarf2_head_bc_print(const void *contents, FILE *f, int indent_level) +{ + /* TODO */ +} + +static int +dwarf2_head_bc_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span, + void *add_span_data) +{ + yasm_internal_error(N_("tried to calc_len a dwarf2 head bytecode")); + /*@notreached@*/ + return 0; +} + +static int +dwarf2_head_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp, + unsigned char *bufstart, void *d, + yasm_output_value_func output_value, + yasm_output_reloc_func output_reloc) +{ + yasm_object *object = yasm_section_get_object(bc->section); + yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2 = (yasm_dbgfmt_dwarf2 *)object->dbgfmt; + dwarf2_head *head = (dwarf2_head *)bc->contents; + unsigned char *buf = *bufp; + yasm_intnum *intn, *cval; + + if (dbgfmt_dwarf2->format == DWARF2_FORMAT_64BIT) { + YASM_WRITE_8(buf, 0xff); + YASM_WRITE_8(buf, 0xff); + YASM_WRITE_8(buf, 0xff); + YASM_WRITE_8(buf, 0xff); + } + + /* Total length of aranges info (following this field) */ + cval = yasm_intnum_create_uint(dbgfmt_dwarf2->sizeof_offset); + intn = yasm_calc_bc_dist(head->start_prevbc, head->end_prevbc); + yasm_intnum_calc(intn, YASM_EXPR_SUB, cval); + yasm_arch_intnum_tobytes(object->arch, intn, buf, + dbgfmt_dwarf2->sizeof_offset, + dbgfmt_dwarf2->sizeof_offset*8, 0, bc, 0); + buf += dbgfmt_dwarf2->sizeof_offset; + yasm_intnum_destroy(intn); + + /* DWARF version */ + yasm_intnum_set_uint(cval, 2); + yasm_arch_intnum_tobytes(object->arch, cval, buf, 2, 16, 0, bc, 0); + buf += 2; + + /* Pointer to another debug section */ + if (head->debug_ptr) { + yasm_value value; + yasm_value_init_sym(&value, + yasm_dwarf2__bc_sym(object->symtab, + yasm_section_bcs_first(head->debug_ptr)), + dbgfmt_dwarf2->sizeof_offset*8); + output_value(&value, buf, dbgfmt_dwarf2->sizeof_offset, + (unsigned long)(buf-bufstart), bc, 0, d); + buf += dbgfmt_dwarf2->sizeof_offset; + } + + /* Size of the offset portion of the address */ + if (head->with_address) + YASM_WRITE_8(buf, dbgfmt_dwarf2->sizeof_address); + + /* Size of a segment descriptor. 0 = flat address space */ + if (head->with_segment) + YASM_WRITE_8(buf, 0); + + *bufp = buf; + + yasm_intnum_destroy(cval); + return 0; +} + +static void +dwarf2_section_data_destroy(void *data) +{ + dwarf2_section_data *dsd = data; + dwarf2_loc *n1, *n2; + + /* Delete locations */ + n1 = STAILQ_FIRST(&dsd->locs); + while (n1) { + n2 = STAILQ_NEXT(n1, link); + yasm_xfree(n1); + n1 = n2; + } + + yasm_xfree(data); +} + +static void +dwarf2_section_data_print(void *data, FILE *f, int indent_level) +{ + /* TODO */ +} + +static const yasm_directive dwarf2_directives[] = { + { ".loc", "gas", yasm_dwarf2__dir_loc, YASM_DIR_ARG_REQUIRED }, + { ".file", "gas", yasm_dwarf2__dir_file, YASM_DIR_ARG_REQUIRED }, + { "loc", "nasm", yasm_dwarf2__dir_loc, YASM_DIR_ARG_REQUIRED }, + { "file", "nasm", yasm_dwarf2__dir_file, YASM_DIR_ARG_REQUIRED }, + { NULL, NULL, NULL, 0 } +}; + +/* Define dbgfmt structure -- see dbgfmt.h for details */ +yasm_dbgfmt_module yasm_dwarf2_LTX_dbgfmt = { + "DWARF2 debugging format", + "dwarf2", + dwarf2_directives, + dwarf2_dbgfmt_create, + dwarf2_dbgfmt_destroy, + dwarf2_dbgfmt_generate +}; diff --git a/contrib/tools/yasm/modules/dbgfmts/dwarf2/dwarf2-dbgfmt.h b/contrib/tools/yasm/modules/dbgfmts/dwarf2/dwarf2-dbgfmt.h new file mode 100644 index 0000000000..03752345cd --- /dev/null +++ b/contrib/tools/yasm/modules/dbgfmts/dwarf2/dwarf2-dbgfmt.h @@ -0,0 +1,131 @@ +/* + * DWARF2 debugging format + * + * Copyright (C) 2006-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_DWARF2_DBGFMT_H +#define YASM_DWARF2_DBGFMT_H + +#define WITH_DWARF3 1 + +typedef struct { + char *pathname; /* full filename */ + char *filename; /* basename of full filename */ + unsigned long dir; /* index into directories array for relative path; + * 0 for current directory. */ +} dwarf2_filename; + +/* Global data */ +typedef struct yasm_dbgfmt_dwarf2 { + yasm_dbgfmt_base dbgfmt; /* base structure */ + + char **dirs; + unsigned long dirs_size; + unsigned long dirs_allocated; + + dwarf2_filename *filenames; + unsigned long filenames_size; + unsigned long filenames_allocated; + + enum { + DWARF2_FORMAT_32BIT, + DWARF2_FORMAT_64BIT + } format; + + unsigned int sizeof_address, sizeof_offset, min_insn_len; +} yasm_dbgfmt_dwarf2; + +/* .loc directive data */ +typedef struct dwarf2_loc { + /*@reldef@*/ STAILQ_ENTRY(dwarf2_loc) link; + + unsigned long vline; /* virtual line number of .loc directive */ + + /* source information */ + unsigned long file; /* index into table of filenames */ + unsigned long line; /* source line number */ + unsigned long column; /* source column */ + unsigned long discriminator; + int isa_change; + unsigned long isa; + enum { + IS_STMT_NOCHANGE = 0, + IS_STMT_SET, + IS_STMT_CLEAR + } is_stmt; + int basic_block; + int prologue_end; + int epilogue_begin; + + yasm_bytecode *bc; /* first bytecode following */ + yasm_symrec *sym; /* last symbol preceding */ +} dwarf2_loc; + +/* Per-section data */ +typedef struct dwarf2_section_data { + /* The locations set by the .loc directives in this section, in assembly + * source order. + */ + /*@reldef@*/ STAILQ_HEAD(dwarf2_lochead, dwarf2_loc) locs; +} dwarf2_section_data; + +extern const yasm_assoc_data_callback yasm_dwarf2__section_data_cb; + +yasm_bytecode *yasm_dwarf2__append_bc(yasm_section *sect, yasm_bytecode *bc); + +/*@dependent@*/ yasm_symrec *yasm_dwarf2__bc_sym(yasm_symtab *symtab, + yasm_bytecode *bc); + +typedef struct dwarf2_head dwarf2_head; +dwarf2_head *yasm_dwarf2__add_head + (yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2, yasm_section *sect, + /*@null@*/ yasm_section *debug_ptr, int with_address, int with_segment); +void yasm_dwarf2__set_head_end(dwarf2_head *head, yasm_bytecode *end_prevbc); + +/* Line number functions */ +yasm_section *yasm_dwarf2__generate_line + (yasm_object *object, yasm_linemap *linemap, yasm_errwarns *errwarns, + int asm_source, /*@out@*/ yasm_section **main_code, + /*@out@*/ size_t *num_line_sections); +void yasm_dwarf2__dir_loc(yasm_object *object, yasm_valparamhead *valparams, + yasm_valparamhead *objext_valparams, + unsigned long line); +void yasm_dwarf2__dir_file(yasm_object *object, yasm_valparamhead *valparams, + yasm_valparamhead *objext_valparams, + unsigned long line); + +/* Address range table functions */ +yasm_section *yasm_dwarf2__generate_aranges(yasm_object *object, + yasm_section *debug_info); + +/* Name lookup table functions */ +yasm_section *yasm_dwarf2__generate_pubnames(yasm_object *object, + yasm_section *debug_info); + +/* Information functions */ +yasm_section *yasm_dwarf2__generate_info + (yasm_object *object, yasm_section *debug_line, + /*@null@*/ yasm_section *main_code); + +#endif diff --git a/contrib/tools/yasm/modules/dbgfmts/dwarf2/dwarf2-info.c b/contrib/tools/yasm/modules/dbgfmts/dwarf2/dwarf2-info.c new file mode 100644 index 0000000000..96d24db06a --- /dev/null +++ b/contrib/tools/yasm/modules/dbgfmts/dwarf2/dwarf2-info.c @@ -0,0 +1,438 @@ +/* + * DWARF2 debugging format - info and abbreviation tables + * + * Copyright (C) 2006-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 "dwarf2-dbgfmt.h" + +#define DW_LANG_Mips_Assembler 0x8001 + +/* Tag encodings */ +typedef enum { + DW_TAG_padding = 0x00, + DW_TAG_array_type = 0x01, + DW_TAG_class_type = 0x02, + DW_TAG_entry_point = 0x03, + DW_TAG_enumeration_type = 0x04, + DW_TAG_formal_parameter = 0x05, + DW_TAG_imported_declaration = 0x08, + DW_TAG_label = 0x0a, + DW_TAG_lexical_block = 0x0b, + DW_TAG_member = 0x0d, + DW_TAG_pointer_type = 0x0f, + DW_TAG_reference_type = 0x10, + DW_TAG_compile_unit = 0x11, + DW_TAG_string_type = 0x12, + DW_TAG_structure_type = 0x13, + DW_TAG_subroutine_type = 0x15, + DW_TAG_typedef = 0x16, + DW_TAG_union_type = 0x17, + DW_TAG_unspecified_parameters = 0x18, + DW_TAG_variant = 0x19, + DW_TAG_common_block = 0x1a, + DW_TAG_common_inclusion = 0x1b, + DW_TAG_inheritance = 0x1c, + DW_TAG_inlined_subroutine = 0x1d, + DW_TAG_module = 0x1e, + DW_TAG_ptr_to_member_type = 0x1f, + DW_TAG_set_type = 0x20, + DW_TAG_subrange_type = 0x21, + DW_TAG_with_stmt = 0x22, + DW_TAG_access_declaration = 0x23, + DW_TAG_base_type = 0x24, + DW_TAG_catch_block = 0x25, + DW_TAG_const_type = 0x26, + DW_TAG_constant = 0x27, + DW_TAG_enumerator = 0x28, + DW_TAG_file_type = 0x29, + DW_TAG_friend = 0x2a, + DW_TAG_namelist = 0x2b, + DW_TAG_namelist_item = 0x2c, + DW_TAG_packed_type = 0x2d, + DW_TAG_subprogram = 0x2e, + DW_TAG_template_type_param = 0x2f, + DW_TAG_template_value_param = 0x30, + DW_TAG_thrown_type = 0x31, + DW_TAG_try_block = 0x32, + DW_TAG_variant_part = 0x33, + DW_TAG_variable = 0x34, + DW_TAG_volatile_type = 0x35 +} dwarf_tag; + +/* Attribute form encodings */ +typedef enum { + DW_FORM_addr = 0x01, + DW_FORM_block2 = 0x03, + DW_FORM_block4 = 0x04, + DW_FORM_data2 = 0x05, + DW_FORM_data4 = 0x06, + DW_FORM_data8 = 0x07, + DW_FORM_string = 0x08, + DW_FORM_block = 0x09, + DW_FORM_block1 = 0x0a, + DW_FORM_data1 = 0x0b, + DW_FORM_flag = 0x0c, + DW_FORM_sdata = 0x0d, + DW_FORM_strp = 0x0e, + DW_FORM_udata = 0x0f, + DW_FORM_ref_addr = 0x10, + DW_FORM_ref1 = 0x11, + DW_FORM_ref2 = 0x12, + DW_FORM_ref4 = 0x13, + DW_FORM_ref8 = 0x14, + DW_FORM_ref_udata = 0x15, + DW_FORM_indirect = 0x16 +} dwarf_form; + +/* Attribute encodings */ +typedef enum { + DW_AT_sibling = 0x01, + DW_AT_location = 0x02, + DW_AT_name = 0x03, + DW_AT_ordering = 0x09, + DW_AT_subscr_data = 0x0a, + DW_AT_byte_size = 0x0b, + DW_AT_bit_offset = 0x0c, + DW_AT_bit_size = 0x0d, + DW_AT_element_list = 0x0f, + DW_AT_stmt_list = 0x10, + DW_AT_low_pc = 0x11, + DW_AT_high_pc = 0x12, + DW_AT_language = 0x13, + DW_AT_member = 0x14, + DW_AT_discr = 0x15, + DW_AT_discr_value = 0x16, + DW_AT_visibility = 0x17, + DW_AT_import = 0x18, + DW_AT_string_length = 0x19, + DW_AT_common_reference = 0x1a, + DW_AT_comp_dir = 0x1b, + DW_AT_const_value = 0x1c, + DW_AT_containing_type = 0x1d, + DW_AT_default_value = 0x1e, + DW_AT_inline = 0x20, + DW_AT_is_optional = 0x21, + DW_AT_lower_bound = 0x22, + DW_AT_producer = 0x25, + DW_AT_prototyped = 0x27, + DW_AT_return_addr = 0x2a, + DW_AT_start_scope = 0x2c, + DW_AT_stride_size = 0x2e, + DW_AT_upper_bound = 0x2f, + DW_AT_abstract_origin = 0x31, + DW_AT_accessibility = 0x32, + DW_AT_address_class = 0x33, + DW_AT_artificial = 0x34, + DW_AT_base_types = 0x35, + DW_AT_calling_convention = 0x36, + DW_AT_count = 0x37, + DW_AT_data_member_location = 0x38, + DW_AT_decl_column = 0x39, + DW_AT_decl_file = 0x3a, + DW_AT_decl_line = 0x3b, + DW_AT_declaration = 0x3c, + DW_AT_discr_list = 0x3d, + DW_AT_encoding = 0x3e, + DW_AT_external = 0x3f, + DW_AT_frame_base = 0x40, + DW_AT_friend = 0x41, + DW_AT_identifier_case = 0x42, + DW_AT_macro_info = 0x43, + DW_AT_namelist_items = 0x44, + DW_AT_priority = 0x45, + DW_AT_segment = 0x46, + DW_AT_specification = 0x47, + DW_AT_static_link = 0x48, + DW_AT_type = 0x49, + DW_AT_use_location = 0x4a, + DW_AT_variable_parameter = 0x4b, + DW_AT_virtuality = 0x4c, + DW_AT_vtable_elem_location = 0x4d +} dwarf_attribute; + +typedef struct dwarf2_abbrev_attr { + STAILQ_ENTRY(dwarf2_abbrev_attr) link; + dwarf_attribute name; + dwarf_form form; +} dwarf2_abbrev_attr; + +typedef struct dwarf2_abbrev { + unsigned long id; + dwarf_tag tag; + int has_children; + STAILQ_HEAD(dwarf2_abbrev_attrhead, dwarf2_abbrev_attr) attrs; +} dwarf2_abbrev; + +/* Bytecode callback function prototypes */ + +static void dwarf2_abbrev_bc_destroy(void *contents); +static void dwarf2_abbrev_bc_print(const void *contents, FILE *f, + int indent_level); +static int dwarf2_abbrev_bc_calc_len + (yasm_bytecode *bc, yasm_bc_add_span_func add_span, void *add_span_data); +static int dwarf2_abbrev_bc_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 dwarf2_abbrev_bc_callback = { + dwarf2_abbrev_bc_destroy, + dwarf2_abbrev_bc_print, + yasm_bc_finalize_common, + NULL, + dwarf2_abbrev_bc_calc_len, + yasm_bc_expand_common, + dwarf2_abbrev_bc_tobytes, + 0 +}; + + +static unsigned long +dwarf2_add_abbrev_attr(dwarf2_abbrev *abbrev, dwarf_attribute name, + dwarf_form form) +{ + dwarf2_abbrev_attr *attr = yasm_xmalloc(sizeof(dwarf2_abbrev_attr)); + attr->name = name; + attr->form = form; + STAILQ_INSERT_TAIL(&abbrev->attrs, attr, link); + return yasm_size_uleb128(name) + yasm_size_uleb128(form); +} + +static void +dwarf2_append_expr(yasm_section *sect, /*@only@*/ yasm_expr *expr, + unsigned int size, int leb) +{ + yasm_datavalhead dvs; + yasm_bytecode *bc; + + yasm_dvs_initialize(&dvs); + yasm_dvs_append(&dvs, yasm_dv_create_expr(expr)); + if (leb == 0) + bc = yasm_bc_create_data(&dvs, size, 0, NULL, 0); + else + bc = yasm_bc_create_leb128(&dvs, leb<0, 0); + yasm_bc_finalize(bc, yasm_dwarf2__append_bc(sect, bc)); + yasm_bc_calc_len(bc, NULL, NULL); +} + +static void +dwarf2_append_str(yasm_section *sect, const char *str) +{ + yasm_datavalhead dvs; + yasm_bytecode *bc; + + yasm_dvs_initialize(&dvs); + yasm_dvs_append(&dvs, yasm_dv_create_string(yasm__xstrdup(str), + strlen(str))); + bc = yasm_bc_create_data(&dvs, 1, 1, NULL, 0); + yasm_bc_finalize(bc, yasm_dwarf2__append_bc(sect, bc)); + yasm_bc_calc_len(bc, NULL, NULL); +} + +yasm_section * +yasm_dwarf2__generate_info(yasm_object *object, yasm_section *debug_line, + yasm_section *main_code) +{ + yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2 = (yasm_dbgfmt_dwarf2 *)object->dbgfmt; + int new; + yasm_bytecode *abc; + dwarf2_abbrev *abbrev; + dwarf2_head *head; + char *buf; + yasm_section *debug_abbrev = + yasm_object_get_general(object, ".debug_abbrev", 4, 0, 0, &new, 0); + yasm_section *debug_info = + yasm_object_get_general(object, ".debug_info", 4, 0, 0, &new, 0); + + yasm_section_set_align(debug_abbrev, 0, 0); + yasm_section_set_align(debug_info, 0, 0); + + /* Create abbreviation table entry for compilation unit */ + abbrev = yasm_xmalloc(sizeof(dwarf2_abbrev)); + abc = yasm_bc_create_common(&dwarf2_abbrev_bc_callback, abbrev, 0); + abbrev->id = 1; + abbrev->tag = DW_TAG_compile_unit; + abbrev->has_children = 0; + abc->len = yasm_size_uleb128(abbrev->id) + yasm_size_uleb128(abbrev->tag) + + 3; + STAILQ_INIT(&abbrev->attrs); + yasm_dwarf2__append_bc(debug_abbrev, abc); + + /* info header */ + head = yasm_dwarf2__add_head(dbgfmt_dwarf2, debug_info, debug_abbrev, 1, 0); + + /* Generate abbreviations at the same time as info (since they're linked + * and we're only generating one piece of info). + */ + + /* generating info using abbrev 1 */ + dwarf2_append_expr(debug_info, + yasm_expr_create_ident(yasm_expr_int(yasm_intnum_create_uint(1)), 0), + 0, 1); + + /* statement list (line numbers) */ + abc->len += dwarf2_add_abbrev_attr(abbrev, DW_AT_stmt_list, DW_FORM_data4); + dwarf2_append_expr(debug_info, + yasm_expr_create_ident(yasm_expr_sym( + yasm_dwarf2__bc_sym(object->symtab, + yasm_section_bcs_first(debug_line))), 0), + dbgfmt_dwarf2->sizeof_offset, 0); + + if (main_code) { + yasm_symrec *first; + first = yasm_dwarf2__bc_sym(object->symtab, + yasm_section_bcs_first(main_code)); + /* All code is contiguous in one section */ + abc->len += dwarf2_add_abbrev_attr(abbrev, DW_AT_low_pc, DW_FORM_addr); + dwarf2_append_expr(debug_info, + yasm_expr_create_ident(yasm_expr_sym(first), 0), + dbgfmt_dwarf2->sizeof_address, 0); + + abc->len += dwarf2_add_abbrev_attr(abbrev, DW_AT_high_pc, DW_FORM_addr); + dwarf2_append_expr(debug_info, + yasm_expr_create(YASM_EXPR_ADD, yasm_expr_sym(first), + yasm_expr_int(yasm_calc_bc_dist( + yasm_section_bcs_first(main_code), + yasm_section_bcs_last(main_code))), 0), + dbgfmt_dwarf2->sizeof_address, 0); + } + + /* input filename */ + abc->len += dwarf2_add_abbrev_attr(abbrev, DW_AT_name, DW_FORM_string); + if (!object->deb_filename) { + object->deb_filename = yasm_replace_path( + dbgfmt_dwarf2->dbgfmt.module->replace_map, dbgfmt_dwarf2->dbgfmt.module->replace_map_size, + object->src_filename, strlen(object->src_filename)); + } + dwarf2_append_str(debug_info, object->deb_filename); + + /* compile directory (current working directory) */ + abc->len += dwarf2_add_abbrev_attr(abbrev, DW_AT_comp_dir, DW_FORM_string); + buf = yasm__getcwd(); + char * new_cwd_name = yasm_replace_path( + dbgfmt_dwarf2->dbgfmt.module->replace_map, dbgfmt_dwarf2->dbgfmt.module->replace_map_size, + buf, strlen(buf)); + dwarf2_append_str(debug_info, new_cwd_name); + yasm_xfree(new_cwd_name); + yasm_xfree(buf); + + /* producer - assembler name */ + abc->len += dwarf2_add_abbrev_attr(abbrev, DW_AT_producer, DW_FORM_string); + if (getenv("YASM_TEST_SUITE")) + dwarf2_append_str(debug_info, "yasm HEAD"); + else + dwarf2_append_str(debug_info, PACKAGE_STRING); + + /* language - no standard code for assembler, use MIPS as a substitute */ + abc->len += dwarf2_add_abbrev_attr(abbrev, DW_AT_language, DW_FORM_data2); + dwarf2_append_expr(debug_info, + yasm_expr_create_ident(yasm_expr_int( + yasm_intnum_create_uint(DW_LANG_Mips_Assembler)), 0), 2, 0); + + /* Terminate list of abbreviations */ + abbrev = yasm_xmalloc(sizeof(dwarf2_abbrev)); + abc = yasm_bc_create_common(&dwarf2_abbrev_bc_callback, abbrev, 0); + abbrev->id = 0; + abbrev->tag = 0; + abbrev->has_children = 0; + STAILQ_INIT(&abbrev->attrs); + abc->len = 1; + yasm_dwarf2__append_bc(debug_abbrev, abc); + + /* mark end of info */ + yasm_dwarf2__set_head_end(head, yasm_section_bcs_last(debug_info)); + + return debug_info; +} + +static void +dwarf2_abbrev_bc_destroy(void *contents) +{ + dwarf2_abbrev *abbrev = (dwarf2_abbrev *)contents; + dwarf2_abbrev_attr *n1, *n2; + + /* Delete attributes */ + n1 = STAILQ_FIRST(&abbrev->attrs); + while (n1) { + n2 = STAILQ_NEXT(n1, link); + yasm_xfree(n1); + n1 = n2; + } + + yasm_xfree(contents); +} + +static void +dwarf2_abbrev_bc_print(const void *contents, FILE *f, int indent_level) +{ + /* TODO */ +} + +static int +dwarf2_abbrev_bc_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span, + void *add_span_data) +{ + yasm_internal_error(N_("tried to calc_len a dwarf2 aranges head bytecode")); + /*@notreached@*/ + return 0; +} + +static int +dwarf2_abbrev_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp, + unsigned char *bufstart, void *d, + yasm_output_value_func output_value, + yasm_output_reloc_func output_reloc) +{ + dwarf2_abbrev *abbrev = (dwarf2_abbrev *)bc->contents; + unsigned char *buf = *bufp; + dwarf2_abbrev_attr *attr; + + if (abbrev->id == 0) { + YASM_WRITE_8(buf, 0); + *bufp = buf; + return 0; + } + + buf += yasm_get_uleb128(abbrev->id, buf); + buf += yasm_get_uleb128(abbrev->tag, buf); + YASM_WRITE_8(buf, abbrev->has_children); + + STAILQ_FOREACH(attr, &abbrev->attrs, link) { + buf += yasm_get_uleb128(attr->name, buf); + buf += yasm_get_uleb128(attr->form, buf); + } + + YASM_WRITE_8(buf, 0); + YASM_WRITE_8(buf, 0); + + *bufp = buf; + return 0; +} + diff --git a/contrib/tools/yasm/modules/dbgfmts/dwarf2/dwarf2-line.c b/contrib/tools/yasm/modules/dbgfmts/dwarf2/dwarf2-line.c new file mode 100644 index 0000000000..14639ca429 --- /dev/null +++ b/contrib/tools/yasm/modules/dbgfmts/dwarf2/dwarf2-line.c @@ -0,0 +1,1156 @@ +/* + * DWARF2 debugging format - line information + * + * Copyright (C) 2006-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. + * 3. Neither the name of the author nor the names of other contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 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 "dwarf2-dbgfmt.h" + +/* DWARF line number opcodes */ +typedef enum { + DW_LNS_extended_op = 0, + DW_LNS_copy, + DW_LNS_advance_pc, + DW_LNS_advance_line, + DW_LNS_set_file, + DW_LNS_set_column, + DW_LNS_negate_stmt, + DW_LNS_set_basic_block, + DW_LNS_const_add_pc, + DW_LNS_fixed_advance_pc, +#ifdef WITH_DWARF3 + /* DWARF 3 extensions */ + DW_LNS_set_prologue_end, + DW_LNS_set_epilogue_begin, + DW_LNS_set_isa, +#endif + DWARF2_LINE_OPCODE_BASE +} dwarf_line_number_op; + +/* # of LEB128 operands needed for each of the above opcodes */ +static unsigned char line_opcode_num_operands[DWARF2_LINE_OPCODE_BASE-1] = { + 0, /* DW_LNS_copy */ + 1, /* DW_LNS_advance_pc */ + 1, /* DW_LNS_advance_line */ + 1, /* DW_LNS_set_file */ + 1, /* DW_LNS_set_column */ + 0, /* DW_LNS_negate_stmt */ + 0, /* DW_LNS_set_basic_block */ + 0, /* DW_LNS_const_add_pc */ + 1, /* DW_LNS_fixed_advance_pc */ +#ifdef WITH_DWARF3 + 0, /* DW_LNS_set_prologue_end */ + 0, /* DW_LNS_set_epilogue_begin */ + 1 /* DW_LNS_set_isa */ +#endif +}; + +/* Line number extended opcodes */ +typedef enum { + DW_LNE_end_sequence = 1, + DW_LNE_set_address, + DW_LNE_define_file, + DW_LNE_set_discriminator +} dwarf_line_number_ext_op; + +/* Base and range for line offsets in special opcodes */ +#define DWARF2_LINE_BASE -5 +#define DWARF2_LINE_RANGE 14 + +#define DWARF2_MAX_SPECIAL_ADDR_DELTA \ + (((255-DWARF2_LINE_OPCODE_BASE)/DWARF2_LINE_RANGE)*\ + dbgfmt_dwarf2->min_insn_len) + +/* Initial value of is_stmt register */ +#define DWARF2_LINE_DEFAULT_IS_STMT 1 + +/* Line number state machine register state */ +typedef struct dwarf2_line_state { + /* static configuration */ + yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2; + + /* DWARF2 state machine registers */ + unsigned long address; + unsigned long file; + unsigned long line; + unsigned long column; + unsigned long isa; + int is_stmt; + + /* other state information */ + /*@null@*/ yasm_bytecode *precbc; +} dwarf2_line_state; + +typedef struct dwarf2_spp { + yasm_bytecode *line_start_prevbc; + yasm_bytecode *line_end_prevbc; +} dwarf2_spp; + +typedef struct dwarf2_line_op { + dwarf_line_number_op opcode; + /*@owned@*/ /*@null@*/ yasm_intnum *operand; + + /* extended opcode */ + dwarf_line_number_ext_op ext_opcode; + /*@null@*/ /*@dependent@*/ yasm_symrec *ext_operand; /* unsigned */ + /*@null@*/ /*@dependent@*/ yasm_intnum *ext_operand_int; /* unsigned */ + unsigned long ext_operandsize; +} dwarf2_line_op; + +/* Bytecode callback function prototypes */ +static void dwarf2_spp_bc_destroy(void *contents); +static void dwarf2_spp_bc_print(const void *contents, FILE *f, + int indent_level); +static int dwarf2_spp_bc_calc_len + (yasm_bytecode *bc, yasm_bc_add_span_func add_span, void *add_span_data); +static int dwarf2_spp_bc_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 dwarf2_line_op_bc_destroy(void *contents); +static void dwarf2_line_op_bc_print(const void *contents, FILE *f, + int indent_level); +static int dwarf2_line_op_bc_calc_len + (yasm_bytecode *bc, yasm_bc_add_span_func add_span, void *add_span_data); +static int dwarf2_line_op_bc_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 dwarf2_spp_bc_callback = { + dwarf2_spp_bc_destroy, + dwarf2_spp_bc_print, + yasm_bc_finalize_common, + NULL, + dwarf2_spp_bc_calc_len, + yasm_bc_expand_common, + dwarf2_spp_bc_tobytes, + 0 +}; + +static const yasm_bytecode_callback dwarf2_line_op_bc_callback = { + dwarf2_line_op_bc_destroy, + dwarf2_line_op_bc_print, + yasm_bc_finalize_common, + NULL, + dwarf2_line_op_bc_calc_len, + yasm_bc_expand_common, + dwarf2_line_op_bc_tobytes, + 0 +}; + + +static size_t +dwarf2_dbgfmt_add_file(yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2, unsigned long filenum, + const char *pathname) +{ + size_t dirlen; + const char *filename; + unsigned long i, dir; + + /* Put the directory into the directory table */ + dir = 0; + dirlen = yasm__splitpath(pathname, &filename); + if (dirlen > 0) { + /* Look to see if we already have that dir in the table */ + for (dir=1; dir<dbgfmt_dwarf2->dirs_size+1; dir++) { + if (strncmp(dbgfmt_dwarf2->dirs[dir-1], pathname, dirlen) == 0 + && dbgfmt_dwarf2->dirs[dir-1][dirlen] == '\0') + break; + } + if (dir >= dbgfmt_dwarf2->dirs_size+1) { + /* Not found in table, add to end, reallocing if necessary */ + if (dir >= dbgfmt_dwarf2->dirs_allocated+1) { + dbgfmt_dwarf2->dirs_allocated = dir+32; + dbgfmt_dwarf2->dirs = yasm_xrealloc(dbgfmt_dwarf2->dirs, + sizeof(char *)*dbgfmt_dwarf2->dirs_allocated); + } + dbgfmt_dwarf2->dirs[dir-1] = yasm__xstrndup(pathname, dirlen); + dbgfmt_dwarf2->dirs_size = dir; + } + } + + /* Put the filename into the filename table */ + if (filenum == 0) { + /* Look to see if we already have that filename in the table */ + for (; filenum<dbgfmt_dwarf2->filenames_size; filenum++) { + if (!dbgfmt_dwarf2->filenames[filenum].filename || + (dbgfmt_dwarf2->filenames[filenum].dir == dir + && strcmp(dbgfmt_dwarf2->filenames[filenum].filename, + filename) == 0)) + break; + } + } else + filenum--; /* array index is 0-based */ + + /* Realloc table if necessary */ + if (filenum >= dbgfmt_dwarf2->filenames_allocated) { + unsigned long old_allocated = dbgfmt_dwarf2->filenames_allocated; + dbgfmt_dwarf2->filenames_allocated = filenum+32; + dbgfmt_dwarf2->filenames = yasm_xrealloc(dbgfmt_dwarf2->filenames, + sizeof(dwarf2_filename)*dbgfmt_dwarf2->filenames_allocated); + for (i=old_allocated; i<dbgfmt_dwarf2->filenames_allocated; i++) { + dbgfmt_dwarf2->filenames[i].pathname = NULL; + dbgfmt_dwarf2->filenames[i].filename = NULL; + dbgfmt_dwarf2->filenames[i].dir = 0; + } + } + + /* Actually save in table */ + if (dbgfmt_dwarf2->filenames[filenum].pathname) + yasm_xfree(dbgfmt_dwarf2->filenames[filenum].pathname); + if (dbgfmt_dwarf2->filenames[filenum].filename) + yasm_xfree(dbgfmt_dwarf2->filenames[filenum].filename); + dbgfmt_dwarf2->filenames[filenum].pathname = yasm__xstrdup(pathname); + dbgfmt_dwarf2->filenames[filenum].filename = yasm__xstrdup(filename); + dbgfmt_dwarf2->filenames[filenum].dir = dir; + + /* Update table size */ + if (filenum >= dbgfmt_dwarf2->filenames_size) + dbgfmt_dwarf2->filenames_size = filenum + 1; + + return filenum; +} + +/* Create and add a new line opcode to a section, updating offset on insertion; + * no optimization necessary. + */ +static yasm_bytecode * +dwarf2_dbgfmt_append_line_op(yasm_section *sect, dwarf_line_number_op opcode, + /*@only@*/ /*@null@*/ yasm_intnum *operand) +{ + dwarf2_line_op *line_op = yasm_xmalloc(sizeof(dwarf2_line_op)); + yasm_bytecode *bc; + + line_op->opcode = opcode; + line_op->operand = operand; + line_op->ext_opcode = 0; + line_op->ext_operand = NULL; + line_op->ext_operand_int = NULL; + line_op->ext_operandsize = 0; + + bc = yasm_bc_create_common(&dwarf2_line_op_bc_callback, line_op, 0); + bc->len = 1; + if (operand) + bc->len += yasm_intnum_size_leb128(operand, + opcode == DW_LNS_advance_line); + + yasm_dwarf2__append_bc(sect, bc); + return bc; +} + +/* Create and add a new extended line opcode to a section, updating offset on + * insertion; no optimization necessary. + */ +static yasm_bytecode * +dwarf2_dbgfmt_append_line_ext_op(yasm_section *sect, + dwarf_line_number_ext_op ext_opcode, + unsigned long ext_operandsize, + /*@null@*/ yasm_symrec *ext_operand) +{ + dwarf2_line_op *line_op = yasm_xmalloc(sizeof(dwarf2_line_op)); + yasm_bytecode *bc; + + line_op->opcode = DW_LNS_extended_op; + line_op->operand = yasm_intnum_create_uint(ext_operandsize+1); + line_op->ext_opcode = ext_opcode; + line_op->ext_operand = ext_operand; + line_op->ext_operand_int = NULL; + line_op->ext_operandsize = ext_operandsize; + + bc = yasm_bc_create_common(&dwarf2_line_op_bc_callback, line_op, 0); + bc->len = 2 + yasm_intnum_size_leb128(line_op->operand, 0) + + ext_operandsize; + + yasm_dwarf2__append_bc(sect, bc); + return bc; +} + +static yasm_bytecode * +dwarf2_dbgfmt_append_line_ext_op_int(yasm_section *sect, + dwarf_line_number_ext_op ext_opcode, + /*@only@*/ yasm_intnum *ext_operand) +{ + dwarf2_line_op *line_op = yasm_xmalloc(sizeof(dwarf2_line_op)); + unsigned long ext_operandsize = yasm_intnum_size_leb128(ext_operand, 0); + yasm_bytecode *bc; + + line_op->opcode = DW_LNS_extended_op; + line_op->operand = yasm_intnum_create_uint(ext_operandsize+1); + line_op->ext_opcode = ext_opcode; + line_op->ext_operand = NULL; + line_op->ext_operand_int = ext_operand; + line_op->ext_operandsize = ext_operandsize; + + bc = yasm_bc_create_common(&dwarf2_line_op_bc_callback, line_op, 0); + bc->len = 2 + yasm_intnum_size_leb128(line_op->operand, 0) + + ext_operandsize; + + yasm_dwarf2__append_bc(sect, bc); + return bc; +} + +static void +dwarf2_dbgfmt_finalize_locs(yasm_section *sect, dwarf2_section_data *dsd) +{ + /*@dependent@*/ yasm_symrec *lastsym = NULL; + /*@null@*/ yasm_bytecode *bc; + /*@null@*/ dwarf2_loc *loc; + + bc = yasm_section_bcs_first(sect); + STAILQ_FOREACH(loc, &dsd->locs, link) { + /* Find the first bytecode following this loc by looking at + * the virtual line numbers. XXX: this assumes the source file + * order will be the same as the actual section order. If we ever + * implement subsegs this will NOT necessarily be true and this logic + * will need to be fixed to handle it! + * + * Keep track of last symbol seen prior to the loc. + */ + while (bc && bc->line <= loc->vline) { + if (bc->symrecs) { + int i = 0; + while (bc->symrecs[i]) { + lastsym = bc->symrecs[i]; + i++; + } + } + bc = yasm_bc__next(bc); + } + loc->sym = lastsym; + loc->bc = bc; + } +} + +static int +dwarf2_dbgfmt_gen_line_op(yasm_section *debug_line, dwarf2_line_state *state, + const dwarf2_loc *loc, + /*@null@*/ const dwarf2_loc *nextloc) +{ + unsigned long addr_delta; + long line_delta; + int opcode1, opcode2; + yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2 = state->dbgfmt_dwarf2; + + if (state->file != loc->file) { + state->file = loc->file; + dwarf2_dbgfmt_append_line_op(debug_line, DW_LNS_set_file, + yasm_intnum_create_uint(state->file)); + } + if (state->column != loc->column) { + state->column = loc->column; + dwarf2_dbgfmt_append_line_op(debug_line, DW_LNS_set_column, + yasm_intnum_create_uint(state->column)); + } + if (loc->discriminator != 0) { + dwarf2_dbgfmt_append_line_ext_op_int(debug_line, + DW_LNE_set_discriminator, + yasm_intnum_create_uint(loc->discriminator)); + } +#ifdef WITH_DWARF3 + if (loc->isa_change) { + state->isa = loc->isa; + dwarf2_dbgfmt_append_line_op(debug_line, DW_LNS_set_isa, + yasm_intnum_create_uint(state->isa)); + } +#endif + if (state->is_stmt == 0 && loc->is_stmt == IS_STMT_SET) { + state->is_stmt = 1; + dwarf2_dbgfmt_append_line_op(debug_line, DW_LNS_negate_stmt, NULL); + } else if (state->is_stmt == 1 && loc->is_stmt == IS_STMT_CLEAR) { + state->is_stmt = 0; + dwarf2_dbgfmt_append_line_op(debug_line, DW_LNS_negate_stmt, NULL); + } + if (loc->basic_block) { + dwarf2_dbgfmt_append_line_op(debug_line, DW_LNS_set_basic_block, NULL); + } +#ifdef WITH_DWARF3 + if (loc->prologue_end) { + dwarf2_dbgfmt_append_line_op(debug_line, DW_LNS_set_prologue_end, NULL); + } + if (loc->epilogue_begin) { + dwarf2_dbgfmt_append_line_op(debug_line, DW_LNS_set_epilogue_begin, + NULL); + } +#endif + + /* If multiple loc for the same location, use last */ + if (nextloc && nextloc->bc->offset == loc->bc->offset) + return 0; + + if (!state->precbc) { + /* Set the starting address for the section */ + if (!loc->sym) { + /* shouldn't happen! */ + yasm_error_set(YASM_ERROR_GENERAL, + N_("could not find label prior to loc")); + return 1; + } + dwarf2_dbgfmt_append_line_ext_op(debug_line, DW_LNE_set_address, + dbgfmt_dwarf2->sizeof_address, loc->sym); + addr_delta = 0; + } else if (loc->bc) { + if (state->precbc->offset > loc->bc->offset) + yasm_internal_error(N_("dwarf2 address went backwards?")); + addr_delta = loc->bc->offset - state->precbc->offset; + } else + return 0; /* ran out of bytecodes! XXX: do something? */ + + /* Generate appropriate opcode(s). Address can only increment, + * whereas line number can go backwards. + */ + line_delta = loc->line - state->line; + state->line = loc->line; + + /* First handle the line delta */ + if (line_delta < DWARF2_LINE_BASE + || line_delta >= DWARF2_LINE_BASE+DWARF2_LINE_RANGE) { + /* Won't fit in special opcode, use (signed) line advance */ + dwarf2_dbgfmt_append_line_op(debug_line, DW_LNS_advance_line, + yasm_intnum_create_int(line_delta)); + line_delta = 0; + } + + /* Next handle the address delta */ + opcode1 = DWARF2_LINE_OPCODE_BASE + line_delta - DWARF2_LINE_BASE + + DWARF2_LINE_RANGE * (addr_delta / dbgfmt_dwarf2->min_insn_len); + opcode2 = DWARF2_LINE_OPCODE_BASE + line_delta - DWARF2_LINE_BASE + + DWARF2_LINE_RANGE * ((addr_delta - DWARF2_MAX_SPECIAL_ADDR_DELTA) / + dbgfmt_dwarf2->min_insn_len); + if (line_delta == 0 && addr_delta == 0) { + /* Both line and addr deltas are 0: do DW_LNS_copy */ + dwarf2_dbgfmt_append_line_op(debug_line, DW_LNS_copy, NULL); + } else if (addr_delta <= DWARF2_MAX_SPECIAL_ADDR_DELTA && opcode1 <= 255) { + /* Addr delta in range of special opcode */ + dwarf2_dbgfmt_append_line_op(debug_line, opcode1, NULL); + } else if (addr_delta <= 2*DWARF2_MAX_SPECIAL_ADDR_DELTA + && opcode2 <= 255) { + /* Addr delta in range of const_add_pc + special */ + dwarf2_dbgfmt_append_line_op(debug_line, DW_LNS_const_add_pc, NULL); + dwarf2_dbgfmt_append_line_op(debug_line, opcode2, NULL); + } else { + /* Need advance_pc */ + dwarf2_dbgfmt_append_line_op(debug_line, DW_LNS_advance_pc, + yasm_intnum_create_uint(addr_delta)); + /* Take care of any remaining line_delta and add entry to matrix */ + if (line_delta == 0) + dwarf2_dbgfmt_append_line_op(debug_line, DW_LNS_copy, NULL); + else { + unsigned int opcode; + opcode = DWARF2_LINE_OPCODE_BASE + line_delta - DWARF2_LINE_BASE; + dwarf2_dbgfmt_append_line_op(debug_line, opcode, NULL); + } + } + state->precbc = loc->bc; + return 0; +} + +typedef struct dwarf2_line_bc_info { + yasm_section *debug_line; + yasm_object *object; + yasm_linemap *linemap; + yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2; + dwarf2_line_state *state; + dwarf2_loc loc; + unsigned long lastfile; +} dwarf2_line_bc_info; + +static int +dwarf2_filename_equals(const dwarf2_filename *fn, + char **dirs, + const char *pathname, + unsigned long dirlen, + const char *filename) +{ + /* check directory */ + if (fn->dir == 0) { + if (dirlen != 0) + return 0; + } else { + if (strncmp(dirs[fn->dir-1], pathname, dirlen) != 0 || + dirs[fn->dir-1][dirlen] != '\0') + return 0; + } + + /* check filename */ + return strcmp(fn->filename, filename) == 0; +} + +static int +dwarf2_generate_line_bc(yasm_bytecode *bc, /*@null@*/ void *d) +{ + dwarf2_line_bc_info *info = (dwarf2_line_bc_info *)d; + yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2 = info->dbgfmt_dwarf2; + unsigned long i; + size_t dirlen; + const char *pathname, *filename; + /*@null@*/ yasm_bytecode *nextbc = yasm_bc__next(bc); + + if (nextbc && bc->offset == nextbc->offset) + return 0; + + info->loc.vline = bc->line; + info->loc.bc = bc; + + /* Keep track of last symbol seen */ + if (bc->symrecs) { + i = 0; + while (bc->symrecs[i]) { + info->loc.sym = bc->symrecs[i]; + i++; + } + } + + yasm_linemap_lookup(info->linemap, bc->line, &pathname, &info->loc.line); + dirlen = yasm__splitpath(pathname, &filename); + char * new_dir_name = yasm_replace_path( + dbgfmt_dwarf2->dbgfmt.module->replace_map, dbgfmt_dwarf2->dbgfmt.module->replace_map_size, + pathname, dirlen); + dirlen = strlen(new_dir_name); + + /* Find file index; just linear search it unless it was the last used */ + if (info->lastfile > 0 + && dwarf2_filename_equals(&dbgfmt_dwarf2->filenames[info->lastfile-1], + dbgfmt_dwarf2->dirs, new_dir_name, dirlen, + filename)) + info->loc.file = info->lastfile; + else { + for (i=0; i<dbgfmt_dwarf2->filenames_size; i++) { + if (dwarf2_filename_equals(&dbgfmt_dwarf2->filenames[i], + dbgfmt_dwarf2->dirs, new_dir_name, dirlen, + filename)) + break; + } + if (i >= dbgfmt_dwarf2->filenames_size) + yasm_internal_error(N_("could not find filename in table")); + info->loc.file = i+1; + info->lastfile = i+1; + } + yasm_xfree(new_dir_name); + if (dwarf2_dbgfmt_gen_line_op(info->debug_line, info->state, &info->loc, + NULL)) + return 1; + return 0; +} + +typedef struct dwarf2_line_info { + yasm_section *debug_line; /* section to which line number info goes */ + yasm_object *object; + yasm_linemap *linemap; + yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2; + yasm_errwarns *errwarns; + + /* Generate based on bytecodes (1) or locs (0)? Use bytecodes if we're + * generating line numbers for the actual assembly source file. + */ + int asm_source; + + /* number of sections line number info generated for */ + size_t num_sections; + /* last section line number info generated for */ + /*@null@*/ yasm_section *last_code; +} dwarf2_line_info; + +static int +dwarf2_generate_line_section(yasm_section *sect, /*@null@*/ void *d) +{ + dwarf2_line_info *info = (dwarf2_line_info *)d; + yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2 = info->dbgfmt_dwarf2; + /*@null@*/ dwarf2_section_data *dsd; + /*@null@*/ yasm_bytecode *bc; + dwarf2_line_state state; + unsigned long addr_delta; + + dsd = yasm_section_get_data(sect, &yasm_dwarf2__section_data_cb); + if (!dsd) { + if (info->asm_source && yasm_section_is_code(sect)) { + /* Create line data for asm code sections */ + dsd = yasm_xmalloc(sizeof(dwarf2_section_data)); + STAILQ_INIT(&dsd->locs); + yasm_section_add_data(sect, &yasm_dwarf2__section_data_cb, dsd); + } else + return 0; /* no line data for this section */ + } + + info->num_sections++; + info->last_code = sect; + + /* initialize state machine registers for each sequence */ + state.dbgfmt_dwarf2 = dbgfmt_dwarf2; + state.address = 0; + state.file = 1; + state.line = 1; + state.column = 0; + state.isa = 0; + state.is_stmt = DWARF2_LINE_DEFAULT_IS_STMT; + state.precbc = NULL; + + if (info->asm_source) { + dwarf2_line_bc_info bcinfo; + + bcinfo.debug_line = info->debug_line; + bcinfo.object = info->object; + bcinfo.linemap = info->linemap; + bcinfo.dbgfmt_dwarf2 = dbgfmt_dwarf2; + bcinfo.state = &state; + bcinfo.lastfile = 0; + bcinfo.loc.isa_change = 0; + bcinfo.loc.column = 0; + bcinfo.loc.discriminator = 0; + bcinfo.loc.is_stmt = IS_STMT_NOCHANGE; + bcinfo.loc.basic_block = 0; + bcinfo.loc.prologue_end = 0; + bcinfo.loc.epilogue_begin = 0; + bcinfo.loc.sym = NULL; + + /* bcs_traverse() skips first "dummy" bytecode, so look at it + * separately to determine the initial symrec. + */ + bc = yasm_section_bcs_first(sect); + if (bc->symrecs) { + size_t i = 0; + while (bc->symrecs[i]) { + bcinfo.loc.sym = bc->symrecs[i]; + i++; + } + } + + yasm_section_bcs_traverse(sect, info->errwarns, &bcinfo, + dwarf2_generate_line_bc); + } else { + /*@null@*/ dwarf2_loc *loc; + + dwarf2_dbgfmt_finalize_locs(sect, dsd); + + STAILQ_FOREACH(loc, &dsd->locs, link) { + if (dwarf2_dbgfmt_gen_line_op(info->debug_line, &state, loc, + STAILQ_NEXT(loc, link))) + return 1; + } + } + + /* End sequence: bring address to end of section, then output end + * sequence opcode. Don't use a special opcode to do this as we don't + * want an extra entry in the line matrix. + */ + if (!state.precbc) + state.precbc = yasm_section_bcs_first(sect); + bc = yasm_section_bcs_last(sect); + addr_delta = yasm_bc_next_offset(bc) - state.precbc->offset; + if (addr_delta == DWARF2_MAX_SPECIAL_ADDR_DELTA) + dwarf2_dbgfmt_append_line_op(info->debug_line, DW_LNS_const_add_pc, + NULL); + else if (addr_delta > 0) + dwarf2_dbgfmt_append_line_op(info->debug_line, DW_LNS_advance_pc, + yasm_intnum_create_uint(addr_delta)); + dwarf2_dbgfmt_append_line_ext_op(info->debug_line, DW_LNE_end_sequence, 0, + NULL); + + return 0; +} + +static int +dwarf2_generate_filename(const char *filename, void *d) +{ + yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2 = (yasm_dbgfmt_dwarf2 *)d; + char *deb_name = yasm_replace_path( + dbgfmt_dwarf2->dbgfmt.module->replace_map, dbgfmt_dwarf2->dbgfmt.module->replace_map_size, + filename, strlen(filename)); + dwarf2_dbgfmt_add_file(dbgfmt_dwarf2, 0, deb_name); + yasm_xfree(deb_name); + return 0; +} + +yasm_section * +yasm_dwarf2__generate_line(yasm_object *object, yasm_linemap *linemap, + yasm_errwarns *errwarns, int asm_source, + /*@out@*/ yasm_section **main_code, + /*@out@*/ size_t *num_line_sections) +{ + yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2 = (yasm_dbgfmt_dwarf2 *)object->dbgfmt; + dwarf2_line_info info; + int new; + size_t i; + yasm_bytecode *sppbc; + dwarf2_spp *spp; + dwarf2_head *head; + + if (asm_source) { + /* Generate dirs and filenames based on linemap */ + yasm_linemap_traverse_filenames(linemap, dbgfmt_dwarf2, + dwarf2_generate_filename); + } + + info.num_sections = 0; + info.last_code = NULL; + info.asm_source = asm_source; + info.object = object; + info.linemap = linemap; + info.dbgfmt_dwarf2 = dbgfmt_dwarf2; + info.debug_line = yasm_object_get_general(object, ".debug_line", 1, 0, 0, + &new, 0); + + /* header */ + head = yasm_dwarf2__add_head(dbgfmt_dwarf2, info.debug_line, NULL, 0, 0); + + /* statement program prologue */ + spp = yasm_xmalloc(sizeof(dwarf2_spp)); + sppbc = yasm_bc_create_common(&dwarf2_spp_bc_callback, spp, 0); + sppbc->len = dbgfmt_dwarf2->sizeof_offset + 5 + + NELEMS(line_opcode_num_operands); + + /* directory list */ + for (i=0; i<dbgfmt_dwarf2->dirs_size; i++) + sppbc->len += (unsigned long)strlen(dbgfmt_dwarf2->dirs[i])+1; + sppbc->len++; + + /* filename list */ + for (i=0; i<dbgfmt_dwarf2->filenames_size; i++) { + if (!dbgfmt_dwarf2->filenames[i].filename) { + yasm_error_set(YASM_ERROR_GENERAL, + N_("dwarf2 file number %d unassigned"), i+1); + yasm_errwarn_propagate(errwarns, 0); + continue; + } + sppbc->len += + (unsigned long)strlen(dbgfmt_dwarf2->filenames[i].filename) + 1 + + yasm_size_uleb128(dbgfmt_dwarf2->filenames[i].dir) + 2; + } + sppbc->len++; + yasm_dwarf2__append_bc(info.debug_line, sppbc); + + /* statement program */ + yasm_object_sections_traverse(object, (void *)&info, + dwarf2_generate_line_section); + + /* mark end of line information */ + yasm_dwarf2__set_head_end(head, yasm_section_bcs_last(info.debug_line)); + + *num_line_sections = info.num_sections; + if (info.num_sections == 1) + *main_code = info.last_code; + else + *main_code = NULL; + return info.debug_line; +} + +static void +dwarf2_spp_bc_destroy(void *contents) +{ + yasm_xfree(contents); +} + +static void +dwarf2_spp_bc_print(const void *contents, FILE *f, int indent_level) +{ + /* TODO */ +} + +static int +dwarf2_spp_bc_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span, + void *add_span_data) +{ + yasm_internal_error(N_("tried to calc_len a dwarf2 spp bytecode")); + /*@notreached@*/ + return 0; +} + +static int +dwarf2_spp_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp, + unsigned char *bufstart, void *d, + yasm_output_value_func output_value, + yasm_output_reloc_func output_reloc) +{ + yasm_object *object = yasm_section_get_object(bc->section); + yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2 = (yasm_dbgfmt_dwarf2 *)object->dbgfmt; + unsigned char *buf = *bufp; + yasm_intnum *cval; + size_t i, len; + + /* Prologue length (following this field) */ + cval = yasm_intnum_create_uint(bc->len - (unsigned long)(buf-*bufp) - + dbgfmt_dwarf2->sizeof_offset); + yasm_arch_intnum_tobytes(object->arch, cval, buf, + dbgfmt_dwarf2->sizeof_offset, + dbgfmt_dwarf2->sizeof_offset*8, 0, bc, 0); + buf += dbgfmt_dwarf2->sizeof_offset; + + YASM_WRITE_8(buf, dbgfmt_dwarf2->min_insn_len); /* minimum_instr_len */ + YASM_WRITE_8(buf, DWARF2_LINE_DEFAULT_IS_STMT); /* default_is_stmt */ + YASM_WRITE_8(buf, DWARF2_LINE_BASE); /* line_base */ + YASM_WRITE_8(buf, DWARF2_LINE_RANGE); /* line_range */ + YASM_WRITE_8(buf, DWARF2_LINE_OPCODE_BASE); /* opcode_base */ + + /* Standard opcode # operands array */ + for (i=0; i<NELEMS(line_opcode_num_operands); i++) + YASM_WRITE_8(buf, line_opcode_num_operands[i]); + + /* directory list */ + for (i=0; i<dbgfmt_dwarf2->dirs_size; i++) { + len = strlen(dbgfmt_dwarf2->dirs[i])+1; + memcpy(buf, dbgfmt_dwarf2->dirs[i], len); + buf += len; + } + /* finish with single 0 byte */ + YASM_WRITE_8(buf, 0); + + /* filename list */ + for (i=0; i<dbgfmt_dwarf2->filenames_size; i++) { + len = strlen(dbgfmt_dwarf2->filenames[i].filename)+1; + memcpy(buf, dbgfmt_dwarf2->filenames[i].filename, len); + buf += len; + + /* dir */ + buf += yasm_get_uleb128(dbgfmt_dwarf2->filenames[i].dir, buf); + YASM_WRITE_8(buf, 0); /* time */ + YASM_WRITE_8(buf, 0); /* length */ + } + /* finish with single 0 byte */ + YASM_WRITE_8(buf, 0); + + *bufp = buf; + + yasm_intnum_destroy(cval); + return 0; +} + +static void +dwarf2_line_op_bc_destroy(void *contents) +{ + dwarf2_line_op *line_op = (dwarf2_line_op *)contents; + if (line_op->operand) + yasm_intnum_destroy(line_op->operand); + if (line_op->ext_operand_int) + yasm_intnum_destroy(line_op->ext_operand_int); + yasm_xfree(contents); +} + +static void +dwarf2_line_op_bc_print(const void *contents, FILE *f, int indent_level) +{ + /* TODO */ +} + +static int +dwarf2_line_op_bc_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span, + void *add_span_data) +{ + yasm_internal_error(N_("tried to calc_len a dwarf2 line_op bytecode")); + /*@notreached@*/ + return 0; +} + +static int +dwarf2_line_op_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp, + unsigned char *bufstart, void *d, + yasm_output_value_func output_value, + yasm_output_reloc_func output_reloc) +{ + dwarf2_line_op *line_op = (dwarf2_line_op *)bc->contents; + unsigned char *buf = *bufp; + + YASM_WRITE_8(buf, line_op->opcode); + if (line_op->operand) + buf += yasm_intnum_get_leb128(line_op->operand, buf, + line_op->opcode == DW_LNS_advance_line); + if (line_op->ext_opcode > 0) { + YASM_WRITE_8(buf, line_op->ext_opcode); + if (line_op->ext_operand) { + yasm_value value; + yasm_value_init_sym(&value, line_op->ext_operand, + line_op->ext_operandsize*8); + output_value(&value, buf, line_op->ext_operandsize, + (unsigned long)(buf-bufstart), bc, 0, d); + buf += line_op->ext_operandsize; + } + if (line_op->ext_operand_int) { + buf += yasm_intnum_get_leb128(line_op->ext_operand_int, buf, 0); + } + } + + *bufp = buf; + return 0; +} + +void +yasm_dwarf2__dir_loc(yasm_object *object, yasm_valparamhead *valparams, + yasm_valparamhead *objext_valparams, unsigned long line) +{ + yasm_valparam *vp; + int in_is_stmt = 0, in_isa = 0, in_discriminator = 0; + + /*@dependent@*/ /*@null@*/ const yasm_intnum *intn; + dwarf2_section_data *dsd; + dwarf2_loc *loc = yasm_xmalloc(sizeof(dwarf2_loc)); + + /* File number (required) */ + if (!valparams || !(vp = yasm_vps_first(valparams)) || + vp->val || vp->type != YASM_PARAM_EXPR) { + yasm_error_set(YASM_ERROR_SYNTAX, N_("file number required")); + yasm_xfree(loc); + return; + } + intn = yasm_expr_get_intnum(&vp->param.e, 0); + if (!intn) { + yasm_error_set(YASM_ERROR_NOT_CONSTANT, + N_("file number is not a constant")); + yasm_xfree(loc); + return; + } + if (yasm_intnum_sign(intn) != 1) { + yasm_error_set(YASM_ERROR_VALUE, N_("file number less than one")); + yasm_xfree(loc); + return; + } + loc->file = yasm_intnum_get_uint(intn); + + /* Line number (required) */ + vp = yasm_vps_next(vp); + if (!vp || vp->val || vp->type != YASM_PARAM_EXPR) { + yasm_error_set(YASM_ERROR_SYNTAX, N_("line number required")); + yasm_xfree(loc); + return; + } + intn = yasm_expr_get_intnum(&vp->param.e, 0); + if (!intn) { + yasm_error_set(YASM_ERROR_NOT_CONSTANT, + N_("line number is not a constant")); + yasm_xfree(loc); + return; + } + loc->line = yasm_intnum_get_uint(intn); + + /* Generate new section data if it doesn't already exist */ + if (!object->cur_section) { + yasm_error_set(YASM_ERROR_SYNTAX, + N_("[%s] can only be used inside of a section"), "loc"); + yasm_xfree(loc); + return; + } + dsd = yasm_section_get_data(object->cur_section, + &yasm_dwarf2__section_data_cb); + if (!dsd) { + dsd = yasm_xmalloc(sizeof(dwarf2_section_data)); + STAILQ_INIT(&dsd->locs); + yasm_section_add_data(object->cur_section, + &yasm_dwarf2__section_data_cb, dsd); + } + + /* Defaults for optional settings */ + loc->column = 0; + loc->discriminator = 0; + loc->isa_change = 0; + loc->isa = 0; + loc->is_stmt = IS_STMT_NOCHANGE; + loc->basic_block = 0; + loc->prologue_end = 0; + loc->epilogue_begin = 0; + + /* Optional column number */ + vp = yasm_vps_next(vp); + if (vp && !vp->val && vp->type == YASM_PARAM_EXPR) { + intn = yasm_expr_get_intnum(&vp->param.e, 0); + if (!intn) { + yasm_error_set(YASM_ERROR_NOT_CONSTANT, + N_("column number is not a constant")); + yasm_xfree(loc); + return; + } + loc->column = yasm_intnum_get_uint(intn); + vp = yasm_vps_next(vp); + } + + /* Other options; note for GAS compatibility we need to support both: + * is_stmt=1 (NASM) and + * is_stmt 1 (GAS) + */ + while (vp) { + /*@null@*/ /*@dependent@*/ const char *s; + /*@null@*/ /*@only@*/ yasm_expr *e; + +restart: + if (in_is_stmt) { + in_is_stmt = 0; + if (!(e = yasm_vp_expr(vp, object->symtab, line)) || + !(intn = yasm_expr_get_intnum(&e, 0))) { + yasm_error_set(YASM_ERROR_NOT_CONSTANT, + N_("is_stmt value is not a constant")); + yasm_xfree(loc); + if (e) + yasm_expr_destroy(e); + return; + } + if (yasm_intnum_is_zero(intn)) + loc->is_stmt = IS_STMT_SET; + else if (yasm_intnum_is_pos1(intn)) + loc->is_stmt = IS_STMT_CLEAR; + else { + yasm_error_set(YASM_ERROR_VALUE, + N_("is_stmt value not 0 or 1")); + yasm_xfree(loc); + yasm_expr_destroy(e); + return; + } + yasm_expr_destroy(e); + } else if (in_isa) { + in_isa = 0; + if (!(e = yasm_vp_expr(vp, object->symtab, line)) || + !(intn = yasm_expr_get_intnum(&e, 0))) { + yasm_error_set(YASM_ERROR_NOT_CONSTANT, + N_("isa value is not a constant")); + yasm_xfree(loc); + if (e) + yasm_expr_destroy(e); + return; + } + if (yasm_intnum_sign(intn) < 0) { + yasm_error_set(YASM_ERROR_VALUE, + N_("isa value less than zero")); + yasm_xfree(loc); + yasm_expr_destroy(e); + return; + } + loc->isa_change = 1; + loc->isa = yasm_intnum_get_uint(intn); + yasm_expr_destroy(e); + } else if (in_discriminator) { + in_discriminator = 0; + if (!(e = yasm_vp_expr(vp, object->symtab, line)) || + !(intn = yasm_expr_get_intnum(&e, 0))) { + yasm_error_set(YASM_ERROR_NOT_CONSTANT, + N_("discriminator value is not a constant")); + yasm_xfree(loc); + if (e) + yasm_expr_destroy(e); + return; + } + if (yasm_intnum_sign(intn) < 0) { + yasm_error_set(YASM_ERROR_VALUE, + N_("discriminator value less than zero")); + yasm_xfree(loc); + yasm_expr_destroy(e); + return; + } + loc->discriminator = yasm_intnum_get_uint(intn); + yasm_expr_destroy(e); + } else if (!vp->val && (s = yasm_vp_id(vp))) { + if (yasm__strcasecmp(s, "is_stmt") == 0) + in_is_stmt = 1; + else if (yasm__strcasecmp(s, "isa") == 0) + in_isa = 1; + else if (yasm__strcasecmp(s, "discriminator") == 0) + in_discriminator = 1; + else if (yasm__strcasecmp(s, "basic_block") == 0) + loc->basic_block = 1; + else if (yasm__strcasecmp(s, "prologue_end") == 0) + loc->prologue_end = 1; + else if (yasm__strcasecmp(s, "epilogue_begin") == 0) + loc->epilogue_begin = 1; + else + yasm_warn_set(YASM_WARN_GENERAL, + N_("unrecognized loc option `%s'"), s); + } else if (!vp->val) { + yasm_warn_set(YASM_WARN_GENERAL, + N_("unrecognized numeric qualifier")); + } else if (yasm__strcasecmp(vp->val, "is_stmt") == 0) { + in_is_stmt = 1; + goto restart; /* don't go to the next valparam */ + } else if (yasm__strcasecmp(vp->val, "isa") == 0) { + in_isa = 1; + goto restart; /* don't go to the next valparam */ + } else if (yasm__strcasecmp(vp->val, "discriminator") == 0) { + in_discriminator = 1; + goto restart; /* don't go to the next valparam */ + } else + yasm_warn_set(YASM_WARN_GENERAL, + N_("unrecognized loc option `%s'"), vp->val); + vp = yasm_vps_next(vp); + } + + if (in_is_stmt || in_isa || in_discriminator) { + yasm_error_set(YASM_ERROR_SYNTAX, N_("%s requires value"), + in_is_stmt ? "is_stmt" : + (in_isa ? "isa" : "discriminator")); + yasm_xfree(loc); + return; + } + + /* Append new location */ + loc->vline = line; + loc->bc = NULL; + loc->sym = NULL; + STAILQ_INSERT_TAIL(&dsd->locs, loc, link); +} + +void +yasm_dwarf2__dir_file(yasm_object *object, yasm_valparamhead *valparams, + yasm_valparamhead *objext_valparams, unsigned long line) +{ + yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2 = (yasm_dbgfmt_dwarf2 *)object->dbgfmt; + yasm_valparam *vp; + /*@dependent@*/ /*@null@*/ const yasm_intnum *file_intn; + unsigned long filenum; + + if (!valparams) { + yasm_error_set(YASM_ERROR_SYNTAX, N_("[%s] requires an argument"), + "FILE"); + return; + } + + vp = yasm_vps_first(valparams); + if (yasm_vp_string(vp)) { + /* Just a bare filename */ + yasm_object_set_source_fn(object, yasm_vp_string(vp)); + object->deb_filename = yasm_replace_path( + dbgfmt_dwarf2->dbgfmt.module->replace_map, dbgfmt_dwarf2->dbgfmt.module->replace_map_size, + yasm_vp_string(vp), strlen(yasm_vp_string(vp))); + return; + } + + /* Otherwise.. first vp is the file number */ + if (vp->type != YASM_PARAM_EXPR || + !(file_intn = yasm_expr_get_intnum(&vp->param.e, 0))) { + yasm_error_set(YASM_ERROR_NOT_CONSTANT, + N_("file number is not a constant")); + return; + } + filenum = yasm_intnum_get_uint(file_intn); + + vp = yasm_vps_next(vp); + if (!yasm_vp_string(vp)) { + yasm_error_set(YASM_ERROR_SYNTAX, + N_("file number given but no filename")); + return; + } + + dwarf2_dbgfmt_add_file(dbgfmt_dwarf2, filenum, yasm_vp_string(vp)); +} diff --git a/contrib/tools/yasm/modules/dbgfmts/null/null-dbgfmt.c b/contrib/tools/yasm/modules/dbgfmts/null/null-dbgfmt.c new file mode 100644 index 0000000000..d2d1bed58e --- /dev/null +++ b/contrib/tools/yasm/modules/dbgfmts/null/null-dbgfmt.c @@ -0,0 +1,64 @@ +/* + * Null debugging format (creates NO debugging information) + * + * 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> + + +yasm_dbgfmt_module yasm_null_LTX_dbgfmt; + + +static /*@null@*/ /*@only@*/ yasm_dbgfmt * +null_dbgfmt_create(yasm_object *object) +{ + yasm_dbgfmt_base *dbgfmt = yasm_xmalloc(sizeof(yasm_dbgfmt_base)); + dbgfmt->module = &yasm_null_LTX_dbgfmt; + return (yasm_dbgfmt *)dbgfmt; +} + +static void +null_dbgfmt_destroy(/*@only@*/ yasm_dbgfmt *dbgfmt) +{ + yasm_xfree(dbgfmt); +} + +static void +null_dbgfmt_generate(yasm_object *object, yasm_linemap *linemap, + yasm_errwarns *errwarns) +{ +} + + +/* Define dbgfmt structure -- see dbgfmt.h for details */ +yasm_dbgfmt_module yasm_null_LTX_dbgfmt = { + "No debugging info", + "null", + NULL, /* no directives */ + null_dbgfmt_create, + null_dbgfmt_destroy, + null_dbgfmt_generate +}; diff --git a/contrib/tools/yasm/modules/dbgfmts/stabs/stabs-dbgfmt.c b/contrib/tools/yasm/modules/dbgfmts/stabs/stabs-dbgfmt.c new file mode 100644 index 0000000000..5c0cba6aeb --- /dev/null +++ b/contrib/tools/yasm/modules/dbgfmts/stabs/stabs-dbgfmt.c @@ -0,0 +1,511 @@ +/* + * Stabs debugging format + * + * Copyright (C) 2003-2007 Michael Urman + * + * 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> + +typedef enum { + N_UNDF = 0x00, /* Undefined */ + N_GSYM = 0x20, /* Global symbol */ + N_FNAME = 0x22, /* Function name (BSD Fortran) */ + N_FUN = 0x24, /* Function name or Text segment variable */ + N_STSYM = 0x26, /* Data segment file-scope variable */ + N_LCSYM = 0x28, /* BSS segment file-scope variable */ + N_MAIN = 0x2a, /* Name of main routine */ + N_ROSYM = 0x2c, /* Variable in .rodata section */ + N_PC = 0x30, /* Global symbol (Pascal) */ + N_SYMS = 0x32, /* Number of symbols (Ultrix V4.0) */ + N_NOMAP = 0x34, /* No DST map */ + N_OBJ = 0x38, /* Object file (Solaris2) */ + N_OPT = 0x3c, /* Debugger options (Solaris2) */ + N_RSYM = 0x40, /* Register variable */ + N_M2C = 0x42, /* Modula-2 compilation unit */ + N_SLINE = 0x44, /* Line numbers in .text segment */ + N_DSLINE = 0x46, /* Line numbers in .data segment */ + N_BSLINE = 0x48, /* Line numbers in .bss segment */ + N_BROWS = 0x48, /* Source code .cb file's path */ + N_DEFD = 0x4a, /* GNU Modula-2 definition module dependency */ + N_FLINE = 0x4c, /* Function start/body/end line numbers (Solaris2) */ + N_EHDECL = 0x50, /* GNU C++ exception variable */ + N_MOD2 = 0x50, /* Modula2 info for imc (Ultrix V4.0) */ + N_CATCH = 0x54, /* GNU C++ catch clause */ + N_SSYM = 0x60, /* Structure or union element */ + N_ENDM = 0x62, /* Last stab for module (Solaris2) */ + N_SO = 0x64, /* Path and name of source files */ + N_LSYM = 0x80, /* Stack variable */ + N_BINCL = 0x84, /* Beginning of include file */ + N_SOL = 0x84, /* Name of include file */ + N_PSYM = 0xa0, /* Parameter variable */ + N_EINCL = 0xa2, /* End of include file */ + N_ENTRY = 0xa4, /* Alternate entry point */ + N_LBRAC = 0xc0, /* Beginning of lexical block */ + N_EXCL = 0xc2, /* Placeholder for a deleted include file */ + N_SCOPE = 0xc4, /* Modula 2 scope info (Sun) */ + N_RBRAC = 0xe0, /* End of lexical block */ + N_BCOMM = 0xe2, /* Begin named common block */ + N_ECOMM = 0xe4, /* End named common block */ + N_ECOML = 0xe8, /* Member of common block */ + N_WITH = 0xea, /* Pascal with statement: type,,0,0,offset (Solaris2) */ + N_NBTEXT = 0xf0, /* Gould non-base registers */ + N_NBDATA = 0xf2, /* Gould non-base registers */ + N_NBBSS = 0xf4, /* Gould non-base registers */ + N_NBSTS = 0xf6, /* Gould non-base registers */ + N_NBLCS = 0xf8 /* Gould non-base registers */ +} stabs_stab_type; + +typedef struct yasm_dbgfmt_stabs { + yasm_dbgfmt_base dbgfmt; /* base structure */ +} yasm_dbgfmt_stabs; + +typedef struct { + unsigned long lastline; /* track line and file of bytecodes */ + unsigned long curline; + const char *lastfile; + const char *curfile; + + unsigned int stablen; /* size of a stab for current machine */ + unsigned long stabcount; /* count stored stabs; doesn't include first */ + + yasm_section *stab; /* sections to which stabs, stabstrs appended */ + yasm_section *stabstr; + + yasm_bytecode *basebc; /* base bytecode from which to track SLINEs */ + + yasm_object *object; + yasm_linemap *linemap; + yasm_errwarns *errwarns; +} stabs_info; + +typedef struct { + /*@null@*/ yasm_bytecode *bcstr; /* bytecode in stabstr for string */ + stabs_stab_type type; /* stab type: N_* */ + unsigned char other; /* unused, but stored here anyway */ + unsigned short desc; /* description element of a stab */ + /*@null@*/ yasm_symrec *symvalue; /* value element needing relocation */ + /*@null@*/yasm_bytecode *bcvalue; /* relocated stab's bytecode */ + unsigned long value; /* fallthrough value if above NULL */ +} stabs_stab; + +/* Bytecode callback function prototypes */ + +static void stabs_bc_str_destroy(void *contents); +static void stabs_bc_str_print(const void *contents, FILE *f, int + indent_level); +static int stabs_bc_str_calc_len + (yasm_bytecode *bc, yasm_bc_add_span_func add_span, void *add_span_data); +static int stabs_bc_str_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 stabs_bc_stab_destroy(void *contents); +static void stabs_bc_stab_print(const void *contents, FILE *f, int + indent_level); +static int stabs_bc_stab_calc_len + (yasm_bytecode *bc, yasm_bc_add_span_func add_span, void *add_span_data); +static int stabs_bc_stab_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 stabs_bc_str_callback = { + stabs_bc_str_destroy, + stabs_bc_str_print, + yasm_bc_finalize_common, + NULL, + stabs_bc_str_calc_len, + yasm_bc_expand_common, + stabs_bc_str_tobytes, + 0 +}; + +static const yasm_bytecode_callback stabs_bc_stab_callback = { + stabs_bc_stab_destroy, + stabs_bc_stab_print, + yasm_bc_finalize_common, + NULL, + stabs_bc_stab_calc_len, + yasm_bc_expand_common, + stabs_bc_stab_tobytes, + 0 +}; + +yasm_dbgfmt_module yasm_stabs_LTX_dbgfmt; + + +static /*@null@*/ /*@only@*/ yasm_dbgfmt * +stabs_dbgfmt_create(yasm_object *object) +{ + yasm_dbgfmt_stabs *dbgfmt_stabs = yasm_xmalloc(sizeof(yasm_dbgfmt_stabs)); + dbgfmt_stabs->dbgfmt.module = &yasm_stabs_LTX_dbgfmt; + return (yasm_dbgfmt *)dbgfmt_stabs; +} + +static void +stabs_dbgfmt_destroy(/*@only@*/ yasm_dbgfmt *dbgfmt) +{ + yasm_xfree(dbgfmt); +} + +/* Create and add a new strtab-style string bytecode to a section, updating + * offset on insertion; no optimization necessary */ +/* Copies the string, so you must still free yours as normal */ +static yasm_bytecode * +stabs_dbgfmt_append_bcstr(yasm_section *sect, const char *str) +{ + yasm_bytecode *bc; + + bc = yasm_bc_create_common(&stabs_bc_str_callback, yasm__xstrdup(str), 0); + bc->len = (unsigned long)(strlen(str)+1); + bc->offset = yasm_bc_next_offset(yasm_section_bcs_last(sect)); + + yasm_section_bcs_append(sect, bc); + + return bc; +} + +/* Create and add a new stab bytecode to a section, updating offset on + * insertion; no optimization necessary. */ +/* Requires a string bytecode, or NULL, for its string entry */ +static stabs_stab * +stabs_dbgfmt_append_stab(stabs_info *info, yasm_section *sect, + /*@null@*/ yasm_bytecode *bcstr, stabs_stab_type type, + unsigned long desc, /*@null@*/ yasm_symrec *symvalue, + /*@null@*/ yasm_bytecode *bcvalue, unsigned long value) +{ + yasm_bytecode *bc; + stabs_stab *stab = yasm_xmalloc(sizeof(stabs_stab)); + + stab->other = 0; + stab->bcstr = bcstr; + stab->type = type; + stab->desc = (unsigned short)desc; + stab->symvalue = symvalue; + stab->bcvalue = bcvalue; + stab->value = value; + + bc = yasm_bc_create_common(&stabs_bc_stab_callback, stab, + bcvalue ? bcvalue->line : 0); + bc->len = info->stablen; + bc->offset = yasm_bc_next_offset(yasm_section_bcs_last(sect)); + + yasm_section_bcs_append(sect, bc); + + info->stabcount++; + return stab; +} + +static void +stabs_dbgfmt_generate_n_fun(stabs_info *info, yasm_bytecode *bc) +{ + /* check all syms at this bc for potential function syms */ + int bcsym; + for (bcsym=0; bc->symrecs && bc->symrecs[bcsym]; bcsym++) + { + char *str; + yasm_symrec *sym = bc->symrecs[bcsym]; + const char *name = yasm_symrec_get_name(sym); + + /* best guess algorithm - ignore labels containing a . or $ */ + if (strchr(name, '.') || strchr(name, '$')) + continue; + + /* if a function, update basebc, and output a funcname:F1 stab */ + info->basebc = bc; + + str = yasm_xmalloc(strlen(name)+4); + strcpy(str, name); + strcat(str, ":F1"); + stabs_dbgfmt_append_stab(info, info->stab, + stabs_dbgfmt_append_bcstr(info->stabstr, str), + N_FUN, 0, sym, info->basebc, 0); + yasm_xfree(str); + break; + } +} + +static int +stabs_dbgfmt_generate_bcs(yasm_bytecode *bc, void *d) +{ + stabs_info *info = (stabs_info *)d; + yasm_linemap_lookup(info->linemap, bc->line, &info->curfile, + &info->curline); + + /* check for new function */ + stabs_dbgfmt_generate_n_fun(info, bc); + + if (info->lastfile != info->curfile) { + info->lastline = 0; /* new file, so line changes */ + /*stabs_dbgfmt_append_stab(info, info->stab, + stabs_dbgfmt_append_bcstr(info->stabstr, info->curfile), + N_SOL, 0, NULL, bc, 0);*/ + } + + /* output new line stabs if there's a basebc (known function) */ + if (info->basebc != NULL && info->curline != info->lastline) { + info->lastline = bc->line; + stabs_dbgfmt_append_stab(info, info->stab, NULL, N_SLINE, + info->curline, NULL, NULL, + bc->offset - info->basebc->offset); + } + + info->lastline = info->curline; + info->lastfile = info->curfile; + + return 0; +} + +static int +stabs_dbgfmt_generate_sections(yasm_section *sect, /*@null@*/ void *d) +{ + stabs_info *info = (stabs_info *)d; + const char *sectname=yasm_section_get_name(sect); + + /* each section has a different base symbol */ + info->basebc = NULL; + + /* handle first (pseudo) bc separately */ + stabs_dbgfmt_generate_n_fun(d, yasm_section_bcs_first(sect)); + + yasm_section_bcs_traverse(sect, info->errwarns, d, + stabs_dbgfmt_generate_bcs); + + if (yasm__strcasecmp(sectname, ".text")==0) { + /* Close out last function by appending a null SO stab after last bc */ + yasm_bytecode *bc = yasm_section_bcs_last(sect); + yasm_symrec *sym = + yasm_symtab_define_label(info->object->symtab, ".n_so", bc, 1, + bc->line); + stabs_dbgfmt_append_stab(info, info->stab, 0, N_SO, 0, sym, bc, 0); + } + + return 1; +} + +static void +stabs_dbgfmt_generate(yasm_object *object, yasm_linemap *linemap, + yasm_errwarns *errwarns) +{ + stabs_info info; + int new; + yasm_bytecode *dbgbc; + stabs_stab *stab; + yasm_bytecode *filebc, *laststr, *firstbc; + yasm_symrec *firstsym; + yasm_section *stext; + + /* Stablen is determined by arch/machine */ + if (yasm__strcasecmp(yasm_arch_keyword(object->arch), "x86") == 0) { + info.stablen = 12; + } + else /* unknown machine; generate nothing */ + return; + + info.object = object; + info.linemap = linemap; + info.errwarns = errwarns; + info.lastline = 0; + info.stabcount = 0; + info.stab = yasm_object_get_general(object, ".stab", 4, 0, 0, &new, 0); + if (!new) { + yasm_bytecode *last = yasm_section_bcs_last(info.stab); + if (last == NULL) { + yasm_error_set(YASM_ERROR_GENERAL, + N_("stabs debugging conflicts with user-defined section .stab")); + yasm_errwarn_propagate(errwarns, + yasm_section_bcs_first(info.stab)->line); + } else { + yasm_warn_set(YASM_WARN_GENERAL, + N_("stabs debugging overrides empty section .stab")); + yasm_errwarn_propagate(errwarns, 0); + } + } + + info.stabstr = + yasm_object_get_general(object, ".stabstr", 1, 0, 0, &new, 0); + if (!new) { + yasm_bytecode *last = yasm_section_bcs_last(info.stabstr); + if (last == NULL) { + yasm_error_set(YASM_ERROR_GENERAL, + N_("stabs debugging conflicts with user-defined section .stabstr")); + yasm_errwarn_propagate(errwarns, + yasm_section_bcs_first(info.stab)->line); + } else { + yasm_warn_set(YASM_WARN_GENERAL, + N_("stabs debugging overrides empty section .stabstr")); + yasm_errwarn_propagate(errwarns, 0); + } + } + + /* initial pseudo-stab */ + stab = yasm_xmalloc(sizeof(stabs_stab)); + dbgbc = yasm_bc_create_common(&stabs_bc_stab_callback, stab, 0); + dbgbc->len = info.stablen; + dbgbc->offset = 0; + yasm_section_bcs_append(info.stab, dbgbc); + + /* initial strtab bytecodes */ + stabs_dbgfmt_append_bcstr(info.stabstr, ""); + filebc = stabs_dbgfmt_append_bcstr(info.stabstr, object->src_filename); + + stext = yasm_object_find_general(object, ".text"); + firstsym = yasm_symtab_use(object->symtab, ".text", 0); + firstbc = yasm_section_bcs_first(stext); + /* N_SO file stab */ + stabs_dbgfmt_append_stab(&info, info.stab, filebc, N_SO, 0, + firstsym, firstbc, 0); + + yasm_object_sections_traverse(object, (void *)&info, + stabs_dbgfmt_generate_sections); + + /* fill initial pseudo-stab's fields */ + laststr = yasm_section_bcs_last(info.stabstr); + if (laststr == NULL) + yasm_internal_error(".stabstr has no entries"); + + stab->bcvalue = NULL; + stab->symvalue = NULL; + stab->value = yasm_bc_next_offset(laststr); + stab->bcstr = filebc; + stab->type = N_UNDF; + stab->other = 0; + if (info.stabcount > 0xffff) { + yasm_warn_set(YASM_WARN_GENERAL, N_("over 65535 stabs")); + yasm_errwarn_propagate(errwarns, 0); + stab->desc = 0xffff; + } else + stab->desc = (unsigned short)info.stabcount; +} + +static int +stabs_bc_stab_tobytes(yasm_bytecode *bc, unsigned char **bufp, + unsigned char *bufstart, void *d, + yasm_output_value_func output_value, + yasm_output_reloc_func output_reloc) +{ + /* This entire function, essentially the core of rendering stabs to a file, + * needs to become endian aware. Size appears not to be an issue, as known + * 64-bit systems use truncated values in 32-bit fields. */ + + const stabs_stab *stab = (const stabs_stab *)bc->contents; + unsigned char *buf = *bufp; + + YASM_WRITE_32_L(buf, stab->bcstr ? stab->bcstr->offset : 0); + YASM_WRITE_8(buf, stab->type); + YASM_WRITE_8(buf, stab->other); + YASM_WRITE_16_L(buf, stab->desc); + + if (stab->symvalue != NULL) { + bc->offset += 8; + output_reloc(stab->symvalue, bc, buf, 4, 32, 0, d); + bc->offset -= 8; + buf += 4; + } + else if (stab->bcvalue != NULL) { + YASM_WRITE_32_L(buf, stab->bcvalue->offset); + } + else { + YASM_WRITE_32_L(buf, stab->value); + } + + *bufp = buf; + return 0; +} + +static int +stabs_bc_str_tobytes(yasm_bytecode *bc, unsigned char **bufp, + unsigned char *bufstart, void *d, + yasm_output_value_func output_value, + yasm_output_reloc_func output_reloc) +{ + const char *str = (const char *)bc->contents; + unsigned char *buf = *bufp; + + strcpy((char *)buf, str); + buf += strlen(str)+1; + + *bufp = buf; + return 0; +} + +static void +stabs_bc_stab_destroy(void *contents) +{ + yasm_xfree(contents); +} + +static void +stabs_bc_str_destroy(void *contents) +{ + yasm_xfree(contents); +} + +static void +stabs_bc_stab_print(const void *contents, FILE *f, int indent_level) +{ + const stabs_stab *stab = (const stabs_stab *)contents; + const char *str = ""; + fprintf(f, "%*s.stabs \"%s\", 0x%x, 0x%x, 0x%x, 0x%lx\n", + indent_level, "", str, stab->type, stab->other, stab->desc, + stab->bcvalue ? stab->bcvalue->offset : stab->value); +} + +static void +stabs_bc_str_print(const void *contents, FILE *f, int indent_level) +{ + fprintf(f, "%*s\"%s\"\n", indent_level, "", (const char *)contents); +} + +static int +stabs_bc_stab_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span, + void *add_span_data) +{ + yasm_internal_error(N_("tried to resolve a stabs stab bytecode")); + /*@notreached@*/ + return 0; +} + +static int +stabs_bc_str_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span, + void *add_span_data) +{ + yasm_internal_error(N_("tried to resolve a stabs str bytecode")); + /*@notreached@*/ + return 0; +} + +/* Define dbgfmt structure -- see dbgfmt.h for details */ +yasm_dbgfmt_module yasm_stabs_LTX_dbgfmt = { + "Stabs debugging format", + "stabs", + NULL, /* no directives */ + stabs_dbgfmt_create, + stabs_dbgfmt_destroy, + stabs_dbgfmt_generate +}; diff --git a/contrib/tools/yasm/modules/gas-token.c b/contrib/tools/yasm/modules/gas-token.c new file mode 100644 index 0000000000..454287b6d8 --- /dev/null +++ b/contrib/tools/yasm/modules/gas-token.c @@ -0,0 +1,1407 @@ +/* Generated by re2c + */ +/* + * GAS-compatible re2c lexer + * + * Copyright (C) 2005-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. + * 3. Neither the name of the author nor the names of other contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 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 "modules/parsers/gas/gas-parser.h" + + +#define BSIZE 8192 + +#define YYCURSOR cursor +#define YYLIMIT (s->lim) +#define YYMARKER (s->ptr) +#define YYFILL(n) {cursor = fill(parser_gas, cursor);} + +#define RETURN(i) do {s->cur = cursor; parser_gas->tokch = s->tok[0]; \ + return i;} while (0) + +#define SCANINIT() {s->tok = cursor;} + +#define TOK ((char *)s->tok) +#define TOKLEN (size_t)(cursor-s->tok) + +/* Bridge function to convert byte-oriented parser with line-oriented + * preprocessor. + */ +static size_t +preproc_input(yasm_parser_gas *parser_gas, /*@out@*/ YYCTYPE *buf, + size_t max_size) +{ + size_t tot=0; + while (max_size > 0) { + size_t n; + + if (!parser_gas->line) { + parser_gas->line = yasm_preproc_get_line(parser_gas->preproc); + if (!parser_gas->line) + return tot; /* EOF */ + parser_gas->linepos = parser_gas->line; + parser_gas->lineleft = strlen(parser_gas->line) + 1; + parser_gas->line[parser_gas->lineleft-1] = '\n'; + } + + n = parser_gas->lineleft<max_size ? parser_gas->lineleft : max_size; + strncpy((char *)buf+tot, parser_gas->linepos, n); + + if (n == parser_gas->lineleft) { + yasm_xfree(parser_gas->line); + parser_gas->line = NULL; + } else { + parser_gas->lineleft -= n; + parser_gas->linepos += n; + } + + tot += n; + max_size -= n; + } + return tot; +} +#if 0 +static size_t +fill_input(void *d, unsigned char *buf, size_t max) +{ + return yasm_preproc_input((yasm_preproc *)d, (char *)buf, max); +} +#endif +static YYCTYPE * +fill(yasm_parser_gas *parser_gas, YYCTYPE *cursor) +{ + yasm_scanner *s = &parser_gas->s; + int first = 0; + if(!s->eof){ + size_t cnt = s->tok - s->bot; + if(cnt){ + memmove(s->bot, s->tok, (size_t)(s->lim - s->tok)); + s->tok = s->bot; + s->ptr -= cnt; + cursor -= cnt; + s->lim -= cnt; + } + if (!s->bot) + first = 1; + if((s->top - s->lim) < BSIZE){ + YYCTYPE *buf = yasm_xmalloc((size_t)(s->lim - s->bot) + BSIZE); + memcpy(buf, s->tok, (size_t)(s->lim - s->tok)); + s->tok = buf; + s->ptr = &buf[s->ptr - s->bot]; + cursor = &buf[cursor - s->bot]; + s->lim = &buf[s->lim - s->bot]; + s->top = &s->lim[BSIZE]; + if (s->bot) + yasm_xfree(s->bot); + s->bot = buf; + } + if((cnt = preproc_input(parser_gas, s->lim, BSIZE)) == 0) { + s->eof = &s->lim[cnt]; *s->eof++ = '\n'; + } + s->lim += cnt; + if (first && parser_gas->save_input) { + int i; + YYCTYPE *saveline; + parser_gas->save_last ^= 1; + saveline = parser_gas->save_line[parser_gas->save_last]; + /* save next line into cur_line */ + for (i=0; i<79 && &s->tok[i] < s->lim && s->tok[i] != '\n'; i++) + saveline[i] = s->tok[i]; + saveline[i] = '\0'; + } + } + return cursor; +} + +static YYCTYPE * +save_line(yasm_parser_gas *parser_gas, YYCTYPE *cursor) +{ + yasm_scanner *s = &parser_gas->s; + int i = 0; + YYCTYPE *saveline; + + parser_gas->save_last ^= 1; + saveline = parser_gas->save_line[parser_gas->save_last]; + + /* save next line into cur_line */ + if ((YYLIMIT - YYCURSOR) < 80) + YYFILL(80); + for (i=0; i<79 && &cursor[i] < s->lim && cursor[i] != '\n'; i++) + saveline[i] = cursor[i]; + saveline[i] = '\0'; + return cursor; +} + +/* starting size of string buffer */ +#define STRBUF_ALLOC_SIZE 128 + +/* string buffer used when parsing strings/character constants */ +static YYCTYPE *strbuf = NULL; + +/* length of strbuf (including terminating NULL character) */ +static size_t strbuf_size = 0; + +static void +strbuf_append(size_t count, YYCTYPE *cursor, yasm_scanner *s, int ch) +{ + if (count >= strbuf_size) { + strbuf = yasm_xrealloc(strbuf, strbuf_size + STRBUF_ALLOC_SIZE); + strbuf_size += STRBUF_ALLOC_SIZE; + } + strbuf[count] = ch; +} + + + + +int +gas_parser_lex(YYSTYPE *lvalp, yasm_parser_gas *parser_gas) +{ + yasm_scanner *s = &parser_gas->s; + YYCTYPE *cursor = s->cur; + size_t count; + YYCTYPE savech; + + /* Handle one token of lookahead */ + if (parser_gas->peek_token != NONE) { + int tok = parser_gas->peek_token; + *lvalp = parser_gas->peek_tokval; /* structure copy */ + parser_gas->tokch = parser_gas->peek_tokch; + parser_gas->peek_token = NONE; + return tok; + } + + /* Catch EOF */ + if (s->eof && cursor == s->eof) + return 0; + + /* Jump to proper "exclusive" states */ + switch (parser_gas->state) { + case COMMENT: + goto comment; + case SECTION_DIRECTIVE: + goto section_directive; + case NASM_FILENAME: + goto nasm_filename; + default: + break; + } + +scan: + SCANINIT(); + + { + static unsigned char yybm[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 12, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 12, 0, + 254, 254, 126, 126, 126, 126, 126, 126, + 94, 94, 0, 0, 0, 0, 0, 0, + 8, 78, 78, 78, 78, 78, 78, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 0, 0, 0, 0, 12, + 0, 78, 78, 78, 78, 78, 78, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 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, 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, 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, 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, 0, + }; + +{ + YYCTYPE yych; + unsigned int yyaccept; + goto yy0; + ++YYCURSOR; +yy0: + if((YYLIMIT - YYCURSOR) < 5) YYFILL(5); + yych = *YYCURSOR; + if(yych <= '/'){ + if(yych <= '#'){ + if(yych <= '\r'){ + if(yych <= '\t'){ + if(yych <= '\b') goto yy30; + goto yy26; + } else { + if(yych <= '\n') goto yy28; + if(yych <= '\f') goto yy30; + goto yy26; + } + } else { + if(yych <= ' '){ + if(yych <= '\037') goto yy30; + goto yy26; + } else { + if(yych <= '!') goto yy17; + if(yych <= '"') goto yy11; + goto yy24; + } + } + } else { + if(yych <= '*'){ + if(yych <= '%'){ + if(yych <= '$') goto yy17; + goto yy22; + } else { + if(yych == '\'') goto yy9; + goto yy17; + } + } else { + if(yych <= ','){ + if(yych <= '+') goto yy5; + goto yy17; + } else { + if(yych <= '-') goto yy5; + if(yych <= '.') goto yy7; + goto yy18; + } + } + } + } else { + if(yych <= 'Z'){ + if(yych <= '<'){ + if(yych <= '9'){ + if(yych >= '1') goto yy4; + goto yy2; + } else { + if(yych <= ':') goto yy17; + if(yych <= ';') goto yy19; + goto yy13; + } + } else { + if(yych <= '>'){ + if(yych <= '=') goto yy17; + goto yy15; + } else { + if(yych <= '?') goto yy30; + if(yych <= '@') goto yy17; + goto yy21; + } + } + } else { + if(yych <= 'z'){ + if(yych <= '^'){ + if(yych <= ']') goto yy30; + goto yy17; + } else { + if(yych == '`') goto yy30; + goto yy21; + } + } else { + if(yych <= '|'){ + if(yych <= '{') goto yy30; + goto yy17; + } else { + if(yych == '~') goto yy17; + goto yy30; + } + } + } + } +yy2: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'T'){ + if(yych <= 'A'){ + if(yych <= '/'){ + if(yych == '.') goto yy90; + goto yy3; + } else { + if(yych <= '9') goto yy90; + if(yych <= ':') goto yy81; + goto yy3; + } + } else { + if(yych <= 'E'){ + if(yych <= 'B') goto yy85; + if(yych >= 'D') goto yy88; + goto yy3; + } else { + if(yych <= 'F') goto yy86; + if(yych >= 'T') goto yy88; + goto yy3; + } + } + } else { + if(yych <= 'e'){ + if(yych <= 'a'){ + if(yych == 'X') goto yy92; + goto yy3; + } else { + if(yych <= 'b') goto yy85; + if(yych >= 'd') goto yy88; + goto yy3; + } + } else { + if(yych <= 't'){ + if(yych <= 'f') goto yy86; + if(yych >= 't') goto yy88; + goto yy3; + } else { + if(yych == 'x') goto yy92; + goto yy3; + } + } + } +yy3: +{ + savech = s->tok[TOKLEN]; + s->tok[TOKLEN] = '\0'; + lvalp->intn = yasm_intnum_create_dec(TOK); + s->tok[TOKLEN] = savech; + RETURN(INTNUM); + } +yy4: yych = *++YYCURSOR; + if(yych <= 'E'){ + if(yych <= ':'){ + if(yych <= '9') goto yy84; + goto yy81; + } else { + if(yych == 'B') goto yy77; + goto yy84; + } + } else { + if(yych <= 'b'){ + if(yych <= 'F') goto yy79; + if(yych <= 'a') goto yy84; + goto yy77; + } else { + if(yych == 'f') goto yy79; + goto yy84; + } + } +yy5: yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == '.') goto yy61; + if(yych <= '/') goto yy6; + if(yych <= '9') goto yy59; + goto yy6; +yy6: +{ RETURN(s->tok[0]); } +yy7: yych = *++YYCURSOR; + if(yybm[0+yych] & 16) { + goto yy49; + } + goto yy37; +yy8: +{ + lvalp->str.contents = yasm__xstrndup(TOK, TOKLEN); + lvalp->str.len = TOKLEN; + RETURN(ID); + } +yy9: yych = *++YYCURSOR; + goto yy10; +yy10: +{ + goto charconst; + } +yy11: yych = *++YYCURSOR; + goto yy12; +yy12: +{ + goto stringconst; + } +yy13: yych = *++YYCURSOR; + if(yych == '<') goto yy47; + goto yy14; +yy14: +{ RETURN(LEFT_OP); } +yy15: yych = *++YYCURSOR; + if(yych == '>') goto yy45; + goto yy16; +yy16: +{ RETURN(RIGHT_OP); } +yy17: yych = *++YYCURSOR; + goto yy6; +yy18: yych = *++YYCURSOR; + if(yych == '*') goto yy43; + if(yych == '/') goto yy41; + goto yy6; +yy19: yych = *++YYCURSOR; + goto yy20; +yy20: +{ + parser_gas->state = INITIAL; + RETURN(s->tok[0]); + } +yy21: yych = *++YYCURSOR; + goto yy37; +yy22: yych = *++YYCURSOR; + if(yybm[0+yych] & 2) { + goto yy33; + } + goto yy23; +yy23: +{ + yasm_warn_set(YASM_WARN_UNREC_CHAR, + N_("ignoring unrecognized character `%s'"), + yasm__conv_unprint(s->tok[0])); + goto scan; + } +yy24: yych = *++YYCURSOR; + goto yy25; +yy25: +{ + if (parser_gas->is_cpp_preproc) + { + RETURN(CPP_LINE_MARKER); + } else + goto line_comment; + } +yy26: yych = *++YYCURSOR; + goto yy32; +yy27: +{ goto scan; } +yy28: yych = *++YYCURSOR; + goto yy29; +yy29: +{ + if (parser_gas->save_input) + cursor = save_line(parser_gas, cursor); + parser_gas->state = INITIAL; + RETURN(s->tok[0]); + } +yy30: yych = *++YYCURSOR; + goto yy23; +yy31: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy32; +yy32: if(yybm[0+yych] & 1) { + goto yy31; + } + goto yy27; +yy33: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy34; +yy34: if(yybm[0+yych] & 2) { + goto yy33; + } + goto yy35; +yy35: +{ + savech = s->tok[TOKLEN]; + s->tok[TOKLEN] = '\0'; + if (parser_gas->is_nasm_preproc && strcmp(TOK+1, "line") == 0) { + s->tok[TOKLEN] = savech; + RETURN(NASM_LINE_MARKER); + } + + switch (yasm_arch_parse_check_regtmod + (p_object->arch, TOK+1, TOKLEN-1, &lvalp->arch_data)) { + case YASM_ARCH_REG: + s->tok[TOKLEN] = savech; + RETURN(REG); + case YASM_ARCH_REGGROUP: + s->tok[TOKLEN] = savech; + RETURN(REGGROUP); + case YASM_ARCH_SEGREG: + s->tok[TOKLEN] = savech; + RETURN(SEGREG); + default: + break; + } + yasm_error_set(YASM_ERROR_GENERAL, + N_("Unrecognized register name `%s'"), s->tok); + s->tok[TOKLEN] = savech; + lvalp->arch_data = 0; + RETURN(REG); + } +yy36: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy37; +yy37: if(yybm[0+yych] & 4) { + goto yy36; + } + if(yych != '@') goto yy8; + goto yy38; +yy38: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy39; +yy39: if(yybm[0+yych] & 8) { + goto yy38; + } + goto yy40; +yy40: +{ + /* if @ not part of ID, move the scanner cursor to the first @ */ + if (!((yasm_objfmt_base *)p_object->objfmt)->module->id_at_ok) + cursor = (unsigned char *)strchr(TOK, '@'); + lvalp->str.contents = yasm__xstrndup(TOK, TOKLEN); + lvalp->str.len = TOKLEN; + RETURN(ID); + } +yy41: yych = *++YYCURSOR; + goto yy42; +yy42: +{ goto line_comment; } +yy43: yych = *++YYCURSOR; + goto yy44; +yy44: +{ parser_gas->state = COMMENT; goto comment; } +yy45: yych = *++YYCURSOR; + goto yy46; +yy46: +{ RETURN(RIGHT_OP); } +yy47: yych = *++YYCURSOR; + goto yy48; +yy48: +{ RETURN(LEFT_OP); } +yy49: ++YYCURSOR; + if((YYLIMIT - YYCURSOR) < 3) YYFILL(3); + yych = *YYCURSOR; + goto yy50; +yy50: if(yybm[0+yych] & 16) { + goto yy49; + } + if(yych <= 'E'){ + if(yych <= '.'){ + if(yych == '$') goto yy36; + if(yych >= '.') goto yy36; + goto yy51; + } else { + if(yych <= '?') goto yy51; + if(yych <= '@') goto yy38; + if(yych <= 'D') goto yy36; + goto yy52; + } + } else { + if(yych <= '`'){ + if(yych <= 'Z') goto yy36; + if(yych == '_') goto yy36; + goto yy51; + } else { + if(yych == 'e') goto yy52; + if(yych <= 'z') goto yy36; + goto yy51; + } + } +yy51: +{ + savech = s->tok[TOKLEN]; + s->tok[TOKLEN] = '\0'; + lvalp->flt = yasm_floatnum_create(TOK); + s->tok[TOKLEN] = savech; + RETURN(FLTNUM); + } +yy52: yyaccept = 2; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= ','){ + if(yych == '+') goto yy55; + goto yy37; + } else { + if(yych <= '-') goto yy55; + if(yych <= '/') goto yy37; + if(yych >= ':') goto yy37; + goto yy53; + } +yy53: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy54; +yy54: if(yych <= '?'){ + if(yych <= '-'){ + if(yych == '$') goto yy36; + goto yy51; + } else { + if(yych <= '.') goto yy36; + if(yych <= '/') goto yy51; + if(yych <= '9') goto yy53; + goto yy51; + } + } else { + if(yych <= '^'){ + if(yych <= '@') goto yy38; + if(yych <= 'Z') goto yy36; + goto yy51; + } else { + if(yych == '`') goto yy51; + if(yych <= 'z') goto yy36; + goto yy51; + } + } +yy55: yych = *++YYCURSOR; + if(yych <= '/') goto yy56; + if(yych <= '9') goto yy57; + goto yy56; +yy56: YYCURSOR = YYMARKER; + switch(yyaccept){ + case 0: goto yy3; + case 6: goto yy91; + case 3: goto yy51; + case 4: goto yy66; + case 5: goto yy87; + case 1: goto yy6; + case 2: goto yy8; + } +yy57: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy58; +yy58: if(yych <= '/') goto yy51; + if(yych <= '9') goto yy57; + goto yy51; +yy59: ++YYCURSOR; + if((YYLIMIT - YYCURSOR) < 4) YYFILL(4); + yych = *YYCURSOR; + goto yy60; +yy60: if(yych == '.') goto yy65; + if(yych <= '/') goto yy56; + if(yych <= '9') goto yy59; + goto yy56; +yy61: yych = *++YYCURSOR; + if(yych <= '/') goto yy56; + if(yych >= ':') goto yy56; + goto yy62; +yy62: yyaccept = 3; + YYMARKER = ++YYCURSOR; + if((YYLIMIT - YYCURSOR) < 3) YYFILL(3); + yych = *YYCURSOR; + goto yy63; +yy63: if(yych <= 'D'){ + if(yych <= '/') goto yy51; + if(yych <= '9') goto yy62; + goto yy51; + } else { + if(yych <= 'E') goto yy64; + if(yych != 'e') goto yy51; + goto yy64; + } +yy64: yych = *++YYCURSOR; + if(yych <= ','){ + if(yych == '+') goto yy55; + goto yy56; + } else { + if(yych <= '-') goto yy55; + if(yych <= '/') goto yy56; + if(yych <= '9') goto yy57; + goto yy56; + } +yy65: yyaccept = 4; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'D'){ + if(yych <= '/') goto yy66; + if(yych <= '9') goto yy67; + goto yy66; + } else { + if(yych <= 'E') goto yy69; + if(yych == 'e') goto yy69; + goto yy66; + } +yy66: +{ + savech = s->tok[TOKLEN]; + s->tok[TOKLEN] = '\0'; + lvalp->flt = yasm_floatnum_create(TOK); + s->tok[TOKLEN] = savech; + RETURN(FLTNUM); + } +yy67: yyaccept = 3; + YYMARKER = ++YYCURSOR; + if((YYLIMIT - YYCURSOR) < 3) YYFILL(3); + yych = *YYCURSOR; + goto yy68; +yy68: if(yych <= 'D'){ + if(yych <= '/') goto yy51; + if(yych <= '9') goto yy67; + goto yy51; + } else { + if(yych <= 'E') goto yy73; + if(yych == 'e') goto yy73; + goto yy51; + } +yy69: yych = *++YYCURSOR; + if(yych <= ','){ + if(yych != '+') goto yy56; + goto yy70; + } else { + if(yych <= '-') goto yy70; + if(yych <= '/') goto yy56; + if(yych <= '9') goto yy71; + goto yy56; + } +yy70: yych = *++YYCURSOR; + if(yych <= '/') goto yy56; + if(yych >= ':') goto yy56; + goto yy71; +yy71: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy72; +yy72: if(yych <= '/') goto yy66; + if(yych <= '9') goto yy71; + goto yy66; +yy73: yych = *++YYCURSOR; + if(yych <= ','){ + if(yych != '+') goto yy56; + goto yy74; + } else { + if(yych <= '-') goto yy74; + if(yych <= '/') goto yy56; + if(yych <= '9') goto yy75; + goto yy56; + } +yy74: yych = *++YYCURSOR; + if(yych <= '/') goto yy56; + if(yych >= ':') goto yy56; + goto yy75; +yy75: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy76; +yy76: if(yych <= '/') goto yy51; + if(yych <= '9') goto yy75; + goto yy51; +yy77: yych = *++YYCURSOR; + goto yy78; +yy78: +{ + /* build local label name */ + lvalp->str.contents = yasm_xmalloc(30); + lvalp->str.len = + sprintf(lvalp->str.contents, "L%c\001%lu", s->tok[0], + parser_gas->local[s->tok[0]-'0']); + RETURN(ID); + } +yy79: yych = *++YYCURSOR; + goto yy80; +yy80: +{ + /* build local label name */ + lvalp->str.contents = yasm_xmalloc(30); + lvalp->str.len = + sprintf(lvalp->str.contents, "L%c\001%lu", s->tok[0], + parser_gas->local[s->tok[0]-'0']+1); + RETURN(ID); + } +yy81: yych = *++YYCURSOR; + goto yy82; +yy82: +{ + /* increment label index */ + parser_gas->local[s->tok[0]-'0']++; + /* build local label name */ + lvalp->str.contents = yasm_xmalloc(30); + lvalp->str.len = + sprintf(lvalp->str.contents, "L%c\001%lu", s->tok[0], + parser_gas->local[s->tok[0]-'0']); + RETURN(LABEL); + } +yy83: ++YYCURSOR; + if((YYLIMIT - YYCURSOR) < 4) YYFILL(4); + yych = *YYCURSOR; + goto yy84; +yy84: if(yych == '.') goto yy65; + if(yych <= '/') goto yy3; + if(yych <= '9') goto yy83; + goto yy3; +yy85: yych = *++YYCURSOR; + if(yybm[0+yych] & 128) { + goto yy104; + } + goto yy78; +yy86: yyaccept = 5; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == '+') goto yy96; + if(yych == '-') goto yy96; + goto yy97; +yy87: +{ + savech = s->tok[TOKLEN]; + s->tok[TOKLEN] = '\0'; + lvalp->flt = yasm_floatnum_create(TOK+2); + s->tok[TOKLEN] = savech; + RETURN(FLTNUM); + } +yy88: yyaccept = 5; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == '+') goto yy96; + if(yych == '-') goto yy96; + goto yy97; +yy89: yyaccept = 6; + YYMARKER = ++YYCURSOR; + if((YYLIMIT - YYCURSOR) < 4) YYFILL(4); + yych = *YYCURSOR; + goto yy90; +yy90: if(yybm[0+yych] & 32) { + goto yy89; + } + if(yych == '.') goto yy65; + if(yych <= '/') goto yy91; + if(yych <= '9') goto yy59; + goto yy91; +yy91: +{ + savech = s->tok[TOKLEN]; + s->tok[TOKLEN] = '\0'; + lvalp->intn = yasm_intnum_create_oct(TOK); + s->tok[TOKLEN] = savech; + RETURN(INTNUM); + } +yy92: yych = *++YYCURSOR; + if(yybm[0+yych] & 64) { + goto yy93; + } + goto yy56; +yy93: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy94; +yy94: if(yybm[0+yych] & 64) { + goto yy93; + } + goto yy95; +yy95: +{ + savech = s->tok[TOKLEN]; + s->tok[TOKLEN] = '\0'; + /* skip 0 and x */ + lvalp->intn = yasm_intnum_create_hex(TOK+2); + s->tok[TOKLEN] = savech; + RETURN(INTNUM); + } +yy96: yyaccept = 5; + YYMARKER = ++YYCURSOR; + if((YYLIMIT - YYCURSOR) < 3) YYFILL(3); + yych = *YYCURSOR; + goto yy97; +yy97: if(yych <= '9'){ + if(yych == '.') goto yy98; + if(yych <= '/') goto yy87; + goto yy96; + } else { + if(yych <= 'E'){ + if(yych <= 'D') goto yy87; + goto yy100; + } else { + if(yych == 'e') goto yy100; + goto yy87; + } + } +yy98: yyaccept = 5; + YYMARKER = ++YYCURSOR; + if((YYLIMIT - YYCURSOR) < 3) YYFILL(3); + yych = *YYCURSOR; + goto yy99; +yy99: if(yych <= 'D'){ + if(yych <= '/') goto yy87; + if(yych <= '9') goto yy98; + goto yy87; + } else { + if(yych <= 'E') goto yy100; + if(yych != 'e') goto yy87; + goto yy100; + } +yy100: yych = *++YYCURSOR; + if(yych <= ','){ + if(yych != '+') goto yy56; + goto yy101; + } else { + if(yych <= '-') goto yy101; + if(yych <= '/') goto yy56; + if(yych <= '9') goto yy102; + goto yy56; + } +yy101: yych = *++YYCURSOR; + if(yych <= '/') goto yy56; + if(yych >= ':') goto yy56; + goto yy102; +yy102: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy103; +yy103: if(yych <= '/') goto yy87; + if(yych <= '9') goto yy102; + goto yy87; +yy104: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy105; +yy105: if(yybm[0+yych] & 128) { + goto yy104; + } + goto yy106; +yy106: +{ + savech = s->tok[TOKLEN]; + s->tok[TOKLEN] = '\0'; + lvalp->intn = yasm_intnum_create_bin(TOK+2); + s->tok[TOKLEN] = savech; + RETURN(INTNUM); + } +} +} + + + /* C-style comment; nesting not supported */ +comment: + SCANINIT(); + + { + +{ + YYCTYPE yych; + goto yy107; + ++YYCURSOR; +yy107: + if((YYLIMIT - YYCURSOR) < 2) YYFILL(2); + yych = *YYCURSOR; + if(yych == '\n') goto yy111; + if(yych != '*') goto yy113; + goto yy109; +yy109: yych = *++YYCURSOR; + if(yych == '/') goto yy114; + goto yy110; +yy110: +{ + if (cursor == s->eof) + return 0; + goto comment; + } +yy111: yych = *++YYCURSOR; + goto yy112; +yy112: +{ + if (parser_gas->save_input) + cursor = save_line(parser_gas, cursor); + RETURN(s->tok[0]); + } +yy113: yych = *++YYCURSOR; + goto yy110; +yy114: yych = *++YYCURSOR; + goto yy115; +yy115: +{ parser_gas->state = INITIAL; goto scan; } +} +} + + + /* Single line comment. */ +line_comment: + { + static unsigned char yybm[] = { + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 0, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + }; + +{ + YYCTYPE yych; + goto yy116; +yy117: ++YYCURSOR; +yy116: + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy118; +yy118: if(yybm[0+yych] & 128) { + goto yy117; + } + goto yy119; +yy119: +{ goto scan; } +} +} + + + /* .section directive (the section name portion thereof) */ +section_directive: + SCANINIT(); + + { + static unsigned char yybm[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 64, 0, 0, 0, 64, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 64, 0, 0, 0, 128, 0, 0, 0, + 0, 0, 0, 0, 0, 128, 128, 0, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 0, 0, 0, 0, 0, 0, + 0, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 0, 0, 0, 0, 128, + 0, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 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, 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, 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, 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, 0, + }; + +{ + YYCTYPE yych; + goto yy120; + ++YYCURSOR; +yy120: + if((YYLIMIT - YYCURSOR) < 2) YYFILL(2); + yych = *YYCURSOR; + if(yych <= '$'){ + if(yych <= '\r'){ + if(yych <= '\t'){ + if(yych <= '\b') goto yy132; + goto yy126; + } else { + if(yych <= '\n') goto yy130; + if(yych <= '\f') goto yy132; + goto yy126; + } + } else { + if(yych <= '!'){ + if(yych == ' ') goto yy126; + goto yy132; + } else { + if(yych <= '"') goto yy124; + if(yych <= '#') goto yy132; + goto yy122; + } + } + } else { + if(yych <= '@'){ + if(yych <= '.'){ + if(yych <= '+') goto yy132; + if(yych <= ',') goto yy128; + goto yy122; + } else { + if(yych <= '/') goto yy132; + if(yych >= ':') goto yy132; + goto yy122; + } + } else { + if(yych <= '_'){ + if(yych <= 'Z') goto yy122; + if(yych <= '^') goto yy132; + goto yy122; + } else { + if(yych <= '`') goto yy132; + if(yych >= '{') goto yy132; + goto yy122; + } + } + } +yy122: yych = *++YYCURSOR; + goto yy137; +yy123: +{ + lvalp->str.contents = yasm__xstrndup(TOK, TOKLEN); + lvalp->str.len = TOKLEN; + parser_gas->state = INITIAL; + RETURN(ID); + } +yy124: yych = *++YYCURSOR; + goto yy125; +yy125: +{ goto stringconst; } +yy126: yych = *++YYCURSOR; + goto yy135; +yy127: +{ goto section_directive; } +yy128: yych = *++YYCURSOR; + goto yy129; +yy129: +{ + parser_gas->state = INITIAL; + RETURN(s->tok[0]); + } +yy130: yych = *++YYCURSOR; + goto yy131; +yy131: +{ + if (parser_gas->save_input) + cursor = save_line(parser_gas, cursor); + parser_gas->state = INITIAL; + RETURN(s->tok[0]); + } +yy132: yych = *++YYCURSOR; + goto yy133; +yy133: +{ + yasm_warn_set(YASM_WARN_UNREC_CHAR, + N_("ignoring unrecognized character `%s'"), + yasm__conv_unprint(s->tok[0])); + goto section_directive; + } +yy134: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy135; +yy135: if(yybm[0+yych] & 64) { + goto yy134; + } + goto yy127; +yy136: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy137; +yy137: if(yybm[0+yych] & 128) { + goto yy136; + } + goto yy123; +} +} + + + /* filename portion of nasm preproc %line */ +nasm_filename: + strbuf = yasm_xmalloc(STRBUF_ALLOC_SIZE); + strbuf_size = STRBUF_ALLOC_SIZE; + count = 0; + +nasm_filename_scan: + SCANINIT(); + + { + static unsigned char yybm[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 128, 0, 0, 0, 128, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 128, 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, 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, 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, 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, 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, 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, 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, + }; + +{ + YYCTYPE yych; + goto yy138; + ++YYCURSOR; +yy138: + if((YYLIMIT - YYCURSOR) < 2) YYFILL(2); + yych = *YYCURSOR; + if(yych <= '\f'){ + if(yych <= '\b') goto yy144; + if(yych <= '\t') goto yy142; + if(yych >= '\v') goto yy144; + goto yy140; + } else { + if(yych <= '\r') goto yy142; + if(yych == ' ') goto yy142; + goto yy144; + } +yy140: yych = *++YYCURSOR; + goto yy141; +yy141: +{ + strbuf_append(count++, cursor, s, '\0'); + lvalp->str.contents = (char *)strbuf; + lvalp->str.len = count; + parser_gas->state = INITIAL; + RETURN(STRING); + } +yy142: yych = *++YYCURSOR; + goto yy147; +yy143: +{ goto nasm_filename_scan; } +yy144: yych = *++YYCURSOR; + goto yy145; +yy145: +{ + if (cursor == s->eof) { + strbuf_append(count++, cursor, s, '\0'); + lvalp->str.contents = (char *)strbuf; + lvalp->str.len = count; + parser_gas->state = INITIAL; + RETURN(STRING); + } + strbuf_append(count++, cursor, s, s->tok[0]); + goto nasm_filename_scan; + } +yy146: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy147; +yy147: if(yybm[0+yych] & 128) { + goto yy146; + } + goto yy143; +} +} + + + /* character constant values */ +charconst: + /*TODO*/ + + /* string constant values */ +stringconst: + strbuf = yasm_xmalloc(STRBUF_ALLOC_SIZE); + strbuf_size = STRBUF_ALLOC_SIZE; + count = 0; + +stringconst_scan: + SCANINIT(); + + { + +{ + YYCTYPE yych; + goto yy148; + ++YYCURSOR; +yy148: + if((YYLIMIT - YYCURSOR) < 2) YYFILL(2); + yych = *YYCURSOR; + if(yych == '"') goto yy152; + if(yych != '\\') goto yy154; + goto yy150; +yy150: yych = *++YYCURSOR; + if(yych != '\n') goto yy155; + goto yy151; +yy151: +{ + if (cursor == s->eof) { + yasm_error_set(YASM_ERROR_SYNTAX, + N_("unexpected end of file in string")); + lvalp->str.contents = (char *)strbuf; + lvalp->str.len = count; + RETURN(STRING); + } + strbuf_append(count++, cursor, s, s->tok[0]); + goto stringconst_scan; + } +yy152: yych = *++YYCURSOR; + goto yy153; +yy153: +{ + strbuf_append(count, cursor, s, '\0'); + yasm_unescape_cstring(strbuf, &count); + lvalp->str.contents = (char *)strbuf; + lvalp->str.len = count; + RETURN(STRING); + } +yy154: yych = *++YYCURSOR; + goto yy151; +yy155: yych = *++YYCURSOR; + goto yy156; +yy156: +{ + if (cursor == s->eof) { + yasm_error_set(YASM_ERROR_SYNTAX, + N_("unexpected end of file in string")); + lvalp->str.contents = (char *)strbuf; + lvalp->str.len = count; + RETURN(STRING); + } + strbuf_append(count++, cursor, s, '\\'); + strbuf_append(count++, cursor, s, s->tok[1]); + goto stringconst_scan; + } +} +} + +} + diff --git a/contrib/tools/yasm/modules/init_plugin.c b/contrib/tools/yasm/modules/init_plugin.c new file mode 100644 index 0000000000..86ae4c53f9 --- /dev/null +++ b/contrib/tools/yasm/modules/init_plugin.c @@ -0,0 +1,86 @@ +/* arch_lc3b arch_x86 listfmt_nasm parser_gas parser_nasm preproc_nasm preproc_raw preproc_cpp preproc_gas dbgfmt_cv8 dbgfmt_dwarf2 dbgfmt_null dbgfmt_stabs objfmt_dbg objfmt_bin objfmt_elf objfmt_elf32 objfmt_elf64 objfmt_elfx32 objfmt_coff objfmt_win32 objfmt_win64 objfmt_macho objfmt_macho32 objfmt_macho64 objfmt_rdf objfmt_xdf + rev 1 + */ + +#include <libyasm.h> +#include <libyasm/module.h> + +extern yasm_arch_module yasm_lc3b_LTX_arch; +extern yasm_arch_module yasm_x86_LTX_arch; +extern yasm_listfmt_module yasm_nasm_LTX_listfmt; +extern yasm_parser_module yasm_gas_LTX_parser; +extern yasm_parser_module yasm_nasm_LTX_parser; +extern yasm_preproc_module yasm_nasm_LTX_preproc; +extern yasm_preproc_module yasm_raw_LTX_preproc; +extern yasm_preproc_module yasm_cpp_LTX_preproc; +extern yasm_preproc_module yasm_gas_LTX_preproc; +extern yasm_dbgfmt_module yasm_cv8_LTX_dbgfmt; +extern yasm_dbgfmt_module yasm_dwarf2_LTX_dbgfmt; +extern yasm_dbgfmt_module yasm_null_LTX_dbgfmt; +extern yasm_dbgfmt_module yasm_stabs_LTX_dbgfmt; +extern yasm_objfmt_module yasm_dbg_LTX_objfmt; +extern yasm_objfmt_module yasm_bin_LTX_objfmt; +extern yasm_objfmt_module yasm_elf_LTX_objfmt; +extern yasm_objfmt_module yasm_elf32_LTX_objfmt; +extern yasm_objfmt_module yasm_elf64_LTX_objfmt; +extern yasm_objfmt_module yasm_elfx32_LTX_objfmt; +extern yasm_objfmt_module yasm_coff_LTX_objfmt; +extern yasm_objfmt_module yasm_win32_LTX_objfmt; +extern yasm_objfmt_module yasm_win64_LTX_objfmt; +extern yasm_objfmt_module yasm_macho_LTX_objfmt; +extern yasm_objfmt_module yasm_macho32_LTX_objfmt; +extern yasm_objfmt_module yasm_macho64_LTX_objfmt; +extern yasm_objfmt_module yasm_rdf_LTX_objfmt; +extern yasm_objfmt_module yasm_xdf_LTX_objfmt; +void +yasm_init_plugin(void) +{ + yasm_register_module(YASM_MODULE_ARCH, "lc3b", &yasm_lc3b_LTX_arch); + yasm_register_module(YASM_MODULE_ARCH, "x86", &yasm_x86_LTX_arch); + yasm_register_module(YASM_MODULE_LISTFMT, "nasm", &yasm_nasm_LTX_listfmt); + yasm_register_module(YASM_MODULE_PARSER, "gas", &yasm_gas_LTX_parser); + yasm_register_module(YASM_MODULE_PARSER, "nasm", &yasm_nasm_LTX_parser); + yasm_register_module(YASM_MODULE_PREPROC, "nasm", &yasm_nasm_LTX_preproc); + yasm_register_module(YASM_MODULE_PREPROC, "raw", &yasm_raw_LTX_preproc); + yasm_register_module(YASM_MODULE_PREPROC, "cpp", &yasm_cpp_LTX_preproc); + yasm_register_module(YASM_MODULE_PREPROC, "gas", &yasm_gas_LTX_preproc); + yasm_register_module(YASM_MODULE_DBGFMT, "cv8", &yasm_cv8_LTX_dbgfmt); + yasm_register_module(YASM_MODULE_DBGFMT, "dwarf2", &yasm_dwarf2_LTX_dbgfmt); + yasm_register_module(YASM_MODULE_DBGFMT, "null", &yasm_null_LTX_dbgfmt); + yasm_register_module(YASM_MODULE_DBGFMT, "stabs", &yasm_stabs_LTX_dbgfmt); + yasm_register_module(YASM_MODULE_OBJFMT, "dbg", &yasm_dbg_LTX_objfmt); + yasm_register_module(YASM_MODULE_OBJFMT, "bin", &yasm_bin_LTX_objfmt); + yasm_register_module(YASM_MODULE_OBJFMT, "elf", &yasm_elf_LTX_objfmt); + yasm_register_module(YASM_MODULE_OBJFMT, "elf32", &yasm_elf32_LTX_objfmt); + yasm_register_module(YASM_MODULE_OBJFMT, "elf64", &yasm_elf64_LTX_objfmt); + yasm_register_module(YASM_MODULE_OBJFMT, "elfx32", &yasm_elfx32_LTX_objfmt); + yasm_register_module(YASM_MODULE_OBJFMT, "coff", &yasm_coff_LTX_objfmt); + yasm_register_module(YASM_MODULE_OBJFMT, "win32", &yasm_win32_LTX_objfmt); + yasm_register_module(YASM_MODULE_OBJFMT, "win64", &yasm_win64_LTX_objfmt); + yasm_register_module(YASM_MODULE_OBJFMT, "macho", &yasm_macho_LTX_objfmt); + yasm_register_module(YASM_MODULE_OBJFMT, "macho32", &yasm_macho32_LTX_objfmt); + yasm_register_module(YASM_MODULE_OBJFMT, "macho64", &yasm_macho64_LTX_objfmt); + yasm_register_module(YASM_MODULE_OBJFMT, "rdf", &yasm_rdf_LTX_objfmt); + yasm_register_module(YASM_MODULE_OBJFMT, "xdf", &yasm_xdf_LTX_objfmt); +} + +void +yasm_plugin_set_replace(const char* replace_params[], int size) { + yasm_dwarf2_LTX_dbgfmt.replace_map = replace_params; + yasm_dwarf2_LTX_dbgfmt.replace_map_size = size; + yasm_elf_LTX_objfmt.replace_map = replace_params; + yasm_elf_LTX_objfmt.replace_map_size = size; + yasm_elf32_LTX_objfmt.replace_map = replace_params; + yasm_elf32_LTX_objfmt.replace_map_size = size; + yasm_elf64_LTX_objfmt.replace_map = replace_params; + yasm_elf64_LTX_objfmt.replace_map_size = size; + yasm_elfx32_LTX_objfmt.replace_map = replace_params; + yasm_elfx32_LTX_objfmt.replace_map_size = size; + + yasm_macho_LTX_objfmt.replace_map = replace_params; + yasm_macho_LTX_objfmt.replace_map_size = size; + yasm_macho32_LTX_objfmt.replace_map = replace_params; + yasm_macho32_LTX_objfmt.replace_map_size = size; + yasm_macho64_LTX_objfmt.replace_map = replace_params; + yasm_macho64_LTX_objfmt.replace_map_size = size; +} diff --git a/contrib/tools/yasm/modules/lc3bid.c b/contrib/tools/yasm/modules/lc3bid.c new file mode 100644 index 0000000000..89903bca51 --- /dev/null +++ b/contrib/tools/yasm/modules/lc3bid.c @@ -0,0 +1,915 @@ +/* Generated by re2c + */ +/* + * LC-3b identifier recognition and instruction handling + * + * 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 "modules/arch/lc3b/lc3barch.h" + + +/* Opcode modifiers. The opcode bytes are in "reverse" order because the + * parameters are read from the arch-specific data in LSB->MSB order. + * (only for asthetic reasons in the lexer code below, no practical reason). + */ +#define MOD_OpHAdd (1UL<<0) /* Parameter adds to upper 8 bits of insn */ +#define MOD_OpLAdd (1UL<<1) /* Parameter adds to lower 8 bits of insn */ + +/* Operand types. These are more detailed than the "general" types for all + * architectures, as they include the size, for instance. + * Bit Breakdown (from LSB to MSB): + * - 1 bit = general type (must be exact match, except for =3): + * 0 = immediate + * 1 = register + * + * MSBs than the above are 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. + * - 2 bits = action: + * 0 = does nothing (operand data is discarded) + * 1 = DR field + * 2 = SR field + * 3 = immediate + * + * Immediate operands can have different sizes. + * - 3 bits = size: + * 0 = no immediate + * 1 = 4-bit immediate + * 2 = 5-bit immediate + * 3 = 6-bit index, word (16 bit)-multiple + * 4 = 6-bit index, byte-multiple + * 5 = 8-bit immediate, word-multiple + * 6 = 9-bit signed immediate, word-multiple + * 7 = 9-bit signed offset from next PC ($+2), word-multiple + */ +#define OPT_Imm 0x0 +#define OPT_Reg 0x1 +#define OPT_MASK 0x1 + +#define OPA_None (0<<1) +#define OPA_DR (1<<1) +#define OPA_SR (2<<1) +#define OPA_Imm (3<<1) +#define OPA_MASK (3<<1) + +#define OPI_None (LC3B_IMM_NONE<<3) +#define OPI_4 (LC3B_IMM_4<<3) +#define OPI_5 (LC3B_IMM_5<<3) +#define OPI_6W (LC3B_IMM_6_WORD<<3) +#define OPI_6B (LC3B_IMM_6_BYTE<<3) +#define OPI_8 (LC3B_IMM_8<<3) +#define OPI_9 (LC3B_IMM_9<<3) +#define OPI_9PC (LC3B_IMM_9_PC<<3) +#define OPI_MASK (7<<3) + +typedef struct lc3b_insn_info { + /* 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 int modifiers; + + /* The basic 2 byte opcode */ + unsigned int opcode; + + /* The number of operands this form of the instruction takes */ + unsigned char num_operands; + + /* The types of each operand, see above */ + unsigned int operands[3]; +} lc3b_insn_info; + +typedef struct lc3b_id_insn { + yasm_insn insn; /* base structure */ + + /* instruction parse group - NULL if empty instruction (just prefixes) */ + /*@null@*/ const lc3b_insn_info *group; + + /* Modifier data */ + unsigned long mod_data; + + /* Number of elements in the instruction parse group */ + unsigned int num_info:8; +} lc3b_id_insn; + +static void lc3b_id_insn_destroy(void *contents); +static void lc3b_id_insn_print(const void *contents, FILE *f, int indent_level); +static void lc3b_id_insn_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc); + +static const yasm_bytecode_callback lc3b_id_insn_callback = { + lc3b_id_insn_destroy, + lc3b_id_insn_print, + lc3b_id_insn_finalize, + NULL, + yasm_bc_calc_len_common, + yasm_bc_expand_common, + yasm_bc_tobytes_common, + YASM_BC_SPECIAL_INSN +}; + +/* + * Instruction groupings + */ + +static const lc3b_insn_info empty_insn[] = { + { 0, 0, 0, {0, 0, 0} } +}; + +static const lc3b_insn_info addand_insn[] = { + { MOD_OpHAdd, 0x1000, 3, + {OPT_Reg|OPA_DR, OPT_Reg|OPA_SR, OPT_Reg|OPA_Imm|OPI_5} }, + { MOD_OpHAdd, 0x1020, 3, + {OPT_Reg|OPA_DR, OPT_Reg|OPA_SR, OPT_Imm|OPA_Imm|OPI_5} } +}; + +static const lc3b_insn_info br_insn[] = { + { MOD_OpHAdd, 0x0000, 1, {OPT_Imm|OPA_Imm|OPI_9PC, 0, 0} } +}; + +static const lc3b_insn_info jmp_insn[] = { + { 0, 0xC000, 2, {OPT_Reg|OPA_DR, OPT_Imm|OPA_Imm|OPI_9, 0} } +}; + +static const lc3b_insn_info lea_insn[] = { + { 0, 0xE000, 2, {OPT_Reg|OPA_DR, OPT_Imm|OPA_Imm|OPI_9PC, 0} } +}; + +static const lc3b_insn_info ldst_insn[] = { + { MOD_OpHAdd, 0x0000, 3, + {OPT_Reg|OPA_DR, OPT_Reg|OPA_SR, OPT_Imm|OPA_Imm|OPI_6W} } +}; + +static const lc3b_insn_info ldstb_insn[] = { + { MOD_OpHAdd, 0x0000, 3, + {OPT_Reg|OPA_DR, OPT_Reg|OPA_SR, OPT_Imm|OPA_Imm|OPI_6B} } +}; + +static const lc3b_insn_info not_insn[] = { + { 0, 0x903F, 2, {OPT_Reg|OPA_DR, OPT_Reg|OPA_SR, 0} } +}; + +static const lc3b_insn_info nooperand_insn[] = { + { MOD_OpHAdd, 0x0000, 0, {0, 0, 0} } +}; + +static const lc3b_insn_info shift_insn[] = { + { MOD_OpLAdd, 0xD000, 3, + {OPT_Reg|OPA_DR, OPT_Reg|OPA_SR, OPT_Imm|OPA_Imm|OPI_4} } +}; + +static const lc3b_insn_info trap_insn[] = { + { 0, 0xF000, 1, {OPT_Imm|OPA_Imm|OPI_8, 0, 0} } +}; + +static void +lc3b_id_insn_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc) +{ + lc3b_id_insn *id_insn = (lc3b_id_insn *)bc->contents; + lc3b_insn *insn; + int num_info = id_insn->num_info; + const lc3b_insn_info *info = id_insn->group; + unsigned long mod_data = id_insn->mod_data; + int found = 0; + yasm_insn_operand *op; + int i; + + yasm_insn_finalize(&id_insn->insn); + + /* Just do a simple linear search through the info array for a match. + * First match wins. + */ + for (; num_info>0 && !found; num_info--, info++) { + int mismatch = 0; + + /* Match # of operands */ + if (id_insn->insn.num_operands != info->num_operands) + continue; + + 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 = yasm_insn_ops_first(&id_insn->insn); + op && i<info->num_operands && !mismatch; + op = yasm_insn_op_next(op), i++) { + /* Check operand type */ + switch ((int)(info->operands[i] & OPT_MASK)) { + case OPT_Imm: + if (op->type != YASM_INSN__OPERAND_IMM) + mismatch = 1; + break; + case OPT_Reg: + if (op->type != YASM_INSN__OPERAND_REG) + mismatch = 1; + break; + default: + yasm_internal_error(N_("invalid operand type")); + } + + if (mismatch) + break; + } + + if (!mismatch) { + found = 1; + break; + } + } + + if (!found) { + /* Didn't find a matching one */ + yasm_error_set(YASM_ERROR_TYPE, + N_("invalid combination of opcode and operands")); + return; + } + + /* Copy what we can from info */ + insn = yasm_xmalloc(sizeof(lc3b_insn)); + yasm_value_initialize(&insn->imm, NULL, 0); + insn->imm_type = LC3B_IMM_NONE; + insn->opcode = info->opcode; + + /* Apply modifiers */ + if (info->modifiers & MOD_OpHAdd) { + insn->opcode += ((unsigned int)(mod_data & 0xFF))<<8; + mod_data >>= 8; + } + if (info->modifiers & MOD_OpLAdd) { + insn->opcode += (unsigned int)(mod_data & 0xFF); + /*mod_data >>= 8;*/ + } + + /* Go through operands and assign */ + if (id_insn->insn.num_operands > 0) { + for(i = 0, op = yasm_insn_ops_first(&id_insn->insn); + op && i<info->num_operands; op = yasm_insn_op_next(op), i++) { + + switch ((int)(info->operands[i] & OPA_MASK)) { + case OPA_None: + /* Throw away the operand contents */ + if (op->type == YASM_INSN__OPERAND_IMM) + yasm_expr_destroy(op->data.val); + break; + case OPA_DR: + if (op->type != YASM_INSN__OPERAND_REG) + yasm_internal_error(N_("invalid operand conversion")); + insn->opcode |= ((unsigned int)(op->data.reg & 0x7)) << 9; + break; + case OPA_SR: + if (op->type != YASM_INSN__OPERAND_REG) + yasm_internal_error(N_("invalid operand conversion")); + insn->opcode |= ((unsigned int)(op->data.reg & 0x7)) << 6; + break; + case OPA_Imm: + insn->imm_type = (info->operands[i] & OPI_MASK)>>3; + switch (op->type) { + case YASM_INSN__OPERAND_IMM: + if (insn->imm_type == LC3B_IMM_6_WORD + || insn->imm_type == LC3B_IMM_8 + || insn->imm_type == LC3B_IMM_9 + || insn->imm_type == LC3B_IMM_9_PC) + op->data.val = yasm_expr_create(YASM_EXPR_SHR, + yasm_expr_expr(op->data.val), + yasm_expr_int(yasm_intnum_create_uint(1)), + op->data.val->line); + if (yasm_value_finalize_expr(&insn->imm, + op->data.val, + prev_bc, 0)) + yasm_error_set(YASM_ERROR_TOO_COMPLEX, + N_("immediate expression too complex")); + break; + case YASM_INSN__OPERAND_REG: + if (yasm_value_finalize_expr(&insn->imm, + yasm_expr_create_ident(yasm_expr_int( + yasm_intnum_create_uint(op->data.reg & 0x7)), + bc->line), prev_bc, 0)) + yasm_internal_error(N_("reg expr too complex?")); + break; + default: + yasm_internal_error(N_("invalid operand conversion")); + } + break; + default: + yasm_internal_error(N_("unknown operand action")); + } + + /* Clear so it doesn't get destroyed */ + op->type = YASM_INSN__OPERAND_REG; + } + + if (insn->imm_type == LC3B_IMM_9_PC) { + if (insn->imm.seg_of || insn->imm.rshift > 1 + || insn->imm.curpos_rel) + yasm_error_set(YASM_ERROR_VALUE, N_("invalid jump target")); + insn->imm.curpos_rel = 1; + } + } + + /* Transform the bytecode */ + yasm_lc3b__bc_transform_insn(bc, insn); +} + + +#define YYCTYPE unsigned char +#define YYCURSOR id +#define YYLIMIT id +#define YYMARKER marker +#define YYFILL(n) (void)(n) + +yasm_arch_regtmod +yasm_lc3b__parse_check_regtmod(yasm_arch *arch, const char *oid, size_t id_len, + uintptr_t *data) +{ + const YYCTYPE *id = (const YYCTYPE *)oid; + /*const char *marker;*/ + +{ + YYCTYPE yych; + goto yy0; + ++YYCURSOR; +yy0: + if((YYLIMIT - YYCURSOR) < 3) YYFILL(3); + yych = *YYCURSOR; + if(yych <= 'R'){ + if(yych <= '\000') goto yy6; + if(yych <= 'Q') goto yy4; + goto yy2; + } else { + if(yych != 'r') goto yy4; + goto yy2; + } +yy2: yych = *++YYCURSOR; + if(yych <= '/') goto yy5; + if(yych <= '7') goto yy8; + goto yy5; +yy3: +{ + return YASM_ARCH_NOTREGTMOD; + } +yy4: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy5; +yy5: if(yych <= '\000') goto yy3; + goto yy4; +yy6: yych = *++YYCURSOR; + goto yy7; +yy7: +{ + return YASM_ARCH_NOTREGTMOD; + } +yy8: yych = *++YYCURSOR; + if(yych >= '\001') goto yy4; + goto yy9; +yy9: +{ + *data = (oid[1]-'0'); + return YASM_ARCH_REG; + } +} + +} + +#define RET_INSN(g, m) \ + do { \ + group = g##_insn; \ + mod = m; \ + nelems = NELEMS(g##_insn); \ + goto done; \ + } while(0) + +yasm_arch_insnprefix +yasm_lc3b__parse_check_insnprefix(yasm_arch *arch, const char *oid, + size_t id_len, unsigned long line, + yasm_bytecode **bc, uintptr_t *prefix) +{ + const YYCTYPE *id = (const YYCTYPE *)oid; + const lc3b_insn_info *group = empty_insn; + unsigned long mod = 0; + unsigned int nelems = NELEMS(empty_insn); + lc3b_id_insn *id_insn; + + *bc = (yasm_bytecode *)NULL; + *prefix = 0; + + /*const char *marker;*/ + +{ + YYCTYPE yych; + goto yy10; + ++YYCURSOR; +yy10: + if((YYLIMIT - YYCURSOR) < 6) YYFILL(6); + yych = *YYCURSOR; + if(yych <= 'T'){ + if(yych <= 'K'){ + if(yych <= 'A'){ + if(yych <= '\000') goto yy23; + if(yych <= '@') goto yy21; + goto yy12; + } else { + if(yych <= 'B') goto yy14; + if(yych == 'J') goto yy15; + goto yy21; + } + } else { + if(yych <= 'N'){ + if(yych <= 'L') goto yy16; + if(yych <= 'M') goto yy21; + goto yy18; + } else { + if(yych <= 'Q') goto yy21; + if(yych <= 'R') goto yy19; + if(yych <= 'S') goto yy17; + goto yy20; + } + } + } else { + if(yych <= 'l'){ + if(yych <= 'b'){ + if(yych <= '`') goto yy21; + if(yych >= 'b') goto yy14; + goto yy12; + } else { + if(yych == 'j') goto yy15; + if(yych <= 'k') goto yy21; + goto yy16; + } + } else { + if(yych <= 'q'){ + if(yych == 'n') goto yy18; + goto yy21; + } else { + if(yych <= 'r') goto yy19; + if(yych <= 's') goto yy17; + if(yych <= 't') goto yy20; + goto yy21; + } + } + } +yy12: yych = *++YYCURSOR; + if(yych <= 'N'){ + if(yych == 'D') goto yy88; + if(yych <= 'M') goto yy22; + goto yy89; + } else { + if(yych <= 'd'){ + if(yych <= 'c') goto yy22; + goto yy88; + } else { + if(yych == 'n') goto yy89; + goto yy22; + } + } +yy13: +{ + return YASM_ARCH_NOTINSNPREFIX; + } +yy14: yych = *++YYCURSOR; + if(yych == 'R') goto yy72; + if(yych == 'r') goto yy72; + goto yy22; +yy15: yych = *++YYCURSOR; + if(yych <= 'S'){ + if(yych == 'M') goto yy66; + if(yych <= 'R') goto yy22; + goto yy67; + } else { + if(yych <= 'm'){ + if(yych <= 'l') goto yy22; + goto yy66; + } else { + if(yych == 's') goto yy67; + goto yy22; + } + } +yy16: yych = *++YYCURSOR; + if(yych <= 'S'){ + if(yych <= 'D'){ + if(yych <= 'C') goto yy22; + goto yy53; + } else { + if(yych <= 'E') goto yy55; + if(yych <= 'R') goto yy22; + goto yy56; + } + } else { + if(yych <= 'e'){ + if(yych <= 'c') goto yy22; + if(yych <= 'd') goto yy53; + goto yy55; + } else { + if(yych == 's') goto yy56; + goto yy22; + } + } +yy17: yych = *++YYCURSOR; + if(yych == 'T') goto yy47; + if(yych == 't') goto yy47; + goto yy22; +yy18: yych = *++YYCURSOR; + if(yych == 'O') goto yy42; + if(yych == 'o') goto yy42; + goto yy22; +yy19: yych = *++YYCURSOR; + if(yych <= 'T'){ + if(yych <= 'E'){ + if(yych <= 'D') goto yy22; + goto yy29; + } else { + if(yych <= 'R') goto yy22; + if(yych <= 'S') goto yy30; + goto yy31; + } + } else { + if(yych <= 'r'){ + if(yych == 'e') goto yy29; + goto yy22; + } else { + if(yych <= 's') goto yy30; + if(yych <= 't') goto yy31; + goto yy22; + } + } +yy20: yych = *++YYCURSOR; + if(yych == 'R') goto yy25; + if(yych == 'r') goto yy25; + goto yy22; +yy21: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy22; +yy22: if(yych <= '\000') goto yy13; + goto yy21; +yy23: yych = *++YYCURSOR; + goto yy24; +yy24: +{ + return YASM_ARCH_NOTINSNPREFIX; + } +yy25: yych = *++YYCURSOR; + if(yych == 'A') goto yy26; + if(yych != 'a') goto yy22; + goto yy26; +yy26: yych = *++YYCURSOR; + if(yych == 'P') goto yy27; + if(yych != 'p') goto yy22; + goto yy27; +yy27: yych = *++YYCURSOR; + if(yych >= '\001') goto yy21; + goto yy28; +yy28: +{ RET_INSN(trap, 0); } +yy29: yych = *++YYCURSOR; + if(yych == 'T') goto yy40; + if(yych == 't') goto yy40; + goto yy22; +yy30: yych = *++YYCURSOR; + if(yych == 'H') goto yy34; + if(yych == 'h') goto yy34; + goto yy22; +yy31: yych = *++YYCURSOR; + if(yych == 'I') goto yy32; + if(yych != 'i') goto yy22; + goto yy32; +yy32: yych = *++YYCURSOR; + if(yych >= '\001') goto yy21; + goto yy33; +yy33: +{ RET_INSN(nooperand, 0x80); } +yy34: yych = *++YYCURSOR; + if(yych == 'F') goto yy35; + if(yych != 'f') goto yy22; + goto yy35; +yy35: yych = *++YYCURSOR; + if(yych <= 'L'){ + if(yych == 'A') goto yy38; + if(yych <= 'K') goto yy22; + goto yy36; + } else { + if(yych <= 'a'){ + if(yych <= '`') goto yy22; + goto yy38; + } else { + if(yych != 'l') goto yy22; + goto yy36; + } + } +yy36: yych = *++YYCURSOR; + if(yych >= '\001') goto yy21; + goto yy37; +yy37: +{ RET_INSN(shift, 0x10); } +yy38: yych = *++YYCURSOR; + if(yych >= '\001') goto yy21; + goto yy39; +yy39: +{ RET_INSN(shift, 0x30); } +yy40: yych = *++YYCURSOR; + if(yych >= '\001') goto yy21; + goto yy41; +yy41: +{ RET_INSN(nooperand, 0xCE); } +yy42: yych = *++YYCURSOR; + if(yych <= 'T'){ + if(yych == 'P') goto yy45; + if(yych <= 'S') goto yy22; + goto yy43; + } else { + if(yych <= 'p'){ + if(yych <= 'o') goto yy22; + goto yy45; + } else { + if(yych != 't') goto yy22; + goto yy43; + } + } +yy43: yych = *++YYCURSOR; + if(yych >= '\001') goto yy21; + goto yy44; +yy44: +{ RET_INSN(not, 0); } +yy45: yych = *++YYCURSOR; + if(yych >= '\001') goto yy21; + goto yy46; +yy46: +{ RET_INSN(nooperand, 0); } +yy47: yych = *++YYCURSOR; + if(yych <= 'I'){ + if(yych <= 'A'){ + if(yych >= '\001') goto yy21; + goto yy48; + } else { + if(yych <= 'B') goto yy51; + if(yych <= 'H') goto yy21; + goto yy49; + } + } else { + if(yych <= 'b'){ + if(yych <= 'a') goto yy21; + goto yy51; + } else { + if(yych == 'i') goto yy49; + goto yy21; + } + } +yy48: +{ RET_INSN(ldst, 0x30); } +yy49: yych = *++YYCURSOR; + if(yych >= '\001') goto yy21; + goto yy50; +yy50: +{ RET_INSN(ldst, 0xB0); } +yy51: yych = *++YYCURSOR; + if(yych >= '\001') goto yy21; + goto yy52; +yy52: +{ RET_INSN(ldstb, 0x70); } +yy53: yych = *++YYCURSOR; + if(yych <= 'I'){ + if(yych <= 'A'){ + if(yych >= '\001') goto yy21; + goto yy54; + } else { + if(yych <= 'B') goto yy64; + if(yych <= 'H') goto yy21; + goto yy62; + } + } else { + if(yych <= 'b'){ + if(yych <= 'a') goto yy21; + goto yy64; + } else { + if(yych == 'i') goto yy62; + goto yy21; + } + } +yy54: +{ RET_INSN(ldst, 0x20); } +yy55: yych = *++YYCURSOR; + if(yych == 'A') goto yy60; + if(yych == 'a') goto yy60; + goto yy22; +yy56: yych = *++YYCURSOR; + if(yych == 'H') goto yy57; + if(yych != 'h') goto yy22; + goto yy57; +yy57: yych = *++YYCURSOR; + if(yych == 'F') goto yy58; + if(yych != 'f') goto yy22; + goto yy58; +yy58: yych = *++YYCURSOR; + if(yych >= '\001') goto yy21; + goto yy59; +yy59: +{ RET_INSN(shift, 0x00); } +yy60: yych = *++YYCURSOR; + if(yych >= '\001') goto yy21; + goto yy61; +yy61: +{ RET_INSN(lea, 0); } +yy62: yych = *++YYCURSOR; + if(yych >= '\001') goto yy21; + goto yy63; +yy63: +{ RET_INSN(ldst, 0xA0); } +yy64: yych = *++YYCURSOR; + if(yych >= '\001') goto yy21; + goto yy65; +yy65: +{ RET_INSN(ldstb, 0x60); } +yy66: yych = *++YYCURSOR; + if(yych == 'P') goto yy70; + if(yych == 'p') goto yy70; + goto yy22; +yy67: yych = *++YYCURSOR; + if(yych == 'R') goto yy68; + if(yych != 'r') goto yy22; + goto yy68; +yy68: yych = *++YYCURSOR; + if(yych >= '\001') goto yy21; + goto yy69; +yy69: +{ RET_INSN(br, 0x40); } +yy70: yych = *++YYCURSOR; + if(yych >= '\001') goto yy21; + goto yy71; +yy71: +{ RET_INSN(jmp, 0); } +yy72: yych = *++YYCURSOR; + if(yych <= 'Z'){ + if(yych <= 'N'){ + if(yych <= '\000') goto yy73; + if(yych <= 'M') goto yy21; + goto yy74; + } else { + if(yych == 'P') goto yy78; + if(yych <= 'Y') goto yy21; + goto yy76; + } + } else { + if(yych <= 'o'){ + if(yych == 'n') goto yy74; + goto yy21; + } else { + if(yych <= 'p') goto yy78; + if(yych == 'z') goto yy76; + goto yy21; + } + } +yy73: +{ RET_INSN(br, 0x00); } +yy74: yych = *++YYCURSOR; + if(yych <= 'Z'){ + if(yych <= 'O'){ + if(yych >= '\001') goto yy21; + goto yy75; + } else { + if(yych <= 'P') goto yy82; + if(yych <= 'Y') goto yy21; + goto yy84; + } + } else { + if(yych <= 'p'){ + if(yych <= 'o') goto yy21; + goto yy82; + } else { + if(yych == 'z') goto yy84; + goto yy21; + } + } +yy75: +{ RET_INSN(br, 0x08); } +yy76: yych = *++YYCURSOR; + if(yych <= 'P'){ + if(yych <= '\000') goto yy77; + if(yych <= 'O') goto yy21; + goto yy80; + } else { + if(yych == 'p') goto yy80; + goto yy21; + } +yy77: +{ RET_INSN(br, 0x04); } +yy78: yych = *++YYCURSOR; + if(yych >= '\001') goto yy21; + goto yy79; +yy79: +{ RET_INSN(br, 0x02); } +yy80: yych = *++YYCURSOR; + if(yych >= '\001') goto yy21; + goto yy81; +yy81: +{ RET_INSN(br, 0x06); } +yy82: yych = *++YYCURSOR; + if(yych >= '\001') goto yy21; + goto yy83; +yy83: +{ RET_INSN(br, 0x0A); } +yy84: yych = *++YYCURSOR; + if(yych <= 'P'){ + if(yych <= '\000') goto yy85; + if(yych <= 'O') goto yy21; + goto yy86; + } else { + if(yych == 'p') goto yy86; + goto yy21; + } +yy85: +{ RET_INSN(br, 0x0C); } +yy86: yych = *++YYCURSOR; + if(yych >= '\001') goto yy21; + goto yy87; +yy87: +{ RET_INSN(br, 0x0E); } +yy88: yych = *++YYCURSOR; + if(yych == 'D') goto yy92; + if(yych == 'd') goto yy92; + goto yy22; +yy89: yych = *++YYCURSOR; + if(yych == 'D') goto yy90; + if(yych != 'd') goto yy22; + goto yy90; +yy90: yych = *++YYCURSOR; + if(yych >= '\001') goto yy21; + goto yy91; +yy91: +{ RET_INSN(addand, 0x40); } +yy92: yych = *++YYCURSOR; + if(yych >= '\001') goto yy21; + goto yy93; +yy93: +{ RET_INSN(addand, 0x00); } +} + + +done: + id_insn = yasm_xmalloc(sizeof(lc3b_id_insn)); + yasm_insn_initialize(&id_insn->insn); + id_insn->group = group; + id_insn->mod_data = mod; + id_insn->num_info = nelems; + *bc = yasm_bc_create_common(&lc3b_id_insn_callback, id_insn, line); + return YASM_ARCH_INSN; +} + +static void +lc3b_id_insn_destroy(void *contents) +{ + lc3b_id_insn *id_insn = (lc3b_id_insn *)contents; + yasm_insn_delete(&id_insn->insn, yasm_lc3b__ea_destroy); + yasm_xfree(contents); +} + +static void +lc3b_id_insn_print(const void *contents, FILE *f, int indent_level) +{ + const lc3b_id_insn *id_insn = (const lc3b_id_insn *)contents; + yasm_insn_print(&id_insn->insn, f, indent_level); + /*TODO*/ +} + +/*@only@*/ yasm_bytecode * +yasm_lc3b__create_empty_insn(yasm_arch *arch, unsigned long line) +{ + lc3b_id_insn *id_insn = yasm_xmalloc(sizeof(lc3b_id_insn)); + + yasm_insn_initialize(&id_insn->insn); + id_insn->group = empty_insn; + id_insn->mod_data = 0; + id_insn->num_info = NELEMS(empty_insn); + + return yasm_bc_create_common(&lc3b_id_insn_callback, id_insn, line); +} + diff --git a/contrib/tools/yasm/modules/listfmts/nasm/nasm-listfmt.c b/contrib/tools/yasm/modules/listfmts/nasm/nasm-listfmt.c new file mode 100644 index 0000000000..1dfc5b621c --- /dev/null +++ b/contrib/tools/yasm/modules/listfmts/nasm/nasm-listfmt.c @@ -0,0 +1,301 @@ +/* + * NASM-style list format + * + * Copyright (C) 2004-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> + +/* NOTE: For this code to generate relocation information, the relocations + * have to be added by the object format to each section in program source + * order. + * + * This should not be an issue, as program source order == section bytecode + * order, so unless the object formats are very obtuse with their bytecode + * iteration, this should just happen. + */ + +#define REGULAR_BUF_SIZE 1024 + +yasm_listfmt_module yasm_nasm_LTX_listfmt; + +typedef struct sectreloc { + /*@reldef@*/ SLIST_ENTRY(sectreloc) link; + yasm_section *sect; + /*@null@*/ yasm_reloc *next_reloc; /* next relocation in section */ + unsigned long next_reloc_addr; +} sectreloc; + +typedef struct bcreloc { + /*@reldef@*/ STAILQ_ENTRY(bcreloc) link; + unsigned long offset; /* start of reloc from start of bytecode */ + size_t size; /* size of reloc in bytes */ + int rel; /* PC/IP-relative or "absolute" */ +} bcreloc; + +typedef struct nasm_listfmt_output_info { + yasm_arch *arch; + /*@reldef@*/ STAILQ_HEAD(bcrelochead, bcreloc) bcrelocs; + /*@null@*/ yasm_reloc *next_reloc; /* next relocation in section */ + unsigned long next_reloc_addr; +} nasm_listfmt_output_info; + + +static /*@null@*/ /*@only@*/ yasm_listfmt * +nasm_listfmt_create(const char *in_filename, const char *obj_filename) +{ + yasm_listfmt_base *listfmt = yasm_xmalloc(sizeof(yasm_listfmt_base)); + listfmt->module = &yasm_nasm_LTX_listfmt; + return (yasm_listfmt *)listfmt; +} + +static void +nasm_listfmt_destroy(/*@only@*/ yasm_listfmt *listfmt) +{ + yasm_xfree(listfmt); +} + +static int +nasm_listfmt_output_value(yasm_value *value, unsigned char *buf, + unsigned int destsize, unsigned long offset, + yasm_bytecode *bc, int warn, /*@null@*/ void *d) +{ + /*@null@*/ nasm_listfmt_output_info *info = (nasm_listfmt_output_info *)d; + /*@dependent@*/ /*@null@*/ yasm_intnum *intn; + unsigned int valsize = value->size; + + assert(info != NULL); + + /* Output */ + switch (yasm_value_output_basic(value, buf, destsize, bc, warn, + info->arch)) { + case -1: + return 1; + case 0: + break; + default: + return 0; + } + + /* Generate reloc if needed */ + if (info->next_reloc && info->next_reloc_addr == bc->offset+offset) { + bcreloc *reloc = yasm_xmalloc(sizeof(bcreloc)); + reloc->offset = offset; + reloc->size = destsize; + reloc->rel = value->curpos_rel; + STAILQ_INSERT_TAIL(&info->bcrelocs, reloc, link); + + /* Get next reloc's info */ + info->next_reloc = yasm_section_reloc_next(info->next_reloc); + if (info->next_reloc) { + yasm_intnum *addr; + yasm_symrec *sym; + yasm_reloc_get(info->next_reloc, &addr, &sym); + info->next_reloc_addr = yasm_intnum_get_uint(addr); + } + } + + if (value->abs) { + intn = yasm_expr_get_intnum(&value->abs, 0); + if (intn) + return yasm_arch_intnum_tobytes(info->arch, intn, buf, destsize, + valsize, 0, bc, 0); + else { + yasm_error_set(YASM_ERROR_TOO_COMPLEX, + N_("relocation too complex")); + return 1; + } + } else { + int retval; + intn = yasm_intnum_create_uint(0); + retval = yasm_arch_intnum_tobytes(info->arch, intn, buf, destsize, + valsize, 0, bc, 0); + yasm_intnum_destroy(intn); + return retval; + } + + return 0; +} + +static void +nasm_listfmt_output(yasm_listfmt *listfmt, FILE *f, yasm_linemap *linemap, + yasm_arch *arch) +{ + yasm_bytecode *bc; + const char *source; + unsigned long line = 1; + unsigned long listline = 1; + /*@only@*/ unsigned char *buf; + nasm_listfmt_output_info info; + /*@reldef@*/ SLIST_HEAD(sectrelochead, sectreloc) reloc_hist; + /*@null@*/ sectreloc *last_hist = NULL; + /*@null@*/ bcreloc *reloc = NULL; + yasm_section *sect; + + SLIST_INIT(&reloc_hist); + + info.arch = arch; + + buf = yasm_xmalloc(REGULAR_BUF_SIZE); + + while (!yasm_linemap_get_source(linemap, line, &bc, &source)) { + if (!bc) { + fprintf(f, "%6lu %*s%s\n", listline++, 32, "", source); + } else { + /* get the next relocation for the bytecode's section */ + sect = yasm_bc_get_section(bc); + if (!last_hist || last_hist->sect != sect) { + int found = 0; + + /* look through reloc_hist for matching section */ + SLIST_FOREACH(last_hist, &reloc_hist, link) { + if (last_hist->sect == sect) { + found = 1; + break; + } + } + + if (!found) { + /* not found, add to list*/ + last_hist = yasm_xmalloc(sizeof(sectreloc)); + last_hist->sect = sect; + last_hist->next_reloc = yasm_section_relocs_first(sect); + + if (last_hist->next_reloc) { + yasm_intnum *addr; + yasm_symrec *sym; + yasm_reloc_get(last_hist->next_reloc, &addr, &sym); + last_hist->next_reloc_addr = + yasm_intnum_get_uint(addr); + } + + SLIST_INSERT_HEAD(&reloc_hist, last_hist, link); + } + } + + info.next_reloc = last_hist->next_reloc; + info.next_reloc_addr = last_hist->next_reloc_addr; + STAILQ_INIT(&info.bcrelocs); + + /* loop over bytecodes on this line (usually only one) */ + while (bc && bc->line == line) { + /*@null@*/ /*@only@*/ unsigned char *bigbuf; + unsigned long size = REGULAR_BUF_SIZE; + long multiple; + unsigned long offset = bc->offset; + unsigned char *origp, *p; + int gap; + + /* convert bytecode into bytes, recording relocs along the + * way + */ + bigbuf = yasm_bc_tobytes(bc, buf, &size, &gap, &info, + nasm_listfmt_output_value, NULL); + yasm_bc_get_multiple(bc, &multiple, 1); + if (multiple <= 0) + size = 0; + else + size /= multiple; + + /* output bytes with reloc information */ + origp = bigbuf ? bigbuf : buf; + p = origp; + reloc = STAILQ_FIRST(&info.bcrelocs); + if (gap) { + fprintf(f, "%6lu %08lX <gap>%*s%s\n", listline++, offset, + 18, "", source ? source : ""); + } else while (size > 0) { + int i; + + fprintf(f, "%6lu %08lX ", listline++, offset); + for (i=0; i<18 && size > 0; size--) { + if (reloc && (unsigned long)(p-origp) == + reloc->offset) { + fprintf(f, "%c", reloc->rel ? '(' : '['); + i++; + } + fprintf(f, "%02X", *(p++)); + i+=2; + if (reloc && (unsigned long)(p-origp) == + reloc->offset+reloc->size) { + fprintf(f, "%c", reloc->rel ? ')' : ']'); + i++; + reloc = STAILQ_NEXT(reloc, link); + } + } + if (size > 0) + fprintf(f, "-"); + else { + if (multiple > 1) { + fprintf(f, "<rept>"); + i += 6; + } + fprintf(f, "%*s", 18-i+1, ""); + } + if (source) { + fprintf(f, " %s", source); + source = NULL; + } + fprintf(f, "\n"); + } + + if (bigbuf) + yasm_xfree(bigbuf); + bc = STAILQ_NEXT(bc, link); + } + + /* delete bcrelocs (newly generated next bytecode if any) */ + reloc = STAILQ_FIRST(&info.bcrelocs); + while (reloc) { + bcreloc *reloc2 = STAILQ_NEXT(reloc, link); + yasm_xfree(reloc); + reloc = reloc2; + } + + /* save reloc context */ + last_hist->next_reloc = info.next_reloc; + last_hist->next_reloc_addr = info.next_reloc_addr; + } + line++; + } + + /* delete reloc history */ + while (!SLIST_EMPTY(&reloc_hist)) { + last_hist = SLIST_FIRST(&reloc_hist); + SLIST_REMOVE_HEAD(&reloc_hist, link); + yasm_xfree(last_hist); + } + + yasm_xfree(buf); +} + +/* Define listfmt structure -- see listfmt.h for details */ +yasm_listfmt_module yasm_nasm_LTX_listfmt = { + "NASM-style list format", + "nasm", + nasm_listfmt_create, + nasm_listfmt_destroy, + nasm_listfmt_output +}; diff --git a/contrib/tools/yasm/modules/nasm-macros.c b/contrib/tools/yasm/modules/nasm-macros.c new file mode 100644 index 0000000000..aa6262a7a8 --- /dev/null +++ b/contrib/tools/yasm/modules/nasm-macros.c @@ -0,0 +1,94 @@ +/* This file auto-generated from standard.mac by genmacro.c - don't edit it */ + +#include <stddef.h> + +static const char *nasm_standard_mac[] = { + "%define __FILE__", + "%define __LINE__", + "%define __SECT__ [section .text]", + "%imacro section 1+.nolist", + "%define __SECT__ [section %1]", + "__SECT__", + "%endmacro", + "%imacro segment 1+.nolist", + "%define __SECT__ [segment %1]", + "__SECT__", + "%endmacro", + "%imacro absolute 1+.nolist", + "%define __SECT__ [absolute %1]", + "__SECT__", + "%endmacro", + "%imacro struc 1-2.nolist 0", + "%push struc", + "%define %$strucname %1", + "[absolute %2]", + "%$strucname:", + "%endmacro", + "%imacro endstruc 0.nolist", + "%{$strucname}_size EQU $ - %$strucname", + "%pop", + "__SECT__", + "%endmacro", + "%imacro istruc 1.nolist", + "%push istruc", + "%define %$strucname %1", + "%$strucstart:", + "%endmacro", + "%imacro at 1-2+.nolist", + "times %1-($-%$strucstart) db 0", + "%2", + "%endmacro", + "%imacro iend 0.nolist", + "times %{$strucname}_size-($-%$strucstart) db 0", + "%pop", + "%endmacro", + "%imacro align 1-2+.nolist nop", + "%ifidni %2,nop", + "[align %1]", + "%else", + "times ($$-$) & ((%1)-1) %2", + "%endif", + "%endmacro", + "%imacro alignb 1-2+.nolist resb 1", + "times ($$-$) & ((%1)-1) %2", + "%endmacro", + "%imacro extern 1-*.nolist", + "%rep %0", + "[extern %1]", + "%rotate 1", + "%endrep", + "%endmacro", + "%imacro bits 1+.nolist", + "[bits %1]", + "%endmacro", + "%imacro use16 0.nolist", + "[bits 16]", + "%endmacro", + "%imacro use32 0.nolist", + "[bits 32]", + "%endmacro", + "%imacro use64 0.nolist", + "[bits 64]", + "%endmacro", + "%imacro global 1-*.nolist", + "%rep %0", + "[global %1]", + "%rotate 1", + "%endrep", + "%endmacro", + "%imacro common 1-*.nolist", + "%rep %0", + "[common %1]", + "%rotate 1", + "%endrep", + "%endmacro", + "%imacro cpu 1+.nolist", + "[cpu %1]", + "%endmacro", + "%imacro default 1+.nolist", + "[default %1]", + "%endmacro", + "%define __OUTPUT_FORMAT__ __YASM_OBJFMT__", + NULL +}; + diff --git a/contrib/tools/yasm/modules/nasm-token.c b/contrib/tools/yasm/modules/nasm-token.c new file mode 100644 index 0000000000..93d91b9f7b --- /dev/null +++ b/contrib/tools/yasm/modules/nasm-token.c @@ -0,0 +1,3217 @@ +/* Generated by re2c + */ +/* + * NASM-compatible re2c lexer + * + * Copyright (C) 2001-2007 Peter Johnson + * + * Portions based on re2c's example code. + * + * 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 "modules/parsers/nasm/nasm-parser.h" +#include "modules/preprocs/nasm/nasm.h" + + +#define YYCURSOR cursor +#define YYLIMIT (s->lim) +#define YYMARKER (s->ptr) +#define YYFILL(n) {} + +#define RETURN(i) {s->cur = cursor; parser_nasm->tokch = s->tok[0]; \ + return i;} + +#define SCANINIT() {s->tok = cursor;} + +#define TOK ((char *)s->tok) +#define TOKLEN (size_t)(cursor-s->tok) + + +/* starting size of string buffer */ +#define STRBUF_ALLOC_SIZE 128 + +/* string buffer used when parsing strings/character constants */ +static YYCTYPE *strbuf = NULL; + +/* length of strbuf (including terminating NULL character) */ +static size_t strbuf_size = 0; + +static int linechg_numcount; + + + +static int +handle_dot_label(YYSTYPE *lvalp, char *tok, size_t toklen, size_t zeropos, + yasm_parser_nasm *parser_nasm) +{ + /* check for special non-local labels like ..start */ + if (tok[zeropos+1] == '.') { + lvalp->str_val = yasm__xstrndup(tok+zeropos+(parser_nasm->tasm?2:0), + toklen-zeropos-(parser_nasm->tasm?2:0)); + /* check for special non-local ..@label */ + if (lvalp->str_val[zeropos+2] == '@') + return NONLOCAL_ID; + return SPECIAL_ID; + } + if (parser_nasm->masm && tok[zeropos] == '.') { + lvalp->str_val = yasm__xstrndup(tok + zeropos, toklen - zeropos); + return SPECIAL_ID; + } + if (parser_nasm->tasm && (!tasm_locals || + (tok[zeropos] == '.' && + tok[zeropos+1] != '@' && tok[zeropos+2] != '@'))) { + /* no locals on Tasm without the 'locals' directive */ + /* .foo is never local either, but .@@foo may be (local structure + * members) */ + lvalp->str_val = yasm__xstrndup(tok + zeropos, toklen - zeropos); + return SPECIAL_ID; + } + if (!parser_nasm->locallabel_base) { + lvalp->str_val = yasm__xstrndup(tok+zeropos, toklen-zeropos); + yasm_warn_set(YASM_WARN_GENERAL, + N_("no non-local label before `%s'"), + lvalp->str_val); + } else { + size_t len = toklen - zeropos + parser_nasm->locallabel_base_len; + lvalp->str_val = yasm_xmalloc(len + 1); + strcpy(lvalp->str_val, parser_nasm->locallabel_base); + strncat(lvalp->str_val, tok+zeropos, toklen-zeropos); + lvalp->str_val[len] = '\0'; + } + + return LOCAL_ID; +} + +int +nasm_parser_lex(YYSTYPE *lvalp, yasm_parser_nasm *parser_nasm) +{ + yasm_scanner *s = &parser_nasm->s; + YYCTYPE *cursor = s->cur; + YYCTYPE endch; + size_t count; + YYCTYPE savech; + + /* Handle one token of lookahead */ + if (parser_nasm->peek_token != NONE) { + int tok = parser_nasm->peek_token; + *lvalp = parser_nasm->peek_tokval; /* structure copy */ + parser_nasm->tokch = parser_nasm->peek_tokch; + parser_nasm->peek_token = NONE; + return tok; + } + + /* Catch EOL (EOF from the scanner perspective) */ + if (s->eof && cursor == s->eof) + return 0; + + /* Jump to proper "exclusive" states */ + switch (parser_nasm->state) { + case DIRECTIVE: + goto directive; + case SECTION_DIRECTIVE: + goto section_directive; + case DIRECTIVE2: + goto directive2; + case LINECHG: + goto linechg; + case LINECHG2: + goto linechg2; + default: + break; + } + +scan: + SCANINIT(); + if (*cursor == '\0') + goto endofinput; + + { + static unsigned char yybm[] = { + 0, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 3, 3, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 3, 1, + 255, 255, 63, 63, 63, 63, 63, 63, + 15, 15, 1, 1, 1, 1, 1, 3, + 3, 7, 7, 7, 7, 7, 7, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 1, 1, 1, 1, 167, + 1, 7, 7, 7, 7, 7, 7, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 1, 1, 1, 3, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 128, 0, 0, 0, 128, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 128, 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, 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, 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, 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, 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, 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, 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, + }; + +{ + YYCTYPE yych; + unsigned int yyaccept; + goto yy0; + ++YYCURSOR; +yy0: + if((YYLIMIT - YYCURSOR) < 8) YYFILL(8); + yych = *YYCURSOR; + switch(yych){ + case '\000': goto yy43; + case '\t': case '\r': case ' ': goto yy41; + case '"': case '\'': goto yy9; + case '$': goto yy7; + case '%': goto yy11; + case '&': case '(': + case ')': + case '*': + case '+': + case ',': + case '-': case ':': case '=': case '[': case '^': case '|': case '~': goto yy32; + case '.': goto yy36; + case '/': goto yy31; + case '0': goto yy2; + case '1': goto yy4; + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': goto yy5; + case '8': + case '9': goto yy6; + case ';': goto yy39; + case '<': goto yy28; + case '>': goto yy30; + case '?': goto yy33; + case '@': goto yy37; + case 'A': case 'a': goto yy26; + case 'B': case 'b': goto yy12; + case 'C': case 'F': + case 'G': case 'J': + case 'K': case 'M': case 'P': case 'U': + case 'V': case 'X': case 'Z': case '_': case 'c': case 'f': + case 'g': case 'j': + case 'k': case 'm': case 'p': case 'u': + case 'v': case 'x': case 'z': goto yy38; + case 'D': case 'd': goto yy16; + case 'E': case 'e': goto yy24; + case 'H': case 'h': goto yy14; + case 'I': case 'i': goto yy23; + case 'L': case 'l': goto yy17; + case 'N': case 'n': goto yy27; + case 'O': case 'o': goto yy20; + case 'Q': case 'q': goto yy18; + case 'R': case 'r': goto yy22; + case 'S': case 's': goto yy25; + case 'T': case 't': goto yy19; + case 'W': case 'w': goto yy15; + case 'Y': case 'y': goto yy21; + case ']': goto yy34; + default: goto yy45; + } +yy2: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yybm[0+yych] & 64) { + goto yy222; + } + switch(yych){ + case '.': goto yy203; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': goto yy216; + case '8': + case '9': goto yy206; + case 'A': case 'C': + case 'D': + case 'E': + case 'F': case 'a': case 'c': + case 'd': + case 'e': + case 'f': goto yy208; + case 'B': case 'b': goto yy224; + case 'H': case 'h': goto yy210; + case 'O': case 'Q': case 'o': case 'q': goto yy220; + case 'X': case 'x': goto yy228; + case '_': goto yy226; + default: goto yy3; + } +yy3: +{ + savech = s->tok[TOKLEN]; + s->tok[TOKLEN] = '\0'; + lvalp->intn = yasm_intnum_create_dec(TOK); + s->tok[TOKLEN] = savech; + RETURN(INTNUM); + } +yy4: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yybm[0+yych] & 64) { + goto yy222; + } + switch(yych){ + case '.': goto yy203; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': goto yy216; + case '8': + case '9': goto yy206; + case 'A': case 'C': + case 'D': + case 'E': + case 'F': case 'a': case 'c': + case 'd': + case 'e': + case 'f': goto yy208; + case 'B': case 'b': goto yy224; + case 'H': case 'h': goto yy210; + case 'O': case 'Q': case 'o': case 'q': goto yy220; + case '_': goto yy226; + default: goto yy3; + } +yy5: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yybm[0+yych] & 16) { + goto yy216; + } + if(yych <= 'P'){ + if(yych <= '@'){ + if(yych <= '.'){ + if(yych <= '-') goto yy3; + goto yy203; + } else { + if(yych <= '/') goto yy3; + if(yych <= '9') goto yy206; + goto yy3; + } + } else { + if(yych <= 'H'){ + if(yych <= 'F') goto yy208; + if(yych <= 'G') goto yy3; + goto yy210; + } else { + if(yych == 'O') goto yy220; + goto yy3; + } + } + } else { + if(yych <= 'g'){ + if(yych <= '_'){ + if(yych <= 'Q') goto yy220; + if(yych <= '^') goto yy3; + goto yy218; + } else { + if(yych <= '`') goto yy3; + if(yych <= 'f') goto yy208; + goto yy3; + } + } else { + if(yych <= 'o'){ + if(yych <= 'h') goto yy210; + if(yych <= 'n') goto yy3; + goto yy220; + } else { + if(yych == 'q') goto yy220; + goto yy3; + } + } + } +yy6: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'G'){ + if(yych <= '/'){ + if(yych == '.') goto yy203; + goto yy3; + } else { + if(yych <= '9') goto yy206; + if(yych <= '@') goto yy3; + if(yych <= 'F') goto yy208; + goto yy3; + } + } else { + if(yych <= '`'){ + if(yych <= 'H') goto yy210; + if(yych == '_') goto yy208; + goto yy3; + } else { + if(yych <= 'f') goto yy208; + if(yych == 'h') goto yy210; + goto yy3; + } + } +yy7: yych = *++YYCURSOR; + if(yych <= '>'){ + if(yych <= '-'){ + if(yych <= '"') goto yy8; + if(yych <= '#') goto yy194; + if(yych <= '$') goto yy197; + goto yy8; + } else { + if(yych <= '.') goto yy194; + if(yych <= '/') goto yy8; + if(yych <= '9') goto yy199; + goto yy8; + } + } else { + if(yych <= '`'){ + if(yych <= 'Z') goto yy194; + if(yych == '_') goto yy194; + goto yy8; + } else { + if(yych <= 'z') goto yy194; + if(yych == '~') goto yy194; + goto yy8; + } + } +yy8: +{ RETURN(s->tok[0]); } +yy9: yych = *++YYCURSOR; + goto yy10; +yy10: +{ + endch = s->tok[0]; + goto stringconst; + } +yy11: yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == '%') goto yy186; + if(yych == 'l') goto yy188; + goto yy8; +yy12: yych = *++YYCURSOR; + if(yych == 'Y') goto yy182; + if(yych == 'y') goto yy182; + goto yy51; +yy13: +{ + savech = s->tok[TOKLEN]; + s->tok[TOKLEN] = '\0'; + if (parser_nasm->state != INSTRUCTION) { + uintptr_t prefix; + switch (yasm_arch_parse_check_insnprefix + (p_object->arch, TOK, TOKLEN, cur_line, &lvalp->bc, + &prefix)) { + case YASM_ARCH_INSN: + parser_nasm->state = INSTRUCTION; + s->tok[TOKLEN] = savech; + RETURN(INSN); + case YASM_ARCH_PREFIX: + lvalp->arch_data = prefix; + s->tok[TOKLEN] = savech; + RETURN(PREFIX); + default: + break; + } + } + switch (yasm_arch_parse_check_regtmod + (p_object->arch, TOK, TOKLEN, &lvalp->arch_data)) { + case YASM_ARCH_REG: + s->tok[TOKLEN] = savech; + RETURN(REG); + case YASM_ARCH_SEGREG: + s->tok[TOKLEN] = savech; + RETURN(SEGREG); + case YASM_ARCH_TARGETMOD: + s->tok[TOKLEN] = savech; + RETURN(TARGETMOD); + case YASM_ARCH_REGGROUP: + if (parser_nasm->masm) { + s->tok[TOKLEN] = savech; + RETURN(REGGROUP); + } + default: + break; + } + if (parser_nasm->masm) { + if (!yasm__strcasecmp(TOK, "offset")) { + s->tok[TOKLEN] = savech; + RETURN(OFFSET); + } + } else if (parser_nasm->tasm) { + if (!yasm__strcasecmp(TOK, "shl")) { + s->tok[TOKLEN] = savech; + RETURN(LEFT_OP); + } + if (!yasm__strcasecmp(TOK, "shr")) { + s->tok[TOKLEN] = savech; + RETURN(RIGHT_OP); + } + if (!yasm__strcasecmp(TOK, "and")) { + s->tok[TOKLEN] = savech; + RETURN('&'); + } + if (!yasm__strcasecmp(TOK, "or")) { + s->tok[TOKLEN] = savech; + RETURN('|'); + } + if (!yasm__strcasecmp(TOK, "not")) { + s->tok[TOKLEN] = savech; + RETURN('~'); + } + if (!yasm__strcasecmp(TOK, "low")) { + s->tok[TOKLEN] = savech; + RETURN(LOW); + } + if (!yasm__strcasecmp(TOK, "high")) { + s->tok[TOKLEN] = savech; + RETURN(HIGH); + } + if (!yasm__strcasecmp(TOK, "offset")) { + s->tok[TOKLEN] = savech; + RETURN(OFFSET); + } + if (!yasm__strcasecmp(TOK, "fword")) { + s->tok[TOKLEN] = savech; + lvalp->int_info = yasm_arch_wordsize(p_object->arch)*2; + RETURN(SIZE_OVERRIDE); + } + if (!yasm__strcasecmp(TOK, "df")) { + s->tok[TOKLEN] = savech; + lvalp->int_info = yasm_arch_wordsize(p_object->arch)*3; + parser_nasm->state = INSTRUCTION; + RETURN(DECLARE_DATA); + } + if (!yasm__strcasecmp(TOK, "label")) { + s->tok[TOKLEN] = savech; + RETURN(LABEL); + } + if (!yasm__strcasecmp(TOK, "dup")) { + s->tok[TOKLEN] = savech; + RETURN(DUP); + } + } + /* Propagate errors in case we got a warning from the arch */ + yasm_errwarn_propagate(parser_nasm->errwarns, cur_line); + /* Just an identifier, return as such. */ + s->tok[TOKLEN] = savech; + lvalp->str_val = yasm__xstrndup(TOK, TOKLEN); + RETURN(ID); + } +yy14: yych = *++YYCURSOR; + if(yych == 'W') goto yy177; + if(yych == 'w') goto yy177; + goto yy51; +yy15: yych = *++YYCURSOR; + if(yych <= 'R'){ + if(yych == 'O') goto yy170; + if(yych <= 'Q') goto yy51; + goto yy171; + } else { + if(yych <= 'o'){ + if(yych <= 'n') goto yy51; + goto yy170; + } else { + if(yych == 'r') goto yy171; + goto yy51; + } + } +yy16: yych = *++YYCURSOR; + switch(yych){ + case 'B': case 'b': goto yy144; + case 'D': case 'd': goto yy146; + case 'H': case 'h': goto yy148; + case 'O': case 'o': goto yy149; + case 'Q': case 'q': goto yy151; + case 'T': case 't': goto yy153; + case 'W': case 'w': goto yy155; + case 'Y': case 'y': goto yy157; + default: goto yy51; + } +yy17: yych = *++YYCURSOR; + if(yych == 'O') goto yy140; + if(yych == 'o') goto yy140; + goto yy51; +yy18: yych = *++YYCURSOR; + if(yych == 'W') goto yy135; + if(yych == 'w') goto yy135; + goto yy51; +yy19: yych = *++YYCURSOR; + if(yych <= 'W'){ + if(yych == 'I') goto yy125; + if(yych <= 'V') goto yy51; + goto yy126; + } else { + if(yych <= 'i'){ + if(yych <= 'h') goto yy51; + goto yy125; + } else { + if(yych == 'w') goto yy126; + goto yy51; + } + } +yy20: yych = *++YYCURSOR; + if(yych == 'W') goto yy120; + if(yych == 'w') goto yy120; + goto yy51; +yy21: yych = *++YYCURSOR; + if(yych == 'W') goto yy115; + if(yych == 'w') goto yy115; + goto yy51; +yy22: yych = *++YYCURSOR; + if(yych == 'E') goto yy92; + if(yych == 'e') goto yy92; + goto yy51; +yy23: yych = *++YYCURSOR; + if(yych == 'N') goto yy86; + if(yych == 'n') goto yy86; + goto yy51; +yy24: yych = *++YYCURSOR; + if(yych == 'Q') goto yy83; + if(yych == 'q') goto yy83; + goto yy51; +yy25: yych = *++YYCURSOR; + if(yych <= 'T'){ + if(yych == 'E') goto yy74; + if(yych <= 'S') goto yy51; + goto yy75; + } else { + if(yych <= 'e'){ + if(yych <= 'd') goto yy51; + goto yy74; + } else { + if(yych == 't') goto yy75; + goto yy51; + } + } +yy26: yych = *++YYCURSOR; + if(yych == 'B') goto yy71; + if(yych == 'b') goto yy71; + goto yy51; +yy27: yych = *++YYCURSOR; + if(yych == 'O') goto yy64; + if(yych == 'o') goto yy64; + goto yy51; +yy28: yych = *++YYCURSOR; + if(yych == '<') goto yy62; + goto yy29; +yy29: +{ + yasm_warn_set(YASM_WARN_UNREC_CHAR, + N_("ignoring unrecognized character `%s'"), + yasm__conv_unprint(s->tok[0])); + goto scan; + } +yy30: yych = *++YYCURSOR; + if(yych == '>') goto yy60; + goto yy29; +yy31: yych = *++YYCURSOR; + if(yych == '/') goto yy58; + goto yy8; +yy32: yych = *++YYCURSOR; + goto yy8; +yy33: yych = *++YYCURSOR; + if(yybm[0+yych] & 2) { + goto yy50; + } + goto yy8; +yy34: yych = *++YYCURSOR; + goto yy35; +yy35: +{ RETURN(s->tok[0]); } +yy36: yych = *++YYCURSOR; + if(yych <= '>'){ + if(yych <= '-'){ + if(yych <= '"') goto yy29; + if(yych <= '$') goto yy56; + goto yy29; + } else { + if(yych == '/') goto yy29; + if(yych <= '9') goto yy56; + goto yy29; + } + } else { + if(yych <= '`'){ + if(yych <= 'Z') goto yy56; + if(yych == '_') goto yy56; + goto yy29; + } else { + if(yych <= 'z') goto yy56; + if(yych == '~') goto yy56; + goto yy29; + } + } +yy37: yych = *++YYCURSOR; + if(yych == '@') goto yy52; + goto yy51; +yy38: yych = *++YYCURSOR; + goto yy51; +yy39: yych = *++YYCURSOR; + goto yy49; +yy40: +{ goto scan; } +yy41: yych = *++YYCURSOR; + goto yy47; +yy42: +{ goto scan; } +yy43: yych = *++YYCURSOR; + goto yy44; +yy44: +{ goto endofinput; } +yy45: yych = *++YYCURSOR; + goto yy29; +yy46: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy47; +yy47: if(yybm[256+yych] & 128) { + goto yy46; + } + goto yy42; +yy48: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy49; +yy49: if(yybm[0+yych] & 1) { + goto yy48; + } + goto yy40; +yy50: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy51; +yy51: if(yybm[0+yych] & 2) { + goto yy50; + } + goto yy13; +yy52: yych = *++YYCURSOR; + if(yych <= '>'){ + if(yych <= '-'){ + if(yych <= '"') goto yy13; + if(yych >= '%') goto yy13; + goto yy53; + } else { + if(yych == '/') goto yy13; + if(yych >= ':') goto yy13; + goto yy53; + } + } else { + if(yych <= '`'){ + if(yych <= 'Z') goto yy53; + if(yych != '_') goto yy13; + goto yy53; + } else { + if(yych <= 'z') goto yy53; + if(yych != '~') goto yy13; + goto yy53; + } + } +yy53: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy54; +yy54: if(yych <= '>'){ + if(yych <= '-'){ + if(yych <= '"') goto yy55; + if(yych <= '$') goto yy53; + goto yy55; + } else { + if(yych == '/') goto yy55; + if(yych <= '9') goto yy53; + goto yy55; + } + } else { + if(yych <= '`'){ + if(yych <= 'Z') goto yy53; + if(yych == '_') goto yy53; + goto yy55; + } else { + if(yych <= 'z') goto yy53; + if(yych == '~') goto yy53; + goto yy55; + } + } +yy55: +{ + RETURN(handle_dot_label(lvalp, TOK, TOKLEN, 0, parser_nasm)); + } +yy56: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy57; +yy57: if(yych <= '>'){ + if(yych <= '-'){ + if(yych <= '"') goto yy55; + if(yych <= '$') goto yy56; + goto yy55; + } else { + if(yych == '/') goto yy55; + if(yych <= '9') goto yy56; + goto yy55; + } + } else { + if(yych <= '`'){ + if(yych <= 'Z') goto yy56; + if(yych == '_') goto yy56; + goto yy55; + } else { + if(yych <= 'z') goto yy56; + if(yych == '~') goto yy56; + goto yy55; + } + } +yy58: yych = *++YYCURSOR; + goto yy59; +yy59: +{ RETURN(SIGNDIV); } +yy60: yych = *++YYCURSOR; + goto yy61; +yy61: +{ RETURN(RIGHT_OP); } +yy62: yych = *++YYCURSOR; + goto yy63; +yy63: +{ RETURN(LEFT_OP); } +yy64: yych = *++YYCURSOR; + if(yych == 'S') goto yy65; + if(yych != 's') goto yy51; + goto yy65; +yy65: yych = *++YYCURSOR; + if(yych == 'P') goto yy66; + if(yych != 'p') goto yy51; + goto yy66; +yy66: yych = *++YYCURSOR; + if(yych == 'L') goto yy67; + if(yych != 'l') goto yy51; + goto yy67; +yy67: yych = *++YYCURSOR; + if(yych == 'I') goto yy68; + if(yych != 'i') goto yy51; + goto yy68; +yy68: yych = *++YYCURSOR; + if(yych == 'T') goto yy69; + if(yych != 't') goto yy51; + goto yy69; +yy69: yych = *++YYCURSOR; + if(yybm[0+yych] & 2) { + goto yy50; + } + goto yy70; +yy70: +{ RETURN(NOSPLIT); } +yy71: yych = *++YYCURSOR; + if(yych == 'S') goto yy72; + if(yych != 's') goto yy51; + goto yy72; +yy72: yych = *++YYCURSOR; + if(yybm[0+yych] & 2) { + goto yy50; + } + goto yy73; +yy73: +{ RETURN(ABS); } +yy74: yych = *++YYCURSOR; + if(yych == 'G') goto yy81; + if(yych == 'g') goto yy81; + goto yy51; +yy75: yych = *++YYCURSOR; + if(yych == 'R') goto yy76; + if(yych != 'r') goto yy51; + goto yy76; +yy76: yych = *++YYCURSOR; + if(yych == 'I') goto yy77; + if(yych != 'i') goto yy51; + goto yy77; +yy77: yych = *++YYCURSOR; + if(yych == 'C') goto yy78; + if(yych != 'c') goto yy51; + goto yy78; +yy78: yych = *++YYCURSOR; + if(yych == 'T') goto yy79; + if(yych != 't') goto yy51; + goto yy79; +yy79: yych = *++YYCURSOR; + if(yybm[0+yych] & 2) { + goto yy50; + } + goto yy80; +yy80: +{ RETURN(STRICT); } +yy81: yych = *++YYCURSOR; + if(yybm[0+yych] & 2) { + goto yy50; + } + goto yy82; +yy82: +{ RETURN(SEG); } +yy83: yych = *++YYCURSOR; + if(yych == 'U') goto yy84; + if(yych != 'u') goto yy51; + goto yy84; +yy84: yych = *++YYCURSOR; + if(yybm[0+yych] & 2) { + goto yy50; + } + goto yy85; +yy85: +{ RETURN(EQU); } +yy86: yych = *++YYCURSOR; + if(yych == 'C') goto yy87; + if(yych != 'c') goto yy51; + goto yy87; +yy87: yych = *++YYCURSOR; + if(yych == 'B') goto yy88; + if(yych != 'b') goto yy51; + goto yy88; +yy88: yych = *++YYCURSOR; + if(yych == 'I') goto yy89; + if(yych != 'i') goto yy51; + goto yy89; +yy89: yych = *++YYCURSOR; + if(yych == 'N') goto yy90; + if(yych != 'n') goto yy51; + goto yy90; +yy90: yych = *++YYCURSOR; + if(yybm[0+yych] & 2) { + goto yy50; + } + goto yy91; +yy91: +{ RETURN(INCBIN); } +yy92: yych = *++YYCURSOR; + if(yych <= 'S'){ + if(yych == 'L') goto yy94; + if(yych <= 'R') goto yy51; + goto yy93; + } else { + if(yych <= 'l'){ + if(yych <= 'k') goto yy51; + goto yy94; + } else { + if(yych != 's') goto yy51; + goto yy93; + } + } +yy93: yych = *++YYCURSOR; + switch(yych){ + case 'B': case 'b': goto yy96; + case 'D': case 'd': goto yy98; + case 'H': case 'h': goto yy100; + case 'O': case 'o': goto yy101; + case 'Q': case 'q': goto yy103; + case 'T': case 't': goto yy105; + case 'W': case 'w': goto yy107; + case 'Y': case 'y': goto yy109; + default: goto yy51; + } +yy94: yych = *++YYCURSOR; + if(yybm[0+yych] & 2) { + goto yy50; + } + goto yy95; +yy95: +{ RETURN(REL); } +yy96: yych = *++YYCURSOR; + if(yybm[0+yych] & 2) { + goto yy50; + } + goto yy97; +yy97: +{ + lvalp->int_info = 8; + parser_nasm->state = INSTRUCTION; + RETURN(RESERVE_SPACE); + } +yy98: yych = *++YYCURSOR; + if(yych <= 'Q'){ + if(yych <= '.'){ + if(yych <= '"') goto yy99; + if(yych <= '$') goto yy50; + if(yych >= '.') goto yy50; + goto yy99; + } else { + if(yych <= '9'){ + if(yych >= '0') goto yy50; + goto yy99; + } else { + if(yych <= '>') goto yy99; + if(yych <= 'P') goto yy50; + goto yy113; + } + } + } else { + if(yych <= 'p'){ + if(yych <= '^'){ + if(yych <= 'Z') goto yy50; + goto yy99; + } else { + if(yych != '`') goto yy50; + goto yy99; + } + } else { + if(yych <= 'z'){ + if(yych <= 'q') goto yy113; + goto yy50; + } else { + if(yych == '~') goto yy50; + goto yy99; + } + } + } +yy99: +{ + lvalp->int_info = yasm_arch_wordsize(p_object->arch)*2; + parser_nasm->state = INSTRUCTION; + RETURN(RESERVE_SPACE); + } +yy100: yych = *++YYCURSOR; + if(yych == 'W') goto yy111; + if(yych == 'w') goto yy111; + goto yy51; +yy101: yych = *++YYCURSOR; + if(yybm[0+yych] & 2) { + goto yy50; + } + goto yy102; +yy102: +{ + lvalp->int_info = yasm_arch_wordsize(p_object->arch)*8; + parser_nasm->state = INSTRUCTION; + RETURN(RESERVE_SPACE); + } +yy103: yych = *++YYCURSOR; + if(yybm[0+yych] & 2) { + goto yy50; + } + goto yy104; +yy104: +{ + lvalp->int_info = yasm_arch_wordsize(p_object->arch)*4; + parser_nasm->state = INSTRUCTION; + RETURN(RESERVE_SPACE); + } +yy105: yych = *++YYCURSOR; + if(yybm[0+yych] & 2) { + goto yy50; + } + goto yy106; +yy106: +{ + lvalp->int_info = 80; + parser_nasm->state = INSTRUCTION; + RETURN(RESERVE_SPACE); + } +yy107: yych = *++YYCURSOR; + if(yybm[0+yych] & 2) { + goto yy50; + } + goto yy108; +yy108: +{ + lvalp->int_info = yasm_arch_wordsize(p_object->arch); + parser_nasm->state = INSTRUCTION; + RETURN(RESERVE_SPACE); + } +yy109: yych = *++YYCURSOR; + if(yybm[0+yych] & 2) { + goto yy50; + } + goto yy110; +yy110: +{ + lvalp->int_info = 256; + parser_nasm->state = INSTRUCTION; + RETURN(RESERVE_SPACE); + } +yy111: yych = *++YYCURSOR; + if(yybm[0+yych] & 2) { + goto yy50; + } + goto yy112; +yy112: +{ + lvalp->int_info = yasm_arch_wordsize(p_object->arch)/2; + parser_nasm->state = INSTRUCTION; + RETURN(RESERVE_SPACE); + } +yy113: yych = *++YYCURSOR; + if(yybm[0+yych] & 2) { + goto yy50; + } + goto yy114; +yy114: +{ + lvalp->int_info = yasm_arch_wordsize(p_object->arch)*8; + parser_nasm->state = INSTRUCTION; + RETURN(RESERVE_SPACE); + } +yy115: yych = *++YYCURSOR; + if(yych == 'O') goto yy116; + if(yych != 'o') goto yy51; + goto yy116; +yy116: yych = *++YYCURSOR; + if(yych == 'R') goto yy117; + if(yych != 'r') goto yy51; + goto yy117; +yy117: yych = *++YYCURSOR; + if(yych == 'D') goto yy118; + if(yych != 'd') goto yy51; + goto yy118; +yy118: yych = *++YYCURSOR; + if(yybm[0+yych] & 2) { + goto yy50; + } + goto yy119; +yy119: +{ + lvalp->int_info = 256; + RETURN(SIZE_OVERRIDE); + } +yy120: yych = *++YYCURSOR; + if(yych == 'O') goto yy121; + if(yych != 'o') goto yy51; + goto yy121; +yy121: yych = *++YYCURSOR; + if(yych == 'R') goto yy122; + if(yych != 'r') goto yy51; + goto yy122; +yy122: yych = *++YYCURSOR; + if(yych == 'D') goto yy123; + if(yych != 'd') goto yy51; + goto yy123; +yy123: yych = *++YYCURSOR; + if(yybm[0+yych] & 2) { + goto yy50; + } + goto yy124; +yy124: +{ + lvalp->int_info = yasm_arch_wordsize(p_object->arch)*8; + RETURN(SIZE_OVERRIDE); + } +yy125: yych = *++YYCURSOR; + if(yych == 'M') goto yy131; + if(yych == 'm') goto yy131; + goto yy51; +yy126: yych = *++YYCURSOR; + if(yych == 'O') goto yy127; + if(yych != 'o') goto yy51; + goto yy127; +yy127: yych = *++YYCURSOR; + if(yych == 'R') goto yy128; + if(yych != 'r') goto yy51; + goto yy128; +yy128: yych = *++YYCURSOR; + if(yych == 'D') goto yy129; + if(yych != 'd') goto yy51; + goto yy129; +yy129: yych = *++YYCURSOR; + if(yybm[0+yych] & 2) { + goto yy50; + } + goto yy130; +yy130: +{ lvalp->int_info = 80; RETURN(SIZE_OVERRIDE); } +yy131: yych = *++YYCURSOR; + if(yych == 'E') goto yy132; + if(yych != 'e') goto yy51; + goto yy132; +yy132: yych = *++YYCURSOR; + if(yych == 'S') goto yy133; + if(yych != 's') goto yy51; + goto yy133; +yy133: yych = *++YYCURSOR; + if(yybm[0+yych] & 2) { + goto yy50; + } + goto yy134; +yy134: +{ RETURN(TIMES); } +yy135: yych = *++YYCURSOR; + if(yych == 'O') goto yy136; + if(yych != 'o') goto yy51; + goto yy136; +yy136: yych = *++YYCURSOR; + if(yych == 'R') goto yy137; + if(yych != 'r') goto yy51; + goto yy137; +yy137: yych = *++YYCURSOR; + if(yych == 'D') goto yy138; + if(yych != 'd') goto yy51; + goto yy138; +yy138: yych = *++YYCURSOR; + if(yybm[0+yych] & 2) { + goto yy50; + } + goto yy139; +yy139: +{ + lvalp->int_info = yasm_arch_wordsize(p_object->arch)*4; + RETURN(SIZE_OVERRIDE); + } +yy140: yych = *++YYCURSOR; + if(yych == 'N') goto yy141; + if(yych != 'n') goto yy51; + goto yy141; +yy141: yych = *++YYCURSOR; + if(yych == 'G') goto yy142; + if(yych != 'g') goto yy51; + goto yy142; +yy142: yych = *++YYCURSOR; + if(yybm[0+yych] & 2) { + goto yy50; + } + goto yy143; +yy143: +{ + lvalp->int_info = yasm_arch_wordsize(p_object->arch)*2; + RETURN(SIZE_OVERRIDE); + } +yy144: yych = *++YYCURSOR; + if(yybm[0+yych] & 2) { + goto yy50; + } + goto yy145; +yy145: +{ + lvalp->int_info = 8; + parser_nasm->state = INSTRUCTION; + RETURN(DECLARE_DATA); + } +yy146: yych = *++YYCURSOR; + if(yych <= 'Q'){ + if(yych <= '.'){ + if(yych <= '"') goto yy147; + if(yych <= '$') goto yy50; + if(yych >= '.') goto yy50; + goto yy147; + } else { + if(yych <= '9'){ + if(yych >= '0') goto yy50; + goto yy147; + } else { + if(yych <= '>') goto yy147; + if(yych <= 'P') goto yy50; + goto yy168; + } + } + } else { + if(yych <= 'p'){ + if(yych <= '^'){ + if(yych <= 'Z') goto yy50; + goto yy147; + } else { + if(yych != '`') goto yy50; + goto yy147; + } + } else { + if(yych <= 'z'){ + if(yych <= 'q') goto yy168; + goto yy50; + } else { + if(yych == '~') goto yy50; + goto yy147; + } + } + } +yy147: +{ + lvalp->int_info = yasm_arch_wordsize(p_object->arch)*2; + parser_nasm->state = INSTRUCTION; + RETURN(DECLARE_DATA); + } +yy148: yych = *++YYCURSOR; + if(yych == 'W') goto yy166; + if(yych == 'w') goto yy166; + goto yy51; +yy149: yych = *++YYCURSOR; + if(yybm[0+yych] & 2) { + goto yy50; + } + goto yy150; +yy150: +{ + lvalp->int_info = yasm_arch_wordsize(p_object->arch)*8; + parser_nasm->state = INSTRUCTION; + RETURN(DECLARE_DATA); + } +yy151: yych = *++YYCURSOR; + if(yych <= 'W'){ + if(yych <= '.'){ + if(yych <= '"') goto yy152; + if(yych <= '$') goto yy50; + if(yych >= '.') goto yy50; + goto yy152; + } else { + if(yych <= '9'){ + if(yych >= '0') goto yy50; + goto yy152; + } else { + if(yych <= '>') goto yy152; + if(yych <= 'V') goto yy50; + goto yy161; + } + } + } else { + if(yych <= 'v'){ + if(yych <= '^'){ + if(yych <= 'Z') goto yy50; + goto yy152; + } else { + if(yych != '`') goto yy50; + goto yy152; + } + } else { + if(yych <= 'z'){ + if(yych <= 'w') goto yy161; + goto yy50; + } else { + if(yych == '~') goto yy50; + goto yy152; + } + } + } +yy152: +{ + lvalp->int_info = yasm_arch_wordsize(p_object->arch)*4; + parser_nasm->state = INSTRUCTION; + RETURN(DECLARE_DATA); + } +yy153: yych = *++YYCURSOR; + if(yybm[0+yych] & 2) { + goto yy50; + } + goto yy154; +yy154: +{ + lvalp->int_info = 80; + parser_nasm->state = INSTRUCTION; + RETURN(DECLARE_DATA); + } +yy155: yych = *++YYCURSOR; + if(yych <= 'O'){ + if(yych <= '.'){ + if(yych <= '"') goto yy156; + if(yych <= '$') goto yy50; + if(yych >= '.') goto yy50; + goto yy156; + } else { + if(yych <= '9'){ + if(yych >= '0') goto yy50; + goto yy156; + } else { + if(yych <= '>') goto yy156; + if(yych <= 'N') goto yy50; + goto yy159; + } + } + } else { + if(yych <= 'n'){ + if(yych <= '^'){ + if(yych <= 'Z') goto yy50; + goto yy156; + } else { + if(yych != '`') goto yy50; + goto yy156; + } + } else { + if(yych <= 'z'){ + if(yych <= 'o') goto yy159; + goto yy50; + } else { + if(yych == '~') goto yy50; + goto yy156; + } + } + } +yy156: +{ + lvalp->int_info = yasm_arch_wordsize(p_object->arch); + parser_nasm->state = INSTRUCTION; + RETURN(DECLARE_DATA); + } +yy157: yych = *++YYCURSOR; + if(yybm[0+yych] & 2) { + goto yy50; + } + goto yy158; +yy158: +{ + lvalp->int_info = 256; + parser_nasm->state = INSTRUCTION; + RETURN(DECLARE_DATA); + } +yy159: yych = *++YYCURSOR; + if(yych == 'R') goto yy160; + if(yych != 'r') goto yy51; + goto yy160; +yy160: yych = *++YYCURSOR; + if(yych == 'D') goto yy142; + if(yych == 'd') goto yy142; + goto yy51; +yy161: yych = *++YYCURSOR; + if(yych == 'O') goto yy162; + if(yych != 'o') goto yy51; + goto yy162; +yy162: yych = *++YYCURSOR; + if(yych == 'R') goto yy163; + if(yych != 'r') goto yy51; + goto yy163; +yy163: yych = *++YYCURSOR; + if(yych == 'D') goto yy164; + if(yych != 'd') goto yy51; + goto yy164; +yy164: yych = *++YYCURSOR; + if(yybm[0+yych] & 2) { + goto yy50; + } + goto yy165; +yy165: +{ + lvalp->int_info = yasm_arch_wordsize(p_object->arch)*8; + RETURN(SIZE_OVERRIDE); + } +yy166: yych = *++YYCURSOR; + if(yybm[0+yych] & 2) { + goto yy50; + } + goto yy167; +yy167: +{ + lvalp->int_info = yasm_arch_wordsize(p_object->arch)/2; + parser_nasm->state = INSTRUCTION; + RETURN(DECLARE_DATA); + } +yy168: yych = *++YYCURSOR; + if(yybm[0+yych] & 2) { + goto yy50; + } + goto yy169; +yy169: +{ + lvalp->int_info = yasm_arch_wordsize(p_object->arch)*8; + parser_nasm->state = INSTRUCTION; + RETURN(DECLARE_DATA); + } +yy170: yych = *++YYCURSOR; + if(yych == 'R') goto yy174; + if(yych == 'r') goto yy174; + goto yy51; +yy171: yych = *++YYCURSOR; + if(yych == 'T') goto yy172; + if(yych != 't') goto yy51; + goto yy172; +yy172: yych = *++YYCURSOR; + if(yybm[0+yych] & 2) { + goto yy50; + } + goto yy173; +yy173: +{ RETURN(WRT); } +yy174: yych = *++YYCURSOR; + if(yych == 'D') goto yy175; + if(yych != 'd') goto yy51; + goto yy175; +yy175: yych = *++YYCURSOR; + if(yybm[0+yych] & 2) { + goto yy50; + } + goto yy176; +yy176: +{ + lvalp->int_info = yasm_arch_wordsize(p_object->arch); + RETURN(SIZE_OVERRIDE); + } +yy177: yych = *++YYCURSOR; + if(yych == 'O') goto yy178; + if(yych != 'o') goto yy51; + goto yy178; +yy178: yych = *++YYCURSOR; + if(yych == 'R') goto yy179; + if(yych != 'r') goto yy51; + goto yy179; +yy179: yych = *++YYCURSOR; + if(yych == 'D') goto yy180; + if(yych != 'd') goto yy51; + goto yy180; +yy180: yych = *++YYCURSOR; + if(yybm[0+yych] & 2) { + goto yy50; + } + goto yy181; +yy181: +{ + lvalp->int_info = yasm_arch_wordsize(p_object->arch)/2; + RETURN(SIZE_OVERRIDE); + } +yy182: yych = *++YYCURSOR; + if(yych == 'T') goto yy183; + if(yych != 't') goto yy51; + goto yy183; +yy183: yych = *++YYCURSOR; + if(yych == 'E') goto yy184; + if(yych != 'e') goto yy51; + goto yy184; +yy184: yych = *++YYCURSOR; + if(yybm[0+yych] & 2) { + goto yy50; + } + goto yy185; +yy185: +{ lvalp->int_info = 8; RETURN(SIZE_OVERRIDE); } +yy186: yych = *++YYCURSOR; + goto yy187; +yy187: +{ RETURN(SIGNMOD); } +yy188: yych = *++YYCURSOR; + if(yych == 'i') goto yy190; + goto yy189; +yy189: YYCURSOR = YYMARKER; + switch(yyaccept){ + case 0: goto yy3; + case 3: goto yy225; + case 2: goto yy205; + case 1: goto yy8; + } +yy190: yych = *++YYCURSOR; + if(yych != 'n') goto yy189; + goto yy191; +yy191: yych = *++YYCURSOR; + if(yych != 'e') goto yy189; + goto yy192; +yy192: yych = *++YYCURSOR; + goto yy193; +yy193: +{ + parser_nasm->state = LINECHG; + linechg_numcount = 0; + RETURN(LINE); + } +yy194: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy195; +yy195: if(yych <= '>'){ + if(yych <= '-'){ + if(yych <= '"') goto yy196; + if(yych <= '$') goto yy194; + goto yy196; + } else { + if(yych == '/') goto yy196; + if(yych <= '9') goto yy194; + goto yy196; + } + } else { + if(yych <= '`'){ + if(yych <= 'Z') goto yy194; + if(yych == '_') goto yy194; + goto yy196; + } else { + if(yych <= 'z') goto yy194; + if(yych == '~') goto yy194; + goto yy196; + } + } +yy196: +{ + if (TOK[1] == '.' || + (parser_nasm->tasm && TOK[1] == '@' && TOK[2] == '@')) { + /* handle like .label */ + RETURN(handle_dot_label(lvalp, TOK, TOKLEN, 1, parser_nasm)); + } + lvalp->str_val = yasm__xstrndup(TOK+1, TOKLEN-1); + RETURN(ID); + } +yy197: yych = *++YYCURSOR; + if(yych <= '>'){ + if(yych <= '-'){ + if(yych <= '"') goto yy198; + if(yych <= '$') goto yy194; + goto yy198; + } else { + if(yych == '/') goto yy198; + if(yych <= '9') goto yy194; + goto yy198; + } + } else { + if(yych <= '`'){ + if(yych <= 'Z') goto yy194; + if(yych == '_') goto yy194; + goto yy198; + } else { + if(yych <= 'z') goto yy194; + if(yych == '~') goto yy194; + goto yy198; + } + } +yy198: +{ RETURN(START_SECTION_ID); } +yy199: yych = *++YYCURSOR; + if(yybm[0+yych] & 4) { + goto yy200; + } + goto yy195; +yy200: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy201; +yy201: if(yybm[0+yych] & 4) { + goto yy200; + } + if(yych <= '>'){ + if(yych <= '$'){ + if(yych >= '#') goto yy194; + goto yy202; + } else { + if(yych == '.') goto yy194; + goto yy202; + } + } else { + if(yych <= 'z'){ + if(yych <= 'Z') goto yy194; + if(yych >= 'g') goto yy194; + goto yy202; + } else { + if(yych == '~') goto yy194; + goto yy202; + } + } +yy202: +{ + savech = s->tok[TOKLEN]; + s->tok[TOKLEN] = '\0'; + if (s->tok[1] == 'x' || s->tok[1] == 'X') + /* skip 0 and x */ + lvalp->intn = yasm_intnum_create_hex(TOK+2); + else + /* don't skip 0 */ + lvalp->intn = yasm_intnum_create_hex(TOK+1); + s->tok[TOKLEN] = savech; + RETURN(INTNUM); + } +yy203: yyaccept = 2; + YYMARKER = ++YYCURSOR; + if((YYLIMIT - YYCURSOR) < 3) YYFILL(3); + yych = *YYCURSOR; + goto yy204; +yy204: if(yybm[0+yych] & 8) { + goto yy203; + } + if(yych == 'E') goto yy212; + if(yych == 'e') goto yy212; + goto yy205; +yy205: +{ + savech = s->tok[TOKLEN]; + s->tok[TOKLEN] = '\0'; + lvalp->flt = yasm_floatnum_create(TOK); + s->tok[TOKLEN] = savech; + RETURN(FLTNUM); + } +yy206: yyaccept = 0; + YYMARKER = ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy207; +yy207: if(yych <= 'G'){ + if(yych <= '/'){ + if(yych == '.') goto yy203; + goto yy3; + } else { + if(yych <= '9') goto yy206; + if(yych <= '@') goto yy3; + if(yych >= 'G') goto yy3; + goto yy208; + } + } else { + if(yych <= '`'){ + if(yych <= 'H') goto yy210; + if(yych != '_') goto yy3; + goto yy208; + } else { + if(yych <= 'f') goto yy208; + if(yych == 'h') goto yy210; + goto yy3; + } + } +yy208: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy209; +yy209: if(yych <= 'H'){ + if(yych <= '@'){ + if(yych <= '/') goto yy189; + if(yych <= '9') goto yy208; + goto yy189; + } else { + if(yych <= 'F') goto yy208; + if(yych <= 'G') goto yy189; + goto yy210; + } + } else { + if(yych <= '`'){ + if(yych == '_') goto yy208; + goto yy189; + } else { + if(yych <= 'f') goto yy208; + if(yych != 'h') goto yy189; + goto yy210; + } + } +yy210: yych = *++YYCURSOR; + goto yy211; +yy211: +{ + s->tok[TOKLEN-1] = '\0'; /* strip off 'h' */ + lvalp->intn = yasm_intnum_create_hex(TOK); + RETURN(INTNUM); + } +yy212: yych = *++YYCURSOR; + if(yych <= ','){ + if(yych != '+') goto yy189; + goto yy213; + } else { + if(yych <= '-') goto yy213; + if(yych <= '/') goto yy189; + if(yych <= '9') goto yy214; + goto yy189; + } +yy213: yych = *++YYCURSOR; + if(yych <= '/') goto yy189; + if(yych >= ':') goto yy189; + goto yy214; +yy214: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy215; +yy215: if(yych <= '/') goto yy205; + if(yych <= '9') goto yy214; + goto yy205; +yy216: yyaccept = 0; + YYMARKER = ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy217; +yy217: if(yybm[0+yych] & 16) { + goto yy216; + } + if(yych <= 'P'){ + if(yych <= '@'){ + if(yych <= '.'){ + if(yych <= '-') goto yy3; + goto yy203; + } else { + if(yych <= '/') goto yy3; + if(yych <= '9') goto yy206; + goto yy3; + } + } else { + if(yych <= 'H'){ + if(yych <= 'F') goto yy208; + if(yych <= 'G') goto yy3; + goto yy210; + } else { + if(yych == 'O') goto yy220; + goto yy3; + } + } + } else { + if(yych <= 'g'){ + if(yych <= '_'){ + if(yych <= 'Q') goto yy220; + if(yych <= '^') goto yy3; + goto yy218; + } else { + if(yych <= '`') goto yy3; + if(yych <= 'f') goto yy208; + goto yy3; + } + } else { + if(yych <= 'o'){ + if(yych <= 'h') goto yy210; + if(yych <= 'n') goto yy3; + goto yy220; + } else { + if(yych == 'q') goto yy220; + goto yy3; + } + } + } +yy218: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy219; +yy219: if(yybm[0+yych] & 32) { + goto yy218; + } + if(yych <= 'P'){ + if(yych <= 'F'){ + if(yych <= '7') goto yy189; + if(yych <= '9') goto yy208; + if(yych <= '@') goto yy189; + goto yy208; + } else { + if(yych <= 'H'){ + if(yych <= 'G') goto yy189; + goto yy210; + } else { + if(yych != 'O') goto yy189; + goto yy220; + } + } + } else { + if(yych <= 'h'){ + if(yych <= '`'){ + if(yych >= 'R') goto yy189; + goto yy220; + } else { + if(yych <= 'f') goto yy208; + if(yych <= 'g') goto yy189; + goto yy210; + } + } else { + if(yych <= 'o'){ + if(yych <= 'n') goto yy189; + goto yy220; + } else { + if(yych != 'q') goto yy189; + goto yy220; + } + } + } +yy220: yych = *++YYCURSOR; + goto yy221; +yy221: +{ + s->tok[TOKLEN-1] = '\0'; /* strip off 'q' or 'o' */ + lvalp->intn = yasm_intnum_create_oct(TOK); + RETURN(INTNUM); + } +yy222: yyaccept = 0; + YYMARKER = ++YYCURSOR; + if((YYLIMIT - YYCURSOR) < 2) YYFILL(2); + yych = *YYCURSOR; + goto yy223; +yy223: if(yybm[0+yych] & 64) { + goto yy222; + } + switch(yych){ + case '.': goto yy203; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': goto yy216; + case '8': + case '9': goto yy206; + case 'A': case 'C': + case 'D': + case 'E': + case 'F': case 'a': case 'c': + case 'd': + case 'e': + case 'f': goto yy208; + case 'B': case 'b': goto yy224; + case 'H': case 'h': goto yy210; + case 'O': case 'Q': case 'o': case 'q': goto yy220; + case '_': goto yy226; + default: goto yy3; + } +yy224: yyaccept = 3; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'H'){ + if(yych <= '@'){ + if(yych <= '/') goto yy225; + if(yych <= '9') goto yy208; + goto yy225; + } else { + if(yych <= 'F') goto yy208; + if(yych >= 'H') goto yy210; + goto yy225; + } + } else { + if(yych <= '`'){ + if(yych == '_') goto yy208; + goto yy225; + } else { + if(yych <= 'f') goto yy208; + if(yych == 'h') goto yy210; + goto yy225; + } + } +yy225: +{ + s->tok[TOKLEN-1] = '\0'; /* strip off 'b' */ + lvalp->intn = yasm_intnum_create_bin(TOK); + RETURN(INTNUM); + } +yy226: ++YYCURSOR; + if((YYLIMIT - YYCURSOR) < 2) YYFILL(2); + yych = *YYCURSOR; + goto yy227; +yy227: if(yybm[0+yych] & 128) { + goto yy226; + } + switch(yych){ + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': goto yy218; + case '8': + case '9': case 'A': case 'C': + case 'D': + case 'E': + case 'F': case 'a': case 'c': + case 'd': + case 'e': + case 'f': goto yy208; + case 'B': case 'b': goto yy224; + case 'H': case 'h': goto yy210; + case 'O': case 'Q': case 'o': case 'q': goto yy220; + default: goto yy189; + } +yy228: yych = *++YYCURSOR; + if(yych <= 'F'){ + if(yych <= '/') goto yy189; + if(yych <= '9') goto yy229; + if(yych <= '@') goto yy189; + goto yy229; + } else { + if(yych <= '_'){ + if(yych <= '^') goto yy189; + goto yy229; + } else { + if(yych <= '`') goto yy189; + if(yych >= 'g') goto yy189; + goto yy229; + } + } +yy229: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy230; +yy230: if(yych <= 'F'){ + if(yych <= '/') goto yy202; + if(yych <= '9') goto yy229; + if(yych <= '@') goto yy202; + goto yy229; + } else { + if(yych <= '_'){ + if(yych <= '^') goto yy202; + goto yy229; + } else { + if(yych <= '`') goto yy202; + if(yych <= 'f') goto yy229; + goto yy202; + } + } +} +} + + + /* %line linenum+lineinc filename */ +linechg: + SCANINIT(); + if (*cursor == '\0') + goto endofinput; + + { + static unsigned char yybm[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 64, 0, 0, 0, 64, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 64, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 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, 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, 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, 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, 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, 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, + }; + +{ + YYCTYPE yych; + goto yy231; + ++YYCURSOR; +yy231: + if((YYLIMIT - YYCURSOR) < 2) YYFILL(2); + yych = *YYCURSOR; + if(yych <= '\037'){ + if(yych <= '\t'){ + if(yych <= '\000') goto yy235; + if(yych <= '\b') goto yy241; + goto yy239; + } else { + if(yych == '\r') goto yy239; + goto yy241; + } + } else { + if(yych <= '+'){ + if(yych <= ' ') goto yy239; + if(yych <= '*') goto yy241; + goto yy237; + } else { + if(yych <= '/') goto yy241; + if(yych >= ':') goto yy241; + goto yy233; + } + } +yy233: yych = *++YYCURSOR; + goto yy246; +yy234: +{ + linechg_numcount++; + savech = s->tok[TOKLEN]; + s->tok[TOKLEN] = '\0'; + lvalp->intn = yasm_intnum_create_dec(TOK); + s->tok[TOKLEN] = savech; + RETURN(INTNUM); + } +yy235: yych = *++YYCURSOR; + goto yy236; +yy236: +{ goto endofinput; } +yy237: yych = *++YYCURSOR; + goto yy238; +yy238: +{ + RETURN(s->tok[0]); + } +yy239: yych = *++YYCURSOR; + goto yy244; +yy240: +{ + if (linechg_numcount == 2) { + parser_nasm->state = LINECHG2; + goto linechg2; + } + goto linechg; + } +yy241: yych = *++YYCURSOR; + goto yy242; +yy242: +{ + yasm_warn_set(YASM_WARN_UNREC_CHAR, + N_("ignoring unrecognized character `%s'"), + yasm__conv_unprint(s->tok[0])); + goto linechg; + } +yy243: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy244; +yy244: if(yybm[0+yych] & 64) { + goto yy243; + } + goto yy240; +yy245: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy246; +yy246: if(yybm[0+yych] & 128) { + goto yy245; + } + goto yy234; +} +} + + +linechg2: + SCANINIT(); + if (*cursor == '\0') + goto endofinput; + + { + static unsigned char yybm[] = { + 0, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + }; + +{ + YYCTYPE yych; + goto yy247; + ++YYCURSOR; +yy247: + if((YYLIMIT - YYCURSOR) < 2) YYFILL(2); + yych = *YYCURSOR; + if(yych <= '\000') goto yy249; + if(yych == '\r') goto yy251; + goto yy253; +yy249: yych = *++YYCURSOR; + goto yy250; +yy250: +{ goto endofinput; } +yy251: yych = *++YYCURSOR; + if(yybm[0+yych] & 128) { + goto yy253; + } + goto yy252; +yy252: +{ goto linechg2; } +yy253: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy254; +yy254: if(yybm[0+yych] & 128) { + goto yy253; + } + goto yy255; +yy255: +{ + parser_nasm->state = LINECHG; + lvalp->str_val = yasm__xstrndup(TOK, TOKLEN); + RETURN(FILENAME); + } +} +} + + + /* directive: [name value] */ +directive: + SCANINIT(); + if (*cursor == '\0') + goto endofinput; + + { + static unsigned char yybm[] = { + 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, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 0, 0, 0, 0, 0, 0, + 0, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 0, 0, 0, 0, 128, + 0, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 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, 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, 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, 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, 0, + }; + +{ + YYCTYPE yych; + goto yy256; + ++YYCURSOR; +yy256: + if((YYLIMIT - YYCURSOR) < 2) YYFILL(2); + yych = *YYCURSOR; + if(yych <= ']'){ + if(yych <= '@'){ + if(yych >= '\001') goto yy263; + goto yy258; + } else { + if(yych <= 'Z') goto yy261; + if(yych <= '\\') goto yy263; + goto yy260; + } + } else { + if(yych <= '_'){ + if(yych <= '^') goto yy263; + goto yy261; + } else { + if(yych <= '`') goto yy263; + if(yych <= 'z') goto yy261; + goto yy263; + } + } +yy258: yych = *++YYCURSOR; + goto yy259; +yy259: +{ goto endofinput; } +yy260: yych = *++YYCURSOR; + goto yy259; +yy261: yych = *++YYCURSOR; + goto yy266; +yy262: +{ + lvalp->str_val = yasm__xstrndup(TOK, TOKLEN); + if (yasm__strcasecmp(lvalp->str_val, "section") == 0 || + yasm__strcasecmp(lvalp->str_val, "segment") == 0) + parser_nasm->state = SECTION_DIRECTIVE; + else + parser_nasm->state = DIRECTIVE2; + RETURN(DIRECTIVE_NAME); + } +yy263: yych = *++YYCURSOR; + goto yy264; +yy264: +{ + yasm_warn_set(YASM_WARN_UNREC_CHAR, + N_("ignoring unrecognized character `%s'"), + yasm__conv_unprint(s->tok[0])); + goto directive; + } +yy265: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy266; +yy266: if(yybm[0+yych] & 128) { + goto yy265; + } + goto yy262; +} +} + + + /* section directive (the section name portion thereof) */ +section_directive: + SCANINIT(); + if (*cursor == '\0') + goto endofinput; + + { + static unsigned char yybm[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 64, 0, 0, 0, 64, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 64, 0, 0, 128, 128, 0, 0, 0, + 0, 0, 0, 0, 0, 128, 128, 0, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 0, 0, 0, 0, 0, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 0, 0, 0, 0, 128, + 0, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 0, 0, 0, 128, 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, + 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, 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, 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, + }; + +{ + YYCTYPE yych; + goto yy267; + ++YYCURSOR; +yy267: + if((YYLIMIT - YYCURSOR) < 2) YYFILL(2); + yych = *YYCURSOR; + if(yych <= ','){ + if(yych <= '\037'){ + if(yych <= '\t'){ + if(yych <= '\000') goto yy275; + if(yych <= '\b') goto yy278; + goto yy273; + } else { + if(yych == '\r') goto yy273; + goto yy278; + } + } else { + if(yych <= '"'){ + if(yych <= ' ') goto yy273; + if(yych <= '!') goto yy278; + goto yy271; + } else { + if(yych <= '$') goto yy269; + if(yych == '\'') goto yy271; + goto yy278; + } + } + } else { + if(yych <= ']'){ + if(yych <= '9'){ + if(yych == '/') goto yy278; + goto yy269; + } else { + if(yych <= '>') goto yy278; + if(yych <= 'Z') goto yy269; + if(yych <= '\\') goto yy278; + goto yy277; + } + } else { + if(yych <= '`'){ + if(yych != '_') goto yy278; + goto yy269; + } else { + if(yych <= 'z') goto yy269; + if(yych != '~') goto yy278; + goto yy269; + } + } + } +yy269: yych = *++YYCURSOR; + goto yy283; +yy270: +{ + lvalp->str.contents = yasm__xstrndup(TOK, TOKLEN); + lvalp->str.len = TOKLEN; + parser_nasm->state = DIRECTIVE2; + RETURN(STRING); + } +yy271: yych = *++YYCURSOR; + goto yy272; +yy272: +{ + parser_nasm->state = DIRECTIVE2; + endch = s->tok[0]; + goto stringconst; + } +yy273: yych = *++YYCURSOR; + goto yy281; +yy274: +{ + parser_nasm->state = DIRECTIVE2; + goto section_directive; + } +yy275: yych = *++YYCURSOR; + goto yy276; +yy276: +{ goto endofinput; } +yy277: yych = *++YYCURSOR; + goto yy276; +yy278: yych = *++YYCURSOR; + goto yy279; +yy279: +{ + yasm_warn_set(YASM_WARN_UNREC_CHAR, + N_("ignoring unrecognized character `%s'"), + yasm__conv_unprint(s->tok[0])); + goto section_directive; + } +yy280: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy281; +yy281: if(yybm[0+yych] & 64) { + goto yy280; + } + goto yy274; +yy282: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy283; +yy283: if(yybm[0+yych] & 128) { + goto yy282; + } + goto yy270; +} +} + + + /* inner part of directive */ +directive2: + SCANINIT(); + if (*cursor == '\0') + goto endofinput; + + { + static unsigned char yybm[] = { + 0, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 3, 3, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 3, 1, + 255, 255, 63, 63, 63, 63, 63, 63, + 15, 15, 1, 1, 1, 1, 1, 3, + 3, 7, 7, 7, 7, 7, 7, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 1, 1, 1, 1, 167, + 1, 7, 7, 7, 7, 7, 7, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 1, 1, 1, 3, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 128, 0, 0, 0, 128, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 128, 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, 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, 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, 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, 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, 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, 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, + }; + +{ + YYCTYPE yych; + unsigned int yyaccept; + goto yy284; + ++YYCURSOR; +yy284: + if((YYLIMIT - YYCURSOR) < 3) YYFILL(3); + yych = *YYCURSOR; + if(yych <= '7'){ + if(yych <= '#'){ + if(yych <= '\r'){ + if(yych <= '\b'){ + if(yych <= '\000') goto yy309; + goto yy311; + } else { + if(yych <= '\t') goto yy307; + if(yych <= '\f') goto yy311; + goto yy307; + } + } else { + if(yych <= ' '){ + if(yych <= '\037') goto yy311; + goto yy307; + } else { + if(yych == '"') goto yy293; + goto yy311; + } + } + } else { + if(yych <= '-'){ + if(yych <= '%'){ + if(yych <= '$') goto yy291; + goto yy299; + } else { + if(yych == '\'') goto yy293; + goto yy300; + } + } else { + if(yych <= '/'){ + if(yych <= '.') goto yy303; + goto yy298; + } else { + if(yych <= '0') goto yy286; + if(yych <= '1') goto yy288; + goto yy289; + } + } + } + } else { + if(yych <= '['){ + if(yych <= '='){ + if(yych <= ':'){ + if(yych <= '9') goto yy290; + goto yy300; + } else { + if(yych <= ';') goto yy305; + if(yych <= '<') goto yy295; + goto yy300; + } + } else { + if(yych <= '?'){ + if(yych <= '>') goto yy297; + goto yy303; + } else { + if(yych <= '@') goto yy311; + if(yych <= 'Z') goto yy303; + goto yy300; + } + } + } else { + if(yych <= '`'){ + if(yych <= ']'){ + if(yych <= '\\') goto yy311; + goto yy301; + } else { + if(yych <= '^') goto yy300; + if(yych <= '_') goto yy303; + goto yy311; + } + } else { + if(yych <= '|'){ + if(yych <= 'z') goto yy303; + if(yych <= '{') goto yy311; + goto yy300; + } else { + if(yych == '~') goto yy300; + goto yy311; + } + } + } + } +yy286: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == 'X') goto yy352; + if(yych == 'x') goto yy352; + goto yy347; +yy287: +{ + savech = s->tok[TOKLEN]; + s->tok[TOKLEN] = '\0'; + lvalp->intn = yasm_intnum_create_dec(TOK); + s->tok[TOKLEN] = savech; + RETURN(INTNUM); + } +yy288: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + goto yy347; +yy289: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + goto yy341; +yy290: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + goto yy334; +yy291: yych = *++YYCURSOR; + if(yych <= '>'){ + if(yych <= '-'){ + if(yych <= '"') goto yy292; + if(yych <= '$') goto yy326; + goto yy292; + } else { + if(yych <= '.') goto yy326; + if(yych <= '/') goto yy292; + if(yych <= '9') goto yy329; + goto yy292; + } + } else { + if(yych <= '`'){ + if(yych <= 'Z') goto yy326; + if(yych == '_') goto yy326; + goto yy292; + } else { + if(yych <= 'z') goto yy326; + if(yych == '~') goto yy326; + goto yy292; + } + } +yy292: +{ RETURN(s->tok[0]); } +yy293: yych = *++YYCURSOR; + goto yy294; +yy294: +{ + endch = s->tok[0]; + goto stringconst; + } +yy295: yych = *++YYCURSOR; + if(yych == '<') goto yy324; + goto yy296; +yy296: +{ + yasm_warn_set(YASM_WARN_UNREC_CHAR, + N_("ignoring unrecognized character `%s'"), + yasm__conv_unprint(s->tok[0])); + goto scan; + } +yy297: yych = *++YYCURSOR; + if(yych == '>') goto yy322; + goto yy296; +yy298: yych = *++YYCURSOR; + if(yych == '/') goto yy320; + goto yy292; +yy299: yych = *++YYCURSOR; + if(yych == '%') goto yy318; + goto yy292; +yy300: yych = *++YYCURSOR; + goto yy292; +yy301: yych = *++YYCURSOR; + goto yy302; +yy302: +{ goto endofinput; } +yy303: yych = *++YYCURSOR; + goto yy317; +yy304: +{ + savech = s->tok[TOKLEN]; + s->tok[TOKLEN] = '\0'; + switch (yasm_arch_parse_check_regtmod + (p_object->arch, TOK, TOKLEN, &lvalp->arch_data)) { + case YASM_ARCH_REG: + s->tok[TOKLEN] = savech; + RETURN(REG); + default: + s->tok[TOKLEN] = savech; + } + /* Propagate errors in case we got a warning from the arch */ + yasm_errwarn_propagate(parser_nasm->errwarns, cur_line); + /* Just an identifier, return as such. */ + lvalp->str_val = yasm__xstrndup(TOK, TOKLEN); + RETURN(ID); + } +yy305: yych = *++YYCURSOR; + goto yy315; +yy306: +{ goto directive2; } +yy307: yych = *++YYCURSOR; + goto yy313; +yy308: +{ goto directive2; } +yy309: yych = *++YYCURSOR; + goto yy310; +yy310: +{ goto endofinput; } +yy311: yych = *++YYCURSOR; + goto yy296; +yy312: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy313; +yy313: if(yybm[256+yych] & 128) { + goto yy312; + } + goto yy308; +yy314: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy315; +yy315: if(yybm[0+yych] & 1) { + goto yy314; + } + goto yy306; +yy316: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy317; +yy317: if(yybm[0+yych] & 2) { + goto yy316; + } + goto yy304; +yy318: yych = *++YYCURSOR; + goto yy319; +yy319: +{ RETURN(SIGNMOD); } +yy320: yych = *++YYCURSOR; + goto yy321; +yy321: +{ RETURN(SIGNDIV); } +yy322: yych = *++YYCURSOR; + goto yy323; +yy323: +{ RETURN(RIGHT_OP); } +yy324: yych = *++YYCURSOR; + goto yy325; +yy325: +{ RETURN(LEFT_OP); } +yy326: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy327; +yy327: if(yych <= '>'){ + if(yych <= '-'){ + if(yych <= '"') goto yy328; + if(yych <= '$') goto yy326; + goto yy328; + } else { + if(yych == '/') goto yy328; + if(yych <= '9') goto yy326; + goto yy328; + } + } else { + if(yych <= '`'){ + if(yych <= 'Z') goto yy326; + if(yych == '_') goto yy326; + goto yy328; + } else { + if(yych <= 'z') goto yy326; + if(yych == '~') goto yy326; + goto yy328; + } + } +yy328: +{ + lvalp->str_val = yasm__xstrndup(TOK, TOKLEN); + RETURN(ID); + } +yy329: yych = *++YYCURSOR; + if(yybm[0+yych] & 4) { + goto yy330; + } + goto yy327; +yy330: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy331; +yy331: if(yybm[0+yych] & 4) { + goto yy330; + } + if(yych <= '>'){ + if(yych <= '$'){ + if(yych >= '#') goto yy326; + goto yy332; + } else { + if(yych == '.') goto yy326; + goto yy332; + } + } else { + if(yych <= 'z'){ + if(yych <= 'Z') goto yy326; + if(yych >= 'g') goto yy326; + goto yy332; + } else { + if(yych == '~') goto yy326; + goto yy332; + } + } +yy332: +{ + savech = s->tok[TOKLEN]; + s->tok[TOKLEN] = '\0'; + if (s->tok[1] == 'x' || s->tok[1] == 'X') + /* skip 0 and x */ + lvalp->intn = yasm_intnum_create_hex(TOK+2); + else + /* don't skip 0 */ + lvalp->intn = yasm_intnum_create_hex(TOK+1); + s->tok[TOKLEN] = savech; + RETURN(INTNUM); + } +yy333: yyaccept = 0; + YYMARKER = ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy334; +yy334: if(yybm[0+yych] & 8) { + goto yy333; + } + if(yych <= '^'){ + if(yych <= 'F'){ + if(yych <= '@') goto yy287; + goto yy335; + } else { + if(yych == 'H') goto yy338; + goto yy287; + } + } else { + if(yych <= 'f'){ + if(yych == '`') goto yy287; + goto yy335; + } else { + if(yych == 'h') goto yy338; + goto yy287; + } + } +yy335: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy336; +yy336: if(yych <= 'H'){ + if(yych <= '@'){ + if(yych <= '/') goto yy337; + if(yych <= '9') goto yy335; + goto yy337; + } else { + if(yych <= 'F') goto yy335; + if(yych >= 'H') goto yy338; + goto yy337; + } + } else { + if(yych <= '`'){ + if(yych == '_') goto yy335; + goto yy337; + } else { + if(yych <= 'f') goto yy335; + if(yych == 'h') goto yy338; + goto yy337; + } + } +yy337: YYCURSOR = YYMARKER; + switch(yyaccept){ + case 0: goto yy287; + case 1: goto yy349; + } +yy338: yych = *++YYCURSOR; + goto yy339; +yy339: +{ + s->tok[TOKLEN-1] = '\0'; /* strip off 'h' */ + lvalp->intn = yasm_intnum_create_hex(TOK); + RETURN(INTNUM); + } +yy340: yyaccept = 0; + YYMARKER = ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy341; +yy341: if(yybm[0+yych] & 16) { + goto yy340; + } + if(yych <= 'Q'){ + if(yych <= 'G'){ + if(yych <= '9'){ + if(yych <= '7') goto yy287; + goto yy333; + } else { + if(yych <= '@') goto yy287; + if(yych <= 'F') goto yy335; + goto yy287; + } + } else { + if(yych <= 'N'){ + if(yych <= 'H') goto yy338; + goto yy287; + } else { + if(yych == 'P') goto yy287; + goto yy344; + } + } + } else { + if(yych <= 'g'){ + if(yych <= '_'){ + if(yych <= '^') goto yy287; + goto yy342; + } else { + if(yych <= '`') goto yy287; + if(yych <= 'f') goto yy335; + goto yy287; + } + } else { + if(yych <= 'o'){ + if(yych <= 'h') goto yy338; + if(yych <= 'n') goto yy287; + goto yy344; + } else { + if(yych == 'q') goto yy344; + goto yy287; + } + } + } +yy342: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy343; +yy343: if(yybm[0+yych] & 32) { + goto yy342; + } + if(yych <= 'P'){ + if(yych <= 'F'){ + if(yych <= '7') goto yy337; + if(yych <= '9') goto yy335; + if(yych <= '@') goto yy337; + goto yy335; + } else { + if(yych <= 'H'){ + if(yych <= 'G') goto yy337; + goto yy338; + } else { + if(yych != 'O') goto yy337; + goto yy344; + } + } + } else { + if(yych <= 'h'){ + if(yych <= '`'){ + if(yych >= 'R') goto yy337; + goto yy344; + } else { + if(yych <= 'f') goto yy335; + if(yych <= 'g') goto yy337; + goto yy338; + } + } else { + if(yych <= 'o'){ + if(yych <= 'n') goto yy337; + goto yy344; + } else { + if(yych != 'q') goto yy337; + goto yy344; + } + } + } +yy344: yych = *++YYCURSOR; + goto yy345; +yy345: +{ + s->tok[TOKLEN-1] = '\0'; /* strip off 'q' or 'o' */ + lvalp->intn = yasm_intnum_create_oct(TOK); + RETURN(INTNUM); + } +yy346: yyaccept = 0; + YYMARKER = ++YYCURSOR; + if((YYLIMIT - YYCURSOR) < 2) YYFILL(2); + yych = *YYCURSOR; + goto yy347; +yy347: if(yybm[0+yych] & 64) { + goto yy346; + } + switch(yych){ + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': goto yy340; + case '8': + case '9': goto yy333; + case 'A': case 'C': + case 'D': + case 'E': + case 'F': case 'a': case 'c': + case 'd': + case 'e': + case 'f': goto yy335; + case 'B': case 'b': goto yy348; + case 'H': case 'h': goto yy338; + case 'O': case 'Q': case 'o': case 'q': goto yy344; + case '_': goto yy350; + default: goto yy287; + } +yy348: yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'H'){ + if(yych <= '@'){ + if(yych <= '/') goto yy349; + if(yych <= '9') goto yy335; + goto yy349; + } else { + if(yych <= 'F') goto yy335; + if(yych >= 'H') goto yy338; + goto yy349; + } + } else { + if(yych <= '`'){ + if(yych == '_') goto yy335; + goto yy349; + } else { + if(yych <= 'f') goto yy335; + if(yych == 'h') goto yy338; + goto yy349; + } + } +yy349: +{ + s->tok[TOKLEN-1] = '\0'; /* strip off 'b' */ + lvalp->intn = yasm_intnum_create_bin(TOK); + RETURN(INTNUM); + } +yy350: ++YYCURSOR; + if((YYLIMIT - YYCURSOR) < 2) YYFILL(2); + yych = *YYCURSOR; + goto yy351; +yy351: if(yybm[0+yych] & 128) { + goto yy350; + } + switch(yych){ + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': goto yy342; + case '8': + case '9': case 'A': case 'C': + case 'D': + case 'E': + case 'F': case 'a': case 'c': + case 'd': + case 'e': + case 'f': goto yy335; + case 'B': case 'b': goto yy348; + case 'H': case 'h': goto yy338; + case 'O': case 'Q': case 'o': case 'q': goto yy344; + default: goto yy337; + } +yy352: yych = *++YYCURSOR; + if(yych <= 'F'){ + if(yych <= '/') goto yy337; + if(yych <= '9') goto yy353; + if(yych <= '@') goto yy337; + goto yy353; + } else { + if(yych <= '_'){ + if(yych <= '^') goto yy337; + goto yy353; + } else { + if(yych <= '`') goto yy337; + if(yych >= 'g') goto yy337; + goto yy353; + } + } +yy353: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy354; +yy354: if(yych <= 'F'){ + if(yych <= '/') goto yy332; + if(yych <= '9') goto yy353; + if(yych <= '@') goto yy332; + goto yy353; + } else { + if(yych <= '_'){ + if(yych <= '^') goto yy332; + goto yy353; + } else { + if(yych <= '`') goto yy332; + if(yych <= 'f') goto yy353; + goto yy332; + } + } +} +} + + + /* string/character constant values */ +stringconst: + strbuf = yasm_xmalloc(STRBUF_ALLOC_SIZE); + strbuf_size = STRBUF_ALLOC_SIZE; + count = 0; + +stringconst_scan: + SCANINIT(); + if (*cursor == '\0') + goto stringconst_error; + + { + +{ + YYCTYPE yych; + goto yy355; + ++YYCURSOR; +yy355: + if((YYLIMIT - YYCURSOR) < 2) YYFILL(2); + yych = *YYCURSOR; + if(yych <= '"'){ + if(yych <= '\000') goto yy357; + if(yych <= '!') goto yy362; + goto yy361; + } else { + if(yych == '\'') goto yy359; + goto yy362; + } +yy357: yych = *++YYCURSOR; + goto yy358; +yy358: +{ goto stringconst_error; } +yy359: yych = *++YYCURSOR; + if(yych == '\'') goto yy363; + goto yy360; +yy360: +{ + if (s->tok[0] == endch) + goto stringconst_end; + + strbuf[count++] = s->tok[0]; + if (count >= strbuf_size) { + strbuf = yasm_xrealloc(strbuf, strbuf_size + STRBUF_ALLOC_SIZE); + strbuf_size += STRBUF_ALLOC_SIZE; + } + + goto stringconst_scan; + } +yy361: yych = *++YYCURSOR; + if(yych == '"') goto yy363; + goto yy360; +yy362: yych = *++YYCURSOR; + goto yy360; +yy363: yych = *++YYCURSOR; + goto yy364; +yy364: +{ + if (endch != s->tok[0]) { + strbuf[count++] = s->tok[0]; + if (count >= strbuf_size) { + strbuf = yasm_xrealloc(strbuf, + strbuf_size + STRBUF_ALLOC_SIZE); + strbuf_size += STRBUF_ALLOC_SIZE; + } + } else if (!parser_nasm->tasm) { + YYCURSOR--; + goto stringconst_end; + } + strbuf[count++] = s->tok[0]; + if (count >= strbuf_size) { + strbuf = yasm_xrealloc(strbuf, strbuf_size + STRBUF_ALLOC_SIZE); + strbuf_size += STRBUF_ALLOC_SIZE; + } + goto stringconst_scan; + } +} +} + + +stringconst_error: + yasm_error_set(YASM_ERROR_SYNTAX, N_("unterminated string")); + +stringconst_end: + strbuf[count] = '\0'; + lvalp->str.contents = (char *)strbuf; + lvalp->str.len = count; + RETURN(STRING); + +endofinput: + parser_nasm->state = INITIAL; + RETURN(s->tok[0]); +} + diff --git a/contrib/tools/yasm/modules/nasm-version.c b/contrib/tools/yasm/modules/nasm-version.c new file mode 100644 index 0000000000..0d806749a5 --- /dev/null +++ b/contrib/tools/yasm/modules/nasm-version.c @@ -0,0 +1,15 @@ +/* This file auto-generated from standard.mac by genmacro.c - don't edit it */ + +#include <stddef.h> + +static const char *nasm_version_mac[] = { + "%define __YASM_MAJOR__ 1", + "%define __YASM_MINOR__ 3", + "%define __YASM_SUBMINOR__ 0", + "%define __YASM_BUILD__ 0", + "%define __YASM_PATCHLEVEL__ 0", + "%define __YASM_VERSION_ID__ 001030000h", + "%define __YASM_VER__ \"1.3.0\"", + NULL +}; + diff --git a/contrib/tools/yasm/modules/objfmts/bin/bin-objfmt.c b/contrib/tools/yasm/modules/objfmts/bin/bin-objfmt.c new file mode 100644 index 0000000000..5f422245d3 --- /dev/null +++ b/contrib/tools/yasm/modules/objfmts/bin/bin-objfmt.c @@ -0,0 +1,1972 @@ +/* + * Flat-format binary object format + * + * 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> + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#include <libyasm.h> + + +#define REGULAR_OUTBUF_SIZE 1024 + +typedef struct bin_section_data { + int bss; /* aka nobits */ + + /* User-provided alignment */ + yasm_intnum *align, *valign; + + /* User-provided starts */ + /*@null@*/ /*@owned@*/ yasm_expr *start, *vstart; + + /* User-provided follows */ + /*@null@*/ /*@owned@*/ char *follows, *vfollows; + + /* Calculated (final) starts, used only during output() */ + /*@null@*/ /*@owned@*/ yasm_intnum *istart, *ivstart; + + /* Calculated (final) length, used only during output() */ + /*@null@*/ /*@owned@*/ yasm_intnum *length; +} bin_section_data; + +typedef struct yasm_objfmt_bin { + yasm_objfmt_base objfmt; /* base structure */ + + enum { + NO_MAP = 0, + MAP_NONE = 0x01, + MAP_BRIEF = 0x02, + MAP_SECTIONS = 0x04, + MAP_SYMBOLS = 0x08 + } map_flags; + /*@null@*/ /*@only@*/ char *map_filename; + + /*@null@*/ /*@only@*/ yasm_expr *org; +} yasm_objfmt_bin; + +/* symrec data is used only for the special symbols section<sectname>.start, + * section<sectname>.vstart, and section<sectname>.length + */ +typedef struct bin_symrec_data { + yasm_section *section; /* referenced section */ + enum bin_ssym { + SSYM_START, + SSYM_VSTART, + SSYM_LENGTH + } which; +} bin_symrec_data; + +static void bin_section_data_destroy(/*@only@*/ void *d); +static void bin_section_data_print(void *data, FILE *f, int indent_level); + +static const yasm_assoc_data_callback bin_section_data_cb = { + bin_section_data_destroy, + bin_section_data_print +}; + +static void bin_symrec_data_destroy(/*@only@*/ void *d); +static void bin_symrec_data_print(void *data, FILE *f, int indent_level); + +static const yasm_assoc_data_callback bin_symrec_data_cb = { + bin_symrec_data_destroy, + bin_symrec_data_print +}; + +yasm_objfmt_module yasm_bin_LTX_objfmt; + + +static yasm_objfmt * +bin_objfmt_create(yasm_object *object) +{ + yasm_objfmt_bin *objfmt_bin = yasm_xmalloc(sizeof(yasm_objfmt_bin)); + objfmt_bin->objfmt.module = &yasm_bin_LTX_objfmt; + + objfmt_bin->map_flags = NO_MAP; + objfmt_bin->map_filename = NULL; + objfmt_bin->org = NULL; + + return (yasm_objfmt *)objfmt_bin; +} + +typedef TAILQ_HEAD(bin_group_head, bin_group) bin_groups; + +typedef struct bin_group { + TAILQ_ENTRY(bin_group) link; + yasm_section *section; + bin_section_data *bsd; + + /* Groups that (in parallel) logically come immediately after this + * group's section. + */ + bin_groups follow_groups; +} bin_group; + +/* Recursive function to find group containing named section. */ +static bin_group * +find_group_by_name(bin_groups *groups, const char *name) +{ + bin_group *group, *found; + TAILQ_FOREACH(group, groups, link) { + if (strcmp(yasm_section_get_name(group->section), name) == 0) + return group; + /* Recurse to loop through follow groups */ + found = find_group_by_name(&group->follow_groups, name); + if (found) + return found; + } + return NULL; +} + +/* Recursive function to find group. Returns NULL if not found. */ +static bin_group * +find_group_by_section(bin_groups *groups, yasm_section *section) +{ + bin_group *group, *found; + TAILQ_FOREACH(group, groups, link) { + if (group->section == section) + return group; + /* Recurse to loop through follow groups */ + found = find_group_by_section(&group->follow_groups, section); + if (found) + return found; + } + return NULL; +} + +#if 0 +/* Debugging function */ +static void +print_groups(const bin_groups *groups, int indent_level) +{ + bin_group *group; + TAILQ_FOREACH(group, groups, link) { + printf("%*sSection `%s':\n", indent_level, "", + yasm_section_get_name(group->section)); + bin_section_data_print(group->bsd, stdout, indent_level+1); + if (!TAILQ_EMPTY(&group->follow_groups)) { + printf("%*sFollowing groups:\n", indent_level, ""); + print_groups(&group->follow_groups, indent_level+1); + } + } +} +#endif + +static void +bin_group_destroy(/*@only@*/ bin_group *group) +{ + bin_group *follow, *group_temp; + TAILQ_FOREACH_SAFE(follow, &group->follow_groups, link, group_temp) + bin_group_destroy(follow); + yasm_xfree(group); +} + +typedef struct bin_objfmt_output_info { + yasm_object *object; + yasm_errwarns *errwarns; + /*@dependent@*/ FILE *f; + /*@only@*/ unsigned char *buf; + /*@observer@*/ const yasm_section *sect; + unsigned long start; /* what normal variables go against */ + + yasm_intnum *origin; + yasm_intnum *tmp_intn; /* temporary working intnum */ + + bin_groups lma_groups, vma_groups; +} bin_objfmt_output_info; + +static int +bin_objfmt_check_sym(yasm_symrec *sym, /*@null@*/ void *d) +{ + /*@null@*/ bin_objfmt_output_info *info = (bin_objfmt_output_info *)d; + yasm_sym_vis vis = yasm_symrec_get_visibility(sym); + assert(info != NULL); + + /* Don't check internally-generated symbols. Only internally generated + * symbols have symrec data, so simply check for its presence. + */ + if (yasm_symrec_get_data(sym, &bin_symrec_data_cb)) + return 0; + + if (vis & YASM_SYM_EXTERN) { + yasm_warn_set(YASM_WARN_GENERAL, + N_("binary object format does not support extern variables")); + yasm_errwarn_propagate(info->errwarns, yasm_symrec_get_decl_line(sym)); + } else if (vis & YASM_SYM_GLOBAL) { + yasm_warn_set(YASM_WARN_GENERAL, + N_("binary object format does not support global variables")); + yasm_errwarn_propagate(info->errwarns, yasm_symrec_get_decl_line(sym)); + } else if (vis & YASM_SYM_COMMON) { + yasm_error_set(YASM_ERROR_TYPE, + N_("binary object format does not support common variables")); + yasm_errwarn_propagate(info->errwarns, yasm_symrec_get_decl_line(sym)); + } + return 0; +} + +static int +bin_lma_create_group(yasm_section *sect, /*@null@*/ void *d) +{ + bin_objfmt_output_info *info = (bin_objfmt_output_info *)d; + bin_section_data *bsd = yasm_section_get_data(sect, &bin_section_data_cb); + unsigned long align = yasm_section_get_align(sect); + bin_group *group; + + assert(info != NULL); + assert(bsd != NULL); + + group = yasm_xmalloc(sizeof(bin_group)); + group->section = sect; + group->bsd = bsd; + TAILQ_INIT(&group->follow_groups); + + /* Determine section alignment as necessary. */ + if (!bsd->align) + bsd->align = yasm_intnum_create_uint(align > 4 ? align : 4); + else { + yasm_intnum *align_intn = yasm_intnum_create_uint(align); + if (yasm_intnum_compare(align_intn, bsd->align) > 0) { + yasm_warn_set(YASM_WARN_GENERAL, + N_("section `%s' internal align of %lu is greater than `%s' of %lu; using `%s'"), + yasm_section_get_name(sect), + yasm_intnum_get_uint(align_intn), + N_("align"), + yasm_intnum_get_uint(bsd->align), + N_("align")); + yasm_errwarn_propagate(info->errwarns, 0); + } + yasm_intnum_destroy(align_intn); + } + + /* Calculate section integer start. */ + if (bsd->start) { + bsd->istart = yasm_expr_get_intnum(&bsd->start, 0); + if (!bsd->istart) { + yasm_error_set(YASM_ERROR_TOO_COMPLEX, + N_("start expression is too complex")); + yasm_errwarn_propagate(info->errwarns, bsd->start->line); + return 1; + } else + bsd->istart = yasm_intnum_copy(bsd->istart); + } else + bsd->istart = NULL; + + /* Calculate section integer vstart. */ + if (bsd->vstart) { + bsd->ivstart = yasm_expr_get_intnum(&bsd->vstart, 0); + if (!bsd->ivstart) { + yasm_error_set(YASM_ERROR_TOO_COMPLEX, + N_("vstart expression is too complex")); + yasm_errwarn_propagate(info->errwarns, bsd->vstart->line); + return 1; + } else + bsd->ivstart = yasm_intnum_copy(bsd->ivstart); + } else + bsd->ivstart = NULL; + + /* Calculate section integer length. */ + bsd->length = yasm_calc_bc_dist(yasm_section_bcs_first(sect), + yasm_section_bcs_last(sect)); + + TAILQ_INSERT_TAIL(&info->lma_groups, group, link); + return 0; +} + +static int +bin_vma_create_group(yasm_section *sect, /*@null@*/ void *d) +{ + bin_objfmt_output_info *info = (bin_objfmt_output_info *)d; + bin_section_data *bsd = yasm_section_get_data(sect, &bin_section_data_cb); + bin_group *group; + + assert(info != NULL); + assert(bsd != NULL); + + group = yasm_xmalloc(sizeof(bin_group)); + group->section = sect; + group->bsd = bsd; + TAILQ_INIT(&group->follow_groups); + + TAILQ_INSERT_TAIL(&info->vma_groups, group, link); + return 0; +} + +/* Calculates new start address based on alignment constraint. + * Start is modified (rounded up) to the closest aligned value greater than + * what was passed in. + * Align must be a power of 2. + */ +static void +bin_objfmt_align(yasm_intnum *start, const yasm_intnum *align) +{ + /* Because alignment is always a power of two, we can use some bit + * trickery to do this easily. + */ + yasm_intnum *align_intn = + yasm_intnum_create_uint(yasm_intnum_get_uint(align)-1); + yasm_intnum_calc(align_intn, YASM_EXPR_AND, start); + if (!yasm_intnum_is_zero(align_intn)) { + /* start = (start & ~(align-1)) + align; */ + yasm_intnum_set_uint(align_intn, yasm_intnum_get_uint(align)-1); + yasm_intnum_calc(align_intn, YASM_EXPR_NOT, NULL); + yasm_intnum_calc(align_intn, YASM_EXPR_AND, start); + yasm_intnum_set(start, align); + yasm_intnum_calc(start, YASM_EXPR_ADD, align_intn); + } + yasm_intnum_destroy(align_intn); +} + +/* Recursive function to assign start addresses. + * Updates start, last, and vdelta parameters as it goes along. + * The tmp parameter is just a working intnum so one doesn't have to be + * locally allocated for this purpose. + */ +static void +group_assign_start_recurse(bin_group *group, yasm_intnum *start, + yasm_intnum *last, yasm_intnum *vdelta, + yasm_intnum *tmp, yasm_errwarns *errwarns) +{ + bin_group *follow_group; + + /* Determine LMA */ + if (group->bsd->istart) { + yasm_intnum_set(group->bsd->istart, start); + if (group->bsd->align) { + bin_objfmt_align(group->bsd->istart, group->bsd->align); + if (yasm_intnum_compare(start, group->bsd->istart) != 0) { + yasm_warn_set(YASM_WARN_GENERAL, + N_("start inconsistent with align; using aligned value")); + yasm_errwarn_propagate(errwarns, group->bsd->start->line); + } + } + } else { + group->bsd->istart = yasm_intnum_copy(start); + if (group->bsd->align != 0) + bin_objfmt_align(group->bsd->istart, group->bsd->align); + } + + /* Determine VMA if either just valign specified or if no v* specified */ + if (!group->bsd->vstart) { + if (!group->bsd->vfollows && !group->bsd->valign) { + /* No v* specified, set VMA=LMA+vdelta. */ + group->bsd->ivstart = yasm_intnum_copy(group->bsd->istart); + yasm_intnum_calc(group->bsd->ivstart, YASM_EXPR_ADD, vdelta); + } else if (!group->bsd->vfollows) { + /* Just valign specified: set VMA=LMA+vdelta, align VMA, then add + * delta between unaligned and aligned to vdelta parameter. + */ + group->bsd->ivstart = yasm_intnum_copy(group->bsd->istart); + yasm_intnum_calc(group->bsd->ivstart, YASM_EXPR_ADD, vdelta); + yasm_intnum_set(tmp, group->bsd->ivstart); + bin_objfmt_align(group->bsd->ivstart, group->bsd->valign); + yasm_intnum_calc(vdelta, YASM_EXPR_ADD, group->bsd->ivstart); + yasm_intnum_calc(vdelta, YASM_EXPR_SUB, tmp); + } + } + + /* Find the maximum end value */ + yasm_intnum_set(tmp, group->bsd->istart); + yasm_intnum_calc(tmp, YASM_EXPR_ADD, group->bsd->length); + if (yasm_intnum_compare(tmp, last) > 0) /* tmp > last */ + yasm_intnum_set(last, tmp); + + /* Recurse for each following group. */ + TAILQ_FOREACH(follow_group, &group->follow_groups, link) { + /* Following sections have to follow this one, + * so add length to start. + */ + yasm_intnum_set(start, group->bsd->istart); + yasm_intnum_calc(start, YASM_EXPR_ADD, group->bsd->length); + + group_assign_start_recurse(follow_group, start, last, vdelta, tmp, + errwarns); + } +} + +/* Recursive function to assign start addresses. + * Updates start parameter as it goes along. + * The tmp parameter is just a working intnum so one doesn't have to be + * locally allocated for this purpose. + */ +static void +group_assign_vstart_recurse(bin_group *group, yasm_intnum *start, + yasm_errwarns *errwarns) +{ + bin_group *follow_group; + + /* Determine VMA section alignment as necessary. + * Default to LMA alignment if not specified. + */ + if (!group->bsd->valign) + group->bsd->valign = yasm_intnum_copy(group->bsd->align); + else { + unsigned long align = yasm_section_get_align(group->section); + yasm_intnum *align_intn = yasm_intnum_create_uint(align); + if (yasm_intnum_compare(align_intn, group->bsd->valign) > 0) { + yasm_warn_set(YASM_WARN_GENERAL, + N_("section `%s' internal align of %lu is greater than `%s' of %lu; using `%s'"), + yasm_section_get_name(group->section), + yasm_intnum_get_uint(align_intn), + N_("valign"), + yasm_intnum_get_uint(group->bsd->valign), + N_("valign")); + yasm_errwarn_propagate(errwarns, 0); + } + yasm_intnum_destroy(align_intn); + } + + /* Determine VMA */ + if (group->bsd->ivstart) { + yasm_intnum_set(group->bsd->ivstart, start); + if (group->bsd->valign) { + bin_objfmt_align(group->bsd->ivstart, group->bsd->valign); + if (yasm_intnum_compare(start, group->bsd->ivstart) != 0) { + yasm_error_set(YASM_ERROR_VALUE, + N_("vstart inconsistent with valign")); + yasm_errwarn_propagate(errwarns, group->bsd->vstart->line); + } + } + } else { + group->bsd->ivstart = yasm_intnum_copy(start); + if (group->bsd->valign) + bin_objfmt_align(group->bsd->ivstart, group->bsd->valign); + } + + /* Recurse for each following group. */ + TAILQ_FOREACH(follow_group, &group->follow_groups, link) { + /* Following sections have to follow this one, + * so add length to start. + */ + yasm_intnum_set(start, group->bsd->ivstart); + yasm_intnum_calc(start, YASM_EXPR_ADD, group->bsd->length); + + group_assign_vstart_recurse(follow_group, start, errwarns); + } +} + +static /*@null@*/ const yasm_intnum * +get_ssym_value(yasm_symrec *sym) +{ + bin_symrec_data *bsymd = yasm_symrec_get_data(sym, &bin_symrec_data_cb); + bin_section_data *bsd; + + if (!bsymd) + return NULL; + + bsd = yasm_section_get_data(bsymd->section, &bin_section_data_cb); + assert(bsd != NULL); + + switch (bsymd->which) { + case SSYM_START: return bsd->istart; + case SSYM_VSTART: return bsd->ivstart; + case SSYM_LENGTH: return bsd->length; + } + return NULL; +} + +static /*@only@*/ yasm_expr * +bin_objfmt_expr_xform(/*@returned@*/ /*@only@*/ yasm_expr *e, + /*@unused@*/ /*@null@*/ void *d) +{ + int i; + for (i=0; i<e->numterms; i++) { + /*@dependent@*/ yasm_section *sect; + /*@dependent@*/ /*@null@*/ yasm_bytecode *precbc; + /*@null@*/ yasm_intnum *dist; + /*@null@*/ const yasm_intnum *ssymval; + + /* Transform symrecs or precbcs that reference sections into + * vstart + intnum(dist). + */ + if (((e->terms[i].type == YASM_EXPR_SYM && + yasm_symrec_get_label(e->terms[i].data.sym, &precbc)) || + (e->terms[i].type == YASM_EXPR_PRECBC && + (precbc = e->terms[i].data.precbc))) && + (sect = yasm_bc_get_section(precbc)) && + (dist = yasm_calc_bc_dist(yasm_section_bcs_first(sect), precbc))) { + bin_section_data *bsd; + bsd = yasm_section_get_data(sect, &bin_section_data_cb); + assert(bsd != NULL); + yasm_intnum_calc(dist, YASM_EXPR_ADD, bsd->ivstart); + e->terms[i].type = YASM_EXPR_INT; + e->terms[i].data.intn = dist; + } + + /* Transform our special symrecs into the appropriate value */ + if (e->terms[i].type == YASM_EXPR_SYM && + (ssymval = get_ssym_value(e->terms[i].data.sym))) { + e->terms[i].type = YASM_EXPR_INT; + e->terms[i].data.intn = yasm_intnum_copy(ssymval); + } + } + + return e; +} + +typedef struct map_output_info { + /* address width */ + int bytes; + + /* intnum output static data areas */ + unsigned char *buf; + yasm_intnum *intn; + + /* symrec output information */ + unsigned long count; + yasm_section *section; /* NULL for EQUs */ + + yasm_object *object; /* object */ + FILE *f; /* map output file */ +} map_output_info; + +static int +map_prescan_bytes(yasm_section *sect, void *d) +{ + bin_section_data *bsd = yasm_section_get_data(sect, &bin_section_data_cb); + map_output_info *info = (map_output_info *)d; + + assert(bsd != NULL); + assert(info != NULL); + + while (!yasm_intnum_check_size(bsd->length, info->bytes * 8, 0, 0)) + info->bytes *= 2; + while (!yasm_intnum_check_size(bsd->istart, info->bytes * 8, 0, 0)) + info->bytes *= 2; + while (!yasm_intnum_check_size(bsd->ivstart, info->bytes * 8, 0, 0)) + info->bytes *= 2; + + return 0; +} + +static void +map_print_intnum(const yasm_intnum *intn, map_output_info *info) +{ + size_t i; + yasm_intnum_get_sized(intn, info->buf, info->bytes, info->bytes*8, 0, 0, + 0); + for (i=info->bytes; i != 0; i--) + fprintf(info->f, "%02X", info->buf[i-1]); +} + +static void +map_sections_summary(bin_groups *groups, map_output_info *info) +{ + bin_group *group; + TAILQ_FOREACH(group, groups, link) { + bin_section_data *bsd = group->bsd; + + assert(bsd != NULL); + assert(info != NULL); + + map_print_intnum(bsd->ivstart, info); + fprintf(info->f, " "); + + yasm_intnum_set(info->intn, bsd->ivstart); + yasm_intnum_calc(info->intn, YASM_EXPR_ADD, bsd->length); + map_print_intnum(info->intn, info); + fprintf(info->f, " "); + + map_print_intnum(bsd->istart, info); + fprintf(info->f, " "); + + yasm_intnum_set(info->intn, bsd->istart); + yasm_intnum_calc(info->intn, YASM_EXPR_ADD, bsd->length); + map_print_intnum(info->intn, info); + fprintf(info->f, " "); + + map_print_intnum(bsd->length, info); + fprintf(info->f, " "); + + fprintf(info->f, "%-*s", 10, bsd->bss ? "nobits" : "progbits"); + fprintf(info->f, "%s\n", yasm_section_get_name(group->section)); + + /* Recurse to loop through follow groups */ + map_sections_summary(&group->follow_groups, info); + } +} + +static void +map_sections_detail(bin_groups *groups, map_output_info *info) +{ + bin_group *group; + TAILQ_FOREACH(group, groups, link) { + bin_section_data *bsd = group->bsd; + size_t i; + const char *s; + + s = yasm_section_get_name(group->section); + fprintf(info->f, "---- Section %s ", s); + for (i=0; i<(65-strlen(s)); i++) + fputc('-', info->f); + + fprintf(info->f, "\n\nclass: %s", + bsd->bss ? "nobits" : "progbits"); + fprintf(info->f, "\nlength: "); + map_print_intnum(bsd->length, info); + fprintf(info->f, "\nstart: "); + map_print_intnum(bsd->istart, info); + fprintf(info->f, "\nalign: "); + map_print_intnum(bsd->align, info); + fprintf(info->f, "\nfollows: %s", + bsd->follows ? bsd->follows : "not defined"); + fprintf(info->f, "\nvstart: "); + map_print_intnum(bsd->ivstart, info); + fprintf(info->f, "\nvalign: "); + map_print_intnum(bsd->valign, info); + fprintf(info->f, "\nvfollows: %s\n\n", + bsd->vfollows ? bsd->vfollows : "not defined"); + + /* Recurse to loop through follow groups */ + map_sections_detail(&group->follow_groups, info); + } +} + +static int +map_symrec_count(yasm_symrec *sym, void *d) +{ + map_output_info *info = (map_output_info *)d; + /*@dependent@*/ yasm_bytecode *precbc; + + assert(info != NULL); + + /* TODO: autodetect wider size */ + if (!info->section && yasm_symrec_get_equ(sym)) { + info->count++; + } else if (yasm_symrec_get_label(sym, &precbc) && + yasm_bc_get_section(precbc) == info->section) { + info->count++; + } + return 0; +} + +static int +map_symrec_output(yasm_symrec *sym, void *d) +{ + map_output_info *info = (map_output_info *)d; + const yasm_expr *equ; + /*@dependent@*/ yasm_bytecode *precbc; + /*@only@*/ char *name = yasm_symrec_get_global_name(sym, info->object); + + assert(info != NULL); + + if (!info->section && (equ = yasm_symrec_get_equ(sym))) { + yasm_expr *realequ = yasm_expr_copy(equ); + realequ = yasm_expr__level_tree + (realequ, 1, 1, 1, 0, bin_objfmt_expr_xform, NULL); + yasm_intnum_set(info->intn, yasm_expr_get_intnum(&realequ, 0)); + yasm_expr_destroy(realequ); + map_print_intnum(info->intn, info); + fprintf(info->f, " %s\n", name); + } else if (yasm_symrec_get_label(sym, &precbc) && + yasm_bc_get_section(precbc) == info->section) { + bin_section_data *bsd = + yasm_section_get_data(info->section, &bin_section_data_cb); + + /* Real address */ + yasm_intnum_set_uint(info->intn, yasm_bc_next_offset(precbc)); + yasm_intnum_calc(info->intn, YASM_EXPR_ADD, bsd->istart); + map_print_intnum(info->intn, info); + fprintf(info->f, " "); + + /* Virtual address */ + yasm_intnum_set_uint(info->intn, yasm_bc_next_offset(precbc)); + yasm_intnum_calc(info->intn, YASM_EXPR_ADD, bsd->ivstart); + map_print_intnum(info->intn, info); + + /* Name */ + fprintf(info->f, " %s\n", name); + } + yasm_xfree(name); + return 0; +} + +static void +map_sections_symbols(bin_groups *groups, map_output_info *info) +{ + bin_group *group; + TAILQ_FOREACH(group, groups, link) { + info->count = 0; + info->section = group->section; + yasm_symtab_traverse(info->object->symtab, info, map_symrec_count); + + if (info->count > 0) { + const char *s = yasm_section_get_name(group->section); + size_t i; + fprintf(info->f, "---- Section %s ", s); + for (i=0; i<(65-strlen(s)); i++) + fputc('-', info->f); + fprintf(info->f, "\n\n%-*s%-*s%s\n", + info->bytes*2+2, "Real", + info->bytes*2+2, "Virtual", + "Name"); + yasm_symtab_traverse(info->object->symtab, info, + map_symrec_output); + fprintf(info->f, "\n\n"); + } + + /* Recurse to loop through follow groups */ + map_sections_symbols(&group->follow_groups, info); + } +} + +static void +output_map(bin_objfmt_output_info *info) +{ + yasm_objfmt_bin *objfmt_bin = (yasm_objfmt_bin *)info->object->objfmt; + FILE *f; + int i; + map_output_info mapinfo; + + if (objfmt_bin->map_flags == NO_MAP) + return; + + if (objfmt_bin->map_flags == MAP_NONE) + objfmt_bin->map_flags = MAP_BRIEF; /* default to brief */ + + if (!objfmt_bin->map_filename) + f = stdout; /* default to stdout */ + else { + f = fopen(objfmt_bin->map_filename, "wt"); + if (!f) { + yasm_warn_set(YASM_WARN_GENERAL, + N_("unable to open map file `%s'"), + objfmt_bin->map_filename); + yasm_errwarn_propagate(info->errwarns, 0); + return; + } + } + + mapinfo.object = info->object; + mapinfo.f = f; + + /* Temporary intnum */ + mapinfo.intn = info->tmp_intn; + + /* Prescan all values to figure out what width we should make the output + * fields. Start with a minimum of 4. + */ + mapinfo.bytes = 4; + while (!yasm_intnum_check_size(info->origin, mapinfo.bytes * 8, 0, 0)) + mapinfo.bytes *= 2; + yasm_object_sections_traverse(info->object, &mapinfo, map_prescan_bytes); + mapinfo.buf = yasm_xmalloc(mapinfo.bytes); + + fprintf(f, "\n- YASM Map file "); + for (i=0; i<63; i++) + fputc('-', f); + fprintf(f, "\n\nSource file: %s\n", info->object->src_filename); + fprintf(f, "Output file: %s\n\n", info->object->obj_filename); + + fprintf(f, "-- Program origin "); + for (i=0; i<61; i++) + fputc('-', f); + fprintf(f, "\n\n"); + map_print_intnum(info->origin, &mapinfo); + fprintf(f, "\n\n"); + + if (objfmt_bin->map_flags & MAP_BRIEF) { + fprintf(f, "-- Sections (summary) "); + for (i=0; i<57; i++) + fputc('-', f); + fprintf(f, "\n\n%-*s%-*s%-*s%-*s%-*s%-*s%s\n", + mapinfo.bytes*2+2, "Vstart", + mapinfo.bytes*2+2, "Vstop", + mapinfo.bytes*2+2, "Start", + mapinfo.bytes*2+2, "Stop", + mapinfo.bytes*2+2, "Length", + 10, "Class", "Name"); + + map_sections_summary(&info->lma_groups, &mapinfo); + fprintf(f, "\n"); + } + + if (objfmt_bin->map_flags & MAP_SECTIONS) { + fprintf(f, "-- Sections (detailed) "); + for (i=0; i<56; i++) + fputc('-', f); + fprintf(f, "\n\n"); + map_sections_detail(&info->lma_groups, &mapinfo); + } + + if (objfmt_bin->map_flags & MAP_SYMBOLS) { + fprintf(f, "-- Symbols "); + for (i=0; i<68; i++) + fputc('-', f); + fprintf(f, "\n\n"); + + /* We do two passes for EQU and each section; the first pass + * determines the byte width to use for the value and whether any + * symbols are present, the second pass actually outputs the text. + */ + + /* EQUs */ + mapinfo.count = 0; + mapinfo.section = NULL; + yasm_symtab_traverse(info->object->symtab, &mapinfo, map_symrec_count); + + if (mapinfo.count > 0) { + fprintf(f, "---- No Section "); + for (i=0; i<63; i++) + fputc('-', f); + fprintf(f, "\n\n%-*s%s\n", mapinfo.bytes*2+2, "Value", "Name"); + yasm_symtab_traverse(info->object->symtab, &mapinfo, + map_symrec_output); + fprintf(f, "\n\n"); + } + + /* Other sections */ + map_sections_symbols(&info->lma_groups, &mapinfo); + } + + if (f != stdout) + fclose(f); + + yasm_xfree(mapinfo.buf); +} + +/* Check for LMA overlap using a simple N^2 algorithm. */ +static int +check_lma_overlap(yasm_section *sect, /*@null@*/ void *d) +{ + bin_section_data *bsd, *bsd2; + yasm_section *other = (yasm_section *)d; + yasm_intnum *overlap; + + if (!d) + return yasm_object_sections_traverse(yasm_section_get_object(sect), + sect, check_lma_overlap); + if (sect == other) + return 0; + + bsd = yasm_section_get_data(sect, &bin_section_data_cb); + bsd2 = yasm_section_get_data(other, &bin_section_data_cb); + + if (yasm_intnum_is_zero(bsd->length) || + yasm_intnum_is_zero(bsd2->length)) + return 0; + + if (yasm_intnum_compare(bsd->istart, bsd2->istart) <= 0) { + overlap = yasm_intnum_copy(bsd->istart); + yasm_intnum_calc(overlap, YASM_EXPR_ADD, bsd->length); + yasm_intnum_calc(overlap, YASM_EXPR_SUB, bsd2->istart); + } else { + overlap = yasm_intnum_copy(bsd2->istart); + yasm_intnum_calc(overlap, YASM_EXPR_ADD, bsd2->length); + yasm_intnum_calc(overlap, YASM_EXPR_SUB, bsd->istart); + } + + if (yasm_intnum_sign(overlap) > 0) { + yasm_error_set(YASM_ERROR_GENERAL, + N_("sections `%s' and `%s' overlap by %lu bytes"), + yasm_section_get_name(sect), + yasm_section_get_name(other), + yasm_intnum_get_uint(overlap)); + yasm_intnum_destroy(overlap); + return -1; + } + + yasm_intnum_destroy(overlap); + return 0; +} + +static int +bin_objfmt_output_value(yasm_value *value, unsigned char *buf, + unsigned int destsize, + /*@unused@*/ unsigned long offset, yasm_bytecode *bc, + int warn, /*@null@*/ void *d) +{ + /*@null@*/ bin_objfmt_output_info *info = (bin_objfmt_output_info *)d; + /*@dependent@*/ /*@null@*/ yasm_bytecode *precbc; + /*@dependent@*/ yasm_section *sect; + + assert(info != NULL); + + /* Binary objects we need to resolve against object, not against section. */ + if (value->rel) { + unsigned int rshift = (unsigned int)value->rshift; + yasm_expr *syme; + /*@null@*/ const yasm_intnum *ssymval; + + if (yasm_symrec_is_abs(value->rel)) { + syme = yasm_expr_create_ident(yasm_expr_int( + yasm_intnum_create_uint(0)), bc->line); + } else if (yasm_symrec_get_label(value->rel, &precbc) + && (sect = yasm_bc_get_section(precbc))) { + syme = yasm_expr_create_ident(yasm_expr_sym(value->rel), bc->line); + } else if ((ssymval = get_ssym_value(value->rel))) { + syme = yasm_expr_create_ident(yasm_expr_int( + yasm_intnum_copy(ssymval)), bc->line); + } else + goto done; + + /* Handle PC-relative */ + if (value->curpos_rel) { + yasm_expr *sube; + sube = yasm_expr_create(YASM_EXPR_SUB, yasm_expr_precbc(bc), + yasm_expr_int(yasm_intnum_create_uint(bc->len*bc->mult_int)), + bc->line); + syme = yasm_expr_create(YASM_EXPR_SUB, yasm_expr_expr(syme), + yasm_expr_expr(sube), bc->line); + value->curpos_rel = 0; + value->ip_rel = 0; + } + + if (value->rshift > 0) + syme = yasm_expr_create(YASM_EXPR_SHR, yasm_expr_expr(syme), + yasm_expr_int(yasm_intnum_create_uint(rshift)), bc->line); + + /* Add into absolute portion */ + if (!value->abs) + value->abs = syme; + else + value->abs = + yasm_expr_create(YASM_EXPR_ADD, yasm_expr_expr(value->abs), + yasm_expr_expr(syme), bc->line); + value->rel = NULL; + value->rshift = 0; + } +done: + /* Simplify absolute portion of value, transforming symrecs */ + if (value->abs) + value->abs = yasm_expr__level_tree + (value->abs, 1, 1, 1, 0, bin_objfmt_expr_xform, NULL); + + /* Output */ + switch (yasm_value_output_basic(value, buf, destsize, bc, warn, + info->object->arch)) { + case -1: + return 1; + case 0: + break; + default: + return 0; + } + + /* Couldn't output, assume it contains an external reference. */ + yasm_error_set(YASM_ERROR_GENERAL, + N_("binary object format does not support external references")); + return 1; +} + +static int +bin_objfmt_output_bytecode(yasm_bytecode *bc, /*@null@*/ void *d) +{ + /*@null@*/ bin_objfmt_output_info *info = (bin_objfmt_output_info *)d; + /*@null@*/ /*@only@*/ unsigned char *bigbuf; + unsigned long size = REGULAR_OUTBUF_SIZE; + int gap; + + assert(info != NULL); + + bigbuf = yasm_bc_tobytes(bc, info->buf, &size, &gap, info, + bin_objfmt_output_value, NULL); + + /* Don't bother doing anything else if size ended up being 0. */ + if (size == 0) { + if (bigbuf) + yasm_xfree(bigbuf); + return 0; + } + + /* Warn that gaps are converted to 0 and write out the 0's. */ + if (gap) { + unsigned long left; + yasm_warn_set(YASM_WARN_UNINIT_CONTENTS, + N_("uninitialized space declared in code/data section: zeroing")); + /* Write out in chunks */ + memset(info->buf, 0, REGULAR_OUTBUF_SIZE); + left = size; + while (left > REGULAR_OUTBUF_SIZE) { + fwrite(info->buf, REGULAR_OUTBUF_SIZE, 1, info->f); + left -= REGULAR_OUTBUF_SIZE; + } + fwrite(info->buf, left, 1, info->f); + } else { + /* Output buf (or bigbuf if non-NULL) to file */ + fwrite(bigbuf ? bigbuf : info->buf, (size_t)size, 1, info->f); + } + + /* If bigbuf was allocated, free it */ + if (bigbuf) + yasm_xfree(bigbuf); + + return 0; +} + +/* Check to ensure bytecode is res* (for BSS sections) */ +static int +bin_objfmt_no_output_bytecode(yasm_bytecode *bc, /*@null@*/ void *d) +{ + /*@null@*/ bin_objfmt_output_info *info = (bin_objfmt_output_info *)d; + /*@null@*/ /*@only@*/ unsigned char *bigbuf; + unsigned long size = REGULAR_OUTBUF_SIZE; + int gap; + + assert(info != NULL); + + bigbuf = yasm_bc_tobytes(bc, info->buf, &size, &gap, info, + bin_objfmt_output_value, NULL); + + /* If bigbuf was allocated, free it */ + if (bigbuf) + yasm_xfree(bigbuf); + + /* Don't bother doing anything else if size ended up being 0. */ + if (size == 0) + return 0; + + /* Warn if not a gap. */ + if (!gap) { + yasm_warn_set(YASM_WARN_GENERAL, + N_("initialized space declared in nobits section: ignoring")); + } + + return 0; +} + +static int +bin_objfmt_output_section(yasm_section *sect, /*@null@*/ void *d) +{ + bin_section_data *bsd = yasm_section_get_data(sect, &bin_section_data_cb); + /*@null@*/ bin_objfmt_output_info *info = (bin_objfmt_output_info *)d; + + assert(bsd != NULL); + assert(info != NULL); + + if (bsd->bss) { + yasm_section_bcs_traverse(sect, info->errwarns, + info, bin_objfmt_no_output_bytecode); + } else { + yasm_intnum_set(info->tmp_intn, bsd->istart); + yasm_intnum_calc(info->tmp_intn, YASM_EXPR_SUB, info->origin); + if (yasm_intnum_sign(info->tmp_intn) < 0) { + yasm_error_set(YASM_ERROR_VALUE, + N_("section `%s' starts before origin (ORG)"), + yasm_section_get_name(sect)); + yasm_errwarn_propagate(info->errwarns, 0); + return 0; + } + if (!yasm_intnum_check_size(info->tmp_intn, sizeof(long)*8, 0, 1)) { + yasm_error_set(YASM_ERROR_VALUE, + N_("section `%s' start value too large"), + yasm_section_get_name(sect)); + yasm_errwarn_propagate(info->errwarns, 0); + return 0; + } + if (fseek(info->f, yasm_intnum_get_int(info->tmp_intn) + info->start, + SEEK_SET) < 0) + yasm__fatal(N_("could not seek on output file")); + yasm_section_bcs_traverse(sect, info->errwarns, + info, bin_objfmt_output_bytecode); + } + + return 0; +} + +static void +bin_objfmt_cleanup(bin_objfmt_output_info *info) +{ + bin_group *group, *group_temp; + + yasm_xfree(info->buf); + yasm_intnum_destroy(info->origin); + yasm_intnum_destroy(info->tmp_intn); + + TAILQ_FOREACH_SAFE(group, &info->lma_groups, link, group_temp) + bin_group_destroy(group); + + TAILQ_FOREACH_SAFE(group, &info->vma_groups, link, group_temp) + bin_group_destroy(group); +} + +static void +bin_objfmt_output(yasm_object *object, FILE *f, /*@unused@*/ int all_syms, + yasm_errwarns *errwarns) +{ + yasm_objfmt_bin *objfmt_bin = (yasm_objfmt_bin *)object->objfmt; + bin_objfmt_output_info info; + bin_group *group, *lma_group, *vma_group, *group_temp; + yasm_intnum *start, *last, *vdelta; + bin_groups unsorted_groups, bss_groups; + + info.start = ftell(f); + + /* Set ORG to 0 unless otherwise specified */ + if (objfmt_bin->org) { + info.origin = yasm_expr_get_intnum(&objfmt_bin->org, 0); + if (!info.origin) { + yasm_error_set(YASM_ERROR_TOO_COMPLEX, + N_("ORG expression is too complex")); + yasm_errwarn_propagate(errwarns, objfmt_bin->org->line); + return; + } + if (yasm_intnum_sign(info.origin) < 0) { + yasm_error_set(YASM_ERROR_VALUE, N_("ORG expression is negative")); + yasm_errwarn_propagate(errwarns, objfmt_bin->org->line); + return; + } + info.origin = yasm_intnum_copy(info.origin); + } else + info.origin = yasm_intnum_create_uint(0); + + info.object = object; + info.errwarns = errwarns; + info.f = f; + info.buf = yasm_xmalloc(REGULAR_OUTBUF_SIZE); + info.tmp_intn = yasm_intnum_create_uint(0); + TAILQ_INIT(&info.lma_groups); + TAILQ_INIT(&info.vma_groups); + + /* Check symbol table */ + yasm_symtab_traverse(object->symtab, &info, bin_objfmt_check_sym); + + /* Create section groups */ + if (yasm_object_sections_traverse(object, &info, bin_lma_create_group)) { + bin_objfmt_cleanup(&info); + return; /* error detected */ + } + + /* Determine section order according to LMA. + * Sections can be ordered either by (priority): + * - follows + * - start + * - progbits/nobits setting + * - order in the input file + */ + + /* Look at each group with follows specified, and find the section + * that group is supposed to follow. + */ + TAILQ_FOREACH_SAFE(lma_group, &info.lma_groups, link, group_temp) { + if (lma_group->bsd->follows) { + bin_group *found; + /* Need to find group containing section this section follows. */ + found = + find_group_by_name(&info.lma_groups, lma_group->bsd->follows); + if (!found) { + yasm_error_set(YASM_ERROR_VALUE, + N_("section `%s' follows an invalid or unknown section `%s'"), + yasm_section_get_name(lma_group->section), + lma_group->bsd->follows); + yasm_errwarn_propagate(errwarns, 0); + bin_objfmt_cleanup(&info); + return; + } + + /* Check for loops */ + if (lma_group->section == found->section || + find_group_by_section(&lma_group->follow_groups, + found->section)) { + yasm_error_set(YASM_ERROR_VALUE, + N_("follows loop between section `%s' and section `%s'"), + yasm_section_get_name(lma_group->section), + yasm_section_get_name(found->section)); + yasm_errwarn_propagate(errwarns, 0); + bin_objfmt_cleanup(&info); + return; + } + + /* Remove this section from main lma groups list */ + TAILQ_REMOVE(&info.lma_groups, lma_group, link); + /* Add it after the section it's supposed to follow. */ + TAILQ_INSERT_TAIL(&found->follow_groups, lma_group, link); + } + } + + /* Sort the top-level groups according to their start address. + * Use Shell sort for ease of implementation. + * If no start address is specified for a section, don't change the order, + * and move BSS sections to a separate list so they can be moved to the + * end of the lma list after all other sections are sorted. + */ + unsorted_groups = info.lma_groups; /* structure copy */ + TAILQ_INIT(&info.lma_groups); + TAILQ_INIT(&bss_groups); + TAILQ_FOREACH_SAFE(lma_group, &unsorted_groups, link, group_temp) { + bin_group *before; + + if (!lma_group->bsd->istart) { + if (lma_group->bsd->bss) + TAILQ_INSERT_TAIL(&bss_groups, lma_group, link); + else + TAILQ_INSERT_TAIL(&info.lma_groups, lma_group, link); + continue; + } + + before = NULL; + TAILQ_FOREACH(group, &info.lma_groups, link) { + if (!group->bsd->istart) + continue; + if (yasm_intnum_compare(group->bsd->istart, + lma_group->bsd->istart) > 0) { + before = group; + break; + } + } + if (before) + TAILQ_INSERT_BEFORE(before, lma_group, link); + else + TAILQ_INSERT_TAIL(&info.lma_groups, lma_group, link); + } + + /* Move the pure-BSS sections to the end of the LMA list. */ + TAILQ_FOREACH_SAFE(group, &bss_groups, link, group_temp) + TAILQ_INSERT_TAIL(&info.lma_groups, group, link); + TAILQ_INIT(&bss_groups); /* For sanity */ + + /* Assign a LMA start address to every section. + * Also assign VMA=LMA unless otherwise specified. + * + * We need to assign VMA=LMA here (while walking the tree) for the case: + * sect1 start=0 (size=0x11) + * sect2 follows=sect1 valign=16 (size=0x104) + * sect3 follows=sect2 valign=16 + * Where the valign of sect2 will result in a sect3 vaddr higher than a + * naive segment-by-segment interpretation (where sect3 and sect2 would + * have a VMA overlap). + * + * Algorithm for VMA=LMA setting: + * Start with delta=0. + * If there's no virtual attributes, we simply set VMA = LMA+delta. + * If there's only valign specified, we set VMA = aligned LMA, and add + * any new alignment difference to delta. + * + * We could do the LMA start and VMA=LMA steps in two separate steps, + * but it's easier to just recurse once. + */ + start = yasm_intnum_copy(info.origin); + last = yasm_intnum_copy(info.origin); + vdelta = yasm_intnum_create_uint(0); + TAILQ_FOREACH(lma_group, &info.lma_groups, link) { + if (lma_group->bsd->istart) + yasm_intnum_set(start, lma_group->bsd->istart); + group_assign_start_recurse(lma_group, start, last, vdelta, + info.tmp_intn, errwarns); + yasm_intnum_set(start, last); + } + yasm_intnum_destroy(last); + yasm_intnum_destroy(vdelta); + + /* + * Determine section order according to VMA + */ + + /* Create section groups */ + if (yasm_object_sections_traverse(object, &info, bin_vma_create_group)) { + yasm_intnum_destroy(start); + bin_objfmt_cleanup(&info); + return; /* error detected */ + } + + /* Look at each group with vfollows specified, and find the section + * that group is supposed to follow. + */ + TAILQ_FOREACH_SAFE(vma_group, &info.vma_groups, link, group_temp) { + if (vma_group->bsd->vfollows) { + bin_group *found; + /* Need to find group containing section this section follows. */ + found = find_group_by_name(&info.vma_groups, + vma_group->bsd->vfollows); + if (!found) { + yasm_error_set(YASM_ERROR_VALUE, + N_("section `%s' vfollows an invalid or unknown section `%s'"), + yasm_section_get_name(vma_group->section), + vma_group->bsd->vfollows); + yasm_errwarn_propagate(errwarns, 0); + yasm_intnum_destroy(start); + bin_objfmt_cleanup(&info); + return; + } + + /* Check for loops */ + if (vma_group->section == found->section || + find_group_by_section(&vma_group->follow_groups, + found->section)) { + yasm_error_set(YASM_ERROR_VALUE, + N_("vfollows loop between section `%s' and section `%s'"), + yasm_section_get_name(vma_group->section), + yasm_section_get_name(found->section)); + yasm_errwarn_propagate(errwarns, 0); + bin_objfmt_cleanup(&info); + return; + } + + /* Remove this section from main lma groups list */ + TAILQ_REMOVE(&info.vma_groups, vma_group, link); + /* Add it after the section it's supposed to follow. */ + TAILQ_INSERT_TAIL(&found->follow_groups, vma_group, link); + } + } + + /* Due to the combination of steps above, we now know that all top-level + * groups have integer ivstart: + * Vstart Vfollows Valign Handled by + * No No No group_assign_start_recurse() + * No No Yes group_assign_start_recurse() + * No Yes - vfollows loop (above) + * Yes - - bin_lma_create_group() + */ + TAILQ_FOREACH(vma_group, &info.vma_groups, link) { + yasm_intnum_set(start, vma_group->bsd->ivstart); + group_assign_vstart_recurse(vma_group, start, errwarns); + } + + /* Output map file */ + output_map(&info); + + /* Ensure we don't have overlapping progbits LMAs. + * Use a dumb O(N^2) algorithm as the number of sections is essentially + * always low. + */ + if (yasm_object_sections_traverse(object, NULL, check_lma_overlap)) { + yasm_errwarn_propagate(errwarns, 0); + yasm_intnum_destroy(start); + bin_objfmt_cleanup(&info); + return; + } + + /* Output sections */ + yasm_object_sections_traverse(object, &info, bin_objfmt_output_section); + + /* Clean up */ + yasm_intnum_destroy(start); + bin_objfmt_cleanup(&info); +} + +static void +bin_objfmt_destroy(yasm_objfmt *objfmt) +{ + yasm_objfmt_bin *objfmt_bin = (yasm_objfmt_bin *)objfmt; + if (objfmt_bin->map_filename) + yasm_xfree(objfmt_bin->map_filename); + yasm_expr_destroy(objfmt_bin->org); + yasm_xfree(objfmt); +} + +static void +define_section_symbol(yasm_symtab *symtab, yasm_section *sect, + const char *sectname, const char *suffix, + enum bin_ssym which, unsigned long line) +{ + yasm_symrec *sym; + bin_symrec_data *bsymd = yasm_xmalloc(sizeof(bin_symrec_data)); + char *symname = yasm_xmalloc(8+strlen(sectname)+strlen(suffix)+1); + + strcpy(symname, "section."); + strcat(symname, sectname); + strcat(symname, suffix); + + bsymd->section = sect; + bsymd->which = which; + + sym = yasm_symtab_declare(symtab, symname, YASM_SYM_EXTERN, line); + yasm_xfree(symname); + yasm_symrec_add_data(sym, &bin_symrec_data_cb, bsymd); +} + +static void +bin_objfmt_init_new_section(yasm_section *sect, unsigned long line) +{ + yasm_object *object = yasm_section_get_object(sect); + const char *sectname = yasm_section_get_name(sect); + /*yasm_objfmt_bin *objfmt_bin = (yasm_objfmt_bin *)object->objfmt;*/ + bin_section_data *data; + + data = yasm_xmalloc(sizeof(bin_section_data)); + data->bss = 0; + data->align = NULL; + data->valign = NULL; + data->start = NULL; + data->vstart = NULL; + data->follows = NULL; + data->vfollows = NULL; + data->istart = NULL; + data->ivstart = NULL; + data->length = NULL; + yasm_section_add_data(sect, &bin_section_data_cb, data); + + define_section_symbol(object->symtab, sect, sectname, ".start", + SSYM_START, line); + define_section_symbol(object->symtab, sect, sectname, ".vstart", + SSYM_VSTART, line); + define_section_symbol(object->symtab, sect, sectname, ".length", + SSYM_LENGTH, line); +} + +static yasm_section * +bin_objfmt_add_default_section(yasm_object *object) +{ + yasm_section *retval; + int isnew; + + retval = yasm_object_get_general(object, ".text", 0, 1, 0, &isnew, 0); + if (isnew) + yasm_section_set_default(retval, 1); + return retval; +} + +/* GAS-style flags */ +static int +bin_helper_gasflags(void *obj, yasm_valparam *vp, unsigned long line, void *d, + /*@unused@*/ uintptr_t arg) +{ + /* TODO */ + return 0; +} + +static /*@observer@*/ /*@null@*/ yasm_section * +bin_objfmt_section_switch(yasm_object *object, yasm_valparamhead *valparams, + /*@unused@*/ /*@null@*/ + yasm_valparamhead *objext_valparams, + unsigned long line) +{ + yasm_valparam *vp; + yasm_section *retval; + int isnew; + int flags_override = 0; + const char *sectname; + bin_section_data *bsd = NULL; + + struct bin_section_switch_data { + /*@only@*/ /*@null@*/ char *follows; + /*@only@*/ /*@null@*/ char *vfollows; + /*@only@*/ /*@null@*/ yasm_expr *start; + /*@only@*/ /*@null@*/ yasm_expr *vstart; + /*@only@*/ /*@null@*/ yasm_intnum *align; + /*@only@*/ /*@null@*/ yasm_intnum *valign; + unsigned long bss; + unsigned long code; + } data; + + static const yasm_dir_help help[] = { + { "follows", 1, yasm_dir_helper_string, + offsetof(struct bin_section_switch_data, follows), 0 }, + { "vfollows", 1, yasm_dir_helper_string, + offsetof(struct bin_section_switch_data, vfollows), 0 }, + { "start", 1, yasm_dir_helper_expr, + offsetof(struct bin_section_switch_data, start), 0 }, + { "vstart", 1, yasm_dir_helper_expr, + offsetof(struct bin_section_switch_data, vstart), 0 }, + { "align", 1, yasm_dir_helper_intn, + offsetof(struct bin_section_switch_data, align), 0 }, + { "valign", 1, yasm_dir_helper_intn, + offsetof(struct bin_section_switch_data, valign), 0 }, + { "nobits", 0, yasm_dir_helper_flag_set, + offsetof(struct bin_section_switch_data, bss), 1 }, + { "progbits", 0, yasm_dir_helper_flag_set, + offsetof(struct bin_section_switch_data, bss), 0 }, + { "code", 0, yasm_dir_helper_flag_set, + offsetof(struct bin_section_switch_data, code), 1 }, + { "data", 0, yasm_dir_helper_flag_set, + offsetof(struct bin_section_switch_data, code), 0 }, + { "execute", 0, yasm_dir_helper_flag_set, + offsetof(struct bin_section_switch_data, code), 1 }, + { "noexecute", 0, yasm_dir_helper_flag_set, + offsetof(struct bin_section_switch_data, code), 0 }, + { "gasflags", 1, bin_helper_gasflags, 0, 0 } + }; + + vp = yasm_vps_first(valparams); + sectname = yasm_vp_string(vp); + if (!sectname) + return NULL; + vp = yasm_vps_next(vp); + + retval = yasm_object_find_general(object, sectname); + if (retval) { + bsd = yasm_section_get_data(retval, &bin_section_data_cb); + assert(bsd != NULL); + data.follows = bsd->follows; + data.vfollows = bsd->vfollows; + data.start = bsd->start; + data.vstart = bsd->vstart; + data.align = NULL; + data.valign = NULL; + data.bss = bsd->bss; + data.code = yasm_section_is_code(retval); + } else { + data.follows = NULL; + data.vfollows = NULL; + data.start = NULL; + data.vstart = NULL; + data.align = NULL; + data.valign = NULL; + data.bss = strcmp(sectname, ".bss") == 0; + data.code = strcmp(sectname, ".text") == 0; + } + + flags_override = yasm_dir_helper(object, vp, line, help, NELEMS(help), + &data, yasm_dir_helper_valparam_warn); + if (flags_override < 0) + return NULL; /* error occurred */ + + if (data.start && data.follows) { + yasm_error_set(YASM_ERROR_GENERAL, + N_("cannot combine `start' and `follows' section attributes")); + return NULL; + } + + if (data.vstart && data.vfollows) { + yasm_error_set(YASM_ERROR_GENERAL, + N_("cannot combine `vstart' and `vfollows' section attributes")); + return NULL; + } + + if (data.align) { + unsigned long align = yasm_intnum_get_uint(data.align); + + /* Alignments must be a power of two. */ + if (!is_exp2(align)) { + yasm_error_set(YASM_ERROR_VALUE, + N_("argument to `%s' is not a power of two"), + "align"); + return NULL; + } + } else + data.align = bsd ? bsd->align : NULL; + + if (data.valign) { + unsigned long valign = yasm_intnum_get_uint(data.valign); + + /* Alignments must be a power of two. */ + if (!is_exp2(valign)) { + yasm_error_set(YASM_ERROR_VALUE, + N_("argument to `%s' is not a power of two"), + "valign"); + return NULL; + } + } else + data.valign = bsd ? bsd->valign : NULL; + + retval = yasm_object_get_general(object, sectname, 0, (int)data.code, + (int)data.bss, &isnew, line); + + bsd = yasm_section_get_data(retval, &bin_section_data_cb); + + if (isnew || yasm_section_is_default(retval)) { + yasm_section_set_default(retval, 0); + } + + /* Update section flags */ + bsd->bss = data.bss; + bsd->align = data.align; + bsd->valign = data.valign; + bsd->start = data.start; + bsd->vstart = data.vstart; + bsd->follows = data.follows; + bsd->vfollows = data.vfollows; + + return retval; +} + +static /*@observer@*/ /*@null@*/ yasm_symrec * +bin_objfmt_get_special_sym(yasm_object *object, const char *name, + const char *parser) +{ + return NULL; +} + +static void +bin_objfmt_dir_org(yasm_object *object, + /*@null@*/ yasm_valparamhead *valparams, + /*@unused@*/ /*@null@*/ + yasm_valparamhead *objext_valparams, unsigned long line) +{ + yasm_objfmt_bin *objfmt_bin = (yasm_objfmt_bin *)object->objfmt; + yasm_valparam *vp; + + /* We only allow a single ORG in a program. */ + if (objfmt_bin->org) { + yasm_error_set(YASM_ERROR_GENERAL, N_("program origin redefined")); + return; + } + + /* ORG takes just a simple expression as param */ + vp = yasm_vps_first(valparams); + objfmt_bin->org = yasm_vp_expr(vp, object->symtab, line); + if (!objfmt_bin->org) { + yasm_error_set(YASM_ERROR_SYNTAX, + N_("argument to ORG must be expression")); + return; + } +} + +struct bin_dir_map_data { + unsigned long flags; + /*@only@*/ /*@null@*/ char *filename; +}; + +static int +dir_map_filename(void *obj, yasm_valparam *vp, unsigned long line, void *data) +{ + struct bin_dir_map_data *mdata = (struct bin_dir_map_data *)data; + const char *filename; + + if (mdata->filename) { + yasm_warn_set(YASM_WARN_GENERAL, N_("map file already specified")); + return 0; + } + + filename = yasm_vp_string(vp); + if (!filename) { + yasm_error_set(YASM_ERROR_SYNTAX, + N_("unexpected expression in [map]")); + return -1; + } + mdata->filename = yasm__xstrdup(filename); + + return 1; +} + +static void +bin_objfmt_dir_map(yasm_object *object, + /*@null@*/ yasm_valparamhead *valparams, + /*@unused@*/ /*@null@*/ + yasm_valparamhead *objext_valparams, unsigned long line) +{ + yasm_objfmt_bin *objfmt_bin = (yasm_objfmt_bin *)object->objfmt; + + struct bin_dir_map_data data; + + static const yasm_dir_help help[] = { + { "all", 0, yasm_dir_helper_flag_or, + offsetof(struct bin_dir_map_data, flags), + MAP_BRIEF|MAP_SECTIONS|MAP_SYMBOLS }, + { "brief", 0, yasm_dir_helper_flag_or, + offsetof(struct bin_dir_map_data, flags), MAP_BRIEF }, + { "sections", 0, yasm_dir_helper_flag_or, + offsetof(struct bin_dir_map_data, flags), MAP_SECTIONS }, + { "segments", 0, yasm_dir_helper_flag_or, + offsetof(struct bin_dir_map_data, flags), MAP_SECTIONS }, + { "symbols", 0, yasm_dir_helper_flag_or, + offsetof(struct bin_dir_map_data, flags), MAP_SYMBOLS } + }; + + data.flags = objfmt_bin->map_flags | MAP_NONE; + data.filename = objfmt_bin->map_filename; + + if (valparams && yasm_dir_helper(object, yasm_vps_first(valparams), line, help, + NELEMS(help), &data, dir_map_filename) < 0) + return; /* error occurred */ + + objfmt_bin->map_flags = data.flags; + objfmt_bin->map_filename = data.filename; +} + +static void +bin_section_data_destroy(void *data) +{ + bin_section_data *bsd = (bin_section_data *)data; + if (bsd->start) + yasm_expr_destroy(bsd->start); + if (bsd->vstart) + yasm_expr_destroy(bsd->vstart); + if (bsd->follows) + yasm_xfree(bsd->follows); + if (bsd->vfollows) + yasm_xfree(bsd->vfollows); + if (bsd->istart) + yasm_intnum_destroy(bsd->istart); + if (bsd->ivstart) + yasm_intnum_destroy(bsd->ivstart); + if (bsd->length) + yasm_intnum_destroy(bsd->length); + yasm_xfree(data); +} + +static void +bin_section_data_print(void *data, FILE *f, int indent_level) +{ + bin_section_data *bsd = (bin_section_data *)data; + + fprintf(f, "%*sbss=%d\n", indent_level, "", bsd->bss); + + fprintf(f, "%*salign=", indent_level, ""); + if (bsd->align) + yasm_intnum_print(bsd->align, f); + else + fprintf(f, "(nil)"); + fprintf(f, "\n%*svalign=", indent_level, ""); + if (bsd->valign) + yasm_intnum_print(bsd->valign, f); + else + fprintf(f, "(nil)"); + + fprintf(f, "\n%*sstart=", indent_level, ""); + yasm_expr_print(bsd->start, f); + fprintf(f, "\n%*svstart=", indent_level, ""); + yasm_expr_print(bsd->vstart, f); + + fprintf(f, "\n%*sfollows=", indent_level, ""); + if (bsd->follows) + fprintf(f, "\"%s\"", bsd->follows); + else + fprintf(f, "(nil)"); + fprintf(f, "\n%*svfollows=", indent_level, ""); + if (bsd->vfollows) + fprintf(f, "\"%s\"", bsd->vfollows); + else + fprintf(f, "(nil)"); + + fprintf(f, "\n%*sistart=", indent_level, ""); + if (bsd->istart) + yasm_intnum_print(bsd->istart, f); + else + fprintf(f, "(nil)"); + fprintf(f, "\n%*sivstart=", indent_level, ""); + if (bsd->ivstart) + yasm_intnum_print(bsd->ivstart, f); + else + fprintf(f, "(nil)"); + + fprintf(f, "\n%*slength=", indent_level, ""); + if (bsd->length) + yasm_intnum_print(bsd->length, f); + else + fprintf(f, "(nil)"); + fprintf(f, "\n"); +} + +static void +bin_symrec_data_destroy(void *data) +{ + yasm_xfree(data); +} + +static void +bin_symrec_data_print(void *data, FILE *f, int indent_level) +{ + bin_symrec_data *bsymd = (bin_symrec_data *)data; + + fprintf(f, "%*ssection=\"%s\"\n", indent_level, "", + yasm_section_get_name(bsymd->section)); + fprintf(f, "%*swhich=", indent_level, ""); + switch (bsymd->which) { + case SSYM_START: fprintf(f, "START"); break; + case SSYM_VSTART: fprintf(f, "VSTART"); break; + case SSYM_LENGTH: fprintf(f, "LENGTH"); break; + } + fprintf(f, "\n"); +} + + +/* Define valid debug formats to use with this object format */ +static const char *bin_objfmt_dbgfmt_keywords[] = { + "null", + NULL +}; + +static const yasm_directive bin_objfmt_directives[] = { + { "org", "nasm", bin_objfmt_dir_org, YASM_DIR_ARG_REQUIRED }, + { "map", "nasm", bin_objfmt_dir_map, YASM_DIR_ANY }, + { NULL, NULL, NULL, 0 } +}; + +static const char *bin_nasm_stdmac[] = { + "%imacro org 1+.nolist", + "[org %1]", + "%endmacro", + NULL +}; + +static const yasm_stdmac bin_objfmt_stdmacs[] = { + { "nasm", "nasm", bin_nasm_stdmac }, + { "tasm", "tasm", bin_nasm_stdmac }, + { NULL, NULL, NULL } +}; + +/* Define objfmt structure -- see objfmt.h for details */ +yasm_objfmt_module yasm_bin_LTX_objfmt = { + "Flat format binary", + "bin", + NULL, + 16, + 0, + bin_objfmt_dbgfmt_keywords, + "null", + bin_objfmt_directives, + bin_objfmt_stdmacs, + bin_objfmt_create, + bin_objfmt_output, + bin_objfmt_destroy, + bin_objfmt_add_default_section, + bin_objfmt_init_new_section, + bin_objfmt_section_switch, + bin_objfmt_get_special_sym +}; + +#define EXE_HEADER_SIZE 0x200 + +/* DOS .EXE binaries are just raw binaries with a header */ +yasm_objfmt_module yasm_dosexe_LTX_objfmt; + +static yasm_objfmt * +dosexe_objfmt_create(yasm_object *object) +{ + yasm_objfmt_bin *objfmt_bin = (yasm_objfmt_bin *) bin_objfmt_create(object); + objfmt_bin->objfmt.module = &yasm_dosexe_LTX_objfmt; + return (yasm_objfmt *)objfmt_bin; +} + +static unsigned long +get_sym(yasm_object *object, const char *name) { + yasm_symrec *symrec = yasm_symtab_get(object->symtab, name); + yasm_bytecode *prevbc; + if (!symrec) + return 0; + if (!yasm_symrec_get_label(symrec, &prevbc)) + return 0; + return prevbc->offset + prevbc->len; +} + +static void +dosexe_objfmt_output(yasm_object *object, FILE *f, /*@unused@*/ int all_syms, + yasm_errwarns *errwarns) +{ + unsigned long tot_size, size, bss_size; + unsigned long start, bss; + unsigned char c; + + fseek(f, EXE_HEADER_SIZE, SEEK_SET); + + bin_objfmt_output(object, f, all_syms, errwarns); + + tot_size = ftell(f); + + /* if there is a __bss_start symbol, data after it is 0, no need to write + * it. */ + bss = get_sym(object, "__bss_start"); + if (bss) + size = bss; + else + size = tot_size; + bss_size = tot_size - size; +#ifdef HAVE_FTRUNCATE + if (size != tot_size) + ftruncate(fileno(f), EXE_HEADER_SIZE + size); +#endif + fseek(f, 0, SEEK_SET); + + /* magic */ + fwrite("MZ", 1, 2, f); + + /* file size */ + c = size & 0xff; + fwrite(&c, 1, 1, f); + c = !!(size & 0x100); + fwrite(&c, 1, 1, f); + c = ((size + 511) >> 9) & 0xff; + fwrite(&c, 1, 1, f); + c = ((size + 511) >> 17) & 0xff; + fwrite(&c, 1, 1, f); + + /* relocation # */ + c = 0; + fwrite(&c, 1, 1, f); + fwrite(&c, 1, 1, f); + + /* header size */ + c = EXE_HEADER_SIZE / 16; + fwrite(&c, 1, 1, f); + c = 0; + fwrite(&c, 1, 1, f); + + /* minimum paragraph # */ + bss_size = (bss_size + 15) >> 4; + c = bss_size & 0xff; + fwrite(&c, 1, 1, f); + c = (bss_size >> 8) & 0xff; + fwrite(&c, 1, 1, f); + + /* maximum paragraph # */ + c = 0xFF; + fwrite(&c, 1, 1, f); + fwrite(&c, 1, 1, f); + + /* relative value of stack segment */ + c = 0; + fwrite(&c, 1, 1, f); + fwrite(&c, 1, 1, f); + + /* SP at start */ + c = 0; + fwrite(&c, 1, 1, f); + fwrite(&c, 1, 1, f); + + /* header checksum */ + c = 0; + fwrite(&c, 1, 1, f); + fwrite(&c, 1, 1, f); + + /* IP at start */ + start = get_sym(object, "start"); + if (!start) { + yasm_error_set(YASM_ERROR_GENERAL, + N_("%s: could not find symbol `start'")); + return; + } + c = start & 0xff; + fwrite(&c, 1, 1, f); + c = (start >> 8) & 0xff; + fwrite(&c, 1, 1, f); + + /* CS start */ + c = 0; + fwrite(&c, 1, 1, f); + fwrite(&c, 1, 1, f); + + /* reloc start */ + c = 0x22; + fwrite(&c, 1, 1, f); + c = 0; + fwrite(&c, 1, 1, f); + + /* Overlay number */ + c = 0; + fwrite(&c, 1, 1, f); + fwrite(&c, 1, 1, f); +} + + +/* Define objfmt structure -- see objfmt.h for details */ +yasm_objfmt_module yasm_dosexe_LTX_objfmt = { + "DOS .EXE format binary", + "dosexe", + "exe", + 16, + 0, + bin_objfmt_dbgfmt_keywords, + "null", + bin_objfmt_directives, + bin_objfmt_stdmacs, + dosexe_objfmt_create, + dosexe_objfmt_output, + bin_objfmt_destroy, + bin_objfmt_add_default_section, + bin_objfmt_init_new_section, + bin_objfmt_section_switch, + bin_objfmt_get_special_sym +}; diff --git a/contrib/tools/yasm/modules/objfmts/coff/coff-objfmt.c b/contrib/tools/yasm/modules/objfmts/coff/coff-objfmt.c new file mode 100644 index 0000000000..388b09af32 --- /dev/null +++ b/contrib/tools/yasm/modules/objfmts/coff/coff-objfmt.c @@ -0,0 +1,2522 @@ +/* + * COFF (DJGPP) object format + * + * 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 <time.h> + +#include <libyasm.h> + +#include "coff-objfmt.h" + + +#define REGULAR_OUTBUF_SIZE 1024 + +/* Defining this to 0 sets all section VMA's to 0 rather than as the same as + * the LMA. According to the DJGPP COFF Spec, this should be set to 1 + * (VMA=LMA), and indeed DJGPP's GCC output shows VMA=LMA. However, NASM + * outputs VMA=0 (as if this was 0), and GNU objdump output looks a lot nicer + * with VMA=0. Who's right? This is #defined as changing this setting affects + * several places in the code. + */ +#define COFF_SET_VMA (!objfmt_coff->win32) + +#define COFF_MACHINE_I386 0x014C +#define COFF_MACHINE_AMD64 0x8664 + +#define COFF_F_LNNO 0x0004 /* line number info NOT present */ +#define COFF_F_LSYMS 0x0008 /* local symbols NOT present */ +#define COFF_F_AR32WR 0x0100 /* 32-bit little endian file */ + +typedef struct coff_reloc { + yasm_reloc reloc; + enum { + COFF_RELOC_ABSOLUTE = 0, /* absolute, no reloc needed */ + + /* I386 relocations */ + COFF_RELOC_I386_ADDR16 = 0x1, /* 16-bit absolute reference */ + COFF_RELOC_I386_REL16 = 0x2, /* 16-bit PC-relative reference */ + COFF_RELOC_I386_ADDR32 = 0x6, /* 32-bit absolute reference */ + COFF_RELOC_I386_ADDR32NB = 0x7, /* 32-bit absolute ref w/o base */ + COFF_RELOC_I386_SEG12 = 0x9, /* 16-bit absolute segment ref */ + COFF_RELOC_I386_SECTION = 0xA, /* section index */ + COFF_RELOC_I386_SECREL = 0xB, /* offset from start of segment */ + COFF_RELOC_I386_TOKEN = 0xC, /* CLR metadata token */ + COFF_RELOC_I386_SECREL7 = 0xD, /* 7-bit offset from base of sect */ + COFF_RELOC_I386_REL32 = 0x14, /* 32-bit PC-relative reference */ + + /* AMD64 relocations */ + COFF_RELOC_AMD64_ADDR64 = 0x1, /* 64-bit address (VA) */ + COFF_RELOC_AMD64_ADDR32 = 0x2, /* 32-bit address (VA) */ + COFF_RELOC_AMD64_ADDR32NB = 0x3, /* 32-bit address w/o base (RVA) */ + COFF_RELOC_AMD64_REL32 = 0x4, /* 32-bit relative (0 byte dist) */ + COFF_RELOC_AMD64_REL32_1 = 0x5, /* 32-bit relative (1 byte dist) */ + COFF_RELOC_AMD64_REL32_2 = 0x6, /* 32-bit relative (2 byte dist) */ + COFF_RELOC_AMD64_REL32_3 = 0x7, /* 32-bit relative (3 byte dist) */ + COFF_RELOC_AMD64_REL32_4 = 0x8, /* 32-bit relative (4 byte dist) */ + COFF_RELOC_AMD64_REL32_5 = 0x9, /* 32-bit relative (5 byte dist) */ + COFF_RELOC_AMD64_SECTION = 0xA, /* section index */ + COFF_RELOC_AMD64_SECREL = 0xB, /* 32-bit offset from base of sect */ + COFF_RELOC_AMD64_SECREL7 = 0xC, /* 7-bit offset from base of sect */ + COFF_RELOC_AMD64_TOKEN = 0xD /* CLR metadata token */ + } type; /* type of relocation */ +} coff_reloc; + +#define COFF_STYP_TEXT 0x00000020UL +#define COFF_STYP_DATA 0x00000040UL +#define COFF_STYP_BSS 0x00000080UL +#define COFF_STYP_INFO 0x00000200UL +#define COFF_STYP_STD_MASK 0x000003FFUL +#define COFF_STYP_ALIGN_MASK 0x00F00000UL +#define COFF_STYP_ALIGN_SHIFT 20 +#define COFF_STYP_NRELOC_OVFL 0x01000000UL +#define COFF_STYP_DISCARD 0x02000000UL +#define COFF_STYP_NOCACHE 0x04000000UL +#define COFF_STYP_NOPAGE 0x08000000UL +#define COFF_STYP_SHARED 0x10000000UL +#define COFF_STYP_EXECUTE 0x20000000UL +#define COFF_STYP_READ 0x40000000UL +#define COFF_STYP_WRITE 0x80000000UL +#define COFF_STYP_WIN32_MASK 0xFF000000UL + +#define COFF_FLAG_NOBASE (1UL<<0) /* Use no-base (NB) relocs */ + +typedef struct coff_section_data { + /*@dependent@*/ yasm_symrec *sym; /* symbol created for this section */ + unsigned int scnum; /* section number (1=first section) */ + unsigned long flags; /* section flags (see COFF_STYP_* above) */ + unsigned long addr; /* starting memory address (first section -> 0) */ + unsigned long scnptr; /* file ptr to raw data */ + unsigned long size; /* size of raw data (section data) in bytes */ + unsigned long relptr; /* file ptr to relocation */ + unsigned long nreloc; /* number of relocation entries >64k -> error */ + unsigned long flags2; /* internal flags (see COFF_FLAG_* above) */ + unsigned long strtab_name; /* strtab offset of name if name > 8 chars */ + int isdebug; /* is a debug section? */ +} coff_section_data; + +typedef enum coff_symrec_sclass { + COFF_SCL_EFCN = 0xff, /* physical end of function */ + COFF_SCL_NULL = 0, + COFF_SCL_AUTO = 1, /* automatic variable */ + COFF_SCL_EXT = 2, /* external symbol */ + COFF_SCL_STAT = 3, /* static */ + COFF_SCL_REG = 4, /* register variable */ + COFF_SCL_EXTDEF = 5, /* external definition */ + COFF_SCL_LABEL = 6, /* label */ + COFF_SCL_ULABEL = 7, /* undefined label */ + COFF_SCL_MOS = 8, /* member of structure */ + COFF_SCL_ARG = 9, /* function argument */ + COFF_SCL_STRTAG = 10, /* structure tag */ + COFF_SCL_MOU = 11, /* member of union */ + COFF_SCL_UNTAG = 12, /* union tag */ + COFF_SCL_TPDEF = 13, /* type definition */ + COFF_SCL_USTATIC = 14, /* undefined static */ + COFF_SCL_ENTAG = 15, /* enumeration tag */ + COFF_SCL_MOE = 16, /* member of enumeration */ + COFF_SCL_REGPARM = 17, /* register parameter */ + COFF_SCL_FIELD = 18, /* bit field */ + COFF_SCL_AUTOARG = 19, /* auto argument */ + COFF_SCL_LASTENT = 20, /* dummy entry (end of block) */ + COFF_SCL_BLOCK = 100, /* ".bb" or ".eb" */ + COFF_SCL_FCN = 101, /* ".bf" or ".ef" */ + COFF_SCL_EOS = 102, /* end of structure */ + COFF_SCL_FILE = 103, /* file name */ + COFF_SCL_LINE = 104, /* line # reformatted as symbol table entry */ + COFF_SCL_ALIAS = 105, /* duplicate tag */ + COFF_SCL_HIDDEN = 106 /* ext symbol in dmert public lib */ +} coff_symrec_sclass; + +typedef union coff_symtab_auxent { + /* no data needed for section symbol auxent, all info avail from sym */ + /*@owned@*/ char *fname; /* filename aux entry */ +} coff_symtab_auxent; + +typedef enum coff_symtab_auxtype { + COFF_SYMTAB_AUX_NONE = 0, + COFF_SYMTAB_AUX_SECT, + COFF_SYMTAB_AUX_FILE +} coff_symtab_auxtype; + +typedef struct coff_symrec_data { + int forcevis; /* force visibility in symbol table */ + unsigned long index; /* assigned COFF symbol table index */ + unsigned int type; /* type */ + coff_symrec_sclass sclass; /* storage class */ + + int numaux; /* number of auxiliary entries */ + coff_symtab_auxtype auxtype; /* type of aux entries */ + coff_symtab_auxent aux[1]; /* actually may be any size (including 0) */ +} coff_symrec_data; + +typedef struct yasm_objfmt_coff { + yasm_objfmt_base objfmt; /* base structure */ + + unsigned int parse_scnum; /* sect numbering in parser */ + int win32; /* nonzero for win32/64 output */ + int win64; /* nonzero for win64 output */ + + unsigned int machine; /* COFF machine to use */ + + coff_symrec_data *filesym_data; /* Data for .file symbol */ + + /* data for .def/.endef and related directives */ + coff_symrec_data *def_sym; /* symbol specified by .def */ + + /* data for win64 proc_frame and related directives */ + unsigned long proc_frame; /* Line number of start of proc, or 0 */ + unsigned long done_prolog; /* Line number of end of prologue, or 0 */ + /*@null@*/ coff_unwind_info *unwind; /* Unwind info */ + + yasm_symrec *ssym_imagebase; /* ..imagebase symbol for win64 */ +} yasm_objfmt_coff; + +typedef struct coff_objfmt_output_info { + yasm_object *object; + yasm_objfmt_coff *objfmt_coff; + yasm_errwarns *errwarns; + /*@dependent@*/ FILE *f; + /*@only@*/ unsigned char *buf; + yasm_section *sect; + /*@dependent@*/ coff_section_data *csd; + unsigned long addr; /* start of next section */ + + unsigned long indx; /* current symbol index */ + int all_syms; /* outputting all symbols? */ + unsigned long strtab_offset; /* current string table offset */ +} coff_objfmt_output_info; + +static void coff_section_data_destroy(/*@only@*/ void *d); +static void coff_section_data_print(void *data, FILE *f, int indent_level); + +static const yasm_assoc_data_callback coff_section_data_cb = { + coff_section_data_destroy, + coff_section_data_print +}; + +static void coff_symrec_data_destroy(/*@only@*/ void *d); +static void coff_symrec_data_print(void *data, FILE *f, int indent_level); + +static const yasm_assoc_data_callback coff_symrec_data_cb = { + coff_symrec_data_destroy, + coff_symrec_data_print +}; + +/* Bytecode callback function prototypes */ +static void win32_sxdata_bc_destroy(void *contents); +static void win32_sxdata_bc_print(const void *contents, FILE *f, + int indent_level); +static int win32_sxdata_bc_calc_len + (yasm_bytecode *bc, yasm_bc_add_span_func add_span, void *add_span_data); +static int win32_sxdata_bc_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 win32_sxdata_bc_callback = { + win32_sxdata_bc_destroy, + win32_sxdata_bc_print, + yasm_bc_finalize_common, + NULL, + win32_sxdata_bc_calc_len, + yasm_bc_expand_common, + win32_sxdata_bc_tobytes, + 0 +}; + +yasm_objfmt_module yasm_coff_LTX_objfmt; +yasm_objfmt_module yasm_win32_LTX_objfmt; +yasm_objfmt_module yasm_win64_LTX_objfmt; + + +static /*@dependent@*/ coff_symrec_data * +coff_objfmt_sym_set_data(yasm_symrec *sym, coff_symrec_sclass sclass, + int numaux, coff_symtab_auxtype auxtype) +{ + coff_symrec_data *sym_data; + + sym_data = yasm_xmalloc(sizeof(coff_symrec_data) + + (numaux-1)*sizeof(coff_symtab_auxent)); + sym_data->forcevis = 0; + sym_data->index = 0; + sym_data->type = 0; + sym_data->sclass = sclass; + sym_data->numaux = numaux; + sym_data->auxtype = auxtype; + + yasm_symrec_add_data(sym, &coff_symrec_data_cb, sym_data); + + return sym_data; +} + +static yasm_objfmt_coff * +coff_common_create(yasm_object *object) +{ + yasm_objfmt_coff *objfmt_coff = yasm_xmalloc(sizeof(yasm_objfmt_coff)); + yasm_symrec *filesym; + + /* Only support x86 arch */ + if (yasm__strcasecmp(yasm_arch_keyword(object->arch), "x86") != 0) { + yasm_xfree(objfmt_coff); + return NULL; + } + + objfmt_coff->parse_scnum = 1; /* section numbering starts at 1 */ + + /* FIXME: misuse of NULL bytecode here; it works, but only barely. */ + filesym = yasm_symtab_define_special(object->symtab, ".file", + YASM_SYM_GLOBAL); + objfmt_coff->filesym_data = + coff_objfmt_sym_set_data(filesym, COFF_SCL_FILE, 1, + COFF_SYMTAB_AUX_FILE); + /* Filename is set in coff_objfmt_output */ + objfmt_coff->filesym_data->aux[0].fname = NULL; + + objfmt_coff->proc_frame = 0; + objfmt_coff->done_prolog = 0; + objfmt_coff->unwind = NULL; + objfmt_coff->ssym_imagebase = NULL; + + return objfmt_coff; +} + +static yasm_objfmt * +coff_objfmt_create(yasm_object *object) +{ + yasm_objfmt_coff *objfmt_coff = coff_common_create(object); + + if (objfmt_coff) { + /* Support x86 and amd64 machines of x86 arch */ + if (yasm__strcasecmp(yasm_arch_get_machine(object->arch), "x86") == 0) + objfmt_coff->machine = COFF_MACHINE_I386; + else if (yasm__strcasecmp(yasm_arch_get_machine(object->arch), + "amd64") == 0) + objfmt_coff->machine = COFF_MACHINE_AMD64; + else { + yasm_xfree(objfmt_coff); + return NULL; + } + + objfmt_coff->objfmt.module = &yasm_coff_LTX_objfmt; + objfmt_coff->win32 = 0; + objfmt_coff->win64 = 0; + } + return (yasm_objfmt *)objfmt_coff; +} + +static yasm_objfmt * +win32_objfmt_create(yasm_object *object) +{ + yasm_objfmt_coff *objfmt_coff = coff_common_create(object); + + if (objfmt_coff) { + /* Support x86 and amd64 machines of x86 arch. + * (amd64 machine supported for backwards compatibility) + */ + if (yasm__strcasecmp(yasm_arch_get_machine(object->arch), + "x86") == 0) { + objfmt_coff->machine = COFF_MACHINE_I386; + objfmt_coff->objfmt.module = &yasm_win32_LTX_objfmt; + objfmt_coff->win64 = 0; + } else if (yasm__strcasecmp(yasm_arch_get_machine(object->arch), + "amd64") == 0) { + objfmt_coff->machine = COFF_MACHINE_AMD64; + objfmt_coff->objfmt.module = &yasm_win64_LTX_objfmt; + objfmt_coff->win64 = 1; + } else { + yasm_xfree(objfmt_coff); + return NULL; + } + + objfmt_coff->win32 = 1; + /* Define a @feat.00 symbol for win32 safeseh handling */ + if (!objfmt_coff->win64) { + yasm_symrec *feat00; + coff_symrec_data *sym_data; + feat00 = yasm_symtab_define_equ(object->symtab, "@feat.00", + yasm_expr_create_ident(yasm_expr_int( + yasm_intnum_create_uint(1)), 0), 0); + sym_data = coff_objfmt_sym_set_data(feat00, COFF_SCL_STAT, 0, + COFF_SYMTAB_AUX_NONE); + sym_data->forcevis = 1; + } + } + return (yasm_objfmt *)objfmt_coff; +} + +static yasm_objfmt * +win64_objfmt_create(yasm_object *object) +{ + yasm_objfmt_coff *objfmt_coff = coff_common_create(object); + + if (objfmt_coff) { + /* Support amd64 machine of x86 arch */ + if (yasm__strcasecmp(yasm_arch_get_machine(object->arch), + "amd64") == 0) { + objfmt_coff->machine = COFF_MACHINE_AMD64; + } else { + yasm_xfree(objfmt_coff); + return NULL; + } + + objfmt_coff->objfmt.module = &yasm_win64_LTX_objfmt; + objfmt_coff->win32 = 1; + objfmt_coff->win64 = 1; + objfmt_coff->ssym_imagebase = + yasm_symtab_define_label(object->symtab, "..imagebase", NULL, 0, 0); + } + return (yasm_objfmt *)objfmt_coff; +} + +static void +coff_objfmt_init_new_section(yasm_section *sect, unsigned long line) +{ + yasm_object *object = yasm_section_get_object(sect); + const char *sectname = yasm_section_get_name(sect); + yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt; + coff_section_data *data; + yasm_symrec *sym; + + data = yasm_xmalloc(sizeof(coff_section_data)); + data->scnum = objfmt_coff->parse_scnum++; + data->flags = 0; + data->addr = 0; + data->scnptr = 0; + data->size = 0; + data->relptr = 0; + data->nreloc = 0; + data->flags2 = 0; + data->strtab_name = 0; + data->isdebug = 0; + + if (yasm__strncasecmp(sectname, ".debug", 6)==0) { + data->flags = COFF_STYP_DATA; + if (objfmt_coff->win32) + data->flags |= COFF_STYP_DISCARD|COFF_STYP_READ; + data->isdebug = 1; + } else + data->flags = COFF_STYP_TEXT; + + yasm_section_add_data(sect, &coff_section_data_cb, data); + + sym = yasm_symtab_define_label(object->symtab, sectname, + yasm_section_bcs_first(sect), 1, line); + yasm_symrec_declare(sym, YASM_SYM_GLOBAL, line); + coff_objfmt_sym_set_data(sym, COFF_SCL_STAT, 1, COFF_SYMTAB_AUX_SECT); + data->sym = sym; +} + +static int +coff_objfmt_set_section_addr(yasm_section *sect, /*@null@*/ void *d) +{ + /*@null@*/ coff_objfmt_output_info *info = (coff_objfmt_output_info *)d; + /*@dependent@*/ /*@null@*/ coff_section_data *csd; + + assert(info != NULL); + csd = yasm_section_get_data(sect, &coff_section_data_cb); + assert(csd != NULL); + + csd->addr = info->addr; + info->addr += yasm_bc_next_offset(yasm_section_bcs_last(sect)); + + return 0; +} + +static int +coff_objfmt_output_value(yasm_value *value, unsigned char *buf, + unsigned int destsize, unsigned long offset, + yasm_bytecode *bc, int warn, /*@null@*/ void *d) +{ + /*@null@*/ coff_objfmt_output_info *info = (coff_objfmt_output_info *)d; + yasm_objfmt_coff *objfmt_coff; + /*@only@*/ /*@null@*/ yasm_intnum *dist = NULL; + /*@dependent@*/ /*@null@*/ yasm_intnum *intn; + unsigned long intn_val, intn_minus; + int retval; + unsigned int valsize = value->size; + + assert(info != NULL); + objfmt_coff = info->objfmt_coff; + + if (value->abs) + value->abs = yasm_expr_simplify(value->abs, 1); + + /* Try to output constant and PC-relative section-local first. + * Note this does NOT output any value with a SEG, WRT, external, + * cross-section, or non-PC-relative reference (those are handled below). + */ + switch (yasm_value_output_basic(value, buf, destsize, bc, warn, + info->object->arch)) { + case -1: + return 1; + case 0: + break; + default: + return 0; + } + + /* Handle other expressions, with relocation if necessary */ + if (value->rshift > 0 + || (value->seg_of && (value->wrt || value->curpos_rel)) + || (value->section_rel && (value->wrt || value->curpos_rel))) { + yasm_error_set(YASM_ERROR_TOO_COMPLEX, + N_("coff: relocation too complex")); + return 1; + } + + intn_val = 0; + intn_minus = 0; + if (value->rel) { + yasm_sym_vis vis = yasm_symrec_get_visibility(value->rel); + /*@dependent@*/ /*@null@*/ yasm_symrec *sym = value->rel; + unsigned long addr; + coff_reloc *reloc; + int nobase = info->csd->flags2 & COFF_FLAG_NOBASE; + + /* Sometimes we want the relocation to be generated against one + * symbol but the value generated correspond to a different symbol. + * This is done through (sym being referenced) WRT (sym used for + * reloc). Note both syms need to be in the same section! + */ + if (value->wrt && value->wrt == objfmt_coff->ssym_imagebase) + nobase = 1; + else if (value->wrt) { + /*@dependent@*/ /*@null@*/ yasm_bytecode *rel_precbc, *wrt_precbc; + + if (!yasm_symrec_get_label(sym, &rel_precbc) + || !yasm_symrec_get_label(value->wrt, &wrt_precbc)) { + yasm_error_set(YASM_ERROR_TOO_COMPLEX, + N_("coff: wrt expression too complex")); + return 1; + } + dist = yasm_calc_bc_dist(wrt_precbc, rel_precbc); + if (!dist) { + yasm_error_set(YASM_ERROR_TOO_COMPLEX, + N_("coff: cannot wrt across sections")); + return 1; + } + sym = value->wrt; + } + + if (vis & YASM_SYM_COMMON) { + /* In standard COFF, COMMON symbols have their length added in */ + if (!objfmt_coff->win32) { + /*@dependent@*/ /*@null@*/ yasm_expr **csize_expr; + /*@dependent@*/ /*@null@*/ yasm_intnum *common_size; + + csize_expr = yasm_symrec_get_common_size(sym); + assert(csize_expr != NULL); + common_size = yasm_expr_get_intnum(csize_expr, 1); + if (!common_size) { + yasm_error_set(YASM_ERROR_TOO_COMPLEX, + N_("coff: common size too complex")); + return 1; + } + + if (yasm_intnum_sign(common_size) < 0) { + yasm_error_set(YASM_ERROR_VALUE, + N_("coff: common size is negative")); + return 1; + } + + intn_val += yasm_intnum_get_uint(common_size); + } + } else if (!(vis & YASM_SYM_EXTERN) && !objfmt_coff->win64) { + /*@dependent@*/ /*@null@*/ yasm_bytecode *sym_precbc; + + /* Local symbols need relocation to their section's start */ + if (yasm_symrec_get_label(sym, &sym_precbc)) { + yasm_section *sym_sect = yasm_bc_get_section(sym_precbc); + /*@null@*/ coff_section_data *sym_csd; + sym_csd = yasm_section_get_data(sym_sect, + &coff_section_data_cb); + assert(sym_csd != NULL); + sym = sym_csd->sym; + intn_val = yasm_bc_next_offset(sym_precbc); + if (COFF_SET_VMA) + intn_val += sym_csd->addr; + } + } + + if (value->curpos_rel) { + /* For standard COFF, need to adjust to start of section, e.g. + * subtract out the bytecode offset. + * For Win32 COFF, need to adjust based on value size and position. + * For Win64 COFF that's IP-relative, adjust to next bytecode; + * the difference between the offset+destsize and BC length is + * taken care of by special relocation types. + */ + if (objfmt_coff->win64 && value->ip_rel) + intn_val += bc->len*bc->mult_int; + else if (objfmt_coff->win32) + intn_val += offset+destsize; + else + intn_minus = bc->offset; + } + + if (value->seg_of) { + /* Segment generation; zero value. */ + intn_val = 0; + intn_minus = 0; + } + + /* Generate reloc */ + reloc = yasm_xmalloc(sizeof(coff_reloc)); + addr = bc->offset + offset; + if (COFF_SET_VMA) + addr += info->addr; + reloc->reloc.addr = yasm_intnum_create_uint(addr); + reloc->reloc.sym = sym; + + if (value->curpos_rel) { + if (objfmt_coff->machine == COFF_MACHINE_I386) { + if (valsize == 32) + reloc->type = COFF_RELOC_I386_REL32; + else { + yasm_error_set(YASM_ERROR_TYPE, + N_("coff: invalid relocation size")); + return 1; + } + } else if (objfmt_coff->machine == COFF_MACHINE_AMD64) { + if (valsize != 32) { + yasm_error_set(YASM_ERROR_TYPE, + N_("coff: invalid relocation size")); + return 1; + } + if (!value->ip_rel) + reloc->type = COFF_RELOC_AMD64_REL32; + else switch (bc->len*bc->mult_int - (offset+destsize)) { + case 0: + reloc->type = COFF_RELOC_AMD64_REL32; + break; + case 1: + reloc->type = COFF_RELOC_AMD64_REL32_1; + break; + case 2: + reloc->type = COFF_RELOC_AMD64_REL32_2; + break; + case 3: + reloc->type = COFF_RELOC_AMD64_REL32_3; + break; + case 4: + reloc->type = COFF_RELOC_AMD64_REL32_4; + break; + case 5: + reloc->type = COFF_RELOC_AMD64_REL32_5; + break; + default: + yasm_error_set(YASM_ERROR_TYPE, + N_("coff: invalid relocation size")); + return 1; + } + } else + yasm_internal_error(N_("coff objfmt: unrecognized machine")); + } else if (value->seg_of) { + if (objfmt_coff->machine == COFF_MACHINE_I386) + reloc->type = COFF_RELOC_I386_SECTION; + else if (objfmt_coff->machine == COFF_MACHINE_AMD64) + reloc->type = COFF_RELOC_AMD64_SECTION; + else + yasm_internal_error(N_("coff objfmt: unrecognized machine")); + } else if (value->section_rel) { + if (objfmt_coff->machine == COFF_MACHINE_I386) + reloc->type = COFF_RELOC_I386_SECREL; + else if (objfmt_coff->machine == COFF_MACHINE_AMD64) + reloc->type = COFF_RELOC_AMD64_SECREL; + else + yasm_internal_error(N_("coff objfmt: unrecognized machine")); + } else { + if (objfmt_coff->machine == COFF_MACHINE_I386) { + if (nobase) + reloc->type = COFF_RELOC_I386_ADDR32NB; + else + reloc->type = COFF_RELOC_I386_ADDR32; + } else if (objfmt_coff->machine == COFF_MACHINE_AMD64) { + if (valsize == 32) { + if (nobase) + reloc->type = COFF_RELOC_AMD64_ADDR32NB; + else + reloc->type = COFF_RELOC_AMD64_ADDR32; + } else if (valsize == 64) + reloc->type = COFF_RELOC_AMD64_ADDR64; + else { + yasm_error_set(YASM_ERROR_TYPE, + N_("coff: invalid relocation size")); + return 1; + } + } else + yasm_internal_error(N_("coff objfmt: unrecognized machine")); + } + info->csd->nreloc++; + yasm_section_add_reloc(info->sect, (yasm_reloc *)reloc, yasm_xfree); + } + + /* Build up final integer output from intn_val, intn_minus, value->abs, + * and dist. We do all this at the end to avoid creating temporary + * intnums above (except for dist). + */ + if (intn_minus <= intn_val) + intn = yasm_intnum_create_uint(intn_val-intn_minus); + else { + intn = yasm_intnum_create_uint(intn_minus-intn_val); + yasm_intnum_calc(intn, YASM_EXPR_NEG, NULL); + } + + if (value->abs) { + yasm_intnum *intn2 = yasm_expr_get_intnum(&value->abs, 0); + if (!intn2) { + yasm_error_set(YASM_ERROR_TOO_COMPLEX, + N_("coff: relocation too complex")); + yasm_intnum_destroy(intn); + if (dist) + yasm_intnum_destroy(dist); + return 1; + } + yasm_intnum_calc(intn, YASM_EXPR_ADD, intn2); + } + + if (dist) { + yasm_intnum_calc(intn, YASM_EXPR_ADD, dist); + yasm_intnum_destroy(dist); + } + + retval = yasm_arch_intnum_tobytes(info->object->arch, intn, buf, destsize, + valsize, 0, bc, warn); + yasm_intnum_destroy(intn); + return retval; +} + +static int +coff_objfmt_output_bytecode(yasm_bytecode *bc, /*@null@*/ void *d) +{ + /*@null@*/ coff_objfmt_output_info *info = (coff_objfmt_output_info *)d; + /*@null@*/ /*@only@*/ unsigned char *bigbuf; + unsigned long size = REGULAR_OUTBUF_SIZE; + int gap; + + assert(info != NULL); + + bigbuf = yasm_bc_tobytes(bc, info->buf, &size, &gap, info, + coff_objfmt_output_value, NULL); + + /* Don't bother doing anything else if size ended up being 0. */ + if (size == 0) { + if (bigbuf) + yasm_xfree(bigbuf); + return 0; + } + + info->csd->size += size; + + /* Warn that gaps are converted to 0 and write out the 0's. */ + if (gap) { + unsigned long left; + yasm_warn_set(YASM_WARN_UNINIT_CONTENTS, + N_("uninitialized space declared in code/data section: zeroing")); + /* Write out in chunks */ + memset(info->buf, 0, REGULAR_OUTBUF_SIZE); + left = size; + while (left > REGULAR_OUTBUF_SIZE) { + fwrite(info->buf, REGULAR_OUTBUF_SIZE, 1, info->f); + left -= REGULAR_OUTBUF_SIZE; + } + fwrite(info->buf, left, 1, info->f); + } else { + /* Output buf (or bigbuf if non-NULL) to file */ + fwrite(bigbuf ? bigbuf : info->buf, (size_t)size, 1, info->f); + } + + /* If bigbuf was allocated, free it */ + if (bigbuf) + yasm_xfree(bigbuf); + + return 0; +} + +static int +coff_objfmt_output_section(yasm_section *sect, /*@null@*/ void *d) +{ + /*@null@*/ coff_objfmt_output_info *info = (coff_objfmt_output_info *)d; + /*@dependent@*/ /*@null@*/ coff_section_data *csd; + long pos; + coff_reloc *reloc; + unsigned char *localbuf; + + assert(info != NULL); + csd = yasm_section_get_data(sect, &coff_section_data_cb); + assert(csd != NULL); + + /* Add to strtab if in win32 format and name > 8 chars */ + if (info->objfmt_coff->win32) { + size_t namelen = strlen(yasm_section_get_name(sect)); + if (namelen > 8) { + csd->strtab_name = info->strtab_offset; + info->strtab_offset += (unsigned long)(namelen + 1); + } + } + + if (!csd->isdebug) + csd->addr = info->addr; + + if ((csd->flags & COFF_STYP_STD_MASK) == COFF_STYP_BSS) { + /* Don't output BSS sections. + * TODO: Check for non-reserve bytecodes? + */ + pos = 0; /* position = 0 because it's not in the file */ + csd->size = yasm_bc_next_offset(yasm_section_bcs_last(sect)); + } else { + pos = ftell(info->f); + if (pos == -1) { + yasm__fatal(N_("could not get file position on output file")); + /*@notreached@*/ + return 1; + } + + info->sect = sect; + info->csd = csd; + yasm_section_bcs_traverse(sect, info->errwarns, info, + coff_objfmt_output_bytecode); + + /* Sanity check final section size */ + if (yasm_errwarns_num_errors(info->errwarns, 0) == 0 && + csd->size != yasm_bc_next_offset(yasm_section_bcs_last(sect))) + yasm_internal_error( + N_("coff: section computed size did not match actual size")); + } + + /* Empty? Go on to next section */ + if (csd->size == 0) + return 0; + + if (!csd->isdebug) + info->addr += csd->size; + csd->scnptr = (unsigned long)pos; + + /* No relocations to output? Go on to next section */ + if (csd->nreloc == 0) + return 0; + + pos = ftell(info->f); + if (pos == -1) { + yasm__fatal(N_("could not get file position on output file")); + /*@notreached@*/ + return 1; + } + csd->relptr = (unsigned long)pos; + + /* If >=64K relocs (for Win32/64), we set a flag in the section header + * (NRELOC_OVFL) and the first relocation contains the number of relocs. + */ + if (csd->nreloc >= 64*1024 && info->objfmt_coff->win32) { + localbuf = info->buf; + YASM_WRITE_32_L(localbuf, csd->nreloc+1); /* address of relocation */ + YASM_WRITE_32_L(localbuf, 0); /* relocated symbol */ + YASM_WRITE_16_L(localbuf, 0); /* type of relocation */ + fwrite(info->buf, 10, 1, info->f); + } + + reloc = (coff_reloc *)yasm_section_relocs_first(sect); + while (reloc) { + /*@null@*/ coff_symrec_data *csymd; + localbuf = info->buf; + + csymd = yasm_symrec_get_data(reloc->reloc.sym, &coff_symrec_data_cb); + if (!csymd) + yasm_internal_error( + N_("coff: no symbol data for relocated symbol")); + + yasm_intnum_get_sized(reloc->reloc.addr, localbuf, 4, 32, 0, 0, 0); + localbuf += 4; /* address of relocation */ + YASM_WRITE_32_L(localbuf, csymd->index); /* relocated symbol */ + YASM_WRITE_16_L(localbuf, reloc->type); /* type of relocation */ + fwrite(info->buf, 10, 1, info->f); + + reloc = (coff_reloc *)yasm_section_reloc_next((yasm_reloc *)reloc); + } + + return 0; +} + +static int +coff_objfmt_output_sectstr(yasm_section *sect, /*@null@*/ void *d) +{ + /*@null@*/ coff_objfmt_output_info *info = (coff_objfmt_output_info *)d; + const char *name; + size_t len; + + /* Add to strtab if in win32 format and name > 8 chars */ + if (!info->objfmt_coff->win32) + return 0; + + name = yasm_section_get_name(sect); + len = strlen(name); + if (len > 8) + fwrite(name, len+1, 1, info->f); + return 0; +} + +static int +coff_objfmt_output_secthead(yasm_section *sect, /*@null@*/ void *d) +{ + /*@null@*/ coff_objfmt_output_info *info = (coff_objfmt_output_info *)d; + yasm_objfmt_coff *objfmt_coff; + /*@dependent@*/ /*@null@*/ coff_section_data *csd; + unsigned char *localbuf; + unsigned long align = yasm_section_get_align(sect); + + assert(info != NULL); + objfmt_coff = info->objfmt_coff; + csd = yasm_section_get_data(sect, &coff_section_data_cb); + assert(csd != NULL); + + /* Check to see if alignment is supported size */ + if (align > 8192) + align = 8192; + + /* Convert alignment into flags setting */ + csd->flags &= ~COFF_STYP_ALIGN_MASK; + while (align != 0) { + csd->flags += 1<<COFF_STYP_ALIGN_SHIFT; + align >>= 1; + } + + /* section name */ + localbuf = info->buf; + if (strlen(yasm_section_get_name(sect)) > 8) { + char namenum[30]; + sprintf(namenum, "/%ld", csd->strtab_name); + strncpy((char *)localbuf, namenum, 8); + } else + strncpy((char *)localbuf, yasm_section_get_name(sect), 8); + localbuf += 8; + if (csd->isdebug) { + YASM_WRITE_32_L(localbuf, 0); /* physical address */ + YASM_WRITE_32_L(localbuf, 0); /* virtual address */ + } else { + YASM_WRITE_32_L(localbuf, csd->addr); /* physical address */ + if (COFF_SET_VMA) + YASM_WRITE_32_L(localbuf, csd->addr);/* virtual address */ + else + YASM_WRITE_32_L(localbuf, 0); /* virtual address */ + } + YASM_WRITE_32_L(localbuf, csd->size); /* section size */ + YASM_WRITE_32_L(localbuf, csd->scnptr); /* file ptr to data */ + YASM_WRITE_32_L(localbuf, csd->relptr); /* file ptr to relocs */ + YASM_WRITE_32_L(localbuf, 0); /* file ptr to line nums */ + if (csd->nreloc >= 64*1024) { + /* Win32/64 has special handling for this case. */ + if (objfmt_coff->win32) + csd->flags |= COFF_STYP_NRELOC_OVFL; + else { + yasm_warn_set(YASM_WARN_GENERAL, + N_("too many relocations in section `%s'"), + yasm_section_get_name(sect)); + yasm_errwarn_propagate(info->errwarns, 0); + } + YASM_WRITE_16_L(localbuf, 0xFFFF); /* max out */ + } else + YASM_WRITE_16_L(localbuf, csd->nreloc); /* num of relocation entries */ + YASM_WRITE_16_L(localbuf, 0); /* num of line number entries */ + YASM_WRITE_32_L(localbuf, csd->flags); /* flags */ + fwrite(info->buf, 40, 1, info->f); + + return 0; +} + +static int +coff_objfmt_count_sym(yasm_symrec *sym, /*@null@*/ void *d) +{ + /*@null@*/ coff_objfmt_output_info *info = (coff_objfmt_output_info *)d; + yasm_sym_vis vis = yasm_symrec_get_visibility(sym); + coff_symrec_data *sym_data; + + assert(info != NULL); + + sym_data = yasm_symrec_get_data(sym, &coff_symrec_data_cb); + + if (info->all_syms || vis != YASM_SYM_LOCAL || yasm_symrec_is_abs(sym) || + (sym_data && sym_data->forcevis)) { + /* Save index in symrec data */ + if (!sym_data) + sym_data = coff_objfmt_sym_set_data(sym, COFF_SCL_NULL, 0, + COFF_SYMTAB_AUX_NONE); + /* Set storage class based on visibility if not already set */ + if (sym_data->sclass == COFF_SCL_NULL) { + if (vis & (YASM_SYM_EXTERN|YASM_SYM_GLOBAL|YASM_SYM_COMMON)) + sym_data->sclass = COFF_SCL_EXT; + else + sym_data->sclass = COFF_SCL_STAT; + } + + sym_data->index = info->indx; + + info->indx += sym_data->numaux + 1; + } + return 0; +} + +static int +coff_objfmt_output_sym(yasm_symrec *sym, /*@null@*/ void *d) +{ + /*@null@*/ coff_objfmt_output_info *info = (coff_objfmt_output_info *)d; + yasm_sym_vis vis = yasm_symrec_get_visibility(sym); + int is_abs = yasm_symrec_is_abs(sym); + /*@dependent@*/ /*@null@*/ coff_symrec_data *csymd; + yasm_valparamhead *objext_valparams = + yasm_symrec_get_objext_valparams(sym); + csymd = yasm_symrec_get_data(sym, &coff_symrec_data_cb); + + assert(info != NULL); + + /* Look for "function" flag on global syms */ + if (csymd && csymd->type == 0 && (vis & YASM_SYM_GLOBAL) != 0) { + if (objext_valparams) { + const char *id = yasm_vp_id(yasm_vps_first(objext_valparams)); + if (yasm__strcasecmp(id, "function") == 0) + csymd->type = 0x20; + } + } + + /* Don't output local syms unless outputting all syms */ + if (info->all_syms || vis != YASM_SYM_LOCAL || is_abs || + (csymd && csymd->forcevis)) { + /*@only*/ char *name; + const yasm_expr *equ_val; + const yasm_intnum *intn; + unsigned char *localbuf; + size_t len; + int aux; + unsigned long value = 0; + unsigned int scnum = 0xfffe; /* -2 = debugging symbol */ + /*@dependent@*/ /*@null@*/ yasm_section *sect; + /*@dependent@*/ /*@null@*/ yasm_bytecode *precbc; + unsigned long scnlen = 0; /* for sect auxent */ + unsigned long nreloc = 0; /* for sect auxent */ + yasm_objfmt_coff *objfmt_coff = info->objfmt_coff; + + if (is_abs) + name = yasm__xstrdup(".absolut"); + else + name = yasm_symrec_get_global_name(sym, info->object); + len = strlen(name); + + /* Get symrec's of_data (needed for storage class) */ + if (!csymd) + yasm_internal_error(N_("coff: expected sym data to be present")); + + /* Look at symrec for value/scnum/etc. */ + if (yasm_symrec_get_label(sym, &precbc)) { + if (precbc) + sect = yasm_bc_get_section(precbc); + else + sect = NULL; + /* it's a label: get value and offset. + * If there is not a section, leave as debugging symbol. + */ + if (sect) { + /*@dependent@*/ /*@null@*/ coff_section_data *csectd; + csectd = yasm_section_get_data(sect, &coff_section_data_cb); + if (csectd) { + scnum = csectd->scnum; + scnlen = csectd->size; + nreloc = csectd->nreloc; + if (COFF_SET_VMA) + value = csectd->addr; + } else + yasm_internal_error(N_("didn't understand section")); + if (precbc) + value += yasm_bc_next_offset(precbc); + } + } else if ((equ_val = yasm_symrec_get_equ(sym))) { + yasm_expr *equ_val_copy = yasm_expr_copy(equ_val); + intn = yasm_expr_get_intnum(&equ_val_copy, 1); + if (!intn) { + if (vis & YASM_SYM_GLOBAL) { + yasm_error_set(YASM_ERROR_NOT_CONSTANT, + N_("global EQU value not an integer expression")); + yasm_errwarn_propagate(info->errwarns, equ_val->line); + } + } else + value = yasm_intnum_get_uint(intn); + yasm_expr_destroy(equ_val_copy); + + scnum = 0xffff; /* -1 = absolute symbol */ + } else { + if (vis & YASM_SYM_COMMON) { + /*@dependent@*/ /*@null@*/ yasm_expr **csize_expr; + csize_expr = yasm_symrec_get_common_size(sym); + assert(csize_expr != NULL); + intn = yasm_expr_get_intnum(csize_expr, 1); + if (!intn) { + yasm_error_set(YASM_ERROR_NOT_CONSTANT, + N_("COMMON data size not an integer expression")); + yasm_errwarn_propagate(info->errwarns, + (*csize_expr)->line); + } else + value = yasm_intnum_get_uint(intn); + scnum = 0; + } + if (vis & YASM_SYM_EXTERN) + scnum = 0; + } + + localbuf = info->buf; + if (len > 8) { + YASM_WRITE_32_L(localbuf, 0); /* "zeros" field */ + YASM_WRITE_32_L(localbuf, info->strtab_offset); /* strtab offset */ + info->strtab_offset += (unsigned long)(len+1); + } else { + /* <8 chars, so no string table entry needed */ + strncpy((char *)localbuf, name, 8); + localbuf += 8; + } + YASM_WRITE_32_L(localbuf, value); /* value */ + YASM_WRITE_16_L(localbuf, scnum); /* section number */ + YASM_WRITE_16_L(localbuf, csymd->type); /* type */ + YASM_WRITE_8(localbuf, csymd->sclass); /* storage class */ + YASM_WRITE_8(localbuf, csymd->numaux); /* number of aux entries */ + fwrite(info->buf, 18, 1, info->f); + for (aux=0; aux<csymd->numaux; aux++) { + localbuf = info->buf; + memset(localbuf, 0, 18); + switch (csymd->auxtype) { + case COFF_SYMTAB_AUX_NONE: + break; + case COFF_SYMTAB_AUX_SECT: + YASM_WRITE_32_L(localbuf, scnlen); /* section length */ + YASM_WRITE_16_L(localbuf, nreloc); /* number relocs */ + YASM_WRITE_16_L(localbuf, 0); /* number line nums */ + break; + case COFF_SYMTAB_AUX_FILE: + len = strlen(csymd->aux[0].fname); + if (len > 14) { + YASM_WRITE_32_L(localbuf, 0); + YASM_WRITE_32_L(localbuf, info->strtab_offset); + info->strtab_offset += (unsigned long)(len+1); + } else + strncpy((char *)localbuf, csymd->aux[0].fname, 14); + break; + default: + yasm_internal_error( + N_("coff: unrecognized aux symtab type")); + } + fwrite(info->buf, 18, 1, info->f); + } + yasm_xfree(name); + } + return 0; +} + +static int +coff_objfmt_output_str(yasm_symrec *sym, /*@null@*/ void *d) +{ + /*@null@*/ coff_objfmt_output_info *info = (coff_objfmt_output_info *)d; + yasm_sym_vis vis = yasm_symrec_get_visibility(sym); + /*@dependent@*/ /*@null@*/ coff_symrec_data *csymd; + csymd = yasm_symrec_get_data(sym, &coff_symrec_data_cb); + + assert(info != NULL); + + /* Don't output local syms unless outputting all syms */ + if (info->all_syms || vis != YASM_SYM_LOCAL || + (csymd && csymd->forcevis)) { + /*@only@*/ char *name = yasm_symrec_get_global_name(sym, info->object); + size_t len = strlen(name); + int aux; + + if (!csymd) + yasm_internal_error(N_("coff: expected sym data to be present")); + + if (len > 8) + fwrite(name, len+1, 1, info->f); + for (aux=0; aux<csymd->numaux; aux++) { + switch (csymd->auxtype) { + case COFF_SYMTAB_AUX_FILE: + len = strlen(csymd->aux[0].fname); + if (len > 14) + fwrite(csymd->aux[0].fname, len+1, 1, info->f); + break; + default: + break; + } + } + yasm_xfree(name); + } + return 0; +} + +static void +coff_objfmt_output(yasm_object *object, FILE *f, int all_syms, + yasm_errwarns *errwarns) +{ + yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt; + coff_objfmt_output_info info; + unsigned char *localbuf; + long pos; + unsigned long symtab_pos; + unsigned long symtab_count; + unsigned int flags; + unsigned long ts; + + if (objfmt_coff->proc_frame) { + yasm_error_set_xref(objfmt_coff->proc_frame, + N_("procedure started here")); + yasm_error_set(YASM_ERROR_GENERAL, + N_("end of file in procedure frame")); + yasm_errwarn_propagate(errwarns, 0); + return; + } + + if (objfmt_coff->filesym_data->aux[0].fname) + yasm_xfree(objfmt_coff->filesym_data->aux[0].fname); + if (!object->deb_filename) { + object->deb_filename = yasm_replace_path( + objfmt_coff->objfmt.module->replace_map, objfmt_coff->objfmt.module->replace_map_size, + object->src_filename, strlen(object->src_filename)); + } + objfmt_coff->filesym_data->aux[0].fname = + yasm__xstrdup(object->deb_filename); + + /* Force all syms for win64 because they're needed for relocations. + * FIXME: Not *all* syms need to be output, only the ones needed for + * relocation. Find a way to do that someday. + */ + all_syms |= objfmt_coff->win64; + + info.strtab_offset = 4; + info.object = object; + info.objfmt_coff = objfmt_coff; + info.errwarns = errwarns; + info.f = f; + info.buf = yasm_xmalloc(REGULAR_OUTBUF_SIZE); + + /* Allocate space for headers by seeking forward */ + if (fseek(f, (long)(20+40*(objfmt_coff->parse_scnum-1)), SEEK_SET) < 0) { + yasm__fatal(N_("could not seek on output file")); + /*@notreached@*/ + return; + } + + /* Finalize symbol table (assign index to each symbol) */ + info.indx = 0; + info.all_syms = all_syms; + yasm_symtab_traverse(object->symtab, &info, coff_objfmt_count_sym); + symtab_count = info.indx; + + /* Section data/relocs */ + if (COFF_SET_VMA) { + /* If we're setting the VMA, we need to do a first section pass to + * determine each section's addr value before actually outputting + * relocations, as a relocation's section address is added into the + * addends in the generated code. + */ + info.addr = 0; + if (yasm_object_sections_traverse(object, &info, + coff_objfmt_set_section_addr)) + return; + } + info.addr = 0; + if (yasm_object_sections_traverse(object, &info, + coff_objfmt_output_section)) + return; + + /* Symbol table */ + pos = ftell(f); + if (pos == -1) { + yasm__fatal(N_("could not get file position on output file")); + /*@notreached@*/ + return; + } + symtab_pos = (unsigned long)pos; + yasm_symtab_traverse(object->symtab, &info, coff_objfmt_output_sym); + + /* String table */ + yasm_fwrite_32_l(info.strtab_offset, f); /* total length */ + yasm_object_sections_traverse(object, &info, coff_objfmt_output_sectstr); + yasm_symtab_traverse(object->symtab, &info, coff_objfmt_output_str); + + /* Write headers */ + if (fseek(f, 0, SEEK_SET) < 0) { + yasm__fatal(N_("could not seek on output file")); + /*@notreached@*/ + return; + } + + localbuf = info.buf; + YASM_WRITE_16_L(localbuf, objfmt_coff->machine); /* magic number */ + YASM_WRITE_16_L(localbuf, objfmt_coff->parse_scnum-1);/* number of sects */ + if (getenv("YASM_TEST_SUITE")) + ts = 0; + else + ts = (unsigned long)time(NULL); + YASM_WRITE_32_L(localbuf, ts); /* time/date stamp */ + YASM_WRITE_32_L(localbuf, symtab_pos); /* file ptr to symtab */ + YASM_WRITE_32_L(localbuf, symtab_count); /* number of symtabs */ + YASM_WRITE_16_L(localbuf, 0); /* size of optional header (none) */ + /* flags */ + flags = 0; + if (strcmp(yasm_dbgfmt_keyword(object->dbgfmt), "null")==0) + flags = COFF_F_LNNO; + if (!all_syms) + flags |= COFF_F_LSYMS; + if (objfmt_coff->machine != COFF_MACHINE_AMD64) + flags |= COFF_F_AR32WR; + YASM_WRITE_16_L(localbuf, flags); + fwrite(info.buf, 20, 1, f); + + yasm_object_sections_traverse(object, &info, coff_objfmt_output_secthead); + + yasm_xfree(info.buf); +} + +static void +coff_objfmt_destroy(yasm_objfmt *objfmt) +{ + yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)objfmt; + if (objfmt_coff->filesym_data->aux[0].fname) + yasm_xfree(objfmt_coff->filesym_data->aux[0].fname); + if (objfmt_coff->unwind) + yasm_win64__uwinfo_destroy(objfmt_coff->unwind); + yasm_xfree(objfmt); +} + +static yasm_section * +coff_objfmt_add_default_section(yasm_object *object) +{ + yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt; + yasm_section *retval; + coff_section_data *csd; + int isnew; + + retval = yasm_object_get_general(object, ".text", 16, 1, 0, &isnew, 0); + if (isnew) { + csd = yasm_section_get_data(retval, &coff_section_data_cb); + csd->flags = COFF_STYP_TEXT; + if (objfmt_coff->win32) + csd->flags |= COFF_STYP_EXECUTE | COFF_STYP_READ; + yasm_section_set_default(retval, 1); + } + return retval; +} + +struct coff_section_switch_data { + int isdefault; + int gasflags; + unsigned long flags; + unsigned long flags2; + /*@only@*/ /*@null@*/ yasm_intnum *align_intn; +}; + +/* GAS-style flags */ +static int +coff_helper_gasflags(void *obj, yasm_valparam *vp, unsigned long line, void *d, + /*@unused@*/ uintptr_t arg) +{ + struct coff_section_switch_data *data = + (struct coff_section_switch_data *)d; + int alloc = 0, load = 0, readonly = 0, code = 0, datasect = 0; + int shared = 0; + const char *s = yasm_vp_string(vp); + size_t i; + + if (!s) { + yasm_error_set(YASM_ERROR_VALUE, N_("non-string section attribute")); + return -1; + } + + /* For GAS, default to read/write data */ + if (data->isdefault) + data->flags = COFF_STYP_TEXT | COFF_STYP_READ | COFF_STYP_WRITE; + + for (i=0; i<strlen(s); i++) { + switch (s[i]) { + case 'a': + break; + case 'b': + alloc = 1; + load = 0; + break; + case 'n': + load = 0; + break; + case 's': + shared = 1; + /*@fallthrough@*/ + case 'd': + datasect = 1; + load = 1; + readonly = 0; + break; + case 'x': + code = 1; + load = 1; + break; + case 'r': + datasect = 1; + load = 1; + readonly = 1; + break; + case 'w': + readonly = 0; + break; + default: + yasm_warn_set(YASM_WARN_GENERAL, + N_("unrecognized section attribute: `%c'"), + s[i]); + } + } + + if (code) + data->flags = COFF_STYP_TEXT | COFF_STYP_EXECUTE | COFF_STYP_READ; + else if (datasect) + data->flags = COFF_STYP_DATA | COFF_STYP_READ | COFF_STYP_WRITE; + else if (readonly) + data->flags = COFF_STYP_DATA | COFF_STYP_READ; + else if (load) + data->flags = COFF_STYP_TEXT; + else if (alloc) + data->flags = COFF_STYP_BSS; + + if (shared) + data->flags |= COFF_STYP_SHARED; + + data->gasflags = 1; + return 0; +} + +static /*@observer@*/ /*@null@*/ yasm_section * +coff_objfmt_section_switch(yasm_object *object, yasm_valparamhead *valparams, + /*@unused@*/ /*@null@*/ + yasm_valparamhead *objext_valparams, + unsigned long line) +{ + yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt; + yasm_valparam *vp; + yasm_section *retval; + int isnew; + int iscode = 0; + int flags_override; + const char *sectname; + char *realname; + int resonly = 0; + unsigned long align = 0; + coff_section_data *csd; + + struct coff_section_switch_data data; + + static const yasm_dir_help help[] = { + { "code", 0, yasm_dir_helper_flag_set, + offsetof(struct coff_section_switch_data, flags), + COFF_STYP_TEXT | COFF_STYP_EXECUTE | COFF_STYP_READ }, + { "text", 0, yasm_dir_helper_flag_set, + offsetof(struct coff_section_switch_data, flags), + COFF_STYP_TEXT | COFF_STYP_EXECUTE | COFF_STYP_READ }, + { "data", 0, yasm_dir_helper_flag_set, + offsetof(struct coff_section_switch_data, flags), + COFF_STYP_DATA | COFF_STYP_READ | COFF_STYP_WRITE }, + { "rdata", 0, yasm_dir_helper_flag_set, + offsetof(struct coff_section_switch_data, flags), + COFF_STYP_DATA | COFF_STYP_READ }, + { "bss", 0, yasm_dir_helper_flag_set, + offsetof(struct coff_section_switch_data, flags), + COFF_STYP_BSS | COFF_STYP_READ | COFF_STYP_WRITE }, + { "info", 0, yasm_dir_helper_flag_set, + offsetof(struct coff_section_switch_data, flags), + COFF_STYP_INFO | COFF_STYP_DISCARD | COFF_STYP_READ }, + { "gasflags", 1, coff_helper_gasflags, 0, 0 }, + /* Win32 only below this point */ + { "discard", 0, yasm_dir_helper_flag_or, + offsetof(struct coff_section_switch_data, flags), COFF_STYP_DISCARD}, + { "nodiscard", 0, yasm_dir_helper_flag_and, + offsetof(struct coff_section_switch_data, flags), COFF_STYP_DISCARD}, + { "cache", 0, yasm_dir_helper_flag_and, + offsetof(struct coff_section_switch_data, flags), COFF_STYP_NOCACHE}, + { "nocache", 0, yasm_dir_helper_flag_or, + offsetof(struct coff_section_switch_data, flags), COFF_STYP_NOCACHE}, + { "page", 0, yasm_dir_helper_flag_and, + offsetof(struct coff_section_switch_data, flags), COFF_STYP_NOPAGE }, + { "nopage", 0, yasm_dir_helper_flag_or, + offsetof(struct coff_section_switch_data, flags), COFF_STYP_NOPAGE }, + { "share", 0, yasm_dir_helper_flag_or, + offsetof(struct coff_section_switch_data, flags), COFF_STYP_SHARED }, + { "noshare", 0, yasm_dir_helper_flag_and, + offsetof(struct coff_section_switch_data, flags), COFF_STYP_SHARED }, + { "execute", 0, yasm_dir_helper_flag_or, + offsetof(struct coff_section_switch_data, flags), COFF_STYP_EXECUTE}, + { "noexecute", 0, yasm_dir_helper_flag_and, + offsetof(struct coff_section_switch_data, flags), COFF_STYP_EXECUTE}, + { "read", 0, yasm_dir_helper_flag_or, + offsetof(struct coff_section_switch_data, flags), COFF_STYP_READ }, + { "noread", 0, yasm_dir_helper_flag_and, + offsetof(struct coff_section_switch_data, flags), COFF_STYP_READ }, + { "write", 0, yasm_dir_helper_flag_or, + offsetof(struct coff_section_switch_data, flags), COFF_STYP_WRITE }, + { "nowrite", 0, yasm_dir_helper_flag_and, + offsetof(struct coff_section_switch_data, flags), COFF_STYP_WRITE }, + { "base", 0, yasm_dir_helper_flag_and, + offsetof(struct coff_section_switch_data, flags2), COFF_FLAG_NOBASE}, + { "nobase", 0, yasm_dir_helper_flag_or, + offsetof(struct coff_section_switch_data, flags2), COFF_FLAG_NOBASE}, + { "align", 1, yasm_dir_helper_intn, + offsetof(struct coff_section_switch_data, align_intn), 0 } + }; + + vp = yasm_vps_first(valparams); + sectname = yasm_vp_string(vp); + if (!sectname) + return NULL; + vp = yasm_vps_next(vp); + + data.isdefault = 0; + data.gasflags = 0; + data.flags = 0; + data.flags2 = 0; + data.align_intn = NULL; + + if (strcmp(sectname, ".data") == 0) { + data.flags = COFF_STYP_DATA | COFF_STYP_READ | COFF_STYP_WRITE; + if (objfmt_coff->win32) { + if (objfmt_coff->machine == COFF_MACHINE_AMD64) + align = 16; + else + align = 4; + } + } else if (strcmp(sectname, ".bss") == 0) { + data.flags = COFF_STYP_BSS | COFF_STYP_READ | COFF_STYP_WRITE; + if (objfmt_coff->win32) { + if (objfmt_coff->machine == COFF_MACHINE_AMD64) + align = 16; + else + align = 4; + } + resonly = 1; + } else if (strcmp(sectname, ".text") == 0) { + data.flags = COFF_STYP_TEXT | COFF_STYP_EXECUTE | COFF_STYP_READ; + if (objfmt_coff->win32) + align = 16; + } else if (strcmp(sectname, ".rdata") == 0 + || strncmp(sectname, ".rodata", 7) == 0 + || strncmp(sectname, ".rdata$", 7) == 0) { + data.flags = COFF_STYP_DATA | COFF_STYP_READ; + if (objfmt_coff->win32) + align = 8; + else + yasm_warn_set(YASM_WARN_GENERAL, + N_("Standard COFF does not support read-only data sections")); + } else if (strcmp(sectname, ".drectve") == 0) { + data.flags = COFF_STYP_INFO; + if (objfmt_coff->win32) + data.flags |= COFF_STYP_DISCARD | COFF_STYP_READ; + } else if (objfmt_coff->win64 && strcmp(sectname, ".pdata") == 0) { + data.flags = COFF_STYP_DATA | COFF_STYP_READ; + align = 4; + data.flags2 = COFF_FLAG_NOBASE; + } else if (objfmt_coff->win64 && strcmp(sectname, ".xdata") == 0) { + data.flags = COFF_STYP_DATA | COFF_STYP_READ; + align = 8; + data.flags2 = COFF_FLAG_NOBASE; + } else if (objfmt_coff->win32 && strcmp(sectname, ".sxdata") == 0) { + data.flags = COFF_STYP_INFO; + } else if (strcmp(sectname, ".comment") == 0) { + data.flags = COFF_STYP_INFO | COFF_STYP_DISCARD | COFF_STYP_READ; + } else if (yasm__strncasecmp(sectname, ".debug", 6)==0) { + data.flags = COFF_STYP_DATA | COFF_STYP_DISCARD | COFF_STYP_READ; + align = 1; + } else { + /* Default to code, but set a flag so if we get gasflags we can + * change it (NASM and GAS have different defaults). + */ + data.isdefault = 1; + data.flags = COFF_STYP_TEXT | COFF_STYP_EXECUTE | COFF_STYP_READ; + } + + flags_override = yasm_dir_helper(object, vp, line, help, + objfmt_coff->win32 ? NELEMS(help) : 7, + &data, yasm_dir_helper_valparam_warn); + if (flags_override < 0) + return NULL; /* error occurred */ + + if (data.flags & COFF_STYP_EXECUTE) + iscode = 1; + + if (!objfmt_coff->win32) + data.flags &= ~COFF_STYP_WIN32_MASK; + + if (data.align_intn) { + align = yasm_intnum_get_uint(data.align_intn); + yasm_intnum_destroy(data.align_intn); + + /* Alignments must be a power of two. */ + if (!is_exp2(align)) { + yasm_error_set(YASM_ERROR_VALUE, + N_("argument to `%s' is not a power of two"), + "align"); + return NULL; + } + + /* Check to see if alignment is supported size */ + if (align > 8192) { + yasm_error_set(YASM_ERROR_VALUE, + N_("Win32 does not support alignments > 8192")); + return NULL; + } + } + + realname = yasm__xstrdup(sectname); + if (strlen(sectname) > 8 && !objfmt_coff->win32) { + /* win32 format supports >8 character section names in object + * files via "/nnnn" (where nnnn is decimal offset into string table), + * so only warn for regular COFF. + */ + yasm_warn_set(YASM_WARN_GENERAL, + N_("COFF section names limited to 8 characters: truncating")); + realname[8] = '\0'; + } + + retval = yasm_object_get_general(object, realname, align, iscode, + resonly, &isnew, line); + yasm_xfree(realname); + + csd = yasm_section_get_data(retval, &coff_section_data_cb); + + if (isnew || yasm_section_is_default(retval)) { + yasm_section_set_default(retval, 0); + csd->flags = data.flags; + csd->flags2 = data.flags2; + yasm_section_set_align(retval, align, line); + } else if (flags_override && !data.gasflags) + yasm_warn_set(YASM_WARN_GENERAL, + N_("section flags ignored on section redeclaration")); + return retval; +} + +static /*@observer@*/ /*@null@*/ yasm_symrec * +coff_objfmt_get_special_sym(yasm_object *object, const char *name, + const char *parser) +{ + return NULL; +} + +static /*@observer@*/ /*@null@*/ yasm_symrec * +win64_objfmt_get_special_sym(yasm_object *object, const char *name, + const char *parser) +{ + if (yasm__strcasecmp(name, "imagebase") == 0) { + yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt; + return objfmt_coff->ssym_imagebase; + } + return NULL; +} + +static void +coff_section_data_destroy(void *data) +{ + yasm_xfree(data); +} + +static void +coff_section_data_print(void *data, FILE *f, int indent_level) +{ + coff_section_data *csd = (coff_section_data *)data; + + fprintf(f, "%*ssym=\n", indent_level, ""); + yasm_symrec_print(csd->sym, f, indent_level+1); + fprintf(f, "%*sscnum=%d\n", indent_level, "", csd->scnum); + fprintf(f, "%*sflags=", indent_level, ""); + switch (csd->flags & COFF_STYP_STD_MASK) { + case COFF_STYP_TEXT: + fprintf(f, "TEXT"); + break; + case COFF_STYP_DATA: + fprintf(f, "DATA"); + break; + case COFF_STYP_BSS: + fprintf(f, "BSS"); + break; + default: + fprintf(f, "UNKNOWN"); + break; + } + fprintf(f, "\n%*saddr=0x%lx\n", indent_level, "", csd->addr); + fprintf(f, "%*sscnptr=0x%lx\n", indent_level, "", csd->scnptr); + fprintf(f, "%*ssize=%ld\n", indent_level, "", csd->size); + fprintf(f, "%*srelptr=0x%lx\n", indent_level, "", csd->relptr); + fprintf(f, "%*snreloc=%ld\n", indent_level, "", csd->nreloc); + fprintf(f, "%*srelocs:\n", indent_level, ""); +} + +static void +coff_symrec_data_destroy(void *data) +{ + yasm_xfree(data); +} + +static void +coff_symrec_data_print(void *data, FILE *f, int indent_level) +{ + coff_symrec_data *csd = (coff_symrec_data *)data; + + fprintf(f, "%*ssymtab index=%lu\n", indent_level, "", csd->index); + fprintf(f, "%*ssclass=%d\n", indent_level, "", csd->sclass); +} + +static void +dir_export(yasm_object *object, yasm_valparamhead *valparams, + yasm_valparamhead *objext_valparams, unsigned long line) +{ + yasm_valparam *vp; + /*@null@*/ const char *symname; + int isnew; + yasm_section *sect; + yasm_datavalhead dvs; + + /* Reference exported symbol (to generate error if not declared) */ + vp = yasm_vps_first(valparams); + symname = yasm_vp_id(vp); + if (symname) + yasm_symtab_use(object->symtab, symname, line); + else { + yasm_error_set(YASM_ERROR_SYNTAX, + N_("argument to EXPORT must be symbol name")); + return; + } + + /* Add to end of linker directives */ + sect = yasm_object_get_general(object, ".drectve", 0, 0, 0, &isnew, line); + + /* Initialize directive section if needed */ + if (isnew) { + coff_section_data *csd; + csd = yasm_section_get_data(sect, &coff_section_data_cb); + csd->flags = COFF_STYP_INFO | COFF_STYP_DISCARD | COFF_STYP_READ; + } + + /* Add text as data bytecode */ + yasm_dvs_initialize(&dvs); + yasm_dvs_append(&dvs, yasm_dv_create_string(yasm__xstrdup("-export:"), + strlen("-export:"))); + yasm_dvs_append(&dvs, yasm_dv_create_string(yasm__xstrdup(symname), + strlen(symname))); + yasm_dvs_append(&dvs, yasm_dv_create_string(yasm__xstrdup(" "), 1)); + yasm_section_bcs_append(sect, yasm_bc_create_data(&dvs, 1, 0, NULL, line)); +} + +static void +dir_safeseh(yasm_object *object, yasm_valparamhead *valparams, + yasm_valparamhead *objext_valparams, unsigned long line) +{ + yasm_valparam *vp; + /*@null@*/ const char *symname; + yasm_symrec *sym; + int isnew; + yasm_section *sect; + + /* Reference symbol (to generate error if not declared). + * Also, symbol must be externally visible, so force it. + */ + vp = yasm_vps_first(valparams); + symname = yasm_vp_id(vp); + if (symname) { + coff_symrec_data *sym_data; + sym = yasm_symtab_use(object->symtab, symname, line); + sym_data = yasm_symrec_get_data(sym, &coff_symrec_data_cb); + if (!sym_data) { + sym_data = coff_objfmt_sym_set_data(sym, COFF_SCL_NULL, 0, + COFF_SYMTAB_AUX_NONE); + } + sym_data->forcevis = 1; + sym_data->type = 0x20; /* function */ + } else { + yasm_error_set(YASM_ERROR_SYNTAX, + N_("argument to SAFESEH must be symbol name")); + return; + } + + /* + * Add symbol number to end of .sxdata section. + */ + + sect = yasm_object_get_general(object, ".sxdata", 0, 0, 0, &isnew, line); + + /* Initialize sxdata section if needed */ + if (isnew) { + coff_section_data *csd; + csd = yasm_section_get_data(sect, &coff_section_data_cb); + csd->flags = COFF_STYP_INFO; + } + + /* Add as sxdata bytecode */ + yasm_section_bcs_append(sect, + yasm_bc_create_common(&win32_sxdata_bc_callback, + sym, line)); +} + +static void +win32_sxdata_bc_destroy(void *contents) +{ + /* Contents is just the symbol pointer, so no need to delete */ +} + +static void +win32_sxdata_bc_print(const void *contents, FILE *f, int indent_level) +{ + /* TODO */ +} + +static int +win32_sxdata_bc_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span, + void *add_span_data) +{ + bc->len += 4; + return 0; +} + +static int +win32_sxdata_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp, + unsigned char *bufstart, void *d, + yasm_output_value_func output_value, + yasm_output_reloc_func output_reloc) +{ + yasm_symrec *sym = (yasm_symrec *)bc->contents; + unsigned char *buf = *bufp; + coff_symrec_data *csymd; + + csymd = yasm_symrec_get_data(sym, &coff_symrec_data_cb); + if (!csymd) + yasm_internal_error(N_("coff: no symbol data for SAFESEH symbol")); + + YASM_WRITE_32_L(buf, csymd->index); + + *bufp = buf; + return 0; +} + +static void +dir_ident(yasm_object *object, yasm_valparamhead *valparams, + yasm_valparamhead *objext_valparams, unsigned long line) +{ + yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt; + yasm_valparamhead sect_vps; + yasm_datavalhead dvs; + yasm_section *comment; + const char *sectname; + yasm_valparam *vp, *vp2; + + /* Accept, but do nothing with empty ident */ + if (!valparams) + return; + + vp = yasm_vps_first(valparams); + if (!vp) + return; + + if (objfmt_coff->win32) { + /* Put ident data into .comment section for COFF, or .rdata$zzz + * to be compatible with the GNU linker, which doesn't ignore + * .comment (see binutils/gas/config/obj-coff.c:476-502). + */ + sectname = ".rdata$zzz"; + } else { + sectname = ".comment"; + } + yasm_vps_initialize(§_vps); + vp2 = yasm_vp_create_id(NULL, yasm__xstrdup(sectname), '\0'); + yasm_vps_append(§_vps, vp2); + comment = coff_objfmt_section_switch(object, §_vps, NULL, line); + yasm_vps_delete(§_vps); + + /* To match GAS output, if the comment section is empty, put an + * initial 0 byte in the section. + */ + if (yasm_section_bcs_first(comment) == yasm_section_bcs_last(comment)) { + yasm_dvs_initialize(&dvs); + yasm_dvs_append(&dvs, yasm_dv_create_expr( + yasm_expr_create_ident(yasm_expr_int(yasm_intnum_create_uint(0)), + line))); + yasm_section_bcs_append(comment, + yasm_bc_create_data(&dvs, 1, 0, object->arch, line)); + } + + yasm_dvs_initialize(&dvs); + do { + const char *s = yasm_vp_string(vp); + if (!s) { + yasm_error_set(YASM_ERROR_VALUE, + N_(".comment requires string parameters")); + yasm_dvs_delete(&dvs); + return; + } + yasm_dvs_append(&dvs, + yasm_dv_create_string(yasm__xstrdup(s), strlen(s))); + } while ((vp = yasm_vps_next(vp))); + + yasm_section_bcs_append(comment, + yasm_bc_create_data(&dvs, 1, 1, object->arch, line)); +} + +static void +dir_secrel32(yasm_object *object, yasm_valparamhead *valparams, + yasm_valparamhead *objext_valparams, unsigned long line) +{ + yasm_datavalhead dvs; + yasm_valparam *vp; + + if (!object->cur_section) { + yasm_error_set(YASM_ERROR_SYNTAX, + N_(".secrel32 can only be used inside of a section")); + return; + } + + vp = yasm_vps_first(valparams); + yasm_dvs_initialize(&dvs); + do { + yasm_expr *e = yasm_vp_expr(vp, object->symtab, line); + yasm_dataval *dv; + if (!e) { + yasm_error_set(YASM_ERROR_VALUE, + N_(".secrel32 requires expressions")); + yasm_dvs_delete(&dvs); + return; + } + dv = yasm_dv_create_expr(e); + yasm_dv_get_value(dv)->section_rel = 1; + yasm_dvs_append(&dvs, dv); + } while ((vp = yasm_vps_next(vp))); + + yasm_section_bcs_append(object->cur_section, + yasm_bc_create_data(&dvs, 4, 0, object->arch, line)); +} + +static void +dir_def(yasm_object *object, yasm_valparamhead *valparams, + yasm_valparamhead *objext_valparams, unsigned long line) +{ + yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt; + yasm_valparam *vp; + const char *symname; + yasm_symrec *sym; + coff_symrec_data *sym_data; + + if (objfmt_coff->def_sym) { + yasm_warn_set(YASM_WARN_GENERAL, + N_(".def pseudo-op used inside of .def/.endef; ignored")); + return; + } + + vp = yasm_vps_first(valparams); + symname = yasm_vp_id(vp); + if (!symname) { + yasm_error_set(YASM_ERROR_SYNTAX, + N_("argument to SAFESEH must be symbol name")); + return; + } + + sym = yasm_symtab_use(object->symtab, symname, line); + sym_data = yasm_symrec_get_data(sym, &coff_symrec_data_cb); + if (!sym_data) { + sym_data = coff_objfmt_sym_set_data(sym, COFF_SCL_NULL, 0, + COFF_SYMTAB_AUX_NONE); + } + objfmt_coff->def_sym = sym_data; +} + +static void +dir_scl(yasm_object *object, yasm_valparamhead *valparams, + yasm_valparamhead *objext_valparams, unsigned long line) +{ + yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt; + yasm_intnum *intn = NULL; + + if (!objfmt_coff->def_sym) { + yasm_warn_set(YASM_WARN_GENERAL, + N_("%s pseudo-op used outside of .def/.endef; ignored"), + ".scl"); + return; + } + + if (yasm_dir_helper_intn(object, yasm_vps_first(valparams), line, + &intn, 0) < 0) + return; + if (!intn) + return; + objfmt_coff->def_sym->sclass = yasm_intnum_get_uint(intn); + yasm_intnum_destroy(intn); +} + +static void +dir_type(yasm_object *object, yasm_valparamhead *valparams, + yasm_valparamhead *objext_valparams, unsigned long line) +{ + yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt; + yasm_intnum *intn = NULL; + + if (!objfmt_coff->def_sym) { + yasm_warn_set(YASM_WARN_GENERAL, + N_("%s pseudo-op used outside of .def/.endef; ignored"), + ".type"); + return; + } + + if (yasm_dir_helper_intn(object, yasm_vps_first(valparams), line, + &intn, 0) < 0) + return; + if (!intn) + return; + objfmt_coff->def_sym->type = yasm_intnum_get_uint(intn); + yasm_intnum_destroy(intn); +} + +static void +dir_endef(yasm_object *object, yasm_valparamhead *valparams, + yasm_valparamhead *objext_valparams, unsigned long line) +{ + yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt; + if (!objfmt_coff->def_sym) { + yasm_warn_set(YASM_WARN_GENERAL, + N_(".endef pseudo-op used before .def; ignored")); + return; + } + objfmt_coff->def_sym = NULL; +} + +static void +dir_proc_frame(yasm_object *object, /*@null@*/ yasm_valparamhead *valparams, + yasm_valparamhead *objext_valparams, unsigned long line) +{ + yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt; + yasm_valparam *vp = yasm_vps_first(valparams); + const char *name = yasm_vp_id(vp); + + if (objfmt_coff->proc_frame) { + yasm_error_set_xref(objfmt_coff->proc_frame, + N_("previous procedure started here")); + yasm_error_set(YASM_ERROR_SYNTAX, + N_("nested procedures not supported (didn't use [ENDPROC_FRAME]?)")); + return; + } + objfmt_coff->proc_frame = line; + objfmt_coff->done_prolog = 0; + objfmt_coff->unwind = yasm_win64__uwinfo_create(); + objfmt_coff->unwind->proc = yasm_symtab_use(object->symtab, name, line); + + /* Optional error handler */ + vp = yasm_vps_next(vp); + if (!vp || !(name = yasm_vp_id(vp))) + return; + objfmt_coff->unwind->ehandler = + yasm_symtab_use(object->symtab, name, line); +} + +static int +procframe_checkstate(yasm_objfmt_coff *objfmt_coff, const char *dirname) +{ + if (!objfmt_coff->proc_frame) { + yasm_error_set(YASM_ERROR_SYNTAX, + N_("[%s] without preceding [PROC_FRAME]"), dirname); + return 0; + } + if (objfmt_coff->done_prolog) { + yasm_error_set_xref(objfmt_coff->done_prolog, + N_("prologue ended here")); + yasm_error_set(YASM_ERROR_SYNTAX, N_("[%s] after end of prologue"), + dirname); + return 0; + } + if (!objfmt_coff->unwind) + yasm_internal_error(N_("unwind info not present")); + return 1; +} + +/* Get current assembly position. + * XXX: There should be a better way to do this. + */ +static yasm_symrec * +get_curpos(yasm_object *object, const char *dirname, unsigned long line) +{ + if (!object->cur_section) { + yasm_error_set(YASM_ERROR_SYNTAX, + N_("[%s] can only be used inside of a section"), + dirname); + return NULL; + } + return yasm_symtab_define_curpos(object->symtab, "$", + yasm_section_bcs_last(object->cur_section), line); +} + +static void +dir_pushreg(yasm_object *object, yasm_valparamhead *valparams, + yasm_valparamhead *objext_valparams, unsigned long line) +{ + yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt; + yasm_valparam *vp = yasm_vps_first(valparams); + coff_unwind_code *code; + const uintptr_t *reg; + + if (!procframe_checkstate(objfmt_coff, "PUSHREG")) + return; + + if (vp->type != YASM_PARAM_EXPR || + !(reg = yasm_expr_get_reg(&vp->param.e, 0))) { + yasm_error_set(YASM_ERROR_SYNTAX, + N_("[%s] requires a register as the first parameter"), + "PUSHREG"); + return; + } + + /* Generate a PUSH_NONVOL unwind code. */ + code = yasm_xmalloc(sizeof(coff_unwind_code)); + code->proc = objfmt_coff->unwind->proc; + code->loc = get_curpos(object, "PUSHREG", line); + code->opcode = UWOP_PUSH_NONVOL; + code->info = (unsigned int)(*reg & 0xF); + yasm_value_initialize(&code->off, NULL, 0); + SLIST_INSERT_HEAD(&objfmt_coff->unwind->codes, code, link); +} + +static void +dir_setframe(yasm_object *object, yasm_valparamhead *valparams, + yasm_valparamhead *objext_valparams, unsigned long line) +{ + yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt; + yasm_valparam *vp = yasm_vps_first(valparams); + coff_unwind_code *code; + const uintptr_t *reg; + yasm_expr *off = NULL; + + if (!procframe_checkstate(objfmt_coff, "SETFRAME")) + return; + + if (vp->type != YASM_PARAM_EXPR || + !(reg = yasm_expr_get_reg(&vp->param.e, 0))) { + yasm_error_set(YASM_ERROR_SYNTAX, + N_("[%s] requires a register as the first parameter"), + "SETFRAME"); + return; + } + + vp = yasm_vps_next(vp); + if (vp) + off = yasm_vp_expr(vp, object->symtab, line); + + /* Set the frame fields in the unwind info */ + objfmt_coff->unwind->framereg = (unsigned long)(*reg); + yasm_value_initialize(&objfmt_coff->unwind->frameoff, off, 8); + + /* Generate a SET_FPREG unwind code */ + code = yasm_xmalloc(sizeof(coff_unwind_code)); + code->proc = objfmt_coff->unwind->proc; + code->loc = get_curpos(object, "SETFRAME", line); + code->opcode = UWOP_SET_FPREG; + code->info = (unsigned int)(*reg & 0xF); + yasm_value_initialize(&code->off, off ? yasm_expr_copy(off) : NULL, 8); + SLIST_INSERT_HEAD(&objfmt_coff->unwind->codes, code, link); +} + +static void +dir_allocstack(yasm_object *object, yasm_valparamhead *valparams, + yasm_valparamhead *objext_valparams, unsigned long line) +{ + yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt; + yasm_valparam *vp = yasm_vps_first(valparams); + /*@null@*/ /*@only@*/ yasm_expr *size; + coff_unwind_code *code; + + if (!procframe_checkstate(objfmt_coff, "ALLOCSTACK")) + return; + + size = yasm_vp_expr(vp, object->symtab, line); + if (!size) { + yasm_error_set(YASM_ERROR_SYNTAX, N_("[%s] requires a size"), + "ALLOCSTACK"); + return; + } + + /* Generate an ALLOC_SMALL unwind code; this will get enlarged to an + * ALLOC_LARGE if necessary. + */ + code = yasm_xmalloc(sizeof(coff_unwind_code)); + code->proc = objfmt_coff->unwind->proc; + code->loc = get_curpos(object, "ALLOCSTACK", line); + code->opcode = UWOP_ALLOC_SMALL; + code->info = 0; + yasm_value_initialize(&code->off, size, 7); + SLIST_INSERT_HEAD(&objfmt_coff->unwind->codes, code, link); +} + +static void +dir_save_common(yasm_object *object, yasm_valparamhead *valparams, + unsigned long line, const char *name, int op) +{ + yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt; + yasm_valparam *vp = yasm_vps_first(valparams); + coff_unwind_code *code; + const uintptr_t *reg; + /*@only@*/ /*@null@*/ yasm_expr *offset; + + if (!procframe_checkstate(objfmt_coff, name)) + return; + + if (vp->type != YASM_PARAM_EXPR || + !(reg = yasm_expr_get_reg(&vp->param.e, 0))) { + yasm_error_set(YASM_ERROR_SYNTAX, + N_("[%s] requires a register as the first parameter"), + name); + return; + } + + vp = yasm_vps_next(vp); + offset = yasm_vp_expr(vp, object->symtab, line); + if (!offset) { + yasm_error_set(YASM_ERROR_SYNTAX, + N_("[%s] requires an offset as the second parameter"), + name); + return; + } + + /* Generate a SAVE_XXX unwind code; this will get enlarged to a + * SAVE_XXX_FAR if necessary. + */ + code = yasm_xmalloc(sizeof(coff_unwind_code)); + code->proc = objfmt_coff->unwind->proc; + code->loc = get_curpos(object, name, line); + code->opcode = op; + code->info = (unsigned int)(*reg & 0xF); + yasm_value_initialize(&code->off, offset, 16); + SLIST_INSERT_HEAD(&objfmt_coff->unwind->codes, code, link); +} + +static void +dir_savereg(yasm_object *object, yasm_valparamhead *valparams, + yasm_valparamhead *objext_valparams, unsigned long line) +{ + dir_save_common(object, valparams, line, "SAVEREG", UWOP_SAVE_NONVOL); +} + +static void +dir_savexmm128(yasm_object *object, yasm_valparamhead *valparams, + yasm_valparamhead *objext_valparams, unsigned long line) +{ + dir_save_common(object, valparams, line, "SAVEXMM128", UWOP_SAVE_XMM128); +} + +static void +dir_pushframe(yasm_object *object, /*@null@*/ yasm_valparamhead *valparams, + yasm_valparamhead *objext_valparams, unsigned long line) +{ + yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt; + yasm_valparam *vp = yasm_vps_first(valparams); + coff_unwind_code *code; + + if (!procframe_checkstate(objfmt_coff, "PUSHFRAME")) + return; + + /* Generate a PUSH_MACHFRAME unwind code. If there's any parameter, + * we set info to 1. Otherwise we set info to 0. + */ + code = yasm_xmalloc(sizeof(coff_unwind_code)); + code->proc = objfmt_coff->unwind->proc; + code->loc = get_curpos(object, "PUSHFRAME", line); + code->opcode = UWOP_PUSH_MACHFRAME; + code->info = vp != NULL; + yasm_value_initialize(&code->off, NULL, 0); + SLIST_INSERT_HEAD(&objfmt_coff->unwind->codes, code, link); +} + +static void +dir_endprolog(yasm_object *object, /*@null@*/ yasm_valparamhead *valparams, + yasm_valparamhead *objext_valparams, unsigned long line) +{ + yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt; + if (!procframe_checkstate(objfmt_coff, "ENDPROLOG")) + return; + objfmt_coff->done_prolog = line; + + objfmt_coff->unwind->prolog = get_curpos(object, "ENDPROLOG", line); +} + +static void +dir_endproc_frame(yasm_object *object, /*@null@*/ yasm_valparamhead *valparams, + yasm_valparamhead *objext_valparams, unsigned long line) +{ + yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt; + yasm_section *sect; + coff_section_data *csd; + yasm_datavalhead dvs; + int isnew; + /*@dependent@*/ yasm_symrec *curpos, *unwindpos, *proc_sym, *xdata_sym; + + if (!objfmt_coff->proc_frame) { + yasm_error_set(YASM_ERROR_SYNTAX, + N_("[%s] without preceding [PROC_FRAME]"), + "ENDPROC_FRAME"); + return; + } + if (!objfmt_coff->done_prolog) { + yasm_error_set_xref(objfmt_coff->proc_frame, + N_("procedure started here")); + yasm_error_set(YASM_ERROR_SYNTAX, + N_("ended procedure without ending prologue"), + "ENDPROC_FRAME"); + objfmt_coff->proc_frame = 0; + yasm_win64__uwinfo_destroy(objfmt_coff->unwind); + objfmt_coff->unwind = NULL; + return; + } + if (!objfmt_coff->unwind) + yasm_internal_error(N_("unwind info not present")); + + proc_sym = objfmt_coff->unwind->proc; + + curpos = get_curpos(object, "ENDPROC_FRAME", line); + + /* + * Add unwind info to end of .xdata section. + */ + + sect = yasm_object_get_general(object, ".xdata", 0, 0, 0, &isnew, line); + + /* Initialize xdata section if needed */ + if (isnew) { + csd = yasm_section_get_data(sect, &coff_section_data_cb); + csd->flags = COFF_STYP_DATA | COFF_STYP_READ; + yasm_section_set_align(sect, 8, line); + } + + /* Get current position in .xdata section */ + unwindpos = yasm_symtab_define_curpos(object->symtab, "$", + yasm_section_bcs_last(sect), line); + /* Get symbol for .xdata as we'll want to reference it with WRT */ + csd = yasm_section_get_data(sect, &coff_section_data_cb); + xdata_sym = csd->sym; + + /* Add unwind info. Use line number of start of procedure. */ + yasm_win64__unwind_generate(sect, objfmt_coff->unwind, + objfmt_coff->proc_frame); + objfmt_coff->unwind = NULL; /* generate keeps the unwind pointer */ + + /* + * Add function lookup to end of .pdata section. + */ + + sect = yasm_object_get_general(object, ".pdata", 0, 0, 0, &isnew, line); + + /* Initialize pdata section if needed */ + if (isnew) { + csd = yasm_section_get_data(sect, &coff_section_data_cb); + csd->flags = COFF_STYP_DATA | COFF_STYP_READ; + csd->flags2 = COFF_FLAG_NOBASE; + yasm_section_set_align(sect, 4, line); + } + + /* Add function structure as data bytecode */ + yasm_dvs_initialize(&dvs); + yasm_dvs_append(&dvs, yasm_dv_create_expr( + yasm_expr_create_ident(yasm_expr_sym(proc_sym), line))); + yasm_dvs_append(&dvs, yasm_dv_create_expr( + yasm_expr_create(YASM_EXPR_WRT, yasm_expr_sym(curpos), + yasm_expr_sym(proc_sym), line))); + yasm_dvs_append(&dvs, yasm_dv_create_expr( + yasm_expr_create(YASM_EXPR_WRT, yasm_expr_sym(unwindpos), + yasm_expr_sym(xdata_sym), line))); + yasm_section_bcs_append(sect, yasm_bc_create_data(&dvs, 4, 0, NULL, line)); + + objfmt_coff->proc_frame = 0; + objfmt_coff->done_prolog = 0; +} + +/* Define valid debug formats to use with this object format */ +static const char *coff_objfmt_dbgfmt_keywords[] = { + "null", + "dwarf2", + NULL +}; + +static const yasm_directive coff_objfmt_directives[] = { + { ".ident", "gas", dir_ident, YASM_DIR_ANY }, + { "ident", "nasm", dir_ident, YASM_DIR_ANY }, + { ".def", "gas", dir_def, YASM_DIR_ID_REQUIRED }, + { ".endef", "gas", dir_endef, YASM_DIR_ANY }, + { ".scl", "gas", dir_scl, YASM_DIR_ARG_REQUIRED }, + { ".type", "gas", dir_type, YASM_DIR_ARG_REQUIRED }, + { ".secrel32", "gas", dir_secrel32, YASM_DIR_ARG_REQUIRED }, + { NULL, NULL, NULL, 0 } +}; + +/* Define objfmt structure -- see objfmt.h for details */ +yasm_objfmt_module yasm_coff_LTX_objfmt = { + "COFF (DJGPP)", + "coff", + "o", + 32, + 0, + coff_objfmt_dbgfmt_keywords, + "null", + coff_objfmt_directives, + NULL, /* no standard macros */ + coff_objfmt_create, + coff_objfmt_output, + coff_objfmt_destroy, + coff_objfmt_add_default_section, + coff_objfmt_init_new_section, + coff_objfmt_section_switch, + coff_objfmt_get_special_sym +}; + +/* Define valid debug formats to use with this object format */ +static const char *winXX_objfmt_dbgfmt_keywords[] = { + "null", + "dwarf2", + "cv8", + NULL +}; + +static const yasm_directive win32_objfmt_directives[] = { + { ".ident", "gas", dir_ident, YASM_DIR_ANY }, + { "ident", "nasm", dir_ident, YASM_DIR_ANY }, + { ".def", "gas", dir_def, YASM_DIR_ID_REQUIRED }, + { ".endef", "gas", dir_endef, YASM_DIR_ANY }, + { ".scl", "gas", dir_scl, YASM_DIR_ARG_REQUIRED }, + { ".type", "gas", dir_type, YASM_DIR_ARG_REQUIRED }, + { ".secrel32", "gas", dir_secrel32, YASM_DIR_ARG_REQUIRED }, + { ".export", "gas", dir_export, YASM_DIR_ID_REQUIRED }, + { "export", "nasm", dir_export, YASM_DIR_ID_REQUIRED }, + { ".safeseh", "gas", dir_safeseh, YASM_DIR_ID_REQUIRED }, + { "safeseh", "nasm", dir_safeseh, YASM_DIR_ID_REQUIRED }, + { NULL, NULL, NULL, 0 } +}; + +static const char *win32_nasm_stdmac[] = { + "%imacro export 1+.nolist", + "[export %1]", + "%endmacro", + "%imacro safeseh 1+.nolist", + "[safeseh %1]", + "%endmacro", + NULL +}; + +static const yasm_stdmac win32_objfmt_stdmacs[] = { + { "nasm", "nasm", win32_nasm_stdmac }, + { NULL, NULL, NULL } +}; + +/* Define objfmt structure -- see objfmt.h for details */ +yasm_objfmt_module yasm_win32_LTX_objfmt = { + "Win32", + "win32", + "obj", + 32, + 1, + winXX_objfmt_dbgfmt_keywords, + "null", + win32_objfmt_directives, + win32_objfmt_stdmacs, + win32_objfmt_create, + coff_objfmt_output, + coff_objfmt_destroy, + coff_objfmt_add_default_section, + coff_objfmt_init_new_section, + coff_objfmt_section_switch, + coff_objfmt_get_special_sym +}; + +static const yasm_directive win64_objfmt_directives[] = { + { ".ident", "gas", dir_ident, YASM_DIR_ANY }, + { "ident", "nasm", dir_ident, YASM_DIR_ANY }, + { ".def", "gas", dir_def, YASM_DIR_ID_REQUIRED }, + { ".endef", "gas", dir_endef, YASM_DIR_ANY }, + { ".scl", "gas", dir_scl, YASM_DIR_ARG_REQUIRED }, + { ".type", "gas", dir_type, YASM_DIR_ARG_REQUIRED }, + { ".secrel32", "gas", dir_secrel32, YASM_DIR_ARG_REQUIRED }, + { ".export", "gas", dir_export, YASM_DIR_ID_REQUIRED }, + { "export", "nasm", dir_export, YASM_DIR_ID_REQUIRED }, + { ".proc_frame", "gas", dir_proc_frame, YASM_DIR_ID_REQUIRED }, + { "proc_frame", "nasm", dir_proc_frame, YASM_DIR_ID_REQUIRED }, + { ".pushreg", "gas", dir_pushreg, YASM_DIR_ARG_REQUIRED }, + { "pushreg", "nasm", dir_pushreg, YASM_DIR_ARG_REQUIRED }, + { ".setframe", "gas", dir_setframe, YASM_DIR_ARG_REQUIRED }, + { "setframe", "nasm", dir_setframe, YASM_DIR_ARG_REQUIRED }, + { ".allocstack", "gas", dir_allocstack, YASM_DIR_ARG_REQUIRED }, + { "allocstack", "nasm", dir_allocstack, YASM_DIR_ARG_REQUIRED }, + { ".savereg", "gas", dir_savereg, YASM_DIR_ARG_REQUIRED }, + { "savereg", "nasm", dir_savereg, YASM_DIR_ARG_REQUIRED }, + { ".savexmm128", "gas", dir_savexmm128, YASM_DIR_ARG_REQUIRED }, + { "savexmm128", "nasm", dir_savexmm128, YASM_DIR_ARG_REQUIRED }, + { ".pushframe", "gas", dir_pushframe, YASM_DIR_ANY }, + { "pushframe", "nasm", dir_pushframe, YASM_DIR_ANY }, + { ".endprolog", "gas", dir_endprolog, YASM_DIR_ANY }, + { "endprolog", "nasm", dir_endprolog, YASM_DIR_ANY }, + { ".endproc_frame", "gas", dir_endproc_frame, YASM_DIR_ANY }, + { "endproc_frame", "nasm", dir_endproc_frame, YASM_DIR_ANY }, + { NULL, NULL, NULL, 0 } +}; + +#include "win64-nasm.c" +#include "win64-gas.c" + +static const yasm_stdmac win64_objfmt_stdmacs[] = { + { "nasm", "nasm", win64_nasm_stdmac }, + { "gas", "nasm", win64_gas_stdmac }, + { NULL, NULL, NULL } +}; + +/* Define objfmt structure -- see objfmt.h for details */ +yasm_objfmt_module yasm_win64_LTX_objfmt = { + "Win64", + "win64", + "obj", + 64, + 1, + winXX_objfmt_dbgfmt_keywords, + "null", + win64_objfmt_directives, + win64_objfmt_stdmacs, + win64_objfmt_create, + coff_objfmt_output, + coff_objfmt_destroy, + coff_objfmt_add_default_section, + coff_objfmt_init_new_section, + coff_objfmt_section_switch, + win64_objfmt_get_special_sym +}; +yasm_objfmt_module yasm_x64_LTX_objfmt = { + "Win64", + "x64", + "obj", + 64, + 1, + winXX_objfmt_dbgfmt_keywords, + "null", + win64_objfmt_directives, + win64_objfmt_stdmacs, + win64_objfmt_create, + coff_objfmt_output, + coff_objfmt_destroy, + coff_objfmt_add_default_section, + coff_objfmt_init_new_section, + coff_objfmt_section_switch, + win64_objfmt_get_special_sym +}; diff --git a/contrib/tools/yasm/modules/objfmts/coff/coff-objfmt.h b/contrib/tools/yasm/modules/objfmts/coff/coff-objfmt.h new file mode 100644 index 0000000000..10d88a0982 --- /dev/null +++ b/contrib/tools/yasm/modules/objfmts/coff/coff-objfmt.h @@ -0,0 +1,77 @@ +/* + * COFF (DJGPP) object format + * + * Copyright (C) 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 COFF_OBJFMT_H +#define COFF_OBJFMT_H + +typedef struct coff_unwind_code { + SLIST_ENTRY(coff_unwind_code) link; + + /*@dependent@*/ yasm_symrec *proc; /* Start of procedure */ + /*@dependent@*/ yasm_symrec *loc; /* Location of operation */ + /* Unwind operation code */ + enum { + UWOP_PUSH_NONVOL = 0, + UWOP_ALLOC_LARGE = 1, + UWOP_ALLOC_SMALL = 2, + UWOP_SET_FPREG = 3, + UWOP_SAVE_NONVOL = 4, + UWOP_SAVE_NONVOL_FAR = 5, + UWOP_SAVE_XMM128 = 8, + UWOP_SAVE_XMM128_FAR = 9, + UWOP_PUSH_MACHFRAME = 10 + } opcode; + unsigned int info; /* Operation info */ + yasm_value off; /* Offset expression (used for some codes) */ +} coff_unwind_code; + +typedef struct coff_unwind_info { + /*@dependent@*/ yasm_symrec *proc; /* Start of procedure */ + /*@dependent@*/ yasm_symrec *prolog; /* End of prologue */ + + /*@null@*/ /*@dependent@*/ yasm_symrec *ehandler; /* Error handler */ + + unsigned long framereg; /* Frame register */ + yasm_value frameoff; /* Frame offset */ + + /* Linked list of codes, in decreasing location offset order. + * Inserting at the head of this list during assembly naturally results + * in this sorting. + */ + SLIST_HEAD(coff_unwind_code_head, coff_unwind_code) codes; + + /* These aren't used until inside of generate. */ + yasm_value prolog_size; + yasm_value codes_count; +} coff_unwind_info; + +coff_unwind_info *yasm_win64__uwinfo_create(void); +void yasm_win64__uwinfo_destroy(coff_unwind_info *info); +void yasm_win64__unwind_generate(yasm_section *xdata, + /*@only@*/ coff_unwind_info *info, + unsigned long line); + +#endif diff --git a/contrib/tools/yasm/modules/objfmts/coff/win64-except.c b/contrib/tools/yasm/modules/objfmts/coff/win64-except.c new file mode 100644 index 0000000000..8c8ecbbc49 --- /dev/null +++ b/contrib/tools/yasm/modules/objfmts/coff/win64-except.c @@ -0,0 +1,559 @@ +/* + * Win64 structured exception handling support + * + * Copyright (C) 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 "coff-objfmt.h" + + +#define UNW_FLAG_EHANDLER 0x01 +#define UNW_FLAG_UHANDLER 0x02 +#define UNW_FLAG_CHAININFO 0x04 + +/* Bytecode callback function prototypes */ +static void win64_uwinfo_bc_destroy(void *contents); +static void win64_uwinfo_bc_print(const void *contents, FILE *f, + int indent_level); +static void win64_uwinfo_bc_finalize(yasm_bytecode *bc, + yasm_bytecode *prev_bc); +static int win64_uwinfo_bc_calc_len + (yasm_bytecode *bc, yasm_bc_add_span_func add_span, void *add_span_data); +static int win64_uwinfo_bc_expand(yasm_bytecode *bc, int span, long old_val, + long new_val, /*@out@*/ long *neg_thres, + /*@out@*/ long *pos_thres); +static int win64_uwinfo_bc_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 win64_uwcode_bc_destroy(void *contents); +static void win64_uwcode_bc_print(const void *contents, FILE *f, + int indent_level); +static void win64_uwcode_bc_finalize(yasm_bytecode *bc, + yasm_bytecode *prev_bc); +static int win64_uwcode_bc_calc_len + (yasm_bytecode *bc, yasm_bc_add_span_func add_span, void *add_span_data); +static int win64_uwcode_bc_expand(yasm_bytecode *bc, int span, long old_val, + long new_val, /*@out@*/ long *neg_thres, + /*@out@*/ long *pos_thres); +static int win64_uwcode_bc_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 win64_uwinfo_bc_callback = { + win64_uwinfo_bc_destroy, + win64_uwinfo_bc_print, + win64_uwinfo_bc_finalize, + NULL, + win64_uwinfo_bc_calc_len, + win64_uwinfo_bc_expand, + win64_uwinfo_bc_tobytes, + 0 +}; + +static const yasm_bytecode_callback win64_uwcode_bc_callback = { + win64_uwcode_bc_destroy, + win64_uwcode_bc_print, + win64_uwcode_bc_finalize, + NULL, + win64_uwcode_bc_calc_len, + win64_uwcode_bc_expand, + win64_uwcode_bc_tobytes, + 0 +}; + + +coff_unwind_info * +yasm_win64__uwinfo_create(void) +{ + coff_unwind_info *info = yasm_xmalloc(sizeof(coff_unwind_info)); + info->proc = NULL; + info->prolog = NULL; + info->ehandler = NULL; + info->framereg = 0; + /* Frameoff is really a 4-bit value, scaled by 16 */ + yasm_value_initialize(&info->frameoff, NULL, 8); + SLIST_INIT(&info->codes); + yasm_value_initialize(&info->prolog_size, NULL, 8); + yasm_value_initialize(&info->codes_count, NULL, 8); + return info; +} + +void +yasm_win64__uwinfo_destroy(coff_unwind_info *info) +{ + coff_unwind_code *code; + + yasm_value_delete(&info->frameoff); + yasm_value_delete(&info->prolog_size); + yasm_value_delete(&info->codes_count); + + while (!SLIST_EMPTY(&info->codes)) { + code = SLIST_FIRST(&info->codes); + SLIST_REMOVE_HEAD(&info->codes, link); + yasm_value_delete(&code->off); + yasm_xfree(code); + } + yasm_xfree(info); +} + +void +yasm_win64__unwind_generate(yasm_section *xdata, coff_unwind_info *info, + unsigned long line) +{ + yasm_bytecode *infobc, *codebc = NULL; + coff_unwind_code *code; + + /* 4-byte align the start of unwind info */ + yasm_section_bcs_append(xdata, yasm_bc_create_align( + yasm_expr_create_ident(yasm_expr_int(yasm_intnum_create_uint(4)), + line), + NULL, NULL, NULL, line)); + + /* Prolog size = end of prolog - start of procedure */ + yasm_value_initialize(&info->prolog_size, + yasm_expr_create(YASM_EXPR_SUB, yasm_expr_sym(info->prolog), + yasm_expr_sym(info->proc), line), + 8); + + /* Unwind info */ + infobc = yasm_bc_create_common(&win64_uwinfo_bc_callback, info, line); + yasm_section_bcs_append(xdata, infobc); + + /* Code array */ + SLIST_FOREACH(code, &info->codes, link) { + codebc = yasm_bc_create_common(&win64_uwcode_bc_callback, code, + yasm_symrec_get_def_line(code->loc)); + yasm_section_bcs_append(xdata, codebc); + } + + /* Avoid double-free (by code destroy and uwinfo destroy). */ + SLIST_INIT(&info->codes); + + /* Number of codes = (Last code - end of info) >> 1 */ + if (!codebc) { + yasm_value_initialize(&info->codes_count, + yasm_expr_create_ident(yasm_expr_int(yasm_intnum_create_uint(0)), + line), + 8); + } else { + yasm_value_initialize(&info->codes_count, + yasm_expr_create(YASM_EXPR_SHR, yasm_expr_expr( + yasm_expr_create(YASM_EXPR_SUB, yasm_expr_precbc(codebc), + yasm_expr_precbc(infobc), line)), + yasm_expr_int(yasm_intnum_create_uint(1)), line), + 8); + } + + /* 4-byte align */ + yasm_section_bcs_append(xdata, yasm_bc_create_align( + yasm_expr_create_ident(yasm_expr_int(yasm_intnum_create_uint(4)), + line), + NULL, NULL, NULL, line)); + + /* Exception handler, if present. Use data bytecode. */ + if (info->ehandler) { + yasm_datavalhead dvs; + + yasm_dvs_initialize(&dvs); + yasm_dvs_append(&dvs, yasm_dv_create_expr( + yasm_expr_create_ident(yasm_expr_sym(info->ehandler), line))); + yasm_section_bcs_append(xdata, + yasm_bc_create_data(&dvs, 4, 0, NULL, line)); + } +} + +static void +win64_uwinfo_bc_destroy(void *contents) +{ + yasm_win64__uwinfo_destroy((coff_unwind_info *)contents); +} + +static void +win64_uwinfo_bc_print(const void *contents, FILE *f, int indent_level) +{ + /* TODO */ +} + +static void +win64_uwinfo_bc_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc) +{ + coff_unwind_info *info = (coff_unwind_info *)bc->contents; + + if (yasm_value_finalize(&info->prolog_size, prev_bc)) + yasm_internal_error(N_("prolog size expression too complex")); + + if (yasm_value_finalize(&info->codes_count, prev_bc)) + yasm_internal_error(N_("codes count expression too complex")); + + if (yasm_value_finalize(&info->frameoff, prev_bc)) + yasm_error_set(YASM_ERROR_VALUE, + N_("frame offset expression too complex")); +} + +static int +win64_uwinfo_bc_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span, + void *add_span_data) +{ + coff_unwind_info *info = (coff_unwind_info *)bc->contents; + /*@only@*/ /*@null@*/ yasm_intnum *intn; + long intv; + + /* Want to make sure prolog size and codes count doesn't exceed + * byte-size, and scaled frame offset doesn't exceed 4 bits. + */ + add_span(add_span_data, bc, 1, &info->prolog_size, 0, 255); + add_span(add_span_data, bc, 2, &info->codes_count, 0, 255); + + intn = yasm_value_get_intnum(&info->frameoff, bc, 0); + if (intn) { + intv = yasm_intnum_get_int(intn); + if (intv < 0 || intv > 240) + yasm_error_set(YASM_ERROR_VALUE, + N_("frame offset of %ld bytes, must be between 0 and 240"), + intv); + else if ((intv & 0xF) != 0) + yasm_error_set(YASM_ERROR_VALUE, + N_("frame offset of %ld is not a multiple of 16"), intv); + yasm_intnum_destroy(intn); + } else + add_span(add_span_data, bc, 3, &info->frameoff, 0, 240); + + bc->len += 4; + return 0; +} + +static int +win64_uwinfo_bc_expand(yasm_bytecode *bc, int span, long old_val, long new_val, + /*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres) +{ + coff_unwind_info *info = (coff_unwind_info *)bc->contents; + switch (span) { + case 1: + yasm_error_set_xref(yasm_symrec_get_def_line(info->prolog), + N_("prologue ended here")); + yasm_error_set(YASM_ERROR_VALUE, + N_("prologue %ld bytes, must be <256"), new_val); + return -1; + case 2: + yasm_error_set(YASM_ERROR_VALUE, + N_("%ld unwind codes, maximum of 255"), new_val); + return -1; + case 3: + yasm_error_set(YASM_ERROR_VALUE, + N_("frame offset of %ld bytes, must be between 0 and 240"), + new_val); + return -1; + default: + yasm_internal_error(N_("unrecognized span id")); + } + return 0; +} + +static int +win64_uwinfo_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp, + unsigned char *bufstart, void *d, + yasm_output_value_func output_value, + yasm_output_reloc_func output_reloc) +{ + coff_unwind_info *info = (coff_unwind_info *)bc->contents; + unsigned char *buf = *bufp; + /*@only@*/ /*@null@*/ yasm_intnum *frameoff; + long intv; + + /* Version and flags */ + if (info->ehandler) + YASM_WRITE_8(buf, 1 | (UNW_FLAG_EHANDLER << 3)); + else + YASM_WRITE_8(buf, 1); + + /* Size of prolog */ + output_value(&info->prolog_size, buf, 1, (unsigned long)(buf-bufstart), + bc, 1, d); + buf += 1; + + /* Count of codes */ + output_value(&info->codes_count, buf, 1, (unsigned long)(buf-bufstart), + bc, 1, d); + buf += 1; + + /* Frame register and offset */ + frameoff = yasm_value_get_intnum(&info->frameoff, bc, 1); + if (!frameoff) { + yasm_error_set(YASM_ERROR_VALUE, + N_("frame offset expression too complex")); + return 1; + } + intv = yasm_intnum_get_int(frameoff); + if (intv < 0 || intv > 240) + yasm_error_set(YASM_ERROR_VALUE, + N_("frame offset of %ld bytes, must be between 0 and 240"), intv); + else if ((intv & 0xF) != 0) + yasm_error_set(YASM_ERROR_VALUE, + N_("frame offset of %ld is not a multiple of 16"), intv); + + YASM_WRITE_8(buf, ((unsigned long)intv & 0xF0) | (info->framereg & 0x0F)); + yasm_intnum_destroy(frameoff); + + *bufp = buf; + return 0; +} + +static void +win64_uwcode_bc_destroy(void *contents) +{ + coff_unwind_code *code = (coff_unwind_code *)contents; + yasm_value_delete(&code->off); + yasm_xfree(contents); +} + +static void +win64_uwcode_bc_print(const void *contents, FILE *f, int indent_level) +{ + /* TODO */ +} + +static void +win64_uwcode_bc_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc) +{ + coff_unwind_code *code = (coff_unwind_code *)bc->contents; + if (yasm_value_finalize(&code->off, prev_bc)) + yasm_error_set(YASM_ERROR_VALUE, N_("offset expression too complex")); +} + +static int +win64_uwcode_bc_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span, + void *add_span_data) +{ + coff_unwind_code *code = (coff_unwind_code *)bc->contents; + int span = 0; + /*@only@*/ /*@null@*/ yasm_intnum *intn; + long intv; + long low, high, mask; + + bc->len += 2; /* Prolog offset, code, and info */ + + switch (code->opcode) { + case UWOP_PUSH_NONVOL: + case UWOP_SET_FPREG: + case UWOP_PUSH_MACHFRAME: + /* always 1 node */ + return 0; + case UWOP_ALLOC_SMALL: + case UWOP_ALLOC_LARGE: + /* Start with smallest, then work our way up as necessary */ + code->opcode = UWOP_ALLOC_SMALL; + code->info = 0; + span = 1; low = 8; high = 128; mask = 0x7; + break; + case UWOP_SAVE_NONVOL: + case UWOP_SAVE_NONVOL_FAR: + /* Start with smallest, then work our way up as necessary */ + code->opcode = UWOP_SAVE_NONVOL; + bc->len += 2; /* Scaled offset */ + span = 2; + low = 0; + high = 8*64*1024-8; /* 16-bit field, *8 scaling */ + mask = 0x7; + break; + case UWOP_SAVE_XMM128: + case UWOP_SAVE_XMM128_FAR: + /* Start with smallest, then work our way up as necessary */ + code->opcode = UWOP_SAVE_XMM128; + bc->len += 2; /* Scaled offset */ + span = 3; + low = 0; + high = 16*64*1024-16; /* 16-bit field, *16 scaling */ + mask = 0xF; + break; + default: + yasm_internal_error(N_("unrecognied unwind opcode")); + /*@unreached@*/ + return 0; + } + + intn = yasm_value_get_intnum(&code->off, bc, 0); + if (intn) { + intv = yasm_intnum_get_int(intn); + if (intv > high) { + /* Expand it ourselves here if we can and we're already larger */ + if (win64_uwcode_bc_expand(bc, span, intv, intv, &low, &high) > 0) + add_span(add_span_data, bc, span, &code->off, low, high); + } + if (intv < low) + yasm_error_set(YASM_ERROR_VALUE, + N_("negative offset not allowed")); + if ((intv & mask) != 0) + yasm_error_set(YASM_ERROR_VALUE, + N_("offset of %ld is not a multiple of %ld"), intv, mask+1); + yasm_intnum_destroy(intn); + } else + add_span(add_span_data, bc, span, &code->off, low, high); + return 0; +} + +static int +win64_uwcode_bc_expand(yasm_bytecode *bc, int span, long old_val, long new_val, + /*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres) +{ + coff_unwind_code *code = (coff_unwind_code *)bc->contents; + + if (new_val < 0) { + yasm_error_set(YASM_ERROR_VALUE, N_("negative offset not allowed")); + return -1; + } + + if (span == 1) { + /* 3 stages: SMALL, LARGE and info=0, LARGE and info=1 */ + if (code->opcode == UWOP_ALLOC_LARGE && code->info == 1) + yasm_internal_error(N_("expansion on already largest alloc")); + + if (code->opcode == UWOP_ALLOC_SMALL && new_val > 128) { + /* Overflowed small size */ + code->opcode = UWOP_ALLOC_LARGE; + bc->len += 2; + } + if (new_val <= 8*64*1024-8) { + /* Still can grow one more size */ + *pos_thres = 8*64*1024-8; + return 1; + } + /* We're into the largest size */ + code->info = 1; + bc->len += 2; + } else if (code->opcode == UWOP_SAVE_NONVOL && span == 2) { + code->opcode = UWOP_SAVE_NONVOL_FAR; + bc->len += 2; + } else if (code->opcode == UWOP_SAVE_XMM128 && span == 3) { + code->opcode = UWOP_SAVE_XMM128_FAR; + bc->len += 2; + } + return 0; +} + +static int +win64_uwcode_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp, + unsigned char *bufstart, void *d, + yasm_output_value_func output_value, + yasm_output_reloc_func output_reloc) +{ + coff_unwind_code *code = (coff_unwind_code *)bc->contents; + unsigned char *buf = *bufp; + yasm_value val; + unsigned int size; + int shift; + long intv, low, high, mask; + yasm_intnum *intn; + + /* Offset in prolog */ + yasm_value_initialize(&val, + yasm_expr_create(YASM_EXPR_SUB, yasm_expr_sym(code->loc), + yasm_expr_sym(code->proc), bc->line), + 8); + output_value(&val, buf, 1, (unsigned long)(buf-bufstart), bc, 1, d); + buf += 1; + yasm_value_delete(&val); + + /* Offset value */ + switch (code->opcode) { + case UWOP_PUSH_NONVOL: + case UWOP_SET_FPREG: + case UWOP_PUSH_MACHFRAME: + /* just 1 node, no offset; write opcode and info and we're done */ + YASM_WRITE_8(buf, (code->info << 4) | (code->opcode & 0xF)); + *bufp = buf; + return 0; + case UWOP_ALLOC_SMALL: + /* 1 node, but offset stored in info */ + size = 0; low = 8; high = 128; shift = 3; mask = 0x7; + break; + case UWOP_ALLOC_LARGE: + if (code->info == 0) { + size = 2; low = 136; high = 8*64*1024-8; shift = 3; + } else { + size = 4; low = high = 0; shift = 0; + } + mask = 0x7; + break; + case UWOP_SAVE_NONVOL: + size = 2; low = 0; high = 8*64*1024-8; shift = 3; mask = 0x7; + break; + case UWOP_SAVE_XMM128: + size = 2; low = 0; high = 16*64*1024-16; shift = 4; mask = 0xF; + break; + case UWOP_SAVE_NONVOL_FAR: + size = 4; low = high = 0; shift = 0; mask = 0x7; + break; + case UWOP_SAVE_XMM128_FAR: + size = 4; low = high = 0; shift = 0; mask = 0xF; + break; + default: + yasm_internal_error(N_("unrecognied unwind opcode")); + /*@unreached@*/ + return 1; + } + + /* Check for overflow */ + intn = yasm_value_get_intnum(&code->off, bc, 1); + if (!intn) { + yasm_error_set(YASM_ERROR_VALUE, N_("offset expression too complex")); + return 1; + } + intv = yasm_intnum_get_int(intn); + if (size != 4 && (intv < low || intv > high)) { + yasm_error_set(YASM_ERROR_VALUE, + N_("offset of %ld bytes, must be between %ld and %ld"), + intv, low, high); + return 1; + } + if ((intv & mask) != 0) { + yasm_error_set(YASM_ERROR_VALUE, + N_("offset of %ld is not a multiple of %ld"), + intv, mask+1); + return 1; + } + + /* Stored value in info instead of extra code space */ + if (size == 0) + code->info = (yasm_intnum_get_uint(intn) >> shift)-1; + + /* Opcode and info */ + YASM_WRITE_8(buf, (code->info << 4) | (code->opcode & 0xF)); + + if (size != 0) { + yasm_intnum_get_sized(intn, buf, size, size*8, -shift, 0, 1); + buf += size; + } + + yasm_intnum_destroy(intn); + + *bufp = buf; + return 0; +} diff --git a/contrib/tools/yasm/modules/objfmts/dbg/dbg-objfmt.c b/contrib/tools/yasm/modules/objfmts/dbg/dbg-objfmt.c new file mode 100644 index 0000000000..bdf403c762 --- /dev/null +++ b/contrib/tools/yasm/modules/objfmts/dbg/dbg-objfmt.c @@ -0,0 +1,183 @@ +/* + * Debugging object format (used to debug object format module interface) + * + * 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> + + +typedef struct yasm_objfmt_dbg { + yasm_objfmt_base objfmt; /* base structure */ + + FILE *dbgfile; +} yasm_objfmt_dbg; + +yasm_objfmt_module yasm_dbg_LTX_objfmt; + + +static yasm_objfmt * +dbg_objfmt_create(yasm_object *object) +{ + yasm_objfmt_dbg *objfmt_dbg = yasm_xmalloc(sizeof(yasm_objfmt_dbg)); + + objfmt_dbg->objfmt.module = &yasm_dbg_LTX_objfmt; + + objfmt_dbg->dbgfile = tmpfile(); + if (!objfmt_dbg->dbgfile) { + fprintf(stderr, N_("could not open temporary file")); + return 0; + } + fprintf(objfmt_dbg->dbgfile, "create()\n"); + return (yasm_objfmt *)objfmt_dbg; +} + +static void +dbg_objfmt_output(yasm_object *object, FILE *f, int all_syms, + yasm_errwarns *errwarns) +{ + yasm_objfmt_dbg *objfmt_dbg = (yasm_objfmt_dbg *)object->objfmt; + char buf[1024]; + size_t i; + + /* Copy temp file to real output file */ + rewind(objfmt_dbg->dbgfile); + while ((i = fread(buf, 1, 1024, objfmt_dbg->dbgfile))) { + if (fwrite(buf, 1, i, f) != i) + break; + } + + /* Reassign objfmt debug file to output file */ + fclose(objfmt_dbg->dbgfile); + objfmt_dbg->dbgfile = f; + + fprintf(objfmt_dbg->dbgfile, "output(f, object->\n"); + yasm_object_print(object, objfmt_dbg->dbgfile, 1); + fprintf(objfmt_dbg->dbgfile, "%d)\n", all_syms); + fprintf(objfmt_dbg->dbgfile, " Symbol Table:\n"); + yasm_symtab_print(object->symtab, objfmt_dbg->dbgfile, 1); +} + +static void +dbg_objfmt_destroy(yasm_objfmt *objfmt) +{ + yasm_objfmt_dbg *objfmt_dbg = (yasm_objfmt_dbg *)objfmt; + fprintf(objfmt_dbg->dbgfile, "destroy()\n"); + yasm_xfree(objfmt); +} + +static void +dbg_objfmt_init_new_section(yasm_section *sect, unsigned long line) +{ + yasm_object *object = yasm_section_get_object(sect); + yasm_objfmt_dbg *objfmt_dbg = (yasm_objfmt_dbg *)object->objfmt; + fprintf(objfmt_dbg->dbgfile, "init_new_section(\"%s\", %lu)\n", + yasm_section_get_name(sect), line); + yasm_symtab_define_label(object->symtab, ".text", + yasm_section_bcs_first(sect), 1, 0); +} + +static yasm_section * +dbg_objfmt_add_default_section(yasm_object *object) +{ + yasm_objfmt_dbg *objfmt_dbg = (yasm_objfmt_dbg *)object->objfmt; + yasm_section *retval; + int isnew; + + fprintf(objfmt_dbg->dbgfile, "add_default_section()\n"); + retval = yasm_object_get_general(object, ".text", 0, 0, 0, &isnew, 0); + if (isnew) { + yasm_section_set_default(retval, 1); + } + return retval; +} + +static /*@observer@*/ /*@null@*/ yasm_section * +dbg_objfmt_section_switch(yasm_object *object, yasm_valparamhead *valparams, + /*@unused@*/ /*@null@*/ + yasm_valparamhead *objext_valparams, + unsigned long line) +{ + yasm_objfmt_dbg *objfmt_dbg = (yasm_objfmt_dbg *)object->objfmt; + yasm_valparam *vp; + yasm_section *retval; + int isnew; + + fprintf(objfmt_dbg->dbgfile, "section_switch(headp, "); + yasm_vps_print(valparams, objfmt_dbg->dbgfile); + fprintf(objfmt_dbg->dbgfile, ", "); + yasm_vps_print(objext_valparams, objfmt_dbg->dbgfile); + fprintf(objfmt_dbg->dbgfile, ", %lu), returning ", line); + + vp = yasm_vps_first(valparams); + if (!yasm_vp_string(vp)) { + fprintf(objfmt_dbg->dbgfile, "NULL\n"); + return NULL; + } + retval = yasm_object_get_general(object, yasm_vp_string(vp), 0, 0, 0, + &isnew, line); + if (isnew) { + fprintf(objfmt_dbg->dbgfile, "(new) "); + } + yasm_section_set_default(retval, 0); + fprintf(objfmt_dbg->dbgfile, "\"%s\" section\n", vp->val); + return retval; +} + +static /*@observer@*/ /*@null@*/ yasm_symrec * +dbg_objfmt_get_special_sym(yasm_object *object, const char *name, + const char *parser) +{ + yasm_objfmt_dbg *objfmt_dbg = (yasm_objfmt_dbg *)object->objfmt; + fprintf(objfmt_dbg->dbgfile, "get_special_sym(object, \"%s\", \"%s\")\n", + name, parser); + return NULL; +} + +/* Define valid debug formats to use with this object format */ +static const char *dbg_objfmt_dbgfmt_keywords[] = { + "null", + NULL +}; + +/* Define objfmt structure -- see objfmt.h for details */ +yasm_objfmt_module yasm_dbg_LTX_objfmt = { + "Trace of all info passed to object format module", + "dbg", + "dbg", + 32, + 0, + dbg_objfmt_dbgfmt_keywords, + "null", + NULL, /* no directives */ + NULL, /* no standard macros */ + dbg_objfmt_create, + dbg_objfmt_output, + dbg_objfmt_destroy, + dbg_objfmt_add_default_section, + dbg_objfmt_init_new_section, + dbg_objfmt_section_switch, + dbg_objfmt_get_special_sym +}; diff --git a/contrib/tools/yasm/modules/objfmts/elf/elf-machine.h b/contrib/tools/yasm/modules/objfmts/elf/elf-machine.h new file mode 100644 index 0000000000..ea6cb4ec94 --- /dev/null +++ b/contrib/tools/yasm/modules/objfmts/elf/elf-machine.h @@ -0,0 +1,108 @@ +/* + * ELF object machine specific format helpers + * + * Copyright (C) 2004-2007 Michael Urman + * + * 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 ELF_MACHINE_H_INCLUDED +#define ELF_MACHINE_H_INCLUDED + +#define YASM_WRITE_32I_L(p, i) do {\ + assert(yasm_intnum_check_size(i, 32, 0, 2)); \ + yasm_intnum_get_sized(i, p, 4, 32, 0, 0, 0); \ + p += 4; } while (0) + +#define YASM_WRITE_64I_L(p, i) do {\ + assert(yasm_intnum_check_size(i, 64, 0, 2)); \ + yasm_intnum_get_sized(i, p, 8, 64, 0, 0, 0); \ + p += 8; } while (0) + +#define YASM_WRITE_64C_L(p, hi, lo) do {\ + YASM_WRITE_32_L(p, lo); \ + YASM_WRITE_32_L(p, hi); } while (0) + +#define YASM_WRITE_64Z_L(p, i) YASM_WRITE_64C_L(p, 0, i) + +typedef int(*func_accepts_reloc)(size_t val, yasm_symrec *wrt); +typedef void(*func_write_symtab_entry)(unsigned char *bufp, + elf_symtab_entry *entry, + yasm_intnum *value_intn, + yasm_intnum *size_intn); +typedef void(*func_write_secthead)(unsigned char *bufp, elf_secthead *shead); +typedef void(*func_write_secthead_rel)(unsigned char *bufp, + elf_secthead *shead, + elf_section_index symtab_idx, + elf_section_index sindex); + +typedef void(*func_handle_reloc_addend)(yasm_intnum *intn, + elf_reloc_entry *reloc, + unsigned long offset); +typedef unsigned int(*func_map_reloc_info_to_type)(elf_reloc_entry *reloc); +typedef void(*func_write_reloc)(unsigned char *bufp, + elf_reloc_entry *reloc, + unsigned int r_type, + unsigned int r_sym); +typedef void (*func_write_proghead)(unsigned char **bufpp, + elf_offset secthead_addr, + unsigned long secthead_count, + elf_section_index shstrtab_index); + +enum { + ELF_SSYM_SYM_RELATIVE = 1 << 0, + ELF_SSYM_CURPOS_ADJUST = 1 << 1, + ELF_SSYM_THREAD_LOCAL = 1 << 2 +}; + +typedef struct { + const char *name; /* should be something like ..name */ + const int sym_rel; /* symbol or section-relative? */ + const unsigned int reloc; /* relocation type */ + const unsigned int size; /* legal data size */ +} elf_machine_ssym; + +struct elf_machine_handler { + const char *arch; + const char *machine; + const char *reloc_section_prefix; + const unsigned long symtab_entry_size; + const unsigned long symtab_entry_align; + const unsigned long reloc_entry_size; + const unsigned long secthead_size; + const unsigned long proghead_size; + func_accepts_reloc accepts_reloc; + func_write_symtab_entry write_symtab_entry; + func_write_secthead write_secthead; + func_write_secthead_rel write_secthead_rel; + func_handle_reloc_addend handle_reloc_addend; + func_map_reloc_info_to_type map_reloc_info_to_type; + func_write_reloc write_reloc; + func_write_proghead write_proghead; + + elf_machine_ssym *ssyms; /* array of "special" syms */ + const size_t num_ssyms; /* size of array */ + + const int bits; /* usually 32 or 64 */ +}; + +#endif /* ELF_MACHINE_H_INCLUDED */ diff --git a/contrib/tools/yasm/modules/objfmts/elf/elf-objfmt.c b/contrib/tools/yasm/modules/objfmts/elf/elf-objfmt.c new file mode 100644 index 0000000000..6874a1689f --- /dev/null +++ b/contrib/tools/yasm/modules/objfmts/elf/elf-objfmt.c @@ -0,0 +1,1403 @@ +/* + * ELF object format + * + * Copyright (C) 2003-2007 Michael Urman + * + * 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> + +/* Notes + * + * elf-objfmt uses the "linking" view of an ELF file: + * ELF header, an optional program header table, several sections, + * and a section header table + * + * The ELF header tells us some overall program information, + * where to find the PHT (if it exists) with phnum and phentsize, + * and where to find the SHT with shnum and shentsize + * + * The PHT doesn't seem to be generated by NASM for elftest.asm + * + * The SHT + * + * Each Section is spatially disjoint, and has exactly one SHT entry. + */ + +#include <libyasm.h> + +#include "elf.h" +#include "elf-machine.h" + +typedef struct yasm_objfmt_elf { + yasm_objfmt_base objfmt; /* base structure */ + + elf_symtab_head* elf_symtab; /* symbol table of indexed syms */ + elf_strtab_head* shstrtab; /* section name strtab */ + elf_strtab_head* strtab; /* strtab entries */ + + elf_strtab_entry *file_strtab_entry;/* .file symbol associated string */ + yasm_symrec *dotdotsym; /* ..sym symbol */ +} yasm_objfmt_elf; + +typedef struct { + yasm_objfmt_elf *objfmt_elf; + yasm_errwarns *errwarns; + FILE *f; + elf_secthead *shead; + yasm_section *sect; + yasm_object *object; + unsigned long sindex; + yasm_symrec *GOT_sym; +} elf_objfmt_output_info; + +typedef struct { + yasm_object *object; + yasm_objfmt_elf *objfmt_elf; + yasm_errwarns *errwarns; + int local_names; +} build_symtab_info; + +yasm_objfmt_module yasm_elf_LTX_objfmt; +yasm_objfmt_module yasm_elf32_LTX_objfmt; +yasm_objfmt_module yasm_elf64_LTX_objfmt; +yasm_objfmt_module yasm_elfx32_LTX_objfmt; + + +static elf_symtab_entry * +elf_objfmt_symtab_append(yasm_objfmt_elf *objfmt_elf, yasm_symrec *sym, + elf_section_index sectidx, elf_symbol_binding bind, + elf_symbol_type type, elf_symbol_vis vis, + yasm_expr *size, elf_address *value, + yasm_object *object) +{ + elf_symtab_entry *entry = yasm_symrec_get_data(sym, &elf_symrec_data); + + if (!entry) { + /*@only@*/ char *symname = yasm_symrec_get_global_name(sym, object); + elf_strtab_entry *name = + elf_strtab_append_str(objfmt_elf->strtab, symname); + yasm_xfree(symname); + entry = elf_symtab_entry_create(name, sym); + yasm_symrec_add_data(sym, &elf_symrec_data, entry); + } + + /* Only append to table if not already appended */ + if (!elf_sym_in_table(entry)) + elf_symtab_append_entry(objfmt_elf->elf_symtab, entry); + + elf_symtab_set_nonzero(entry, NULL, sectidx, bind, type, size, value); + elf_sym_set_visibility(entry, vis); + + return entry; +} + +static elf_symtab_entry * +build_extern(yasm_objfmt_elf *objfmt_elf, yasm_symrec *sym, yasm_object *object) +{ + yasm_valparamhead *objext_valparams = + yasm_symrec_get_objext_valparams(sym); + + if (objext_valparams) { + yasm_valparam *vp = yasm_vps_first(objext_valparams); + for (; vp; vp = yasm_vps_next(vp)) { + if (yasm_vp_string(vp)) + yasm_error_set(YASM_ERROR_TYPE, + N_("unrecognized symbol type `%s'"), + yasm_vp_string(vp)); + } + } + + return elf_objfmt_symtab_append(objfmt_elf, sym, SHN_UNDEF, STB_GLOBAL, 0, + STV_DEFAULT, NULL, NULL, object); +} + +struct elf_build_global_data { + yasm_expr *size; + unsigned long type; /* elf_symbol_type */ + elf_symbol_vis vis; + unsigned int vis_overrides; +}; + +static int +elf_global_helper_valparam(void *obj, yasm_valparam *vp, unsigned long line, + void *d) + +{ + struct elf_build_global_data *data = (struct elf_build_global_data *)d; + const char *s; + + if (!vp->val && (s = yasm_vp_id(vp))) { + yasm_error_set(YASM_ERROR_TYPE, N_("unrecognized symbol type `%s'"), + s); + return -1; + } else if (!vp->val && vp->type == YASM_PARAM_EXPR && !data->size) { + data->size = yasm_expr_copy(vp->param.e); + return 0; + } else + return yasm_dir_helper_valparam_warn(obj, vp, line, d); +} + +static int +elf_global_helper_vis(void *obj, yasm_valparam *vp, unsigned long line, + void *d, uintptr_t vis) +{ + struct elf_build_global_data *data = (struct elf_build_global_data *)d; + data->vis = vis; + data->vis_overrides++; + return 0; +} + + +static elf_symtab_entry * +build_global(yasm_objfmt_elf *objfmt_elf, yasm_symrec *sym, yasm_object *object) +{ + yasm_valparamhead *objext_valparams = + yasm_symrec_get_objext_valparams(sym); + + struct elf_build_global_data data; + + static const yasm_dir_help help[] = { + { "function", 0, yasm_dir_helper_flag_set, + offsetof(struct elf_build_global_data, type), STT_FUNC }, + { "data", 0, yasm_dir_helper_flag_set, + offsetof(struct elf_build_global_data, type), STT_OBJECT }, + { "object", 0, yasm_dir_helper_flag_set, + offsetof(struct elf_build_global_data, type), STT_OBJECT }, + { "internal", 0, elf_global_helper_vis, 0, STV_INTERNAL }, + { "hidden", 0, elf_global_helper_vis, 0, STV_HIDDEN }, + { "protected", 0, elf_global_helper_vis, 0, STV_PROTECTED }, + }; + + data.size = NULL; + data.type = 0; + data.vis = STV_DEFAULT; + data.vis_overrides = 0; + + if (objext_valparams) + yasm_dir_helper(sym, yasm_vps_first(objext_valparams), + yasm_symrec_get_decl_line(sym), help, NELEMS(help), + &data, elf_global_helper_valparam); + + if (data.vis_overrides > 1) { + yasm_warn_set(YASM_WARN_GENERAL, + N_("More than one symbol visibility provided; using last")); + } + + return elf_objfmt_symtab_append(objfmt_elf, sym, SHN_UNDEF, STB_GLOBAL, + data.type, data.vis, data.size, NULL, + object); +} + +static /*@null@*/ elf_symtab_entry * +build_common(yasm_objfmt_elf *objfmt_elf, yasm_symrec *sym, yasm_object *object) +{ + yasm_expr **size = yasm_symrec_get_common_size(sym); + yasm_valparamhead *objext_valparams = + yasm_symrec_get_objext_valparams(sym); + unsigned long addralign = 0; + + if (objext_valparams) { + yasm_valparam *vp = yasm_vps_first(objext_valparams); + for (; vp; vp = yasm_vps_next(vp)) { + if (!vp->val) { + /*@only@*/ /*@null@*/ yasm_expr *align_expr; + /*@dependent@*/ /*@null@*/ const yasm_intnum *align_intn; + + if (!(align_expr = yasm_vp_expr(vp, object->symtab, + yasm_symrec_get_def_line(sym))) + || !(align_intn = yasm_expr_get_intnum(&align_expr, 0))) { + yasm_error_set(YASM_ERROR_VALUE, + N_("alignment constraint is not an integer")); + if (align_expr) + yasm_expr_destroy(align_expr); + return NULL; + } + addralign = yasm_intnum_get_uint(align_intn); + yasm_expr_destroy(align_expr); + + /* Alignments must be a power of two. */ + if (!is_exp2(addralign)) { + yasm_error_set(YASM_ERROR_VALUE, + N_("alignment constraint is not a power of two")); + return NULL; + } + } else + yasm_warn_set(YASM_WARN_GENERAL, + N_("Unrecognized qualifier `%s'"), vp->val); + } + } + + return elf_objfmt_symtab_append(objfmt_elf, sym, SHN_COMMON, STB_GLOBAL, + 0, STV_DEFAULT, *size, &addralign, object); +} + +static int +elf_objfmt_build_symtab(yasm_symrec *sym, /*@null@*/ void *d) +{ + build_symtab_info *info = (build_symtab_info *)d; + yasm_sym_vis vis = yasm_symrec_get_visibility(sym); + yasm_sym_status status = yasm_symrec_get_status(sym); + elf_symtab_entry *entry = yasm_symrec_get_data(sym, &elf_symrec_data); + elf_address value=0; + yasm_section *sect=NULL; + yasm_bytecode *precbc=NULL; + + assert(info != NULL); + + if (vis & YASM_SYM_EXTERN) { + entry = build_extern(info->objfmt_elf, sym, info->object); + yasm_errwarn_propagate(info->errwarns, + yasm_symrec_get_decl_line(sym)); + return 0; + } + + if (vis & YASM_SYM_COMMON) { + entry = build_common(info->objfmt_elf, sym, info->object); + yasm_errwarn_propagate(info->errwarns, + yasm_symrec_get_decl_line(sym)); + /* If the COMMON variable was actually defined, fall through. */ + if (!(status & YASM_SYM_DEFINED)) + return 0; + } + + /* Ignore any undefined at this point. */ + if (!(status & YASM_SYM_DEFINED)) + return 0; + + if (!yasm_symrec_get_label(sym, &precbc)) { + if (!yasm_symrec_get_equ(sym) && !yasm_symrec_is_abs(sym)) + return 0; + precbc = NULL; + } + + if (precbc) + sect = yasm_bc_get_section(precbc); + + if (entry && elf_sym_in_table(entry)) + ; + else if (vis & YASM_SYM_GLOBAL) { + entry = build_global(info->objfmt_elf, sym, info->object); + yasm_errwarn_propagate(info->errwarns, yasm_symrec_get_decl_line(sym)); + } else { + int is_sect = 0; + + /* Locals (except when debugging) do not need to be + * in the symbol table, unless they're a section. + */ + if (sect && + strcmp(yasm_symrec_get_name(sym), yasm_section_get_name(sect))==0) + is_sect = 1; +#if 0 + /* FIXME: to enable this we must have handling in place for special + * symbols. + */ + if (!info->local_names && !is_sect) + return 0; +#else + if (yasm_symrec_get_equ(sym) && !yasm_symrec_is_abs(sym)) + return 0; +#endif + entry = yasm_symrec_get_data(sym, &elf_symrec_data); + if (!entry) { + /*@only@*/ char *symname = + yasm_symrec_get_global_name(sym, info->object); + elf_strtab_entry *name = !info->local_names || is_sect ? NULL : + elf_strtab_append_str(info->objfmt_elf->strtab, symname); + yasm_xfree(symname); + entry = elf_symtab_entry_create(name, sym); + yasm_symrec_add_data(sym, &elf_symrec_data, entry); + } + + if (!elf_sym_in_table(entry)) + elf_symtab_insert_local_sym(info->objfmt_elf->elf_symtab, entry); + + elf_symtab_set_nonzero(entry, sect, 0, STB_LOCAL, + is_sect ? STT_SECTION : 0, NULL, 0); + + if (is_sect) + return 0; + } + + if (precbc) + value = yasm_bc_next_offset(precbc); + elf_symtab_set_nonzero(entry, sect, 0, 0, 0, NULL, &value); + + return 0; +} + +static yasm_objfmt * +elf_objfmt_create_common(yasm_object *object, yasm_objfmt_module *module, + int bits_pref, + const elf_machine_handler **elf_march_out) +{ + yasm_objfmt_elf *objfmt_elf = yasm_xmalloc(sizeof(yasm_objfmt_elf)); + yasm_symrec *filesym; + elf_symtab_entry *entry; + const elf_machine_handler *elf_march; + + objfmt_elf->objfmt.module = module; + elf_march = elf_set_arch(object->arch, object->symtab, bits_pref); + if (!elf_march) { + yasm_xfree(objfmt_elf); + return NULL; + } + if (elf_march_out) + *elf_march_out = elf_march; + + objfmt_elf->shstrtab = elf_strtab_create(); + objfmt_elf->strtab = elf_strtab_create(); + objfmt_elf->elf_symtab = elf_symtab_create(); + + /* FIXME: misuse of NULL bytecode here; it works, but only barely. */ + filesym = yasm_symtab_define_label(object->symtab, ".file", NULL, 0, 0); + if (!object->deb_filename) { + object->deb_filename = yasm_replace_path( + module->replace_map, module->replace_map_size, + object->src_filename, strlen(object->src_filename)); + } + /* Put in current input filename; we'll replace it in output() */ + objfmt_elf->file_strtab_entry = + elf_strtab_append_str(objfmt_elf->strtab, object->deb_filename); + entry = elf_symtab_entry_create(objfmt_elf->file_strtab_entry, filesym); + yasm_symrec_add_data(filesym, &elf_symrec_data, entry); + elf_symtab_set_nonzero(entry, NULL, SHN_ABS, STB_LOCAL, STT_FILE, NULL, + NULL); + elf_symtab_append_entry(objfmt_elf->elf_symtab, entry); + + /* FIXME: misuse of NULL bytecode */ + objfmt_elf->dotdotsym = + yasm_symtab_define_label(object->symtab, "..sym", NULL, 0, 0); + + return (yasm_objfmt *)objfmt_elf; +} + +static yasm_objfmt * +elf_objfmt_create(yasm_object *object) +{ + const elf_machine_handler *elf_march; + yasm_objfmt *objfmt; + yasm_objfmt_elf *objfmt_elf; + + objfmt = elf_objfmt_create_common(object, &yasm_elf_LTX_objfmt, 0, + &elf_march); + if (objfmt) { + objfmt_elf = (yasm_objfmt_elf *)objfmt; + /* Figure out which bitness of object format to use */ + if (strcmp (elf_march->machine, "x32") == 0) + objfmt_elf->objfmt.module = &yasm_elfx32_LTX_objfmt; + else if (elf_march->bits == 32) + objfmt_elf->objfmt.module = &yasm_elf32_LTX_objfmt; + else if (elf_march->bits == 64) + objfmt_elf->objfmt.module = &yasm_elf64_LTX_objfmt; + } + return objfmt; +} + +static yasm_objfmt * +elf32_objfmt_create(yasm_object *object) +{ + return elf_objfmt_create_common(object, &yasm_elf32_LTX_objfmt, 32, NULL); +} + +static yasm_objfmt * +elf64_objfmt_create(yasm_object *object) +{ + return elf_objfmt_create_common(object, &yasm_elf64_LTX_objfmt, 64, NULL); +} + +static yasm_objfmt * +elfx32_objfmt_create(yasm_object *object) +{ + return elf_objfmt_create_common(object, &yasm_elfx32_LTX_objfmt, 32, NULL); +} + +static long +elf_objfmt_output_align(FILE *f, unsigned int align) +{ + long pos; + unsigned long delta; + if (!is_exp2(align)) + yasm_internal_error("requested alignment not a power of two"); + + pos = ftell(f); + if (pos == -1) { + yasm_error_set(YASM_ERROR_IO, + N_("could not get file position on output file")); + return -1; + } + delta = align - (pos & (align-1)); + if (delta != align) { + pos += delta; + if (fseek(f, pos, SEEK_SET) < 0) { + yasm_error_set(YASM_ERROR_IO, + N_("could not set file position on output file")); + return -1; + } + } + return pos; +} + +static int +elf_objfmt_output_reloc(yasm_symrec *sym, yasm_bytecode *bc, + unsigned char *buf, unsigned int destsize, + unsigned int valsize, int warn, void *d) +{ + elf_reloc_entry *reloc; + elf_objfmt_output_info *info = d; + yasm_intnum *zero; + int retval; + + reloc = elf_reloc_entry_create(sym, NULL, + yasm_intnum_create_uint(bc->offset), 0, valsize, 0); + if (reloc == NULL) { + yasm_error_set(YASM_ERROR_TYPE, N_("elf: invalid relocation size")); + return 1; + } + /* allocate .rel[a] sections on a need-basis */ + elf_secthead_append_reloc(info->sect, info->shead, reloc); + + zero = yasm_intnum_create_uint(0); + elf_handle_reloc_addend(zero, reloc, 0); + retval = yasm_arch_intnum_tobytes(info->object->arch, zero, buf, destsize, + valsize, 0, bc, warn); + yasm_intnum_destroy(zero); + return retval; +} + +static int +elf_objfmt_output_value(yasm_value *value, unsigned char *buf, + unsigned int destsize, unsigned long offset, + yasm_bytecode *bc, int warn, /*@null@*/ void *d) +{ + /*@null@*/ elf_objfmt_output_info *info = (elf_objfmt_output_info *)d; + /*@dependent@*/ /*@null@*/ yasm_intnum *intn; + unsigned long intn_val; + /*@null@*/ elf_reloc_entry *reloc = NULL; + int retval; + unsigned int valsize = value->size; + + if (info == NULL) + yasm_internal_error("null info struct"); + + if (value->abs) + value->abs = yasm_expr_simplify(value->abs, 1); + + /* Try to output constant and PC-relative section-local first. + * Note this does NOT output any value with a SEG, WRT, external, + * cross-section, or non-PC-relative reference (those are handled below). + */ + switch (yasm_value_output_basic(value, buf, destsize, bc, warn, + info->object->arch)) { + case -1: + return 1; + case 0: + break; + default: + return 0; + } + + /* Handle other expressions, with relocation if necessary */ + if (value->seg_of || value->section_rel || value->rshift > 0) { + yasm_error_set(YASM_ERROR_TOO_COMPLEX, + N_("elf: relocation too complex")); + return 1; + } + + intn_val = 0; + if (value->rel) { + yasm_sym_vis vis = yasm_symrec_get_visibility(value->rel); + /*@dependent@*/ /*@null@*/ yasm_symrec *sym = value->rel; + /*@dependent@*/ /*@null@*/ yasm_symrec *wrt = value->wrt; + + if (wrt == info->objfmt_elf->dotdotsym) + wrt = NULL; + else if (wrt && elf_is_wrt_sym_relative(wrt)) + ; + else if (wrt && elf_is_wrt_pos_adjusted(wrt)) + intn_val = offset + bc->offset; + else if (vis == YASM_SYM_LOCAL) { + yasm_bytecode *sym_precbc; + /* Local symbols need relocation to their section's start, and + * add in the offset of the bytecode (within the target section) + * into the abs portion. + * + * This is only done if the symbol is relocated against the + * section instead of the symbol itself. + */ + if (yasm_symrec_get_label(sym, &sym_precbc)) { + /* Relocate to section start */ + yasm_section *sym_sect = yasm_bc_get_section(sym_precbc); + /*@null@*/ elf_secthead *sym_shead; + sym_shead = yasm_section_get_data(sym_sect, &elf_section_data); + assert(sym_shead != NULL); + sym = elf_secthead_get_sym(sym_shead); + + intn_val = yasm_bc_next_offset(sym_precbc); + } + } + + /* For PC-relative, need to add offset of expression within bc. */ + if (value->curpos_rel) + intn_val += offset; + + /* Check for _GLOBAL_OFFSET_TABLE_ symbol reference */ + reloc = elf_reloc_entry_create(sym, wrt, + yasm_intnum_create_uint(bc->offset + offset), value->curpos_rel, + valsize, sym == info->GOT_sym); + if (reloc == NULL) { + yasm_error_set(YASM_ERROR_TYPE, + N_("elf: invalid relocation (WRT or size)")); + return 1; + } + /* allocate .rel[a] sections on a need-basis */ + elf_secthead_append_reloc(info->sect, info->shead, reloc); + } + + intn = yasm_intnum_create_uint(intn_val); + + if (value->abs) { + yasm_intnum *intn2 = yasm_expr_get_intnum(&value->abs, 0); + if (!intn2) { + yasm_error_set(YASM_ERROR_TOO_COMPLEX, + N_("elf: relocation too complex")); + yasm_intnum_destroy(intn); + return 1; + } + yasm_intnum_calc(intn, YASM_EXPR_ADD, intn2); + } + + if (reloc) + elf_handle_reloc_addend(intn, reloc, offset); + retval = yasm_arch_intnum_tobytes(info->object->arch, intn, buf, destsize, + valsize, 0, bc, warn); + yasm_intnum_destroy(intn); + return retval; +} + +static int +elf_objfmt_output_bytecode(yasm_bytecode *bc, /*@null@*/ void *d) +{ + /*@null@*/ elf_objfmt_output_info *info = (elf_objfmt_output_info *)d; + unsigned char buf[256]; + /*@null@*/ /*@only@*/ unsigned char *bigbuf; + unsigned long size = 256; + int gap; + + if (info == NULL) + yasm_internal_error("null info struct"); + + bigbuf = yasm_bc_tobytes(bc, buf, &size, &gap, info, + elf_objfmt_output_value, elf_objfmt_output_reloc); + + /* Don't bother doing anything else if size ended up being 0. */ + if (size == 0) { + if (bigbuf) + yasm_xfree(bigbuf); + return 0; + } + else { + yasm_intnum *bcsize = yasm_intnum_create_uint(size); + elf_secthead_add_size(info->shead, bcsize); + yasm_intnum_destroy(bcsize); + } + + /* Warn that gaps are converted to 0 and write out the 0's. */ + if (gap) { + unsigned long left; + yasm_warn_set(YASM_WARN_UNINIT_CONTENTS, + N_("uninitialized space declared in code/data section: zeroing")); + /* Write out in chunks */ + memset(buf, 0, 256); + left = size; + while (left > 256) { + fwrite(buf, 256, 1, info->f); + left -= 256; + } + fwrite(buf, left, 1, info->f); + } else { + /* Output buf (or bigbuf if non-NULL) to file */ + fwrite(bigbuf ? bigbuf : buf, (size_t)size, 1, info->f); + } + + /* If bigbuf was allocated, free it */ + if (bigbuf) + yasm_xfree(bigbuf); + + return 0; +} + +static int +elf_objfmt_output_section(yasm_section *sect, /*@null@*/ void *d) +{ + /*@null@*/ elf_objfmt_output_info *info = (elf_objfmt_output_info *)d; + /*@dependent@*/ /*@null@*/ elf_secthead *shead; + long pos; + char *relname; + const char *sectname; + + if (info == NULL) + yasm_internal_error("null info struct"); + shead = yasm_section_get_data(sect, &elf_section_data); + if (shead == NULL) + yasm_internal_error("no associated data"); + + if (elf_secthead_get_align(shead) == 0) + elf_secthead_set_align(shead, yasm_section_get_align(sect)); + + /* don't output header-only sections */ + if ((elf_secthead_get_type(shead) & SHT_NOBITS) == SHT_NOBITS) + { + yasm_bytecode *last = yasm_section_bcs_last(sect); + if (last) { + yasm_intnum *sectsize; + sectsize = yasm_intnum_create_uint(yasm_bc_next_offset(last)); + elf_secthead_add_size(shead, sectsize); + yasm_intnum_destroy(sectsize); + } + elf_secthead_set_index(shead, ++info->sindex); + return 0; + } + + if ((pos = ftell(info->f)) == -1) { + yasm_error_set(YASM_ERROR_IO, + N_("couldn't read position on output stream")); + yasm_errwarn_propagate(info->errwarns, 0); + } + pos = elf_secthead_set_file_offset(shead, pos); + if (fseek(info->f, pos, SEEK_SET) < 0) { + yasm_error_set(YASM_ERROR_IO, N_("couldn't seek on output stream")); + yasm_errwarn_propagate(info->errwarns, 0); + } + + info->sect = sect; + info->shead = shead; + yasm_section_bcs_traverse(sect, info->errwarns, info, + elf_objfmt_output_bytecode); + + elf_secthead_set_index(shead, ++info->sindex); + + /* No relocations to output? Go on to next section */ + if (elf_secthead_write_relocs_to_file(info->f, sect, shead, + info->errwarns) == 0) + return 0; + elf_secthead_set_rel_index(shead, ++info->sindex); + + /* name the relocation section .rel[a].foo */ + sectname = yasm_section_get_name(sect); + relname = elf_secthead_name_reloc_section(sectname); + elf_secthead_set_rel_name(shead, + elf_strtab_append_str(info->objfmt_elf->shstrtab, relname)); + yasm_xfree(relname); + + return 0; +} + +static int +elf_objfmt_output_secthead(yasm_section *sect, /*@null@*/ void *d) +{ + /*@null@*/ elf_objfmt_output_info *info = (elf_objfmt_output_info *)d; + /*@dependent@*/ /*@null@*/ elf_secthead *shead; + + if (info == NULL) + yasm_internal_error("null info struct"); + shead = yasm_section_get_data(sect, &elf_section_data); + if (shead == NULL) + yasm_internal_error("no section header attached to section"); + + if(elf_secthead_write_to_file(info->f, shead, info->sindex+1)) + info->sindex++; + + /* output strtab headers here? */ + + /* relocation entries for .foo are stored in section .rel[a].foo */ + if(elf_secthead_write_rel_to_file(info->f, 3, sect, shead, + info->sindex+1)) + info->sindex++; + + return 0; +} + +static void +elf_objfmt_output(yasm_object *object, FILE *f, int all_syms, + yasm_errwarns *errwarns) +{ + yasm_objfmt_elf *objfmt_elf = (yasm_objfmt_elf *)object->objfmt; + elf_objfmt_output_info info; + build_symtab_info buildsym_info; + long pos; + unsigned long elf_shead_addr; + elf_secthead *esdn; + unsigned long elf_strtab_offset, elf_shstrtab_offset, elf_symtab_offset; + unsigned long elf_strtab_size, elf_shstrtab_size, elf_symtab_size; + elf_strtab_entry *elf_strtab_name, *elf_shstrtab_name, *elf_symtab_name; + unsigned long elf_symtab_nlocal; + + info.object = object; + info.objfmt_elf = objfmt_elf; + info.errwarns = errwarns; + info.f = f; + info.GOT_sym = yasm_symtab_get(object->symtab, "_GLOBAL_OFFSET_TABLE_"); + + if (!object->deb_filename) { + object->deb_filename = yasm_replace_path( + objfmt_elf->objfmt.module->replace_map, objfmt_elf->objfmt.module->replace_map_size, + object->src_filename, strlen(object->src_filename)); + } + /* Update filename strtab */ + elf_strtab_entry_set_str(objfmt_elf->file_strtab_entry, + object->deb_filename); + + /* Allocate space for Ehdr by seeking forward */ + if (fseek(f, (long)(elf_proghead_get_size()), SEEK_SET) < 0) { + yasm_error_set(YASM_ERROR_IO, N_("could not seek on output file")); + yasm_errwarn_propagate(errwarns, 0); + return; + } + + /* add all (local) syms to symtab because relocation needs a symtab index + * if all_syms, register them by name. if not, use strtab entry 0 */ + buildsym_info.object = object; + buildsym_info.objfmt_elf = objfmt_elf; + buildsym_info.errwarns = errwarns; + buildsym_info.local_names = all_syms; + yasm_symtab_traverse(object->symtab, &buildsym_info, + elf_objfmt_build_symtab); + elf_symtab_nlocal = elf_symtab_assign_indices(objfmt_elf->elf_symtab); + + /* output known sections - includes reloc sections which aren't in yasm's + * list. Assign indices as we go. */ + info.sindex = 3; + if (yasm_object_sections_traverse(object, &info, + elf_objfmt_output_section)) + return; + + /* add final sections to the shstrtab */ + elf_strtab_name = elf_strtab_append_str(objfmt_elf->shstrtab, ".strtab"); + elf_symtab_name = elf_strtab_append_str(objfmt_elf->shstrtab, ".symtab"); + elf_shstrtab_name = elf_strtab_append_str(objfmt_elf->shstrtab, + ".shstrtab"); + + /* output .shstrtab */ + if ((pos = elf_objfmt_output_align(f, 4)) == -1) { + yasm_errwarn_propagate(errwarns, 0); + return; + } + elf_shstrtab_offset = (unsigned long) pos; + elf_shstrtab_size = elf_strtab_output_to_file(f, objfmt_elf->shstrtab); + + /* output .strtab */ + if ((pos = elf_objfmt_output_align(f, 4)) == -1) { + yasm_errwarn_propagate(errwarns, 0); + return; + } + elf_strtab_offset = (unsigned long) pos; + elf_strtab_size = elf_strtab_output_to_file(f, objfmt_elf->strtab); + + /* output .symtab - last section so all others have indexes */ + if ((pos = elf_objfmt_output_align(f, 4)) == -1) { + yasm_errwarn_propagate(errwarns, 0); + return; + } + elf_symtab_offset = (unsigned long) pos; + elf_symtab_size = elf_symtab_write_to_file(f, objfmt_elf->elf_symtab, + errwarns); + + /* output section header table */ + if ((pos = elf_objfmt_output_align(f, 16)) == -1) { + yasm_errwarn_propagate(errwarns, 0); + return; + } + elf_shead_addr = (unsigned long) pos; + + /* stabs debugging support */ + if (strcmp(yasm_dbgfmt_keyword(object->dbgfmt), "stabs")==0) { + yasm_section *stabsect = yasm_object_find_general(object, ".stab"); + yasm_section *stabstrsect = + yasm_object_find_general(object, ".stabstr"); + if (stabsect && stabstrsect) { + elf_secthead *stab = + yasm_section_get_data(stabsect, &elf_section_data); + elf_secthead *stabstr = + yasm_section_get_data(stabstrsect, &elf_section_data); + if (stab && stabstr) { + elf_secthead_set_link(stab, elf_secthead_get_index(stabstr)); + } + else + yasm_internal_error(N_("missing .stab or .stabstr section/data")); + } + } + + /* output dummy section header - 0 */ + info.sindex = 0; + + esdn = elf_secthead_create(NULL, SHT_NULL, 0, 0, 0); + elf_secthead_set_index(esdn, 0); + elf_secthead_write_to_file(f, esdn, 0); + elf_secthead_destroy(esdn); + + esdn = elf_secthead_create(elf_shstrtab_name, SHT_STRTAB, 0, + elf_shstrtab_offset, elf_shstrtab_size); + elf_secthead_set_index(esdn, 1); + elf_secthead_write_to_file(f, esdn, 1); + elf_secthead_destroy(esdn); + + esdn = elf_secthead_create(elf_strtab_name, SHT_STRTAB, 0, + elf_strtab_offset, elf_strtab_size); + elf_secthead_set_index(esdn, 2); + elf_secthead_write_to_file(f, esdn, 2); + elf_secthead_destroy(esdn); + + esdn = elf_secthead_create(elf_symtab_name, SHT_SYMTAB, 0, + elf_symtab_offset, elf_symtab_size); + elf_secthead_set_index(esdn, 3); + elf_secthead_set_info(esdn, elf_symtab_nlocal); + elf_secthead_set_link(esdn, 2); /* for .strtab, which is index 2 */ + elf_secthead_write_to_file(f, esdn, 3); + elf_secthead_destroy(esdn); + + info.sindex = 3; + /* output remaining section headers */ + yasm_object_sections_traverse(object, &info, elf_objfmt_output_secthead); + + /* output Ehdr */ + if (fseek(f, 0, SEEK_SET) < 0) { + yasm_error_set(YASM_ERROR_IO, N_("could not seek on output file")); + yasm_errwarn_propagate(errwarns, 0); + return; + } + + elf_proghead_write_to_file(f, elf_shead_addr, info.sindex+1, 1); +} + +static void +elf_objfmt_destroy(yasm_objfmt *objfmt) +{ + yasm_objfmt_elf *objfmt_elf = (yasm_objfmt_elf *)objfmt; + elf_symtab_destroy(objfmt_elf->elf_symtab); + elf_strtab_destroy(objfmt_elf->shstrtab); + elf_strtab_destroy(objfmt_elf->strtab); + yasm_xfree(objfmt); +} + +static void +elf_objfmt_init_new_section(yasm_section *sect, unsigned long line) +{ + yasm_object *object = yasm_section_get_object(sect); + const char *sectname = yasm_section_get_name(sect); + yasm_objfmt_elf *objfmt_elf = (yasm_objfmt_elf *)object->objfmt; + elf_secthead *esd; + yasm_symrec *sym; + elf_strtab_entry *name = elf_strtab_append_str(objfmt_elf->shstrtab, + sectname); + + elf_section_type type=SHT_PROGBITS; + elf_size entsize=0; + + if (yasm__strcasecmp(sectname, ".stab")==0) { + entsize = 12; + } else if (yasm__strcasecmp(sectname, ".stabstr")==0) { + type = SHT_STRTAB; + } + + esd = elf_secthead_create(name, type, 0, 0, 0); + elf_secthead_set_entsize(esd, entsize); + yasm_section_add_data(sect, &elf_section_data, esd); + sym = yasm_symtab_define_label(object->symtab, sectname, + yasm_section_bcs_first(sect), 1, line); + + elf_secthead_set_sym(esd, sym); +} + +static yasm_section * +elf_objfmt_add_default_section(yasm_object *object) +{ + yasm_section *retval; + int isnew; + + retval = yasm_object_get_general(object, ".text", 16, 1, 0, &isnew, 0); + if (isnew) + { + elf_secthead *esd = yasm_section_get_data(retval, &elf_section_data); + elf_secthead_set_typeflags(esd, SHT_PROGBITS, + SHF_ALLOC + SHF_EXECINSTR); + yasm_section_set_default(retval, 1); + } + return retval; +} + +struct elf_section_switch_data { + /*@only@*/ /*@null@*/ yasm_intnum *align_intn; + unsigned long flags; + unsigned long type; + int gasflags; + int stdsect; +}; + +/* GAS-style flags */ +static int +elf_helper_gasflags(void *obj, yasm_valparam *vp, unsigned long line, void *d, + /*@unused@*/ uintptr_t arg) +{ + struct elf_section_switch_data *data = (struct elf_section_switch_data *)d; + const char *s = yasm_vp_string(vp); + size_t i; + + if (!s) { + yasm_error_set(YASM_ERROR_VALUE, + N_("non-string section attribute")); + return -1; + } + + if (data->stdsect && strlen(s) == 0) { + data->gasflags = 1; + return 0; + } + + data->flags = 0; + for (i=0; i<strlen(s); i++) { + switch (s[i]) { + case 'a': + data->flags |= SHF_ALLOC; + break; + case 'w': + data->flags |= SHF_WRITE; + break; + case 'x': + data->flags |= SHF_EXECINSTR; + break; + case 'M': + data->flags |= SHF_MERGE; + break; + case 'S': + data->flags |= SHF_STRINGS; + break; + case 'G': + data->flags |= SHF_GROUP; + break; + case 'T': + data->flags |= SHF_TLS; + break; + default: + yasm_warn_set(YASM_WARN_GENERAL, + N_("unrecognized section attribute: `%c'"), + s[i]); + } + } + + data->gasflags = 1; + return 0; +} + +static /*@observer@*/ /*@null@*/ yasm_section * +elf_objfmt_section_switch(yasm_object *object, yasm_valparamhead *valparams, + /*@null@*/ yasm_valparamhead *objext_valparams, + unsigned long line) +{ + yasm_valparam *vp; + yasm_section *retval; + int isnew; + unsigned long align = 4; + int flags_override = 0; + const char *sectname; + int resonly = 0; + + struct elf_section_switch_data data; + + static const yasm_dir_help help[] = { + { "alloc", 0, yasm_dir_helper_flag_or, + offsetof(struct elf_section_switch_data, flags), SHF_ALLOC }, + { "exec", 0, yasm_dir_helper_flag_or, + offsetof(struct elf_section_switch_data, flags), SHF_EXECINSTR }, + { "write", 0, yasm_dir_helper_flag_or, + offsetof(struct elf_section_switch_data, flags), SHF_WRITE }, + { "tls", 0, yasm_dir_helper_flag_or, + offsetof(struct elf_section_switch_data, flags), SHF_TLS }, + { "progbits", 0, yasm_dir_helper_flag_set, + offsetof(struct elf_section_switch_data, type), SHT_PROGBITS }, + { "noalloc", 0, yasm_dir_helper_flag_and, + offsetof(struct elf_section_switch_data, flags), SHF_ALLOC }, + { "noexec", 0, yasm_dir_helper_flag_and, + offsetof(struct elf_section_switch_data, flags), SHF_EXECINSTR }, + { "nowrite", 0, yasm_dir_helper_flag_and, + offsetof(struct elf_section_switch_data, flags), SHF_WRITE }, + { "notls", 0, yasm_dir_helper_flag_and, + offsetof(struct elf_section_switch_data, flags), SHF_TLS }, + { "noprogbits", 0, yasm_dir_helper_flag_set, + offsetof(struct elf_section_switch_data, type), SHT_NOBITS }, + { "nobits", 0, yasm_dir_helper_flag_set, + offsetof(struct elf_section_switch_data, type), SHT_NOBITS }, + { "gasflags", 1, elf_helper_gasflags, 0, 0 }, + { "align", 1, yasm_dir_helper_intn, + offsetof(struct elf_section_switch_data, align_intn), 0 } + }; + /*@only@*/ /*@null@*/ yasm_expr *merge_expr = NULL; + /*@dependent@*/ /*@null@*/ const yasm_intnum *merge_intn = NULL; + elf_secthead *esd; + + data.align_intn = NULL; + data.flags = SHF_ALLOC; + data.type = SHT_PROGBITS; + data.gasflags = 0; + data.stdsect = 1; + + vp = yasm_vps_first(valparams); + sectname = yasm_vp_string(vp); + if (!sectname) + return NULL; + vp = yasm_vps_next(vp); + + if (strcmp(sectname, ".bss") == 0) { + data.type = SHT_NOBITS; + data.flags = SHF_ALLOC + SHF_WRITE; + resonly = 1; + } else if (strcmp(sectname, ".data") == 0) { + data.type = SHT_PROGBITS; + data.flags = SHF_ALLOC + SHF_WRITE; + } else if (strcmp(sectname, ".tdata") == 0) { + data.type = SHT_PROGBITS; + data.flags = SHF_ALLOC + SHF_WRITE + SHF_TLS; + } else if (strcmp(sectname, ".rodata") == 0) { + data.type = SHT_PROGBITS; + data.flags = SHF_ALLOC; + } else if (strcmp(sectname, ".text") == 0) { + align = 16; + data.type = SHT_PROGBITS; + data.flags = SHF_ALLOC + SHF_EXECINSTR; + } else if (strcmp(sectname, ".comment") == 0) { + align = 0; + data.type = SHT_PROGBITS; + data.flags = 0; + } else { + /* Default to code */ + align = 1; + data.stdsect = 0; + } + + flags_override = yasm_dir_helper(object, vp, line, help, NELEMS(help), + &data, yasm_dir_helper_valparam_warn); + if (flags_override < 0) + return NULL; /* error occurred */ + + if (data.align_intn) { + align = yasm_intnum_get_uint(data.align_intn); + yasm_intnum_destroy(data.align_intn); + + /* Alignments must be a power of two. */ + if (!is_exp2(align)) { + yasm_error_set(YASM_ERROR_VALUE, + N_("argument to `%s' is not a power of two"), + "align"); + return NULL; + } + } + + /* Handle merge entity size */ + if (data.flags & SHF_MERGE) { + if (objext_valparams && (vp = yasm_vps_first(objext_valparams)) + && !vp->val) { + if (!(merge_expr = yasm_vp_expr(vp, object->symtab, line)) || + !(merge_intn = yasm_expr_get_intnum(&merge_expr, 0))) + yasm_warn_set(YASM_WARN_GENERAL, + N_("invalid merge entity size")); + } else { + yasm_warn_set(YASM_WARN_GENERAL, + N_("entity size for SHF_MERGE not specified")); + data.flags &= ~SHF_MERGE; + } + } + + retval = yasm_object_get_general(object, sectname, align, + (data.flags & SHF_EXECINSTR) != 0, + resonly, &isnew, line); + + esd = yasm_section_get_data(retval, &elf_section_data); + + if (isnew || yasm_section_is_default(retval)) { + yasm_section_set_default(retval, 0); + elf_secthead_set_typeflags(esd, data.type, data.flags); + if (merge_intn) + elf_secthead_set_entsize(esd, yasm_intnum_get_uint(merge_intn)); + yasm_section_set_align(retval, align, line); + } else if (flags_override && !data.gasflags) + yasm_warn_set(YASM_WARN_GENERAL, + N_("section flags ignored on section redeclaration")); + if (merge_expr) + yasm_expr_destroy(merge_expr); + return retval; +} + +static /*@observer@*/ /*@null@*/ yasm_symrec * +elf_objfmt_get_special_sym(yasm_object *object, const char *name, + const char *parser) +{ + if (yasm__strcasecmp(name, "sym") == 0) { + yasm_objfmt_elf *objfmt_elf = (yasm_objfmt_elf *)object->objfmt; + return objfmt_elf->dotdotsym; + } + return elf_get_special_sym(name, parser); +} + +static void +dir_type(yasm_object *object, yasm_valparamhead *valparams, + yasm_valparamhead *objext_valparams, unsigned long line) +{ + yasm_objfmt_elf *objfmt_elf = (yasm_objfmt_elf *)object->objfmt; + yasm_valparam *vp = yasm_vps_first(valparams); + const char *symname = yasm_vp_id(vp); + /* Get symbol elf data */ + yasm_symrec *sym = yasm_symtab_use(object->symtab, symname, line); + elf_symtab_entry *entry = yasm_symrec_get_data(sym, &elf_symrec_data); + /*@null@*/ const char *type; + + /* Create entry if necessary */ + if (!entry) { + entry = elf_symtab_entry_create( + elf_strtab_append_str(objfmt_elf->strtab, symname), sym); + yasm_symrec_add_data(sym, &elf_symrec_data, entry); + } + + /* Pull new type from param */ + vp = yasm_vps_next(vp); + if (vp && !vp->val && (type = yasm_vp_id(vp))) { + if (yasm__strcasecmp(type, "function") == 0) + elf_sym_set_type(entry, STT_FUNC); + else if (yasm__strcasecmp(type, "object") == 0) + elf_sym_set_type(entry, STT_OBJECT); + else if (yasm__strcasecmp(type, "tls_object") == 0) + elf_sym_set_type(entry, STT_TLS); + else if (yasm__strcasecmp(type, "notype") == 0) + elf_sym_set_type(entry, STT_NOTYPE); + else + yasm_warn_set(YASM_WARN_GENERAL, + N_("unrecognized symbol type `%s'"), type); + } else + yasm_error_set(YASM_ERROR_SYNTAX, N_("no type specified")); +} + +static void +dir_size(yasm_object *object, yasm_valparamhead *valparams, + yasm_valparamhead *objext_valparams, unsigned long line) +{ + yasm_objfmt_elf *objfmt_elf = (yasm_objfmt_elf *)object->objfmt; + yasm_valparam *vp = yasm_vps_first(valparams); + const char *symname = yasm_vp_id(vp); + /* Get symbol elf data */ + yasm_symrec *sym = yasm_symtab_use(object->symtab, symname, line); + elf_symtab_entry *entry = yasm_symrec_get_data(sym, &elf_symrec_data); + /*@only@*/ /*@null@*/ yasm_expr *size; + + /* Create entry if necessary */ + if (!entry) { + entry = elf_symtab_entry_create( + elf_strtab_append_str(objfmt_elf->strtab, symname), sym); + yasm_symrec_add_data(sym, &elf_symrec_data, entry); + } + + /* Pull new size from param */ + vp = yasm_vps_next(vp); + if (vp && !vp->val && (size = yasm_vp_expr(vp, object->symtab, line))) + elf_sym_set_size(entry, size); + else + yasm_error_set(YASM_ERROR_SYNTAX, N_("no size specified")); +} + +static void +dir_weak(yasm_object *object, yasm_valparamhead *valparams, + yasm_valparamhead *objext_valparams, unsigned long line) +{ + yasm_objfmt_elf *objfmt_elf = (yasm_objfmt_elf *)object->objfmt; + yasm_valparam *vp = yasm_vps_first(valparams); + const char *symname = yasm_vp_id(vp); + yasm_symrec *sym = yasm_symtab_declare(object->symtab, symname, + YASM_SYM_GLOBAL, line); + elf_objfmt_symtab_append(objfmt_elf, sym, SHN_UNDEF, STB_WEAK, 0, + STV_DEFAULT, NULL, NULL, object); +} + +static void +dir_ident(yasm_object *object, yasm_valparamhead *valparams, + yasm_valparamhead *objext_valparams, unsigned long line) +{ + yasm_valparamhead sect_vps; + yasm_datavalhead dvs; + yasm_section *comment; + yasm_valparam *vp; + yasm_valparam *vp2; + + /* Accept, but do nothing with empty ident */ + if (!valparams) + return; + vp = yasm_vps_first(valparams); + if (!vp) + return; + + /* Put ident data into .comment section */ + yasm_vps_initialize(§_vps); + vp2 = yasm_vp_create_string(NULL, yasm__xstrdup(".comment")); + yasm_vps_append(§_vps, vp2); + comment = elf_objfmt_section_switch(object, §_vps, NULL, line); + yasm_vps_delete(§_vps); + + /* To match GAS output, if the comment section is empty, put an + * initial 0 byte in the section. + */ + if (yasm_section_bcs_first(comment) == yasm_section_bcs_last(comment)) { + yasm_dvs_initialize(&dvs); + yasm_dvs_append(&dvs, yasm_dv_create_expr( + yasm_expr_create_ident( + yasm_expr_int(yasm_intnum_create_uint(0)), line))); + yasm_section_bcs_append(comment, + yasm_bc_create_data(&dvs, 1, 0, object->arch, line)); + } + + yasm_dvs_initialize(&dvs); + do { + const char *s = yasm_vp_string(vp); + if (!s) { + yasm_error_set(YASM_ERROR_VALUE, + N_(".comment requires string parameters")); + yasm_dvs_delete(&dvs); + return; + } + yasm_dvs_append(&dvs, + yasm_dv_create_string(yasm__xstrdup(s), strlen(s))); + } while ((vp = yasm_vps_next(vp))); + + yasm_section_bcs_append(comment, + yasm_bc_create_data(&dvs, 1, 1, object->arch, line)); +} + +/* Define valid debug formats to use with this object format */ +static const char *elf_objfmt_dbgfmt_keywords[] = { + "null", + "stabs", + "dwarf2", + NULL +}; + +static const yasm_directive elf_objfmt_directives[] = { + { ".type", "gas", dir_type, YASM_DIR_ID_REQUIRED }, + { ".size", "gas", dir_size, YASM_DIR_ID_REQUIRED }, + { ".weak", "gas", dir_weak, YASM_DIR_ID_REQUIRED }, + { ".ident", "gas", dir_ident, YASM_DIR_ANY }, + { "type", "nasm", dir_type, YASM_DIR_ID_REQUIRED }, + { "size", "nasm", dir_size, YASM_DIR_ID_REQUIRED }, + { "weak", "nasm", dir_weak, YASM_DIR_ID_REQUIRED }, + { "ident", "nasm", dir_ident, YASM_DIR_ANY }, + { NULL, NULL, NULL, 0 } +}; + +static const char *elf_nasm_stdmac[] = { + "%imacro type 1+.nolist", + "[type %1]", + "%endmacro", + "%imacro size 1+.nolist", + "[size %1]", + "%endmacro", + "%imacro weak 1+.nolist", + "[weak %1]", + "%endmacro", + NULL +}; + +static const yasm_stdmac elf_objfmt_stdmacs[] = { + { "nasm", "nasm", elf_nasm_stdmac }, + { NULL, NULL, NULL } +}; + +/* Define objfmt structure -- see objfmt.h for details */ +yasm_objfmt_module yasm_elf_LTX_objfmt = { + "ELF", + "elf", + "o", + 32, + 0, + elf_objfmt_dbgfmt_keywords, + "null", + elf_objfmt_directives, + elf_objfmt_stdmacs, + elf_objfmt_create, + elf_objfmt_output, + elf_objfmt_destroy, + elf_objfmt_add_default_section, + elf_objfmt_init_new_section, + elf_objfmt_section_switch, + elf_objfmt_get_special_sym +}; + +yasm_objfmt_module yasm_elf32_LTX_objfmt = { + "ELF (32-bit)", + "elf32", + "o", + 32, + 0, + elf_objfmt_dbgfmt_keywords, + "null", + elf_objfmt_directives, + elf_objfmt_stdmacs, + elf32_objfmt_create, + elf_objfmt_output, + elf_objfmt_destroy, + elf_objfmt_add_default_section, + elf_objfmt_init_new_section, + elf_objfmt_section_switch, + elf_objfmt_get_special_sym +}; + +yasm_objfmt_module yasm_elf64_LTX_objfmt = { + "ELF (64-bit)", + "elf64", + "o", + 64, + 0, + elf_objfmt_dbgfmt_keywords, + "null", + elf_objfmt_directives, + elf_objfmt_stdmacs, + elf64_objfmt_create, + elf_objfmt_output, + elf_objfmt_destroy, + elf_objfmt_add_default_section, + elf_objfmt_init_new_section, + elf_objfmt_section_switch, + elf_objfmt_get_special_sym +}; + +yasm_objfmt_module yasm_elfx32_LTX_objfmt = { + "ELF (x32)", + "elfx32", + "o", + 64, + 0, + elf_objfmt_dbgfmt_keywords, + "null", + elf_objfmt_directives, + elf_objfmt_stdmacs, + elfx32_objfmt_create, + elf_objfmt_output, + elf_objfmt_destroy, + elf_objfmt_add_default_section, + elf_objfmt_init_new_section, + elf_objfmt_section_switch, + elf_objfmt_get_special_sym +}; diff --git a/contrib/tools/yasm/modules/objfmts/elf/elf-x86-amd64.c b/contrib/tools/yasm/modules/objfmts/elf/elf-x86-amd64.c new file mode 100644 index 0000000000..3ba376af03 --- /dev/null +++ b/contrib/tools/yasm/modules/objfmts/elf/elf-x86-amd64.c @@ -0,0 +1,256 @@ +/* + * ELF object format helpers - x86:amd64 + * + * Copyright (C) 2004-2007 Michael Urman + * + * 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> +#define YASM_OBJFMT_ELF_INTERNAL +#include "elf.h" +#include "elf-machine.h" + +static elf_machine_ssym elf_x86_amd64_ssyms[] = { + {"pltoff", ELF_SSYM_SYM_RELATIVE, R_X86_64_PLTOFF64, 64}, + {"plt", ELF_SSYM_SYM_RELATIVE, R_X86_64_PLT32, 32}, + {"gotplt", ELF_SSYM_SYM_RELATIVE, R_X86_64_GOTPLT64, 64}, + {"gotoff", ELF_SSYM_SYM_RELATIVE, R_X86_64_GOTOFF64, 64}, + {"gotpcrel", ELF_SSYM_SYM_RELATIVE, R_X86_64_GOTPCREL, 32}, + {"tlsgd", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL, + R_X86_64_TLSGD, 32}, + {"tlsld", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL, + R_X86_64_TLSLD, 32}, + {"gottpoff", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL, + R_X86_64_GOTTPOFF, 32}, + {"tpoff", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL, + R_X86_64_TPOFF32, 32}, + {"dtpoff", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL, + R_X86_64_DTPOFF32, 32}, + {"got", ELF_SSYM_SYM_RELATIVE, R_X86_64_GOT32, 32}, + {"tlsdesc", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL, + R_X86_64_GOTPC32_TLSDESC, 32}, + {"tlscall", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL, + R_X86_64_TLSDESC_CALL, 32} +}; + +static int +elf_x86_amd64_accepts_reloc(size_t val, yasm_symrec *wrt) +{ + if (wrt) { + const elf_machine_ssym *ssym = (elf_machine_ssym *) + yasm_symrec_get_data(wrt, &elf_ssym_symrec_data); + if (!ssym || val != ssym->size) + return 0; + return 1; + } + return (val&(val-1)) ? 0 : ((val & (8|16|32|64)) != 0); +} + +static void +elf_x86_amd64_write_symtab_entry(unsigned char *bufp, + elf_symtab_entry *entry, + yasm_intnum *value_intn, + yasm_intnum *size_intn) +{ + YASM_WRITE_32_L(bufp, entry->name ? entry->name->index : 0); + YASM_WRITE_8(bufp, ELF64_ST_INFO(entry->bind, entry->type)); + YASM_WRITE_8(bufp, ELF64_ST_OTHER(entry->vis)); + if (entry->sect) { + elf_secthead *shead = + yasm_section_get_data(entry->sect, &elf_section_data); + if (!shead) + yasm_internal_error(N_("symbol references section without data")); + YASM_WRITE_16_L(bufp, shead->index); + } else { + YASM_WRITE_16_L(bufp, entry->index); + } + YASM_WRITE_64I_L(bufp, value_intn); + YASM_WRITE_64I_L(bufp, size_intn); +} + +static void +elf_x86_amd64_write_secthead(unsigned char *bufp, elf_secthead *shead) +{ + YASM_WRITE_32_L(bufp, shead->name ? shead->name->index : 0); + YASM_WRITE_32_L(bufp, shead->type); + YASM_WRITE_64Z_L(bufp, shead->flags); + YASM_WRITE_64Z_L(bufp, 0); /* vmem address */ + YASM_WRITE_64Z_L(bufp, shead->offset); + YASM_WRITE_64I_L(bufp, shead->size); + + YASM_WRITE_32_L(bufp, shead->link); + YASM_WRITE_32_L(bufp, shead->info); + + YASM_WRITE_64Z_L(bufp, shead->align); + YASM_WRITE_64Z_L(bufp, shead->entsize); +} + +static void +elf_x86_amd64_write_secthead_rel(unsigned char *bufp, + elf_secthead *shead, + elf_section_index symtab_idx, + elf_section_index sindex) +{ + yasm_intnum *nreloc; + yasm_intnum *relocsize; + + YASM_WRITE_32_L(bufp, shead->rel_name ? shead->rel_name->index : 0); + YASM_WRITE_32_L(bufp, SHT_RELA); + YASM_WRITE_64Z_L(bufp, 0); + YASM_WRITE_64Z_L(bufp, 0); + YASM_WRITE_64Z_L(bufp, shead->rel_offset); + + nreloc = yasm_intnum_create_uint(shead->nreloc); + relocsize = yasm_intnum_create_uint(RELOC64A_SIZE); + yasm_intnum_calc(relocsize, YASM_EXPR_MUL, nreloc); + YASM_WRITE_64I_L(bufp, relocsize); /* size */ + yasm_intnum_destroy(nreloc); + yasm_intnum_destroy(relocsize); + + YASM_WRITE_32_L(bufp, symtab_idx); /* link: symtab index */ + YASM_WRITE_32_L(bufp, shead->index); /* info: relocated's index */ + YASM_WRITE_64Z_L(bufp, RELOC64_ALIGN); /* align */ + YASM_WRITE_64Z_L(bufp, RELOC64A_SIZE); /* entity size */ +} + +static void +elf_x86_amd64_handle_reloc_addend(yasm_intnum *intn, + elf_reloc_entry *reloc, + unsigned long offset) +{ + /* .rela: copy value out as addend, replace original with 0 */ + reloc->addend = yasm_intnum_copy(intn); + yasm_intnum_zero(intn); +} + +static unsigned int +elf_x86_amd64_map_reloc_info_to_type(elf_reloc_entry *reloc) +{ + if (reloc->wrt) { + const elf_machine_ssym *ssym = (elf_machine_ssym *) + yasm_symrec_get_data(reloc->wrt, &elf_ssym_symrec_data); + if (!ssym || reloc->valsize != ssym->size) + yasm_internal_error(N_("Unsupported WRT")); + + /* Force TLS type; this is required by the linker. */ + if (ssym->sym_rel & ELF_SSYM_THREAD_LOCAL) { + elf_symtab_entry *esym; + + esym = yasm_symrec_get_data(reloc->reloc.sym, &elf_symrec_data); + if (esym) + esym->type = STT_TLS; + } + /* Map PC-relative GOT to appropriate relocation */ + if (reloc->rtype_rel && ssym->reloc == R_X86_64_GOT32) + return (unsigned char) R_X86_64_GOTPCREL; + return (unsigned char) ssym->reloc; + } else if (reloc->is_GOT_sym && reloc->valsize == 32) { + return (unsigned char) R_X86_64_GOTPC32; + } else if (reloc->is_GOT_sym && reloc->valsize == 64) { + return (unsigned char) R_X86_64_GOTPC64; + } else if (reloc->rtype_rel) { + switch (reloc->valsize) { + case 8: return (unsigned char) R_X86_64_PC8; + case 16: return (unsigned char) R_X86_64_PC16; + case 32: return (unsigned char) R_X86_64_PC32; + case 64: return (unsigned char) R_X86_64_PC64; + default: yasm_internal_error(N_("Unsupported relocation size")); + } + } else { + switch (reloc->valsize) { + case 8: return (unsigned char) R_X86_64_8; + case 16: return (unsigned char) R_X86_64_16; + case 32: return (unsigned char) R_X86_64_32; + case 64: return (unsigned char) R_X86_64_64; + default: yasm_internal_error(N_("Unsupported relocation size")); + } + } + return 0; +} + +static void +elf_x86_amd64_write_reloc(unsigned char *bufp, elf_reloc_entry *reloc, + unsigned int r_type, unsigned int r_sym) +{ + YASM_WRITE_64I_L(bufp, reloc->reloc.addr); + /*YASM_WRITE_64_L(bufp, ELF64_R_INFO(r_sym, r_type));*/ + YASM_WRITE_64C_L(bufp, r_sym, r_type); + if (reloc->addend) + YASM_WRITE_64I_L(bufp, reloc->addend); + else { + YASM_WRITE_32_L(bufp, 0); + YASM_WRITE_32_L(bufp, 0); + } +} + +static void +elf_x86_amd64_write_proghead(unsigned char **bufpp, + elf_offset secthead_addr, + unsigned long secthead_count, + elf_section_index shstrtab_index) +{ + unsigned char *bufp = *bufpp; + unsigned char *buf = bufp-4; + YASM_WRITE_8(bufp, ELFCLASS64); /* elf class */ + YASM_WRITE_8(bufp, ELFDATA2LSB); /* data encoding :: MSB? */ + YASM_WRITE_8(bufp, EV_CURRENT); /* elf version */ + YASM_WRITE_8(bufp, ELFOSABI_SYSV); /* os/abi */ + YASM_WRITE_8(bufp, 0); /* SYSV v3 ABI=0 */ + while (bufp-buf < EI_NIDENT) /* e_ident padding */ + YASM_WRITE_8(bufp, 0); + + YASM_WRITE_16_L(bufp, ET_REL); /* e_type - object file */ + YASM_WRITE_16_L(bufp, EM_X86_64); /* e_machine - or others */ + YASM_WRITE_32_L(bufp, EV_CURRENT); /* elf version */ + YASM_WRITE_64Z_L(bufp, 0); /* e_entry */ + YASM_WRITE_64Z_L(bufp, 0); /* e_phoff */ + YASM_WRITE_64Z_L(bufp, secthead_addr); /* e_shoff secthead off */ + + YASM_WRITE_32_L(bufp, 0); /* e_flags */ + YASM_WRITE_16_L(bufp, EHDR64_SIZE); /* e_ehsize */ + YASM_WRITE_16_L(bufp, 0); /* e_phentsize */ + YASM_WRITE_16_L(bufp, 0); /* e_phnum */ + YASM_WRITE_16_L(bufp, SHDR64_SIZE); /* e_shentsize */ + YASM_WRITE_16_L(bufp, secthead_count); /* e_shnum */ + YASM_WRITE_16_L(bufp, shstrtab_index); /* e_shstrndx */ + *bufpp = bufp; +} + +const elf_machine_handler +elf_machine_handler_x86_amd64 = { + "x86", "amd64", ".rela", + SYMTAB64_SIZE, SYMTAB64_ALIGN, RELOC64A_SIZE, SHDR64_SIZE, EHDR64_SIZE, + elf_x86_amd64_accepts_reloc, + elf_x86_amd64_write_symtab_entry, + elf_x86_amd64_write_secthead, + elf_x86_amd64_write_secthead_rel, + elf_x86_amd64_handle_reloc_addend, + elf_x86_amd64_map_reloc_info_to_type, + elf_x86_amd64_write_reloc, + elf_x86_amd64_write_proghead, + elf_x86_amd64_ssyms, + sizeof(elf_x86_amd64_ssyms)/sizeof(elf_x86_amd64_ssyms[0]), + 64 +}; diff --git a/contrib/tools/yasm/modules/objfmts/elf/elf-x86-x32.c b/contrib/tools/yasm/modules/objfmts/elf/elf-x86-x32.c new file mode 100644 index 0000000000..40a25a12a7 --- /dev/null +++ b/contrib/tools/yasm/modules/objfmts/elf/elf-x86-x32.c @@ -0,0 +1,251 @@ +/* + * ELF object format helpers - x86:x32 + * + * Copyright (C) 2012 Michael Urman and H.J. Lu + * + * 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> +#define YASM_OBJFMT_ELF_INTERNAL +#include "elf.h" +#include "elf-machine.h" + +static elf_machine_ssym elf_x86_x32_ssyms[] = { + {"plt", ELF_SSYM_SYM_RELATIVE, R_X86_64_PLT32, 32}, + {"gotpcrel", ELF_SSYM_SYM_RELATIVE, R_X86_64_GOTPCREL, 32}, + {"tlsgd", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL, + R_X86_64_TLSGD, 32}, + {"tlsld", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL, + R_X86_64_TLSLD, 32}, + {"gottpoff", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL, + R_X86_64_GOTTPOFF, 32}, + {"tpoff", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL, + R_X86_64_TPOFF32, 32}, + {"dtpoff", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL, + R_X86_64_DTPOFF32, 32}, + {"got", ELF_SSYM_SYM_RELATIVE, R_X86_64_GOT32, 32}, + {"tlsdesc", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL, + R_X86_64_GOTPC32_TLSDESC, 32}, + {"tlscall", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL, + R_X86_64_TLSDESC_CALL, 32} +}; + +static int +elf_x86_x32_accepts_reloc(size_t val, yasm_symrec *wrt) +{ + if (wrt) { + const elf_machine_ssym *ssym = (elf_machine_ssym *) + yasm_symrec_get_data(wrt, &elf_ssym_symrec_data); + if (!ssym || val != ssym->size) + return 0; + return 1; + } + return (val&(val-1)) ? 0 : ((val & (8|16|32)) != 0); +} + +static void +elf_x86_x32_write_symtab_entry(unsigned char *bufp, + elf_symtab_entry *entry, + yasm_intnum *value_intn, + yasm_intnum *size_intn) +{ + YASM_WRITE_32_L(bufp, entry->name ? entry->name->index : 0); + YASM_WRITE_32I_L(bufp, value_intn); + YASM_WRITE_32I_L(bufp, size_intn); + + YASM_WRITE_8(bufp, ELF32_ST_INFO(entry->bind, entry->type)); + YASM_WRITE_8(bufp, ELF32_ST_OTHER(entry->vis)); + if (entry->sect) { + elf_secthead *shead = + yasm_section_get_data(entry->sect, &elf_section_data); + if (!shead) + yasm_internal_error(N_("symbol references section without data")); + YASM_WRITE_16_L(bufp, shead->index); + } else { + YASM_WRITE_16_L(bufp, entry->index); + } +} + +static void +elf_x86_x32_write_secthead(unsigned char *bufp, elf_secthead *shead) +{ + YASM_WRITE_32_L(bufp, shead->name ? shead->name->index : 0); + YASM_WRITE_32_L(bufp, shead->type); + YASM_WRITE_32_L(bufp, shead->flags); + YASM_WRITE_32_L(bufp, 0); /* vmem address */ + YASM_WRITE_32_L(bufp, shead->offset); + YASM_WRITE_32I_L(bufp, shead->size); + + YASM_WRITE_32_L(bufp, shead->link); + YASM_WRITE_32_L(bufp, shead->info); + + YASM_WRITE_32_L(bufp, shead->align); + YASM_WRITE_32_L(bufp, shead->entsize); +} + +static void +elf_x86_x32_write_secthead_rel(unsigned char *bufp, + elf_secthead *shead, + elf_section_index symtab_idx, + elf_section_index sindex) +{ + yasm_intnum *nreloc; + yasm_intnum *relocsize; + + YASM_WRITE_32_L(bufp, shead->rel_name ? shead->rel_name->index : 0); + YASM_WRITE_32_L(bufp, SHT_RELA); + YASM_WRITE_32_L(bufp, 0); + YASM_WRITE_32_L(bufp, 0); + YASM_WRITE_32_L(bufp, shead->rel_offset); + + nreloc = yasm_intnum_create_uint(shead->nreloc); + relocsize = yasm_intnum_create_uint(RELOC32A_SIZE); + yasm_intnum_calc(relocsize, YASM_EXPR_MUL, nreloc); + YASM_WRITE_32I_L(bufp, relocsize); /* size */ + yasm_intnum_destroy(nreloc); + yasm_intnum_destroy(relocsize); + + YASM_WRITE_32_L(bufp, symtab_idx); /* link: symtab index */ + YASM_WRITE_32_L(bufp, shead->index); /* info: relocated's index */ + YASM_WRITE_32_L(bufp, RELOC32_ALIGN); /* align */ + YASM_WRITE_32_L(bufp, RELOC32A_SIZE); /* entity size */ +} + +static void +elf_x86_x32_handle_reloc_addend(yasm_intnum *intn, + elf_reloc_entry *reloc, + unsigned long offset) +{ + /* .rela: copy value out as addend, replace original with 0 */ + reloc->addend = yasm_intnum_copy(intn); + yasm_intnum_zero(intn); +} + +static unsigned int +elf_x86_x32_map_reloc_info_to_type(elf_reloc_entry *reloc) +{ + if (reloc->wrt) { + const elf_machine_ssym *ssym = (elf_machine_ssym *) + yasm_symrec_get_data(reloc->wrt, &elf_ssym_symrec_data); + if (!ssym || reloc->valsize != ssym->size) + yasm_internal_error(N_("Unsupported WRT")); + + /* Force TLS type; this is required by the linker. */ + if (ssym->sym_rel & ELF_SSYM_THREAD_LOCAL) { + elf_symtab_entry *esym; + + esym = yasm_symrec_get_data(reloc->reloc.sym, &elf_symrec_data); + if (esym) + esym->type = STT_TLS; + } + /* Map PC-relative GOT to appropriate relocation */ + if (reloc->rtype_rel && ssym->reloc == R_X86_64_GOT32) + return (unsigned char) R_X86_64_GOTPCREL; + return (unsigned char) ssym->reloc; + } else if (reloc->is_GOT_sym && reloc->valsize == 32) { + return (unsigned char) R_X86_64_GOTPC32; + } else if (reloc->is_GOT_sym && reloc->valsize == 64) { + yasm_internal_error(N_("Unsupported relocation size")); + } else if (reloc->rtype_rel) { + switch (reloc->valsize) { + case 8: return (unsigned char) R_X86_64_PC8; + case 16: return (unsigned char) R_X86_64_PC16; + case 32: return (unsigned char) R_X86_64_PC32; + default: yasm_internal_error(N_("Unsupported relocation size")); + } + } else { + switch (reloc->valsize) { + case 8: return (unsigned char) R_X86_64_8; + case 16: return (unsigned char) R_X86_64_16; + case 32: return (unsigned char) R_X86_64_32; + case 64: return (unsigned char) R_X86_64_64; + default: yasm_internal_error(N_("Unsupported relocation size")); + } + } + return 0; +} + +static void +elf_x86_x32_write_reloc(unsigned char *bufp, elf_reloc_entry *reloc, + unsigned int r_type, unsigned int r_sym) +{ + YASM_WRITE_32I_L(bufp, reloc->reloc.addr); + YASM_WRITE_32_L(bufp, ELF32_R_INFO((unsigned long)r_sym, (unsigned char)r_type)); + if (reloc->addend) + YASM_WRITE_32I_L(bufp, reloc->addend); + else { + YASM_WRITE_32_L(bufp, 0); + } +} + +static void +elf_x86_x32_write_proghead(unsigned char **bufpp, + elf_offset secthead_addr, + unsigned long secthead_count, + elf_section_index shstrtab_index) +{ + unsigned char *bufp = *bufpp; + unsigned char *buf = bufp-4; + YASM_WRITE_8(bufp, ELFCLASS32); /* elf class */ + YASM_WRITE_8(bufp, ELFDATA2LSB); /* data encoding :: MSB? */ + YASM_WRITE_8(bufp, EV_CURRENT); /* elf version */ + YASM_WRITE_8(bufp, ELFOSABI_SYSV); /* os/abi */ + YASM_WRITE_8(bufp, 0); /* SYSV v3 ABI=0 */ + while (bufp-buf < EI_NIDENT) /* e_ident padding */ + YASM_WRITE_8(bufp, 0); + + YASM_WRITE_16_L(bufp, ET_REL); /* e_type - object file */ + YASM_WRITE_16_L(bufp, EM_X86_64); /* e_machine - or others */ + YASM_WRITE_32_L(bufp, EV_CURRENT); /* elf version */ + YASM_WRITE_32_L(bufp, 0); /* e_entry */ + YASM_WRITE_32_L(bufp, 0); /* e_phoff */ + YASM_WRITE_32_L(bufp, secthead_addr); /* e_shoff secthead off */ + + YASM_WRITE_32_L(bufp, 0); /* e_flags */ + YASM_WRITE_16_L(bufp, EHDR32_SIZE); /* e_ehsize */ + YASM_WRITE_16_L(bufp, 0); /* e_phentsize */ + YASM_WRITE_16_L(bufp, 0); /* e_phnum */ + YASM_WRITE_16_L(bufp, SHDR32_SIZE); /* e_shentsize */ + YASM_WRITE_16_L(bufp, secthead_count); /* e_shnum */ + YASM_WRITE_16_L(bufp, shstrtab_index); /* e_shstrndx */ + *bufpp = bufp; +} + +const elf_machine_handler +elf_machine_handler_x86_x32 = { + "x86", "x32", ".rela", + SYMTAB32_SIZE, SYMTAB32_ALIGN, RELOC32A_SIZE, SHDR32_SIZE, EHDR32_SIZE, + elf_x86_x32_accepts_reloc, + elf_x86_x32_write_symtab_entry, + elf_x86_x32_write_secthead, + elf_x86_x32_write_secthead_rel, + elf_x86_x32_handle_reloc_addend, + elf_x86_x32_map_reloc_info_to_type, + elf_x86_x32_write_reloc, + elf_x86_x32_write_proghead, + elf_x86_x32_ssyms, + sizeof(elf_x86_x32_ssyms)/sizeof(elf_x86_x32_ssyms[0]), + 32 +}; diff --git a/contrib/tools/yasm/modules/objfmts/elf/elf-x86-x86.c b/contrib/tools/yasm/modules/objfmts/elf/elf-x86-x86.c new file mode 100644 index 0000000000..d79ec6eabd --- /dev/null +++ b/contrib/tools/yasm/modules/objfmts/elf/elf-x86-x86.c @@ -0,0 +1,242 @@ +/* + * ELF object format helpers - x86:x86 + * + * Copyright (C) 2004-2007 Michael Urman + * + * 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> +#define YASM_OBJFMT_ELF_INTERNAL +#include "elf.h" +#include "elf-machine.h" + +static elf_machine_ssym elf_x86_x86_ssyms[] = { + {"plt", ELF_SSYM_SYM_RELATIVE, R_386_PLT32, 32}, + {"gotoff", 0, R_386_GOTOFF, 32}, + /* special one for NASM */ + {"gotpc", ELF_SSYM_CURPOS_ADJUST, R_386_GOTPC, 32}, + {"tlsgd", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL, + R_386_TLS_GD, 32}, + {"tlsldm", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL, + R_386_TLS_LDM, 32}, + {"gottpoff", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL, + R_386_TLS_IE_32, 32}, + {"tpoff", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL, + R_386_TLS_LE_32, 32}, + {"ntpoff", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL, + R_386_TLS_LE, 32}, + {"dtpoff", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL, + R_386_TLS_LDO_32, 32}, + {"gotntpoff", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL, + R_386_TLS_GOTIE, 32}, + {"indntpoff", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL, + R_386_TLS_IE, 32}, + {"got", ELF_SSYM_SYM_RELATIVE, R_386_GOT32, 32}, + {"tlsdesc", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL, + R_386_TLS_GOTDESC, 32}, + {"tlscall", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL, + R_386_TLS_DESC_CALL, 32} +}; + +static int +elf_x86_x86_accepts_reloc(size_t val, yasm_symrec *wrt) +{ + if (wrt) { + const elf_machine_ssym *ssym = (elf_machine_ssym *) + yasm_symrec_get_data(wrt, &elf_ssym_symrec_data); + if (!ssym || val != ssym->size) + return 0; + return 1; + } + return (val&(val-1)) ? 0 : ((val & (8|16|32)) != 0); +} + +static void +elf_x86_x86_write_symtab_entry(unsigned char *bufp, + elf_symtab_entry *entry, + yasm_intnum *value_intn, + yasm_intnum *size_intn) +{ + YASM_WRITE_32_L(bufp, entry->name ? entry->name->index : 0); + YASM_WRITE_32I_L(bufp, value_intn); + YASM_WRITE_32I_L(bufp, size_intn); + + YASM_WRITE_8(bufp, ELF32_ST_INFO(entry->bind, entry->type)); + YASM_WRITE_8(bufp, ELF32_ST_OTHER(entry->vis)); + if (entry->sect) { + elf_secthead *shead = + yasm_section_get_data(entry->sect, &elf_section_data); + if (!shead) + yasm_internal_error(N_("symbol references section without data")); + YASM_WRITE_16_L(bufp, shead->index); + } else { + YASM_WRITE_16_L(bufp, entry->index); + } +} + +static void +elf_x86_x86_write_secthead(unsigned char *bufp, elf_secthead *shead) +{ + YASM_WRITE_32_L(bufp, shead->name ? shead->name->index : 0); + YASM_WRITE_32_L(bufp, shead->type); + YASM_WRITE_32_L(bufp, shead->flags); + YASM_WRITE_32_L(bufp, 0); /* vmem address */ + + YASM_WRITE_32_L(bufp, shead->offset); + YASM_WRITE_32I_L(bufp, shead->size); + YASM_WRITE_32_L(bufp, shead->link); + YASM_WRITE_32_L(bufp, shead->info); + + YASM_WRITE_32_L(bufp, shead->align); + YASM_WRITE_32_L(bufp, shead->entsize); + +} + +static void +elf_x86_x86_write_secthead_rel(unsigned char *bufp, + elf_secthead *shead, + elf_section_index symtab_idx, + elf_section_index sindex) +{ + YASM_WRITE_32_L(bufp, shead->rel_name ? shead->rel_name->index : 0); + YASM_WRITE_32_L(bufp, SHT_REL); + YASM_WRITE_32_L(bufp, 0); + YASM_WRITE_32_L(bufp, 0); + + YASM_WRITE_32_L(bufp, shead->rel_offset); + YASM_WRITE_32_L(bufp, RELOC32_SIZE * shead->nreloc);/* size */ + YASM_WRITE_32_L(bufp, symtab_idx); /* link: symtab index */ + YASM_WRITE_32_L(bufp, shead->index); /* info: relocated's index */ + + YASM_WRITE_32_L(bufp, RELOC32_ALIGN); /* align */ + YASM_WRITE_32_L(bufp, RELOC32_SIZE); /* entity size */ +} + +static void +elf_x86_x86_handle_reloc_addend(yasm_intnum *intn, + elf_reloc_entry *reloc, + unsigned long offset) +{ + if (!reloc->wrt && reloc->is_GOT_sym && reloc->valsize == 32 && offset != 0) + { + yasm_intnum *off_intn = yasm_intnum_create_uint(offset); + yasm_intnum_calc(intn, YASM_EXPR_ADD, off_intn); + yasm_intnum_destroy(off_intn); + } + return; /* .rel: Leave addend in intn */ +} + +static unsigned int +elf_x86_x86_map_reloc_info_to_type(elf_reloc_entry *reloc) +{ + if (reloc->wrt) { + const elf_machine_ssym *ssym = (elf_machine_ssym *) + yasm_symrec_get_data(reloc->wrt, &elf_ssym_symrec_data); + if (!ssym || reloc->valsize != ssym->size) + yasm_internal_error(N_("Unsupported WRT")); + + /* Force TLS type; this is required by the linker. */ + if (ssym->sym_rel & ELF_SSYM_THREAD_LOCAL) { + elf_symtab_entry *esym; + + esym = yasm_symrec_get_data(reloc->reloc.sym, &elf_symrec_data); + if (esym) + esym->type = STT_TLS; + } + return (unsigned char) ssym->reloc; + } else if (reloc->is_GOT_sym && reloc->valsize == 32) { + return (unsigned char) R_386_GOTPC; + } else if (reloc->rtype_rel) { + switch (reloc->valsize) { + case 8: return (unsigned char) R_386_PC8; + case 16: return (unsigned char) R_386_PC16; + case 32: return (unsigned char) R_386_PC32; + default: yasm_internal_error(N_("Unsupported relocation size")); + } + } else { + switch (reloc->valsize) { + case 8: return (unsigned char) R_386_8; + case 16: return (unsigned char) R_386_16; + case 32: return (unsigned char) R_386_32; + default: yasm_internal_error(N_("Unsupported relocation size")); + } + } + return 0; +} + +static void +elf_x86_x86_write_reloc(unsigned char *bufp, elf_reloc_entry *reloc, + unsigned int r_type, unsigned int r_sym) +{ + YASM_WRITE_32I_L(bufp, reloc->reloc.addr); + YASM_WRITE_32_L(bufp, ELF32_R_INFO((unsigned long)r_sym, (unsigned char)r_type)); +} + +static void +elf_x86_x86_write_proghead(unsigned char **bufpp, + elf_offset secthead_addr, + unsigned long secthead_count, + elf_section_index shstrtab_index) +{ + unsigned char *bufp = *bufpp; + unsigned char *buf = bufp-4; + YASM_WRITE_8(bufp, ELFCLASS32); /* elf class */ + YASM_WRITE_8(bufp, ELFDATA2LSB); /* data encoding :: MSB? */ + YASM_WRITE_8(bufp, EV_CURRENT); /* elf version */ + while (bufp-buf < EI_NIDENT) /* e_ident padding */ + YASM_WRITE_8(bufp, 0); + + YASM_WRITE_16_L(bufp, ET_REL); /* e_type - object file */ + YASM_WRITE_16_L(bufp, EM_386); /* e_machine - or others */ + YASM_WRITE_32_L(bufp, EV_CURRENT); /* elf version */ + YASM_WRITE_32_L(bufp, 0); /* e_entry exection startaddr */ + YASM_WRITE_32_L(bufp, 0); /* e_phoff program header off */ + YASM_WRITE_32_L(bufp, secthead_addr); /* e_shoff section header off */ + YASM_WRITE_32_L(bufp, 0); /* e_flags also by arch */ + YASM_WRITE_16_L(bufp, EHDR32_SIZE); /* e_ehsize */ + YASM_WRITE_16_L(bufp, 0); /* e_phentsize */ + YASM_WRITE_16_L(bufp, 0); /* e_phnum */ + YASM_WRITE_16_L(bufp, SHDR32_SIZE); /* e_shentsize */ + YASM_WRITE_16_L(bufp, secthead_count); /* e_shnum */ + YASM_WRITE_16_L(bufp, shstrtab_index); /* e_shstrndx */ + *bufpp = bufp; +} + +const elf_machine_handler +elf_machine_handler_x86_x86 = { + "x86", "x86", ".rel", + SYMTAB32_SIZE, SYMTAB32_ALIGN, RELOC32_SIZE, SHDR32_SIZE, EHDR32_SIZE, + elf_x86_x86_accepts_reloc, + elf_x86_x86_write_symtab_entry, + elf_x86_x86_write_secthead, + elf_x86_x86_write_secthead_rel, + elf_x86_x86_handle_reloc_addend, + elf_x86_x86_map_reloc_info_to_type, + elf_x86_x86_write_reloc, + elf_x86_x86_write_proghead, + elf_x86_x86_ssyms, + sizeof(elf_x86_x86_ssyms)/sizeof(elf_x86_x86_ssyms[0]), + 32 +}; diff --git a/contrib/tools/yasm/modules/objfmts/elf/elf.c b/contrib/tools/yasm/modules/objfmts/elf/elf.c new file mode 100644 index 0000000000..2486bba8df --- /dev/null +++ b/contrib/tools/yasm/modules/objfmts/elf/elf.c @@ -0,0 +1,960 @@ +/* + * ELF object format helpers + * + * Copyright (C) 2003-2007 Michael Urman + * + * 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> +#define YASM_OBJFMT_ELF_INTERNAL +#include "elf.h" +#include "elf-machine.h" + +static void elf_section_data_destroy(void *data); +static void elf_secthead_print(void *data, FILE *f, int indent_level); + +const yasm_assoc_data_callback elf_section_data = { + elf_section_data_destroy, + elf_secthead_print +}; + +static void elf_symrec_data_destroy(/*@only@*/ void *d); +static void elf_symtab_entry_print(void *data, FILE *f, int indent_level); +static void elf_ssym_symtab_entry_print(void *data, FILE *f, int indent_level); + +const yasm_assoc_data_callback elf_symrec_data = { + elf_symrec_data_destroy, + elf_symtab_entry_print +}; + +const yasm_assoc_data_callback elf_ssym_symrec_data = { + elf_symrec_data_destroy, + elf_ssym_symtab_entry_print +}; + +extern elf_machine_handler + elf_machine_handler_x86_x86, + elf_machine_handler_x86_amd64, + elf_machine_handler_x86_x32; + +static const elf_machine_handler *elf_machine_handlers[] = +{ + &elf_machine_handler_x86_x86, + &elf_machine_handler_x86_amd64, + &elf_machine_handler_x86_x32, + NULL +}; +static const elf_machine_handler elf_null_machine = {0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0}; +static elf_machine_handler const *elf_march = &elf_null_machine; +static yasm_symrec **elf_ssyms; + +const elf_machine_handler * +elf_set_arch(yasm_arch *arch, yasm_symtab *symtab, int bits_pref) +{ + const char *machine = yasm_arch_get_machine(arch); + int i; + + for (i=0, elf_march = elf_machine_handlers[0]; + elf_march != NULL; + elf_march = elf_machine_handlers[++i]) + { + if (yasm__strcasecmp(yasm_arch_keyword(arch), elf_march->arch)==0) { + if (yasm__strcasecmp(machine, elf_march->machine)==0) { + if (bits_pref == 0 || bits_pref == elf_march->bits) + break; + } else if (bits_pref == elf_march->bits + && yasm__strcasecmp(machine, "amd64") == 0 + && yasm__strcasecmp(elf_march->machine, "x32") == 0) + break; + } + } + + if (elf_march && elf_march->num_ssyms > 0) + { + /* Allocate "special" syms */ + elf_ssyms = + yasm_xmalloc(elf_march->num_ssyms * sizeof(yasm_symrec *)); + for (i=0; (unsigned int)i<elf_march->num_ssyms; i++) + { + /* FIXME: misuse of NULL bytecode */ + elf_ssyms[i] = yasm_symtab_define_label(symtab, + elf_march->ssyms[i].name, + NULL, 0, 0); + yasm_symrec_add_data(elf_ssyms[i], &elf_ssym_symrec_data, + (void*)&elf_march->ssyms[i]); + } + } + + return elf_march; +} + +yasm_symrec * +elf_get_special_sym(const char *name, const char *parser) +{ + int i; + for (i=0; (unsigned int)i<elf_march->num_ssyms; i++) { + if (yasm__strcasecmp(name, elf_march->ssyms[i].name) == 0) + return elf_ssyms[i]; + } + return NULL; +} + +/* reloc functions */ +int elf_ssym_has_flag(yasm_symrec *wrt, int flag); + +int +elf_is_wrt_sym_relative(yasm_symrec *wrt) +{ + return elf_ssym_has_flag(wrt, ELF_SSYM_SYM_RELATIVE); +} + +int +elf_is_wrt_pos_adjusted(yasm_symrec *wrt) +{ + return elf_ssym_has_flag(wrt, ELF_SSYM_CURPOS_ADJUST); +} + +int +elf_ssym_has_flag(yasm_symrec *wrt, int flag) +{ + int i; + for (i=0; (unsigned int)i<elf_march->num_ssyms; i++) { + if (elf_ssyms[i] == wrt) + return (elf_march->ssyms[i].sym_rel & flag) != 0; + } + return 0; +} + +/* takes ownership of addr */ +elf_reloc_entry * +elf_reloc_entry_create(yasm_symrec *sym, + yasm_symrec *wrt, + yasm_intnum *addr, + int rel, + size_t valsize, + int is_GOT_sym) +{ + elf_reloc_entry *entry; + + if (!elf_march->accepts_reloc) + yasm_internal_error(N_("Unsupported machine for ELF output")); + + if (!elf_march->accepts_reloc(valsize, wrt)) + { + if (addr) + yasm_intnum_destroy(addr); + return NULL; + } + + if (sym == NULL) + yasm_internal_error("sym is null"); + + entry = yasm_xmalloc(sizeof(elf_reloc_entry)); + entry->reloc.sym = sym; + entry->reloc.addr = addr; + entry->rtype_rel = rel; + entry->valsize = valsize; + entry->addend = NULL; + entry->wrt = wrt; + entry->is_GOT_sym = is_GOT_sym; + + return entry; +} + +void +elf_reloc_entry_destroy(void *entry) +{ + if (((elf_reloc_entry*)entry)->addend) + yasm_intnum_destroy(((elf_reloc_entry*)entry)->addend); + yasm_xfree(entry); +} + +/* strtab functions */ +elf_strtab_entry * +elf_strtab_entry_create(const char *str) +{ + elf_strtab_entry *entry = yasm_xmalloc(sizeof(elf_strtab_entry)); + entry->str = yasm__xstrdup(str); + entry->index = 0; + return entry; +} + +void +elf_strtab_entry_set_str(elf_strtab_entry *entry, const char *str) +{ + elf_strtab_entry *last; + if (entry->str) + yasm_xfree(entry->str); + entry->str = yasm__xstrdup(str); + + /* Update all following indices since string length probably changes */ + last = entry; + entry = STAILQ_NEXT(last, qlink); + while (entry) { + entry->index = last->index + (unsigned long)strlen(last->str) + 1; + last = entry; + entry = STAILQ_NEXT(last, qlink); + } +} + +elf_strtab_head * +elf_strtab_create() +{ + elf_strtab_head *strtab = yasm_xmalloc(sizeof(elf_strtab_head)); + elf_strtab_entry *entry = yasm_xmalloc(sizeof(elf_strtab_entry)); + + STAILQ_INIT(strtab); + entry->index = 0; + entry->str = yasm__xstrdup(""); + + STAILQ_INSERT_TAIL(strtab, entry, qlink); + return strtab; +} + +elf_strtab_entry * +elf_strtab_append_str(elf_strtab_head *strtab, const char *str) +{ + elf_strtab_entry *last, *entry; + + if (strtab == NULL) + yasm_internal_error("strtab is null"); + if (STAILQ_EMPTY(strtab)) + yasm_internal_error("strtab is missing initial dummy entry"); + + last = STAILQ_LAST(strtab, elf_strtab_entry, qlink); + + entry = elf_strtab_entry_create(str); + entry->index = last->index + (unsigned long)strlen(last->str) + 1; + + STAILQ_INSERT_TAIL(strtab, entry, qlink); + return entry; +} + +void +elf_strtab_destroy(elf_strtab_head *strtab) +{ + elf_strtab_entry *s1, *s2; + + if (strtab == NULL) + yasm_internal_error("strtab is null"); + if (STAILQ_EMPTY(strtab)) + yasm_internal_error("strtab is missing initial dummy entry"); + + s1 = STAILQ_FIRST(strtab); + while (s1 != NULL) { + s2 = STAILQ_NEXT(s1, qlink); + yasm_xfree(s1->str); + yasm_xfree(s1); + s1 = s2; + } + yasm_xfree(strtab); +} + +unsigned long +elf_strtab_output_to_file(FILE *f, elf_strtab_head *strtab) +{ + unsigned long size = 0; + elf_strtab_entry *entry; + + if (strtab == NULL) + yasm_internal_error("strtab is null"); + + /* consider optimizing tables here */ + STAILQ_FOREACH(entry, strtab, qlink) { + size_t len = 1 + strlen(entry->str); + fwrite(entry->str, len, 1, f); + size += (unsigned long)len; + } + return size; +} + + + +/* symtab functions */ +elf_symtab_entry * +elf_symtab_entry_create(elf_strtab_entry *name, + yasm_symrec *sym) +{ + elf_symtab_entry *entry = yasm_xmalloc(sizeof(elf_symtab_entry)); + entry->in_table = 0; + entry->sym = sym; + entry->sect = NULL; + entry->name = name; + entry->value = 0; + + entry->xsize = NULL; + entry->size = 0; + entry->index = 0; + entry->bind = 0; + entry->type = STT_NOTYPE; + entry->vis = STV_DEFAULT; + + return entry; +} + +static void +elf_symtab_entry_destroy(elf_symtab_entry *entry) +{ + if (entry == NULL) + yasm_internal_error("symtab entry is null"); + + yasm_xfree(entry); +} + +static void +elf_symrec_data_destroy(void *data) +{ + /* do nothing, as this stuff is in the symtab anyway... this speaks of bad + * design/use or this stuff, i fear */ + + /* watch for double-free here ... */ + /*elf_symtab_entry_destroy((elf_symtab_entry *)data);*/ +} + +static void +elf_symtab_entry_print(void *data, FILE *f, int indent_level) +{ + elf_symtab_entry *entry = data; + if (entry == NULL) + yasm_internal_error("symtab entry is null"); + + fprintf(f, "%*sbind=", indent_level, ""); + switch (entry->bind) { + case STB_LOCAL: fprintf(f, "local\n"); break; + case STB_GLOBAL: fprintf(f, "global\n"); break; + case STB_WEAK: fprintf(f, "weak\n"); break; + default: fprintf(f, "undef\n"); break; + } + fprintf(f, "%*stype=", indent_level, ""); + switch (entry->type) { + case STT_NOTYPE: fprintf(f, "notype\n"); break; + case STT_OBJECT: fprintf(f, "object\n"); break; + case STT_FUNC: fprintf(f, "func\n"); break; + case STT_SECTION: fprintf(f, "section\n");break; + case STT_FILE: fprintf(f, "file\n"); break; + default: fprintf(f, "undef\n"); break; + } + fprintf(f, "%*ssize=", indent_level, ""); + if (entry->xsize) + yasm_expr_print(entry->xsize, f); + else + fprintf(f, "%ld", entry->size); + fprintf(f, "\n"); +} + +static void +elf_ssym_symtab_entry_print(void *data, FILE *f, int indent_level) +{ + /* TODO */ +} + +elf_symtab_head * +elf_symtab_create() +{ + elf_symtab_head *symtab = yasm_xmalloc(sizeof(elf_symtab_head)); + elf_symtab_entry *entry = yasm_xmalloc(sizeof(elf_symtab_entry)); + + STAILQ_INIT(symtab); + entry->in_table = 1; + entry->sym = NULL; + entry->sect = NULL; + entry->name = NULL; + entry->value = 0; + entry->xsize = NULL; + entry->size = 0; + entry->index = SHN_UNDEF; + entry->bind = STB_LOCAL; + entry->type = STT_NOTYPE; + entry->vis = STV_DEFAULT; + entry->symindex = 0; + STAILQ_INSERT_TAIL(symtab, entry, qlink); + return symtab; +} + +void +elf_symtab_append_entry(elf_symtab_head *symtab, elf_symtab_entry *entry) +{ + if (symtab == NULL) + yasm_internal_error("symtab is null"); + if (entry == NULL) + yasm_internal_error("symtab entry is null"); + if (STAILQ_EMPTY(symtab)) + yasm_internal_error(N_("symtab is missing initial dummy entry")); + + STAILQ_INSERT_TAIL(symtab, entry, qlink); + entry->in_table = 1; +} + +void +elf_symtab_insert_local_sym(elf_symtab_head *symtab, elf_symtab_entry *entry) +{ + elf_symtab_entry *after = STAILQ_FIRST(symtab); + elf_symtab_entry *before = NULL; + + while (after && (after->bind == STB_LOCAL)) { + before = after; + if (before->type == STT_FILE) break; + after = STAILQ_NEXT(after, qlink); + } + STAILQ_INSERT_AFTER(symtab, before, entry, qlink); + entry->in_table = 1; +} + +void +elf_symtab_destroy(elf_symtab_head *symtab) +{ + elf_symtab_entry *s1, *s2; + + if (symtab == NULL) + yasm_internal_error("symtab is null"); + if (STAILQ_EMPTY(symtab)) + yasm_internal_error(N_("symtab is missing initial dummy entry")); + + s1 = STAILQ_FIRST(symtab); + while (s1 != NULL) { + s2 = STAILQ_NEXT(s1, qlink); + elf_symtab_entry_destroy(s1); + s1 = s2; + } + yasm_xfree(symtab); +} + +unsigned long +elf_symtab_assign_indices(elf_symtab_head *symtab) +{ + elf_symtab_entry *entry, *prev=NULL; + unsigned long last_local=0; + + if (symtab == NULL) + yasm_internal_error("symtab is null"); + if (STAILQ_EMPTY(symtab)) + yasm_internal_error(N_("symtab is missing initial dummy entry")); + + STAILQ_FOREACH(entry, symtab, qlink) { + if (prev) + entry->symindex = prev->symindex + 1; + if (entry->bind == STB_LOCAL) + last_local = entry->symindex; + prev = entry; + } + return last_local + 1; +} + +unsigned long +elf_symtab_write_to_file(FILE *f, elf_symtab_head *symtab, + yasm_errwarns *errwarns) +{ + unsigned char buf[SYMTAB_MAXSIZE], *bufp; + elf_symtab_entry *entry; + unsigned long size = 0; + + if (!symtab) + yasm_internal_error(N_("symtab is null")); + + STAILQ_FOREACH(entry, symtab, qlink) { + + yasm_intnum *size_intn=NULL, *value_intn=NULL; + bufp = buf; + + /* get size (if specified); expr overrides stored integer */ + if (entry->xsize) { + size_intn = yasm_intnum_copy( + yasm_expr_get_intnum(&entry->xsize, 1)); + if (!size_intn) { + yasm_error_set(YASM_ERROR_VALUE, + N_("size specifier not an integer expression")); + yasm_errwarn_propagate(errwarns, entry->xsize->line); + } + } + else + size_intn = yasm_intnum_create_uint(entry->size); + + /* get EQU value for constants */ + if (entry->sym) { + const yasm_expr *equ_expr_c; + equ_expr_c = yasm_symrec_get_equ(entry->sym); + + if (equ_expr_c != NULL) { + const yasm_intnum *equ_intn; + yasm_expr *equ_expr = yasm_expr_copy(equ_expr_c); + equ_intn = yasm_expr_get_intnum(&equ_expr, 1); + + if (equ_intn == NULL) { + yasm_error_set(YASM_ERROR_VALUE, + N_("EQU value not an integer expression")); + yasm_errwarn_propagate(errwarns, equ_expr->line); + } else + value_intn = yasm_intnum_copy(equ_intn); + entry->index = SHN_ABS; + yasm_expr_destroy(equ_expr); + } + } + if (value_intn == NULL) + value_intn = yasm_intnum_create_uint(entry->value); + + /* If symbol is in a TLS section, force its type to TLS. */ + if (entry->sym) { + yasm_bytecode *precbc; + yasm_section *sect; + elf_secthead *shead; + if (yasm_symrec_get_label(entry->sym, &precbc) && + (sect = yasm_bc_get_section(precbc)) && + (shead = yasm_section_get_data(sect, &elf_section_data)) && + shead->flags & SHF_TLS) { + entry->type = STT_TLS; + } + } + + if (!elf_march->write_symtab_entry || !elf_march->symtab_entry_size) + yasm_internal_error(N_("Unsupported machine for ELF output")); + elf_march->write_symtab_entry(bufp, entry, value_intn, size_intn); + fwrite(buf, elf_march->symtab_entry_size, 1, f); + size += elf_march->symtab_entry_size; + + yasm_intnum_destroy(size_intn); + yasm_intnum_destroy(value_intn); + } + return size; +} + +void elf_symtab_set_nonzero(elf_symtab_entry *entry, + yasm_section *sect, + elf_section_index sectidx, + elf_symbol_binding bind, + elf_symbol_type type, + yasm_expr *xsize, + elf_address *value) +{ + if (!entry) + yasm_internal_error("NULL entry"); + if (sect) entry->sect = sect; + if (sectidx) entry->index = sectidx; + if (bind) entry->bind = bind; + if (type) entry->type = type; + if (xsize) entry->xsize = xsize; + if (value) entry->value = *value; +} + +void +elf_sym_set_visibility(elf_symtab_entry *entry, + elf_symbol_vis vis) +{ + entry->vis = ELF_ST_VISIBILITY(vis); +} + +void +elf_sym_set_type(elf_symtab_entry *entry, + elf_symbol_type type) +{ + entry->type = type; +} + +void +elf_sym_set_size(elf_symtab_entry *entry, + struct yasm_expr *size) +{ + if (entry->xsize) + yasm_expr_destroy(entry->xsize); + entry->xsize = size; +} + +int +elf_sym_in_table(elf_symtab_entry *entry) +{ + return entry->in_table; +} + +elf_secthead * +elf_secthead_create(elf_strtab_entry *name, + elf_section_type type, + elf_section_flags flags, + elf_address offset, + elf_size size) +{ + elf_secthead *esd = yasm_xmalloc(sizeof(elf_secthead)); + + esd->type = type; + esd->flags = flags; + esd->offset = offset; + esd->size = yasm_intnum_create_uint(size); + esd->link = 0; + esd->info = 0; + esd->align = 0; + esd->entsize = 0; + esd->index = 0; + + esd->sym = NULL; + esd->name = name; + esd->index = 0; + esd->rel_name = NULL; + esd->rel_index = 0; + esd->rel_offset = 0; + esd->nreloc = 0; + + if (name && (strcmp(name->str, ".symtab") == 0)) { + if (!elf_march->symtab_entry_size || !elf_march->symtab_entry_align) + yasm_internal_error(N_("unsupported ELF format")); + esd->entsize = elf_march->symtab_entry_size; + esd->align = elf_march->symtab_entry_align; + } + + return esd; +} + +void +elf_secthead_destroy(elf_secthead *shead) +{ + if (shead == NULL) + yasm_internal_error(N_("shead is null")); + + yasm_intnum_destroy(shead->size); + + yasm_xfree(shead); +} + +static void +elf_section_data_destroy(void *data) +{ + elf_secthead_destroy((elf_secthead *)data); +} + +static void +elf_secthead_print(void *data, FILE *f, int indent_level) +{ + elf_secthead *sect = data; + fprintf(f, "%*sname=%s\n", indent_level, "", + sect->name ? sect->name->str : "<undef>"); + fprintf(f, "%*ssym=\n", indent_level, ""); + yasm_symrec_print(sect->sym, f, indent_level+1); + fprintf(f, "%*sindex=0x%x\n", indent_level, "", sect->index); + fprintf(f, "%*sflags=", indent_level, ""); + if (sect->flags & SHF_WRITE) + fprintf(f, "WRITE "); + if (sect->flags & SHF_ALLOC) + fprintf(f, "ALLOC "); + if (sect->flags & SHF_EXECINSTR) + fprintf(f, "EXEC "); + /*if (sect->flags & SHF_MASKPROC) + fprintf(f, "PROC-SPECIFIC"); */ + fprintf(f, "%*soffset=0x%lx\n", indent_level, "", sect->offset); + fprintf(f, "%*ssize=0x%lx\n", indent_level, "", + yasm_intnum_get_uint(sect->size)); + fprintf(f, "%*slink=0x%x\n", indent_level, "", sect->link); + fprintf(f, "%*salign=%lu\n", indent_level, "", sect->align); + fprintf(f, "%*snreloc=%ld\n", indent_level, "", sect->nreloc); +} + +unsigned long +elf_secthead_write_to_file(FILE *f, elf_secthead *shead, + elf_section_index sindex) +{ + unsigned char buf[SHDR_MAXSIZE], *bufp = buf; + shead->index = sindex; + + if (shead == NULL) + yasm_internal_error("shead is null"); + + if (!elf_march->write_secthead || !elf_march->secthead_size) + yasm_internal_error(N_("Unsupported machine for ELF output")); + elf_march->write_secthead(bufp, shead); + if (fwrite(buf, elf_march->secthead_size, 1, f)) + return elf_march->secthead_size; + yasm_internal_error(N_("Failed to write an elf section header")); + return 0; +} + +void +elf_secthead_append_reloc(yasm_section *sect, elf_secthead *shead, + elf_reloc_entry *reloc) +{ + if (sect == NULL) + yasm_internal_error("sect is null"); + if (shead == NULL) + yasm_internal_error("shead is null"); + if (reloc == NULL) + yasm_internal_error("reloc is null"); + + shead->nreloc++; + yasm_section_add_reloc(sect, (yasm_reloc *)reloc, elf_reloc_entry_destroy); +} + +char * +elf_secthead_name_reloc_section(const char *basesect) +{ + if (!elf_march->reloc_section_prefix) + { + yasm_internal_error(N_("Unsupported machine for ELF output")); + return NULL; + } + else + { + size_t prepend_length = strlen(elf_march->reloc_section_prefix); + char *sectname = yasm_xmalloc(prepend_length + strlen(basesect) + 1); + strcpy(sectname, elf_march->reloc_section_prefix); + strcat(sectname, basesect); + return sectname; + } +} + +void +elf_handle_reloc_addend(yasm_intnum *intn, + elf_reloc_entry *reloc, + unsigned long offset) +{ + if (!elf_march->handle_reloc_addend) + yasm_internal_error(N_("Unsupported machine for ELF output")); + elf_march->handle_reloc_addend(intn, reloc, offset); +} + +unsigned long +elf_secthead_write_rel_to_file(FILE *f, elf_section_index symtab_idx, + yasm_section *sect, elf_secthead *shead, + elf_section_index sindex) +{ + unsigned char buf[SHDR_MAXSIZE], *bufp = buf; + + if (shead == NULL) + yasm_internal_error("shead is null"); + + if (!yasm_section_relocs_first(sect)) + return 0; /* no relocations, no .rel.* section header */ + + shead->rel_index = sindex; + + if (!elf_march->write_secthead_rel || !elf_march->secthead_size) + yasm_internal_error(N_("Unsupported machine for ELF output")); + elf_march->write_secthead_rel(bufp, shead, symtab_idx, sindex); + if (fwrite(buf, elf_march->secthead_size, 1, f)) + return elf_march->secthead_size; + yasm_internal_error(N_("Failed to write an elf section header")); + return 0; +} + +unsigned long +elf_secthead_write_relocs_to_file(FILE *f, yasm_section *sect, + elf_secthead *shead, yasm_errwarns *errwarns) +{ + elf_reloc_entry *reloc; + unsigned char buf[RELOC_MAXSIZE], *bufp; + unsigned long size = 0; + long pos; + + if (shead == NULL) + yasm_internal_error("shead is null"); + + reloc = (elf_reloc_entry *)yasm_section_relocs_first(sect); + if (!reloc) + return 0; + + /* first align section to multiple of 4 */ + pos = ftell(f); + if (pos == -1) { + yasm_error_set(YASM_ERROR_IO, + N_("couldn't read position on output stream")); + yasm_errwarn_propagate(errwarns, 0); + } + pos = (pos + 3) & ~3; + if (fseek(f, pos, SEEK_SET) < 0) { + yasm_error_set(YASM_ERROR_IO, N_("couldn't seek on output stream")); + yasm_errwarn_propagate(errwarns, 0); + } + shead->rel_offset = (unsigned long)pos; + + + while (reloc) { + unsigned int r_type=0, r_sym; + elf_symtab_entry *esym; + + esym = yasm_symrec_get_data(reloc->reloc.sym, &elf_symrec_data); + if (esym) + r_sym = esym->symindex; + else + r_sym = STN_UNDEF; + + if (!elf_march->map_reloc_info_to_type) + yasm_internal_error(N_("Unsupported arch/machine for elf output")); + r_type = elf_march->map_reloc_info_to_type(reloc); + + bufp = buf; + if (!elf_march->write_reloc || !elf_march->reloc_entry_size) + yasm_internal_error(N_("Unsupported arch/machine for elf output")); + elf_march->write_reloc(bufp, reloc, r_type, r_sym); + fwrite(buf, elf_march->reloc_entry_size, 1, f); + size += elf_march->reloc_entry_size; + + reloc = (elf_reloc_entry *) + yasm_section_reloc_next((yasm_reloc *)reloc); + } + return size; +} + +elf_section_type +elf_secthead_get_type(elf_secthead *shead) +{ + return shead->type; +} + +void +elf_secthead_set_typeflags(elf_secthead *shead, elf_section_type type, + elf_section_flags flags) +{ + shead->type = type; + shead->flags = flags; +} + +int +elf_secthead_is_empty(elf_secthead *shead) +{ + return yasm_intnum_is_zero(shead->size); +} + +yasm_symrec * +elf_secthead_get_sym(elf_secthead *shead) +{ + return shead->sym; +} + +elf_section_index +elf_secthead_get_index(elf_secthead *shead) +{ + return shead->index; +} + +unsigned long +elf_secthead_get_align(const elf_secthead *shead) +{ + return shead->align; +} + +unsigned long +elf_secthead_set_align(elf_secthead *shead, unsigned long align) +{ + return shead->align = align; +} + +elf_section_info +elf_secthead_set_info(elf_secthead *shead, elf_section_info info) +{ + return shead->info = info; +} + +elf_section_index +elf_secthead_set_index(elf_secthead *shead, elf_section_index sectidx) +{ + return shead->index = sectidx; +} + +elf_section_index +elf_secthead_set_link(elf_secthead *shead, elf_section_index link) +{ + return shead->link = link; +} + +elf_section_index +elf_secthead_set_rel_index(elf_secthead *shead, elf_section_index sectidx) +{ + return shead->rel_index = sectidx; +} + +elf_strtab_entry * +elf_secthead_set_rel_name(elf_secthead *shead, elf_strtab_entry *entry) +{ + return shead->rel_name = entry; +} + +elf_size +elf_secthead_set_entsize(elf_secthead *shead, elf_size size) +{ + return shead->entsize = size; +} + +yasm_symrec * +elf_secthead_set_sym(elf_secthead *shead, yasm_symrec *sym) +{ + return shead->sym = sym; +} + +void +elf_secthead_add_size(elf_secthead *shead, yasm_intnum *size) +{ + if (size) { + yasm_intnum_calc(shead->size, YASM_EXPR_ADD, size); + } +} + +long +elf_secthead_set_file_offset(elf_secthead *shead, long pos) +{ + unsigned long align = shead->align; + + if (align == 0 || align == 1) { + shead->offset = (unsigned long)pos; + return pos; + } + else if (align & (align - 1)) + yasm_internal_error( + N_("alignment %d for section `%s' is not a power of 2")); + /*, align, sect->name->str);*/ + + shead->offset = (unsigned long)((pos + align - 1) & ~(align - 1)); + return (long)shead->offset; +} + +unsigned long +elf_proghead_get_size(void) +{ + if (!elf_march->proghead_size) + yasm_internal_error(N_("Unsupported ELF format for output")); + return elf_march->proghead_size; +} + +unsigned long +elf_proghead_write_to_file(FILE *f, + elf_offset secthead_addr, + unsigned long secthead_count, + elf_section_index shstrtab_index) +{ + unsigned char buf[EHDR_MAXSIZE], *bufp = buf; + + YASM_WRITE_8(bufp, ELFMAG0); /* ELF magic number */ + YASM_WRITE_8(bufp, ELFMAG1); + YASM_WRITE_8(bufp, ELFMAG2); + YASM_WRITE_8(bufp, ELFMAG3); + + if (!elf_march->write_proghead || !elf_march->proghead_size) + yasm_internal_error(N_("Unsupported ELF format for output")); + elf_march->write_proghead(&bufp, secthead_addr, secthead_count, shstrtab_index); + + if (((unsigned)(bufp - buf)) != elf_march->proghead_size) + yasm_internal_error(N_("ELF program header is not proper length")); + + if (fwrite(buf, elf_march->proghead_size, 1, f)) + return elf_march->proghead_size; + + yasm_internal_error(N_("Failed to write ELF program header")); + return 0; +} diff --git a/contrib/tools/yasm/modules/objfmts/elf/elf.h b/contrib/tools/yasm/modules/objfmts/elf/elf.h new file mode 100644 index 0000000000..fce629ae45 --- /dev/null +++ b/contrib/tools/yasm/modules/objfmts/elf/elf.h @@ -0,0 +1,532 @@ +/* + * ELF object format helpers + * + * Copyright (C) 2003-2007 Michael Urman + * + * 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 ELF_H_INCLUDED +#define ELF_H_INCLUDED + +typedef struct elf_reloc_entry elf_reloc_entry; +typedef struct elf_reloc_head elf_reloc_head; +typedef struct elf_secthead elf_secthead; +typedef struct elf_strtab_entry elf_strtab_entry; +typedef struct elf_strtab_head elf_strtab_head; +typedef struct elf_symtab_entry elf_symtab_entry; +typedef struct elf_symtab_head elf_symtab_head; + +typedef struct elf_machine_handler elf_machine_handler; + +typedef unsigned long elf_address; +typedef unsigned long elf_offset; +typedef unsigned long elf_size; +typedef unsigned long elf_section_info; + +typedef enum { + ET_NONE = 0, + ET_REL = 1, /* Relocatable */ + ET_EXEC = 2, /* Executable */ + ET_DYN = 3, /* Shared object */ + ET_CORE = 4, /* Core */ + ET_LOOS = 0xfe00, /* Environment specific */ + ET_HIOS = 0xfeff, + ET_LOPROC = 0xff00, /* Processor specific */ + ET_HIPROC = 0xffff +} elf_file_type; + +typedef enum { + EM_NONE = 0, + EM_M32 = 1, /* AT&T WE 32100 */ + EM_SPARC = 2, /* SPARC */ + EM_386 = 3, /* Intel 80386 */ + EM_68K = 4, /* Motorola 68000 */ + EM_88K = 5, /* Motorola 88000 */ + EM_860 = 7, /* Intel 80860 */ + EM_MIPS = 8, /* MIPS RS3000 */ + + EM_S370 = 9, /* IBM System/370 */ + EM_MIPS_RS4_BE = 10, /* MIPS R4000 Big-Endian (dep)*/ + EM_PARISC = 15, /* HPPA */ + EM_SPARC32PLUS = 18, /* SPARC v8plus */ + EM_PPC = 20, /* PowerPC 32-bit */ + EM_PPC64 = 21, /* PowerPC 64-bit */ + EM_ARM = 40, /* ARM */ + EM_SPARCV9 = 43, /* SPARC v9 64-bit */ + EM_IA_64 = 50, /* Intel IA-64 */ + EM_X86_64 = 62, /* AMD x86-64 */ + EM_ALPHA = 0x9026 /* Alpha (no ABI) */ +} elf_machine; + +typedef enum { + ELFMAG0 = 0x7f, + ELFMAG1 = 0x45, + ELFMAG2 = 0x4c, + ELFMAG3 = 0x46 +} elf_magic; + +typedef enum { + EV_NONE = 0, /* invalid */ + EV_CURRENT = 1 /* current */ +} elf_version; + +typedef enum { + EI_MAG0 = 0, /* File id */ + EI_MAG1 = 1, + EI_MAG2 = 2, + EI_MAG3 = 3, + EI_CLASS = 4, /* File class */ + EI_DATA = 5, /* Data encoding */ + EI_VERSION = 6, /* File version */ + EI_OSABI = 7, /* OS and ABI */ + EI_ABIVERSION = 8, /* version of ABI */ + + EI_PAD = 9, /* Pad to end; start here */ + EI_NIDENT = 16 /* Sizeof e_ident[] */ +} elf_identification_index; + +typedef enum { + ELFOSABI_SYSV = 0, /* System V ABI */ + ELFOSABI_HPUX = 1, /* HP-UX os */ + ELFOSABI_STANDALONE = 255 /* Standalone / embedded app */ +} elf_osabi_index; + +typedef enum { + ELFCLASSNONE = 0, /* invalid */ + ELFCLASS32 = 1, /* 32-bit */ + ELFCLASS64 = 2 /* 64-bit */ +} elf_class; + +typedef enum { + ELFDATANONE = 0, + ELFDATA2LSB = 1, + ELFDATA2MSB = 2 +} elf_data_encoding; + +/* elf section types - index of semantics */ +typedef enum { + SHT_NULL = 0, /* inactive section - no associated data */ + SHT_PROGBITS = 1, /* defined by program for its own meaning */ + SHT_SYMTAB = 2, /* symbol table (primarily) for linking */ + SHT_STRTAB = 3, /* string table - symbols need names */ + SHT_RELA = 4, /* relocation entries w/ explicit addends */ + SHT_HASH = 5, /* symbol hash table - for dynamic linking */ + SHT_DYNAMIC = 6, /* information for dynamic linking */ + SHT_NOTE = 7, /* extra data marking the file somehow */ + SHT_NOBITS = 8, /* no stored data, but occupies runtime space */ + SHT_REL = 9, /* relocations entries w/o explicit addends */ + SHT_SHLIB = 10, /* reserved; unspecified semantics */ + SHT_DYNSYM = 11, /* like symtab, but more for dynamic linking */ + + SHT_LOOS = 0x60000000, /* reserved for environment specific use */ + SHT_HIOS = 0x6fffffff, + SHT_LOPROC = 0x70000000, /* reserved for processor specific semantics */ + SHT_HIPROC = 0x7fffffff/*, + SHT_LOUSER = 0x80000000,*/ /* reserved for applications; safe */ + /*SHT_HIUSER = 0xffffffff*/ +} elf_section_type; + +/* elf section flags - bitfield of attributes */ +typedef enum { + SHF_WRITE = 0x1, /* data should be writable at runtime */ + SHF_ALLOC = 0x2, /* occupies memory at runtime */ + SHF_EXECINSTR = 0x4, /* contains machine instructions */ + SHF_MERGE = 0x10, /* data can be merged */ + SHF_STRINGS = 0x20, /* contains 0-terminated strings */ + SHF_GROUP = 0x200, /* member of a section group */ + SHF_TLS = 0x400, /* thread local storage */ + SHF_MASKOS = 0x0f000000/*,*//* environment specific use */ + /*SHF_MASKPROC = 0xf0000000*/ /* bits reserved for processor specific needs */ +} elf_section_flags; + +/* elf section index - just the special ones */ +typedef enum { + SHN_UNDEF = 0, /* undefined symbol; requires other global */ + SHN_LORESERVE = 0xff00, /* reserved for various semantics */ + SHN_LOPROC = 0xff00, /* reserved for processor specific semantics */ + SHN_HIPROC = 0xff1f, + SHN_LOOS = 0xff20, /* reserved for environment specific use */ + SHN_HIOS = 0xff3f, + SHN_ABS = 0xfff1, /* associated symbols don't change on reloc */ + SHN_COMMON = 0xfff2, /* associated symbols refer to unallocated */ + SHN_HIRESERVE = 0xffff +} elf_section_index; + +/* elf symbol binding - index of visibility/behavior */ +typedef enum { + STB_LOCAL = 0, /* invisible outside defining file */ + STB_GLOBAL = 1, /* visible to all combined object files */ + STB_WEAK = 2, /* global but lower precedence */ + + STB_LOOS = 10, /* Environment specific use */ + STB_HIOS = 12, + STB_LOPROC = 13, /* reserved for processor specific semantics */ + STB_HIPROC = 15 +} elf_symbol_binding; + +/* elf symbol type - index of classifications */ +typedef enum { + STT_NOTYPE = 0, /* type not specified */ + STT_OBJECT = 1, /* data object such as a variable, array, etc */ + STT_FUNC = 2, /* a function or executable code */ + STT_SECTION = 3, /* a section: often for relocation, STB_LOCAL */ + STT_FILE = 4, /* often source filename: STB_LOCAL, SHN_ABS */ + STT_COMMON = 5, /* Uninitialized common block. */ + STT_TLS = 6, /* TLS object. */ + STT_NUM = 7, + + STT_LOOS = 10, /* Environment specific use */ + STT_HIOS = 12, + STT_LOPROC = 13, /* reserved for processor specific semantics */ + STT_HIPROC = 15 +} elf_symbol_type; + +typedef enum { + STN_UNDEF = 0 +} elf_symbol_index; + +/* elf symbol visibility - lower two bits of OTHER field */ +typedef enum { + STV_DEFAULT = 0, /* Default symbol visibility rules */ + STV_INTERNAL = 1, /* Processor specific hidden class */ + STV_HIDDEN = 2, /* Sym unavailable in other modules */ + STV_PROTECTED = 3 /* Not preemptable, not exported */ +} elf_symbol_vis; + + +/* internal only object definitions */ +#ifdef YASM_OBJFMT_ELF_INTERNAL + +#define ELF_VISIBILITY_MASK 0x03 +#define ELF_ST_VISIBILITY(v) ((v) & ELF_VISIBILITY_MASK) + +#define ELF32_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf)) +#define ELF32_R_INFO(s,t) (((s)<<8)+(unsigned char)(t)) +#define ELF32_ST_OTHER(vis) ELF_ST_VISIBILITY(vis) + +#define ELF64_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf)) +#define ELF64_R_INFO(s,t) (((s)<<32) + ((t) & 0xffffffffL)) +#define ELF64_ST_OTHER(vis) ELF_ST_VISIBILITY(vis) + +#define EHDR32_SIZE 52 +#define EHDR64_SIZE 64 +#define EHDR_MAXSIZE 64 + +#define SHDR32_SIZE 40 +#define SHDR64_SIZE 64 +#define SHDR_MAXSIZE 64 + +#define SYMTAB32_SIZE 16 +#define SYMTAB64_SIZE 24 +#define SYMTAB_MAXSIZE 24 + +#define SYMTAB32_ALIGN 4 +#define SYMTAB64_ALIGN 8 + +#define RELOC32_SIZE 8 +#define RELOC32A_SIZE 12 +#define RELOC64_SIZE 16 +#define RELOC64A_SIZE 24 +#define RELOC_MAXSIZE 24 + +#define RELOC32_ALIGN 4 +#define RELOC64_ALIGN 8 + + +/* elf relocation type - index of semantics + * + * A = Addend (r_addend for RELA, value at location for REL) + * B = Base address + * G = Offset into global offset table (GOT) + * GOT = Address of the global offset table (GOT) + * L = Location of procedure linkage table (PLT) + * P = Location of location being relocated (r_offset) + * S = Value of symbol + */ +typedef enum { + R_386_NONE = 0, /* none */ + R_386_32 = 1, /* word32, S + A */ + R_386_PC32 = 2, /* word32, S + A - P */ + R_386_GOT32 = 3, /* word32, G + A - P */ + R_386_PLT32 = 4, /* word32, L + A - P */ + R_386_COPY = 5, /* none */ + R_386_GLOB_DAT = 6, /* word32, S */ + R_386_JMP_SLOT = 7, /* word32, S */ + R_386_RELATIVE = 8, /* word32, B + A */ + R_386_GOTOFF = 9, /* word32, S + A - GOT */ + R_386_GOTPC = 10, /* word32, GOT + A - P */ + R_386_TLS_TPOFF = 14, /* Negative offset in static TLS block (GNU + version) */ + R_386_TLS_IE = 15, /* Absolute address of GOT entry for negative + static TLS block offset */ + R_386_TLS_GOTIE = 16, /* GOT entry for negative static TLS block + offset */ + R_386_TLS_LE = 17, /* Negative offset relative to static TLS + (GNU version) */ + R_386_TLS_GD = 18, /* Direct 32 bit for GNU version of GD TLS */ + R_386_TLS_LDM = 19, /* Direct 32 bit for GNU version of LD TLS + in LE code */ + R_386_16 = 20, /* word16, S + A (GNU extension) */ + R_386_PC16 = 21, /* word16, S + A - P (GNU extension) */ + R_386_8 = 22, /* word8, S + A (GNU extension) */ + R_386_PC8 = 23, /* word8, S + A - P (GNU extension) */ + R_386_TLS_GD_32 = 24, /* Direct 32 bit for GD TLS */ + R_386_TLS_GD_PUSH = 25, /* Tag for pushl in GD TLS code */ + R_386_TLS_GD_CALL = 26, /* Relocation for call to */ + R_386_TLS_GD_POP = 27, /* Tag for popl in GD TLS code */ + R_386_TLS_LDM_32 = 28, /* Direct 32 bit for local dynamic code */ + R_386_TLS_LDM_PUSH = 29, /* Tag for pushl in LDM TLS code */ + R_386_TLS_LDM_CALL = 30, /* Relocation for call to */ + R_386_TLS_LDM_POP = 31, /* Tag for popl in LDM TLS code */ + R_386_TLS_LDO_32 = 32, /* Offset relative to TLS block */ + R_386_TLS_IE_32 = 33, /* GOT entry for static TLS block */ + R_386_TLS_LE_32 = 34, /* Offset relative to static TLS block */ + R_386_TLS_DTPMOD32 = 35, /* ID of module containing symbol */ + R_386_TLS_DTPOFF32 = 36, /* Offset in TLS block */ + R_386_TLS_TPOFF32 = 37, /* Offset in static TLS block */ + R_386_TLS_GOTDESC = 39, + R_386_TLS_DESC_CALL = 40, + R_386_TLS_DESC = 41 +} elf_386_relocation_type; + +typedef enum { + R_X86_64_NONE = 0, /* none */ + R_X86_64_64 = 1, /* word64, S + A */ + R_X86_64_PC32 = 2, /* word32, S + A - P */ + R_X86_64_GOT32 = 3, /* word32, G + A */ + R_X86_64_PLT32 = 4, /* word32, L + A - P */ + R_X86_64_COPY = 5, /* none */ + R_X86_64_GLOB_DAT = 6, /* word64, S, set GOT entry to data address */ + R_X86_64_JMP_SLOT = 7, /* word64, S, set GOT entry to code address */ + R_X86_64_RELATIVE = 8, /* word64, B + A */ + R_X86_64_GOTPCREL = 9, /* word32, G + GOT + A - P */ + R_X86_64_32 = 10, /* word32 (zero extend), S + A */ + R_X86_64_32S = 11, /* word32 (sign extend), S + A */ + R_X86_64_16 = 12, /* word16, S + A */ + R_X86_64_PC16 = 13, /* word16, S + A - P */ + R_X86_64_8 = 14, /* word8, S + A */ + R_X86_64_PC8 = 15, /* word8, S + A - P */ + R_X86_64_DPTMOD64 = 16, /* word64, ID of module containing symbol */ + R_X86_64_DTPOFF64 = 17, /* word64, offset in TLS block */ + R_X86_64_TPOFF64 = 18, /* word64, offset in initial TLS block */ + R_X86_64_TLSGD = 19, /* word32, PC-rel offset to GD GOT block */ + R_X86_64_TLSLD = 20, /* word32, PC-rel offset to LD GOT block */ + R_X86_64_DTPOFF32 = 21, /* word32, offset to TLS block */ + R_X86_64_GOTTPOFF = 22, /* word32, PC-rel offset to IE GOT entry */ + R_X86_64_TPOFF32 = 23, /* word32, offset in initial TLS block */ + R_X86_64_PC64 = 24, /* word64, PC relative */ + R_X86_64_GOTOFF64 = 25, /* word64, offset to GOT */ + R_X86_64_GOTPC32 = 26, /* word32, signed pc relative to GOT */ + R_X86_64_GOT64 = 27, /* word64, GOT entry offset */ + R_X86_64_GOTPCREL64 = 28, /* word64, signed pc relative to GOT entry */ + R_X86_64_GOTPC64 = 29, /* word64, signed pc relative to GOT */ + R_X86_64_GOTPLT64 = 30, /* like GOT64, but indicates PLT entry needed */ + R_X86_64_PLTOFF64 = 31, /* word64, GOT relative offset to PLT entry */ + R_X86_64_GOTPC32_TLSDESC = 34, /* GOT offset for TLS descriptor */ + R_X86_64_TLSDESC_CALL = 35, /* Marker for call through TLS descriptor */ + R_X86_64_TLSDESC = 36 /* TLS descriptor */ +} elf_x86_64_relocation_type; + +struct elf_secthead { + elf_section_type type; + elf_section_flags flags; + elf_address offset; + yasm_intnum *size; + elf_section_index link; + elf_section_info info; /* see note ESD1 */ + unsigned long align; + elf_size entsize; + + yasm_symrec *sym; + elf_strtab_entry *name; + elf_section_index index; + + elf_strtab_entry *rel_name; + elf_section_index rel_index; + elf_address rel_offset; + unsigned long nreloc; +}; + +/* Note ESD1: + * for section types SHT_REL, SHT_RELA: + * link -> index of associated symbol table + * info -> index of relocated section + * for section types SHT_SYMTAB, SHT_DYNSYM: + * link -> index of associated string table + * info -> 1+index of last "local symbol" (bind == STB_LOCAL) + * (for section type SHT_DNAMIC: + * link -> index of string table + * info -> 0 ) + * (for section type SHT_HASH: + * link -> index of symbol table to which hash applies + * info -> 0 ) + * for all others: + * link -> SHN_UNDEF + * info -> 0 + */ + +struct elf_reloc_entry { + yasm_reloc reloc; + int rtype_rel; + size_t valsize; + yasm_intnum *addend; + /*@null@*/ yasm_symrec *wrt; + int is_GOT_sym; +}; + +STAILQ_HEAD(elf_strtab_head, elf_strtab_entry); +struct elf_strtab_entry { + STAILQ_ENTRY(elf_strtab_entry) qlink; + unsigned long index; + char *str; +}; + +STAILQ_HEAD(elf_symtab_head, elf_symtab_entry); +struct elf_symtab_entry { + STAILQ_ENTRY(elf_symtab_entry) qlink; + int in_table; + yasm_symrec *sym; + yasm_section *sect; + elf_strtab_entry *name; + elf_address value; + /*@dependent@*/ yasm_expr *xsize; + elf_size size; + elf_section_index index; + elf_symbol_binding bind; + elf_symbol_type type; + elf_symbol_vis vis; + elf_symbol_index symindex; +}; + +#endif /* defined(YASM_OBJFMT_ELF_INTERNAL) */ + +extern const yasm_assoc_data_callback elf_section_data; +extern const yasm_assoc_data_callback elf_symrec_data; +extern const yasm_assoc_data_callback elf_ssym_symrec_data; + + +const elf_machine_handler *elf_set_arch(struct yasm_arch *arch, + yasm_symtab *symtab, + int bits_pref); + +yasm_symrec *elf_get_special_sym(const char *name, const char *parser); + +/* reloc functions */ +int elf_is_wrt_sym_relative(yasm_symrec *wrt); +int elf_is_wrt_pos_adjusted(yasm_symrec *wrt); +elf_reloc_entry *elf_reloc_entry_create(yasm_symrec *sym, + /*@null@*/ yasm_symrec *wrt, + yasm_intnum *addr, + int rel, + size_t valsize, + int is_GOT_sym); +void elf_reloc_entry_destroy(void *entry); + +/* strtab functions */ +elf_strtab_entry *elf_strtab_entry_create(const char *str); +void elf_strtab_entry_set_str(elf_strtab_entry *entry, const char *str); +elf_strtab_head *elf_strtab_create(void); +elf_strtab_entry *elf_strtab_append_str(elf_strtab_head *head, const char *str); +void elf_strtab_destroy(elf_strtab_head *head); +unsigned long elf_strtab_output_to_file(FILE *f, elf_strtab_head *head); + +/* symtab functions */ +elf_symtab_entry *elf_symtab_entry_create(elf_strtab_entry *name, + struct yasm_symrec *sym); +elf_symtab_head *elf_symtab_create(void); +void elf_symtab_append_entry(elf_symtab_head *symtab, elf_symtab_entry *entry); +void elf_symtab_insert_local_sym(elf_symtab_head *symtab, + elf_symtab_entry *entry); +void elf_symtab_destroy(elf_symtab_head *head); +unsigned long elf_symtab_assign_indices(elf_symtab_head *symtab); +unsigned long elf_symtab_write_to_file(FILE *f, elf_symtab_head *symtab, + yasm_errwarns *errwarns); +void elf_symtab_set_nonzero(elf_symtab_entry *entry, + struct yasm_section *sect, + elf_section_index sectidx, + elf_symbol_binding bind, + elf_symbol_type type, + struct yasm_expr *size, + elf_address *value); +void elf_sym_set_visibility(elf_symtab_entry *entry, + elf_symbol_vis vis); +void elf_sym_set_type(elf_symtab_entry *entry, elf_symbol_type type); +void elf_sym_set_size(elf_symtab_entry *entry, struct yasm_expr *size); +int elf_sym_in_table(elf_symtab_entry *entry); + +/* section header functions */ +elf_secthead *elf_secthead_create(elf_strtab_entry *name, + elf_section_type type, + elf_section_flags flags, + elf_address offset, + elf_size size); +void elf_secthead_destroy(elf_secthead *esd); +unsigned long elf_secthead_write_to_file(FILE *f, elf_secthead *esd, + elf_section_index sindex); +void elf_secthead_append_reloc(yasm_section *sect, elf_secthead *shead, + elf_reloc_entry *reloc); +elf_section_type elf_secthead_get_type(elf_secthead *shead); +void elf_secthead_set_typeflags(elf_secthead *shead, elf_section_type type, + elf_section_flags flags); +int elf_secthead_is_empty(elf_secthead *shead); +struct yasm_symrec *elf_secthead_get_sym(elf_secthead *shead); +unsigned long elf_secthead_get_align(const elf_secthead *shead); +unsigned long elf_secthead_set_align(elf_secthead *shead, unsigned long align); +elf_section_index elf_secthead_get_index(elf_secthead *shead); +elf_section_info elf_secthead_set_info(elf_secthead *shead, + elf_section_info info); +elf_section_index elf_secthead_set_index(elf_secthead *shead, + elf_section_index sectidx); +elf_section_index elf_secthead_set_link(elf_secthead *shead, + elf_section_index link); +elf_section_index elf_secthead_set_rel_index(elf_secthead *shead, + elf_section_index sectidx); +elf_strtab_entry *elf_secthead_set_rel_name(elf_secthead *shead, + elf_strtab_entry *entry); +elf_size elf_secthead_set_entsize(elf_secthead *shead, elf_size size); +struct yasm_symrec *elf_secthead_set_sym(elf_secthead *shead, + struct yasm_symrec *sym); +void elf_secthead_add_size(elf_secthead *shead, yasm_intnum *size); +char *elf_secthead_name_reloc_section(const char *basesect); +void elf_handle_reloc_addend(yasm_intnum *intn, + elf_reloc_entry *reloc, + unsigned long offset); +unsigned long elf_secthead_write_rel_to_file(FILE *f, elf_section_index symtab, + yasm_section *sect, + elf_secthead *esd, + elf_section_index sindex); +unsigned long elf_secthead_write_relocs_to_file(FILE *f, yasm_section *sect, + elf_secthead *shead, + yasm_errwarns *errwarns); +long elf_secthead_set_file_offset(elf_secthead *shead, long pos); + +/* program header function */ +unsigned long +elf_proghead_get_size(void); +unsigned long +elf_proghead_write_to_file(FILE *f, + elf_offset secthead_addr, + unsigned long secthead_count, + elf_section_index shstrtab_index); + +#endif /* ELF_H_INCLUDED */ diff --git a/contrib/tools/yasm/modules/objfmts/macho/macho-objfmt.c b/contrib/tools/yasm/modules/objfmts/macho/macho-objfmt.c new file mode 100644 index 0000000000..0a48d9b905 --- /dev/null +++ b/contrib/tools/yasm/modules/objfmts/macho/macho-objfmt.c @@ -0,0 +1,1620 @@ +/* + * Mac OS X ABI Mach-O File Format + * + * Copyright (C) 2007 Henryk Richter, built upon xdf objfmt (C) 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. + */ +/* + notes: This implementation is rather basic. There are several implementation + issues to be sorted out for full compliance and error resilience. + Some examples are given below (nasm syntax). + + 1) section placement + Mach-O requires BSS sections to be placed last in object files. This + has to be done manually. + Example: + + section .text + mov rax,[qword foo] + section .data + dw 0 + section .bss + foo dw 0 + + 2) addressing issues + + 2.1) symbol relative relocation (i.e. mov eax,[foo wrt bar]) + Not implemented yet. + + 2.2) data referencing in 64 bit mode + While ELF allows 32 bit absolute relocations in 64 bit mode, Mach-O + does not. Therefore code like + lea rbx,[_foo] ;48 8d 1c 25 00 00 00 00 + mov rcx,[_bar] ;48 8b 0c 25 00 00 00 00 + with a 32 bit address field cannot be relocated into an address >= 0x100000000 (OSX actually + uses that). + + Actually, the only register where a 64 bit displacement is allowed in x86-64, is rax + as in the example 1). + + A plausible workaround is either classic PIC (like in C), which is in turn + not implemented in this object format. The recommended was is PC relative + code (called RIP-relative in x86-64). So instead of the lines above, just write: + lea rbx,[_foo wrt rip] + mov rcx,[_bar wrt rip] + + 2.3) section/data alignment + Normally, you specify sections with a specific alignment + and get your data layed out as desired. Unfortunately, the + linker in MacOS X seems to ignore the section alignment requests. + The workaround is an explicit alignment at the end of the text section. + + section .text + movdqa xmm0,[_foo wrt rip] + + align 16 + section .data align=16 + _foo dw 32,32,32,32,32,32,32,32 + + FIXME: perform that operation implicitly! + + 2.4) cross section symbol differences unsupported in current implementation + [extern foo] + [extern bar] + section .data + dq bar-foo + + Will currently produce an error though the necessary means are provided + by the Mach-O specification. + +*/ + +#include <util.h> + +#include <libyasm.h> + +/* MACH-O DEFINES */ +/* Mach-O in-file header structure sizes (32 BIT, see below for 64 bit defs) */ +#define MACHO_HEADER_SIZE 28 +#define MACHO_SEGCMD_SIZE 56 +#define MACHO_SECTCMD_SIZE 68 +#define MACHO_SYMCMD_SIZE 24 +#define MACHO_NLIST_SIZE 12 +#define MACHO_RELINFO_SIZE 8 + +/* 64 bit sizes */ +#define MACHO_HEADER64_SIZE 32 +#define MACHO_SEGCMD64_SIZE 72 +#define MACHO_SECTCMD64_SIZE 80 +#define MACHO_NLIST64_SIZE 16 +#define MACHO_RELINFO64_SIZE 8 + + +/* Mach-O file header values */ +#define MH_MAGIC 0xfeedface +#define MH_MAGIC_64 0xfeedfacf + +/* CPU machine type */ +#define CPU_TYPE_I386 7 /* x86 platform */ +#define CPU_TYPE_X86_64 (CPU_TYPE_I386|CPU_ARCH_ABI64) +#define CPU_ARCH_ABI64 0x01000000 /* 64 bit ABI */ + +/* CPU machine subtype, e.g. processor */ +#define CPU_SUBTYPE_I386_ALL 3 /* all-x86 compatible */ +#define CPU_SUBTYPE_X86_64_ALL CPU_SUBTYPE_I386_ALL +#define CPU_SUBTYPE_386 3 +#define CPU_SUBTYPE_486 4 +#define CPU_SUBTYPE_486SX (4 + 128) +#define CPU_SUBTYPE_586 5 +#define CPU_SUBTYPE_INTEL(f, m) ((f) + ((m) << 4)) +#define CPU_SUBTYPE_PENT CPU_SUBTYPE_INTEL(5, 0) +#define CPU_SUBTYPE_PENTPRO CPU_SUBTYPE_INTEL(6, 1) +#define CPU_SUBTYPE_PENTII_M3 CPU_SUBTYPE_INTEL(6, 3) +#define CPU_SUBTYPE_PENTII_M5 CPU_SUBTYPE_INTEL(6, 5) +#define CPU_SUBTYPE_PENTIUM_4 CPU_SUBTYPE_INTEL(10, 0) + +#define CPU_SUBTYPE_INTEL_FAMILY(x) ((x) & 15) +#define CPU_SUBTYPE_INTEL_FAMILY_MAX 15 + +#define CPU_SUBTYPE_INTEL_MODEL(x) ((x) >> 4) +#define CPU_SUBTYPE_INTEL_MODEL_ALL 0 + +#define MH_OBJECT 0x1 /* object file */ + +#define LC_SEGMENT 0x1 /* segment load command */ +#define LC_SYMTAB 0x2 /* symbol table load command */ +#define LC_SEGMENT_64 0x19 /* segment load command */ + + +#define VM_PROT_NONE 0x00 +#define VM_PROT_READ 0x01 +#define VM_PROT_WRITE 0x02 +#define VM_PROT_EXECUTE 0x04 + +#define VM_PROT_DEFAULT (VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE) +#define VM_PROT_ALL (VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE) + +#define SECTION_TYPE 0x000000ff /* section type mask */ +#define SECTION_ATTRIBUTES 0xffffff00UL/* section attributes mask */ + +#define S_REGULAR 0x0 /* standard section */ +#define S_ZEROFILL 0x1 /* zerofill, in-memory only */ +#define S_CSTRING_LITERALS 0x2 /* literal C strings */ +#define S_4BYTE_LITERALS 0x3 /* only 4-byte literals */ +#define S_8BYTE_LITERALS 0x4 /* only 8-byte literals */ +#define S_LITERAL_POINTERS 0x5 /* only pointers to literals */ +#define S_NON_LAZY_SYMBOL_POINTERS 0x6 /* only non-lazy symbol pointers */ +#define S_LAZY_SYMBOL_POINTERS 0x7 /* only lazy symbol pointers */ +#define S_SYMBOL_STUBS 0x8 /* only symbol stubs; byte size of + * stub in the reserved2 field */ +#define S_MOD_INIT_FUNC_POINTERS 0x9 /* only function pointers for init */ +#define S_MOD_TERM_FUNC_POINTERS 0xa /* only function pointers for term */ +#define S_COALESCED 0xb /* symbols that are to be coalesced */ +#define S_GB_ZEROFILL 0xc /* >4GB zero fill on demand section */ +#define S_INTERPOSING 0xd /* only pairs of function pointers for + * interposing */ +#define S_16BYTE_LITERALS 0xe /* only 16 byte literals */ + +#define S_ATTR_DEBUG 0x02000000 /* a debug section */ +#define SECTION_ATTRIBUTES_SYS 0x00ffff00 /* system setable attributes */ +#define S_ATTR_SOME_INSTRUCTIONS 0x00000400 /* section contains some + * machine instructions */ +#define S_ATTR_EXT_RELOC 0x00000200 /* section has external + * relocation entries */ +#define S_ATTR_LOC_RELOC 0x00000100 /* section has local + * relocation entries */ + +#define SECTION_ATTRIBUTES_USR 0xff000000UL /* User setable attributes */ +#define S_ATTR_PURE_INSTRUCTIONS 0x80000000UL /* only true machine insns */ +#define S_ATTR_NO_TOC 0x40000000UL /* coalesced symbols that are + * not to be in a ranlib table + * of contents */ +#define S_ATTR_STRIP_STATIC_SYMS 0x20000000UL /* ok to strip static symbols + * in this section in files + * with the MH_DYLDLINK flag */ +#define S_ATTR_NO_DEAD_STRIP 0x10000000UL /* no dead stripping */ +#define S_ATTR_LIVE_SUPPORT 0x08000000UL /* blocks are live if they + * reference live blocks */ +#define S_ATTR_SELF_MODIFYING_CODE 0x04000000UL /* Used with i386 code stubs + * written on by dyld */ + +/* macho references symbols in different ways whether they are linked at + * runtime (LAZY, read library functions) or at link time (NON_LAZY, mostly + * data) + * + * TODO: proper support for dynamically linkable modules would require the + * __import sections as well as the dsymtab command + */ +#define REFERENCE_FLAG_UNDEFINED_NON_LAZY 0x0 +#define REFERENCE_FLAG_UNDEFINED_LAZY 0x1 + +#define align(x, y) \ + (((x) + (y) - 1) & ~((y) - 1)) /* align x to multiple of y */ + +#define align32(x) \ + align(x, 4) /* align x to 32 bit boundary */ + +#define macho_MAGIC 0x87654322 + +/* Symbol table type field bit masks */ +#define N_STAB 0xe0 /* mask indicating stab entry */ +#define N_PEXT 0x10 /* private external bit */ +#define N_TYPE 0x0e /* mask for all the type bits */ +#define N_EXT 0x01 /* external (global) bit */ + +/* Symbol table type field values */ +#define N_UNDF 0x00 /* undefined */ +#define N_ABS 0x02 /* absolute address */ +#define N_SECT 0x0e /* symbol is defined in a section */ + +#define NO_SECT 0 /* no section for symbol in nlist */ + +#define REGULAR_OUTBUF_SIZE 1024 + + +typedef struct macho_reloc { + yasm_reloc reloc; + int pcrel; + int length; + int ext; + enum reloc_type_x86_64 { + /* x86 relocations */ + GENERIC_RELOC_VANILLA = 0, /* generic relocation */ + GENERIC_RELOC_PAIR = 1, /* Only follows a GENERIC_RELOC_SECTDIFF */ + GENERIC_RELOC_SECTDIFF = 2, + GENERIC_RELOC_PB_LA_PTR = 3, /* prebound lazy pointer */ + GENERIC_RELOC_LOCAL_SECTDIFF = 4, + + /* x86-64 relocations */ + X86_64_RELOC_UNSIGNED = 0, /* for absolute addresses */ + X86_64_RELOC_SIGNED = 1, /* for signed 32-bit displacement */ + X86_64_RELOC_BRANCH = 2, /* a CALL/JMP insn with 32-bit disp */ + X86_64_RELOC_GOT_LOAD = 3, /* a MOVQ load of a GOT entry */ + X86_64_RELOC_GOT = 4, /* other GOT references */ + X86_64_RELOC_SUBTRACTOR = 5, /* must be followed by a X86_64_RELOC_UNSIGNED */ + X86_64_RELOC_SIGNED_1 = 6, /* signed 32-bit disp, -1 addend */ + X86_64_RELOC_SIGNED_2 = 7, /* signed 32-bit disp, -2 addend */ + X86_64_RELOC_SIGNED_4 = 8 /* signed 32-bit disp, -4 addend */ + } type; +} macho_reloc; + +typedef struct macho_section_data { + /*@dependent@*/ yasm_symrec *sym; /* symbol created for this section */ + long scnum; /* section number (0=first section) */ + /*@only@*/ char *segname; /* segment name in file */ + /*@only@*/ char *sectname; /* section name in file */ + unsigned long flags; /* S_* flags */ + unsigned long size; /* size of raw data (section data) in bytes */ + unsigned long offset; /* offset in raw data within file in bytes */ + unsigned long vmoff; /* memory offset */ + unsigned long nreloc; /* number of relocation entries */ + unsigned int extreloc; /* external relocations present (0/1) */ +} macho_section_data; + + +typedef struct macho_symrec_data { + unsigned long index; /* index in output order */ + yasm_intnum *value; /* valid after writing symtable to file */ + unsigned long length; /* length + 1 (plus auto underscore) */ +} macho_symrec_data; + + +typedef struct yasm_objfmt_macho { + yasm_objfmt_base objfmt; /* base structure */ + + long parse_scnum; /* sect numbering in parser */ + int bits; /* 32 / 64 */ + + yasm_symrec *gotpcrel_sym; /* ..gotpcrel */ +} yasm_objfmt_macho; + + +typedef struct macho_objfmt_output_info { + yasm_object *object; + yasm_objfmt_macho *objfmt_macho; + yasm_errwarns *errwarns; + /*@dependent@ */ FILE *f; + /*@only@ */ unsigned char *buf; + yasm_section *sect; + /*@dependent@ */ macho_section_data *msd; + + unsigned int is_64; /* write object in 64 bit mode */ + + /* vmsize and filesize available after traversing section count routine */ + unsigned long vmsize; /* raw size of all sections (including BSS) */ + unsigned long filesize; /* size of sections in file (excluding BSS) */ + unsigned long offset; /* offset within file */ + + /* forward offset tracking */ + unsigned long rel_base; /* first relocation in file */ + unsigned long s_reloff; /* in-file offset to relocations */ + + unsigned long indx; /* current symbol size in bytes (name length+1) */ + unsigned long symindex; /* current symbol index in output order */ + int all_syms; /* outputting all symbols? */ + unsigned long strlength; /* length of all strings */ +} macho_objfmt_output_info; + + +static void macho_section_data_destroy(/*@only@*/ void *d); +static void macho_section_data_print(void *data, FILE *f, int indent_level); + +static const yasm_assoc_data_callback macho_section_data_cb = { + macho_section_data_destroy, + macho_section_data_print +}; + +static void macho_symrec_data_destroy(/*@only@*/ void *d); +static void macho_symrec_data_print(void *data, FILE *f, int indent_level); + +static const yasm_assoc_data_callback macho_symrec_data_cb = { + macho_symrec_data_destroy, + macho_symrec_data_print +}; + +yasm_objfmt_module yasm_macho_LTX_objfmt; +yasm_objfmt_module yasm_macho32_LTX_objfmt; +yasm_objfmt_module yasm_macho64_LTX_objfmt; + +static yasm_objfmt * +macho_objfmt_create_common(yasm_object *object, yasm_objfmt_module *module, + int bits_pref) +{ + yasm_objfmt_macho *objfmt_macho = yasm_xmalloc(sizeof(yasm_objfmt_macho)); + + objfmt_macho->objfmt.module = module; + + /* Only support x86 arch for now */ + if (yasm__strcasecmp(yasm_arch_keyword(object->arch), "x86") != 0) { + yasm_xfree(objfmt_macho); + return NULL; + } + + /* Support x86 and amd64 machines of x86 arch */ + if (yasm__strcasecmp(yasm_arch_get_machine(object->arch), "x86") == 0 && + (bits_pref == 0 || bits_pref == 32)) { + objfmt_macho->bits = 32; + objfmt_macho->gotpcrel_sym = NULL; + } else if (yasm__strcasecmp(yasm_arch_get_machine(object->arch), + "amd64") == 0 && + (bits_pref == 0 || bits_pref == 64)) { + objfmt_macho->bits = 64; + /* FIXME: misuse of NULL bytecode */ + objfmt_macho->gotpcrel_sym = + yasm_symtab_define_label(object->symtab, "..gotpcrel", NULL, 0, 0); + } else { + yasm_xfree(objfmt_macho); + return NULL; + } + + objfmt_macho->parse_scnum = 0; /* section numbering starts at 0 */ + return (yasm_objfmt *)objfmt_macho; +} + +static yasm_objfmt * +macho_objfmt_create(yasm_object *object) +{ + yasm_objfmt *objfmt; + yasm_objfmt_macho *objfmt_macho; + + objfmt = macho_objfmt_create_common(object, &yasm_macho_LTX_objfmt, 0); + if (objfmt) { + objfmt_macho = (yasm_objfmt_macho *)objfmt; + /* Figure out which bitness of object format to use */ + if (objfmt_macho->bits == 32) + objfmt_macho->objfmt.module = &yasm_macho32_LTX_objfmt; + else if (objfmt_macho->bits == 64) + objfmt_macho->objfmt.module = &yasm_macho64_LTX_objfmt; + } + return objfmt; +} + +static yasm_objfmt * +macho32_objfmt_create(yasm_object *object) +{ + return macho_objfmt_create_common(object, &yasm_macho32_LTX_objfmt, 32); +} + +static yasm_objfmt * +macho64_objfmt_create(yasm_object *object) +{ + return macho_objfmt_create_common(object, &yasm_macho64_LTX_objfmt, 64); +} + +static int +macho_objfmt_output_value(yasm_value *value, unsigned char *buf, + unsigned int destsize, unsigned long offset, + yasm_bytecode *bc, int warn, /*@null@*/ void *d) +{ + /*@null@*/ macho_objfmt_output_info *info = (macho_objfmt_output_info *)d; + yasm_objfmt_macho *objfmt_macho; + /*@dependent@*/ /*@null@*/ yasm_intnum *intn; + unsigned long intn_minus = 0, intn_plus = 0; + int retval; + unsigned int valsize = value->size; + macho_reloc *reloc = NULL; + + assert(info != NULL); + objfmt_macho = info->objfmt_macho; + + if (value->abs) + value->abs = yasm_expr_simplify(value->abs, 1); + + /* Try to output constant and PC-relative section-local first. + * Note this does NOT output any value with a SEG, WRT, external, + * cross-section, or non-PC-relative reference (those are handled below). + */ + switch (yasm_value_output_basic(value, buf, destsize, bc, warn, + info->object->arch)) { + case -1: + return 1; + case 0: + break; + default: + return 0; + } + + if (value->section_rel) { + yasm_error_set(YASM_ERROR_TOO_COMPLEX, + N_("macho: relocation too complex for current implementation")); + return 1; + } + + if (value->rel) { + yasm_sym_vis vis = yasm_symrec_get_visibility(value->rel); + + reloc = yasm_xcalloc(sizeof(macho_reloc), 1); + reloc->reloc.addr = yasm_intnum_create_uint(bc->offset + offset); + reloc->reloc.sym = value->rel; + switch (valsize) { + case 64: + reloc->length = 3; + break; + case 32: + reloc->length = 2; + break; + case 16: + reloc->length = 1; + break; + case 8: + reloc->length = 0; + break; + default: + yasm_error_set(YASM_ERROR_TOO_COMPLEX, + N_("macho: relocation size unsupported")); + yasm_xfree(reloc); + return 1; + } + reloc->pcrel = 0; + reloc->ext = 0; + reloc->type = GENERIC_RELOC_VANILLA; + /* R_ABS */ + + if (value->rshift > 0) { + yasm_error_set(YASM_ERROR_TOO_COMPLEX, + N_("macho: shifted relocations not supported")); + yasm_xfree(reloc); + return 1; + } + + if (value->seg_of) { + yasm_error_set(YASM_ERROR_TOO_COMPLEX, + N_("macho: SEG not supported")); + yasm_xfree(reloc); + return 1; + } + + if (value->curpos_rel && objfmt_macho->gotpcrel_sym && + value->wrt == objfmt_macho->gotpcrel_sym) { + reloc->type = X86_64_RELOC_GOT; + value->wrt = NULL; + } else if (value->wrt) { + yasm_error_set(YASM_ERROR_TOO_COMPLEX, + N_("macho: invalid WRT")); + yasm_xfree(reloc); + return 1; + } + + if (value->curpos_rel) { + reloc->pcrel = 1; + if (!info->is_64) { + /* Adjust to start of section, so subtract out the bytecode + * offset. + */ + intn_minus = bc->offset; + } else { + /* Add in the offset plus value size to end up with 0. */ + intn_plus = offset+destsize; + if (reloc->type == X86_64_RELOC_GOT) { + /* XXX: This is a hack */ + if (offset >= 2 && buf[-2] == 0x8B) + reloc->type = X86_64_RELOC_GOT_LOAD; + } else if (value->jump_target) + reloc->type = X86_64_RELOC_BRANCH; + else + reloc->type = X86_64_RELOC_SIGNED; + } + } else if (info->is_64) { + if (valsize == 32) { + yasm_error_set(YASM_ERROR_NOT_CONSTANT, + N_("macho: sorry, cannot apply 32 bit absolute relocations in 64 bit mode, consider \"[_symbol wrt rip]\" for mem access, \"qword\" and \"dq _foo\" for pointers.")); + return 1; + } + reloc->type = X86_64_RELOC_UNSIGNED; + } + + /* It seems that x86-64 objects need to have all extern relocs? */ + if (info->is_64) + reloc->ext = 1; + + if ((vis & YASM_SYM_EXTERN) || (vis & YASM_SYM_COMMON)) { + reloc->ext = 1; + info->msd->extreloc = 1; /* section has external relocations */ + } else if (!info->is_64) { + /*@dependent@*/ /*@null@*/ yasm_bytecode *sym_precbc; + + /* Local symbols need valued to their actual address */ + if (yasm_symrec_get_label(value->rel, &sym_precbc)) { + yasm_section *sym_sect = yasm_bc_get_section(sym_precbc); + /*@null@*/ macho_section_data *msd; + msd = yasm_section_get_data(sym_sect, &macho_section_data_cb); + assert(msd != NULL); + intn_plus += msd->vmoff + yasm_bc_next_offset(sym_precbc); + } + } + + info->msd->nreloc++; + /*printf("reloc %s type %d ",yasm_symrec_get_name(reloc->reloc.sym),reloc->type);*/ + yasm_section_add_reloc(info->sect, (yasm_reloc *)reloc, yasm_xfree); + } + + if (intn_minus <= intn_plus) + intn = yasm_intnum_create_uint(intn_plus-intn_minus); + else { + intn = yasm_intnum_create_uint(intn_minus-intn_plus); + yasm_intnum_calc(intn, YASM_EXPR_NEG, NULL); + } + + if (value->abs) { + yasm_intnum *intn2 = yasm_expr_get_intnum(&value->abs, 0); + + if (!intn2) { + yasm_error_set(YASM_ERROR_TOO_COMPLEX, + N_("macho: relocation too complex")); + yasm_intnum_destroy(intn); + return 1; + } + yasm_intnum_calc(intn, YASM_EXPR_ADD, intn2); + } + + retval = yasm_arch_intnum_tobytes(info->object->arch, intn, buf, destsize, + valsize, 0, bc, warn); + /*printf("val %ld\n",yasm_intnum_get_int(intn));*/ + yasm_intnum_destroy(intn); + return retval; +} + +static int +macho_objfmt_output_bytecode(yasm_bytecode *bc, /*@null@*/ void *d) +{ + /*@null@*/ macho_objfmt_output_info *info = (macho_objfmt_output_info *)d; + /*@null@*/ /*@only@*/ unsigned char *bigbuf; + unsigned long size = REGULAR_OUTBUF_SIZE; + int gap; + + assert(info != NULL); + + bigbuf = yasm_bc_tobytes(bc, info->buf, &size, &gap, info, + macho_objfmt_output_value, NULL); + + /* Don't bother doing anything else if size ended up being 0. */ + if (size == 0) { + if (bigbuf) + yasm_xfree(bigbuf); + return 0; + } + + /* Warn that gaps are converted to 0 and write out the 0's. */ + if (gap) { + unsigned long left; + + yasm_warn_set(YASM_WARN_UNINIT_CONTENTS, + N_("uninitialized space: zeroing")); + /* Write out in chunks */ + memset(info->buf, 0, REGULAR_OUTBUF_SIZE); + left = size; + while (left > REGULAR_OUTBUF_SIZE) { + fwrite(info->buf, REGULAR_OUTBUF_SIZE, 1, info->f); + left -= REGULAR_OUTBUF_SIZE; + } + fwrite(info->buf, left, 1, info->f); + } else { + /* Output buf (or bigbuf if non-NULL) to file */ + fwrite(bigbuf ? bigbuf : info->buf, (size_t) size, 1, info->f); + } + + /* If bigbuf was allocated, free it */ + if (bigbuf) + yasm_xfree(bigbuf); + + return 0; +} + +static int +macho_objfmt_output_section(yasm_section *sect, /*@null@ */ void *d) +{ + /*@null@ */ macho_objfmt_output_info *info = + (macho_objfmt_output_info *) d; + /*@dependent@ *//*@null@ */ macho_section_data *msd; + + assert(info != NULL); + msd = yasm_section_get_data(sect, &macho_section_data_cb); + assert(msd != NULL); + + if (!(msd->flags & S_ZEROFILL)) { + /* Output non-BSS sections */ + info->sect = sect; + info->msd = msd; + yasm_section_bcs_traverse(sect, info->errwarns, info, + macho_objfmt_output_bytecode); + } + return 0; +} + +static int +macho_objfmt_output_relocs(yasm_section *sect, /*@null@*/ void *d) +{ + /*@null@*/ macho_objfmt_output_info *info = (macho_objfmt_output_info *)d; + /*@dependent@*/ /*@null@*/ macho_section_data *msd; + macho_reloc *reloc; + + reloc = (macho_reloc *)yasm_section_relocs_first(sect); + while (reloc) { + unsigned char *localbuf = info->buf; + /*@null@*/ macho_symrec_data *xsymd; + unsigned long symnum; + + xsymd = yasm_symrec_get_data(reloc->reloc.sym, &macho_symrec_data_cb); + yasm_intnum_get_sized(reloc->reloc.addr, localbuf, 4, 32, 0, 0, 0); + localbuf += 4; /* address of relocation */ + + if (reloc->ext) + symnum = xsymd->index; + else { + /* find section where the symbol relates to */ + /*@dependent@*/ /*@null@*/ yasm_section *dsect; + /*@dependent@*/ /*@null@*/ yasm_bytecode *precbc; + symnum = 0; /* default to absolute */ + if (yasm_symrec_get_label(reloc->reloc.sym, &precbc) && + (dsect = yasm_bc_get_section(precbc)) && + (msd = yasm_section_get_data(dsect, &macho_section_data_cb))) + symnum = msd->scnum+1; + } + YASM_WRITE_32_L(localbuf, + (symnum & 0x00ffffff) | + (((unsigned long)reloc->pcrel & 1) << 24) | + (((unsigned long)reloc->length & 3) << 25) | + (((unsigned long)reloc->ext & 1) << 27) | + (((unsigned long)reloc->type & 0xf) << 28)); + fwrite(info->buf, 8, 1, info->f); + reloc = (macho_reloc *)yasm_section_reloc_next((yasm_reloc *)reloc); + } + + return 0; +} + +static int +exp2_to_bits(unsigned long val) +{ + int ret = 0; + + while (val) { + val >>= 1; + ret++; + } + ret = (ret > 0) ? ret - 1 : 0; + + return ret; +} + +static int +macho_objfmt_is_section_label(yasm_symrec *sym) +{ + /*@dependent@*/ /*@null@*/ yasm_section *sect; + /*@dependent@*/ /*@null@*/ yasm_bytecode *precbc; + + /* Look at symrec for value/scnum/etc. */ + if (yasm_symrec_get_label(sym, &precbc)) { + if (precbc) + sect = yasm_bc_get_section(precbc); + else + sect = NULL; + /* it's a label: get value and offset. + * If there is not a section, leave as debugging symbol. + */ + if (sect) { + /*@dependent@*/ /*@null@*/ macho_section_data *msd; + + msd = yasm_section_get_data(sect, &macho_section_data_cb); + if (msd) { + if (msd->sym == sym) + return 1; /* don't store section names */ + } + } + } + return 0; +} + +static int +macho_objfmt_output_secthead(yasm_section *sect, /*@null@*/ void *d) +{ + /*@null@*/ macho_objfmt_output_info *info = (macho_objfmt_output_info *)d; + /*@dependent@*/ /*@null@*/ macho_section_data *msd; + unsigned char *localbuf; + + assert(info != NULL); + msd = yasm_section_get_data(sect, &macho_section_data_cb); + assert(msd != NULL); + + localbuf = info->buf; + + memset(localbuf, 0, 16); + strncpy((char *)localbuf, msd->sectname, 16); + localbuf += 16; + memset(localbuf, 0, 16); + strncpy((char *)localbuf, msd->segname, 16); + localbuf += 16; + /* section address, size depend on 32/64 bit mode */ + YASM_WRITE_32_L(localbuf, msd->vmoff); /* address in memory */ + if (info->is_64) + YASM_WRITE_32_L(localbuf, 0); /* 64-bit mode: upper 32 bits = 0 */ + YASM_WRITE_32_L(localbuf, msd->size); /* size in memory */ + if (info->is_64) + YASM_WRITE_32_L(localbuf, 0); /* 64-bit mode: upper 32 bits = 0 */ + + /* offset,align,reloff,nreloc,flags,reserved1,reserved2 are 32 bit */ + if ((msd->flags & SECTION_TYPE) != S_ZEROFILL) { + YASM_WRITE_32_L(localbuf, msd->offset); + YASM_WRITE_32_L(localbuf, exp2_to_bits(yasm_section_get_align(sect))); + if (msd->nreloc) { + msd->flags |= S_ATTR_LOC_RELOC; + if (msd->extreloc) + msd->flags |= S_ATTR_EXT_RELOC; + YASM_WRITE_32_L(localbuf, + align32((long)(info->rel_base + info->s_reloff))); + YASM_WRITE_32_L(localbuf, msd->nreloc); /* nreloc */ + } else { + YASM_WRITE_32_L(localbuf, 0); + YASM_WRITE_32_L(localbuf, 0); + } + + info->s_reloff += msd->nreloc * MACHO_RELINFO_SIZE; /* nreloc */ + } else { + YASM_WRITE_32_L(localbuf, 0); /* these are zero in BSS */ + YASM_WRITE_32_L(localbuf, 0); + YASM_WRITE_32_L(localbuf, 0); + YASM_WRITE_32_L(localbuf, 0); + } + + YASM_WRITE_32_L(localbuf, msd->flags); /* flags */ + YASM_WRITE_32_L(localbuf, 0); /* reserved 1 */ + YASM_WRITE_32_L(localbuf, 0); /* reserved 2 */ + + if (info->is_64) + fwrite(info->buf, MACHO_SECTCMD64_SIZE, 1, info->f); + else + fwrite(info->buf, MACHO_SECTCMD_SIZE, 1, info->f); + + return 0; +} + + +static int +macho_objfmt_count_sym(yasm_symrec *sym, /*@null@*/ void *d) +{ + /*@null@*/ macho_objfmt_output_info *info = (macho_objfmt_output_info *)d; + /*@only@*/ char *name; + yasm_sym_vis vis = yasm_symrec_get_visibility(sym); + + assert(info != NULL); + if (info->all_syms || + vis & (YASM_SYM_GLOBAL | YASM_SYM_COMMON | YASM_SYM_EXTERN)) { + if (0 == macho_objfmt_is_section_label(sym)) { + /* Save index in symrec data */ + macho_symrec_data *sym_data = + yasm_symrec_get_data(sym, &macho_symrec_data_cb); + if (!sym_data) { + sym_data = yasm_xcalloc(sizeof(macho_symrec_data), 1); + yasm_symrec_add_data(sym, &macho_symrec_data_cb, sym_data); + } + sym_data->index = info->symindex; + info->symindex++; + + name = yasm_symrec_get_global_name(sym, info->object); + /*printf("%s\n",name); */ + /* name length + delimiter */ + sym_data->length = (unsigned long)strlen(name) + 1; + info->strlength += sym_data->length; + info->indx++; + yasm_xfree(name); + } + } + return 0; +} + + +static int +macho_objfmt_output_symtable(yasm_symrec *sym, /*@null@*/ void *d) +{ + /*@null@*/ macho_objfmt_output_info *info = (macho_objfmt_output_info *)d; + yasm_sym_vis vis = yasm_symrec_get_visibility(sym); + + assert(info != NULL); + + if (info->all_syms || + vis & (YASM_SYM_GLOBAL | YASM_SYM_COMMON | YASM_SYM_EXTERN)) { + const yasm_expr *equ_val; + const yasm_intnum *intn; + unsigned long value = 0; + long scnum = -3; /* -3 = debugging symbol */ + /*@dependent@*/ /*@null@*/ yasm_section *sect; + /*@dependent@*/ /*@null@*/ yasm_bytecode *precbc; + unsigned char *localbuf; + yasm_intnum *val; + unsigned int long_int_bytes = (info->is_64) ? 8 : 4; + unsigned int n_type = 0, n_sect = 0, n_desc = 0; + macho_symrec_data *symd; + + val = yasm_intnum_create_uint(0); + + symd = yasm_symrec_get_data(sym, &macho_symrec_data_cb); + + /* Look at symrec for value/scnum/etc. */ + if (yasm_symrec_get_label(sym, &precbc)) { + if (precbc) + sect = yasm_bc_get_section(precbc); + else + sect = NULL; + /* it's a label: get value and offset. + * If there is not a section, leave as debugging symbol. + */ + if (sect) { + /*@dependent@*/ /*@null@*/ macho_section_data *msd; + + msd = yasm_section_get_data(sect, &macho_section_data_cb); + if (msd) { + if (msd->sym == sym) { + /* don't store section names */ + yasm_intnum_destroy(val); + return 0; + } + scnum = msd->scnum; + n_type = N_SECT; + } else + yasm_internal_error(N_("didn't understand section")); + if (precbc) + value += yasm_bc_next_offset(precbc); + /* all values are subject to correction: base offset is first + * raw section, therefore add section offset + */ + if (msd) + value += msd->vmoff; + yasm_intnum_set_uint(val, value); + /*printf("%s offset %lx\n",name,value);*/ + } + } else if ((equ_val = yasm_symrec_get_equ(sym))) { + yasm_expr *equ_val_copy = yasm_expr_copy(equ_val); + + intn = yasm_expr_get_intnum(&equ_val_copy, 1); + if (!intn) { + if (vis & YASM_SYM_GLOBAL) { + yasm_error_set(YASM_ERROR_NOT_CONSTANT, + N_("global EQU value not an integer expression")); + yasm_errwarn_propagate(info->errwarns, equ_val->line); + } + } else + value = yasm_intnum_get_uint(intn); + yasm_expr_destroy(equ_val_copy); + yasm_intnum_set_uint(val, value); + n_type = N_ABS; + scnum = -2; /* -2 = absolute symbol */ + } + + if (vis & YASM_SYM_EXTERN) { + n_type = N_EXT; + scnum = -1; + /*n_desc = REFERENCE_FLAG_UNDEFINED_LAZY; * FIXME: see definition of REFERENCE_FLAG_* above */ + } else if (vis & YASM_SYM_COMMON) { + yasm_expr **csize = yasm_symrec_get_common_size(sym); + n_type = N_UNDF | N_EXT; + if (csize) { + intn = yasm_expr_get_intnum(csize, 1); + if (!intn) { + yasm_error_set(YASM_ERROR_NOT_CONSTANT, + N_("COMMON data size not an integer expression")); + yasm_errwarn_propagate(info->errwarns, (*csize)->line); + } else + yasm_intnum_set_uint(val, yasm_intnum_get_uint(intn)); + } + /*printf("common symbol %s val %lu\n", name, yasm_intnum_get_uint(val));*/ + } else if (vis & YASM_SYM_GLOBAL) { + yasm_valparamhead *valparams = + yasm_symrec_get_objext_valparams(sym); + + struct macho_global_data { + unsigned long flag; /* N_PEXT */ + } data; + + data.flag = 0; + + if (valparams) { + static const yasm_dir_help help[] = { + { "private_extern", 0, yasm_dir_helper_flag_set, + offsetof(struct macho_global_data, flag), N_PEXT }, + }; + yasm_dir_helper(sym, yasm_vps_first(valparams), + yasm_symrec_get_decl_line(sym), help, NELEMS(help), + &data, yasm_dir_helper_valparam_warn); + } + + n_type |= N_EXT | data.flag; + } + + localbuf = info->buf; + YASM_WRITE_32_L(localbuf, info->indx); /* offset in string table */ + YASM_WRITE_8(localbuf, n_type); /* type of symbol entry */ + n_sect = (scnum >= 0) ? scnum + 1 : NO_SECT; + YASM_WRITE_8(localbuf, n_sect); /* referring section where symbol is found */ + YASM_WRITE_16_L(localbuf, n_desc); /* extra description */ + yasm_intnum_get_sized(val, localbuf, long_int_bytes, ((long_int_bytes) << 3), 0, 0, 0); /* value/argument */ + localbuf += long_int_bytes; + if (symd) + symd->value = val; + else + yasm_intnum_destroy(val); + + info->indx += symd->length; + + fwrite(info->buf, 8 + long_int_bytes, 1, info->f); + } + + return 0; +} + + +static int +macho_objfmt_output_str(yasm_symrec *sym, /*@null@*/ void *d) +{ + /*@null@*/ macho_objfmt_output_info *info = (macho_objfmt_output_info *)d; + yasm_sym_vis vis = yasm_symrec_get_visibility(sym); + + assert(info != NULL); + + if (info->all_syms || + vis & (YASM_SYM_GLOBAL | YASM_SYM_COMMON | YASM_SYM_EXTERN)) { + if (0 == macho_objfmt_is_section_label(sym)) { + /*@only@*/ char *name = + yasm_symrec_get_global_name(sym, info->object); + size_t len = strlen(name); + + fwrite(name, len + 1, 1, info->f); + yasm_xfree(name); + } + } + return 0; +} + +static int +macho_objfmt_calc_sectsize(yasm_section *sect, /*@null@ */ void *d) +{ + /*@null@ */ macho_objfmt_output_info *info = + (macho_objfmt_output_info *) d; + /*@dependent@ *//*@null@ */ macho_section_data *msd; + unsigned long align; + + assert(info != NULL); + msd = yasm_section_get_data(sect, &macho_section_data_cb); + assert(msd != NULL); + + msd->size = yasm_bc_next_offset(yasm_section_bcs_last(sect)); + if (!(msd->flags & S_ZEROFILL)) { + msd->offset = info->offset; + info->offset += msd->size; + info->filesize += msd->size; + } + + /* accumulate size in memory */ + msd->vmoff = info->vmsize; + info->vmsize += msd->size; + + /* align both start and end of section */ + align = yasm_section_get_align(sect); + if (align != 0) { + unsigned long delta = msd->vmoff % align; + if (delta > 0) { + msd->vmoff += align - delta; + info->vmsize += align - delta; + } + } + + return 0; +} + +/* write object */ +static void +macho_objfmt_output(yasm_object *object, FILE *f, int all_syms, + yasm_errwarns *errwarns) +{ + yasm_objfmt_macho *objfmt_macho = (yasm_objfmt_macho *)object->objfmt; + macho_objfmt_output_info info; + unsigned char *localbuf; + unsigned long symtab_count = 0; + unsigned long headsize; + unsigned int macho_segcmdsize, macho_sectcmdsize, macho_nlistsize; + unsigned int macho_segcmd; + unsigned int head_ncmds, head_sizeofcmds; + unsigned long fileoffset, fileoff_sections; + yasm_intnum *val; + unsigned long long_int_bytes; + const char pad_data[3] = "\0\0\0"; + + info.object = object; + info.objfmt_macho = objfmt_macho; + info.errwarns = errwarns; + info.f = f; + info.buf = yasm_xmalloc(REGULAR_OUTBUF_SIZE); + + if (objfmt_macho->parse_scnum == 0) { + yasm_internal_error(N_("no sections defined")); + /*@notreached@*/ + return; + } + + val = yasm_intnum_create_uint(0); + + /* + * MACH-O Header, Seg CMD, Sect CMDs, Sym Tab, Reloc Data + */ + info.is_64 = (objfmt_macho->bits == 32) ? 0 : 1; + if (info.is_64) { + /* this works only when SYMBOLS and SECTIONS present */ + headsize = + MACHO_HEADER64_SIZE + MACHO_SEGCMD64_SIZE + + (MACHO_SECTCMD64_SIZE * (objfmt_macho->parse_scnum)) + + MACHO_SYMCMD_SIZE; + macho_segcmd = LC_SEGMENT_64; + macho_segcmdsize = MACHO_SEGCMD64_SIZE; + macho_sectcmdsize = MACHO_SECTCMD64_SIZE; + macho_nlistsize = MACHO_NLIST64_SIZE; + long_int_bytes = 8; + } else { + headsize = + MACHO_HEADER_SIZE + MACHO_SEGCMD_SIZE + + (MACHO_SECTCMD_SIZE * (objfmt_macho->parse_scnum)) + + MACHO_SYMCMD_SIZE; + macho_segcmd = LC_SEGMENT; + macho_segcmdsize = MACHO_SEGCMD_SIZE; + macho_sectcmdsize = MACHO_SECTCMD_SIZE; + macho_nlistsize = MACHO_NLIST_SIZE; + long_int_bytes = 4; + } + + /* Get number of symbols */ + info.symindex = 0; + info.indx = 0; + info.strlength = 1; /* string table starts with a zero byte */ + info.all_syms = all_syms || info.is_64; + /*info.all_syms = 1; * force all syms into symbol table */ + yasm_symtab_traverse(object->symtab, &info, macho_objfmt_count_sym); + symtab_count = info.indx; + + /* write raw section data first */ + if (fseek(f, (long)headsize, SEEK_SET) < 0) { + yasm__fatal(N_("could not seek on output file")); + /*@notreached@ */ + return; + } + + /* get size of sections in memory (including BSS) and size of sections + * in file (without BSS) + */ + info.vmsize = 0; + info.filesize = 0; + info.offset = headsize; + yasm_object_sections_traverse(object, &info, macho_objfmt_calc_sectsize); + + /* output sections to file */ + yasm_object_sections_traverse(object, &info, macho_objfmt_output_section); + + fileoff_sections = ftell(f); + + /* Write headers */ + if (fseek(f, 0, SEEK_SET) < 0) { + yasm__fatal(N_("could not seek on output file")); + /*@notreached@*/ + return; + } + + localbuf = info.buf; + + /* header size is common to 32 bit and 64 bit variants */ + if (info.is_64) { + YASM_WRITE_32_L(localbuf, MH_MAGIC_64); /* magic number */ + /* i386 64-bit ABI */ + YASM_WRITE_32_L(localbuf, CPU_ARCH_ABI64 | CPU_TYPE_I386); + } else { + YASM_WRITE_32_L(localbuf, MH_MAGIC); /* magic number */ + YASM_WRITE_32_L(localbuf, CPU_TYPE_I386); /* i386 32-bit ABI */ + } + /* i386 all cpu subtype compatible */ + YASM_WRITE_32_L(localbuf, CPU_SUBTYPE_I386_ALL); + YASM_WRITE_32_L(localbuf, MH_OBJECT); /* MACH file type */ + + /* calculate number of commands and their size, put to stream */ + head_ncmds = 0; + head_sizeofcmds = 0; + if (objfmt_macho->parse_scnum > 0) { + head_ncmds++; + head_sizeofcmds += + macho_segcmdsize + macho_sectcmdsize * objfmt_macho->parse_scnum; + } + if (symtab_count > 0) { + head_ncmds++; + head_sizeofcmds += MACHO_SYMCMD_SIZE; + } + + YASM_WRITE_32_L(localbuf, head_ncmds); + YASM_WRITE_32_L(localbuf, head_sizeofcmds); + YASM_WRITE_32_L(localbuf, 0); /* no flags (yet) */ + if (info.is_64) { + YASM_WRITE_32_L(localbuf, 0); /* reserved in 64 bit */ + fileoffset = MACHO_HEADER64_SIZE + head_sizeofcmds; + } else { + /* initial offset to first section */ + fileoffset = MACHO_HEADER_SIZE + head_sizeofcmds; + } + + /* --------------- write segment header command ---------------- */ + YASM_WRITE_32_L(localbuf, macho_segcmd); /* command LC_SEGMENT */ + /* size of load command including section load commands */ + YASM_WRITE_32_L(localbuf, + macho_segcmdsize + + macho_sectcmdsize * objfmt_macho->parse_scnum); + /* in an MH_OBJECT file all sections are in one unnamed (name all zeros) + * segment (16x0) + */ + YASM_WRITE_32_L(localbuf, 0); + YASM_WRITE_32_L(localbuf, 0); + YASM_WRITE_32_L(localbuf, 0); + YASM_WRITE_32_L(localbuf, 0); + + /* in-memory offset, in-memory size */ + yasm_intnum_set_uint(val, 0); /* offset in memory (vmaddr) */ + yasm_intnum_get_sized(val, localbuf, long_int_bytes, + ((long_int_bytes) << 3), 0, 0, 0); + localbuf += long_int_bytes; + yasm_intnum_set_uint(val, info.vmsize); /* size in memory (vmsize) */ + yasm_intnum_get_sized(val, localbuf, long_int_bytes, + ((long_int_bytes) << 3), 0, 0, 0); + localbuf += long_int_bytes; + /* offset in file to first section */ + yasm_intnum_set_uint(val, fileoffset); + yasm_intnum_get_sized(val, localbuf, long_int_bytes, + ((long_int_bytes) << 3), 0, 0, 0); + localbuf += long_int_bytes; + yasm_intnum_set_uint(val, info.filesize); /* overall size in file */ + yasm_intnum_get_sized(val, localbuf, long_int_bytes, + ((long_int_bytes) << 3), 0, 0, 0); + localbuf += long_int_bytes; + + YASM_WRITE_32_L(localbuf, VM_PROT_DEFAULT); /* VM protection, maximum */ + YASM_WRITE_32_L(localbuf, VM_PROT_DEFAULT); /* VM protection, initial */ + /* number of sections */ + YASM_WRITE_32_L(localbuf, objfmt_macho->parse_scnum); + YASM_WRITE_32_L(localbuf, 0); /* no flags */ + + /* write MACH-O header and segment command to outfile */ + fwrite(info.buf, (size_t) (localbuf - info.buf), 1, f); + + /* next: section headers */ + /* offset to relocs for first section */ + info.rel_base = align32((long)fileoff_sections); + info.s_reloff = 0; /* offset for relocs of following sections */ + yasm_object_sections_traverse(object, &info, macho_objfmt_output_secthead); + + localbuf = info.buf; + /* write out symbol command */ + YASM_WRITE_32_L(localbuf, LC_SYMTAB); /* cmd == LC_SYMTAB */ + YASM_WRITE_32_L(localbuf, MACHO_SYMCMD_SIZE); + /* symbol table offset */ + YASM_WRITE_32_L(localbuf, info.rel_base + info.s_reloff); + YASM_WRITE_32_L(localbuf, symtab_count); /* number of symbols */ + + YASM_WRITE_32_L(localbuf, macho_nlistsize * symtab_count + info.rel_base + + info.s_reloff); /* string table offset */ + YASM_WRITE_32_L(localbuf, info.strlength); /* string table size */ + /* write symbol command */ + fwrite(info.buf, (size_t)(localbuf - info.buf), 1, f); + + /*printf("num symbols %d, vmsize %d, filesize %d\n",symtab_count, + info.vmsize, info.filesize ); */ + + /* get back to end of raw section data */ + if (fseek(f, (long)fileoff_sections, SEEK_SET) < 0) { + yasm__fatal(N_("could not seek on output file")); + /*@notreached@*/ + return; + } + + /* padding to long boundary */ + if ((info.rel_base - fileoff_sections) > 0) { + fwrite(pad_data, info.rel_base - fileoff_sections, 1, f); + } + + /* relocation data */ + yasm_object_sections_traverse(object, &info, macho_objfmt_output_relocs); + + /* symbol table (NLIST) */ + info.indx = 1; /* restart symbol table indices */ + yasm_symtab_traverse(object->symtab, &info, macho_objfmt_output_symtable); + + /* symbol strings */ + fwrite(pad_data, 1, 1, f); + yasm_symtab_traverse(object->symtab, &info, macho_objfmt_output_str); + + yasm_intnum_destroy(val); + yasm_xfree(info.buf); +} + +static void +macho_objfmt_destroy(yasm_objfmt *objfmt) +{ + yasm_xfree(objfmt); +} + +static void +macho_objfmt_init_new_section(yasm_section *sect, unsigned long line) +{ + yasm_object *object = yasm_section_get_object(sect); + const char *sectname = yasm_section_get_name(sect); + yasm_objfmt_macho *objfmt_macho = (yasm_objfmt_macho *)object->objfmt; + macho_section_data *data; + yasm_symrec *sym; + + data = yasm_xmalloc(sizeof(macho_section_data)); + data->scnum = objfmt_macho->parse_scnum++; + data->segname = NULL; + data->sectname = NULL; + data->flags = S_REGULAR; + data->size = 0; + data->offset = 0; + data->vmoff = 0; + data->nreloc = 0; + data->extreloc = 0; + yasm_section_add_data(sect, &macho_section_data_cb, data); + + sym = yasm_symtab_define_label(object->symtab, sectname, + yasm_section_bcs_first(sect), 1, line); + data->sym = sym; +} + +static yasm_section * +macho_objfmt_add_default_section(yasm_object *object) +{ + yasm_section *retval; + macho_section_data *msd; + int isnew; + + retval = yasm_object_get_general(object, "LC_SEGMENT.__TEXT.__text", 0, 1, + 0, &isnew, 0); + if (isnew) { + msd = yasm_section_get_data(retval, &macho_section_data_cb); + msd->segname = yasm__xstrdup("__TEXT"); + msd->sectname = yasm__xstrdup("__text"); + msd->flags = S_ATTR_PURE_INSTRUCTIONS; + yasm_section_set_align(retval, 0, 0); + yasm_section_set_default(retval, 1); + } + return retval; +} + +static /*@observer@*/ /*@null@*/ yasm_section * +macho_objfmt_section_switch(yasm_object *object, yasm_valparamhead *valparams, + /*@unused@*/ /*@null@*/ + yasm_valparamhead *objext_valparams, + unsigned long line) +{ + yasm_valparam *vp; + yasm_section *retval; + int isnew; + /*@only@*/ char *f_sectname; + unsigned long flags; + unsigned long align; + int flags_override = 0; + const char *sectname; + char *realname; + int resonly = 0; + macho_section_data *msd; + size_t i; + + static const struct { + const char *in; + const char *seg; + const char *sect; + unsigned long flags; + unsigned long align; + } section_name_translation[] = { + {".text", "__TEXT", "__text", S_ATTR_PURE_INSTRUCTIONS, 0}, + {".const", "__TEXT", "__const", S_REGULAR, 0}, + {".static_const", "__TEXT", "__static_const", S_REGULAR, 0}, + {".cstring", "__TEXT", "__cstring", S_CSTRING_LITERALS, 0}, + {".literal4", "__TEXT", "__literal4", S_4BYTE_LITERALS, 4}, + {".literal8", "__TEXT", "__literal8", S_8BYTE_LITERALS, 8}, + {".literal16", "__TEXT", "__literal16", S_16BYTE_LITERALS, 16}, + {".constructor", "__TEXT", "__constructor", S_REGULAR, 0}, + {".destructor", "__TEXT", "__destructor", S_REGULAR, 0}, + {".fvmlib_init0", "__TEXT", "__fvmlib_init0", S_REGULAR, 0}, + {".fvmlib_init1", "__TEXT", "__fvmlib_init1", S_REGULAR, 0}, + {".mod_init_func", "__DATA", "__mod_init_func", + S_MOD_INIT_FUNC_POINTERS, 4}, + {".mod_term_func", "__DATA", "__mod_term_func", + S_MOD_TERM_FUNC_POINTERS, 4}, + {".dyld", "__DATA", "__dyld", S_REGULAR, 0}, + {".data", "__DATA", "__data", S_REGULAR, 0}, + {".static_data", "__DATA", "__static_data", S_REGULAR, 0}, + {".const_data", "__DATA", "__const", S_REGULAR, 0}, + {".rodata", "__DATA", "__const", S_REGULAR, 0}, + {".bss", "__DATA", "__bss", S_ZEROFILL, 0}, + {".objc_class_names", "__TEXT", "__cstring", S_CSTRING_LITERALS, 0}, + {".objc_meth_var_types","__TEXT", "__cstring", S_CSTRING_LITERALS, 0}, + {".objc_meth_var_names","__TEXT", "__cstring", S_CSTRING_LITERALS, 0}, + {".objc_selector_strs", "__OBJC", "__selector_strs", + S_CSTRING_LITERALS, 0}, + {".objc_class", "__OBJC", "__class", + S_ATTR_NO_DEAD_STRIP, 0}, + {".objc_meta_class", "__OBJC", "__meta_class", + S_ATTR_NO_DEAD_STRIP, 0}, + {".objc_string_object", "__OBJC", "__string_object", + S_ATTR_NO_DEAD_STRIP, 0}, + {".objc_protocol", "__OBJC", "__protocol", + S_ATTR_NO_DEAD_STRIP, 0}, + {".objc_cat_cls_meth", "__OBJC", "__cat_cls_meth", + S_ATTR_NO_DEAD_STRIP, 0}, + {".objc_cat_inst_meth", "__OBJC", "__cat_inst_meth", + S_ATTR_NO_DEAD_STRIP, 0}, + {".objc_cls_meth", "__OBJC", "__cls_meth", + S_ATTR_NO_DEAD_STRIP, 0}, + {".objc_inst_meth", "__OBJC", "__inst_meth", + S_ATTR_NO_DEAD_STRIP, 0}, + {".objc_message_refs", "__OBJC", "__message_refs", + S_LITERAL_POINTERS|S_ATTR_NO_DEAD_STRIP, 4}, + {".objc_cls_refs", "__OBJC", "__cls_refs", + S_LITERAL_POINTERS|S_ATTR_NO_DEAD_STRIP, 4}, + {".objc_module_info", "__OBJC", "__module_info", + S_ATTR_NO_DEAD_STRIP, 0}, + {".objc_symbols", "__OBJC", "__symbols", + S_ATTR_NO_DEAD_STRIP, 0}, + {".objc_category", "__OBJC", "__category", + S_ATTR_NO_DEAD_STRIP, 0}, + {".objc_class_vars", "__OBJC", "__class_vars", + S_ATTR_NO_DEAD_STRIP, 0}, + {".objc_instance_vars", "__OBJC", "__instance_vars", + S_ATTR_NO_DEAD_STRIP, 0} + }; + + struct macho_section_switch_data { + /*@only@*/ /*@null@*/ char *f_segname; + /*@only@*/ /*@null@*/ yasm_intnum *align_intn; + } data; + + static const yasm_dir_help help[] = { + { "segname", 1, yasm_dir_helper_string, + offsetof(struct macho_section_switch_data, f_segname), 0 }, + { "align", 1, yasm_dir_helper_intn, + offsetof(struct macho_section_switch_data, align_intn), 0 } + }; + + data.f_segname = NULL; + data.align_intn = NULL; + + vp = yasm_vps_first(valparams); + sectname = yasm_vp_string(vp); + if (!sectname) + return NULL; + vp = yasm_vps_next(vp); + + /* translate .text,.data,.bss to __text,__data,__bss... */ + for (i=0; i<NELEMS(section_name_translation); i++) { + if (yasm__strcasecmp(sectname, section_name_translation[i].in) == 0) + break; + } + + if (i == NELEMS(section_name_translation)) { + const char *s; + if (vp && !vp->val && (s = yasm_vp_string(vp))) { + /* Treat as SEGNAME, SECTNAME */ + if (strlen(sectname) > 16) + yasm_warn_set(YASM_WARN_GENERAL, + N_("segment name is too long, max 16 chars; truncating")); + data.f_segname = yasm__xstrndup(sectname, 16); + if (strlen(s) > 16) + yasm_warn_set(YASM_WARN_GENERAL, + N_("section name is too long, max 16 chars; truncating")); + f_sectname = yasm__xstrndup(s, 16); + flags = S_REGULAR; + align = 0; + + sectname = s; + vp = yasm_vps_next(vp); + } else { + data.f_segname = NULL; + if (strlen(sectname) > 16) + yasm_warn_set(YASM_WARN_GENERAL, + N_("section name is too long, max 16 chars; truncating")); + f_sectname = yasm__xstrndup(sectname, 16); + flags = S_ATTR_SOME_INSTRUCTIONS; + align = 0; + } + } else { + data.f_segname = yasm__xstrdup(section_name_translation[i].seg); + f_sectname = yasm__xstrdup(section_name_translation[i].sect); + flags = section_name_translation[i].flags; + align = section_name_translation[i].align; + } + + flags_override = yasm_dir_helper(object, vp, line, help, NELEMS(help), + &data, yasm_dir_helper_valparam_warn); + if (flags_override < 0) + return NULL; /* error occurred */ + + if (data.align_intn) { + align = yasm_intnum_get_uint(data.align_intn); + yasm_intnum_destroy(data.align_intn); + + /* Alignments must be a power of two. */ + if (!is_exp2(align)) { + yasm_error_set(YASM_ERROR_VALUE, + N_("argument to `%s' is not a power of two"), + vp->val); + return NULL; + } + + /* Check to see if alignment is supported size */ + if (align > 16384) { + yasm_error_set(YASM_ERROR_VALUE, + N_("macho implementation does not support alignments > 16384")); + return NULL; + } + } + + if (!data.f_segname) { + yasm_warn_set(YASM_WARN_GENERAL, + N_("Unknown section name, defaulting to __TEXT segment")); + data.f_segname = yasm__xstrdup("__TEXT"); + } + + /* Build a unique sectname from f_segname and f_sectname. */ + realname = yasm_xmalloc(strlen("LC_SEGMENT") + 1 + strlen(data.f_segname) + 1 + + strlen(f_sectname) + 1); + sprintf(realname, "LC_SEGMENT.%s.%s", data.f_segname, f_sectname); + retval = yasm_object_get_general(object, realname, align, 1, resonly, + &isnew, line); + yasm_xfree(realname); + + msd = yasm_section_get_data(retval, &macho_section_data_cb); + + if (isnew || yasm_section_is_default(retval)) { + yasm_section_set_default(retval, 0); + msd->segname = data.f_segname; + msd->sectname = f_sectname; + msd->flags = flags; + yasm_section_set_align(retval, align, line); + } else if (flags_override) { + /* align is the only value used from overrides. */ + if (yasm_section_get_align(retval) != align) { + yasm_warn_set(YASM_WARN_GENERAL, + N_("section flags ignored on section redeclaration")); + } + } + return retval; +} + +static /*@observer@*/ /*@null@*/ yasm_symrec * +macho_objfmt_get_special_sym(yasm_object *object, const char *name, + const char *parser) +{ + yasm_objfmt_macho *objfmt_macho = (yasm_objfmt_macho *)object->objfmt; + if (yasm__strcasecmp(name, "gotpcrel") == 0) { + return objfmt_macho->gotpcrel_sym; + } + return NULL; +} + +static void +macho_section_data_destroy(void *data) +{ + macho_section_data *msd = (macho_section_data *) data; + yasm_xfree(msd->segname); + yasm_xfree(msd->sectname); + yasm_xfree(data); +} + +static void +macho_section_data_print(void *data, FILE *f, int indent_level) +{ + macho_section_data *msd = (macho_section_data *) data; + + fprintf(f, "%*ssym=\n", indent_level, ""); + yasm_symrec_print(msd->sym, f, indent_level + 1); + fprintf(f, "%*sscnum=%ld\n", indent_level, "", msd->scnum); + fprintf(f, "%*sflags=0x%lx\n", indent_level, "", msd->flags); + fprintf(f, "%*ssize=%lu\n", indent_level, "", msd->size); + fprintf(f, "%*snreloc=%lu\n", indent_level, "", msd->nreloc); + fprintf(f, "%*soffset=%lu\n", indent_level, "", msd->offset); + fprintf(f, "%*sextreloc=%u\n", indent_level, "", msd->extreloc); +} + +static void +macho_symrec_data_destroy(void *data) +{ + yasm_xfree(data); +} + +static void +macho_symrec_data_print(void *data, FILE *f, int indent_level) +{ + macho_symrec_data *msd = (macho_symrec_data *)data; + + fprintf(f, "%*sindex=%ld\n", indent_level, "", msd->index); + fprintf(f, "%*svalue=", indent_level, ""); + if (msd->value) + fprintf(f, "%ld\n", yasm_intnum_get_int(msd->value)); + else + fprintf(f, "nil\n"); +} + + +/* Define valid debug formats to use with this object format */ +static const char *macho_objfmt_dbgfmt_keywords[] = { + "null", + NULL +}; + +/* Define objfmt structure -- see objfmt.h for details */ +yasm_objfmt_module yasm_macho_LTX_objfmt = { + "Mac OS X ABI Mach-O File Format", + "macho", + "o", + 32, + 0, + macho_objfmt_dbgfmt_keywords, + "null", + NULL, /* no directives */ + NULL, /* no standard macros */ + macho_objfmt_create, + macho_objfmt_output, + macho_objfmt_destroy, + macho_objfmt_add_default_section, + macho_objfmt_init_new_section, + macho_objfmt_section_switch, + macho_objfmt_get_special_sym +}; + +yasm_objfmt_module yasm_macho32_LTX_objfmt = { + "Mac OS X ABI Mach-O File Format (32-bit)", + "macho32", + "o", + 32, + 0, + macho_objfmt_dbgfmt_keywords, + "null", + NULL, /* no directives */ + NULL, /* no standard macros */ + macho32_objfmt_create, + macho_objfmt_output, + macho_objfmt_destroy, + macho_objfmt_add_default_section, + macho_objfmt_init_new_section, + macho_objfmt_section_switch, + macho_objfmt_get_special_sym +}; + +yasm_objfmt_module yasm_macho64_LTX_objfmt = { + "Mac OS X ABI Mach-O File Format (64-bit)", + "macho64", + "o", + 64, + 0, + macho_objfmt_dbgfmt_keywords, + "null", + NULL, /* no directives */ + NULL, /* no standard macros */ + macho64_objfmt_create, + macho_objfmt_output, + macho_objfmt_destroy, + macho_objfmt_add_default_section, + macho_objfmt_init_new_section, + macho_objfmt_section_switch, + macho_objfmt_get_special_sym +}; diff --git a/contrib/tools/yasm/modules/objfmts/rdf/rdf-objfmt.c b/contrib/tools/yasm/modules/objfmts/rdf/rdf-objfmt.c new file mode 100644 index 0000000000..eb3c66688c --- /dev/null +++ b/contrib/tools/yasm/modules/objfmts/rdf/rdf-objfmt.c @@ -0,0 +1,1088 @@ +/* + * Relocatable Dynamic Object File Format (RDOFF) version 2 format + * + * Copyright (C) 2006-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> + + +#define REGULAR_OUTBUF_SIZE 1024 + +#define RDF_MAGIC "RDOFF2" + +/* Maximum size of an import/export label (including trailing zero) */ +#define EXIM_LABEL_MAX 64 + +/* Maximum size of library or module name (including trailing zero) */ +#define MODLIB_NAME_MAX 128 + +/* Maximum number of segments that we can handle in one file */ +#define RDF_MAXSEGS 64 + +/* Record types that may present the RDOFF header */ +#define RDFREC_GENERIC 0 +#define RDFREC_RELOC 1 +#define RDFREC_IMPORT 2 +#define RDFREC_GLOBAL 3 +#define RDFREC_DLL 4 +#define RDFREC_BSS 5 +#define RDFREC_SEGRELOC 6 +#define RDFREC_FARIMPORT 7 +#define RDFREC_MODNAME 8 +#define RDFREC_COMMON 10 + +/* Flags for ExportRec/ImportRec */ +#define SYM_DATA 1 +#define SYM_FUNCTION 2 + +/* Flags for ExportRec */ +#define SYM_GLOBAL 4 + +/* Flags for ImportRec */ +#define SYM_IMPORT 8 +#define SYM_FAR 16 + +typedef struct rdf_reloc { + yasm_reloc reloc; + enum { + RDF_RELOC_NORM, /* normal */ + RDF_RELOC_REL, /* relative to current position */ + RDF_RELOC_SEG /* segment containing symbol */ + } type; /* type of relocation */ + unsigned int size; + unsigned int refseg; +} rdf_reloc; + +typedef struct rdf_section_data { + /*@dependent@*/ yasm_symrec *sym; /* symbol created for this section */ + long scnum; /* section number (0=first section) */ + enum { + RDF_SECT_BSS = 0, + RDF_SECT_CODE = 1, + RDF_SECT_DATA = 2, + RDF_SECT_COMMENT = 3, + RDF_SECT_LCOMMENT = 4, + RDF_SECT_PCOMMENT = 5, + RDF_SECT_SYMDEBUG = 6, + RDF_SECT_LINEDEBUG = 7 + } type; /* section type */ + unsigned int reserved; /* reserved data */ + unsigned long size; /* size of raw data (section data) in bytes */ + + unsigned char *raw_data; /* raw section data, only used during output */ +} rdf_section_data; + +typedef struct rdf_symrec_data { + unsigned int segment; /* assigned RDF "segment" index */ +} rdf_symrec_data; + +typedef STAILQ_HEAD(xdf_str_head, xdf_str) xdf_str_head; +typedef struct xdf_str { + STAILQ_ENTRY(xdf_str) link; + /*@owned@*/ char *str; +} xdf_str; + +typedef struct yasm_objfmt_rdf { + yasm_objfmt_base objfmt; /* base structure */ + + long parse_scnum; /* sect numbering in parser */ + + /*@owned@*/ xdf_str_head module_names; + /*@owned@*/ xdf_str_head library_names; +} yasm_objfmt_rdf; + +typedef struct rdf_objfmt_output_info { + yasm_object *object; + yasm_objfmt_rdf *objfmt_rdf; + yasm_errwarns *errwarns; + /*@dependent@*/ FILE *f; + /*@only@*/ unsigned char *buf; + yasm_section *sect; + /*@dependent@*/ rdf_section_data *rsd; + + unsigned long indx; /* symbol "segment" (extern/common only) */ + + unsigned long bss_size; /* total BSS size */ +} rdf_objfmt_output_info; + +static void rdf_section_data_destroy(/*@only@*/ void *d); +static void rdf_section_data_print(void *data, FILE *f, int indent_level); + +static const yasm_assoc_data_callback rdf_section_data_cb = { + rdf_section_data_destroy, + rdf_section_data_print +}; + +static void rdf_symrec_data_destroy(/*@only@*/ void *d); +static void rdf_symrec_data_print(void *data, FILE *f, int indent_level); + +static const yasm_assoc_data_callback rdf_symrec_data_cb = { + rdf_symrec_data_destroy, + rdf_symrec_data_print +}; + +yasm_objfmt_module yasm_rdf_LTX_objfmt; + + +static /*@dependent@*/ rdf_symrec_data * +rdf_objfmt_sym_set_data(yasm_symrec *sym, unsigned int segment) +{ + rdf_symrec_data *rsymd = yasm_xmalloc(sizeof(rdf_symrec_data)); + + rsymd->segment = segment; + + yasm_symrec_add_data(sym, &rdf_symrec_data_cb, rsymd); + return rsymd; +} + +static yasm_objfmt * +rdf_objfmt_create(yasm_object *object) +{ + yasm_objfmt_rdf *objfmt_rdf = yasm_xmalloc(sizeof(yasm_objfmt_rdf)); + + /* We theoretically support all arches, so don't check. + * Really we only support byte-addressable ones. + */ + + objfmt_rdf->parse_scnum = 0; /* section numbering starts at 0 */ + + STAILQ_INIT(&objfmt_rdf->module_names); + STAILQ_INIT(&objfmt_rdf->library_names); + + objfmt_rdf->objfmt.module = &yasm_rdf_LTX_objfmt; + + return (yasm_objfmt *)objfmt_rdf; +} + +static int +rdf_objfmt_output_value(yasm_value *value, unsigned char *buf, + unsigned int destsize, unsigned long offset, + yasm_bytecode *bc, int warn, /*@null@*/ void *d) +{ + /*@null@*/ rdf_objfmt_output_info *info = (rdf_objfmt_output_info *)d; + /*@dependent@*/ /*@null@*/ yasm_intnum *intn; + unsigned long intn_minus; + unsigned long intn_plus; + int retval; + unsigned int valsize = value->size; + + assert(info != NULL); + + if (value->abs) + value->abs = yasm_expr_simplify(value->abs, 1); + + /* Try to output constant and PC-relative section-local first. + * Note this does NOT output any value with a SEG, WRT, external, + * cross-section, or non-PC-relative reference (those are handled below). + */ + switch (yasm_value_output_basic(value, buf, destsize, bc, warn, + info->object->arch)) { + case -1: + return 1; + case 0: + break; + default: + return 0; + } + + if (value->section_rel) { + yasm_error_set(YASM_ERROR_TOO_COMPLEX, + N_("rdf: relocation too complex")); + return 1; + } + + if (value->rel && value->wrt) { + yasm_error_set(YASM_ERROR_TOO_COMPLEX, + N_("rdf: WRT not supported")); + return 1; + } + + intn_minus = 0; + intn_plus = 0; + if (value->rel) { + rdf_reloc *reloc; + /*@null@*/ rdf_symrec_data *rsymd; + /*@dependent@*/ yasm_bytecode *precbc; + + reloc = yasm_xmalloc(sizeof(rdf_reloc)); + reloc->reloc.addr = yasm_intnum_create_uint(bc->offset + offset); + reloc->reloc.sym = value->rel; + reloc->size = valsize/8; + + if (value->seg_of) + reloc->type = RDF_RELOC_SEG; + else if (value->curpos_rel) { + reloc->type = RDF_RELOC_REL; + /* Adjust to start of section, so subtract out the bytecode + * offset. + */ + intn_minus = bc->offset; + } else + reloc->type = RDF_RELOC_NORM; + + if (yasm_symrec_get_label(value->rel, &precbc)) { + /* local, set the value to be the offset, and the refseg to the + * segment number. + */ + /*@dependent@*/ /*@null@*/ rdf_section_data *csectd; + /*@dependent@*/ yasm_section *sect; + + sect = yasm_bc_get_section(precbc); + csectd = yasm_section_get_data(sect, &rdf_section_data_cb); + if (!csectd) + yasm_internal_error(N_("didn't understand section")); + reloc->refseg = csectd->scnum; + intn_plus = yasm_bc_next_offset(precbc); + } else { + /* must be common/external */ + rsymd = yasm_symrec_get_data(reloc->reloc.sym, + &rdf_symrec_data_cb); + if (!rsymd) + yasm_internal_error( + N_("rdf: no symbol data for relocated symbol")); + reloc->refseg = rsymd->segment; + } + + yasm_section_add_reloc(info->sect, (yasm_reloc *)reloc, yasm_xfree); + } + + if (intn_minus > 0) { + intn = yasm_intnum_create_uint(intn_minus); + yasm_intnum_calc(intn, YASM_EXPR_NEG, NULL); + } else + intn = yasm_intnum_create_uint(intn_plus); + + if (value->abs) { + yasm_intnum *intn2 = yasm_expr_get_intnum(&value->abs, 0); + if (!intn2) { + yasm_error_set(YASM_ERROR_TOO_COMPLEX, + N_("rdf: relocation too complex")); + yasm_intnum_destroy(intn); + return 1; + } + yasm_intnum_calc(intn, YASM_EXPR_ADD, intn2); + } + + retval = yasm_arch_intnum_tobytes(info->object->arch, intn, buf, destsize, + valsize, 0, bc, warn); + yasm_intnum_destroy(intn); + return retval; +} + +static int +rdf_objfmt_output_bytecode(yasm_bytecode *bc, /*@null@*/ void *d) +{ + /*@null@*/ rdf_objfmt_output_info *info = (rdf_objfmt_output_info *)d; + /*@null@*/ /*@only@*/ unsigned char *bigbuf; + unsigned long size = REGULAR_OUTBUF_SIZE; + int gap; + + assert(info != NULL); + + bigbuf = yasm_bc_tobytes(bc, info->buf, &size, &gap, info, + rdf_objfmt_output_value, NULL); + + /* Don't bother doing anything else if size ended up being 0. */ + if (size == 0) { + if (bigbuf) + yasm_xfree(bigbuf); + return 0; + } + + /* Warn that gaps are converted to 0 and write out the 0's. */ + if (gap) { + yasm_warn_set(YASM_WARN_UNINIT_CONTENTS, + N_("uninitialized space: zeroing")); + /* Write out in chunks */ + memset(&info->rsd->raw_data[info->rsd->size], 0, size); + } else { + /* Output buf (or bigbuf if non-NULL) to file */ + memcpy(&info->rsd->raw_data[info->rsd->size], + bigbuf ? bigbuf : info->buf, (size_t)size); + } + + info->rsd->size += size; + + /* If bigbuf was allocated, free it */ + if (bigbuf) + yasm_xfree(bigbuf); + + return 0; +} + +static int +rdf_objfmt_output_section_mem(yasm_section *sect, /*@null@*/ void *d) +{ + /*@null@*/ rdf_objfmt_output_info *info = (rdf_objfmt_output_info *)d; + /*@dependent@*/ /*@null@*/ rdf_section_data *rsd; + unsigned long size; + + assert(info != NULL); + rsd = yasm_section_get_data(sect, &rdf_section_data_cb); + assert(rsd != NULL); + + size = yasm_bc_next_offset(yasm_section_bcs_last(sect)); + + if (rsd->type == RDF_SECT_BSS) { + /* Don't output BSS sections, but remember length + * TODO: Check for non-reserve bytecodes? + */ + info->bss_size += size; + return 0; + } + + /* Empty? Go on to next section */ + if (size == 0) + return 0; + + /* See UGH comment in output() for why we're doing this */ + rsd->raw_data = yasm_xmalloc(size); + rsd->size = 0; + + info->sect = sect; + info->rsd = rsd; + yasm_section_bcs_traverse(sect, info->errwarns, info, + rdf_objfmt_output_bytecode); + + /* Sanity check final section size */ + if (rsd->size != size) + yasm_internal_error( + N_("rdf: section computed size did not match actual size")); + + return 0; +} + +static int +rdf_objfmt_output_section_reloc(yasm_section *sect, /*@null@*/ void *d) +{ + /*@null@*/ rdf_objfmt_output_info *info = (rdf_objfmt_output_info *)d; + /*@dependent@*/ /*@null@*/ rdf_section_data *rsd; + rdf_reloc *reloc; + + assert(info != NULL); + rsd = yasm_section_get_data(sect, &rdf_section_data_cb); + assert(rsd != NULL); + + if (rsd->type == RDF_SECT_BSS) { + /* Don't output BSS sections. */ + return 0; + } + + /* Empty? Go on to next section */ + if (rsd->size == 0) + return 0; + + reloc = (rdf_reloc *)yasm_section_relocs_first(sect); + while (reloc) { + unsigned char *localbuf = info->buf; + + if (reloc->type == RDF_RELOC_SEG) + YASM_WRITE_8(localbuf, RDFREC_SEGRELOC); + else + YASM_WRITE_8(localbuf, RDFREC_RELOC); + YASM_WRITE_8(localbuf, 8); /* record length */ + /* Section number, +0x40 if relative reloc */ + YASM_WRITE_8(localbuf, rsd->scnum + + (reloc->type == RDF_RELOC_REL ? 0x40 : 0)); + yasm_intnum_get_sized(reloc->reloc.addr, localbuf, 4, 32, 0, 0, 0); + localbuf += 4; /* offset of relocation */ + YASM_WRITE_8(localbuf, reloc->size); /* size of relocation */ + YASM_WRITE_16_L(localbuf, reloc->refseg); /* relocated symbol */ + fwrite(info->buf, 10, 1, info->f); + + reloc = (rdf_reloc *)yasm_section_reloc_next((yasm_reloc *)reloc); + } + + return 0; +} + +static int +rdf_objfmt_output_section_file(yasm_section *sect, /*@null@*/ void *d) +{ + /*@null@*/ rdf_objfmt_output_info *info = (rdf_objfmt_output_info *)d; + /*@dependent@*/ /*@null@*/ rdf_section_data *rsd; + unsigned char *localbuf; + + assert(info != NULL); + rsd = yasm_section_get_data(sect, &rdf_section_data_cb); + assert(rsd != NULL); + + if (rsd->type == RDF_SECT_BSS) { + /* Don't output BSS sections. */ + return 0; + } + + /* Empty? Go on to next section */ + if (rsd->size == 0) + return 0; + + /* Section header */ + localbuf = info->buf; + YASM_WRITE_16_L(localbuf, rsd->type); /* type */ + YASM_WRITE_16_L(localbuf, rsd->scnum); /* number */ + YASM_WRITE_16_L(localbuf, rsd->reserved); /* reserved */ + YASM_WRITE_32_L(localbuf, rsd->size); /* length */ + fwrite(info->buf, 10, 1, info->f); + + /* Section data */ + fwrite(rsd->raw_data, rsd->size, 1, info->f); + + /* Free section data */ + yasm_xfree(rsd->raw_data); + rsd->raw_data = NULL; + + return 0; +} + +#define FLAG_EXT 0x1000 +#define FLAG_GLOB 0x2000 +#define FLAG_SET 0x4000 +#define FLAG_CLR 0x8000 +#define FLAG_MASK 0x0fff + +static int +rdf_helper_flag(void *obj, yasm_valparam *vp, unsigned long line, void *d, + uintptr_t flag) +{ + yasm_symrec *sym = (yasm_symrec *)obj; + yasm_sym_vis vis = yasm_symrec_get_visibility(sym); + unsigned int *flags = (unsigned int *)d; + + if (((vis & YASM_SYM_GLOBAL) && (flag & FLAG_GLOB)) || + ((vis & YASM_SYM_EXTERN) && (flag & FLAG_EXT))) { + if (flag & FLAG_SET) + *flags |= flag & FLAG_MASK; + else if (flag & FLAG_CLR) + *flags &= ~(flag & FLAG_MASK); + } + return 0; +} + +static unsigned int +rdf_parse_flags(yasm_symrec *sym) +{ + /*@dependent@*/ /*@null@*/ yasm_valparamhead *objext_valparams = + yasm_symrec_get_objext_valparams(sym); + unsigned int flags = 0; + + static const yasm_dir_help help[] = { + { "data", 0, rdf_helper_flag, 0, + FLAG_EXT|FLAG_GLOB|FLAG_SET|SYM_DATA }, + { "object", 0, rdf_helper_flag, 0, + FLAG_EXT|FLAG_GLOB|FLAG_SET|SYM_DATA }, + { "proc", 0, rdf_helper_flag, 0, + FLAG_EXT|FLAG_GLOB|FLAG_SET|SYM_FUNCTION }, + { "function", 0, rdf_helper_flag, 0, + FLAG_EXT|FLAG_GLOB|FLAG_SET|SYM_FUNCTION }, + { "import", 0, rdf_helper_flag, 0, FLAG_EXT|FLAG_SET|SYM_IMPORT }, + { "export", 0, rdf_helper_flag, 0, FLAG_GLOB|FLAG_SET|SYM_GLOBAL }, + { "far", 0, rdf_helper_flag, 0, FLAG_EXT|FLAG_SET|SYM_FAR }, + { "near", 0, rdf_helper_flag, 0, FLAG_EXT|FLAG_CLR|SYM_FAR } + }; + + if (!objext_valparams) + return 0; + + yasm_dir_helper(sym, yasm_vps_first(objext_valparams), 0, help, + NELEMS(help), &flags, yasm_dir_helper_valparam_warn); + + return flags; +} + +static int +rdf_objfmt_output_sym(yasm_symrec *sym, /*@null@*/ void *d) +{ + /*@null@*/ rdf_objfmt_output_info *info = (rdf_objfmt_output_info *)d; + yasm_sym_vis vis = yasm_symrec_get_visibility(sym); + /*@only@*/ char *name; + size_t len; + unsigned long value = 0; + unsigned int scnum = 0; + /*@dependent@*/ /*@null@*/ yasm_section *sect; + /*@dependent@*/ /*@null@*/ yasm_bytecode *precbc; + unsigned char *localbuf; + + assert(info != NULL); + + if (vis == YASM_SYM_LOCAL || vis == YASM_SYM_DLOCAL) + return 0; /* skip local syms */ + + /* Look at symrec for value/scnum/etc. */ + if (yasm_symrec_get_label(sym, &precbc)) { + /*@dependent@*/ /*@null@*/ rdf_section_data *csectd; + + if (precbc) + sect = yasm_bc_get_section(precbc); + else + sect = NULL; + if (!sect) + return 0; + + /* it's a label: get value and offset. */ + csectd = yasm_section_get_data(sect, &rdf_section_data_cb); + if (csectd) + scnum = csectd->scnum; + else + yasm_internal_error(N_("didn't understand section")); + value = yasm_bc_next_offset(precbc); + } else if (yasm_symrec_get_equ(sym)) { + yasm_warn_set(YASM_WARN_GENERAL, + N_("rdf does not support exporting EQU/absolute values")); + yasm_errwarn_propagate(info->errwarns, yasm_symrec_get_decl_line(sym)); + return 0; + } + + name = yasm_symrec_get_global_name(sym, info->object); + len = strlen(name); + + if (len > EXIM_LABEL_MAX-1) { + yasm_warn_set(YASM_WARN_GENERAL, + N_("label name too long, truncating to %d bytes"), + EXIM_LABEL_MAX); + len = EXIM_LABEL_MAX-1; + } + + localbuf = info->buf; + if (vis & YASM_SYM_GLOBAL) { + YASM_WRITE_8(localbuf, RDFREC_GLOBAL); + YASM_WRITE_8(localbuf, 6+len+1); /* record length */ + YASM_WRITE_8(localbuf, rdf_parse_flags(sym)); /* flags */ + YASM_WRITE_8(localbuf, scnum); /* segment referred to */ + YASM_WRITE_32_L(localbuf, value); /* offset */ + } else { + /* Save symbol segment in symrec data (for later reloc gen) */ + scnum = info->indx++; + rdf_objfmt_sym_set_data(sym, scnum); + + if (vis & YASM_SYM_COMMON) { + /*@dependent@*/ /*@null@*/ yasm_expr **csize_expr; + const yasm_intnum *intn; + /*@dependent@*/ /*@null@*/ yasm_valparamhead *objext_valparams = + yasm_symrec_get_objext_valparams(sym); + unsigned long addralign = 0; + + YASM_WRITE_8(localbuf, RDFREC_COMMON); + YASM_WRITE_8(localbuf, 8+len+1); /* record length */ + YASM_WRITE_16_L(localbuf, scnum); /* segment allocated */ + + /* size */ + csize_expr = yasm_symrec_get_common_size(sym); + assert(csize_expr != NULL); + intn = yasm_expr_get_intnum(csize_expr, 1); + if (!intn) { + yasm_error_set(YASM_ERROR_NOT_CONSTANT, + N_("COMMON data size not an integer expression")); + } else + value = yasm_intnum_get_uint(intn); + YASM_WRITE_32_L(localbuf, value); + + /* alignment */ + if (objext_valparams) { + yasm_valparam *vp = yasm_vps_first(objext_valparams); + for (; vp; vp = yasm_vps_next(vp)) { + if (!vp->val) { + /*@only@*/ /*@null@*/ yasm_expr *align_expr; + /*@dependent@*/ /*@null@*/ + const yasm_intnum *align_intn; + + if (!(align_expr = yasm_vp_expr(vp, + info->object->symtab, + yasm_symrec_get_decl_line(sym))) || + !(align_intn = yasm_expr_get_intnum(&align_expr, + 0))) { + yasm_error_set(YASM_ERROR_VALUE, + N_("argument to `%s' is not an integer"), + vp->val); + if (align_expr) + yasm_expr_destroy(align_expr); + continue; + } + addralign = yasm_intnum_get_uint(align_intn); + yasm_expr_destroy(align_expr); + + /* Alignments must be a power of two. */ + if (!is_exp2(addralign)) { + yasm_error_set(YASM_ERROR_VALUE, + N_("alignment constraint is not a power of two")); + continue; + } + } else + yasm_warn_set(YASM_WARN_GENERAL, + N_("Unrecognized qualifier `%s'"), vp->val); + } + } + YASM_WRITE_16_L(localbuf, addralign); + } else if (vis & YASM_SYM_EXTERN) { + unsigned int flags = rdf_parse_flags(sym); + if (flags & SYM_FAR) { + YASM_WRITE_8(localbuf, RDFREC_FARIMPORT); + flags &= ~SYM_FAR; + } else + YASM_WRITE_8(localbuf, RDFREC_IMPORT); + YASM_WRITE_8(localbuf, 3+len+1); /* record length */ + YASM_WRITE_8(localbuf, flags); /* flags */ + YASM_WRITE_16_L(localbuf, scnum); /* segment allocated */ + } + } + + /* Symbol name */ + memcpy(localbuf, name, len); + localbuf += len; + YASM_WRITE_8(localbuf, 0); /* 0-terminated name */ + yasm_xfree(name); + + fwrite(info->buf, (unsigned long)(localbuf-info->buf), 1, info->f); + + yasm_errwarn_propagate(info->errwarns, yasm_symrec_get_decl_line(sym)); + return 0; +} + +static void +rdf_objfmt_output(yasm_object *object, FILE *f, int all_syms, + yasm_errwarns *errwarns) +{ + yasm_objfmt_rdf *objfmt_rdf = (yasm_objfmt_rdf *)object->objfmt; + rdf_objfmt_output_info info; + unsigned char *localbuf; + long headerlen, filelen; + xdf_str *cur; + size_t len; + + info.object = object; + info.objfmt_rdf = objfmt_rdf; + info.errwarns = errwarns; + info.f = f; + info.buf = yasm_xmalloc(REGULAR_OUTBUF_SIZE); + info.bss_size = 0; + + /* Allocate space for file header by seeking forward */ + if (fseek(f, (long)strlen(RDF_MAGIC)+8, SEEK_SET) < 0) { + yasm__fatal(N_("could not seek on output file")); + /*@notreached@*/ + return; + } + + /* Output custom header records (library and module, etc) */ + cur = STAILQ_FIRST(&objfmt_rdf->module_names); + while (cur) { + len = strlen(cur->str)+1; + localbuf = info.buf; + YASM_WRITE_8(localbuf, RDFREC_MODNAME); /* record type */ + YASM_WRITE_8(localbuf, len); /* record length */ + fwrite(info.buf, 2, 1, f); + fwrite(cur->str, len, 1, f); + cur = STAILQ_NEXT(cur, link); + } + + cur = STAILQ_FIRST(&objfmt_rdf->library_names); + while (cur) { + len = strlen(cur->str)+1; + localbuf = info.buf; + YASM_WRITE_8(localbuf, RDFREC_DLL); /* record type */ + YASM_WRITE_8(localbuf, len); /* record length */ + fwrite(info.buf, 2, 1, f); + fwrite(cur->str, len, 1, f); + cur = STAILQ_NEXT(cur, link); + } + + /* Output symbol table */ + info.indx = objfmt_rdf->parse_scnum; + yasm_symtab_traverse(object->symtab, &info, rdf_objfmt_output_sym); + + /* UGH! Due to the fact the relocs go at the beginning of the file, and + * we only know if we have relocs when we output the sections, we have + * to output the section data before we have output the relocs. But + * we also don't know how much space to preallocate for relocs, so.... + * we output into memory buffers first (thus the UGH). + * + * Stupid object format design, if you ask me (basically all other + * object formats put the relocs *after* the section data to avoid this + * exact problem). + * + * We also calculate the total size of all BSS sections here. + */ + if (yasm_object_sections_traverse(object, &info, + rdf_objfmt_output_section_mem)) + return; + + /* Output all relocs */ + if (yasm_object_sections_traverse(object, &info, + rdf_objfmt_output_section_reloc)) + return; + + /* Output BSS record */ + if (info.bss_size > 0) { + localbuf = info.buf; + YASM_WRITE_8(localbuf, RDFREC_BSS); /* record type */ + YASM_WRITE_8(localbuf, 4); /* record length */ + YASM_WRITE_32_L(localbuf, info.bss_size); /* total BSS size */ + fwrite(info.buf, 6, 1, f); + } + + /* Determine header length */ + headerlen = ftell(f); + if (headerlen == -1) { + yasm__fatal(N_("could not get file position on output file")); + /*@notreached@*/ + return; + } + + /* Section data (to file) */ + if (yasm_object_sections_traverse(object, &info, + rdf_objfmt_output_section_file)) + return; + + /* NULL section to end file */ + memset(info.buf, 0, 10); + fwrite(info.buf, 10, 1, f); + + /* Determine object length */ + filelen = ftell(f); + if (filelen == -1) { + yasm__fatal(N_("could not get file position on output file")); + /*@notreached@*/ + return; + } + + /* Write file header */ + if (fseek(f, 0, SEEK_SET) < 0) { + yasm__fatal(N_("could not seek on output file")); + /*@notreached@*/ + return; + } + + fwrite(RDF_MAGIC, strlen(RDF_MAGIC), 1, f); + localbuf = info.buf; + YASM_WRITE_32_L(localbuf, filelen-10); /* object size */ + YASM_WRITE_32_L(localbuf, headerlen-14); /* header size */ + fwrite(info.buf, 8, 1, f); + + yasm_xfree(info.buf); +} + +static void +rdf_objfmt_destroy(yasm_objfmt *objfmt) +{ + yasm_objfmt_rdf *objfmt_rdf = (yasm_objfmt_rdf *)objfmt; + xdf_str *cur, *next; + + cur = STAILQ_FIRST(&objfmt_rdf->module_names); + while (cur) { + next = STAILQ_NEXT(cur, link); + yasm_xfree(cur->str); + yasm_xfree(cur); + cur = next; + } + + cur = STAILQ_FIRST(&objfmt_rdf->library_names); + while (cur) { + next = STAILQ_NEXT(cur, link); + yasm_xfree(cur->str); + yasm_xfree(cur); + cur = next; + } + + yasm_xfree(objfmt); +} + +static void +rdf_objfmt_init_new_section(yasm_section *sect, unsigned long line) +{ + yasm_object *object = yasm_section_get_object(sect); + const char *sectname = yasm_section_get_name(sect); + yasm_objfmt_rdf *objfmt_rdf = (yasm_objfmt_rdf *)object->objfmt; + rdf_section_data *data; + yasm_symrec *sym; + + data = yasm_xmalloc(sizeof(rdf_section_data)); + data->scnum = objfmt_rdf->parse_scnum++; + data->type = 0; + data->reserved = 0; + data->size = 0; + data->raw_data = NULL; + yasm_section_add_data(sect, &rdf_section_data_cb, data); + + sym = yasm_symtab_define_label(object->symtab, sectname, + yasm_section_bcs_first(sect), 1, line); + data->sym = sym; +} + +static yasm_section * +rdf_objfmt_add_default_section(yasm_object *object) +{ + yasm_section *retval; + rdf_section_data *rsd; + int isnew; + + retval = yasm_object_get_general(object, ".text", 0, 1, 0, &isnew, 0); + if (isnew) { + rsd = yasm_section_get_data(retval, &rdf_section_data_cb); + rsd->type = RDF_SECT_CODE; + rsd->reserved = 0; + yasm_section_set_default(retval, 1); + } + return retval; +} + +static int +rdf_helper_set_type(void *obj, yasm_valparam *vp, unsigned long line, + void *d, uintptr_t newtype) +{ + unsigned int *type = (unsigned int *)d; + *type = newtype; + return 0; +} + +struct rdf_section_switch_data { + /*@only@*/ /*@null@*/ yasm_intnum *reserved_intn; + unsigned int type; +}; + +static int +rdf_helper_set_reserved(void *obj, yasm_valparam *vp, unsigned long line, + void *d) +{ + struct rdf_section_switch_data *data = (struct rdf_section_switch_data *)d; + + if (!vp->val && vp->type == YASM_PARAM_EXPR) + return yasm_dir_helper_intn(obj, vp, line, &data->reserved_intn, 0); + else + return yasm_dir_helper_valparam_warn(obj, vp, line, d); +} + +static /*@observer@*/ /*@null@*/ yasm_section * +rdf_objfmt_section_switch(yasm_object *object, yasm_valparamhead *valparams, + /*@unused@*/ /*@null@*/ + yasm_valparamhead *objext_valparams, + unsigned long line) +{ + yasm_valparam *vp = yasm_vps_first(valparams); + yasm_section *retval; + int isnew; + unsigned int reserved = 0; + int flags_override = 0; + const char *sectname; + rdf_section_data *rsd; + + struct rdf_section_switch_data data; + + static const yasm_dir_help help[] = { + { "bss", 0, rdf_helper_set_type, + offsetof(struct rdf_section_switch_data, type), RDF_SECT_BSS }, + { "code", 0, rdf_helper_set_type, + offsetof(struct rdf_section_switch_data, type), RDF_SECT_CODE }, + { "text", 0, rdf_helper_set_type, + offsetof(struct rdf_section_switch_data, type), RDF_SECT_CODE }, + { "data", 0, rdf_helper_set_type, + offsetof(struct rdf_section_switch_data, type), RDF_SECT_DATA }, + { "comment", 0, rdf_helper_set_type, + offsetof(struct rdf_section_switch_data, type), RDF_SECT_COMMENT }, + { "lcomment", 0, rdf_helper_set_type, + offsetof(struct rdf_section_switch_data, type), RDF_SECT_LCOMMENT }, + { "pcomment", 0, rdf_helper_set_type, + offsetof(struct rdf_section_switch_data, type), RDF_SECT_PCOMMENT }, + { "symdebug", 0, rdf_helper_set_type, + offsetof(struct rdf_section_switch_data, type), RDF_SECT_SYMDEBUG }, + { "linedebug", 0, rdf_helper_set_type, + offsetof(struct rdf_section_switch_data, type), RDF_SECT_LINEDEBUG }, + { "reserved", 1, yasm_dir_helper_intn, + offsetof(struct rdf_section_switch_data, reserved_intn), 0 } + }; + + data.reserved_intn = NULL; + data.type = 0xffff; + + vp = yasm_vps_first(valparams); + sectname = yasm_vp_string(vp); + if (!sectname) + return NULL; + vp = yasm_vps_next(vp); + + if (strcmp(sectname, ".text") == 0) + data.type = RDF_SECT_CODE; + else if (strcmp(sectname, ".data") == 0) + data.type = RDF_SECT_DATA; + else if (strcmp(sectname, ".bss") == 0) + data.type = RDF_SECT_BSS; + + flags_override = yasm_dir_helper(object, vp, line, help, NELEMS(help), + &data, rdf_helper_set_reserved); + if (flags_override < 0) + return NULL; /* error occurred */ + + if (data.type == 0xffff) { + yasm_error_set(YASM_ERROR_VALUE, + N_("new segment declared without type code")); + data.type = RDF_SECT_DATA; + } + + if (data.reserved_intn) { + reserved = yasm_intnum_get_uint(data.reserved_intn); + yasm_intnum_destroy(data.reserved_intn); + } + + retval = yasm_object_get_general(object, sectname, 0, 1, + data.type == RDF_SECT_BSS, &isnew, line); + + rsd = yasm_section_get_data(retval, &rdf_section_data_cb); + + if (isnew || yasm_section_is_default(retval)) { + yasm_section_set_default(retval, 0); + rsd->type = data.type; + rsd->reserved = reserved; + } else if (flags_override) + yasm_warn_set(YASM_WARN_GENERAL, + N_("section flags ignored on section redeclaration")); + return retval; +} + +static /*@observer@*/ /*@null@*/ yasm_symrec * +rdf_objfmt_get_special_sym(yasm_object *object, const char *name, + const char *parser) +{ + return NULL; +} + +static void +rdf_section_data_destroy(void *data) +{ + rdf_section_data *rsd = (rdf_section_data *)data; + if (rsd->raw_data) + yasm_xfree(rsd->raw_data); + yasm_xfree(data); +} + +static void +rdf_section_data_print(void *data, FILE *f, int indent_level) +{ + rdf_section_data *rsd = (rdf_section_data *)data; + + fprintf(f, "%*ssym=\n", indent_level, ""); + yasm_symrec_print(rsd->sym, f, indent_level+1); + fprintf(f, "%*sscnum=%ld\n", indent_level, "", rsd->scnum); + fprintf(f, "%*stype=0x%x\n", indent_level, "", rsd->type); + fprintf(f, "%*sreserved=0x%x\n", indent_level, "", rsd->reserved); + fprintf(f, "%*ssize=%ld\n", indent_level, "", rsd->size); +} + +static void +rdf_symrec_data_destroy(void *data) +{ + yasm_xfree(data); +} + +static void +rdf_symrec_data_print(void *data, FILE *f, int indent_level) +{ + rdf_symrec_data *rsymd = (rdf_symrec_data *)data; + + fprintf(f, "%*ssymtab segment=%u\n", indent_level, "", rsymd->segment); +} + +static void +rdf_objfmt_add_libmodule(yasm_object *object, char *name, int lib) +{ + yasm_objfmt_rdf *objfmt_rdf = (yasm_objfmt_rdf *)object->objfmt; + xdf_str *str; + + /* Add to list */ + str = yasm_xmalloc(sizeof(xdf_str)); + str->str = name; + if (lib) + STAILQ_INSERT_TAIL(&objfmt_rdf->library_names, str, link); + else + STAILQ_INSERT_TAIL(&objfmt_rdf->module_names, str, link); + + if (strlen(str->str) > MODLIB_NAME_MAX-1) { + yasm_warn_set(YASM_WARN_GENERAL, + N_("name too long, truncating to %d bytes"), + MODLIB_NAME_MAX); + str->str[MODLIB_NAME_MAX-1] = '\0'; + } +} + +static void +dir_library(yasm_object *object, yasm_valparamhead *valparams, + yasm_valparamhead *objext_valparams, unsigned long line) +{ + yasm_valparam *vp = yasm_vps_first(valparams); + rdf_objfmt_add_libmodule(object, yasm__xstrdup(yasm_vp_string(vp)), 1); +} + +static void +dir_module(yasm_object *object, yasm_valparamhead *valparams, + yasm_valparamhead *objext_valparams, unsigned long line) +{ + yasm_valparam *vp = yasm_vps_first(valparams); + rdf_objfmt_add_libmodule(object, yasm__xstrdup(yasm_vp_string(vp)), 0); +} + +/* Define valid debug formats to use with this object format */ +static const char *rdf_objfmt_dbgfmt_keywords[] = { + "null", + NULL +}; + +static const yasm_directive rdf_objfmt_directives[] = { + { "library", "nasm", dir_library, YASM_DIR_ARG_REQUIRED }, + { "module", "nasm", dir_module, YASM_DIR_ARG_REQUIRED }, + { NULL, NULL, NULL, 0 } +}; + +static const char *rdf_nasm_stdmac[] = { + "%imacro library 1+.nolist", + "[library %1]", + "%endmacro", + "%imacro module 1+.nolist", + "[module %1]", + "%endmacro", + NULL +}; + +static const yasm_stdmac rdf_objfmt_stdmacs[] = { + { "nasm", "nasm", rdf_nasm_stdmac }, + { NULL, NULL, NULL } +}; + +/* Define objfmt structure -- see objfmt.h for details */ +yasm_objfmt_module yasm_rdf_LTX_objfmt = { + "Relocatable Dynamic Object File Format (RDOFF) v2.0", + "rdf", + "rdf", + 32, + 0, + rdf_objfmt_dbgfmt_keywords, + "null", + rdf_objfmt_directives, + rdf_objfmt_stdmacs, + rdf_objfmt_create, + rdf_objfmt_output, + rdf_objfmt_destroy, + rdf_objfmt_add_default_section, + rdf_objfmt_init_new_section, + rdf_objfmt_section_switch, + rdf_objfmt_get_special_sym +}; diff --git a/contrib/tools/yasm/modules/objfmts/xdf/xdf-objfmt.c b/contrib/tools/yasm/modules/objfmts/xdf/xdf-objfmt.c new file mode 100644 index 0000000000..9ad0e60afa --- /dev/null +++ b/contrib/tools/yasm/modules/objfmts/xdf/xdf-objfmt.c @@ -0,0 +1,842 @@ +/* + * Extended Dynamic Object format + * + * Copyright (C) 2004-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> + + +#define REGULAR_OUTBUF_SIZE 1024 + +#define XDF_MAGIC 0x87654322 + +#define XDF_SYM_EXTERN 1 +#define XDF_SYM_GLOBAL 2 +#define XDF_SYM_EQU 4 + +typedef struct xdf_reloc { + yasm_reloc reloc; + /*@null@*/ yasm_symrec *base; /* base symbol (for WRT) */ + enum { + XDF_RELOC_REL = 1, /* relative to segment */ + XDF_RELOC_WRT = 2, /* relative to symbol */ + XDF_RELOC_RIP = 4, /* RIP-relative */ + XDF_RELOC_SEG = 8 /* segment containing symbol */ + } type; /* type of relocation */ + enum { + XDF_RELOC_8 = 1, + XDF_RELOC_16 = 2, + XDF_RELOC_32 = 4, + XDF_RELOC_64 = 8 + } size; /* size of relocation */ + unsigned int shift; /* relocation shift (0,4,8,16,24,32) */ +} xdf_reloc; + +typedef struct xdf_section_data { + /*@dependent@*/ yasm_symrec *sym; /* symbol created for this section */ + yasm_intnum *addr; /* starting memory address */ + yasm_intnum *vaddr; /* starting virtual address */ + long scnum; /* section number (0=first section) */ + enum { + XDF_SECT_ABSOLUTE = 0x01, + XDF_SECT_FLAT = 0x02, + XDF_SECT_BSS = 0x04, + XDF_SECT_EQU = 0x08, + XDF_SECT_USE_16 = 0x10, + XDF_SECT_USE_32 = 0x20, + XDF_SECT_USE_64 = 0x40 + } flags; /* section flags */ + unsigned long scnptr; /* file ptr to raw data */ + unsigned long size; /* size of raw data (section data) in bytes */ + unsigned long relptr; /* file ptr to relocation */ + unsigned long nreloc; /* number of relocation entries >64k -> error */ +} xdf_section_data; + +typedef struct xdf_symrec_data { + unsigned long index; /* assigned XDF symbol table index */ +} xdf_symrec_data; + +typedef struct yasm_objfmt_xdf { + yasm_objfmt_base objfmt; /* base structure */ + + long parse_scnum; /* sect numbering in parser */ +} yasm_objfmt_xdf; + +typedef struct xdf_objfmt_output_info { + yasm_object *object; + yasm_objfmt_xdf *objfmt_xdf; + yasm_errwarns *errwarns; + /*@dependent@*/ FILE *f; + /*@only@*/ unsigned char *buf; + yasm_section *sect; + /*@dependent@*/ xdf_section_data *xsd; + + unsigned long indx; /* current symbol index */ + int all_syms; /* outputting all symbols? */ + unsigned long strtab_offset; /* current string table offset */ +} xdf_objfmt_output_info; + +static void xdf_section_data_destroy(/*@only@*/ void *d); +static void xdf_section_data_print(void *data, FILE *f, int indent_level); + +static const yasm_assoc_data_callback xdf_section_data_cb = { + xdf_section_data_destroy, + xdf_section_data_print +}; + +static void xdf_symrec_data_destroy(/*@only@*/ void *d); +static void xdf_symrec_data_print(void *data, FILE *f, int indent_level); + +static const yasm_assoc_data_callback xdf_symrec_data_cb = { + xdf_symrec_data_destroy, + xdf_symrec_data_print +}; + +yasm_objfmt_module yasm_xdf_LTX_objfmt; + + +static yasm_objfmt * +xdf_objfmt_create(yasm_object *object) +{ + yasm_objfmt_xdf *objfmt_xdf = yasm_xmalloc(sizeof(yasm_objfmt_xdf)); + + /* Only support x86 arch */ + if (yasm__strcasecmp(yasm_arch_keyword(object->arch), "x86") != 0) { + yasm_xfree(objfmt_xdf); + return NULL; + } + + /* Support x86 and amd64 machines of x86 arch */ + if (yasm__strcasecmp(yasm_arch_get_machine(object->arch), "x86") && + yasm__strcasecmp(yasm_arch_get_machine(object->arch), "amd64")) { + yasm_xfree(objfmt_xdf); + return NULL; + } + + objfmt_xdf->parse_scnum = 0; /* section numbering starts at 0 */ + + objfmt_xdf->objfmt.module = &yasm_xdf_LTX_objfmt; + + return (yasm_objfmt *)objfmt_xdf; +} + +static int +xdf_objfmt_output_value(yasm_value *value, unsigned char *buf, + unsigned int destsize, unsigned long offset, + yasm_bytecode *bc, int warn, /*@null@*/ void *d) +{ + /*@null@*/ xdf_objfmt_output_info *info = (xdf_objfmt_output_info *)d; + /*@dependent@*/ /*@null@*/ yasm_intnum *intn; + unsigned long intn_minus; + int retval; + unsigned int valsize = value->size; + + assert(info != NULL); + + if (value->abs) + value->abs = yasm_expr_simplify(value->abs, 1); + + /* Try to output constant and PC-relative section-local first. + * Note this does NOT output any value with a SEG, WRT, external, + * cross-section, or non-PC-relative reference (those are handled below). + */ + switch (yasm_value_output_basic(value, buf, destsize, bc, warn, + info->object->arch)) { + case -1: + return 1; + case 0: + break; + default: + return 0; + } + + if (value->section_rel) { + yasm_error_set(YASM_ERROR_TOO_COMPLEX, + N_("xdf: relocation too complex")); + return 1; + } + + intn_minus = 0; + if (value->rel) { + xdf_reloc *reloc; + + reloc = yasm_xmalloc(sizeof(xdf_reloc)); + reloc->reloc.addr = yasm_intnum_create_uint(bc->offset + offset); + reloc->reloc.sym = value->rel; + reloc->base = NULL; + reloc->size = valsize/8; + reloc->shift = value->rshift; + + if (value->seg_of) + reloc->type = XDF_RELOC_SEG; + else if (value->wrt) { + reloc->base = value->wrt; + reloc->type = XDF_RELOC_WRT; + } else if (value->curpos_rel) { + reloc->type = XDF_RELOC_RIP; + /* Adjust to start of section, so subtract out the bytecode + * offset. + */ + intn_minus = bc->offset; + } else + reloc->type = XDF_RELOC_REL; + info->xsd->nreloc++; + yasm_section_add_reloc(info->sect, (yasm_reloc *)reloc, yasm_xfree); + } + + if (intn_minus > 0) { + intn = yasm_intnum_create_uint(intn_minus); + yasm_intnum_calc(intn, YASM_EXPR_NEG, NULL); + } else + intn = yasm_intnum_create_uint(0); + + if (value->abs) { + yasm_intnum *intn2 = yasm_expr_get_intnum(&value->abs, 0); + if (!intn2) { + yasm_error_set(YASM_ERROR_TOO_COMPLEX, + N_("xdf: relocation too complex")); + yasm_intnum_destroy(intn); + return 1; + } + yasm_intnum_calc(intn, YASM_EXPR_ADD, intn2); + } + + retval = yasm_arch_intnum_tobytes(info->object->arch, intn, buf, destsize, + valsize, 0, bc, warn); + yasm_intnum_destroy(intn); + return retval; +} + +static int +xdf_objfmt_output_bytecode(yasm_bytecode *bc, /*@null@*/ void *d) +{ + /*@null@*/ xdf_objfmt_output_info *info = (xdf_objfmt_output_info *)d; + /*@null@*/ /*@only@*/ unsigned char *bigbuf; + unsigned long size = REGULAR_OUTBUF_SIZE; + int gap; + + assert(info != NULL); + + bigbuf = yasm_bc_tobytes(bc, info->buf, &size, &gap, info, + xdf_objfmt_output_value, NULL); + + /* Don't bother doing anything else if size ended up being 0. */ + if (size == 0) { + if (bigbuf) + yasm_xfree(bigbuf); + return 0; + } + + info->xsd->size += size; + + /* Warn that gaps are converted to 0 and write out the 0's. */ + if (gap) { + unsigned long left; + yasm_warn_set(YASM_WARN_UNINIT_CONTENTS, + N_("uninitialized space: zeroing")); + /* Write out in chunks */ + memset(info->buf, 0, REGULAR_OUTBUF_SIZE); + left = size; + while (left > REGULAR_OUTBUF_SIZE) { + fwrite(info->buf, REGULAR_OUTBUF_SIZE, 1, info->f); + left -= REGULAR_OUTBUF_SIZE; + } + fwrite(info->buf, left, 1, info->f); + } else { + /* Output buf (or bigbuf if non-NULL) to file */ + fwrite(bigbuf ? bigbuf : info->buf, (size_t)size, 1, info->f); + } + + /* If bigbuf was allocated, free it */ + if (bigbuf) + yasm_xfree(bigbuf); + + return 0; +} + +static int +xdf_objfmt_output_section(yasm_section *sect, /*@null@*/ void *d) +{ + /*@null@*/ xdf_objfmt_output_info *info = (xdf_objfmt_output_info *)d; + /*@dependent@*/ /*@null@*/ xdf_section_data *xsd; + long pos; + xdf_reloc *reloc; + + assert(info != NULL); + xsd = yasm_section_get_data(sect, &xdf_section_data_cb); + assert(xsd != NULL); + + if (xsd->flags & XDF_SECT_BSS) { + /* Don't output BSS sections. + * TODO: Check for non-reserve bytecodes? + */ + pos = 0; /* position = 0 because it's not in the file */ + xsd->size = yasm_bc_next_offset(yasm_section_bcs_last(sect)); + } else { + pos = ftell(info->f); + if (pos == -1) { + yasm__fatal(N_("could not get file position on output file")); + /*@notreached@*/ + return 1; + } + + info->sect = sect; + info->xsd = xsd; + yasm_section_bcs_traverse(sect, info->errwarns, info, + xdf_objfmt_output_bytecode); + + /* Sanity check final section size */ + if (xsd->size != yasm_bc_next_offset(yasm_section_bcs_last(sect))) + yasm_internal_error( + N_("xdf: section computed size did not match actual size")); + } + + /* Empty? Go on to next section */ + if (xsd->size == 0) + return 0; + + xsd->scnptr = (unsigned long)pos; + + /* No relocations to output? Go on to next section */ + if (xsd->nreloc == 0) + return 0; + + pos = ftell(info->f); + if (pos == -1) { + yasm__fatal(N_("could not get file position on output file")); + /*@notreached@*/ + return 1; + } + xsd->relptr = (unsigned long)pos; + + reloc = (xdf_reloc *)yasm_section_relocs_first(sect); + while (reloc) { + unsigned char *localbuf = info->buf; + /*@null@*/ xdf_symrec_data *xsymd; + + xsymd = yasm_symrec_get_data(reloc->reloc.sym, &xdf_symrec_data_cb); + if (!xsymd) + yasm_internal_error( + N_("xdf: no symbol data for relocated symbol")); + + yasm_intnum_get_sized(reloc->reloc.addr, localbuf, 4, 32, 0, 0, 0); + localbuf += 4; /* address of relocation */ + YASM_WRITE_32_L(localbuf, xsymd->index); /* relocated symbol */ + if (reloc->base) { + xsymd = yasm_symrec_get_data(reloc->base, &xdf_symrec_data_cb); + if (!xsymd) + yasm_internal_error( + N_("xdf: no symbol data for relocated base symbol")); + YASM_WRITE_32_L(localbuf, xsymd->index); /* base symbol */ + } else { + if (reloc->type == XDF_RELOC_WRT) + yasm_internal_error( + N_("xdf: no base symbol for WRT relocation")); + YASM_WRITE_32_L(localbuf, 0); /* no base symbol */ + } + YASM_WRITE_8(localbuf, reloc->type); /* type of relocation */ + YASM_WRITE_8(localbuf, reloc->size); /* size of relocation */ + YASM_WRITE_8(localbuf, reloc->shift); /* relocation shift */ + YASM_WRITE_8(localbuf, 0); /* flags */ + fwrite(info->buf, 16, 1, info->f); + + reloc = (xdf_reloc *)yasm_section_reloc_next((yasm_reloc *)reloc); + } + + return 0; +} + +static int +xdf_objfmt_output_secthead(yasm_section *sect, /*@null@*/ void *d) +{ + /*@null@*/ xdf_objfmt_output_info *info = (xdf_objfmt_output_info *)d; + /*@dependent@*/ /*@null@*/ xdf_section_data *xsd; + /*@null@*/ xdf_symrec_data *xsymd; + unsigned char *localbuf; + + assert(info != NULL); + xsd = yasm_section_get_data(sect, &xdf_section_data_cb); + assert(xsd != NULL); + + localbuf = info->buf; + xsymd = yasm_symrec_get_data(xsd->sym, &xdf_symrec_data_cb); + assert(xsymd != NULL); + + YASM_WRITE_32_L(localbuf, xsymd->index); /* section name symbol */ + if (xsd->addr) { + yasm_intnum_get_sized(xsd->addr, localbuf, 8, 64, 0, 0, 0); + localbuf += 8; /* physical address */ + } else { + YASM_WRITE_32_L(localbuf, 0); + YASM_WRITE_32_L(localbuf, 0); + } + if (xsd->vaddr) { + yasm_intnum_get_sized(xsd->vaddr, localbuf, 8, 64, 0, 0, 0); + localbuf += 8; /* virtual address */ + } else if (xsd->addr) { + yasm_intnum_get_sized(xsd->addr, localbuf, 8, 64, 0, 0, 0); + localbuf += 8; /* VA=PA */ + } else { + YASM_WRITE_32_L(localbuf, 0); + YASM_WRITE_32_L(localbuf, 0); + } + YASM_WRITE_16_L(localbuf, yasm_section_get_align(sect)); /* alignment */ + YASM_WRITE_16_L(localbuf, xsd->flags); /* flags */ + YASM_WRITE_32_L(localbuf, xsd->scnptr); /* file ptr to data */ + YASM_WRITE_32_L(localbuf, xsd->size); /* section size */ + YASM_WRITE_32_L(localbuf, xsd->relptr); /* file ptr to relocs */ + YASM_WRITE_32_L(localbuf, xsd->nreloc); /* num of relocation entries */ + fwrite(info->buf, 40, 1, info->f); + + return 0; +} + +static int +xdf_objfmt_count_sym(yasm_symrec *sym, /*@null@*/ void *d) +{ + /*@null@*/ xdf_objfmt_output_info *info = (xdf_objfmt_output_info *)d; + yasm_sym_vis vis = yasm_symrec_get_visibility(sym); + assert(info != NULL); + if (vis & YASM_SYM_COMMON) { + yasm_error_set(YASM_ERROR_GENERAL, + N_("XDF object format does not support common variables")); + yasm_errwarn_propagate(info->errwarns, yasm_symrec_get_decl_line(sym)); + return 0; + } + if (info->all_syms || + (vis != YASM_SYM_LOCAL && !(vis & YASM_SYM_DLOCAL))) { + /* Save index in symrec data */ + xdf_symrec_data *sym_data = yasm_xmalloc(sizeof(xdf_symrec_data)); + sym_data->index = info->indx; + yasm_symrec_add_data(sym, &xdf_symrec_data_cb, sym_data); + + info->indx++; + } + return 0; +} + +static int +xdf_objfmt_output_sym(yasm_symrec *sym, /*@null@*/ void *d) +{ + /*@null@*/ xdf_objfmt_output_info *info = (xdf_objfmt_output_info *)d; + yasm_sym_vis vis = yasm_symrec_get_visibility(sym); + + assert(info != NULL); + + if (info->all_syms || vis != YASM_SYM_LOCAL) { + /*@only@*/ char *name = yasm_symrec_get_global_name(sym, info->object); + const yasm_expr *equ_val; + const yasm_intnum *intn; + size_t len = strlen(name); + unsigned long value = 0; + long scnum = -3; /* -3 = debugging symbol */ + /*@dependent@*/ /*@null@*/ yasm_section *sect; + /*@dependent@*/ /*@null@*/ yasm_bytecode *precbc; + unsigned long flags = 0; + unsigned char *localbuf; + + if (vis & YASM_SYM_GLOBAL) + flags = XDF_SYM_GLOBAL; + + /* Look at symrec for value/scnum/etc. */ + if (yasm_symrec_get_label(sym, &precbc)) { + if (precbc) + sect = yasm_bc_get_section(precbc); + else + sect = NULL; + /* it's a label: get value and offset. + * If there is not a section, leave as debugging symbol. + */ + if (sect) { + /*@dependent@*/ /*@null@*/ xdf_section_data *csectd; + csectd = yasm_section_get_data(sect, &xdf_section_data_cb); + if (csectd) + scnum = csectd->scnum; + else + yasm_internal_error(N_("didn't understand section")); + if (precbc) + value += yasm_bc_next_offset(precbc); + } + } else if ((equ_val = yasm_symrec_get_equ(sym))) { + yasm_expr *equ_val_copy = yasm_expr_copy(equ_val); + intn = yasm_expr_get_intnum(&equ_val_copy, 1); + if (!intn) { + if (vis & YASM_SYM_GLOBAL) { + yasm_error_set(YASM_ERROR_NOT_CONSTANT, + N_("global EQU value not an integer expression")); + yasm_errwarn_propagate(info->errwarns, equ_val->line); + } + } else + value = yasm_intnum_get_uint(intn); + yasm_expr_destroy(equ_val_copy); + + flags |= XDF_SYM_EQU; + scnum = -2; /* -2 = absolute symbol */ + } else { + if (vis & YASM_SYM_EXTERN) { + flags = XDF_SYM_EXTERN; + scnum = -1; + } + } + + localbuf = info->buf; + YASM_WRITE_32_L(localbuf, scnum); /* section number */ + YASM_WRITE_32_L(localbuf, value); /* value */ + YASM_WRITE_32_L(localbuf, info->strtab_offset); + info->strtab_offset += (unsigned long)(len+1); + YASM_WRITE_32_L(localbuf, flags); /* flags */ + fwrite(info->buf, 16, 1, info->f); + yasm_xfree(name); + } + return 0; +} + +static int +xdf_objfmt_output_str(yasm_symrec *sym, /*@null@*/ void *d) +{ + /*@null@*/ xdf_objfmt_output_info *info = (xdf_objfmt_output_info *)d; + yasm_sym_vis vis = yasm_symrec_get_visibility(sym); + + assert(info != NULL); + + if (info->all_syms || vis != YASM_SYM_LOCAL) { + /*@only@*/ char *name = yasm_symrec_get_global_name(sym, info->object); + size_t len = strlen(name); + fwrite(name, len+1, 1, info->f); + yasm_xfree(name); + } + return 0; +} + +static void +xdf_objfmt_output(yasm_object *object, FILE *f, int all_syms, + yasm_errwarns *errwarns) +{ + yasm_objfmt_xdf *objfmt_xdf = (yasm_objfmt_xdf *)object->objfmt; + xdf_objfmt_output_info info; + unsigned char *localbuf; + unsigned long symtab_count = 0; + + info.object = object; + info.objfmt_xdf = objfmt_xdf; + info.errwarns = errwarns; + info.f = f; + info.buf = yasm_xmalloc(REGULAR_OUTBUF_SIZE); + + /* Allocate space for headers by seeking forward */ + if (fseek(f, (long)(16+40*(objfmt_xdf->parse_scnum)), SEEK_SET) < 0) { + yasm__fatal(N_("could not seek on output file")); + /*@notreached@*/ + return; + } + + /* Get number of symbols */ + info.indx = 0; + info.all_syms = 1; /* force all syms into symbol table */ + yasm_symtab_traverse(object->symtab, &info, xdf_objfmt_count_sym); + symtab_count = info.indx; + + /* Get file offset of start of string table */ + info.strtab_offset = 16+40*(objfmt_xdf->parse_scnum)+16*symtab_count; + + /* Output symbol table */ + yasm_symtab_traverse(object->symtab, &info, xdf_objfmt_output_sym); + + /* Output string table */ + yasm_symtab_traverse(object->symtab, &info, xdf_objfmt_output_str); + + /* Section data/relocs */ + if (yasm_object_sections_traverse(object, &info, + xdf_objfmt_output_section)) + return; + + /* Write headers */ + if (fseek(f, 0, SEEK_SET) < 0) { + yasm__fatal(N_("could not seek on output file")); + /*@notreached@*/ + return; + } + + localbuf = info.buf; + YASM_WRITE_32_L(localbuf, XDF_MAGIC); /* magic number */ + YASM_WRITE_32_L(localbuf, objfmt_xdf->parse_scnum); /* number of sects */ + YASM_WRITE_32_L(localbuf, symtab_count); /* number of symtabs */ + /* size of sect headers + symbol table + strings */ + YASM_WRITE_32_L(localbuf, info.strtab_offset-16); + fwrite(info.buf, 16, 1, f); + + yasm_object_sections_traverse(object, &info, xdf_objfmt_output_secthead); + + yasm_xfree(info.buf); +} + +static void +xdf_objfmt_destroy(yasm_objfmt *objfmt) +{ + yasm_xfree(objfmt); +} + +static void +xdf_objfmt_init_new_section(yasm_section *sect, unsigned long line) +{ + yasm_object *object = yasm_section_get_object(sect); + const char *sectname = yasm_section_get_name(sect); + yasm_objfmt_xdf *objfmt_xdf = (yasm_objfmt_xdf *)object->objfmt; + xdf_section_data *data; + yasm_symrec *sym; + + data = yasm_xmalloc(sizeof(xdf_section_data)); + data->scnum = objfmt_xdf->parse_scnum++; + data->flags = 0; + data->addr = NULL; + data->vaddr = NULL; + data->scnptr = 0; + data->size = 0; + data->relptr = 0; + data->nreloc = 0; + yasm_section_add_data(sect, &xdf_section_data_cb, data); + + sym = yasm_symtab_define_label(object->symtab, sectname, + yasm_section_bcs_first(sect), 1, line); + data->sym = sym; +} + +static yasm_section * +xdf_objfmt_add_default_section(yasm_object *object) +{ + yasm_section *retval; + int isnew; + + retval = yasm_object_get_general(object, ".text", 0, 1, 0, &isnew, 0); + if (isnew) + yasm_section_set_default(retval, 1); + return retval; +} + +static int +xdf_helper_use(void *obj, yasm_valparam *vp, unsigned long line, void *d, + uintptr_t bits) +{ + yasm_object *object = (yasm_object *)obj; + unsigned long *flags = (unsigned long *)d; + *flags &= ~(XDF_SECT_USE_16|XDF_SECT_USE_32|XDF_SECT_USE_64); + switch (bits) { + case 16: *flags |= XDF_SECT_USE_16; break; + case 32: *flags |= XDF_SECT_USE_32; break; + case 64: *flags |= XDF_SECT_USE_64; break; + }; + yasm_arch_set_var(object->arch, "mode_bits", bits); + return 0; +} + +static /*@observer@*/ /*@null@*/ yasm_section * +xdf_objfmt_section_switch(yasm_object *object, yasm_valparamhead *valparams, + /*@unused@*/ /*@null@*/ + yasm_valparamhead *objext_valparams, + unsigned long line) +{ + yasm_valparam *vp; + yasm_section *retval; + int isnew; + int flags_override = 0; + const char *sectname; + int resonly = 0; + xdf_section_data *xsd; + unsigned long align = 0; + + struct xdf_section_switch_data { + /*@only@*/ /*@null@*/ yasm_intnum *absaddr; + /*@only@*/ /*@null@*/ yasm_intnum *vaddr; + /*@only@*/ /*@null@*/ yasm_intnum *align_intn; + unsigned long flags; + } data; + + static const yasm_dir_help help[] = { + { "use16", 0, xdf_helper_use, + offsetof(struct xdf_section_switch_data, flags), 16 }, + { "use32", 0, xdf_helper_use, + offsetof(struct xdf_section_switch_data, flags), 32 }, + { "use64", 0, xdf_helper_use, + offsetof(struct xdf_section_switch_data, flags), 64 }, + { "bss", 0, yasm_dir_helper_flag_or, + offsetof(struct xdf_section_switch_data, flags), XDF_SECT_BSS }, + { "flat", 0, yasm_dir_helper_flag_or, + offsetof(struct xdf_section_switch_data, flags), XDF_SECT_FLAT }, + { "absolute", 1, yasm_dir_helper_intn, + offsetof(struct xdf_section_switch_data, absaddr), 0 }, + { "virtual", 1, yasm_dir_helper_intn, + offsetof(struct xdf_section_switch_data, vaddr), 0 }, + { "align", 1, yasm_dir_helper_intn, + offsetof(struct xdf_section_switch_data, align_intn), 0 } + }; + + data.absaddr = NULL; + data.vaddr = NULL; + data.align_intn = NULL; + data.flags = 0; + + vp = yasm_vps_first(valparams); + sectname = yasm_vp_string(vp); + if (!sectname) + return NULL; + vp = yasm_vps_next(vp); + + flags_override = yasm_dir_helper(object, vp, line, help, NELEMS(help), + &data, yasm_dir_helper_valparam_warn); + if (flags_override < 0) + return NULL; /* error occurred */ + + if (data.absaddr) + data.flags |= XDF_SECT_ABSOLUTE; + if (data.align_intn) { + align = yasm_intnum_get_uint(data.align_intn); + yasm_intnum_destroy(data.align_intn); + + /* Alignments must be a power of two. */ + if (!is_exp2(align)) { + yasm_error_set(YASM_ERROR_VALUE, + N_("argument to `%s' is not a power of two"), + "align"); + if (data.vaddr) + yasm_intnum_destroy(data.vaddr); + if (data.absaddr) + yasm_intnum_destroy(data.absaddr); + return NULL; + } + + /* Check to see if alignment is supported size */ + if (align > 4096) { + yasm_error_set(YASM_ERROR_VALUE, + N_("XDF does not support alignments > 4096")); + if (data.vaddr) + yasm_intnum_destroy(data.vaddr); + if (data.absaddr) + yasm_intnum_destroy(data.absaddr); + return NULL; + } + } + + retval = yasm_object_get_general(object, sectname, align, 1, resonly, + &isnew, line); + + xsd = yasm_section_get_data(retval, &xdf_section_data_cb); + + if (isnew || yasm_section_is_default(retval)) { + yasm_section_set_default(retval, 0); + xsd->flags = data.flags; + if (data.absaddr) { + if (xsd->addr) + yasm_intnum_destroy(xsd->addr); + xsd->addr = data.absaddr; + } + if (data.vaddr) { + if (xsd->vaddr) + yasm_intnum_destroy(xsd->vaddr); + xsd->vaddr = data.vaddr; + } + yasm_section_set_align(retval, align, line); + } else if (flags_override) + yasm_warn_set(YASM_WARN_GENERAL, + N_("section flags ignored on section redeclaration")); + return retval; +} + +static /*@observer@*/ /*@null@*/ yasm_symrec * +xdf_objfmt_get_special_sym(yasm_object *object, const char *name, + const char *parser) +{ + return NULL; +} + +static void +xdf_section_data_destroy(void *data) +{ + xdf_section_data *xsd = (xdf_section_data *)data; + if (xsd->addr) + yasm_intnum_destroy(xsd->addr); + if (xsd->vaddr) + yasm_intnum_destroy(xsd->vaddr); + yasm_xfree(data); +} + +static void +xdf_section_data_print(void *data, FILE *f, int indent_level) +{ + xdf_section_data *xsd = (xdf_section_data *)data; + + fprintf(f, "%*ssym=\n", indent_level, ""); + yasm_symrec_print(xsd->sym, f, indent_level+1); + fprintf(f, "%*sscnum=%ld\n", indent_level, "", xsd->scnum); + fprintf(f, "%*sflags=0x%x\n", indent_level, "", xsd->flags); + fprintf(f, "%*saddr=", indent_level, ""); + yasm_intnum_print(xsd->addr, f); + fprintf(f, "%*svaddr=", indent_level, ""); + yasm_intnum_print(xsd->vaddr, f); + fprintf(f, "%*sscnptr=0x%lx\n", indent_level, "", xsd->scnptr); + fprintf(f, "%*ssize=%ld\n", indent_level, "", xsd->size); + fprintf(f, "%*srelptr=0x%lx\n", indent_level, "", xsd->relptr); + fprintf(f, "%*snreloc=%ld\n", indent_level, "", xsd->nreloc); +} + +static void +xdf_symrec_data_destroy(void *data) +{ + yasm_xfree(data); +} + +static void +xdf_symrec_data_print(void *data, FILE *f, int indent_level) +{ + xdf_symrec_data *xsd = (xdf_symrec_data *)data; + + fprintf(f, "%*ssymtab index=%lu\n", indent_level, "", xsd->index); +} + +/* Define valid debug formats to use with this object format */ +static const char *xdf_objfmt_dbgfmt_keywords[] = { + "null", + NULL +}; + +/* Define objfmt structure -- see objfmt.h for details */ +yasm_objfmt_module yasm_xdf_LTX_objfmt = { + "Extended Dynamic Object", + "xdf", + "xdf", + 32, + 0, + xdf_objfmt_dbgfmt_keywords, + "null", + NULL, /* no directives */ + NULL, /* no standard macros */ + xdf_objfmt_create, + xdf_objfmt_output, + xdf_objfmt_destroy, + xdf_objfmt_add_default_section, + xdf_objfmt_init_new_section, + xdf_objfmt_section_switch, + xdf_objfmt_get_special_sym +}; diff --git a/contrib/tools/yasm/modules/parsers/gas/gas-parse-intel.c b/contrib/tools/yasm/modules/parsers/gas/gas-parse-intel.c new file mode 100644 index 0000000000..9d412fc7d3 --- /dev/null +++ b/contrib/tools/yasm/modules/parsers/gas/gas-parse-intel.c @@ -0,0 +1,90 @@ +/* + * GAS-compatible parser Intel syntax support + * + * Copyright (C) 2010 Alexei Svitkine + * + * 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. + * 3. Neither the name of the author nor the names of other contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 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 "modules/parsers/gas/gas-parser.h" +#include "modules/parsers/nasm/nasm-parser-struct.h" + +extern yasm_bytecode *gas_intel_syntax_parse_instr(yasm_parser_nasm *parser_nasm, unsigned char *instr); + +#define SET_FIELDS(to, from) \ + (to)->object = (from)->object; \ + (to)->locallabel_base = (from)->locallabel_base; \ + (to)->locallabel_base_len = (from)->locallabel_base_len; \ + (to)->preproc = (from)->preproc; \ + (to)->errwarns = (from)->errwarns; \ + (to)->linemap = (from)->linemap; \ + (to)->prev_bc = (from)->prev_bc; + +yasm_bytecode *parse_instr_intel(yasm_parser_gas *parser_gas) +{ + char *stok, *slim; + unsigned char *line; + size_t length; + + yasm_parser_nasm parser_nasm; + yasm_bytecode *bc; + + memset(&parser_nasm, 0, sizeof(parser_nasm)); + + yasm_arch_set_var(parser_gas->object->arch, "gas_intel_mode", 1); + SET_FIELDS(&parser_nasm, parser_gas); + parser_nasm.masm = 1; + + stok = (char *) parser_gas->s.tok; + slim = (char *) parser_gas->s.lim; + length = 0; + while (&stok[length] < slim && stok[length] != '\n') { + length++; + } + + if (&stok[length] == slim && parser_gas->line) { + line = yasm_xmalloc(length + parser_gas->lineleft + 1); + memcpy(line, parser_gas->s.tok, length); + memcpy(line + length, parser_gas->linepos, parser_gas->lineleft); + length += parser_gas->lineleft; + if (line[length - 1] == '\n') length--; + } else { + line = yasm_xmalloc(length + 1); + memcpy(line, parser_gas->s.tok, length); + } + line[length] = '\0'; + + bc = gas_intel_syntax_parse_instr(&parser_nasm, line); + + SET_FIELDS(parser_gas, &parser_nasm); + yasm_arch_set_var(parser_gas->object->arch, "gas_intel_mode", 0); + + yasm_xfree(line); + + return bc; +} diff --git a/contrib/tools/yasm/modules/parsers/gas/gas-parse.c b/contrib/tools/yasm/modules/parsers/gas/gas-parse.c new file mode 100644 index 0000000000..14c86a70f4 --- /dev/null +++ b/contrib/tools/yasm/modules/parsers/gas/gas-parse.c @@ -0,0 +1,1766 @@ +/* + * GAS-compatible parser + * + * Copyright (C) 2005-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. + * 3. Neither the name of the author nor the names of other contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 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 <ctype.h> +#include <limits.h> +#include <math.h> + +#include "modules/parsers/gas/gas-parser.h" + +typedef struct dir_lookup { + const char *name; + yasm_bytecode * (*handler) (yasm_parser_gas *, unsigned int); + unsigned int param; + enum gas_parser_state newstate; +} dir_lookup; + +static void cpp_line_marker(yasm_parser_gas *parser_gas); +static void nasm_line_marker(yasm_parser_gas *parser_gas); +static yasm_bytecode *parse_instr(yasm_parser_gas *parser_gas); +static int parse_dirvals(yasm_parser_gas *parser_gas, yasm_valparamhead *vps); +static int parse_datavals(yasm_parser_gas *parser_gas, yasm_datavalhead *dvs); +static int parse_strvals(yasm_parser_gas *parser_gas, yasm_datavalhead *dvs); +static yasm_effaddr *parse_memaddr(yasm_parser_gas *parser_gas); +static yasm_insn_operand *parse_operand(yasm_parser_gas *parser_gas); +static yasm_expr *parse_expr(yasm_parser_gas *parser_gas); +static yasm_expr *parse_expr0(yasm_parser_gas *parser_gas); +static yasm_expr *parse_expr1(yasm_parser_gas *parser_gas); +static yasm_expr *parse_expr2(yasm_parser_gas *parser_gas); + +static void define_label(yasm_parser_gas *parser_gas, char *name, int local); +static void define_lcomm(yasm_parser_gas *parser_gas, /*@only@*/ char *name, + yasm_expr *size, /*@null@*/ yasm_expr *align); +static yasm_section *gas_get_section + (yasm_parser_gas *parser_gas, /*@only@*/ char *name, /*@null@*/ char *flags, + /*@null@*/ char *type, /*@null@*/ yasm_valparamhead *objext_valparams, + int builtin); +static void gas_switch_section + (yasm_parser_gas *parser_gas, /*@only@*/ const char *name, + /*@null@*/ char *flags, /*@null@*/ char *type, + /*@null@*/ yasm_valparamhead *objext_valparams, int builtin); +static yasm_bytecode *gas_parser_align + (yasm_parser_gas *parser_gas, yasm_section *sect, yasm_expr *boundval, + /*@null@*/ yasm_expr *fillval, /*@null@*/ yasm_expr *maxskipval, + int power2); +static yasm_bytecode *gas_parser_dir_fill + (yasm_parser_gas *parser_gas, /*@only@*/ yasm_expr *repeat, + /*@only@*/ /*@null@*/ yasm_expr *size, + /*@only@*/ /*@null@*/ yasm_expr *value); + +#define is_eol_tok(tok) ((tok) == '\n' || (tok) == ';' || (tok) == 0) +#define is_eol() is_eol_tok(curtok) + +#define get_next_token() (curtok = gas_parser_lex(&curval, parser_gas)) + +static void +get_peek_token(yasm_parser_gas *parser_gas) +{ + char savech = parser_gas->tokch; + if (parser_gas->peek_token != NONE) + yasm_internal_error(N_("can only have one token of lookahead")); + parser_gas->peek_token = + gas_parser_lex(&parser_gas->peek_tokval, parser_gas); + parser_gas->peek_tokch = parser_gas->tokch; + parser_gas->tokch = savech; +} + +static void +destroy_curtok_(yasm_parser_gas *parser_gas) +{ + if (curtok < 256) + ; + else switch ((enum tokentype)curtok) { + case INTNUM: + yasm_intnum_destroy(curval.intn); + break; + case FLTNUM: + yasm_floatnum_destroy(curval.flt); + break; + case ID: + case LABEL: + case STRING: + yasm_xfree(curval.str.contents); + break; + default: + break; + } + curtok = NONE; /* sanity */ +} +#define destroy_curtok() destroy_curtok_(parser_gas) + +/* Eat all remaining tokens to EOL, discarding all of them. If there's any + * intervening tokens, generates an error (junk at end of line). + */ +static void +demand_eol_(yasm_parser_gas *parser_gas) +{ + if (is_eol()) + return; + + yasm_error_set(YASM_ERROR_SYNTAX, + N_("junk at end of line, first unrecognized character is `%c'"), + parser_gas->tokch); + + do { + destroy_curtok(); + get_next_token(); + } while (!is_eol()); +} +#define demand_eol() demand_eol_(parser_gas) + +static int +expect_(yasm_parser_gas *parser_gas, int token) +{ + static char strch[] = "` '"; + const char *str; + + if (curtok == token) + return 1; + + switch (token) { + case INTNUM: str = "integer"; break; + case FLTNUM: str = "floating point value"; break; + case STRING: str = "string"; break; + case REG: str = "register"; break; + case REGGROUP: str = "register group"; break; + case SEGREG: str = "segment register"; break; + case TARGETMOD: str = "target modifier"; break; + case LEFT_OP: str = "<<"; break; + case RIGHT_OP: str = ">>"; break; + case ID: str = "identifier"; break; + case LABEL: str = "label"; break; + default: + strch[1] = token; + str = strch; + break; + } + yasm_error_set(YASM_ERROR_PARSE, "expected %s", str); + destroy_curtok(); + return 0; +} +#define expect(token) expect_(parser_gas, token) + +static yasm_bytecode * +parse_line(yasm_parser_gas *parser_gas) +{ + yasm_bytecode *bc; + yasm_expr *e; + yasm_valparamhead vps; + char *id; + const dir_lookup *dir; + + if (is_eol()) + return NULL; + + bc = parse_instr(parser_gas); + if (bc) + return bc; + + switch (curtok) { + case ID: + id = ID_val; + + /* See if it's a gas-specific directive */ + dir = (const dir_lookup *)HAMT_search(parser_gas->dirs, id); + if (dir) { + parser_gas->state = dir->newstate; + get_next_token(); /* ID */ + return dir->handler(parser_gas, dir->param); + } + + get_next_token(); /* ID */ + if (curtok == ':') { + /* Label */ + parser_gas->state = INITIAL; + get_next_token(); /* : */ + define_label(parser_gas, id, 0); + return parse_line(parser_gas); + } else if (curtok == '=') { + /* EQU */ + /* TODO: allow redefinition, assigning to . (same as .org) */ + parser_gas->state = INITIAL; + get_next_token(); /* = */ + e = parse_expr(parser_gas); + if (e) + yasm_symtab_define_equ(p_symtab, id, e, cur_line); + else + yasm_error_set(YASM_ERROR_SYNTAX, + N_("expression expected after `%s'"), "="); + yasm_xfree(id); + return NULL; + } + + /* possibly a directive; try to parse it */ + parse_dirvals(parser_gas, &vps); + if (!yasm_object_directive(p_object, id, "gas", &vps, NULL, + cur_line)) { + yasm_vps_delete(&vps); + yasm_xfree(id); + return NULL; + } + yasm_vps_delete(&vps); + if (id[0] == '.') + yasm_warn_set(YASM_WARN_GENERAL, + N_("directive `%s' not recognized"), id); + else + yasm_error_set(YASM_ERROR_SYNTAX, + N_("instruction not recognized: `%s'"), id); + yasm_xfree(id); + return NULL; + case LABEL: + define_label(parser_gas, LABEL_val, 0); + get_next_token(); /* LABEL */ + return parse_line(parser_gas); + case CPP_LINE_MARKER: + get_next_token(); + cpp_line_marker(parser_gas); + return NULL; + case NASM_LINE_MARKER: + get_next_token(); + nasm_line_marker(parser_gas); + return NULL; + default: + yasm_error_set(YASM_ERROR_SYNTAX, + N_("label or instruction expected at start of line")); + return NULL; + } +} + +/* + Handle line markers generated by cpp. + + We expect a positive integer (line) followed by a string (filename). If we + fail to find either of these, we treat the line as a comment. There is a + possibility of false positives (mistaking a comment for a line marker, when + the comment is not intended as a line marker) but this cannot be avoided + without adding a filter to the input before passing it to cpp. + + This function is only called if the preprocessor was 'cpp', since the + CPP_LINE_MARKER token isn't generated for any other preprocessor. With any + other preprocessor, anything after a '#' is always treated as a comment. +*/ +static void +cpp_line_marker(yasm_parser_gas *parser_gas) +{ + yasm_valparamhead vps; + yasm_valparam *vp; + unsigned long line; + char *filename; + + /* Line number. */ + if (curtok != INTNUM) { + /* Skip over a comment. */ + while (curtok != '\n') + get_next_token(); + + return; + } + + if (yasm_intnum_sign(INTNUM_val) < 0) { + get_next_token(); /* INTNUM */ + yasm_error_set(YASM_ERROR_SYNTAX, + N_("line number is negative")); + return; + } + + line = yasm_intnum_get_uint(INTNUM_val); + + /* + Set to (line - 1) since the directive indicates that the *next* line + will have the number given. + + cpp should never produce line=0, but the if keeps us safe just incase. + */ + if (line != 0) + line--; + + yasm_intnum_destroy(INTNUM_val); + get_next_token(); /* INTNUM */ + + /* File name, in quotes. */ + if (curtok != STRING) { + /* Skip over a comment. */ + while (curtok != '\n') + get_next_token(); + + return; + } + + filename = STRING_val.contents; + get_next_token(); + + /* Set linemap. */ + yasm_linemap_set(parser_gas->linemap, filename, 0, line, 1); + + /* + The first line marker in the file (which should be on the first line + of the file) will give us the name of the source file. This information + needs to be passed on to the debug format module. + */ + if (parser_gas->seen_line_marker == 0) { + parser_gas->seen_line_marker = 1; + + yasm_vps_initialize(&vps); + vp = yasm_vp_create_string(NULL, filename); + yasm_vps_append(&vps, vp); + + yasm_object_directive(p_object, ".file", "gas", &vps, NULL, cur_line); + + yasm_vps_delete(&vps); + } else + yasm_xfree(filename); + + /* Skip flags. */ + while (1) { + switch (curtok) { + case INTNUM: + break; + + case '\n': + return; + + default: + yasm_error_set(YASM_ERROR_SYNTAX, + N_("junk at end of cpp line marker")); + return; + } + get_next_token(); + } +} + +/* + Handle line markers generated by the nasm preproc. + + We expect a positive integer (line) followed by a plus sign, followed by + another positive integer, followed by a string (filename). + + This function is only called if the preprocessor was 'nasm', since the + NASM_LINE_MARKER token isn't generated for any other preprocessor. +*/ +static void +nasm_line_marker(yasm_parser_gas *parser_gas) +{ + yasm_valparamhead vps; + yasm_valparam *vp; + unsigned long line, incr; + char *filename; + + /* Line number. */ + if (!expect(INTNUM)) return; + + if (yasm_intnum_sign(INTNUM_val) < 0) { + get_next_token(); /* INTNUM */ + yasm_error_set(YASM_ERROR_SYNTAX, + N_("line number is negative")); + return; + } + + line = yasm_intnum_get_uint(INTNUM_val); + + /* + Set to (line - 1) since the directive indicates that the *next* line + will have the number given. + + cpp should never produce line=0, but the if keeps us safe just incase. + */ + if (line != 0) + line--; + + yasm_intnum_destroy(INTNUM_val); + get_next_token(); /* INTNUM */ + + if (!expect('+')) return; + get_next_token(); /* + */ + + /* Line number increment. */ + if (!expect(INTNUM)) return; + + if (yasm_intnum_sign(INTNUM_val) < 0) { + get_next_token(); /* INTNUM */ + yasm_error_set(YASM_ERROR_SYNTAX, + N_("line increment is negative")); + return; + } + + incr = yasm_intnum_get_uint(INTNUM_val); + yasm_intnum_destroy(INTNUM_val); + + /* File name is not in quotes, so need to switch to a different tokenizer + * state. + */ + parser_gas->state = NASM_FILENAME; + get_next_token(); /* INTNUM */ + if (!expect(STRING)) { + parser_gas->state = INITIAL; + return; + } + + filename = STRING_val.contents; + + /* Set linemap. */ + yasm_linemap_set(parser_gas->linemap, filename, 0, line, incr); + + /* + The first line marker in the file (which should be on the first line + of the file) will give us the name of the source file. This information + needs to be passed on to the debug format module. + */ + if (parser_gas->seen_line_marker == 0) { + parser_gas->seen_line_marker = 1; + + yasm_vps_initialize(&vps); + vp = yasm_vp_create_string(NULL, filename); + yasm_vps_append(&vps, vp); + + yasm_object_directive(p_object, ".file", "gas", &vps, NULL, cur_line); + + yasm_vps_delete(&vps); + } else + yasm_xfree(filename); + + /* We need to poke back on the \n that was consumed by the tokenizer */ + parser_gas->peek_token = '\n'; + get_next_token(); +} + +/* Line directive */ +static yasm_bytecode * +dir_line(yasm_parser_gas *parser_gas, unsigned int param) +{ + if (!expect(INTNUM)) return NULL; + if (yasm_intnum_sign(INTNUM_val) < 0) { + get_next_token(); /* INTNUM */ + yasm_error_set(YASM_ERROR_SYNTAX, + N_("line number is negative")); + return NULL; + } + + parser_gas->dir_line = yasm_intnum_get_uint(INTNUM_val); + yasm_intnum_destroy(INTNUM_val); + get_next_token(); /* INTNUM */ + + if (parser_gas->dir_fileline == 3) { + /* Have both file and line */ + yasm_linemap_set(parser_gas->linemap, NULL, 0, + parser_gas->dir_line, 1); + } else if (parser_gas->dir_fileline == 1) { + /* Had previous file directive only */ + parser_gas->dir_fileline = 3; + yasm_linemap_set(parser_gas->linemap, parser_gas->dir_file, 0, + parser_gas->dir_line, 1); + } else { + /* Didn't see file yet */ + parser_gas->dir_fileline = 2; + } + return NULL; +} + +/* Alignment directives */ + +static yasm_bytecode * +dir_align(yasm_parser_gas *parser_gas, unsigned int param) +{ + yasm_expr *bound, *fill=NULL, *maxskip=NULL; + + bound = parse_expr(parser_gas); + if (!bound) { + yasm_error_set(YASM_ERROR_SYNTAX, + N_(".align directive must specify alignment")); + return NULL; + } + + if (curtok == ',') { + get_next_token(); /* ',' */ + fill = parse_expr(parser_gas); + if (curtok == ',') { + get_next_token(); /* ',' */ + maxskip = parse_expr(parser_gas); + } + } + + return gas_parser_align(parser_gas, cursect, bound, fill, maxskip, + (int)param); +} + +static yasm_bytecode * +dir_org(yasm_parser_gas *parser_gas, unsigned int param) +{ + yasm_intnum *start, *value=NULL; + yasm_bytecode *bc; + + /* TODO: support expr instead of intnum */ + if (!expect(INTNUM)) return NULL; + start = INTNUM_val; + get_next_token(); /* INTNUM */ + + if (curtok == ',') { + get_next_token(); /* ',' */ + /* TODO: support expr instead of intnum */ + if (!expect(INTNUM)) return NULL; + value = INTNUM_val; + get_next_token(); /* INTNUM */ + } + if (value) { + bc = yasm_bc_create_org(yasm_intnum_get_uint(start), + yasm_intnum_get_uint(value), cur_line); + yasm_intnum_destroy(value); + } else + bc = yasm_bc_create_org(yasm_intnum_get_uint(start), 0, + cur_line); + yasm_intnum_destroy(start); + return bc; +} + +/* Data visibility directives */ + +static yasm_bytecode * +dir_local(yasm_parser_gas *parser_gas, unsigned int param) +{ + if (!expect(ID)) return NULL; + yasm_symtab_declare(p_symtab, ID_val, YASM_SYM_DLOCAL, cur_line); + yasm_xfree(ID_val); + get_next_token(); /* ID */ + return NULL; +} + +static yasm_bytecode * +dir_comm(yasm_parser_gas *parser_gas, unsigned int is_lcomm) +{ + yasm_expr *align = NULL; + /*@null@*/ /*@dependent@*/ yasm_symrec *sym; + char *id; + yasm_expr *e; + + if (!expect(ID)) return NULL; + id = ID_val; + get_next_token(); /* ID */ + if (!expect(',')) { + yasm_xfree(id); + return NULL; + } + get_next_token(); /* , */ + e = parse_expr(parser_gas); + if (!e) { + yasm_error_set(YASM_ERROR_SYNTAX, N_("size expected for `%s'"), + ".COMM"); + return NULL; + } + if (curtok == ',') { + /* Optional alignment expression */ + get_next_token(); /* ',' */ + align = parse_expr(parser_gas); + } + /* If already explicitly declared local, treat like LCOMM */ + if (is_lcomm + || ((sym = yasm_symtab_get(p_symtab, id)) + && yasm_symrec_get_visibility(sym) == YASM_SYM_DLOCAL)) { + define_lcomm(parser_gas, id, e, align); + } else if (align) { + /* Give third parameter as objext valparam */ + yasm_valparamhead *extvps = yasm_vps_create(); + yasm_valparam *vp = yasm_vp_create_expr(NULL, align); + yasm_vps_append(extvps, vp); + + sym = yasm_symtab_declare(p_symtab, id, YASM_SYM_COMMON, + cur_line); + yasm_symrec_set_common_size(sym, e); + yasm_symrec_set_objext_valparams(sym, extvps); + + yasm_xfree(id); + } else { + sym = yasm_symtab_declare(p_symtab, id, YASM_SYM_COMMON, + cur_line); + yasm_symrec_set_common_size(sym, e); + yasm_xfree(id); + } + return NULL; +} + +/* Integer data definition directives */ + +static yasm_bytecode * +dir_ascii(yasm_parser_gas *parser_gas, unsigned int withzero) +{ + yasm_datavalhead dvs; + if (!parse_strvals(parser_gas, &dvs)) + return NULL; + return yasm_bc_create_data(&dvs, 1, (int)withzero, p_object->arch, + cur_line); +} + +static yasm_bytecode * +dir_data(yasm_parser_gas *parser_gas, unsigned int size) +{ + yasm_datavalhead dvs; + if (!parse_datavals(parser_gas, &dvs)) + return NULL; + return yasm_bc_create_data(&dvs, size, 0, p_object->arch, cur_line); +} + +static yasm_bytecode * +dir_leb128(yasm_parser_gas *parser_gas, unsigned int sign) +{ + yasm_datavalhead dvs; + if (!parse_datavals(parser_gas, &dvs)) + return NULL; + return yasm_bc_create_leb128(&dvs, (int)sign, cur_line); +} + +/* Empty space / fill data definition directives */ + +static yasm_bytecode * +dir_zero(yasm_parser_gas *parser_gas, unsigned int param) +{ + yasm_bytecode *bc; + yasm_datavalhead dvs; + yasm_expr *e = parse_expr(parser_gas); + if (!e) { + yasm_error_set(YASM_ERROR_SYNTAX, + N_("expression expected after `%s'"), ".ZERO"); + return NULL; + } + + yasm_dvs_initialize(&dvs); + yasm_dvs_append(&dvs, yasm_dv_create_expr( + p_expr_new_ident(yasm_expr_int(yasm_intnum_create_uint(0))))); + bc = yasm_bc_create_data(&dvs, 1, 0, p_object->arch, cur_line); + yasm_bc_set_multiple(bc, e); + return bc; +} + +static yasm_bytecode * +dir_skip(yasm_parser_gas *parser_gas, unsigned int param) +{ + yasm_expr *e, *e_val; + yasm_bytecode *bc; + yasm_datavalhead dvs; + + e = parse_expr(parser_gas); + if (!e) { + yasm_error_set(YASM_ERROR_SYNTAX, + N_("expression expected after `%s'"), ".SKIP"); + return NULL; + } + if (curtok != ',') + return yasm_bc_create_reserve(e, 1, cur_line); + get_next_token(); /* ',' */ + e_val = parse_expr(parser_gas); + yasm_dvs_initialize(&dvs); + yasm_dvs_append(&dvs, yasm_dv_create_expr(e_val)); + bc = yasm_bc_create_data(&dvs, 1, 0, p_object->arch, cur_line); + + yasm_bc_set_multiple(bc, e); + return bc; +} + +/* fill data definition directive */ +static yasm_bytecode * +dir_fill(yasm_parser_gas *parser_gas, unsigned int param) +{ + yasm_expr *sz=NULL, *val=NULL; + yasm_expr *e = parse_expr(parser_gas); + if (!e) { + yasm_error_set(YASM_ERROR_SYNTAX, + N_("expression expected after `%s'"), ".FILL"); + return NULL; + } + if (curtok == ',') { + get_next_token(); /* ',' */ + sz = parse_expr(parser_gas); + if (curtok == ',') { + get_next_token(); /* ',' */ + val = parse_expr(parser_gas); + } + } + return gas_parser_dir_fill(parser_gas, e, sz, val); +} + +/* Section directives */ + +static yasm_bytecode * +dir_bss_section(yasm_parser_gas *parser_gas, unsigned int param) +{ + gas_switch_section(parser_gas, ".bss", NULL, NULL, NULL, 1); + return NULL; +} + +static yasm_bytecode * +dir_data_section(yasm_parser_gas *parser_gas, unsigned int param) +{ + gas_switch_section(parser_gas, ".data", NULL, NULL, NULL, 1); + return NULL; +} + +static yasm_bytecode * +dir_text_section(yasm_parser_gas *parser_gas, unsigned int param) +{ + gas_switch_section(parser_gas, ".text", NULL, NULL, NULL, 1); + return NULL; +} + +static yasm_bytecode * +dir_section(yasm_parser_gas *parser_gas, unsigned int param) +{ + /* DIR_SECTION ID ',' STRING ',' '@' ID ',' dirvals */ + char *sectname, *flags = NULL, *type = NULL; + yasm_valparamhead vps; + int have_vps = 0; + + if (!expect(ID)) return NULL; + sectname = ID_val; + get_next_token(); /* ID */ + + if (curtok == ',') { + get_next_token(); /* ',' */ + if (!expect(STRING)) { + yasm_error_set(YASM_ERROR_SYNTAX, + N_("flag string expected")); + yasm_xfree(sectname); + return NULL; + } + flags = STRING_val.contents; + get_next_token(); /* STRING */ + } + + if (curtok == ',') { + get_next_token(); /* ',' */ + if (!expect('@')) { + yasm_xfree(sectname); + yasm_xfree(flags); + return NULL; + } + get_next_token(); /* '@' */ + if (!expect(ID)) { + yasm_xfree(sectname); + yasm_xfree(flags); + return NULL; + } + type = ID_val; + get_next_token(); /* ID */ + } + + if (curtok == ',') { + get_next_token(); /* ',' */ + if (parse_dirvals(parser_gas, &vps)) + have_vps = 1; + } + + gas_switch_section(parser_gas, sectname, flags, type, + have_vps ? &vps : NULL, 0); + yasm_xfree(sectname); + yasm_xfree(flags); + return NULL; +} + +/* Other directives */ + +static yasm_bytecode * +dir_equ(yasm_parser_gas *parser_gas, unsigned int param) +{ + yasm_expr *e; + char *id; + + /* ID ',' expr */ + if (!expect(ID)) return NULL; + id = ID_val; + get_next_token(); /* ID */ + if (!expect(',')) { + yasm_xfree(id); + return NULL; + } + get_next_token(); /* ',' */ + e = parse_expr(parser_gas); + if (e) + yasm_symtab_define_equ(p_symtab, id, e, cur_line); + else + yasm_error_set(YASM_ERROR_SYNTAX, + N_("expression expected after `%s'"), ","); + yasm_xfree(id); + return NULL; +} + +static yasm_bytecode * +dir_file(yasm_parser_gas *parser_gas, unsigned int param) +{ + yasm_valparamhead vps; + yasm_valparam *vp; + + if (curtok == STRING) { + /* No file number; this form also sets the assembler's + * internal line number. + */ + char *filename = STRING_val.contents; + + get_next_token(); /* STRING */ + if (parser_gas->dir_fileline == 3) { + /* Have both file and line */ + const char *old_fn; + unsigned long old_line; + + yasm_linemap_lookup(parser_gas->linemap, cur_line, &old_fn, + &old_line); + yasm_linemap_set(parser_gas->linemap, filename, 0, old_line, + 1); + } else if (parser_gas->dir_fileline == 2) { + /* Had previous line directive only */ + parser_gas->dir_fileline = 3; + yasm_linemap_set(parser_gas->linemap, filename, 0, + parser_gas->dir_line, 1); + } else { + /* Didn't see line yet, save file */ + parser_gas->dir_fileline = 1; + if (parser_gas->dir_file) + yasm_xfree(parser_gas->dir_file); + parser_gas->dir_file = yasm__xstrdup(filename); + } + + /* Pass change along to debug format */ + yasm_vps_initialize(&vps); + vp = yasm_vp_create_string(NULL, filename); + yasm_vps_append(&vps, vp); + + yasm_object_directive(p_object, ".file", "gas", &vps, NULL, + cur_line); + + yasm_vps_delete(&vps); + return NULL; + } + + /* fileno filename form */ + yasm_vps_initialize(&vps); + + if (!expect(INTNUM)) return NULL; + vp = yasm_vp_create_expr(NULL, + p_expr_new_ident(yasm_expr_int(INTNUM_val))); + yasm_vps_append(&vps, vp); + get_next_token(); /* INTNUM */ + + if (!expect(STRING)) { + yasm_vps_delete(&vps); + return NULL; + } + vp = yasm_vp_create_string(NULL, STRING_val.contents); + yasm_vps_append(&vps, vp); + get_next_token(); /* STRING */ + + yasm_object_directive(p_object, ".file", "gas", &vps, NULL, + cur_line); + + yasm_vps_delete(&vps); + return NULL; +} + + +static yasm_bytecode * +dir_intel_syntax(yasm_parser_gas *parser_gas, unsigned int param) +{ + parser_gas->intel_syntax = 1; + + do { + destroy_curtok(); + get_next_token(); + } while (!is_eol()); + return NULL; +} + +static yasm_bytecode * +dir_att_syntax(yasm_parser_gas *parser_gas, unsigned int param) +{ + parser_gas->intel_syntax = 0; + return NULL; +} + +static yasm_bytecode * +parse_instr(yasm_parser_gas *parser_gas) +{ + yasm_bytecode *bc; + char *id; + uintptr_t prefix; + + if (parser_gas->intel_syntax) { + bc = parse_instr_intel(parser_gas); + if (bc) { + yasm_warn_disable(YASM_WARN_UNREC_CHAR); + do { + destroy_curtok(); + get_next_token(); + } while (!is_eol()); + yasm_warn_enable(YASM_WARN_UNREC_CHAR); + } + return bc; + } + + if (curtok != ID) + return NULL; + + id = ID_val; + + /* instructions/prefixes must start with a letter */ + if (!isalpha(id[0])) + return NULL; + + /* check to be sure it's not a label or equ */ + get_peek_token(parser_gas); + if (parser_gas->peek_token == ':' || parser_gas->peek_token == '=') + return NULL; + + switch (yasm_arch_parse_check_insnprefix + (p_object->arch, ID_val, ID_len, cur_line, &bc, &prefix)) { + case YASM_ARCH_INSN: + { + yasm_insn *insn; + + /* Propagate errors in case we got a warning from the arch */ + yasm_errwarn_propagate(parser_gas->errwarns, cur_line); + + insn = yasm_bc_get_insn(bc); + + yasm_xfree(id); + get_next_token(); /* ID */ + if (is_eol()) + return bc; /* no operands */ + + /* parse operands */ + for (;;) { + yasm_insn_operand *op = parse_operand(parser_gas); + if (!op) { + yasm_error_set(YASM_ERROR_SYNTAX, + N_("expression syntax error")); + yasm_bc_destroy(bc); + return NULL; + } + yasm_insn_ops_append(insn, op); + + if (is_eol()) + break; + if (!expect(',')) { + yasm_bc_destroy(bc); + return NULL; + } + get_next_token(); + } + return bc; + } + case YASM_ARCH_PREFIX: + /* Propagate errors in case we got a warning from the arch */ + yasm_errwarn_propagate(parser_gas->errwarns, cur_line); + + yasm_xfree(id); + get_next_token(); /* ID */ + bc = parse_instr(parser_gas); + if (!bc) + bc = yasm_arch_create_empty_insn(p_object->arch, cur_line); + yasm_insn_add_prefix(yasm_bc_get_insn(bc), prefix); + return bc; + default: + break; + } + + /* Check for segment register used as prefix */ + switch (yasm_arch_parse_check_regtmod(p_object->arch, ID_val, ID_len, + &prefix)) { + case YASM_ARCH_SEGREG: + yasm_xfree(id); + get_next_token(); /* ID */ + bc = parse_instr(parser_gas); + if (!bc) + bc = yasm_arch_create_empty_insn(p_object->arch, cur_line); + yasm_insn_add_seg_prefix(yasm_bc_get_insn(bc), prefix); + return bc; + default: + return NULL; + } +} + +static int +parse_dirvals(yasm_parser_gas *parser_gas, yasm_valparamhead *vps) +{ + yasm_valparam *vp; + yasm_expr *e; + int num = 0; + + yasm_vps_initialize(vps); + + for (;;) { + switch (curtok) { + case ID: + get_peek_token(parser_gas); + switch (parser_gas->peek_token) { + case '+': case '-': + case '|': case '^': case '&': case '!': + case '*': case '/': case '%': case LEFT_OP: case RIGHT_OP: + e = parse_expr(parser_gas); + vp = yasm_vp_create_expr(NULL, e); + break; + default: + /* Just an ID */ + vp = yasm_vp_create_id(NULL, ID_val, '\0'); + get_next_token(); /* ID */ + break; + } + break; + case STRING: + vp = yasm_vp_create_string(NULL, STRING_val.contents); + get_next_token(); /* STRING */ + break; + case REG: + e = p_expr_new_ident(yasm_expr_reg(REG_val)); + vp = yasm_vp_create_expr(NULL, e); + get_next_token(); /* REG */ + break; + case '@': + /* XXX: is throwing it away *really* the right thing? */ + get_next_token(); /* @ */ + continue; + default: + e = parse_expr(parser_gas); + if (!e) + return num; + vp = yasm_vp_create_expr(NULL, e); + break; + } + yasm_vps_append(vps, vp); + num++; + if (curtok == ',') + get_next_token(); /* ',' */ + } + return num; +} + +static int +parse_datavals(yasm_parser_gas *parser_gas, yasm_datavalhead *dvs) +{ + yasm_expr *e; + yasm_dataval *dv; + int num = 0; + + yasm_dvs_initialize(dvs); + + for (;;) { + e = parse_expr(parser_gas); + if (!e) { + yasm_dvs_delete(dvs); + yasm_dvs_initialize(dvs); + return 0; + } + dv = yasm_dv_create_expr(e); + yasm_dvs_append(dvs, dv); + num++; + if (curtok != ',') + break; + get_next_token(); /* ',' */ + } + return num; +} + +static int +parse_strvals(yasm_parser_gas *parser_gas, yasm_datavalhead *dvs) +{ + yasm_dataval *dv; + int num = 0; + + yasm_dvs_initialize(dvs); + + for (;;) { + if (!expect(STRING)) { + yasm_dvs_delete(dvs); + yasm_dvs_initialize(dvs); + return 0; + } + dv = yasm_dv_create_string(STRING_val.contents, STRING_val.len); + yasm_dvs_append(dvs, dv); + get_next_token(); /* STRING */ + num++; + if (curtok != ',') + break; + get_next_token(); /* ',' */ + } + return num; +} + +/* instruction operands */ +/* memory addresses */ +static yasm_effaddr * +parse_memaddr(yasm_parser_gas *parser_gas) +{ + yasm_effaddr *ea = NULL; + yasm_expr *e1, *e2; + int strong = 0; + + if (curtok == SEGREG) { + uintptr_t segreg = SEGREG_val; + get_next_token(); /* SEGREG */ + if (!expect(':')) return NULL; + get_next_token(); /* ':' */ + ea = parse_memaddr(parser_gas); + if (!ea) + return NULL; + yasm_ea_set_segreg(ea, segreg); + return ea; + } + + /* We want to parse a leading expression, except when it's actually + * just a memory address (with no preceding expression) such as + * (REG...) or (,...). + */ + get_peek_token(parser_gas); + if (curtok != '(' || (parser_gas->peek_token != REG + && parser_gas->peek_token != ',')) + e1 = parse_expr(parser_gas); + else + e1 = NULL; + + if (curtok == '(') { + int havereg = 0; + uintptr_t reg = 0; + yasm_intnum *scale = NULL; + + get_next_token(); /* '(' */ + + /* base register */ + if (curtok == REG) { + e2 = p_expr_new_ident(yasm_expr_reg(REG_val)); + get_next_token(); /* REG */ + } else + e2 = p_expr_new_ident(yasm_expr_int(yasm_intnum_create_uint(0))); + + if (curtok == ')') + goto done; + + if (!expect(',')) { + yasm_error_set(YASM_ERROR_SYNTAX, N_("invalid memory expression")); + if (e1) yasm_expr_destroy(e1); + yasm_expr_destroy(e2); + return NULL; + } + get_next_token(); /* ',' */ + + if (curtok == ')') + goto done; + + /* index register */ + if (curtok == REG) { + reg = REG_val; + havereg = 1; + get_next_token(); /* REG */ + if (curtok != ',') { + scale = yasm_intnum_create_uint(1); + goto done; + } + get_next_token(); /* ',' */ + } + + /* scale */ + if (!expect(INTNUM)) { + yasm_error_set(YASM_ERROR_SYNTAX, N_("non-integer scale")); + if (e1) yasm_expr_destroy(e1); + yasm_expr_destroy(e2); + return NULL; + } + scale = INTNUM_val; + get_next_token(); /* INTNUM */ + +done: + if (!expect(')')) { + yasm_error_set(YASM_ERROR_SYNTAX, N_("invalid memory expression")); + if (scale) yasm_intnum_destroy(scale); + if (e1) yasm_expr_destroy(e1); + yasm_expr_destroy(e2); + return NULL; + } + get_next_token(); /* ')' */ + + if (scale) { + if (!havereg) { + if (yasm_intnum_get_uint(scale) != 1) + yasm_warn_set(YASM_WARN_GENERAL, + N_("scale factor of %u without an index register"), + yasm_intnum_get_uint(scale)); + yasm_intnum_destroy(scale); + } else + e2 = p_expr_new(yasm_expr_expr(e2), YASM_EXPR_ADD, + yasm_expr_expr(p_expr_new(yasm_expr_reg(reg), YASM_EXPR_MUL, + yasm_expr_int(scale)))); + } + + if (e1) { + /* Ordering is critical here to correctly detecting presence of + * RIP in RIP-relative expressions. + */ + e1 = p_expr_new_tree(e2, YASM_EXPR_ADD, e1); + } else + e1 = e2; + strong = 1; + } + + if (!e1) + return NULL; + ea = yasm_arch_ea_create(p_object->arch, e1); + if (strong) + ea->strong = 1; + return ea; +} + +static yasm_insn_operand * +parse_operand(yasm_parser_gas *parser_gas) +{ + yasm_effaddr *ea; + yasm_insn_operand *op; + uintptr_t reg; + + switch (curtok) { + case REG: + reg = REG_val; + get_next_token(); /* REG */ + return yasm_operand_create_reg(reg); + case SEGREG: + /* need to see if it's really a memory address */ + get_peek_token(parser_gas); + if (parser_gas->peek_token == ':') { + ea = parse_memaddr(parser_gas); + if (!ea) + return NULL; + return yasm_operand_create_mem(ea); + } + reg = SEGREG_val; + get_next_token(); /* SEGREG */ + return yasm_operand_create_segreg(reg); + case REGGROUP: + { + unsigned long regindex; + reg = REGGROUP_val; + get_next_token(); /* REGGROUP */ + if (curtok != '(') + return yasm_operand_create_reg(reg); + get_next_token(); /* '(' */ + if (!expect(INTNUM)) { + yasm_error_set(YASM_ERROR_SYNTAX, + N_("integer register index expected")); + return NULL; + } + regindex = yasm_intnum_get_uint(INTNUM_val); + get_next_token(); /* INTNUM */ + if (!expect(')')) { + yasm_error_set(YASM_ERROR_SYNTAX, + N_("missing closing parenthesis for register index")); + return NULL; + } + get_next_token(); /* ')' */ + reg = yasm_arch_reggroup_get_reg(p_object->arch, reg, regindex); + if (reg == 0) { + yasm_error_set(YASM_ERROR_SYNTAX, N_("bad register index `%u'"), + regindex); + return NULL; + } + return yasm_operand_create_reg(reg); + } + case '$': + { + yasm_expr *e; + get_next_token(); /* '$' */ + e = parse_expr(parser_gas); + if (!e) { + yasm_error_set(YASM_ERROR_SYNTAX, + N_("expression missing after `%s'"), "$"); + return NULL; + } + return yasm_operand_create_imm(e); + } + case '*': + get_next_token(); /* '*' */ + if (curtok == REG) { + op = yasm_operand_create_reg(REG_val); + get_next_token(); /* REG */ + } else { + ea = parse_memaddr(parser_gas); + if (!ea) { + yasm_error_set(YASM_ERROR_SYNTAX, + N_("expression missing after `%s'"), "*"); + return NULL; + } + op = yasm_operand_create_mem(ea); + } + op->deref = 1; + return op; + default: + ea = parse_memaddr(parser_gas); + if (!ea) + return NULL; + return yasm_operand_create_mem(ea); + } +} + +/* Expression grammar parsed is: + * + * expr : expr0 [ {+,-} expr0...] + * expr0 : expr1 [ {|,^,&,!} expr1...] + * expr1 : expr2 [ {*,/,%,<<,>>} expr2...] + * expr2 : { ~,+,- } expr2 + * | (expr) + * | symbol + * | number + */ + +static yasm_expr * +parse_expr(yasm_parser_gas *parser_gas) +{ + yasm_expr *e, *f; + e = parse_expr0(parser_gas); + if (!e) + return NULL; + + while (curtok == '+' || curtok == '-') { + int op = curtok; + get_next_token(); + f = parse_expr0(parser_gas); + if (!f) { + yasm_expr_destroy(e); + return NULL; + } + + switch (op) { + case '+': e = p_expr_new_tree(e, YASM_EXPR_ADD, f); break; + case '-': e = p_expr_new_tree(e, YASM_EXPR_SUB, f); break; + } + } + return e; +} + +static yasm_expr * +parse_expr0(yasm_parser_gas *parser_gas) +{ + yasm_expr *e, *f; + e = parse_expr1(parser_gas); + if (!e) + return NULL; + + while (curtok == '|' || curtok == '^' || curtok == '&' || curtok == '!') { + int op = curtok; + get_next_token(); + f = parse_expr1(parser_gas); + if (!f) { + yasm_expr_destroy(e); + return NULL; + } + + switch (op) { + case '|': e = p_expr_new_tree(e, YASM_EXPR_OR, f); break; + case '^': e = p_expr_new_tree(e, YASM_EXPR_XOR, f); break; + case '&': e = p_expr_new_tree(e, YASM_EXPR_AND, f); break; + case '!': e = p_expr_new_tree(e, YASM_EXPR_NOR, f); break; + } + } + return e; +} + +static yasm_expr * +parse_expr1(yasm_parser_gas *parser_gas) +{ + yasm_expr *e, *f; + e = parse_expr2(parser_gas); + if (!e) + return NULL; + + while (curtok == '*' || curtok == '/' || curtok == '%' || curtok == LEFT_OP + || curtok == RIGHT_OP) { + int op = curtok; + get_next_token(); + f = parse_expr2(parser_gas); + if (!f) { + yasm_expr_destroy(e); + return NULL; + } + + switch (op) { + case '*': e = p_expr_new_tree(e, YASM_EXPR_MUL, f); break; + case '/': e = p_expr_new_tree(e, YASM_EXPR_DIV, f); break; + case '%': e = p_expr_new_tree(e, YASM_EXPR_MOD, f); break; + case LEFT_OP: e = p_expr_new_tree(e, YASM_EXPR_SHL, f); break; + case RIGHT_OP: e = p_expr_new_tree(e, YASM_EXPR_SHR, f); break; + } + } + return e; +} + +static yasm_expr * +parse_expr2(yasm_parser_gas *parser_gas) +{ + yasm_expr *e; + yasm_symrec *sym; + + switch (curtok) { + case '+': + get_next_token(); + return parse_expr2(parser_gas); + case '-': + get_next_token(); + e = parse_expr2(parser_gas); + if (!e) + return NULL; + return p_expr_new_branch(YASM_EXPR_NEG, e); + case '~': + get_next_token(); + e = parse_expr2(parser_gas); + if (!e) + return NULL; + return p_expr_new_branch(YASM_EXPR_NOT, e); + case '(': + get_next_token(); + e = parse_expr(parser_gas); + if (!e) + return NULL; + if (!expect(')')) { + yasm_error_set(YASM_ERROR_SYNTAX, N_("missing parenthesis")); + return NULL; + } + get_next_token(); + return e; + case INTNUM: + e = p_expr_new_ident(yasm_expr_int(INTNUM_val)); + get_next_token(); + return e; + case FLTNUM: + e = p_expr_new_ident(yasm_expr_float(FLTNUM_val)); + get_next_token(); + return e; + case ID: + { + char *name = ID_val; + get_next_token(); /* ID */ + + /* "." references the current assembly position */ + if (name[1] == '\0' && name[0] == '.') + sym = yasm_symtab_define_curpos(p_symtab, ".", + parser_gas->prev_bc, cur_line); + else + sym = yasm_symtab_use(p_symtab, name, cur_line); + yasm_xfree(name); + + if (curtok == '@') { + yasm_symrec *wrt; + /* TODO: this is needed for shared objects, e.g. sym@PLT */ + get_next_token(); /* '@' */ + if (!expect(ID)) { + yasm_error_set(YASM_ERROR_SYNTAX, + N_("expected identifier after `@'")); + return NULL; + } + wrt = yasm_objfmt_get_special_sym(p_object, ID_val, "gas"); + yasm_xfree(ID_val); + get_next_token(); /* ID */ + if (!wrt) { + yasm_warn_set(YASM_WARN_GENERAL, + N_("unrecognized identifier after `@'")); + return p_expr_new_ident(yasm_expr_sym(sym)); + } + return p_expr_new(yasm_expr_sym(sym), YASM_EXPR_WRT, + yasm_expr_sym(wrt)); + } + + return p_expr_new_ident(yasm_expr_sym(sym)); + } + default: + return NULL; + } +} + +static void +define_label(yasm_parser_gas *parser_gas, char *name, int local) +{ + if (!local) { + if (parser_gas->locallabel_base) + yasm_xfree(parser_gas->locallabel_base); + parser_gas->locallabel_base_len = strlen(name); + parser_gas->locallabel_base = + yasm_xmalloc(parser_gas->locallabel_base_len+1); + strcpy(parser_gas->locallabel_base, name); + } + + yasm_symtab_define_label(p_symtab, name, parser_gas->prev_bc, 1, + cur_line); + yasm_xfree(name); +} + +static void +define_lcomm(yasm_parser_gas *parser_gas, /*@only@*/ char *name, + yasm_expr *size, /*@null@*/ yasm_expr *align) +{ + /* Put into .bss section. */ + /*@dependent@*/ yasm_section *bss = + gas_get_section(parser_gas, yasm__xstrdup(".bss"), NULL, NULL, NULL, 1); + + if (align) { + /* XXX: assume alignment is in bytes, not power-of-two */ + yasm_section_bcs_append(bss, gas_parser_align(parser_gas, bss, align, + NULL, NULL, 0)); + } + + yasm_symtab_define_label(p_symtab, name, yasm_section_bcs_last(bss), 1, + cur_line); + yasm_section_bcs_append(bss, yasm_bc_create_reserve(size, 1, cur_line)); + yasm_xfree(name); +} + +static yasm_section * +gas_get_section(yasm_parser_gas *parser_gas, char *name, + /*@null@*/ char *flags, /*@null@*/ char *type, + /*@null@*/ yasm_valparamhead *objext_valparams, + int builtin) +{ + yasm_valparamhead vps; + yasm_valparam *vp; + char *gasflags; + yasm_section *new_section; + + yasm_vps_initialize(&vps); + vp = yasm_vp_create_id(NULL, name, '\0'); + yasm_vps_append(&vps, vp); + + if (!builtin) { + if (flags) + gasflags = yasm__xstrdup(flags); + else + gasflags = yasm__xstrdup(""); + vp = yasm_vp_create_string(yasm__xstrdup("gasflags"), gasflags); + yasm_vps_append(&vps, vp); + if (type) { + vp = yasm_vp_create_id(NULL, type, '\0'); + yasm_vps_append(&vps, vp); + } + } + + new_section = yasm_objfmt_section_switch(p_object, &vps, objext_valparams, + cur_line); + + yasm_vps_delete(&vps); + return new_section; +} + +static void +gas_switch_section(yasm_parser_gas *parser_gas, const char *name, + /*@null@*/ char *flags, /*@null@*/ char *type, + /*@null@*/ yasm_valparamhead *objext_valparams, + int builtin) +{ + yasm_section *new_section; + + new_section = gas_get_section(parser_gas, yasm__xstrdup(name), flags, type, + objext_valparams, builtin); + if (new_section) { + cursect = new_section; + parser_gas->prev_bc = yasm_section_bcs_last(new_section); + } else + yasm_error_set(YASM_ERROR_GENERAL, N_("invalid section name `%s'"), + name); + + if (objext_valparams) + yasm_vps_delete(objext_valparams); +} + +static yasm_bytecode * +gas_parser_align(yasm_parser_gas *parser_gas, yasm_section *sect, + yasm_expr *boundval, /*@null@*/ yasm_expr *fillval, + /*@null@*/ yasm_expr *maxskipval, int power2) +{ + yasm_intnum *boundintn; + + /* Convert power of two to number of bytes if necessary */ + if (power2) + boundval = yasm_expr_create(YASM_EXPR_SHL, + yasm_expr_int(yasm_intnum_create_uint(1)), + yasm_expr_expr(boundval), cur_line); + + /* Largest .align in the section specifies section alignment. */ + boundintn = yasm_expr_get_intnum(&boundval, 0); + if (boundintn) { + unsigned long boundint = yasm_intnum_get_uint(boundintn); + + /* Alignments must be a power of two. */ + if (is_exp2(boundint)) { + if (boundint > yasm_section_get_align(sect)) + yasm_section_set_align(sect, boundint, cur_line); + } + } + + return yasm_bc_create_align(boundval, fillval, maxskipval, + yasm_section_is_code(sect) ? + yasm_arch_get_fill(p_object->arch) : NULL, + cur_line); +} + +static yasm_bytecode * +gas_parser_dir_fill(yasm_parser_gas *parser_gas, /*@only@*/ yasm_expr *repeat, + /*@only@*/ /*@null@*/ yasm_expr *size, + /*@only@*/ /*@null@*/ yasm_expr *value) +{ + yasm_datavalhead dvs; + yasm_bytecode *bc; + unsigned int ssize; + + if (size) { + /*@dependent@*/ /*@null@*/ yasm_intnum *intn; + intn = yasm_expr_get_intnum(&size, 0); + if (!intn) { + yasm_error_set(YASM_ERROR_NOT_ABSOLUTE, + N_("size must be an absolute expression")); + yasm_expr_destroy(repeat); + yasm_expr_destroy(size); + if (value) + yasm_expr_destroy(value); + return NULL; + } + ssize = yasm_intnum_get_uint(intn); + } else + ssize = 1; + + if (!value) + value = yasm_expr_create_ident( + yasm_expr_int(yasm_intnum_create_uint(0)), cur_line); + + yasm_dvs_initialize(&dvs); + yasm_dvs_append(&dvs, yasm_dv_create_expr(value)); + bc = yasm_bc_create_data(&dvs, ssize, 0, p_object->arch, cur_line); + + yasm_bc_set_multiple(bc, repeat); + + return bc; +} + +static dir_lookup dirs_static[] = { + /* FIXME: Whether this is power-of-two or not depends on arch and objfmt. */ + {".align", dir_align, 0, INITIAL}, + {".p2align", dir_align, 1, INITIAL}, + {".balign", dir_align, 0, INITIAL}, + {".org", dir_org, 0, INITIAL}, + /* data visibility directives */ + {".local", dir_local, 0, INITIAL}, + {".comm", dir_comm, 0, INITIAL}, + {".lcomm", dir_comm, 1, INITIAL}, + /* integer data declaration directives */ + {".byte", dir_data, 1, INITIAL}, + {".2byte", dir_data, 2, INITIAL}, + {".4byte", dir_data, 4, INITIAL}, + {".8byte", dir_data, 8, INITIAL}, + {".16byte", dir_data, 16, INITIAL}, + /* TODO: These should depend on arch */ + {".short", dir_data, 2, INITIAL}, + {".int", dir_data, 4, INITIAL}, + {".long", dir_data, 4, INITIAL}, + {".hword", dir_data, 2, INITIAL}, + {".quad", dir_data, 8, INITIAL}, + {".octa", dir_data, 16, INITIAL}, + /* XXX: At least on x86, this is 2 bytes */ + {".value", dir_data, 2, INITIAL}, + /* ASCII data declaration directives */ + {".ascii", dir_ascii, 0, INITIAL}, /* no terminating zero */ + {".asciz", dir_ascii, 1, INITIAL}, /* add terminating zero */ + {".string", dir_ascii, 1, INITIAL}, /* add terminating zero */ + /* LEB128 integer data declaration directives */ + {".sleb128", dir_leb128, 1, INITIAL}, /* signed */ + {".uleb128", dir_leb128, 0, INITIAL}, /* unsigned */ + /* floating point data declaration directives */ + {".float", dir_data, 4, INITIAL}, + {".single", dir_data, 4, INITIAL}, + {".double", dir_data, 8, INITIAL}, + {".tfloat", dir_data, 10, INITIAL}, + /* section directives */ + {".bss", dir_bss_section, 0, INITIAL}, + {".data", dir_data_section, 0, INITIAL}, + {".text", dir_text_section, 0, INITIAL}, + {".section", dir_section, 0, SECTION_DIRECTIVE}, + /* empty space/fill directives */ + {".skip", dir_skip, 0, INITIAL}, + {".space", dir_skip, 0, INITIAL}, + {".fill", dir_fill, 0, INITIAL}, + {".zero", dir_zero, 0, INITIAL}, + /* syntax directives */ + {".intel_syntax", dir_intel_syntax, 0, INITIAL}, + {".att_syntax", dir_att_syntax, 0, INITIAL}, + /* other directives */ + {".equ", dir_equ, 0, INITIAL}, + {".file", dir_file, 0, INITIAL}, + {".line", dir_line, 0, INITIAL}, + {".set", dir_equ, 0, INITIAL} +}; + +static void +no_delete(void *data) +{ +} + +void +gas_parser_parse(yasm_parser_gas *parser_gas) +{ + dir_lookup word; + unsigned int i; + int replace = 1; + + word.name = ".word"; + word.handler = dir_data; + word.param = yasm_arch_wordsize(p_object->arch)/8; + word.newstate = INITIAL; + + /* Create directive lookup */ + parser_gas->dirs = HAMT_create(1, yasm_internal_error_); + HAMT_insert(parser_gas->dirs, word.name, &word, &replace, no_delete); + for (i=0; i<NELEMS(dirs_static); i++) { + replace = 1; + HAMT_insert(parser_gas->dirs, dirs_static[i].name, + &dirs_static[i], &replace, no_delete); + } + + while (get_next_token() != 0) { + yasm_bytecode *bc = NULL, *temp_bc; + + if (!is_eol()) { + bc = parse_line(parser_gas); + demand_eol(); + } + + yasm_errwarn_propagate(parser_gas->errwarns, cur_line); + + temp_bc = yasm_section_bcs_append(cursect, bc); + if (temp_bc) + parser_gas->prev_bc = temp_bc; + if (curtok == ';') + continue; /* don't advance line number until \n */ + if (parser_gas->save_input) + yasm_linemap_add_source(parser_gas->linemap, + temp_bc, + (char *)parser_gas->save_line[parser_gas->save_last ^ 1]); + yasm_linemap_goto_next(parser_gas->linemap); + parser_gas->dir_line++; /* keep track for .line followed by .file */ + } + + HAMT_destroy(parser_gas->dirs, no_delete); +} diff --git a/contrib/tools/yasm/modules/parsers/gas/gas-parser.c b/contrib/tools/yasm/modules/parsers/gas/gas-parser.c new file mode 100644 index 0000000000..088bcdad0a --- /dev/null +++ b/contrib/tools/yasm/modules/parsers/gas/gas-parser.c @@ -0,0 +1,133 @@ +/* + * GAS-compatible parser + * + * Copyright (C) 2005-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. + * 3. Neither the name of the author nor the names of other contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 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 "gas-parser.h" + + +static void +gas_parser_do_parse(yasm_object *object, yasm_preproc *pp, + int save_input, yasm_linemap *linemap, + yasm_errwarns *errwarns) +{ + yasm_parser_gas parser_gas; + int i; + + parser_gas.object = object; + parser_gas.linemap = linemap; + + parser_gas.locallabel_base = (char *)NULL; + parser_gas.locallabel_base_len = 0; + + parser_gas.dir_fileline = 0; + parser_gas.dir_file = NULL; + parser_gas.dir_line = 0; + parser_gas.seen_line_marker = 0; + + parser_gas.preproc = pp; + parser_gas.errwarns = errwarns; + + parser_gas.prev_bc = yasm_section_bcs_first(object->cur_section); + + parser_gas.save_input = save_input; + parser_gas.save_last = 0; + + parser_gas.peek_token = NONE; + + parser_gas.line = NULL; + + /* initialize scanner structure */ + yasm_scanner_initialize(&parser_gas.s); + + parser_gas.state = INITIAL; + + for (i=0; i<10; i++) + parser_gas.local[i] = 0; + + parser_gas.intel_syntax = 0; + + parser_gas.is_cpp_preproc = + yasm__strcasecmp(((yasm_preproc_base*)pp)->module->keyword, "cpp") == 0; + parser_gas.is_nasm_preproc = + yasm__strcasecmp(((yasm_preproc_base*)pp)->module->keyword, "nasm") == 0; + + gas_parser_parse(&parser_gas); + + /* Check for ending inside a comment */ + if (parser_gas.state == COMMENT) { + yasm_warn_set(YASM_WARN_GENERAL, N_("end of file in comment")); + /* XXX: Minus two to compensate for already having moved past the EOF + * in the linemap. + */ + yasm_errwarn_propagate(errwarns, + yasm_linemap_get_current(parser_gas.linemap)-2); + } + + yasm_scanner_delete(&parser_gas.s); + + /* Free locallabel base if necessary */ + if (parser_gas.locallabel_base) + yasm_xfree(parser_gas.locallabel_base); + + if (parser_gas.dir_file) + yasm_xfree(parser_gas.dir_file); + + /* Convert all undefined symbols into extern symbols */ + yasm_symtab_parser_finalize(object->symtab, 1, errwarns); +} + +/* Define valid preprocessors to use with this parser */ +static const char *gas_parser_preproc_keywords[] = { + "gas", + "raw", + "cpp", + "nasm", + NULL +}; + +/* Define parser structure -- see parser.h for details */ +yasm_parser_module yasm_gas_LTX_parser = { + "GNU AS (GAS)-compatible parser", + "gas", + gas_parser_preproc_keywords, + "gas", + NULL, /* No standard macros */ + gas_parser_do_parse +}; +yasm_parser_module yasm_gnu_LTX_parser = { + "GNU AS (GAS)-compatible parser", + "gnu", + gas_parser_preproc_keywords, + "gas", + NULL, /* No standard macros */ + gas_parser_do_parse +}; diff --git a/contrib/tools/yasm/modules/parsers/gas/gas-parser.h b/contrib/tools/yasm/modules/parsers/gas/gas-parser.h new file mode 100644 index 0000000000..99659e964a --- /dev/null +++ b/contrib/tools/yasm/modules/parsers/gas/gas-parser.h @@ -0,0 +1,163 @@ +/* + * GAS-compatible parser header file + * + * Copyright (C) 2005-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. + * 3. Neither the name of the author nor the names of other contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 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_GAS_PARSER_H +#define YASM_GAS_PARSER_H + +#define YYCTYPE unsigned char + +#define MAX_SAVED_LINE_LEN 80 + +enum tokentype { + INTNUM = 258, + FLTNUM, + STRING, + REG, + REGGROUP, + SEGREG, + TARGETMOD, + LEFT_OP, + RIGHT_OP, + ID, + LABEL, + CPP_LINE_MARKER, + NASM_LINE_MARKER, + NONE +}; + +typedef union { + unsigned int int_info; + yasm_intnum *intn; + yasm_floatnum *flt; + yasm_bytecode *bc; + uintptr_t arch_data; + struct { + char *contents; + size_t len; + } str; +} yystype; +#define YYSTYPE yystype + +enum gas_parser_state { + INITIAL, + COMMENT, + SECTION_DIRECTIVE, + NASM_FILENAME +}; + +typedef struct yasm_parser_gas { + /*@only@*/ yasm_object *object; + + /* last "base" label for local (.) labels */ + /*@null@*/ char *locallabel_base; + size_t locallabel_base_len; + + /* .line/.file: we have to see both to start setting linemap versions */ + int dir_fileline; + /*@null@*/ char *dir_file; + unsigned long dir_line; + + /* Have we seen a line marker? */ + int seen_line_marker; + + /*@dependent@*/ yasm_preproc *preproc; + /*@dependent@*/ yasm_errwarns *errwarns; + + /*@dependent@*/ yasm_linemap *linemap; + + /*@null@*/ yasm_bytecode *prev_bc; + yasm_bytecode *temp_bc; + + int save_input; + YYCTYPE save_line[2][MAX_SAVED_LINE_LEN]; + int save_last; + + /* Line data storage used in preproc_input(). */ + char *line, *linepos; + size_t lineleft; + + yasm_scanner s; + enum gas_parser_state state; + + int token; /* enum tokentype or any character */ + yystype tokval; + char tokch; /* first character of token */ + + /* one token of lookahead; used sparingly */ + int peek_token; /* NONE if none */ + yystype peek_tokval; + char peek_tokch; + + /* Index of local labels; what's stored here is the /next/ index, + * so these are all 0 at start. + */ + unsigned long local[10]; + + /* Parser-handled directives HAMT lookup */ + HAMT *dirs; + + int intel_syntax; + + int is_nasm_preproc; + int is_cpp_preproc; +} yasm_parser_gas; + +/* shorter access names to commonly used parser_gas fields */ +#define p_object (parser_gas->object) +#define p_symtab (parser_gas->object->symtab) +#define cursect (parser_gas->object->cur_section) +#define curtok (parser_gas->token) +#define curval (parser_gas->tokval) + +#define INTNUM_val (curval.intn) +#define FLTNUM_val (curval.flt) +#define STRING_val (curval.str) +#define REG_val (curval.arch_data) +#define REGGROUP_val (curval.arch_data) +#define SEGREG_val (curval.arch_data) +#define TARGETMOD_val (curval.arch_data) +#define ID_val (curval.str.contents) +#define ID_len (curval.str.len) +#define LABEL_val (curval.str.contents) +#define LABEL_len (curval.str.len) + +#define cur_line (yasm_linemap_get_current(parser_gas->linemap)) + +#define p_expr_new(l,o,r) yasm_expr_create(o,l,r,cur_line) +#define p_expr_new_tree(l,o,r) yasm_expr_create_tree(l,o,r,cur_line) +#define p_expr_new_branch(o,r) yasm_expr_create_branch(o,r,cur_line) +#define p_expr_new_ident(r) yasm_expr_create_ident(r,cur_line) + +yasm_bytecode *parse_instr_intel(yasm_parser_gas *parser_gas); + +void gas_parser_parse(yasm_parser_gas *parser_gas); +void gas_parser_cleanup(yasm_parser_gas *parser_gas); +int gas_parser_lex(YYSTYPE *lvalp, yasm_parser_gas *parser_gas); + +#endif diff --git a/contrib/tools/yasm/modules/parsers/nasm/nasm-parse.c b/contrib/tools/yasm/modules/parsers/nasm/nasm-parse.c new file mode 100644 index 0000000000..44d3b5d707 --- /dev/null +++ b/contrib/tools/yasm/modules/parsers/nasm/nasm-parse.c @@ -0,0 +1,1680 @@ +/* + * NASM-compatible parser + * + * Copyright (C) 2001-2007 Peter Johnson, Michael Urman + * + * 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 <math.h> + +#include "modules/parsers/nasm/nasm-parser.h" +#include "modules/preprocs/nasm/nasm.h" + +typedef enum { + NORM_EXPR, + DIR_EXPR, /* Can't have seg:off or WRT anywhere */ + DV_EXPR /* Can't have registers anywhere */ +} expr_type; + +static yasm_bytecode *parse_line(yasm_parser_nasm *parser_nasm); +static int parse_directive_valparams(yasm_parser_nasm *parser_nasm, + /*@out@*/ yasm_valparamhead *vps); +static yasm_bytecode *parse_times(yasm_parser_nasm *parser_nasm); +static yasm_bytecode *parse_exp(yasm_parser_nasm *parser_nasm); +static yasm_bytecode *parse_instr(yasm_parser_nasm *parser_nasm); +static yasm_insn_operand *parse_operand(yasm_parser_nasm *parser_nasm); +static yasm_insn_operand *parse_memaddr(yasm_parser_nasm *parser_nasm); +static yasm_expr *parse_expr(yasm_parser_nasm *parser_nasm, expr_type type); +static yasm_expr *parse_bexpr(yasm_parser_nasm *parser_nasm, expr_type type); +static yasm_expr *parse_expr0(yasm_parser_nasm *parser_nasm, expr_type type); +static yasm_expr *parse_expr1(yasm_parser_nasm *parser_nasm, expr_type type); +static yasm_expr *parse_expr2(yasm_parser_nasm *parser_nasm, expr_type type); +static yasm_expr *parse_expr3(yasm_parser_nasm *parser_nasm, expr_type type); +static yasm_expr *parse_expr4(yasm_parser_nasm *parser_nasm, expr_type type); +static yasm_expr *parse_expr5(yasm_parser_nasm *parser_nasm, expr_type type); +static yasm_expr *parse_expr6(yasm_parser_nasm *parser_nasm, expr_type type); + +static void nasm_parser_directive + (yasm_parser_nasm *parser_nasm, const char *name, + /*@null@*/ yasm_valparamhead *valparams, + /*@null@*/ yasm_valparamhead *objext_valparams); +static void set_nonlocal_label(yasm_parser_nasm *parser_nasm, const char *name); +static void define_label(yasm_parser_nasm *parser_nasm, /*@only@*/ char *name, + unsigned int size); + +static void yasm_ea_set_implicit_size_segment(yasm_parser_nasm *parser_nasm, + yasm_effaddr *ea, yasm_expr *e) +{ + if (parser_nasm->tasm) { + const char *segment = yasm_expr_segment(e); + ea->data_len = yasm_expr_size(e); + if (segment) { + const char *segreg = tasm_get_segment_register(segment); + if (segreg) + yasm_arch_parse_check_regtmod(p_object->arch, segreg, + strlen(segreg), &ea->segreg); + } + } +} + + +#define is_eol_tok(tok) ((tok) == 0) +#define is_eol() is_eol_tok(curtok) + +#define get_next_token() (curtok = nasm_parser_lex(&curval, parser_nasm)) + +static void +get_peek_token(yasm_parser_nasm *parser_nasm) +{ + char savech = parser_nasm->tokch; + if (parser_nasm->peek_token != NONE) + yasm_internal_error(N_("only can have one token of lookahead")); + parser_nasm->peek_token = + nasm_parser_lex(&parser_nasm->peek_tokval, parser_nasm); + parser_nasm->peek_tokch = parser_nasm->tokch; + parser_nasm->tokch = savech; +} + +static void +destroy_curtok_(yasm_parser_nasm *parser_nasm) +{ + if (curtok < 256) + ; + else switch ((enum tokentype)curtok) { + case INTNUM: + yasm_intnum_destroy(curval.intn); + break; + case FLTNUM: + yasm_floatnum_destroy(curval.flt); + break; + case DIRECTIVE_NAME: + case FILENAME: + case ID: + case LOCAL_ID: + case SPECIAL_ID: + case NONLOCAL_ID: + yasm_xfree(curval.str_val); + break; + case STRING: + yasm_xfree(curval.str.contents); + break; + case INSN: + yasm_bc_destroy(curval.bc); + break; + default: + break; + } + curtok = NONE; /* sanity */ +} +#define destroy_curtok() destroy_curtok_(parser_nasm) + +/* Eat all remaining tokens to EOL, discarding all of them. If there's any + * intervening tokens, generates an error (junk at end of line). + */ +static void +demand_eol_(yasm_parser_nasm *parser_nasm) +{ + if (is_eol()) + return; + + yasm_error_set(YASM_ERROR_SYNTAX, + N_("junk at end of line, first unrecognized character is `%c'"), + parser_nasm->tokch); + + do { + destroy_curtok(); + get_next_token(); + } while (!is_eol()); +} +#define demand_eol() demand_eol_(parser_nasm) + +static const char * +describe_token(int token) +{ + static char strch[] = "` '"; + const char *str; + + switch (token) { + case 0: str = "end of line"; break; + case INTNUM: str = "integer"; break; + case FLTNUM: str = "floating point value"; break; + case DIRECTIVE_NAME: str = "directive name"; break; + case FILENAME: str = "filename"; break; + case STRING: str = "string"; break; + case SIZE_OVERRIDE: str = "size override"; break; + case DECLARE_DATA: str = "DB/DW/etc."; break; + case RESERVE_SPACE: str = "RESB/RESW/etc."; break; + case INCBIN: str = "INCBIN"; break; + case EQU: str = "EQU"; break; + case TIMES: str = "TIMES"; break; + case SEG: str = "SEG"; break; + case WRT: str = "WRT"; break; + case NOSPLIT: str = "NOSPLIT"; break; + case STRICT: str = "STRICT"; break; + case INSN: str = "instruction"; break; + case PREFIX: str = "instruction prefix"; break; + case REG: str = "register"; break; + case REGGROUP: str = "register group"; break; + case SEGREG: str = "segment register"; break; + case TARGETMOD: str = "target modifier"; break; + case LEFT_OP: str = "<<"; break; + case RIGHT_OP: str = ">>"; break; + case SIGNDIV: str = "//"; break; + case SIGNMOD: str = "%%"; break; + case START_SECTION_ID: str = "$$"; break; + case ID: str = "identifier"; break; + case LOCAL_ID: str = ".identifier"; break; + case SPECIAL_ID: str = "..identifier"; break; + case NONLOCAL_ID: str = "..@identifier"; break; + case LINE: str = "%line"; break; + default: + strch[1] = token; + str = strch; + break; + } + + return str; +} + +static int +expect_(yasm_parser_nasm *parser_nasm, int token) +{ + if (curtok == token) + return 1; + + yasm_error_set(YASM_ERROR_PARSE, "expected %s", describe_token(token)); + destroy_curtok(); + return 0; +} +#define expect(token) expect_(parser_nasm, token) + +void +nasm_parser_parse(yasm_parser_nasm *parser_nasm) +{ + unsigned char *line; + while ((line = (unsigned char *) + yasm_preproc_get_line(parser_nasm->preproc)) != NULL) { + yasm_bytecode *bc = NULL, *temp_bc; + + parser_nasm->s.bot = line; + parser_nasm->s.tok = line; + parser_nasm->s.ptr = line; + parser_nasm->s.cur = line; + parser_nasm->s.lim = line + strlen((char *)line)+1; + parser_nasm->s.top = parser_nasm->s.lim; + + get_next_token(); + if (!is_eol()) { + bc = parse_line(parser_nasm); + demand_eol(); + } + + if (parser_nasm->abspos) { + /* If we're inside an absolute section, just add to the absolute + * position rather than appending bytecodes to a section. + * Only RES* are allowed in an absolute section, so this is easy. + */ + if (bc) { + /*@null@*/ const yasm_expr *numitems, *multiple; + unsigned int itemsize; + numitems = yasm_bc_reserve_numitems(bc, &itemsize); + if (numitems) { + yasm_expr *e; + e = yasm_expr_create(YASM_EXPR_MUL, + yasm_expr_expr(yasm_expr_copy(numitems)), + yasm_expr_int(yasm_intnum_create_uint(itemsize)), + cur_line); + multiple = yasm_bc_get_multiple_expr(bc); + if (multiple) + e = yasm_expr_create_tree(e, YASM_EXPR_MUL, + yasm_expr_copy(multiple), + cur_line); + parser_nasm->abspos = yasm_expr_create_tree( + parser_nasm->abspos, YASM_EXPR_ADD, e, cur_line); + } else + yasm_error_set(YASM_ERROR_SYNTAX, + N_("only RES* allowed within absolute section")); + yasm_bc_destroy(bc); + } + temp_bc = NULL; + } else if (bc) { + temp_bc = yasm_section_bcs_append(cursect, bc); + if (temp_bc) + parser_nasm->prev_bc = temp_bc; + } else + temp_bc = NULL; + yasm_errwarn_propagate(parser_nasm->errwarns, cur_line); + + if (parser_nasm->save_input) + yasm_linemap_add_source(parser_nasm->linemap, temp_bc, + (char *)line); + yasm_linemap_goto_next(parser_nasm->linemap); + yasm_xfree(line); + } +} + +/* All parse_* functions expect to be called with curtok being their first + * token. They should return with curtok being the token *after* their + * information. + */ + +static yasm_bytecode * +parse_line(yasm_parser_nasm *parser_nasm) +{ + yasm_bytecode *bc; + + bc = parse_exp(parser_nasm); + if (bc) + return bc; + + switch (curtok) { + case LINE: /* LINE INTNUM '+' INTNUM FILENAME */ + { + yasm_intnum *line, *incr; + char *filename; + + get_next_token(); + + if (!expect(INTNUM)) return NULL; + line = INTNUM_val; + get_next_token(); + + if (!expect('+')) return NULL; + get_next_token(); + + if (!expect(INTNUM)) return NULL; + incr = INTNUM_val; + get_next_token(); + + if (!expect(FILENAME)) return NULL; + filename = FILENAME_val; + get_next_token(); + + /* %line indicates the line number of the *next* line, so subtract + * out the increment when setting the line number. + */ + yasm_linemap_set(parser_nasm->linemap, filename, 0, + yasm_intnum_get_uint(line) - yasm_intnum_get_uint(incr), + yasm_intnum_get_uint(incr)); + yasm_intnum_destroy(line); + yasm_intnum_destroy(incr); + yasm_xfree(filename); + return NULL; + } + case '[': /* [ directive ] */ + { + char *dirname; + yasm_valparamhead dir_vps; + int have_vps = 1; + + parser_nasm->state = DIRECTIVE; + get_next_token(); + + if (!expect(DIRECTIVE_NAME)) + return NULL; + dirname = DIRECTIVE_NAME_val; + get_next_token(); + + /* ignore [warning]. TODO: actually implement */ + if (yasm__strcasecmp(dirname, "warning") == 0) { + yasm_warn_set(YASM_WARN_GENERAL, + N_("[warning] directive not supported; ignored")); + + /* throw away the rest of the directive tokens */ + while (!is_eol() && curtok != ']') + { + destroy_curtok(); + get_next_token(); + } + expect(']'); + get_next_token(); + return NULL; + } + + if (curtok == ']' || curtok == ':') + have_vps = 0; + else if (!parse_directive_valparams(parser_nasm, &dir_vps)) { + yasm_error_set(YASM_ERROR_SYNTAX, + N_("invalid arguments to [%s]"), dirname); + yasm_xfree(dirname); + return NULL; + } + if (curtok == ':') { + yasm_valparamhead ext_vps; + get_next_token(); + if (!parse_directive_valparams(parser_nasm, &ext_vps)) { + yasm_error_set(YASM_ERROR_SYNTAX, + N_("invalid arguments to [%s]"), dirname); + yasm_xfree(dirname); + return NULL; + } + nasm_parser_directive(parser_nasm, dirname, + have_vps ? &dir_vps : NULL, &ext_vps); + } else + nasm_parser_directive(parser_nasm, dirname, + have_vps ? &dir_vps : NULL, NULL); + yasm_xfree(dirname); + expect(']'); + get_next_token(); + return NULL; + } + case TIMES: /* TIMES expr exp */ + get_next_token(); + return parse_times(parser_nasm); + case ID: + case SPECIAL_ID: + case NONLOCAL_ID: + case LOCAL_ID: + { + char *name = ID_val; + int local = parser_nasm->tasm + ? (curtok == ID || curtok == LOCAL_ID || + (curtok == SPECIAL_ID && name[0] == '@')) + : (curtok != ID); + unsigned int size = 0; + + get_next_token(); + if (is_eol()) { + /* label alone on the line */ + yasm_warn_set(YASM_WARN_ORPHAN_LABEL, + N_("label alone on a line without a colon might be in error")); + if (!local) + set_nonlocal_label(parser_nasm, name); + define_label(parser_nasm, name, 0); + return NULL; + } + if (curtok == ':') + get_next_token(); + + if (curtok == EQU || (parser_nasm->tasm && curtok == '=')) { + /* label EQU expr */ + yasm_expr *e; + get_next_token(); + + if (parser_nasm->tasm && curtok == SIZE_OVERRIDE) { + size = SIZE_OVERRIDE_val; + get_next_token(); + } + + e = parse_expr(parser_nasm, NORM_EXPR); + if (!e) { + yasm_error_set(YASM_ERROR_SYNTAX, + N_("expression expected after %s"), "EQU"); + yasm_xfree(name); + return NULL; + } + yasm_symtab_define_equ(p_symtab, name, e, cur_line); + yasm_xfree(name); + return NULL; + } + + if (parser_nasm->tasm && curtok == LABEL) + get_next_token(); + + if (parser_nasm->tasm && curtok == SIZE_OVERRIDE) { + size = SIZE_OVERRIDE_val; + get_next_token(); + } + + if (!local) + set_nonlocal_label(parser_nasm, name); + + if (is_eol()) { + define_label(parser_nasm, name, size); + return NULL; + } + if (curtok == TIMES) { + define_label(parser_nasm, name, size); + get_next_token(); + return parse_times(parser_nasm); + } + bc = parse_exp(parser_nasm); + if (!parser_nasm->tasm && !bc) + yasm_error_set(YASM_ERROR_SYNTAX, + N_("instruction expected after label")); + if (parser_nasm->tasm && bc && !size) + size = yasm_bc_elem_size(bc); + define_label(parser_nasm, name, size); + return bc; + } + default: + yasm_error_set(YASM_ERROR_SYNTAX, + N_("label or instruction expected at start of line")); + return NULL; + } +} + +static int +parse_directive_valparams(yasm_parser_nasm *parser_nasm, + /*@out@*/ yasm_valparamhead *vps) +{ + yasm_vps_initialize(vps); + for (;;) { + yasm_valparam *vp; + yasm_expr *e; + char *id = NULL; + + /* Look for value first */ + if (curtok == ID) { + get_peek_token(parser_nasm); + if (parser_nasm->peek_token == '=') { + id = ID_val; + get_next_token(); /* id */ + get_next_token(); /* '=' */ + } + } + + /* Look for parameter */ + switch (curtok) { + case STRING: + vp = yasm_vp_create_string(id, STRING_val.contents); + get_next_token(); + break; + case ID: + /* We need a peek token, but avoid error if we have one + * already; we need to work whether or not we hit the + * "value=" if test above. + * + * We cheat and peek ahead to see if this is just an ID or + * the ID is part of an expression. We assume a + or - means + * that it's part of an expression (e.g. "x+y" is parsed as + * the expression "x+y" and not as "x", "+y"). + */ + if (parser_nasm->peek_token == NONE) + get_peek_token(parser_nasm); + switch (parser_nasm->peek_token) { + case '|': case '^': case '&': case LEFT_OP: case RIGHT_OP: + case '+': case '-': + case '*': case '/': case '%': case SIGNDIV: case SIGNMOD: + break; + default: + /* Just an id */ + vp = yasm_vp_create_id(id, ID_val, '$'); + get_next_token(); + goto next; + } + /*@fallthrough@*/ + default: + e = parse_expr(parser_nasm, DIR_EXPR); + if (!e) { + yasm_vps_delete(vps); + return 0; + } + vp = yasm_vp_create_expr(id, e); + break; + } +next: + yasm_vps_append(vps, vp); + if (curtok == ',') + get_next_token(); + if (curtok == ']' || curtok == ':' || is_eol()) + return 1; + } +} + +static yasm_bytecode * +parse_times(yasm_parser_nasm *parser_nasm) +{ + yasm_expr *multiple; + yasm_bytecode *bc; + + multiple = parse_bexpr(parser_nasm, DV_EXPR); + if (!multiple) { + yasm_error_set(YASM_ERROR_SYNTAX, N_("expression expected after %s"), + "TIMES"); + return NULL; + } + bc = parse_exp(parser_nasm); + if (!bc) { + yasm_error_set(YASM_ERROR_SYNTAX, + N_("instruction expected after TIMES expression")); + yasm_expr_destroy(multiple); + return NULL; + } + yasm_bc_set_multiple(bc, multiple); + return bc; +} + +static yasm_bytecode * +parse_exp(yasm_parser_nasm *parser_nasm) +{ + yasm_bytecode *bc; + + bc = parse_instr(parser_nasm); + if (bc) + return bc; + + switch (curtok) { + case DECLARE_DATA: + { + unsigned int size = DECLARE_DATA_val/8; + yasm_datavalhead dvs; + yasm_dataval *dv; + yasm_expr *e, *e2; + + get_next_token(); + + yasm_dvs_initialize(&dvs); + for (;;) { + if (curtok == STRING) { + /* Peek ahead to see if we're in an expr. If we're not, + * then generate a real string dataval. + */ + get_peek_token(parser_nasm); + if (parser_nasm->peek_token == ',' + || is_eol_tok(parser_nasm->peek_token)) { + dv = yasm_dv_create_string(STRING_val.contents, + STRING_val.len); + get_next_token(); + goto dv_done; + } + } + if (curtok == '?') { + yasm_dvs_delete(&dvs); + get_next_token(); + if (! is_eol_tok(curtok)) { + yasm_error_set(YASM_ERROR_SYNTAX, + N_("can not handle more than one '?'")); + return NULL; + } + return yasm_bc_create_reserve( + p_expr_new_ident(yasm_expr_int( + yasm_intnum_create_uint(1))), + size, cur_line); + } + if (!(e = parse_bexpr(parser_nasm, DV_EXPR))) { + yasm_error_set(YASM_ERROR_SYNTAX, + N_("expression or string expected")); + yasm_dvs_delete(&dvs); + return NULL; + } + if (curtok == DUP) { + get_next_token(); + if (curtok != '(') { + yasm_error_set(YASM_ERROR_SYNTAX, + N_("expected ( after DUP")); + goto error; + } + get_next_token(); + if (curtok == '?') { + get_next_token(); + if (curtok != ')') { + yasm_error_set(YASM_ERROR_SYNTAX, + N_("expected ) after DUPlicated expression")); + goto error; + } + get_next_token(); + if (! is_eol_tok(curtok)) { + yasm_error_set(YASM_ERROR_SYNTAX, + N_("can not handle more than one '?'")); + goto error; + } + yasm_dvs_delete(&dvs); + return yasm_bc_create_reserve(e, size, cur_line); + } else if ((e2 = parse_bexpr(parser_nasm, DV_EXPR))) { + if (curtok != ')') { + yasm_expr_destroy(e2); + yasm_error_set(YASM_ERROR_SYNTAX, + N_("expected ) after DUPlicated expression")); + goto error; + } + get_next_token(); + dv = yasm_dv_create_expr(e2); + yasm_dv_set_multiple(dv, e); + } else { + yasm_error_set(YASM_ERROR_SYNTAX, + N_("expression or string expected")); +error: + yasm_expr_destroy(e); + yasm_dvs_delete(&dvs); + return NULL; + } + } else + dv = yasm_dv_create_expr(e); +dv_done: + yasm_dvs_append(&dvs, dv); + if (is_eol()) + break; + if (!expect(',')) { + yasm_dvs_delete(&dvs); + return NULL; + } + get_next_token(); + if (is_eol()) /* allow trailing , on list */ + break; + } + return yasm_bc_create_data(&dvs, size, 0, p_object->arch, + cur_line); + } + case RESERVE_SPACE: + { + unsigned int size = RESERVE_SPACE_val/8; + yasm_expr *e; + get_next_token(); + e = parse_bexpr(parser_nasm, DV_EXPR); + if (!e) { + yasm_error_set(YASM_ERROR_SYNTAX, + N_("expression expected after %s"), "RESx"); + return NULL; + } + return yasm_bc_create_reserve(e, size, cur_line); + } + case INCBIN: + { + char *filename; + yasm_expr *start = NULL, *maxlen = NULL; + + get_next_token(); + + if (!expect(STRING)) { + yasm_error_set(YASM_ERROR_SYNTAX, + N_("filename string expected after INCBIN")); + return NULL; + } + filename = STRING_val.contents; + get_next_token(); + + /* optional start expression */ + if (curtok == ',') + get_next_token(); + if (is_eol()) + goto incbin_done; + start = parse_bexpr(parser_nasm, DV_EXPR); + if (!start) { + yasm_error_set(YASM_ERROR_SYNTAX, + N_("expression expected for INCBIN start")); + return NULL; + } + + /* optional maxlen expression */ + if (curtok == ',') + get_next_token(); + if (is_eol()) + goto incbin_done; + maxlen = parse_bexpr(parser_nasm, DV_EXPR); + if (!maxlen) { + yasm_error_set(YASM_ERROR_SYNTAX, + N_("expression expected for INCBIN maximum length")); + return NULL; + } + +incbin_done: + return yasm_bc_create_incbin(filename, start, maxlen, + parser_nasm->linemap, cur_line); + } + default: + return NULL; + } +} + +static yasm_bytecode * +parse_instr(yasm_parser_nasm *parser_nasm) +{ + yasm_bytecode *bc; + + switch (curtok) { + case INSN: + { + yasm_insn *insn; + bc = INSN_val; + insn = yasm_bc_get_insn(bc); + + get_next_token(); + if (is_eol()) + return bc; /* no operands */ + + /* parse operands */ + for (;;) { + yasm_insn_operand *op = parse_operand(parser_nasm); + if (!op) { + if (insn->num_operands == 0) + yasm_error_set(YASM_ERROR_SYNTAX, + N_("unexpected %s after instruction"), + describe_token(curtok)); + else + yasm_error_set(YASM_ERROR_SYNTAX, + N_("expected operand, got %s"), + describe_token(curtok)); + yasm_bc_destroy(bc); + return NULL; + } + yasm_insn_ops_append(insn, op); + + if (is_eol()) + break; + if (!expect(',')) { + yasm_bc_destroy(bc); + return NULL; + } + get_next_token(); + } + return bc; + } + case PREFIX: + { + uintptr_t prefix = PREFIX_val; + get_next_token(); + bc = parse_instr(parser_nasm); + if (!bc) + bc = yasm_arch_create_empty_insn(p_object->arch, cur_line); + yasm_insn_add_prefix(yasm_bc_get_insn(bc), prefix); + return bc; + } + case SEGREG: + { + uintptr_t segreg = SEGREG_val; + get_next_token(); + bc = parse_instr(parser_nasm); + if (!bc) + bc = yasm_arch_create_empty_insn(p_object->arch, cur_line); + yasm_insn_add_seg_prefix(yasm_bc_get_insn(bc), segreg); + return bc; + } + default: + return NULL; + } +} + +static yasm_insn_operand * +parse_operand(yasm_parser_nasm *parser_nasm) +{ + yasm_insn_operand *op; + switch (curtok) { + case '[': + { + get_next_token(); + op = parse_memaddr(parser_nasm); + + expect(']'); + get_next_token(); + + if (!op) { + yasm_error_set(YASM_ERROR_SYNTAX, + N_("memory address expected")); + return NULL; + } + + if (parser_nasm->tasm && !is_eol() && curtok != ',') { + yasm_expr *e = NULL, *f; + yasm_effaddr *ea; + + switch (op->type) { + case YASM_INSN__OPERAND_IMM: + e = op->data.val; + break; + case YASM_INSN__OPERAND_MEMORY: + if (op->data.ea->disp.rel) { + yasm_error_set(YASM_ERROR_SYNTAX, + N_("relative adressing not supported\n")); + return NULL; + } + e = yasm_expr_copy(op->data.ea->disp.abs); + yasm_arch_ea_destroy(p_object->arch, op->data.ea); + break; + case YASM_INSN__OPERAND_REG: + case YASM_INSN__OPERAND_SEGREG: + yasm_error_set(YASM_ERROR_SYNTAX, + N_("register adressing not supported\n")); + return NULL; + } + yasm_xfree(op); + f = parse_bexpr(parser_nasm, NORM_EXPR); + if (!f) { + yasm_expr_destroy(e); + yasm_error_set(YASM_ERROR_SYNTAX, + N_("expected expression after ]")); + return NULL; + } + e = p_expr_new_tree(e, YASM_EXPR_ADD, f); + ea = yasm_arch_ea_create(p_object->arch, e); + yasm_ea_set_implicit_size_segment(parser_nasm, ea, e); + op = yasm_operand_create_mem(ea); + } + return op; + } + case OFFSET: + { + yasm_insn_operand *op2; + get_next_token(); + if (parser_nasm->masm && curtok == ID && !yasm__strcasecmp(ID_val, "flat")) { + get_next_token(); + if (curtok == ':') { + get_next_token(); + } + } + op = parse_operand(parser_nasm); + if (!op) { + yasm_error_set(YASM_ERROR_SYNTAX, + N_("memory address expected")); + return NULL; + } + if (op->type == YASM_INSN__OPERAND_IMM) + return op; + if (op->type != YASM_INSN__OPERAND_MEMORY) { + yasm_error_set(YASM_ERROR_SYNTAX, + N_("OFFSET applied to non-memory operand")); + return NULL; + } + if (op->data.ea->disp.rel) { + yasm_error_set(YASM_ERROR_SYNTAX, + N_("OFFSET applied to non-absolute memory operand")); + return NULL; + } + if (op->data.ea->disp.abs) + op2 = yasm_operand_create_imm(op->data.ea->disp.abs); + else + op2 = yasm_operand_create_imm(p_expr_new_ident( + yasm_expr_int(yasm_intnum_create_uint(0)))); + yasm_xfree(op); + return op2; + } + case SEGREG: + { + uintptr_t segreg = SEGREG_val; + get_next_token(); + if (parser_nasm->tasm && curtok == ':') { + get_next_token(); + op = parse_operand(parser_nasm); + if (!op) + return NULL; + if (op->type == YASM_INSN__OPERAND_IMM) { + yasm_effaddr *ea = yasm_arch_ea_create(p_object->arch, + op->data.val); + yasm_insn_operand *op2; + yasm_ea_set_implicit_size_segment(parser_nasm, ea, + op->data.val); + op2 = yasm_operand_create_mem(ea); + op2->size = op->size; + yasm_xfree(op); + op = op2; + } + if (op->type != YASM_INSN__OPERAND_MEMORY) { + yasm_error_set(YASM_ERROR_SYNTAX, + N_("segment applied to non-memory operand")); + return NULL; + } + yasm_ea_set_segreg(op->data.ea, segreg); + return op; + } + op = yasm_operand_create_segreg(segreg); + return op; + } + case REG: + op = yasm_operand_create_reg(REG_val); + get_next_token(); + return op; + case REGGROUP: + { + unsigned long regindex; + uintptr_t reg = REGGROUP_val; + get_next_token(); /* REGGROUP */ + if (curtok != '(') + return yasm_operand_create_reg(reg); + get_next_token(); /* '(' */ + if (!expect(INTNUM)) { + yasm_error_set(YASM_ERROR_SYNTAX, + N_("integer register index expected")); + return NULL; + } + regindex = yasm_intnum_get_uint(INTNUM_val); + get_next_token(); /* INTNUM */ + if (!expect(')')) { + yasm_error_set(YASM_ERROR_SYNTAX, + N_("missing closing parenthesis for register index")); + return NULL; + } + get_next_token(); /* ')' */ + reg = yasm_arch_reggroup_get_reg(p_object->arch, reg, regindex); + if (reg == 0) { + yasm_error_set(YASM_ERROR_SYNTAX, N_("bad register index `%u'"), + regindex); + return NULL; + } + return yasm_operand_create_reg(reg); + } + case STRICT: + get_next_token(); + op = parse_operand(parser_nasm); + if (op) + op->strict = 1; + return op; + case SIZE_OVERRIDE: + { + unsigned int size = SIZE_OVERRIDE_val; + get_next_token(); + if (parser_nasm->masm && curtok == ID && !yasm__strcasecmp(ID_val, "ptr")) { + get_next_token(); + } + op = parse_operand(parser_nasm); + if (!op) + return NULL; + if (op->type == YASM_INSN__OPERAND_REG && + yasm_arch_get_reg_size(p_object->arch, op->data.reg) != size) + yasm_error_set(YASM_ERROR_TYPE, + N_("cannot override register size")); + else { + /* Silently override others unless a warning is turned on. + * This is to allow overrides such as: + * %define arg1 dword [bp+4] + * cmp word arg1, 2 + * Which expands to: + * cmp word dword [bp+4], 2 + */ + if (op->size != 0) { + if (op->size != size) + yasm_warn_set(YASM_WARN_SIZE_OVERRIDE, + N_("overriding operand size from %u-bit to %u-bit"), + op->size, size); + else + yasm_warn_set(YASM_WARN_SIZE_OVERRIDE, + N_("double operand size override")); + } + op->size = size; + } + return op; + } + case TARGETMOD: + { + uintptr_t tmod = TARGETMOD_val; + get_next_token(); + op = parse_operand(parser_nasm); + if (op) + op->targetmod = tmod; + return op; + } + case ID: + case LOCAL_ID: + case NONLOCAL_ID: + if (parser_nasm->tasm) { + get_peek_token(parser_nasm); + if (parser_nasm->peek_token == '[') { + yasm_symrec *sym = yasm_symtab_use(p_symtab, ID_val, + cur_line); + yasm_expr *e = p_expr_new_ident(yasm_expr_sym(sym)), *f; + yasm_effaddr *ea; + yasm_xfree(ID_val); + get_next_token(); + get_next_token(); + f = parse_bexpr(parser_nasm, NORM_EXPR); + if (!f) { + yasm_error_set(YASM_ERROR_SYNTAX, + N_("expected expression after [")); + return NULL; + } + e = p_expr_new_tree(e, YASM_EXPR_ADD, f); + if (!expect(']')) { + yasm_error_set(YASM_ERROR_SYNTAX, N_("missing closing bracket")); + return NULL; + } + get_next_token(); + ea = yasm_arch_ea_create(p_object->arch, e); + yasm_ea_set_implicit_size_segment(parser_nasm, ea, e); + op = yasm_operand_create_mem(ea); + return op; + } + } + /* Fallthrough */ + default: + { + yasm_expr *e = parse_bexpr(parser_nasm, NORM_EXPR); + if (!e) + return NULL; + if (curtok != ':') { + if (parser_nasm->tasm && yasm_expr_size(e)) { + yasm_effaddr *ea = yasm_arch_ea_create(p_object->arch, e); + yasm_ea_set_implicit_size_segment(parser_nasm, ea, e); + op = yasm_operand_create_mem(ea); + return op; + } else if (curtok == '[') { + yasm_expr *f; + yasm_effaddr *ea; + yasm_insn_operand *op2; + + op = parse_operand(parser_nasm); + if (!op) + return NULL; + + f = op->data.ea->disp.abs; + e = p_expr_new_tree(e, YASM_EXPR_ADD, f); + ea = yasm_arch_ea_create(p_object->arch, e); + yasm_ea_set_implicit_size_segment(parser_nasm, ea, e); + op2 = yasm_operand_create_mem(ea); + + yasm_xfree(op); + + return op2; + } else { + return yasm_operand_create_imm(e); + } + } else { + yasm_expr *off; + get_next_token(); + off = parse_bexpr(parser_nasm, NORM_EXPR); + if (!off) { + yasm_expr_destroy(e); + return NULL; + } + op = yasm_operand_create_imm(off); + op->seg = e; + return op; + } + } + } +} + +/* memory addresses */ +static yasm_insn_operand * +parse_memaddr(yasm_parser_nasm *parser_nasm) +{ + yasm_insn_operand *op; + switch (curtok) { + case SEGREG: + { + uintptr_t segreg = SEGREG_val; + get_next_token(); + if (!expect(':')) { + yasm_error_set(YASM_ERROR_SYNTAX, + N_("`:' required after segment register")); + return NULL; + } + get_next_token(); + op = parse_memaddr(parser_nasm); + if (op) + yasm_ea_set_segreg(op->data.ea, segreg); + return op; + } + case SIZE_OVERRIDE: + { + unsigned int size = SIZE_OVERRIDE_val; + get_next_token(); + op = parse_memaddr(parser_nasm); + if (op) + op->data.ea->disp.size = size; + return op; + } + case NOSPLIT: + get_next_token(); + op = parse_memaddr(parser_nasm); + if (op) + op->data.ea->nosplit = 1; + return op; + case REL: + get_next_token(); + op = parse_memaddr(parser_nasm); + if (op) { + op->data.ea->pc_rel = 1; + op->data.ea->not_pc_rel = 0; + } + return op; + case ABS: + get_next_token(); + op = parse_memaddr(parser_nasm); + if (op) { + op->data.ea->pc_rel = 0; + op->data.ea->not_pc_rel = 1; + } + return op; + default: + { + yasm_expr *e = parse_bexpr(parser_nasm, NORM_EXPR); + if (!e) + return NULL; + if (curtok != ':') { + yasm_effaddr *ea = yasm_arch_ea_create(p_object->arch, e); + yasm_ea_set_implicit_size_segment(parser_nasm, ea, e); + return yasm_operand_create_mem(ea); + } else { + yasm_effaddr *ea; + yasm_expr *off; + get_next_token(); + off = parse_bexpr(parser_nasm, NORM_EXPR); + if (!off) { + yasm_expr_destroy(e); + return NULL; + } + ea = yasm_arch_ea_create(p_object->arch, off); + yasm_ea_set_implicit_size_segment(parser_nasm, ea, off); + op = yasm_operand_create_mem(ea); + op->seg = e; + return op; + } + } + } +} + +/* Expression grammar parsed is: + * + * expr : bexpr [ : bexpr ] + * bexpr : expr0 [ WRT expr6 ] + * expr0 : expr1 [ {|} expr1...] + * expr1 : expr2 [ {^} expr2...] + * expr2 : expr3 [ {&} expr3...] + * expr3 : expr4 [ {<<,>>} expr4...] + * expr4 : expr5 [ {+,-} expr5...] + * expr5 : expr6 [ {*,/,%,//,%%} expr6...] + * expr6 : { ~,+,-,SEG } expr6 + * | (expr) + * | symbol + * | $ + * | number + */ + +#define parse_expr_common(leftfunc, tok, rightfunc, op) \ + do { \ + yasm_expr *e, *f; \ + e = leftfunc(parser_nasm, type); \ + if (!e) \ + return NULL; \ + \ + while (curtok == tok) { \ + get_next_token(); \ + f = rightfunc(parser_nasm, type); \ + if (!f) { \ + yasm_error_set(YASM_ERROR_SYNTAX, \ + N_("expected expression after %s"), \ + describe_token(op)); \ + yasm_expr_destroy(e); \ + return NULL; \ + } \ + e = p_expr_new_tree(e, op, f); \ + } \ + return e; \ + } while(0) + +static yasm_expr * +parse_expr(yasm_parser_nasm *parser_nasm, expr_type type) +{ + switch (type) { + case DIR_EXPR: + /* directive expressions can't handle seg:off or WRT */ + return parse_expr0(parser_nasm, type); + default: + parse_expr_common(parse_bexpr, ':', parse_bexpr, YASM_EXPR_SEGOFF); + } + /*@notreached@*/ + return NULL; +} + +static yasm_expr * +parse_bexpr(yasm_parser_nasm *parser_nasm, expr_type type) +{ + parse_expr_common(parse_expr0, WRT, parse_expr6, YASM_EXPR_WRT); +} + +static yasm_expr * +parse_expr0(yasm_parser_nasm *parser_nasm, expr_type type) +{ + parse_expr_common(parse_expr1, '|', parse_expr1, YASM_EXPR_OR); +} + +static yasm_expr * +parse_expr1(yasm_parser_nasm *parser_nasm, expr_type type) +{ + parse_expr_common(parse_expr2, '^', parse_expr2, YASM_EXPR_XOR); +} + +static yasm_expr * +parse_expr2(yasm_parser_nasm *parser_nasm, expr_type type) +{ + parse_expr_common(parse_expr3, '&', parse_expr3, YASM_EXPR_AND); +} + +static yasm_expr * +parse_expr3(yasm_parser_nasm *parser_nasm, expr_type type) +{ + yasm_expr *e, *f; + e = parse_expr4(parser_nasm, type); + if (!e) + return NULL; + + while (curtok == LEFT_OP || curtok == RIGHT_OP) { + int op = curtok; + get_next_token(); + f = parse_expr4(parser_nasm, type); + if (!f) { + yasm_error_set(YASM_ERROR_SYNTAX, + N_("expected expression after %s"), + describe_token(op)); + yasm_expr_destroy(e); + return NULL; + } + + switch (op) { + case LEFT_OP: e = p_expr_new_tree(e, YASM_EXPR_SHL, f); break; + case RIGHT_OP: e = p_expr_new_tree(e, YASM_EXPR_SHR, f); break; + } + } + return e; +} + +static yasm_expr * +parse_expr4(yasm_parser_nasm *parser_nasm, expr_type type) +{ + yasm_expr *e, *f; + e = parse_expr5(parser_nasm, type); + if (!e) + return NULL; + + while (curtok == '+' || curtok == '-') { + int op = curtok; + get_next_token(); + f = parse_expr5(parser_nasm, type); + if (!f) { + yasm_error_set(YASM_ERROR_SYNTAX, + N_("expected expression after %s"), + describe_token(op)); + yasm_expr_destroy(e); + return NULL; + } + + switch (op) { + case '+': e = p_expr_new_tree(e, YASM_EXPR_ADD, f); break; + case '-': e = p_expr_new_tree(e, YASM_EXPR_SUB, f); break; + } + } + return e; +} + +static yasm_expr * +parse_expr5(yasm_parser_nasm *parser_nasm, expr_type type) +{ + yasm_expr *e, *f; + e = parse_expr6(parser_nasm, type); + if (!e) + return NULL; + + while (curtok == '*' || curtok == '/' || curtok == '%' + || curtok == SIGNDIV || curtok == SIGNMOD) { + int op = curtok; + get_next_token(); + f = parse_expr6(parser_nasm, type); + if (!f) { + yasm_error_set(YASM_ERROR_SYNTAX, + N_("expected expression after %s"), + describe_token(op)); + yasm_expr_destroy(e); + return NULL; + } + + switch (op) { + case '*': e = p_expr_new_tree(e, YASM_EXPR_MUL, f); break; + case '/': e = p_expr_new_tree(e, YASM_EXPR_DIV, f); break; + case '%': e = p_expr_new_tree(e, YASM_EXPR_MOD, f); break; + case SIGNDIV: e = p_expr_new_tree(e, YASM_EXPR_SIGNDIV, f); break; + case SIGNMOD: e = p_expr_new_tree(e, YASM_EXPR_SIGNMOD, f); break; + } + } + return e; +} + +static yasm_expr * +parse_expr6(yasm_parser_nasm *parser_nasm, expr_type type) +{ + yasm_expr *e; + yasm_symrec *sym; + + switch (curtok) { + case '+': + get_next_token(); + e = parse_expr6(parser_nasm, type); + if (!e) { + yasm_error_set(YASM_ERROR_SYNTAX, + N_("expected expression after %s"), "`+'"); + } + return e; + case '-': + get_next_token(); + e = parse_expr6(parser_nasm, type); + if (!e) { + yasm_error_set(YASM_ERROR_SYNTAX, + N_("expected expression after %s"), "`-'"); + return NULL; + } + return p_expr_new_branch(YASM_EXPR_NEG, e); + case '~': + get_next_token(); + e = parse_expr6(parser_nasm, type); + if (!e) { + yasm_error_set(YASM_ERROR_SYNTAX, + N_("expected expression after %s"), "`~'"); + return NULL; + } + return p_expr_new_branch(YASM_EXPR_NOT, e); + case LOW: + get_next_token(); + e = parse_expr6(parser_nasm, type); + if (!e) { + yasm_error_set(YASM_ERROR_SYNTAX, + N_("expected expression after %s"), "LOW"); + return NULL; + } + return p_expr_new_tree(e, YASM_EXPR_AND, + p_expr_new_ident(yasm_expr_int(yasm_intnum_create_uint(0xff)))); + case HIGH: + get_next_token(); + e = parse_expr6(parser_nasm, type); + if (!e) { + yasm_error_set(YASM_ERROR_SYNTAX, + N_("expected expression after %s"), "HIGH"); + return NULL; + } + return p_expr_new_tree( + p_expr_new_tree(e, YASM_EXPR_SHR, + p_expr_new_ident(yasm_expr_int( + yasm_intnum_create_uint(8)))), + YASM_EXPR_AND, + p_expr_new_ident(yasm_expr_int(yasm_intnum_create_uint(0xff)))); + case SEG: + get_next_token(); + e = parse_expr6(parser_nasm, type); + if (!e) { + yasm_error_set(YASM_ERROR_SYNTAX, + N_("expected expression after %s"), "SEG"); + return NULL; + } + return p_expr_new_branch(YASM_EXPR_SEG, e); + case '(': + get_next_token(); + e = parse_expr(parser_nasm, type); + if (!e) { + yasm_error_set(YASM_ERROR_SYNTAX, + N_("expected expression after %s"), "`('"); + return NULL; + } + if (!expect(')')) { + yasm_error_set(YASM_ERROR_SYNTAX, N_("missing parenthesis")); + return NULL; + } + get_next_token(); + return e; + case INTNUM: + e = p_expr_new_ident(yasm_expr_int(INTNUM_val)); + get_next_token(); + return e; + case REG: + if (type == DV_EXPR) { + yasm_error_set(YASM_ERROR_SYNTAX, + N_("data values can't have registers")); + return NULL; + } + e = p_expr_new_ident(yasm_expr_reg(REG_val)); + get_next_token(); + return e; + } + + /* directives allow very little and handle IDs specially */ + if (type == DIR_EXPR) { + switch (curtok) { + case ID: + sym = yasm_symtab_use(p_symtab, ID_val, cur_line); + e = p_expr_new_ident(yasm_expr_sym(sym)); + yasm_xfree(ID_val); + break; + default: + return NULL; + } + } else switch (curtok) { + case FLTNUM: + e = p_expr_new_ident(yasm_expr_float(FLTNUM_val)); + break; + case STRING: + { + yasm_intnum *intn; + if (parser_nasm->tasm) + intn = yasm_intnum_create_charconst_tasm(STRING_val.contents); + else + intn = yasm_intnum_create_charconst_nasm(STRING_val.contents); + e = p_expr_new_ident(yasm_expr_int(intn)); + yasm_xfree(STRING_val.contents); + break; + } + case SPECIAL_ID: + sym = yasm_objfmt_get_special_sym(p_object, ID_val+2, "nasm"); + if (sym) { + e = p_expr_new_ident(yasm_expr_sym(sym)); + yasm_xfree(ID_val); + break; + } + /*@fallthrough@*/ + case ID: + case LOCAL_ID: + case NONLOCAL_ID: + sym = yasm_symtab_use(p_symtab, ID_val, cur_line); + e = p_expr_new_ident(yasm_expr_sym(sym)); + yasm_xfree(ID_val); + break; + case '$': + /* "$" references the current assembly position */ + if (parser_nasm->abspos) + e = yasm_expr_copy(parser_nasm->abspos); + else { + sym = yasm_symtab_define_curpos(p_symtab, "$", + parser_nasm->prev_bc, cur_line); + e = p_expr_new_ident(yasm_expr_sym(sym)); + } + break; + case START_SECTION_ID: + /* "$$" references the start of the current section */ + if (parser_nasm->absstart) + e = yasm_expr_copy(parser_nasm->absstart); + else { + sym = yasm_symtab_define_label(p_symtab, "$$", + yasm_section_bcs_first(cursect), 0, cur_line); + e = p_expr_new_ident(yasm_expr_sym(sym)); + } + break; + default: + return NULL; + } + + get_next_token(); + return e; +} + +static void +set_nonlocal_label(yasm_parser_nasm *parser_nasm, const char *name) +{ + if (!parser_nasm->tasm || tasm_locals) { + if (parser_nasm->locallabel_base) + yasm_xfree(parser_nasm->locallabel_base); + parser_nasm->locallabel_base_len = strlen(name); + parser_nasm->locallabel_base = + yasm_xmalloc(parser_nasm->locallabel_base_len+1); + strcpy(parser_nasm->locallabel_base, name); + } +} + +static void +define_label(yasm_parser_nasm *parser_nasm, char *name, unsigned int size) +{ + yasm_symrec *symrec; + + if (parser_nasm->abspos) + symrec = yasm_symtab_define_equ(p_symtab, name, + yasm_expr_copy(parser_nasm->abspos), + cur_line); + else + symrec = yasm_symtab_define_label(p_symtab, name, parser_nasm->prev_bc, + 1, cur_line); + + yasm_symrec_set_size(symrec, size); + yasm_symrec_set_segment(symrec, tasm_segment); + + yasm_xfree(name); +} + +static void +dir_align(yasm_object *object, yasm_valparamhead *valparams, + yasm_valparamhead *objext_valparams, unsigned long line) +{ + yasm_valparam *vp = yasm_vps_first(valparams); + yasm_expr *boundval = yasm_vp_expr(vp, object->symtab, line); + /*@depedent@*/ yasm_intnum *boundintn; + + /* Largest .align in the section specifies section alignment. + * Note: this doesn't match NASM behavior, but is a lot more + * intelligent! + */ + if (boundval && (boundintn = yasm_expr_get_intnum(&boundval, 0))) { + unsigned long boundint = yasm_intnum_get_uint(boundintn); + + /* Alignments must be a power of two. */ + if (is_exp2(boundint)) { + if (boundint > yasm_section_get_align(object->cur_section)) + yasm_section_set_align(object->cur_section, boundint, line); + } + } + + /* As this directive is called only when nop is used as fill, always + * use arch (nop) fill. + */ + yasm_section_bcs_append(object->cur_section, + yasm_bc_create_align(boundval, NULL, NULL, + /*yasm_section_is_code(object->cur_section) ?*/ + yasm_arch_get_fill(object->arch)/* : NULL*/, + line)); +} + +static void +nasm_parser_directive(yasm_parser_nasm *parser_nasm, const char *name, + yasm_valparamhead *valparams, + yasm_valparamhead *objext_valparams) +{ + unsigned long line = cur_line; + yasm_valparam *vp; + + if (!yasm_object_directive(p_object, name, "nasm", valparams, + objext_valparams, line)) + ; + else if (yasm__strcasecmp(name, "absolute") == 0) { + if (!valparams) { + yasm_error_set(YASM_ERROR_SYNTAX, + N_("directive `%s' requires an argument"), + "absolute"); + } else { + vp = yasm_vps_first(valparams); + if (parser_nasm->absstart) + yasm_expr_destroy(parser_nasm->absstart); + if (parser_nasm->abspos) + yasm_expr_destroy(parser_nasm->abspos); + parser_nasm->absstart = yasm_vp_expr(vp, p_object->symtab, line); + parser_nasm->abspos = yasm_expr_copy(parser_nasm->absstart); + cursect = NULL; + parser_nasm->prev_bc = NULL; + } + } else if (yasm__strcasecmp(name, "align") == 0) { + /* Really, we shouldn't end up with an align directive in an absolute + * section (as it's supposed to be only used for nop fill), but handle + * it gracefully anyway. + */ + if (parser_nasm->abspos) { + yasm_expr *boundval, *e; + vp = yasm_vps_first(valparams); + boundval = yasm_vp_expr(vp, p_object->symtab, line); + e = yasm_expr_create_tree( + yasm_expr_create_tree(yasm_expr_copy(parser_nasm->absstart), + YASM_EXPR_SUB, + yasm_expr_copy(parser_nasm->abspos), + cur_line), + YASM_EXPR_AND, + yasm_expr_create(YASM_EXPR_SUB, yasm_expr_expr(boundval), + yasm_expr_int(yasm_intnum_create_uint(1)), + cur_line), + cur_line); + parser_nasm->abspos = yasm_expr_create_tree( + parser_nasm->abspos, YASM_EXPR_ADD, e, cur_line); + } else if (!valparams) { + yasm_error_set(YASM_ERROR_SYNTAX, + N_("directive `%s' requires an argument"), "align"); + } else + dir_align(p_object, valparams, objext_valparams, line); + } else if (yasm__strcasecmp(name, "default") == 0) { + if (!valparams) + ; + else { + vp = yasm_vps_first(valparams); + while (vp) { + const char *id = yasm_vp_id(vp); + if (id) { + if (yasm__strcasecmp(id, "rel") == 0) + yasm_arch_set_var(p_object->arch, "default_rel", 1); + else if (yasm__strcasecmp(id, "abs") == 0) + yasm_arch_set_var(p_object->arch, "default_rel", 0); + else + yasm_error_set(YASM_ERROR_SYNTAX, + N_("unrecognized default `%s'"), id); + } else + yasm_error_set(YASM_ERROR_SYNTAX, + N_("unrecognized default value")); + vp = yasm_vps_next(vp); + } + } + } else + yasm_error_set(YASM_ERROR_SYNTAX, N_("unrecognized directive `%s'"), + name); + + if (parser_nasm->absstart && cursect) { + /* We switched to a new section. Get out of absolute section mode. */ + yasm_expr_destroy(parser_nasm->absstart); + parser_nasm->absstart = NULL; + if (parser_nasm->abspos) { + yasm_expr_destroy(parser_nasm->abspos); + parser_nasm->abspos = NULL; + } + } + + if (cursect) { + /* In case cursect changed or a bytecode was added, update prev_bc. */ + parser_nasm->prev_bc = yasm_section_bcs_last(cursect); + } + + if (valparams) + yasm_vps_delete(valparams); + if (objext_valparams) + yasm_vps_delete(objext_valparams); +} + +yasm_bytecode * +gas_intel_syntax_parse_instr(yasm_parser_nasm *parser_nasm, unsigned char *instr) +{ + yasm_bytecode *bc = NULL; + char *sinstr = (char *) instr; + + parser_nasm->s.bot = instr; + parser_nasm->s.tok = instr; + parser_nasm->s.ptr = instr; + parser_nasm->s.cur = instr; + parser_nasm->s.lim = instr + strlen(sinstr) + 1; + parser_nasm->s.top = parser_nasm->s.lim; + parser_nasm->peek_token = NONE; + + get_next_token(); + if (!is_eol()) { + bc = parse_instr(parser_nasm); + } + + return bc; +} diff --git a/contrib/tools/yasm/modules/parsers/nasm/nasm-parser-struct.h b/contrib/tools/yasm/modules/parsers/nasm/nasm-parser-struct.h new file mode 100644 index 0000000000..b9223510ba --- /dev/null +++ b/contrib/tools/yasm/modules/parsers/nasm/nasm-parser-struct.h @@ -0,0 +1,85 @@ +/* + * NASM-compatible parser struct header file + * + * 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. + */ +#ifndef YASM_NASM_PARSER_STRUCT_H +#define YASM_NASM_PARSER_STRUCT_H + +typedef union { + unsigned int int_info; + char *str_val; + yasm_intnum *intn; + yasm_floatnum *flt; + yasm_bytecode *bc; + uintptr_t arch_data; + struct { + char *contents; + size_t len; + } str; +} nasm_yystype; + +typedef struct yasm_parser_nasm { + int tasm; + int masm; + + /*@only@*/ yasm_object *object; + + /* last "base" label for local (.) labels */ + /*@null@*/ char *locallabel_base; + size_t locallabel_base_len; + + /*@dependent@*/ yasm_preproc *preproc; + /*@dependent@*/ yasm_errwarns *errwarns; + + /*@dependent@*/ yasm_linemap *linemap; + + /*@null@*/ yasm_bytecode *prev_bc; + + int save_input; + + yasm_scanner s; + int state; + + int token; /* enum tokentype or any character */ + nasm_yystype tokval; + char tokch; /* first character of token */ + + /* one token of lookahead; used sparingly */ + int peek_token; /* NONE if none */ + nasm_yystype peek_tokval; + char peek_tokch; + + /* Starting point of the absolute section. NULL if not in an absolute + * section. + */ + /*@null@*/ yasm_expr *absstart; + + /* Current location inside an absolute section (including the start). + * NULL if not in an absolute section. + */ + /*@null@*/ yasm_expr *abspos; +} yasm_parser_nasm; + +#endif diff --git a/contrib/tools/yasm/modules/parsers/nasm/nasm-parser.c b/contrib/tools/yasm/modules/parsers/nasm/nasm-parser.c new file mode 100644 index 0000000000..bd166929f7 --- /dev/null +++ b/contrib/tools/yasm/modules/parsers/nasm/nasm-parser.c @@ -0,0 +1,140 @@ +/* + * NASM-compatible parser + * + * 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 "nasm-parser.h" + + +static void +nasm_do_parse(yasm_object *object, yasm_preproc *pp, int save_input, + yasm_linemap *linemap, yasm_errwarns *errwarns, int tasm) +{ + yasm_parser_nasm parser_nasm; + + parser_nasm.tasm = tasm; + parser_nasm.masm = 0; + + parser_nasm.object = object; + parser_nasm.linemap = linemap; + + parser_nasm.locallabel_base = (char *)NULL; + parser_nasm.locallabel_base_len = 0; + + parser_nasm.preproc = pp; + parser_nasm.errwarns = errwarns; + + parser_nasm.prev_bc = yasm_section_bcs_first(object->cur_section); + + parser_nasm.save_input = save_input; + + parser_nasm.peek_token = NONE; + + parser_nasm.absstart = NULL; + parser_nasm.abspos = NULL; + + /* initialize scanner structure */ + yasm_scanner_initialize(&parser_nasm.s); + + parser_nasm.state = INITIAL; + + nasm_parser_parse(&parser_nasm); + + /*yasm_scanner_delete(&parser_nasm.s);*/ + + /* Free locallabel base if necessary */ + if (parser_nasm.locallabel_base) + yasm_xfree(parser_nasm.locallabel_base); + + /* Check for undefined symbols */ + yasm_symtab_parser_finalize(object->symtab, 0, errwarns); +} + +static void +nasm_parser_do_parse(yasm_object *object, yasm_preproc *pp, + int save_input, yasm_linemap *linemap, + yasm_errwarns *errwarns) +{ + nasm_do_parse(object, pp, save_input, linemap, errwarns, 0); +} + +#include "nasm-macros.c" + +/* Define valid preprocessors to use with this parser */ +static const char *nasm_parser_preproc_keywords[] = { + "raw", + "nasm", + NULL +}; + +static const yasm_stdmac nasm_parser_stdmacs[] = { + { "nasm", "nasm", nasm_standard_mac }, + { NULL, NULL, NULL } +}; + +/* Define parser structure -- see parser.h for details */ +yasm_parser_module yasm_nasm_LTX_parser = { + "NASM-compatible parser", + "nasm", + nasm_parser_preproc_keywords, + "nasm", + nasm_parser_stdmacs, + nasm_parser_do_parse +}; + +static void +tasm_parser_do_parse(yasm_object *object, yasm_preproc *pp, + int save_input, yasm_linemap *linemap, + yasm_errwarns *errwarns) +{ + yasm_symtab_set_case_sensitive(object->symtab, 0); + yasm_warn_disable(YASM_WARN_IMPLICIT_SIZE_OVERRIDE); + nasm_do_parse(object, pp, save_input, linemap, errwarns, 1); +} + +/* Define valid preprocessors to use with this parser */ +static const char *tasm_parser_preproc_keywords[] = { + "raw", + "tasm", + NULL +}; + +static const yasm_stdmac tasm_parser_stdmacs[] = { + { "tasm", "tasm", nasm_standard_mac }, + { NULL, NULL, NULL } +}; + +/* Define parser structure -- see parser.h for details */ +yasm_parser_module yasm_tasm_LTX_parser = { + "TASM-compatible parser", + "tasm", + tasm_parser_preproc_keywords, + "tasm", + tasm_parser_stdmacs, + tasm_parser_do_parse +}; diff --git a/contrib/tools/yasm/modules/parsers/nasm/nasm-parser.h b/contrib/tools/yasm/modules/parsers/nasm/nasm-parser.h new file mode 100644 index 0000000000..dc19cfb5e0 --- /dev/null +++ b/contrib/tools/yasm/modules/parsers/nasm/nasm-parser.h @@ -0,0 +1,123 @@ +/* + * NASM-compatible parser header file + * + * 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. + */ +#ifndef YASM_NASM_PARSER_H +#define YASM_NASM_PARSER_H + +#include "nasm-parser-struct.h" + +#define YYCTYPE unsigned char + +#define MAX_SAVED_LINE_LEN 80 + +enum tokentype { + INTNUM = 258, + FLTNUM, + DIRECTIVE_NAME, + FILENAME, + STRING, + SIZE_OVERRIDE, + OFFSET, + DECLARE_DATA, + RESERVE_SPACE, + LABEL, + INCBIN, + EQU, + TIMES, + DUP, + SEG, + WRT, + ABS, + REL, + NOSPLIT, + STRICT, + INSN, + PREFIX, + REG, + REGGROUP, + SEGREG, + TARGETMOD, + LEFT_OP, + RIGHT_OP, + LOW, + HIGH, + SIGNDIV, + SIGNMOD, + START_SECTION_ID, + ID, + LOCAL_ID, + SPECIAL_ID, + NONLOCAL_ID, + LINE, + NONE /* special token for lookahead */ +}; + +enum nasm_parser_state { + INITIAL, + DIRECTIVE, + SECTION_DIRECTIVE, + DIRECTIVE2, + LINECHG, + LINECHG2, + INSTRUCTION +}; + +#define YYSTYPE nasm_yystype + +/* shorter access names to commonly used parser_nasm fields */ +#define p_object (parser_nasm->object) +#define p_symtab (parser_nasm->object->symtab) +#define cursect (parser_nasm->object->cur_section) +#define curtok (parser_nasm->token) +#define curval (parser_nasm->tokval) + +#define INTNUM_val (curval.intn) +#define FLTNUM_val (curval.flt) +#define DIRECTIVE_NAME_val (curval.str_val) +#define FILENAME_val (curval.str_val) +#define STRING_val (curval.str) +#define SIZE_OVERRIDE_val (curval.int_info) +#define DECLARE_DATA_val (curval.int_info) +#define RESERVE_SPACE_val (curval.int_info) +#define INSN_val (curval.bc) +#define PREFIX_val (curval.arch_data) +#define REG_val (curval.arch_data) +#define REGGROUP_val (curval.arch_data) +#define SEGREG_val (curval.arch_data) +#define TARGETMOD_val (curval.arch_data) +#define ID_val (curval.str_val) + +#define cur_line (yasm_linemap_get_current(parser_nasm->linemap)) + +#define p_expr_new_tree(l,o,r) yasm_expr_create_tree(l,o,r,cur_line) +#define p_expr_new_branch(o,r) yasm_expr_create_branch(o,r,cur_line) +#define p_expr_new_ident(r) yasm_expr_create_ident(r,cur_line) + +void nasm_parser_parse(yasm_parser_nasm *parser_nasm); +void nasm_parser_cleanup(yasm_parser_nasm *parser_nasm); +int nasm_parser_lex(YYSTYPE *lvalp, yasm_parser_nasm *parser_nasm); + +#endif diff --git a/contrib/tools/yasm/modules/preprocs/cpp/cpp-preproc.c b/contrib/tools/yasm/modules/preprocs/cpp/cpp-preproc.c new file mode 100644 index 0000000000..663f726cc7 --- /dev/null +++ b/contrib/tools/yasm/modules/preprocs/cpp/cpp-preproc.c @@ -0,0 +1,402 @@ +/* + * Invoke an external C preprocessor + * + * Copyright (C) 2007 Paul Barker + * 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> + +/* TODO: Use autoconf to get the limit on the command line length. */ +#define CMDLINE_SIZE 32770 + +#define BSIZE 512 + +/* Pre-declare the preprocessor module object. */ +yasm_preproc_module yasm_cpp_LTX_preproc; + +/******************************************************************************* + Structures. +*******************************************************************************/ + +/* An entry in a list of arguments to pass to cpp. */ +typedef struct cpp_arg_entry { + TAILQ_ENTRY(cpp_arg_entry) entry; + + /* + The operator (eg "-I") and the parameter (eg "include/"). op is expected + to point to a string literal, whereas param is expected to be a copy of + the parameter which is free'd when no-longer needed (in + cpp_preproc_destroy()). + */ + const char *op; + char *param; +} cpp_arg_entry; + +typedef struct yasm_preproc_cpp { + yasm_preproc_base preproc; /* base structure */ + + /* List of arguments to pass to cpp. */ + TAILQ_HEAD(cpp_arg_head, cpp_arg_entry) cpp_args; + + char *filename; + FILE *f, *f_deps; + yasm_linemap *cur_lm; + yasm_errwarns *errwarns; + + int flags; +} yasm_preproc_cpp; + +/* Flag values for yasm_preproc_cpp->flags. */ +#define CPP_HAS_BEEN_INVOKED 0x01 +#define CPP_HAS_GENERATED_DEPS 0x02 + +/******************************************************************************* + Internal functions and helpers. +*******************************************************************************/ + +/* + Append a string to the command line, ensuring that we don't overflow the + buffer. +*/ +#define APPEND(s) do { \ + size_t _len = strlen(s); \ + if (p + _len >= limit) \ + yasm__fatal(N_("command line too long!")); \ + strcpy(p, s); \ + p += _len; \ +} while (0) + +/* + Put all the options together into a command line that can be used to invoke + cpp. +*/ +static char * +cpp_build_cmdline(yasm_preproc_cpp *pp, const char *extra) +{ + char *cmdline, *p, *limit; + cpp_arg_entry *arg; + + /* Initialize command line. */ + cmdline = p = yasm_xmalloc(strlen(CPP_PROG)+CMDLINE_SIZE); + limit = p + CMDLINE_SIZE; + strcpy(p, CPP_PROG); + p += strlen(CPP_PROG); + + arg = TAILQ_FIRST(&pp->cpp_args); + + /* Append arguments from the list. */ + while ( arg ) { + APPEND(" "); + APPEND(arg->op); + APPEND(" "); + APPEND(arg->param); + + arg = TAILQ_NEXT(arg, entry); + } + + /* Append extra arguments. */ + if (extra) { + APPEND(" "); + APPEND(extra); + } + /* Append final arguments. */ + APPEND(" -x assembler-with-cpp "); + APPEND(pp->filename); + + return cmdline; +} + +/* Invoke the c preprocessor. */ +static void +cpp_invoke(yasm_preproc_cpp *pp) +{ + char *cmdline; + + cmdline = cpp_build_cmdline(pp, NULL); + +#ifdef HAVE_POPEN + pp->f = popen(cmdline, "r"); + if (!pp->f) + yasm__fatal( N_("Failed to execute preprocessor") ); +#else + yasm__fatal( N_("Cannot execute preprocessor, no popen available") ); +#endif + + yasm_xfree(cmdline); +} + +/* Free memory used by the list of arguments. */ +static void +cpp_destroy_args(yasm_preproc_cpp *pp) +{ + cpp_arg_entry *arg; + + while ( (arg = TAILQ_FIRST(&pp->cpp_args)) ) { + TAILQ_REMOVE(&pp->cpp_args, arg, entry); + yasm_xfree(arg->param); + yasm_xfree(arg); + } +} + +/* Invoke the c preprocessor to generate dependency info. */ +static void +cpp_generate_deps(yasm_preproc_cpp *pp) +{ + char *cmdline; + + cmdline = cpp_build_cmdline(pp, "-M"); + +#ifdef HAVE_POPEN + pp->f_deps = popen(cmdline, "r"); + if (!pp->f_deps) + yasm__fatal( N_("Failed to execute preprocessor") ); +#else + yasm__fatal( N_("Cannot execute preprocessor, no popen available") ); +#endif + + yasm_xfree(cmdline); +} + +/******************************************************************************* + Interface functions. +*******************************************************************************/ +static yasm_preproc * +cpp_preproc_create(const char *in, yasm_symtab *symtab, yasm_linemap *lm, + yasm_errwarns *errwarns) +{ + yasm_preproc_cpp *pp = yasm_xmalloc(sizeof(yasm_preproc_cpp)); + void * iter; + const char * inc_dir; + + pp->preproc.module = &yasm_cpp_LTX_preproc; + pp->f = pp->f_deps = NULL; + pp->cur_lm = lm; + pp->errwarns = errwarns; + pp->flags = 0; + pp->filename = yasm__xstrdup(in); + + TAILQ_INIT(&pp->cpp_args); + + /* Iterate through the list of include dirs. */ + iter = NULL; + while ((inc_dir = yasm_get_include_dir(&iter)) != NULL) { + cpp_arg_entry *arg = yasm_xmalloc(sizeof(cpp_arg_entry)); + arg->op = "-I"; + arg->param = yasm__xstrdup(inc_dir); + + TAILQ_INSERT_TAIL(&pp->cpp_args, arg, entry); + } + + return (yasm_preproc *)pp; +} + +static void +cpp_preproc_destroy(yasm_preproc *preproc) +{ + yasm_preproc_cpp *pp = (yasm_preproc_cpp *)preproc; + + if (pp->f) { +#ifdef HAVE_POPEN + if (pclose(pp->f) != 0) + yasm__fatal( N_("Preprocessor exited with failure") ); +#endif + } + + cpp_destroy_args(pp); + + yasm_xfree(pp->filename); + yasm_xfree(pp); +} + +static char * +cpp_preproc_get_line(yasm_preproc *preproc) +{ + yasm_preproc_cpp *pp = (yasm_preproc_cpp *)preproc; + int bufsize = BSIZE; + char *buf, *p; + + if (! (pp->flags & CPP_HAS_BEEN_INVOKED) ) { + pp->flags |= CPP_HAS_BEEN_INVOKED; + + cpp_invoke(pp); + } + + /* + Once the preprocessor has been run, we're just dealing with a normal + file. + */ + + /* Loop to ensure entire line is read (don't want to limit line length). */ + buf = yasm_xmalloc((size_t)bufsize); + p = buf; + for (;;) { + if (!fgets(p, bufsize-(p-buf), pp->f)) { + if (ferror(pp->f)) { + yasm_error_set(YASM_ERROR_IO, + N_("error when reading from file")); + yasm_errwarn_propagate(pp->errwarns, + yasm_linemap_get_current(pp->cur_lm)); + } + break; + } + p += strlen(p); + if (p > buf && p[-1] == '\n') + break; + if ((p-buf) >= bufsize) { + /* Increase size of buffer */ + char *oldbuf = buf; + bufsize *= 2; + buf = yasm_xrealloc(buf, (size_t)bufsize); + p = buf + (p-oldbuf); + } + } + + if (p == buf) { + /* No data; must be at EOF */ + yasm_xfree(buf); + return NULL; + } + + /* Strip the line ending */ + buf[strcspn(buf, "\r\n")] = '\0'; + + return buf; +} + +static size_t +cpp_preproc_get_included_file(yasm_preproc *preproc, char *buf, + size_t max_size) +{ + char *p = buf; + int ch = '\0'; + size_t n = 0; + yasm_preproc_cpp *pp = (yasm_preproc_cpp *)preproc; + + if (! (pp->flags & CPP_HAS_GENERATED_DEPS) ) { + pp->flags |= CPP_HAS_GENERATED_DEPS; + + cpp_generate_deps(pp); + + /* Skip target name and first dependency. */ + while (ch != ':') + ch = fgetc(pp->f_deps); + + fgetc(pp->f_deps); /* Discard space after colon. */ + + while (ch != ' ' && ch != EOF) + ch = fgetc(pp->f_deps); + + if (ch == EOF) + return 0; + } + + while (n < max_size) { + ch = fgetc(pp->f_deps); + + if (ch == ' ' || ch == EOF) { + *p = '\0'; + return n; + } + + /* Eat any silly characters. */ + if (ch < ' ') + continue; + + *p++ = ch; + n++; + } + + /* Ensure the buffer is null-terminated. */ + *(p - 1) = '\0'; + return n; +} + +static void +cpp_preproc_add_include_file(yasm_preproc *preproc, const char *filename) +{ + yasm_preproc_cpp *pp = (yasm_preproc_cpp *)preproc; + + cpp_arg_entry *arg = yasm_xmalloc(sizeof(cpp_arg_entry)); + arg->op = "-include"; + arg->param = yasm__xstrdup(filename); + + TAILQ_INSERT_TAIL(&pp->cpp_args, arg, entry); +} + +static void +cpp_preproc_predefine_macro(yasm_preproc *preproc, const char *macronameval) +{ + yasm_preproc_cpp *pp = (yasm_preproc_cpp *)preproc; + + cpp_arg_entry *arg = yasm_xmalloc(sizeof(cpp_arg_entry)); + arg->op = "-D"; + arg->param = yasm__xstrdup(macronameval); + + TAILQ_INSERT_TAIL(&pp->cpp_args, arg, entry); +} + +static void +cpp_preproc_undefine_macro(yasm_preproc *preproc, const char *macroname) +{ + yasm_preproc_cpp *pp = (yasm_preproc_cpp *)preproc; + + cpp_arg_entry *arg = yasm_xmalloc(sizeof(cpp_arg_entry)); + arg->op = "-U"; + arg->param = yasm__xstrdup(macroname); + + TAILQ_INSERT_TAIL(&pp->cpp_args, arg, entry); +} + +static void +cpp_preproc_define_builtin(yasm_preproc *preproc, const char *macronameval) +{ + /* Handle a builtin as if it were a predefine. */ + cpp_preproc_predefine_macro(preproc, macronameval); +} + +static void +cpp_preproc_add_standard(yasm_preproc *preproc, const char **macros) +{ + /* TODO */ +} + +/******************************************************************************* + Preprocessor module object. +*******************************************************************************/ + +yasm_preproc_module yasm_cpp_LTX_preproc = { + "Run input through external C preprocessor", + "cpp", + cpp_preproc_create, + cpp_preproc_destroy, + cpp_preproc_get_line, + cpp_preproc_get_included_file, + cpp_preproc_add_include_file, + cpp_preproc_predefine_macro, + cpp_preproc_undefine_macro, + cpp_preproc_define_builtin, + cpp_preproc_add_standard +}; diff --git a/contrib/tools/yasm/modules/preprocs/gas/gas-eval.c b/contrib/tools/yasm/modules/preprocs/gas/gas-eval.c new file mode 100644 index 0000000000..3625c7a9be --- /dev/null +++ b/contrib/tools/yasm/modules/preprocs/gas/gas-eval.c @@ -0,0 +1,444 @@ +/* eval.c expression evaluator for the Netwide Assembler + * + * The Netwide Assembler is copyright (C) 1996 Simon Tatham and + * Julian Hall. All rights reserved. The software is + * redistributable under the licence given in the file "Licence" + * distributed in the NASM archive. + * + * initial version 27/iii/95 by Simon Tatham + */ +#include <util.h> +#include <libyasm-stdint.h> +#include <libyasm/coretype.h> +#include <libyasm/intnum.h> +#include <libyasm/expr.h> +#include <libyasm/symrec.h> +#include <ctype.h> + +#include "gas-eval.h" + +/* The assembler symbol table. */ +static yasm_symtab *symtab; + +static scanner scan; /* Address of scanner routine */ +static efunc error; /* Address of error reporting routine */ + +static struct tokenval *tokval; /* The current token */ +static int i; /* The t_type of tokval */ + +static void *scpriv; +static void *epriv; + +/* + * Recursive-descent parser. Called with a single boolean operand, + * which is TRUE if the evaluation is critical (i.e. unresolved + * symbols are an error condition). Must update the global `i' to + * reflect the token after the parsed string. May return NULL. + * + * evaluate() should report its own errors: on return it is assumed + * that if NULL has been returned, the error has already been + * reported. + */ + +/* + * Grammar parsed is: + * + * expr : bexpr [ WRT expr6 ] + * bexpr : rexp0 or expr0 depending on relative-mode setting + * rexp0 : rexp1 [ {||} rexp1...] + * rexp1 : rexp2 [ {^^} rexp2...] + * rexp2 : rexp3 [ {&&} rexp3...] + * rexp3 : expr0 [ {=,==,<>,!=,<,>,<=,>=} expr0 ] + * expr0 : expr1 [ {|} expr1...] + * expr1 : expr2 [ {^} expr2...] + * expr2 : expr3 [ {&} expr3...] + * expr3 : expr4 [ {<<,>>} expr4...] + * expr4 : expr5 [ {+,-} expr5...] + * expr5 : expr6 [ {*,/,%,//,%%} expr6...] + * expr6 : { ~,+,-,SEG } expr6 + * | (bexpr) + * | symbol + * | $ + * | number + */ + +static yasm_expr *rexp0(void), *rexp1(void), *rexp2(void), *rexp3(void); + +static yasm_expr *expr0(void), *expr1(void), *expr2(void), *expr3(void); +static yasm_expr *expr4(void), *expr5(void), *expr6(void); + +static yasm_expr *(*bexpr)(void); + +static yasm_expr *rexp0(void) +{ + yasm_expr *e, *f; + + e = rexp1(); + if (!e) + return NULL; + + while (i == TOKEN_DBL_OR) + { + i = scan(scpriv, tokval); + f = rexp1(); + if (!f) { + yasm_expr_destroy(e); + return NULL; + } + + e = yasm_expr_create_tree(e, YASM_EXPR_LOR, f, 0); + } + return e; +} + +static yasm_expr *rexp1(void) +{ + yasm_expr *e, *f; + + e = rexp2(); + if (!e) + return NULL; + + while (i == TOKEN_DBL_XOR) + { + i = scan(scpriv, tokval); + f = rexp2(); + if (!f) { + yasm_expr_destroy(e); + return NULL; + } + + e = yasm_expr_create_tree(e, YASM_EXPR_LXOR, f, 0); + } + return e; +} + +static yasm_expr *rexp2(void) +{ + yasm_expr *e, *f; + + e = rexp3(); + if (!e) + return NULL; + while (i == TOKEN_DBL_AND) + { + i = scan(scpriv, tokval); + f = rexp3(); + if (!f) { + yasm_expr_destroy(e); + return NULL; + } + + e = yasm_expr_create_tree(e, YASM_EXPR_LAND, f, 0); + } + return e; +} + +static yasm_expr *rexp3(void) +{ + yasm_expr *e, *f; + + e = expr0(); + if (!e) + return NULL; + + while (i == TOKEN_EQ || i == TOKEN_LT || i == TOKEN_GT || + i == TOKEN_NE || i == TOKEN_LE || i == TOKEN_GE) + { + int j = i; + i = scan(scpriv, tokval); + f = expr0(); + if (!f) { + yasm_expr_destroy(e); + return NULL; + } + + switch (j) + { + case TOKEN_EQ: + e = yasm_expr_create_tree(e, YASM_EXPR_EQ, f, 0); + break; + case TOKEN_LT: + e = yasm_expr_create_tree(e, YASM_EXPR_LT, f, 0); + break; + case TOKEN_GT: + e = yasm_expr_create_tree(e, YASM_EXPR_GT, f, 0); + break; + case TOKEN_NE: + e = yasm_expr_create_tree(e, YASM_EXPR_NE, f, 0); + break; + case TOKEN_LE: + e = yasm_expr_create_tree(e, YASM_EXPR_LE, f, 0); + break; + case TOKEN_GE: + e = yasm_expr_create_tree(e, YASM_EXPR_GE, f, 0); + break; + } + } + return e; +} + +static yasm_expr *expr0(void) +{ + yasm_expr *e, *f; + + e = expr1(); + if (!e) + return NULL; + + while (i == '|') + { + i = scan(scpriv, tokval); + f = expr1(); + if (!f) { + yasm_expr_destroy(e); + return NULL; + } + + e = yasm_expr_create_tree(e, YASM_EXPR_OR, f, 0); + } + return e; +} + +static yasm_expr *expr1(void) +{ + yasm_expr *e, *f; + + e = expr2(); + if (!e) + return NULL; + + while (i == '^') { + i = scan(scpriv, tokval); + f = expr2(); + if (!f) { + yasm_expr_destroy(e); + return NULL; + } + + e = yasm_expr_create_tree(e, YASM_EXPR_XOR, f, 0); + } + return e; +} + +static yasm_expr *expr2(void) +{ + yasm_expr *e, *f; + + e = expr3(); + if (!e) + return NULL; + + while (i == '&') { + i = scan(scpriv, tokval); + f = expr3(); + if (!f) { + yasm_expr_destroy(e); + return NULL; + } + + e = yasm_expr_create_tree(e, YASM_EXPR_AND, f, 0); + } + return e; +} + +static yasm_expr *expr3(void) +{ + yasm_expr *e, *f; + + e = expr4(); + if (!e) + return NULL; + + while (i == TOKEN_SHL || i == TOKEN_SHR) + { + int j = i; + i = scan(scpriv, tokval); + f = expr4(); + if (!f) { + yasm_expr_destroy(e); + return NULL; + } + + switch (j) { + case TOKEN_SHL: + e = yasm_expr_create_tree(e, YASM_EXPR_SHL, f, 0); + break; + case TOKEN_SHR: + e = yasm_expr_create_tree(e, YASM_EXPR_SHR, f, 0); + break; + } + } + return e; +} + +static yasm_expr *expr4(void) +{ + yasm_expr *e, *f; + + e = expr5(); + if (!e) + return NULL; + while (i == '+' || i == '-') + { + int j = i; + i = scan(scpriv, tokval); + f = expr5(); + if (!f) { + yasm_expr_destroy(e); + return NULL; + } + switch (j) { + case '+': + e = yasm_expr_create_tree(e, YASM_EXPR_ADD, f, 0); + break; + case '-': + e = yasm_expr_create_tree(e, YASM_EXPR_SUB, f, 0); + break; + } + } + return e; +} + +static yasm_expr *expr5(void) +{ + yasm_expr *e, *f; + + e = expr6(); + if (!e) + return NULL; + while (i == '*' || i == '/' || i == '%' || + i == TOKEN_SDIV || i == TOKEN_SMOD) + { + int j = i; + i = scan(scpriv, tokval); + f = expr6(); + if (!f) { + yasm_expr_destroy(e); + return NULL; + } + switch (j) { + case '*': + e = yasm_expr_create_tree(e, YASM_EXPR_MUL, f, 0); + break; + case '/': + e = yasm_expr_create_tree(e, YASM_EXPR_DIV, f, 0); + break; + case '%': + e = yasm_expr_create_tree(e, YASM_EXPR_MOD, f, 0); + break; + case TOKEN_SDIV: + e = yasm_expr_create_tree(e, YASM_EXPR_SIGNDIV, f, 0); + break; + case TOKEN_SMOD: + e = yasm_expr_create_tree(e, YASM_EXPR_SIGNMOD, f, 0); + break; + } + } + return e; +} + +static yasm_expr *expr6(void) +{ + yasm_expr *e = NULL; + + if (i == '-') { + i = scan(scpriv, tokval); + e = expr6(); + if (!e) + return NULL; + return yasm_expr_create_branch(YASM_EXPR_NEG, e, 0); + } else if (i == '+') { + i = scan(scpriv, tokval); + return expr6(); + } else if (i == '~') { + i = scan(scpriv, tokval); + e = expr6(); + if (!e) + return NULL; + return yasm_expr_create_branch(YASM_EXPR_NOT, e, 0); + } else if (i == TOKEN_SEG) { + i = scan(scpriv, tokval); + e = expr6(); + if (!e) + return NULL; + error(epriv, ERR_NONFATAL, "%s not supported", "SEG"); + return e; + } else if (i == '(') { + i = scan(scpriv, tokval); + e = bexpr(); + if (!e) + return NULL; + if (i != ')') { + error(epriv, ERR_NONFATAL, "expecting `)'"); + return NULL; + } + i = scan(scpriv, tokval); + return e; + } + else if (i == TOKEN_NUM || i == TOKEN_ID || + i == TOKEN_HERE || i == TOKEN_BASE) + { + switch (i) { + case TOKEN_NUM: + e = yasm_expr_create_ident(yasm_expr_int(tokval->t_integer), 0); + tokval->t_integer = NULL; + break; + case TOKEN_ID: + if (symtab) { + yasm_symrec *sym = + yasm_symtab_get(symtab, tokval->t_charptr); + if (sym) { + e = yasm_expr_create_ident(yasm_expr_sym(sym), 0); + } else { + error(epriv, ERR_NONFATAL, + "undefined symbol `%s' in preprocessor", + tokval->t_charptr); + e = yasm_expr_create_ident(yasm_expr_int( + yasm_intnum_create_int(1)), 0); + } + break; + } + /*fallthrough*/ + case TOKEN_HERE: + case TOKEN_BASE: + error(epriv, ERR_NONFATAL, + "cannot reference symbol `%s' in preprocessor", + (i == TOKEN_ID ? tokval->t_charptr : + i == TOKEN_HERE ? "$" : "$$")); + e = yasm_expr_create_ident(yasm_expr_int(yasm_intnum_create_int(1)), + 0); + break; + } + i = scan(scpriv, tokval); + return e; + } else { + error(epriv, ERR_NONFATAL, "expression syntax error"); + return NULL; + } +} + +yasm_expr *evaluate (scanner sc, void *scprivate, struct tokenval *tv, + void *eprivate, int critical, efunc report_error, + yasm_symtab *st) +{ + if (critical & CRITICAL) { + critical &= ~CRITICAL; + bexpr = rexp0; + } else + bexpr = expr0; + + scan = sc; + scpriv = scprivate; + tokval = tv; + error = report_error; + epriv = eprivate; + symtab = st; + + if (tokval->t_type == TOKEN_INVALID) + i = scan(scpriv, tokval); + else + i = tokval->t_type; + + return bexpr (); +} diff --git a/contrib/tools/yasm/modules/preprocs/gas/gas-eval.h b/contrib/tools/yasm/modules/preprocs/gas/gas-eval.h new file mode 100644 index 0000000000..18dcc517a9 --- /dev/null +++ b/contrib/tools/yasm/modules/preprocs/gas/gas-eval.h @@ -0,0 +1,120 @@ +/* eval.h header file for eval.c + * + * The Netwide Assembler is copyright (C) 1996 Simon Tatham and + * Julian Hall. All rights reserved. The software is + * redistributable under the licence given in the file "Licence" + * distributed in the NASM archive. + */ + +#ifndef YASM_EVAL_H +#define YASM_EVAL_H + +/* + * ------------------------- + * Error reporting functions + * ------------------------- + */ + +/* + * An error reporting function should look like this. + */ +typedef void (*efunc) (void *private_data, int severity, const char *fmt, ...); + +/* + * These are the error severity codes which get passed as the first + * argument to an efunc. + */ + +#define ERR_DEBUG 0x00000008 /* put out debugging message */ +#define ERR_WARNING 0x00000000 /* warn only: no further action */ +#define ERR_NONFATAL 0x00000001 /* terminate assembly after phase */ +#define ERR_FATAL 0x00000002 /* instantly fatal: exit with error */ +#define ERR_PANIC 0x00000003 /* internal error: panic instantly + * and dump core for reference */ +#define ERR_MASK 0x0000000F /* mask off the above codes */ +#define ERR_NOFILE 0x00000010 /* don't give source file name/line */ +#define ERR_USAGE 0x00000020 /* print a usage message */ +#define ERR_PASS1 0x00000040 /* only print this error on pass one */ + +/* + * These codes define specific types of suppressible warning. + */ + +#define ERR_WARN_MASK 0x0000FF00 /* the mask for this feature */ +#define ERR_WARN_SHR 8 /* how far to shift right */ + +#define ERR_WARN_MNP 0x00000100 /* macro-num-parameters warning */ +#define ERR_WARN_MSR 0x00000200 /* macro self-reference */ +#define ERR_WARN_OL 0x00000300 /* orphan label (no colon, and + * alone on line) */ +#define ERR_WARN_NOV 0x00000400 /* numeric overflow */ +#define ERR_WARN_GNUELF 0x00000500 /* using GNU ELF extensions */ +#define ERR_WARN_MAX 5 /* the highest numbered one */ + +/* + * The expression evaluator must be passed a scanner function; a + * standard scanner is provided as part of nasmlib.c. The + * preprocessor will use a different one. Scanners, and the + * token-value structures they return, look like this. + * + * The return value from the scanner is always a copy of the + * `t_type' field in the structure. + */ +struct tokenval { + int t_type; + yasm_intnum *t_integer, *t_inttwo; + char *t_charptr; +}; +typedef int (*scanner) (void *private_data, struct tokenval *tv); + +/* + * Token types returned by the scanner, in addition to ordinary + * ASCII character values, and zero for end-of-string. + */ +enum { /* token types, other than chars */ + TOKEN_INVALID = -1, /* a placeholder value */ + TOKEN_EOS = 0, /* end of string */ + TOKEN_EQ = '=', TOKEN_GT = '>', TOKEN_LT = '<', /* aliases */ + TOKEN_ID = 256, TOKEN_NUM, TOKEN_REG, TOKEN_INSN, /* major token types */ + TOKEN_ERRNUM, /* numeric constant with error in */ + TOKEN_HERE, TOKEN_BASE, /* $ and $$ */ + TOKEN_SPECIAL, /* BYTE, WORD, DWORD, FAR, NEAR, etc */ + TOKEN_PREFIX, /* A32, O16, LOCK, REPNZ, TIMES, etc */ + TOKEN_SHL, TOKEN_SHR, /* << and >> */ + TOKEN_SDIV, TOKEN_SMOD, /* // and %% */ + TOKEN_GE, TOKEN_LE, TOKEN_NE, /* >=, <= and <> (!= is same as <>) */ + TOKEN_DBL_AND, TOKEN_DBL_OR, TOKEN_DBL_XOR, /* &&, || and ^^ */ + TOKEN_SEG, TOKEN_WRT, /* SEG and WRT */ + TOKEN_FLOAT /* floating-point constant */ +}; + +/* + * The actual expression evaluator function looks like this. When + * called, it expects the first token of its expression to already + * be in `*tv'; if it is not, set tv->t_type to TOKEN_INVALID and + * it will start by calling the scanner. + * + * `critical' is non-zero if the expression may not contain forward + * references. The evaluator will report its own error if this + * occurs; if `critical' is 1, the error will be "symbol not + * defined before use", whereas if `critical' is 2, the error will + * be "symbol undefined". + * + * If `critical' has bit 8 set (in addition to its main value: 0x101 + * and 0x102 correspond to 1 and 2) then an extended expression + * syntax is recognised, in which relational operators such as =, < + * and >= are accepted, as well as low-precedence logical operators + * &&, ^^ and ||. + */ +#define CRITICAL 0x100 +typedef yasm_expr *(*evalfunc) (scanner sc, void *scprivate, struct tokenval *tv, + int critical, efunc error, yasm_symtab *symtab); + +/* + * The evaluator itself. + */ +yasm_expr *evaluate (scanner sc, void *scprivate, struct tokenval *tv, + void *eprivate, int critical, efunc report_error, + yasm_symtab *symtab); + +#endif diff --git a/contrib/tools/yasm/modules/preprocs/gas/gas-preproc.c b/contrib/tools/yasm/modules/preprocs/gas/gas-preproc.c new file mode 100644 index 0000000000..60c9e4f0cd --- /dev/null +++ b/contrib/tools/yasm/modules/preprocs/gas/gas-preproc.c @@ -0,0 +1,1409 @@ +/* + * GAS preprocessor (emulates GNU Assembler's preprocessor) + * + * Copyright (C) 2009 Alexei Svitkine + * + * 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 <ctype.h> + +#include <libyasm.h> +#include "modules/preprocs/gas/gas-eval.h" + +#define FALSE 0 +#define TRUE 1 +#define BSIZE 512 + +#ifndef MAXPATHLEN +#define MAXPATHLEN 1024 +#endif + +typedef struct buffered_line { + char *line; + int line_number; + SLIST_ENTRY(buffered_line) next; +} buffered_line; + +typedef struct included_file { + char *filename; + int lines_remaining; + SLIST_ENTRY(included_file) next; +} included_file; + +typedef struct macro_entry { + char *name; + int num_params; + char **params; + int num_lines; + char **lines; + STAILQ_ENTRY(macro_entry) next; +} macro_entry; + +typedef struct deferred_define { + char *name; + char *value; + SLIST_ENTRY(deferred_define) next; +} deferred_define; + +typedef struct expr_state { + const char *string; + char *symbol; + int string_cursor; +} expr_state; + +typedef struct yasm_preproc_gas { + yasm_preproc_base preproc; /* base structure */ + + FILE *in; + char *in_filename; + + yasm_symtab *defines; + SLIST_HEAD(deferred_defines_head, deferred_define) deferred_defines; + + int depth; + int skip_depth; + + int in_comment; + + expr_state expr; + + SLIST_HEAD(buffered_lines_head, buffered_line) buffered_lines; + SLIST_HEAD(included_files_head, included_file) included_files; + STAILQ_HEAD(macros_head, macro_entry) macros; + + int in_line_number; + int next_line_number; + int current_line_number; /* virtual (output) line number */ + + yasm_linemap *cur_lm; + yasm_errwarns *errwarns; + int fatal_error; + int detect_errors_only; +} yasm_preproc_gas; + +yasm_preproc_module yasm_gas_LTX_preproc; + +/* Forward declarations. */ + +static int substitute_values(yasm_preproc_gas *pp, char **line_ptr); + +/* String helpers. */ + +static const char *starts_with(const char *big, const char *little) +{ + while (*little) { + if (*little++ != *big++) { + return NULL; + } + } + return big; +} + +static void skip_whitespace(const char **line) +{ + while (isspace(**line)) { + (*line)++; + } +} + +static void skip_whitespace2(char **line) +{ + while (isspace(**line)) { + (*line)++; + } +} + +static const char *matches(const char *line, const char *directive) +{ + skip_whitespace(&line); + + if (*line == '.') { + line = starts_with(line + 1, directive); + if (line && (!*line || isspace(*line))) { + skip_whitespace(&line); + return line; + } + } + + return NULL; +} + +static int unquote(const char *arg, char *to, size_t to_size, char q, char expected, const char **remainder) +{ + const char *quote; + const char *end; + size_t len; + + skip_whitespace(&arg); + if (*arg != q) { + return -1; + } + + arg++; + + end = arg; + do { + quote = strchr(end, q); + if (!quote) { + return -2; + } + end = quote + 1; + } while (*(quote - 1) == '\\'); + + skip_whitespace(&end); + if (*end != expected) { + return -3; + } + + if (remainder) { + *remainder = end + 1; + } + + len = (size_t) (quote - arg); + if (len >= to_size) { + return -4; + } + + strncpy(to, arg, len); + to[len] = '\0'; + + return (int) len; +} + +/* Line-reading. */ + +static char *read_line_from_file(yasm_preproc_gas *pp, FILE *file) +{ + int bufsize = BSIZE; + char *buf; + char *p; + + buf = yasm_xmalloc((size_t)bufsize); + + /* Loop to ensure entire line is read (don't want to limit line length). */ + p = buf; + for (;;) { + if (!fgets(p, bufsize - (p - buf), file)) { + if (ferror(file)) { + yasm_error_set(YASM_ERROR_IO, N_("error when reading from file")); + yasm_errwarn_propagate(pp->errwarns, pp->current_line_number); + } + break; + } + p += strlen(p); + if (p > buf && p[-1] == '\n') { + break; + } + if ((p - buf) + 1 >= bufsize) { + /* Increase size of buffer */ + char *oldbuf = buf; + bufsize *= 2; + buf = yasm_xrealloc(buf, (size_t) bufsize); + p = buf + (p - oldbuf); + } + } + + if (p == buf) { + /* No data; must be at EOF */ + yasm_xfree(buf); + return NULL; + } + + /* Strip the line ending */ + buf[strcspn(buf, "\r\n")] = '\0'; + return buf; +} + +static char *read_line(yasm_preproc_gas *pp) +{ + char *line; + + if (!SLIST_EMPTY(&pp->included_files)) { + included_file *inc_file = SLIST_FIRST(&pp->included_files); + if (inc_file->lines_remaining <= 0) { + SLIST_REMOVE_HEAD(&pp->included_files, next); + yasm_xfree(inc_file->filename); + yasm_xfree(inc_file); + } + } + + if (!SLIST_EMPTY(&pp->buffered_lines)) { + buffered_line *bline = SLIST_FIRST(&pp->buffered_lines); + SLIST_REMOVE_HEAD(&pp->buffered_lines, next); + line = bline->line; + if (bline->line_number != -1) { + pp->next_line_number = bline->line_number; + } + yasm_xfree(bline); + if (!SLIST_EMPTY(&pp->included_files)) { + SLIST_FIRST(&pp->included_files)->lines_remaining--; + } + return line; + } + + line = read_line_from_file(pp, pp->in); + if (line) { + pp->in_line_number++; + pp->next_line_number = pp->in_line_number; + } + + return line; +} + +static const char *get_arg(yasm_preproc_gas *pp, const char *src, char *dest, size_t dest_size) +{ + const char *comma = strchr(src, ','); + if (comma) { + size_t len = (size_t) (comma - src); + if (len >= dest_size) { + len = dest_size - 1; + } + strncpy(dest, src, len); + dest[len] = '\0'; + comma++; + skip_whitespace(&comma); + } else { + yasm_error_set(YASM_ERROR_SYNTAX, N_("expected comma")); + yasm_errwarn_propagate(pp->errwarns, pp->current_line_number); + } + return comma; +} + +/* GAS expression evaluation. */ + +static char get_char(yasm_preproc_gas *pp) +{ + return pp->expr.string[pp->expr.string_cursor]; +} + +static const char *get_str(yasm_preproc_gas *pp) +{ + return pp->expr.string + pp->expr.string_cursor; +} + +static void next_char(yasm_preproc_gas *pp) +{ + pp->expr.string_cursor++; +} + +static int ishex(char c) +{ + c = tolower(c); + return isdigit(c) || (c >= 'a' && c <= 'f'); +} + +static void gas_scan_init(yasm_preproc_gas *pp, struct tokenval *tokval, const char *arg1) +{ + pp->expr.symbol = NULL; + pp->expr.string = arg1; + pp->expr.string_cursor = 0; + memset(tokval, 0, sizeof(struct tokenval)); + tokval->t_type = TOKEN_INVALID; +} + +static void gas_scan_cleanup(yasm_preproc_gas *pp, struct tokenval *tokval) +{ + if (tokval->t_integer) { + yasm_intnum_destroy(tokval->t_integer); + tokval->t_integer = NULL; + } + if (pp->expr.symbol) { + yasm_xfree(pp->expr.symbol); + pp->expr.symbol = NULL; + } +} + +static int gas_scan(void *preproc, struct tokenval *tokval) +{ + yasm_preproc_gas *pp = (yasm_preproc_gas *) preproc; + char c = get_char(pp); + const char *str; + + tokval->t_charptr = NULL; + + if (c == '\0') { + return tokval->t_type = TOKEN_EOS; + } + + if (isspace(c)) { + do { + next_char(pp); + c = get_char(pp); + } while (isspace(c)); + } + + if (isdigit(c)) { + int char_index = 0; + int value = 0; + + do { + value = value*10 + (c - '0'); + char_index++; + next_char(pp); + c = get_char(pp); + if (char_index == 1 && c == 'x' && value == 0) { + next_char(pp); + c = get_char(pp); + /* Hex notation. */ + while (ishex(c)) { + if (isdigit(c)) { + value = (value << 4) | (c - '0'); + } else { + value = (value << 4) | (tolower(c) - 'a' + 0xa); + } + next_char(pp); + c = get_char(pp); + } + break; + } + } while (isdigit(c)); + + if (tokval->t_integer) { + yasm_intnum_destroy(tokval->t_integer); + } + tokval->t_integer = yasm_intnum_create_int(value); + return tokval->t_type = TOKEN_NUM; + } + + tokval->t_type = TOKEN_INVALID; + str = get_str(pp); + + { + /* It should be tested whether GAS supports all of these or if there are missing ones. */ + unsigned i; + struct { + const char *op; + int token; + } ops[] = { + { "<<", TOKEN_SHL }, + { ">>", TOKEN_SHR }, + { "//", TOKEN_SDIV }, + { "%%", TOKEN_SMOD }, + { "==", TOKEN_EQ }, + { "!=", TOKEN_NE }, + { "<>", TOKEN_NE }, + { "<>", TOKEN_NE }, + { "<=", TOKEN_LE }, + { ">=", TOKEN_GE }, + { "&&", TOKEN_DBL_AND }, + { "^^", TOKEN_DBL_XOR }, + { "||", TOKEN_DBL_OR } + }; + for (i = 0; i < sizeof(ops)/sizeof(ops[0]); i++) { + if (!strcmp(str, ops[i].op)) { + tokval->t_type = ops[i].token; + break; + } + } + } + + if (tokval->t_type != TOKEN_INVALID) { + next_char(pp); + next_char(pp); + } else { + str = get_str(pp); + + next_char(pp); + tokval->t_type = c; + + /* Is it a symbol? If so we need to make it a TOKEN_ID. */ + if (isalpha(c) || c == '_' || c == '.') { + int symbol_length = 1; + + c = get_char(pp); + while (isalnum(c) || c == '$' || c == '_') { + symbol_length++; + next_char(pp); + c = get_char(pp); + } + + pp->expr.symbol = yasm_xrealloc(pp->expr.symbol, symbol_length + 1); + memcpy(pp->expr.symbol, str, symbol_length); + pp->expr.symbol[symbol_length] = '\0'; + + tokval->t_type = TOKEN_ID; + tokval->t_charptr = pp->expr.symbol; + } + } + + return tokval->t_type; +} + +static void gas_err(void *private_data, int severity, const char *fmt, ...) +{ + va_list args; + yasm_preproc_gas *pp = private_data; + + if (!pp->detect_errors_only) { + va_start(args, fmt); + yasm_error_set_va(YASM_ERROR_SYNTAX, N_(fmt), args); + yasm_errwarn_propagate(pp->errwarns, pp->current_line_number); + va_end(args); + } + + pp->fatal_error = 1; +} + +static long eval_expr(yasm_preproc_gas *pp, const char *arg1) +{ + struct tokenval tv; + yasm_expr *expr; + yasm_intnum *intn; + long value; + expr_state prev_state; + + if (!*arg1) { + return 0; + } + + prev_state = pp->expr; + gas_scan_init(pp, &tv, arg1); + expr = evaluate(gas_scan, pp, &tv, pp, CRITICAL, gas_err, pp->defines); + intn = yasm_expr_get_intnum(&expr, 0); + value = yasm_intnum_get_int(intn); + yasm_expr_destroy(expr); + gas_scan_cleanup(pp, &tv); + pp->expr = prev_state; + + return value; +} + +/* If-directive helpers. */ + +static int handle_if(yasm_preproc_gas *pp, int is_true) +{ + assert(pp->depth >= 0); + assert(pp->skip_depth == 0); + if (is_true) { + pp->depth++; + } else { + pp->skip_depth = 1; + } + return 1; +} + +static int handle_endif(yasm_preproc_gas *pp) +{ + if (pp->depth) { + pp->depth--; + } else { + yasm_error_set(YASM_ERROR_SYNTAX, N_("\".endif\" without \".if\"")); + yasm_errwarn_propagate(pp->errwarns, pp->current_line_number); + return 0; + } + return 1; +} + +static int handle_else(yasm_preproc_gas *pp, int is_elseif) +{ + if (!pp->depth) { + yasm_error_set(YASM_ERROR_SYNTAX, N_("\".%s\" without \".if\""), is_elseif ? "elseif" : "else"); + yasm_errwarn_propagate(pp->errwarns, pp->current_line_number); + return 0; + } else { + pp->skip_depth = 1; + } + return 1; +} + +/* Directive-handling functions. */ + +static int eval_if(yasm_preproc_gas *pp, int negate, const char *arg1) +{ + long value; + if (!*arg1) { + yasm_error_set(YASM_ERROR_SYNTAX, N_("expression is required in \".if\" statement")); + yasm_errwarn_propagate(pp->errwarns, pp->current_line_number); + return 0; + } + value = eval_expr(pp, arg1); + handle_if(pp, (negate ? !value : !!value)); + return 1; +} + +static int eval_else(yasm_preproc_gas *pp, int unused) +{ + return handle_else(pp, 0); +} + +static int eval_endif(yasm_preproc_gas *pp, int unused) +{ + return handle_endif(pp); +} + +static int eval_elseif(yasm_preproc_gas *pp, int unused, const char *arg1) +{ + if (!*arg1) { + yasm_error_set(YASM_ERROR_SYNTAX, N_("expression is required in \".elseif\" statement")); + yasm_errwarn_propagate(pp->errwarns, pp->current_line_number); + return 0; + } + if (!handle_else(pp, 1)) { + return 0; + } + return eval_if(pp, 0, arg1); +} + +static int eval_ifb(yasm_preproc_gas *pp, int negate, const char *arg1) +{ + int is_blank = !*arg1; + return handle_if(pp, (negate ? !is_blank : is_blank)); +} + +static int eval_ifc(yasm_preproc_gas *pp, int negate, const char *args) +{ + char arg1[512], arg2[512]; + const char *remainder; + int len = unquote(args, arg1, sizeof(arg1), '\'', ',', &remainder); + if (len >= 0) { + len = unquote(remainder, arg2, sizeof(arg2), '\'', '\0', NULL); + if (len >= 0) { + int result = !strcmp(arg1, arg2); + return handle_if(pp, (negate ? !result : result)); + } + } else { + /* first argument was not single-quoted, assume non-quoted mode */ + remainder = get_arg(pp, args, arg1, sizeof(arg1)); + if (remainder) { + int result = !strcmp(arg1, remainder); + return handle_if(pp, (negate ? !result : result)); + } + } + yasm_error_set(YASM_ERROR_SYNTAX, N_("\"%s\" expects two single-quoted or unquoted arguments"), negate ? ".ifnc" : ".ifc"); + yasm_errwarn_propagate(pp->errwarns, pp->current_line_number); + return 0; +} + +static int eval_ifeqs(yasm_preproc_gas *pp, int negate, const char *args) +{ + char arg1[512], arg2[512]; + const char *remainder; + int len = unquote(args, arg1, sizeof(arg1), '"', ',', &remainder); + if (len >= 0) { + len = unquote(remainder, arg2, sizeof(arg2), '"', '\0', NULL); + if (len >= 0) { + int result = !strcmp(arg1, arg2); + return handle_if(pp, (negate ? !result : result)); + } + } + yasm_error_set(YASM_ERROR_SYNTAX, N_("\"%s\" expects two double-quoted arguments"), negate ? ".ifnes" : ".ifeqs"); + yasm_errwarn_propagate(pp->errwarns, pp->current_line_number); + return 1; +} + +static int eval_ifdef(yasm_preproc_gas *pp, int negate, const char *name) +{ + yasm_symrec *rec = yasm_symtab_get(pp->defines, name); + int result = (rec != NULL); + return handle_if(pp, (negate ? !result : result)); +} + +static int eval_ifge(yasm_preproc_gas *pp, int negate, const char *arg1) +{ + long value = eval_expr(pp, arg1); + int result = (value >= 0); + return handle_if(pp, (negate ? !result : result)); +} + +static int eval_ifgt(yasm_preproc_gas *pp, int negate, const char *arg1) +{ + long value = eval_expr(pp, arg1); + int result = (value > 0); + return handle_if(pp, (negate ? !result : result)); +} + +static int eval_include(yasm_preproc_gas *pp, int unused, const char *arg1) +{ + char *current_filename; + char filename[MAXPATHLEN]; + char *line; + int num_lines; + FILE *file; + buffered_line *prev_bline; + included_file *inc_file; + + if (unquote(arg1, filename, sizeof(filename), '"', '\0', NULL) < 0) { + yasm_error_set(YASM_ERROR_SYNTAX, N_("string expected")); + yasm_errwarn_propagate(pp->errwarns, pp->current_line_number); + return 0; + } + + if (SLIST_EMPTY(&pp->included_files)) { + current_filename = pp->in_filename; + } else { + current_filename = SLIST_FIRST(&pp->included_files)->filename; + } + file = yasm_fopen_include(filename, current_filename, "r", NULL); + if (!file) { + yasm_error_set(YASM_ERROR_SYNTAX, N_("unable to open included file \"%s\""), filename); + yasm_errwarn_propagate(pp->errwarns, pp->current_line_number); + return 0; + } + + num_lines = 0; + prev_bline = NULL; + line = read_line_from_file(pp, file); + while (line) { + buffered_line *bline = yasm_xmalloc(sizeof(buffered_line)); + bline->line = line; + bline->line_number = -1; + if (prev_bline) { + SLIST_INSERT_AFTER(prev_bline, bline, next); + } else { + SLIST_INSERT_HEAD(&pp->buffered_lines, bline, next); + } + prev_bline = bline; + line = read_line_from_file(pp, file); + num_lines++; + } + + inc_file = yasm_xmalloc(sizeof(included_file)); + inc_file->filename = yasm__xstrdup(filename); + inc_file->lines_remaining = num_lines; + SLIST_INSERT_HEAD(&pp->included_files, inc_file, next); + return 1; +} + +static int try_eval_expr(yasm_preproc_gas *pp, const char *value, long *result) +{ + int success; + + pp->detect_errors_only = 1; + *result = eval_expr(pp, value); + success = !pp->fatal_error; + pp->fatal_error = 0; + pp->detect_errors_only = 0; + + return success; +} + +static int remove_define(yasm_preproc_gas *pp, const char *name, int allow_redefine) +{ + yasm_symrec *rec = yasm_symtab_get(pp->defines, name); + if (rec) { + const yasm_symtab_iter *entry; + yasm_symtab *new_defines; + + if (!allow_redefine) { + yasm_error_set(YASM_ERROR_SYNTAX, N_("symbol \"%s\" is already defined"), name); + yasm_errwarn_propagate(pp->errwarns, pp->current_line_number); + return 0; + } + + new_defines = yasm_symtab_create(); + + for (entry = yasm_symtab_first(pp->defines); entry; entry = yasm_symtab_next(entry)) { + yasm_symrec *entry_rec = yasm_symtab_iter_value(entry); + const char *rec_name = yasm_symrec_get_name(entry_rec); + if (strcmp(rec_name, name)) { + yasm_intnum *num = yasm_intnum_create_int(eval_expr(pp, rec_name)); + yasm_expr *expr = yasm_expr_create_ident(yasm_expr_int(num), 0); + yasm_symtab_define_equ(new_defines, rec_name, expr, 0); + } + } + + yasm_symtab_destroy(pp->defines); + pp->defines = new_defines; + } + return (rec != NULL); +} + +static void add_define(yasm_preproc_gas *pp, const char *name, long value, int allow_redefine, int substitute) +{ + deferred_define *def, *prev_def, *temp_def; + yasm_intnum *num; + yasm_expr *expr; + + remove_define(pp, name, allow_redefine); + + /* Add the new define. */ + num = yasm_intnum_create_int(value); + expr = yasm_expr_create_ident(yasm_expr_int(num), 0); + yasm_symtab_define_equ(pp->defines, name, expr, 0); + + /* Perform substitution on any deferred defines. */ + if (substitute) { + prev_def = NULL; + temp_def = NULL; + SLIST_FOREACH_SAFE(def, &pp->deferred_defines, next, temp_def) { + if (substitute_values(pp, &def->value)) { + /* Value was updated - check if it can be added to the symtab. */ + if (try_eval_expr(pp, def->value, &value)) { + add_define(pp, def->name, value, FALSE, FALSE); + if (prev_def) { + SLIST_NEXT(prev_def, next) = SLIST_NEXT(def, next); + } else { + SLIST_FIRST(&pp->deferred_defines) = SLIST_NEXT(def, next); + } + yasm_xfree(def->name); + yasm_xfree(def->value); + yasm_xfree(def); + continue; + } + } + prev_def = def; + } + } +} + +static int eval_set(yasm_preproc_gas *pp, int allow_redefine, const char *name, const char *value) +{ + if (!pp->skip_depth) { + long result; + + if (!try_eval_expr(pp, value, &result)) { + deferred_define *def; + remove_define(pp, name, allow_redefine); + def = yasm_xmalloc(sizeof(deferred_define)); + def->name = yasm__xstrdup(name); + def->value = yasm__xstrdup(value); + substitute_values(pp, &def->value); + SLIST_INSERT_HEAD(&pp->deferred_defines, def, next); + } else { + add_define(pp, name, result, allow_redefine, TRUE); + } + } + return 1; +} + +static int eval_macro(yasm_preproc_gas *pp, int unused, char *args) +{ + char *end; + char *line; + long nesting = 1; + macro_entry *macro = yasm_xmalloc(sizeof(macro_entry)); + + memset(macro, 0, sizeof(macro_entry)); + + end = args; + while (*end && !isspace(*end)) { + end++; + } + macro->name = yasm_xmalloc(end - args + 1); + memcpy(macro->name, args, end - args); + macro->name[end - args] = '\0'; + + skip_whitespace2(&end); + while (*end) { + args = end; + while (*end && !isspace(*end) && *end != ',') { + end++; + } + macro->num_params++; + macro->params = yasm_xrealloc(macro->params, macro->num_params*sizeof(char *)); + macro->params[macro->num_params - 1] = yasm_xmalloc(end - args + 1); + memcpy(macro->params[macro->num_params - 1], args, end - args); + macro->params[macro->num_params - 1][end - args] = '\0'; + skip_whitespace2(&end); + if (*end == ',') { + end++; + skip_whitespace2(&end); + } + } + + STAILQ_INSERT_TAIL(&pp->macros, macro, next); + + line = read_line(pp); + while (line) { + char *line2 = line; + skip_whitespace2(&line2); + if (starts_with(line2, ".macro")) { + nesting++; + } else if (starts_with(line, ".endm") && --nesting == 0) { + return 1; + } + macro->num_lines++; + macro->lines = yasm_xrealloc(macro->lines, macro->num_lines*sizeof(char *)); + macro->lines[macro->num_lines - 1] = line; + line = read_line(pp); + } + + yasm_error_set(YASM_ERROR_SYNTAX, N_("unexpected EOF in \".macro\" block")); + yasm_errwarn_propagate(pp->errwarns, yasm_linemap_get_current(pp->cur_lm)); + return 0; +} + +static int eval_endm(yasm_preproc_gas *pp, int unused) +{ + yasm_error_set(YASM_ERROR_SYNTAX, N_("\".endm\" without \".macro\"")); + yasm_errwarn_propagate(pp->errwarns, yasm_linemap_get_current(pp->cur_lm)); + return 0; +} + +static void get_param_value(macro_entry *macro, int param_index, const char *args, const char **value, int *length) +{ + int arg_index = 0; + const char *default_value = NULL; + const char *end, *eq = strstr(macro->params[param_index], "="); + + if (eq) { + default_value = eq + 1; + } + + skip_whitespace(&args); + end = args; + while (*end) { + args = end; + while (*end && !isspace(*end) && *end != ',') { + end++; + } + if (arg_index == param_index) { + if (end == args && default_value) { + *value = default_value; + *length = strlen(default_value); + } else { + *value = args; + *length = end - args; + } + return; + } + arg_index++; + skip_whitespace(&end); + if (*end == ',') { + end++; + skip_whitespace(&end); + } + } + + *value = default_value; + *length = (default_value ? strlen(default_value) : 0); +} + +static void expand_macro(yasm_preproc_gas *pp, macro_entry *macro, const char *args) +{ + int i, j; + buffered_line *prev_bline = NULL; + + for (i = 0; i < macro->num_lines; i++) { + buffered_line *bline = yasm_xmalloc(sizeof(buffered_line)); + struct tokenval tokval; + int prev_was_backslash = FALSE; + int line_length = strlen(macro->lines[i]); + char *work = yasm__xstrdup(macro->lines[i]); + expr_state prev_state = pp->expr; + + gas_scan_init(pp, &tokval, work); + while (gas_scan(pp, &tokval) != TOKEN_EOS) { + if (prev_was_backslash) { + if (tokval.t_type == TOKEN_ID) { + for (j = 0; j < macro->num_params; j++) { + char *end = strstr(macro->params[j], "="); + int len = (end ? (size_t)(end - macro->params[j]) + : strlen(macro->params[j])); + if (!strncmp(tokval.t_charptr, macro->params[j], len) + && tokval.t_charptr[len] == '\0') { + /* now, find matching argument. */ + const char *value; + char *line = work + (pp->expr.string - work); + int cursor = pp->expr.string_cursor; + int value_length, delta; + + get_param_value(macro, j, args, &value, &value_length); + + len++; /* leading slash */ + delta = value_length - len; + line_length += delta; + if (delta > 0) { + line = yasm_xrealloc(line, line_length + 1); + } + memmove(line + cursor - len + value_length, line + cursor, strlen(line + cursor) + 1); + memcpy(line + cursor - len, value, value_length); + pp->expr.string = work = line; + pp->expr.string_cursor += delta; + if (pp->expr.symbol) { + yasm_xfree(pp->expr.symbol); + pp->expr.symbol = NULL; + } + } + } + } + prev_was_backslash = FALSE; + } else if (tokval.t_type == '\\') { + prev_was_backslash = TRUE; + } + } + gas_scan_cleanup(pp, &tokval); + + bline->line = work + (pp->expr.string - work); + bline->line_number = -1; + pp->expr = prev_state; + + if (prev_bline) { + SLIST_INSERT_AFTER(prev_bline, bline, next); + } else { + SLIST_INSERT_HEAD(&pp->buffered_lines, bline, next); + } + prev_bline = bline; + } +} + +static int eval_rept(yasm_preproc_gas *pp, int unused, const char *arg1) +{ + long i, n = eval_expr(pp, arg1); + long num_lines = 0; + long nesting = 1; + char *line = read_line(pp); + buffered_line *prev_bline = NULL; + SLIST_HEAD(buffered_lines_head, buffered_line) lines; + int rept_start_file_line_number = pp->next_line_number - 1; + int rept_start_output_line_number = pp->current_line_number; + + SLIST_INIT(&lines); + + while (line) { + skip_whitespace2(&line); + if (starts_with(line, ".rept")) { + nesting++; + } else if (starts_with(line, ".endr") && --nesting == 0) { + for (i = 0; i < n; i++) { + buffered_line *current_line; + prev_bline = NULL; + SLIST_FOREACH(current_line, &lines, next) { + buffered_line *bline = yasm_xmalloc(sizeof(buffered_line)); + bline->line = yasm__xstrdup(current_line->line); + bline->line_number = current_line->line_number; + if (prev_bline) { + SLIST_INSERT_AFTER(prev_bline, bline, next); + } else { + SLIST_INSERT_HEAD(&pp->buffered_lines, bline, next); + } + prev_bline = bline; + } + } + if (!SLIST_EMPTY(&pp->included_files)) { + included_file *inc_file = SLIST_FIRST(&pp->included_files); + inc_file->lines_remaining += n * num_lines; + } + while (!SLIST_EMPTY(&lines)) { + buffered_line *bline = SLIST_FIRST(&lines); + SLIST_REMOVE_HEAD(&lines, next); + yasm_xfree(bline->line); + yasm_xfree(bline); + } + yasm_xfree(line); + return 1; + } + if (n > 0) { + buffered_line *bline = yasm_xmalloc(sizeof(buffered_line)); + bline->line = line; + bline->line_number = pp->next_line_number; + if (prev_bline) { + SLIST_INSERT_AFTER(prev_bline, bline, next); + } else { + SLIST_INSERT_HEAD(&lines, bline, next); + } + prev_bline = bline; + } else { + yasm_xfree(line); + } + line = read_line(pp); + num_lines++; + } + yasm_linemap_set(pp->cur_lm, pp->in_filename, rept_start_output_line_number, rept_start_file_line_number, 0); + yasm_error_set(YASM_ERROR_SYNTAX, N_("rept without matching endr")); + yasm_errwarn_propagate(pp->errwarns, rept_start_output_line_number); + return 0; +} + +static int eval_endr(yasm_preproc_gas *pp, int unused) +{ + yasm_error_set(YASM_ERROR_SYNTAX, N_("\".endr\" without \".rept\"")); + yasm_errwarn_propagate(pp->errwarns, pp->current_line_number); + return 0; +} + +/* Top-level line processing. */ + +typedef int (*pp_fn0_t)(yasm_preproc_gas *pp, int param); +typedef int (*pp_fn1_t)(yasm_preproc_gas *pp, int param, const char *arg1); +typedef int (*pp_fn2_t)(yasm_preproc_gas *pp, int param, const char *arg1, const char *arg2); + +#define FN(f) ((pp_fn0_t) &(f)) + +static void kill_comments(yasm_preproc_gas *pp, char *line) +{ + int next = 2; + char *cstart; + + skip_whitespace2(&line); + if (*line == '#' || !strncmp(line, "//", 2)) { + *line = '\0'; + return; + } + + if (pp->in_comment) { + cstart = line; + next = 0; + } else { + cstart = strstr(line, "/*"); + next = 2; + } + + while (cstart) { + char *cend = strstr(cstart + next, "*/"); + + if (!cend) { + *cstart = '\0'; + pp->in_comment = TRUE; + return; + } + + memmove(cstart, cend + 2, strlen(cend + 2) + 1); + pp->in_comment = FALSE; + cstart = strstr(cstart, "/*"); + next = 2; + } +} + +static int substitute_values(yasm_preproc_gas *pp, char **line_ptr) +{ + int changed = 0; + char *line = *line_ptr; + int line_length = strlen(line); + struct tokenval tokval; + expr_state prev_state = pp->expr; + + gas_scan_init(pp, &tokval, line); + while (gas_scan(pp, &tokval) != TOKEN_EOS) { + if (tokval.t_type == TOKEN_ID) { + yasm_symrec *rec = yasm_symtab_get(pp->defines, tokval.t_charptr); + if (rec) { + int cursor = pp->expr.string_cursor; + int len = strlen(tokval.t_charptr); + char value[64]; + int value_length = sprintf(value, "%ld", eval_expr(pp, tokval.t_charptr)); + int delta = value_length - len; + + line_length += delta; + if (delta > 0) { + line = yasm_xrealloc(line, line_length + 1); + } + memmove(line + cursor - len + value_length, line + cursor, strlen(line + cursor) + 1); + memcpy(line + cursor - len, value, value_length); + pp->expr.string = line; + pp->expr.string_cursor = cursor + delta; + changed = 1; + } + yasm_xfree(pp->expr.symbol); + pp->expr.symbol = NULL; + } + } + gas_scan_cleanup(pp, &tokval); + pp->expr = prev_state; + + if (changed) { + *line_ptr = line; + } + + return changed; +} + +static int process_line(yasm_preproc_gas *pp, char **line_ptr) +{ + macro_entry *macro; + size_t i; + char *line = *line_ptr; + struct { + const char *name; + int nargs; + pp_fn0_t fn; + int param; + } directives[] = { + {"else", 0, FN(eval_else), 0}, + {"elseif", 1, FN(eval_elseif), 0}, + {"endif", 0, FN(eval_endif), 0}, + {"if", 1, FN(eval_if), 0}, + {"ifb", 1, FN(eval_ifb), 0}, + {"ifc", 1, FN(eval_ifc), 0}, + {"ifdef", 1, FN(eval_ifdef), 0}, + {"ifeq", 1, FN(eval_if), 1}, + {"ifeqs", 1, FN(eval_ifeqs), 0}, + {"ifge", 1, FN(eval_ifge), 0}, + {"ifgt", 1, FN(eval_ifgt), 0}, + {"ifle", 1, FN(eval_ifgt), 1}, + {"iflt", 1, FN(eval_ifge), 1}, + {"ifnb", 1, FN(eval_ifb), 1}, + {"ifnc", 1, FN(eval_ifc), 1}, + {"ifndef", 1, FN(eval_ifdef), 1}, + {"ifnotdef", 1, FN(eval_ifdef), 1}, + {"ifne", 1, FN(eval_if), 0}, + {"ifnes", 1, FN(eval_ifeqs), 1}, + {"include", 1, FN(eval_include), 0}, + {"set", 2, FN(eval_set), 1}, + {"equ", 2, FN(eval_set), 1}, + {"equiv", 2, FN(eval_set), 0}, + {"macro", 1, FN(eval_macro), 0}, + {"endm", 0, FN(eval_endm), 0}, + {"rept", 1, FN(eval_rept), 0}, + {"endr", 1, FN(eval_endr), 0}, + }; + + kill_comments(pp, line); + skip_whitespace2(&line); + if (*line == '\0') { + return FALSE; + } + + /* See if this is a macro call. */ + STAILQ_FOREACH(macro, &pp->macros, next) { + const char *remainder = starts_with(line, macro->name); + if (remainder && (!*remainder || isspace(*remainder))) { + skip_whitespace2(&line); + expand_macro(pp, macro, remainder); + return FALSE; + } + } + + for (i = 0; i < sizeof(directives)/sizeof(directives[0]); i++) { + char buf1[1024]; + const char *remainder = matches(line, directives[i].name); + + if (remainder) { + if (pp->skip_depth) { + if (!strncmp("if", directives[i].name, 2)) { + pp->skip_depth++; + } else if (!strcmp("endif", directives[i].name)) { + pp->skip_depth--; + } else if (!strcmp("else", directives[i].name)) { + if (pp->skip_depth == 1) { + pp->skip_depth = 0; + pp->depth++; + } + } + return FALSE; + } else if (directives[i].nargs == 0) { + pp_fn0_t fn = (pp_fn0_t) directives[i].fn; + pp->fatal_error = !fn(pp, directives[i].param); + return FALSE; + } else if (directives[i].nargs == 1) { + pp_fn1_t fn = (pp_fn1_t) directives[i].fn; + skip_whitespace(&remainder); + pp->fatal_error = !fn(pp, directives[i].param, remainder); + return FALSE; + } else if (directives[i].nargs == 2) { + remainder = get_arg(pp, remainder, buf1, sizeof(buf1)); + if (!remainder || !*remainder || !*buf1) { + yasm_error_set(YASM_ERROR_SYNTAX, N_("\".%s\" expects two arguments"), directives[i].name); + yasm_errwarn_propagate(pp->errwarns, pp->current_line_number); + pp->fatal_error = 1; + } else { + pp_fn2_t fn = (pp_fn2_t) directives[i].fn; + pp->fatal_error = !fn(pp, directives[i].param, buf1, remainder); + } + return FALSE; + } + } + } + + if (pp->skip_depth == 0) { + substitute_values(pp, line_ptr); + return TRUE; + } + + return FALSE; +} + +/* Functions exported by the preprocessor. */ + +static yasm_preproc * +gas_preproc_create(const char *in_filename, yasm_symtab *symtab, + yasm_linemap *lm, yasm_errwarns *errwarns) +{ + FILE *f; + yasm_preproc_gas *pp = yasm_xmalloc(sizeof(yasm_preproc_gas)); + + if (strcmp(in_filename, "-") != 0) { + f = fopen(in_filename, "r"); + if (!f) { + yasm__fatal_missing_input_file(N_("Could not open input file"), in_filename); + } + } else { + f = stdin; + } + + pp->preproc.module = &yasm_gas_LTX_preproc; + pp->in = f; + pp->in_filename = yasm__xstrdup(in_filename); + pp->defines = yasm_symtab_create(); + SLIST_INIT(&pp->deferred_defines); + yasm_symtab_set_case_sensitive(pp->defines, 1); + pp->depth = 0; + pp->skip_depth = 0; + pp->in_comment = FALSE; + SLIST_INIT(&pp->buffered_lines); + SLIST_INIT(&pp->included_files); + STAILQ_INIT(&pp->macros); + pp->in_line_number = 0; + pp->next_line_number = 0; + pp->current_line_number = 0; + pp->cur_lm = lm; + pp->errwarns = errwarns; + pp->fatal_error = 0; + pp->detect_errors_only = 0; + + return (yasm_preproc *) pp; +} + +static void +gas_preproc_destroy(yasm_preproc *preproc) +{ + yasm_preproc_gas *pp = (yasm_preproc_gas *) preproc; + yasm_xfree(pp->in_filename); + yasm_symtab_destroy(pp->defines); + while (!SLIST_EMPTY(&pp->deferred_defines)) { + deferred_define *def = SLIST_FIRST(&pp->deferred_defines); + SLIST_REMOVE_HEAD(&pp->deferred_defines, next); + yasm_xfree(def->name); + yasm_xfree(def->value); + yasm_xfree(def); + } + while (!SLIST_EMPTY(&pp->buffered_lines)) { + buffered_line *bline = SLIST_FIRST(&pp->buffered_lines); + SLIST_REMOVE_HEAD(&pp->buffered_lines, next); + yasm_xfree(bline->line); + yasm_xfree(bline); + } + while (!SLIST_EMPTY(&pp->included_files)) { + included_file *inc_file = SLIST_FIRST(&pp->included_files); + SLIST_REMOVE_HEAD(&pp->included_files, next); + yasm_xfree(inc_file->filename); + yasm_xfree(inc_file); + } + while (!STAILQ_EMPTY(&pp->macros)) { + int i; + macro_entry *macro = STAILQ_FIRST(&pp->macros); + STAILQ_REMOVE_HEAD(&pp->macros, next); + yasm_xfree(macro->name); + for (i = 0; i < macro->num_params; i++) + yasm_xfree(macro->params[i]); + yasm_xfree(macro->params); + for (i = 0; i < macro->num_lines; i++) + yasm_xfree(macro->lines[i]); + yasm_xfree(macro->lines); + yasm_xfree(macro); + } + yasm_xfree(preproc); +} + +static char * +gas_preproc_get_line(yasm_preproc *preproc) +{ + yasm_preproc_gas *pp = (yasm_preproc_gas *)preproc; + int done = FALSE; + char *line = NULL; + + pp->current_line_number++; + + do { + if (line != NULL) { + yasm_xfree(line); + } + if (pp->fatal_error) { + return NULL; + } + line = read_line(pp); + if (line == NULL) { + if (pp->in_comment) { + yasm_linemap_set(pp->cur_lm, pp->in_filename, pp->current_line_number, pp->next_line_number, 0); + yasm_warn_set(YASM_WARN_GENERAL, N_("end of file in comment")); + yasm_errwarn_propagate(pp->errwarns, pp->current_line_number); + pp->in_comment = FALSE; + } + return NULL; + } + done = process_line(pp, &line); + } while (!done); + + yasm_linemap_set(pp->cur_lm, pp->in_filename, pp->current_line_number, pp->next_line_number, 0); + + return line; +} + +static size_t +gas_preproc_get_included_file(yasm_preproc *preproc, char *buf, + size_t max_size) +{ + /* TODO */ + return 0; +} + +static void +gas_preproc_add_include_file(yasm_preproc *preproc, const char *filename) +{ + yasm_preproc_gas *pp = (yasm_preproc_gas *) preproc; + eval_include(pp, 0, filename); +} + +static void +gas_preproc_predefine_macro(yasm_preproc *preproc, const char *macronameval) +{ + yasm_preproc_gas *pp = (yasm_preproc_gas *) preproc; + const char *eq = strstr(macronameval, "="); + char *name, *value; + if (eq) { + value = yasm__xstrdup(eq + 1); + name = yasm_xmalloc(eq - macronameval + 1); + memcpy(name, macronameval, eq - macronameval); + name[eq - macronameval] = '\0'; + } else { + name = yasm__xstrdup(macronameval); + value = yasm__xstrdup(""); + } + eval_set(pp, 1, name, value); + yasm_xfree(name); + yasm_xfree(value); +} + +static void +gas_preproc_undefine_macro(yasm_preproc *preproc, const char *macroname) +{ + /* TODO */ +} + +static void +gas_preproc_define_builtin(yasm_preproc *preproc, const char *macronameval) +{ + /* TODO */ +} + +static void +gas_preproc_add_standard(yasm_preproc *preproc, const char **macros) +{ + /* TODO */ +} + + +/* Define preproc structure -- see preproc.h for details */ +yasm_preproc_module yasm_gas_LTX_preproc = { + "GNU AS (GAS)-compatible preprocessor", + "gas", + gas_preproc_create, + gas_preproc_destroy, + gas_preproc_get_line, + gas_preproc_get_included_file, + gas_preproc_add_include_file, + gas_preproc_predefine_macro, + gas_preproc_undefine_macro, + gas_preproc_define_builtin, + gas_preproc_add_standard +}; diff --git a/contrib/tools/yasm/modules/preprocs/nasm/genversion.c b/contrib/tools/yasm/modules/preprocs/nasm/genversion.c new file mode 100644 index 0000000000..164b4d6b51 --- /dev/null +++ b/contrib/tools/yasm/modules/preprocs/nasm/genversion.c @@ -0,0 +1,81 @@ +/* + * + * Generate version.mac + * + * Copyright (C) 2006-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 "config.h" /* for PACKAGE_VERSION */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> + +int +main(int argc, char *argv[]) +{ + FILE *out; + int major, minor, subminor, patchlevel, matched; + + if (argc != 2) { + fprintf(stderr, "Usage: %s <outfile>\n", argv[0]); + return EXIT_FAILURE; + } + + matched = sscanf(PACKAGE_VERSION, "%d.%d.%d.%d", &major, &minor, &subminor, + &patchlevel); + + if (matched == 3) + patchlevel = 0; + else if (matched != 4) { + fprintf(stderr, "Version tokenizing error\n"); + return EXIT_FAILURE; + } + + out = fopen(argv[1], "wt"); + + if (!out) { + fprintf(stderr, "Could not open `%s'.\n", argv[1]); + return EXIT_FAILURE; + } + + fprintf(out, "; This file auto-generated by genversion.c" + " - don't edit it\n"); + + fprintf(out, "%%define __YASM_MAJOR__ %d\n", major); + fprintf(out, "%%define __YASM_MINOR__ %d\n", minor); + fprintf(out, "%%define __YASM_SUBMINOR__ %d\n", subminor); + fprintf(out, "%%define __YASM_BUILD__ %d\n", patchlevel); + fprintf(out, "%%define __YASM_PATCHLEVEL__ %d\n", patchlevel); + + /* Version id (hex number) */ + fprintf(out, "%%define __YASM_VERSION_ID__ 0%02x%02x%02x%02xh\n", major, + minor, subminor, patchlevel); + + /* Version string */ + fprintf(out, "%%define __YASM_VER__ \"%s\"\n", PACKAGE_VERSION); + fclose(out); + + return EXIT_SUCCESS; +} diff --git a/contrib/tools/yasm/modules/preprocs/nasm/nasm-eval.c b/contrib/tools/yasm/modules/preprocs/nasm/nasm-eval.c new file mode 100644 index 0000000000..e249484cd5 --- /dev/null +++ b/contrib/tools/yasm/modules/preprocs/nasm/nasm-eval.c @@ -0,0 +1,441 @@ +/* eval.c expression evaluator for the Netwide Assembler + * + * The Netwide Assembler is copyright (C) 1996 Simon Tatham and + * Julian Hall. All rights reserved. The software is + * redistributable under the licence given in the file "Licence" + * distributed in the NASM archive. + * + * initial version 27/iii/95 by Simon Tatham + */ +#include <util.h> +#include <libyasm-stdint.h> +#include <libyasm/coretype.h> +#include <libyasm/intnum.h> +#include <libyasm/expr.h> +#include <libyasm/symrec.h> +#include <ctype.h> + +#include "nasm.h" +#include "nasmlib.h" +#include "nasm-eval.h" + +/* The assembler symbol table. */ +extern yasm_symtab *nasm_symtab; + +static scanner scan; /* Address of scanner routine */ +static efunc error; /* Address of error reporting routine */ + +static struct tokenval *tokval; /* The current token */ +static int i; /* The t_type of tokval */ + +static void *scpriv; + +/* + * Recursive-descent parser. Called with a single boolean operand, + * which is TRUE if the evaluation is critical (i.e. unresolved + * symbols are an error condition). Must update the global `i' to + * reflect the token after the parsed string. May return NULL. + * + * evaluate() should report its own errors: on return it is assumed + * that if NULL has been returned, the error has already been + * reported. + */ + +/* + * Grammar parsed is: + * + * expr : bexpr [ WRT expr6 ] + * bexpr : rexp0 or expr0 depending on relative-mode setting + * rexp0 : rexp1 [ {||} rexp1...] + * rexp1 : rexp2 [ {^^} rexp2...] + * rexp2 : rexp3 [ {&&} rexp3...] + * rexp3 : expr0 [ {=,==,<>,!=,<,>,<=,>=} expr0 ] + * expr0 : expr1 [ {|} expr1...] + * expr1 : expr2 [ {^} expr2...] + * expr2 : expr3 [ {&} expr3...] + * expr3 : expr4 [ {<<,>>} expr4...] + * expr4 : expr5 [ {+,-} expr5...] + * expr5 : expr6 [ {*,/,%,//,%%} expr6...] + * expr6 : { ~,+,-,SEG } expr6 + * | (bexpr) + * | symbol + * | $ + * | number + */ + +static yasm_expr *rexp0(void), *rexp1(void), *rexp2(void), *rexp3(void); + +static yasm_expr *expr0(void), *expr1(void), *expr2(void), *expr3(void); +static yasm_expr *expr4(void), *expr5(void), *expr6(void); + +static yasm_expr *(*bexpr)(void); + +static yasm_expr *rexp0(void) +{ + yasm_expr *e, *f; + + e = rexp1(); + if (!e) + return NULL; + + while (i == TOKEN_DBL_OR) + { + i = scan(scpriv, tokval); + f = rexp1(); + if (!f) { + yasm_expr_destroy(e); + return NULL; + } + + e = yasm_expr_create_tree(e, YASM_EXPR_LOR, f, 0); + } + return e; +} + +static yasm_expr *rexp1(void) +{ + yasm_expr *e, *f; + + e = rexp2(); + if (!e) + return NULL; + + while (i == TOKEN_DBL_XOR) + { + i = scan(scpriv, tokval); + f = rexp2(); + if (!f) { + yasm_expr_destroy(e); + return NULL; + } + + e = yasm_expr_create_tree(e, YASM_EXPR_LXOR, f, 0); + } + return e; +} + +static yasm_expr *rexp2(void) +{ + yasm_expr *e, *f; + + e = rexp3(); + if (!e) + return NULL; + while (i == TOKEN_DBL_AND) + { + i = scan(scpriv, tokval); + f = rexp3(); + if (!f) { + yasm_expr_destroy(e); + return NULL; + } + + e = yasm_expr_create_tree(e, YASM_EXPR_LAND, f, 0); + } + return e; +} + +static yasm_expr *rexp3(void) +{ + yasm_expr *e, *f; + + e = expr0(); + if (!e) + return NULL; + + while (i == TOKEN_EQ || i == TOKEN_LT || i == TOKEN_GT || + i == TOKEN_NE || i == TOKEN_LE || i == TOKEN_GE) + { + int j = i; + i = scan(scpriv, tokval); + f = expr0(); + if (!f) { + yasm_expr_destroy(e); + return NULL; + } + + switch (j) + { + case TOKEN_EQ: + e = yasm_expr_create_tree(e, YASM_EXPR_EQ, f, 0); + break; + case TOKEN_LT: + e = yasm_expr_create_tree(e, YASM_EXPR_LT, f, 0); + break; + case TOKEN_GT: + e = yasm_expr_create_tree(e, YASM_EXPR_GT, f, 0); + break; + case TOKEN_NE: + e = yasm_expr_create_tree(e, YASM_EXPR_NE, f, 0); + break; + case TOKEN_LE: + e = yasm_expr_create_tree(e, YASM_EXPR_LE, f, 0); + break; + case TOKEN_GE: + e = yasm_expr_create_tree(e, YASM_EXPR_GE, f, 0); + break; + } + } + return e; +} + +static yasm_expr *expr0(void) +{ + yasm_expr *e, *f; + + e = expr1(); + if (!e) + return NULL; + + while (i == '|') + { + i = scan(scpriv, tokval); + f = expr1(); + if (!f) { + yasm_expr_destroy(e); + return NULL; + } + + e = yasm_expr_create_tree(e, YASM_EXPR_OR, f, 0); + } + return e; +} + +static yasm_expr *expr1(void) +{ + yasm_expr *e, *f; + + e = expr2(); + if (!e) + return NULL; + + while (i == '^') { + i = scan(scpriv, tokval); + f = expr2(); + if (!f) { + yasm_expr_destroy(e); + return NULL; + } + + e = yasm_expr_create_tree(e, YASM_EXPR_XOR, f, 0); + } + return e; +} + +static yasm_expr *expr2(void) +{ + yasm_expr *e, *f; + + e = expr3(); + if (!e) + return NULL; + + while (i == '&') { + i = scan(scpriv, tokval); + f = expr3(); + if (!f) { + yasm_expr_destroy(e); + return NULL; + } + + e = yasm_expr_create_tree(e, YASM_EXPR_AND, f, 0); + } + return e; +} + +static yasm_expr *expr3(void) +{ + yasm_expr *e, *f; + + e = expr4(); + if (!e) + return NULL; + + while (i == TOKEN_SHL || i == TOKEN_SHR) + { + int j = i; + i = scan(scpriv, tokval); + f = expr4(); + if (!f) { + yasm_expr_destroy(e); + return NULL; + } + + switch (j) { + case TOKEN_SHL: + e = yasm_expr_create_tree(e, YASM_EXPR_SHL, f, 0); + break; + case TOKEN_SHR: + e = yasm_expr_create_tree(e, YASM_EXPR_SHR, f, 0); + break; + } + } + return e; +} + +static yasm_expr *expr4(void) +{ + yasm_expr *e, *f; + + e = expr5(); + if (!e) + return NULL; + while (i == '+' || i == '-') + { + int j = i; + i = scan(scpriv, tokval); + f = expr5(); + if (!f) { + yasm_expr_destroy(e); + return NULL; + } + switch (j) { + case '+': + e = yasm_expr_create_tree(e, YASM_EXPR_ADD, f, 0); + break; + case '-': + e = yasm_expr_create_tree(e, YASM_EXPR_SUB, f, 0); + break; + } + } + return e; +} + +static yasm_expr *expr5(void) +{ + yasm_expr *e, *f; + + e = expr6(); + if (!e) + return NULL; + while (i == '*' || i == '/' || i == '%' || + i == TOKEN_SDIV || i == TOKEN_SMOD) + { + int j = i; + i = scan(scpriv, tokval); + f = expr6(); + if (!f) { + yasm_expr_destroy(e); + return NULL; + } + switch (j) { + case '*': + e = yasm_expr_create_tree(e, YASM_EXPR_MUL, f, 0); + break; + case '/': + e = yasm_expr_create_tree(e, YASM_EXPR_DIV, f, 0); + break; + case '%': + e = yasm_expr_create_tree(e, YASM_EXPR_MOD, f, 0); + break; + case TOKEN_SDIV: + e = yasm_expr_create_tree(e, YASM_EXPR_SIGNDIV, f, 0); + break; + case TOKEN_SMOD: + e = yasm_expr_create_tree(e, YASM_EXPR_SIGNMOD, f, 0); + break; + } + } + return e; +} + +static yasm_expr *expr6(void) +{ + yasm_expr *e = NULL; + + if (i == '-') { + i = scan(scpriv, tokval); + e = expr6(); + if (!e) + return NULL; + return yasm_expr_create_branch(YASM_EXPR_NEG, e, 0); + } else if (i == '+') { + i = scan(scpriv, tokval); + return expr6(); + } else if (i == '~') { + i = scan(scpriv, tokval); + e = expr6(); + if (!e) + return NULL; + return yasm_expr_create_branch(YASM_EXPR_NOT, e, 0); + } else if (i == TOKEN_SEG) { + i = scan(scpriv, tokval); + e = expr6(); + if (!e) + return NULL; + error(ERR_NONFATAL, "%s not supported", "SEG"); + return e; + } else if (i == '(') { + i = scan(scpriv, tokval); + e = bexpr(); + if (!e) + return NULL; + if (i != ')') { + error(ERR_NONFATAL, "expecting `)'"); + return NULL; + } + i = scan(scpriv, tokval); + return e; + } + else if (i == TOKEN_NUM || i == TOKEN_ID || + i == TOKEN_HERE || i == TOKEN_BASE) + { + switch (i) { + case TOKEN_NUM: + e = yasm_expr_create_ident(yasm_expr_int(tokval->t_integer), 0); + break; + case TOKEN_ID: + if (nasm_symtab) { + yasm_symrec *sym = + yasm_symtab_get(nasm_symtab, tokval->t_charptr); + if (sym) { + e = yasm_expr_create_ident(yasm_expr_sym(sym), 0); + } else { + error(ERR_NONFATAL, + "undefined symbol `%s' in preprocessor", + tokval->t_charptr); + e = yasm_expr_create_ident(yasm_expr_int( + yasm_intnum_create_int(1)), 0); + } + break; + } + /*fallthrough*/ + case TOKEN_HERE: + case TOKEN_BASE: + error(ERR_NONFATAL, + "cannot reference symbol `%s' in preprocessor", + (i == TOKEN_ID ? tokval->t_charptr : + i == TOKEN_HERE ? "$" : "$$")); + e = yasm_expr_create_ident(yasm_expr_int(yasm_intnum_create_int(1)), + 0); + break; + } + i = scan(scpriv, tokval); + return e; + } else { + error(ERR_NONFATAL, "expression syntax error"); + return NULL; + } +} + +yasm_expr *nasm_evaluate (scanner sc, void *scprivate, struct tokenval *tv, + int critical, efunc report_error) +{ + if (critical & CRITICAL) { + critical &= ~CRITICAL; + bexpr = rexp0; + } else + bexpr = expr0; + + scan = sc; + scpriv = scprivate; + tokval = tv; + error = report_error; + + if (tokval->t_type == TOKEN_INVALID) + i = scan(scpriv, tokval); + else + i = tokval->t_type; + + return bexpr (); +} diff --git a/contrib/tools/yasm/modules/preprocs/nasm/nasm-eval.h b/contrib/tools/yasm/modules/preprocs/nasm/nasm-eval.h new file mode 100644 index 0000000000..f06937c5cc --- /dev/null +++ b/contrib/tools/yasm/modules/preprocs/nasm/nasm-eval.h @@ -0,0 +1,18 @@ +/* eval.h header file for eval.c + * + * The Netwide Assembler is copyright (C) 1996 Simon Tatham and + * Julian Hall. All rights reserved. The software is + * redistributable under the licence given in the file "Licence" + * distributed in the NASM archive. + */ + +#ifndef NASM_EVAL_H +#define NASM_EVAL_H + +/* + * The evaluator itself. + */ +yasm_expr *nasm_evaluate (scanner sc, void *scprivate, struct tokenval *tv, + int critical, efunc report_error); + +#endif diff --git a/contrib/tools/yasm/modules/preprocs/nasm/nasm-pp.c b/contrib/tools/yasm/modules/preprocs/nasm/nasm-pp.c new file mode 100644 index 0000000000..27a8cc6c93 --- /dev/null +++ b/contrib/tools/yasm/modules/preprocs/nasm/nasm-pp.c @@ -0,0 +1,5317 @@ +/* -*- mode: c; c-file-style: "bsd" -*- */ +/* preproc.c macro preprocessor for the Netwide Assembler + * + * The Netwide Assembler is copyright (C) 1996 Simon Tatham and + * Julian Hall. All rights reserved. The software is + * redistributable under the licence given in the file "Licence" + * distributed in the NASM archive. + * + * initial version 18/iii/97 by Simon Tatham + */ + +/* Typical flow of text through preproc + * + * pp_getline gets tokenised lines, either + * + * from a macro expansion + * + * or + * { + * read_line gets raw text from stdmacpos, or predef, or current input file + * tokenise converts to tokens + * } + * + * expand_mmac_params is used to expand %1 etc., unless a macro is being + * defined or a false conditional is being processed + * (%0, %1, %+1, %-1, %%foo + * + * do_directive checks for directives + * + * expand_smacro is used to expand single line macros + * + * expand_mmacro is used to expand multi-line macros + * + * detoken is used to convert the line back to text + */ +#include <util.h> +#include <libyasm-stdint.h> +#include <libyasm/coretype.h> +#include <libyasm/intnum.h> +#include <libyasm/expr.h> +#include <libyasm/file.h> +#include <stdarg.h> +#include <ctype.h> +#include <limits.h> + +#include "nasm.h" +#include "nasmlib.h" +#include "nasm-pp.h" + +typedef struct SMacro SMacro; +typedef struct MMacro MMacro; +typedef struct Context Context; +typedef struct Token Token; +typedef struct Blocks Blocks; +typedef struct Line Line; +typedef struct Include Include; +typedef struct Cond Cond; + +/* + * Store the definition of a single-line macro. + */ +struct SMacro +{ + SMacro *next; + char *name; + int level; + int casesense; + int nparam; + int in_progress; + Token *expansion; +}; + +/* + * Store the definition of a multi-line macro. This is also used to + * store the interiors of `%rep...%endrep' blocks, which are + * effectively self-re-invoking multi-line macros which simply + * don't have a name or bother to appear in the hash tables. %rep + * blocks are signified by having a NULL `name' field. + * + * In a MMacro describing a `%rep' block, the `in_progress' field + * isn't merely boolean, but gives the number of repeats left to + * run. + * + * The `next' field is used for storing MMacros in hash tables; the + * `next_active' field is for stacking them on istk entries. + * + * When a MMacro is being expanded, `params', `iline', `nparam', + * `paramlen', `rotate' and `unique' are local to the invocation. + */ +struct MMacro +{ + MMacro *next; + char *name; + int casesense; + long nparam_min, nparam_max; + int plus; /* is the last parameter greedy? */ + int nolist; /* is this macro listing-inhibited? */ + int in_progress; + Token *dlist; /* All defaults as one list */ + Token **defaults; /* Parameter default pointers */ + int ndefs; /* number of default parameters */ + Line *expansion; + + MMacro *next_active; + MMacro *rep_nest; /* used for nesting %rep */ + Token **params; /* actual parameters */ + Token *iline; /* invocation line */ + long nparam, rotate, *paramlen; + unsigned long unique; + int lineno; /* Current line number on expansion */ +}; + +/* + * The context stack is composed of a linked list of these. + */ +struct Context +{ + Context *next; + SMacro *localmac; + char *name; + unsigned long number; +}; + +/* + * This is the internal form which we break input lines up into. + * Typically stored in linked lists. + * + * Note that `type' serves a double meaning: TOK_SMAC_PARAM is not + * necessarily used as-is, but is intended to denote the number of + * the substituted parameter. So in the definition + * + * %define a(x,y) ( (x) & ~(y) ) + * + * the token representing `x' will have its type changed to + * TOK_SMAC_PARAM, but the one representing `y' will be + * TOK_SMAC_PARAM+1. + * + * TOK_INTERNAL_STRING is a dirty hack: it's a single string token + * which doesn't need quotes around it. Used in the pre-include + * mechanism as an alternative to trying to find a sensible type of + * quote to use on the filename we were passed. + */ +struct Token +{ + Token *next; + char *text; + SMacro *mac; /* associated macro for TOK_SMAC_END */ + int type; +}; +enum +{ + TOK_WHITESPACE = 1, TOK_COMMENT, TOK_ID, TOK_PREPROC_ID, TOK_STRING, + TOK_NUMBER, TOK_SMAC_END, TOK_OTHER, TOK_SMAC_PARAM, + TOK_INTERNAL_STRING +}; + +/* + * Multi-line macro definitions are stored as a linked list of + * these, which is essentially a container to allow several linked + * lists of Tokens. + * + * Note that in this module, linked lists are treated as stacks + * wherever possible. For this reason, Lines are _pushed_ on to the + * `expansion' field in MMacro structures, so that the linked list, + * if walked, would give the macro lines in reverse order; this + * means that we can walk the list when expanding a macro, and thus + * push the lines on to the `expansion' field in _istk_ in reverse + * order (so that when popped back off they are in the right + * order). It may seem cockeyed, and it relies on my design having + * an even number of steps in, but it works... + * + * Some of these structures, rather than being actual lines, are + * markers delimiting the end of the expansion of a given macro. + * This is for use in the cycle-tracking and %rep-handling code. + * Such structures have `finishes' non-NULL, and `first' NULL. All + * others have `finishes' NULL, but `first' may still be NULL if + * the line is blank. + */ +struct Line +{ + Line *next; + MMacro *finishes; + Token *first; +}; + +/* + * To handle an arbitrary level of file inclusion, we maintain a + * stack (ie linked list) of these things. + */ +struct Include +{ + Include *next; + FILE *fp; + Cond *conds; + Line *expansion; + char *fname; + int lineno, lineinc; + MMacro *mstk; /* stack of active macros/reps */ +}; + +/* + * Conditional assembly: we maintain a separate stack of these for + * each level of file inclusion. (The only reason we keep the + * stacks separate is to ensure that a stray `%endif' in a file + * included from within the true branch of a `%if' won't terminate + * it and cause confusion: instead, rightly, it'll cause an error.) + */ +struct Cond +{ + Cond *next; + int state; +}; +enum +{ + /* + * These states are for use just after %if or %elif: IF_TRUE + * means the condition has evaluated to truth so we are + * currently emitting, whereas IF_FALSE means we are not + * currently emitting but will start doing so if a %else comes + * up. In these states, all directives are admissible: %elif, + * %else and %endif. (And of course %if.) + */ + COND_IF_TRUE, COND_IF_FALSE, + /* + * These states come up after a %else: ELSE_TRUE means we're + * emitting, and ELSE_FALSE means we're not. In ELSE_* states, + * any %elif or %else will cause an error. + */ + COND_ELSE_TRUE, COND_ELSE_FALSE, + /* + * This state means that we're not emitting now, and also that + * nothing until %endif will be emitted at all. It's for use in + * two circumstances: (i) when we've had our moment of emission + * and have now started seeing %elifs, and (ii) when the + * condition construct in question is contained within a + * non-emitting branch of a larger condition construct. + */ + COND_NEVER +}; +#define emitting(x) ( (x) == COND_IF_TRUE || (x) == COND_ELSE_TRUE ) + +/* + * These defines are used as the possible return values for do_directive + */ +#define NO_DIRECTIVE_FOUND 0 +#define DIRECTIVE_FOUND 1 + +/* + * Condition codes. Note that we use c_ prefix not C_ because C_ is + * used in nasm.h for the "real" condition codes. At _this_ level, + * we treat CXZ and ECXZ as condition codes, albeit non-invertible + * ones, so we need a different enum... + */ +static const char *conditions[] = { + "a", "ae", "b", "be", "c", "cxz", "e", "ecxz", "g", "ge", "l", "le", + "na", "nae", "nb", "nbe", "nc", "ne", "ng", "nge", "nl", "nle", "no", + "np", "ns", "nz", "o", "p", "pe", "po", "s", "z" +}; +enum +{ + c_A, c_AE, c_B, c_BE, c_C, c_CXZ, c_E, c_ECXZ, c_G, c_GE, c_L, c_LE, + c_NA, c_NAE, c_NB, c_NBE, c_NC, c_NE, c_NG, c_NGE, c_NL, c_NLE, c_NO, + c_NP, c_NS, c_NZ, c_O, c_P, c_PE, c_PO, c_S, c_Z +}; +static int inverse_ccs[] = { + c_NA, c_NAE, c_NB, c_NBE, c_NC, -1, c_NE, -1, c_NG, c_NGE, c_NL, c_NLE, + c_A, c_AE, c_B, c_BE, c_C, c_E, c_G, c_GE, c_L, c_LE, c_O, c_P, c_S, + c_Z, c_NO, c_NP, c_PO, c_PE, c_NS, c_NZ +}; + +/* + * Directive names. + */ +static const char *directives[] = { + "%arg", + "%assign", "%clear", "%define", "%elif", "%elifctx", "%elifdef", + "%elifid", "%elifidn", "%elifidni", "%elifmacro", "%elifnctx", "%elifndef", + "%elifnid", "%elifnidn", "%elifnidni", "%elifnmacro", "%elifnnum", "%elifnstr", + "%elifnum", "%elifstr", "%else", "%endif", "%endm", "%endmacro", + "%endrep", "%endscope", "%error", "%exitrep", "%iassign", "%idefine", "%if", + "%ifctx", "%ifdef", "%ifid", "%ifidn", "%ifidni", "%ifmacro", "%ifnctx", + "%ifndef", "%ifnid", "%ifnidn", "%ifnidni", "%ifnmacro", "%ifnnum", + "%ifnstr", "%ifnum", "%ifstr", "%imacro", "%include", + "%ixdefine", "%line", + "%local", + "%macro", "%pop", "%push", "%rep", "%repl", "%rotate", + "%scope", "%stacksize", + "%strlen", "%substr", "%undef", "%xdefine" +}; +enum +{ + PP_ARG, + PP_ASSIGN, PP_CLEAR, PP_DEFINE, PP_ELIF, PP_ELIFCTX, PP_ELIFDEF, + PP_ELIFID, PP_ELIFIDN, PP_ELIFIDNI, PP_ELIFMACRO, PP_ELIFNCTX, PP_ELIFNDEF, + PP_ELIFNID, PP_ELIFNIDN, PP_ELIFNIDNI, PP_ELIFNMACRO, PP_ELIFNNUM, PP_ELIFNSTR, + PP_ELIFNUM, PP_ELIFSTR, PP_ELSE, PP_ENDIF, PP_ENDM, PP_ENDMACRO, + PP_ENDREP, PP_ENDSCOPE, PP_ERROR, PP_EXITREP, PP_IASSIGN, PP_IDEFINE, PP_IF, + PP_IFCTX, PP_IFDEF, PP_IFID, PP_IFIDN, PP_IFIDNI, PP_IFMACRO, PP_IFNCTX, + PP_IFNDEF, PP_IFNID, PP_IFNIDN, PP_IFNIDNI, PP_IFNMACRO, PP_IFNNUM, + PP_IFNSTR, PP_IFNUM, PP_IFSTR, PP_IMACRO, PP_INCLUDE, + PP_IXDEFINE, PP_LINE, + PP_LOCAL, + PP_MACRO, PP_POP, PP_PUSH, PP_REP, PP_REPL, PP_ROTATE, + PP_SCOPE, PP_STACKSIZE, + PP_STRLEN, PP_SUBSTR, PP_UNDEF, PP_XDEFINE +}; + +/* If this is a an IF, ELIF, ELSE or ENDIF keyword */ +static int is_condition(int arg) +{ + return ((arg >= PP_ELIF) && (arg <= PP_ENDIF)) || + ((arg >= PP_IF) && (arg <= PP_IFSTR)); +} + +/* For TASM compatibility we need to be able to recognise TASM compatible + * conditional compilation directives. Using the NASM pre-processor does + * not work, so we look for them specifically from the following list and + * then jam in the equivalent NASM directive into the input stream. + */ + +#ifndef MAX +# define MAX(a,b) ( ((a) > (b)) ? (a) : (b)) +#endif + +enum +{ + TM_ARG, TM_ELIF, TM_ELSE, TM_ENDIF, TM_IF, TM_IFDEF, TM_IFDIFI, + TM_IFNDEF, TM_INCLUDE, TM_LOCAL, + TM_REPT, TM_IRP, TM_MACRO, + TM_STRUC, TM_SEGMENT +}; + +static const char *tasm_directives[] = { + "arg", "elif", "else", "endif", "if", "ifdef", "ifdifi", + "ifndef", "include", "local" +}; + +static int StackSize = 4; +static const char *StackPointer = "ebp"; +static int ArgOffset = 8; +static int LocalOffset = 4; +static int Level = 0; + + +static Context *cstk; +static Include *istk; + +static FILE *first_fp = NULL; + +static efunc _error; /* Pointer to client-provided error reporting function */ +static evalfunc evaluate; + +static int pass; /* HACK: pass 0 = generate dependencies only */ + +static unsigned long unique; /* unique identifier numbers */ + +static Line *builtindef = NULL; +static Line *stddef = NULL; +static Line *predef = NULL; +static int first_line = 1; + +static ListGen *list; + +/* + * The number of hash values we use for the macro lookup tables. + * FIXME: We should *really* be able to configure this at run time, + * or even have the hash table automatically expanding when necessary. + */ +#define NHASH 4096 + +/* + * The current set of multi-line macros we have defined. + */ +static MMacro *mmacros[NHASH]; + +/* + * The current set of single-line macros we have defined. + */ +static SMacro *smacros[NHASH]; + +/* + * The multi-line macro we are currently defining, or the %rep + * block we are currently reading, if any. + */ +static MMacro *defining; + +/* + * The number of macro parameters to allocate space for at a time. + */ +#define PARAM_DELTA 16 + +/* + * Macros to make NASM ignore some TASM directives before the first include + * directive. + */ +static const char *tasm_compat_macros[] = +{ + "%idefine IDEAL", + "%idefine JUMPS", + "%idefine END", + "%idefine P8086 CPU 8086", + "%idefine P186 CPU 186", + "%idefine P286 CPU 286", + "%idefine P286N CPU 286", + "%idefine P286P CPU 286 Priv", + "%idefine P386 CPU 386", + "%idefine P386N CPU 386", + "%idefine P386P CPU 386 Priv", + "%idefine P486 CPU 486", + "%idefine P586 CPU 586", + "%idefine .8086 CPU 8086", + "%idefine .186 CPU 186", + "%idefine .286 CPU 286", + "%idefine .286C CPU 286", + "%idefine .286P CPU 286", + "%idefine .386 CPU 386", + "%idefine .386C CPU 386", + "%idefine .386P CPU 386", + "%idefine .486 CPU 486", + "%idefine .486C CPU 486", + "%idefine .486P CPU 486", + "%idefine .586 CPU 586", + "%idefine .586C CPU 586", + "%idefine .586P CPU 586", + "", + "%imacro TITLE 1", + "%endm", + "%imacro NAME 1", + "%endm", + "", + "%imacro EXTRN 1-*.nolist", + "%rep %0", + "[extern %1]", + "%rotate 1", + "%endrep", + "%endmacro", + "", + "%imacro PUBLIC 1-*.nolist", + "%rep %0", + "[global %1]", + "%rotate 1", + "%endrep", + "%endmacro", + "", + "; this is not needed", + "%idefine PTR", + NULL +}; + +static int nested_mac_count, nested_rep_count; + +/* + * Tokens are allocated in blocks to improve speed + */ +#define TOKEN_BLOCKSIZE 4096 +static Token *freeTokens = NULL; +struct Blocks { + Blocks *next; + void *chunk; +}; + +static Blocks blocks = { NULL, NULL }; + +/* + * Forward declarations. + */ +static Token *expand_mmac_params(Token * tline); +static Token *expand_smacro(Token * tline); +static Token *expand_id(Token * tline); +static Context *get_ctx(char *name, int all_contexts); +static void make_tok_num(Token * tok, yasm_intnum *val); +static void error(int severity, const char *fmt, ...); +static void *new_Block(size_t size); +static void delete_Blocks(void); +static Token *new_Token(Token * next, int type, const char *text, + size_t txtlen); +static Token *delete_Token(Token * t); +static Token *tokenise(char *line); + +/* + * Macros for safe checking of token pointers, avoid *(NULL) + */ +#define tok_type_(x,t) ((x) && (x)->type == (t)) +#define skip_white_(x) if (tok_type_((x), TOK_WHITESPACE)) (x)=(x)->next +#define tok_is_(x,v) (tok_type_((x), TOK_OTHER) && !strcmp((x)->text,(v))) +#define tok_isnt_(x,v) ((x) && ((x)->type!=TOK_OTHER || strcmp((x)->text,(v)))) + +/* Handle TASM specific directives, which do not contain a % in + * front of them. We do it here because I could not find any other + * place to do it for the moment, and it is a hack (ideally it would + * be nice to be able to use the NASM pre-processor to do it). + */ + +typedef struct TMEndItem { + int type; + void *data; + struct TMEndItem *next; +} TMEndItem; + +static TMEndItem *EndmStack = NULL, *EndsStack = NULL; + +char **TMParameters; + +struct TStrucField { + char *name; + char *type; + struct TStrucField *next; +}; +struct TStruc { + char *name; + struct TStrucField *fields, *lastField; + struct TStruc *next; +}; +static struct TStruc *TStrucs = NULL; +static int inTstruc = 0; + +struct TSegmentAssume { + char *segreg; + char *segment; +}; +struct TSegmentAssume *TAssumes; + +const char *tasm_get_segment_register(const char *segment) +{ + struct TSegmentAssume *assume; + if (!TAssumes) + return NULL; + for (assume = TAssumes; assume->segreg; assume++) { + if (!strcmp(assume->segment, segment)) + break; + } + return assume->segreg; +} + +static char * +check_tasm_directive(char *line) +{ + int i, j, k, m; + size_t len, len2; + char *p, *oldline, oldchar, *q, oldchar2; + TMEndItem *end; + + p = line; + + /* Skip whitespace */ + while (isspace(*p) && *p != 0 && *p != ';') + p++; + + /* Ignore nasm directives */ + if (*p == '%') + return line; + + /* Binary search for the directive name */ + len = 0; + while (!isspace(p[len]) && p[len] != 0 && p[len] != ';') + len++; + if (!len) + return line; + + oldchar = p[len]; + p[len] = 0; + i = -1; + j = elements(tasm_directives); + while (j - i > 1) + { + k = (j + i) / 2; + m = nasm_stricmp(p, tasm_directives[k]); + if (m == 0) + { + /* We have found a directive, so jam a % in front of it + * so that NASM will then recognise it as one if it's own. + */ + p[len] = oldchar; + len = strlen(p); + oldline = line; + if (k == TM_IFDIFI) + { + /* NASM does not recognise IFDIFI, so we convert it to + * %ifdef BOGUS. This is not used in NASM comaptible + * code, but does need to parse for the TASM macro + * package. + */ + line = nasm_malloc(13); + strcpy(line, "%ifdef BOGUS"); + } + else if (k == TM_INCLUDE) + { + /* add double quotes around file name */ + p += 7 + 1; + while (isspace(*p) && *p) + p++; + len = strlen(p); + line = nasm_malloc(1 + 7 + 1 + 1 + len + 1 + 1); + sprintf(line, "%%include \"%s\"", p); + } + else + { + line = nasm_malloc(len + 2); + line[0] = '%'; + memcpy(line + 1, p, len + 1); + } + nasm_free(oldline); + return line; + } + else if (m < 0) + { + j = k; + } + else + i = k; + } + + /* Not a simple directive */ + + if (!nasm_stricmp(p, "endm")) { + /* handle end of endm directive */ + char **parameter; + end = EndmStack; + /* undef parameters */ + if (!end) { + error(ERR_FATAL, "ENDM: not in an endm context"); + return line; + } + EndmStack = EndmStack->next; + nasm_free(line); + switch (end->type) { + case TM_MACRO: + len = 0; + for (parameter = end->data; *parameter; parameter++) + len += 6 + 1 + strlen(*parameter) + 1; + len += 5 + 1; + line = nasm_malloc(len); + p = line; + for (parameter = end->data; *parameter; parameter++) { + p += sprintf(p, "%%undef %s\n", *parameter); + nasm_free(*parameter); + } + nasm_free(end->data); + nasm_free(end); + sprintf(p, "%%endm"); + return line; + case TM_REPT: + nasm_free(end); + return nasm_strdup("%endrep"); + case TM_IRP: { + char **data; + const char *irp_format = + "%%undef %s\n" + "%%rotate 1\n" + "%%endrep\n" + "%%endm\n" + "irp %s\n" + "%%undef irp"; + data = end->data; + line = nasm_malloc(strlen(irp_format) - 4 + strlen(data[0]) + + strlen(data[1])); + sprintf(line, irp_format, data[0], data[1]); + nasm_free(data[0]); + nasm_free(data[1]); + nasm_free(data); + return line; + } + default: + error(ERR_FATAL, "ENDM: bogus endm context type %d\n",end->type); + return NULL; + } + } else if (!nasm_stricmp(p, "end")) { + nasm_free(line); + return nasm_strdup(""); + } else if (!nasm_stricmp(p, "rept")) { + /* handle repeat directive */ + end = nasm_malloc(sizeof(*end)); + end->type = TM_REPT; + end->next = EndmStack; + EndmStack = end; + memcpy(p, "%rep", 4); + p[len] = oldchar; + return line; + } else if (!nasm_stricmp(p, "locals")) { + tasm_locals = 1; + nasm_free(line); + return nasm_strdup(""); + } + + if (!oldchar) + return line; + + /* handle two-words directives */ + q = p + len + 1; + /* Skip whitespaces */ + while (isspace(*q) && *q) + q++; + + len2 = 0; + while (!isspace(q[len2]) && q[len2]!=',' && q[len2] != 0) + len2++; + oldchar2 = q[len2]; + q[len2] = '\0'; + + if (!nasm_stricmp(p, "irp")) { + /* handle indefinite repeat directive */ + const char *irp_format = + "%%imacro irp 0-*\n" + "%%rep %%0\n" + "%%define %s %%1\n"; + char **data; + + data = malloc(2*sizeof(char*)); + oldline = line; + line = nasm_malloc(strlen(irp_format) - 2 + len2 + 1); + sprintf(line,irp_format,q); + data[0] = nasm_strdup(q); + + if (!oldchar2) + error(ERR_FATAL, "%s: expected <values>", q + len2); + p = strchr(q + len2 + 1, '<'); + if (!p) + error(ERR_FATAL, "%s: expected <values>", q + len2); + p++; + q = strchr(p, '>'); + data[1] = nasm_strndup(p, q - p); + + end = nasm_malloc(sizeof(*end)); + end->type = TM_IRP; + end->next = EndmStack; + end->data = data; + EndmStack = end; + + nasm_free(oldline); + return line; + } else if (!nasm_stricmp(q, "macro")) { + char *name = p; + /* handle MACRO */ + /* count parameters */ + j = 1; + i = 0; + TMParameters = nasm_malloc(j*sizeof(*TMParameters)); + len = 0; + p = q + len2 + 1; + /* Skip whitespaces */ + while (isspace(*p) && *p) + p++; + while (*p) { + /* Get parameter name */ + for (q = p; !isspace(*q) && *q != ',' && *q; q++); + len2 = q-p; + if (len2 == 0) + error(ERR_FATAL, "'%s': expected parameter name", p); + TMParameters[i] = nasm_malloc(len2 + 1); + memcpy(TMParameters[i], p, len2); + TMParameters[i][len2] = '\0'; + len += len2; + i++; + if (i + 1 > j) { + j *= 2; + TMParameters = nasm_realloc(TMParameters, + j*sizeof(*TMParameters)); + } + if (i == 1000) + error(ERR_FATAL, "too many parameters for macro %s", name); + p = q; + while (isspace(*p) && *p) + p++; + if (!*p) + break; + if (*p != ',') + error(ERR_FATAL, "expected comma"); + p++; + while (isspace(*p) && *p) + p++; + } + TMParameters[i] = NULL; + TMParameters = nasm_realloc(TMParameters, + (i+1)*sizeof(*TMParameters)); + len += 1 + 6 + 1 + strlen(name) + 1 + 3; /* macro definition */ + len += i * (1 + 9 + 1 + 1 + 1 + 3 + 2); /* macro parameter definition */ + oldline = line; + p = line = nasm_malloc(len + 1); + p += sprintf(p, "%%imacro %s 0-*", name); + nasm_free(oldline); + for (j = 0; TMParameters[j]; j++) { + p += sprintf(p, "\n%%idefine %s %%{%-u}", TMParameters[j], j + 1); + } + end = nasm_malloc(sizeof(*end)); + end->type = TM_MACRO; + end->next = EndmStack; + end->data = TMParameters; + EndmStack = end; + return line; + } else if (!nasm_stricmp(q, "proc")) { + /* handle PROC */ + oldline = line; + line = nasm_malloc(2 + len + 1); + sprintf(line, "..%s",p); + nasm_free(oldline); + return line; + } else if (!nasm_stricmp(q, "struc")) { + /* handle struc */ + struct TStruc *struc; + if (inTstruc) { + error(ERR_FATAL, "STRUC: already in a struc context"); + return line; + } + oldline = line; + line = nasm_malloc(5 + 1 + len + 1); + sprintf(line, "struc %s", p); + struc = malloc(sizeof(*struc)); + struc->name = nasm_strdup(p); + struc->fields = NULL; + struc->lastField = NULL; + struc->next = TStrucs; + TStrucs = struc; + inTstruc = 1; + nasm_free(oldline); + end = nasm_malloc(sizeof(*end)); + end->type = TM_STRUC; + end->next = EndsStack; + EndsStack = end; + return line; + } else if (!nasm_stricmp(q, "segment")) { + /* handle SEGMENT */ + oldline = line; + line = nasm_strdup(oldchar2?q+len2+1:""); + if (tasm_segment) { + error(ERR_FATAL, "SEGMENT: already in a segment context"); + return line; + } + tasm_segment = nasm_strdup(p); + nasm_free(oldline); + end = nasm_malloc(sizeof(*end)); + end->type = TM_SEGMENT; + end->next = EndsStack; + EndsStack = end; + return line; + } else if (!nasm_stricmp(p, "ends") || !nasm_stricmp(q, "ends")) { + /* handle end of ends directive */ + end = EndsStack; + /* undef parameters */ + if (!end) { + error(ERR_FATAL, "ENDS: not in an ends context"); + return line; + } + EndsStack = EndsStack->next; + nasm_free(line); + switch (end->type) { + case TM_STRUC: + inTstruc = 0; + return nasm_strdup("endstruc"); + case TM_SEGMENT: + /* XXX: yes, we leak memory here, but that permits labels + * to avoid strduping... */ + tasm_segment = NULL; + return nasm_strdup(""); + default: + error(ERR_FATAL, "ENDS: bogus ends context type %d",end->type); + return NULL; + } + } else if (!nasm_stricmp(p, "endp") || !nasm_stricmp(q, "endp")) { + nasm_free(line); + return nasm_strdup(""); + } else if (!nasm_stricmp(p, "assume")) { + struct TSegmentAssume *assume; + /* handle ASSUME */ + if (!TAssumes) { + TAssumes = nasm_malloc(sizeof(*TAssumes)); + TAssumes[0].segreg = NULL; + } + i = 0; + q[len2] = oldchar2; + /* Skip whitespaces */ + while (isspace(*q) && *q) + q++; + while (*q && *q != ';') { + p = q; + for (; *q && *q != ';' && *q != ':' && !isspace(*q); q++); + if (!*q || *q == ';') + break; + /* segment register name */ + for (assume = TAssumes; assume->segreg; assume++) + if (strlen(assume->segreg) == (size_t)(q-p) && + !yasm__strncasecmp(assume->segreg, p, q-p)) + break; + if (!assume->segreg) { + i = assume - TAssumes + 1; + TAssumes = nasm_realloc(TAssumes, (i+1)*sizeof(*TAssumes)); + assume = TAssumes + i - 1; + assume->segreg = nasm_strndup(p, q-p); + assume[1].segreg = NULL; + } + for (; *q && *q != ';' && *q != ':' && isspace(*q); q++); + if (*q != ':') + error(ERR_FATAL, "expected `:' instead of `%c'", *q); + for (q++; *q && isspace(*q); q++); + + /* segment name */ + p = q; + for (; *q && *q != ';' && *q != ',' && !isspace(*q); q++); + assume->segment = nasm_strndup(p, q-p); + for (; *q && isspace(*q); q++); + if (*q && *q != ';' && *q != ',') + error(ERR_FATAL, "expected `,' instead of `%c'", *q); + + if (*q && *q != ';') + q++; + for (; *q && isspace(*q); q++); + } + TAssumes[i].segreg = NULL; + TAssumes = nasm_realloc(TAssumes, (i+1)*sizeof(*TAssumes)); + nasm_free(line); + return nasm_strdup(""); + } else if (inTstruc) { + struct TStrucField *field; + /* TODO: handle unnamed data */ + field = nasm_malloc(sizeof(*field)); + field->name = nasm_strdup(p); + /* TODO: type struc ! */ + field->type = nasm_strdup(q); + field->next = NULL; + if (!TStrucs->fields) + TStrucs->fields = field; + else if (TStrucs->lastField) + TStrucs->lastField->next = field; + TStrucs->lastField = field; + if (!oldchar2) { + error(ERR_FATAL, "Expected struc field initializer after %s %s", p, q); + return line; + } + oldline = line; + line = nasm_malloc(1 + len + 1 + len2 + 1 + strlen(q+len2+1) + 1); + sprintf(line, ".%s %s %s", p, q, q+len2+1); + nasm_free(oldline); + return line; + } + { + struct TStruc *struc; + for (struc = TStrucs; struc; struc = struc->next) { + if (!yasm__strcasecmp(q, struc->name)) { + char *r = q + len2 + 1, *s, *t, tasm_param[6]; + struct TStrucField *field = struc->fields; + int size, n; + if (!oldchar2) { + error(ERR_FATAL, "Expected struc field initializer after %s %s", p, q); + return line; + } + r = strchr(r, '<'); + if (!r) { + error(ERR_FATAL, "Expected < for struc field initializer in %s %s %s", p, q, r); + return line; + } + t = strchr(r + 1, '>'); + if (!t) { + error(ERR_FATAL, "Expected > for struc field initializer in %s %s %s", p, q, r); + return line; + } + *t = 0; + oldline = line; + size = len + len2 + 128; + line = nasm_malloc(size); + if (defining) + for (n=0;TMParameters[n];n++) + if (!strcmp(TMParameters[n],p)) { + sprintf(tasm_param,"%%{%d}",n+1); + p = tasm_param; + break; + } + n = sprintf(line, "%s: istruc %s\n", p, q); + /* use initialisers */ + while ((s = strchr(r + 1, ','))) { + if (!field) { + error(ERR_FATAL, "Too many initializers in structure %s %s", p, q); + return oldline; + } + *s = 0; + m = strlen(p) + 1 + strlen(field->name)*2 + 8 + + strlen(field->type) + 1 + strlen(r+1) + 2; + size += m; + line = nasm_realloc(line, size); + sprintf(line + n, "%s.%s: at .%s, %s %s\n", + p, field->name, field->name, field->type, r + 1); + n += m-1; + r = s; + field = field->next; + } + /* complete with last initializer and '?' */ + while(field) { + m = strlen(p) + 1 + strlen(field->name)*2 + 8 + + strlen(field->type) + 1 + (r ? strlen(r+1) : 1) + 2; + size += m; + line = nasm_realloc(line, size); + sprintf(line + n, "%s.%s: at .%s, %s %s\n", p, field->name, + field->name, field->type, r ? r + 1: "?"); + n += m-1; + r = NULL; + field = field->next; + } + line = nasm_realloc(line, n + 5); + sprintf(line + n, "iend"); + nasm_free(oldline); + return line; + } + } + } + + q[len2] = oldchar2; + p[len] = oldchar; + + return line; +} + +static Token * tasm_join_tokens(Token *tline) +{ + Token *t, *prev, *next; + for (prev = NULL, t = tline; t; prev = t, t = next) { + next = t->next; + if (t->type == TOK_OTHER && !strcmp(t->text,"&")) { + if (!prev) + error(ERR_FATAL, "no token before &"); + else if (!next) + error(ERR_FATAL, "no token after &"); + else if (prev->type != next->type) + error(ERR_FATAL, "can't handle different types of token around &"); + else if (!prev->text || !next->text) + error(ERR_FATAL, "can't handle empty token around &"); + else { + int lenp = strlen(prev->text); + int lenn = strlen(next->text); + prev->text = nasm_realloc(prev->text, lenp + lenn + 1); + strncpy(prev->text + lenp, next->text, lenn + 1); + (void) delete_Token(t); + prev->next = delete_Token(next); + t = prev; + next = t->next; + } + } + } + return tline; +} + +/* + * The pre-preprocessing stage... This function translates line + * number indications as they emerge from GNU cpp (`# lineno "file" + * flags') into NASM preprocessor line number indications (`%line + * lineno file'). + */ +static char * +prepreproc(char *line) +{ + int lineno; + size_t fnlen; + char *fname, *oldline; + char *c, *d, *ret; + Line *l, **lp; + + if (line[0] == '#' && line[1] == ' ') + { + oldline = line; + fname = oldline + 2; + lineno = atoi(fname); + fname += strspn(fname, "0123456789 "); + if (*fname == '"') + fname++; + fnlen = strcspn(fname, "\""); + line = nasm_malloc(20 + fnlen); + sprintf(line, "%%line %d %.*s", lineno, (int)fnlen, fname); + nasm_free(oldline); + } + if (tasm_compatible_mode) + line = check_tasm_directive(line); + + if (!(c = strchr(line, '\n'))) + return line; + + /* Turn multiline macros into several lines */ + *c = '\0'; + ret = nasm_strdup(line); + + lp = &istk->expansion; + do { + d = strchr(c+1, '\n'); + if (d) + *d = '\0'; + l = malloc(sizeof(*l)); + l -> first = tokenise(c+1); + l -> finishes = NULL; + l -> next = *lp; + *lp = l; + c = d; + lp = &l -> next; + } while (c); + nasm_free(line); + return ret; +} + +/* + * The hash function for macro lookups. Note that due to some + * macros having case-insensitive names, the hash function must be + * invariant under case changes. We implement this by applying a + * perfectly normal hash function to the uppercase of the string. + */ +static int +hash(char *s) +{ + unsigned int h = 0; + unsigned int i = 0; + /* + * Powers of three, mod 31. + */ + static const int multipliers[] = { + 1, 3, 9, 27, 19, 26, 16, 17, 20, 29, 25, 13, 8, 24, 10, + 30, 28, 22, 4, 12, 5, 15, 14, 11, 2, 6, 18, 23, 7, 21 + }; + + + while (*s) + { + h += multipliers[i] * (unsigned char) (toupper(*s)); + s++; + if (++i >= elements(multipliers)) + i = 0; + } + h %= NHASH; + return h; +} + +/* + * Free a linked list of tokens. + */ +static void +free_tlist(Token * list_) +{ + while (list_) + { + list_ = delete_Token(list_); + } +} + +/* + * Free a linked list of lines. + */ +static void +free_llist(Line * list_) +{ + Line *l; + while (list_) + { + l = list_; + list_ = list_->next; + free_tlist(l->first); + nasm_free(l); + } +} + +/* + * Free an MMacro + */ +static void +free_mmacro(MMacro * m) +{ + nasm_free(m->name); + free_tlist(m->dlist); + nasm_free(m->defaults); + free_llist(m->expansion); + nasm_free(m); +} + +/* + * Pop the context stack. + */ +static void +ctx_pop(void) +{ + Context *c = cstk; + SMacro *smac, *s; + + cstk = cstk->next; + smac = c->localmac; + while (smac) + { + s = smac; + smac = smac->next; + nasm_free(s->name); + free_tlist(s->expansion); + nasm_free(s); + } + nasm_free(c->name); + nasm_free(c); +} + +#define BUF_DELTA 512 +/* + * Read a line from the top file in istk, handling multiple CR/LFs + * at the end of the line read, and handling spurious ^Zs. Will + * return lines from the standard macro set if this has not already + * been done. + */ +static char * +read_line(void) +{ + char *buffer, *p, *q; + int bufsize, continued_count; + + bufsize = BUF_DELTA; + buffer = nasm_malloc(BUF_DELTA); + p = buffer; + continued_count = 0; + while (1) + { + q = fgets(p, bufsize - (int)(p - buffer), istk->fp); + if (!q) + break; + p += strlen(p); + if (p > buffer && p[-1] == '\n') + { + /* Convert backslash-CRLF line continuation sequences into + nothing at all (for DOS and Windows) */ + if (((p - 2) > buffer) && (p[-3] == '\\') && (p[-2] == '\r')) { + p -= 3; + *p = 0; + continued_count++; + } + /* Also convert backslash-LF line continuation sequences into + nothing at all (for Unix) */ + else if (((p - 1) > buffer) && (p[-2] == '\\')) { + p -= 2; + *p = 0; + continued_count++; + } + else { + break; + } + } + if (p - buffer > bufsize - 10) + { + long offset = (long)(p - buffer); + bufsize += BUF_DELTA; + buffer = nasm_realloc(buffer, (size_t)bufsize); + p = buffer + offset; /* prevent stale-pointer problems */ + } + } + + if (!q && p == buffer) + { + nasm_free(buffer); + return NULL; + } + + nasm_src_set_linnum(nasm_src_get_linnum() + istk->lineinc + (continued_count * istk->lineinc)); + + /* + * Play safe: remove CRs as well as LFs, if any of either are + * present at the end of the line. + */ + while (--p >= buffer && (*p == '\n' || *p == '\r')) + *p = '\0'; + + /* + * Handle spurious ^Z, which may be inserted into source files + * by some file transfer utilities. + */ + buffer[strcspn(buffer, "\032")] = '\0'; + + list->line(LIST_READ, buffer); + + return buffer; +} + +/* + * Tokenise a line of text. This is a very simple process since we + * don't need to parse the value out of e.g. numeric tokens: we + * simply split one string into many. + */ +static Token * +tokenise(char *line) +{ + char *p = line; + int type; + Token *list_ = NULL; + Token *t, **tail = &list_; + + while (*line) + { + p = line; + if (*p == '%') + { + p++; + if ( isdigit(*p) || + ((*p == '-' || *p == '+') && isdigit(p[1])) || + ((*p == '+') && (isspace(p[1]) || !p[1]))) + { + do + { + p++; + } + while (isdigit(*p)); + type = TOK_PREPROC_ID; + } + else if (*p == '{') + { + p++; + while (*p && *p != '}') + { + p[-1] = *p; + p++; + } + p[-1] = '\0'; + if (*p) + p++; + type = TOK_PREPROC_ID; + } + else if (isidchar(*p) || + ((*p == '!' || *p == '%' || *p == '$') && + isidchar(p[1]))) + { + do + { + p++; + } + while (isidchar(*p)); + type = TOK_PREPROC_ID; + } + else + { + type = TOK_OTHER; + if (*p == '%') + p++; + } + } + else if (isidstart(*p) || (*p == '$' && isidstart(p[1]))) + { + type = TOK_ID; + p++; + while (*p && isidchar(*p)) + p++; + } + else if (*p == '\'' || *p == '"') + { + /* + * A string token. + */ + char c = *p; + p++; + type = TOK_STRING; + while (*p && *p != c) + p++; + + if (*p) + { + p++; + } + else + { + error(ERR_WARNING, "unterminated string"); + type = -1; + } + } + else if (isnumstart(*p)) + { + /* + * A number token. + */ + type = TOK_NUMBER; + p++; + while (*p && isnumchar(*p)) + p++; + } + else if (isspace(*p)) + { + type = TOK_WHITESPACE; + p++; + while (*p && isspace(*p)) + p++; + /* + * Whitespace just before end-of-line is discarded by + * pretending it's a comment; whitespace just before a + * comment gets lumped into the comment. + */ + if (!*p || *p == ';') + { + type = TOK_COMMENT; + while (*p) + p++; + } + } + else if (*p == ';') + { + type = TOK_COMMENT; + while (*p) + p++; + } + else + { + /* + * Anything else is an operator of some kind. We check + * for all the double-character operators (>>, <<, //, + * %%, <=, >=, ==, !=, <>, &&, ||, ^^), but anything + * else is a single-character operator. + */ + type = TOK_OTHER; + if ((p[0] == '>' && p[1] == '>') || + (p[0] == '<' && p[1] == '<') || + (p[0] == '/' && p[1] == '/') || + (p[0] == '<' && p[1] == '=') || + (p[0] == '>' && p[1] == '=') || + (p[0] == '=' && p[1] == '=') || + (p[0] == '!' && p[1] == '=') || + (p[0] == '<' && p[1] == '>') || + (p[0] == '&' && p[1] == '&') || + (p[0] == '|' && p[1] == '|') || + (p[0] == '^' && p[1] == '^')) + { + p++; + } + p++; + } + + /* Handle unterminated string */ + if (type == -1) + { + *tail = t = new_Token(NULL, TOK_STRING, line, (size_t)(p-line)+1); + t->text[p-line] = *line; + tail = &t->next; + } + else if (type != TOK_COMMENT) + { + *tail = t = new_Token(NULL, type, line, (size_t)(p - line)); + tail = &t->next; + } + line = p; + } + return list_; +} + +/* + * this function allocates a new managed block of memory and + * returns a pointer to the block. The managed blocks are + * deleted only all at once by the delete_Blocks function. + */ +static void * +new_Block(size_t size) +{ + Blocks *b = &blocks; + + /* first, get to the end of the linked list */ + while (b->next) + b = b->next; + /* now allocate the requested chunk */ + b->chunk = nasm_malloc(size); + + /* now allocate a new block for the next request */ + b->next = nasm_malloc(sizeof(Blocks)); + /* and initialize the contents of the new block */ + b->next->next = NULL; + b->next->chunk = NULL; + return b->chunk; +} + +/* + * this function deletes all managed blocks of memory + */ +static void +delete_Blocks(void) +{ + Blocks *a,*b = &blocks; + + /* + * keep in mind that the first block, pointed to by blocks + * is a static and not dynamically allocated, so we don't + * free it. + */ + while (b) + { + if (b->chunk) + nasm_free(b->chunk); + a = b; + b = b->next; + if (a != &blocks) + nasm_free(a); + } +} + +/* + * this function creates a new Token and passes a pointer to it + * back to the caller. It sets the type and text elements, and + * also the mac and next elements to NULL. + */ +static Token * +new_Token(Token * next, int type, const char *text, size_t txtlen) +{ + Token *t; + int i; + + if (freeTokens == NULL) + { + freeTokens = (Token *)new_Block(TOKEN_BLOCKSIZE * sizeof(Token)); + for (i = 0; i < TOKEN_BLOCKSIZE - 1; i++) + freeTokens[i].next = &freeTokens[i + 1]; + freeTokens[i].next = NULL; + } + t = freeTokens; + freeTokens = t->next; + t->next = next; + t->mac = NULL; + t->type = type; + if (type == TOK_WHITESPACE || text == NULL) + { + t->text = NULL; + } + else + { + if (txtlen == 0) + txtlen = strlen(text); + t->text = nasm_malloc(1 + txtlen); + strncpy(t->text, text, txtlen); + t->text[txtlen] = '\0'; + } + return t; +} + +static Token * +delete_Token(Token * t) +{ + Token *next = t->next; + nasm_free(t->text); + t->next = freeTokens; + freeTokens = t; + return next; +} + +/* + * Convert a line of tokens back into text. + * If expand_locals is not zero, identifiers of the form "%$*xxx" + * will be transformed into ..@ctxnum.xxx + */ +static char * +detoken(Token * tlist, int expand_locals) +{ + Token *t; + size_t len; + char *line, *p; + + len = 0; + for (t = tlist; t; t = t->next) + { + if (t->type == TOK_PREPROC_ID && t->text[1] == '!') + { + char *p2 = getenv(t->text + 2); + nasm_free(t->text); + if (p2) + t->text = nasm_strdup(p2); + else + t->text = NULL; + } + /* Expand local macros here and not during preprocessing */ + if (expand_locals && + t->type == TOK_PREPROC_ID && t->text && + t->text[0] == '%' && t->text[1] == '$') + { + Context *ctx = get_ctx(t->text, FALSE); + if (ctx) + { + char buffer[40]; + char *p2, *q = t->text + 2; + + q += strspn(q, "$"); + sprintf(buffer, "..@%lu.", ctx->number); + p2 = nasm_strcat(buffer, q); + nasm_free(t->text); + t->text = p2; + } + } + if (t->type == TOK_WHITESPACE) + { + len++; + } + else if (t->text) + { + len += strlen(t->text); + } + } + p = line = nasm_malloc(len + 1); + for (t = tlist; t; t = t->next) + { + if (t->type == TOK_WHITESPACE) + { + *p = ' '; + p++; + *p = '\0'; + } + else if (t->text) + { + strcpy(p, t->text); + p += strlen(p); + } + } + *p = '\0'; + return line; +} + +/* + * A scanner, suitable for use by the expression evaluator, which + * operates on a line of Tokens. Expects a pointer to a pointer to + * the first token in the line to be passed in as its private_data + * field. + */ +static int +ppscan(void *private_data, struct tokenval *tokval) +{ + Token **tlineptr = private_data; + Token *tline; + + do + { + tline = *tlineptr; + *tlineptr = tline ? tline->next : NULL; + } + while (tline && (tline->type == TOK_WHITESPACE || + tline->type == TOK_COMMENT)); + + if (!tline) + return tokval->t_type = TOKEN_EOS; + + if (tline->text[0] == '$' && !tline->text[1]) + return tokval->t_type = TOKEN_HERE; + if (tline->text[0] == '$' && tline->text[1] == '$' && !tline->text[2]) + return tokval->t_type = TOKEN_BASE; + + if (tline->type == TOK_ID) + { + tokval->t_charptr = tline->text; + if (tline->text[0] == '$') + { + tokval->t_charptr++; + return tokval->t_type = TOKEN_ID; + } + + /* + * This is the only special case we actually need to worry + * about in this restricted context. + */ + if (!nasm_stricmp(tline->text, "seg")) + return tokval->t_type = TOKEN_SEG; + + return tokval->t_type = TOKEN_ID; + } + + if (tline->type == TOK_NUMBER) + { + int rn_error; + + tokval->t_integer = nasm_readnum(tline->text, &rn_error); + if (rn_error) + return tokval->t_type = TOKEN_ERRNUM; + tokval->t_charptr = NULL; + return tokval->t_type = TOKEN_NUM; + } + + if (tline->type == TOK_STRING) + { + int rn_warn; + char q, *r; + size_t l; + + r = tline->text; + q = *r++; + l = strlen(r); + + if (l == 0 || r[l - 1] != q) + return tokval->t_type = TOKEN_ERRNUM; + tokval->t_integer = nasm_readstrnum(r, l - 1, &rn_warn); + if (rn_warn) + error(ERR_WARNING | ERR_PASS1, "character constant too long"); + tokval->t_charptr = NULL; + return tokval->t_type = TOKEN_NUM; + } + + if (tline->type == TOK_OTHER) + { + if (!strcmp(tline->text, "<<")) + return tokval->t_type = TOKEN_SHL; + if (!strcmp(tline->text, ">>")) + return tokval->t_type = TOKEN_SHR; + if (!strcmp(tline->text, "//")) + return tokval->t_type = TOKEN_SDIV; + if (!strcmp(tline->text, "%%")) + return tokval->t_type = TOKEN_SMOD; + if (!strcmp(tline->text, "==")) + return tokval->t_type = TOKEN_EQ; + if (!strcmp(tline->text, "<>")) + return tokval->t_type = TOKEN_NE; + if (!strcmp(tline->text, "!=")) + return tokval->t_type = TOKEN_NE; + if (!strcmp(tline->text, "<=")) + return tokval->t_type = TOKEN_LE; + if (!strcmp(tline->text, ">=")) + return tokval->t_type = TOKEN_GE; + if (!strcmp(tline->text, "&&")) + return tokval->t_type = TOKEN_DBL_AND; + if (!strcmp(tline->text, "^^")) + return tokval->t_type = TOKEN_DBL_XOR; + if (!strcmp(tline->text, "||")) + return tokval->t_type = TOKEN_DBL_OR; + } + + /* + * We have no other options: just return the first character of + * the token text. + */ + return tokval->t_type = tline->text[0]; +} + +/* + * Compare a string to the name of an existing macro; this is a + * simple wrapper which calls either strcmp or nasm_stricmp + * depending on the value of the `casesense' parameter. + */ +static int +mstrcmp(char *p, char *q, int casesense) +{ + return casesense ? strcmp(p, q) : nasm_stricmp(p, q); +} + +/* + * Return the Context structure associated with a %$ token. Return + * NULL, having _already_ reported an error condition, if the + * context stack isn't deep enough for the supplied number of $ + * signs. + * If all_contexts == TRUE, contexts that enclose current are + * also scanned for such smacro, until it is found; if not - + * only the context that directly results from the number of $'s + * in variable's name. + */ +static Context * +get_ctx(char *name, int all_contexts) +{ + Context *ctx; + SMacro *m; + size_t i; + + if (!name || name[0] != '%' || name[1] != '$') + return NULL; + + if (!cstk) + { + error(ERR_NONFATAL, "`%s': context stack is empty", name); + return NULL; + } + + for (i = strspn(name + 2, "$"), ctx = cstk; (i > 0) && ctx; i--) + { + ctx = ctx->next; +/* i--; Lino - 02/25/02 */ + } + if (!ctx) + { + error(ERR_NONFATAL, "`%s': context stack is only" + " %d level%s deep", name, i - 1, (i == 2 ? "" : "s")); + return NULL; + } + if (!all_contexts) + return ctx; + + do + { + /* Search for this smacro in found context */ + m = ctx->localmac; + while (m) + { + if (!mstrcmp(m->name, name, m->casesense)) + return ctx; + m = m->next; + } + ctx = ctx->next; + } + while (ctx); + return NULL; +} + +/* + * Open an include file. This routine must always return a valid + * file pointer if it returns - it's responsible for throwing an + * ERR_FATAL and bombing out completely if not. It should also try + * the include path one by one until it finds the file or reaches + * the end of the path. + */ +static FILE * +inc_fopen(char *file, char **newname) +{ + FILE *fp; + char *combine = NULL, *c; + char *pb, *p1, *p2, *file2 = NULL; + + /* Try to expand all %ENVVAR% in filename. Warn, and leave %string% + * intact, if ENVVAR is not set in the environment. + */ + pb = file; + p1 = pb; + for (;;) { + char *env; + while (*p1 != '\0' && *p1 != '%') + p1++; + if (*p1 == '\0') + break; + p2 = p1+1; + while (*p2 != '\0' && *p2 != '%') + p2++; + if (*p2 == '\0') + break; + /* Okay, we have a %...%, with p1 pointing to the first %, and p2 + * pointing to the second %. + */ + *p2 = '\0'; + env = getenv(p1+1); + if (!env) { + /* warn, restore %, and continue looking */ + error(ERR_WARNING, "environment variable `%s' does not exist", + p1+1); + *p2 = '%'; + p1 = p2+1; + continue; + } + /* need to expand */ + if (!file2) { + file2 = nasm_malloc(strlen(file)+strlen(env)+1); + file2[0] = '\0'; + } else + file2 = nasm_realloc(file2, strlen(file2)+strlen(env)+1); + *p1 = '\0'; + strcat(file2, pb); + strcat(file2, env); + pb = p2+1; + p1 = pb; + } + /* add tail end; string is long enough that we don't need to realloc */ + if (file2) + strcat(file2, pb); + + fp = yasm_fopen_include(file2 ? file2 : file, nasm_src_get_fname(), "r", + &combine); + if (!fp && tasm_compatible_mode) + { + char *thefile = file2 ? file2 : file; + /* try a few case combinations */ + do { + for (c = thefile; *c; c++) + *c = toupper(*c); + fp = yasm_fopen_include(thefile, nasm_src_get_fname(), "r", &combine); + if (fp) break; + *thefile = tolower(*thefile); + fp = yasm_fopen_include(thefile, nasm_src_get_fname(), "r", &combine); + if (fp) break; + for (c = thefile; *c; c++) + *c = tolower(*c); + fp = yasm_fopen_include(thefile, nasm_src_get_fname(), "r", &combine); + if (fp) break; + *thefile = toupper(*thefile); + fp = yasm_fopen_include(thefile, nasm_src_get_fname(), "r", &combine); + if (fp) break; + } while (0); + } + if (!fp) + error(ERR_FATAL, "unable to open include file `%s'", + file2 ? file2 : file); + nasm_preproc_add_dep(combine); + + if (file2) + nasm_free(file2); + + *newname = combine; + return fp; +} + +/* + * Determine if we should warn on defining a single-line macro of + * name `name', with `nparam' parameters. If nparam is 0 or -1, will + * return TRUE if _any_ single-line macro of that name is defined. + * Otherwise, will return TRUE if a single-line macro with either + * `nparam' or no parameters is defined. + * + * If a macro with precisely the right number of parameters is + * defined, or nparam is -1, the address of the definition structure + * will be returned in `defn'; otherwise NULL will be returned. If `defn' + * is NULL, no action will be taken regarding its contents, and no + * error will occur. + * + * Note that this is also called with nparam zero to resolve + * `ifdef'. + * + * If you already know which context macro belongs to, you can pass + * the context pointer as first parameter; if you won't but name begins + * with %$ the context will be automatically computed. If all_contexts + * is true, macro will be searched in outer contexts as well. + */ +static int +smacro_defined(Context * ctx, char *name, int nparam, SMacro ** defn, + int nocase) +{ + SMacro *m; + int highest_level = -1; + + if (ctx) + m = ctx->localmac; + else if (name[0] == '%' && name[1] == '$') + { + if (cstk) + ctx = get_ctx(name, FALSE); + if (!ctx) + return FALSE; /* got to return _something_ */ + m = ctx->localmac; + } + else + m = smacros[hash(name)]; + + while (m) + { + if (!mstrcmp(m->name, name, m->casesense && nocase) && + (nparam <= 0 || m->nparam == 0 || nparam == m->nparam) && (highest_level < 0 || m->level > highest_level)) + { + highest_level = m->level; + if (defn) + { + if (nparam == m->nparam || nparam == -1) + *defn = m; + else + *defn = NULL; + } + } + m = m->next; + } + + return highest_level >= 0; +} + +/* + * Count and mark off the parameters in a multi-line macro call. + * This is called both from within the multi-line macro expansion + * code, and also to mark off the default parameters when provided + * in a %macro definition line. + */ +static void +count_mmac_params(Token * t, int *nparam, Token *** params) +{ + int paramsize, brace; + + *nparam = paramsize = 0; + *params = NULL; + while (t) + { + if (*nparam+1 >= paramsize) + { + paramsize += PARAM_DELTA; + *params = nasm_realloc(*params, sizeof(**params) * paramsize); + } + skip_white_(t); + brace = FALSE; + if (tok_is_(t, "{")) + brace = TRUE; + (*params)[(*nparam)++] = t; + while (tok_isnt_(t, brace ? "}" : ",")) + t = t->next; + if (t) + { /* got a comma/brace */ + t = t->next; + if (brace) + { + /* + * Now we've found the closing brace, look further + * for the comma. + */ + skip_white_(t); + if (tok_isnt_(t, ",")) + { + error(ERR_NONFATAL, + "braces do not enclose all of macro parameter"); + while (tok_isnt_(t, ",")) + t = t->next; + } + if (t) + t = t->next; /* eat the comma */ + } + } + } +} + +/* + * Determine whether one of the various `if' conditions is true or + * not. + * + * We must free the tline we get passed. + */ +static int +if_condition(Token * tline, int i) +{ + int j, casesense; + Token *t, *tt, **tptr, *origline; + struct tokenval tokval; + yasm_expr *evalresult; + yasm_intnum *intn; + + origline = tline; + + switch (i) + { + case PP_IFCTX: + case PP_ELIFCTX: + case PP_IFNCTX: + case PP_ELIFNCTX: + j = FALSE; /* have we matched yet? */ + while (cstk && tline) + { + skip_white_(tline); + if (!tline || tline->type != TOK_ID) + { + error(ERR_NONFATAL, + "`%s' expects context identifiers", + directives[i]); + free_tlist(origline); + return -1; + } + if (!nasm_stricmp(tline->text, cstk->name)) + j = TRUE; + tline = tline->next; + } + if (i == PP_IFNCTX || i == PP_ELIFNCTX) + j = !j; + free_tlist(origline); + return j; + + case PP_IFDEF: + case PP_ELIFDEF: + case PP_IFNDEF: + case PP_ELIFNDEF: + j = FALSE; /* have we matched yet? */ + while (tline) + { + skip_white_(tline); + if (!tline || (tline->type != TOK_ID && + (tline->type != TOK_PREPROC_ID || + tline->text[1] != '$'))) + { + error(ERR_NONFATAL, + "`%s' expects macro identifiers", + directives[i]); + free_tlist(origline); + return -1; + } + if (smacro_defined(NULL, tline->text, 0, NULL, 1)) + j = TRUE; + tline = tline->next; + } + if (i == PP_IFNDEF || i == PP_ELIFNDEF) + j = !j; + free_tlist(origline); + return j; + + case PP_IFIDN: + case PP_ELIFIDN: + case PP_IFNIDN: + case PP_ELIFNIDN: + case PP_IFIDNI: + case PP_ELIFIDNI: + case PP_IFNIDNI: + case PP_ELIFNIDNI: + tline = expand_smacro(tline); + t = tt = tline; + while (tok_isnt_(tt, ",")) + tt = tt->next; + if (!tt) + { + error(ERR_NONFATAL, + "`%s' expects two comma-separated arguments", + directives[i]); + free_tlist(tline); + return -1; + } + tt = tt->next; + casesense = (i == PP_IFIDN || i == PP_ELIFIDN || + i == PP_IFNIDN || i == PP_ELIFNIDN); + j = TRUE; /* assume equality unless proved not */ + while ((t->type != TOK_OTHER || strcmp(t->text, ",")) && tt) + { + if (tt->type == TOK_OTHER && !strcmp(tt->text, ",")) + { + error(ERR_NONFATAL, "`%s': more than one comma on line", + directives[i]); + free_tlist(tline); + return -1; + } + if (t->type == TOK_WHITESPACE) + { + t = t->next; + continue; + } + if (tt->type == TOK_WHITESPACE) + { + tt = tt->next; + continue; + } + if (tt->type != t->type) + { + j = FALSE; /* found mismatching tokens */ + break; + } + /* Unify surrounding quotes for strings */ + if (t->type == TOK_STRING) + { + tt->text[0] = t->text[0]; + tt->text[strlen(tt->text) - 1] = t->text[0]; + } + if (mstrcmp(tt->text, t->text, casesense) != 0) + { + j = FALSE; /* found mismatching tokens */ + break; + } + + t = t->next; + tt = tt->next; + } + if ((t->type != TOK_OTHER || strcmp(t->text, ",")) || tt) + j = FALSE; /* trailing gunk on one end or other */ + if (i == PP_IFNIDN || i == PP_ELIFNIDN || + i == PP_IFNIDNI || i == PP_ELIFNIDNI) + j = !j; + free_tlist(tline); + return j; + + case PP_IFMACRO: + case PP_ELIFMACRO: + case PP_IFNMACRO: + case PP_ELIFNMACRO: + { + int found = 0; + MMacro searching, *mmac; + + tline = tline->next; + skip_white_(tline); + tline = expand_id(tline); + if (!tok_type_(tline, TOK_ID)) + { + error(ERR_NONFATAL, + "`%s' expects a macro name", + directives[i]); + return -1; + } + searching.name = nasm_strdup(tline->text); + searching.casesense = (i == PP_MACRO); + searching.plus = FALSE; + searching.nolist = FALSE; + searching.in_progress = FALSE; + searching.rep_nest = NULL; + searching.nparam_min = 0; + searching.nparam_max = INT_MAX; + tline = expand_smacro(tline->next); + skip_white_(tline); + if (!tline) + { + } else if (!tok_type_(tline, TOK_NUMBER)) + { + error(ERR_NONFATAL, + "`%s' expects a parameter count or nothing", + directives[i]); + } + else + { + intn = nasm_readnum(tline->text, &j); + searching.nparam_min = searching.nparam_max = + yasm_intnum_get_int(intn); + yasm_intnum_destroy(intn); + if (j) + error(ERR_NONFATAL, + "unable to parse parameter count `%s'", + tline->text); + } + if (tline && tok_is_(tline->next, "-")) + { + tline = tline->next->next; + if (tok_is_(tline, "*")) + searching.nparam_max = INT_MAX; + else if (!tok_type_(tline, TOK_NUMBER)) + error(ERR_NONFATAL, + "`%s' expects a parameter count after `-'", + directives[i]); + else + { + intn = nasm_readnum(tline->text, &j); + searching.nparam_max = yasm_intnum_get_int(intn); + yasm_intnum_destroy(intn); + if (j) + error(ERR_NONFATAL, + "unable to parse parameter count `%s'", + tline->text); + if (searching.nparam_min > searching.nparam_max) + error(ERR_NONFATAL, + "minimum parameter count exceeds maximum"); + } + } + if (tline && tok_is_(tline->next, "+")) + { + tline = tline->next; + searching.plus = TRUE; + } + mmac = mmacros[hash(searching.name)]; + while (mmac) + { + if (!strcmp(mmac->name, searching.name) && + (mmac->nparam_min <= searching.nparam_max + || searching.plus) + && (searching.nparam_min <= mmac->nparam_max + || mmac->plus)) + { + found = TRUE; + break; + } + mmac = mmac->next; + } + nasm_free(searching.name); + free_tlist(origline); + if (i == PP_IFNMACRO || i == PP_ELIFNMACRO) + found = !found; + return found; + } + + case PP_IFID: + case PP_ELIFID: + case PP_IFNID: + case PP_ELIFNID: + case PP_IFNUM: + case PP_ELIFNUM: + case PP_IFNNUM: + case PP_ELIFNNUM: + case PP_IFSTR: + case PP_ELIFSTR: + case PP_IFNSTR: + case PP_ELIFNSTR: + tline = expand_smacro(tline); + t = tline; + while (tok_type_(t, TOK_WHITESPACE)) + t = t->next; + j = FALSE; /* placate optimiser */ + if (t) + switch (i) + { + case PP_IFID: + case PP_ELIFID: + case PP_IFNID: + case PP_ELIFNID: + j = (t->type == TOK_ID); + break; + case PP_IFNUM: + case PP_ELIFNUM: + case PP_IFNNUM: + case PP_ELIFNNUM: + j = (t->type == TOK_NUMBER); + break; + case PP_IFSTR: + case PP_ELIFSTR: + case PP_IFNSTR: + case PP_ELIFNSTR: + j = (t->type == TOK_STRING); + break; + } + if (i == PP_IFNID || i == PP_ELIFNID || + i == PP_IFNNUM || i == PP_ELIFNNUM || + i == PP_IFNSTR || i == PP_ELIFNSTR) + j = !j; + free_tlist(tline); + return j; + + case PP_IF: + case PP_ELIF: + t = tline = expand_smacro(tline); + tptr = &t; + tokval.t_type = TOKEN_INVALID; + evalresult = evaluate(ppscan, tptr, &tokval, pass | CRITICAL, + error); + free_tlist(tline); + if (!evalresult) + return -1; + if (tokval.t_type) + error(ERR_WARNING, + "trailing garbage after expression ignored"); + intn = yasm_expr_get_intnum(&evalresult, 0); + if (!intn) + { + error(ERR_NONFATAL, + "non-constant value given to `%s'", directives[i]); + yasm_expr_destroy(evalresult); + return -1; + } + j = !yasm_intnum_is_zero(intn); + yasm_expr_destroy(evalresult); + return j; + + default: + error(ERR_FATAL, + "preprocessor directive `%s' not yet implemented", + directives[i]); + free_tlist(origline); + return -1; /* yeah, right */ + } +} + +/* + * Expand macros in a string. Used in %error and %include directives. + * First tokenise the string, apply "expand_smacro" and then de-tokenise back. + * The returned variable should ALWAYS be freed after usage. + */ +static void +expand_macros_in_string(char **p) +{ + Token *line = tokenise(*p); + line = expand_smacro(line); + *p = detoken(line, FALSE); +} + +/** + * find and process preprocessor directive in passed line + * Find out if a line contains a preprocessor directive, and deal + * with it if so. + * + * If a directive _is_ found, it is the responsibility of this routine + * (and not the caller) to free_tlist() the line. + * + * @param tline a pointer to the current tokeninzed line linked list + * @return DIRECTIVE_FOUND or NO_DIRECTIVE_FOUND + * + */ +static int +do_directive(Token * tline) +{ + int i, j, k, m, nparam, nolist; + int offset; + char *p, *mname, *newname; + Include *inc; + Context *ctx; + Cond *cond; + SMacro *smac, **smhead; + MMacro *mmac; + Token *t, *tt, *param_start, *macro_start, *last, **tptr, *origline; + Line *l; + struct tokenval tokval; + yasm_expr *evalresult; + MMacro *tmp_defining; /* Used when manipulating rep_nest */ + yasm_intnum *intn; + + origline = tline; + + skip_white_(tline); + if (!tok_type_(tline, TOK_PREPROC_ID) || + (tline->text[1] == '%' || tline->text[1] == '$' + || tline->text[1] == '!')) + return NO_DIRECTIVE_FOUND; + + i = -1; + j = elements(directives); + while (j - i > 1) + { + k = (j + i) / 2; + m = nasm_stricmp(tline->text, directives[k]); + if (m == 0) { + if (tasm_compatible_mode) { + i = k; + j = -2; + } else if (k != PP_ARG && k != PP_LOCAL && k != PP_STACKSIZE) { + i = k; + j = -2; + } + break; + } + else if (m < 0) { + j = k; + } + else + i = k; + } + + /* + * If we're in a non-emitting branch of a condition construct, + * or walking to the end of an already terminated %rep block, + * we should ignore all directives except for condition + * directives. + */ + if (((istk->conds && !emitting(istk->conds->state)) || + (istk->mstk && !istk->mstk->in_progress)) && + !is_condition(i)) + { + return NO_DIRECTIVE_FOUND; + } + + /* + * If we're defining a macro or reading a %rep block, we should + * ignore all directives except for %macro/%imacro (which + * generate an error), %endm/%endmacro, and (only if we're in a + * %rep block) %endrep. If we're in a %rep block, another %rep + * causes an error, so should be let through. + */ + if (defining && i != PP_MACRO && i != PP_IMACRO && + i != PP_ENDMACRO && i != PP_ENDM && + (defining->name || (i != PP_ENDREP && i != PP_REP))) + { + return NO_DIRECTIVE_FOUND; + } + + if (defining) { + if (i == PP_MACRO || i == PP_IMACRO) { + nested_mac_count++; + return NO_DIRECTIVE_FOUND; + } else if (nested_mac_count > 0) { + if (i == PP_ENDMACRO) { + nested_mac_count--; + return NO_DIRECTIVE_FOUND; + } + } + if (!defining->name) { + if (i == PP_REP) { + nested_rep_count++; + return NO_DIRECTIVE_FOUND; + } else if (nested_rep_count > 0) { + if (i == PP_ENDREP) { + nested_rep_count--; + return NO_DIRECTIVE_FOUND; + } + } + } + } + + if (j != -2) + { + error(ERR_NONFATAL, "unknown preprocessor directive `%s'", + tline->text); + return NO_DIRECTIVE_FOUND; /* didn't get it */ + } + + switch (i) + { + case PP_STACKSIZE: + /* Directive to tell NASM what the default stack size is. The + * default is for a 16-bit stack, and this can be overriden with + * %stacksize large. + * the following form: + * + * ARG arg1:WORD, arg2:DWORD, arg4:QWORD + */ + tline = tline->next; + if (tline && tline->type == TOK_WHITESPACE) + tline = tline->next; + if (!tline || tline->type != TOK_ID) + { + error(ERR_NONFATAL, "`%%stacksize' missing size parameter"); + free_tlist(origline); + return DIRECTIVE_FOUND; + } + if (nasm_stricmp(tline->text, "flat") == 0) + { + /* All subsequent ARG directives are for a 32-bit stack */ + StackSize = 4; + StackPointer = "ebp"; + ArgOffset = 8; + LocalOffset = 4; + } + else if (nasm_stricmp(tline->text, "large") == 0) + { + /* All subsequent ARG directives are for a 16-bit stack, + * far function call. + */ + StackSize = 2; + StackPointer = "bp"; + ArgOffset = 4; + LocalOffset = 2; + } + else if (nasm_stricmp(tline->text, "small") == 0) + { + /* All subsequent ARG directives are for a 16-bit stack, + * far function call. We don't support near functions. + */ + StackSize = 2; + StackPointer = "bp"; + ArgOffset = 6; + LocalOffset = 2; + } + else + { + error(ERR_NONFATAL, "`%%stacksize' invalid size type"); + free_tlist(origline); + return DIRECTIVE_FOUND; + } + free_tlist(origline); + return DIRECTIVE_FOUND; + + case PP_ARG: + /* TASM like ARG directive to define arguments to functions, in + * the following form: + * + * ARG arg1:WORD, arg2:DWORD, arg4:QWORD + */ + offset = ArgOffset; + do + { + char *arg, directive[256]; + int size = StackSize; + + /* Find the argument name */ + tline = tline->next; + if (tline && tline->type == TOK_WHITESPACE) + tline = tline->next; + if (!tline || tline->type != TOK_ID) + { + error(ERR_NONFATAL, "`%%arg' missing argument parameter"); + free_tlist(origline); + return DIRECTIVE_FOUND; + } + arg = tline->text; + + /* Find the argument size type */ + tline = tline->next; + if (!tline || tline->type != TOK_OTHER + || tline->text[0] != ':') + { + error(ERR_NONFATAL, + "Syntax error processing `%%arg' directive"); + free_tlist(origline); + return DIRECTIVE_FOUND; + } + tline = tline->next; + if (!tline || tline->type != TOK_ID) + { + error(ERR_NONFATAL, + "`%%arg' missing size type parameter"); + free_tlist(origline); + return DIRECTIVE_FOUND; + } + + /* Allow macro expansion of type parameter */ + tt = tokenise(tline->text); + tt = expand_smacro(tt); + if (nasm_stricmp(tt->text, "byte") == 0) + { + size = MAX(StackSize, 1); + } + else if (nasm_stricmp(tt->text, "word") == 0) + { + size = MAX(StackSize, 2); + } + else if (nasm_stricmp(tt->text, "dword") == 0) + { + size = MAX(StackSize, 4); + } + else if (nasm_stricmp(tt->text, "qword") == 0) + { + size = MAX(StackSize, 8); + } + else if (nasm_stricmp(tt->text, "tword") == 0) + { + size = MAX(StackSize, 10); + } + else + { + error(ERR_NONFATAL, + "Invalid size type for `%%arg' missing directive"); + free_tlist(tt); + free_tlist(origline); + return DIRECTIVE_FOUND; + } + free_tlist(tt); + + /* Now define the macro for the argument */ + sprintf(directive, "%%define %s (%s+%d)", arg, StackPointer, + offset); + do_directive(tokenise(directive)); + offset += size; + + /* Move to the next argument in the list */ + tline = tline->next; + if (tline && tline->type == TOK_WHITESPACE) + tline = tline->next; + } + while (tline && tline->type == TOK_OTHER + && tline->text[0] == ','); + free_tlist(origline); + return DIRECTIVE_FOUND; + + case PP_LOCAL: + /* TASM like LOCAL directive to define local variables for a + * function, in the following form: + * + * LOCAL local1:WORD, local2:DWORD, local4:QWORD = LocalSize + * + * The '= LocalSize' at the end is ignored by NASM, but is + * required by TASM to define the local parameter size (and used + * by the TASM macro package). + */ + offset = LocalOffset; + do + { + char *local, directive[256]; + int size = StackSize; + + /* Find the argument name */ + tline = tline->next; + if (tline && tline->type == TOK_WHITESPACE) + tline = tline->next; + if (!tline || tline->type != TOK_ID) + { + error(ERR_NONFATAL, + "`%%local' missing argument parameter"); + free_tlist(origline); + return DIRECTIVE_FOUND; + } + local = tline->text; + + /* Find the argument size type */ + tline = tline->next; + if (!tline || tline->type != TOK_OTHER + || tline->text[0] != ':') + { + error(ERR_NONFATAL, + "Syntax error processing `%%local' directive"); + free_tlist(origline); + return DIRECTIVE_FOUND; + } + tline = tline->next; + if (!tline || tline->type != TOK_ID) + { + error(ERR_NONFATAL, + "`%%local' missing size type parameter"); + free_tlist(origline); + return DIRECTIVE_FOUND; + } + + /* Allow macro expansion of type parameter */ + tt = tokenise(tline->text); + tt = expand_smacro(tt); + if (nasm_stricmp(tt->text, "byte") == 0) + { + size = MAX(StackSize, 1); + } + else if (nasm_stricmp(tt->text, "word") == 0) + { + size = MAX(StackSize, 2); + } + else if (nasm_stricmp(tt->text, "dword") == 0) + { + size = MAX(StackSize, 4); + } + else if (nasm_stricmp(tt->text, "qword") == 0) + { + size = MAX(StackSize, 8); + } + else if (nasm_stricmp(tt->text, "tword") == 0) + { + size = MAX(StackSize, 10); + } + else + { + error(ERR_NONFATAL, + "Invalid size type for `%%local' missing directive"); + free_tlist(tt); + free_tlist(origline); + return DIRECTIVE_FOUND; + } + free_tlist(tt); + + /* Now define the macro for the argument */ + sprintf(directive, "%%define %s (%s-%d)", local, StackPointer, + offset); + do_directive(tokenise(directive)); + offset += size; + + /* Now define the assign to setup the enter_c macro correctly */ + sprintf(directive, "%%assign %%$localsize %%$localsize+%d", + size); + do_directive(tokenise(directive)); + + /* Move to the next argument in the list */ + tline = tline->next; + if (tline && tline->type == TOK_WHITESPACE) + tline = tline->next; + } + while (tline && tline->type == TOK_OTHER + && tline->text[0] == ','); + free_tlist(origline); + return DIRECTIVE_FOUND; + + case PP_CLEAR: + if (tline->next) + error(ERR_WARNING, + "trailing garbage after `%%clear' ignored"); + for (j = 0; j < NHASH; j++) + { + while (mmacros[j]) + { + MMacro *m2 = mmacros[j]; + mmacros[j] = m2->next; + free_mmacro(m2); + } + while (smacros[j]) + { + SMacro *s = smacros[j]; + smacros[j] = smacros[j]->next; + nasm_free(s->name); + free_tlist(s->expansion); + nasm_free(s); + } + } + free_tlist(origline); + return DIRECTIVE_FOUND; + + case PP_INCLUDE: + tline = tline->next; + skip_white_(tline); + if (!tline || (tline->type != TOK_STRING && + tline->type != TOK_INTERNAL_STRING)) + { + error(ERR_NONFATAL, "`%%include' expects a file name"); + free_tlist(origline); + return DIRECTIVE_FOUND; /* but we did _something_ */ + } + if (tline->next) + error(ERR_WARNING, + "trailing garbage after `%%include' ignored"); + if (tline->type != TOK_INTERNAL_STRING) + { + p = tline->text + 1; /* point past the quote to the name */ + p[strlen(p) - 1] = '\0'; /* remove the trailing quote */ + } + else + p = tline->text; /* internal_string is easier */ + expand_macros_in_string(&p); + inc = nasm_malloc(sizeof(Include)); + inc->next = istk; + inc->conds = NULL; + inc->fp = inc_fopen(p, &newname); + inc->fname = nasm_src_set_fname(newname); + inc->lineno = nasm_src_set_linnum(0); + inc->lineinc = 1; + inc->expansion = NULL; + inc->mstk = NULL; + istk = inc; + list->uplevel(LIST_INCLUDE); + free_tlist(origline); + return DIRECTIVE_FOUND; + + case PP_PUSH: + tline = tline->next; + skip_white_(tline); + tline = expand_id(tline); + if (!tok_type_(tline, TOK_ID)) + { + error(ERR_NONFATAL, "`%%push' expects a context identifier"); + free_tlist(origline); + return DIRECTIVE_FOUND; /* but we did _something_ */ + } + if (tline->next) + error(ERR_WARNING, "trailing garbage after `%%push' ignored"); + ctx = nasm_malloc(sizeof(Context)); + ctx->next = cstk; + ctx->localmac = NULL; + ctx->name = nasm_strdup(tline->text); + ctx->number = unique++; + cstk = ctx; + free_tlist(origline); + break; + + case PP_REPL: + tline = tline->next; + skip_white_(tline); + tline = expand_id(tline); + if (!tok_type_(tline, TOK_ID)) + { + error(ERR_NONFATAL, "`%%repl' expects a context identifier"); + free_tlist(origline); + return DIRECTIVE_FOUND; /* but we did _something_ */ + } + if (tline->next) + error(ERR_WARNING, "trailing garbage after `%%repl' ignored"); + if (!cstk) + error(ERR_NONFATAL, "`%%repl': context stack is empty"); + else + { + nasm_free(cstk->name); + cstk->name = nasm_strdup(tline->text); + } + free_tlist(origline); + break; + + case PP_POP: + if (tline->next) + error(ERR_WARNING, "trailing garbage after `%%pop' ignored"); + if (!cstk) + error(ERR_NONFATAL, + "`%%pop': context stack is already empty"); + else + ctx_pop(); + free_tlist(origline); + break; + + case PP_SCOPE: + if (tline->next) + error(ERR_WARNING, "trailing garbage after `%%scope' ignored"); + Level++; + free_tlist(origline); + break; + + case PP_ENDSCOPE: + if (tline->next) + error(ERR_WARNING, "trailing garbage after `%%endscope' ignored"); + if (!Level) + error(ERR_NONFATAL, + "`%%endscope': already popped all levels"); + else + { + for (k = 0; k < NHASH; k++) + { + SMacro **smlast = &smacros[k]; + smac = smacros[k]; + while (smac) + { + if (smac->level < Level) + { + smlast = &smac->next; + smac = smac->next; + } + else + { + *smlast = smac->next; + nasm_free(smac->name); + free_tlist(smac->expansion); + nasm_free(smac); + smac = *smlast; + } + } + } + for (ctx = cstk; ctx; ctx = ctx->next) + { + SMacro **smlast = &ctx->localmac; + smac = ctx->localmac; + while (smac) + { + if (smac->level < Level) + { + smlast = &smac->next; + smac = smac->next; + } + else + { + *smlast = smac->next; + nasm_free(smac->name); + free_tlist(smac->expansion); + nasm_free(smac); + smac = *smlast; + } + } + } + Level--; + } + free_tlist(origline); + break; + + case PP_ERROR: + tline->next = expand_smacro(tline->next); + tline = tline->next; + skip_white_(tline); + if (tok_type_(tline, TOK_STRING)) + { + p = tline->text + 1; /* point past the quote to the name */ + p[strlen(p) - 1] = '\0'; /* remove the trailing quote */ + expand_macros_in_string(&p); + error(ERR_NONFATAL, "%s", p); + nasm_free(p); + } + else + { + p = detoken(tline, FALSE); + error(ERR_WARNING, "%s", p); + nasm_free(p); + } + free_tlist(origline); + break; + + case PP_IF: + case PP_IFCTX: + case PP_IFDEF: + case PP_IFID: + case PP_IFIDN: + case PP_IFIDNI: + case PP_IFMACRO: + case PP_IFNCTX: + case PP_IFNDEF: + case PP_IFNID: + case PP_IFNIDN: + case PP_IFNIDNI: + case PP_IFNMACRO: + case PP_IFNNUM: + case PP_IFNSTR: + case PP_IFNUM: + case PP_IFSTR: + if (istk->conds && !emitting(istk->conds->state)) + j = COND_NEVER; + else + { + j = if_condition(tline->next, i); + tline->next = NULL; /* it got freed */ + j = j < 0 ? COND_NEVER : j ? COND_IF_TRUE : COND_IF_FALSE; + } + free_tlist(origline); + cond = nasm_malloc(sizeof(Cond)); + cond->next = istk->conds; + cond->state = j; + istk->conds = cond; + return DIRECTIVE_FOUND; + + case PP_ELIF: + case PP_ELIFCTX: + case PP_ELIFDEF: + case PP_ELIFID: + case PP_ELIFIDN: + case PP_ELIFIDNI: + case PP_ELIFMACRO: + case PP_ELIFNCTX: + case PP_ELIFNDEF: + case PP_ELIFNID: + case PP_ELIFNIDN: + case PP_ELIFNIDNI: + case PP_ELIFNMACRO: + case PP_ELIFNNUM: + case PP_ELIFNSTR: + case PP_ELIFNUM: + case PP_ELIFSTR: + if (!istk->conds) + error(ERR_FATAL, "`%s': no matching `%%if'", directives[i]); + if (emitting(istk->conds->state) + || istk->conds->state == COND_NEVER) + istk->conds->state = COND_NEVER; + else + { + /* + * IMPORTANT: In the case of %if, we will already have + * called expand_mmac_params(); however, if we're + * processing an %elif we must have been in a + * non-emitting mode, which would have inhibited + * the normal invocation of expand_mmac_params(). Therefore, + * we have to do it explicitly here. + */ + j = if_condition(expand_mmac_params(tline->next), i); + tline->next = NULL; /* it got freed */ + istk->conds->state = + j < 0 ? COND_NEVER : j ? COND_IF_TRUE : COND_IF_FALSE; + } + free_tlist(origline); + return DIRECTIVE_FOUND; + + case PP_ELSE: + if (tline->next) + error(ERR_WARNING, "trailing garbage after `%%else' ignored"); + if (!istk->conds) + error(ERR_FATAL, "`%%else': no matching `%%if'"); + if (emitting(istk->conds->state) + || istk->conds->state == COND_NEVER) + istk->conds->state = COND_ELSE_FALSE; + else + istk->conds->state = COND_ELSE_TRUE; + free_tlist(origline); + return DIRECTIVE_FOUND; + + case PP_ENDIF: + if (tline->next) + error(ERR_WARNING, + "trailing garbage after `%%endif' ignored"); + if (!istk->conds) + error(ERR_FATAL, "`%%endif': no matching `%%if'"); + cond = istk->conds; + istk->conds = cond->next; + nasm_free(cond); + free_tlist(origline); + return DIRECTIVE_FOUND; + + case PP_MACRO: + case PP_IMACRO: + if (defining) + error(ERR_FATAL, + "`%%%smacro': already defining a macro", + (i == PP_IMACRO ? "i" : "")); + tline = tline->next; + skip_white_(tline); + tline = expand_id(tline); + if (!tok_type_(tline, TOK_ID)) + { + error(ERR_NONFATAL, + "`%%%smacro' expects a macro name", + (i == PP_IMACRO ? "i" : "")); + return DIRECTIVE_FOUND; + } + defining = nasm_malloc(sizeof(MMacro)); + defining->name = nasm_strdup(tline->text); + defining->casesense = (i == PP_MACRO); + defining->plus = FALSE; + defining->nolist = FALSE; + defining->in_progress = FALSE; + defining->rep_nest = NULL; + tline = expand_smacro(tline->next); + skip_white_(tline); + if (!tok_type_(tline, TOK_NUMBER)) + { + error(ERR_NONFATAL, + "`%%%smacro' expects a parameter count", + (i == PP_IMACRO ? "i" : "")); + defining->nparam_min = defining->nparam_max = 0; + } + else + { + intn = nasm_readnum(tline->text, &j); + defining->nparam_min = defining->nparam_max = + yasm_intnum_get_int(intn); + yasm_intnum_destroy(intn); + if (j) + error(ERR_NONFATAL, + "unable to parse parameter count `%s'", + tline->text); + } + if (tline && tok_is_(tline->next, "-")) + { + tline = tline->next->next; + if (tok_is_(tline, "*")) + defining->nparam_max = INT_MAX; + else if (!tok_type_(tline, TOK_NUMBER)) + error(ERR_NONFATAL, + "`%%%smacro' expects a parameter count after `-'", + (i == PP_IMACRO ? "i" : "")); + else + { + intn = nasm_readnum(tline->text, &j); + defining->nparam_max = yasm_intnum_get_int(intn); + yasm_intnum_destroy(intn); + if (j) + error(ERR_NONFATAL, + "unable to parse parameter count `%s'", + tline->text); + if (defining->nparam_min > defining->nparam_max) + error(ERR_NONFATAL, + "minimum parameter count exceeds maximum"); + } + } + if (tline && tok_is_(tline->next, "+")) + { + tline = tline->next; + defining->plus = TRUE; + } + if (tline && tok_type_(tline->next, TOK_ID) && + !nasm_stricmp(tline->next->text, ".nolist")) + { + tline = tline->next; + defining->nolist = TRUE; + } + mmac = mmacros[hash(defining->name)]; + while (mmac) + { + if (!strcmp(mmac->name, defining->name) && + (mmac->nparam_min <= defining->nparam_max + || defining->plus) + && (defining->nparam_min <= mmac->nparam_max + || mmac->plus)) + { + error(ERR_WARNING, + "redefining multi-line macro `%s'", + defining->name); + break; + } + mmac = mmac->next; + } + /* + * Handle default parameters. + */ + if (tline && tline->next) + { + defining->dlist = tline->next; + tline->next = NULL; + count_mmac_params(defining->dlist, &defining->ndefs, + &defining->defaults); + } + else + { + defining->dlist = NULL; + defining->defaults = NULL; + } + defining->expansion = NULL; + free_tlist(origline); + return DIRECTIVE_FOUND; + + case PP_ENDM: + case PP_ENDMACRO: + if (!defining) + { + error(ERR_NONFATAL, "`%s': not defining a macro", + tline->text); + return DIRECTIVE_FOUND; + } + k = hash(defining->name); + defining->next = mmacros[k]; + mmacros[k] = defining; + defining = NULL; + free_tlist(origline); + return DIRECTIVE_FOUND; + + case PP_ROTATE: + if (tline->next && tline->next->type == TOK_WHITESPACE) + tline = tline->next; + if (tline->next == NULL) + { + free_tlist(origline); + error(ERR_NONFATAL, "`%%rotate' missing rotate count"); + return DIRECTIVE_FOUND; + } + t = expand_smacro(tline->next); + tline->next = NULL; + free_tlist(origline); + tline = t; + tptr = &t; + tokval.t_type = TOKEN_INVALID; + evalresult = evaluate(ppscan, tptr, &tokval, pass, error); + free_tlist(tline); + if (!evalresult) + return DIRECTIVE_FOUND; + if (tokval.t_type) + error(ERR_WARNING, + "trailing garbage after expression ignored"); + intn = yasm_expr_get_intnum(&evalresult, 0); + if (!intn) + { + error(ERR_NONFATAL, "non-constant value given to `%%rotate'"); + yasm_expr_destroy(evalresult); + return DIRECTIVE_FOUND; + } + mmac = istk->mstk; + while (mmac && !mmac->name) /* avoid mistaking %reps for macros */ + mmac = mmac->next_active; + if (!mmac) + { + error(ERR_NONFATAL, + "`%%rotate' invoked outside a macro call"); + } + else if (mmac->nparam == 0) + { + error(ERR_NONFATAL, + "`%%rotate' invoked within macro without parameters"); + } + else + { + mmac->rotate = mmac->rotate + yasm_intnum_get_int(intn); + + if (mmac->rotate < 0) + mmac->rotate = + mmac->nparam - (-mmac->rotate) % mmac->nparam; + mmac->rotate %= mmac->nparam; + } + yasm_expr_destroy(evalresult); + return DIRECTIVE_FOUND; + + case PP_REP: + nolist = FALSE; + do { + tline = tline->next; + } while (tok_type_(tline, TOK_WHITESPACE)); + + if (tok_type_(tline, TOK_ID) && + nasm_stricmp(tline->text, ".nolist") == 0) + { + nolist = TRUE; + do { + tline = tline->next; + } while (tok_type_(tline, TOK_WHITESPACE)); + } + + if (tline) + { + t = expand_smacro(tline); + tptr = &t; + tokval.t_type = TOKEN_INVALID; + evalresult = evaluate(ppscan, tptr, &tokval, pass, error); + if (!evalresult) + { + free_tlist(origline); + return DIRECTIVE_FOUND; + } + if (tokval.t_type) + error(ERR_WARNING, + "trailing garbage after expression ignored"); + intn = yasm_expr_get_intnum(&evalresult, 0); + if (!intn) + { + error(ERR_NONFATAL, "non-constant value given to `%%rep'"); + yasm_expr_destroy(evalresult); + return DIRECTIVE_FOUND; + } + i = (int)yasm_intnum_get_int(intn) + 1; + yasm_expr_destroy(evalresult); + } + else + { + error(ERR_NONFATAL, "`%%rep' expects a repeat count"); + i = 0; + } + free_tlist(origline); + + tmp_defining = defining; + defining = nasm_malloc(sizeof(MMacro)); + defining->name = NULL; /* flags this macro as a %rep block */ + defining->casesense = 0; + defining->plus = FALSE; + defining->nolist = nolist; + defining->in_progress = i; + defining->nparam_min = defining->nparam_max = 0; + defining->defaults = NULL; + defining->dlist = NULL; + defining->expansion = NULL; + defining->next_active = istk->mstk; + defining->rep_nest = tmp_defining; + return DIRECTIVE_FOUND; + + case PP_ENDREP: + if (!defining || defining->name) + { + error(ERR_NONFATAL, "`%%endrep': no matching `%%rep'"); + return DIRECTIVE_FOUND; + } + + /* + * Now we have a "macro" defined - although it has no name + * and we won't be entering it in the hash tables - we must + * push a macro-end marker for it on to istk->expansion. + * After that, it will take care of propagating itself (a + * macro-end marker line for a macro which is really a %rep + * block will cause the macro to be re-expanded, complete + * with another macro-end marker to ensure the process + * continues) until the whole expansion is forcibly removed + * from istk->expansion by a %exitrep. + */ + l = nasm_malloc(sizeof(Line)); + l->next = istk->expansion; + l->finishes = defining; + l->first = NULL; + istk->expansion = l; + + istk->mstk = defining; + + list->uplevel(defining->nolist ? LIST_MACRO_NOLIST : LIST_MACRO); + tmp_defining = defining; + defining = defining->rep_nest; + free_tlist(origline); + return DIRECTIVE_FOUND; + + case PP_EXITREP: + /* + * We must search along istk->expansion until we hit a + * macro-end marker for a macro with no name. Then we set + * its `in_progress' flag to 0. + */ + for (l = istk->expansion; l; l = l->next) + if (l->finishes && !l->finishes->name) + break; + + if (l) + l->finishes->in_progress = 0; + else + error(ERR_NONFATAL, "`%%exitrep' not within `%%rep' block"); + free_tlist(origline); + return DIRECTIVE_FOUND; + + case PP_XDEFINE: + case PP_IXDEFINE: + case PP_DEFINE: + case PP_IDEFINE: + tline = tline->next; + skip_white_(tline); + tline = expand_id(tline); + if (!tline || (tline->type != TOK_ID && + (tline->type != TOK_PREPROC_ID || + tline->text[1] != '$'))) + { + error(ERR_NONFATAL, + "`%%%s%sdefine' expects a macro identifier", + ((i == PP_IDEFINE || i == PP_IXDEFINE) ? "i" : ""), + ((i == PP_XDEFINE || i == PP_IXDEFINE) ? "x" : "")); + free_tlist(origline); + return DIRECTIVE_FOUND; + } + + ctx = get_ctx(tline->text, FALSE); + if (!ctx) + smhead = &smacros[hash(tline->text)]; + else + smhead = &ctx->localmac; + mname = tline->text; + last = tline; + param_start = tline = tline->next; + nparam = 0; + + /* Expand the macro definition now for %xdefine and %ixdefine */ + if ((i == PP_XDEFINE) || (i == PP_IXDEFINE)) + tline = expand_smacro(tline); + + if (tok_is_(tline, "(")) + { + /* + * This macro has parameters. + */ + + tline = tline->next; + while (1) + { + skip_white_(tline); + if (!tline) + { + error(ERR_NONFATAL, "parameter identifier expected"); + free_tlist(origline); + return DIRECTIVE_FOUND; + } + if (tline->type != TOK_ID) + { + error(ERR_NONFATAL, + "`%s': parameter identifier expected", + tline->text); + free_tlist(origline); + return DIRECTIVE_FOUND; + } + tline->type = TOK_SMAC_PARAM + nparam++; + tline = tline->next; + skip_white_(tline); + if (tok_is_(tline, ",")) + { + tline = tline->next; + continue; + } + if (!tok_is_(tline, ")")) + { + error(ERR_NONFATAL, + "`)' expected to terminate macro template"); + free_tlist(origline); + return DIRECTIVE_FOUND; + } + break; + } + last = tline; + tline = tline->next; + } + if (tok_type_(tline, TOK_WHITESPACE)) + last = tline, tline = tline->next; + macro_start = NULL; + last->next = NULL; + t = tline; + while (t) + { + if (t->type == TOK_ID) + { + for (tt = param_start; tt; tt = tt->next) + if (tt->type >= TOK_SMAC_PARAM && + !strcmp(tt->text, t->text)) + t->type = tt->type; + } + tt = t->next; + t->next = macro_start; + macro_start = t; + t = tt; + } + /* + * Good. We now have a macro name, a parameter count, and a + * token list (in reverse order) for an expansion. We ought + * to be OK just to create an SMacro, store it, and let + * free_tlist have the rest of the line (which we have + * carefully re-terminated after chopping off the expansion + * from the end). + */ + if (smacro_defined(ctx, mname, nparam, &smac, i == PP_DEFINE)) + { + if (!smac) + { + error(ERR_WARNING, + "single-line macro `%s' defined both with and" + " without parameters", mname); + free_tlist(origline); + free_tlist(macro_start); + return DIRECTIVE_FOUND; + } + else if (smac->level == Level) + { + /* + * We're redefining in the same level, so we have to + * take over an existing SMacro structure. This means + * freeing what was already in it. + */ + nasm_free(smac->name); + free_tlist(smac->expansion); + } + else + { + smac = nasm_malloc(sizeof(SMacro)); + smac->next = *smhead; + *smhead = smac; + } + } + else + { + smac = nasm_malloc(sizeof(SMacro)); + smac->next = *smhead; + *smhead = smac; + } + smac->name = nasm_strdup(mname); + smac->casesense = ((i == PP_DEFINE) || (i == PP_XDEFINE)); + smac->nparam = nparam; + smac->level = Level; + smac->expansion = macro_start; + smac->in_progress = FALSE; + free_tlist(origline); + return DIRECTIVE_FOUND; + + case PP_UNDEF: + tline = tline->next; + skip_white_(tline); + tline = expand_id(tline); + if (!tline || (tline->type != TOK_ID && + (tline->type != TOK_PREPROC_ID || + tline->text[1] != '$'))) + { + error(ERR_NONFATAL, "`%%undef' expects a macro identifier"); + free_tlist(origline); + return DIRECTIVE_FOUND; + } + if (tline->next) + { + error(ERR_WARNING, + "trailing garbage after macro name ignored"); + } + + /* Find the context that symbol belongs to */ + ctx = get_ctx(tline->text, FALSE); + if (!ctx) + smhead = &smacros[hash(tline->text)]; + else + smhead = &ctx->localmac; + + mname = tline->text; + + /* + * We now have a macro name... go hunt for it. + */ + while (smacro_defined(ctx, mname, -1, &smac, 1)) + { + /* Defined, so we need to find its predecessor and nuke it */ + SMacro **s; + for (s = smhead; *s && *s != smac; s = &(*s)->next); + if (*s) + { + *s = smac->next; + nasm_free(smac->name); + free_tlist(smac->expansion); + nasm_free(smac); + } + } + free_tlist(origline); + return DIRECTIVE_FOUND; + + case PP_STRLEN: + tline = tline->next; + skip_white_(tline); + tline = expand_id(tline); + if (!tline || (tline->type != TOK_ID && + (tline->type != TOK_PREPROC_ID || + tline->text[1] != '$'))) + { + error(ERR_NONFATAL, + "`%%strlen' expects a macro identifier as first parameter"); + free_tlist(origline); + return DIRECTIVE_FOUND; + } + ctx = get_ctx(tline->text, FALSE); + if (!ctx) + smhead = &smacros[hash(tline->text)]; + else + smhead = &ctx->localmac; + mname = tline->text; + last = tline; + tline = expand_smacro(tline->next); + last->next = NULL; + + t = tline; + while (tok_type_(t, TOK_WHITESPACE)) + t = t->next; + /* t should now point to the string */ + if (t->type != TOK_STRING) + { + error(ERR_NONFATAL, + "`%%strlen` requires string as second parameter"); + free_tlist(tline); + free_tlist(origline); + return DIRECTIVE_FOUND; + } + + macro_start = nasm_malloc(sizeof(*macro_start)); + macro_start->next = NULL; + make_tok_num(macro_start, + yasm_intnum_create_uint((unsigned long)(strlen(t->text) - 2))); + macro_start->mac = NULL; + + /* + * We now have a macro name, an implicit parameter count of + * zero, and a numeric token to use as an expansion. Create + * and store an SMacro. + */ + if (smacro_defined(ctx, mname, 0, &smac, i == PP_STRLEN)) + { + if (!smac) + error(ERR_WARNING, + "single-line macro `%s' defined both with and" + " without parameters", mname); + else + { + /* + * We're redefining, so we have to take over an + * existing SMacro structure. This means freeing + * what was already in it. + */ + nasm_free(smac->name); + free_tlist(smac->expansion); + } + } + else + { + smac = nasm_malloc(sizeof(SMacro)); + smac->next = *smhead; + *smhead = smac; + } + smac->name = nasm_strdup(mname); + smac->casesense = (i == PP_STRLEN); + smac->nparam = 0; + smac->level = 0; + smac->expansion = macro_start; + smac->in_progress = FALSE; + free_tlist(tline); + free_tlist(origline); + return DIRECTIVE_FOUND; + + case PP_SUBSTR: + tline = tline->next; + skip_white_(tline); + tline = expand_id(tline); + if (!tline || (tline->type != TOK_ID && + (tline->type != TOK_PREPROC_ID || + tline->text[1] != '$'))) + { + error(ERR_NONFATAL, + "`%%substr' expects a macro identifier as first parameter"); + free_tlist(origline); + return DIRECTIVE_FOUND; + } + ctx = get_ctx(tline->text, FALSE); + if (!ctx) + smhead = &smacros[hash(tline->text)]; + else + smhead = &ctx->localmac; + mname = tline->text; + last = tline; + tline = expand_smacro(tline->next); + last->next = NULL; + + t = tline->next; + while (tok_type_(t, TOK_WHITESPACE)) + t = t->next; + + /* t should now point to the string */ + if (t->type != TOK_STRING) + { + error(ERR_NONFATAL, + "`%%substr` requires string as second parameter"); + free_tlist(tline); + free_tlist(origline); + return DIRECTIVE_FOUND; + } + + tt = t->next; + tptr = &tt; + tokval.t_type = TOKEN_INVALID; + evalresult = evaluate(ppscan, tptr, &tokval, pass, error); + if (!evalresult) + { + free_tlist(tline); + free_tlist(origline); + return DIRECTIVE_FOUND; + } + intn = yasm_expr_get_intnum(&evalresult, 0); + if (!intn) + { + error(ERR_NONFATAL, "non-constant value given to `%%substr`"); + free_tlist(tline); + free_tlist(origline); + yasm_expr_destroy(evalresult); + return DIRECTIVE_FOUND; + } + + macro_start = nasm_malloc(sizeof(*macro_start)); + macro_start->next = NULL; + macro_start->text = nasm_strdup("'''"); + if (yasm_intnum_sign(intn) == 1 + && yasm_intnum_get_uint(intn) < strlen(t->text) - 1) + { + macro_start->text[1] = t->text[yasm_intnum_get_uint(intn)]; + } + else + { + macro_start->text[2] = '\0'; + } + yasm_expr_destroy(evalresult); + macro_start->type = TOK_STRING; + macro_start->mac = NULL; + + /* + * We now have a macro name, an implicit parameter count of + * zero, and a numeric token to use as an expansion. Create + * and store an SMacro. + */ + if (smacro_defined(ctx, mname, 0, &smac, i == PP_SUBSTR)) + { + if (!smac) + error(ERR_WARNING, + "single-line macro `%s' defined both with and" + " without parameters", mname); + else + { + /* + * We're redefining, so we have to take over an + * existing SMacro structure. This means freeing + * what was already in it. + */ + nasm_free(smac->name); + free_tlist(smac->expansion); + } + } + else + { + smac = nasm_malloc(sizeof(SMacro)); + smac->next = *smhead; + *smhead = smac; + } + smac->name = nasm_strdup(mname); + smac->casesense = (i == PP_SUBSTR); + smac->nparam = 0; + smac->level = 0; + smac->expansion = macro_start; + smac->in_progress = FALSE; + free_tlist(tline); + free_tlist(origline); + return DIRECTIVE_FOUND; + + + case PP_ASSIGN: + case PP_IASSIGN: + tline = tline->next; + skip_white_(tline); + tline = expand_id(tline); + if (!tline || (tline->type != TOK_ID && + (tline->type != TOK_PREPROC_ID || + tline->text[1] != '$'))) + { + error(ERR_NONFATAL, + "`%%%sassign' expects a macro identifier", + (i == PP_IASSIGN ? "i" : "")); + free_tlist(origline); + return DIRECTIVE_FOUND; + } + ctx = get_ctx(tline->text, FALSE); + if (!ctx) + smhead = &smacros[hash(tline->text)]; + else + smhead = &ctx->localmac; + mname = tline->text; + last = tline; + tline = expand_smacro(tline->next); + last->next = NULL; + + t = tline; + tptr = &t; + tokval.t_type = TOKEN_INVALID; + evalresult = evaluate(ppscan, tptr, &tokval, pass, error); + free_tlist(tline); + if (!evalresult) + { + free_tlist(origline); + return DIRECTIVE_FOUND; + } + + if (tokval.t_type) + error(ERR_WARNING, + "trailing garbage after expression ignored"); + + intn = yasm_expr_get_intnum(&evalresult, 0); + if (!intn) + { + error(ERR_NONFATAL, + "non-constant value given to `%%%sassign'", + (i == PP_IASSIGN ? "i" : "")); + free_tlist(origline); + yasm_expr_destroy(evalresult); + return DIRECTIVE_FOUND; + } + + macro_start = nasm_malloc(sizeof(*macro_start)); + macro_start->next = NULL; + make_tok_num(macro_start, yasm_intnum_copy(intn)); + yasm_expr_destroy(evalresult); + macro_start->mac = NULL; + + /* + * We now have a macro name, an implicit parameter count of + * zero, and a numeric token to use as an expansion. Create + * and store an SMacro. + */ + if (smacro_defined(ctx, mname, 0, &smac, i == PP_ASSIGN)) + { + if (!smac) + error(ERR_WARNING, + "single-line macro `%s' defined both with and" + " without parameters", mname); + else + { + /* + * We're redefining, so we have to take over an + * existing SMacro structure. This means freeing + * what was already in it. + */ + nasm_free(smac->name); + free_tlist(smac->expansion); + } + } + else + { + smac = nasm_malloc(sizeof(SMacro)); + smac->next = *smhead; + *smhead = smac; + } + smac->name = nasm_strdup(mname); + smac->casesense = (i == PP_ASSIGN); + smac->nparam = 0; + smac->level = 0; + smac->expansion = macro_start; + smac->in_progress = FALSE; + free_tlist(origline); + return DIRECTIVE_FOUND; + + case PP_LINE: + /* + * Syntax is `%line nnn[+mmm] [filename]' + */ + tline = tline->next; + skip_white_(tline); + if (!tok_type_(tline, TOK_NUMBER)) + { + error(ERR_NONFATAL, "`%%line' expects line number"); + free_tlist(origline); + return DIRECTIVE_FOUND; + } + intn = nasm_readnum(tline->text, &j); + k = yasm_intnum_get_int(intn); + yasm_intnum_destroy(intn); + m = 1; + tline = tline->next; + if (tok_is_(tline, "+")) + { + tline = tline->next; + if (!tok_type_(tline, TOK_NUMBER)) + { + error(ERR_NONFATAL, "`%%line' expects line increment"); + free_tlist(origline); + return DIRECTIVE_FOUND; + } + intn = nasm_readnum(tline->text, &j); + m = yasm_intnum_get_int(intn); + yasm_intnum_destroy(intn); + tline = tline->next; + } + skip_white_(tline); + nasm_src_set_linnum(k); + istk->lineinc = m; + if (tline) + { + nasm_free(nasm_src_set_fname(detoken(tline, FALSE))); + } + free_tlist(origline); + return DIRECTIVE_FOUND; + + default: + error(ERR_FATAL, + "preprocessor directive `%s' not yet implemented", + directives[i]); + break; + } + return DIRECTIVE_FOUND; +} + +/* + * Ensure that a macro parameter contains a condition code and + * nothing else. Return the condition code index if so, or -1 + * otherwise. + */ +static int +find_cc(Token * t) +{ + Token *tt; + int i, j, k, m; + + skip_white_(t); + if (t->type != TOK_ID) + return -1; + tt = t->next; + skip_white_(tt); + if (tt && (tt->type != TOK_OTHER || strcmp(tt->text, ","))) + return -1; + + i = -1; + j = elements(conditions); + while (j - i > 1) + { + k = (j + i) / 2; + m = nasm_stricmp(t->text, conditions[k]); + if (m == 0) + { + i = k; + j = -2; + break; + } + else if (m < 0) + { + j = k; + } + else + i = k; + } + if (j != -2) + return -1; + return i; +} + +/* + * Expand MMacro-local things: parameter references (%0, %n, %+n, + * %-n) and MMacro-local identifiers (%%foo). + */ +static Token * +expand_mmac_params(Token * tline) +{ + Token *t, *tt, **tail, *thead; + + tail = &thead; + thead = NULL; + + while (tline) + { + if (tline->type == TOK_PREPROC_ID && + (((tline->text[1] == '+' || tline->text[1] == '-') + && tline->text[2]) || tline->text[1] == '%' + || (tline->text[1] >= '0' && tline->text[1] <= '9'))) + { + char *text = NULL; + int type = 0, cc; /* type = 0 to placate optimisers */ + char tmpbuf[30]; + char *second_text = NULL; + int n, i; + MMacro *mac; + + t = tline; + tline = tline->next; + + second_text = strchr(t->text, ':'); + + mac = istk->mstk; + while (mac && !mac->name) /* avoid mistaking %reps for macros */ + mac = mac->next_active; + if (!mac) + error(ERR_NONFATAL, "`%s': not in a macro call", t->text); + else + { + if (second_text) + { + int end = atoi(second_text+1)-1; + int is_fst = 1; + int k; + n = atoi(t->text + 1)-1; + if (end < 0) + end += mac->nparam; + + for (k = n; k <= end; k++) + { + if (k >= mac->nparam) + tt = NULL; + else + { + if (mac->nparam > 1) + k = (k + mac->rotate) % mac->nparam; + tt = mac->params[k]; + } + if (tt) + { + if (!is_fst && mac->paramlen[k]) + { + *tail = new_Token(NULL, TOK_OTHER, ",", 0); + tail = &(*tail)->next; + } + if (mac->paramlen[k]) + is_fst = 0; + for (i = 0; i < mac->paramlen[k]; i++) + { + *tail = + new_Token(NULL, tt->type, tt->text, + 0); + tail = &(*tail)->next; + tt = tt->next; + } + } + text = NULL; /* we've done it here */ + } + } + else + { + switch (t->text[1]) + { + /* + * We have to make a substitution of one of the + * forms %1, %-1, %+1, %%foo, %0. + */ + case '0': + type = TOK_NUMBER; + sprintf(tmpbuf, "%ld", mac->nparam); + text = nasm_strdup(tmpbuf); + break; + case '%': + type = TOK_ID; + sprintf(tmpbuf, "..@%lu.", mac->unique); + text = nasm_strcat(tmpbuf, t->text + 2); + break; + case '-': + n = atoi(t->text + 2) - 1; + if (n >= mac->nparam) + tt = NULL; + else + { + if (mac->nparam > 1) + n = (n + mac->rotate) % mac->nparam; + tt = mac->params[n]; + } + cc = find_cc(tt); + if (cc == -1) + { + error(ERR_NONFATAL, + "macro parameter %d is not a condition code", + n + 1); + text = NULL; + } + else + { + type = TOK_ID; + if (inverse_ccs[cc] == -1) + { + error(ERR_NONFATAL, + "condition code `%s' is not invertible", + conditions[cc]); + text = NULL; + } + else + text = + nasm_strdup(conditions[inverse_ccs + [cc]]); + } + break; + case '+': + n = atoi(t->text + 2) - 1; + if (n >= mac->nparam) + tt = NULL; + else + { + if (mac->nparam > 1) + n = (n + mac->rotate) % mac->nparam; + tt = mac->params[n]; + } + cc = find_cc(tt); + if (cc == -1) + { + error(ERR_NONFATAL, + "macro parameter %d is not a condition code", + n + 1); + text = NULL; + } + else + { + type = TOK_ID; + text = nasm_strdup(conditions[cc]); + } + break; + default: + n = atoi(t->text + 1) - 1; + if (n >= mac->nparam) + tt = NULL; + else + { + if (mac->nparam > 1) + n = (n + mac->rotate) % mac->nparam; + tt = mac->params[n]; + } + if (tt) + { + for (i = 0; i < mac->paramlen[n]; i++) + { + *tail = + new_Token(NULL, tt->type, tt->text, + 0); + tail = &(*tail)->next; + tt = tt->next; + } + } + text = NULL; /* we've done it here */ + break; + } + } + } + + if (!text) + { + delete_Token(t); + } + else + { + *tail = t; + tail = &t->next; + t->type = type; + nasm_free(t->text); + t->text = text; + t->mac = NULL; + } + continue; + } + else + { + t = *tail = tline; + tline = tline->next; + t->mac = NULL; + tail = &t->next; + } + } + *tail = NULL; + t = thead; + for (; t && (tt = t->next) != NULL; t = t->next) + switch (t->type) + { + case TOK_WHITESPACE: + if (tt->type == TOK_WHITESPACE) + { + t->next = delete_Token(tt); + } + break; + case TOK_ID: + if (tt->type == TOK_ID || tt->type == TOK_NUMBER) + { + char *tmp = nasm_strcat(t->text, tt->text); + nasm_free(t->text); + t->text = tmp; + t->next = delete_Token(tt); + } + break; + case TOK_NUMBER: + if (tt->type == TOK_NUMBER) + { + char *tmp = nasm_strcat(t->text, tt->text); + nasm_free(t->text); + t->text = tmp; + t->next = delete_Token(tt); + } + break; + } + + return thead; +} + +/* + * Expand all single-line macro calls made in the given line. + * Return the expanded version of the line. The original is deemed + * to be destroyed in the process. (In reality we'll just move + * Tokens from input to output a lot of the time, rather than + * actually bothering to destroy and replicate.) + */ +static Token * +expand_smacro(Token * tline) +{ + Token *t, *tt, *mstart, **tail, *thead; + SMacro *head = NULL, *m; + Token **params; + int *paramsize; + int nparam, sparam, brackets, rescan; + Token *org_tline = tline; + Context *ctx; + char *mname; + + /* + * Trick: we should avoid changing the start token pointer since it can + * be contained in "next" field of other token. Because of this + * we allocate a copy of first token and work with it; at the end of + * routine we copy it back + */ + if (org_tline) + { + tline = + new_Token(org_tline->next, org_tline->type, org_tline->text, + 0); + tline->mac = org_tline->mac; + nasm_free(org_tline->text); + org_tline->text = NULL; + } + + again: + tail = &thead; + thead = NULL; + + while (tline) + { /* main token loop */ + if ((mname = tline->text)) + { + /* if this token is a local macro, look in local context */ + if (tline->type == TOK_ID || tline->type == TOK_PREPROC_ID) + ctx = get_ctx(mname, TRUE); + else + ctx = NULL; + if (!ctx) + head = smacros[hash(mname)]; + else + head = ctx->localmac; + /* + * We've hit an identifier. As in is_mmacro below, we first + * check whether the identifier is a single-line macro at + * all, then think about checking for parameters if + * necessary. + */ + for (m = head; m; m = m->next) + if (!mstrcmp(m->name, mname, m->casesense)) + break; + if (m) + { + mstart = tline; + params = NULL; + paramsize = NULL; + if (m->nparam == 0) + { + /* + * Simple case: the macro is parameterless. Discard the + * one token that the macro call took, and push the + * expansion back on the to-do stack. + */ + if (!m->expansion) + { + if (!strcmp("__FILE__", m->name)) + { + long num = 0; + nasm_src_get(&num, &(tline->text)); + nasm_quote(&(tline->text)); + tline->type = TOK_STRING; + continue; + } + if (!strcmp("__LINE__", m->name)) + { + nasm_free(tline->text); + make_tok_num(tline, yasm_intnum_create_int(nasm_src_get_linnum())); + continue; + } + tline = delete_Token(tline); + continue; + } + } + else + { + /* + * Complicated case: at least one macro with this name + * exists and takes parameters. We must find the + * parameters in the call, count them, find the SMacro + * that corresponds to that form of the macro call, and + * substitute for the parameters when we expand. What a + * pain. + */ + /*tline = tline->next; + skip_white_(tline);*/ + do { + t = tline->next; + while (tok_type_(t, TOK_SMAC_END)) + { + t->mac->in_progress = FALSE; + t->text = NULL; + t = tline->next = delete_Token(t); + } + tline = t; + } while (tok_type_(tline, TOK_WHITESPACE)); + if (!tok_is_(tline, "(")) + { + /* + * This macro wasn't called with parameters: ignore + * the call. (Behaviour borrowed from gnu cpp.) + */ + tline = mstart; + m = NULL; + } + else + { + int paren = 0; + int white = 0; + brackets = 0; + nparam = 0; + sparam = PARAM_DELTA; + params = nasm_malloc(sparam * sizeof(Token *)); + params[0] = tline->next; + paramsize = nasm_malloc(sparam * sizeof(int)); + paramsize[0] = 0; + while (TRUE) + { /* parameter loop */ + /* + * For some unusual expansions + * which concatenates function call + */ + t = tline->next; + while (tok_type_(t, TOK_SMAC_END)) + { + t->mac->in_progress = FALSE; + t->text = NULL; + t = tline->next = delete_Token(t); + } + tline = t; + + if (!tline) + { + error(ERR_NONFATAL, + "macro call expects terminating `)'"); + break; + } + if (tline->type == TOK_WHITESPACE + && brackets <= 0) + { + if (paramsize[nparam]) + white++; + else + params[nparam] = tline->next; + continue; /* parameter loop */ + } + if (tline->type == TOK_OTHER + && tline->text[1] == 0) + { + char ch = tline->text[0]; + if (ch == ',' && !paren && brackets <= 0) + { + if (++nparam >= sparam) + { + sparam += PARAM_DELTA; + params = nasm_realloc(params, + sparam * sizeof(Token *)); + paramsize = nasm_realloc(paramsize, + sparam * sizeof(int)); + } + params[nparam] = tline->next; + paramsize[nparam] = 0; + white = 0; + continue; /* parameter loop */ + } + if (ch == '{' && + (brackets > 0 || (brackets == 0 && + !paramsize[nparam]))) + { + if (!(brackets++)) + { + params[nparam] = tline->next; + continue; /* parameter loop */ + } + } + if (ch == '}' && brackets > 0) + if (--brackets == 0) + { + brackets = -1; + continue; /* parameter loop */ + } + if (ch == '(' && !brackets) + paren++; + if (ch == ')' && brackets <= 0) + if (--paren < 0) + break; + } + if (brackets < 0) + { + brackets = 0; + error(ERR_NONFATAL, "braces do not " + "enclose all of macro parameter"); + } + paramsize[nparam] += white + 1; + white = 0; + } /* parameter loop */ + nparam++; + while (m && (m->nparam != nparam || + mstrcmp(m->name, mname, + m->casesense))) + m = m->next; + if (!m) + error(ERR_WARNING | ERR_WARN_MNP, + "macro `%s' exists, " + "but not taking %d parameters", + mstart->text, nparam); + } + } + if (m && m->in_progress) + m = NULL; + if (!m) /* in progess or didn't find '(' or wrong nparam */ + { + /* + * Design question: should we handle !tline, which + * indicates missing ')' here, or expand those + * macros anyway, which requires the (t) test a few + * lines down? + */ + nasm_free(params); + nasm_free(paramsize); + tline = mstart; + } + else + { + /* + * Expand the macro: we are placed on the last token of the + * call, so that we can easily split the call from the + * following tokens. We also start by pushing an SMAC_END + * token for the cycle removal. + */ + t = tline; + if (t) + { + tline = t->next; + t->next = NULL; + } + tt = new_Token(tline, TOK_SMAC_END, NULL, 0); + tt->mac = m; + m->in_progress = TRUE; + tline = tt; + for (t = m->expansion; t; t = t->next) + { + if (t->type >= TOK_SMAC_PARAM) + { + Token *pcopy = tline, **ptail = &pcopy; + Token *ttt, *pt; + int i; + + ttt = params[t->type - TOK_SMAC_PARAM]; + for (i = paramsize[t->type - TOK_SMAC_PARAM]; + --i >= 0;) + { + pt = *ptail = + new_Token(tline, ttt->type, ttt->text, + 0); + ptail = &pt->next; + ttt = ttt->next; + } + tline = pcopy; + } + else + { + tt = new_Token(tline, t->type, t->text, 0); + tline = tt; + } + } + + /* + * Having done that, get rid of the macro call, and clean + * up the parameters. + */ + nasm_free(params); + nasm_free(paramsize); + free_tlist(mstart); + continue; /* main token loop */ + } + } + } + + if (tline->type == TOK_SMAC_END) + { + tline->mac->in_progress = FALSE; + tline = delete_Token(tline); + } + else + { + t = *tail = tline; + tline = tline->next; + t->mac = NULL; + t->next = NULL; + tail = &t->next; + } + } + + /* + * Now scan the entire line and look for successive TOK_IDs that resulted + * after expansion (they can't be produced by tokenise()). The successive + * TOK_IDs should be concatenated. + * Also we look for %+ tokens and concatenate the tokens before and after + * them (without white spaces in between). + */ + t = thead; + rescan = 0; + while (t) + { + while (t && t->type != TOK_ID && t->type != TOK_PREPROC_ID) + t = t->next; + if (!t || !t->next) + break; + if (t->next->type == TOK_ID || + t->next->type == TOK_PREPROC_ID || + t->next->type == TOK_NUMBER) + { + char *p = nasm_strcat(t->text, t->next->text); + nasm_free(t->text); + t->next = delete_Token(t->next); + t->text = p; + rescan = 1; + } + else if (t->next->type == TOK_WHITESPACE && t->next->next && + t->next->next->type == TOK_PREPROC_ID && + strcmp(t->next->next->text, "%+") == 0) + { + /* free the next whitespace, the %+ token and next whitespace */ + int i; + for (i = 1; i <= 3; i++) + { + if (!t->next || (i != 2 && t->next->type != TOK_WHITESPACE)) + break; + t->next = delete_Token(t->next); + } /* endfor */ + } + else + t = t->next; + } + /* If we concatenaded something, re-scan the line for macros */ + if (rescan) + { + tline = thead; + goto again; + } + + if (org_tline) + { + if (thead) + { + *org_tline = *thead; + /* since we just gave text to org_line, don't free it */ + thead->text = NULL; + delete_Token(thead); + } + else + { + /* the expression expanded to empty line; + we can't return NULL for some reasons + we just set the line to a single WHITESPACE token. */ + memset(org_tline, 0, sizeof(*org_tline)); + org_tline->text = NULL; + org_tline->type = TOK_WHITESPACE; + } + thead = org_tline; + } + + return thead; +} + +/* + * Similar to expand_smacro but used exclusively with macro identifiers + * right before they are fetched in. The reason is that there can be + * identifiers consisting of several subparts. We consider that if there + * are more than one element forming the name, user wants a expansion, + * otherwise it will be left as-is. Example: + * + * %define %$abc cde + * + * the identifier %$abc will be left as-is so that the handler for %define + * will suck it and define the corresponding value. Other case: + * + * %define _%$abc cde + * + * In this case user wants name to be expanded *before* %define starts + * working, so we'll expand %$abc into something (if it has a value; + * otherwise it will be left as-is) then concatenate all successive + * PP_IDs into one. + */ +static Token * +expand_id(Token * tline) +{ + Token *cur, *oldnext = NULL; + + if (!tline || !tline->next) + return tline; + + cur = tline; + while (cur->next && + (cur->next->type == TOK_ID || + cur->next->type == TOK_PREPROC_ID || cur->next->type == TOK_NUMBER)) + cur = cur->next; + + /* If identifier consists of just one token, don't expand */ + if (cur == tline) + return tline; + + if (cur) + { + oldnext = cur->next; /* Detach the tail past identifier */ + cur->next = NULL; /* so that expand_smacro stops here */ + } + + tline = expand_smacro(tline); + + if (cur) + { + /* expand_smacro possibly changhed tline; re-scan for EOL */ + cur = tline; + while (cur && cur->next) + cur = cur->next; + if (cur) + cur->next = oldnext; + } + + return tline; +} + +/* + * Determine whether the given line constitutes a multi-line macro + * call, and return the MMacro structure called if so. Doesn't have + * to check for an initial label - that's taken care of in + * expand_mmacro - but must check numbers of parameters. Guaranteed + * to be called with tline->type == TOK_ID, so the putative macro + * name is easy to find. + */ +static MMacro * +is_mmacro(Token * tline, Token *** params_array) +{ + MMacro *head, *m; + Token **params; + int nparam; + + head = mmacros[hash(tline->text)]; + + /* + * Efficiency: first we see if any macro exists with the given + * name. If not, we can return NULL immediately. _Then_ we + * count the parameters, and then we look further along the + * list if necessary to find the proper MMacro. + */ + for (m = head; m; m = m->next) + if (!mstrcmp(m->name, tline->text, m->casesense)) + break; + if (!m) + return NULL; + + /* + * OK, we have a potential macro. Count and demarcate the + * parameters. + */ + count_mmac_params(tline->next, &nparam, ¶ms); + + /* + * So we know how many parameters we've got. Find the MMacro + * structure that handles this number. + */ + while (m) + { + if (m->nparam_min <= nparam && (m->plus || nparam <= m->nparam_max)) + { + /* + * This one is right. Just check if cycle removal + * prohibits us using it before we actually celebrate... + */ + if (m->in_progress) + { +#if 0 + error(ERR_NONFATAL, + "self-reference in multi-line macro `%s'", m->name); +#endif + nasm_free(params); + return NULL; + } + /* + * It's right, and we can use it. Add its default + * parameters to the end of our list if necessary. + */ + if (m->defaults && nparam < m->nparam_min + m->ndefs) + { + params = + nasm_realloc(params, + ((m->nparam_min + m->ndefs + 1) * sizeof(*params))); + while (nparam < m->nparam_min + m->ndefs) + { + params[nparam] = m->defaults[nparam - m->nparam_min]; + nparam++; + } + } + /* + * If we've gone over the maximum parameter count (and + * we're in Plus mode), ignore parameters beyond + * nparam_max. + */ + if (m->plus && nparam > m->nparam_max) + nparam = m->nparam_max; + /* + * Then terminate the parameter list, and leave. + */ + if (!params) + { /* need this special case */ + params = nasm_malloc(sizeof(*params)); + nparam = 0; + } + params[nparam] = NULL; + *params_array = params; + return m; + } + /* + * This one wasn't right: look for the next one with the + * same name. + */ + for (m = m->next; m; m = m->next) + if (!mstrcmp(m->name, tline->text, m->casesense)) + break; + } + + /* + * After all that, we didn't find one with the right number of + * parameters. Issue a warning, and fail to expand the macro. + */ + error(ERR_WARNING | ERR_WARN_MNP, + "macro `%s' exists, but not taking %d parameters", + tline->text, nparam); + nasm_free(params); + return NULL; +} + +/* + * Expand the multi-line macro call made by the given line, if + * there is one to be expanded. If there is, push the expansion on + * istk->expansion and return 1. Otherwise return 0. + */ +static int +expand_mmacro(Token * tline) +{ + Token *startline = tline; + Token *label = NULL; + int dont_prepend = 0; + Token **params, *t, *tt; + MMacro *m; + Line *l, *ll; + int i, nparam; + long *paramlen; + + t = tline; + skip_white_(t); +/* if (!tok_type_(t, TOK_ID)) Lino 02/25/02 */ + if (!tok_type_(t, TOK_ID) && !tok_type_(t, TOK_PREPROC_ID)) + return 0; + m = is_mmacro(t, ¶ms); + if (!m) + { + Token *last; + /* + * We have an id which isn't a macro call. We'll assume + * it might be a label; we'll also check to see if a + * colon follows it. Then, if there's another id after + * that lot, we'll check it again for macro-hood. + */ + label = last = t; + t = t->next; + if (tok_type_(t, TOK_WHITESPACE)) + last = t, t = t->next; + if (tok_is_(t, ":")) + { + dont_prepend = 1; + last = t, t = t->next; + if (tok_type_(t, TOK_WHITESPACE)) + last = t, t = t->next; + } + if (!tok_type_(t, TOK_ID) || (m = is_mmacro(t, ¶ms)) == NULL) + return 0; + last->next = NULL; + tline = t; + } + + /* + * Fix up the parameters: this involves stripping leading and + * trailing whitespace, then stripping braces if they are + * present. + */ + for (nparam = 0; params[nparam]; nparam++) + ; + paramlen = nparam ? nasm_malloc(nparam * sizeof(*paramlen)) : NULL; + + for (i = 0; params[i]; i++) + { + int brace = FALSE; + int comma = (!m->plus || i < nparam - 1); + + t = params[i]; + skip_white_(t); + if (tok_is_(t, "{")) + t = t->next, brace = TRUE, comma = FALSE; + params[i] = t; + paramlen[i] = 0; + while (t) + { + if (comma && t->type == TOK_OTHER && !strcmp(t->text, ",")) + break; /* ... because we have hit a comma */ + if (comma && t->type == TOK_WHITESPACE && tok_is_(t->next, ",")) + break; /* ... or a space then a comma */ + if (brace && t->type == TOK_OTHER && !strcmp(t->text, "}")) + break; /* ... or a brace */ + t = t->next; + paramlen[i]++; + } + } + + /* + * OK, we have a MMacro structure together with a set of + * parameters. We must now go through the expansion and push + * copies of each Line on to istk->expansion. Substitution of + * parameter tokens and macro-local tokens doesn't get done + * until the single-line macro substitution process; this is + * because delaying them allows us to change the semantics + * later through %rotate. + * + * First, push an end marker on to istk->expansion, mark this + * macro as in progress, and set up its invocation-specific + * variables. + */ + ll = nasm_malloc(sizeof(Line)); + ll->next = istk->expansion; + ll->finishes = m; + ll->first = NULL; + istk->expansion = ll; + + m->in_progress = TRUE; + m->params = params; + m->iline = tline; + m->nparam = nparam; + m->rotate = 0; + m->paramlen = paramlen; + m->unique = unique++; + m->lineno = 0; + + m->next_active = istk->mstk; + istk->mstk = m; + + for (l = m->expansion; l; l = l->next) + { + Token **tail; + + ll = nasm_malloc(sizeof(Line)); + ll->finishes = NULL; + ll->next = istk->expansion; + istk->expansion = ll; + tail = &ll->first; + + for (t = l->first; t; t = t->next) + { + Token *x = t; + if (t->type == TOK_PREPROC_ID && + t->text[1] == '0' && t->text[2] == '0') + { + dont_prepend = -1; + x = label; + if (!x) + continue; + } + tt = *tail = new_Token(NULL, x->type, x->text, 0); + tail = &tt->next; + } + *tail = NULL; + } + + /* + * If we had a label, push it on as the first line of + * the macro expansion. + */ + if (label) + { + if (dont_prepend < 0) + free_tlist(startline); + else + { + ll = nasm_malloc(sizeof(Line)); + ll->finishes = NULL; + ll->next = istk->expansion; + istk->expansion = ll; + ll->first = startline; + if (!dont_prepend) + { + while (label->next) + label = label->next; + label->next = tt = new_Token(NULL, TOK_OTHER, ":", 0); + } + } + } + + list->uplevel(m->nolist ? LIST_MACRO_NOLIST : LIST_MACRO); + + return 1; +} + +/* + * Since preprocessor always operates only on the line that didn't + * arrive yet, we should always use ERR_OFFBY1. Also since user + * won't want to see same error twice (preprocessing is done once + * per pass) we will want to show errors only during pass one. + */ +static void +error(int severity, const char *fmt, ...) +{ + va_list arg; + char buff[1024]; + + /* If we're in a dead branch of IF or something like it, ignore the error */ + if (istk && istk->conds && !emitting(istk->conds->state)) + return; + + va_start(arg, fmt); +#ifdef HAVE_VSNPRINTF + vsnprintf(buff, sizeof(buff), fmt, arg); +#else + vsprintf(buff, fmt, arg); +#endif + va_end(arg); + + if (istk && istk->mstk && istk->mstk->name) + _error(severity | ERR_PASS1, "(%s:%d) %s", istk->mstk->name, + istk->mstk->lineno, buff); + else + _error(severity | ERR_PASS1, "%s", buff); +} + +static void +pp_reset(FILE *f, const char *file, int apass, efunc errfunc, evalfunc eval, + ListGen * listgen) +{ + int h; + + first_fp = f; + _error = errfunc; + cstk = NULL; + istk = nasm_malloc(sizeof(Include)); + istk->next = NULL; + istk->conds = NULL; + istk->expansion = NULL; + istk->mstk = NULL; + istk->fp = f; + istk->fname = NULL; + nasm_free(nasm_src_set_fname(nasm_strdup(file))); + nasm_src_set_linnum(0); + istk->lineinc = 1; + defining = NULL; + nested_mac_count = 0; + nested_rep_count = 0; + for (h = 0; h < NHASH; h++) + { + mmacros[h] = NULL; + smacros[h] = NULL; + } + unique = 0; + if (tasm_compatible_mode) { + pp_extra_stdmac(tasm_compat_macros); + } + list = listgen; + evaluate = eval; + pass = apass; + first_line = 1; +} + +/* + * Nasty hack: here we push the contents of `predef' on + * to the top-level expansion stack, since this is the + * most convenient way to implement the pre-include and + * pre-define features. + */ +static void +poke_predef(Line *predef_lines) +{ + Line *pd, *l; + Token *head, **tail, *t; + + for (pd = predef_lines; pd; pd = pd->next) + { + head = NULL; + tail = &head; + for (t = pd->first; t; t = t->next) + { + *tail = new_Token(NULL, t->type, t->text, 0); + tail = &(*tail)->next; + } + l = nasm_malloc(sizeof(Line)); + l->next = istk->expansion; + l->first = head; + l->finishes = FALSE; + istk->expansion = l; + } +} + +static char * +pp_getline(void) +{ + char *line; + Token *tline; + + while (1) + { + /* + * Fetch a tokenised line, either from the macro-expansion + * buffer or from the input file. + */ + tline = NULL; + + if (first_line) + { + /* Reverse order */ + poke_predef(predef); + poke_predef(stddef); + poke_predef(builtindef); + first_line = 0; + } + + if (!istk) + return NULL; + while (istk->expansion && istk->expansion->finishes) + { + Line *l = istk->expansion; + if (!l->finishes->name && l->finishes->in_progress > 1) + { + Line *ll; + + /* + * This is a macro-end marker for a macro with no + * name, which means it's not really a macro at all + * but a %rep block, and the `in_progress' field is + * more than 1, meaning that we still need to + * repeat. (1 means the natural last repetition; 0 + * means termination by %exitrep.) We have + * therefore expanded up to the %endrep, and must + * push the whole block on to the expansion buffer + * again. We don't bother to remove the macro-end + * marker: we'd only have to generate another one + * if we did. + */ + l->finishes->in_progress--; + for (l = l->finishes->expansion; l; l = l->next) + { + Token *t, *tt, **tail; + + ll = nasm_malloc(sizeof(Line)); + ll->next = istk->expansion; + ll->finishes = NULL; + ll->first = NULL; + tail = &ll->first; + + for (t = l->first; t; t = t->next) + { + if (t->text || t->type == TOK_WHITESPACE) + { + tt = *tail = new_Token(NULL, t->type, t->text, 0); + tail = &tt->next; + } + } + + istk->expansion = ll; + } + } + else + { + /* + * Check whether a `%rep' was started and not ended + * within this macro expansion. This can happen and + * should be detected. It's a fatal error because + * I'm too confused to work out how to recover + * sensibly from it. + */ + if (defining) + { + if (defining->name) + error(ERR_PANIC, "defining with name in expansion"); + else if (istk->mstk->name) + error(ERR_FATAL, "`%%rep' without `%%endrep' within" + " expansion of macro `%s'", istk->mstk->name); + } + + /* + * FIXME: investigate the relationship at this point between + * istk->mstk and l->finishes + */ + { + MMacro *m = istk->mstk; + istk->mstk = m->next_active; + if (m->name) + { + /* + * This was a real macro call, not a %rep, and + * therefore the parameter information needs to + * be freed. + */ + nasm_free(m->params); + free_tlist(m->iline); + nasm_free(m->paramlen); + l->finishes->in_progress = FALSE; + } + else + free_mmacro(m); + } + istk->expansion = l->next; + nasm_free(l); + list->downlevel(LIST_MACRO); + } + } + while (1) + { /* until we get a line we can use */ + + if (istk->expansion) + { /* from a macro expansion */ + char *p; + Line *l = istk->expansion; + if (istk->mstk) + istk->mstk->lineno++; + tline = l->first; + istk->expansion = l->next; + nasm_free(l); + p = detoken(tline, FALSE); + list->line(LIST_MACRO, p); + nasm_free(p); + break; + } + line = read_line(); + if (line) + { /* from the current input file */ + line = prepreproc(line); + tline = tokenise(line); + nasm_free(line); + break; + } + /* + * The current file has ended; work down the istk + */ + { + Include *i = istk; + if (i->fp != first_fp) + fclose(i->fp); + if (i->conds) + error(ERR_FATAL, "expected `%%endif' before end of file"); + /* only set line and file name if there's a next node */ + if (i->next) + { + nasm_src_set_linnum(i->lineno); + nasm_free(nasm_src_set_fname(nasm_strdup(i->fname))); + } + istk = i->next; + list->downlevel(LIST_INCLUDE); + nasm_free(i); + if (!istk) + return NULL; + if (istk->expansion && istk->expansion->finishes) + break; + } + } + + /* + * We must expand MMacro parameters and MMacro-local labels + * _before_ we plunge into directive processing, to cope + * with things like `%define something %1' such as STRUC + * uses. Unless we're _defining_ a MMacro, in which case + * those tokens should be left alone to go into the + * definition; and unless we're in a non-emitting + * condition, in which case we don't want to meddle with + * anything. + */ + if (!defining && !(istk->conds && !emitting(istk->conds->state))) + tline = expand_mmac_params(tline); + + /* + * Check the line to see if it's a preprocessor directive. + */ + if (do_directive(tline) == DIRECTIVE_FOUND) + { + continue; + } + else if (defining) + { + /* + * We're defining a multi-line macro. We emit nothing + * at all, and just + * shove the tokenised line on to the macro definition. + */ + Line *l = nasm_malloc(sizeof(Line)); + l->next = defining->expansion; + l->first = tline; + l->finishes = FALSE; + defining->expansion = l; + continue; + } + else if (istk->conds && !emitting(istk->conds->state)) + { + /* + * We're in a non-emitting branch of a condition block. + * Emit nothing at all, not even a blank line: when we + * emerge from the condition we'll give a line-number + * directive so we keep our place correctly. + */ + free_tlist(tline); + continue; + } + else if (istk->mstk && !istk->mstk->in_progress) + { + /* + * We're in a %rep block which has been terminated, so + * we're walking through to the %endrep without + * emitting anything. Emit nothing at all, not even a + * blank line: when we emerge from the %rep block we'll + * give a line-number directive so we keep our place + * correctly. + */ + free_tlist(tline); + continue; + } + else + { + tline = expand_smacro(tline); + if (!expand_mmacro(tline)) + { + /* + * De-tokenise the line again, and emit it. + */ + if (tasm_compatible_mode) + tline = tasm_join_tokens(tline); + + line = detoken(tline, TRUE); + free_tlist(tline); + break; + } + else + { + continue; /* expand_mmacro calls free_tlist */ + } + } + } + + return line; +} + +static void +pp_cleanup(int pass_) +{ + int h; + + if (pass_ == 1) + { + if (defining) + { + error(ERR_NONFATAL, "end of file while still defining macro `%s'", + defining->name); + free_mmacro(defining); + } + return; + } + while (cstk) + ctx_pop(); + for (h = 0; h < NHASH; h++) + { + while (mmacros[h]) + { + MMacro *m = mmacros[h]; + mmacros[h] = mmacros[h]->next; + free_mmacro(m); + } + while (smacros[h]) + { + SMacro *s = smacros[h]; + smacros[h] = smacros[h]->next; + nasm_free(s->name); + free_tlist(s->expansion); + nasm_free(s); + } + } + while (istk) + { + Include *i = istk; + istk = istk->next; + if (i->fp != first_fp) + fclose(i->fp); + nasm_free(i->fname); + nasm_free(i); + } + while (cstk) + ctx_pop(); + if (pass_ == 0) + { + free_llist(builtindef); + free_llist(stddef); + free_llist(predef); + builtindef = NULL; + stddef = NULL; + predef = NULL; + freeTokens = NULL; + delete_Blocks(); + blocks.next = NULL; + blocks.chunk = NULL; + } +} + +void +pp_pre_include(const char *fname) +{ + Token *inc, *space, *name; + Line *l; + + name = new_Token(NULL, TOK_INTERNAL_STRING, fname, 0); + space = new_Token(name, TOK_WHITESPACE, NULL, 0); + inc = new_Token(space, TOK_PREPROC_ID, "%include", 0); + + l = nasm_malloc(sizeof(Line)); + l->next = predef; + l->first = inc; + l->finishes = FALSE; + predef = l; +} + +void +pp_pre_define(char *definition) +{ + Token *def, *space; + Line *l; + char *equals; + + equals = strchr(definition, '='); + space = new_Token(NULL, TOK_WHITESPACE, NULL, 0); + def = new_Token(space, TOK_PREPROC_ID, "%define", 0); + if (equals) + *equals = ' '; + space->next = tokenise(definition); + if (equals) + *equals = '='; + + l = nasm_malloc(sizeof(Line)); + l->next = predef; + l->first = def; + l->finishes = FALSE; + predef = l; +} + +void +pp_pre_undefine(char *definition) +{ + Token *def, *space; + Line *l; + + space = new_Token(NULL, TOK_WHITESPACE, NULL, 0); + def = new_Token(space, TOK_PREPROC_ID, "%undef", 0); + space->next = tokenise(definition); + + l = nasm_malloc(sizeof(Line)); + l->next = predef; + l->first = def; + l->finishes = FALSE; + predef = l; +} + +void +pp_builtin_define(char *definition) +{ + Token *def, *space; + Line *l; + char *equals; + + equals = strchr(definition, '='); + space = new_Token(NULL, TOK_WHITESPACE, NULL, 0); + def = new_Token(space, TOK_PREPROC_ID, "%define", 0); + if (equals) + *equals = ' '; + space->next = tokenise(definition); + if (equals) + *equals = '='; + + l = nasm_malloc(sizeof(Line)); + l->next = builtindef; + l->first = def; + l->finishes = FALSE; + builtindef = l; +} + +void +pp_extra_stdmac(const char **macros) +{ + const char **lp; + + for (lp=macros; *lp; lp++) + { + char *macro; + Token *t; + Line *l; + + macro = nasm_strdup(*lp); + t = tokenise(macro); + nasm_free(macro); + + l = nasm_malloc(sizeof(Line)); + l->next = stddef; + l->first = t; + l->finishes = FALSE; + stddef = l; + } +} + +static void +make_tok_num(Token * tok, yasm_intnum *val) +{ + tok->text = yasm_intnum_get_str(val); + tok->type = TOK_NUMBER; + yasm_intnum_destroy(val); +} + +Preproc nasmpp = { + pp_reset, + pp_getline, + pp_cleanup +}; diff --git a/contrib/tools/yasm/modules/preprocs/nasm/nasm-pp.h b/contrib/tools/yasm/modules/preprocs/nasm/nasm-pp.h new file mode 100644 index 0000000000..a1990206f2 --- /dev/null +++ b/contrib/tools/yasm/modules/preprocs/nasm/nasm-pp.h @@ -0,0 +1,22 @@ +/* preproc.h header file for preproc.c + * + * The Netwide Assembler is copyright (C) 1996 Simon Tatham and + * Julian Hall. All rights reserved. The software is + * redistributable under the licence given in the file "Licence" + * distributed in the NASM archive. + */ + +#ifndef YASM_NASM_PREPROC_H +#define YASM_NASM_PREPROC_H + +void pp_pre_include (const char *); +void pp_pre_define (char *); +void pp_pre_undefine (char *); +void pp_builtin_define (char *); +void pp_extra_stdmac (const char **); + +extern Preproc nasmpp; + +void nasm_preproc_add_dep(char *); + +#endif diff --git a/contrib/tools/yasm/modules/preprocs/nasm/nasm-preproc.c b/contrib/tools/yasm/modules/preprocs/nasm/nasm-preproc.c new file mode 100644 index 0000000000..566dd8004b --- /dev/null +++ b/contrib/tools/yasm/modules/preprocs/nasm/nasm-preproc.c @@ -0,0 +1,342 @@ +/* + * Imported NASM preprocessor - glue code + * + * 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 "nasm.h" +#include "nasmlib.h" +#include "nasm-pp.h" +#include "nasm-eval.h" + +typedef struct yasm_preproc_nasm { + yasm_preproc_base preproc; /* Base structure */ + + FILE *in; + char *line; + char *file_name; + long prior_linnum; + int lineinc; +} yasm_preproc_nasm; +yasm_symtab *nasm_symtab; +static yasm_linemap *cur_lm; +static yasm_errwarns *cur_errwarns; +int tasm_compatible_mode = 0; +int tasm_locals; +const char *tasm_segment; + +#include "nasm-version.c" + +typedef struct preproc_dep { + STAILQ_ENTRY(preproc_dep) link; + char *name; +} preproc_dep; + +static STAILQ_HEAD(preproc_dep_head, preproc_dep) *preproc_deps; +static int done_dep_preproc; + +yasm_preproc_module yasm_nasm_LTX_preproc; + +static void +nil_listgen_init(char *p, efunc e) +{ +} + +static void +nil_listgen_cleanup(void) +{ +} + +static void +nil_listgen_output(long v, const void *d, unsigned long v2) +{ +} + +static void +nil_listgen_line(int v, char *p) +{ +} + +static void +nil_listgen_uplevel(int v) +{ +} + +static void +nil_listgen_downlevel(int v) +{ +} + +static ListGen nil_list = { + nil_listgen_init, + nil_listgen_cleanup, + nil_listgen_output, + nil_listgen_line, + nil_listgen_uplevel, + nil_listgen_downlevel +}; + + +static void +nasm_efunc(int severity, const char *fmt, ...) +{ + va_list va; + + va_start(va, fmt); + switch (severity & ERR_MASK) { + case ERR_WARNING: + yasm_warn_set_va(YASM_WARN_PREPROC, fmt, va); + break; + case ERR_NONFATAL: + yasm_error_set_va(YASM_ERROR_GENERAL, fmt, va); + break; + case ERR_FATAL: + yasm_fatal(fmt, va); + /*@notreached@*/ + break; + case ERR_PANIC: + yasm_internal_error(fmt); /* FIXME */ + break; + case ERR_DEBUG: + break; + } + va_end(va); + yasm_errwarn_propagate(cur_errwarns, + yasm_linemap_poke(cur_lm, nasm_src_get_fname(), + (unsigned long)nasm_src_get_linnum())); +} + +static yasm_preproc * +nasm_preproc_create(const char *in_filename, yasm_symtab *symtab, + yasm_linemap *lm, yasm_errwarns *errwarns) +{ + FILE *f; + yasm_preproc_nasm *preproc_nasm = yasm_xmalloc(sizeof(yasm_preproc_nasm)); + + preproc_nasm->preproc.module = &yasm_nasm_LTX_preproc; + + if (strcmp(in_filename, "-") != 0) { + f = fopen(in_filename, "r"); + if (!f) + yasm__fatal_missing_input_file( N_("Could not open input file"), in_filename ); + } + else + f = stdin; + + preproc_nasm->in = f; + nasm_symtab = symtab; + cur_lm = lm; + cur_errwarns = errwarns; + preproc_deps = NULL; + done_dep_preproc = 0; + preproc_nasm->line = NULL; + preproc_nasm->file_name = NULL; + preproc_nasm->prior_linnum = 0; + preproc_nasm->lineinc = 0; + nasmpp.reset(f, in_filename, 2, nasm_efunc, nasm_evaluate, &nil_list); + + pp_extra_stdmac(nasm_version_mac); + + return (yasm_preproc *)preproc_nasm; +} + +static void +nasm_preproc_destroy(yasm_preproc *preproc) +{ + yasm_preproc_nasm *preproc_nasm = (yasm_preproc_nasm *)preproc; + nasmpp.cleanup(0); + if (preproc_nasm->line) + yasm_xfree(preproc_nasm->line); + if (preproc_nasm->file_name) + yasm_xfree(preproc_nasm->file_name); + yasm_xfree(preproc); + if (preproc_deps) + yasm_xfree(preproc_deps); +} + +static char * +nasm_preproc_get_line(yasm_preproc *preproc) +{ + yasm_preproc_nasm *preproc_nasm = (yasm_preproc_nasm *)preproc; + long linnum; + int altline; + char *line; + + if (preproc_nasm->line) { + char *retval = preproc_nasm->line; + preproc_nasm->line = NULL; + return retval; + } + + line = nasmpp.getline(); + if (!line) + { + nasmpp.cleanup(1); + return NULL; /* EOF */ + } + + linnum = preproc_nasm->prior_linnum += preproc_nasm->lineinc; + altline = nasm_src_get(&linnum, &preproc_nasm->file_name); + if (altline != 0) { + preproc_nasm->lineinc = + (altline != -1 || preproc_nasm->lineinc != 1); + preproc_nasm->line = line; + line = yasm_xmalloc(40+strlen(preproc_nasm->file_name)); + sprintf(line, "%%line %ld+%d %s", linnum, + preproc_nasm->lineinc, preproc_nasm->file_name); + preproc_nasm->prior_linnum = linnum; + } + + return line; +} + +void +nasm_preproc_add_dep(char *name) +{ + preproc_dep *dep; + + /* If not processing dependencies, simply return */ + if (!preproc_deps) + return; + + /* Save in preproc_deps */ + dep = yasm_xmalloc(sizeof(preproc_dep)); + dep->name = yasm__xstrdup(name); + STAILQ_INSERT_TAIL(preproc_deps, dep, link); +} + +static size_t +nasm_preproc_get_included_file(yasm_preproc *preproc, /*@out@*/ char *buf, + size_t max_size) +{ + if (!preproc_deps) { + preproc_deps = yasm_xmalloc(sizeof(struct preproc_dep_head)); + STAILQ_INIT(preproc_deps); + } + + for (;;) { + char *line; + + /* Pull first dep out of preproc_deps and return it if there is one */ + if (!STAILQ_EMPTY(preproc_deps)) { + char *name; + preproc_dep *dep = STAILQ_FIRST(preproc_deps); + STAILQ_REMOVE_HEAD(preproc_deps, link); + name = dep->name; + yasm_xfree(dep); + strncpy(buf, name, max_size); + buf[max_size-1] = '\0'; + yasm_xfree(name); + return strlen(buf); + } + + /* No more preprocessing to do */ + if (done_dep_preproc) { + return 0; + } + + /* Preprocess some more, throwing away the result */ + line = nasmpp.getline(); + if (line) + yasm_xfree(line); + else + done_dep_preproc = 1; + } +} + +static void +nasm_preproc_add_include_file(yasm_preproc *preproc, const char *filename) +{ + pp_pre_include(filename); +} + +static void +nasm_preproc_predefine_macro(yasm_preproc *preproc, const char *macronameval) +{ + char *mnv = yasm__xstrdup(macronameval); + pp_pre_define(mnv); + yasm_xfree(mnv); +} + +static void +nasm_preproc_undefine_macro(yasm_preproc *preproc, const char *macroname) +{ + char *mn = yasm__xstrdup(macroname); + pp_pre_undefine(mn); + yasm_xfree(mn); +} + +static void +nasm_preproc_define_builtin(yasm_preproc *preproc, const char *macronameval) +{ + char *mnv = yasm__xstrdup(macronameval); + pp_builtin_define(mnv); + yasm_xfree(mnv); +} + +static void +nasm_preproc_add_standard(yasm_preproc *preproc, const char **macros) +{ + pp_extra_stdmac(macros); +} + +/* Define preproc structure -- see preproc.h for details */ +yasm_preproc_module yasm_nasm_LTX_preproc = { + "Real NASM Preprocessor", + "nasm", + nasm_preproc_create, + nasm_preproc_destroy, + nasm_preproc_get_line, + nasm_preproc_get_included_file, + nasm_preproc_add_include_file, + nasm_preproc_predefine_macro, + nasm_preproc_undefine_macro, + nasm_preproc_define_builtin, + nasm_preproc_add_standard +}; + +static yasm_preproc * +tasm_preproc_create(const char *in_filename, yasm_symtab *symtab, + yasm_linemap *lm, yasm_errwarns *errwarns) +{ + tasm_compatible_mode = 1; + return nasm_preproc_create(in_filename, symtab, lm, errwarns); +} + +yasm_preproc_module yasm_tasm_LTX_preproc = { + "Real TASM Preprocessor", + "tasm", + tasm_preproc_create, + nasm_preproc_destroy, + nasm_preproc_get_line, + nasm_preproc_get_included_file, + nasm_preproc_add_include_file, + nasm_preproc_predefine_macro, + nasm_preproc_undefine_macro, + nasm_preproc_define_builtin, + nasm_preproc_add_standard +}; diff --git a/contrib/tools/yasm/modules/preprocs/nasm/nasm.h b/contrib/tools/yasm/modules/preprocs/nasm/nasm.h new file mode 100644 index 0000000000..b3382ffe92 --- /dev/null +++ b/contrib/tools/yasm/modules/preprocs/nasm/nasm.h @@ -0,0 +1,283 @@ +/* nasm.h main header file for the Netwide Assembler: inter-module interface + * + * The Netwide Assembler is copyright (C) 1996 Simon Tatham and + * Julian Hall. All rights reserved. The software is + * redistributable under the licence given in the file "Licence" + * distributed in the NASM archive. + * + * initial version: 27/iii/95 by Simon Tatham + */ +#ifndef YASM_NASM_H +#define YASM_NASM_H + +#ifndef NULL +#define NULL 0 +#endif + +#ifndef FALSE +#define FALSE 0 /* comes in handy */ +#endif +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FILENAME_MAX +#define FILENAME_MAX 256 +#endif + +#ifndef PREFIX_MAX +#define PREFIX_MAX 10 +#endif + +#ifndef POSTFIX_MAX +#define POSTFIX_MAX 10 +#endif + +#define IDLEN_MAX 4096 + +/* + * ------------------------- + * Error reporting functions + * ------------------------- + */ + +/* + * An error reporting function should look like this. + */ +typedef void (*efunc) (int severity, const char *fmt, ...); + +/* + * These are the error severity codes which get passed as the first + * argument to an efunc. + */ + +#define ERR_DEBUG 0x00000008 /* put out debugging message */ +#define ERR_WARNING 0x00000000 /* warn only: no further action */ +#define ERR_NONFATAL 0x00000001 /* terminate assembly after phase */ +#define ERR_FATAL 0x00000002 /* instantly fatal: exit with error */ +#define ERR_PANIC 0x00000003 /* internal error: panic instantly + * and dump core for reference */ +#define ERR_MASK 0x0000000F /* mask off the above codes */ +#define ERR_NOFILE 0x00000010 /* don't give source file name/line */ +#define ERR_USAGE 0x00000020 /* print a usage message */ +#define ERR_PASS1 0x00000040 /* only print this error on pass one */ + +/* + * These codes define specific types of suppressible warning. + */ + +#define ERR_WARN_MASK 0x0000FF00 /* the mask for this feature */ +#define ERR_WARN_SHR 8 /* how far to shift right */ + +#define ERR_WARN_MNP 0x00000100 /* macro-num-parameters warning */ +#define ERR_WARN_MSR 0x00000200 /* macro self-reference */ +#define ERR_WARN_OL 0x00000300 /* orphan label (no colon, and + * alone on line) */ +#define ERR_WARN_NOV 0x00000400 /* numeric overflow */ +#define ERR_WARN_GNUELF 0x00000500 /* using GNU ELF extensions */ +#define ERR_WARN_MAX 5 /* the highest numbered one */ + +/* + * ----------------------- + * Other function typedefs + * ----------------------- + */ + +/* + * List-file generators should look like this: + */ +typedef struct { + /* + * Called to initialise the listing file generator. Before this + * is called, the other routines will silently do nothing when + * called. The `char *' parameter is the file name to write the + * listing to. + */ + void (*init) (char *, efunc); + + /* + * Called to clear stuff up and close the listing file. + */ + void (*cleanup) (void); + + /* + * Called to output binary data. Parameters are: the offset; + * the data; the data type. Data types are similar to the + * output-format interface, only OUT_ADDRESS will _always_ be + * displayed as if it's relocatable, so ensure that any non- + * relocatable address has been converted to OUT_RAWDATA by + * then. Note that OUT_RAWDATA+0 is a valid data type, and is a + * dummy call used to give the listing generator an offset to + * work with when doing things like uplevel(LIST_TIMES) or + * uplevel(LIST_INCBIN). + */ + void (*output) (long, const void *, unsigned long); + + /* + * Called to send a text line to the listing generator. The + * `int' parameter is LIST_READ or LIST_MACRO depending on + * whether the line came directly from an input file or is the + * result of a multi-line macro expansion. + */ + void (*line) (int, char *); + + /* + * Called to change one of the various levelled mechanisms in + * the listing generator. LIST_INCLUDE and LIST_MACRO can be + * used to increase the nesting level of include files and + * macro expansions; LIST_TIMES and LIST_INCBIN switch on the + * two binary-output-suppression mechanisms for large-scale + * pseudo-instructions. + * + * LIST_MACRO_NOLIST is synonymous with LIST_MACRO except that + * it indicates the beginning of the expansion of a `nolist' + * macro, so anything under that level won't be expanded unless + * it includes another file. + */ + void (*uplevel) (int); + + /* + * Reverse the effects of uplevel. + */ + void (*downlevel) (int); +} ListGen; + +/* + * The expression evaluator must be passed a scanner function; a + * standard scanner is provided as part of nasmlib.c. The + * preprocessor will use a different one. Scanners, and the + * token-value structures they return, look like this. + * + * The return value from the scanner is always a copy of the + * `t_type' field in the structure. + */ +struct tokenval { + int t_type; + yasm_intnum *t_integer, *t_inttwo; + char *t_charptr; +}; +typedef int (*scanner) (void *private_data, struct tokenval *tv); + +/* + * Token types returned by the scanner, in addition to ordinary + * ASCII character values, and zero for end-of-string. + */ +enum { /* token types, other than chars */ + TOKEN_INVALID = -1, /* a placeholder value */ + TOKEN_EOS = 0, /* end of string */ + TOKEN_EQ = '=', TOKEN_GT = '>', TOKEN_LT = '<', /* aliases */ + TOKEN_ID = 256, TOKEN_NUM, TOKEN_REG, TOKEN_INSN, /* major token types */ + TOKEN_ERRNUM, /* numeric constant with error in */ + TOKEN_HERE, TOKEN_BASE, /* $ and $$ */ + TOKEN_SPECIAL, /* BYTE, WORD, DWORD, FAR, NEAR, etc */ + TOKEN_PREFIX, /* A32, O16, LOCK, REPNZ, TIMES, etc */ + TOKEN_SHL, TOKEN_SHR, /* << and >> */ + TOKEN_SDIV, TOKEN_SMOD, /* // and %% */ + TOKEN_GE, TOKEN_LE, TOKEN_NE, /* >=, <= and <> (!= is same as <>) */ + TOKEN_DBL_AND, TOKEN_DBL_OR, TOKEN_DBL_XOR, /* &&, || and ^^ */ + TOKEN_SEG, TOKEN_WRT, /* SEG and WRT */ + TOKEN_FLOAT /* floating-point constant */ +}; + +/* + * The actual expression evaluator function looks like this. When + * called, it expects the first token of its expression to already + * be in `*tv'; if it is not, set tv->t_type to TOKEN_INVALID and + * it will start by calling the scanner. + * + * `critical' is non-zero if the expression may not contain forward + * references. The evaluator will report its own error if this + * occurs; if `critical' is 1, the error will be "symbol not + * defined before use", whereas if `critical' is 2, the error will + * be "symbol undefined". + * + * If `critical' has bit 8 set (in addition to its main value: 0x101 + * and 0x102 correspond to 1 and 2) then an extended expression + * syntax is recognised, in which relational operators such as =, < + * and >= are accepted, as well as low-precedence logical operators + * &&, ^^ and ||. + */ +#define CRITICAL 0x100 +typedef yasm_expr *(*evalfunc) (scanner sc, void *scprivate, struct tokenval *tv, + int critical, efunc error); + +/* + * Preprocessors ought to look like this: + */ +typedef struct { + /* + * Called at the start of a pass; given a file name, the number + * of the pass, an error reporting function, an evaluator + * function, and a listing generator to talk to. + */ + void (*reset) (FILE *, const char *, int, efunc, evalfunc, ListGen *); + + /* + * Called to fetch a line of preprocessed source. The line + * returned has been malloc'ed, and so should be freed after + * use. + */ + char *(*getline) (void); + + /* + * Called at the end of a pass. + */ + void (*cleanup) (int); +} Preproc; + +/* + * ---------------------------------------------------------------- + * Some lexical properties of the NASM source language, included + * here because they are shared between the parser and preprocessor + * ---------------------------------------------------------------- + */ + +/* + * isidstart matches any character that may start an identifier, and isidchar + * matches any character that may appear at places other than the start of an + * identifier. E.g. a period may only appear at the start of an identifier + * (for local labels), whereas a number may appear anywhere *but* at the + * start. + */ + +#define isidstart(c) ( isalpha(c) || (c)=='_' || (c)=='.' || (c)=='?' \ + || (c)=='@' ) +#define isidchar(c) ( isidstart(c) || isdigit(c) || (c)=='$' || (c)=='#' \ + || (c)=='~' ) + +/* Ditto for numeric constants. */ + +#define isnumstart(c) ( isdigit(c) || (c)=='$' ) +#define isnumchar(c) ( isalnum(c) ) + +/* This returns the numeric value of a given 'digit'. */ + +#define numvalue(c) ((c)>='a' ? (c)-'a'+10 : (c)>='A' ? (c)-'A'+10 : (c)-'0') + +/* + * Data-type flags that get passed to listing-file routines. + */ +enum { + LIST_READ, LIST_MACRO, LIST_MACRO_NOLIST, LIST_INCLUDE, + LIST_INCBIN, LIST_TIMES +}; + +/* + * ----- + * Other + * ----- + */ + +/* + * This is a useful #define which I keep meaning to use more often: + * the number of elements of a statically defined array. + */ + +#define elements(x) ( sizeof(x) / sizeof(*(x)) ) + +extern int tasm_compatible_mode; +extern int tasm_locals; +extern const char *tasm_segment; +const char *tasm_get_segment_register(const char *segment); + +#endif diff --git a/contrib/tools/yasm/modules/preprocs/nasm/nasmlib.c b/contrib/tools/yasm/modules/preprocs/nasm/nasmlib.c new file mode 100644 index 0000000000..2ced911780 --- /dev/null +++ b/contrib/tools/yasm/modules/preprocs/nasm/nasmlib.c @@ -0,0 +1,201 @@ +/* nasmlib.c library routines for the Netwide Assembler + * + * The Netwide Assembler is copyright (C) 1996 Simon Tatham and + * Julian Hall. All rights reserved. The software is + * redistributable under the licence given in the file "Licence" + * distributed in the NASM archive. + */ +#include <util.h> +#include <libyasm/coretype.h> +#include <libyasm/intnum.h> +#include <ctype.h> + +#include "nasm.h" +#include "nasmlib.h" +/*#include "insns.h"*/ /* For MAX_KEYWORD */ + +#define lib_isnumchar(c) ( isalnum(c) || (c) == '$') +#define numvalue(c) ((c)>='a' ? (c)-'a'+10 : (c)>='A' ? (c)-'A'+10 : (c)-'0') + +yasm_intnum *nasm_readnum (char *str, int *error) +{ + char *r = str, *q, *p; + long radix; + yasm_intnum *intn; + char save; + int digit; + int sign = 0; + + *error = FALSE; + + while (isspace(*r)) r++; /* find start of number */ + + /* + * If the number came from make_tok_num (as a result of an %assign), it + * might have a '-' built into it (rather than in a preceeding token). + */ + if (*r == '-') + { + r++; + sign = 1; + } + + q = r; + + while (lib_isnumchar(*q)) q++; /* find end of number */ + + /* + * If it begins 0x, 0X or $, or ends in H, it's in hex. if it + * ends in Q, it's octal. if it ends in B, it's binary. + * Otherwise, it's ordinary decimal. + */ + if (*r=='0' && (r[1]=='x' || r[1]=='X')) + radix = 16, r += 2; + else if (*r=='$') + radix = 16, r++; + else if (q[-1]=='H' || q[-1]=='h') + radix = 16 , q--; + else if (q[-1]=='Q' || q[-1]=='q' || q[-1]=='O' || q[-1]=='o') + radix = 8 , q--; + else if (q[-1]=='B' || q[-1]=='b') + radix = 2 , q--; + else + radix = 10; + + /* + * If this number has been found for us by something other than + * the ordinary scanners, then it might be malformed by having + * nothing between the prefix and the suffix. Check this case + * now. + */ + if (r >= q) { + *error = TRUE; + return yasm_intnum_create_uint(0); + } + + /* Check for valid number of that radix */ + p = r; + while (*p && p < q) { + if (*p<'0' || (*p>'9' && *p<'A') || (digit = numvalue(*p)) >= radix) + { + *error = TRUE; + return yasm_intnum_create_uint(0); + } + p++; + } + + /* Use intnum to actually do the conversion */ + save = *q; + *q = '\0'; + switch (radix) { + case 2: + intn = yasm_intnum_create_bin(r); + break; + case 8: + intn = yasm_intnum_create_oct(r); + break; + case 10: + intn = yasm_intnum_create_dec(r); + break; + case 16: + intn = yasm_intnum_create_hex(r); + break; + default: + *error = TRUE; + intn = yasm_intnum_create_uint(0); + break; + } + *q = save; + + if (sign) + yasm_intnum_calc(intn, YASM_EXPR_NEG, NULL); + return intn; +} + +yasm_intnum *nasm_readstrnum (char *str, size_t length, int *warn) +{ + char save; + yasm_intnum *intn; + + *warn = FALSE; + + save = str[length]; + str[length] = '\0'; + intn = yasm_intnum_create_charconst_nasm(str); + str[length] = save; + + return intn; +} + +static char *file_name = NULL; +static long line_number = 0; + +char *nasm_src_set_fname(char *newname) +{ + char *oldname = file_name; + file_name = newname; + return oldname; +} + +char *nasm_src_get_fname(void) +{ + return file_name; +} + +long nasm_src_set_linnum(long newline) +{ + long oldline = line_number; + line_number = newline; + return oldline; +} + +long nasm_src_get_linnum(void) +{ + return line_number; +} + +int nasm_src_get(long *xline, char **xname) +{ + if (!file_name || !*xname || strcmp(*xname, file_name)) + { + nasm_free(*xname); + *xname = file_name ? nasm_strdup(file_name) : NULL; + *xline = line_number; + return -2; + } + if (*xline != line_number) + { + long tmp = line_number - *xline; + *xline = line_number; + return tmp; + } + return 0; +} + +void nasm_quote(char **str) +{ + size_t ln=strlen(*str); + char q=(*str)[0]; + char *p; + if (ln>1 && (*str)[ln-1]==q && (q=='"' || q=='\'')) + return; + q = '"'; + if (strchr(*str,q)) + q = '\''; + p = nasm_malloc(ln+3); + strcpy(p+1, *str); + nasm_free(*str); + p[ln+1] = p[0] = q; + p[ln+2] = 0; + *str = p; +} + +char *nasm_strcat(const char *one, const char *two) +{ + char *rslt; + size_t l1=strlen(one); + rslt = nasm_malloc(l1+strlen(two)+1); + strcpy(rslt, one); + strcpy(rslt+l1, two); + return rslt; +} diff --git a/contrib/tools/yasm/modules/preprocs/nasm/nasmlib.h b/contrib/tools/yasm/modules/preprocs/nasm/nasmlib.h new file mode 100644 index 0000000000..c26c0668b5 --- /dev/null +++ b/contrib/tools/yasm/modules/preprocs/nasm/nasmlib.h @@ -0,0 +1,60 @@ +/* nasmlib.h header file for nasmlib.c + * + * The Netwide Assembler is copyright (C) 1996 Simon Tatham and + * Julian Hall. All rights reserved. The software is + * redistributable under the licence given in the file "Licence" + * distributed in the NASM archive. + */ + +#ifndef YASM_NASMLIB_H +#define YASM_NASMLIB_H + +/* + * Wrappers around malloc, realloc and free. nasm_malloc will + * fatal-error and die rather than return NULL; nasm_realloc will + * do likewise, and will also guarantee to work right on being + * passed a NULL pointer; nasm_free will do nothing if it is passed + * a NULL pointer. + */ +#define nasm_malloc yasm_xmalloc +#define nasm_realloc yasm_xrealloc +#ifdef WITH_DMALLOC +#define nasm_free(p) do { if (p) yasm_xfree(p); } while(0) +#else +#define nasm_free(p) yasm_xfree(p) +#endif +#define nasm_strdup yasm__xstrdup +#define nasm_strndup yasm__xstrndup +#define nasm_stricmp yasm__strcasecmp +#define nasm_strnicmp yasm__strncasecmp + +/* + * Convert a string into a number, using NASM number rules. Sets + * `*error' to TRUE if an error occurs, and FALSE otherwise. + */ +yasm_intnum *nasm_readnum(char *str, int *error); + +/* + * Convert a character constant into a number. Sets + * `*warn' to TRUE if an overflow occurs, and FALSE otherwise. + * str points to and length covers the middle of the string, + * without the quotes. + */ +yasm_intnum *nasm_readstrnum(char *str, size_t length, int *warn); + +char *nasm_src_set_fname(char *newname); +char *nasm_src_get_fname(void); +long nasm_src_set_linnum(long newline); +long nasm_src_get_linnum(void); +/* + * src_get may be used if you simply want to know the source file and line. + * It is also used if you maintain private status about the source location + * It return 0 if the information was the same as the last time you + * checked, -1 if the name changed and (new-old) if just the line changed. + */ +int nasm_src_get(long *xline, char **xname); + +void nasm_quote(char **str); +char *nasm_strcat(const char *one, const char *two); + +#endif diff --git a/contrib/tools/yasm/modules/preprocs/raw/raw-preproc.c b/contrib/tools/yasm/modules/preprocs/raw/raw-preproc.c new file mode 100644 index 0000000000..9745b242fe --- /dev/null +++ b/contrib/tools/yasm/modules/preprocs/raw/raw-preproc.c @@ -0,0 +1,169 @@ +/* + * Raw preprocessor (preforms NO preprocessing) + * + * 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> + + +#define BSIZE 512 + +typedef struct yasm_preproc_raw { + yasm_preproc_base preproc; /* base structure */ + + FILE *in; + yasm_linemap *cur_lm; + yasm_errwarns *errwarns; +} yasm_preproc_raw; + +yasm_preproc_module yasm_raw_LTX_preproc; + +static yasm_preproc * +raw_preproc_create(const char *in_filename, yasm_symtab *symtab, + yasm_linemap *lm, yasm_errwarns *errwarns) +{ + FILE *f; + yasm_preproc_raw *preproc_raw = yasm_xmalloc(sizeof(yasm_preproc_raw)); + + if (strcmp(in_filename, "-") != 0) { + f = fopen(in_filename, "r"); + if (!f) + yasm__fatal_missing_input_file( N_("Could not open input file"), in_filename ); + } + else + f = stdin; + + preproc_raw->preproc.module = &yasm_raw_LTX_preproc; + preproc_raw->in = f; + preproc_raw->cur_lm = lm; + preproc_raw->errwarns = errwarns; + + return (yasm_preproc *)preproc_raw; +} + +static void +raw_preproc_destroy(yasm_preproc *preproc) +{ + yasm_xfree(preproc); +} + +static char * +raw_preproc_get_line(yasm_preproc *preproc) +{ + yasm_preproc_raw *preproc_raw = (yasm_preproc_raw *)preproc; + int bufsize = BSIZE; + char *buf = yasm_xmalloc((size_t)bufsize); + char *p; + + /* Loop to ensure entire line is read (don't want to limit line length). */ + p = buf; + for (;;) { + if (!fgets(p, bufsize-(p-buf), preproc_raw->in)) { + if (ferror(preproc_raw->in)) { + yasm_error_set(YASM_ERROR_IO, + N_("error when reading from file")); + yasm_errwarn_propagate(preproc_raw->errwarns, + yasm_linemap_get_current(preproc_raw->cur_lm)); + } + break; + } + p += strlen(p); + if (p > buf && p[-1] == '\n') + break; + if ((p-buf)+1 >= bufsize) { + /* Increase size of buffer */ + char *oldbuf = buf; + bufsize *= 2; + buf = yasm_xrealloc(buf, (size_t)bufsize); + p = buf + (p-oldbuf); + } + } + + if (p == buf) { + /* No data; must be at EOF */ + yasm_xfree(buf); + return NULL; + } + + /* Strip the line ending */ + buf[strcspn(buf, "\r\n")] = '\0'; + + return buf; +} + +static size_t +raw_preproc_get_included_file(yasm_preproc *preproc, char *buf, + size_t max_size) +{ + /* no included files */ + return 0; +} + +static void +raw_preproc_add_include_file(yasm_preproc *preproc, const char *filename) +{ + /* no pre-include files */ +} + +static void +raw_preproc_predefine_macro(yasm_preproc *preproc, const char *macronameval) +{ + /* no pre-defining macros */ +} + +static void +raw_preproc_undefine_macro(yasm_preproc *preproc, const char *macroname) +{ + /* no undefining macros */ +} + +static void +raw_preproc_define_builtin(yasm_preproc *preproc, const char *macronameval) +{ + /* no builtin defines */ +} + +static void +raw_preproc_add_standard(yasm_preproc *preproc, const char **macros) +{ + /* no standard macros */ +} + + +/* Define preproc structure -- see preproc.h for details */ +yasm_preproc_module yasm_raw_LTX_preproc = { + "Disable preprocessing", + "raw", + raw_preproc_create, + raw_preproc_destroy, + raw_preproc_get_line, + raw_preproc_get_included_file, + raw_preproc_add_include_file, + raw_preproc_predefine_macro, + raw_preproc_undefine_macro, + raw_preproc_define_builtin, + raw_preproc_add_standard +}; diff --git a/contrib/tools/yasm/modules/win64-gas.c b/contrib/tools/yasm/modules/win64-gas.c new file mode 100644 index 0000000000..1ad8be329c --- /dev/null +++ b/contrib/tools/yasm/modules/win64-gas.c @@ -0,0 +1,65 @@ +/* This file auto-generated from standard.mac by genmacro.c - don't edit it */ + +#include <stddef.h> + +static const char *win64_gas_stdmac[] = { + "%imacro export 1+.nolist", + ".export %1", + "%endmacro", + "%imacro proc_frame 1+.nolist", + "%1:", + ".proc_frame %1", + "%endmacro", + "%imacro endproc_frame 0.nolist", + ".endproc_frame", + "%endmacro", + "%imacro push_reg 1", + "pushq %1", + ".pushreg %1", + "%endmacro", + "%imacro rex_push_reg 1", + ".byte 0x48", + "pushq %1", + ".pushreg %1", + "%endmacro", + "%imacro push_eflags 0", + "pushfq", + ".allocstack 8", + "%endmacro", + "%imacro rex_push_eflags 0", + ".byte 0x48", + "pushfq", + ".allocstack 8", + "%endmacro", + "%imacro alloc_stack 1", + "subq $%1, %rsp", + ".allocstack %1", + "%endmacro", + "%imacro save_reg 2", + "movq %1, %2(%rsp)", + ".savereg %1 %2", + "%endmacro", + "%imacro save_xmm128 2", + "movdqa %1, %2(%rsp)", + ".savexmm128 %1, %2", + "%endmacro", + "%imacro push_frame 0-1.nolist", + ".pushframe %1", + "%endmacro", + "%imacro set_frame 1-2", + "%if %0==1", + "movq %rsp, %1", + "%else", + "leaq %2(%rsp), %1", + "%endif", + ".setframe %1, %2", + "%endmacro", + "%imacro end_prolog 0.nolist", + ".endprolog", + "%endmacro", + "%imacro end_prologue 0.nolist", + ".endprolog", + "%endmacro", + NULL +}; + diff --git a/contrib/tools/yasm/modules/win64-nasm.c b/contrib/tools/yasm/modules/win64-nasm.c new file mode 100644 index 0000000000..95152c3893 --- /dev/null +++ b/contrib/tools/yasm/modules/win64-nasm.c @@ -0,0 +1,65 @@ +/* This file auto-generated from standard.mac by genmacro.c - don't edit it */ + +#include <stddef.h> + +static const char *win64_nasm_stdmac[] = { + "%imacro export 1+.nolist", + "[export %1]", + "%endmacro", + "%imacro proc_frame 1+.nolist", + "%1:", + "[proc_frame %1]", + "%endmacro", + "%imacro endproc_frame 0.nolist", + "[endproc_frame]", + "%endmacro", + "%imacro push_reg 1", + "push %1", + "[pushreg %1]", + "%endmacro", + "%imacro rex_push_reg 1", + "db 0x48", + "push %1", + "[pushreg %1]", + "%endmacro", + "%imacro push_eflags 0", + "pushfq", + "[allocstack 8]", + "%endmacro", + "%imacro rex_push_eflags 0", + "db 0x48", + "pushfq", + "[allocstack 8]", + "%endmacro", + "%imacro alloc_stack 1", + "sub rsp, %1", + "[allocstack %1]", + "%endmacro", + "%imacro save_reg 2", + "mov [rsp+%2], %1", + "[savereg %1 %2]", + "%endmacro", + "%imacro save_xmm128 2", + "movdqa [rsp+%2], %1", + "[savexmm128 %1 %2]", + "%endmacro", + "%imacro push_frame 0-1.nolist", + "[pushframe %1]", + "%endmacro", + "%imacro set_frame 1-2", + "%if %0==1", + "mov %1, rsp", + "%else", + "lea %1, [rsp+%2]", + "%endif", + "[setframe %1 %2]", + "%endmacro", + "%imacro end_prolog 0.nolist", + "[endprolog]", + "%endmacro", + "%imacro end_prologue 0.nolist", + "[endprolog]", + "%endmacro", + NULL +}; + diff --git a/contrib/tools/yasm/modules/x86cpu.c b/contrib/tools/yasm/modules/x86cpu.c new file mode 100644 index 0000000000..f1677a4382 --- /dev/null +++ b/contrib/tools/yasm/modules/x86cpu.c @@ -0,0 +1,481 @@ +/* ANSI-C code produced by genperf */ + +#include <util.h> + +#include <ctype.h> +#include <libyasm.h> +#include <libyasm/phash.h> + +#include "modules/arch/x86/x86arch.h" + +#define PROC_8086 0 +#define PROC_186 1 +#define PROC_286 2 +#define PROC_386 3 +#define PROC_486 4 +#define PROC_586 5 +#define PROC_686 6 +#define PROC_p2 7 +#define PROC_p3 8 +#define PROC_p4 9 +#define PROC_prescott 10 +#define PROC_conroe 11 +#define PROC_penryn 12 +#define PROC_nehalem 13 +#define PROC_westmere 14 +#define PROC_sandybridge 15 +#define PROC_ivybridge 16 +#define PROC_haswell 17 +#define PROC_broadwell 18 +#define PROC_skylake 19 + +static void +x86_cpu_intel(wordptr cpu, yasm_arch_x86 *arch_x86, unsigned int data) +{ + BitVector_Empty(cpu); + + BitVector_Bit_On(cpu, CPU_Priv); + if (data >= PROC_286) + BitVector_Bit_On(cpu, CPU_Prot); + if (data >= PROC_386) + BitVector_Bit_On(cpu, CPU_SMM); + if (data >= PROC_skylake) { + BitVector_Bit_On(cpu, CPU_SHA); + } + if (data >= PROC_broadwell) { + BitVector_Bit_On(cpu, CPU_RDSEED); + BitVector_Bit_On(cpu, CPU_ADX); + BitVector_Bit_On(cpu, CPU_PRFCHW); + } + if (data >= PROC_haswell) { + BitVector_Bit_On(cpu, CPU_FMA); + BitVector_Bit_On(cpu, CPU_AVX2); + BitVector_Bit_On(cpu, CPU_BMI1); + BitVector_Bit_On(cpu, CPU_BMI2); + BitVector_Bit_On(cpu, CPU_INVPCID); + BitVector_Bit_On(cpu, CPU_LZCNT); + BitVector_Bit_On(cpu, CPU_TSX); + BitVector_Bit_On(cpu, CPU_SMAP); + } + if (data >= PROC_ivybridge) { + BitVector_Bit_On(cpu, CPU_F16C); + BitVector_Bit_On(cpu, CPU_FSGSBASE); + BitVector_Bit_On(cpu, CPU_RDRAND); + } + if (data >= PROC_sandybridge) { + BitVector_Bit_On(cpu, CPU_AVX); + BitVector_Bit_On(cpu, CPU_XSAVEOPT); + BitVector_Bit_On(cpu, CPU_EPTVPID); + BitVector_Bit_On(cpu, CPU_SMX); + } + if (data >= PROC_westmere) { + BitVector_Bit_On(cpu, CPU_AES); + BitVector_Bit_On(cpu, CPU_CLMUL); + } + if (data >= PROC_nehalem) { + BitVector_Bit_On(cpu, CPU_SSE42); + BitVector_Bit_On(cpu, CPU_XSAVE); + } + if (data >= PROC_penryn) + BitVector_Bit_On(cpu, CPU_SSE41); + if (data >= PROC_conroe) + BitVector_Bit_On(cpu, CPU_SSSE3); + if (data >= PROC_prescott) + BitVector_Bit_On(cpu, CPU_SSE3); + if (data >= PROC_p4) + BitVector_Bit_On(cpu, CPU_SSE2); + if (data >= PROC_p3) + BitVector_Bit_On(cpu, CPU_SSE); + if (data >= PROC_p2) + BitVector_Bit_On(cpu, CPU_MMX); + if (data >= PROC_486) + BitVector_Bit_On(cpu, CPU_FPU); + if (data >= PROC_prescott) + BitVector_Bit_On(cpu, CPU_EM64T); + + if (data >= PROC_p4) + BitVector_Bit_On(cpu, CPU_P4); + if (data >= PROC_p3) + BitVector_Bit_On(cpu, CPU_P3); + if (data >= PROC_686) + BitVector_Bit_On(cpu, CPU_686); + if (data >= PROC_586) + BitVector_Bit_On(cpu, CPU_586); + if (data >= PROC_486) + BitVector_Bit_On(cpu, CPU_486); + if (data >= PROC_386) + BitVector_Bit_On(cpu, CPU_386); + if (data >= PROC_286) + BitVector_Bit_On(cpu, CPU_286); + if (data >= PROC_186) + BitVector_Bit_On(cpu, CPU_186); + BitVector_Bit_On(cpu, CPU_086); + + /* Use Intel long NOPs if 686 or better */ + if (data >= PROC_686) + arch_x86->nop = X86_NOP_INTEL; + else + arch_x86->nop = X86_NOP_BASIC; +} + +static void +x86_cpu_ia64(wordptr cpu, yasm_arch_x86 *arch_x86, unsigned int data) +{ + BitVector_Empty(cpu); + BitVector_Bit_On(cpu, CPU_Priv); + BitVector_Bit_On(cpu, CPU_Prot); + BitVector_Bit_On(cpu, CPU_SMM); + BitVector_Bit_On(cpu, CPU_SSE2); + BitVector_Bit_On(cpu, CPU_SSE); + BitVector_Bit_On(cpu, CPU_MMX); + BitVector_Bit_On(cpu, CPU_FPU); + BitVector_Bit_On(cpu, CPU_IA64); + BitVector_Bit_On(cpu, CPU_P4); + BitVector_Bit_On(cpu, CPU_P3); + BitVector_Bit_On(cpu, CPU_686); + BitVector_Bit_On(cpu, CPU_586); + BitVector_Bit_On(cpu, CPU_486); + BitVector_Bit_On(cpu, CPU_386); + BitVector_Bit_On(cpu, CPU_286); + BitVector_Bit_On(cpu, CPU_186); + BitVector_Bit_On(cpu, CPU_086); +} + +#define PROC_bulldozer 11 +#define PROC_k10 10 +#define PROC_venice 9 +#define PROC_hammer 8 +#define PROC_k7 7 +#define PROC_k6 6 + +static void +x86_cpu_amd(wordptr cpu, yasm_arch_x86 *arch_x86, unsigned int data) +{ + BitVector_Empty(cpu); + + BitVector_Bit_On(cpu, CPU_Priv); + BitVector_Bit_On(cpu, CPU_Prot); + BitVector_Bit_On(cpu, CPU_SMM); + BitVector_Bit_On(cpu, CPU_3DNow); + if (data >= PROC_bulldozer) { + BitVector_Bit_On(cpu, CPU_XOP); + BitVector_Bit_On(cpu, CPU_FMA4); + } + if (data >= PROC_k10) + BitVector_Bit_On(cpu, CPU_SSE4a); + if (data >= PROC_venice) + BitVector_Bit_On(cpu, CPU_SSE3); + if (data >= PROC_hammer) + BitVector_Bit_On(cpu, CPU_SSE2); + if (data >= PROC_k7) + BitVector_Bit_On(cpu, CPU_SSE); + if (data >= PROC_k6) + BitVector_Bit_On(cpu, CPU_MMX); + BitVector_Bit_On(cpu, CPU_FPU); + + if (data >= PROC_hammer) + BitVector_Bit_On(cpu, CPU_Hammer); + if (data >= PROC_k7) + BitVector_Bit_On(cpu, CPU_Athlon); + if (data >= PROC_k6) + BitVector_Bit_On(cpu, CPU_K6); + BitVector_Bit_On(cpu, CPU_686); + BitVector_Bit_On(cpu, CPU_586); + BitVector_Bit_On(cpu, CPU_486); + BitVector_Bit_On(cpu, CPU_386); + BitVector_Bit_On(cpu, CPU_286); + BitVector_Bit_On(cpu, CPU_186); + BitVector_Bit_On(cpu, CPU_086); + + /* Use AMD long NOPs if k6 or better */ + if (data >= PROC_k6) + arch_x86->nop = X86_NOP_AMD; + else + arch_x86->nop = X86_NOP_BASIC; +} + +static void +x86_cpu_set(wordptr cpu, yasm_arch_x86 *arch_x86, unsigned int data) +{ + BitVector_Bit_On(cpu, data); +} + +static void +x86_cpu_clear(wordptr cpu, yasm_arch_x86 *arch_x86, unsigned int data) +{ + BitVector_Bit_Off(cpu, data); +} + +static void +x86_cpu_set_sse4(wordptr cpu, yasm_arch_x86 *arch_x86, unsigned int data) +{ + BitVector_Bit_On(cpu, CPU_SSE41); + BitVector_Bit_On(cpu, CPU_SSE42); +} + +static void +x86_cpu_clear_sse4(wordptr cpu, yasm_arch_x86 *arch_x86, unsigned int data) +{ + BitVector_Bit_Off(cpu, CPU_SSE41); + BitVector_Bit_Off(cpu, CPU_SSE42); +} + +static void +x86_nop(wordptr cpu, yasm_arch_x86 *arch_x86, unsigned int data) +{ + arch_x86->nop = data; +} + +struct cpu_parse_data { + const char *name; + void (*handler) (wordptr cpu, yasm_arch_x86 *arch_x86, unsigned int data); + unsigned int data; +}; +static const struct cpu_parse_data * +cpu_find(const char *key, size_t len) +{ + static const struct cpu_parse_data pd[179] = { + {"noeptvpid", x86_cpu_clear, CPU_EPTVPID}, + {"amd", x86_cpu_set, CPU_AMD}, + {"sse41", x86_cpu_set, CPU_SSE41}, + {"pentium", x86_cpu_intel, PROC_586}, + {"intelnop", x86_nop, X86_NOP_INTEL}, + {"pclmulqdq", x86_cpu_set, CPU_CLMUL}, + {"sse42", x86_cpu_set, CPU_SSE42}, + {"nobmi2", x86_cpu_clear, CPU_BMI2}, + {"pentium3", x86_cpu_intel, PROC_p3}, + {"broadwell", x86_cpu_intel, PROC_broadwell}, + {"aes", x86_cpu_set, CPU_AES}, + {"eptvpid", x86_cpu_set, CPU_EPTVPID}, + {"f16c", x86_cpu_set, CPU_F16C}, + {"amdnop", x86_nop, X86_NOP_AMD}, + {"pentium-2", x86_cpu_intel, PROC_p2}, + {"nofpu", x86_cpu_clear, CPU_FPU}, + {"bmi2", x86_cpu_set, CPU_BMI2}, + {"katmai", x86_cpu_intel, PROC_p3}, + {"pentiumiii", x86_cpu_intel, PROC_p3}, + {"fpu", x86_cpu_set, CPU_FPU}, + {"noundoc", x86_cpu_clear, CPU_Undoc}, + {"no3dnow", x86_cpu_clear, CPU_3DNow}, + {"i486", x86_cpu_intel, PROC_486}, + {"noundocumented", x86_cpu_clear, CPU_Undoc}, + {"sse", x86_cpu_set, CPU_SSE}, + {"nossse3", x86_cpu_clear, CPU_SSSE3}, + {"noclmul", x86_cpu_clear, CPU_CLMUL}, + {"tsx", x86_cpu_set, CPU_TSX}, + {"nocyrix", x86_cpu_clear, CPU_Cyrix}, + {"nosse", x86_cpu_clear, CPU_SSE}, + {"nofma", x86_cpu_clear, CPU_FMA}, + {"phenom", x86_cpu_amd, PROC_k10}, + {"haswell", x86_cpu_intel, PROC_haswell}, + {"noprot", x86_cpu_clear, CPU_Prot}, + {"padlock", x86_cpu_set, CPU_PadLock}, + {"nopclmulqdq", x86_cpu_clear, CPU_CLMUL}, + {"nofma4", x86_cpu_clear, CPU_FMA4}, + {"nofsgsbase", x86_cpu_clear, CPU_FSGSBASE}, + {"prot", x86_cpu_set, CPU_Prot}, + {"opteron", x86_cpu_amd, PROC_hammer}, + {"nof16c", x86_cpu_clear, CPU_F16C}, + {"i386", x86_cpu_intel, PROC_386}, + {"ssse3", x86_cpu_set, CPU_SSSE3}, + {"protected", x86_cpu_set, CPU_Prot}, + {"bulldozer", x86_cpu_amd, PROC_bulldozer}, + {"lzcnt", x86_cpu_set, CPU_LZCNT}, + {"obs", x86_cpu_set, CPU_Obs}, + {"noprotected", x86_cpu_clear, CPU_Prot}, + {"athlon-64", x86_cpu_amd, PROC_hammer}, + {"undocumented", x86_cpu_set, CPU_Undoc}, + {"i686", x86_cpu_intel, PROC_686}, + {"k8", x86_cpu_amd, PROC_hammer}, + {"k10", x86_cpu_amd, PROC_k10}, + {"noavx2", x86_cpu_clear, CPU_AVX2}, + {"sandybridge", x86_cpu_intel, PROC_sandybridge}, + {"nommx", x86_cpu_clear, CPU_MMX}, + {"priv", x86_cpu_set, CPU_Priv}, + {"sse4.1", x86_cpu_set, CPU_SSE41}, + {"8086", x86_cpu_intel, PROC_8086}, + {"noprivileged", x86_cpu_clear, CPU_Priv}, + {"i586", x86_cpu_intel, PROC_586}, + {"ia-64", x86_cpu_ia64, 0}, + {"nosse2", x86_cpu_clear, CPU_SSE2}, + {"obsolete", x86_cpu_set, CPU_Obs}, + {"186", x86_cpu_intel, PROC_186}, + {"sse4a", x86_cpu_set, CPU_SSE4a}, + {"ia64", x86_cpu_ia64, 0}, + {"core2", x86_cpu_intel, PROC_conroe}, + {"noxsaveopt", x86_cpu_clear, CPU_XSAVEOPT}, + {"sse4.2", x86_cpu_set, CPU_SSE42}, + {"prescott", x86_cpu_intel, PROC_prescott}, + {"avx2", x86_cpu_set, CPU_AVX2}, + {"80186", x86_cpu_intel, PROC_186}, + {"nopriv", x86_cpu_clear, CPU_Priv}, + {"nosse4.1", x86_cpu_clear, CPU_SSE41}, + {"nordseed", x86_cpu_clear, CPU_RDSEED}, + {"pentium2", x86_cpu_intel, PROC_p2}, + {"conroe", x86_cpu_intel, PROC_conroe}, + {"nosse42", x86_cpu_clear, CPU_SSE42}, + {"pentium-ii", x86_cpu_intel, PROC_p2}, + {"svm", x86_cpu_set, CPU_SVM}, + {"386", x86_cpu_intel, PROC_386}, + {"em64t", x86_cpu_set, CPU_EM64T}, + {"p2", x86_cpu_intel, PROC_p2}, + {"athlon64", x86_cpu_amd, PROC_hammer}, + {"3dnow", x86_cpu_set, CPU_3DNow}, + {"nosse4", x86_cpu_clear_sse4, 0}, + {"nosmx", x86_cpu_clear, CPU_SMX}, + {"williamette", x86_cpu_intel, PROC_p4}, + {"family10h", x86_cpu_amd, PROC_k10}, + {"athlon", x86_cpu_amd, PROC_k7}, + {"586", x86_cpu_intel, PROC_586}, + {"686", x86_cpu_intel, PROC_686}, + {"smm", x86_cpu_set, CPU_SMM}, + {"xsave", x86_cpu_set, CPU_XSAVE}, + {"privileged", x86_cpu_set, CPU_Priv}, + {"p6", x86_cpu_intel, PROC_686}, + {"smap", x86_cpu_set, CPU_SMAP}, + {"avx", x86_cpu_set, CPU_AVX}, + {"pentium-4", x86_cpu_intel, PROC_p4}, + {"pentiumii", x86_cpu_intel, PROC_p2}, + {"sha", x86_cpu_set, CPU_SHA}, + {"fma4", x86_cpu_set, CPU_FMA4}, + {"pentium-iii", x86_cpu_intel, PROC_p3}, + {"skylake", x86_cpu_intel, PROC_skylake}, + {"nosse4.2", x86_cpu_clear, CPU_SSE42}, + {"pentium4", x86_cpu_intel, PROC_p4}, + {"noaes", x86_cpu_clear, CPU_AES}, + {"i186", x86_cpu_intel, PROC_186}, + {"rdrand", x86_cpu_set, CPU_RDRAND}, + {"80286", x86_cpu_intel, PROC_286}, + {"pentiumiv", x86_cpu_intel, PROC_p4}, + {"xop", x86_cpu_set, CPU_XOP}, + {"mmx", x86_cpu_set, CPU_MMX}, + {"486", x86_cpu_intel, PROC_486}, + {"clawhammer", x86_cpu_amd, PROC_hammer}, + {"rdseed", x86_cpu_set, CPU_RDSEED}, + {"i286", x86_cpu_intel, PROC_286}, + {"prfchw", x86_cpu_set, CPU_PRFCHW}, + {"nosse3", x86_cpu_clear, CPU_SSE3}, + {"sse4", x86_cpu_set_sse4, 0}, + {"pentium-iv", x86_cpu_intel, PROC_p4}, + {"p4", x86_cpu_intel, PROC_p4}, + {"nordrand", x86_cpu_clear, CPU_RDRAND}, + {"ppro", x86_cpu_intel, PROC_686}, + {"p5", x86_cpu_intel, PROC_586}, + {"notbm", x86_cpu_clear, CPU_TBM}, + {"cyrix", x86_cpu_set, CPU_Cyrix}, + {"80386", x86_cpu_intel, PROC_386}, + {"k6", x86_cpu_amd, PROC_k6}, + {"basicnop", x86_nop, X86_NOP_BASIC}, + {"nomovbe", x86_cpu_clear, CPU_MOVBE}, + {"noadx", x86_cpu_clear, CPU_ADX}, + {"nosmap", x86_cpu_clear, CPU_SMAP}, + {"nosmm", x86_cpu_clear, CPU_SMM}, + {"xsaveopt", x86_cpu_set, CPU_XSAVEOPT}, + {"pentium-3", x86_cpu_intel, PROC_p3}, + {"nosvm", x86_cpu_clear, CPU_SVM}, + {"nosha", x86_cpu_clear, CPU_SHA}, + {"invpcid", x86_cpu_set, CPU_INVPCID}, + {"nobmi1", x86_cpu_clear, CPU_BMI1}, + {"ivybridge", x86_cpu_intel, PROC_ivybridge}, + {"p3", x86_cpu_intel, PROC_p3}, + {"pentiumpro", x86_cpu_intel, PROC_686}, + {"penryn", x86_cpu_intel, PROC_penryn}, + {"80486", x86_cpu_intel, PROC_486}, + {"noxop", x86_cpu_clear, CPU_XOP}, + {"undoc", x86_cpu_set, CPU_Undoc}, + {"noobsolete", x86_cpu_clear, CPU_Obs}, + {"noavx", x86_cpu_clear, CPU_AVX}, + {"nolzcnt", x86_cpu_clear, CPU_LZCNT}, + {"noprfchw", x86_cpu_clear, CPU_PRFCHW}, + {"notsx", x86_cpu_clear, CPU_TSX}, + {"bmi1", x86_cpu_set, CPU_BMI1}, + {"itanium", x86_cpu_ia64, 0}, + {"venice", x86_cpu_amd, PROC_venice}, + {"noxsave", x86_cpu_clear, CPU_XSAVE}, + {"noamd", x86_cpu_clear, CPU_AMD}, + {"noobs", x86_cpu_clear, CPU_Obs}, + {"noem64t", x86_cpu_clear, CPU_EM64T}, + {"hammer", x86_cpu_amd, PROC_hammer}, + {"nehalem", x86_cpu_intel, PROC_nehalem}, + {"sse3", x86_cpu_set, CPU_SSE3}, + {"sse2", x86_cpu_set, CPU_SSE2}, + {"clmul", x86_cpu_set, CPU_CLMUL}, + {"smx", x86_cpu_set, CPU_SMX}, + {"nosse4a", x86_cpu_clear, CPU_SSE4a}, + {"tbm", x86_cpu_set, CPU_TBM}, + {"fma", x86_cpu_set, CPU_FMA}, + {"nopadlock", x86_cpu_clear, CPU_PadLock}, + {"nosse41", x86_cpu_clear, CPU_SSE41}, + {"adx", x86_cpu_set, CPU_ADX}, + {"westmere", x86_cpu_intel, PROC_westmere}, + {"k7", x86_cpu_amd, PROC_k7}, + {"noinvpcid", x86_cpu_clear, CPU_INVPCID}, + {"fsgsbase", x86_cpu_set, CPU_FSGSBASE}, + {"corei7", x86_cpu_intel, PROC_nehalem}, + {"movbe", x86_cpu_set, CPU_MOVBE}, + {"286", x86_cpu_intel, PROC_286} + }; + static const unsigned char tab[] = { + 183,125,113,40,125,0,0,0,183,146,116,85,0,113,113,183, + 113,131,0,82,88,0,131,125,85,0,113,0,0,7,0,40, + 22,7,0,0,125,220,87,183,184,7,0,0,0,113,11,0, + 84,0,0,0,0,131,0,113,0,120,0,113,0,0,51,11, + 55,190,0,0,183,61,120,131,85,135,0,0,0,0,0,82, + 74,183,0,87,220,0,235,0,220,229,0,0,220,243,124,145, + 0,220,131,0,221,0,0,0,237,0,135,125,124,168,0,69, + 0,124,22,0,131,131,163,113,184,214,155,133,55,0,0,0, + }; + + const struct cpu_parse_data *ret; + unsigned long rsl, val = phash_lookup(key, len, 0xdaa66d2bUL); + rsl = ((val>>25)^tab[val&0x7f]); + if (rsl >= 179) return NULL; + ret = &pd[rsl]; + if (strcmp(key, ret->name) != 0) return NULL; + return ret; +} + + + +void +yasm_x86__parse_cpu(yasm_arch_x86 *arch_x86, const char *cpuid, + size_t cpuid_len) +{ + /*@null@*/ const struct cpu_parse_data *pdata; + wordptr new_cpu; + size_t i; + static char lcaseid[16]; + + if (cpuid_len > 15) + return; + for (i=0; i<cpuid_len; i++) + lcaseid[i] = tolower(cpuid[i]); + lcaseid[cpuid_len] = '\0'; + + pdata = cpu_find(lcaseid, cpuid_len); + if (!pdata) { + yasm_warn_set(YASM_WARN_GENERAL, + N_("unrecognized CPU identifier `%s'"), cpuid); + return; + } + + new_cpu = BitVector_Clone(arch_x86->cpu_enables[arch_x86->active_cpu]); + pdata->handler(new_cpu, arch_x86, pdata->data); + + /* try to find an existing match in the CPU table first */ + for (i=0; i<arch_x86->cpu_enables_size; i++) { + if (BitVector_equal(arch_x86->cpu_enables[i], new_cpu)) { + arch_x86->active_cpu = i; + BitVector_Destroy(new_cpu); + return; + } + } + + /* not found, need to add a new entry */ + arch_x86->active_cpu = arch_x86->cpu_enables_size++; + arch_x86->cpu_enables = + yasm_xrealloc(arch_x86->cpu_enables, + arch_x86->cpu_enables_size*sizeof(wordptr)); + arch_x86->cpu_enables[arch_x86->active_cpu] = new_cpu; +} + diff --git a/contrib/tools/yasm/modules/x86insn_gas.c b/contrib/tools/yasm/modules/x86insn_gas.c new file mode 100644 index 0000000000..e0773185ba --- /dev/null +++ b/contrib/tools/yasm/modules/x86insn_gas.c @@ -0,0 +1,2154 @@ +/* ANSI-C code produced by genperf */ +struct insnprefix_parse_data; +static const struct insnprefix_parse_data * +insnprefix_gas_find(const char *key, size_t len) +{ + static const struct insnprefix_parse_data pd[2070] = { + {"vpunpckhqdq", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0x6D, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"psrad", pshift_insn, 4, SUF_Z, 0xE2, 0x72, 0x04, 0, CPU_MMX, 0, 0}, + {"rsldt", cyrixsmm_insn, 1, SUF_Z, 0x7B, 0, 0, 0, CPU_486, CPU_Cyrix, CPU_SMM}, + {"ldmxcsr", ldstmxcsr_insn, 1, SUF_Z, 0x02, 0, 0, 0, CPU_SSE, 0, 0}, + {"idivl", div_insn, 8, SUF_L, 0x07, 0, 0, 0, CPU_386, 0, 0}, + {"vhaddpd", xmm_xmm128_256_insn, 4, SUF_Z, 0x66, 0x7C, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"aqword", NULL, X86_ADDRSIZE>>8, 0x40, 0, 0, 0, ONLY_64, 0, 0, 0}, + {"vcmpeq_uqsd", ssecmp_64_insn, 4, SUF_Z, 0x08, 0xF2, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"subl", arith_insn, 22, SUF_L, 0x28, 0x05, 0, 0, CPU_386, 0, 0}, + {"vcmple_oqsd", ssecmp_64_insn, 4, SUF_Z, 0x12, 0xF2, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"shrdw", shlrd_insn, 9, SUF_W, 0xAC, 0, 0, 0, CPU_386, 0, 0}, + {"xchgb", xchg_insn, 16, SUF_B, 0, 0, 0, 0, 0, 0, 0}, + {"dec", incdec_insn, 6, SUF_Z, 0x48, 0x01, 0, 0, 0, 0, 0}, + {"finit", threebyte_insn, 1, SUF_Z, 0x9B, 0xDB, 0xE3, 0, CPU_FPU, 0, 0}, + {"iret", onebyte_insn, 1, SUF_Z, 0xCF, 0, 0, 0, 0, 0, 0}, + {"mul", f6_insn, 4, SUF_Z, 0x04, 0, 0, 0, 0, 0, 0}, + {"vcvtdq2pd", avx_cvt_xmm64_insn, 3, SUF_Z, 0xF3, 0xE6, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"lzcntl", cnt_insn, 3, SUF_L, 0xBD, 0, 0, 0, CPU_LZCNT, 0, 0}, + {"vucomiss", avx_xmm_xmm32_insn, 2, SUF_Z, 0x00, 0x2E, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vblendpd", sse4imm_256_insn, 4, SUF_Z, 0x0D, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"sscal", onebyte_insn, 1, SUF_Z, 0xAF, 0x20, 0, 0, CPU_386, 0, 0}, + {"vcmpnlt_uqpd", ssecmp_128_insn, 3, SUF_Z, 0x15, 0x66, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"setpob", setcc_insn, 1, SUF_B, 0x0B, 0, 0, 0, CPU_386, 0, 0}, + {"andn", vex_gpr_reg_nds_rm_0F_insn, 2, SUF_Z, 0x00, 0x38, 0xF2, ONLY_AVX, CPU_BMI1, 0, 0}, + {"scasq", onebyte_insn, 1, SUF_Z, 0xAF, 0x40, 0, ONLY_64, 0, 0, 0}, + {"xorw", arith_insn, 22, SUF_W, 0x30, 0x06, 0, 0, 0, 0, 0}, + {"vprotw", vprot_insn, 3, SUF_Z, 0x01, 0, 0, 0, CPU_XOP, 0, 0}, + {"vfmsub231sd", vfma_sd_insn, 2, SUF_Z, 0xBB, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"vpmovmskbq", pmovmskb_insn, 6, SUF_Q, 0xC0, 0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"data32", NULL, X86_OPERSIZE>>8, 0x20, 0, 0, 0, 0, 0, 0, 0}, + {"movntdq", movnt_insn, 2, SUF_Z, 0x66, 0xE7, 0, 0, CPU_SSE2, 0, 0}, + {"vandps", xmm_xmm128_256_insn, 4, SUF_Z, 0x00, 0x54, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"fidivrs", fiarith_insn, 2, SUF_S, 0x07, 0xDA, 0, 0, CPU_FPU, 0, 0}, + {"vcmpfalse_osss", ssecmp_32_insn, 4, SUF_Z, 0x1B, 0xF3, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vcmpneqpd", ssecmp_128_insn, 3, SUF_Z, 0x04, 0x66, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vcmpneq_oqsd", ssecmp_64_insn, 4, SUF_Z, 0x0C, 0xF2, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpcomnequb", vpcom_insn, 1, SUF_Z, 0xEC, 0x05, 0, 0, CPU_XOP, 0, 0}, + {"vfnmadd213sd", vfma_sd_insn, 2, SUF_Z, 0xAD, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"cmplesd", ssecmp_64_insn, 4, SUF_Z, 0x02, 0xF2, 0, 0, CPU_SSE2, 0, 0}, + {"vpshaq", amd_vpshift_insn, 2, SUF_Z, 0x9B, 0, 0, 0, CPU_XOP, 0, 0}, + {"iretw", onebyte_insn, 1, SUF_Z, 0xCF, 0x10, 0, 0, 0, 0, 0}, + {"vpcomltub", vpcom_insn, 1, SUF_Z, 0xEC, 0x00, 0, 0, CPU_XOP, 0, 0}, + {"vmovupd", movau_insn, 6, SUF_Z, 0x66, 0x10, 0x01, ONLY_AVX, CPU_AVX, 0, 0}, + {"fabs", twobyte_insn, 1, SUF_Z, 0xD9, 0xE1, 0, 0, CPU_FPU, 0, 0}, + {"lgdtq", twobytemem_insn, 1, SUF_Q, 0x02, 0x0F, 0x01, 0, CPU_286, CPU_Priv, 0}, + {"vcmpgeps", ssecmp_128_insn, 3, SUF_Z, 0x0D, 0x00, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"popfw", onebyte_insn, 1, SUF_Z, 0x9D, 0x10, 0x40, 0, 0, 0, 0}, + {"vpmovsxwd", sse4m64_insn, 4, SUF_Z, 0x23, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpsravd", vpshiftv_vexw0_avx2_insn, 2, SUF_Z, 0x46, 0, 0, ONLY_AVX, CPU_AVX2, 0, 0}, + {"vpmadcswd", vpma_insn, 1, SUF_Z, 0xB6, 0, 0, 0, CPU_XOP, 0, 0}, + {"vpmovsxbq", sse4m16_insn, 4, SUF_Z, 0x22, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpcomleud", vpcom_insn, 1, SUF_Z, 0xEE, 0x01, 0, 0, CPU_XOP, 0, 0}, + {"phsubw", ssse3_insn, 5, SUF_Z, 0x05, 0, 0, 0, CPU_SSSE3, 0, 0}, + {"call", call_insn, 30, SUF_Z, 0, 0, 0, 0, 0, 0, 0}, + {"cmovpe", cmovcc_insn, 3, SUF_Z, 0x0A, 0, 0, 0, CPU_686, 0, 0}, + {"vpcomneqq", vpcom_insn, 1, SUF_Z, 0xCF, 0x05, 0, 0, CPU_XOP, 0, 0}, + {"fcomp", fcom_insn, 6, SUF_Z, 0xD8, 0x03, 0, 0, CPU_FPU, 0, 0}, + {"vdpps", sse4imm_256_insn, 4, SUF_Z, 0x40, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"pmovsxdq", sse4m64_insn, 4, SUF_Z, 0x25, 0, 0, 0, CPU_SSE41, 0, 0}, + {"rcll", shift_insn, 16, SUF_L, 0x02, 0, 0, 0, CPU_386, 0, 0}, + {"xorps", xmm_xmm128_insn, 2, SUF_Z, 0x00, 0x57, 0, 0, CPU_SSE, 0, 0}, + {"cmovaq", cmovcc_insn, 3, SUF_Q, 0x07, 0, 0, ONLY_64, CPU_686, 0, 0}, + {"int3", onebyte_insn, 1, SUF_Z, 0xCC, 0, 0, 0, 0, 0, 0}, + {"fsubrp", farithp_insn, 3, SUF_Z, 0xE8, 0, 0, 0, CPU_FPU, 0, 0}, + {"pdepq", vex_gpr_reg_nds_rm_0F_insn, 2, SUF_Q, 0xF2, 0x38, 0xF5, ONLY_64|ONLY_AVX, CPU_BMI2, 0, 0}, + {"vfmadd132pd", vfma_pd_insn, 2, SUF_Z, 0x98, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"bts", bittest_insn, 6, SUF_Z, 0xAB, 0x05, 0, 0, CPU_386, 0, 0}, + {"jnge", jcc_insn, 9, SUF_Z, 0x0C, 0, 0, 0, 0, 0, 0}, + {"movbe", movbe_insn, 6, SUF_Z, 0, 0, 0, 0, CPU_MOVBE, 0, 0}, + {"rsdc", rsdc_insn, 1, SUF_Z, 0, 0, 0, 0, CPU_486, CPU_Cyrix, CPU_SMM}, + {"psubusb", mmxsse2_insn, 2, SUF_Z, 0xD8, 0, 0, 0, CPU_MMX, 0, 0}, + {"pmaxsb", sse4_insn, 2, SUF_Z, 0x3C, 0, 0, 0, CPU_SSE41, 0, 0}, + {"ffree", ffree_insn, 1, SUF_Z, 0xDD, 0, 0, 0, CPU_FPU, 0, 0}, + {"fsubrl", farith_insn, 7, SUF_L, 0xE0, 0xE8, 0x05, 0, CPU_FPU, 0, 0}, + {"pminsb", sse4_insn, 2, SUF_Z, 0x38, 0, 0, 0, CPU_SSE41, 0, 0}, + {"vcmpltsd", ssecmp_64_insn, 4, SUF_Z, 0x01, 0xF2, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vcvtsd2ss", xmm_xmm64_insn, 4, SUF_Z, 0xF2, 0x5A, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"verr", prot286_insn, 1, SUF_Z, 0x04, 0x00, 0, 0, CPU_286, CPU_Prot, 0}, + {"pcmpgtb", mmxsse2_insn, 2, SUF_Z, 0x64, 0, 0, 0, CPU_MMX, 0, 0}, + {"lcall", ljmpcall_insn, 7, SUF_Z, 0x03, 0x9A, 0, 0, 0, 0, 0}, + {"vcmpngt_uqss", ssecmp_32_insn, 4, SUF_Z, 0x1A, 0xF3, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"pmulhuw", mmxsse2_insn, 2, SUF_Z, 0xE4, 0, 0, 0, CPU_MMX, CPU_P3, 0}, + {"vcmpeq_ossd", ssecmp_64_insn, 4, SUF_Z, 0x10, 0xF2, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vmaxsd", xmm_xmm64_insn, 4, SUF_Z, 0xF2, 0x5F, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpclmulhqlqdq", pclmulqdq_fixed_insn, 2, SUF_Z, 0x01, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vcmpunord_sps", ssecmp_128_insn, 3, SUF_Z, 0x13, 0x00, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"data64", NULL, X86_OPERSIZE>>8, 0x40, 0, 0, 0, ONLY_64, 0, 0, 0}, + {"fimul", fiarith_insn, 2, SUF_Z, 0x01, 0xDA, 0, 0, CPU_FPU, 0, 0}, + {"tzcntq", cnt_insn, 3, SUF_Q, 0xBC, 0, 0, ONLY_64, CPU_BMI1, 0, 0}, + {"cmovgel", cmovcc_insn, 3, SUF_L, 0x0D, 0, 0, 0, CPU_686, 0, 0}, + {"cmovbw", cmovcc_insn, 3, SUF_W, 0x02, 0, 0, 0, CPU_686, 0, 0}, + {"vcmpordss", ssecmp_32_insn, 4, SUF_Z, 0x07, 0xF3, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"blendpd", sse4imm_insn, 2, SUF_Z, 0x0D, 0, 0, 0, CPU_SSE41, 0, 0}, + {"seta", setcc_insn, 1, SUF_Z, 0x07, 0, 0, 0, CPU_386, 0, 0}, + {"vfnmaddss", fma_128_m32_insn, 3, SUF_Z, 0x7A, 0, 0, ONLY_AVX, CPU_FMA4, 0, 0}, + {"blsfilll", xop_gpr_reg_rm_09_insn, 2, SUF_L, 0x01, 0x02, 0, 0, CPU_386, CPU_TBM, 0}, + {"incw", incdec_insn, 6, SUF_W, 0x40, 0x00, 0, 0, 0, 0, 0}, + {"blsmsk", vex_gpr_ndd_rm_0F38_regext_insn, 2, SUF_Z, 0x00, 0xF3, 0x02, ONLY_AVX, CPU_BMI1, 0, 0}, + {"testq", test_insn, 20, SUF_Q, 0, 0, 0, ONLY_64, 0, 0, 0}, + {"pushfq", onebyte_insn, 1, SUF_Z, 0x9C, 0x40, 0x40, ONLY_64, 0, 0, 0}, + {"jbe", jcc_insn, 9, SUF_Z, 0x06, 0, 0, 0, 0, 0, 0}, + {"vpcomuw", vpcom_imm_insn, 1, SUF_Z, 0xED, 0, 0, 0, CPU_XOP, 0, 0}, + {"vcomisd", avx_xmm_xmm64_insn, 2, SUF_Z, 0x66, 0x2F, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vcmpneq_osps", ssecmp_128_insn, 3, SUF_Z, 0x1C, 0x00, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vcmpneq_usps", ssecmp_128_insn, 3, SUF_Z, 0x14, 0x00, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"pswapd", now3d_insn, 1, SUF_Z, 0xBB, 0, 0, 0, CPU_3DNow, CPU_Athlon, 0}, + {"blciq", xop_gpr_reg_rm_09_insn, 2, SUF_Q, 0x02, 0x06, 0, ONLY_64, CPU_TBM, 0, 0}, + {"skinit", skinit_insn, 2, SUF_Z, 0, 0, 0, 0, CPU_SVM, 0, 0}, + {"sqrtsd", xmm_xmm64_insn, 4, SUF_Z, 0xF2, 0x51, 0, 0, CPU_SSE2, 0, 0}, + {"frndint", twobyte_insn, 1, SUF_Z, 0xD9, 0xFC, 0, 0, CPU_FPU, 0, 0}, + {"vpxor", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0xEF, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"movmskpdl", movmsk_insn, 4, SUF_L, 0x66, 0, 0, 0, CPU_SSE2, 0, 0}, + {"cmpltss", ssecmp_32_insn, 4, SUF_Z, 0x01, 0xF3, 0, 0, CPU_SSE, 0, 0}, + {"loop", loop_insn, 8, SUF_Z, 0x02, 0, 0, 0, 0, 0, 0}, + {"vphsubwd", vphaddsub_insn, 1, SUF_Z, 0xE2, 0, 0, 0, CPU_XOP, 0, 0}, + {"vpcomltuq", vpcom_insn, 1, SUF_Z, 0xEF, 0x00, 0, 0, CPU_XOP, 0, 0}, + {"psubq", mmxsse2_insn, 2, SUF_Z, 0xFB, 0, 0, 0, CPU_MMX, 0, 0}, + {"cmovcq", cmovcc_insn, 3, SUF_Q, 0x02, 0, 0, ONLY_64, CPU_686, 0, 0}, + {"vpsrlw", vpshift_insn, 8, SUF_Z, 0xD1, 0x71, 0x02, ONLY_AVX, CPU_AVX, 0, 0}, + {"setleb", setcc_insn, 1, SUF_B, 0x0E, 0, 0, 0, CPU_386, 0, 0}, + {"vcmpnltps", ssecmp_128_insn, 3, SUF_Z, 0x05, 0x00, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"cvtps2pi", cvt_mm_xmm64_insn, 2, SUF_Z, 0x2D, 0, 0, 0, CPU_SSE, 0, 0}, + {"lgdtw", twobytemem_insn, 1, SUF_W, 0x02, 0x0F, 0x01, 0, CPU_286, CPU_Priv, 0}, + {"vpcomq", vpcom_imm_insn, 1, SUF_Z, 0xCF, 0, 0, 0, CPU_XOP, 0, 0}, + {"jna", jcc_insn, 9, SUF_Z, 0x06, 0, 0, 0, 0, 0, 0}, + {"vpsubusb", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0xD8, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vcmpgt_oqss", ssecmp_32_insn, 4, SUF_Z, 0x1E, 0xF3, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vfmsub231ps", vfma_ps_insn, 2, SUF_Z, 0xBA, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"vfnmsubpd", fma_128_256_insn, 4, SUF_Z, 0x7D, 0, 0, ONLY_AVX, CPU_FMA4, 0, 0}, + {"vmsave", svm_rax_insn, 2, SUF_Z, 0xDB, 0, 0, 0, CPU_SVM, 0, 0}, + {"aesdec", aes_insn, 2, SUF_Z, 0x38, 0xDE, 0, 0, CPU_AVX, 0, 0}, + {"vcvtpd2ps", avx_cvt_xmm128_insn, 2, SUF_Z, 0x66, 0x5A, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vphaddwq", vphaddsub_insn, 1, SUF_Z, 0xC7, 0, 0, 0, CPU_XOP, 0, 0}, + {"cmovpo", cmovcc_insn, 3, SUF_Z, 0x0B, 0, 0, 0, CPU_686, 0, 0}, + {"pmulld", sse4_insn, 2, SUF_Z, 0x40, 0, 0, 0, CPU_SSE41, 0, 0}, + {"cbtw", onebyte_insn, 1, SUF_Z, 0x98, 0x10, 0, 0, 0, 0, 0}, + {"loadall286", twobyte_insn, 1, SUF_Z, 0x0F, 0x05, 0, 0, CPU_286, CPU_Undoc, 0}, + {"rexy", NULL, X86_REX>>8, 0x42, 0, 0, 0, ONLY_64, 0, 0, 0}, + {"lgsw", lfgss_insn, 3, SUF_W, 0xB5, 0, 0, 0, CPU_386, 0, 0}, + {"vcmpngeps", ssecmp_128_insn, 3, SUF_Z, 0x09, 0x00, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"btc", bittest_insn, 6, SUF_Z, 0xBB, 0x07, 0, 0, CPU_386, 0, 0}, + {"vcmpeq_uqss", ssecmp_32_insn, 4, SUF_Z, 0x08, 0xF3, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"invept", eptvpid_insn, 2, SUF_Z, 0x00, 0, 0, 0, CPU_386, CPU_EPTVPID, 0}, + {"vfmaddsub231pd", vfma_pd_insn, 2, SUF_Z, 0xB6, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"strl", str_insn, 4, SUF_L, 0, 0, 0, 0, CPU_386, CPU_Prot, 0}, + {"shlxl", vex_gpr_reg_rm_nds_0F_insn, 2, SUF_L, 0x66, 0x38, 0xF7, ONLY_AVX, CPU_BMI2, 0, 0}, + {"loopq", loopq_insn, 4, SUF_Z, 0x02, 0x40, 0, ONLY_64, 0, 0, 0}, + {"pmvzb", cyrixmmx_insn, 1, SUF_Z, 0x58, 0, 0, 0, CPU_Cyrix, CPU_MMX, 0}, + {"vshufpd", xmm_xmm128_imm_256_insn, 3, SUF_Z, 0x66, 0xC6, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpsubq", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0xFB, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"fnstsw", fnstsw_insn, 2, SUF_Z, 0, 0, 0, 0, CPU_FPU, 0, 0}, + {"incl", incdec_insn, 6, SUF_L, 0x40, 0x00, 0, 0, CPU_386, 0, 0}, + {"fnop", twobyte_insn, 1, SUF_Z, 0xD9, 0xD0, 0, 0, CPU_FPU, 0, 0}, + {"punpckhdq", mmxsse2_insn, 2, SUF_Z, 0x6A, 0, 0, 0, CPU_MMX, 0, 0}, + {"vphadduwd", vphaddsub_insn, 1, SUF_Z, 0xD6, 0, 0, 0, CPU_XOP, 0, 0}, + {"vmovaps", movau_insn, 6, SUF_Z, 0x00, 0x28, 0x01, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpsllq", vpshift_insn, 8, SUF_Z, 0xF3, 0x73, 0x06, ONLY_AVX, CPU_AVX, 0, 0}, + {"pfmul", now3d_insn, 1, SUF_Z, 0xB4, 0, 0, 0, CPU_3DNow, 0, 0}, + {"vcmpfalsess", ssecmp_32_insn, 4, SUF_Z, 0x0B, 0xF3, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vcmptrue_ussd", ssecmp_64_insn, 4, SUF_Z, 0x1F, 0xF2, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vcmple_oqps", ssecmp_128_insn, 3, SUF_Z, 0x12, 0x00, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpinsrwq", pinsrw_insn, 9, SUF_Q, 0xC0, 0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpminub", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0xDA, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"blcfillq", xop_gpr_reg_rm_09_insn, 2, SUF_Q, 0x01, 0x01, 0, ONLY_64, CPU_TBM, 0, 0}, + {"incq", incdec_insn, 6, SUF_Q, 0x40, 0x00, 0, ONLY_64, 0, 0, 0}, + {"pdep", vex_gpr_reg_nds_rm_0F_insn, 2, SUF_Z, 0xF2, 0x38, 0xF5, ONLY_AVX, CPU_BMI2, 0, 0}, + {"cmovnc", cmovcc_insn, 3, SUF_Z, 0x03, 0, 0, 0, CPU_686, 0, 0}, + {"movntil", movnti_insn, 2, SUF_L, 0, 0, 0, 0, CPU_P4, 0, 0}, + {"cmoveq", cmovcc_insn, 3, SUF_Q, 0x04, 0, 0, ONLY_64, CPU_686, 0, 0}, + {"pfrcpit2", now3d_insn, 1, SUF_Z, 0xB6, 0, 0, 0, CPU_3DNow, 0, 0}, + {"cmovaew", cmovcc_insn, 3, SUF_W, 0x03, 0, 0, 0, CPU_686, 0, 0}, + {"vinserti128", vinsertif128_insn, 1, SUF_Z, 0x38, 0, 0, ONLY_AVX, CPU_AVX2, 0, 0}, + {"movmskpdq", movmsk_insn, 4, SUF_Q, 0x66, 0, 0, ONLY_64, CPU_SSE2, 0, 0}, + {"vpmaxud", ssse3_insn, 5, SUF_Z, 0x3F, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"xaddw", cmpxchgxadd_insn, 4, SUF_W, 0xC0, 0, 0, 0, CPU_486, 0, 0}, + {"psubb", mmxsse2_insn, 2, SUF_Z, 0xF8, 0, 0, 0, CPU_MMX, 0, 0}, + {"vminpd", xmm_xmm128_256_insn, 4, SUF_Z, 0x66, 0x5D, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"mulpd", xmm_xmm128_insn, 2, SUF_Z, 0x66, 0x59, 0, 0, CPU_SSE2, 0, 0}, + {"fisttpl", fildstp_insn, 4, SUF_L, 0x01, 0x00, 0x01, 0, CPU_SSE3, 0, 0}, + {"vcmpordps", ssecmp_128_insn, 3, SUF_Z, 0x07, 0x00, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"lgs", lfgss_insn, 3, SUF_Z, 0xB5, 0, 0, 0, CPU_386, 0, 0}, + {"lzcntq", cnt_insn, 3, SUF_Q, 0xBD, 0, 0, ONLY_64, CPU_LZCNT, 0, 0}, + {"frstor", onebytemem_insn, 1, SUF_Z, 0x04, 0xDD, 0, 0, CPU_FPU, 0, 0}, + {"vcmpge_oqpd", ssecmp_128_insn, 3, SUF_Z, 0x1D, 0x66, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"setnbb", setcc_insn, 1, SUF_B, 0x03, 0, 0, 0, CPU_386, 0, 0}, + {"fcmovnbe", fcmovcc_insn, 1, SUF_Z, 0xDB, 0xD0, 0, 0, CPU_686, CPU_FPU, 0}, + {"pminub", mmxsse2_insn, 2, SUF_Z, 0xDA, 0, 0, 0, CPU_MMX, CPU_P3, 0}, + {"vcvttpd2dqx", avx_cvt_xmm128_x_insn, 1, SUF_Z, 0x66, 0xE6, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vfmaddsub231ps", vfma_ps_insn, 2, SUF_Z, 0xB6, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"data16", NULL, X86_OPERSIZE>>8, 0x10, 0, 0, 0, 0, 0, 0, 0}, + {"lmsw", prot286_insn, 1, SUF_Z, 0x06, 0x01, 0, 0, CPU_286, CPU_Priv, 0}, + {"cmovnsq", cmovcc_insn, 3, SUF_Q, 0x09, 0, 0, ONLY_64, CPU_686, 0, 0}, + {"ficompl", fiarith_insn, 2, SUF_L, 0x03, 0xDA, 0, 0, CPU_FPU, 0, 0}, + {"sets", setcc_insn, 1, SUF_Z, 0x08, 0, 0, 0, CPU_386, 0, 0}, + {"vpmuldq", ssse3_insn, 5, SUF_Z, 0x28, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"mulss", xmm_xmm32_insn, 4, SUF_Z, 0xF3, 0x59, 0, 0, CPU_SSE, 0, 0}, + {"minpd", xmm_xmm128_insn, 2, SUF_Z, 0x66, 0x5D, 0, 0, CPU_SSE2, 0, 0}, + {"pshufhw", xmm_xmm128_imm_insn, 1, SUF_Z, 0xF3, 0x70, 0, 0, CPU_SSE2, 0, 0}, + {"dword", NULL, X86_OPERSIZE>>8, 0x20, 0, 0, 0, 0, 0, 0, 0}, + {"cmovnael", cmovcc_insn, 3, SUF_L, 0x02, 0, 0, 0, CPU_686, 0, 0}, + {"xtest", tsx_0x0F_0x01_insn, 1, SUF_Z, 0xD6, 0, 0, 0, CPU_TSX, 0, 0}, + {"sar", shift_insn, 16, SUF_Z, 0x07, 0, 0, 0, 0, 0, 0}, + {"cmovngel", cmovcc_insn, 3, SUF_L, 0x0C, 0, 0, 0, CPU_686, 0, 0}, + {"cmovnlew", cmovcc_insn, 3, SUF_W, 0x0F, 0, 0, 0, CPU_686, 0, 0}, + {"sidt", twobytemem_insn, 1, SUF_Z, 0x01, 0x0F, 0x01, 0, CPU_286, CPU_Priv, 0}, + {"fxrstor", twobytemem_insn, 1, SUF_Z, 0x01, 0x0F, 0xAE, 0, CPU_686, CPU_FPU, 0}, + {"adcxl", vex_gpr_ndd_rm_0F38_insn, 2, SUF_L, 0x66, 0xF6, 0, 0, CPU_ADX, 0, 0}, + {"mull", f6_insn, 4, SUF_L, 0x04, 0, 0, 0, CPU_386, 0, 0}, + {"wbinvd", twobyte_insn, 1, SUF_Z, 0x0F, 0x09, 0, 0, CPU_486, CPU_Priv, 0}, + {"pmaxuw", sse4_insn, 2, SUF_Z, 0x3E, 0, 0, 0, CPU_SSE41, 0, 0}, + {"setnp", setcc_insn, 1, SUF_Z, 0x0B, 0, 0, 0, CPU_386, 0, 0}, + {"decb", incdec_insn, 6, SUF_B, 0x48, 0x01, 0, 0, 0, 0, 0}, + {"fnsaves", onebytemem_insn, 1, SUF_S, 0x06, 0xDD, 0, 0, CPU_FPU, 0, 0}, + {"cmovbe", cmovcc_insn, 3, SUF_Z, 0x06, 0, 0, 0, CPU_686, 0, 0}, + {"fsaves", twobytemem_insn, 1, SUF_S, 0x06, 0x9B, 0xDD, 0, CPU_FPU, 0, 0}, + {"jz", jcc_insn, 9, SUF_Z, 0x04, 0, 0, 0, 0, 0, 0}, + {"cmovngeq", cmovcc_insn, 3, SUF_Q, 0x0C, 0, 0, ONLY_64, CPU_686, 0, 0}, + {"neg", f6_insn, 4, SUF_Z, 0x03, 0, 0, 0, 0, 0, 0}, + {"jmp", jmp_insn, 31, SUF_Z, 0, 0, 0, 0, 0, 0, 0}, + {"fdivrp", farithp_insn, 3, SUF_Z, 0xF8, 0, 0, 0, CPU_FPU, 0, 0}, + {"cmovnsl", cmovcc_insn, 3, SUF_L, 0x09, 0, 0, 0, CPU_686, 0, 0}, + {"lesl", ldes_insn, 2, SUF_L, 0xC4, 0, 0, NOT_64, CPU_386, 0, 0}, + {"vpsllvq", vpshiftv_vexw1_avx2_insn, 2, SUF_Z, 0x47, 0, 0, ONLY_AVX, CPU_AVX2, 0, 0}, + {"movslq", movsxd_insn, 1, SUF_L, 0, 0, 0, ONLY_64, 0, 0, 0}, + {"vmovss", movss_insn, 4, SUF_Z, 0xC0, 0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"cmovbew", cmovcc_insn, 3, SUF_W, 0x06, 0, 0, 0, CPU_686, 0, 0}, + {"vpermpd", vperm_imm_avx2_insn, 1, SUF_Z, 0x01, 0, 0, ONLY_AVX, CPU_AVX2, 0, 0}, + {"vcmpfalsesd", ssecmp_64_insn, 4, SUF_Z, 0x0B, 0xF2, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"pcmpeqd", mmxsse2_insn, 2, SUF_Z, 0x76, 0, 0, 0, CPU_MMX, 0, 0}, + {"cmovne", cmovcc_insn, 3, SUF_Z, 0x05, 0, 0, 0, CPU_686, 0, 0}, + {"vpcomeqw", vpcom_insn, 1, SUF_Z, 0xCD, 0x04, 0, 0, CPU_XOP, 0, 0}, + {"movsb", onebyte_insn, 1, SUF_Z, 0xA4, 0x00, 0, 0, 0, 0, 0}, + {"loopnzl", loopl_insn, 4, SUF_Z, 0x00, 0x20, 0, 0, 0, 0, 0}, + {"pmaxsd", sse4_insn, 2, SUF_Z, 0x3D, 0, 0, 0, CPU_SSE41, 0, 0}, + {"fld", fld_insn, 4, SUF_Z, 0, 0, 0, 0, CPU_FPU, 0, 0}, + {"fstpt", fldstpt_insn, 1, SUF_Z, 0x07, 0, 0, 0, CPU_FPU, 0, 0}, + {"vcmplepd", ssecmp_128_insn, 3, SUF_Z, 0x02, 0x66, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"lidtq", twobytemem_insn, 1, SUF_Q, 0x03, 0x0F, 0x01, 0, CPU_286, CPU_Priv, 0}, + {"blsmskl", vex_gpr_ndd_rm_0F38_regext_insn, 2, SUF_L, 0x00, 0xF3, 0x02, ONLY_AVX, CPU_BMI1, 0, 0}, + {"vcmpge_oqsd", ssecmp_64_insn, 4, SUF_Z, 0x1D, 0xF2, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"unpckhps", xmm_xmm128_insn, 2, SUF_Z, 0x00, 0x15, 0, 0, CPU_SSE, 0, 0}, + {"vmreadq", vmxmemrd_insn, 2, SUF_Q, 0, 0, 0, ONLY_64, CPU_P4, 0, 0}, + {"btsw", bittest_insn, 6, SUF_W, 0xAB, 0x05, 0, 0, CPU_386, 0, 0}, + {"vpinsrwl", pinsrw_insn, 9, SUF_L, 0xC0, 0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpcmpgtw", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0x65, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"pextq", vex_gpr_reg_nds_rm_0F_insn, 2, SUF_Q, 0xF3, 0x38, 0xF5, ONLY_64|ONLY_AVX, CPU_BMI2, 0, 0}, + {"vcmpnge_uqsd", ssecmp_64_insn, 4, SUF_Z, 0x19, 0xF2, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"pavgw", mmxsse2_insn, 2, SUF_Z, 0xE3, 0, 0, 0, CPU_MMX, CPU_P3, 0}, + {"vpunpckhbw", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0x68, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vmlaunch", threebyte_insn, 1, SUF_Z, 0x0F, 0x01, 0xC2, 0, CPU_P4, 0, 0}, + {"loopnew", loopw_insn, 4, SUF_Z, 0x00, 0x10, 0, NOT_64, 0, 0, 0}, + {"vmaxps", xmm_xmm128_256_insn, 4, SUF_Z, 0x00, 0x5F, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"rdshr", rdwrshr_insn, 1, SUF_Z, 0x00, 0, 0, 0, CPU_686, CPU_Cyrix, CPU_SMM}, + {"setge", setcc_insn, 1, SUF_Z, 0x0D, 0, 0, 0, CPU_386, 0, 0}, + {"pcmpgtw", mmxsse2_insn, 2, SUF_Z, 0x65, 0, 0, 0, CPU_MMX, 0, 0}, + {"vsqrtpd", avx_xmm_xmm128_insn, 2, SUF_Z, 0x66, 0x51, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"fstsw", fstsw_insn, 2, SUF_Z, 0, 0, 0, 0, CPU_FPU, 0, 0}, + {"cmovzw", cmovcc_insn, 3, SUF_W, 0x04, 0, 0, 0, CPU_686, 0, 0}, + {"frstors", onebytemem_insn, 1, SUF_S, 0x04, 0xDD, 0, 0, CPU_FPU, 0, 0}, + {"smsww", sldtmsw_insn, 6, SUF_W, 0x04, 0x01, 0, 0, CPU_286, 0, 0}, + {"vpsubusw", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0xD9, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"fisubrs", fiarith_insn, 2, SUF_S, 0x05, 0xDA, 0, 0, CPU_FPU, 0, 0}, + {"vmovshdup", avx_xmm_xmm128_insn, 2, SUF_Z, 0xF3, 0x16, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"xacquire", NULL, X86_ACQREL>>8, 0xF2, 0, 0, 0, 0, 0, 0, 0}, + {"vcmple_oqss", ssecmp_32_insn, 4, SUF_Z, 0x12, 0xF3, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vcmpgt_oqpd", ssecmp_128_insn, 3, SUF_Z, 0x1E, 0x66, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"pfsub", now3d_insn, 1, SUF_Z, 0x9A, 0, 0, 0, CPU_3DNow, 0, 0}, + {"vpgatherdd", gather_32x_32y_insn, 2, SUF_Z, 0x90, 0, 0, ONLY_AVX, CPU_AVX2, 0, 0}, + {"vcmpngtss", ssecmp_32_insn, 4, SUF_Z, 0x0A, 0xF3, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"pmovzxbw", sse4m64_insn, 4, SUF_Z, 0x30, 0, 0, 0, CPU_SSE41, 0, 0}, + {"cmovgl", cmovcc_insn, 3, SUF_L, 0x0F, 0, 0, 0, CPU_686, 0, 0}, + {"movaps", movau_insn, 6, SUF_Z, 0x00, 0x28, 0x01, 0, CPU_SSE, 0, 0}, + {"rdfsbase", fs_gs_base_insn, 2, SUF_Z, 0x00, 0, 0, ONLY_64, CPU_FSGSBASE, 0, 0}, + {"wrmsr", twobyte_insn, 1, SUF_Z, 0x0F, 0x30, 0, 0, CPU_586, CPU_Priv, 0}, + {"movmskpsl", movmsk_insn, 4, SUF_L, 0, 0, 0, 0, CPU_386, CPU_SSE, 0}, + {"vcmpngtpd", ssecmp_128_insn, 3, SUF_Z, 0x0A, 0x66, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"decw", incdec_insn, 6, SUF_W, 0x48, 0x01, 0, 0, 0, 0, 0}, + {"vmclear", vmxthreebytemem_insn, 1, SUF_Z, 0x66, 0, 0, 0, CPU_P4, 0, 0}, + {"vfmsub213pd", vfma_pd_insn, 2, SUF_Z, 0xAA, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"roundps", sse4imm_insn, 2, SUF_Z, 0x08, 0, 0, 0, CPU_SSE41, 0, 0}, + {"xsaveopt", twobytemem_insn, 1, SUF_Z, 0x06, 0x0F, 0xAE, 0, CPU_XSAVEOPT, 0, 0}, + {"blsmskq", vex_gpr_ndd_rm_0F38_regext_insn, 2, SUF_Q, 0x00, 0xF3, 0x02, ONLY_64|ONLY_AVX, CPU_BMI1, 0, 0}, + {"fnstcww", fldnstcw_insn, 1, SUF_W, 0x07, 0, 0, 0, CPU_FPU, 0, 0}, + {"unpcklpd", xmm_xmm128_insn, 2, SUF_Z, 0x66, 0x14, 0, 0, CPU_SSE2, 0, 0}, + {"pfrcp", now3d_insn, 1, SUF_Z, 0x96, 0, 0, 0, CPU_3DNow, 0, 0}, + {"phaddw", ssse3_insn, 5, SUF_Z, 0x01, 0, 0, 0, CPU_SSSE3, 0, 0}, + {"adoxq", vex_gpr_ndd_rm_0F38_insn, 2, SUF_Q, 0xF3, 0xF6, 0, ONLY_64, CPU_ADX, 0, 0}, + {"vcmpnltsd", ssecmp_64_insn, 4, SUF_Z, 0x05, 0xF2, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpcomleub", vpcom_insn, 1, SUF_Z, 0xEC, 0x01, 0, 0, CPU_XOP, 0, 0}, + {"vpsrlq", vpshift_insn, 8, SUF_Z, 0xD3, 0x73, 0x02, ONLY_AVX, CPU_AVX, 0, 0}, + {"psllq", pshift_insn, 4, SUF_Z, 0xF3, 0x73, 0x06, 0, CPU_MMX, 0, 0}, + {"enterl", enter_insn, 3, SUF_L, 0, 0, 0, NOT_64, CPU_186, 0, 0}, + {"wrshr", rdwrshr_insn, 1, SUF_Z, 0x01, 0, 0, 0, CPU_686, CPU_Cyrix, CPU_SMM}, + {"blcsq", xop_gpr_reg_rm_09_insn, 2, SUF_Q, 0x01, 0x03, 0, ONLY_64, CPU_TBM, 0, 0}, + {"vpmadcsswd", vpma_insn, 1, SUF_Z, 0xA6, 0, 0, 0, CPU_XOP, 0, 0}, + {"fdivl", farith_insn, 7, SUF_L, 0xF8, 0xF0, 0x06, 0, CPU_FPU, 0, 0}, + {"salb", shift_insn, 16, SUF_B, 0x04, 0, 0, 0, 0, 0, 0}, + {"vpcomequq", vpcom_insn, 1, SUF_Z, 0xEF, 0x04, 0, 0, CPU_XOP, 0, 0}, + {"cmovpw", cmovcc_insn, 3, SUF_W, 0x0A, 0, 0, 0, CPU_686, 0, 0}, + {"cmovgw", cmovcc_insn, 3, SUF_W, 0x0F, 0, 0, 0, CPU_686, 0, 0}, + {"vpmovmskbl", pmovmskb_insn, 6, SUF_L, 0xC0, 0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"iretl", onebyte_insn, 1, SUF_Z, 0xCF, 0x20, 0, 0, CPU_386, 0, 0}, + {"fdiv", farith_insn, 7, SUF_Z, 0xF8, 0xF0, 0x06, 0, CPU_FPU, 0, 0}, + {"vpermps", vperm_var_avx2_insn, 1, SUF_Z, 0x16, 0, 0, ONLY_AVX, CPU_AVX2, 0, 0}, + {"vphaddwd", vphaddsub_insn, 1, SUF_Z, 0xC6, 0, 0, 0, CPU_XOP, 0, 0}, + {"vcmpnlt_uqss", ssecmp_32_insn, 4, SUF_Z, 0x15, 0xF3, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpcomleuw", vpcom_insn, 1, SUF_Z, 0xED, 0x01, 0, 0, CPU_XOP, 0, 0}, + {"crc32l", crc32_insn, 5, SUF_L, 0, 0, 0, 0, CPU_386, CPU_SSE42, 0}, + {"cmpsq", onebyte_insn, 1, SUF_Z, 0xA7, 0x40, 0, ONLY_64, 0, 0, 0}, + {"cmovpel", cmovcc_insn, 3, SUF_L, 0x0A, 0, 0, 0, CPU_686, 0, 0}, + {"cmovnlel", cmovcc_insn, 3, SUF_L, 0x0F, 0, 0, 0, CPU_686, 0, 0}, + {"sysretl", twobyte_insn, 1, SUF_L, 0x0F, 0x07, 0, 0, CPU_686, CPU_AMD, CPU_Priv}, + {"setpo", setcc_insn, 1, SUF_Z, 0x0B, 0, 0, 0, CPU_386, 0, 0}, + {"vpcomgtq", vpcom_insn, 1, SUF_Z, 0xCF, 0x02, 0, 0, CPU_XOP, 0, 0}, + {"phsubsw", ssse3_insn, 5, SUF_Z, 0x07, 0, 0, 0, CPU_SSSE3, 0, 0}, + {"pinsrw", pinsrw_insn, 9, SUF_Z, 0, 0, 0, 0, CPU_MMX, CPU_P3, 0}, + {"vfmadd231ps", vfma_ps_insn, 2, SUF_Z, 0xB8, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"mulps", xmm_xmm128_insn, 2, SUF_Z, 0x00, 0x59, 0, 0, CPU_SSE, 0, 0}, + {"setz", setcc_insn, 1, SUF_Z, 0x04, 0, 0, 0, CPU_386, 0, 0}, + {"cmpltsd", ssecmp_64_insn, 4, SUF_Z, 0x01, 0xF2, 0, 0, CPU_SSE2, 0, 0}, + {"fstl", fst_insn, 3, SUF_L, 0, 0, 0, 0, CPU_FPU, 0, 0}, + {"vcmptrueps", ssecmp_128_insn, 3, SUF_Z, 0x0F, 0x00, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"cmovow", cmovcc_insn, 3, SUF_W, 0x00, 0, 0, 0, CPU_686, 0, 0}, + {"extrq", extrq_insn, 2, SUF_Z, 0, 0, 0, 0, CPU_SSE4a, 0, 0}, + {"verrw", prot286_insn, 1, SUF_W, 0x04, 0x00, 0, 0, CPU_286, CPU_Prot, 0}, + {"setno", setcc_insn, 1, SUF_Z, 0x01, 0, 0, 0, CPU_386, 0, 0}, + {"lssw", lfgss_insn, 3, SUF_W, 0xB2, 0, 0, 0, CPU_386, 0, 0}, + {"cmpunordps", ssecmp_128_insn, 3, SUF_Z, 0x03, 0, 0, 0, CPU_SSE, 0, 0}, + {"shlxq", vex_gpr_reg_rm_nds_0F_insn, 2, SUF_Q, 0x66, 0x38, 0xF7, ONLY_64|ONLY_AVX, CPU_BMI2, 0, 0}, + {"emms", twobyte_insn, 1, SUF_Z, 0x0F, 0x77, 0, 0, CPU_MMX, 0, 0}, + {"sarq", shift_insn, 16, SUF_Q, 0x07, 0, 0, ONLY_64, 0, 0, 0}, + {"pminsd", sse4_insn, 2, SUF_Z, 0x39, 0, 0, 0, CPU_SSE41, 0, 0}, + {"rorw", shift_insn, 16, SUF_W, 0x01, 0, 0, 0, 0, 0, 0}, + {"pxor", mmxsse2_insn, 2, SUF_Z, 0xEF, 0, 0, 0, CPU_MMX, 0, 0}, + {"pfnacc", now3d_insn, 1, SUF_Z, 0x8A, 0, 0, 0, CPU_3DNow, CPU_Athlon, 0}, + {"pf2iw", now3d_insn, 1, SUF_Z, 0x1C, 0, 0, 0, CPU_3DNow, CPU_Athlon, 0}, + {"invpcid", invpcid_insn, 2, SUF_Z, 0, 0, 0, 0, CPU_386, CPU_INVPCID, CPU_Priv}, + {"fcompl", fcom_insn, 6, SUF_L, 0xD8, 0x03, 0, 0, CPU_FPU, 0, 0}, + {"larq", larlsl_insn, 6, SUF_Q, 0x02, 0, 0, ONLY_64, CPU_286, CPU_Prot, 0}, + {"str", str_insn, 4, SUF_Z, 0, 0, 0, 0, CPU_286, CPU_Prot, 0}, + {"movmskpsq", movmsk_insn, 4, SUF_Q, 0, 0, 0, ONLY_64, CPU_SSE, 0, 0}, + {"lds", ldes_insn, 2, SUF_Z, 0xC5, 0, 0, NOT_64, 0, 0, 0}, + {"vpinsrb", pinsrb_insn, 4, SUF_Z, 0xC0, 0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"pushf", onebyte_insn, 1, SUF_Z, 0x9C, 0x00, 0x40, 0, 0, 0, 0}, + {"vcvtsd2sil", cvt_rx_xmm64_insn, 4, SUF_L, 0xF2, 0x2D, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"jge", jcc_insn, 9, SUF_Z, 0x0D, 0, 0, 0, 0, 0, 0}, + {"setpb", setcc_insn, 1, SUF_B, 0x0A, 0, 0, 0, CPU_386, 0, 0}, + {"andl", arith_insn, 22, SUF_L, 0x20, 0x04, 0, 0, CPU_386, 0, 0}, + {"vaesdec", aes_insn, 2, SUF_Z, 0x38, 0xDE, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"xstore", padlock_insn, 1, SUF_Z, 0xC0, 0x00, 0xA7, 0, CPU_PadLock, 0, 0}, + {"sha1nexte", intel_SHA1NEXTE_insn, 1, SUF_Z, 0, 0, 0, 0, CPU_SHA, 0, 0}, + {"andps", xmm_xmm128_insn, 2, SUF_Z, 0x00, 0x54, 0, 0, CPU_SSE, 0, 0}, + {"vphaddbd", vphaddsub_insn, 1, SUF_Z, 0xC2, 0, 0, 0, CPU_XOP, 0, 0}, + {"rorxl", vex_gpr_reg_rm_0F_imm8_insn, 2, SUF_L, 0xF2, 0x3A, 0xF0, ONLY_AVX, CPU_BMI2, 0, 0}, + {"jmpw", jmp_insn, 31, SUF_W, 0, 0, 0, 0, 0, 0, 0}, + {"fildll", fbldstp_insn, 1, SUF_Z, 0x05, 0, 0, 0, CPU_FPU, 0, 0}, + {"out", out_insn, 12, SUF_Z, 0, 0, 0, 0, 0, 0, 0}, + {"mulsd", xmm_xmm64_insn, 4, SUF_Z, 0xF2, 0x59, 0, 0, CPU_SSE2, 0, 0}, + {"movss", movss_insn, 4, SUF_Z, 0, 0, 0, 0, CPU_SSE, 0, 0}, + {"smswl", sldtmsw_insn, 6, SUF_L, 0x04, 0x01, 0, 0, CPU_386, 0, 0}, + {"aam", aadm_insn, 2, SUF_Z, 0x00, 0, 0, NOT_64, 0, 0, 0}, + {"stosw", onebyte_insn, 1, SUF_Z, 0xAB, 0x10, 0, 0, 0, 0, 0}, + {"ptest", sse4_insn, 2, SUF_Z, 0x17, 0, 0, 0, CPU_SSE41, 0, 0}, + {"lretw", retnf_insn, 6, SUF_W, 0xCA, 0x10, 0, 0, 0, 0, 0}, + {"notq", f6_insn, 4, SUF_Q, 0x02, 0, 0, ONLY_64, 0, 0, 0}, + {"vmload", svm_rax_insn, 2, SUF_Z, 0xDA, 0, 0, 0, CPU_SVM, 0, 0}, + {"andb", arith_insn, 22, SUF_B, 0x20, 0x04, 0, 0, 0, 0, 0}, + {"vcmpeq_usss", ssecmp_32_insn, 4, SUF_Z, 0x18, 0xF3, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpsubsw", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0xE9, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vmovmskpd", movmsk_insn, 4, SUF_Z, 0x66, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vfnmsub231pd", vfma_pd_insn, 2, SUF_Z, 0xBE, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"cmovg", cmovcc_insn, 3, SUF_Z, 0x0F, 0, 0, 0, CPU_686, 0, 0}, + {"cmpeqpd", ssecmp_128_insn, 3, SUF_Z, 0x00, 0x66, 0, 0, CPU_SSE, 0, 0}, + {"vfmsub213sd", vfma_sd_insn, 2, SUF_Z, 0xAB, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"rex64", NULL, X86_REX>>8, 0x48, 0, 0, 0, ONLY_64, 0, 0, 0}, + {"vpcmpistri", sse4pcmpstr_insn, 1, SUF_Z, 0x63, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpminsb", ssse3_insn, 5, SUF_Z, 0x38, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vfnmadd231pd", vfma_pd_insn, 2, SUF_Z, 0xBC, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"ja", jcc_insn, 9, SUF_Z, 0x07, 0, 0, 0, 0, 0, 0}, + {"vpmullw", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0xD5, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vcvttpd2dq", avx_cvt_xmm128_insn, 2, SUF_Z, 0x66, 0xE6, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vgatherdps", gather_32x_32y_insn, 2, SUF_Z, 0x92, 0, 0, ONLY_AVX, CPU_AVX2, 0, 0}, + {"vfmsub213ss", vfma_ss_insn, 2, SUF_Z, 0xAB, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"cmpxchgb", cmpxchgxadd_insn, 4, SUF_B, 0xB0, 0, 0, 0, CPU_486, 0, 0}, + {"sgdtw", twobytemem_insn, 1, SUF_W, 0x00, 0x0F, 0x01, 0, CPU_286, CPU_Priv, 0}, + {"cmpb", arith_insn, 22, SUF_B, 0x38, 0x07, 0, 0, 0, 0, 0}, + {"vmulpd", xmm_xmm128_256_insn, 4, SUF_Z, 0x66, 0x59, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"cvttsd2siq", cvt_rx_xmm64_insn, 4, SUF_Q, 0xF2, 0x2C, 0, ONLY_64, CPU_SSE2, 0, 0}, + {"movzwq", movszx_insn, 5, SUF_W, 0xB6, 0, 0, ONLY_64, CPU_386, 0, 0}, + {"les", ldes_insn, 2, SUF_Z, 0xC4, 0, 0, NOT_64, 0, 0, 0}, + {"vcmpngepd", ssecmp_128_insn, 3, SUF_Z, 0x09, 0x66, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"clflush", clflush_insn, 1, SUF_Z, 0, 0, 0, 0, CPU_P3, 0, 0}, + {"leavew", onebyte_insn, 1, SUF_Z, 0xC9, 0x10, 0x00, 0, CPU_186, 0, 0}, + {"addsubps", xmm_xmm128_insn, 2, SUF_Z, 0xF2, 0xD0, 0, 0, CPU_SSE3, 0, 0}, + {"vinsertps", insertps_insn, 4, SUF_Z, 0xC0, 0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vmresume", threebyte_insn, 1, SUF_Z, 0x0F, 0x01, 0xC3, 0, CPU_P4, 0, 0}, + {"cmpnlesd", ssecmp_64_insn, 4, SUF_Z, 0x06, 0xF2, 0, 0, CPU_SSE2, 0, 0}, + {"setnge", setcc_insn, 1, SUF_Z, 0x0C, 0, 0, 0, CPU_386, 0, 0}, + {"adcxq", vex_gpr_ndd_rm_0F38_insn, 2, SUF_Q, 0x66, 0xF6, 0, ONLY_64, CPU_ADX, 0, 0}, + {"xsetbv", threebyte_insn, 1, SUF_Z, 0x0F, 0x01, 0xD1, 0, CPU_386, CPU_Priv, CPU_XSAVE}, + {"vphsubsw", ssse3_insn, 5, SUF_Z, 0x07, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vcmpgtsd", ssecmp_64_insn, 4, SUF_Z, 0x0E, 0xF2, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vphsubw", ssse3_insn, 5, SUF_Z, 0x05, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"cmovnbel", cmovcc_insn, 3, SUF_L, 0x07, 0, 0, 0, CPU_686, 0, 0}, + {"fcomi", fcom2_insn, 2, SUF_Z, 0xDB, 0xF0, 0, 0, CPU_686, CPU_FPU, 0}, + {"blsfillq", xop_gpr_reg_rm_09_insn, 2, SUF_Q, 0x01, 0x02, 0, ONLY_64, CPU_TBM, 0, 0}, + {"mulxl", vex_gpr_reg_nds_rm_0F_insn, 2, SUF_L, 0xF2, 0x38, 0xF6, ONLY_AVX, CPU_BMI2, 0, 0}, + {"fcomip", fcom2_insn, 2, SUF_Z, 0xDF, 0xF0, 0, 0, CPU_686, CPU_FPU, 0}, + {"vpinsrq", pinsrq_insn, 2, SUF_Z, 0xC0, 0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpcomw", vpcom_imm_insn, 1, SUF_Z, 0xCD, 0, 0, 0, CPU_XOP, 0, 0}, + {"rsts", cyrixsmm_insn, 1, SUF_Z, 0x7D, 0, 0, 0, CPU_486, CPU_Cyrix, CPU_SMM}, + {"vpcomleb", vpcom_insn, 1, SUF_Z, 0xCC, 0x01, 0, 0, CPU_XOP, 0, 0}, + {"vdivpd", xmm_xmm128_256_insn, 4, SUF_Z, 0x66, 0x5E, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"add", arith_insn, 22, SUF_Z, 0x00, 0x00, 0, 0, 0, 0, 0}, + {"sldtw", sldtmsw_insn, 6, SUF_W, 0x00, 0x00, 0, 0, CPU_286, 0, 0}, + {"rorl", shift_insn, 16, SUF_L, 0x01, 0, 0, 0, CPU_386, 0, 0}, + {"vcvtsi2sd", cvt_xmm_rmx_insn, 6, SUF_Z, 0xF2, 0x2A, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vcmpnge_uqps", ssecmp_128_insn, 3, SUF_Z, 0x19, 0x00, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vfmsubpd", fma_128_256_insn, 4, SUF_Z, 0x6D, 0, 0, ONLY_AVX, CPU_FMA4, 0, 0}, + {"vpminsd", ssse3_insn, 5, SUF_Z, 0x39, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"fistl", fiarith_insn, 2, SUF_L, 0x02, 0xDB, 0, 0, CPU_FPU, 0, 0}, + {"fcmovu", fcmovcc_insn, 1, SUF_Z, 0xDA, 0xD8, 0, 0, CPU_686, CPU_FPU, 0}, + {"scasb", onebyte_insn, 1, SUF_Z, 0xAE, 0x00, 0, 0, 0, 0, 0}, + {"phminposuw", sse4_insn, 2, SUF_Z, 0x41, 0, 0, 0, CPU_SSE41, 0, 0}, + {"pextrwl", pextrw_insn, 7, SUF_L, 0, 0, 0, 0, CPU_MMX, CPU_P3, 0}, + {"vpclmulqdq", pclmulqdq_insn, 2, SUF_Z, 0x3A, 0x44, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vphaddbw", vphaddsub_insn, 1, SUF_Z, 0xC1, 0, 0, 0, CPU_XOP, 0, 0}, + {"psubsb", mmxsse2_insn, 2, SUF_Z, 0xE8, 0, 0, 0, CPU_MMX, 0, 0}, + {"lss", lfgss_insn, 3, SUF_Z, 0xB2, 0, 0, 0, CPU_386, 0, 0}, + {"pushal", onebyte_insn, 1, SUF_Z, 0x60, 0x20, 0, NOT_64, CPU_386, 0, 0}, + {"setb", setcc_insn, 1, SUF_Z, 0x02, 0, 0, 0, CPU_386, 0, 0}, + {"cmpnltps", ssecmp_128_insn, 3, SUF_Z, 0x05, 0, 0, 0, CPU_SSE, 0, 0}, + {"rcpss", xmm_xmm32_insn, 4, SUF_Z, 0xF3, 0x53, 0, 0, CPU_SSE, 0, 0}, + {"vcmpnltpd", ssecmp_128_insn, 3, SUF_Z, 0x05, 0x66, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"cmpneqps", ssecmp_128_insn, 3, SUF_Z, 0x04, 0, 0, 0, CPU_SSE, 0, 0}, + {"vpsadbw", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0xF6, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vcvtss2sil", cvt_rx_xmm32_insn, 4, SUF_L, 0xF3, 0x2D, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"fadds", farith_insn, 7, SUF_S, 0xC0, 0xC0, 0x00, 0, CPU_FPU, 0, 0}, + {"cmovbeq", cmovcc_insn, 3, SUF_Q, 0x06, 0, 0, ONLY_64, CPU_686, 0, 0}, + {"bextrl", bextr_insn, 4, SUF_L, 0, 0, 0, ONLY_AVX, CPU_386, CPU_BMI1, 0}, + {"vsqrtps", avx_xmm_xmm128_insn, 2, SUF_Z, 0x00, 0x51, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vcmpunord_ssd", ssecmp_64_insn, 4, SUF_Z, 0x13, 0xF2, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"pmaxsw", mmxsse2_insn, 2, SUF_Z, 0xEE, 0, 0, 0, CPU_MMX, CPU_P3, 0}, + {"lcallq", ljmpcall_insn, 7, SUF_Q, 0x03, 0x9A, 0, ONLY_64, 0, 0, 0}, + {"vpextrb", pextrb_insn, 3, SUF_Z, 0xC0, 0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"fchs", twobyte_insn, 1, SUF_Z, 0xD9, 0xE0, 0, 0, CPU_FPU, 0, 0}, + {"cmovnbeq", cmovcc_insn, 3, SUF_Q, 0x07, 0, 0, ONLY_64, CPU_686, 0, 0}, + {"sha1msg2", intel_SHA1MSG2_insn, 1, SUF_Z, 0, 0, 0, 0, CPU_SHA, 0, 0}, + {"vpaddusb", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0xDC, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"faddp", farithp_insn, 3, SUF_Z, 0xC0, 0, 0, 0, CPU_FPU, 0, 0}, + {"cmovnbe", cmovcc_insn, 3, SUF_Z, 0x07, 0, 0, 0, CPU_686, 0, 0}, + {"psrldq", pslrldq_insn, 4, SUF_Z, 0x03, 0, 0, 0, CPU_SSE2, 0, 0}, + {"movswl", movszx_insn, 5, SUF_W, 0xBE, 0, 0, 0, CPU_386, 0, 0}, + {"outsw", onebyte_insn, 1, SUF_Z, 0x6F, 0x10, 0, 0, 0, 0, 0}, + {"vpminud", ssse3_insn, 5, SUF_Z, 0x3B, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"aesimc", aesimc_insn, 1, SUF_Z, 0x38, 0xDB, 0, 0, CPU_AES, 0, 0}, + {"movsd", movsd_insn, 5, SUF_Z, 0, 0, 0, 0, CPU_386, 0, 0}, + {"fistpq", fildstp_insn, 4, SUF_Q, 0x03, 0x02, 0x07, 0, CPU_FPU, 0, 0}, + {"loopnzq", loopq_insn, 4, SUF_Z, 0x00, 0x40, 0, ONLY_64, 0, 0, 0}, + {"vcmpngt_uqps", ssecmp_128_insn, 3, SUF_Z, 0x1A, 0x00, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"setsb", setcc_insn, 1, SUF_B, 0x08, 0, 0, 0, CPU_386, 0, 0}, + {"vpsignw", ssse3_insn, 5, SUF_Z, 0x09, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"scasl", onebyte_insn, 1, SUF_Z, 0xAF, 0x20, 0, 0, CPU_386, 0, 0}, + {"addb", arith_insn, 22, SUF_B, 0x00, 0x00, 0, 0, 0, 0, 0}, + {"jnc", jcc_insn, 9, SUF_Z, 0x03, 0, 0, 0, 0, 0, 0}, + {"cmpeqsd", ssecmp_64_insn, 4, SUF_Z, 0x00, 0xF2, 0, 0, CPU_SSE2, 0, 0}, + {"maxss", xmm_xmm32_insn, 4, SUF_Z, 0xF3, 0x5F, 0, 0, CPU_SSE, 0, 0}, + {"lodsl", onebyte_insn, 1, SUF_Z, 0xAD, 0x20, 0, 0, CPU_386, 0, 0}, + {"lahf", onebyte_insn, 1, SUF_Z, 0x9F, 0, 0, 0, 0, 0, 0}, + {"setp", setcc_insn, 1, SUF_Z, 0x0A, 0, 0, 0, CPU_386, 0, 0}, + {"vpunpcklwd", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0x61, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vmwritel", vmxmemwr_insn, 2, SUF_L, 0, 0, 0, NOT_64, CPU_P4, 0, 0}, + {"blendps", sse4imm_insn, 2, SUF_Z, 0x0C, 0, 0, 0, CPU_SSE41, 0, 0}, + {"vmcall", threebyte_insn, 1, SUF_Z, 0x0F, 0x01, 0xC1, 0, CPU_P4, 0, 0}, + {"pushq", push_insn, 35, SUF_Q, 0, 0, 0, ONLY_64, 0, 0, 0}, + {"vcmpnleps", ssecmp_128_insn, 3, SUF_Z, 0x06, 0x00, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpcomtrueuw", vpcom_insn, 1, SUF_Z, 0xED, 0x07, 0, 0, CPU_XOP, 0, 0}, + {"pmuldq", sse4_insn, 2, SUF_Z, 0x28, 0, 0, 0, CPU_SSE41, 0, 0}, + {"cmpl", arith_insn, 22, SUF_L, 0x38, 0x07, 0, 0, CPU_386, 0, 0}, + {"pfmin", now3d_insn, 1, SUF_Z, 0x94, 0, 0, 0, CPU_3DNow, 0, 0}, + {"fldpi", twobyte_insn, 1, SUF_Z, 0xD9, 0xEB, 0, 0, CPU_FPU, 0, 0}, + {"vcvtsi2sdl", cvt_xmm_rmx_insn, 6, SUF_L, 0xF2, 0x2A, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpsraw", vpshift_insn, 8, SUF_Z, 0xE1, 0x71, 0x04, ONLY_AVX, CPU_AVX, 0, 0}, + {"vcvtps2ph", avx_cvtps2ph_insn, 4, SUF_Z, 0x66, 0x1D, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"subq", arith_insn, 22, SUF_Q, 0x28, 0x05, 0, ONLY_64, 0, 0, 0}, + {"fsubrs", farith_insn, 7, SUF_S, 0xE0, 0xE8, 0x05, 0, CPU_FPU, 0, 0}, + {"xchgq", xchg_insn, 16, SUF_Q, 0, 0, 0, ONLY_64, 0, 0, 0}, + {"cmovsq", cmovcc_insn, 3, SUF_Q, 0x08, 0, 0, ONLY_64, CPU_686, 0, 0}, + {"shldq", shlrd_insn, 9, SUF_Q, 0xA4, 0, 0, ONLY_64, CPU_386, 0, 0}, + {"leaveq", onebyte_insn, 1, SUF_Z, 0xC9, 0x00, 0x40, ONLY_64, 0, 0, 0}, + {"stc", onebyte_insn, 1, SUF_Z, 0xF9, 0, 0, 0, 0, 0, 0}, + {"fsave", twobytemem_insn, 1, SUF_Z, 0x06, 0x9B, 0xDD, 0, CPU_FPU, 0, 0}, + {"rclb", shift_insn, 16, SUF_B, 0x02, 0, 0, 0, 0, 0, 0}, + {"fisubrl", fiarith_insn, 2, SUF_L, 0x05, 0xDA, 0, 0, CPU_FPU, 0, 0}, + {"vpsrlvd", vpshiftv_vexw0_avx2_insn, 2, SUF_Z, 0x45, 0, 0, ONLY_AVX, CPU_AVX2, 0, 0}, + {"fstenvl", twobytemem_insn, 1, SUF_L, 0x06, 0x9B, 0xD9, 0, CPU_FPU, 0, 0}, + {"paddsb", mmxsse2_insn, 2, SUF_Z, 0xEC, 0, 0, 0, CPU_MMX, 0, 0}, + {"vmwriteq", vmxmemwr_insn, 2, SUF_Q, 0, 0, 0, ONLY_64, CPU_P4, 0, 0}, + {"ud2", twobyte_insn, 1, SUF_Z, 0x0F, 0x0B, 0, 0, CPU_286, 0, 0}, + {"vfmaddsub132pd", vfma_pd_insn, 2, SUF_Z, 0x96, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"sti", onebyte_insn, 1, SUF_Z, 0xFB, 0, 0, 0, 0, 0, 0}, + {"shld", shlrd_insn, 9, SUF_Z, 0xA4, 0, 0, 0, CPU_386, 0, 0}, + {"vpabsd", avx2_ssse3_2op_insn, 2, SUF_Z, 0x1E, 0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"mwait", threebyte_insn, 1, SUF_Z, 0x0F, 0x01, 0xC9, 0, CPU_SSE3, 0, 0}, + {"cvtsi2sd", cvt_xmm_rmx_insn, 6, SUF_Z, 0xF2, 0x2A, 0, 0, CPU_SSE2, 0, 0}, + {"cmovnp", cmovcc_insn, 3, SUF_Z, 0x0B, 0, 0, 0, CPU_686, 0, 0}, + {"vcvtpd2dq", avx_cvt_xmm128_insn, 2, SUF_Z, 0xF2, 0xE6, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"pmovsxbw", sse4m64_insn, 4, SUF_Z, 0x20, 0, 0, 0, CPU_SSE41, 0, 0}, + {"fisubl", fiarith_insn, 2, SUF_L, 0x04, 0xDA, 0, 0, CPU_FPU, 0, 0}, + {"daa", onebyte_insn, 1, SUF_Z, 0x27, 0, 0, NOT_64, 0, 0, 0}, + {"fdivrl", farith_insn, 7, SUF_L, 0xF0, 0xF8, 0x07, 0, CPU_FPU, 0, 0}, + {"stac", threebyte_insn, 1, SUF_Z, 0x0F, 0x01, 0xCB, 0, CPU_SMAP, 0, 0}, + {"testw", test_insn, 20, SUF_W, 0, 0, 0, 0, 0, 0, 0}, + {"movzwl", movszx_insn, 5, SUF_W, 0xB6, 0, 0, 0, CPU_386, 0, 0}, + {"vpblendw", sse4imm_256avx2_insn, 4, SUF_Z, 0x0E, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpcomgtuq", vpcom_insn, 1, SUF_Z, 0xEF, 0x02, 0, 0, CPU_XOP, 0, 0}, + {"setnaeb", setcc_insn, 1, SUF_B, 0x02, 0, 0, 0, CPU_386, 0, 0}, + {"pextrwq", pextrw_insn, 7, SUF_Q, 0, 0, 0, ONLY_64, CPU_MMX, CPU_P3, 0}, + {"lodsq", onebyte_insn, 1, SUF_Z, 0xAD, 0x40, 0, ONLY_64, 0, 0, 0}, + {"fincstp", twobyte_insn, 1, SUF_Z, 0xD9, 0xF7, 0, 0, CPU_FPU, 0, 0}, + {"cmovlew", cmovcc_insn, 3, SUF_W, 0x0E, 0, 0, 0, CPU_686, 0, 0}, + {"insertq", insertq_insn, 2, SUF_Z, 0, 0, 0, 0, CPU_SSE4a, 0, 0}, + {"notl", f6_insn, 4, SUF_L, 0x02, 0, 0, 0, CPU_386, 0, 0}, + {"vfnmadd132sd", vfma_sd_insn, 2, SUF_Z, 0x9D, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"cmova", cmovcc_insn, 3, SUF_Z, 0x07, 0, 0, 0, CPU_686, 0, 0}, + {"fstcw", fstcw_insn, 1, SUF_Z, 0, 0, 0, 0, CPU_FPU, 0, 0}, + {"vpclmullqhqdq", pclmulqdq_fixed_insn, 2, SUF_Z, 0x10, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"movnti", movnti_insn, 2, SUF_Z, 0, 0, 0, 0, CPU_P4, 0, 0}, + {"packusdw", sse4_insn, 2, SUF_Z, 0x2B, 0, 0, 0, CPU_SSE41, 0, 0}, + {"punpckhqdq", xmm_xmm128_insn, 2, SUF_Z, 0x66, 0x6D, 0, 0, CPU_SSE2, 0, 0}, + {"lzcntw", cnt_insn, 3, SUF_W, 0xBD, 0, 0, 0, CPU_LZCNT, 0, 0}, + {"pcmpistri", sse4pcmpstr_insn, 1, SUF_Z, 0x63, 0, 0, 0, CPU_SSE42, 0, 0}, + {"fimull", fiarith_insn, 2, SUF_L, 0x01, 0xDA, 0, 0, CPU_FPU, 0, 0}, + {"fnstenv", onebytemem_insn, 1, SUF_Z, 0x06, 0xD9, 0, 0, CPU_FPU, 0, 0}, + {"cmovncw", cmovcc_insn, 3, SUF_W, 0x03, 0, 0, 0, CPU_686, 0, 0}, + {"leaw", lea_insn, 3, SUF_W, 0, 0, 0, 0, 0, 0, 0}, + {"vfmadd132ss", vfma_ss_insn, 2, SUF_Z, 0x99, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"pshufd", xmm_xmm128_imm_insn, 1, SUF_Z, 0x66, 0x70, 0, 0, CPU_SSE2, 0, 0}, + {"blsil", vex_gpr_ndd_rm_0F38_regext_insn, 2, SUF_L, 0x00, 0xF3, 0x03, ONLY_AVX, CPU_BMI1, 0, 0}, + {"stosl", onebyte_insn, 1, SUF_Z, 0xAB, 0x20, 0, 0, CPU_386, 0, 0}, + {"mulq", f6_insn, 4, SUF_Q, 0x04, 0, 0, ONLY_64, 0, 0, 0}, + {"cmovbl", cmovcc_insn, 3, SUF_L, 0x02, 0, 0, 0, CPU_686, 0, 0}, + {"vpmaxsd", ssse3_insn, 5, SUF_Z, 0x3D, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"rsqrtps", xmm_xmm128_insn, 2, SUF_Z, 0x00, 0x52, 0, 0, CPU_SSE, 0, 0}, + {"ror", shift_insn, 16, SUF_Z, 0x01, 0, 0, 0, 0, 0, 0}, + {"vcmptrue_usss", ssecmp_32_insn, 4, SUF_Z, 0x1F, 0xF3, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpermq", vperm_imm_avx2_insn, 1, SUF_Z, 0x00, 0, 0, ONLY_AVX, CPU_AVX2, 0, 0}, + {"xcryptofb", padlock_insn, 1, SUF_Z, 0xE8, 0xF3, 0xA7, 0, CPU_PadLock, 0, 0}, + {"btsl", bittest_insn, 6, SUF_L, 0xAB, 0x05, 0, 0, CPU_386, 0, 0}, + {"vfnmsub213ps", vfma_ps_insn, 2, SUF_Z, 0xAE, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"stmxcsr", ldstmxcsr_insn, 1, SUF_Z, 0x03, 0, 0, 0, CPU_SSE, 0, 0}, + {"vzeroupper", vzero_insn, 1, SUF_Z, 0xC0, 0, 0, 0, CPU_AVX, 0, 0}, + {"adcx", vex_gpr_ndd_rm_0F38_insn, 2, SUF_Z, 0x66, 0xF6, 0, 0, CPU_ADX, 0, 0}, + {"setnz", setcc_insn, 1, SUF_Z, 0x05, 0, 0, 0, CPU_386, 0, 0}, + {"fildl", fildstp_insn, 4, SUF_L, 0x00, 0x02, 0x05, 0, CPU_FPU, 0, 0}, + {"movlps", movhlp_insn, 3, SUF_Z, 0x00, 0x12, 0, 0, CPU_SSE, 0, 0}, + {"vmovmskpdq", movmsk_insn, 4, SUF_Q, 0x66, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"cmovngw", cmovcc_insn, 3, SUF_W, 0x0E, 0, 0, 0, CPU_686, 0, 0}, + {"cltd", onebyte_insn, 1, SUF_Z, 0x99, 0x20, 0, 0, CPU_386, 0, 0}, + {"fmuls", farith_insn, 7, SUF_S, 0xC8, 0xC8, 0x01, 0, CPU_FPU, 0, 0}, + {"fcom", fcom_insn, 6, SUF_Z, 0xD0, 0x02, 0, 0, CPU_FPU, 0, 0}, + {"andq", arith_insn, 22, SUF_Q, 0x20, 0x04, 0, ONLY_64, 0, 0, 0}, + {"vfmaddps", fma_128_256_insn, 4, SUF_Z, 0x68, 0, 0, ONLY_AVX, CPU_FMA4, 0, 0}, + {"fst", fst_insn, 3, SUF_Z, 0, 0, 0, 0, CPU_FPU, 0, 0}, + {"vmaskmovpd", vmaskmov_insn, 4, SUF_Z, 0x2D, 0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"cld", onebyte_insn, 1, SUF_Z, 0xFC, 0, 0, 0, 0, 0, 0}, + {"vpinsrd", pinsrd_insn, 2, SUF_Z, 0xC0, 0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"xchgl", xchg_insn, 16, SUF_L, 0, 0, 0, 0, 0, 0, 0}, + {"vcmpgtpd", ssecmp_128_insn, 3, SUF_Z, 0x0E, 0x66, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"cmovael", cmovcc_insn, 3, SUF_L, 0x03, 0, 0, 0, CPU_686, 0, 0}, + {"phaddsw", ssse3_insn, 5, SUF_Z, 0x03, 0, 0, 0, CPU_SSSE3, 0, 0}, + {"pclmullqlqdq", pclmulqdq_fixed_insn, 2, SUF_Z, 0x00, 0, 0, 0, CPU_AVX, 0, 0}, + {"cmovnleq", cmovcc_insn, 3, SUF_Q, 0x0F, 0, 0, ONLY_64, CPU_686, 0, 0}, + {"pcmpeqb", mmxsse2_insn, 2, SUF_Z, 0x74, 0, 0, 0, CPU_MMX, 0, 0}, + {"word", NULL, X86_OPERSIZE>>8, 0x10, 0, 0, 0, 0, 0, 0, 0}, + {"blcmskq", xop_gpr_reg_rm_09_insn, 2, SUF_Q, 0x02, 0x01, 0, ONLY_64, CPU_TBM, 0, 0}, + {"vpcomgtud", vpcom_insn, 1, SUF_Z, 0xEE, 0x02, 0, 0, CPU_XOP, 0, 0}, + {"fsubr", farith_insn, 7, SUF_Z, 0xE0, 0xE8, 0x05, 0, CPU_FPU, 0, 0}, + {"cmovp", cmovcc_insn, 3, SUF_Z, 0x0A, 0, 0, 0, CPU_686, 0, 0}, + {"shrq", shift_insn, 16, SUF_Q, 0x05, 0, 0, ONLY_64, 0, 0, 0}, + {"vpcomgtd", vpcom_insn, 1, SUF_Z, 0xCE, 0x02, 0, 0, CPU_XOP, 0, 0}, + {"vfnmsub132sd", vfma_sd_insn, 2, SUF_Z, 0x9F, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"vpor", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0xEB, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"psllw", pshift_insn, 4, SUF_Z, 0xF1, 0x71, 0x06, 0, CPU_MMX, 0, 0}, + {"fbld", fbldstp_insn, 1, SUF_Z, 0x04, 0, 0, 0, CPU_FPU, 0, 0}, + {"subw", arith_insn, 22, SUF_W, 0x28, 0x05, 0, 0, 0, 0, 0}, + {"vmovhlps", movhllhps_insn, 2, SUF_Z, 0x12, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"cmovleq", cmovcc_insn, 3, SUF_Q, 0x0E, 0, 0, ONLY_64, CPU_686, 0, 0}, + {"imulw", imul_insn, 19, SUF_W, 0, 0, 0, 0, 0, 0, 0}, + {"cvttss2siq", cvt_rx_xmm32_insn, 4, SUF_Q, 0xF3, 0x2C, 0, ONLY_64, CPU_SSE, 0, 0}, + {"vgatherqpd", gather_64x_64y_insn, 2, SUF_Z, 0x93, 0, 0, ONLY_AVX, CPU_AVX2, 0, 0}, + {"imulq", imul_insn, 19, SUF_Q, 0, 0, 0, ONLY_64, 0, 0, 0}, + {"ret", retnf_insn, 6, SUF_Z, 0xC2, 0, 0, 0, 0, 0, 0}, + {"vphminposuw", avx_ssse3_2op_insn, 1, SUF_Z, 0x41, 0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"cmpneqsd", ssecmp_64_insn, 4, SUF_Z, 0x04, 0xF2, 0, 0, CPU_SSE2, 0, 0}, + {"jae", jcc_insn, 9, SUF_Z, 0x03, 0, 0, 0, 0, 0, 0}, + {"vpavgb", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0xE0, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"cwtd", onebyte_insn, 1, SUF_Z, 0x99, 0x10, 0, 0, 0, 0, 0}, + {"movddup", xmm_xmm64_insn, 4, SUF_Z, 0xF2, 0x12, 0, 0, CPU_SSE3, 0, 0}, + {"vpcomud", vpcom_imm_insn, 1, SUF_Z, 0xEE, 0, 0, 0, CPU_XOP, 0, 0}, + {"vpmovzxwd", sse4m64_insn, 4, SUF_Z, 0x33, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vfnmsubss", fma_128_m32_insn, 3, SUF_Z, 0x7E, 0, 0, ONLY_AVX, CPU_FMA4, 0, 0}, + {"cmovgew", cmovcc_insn, 3, SUF_W, 0x0D, 0, 0, 0, CPU_686, 0, 0}, + {"bzhi", vex_gpr_reg_rm_nds_0F_insn, 2, SUF_Z, 0x00, 0x38, 0xF5, ONLY_AVX, CPU_BMI2, 0, 0}, + {"setab", setcc_insn, 1, SUF_B, 0x07, 0, 0, 0, CPU_386, 0, 0}, + {"rsqrtss", xmm_xmm32_insn, 4, SUF_Z, 0xF3, 0x52, 0, 0, CPU_SSE, 0, 0}, + {"vfmaddsub213pd", vfma_pd_insn, 2, SUF_Z, 0xA6, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"montmul", padlock_insn, 1, SUF_Z, 0xC0, 0xF3, 0xA6, 0, CPU_PadLock, 0, 0}, + {"rcrq", shift_insn, 16, SUF_Q, 0x03, 0, 0, ONLY_64, 0, 0, 0}, + {"vpaddsb", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0xEC, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vbroadcastss", vbroadcastss_insn, 4, SUF_Z, 0, 0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"cmovnz", cmovcc_insn, 3, SUF_Z, 0x05, 0, 0, 0, CPU_686, 0, 0}, + {"cmpxchgw", cmpxchgxadd_insn, 4, SUF_W, 0xB0, 0, 0, 0, CPU_486, 0, 0}, + {"fcompp", twobyte_insn, 1, SUF_Z, 0xDE, 0xD9, 0, 0, CPU_FPU, 0, 0}, + {"vpshab", amd_vpshift_insn, 2, SUF_Z, 0x98, 0, 0, 0, CPU_XOP, 0, 0}, + {"vaddpd", xmm_xmm128_256_insn, 4, SUF_Z, 0x66, 0x58, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vcvtsi2ssq", cvt_xmm_rmx_insn, 6, SUF_Q, 0xF3, 0x2A, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"clc", onebyte_insn, 1, SUF_Z, 0xF8, 0, 0, 0, 0, 0, 0}, + {"cmovlw", cmovcc_insn, 3, SUF_W, 0x0C, 0, 0, 0, CPU_686, 0, 0}, + {"lgdt", twobytemem_insn, 1, SUF_Z, 0x02, 0x0F, 0x01, 0, CPU_286, CPU_Priv, 0}, + {"getsec", twobyte_insn, 1, SUF_Z, 0x0F, 0x37, 0, 0, CPU_SMX, 0, 0}, + {"blsrl", vex_gpr_ndd_rm_0F38_regext_insn, 2, SUF_L, 0x00, 0xF3, 0x01, ONLY_AVX, CPU_BMI1, 0, 0}, + {"vpsignb", ssse3_insn, 5, SUF_Z, 0x08, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"pblendw", sse4imm_insn, 2, SUF_Z, 0x0E, 0, 0, 0, CPU_SSE41, 0, 0}, + {"vmovlhps", movhllhps_insn, 2, SUF_Z, 0x16, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"svdc", svdc_insn, 1, SUF_Z, 0, 0, 0, 0, CPU_486, CPU_Cyrix, CPU_SMM}, + {"vmovlpd", movhlp_insn, 3, SUF_Z, 0x66, 0x12, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vdppd", sse4imm_insn, 2, SUF_Z, 0x41, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"xbegin", tsx_xbegin_insn, 2, SUF_Z, 0, 0, 0, 0, CPU_386, CPU_TSX, 0}, + {"sldtq", sldtmsw_insn, 6, SUF_Q, 0x00, 0x00, 0, ONLY_64, CPU_286, 0, 0}, + {"vpcmpeqb", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0x74, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"cmpnless", ssecmp_32_insn, 4, SUF_Z, 0x06, 0xF3, 0, 0, CPU_SSE, 0, 0}, + {"fprem1", twobyte_insn, 1, SUF_Z, 0xD9, 0xF5, 0, 0, CPU_286, CPU_FPU, 0}, + {"lssl", lfgss_insn, 3, SUF_L, 0xB2, 0, 0, 0, CPU_386, 0, 0}, + {"inw", in_insn, 12, SUF_W, 0, 0, 0, 0, 0, 0, 0}, + {"bzhiq", vex_gpr_reg_rm_nds_0F_insn, 2, SUF_Q, 0x00, 0x38, 0xF5, ONLY_64|ONLY_AVX, CPU_BMI2, 0, 0}, + {"pop", pop_insn, 23, SUF_Z, 0, 0, 0, 0, 0, 0, 0}, + {"vblendps", sse4imm_256_insn, 4, SUF_Z, 0x0C, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"flds", fld_insn, 4, SUF_S, 0, 0, 0, 0, CPU_FPU, 0, 0}, + {"movsxw", movszx_insn, 5, SUF_W, 0xBE, 0, 0, 0, CPU_386, 0, 0}, + {"movabsw", movabs_insn, 9, SUF_W, 0, 0, 0, ONLY_64, 0, 0, 0}, + {"divps", xmm_xmm128_insn, 2, SUF_Z, 0x00, 0x5E, 0, 0, CPU_SSE, 0, 0}, + {"vpcomfalseb", vpcom_insn, 1, SUF_Z, 0xCC, 0x06, 0, 0, CPU_XOP, 0, 0}, + {"vcmpsd", cmpsd_insn, 5, SUF_Z, 0xC0, 0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpcmpgtq", ssse3_insn, 5, SUF_Z, 0x37, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"setbb", setcc_insn, 1, SUF_B, 0x02, 0, 0, 0, CPU_386, 0, 0}, + {"shrw", shift_insn, 16, SUF_W, 0x05, 0, 0, 0, 0, 0, 0}, + {"andpd", xmm_xmm128_insn, 2, SUF_Z, 0x66, 0x54, 0, 0, CPU_SSE2, 0, 0}, + {"vaesdeclast", aes_insn, 2, SUF_Z, 0x38, 0xDF, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"testb", test_insn, 20, SUF_B, 0, 0, 0, 0, 0, 0, 0}, + {"vfmsub231ss", vfma_ss_insn, 2, SUF_Z, 0xBB, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"rexxz", NULL, X86_REX>>8, 0x45, 0, 0, 0, ONLY_64, 0, 0, 0}, + {"cmpnlepd", ssecmp_128_insn, 3, SUF_Z, 0x06, 0x66, 0, 0, CPU_SSE, 0, 0}, + {"lidt", twobytemem_insn, 1, SUF_Z, 0x03, 0x0F, 0x01, 0, CPU_286, CPU_Priv, 0}, + {"vfmsubps", fma_128_256_insn, 4, SUF_Z, 0x6C, 0, 0, ONLY_AVX, CPU_FMA4, 0, 0}, + {"svldt", cyrixsmm_insn, 1, SUF_Z, 0x7A, 0, 0, 0, CPU_486, CPU_Cyrix, CPU_SMM}, + {"rclw", shift_insn, 16, SUF_W, 0x02, 0, 0, 0, 0, 0, 0}, + {"vphsubbw", vphaddsub_insn, 1, SUF_Z, 0xE1, 0, 0, 0, CPU_XOP, 0, 0}, + {"vcmpnge_uqss", ssecmp_32_insn, 4, SUF_Z, 0x19, 0xF3, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"movswq", movszx_insn, 5, SUF_W, 0xBE, 0, 0, ONLY_64, CPU_386, 0, 0}, + {"blcic", xop_gpr_reg_rm_09_insn, 2, SUF_Z, 0x01, 0x05, 0, 0, CPU_386, CPU_TBM, 0}, + {"setns", setcc_insn, 1, SUF_Z, 0x09, 0, 0, 0, CPU_386, 0, 0}, + {"vcmpneq_oqps", ssecmp_128_insn, 3, SUF_Z, 0x0C, 0x00, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"rorb", shift_insn, 16, SUF_B, 0x01, 0, 0, 0, 0, 0, 0}, + {"vpcomgtuw", vpcom_insn, 1, SUF_Z, 0xED, 0x02, 0, 0, CPU_XOP, 0, 0}, + {"vfmsubss", fma_128_m32_insn, 3, SUF_Z, 0x6E, 0, 0, ONLY_AVX, CPU_FMA4, 0, 0}, + {"vpperm", vpperm_insn, 2, SUF_Z, 0, 0, 0, 0, CPU_XOP, 0, 0}, + {"cmpxchg", cmpxchgxadd_insn, 4, SUF_Z, 0xB0, 0, 0, 0, CPU_486, 0, 0}, + {"setnbeb", setcc_insn, 1, SUF_B, 0x07, 0, 0, 0, CPU_386, 0, 0}, + {"vmovsd", movsd_insn, 5, SUF_Z, 0xC0, 0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vrcpss", xmm_xmm32_insn, 4, SUF_Z, 0xF3, 0x53, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"pmovzxbd", sse4m32_insn, 4, SUF_Z, 0x31, 0, 0, 0, CPU_SSE41, 0, 0}, + {"vroundpd", avx_sse4imm_insn, 3, SUF_Z, 0x09, 0, 0, ONLY_AVX, CPU_SSE41, 0, 0}, + {"popl", pop_insn, 23, SUF_L, 0, 0, 0, NOT_64, CPU_386, 0, 0}, + {"fisttpll", fildstp_insn, 4, SUF_Q, 0x07, 0, 0, 0, CPU_SSE3, 0, 0}, + {"vaddsubpd", xmm_xmm128_256_insn, 4, SUF_Z, 0x66, 0xD0, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vfmadd132ps", vfma_ps_insn, 2, SUF_Z, 0x98, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"blcfill", xop_gpr_reg_rm_09_insn, 2, SUF_Z, 0x01, 0x01, 0, 0, CPU_386, CPU_TBM, 0}, + {"vandnpd", xmm_xmm128_256_insn, 4, SUF_Z, 0x66, 0x55, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"sbbb", arith_insn, 22, SUF_B, 0x18, 0x03, 0, 0, 0, 0, 0}, + {"vcmpfalseps", ssecmp_128_insn, 3, SUF_Z, 0x0B, 0x00, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"popcnt", cnt_insn, 3, SUF_Z, 0xB8, 0, 0, 0, CPU_SSE42, 0, 0}, + {"vpcomnequd", vpcom_insn, 1, SUF_Z, 0xEE, 0x05, 0, 0, CPU_XOP, 0, 0}, + {"adcq", arith_insn, 22, SUF_Q, 0x10, 0x02, 0, ONLY_64, 0, 0, 0}, + {"vpcomequw", vpcom_insn, 1, SUF_Z, 0xED, 0x04, 0, 0, CPU_XOP, 0, 0}, + {"prefetcht1", twobytemem_insn, 1, SUF_Z, 0x02, 0x0F, 0x18, 0, CPU_P3, 0, 0}, + {"movdqa", movau_insn, 6, SUF_Z, 0x66, 0x6F, 0x10, 0, CPU_SSE2, 0, 0}, + {"vmovq", vmovq_insn, 5, SUF_Z, 0, 0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"cmpxchg16b", cmpxchg16b_insn, 1, SUF_Z, 0, 0, 0, ONLY_64, 0, 0, 0}, + {"smovq", onebyte_insn, 1, SUF_Z, 0xA5, 0x40, 0, ONLY_64, 0, 0, 0}, + {"fildq", fildstp_insn, 4, SUF_Q, 0x00, 0x02, 0x05, 0, CPU_FPU, 0, 0}, + {"ficoml", fiarith_insn, 2, SUF_L, 0x02, 0xDA, 0, 0, CPU_FPU, 0, 0}, + {"cmovae", cmovcc_insn, 3, SUF_Z, 0x03, 0, 0, 0, CPU_686, 0, 0}, + {"vaddsd", xmm_xmm64_insn, 4, SUF_Z, 0xF2, 0x58, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"movb", mov_insn, 69, SUF_B, 0, 0, 0, 0, 0, 0, 0}, + {"fist", fiarith_insn, 2, SUF_Z, 0x02, 0xDB, 0, 0, CPU_FPU, 0, 0}, + {"vpcomb", vpcom_imm_insn, 1, SUF_Z, 0xCC, 0, 0, 0, CPU_XOP, 0, 0}, + {"vcmpneq_oqss", ssecmp_32_insn, 4, SUF_Z, 0x0C, 0xF3, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"xorpd", xmm_xmm128_insn, 2, SUF_Z, 0x66, 0x57, 0, 0, CPU_SSE2, 0, 0}, + {"cmpsd", cmpsd_insn, 5, SUF_Z, 0, 0, 0, 0, 0, 0, 0}, + {"movabs", movabs_insn, 9, SUF_Z, 0, 0, 0, ONLY_64, 0, 0, 0}, + {"jrcxz", jcxz_insn, 2, SUF_Z, 0x40, 0, 0, ONLY_64, 0, 0, 0}, + {"vmovhpd", movhlp_insn, 3, SUF_Z, 0x66, 0x16, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"cmovpq", cmovcc_insn, 3, SUF_Q, 0x0A, 0, 0, ONLY_64, CPU_686, 0, 0}, + {"vpsubw", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0xF9, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"smovl", onebyte_insn, 1, SUF_Z, 0xA5, 0x20, 0, 0, CPU_386, 0, 0}, + {"and", arith_insn, 22, SUF_Z, 0x20, 0x04, 0, 0, 0, 0, 0}, + {"andw", arith_insn, 22, SUF_W, 0x20, 0x04, 0, 0, 0, 0, 0}, + {"cmpleps", ssecmp_128_insn, 3, SUF_Z, 0x02, 0, 0, 0, CPU_SSE, 0, 0}, + {"vpmovzxdq", sse4m64_insn, 4, SUF_Z, 0x35, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"subss", xmm_xmm32_insn, 4, SUF_Z, 0xF3, 0x5C, 0, 0, CPU_SSE, 0, 0}, + {"vpcomtrueq", vpcom_insn, 1, SUF_Z, 0xCF, 0x07, 0, 0, CPU_XOP, 0, 0}, + {"fldl2e", twobyte_insn, 1, SUF_Z, 0xD9, 0xEA, 0, 0, CPU_FPU, 0, 0}, + {"negw", f6_insn, 4, SUF_W, 0x03, 0, 0, 0, 0, 0, 0}, + {"fidivl", fiarith_insn, 2, SUF_L, 0x06, 0xDA, 0, 0, CPU_FPU, 0, 0}, + {"setnc", setcc_insn, 1, SUF_Z, 0x03, 0, 0, 0, CPU_386, 0, 0}, + {"clts", twobyte_insn, 1, SUF_Z, 0x0F, 0x06, 0, 0, CPU_286, CPU_Priv, 0}, + {"vcmpgtps", ssecmp_128_insn, 3, SUF_Z, 0x0E, 0x00, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"setnl", setcc_insn, 1, SUF_Z, 0x0D, 0, 0, 0, CPU_386, 0, 0}, + {"vphaddd", ssse3_insn, 5, SUF_Z, 0x02, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpcomneub", vpcom_insn, 1, SUF_Z, 0xEC, 0x05, 0, 0, CPU_XOP, 0, 0}, + {"cmp", arith_insn, 22, SUF_Z, 0x38, 0x07, 0, 0, 0, 0, 0}, + {"fstsww", fstsw_insn, 2, SUF_W, 0, 0, 0, 0, CPU_FPU, 0, 0}, + {"cmpordpd", ssecmp_128_insn, 3, SUF_Z, 0x07, 0x66, 0, 0, CPU_SSE, 0, 0}, + {"punpckhbw", mmxsse2_insn, 2, SUF_Z, 0x68, 0, 0, 0, CPU_MMX, 0, 0}, + {"svts", cyrixsmm_insn, 1, SUF_Z, 0x7C, 0, 0, 0, CPU_486, CPU_Cyrix, CPU_SMM}, + {"cmpq", arith_insn, 22, SUF_Q, 0x38, 0x07, 0, ONLY_64, 0, 0, 0}, + {"cmovbq", cmovcc_insn, 3, SUF_Q, 0x02, 0, 0, ONLY_64, CPU_686, 0, 0}, + {"ficomp", fiarith_insn, 2, SUF_Z, 0x03, 0xDA, 0, 0, CPU_FPU, 0, 0}, + {"vmmcall", threebyte_insn, 1, SUF_Z, 0x0F, 0x01, 0xD9, 0, CPU_SVM, 0, 0}, + {"cqo", onebyte_insn, 1, SUF_Z, 0x99, 0x40, 0, ONLY_64, 0, 0, 0}, + {"vcmpnlepd", ssecmp_128_insn, 3, SUF_Z, 0x06, 0x66, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"setnb", setcc_insn, 1, SUF_Z, 0x03, 0, 0, 0, CPU_386, 0, 0}, + {"vpsllvd", vpshiftv_vexw0_avx2_insn, 2, SUF_Z, 0x47, 0, 0, ONLY_AVX, CPU_AVX2, 0, 0}, + {"vcmplt_oqpd", ssecmp_128_insn, 3, SUF_Z, 0x11, 0x66, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"pextrw", pextrw_insn, 7, SUF_Z, 0, 0, 0, 0, CPU_MMX, CPU_P3, 0}, + {"loopzl", loopl_insn, 4, SUF_Z, 0x01, 0x20, 0, 0, 0, 0, 0}, + {"retq", retnf_insn, 6, SUF_Z, 0xC2, 0, 0, ONLY_64, 0, 0, 0}, + {"vcmpordsd", ssecmp_64_insn, 4, SUF_Z, 0x07, 0xF2, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"seteb", setcc_insn, 1, SUF_B, 0x04, 0, 0, 0, CPU_386, 0, 0}, + {"vmxoff", threebyte_insn, 1, SUF_Z, 0x0F, 0x01, 0xC4, 0, CPU_P4, 0, 0}, + {"pfcmpeq", now3d_insn, 1, SUF_Z, 0xB0, 0, 0, 0, CPU_3DNow, 0, 0}, + {"pmovsxbq", sse4m16_insn, 4, SUF_Z, 0x22, 0, 0, 0, CPU_SSE41, 0, 0}, + {"vfnmadd231ss", vfma_ss_insn, 2, SUF_Z, 0xBD, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"loopel", loopl_insn, 4, SUF_Z, 0x01, 0x20, 0, 0, 0, 0, 0}, + {"pause", onebyte_prefix_insn, 1, SUF_Z, 0xF3, 0x90, 0, 0, CPU_P4, 0, 0}, + {"addps", xmm_xmm128_insn, 2, SUF_Z, 0x00, 0x58, 0, 0, CPU_SSE, 0, 0}, + {"vcmpfalse_ossd", ssecmp_64_insn, 4, SUF_Z, 0x1B, 0xF2, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"rcr", shift_insn, 16, SUF_Z, 0x03, 0, 0, 0, 0, 0, 0}, + {"vfmadd213pd", vfma_pd_insn, 2, SUF_Z, 0xA8, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"xchg", xchg_insn, 16, SUF_Z, 0, 0, 0, 0, 0, 0, 0}, + {"ucomiss", xmm_xmm32_insn, 4, SUF_Z, 0x00, 0x2E, 0, 0, CPU_SSE, 0, 0}, + {"popq", pop_insn, 23, SUF_Q, 0, 0, 0, ONLY_64, 0, 0, 0}, + {"lfsq", lfgss_insn, 3, SUF_Q, 0xB4, 0, 0, ONLY_64, CPU_386, 0, 0}, + {"vcmpneq_usss", ssecmp_32_insn, 4, SUF_Z, 0x14, 0xF3, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"crc32w", crc32_insn, 5, SUF_W, 0, 0, 0, 0, CPU_386, CPU_SSE42, 0}, + {"setngeb", setcc_insn, 1, SUF_B, 0x0C, 0, 0, 0, CPU_386, 0, 0}, + {"vpalignr", sse4imm_256avx2_insn, 4, SUF_Z, 0x0F, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpcomtrueuq", vpcom_insn, 1, SUF_Z, 0xEF, 0x07, 0, 0, CPU_XOP, 0, 0}, + {"pinsrb", pinsrb_insn, 4, SUF_Z, 0, 0, 0, 0, CPU_SSE41, 0, 0}, + {"movshdup", xmm_xmm128_insn, 2, SUF_Z, 0xF3, 0x16, 0, 0, CPU_SSE3, 0, 0}, + {"cmovll", cmovcc_insn, 3, SUF_L, 0x0C, 0, 0, 0, CPU_686, 0, 0}, + {"vpextrd", pextrd_insn, 1, SUF_Z, 0xC0, 0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"lgdtl", twobytemem_insn, 1, SUF_L, 0x02, 0x0F, 0x01, 0, CPU_286, CPU_Priv, 0}, + {"vpblendvb", avx2_sse4xmm0_insn, 2, SUF_Z, 0x4C, 0, 0, ONLY_AVX, CPU_AVX2, 0, 0}, + {"setlb", setcc_insn, 1, SUF_B, 0x0C, 0, 0, 0, CPU_386, 0, 0}, + {"vfmsubadd213ps", vfma_ps_insn, 2, SUF_Z, 0xA7, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"unpckhpd", xmm_xmm128_insn, 2, SUF_Z, 0x66, 0x15, 0, 0, CPU_SSE2, 0, 0}, + {"vpcomfalseud", vpcom_insn, 1, SUF_Z, 0xEE, 0x06, 0, 0, CPU_XOP, 0, 0}, + {"cmovnlq", cmovcc_insn, 3, SUF_Q, 0x0D, 0, 0, ONLY_64, CPU_686, 0, 0}, + {"cmovge", cmovcc_insn, 3, SUF_Z, 0x0D, 0, 0, 0, CPU_686, 0, 0}, + {"movabsb", movabs_insn, 9, SUF_B, 0, 0, 0, ONLY_64, 0, 0, 0}, + {"popa", onebyte_insn, 1, SUF_Z, 0x61, 0x00, 0, NOT_64, CPU_186, 0, 0}, + {"invvpid", eptvpid_insn, 2, SUF_Z, 0x01, 0, 0, 0, CPU_386, CPU_EPTVPID, 0}, + {"vpcomneud", vpcom_insn, 1, SUF_Z, 0xEE, 0x05, 0, 0, CPU_XOP, 0, 0}, + {"blsrq", vex_gpr_ndd_rm_0F38_regext_insn, 2, SUF_Q, 0x00, 0xF3, 0x01, ONLY_64|ONLY_AVX, CPU_BMI1, 0, 0}, + {"ljmpl", ljmpcall_insn, 7, SUF_L, 0x05, 0xEA, 0, 0, CPU_386, 0, 0}, + {"movzx", movszx_insn, 5, SUF_Z, 0xB6, 0, 0, 0, CPU_386, 0, 0}, + {"pi2fd", now3d_insn, 1, SUF_Z, 0x0D, 0, 0, 0, CPU_3DNow, 0, 0}, + {"setng", setcc_insn, 1, SUF_Z, 0x0E, 0, 0, 0, CPU_386, 0, 0}, + {"vpcomfalsed", vpcom_insn, 1, SUF_Z, 0xCE, 0x06, 0, 0, CPU_XOP, 0, 0}, + {"vpabsb", avx2_ssse3_2op_insn, 2, SUF_Z, 0x1C, 0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vcmpgesd", ssecmp_64_insn, 4, SUF_Z, 0x0D, 0xF2, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vfnmaddsd", fma_128_m64_insn, 3, SUF_Z, 0x7B, 0, 0, ONLY_AVX, CPU_FMA4, 0, 0}, + {"rdgsbase", fs_gs_base_insn, 2, SUF_Z, 0x01, 0, 0, ONLY_64, CPU_FSGSBASE, 0, 0}, + {"testl", test_insn, 20, SUF_L, 0, 0, 0, 0, CPU_386, 0, 0}, + {"vsubsd", xmm_xmm64_insn, 4, SUF_Z, 0xF2, 0x5C, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"shrxl", vex_gpr_reg_rm_nds_0F_insn, 2, SUF_L, 0xF2, 0x38, 0xF7, ONLY_AVX, CPU_BMI2, 0, 0}, + {"enter", enter_insn, 3, SUF_Z, 0, 0, 0, 0, CPU_186, 0, 0}, + {"vpmacsdqh", vpma_insn, 1, SUF_Z, 0x9F, 0, 0, 0, CPU_XOP, 0, 0}, + {"vfnmadd213ss", vfma_ss_insn, 2, SUF_Z, 0xAD, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"setaeb", setcc_insn, 1, SUF_B, 0x03, 0, 0, 0, CPU_386, 0, 0}, + {"vpgatherdq", gather_64x_64x_insn, 2, SUF_Z, 0x90, 0, 0, ONLY_AVX, CPU_AVX2, 0, 0}, + {"cmpxchg8b", cmpxchg8b_insn, 1, SUF_Z, 0, 0, 0, 0, CPU_586, 0, 0}, + {"cvttps2pi", cvt_mm_xmm64_insn, 2, SUF_Z, 0x2C, 0, 0, 0, CPU_SSE, 0, 0}, + {"pmovmskb", pmovmskb_insn, 6, SUF_Z, 0, 0, 0, 0, CPU_MMX, CPU_P3, 0}, + {"fdivp", farithp_insn, 3, SUF_Z, 0xF0, 0, 0, 0, CPU_FPU, 0, 0}, + {"vcmpnle_uqsd", ssecmp_64_insn, 4, SUF_Z, 0x16, 0xF2, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"cvtsd2si", cvt_rx_xmm64_insn, 4, SUF_Z, 0xF2, 0x2D, 0, 0, CPU_386, CPU_SSE2, 0}, + {"vpcomgeq", vpcom_insn, 1, SUF_Z, 0xCF, 0x03, 0, 0, CPU_XOP, 0, 0}, + {"vfnmadd132ss", vfma_ss_insn, 2, SUF_Z, 0x9D, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"vpmacssdql", vpma_insn, 1, SUF_Z, 0x87, 0, 0, 0, CPU_XOP, 0, 0}, + {"vpunpcklqdq", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0x6C, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"sysenter", twobyte_insn, 1, SUF_Z, 0x0F, 0x34, 0, NOT_64, CPU_686, 0, 0}, + {"popw", pop_insn, 23, SUF_W, 0, 0, 0, 0, 0, 0, 0}, + {"lodsw", onebyte_insn, 1, SUF_Z, 0xAD, 0x10, 0, 0, 0, 0, 0}, + {"vcmpgt_oqps", ssecmp_128_insn, 3, SUF_Z, 0x1E, 0x00, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"pmovmskbl", pmovmskb_insn, 6, SUF_L, 0, 0, 0, 0, CPU_MMX, CPU_P3, 0}, + {"pinsrq", pinsrq_insn, 2, SUF_Z, 0, 0, 0, ONLY_64, CPU_SSE41, 0, 0}, + {"movsl", onebyte_insn, 1, SUF_Z, 0xA5, 0x20, 0, 0, CPU_386, 0, 0}, + {"vcmptrue_usps", ssecmp_128_insn, 3, SUF_Z, 0x1F, 0x00, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"addr64", NULL, X86_ADDRSIZE>>8, 0x40, 0, 0, 0, ONLY_64, 0, 0, 0}, + {"fsin", twobyte_insn, 1, SUF_Z, 0xD9, 0xFE, 0, 0, CPU_286, CPU_FPU, 0}, + {"adoxl", vex_gpr_ndd_rm_0F38_insn, 2, SUF_L, 0xF3, 0xF6, 0, 0, CPU_ADX, 0, 0}, + {"vpcomnequq", vpcom_insn, 1, SUF_Z, 0xEF, 0x05, 0, 0, CPU_XOP, 0, 0}, + {"pfmax", now3d_insn, 1, SUF_Z, 0xA4, 0, 0, 0, CPU_3DNow, 0, 0}, + {"pfcmpge", now3d_insn, 1, SUF_Z, 0x90, 0, 0, 0, CPU_3DNow, 0, 0}, + {"loopnz", loop_insn, 8, SUF_Z, 0x00, 0, 0, 0, 0, 0, 0}, + {"vcmpnle_uqss", ssecmp_32_insn, 4, SUF_Z, 0x16, 0xF3, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"setpeb", setcc_insn, 1, SUF_B, 0x0A, 0, 0, 0, CPU_386, 0, 0}, + {"vextractps", extractps_insn, 2, SUF_Z, 0xC0, 0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"jc", jcc_insn, 9, SUF_Z, 0x02, 0, 0, 0, 0, 0, 0}, + {"vpcomltq", vpcom_insn, 1, SUF_Z, 0xCF, 0x00, 0, 0, CPU_XOP, 0, 0}, + {"vfmsubsd", fma_128_m64_insn, 3, SUF_Z, 0x6F, 0, 0, ONLY_AVX, CPU_FMA4, 0, 0}, + {"movmskpd", movmsk_insn, 4, SUF_Z, 0x66, 0, 0, 0, CPU_SSE2, 0, 0}, + {"vfmsubadd231ps", vfma_ps_insn, 2, SUF_Z, 0xB7, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"vcmpeq_usps", ssecmp_128_insn, 3, SUF_Z, 0x18, 0x00, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"fistpl", fildstp_insn, 4, SUF_L, 0x03, 0x02, 0x07, 0, CPU_FPU, 0, 0}, + {"fistpll", fbldstp_insn, 1, SUF_Z, 0x07, 0, 0, 0, CPU_FPU, 0, 0}, + {"jnbe", jcc_insn, 9, SUF_Z, 0x07, 0, 0, 0, 0, 0, 0}, + {"pmovsxwq", sse4m32_insn, 4, SUF_Z, 0x24, 0, 0, 0, CPU_SSE41, 0, 0}, + {"vpcomgtub", vpcom_insn, 1, SUF_Z, 0xEC, 0x02, 0, 0, CPU_XOP, 0, 0}, + {"unpcklps", xmm_xmm128_insn, 2, SUF_Z, 0x00, 0x14, 0, 0, CPU_SSE, 0, 0}, + {"btr", bittest_insn, 6, SUF_Z, 0xB3, 0x06, 0, 0, CPU_386, 0, 0}, + {"cmovnsw", cmovcc_insn, 3, SUF_W, 0x09, 0, 0, 0, CPU_686, 0, 0}, + {"sbbl", arith_insn, 22, SUF_L, 0x18, 0x03, 0, 0, CPU_386, 0, 0}, + {"idivq", div_insn, 8, SUF_Q, 0x07, 0, 0, ONLY_64, 0, 0, 0}, + {"strw", str_insn, 4, SUF_W, 0, 0, 0, 0, CPU_286, CPU_Prot, 0}, + {"psignw", ssse3_insn, 5, SUF_Z, 0x09, 0, 0, 0, CPU_SSSE3, 0, 0}, + {"vcvtsi2sdq", cvt_xmm_rmx_insn, 6, SUF_Q, 0xF2, 0x2A, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"setgb", setcc_insn, 1, SUF_B, 0x0F, 0, 0, 0, CPU_386, 0, 0}, + {"vpextrw", pextrw_insn, 7, SUF_Z, 0xC0, 0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"cmoval", cmovcc_insn, 3, SUF_L, 0x07, 0, 0, 0, CPU_686, 0, 0}, + {"vpextrwq", pextrw_insn, 7, SUF_Q, 0xC0, 0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"sldtl", sldtmsw_insn, 6, SUF_L, 0x00, 0x00, 0, 0, CPU_386, 0, 0}, + {"vcmpunordss", ssecmp_32_insn, 4, SUF_Z, 0x03, 0xF3, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"aesenc", aes_insn, 2, SUF_Z, 0x38, 0xDC, 0, 0, CPU_AVX, 0, 0}, + {"pmaddubsw", ssse3_insn, 5, SUF_Z, 0x04, 0, 0, 0, CPU_SSSE3, 0, 0}, + {"cvtsi2ss", cvt_xmm_rmx_insn, 6, SUF_Z, 0xF3, 0x2A, 0, 0, CPU_386, CPU_SSE, 0}, + {"vphaddw", ssse3_insn, 5, SUF_Z, 0x01, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"repnz", NULL, X86_LOCKREP>>8, 0xF2, 0, 0, 0, 0, 0, 0, 0}, + {"fidivrl", fiarith_insn, 2, SUF_L, 0x07, 0xDA, 0, 0, CPU_FPU, 0, 0}, + {"fsqrt", twobyte_insn, 1, SUF_Z, 0xD9, 0xFA, 0, 0, CPU_FPU, 0, 0}, + {"fsetpm", twobyte_insn, 1, SUF_Z, 0xDB, 0xE4, 0, 0, CPU_286, CPU_FPU, CPU_Obs}, + {"insw", onebyte_insn, 1, SUF_Z, 0x6D, 0x10, 0, 0, 0, 0, 0}, + {"setbeb", setcc_insn, 1, SUF_B, 0x06, 0, 0, 0, CPU_386, 0, 0}, + {"vpsubb", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0xF8, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"rex64xy", NULL, X86_REX>>8, 0x4E, 0, 0, 0, ONLY_64, 0, 0, 0}, + {"vpsrldq", pslrldq_insn, 4, SUF_Z, 0x03, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"xorq", arith_insn, 22, SUF_Q, 0x30, 0x06, 0, ONLY_64, 0, 0, 0}, + {"punpcklbw", mmxsse2_insn, 2, SUF_Z, 0x60, 0, 0, 0, CPU_MMX, 0, 0}, + {"rdtscp", threebyte_insn, 1, SUF_Z, 0x0F, 0x01, 0xF9, 0, CPU_686, CPU_AMD, CPU_Priv}, + {"lfence", threebyte_insn, 1, SUF_Z, 0x0F, 0xAE, 0xE8, 0, CPU_P3, 0, 0}, + {"vpcmpestri", sse4pcmpstr_insn, 1, SUF_Z, 0x61, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"divpd", xmm_xmm128_insn, 2, SUF_Z, 0x66, 0x5E, 0, 0, CPU_SSE2, 0, 0}, + {"vcmpss", xmm_xmm32_imm_insn, 4, SUF_Z, 0xF3, 0xC2, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"fidivs", fiarith_insn, 2, SUF_S, 0x06, 0xDA, 0, 0, CPU_FPU, 0, 0}, + {"pcmpeqq", sse4_insn, 2, SUF_Z, 0x29, 0, 0, 0, CPU_SSE41, 0, 0}, + {"setnbe", setcc_insn, 1, SUF_Z, 0x07, 0, 0, 0, CPU_386, 0, 0}, + {"pshufb", ssse3_insn, 5, SUF_Z, 0x00, 0, 0, 0, CPU_SSSE3, 0, 0}, + {"cmovgeq", cmovcc_insn, 3, SUF_Q, 0x0D, 0, 0, ONLY_64, CPU_686, 0, 0}, + {"vpaddq", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0xD4, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"clgi", threebyte_insn, 1, SUF_Z, 0x0F, 0x01, 0xDD, 0, CPU_SVM, 0, 0}, + {"rcpps", xmm_xmm128_insn, 2, SUF_Z, 0x00, 0x53, 0, 0, CPU_SSE, 0, 0}, + {"cmovno", cmovcc_insn, 3, SUF_Z, 0x01, 0, 0, 0, CPU_686, 0, 0}, + {"addss", xmm_xmm32_insn, 4, SUF_Z, 0xF3, 0x58, 0, 0, CPU_SSE, 0, 0}, + {"vcmpneqss", ssecmp_32_insn, 4, SUF_Z, 0x04, 0xF3, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"pavgusb", now3d_insn, 1, SUF_Z, 0xBF, 0, 0, 0, CPU_3DNow, 0, 0}, + {"vfmadd213ps", vfma_ps_insn, 2, SUF_Z, 0xA8, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"vpcomneqw", vpcom_insn, 1, SUF_Z, 0xCD, 0x05, 0, 0, CPU_XOP, 0, 0}, + {"vpmaxsb", ssse3_insn, 5, SUF_Z, 0x3C, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"pminsw", mmxsse2_insn, 2, SUF_Z, 0xEA, 0, 0, 0, CPU_MMX, CPU_P3, 0}, + {"vcmpnge_uqpd", ssecmp_128_insn, 3, SUF_Z, 0x19, 0x66, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpcomtrueud", vpcom_insn, 1, SUF_Z, 0xEE, 0x07, 0, 0, CPU_XOP, 0, 0}, + {"setpe", setcc_insn, 1, SUF_Z, 0x0A, 0, 0, 0, CPU_386, 0, 0}, + {"cmovnlw", cmovcc_insn, 3, SUF_W, 0x0D, 0, 0, 0, CPU_686, 0, 0}, + {"cbw", onebyte_insn, 1, SUF_Z, 0x98, 0x10, 0, 0, 0, 0, 0}, + {"vcmpge_oqss", ssecmp_32_insn, 4, SUF_Z, 0x1D, 0xF3, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"jpo", jcc_insn, 9, SUF_Z, 0x0B, 0, 0, 0, 0, 0, 0}, + {"leavel", onebyte_insn, 1, SUF_Z, 0xC9, 0x00, 0x40, 0, CPU_186, 0, 0}, + {"mpsadbw", sse4imm_insn, 2, SUF_Z, 0x42, 0, 0, 0, CPU_SSE41, 0, 0}, + {"vcvttsd2si", cvt_rx_xmm64_insn, 4, SUF_Z, 0xF2, 0x2C, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vminps", xmm_xmm128_256_insn, 4, SUF_Z, 0x00, 0x5D, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"cmpnleps", ssecmp_128_insn, 3, SUF_Z, 0x06, 0, 0, 0, CPU_SSE, 0, 0}, + {"blendvpd", sse4xmm0_insn, 2, SUF_Z, 0x15, 0, 0, 0, CPU_SSE41, 0, 0}, + {"vaddss", xmm_xmm32_insn, 4, SUF_Z, 0xF3, 0x58, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpcomltuw", vpcom_insn, 1, SUF_Z, 0xED, 0x00, 0, 0, CPU_XOP, 0, 0}, + {"orw", arith_insn, 22, SUF_W, 0x08, 0x01, 0, 0, 0, 0, 0}, + {"adword", NULL, X86_ADDRSIZE>>8, 0x20, 0, 0, 0, 0, 0, 0, 0}, + {"vprotb", vprot_insn, 3, SUF_Z, 0x00, 0, 0, 0, CPU_XOP, 0, 0}, + {"pclmulhqhqdq", pclmulqdq_fixed_insn, 2, SUF_Z, 0x11, 0, 0, 0, CPU_AVX, 0, 0}, + {"shrdq", shlrd_insn, 9, SUF_Q, 0xAC, 0, 0, ONLY_64, CPU_386, 0, 0}, + {"vminss", xmm_xmm32_insn, 4, SUF_Z, 0xF3, 0x5D, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpmaxub", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0xDE, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpcomltud", vpcom_insn, 1, SUF_Z, 0xEE, 0x00, 0, 0, CPU_XOP, 0, 0}, + {"vpaddusw", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0xDD, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"movsq", onebyte_insn, 1, SUF_Z, 0xA5, 0x40, 0, ONLY_64, 0, 0, 0}, + {"subsd", xmm_xmm64_insn, 4, SUF_Z, 0xF2, 0x5C, 0, 0, CPU_SSE2, 0, 0}, + {"vfmaddsubpd", fma_128_256_insn, 4, SUF_Z, 0x5D, 0, 0, ONLY_AVX, CPU_FMA4, 0, 0}, + {"cvtdq2ps", xmm_xmm128_insn, 2, SUF_Z, 0x00, 0x5B, 0, 0, CPU_SSE2, 0, 0}, + {"prefetch", twobytemem_insn, 1, SUF_Z, 0x00, 0x0F, 0x0D, 0, CPU_3DNow, 0, 0}, + {"vaesenc", aes_insn, 2, SUF_Z, 0x38, 0xDC, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"shl", shift_insn, 16, SUF_Z, 0x04, 0, 0, 0, 0, 0, 0}, + {"vcmpunord_spd", ssecmp_128_insn, 3, SUF_Z, 0x13, 0x66, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"bsfw", bsfr_insn, 3, SUF_W, 0xBC, 0, 0, 0, CPU_386, 0, 0}, + {"bswap", bswap_insn, 2, SUF_Z, 0, 0, 0, 0, CPU_486, 0, 0}, + {"vfmadd231sd", vfma_sd_insn, 2, SUF_Z, 0xB9, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"fistps", fildstp_insn, 4, SUF_S, 0x03, 0x02, 0x07, 0, CPU_FPU, 0, 0}, + {"fdivs", farith_insn, 7, SUF_S, 0xF8, 0xF0, 0x06, 0, CPU_FPU, 0, 0}, + {"pextrq", pextrq_insn, 1, SUF_Z, 0, 0, 0, ONLY_64, CPU_SSE41, 0, 0}, + {"adcl", arith_insn, 22, SUF_L, 0x10, 0x02, 0, 0, CPU_386, 0, 0}, + {"vpmacsdql", vpma_insn, 1, SUF_Z, 0x97, 0, 0, 0, CPU_XOP, 0, 0}, + {"vpcomeqq", vpcom_insn, 1, SUF_Z, 0xCF, 0x04, 0, 0, CPU_XOP, 0, 0}, + {"tzmskq", xop_gpr_reg_rm_09_insn, 2, SUF_Q, 0x01, 0x04, 0, ONLY_64, CPU_TBM, 0, 0}, + {"rcl", shift_insn, 16, SUF_Z, 0x02, 0, 0, 0, 0, 0, 0}, + {"vsqrtsd", xmm_xmm64_insn, 4, SUF_Z, 0xF2, 0x51, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"cdqe", onebyte_insn, 1, SUF_Z, 0x98, 0x40, 0, ONLY_64, 0, 0, 0}, + {"negq", f6_insn, 4, SUF_Q, 0x03, 0, 0, ONLY_64, 0, 0, 0}, + {"pextrb", pextrb_insn, 3, SUF_Z, 0, 0, 0, 0, CPU_SSE41, 0, 0}, + {"movzbq", movszx_insn, 5, SUF_B, 0xB6, 0, 0, ONLY_64, CPU_386, 0, 0}, + {"vcmpngtps", ssecmp_128_insn, 3, SUF_Z, 0x0A, 0x00, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpcomgeb", vpcom_insn, 1, SUF_Z, 0xCC, 0x03, 0, 0, CPU_XOP, 0, 0}, + {"lea", lea_insn, 3, SUF_Z, 0, 0, 0, 0, 0, 0, 0}, + {"invd", twobyte_insn, 1, SUF_Z, 0x0F, 0x08, 0, 0, CPU_486, CPU_Priv, 0}, + {"sarxl", vex_gpr_reg_rm_nds_0F_insn, 2, SUF_L, 0xF3, 0x38, 0xF7, ONLY_AVX, CPU_BMI2, 0, 0}, + {"movdqu", movau_insn, 6, SUF_Z, 0xF3, 0x6F, 0x10, 0, CPU_SSE2, 0, 0}, + {"vdivsd", xmm_xmm64_insn, 4, SUF_Z, 0xF2, 0x5E, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"cmpneqpd", ssecmp_128_insn, 3, SUF_Z, 0x04, 0x66, 0, 0, CPU_SSE, 0, 0}, + {"xcryptecb", padlock_insn, 1, SUF_Z, 0xC8, 0xF3, 0xA7, 0, CPU_PadLock, 0, 0}, + {"shll", shift_insn, 16, SUF_L, 0x04, 0, 0, 0, CPU_386, 0, 0}, + {"int", int_insn, 1, SUF_Z, 0, 0, 0, 0, 0, 0, 0}, + {"wrfsbase", fs_gs_base_insn, 2, SUF_Z, 0x02, 0, 0, ONLY_64, CPU_FSGSBASE, 0, 0}, + {"shufps", xmm_xmm128_imm_insn, 1, SUF_Z, 0x00, 0xC6, 0, 0, CPU_SSE, 0, 0}, + {"subpd", xmm_xmm128_insn, 2, SUF_Z, 0x66, 0x5C, 0, 0, CPU_SSE2, 0, 0}, + {"vcvtpd2psy", avx_cvt_xmm128_y_insn, 1, SUF_Z, 0x66, 0x5A, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"cmovnew", cmovcc_insn, 3, SUF_W, 0x05, 0, 0, 0, CPU_686, 0, 0}, + {"crc32", crc32_insn, 5, SUF_Z, 0, 0, 0, 0, CPU_386, CPU_SSE42, 0}, + {"vmovapd", movau_insn, 6, SUF_Z, 0x66, 0x28, 0x01, ONLY_AVX, CPU_AVX, 0, 0}, + {"rdrand", rdrand_insn, 3, SUF_Z, 0x06, 0, 0, 0, CPU_RDRAND, 0, 0}, + {"cmovnbew", cmovcc_insn, 3, SUF_W, 0x07, 0, 0, 0, CPU_686, 0, 0}, + {"invvpidl", eptvpid_insn, 2, SUF_L, 0x01, 0, 0, NOT_64, CPU_386, CPU_EPTVPID, 0}, + {"ljmp", ljmpcall_insn, 7, SUF_Z, 0x05, 0xEA, 0, 0, 0, 0, 0}, + {"vcmpeqpd", ssecmp_128_insn, 3, SUF_Z, 0x00, 0x66, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"popfl", onebyte_insn, 1, SUF_Z, 0x9D, 0x20, 0, NOT_64, CPU_386, 0, 0}, + {"wrgsbase", fs_gs_base_insn, 2, SUF_Z, 0x03, 0, 0, ONLY_64, CPU_FSGSBASE, 0, 0}, + {"lodsb", onebyte_insn, 1, SUF_Z, 0xAC, 0x00, 0, 0, 0, 0, 0}, + {"vcmpgess", ssecmp_32_insn, 4, SUF_Z, 0x0D, 0xF3, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"aesenclast", aes_insn, 2, SUF_Z, 0x38, 0xDD, 0, 0, CPU_AVX, 0, 0}, + {"cmovel", cmovcc_insn, 3, SUF_L, 0x04, 0, 0, 0, CPU_686, 0, 0}, + {"vpsignd", ssse3_insn, 5, SUF_Z, 0x0A, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"stosb", onebyte_insn, 1, SUF_Z, 0xAA, 0x00, 0, 0, 0, 0, 0}, + {"smovb", onebyte_insn, 1, SUF_Z, 0xA4, 0x00, 0, 0, 0, 0, 0}, + {"vcmpeqss", ssecmp_32_insn, 4, SUF_Z, 0x00, 0xF3, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpandn", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0xDF, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vmovmskpsl", movmsk_insn, 4, SUF_L, 0x00, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vmovntps", movnt_insn, 2, SUF_Z, 0x00, 0x2B, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vcvtpd2psx", avx_cvt_xmm128_x_insn, 1, SUF_Z, 0x66, 0x5A, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"cmpordps", ssecmp_128_insn, 3, SUF_Z, 0x07, 0, 0, 0, CPU_SSE, 0, 0}, + {"vpaddd", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0xFE, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"fptan", twobyte_insn, 1, SUF_Z, 0xD9, 0xF2, 0, 0, CPU_FPU, 0, 0}, + {"shldw", shlrd_insn, 9, SUF_W, 0xA4, 0, 0, 0, CPU_386, 0, 0}, + {"outsl", onebyte_insn, 1, SUF_Z, 0x6F, 0x20, 0, 0, CPU_386, 0, 0}, + {"vmovmskpsq", movmsk_insn, 4, SUF_Q, 0x00, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"fldcw", fldnstcw_insn, 1, SUF_Z, 0x05, 0, 0, 0, CPU_FPU, 0, 0}, + {"vcmpord_ssd", ssecmp_64_insn, 4, SUF_Z, 0x17, 0xF2, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vfnmsub231sd", vfma_sd_insn, 2, SUF_Z, 0xBF, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"pmullw", mmxsse2_insn, 2, SUF_Z, 0xD5, 0, 0, 0, CPU_MMX, 0, 0}, + {"jno", jcc_insn, 9, SUF_Z, 0x01, 0, 0, 0, 0, 0, 0}, + {"vprotq", vprot_insn, 3, SUF_Z, 0x03, 0, 0, 0, CPU_XOP, 0, 0}, + {"vcmpneq_ospd", ssecmp_128_insn, 3, SUF_Z, 0x1C, 0x66, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"sarb", shift_insn, 16, SUF_B, 0x07, 0, 0, 0, 0, 0, 0}, + {"aaa", onebyte_insn, 1, SUF_Z, 0x37, 0, 0, NOT_64, 0, 0, 0}, + {"psubd", mmxsse2_insn, 2, SUF_Z, 0xFA, 0, 0, 0, CPU_MMX, 0, 0}, + {"cmovpew", cmovcc_insn, 3, SUF_W, 0x0A, 0, 0, 0, CPU_686, 0, 0}, + {"blci", xop_gpr_reg_rm_09_insn, 2, SUF_Z, 0x02, 0x06, 0, 0, CPU_386, CPU_TBM, 0}, + {"cmpnltsd", ssecmp_64_insn, 4, SUF_Z, 0x05, 0xF2, 0, 0, CPU_SSE2, 0, 0}, + {"rex64x", NULL, X86_REX>>8, 0x4C, 0, 0, 0, ONLY_64, 0, 0, 0}, + {"blsr", vex_gpr_ndd_rm_0F38_regext_insn, 2, SUF_Z, 0x00, 0xF3, 0x01, ONLY_AVX, CPU_BMI1, 0, 0}, + {"vaeskeygenassist", aes_imm_insn, 1, SUF_Z, 0x3A, 0xDF, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"cmpnltss", ssecmp_32_insn, 4, SUF_Z, 0x05, 0xF3, 0, 0, CPU_SSE, 0, 0}, + {"cwde", onebyte_insn, 1, SUF_Z, 0x98, 0x20, 0, 0, CPU_386, 0, 0}, + {"fcmovne", fcmovcc_insn, 1, SUF_Z, 0xDB, 0xC8, 0, 0, CPU_686, CPU_FPU, 0}, + {"sscab", onebyte_insn, 1, SUF_Z, 0xAE, 0x00, 0, 0, 0, 0, 0}, + {"vphaddbq", vphaddsub_insn, 1, SUF_Z, 0xC3, 0, 0, 0, CPU_XOP, 0, 0}, + {"vcvttss2sil", cvt_rx_xmm32_insn, 4, SUF_L, 0xF3, 0x2C, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"roundsd", sse4m64imm_insn, 4, SUF_Z, 0x0B, 0, 0, 0, CPU_SSE41, 0, 0}, + {"pfacc", now3d_insn, 1, SUF_Z, 0xAE, 0, 0, 0, CPU_3DNow, 0, 0}, + {"fsubl", farith_insn, 7, SUF_L, 0xE8, 0xE0, 0x04, 0, CPU_FPU, 0, 0}, + {"invlpg", twobytemem_insn, 1, SUF_Z, 0x07, 0x0F, 0x01, 0, CPU_486, CPU_Priv, 0}, + {"pextl", vex_gpr_reg_nds_rm_0F_insn, 2, SUF_L, 0xF3, 0x38, 0xF5, ONLY_AVX, CPU_BMI2, 0, 0}, + {"fldenvl", onebytemem_insn, 1, SUF_L, 0x04, 0xD9, 0, 0, CPU_FPU, 0, 0}, + {"lretq", retnf_insn, 6, SUF_Q, 0xCA, 0x40, 0, ONLY_64, 0, 0, 0}, + {"addr16", NULL, X86_ADDRSIZE>>8, 0x10, 0, 0, 0, 0, 0, 0, 0}, + {"cmovncl", cmovcc_insn, 3, SUF_L, 0x03, 0, 0, 0, CPU_686, 0, 0}, + {"movzbw", movszx_insn, 5, SUF_B, 0xB6, 0, 0, 0, CPU_386, 0, 0}, + {"pmvlzb", cyrixmmx_insn, 1, SUF_Z, 0x5B, 0, 0, 0, CPU_Cyrix, CPU_MMX, 0}, + {"boundw", bound_insn, 2, SUF_W, 0, 0, 0, NOT_64, CPU_186, 0, 0}, + {"vroundsd", sse4m64imm_insn, 4, SUF_Z, 0x0B, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"loopz", loop_insn, 8, SUF_Z, 0x01, 0, 0, 0, 0, 0, 0}, + {"roundpd", sse4imm_insn, 2, SUF_Z, 0x09, 0, 0, 0, CPU_SSE41, 0, 0}, + {"sfence", threebyte_insn, 1, SUF_Z, 0x0F, 0xAE, 0xF8, 0, CPU_P3, 0, 0}, + {"vpcomgew", vpcom_insn, 1, SUF_Z, 0xCD, 0x03, 0, 0, CPU_XOP, 0, 0}, + {"vpcmpistrm", sse4pcmpstr_insn, 1, SUF_Z, 0x62, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"repz", NULL, X86_LOCKREP>>8, 0xF3, 0, 0, 0, 0, 0, 0, 0}, + {"iretq", onebyte_insn, 1, SUF_Z, 0xCF, 0x40, 0, ONLY_64, 0, 0, 0}, + {"pclmullqhqdq", pclmulqdq_fixed_insn, 2, SUF_Z, 0x10, 0, 0, 0, CPU_AVX, 0, 0}, + {"vcmplt_oqss", ssecmp_32_insn, 4, SUF_Z, 0x11, 0xF3, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vcmpeq_osps", ssecmp_128_insn, 3, SUF_Z, 0x10, 0x00, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"cmpw", arith_insn, 22, SUF_W, 0x38, 0x07, 0, 0, 0, 0, 0}, + {"adox", vex_gpr_ndd_rm_0F38_insn, 2, SUF_Z, 0xF3, 0xF6, 0, 0, CPU_ADX, 0, 0}, + {"rexyz", NULL, X86_REX>>8, 0x43, 0, 0, 0, ONLY_64, 0, 0, 0}, + {"rorxq", vex_gpr_reg_rm_0F_imm8_insn, 2, SUF_Q, 0xF2, 0x3A, 0xF0, ONLY_64|ONLY_AVX, CPU_BMI2, 0, 0}, + {"movsxb", movszx_insn, 5, SUF_B, 0xBE, 0, 0, 0, CPU_386, 0, 0}, + {"paddsw", mmxsse2_insn, 2, SUF_Z, 0xED, 0, 0, 0, CPU_MMX, 0, 0}, + {"lldtw", prot286_insn, 1, SUF_W, 0x02, 0x00, 0, 0, CPU_286, CPU_Priv, CPU_Prot}, + {"vpcomneuw", vpcom_insn, 1, SUF_Z, 0xED, 0x05, 0, 0, CPU_XOP, 0, 0}, + {"vcmpnlesd", ssecmp_64_insn, 4, SUF_Z, 0x06, 0xF2, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vfrczss", vfrczss_insn, 2, SUF_Z, 0, 0, 0, 0, CPU_XOP, 0, 0}, + {"movw", mov_insn, 69, SUF_W, 0, 0, 0, 0, 0, 0, 0}, + {"crc32q", crc32_insn, 5, SUF_Q, 0, 0, 0, ONLY_64, CPU_SSE42, 0, 0}, + {"vextracti128", vextractif128_insn, 1, SUF_Z, 0x39, 0, 0, ONLY_AVX, CPU_AVX2, 0, 0}, + {"subps", xmm_xmm128_insn, 2, SUF_Z, 0x00, 0x5C, 0, 0, CPU_SSE, 0, 0}, + {"inb", in_insn, 12, SUF_B, 0, 0, 0, 0, 0, 0, 0}, + {"vfnmsub231ps", vfma_ps_insn, 2, SUF_Z, 0xBE, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"vphaddubw", vphaddsub_insn, 1, SUF_Z, 0xD1, 0, 0, 0, CPU_XOP, 0, 0}, + {"pmachriw", pmachriw_insn, 1, SUF_Z, 0, 0, 0, 0, CPU_Cyrix, CPU_MMX, 0}, + {"vmpsadbw", sse4imm_256avx2_insn, 4, SUF_Z, 0x42, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"cmovngew", cmovcc_insn, 3, SUF_W, 0x0C, 0, 0, 0, CPU_686, 0, 0}, + {"popcntq", cnt_insn, 3, SUF_Q, 0xB8, 0, 0, ONLY_64, CPU_SSE42, 0, 0}, + {"insertps", insertps_insn, 4, SUF_Z, 0, 0, 0, 0, CPU_SSE41, 0, 0}, + {"cmpxchgl", cmpxchgxadd_insn, 4, SUF_L, 0xB0, 0, 0, 0, CPU_486, 0, 0}, + {"vcomiss", avx_xmm_xmm32_insn, 2, SUF_Z, 0x00, 0x2F, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpcmpgtd", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0x66, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"loopzw", loopw_insn, 4, SUF_Z, 0x01, 0x10, 0, NOT_64, 0, 0, 0}, + {"retw", retnf_insn, 6, SUF_Z, 0xC2, 0x10, 0, 0, 0, 0, 0}, + {"pavgb", mmxsse2_insn, 2, SUF_Z, 0xE0, 0, 0, 0, CPU_MMX, CPU_P3, 0}, + {"loopnel", loopl_insn, 4, SUF_Z, 0x00, 0x20, 0, 0, 0, 0, 0}, + {"vpsrld", vpshift_insn, 8, SUF_Z, 0xD2, 0x72, 0x02, ONLY_AVX, CPU_AVX, 0, 0}, + {"vcvtpd2dqx", avx_cvt_xmm128_x_insn, 1, SUF_Z, 0xF2, 0xE6, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"ficomps", fiarith_insn, 2, SUF_S, 0x03, 0xDA, 0, 0, CPU_FPU, 0, 0}, + {"fisttps", fildstp_insn, 4, SUF_S, 0x01, 0x00, 0x01, 0, CPU_SSE3, 0, 0}, + {"vandpd", xmm_xmm128_256_insn, 4, SUF_Z, 0x66, 0x54, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"haddpd", xmm_xmm128_insn, 2, SUF_Z, 0x66, 0x7C, 0, 0, CPU_SSE3, 0, 0}, + {"bsfl", bsfr_insn, 3, SUF_L, 0xBC, 0, 0, 0, CPU_386, 0, 0}, + {"rolq", shift_insn, 16, SUF_Q, 0x00, 0, 0, ONLY_64, 0, 0, 0}, + {"vcmpneq_ussd", ssecmp_64_insn, 4, SUF_Z, 0x14, 0xF2, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"pinsrwl", pinsrw_insn, 9, SUF_L, 0, 0, 0, 0, CPU_MMX, CPU_P3, 0}, + {"pmovzxwd", sse4m64_insn, 4, SUF_Z, 0x33, 0, 0, 0, CPU_SSE41, 0, 0}, + {"vcmpgt_oqsd", ssecmp_64_insn, 4, SUF_Z, 0x1E, 0xF2, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"pslld", pshift_insn, 4, SUF_Z, 0xF2, 0x72, 0x06, 0, CPU_MMX, 0, 0}, + {"bextr", bextr_insn, 4, SUF_Z, 0, 0, 0, ONLY_AVX, CPU_386, CPU_BMI1, 0}, + {"movsbl", movszx_insn, 5, SUF_B, 0xBE, 0, 0, 0, CPU_386, 0, 0}, + {"vpcomuq", vpcom_imm_insn, 1, SUF_Z, 0xEF, 0, 0, 0, CPU_XOP, 0, 0}, + {"pcmpestrm", sse4pcmpstr_insn, 1, SUF_Z, 0x60, 0, 0, 0, CPU_SSE42, 0, 0}, + {"pfcmpgt", now3d_insn, 1, SUF_Z, 0xA0, 0, 0, 0, CPU_3DNow, 0, 0}, + {"ltrw", prot286_insn, 1, SUF_W, 0x03, 0x00, 0, 0, CPU_286, CPU_Priv, CPU_Prot}, + {"paddusw", mmxsse2_insn, 2, SUF_Z, 0xDD, 0, 0, 0, CPU_MMX, 0, 0}, + {"vpmacsswd", vpma_insn, 1, SUF_Z, 0x86, 0, 0, 0, CPU_XOP, 0, 0}, + {"vfnmsubsd", fma_128_m64_insn, 3, SUF_Z, 0x7F, 0, 0, ONLY_AVX, CPU_FMA4, 0, 0}, + {"loopew", loopw_insn, 4, SUF_Z, 0x01, 0x10, 0, NOT_64, 0, 0, 0}, + {"vmaskmovdqu", maskmovdqu_insn, 1, SUF_Z, 0xC0, 0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"cvtsi2sdq", cvt_xmm_rmx_insn, 6, SUF_Q, 0xF2, 0x2A, 0, ONLY_64, CPU_SSE2, 0, 0}, + {"fisubs", fiarith_insn, 2, SUF_S, 0x04, 0xDA, 0, 0, CPU_FPU, 0, 0}, + {"cmpeqss", ssecmp_32_insn, 4, SUF_Z, 0x00, 0xF3, 0, 0, CPU_SSE, 0, 0}, + {"cqto", onebyte_insn, 1, SUF_Z, 0x99, 0x40, 0, ONLY_64, 0, 0, 0}, + {"vcmpunordpd", ssecmp_128_insn, 3, SUF_Z, 0x03, 0x66, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"setna", setcc_insn, 1, SUF_Z, 0x06, 0, 0, 0, CPU_386, 0, 0}, + {"cvtdq2pd", xmm_xmm64_insn, 4, SUF_Z, 0xF3, 0xE6, 0, 0, CPU_SSE2, 0, 0}, + {"andnpd", xmm_xmm128_insn, 2, SUF_Z, 0x66, 0x55, 0, 0, CPU_SSE2, 0, 0}, + {"vcmpeq_uqps", ssecmp_128_insn, 3, SUF_Z, 0x08, 0x00, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vcvtsi2ss", cvt_xmm_rmx_insn, 6, SUF_Z, 0xF3, 0x2A, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"psrld", pshift_insn, 4, SUF_Z, 0xD2, 0x72, 0x02, 0, CPU_MMX, 0, 0}, + {"outl", out_insn, 12, SUF_L, 0, 0, 0, 0, CPU_386, 0, 0}, + {"vcvttss2siq", cvt_rx_xmm32_insn, 4, SUF_Q, 0xF3, 0x2C, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"paddq", mmxsse2_insn, 2, SUF_Z, 0xD4, 0, 0, 0, CPU_MMX, 0, 0}, + {"cmpneqss", ssecmp_32_insn, 4, SUF_Z, 0x04, 0xF3, 0, 0, CPU_SSE, 0, 0}, + {"vfrczsd", vfrczsd_insn, 2, SUF_Z, 0, 0, 0, 0, CPU_XOP, 0, 0}, + {"xsaveopt64", xsaveopt64_insn, 1, SUF_Z, 0x06, 0x0F, 0xAE, ONLY_64, CPU_XSAVEOPT, 0, 0}, + {"fnstsww", fnstsw_insn, 2, SUF_W, 0, 0, 0, 0, CPU_FPU, 0, 0}, + {"vfmaddss", fma_128_m32_insn, 3, SUF_Z, 0x6A, 0, 0, ONLY_AVX, CPU_FMA4, 0, 0}, + {"fsubs", farith_insn, 7, SUF_S, 0xE8, 0xE0, 0x04, 0, CPU_FPU, 0, 0}, + {"vpshufd", xmm_xmm128_imm_256avx2_insn, 2, SUF_Z, 0x66, 0x70, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"fstpl", fstp_insn, 4, SUF_L, 0, 0, 0, 0, CPU_FPU, 0, 0}, + {"vcmpeq_ussd", ssecmp_64_insn, 4, SUF_Z, 0x18, 0xF2, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"jle", jcc_insn, 9, SUF_Z, 0x0E, 0, 0, 0, 0, 0, 0}, + {"sidtq", twobytemem_insn, 1, SUF_Q, 0x01, 0x0F, 0x01, 0, CPU_286, CPU_Priv, 0}, + {"vpshlb", amd_vpshift_insn, 2, SUF_Z, 0x94, 0, 0, 0, CPU_XOP, 0, 0}, + {"pinsrwq", pinsrw_insn, 9, SUF_Q, 0, 0, 0, ONLY_64, CPU_MMX, CPU_P3, 0}, + {"js", jcc_insn, 9, SUF_Z, 0x08, 0, 0, 0, 0, 0, 0}, + {"andnq", vex_gpr_reg_nds_rm_0F_insn, 2, SUF_Q, 0x00, 0x38, 0xF2, ONLY_64|ONLY_AVX, CPU_BMI1, 0, 0}, + {"cmpsl", onebyte_insn, 1, SUF_Z, 0xA7, 0x20, 0, 0, CPU_386, 0, 0}, + {"vmovlps", movhlp_insn, 3, SUF_Z, 0x00, 0x12, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"pabsd", ssse3_insn, 5, SUF_Z, 0x1E, 0, 0, 0, CPU_SSSE3, 0, 0}, + {"vpcomequd", vpcom_insn, 1, SUF_Z, 0xEE, 0x04, 0, 0, CPU_XOP, 0, 0}, + {"salw", shift_insn, 16, SUF_W, 0x04, 0, 0, 0, 0, 0, 0}, + {"movntss", movntss_insn, 1, SUF_Z, 0, 0, 0, 0, CPU_SSE4a, 0, 0}, + {"movlhps", movhllhps_insn, 2, SUF_Z, 0x16, 0, 0, 0, CPU_SSE, 0, 0}, + {"vcmpltps", ssecmp_128_insn, 3, SUF_Z, 0x01, 0x00, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"cmovoq", cmovcc_insn, 3, SUF_Q, 0x00, 0, 0, ONLY_64, CPU_686, 0, 0}, + {"rex64xz", NULL, X86_REX>>8, 0x4D, 0, 0, 0, ONLY_64, 0, 0, 0}, + {"vfmsubadd132ps", vfma_ps_insn, 2, SUF_Z, 0x97, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"vcmplt_oqsd", ssecmp_64_insn, 4, SUF_Z, 0x11, 0xF2, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"cmovnzl", cmovcc_insn, 3, SUF_L, 0x05, 0, 0, 0, CPU_686, 0, 0}, + {"cvttss2sil", cvt_rx_xmm32_insn, 4, SUF_L, 0xF3, 0x2C, 0, 0, CPU_386, CPU_SSE, 0}, + {"pand", mmxsse2_insn, 2, SUF_Z, 0xDB, 0, 0, 0, CPU_MMX, 0, 0}, + {"packuswb", mmxsse2_insn, 2, SUF_Z, 0x67, 0, 0, 0, CPU_MMX, 0, 0}, + {"rcrw", shift_insn, 16, SUF_W, 0x03, 0, 0, 0, 0, 0, 0}, + {"loadall", twobyte_insn, 1, SUF_Z, 0x0F, 0x07, 0, 0, CPU_386, CPU_Undoc, 0}, + {"vprotd", vprot_insn, 3, SUF_Z, 0x02, 0, 0, 0, CPU_XOP, 0, 0}, + {"popcntl", cnt_insn, 3, SUF_L, 0xB8, 0, 0, 0, CPU_SSE42, 0, 0}, + {"xsave", twobytemem_insn, 1, SUF_Z, 0x04, 0x0F, 0xAE, 0, CPU_386, CPU_XSAVE, 0}, + {"addq", arith_insn, 22, SUF_Q, 0x00, 0x00, 0, ONLY_64, 0, 0, 0}, + {"fldlg2", twobyte_insn, 1, SUF_Z, 0xD9, 0xEC, 0, 0, CPU_FPU, 0, 0}, + {"fwait", onebyte_insn, 1, SUF_Z, 0x9B, 0, 0, 0, CPU_FPU, 0, 0}, + {"cvtsi2sdl", cvt_xmm_rmx_insn, 6, SUF_L, 0xF2, 0x2A, 0, 0, CPU_SSE2, 0, 0}, + {"cmovl", cmovcc_insn, 3, SUF_Z, 0x0C, 0, 0, 0, CPU_686, 0, 0}, + {"rol", shift_insn, 16, SUF_Z, 0x00, 0, 0, 0, 0, 0, 0}, + {"tzmsk", xop_gpr_reg_rm_09_insn, 2, SUF_Z, 0x01, 0x04, 0, 0, CPU_386, CPU_TBM, 0}, + {"loope", loop_insn, 8, SUF_Z, 0x01, 0, 0, 0, 0, 0, 0}, + {"decl", incdec_insn, 6, SUF_L, 0x48, 0x01, 0, 0, CPU_386, 0, 0}, + {"shlb", shift_insn, 16, SUF_B, 0x04, 0, 0, 0, 0, 0, 0}, + {"cmpsw", onebyte_insn, 1, SUF_Z, 0xA7, 0x10, 0, 0, 0, 0, 0}, + {"inc", incdec_insn, 6, SUF_Z, 0x40, 0x00, 0, 0, 0, 0, 0}, + {"vpshlw", amd_vpshift_insn, 2, SUF_Z, 0x95, 0, 0, 0, CPU_XOP, 0, 0}, + {"vpcomneqd", vpcom_insn, 1, SUF_Z, 0xCE, 0x05, 0, 0, CPU_XOP, 0, 0}, + {"vunpckhps", xmm_xmm128_256_insn, 4, SUF_Z, 0x00, 0x15, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"movups", movau_insn, 6, SUF_Z, 0x00, 0x10, 0x01, 0, CPU_SSE, 0, 0}, + {"smint", twobyte_insn, 1, SUF_Z, 0x0F, 0x38, 0, 0, CPU_686, CPU_Cyrix, 0}, + {"addsubpd", xmm_xmm128_insn, 2, SUF_Z, 0x66, 0xD0, 0, 0, CPU_SSE3, 0, 0}, + {"sha1msg1", intel_SHA1MSG1_insn, 1, SUF_Z, 0, 0, 0, 0, CPU_SHA, 0, 0}, + {"pmovzxdq", sse4m64_insn, 4, SUF_Z, 0x35, 0, 0, 0, CPU_SSE41, 0, 0}, + {"vaddps", xmm_xmm128_256_insn, 4, SUF_Z, 0x00, 0x58, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"in", in_insn, 12, SUF_Z, 0, 0, 0, 0, 0, 0, 0}, + {"setnpb", setcc_insn, 1, SUF_B, 0x0B, 0, 0, 0, CPU_386, 0, 0}, + {"sete", setcc_insn, 1, SUF_Z, 0x04, 0, 0, 0, CPU_386, 0, 0}, + {"vcmpnlt_uqsd", ssecmp_64_insn, 4, SUF_Z, 0x15, 0xF2, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vfmsub132sd", vfma_sd_insn, 2, SUF_Z, 0x9B, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"cmovnae", cmovcc_insn, 3, SUF_Z, 0x02, 0, 0, 0, CPU_686, 0, 0}, + {"xcryptcfb", padlock_insn, 1, SUF_Z, 0xE0, 0xF3, 0xA7, 0, CPU_PadLock, 0, 0}, + {"vcvtss2siq", cvt_rx_xmm32_insn, 4, SUF_Q, 0xF3, 0x2D, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"fcmovnb", fcmovcc_insn, 1, SUF_Z, 0xDB, 0xC0, 0, 0, CPU_686, CPU_FPU, 0}, + {"vfmadd213ss", vfma_ss_insn, 2, SUF_Z, 0xA9, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"pushfw", onebyte_insn, 1, SUF_Z, 0x9C, 0x10, 0x40, 0, 0, 0, 0}, + {"vcmpless", ssecmp_32_insn, 4, SUF_Z, 0x02, 0xF3, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"sidtl", twobytemem_insn, 1, SUF_L, 0x01, 0x0F, 0x01, 0, CPU_286, CPU_Priv, 0}, + {"vpcomfalsew", vpcom_insn, 1, SUF_Z, 0xCD, 0x06, 0, 0, CPU_XOP, 0, 0}, + {"xcryptctr", padlock_insn, 1, SUF_Z, 0xD8, 0xF3, 0xA7, 0, CPU_PadLock, 0, 0}, + {"fidiv", fiarith_insn, 2, SUF_Z, 0x06, 0xDA, 0, 0, CPU_FPU, 0, 0}, + {"cvtpi2pd", cvt_xmm_mm_ss_insn, 1, SUF_Z, 0x66, 0x2A, 0, 0, CPU_SSE2, 0, 0}, + {"fxrstorq", twobytemem_insn, 1, SUF_Q, 0x01, 0x0F, 0xAE, 0, CPU_686, CPU_FPU, 0}, + {"aas", onebyte_insn, 1, SUF_Z, 0x3F, 0, 0, NOT_64, 0, 0, 0}, + {"pfrsqrt", now3d_insn, 1, SUF_Z, 0x97, 0, 0, 0, CPU_3DNow, 0, 0}, + {"cmovpeq", cmovcc_insn, 3, SUF_Q, 0x0A, 0, 0, ONLY_64, CPU_686, 0, 0}, + {"vaesenclast", aes_insn, 2, SUF_Z, 0x38, 0xDD, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vmreadl", vmxmemrd_insn, 2, SUF_L, 0, 0, 0, NOT_64, CPU_P4, 0, 0}, + {"vpcomub", vpcom_imm_insn, 1, SUF_Z, 0xEC, 0, 0, 0, CPU_XOP, 0, 0}, + {"movupd", movau_insn, 6, SUF_Z, 0x66, 0x10, 0x01, 0, CPU_SSE2, 0, 0}, + {"btcw", bittest_insn, 6, SUF_W, 0xBB, 0x07, 0, 0, CPU_386, 0, 0}, + {"popfq", onebyte_insn, 1, SUF_Z, 0x9D, 0x40, 0x40, ONLY_64, 0, 0, 0}, + {"pmulhrw", now3d_insn, 1, SUF_Z, 0xB7, 0, 0, 0, CPU_3DNow, 0, 0}, + {"psubsw", mmxsse2_insn, 2, SUF_Z, 0xE9, 0, 0, 0, CPU_MMX, 0, 0}, + {"lsl", larlsl_insn, 6, SUF_Z, 0x03, 0, 0, 0, CPU_286, CPU_Prot, 0}, + {"rdtsc", twobyte_insn, 1, SUF_Z, 0x0F, 0x31, 0, 0, CPU_586, 0, 0}, + {"scasw", onebyte_insn, 1, SUF_Z, 0xAF, 0x10, 0, 0, 0, 0, 0}, + {"pmvnzb", cyrixmmx_insn, 1, SUF_Z, 0x5A, 0, 0, 0, CPU_Cyrix, CPU_MMX, 0}, + {"pmulhw", mmxsse2_insn, 2, SUF_Z, 0xE5, 0, 0, 0, CPU_MMX, 0, 0}, + {"sha1rnds4", intel_SHA1RNDS4_insn, 1, SUF_Z, 0, 0, 0, 0, CPU_SHA, 0, 0}, + {"jb", jcc_insn, 9, SUF_Z, 0x02, 0, 0, 0, 0, 0, 0}, + {"blsi", vex_gpr_ndd_rm_0F38_regext_insn, 2, SUF_Z, 0x00, 0xF3, 0x03, ONLY_AVX, CPU_BMI1, 0, 0}, + {"vfmaddsub213ps", vfma_ps_insn, 2, SUF_Z, 0xA6, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"vpcmpeqw", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0x75, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vfmaddsd", fma_128_m64_insn, 3, SUF_Z, 0x6B, 0, 0, ONLY_AVX, CPU_FMA4, 0, 0}, + {"vcmpordpd", ssecmp_128_insn, 3, SUF_Z, 0x07, 0x66, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpclmulhqhqdq", pclmulqdq_fixed_insn, 2, SUF_Z, 0x11, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"setne", setcc_insn, 1, SUF_Z, 0x05, 0, 0, 0, CPU_386, 0, 0}, + {"pmaddwd", mmxsse2_insn, 2, SUF_Z, 0xF5, 0, 0, 0, CPU_MMX, 0, 0}, + {"vpcomneb", vpcom_insn, 1, SUF_Z, 0xCC, 0x05, 0, 0, CPU_XOP, 0, 0}, + {"pclmulhqlqdq", pclmulqdq_fixed_insn, 2, SUF_Z, 0x01, 0, 0, 0, CPU_AVX, 0, 0}, + {"xaddb", cmpxchgxadd_insn, 4, SUF_B, 0xC0, 0, 0, 0, CPU_486, 0, 0}, + {"cmpps", xmm_xmm128_imm_insn, 1, SUF_Z, 0x00, 0xC2, 0, 0, CPU_SSE, 0, 0}, + {"movntq", movntq_insn, 1, SUF_Z, 0, 0, 0, 0, CPU_SSE, 0, 0}, + {"idivw", div_insn, 8, SUF_W, 0x07, 0, 0, 0, 0, 0, 0}, + {"push", push_insn, 35, SUF_Z, 0, 0, 0, 0, 0, 0, 0}, + {"vfmsub231pd", vfma_pd_insn, 2, SUF_Z, 0xBA, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"test", test_insn, 20, SUF_Z, 0, 0, 0, 0, 0, 0, 0}, + {"pslldq", pslrldq_insn, 4, SUF_Z, 0x07, 0, 0, 0, CPU_SSE2, 0, 0}, + {"sha256rnds2", intel_SHA256RNDS2_insn, 1, SUF_Z, 0, 0, 0, 0, CPU_SHA, 0, 0}, + {"cmovb", cmovcc_insn, 3, SUF_Z, 0x02, 0, 0, 0, CPU_686, 0, 0}, + {"rex64xyz", NULL, X86_REX>>8, 0x4F, 0, 0, 0, ONLY_64, 0, 0, 0}, + {"blcs", xop_gpr_reg_rm_09_insn, 2, SUF_Z, 0x01, 0x03, 0, 0, CPU_386, CPU_TBM, 0}, + {"punpcklwd", mmxsse2_insn, 2, SUF_Z, 0x61, 0, 0, 0, CPU_MMX, 0, 0}, + {"sqrtps", xmm_xmm128_insn, 2, SUF_Z, 0x00, 0x51, 0, 0, CPU_SSE, 0, 0}, + {"cmovnaeq", cmovcc_insn, 3, SUF_Q, 0x02, 0, 0, ONLY_64, CPU_686, 0, 0}, + {"vmread", vmxmemrd_insn, 2, SUF_Z, 0, 0, 0, 0, CPU_P4, 0, 0}, + {"fldz", twobyte_insn, 1, SUF_Z, 0xD9, 0xEE, 0, 0, CPU_FPU, 0, 0}, + {"vpunpckldq", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0x62, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"retl", retnf_insn, 6, SUF_Z, 0xC2, 0, 0, NOT_64, 0, 0, 0}, + {"vlddqu", lddqu_insn, 2, SUF_Z, 0xC0, 0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"loopnzw", loopw_insn, 4, SUF_Z, 0x00, 0x10, 0, NOT_64, 0, 0, 0}, + {"vmaxss", xmm_xmm32_insn, 4, SUF_Z, 0xF3, 0x5F, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"cvttpd2pi", cvt_mm_xmm_insn, 1, SUF_Z, 0x66, 0x2C, 0, 0, CPU_SSE2, 0, 0}, + {"btrl", bittest_insn, 6, SUF_L, 0xB3, 0x06, 0, 0, CPU_386, 0, 0}, + {"cvttsd2si", cvt_rx_xmm64_insn, 4, SUF_Z, 0xF2, 0x2C, 0, 0, CPU_SSE2, 0, 0}, + {"cmovns", cmovcc_insn, 3, SUF_Z, 0x09, 0, 0, 0, CPU_686, 0, 0}, + {"vblendvpd", avx_sse4xmm0_insn, 2, SUF_Z, 0x4B, 0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"fistp", fildstp_insn, 4, SUF_Z, 0x03, 0x02, 0x07, 0, CPU_FPU, 0, 0}, + {"setbe", setcc_insn, 1, SUF_Z, 0x06, 0, 0, 0, CPU_386, 0, 0}, + {"cmpordss", ssecmp_32_insn, 4, SUF_Z, 0x07, 0xF3, 0, 0, CPU_SSE, 0, 0}, + {"vfrczps", vfrc_pdps_insn, 2, SUF_Z, 0x00, 0, 0, 0, CPU_XOP, 0, 0}, + {"sysret", twobyte_insn, 1, SUF_Z, 0x0F, 0x07, 0, 0, CPU_686, CPU_AMD, CPU_Priv}, + {"pfrsqit1", now3d_insn, 1, SUF_Z, 0xA7, 0, 0, 0, CPU_3DNow, 0, 0}, + {"pdistib", cyrixmmx_insn, 1, SUF_Z, 0x54, 0, 0, 0, CPU_Cyrix, CPU_MMX, 0}, + {"sha256msg2", intel_SHA256MSG2_insn, 1, SUF_Z, 0, 0, 0, 0, CPU_SHA, 0, 0}, + {"pshuflw", xmm_xmm128_imm_insn, 1, SUF_Z, 0xF2, 0x70, 0, 0, CPU_SSE2, 0, 0}, + {"vpcomged", vpcom_insn, 1, SUF_Z, 0xCE, 0x03, 0, 0, CPU_XOP, 0, 0}, + {"addpd", xmm_xmm128_insn, 2, SUF_Z, 0x66, 0x58, 0, 0, CPU_SSE2, 0, 0}, + {"fstenv", twobytemem_insn, 1, SUF_Z, 0x06, 0x9B, 0xD9, 0, CPU_FPU, 0, 0}, + {"vpcomled", vpcom_insn, 1, SUF_Z, 0xCE, 0x01, 0, 0, CPU_XOP, 0, 0}, + {"vpackssdw", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0x6B, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"cmovnbl", cmovcc_insn, 3, SUF_L, 0x03, 0, 0, 0, CPU_686, 0, 0}, + {"vpcomleuq", vpcom_insn, 1, SUF_Z, 0xEF, 0x01, 0, 0, CPU_XOP, 0, 0}, + {"paddsiw", cyrixmmx_insn, 1, SUF_Z, 0x51, 0, 0, 0, CPU_Cyrix, CPU_MMX, 0}, + {"dppd", sse4imm_insn, 2, SUF_Z, 0x41, 0, 0, 0, CPU_SSE41, 0, 0}, + {"incb", incdec_insn, 6, SUF_B, 0x40, 0x00, 0, 0, 0, 0, 0}, + {"vpmulhuw", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0xE4, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vmovmskpdl", movmsk_insn, 4, SUF_L, 0x66, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"hnt", NULL, X86_SEGREG>>8, 0x2E, 0, 0, 0, 0, 0, 0, 0}, + {"fclex", threebyte_insn, 1, SUF_Z, 0x9B, 0xDB, 0xE2, 0, CPU_FPU, 0, 0}, + {"vcmpord_sss", ssecmp_32_insn, 4, SUF_Z, 0x17, 0xF3, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"aeskeygenassist", aes_imm_insn, 1, SUF_Z, 0x3A, 0xDF, 0, 0, CPU_AES, 0, 0}, + {"cvtsi2ssq", cvt_xmm_rmx_insn, 6, SUF_Q, 0xF3, 0x2A, 0, ONLY_64, CPU_SSE, 0, 0}, + {"extractps", extractps_insn, 2, SUF_Z, 0, 0, 0, 0, CPU_386, CPU_SSE41, 0}, + {"cmpless", ssecmp_32_insn, 4, SUF_Z, 0x02, 0xF3, 0, 0, CPU_SSE, 0, 0}, + {"psubusw", mmxsse2_insn, 2, SUF_Z, 0xD9, 0, 0, 0, CPU_MMX, 0, 0}, + {"setnzb", setcc_insn, 1, SUF_B, 0x05, 0, 0, 0, CPU_386, 0, 0}, + {"vpacksswb", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0x63, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"pandn", mmxsse2_insn, 2, SUF_Z, 0xDF, 0, 0, 0, CPU_MMX, 0, 0}, + {"vpsubd", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0xFA, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vcmptruesd", ssecmp_64_insn, 4, SUF_Z, 0x0F, 0xF2, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"fucomp", fcom2_insn, 2, SUF_Z, 0xDD, 0xE8, 0, 0, CPU_286, CPU_FPU, 0}, + {"lar", larlsl_insn, 6, SUF_Z, 0x02, 0, 0, 0, CPU_286, CPU_Prot, 0}, + {"blsic", xop_gpr_reg_rm_09_insn, 2, SUF_Z, 0x01, 0x06, 0, 0, CPU_386, CPU_TBM, 0}, + {"ibts", ibts_insn, 2, SUF_Z, 0, 0, 0, 0, CPU_386, CPU_Obs, CPU_Undoc}, + {"sysexit", twobyte_insn, 1, SUF_Z, 0x0F, 0x35, 0, NOT_64, CPU_686, CPU_Priv, 0}, + {"vmovmskps", movmsk_insn, 4, SUF_Z, 0x00, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vcvtss2sd", xmm_xmm32_insn, 4, SUF_Z, 0xF3, 0x5A, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vunpcklps", xmm_xmm128_256_insn, 4, SUF_Z, 0x00, 0x14, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"fdivr", farith_insn, 7, SUF_Z, 0xF0, 0xF8, 0x07, 0, CPU_FPU, 0, 0}, + {"vpshufb", ssse3_insn, 5, SUF_Z, 0x00, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vcmptruepd", ssecmp_128_insn, 3, SUF_Z, 0x0F, 0x66, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpshufhw", xmm_xmm128_imm_256avx2_insn, 2, SUF_Z, 0xF3, 0x70, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"loopl", loopl_insn, 4, SUF_Z, 0x02, 0x20, 0, 0, 0, 0, 0}, + {"vfnmaddps", fma_128_256_insn, 4, SUF_Z, 0x78, 0, 0, ONLY_AVX, CPU_FMA4, 0, 0}, + {"movsbw", movszx_insn, 5, SUF_B, 0xBE, 0, 0, 0, CPU_386, 0, 0}, + {"fstps", fstp_insn, 4, SUF_S, 0, 0, 0, 0, CPU_FPU, 0, 0}, + {"fadd", farith_insn, 7, SUF_Z, 0xC0, 0xC0, 0x00, 0, CPU_FPU, 0, 0}, + {"vcmpeqsd", ssecmp_64_insn, 4, SUF_Z, 0x00, 0xF2, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vcmpngt_uqsd", ssecmp_64_insn, 4, SUF_Z, 0x1A, 0xF2, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"sscaw", onebyte_insn, 1, SUF_Z, 0xAF, 0x10, 0, 0, 0, 0, 0}, + {"setnlb", setcc_insn, 1, SUF_B, 0x0D, 0, 0, 0, CPU_386, 0, 0}, + {"vpmulld", ssse3_insn, 5, SUF_Z, 0x40, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vfmsub132pd", vfma_pd_insn, 2, SUF_Z, 0x9A, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"palignr", ssse3imm_insn, 2, SUF_Z, 0x0F, 0, 0, 0, CPU_SSSE3, 0, 0}, + {"orpd", xmm_xmm128_insn, 2, SUF_Z, 0x66, 0x56, 0, 0, CPU_SSE2, 0, 0}, + {"vminsd", xmm_xmm64_insn, 4, SUF_Z, 0xF2, 0x5D, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"fsincos", twobyte_insn, 1, SUF_Z, 0xD9, 0xFB, 0, 0, CPU_286, CPU_FPU, 0}, + {"vcmple_oqpd", ssecmp_128_insn, 3, SUF_Z, 0x12, 0x66, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"pmagw", cyrixmmx_insn, 1, SUF_Z, 0x52, 0, 0, 0, CPU_Cyrix, CPU_MMX, 0}, + {"setnleb", setcc_insn, 1, SUF_B, 0x0F, 0, 0, 0, CPU_386, 0, 0}, + {"vcmpps", xmm_xmm128_imm_256_insn, 3, SUF_Z, 0x00, 0xC2, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpmulhrsw", ssse3_insn, 5, SUF_Z, 0x0B, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"setcb", setcc_insn, 1, SUF_B, 0x02, 0, 0, 0, CPU_386, 0, 0}, + {"lgsl", lfgss_insn, 3, SUF_L, 0xB5, 0, 0, 0, CPU_386, 0, 0}, + {"paveb", cyrixmmx_insn, 1, SUF_Z, 0x50, 0, 0, 0, CPU_Cyrix, CPU_MMX, 0}, + {"sbbq", arith_insn, 22, SUF_Q, 0x18, 0x03, 0, ONLY_64, 0, 0, 0}, + {"vfmaddpd", fma_128_256_insn, 4, SUF_Z, 0x69, 0, 0, ONLY_AVX, CPU_FMA4, 0, 0}, + {"fcos", twobyte_insn, 1, SUF_Z, 0xD9, 0xFF, 0, 0, CPU_286, CPU_FPU, 0}, + {"cvtsi2ssl", cvt_xmm_rmx_insn, 6, SUF_L, 0xF3, 0x2A, 0, 0, CPU_386, CPU_SSE, 0}, + {"setneb", setcc_insn, 1, SUF_B, 0x05, 0, 0, 0, CPU_386, 0, 0}, + {"vfnmsub132ps", vfma_ps_insn, 2, SUF_Z, 0x9E, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"lfsw", lfgss_insn, 3, SUF_W, 0xB4, 0, 0, 0, CPU_386, 0, 0}, + {"vpcmpestrm", sse4pcmpstr_insn, 1, SUF_Z, 0x60, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"arpl", arpl_insn, 1, SUF_Z, 0, 0, 0, NOT_64, CPU_286, CPU_Prot, 0}, + {"cmovew", cmovcc_insn, 3, SUF_W, 0x04, 0, 0, 0, CPU_686, 0, 0}, + {"pminuw", sse4_insn, 2, SUF_Z, 0x3A, 0, 0, 0, CPU_SSE41, 0, 0}, + {"movabsq", movabs_insn, 9, SUF_Q, 0, 0, 0, ONLY_64, 0, 0, 0}, + {"cmovo", cmovcc_insn, 3, SUF_Z, 0x00, 0, 0, 0, CPU_686, 0, 0}, + {"blsicl", xop_gpr_reg_rm_09_insn, 2, SUF_L, 0x01, 0x06, 0, 0, CPU_386, CPU_TBM, 0}, + {"smovw", onebyte_insn, 1, SUF_Z, 0xA5, 0x10, 0, 0, 0, 0, 0}, + {"faddl", farith_insn, 7, SUF_L, 0xC0, 0xC0, 0x00, 0, CPU_FPU, 0, 0}, + {"maxsd", xmm_xmm64_insn, 4, SUF_Z, 0xF2, 0x5F, 0, 0, CPU_SSE2, 0, 0}, + {"aad", aadm_insn, 2, SUF_Z, 0x01, 0, 0, NOT_64, 0, 0, 0}, + {"vpmaskmovq", vmaskmov_vexw1_avx2_insn, 4, SUF_Z, 0x8C, 0, 0, ONLY_AVX, CPU_AVX2, 0, 0}, + {"vfmadd132sd", vfma_sd_insn, 2, SUF_Z, 0x99, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"rep", NULL, X86_LOCKREP>>8, 0xF3, 0, 0, 0, 0, 0, 0, 0}, + {"vcmpltss", ssecmp_32_insn, 4, SUF_Z, 0x01, 0xF3, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"sub", arith_insn, 22, SUF_Z, 0x28, 0x05, 0, 0, 0, 0, 0}, + {"smswq", sldtmsw_insn, 6, SUF_Q, 0x04, 0x01, 0, ONLY_64, CPU_286, 0, 0}, + {"qword", NULL, X86_OPERSIZE>>8, 0x40, 0, 0, 0, ONLY_64, 0, 0, 0}, + {"vcmpunordps", ssecmp_128_insn, 3, SUF_Z, 0x03, 0x00, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"cltq", onebyte_insn, 1, SUF_Z, 0x98, 0x40, 0, ONLY_64, 0, 0, 0}, + {"vfnmadd213pd", vfma_pd_insn, 2, SUF_Z, 0xAC, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"minsd", xmm_xmm64_insn, 4, SUF_Z, 0xF2, 0x5D, 0, 0, CPU_SSE2, 0, 0}, + {"fmul", farith_insn, 7, SUF_Z, 0xC8, 0xC8, 0x01, 0, CPU_FPU, 0, 0}, + {"cmpss", xmm_xmm32_imm_insn, 4, SUF_Z, 0xF3, 0xC2, 0, 0, CPU_SSE, 0, 0}, + {"vcvtsd2si", cvt_rx_xmm64_insn, 4, SUF_Z, 0xF2, 0x2D, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"addsd", xmm_xmm64_insn, 4, SUF_Z, 0xF2, 0x58, 0, 0, CPU_SSE2, 0, 0}, + {"vmulss", xmm_xmm32_insn, 4, SUF_Z, 0xF3, 0x59, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"btsq", bittest_insn, 6, SUF_Q, 0xAB, 0x05, 0, ONLY_64, CPU_386, 0, 0}, + {"cvtsd2sil", cvt_rx_xmm64_insn, 4, SUF_L, 0xF2, 0x2D, 0, 0, CPU_386, CPU_SSE2, 0}, + {"vpcomtrueb", vpcom_insn, 1, SUF_Z, 0xCC, 0x07, 0, 0, CPU_XOP, 0, 0}, + {"vpcomeqb", vpcom_insn, 1, SUF_Z, 0xCC, 0x04, 0, 0, CPU_XOP, 0, 0}, + {"fidivr", fiarith_insn, 2, SUF_Z, 0x07, 0xDA, 0, 0, CPU_FPU, 0, 0}, + {"vpcomgeuw", vpcom_insn, 1, SUF_Z, 0xED, 0x03, 0, 0, CPU_XOP, 0, 0}, + {"cmovnel", cmovcc_insn, 3, SUF_L, 0x05, 0, 0, 0, CPU_686, 0, 0}, + {"vpmovzxwq", sse4m32_insn, 4, SUF_Z, 0x34, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vcmpeq_osss", ssecmp_32_insn, 4, SUF_Z, 0x10, 0xF3, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"shrb", shift_insn, 16, SUF_B, 0x05, 0, 0, 0, 0, 0, 0}, + {"maxpd", xmm_xmm128_insn, 2, SUF_Z, 0x66, 0x5F, 0, 0, CPU_SSE2, 0, 0}, + {"hsubps", xmm_xmm128_insn, 2, SUF_Z, 0xF2, 0x7D, 0, 0, CPU_SSE3, 0, 0}, + {"sarx", vex_gpr_reg_rm_nds_0F_insn, 2, SUF_Z, 0xF3, 0x38, 0xF7, ONLY_AVX, CPU_BMI2, 0, 0}, + {"vpcomgtb", vpcom_insn, 1, SUF_Z, 0xCC, 0x02, 0, 0, CPU_XOP, 0, 0}, + {"vextractf128", vextractif128_insn, 1, SUF_Z, 0x19, 0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vcvtsi2ssl", cvt_xmm_rmx_insn, 6, SUF_L, 0xF3, 0x2A, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"movzxb", movszx_insn, 5, SUF_B, 0xB6, 0, 0, 0, CPU_386, 0, 0}, + {"vpbroadcastw", vpbroadcastw_avx2_insn, 4, SUF_Z, 0, 0, 0, ONLY_AVX, CPU_AVX2, 0, 0}, + {"shlw", shift_insn, 16, SUF_W, 0x04, 0, 0, 0, 0, 0, 0}, + {"cmpltps", ssecmp_128_insn, 3, SUF_Z, 0x01, 0, 0, 0, CPU_SSE, 0, 0}, + {"xlatb", onebyte_insn, 1, SUF_Z, 0xD7, 0x00, 0, 0, 0, 0, 0}, + {"xsha1", padlock_insn, 1, SUF_Z, 0xC8, 0xF3, 0xA6, 0, CPU_PadLock, 0, 0}, + {"lret", retnf_insn, 6, SUF_Z, 0xCA, 0, 0, 0, 0, 0, 0}, + {"xsha256", padlock_insn, 1, SUF_Z, 0xD0, 0xF3, 0xA6, 0, CPU_PadLock, 0, 0}, + {"vpsrad", vpshift_insn, 8, SUF_Z, 0xE2, 0x72, 0x04, ONLY_AVX, CPU_AVX, 0, 0}, + {"cmovnpl", cmovcc_insn, 3, SUF_L, 0x0B, 0, 0, 0, CPU_686, 0, 0}, + {"addw", arith_insn, 22, SUF_W, 0x00, 0x00, 0, 0, 0, 0, 0}, + {"setg", setcc_insn, 1, SUF_Z, 0x0F, 0, 0, 0, CPU_386, 0, 0}, + {"vphaddubq", vphaddsub_insn, 1, SUF_Z, 0xD3, 0, 0, 0, CPU_XOP, 0, 0}, + {"cmovngl", cmovcc_insn, 3, SUF_L, 0x0E, 0, 0, 0, CPU_686, 0, 0}, + {"vpermilpd", vpermil_insn, 4, SUF_Z, 0x05, 0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpmacswd", vpma_insn, 1, SUF_Z, 0x96, 0, 0, 0, CPU_XOP, 0, 0}, + {"clac", threebyte_insn, 1, SUF_Z, 0x0F, 0x01, 0xCA, 0, CPU_SMAP, 0, 0}, + {"punpckhwd", mmxsse2_insn, 2, SUF_Z, 0x69, 0, 0, 0, CPU_MMX, 0, 0}, + {"vpcmpgtb", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0x64, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"leave", onebyte_insn, 1, SUF_Z, 0xC9, 0x00, 0x40, 0, CPU_186, 0, 0}, + {"shrd", shlrd_insn, 9, SUF_Z, 0xAC, 0, 0, 0, CPU_386, 0, 0}, + {"vfmsub132ps", vfma_ps_insn, 2, SUF_Z, 0x9A, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"lretl", retnf_insn, 6, SUF_L, 0xCA, 0, 0, 0, 0, 0, 0}, + {"cmovpol", cmovcc_insn, 3, SUF_L, 0x0B, 0, 0, 0, CPU_686, 0, 0}, + {"orl", arith_insn, 22, SUF_L, 0x08, 0x01, 0, 0, CPU_386, 0, 0}, + {"fnstcw", fldnstcw_insn, 1, SUF_Z, 0x07, 0, 0, 0, CPU_FPU, 0, 0}, + {"punpckldq", mmxsse2_insn, 2, SUF_Z, 0x62, 0, 0, 0, CPU_MMX, 0, 0}, + {"vpmaddwd", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0xF5, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"mulb", f6_insn, 4, SUF_B, 0x04, 0, 0, 0, 0, 0, 0}, + {"cmppd", xmm_xmm128_imm_insn, 1, SUF_Z, 0x66, 0xC2, 0, 0, CPU_SSE2, 0, 0}, + {"rex", NULL, X86_REX>>8, 0x40, 0, 0, 0, ONLY_64, 0, 0, 0}, + {"movd", movd_insn, 8, SUF_Z, 0, 0, 0, 0, CPU_386, CPU_MMX, 0}, + {"vpshaw", amd_vpshift_insn, 2, SUF_Z, 0x99, 0, 0, 0, CPU_XOP, 0, 0}, + {"vrsqrtps", avx_xmm_xmm128_insn, 2, SUF_Z, 0x00, 0x52, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vcvtph2ps", avx_cvtph2ps_insn, 4, SUF_Z, 0x66, 0x13, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vsubss", xmm_xmm32_insn, 4, SUF_Z, 0xF3, 0x5C, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"tzcntl", cnt_insn, 3, SUF_L, 0xBC, 0, 0, 0, CPU_BMI1, 0, 0}, + {"not", f6_insn, 4, SUF_Z, 0x02, 0, 0, 0, 0, 0, 0}, + {"cvtpd2pi", cvt_mm_xmm_insn, 1, SUF_Z, 0x66, 0x2D, 0, 0, CPU_SSE2, 0, 0}, + {"vcmpngtsd", ssecmp_64_insn, 4, SUF_Z, 0x0A, 0xF2, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"rex64yz", NULL, X86_REX>>8, 0x4B, 0, 0, 0, ONLY_64, 0, 0, 0}, + {"vpblendd", vex_66_0F3A_imm8_avx2_insn, 2, SUF_Z, 0x02, 0, 0, ONLY_AVX, CPU_AVX2, 0, 0}, + {"vpmovmskb", pmovmskb_insn, 6, SUF_Z, 0xC0, 0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"fldt", fldstpt_insn, 1, SUF_Z, 0x05, 0, 0, 0, CPU_FPU, 0, 0}, + {"vpunpcklbw", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0x60, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"femms", twobyte_insn, 1, SUF_Z, 0x0F, 0x0E, 0, 0, CPU_3DNow, 0, 0}, + {"vpsrlvq", vpshiftv_vexw1_avx2_insn, 2, SUF_Z, 0x45, 0, 0, ONLY_AVX, CPU_AVX2, 0, 0}, + {"paddusb", mmxsse2_insn, 2, SUF_Z, 0xDC, 0, 0, 0, CPU_MMX, 0, 0}, + {"movdq2q", movdq2q_insn, 1, SUF_Z, 0, 0, 0, 0, CPU_SSE2, 0, 0}, + {"vfnmsub132pd", vfma_pd_insn, 2, SUF_Z, 0x9E, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"adcb", arith_insn, 22, SUF_B, 0x10, 0x02, 0, 0, 0, 0, 0}, + {"vcmpneqps", ssecmp_128_insn, 3, SUF_Z, 0x04, 0x00, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"andnl", vex_gpr_reg_nds_rm_0F_insn, 2, SUF_L, 0x00, 0x38, 0xF2, ONLY_AVX, CPU_BMI1, 0, 0}, + {"fnstenvl", onebytemem_insn, 1, SUF_L, 0x06, 0xD9, 0, 0, CPU_FPU, 0, 0}, + {"smi", onebyte_insn, 1, SUF_Z, 0xF1, 0, 0, 0, CPU_386, CPU_Undoc, 0}, + {"cmovol", cmovcc_insn, 3, SUF_L, 0x00, 0, 0, 0, CPU_686, 0, 0}, + {"wait", onebyte_insn, 1, SUF_Z, 0x9B, 0, 0, 0, 0, 0, 0}, + {"vpcmov", vpcmov_insn, 4, SUF_Z, 0, 0, 0, 0, CPU_XOP, 0, 0}, + {"vunpcklpd", xmm_xmm128_256_insn, 4, SUF_Z, 0x66, 0x14, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"jl", jcc_insn, 9, SUF_Z, 0x0C, 0, 0, 0, 0, 0, 0}, + {"fnclex", twobyte_insn, 1, SUF_Z, 0xDB, 0xE2, 0, 0, CPU_FPU, 0, 0}, + {"shlq", shift_insn, 16, SUF_Q, 0x04, 0, 0, ONLY_64, 0, 0, 0}, + {"sall", shift_insn, 16, SUF_L, 0x04, 0, 0, 0, CPU_386, 0, 0}, + {"swapgs", threebyte_insn, 1, SUF_Z, 0x0F, 0x01, 0xF8, ONLY_64, 0, 0, 0}, + {"cvttps2dq", xmm_xmm128_insn, 2, SUF_Z, 0xF3, 0x5B, 0, 0, CPU_SSE2, 0, 0}, + {"pmaxud", sse4_insn, 2, SUF_Z, 0x3F, 0, 0, 0, CPU_SSE41, 0, 0}, + {"vpaddsw", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0xED, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"prefetcht0", twobytemem_insn, 1, SUF_Z, 0x01, 0x0F, 0x18, 0, CPU_P3, 0, 0}, + {"repne", NULL, X86_LOCKREP>>8, 0xF2, 0, 0, 0, 0, 0, 0, 0}, + {"vfmsub132ss", vfma_ss_insn, 2, SUF_Z, 0x9B, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"lsll", larlsl_insn, 6, SUF_L, 0x03, 0, 0, 0, CPU_286, CPU_Prot, 0}, + {"vgatherqps", gather_32x_32y_128_insn, 2, SUF_Z, 0x93, 0, 0, ONLY_AVX, CPU_AVX2, 0, 0}, + {"vrsqrtss", xmm_xmm32_insn, 4, SUF_Z, 0xF3, 0x52, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"divl", div_insn, 8, SUF_L, 0x06, 0, 0, 0, CPU_386, 0, 0}, + {"pcmpgtq", sse4_insn, 2, SUF_Z, 0x37, 0, 0, 0, CPU_SSE41, 0, 0}, + {"pmulhrsw", ssse3_insn, 5, SUF_Z, 0x0B, 0, 0, 0, CPU_SSSE3, 0, 0}, + {"repe", NULL, X86_LOCKREP>>8, 0xF3, 0, 0, 0, 0, 0, 0, 0}, + {"vpcomtrued", vpcom_insn, 1, SUF_Z, 0xCE, 0x07, 0, 0, CPU_XOP, 0, 0}, + {"fldl", fld_insn, 4, SUF_L, 0, 0, 0, 0, CPU_FPU, 0, 0}, + {"cvtps2pd", xmm_xmm64_insn, 4, SUF_Z, 0x00, 0x5A, 0, 0, CPU_SSE2, 0, 0}, + {"vcmpnless", ssecmp_32_insn, 4, SUF_Z, 0x06, 0xF3, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"loopeq", loopq_insn, 4, SUF_Z, 0x01, 0x40, 0, ONLY_64, 0, 0, 0}, + {"aesdeclast", aes_insn, 2, SUF_Z, 0x38, 0xDF, 0, 0, CPU_AVX, 0, 0}, + {"vpcomequb", vpcom_insn, 1, SUF_Z, 0xEC, 0x04, 0, 0, CPU_XOP, 0, 0}, + {"stgi", threebyte_insn, 1, SUF_Z, 0x0F, 0x01, 0xDC, 0, CPU_SVM, 0, 0}, + {"vpmovzxbd", sse4m32_insn, 4, SUF_Z, 0x31, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"psignb", ssse3_insn, 5, SUF_Z, 0x08, 0, 0, 0, CPU_SSSE3, 0, 0}, + {"vpshlq", amd_vpshift_insn, 2, SUF_Z, 0x97, 0, 0, 0, CPU_XOP, 0, 0}, + {"vpcomfalseuq", vpcom_insn, 1, SUF_Z, 0xEF, 0x06, 0, 0, CPU_XOP, 0, 0}, + {"mulxq", vex_gpr_reg_nds_rm_0F_insn, 2, SUF_Q, 0xF2, 0x38, 0xF6, ONLY_64|ONLY_AVX, CPU_BMI2, 0, 0}, + {"jmpq", jmp_insn, 31, SUF_Q, 0, 0, 0, ONLY_64, 0, 0, 0}, + {"cvtsd2siq", cvt_rx_xmm64_insn, 4, SUF_Q, 0xF2, 0x2D, 0, ONLY_64, CPU_SSE2, 0, 0}, + {"movhpd", movhlp_insn, 3, SUF_Z, 0x66, 0x16, 0, 0, CPU_SSE2, 0, 0}, + {"punpcklqdq", xmm_xmm128_insn, 2, SUF_Z, 0x66, 0x6C, 0, 0, CPU_SSE2, 0, 0}, + {"verw", prot286_insn, 1, SUF_Z, 0x05, 0x00, 0, 0, CPU_286, CPU_Prot, 0}, + {"cmpunordsd", ssecmp_64_insn, 4, SUF_Z, 0x03, 0xF2, 0, 0, CPU_SSE2, 0, 0}, + {"vzeroall", vzero_insn, 1, SUF_Z, 0xC4, 0, 0, 0, CPU_AVX, 0, 0}, + {"vperm2i128", vperm2i128_avx2_insn, 1, SUF_Z, 0, 0, 0, ONLY_AVX, CPU_AVX2, 0, 0}, + {"jo", jcc_insn, 9, SUF_Z, 0x00, 0, 0, 0, 0, 0, 0}, + {"callq", call_insn, 30, SUF_Q, 0, 0, 0, ONLY_64, 0, 0, 0}, + {"cmovle", cmovcc_insn, 3, SUF_Z, 0x0E, 0, 0, 0, CPU_686, 0, 0}, + {"sgdtq", twobytemem_insn, 1, SUF_Q, 0x00, 0x0F, 0x01, 0, CPU_286, CPU_Priv, 0}, + {"cmovnpq", cmovcc_insn, 3, SUF_Q, 0x0B, 0, 0, ONLY_64, CPU_686, 0, 0}, + {"cvtpd2ps", xmm_xmm128_insn, 2, SUF_Z, 0x66, 0x5A, 0, 0, CPU_SSE2, 0, 0}, + {"minss", xmm_xmm32_insn, 4, SUF_Z, 0xF3, 0x5D, 0, 0, CPU_SSE, 0, 0}, + {"loopw", loopw_insn, 4, SUF_Z, 0x02, 0x10, 0, NOT_64, 0, 0, 0}, + {"inveptl", eptvpid_insn, 2, SUF_L, 0x00, 0, 0, NOT_64, CPU_386, CPU_EPTVPID, 0}, + {"bsr", bsfr_insn, 3, SUF_Z, 0xBD, 0, 0, 0, CPU_386, 0, 0}, + {"vcmpgtss", ssecmp_32_insn, 4, SUF_Z, 0x0E, 0xF3, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"negl", f6_insn, 4, SUF_L, 0x03, 0, 0, 0, CPU_386, 0, 0}, + {"psrlw", pshift_insn, 4, SUF_Z, 0xD1, 0x71, 0x02, 0, CPU_MMX, 0, 0}, + {"vpmuludq", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0xF4, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"pext", vex_gpr_reg_nds_rm_0F_insn, 2, SUF_Z, 0xF3, 0x38, 0xF5, ONLY_AVX, CPU_BMI2, 0, 0}, + {"rsm", twobyte_insn, 1, SUF_Z, 0x0F, 0xAA, 0, 0, CPU_586, CPU_SMM, 0}, + {"addl", arith_insn, 22, SUF_L, 0x00, 0x00, 0, 0, CPU_386, 0, 0}, + {"vpermd", vperm_var_avx2_insn, 1, SUF_Z, 0x36, 0, 0, ONLY_AVX, CPU_AVX2, 0, 0}, + {"fxsave", twobytemem_insn, 1, SUF_Z, 0x00, 0x0F, 0xAE, 0, CPU_686, CPU_FPU, 0}, + {"vphadduwq", vphaddsub_insn, 1, SUF_Z, 0xD7, 0, 0, 0, CPU_XOP, 0, 0}, + {"pminud", sse4_insn, 2, SUF_Z, 0x3B, 0, 0, 0, CPU_SSE41, 0, 0}, + {"ldsw", ldes_insn, 2, SUF_W, 0xC5, 0, 0, NOT_64, 0, 0, 0}, + {"movsw", onebyte_insn, 1, SUF_Z, 0xA5, 0x10, 0, 0, 0, 0, 0}, + {"pmaxub", mmxsse2_insn, 2, SUF_Z, 0xDE, 0, 0, 0, CPU_MMX, CPU_P3, 0}, + {"vldmxcsr", ldstmxcsr_insn, 1, SUF_Z, 0x02, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vhsubpd", xmm_xmm128_256_insn, 4, SUF_Z, 0x66, 0x7D, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vucomisd", avx_xmm_xmm64_insn, 2, SUF_Z, 0x66, 0x2E, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"cmovpow", cmovcc_insn, 3, SUF_W, 0x0B, 0, 0, 0, CPU_686, 0, 0}, + {"pmvgezb", cyrixmmx_insn, 1, SUF_Z, 0x5C, 0, 0, 0, CPU_Cyrix, CPU_MMX, 0}, + {"cvtsd2ss", xmm_xmm64_insn, 4, SUF_Z, 0xF2, 0x5A, 0, 0, CPU_SSE2, 0, 0}, + {"vbroadcastf128", vbroadcastif128_insn, 1, SUF_Z, 0x1A, 0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"lldt", prot286_insn, 1, SUF_Z, 0x02, 0x00, 0, 0, CPU_286, CPU_Priv, CPU_Prot}, + {"t1mskc", xop_gpr_reg_rm_09_insn, 2, SUF_Z, 0x01, 0x07, 0, 0, CPU_386, CPU_TBM, 0}, + {"movsx", movszx_insn, 5, SUF_Z, 0xBE, 0, 0, 0, CPU_386, 0, 0}, + {"vpmacsdd", vpma_insn, 1, SUF_Z, 0x9E, 0, 0, 0, CPU_XOP, 0, 0}, + {"vcmplesd", ssecmp_64_insn, 4, SUF_Z, 0x02, 0xF2, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"prefetchw", twobytemem_insn, 1, SUF_Z, 0x01, 0x0F, 0x0D, 0, CPU_PRFCHW, 0, 0}, + {"pextrd", pextrd_insn, 1, SUF_Z, 0, 0, 0, 0, CPU_386, CPU_SSE41, 0}, + {"vcmpfalse_osps", ssecmp_128_insn, 3, SUF_Z, 0x1B, 0x00, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vptest", sse4_insn, 2, SUF_Z, 0x17, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"loopneq", loopq_insn, 4, SUF_Z, 0x00, 0x40, 0, ONLY_64, 0, 0, 0}, + {"fucompp", twobyte_insn, 1, SUF_Z, 0xDA, 0xE9, 0, 0, CPU_286, CPU_FPU, 0}, + {"vpextrq", pextrq_insn, 1, SUF_Z, 0xC0, 0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"umov", umov_insn, 6, SUF_Z, 0, 0, 0, 0, CPU_386, CPU_Undoc, 0}, + {"fcmovb", fcmovcc_insn, 1, SUF_Z, 0xDA, 0xC0, 0, 0, CPU_686, CPU_FPU, 0}, + {"vinsertf128", vinsertif128_insn, 1, SUF_Z, 0x18, 0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"std", onebyte_insn, 1, SUF_Z, 0xFD, 0, 0, 0, 0, 0, 0}, + {"cvtpd2dq", xmm_xmm128_insn, 2, SUF_Z, 0xF2, 0xE6, 0, 0, CPU_SSE2, 0, 0}, + {"vpcomned", vpcom_insn, 1, SUF_Z, 0xCE, 0x05, 0, 0, CPU_XOP, 0, 0}, + {"vpand", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0xDB, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"bswapq", bswap_insn, 2, SUF_Q, 0, 0, 0, ONLY_64, 0, 0, 0}, + {"vpmacssdqh", vpma_insn, 1, SUF_Z, 0x8F, 0, 0, 0, CPU_XOP, 0, 0}, + {"blcicl", xop_gpr_reg_rm_09_insn, 2, SUF_L, 0x01, 0x05, 0, 0, CPU_386, CPU_TBM, 0}, + {"strq", str_insn, 4, SUF_Q, 0, 0, 0, ONLY_64, CPU_286, CPU_Prot, 0}, + {"vshufps", xmm_xmm128_imm_256_insn, 3, SUF_Z, 0x00, 0xC6, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"roll", shift_insn, 16, SUF_L, 0x00, 0, 0, 0, CPU_386, 0, 0}, + {"cvttpd2dq", xmm_xmm128_insn, 2, SUF_Z, 0x66, 0xE6, 0, 0, CPU_SSE2, 0, 0}, + {"salq", shift_insn, 16, SUF_Q, 0x04, 0, 0, ONLY_64, 0, 0, 0}, + {"vpcomfalseq", vpcom_insn, 1, SUF_Z, 0xCF, 0x06, 0, 0, CPU_XOP, 0, 0}, + {"leaq", lea_insn, 3, SUF_Q, 0, 0, 0, ONLY_64, 0, 0, 0}, + {"vmovdqu", movau_insn, 6, SUF_Z, 0xF3, 0x6F, 0x10, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpmaddubsw", ssse3_insn, 5, SUF_Z, 0x04, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"cmpltpd", ssecmp_128_insn, 3, SUF_Z, 0x01, 0x66, 0, 0, CPU_SSE, 0, 0}, + {"outw", out_insn, 12, SUF_W, 0, 0, 0, 0, 0, 0, 0}, + {"cmovncq", cmovcc_insn, 3, SUF_Q, 0x03, 0, 0, ONLY_64, CPU_686, 0, 0}, + {"blcmskl", xop_gpr_reg_rm_09_insn, 2, SUF_L, 0x02, 0x01, 0, 0, CPU_386, CPU_TBM, 0}, + {"vfmadd231ss", vfma_ss_insn, 2, SUF_Z, 0xB9, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"cmpordsd", ssecmp_64_insn, 4, SUF_Z, 0x07, 0xF2, 0, 0, CPU_SSE2, 0, 0}, + {"setnle", setcc_insn, 1, SUF_Z, 0x0F, 0, 0, 0, CPU_386, 0, 0}, + {"vfmadd231pd", vfma_pd_insn, 2, SUF_Z, 0xB8, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"vcmpneqsd", ssecmp_64_insn, 4, SUF_Z, 0x04, 0xF2, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vmptrst", vmxtwobytemem_insn, 1, SUF_Z, 0x07, 0, 0, 0, CPU_P4, 0, 0}, + {"cmovsl", cmovcc_insn, 3, SUF_L, 0x08, 0, 0, 0, CPU_686, 0, 0}, + {"vpmovsxbw", sse4m64_insn, 4, SUF_Z, 0x20, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vcmpneq_ossd", ssecmp_64_insn, 4, SUF_Z, 0x1C, 0xF2, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"xgetbv", threebyte_insn, 1, SUF_Z, 0x0F, 0x01, 0xD0, 0, CPU_386, CPU_XSAVE, 0}, + {"addr32", NULL, X86_ADDRSIZE>>8, 0x20, 0, 0, 0, 0, 0, 0, 0}, + {"vcmpneq_osss", ssecmp_32_insn, 4, SUF_Z, 0x1C, 0xF3, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vmulsd", xmm_xmm64_insn, 4, SUF_Z, 0xF2, 0x59, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"maskmovdqu", maskmovdqu_insn, 1, SUF_Z, 0, 0, 0, 0, CPU_SSE2, 0, 0}, + {"vpslldq", pslrldq_insn, 4, SUF_Z, 0x07, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"maskmovq", maskmovq_insn, 1, SUF_Z, 0, 0, 0, 0, CPU_MMX, CPU_P3, 0}, + {"vcmpeq_uspd", ssecmp_128_insn, 3, SUF_Z, 0x18, 0x66, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"pmulhriw", cyrixmmx_insn, 1, SUF_Z, 0x5D, 0, 0, 0, CPU_Cyrix, CPU_MMX, 0}, + {"vcvtps2dq", avx_xmm_xmm128_insn, 2, SUF_Z, 0x66, 0x5B, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vfnmsub231ss", vfma_ss_insn, 2, SUF_Z, 0xBF, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"shrx", vex_gpr_reg_rm_nds_0F_insn, 2, SUF_Z, 0xF2, 0x38, 0xF7, ONLY_AVX, CPU_BMI2, 0, 0}, + {"psadbw", mmxsse2_insn, 2, SUF_Z, 0xF6, 0, 0, 0, CPU_MMX, CPU_P3, 0}, + {"vmovd", vmovd_insn, 2, SUF_Z, 0, 0, 0, ONLY_AVX, CPU_386, CPU_AVX, 0}, + {"pushfl", onebyte_insn, 1, SUF_Z, 0x9C, 0x20, 0, NOT_64, CPU_386, 0, 0}, + {"vfnmadd132ps", vfma_ps_insn, 2, SUF_Z, 0x9C, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"sqrtpd", xmm_xmm128_insn, 2, SUF_Z, 0x66, 0x51, 0, 0, CPU_SSE2, 0, 0}, + {"cvtss2sil", cvt_rx_xmm32_insn, 4, SUF_L, 0xF3, 0x2D, 0, 0, CPU_386, CPU_SSE, 0}, + {"fyl2x", twobyte_insn, 1, SUF_Z, 0xD9, 0xF1, 0, 0, CPU_FPU, 0, 0}, + {"btq", bittest_insn, 6, SUF_Q, 0xA3, 0x04, 0, ONLY_64, CPU_386, 0, 0}, + {"vpslld", vpshift_insn, 8, SUF_Z, 0xF2, 0x72, 0x06, ONLY_AVX, CPU_AVX, 0, 0}, + {"invlpga", invlpga_insn, 2, SUF_Z, 0, 0, 0, 0, CPU_SVM, 0, 0}, + {"xorb", arith_insn, 22, SUF_B, 0x30, 0x06, 0, 0, 0, 0, 0}, + {"fsubp", farithp_insn, 3, SUF_Z, 0xE0, 0, 0, 0, CPU_FPU, 0, 0}, + {"vcvtps2pd", avx_cvt_xmm64_insn, 3, SUF_Z, 0x00, 0x5A, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vfnmsub213pd", vfma_pd_insn, 2, SUF_Z, 0xAE, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"vcvttsd2sil", cvt_rx_xmm64_insn, 4, SUF_L, 0xF2, 0x2C, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"jp", jcc_insn, 9, SUF_Z, 0x0A, 0, 0, 0, 0, 0, 0}, + {"vsubpd", xmm_xmm128_256_insn, 4, SUF_Z, 0x66, 0x5C, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"lesw", ldes_insn, 2, SUF_W, 0xC4, 0, 0, NOT_64, 0, 0, 0}, + {"vxorps", xmm_xmm128_256_insn, 4, SUF_Z, 0x00, 0x57, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"divb", div_insn, 8, SUF_B, 0x06, 0, 0, 0, 0, 0, 0}, + {"movq", mov_insn, 69, SUF_Q, 0, 0, 0, 0, 0, 0, 0}, + {"lfsl", lfgss_insn, 3, SUF_L, 0xB4, 0, 0, 0, CPU_386, 0, 0}, + {"syscall", twobyte_insn, 1, SUF_Z, 0x0F, 0x05, 0, 0, CPU_686, CPU_AMD, 0}, + {"btl", bittest_insn, 6, SUF_L, 0xA3, 0x04, 0, 0, CPU_386, 0, 0}, + {"fucomip", fcom2_insn, 2, SUF_Z, 0xDF, 0xE8, 0, 0, CPU_686, CPU_FPU, 0}, + {"setncb", setcc_insn, 1, SUF_B, 0x03, 0, 0, 0, CPU_386, 0, 0}, + {"cmovnol", cmovcc_insn, 3, SUF_L, 0x01, 0, 0, 0, CPU_686, 0, 0}, + {"xcryptcbc", padlock_insn, 1, SUF_Z, 0xD0, 0xF3, 0xA7, 0, CPU_PadLock, 0, 0}, + {"vcmplt_oqps", ssecmp_128_insn, 3, SUF_Z, 0x11, 0x00, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"btrq", bittest_insn, 6, SUF_Q, 0xB3, 0x06, 0, ONLY_64, CPU_386, 0, 0}, + {"paddw", mmxsse2_insn, 2, SUF_Z, 0xFD, 0, 0, 0, CPU_MMX, 0, 0}, + {"pmovzxbq", sse4m16_insn, 4, SUF_Z, 0x32, 0, 0, 0, CPU_SSE41, 0, 0}, + {"rorq", shift_insn, 16, SUF_Q, 0x01, 0, 0, ONLY_64, 0, 0, 0}, + {"xrelease", NULL, X86_ACQREL>>8, 0xF3, 0, 0, 0, 0, 0, 0, 0}, + {"vpshld", amd_vpshift_insn, 2, SUF_Z, 0x96, 0, 0, 0, CPU_XOP, 0, 0}, + {"fstp", fstp_insn, 4, SUF_Z, 0, 0, 0, 0, CPU_FPU, 0, 0}, + {"movsbq", movszx_insn, 5, SUF_B, 0xBE, 0, 0, ONLY_64, CPU_386, 0, 0}, + {"fucom", fcom2_insn, 2, SUF_Z, 0xDD, 0xE0, 0, 0, CPU_286, CPU_FPU, 0}, + {"vpclmullqlqdq", pclmulqdq_fixed_insn, 2, SUF_Z, 0x00, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"hsubpd", xmm_xmm128_insn, 2, SUF_Z, 0x66, 0x7D, 0, 0, CPU_SSE3, 0, 0}, + {"por", mmxsse2_insn, 2, SUF_Z, 0xEB, 0, 0, 0, CPU_MMX, 0, 0}, + {"mulx", vex_gpr_reg_nds_rm_0F_insn, 2, SUF_Z, 0xF2, 0x38, 0xF6, ONLY_AVX, CPU_BMI2, 0, 0}, + {"vpcomneqb", vpcom_insn, 1, SUF_Z, 0xCC, 0x05, 0, 0, CPU_XOP, 0, 0}, + {"movmskps", movmsk_insn, 4, SUF_Z, 0, 0, 0, 0, CPU_386, CPU_SSE, 0}, + {"fucomi", fcom2_insn, 2, SUF_Z, 0xDB, 0xE8, 0, 0, CPU_686, CPU_FPU, 0}, + {"ht", NULL, X86_SEGREG>>8, 0x3E, 0, 0, 0, 0, 0, 0, 0}, + {"vroundps", avx_sse4imm_insn, 3, SUF_Z, 0x08, 0, 0, ONLY_AVX, CPU_SSE41, 0, 0}, + {"ud1", twobyte_insn, 1, SUF_Z, 0x0F, 0xB9, 0, 0, CPU_286, CPU_Undoc, 0}, + {"insl", onebyte_insn, 1, SUF_Z, 0x6D, 0x20, 0, 0, CPU_386, 0, 0}, + {"vcmpngt_uqpd", ssecmp_128_insn, 3, SUF_Z, 0x1A, 0x66, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"rex64y", NULL, X86_REX>>8, 0x4A, 0, 0, 0, ONLY_64, 0, 0, 0}, + {"fldln2", twobyte_insn, 1, SUF_Z, 0xD9, 0xED, 0, 0, CPU_FPU, 0, 0}, + {"ldsl", ldes_insn, 2, SUF_L, 0xC5, 0, 0, NOT_64, CPU_386, 0, 0}, + {"tzmskl", xop_gpr_reg_rm_09_insn, 2, SUF_L, 0x01, 0x04, 0, 0, CPU_386, CPU_TBM, 0}, + {"vcmppd", xmm_xmm128_imm_256_insn, 3, SUF_Z, 0x66, 0xC2, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"sidtw", twobytemem_insn, 1, SUF_W, 0x01, 0x0F, 0x01, 0, CPU_286, CPU_Priv, 0}, + {"vpextrwl", pextrw_insn, 7, SUF_L, 0xC0, 0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"fldl2t", twobyte_insn, 1, SUF_Z, 0xD9, 0xE9, 0, 0, CPU_FPU, 0, 0}, + {"insb", onebyte_insn, 1, SUF_Z, 0x6C, 0x00, 0, 0, 0, 0, 0}, + {"bound", bound_insn, 2, SUF_Z, 0, 0, 0, NOT_64, CPU_186, 0, 0}, + {"vmwrite", vmxmemwr_insn, 2, SUF_Z, 0, 0, 0, 0, CPU_P4, 0, 0}, + {"cmpxchgq", cmpxchgxadd_insn, 4, SUF_Q, 0xB0, 0, 0, ONLY_64, CPU_486, 0, 0}, + {"fsts", fst_insn, 3, SUF_S, 0, 0, 0, 0, CPU_FPU, 0, 0}, + {"orps", xmm_xmm128_insn, 2, SUF_Z, 0x00, 0x56, 0, 0, CPU_SSE, 0, 0}, + {"vandnps", xmm_xmm128_256_insn, 4, SUF_Z, 0x00, 0x55, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"fdivrs", farith_insn, 7, SUF_S, 0xF0, 0xF8, 0x07, 0, CPU_FPU, 0, 0}, + {"fldcww", fldnstcw_insn, 1, SUF_W, 0x05, 0, 0, 0, CPU_FPU, 0, 0}, + {"movl", mov_insn, 69, SUF_L, 0, 0, 0, 0, CPU_386, 0, 0}, + {"movq2dq", movq2dq_insn, 1, SUF_Z, 0, 0, 0, 0, CPU_SSE2, 0, 0}, + {"cmpunordpd", ssecmp_128_insn, 3, SUF_Z, 0x03, 0x66, 0, 0, CPU_SSE, 0, 0}, + {"rdseed", rdrand_insn, 3, SUF_Z, 0x07, 0, 0, 0, CPU_RDSEED, 0, 0}, + {"cmovneq", cmovcc_insn, 3, SUF_Q, 0x05, 0, 0, ONLY_64, CPU_686, 0, 0}, + {"vpmovzxbq", sse4m16_insn, 4, SUF_Z, 0x32, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"cmpsb", onebyte_insn, 1, SUF_Z, 0xA6, 0x00, 0, 0, 0, 0, 0}, + {"vfmadd213sd", vfma_sd_insn, 2, SUF_Z, 0xA9, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"into", onebyte_insn, 1, SUF_Z, 0xCE, 0, 0, NOT_64, 0, 0, 0}, + {"cmovzl", cmovcc_insn, 3, SUF_L, 0x04, 0, 0, 0, CPU_686, 0, 0}, + {"imulb", imul_insn, 19, SUF_B, 0, 0, 0, 0, 0, 0, 0}, + {"setc", setcc_insn, 1, SUF_Z, 0x02, 0, 0, 0, CPU_386, 0, 0}, + {"vstmxcsr", ldstmxcsr_insn, 1, SUF_Z, 0x03, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"fldenv", onebytemem_insn, 1, SUF_Z, 0x04, 0xD9, 0, 0, CPU_FPU, 0, 0}, + {"pmovsxwd", sse4m64_insn, 4, SUF_Z, 0x23, 0, 0, 0, CPU_SSE41, 0, 0}, + {"vcmpnltss", ssecmp_32_insn, 4, SUF_Z, 0x05, 0xF3, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"movntpd", movnt_insn, 2, SUF_Z, 0x66, 0x2B, 0, 0, CPU_SSE2, 0, 0}, + {"pcmpeqw", mmxsse2_insn, 2, SUF_Z, 0x75, 0, 0, 0, CPU_MMX, 0, 0}, + {"fcoms", fcom_insn, 6, SUF_S, 0xD0, 0x02, 0, 0, CPU_FPU, 0, 0}, + {"vpaddb", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0xFC, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"sldt", sldtmsw_insn, 6, SUF_Z, 0x00, 0x00, 0, 0, CPU_286, 0, 0}, + {"fisttpq", fildstp_insn, 4, SUF_Q, 0x01, 0x00, 0x01, 0, CPU_SSE3, 0, 0}, + {"vpmacsww", vpma_insn, 1, SUF_Z, 0x95, 0, 0, 0, CPU_XOP, 0, 0}, + {"jne", jcc_insn, 9, SUF_Z, 0x05, 0, 0, 0, 0, 0, 0}, + {"shldl", shlrd_insn, 9, SUF_L, 0xA4, 0, 0, 0, CPU_386, 0, 0}, + {"cmc", onebyte_insn, 1, SUF_Z, 0xF5, 0, 0, 0, 0, 0, 0}, + {"cmovs", cmovcc_insn, 3, SUF_Z, 0x08, 0, 0, 0, CPU_686, 0, 0}, + {"movlpd", movhlp_insn, 3, SUF_Z, 0x66, 0x12, 0, 0, CPU_SSE2, 0, 0}, + {"calll", call_insn, 30, SUF_L, 0, 0, 0, 0, CPU_386, 0, 0}, + {"subb", arith_insn, 22, SUF_B, 0x28, 0x05, 0, 0, 0, 0, 0}, + {"lmsww", prot286_insn, 1, SUF_W, 0x06, 0x01, 0, 0, CPU_286, CPU_Priv, 0}, + {"vmrun", svm_rax_insn, 2, SUF_Z, 0xD8, 0, 0, 0, CPU_SVM, 0, 0}, + {"cmovna", cmovcc_insn, 3, SUF_Z, 0x06, 0, 0, 0, CPU_686, 0, 0}, + {"cmovnpw", cmovcc_insn, 3, SUF_W, 0x0B, 0, 0, 0, CPU_686, 0, 0}, + {"bextrq", bextr_insn, 4, SUF_Q, 0, 0, 0, ONLY_64|ONLY_AVX, CPU_BMI1, 0, 0}, + {"vpmacssww", vpma_insn, 1, SUF_Z, 0x85, 0, 0, 0, CPU_XOP, 0, 0}, + {"vdivss", xmm_xmm32_insn, 4, SUF_Z, 0xF3, 0x5E, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"movabsl", movabs_insn, 9, SUF_L, 0, 0, 0, ONLY_64, 0, 0, 0}, + {"callw", call_insn, 30, SUF_W, 0, 0, 0, 0, 0, 0, 0}, + {"vpcomlew", vpcom_insn, 1, SUF_Z, 0xCD, 0x01, 0, 0, CPU_XOP, 0, 0}, + {"fninit", twobyte_insn, 1, SUF_Z, 0xDB, 0xE3, 0, 0, CPU_FPU, 0, 0}, + {"vpavgw", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0xE3, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vcmpltpd", ssecmp_128_insn, 3, SUF_Z, 0x01, 0x66, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"cpuid", twobyte_insn, 1, SUF_Z, 0x0F, 0xA2, 0, 0, CPU_486, 0, 0}, + {"pmovzxwq", sse4m32_insn, 4, SUF_Z, 0x34, 0, 0, 0, CPU_SSE41, 0, 0}, + {"cmovnaew", cmovcc_insn, 3, SUF_W, 0x02, 0, 0, 0, CPU_686, 0, 0}, + {"comiss", xmm_xmm32_insn, 4, SUF_Z, 0x00, 0x2F, 0, 0, CPU_SSE, 0, 0}, + {"cmovnoq", cmovcc_insn, 3, SUF_Q, 0x01, 0, 0, ONLY_64, CPU_686, 0, 0}, + {"negb", f6_insn, 4, SUF_B, 0x03, 0, 0, 0, 0, 0, 0}, + {"vfnmadd231sd", vfma_sd_insn, 2, SUF_Z, 0xBD, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"xchgw", xchg_insn, 16, SUF_W, 0, 0, 0, 0, 0, 0, 0}, + {"rexz", NULL, X86_REX>>8, 0x41, 0, 0, 0, ONLY_64, 0, 0, 0}, + {"sbb", arith_insn, 22, SUF_Z, 0x18, 0x03, 0, 0, 0, 0, 0}, + {"lslw", larlsl_insn, 6, SUF_W, 0x03, 0, 0, 0, CPU_286, CPU_Prot, 0}, + {"cmovnzw", cmovcc_insn, 3, SUF_W, 0x05, 0, 0, 0, CPU_686, 0, 0}, + {"vfrczpd", vfrc_pdps_insn, 2, SUF_Z, 0x01, 0, 0, 0, CPU_XOP, 0, 0}, + {"bsrw", bsfr_insn, 3, SUF_W, 0xBD, 0, 0, 0, CPU_386, 0, 0}, + {"fcomps", fcom_insn, 6, SUF_S, 0xD8, 0x03, 0, 0, CPU_FPU, 0, 0}, + {"rorx", vex_gpr_reg_rm_0F_imm8_insn, 2, SUF_Z, 0xF2, 0x3A, 0xF0, ONLY_AVX, CPU_BMI2, 0, 0}, + {"shufpd", xmm_xmm128_imm_insn, 1, SUF_Z, 0x66, 0xC6, 0, 0, CPU_SSE2, 0, 0}, + {"vpcomleq", vpcom_insn, 1, SUF_Z, 0xCF, 0x01, 0, 0, CPU_XOP, 0, 0}, + {"vcmpunordsd", ssecmp_64_insn, 4, SUF_Z, 0x03, 0xF2, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"minps", xmm_xmm128_insn, 2, SUF_Z, 0x00, 0x5D, 0, 0, CPU_SSE, 0, 0}, + {"vaesimc", aesimc_insn, 1, SUF_Z, 0x38, 0xDB, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"movhps", movhlp_insn, 3, SUF_Z, 0x00, 0x16, 0, 0, CPU_SSE, 0, 0}, + {"vdivps", xmm_xmm128_256_insn, 4, SUF_Z, 0x00, 0x5E, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"filds", fildstp_insn, 4, SUF_S, 0x00, 0x02, 0x05, 0, CPU_FPU, 0, 0}, + {"adc", arith_insn, 22, SUF_Z, 0x10, 0x02, 0, 0, 0, 0, 0}, + {"vtestpd", sse4_insn, 2, SUF_Z, 0x0F, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"pfpnacc", now3d_insn, 1, SUF_Z, 0x8E, 0, 0, 0, CPU_3DNow, CPU_Athlon, 0}, + {"vmovsldup", avx_xmm_xmm128_insn, 2, SUF_Z, 0xF3, 0x12, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpbroadcastb", vpbroadcastb_avx2_insn, 4, SUF_Z, 0, 0, 0, ONLY_AVX, CPU_AVX2, 0, 0}, + {"sahf", onebyte_insn, 1, SUF_Z, 0x9E, 0, 0, 0, 0, 0, 0}, + {"vmovhps", movhlp_insn, 3, SUF_Z, 0x00, 0x16, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"fpatan", twobyte_insn, 1, SUF_Z, 0xD9, 0xF3, 0, 0, CPU_FPU, 0, 0}, + {"psubw", mmxsse2_insn, 2, SUF_Z, 0xF9, 0, 0, 0, CPU_MMX, 0, 0}, + {"sqrtss", xmm_xmm32_insn, 4, SUF_Z, 0xF3, 0x51, 0, 0, CPU_SSE, 0, 0}, + {"vpminuw", ssse3_insn, 5, SUF_Z, 0x3A, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"rex64z", NULL, X86_REX>>8, 0x49, 0, 0, 0, ONLY_64, 0, 0, 0}, + {"cmovng", cmovcc_insn, 3, SUF_Z, 0x0E, 0, 0, 0, CPU_686, 0, 0}, + {"cmovngq", cmovcc_insn, 3, SUF_Q, 0x0E, 0, 0, ONLY_64, CPU_686, 0, 0}, + {"blcil", xop_gpr_reg_rm_09_insn, 2, SUF_L, 0x02, 0x06, 0, 0, CPU_386, CPU_TBM, 0}, + {"setob", setcc_insn, 1, SUF_B, 0x00, 0, 0, 0, CPU_386, 0, 0}, + {"xbts", xbts_insn, 2, SUF_Z, 0, 0, 0, 0, CPU_386, CPU_Obs, CPU_Undoc}, + {"loopne", loop_insn, 8, SUF_Z, 0x00, 0, 0, 0, 0, 0, 0}, + {"fxch", fxch_insn, 4, SUF_Z, 0, 0, 0, 0, CPU_FPU, 0, 0}, + {"vfmsubadd132pd", vfma_pd_insn, 2, SUF_Z, 0x97, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"vmovddup", vmovddup_insn, 3, SUF_Z, 0xF2, 0x12, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"enterq", enter_insn, 3, SUF_Q, 0, 0, 0, ONLY_64, CPU_186, 0, 0}, + {"vpcomnequw", vpcom_insn, 1, SUF_Z, 0xED, 0x05, 0, 0, CPU_XOP, 0, 0}, + {"vpunpckhdq", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0x6A, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"fnstenvs", onebytemem_insn, 1, SUF_S, 0x06, 0xD9, 0, 0, CPU_FPU, 0, 0}, + {"phaddd", ssse3_insn, 5, SUF_Z, 0x02, 0, 0, 0, CPU_SSSE3, 0, 0}, + {"vmovups", movau_insn, 6, SUF_Z, 0x00, 0x10, 0x01, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpcomneuq", vpcom_insn, 1, SUF_Z, 0xEF, 0x05, 0, 0, CPU_XOP, 0, 0}, + {"imul", imul_insn, 19, SUF_Z, 0, 0, 0, 0, 0, 0, 0}, + {"fimuls", fiarith_insn, 2, SUF_S, 0x01, 0xDA, 0, 0, CPU_FPU, 0, 0}, + {"jg", jcc_insn, 9, SUF_Z, 0x0F, 0, 0, 0, 0, 0, 0}, + {"fcoml", fcom_insn, 6, SUF_L, 0xD0, 0x02, 0, 0, CPU_FPU, 0, 0}, + {"vxorpd", xmm_xmm128_256_insn, 4, SUF_Z, 0x66, 0x57, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vfmaddsubps", fma_128_256_insn, 4, SUF_Z, 0x5C, 0, 0, ONLY_AVX, CPU_FMA4, 0, 0}, + {"vpaddw", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0xFD, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vbroadcasti128", vbroadcastif128_insn, 1, SUF_Z, 0x5A, 0, 0, ONLY_AVX, CPU_AVX2, 0, 0}, + {"vcvttpd2dqy", avx_cvt_xmm128_y_insn, 1, SUF_Z, 0x66, 0xE6, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"mov", mov_insn, 69, SUF_Z, 0, 0, 0, 0, 0, 0, 0}, + {"fmull", farith_insn, 7, SUF_L, 0xC8, 0xC8, 0x01, 0, CPU_FPU, 0, 0}, + {"vpcomfalseub", vpcom_insn, 1, SUF_Z, 0xEC, 0x06, 0, 0, CPU_XOP, 0, 0}, + {"xaddq", cmpxchgxadd_insn, 4, SUF_Q, 0xC0, 0, 0, ONLY_64, CPU_486, 0, 0}, + {"inl", in_insn, 12, SUF_L, 0, 0, 0, 0, CPU_386, 0, 0}, + {"t1mskcl", xop_gpr_reg_rm_09_insn, 2, SUF_L, 0x01, 0x07, 0, 0, CPU_386, CPU_TBM, 0}, + {"nop", onebyte_insn, 1, SUF_Z, 0x90, 0, 0, 0, 0, 0, 0}, + {"rexx", NULL, X86_REX>>8, 0x44, 0, 0, 0, ONLY_64, 0, 0, 0}, + {"vperm2f128", vperm2f128_insn, 1, SUF_Z, 0, 0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"tzcnt", cnt_insn, 3, SUF_Z, 0xBC, 0, 0, 0, CPU_BMI1, 0, 0}, + {"hlt", onebyte_insn, 1, SUF_Z, 0xF4, 0, 0, 0, CPU_Priv, 0, 0}, + {"vcmpeq_uqpd", ssecmp_128_insn, 3, SUF_Z, 0x08, 0x66, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"sgdt", twobytemem_insn, 1, SUF_Z, 0x00, 0x0F, 0x01, 0, CPU_286, CPU_Priv, 0}, + {"cwtl", onebyte_insn, 1, SUF_Z, 0x98, 0x20, 0, 0, CPU_386, 0, 0}, + {"xorl", arith_insn, 22, SUF_L, 0x30, 0x06, 0, 0, CPU_386, 0, 0}, + {"movapd", movau_insn, 6, SUF_Z, 0x66, 0x28, 0x01, 0, CPU_SSE2, 0, 0}, + {"vpmovsxwq", sse4m32_insn, 4, SUF_Z, 0x24, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vfmsubadd231pd", vfma_pd_insn, 2, SUF_Z, 0xB7, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"cvttsd2sil", cvt_rx_xmm64_insn, 4, SUF_L, 0xF2, 0x2C, 0, 0, CPU_SSE2, 0, 0}, + {"cmpunordss", ssecmp_32_insn, 4, SUF_Z, 0x03, 0xF3, 0, 0, CPU_SSE, 0, 0}, + {"vpcomneq", vpcom_insn, 1, SUF_Z, 0xCF, 0x05, 0, 0, CPU_XOP, 0, 0}, + {"ffreep", ffree_insn, 1, SUF_Z, 0xDF, 0, 0, 0, CPU_686, CPU_FPU, CPU_Undoc}, + {"vfnmsub213ss", vfma_ss_insn, 2, SUF_Z, 0xAF, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"outsb", onebyte_insn, 1, SUF_Z, 0x6E, 0x00, 0, 0, 0, 0, 0}, + {"psubsiw", cyrixmmx_insn, 1, SUF_Z, 0x55, 0, 0, 0, CPU_Cyrix, CPU_MMX, 0}, + {"jng", jcc_insn, 9, SUF_Z, 0x0E, 0, 0, 0, 0, 0, 0}, + {"vpcomltd", vpcom_insn, 1, SUF_Z, 0xCE, 0x00, 0, 0, CPU_XOP, 0, 0}, + {"t1mskcq", xop_gpr_reg_rm_09_insn, 2, SUF_Q, 0x01, 0x07, 0, ONLY_64, CPU_TBM, 0, 0}, + {"rdmsr", twobyte_insn, 1, SUF_Z, 0x0F, 0x32, 0, 0, CPU_586, CPU_Priv, 0}, + {"notb", f6_insn, 4, SUF_B, 0x02, 0, 0, 0, 0, 0, 0}, + {"idiv", div_insn, 8, SUF_Z, 0x07, 0, 0, 0, 0, 0, 0}, + {"vpshuflw", xmm_xmm128_imm_256avx2_insn, 2, SUF_Z, 0xF2, 0x70, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"paddd", mmxsse2_insn, 2, SUF_Z, 0xFE, 0, 0, 0, CPU_MMX, 0, 0}, + {"tzcntw", cnt_insn, 3, SUF_W, 0xBC, 0, 0, 0, CPU_BMI1, 0, 0}, + {"pcmpgtd", mmxsse2_insn, 2, SUF_Z, 0x66, 0, 0, 0, CPU_MMX, 0, 0}, + {"stosq", onebyte_insn, 1, SUF_Z, 0xAB, 0x40, 0, ONLY_64, 0, 0, 0}, + {"arplw", arpl_insn, 1, SUF_W, 0, 0, 0, NOT_64, CPU_286, CPU_Prot, 0}, + {"vpermilps", vpermil_insn, 4, SUF_Z, 0x04, 0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vfnmadd231ps", vfma_ps_insn, 2, SUF_Z, 0xBC, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"xadd", cmpxchgxadd_insn, 4, SUF_Z, 0xC0, 0, 0, 0, CPU_486, 0, 0}, + {"shrdl", shlrd_insn, 9, SUF_L, 0xAC, 0, 0, 0, CPU_386, 0, 0}, + {"fscale", twobyte_insn, 1, SUF_Z, 0xD9, 0xFD, 0, 0, CPU_FPU, 0, 0}, + {"rdpmc", twobyte_insn, 1, SUF_Z, 0x0F, 0x33, 0, 0, CPU_686, 0, 0}, + {"cvtpi2ps", cvt_xmm_mm_ps_insn, 1, SUF_Z, 0x2A, 0, 0, 0, CPU_SSE, 0, 0}, + {"cmovgq", cmovcc_insn, 3, SUF_Q, 0x0F, 0, 0, ONLY_64, CPU_686, 0, 0}, + {"vfnmsubps", fma_128_256_insn, 4, SUF_Z, 0x7C, 0, 0, ONLY_AVX, CPU_FMA4, 0, 0}, + {"seto", setcc_insn, 1, SUF_Z, 0x00, 0, 0, 0, CPU_386, 0, 0}, + {"jnae", jcc_insn, 9, SUF_Z, 0x02, 0, 0, 0, 0, 0, 0}, + {"popcntw", cnt_insn, 3, SUF_W, 0xB8, 0, 0, 0, CPU_SSE42, 0, 0}, + {"vpgatherqd", gather_32x_32y_128_insn, 2, SUF_Z, 0x91, 0, 0, ONLY_AVX, CPU_AVX2, 0, 0}, + {"salc", onebyte_insn, 1, SUF_Z, 0xD6, 0, 0, NOT_64, CPU_Undoc, 0, 0}, + {"vcmpngesd", ssecmp_64_insn, 4, SUF_Z, 0x09, 0xF2, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpcomgeud", vpcom_insn, 1, SUF_Z, 0xEE, 0x03, 0, 0, CPU_XOP, 0, 0}, + {"blcicq", xop_gpr_reg_rm_09_insn, 2, SUF_Q, 0x01, 0x05, 0, ONLY_64, CPU_TBM, 0, 0}, + {"pcmpestri", sse4pcmpstr_insn, 1, SUF_Z, 0x61, 0, 0, 0, CPU_SSE42, 0, 0}, + {"sarxq", vex_gpr_reg_rm_nds_0F_insn, 2, SUF_Q, 0xF3, 0x38, 0xF7, ONLY_64|ONLY_AVX, CPU_BMI2, 0, 0}, + {"lddqu", lddqu_insn, 2, SUF_Z, 0, 0, 0, 0, CPU_SSE3, 0, 0}, + {"vpcomtruew", vpcom_insn, 1, SUF_Z, 0xCD, 0x07, 0, 0, CPU_XOP, 0, 0}, + {"fxam", twobyte_insn, 1, SUF_Z, 0xD9, 0xE5, 0, 0, CPU_FPU, 0, 0}, + {"crc32b", crc32_insn, 5, SUF_B, 0, 0, 0, 0, CPU_386, CPU_SSE42, 0}, + {"vpinsrw", pinsrw_insn, 9, SUF_Z, 0xC0, 0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vphsubdq", vphaddsub_insn, 1, SUF_Z, 0xE3, 0, 0, 0, CPU_XOP, 0, 0}, + {"vfmsubaddps", fma_128_256_insn, 4, SUF_Z, 0x5E, 0, 0, ONLY_AVX, CPU_FMA4, 0, 0}, + {"btw", bittest_insn, 6, SUF_W, 0xA3, 0x04, 0, 0, CPU_386, 0, 0}, + {"pi2fw", now3d_insn, 1, SUF_Z, 0x0C, 0, 0, 0, CPU_3DNow, CPU_Athlon, 0}, + {"movhlps", movhllhps_insn, 2, SUF_Z, 0x12, 0, 0, 0, CPU_SSE, 0, 0}, + {"divsd", xmm_xmm64_insn, 4, SUF_Z, 0xF2, 0x5E, 0, 0, CPU_SSE2, 0, 0}, + {"vcmpge_oqps", ssecmp_128_insn, 3, SUF_Z, 0x1D, 0x00, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"rexxyz", NULL, X86_REX>>8, 0x47, 0, 0, 0, ONLY_64, 0, 0, 0}, + {"pf2id", now3d_insn, 1, SUF_Z, 0x1D, 0, 0, 0, CPU_3DNow, 0, 0}, + {"andnps", xmm_xmm128_insn, 2, SUF_Z, 0x00, 0x55, 0, 0, CPU_SSE, 0, 0}, + {"cmovzq", cmovcc_insn, 3, SUF_Q, 0x04, 0, 0, ONLY_64, CPU_686, 0, 0}, + {"cwd", onebyte_insn, 1, SUF_Z, 0x99, 0x10, 0, 0, 0, 0, 0}, + {"blcsl", xop_gpr_reg_rm_09_insn, 2, SUF_L, 0x01, 0x03, 0, 0, CPU_386, CPU_TBM, 0}, + {"maxps", xmm_xmm128_insn, 2, SUF_Z, 0x00, 0x5F, 0, 0, CPU_SSE, 0, 0}, + {"comisd", xmm_xmm64_insn, 4, SUF_Z, 0x66, 0x2F, 0, 0, CPU_SSE2, 0, 0}, + {"vcmpnle_uqps", ssecmp_128_insn, 3, SUF_Z, 0x16, 0x00, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"cmovnzq", cmovcc_insn, 3, SUF_Q, 0x05, 0, 0, ONLY_64, CPU_686, 0, 0}, + {"ljmpw", ljmpcall_insn, 7, SUF_W, 0x05, 0xEA, 0, 0, 0, 0, 0}, + {"cmpeqps", ssecmp_128_insn, 3, SUF_Z, 0x00, 0, 0, 0, CPU_SSE, 0, 0}, + {"orb", arith_insn, 22, SUF_B, 0x08, 0x01, 0, 0, 0, 0, 0}, + {"fists", fiarith_insn, 2, SUF_S, 0x02, 0xDB, 0, 0, CPU_FPU, 0, 0}, + {"vmaskmovps", vmaskmov_insn, 4, SUF_Z, 0x2C, 0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"xend", tsx_0x0F_0x01_insn, 1, SUF_Z, 0xD5, 0, 0, 0, CPU_TSX, 0, 0}, + {"fiadd", fiarith_insn, 2, SUF_Z, 0x00, 0xDA, 0, 0, CPU_FPU, 0, 0}, + {"jns", jcc_insn, 9, SUF_Z, 0x09, 0, 0, 0, 0, 0, 0}, + {"vpcomfalseuw", vpcom_insn, 1, SUF_Z, 0xED, 0x06, 0, 0, CPU_XOP, 0, 0}, + {"bsrl", bsfr_insn, 3, SUF_L, 0xBD, 0, 0, 0, CPU_386, 0, 0}, + {"pabsb", ssse3_insn, 5, SUF_Z, 0x1C, 0, 0, 0, CPU_SSSE3, 0, 0}, + {"vcmptruess", ssecmp_32_insn, 4, SUF_Z, 0x0F, 0xF3, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"sal", shift_insn, 16, SUF_Z, 0x04, 0, 0, 0, 0, 0, 0}, + {"movzbl", movszx_insn, 5, SUF_B, 0xB6, 0, 0, 0, CPU_386, 0, 0}, + {"packssdw", mmxsse2_insn, 2, SUF_Z, 0x6B, 0, 0, 0, CPU_MMX, 0, 0}, + {"fcmovbe", fcmovcc_insn, 1, SUF_Z, 0xDA, 0xD0, 0, 0, CPU_686, CPU_FPU, 0}, + {"orq", arith_insn, 22, SUF_Q, 0x08, 0x01, 0, ONLY_64, 0, 0, 0}, + {"blsicq", xop_gpr_reg_rm_09_insn, 2, SUF_Q, 0x01, 0x06, 0, ONLY_64, CPU_TBM, 0, 0}, + {"fiaddl", fiarith_insn, 2, SUF_L, 0x00, 0xDA, 0, 0, CPU_FPU, 0, 0}, + {"fprem", twobyte_insn, 1, SUF_Z, 0xD9, 0xF8, 0, 0, CPU_FPU, 0, 0}, + {"vpcomltw", vpcom_insn, 1, SUF_Z, 0xCD, 0x00, 0, 0, CPU_XOP, 0, 0}, + {"sarl", shift_insn, 16, SUF_L, 0x07, 0, 0, 0, CPU_386, 0, 0}, + {"shr", shift_insn, 16, SUF_Z, 0x05, 0, 0, 0, 0, 0, 0}, + {"pushl", push_insn, 35, SUF_L, 0, 0, 0, 0, CPU_386, 0, 0}, + {"imull", imul_insn, 19, SUF_L, 0, 0, 0, 0, CPU_386, 0, 0}, + {"ftst", twobyte_insn, 1, SUF_Z, 0xD9, 0xE4, 0, 0, CPU_FPU, 0, 0}, + {"vcmpeqps", ssecmp_128_insn, 3, SUF_Z, 0x00, 0x00, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"lcalll", ljmpcall_insn, 7, SUF_L, 0x03, 0x9A, 0, 0, CPU_386, 0, 0}, + {"lock", NULL, X86_LOCKREP>>8, 0xF0, 0, 0, 0, 0, 0, 0, 0}, + {"cmovnbw", cmovcc_insn, 3, SUF_W, 0x03, 0, 0, 0, CPU_686, 0, 0}, + {"movzxw", movszx_insn, 5, SUF_W, 0xB6, 0, 0, 0, CPU_386, 0, 0}, + {"or", arith_insn, 22, SUF_Z, 0x08, 0x01, 0, 0, 0, 0, 0}, + {"vcmpnle_uqpd", ssecmp_128_insn, 3, SUF_Z, 0x16, 0x66, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"setl", setcc_insn, 1, SUF_Z, 0x0C, 0, 0, 0, CPU_386, 0, 0}, + {"movntiq", movnti_insn, 2, SUF_Q, 0, 0, 0, ONLY_64, CPU_P4, 0, 0}, + {"lfs", lfgss_insn, 3, SUF_Z, 0xB4, 0, 0, 0, CPU_386, 0, 0}, + {"vroundss", sse4m32imm_insn, 4, SUF_Z, 0x0A, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"setzb", setcc_insn, 1, SUF_B, 0x04, 0, 0, 0, CPU_386, 0, 0}, + {"pcmpistrm", sse4pcmpstr_insn, 1, SUF_Z, 0x62, 0, 0, 0, CPU_SSE42, 0, 0}, + {"je", jcc_insn, 9, SUF_Z, 0x04, 0, 0, 0, 0, 0, 0}, + {"psraw", pshift_insn, 4, SUF_Z, 0xE1, 0x71, 0x04, 0, CPU_MMX, 0, 0}, + {"shlx", vex_gpr_reg_rm_nds_0F_insn, 2, SUF_Z, 0x66, 0x38, 0xF7, ONLY_AVX, CPU_BMI2, 0, 0}, + {"mfence", threebyte_insn, 1, SUF_Z, 0x0F, 0xAE, 0xF0, 0, CPU_P3, 0, 0}, + {"vcvtsd2siq", cvt_rx_xmm64_insn, 4, SUF_Q, 0xF2, 0x2D, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vtestps", sse4_insn, 2, SUF_Z, 0x0E, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"verww", prot286_insn, 1, SUF_W, 0x05, 0x00, 0, 0, CPU_286, CPU_Prot, 0}, + {"vfmsubaddpd", fma_128_256_insn, 4, SUF_Z, 0x5F, 0, 0, ONLY_AVX, CPU_FMA4, 0, 0}, + {"fyl2xp1", twobyte_insn, 1, SUF_Z, 0xD9, 0xF9, 0, 0, CPU_FPU, 0, 0}, + {"vunpckhpd", xmm_xmm128_256_insn, 4, SUF_Z, 0x66, 0x15, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vsubps", xmm_xmm128_256_insn, 4, SUF_Z, 0x00, 0x5C, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"divss", xmm_xmm32_insn, 4, SUF_Z, 0xF3, 0x5E, 0, 0, CPU_SSE, 0, 0}, + {"blcfilll", xop_gpr_reg_rm_09_insn, 2, SUF_L, 0x01, 0x01, 0, 0, CPU_386, CPU_TBM, 0}, + {"vcmptrue_uspd", ssecmp_128_insn, 3, SUF_Z, 0x1F, 0x66, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vorpd", xmm_xmm128_256_insn, 4, SUF_Z, 0x66, 0x56, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"setgeb", setcc_insn, 1, SUF_B, 0x0D, 0, 0, 0, CPU_386, 0, 0}, + {"vmxon", vmxthreebytemem_insn, 1, SUF_Z, 0xF3, 0, 0, 0, CPU_P4, 0, 0}, + {"vpmaskmovd", vmaskmov_insn, 4, SUF_Z, 0x8C, 0, 0, ONLY_AVX, CPU_AVX2, 0, 0}, + {"vfnmaddpd", fma_128_256_insn, 4, SUF_Z, 0x79, 0, 0, ONLY_AVX, CPU_FMA4, 0, 0}, + {"cmovpl", cmovcc_insn, 3, SUF_L, 0x0A, 0, 0, 0, CPU_686, 0, 0}, + {"pabsw", ssse3_insn, 5, SUF_Z, 0x1D, 0, 0, 0, CPU_SSSE3, 0, 0}, + {"cmovnge", cmovcc_insn, 3, SUF_Z, 0x0C, 0, 0, 0, CPU_686, 0, 0}, + {"aword", NULL, X86_ADDRSIZE>>8, 0x10, 0, 0, 0, 0, 0, 0, 0}, + {"sscaq", onebyte_insn, 1, SUF_Z, 0xAF, 0x40, 0, ONLY_64, 0, 0, 0}, + {"fstenvs", twobytemem_insn, 1, SUF_S, 0x06, 0x9B, 0xD9, 0, CPU_FPU, 0, 0}, + {"vpmovzxbw", sse4m64_insn, 4, SUF_Z, 0x30, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpsllw", vpshift_insn, 8, SUF_Z, 0xF1, 0x71, 0x06, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpabsw", avx2_ssse3_2op_insn, 2, SUF_Z, 0x1D, 0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"popf", onebyte_insn, 1, SUF_Z, 0x9D, 0x00, 0x40, 0, 0, 0, 0}, + {"vcmpunord_sss", ssecmp_32_insn, 4, SUF_Z, 0x13, 0xF3, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"bsf", bsfr_insn, 3, SUF_Z, 0xBC, 0, 0, 0, CPU_386, 0, 0}, + {"cmovaw", cmovcc_insn, 3, SUF_W, 0x07, 0, 0, 0, CPU_686, 0, 0}, + {"psrlq", pshift_insn, 4, SUF_Z, 0xD3, 0x73, 0x02, 0, CPU_MMX, 0, 0}, + {"divw", div_insn, 8, SUF_W, 0x06, 0, 0, 0, 0, 0, 0}, + {"cmovnal", cmovcc_insn, 3, SUF_L, 0x06, 0, 0, 0, CPU_686, 0, 0}, + {"vpcmpeqq", ssse3_insn, 5, SUF_Z, 0x29, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"cmovnaq", cmovcc_insn, 3, SUF_Q, 0x06, 0, 0, ONLY_64, CPU_686, 0, 0}, + {"cmove", cmovcc_insn, 3, SUF_Z, 0x04, 0, 0, 0, CPU_686, 0, 0}, + {"popaw", onebyte_insn, 1, SUF_Z, 0x61, 0x10, 0, NOT_64, CPU_186, 0, 0}, + {"invvpidq", eptvpid_insn, 2, SUF_Q, 0x01, 0, 0, ONLY_64, CPU_EPTVPID, 0, 0}, + {"vcvtdq2ps", avx_xmm_xmm128_insn, 2, SUF_Z, 0x00, 0x5B, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vrcpps", avx_xmm_xmm128_insn, 2, SUF_Z, 0x00, 0x53, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"packsswb", mmxsse2_insn, 2, SUF_Z, 0x63, 0, 0, 0, CPU_MMX, 0, 0}, + {"sarw", shift_insn, 16, SUF_W, 0x07, 0, 0, 0, 0, 0, 0}, + {"pfrcpit1", now3d_insn, 1, SUF_Z, 0xA6, 0, 0, 0, CPU_3DNow, 0, 0}, + {"btcl", bittest_insn, 6, SUF_L, 0xBB, 0x07, 0, 0, CPU_386, 0, 0}, + {"rolb", shift_insn, 16, SUF_B, 0x00, 0, 0, 0, 0, 0, 0}, + {"vphadddq", vphaddsub_insn, 1, SUF_Z, 0xCB, 0, 0, 0, CPU_XOP, 0, 0}, + {"vpmaxsw", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0xEE, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpminsw", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0xEA, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"jnz", jcc_insn, 9, SUF_Z, 0x05, 0, 0, 0, 0, 0, 0}, + {"vphsubd", ssse3_insn, 5, SUF_Z, 0x06, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vblendvps", avx_sse4xmm0_insn, 2, SUF_Z, 0x4A, 0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vhaddps", xmm_xmm128_256_insn, 4, SUF_Z, 0xF2, 0x7C, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"lidtl", twobytemem_insn, 1, SUF_L, 0x03, 0x0F, 0x01, 0, CPU_286, CPU_Priv, 0}, + {"divq", div_insn, 8, SUF_Q, 0x06, 0, 0, ONLY_64, 0, 0, 0}, + {"outb", out_insn, 12, SUF_B, 0, 0, 0, 0, 0, 0, 0}, + {"setnsb", setcc_insn, 1, SUF_B, 0x09, 0, 0, 0, CPU_386, 0, 0}, + {"vcmpfalse_ospd", ssecmp_128_insn, 3, SUF_Z, 0x1B, 0x66, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"jnb", jcc_insn, 9, SUF_Z, 0x03, 0, 0, 0, 0, 0, 0}, + {"vpmovsxdq", sse4m64_insn, 4, SUF_Z, 0x25, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"adcw", arith_insn, 22, SUF_W, 0x10, 0x02, 0, 0, 0, 0, 0}, + {"cmovbel", cmovcc_insn, 3, SUF_L, 0x06, 0, 0, 0, CPU_686, 0, 0}, + {"cmovaeq", cmovcc_insn, 3, SUF_Q, 0x03, 0, 0, ONLY_64, CPU_686, 0, 0}, + {"fcmovnu", fcmovcc_insn, 1, SUF_Z, 0xDB, 0xD8, 0, 0, CPU_686, CPU_FPU, 0}, + {"idivb", div_insn, 8, SUF_B, 0x07, 0, 0, 0, 0, 0, 0}, + {"sgdtl", twobytemem_insn, 1, SUF_L, 0x00, 0x0F, 0x01, 0, CPU_286, CPU_Priv, 0}, + {"jmpl", jmp_insn, 31, SUF_L, 0, 0, 0, 0, CPU_386, 0, 0}, + {"fisttp", fildstp_insn, 4, SUF_Z, 0x01, 0x00, 0x01, 0, CPU_SSE3, 0, 0}, + {"vcmpord_sps", ssecmp_128_insn, 3, SUF_Z, 0x17, 0x00, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"haddps", xmm_xmm128_insn, 2, SUF_Z, 0xF2, 0x7C, 0, 0, CPU_SSE3, 0, 0}, + {"rolw", shift_insn, 16, SUF_W, 0x00, 0, 0, 0, 0, 0, 0}, + {"vcvtpd2dqy", avx_cvt_xmm128_y_insn, 1, SUF_Z, 0xF2, 0xE6, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"bt", bittest_insn, 6, SUF_Z, 0xA3, 0x04, 0, 0, CPU_386, 0, 0}, + {"vcmpfalsepd", ssecmp_128_insn, 3, SUF_Z, 0x0B, 0x66, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vcmpleps", ssecmp_128_insn, 3, SUF_Z, 0x02, 0x00, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vphaddubd", vphaddsub_insn, 1, SUF_Z, 0xD2, 0, 0, 0, CPU_XOP, 0, 0}, + {"vfnmsub132ss", vfma_ss_insn, 2, SUF_Z, 0x9F, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"cmovnow", cmovcc_insn, 3, SUF_W, 0x01, 0, 0, 0, CPU_686, 0, 0}, + {"cvtps2dq", xmm_xmm128_insn, 2, SUF_Z, 0x66, 0x5B, 0, 0, CPU_SSE2, 0, 0}, + {"bsrq", bsfr_insn, 3, SUF_Q, 0xBD, 0, 0, ONLY_64, CPU_386, 0, 0}, + {"vcmpord_spd", ssecmp_128_insn, 3, SUF_Z, 0x17, 0x66, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpcomd", vpcom_imm_insn, 1, SUF_Z, 0xCE, 0, 0, 0, CPU_XOP, 0, 0}, + {"jnle", jcc_insn, 9, SUF_Z, 0x0F, 0, 0, 0, 0, 0, 0}, + {"vhsubps", xmm_xmm128_256_insn, 4, SUF_Z, 0xF2, 0x7D, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"jcxz", jcxz_insn, 2, SUF_Z, 0x10, 0, 0, 0, 0, 0, 0}, + {"fsavel", twobytemem_insn, 1, SUF_L, 0x06, 0x9B, 0xDD, 0, CPU_FPU, 0, 0}, + {"cmovnbq", cmovcc_insn, 3, SUF_Q, 0x03, 0, 0, ONLY_64, CPU_686, 0, 0}, + {"lidtw", twobytemem_insn, 1, SUF_W, 0x03, 0x0F, 0x01, 0, CPU_286, CPU_Priv, 0}, + {"vcvtss2si", cvt_rx_xmm32_insn, 4, SUF_Z, 0xF3, 0x2D, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"mulw", f6_insn, 4, SUF_W, 0x04, 0, 0, 0, 0, 0, 0}, + {"vbroadcastsd", vbroadcastsd_insn, 2, SUF_Z, 0, 0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"cmovlel", cmovcc_insn, 3, SUF_L, 0x0E, 0, 0, 0, CPU_686, 0, 0}, + {"pmovmskbq", pmovmskb_insn, 6, SUF_Q, 0, 0, 0, ONLY_64, CPU_MMX, CPU_P3, 0}, + {"frstorl", onebytemem_insn, 1, SUF_L, 0x04, 0xDD, 0, 0, CPU_FPU, 0, 0}, + {"cvttss2si", cvt_rx_xmm32_insn, 4, SUF_Z, 0xF3, 0x2C, 0, 0, CPU_386, CPU_SSE, 0}, + {"cmpnltpd", ssecmp_128_insn, 3, SUF_Z, 0x05, 0x66, 0, 0, CPU_SSE, 0, 0}, + {"vpcomgtw", vpcom_insn, 1, SUF_Z, 0xCD, 0x02, 0, 0, CPU_XOP, 0, 0}, + {"xaddl", cmpxchgxadd_insn, 4, SUF_L, 0xC0, 0, 0, 0, CPU_486, 0, 0}, + {"vpmulhw", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0xE5, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"lgsq", lfgss_insn, 3, SUF_Q, 0xB5, 0, 0, ONLY_64, CPU_386, 0, 0}, + {"boundl", bound_insn, 2, SUF_L, 0, 0, 0, NOT_64, CPU_386, 0, 0}, + {"vmaxpd", xmm_xmm128_256_insn, 4, SUF_Z, 0x66, 0x5F, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"movntdqa", movntdqa_insn, 2, SUF_Z, 0, 0, 0, 0, CPU_SSE41, 0, 0}, + {"xstorerng", padlock_insn, 1, SUF_Z, 0xC0, 0x00, 0xA7, 0, CPU_PadLock, 0, 0}, + {"fxsaveq", twobytemem_insn, 1, SUF_Q, 0x00, 0x0F, 0xAE, 0, CPU_686, CPU_FPU, 0}, + {"cmplepd", ssecmp_128_insn, 3, SUF_Z, 0x02, 0x66, 0, 0, CPU_SSE, 0, 0}, + {"vpunpckhwd", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0x69, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"fiadds", fiarith_insn, 2, SUF_S, 0x00, 0xDA, 0, 0, CPU_FPU, 0, 0}, + {"bsfq", bsfr_insn, 3, SUF_Q, 0xBC, 0, 0, ONLY_64, CPU_386, 0, 0}, + {"cvtss2si", cvt_rx_xmm32_insn, 4, SUF_Z, 0xF3, 0x2D, 0, 0, CPU_386, CPU_SSE, 0}, + {"pushw", push_insn, 35, SUF_W, 0, 0, 0, 0, 0, 0, 0}, + {"vphaddsw", ssse3_insn, 5, SUF_Z, 0x03, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"prefetcht2", twobytemem_insn, 1, SUF_Z, 0x03, 0x0F, 0x18, 0, CPU_P3, 0, 0}, + {"setnae", setcc_insn, 1, SUF_Z, 0x02, 0, 0, 0, CPU_386, 0, 0}, + {"xor", arith_insn, 22, SUF_Z, 0x30, 0x06, 0, 0, 0, 0, 0}, + {"pshufw", pshufw_insn, 1, SUF_Z, 0, 0, 0, 0, CPU_MMX, CPU_P3, 0}, + {"div", div_insn, 8, SUF_Z, 0x06, 0, 0, 0, 0, 0, 0}, + {"xabort", tsx_xabort_insn, 1, SUF_Z, 0, 0, 0, 0, CPU_TSX, 0, 0}, + {"vmovntdq", movnt_insn, 2, SUF_Z, 0x66, 0xE7, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"das", onebyte_insn, 1, SUF_Z, 0x2F, 0, 0, NOT_64, 0, 0, 0}, + {"notw", f6_insn, 4, SUF_W, 0x02, 0, 0, 0, 0, 0, 0}, + {"monitor", threebyte_insn, 1, SUF_Z, 0x0F, 0x01, 0xC8, 0, CPU_SSE3, 0, 0}, + {"pmuludq", mmxsse2_insn, 2, SUF_Z, 0xF4, 0, 0, 0, CPU_SSE2, 0, 0}, + {"psignd", ssse3_insn, 5, SUF_Z, 0x0A, 0, 0, 0, CPU_SSSE3, 0, 0}, + {"vpmaxuw", ssse3_insn, 5, SUF_Z, 0x3E, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"rexxy", NULL, X86_REX>>8, 0x46, 0, 0, 0, ONLY_64, 0, 0, 0}, + {"vcmpnlt_uqps", ssecmp_128_insn, 3, SUF_Z, 0x15, 0x00, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"decq", incdec_insn, 6, SUF_Q, 0x48, 0x01, 0, ONLY_64, 0, 0, 0}, + {"fsub", farith_insn, 7, SUF_Z, 0xE8, 0xE0, 0x04, 0, CPU_FPU, 0, 0}, + {"ficoms", fiarith_insn, 2, SUF_S, 0x02, 0xDA, 0, 0, CPU_FPU, 0, 0}, + {"btrw", bittest_insn, 6, SUF_W, 0xB3, 0x06, 0, 0, CPU_386, 0, 0}, + {"vfnmsub213sd", vfma_sd_insn, 2, SUF_Z, 0xAF, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"setnob", setcc_insn, 1, SUF_B, 0x01, 0, 0, 0, CPU_386, 0, 0}, + {"vpcomgeub", vpcom_insn, 1, SUF_Z, 0xEC, 0x03, 0, 0, CPU_XOP, 0, 0}, + {"cmovz", cmovcc_insn, 3, SUF_Z, 0x04, 0, 0, 0, CPU_686, 0, 0}, + {"vpackuswb", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0x67, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"cli", onebyte_insn, 1, SUF_Z, 0xFA, 0, 0, 0, 0, 0, 0}, + {"pinsrd", pinsrd_insn, 2, SUF_Z, 0, 0, 0, 0, CPU_386, CPU_SSE41, 0}, + {"vfmsubadd213pd", vfma_pd_insn, 2, SUF_Z, 0xA7, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"setnab", setcc_insn, 1, SUF_B, 0x06, 0, 0, 0, CPU_386, 0, 0}, + {"larw", larlsl_insn, 6, SUF_W, 0x02, 0, 0, 0, CPU_286, CPU_Prot, 0}, + {"pusha", onebyte_insn, 1, SUF_Z, 0x60, 0x00, 0, NOT_64, CPU_186, 0, 0}, + {"pfadd", now3d_insn, 1, SUF_Z, 0x9E, 0, 0, 0, CPU_3DNow, 0, 0}, + {"bzhil", vex_gpr_reg_rm_nds_0F_insn, 2, SUF_L, 0x00, 0x38, 0xF5, ONLY_AVX, CPU_BMI2, 0, 0}, + {"cmovpoq", cmovcc_insn, 3, SUF_Q, 0x0B, 0, 0, ONLY_64, CPU_686, 0, 0}, + {"blsfill", xop_gpr_reg_rm_09_insn, 2, SUF_Z, 0x01, 0x02, 0, 0, CPU_386, CPU_TBM, 0}, + {"cdq", onebyte_insn, 1, SUF_Z, 0x99, 0x20, 0, 0, CPU_386, 0, 0}, + {"cvtss2siq", cvt_rx_xmm32_insn, 4, SUF_Q, 0xF3, 0x2D, 0, ONLY_64, CPU_SSE, 0, 0}, + {"cmovnb", cmovcc_insn, 3, SUF_Z, 0x03, 0, 0, 0, CPU_686, 0, 0}, + {"vcvttsd2siq", cvt_rx_xmm64_insn, 4, SUF_Q, 0xF2, 0x2C, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"setae", setcc_insn, 1, SUF_Z, 0x03, 0, 0, 0, CPU_386, 0, 0}, + {"movntps", movnt_insn, 2, SUF_Z, 0x00, 0x2B, 0, 0, CPU_SSE, 0, 0}, + {"vcmpneq_oqpd", ssecmp_128_insn, 3, SUF_Z, 0x0C, 0x66, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"lssq", lfgss_insn, 3, SUF_Q, 0xB2, 0, 0, ONLY_64, CPU_386, 0, 0}, + {"jpe", jcc_insn, 9, SUF_Z, 0x0A, 0, 0, 0, 0, 0, 0}, + {"fstcww", fstcw_insn, 1, SUF_W, 0, 0, 0, 0, CPU_FPU, 0, 0}, + {"fnsave", onebytemem_insn, 1, SUF_Z, 0x06, 0xDD, 0, 0, CPU_FPU, 0, 0}, + {"movntsd", movntsd_insn, 1, SUF_Z, 0, 0, 0, 0, CPU_SSE4a, 0, 0}, + {"pblendvb", sse4xmm0_insn, 2, SUF_Z, 0x10, 0, 0, 0, CPU_SSE41, 0, 0}, + {"enterw", enter_insn, 3, SUF_W, 0, 0, 0, 0, CPU_186, 0, 0}, + {"larl", larlsl_insn, 6, SUF_L, 0x02, 0, 0, 0, CPU_286, CPU_Prot, 0}, + {"blendvps", sse4xmm0_insn, 2, SUF_Z, 0x14, 0, 0, 0, CPU_SSE41, 0, 0}, + {"pdepl", vex_gpr_reg_nds_rm_0F_insn, 2, SUF_L, 0xF2, 0x38, 0xF5, ONLY_AVX, CPU_BMI2, 0, 0}, + {"jecxz", jcxz_insn, 2, SUF_Z, 0x20, 0, 0, 0, CPU_386, 0, 0}, + {"blcmsk", xop_gpr_reg_rm_09_insn, 2, SUF_Z, 0x02, 0x01, 0, 0, CPU_386, CPU_TBM, 0}, + {"vpshad", amd_vpshift_insn, 2, SUF_Z, 0x9A, 0, 0, 0, CPU_XOP, 0, 0}, + {"smsw", sldtmsw_insn, 6, SUF_Z, 0x04, 0x01, 0, 0, CPU_286, 0, 0}, + {"vcvttps2dq", avx_xmm_xmm128_insn, 2, SUF_Z, 0xF3, 0x5B, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vcvttss2si", cvt_rx_xmm32_insn, 4, SUF_Z, 0xF3, 0x2C, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"cmovcw", cmovcc_insn, 3, SUF_W, 0x02, 0, 0, 0, CPU_686, 0, 0}, + {"vpsubsb", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0xE8, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"pfsubr", now3d_insn, 1, SUF_Z, 0xAA, 0, 0, 0, CPU_3DNow, 0, 0}, + {"dpps", sse4imm_insn, 2, SUF_Z, 0x40, 0, 0, 0, CPU_SSE41, 0, 0}, + {"pmulhrwc", cyrixmmx_insn, 1, SUF_Z, 0x59, 0, 0, 0, CPU_Cyrix, CPU_MMX, 0}, + {"fdecstp", twobyte_insn, 1, SUF_Z, 0xD9, 0xF6, 0, 0, CPU_FPU, 0, 0}, + {"fld1", twobyte_insn, 1, SUF_Z, 0xD9, 0xE8, 0, 0, CPU_FPU, 0, 0}, + {"lslq", larlsl_insn, 6, SUF_Q, 0x03, 0, 0, ONLY_64, CPU_286, CPU_Prot, 0}, + {"movsldup", xmm_xmm128_insn, 2, SUF_Z, 0xF3, 0x12, 0, 0, CPU_SSE3, 0, 0}, + {"vfnmadd213ps", vfma_ps_insn, 2, SUF_Z, 0xAC, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"vorps", xmm_xmm128_256_insn, 4, SUF_Z, 0x00, 0x56, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"fxtract", twobyte_insn, 1, SUF_Z, 0xD9, 0xF4, 0, 0, CPU_FPU, 0, 0}, + {"xrstor", twobytemem_insn, 1, SUF_Z, 0x05, 0x0F, 0xAE, 0, CPU_386, CPU_XSAVE, 0}, + {"vfnmadd132pd", vfma_pd_insn, 2, SUF_Z, 0x9C, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"cmovsw", cmovcc_insn, 3, SUF_W, 0x08, 0, 0, 0, CPU_686, 0, 0}, + {"vpcomnew", vpcom_insn, 1, SUF_Z, 0xCD, 0x05, 0, 0, CPU_XOP, 0, 0}, + {"cmovc", cmovcc_insn, 3, SUF_Z, 0x02, 0, 0, 0, CPU_686, 0, 0}, + {"cmpxchg8bq", cmpxchg8b_insn, 1, SUF_Q, 0, 0, 0, 0, CPU_586, 0, 0}, + {"roundss", sse4m32imm_insn, 4, SUF_Z, 0x0A, 0, 0, 0, CPU_SSE41, 0, 0}, + {"vsqrtss", xmm_xmm32_insn, 4, SUF_Z, 0xF3, 0x51, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"rcrb", shift_insn, 16, SUF_B, 0x03, 0, 0, 0, 0, 0, 0}, + {"vmptrld", vmxtwobytemem_insn, 1, SUF_Z, 0x06, 0, 0, 0, CPU_P4, 0, 0}, + {"popal", onebyte_insn, 1, SUF_Z, 0x61, 0x20, 0, NOT_64, CPU_386, 0, 0}, + {"sysretq", twobyte_insn, 1, SUF_Q, 0x0F, 0x07, 0, 0, CPU_686, CPU_AMD, CPU_Priv}, + {"setle", setcc_insn, 1, SUF_Z, 0x0E, 0, 0, 0, CPU_386, 0, 0}, + {"jnl", jcc_insn, 9, SUF_Z, 0x0D, 0, 0, 0, 0, 0, 0}, + {"ucomisd", xmm_xmm64_insn, 4, SUF_Z, 0x66, 0x2E, 0, 0, CPU_SSE2, 0, 0}, + {"sbbw", arith_insn, 22, SUF_W, 0x18, 0x03, 0, 0, 0, 0, 0}, + {"fbstp", fbldstp_insn, 1, SUF_Z, 0x06, 0, 0, 0, CPU_FPU, 0, 0}, + {"vpcomtrueub", vpcom_insn, 1, SUF_Z, 0xEC, 0x07, 0, 0, CPU_XOP, 0, 0}, + {"paddb", mmxsse2_insn, 2, SUF_Z, 0xFC, 0, 0, 0, CPU_MMX, 0, 0}, + {"cmovnll", cmovcc_insn, 3, SUF_L, 0x0D, 0, 0, 0, CPU_686, 0, 0}, + {"cvtss2sd", xmm_xmm32_insn, 4, SUF_Z, 0xF3, 0x5A, 0, 0, CPU_SSE2, 0, 0}, + {"vpcmpeqd", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0x76, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"cmovnl", cmovcc_insn, 3, SUF_Z, 0x0D, 0, 0, 0, CPU_686, 0, 0}, + {"vpcomltb", vpcom_insn, 1, SUF_Z, 0xCC, 0x00, 0, 0, CPU_XOP, 0, 0}, + {"setngb", setcc_insn, 1, SUF_B, 0x0E, 0, 0, 0, CPU_386, 0, 0}, + {"vphaddudq", vphaddsub_insn, 1, SUF_Z, 0xDB, 0, 0, 0, CPU_XOP, 0, 0}, + {"vpmovsxbd", sse4m32_insn, 4, SUF_Z, 0x21, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"loopzq", loopq_insn, 4, SUF_Z, 0x01, 0x40, 0, ONLY_64, 0, 0, 0}, + {"cmovnle", cmovcc_insn, 3, SUF_Z, 0x0F, 0, 0, 0, CPU_686, 0, 0}, + {"vcmpgepd", ssecmp_128_insn, 3, SUF_Z, 0x0D, 0x66, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"btcq", bittest_insn, 6, SUF_Q, 0xBB, 0x07, 0, ONLY_64, CPU_386, 0, 0}, + {"rcrl", shift_insn, 16, SUF_L, 0x03, 0, 0, 0, CPU_386, 0, 0}, + {"vmovntdqa", movntdqa_insn, 2, SUF_Z, 0xC0, 0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"cmovcl", cmovcc_insn, 3, SUF_L, 0x02, 0, 0, 0, CPU_686, 0, 0}, + {"vcmpeq_ospd", ssecmp_128_insn, 3, SUF_Z, 0x10, 0x66, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"f2xm1", twobyte_insn, 1, SUF_Z, 0xD9, 0xF0, 0, 0, CPU_FPU, 0, 0}, + {"vpmacssdd", vpma_insn, 1, SUF_Z, 0x8E, 0, 0, 0, CPU_XOP, 0, 0}, + {"leal", lea_insn, 3, SUF_L, 0, 0, 0, 0, CPU_386, 0, 0}, + {"vpcomeqd", vpcom_insn, 1, SUF_Z, 0xCE, 0x04, 0, 0, CPU_XOP, 0, 0}, + {"ljmpq", ljmpcall_insn, 7, SUF_Q, 0x05, 0xEA, 0, ONLY_64, 0, 0, 0}, + {"vpbroadcastd", vpbroadcastd_avx2_insn, 4, SUF_Z, 0, 0, 0, ONLY_AVX, CPU_AVX2, 0, 0}, + {"jnp", jcc_insn, 9, SUF_Z, 0x0B, 0, 0, 0, 0, 0, 0}, + {"vpcomgeuq", vpcom_insn, 1, SUF_Z, 0xEF, 0x03, 0, 0, CPU_XOP, 0, 0}, + {"prefetchnta", twobytemem_insn, 1, SUF_Z, 0x00, 0x0F, 0x18, 0, CPU_P3, 0, 0}, + {"bswapl", bswap_insn, 2, SUF_L, 0, 0, 0, 0, CPU_486, 0, 0}, + {"pmovsxbd", sse4m32_insn, 4, SUF_Z, 0x21, 0, 0, 0, CPU_SSE41, 0, 0}, + {"lzcnt", cnt_insn, 3, SUF_Z, 0xBD, 0, 0, 0, CPU_LZCNT, 0, 0}, + {"sha256msg1", intel_SHA256MSG1_insn, 1, SUF_Z, 0, 0, 0, 0, CPU_SHA, 0, 0}, + {"cmovnaw", cmovcc_insn, 3, SUF_W, 0x06, 0, 0, 0, CPU_686, 0, 0}, + {"ficom", fiarith_insn, 2, SUF_Z, 0x02, 0xDA, 0, 0, CPU_FPU, 0, 0}, + {"vmovntpd", movnt_insn, 2, SUF_Z, 0x66, 0x2B, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vcmpngess", ssecmp_32_insn, 4, SUF_Z, 0x09, 0xF3, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"fisubr", fiarith_insn, 2, SUF_Z, 0x05, 0xDA, 0, 0, CPU_FPU, 0, 0}, + {"vfmaddsub132ps", vfma_ps_insn, 2, SUF_Z, 0x96, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"vaddsubps", xmm_xmm128_256_insn, 4, SUF_Z, 0xF2, 0xD0, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpbroadcastq", vpbroadcastq_avx2_insn, 4, SUF_Z, 0, 0, 0, ONLY_AVX, CPU_AVX2, 0, 0}, + {"cmovlq", cmovcc_insn, 3, SUF_Q, 0x0C, 0, 0, ONLY_64, CPU_686, 0, 0}, + {"inveptq", eptvpid_insn, 2, SUF_Q, 0x00, 0, 0, ONLY_64, CPU_EPTVPID, 0, 0}, + {"vmulps", xmm_xmm128_256_insn, 4, SUF_Z, 0x00, 0x59, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"pclmulqdq", pclmulqdq_insn, 2, SUF_Z, 0x3A, 0x44, 0, 0, CPU_AVX, 0, 0}, + {"vfmsub213ps", vfma_ps_insn, 2, SUF_Z, 0xAA, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"phsubd", ssse3_insn, 5, SUF_Z, 0x06, 0, 0, 0, CPU_SSSE3, 0, 0}, + {"fmulp", farithp_insn, 3, SUF_Z, 0xC8, 0, 0, 0, CPU_FPU, 0, 0}, + {"lcallw", ljmpcall_insn, 7, SUF_W, 0x03, 0x9A, 0, 0, 0, 0, 0}, + {"fisub", fiarith_insn, 2, SUF_Z, 0x04, 0xDA, 0, 0, CPU_FPU, 0, 0}, + {"vpackusdw", ssse3_insn, 5, SUF_Z, 0x2B, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"smintold", twobyte_insn, 1, SUF_Z, 0x0F, 0x7E, 0, 0, CPU_486, CPU_Cyrix, CPU_Obs}, + {"vpgatherqq", gather_64x_64y_insn, 2, SUF_Z, 0x91, 0, 0, ONLY_AVX, CPU_AVX2, 0, 0}, + {"vcmpneq_uspd", ssecmp_128_insn, 3, SUF_Z, 0x14, 0x66, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"blsiq", vex_gpr_ndd_rm_0F38_regext_insn, 2, SUF_Q, 0x00, 0xF3, 0x03, ONLY_64|ONLY_AVX, CPU_BMI1, 0, 0}, + {"ltr", prot286_insn, 1, SUF_Z, 0x03, 0x00, 0, 0, CPU_286, CPU_Priv, CPU_Prot}, + {"fild", fildstp_insn, 4, SUF_Z, 0x00, 0x02, 0x05, 0, CPU_FPU, 0, 0}, + {"fldenvs", onebytemem_insn, 1, SUF_S, 0x04, 0xD9, 0, 0, CPU_FPU, 0, 0}, + {"vmovdqa", movau_insn, 6, SUF_Z, 0x66, 0x6F, 0x10, ONLY_AVX, CPU_AVX, 0, 0}, + {"shrxq", vex_gpr_reg_rm_nds_0F_insn, 2, SUF_Q, 0xF2, 0x38, 0xF7, ONLY_64|ONLY_AVX, CPU_BMI2, 0, 0}, + {"fcmove", fcmovcc_insn, 1, SUF_Z, 0xDA, 0xC8, 0, 0, CPU_686, CPU_FPU, 0}, + {"shrl", shift_insn, 16, SUF_L, 0x05, 0, 0, 0, CPU_386, 0, 0}, + {"rclq", shift_insn, 16, SUF_Q, 0x02, 0, 0, ONLY_64, 0, 0, 0}, + {"fnsavel", onebytemem_insn, 1, SUF_L, 0x06, 0xDD, 0, 0, CPU_FPU, 0, 0}, + {"vgatherdpd", gather_64x_64x_insn, 2, SUF_Z, 0x92, 0, 0, ONLY_AVX, CPU_AVX2, 0, 0}, + {"pushaw", onebyte_insn, 1, SUF_Z, 0x60, 0x10, 0, NOT_64, CPU_186, 0, 0} + }; + static const unsigned short tab[] = { + 555,1559,555,108,108,1495,0,108,0,0,2332,555,1208,0,108,1317, + 1317,1732,0,0,1495,555,463,517,1636,1317,988,0,1317,0,555,555, + 1929,108,1325,0,274,555,1633,1633,555,555,1325,555,2040,274,1325,1383, + 555,1383,0,555,1317,988,1732,555,274,1636,1633,1602,1325,1383,0,0, + 1325,1929,2332,1514,1383,108,0,0,1383,0,0,988,1317,274,1325,1633, + 1325,517,1383,0,0,1633,108,274,1325,555,108,0,939,0,1636,274, + 0,1995,274,1929,1383,0,0,1317,1929,555,0,0,0,555,0,0, + 0,0,0,1514,1383,1633,1325,0,1633,0,1325,274,0,274,1317,0, + 1602,1317,0,2260,555,1633,1633,0,555,1325,0,1732,1325,988,1325,0, + 1383,1495,1636,555,901,274,1495,555,1208,1912,1602,1325,1633,0,1325,2403, + 108,1383,1317,108,0,0,517,0,673,0,0,0,1495,1325,1208,0, + 555,1317,1317,2332,1325,0,1514,555,555,555,1732,1602,0,0,274,0, + 517,939,0,2242,1633,0,1633,555,0,1732,555,517,2040,1633,1633,0, + 1602,0,1317,274,1383,0,1633,517,0,673,1995,1732,1912,1636,1602,1732, + 673,0,1732,108,1325,555,555,1633,1317,0,1732,555,555,555,939,0, + 517,1602,0,0,1929,555,901,0,108,108,1325,517,108,1325,1317,0, + 1325,0,1208,0,0,0,108,274,555,0,1383,1325,555,1325,1633,0, + 1383,1602,1383,0,0,517,274,0,591,0,1455,555,555,1317,1325,555, + 555,1317,0,108,555,0,0,108,1633,555,1602,0,1732,555,0,108, + 0,1636,1633,1633,517,555,555,0,274,1317,0,1912,1325,1208,1325,555, + 1383,1633,108,1317,0,1325,1495,1929,1633,673,1633,463,1317,0,0,517, + 0,1317,1929,0,455,1633,0,0,1602,1929,0,1929,2332,1317,555,238, + 0,274,517,1325,1317,0,274,0,555,1317,555,555,0,1192,1325,463, + 555,939,1633,0,0,0,1929,1325,1359,555,1317,1317,274,1732,555,0, + 555,1929,0,1325,448,0,1636,555,988,1208,108,274,555,1325,1317,555, + 1929,1929,1317,1325,108,902,555,0,555,988,1325,901,1325,1317,1732,1101, + 1208,1633,1732,108,1317,1317,108,555,1929,555,1995,1317,1929,1383,517,0, + 0,1633,1602,1912,1929,274,2464,0,555,1929,1317,0,0,555,1317,2180, + 1327,0,517,555,1633,1732,1636,1602,517,1208,555,555,1383,1317,1633,0, + 988,1192,0,0,1495,673,673,0,555,1495,1325,517,1732,1633,555,1325, + 108,1929,1732,1325,988,555,1325,1208,1929,274,0,673,555,1732,1633,134, + 108,1929,673,1208,555,1208,0,0,2464,0,1633,1929,0,913,673,0, + 108,1317,1383,1633,0,555,0,0,1995,1317,0,2040,1317,1633,2332,108, + 1633,1495,555,0,0,2040,926,673,1929,1325,1732,1929,1342,1633,1636,517, + 0,0,517,182,1359,108,274,2040,108,108,0,0,555,988,517,1633, + 1633,1325,1929,673,1633,1912,1288,555,1732,1325,0,1325,517,1325,1325,555, + 0,0,2055,108,0,1732,517,274,901,1359,1929,1417,1636,926,555,0, + 2040,0,1633,591,1929,1325,274,926,1325,517,0,765,108,0,2040,1383, + 1514,901,1809,666,1732,1732,555,1732,555,0,0,1912,555,555,555,1929, + 1317,0,517,673,555,274,673,2398,1208,555,1853,1633,1325,555,0,555, + 0,1383,1325,1317,1929,108,2037,1383,108,1728,673,555,1835,591,1732,1995, + 0,0,939,555,666,1325,1011,555,0,1929,108,1602,2332,0,1325,1633, + 1732,1602,555,429,2040,1633,0,555,2040,1633,0,0,1325,1929,0,1912, + 2040,1011,0,1732,517,1732,0,0,1633,1325,555,108,517,469,1636,108, + 1011,0,0,0,1912,926,1929,988,1636,1633,274,182,1317,108,1325,0, + 555,988,0,0,0,1771,1633,939,1732,1995,0,858,0,555,1633,0, + 939,0,555,108,555,1633,1995,555,2510,0,516,939,1208,1912,858,1205, + 0,785,0,988,1495,274,1011,902,0,0,184,0,1514,108,0,0, + 1732,1633,469,1005,455,555,0,0,1455,428,1929,0,926,1633,1317,555, + 939,0,1317,939,0,1327,1929,0,1668,1732,555,0,1929,1633,1929,555, + 0,0,0,555,1607,1011,1325,1495,400,1011,1924,1383,901,469,1929,1835, + 2040,1602,227,1342,1325,1192,0,1728,2040,1343,517,227,1929,1591,1912,429, + 988,1559,1929,1325,0,1732,1317,0,902,0,555,0,1912,988,1633,1547, + 200,1618,1636,926,0,1636,274,999,274,1809,1929,673,902,555,1624,591, + 1636,591,0,517,555,1383,1633,0,1809,1679,0,673,1011,555,0,108, + 1929,1495,1111,0,988,0,108,0,1995,2403,238,514,0,1995,1317,0, + 1343,517,913,673,988,1614,1912,1325,673,816,1212,1325,1732,1929,1835,1602, + 0,1636,108,455,1912,555,0,816,555,274,1633,0,1325,0,1929,1111, + 634,1636,555,1636,1559,0,1636,0,1514,2040,657,1034,1771,1853,258,1633, + 901,555,1208,1912,1959,816,440,0,1807,1924,1514,316,182,1732,1383,1618, + 988,1591,1559,274,274,0,858,0,1383,1929,1602,1633,1514,1005,1617,0, + 2060,517,1715,988,1542,1732,820,1633,1011,1383,1851,0,1650,1633,108,1912, + 1995,916,1636,1995,1208,0,0,1325,274,1645,108,0,0,0,0,440, + 1670,2060,676,1602,1942,1420,1317,939,729,274,0,0,1965,274,975,238, + }; + + const struct insnprefix_parse_data *ret; + unsigned long rsl, val = phash_lookup(key, len, 0xbc1b868fUL); + rsl = ((val>>23)^tab[val&0x3ff]); + if (rsl >= 2070) return NULL; + ret = &pd[rsl]; + if (strcmp(key, ret->name) != 0) return NULL; + return ret; +} + + diff --git a/contrib/tools/yasm/modules/x86insn_nasm.c b/contrib/tools/yasm/modules/x86insn_nasm.c new file mode 100644 index 0000000000..9d59b2e24b --- /dev/null +++ b/contrib/tools/yasm/modules/x86insn_nasm.c @@ -0,0 +1,1506 @@ +/* ANSI-C code produced by genperf */ +struct insnprefix_parse_data; +static const struct insnprefix_parse_data * +insnprefix_nasm_find(const char *key, size_t len) +{ + static const struct insnprefix_parse_data pd[1454] = { + {"vpsubd", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0xFA, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vcmpltps", ssecmp_128_insn, 3, SUF_Z, 0x01, 0x00, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vmovhpd", movhlp_insn, 3, SUF_Z, 0x66, 0x16, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vcomisd", avx_xmm_xmm64_insn, 2, SUF_Z, 0x66, 0x2F, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"cmpltpd", ssecmp_128_insn, 3, SUF_Z, 0x01, 0x66, 0, 0, CPU_SSE, 0, 0}, + {"pmvgezb", cyrixmmx_insn, 1, SUF_Z, 0x5C, 0, 0, 0, CPU_Cyrix, CPU_MMX, 0}, + {"cmovle", cmovcc_insn, 3, SUF_Z, 0x0E, 0, 0, 0, CPU_686, 0, 0}, + {"cvttss2si", cvt_rx_xmm32_insn, 4, SUF_Z, 0xF3, 0x2C, 0, 0, CPU_386, CPU_SSE, 0}, + {"xbegin", tsx_xbegin_insn, 2, SUF_Z, 0, 0, 0, 0, CPU_386, CPU_TSX, 0}, + {"vmovapd", movau_insn, 6, SUF_Z, 0x66, 0x28, 0x01, ONLY_AVX, CPU_AVX, 0, 0}, + {"cmovc", cmovcc_insn, 3, SUF_Z, 0x02, 0, 0, 0, CPU_686, 0, 0}, + {"fninit", twobyte_insn, 1, SUF_Z, 0xDB, 0xE3, 0, 0, CPU_FPU, 0, 0}, + {"vfrczss", vfrczss_insn, 2, SUF_Z, 0, 0, 0, 0, CPU_XOP, 0, 0}, + {"pushfd", onebyte_insn, 1, SUF_Z, 0x9C, 0x20, 0, NOT_64, CPU_386, 0, 0}, + {"vpcomleuq", vpcom_insn, 1, SUF_Z, 0xEF, 0x01, 0, 0, CPU_XOP, 0, 0}, + {"vpmulhuw", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0xE4, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpsubq", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0xFB, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"fstpt", fldstpt_insn, 1, SUF_Z, 0x07, 0, 0, 0, CPU_FPU, 0, 0}, + {"adc", arith_insn, 22, SUF_Z, 0x10, 0x02, 0, 0, 0, 0, 0}, + {"vmulss", xmm_xmm32_insn, 4, SUF_Z, 0xF3, 0x59, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"stosq", onebyte_insn, 1, SUF_Z, 0xAB, 0x40, 0, ONLY_64, 0, 0, 0}, + {"vzeroupper", vzero_insn, 1, SUF_Z, 0xC0, 0, 0, 0, CPU_AVX, 0, 0}, + {"jnle", jcc_insn, 9, SUF_Z, 0x0F, 0, 0, 0, 0, 0, 0}, + {"pmulhuw", mmxsse2_insn, 2, SUF_Z, 0xE4, 0, 0, 0, CPU_MMX, CPU_P3, 0}, + {"vcmpord_sss", ssecmp_32_insn, 4, SUF_Z, 0x17, 0xF3, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"fxsave", twobytemem_insn, 1, SUF_Z, 0x00, 0x0F, 0xAE, 0, CPU_686, CPU_FPU, 0}, + {"setnbe", setcc_insn, 1, SUF_Z, 0x07, 0, 0, 0, CPU_386, 0, 0}, + {"insertps", insertps_insn, 4, SUF_Z, 0, 0, 0, 0, CPU_SSE41, 0, 0}, + {"rdtsc", twobyte_insn, 1, SUF_Z, 0x0F, 0x31, 0, 0, CPU_586, 0, 0}, + {"psubd", mmxsse2_insn, 2, SUF_Z, 0xFA, 0, 0, 0, CPU_MMX, 0, 0}, + {"vcmptrue_uspd", ssecmp_128_insn, 3, SUF_Z, 0x1F, 0x66, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vmulps", xmm_xmm128_256_insn, 4, SUF_Z, 0x00, 0x59, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vcmpeq_usps", ssecmp_128_insn, 3, SUF_Z, 0x18, 0x00, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"cvtpd2ps", xmm_xmm128_insn, 2, SUF_Z, 0x66, 0x5A, 0, 0, CPU_SSE2, 0, 0}, + {"vfnmsubsd", fma_128_m64_insn, 3, SUF_Z, 0x7F, 0, 0, ONLY_AVX, CPU_FMA4, 0, 0}, + {"vpcomtrueq", vpcom_insn, 1, SUF_Z, 0xCF, 0x07, 0, 0, CPU_XOP, 0, 0}, + {"vpclmulqdq", pclmulqdq_insn, 2, SUF_Z, 0x3A, 0x44, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"cmova", cmovcc_insn, 3, SUF_Z, 0x07, 0, 0, 0, CPU_686, 0, 0}, + {"vmaxss", xmm_xmm32_insn, 4, SUF_Z, 0xF3, 0x5F, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"pi2fw", now3d_insn, 1, SUF_Z, 0x0C, 0, 0, 0, CPU_3DNow, CPU_Athlon, 0}, + {"vfnmadd132pd", vfma_pd_insn, 2, SUF_Z, 0x9C, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"vdpps", sse4imm_256_insn, 4, SUF_Z, 0x40, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpclmulhqhqdq", pclmulqdq_fixed_insn, 2, SUF_Z, 0x11, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vfmsub213pd", vfma_pd_insn, 2, SUF_Z, 0xAA, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"pmaxsw", mmxsse2_insn, 2, SUF_Z, 0xEE, 0, 0, 0, CPU_MMX, CPU_P3, 0}, + {"vpaddq", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0xD4, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpcmov", vpcmov_insn, 4, SUF_Z, 0, 0, 0, 0, CPU_XOP, 0, 0}, + {"vpcomud", vpcom_imm_insn, 1, SUF_Z, 0xEE, 0, 0, 0, CPU_XOP, 0, 0}, + {"vpslld", vpshift_insn, 8, SUF_Z, 0xF2, 0x72, 0x06, ONLY_AVX, CPU_AVX, 0, 0}, + {"shufpd", xmm_xmm128_imm_insn, 1, SUF_Z, 0x66, 0xC6, 0, 0, CPU_SSE2, 0, 0}, + {"vpcomgtud", vpcom_insn, 1, SUF_Z, 0xEE, 0x02, 0, 0, CPU_XOP, 0, 0}, + {"cdq", onebyte_insn, 1, SUF_Z, 0x99, 0x20, 0, 0, CPU_386, 0, 0}, + {"vcmpge_oqps", ssecmp_128_insn, 3, SUF_Z, 0x1D, 0x00, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"rcpss", xmm_xmm32_insn, 4, SUF_Z, 0xF3, 0x53, 0, 0, CPU_SSE, 0, 0}, + {"aad", aadm_insn, 2, SUF_Z, 0x01, 0, 0, NOT_64, 0, 0, 0}, + {"vinserti128", vinsertif128_insn, 1, SUF_Z, 0x38, 0, 0, ONLY_AVX, CPU_AVX2, 0, 0}, + {"vphsubd", ssse3_insn, 5, SUF_Z, 0x06, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"fdiv", farith_insn, 7, SUF_Z, 0xF8, 0xF0, 0x06, 0, CPU_FPU, 0, 0}, + {"fst", fst_insn, 3, SUF_Z, 0, 0, 0, 0, CPU_FPU, 0, 0}, + {"vpcomled", vpcom_insn, 1, SUF_Z, 0xCE, 0x01, 0, 0, CPU_XOP, 0, 0}, + {"setne", setcc_insn, 1, SUF_Z, 0x05, 0, 0, 0, CPU_386, 0, 0}, + {"xcryptcfb", padlock_insn, 1, SUF_Z, 0xE0, 0xF3, 0xA7, 0, CPU_PadLock, 0, 0}, + {"pmaddubsw", ssse3_insn, 5, SUF_Z, 0x04, 0, 0, 0, CPU_SSSE3, 0, 0}, + {"bt", bittest_insn, 6, SUF_Z, 0xA3, 0x04, 0, 0, CPU_386, 0, 0}, + {"blendvpd", sse4xmm0_insn, 2, SUF_Z, 0x15, 0, 0, 0, CPU_SSE41, 0, 0}, + {"vroundss", sse4m32imm_insn, 4, SUF_Z, 0x0A, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"iret", onebyte_insn, 1, SUF_Z, 0xCF, 0, 0, 0, 0, 0, 0}, + {"movbe", movbe_insn, 6, SUF_Z, 0, 0, 0, 0, CPU_MOVBE, 0, 0}, + {"lar", larlsl_insn, 6, SUF_Z, 0x02, 0, 0, 0, CPU_286, CPU_Prot, 0}, + {"mulss", xmm_xmm32_insn, 4, SUF_Z, 0xF3, 0x59, 0, 0, CPU_SSE, 0, 0}, + {"or", arith_insn, 22, SUF_Z, 0x08, 0x01, 0, 0, 0, 0, 0}, + {"cmpxchg", cmpxchgxadd_insn, 4, SUF_Z, 0xB0, 0, 0, 0, CPU_486, 0, 0}, + {"vcvttpd2dq", avx_cvt_xmm128_insn, 2, SUF_Z, 0x66, 0xE6, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"lds", ldes_insn, 2, SUF_Z, 0xC5, 0, 0, NOT_64, 0, 0, 0}, + {"vphaddubw", vphaddsub_insn, 1, SUF_Z, 0xD1, 0, 0, 0, CPU_XOP, 0, 0}, + {"jg", jcc_insn, 9, SUF_Z, 0x0F, 0, 0, 0, 0, 0, 0}, + {"movzx", movszx_insn, 5, SUF_Z, 0xB6, 0, 0, 0, CPU_386, 0, 0}, + {"vpmacssdqh", vpma_insn, 1, SUF_Z, 0x8F, 0, 0, 0, CPU_XOP, 0, 0}, + {"addsubps", xmm_xmm128_insn, 2, SUF_Z, 0xF2, 0xD0, 0, 0, CPU_SSE3, 0, 0}, + {"fsin", twobyte_insn, 1, SUF_Z, 0xD9, 0xFE, 0, 0, CPU_286, CPU_FPU, 0}, + {"vpminsb", ssse3_insn, 5, SUF_Z, 0x38, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"psignd", ssse3_insn, 5, SUF_Z, 0x0A, 0, 0, 0, CPU_SSSE3, 0, 0}, + {"fucompp", twobyte_insn, 1, SUF_Z, 0xDA, 0xE9, 0, 0, CPU_286, CPU_FPU, 0}, + {"vpunpcklqdq", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0x6C, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"pcmpeqb", mmxsse2_insn, 2, SUF_Z, 0x74, 0, 0, 0, CPU_MMX, 0, 0}, + {"extractps", extractps_insn, 2, SUF_Z, 0, 0, 0, 0, CPU_386, CPU_SSE41, 0}, + {"btc", bittest_insn, 6, SUF_Z, 0xBB, 0x07, 0, 0, CPU_386, 0, 0}, + {"vpshlb", amd_vpshift_insn, 2, SUF_Z, 0x94, 0, 0, 0, CPU_XOP, 0, 0}, + {"ror", shift_insn, 16, SUF_Z, 0x01, 0, 0, 0, 0, 0, 0}, + {"vpsravd", vpshiftv_vexw0_avx2_insn, 2, SUF_Z, 0x46, 0, 0, ONLY_AVX, CPU_AVX2, 0, 0}, + {"setge", setcc_insn, 1, SUF_Z, 0x0D, 0, 0, 0, CPU_386, 0, 0}, + {"vpcomgtub", vpcom_insn, 1, SUF_Z, 0xEC, 0x02, 0, 0, CPU_XOP, 0, 0}, + {"vfmaddsub213ps", vfma_ps_insn, 2, SUF_Z, 0xA6, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"vpcomleub", vpcom_insn, 1, SUF_Z, 0xEC, 0x01, 0, 0, CPU_XOP, 0, 0}, + {"cmpordps", ssecmp_128_insn, 3, SUF_Z, 0x07, 0, 0, 0, CPU_SSE, 0, 0}, + {"movhpd", movhlp_insn, 3, SUF_Z, 0x66, 0x16, 0, 0, CPU_SSE2, 0, 0}, + {"mwait", threebyte_insn, 1, SUF_Z, 0x0F, 0x01, 0xC9, 0, CPU_SSE3, 0, 0}, + {"vmovmskps", movmsk_insn, 4, SUF_Z, 0x00, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpaddd", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0xFE, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vfmsub132ss", vfma_ss_insn, 2, SUF_Z, 0x9B, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"vpminuw", ssse3_insn, 5, SUF_Z, 0x3A, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpshaq", amd_vpshift_insn, 2, SUF_Z, 0x9B, 0, 0, 0, CPU_XOP, 0, 0}, + {"dec", incdec_insn, 6, SUF_Z, 0x48, 0x01, 0, 0, 0, 0, 0}, + {"vmovss", movss_insn, 4, SUF_Z, 0xC0, 0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vfmadd132ps", vfma_ps_insn, 2, SUF_Z, 0x98, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"int03", onebyte_insn, 1, SUF_Z, 0xCC, 0, 0, 0, 0, 0, 0}, + {"blcfill", xop_gpr_reg_rm_09_insn, 2, SUF_Z, 0x01, 0x01, 0, 0, CPU_386, CPU_TBM, 0}, + {"phsubsw", ssse3_insn, 5, SUF_Z, 0x07, 0, 0, 0, CPU_SSSE3, 0, 0}, + {"subpd", xmm_xmm128_insn, 2, SUF_Z, 0x66, 0x5C, 0, 0, CPU_SSE2, 0, 0}, + {"stmxcsr", ldstmxcsr_insn, 1, SUF_Z, 0x03, 0, 0, 0, CPU_SSE, 0, 0}, + {"cmovl", cmovcc_insn, 3, SUF_Z, 0x0C, 0, 0, 0, CPU_686, 0, 0}, + {"vpcomneud", vpcom_insn, 1, SUF_Z, 0xEE, 0x05, 0, 0, CPU_XOP, 0, 0}, + {"xorps", xmm_xmm128_insn, 2, SUF_Z, 0x00, 0x57, 0, 0, CPU_SSE, 0, 0}, + {"vcmpeq_usss", ssecmp_32_insn, 4, SUF_Z, 0x18, 0xF3, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vcmpngt_uqsd", ssecmp_64_insn, 4, SUF_Z, 0x1A, 0xF2, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vsubps", xmm_xmm128_256_insn, 4, SUF_Z, 0x00, 0x5C, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vucomiss", avx_xmm_xmm32_insn, 2, SUF_Z, 0x00, 0x2E, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"cmp", arith_insn, 22, SUF_Z, 0x38, 0x07, 0, 0, 0, 0, 0}, + {"bsr", bsfr_insn, 3, SUF_Z, 0xBD, 0, 0, 0, CPU_386, 0, 0}, + {"cmc", onebyte_insn, 1, SUF_Z, 0xF5, 0, 0, 0, 0, 0, 0}, + {"vpshad", amd_vpshift_insn, 2, SUF_Z, 0x9A, 0, 0, 0, CPU_XOP, 0, 0}, + {"pmovmskb", pmovmskb_insn, 6, SUF_Z, 0, 0, 0, 0, CPU_MMX, CPU_P3, 0}, + {"setz", setcc_insn, 1, SUF_Z, 0x04, 0, 0, 0, CPU_386, 0, 0}, + {"cmovo", cmovcc_insn, 3, SUF_Z, 0x00, 0, 0, 0, CPU_686, 0, 0}, + {"vfmaddsd", fma_128_m64_insn, 3, SUF_Z, 0x6B, 0, 0, ONLY_AVX, CPU_FMA4, 0, 0}, + {"vcmpnltsd", ssecmp_64_insn, 4, SUF_Z, 0x05, 0xF2, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"xsha1", padlock_insn, 1, SUF_Z, 0xC8, 0xF3, 0xA6, 0, CPU_PadLock, 0, 0}, + {"out", out_insn, 12, SUF_Z, 0, 0, 0, 0, 0, 0, 0}, + {"vdivsd", xmm_xmm64_insn, 4, SUF_Z, 0xF2, 0x5E, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vfrczsd", vfrczsd_insn, 2, SUF_Z, 0, 0, 0, 0, CPU_XOP, 0, 0}, + {"vpextrw", pextrw_insn, 7, SUF_Z, 0xC0, 0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"subss", xmm_xmm32_insn, 4, SUF_Z, 0xF3, 0x5C, 0, 0, CPU_SSE, 0, 0}, + {"roundpd", sse4imm_insn, 2, SUF_Z, 0x09, 0, 0, 0, CPU_SSE41, 0, 0}, + {"vpermilpd", vpermil_insn, 4, SUF_Z, 0x05, 0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vfnmsub231ps", vfma_ps_insn, 2, SUF_Z, 0xBE, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"sysret", twobyte_insn, 1, SUF_Z, 0x0F, 0x07, 0, 0, CPU_686, CPU_AMD, CPU_Priv}, + {"sub", arith_insn, 22, SUF_Z, 0x28, 0x05, 0, 0, 0, 0, 0}, + {"popf", onebyte_insn, 1, SUF_Z, 0x9D, 0x00, 0x40, 0, 0, 0, 0}, + {"pmvlzb", cyrixmmx_insn, 1, SUF_Z, 0x5B, 0, 0, 0, CPU_Cyrix, CPU_MMX, 0}, + {"vfmadd213ss", vfma_ss_insn, 2, SUF_Z, 0xA9, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"str", str_insn, 4, SUF_Z, 0, 0, 0, 0, CPU_286, CPU_Prot, 0}, + {"lahf", onebyte_insn, 1, SUF_Z, 0x9F, 0, 0, 0, 0, 0, 0}, + {"fnstenv", onebytemem_insn, 1, SUF_Z, 0x06, 0xD9, 0, 0, CPU_FPU, 0, 0}, + {"ficom", fiarith_insn, 2, SUF_Z, 0x02, 0xDA, 0, 0, CPU_FPU, 0, 0}, + {"vpmovsxbq", sse4m16_insn, 4, SUF_Z, 0x22, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"pminub", mmxsse2_insn, 2, SUF_Z, 0xDA, 0, 0, 0, CPU_MMX, CPU_P3, 0}, + {"sqrtpd", xmm_xmm128_insn, 2, SUF_Z, 0x66, 0x51, 0, 0, CPU_SSE2, 0, 0}, + {"stac", threebyte_insn, 1, SUF_Z, 0x0F, 0x01, 0xCB, 0, CPU_SMAP, 0, 0}, + {"vfmaddsub231ps", vfma_ps_insn, 2, SUF_Z, 0xB6, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"vpcomltq", vpcom_insn, 1, SUF_Z, 0xCF, 0x00, 0, 0, CPU_XOP, 0, 0}, + {"cli", onebyte_insn, 1, SUF_Z, 0xFA, 0, 0, 0, 0, 0, 0}, + {"vfnmadd132sd", vfma_sd_insn, 2, SUF_Z, 0x9D, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"vrcpss", xmm_xmm32_insn, 4, SUF_Z, 0xF3, 0x53, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"fnstsw", fnstsw_insn, 2, SUF_Z, 0, 0, 0, 0, CPU_FPU, 0, 0}, + {"vrsqrtps", avx_xmm_xmm128_insn, 2, SUF_Z, 0x00, 0x52, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpcomb", vpcom_imm_insn, 1, SUF_Z, 0xCC, 0, 0, 0, CPU_XOP, 0, 0}, + {"verr", prot286_insn, 1, SUF_Z, 0x04, 0x00, 0, 0, CPU_286, CPU_Prot, 0}, + {"pmovzxdq", sse4m64_insn, 4, SUF_Z, 0x35, 0, 0, 0, CPU_SSE41, 0, 0}, + {"vcmpneq_oqpd", ssecmp_128_insn, 3, SUF_Z, 0x0C, 0x66, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"setae", setcc_insn, 1, SUF_Z, 0x03, 0, 0, 0, CPU_386, 0, 0}, + {"vhaddpd", xmm_xmm128_256_insn, 4, SUF_Z, 0x66, 0x7C, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vcvtsd2si", cvt_rx_xmm64_insn, 4, SUF_Z, 0xF2, 0x2D, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"pmaxuw", sse4_insn, 2, SUF_Z, 0x3E, 0, 0, 0, CPU_SSE41, 0, 0}, + {"rorx", vex_gpr_reg_rm_0F_imm8_insn, 2, SUF_Z, 0xF2, 0x3A, 0xF0, ONLY_AVX, CPU_BMI2, 0, 0}, + {"andn", vex_gpr_reg_nds_rm_0F_insn, 2, SUF_Z, 0x00, 0x38, 0xF2, ONLY_AVX, CPU_BMI1, 0, 0}, + {"vpmovzxwq", sse4m32_insn, 4, SUF_Z, 0x34, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"fisub", fiarith_insn, 2, SUF_Z, 0x04, 0xDA, 0, 0, CPU_FPU, 0, 0}, + {"vcmptrue_usps", ssecmp_128_insn, 3, SUF_Z, 0x1F, 0x00, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpcomneq", vpcom_insn, 1, SUF_Z, 0xCF, 0x05, 0, 0, CPU_XOP, 0, 0}, + {"getsec", twobyte_insn, 1, SUF_Z, 0x0F, 0x37, 0, 0, CPU_SMX, 0, 0}, + {"bzhi", vex_gpr_reg_rm_nds_0F_insn, 2, SUF_Z, 0x00, 0x38, 0xF5, ONLY_AVX, CPU_BMI2, 0, 0}, + {"cvtsd2si", cvt_rx_xmm64_insn, 4, SUF_Z, 0xF2, 0x2D, 0, 0, CPU_386, CPU_SSE2, 0}, + {"vpcomned", vpcom_insn, 1, SUF_Z, 0xCE, 0x05, 0, 0, CPU_XOP, 0, 0}, + {"xtest", tsx_0x0F_0x01_insn, 1, SUF_Z, 0xD6, 0, 0, 0, CPU_TSX, 0, 0}, + {"pclmulqdq", pclmulqdq_insn, 2, SUF_Z, 0x3A, 0x44, 0, 0, CPU_AVX, 0, 0}, + {"minsd", xmm_xmm64_insn, 4, SUF_Z, 0xF2, 0x5D, 0, 0, CPU_SSE2, 0, 0}, + {"vldmxcsr", ldstmxcsr_insn, 1, SUF_Z, 0x02, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vcmpneq_oqps", ssecmp_128_insn, 3, SUF_Z, 0x0C, 0x00, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"pmovsxwd", sse4m64_insn, 4, SUF_Z, 0x23, 0, 0, 0, CPU_SSE41, 0, 0}, + {"iretd", onebyte_insn, 1, SUF_Z, 0xCF, 0x20, 0, 0, CPU_386, 0, 0}, + {"vmcall", threebyte_insn, 1, SUF_Z, 0x0F, 0x01, 0xC1, 0, CPU_P4, 0, 0}, + {"shl", shift_insn, 16, SUF_Z, 0x04, 0, 0, 0, 0, 0, 0}, + {"cmovnp", cmovcc_insn, 3, SUF_Z, 0x0B, 0, 0, 0, CPU_686, 0, 0}, + {"cmpltss", ssecmp_32_insn, 4, SUF_Z, 0x01, 0xF3, 0, 0, CPU_SSE, 0, 0}, + {"movddup", xmm_xmm64_insn, 4, SUF_Z, 0xF2, 0x12, 0, 0, CPU_SSE3, 0, 0}, + {"xrstor", twobytemem_insn, 1, SUF_Z, 0x05, 0x0F, 0xAE, 0, CPU_386, CPU_XSAVE, 0}, + {"pinsrb", pinsrb_insn, 4, SUF_Z, 0, 0, 0, 0, CPU_SSE41, 0, 0}, + {"pushf", onebyte_insn, 1, SUF_Z, 0x9C, 0x00, 0x40, 0, 0, 0, 0}, + {"vxorpd", xmm_xmm128_256_insn, 4, SUF_Z, 0x66, 0x57, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vcmpunordss", ssecmp_32_insn, 4, SUF_Z, 0x03, 0xF3, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpmaxud", ssse3_insn, 5, SUF_Z, 0x3F, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"fiadd", fiarith_insn, 2, SUF_Z, 0x00, 0xDA, 0, 0, CPU_FPU, 0, 0}, + {"vcmple_oqpd", ssecmp_128_insn, 3, SUF_Z, 0x12, 0x66, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vcmpss", xmm_xmm32_imm_insn, 4, SUF_Z, 0xF3, 0xC2, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"sysenter", twobyte_insn, 1, SUF_Z, 0x0F, 0x34, 0, NOT_64, CPU_686, 0, 0}, + {"vpcomleq", vpcom_insn, 1, SUF_Z, 0xCF, 0x01, 0, 0, CPU_XOP, 0, 0}, + {"finit", threebyte_insn, 1, SUF_Z, 0x9B, 0xDB, 0xE3, 0, CPU_FPU, 0, 0}, + {"vpcomneqw", vpcom_insn, 1, SUF_Z, 0xCD, 0x05, 0, 0, CPU_XOP, 0, 0}, + {"clgi", threebyte_insn, 1, SUF_Z, 0x0F, 0x01, 0xDD, 0, CPU_SVM, 0, 0}, + {"vpabsb", avx2_ssse3_2op_insn, 2, SUF_Z, 0x1C, 0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"addpd", xmm_xmm128_insn, 2, SUF_Z, 0x66, 0x58, 0, 0, CPU_SSE2, 0, 0}, + {"cmovg", cmovcc_insn, 3, SUF_Z, 0x0F, 0, 0, 0, CPU_686, 0, 0}, + {"movlps", movhlp_insn, 3, SUF_Z, 0x00, 0x12, 0, 0, CPU_SSE, 0, 0}, + {"vaddss", xmm_xmm32_insn, 4, SUF_Z, 0xF3, 0x58, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"outsb", onebyte_insn, 1, SUF_Z, 0x6E, 0x00, 0, 0, 0, 0, 0}, + {"vpcomequd", vpcom_insn, 1, SUF_Z, 0xEE, 0x04, 0, 0, CPU_XOP, 0, 0}, + {"wrmsr", twobyte_insn, 1, SUF_Z, 0x0F, 0x30, 0, 0, CPU_586, CPU_Priv, 0}, + {"vpshufb", ssse3_insn, 5, SUF_Z, 0x00, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpackssdw", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0x6B, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"ftst", twobyte_insn, 1, SUF_Z, 0xD9, 0xE4, 0, 0, CPU_FPU, 0, 0}, + {"arpl", arpl_insn, 1, SUF_Z, 0, 0, 0, NOT_64, CPU_286, CPU_Prot, 0}, + {"fcmovb", fcmovcc_insn, 1, SUF_Z, 0xDA, 0xC0, 0, 0, CPU_686, CPU_FPU, 0}, + {"vfnmadd132ss", vfma_ss_insn, 2, SUF_Z, 0x9D, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"rsldt", cyrixsmm_insn, 1, SUF_Z, 0x7B, 0, 0, 0, CPU_486, CPU_Cyrix, CPU_SMM}, + {"vfmsubss", fma_128_m32_insn, 3, SUF_Z, 0x6E, 0, 0, ONLY_AVX, CPU_FMA4, 0, 0}, + {"pcmpgtw", mmxsse2_insn, 2, SUF_Z, 0x65, 0, 0, 0, CPU_MMX, 0, 0}, + {"vcmpfalse_osss", ssecmp_32_insn, 4, SUF_Z, 0x1B, 0xF3, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"comiss", xmm_xmm32_insn, 4, SUF_Z, 0x00, 0x2F, 0, 0, CPU_SSE, 0, 0}, + {"loopz", loop_insn, 8, SUF_Z, 0x01, 0, 0, 0, 0, 0, 0}, + {"cmpnlepd", ssecmp_128_insn, 3, SUF_Z, 0x06, 0x66, 0, 0, CPU_SSE, 0, 0}, + {"pfmin", now3d_insn, 1, SUF_Z, 0x94, 0, 0, 0, CPU_3DNow, 0, 0}, + {"xsha256", padlock_insn, 1, SUF_Z, 0xD0, 0xF3, 0xA6, 0, CPU_PadLock, 0, 0}, + {"vfnmsub132ss", vfma_ss_insn, 2, SUF_Z, 0x9F, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"fldl2t", twobyte_insn, 1, SUF_Z, 0xD9, 0xE9, 0, 0, CPU_FPU, 0, 0}, + {"vpsignd", ssse3_insn, 5, SUF_Z, 0x0A, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpaddusw", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0xDD, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"fcmovu", fcmovcc_insn, 1, SUF_Z, 0xDA, 0xD8, 0, 0, CPU_686, CPU_FPU, 0}, + {"vmovaps", movau_insn, 6, SUF_Z, 0x00, 0x28, 0x01, ONLY_AVX, CPU_AVX, 0, 0}, + {"vcmple_oqsd", ssecmp_64_insn, 4, SUF_Z, 0x12, 0xF2, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpextrq", pextrq_insn, 1, SUF_Z, 0xC0, 0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"cmpnltps", ssecmp_128_insn, 3, SUF_Z, 0x05, 0, 0, 0, CPU_SSE, 0, 0}, + {"vfnmadd231pd", vfma_pd_insn, 2, SUF_Z, 0xBC, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"fsubp", farithp_insn, 3, SUF_Z, 0xE8, 0, 0, 0, CPU_FPU, 0, 0}, + {"pmulld", sse4_insn, 2, SUF_Z, 0x40, 0, 0, 0, CPU_SSE41, 0, 0}, + {"vfnmadd132ps", vfma_ps_insn, 2, SUF_Z, 0x9C, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"vpunpcklbw", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0x60, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vorps", xmm_xmm128_256_insn, 4, SUF_Z, 0x00, 0x56, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vmovmskpd", movmsk_insn, 4, SUF_Z, 0x66, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"cmpeqpd", ssecmp_128_insn, 3, SUF_Z, 0x00, 0x66, 0, 0, CPU_SSE, 0, 0}, + {"vmovdqa", movau_insn, 6, SUF_Z, 0x66, 0x6F, 0x10, ONLY_AVX, CPU_AVX, 0, 0}, + {"jl", jcc_insn, 9, SUF_Z, 0x0C, 0, 0, 0, 0, 0, 0}, + {"vcmpgesd", ssecmp_64_insn, 4, SUF_Z, 0x0D, 0xF2, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"cvttpd2pi", cvt_mm_xmm_insn, 1, SUF_Z, 0x66, 0x2C, 0, 0, CPU_SSE2, 0, 0}, + {"phsubw", ssse3_insn, 5, SUF_Z, 0x05, 0, 0, 0, CPU_SSSE3, 0, 0}, + {"pminsw", mmxsse2_insn, 2, SUF_Z, 0xEA, 0, 0, 0, CPU_MMX, CPU_P3, 0}, + {"vpgatherqq", gather_64x_64y_insn, 2, SUF_Z, 0x91, 0, 0, ONLY_AVX, CPU_AVX2, 0, 0}, + {"vfmadd132sd", vfma_sd_insn, 2, SUF_Z, 0x99, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"setpo", setcc_insn, 1, SUF_Z, 0x0B, 0, 0, 0, CPU_386, 0, 0}, + {"fidiv", fiarith_insn, 2, SUF_Z, 0x06, 0xDA, 0, 0, CPU_FPU, 0, 0}, + {"clts", twobyte_insn, 1, SUF_Z, 0x0F, 0x06, 0, 0, CPU_286, CPU_Priv, 0}, + {"prefetcht0", twobytemem_insn, 1, SUF_Z, 0x01, 0x0F, 0x18, 0, CPU_P3, 0, 0}, + {"cvtsi2ss", cvt_xmm_rmx_insn, 6, SUF_Z, 0xF3, 0x2A, 0, 0, CPU_386, CPU_SSE, 0}, + {"vpmuludq", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0xF4, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"xcryptctr", padlock_insn, 1, SUF_Z, 0xD8, 0xF3, 0xA7, 0, CPU_PadLock, 0, 0}, + {"vfmadd132ss", vfma_ss_insn, 2, SUF_Z, 0x99, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"vpcmpistri", sse4pcmpstr_insn, 1, SUF_Z, 0x63, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"popfw", onebyte_insn, 1, SUF_Z, 0x9D, 0x10, 0x40, 0, 0, 0, 0}, + {"vstmxcsr", ldstmxcsr_insn, 1, SUF_Z, 0x03, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpmovzxbd", sse4m32_insn, 4, SUF_Z, 0x31, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"rsqrtps", xmm_xmm128_insn, 2, SUF_Z, 0x00, 0x52, 0, 0, CPU_SSE, 0, 0}, + {"vfmsubadd213pd", vfma_pd_insn, 2, SUF_Z, 0xA7, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"prefetcht1", twobytemem_insn, 1, SUF_Z, 0x02, 0x0F, 0x18, 0, CPU_P3, 0, 0}, + {"xrelease", NULL, X86_ACQREL>>8, 0xF3, 0, 0, 0, 0, 0, 0, 0}, + {"wait", onebyte_insn, 1, SUF_Z, 0x9B, 0, 0, 0, 0, 0, 0}, + {"aesenc", aes_insn, 2, SUF_Z, 0x38, 0xDC, 0, 0, CPU_AVX, 0, 0}, + {"cmpordsd", ssecmp_64_insn, 4, SUF_Z, 0x07, 0xF2, 0, 0, CPU_SSE2, 0, 0}, + {"lodsb", onebyte_insn, 1, SUF_Z, 0xAC, 0x00, 0, 0, 0, 0, 0}, + {"vcmpeq_ussd", ssecmp_64_insn, 4, SUF_Z, 0x18, 0xF2, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"fimul", fiarith_insn, 2, SUF_Z, 0x01, 0xDA, 0, 0, CPU_FPU, 0, 0}, + {"setns", setcc_insn, 1, SUF_Z, 0x09, 0, 0, 0, CPU_386, 0, 0}, + {"vunpcklpd", xmm_xmm128_256_insn, 4, SUF_Z, 0x66, 0x14, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"sha1nexte", intel_SHA1NEXTE_insn, 1, SUF_Z, 0, 0, 0, 0, CPU_SHA, 0, 0}, + {"xorpd", xmm_xmm128_insn, 2, SUF_Z, 0x66, 0x57, 0, 0, CPU_SSE2, 0, 0}, + {"jp", jcc_insn, 9, SUF_Z, 0x0A, 0, 0, 0, 0, 0, 0}, + {"vcmpfalse_ossd", ssecmp_64_insn, 4, SUF_Z, 0x1B, 0xF2, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vaesenc", aes_insn, 2, SUF_Z, 0x38, 0xDC, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"fnop", twobyte_insn, 1, SUF_Z, 0xD9, 0xD0, 0, 0, CPU_FPU, 0, 0}, + {"nop", onebyte_insn, 1, SUF_Z, 0x90, 0, 0, 0, 0, 0, 0}, + {"test", test_insn, 20, SUF_Z, 0, 0, 0, 0, 0, 0, 0}, + {"pmulhrsw", ssse3_insn, 5, SUF_Z, 0x0B, 0, 0, 0, CPU_SSSE3, 0, 0}, + {"cvtdq2pd", xmm_xmm64_insn, 4, SUF_Z, 0xF3, 0xE6, 0, 0, CPU_SSE2, 0, 0}, + {"pmaddwd", mmxsse2_insn, 2, SUF_Z, 0xF5, 0, 0, 0, CPU_MMX, 0, 0}, + {"vperm2i128", vperm2i128_avx2_insn, 1, SUF_Z, 0, 0, 0, ONLY_AVX, CPU_AVX2, 0, 0}, + {"vcmpnltss", ssecmp_32_insn, 4, SUF_Z, 0x05, 0xF3, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"frstor", onebytemem_insn, 1, SUF_Z, 0x04, 0xDD, 0, 0, CPU_FPU, 0, 0}, + {"vcmpnlt_uqps", ssecmp_128_insn, 3, SUF_Z, 0x15, 0x00, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"blcic", xop_gpr_reg_rm_09_insn, 2, SUF_Z, 0x01, 0x05, 0, 0, CPU_386, CPU_TBM, 0}, + {"vfnmsub132sd", vfma_sd_insn, 2, SUF_Z, 0x9F, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"loopnz", loop_insn, 8, SUF_Z, 0x00, 0, 0, 0, 0, 0, 0}, + {"vcmpordss", ssecmp_32_insn, 4, SUF_Z, 0x07, 0xF3, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"movntsd", movntsd_insn, 1, SUF_Z, 0, 0, 0, 0, CPU_SSE4a, 0, 0}, + {"mov", mov_insn, 69, SUF_Z, 0, 0, 0, 0, 0, 0, 0}, + {"jc", jcc_insn, 9, SUF_Z, 0x02, 0, 0, 0, 0, 0, 0}, + {"cmpltps", ssecmp_128_insn, 3, SUF_Z, 0x01, 0, 0, 0, CPU_SSE, 0, 0}, + {"palignr", ssse3imm_insn, 2, SUF_Z, 0x0F, 0, 0, 0, CPU_SSSE3, 0, 0}, + {"vpmuldq", ssse3_insn, 5, SUF_Z, 0x28, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"cmovnz", cmovcc_insn, 3, SUF_Z, 0x05, 0, 0, 0, CPU_686, 0, 0}, + {"vpshuflw", xmm_xmm128_imm_256avx2_insn, 2, SUF_Z, 0xF2, 0x70, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpmovzxdq", sse4m64_insn, 4, SUF_Z, 0x35, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vcmpnge_uqps", ssecmp_128_insn, 3, SUF_Z, 0x19, 0x00, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"fstp", fstp_insn, 4, SUF_Z, 0, 0, 0, 0, CPU_FPU, 0, 0}, + {"vpacksswb", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0x63, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vfmaddps", fma_128_256_insn, 4, SUF_Z, 0x68, 0, 0, ONLY_AVX, CPU_FMA4, 0, 0}, + {"vcmptruepd", ssecmp_128_insn, 3, SUF_Z, 0x0F, 0x66, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vaddsd", xmm_xmm64_insn, 4, SUF_Z, 0xF2, 0x58, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vphaddbq", vphaddsub_insn, 1, SUF_Z, 0xC3, 0, 0, 0, CPU_XOP, 0, 0}, + {"vaesimc", aesimc_insn, 1, SUF_Z, 0x38, 0xDB, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"wbinvd", twobyte_insn, 1, SUF_Z, 0x0F, 0x09, 0, 0, CPU_486, CPU_Priv, 0}, + {"salc", onebyte_insn, 1, SUF_Z, 0xD6, 0, 0, NOT_64, CPU_Undoc, 0, 0}, + {"vcmpnltps", ssecmp_128_insn, 3, SUF_Z, 0x05, 0x00, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"ptest", sse4_insn, 2, SUF_Z, 0x17, 0, 0, 0, CPU_SSE41, 0, 0}, + {"jne", jcc_insn, 9, SUF_Z, 0x05, 0, 0, 0, 0, 0, 0}, + {"vpmovsxbd", sse4m32_insn, 4, SUF_Z, 0x21, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vminsd", xmm_xmm64_insn, 4, SUF_Z, 0xF2, 0x5D, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"fcmovnb", fcmovcc_insn, 1, SUF_Z, 0xDB, 0xC0, 0, 0, CPU_686, CPU_FPU, 0}, + {"vpunpcklwd", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0x61, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"pclmullqhqdq", pclmulqdq_fixed_insn, 2, SUF_Z, 0x10, 0, 0, 0, CPU_AVX, 0, 0}, + {"loadall286", twobyte_insn, 1, SUF_Z, 0x0F, 0x05, 0, 0, CPU_286, CPU_Undoc, 0}, + {"popcnt", cnt_insn, 3, SUF_Z, 0xB8, 0, 0, 0, CPU_SSE42, 0, 0}, + {"fld", fld_insn, 4, SUF_Z, 0, 0, 0, 0, CPU_FPU, 0, 0}, + {"vpcomfalseuw", vpcom_insn, 1, SUF_Z, 0xED, 0x06, 0, 0, CPU_XOP, 0, 0}, + {"fprem", twobyte_insn, 1, SUF_Z, 0xD9, 0xF8, 0, 0, CPU_FPU, 0, 0}, + {"vcvtps2pd", avx_cvt_xmm64_insn, 3, SUF_Z, 0x00, 0x5A, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vfmsub231ss", vfma_ss_insn, 2, SUF_Z, 0xBB, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"vfmadd213sd", vfma_sd_insn, 2, SUF_Z, 0xA9, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"vprotw", vprot_insn, 3, SUF_Z, 0x01, 0, 0, 0, CPU_XOP, 0, 0}, + {"cmovge", cmovcc_insn, 3, SUF_Z, 0x0D, 0, 0, 0, CPU_686, 0, 0}, + {"popa", onebyte_insn, 1, SUF_Z, 0x61, 0x00, 0, NOT_64, CPU_186, 0, 0}, + {"cmovna", cmovcc_insn, 3, SUF_Z, 0x06, 0, 0, 0, CPU_686, 0, 0}, + {"vroundpd", avx_sse4imm_insn, 3, SUF_Z, 0x09, 0, 0, ONLY_AVX, CPU_SSE41, 0, 0}, + {"pcmpistrm", sse4pcmpstr_insn, 1, SUF_Z, 0x62, 0, 0, 0, CPU_SSE42, 0, 0}, + {"movq2dq", movq2dq_insn, 1, SUF_Z, 0, 0, 0, 0, CPU_SSE2, 0, 0}, + {"blsi", vex_gpr_ndd_rm_0F38_regext_insn, 2, SUF_Z, 0x00, 0xF3, 0x03, ONLY_AVX, CPU_BMI1, 0, 0}, + {"vminps", xmm_xmm128_256_insn, 4, SUF_Z, 0x00, 0x5D, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"maxsd", xmm_xmm64_insn, 4, SUF_Z, 0xF2, 0x5F, 0, 0, CPU_SSE2, 0, 0}, + {"vcmpneq_ossd", ssecmp_64_insn, 4, SUF_Z, 0x1C, 0xF2, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"in", in_insn, 12, SUF_Z, 0, 0, 0, 0, 0, 0, 0}, + {"retn", retnf_insn, 6, SUF_Z, 0xC2, 0, 0, 0, 0, 0, 0}, + {"cmpsd", cmpsd_insn, 5, SUF_Z, 0, 0, 0, 0, 0, 0, 0}, + {"psrlw", pshift_insn, 4, SUF_Z, 0xD1, 0x71, 0x02, 0, CPU_MMX, 0, 0}, + {"vpsrlvd", vpshiftv_vexw0_avx2_insn, 2, SUF_Z, 0x45, 0, 0, ONLY_AVX, CPU_AVX2, 0, 0}, + {"movsd", movsd_insn, 5, SUF_Z, 0, 0, 0, 0, CPU_386, 0, 0}, + {"subsd", xmm_xmm64_insn, 4, SUF_Z, 0xF2, 0x5C, 0, 0, CPU_SSE2, 0, 0}, + {"das", onebyte_insn, 1, SUF_Z, 0x2F, 0, 0, NOT_64, 0, 0, 0}, + {"movaps", movau_insn, 6, SUF_Z, 0x00, 0x28, 0x01, 0, CPU_SSE, 0, 0}, + {"fxtract", twobyte_insn, 1, SUF_Z, 0xD9, 0xF4, 0, 0, CPU_FPU, 0, 0}, + {"rep", NULL, X86_LOCKREP>>8, 0xF3, 0, 0, 0, 0, 0, 0, 0}, + {"vcmpnless", ssecmp_32_insn, 4, SUF_Z, 0x06, 0xF3, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vaeskeygenassist", aes_imm_insn, 1, SUF_Z, 0x3A, 0xDF, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpaddsb", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0xEC, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"pand", mmxsse2_insn, 2, SUF_Z, 0xDB, 0, 0, 0, CPU_MMX, 0, 0}, + {"cmovb", cmovcc_insn, 3, SUF_Z, 0x02, 0, 0, 0, CPU_686, 0, 0}, + {"vpcmpgtd", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0x66, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"pmovzxwq", sse4m32_insn, 4, SUF_Z, 0x34, 0, 0, 0, CPU_SSE41, 0, 0}, + {"vfmsubadd132ps", vfma_ps_insn, 2, SUF_Z, 0x97, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"vpmovsxdq", sse4m64_insn, 4, SUF_Z, 0x25, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"psrlq", pshift_insn, 4, SUF_Z, 0xD3, 0x73, 0x02, 0, CPU_MMX, 0, 0}, + {"vshufps", xmm_xmm128_imm_256_insn, 3, SUF_Z, 0x00, 0xC6, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"ficomp", fiarith_insn, 2, SUF_Z, 0x03, 0xDA, 0, 0, CPU_FPU, 0, 0}, + {"vpcomneqq", vpcom_insn, 1, SUF_Z, 0xCF, 0x05, 0, 0, CPU_XOP, 0, 0}, + {"vphaddwd", vphaddsub_insn, 1, SUF_Z, 0xC6, 0, 0, 0, CPU_XOP, 0, 0}, + {"scasq", onebyte_insn, 1, SUF_Z, 0xAF, 0x40, 0, ONLY_64, 0, 0, 0}, + {"vcmpgess", ssecmp_32_insn, 4, SUF_Z, 0x0D, 0xF3, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vcmptrueps", ssecmp_128_insn, 3, SUF_Z, 0x0F, 0x00, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"divss", xmm_xmm32_insn, 4, SUF_Z, 0xF3, 0x5E, 0, 0, CPU_SSE, 0, 0}, + {"vblendvpd", avx_sse4xmm0_insn, 2, SUF_Z, 0x4B, 0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vcmpnle_uqss", ssecmp_32_insn, 4, SUF_Z, 0x16, 0xF3, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"punpcklqdq", xmm_xmm128_insn, 2, SUF_Z, 0x66, 0x6C, 0, 0, CPU_SSE2, 0, 0}, + {"vphsubbw", vphaddsub_insn, 1, SUF_Z, 0xE1, 0, 0, 0, CPU_XOP, 0, 0}, + {"hsubpd", xmm_xmm128_insn, 2, SUF_Z, 0x66, 0x7D, 0, 0, CPU_SSE3, 0, 0}, + {"vfnmsub132ps", vfma_ps_insn, 2, SUF_Z, 0x9E, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"fxch", fxch_insn, 4, SUF_Z, 0, 0, 0, 0, CPU_FPU, 0, 0}, + {"vpsrad", vpshift_insn, 8, SUF_Z, 0xE2, 0x72, 0x04, ONLY_AVX, CPU_AVX, 0, 0}, + {"sets", setcc_insn, 1, SUF_Z, 0x08, 0, 0, 0, CPU_386, 0, 0}, + {"montmul", padlock_insn, 1, SUF_Z, 0xC0, 0xF3, 0xA6, 0, CPU_PadLock, 0, 0}, + {"shld", shlrd_insn, 9, SUF_Z, 0xA4, 0, 0, 0, CPU_386, 0, 0}, + {"jnbe", jcc_insn, 9, SUF_Z, 0x07, 0, 0, 0, 0, 0, 0}, + {"fucomip", fcom2_insn, 2, SUF_Z, 0xDF, 0xE8, 0, 0, CPU_686, CPU_FPU, 0}, + {"vfnmsubpd", fma_128_256_insn, 4, SUF_Z, 0x7D, 0, 0, ONLY_AVX, CPU_FMA4, 0, 0}, + {"psllw", pshift_insn, 4, SUF_Z, 0xF1, 0x71, 0x06, 0, CPU_MMX, 0, 0}, + {"vpsubw", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0xF9, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"fcomi", fcom2_insn, 2, SUF_Z, 0xDB, 0xF0, 0, 0, CPU_686, CPU_FPU, 0}, + {"pusha", onebyte_insn, 1, SUF_Z, 0x60, 0x00, 0, NOT_64, CPU_186, 0, 0}, + {"vcmpnltpd", ssecmp_128_insn, 3, SUF_Z, 0x05, 0x66, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"adox", vex_gpr_ndd_rm_0F38_insn, 2, SUF_Z, 0xF3, 0xF6, 0, 0, CPU_ADX, 0, 0}, + {"cmpordpd", ssecmp_128_insn, 3, SUF_Z, 0x07, 0x66, 0, 0, CPU_SSE, 0, 0}, + {"lfence", threebyte_insn, 1, SUF_Z, 0x0F, 0xAE, 0xE8, 0, CPU_P3, 0, 0}, + {"loopne", loop_insn, 8, SUF_Z, 0x00, 0, 0, 0, 0, 0, 0}, + {"vfmadd213pd", vfma_pd_insn, 2, SUF_Z, 0xA8, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"movsq", onebyte_insn, 1, SUF_Z, 0xA5, 0x40, 0, ONLY_64, 0, 0, 0}, + {"vcmpunord_ssd", ssecmp_64_insn, 4, SUF_Z, 0x13, 0xF2, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"pslldq", pslrldq_insn, 4, SUF_Z, 0x07, 0, 0, 0, CPU_SSE2, 0, 0}, + {"fisttp", fildstp_insn, 4, SUF_Z, 0x01, 0x00, 0x01, 0, CPU_SSE3, 0, 0}, + {"fldcw", fldnstcw_insn, 1, SUF_Z, 0x05, 0, 0, 0, CPU_FPU, 0, 0}, + {"vpcomltw", vpcom_insn, 1, SUF_Z, 0xCD, 0x00, 0, 0, CPU_XOP, 0, 0}, + {"vpackusdw", ssse3_insn, 5, SUF_Z, 0x2B, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"cmovng", cmovcc_insn, 3, SUF_Z, 0x0E, 0, 0, 0, CPU_686, 0, 0}, + {"andnps", xmm_xmm128_insn, 2, SUF_Z, 0x00, 0x55, 0, 0, CPU_SSE, 0, 0}, + {"cwde", onebyte_insn, 1, SUF_Z, 0x98, 0x20, 0, 0, CPU_386, 0, 0}, + {"vpcomtruew", vpcom_insn, 1, SUF_Z, 0xCD, 0x07, 0, 0, CPU_XOP, 0, 0}, + {"xsetbv", threebyte_insn, 1, SUF_Z, 0x0F, 0x01, 0xD1, 0, CPU_386, CPU_Priv, CPU_XSAVE}, + {"movsw", onebyte_insn, 1, SUF_Z, 0xA5, 0x10, 0, 0, 0, 0, 0}, + {"vpcomw", vpcom_imm_insn, 1, SUF_Z, 0xCD, 0, 0, 0, CPU_XOP, 0, 0}, + {"pext", vex_gpr_reg_nds_rm_0F_insn, 2, SUF_Z, 0xF3, 0x38, 0xF5, ONLY_AVX, CPU_BMI2, 0, 0}, + {"pmovsxbd", sse4m32_insn, 4, SUF_Z, 0x21, 0, 0, 0, CPU_SSE41, 0, 0}, + {"cmpnleps", ssecmp_128_insn, 3, SUF_Z, 0x06, 0, 0, 0, CPU_SSE, 0, 0}, + {"vfmsubsd", fma_128_m64_insn, 3, SUF_Z, 0x6F, 0, 0, ONLY_AVX, CPU_FMA4, 0, 0}, + {"fcos", twobyte_insn, 1, SUF_Z, 0xD9, 0xFF, 0, 0, CPU_286, CPU_FPU, 0}, + {"repnz", NULL, X86_LOCKREP>>8, 0xF2, 0, 0, 0, 0, 0, 0, 0}, + {"vcmpngtsd", ssecmp_64_insn, 4, SUF_Z, 0x0A, 0xF2, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"fsubr", farith_insn, 7, SUF_Z, 0xE0, 0xE8, 0x05, 0, CPU_FPU, 0, 0}, + {"setng", setcc_insn, 1, SUF_Z, 0x0E, 0, 0, 0, CPU_386, 0, 0}, + {"paddsiw", cyrixmmx_insn, 1, SUF_Z, 0x51, 0, 0, 0, CPU_Cyrix, CPU_MMX, 0}, + {"psubusb", mmxsse2_insn, 2, SUF_Z, 0xD8, 0, 0, 0, CPU_MMX, 0, 0}, + {"psignw", ssse3_insn, 5, SUF_Z, 0x09, 0, 0, 0, CPU_SSSE3, 0, 0}, + {"cmovnae", cmovcc_insn, 3, SUF_Z, 0x02, 0, 0, 0, CPU_686, 0, 0}, + {"vpcomgeb", vpcom_insn, 1, SUF_Z, 0xCC, 0x03, 0, 0, CPU_XOP, 0, 0}, + {"vmovshdup", avx_xmm_xmm128_insn, 2, SUF_Z, 0xF3, 0x16, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"pshufhw", xmm_xmm128_imm_insn, 1, SUF_Z, 0xF3, 0x70, 0, 0, CPU_SSE2, 0, 0}, + {"fldt", fldstpt_insn, 1, SUF_Z, 0x05, 0, 0, 0, CPU_FPU, 0, 0}, + {"pmovsxbq", sse4m16_insn, 4, SUF_Z, 0x22, 0, 0, 0, CPU_SSE41, 0, 0}, + {"extrq", extrq_insn, 2, SUF_Z, 0, 0, 0, 0, CPU_SSE4a, 0, 0}, + {"fidivr", fiarith_insn, 2, SUF_Z, 0x07, 0xDA, 0, 0, CPU_FPU, 0, 0}, + {"vpabsd", avx2_ssse3_2op_insn, 2, SUF_Z, 0x1E, 0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vmaskmovpd", vmaskmov_insn, 4, SUF_Z, 0x2D, 0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"rsts", cyrixsmm_insn, 1, SUF_Z, 0x7D, 0, 0, 0, CPU_486, CPU_Cyrix, CPU_SMM}, + {"vfmsubaddpd", fma_128_256_insn, 4, SUF_Z, 0x5F, 0, 0, ONLY_AVX, CPU_FMA4, 0, 0}, + {"paddsw", mmxsse2_insn, 2, SUF_Z, 0xED, 0, 0, 0, CPU_MMX, 0, 0}, + {"cmpnless", ssecmp_32_insn, 4, SUF_Z, 0x06, 0xF3, 0, 0, CPU_SSE, 0, 0}, + {"vinsertps", insertps_insn, 4, SUF_Z, 0xC0, 0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"fcmovne", fcmovcc_insn, 1, SUF_Z, 0xDB, 0xC8, 0, 0, CPU_686, CPU_FPU, 0}, + {"vcmpneq_osps", ssecmp_128_insn, 3, SUF_Z, 0x1C, 0x00, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vextractf128", vextractif128_insn, 1, SUF_Z, 0x19, 0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"pmulhw", mmxsse2_insn, 2, SUF_Z, 0xE5, 0, 0, 0, CPU_MMX, 0, 0}, + {"vfnmsub213ps", vfma_ps_insn, 2, SUF_Z, 0xAE, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"sha256rnds2", intel_SHA256RNDS2_insn, 1, SUF_Z, 0, 0, 0, 0, CPU_SHA, 0, 0}, + {"vcmpnle_uqsd", ssecmp_64_insn, 4, SUF_Z, 0x16, 0xF2, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"cmovns", cmovcc_insn, 3, SUF_Z, 0x09, 0, 0, 0, CPU_686, 0, 0}, + {"xcryptecb", padlock_insn, 1, SUF_Z, 0xC8, 0xF3, 0xA7, 0, CPU_PadLock, 0, 0}, + {"vcvtpd2dq", avx_cvt_xmm128_insn, 2, SUF_Z, 0xF2, 0xE6, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"pfadd", now3d_insn, 1, SUF_Z, 0x9E, 0, 0, 0, CPU_3DNow, 0, 0}, + {"fbld", fbldstp_insn, 1, SUF_Z, 0x04, 0, 0, 0, CPU_FPU, 0, 0}, + {"rsm", twobyte_insn, 1, SUF_Z, 0x0F, 0xAA, 0, 0, CPU_586, CPU_SMM, 0}, + {"vxorps", xmm_xmm128_256_insn, 4, SUF_Z, 0x00, 0x57, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"pmuldq", sse4_insn, 2, SUF_Z, 0x28, 0, 0, 0, CPU_SSE41, 0, 0}, + {"vshufpd", xmm_xmm128_imm_256_insn, 3, SUF_Z, 0x66, 0xC6, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vcmpgtps", ssecmp_128_insn, 3, SUF_Z, 0x0E, 0x00, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"pop", pop_insn, 23, SUF_Z, 0, 0, 0, 0, 0, 0, 0}, + {"movhps", movhlp_insn, 3, SUF_Z, 0x00, 0x16, 0, 0, CPU_SSE, 0, 0}, + {"sqrtss", xmm_xmm32_insn, 4, SUF_Z, 0xF3, 0x51, 0, 0, CPU_SSE, 0, 0}, + {"vcmpord_spd", ssecmp_128_insn, 3, SUF_Z, 0x17, 0x66, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"cvtpi2pd", cvt_xmm_mm_ss_insn, 1, SUF_Z, 0x66, 0x2A, 0, 0, CPU_SSE2, 0, 0}, + {"vpunpckhwd", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0x69, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vfmsub213ps", vfma_ps_insn, 2, SUF_Z, 0xAA, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"vmovntdq", movnt_insn, 2, SUF_Z, 0x66, 0xE7, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"cmove", cmovcc_insn, 3, SUF_Z, 0x04, 0, 0, 0, CPU_686, 0, 0}, + {"setl", setcc_insn, 1, SUF_Z, 0x0C, 0, 0, 0, CPU_386, 0, 0}, + {"vpcomnequw", vpcom_insn, 1, SUF_Z, 0xED, 0x05, 0, 0, CPU_XOP, 0, 0}, + {"vcmpeqps", ssecmp_128_insn, 3, SUF_Z, 0x00, 0x00, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vmrun", svm_rax_insn, 2, SUF_Z, 0xD8, 0, 0, 0, CPU_SVM, 0, 0}, + {"pswapd", now3d_insn, 1, SUF_Z, 0xBB, 0, 0, 0, CPU_3DNow, CPU_Athlon, 0}, + {"vcmpltpd", ssecmp_128_insn, 3, SUF_Z, 0x01, 0x66, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"pmovsxdq", sse4m64_insn, 4, SUF_Z, 0x25, 0, 0, 0, CPU_SSE41, 0, 0}, + {"skinit", skinit_insn, 2, SUF_Z, 0, 0, 0, 0, CPU_SVM, 0, 0}, + {"setno", setcc_insn, 1, SUF_Z, 0x01, 0, 0, 0, CPU_386, 0, 0}, + {"pmaxub", mmxsse2_insn, 2, SUF_Z, 0xDE, 0, 0, 0, CPU_MMX, CPU_P3, 0}, + {"ldmxcsr", ldstmxcsr_insn, 1, SUF_Z, 0x02, 0, 0, 0, CPU_SSE, 0, 0}, + {"setnc", setcc_insn, 1, SUF_Z, 0x03, 0, 0, 0, CPU_386, 0, 0}, + {"xsaveopt", twobytemem_insn, 1, SUF_Z, 0x06, 0x0F, 0xAE, 0, CPU_XSAVEOPT, 0, 0}, + {"vcmpnlesd", ssecmp_64_insn, 4, SUF_Z, 0x06, 0xF2, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpslldq", pslrldq_insn, 4, SUF_Z, 0x07, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vphsubdq", vphaddsub_insn, 1, SUF_Z, 0xE3, 0, 0, 0, CPU_XOP, 0, 0}, + {"cdqe", onebyte_insn, 1, SUF_Z, 0x98, 0x40, 0, ONLY_64, 0, 0, 0}, + {"cvtps2dq", xmm_xmm128_insn, 2, SUF_Z, 0x66, 0x5B, 0, 0, CPU_SSE2, 0, 0}, + {"vpsubusw", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0xD9, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"btr", bittest_insn, 6, SUF_Z, 0xB3, 0x06, 0, 0, CPU_386, 0, 0}, + {"fnclex", twobyte_insn, 1, SUF_Z, 0xDB, 0xE2, 0, 0, CPU_FPU, 0, 0}, + {"invlpg", twobytemem_insn, 1, SUF_Z, 0x07, 0x0F, 0x01, 0, CPU_486, CPU_Priv, 0}, + {"vfmaddsubpd", fma_128_256_insn, 4, SUF_Z, 0x5D, 0, 0, ONLY_AVX, CPU_FMA4, 0, 0}, + {"vpbroadcastw", vpbroadcastw_avx2_insn, 4, SUF_Z, 0, 0, 0, ONLY_AVX, CPU_AVX2, 0, 0}, + {"xstorerng", padlock_insn, 1, SUF_Z, 0xC0, 0x00, 0xA7, 0, CPU_PadLock, 0, 0}, + {"neg", f6_insn, 4, SUF_Z, 0x03, 0, 0, 0, 0, 0, 0}, + {"vpshufhw", xmm_xmm128_imm_256avx2_insn, 2, SUF_Z, 0xF3, 0x70, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"a64", NULL, X86_ADDRSIZE>>8, 0x40, 0, 0, 0, ONLY_64, 0, 0, 0}, + {"insertq", insertq_insn, 2, SUF_Z, 0, 0, 0, 0, CPU_SSE4a, 0, 0}, + {"vcmpnle_uqps", ssecmp_128_insn, 3, SUF_Z, 0x16, 0x00, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"int", int_insn, 1, SUF_Z, 0, 0, 0, 0, 0, 0, 0}, + {"vpshufd", xmm_xmm128_imm_256avx2_insn, 2, SUF_Z, 0x66, 0x70, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vsqrtss", xmm_xmm32_insn, 4, SUF_Z, 0xF3, 0x51, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpcmpistrm", sse4pcmpstr_insn, 1, SUF_Z, 0x62, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vcmptruess", ssecmp_32_insn, 4, SUF_Z, 0x0F, 0xF3, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vcmpunordsd", ssecmp_64_insn, 4, SUF_Z, 0x03, 0xF2, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"maxpd", xmm_xmm128_insn, 2, SUF_Z, 0x66, 0x5F, 0, 0, CPU_SSE2, 0, 0}, + {"vcmpneqss", ssecmp_32_insn, 4, SUF_Z, 0x04, 0xF3, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"fucomi", fcom2_insn, 2, SUF_Z, 0xDB, 0xE8, 0, 0, CPU_686, CPU_FPU, 0}, + {"packusdw", sse4_insn, 2, SUF_Z, 0x2B, 0, 0, 0, CPU_SSE41, 0, 0}, + {"lodsw", onebyte_insn, 1, SUF_Z, 0xAD, 0x10, 0, 0, 0, 0, 0}, + {"vpalignr", sse4imm_256avx2_insn, 4, SUF_Z, 0x0F, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpmovmskb", pmovmskb_insn, 6, SUF_Z, 0xC0, 0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vinsertf128", vinsertif128_insn, 1, SUF_Z, 0x18, 0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"paddw", mmxsse2_insn, 2, SUF_Z, 0xFD, 0, 0, 0, CPU_MMX, 0, 0}, + {"pmvnzb", cyrixmmx_insn, 1, SUF_Z, 0x5A, 0, 0, 0, CPU_Cyrix, CPU_MMX, 0}, + {"pabsb", ssse3_insn, 5, SUF_Z, 0x1C, 0, 0, 0, CPU_SSSE3, 0, 0}, + {"vfnmsub231ss", vfma_ss_insn, 2, SUF_Z, 0xBF, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"pandn", mmxsse2_insn, 2, SUF_Z, 0xDF, 0, 0, 0, CPU_MMX, 0, 0}, + {"setnl", setcc_insn, 1, SUF_Z, 0x0D, 0, 0, 0, CPU_386, 0, 0}, + {"vmovupd", movau_insn, 6, SUF_Z, 0x66, 0x10, 0x01, ONLY_AVX, CPU_AVX, 0, 0}, + {"vcvtph2ps", avx_cvtph2ps_insn, 4, SUF_Z, 0x66, 0x13, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vaddsubps", xmm_xmm128_256_insn, 4, SUF_Z, 0xF2, 0xD0, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"sarx", vex_gpr_reg_rm_nds_0F_insn, 2, SUF_Z, 0xF3, 0x38, 0xF7, ONLY_AVX, CPU_BMI2, 0, 0}, + {"vpcomtrued", vpcom_insn, 1, SUF_Z, 0xCE, 0x07, 0, 0, CPU_XOP, 0, 0}, + {"vpsllq", vpshift_insn, 8, SUF_Z, 0xF3, 0x73, 0x06, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpcmpgtq", ssse3_insn, 5, SUF_Z, 0x37, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"cmpxchg8b", cmpxchg8b_insn, 1, SUF_Z, 0, 0, 0, 0, CPU_586, 0, 0}, + {"vfmaddsub132ps", vfma_ps_insn, 2, SUF_Z, 0x96, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"vfnmsub231sd", vfma_sd_insn, 2, SUF_Z, 0xBF, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"vroundps", avx_sse4imm_insn, 3, SUF_Z, 0x08, 0, 0, ONLY_AVX, CPU_SSE41, 0, 0}, + {"xchg", xchg_insn, 16, SUF_Z, 0, 0, 0, 0, 0, 0, 0}, + {"umov", umov_insn, 6, SUF_Z, 0, 0, 0, 0, CPU_386, CPU_Undoc, 0}, + {"vpbroadcastd", vpbroadcastd_avx2_insn, 4, SUF_Z, 0, 0, 0, ONLY_AVX, CPU_AVX2, 0, 0}, + {"fild", fildstp_insn, 4, SUF_Z, 0x00, 0x02, 0x05, 0, CPU_FPU, 0, 0}, + {"sldt", sldtmsw_insn, 6, SUF_Z, 0x00, 0x00, 0, 0, CPU_286, 0, 0}, + {"fdivp", farithp_insn, 3, SUF_Z, 0xF8, 0, 0, 0, CPU_FPU, 0, 0}, + {"jna", jcc_insn, 9, SUF_Z, 0x06, 0, 0, 0, 0, 0, 0}, + {"vpcomtrueb", vpcom_insn, 1, SUF_Z, 0xCC, 0x07, 0, 0, CPU_XOP, 0, 0}, + {"aaa", onebyte_insn, 1, SUF_Z, 0x37, 0, 0, NOT_64, 0, 0, 0}, + {"bsf", bsfr_insn, 3, SUF_Z, 0xBC, 0, 0, 0, CPU_386, 0, 0}, + {"dppd", sse4imm_insn, 2, SUF_Z, 0x41, 0, 0, 0, CPU_SSE41, 0, 0}, + {"cmovnc", cmovcc_insn, 3, SUF_Z, 0x03, 0, 0, 0, CPU_686, 0, 0}, + {"vpcomltb", vpcom_insn, 1, SUF_Z, 0xCC, 0x00, 0, 0, CPU_XOP, 0, 0}, + {"cmpss", xmm_xmm32_imm_insn, 4, SUF_Z, 0xF3, 0xC2, 0, 0, CPU_SSE, 0, 0}, + {"xbts", xbts_insn, 2, SUF_Z, 0, 0, 0, 0, CPU_386, CPU_Obs, CPU_Undoc}, + {"vmovsd", movsd_insn, 5, SUF_Z, 0xC0, 0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"fstsw", fstsw_insn, 2, SUF_Z, 0, 0, 0, 0, CPU_FPU, 0, 0}, + {"xgetbv", threebyte_insn, 1, SUF_Z, 0x0F, 0x01, 0xD0, 0, CPU_386, CPU_XSAVE, 0}, + {"vpcomneuq", vpcom_insn, 1, SUF_Z, 0xEF, 0x05, 0, 0, CPU_XOP, 0, 0}, + {"vcmpneq_usps", ssecmp_128_insn, 3, SUF_Z, 0x14, 0x00, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"roundss", sse4m32imm_insn, 4, SUF_Z, 0x0A, 0, 0, 0, CPU_SSE41, 0, 0}, + {"vpmacsdqh", vpma_insn, 1, SUF_Z, 0x9F, 0, 0, 0, CPU_XOP, 0, 0}, + {"vcmpgepd", ssecmp_128_insn, 3, SUF_Z, 0x0D, 0x66, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vphaddw", ssse3_insn, 5, SUF_Z, 0x01, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"fxrstor", twobytemem_insn, 1, SUF_Z, 0x01, 0x0F, 0xAE, 0, CPU_686, CPU_FPU, 0}, + {"fsave", twobytemem_insn, 1, SUF_Z, 0x06, 0x9B, 0xDD, 0, CPU_FPU, 0, 0}, + {"hlt", onebyte_insn, 1, SUF_Z, 0xF4, 0, 0, 0, CPU_Priv, 0, 0}, + {"fldpi", twobyte_insn, 1, SUF_Z, 0xD9, 0xEB, 0, 0, CPU_FPU, 0, 0}, + {"pavgw", mmxsse2_insn, 2, SUF_Z, 0xE3, 0, 0, 0, CPU_MMX, CPU_P3, 0}, + {"vfmadd231ps", vfma_ps_insn, 2, SUF_Z, 0xB8, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"vpmaxub", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0xDE, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"movd", movd_insn, 8, SUF_Z, 0, 0, 0, 0, CPU_386, CPU_MMX, 0}, + {"pabsw", ssse3_insn, 5, SUF_Z, 0x1D, 0, 0, 0, CPU_SSSE3, 0, 0}, + {"cpuid", twobyte_insn, 1, SUF_Z, 0x0F, 0xA2, 0, 0, CPU_486, 0, 0}, + {"pf2iw", now3d_insn, 1, SUF_Z, 0x1C, 0, 0, 0, CPU_3DNow, CPU_Athlon, 0}, + {"vpcomgeud", vpcom_insn, 1, SUF_Z, 0xEE, 0x03, 0, 0, CPU_XOP, 0, 0}, + {"vcmpgtss", ssecmp_32_insn, 4, SUF_Z, 0x0E, 0xF3, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vcmpsd", cmpsd_insn, 5, SUF_Z, 0xC0, 0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpcomneuw", vpcom_insn, 1, SUF_Z, 0xED, 0x05, 0, 0, CPU_XOP, 0, 0}, + {"cmpunordpd", ssecmp_128_insn, 3, SUF_Z, 0x03, 0x66, 0, 0, CPU_SSE, 0, 0}, + {"pause", onebyte_prefix_insn, 1, SUF_Z, 0xF3, 0x90, 0, 0, CPU_P4, 0, 0}, + {"unpckhpd", xmm_xmm128_insn, 2, SUF_Z, 0x66, 0x15, 0, 0, CPU_SSE2, 0, 0}, + {"vcmpge_oqsd", ssecmp_64_insn, 4, SUF_Z, 0x1D, 0xF2, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"xadd", cmpxchgxadd_insn, 4, SUF_Z, 0xC0, 0, 0, 0, CPU_486, 0, 0}, + {"vpmaxuw", ssse3_insn, 5, SUF_Z, 0x3E, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"cvtsd2ss", xmm_xmm64_insn, 4, SUF_Z, 0xF2, 0x5A, 0, 0, CPU_SSE2, 0, 0}, + {"rcr", shift_insn, 16, SUF_Z, 0x03, 0, 0, 0, 0, 0, 0}, + {"clc", onebyte_insn, 1, SUF_Z, 0xF8, 0, 0, 0, 0, 0, 0}, + {"vpcomgew", vpcom_insn, 1, SUF_Z, 0xCD, 0x03, 0, 0, CPU_XOP, 0, 0}, + {"vpminub", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0xDA, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"movntps", movnt_insn, 2, SUF_Z, 0x00, 0x2B, 0, 0, CPU_SSE, 0, 0}, + {"monitor", threebyte_insn, 1, SUF_Z, 0x0F, 0x01, 0xC8, 0, CPU_SSE3, 0, 0}, + {"vfnmaddss", fma_128_m32_insn, 3, SUF_Z, 0x7A, 0, 0, ONLY_AVX, CPU_FMA4, 0, 0}, + {"seto", setcc_insn, 1, SUF_Z, 0x00, 0, 0, 0, CPU_386, 0, 0}, + {"vcmpneqps", ssecmp_128_insn, 3, SUF_Z, 0x04, 0x00, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vcmplt_oqps", ssecmp_128_insn, 3, SUF_Z, 0x11, 0x00, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vmread", vmxmemrd_insn, 2, SUF_Z, 0, 0, 0, 0, CPU_P4, 0, 0}, + {"vpclmullqlqdq", pclmulqdq_fixed_insn, 2, SUF_Z, 0x00, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"punpckldq", mmxsse2_insn, 2, SUF_Z, 0x62, 0, 0, 0, CPU_MMX, 0, 0}, + {"vpavgb", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0xE0, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"psignb", ssse3_insn, 5, SUF_Z, 0x08, 0, 0, 0, CPU_SSSE3, 0, 0}, + {"fcmovnu", fcmovcc_insn, 1, SUF_Z, 0xDB, 0xD8, 0, 0, CPU_686, CPU_FPU, 0}, + {"vgatherqps", gather_32x_32y_128_insn, 2, SUF_Z, 0x93, 0, 0, ONLY_AVX, CPU_AVX2, 0, 0}, + {"vpcomuw", vpcom_imm_insn, 1, SUF_Z, 0xED, 0, 0, 0, CPU_XOP, 0, 0}, + {"pi2fd", now3d_insn, 1, SUF_Z, 0x0D, 0, 0, 0, CPU_3DNow, 0, 0}, + {"vpcomq", vpcom_imm_insn, 1, SUF_Z, 0xCF, 0, 0, 0, CPU_XOP, 0, 0}, + {"vhaddps", xmm_xmm128_256_insn, 4, SUF_Z, 0xF2, 0x7C, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vphadddq", vphaddsub_insn, 1, SUF_Z, 0xCB, 0, 0, 0, CPU_XOP, 0, 0}, + {"vmulsd", xmm_xmm64_insn, 4, SUF_Z, 0xF2, 0x59, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"mulx", vex_gpr_reg_nds_rm_0F_insn, 2, SUF_Z, 0xF2, 0x38, 0xF6, ONLY_AVX, CPU_BMI2, 0, 0}, + {"vpermpd", vperm_imm_avx2_insn, 1, SUF_Z, 0x01, 0, 0, ONLY_AVX, CPU_AVX2, 0, 0}, + {"vpmovzxbq", sse4m16_insn, 4, SUF_Z, 0x32, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"psraw", pshift_insn, 4, SUF_Z, 0xE1, 0x71, 0x04, 0, CPU_MMX, 0, 0}, + {"vpermilps", vpermil_insn, 4, SUF_Z, 0x04, 0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"jno", jcc_insn, 9, SUF_Z, 0x01, 0, 0, 0, 0, 0, 0}, + {"vcmpordpd", ssecmp_128_insn, 3, SUF_Z, 0x07, 0x66, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"comisd", xmm_xmm64_insn, 4, SUF_Z, 0x66, 0x2F, 0, 0, CPU_SSE2, 0, 0}, + {"vfnmaddsd", fma_128_m64_insn, 3, SUF_Z, 0x7B, 0, 0, ONLY_AVX, CPU_FMA4, 0, 0}, + {"punpckhdq", mmxsse2_insn, 2, SUF_Z, 0x6A, 0, 0, 0, CPU_MMX, 0, 0}, + {"vcmpnle_uqpd", ssecmp_128_insn, 3, SUF_Z, 0x16, 0x66, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"aesenclast", aes_insn, 2, SUF_Z, 0x38, 0xDD, 0, 0, CPU_AVX, 0, 0}, + {"pcmpeqd", mmxsse2_insn, 2, SUF_Z, 0x76, 0, 0, 0, CPU_MMX, 0, 0}, + {"sha1msg2", intel_SHA1MSG2_insn, 1, SUF_Z, 0, 0, 0, 0, CPU_SHA, 0, 0}, + {"vtestps", sse4_insn, 2, SUF_Z, 0x0E, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"pmagw", cyrixmmx_insn, 1, SUF_Z, 0x52, 0, 0, 0, CPU_Cyrix, CPU_MMX, 0}, + {"vpinsrw", pinsrw_insn, 9, SUF_Z, 0xC0, 0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"movntq", movntq_insn, 1, SUF_Z, 0, 0, 0, 0, CPU_SSE, 0, 0}, + {"vfmsub231ps", vfma_ps_insn, 2, SUF_Z, 0xBA, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"cmovno", cmovcc_insn, 3, SUF_Z, 0x01, 0, 0, 0, CPU_686, 0, 0}, + {"punpckhwd", mmxsse2_insn, 2, SUF_Z, 0x69, 0, 0, 0, CPU_MMX, 0, 0}, + {"movq", movq_insn, 9, SUF_Z, 0, 0, 0, 0, CPU_MMX, 0, 0}, + {"vfnmsub132pd", vfma_pd_insn, 2, SUF_Z, 0x9E, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"push", push_insn, 35, SUF_Z, 0, 0, 0, 0, 0, 0, 0}, + {"imul", imul_insn, 19, SUF_Z, 0, 0, 0, 0, 0, 0, 0}, + {"popfd", onebyte_insn, 1, SUF_Z, 0x9D, 0x20, 0, NOT_64, CPU_386, 0, 0}, + {"vfmsub213sd", vfma_sd_insn, 2, SUF_Z, 0xAB, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"call", call_insn, 30, SUF_Z, 0, 0, 0, 0, 0, 0, 0}, + {"pmvzb", cyrixmmx_insn, 1, SUF_Z, 0x58, 0, 0, 0, CPU_Cyrix, CPU_MMX, 0}, + {"vsubpd", xmm_xmm128_256_insn, 4, SUF_Z, 0x66, 0x5C, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpsllvq", vpshiftv_vexw1_avx2_insn, 2, SUF_Z, 0x47, 0, 0, ONLY_AVX, CPU_AVX2, 0, 0}, + {"pclmulhqhqdq", pclmulqdq_fixed_insn, 2, SUF_Z, 0x11, 0, 0, 0, CPU_AVX, 0, 0}, + {"blsmsk", vex_gpr_ndd_rm_0F38_regext_insn, 2, SUF_Z, 0x00, 0xF3, 0x02, ONLY_AVX, CPU_BMI1, 0, 0}, + {"vprotb", vprot_insn, 3, SUF_Z, 0x00, 0, 0, 0, CPU_XOP, 0, 0}, + {"loop", loop_insn, 8, SUF_Z, 0x02, 0, 0, 0, 0, 0, 0}, + {"jle", jcc_insn, 9, SUF_Z, 0x0E, 0, 0, 0, 0, 0, 0}, + {"stgi", threebyte_insn, 1, SUF_Z, 0x0F, 0x01, 0xDC, 0, CPU_SVM, 0, 0}, + {"not", f6_insn, 4, SUF_Z, 0x02, 0, 0, 0, 0, 0, 0}, + {"svldt", cyrixsmm_insn, 1, SUF_Z, 0x7A, 0, 0, 0, CPU_486, CPU_Cyrix, CPU_SMM}, + {"vpmaxsd", ssse3_insn, 5, SUF_Z, 0x3D, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"maxss", xmm_xmm32_insn, 4, SUF_Z, 0xF3, 0x5F, 0, 0, CPU_SSE, 0, 0}, + {"vminpd", xmm_xmm128_256_insn, 4, SUF_Z, 0x66, 0x5D, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"blcs", xop_gpr_reg_rm_09_insn, 2, SUF_Z, 0x01, 0x03, 0, 0, CPU_386, CPU_TBM, 0}, + {"vpcmpeqw", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0x75, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"frndint", twobyte_insn, 1, SUF_Z, 0xD9, 0xFC, 0, 0, CPU_FPU, 0, 0}, + {"vpcmpestrm", sse4pcmpstr_insn, 1, SUF_Z, 0x60, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"cmpeqss", ssecmp_32_insn, 4, SUF_Z, 0x00, 0xF3, 0, 0, CPU_SSE, 0, 0}, + {"vfmsubadd213ps", vfma_ps_insn, 2, SUF_Z, 0xA7, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"cmovnl", cmovcc_insn, 3, SUF_Z, 0x0D, 0, 0, 0, CPU_686, 0, 0}, + {"fldlg2", twobyte_insn, 1, SUF_Z, 0xD9, 0xEC, 0, 0, CPU_FPU, 0, 0}, + {"clflush", clflush_insn, 1, SUF_Z, 0, 0, 0, 0, CPU_P3, 0, 0}, + {"iretq", onebyte_insn, 1, SUF_Z, 0xCF, 0x40, 0, ONLY_64, 0, 0, 0}, + {"vphaddubd", vphaddsub_insn, 1, SUF_Z, 0xD2, 0, 0, 0, CPU_XOP, 0, 0}, + {"vfnmadd213ps", vfma_ps_insn, 2, SUF_Z, 0xAC, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"vmload", svm_rax_insn, 2, SUF_Z, 0xDA, 0, 0, 0, CPU_SVM, 0, 0}, + {"vpminud", ssse3_insn, 5, SUF_Z, 0x3B, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"packssdw", mmxsse2_insn, 2, SUF_Z, 0x6B, 0, 0, 0, CPU_MMX, 0, 0}, + {"pcmpeqw", mmxsse2_insn, 2, SUF_Z, 0x75, 0, 0, 0, CPU_MMX, 0, 0}, + {"js", jcc_insn, 9, SUF_Z, 0x08, 0, 0, 0, 0, 0, 0}, + {"jpo", jcc_insn, 9, SUF_Z, 0x0B, 0, 0, 0, 0, 0, 0}, + {"sidt", twobytemem_insn, 1, SUF_Z, 0x01, 0x0F, 0x01, 0, CPU_286, CPU_Priv, 0}, + {"jnge", jcc_insn, 9, SUF_Z, 0x0C, 0, 0, 0, 0, 0, 0}, + {"loope", loop_insn, 8, SUF_Z, 0x01, 0, 0, 0, 0, 0, 0}, + {"invpcid", invpcid_insn, 2, SUF_Z, 0, 0, 0, 0, CPU_386, CPU_INVPCID, CPU_Priv}, + {"pavgb", mmxsse2_insn, 2, SUF_Z, 0xE0, 0, 0, 0, CPU_MMX, CPU_P3, 0}, + {"pminsd", sse4_insn, 2, SUF_Z, 0x39, 0, 0, 0, CPU_SSE41, 0, 0}, + {"cmovnb", cmovcc_insn, 3, SUF_Z, 0x03, 0, 0, 0, CPU_686, 0, 0}, + {"mulsd", xmm_xmm64_insn, 4, SUF_Z, 0xF2, 0x59, 0, 0, CPU_SSE2, 0, 0}, + {"vcmpgt_oqsd", ssecmp_64_insn, 4, SUF_Z, 0x1E, 0xF2, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"blsr", vex_gpr_ndd_rm_0F38_regext_insn, 2, SUF_Z, 0x00, 0xF3, 0x01, ONLY_AVX, CPU_BMI1, 0, 0}, + {"vcmplt_oqss", ssecmp_32_insn, 4, SUF_Z, 0x11, 0xF3, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vfnmsub213sd", vfma_sd_insn, 2, SUF_Z, 0xAF, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"shrd", shlrd_insn, 9, SUF_Z, 0xAC, 0, 0, 0, CPU_386, 0, 0}, + {"vpackuswb", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0x67, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"paddd", mmxsse2_insn, 2, SUF_Z, 0xFE, 0, 0, 0, CPU_MMX, 0, 0}, + {"vcmpeq_osps", ssecmp_128_insn, 3, SUF_Z, 0x10, 0x00, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vaddpd", xmm_xmm128_256_insn, 4, SUF_Z, 0x66, 0x58, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpbroadcastb", vpbroadcastb_avx2_insn, 4, SUF_Z, 0, 0, 0, ONLY_AVX, CPU_AVX2, 0, 0}, + {"pmuludq", mmxsse2_insn, 2, SUF_Z, 0xF4, 0, 0, 0, CPU_SSE2, 0, 0}, + {"cmpnltsd", ssecmp_64_insn, 4, SUF_Z, 0x05, 0xF2, 0, 0, CPU_SSE2, 0, 0}, + {"vcmpgt_oqpd", ssecmp_128_insn, 3, SUF_Z, 0x1E, 0x66, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpcmpgtb", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0x64, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpcomfalseq", vpcom_insn, 1, SUF_Z, 0xCF, 0x06, 0, 0, CPU_XOP, 0, 0}, + {"vcmpgtpd", ssecmp_128_insn, 3, SUF_Z, 0x0E, 0x66, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vfnmadd231ps", vfma_ps_insn, 2, SUF_Z, 0xBC, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"paddusb", mmxsse2_insn, 2, SUF_Z, 0xDC, 0, 0, 0, CPU_MMX, 0, 0}, + {"vcmpnge_uqpd", ssecmp_128_insn, 3, SUF_Z, 0x19, 0x66, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"cmpps", xmm_xmm128_imm_insn, 1, SUF_Z, 0x00, 0xC2, 0, 0, CPU_SSE, 0, 0}, + {"vsqrtsd", xmm_xmm64_insn, 4, SUF_Z, 0xF2, 0x51, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"setnp", setcc_insn, 1, SUF_Z, 0x0B, 0, 0, 0, CPU_386, 0, 0}, + {"vpcmpeqb", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0x74, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"psubsb", mmxsse2_insn, 2, SUF_Z, 0xE8, 0, 0, 0, CPU_MMX, 0, 0}, + {"vzeroall", vzero_insn, 1, SUF_Z, 0xC4, 0, 0, 0, CPU_AVX, 0, 0}, + {"jo", jcc_insn, 9, SUF_Z, 0x00, 0, 0, 0, 0, 0, 0}, + {"vpmovzxwd", sse4m64_insn, 4, SUF_Z, 0x33, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpminsw", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0xEA, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"bswap", bswap_insn, 2, SUF_Z, 0, 0, 0, 0, CPU_486, 0, 0}, + {"movntpd", movnt_insn, 2, SUF_Z, 0x66, 0x2B, 0, 0, CPU_SSE2, 0, 0}, + {"paddb", mmxsse2_insn, 2, SUF_Z, 0xFC, 0, 0, 0, CPU_MMX, 0, 0}, + {"vpmaskmovq", vmaskmov_vexw1_avx2_insn, 4, SUF_Z, 0x8C, 0, 0, ONLY_AVX, CPU_AVX2, 0, 0}, + {"vfnmsub213pd", vfma_pd_insn, 2, SUF_Z, 0xAE, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"jng", jcc_insn, 9, SUF_Z, 0x0E, 0, 0, 0, 0, 0, 0}, + {"vcmpngeps", ssecmp_128_insn, 3, SUF_Z, 0x09, 0x00, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"minss", xmm_xmm32_insn, 4, SUF_Z, 0xF3, 0x5D, 0, 0, CPU_SSE, 0, 0}, + {"vpsubusb", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0xD8, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vsqrtps", avx_xmm_xmm128_insn, 2, SUF_Z, 0x00, 0x51, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"fclex", threebyte_insn, 1, SUF_Z, 0x9B, 0xDB, 0xE2, 0, CPU_FPU, 0, 0}, + {"pmovzxbq", sse4m16_insn, 4, SUF_Z, 0x32, 0, 0, 0, CPU_SSE41, 0, 0}, + {"vextracti128", vextractif128_insn, 1, SUF_Z, 0x39, 0, 0, ONLY_AVX, CPU_AVX2, 0, 0}, + {"pcmpistri", sse4pcmpstr_insn, 1, SUF_Z, 0x63, 0, 0, 0, CPU_SSE42, 0, 0}, + {"ucomisd", xmm_xmm64_insn, 4, SUF_Z, 0x66, 0x2E, 0, 0, CPU_SSE2, 0, 0}, + {"vmwrite", vmxmemwr_insn, 2, SUF_Z, 0, 0, 0, 0, CPU_P4, 0, 0}, + {"pfacc", now3d_insn, 1, SUF_Z, 0xAE, 0, 0, 0, CPU_3DNow, 0, 0}, + {"lldt", prot286_insn, 1, SUF_Z, 0x02, 0x00, 0, 0, CPU_286, CPU_Priv, CPU_Prot}, + {"fincstp", twobyte_insn, 1, SUF_Z, 0xD9, 0xF7, 0, 0, CPU_FPU, 0, 0}, + {"vcmpps", xmm_xmm128_imm_256_insn, 3, SUF_Z, 0x00, 0xC2, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"fcomp", fcom_insn, 6, SUF_Z, 0xD8, 0x03, 0, 0, CPU_FPU, 0, 0}, + {"pmullw", mmxsse2_insn, 2, SUF_Z, 0xD5, 0, 0, 0, CPU_MMX, 0, 0}, + {"cqo", onebyte_insn, 1, SUF_Z, 0x99, 0x40, 0, ONLY_64, 0, 0, 0}, + {"blendvps", sse4xmm0_insn, 2, SUF_Z, 0x14, 0, 0, 0, CPU_SSE41, 0, 0}, + {"vpcomfalseud", vpcom_insn, 1, SUF_Z, 0xEE, 0x06, 0, 0, CPU_XOP, 0, 0}, + {"vpsignw", ssse3_insn, 5, SUF_Z, 0x09, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"lgs", lfgss_insn, 3, SUF_Z, 0xB5, 0, 0, 0, CPU_386, 0, 0}, + {"vfmaddpd", fma_128_256_insn, 4, SUF_Z, 0x69, 0, 0, ONLY_AVX, CPU_FMA4, 0, 0}, + {"vcmpnge_uqss", ssecmp_32_insn, 4, SUF_Z, 0x19, 0xF3, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"minps", xmm_xmm128_insn, 2, SUF_Z, 0x00, 0x5D, 0, 0, CPU_SSE, 0, 0}, + {"aesdec", aes_insn, 2, SUF_Z, 0x38, 0xDE, 0, 0, CPU_AVX, 0, 0}, + {"vpsignb", ssse3_insn, 5, SUF_Z, 0x08, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"pminud", sse4_insn, 2, SUF_Z, 0x3B, 0, 0, 0, CPU_SSE41, 0, 0}, + {"vpcomuq", vpcom_imm_insn, 1, SUF_Z, 0xEF, 0, 0, 0, CPU_XOP, 0, 0}, + {"vpmaxsw", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0xEE, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vmmcall", threebyte_insn, 1, SUF_Z, 0x0F, 0x01, 0xD9, 0, CPU_SVM, 0, 0}, + {"vpunpckldq", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0x62, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"fcompp", twobyte_insn, 1, SUF_Z, 0xDE, 0xD9, 0, 0, CPU_FPU, 0, 0}, + {"vcmpneq_ussd", ssecmp_64_insn, 4, SUF_Z, 0x14, 0xF2, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpcomneqd", vpcom_insn, 1, SUF_Z, 0xCE, 0x05, 0, 0, CPU_XOP, 0, 0}, + {"pblendw", sse4imm_insn, 2, SUF_Z, 0x0E, 0, 0, 0, CPU_SSE41, 0, 0}, + {"vmovq", vmovq_insn, 5, SUF_Z, 0, 0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"haddps", xmm_xmm128_insn, 2, SUF_Z, 0xF2, 0x7C, 0, 0, CPU_SSE3, 0, 0}, + {"svts", cyrixsmm_insn, 1, SUF_Z, 0x7C, 0, 0, 0, CPU_486, CPU_Cyrix, CPU_SMM}, + {"o16", NULL, X86_OPERSIZE>>8, 0x10, 0, 0, 0, 0, 0, 0, 0}, + {"rcl", shift_insn, 16, SUF_Z, 0x02, 0, 0, 0, 0, 0, 0}, + {"jge", jcc_insn, 9, SUF_Z, 0x0D, 0, 0, 0, 0, 0, 0}, + {"pfrcpit1", now3d_insn, 1, SUF_Z, 0xA6, 0, 0, 0, CPU_3DNow, 0, 0}, + {"pminsb", sse4_insn, 2, SUF_Z, 0x38, 0, 0, 0, CPU_SSE41, 0, 0}, + {"daa", onebyte_insn, 1, SUF_Z, 0x27, 0, 0, NOT_64, 0, 0, 0}, + {"vpcomtrueub", vpcom_insn, 1, SUF_Z, 0xEC, 0x07, 0, 0, CPU_XOP, 0, 0}, + {"andnpd", xmm_xmm128_insn, 2, SUF_Z, 0x66, 0x55, 0, 0, CPU_SSE2, 0, 0}, + {"stosw", onebyte_insn, 1, SUF_Z, 0xAB, 0x10, 0, 0, 0, 0, 0}, + {"vpabsw", avx2_ssse3_2op_insn, 2, SUF_Z, 0x1D, 0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"pfrsqit1", now3d_insn, 1, SUF_Z, 0xA7, 0, 0, 0, CPU_3DNow, 0, 0}, + {"sqrtps", xmm_xmm128_insn, 2, SUF_Z, 0x00, 0x51, 0, 0, CPU_SSE, 0, 0}, + {"fnsave", onebytemem_insn, 1, SUF_Z, 0x06, 0xDD, 0, 0, CPU_FPU, 0, 0}, + {"vpcomleuw", vpcom_insn, 1, SUF_Z, 0xED, 0x01, 0, 0, CPU_XOP, 0, 0}, + {"cvtdq2ps", xmm_xmm128_insn, 2, SUF_Z, 0x00, 0x5B, 0, 0, CPU_SSE2, 0, 0}, + {"vcvtsd2ss", xmm_xmm64_insn, 4, SUF_Z, 0xF2, 0x5A, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vdivpd", xmm_xmm128_256_insn, 4, SUF_Z, 0x66, 0x5E, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vcmpneq_ospd", ssecmp_128_insn, 3, SUF_Z, 0x1C, 0x66, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"wrgsbase", fs_gs_base_insn, 2, SUF_Z, 0x03, 0, 0, ONLY_64, CPU_FSGSBASE, 0, 0}, + {"add", arith_insn, 22, SUF_Z, 0x00, 0x00, 0, 0, 0, 0, 0}, + {"smi", onebyte_insn, 1, SUF_Z, 0xF1, 0, 0, 0, CPU_386, CPU_Undoc, 0}, + {"vpcomequq", vpcom_insn, 1, SUF_Z, 0xEF, 0x04, 0, 0, CPU_XOP, 0, 0}, + {"movapd", movau_insn, 6, SUF_Z, 0x66, 0x28, 0x01, 0, CPU_SSE2, 0, 0}, + {"vpmulhw", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0xE5, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"cvttps2dq", xmm_xmm128_insn, 2, SUF_Z, 0xF3, 0x5B, 0, 0, CPU_SSE2, 0, 0}, + {"addss", xmm_xmm32_insn, 4, SUF_Z, 0xF3, 0x58, 0, 0, CPU_SSE, 0, 0}, + {"rsqrtss", xmm_xmm32_insn, 4, SUF_Z, 0xF3, 0x52, 0, 0, CPU_SSE, 0, 0}, + {"vpperm", vpperm_insn, 2, SUF_Z, 0, 0, 0, 0, CPU_XOP, 0, 0}, + {"vpcomnequq", vpcom_insn, 1, SUF_Z, 0xEF, 0x05, 0, 0, CPU_XOP, 0, 0}, + {"vcvttsd2si", cvt_rx_xmm64_insn, 4, SUF_Z, 0xF2, 0x2C, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"pmulhriw", cyrixmmx_insn, 1, SUF_Z, 0x5D, 0, 0, 0, CPU_Cyrix, CPU_MMX, 0}, + {"mul", f6_insn, 4, SUF_Z, 0x04, 0, 0, 0, 0, 0, 0}, + {"ucomiss", xmm_xmm32_insn, 4, SUF_Z, 0x00, 0x2E, 0, 0, CPU_SSE, 0, 0}, + {"vpcomneqb", vpcom_insn, 1, SUF_Z, 0xCC, 0x05, 0, 0, CPU_XOP, 0, 0}, + {"vpsllw", vpshift_insn, 8, SUF_Z, 0xF1, 0x71, 0x06, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpcomfalseb", vpcom_insn, 1, SUF_Z, 0xCC, 0x06, 0, 0, CPU_XOP, 0, 0}, + {"vpmovsxwd", sse4m64_insn, 4, SUF_Z, 0x23, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"xend", tsx_0x0F_0x01_insn, 1, SUF_Z, 0xD5, 0, 0, 0, CPU_TSX, 0, 0}, + {"pshufd", xmm_xmm128_imm_insn, 1, SUF_Z, 0x66, 0x70, 0, 0, CPU_SSE2, 0, 0}, + {"jnc", jcc_insn, 9, SUF_Z, 0x03, 0, 0, 0, 0, 0, 0}, + {"vcmpnleps", ssecmp_128_insn, 3, SUF_Z, 0x06, 0x00, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"psrldq", pslrldq_insn, 4, SUF_Z, 0x03, 0, 0, 0, CPU_SSE2, 0, 0}, + {"setb", setcc_insn, 1, SUF_Z, 0x02, 0, 0, 0, CPU_386, 0, 0}, + {"pinsrw", pinsrw_insn, 9, SUF_Z, 0, 0, 0, 0, CPU_MMX, CPU_P3, 0}, + {"jnae", jcc_insn, 9, SUF_Z, 0x02, 0, 0, 0, 0, 0, 0}, + {"movupd", movau_insn, 6, SUF_Z, 0x66, 0x10, 0x01, 0, CPU_SSE2, 0, 0}, + {"vcmptrue_ussd", ssecmp_64_insn, 4, SUF_Z, 0x1F, 0xF2, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"fcmovbe", fcmovcc_insn, 1, SUF_Z, 0xDA, 0xD0, 0, 0, CPU_686, CPU_FPU, 0}, + {"movups", movau_insn, 6, SUF_Z, 0x00, 0x10, 0x01, 0, CPU_SSE, 0, 0}, + {"fyl2x", twobyte_insn, 1, SUF_Z, 0xD9, 0xF1, 0, 0, CPU_FPU, 0, 0}, + {"stosd", onebyte_insn, 1, SUF_Z, 0xAB, 0x20, 0, 0, CPU_386, 0, 0}, + {"vcmple_oqss", ssecmp_32_insn, 4, SUF_Z, 0x12, 0xF3, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"jb", jcc_insn, 9, SUF_Z, 0x02, 0, 0, 0, 0, 0, 0}, + {"vpcomfalseub", vpcom_insn, 1, SUF_Z, 0xEC, 0x06, 0, 0, CPU_XOP, 0, 0}, + {"fxam", twobyte_insn, 1, SUF_Z, 0xD9, 0xE5, 0, 0, CPU_FPU, 0, 0}, + {"vmresume", threebyte_insn, 1, SUF_Z, 0x0F, 0x01, 0xC3, 0, CPU_P4, 0, 0}, + {"vcmpneq_osss", ssecmp_32_insn, 4, SUF_Z, 0x1C, 0xF3, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"swapgs", threebyte_insn, 1, SUF_Z, 0x0F, 0x01, 0xF8, ONLY_64, 0, 0, 0}, + {"vpunpckhqdq", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0x6D, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"prefetcht2", twobytemem_insn, 1, SUF_Z, 0x03, 0x0F, 0x18, 0, CPU_P3, 0, 0}, + {"pmachriw", pmachriw_insn, 1, SUF_Z, 0, 0, 0, 0, CPU_Cyrix, CPU_MMX, 0}, + {"aas", onebyte_insn, 1, SUF_Z, 0x3F, 0, 0, NOT_64, 0, 0, 0}, + {"fldz", twobyte_insn, 1, SUF_Z, 0xD9, 0xEE, 0, 0, CPU_FPU, 0, 0}, + {"vcmppd", xmm_xmm128_imm_256_insn, 3, SUF_Z, 0x66, 0xC2, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"retf", retnf_insn, 6, SUF_Z, 0xCA, 0x40, 0, 0, 0, 0, 0}, + {"iretw", onebyte_insn, 1, SUF_Z, 0xCF, 0x10, 0, 0, 0, 0, 0}, + {"pclmulhqlqdq", pclmulqdq_fixed_insn, 2, SUF_Z, 0x01, 0, 0, 0, CPU_AVX, 0, 0}, + {"vpcomgtw", vpcom_insn, 1, SUF_Z, 0xCD, 0x02, 0, 0, CPU_XOP, 0, 0}, + {"pfcmpeq", now3d_insn, 1, SUF_Z, 0xB0, 0, 0, 0, CPU_3DNow, 0, 0}, + {"mfence", threebyte_insn, 1, SUF_Z, 0x0F, 0xAE, 0xF0, 0, CPU_P3, 0, 0}, + {"vprotq", vprot_insn, 3, SUF_Z, 0x03, 0, 0, 0, CPU_XOP, 0, 0}, + {"jae", jcc_insn, 9, SUF_Z, 0x03, 0, 0, 0, 0, 0, 0}, + {"fpatan", twobyte_insn, 1, SUF_Z, 0xD9, 0xF3, 0, 0, CPU_FPU, 0, 0}, + {"pfsub", now3d_insn, 1, SUF_Z, 0x9A, 0, 0, 0, CPU_3DNow, 0, 0}, + {"pmaxsb", sse4_insn, 2, SUF_Z, 0x3C, 0, 0, 0, CPU_SSE41, 0, 0}, + {"vcmpltsd", ssecmp_64_insn, 4, SUF_Z, 0x01, 0xF2, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpcomnequb", vpcom_insn, 1, SUF_Z, 0xEC, 0x05, 0, 0, CPU_XOP, 0, 0}, + {"insw", onebyte_insn, 1, SUF_Z, 0x6D, 0x10, 0, 0, 0, 0, 0}, + {"vfmsub132sd", vfma_sd_insn, 2, SUF_Z, 0x9B, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"prefetchw", twobytemem_insn, 1, SUF_Z, 0x01, 0x0F, 0x0D, 0, CPU_PRFCHW, 0, 0}, + {"vlddqu", lddqu_insn, 2, SUF_Z, 0xC0, 0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vcmpfalsepd", ssecmp_128_insn, 3, SUF_Z, 0x0B, 0x66, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"cmpxchg16b", cmpxchg16b_insn, 1, SUF_Z, 0, 0, 0, ONLY_64, 0, 0, 0}, + {"vpmaddubsw", ssse3_insn, 5, SUF_Z, 0x04, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"smsw", sldtmsw_insn, 6, SUF_Z, 0x04, 0x01, 0, 0, CPU_286, 0, 0}, + {"movlpd", movhlp_insn, 3, SUF_Z, 0x66, 0x12, 0, 0, CPU_SSE2, 0, 0}, + {"vcmpngess", ssecmp_32_insn, 4, SUF_Z, 0x09, 0xF3, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"maskmovq", maskmovq_insn, 1, SUF_Z, 0, 0, 0, 0, CPU_MMX, CPU_P3, 0}, + {"cmovae", cmovcc_insn, 3, SUF_Z, 0x03, 0, 0, 0, CPU_686, 0, 0}, + {"setnae", setcc_insn, 1, SUF_Z, 0x02, 0, 0, 0, CPU_386, 0, 0}, + {"vminss", xmm_xmm32_insn, 4, SUF_Z, 0xF3, 0x5D, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpcomgeub", vpcom_insn, 1, SUF_Z, 0xEC, 0x03, 0, 0, CPU_XOP, 0, 0}, + {"jns", jcc_insn, 9, SUF_Z, 0x09, 0, 0, 0, 0, 0, 0}, + {"ibts", ibts_insn, 2, SUF_Z, 0, 0, 0, 0, CPU_386, CPU_Obs, CPU_Undoc}, + {"je", jcc_insn, 9, SUF_Z, 0x04, 0, 0, 0, 0, 0, 0}, + {"pmovsxbw", sse4m64_insn, 4, SUF_Z, 0x20, 0, 0, 0, CPU_SSE41, 0, 0}, + {"vunpckhps", xmm_xmm128_256_insn, 4, SUF_Z, 0x00, 0x15, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vbroadcasti128", vbroadcastif128_insn, 1, SUF_Z, 0x5A, 0, 0, ONLY_AVX, CPU_AVX2, 0, 0}, + {"cld", onebyte_insn, 1, SUF_Z, 0xFC, 0, 0, 0, 0, 0, 0}, + {"ud1", twobyte_insn, 1, SUF_Z, 0x0F, 0xB9, 0, 0, CPU_286, CPU_Undoc, 0}, + {"vmovups", movau_insn, 6, SUF_Z, 0x00, 0x10, 0x01, ONLY_AVX, CPU_AVX, 0, 0}, + {"f2xm1", twobyte_insn, 1, SUF_Z, 0xD9, 0xF0, 0, 0, CPU_FPU, 0, 0}, + {"vcmpneq_uspd", ssecmp_128_insn, 3, SUF_Z, 0x14, 0x66, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vfnmadd231ss", vfma_ss_insn, 2, SUF_Z, 0xBD, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"vcmpneq_oqss", ssecmp_32_insn, 4, SUF_Z, 0x0C, 0xF3, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpor", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0xEB, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"jrcxz", jcxz_insn, 2, SUF_Z, 0x40, 0, 0, ONLY_64, 0, 0, 0}, + {"vpand", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0xDB, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpminsd", ssse3_insn, 5, SUF_Z, 0x39, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpcomgtuq", vpcom_insn, 1, SUF_Z, 0xEF, 0x02, 0, 0, CPU_XOP, 0, 0}, + {"vpmovzxbw", sse4m64_insn, 4, SUF_Z, 0x30, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpcomtrueud", vpcom_insn, 1, SUF_Z, 0xEE, 0x07, 0, 0, CPU_XOP, 0, 0}, + {"vpcomneb", vpcom_insn, 1, SUF_Z, 0xCC, 0x05, 0, 0, CPU_XOP, 0, 0}, + {"cvttps2pi", cvt_mm_xmm64_insn, 2, SUF_Z, 0x2C, 0, 0, 0, CPU_SSE, 0, 0}, + {"movmskpd", movmsk_insn, 4, SUF_Z, 0x66, 0, 0, 0, CPU_SSE2, 0, 0}, + {"pfsubr", now3d_insn, 1, SUF_Z, 0xAA, 0, 0, 0, CPU_3DNow, 0, 0}, + {"vsubss", xmm_xmm32_insn, 4, SUF_Z, 0xF3, 0x5C, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"invvpid", eptvpid_insn, 2, SUF_Z, 0x01, 0, 0, 0, CPU_386, CPU_EPTVPID, 0}, + {"cmpleps", ssecmp_128_insn, 3, SUF_Z, 0x02, 0, 0, 0, CPU_SSE, 0, 0}, + {"vpavgw", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0xE3, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vmovhlps", movhllhps_insn, 2, SUF_Z, 0x12, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vcmpeq_uqpd", ssecmp_128_insn, 3, SUF_Z, 0x08, 0x66, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"maxps", xmm_xmm128_insn, 2, SUF_Z, 0x00, 0x5F, 0, 0, CPU_SSE, 0, 0}, + {"insb", onebyte_insn, 1, SUF_Z, 0x6C, 0x00, 0, 0, 0, 0, 0}, + {"vpmaxsb", ssse3_insn, 5, SUF_Z, 0x3C, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vcmplepd", ssecmp_128_insn, 3, SUF_Z, 0x02, 0x66, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"popad", onebyte_insn, 1, SUF_Z, 0x61, 0x20, 0, NOT_64, CPU_386, 0, 0}, + {"cmovnge", cmovcc_insn, 3, SUF_Z, 0x0C, 0, 0, 0, CPU_686, 0, 0}, + {"unpckhps", xmm_xmm128_insn, 2, SUF_Z, 0x00, 0x15, 0, 0, CPU_SSE, 0, 0}, + {"cmovpo", cmovcc_insn, 3, SUF_Z, 0x0B, 0, 0, 0, CPU_686, 0, 0}, + {"setnb", setcc_insn, 1, SUF_Z, 0x03, 0, 0, 0, CPU_386, 0, 0}, + {"sbb", arith_insn, 22, SUF_Z, 0x18, 0x03, 0, 0, 0, 0, 0}, + {"divpd", xmm_xmm128_insn, 2, SUF_Z, 0x66, 0x5E, 0, 0, CPU_SSE2, 0, 0}, + {"vbroadcastf128", vbroadcastif128_insn, 1, SUF_Z, 0x1A, 0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"insd", onebyte_insn, 1, SUF_Z, 0x6D, 0x20, 0, 0, CPU_386, 0, 0}, + {"invept", eptvpid_insn, 2, SUF_Z, 0x00, 0, 0, 0, CPU_386, CPU_EPTVPID, 0}, + {"vmaxsd", xmm_xmm64_insn, 4, SUF_Z, 0xF2, 0x5F, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"cmpsw", onebyte_insn, 1, SUF_Z, 0xA7, 0x10, 0, 0, 0, 0, 0}, + {"vcmpeqss", ssecmp_32_insn, 4, SUF_Z, 0x00, 0xF3, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"mulps", xmm_xmm128_insn, 2, SUF_Z, 0x00, 0x59, 0, 0, CPU_SSE, 0, 0}, + {"vaddps", xmm_xmm128_256_insn, 4, SUF_Z, 0x00, 0x58, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vcmpgeps", ssecmp_128_insn, 3, SUF_Z, 0x0D, 0x00, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vfrczps", vfrc_pdps_insn, 2, SUF_Z, 0x00, 0, 0, 0, CPU_XOP, 0, 0}, + {"vcmpeq_uqss", ssecmp_32_insn, 4, SUF_Z, 0x08, 0xF3, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"sysexit", twobyte_insn, 1, SUF_Z, 0x0F, 0x35, 0, NOT_64, CPU_686, CPU_Priv, 0}, + {"xor", arith_insn, 22, SUF_Z, 0x30, 0x06, 0, 0, 0, 0, 0}, + {"pshuflw", xmm_xmm128_imm_insn, 1, SUF_Z, 0xF2, 0x70, 0, 0, CPU_SSE2, 0, 0}, + {"vfrczpd", vfrc_pdps_insn, 2, SUF_Z, 0x01, 0, 0, 0, CPU_XOP, 0, 0}, + {"vpcomleud", vpcom_insn, 1, SUF_Z, 0xEE, 0x01, 0, 0, CPU_XOP, 0, 0}, + {"vpcomlew", vpcom_insn, 1, SUF_Z, 0xCD, 0x01, 0, 0, CPU_XOP, 0, 0}, + {"addps", xmm_xmm128_insn, 2, SUF_Z, 0x00, 0x58, 0, 0, CPU_SSE, 0, 0}, + {"vpsraw", vpshift_insn, 8, SUF_Z, 0xE1, 0x71, 0x04, ONLY_AVX, CPU_AVX, 0, 0}, + {"vcomiss", avx_xmm_xmm32_insn, 2, SUF_Z, 0x00, 0x2F, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vcmpngtpd", ssecmp_128_insn, 3, SUF_Z, 0x0A, 0x66, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"cmpnltpd", ssecmp_128_insn, 3, SUF_Z, 0x05, 0x66, 0, 0, CPU_SSE, 0, 0}, + {"sqrtsd", xmm_xmm64_insn, 4, SUF_Z, 0xF2, 0x51, 0, 0, CPU_SSE2, 0, 0}, + {"pfrsqrt", now3d_insn, 1, SUF_Z, 0x97, 0, 0, 0, CPU_3DNow, 0, 0}, + {"scasw", onebyte_insn, 1, SUF_Z, 0xAF, 0x10, 0, 0, 0, 0, 0}, + {"pinsrd", pinsrd_insn, 2, SUF_Z, 0, 0, 0, 0, CPU_386, CPU_SSE41, 0}, + {"vaesenclast", aes_insn, 2, SUF_Z, 0x38, 0xDD, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"rdtscp", threebyte_insn, 1, SUF_Z, 0x0F, 0x01, 0xF9, 0, CPU_686, CPU_AMD, CPU_Priv}, + {"vcmpeq_ospd", ssecmp_128_insn, 3, SUF_Z, 0x10, 0x66, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"div", div_insn, 8, SUF_Z, 0x06, 0, 0, 0, 0, 0, 0}, + {"cvtpd2pi", cvt_mm_xmm_insn, 1, SUF_Z, 0x66, 0x2D, 0, 0, CPU_SSE2, 0, 0}, + {"vcmpltss", ssecmp_32_insn, 4, SUF_Z, 0x01, 0xF3, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vphaddwq", vphaddsub_insn, 1, SUF_Z, 0xC7, 0, 0, 0, CPU_XOP, 0, 0}, + {"cmovz", cmovcc_insn, 3, SUF_Z, 0x04, 0, 0, 0, CPU_686, 0, 0}, + {"vpcomltud", vpcom_insn, 1, SUF_Z, 0xEE, 0x00, 0, 0, CPU_XOP, 0, 0}, + {"ret", retnf_insn, 6, SUF_Z, 0xC2, 0, 0, 0, 0, 0, 0}, + {"vpshaw", amd_vpshift_insn, 2, SUF_Z, 0x99, 0, 0, 0, CPU_XOP, 0, 0}, + {"pblendvb", sse4xmm0_insn, 2, SUF_Z, 0x10, 0, 0, 0, CPU_SSE41, 0, 0}, + {"pinsrq", pinsrq_insn, 2, SUF_Z, 0, 0, 0, ONLY_64, CPU_SSE41, 0, 0}, + {"vmulpd", xmm_xmm128_256_insn, 4, SUF_Z, 0x66, 0x59, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"pmaxsd", sse4_insn, 2, SUF_Z, 0x3D, 0, 0, 0, CPU_SSE41, 0, 0}, + {"cmovne", cmovcc_insn, 3, SUF_Z, 0x05, 0, 0, 0, CPU_686, 0, 0}, + {"ltr", prot286_insn, 1, SUF_Z, 0x03, 0x00, 0, 0, CPU_286, CPU_Priv, CPU_Prot}, + {"fdecstp", twobyte_insn, 1, SUF_Z, 0xD9, 0xF6, 0, 0, CPU_FPU, 0, 0}, + {"lsl", larlsl_insn, 6, SUF_Z, 0x03, 0, 0, 0, CPU_286, CPU_Prot, 0}, + {"pcmpgtb", mmxsse2_insn, 2, SUF_Z, 0x64, 0, 0, 0, CPU_MMX, 0, 0}, + {"psrld", pshift_insn, 4, SUF_Z, 0xD2, 0x72, 0x02, 0, CPU_MMX, 0, 0}, + {"xsave", twobytemem_insn, 1, SUF_Z, 0x04, 0x0F, 0xAE, 0, CPU_386, CPU_XSAVE, 0}, + {"hsubps", xmm_xmm128_insn, 2, SUF_Z, 0xF2, 0x7D, 0, 0, CPU_SSE3, 0, 0}, + {"sti", onebyte_insn, 1, SUF_Z, 0xFB, 0, 0, 0, 0, 0, 0}, + {"pfcmpge", now3d_insn, 1, SUF_Z, 0x90, 0, 0, 0, CPU_3DNow, 0, 0}, + {"setnz", setcc_insn, 1, SUF_Z, 0x05, 0, 0, 0, CPU_386, 0, 0}, + {"vaesdeclast", aes_insn, 2, SUF_Z, 0x38, 0xDF, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vfnmadd213ss", vfma_ss_insn, 2, SUF_Z, 0xAD, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"pcmpestri", sse4pcmpstr_insn, 1, SUF_Z, 0x61, 0, 0, 0, CPU_SSE42, 0, 0}, + {"vpcmpeqq", ssse3_insn, 5, SUF_Z, 0x29, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"fmul", farith_insn, 7, SUF_Z, 0xC8, 0xC8, 0x01, 0, CPU_FPU, 0, 0}, + {"vmovntpd", movnt_insn, 2, SUF_Z, 0x66, 0x2B, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpmadcsswd", vpma_insn, 1, SUF_Z, 0xA6, 0, 0, 0, CPU_XOP, 0, 0}, + {"vcmpngt_uqps", ssecmp_128_insn, 3, SUF_Z, 0x1A, 0x00, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"svdc", svdc_insn, 1, SUF_Z, 0, 0, 0, 0, CPU_486, CPU_Cyrix, CPU_SMM}, + {"orpd", xmm_xmm128_insn, 2, SUF_Z, 0x66, 0x56, 0, 0, CPU_SSE2, 0, 0}, + {"fdivrp", farithp_insn, 3, SUF_Z, 0xF0, 0, 0, 0, CPU_FPU, 0, 0}, + {"vgatherdps", gather_32x_32y_insn, 2, SUF_Z, 0x92, 0, 0, ONLY_AVX, CPU_AVX2, 0, 0}, + {"packsswb", mmxsse2_insn, 2, SUF_Z, 0x63, 0, 0, 0, CPU_MMX, 0, 0}, + {"scasd", onebyte_insn, 1, SUF_Z, 0xAF, 0x20, 0, 0, CPU_386, 0, 0}, + {"vfmsub231pd", vfma_pd_insn, 2, SUF_Z, 0xBA, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"fptan", twobyte_insn, 1, SUF_Z, 0xD9, 0xF2, 0, 0, CPU_FPU, 0, 0}, + {"vpcomd", vpcom_imm_insn, 1, SUF_Z, 0xCE, 0, 0, 0, CPU_XOP, 0, 0}, + {"cvtsi2sd", cvt_xmm_rmx_insn, 6, SUF_Z, 0xF2, 0x2A, 0, 0, CPU_SSE2, 0, 0}, + {"vphsubwd", vphaddsub_insn, 1, SUF_Z, 0xE2, 0, 0, 0, CPU_XOP, 0, 0}, + {"vcmpnlt_uqpd", ssecmp_128_insn, 3, SUF_Z, 0x15, 0x66, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"cmpneqpd", ssecmp_128_insn, 3, SUF_Z, 0x04, 0x66, 0, 0, CPU_SSE, 0, 0}, + {"ud2", twobyte_insn, 1, SUF_Z, 0x0F, 0x0B, 0, 0, CPU_286, 0, 0}, + {"andps", xmm_xmm128_insn, 2, SUF_Z, 0x00, 0x54, 0, 0, CPU_SSE, 0, 0}, + {"vorpd", xmm_xmm128_256_insn, 4, SUF_Z, 0x66, 0x56, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"lmsw", prot286_insn, 1, SUF_Z, 0x06, 0x01, 0, 0, CPU_286, CPU_Priv, 0}, + {"tzmsk", xop_gpr_reg_rm_09_insn, 2, SUF_Z, 0x01, 0x04, 0, 0, CPU_386, CPU_TBM, 0}, + {"vdppd", sse4imm_insn, 2, SUF_Z, 0x41, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"smintold", twobyte_insn, 1, SUF_Z, 0x0F, 0x7E, 0, 0, CPU_486, CPU_Cyrix, CPU_Obs}, + {"smint", twobyte_insn, 1, SUF_Z, 0x0F, 0x38, 0, 0, CPU_686, CPU_Cyrix, 0}, + {"vcmpnlt_uqss", ssecmp_32_insn, 4, SUF_Z, 0x15, 0xF3, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"cmovs", cmovcc_insn, 3, SUF_Z, 0x08, 0, 0, 0, CPU_686, 0, 0}, + {"vpcomequw", vpcom_insn, 1, SUF_Z, 0xED, 0x04, 0, 0, CPU_XOP, 0, 0}, + {"cvttsd2si", cvt_rx_xmm64_insn, 4, SUF_Z, 0xF2, 0x2C, 0, 0, CPU_SSE2, 0, 0}, + {"vcmpge_oqss", ssecmp_32_insn, 4, SUF_Z, 0x1D, 0xF3, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"minpd", xmm_xmm128_insn, 2, SUF_Z, 0x66, 0x5D, 0, 0, CPU_SSE2, 0, 0}, + {"por", mmxsse2_insn, 2, SUF_Z, 0xEB, 0, 0, 0, CPU_MMX, 0, 0}, + {"vcmpfalseps", ssecmp_128_insn, 3, SUF_Z, 0x0B, 0x00, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vaddsubpd", xmm_xmm128_256_insn, 4, SUF_Z, 0x66, 0xD0, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vmxon", vmxthreebytemem_insn, 1, SUF_Z, 0xF3, 0, 0, 0, CPU_P4, 0, 0}, + {"fldln2", twobyte_insn, 1, SUF_Z, 0xD9, 0xED, 0, 0, CPU_FPU, 0, 0}, + {"pfpnacc", now3d_insn, 1, SUF_Z, 0x8E, 0, 0, 0, CPU_3DNow, CPU_Athlon, 0}, + {"lfs", lfgss_insn, 3, SUF_Z, 0xB4, 0, 0, 0, CPU_386, 0, 0}, + {"vmovlps", movhlp_insn, 3, SUF_Z, 0x00, 0x12, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vcvtsi2sd", cvt_xmm_rmx_insn, 6, SUF_Z, 0xF2, 0x2A, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vcvtdq2ps", avx_xmm_xmm128_insn, 2, SUF_Z, 0x00, 0x5B, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vcvtss2sd", xmm_xmm32_insn, 4, SUF_Z, 0xF3, 0x5A, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vcmpge_oqpd", ssecmp_128_insn, 3, SUF_Z, 0x1D, 0x66, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vfmsub132pd", vfma_pd_insn, 2, SUF_Z, 0x9A, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"vpblendw", sse4imm_256avx2_insn, 4, SUF_Z, 0x0E, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"pmulhrw", now3d_insn, 1, SUF_Z, 0xB7, 0, 0, 0, CPU_3DNow, 0, 0}, + {"vcmpless", ssecmp_32_insn, 4, SUF_Z, 0x02, 0xF3, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"movntss", movntss_insn, 1, SUF_Z, 0, 0, 0, 0, CPU_SSE4a, 0, 0}, + {"vpandn", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0xDF, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"pextrd", pextrd_insn, 1, SUF_Z, 0, 0, 0, 0, CPU_386, CPU_SSE41, 0}, + {"divsd", xmm_xmm64_insn, 4, SUF_Z, 0xF2, 0x5E, 0, 0, CPU_SSE2, 0, 0}, + {"pmaxud", sse4_insn, 2, SUF_Z, 0x3F, 0, 0, 0, CPU_SSE41, 0, 0}, + {"pfmul", now3d_insn, 1, SUF_Z, 0xB4, 0, 0, 0, CPU_3DNow, 0, 0}, + {"vmaxpd", xmm_xmm128_256_insn, 4, SUF_Z, 0x66, 0x5F, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vgatherdpd", gather_64x_64x_insn, 2, SUF_Z, 0x92, 0, 0, ONLY_AVX, CPU_AVX2, 0, 0}, + {"movnti", movnti_insn, 2, SUF_Z, 0, 0, 0, 0, CPU_P4, 0, 0}, + {"pxor", mmxsse2_insn, 2, SUF_Z, 0xEF, 0, 0, 0, CPU_MMX, 0, 0}, + {"vpmovsxbw", sse4m64_insn, 4, SUF_Z, 0x20, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vmovhps", movhlp_insn, 3, SUF_Z, 0x00, 0x16, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"jbe", jcc_insn, 9, SUF_Z, 0x06, 0, 0, 0, 0, 0, 0}, + {"outsw", onebyte_insn, 1, SUF_Z, 0x6F, 0x10, 0, 0, 0, 0, 0}, + {"vcmpngt_uqpd", ssecmp_128_insn, 3, SUF_Z, 0x1A, 0x66, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vcmpeqpd", ssecmp_128_insn, 3, SUF_Z, 0x00, 0x66, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpermd", vperm_var_avx2_insn, 1, SUF_Z, 0x36, 0, 0, ONLY_AVX, CPU_AVX2, 0, 0}, + {"vpcomltuw", vpcom_insn, 1, SUF_Z, 0xED, 0x00, 0, 0, CPU_XOP, 0, 0}, + {"wrshr", rdwrshr_insn, 1, SUF_Z, 0x01, 0, 0, 0, CPU_686, CPU_Cyrix, CPU_SMM}, + {"vmxoff", threebyte_insn, 1, SUF_Z, 0x0F, 0x01, 0xC4, 0, CPU_P4, 0, 0}, + {"paddq", mmxsse2_insn, 2, SUF_Z, 0xD4, 0, 0, 0, CPU_MMX, 0, 0}, + {"fstcw", fstcw_insn, 1, SUF_Z, 0, 0, 0, 0, CPU_FPU, 0, 0}, + {"setnle", setcc_insn, 1, SUF_Z, 0x0F, 0, 0, 0, CPU_386, 0, 0}, + {"cbw", onebyte_insn, 1, SUF_Z, 0x98, 0x10, 0, 0, 0, 0, 0}, + {"vfmsub213ss", vfma_ss_insn, 2, SUF_Z, 0xAB, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"pfmax", now3d_insn, 1, SUF_Z, 0xA4, 0, 0, 0, CPU_3DNow, 0, 0}, + {"jnb", jcc_insn, 9, SUF_Z, 0x03, 0, 0, 0, 0, 0, 0}, + {"blendps", sse4imm_insn, 2, SUF_Z, 0x0C, 0, 0, 0, CPU_SSE41, 0, 0}, + {"fsincos", twobyte_insn, 1, SUF_Z, 0xD9, 0xFB, 0, 0, CPU_286, CPU_FPU, 0}, + {"vfmadd231ss", vfma_ss_insn, 2, SUF_Z, 0xB9, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"fld1", twobyte_insn, 1, SUF_Z, 0xD9, 0xE8, 0, 0, CPU_FPU, 0, 0}, + {"t1mskc", xop_gpr_reg_rm_09_insn, 2, SUF_Z, 0x01, 0x07, 0, 0, CPU_386, CPU_TBM, 0}, + {"xabort", tsx_xabort_insn, 1, SUF_Z, 0, 0, 0, 0, CPU_TSX, 0, 0}, + {"pextrw", pextrw_insn, 7, SUF_Z, 0, 0, 0, 0, CPU_MMX, CPU_P3, 0}, + {"vfnmsub231pd", vfma_pd_insn, 2, SUF_Z, 0xBE, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"psubsw", mmxsse2_insn, 2, SUF_Z, 0xE9, 0, 0, 0, CPU_MMX, 0, 0}, + {"vfnmsubss", fma_128_m32_insn, 3, SUF_Z, 0x7E, 0, 0, ONLY_AVX, CPU_FMA4, 0, 0}, + {"lea", lea_insn, 3, SUF_Z, 0, 0, 0, 0, 0, 0, 0}, + {"vmptrld", vmxtwobytemem_insn, 1, SUF_Z, 0x06, 0, 0, 0, CPU_P4, 0, 0}, + {"cmpeqsd", ssecmp_64_insn, 4, SUF_Z, 0x00, 0xF2, 0, 0, CPU_SSE2, 0, 0}, + {"o64", NULL, X86_OPERSIZE>>8, 0x40, 0, 0, 0, ONLY_64, 0, 0, 0}, + {"vcvtpd2ps", avx_cvt_xmm128_insn, 2, SUF_Z, 0x66, 0x5A, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"faddp", farithp_insn, 3, SUF_Z, 0xC0, 0, 0, 0, CPU_FPU, 0, 0}, + {"vpsrldq", pslrldq_insn, 4, SUF_Z, 0x03, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vcmpfalsesd", ssecmp_64_insn, 4, SUF_Z, 0x0B, 0xF2, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"lzcnt", cnt_insn, 3, SUF_Z, 0xBD, 0, 0, 0, CPU_LZCNT, 0, 0}, + {"vcmpunord_sss", ssecmp_32_insn, 4, SUF_Z, 0x13, 0xF3, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vcmpleps", ssecmp_128_insn, 3, SUF_Z, 0x02, 0x00, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vextractps", extractps_insn, 2, SUF_Z, 0xC0, 0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"enter", enter_insn, 3, SUF_Z, 0, 0, 0, 0, CPU_186, 0, 0}, + {"vandnpd", xmm_xmm128_256_insn, 4, SUF_Z, 0x66, 0x55, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"roundsd", sse4m64imm_insn, 4, SUF_Z, 0x0B, 0, 0, 0, CPU_SSE41, 0, 0}, + {"vpaddb", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0xFC, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"cmpordss", ssecmp_32_insn, 4, SUF_Z, 0x07, 0xF3, 0, 0, CPU_SSE, 0, 0}, + {"vpcomeqb", vpcom_insn, 1, SUF_Z, 0xCC, 0x04, 0, 0, CPU_XOP, 0, 0}, + {"vgatherqpd", gather_64x_64y_insn, 2, SUF_Z, 0x93, 0, 0, ONLY_AVX, CPU_AVX2, 0, 0}, + {"pcmpeqq", sse4_insn, 2, SUF_Z, 0x29, 0, 0, 0, CPU_SSE41, 0, 0}, + {"fsetpm", twobyte_insn, 1, SUF_Z, 0xDB, 0xE4, 0, 0, CPU_286, CPU_FPU, CPU_Obs}, + {"vpcomgeuw", vpcom_insn, 1, SUF_Z, 0xED, 0x03, 0, 0, CPU_XOP, 0, 0}, + {"vpmadcswd", vpma_insn, 1, SUF_Z, 0xB6, 0, 0, 0, CPU_XOP, 0, 0}, + {"vcvtps2ph", avx_cvtps2ph_insn, 4, SUF_Z, 0x66, 0x1D, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vcmpneqpd", ssecmp_128_insn, 3, SUF_Z, 0x04, 0x66, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"fcmove", fcmovcc_insn, 1, SUF_Z, 0xDA, 0xC8, 0, 0, CPU_686, CPU_FPU, 0}, + {"vfmadd231pd", vfma_pd_insn, 2, SUF_Z, 0xB8, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"fprem1", twobyte_insn, 1, SUF_Z, 0xD9, 0xF5, 0, 0, CPU_286, CPU_FPU, 0}, + {"setna", setcc_insn, 1, SUF_Z, 0x06, 0, 0, 0, CPU_386, 0, 0}, + {"cwd", onebyte_insn, 1, SUF_Z, 0x99, 0x10, 0, 0, 0, 0, 0}, + {"aesimc", aesimc_insn, 1, SUF_Z, 0x38, 0xDB, 0, 0, CPU_AES, 0, 0}, + {"idiv", div_insn, 8, SUF_Z, 0x07, 0, 0, 0, 0, 0, 0}, + {"vcmplt_oqsd", ssecmp_64_insn, 4, SUF_Z, 0x11, 0xF2, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"cvtps2pi", cvt_mm_xmm64_insn, 2, SUF_Z, 0x2D, 0, 0, 0, CPU_SSE, 0, 0}, + {"vblendps", sse4imm_256_insn, 4, SUF_Z, 0x0C, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"setnge", setcc_insn, 1, SUF_Z, 0x0C, 0, 0, 0, CPU_386, 0, 0}, + {"xsaveopt64", xsaveopt64_insn, 1, SUF_Z, 0x06, 0x0F, 0xAE, ONLY_64, CPU_XSAVEOPT, 0, 0}, + {"pcmpestrm", sse4pcmpstr_insn, 1, SUF_Z, 0x60, 0, 0, 0, CPU_SSE42, 0, 0}, + {"vpshlq", amd_vpshift_insn, 2, SUF_Z, 0x97, 0, 0, 0, CPU_XOP, 0, 0}, + {"vmaskmovdqu", maskmovdqu_insn, 1, SUF_Z, 0xC0, 0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpcomnew", vpcom_insn, 1, SUF_Z, 0xCD, 0x05, 0, 0, CPU_XOP, 0, 0}, + {"vcmpunordpd", ssecmp_128_insn, 3, SUF_Z, 0x03, 0x66, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vcmpneqsd", ssecmp_64_insn, 4, SUF_Z, 0x04, 0xF2, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"cvttpd2dq", xmm_xmm128_insn, 2, SUF_Z, 0x66, 0xE6, 0, 0, CPU_SSE2, 0, 0}, + {"sahf", onebyte_insn, 1, SUF_Z, 0x9E, 0, 0, 0, 0, 0, 0}, + {"vpshab", amd_vpshift_insn, 2, SUF_Z, 0x98, 0, 0, 0, CPU_XOP, 0, 0}, + {"jnz", jcc_insn, 9, SUF_Z, 0x05, 0, 0, 0, 0, 0, 0}, + {"pextrb", pextrb_insn, 3, SUF_Z, 0, 0, 0, 0, CPU_SSE41, 0, 0}, + {"vmsave", svm_rax_insn, 2, SUF_Z, 0xDB, 0, 0, 0, CPU_SVM, 0, 0}, + {"vcmpordsd", ssecmp_64_insn, 4, SUF_Z, 0x07, 0xF2, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"setbe", setcc_insn, 1, SUF_Z, 0x06, 0, 0, 0, CPU_386, 0, 0}, + {"vfmsubadd231ps", vfma_ps_insn, 2, SUF_Z, 0xB7, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"vpcomgtb", vpcom_insn, 1, SUF_Z, 0xCC, 0x02, 0, 0, CPU_XOP, 0, 0}, + {"vfnmsubps", fma_128_256_insn, 4, SUF_Z, 0x7C, 0, 0, ONLY_AVX, CPU_FMA4, 0, 0}, + {"shrx", vex_gpr_reg_rm_nds_0F_insn, 2, SUF_Z, 0xF2, 0x38, 0xF7, ONLY_AVX, CPU_BMI2, 0, 0}, + {"dpps", sse4imm_insn, 2, SUF_Z, 0x40, 0, 0, 0, CPU_SSE41, 0, 0}, + {"movdqa", movau_insn, 6, SUF_Z, 0x66, 0x6F, 0x10, 0, CPU_SSE2, 0, 0}, + {"xcryptofb", padlock_insn, 1, SUF_Z, 0xE8, 0xF3, 0xA7, 0, CPU_PadLock, 0, 0}, + {"jmp", jmp_insn, 31, SUF_Z, 0, 0, 0, 0, 0, 0, 0}, + {"vpsrlq", vpshift_insn, 8, SUF_Z, 0xD3, 0x73, 0x02, ONLY_AVX, CPU_AVX, 0, 0}, + {"invlpga", invlpga_insn, 2, SUF_Z, 0, 0, 0, 0, CPU_SVM, 0, 0}, + {"vpcomgtq", vpcom_insn, 1, SUF_Z, 0xCF, 0x02, 0, 0, CPU_XOP, 0, 0}, + {"vpsadbw", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0xF6, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vroundsd", sse4m64imm_insn, 4, SUF_Z, 0x0B, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vfmaddss", fma_128_m32_insn, 3, SUF_Z, 0x6A, 0, 0, ONLY_AVX, CPU_FMA4, 0, 0}, + {"fbstp", fbldstp_insn, 1, SUF_Z, 0x06, 0, 0, 0, CPU_FPU, 0, 0}, + {"rdpmc", twobyte_insn, 1, SUF_Z, 0x0F, 0x33, 0, 0, CPU_686, 0, 0}, + {"pslld", pshift_insn, 4, SUF_Z, 0xF2, 0x72, 0x06, 0, CPU_MMX, 0, 0}, + {"vpcomeqd", vpcom_insn, 1, SUF_Z, 0xCE, 0x04, 0, 0, CPU_XOP, 0, 0}, + {"movntdqa", movntdqa_insn, 2, SUF_Z, 0, 0, 0, 0, CPU_SSE41, 0, 0}, + {"subps", xmm_xmm128_insn, 2, SUF_Z, 0x00, 0x5C, 0, 0, CPU_SSE, 0, 0}, + {"adcx", vex_gpr_ndd_rm_0F38_insn, 2, SUF_Z, 0x66, 0xF6, 0, 0, CPU_ADX, 0, 0}, + {"repz", NULL, X86_LOCKREP>>8, 0xF3, 0, 0, 0, 0, 0, 0, 0}, + {"ja", jcc_insn, 9, SUF_Z, 0x07, 0, 0, 0, 0, 0, 0}, + {"vpmacsdql", vpma_insn, 1, SUF_Z, 0x97, 0, 0, 0, CPU_XOP, 0, 0}, + {"psadbw", mmxsse2_insn, 2, SUF_Z, 0xF6, 0, 0, 0, CPU_MMX, CPU_P3, 0}, + {"vfnmaddps", fma_128_256_insn, 4, SUF_Z, 0x78, 0, 0, ONLY_AVX, CPU_FMA4, 0, 0}, + {"pshufb", ssse3_insn, 5, SUF_Z, 0x00, 0, 0, 0, CPU_SSSE3, 0, 0}, + {"o32", NULL, X86_OPERSIZE>>8, 0x20, 0, 0, 0, 0, 0, 0, 0}, + {"vpcomeqq", vpcom_insn, 1, SUF_Z, 0xCF, 0x04, 0, 0, CPU_XOP, 0, 0}, + {"blendpd", sse4imm_insn, 2, SUF_Z, 0x0D, 0, 0, 0, CPU_SSE41, 0, 0}, + {"popfq", onebyte_insn, 1, SUF_Z, 0x9D, 0x40, 0x40, ONLY_64, 0, 0, 0}, + {"vhsubps", xmm_xmm128_256_insn, 4, SUF_Z, 0xF2, 0x7D, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpclmulhqlqdq", pclmulqdq_fixed_insn, 2, SUF_Z, 0x01, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vandpd", xmm_xmm128_256_insn, 4, SUF_Z, 0x66, 0x54, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"cvtpi2ps", cvt_xmm_mm_ps_insn, 1, SUF_Z, 0x2A, 0, 0, 0, CPU_SSE, 0, 0}, + {"vpblendvb", avx2_sse4xmm0_insn, 2, SUF_Z, 0x4C, 0, 0, ONLY_AVX, CPU_AVX2, 0, 0}, + {"movntdq", movnt_insn, 2, SUF_Z, 0x66, 0xE7, 0, 0, CPU_SSE2, 0, 0}, + {"vpaddw", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0xFD, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpcomeqw", vpcom_insn, 1, SUF_Z, 0xCD, 0x04, 0, 0, CPU_XOP, 0, 0}, + {"unpcklpd", xmm_xmm128_insn, 2, SUF_Z, 0x66, 0x14, 0, 0, CPU_SSE2, 0, 0}, + {"vpcomgtuw", vpcom_insn, 1, SUF_Z, 0xED, 0x02, 0, 0, CPU_XOP, 0, 0}, + {"fadd", farith_insn, 7, SUF_Z, 0xC0, 0xC0, 0x00, 0, CPU_FPU, 0, 0}, + {"fcmovnbe", fcmovcc_insn, 1, SUF_Z, 0xDB, 0xD0, 0, 0, CPU_686, CPU_FPU, 0}, + {"vpcomltub", vpcom_insn, 1, SUF_Z, 0xEC, 0x00, 0, 0, CPU_XOP, 0, 0}, + {"cmplepd", ssecmp_128_insn, 3, SUF_Z, 0x02, 0x66, 0, 0, CPU_SSE, 0, 0}, + {"fyl2xp1", twobyte_insn, 1, SUF_Z, 0xD9, 0xF9, 0, 0, CPU_FPU, 0, 0}, + {"vpmacssdql", vpma_insn, 1, SUF_Z, 0x87, 0, 0, 0, CPU_XOP, 0, 0}, + {"vmpsadbw", sse4imm_256avx2_insn, 4, SUF_Z, 0x42, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"punpckhqdq", xmm_xmm128_insn, 2, SUF_Z, 0x66, 0x6D, 0, 0, CPU_SSE2, 0, 0}, + {"pushaw", onebyte_insn, 1, SUF_Z, 0x60, 0x10, 0, NOT_64, CPU_186, 0, 0}, + {"sar", shift_insn, 16, SUF_Z, 0x07, 0, 0, 0, 0, 0, 0}, + {"shlx", vex_gpr_reg_rm_nds_0F_insn, 2, SUF_Z, 0x66, 0x38, 0xF7, ONLY_AVX, CPU_BMI2, 0, 0}, + {"vcmpunord_sps", ssecmp_128_insn, 3, SUF_Z, 0x13, 0x00, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpcomfalsew", vpcom_insn, 1, SUF_Z, 0xCD, 0x06, 0, 0, CPU_XOP, 0, 0}, + {"vpbroadcastq", vpbroadcastq_avx2_insn, 4, SUF_Z, 0, 0, 0, ONLY_AVX, CPU_AVX2, 0, 0}, + {"movdqu", movau_insn, 6, SUF_Z, 0xF3, 0x6F, 0x10, 0, CPU_SSE2, 0, 0}, + {"vcmpord_ssd", ssecmp_64_insn, 4, SUF_Z, 0x17, 0xF2, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vcmpfalsess", ssecmp_32_insn, 4, SUF_Z, 0x0B, 0xF3, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"lddqu", lddqu_insn, 2, SUF_Z, 0, 0, 0, 0, CPU_SSE3, 0, 0}, + {"sha1msg1", intel_SHA1MSG1_insn, 1, SUF_Z, 0, 0, 0, 0, CPU_SHA, 0, 0}, + {"lock", NULL, X86_LOCKREP>>8, 0xF0, 0, 0, 0, 0, 0, 0, 0}, + {"lss", lfgss_insn, 3, SUF_Z, 0xB2, 0, 0, 0, CPU_386, 0, 0}, + {"orps", xmm_xmm128_insn, 2, SUF_Z, 0x00, 0x56, 0, 0, CPU_SSE, 0, 0}, + {"vbroadcastsd", vbroadcastsd_insn, 2, SUF_Z, 0, 0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"rsdc", rsdc_insn, 1, SUF_Z, 0, 0, 0, 0, CPU_486, CPU_Cyrix, CPU_SMM}, + {"crc32", crc32_insn, 5, SUF_Z, 0, 0, 0, 0, CPU_386, CPU_SSE42, 0}, + {"sal", shift_insn, 16, SUF_Z, 0x04, 0, 0, 0, 0, 0, 0}, + {"movsldup", xmm_xmm128_insn, 2, SUF_Z, 0xF3, 0x12, 0, 0, CPU_SSE3, 0, 0}, + {"vpcomneub", vpcom_insn, 1, SUF_Z, 0xEC, 0x05, 0, 0, CPU_XOP, 0, 0}, + {"movsb", onebyte_insn, 1, SUF_Z, 0xA4, 0x00, 0, 0, 0, 0, 0}, + {"jcxz", jcxz_insn, 2, SUF_Z, 0x10, 0, 0, 0, 0, 0, 0}, + {"vphadduwd", vphaddsub_insn, 1, SUF_Z, 0xD6, 0, 0, 0, CPU_XOP, 0, 0}, + {"vpcomequb", vpcom_insn, 1, SUF_Z, 0xEC, 0x04, 0, 0, CPU_XOP, 0, 0}, + {"vpcomgeq", vpcom_insn, 1, SUF_Z, 0xCF, 0x03, 0, 0, CPU_XOP, 0, 0}, + {"cmpeqps", ssecmp_128_insn, 3, SUF_Z, 0x00, 0, 0, 0, CPU_SSE, 0, 0}, + {"psubsiw", cyrixmmx_insn, 1, SUF_Z, 0x55, 0, 0, 0, CPU_Cyrix, CPU_MMX, 0}, + {"vpcomfalseuq", vpcom_insn, 1, SUF_Z, 0xEF, 0x06, 0, 0, CPU_XOP, 0, 0}, + {"vcmpngesd", ssecmp_64_insn, 4, SUF_Z, 0x09, 0xF2, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpsubb", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0xF8, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpextrb", pextrb_insn, 3, SUF_Z, 0xC0, 0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"fdivr", farith_insn, 7, SUF_Z, 0xF0, 0xF8, 0x07, 0, CPU_FPU, 0, 0}, + {"cmpless", ssecmp_32_insn, 4, SUF_Z, 0x02, 0xF3, 0, 0, CPU_SSE, 0, 0}, + {"vcmpeq_ossd", ssecmp_64_insn, 4, SUF_Z, 0x10, 0xF2, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"pabsd", ssse3_insn, 5, SUF_Z, 0x1E, 0, 0, 0, CPU_SSSE3, 0, 0}, + {"vprotd", vprot_insn, 3, SUF_Z, 0x02, 0, 0, 0, CPU_XOP, 0, 0}, + {"vpermq", vperm_imm_avx2_insn, 1, SUF_Z, 0x00, 0, 0, ONLY_AVX, CPU_AVX2, 0, 0}, + {"vmovntps", movnt_insn, 2, SUF_Z, 0x00, 0x2B, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vcvtps2dq", avx_xmm_xmm128_insn, 2, SUF_Z, 0x66, 0x5B, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"pmovzxwd", sse4m64_insn, 4, SUF_Z, 0x33, 0, 0, 0, CPU_SSE41, 0, 0}, + {"phaddd", ssse3_insn, 5, SUF_Z, 0x02, 0, 0, 0, CPU_SSSE3, 0, 0}, + {"jnp", jcc_insn, 9, SUF_Z, 0x0B, 0, 0, 0, 0, 0, 0}, + {"vdivss", xmm_xmm32_insn, 4, SUF_Z, 0xF3, 0x5E, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vunpcklps", xmm_xmm128_256_insn, 4, SUF_Z, 0x00, 0x14, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"punpcklbw", mmxsse2_insn, 2, SUF_Z, 0x60, 0, 0, 0, CPU_MMX, 0, 0}, + {"pmovzxbd", sse4m32_insn, 4, SUF_Z, 0x31, 0, 0, 0, CPU_SSE41, 0, 0}, + {"vcmpfalse_ospd", ssecmp_128_insn, 3, SUF_Z, 0x1B, 0x66, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vmaxps", xmm_xmm128_256_insn, 4, SUF_Z, 0x00, 0x5F, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpcomub", vpcom_imm_insn, 1, SUF_Z, 0xEC, 0, 0, 0, CPU_XOP, 0, 0}, + {"vcmptrue_usss", ssecmp_32_insn, 4, SUF_Z, 0x1F, 0xF3, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vphaddbw", vphaddsub_insn, 1, SUF_Z, 0xC1, 0, 0, 0, CPU_XOP, 0, 0}, + {"vpmacssdd", vpma_insn, 1, SUF_Z, 0x8E, 0, 0, 0, CPU_XOP, 0, 0}, + {"sete", setcc_insn, 1, SUF_Z, 0x04, 0, 0, 0, CPU_386, 0, 0}, + {"fcom", fcom_insn, 6, SUF_Z, 0xD0, 0x02, 0, 0, CPU_FPU, 0, 0}, + {"paveb", cyrixmmx_insn, 1, SUF_Z, 0x50, 0, 0, 0, CPU_Cyrix, CPU_MMX, 0}, + {"vphaddd", ssse3_insn, 5, SUF_Z, 0x02, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpcomltuq", vpcom_insn, 1, SUF_Z, 0xEF, 0x00, 0, 0, CPU_XOP, 0, 0}, + {"aeskeygenassist", aes_imm_insn, 1, SUF_Z, 0x3A, 0xDF, 0, 0, CPU_AES, 0, 0}, + {"movss", movss_insn, 4, SUF_Z, 0, 0, 0, 0, CPU_SSE, 0, 0}, + {"vpmacsswd", vpma_insn, 1, SUF_Z, 0x86, 0, 0, 0, CPU_XOP, 0, 0}, + {"fchs", twobyte_insn, 1, SUF_Z, 0xD9, 0xE0, 0, 0, CPU_FPU, 0, 0}, + {"vphminposuw", avx_ssse3_2op_insn, 1, SUF_Z, 0x41, 0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"les", ldes_insn, 2, SUF_Z, 0xC4, 0, 0, NOT_64, 0, 0, 0}, + {"movhlps", movhllhps_insn, 2, SUF_Z, 0x12, 0, 0, 0, CPU_SSE, 0, 0}, + {"a16", NULL, X86_ADDRSIZE>>8, 0x10, 0, 0, 0, 0, 0, 0, 0}, + {"vpaddsw", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0xED, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"aesdeclast", aes_insn, 2, SUF_Z, 0x38, 0xDF, 0, 0, CPU_AVX, 0, 0}, + {"lodsq", onebyte_insn, 1, SUF_Z, 0xAD, 0x40, 0, ONLY_64, 0, 0, 0}, + {"vpinsrd", pinsrd_insn, 2, SUF_Z, 0xC0, 0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpgatherdq", gather_64x_64x_insn, 2, SUF_Z, 0x90, 0, 0, ONLY_AVX, CPU_AVX2, 0, 0}, + {"pshufw", pshufw_insn, 1, SUF_Z, 0, 0, 0, 0, CPU_MMX, CPU_P3, 0}, + {"vpgatherqd", gather_32x_32y_128_insn, 2, SUF_Z, 0x91, 0, 0, ONLY_AVX, CPU_AVX2, 0, 0}, + {"vpblendd", vex_66_0F3A_imm8_avx2_insn, 2, SUF_Z, 0x02, 0, 0, ONLY_AVX, CPU_AVX2, 0, 0}, + {"vblendpd", sse4imm_256_insn, 4, SUF_Z, 0x0D, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"pushfw", onebyte_insn, 1, SUF_Z, 0x9C, 0x10, 0x40, 0, 0, 0, 0}, + {"lodsd", onebyte_insn, 1, SUF_Z, 0xAD, 0x20, 0, 0, CPU_386, 0, 0}, + {"vfmaddsub213pd", vfma_pd_insn, 2, SUF_Z, 0xA6, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"vpcomfalsed", vpcom_insn, 1, SUF_Z, 0xCE, 0x06, 0, 0, CPU_XOP, 0, 0}, + {"fnstcw", fldnstcw_insn, 1, SUF_Z, 0x07, 0, 0, 0, CPU_FPU, 0, 0}, + {"rdshr", rdwrshr_insn, 1, SUF_Z, 0x00, 0, 0, 0, CPU_686, CPU_Cyrix, CPU_SMM}, + {"phminposuw", sse4_insn, 2, SUF_Z, 0x41, 0, 0, 0, CPU_SSE41, 0, 0}, + {"pclmullqlqdq", pclmulqdq_fixed_insn, 2, SUF_Z, 0x00, 0, 0, 0, CPU_AVX, 0, 0}, + {"bound", bound_insn, 2, SUF_Z, 0, 0, 0, NOT_64, CPU_186, 0, 0}, + {"tzcnt", cnt_insn, 3, SUF_Z, 0xBC, 0, 0, 0, CPU_BMI1, 0, 0}, + {"rdrand", rdrand_insn, 3, SUF_Z, 0x06, 0, 0, 0, CPU_RDRAND, 0, 0}, + {"vpcomtrueuq", vpcom_insn, 1, SUF_Z, 0xEF, 0x07, 0, 0, CPU_XOP, 0, 0}, + {"pfrcp", now3d_insn, 1, SUF_Z, 0x96, 0, 0, 0, CPU_3DNow, 0, 0}, + {"vcmpneq_oqsd", ssecmp_64_insn, 4, SUF_Z, 0x0C, 0xF2, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vcvttps2dq", avx_xmm_xmm128_insn, 2, SUF_Z, 0xF3, 0x5B, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpinsrb", pinsrb_insn, 4, SUF_Z, 0xC0, 0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"movlhps", movhllhps_insn, 2, SUF_Z, 0x16, 0, 0, 0, CPU_SSE, 0, 0}, + {"vpmovsxwq", sse4m32_insn, 4, SUF_Z, 0x24, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"pdistib", cyrixmmx_insn, 1, SUF_Z, 0x54, 0, 0, 0, CPU_Cyrix, CPU_MMX, 0}, + {"vpxor", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0xEF, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"fabs", twobyte_insn, 1, SUF_Z, 0xD9, 0xE1, 0, 0, CPU_FPU, 0, 0}, + {"blci", xop_gpr_reg_rm_09_insn, 2, SUF_Z, 0x02, 0x06, 0, 0, CPU_386, CPU_TBM, 0}, + {"vmovlpd", movhlp_insn, 3, SUF_Z, 0x66, 0x12, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vbroadcastss", vbroadcastss_insn, 4, SUF_Z, 0, 0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vcmpngt_uqss", ssecmp_32_insn, 4, SUF_Z, 0x1A, 0xF3, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"roundps", sse4imm_insn, 2, SUF_Z, 0x08, 0, 0, 0, CPU_SSE41, 0, 0}, + {"sha256msg1", intel_SHA256MSG1_insn, 1, SUF_Z, 0, 0, 0, 0, CPU_SHA, 0, 0}, + {"movsxd", movsxd_insn, 1, SUF_Z, 0, 0, 0, ONLY_64, 0, 0, 0}, + {"fsubrp", farithp_insn, 3, SUF_Z, 0xE0, 0, 0, 0, CPU_FPU, 0, 0}, + {"vmaskmovps", vmaskmov_insn, 4, SUF_Z, 0x2C, 0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"movsx", movszx_insn, 5, SUF_Z, 0xBE, 0, 0, 0, CPU_386, 0, 0}, + {"fistp", fildstp_insn, 4, SUF_Z, 0x03, 0x02, 0x07, 0, CPU_FPU, 0, 0}, + {"vfmsubps", fma_128_256_insn, 4, SUF_Z, 0x6C, 0, 0, ONLY_AVX, CPU_FMA4, 0, 0}, + {"movmskps", movmsk_insn, 4, SUF_Z, 0, 0, 0, 0, CPU_386, CPU_SSE, 0}, + {"cmplesd", ssecmp_64_insn, 4, SUF_Z, 0x02, 0xF2, 0, 0, CPU_SSE2, 0, 0}, + {"maskmovdqu", maskmovdqu_insn, 1, SUF_Z, 0, 0, 0, 0, CPU_SSE2, 0, 0}, + {"prefetchnta", twobytemem_insn, 1, SUF_Z, 0x00, 0x0F, 0x18, 0, CPU_P3, 0, 0}, + {"loadall", twobyte_insn, 1, SUF_Z, 0x0F, 0x07, 0, 0, CPU_386, CPU_Undoc, 0}, + {"cmpunordsd", ssecmp_64_insn, 4, SUF_Z, 0x03, 0xF2, 0, 0, CPU_SSE2, 0, 0}, + {"haddpd", xmm_xmm128_insn, 2, SUF_Z, 0x66, 0x7C, 0, 0, CPU_SSE3, 0, 0}, + {"vpshlw", amd_vpshift_insn, 2, SUF_Z, 0x95, 0, 0, 0, CPU_XOP, 0, 0}, + {"addsubpd", xmm_xmm128_insn, 2, SUF_Z, 0x66, 0xD0, 0, 0, CPU_SSE3, 0, 0}, + {"phaddw", ssse3_insn, 5, SUF_Z, 0x01, 0, 0, 0, CPU_SSSE3, 0, 0}, + {"vphaddsw", ssse3_insn, 5, SUF_Z, 0x03, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vcmpeq_uqsd", ssecmp_64_insn, 4, SUF_Z, 0x08, 0xF2, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"cmpunordss", ssecmp_32_insn, 4, SUF_Z, 0x03, 0xF3, 0, 0, CPU_SSE, 0, 0}, + {"cmpsb", onebyte_insn, 1, SUF_Z, 0xA6, 0x00, 0, 0, 0, 0, 0}, + {"vpcomtrueuw", vpcom_insn, 1, SUF_Z, 0xED, 0x07, 0, 0, CPU_XOP, 0, 0}, + {"rcpps", xmm_xmm128_insn, 2, SUF_Z, 0x00, 0x53, 0, 0, CPU_SSE, 0, 0}, + {"packuswb", mmxsse2_insn, 2, SUF_Z, 0x67, 0, 0, 0, CPU_MMX, 0, 0}, + {"vmovlhps", movhllhps_insn, 2, SUF_Z, 0x16, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"cmppd", xmm_xmm128_imm_insn, 1, SUF_Z, 0x66, 0xC2, 0, 0, CPU_SSE2, 0, 0}, + {"vfmsubadd231pd", vfma_pd_insn, 2, SUF_Z, 0xB7, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"vphaddudq", vphaddsub_insn, 1, SUF_Z, 0xDB, 0, 0, 0, CPU_XOP, 0, 0}, + {"vphaddubq", vphaddsub_insn, 1, SUF_Z, 0xD3, 0, 0, 0, CPU_XOP, 0, 0}, + {"scasb", onebyte_insn, 1, SUF_Z, 0xAE, 0x00, 0, 0, 0, 0, 0}, + {"vfmaddsubps", fma_128_256_insn, 4, SUF_Z, 0x5C, 0, 0, ONLY_AVX, CPU_FMA4, 0, 0}, + {"vpcomgtd", vpcom_insn, 1, SUF_Z, 0xCE, 0x02, 0, 0, CPU_XOP, 0, 0}, + {"seta", setcc_insn, 1, SUF_Z, 0x07, 0, 0, 0, CPU_386, 0, 0}, + {"pmulhrwc", cyrixmmx_insn, 1, SUF_Z, 0x59, 0, 0, 0, CPU_Cyrix, CPU_MMX, 0}, + {"vtestpd", sse4_insn, 2, SUF_Z, 0x0F, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vfmaddsub132pd", vfma_pd_insn, 2, SUF_Z, 0x96, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"cmpneqps", ssecmp_128_insn, 3, SUF_Z, 0x04, 0, 0, 0, CPU_SSE, 0, 0}, + {"vpmaskmovd", vmaskmov_insn, 4, SUF_Z, 0x8C, 0, 0, ONLY_AVX, CPU_AVX2, 0, 0}, + {"vcmpordps", ssecmp_128_insn, 3, SUF_Z, 0x07, 0x00, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vcvtsi2ss", cvt_xmm_rmx_insn, 6, SUF_Z, 0xF3, 0x2A, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vunpckhpd", xmm_xmm128_256_insn, 4, SUF_Z, 0x66, 0x15, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"setc", setcc_insn, 1, SUF_Z, 0x02, 0, 0, 0, CPU_386, 0, 0}, + {"repne", NULL, X86_LOCKREP>>8, 0xF2, 0, 0, 0, 0, 0, 0, 0}, + {"vandnps", xmm_xmm128_256_insn, 4, SUF_Z, 0x00, 0x55, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"aam", aadm_insn, 2, SUF_Z, 0x00, 0, 0, NOT_64, 0, 0, 0}, + {"mulpd", xmm_xmm128_insn, 2, SUF_Z, 0x66, 0x59, 0, 0, CPU_SSE2, 0, 0}, + {"a32", NULL, X86_ADDRSIZE>>8, 0x20, 0, 0, 0, 0, 0, 0, 0}, + {"vcmpfalse_osps", ssecmp_128_insn, 3, SUF_Z, 0x1B, 0x00, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"jecxz", jcxz_insn, 2, SUF_Z, 0x20, 0, 0, 0, CPU_386, 0, 0}, + {"vcmple_oqps", ssecmp_128_insn, 3, SUF_Z, 0x12, 0x00, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"cmovpe", cmovcc_insn, 3, SUF_Z, 0x0A, 0, 0, 0, CPU_686, 0, 0}, + {"vcmpngepd", ssecmp_128_insn, 3, SUF_Z, 0x09, 0x66, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vsqrtpd", avx_xmm_xmm128_insn, 2, SUF_Z, 0x66, 0x51, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpmacsww", vpma_insn, 1, SUF_Z, 0x95, 0, 0, 0, CPU_XOP, 0, 0}, + {"vfmaddsub231pd", vfma_pd_insn, 2, SUF_Z, 0xB6, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"int3", onebyte_insn, 1, SUF_Z, 0xCC, 0, 0, 0, 0, 0, 0}, + {"vcvtdq2pd", avx_cvt_xmm64_insn, 3, SUF_Z, 0xF3, 0xE6, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"fisubr", fiarith_insn, 2, SUF_Z, 0x05, 0xDA, 0, 0, CPU_FPU, 0, 0}, + {"pextrq", pextrq_insn, 1, SUF_Z, 0, 0, 0, ONLY_64, CPU_SSE41, 0, 0}, + {"popaw", onebyte_insn, 1, SUF_Z, 0x61, 0x10, 0, NOT_64, CPU_186, 0, 0}, + {"vcmpnge_uqsd", ssecmp_64_insn, 4, SUF_Z, 0x19, 0xF2, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vfmsub132ps", vfma_ps_insn, 2, SUF_Z, 0x9A, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"vcmplesd", ssecmp_64_insn, 4, SUF_Z, 0x02, 0xF2, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"into", onebyte_insn, 1, SUF_Z, 0xCE, 0, 0, NOT_64, 0, 0, 0}, + {"vpmacsdd", vpma_insn, 1, SUF_Z, 0x9E, 0, 0, 0, CPU_XOP, 0, 0}, + {"cmovbe", cmovcc_insn, 3, SUF_Z, 0x06, 0, 0, 0, CPU_686, 0, 0}, + {"vpsubsb", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0xE8, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpmulld", ssse3_insn, 5, SUF_Z, 0x40, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vphsubw", ssse3_insn, 5, SUF_Z, 0x05, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpsrlvq", vpshiftv_vexw1_avx2_insn, 2, SUF_Z, 0x45, 0, 0, ONLY_AVX, CPU_AVX2, 0, 0}, + {"vpsllvd", vpshiftv_vexw0_avx2_insn, 2, SUF_Z, 0x47, 0, 0, ONLY_AVX, CPU_AVX2, 0, 0}, + {"std", onebyte_insn, 1, SUF_Z, 0xFD, 0, 0, 0, 0, 0, 0}, + {"psrad", pshift_insn, 4, SUF_Z, 0xE2, 0x72, 0x04, 0, CPU_MMX, 0, 0}, + {"psllq", pshift_insn, 4, SUF_Z, 0xF3, 0x73, 0x06, 0, CPU_MMX, 0, 0}, + {"fucom", fcom2_insn, 2, SUF_Z, 0xDD, 0xE0, 0, 0, CPU_286, CPU_FPU, 0}, + {"vpcmpeqd", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0x76, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vcmpord_sps", ssecmp_128_insn, 3, SUF_Z, 0x17, 0x00, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vmovntdqa", movntdqa_insn, 2, SUF_Z, 0xC0, 0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpgatherdd", gather_32x_32y_insn, 2, SUF_Z, 0x90, 0, 0, ONLY_AVX, CPU_AVX2, 0, 0}, + {"vfmsubpd", fma_128_256_insn, 4, SUF_Z, 0x6D, 0, 0, ONLY_AVX, CPU_FMA4, 0, 0}, + {"vaesdec", aes_insn, 2, SUF_Z, 0x38, 0xDE, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpcomged", vpcom_insn, 1, SUF_Z, 0xCE, 0x03, 0, 0, CPU_XOP, 0, 0}, + {"rol", shift_insn, 16, SUF_Z, 0x00, 0, 0, 0, 0, 0, 0}, + {"punpckhbw", mmxsse2_insn, 2, SUF_Z, 0x68, 0, 0, 0, CPU_MMX, 0, 0}, + {"vphsubsw", ssse3_insn, 5, SUF_Z, 0x07, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"cmpltsd", ssecmp_64_insn, 4, SUF_Z, 0x01, 0xF2, 0, 0, CPU_SSE2, 0, 0}, + {"fcomip", fcom2_insn, 2, SUF_Z, 0xDF, 0xF0, 0, 0, CPU_686, CPU_FPU, 0}, + {"vfmadd231sd", vfma_sd_insn, 2, SUF_Z, 0xB9, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"psubusw", mmxsse2_insn, 2, SUF_Z, 0xD9, 0, 0, 0, CPU_MMX, 0, 0}, + {"vcmpunord_spd", ssecmp_128_insn, 3, SUF_Z, 0x13, 0x66, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vcmpneq_usss", ssecmp_32_insn, 4, SUF_Z, 0x14, 0xF3, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpclmullqhqdq", pclmulqdq_fixed_insn, 2, SUF_Z, 0x10, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vcmpeq_uspd", ssecmp_128_insn, 3, SUF_Z, 0x18, 0x66, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"inc", incdec_insn, 6, SUF_Z, 0x40, 0x00, 0, 0, 0, 0, 0}, + {"psubq", mmxsse2_insn, 2, SUF_Z, 0xFB, 0, 0, 0, CPU_MMX, 0, 0}, + {"unpcklps", xmm_xmm128_insn, 2, SUF_Z, 0x00, 0x14, 0, 0, CPU_SSE, 0, 0}, + {"vcmpgt_oqss", ssecmp_32_insn, 4, SUF_Z, 0x1E, 0xF3, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vcmpunordps", ssecmp_128_insn, 3, SUF_Z, 0x03, 0x00, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vfnmadd213sd", vfma_sd_insn, 2, SUF_Z, 0xAD, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"pdep", vex_gpr_reg_nds_rm_0F_insn, 2, SUF_Z, 0xF2, 0x38, 0xF5, ONLY_AVX, CPU_BMI2, 0, 0}, + {"phaddsw", ssse3_insn, 5, SUF_Z, 0x03, 0, 0, 0, CPU_SSSE3, 0, 0}, + {"xcryptcbc", padlock_insn, 1, SUF_Z, 0xD0, 0xF3, 0xA7, 0, CPU_PadLock, 0, 0}, + {"vpmullw", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0xD5, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"blsfill", xop_gpr_reg_rm_09_insn, 2, SUF_Z, 0x01, 0x02, 0, 0, CPU_386, CPU_TBM, 0}, + {"and", arith_insn, 22, SUF_Z, 0x20, 0x04, 0, 0, 0, 0, 0}, + {"xacquire", NULL, X86_ACQREL>>8, 0xF2, 0, 0, 0, 0, 0, 0, 0}, + {"vpcomnequd", vpcom_insn, 1, SUF_Z, 0xEE, 0x05, 0, 0, CPU_XOP, 0, 0}, + {"movshdup", xmm_xmm128_insn, 2, SUF_Z, 0xF3, 0x16, 0, 0, CPU_SSE3, 0, 0}, + {"vfnmadd231sd", vfma_sd_insn, 2, SUF_Z, 0xBD, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"femms", twobyte_insn, 1, SUF_Z, 0x0F, 0x0E, 0, 0, CPU_3DNow, 0, 0}, + {"vpcomgeuq", vpcom_insn, 1, SUF_Z, 0xEF, 0x03, 0, 0, CPU_XOP, 0, 0}, + {"vcmpnlt_uqsd", ssecmp_64_insn, 4, SUF_Z, 0x15, 0xF2, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"pcmpgtd", mmxsse2_insn, 2, SUF_Z, 0x66, 0, 0, 0, CPU_MMX, 0, 0}, + {"andpd", xmm_xmm128_insn, 2, SUF_Z, 0x66, 0x54, 0, 0, CPU_SSE2, 0, 0}, + {"vhsubpd", xmm_xmm128_256_insn, 4, SUF_Z, 0x66, 0x7D, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vblendvps", avx_sse4xmm0_insn, 2, SUF_Z, 0x4A, 0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vcmpgtsd", ssecmp_64_insn, 4, SUF_Z, 0x0E, 0xF2, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpcmpestri", sse4pcmpstr_insn, 1, SUF_Z, 0x61, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"rdmsr", twobyte_insn, 1, SUF_Z, 0x0F, 0x32, 0, 0, CPU_586, CPU_Priv, 0}, + {"vpcmpgtw", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0x65, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"pfnacc", now3d_insn, 1, SUF_Z, 0x8A, 0, 0, 0, CPU_3DNow, CPU_Athlon, 0}, + {"leave", onebyte_insn, 1, SUF_Z, 0xC9, 0x00, 0x40, 0, CPU_186, 0, 0}, + {"jz", jcc_insn, 9, SUF_Z, 0x04, 0, 0, 0, 0, 0, 0}, + {"psubw", mmxsse2_insn, 2, SUF_Z, 0xF9, 0, 0, 0, CPU_MMX, 0, 0}, + {"jnl", jcc_insn, 9, SUF_Z, 0x0D, 0, 0, 0, 0, 0, 0}, + {"repe", NULL, X86_LOCKREP>>8, 0xF3, 0, 0, 0, 0, 0, 0, 0}, + {"pushfq", onebyte_insn, 1, SUF_Z, 0x9C, 0x40, 0x40, ONLY_64, 0, 0, 0}, + {"vmlaunch", threebyte_insn, 1, SUF_Z, 0x0F, 0x01, 0xC2, 0, CPU_P4, 0, 0}, + {"vfmsubaddps", fma_128_256_insn, 4, SUF_Z, 0x5E, 0, 0, ONLY_AVX, CPU_FMA4, 0, 0}, + {"cmpxchg486", cmpxchgxadd_insn, 4, SUF_Z, 0xA6, 0, 0, 0, CPU_486, CPU_Undoc, 0}, + {"blsic", xop_gpr_reg_rm_09_insn, 2, SUF_Z, 0x01, 0x06, 0, 0, CPU_386, CPU_TBM, 0}, + {"vcmptruesd", ssecmp_64_insn, 4, SUF_Z, 0x0F, 0xF2, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"stc", onebyte_insn, 1, SUF_Z, 0xF9, 0, 0, 0, 0, 0, 0}, + {"vpermps", vperm_var_avx2_insn, 1, SUF_Z, 0x16, 0, 0, ONLY_AVX, CPU_AVX2, 0, 0}, + {"xlatb", onebyte_insn, 1, SUF_Z, 0xD7, 0x00, 0, 0, 0, 0, 0}, + {"vpmacssww", vpma_insn, 1, SUF_Z, 0x85, 0, 0, 0, CPU_XOP, 0, 0}, + {"pavgusb", now3d_insn, 1, SUF_Z, 0xBF, 0, 0, 0, CPU_3DNow, 0, 0}, + {"vfmsub231sd", vfma_sd_insn, 2, SUF_Z, 0xBB, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"vmovd", vmovd_insn, 2, SUF_Z, 0, 0, 0, ONLY_AVX, CPU_386, CPU_AVX, 0}, + {"cvtps2pd", xmm_xmm64_insn, 4, SUF_Z, 0x00, 0x5A, 0, 0, CPU_SSE2, 0, 0}, + {"verw", prot286_insn, 1, SUF_Z, 0x05, 0x00, 0, 0, CPU_286, CPU_Prot, 0}, + {"pushad", onebyte_insn, 1, SUF_Z, 0x60, 0x20, 0, NOT_64, CPU_386, 0, 0}, + {"wrfsbase", fs_gs_base_insn, 2, SUF_Z, 0x02, 0, 0, ONLY_64, CPU_FSGSBASE, 0, 0}, + {"paddusw", mmxsse2_insn, 2, SUF_Z, 0xDD, 0, 0, 0, CPU_MMX, 0, 0}, + {"vucomisd", avx_xmm_xmm64_insn, 2, SUF_Z, 0x66, 0x2E, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"fldenv", onebytemem_insn, 1, SUF_Z, 0x04, 0xD9, 0, 0, CPU_FPU, 0, 0}, + {"psubb", mmxsse2_insn, 2, SUF_Z, 0xF8, 0, 0, 0, CPU_MMX, 0, 0}, + {"lidt", twobytemem_insn, 1, SUF_Z, 0x03, 0x0F, 0x01, 0, CPU_286, CPU_Priv, 0}, + {"vfmadd213ps", vfma_ps_insn, 2, SUF_Z, 0xA8, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"cmovnbe", cmovcc_insn, 3, SUF_Z, 0x07, 0, 0, 0, CPU_686, 0, 0}, + {"shufps", xmm_xmm128_imm_insn, 1, SUF_Z, 0x00, 0xC6, 0, 0, CPU_SSE, 0, 0}, + {"emms", twobyte_insn, 1, SUF_Z, 0x0F, 0x77, 0, 0, CPU_MMX, 0, 0}, + {"vfmsubadd132pd", vfma_pd_insn, 2, SUF_Z, 0x97, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"fldl2e", twobyte_insn, 1, SUF_Z, 0xD9, 0xEA, 0, 0, CPU_FPU, 0, 0}, + {"invd", twobyte_insn, 1, SUF_Z, 0x0F, 0x08, 0, 0, CPU_486, CPU_Priv, 0}, + {"vphadduwq", vphaddsub_insn, 1, SUF_Z, 0xD7, 0, 0, 0, CPU_XOP, 0, 0}, + {"cvtss2si", cvt_rx_xmm32_insn, 4, SUF_Z, 0xF3, 0x2D, 0, 0, CPU_386, CPU_SSE, 0}, + {"vpcomltd", vpcom_insn, 1, SUF_Z, 0xCE, 0x00, 0, 0, CPU_XOP, 0, 0}, + {"shr", shift_insn, 16, SUF_Z, 0x05, 0, 0, 0, 0, 0, 0}, + {"vcvtss2si", cvt_rx_xmm32_insn, 4, SUF_Z, 0xF3, 0x2D, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vcmpeq_uqps", ssecmp_128_insn, 3, SUF_Z, 0x08, 0x00, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vsubsd", xmm_xmm64_insn, 4, SUF_Z, 0xF2, 0x5C, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"pminuw", sse4_insn, 2, SUF_Z, 0x3A, 0, 0, 0, CPU_SSE41, 0, 0}, + {"vcmpgt_oqps", ssecmp_128_insn, 3, SUF_Z, 0x1E, 0x00, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"xstore", padlock_insn, 1, SUF_Z, 0xC0, 0x00, 0xA7, 0, CPU_PadLock, 0, 0}, + {"pmovsxwq", sse4m32_insn, 4, SUF_Z, 0x24, 0, 0, 0, CPU_SSE41, 0, 0}, + {"vcmpngtss", ssecmp_32_insn, 4, SUF_Z, 0x0A, 0xF3, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vfnmadd213pd", vfma_pd_insn, 2, SUF_Z, 0xAC, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"vphaddbd", vphaddsub_insn, 1, SUF_Z, 0xC2, 0, 0, 0, CPU_XOP, 0, 0}, + {"divps", xmm_xmm128_insn, 2, SUF_Z, 0x00, 0x5E, 0, 0, CPU_SSE, 0, 0}, + {"pf2id", now3d_insn, 1, SUF_Z, 0x1D, 0, 0, 0, CPU_3DNow, 0, 0}, + {"lgdt", twobytemem_insn, 1, SUF_Z, 0x02, 0x0F, 0x01, 0, CPU_286, CPU_Priv, 0}, + {"syscall", twobyte_insn, 1, SUF_Z, 0x0F, 0x05, 0, 0, CPU_686, CPU_AMD, 0}, + {"vpmaddwd", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0xF5, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"cmpneqss", ssecmp_32_insn, 4, SUF_Z, 0x04, 0xF3, 0, 0, CPU_SSE, 0, 0}, + {"setle", setcc_insn, 1, SUF_Z, 0x0E, 0, 0, 0, CPU_386, 0, 0}, + {"stosb", onebyte_insn, 1, SUF_Z, 0xAA, 0x00, 0, 0, 0, 0, 0}, + {"sha1rnds4", intel_SHA1RNDS4_insn, 1, SUF_Z, 0, 0, 0, 0, CPU_SHA, 0, 0}, + {"setg", setcc_insn, 1, SUF_Z, 0x0F, 0, 0, 0, CPU_386, 0, 0}, + {"ffree", ffree_insn, 1, SUF_Z, 0xDD, 0, 0, 0, CPU_FPU, 0, 0}, + {"fmulp", farithp_insn, 3, SUF_Z, 0xC8, 0, 0, 0, CPU_FPU, 0, 0}, + {"fucomp", fcom2_insn, 2, SUF_Z, 0xDD, 0xE8, 0, 0, CPU_286, CPU_FPU, 0}, + {"cvtss2sd", xmm_xmm32_insn, 4, SUF_Z, 0xF3, 0x5A, 0, 0, CPU_SSE2, 0, 0}, + {"phsubd", ssse3_insn, 5, SUF_Z, 0x06, 0, 0, 0, CPU_SSSE3, 0, 0}, + {"vdivps", xmm_xmm128_256_insn, 4, SUF_Z, 0x00, 0x5E, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"rdseed", rdrand_insn, 3, SUF_Z, 0x07, 0, 0, 0, CPU_RDSEED, 0, 0}, + {"vpsrlw", vpshift_insn, 8, SUF_Z, 0xD1, 0x71, 0x02, ONLY_AVX, CPU_AVX, 0, 0}, + {"vcmpeqsd", ssecmp_64_insn, 4, SUF_Z, 0x00, 0xF2, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vcmpngtps", ssecmp_128_insn, 3, SUF_Z, 0x0A, 0x00, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"cvtpd2dq", xmm_xmm128_insn, 2, SUF_Z, 0xF2, 0xE6, 0, 0, CPU_SSE2, 0, 0}, + {"vfnmaddpd", fma_128_256_insn, 4, SUF_Z, 0x79, 0, 0, ONLY_AVX, CPU_FMA4, 0, 0}, + {"vmptrst", vmxtwobytemem_insn, 1, SUF_Z, 0x07, 0, 0, 0, CPU_P4, 0, 0}, + {"rdgsbase", fs_gs_base_insn, 2, SUF_Z, 0x01, 0, 0, ONLY_64, CPU_FSGSBASE, 0, 0}, + {"vpcomleb", vpcom_insn, 1, SUF_Z, 0xCC, 0x01, 0, 0, CPU_XOP, 0, 0}, + {"pmovzxbw", sse4m64_insn, 4, SUF_Z, 0x30, 0, 0, 0, CPU_SSE41, 0, 0}, + {"vrsqrtss", xmm_xmm32_insn, 4, SUF_Z, 0xF3, 0x52, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"setpe", setcc_insn, 1, SUF_Z, 0x0A, 0, 0, 0, CPU_386, 0, 0}, + {"ffreep", ffree_insn, 1, SUF_Z, 0xDF, 0, 0, 0, CPU_686, CPU_FPU, CPU_Undoc}, + {"sgdt", twobytemem_insn, 1, SUF_Z, 0x00, 0x0F, 0x01, 0, CPU_286, CPU_Priv, 0}, + {"addsd", xmm_xmm64_insn, 4, SUF_Z, 0xF2, 0x58, 0, 0, CPU_SSE2, 0, 0}, + {"sfence", threebyte_insn, 1, SUF_Z, 0x0F, 0xAE, 0xF8, 0, CPU_P3, 0, 0}, + {"mpsadbw", sse4imm_insn, 2, SUF_Z, 0x42, 0, 0, 0, CPU_SSE41, 0, 0}, + {"vpunpckhbw", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0x68, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vcmpnlepd", ssecmp_128_insn, 3, SUF_Z, 0x06, 0x66, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vandps", xmm_xmm128_256_insn, 4, SUF_Z, 0x00, 0x54, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"cmpneqsd", ssecmp_64_insn, 4, SUF_Z, 0x04, 0xF2, 0, 0, CPU_SSE2, 0, 0}, + {"fsqrt", twobyte_insn, 1, SUF_Z, 0xD9, 0xFA, 0, 0, CPU_FPU, 0, 0}, + {"vpinsrq", pinsrq_insn, 2, SUF_Z, 0xC0, 0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vmovddup", vmovddup_insn, 3, SUF_Z, 0xF2, 0x12, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpmacswd", vpma_insn, 1, SUF_Z, 0x96, 0, 0, 0, CPU_XOP, 0, 0}, + {"vcmpeq_osss", ssecmp_32_insn, 4, SUF_Z, 0x10, 0xF3, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"setp", setcc_insn, 1, SUF_Z, 0x0A, 0, 0, 0, CPU_386, 0, 0}, + {"cmpsq", onebyte_insn, 1, SUF_Z, 0xA7, 0x40, 0, ONLY_64, 0, 0, 0}, + {"vmovdqu", movau_insn, 6, SUF_Z, 0xF3, 0x6F, 0x10, ONLY_AVX, CPU_AVX, 0, 0}, + {"pfrcpit2", now3d_insn, 1, SUF_Z, 0xB6, 0, 0, 0, CPU_3DNow, 0, 0}, + {"jpe", jcc_insn, 9, SUF_Z, 0x0A, 0, 0, 0, 0, 0, 0}, + {"vpunpckhdq", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0x6A, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"bextr", bextr_insn, 4, SUF_Z, 0, 0, 0, ONLY_AVX, CPU_386, CPU_BMI1, 0}, + {"vmovsldup", avx_xmm_xmm128_insn, 2, SUF_Z, 0xF3, 0x12, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpaddusb", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0xDC, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vperm2f128", vperm2f128_insn, 1, SUF_Z, 0, 0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"pcmpgtq", sse4_insn, 2, SUF_Z, 0x37, 0, 0, 0, CPU_SSE41, 0, 0}, + {"vpshld", amd_vpshift_insn, 2, SUF_Z, 0x96, 0, 0, 0, CPU_XOP, 0, 0}, + {"fsub", farith_insn, 7, SUF_Z, 0xE8, 0xE0, 0x04, 0, CPU_FPU, 0, 0}, + {"movdq2q", movdq2q_insn, 1, SUF_Z, 0, 0, 0, 0, CPU_SSE2, 0, 0}, + {"vpsrld", vpshift_insn, 8, SUF_Z, 0xD2, 0x72, 0x02, ONLY_AVX, CPU_AVX, 0, 0}, + {"fwait", onebyte_insn, 1, SUF_Z, 0x9B, 0, 0, 0, CPU_FPU, 0, 0}, + {"cmpnltss", ssecmp_32_insn, 4, SUF_Z, 0x05, 0xF3, 0, 0, CPU_SSE, 0, 0}, + {"blcmsk", xop_gpr_reg_rm_09_insn, 2, SUF_Z, 0x02, 0x01, 0, 0, CPU_386, CPU_TBM, 0}, + {"punpcklwd", mmxsse2_insn, 2, SUF_Z, 0x61, 0, 0, 0, CPU_MMX, 0, 0}, + {"cmpunordps", ssecmp_128_insn, 3, SUF_Z, 0x03, 0, 0, 0, CPU_SSE, 0, 0}, + {"cmpnlesd", ssecmp_64_insn, 4, SUF_Z, 0x06, 0xF2, 0, 0, CPU_SSE2, 0, 0}, + {"pfcmpgt", now3d_insn, 1, SUF_Z, 0xA0, 0, 0, 0, CPU_3DNow, 0, 0}, + {"cmovnle", cmovcc_insn, 3, SUF_Z, 0x0F, 0, 0, 0, CPU_686, 0, 0}, + {"vmclear", vmxthreebytemem_insn, 1, SUF_Z, 0x66, 0, 0, 0, CPU_P4, 0, 0}, + {"vcmplt_oqpd", ssecmp_128_insn, 3, SUF_Z, 0x11, 0x66, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"clac", threebyte_insn, 1, SUF_Z, 0x0F, 0x01, 0xCA, 0, CPU_SMAP, 0, 0}, + {"fscale", twobyte_insn, 1, SUF_Z, 0xD9, 0xFD, 0, 0, CPU_FPU, 0, 0}, + {"vrcpps", avx_xmm_xmm128_insn, 2, SUF_Z, 0x00, 0x53, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"outsd", onebyte_insn, 1, SUF_Z, 0x6F, 0x20, 0, 0, CPU_386, 0, 0}, + {"fist", fiarith_insn, 2, SUF_Z, 0x02, 0xDB, 0, 0, CPU_FPU, 0, 0}, + {"vfnmsub213ss", vfma_ss_insn, 2, SUF_Z, 0xAF, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"bts", bittest_insn, 6, SUF_Z, 0xAB, 0x05, 0, 0, CPU_386, 0, 0}, + {"paddsb", mmxsse2_insn, 2, SUF_Z, 0xEC, 0, 0, 0, CPU_MMX, 0, 0}, + {"cmovp", cmovcc_insn, 3, SUF_Z, 0x0A, 0, 0, 0, CPU_686, 0, 0}, + {"fstenv", twobytemem_insn, 1, SUF_Z, 0x06, 0x9B, 0xD9, 0, CPU_FPU, 0, 0}, + {"rdfsbase", fs_gs_base_insn, 2, SUF_Z, 0x00, 0, 0, ONLY_64, CPU_FSGSBASE, 0, 0}, + {"vcvttss2si", cvt_rx_xmm32_insn, 4, SUF_Z, 0xF3, 0x2C, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vptest", sse4_insn, 2, SUF_Z, 0x17, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vfmadd132pd", vfma_pd_insn, 2, SUF_Z, 0x98, 0, 0, ONLY_AVX, CPU_FMA, 0, 0}, + {"prefetch", twobytemem_insn, 1, SUF_Z, 0x00, 0x0F, 0x0D, 0, CPU_3DNow, 0, 0}, + {"sha256msg2", intel_SHA256MSG2_insn, 1, SUF_Z, 0, 0, 0, 0, CPU_SHA, 0, 0}, + {"vpsubsw", xmm_xmm128_256avx2_insn, 4, SUF_Z, 0x66, 0xE9, 0xC0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpmulhrsw", ssse3_insn, 5, SUF_Z, 0x0B, 0xC0, 0, ONLY_AVX, CPU_AVX, 0, 0}, + {"vpextrd", pextrd_insn, 1, SUF_Z, 0xC0, 0, 0, ONLY_AVX, CPU_AVX, 0, 0} + }; + static const unsigned short tab[] = { + 894,83,1140,0,1213,1379,1140,864,11,0,281,793,281,281,864,0, + 0,517,0,1312,1213,0,1213,323,0,11,11,1212,0,0,764,0, + 351,793,1140,762,323,823,323,1044,1213,323,665,764,665,665,0,1044, + 159,764,197,1044,0,1312,1042,605,281,721,1379,333,348,1432,764,665, + 0,629,83,764,0,508,1140,0,1140,0,0,605,764,1042,0,1059, + 1042,11,83,517,1044,1140,1042,665,1213,629,351,630,665,348,83,924, + 1042,11,0,517,83,395,1140,1379,988,1213,1213,281,323,629,1140,1116, + 1477,574,1312,864,323,1000,323,823,793,281,721,1074,1044,864,1044,1044, + 896,1213,517,11,281,0,764,1042,1312,281,1379,702,605,1203,1212,824, + 1481,0,1232,0,1000,323,1105,0,307,764,0,508,281,764,988,0, + 884,665,0,0,824,1312,1140,517,517,288,281,823,1140,702,823,517, + 341,528,1042,1338,0,1044,1529,1232,988,1203,517,323,0,0,47,764, + 399,1213,1140,333,1338,64,1213,11,864,293,1312,1109,0,988,1116,427, + 323,1140,1432,764,11,764,323,0,1042,630,427,0,580,630,336,1312, + 179,517,1042,1383,0,506,0,988,83,988,1140,336,11,11,1140,11, + 1042,864,1218,630,517,83,333,1044,1312,197,0,0,864,793,702,323, + 0,1140,574,764,83,924,111,764,1312,159,94,1481,1044,265,281,665, + 0,1140,665,1383,62,323,528,764,574,986,764,665,935,630,1042,281, + 988,517,1044,83,630,567,988,399,1140,1232,1042,580,764,1042,0,864, + 1189,605,443,348,11,864,83,307,894,605,1204,1140,0,764,829,1140, + 892,665,988,1116,517,1042,517,0,348,1213,1109,605,605,1312,1140,197, + 1044,0,891,83,982,83,6,1185,1127,83,399,83,1042,1312,1044,1042, + 0,281,197,1509,924,517,630,935,811,665,896,517,179,1203,605,829, + 864,83,1295,83,0,1312,11,328,1140,891,1432,0,0,764,793,1218, + 1217,665,1089,519,1312,570,629,1312,764,1165,307,281,257,889,1042,721, + 764,1109,443,281,0,0,884,440,688,0,864,1140,1116,83,1140,874, + 1042,1213,0,1053,1477,427,336,0,605,665,1312,803,0,764,442,517, + 605,1212,1508,702,333,665,764,0,0,630,0,1140,968,525,1212,0, + 0,1379,72,0,764,0,1027,327,83,788,145,1476,1107,0,721,358, + 894,823,1206,307,1523,281,630,988,94,793,764,1415,721,1074,0,0, + 629,1218,919,665,336,1474,799,733,1044,876,215,1212,1169,665,864,864, + 764,605,342,1438,569,0,11,0,522,1212,1020,33,427,1064,265,835, + }; + + const struct insnprefix_parse_data *ret; + unsigned long rsl, val = phash_lookup(key, len, 0xbe1e08bbUL); + rsl = ((val>>23)^tab[val&0x1ff]); + if (rsl >= 1454) return NULL; + ret = &pd[rsl]; + if (strcmp(key, ret->name) != 0) return NULL; + return ret; +} + + diff --git a/contrib/tools/yasm/modules/x86insns.c b/contrib/tools/yasm/modules/x86insns.c new file mode 100644 index 0000000000..df5b6fae36 --- /dev/null +++ b/contrib/tools/yasm/modules/x86insns.c @@ -0,0 +1,2424 @@ +/* Generated by gen_x86_insn.py rHEAD, do not edit */ +static const x86_info_operand insn_operands[] = { + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_VEX, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Imm, OPS_8, 1, 0, OPTM_None, OPA_Imm, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_VEX, OPAP_None}, + {OPT_Mem, OPS_64, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Imm, OPS_8, 1, 0, OPTM_None, OPA_Imm, OPAP_None}, + {OPT_SIMDReg, OPS_256, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_SIMDReg, OPS_256, 0, 0, OPTM_None, OPA_VEX, OPAP_None}, + {OPT_SIMDRM, OPS_128, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Imm, OPS_8, 1, 0, OPTM_None, OPA_Imm, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_VEX, OPAP_None}, + {OPT_SIMDRM, OPS_128, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_VEXImmSrc, OPAP_None}, + {OPT_SIMDReg, OPS_256, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_SIMDReg, OPS_256, 0, 0, OPTM_None, OPA_VEX, OPAP_None}, + {OPT_SIMDRM, OPS_256, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_SIMDReg, OPS_256, 0, 0, OPTM_None, OPA_VEXImmSrc, OPAP_None}, + {OPT_SIMDReg, OPS_256, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_SIMDReg, OPS_256, 0, 0, OPTM_None, OPA_VEX, OPAP_None}, + {OPT_SIMDRM, OPS_256, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Imm, OPS_8, 1, 0, OPTM_None, OPA_Imm, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_VEX, OPAP_None}, + {OPT_Reg, OPS_32, 0, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Imm, OPS_8, 1, 0, OPTM_None, OPA_Imm, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_VEX, OPAP_None}, + {OPT_Reg, OPS_64, 0, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Imm, OPS_8, 1, 0, OPTM_None, OPA_Imm, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_VEX, OPAP_None}, + {OPT_Mem, OPS_16, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Imm, OPS_8, 1, 0, OPTM_None, OPA_Imm, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_VEX, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_VEXImmSrc, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_VEX, OPAP_None}, + {OPT_Mem, OPS_64, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_VEXImmSrc, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_VEX, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_VEXImmSrc, OPAP_None}, + {OPT_Mem, OPS_64, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_VEX, OPAP_None}, + {OPT_Mem, OPS_8, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Imm, OPS_8, 1, 0, OPTM_None, OPA_Imm, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_SpareVEX, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_VEX, OPAP_None}, + {OPT_Reg, OPS_32, 0, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Imm, OPS_8, 1, 0, OPTM_None, OPA_Imm, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_VEX, OPAP_None}, + {OPT_Mem, OPS_32, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Imm, OPS_8, 1, 0, OPTM_None, OPA_Imm, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_VEX, OPAP_None}, + {OPT_SIMDRM, OPS_128, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Imm, OPS_8, 1, 0, OPTM_None, OPA_Imm, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Imm, OPS_8, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Imm, OPS_8, 1, 0, OPTM_None, OPA_Imm, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_VEX, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_VEXImmSrc, OPAP_None}, + {OPT_SIMDRM, OPS_128, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_SIMDReg, OPS_256, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_SIMDReg, OPS_256, 0, 0, OPTM_None, OPA_VEX, OPAP_None}, + {OPT_SIMDReg, OPS_256, 0, 0, OPTM_None, OPA_VEXImmSrc, OPAP_None}, + {OPT_SIMDRM, OPS_256, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_VEX, OPAP_None}, + {OPT_Mem, OPS_32, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_VEXImmSrc, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_VEX, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_VEXImmSrc, OPAP_None}, + {OPT_Mem, OPS_32, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_SpareVEX, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_VEX, OPAP_None}, + {OPT_RM, OPS_64, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Imm, OPS_8, 1, 0, OPTM_None, OPA_Imm, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_VEX, OPAP_None}, + {OPT_RM, OPS_32, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Imm, OPS_8, 1, 0, OPTM_None, OPA_Imm, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_SpareVEX, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Imm, OPS_8, 1, 0, OPTM_None, OPA_Imm, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_SpareVEX, OPAP_None}, + {OPT_Mem, OPS_64, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Imm, OPS_8, 1, 0, OPTM_None, OPA_Imm, OPAP_None}, + {OPT_Reg, OPS_16, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_RM, OPS_16, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Imm, OPS_8, 0, 0, OPTM_None, OPA_SImm, OPAP_None}, + {OPT_Reg, OPS_32, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_RM, OPS_32, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Imm, OPS_8, 0, 0, OPTM_None, OPA_SImm, OPAP_None}, + {OPT_Reg, OPS_64, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_RM, OPS_64, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Imm, OPS_8, 0, 0, OPTM_None, OPA_SImm, OPAP_None}, + {OPT_Reg, OPS_16, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_RM, OPS_16, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Imm, OPS_16, 1, 0, OPTM_None, OPA_SImm, OPAP_SImm8}, + {OPT_Reg, OPS_32, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_RM, OPS_32, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Imm, OPS_32, 1, 0, OPTM_None, OPA_SImm, OPAP_SImm8}, + {OPT_Reg, OPS_64, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_RM, OPS_64, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Imm, OPS_32, 1, 0, OPTM_None, OPA_SImm, OPAP_SImm8}, + {OPT_SIMDReg, OPS_64, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_Reg, OPS_32, 0, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Imm, OPS_8, 1, 0, OPTM_None, OPA_Imm, OPAP_None}, + {OPT_SIMDReg, OPS_64, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_Reg, OPS_64, 0, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Imm, OPS_8, 1, 0, OPTM_None, OPA_Imm, OPAP_None}, + {OPT_SIMDReg, OPS_64, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_Mem, OPS_16, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Imm, OPS_8, 1, 0, OPTM_None, OPA_Imm, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_SpareVEX, OPAP_None}, + {OPT_Reg, OPS_32, 0, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Imm, OPS_8, 1, 0, OPTM_None, OPA_Imm, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_SpareVEX, OPAP_None}, + {OPT_Reg, OPS_64, 0, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Imm, OPS_8, 1, 0, OPTM_None, OPA_Imm, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_SpareVEX, OPAP_None}, + {OPT_Mem, OPS_16, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Imm, OPS_8, 1, 0, OPTM_None, OPA_Imm, OPAP_None}, + {OPT_Reg, OPS_32, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_RM, OPS_32, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Imm, OPS_8, 1, 0, OPTM_None, OPA_Imm, OPAP_None}, + {OPT_Reg, OPS_64, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_RM, OPS_64, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Imm, OPS_8, 1, 0, OPTM_None, OPA_Imm, OPAP_None}, + {OPT_SIMDReg, OPS_64, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_SIMDRM, OPS_64, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Imm, OPS_8, 1, 0, OPTM_None, OPA_Imm, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_SpareVEX, OPAP_None}, + {OPT_Mem, OPS_8, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Imm, OPS_8, 1, 0, OPTM_None, OPA_Imm, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_SpareVEX, OPAP_None}, + {OPT_Mem, OPS_32, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Imm, OPS_8, 1, 0, OPTM_None, OPA_Imm, OPAP_None}, + {OPT_Reg, OPS_32, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_RM, OPS_32, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Reg, OPS_32, 0, 0, OPTM_None, OPA_VEX, OPAP_None}, + {OPT_Reg, OPS_64, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_RM, OPS_64, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Reg, OPS_64, 0, 0, OPTM_None, OPA_VEX, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_SIMDRM, OPS_128, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_VEX, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_SpareVEX, OPAP_None}, + {OPT_SIMDRM, OPS_128, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Imm, OPS_8, 1, 0, OPTM_None, OPA_Imm, OPAP_None}, + {OPT_Reg, OPS_32, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_SIMDReg, OPS_64, 0, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Imm, OPS_8, 1, 0, OPTM_None, OPA_Imm, OPAP_None}, + {OPT_Reg, OPS_32, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Imm, OPS_8, 1, 0, OPTM_None, OPA_Imm, OPAP_None}, + {OPT_Reg, OPS_64, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_SIMDReg, OPS_64, 0, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Imm, OPS_8, 1, 0, OPTM_None, OPA_Imm, OPAP_None}, + {OPT_Reg, OPS_64, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Imm, OPS_8, 1, 0, OPTM_None, OPA_Imm, OPAP_None}, + {OPT_Mem, OPS_16, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_Imm, OPS_8, 1, 0, OPTM_None, OPA_Imm, OPAP_None}, + {OPT_Reg, OPS_32, 0, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_Imm, OPS_8, 1, 0, OPTM_None, OPA_Imm, OPAP_None}, + {OPT_Reg, OPS_64, 0, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_Imm, OPS_8, 1, 0, OPTM_None, OPA_Imm, OPAP_None}, + {OPT_RM, OPS_64, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_Imm, OPS_8, 1, 0, OPTM_None, OPA_Imm, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_SIMDRM, OPS_128, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Imm, OPS_8, 1, 0, OPTM_None, OPA_Imm, OPAP_None}, + {OPT_RM, OPS_32, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_Imm, OPS_8, 1, 0, OPTM_None, OPA_Imm, OPAP_None}, + {OPT_SIMDReg, OPS_256, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_SIMDRM, OPS_256, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Imm, OPS_8, 1, 0, OPTM_None, OPA_Imm, OPAP_None}, + {OPT_Mem, OPS_8, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_Imm, OPS_8, 1, 0, OPTM_None, OPA_Imm, OPAP_None}, + {OPT_SIMDReg, OPS_256, 0, 0, OPTM_None, OPA_SpareVEX, OPAP_None}, + {OPT_SIMDRM, OPS_256, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Imm, OPS_8, 1, 0, OPTM_None, OPA_Imm, OPAP_None}, + {OPT_SIMDReg, OPS_256, 0, 0, OPTM_None, OPA_VEX, OPAP_None}, + {OPT_SIMDReg, OPS_256, 0, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Imm, OPS_8, 1, 0, OPTM_None, OPA_Imm, OPAP_None}, + {OPT_SIMDRM, OPS_128, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_VEX, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_SIMDRM, OPS_256, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_SIMDReg, OPS_256, 0, 0, OPTM_None, OPA_VEX, OPAP_None}, + {OPT_SIMDReg, OPS_256, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_Imm, OPS_8, 1, 0, OPTM_None, OPA_Imm, OPAP_None}, + {OPT_Mem, OPS_64, 0, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_Imm, OPS_8, 1, 0, OPTM_None, OPA_Imm, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_SIMDReg, OPS_256, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_Imm, OPS_8, 1, 0, OPTM_None, OPA_Imm, OPAP_None}, + {OPT_Mem, OPS_128, 0, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_SIMDReg, OPS_256, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_Imm, OPS_8, 1, 0, OPTM_None, OPA_Imm, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_MemXMMIndex, OPS_64, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_VEX, OPAP_None}, + {OPT_SIMDReg, OPS_256, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_MemXMMIndex, OPS_64, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_SIMDReg, OPS_256, 0, 0, OPTM_None, OPA_VEX, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_SpareVEX, OPAP_None}, + {OPT_RM, OPS_64, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Imm, OPS_8, 1, 0, OPTM_None, OPA_Imm, OPAP_None}, + {OPT_Reg, OPS_32, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_RM, OPS_32, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Imm, OPS_32, 1, 0, OPTM_None, OPA_Imm, OPAP_None}, + {OPT_Reg, OPS_64, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_RM, OPS_64, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Imm, OPS_32, 1, 0, OPTM_None, OPA_Imm, OPAP_None}, + {OPT_SIMDRM, OPS_128, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_SIMDReg, OPS_256, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_Imm, OPS_8, 1, 0, OPTM_None, OPA_Imm, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_SpareVEX, OPAP_None}, + {OPT_RM, OPS_32, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Imm, OPS_8, 1, 0, OPTM_None, OPA_Imm, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_SIMDRM, OPS_128, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_XMM0, OPS_128, 0, 0, OPTM_None, OPA_None, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_MemXMMIndex, OPS_32, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_VEX, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_MemYMMIndex, OPS_32, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_VEX, OPAP_None}, + {OPT_SIMDReg, OPS_256, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_MemYMMIndex, OPS_32, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_SIMDReg, OPS_256, 0, 0, OPTM_None, OPA_VEX, OPAP_None}, + {OPT_Reg, OPS_32, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_Reg, OPS_32, 0, 0, OPTM_None, OPA_VEX, OPAP_None}, + {OPT_RM, OPS_32, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Reg, OPS_64, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_Reg, OPS_64, 0, 0, OPTM_None, OPA_VEX, OPAP_None}, + {OPT_RM, OPS_64, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_RM, OPS_16, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Reg, OPS_16, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_Imm, OPS_8, 1, 0, OPTM_None, OPA_Imm, OPAP_None}, + {OPT_RM, OPS_16, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Reg, OPS_16, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_Creg, OPS_8, 0, 0, OPTM_None, OPA_None, OPAP_None}, + {OPT_RM, OPS_32, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Reg, OPS_32, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_Imm, OPS_8, 1, 0, OPTM_None, OPA_Imm, OPAP_None}, + {OPT_RM, OPS_32, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Reg, OPS_32, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_Creg, OPS_8, 0, 0, OPTM_None, OPA_None, OPAP_None}, + {OPT_RM, OPS_64, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Reg, OPS_64, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_Imm, OPS_8, 1, 0, OPTM_None, OPA_Imm, OPAP_None}, + {OPT_RM, OPS_64, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Reg, OPS_64, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_Creg, OPS_8, 0, 0, OPTM_None, OPA_None, OPAP_None}, + {OPT_SIMDReg, OPS_256, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_MemYMMIndex, OPS_64, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_SIMDReg, OPS_256, 0, 0, OPTM_None, OPA_VEX, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_VEX, OPAP_None}, + {OPT_RM, OPS_32, 0, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_VEX, OPAP_None}, + {OPT_RM, OPS_64, 0, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_RM, OPS_16, 0, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Imm, OPS_8, 1, 0, OPTM_None, OPA_Imm, OPAP_None}, + {OPT_RM, OPS_32, 0, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Imm, OPS_8, 1, 0, OPTM_None, OPA_Imm, OPAP_None}, + {OPT_RM, OPS_64, 0, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Imm, OPS_8, 1, 0, OPTM_None, OPA_Imm, OPAP_None}, + {OPT_SIMDReg, OPS_64, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_RM, OPS_32, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_SIMDReg, OPS_64, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_RM, OPS_64, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_RM, OPS_64, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_SIMDReg, OPS_64, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_RM, OPS_32, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_RM, OPS_64, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Reg, OPS_16, 0, 0, OPTM_None, OPA_SpareEA, OPAP_None}, + {OPT_Imm, OPS_8, 0, 0, OPTM_None, OPA_SImm, OPAP_None}, + {OPT_Reg, OPS_32, 0, 0, OPTM_None, OPA_SpareEA, OPAP_None}, + {OPT_Imm, OPS_8, 0, 0, OPTM_None, OPA_SImm, OPAP_None}, + {OPT_Reg, OPS_64, 0, 0, OPTM_None, OPA_SpareEA, OPAP_None}, + {OPT_Imm, OPS_8, 0, 0, OPTM_None, OPA_SImm, OPAP_None}, + {OPT_Reg, OPS_16, 0, 0, OPTM_None, OPA_SpareEA, OPAP_None}, + {OPT_Imm, OPS_16, 1, 0, OPTM_None, OPA_SImm, OPAP_SImm8}, + {OPT_Reg, OPS_32, 0, 0, OPTM_None, OPA_SpareEA, OPAP_None}, + {OPT_Imm, OPS_32, 1, 0, OPTM_None, OPA_SImm, OPAP_SImm8}, + {OPT_Reg, OPS_64, 0, 0, OPTM_None, OPA_SpareEA, OPAP_None}, + {OPT_Imm, OPS_32, 1, 0, OPTM_None, OPA_SImm, OPAP_SImm8}, + {OPT_SIMDReg, OPS_64, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_SIMDReg, OPS_64, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_Mem, OPS_64, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Reg, OPS_32, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_SIMDReg, OPS_256, 0, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Reg, OPS_64, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_SIMDReg, OPS_256, 0, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_RM, OPS_8, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Reg, OPS_8, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_Reg, OPS_8, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_RM, OPS_8, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_ST0, OPS_80, 0, 0, OPTM_None, OPA_None, OPAP_None}, + {OPT_Reg, OPS_80, 0, 0, OPTM_None, OPA_Op1Add, OPAP_None}, + {OPT_Reg, OPS_80, 0, 0, OPTM_None, OPA_Op1Add, OPAP_None}, + {OPT_ST0, OPS_80, 0, 0, OPTM_None, OPA_None, OPAP_None}, + {OPT_SIMDRM, OPS_64, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_SIMDReg, OPS_64, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_SIMDRM, OPS_64, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_SIMDRM, OPS_64, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_Mem, OPS_32, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Reg, OPS_32, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_Mem, OPS_64, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Reg, OPS_64, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_Areg, OPS_8, 0, 0, OPTM_None, OPA_None, OPAP_None}, + {OPT_MemOffs, OPS_8, 1, 1, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Areg, OPS_16, 0, 0, OPTM_None, OPA_None, OPAP_None}, + {OPT_MemOffs, OPS_16, 1, 1, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Areg, OPS_32, 0, 0, OPTM_None, OPA_None, OPAP_None}, + {OPT_MemOffs, OPS_32, 1, 1, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Areg, OPS_64, 0, 0, OPTM_None, OPA_None, OPAP_None}, + {OPT_MemOffs, OPS_64, 1, 1, OPTM_None, OPA_EA, OPAP_None}, + {OPT_MemOffs, OPS_8, 1, 1, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Areg, OPS_8, 0, 0, OPTM_None, OPA_None, OPAP_None}, + {OPT_MemOffs, OPS_16, 1, 1, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Areg, OPS_16, 0, 0, OPTM_None, OPA_None, OPAP_None}, + {OPT_MemOffs, OPS_32, 1, 1, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Areg, OPS_32, 0, 0, OPTM_None, OPA_None, OPAP_None}, + {OPT_MemOffs, OPS_64, 1, 1, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Areg, OPS_64, 0, 0, OPTM_None, OPA_None, OPAP_None}, + {OPT_Reg, OPS_64, 0, 0, OPTM_None, OPA_Op0Add, OPAP_None}, + {OPT_Imm, OPS_64, 1, 0, OPTM_None, OPA_Imm, OPAP_None}, + {OPT_Reg, OPS_32, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_Mem, OPS_32, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Reg, OPS_64, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_Mem, OPS_32, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Mem, OPS_64, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_SIMDReg, OPS_64, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_Areg, OPS_8, 0, 0, OPTM_None, OPA_None, OPAP_None}, + {OPT_MemOffs, OPS_8, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Areg, OPS_16, 0, 0, OPTM_None, OPA_None, OPAP_None}, + {OPT_MemOffs, OPS_16, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Areg, OPS_32, 0, 0, OPTM_None, OPA_None, OPAP_None}, + {OPT_MemOffs, OPS_32, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_MemOffs, OPS_8, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Areg, OPS_8, 0, 0, OPTM_None, OPA_None, OPAP_None}, + {OPT_MemOffs, OPS_16, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Areg, OPS_16, 0, 0, OPTM_None, OPA_None, OPAP_None}, + {OPT_MemOffs, OPS_32, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Areg, OPS_32, 0, 0, OPTM_None, OPA_None, OPAP_None}, + {OPT_RM, OPS_8, 1, 0, OPTM_None, OPA_EA, OPAP_ShortMov}, + {OPT_Areg, OPS_8, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_RM, OPS_16, 1, 0, OPTM_None, OPA_EA, OPAP_ShortMov}, + {OPT_Areg, OPS_16, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_RM, OPS_32, 1, 0, OPTM_None, OPA_EA, OPAP_ShortMov}, + {OPT_Areg, OPS_32, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_RM, OPS_64, 1, 0, OPTM_None, OPA_EA, OPAP_ShortMov}, + {OPT_Areg, OPS_64, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_Areg, OPS_8, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_RM, OPS_8, 1, 0, OPTM_None, OPA_EA, OPAP_ShortMov}, + {OPT_Areg, OPS_16, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_RM, OPS_16, 1, 0, OPTM_None, OPA_EA, OPAP_ShortMov}, + {OPT_Areg, OPS_32, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_RM, OPS_32, 1, 0, OPTM_None, OPA_EA, OPAP_ShortMov}, + {OPT_Areg, OPS_64, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_RM, OPS_64, 1, 0, OPTM_None, OPA_EA, OPAP_ShortMov}, + {OPT_Mem, OPS_16, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_SegReg, OPS_16, 1, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_Reg, OPS_16, 0, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_SegReg, OPS_16, 1, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_Reg, OPS_32, 0, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_SegReg, OPS_16, 1, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_Reg, OPS_64, 0, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_SegReg, OPS_16, 1, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_SegReg, OPS_16, 1, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_RM, OPS_16, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Reg, OPS_8, 0, 0, OPTM_None, OPA_Op0Add, OPAP_None}, + {OPT_Imm, OPS_8, 1, 0, OPTM_None, OPA_Imm, OPAP_None}, + {OPT_Reg, OPS_16, 0, 0, OPTM_None, OPA_Op0Add, OPAP_None}, + {OPT_Imm, OPS_16, 1, 0, OPTM_None, OPA_Imm, OPAP_None}, + {OPT_Reg, OPS_32, 0, 0, OPTM_None, OPA_Op0Add, OPAP_None}, + {OPT_Imm, OPS_32, 1, 0, OPTM_None, OPA_Imm, OPAP_None}, + {OPT_Reg, OPS_64, 0, 0, OPTM_None, OPA_Op0Add, OPAP_None}, + {OPT_Imm, OPS_64, 0, 0, OPTM_None, OPA_Imm, OPAP_None}, + {OPT_Reg, OPS_64, 0, 0, OPTM_None, OPA_Op0Add, OPAP_None}, + {OPT_Imm, OPS_64, 1, 0, OPTM_None, OPA_Imm, OPAP_SImm32Avail}, + {OPT_RM, OPS_8, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Imm, OPS_8, 0, 0, OPTM_None, OPA_Imm, OPAP_None}, + {OPT_RM, OPS_16, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Imm, OPS_16, 0, 0, OPTM_None, OPA_Imm, OPAP_None}, + {OPT_RM, OPS_32, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Imm, OPS_32, 0, 0, OPTM_None, OPA_Imm, OPAP_None}, + {OPT_RM, OPS_64, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Imm, OPS_32, 0, 0, OPTM_None, OPA_Imm, OPAP_None}, + {OPT_RM, OPS_8, 0, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Imm, OPS_8, 1, 0, OPTM_None, OPA_Imm, OPAP_None}, + {OPT_RM, OPS_16, 0, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Imm, OPS_16, 1, 0, OPTM_None, OPA_Imm, OPAP_None}, + {OPT_RM, OPS_32, 0, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Imm, OPS_32, 1, 0, OPTM_None, OPA_Imm, OPAP_None}, + {OPT_RM, OPS_64, 0, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Imm, OPS_32, 1, 0, OPTM_None, OPA_Imm, OPAP_None}, + {OPT_CR4, OPS_32, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_Reg, OPS_32, 0, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_CRReg, OPS_32, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_Reg, OPS_32, 0, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_CRReg, OPS_32, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_Reg, OPS_64, 0, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Reg, OPS_32, 0, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_CR4, OPS_32, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_Reg, OPS_64, 0, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_CRReg, OPS_32, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_DRReg, OPS_32, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_Reg, OPS_32, 0, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_DRReg, OPS_32, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_Reg, OPS_64, 0, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Reg, OPS_64, 0, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_DRReg, OPS_32, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_SIMDReg, OPS_64, 0, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_Mem, OPS_16, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_SIMDReg, OPS_256, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_Mem, OPS_32, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_Mem, OPS_64, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_SIMDReg, OPS_256, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_SIMDRM, OPS_128, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Reg, OPS_16, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_Reg, OPS_16, 0, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Reg, OPS_32, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_Reg, OPS_32, 0, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Reg, OPS_32, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_RM, OPS_16, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Reg, OPS_64, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_Reg, OPS_32, 0, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Reg, OPS_64, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_RM, OPS_16, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Reg, OPS_16, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_Mem, OPS_16, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Mem, OPS_16, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Reg, OPS_16, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_Reg, OPS_64, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_Mem, OPS_64, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Areg, OPS_8, 0, 0, OPTM_None, OPA_None, OPAP_None}, + {OPT_RM, OPS_8, 0, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Areg, OPS_16, 0, 0, OPTM_None, OPA_None, OPAP_None}, + {OPT_RM, OPS_16, 0, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Areg, OPS_32, 0, 0, OPTM_None, OPA_None, OPAP_None}, + {OPT_RM, OPS_32, 0, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Areg, OPS_64, 0, 0, OPTM_None, OPA_None, OPAP_None}, + {OPT_RM, OPS_64, 0, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_SIMDReg, OPS_256, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_Mem, OPS_64, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Imm, OPS_Any, 0, 0, OPTM_None, OPA_JmpRel, OPAP_None}, + {OPT_Creg, OPS_32, 0, 0, OPTM_None, OPA_AdSizeR, OPAP_None}, + {OPT_Imm, OPS_Any, 0, 0, OPTM_Short, OPA_JmpRel, OPAP_None}, + {OPT_Creg, OPS_32, 0, 0, OPTM_None, OPA_AdSizeR, OPAP_None}, + {OPT_SIMDRM, OPS_128, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_SIMDRM, OPS_256, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_SIMDReg, OPS_256, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_Imm, OPS_Any, 0, 0, OPTM_None, OPA_JmpRel, OPAP_None}, + {OPT_Creg, OPS_64, 0, 0, OPTM_None, OPA_AdSizeR, OPAP_None}, + {OPT_Imm, OPS_Any, 0, 0, OPTM_Short, OPA_JmpRel, OPAP_None}, + {OPT_Creg, OPS_64, 0, 0, OPTM_None, OPA_AdSizeR, OPAP_None}, + {OPT_Imm, OPS_Any, 0, 0, OPTM_None, OPA_JmpRel, OPAP_None}, + {OPT_Creg, OPS_16, 0, 0, OPTM_None, OPA_AdSizeR, OPAP_None}, + {OPT_Imm, OPS_Any, 0, 0, OPTM_Short, OPA_JmpRel, OPAP_None}, + {OPT_Creg, OPS_16, 0, 0, OPTM_None, OPA_AdSizeR, OPAP_None}, + {OPT_Imm, OPS_8, 1, 0, OPTM_None, OPA_Imm, OPAP_None}, + {OPT_Areg, OPS_8, 0, 0, OPTM_None, OPA_None, OPAP_None}, + {OPT_Imm, OPS_8, 1, 0, OPTM_None, OPA_Imm, OPAP_None}, + {OPT_Areg, OPS_16, 0, 0, OPTM_None, OPA_None, OPAP_None}, + {OPT_Imm, OPS_8, 1, 0, OPTM_None, OPA_Imm, OPAP_None}, + {OPT_Areg, OPS_32, 0, 0, OPTM_None, OPA_None, OPAP_None}, + {OPT_Dreg, OPS_16, 0, 0, OPTM_None, OPA_None, OPAP_None}, + {OPT_Areg, OPS_8, 0, 0, OPTM_None, OPA_None, OPAP_None}, + {OPT_Dreg, OPS_16, 0, 0, OPTM_None, OPA_None, OPAP_None}, + {OPT_Areg, OPS_16, 0, 0, OPTM_None, OPA_None, OPAP_None}, + {OPT_Dreg, OPS_16, 0, 0, OPTM_None, OPA_None, OPAP_None}, + {OPT_Areg, OPS_32, 0, 0, OPTM_None, OPA_None, OPAP_None}, + {OPT_SIMDReg, OPS_256, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_Mem, OPS_128, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_EAVEX, OPAP_None}, + {OPT_Imm, OPS_8, 1, 0, OPTM_None, OPA_Imm, OPAP_None}, + {OPT_SIMDReg, OPS_256, 0, 0, OPTM_None, OPA_EAVEX, OPAP_None}, + {OPT_Imm, OPS_8, 1, 0, OPTM_None, OPA_Imm, OPAP_None}, + {OPT_MemrAX, OPS_Any, 0, 0, OPTM_None, OPA_AdSizeEA, OPAP_None}, + {OPT_Creg, OPS_32, 0, 0, OPTM_None, OPA_None, OPAP_None}, + {OPT_Areg, OPS_16, 0, 0, OPTM_None, OPA_None, OPAP_None}, + {OPT_Reg, OPS_16, 0, 0, OPTM_None, OPA_Op0Add, OPAP_None}, + {OPT_Reg, OPS_16, 0, 0, OPTM_None, OPA_Op0Add, OPAP_None}, + {OPT_Areg, OPS_16, 0, 0, OPTM_None, OPA_None, OPAP_None}, + {OPT_Areg, OPS_32, 0, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Areg, OPS_32, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_Areg, OPS_32, 0, 0, OPTM_None, OPA_None, OPAP_None}, + {OPT_Reg, OPS_32, 0, 0, OPTM_None, OPA_Op0Add, OPAP_None}, + {OPT_Reg, OPS_32, 0, 0, OPTM_None, OPA_Op0Add, OPAP_None}, + {OPT_Areg, OPS_32, 0, 0, OPTM_None, OPA_None, OPAP_None}, + {OPT_Areg, OPS_64, 0, 0, OPTM_None, OPA_None, OPAP_None}, + {OPT_Areg, OPS_64, 0, 0, OPTM_None, OPA_Op0Add, OPAP_None}, + {OPT_Reg, OPS_64, 0, 0, OPTM_None, OPA_Op0Add, OPAP_None}, + {OPT_Areg, OPS_64, 0, 0, OPTM_None, OPA_None, OPAP_None}, + {OPT_Reg, OPS_16, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_Mem, OPS_Any, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Reg, OPS_32, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_Mem, OPS_Any, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Reg, OPS_64, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_Mem, OPS_Any, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Reg, OPS_32, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_RM, OPS_8, 0, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Reg, OPS_32, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_RM, OPS_16, 0, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Reg, OPS_64, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_RM, OPS_8, 0, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_SIMDReg, OPS_128, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_SIMDReg, OPS_256, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_SIMDReg, OPS_128, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_RM, OPS_16, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_SIMDReg, OPS_256, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_RM, OPS_16, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_RM, OPS_8, 0, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Creg, OPS_8, 0, 0, OPTM_None, OPA_None, OPAP_None}, + {OPT_RM, OPS_8, 0, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Imm1, OPS_8, 1, 0, OPTM_None, OPA_None, OPAP_None}, + {OPT_RM, OPS_16, 0, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Creg, OPS_8, 0, 0, OPTM_None, OPA_None, OPAP_None}, + {OPT_RM, OPS_16, 0, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Imm1, OPS_8, 1, 0, OPTM_None, OPA_None, OPAP_None}, + {OPT_RM, OPS_32, 0, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Creg, OPS_8, 0, 0, OPTM_None, OPA_None, OPAP_None}, + {OPT_RM, OPS_32, 0, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Imm1, OPS_8, 1, 0, OPTM_None, OPA_None, OPAP_None}, + {OPT_RM, OPS_64, 0, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Creg, OPS_8, 0, 0, OPTM_None, OPA_None, OPAP_None}, + {OPT_RM, OPS_64, 0, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Imm1, OPS_8, 1, 0, OPTM_None, OPA_None, OPAP_None}, + {OPT_Imm, OPS_16, 1, 0, OPTM_None, OPA_JmpFar, OPAP_None}, + {OPT_Imm, OPS_16, 1, 0, OPTM_None, OPA_JmpFar, OPAP_None}, + {OPT_Imm, OPS_16, 1, 0, OPTM_None, OPA_JmpFar, OPAP_None}, + {OPT_Imm, OPS_32, 1, 0, OPTM_None, OPA_JmpFar, OPAP_None}, + {OPT_Imm, OPS_16, 1, 0, OPTM_None, OPA_JmpFar, OPAP_None}, + {OPT_Imm, OPS_BITS, 1, 0, OPTM_None, OPA_JmpFar, OPAP_None}, + {OPT_Areg, OPS_16, 0, 0, OPTM_None, OPA_None, OPAP_None}, + {OPT_Imm, OPS_16, 1, 0, OPTM_None, OPA_Imm, OPAP_SImm8}, + {OPT_Areg, OPS_32, 0, 0, OPTM_None, OPA_None, OPAP_None}, + {OPT_Imm, OPS_32, 1, 0, OPTM_None, OPA_Imm, OPAP_SImm8}, + {OPT_Areg, OPS_64, 0, 0, OPTM_None, OPA_None, OPAP_None}, + {OPT_Imm, OPS_32, 1, 0, OPTM_None, OPA_Imm, OPAP_SImm8}, + {OPT_RM, OPS_16, 0, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Imm, OPS_8, 0, 0, OPTM_None, OPA_SImm, OPAP_None}, + {OPT_RM, OPS_16, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Imm, OPS_16, 0, 0, OPTM_None, OPA_Imm, OPAP_SImm8}, + {OPT_RM, OPS_16, 0, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Imm, OPS_16, 1, 0, OPTM_None, OPA_Imm, OPAP_SImm8}, + {OPT_RM, OPS_32, 0, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Imm, OPS_8, 0, 0, OPTM_None, OPA_SImm, OPAP_None}, + {OPT_RM, OPS_32, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Imm, OPS_32, 0, 0, OPTM_None, OPA_Imm, OPAP_SImm8}, + {OPT_RM, OPS_32, 0, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Imm, OPS_32, 1, 0, OPTM_None, OPA_Imm, OPAP_SImm8}, + {OPT_RM, OPS_64, 0, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Imm, OPS_8, 0, 0, OPTM_None, OPA_SImm, OPAP_None}, + {OPT_RM, OPS_64, 0, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Imm, OPS_32, 1, 0, OPTM_None, OPA_Imm, OPAP_SImm8}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_Mem, OPS_128, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_SIMDReg, OPS_256, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_Mem, OPS_256, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Mem, OPS_128, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_Mem, OPS_256, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_SIMDReg, OPS_256, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_Reg, OPS_16, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_RM, OPS_8, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Reg, OPS_64, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_RM, OPS_16, 0, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_SIMDRM, OPS_128, 0, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_SIMDRM, OPS_256, 0, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Reg, OPS_32, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_Mem, OPS_128, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Reg, OPS_64, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_Mem, OPS_128, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_SIMDReg, OPS_64, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_SIMDRM, OPS_128, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Areg, OPS_32, 0, 0, OPTM_None, OPA_None, OPAP_None}, + {OPT_Imm, OPS_8, 1, 0, OPTM_None, OPA_Imm, OPAP_None}, + {OPT_Mem, OPS_80, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_SegReg, OPS_16, 1, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_SIMDReg, OPS_256, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_SIMDRM, OPS_64, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Areg, OPS_16, 0, 0, OPTM_None, OPA_None, OPAP_None}, + {OPT_Imm, OPS_16, 1, 0, OPTM_None, OPA_Imm, OPAP_None}, + {OPT_Areg, OPS_32, 0, 0, OPTM_None, OPA_None, OPAP_None}, + {OPT_Imm, OPS_32, 1, 0, OPTM_None, OPA_Imm, OPAP_None}, + {OPT_Areg, OPS_64, 0, 0, OPTM_None, OPA_None, OPAP_None}, + {OPT_Imm, OPS_32, 1, 0, OPTM_None, OPA_Imm, OPAP_None}, + {OPT_SegReg, OPS_16, 1, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_Mem, OPS_80, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_Mem, OPS_64, 0, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_SIMDReg, OPS_256, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_Mem, OPS_128, 0, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_RM, OPS_8, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_SIMDReg, OPS_256, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_RM, OPS_8, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_SIMDReg, OPS_256, 0, 0, OPTM_None, OPA_SpareVEX, OPAP_None}, + {OPT_SIMDRM, OPS_128, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_SIMDReg, OPS_64, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_SIMDReg, OPS_64, 0, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_SIMDReg, OPS_256, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_RM, OPS_32, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Imm, OPS_16, 1, 0, OPTM_None, OPA_EA, OPAP_A16}, + {OPT_Imm, OPS_8, 1, 0, OPTM_None, OPA_Imm, OPAP_None}, + {OPT_Reg, OPS_64, 0, 0, OPTM_None, OPA_Spare, OPAP_None}, + {OPT_RM, OPS_32, 0, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_SpareVEX, OPAP_None}, + {OPT_RM, OPS_32, 0, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_SIMDReg, OPS_128, 0, 0, OPTM_None, OPA_SpareVEX, OPAP_None}, + {OPT_RM, OPS_64, 0, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Mem, OPS_16, 0, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Mem, OPS_32, 0, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_MemEAX, OPS_Any, 0, 0, OPTM_None, OPA_None, OPAP_None}, + {OPT_Mem, OPS_80, 0, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Reg, OPS_BITS, 0, 0, OPTM_None, OPA_Op0Add, OPAP_None}, + {OPT_RM, OPS_BITS, 0, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_SS, OPS_Any, 0, 0, OPTM_None, OPA_None, OPAP_None}, + {OPT_SS, OPS_16, 0, 0, OPTM_None, OPA_None, OPAP_None}, + {OPT_SS, OPS_32, 0, 0, OPTM_None, OPA_None, OPAP_None}, + {OPT_DS, OPS_Any, 0, 0, OPTM_None, OPA_None, OPAP_None}, + {OPT_DS, OPS_16, 0, 0, OPTM_None, OPA_None, OPAP_None}, + {OPT_DS, OPS_32, 0, 0, OPTM_None, OPA_None, OPAP_None}, + {OPT_ES, OPS_Any, 0, 0, OPTM_None, OPA_None, OPAP_None}, + {OPT_ES, OPS_16, 0, 0, OPTM_None, OPA_None, OPAP_None}, + {OPT_ES, OPS_32, 0, 0, OPTM_None, OPA_None, OPAP_None}, + {OPT_FS, OPS_Any, 0, 0, OPTM_None, OPA_None, OPAP_None}, + {OPT_FS, OPS_16, 0, 0, OPTM_None, OPA_None, OPAP_None}, + {OPT_FS, OPS_32, 0, 0, OPTM_None, OPA_None, OPAP_None}, + {OPT_GS, OPS_Any, 0, 0, OPTM_None, OPA_None, OPAP_None}, + {OPT_GS, OPS_16, 0, 0, OPTM_None, OPA_None, OPAP_None}, + {OPT_GS, OPS_32, 0, 0, OPTM_None, OPA_None, OPAP_None}, + {OPT_Mem, OPS_Any, 0, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_ImmNotSegOff, OPS_Any, 0, 0, OPTM_None, OPA_JmpRel, OPAP_None}, + {OPT_ImmNotSegOff, OPS_16, 0, 0, OPTM_None, OPA_JmpRel, OPAP_None}, + {OPT_ImmNotSegOff, OPS_32, 0, 0, OPTM_None, OPA_JmpRel, OPAP_None}, + {OPT_Imm, OPS_16, 0, 0, OPTM_Near, OPA_JmpRel, OPAP_None}, + {OPT_Imm, OPS_32, 0, 0, OPTM_Near, OPA_JmpRel, OPAP_None}, + {OPT_Imm, OPS_Any, 0, 0, OPTM_Near, OPA_JmpRel, OPAP_None}, + {OPT_Reg, OPS_BITS, 0, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_RM, OPS_16, 0, 0, OPTM_Near, OPA_EA, OPAP_None}, + {OPT_RM, OPS_32, 0, 0, OPTM_Near, OPA_EA, OPAP_None}, + {OPT_RM, OPS_64, 0, 0, OPTM_Near, OPA_EA, OPAP_None}, + {OPT_Mem, OPS_Any, 0, 0, OPTM_Near, OPA_EA, OPAP_None}, + {OPT_Mem, OPS_16, 0, 0, OPTM_Far, OPA_EA, OPAP_None}, + {OPT_Mem, OPS_32, 0, 0, OPTM_Far, OPA_EA, OPAP_None}, + {OPT_Mem, OPS_64, 0, 0, OPTM_Far, OPA_EA, OPAP_None}, + {OPT_Mem, OPS_Any, 0, 0, OPTM_Far, OPA_EA, OPAP_None}, + {OPT_Imm, OPS_16, 0, 0, OPTM_Far, OPA_JmpFar, OPAP_None}, + {OPT_Imm, OPS_32, 0, 0, OPTM_Far, OPA_JmpFar, OPAP_None}, + {OPT_Imm, OPS_Any, 0, 0, OPTM_Far, OPA_JmpFar, OPAP_None}, + {OPT_Imm, OPS_16, 0, 0, OPTM_None, OPA_JmpFar, OPAP_None}, + {OPT_Imm, OPS_32, 0, 0, OPTM_None, OPA_JmpFar, OPAP_None}, + {OPT_Imm, OPS_Any, 0, 0, OPTM_None, OPA_JmpFar, OPAP_None}, + {OPT_Reg, OPS_80, 0, 0, OPTM_To, OPA_Op1Add, OPAP_None}, + {OPT_Reg, OPS_32, 0, 0, OPTM_None, OPA_Op1Add, OPAP_None}, + {OPT_Reg, OPS_64, 0, 0, OPTM_None, OPA_Op1Add, OPAP_None}, + {OPT_Mem, OPS_BITS, 1, 0, OPTM_None, OPA_EA, OPAP_None}, + {OPT_Imm, OPS_16, 0, 0, OPTM_None, OPA_JmpRel, OPAP_None}, + {OPT_Imm, OPS_32, 0, 0, OPTM_None, OPA_JmpRel, OPAP_None}, + {OPT_Imm, OPS_8, 1, 0, OPTM_None, OPA_SImm, OPAP_None}, + {OPT_Imm, OPS_BITS, 1, 0, OPTM_None, OPA_Imm, OPAP_SImm8}, + {OPT_Imm, OPS_32, 0, 0, OPTM_None, OPA_SImm, OPAP_None}, + {OPT_CS, OPS_Any, 0, 0, OPTM_None, OPA_None, OPAP_None}, + {OPT_CS, OPS_16, 0, 0, OPTM_None, OPA_None, OPAP_None}, + {OPT_CS, OPS_32, 0, 0, OPTM_None, OPA_None, OPAP_None} +}; + +static const x86_insn_info empty_insn[] = { + { SUF_Z, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0 } +}; + +static const x86_insn_info not64_insn[] = { + { SUF_Z, NOT_64, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0 } +}; + +static const x86_insn_info onebyte_insn[] = { + { SUF_Z, 0, 0, 0, 0, {MOD_Op0Add, MOD_OpSizeR, MOD_DOpS64R}, 0, 0, 0, 1, {0x00, 0, 0}, 0, 0, 0 } +}; + +static const x86_insn_info onebyte_prefix_insn[] = { + { SUF_Z, 0, 0, 0, 0, {MOD_PreAdd, MOD_Op0Add, 0}, 0, 0, 0x00, 1, {0x00, 0, 0}, 0, 0, 0 } +}; + +static const x86_insn_info twobyte_insn[] = { + { SUF_L|SUF_Q|SUF_Z, 0, 0, 0, 0, {MOD_Op0Add, MOD_Op1Add, 0}, 0, 0, 0, 2, {0x00, 0x00, 0}, 0, 0, 0 } +}; + +static const x86_insn_info threebyte_insn[] = { + { SUF_Z, 0, 0, 0, 0, {MOD_Op0Add, MOD_Op1Add, MOD_Op2Add}, 0, 0, 0, 3, {0x00, 0x00, 0x00}, 0, 0, 0 } +}; + +static const x86_insn_info onebytemem_insn[] = { + { SUF_L|SUF_Q|SUF_S|SUF_Z, 0, 0, 0, 0, {MOD_SpAdd, MOD_Op0Add, 0}, 0, 0, 0, 1, {0x00, 0, 0}, 0, 1, 674 } +}; + +static const x86_insn_info twobytemem_insn[] = { + { SUF_L|SUF_Q|SUF_S|SUF_W|SUF_Z, 0, 0, 0, 0, {MOD_SpAdd, MOD_Op0Add, MOD_Op1Add}, 0, 0, 0, 2, {0x00, 0x00, 0}, 0, 1, 532 } +}; + +static const x86_insn_info mov_insn[] = { + { SUF_B|SUF_Z, NOT_64, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 1, {0xA0, 0, 0}, 0, 2, 365 }, + { SUF_W|SUF_Z, NOT_64, 0, 0, 0, {0, 0, 0}, 16, 0, 0, 1, {0xA1, 0, 0}, 0, 2, 367 }, + { SUF_L|SUF_Z, NOT_64, CPU_386, 0, 0, {0, 0, 0}, 32, 0, 0, 1, {0xA1, 0, 0}, 0, 2, 369 }, + { SUF_B|SUF_Z, NOT_64, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 1, {0xA2, 0, 0}, 0, 2, 371 }, + { SUF_W|SUF_Z, NOT_64, 0, 0, 0, {0, 0, 0}, 16, 0, 0, 1, {0xA3, 0, 0}, 0, 2, 373 }, + { SUF_L|SUF_Z, NOT_64, CPU_386, 0, 0, {0, 0, 0}, 32, 0, 0, 1, {0xA3, 0, 0}, 0, 2, 375 }, + { SUF_Z, ONLY_64, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 1, {0xA0, 0, 0}, 0, 2, 341 }, + { SUF_Z, ONLY_64, 0, 0, 0, {0, 0, 0}, 16, 0, 0, 1, {0xA1, 0, 0}, 0, 2, 343 }, + { SUF_Z, ONLY_64, 0, 0, 0, {0, 0, 0}, 32, 0, 0, 1, {0xA1, 0, 0}, 0, 2, 345 }, + { SUF_Z, ONLY_64, 0, 0, 0, {0, 0, 0}, 64, 0, 0, 1, {0xA1, 0, 0}, 0, 2, 347 }, + { SUF_Z, ONLY_64, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 1, {0xA2, 0, 0}, 0, 2, 349 }, + { SUF_Z, ONLY_64, 0, 0, 0, {0, 0, 0}, 16, 0, 0, 1, {0xA3, 0, 0}, 0, 2, 351 }, + { SUF_Z, ONLY_64, 0, 0, 0, {0, 0, 0}, 32, 0, 0, 1, {0xA3, 0, 0}, 0, 2, 353 }, + { SUF_Z, ONLY_64, 0, 0, 0, {0, 0, 0}, 64, 0, 0, 1, {0xA3, 0, 0}, 0, 2, 355 }, + { SUF_B|SUF_Z, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 1, {0x88, 0xA2, 0}, 0, 2, 377 }, + { SUF_W|SUF_Z, 0, 0, 0, 0, {0, 0, 0}, 16, 0, 0, 1, {0x89, 0xA3, 0}, 0, 2, 379 }, + { SUF_L|SUF_Z, 0, CPU_386, 0, 0, {0, 0, 0}, 32, 0, 0, 1, {0x89, 0xA3, 0}, 0, 2, 381 }, + { SUF_Q|SUF_Z, ONLY_64, 0, 0, 0, {0, 0, 0}, 64, 0, 0, 1, {0x89, 0xA3, 0}, 0, 2, 383 }, + { SUF_B|SUF_Z, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 1, {0x88, 0, 0}, 0, 2, 323 }, + { SUF_W|SUF_Z, 0, 0, 0, 0, {0, 0, 0}, 16, 0, 0, 1, {0x89, 0, 0}, 0, 2, 260 }, + { SUF_L|SUF_Z, 0, CPU_386, 0, 0, {0, 0, 0}, 32, 0, 0, 1, {0x89, 0, 0}, 0, 2, 266 }, + { SUF_Q|SUF_Z, ONLY_64, 0, 0, 0, {0, 0, 0}, 64, 0, 0, 1, {0x89, 0, 0}, 0, 2, 272 }, + { SUF_B|SUF_Z, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 1, {0x8A, 0xA0, 0}, 0, 2, 385 }, + { SUF_W|SUF_Z, 0, 0, 0, 0, {0, 0, 0}, 16, 0, 0, 1, {0x8B, 0xA1, 0}, 0, 2, 387 }, + { SUF_L|SUF_Z, 0, CPU_386, 0, 0, {0, 0, 0}, 32, 0, 0, 1, {0x8B, 0xA1, 0}, 0, 2, 389 }, + { SUF_Q|SUF_Z, ONLY_64, 0, 0, 0, {0, 0, 0}, 64, 0, 0, 1, {0x8B, 0xA1, 0}, 0, 2, 391 }, + { SUF_B|SUF_Z, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 1, {0x8A, 0, 0}, 0, 2, 325 }, + { SUF_W|SUF_Z, 0, 0, 0, 0, {0, 0, 0}, 16, 0, 0, 1, {0x8B, 0, 0}, 0, 2, 98 }, + { SUF_L|SUF_Z, 0, CPU_386, 0, 0, {0, 0, 0}, 32, 0, 0, 1, {0x8B, 0, 0}, 0, 2, 101 }, + { SUF_Q|SUF_Z, ONLY_64, 0, 0, 0, {0, 0, 0}, 64, 0, 0, 1, {0x8B, 0, 0}, 0, 2, 104 }, + { SUF_W|SUF_Z, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 1, {0x8C, 0, 0}, 0, 2, 393 }, + { SUF_W|SUF_Z, 0, 0, 0, 0, {0, 0, 0}, 16, 0, 0, 1, {0x8C, 0, 0}, 0, 2, 395 }, + { SUF_L|SUF_Z, 0, CPU_386, 0, 0, {0, 0, 0}, 32, 0, 0, 1, {0x8C, 0, 0}, 0, 2, 397 }, + { SUF_Q|SUF_Z, ONLY_64, 0, 0, 0, {0, 0, 0}, 64, 0, 0, 1, {0x8C, 0, 0}, 0, 2, 399 }, + { SUF_W|SUF_Z, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 1, {0x8E, 0, 0}, 0, 2, 401 }, + { SUF_L|SUF_Z, 0, CPU_386, 0, 0, {0, 0, 0}, 0, 0, 0, 1, {0x8E, 0, 0}, 0, 2, 396 }, + { SUF_Q|SUF_Z, ONLY_64, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 1, {0x8E, 0, 0}, 0, 2, 398 }, + { SUF_B|SUF_Z, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 1, {0xB0, 0, 0}, 0, 2, 403 }, + { SUF_W|SUF_Z, 0, 0, 0, 0, {0, 0, 0}, 16, 0, 0, 1, {0xB8, 0, 0}, 0, 2, 405 }, + { SUF_L|SUF_Z, 0, CPU_386, 0, 0, {0, 0, 0}, 32, 0, 0, 1, {0xB8, 0, 0}, 0, 2, 407 }, + { GAS_ILLEGAL|SUF_Z, ONLY_64, 0, 0, 0, {0, 0, 0}, 64, 0, 0, 1, {0xB8, 0, 0}, 0, 2, 409 }, + { SUF_Q|SUF_Z, ONLY_64, 0, 0, 0, {0, 0, 0}, 64, 0, 0, 1, {0xB8, 0xC7, 0}, 0, 2, 411 }, + { SUF_B|SUF_Z, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 1, {0xC6, 0, 0}, 0, 2, 413 }, + { SUF_W|SUF_Z, 0, 0, 0, 0, {0, 0, 0}, 16, 0, 0, 1, {0xC7, 0, 0}, 0, 2, 415 }, + { SUF_L|SUF_Z, 0, CPU_386, 0, 0, {0, 0, 0}, 32, 0, 0, 1, {0xC7, 0, 0}, 0, 2, 417 }, + { SUF_Q|SUF_Z, ONLY_64, 0, 0, 0, {0, 0, 0}, 64, 0, 0, 1, {0xC7, 0, 0}, 0, 2, 419 }, + { SUF_B|SUF_Z, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 1, {0xC6, 0, 0}, 0, 2, 421 }, + { SUF_W|SUF_Z, 0, 0, 0, 0, {0, 0, 0}, 16, 0, 0, 1, {0xC7, 0, 0}, 0, 2, 423 }, + { SUF_L|SUF_Z, 0, CPU_386, 0, 0, {0, 0, 0}, 32, 0, 0, 1, {0xC7, 0, 0}, 0, 2, 425 }, + { SUF_Q|SUF_Z, ONLY_64, 0, 0, 0, {0, 0, 0}, 64, 0, 0, 1, {0xC7, 0, 0}, 0, 2, 427 }, + { SUF_L|SUF_Z, NOT_64, CPU_586, CPU_Priv, 0, {0, 0, 0}, 0, 0, 0, 2, {0x0F, 0x22, 0}, 0, 2, 429 }, + { SUF_L|SUF_Z, NOT_64, CPU_386, CPU_Priv, 0, {0, 0, 0}, 0, 0, 0, 2, {0x0F, 0x22, 0}, 0, 2, 431 }, + { SUF_Q|SUF_Z, ONLY_64, CPU_Priv, 0, 0, {0, 0, 0}, 0, 0, 0, 2, {0x0F, 0x22, 0}, 0, 2, 433 }, + { SUF_L|SUF_Z, NOT_64, CPU_586, CPU_Priv, 0, {0, 0, 0}, 0, 0, 0, 2, {0x0F, 0x20, 0}, 0, 2, 435 }, + { SUF_L|SUF_Z, NOT_64, CPU_386, CPU_Priv, 0, {0, 0, 0}, 0, 0, 0, 2, {0x0F, 0x20, 0}, 0, 2, 430 }, + { SUF_Q|SUF_Z, ONLY_64, CPU_Priv, 0, 0, {0, 0, 0}, 0, 0, 0, 2, {0x0F, 0x20, 0}, 0, 2, 437 }, + { SUF_L|SUF_Z, NOT_64, CPU_386, CPU_Priv, 0, {0, 0, 0}, 0, 0, 0, 2, {0x0F, 0x23, 0}, 0, 2, 439 }, + { SUF_Q|SUF_Z, ONLY_64, CPU_Priv, 0, 0, {0, 0, 0}, 0, 0, 0, 2, {0x0F, 0x23, 0}, 0, 2, 441 }, + { SUF_L|SUF_Z, NOT_64, CPU_386, CPU_Priv, 0, {0, 0, 0}, 0, 0, 0, 2, {0x0F, 0x21, 0}, 0, 2, 440 }, + { SUF_Q|SUF_Z, ONLY_64, CPU_Priv, 0, 0, {0, 0, 0}, 0, 0, 0, 2, {0x0F, 0x21, 0}, 0, 2, 443 }, + { GAS_ONLY|SUF_Q|SUF_Z, 0, CPU_MMX, 0, 0, {0, 0, 0}, 0, 0, 0, 2, {0x0F, 0x6F, 0}, 0, 2, 140 }, + { GAS_ONLY|SUF_Q|SUF_Z, ONLY_64, CPU_MMX, 0, 0, {0, 0, 0}, 64, 0, 0, 2, {0x0F, 0x6E, 0}, 0, 2, 295 }, + { GAS_ONLY|SUF_Q|SUF_Z, 0, CPU_MMX, 0, 0, {0, 0, 0}, 0, 0, 0, 2, {0x0F, 0x7F, 0}, 0, 2, 331 }, + { GAS_ONLY|SUF_Q|SUF_Z, ONLY_64, CPU_MMX, 0, 0, {0, 0, 0}, 64, 0, 0, 2, {0x0F, 0x7E, 0}, 0, 2, 297 }, + { GAS_ONLY|SUF_Q|SUF_Z, 0, CPU_SSE2, 0, 0, {0, 0, 0}, 0, 0, 0xF3, 2, {0x0F, 0x7E, 0}, 0, 2, 64 }, + { GAS_ONLY|SUF_Q|SUF_Z, 0, CPU_SSE2, 0, 0, {0, 0, 0}, 0, 0, 0xF3, 2, {0x0F, 0x7E, 0}, 0, 2, 333 }, + { GAS_ONLY|SUF_Q|SUF_Z, ONLY_64, CPU_SSE2, 0, 0, {0, 0, 0}, 64, 0, 0x66, 2, {0x0F, 0x6E, 0}, 0, 2, 301 }, + { GAS_ONLY|SUF_Q|SUF_Z, 0, CPU_SSE2, 0, 0, {0, 0, 0}, 0, 0, 0x66, 2, {0x0F, 0xD6, 0}, 0, 2, 335 }, + { GAS_ONLY|SUF_Q|SUF_Z, ONLY_64, CPU_SSE2, 0, 0, {0, 0, 0}, 64, 0, 0x66, 2, {0x0F, 0x7E, 0}, 0, 2, 182 } +}; + +static const x86_insn_info movabs_insn[] = { + { SUF_B|SUF_Z, ONLY_64, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 1, {0xA0, 0, 0}, 0, 2, 341 }, + { SUF_W|SUF_Z, ONLY_64, 0, 0, 0, {0, 0, 0}, 16, 0, 0, 1, {0xA1, 0, 0}, 0, 2, 343 }, + { SUF_L|SUF_Z, ONLY_64, 0, 0, 0, {0, 0, 0}, 32, 0, 0, 1, {0xA1, 0, 0}, 0, 2, 345 }, + { SUF_Q|SUF_Z, ONLY_64, 0, 0, 0, {0, 0, 0}, 64, 0, 0, 1, {0xA1, 0, 0}, 0, 2, 347 }, + { SUF_B|SUF_Z, ONLY_64, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 1, {0xA2, 0, 0}, 0, 2, 349 }, + { SUF_W|SUF_Z, ONLY_64, 0, 0, 0, {0, 0, 0}, 16, 0, 0, 1, {0xA3, 0, 0}, 0, 2, 351 }, + { SUF_L|SUF_Z, ONLY_64, 0, 0, 0, {0, 0, 0}, 32, 0, 0, 1, {0xA3, 0, 0}, 0, 2, 353 }, + { SUF_Q|SUF_Z, ONLY_64, 0, 0, 0, {0, 0, 0}, 64, 0, 0, 1, {0xA3, 0, 0}, 0, 2, 355 }, + { SUF_Q|SUF_Z, ONLY_64, 0, 0, 0, {0, 0, 0}, 64, 0, 0, 1, {0xB8, 0, 0}, 0, 2, 357 } +}; + +static const x86_insn_info movszx_insn[] = { + { SUF_B|SUF_Z, 0, CPU_386, 0, 0, {MOD_Op1Add, 0, 0}, 16, 0, 0, 2, {0x0F, 0x00, 0}, 0, 2, 603 }, + { SUF_B|SUF_Z, 0, CPU_386, 0, 0, {MOD_Op1Add, 0, 0}, 32, 0, 0, 2, {0x0F, 0x00, 0}, 0, 2, 537 }, + { SUF_B|SUF_Z, ONLY_64, 0, 0, 0, {MOD_Op1Add, 0, 0}, 64, 0, 0, 2, {0x0F, 0x00, 0}, 0, 2, 541 }, + { SUF_W|SUF_Z, 0, CPU_386, 0, 0, {MOD_Op1Add, 0, 0}, 32, 0, 0, 2, {0x0F, 0x01, 0}, 0, 2, 539 }, + { SUF_W|SUF_Z, ONLY_64, 0, 0, 0, {MOD_Op1Add, 0, 0}, 64, 0, 0, 2, {0x0F, 0x01, 0}, 0, 2, 605 } +}; + +static const x86_insn_info movsxd_insn[] = { + { SUF_L|SUF_Z, ONLY_64, 0, 0, 0, {0, 0, 0}, 64, 0, 0, 1, {0x63, 0, 0}, 0, 2, 647 } +}; + +static const x86_insn_info push_insn[] = { + { SUF_Z, 0, 0, 0, 0, {0, 0, 0}, 0, 64, 0, 1, {0x50, 0, 0}, 0, 1, 657 }, + { SUF_W|SUF_Z, 0, 0, 0, 0, {0, 0, 0}, 16, 64, 0, 1, {0x50, 0, 0}, 0, 1, 405 }, + { SUF_L|SUF_Z, NOT_64, CPU_386, 0, 0, {0, 0, 0}, 32, 0, 0, 1, {0x50, 0, 0}, 0, 1, 407 }, + { SUF_Q|SUF_Z, ONLY_64, 0, 0, 0, {0, 0, 0}, 0, 64, 0, 1, {0x50, 0, 0}, 0, 1, 357 }, + { SUF_Z, 0, 0, 0, 0, {0, 0, 0}, 0, 64, 0, 1, {0xFF, 0, 0}, 6, 1, 658 }, + { SUF_W|SUF_Z, 0, 0, 0, 0, {0, 0, 0}, 16, 64, 0, 1, {0xFF, 0, 0}, 6, 1, 287 }, + { SUF_L|SUF_Z, NOT_64, CPU_386, 0, 0, {0, 0, 0}, 32, 0, 0, 1, {0xFF, 0, 0}, 6, 1, 283 }, + { SUF_Q|SUF_Z, ONLY_64, 0, 0, 0, {0, 0, 0}, 0, 64, 0, 1, {0xFF, 0, 0}, 6, 1, 286 }, + { GAS_ILLEGAL|SUF_Z, 0, CPU_186, 0, 0, {0, 0, 0}, 0, 64, 0, 1, {0x6A, 0, 0}, 0, 1, 100 }, + { GAS_ONLY|SUF_Z, 0, CPU_186, 0, 0, {0, 0, 0}, 0, 64, 0, 1, {0x6A, 0, 0}, 0, 1, 702 }, + { SUF_Q|SUF_Z, ONLY_64, 0, 0, 0, {0, 0, 0}, 64, 64, 0, 1, {0x6A, 0x68, 0}, 0, 1, 112 }, + { GAS_ILLEGAL|SUF_Z, NOT_64, CPU_186, 0, 0, {0, 0, 0}, 0, 0, 0, 1, {0x6A, 0x68, 0}, 0, 1, 703 }, + { SUF_W|SUF_Z, 0, CPU_186, 0, 0, {0, 0, 0}, 16, 64, 0, 1, {0x6A, 0x68, 0}, 0, 1, 574 }, + { SUF_L|SUF_Z, NOT_64, CPU_386, 0, 0, {0, 0, 0}, 32, 0, 0, 1, {0x6A, 0x68, 0}, 0, 1, 576 }, + { GAS_ILLEGAL|SUF_Z, 0, CPU_186, 0, 0, {0, 0, 0}, 16, 64, 0, 1, {0x68, 0, 0}, 0, 1, 416 }, + { GAS_ILLEGAL|SUF_Z, NOT_64, CPU_386, 0, 0, {0, 0, 0}, 32, 0, 0, 1, {0x68, 0, 0}, 0, 1, 418 }, + { GAS_ILLEGAL|SUF_Z, ONLY_64, 0, 0, 0, {0, 0, 0}, 64, 64, 0, 1, {0x68, 0, 0}, 0, 1, 704 }, + { SUF_Z, NOT_64, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 1, {0x0E, 0, 0}, 0, 1, 705 }, + { SUF_W|SUF_Z, NOT_64, 0, 0, 0, {0, 0, 0}, 16, 0, 0, 1, {0x0E, 0, 0}, 0, 1, 706 }, + { SUF_L|SUF_Z, NOT_64, CPU_386, 0, 0, {0, 0, 0}, 32, 0, 0, 1, {0x0E, 0, 0}, 0, 1, 707 }, + { SUF_Z, NOT_64, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 1, {0x16, 0, 0}, 0, 1, 659 }, + { SUF_W|SUF_Z, NOT_64, 0, 0, 0, {0, 0, 0}, 16, 0, 0, 1, {0x16, 0, 0}, 0, 1, 660 }, + { SUF_L|SUF_Z, NOT_64, CPU_386, 0, 0, {0, 0, 0}, 32, 0, 0, 1, {0x16, 0, 0}, 0, 1, 661 }, + { SUF_Z, NOT_64, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 1, {0x1E, 0, 0}, 0, 1, 662 }, + { SUF_W|SUF_Z, NOT_64, 0, 0, 0, {0, 0, 0}, 16, 0, 0, 1, {0x1E, 0, 0}, 0, 1, 663 }, + { SUF_L|SUF_Z, NOT_64, CPU_386, 0, 0, {0, 0, 0}, 32, 0, 0, 1, {0x1E, 0, 0}, 0, 1, 664 }, + { SUF_Z, NOT_64, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 1, {0x06, 0, 0}, 0, 1, 665 }, + { SUF_W|SUF_Z, NOT_64, 0, 0, 0, {0, 0, 0}, 16, 0, 0, 1, {0x06, 0, 0}, 0, 1, 666 }, + { SUF_L|SUF_Z, NOT_64, CPU_386, 0, 0, {0, 0, 0}, 32, 0, 0, 1, {0x06, 0, 0}, 0, 1, 667 }, + { SUF_Z, 0, CPU_386, 0, 0, {0, 0, 0}, 0, 0, 0, 2, {0x0F, 0xA0, 0}, 0, 1, 668 }, + { SUF_W|SUF_Z, 0, CPU_386, 0, 0, {0, 0, 0}, 16, 0, 0, 2, {0x0F, 0xA0, 0}, 0, 1, 669 }, + { SUF_L|SUF_Z, 0, CPU_386, 0, 0, {0, 0, 0}, 32, 0, 0, 2, {0x0F, 0xA0, 0}, 0, 1, 670 }, + { SUF_Z, 0, CPU_386, 0, 0, {0, 0, 0}, 0, 0, 0, 2, {0x0F, 0xA8, 0}, 0, 1, 671 }, + { SUF_W|SUF_Z, 0, CPU_386, 0, 0, {0, 0, 0}, 16, 0, 0, 2, {0x0F, 0xA8, 0}, 0, 1, 672 }, + { SUF_L|SUF_Z, 0, CPU_386, 0, 0, {0, 0, 0}, 32, 0, 0, 2, {0x0F, 0xA8, 0}, 0, 1, 673 } +}; + +static const x86_insn_info pop_insn[] = { + { SUF_Z, 0, 0, 0, 0, {0, 0, 0}, 0, 64, 0, 1, {0x58, 0, 0}, 0, 1, 657 }, + { SUF_W|SUF_Z, 0, 0, 0, 0, {0, 0, 0}, 16, 64, 0, 1, {0x58, 0, 0}, 0, 1, 405 }, + { SUF_L|SUF_Z, NOT_64, CPU_386, 0, 0, {0, 0, 0}, 32, 0, 0, 1, {0x58, 0, 0}, 0, 1, 407 }, + { SUF_Q|SUF_Z, ONLY_64, 0, 0, 0, {0, 0, 0}, 0, 64, 0, 1, {0x58, 0, 0}, 0, 1, 357 }, + { SUF_Z, 0, 0, 0, 0, {0, 0, 0}, 0, 64, 0, 1, {0x8F, 0, 0}, 0, 1, 658 }, + { SUF_W|SUF_Z, 0, 0, 0, 0, {0, 0, 0}, 16, 64, 0, 1, {0x8F, 0, 0}, 0, 1, 287 }, + { SUF_L|SUF_Z, NOT_64, CPU_386, 0, 0, {0, 0, 0}, 32, 0, 0, 1, {0x8F, 0, 0}, 0, 1, 283 }, + { SUF_Q|SUF_Z, ONLY_64, 0, 0, 0, {0, 0, 0}, 0, 64, 0, 1, {0x8F, 0, 0}, 0, 1, 286 }, + { SUF_Z, NOT_64, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 1, {0x17, 0, 0}, 0, 1, 659 }, + { SUF_Z, NOT_64, 0, 0, 0, {0, 0, 0}, 16, 0, 0, 1, {0x17, 0, 0}, 0, 1, 660 }, + { SUF_Z, NOT_64, CPU_386, 0, 0, {0, 0, 0}, 32, 0, 0, 1, {0x17, 0, 0}, 0, 1, 661 }, + { SUF_Z, NOT_64, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 1, {0x1F, 0, 0}, 0, 1, 662 }, + { SUF_Z, NOT_64, 0, 0, 0, {0, 0, 0}, 16, 0, 0, 1, {0x1F, 0, 0}, 0, 1, 663 }, + { SUF_Z, NOT_64, CPU_386, 0, 0, {0, 0, 0}, 32, 0, 0, 1, {0x1F, 0, 0}, 0, 1, 664 }, + { SUF_Z, NOT_64, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 1, {0x07, 0, 0}, 0, 1, 665 }, + { SUF_Z, NOT_64, 0, 0, 0, {0, 0, 0}, 16, 0, 0, 1, {0x07, 0, 0}, 0, 1, 666 }, + { SUF_Z, NOT_64, CPU_386, 0, 0, {0, 0, 0}, 32, 0, 0, 1, {0x07, 0, 0}, 0, 1, 667 }, + { SUF_Z, 0, CPU_386, 0, 0, {0, 0, 0}, 0, 0, 0, 2, {0x0F, 0xA1, 0}, 0, 1, 668 }, + { SUF_Z, 0, CPU_386, 0, 0, {0, 0, 0}, 16, 0, 0, 2, {0x0F, 0xA1, 0}, 0, 1, 669 }, + { SUF_Z, 0, CPU_386, 0, 0, {0, 0, 0}, 32, 0, 0, 2, {0x0F, 0xA1, 0}, 0, 1, 670 }, + { SUF_Z, 0, CPU_386, 0, 0, {0, 0, 0}, 0, 0, 0, 2, {0x0F, 0xA9, 0}, 0, 1, 671 }, + { SUF_Z, 0, CPU_386, 0, 0, {0, 0, 0}, 16, 0, 0, 2, {0x0F, 0xA9, 0}, 0, 1, 672 }, + { SUF_Z, 0, CPU_386, 0, 0, {0, 0, 0}, 32, 0, 0, 2, {0x0F, 0xA9, 0}, 0, 1, 673 } +}; + +static const x86_insn_info xchg_insn[] = { + { SUF_B|SUF_Z, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 1, {0x86, 0, 0}, 0, 2, 323 }, + { SUF_B|SUF_Z, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 1, {0x86, 0, 0}, 0, 2, 325 }, + { SUF_W|SUF_Z, 0, 0, 0, 0, {0, 0, 0}, 16, 0, 0, 1, {0x90, 0, 0}, 0, 2, 517 }, + { SUF_W|SUF_Z, 0, 0, 0, 0, {0, 0, 0}, 16, 0, 0, 1, {0x90, 0, 0}, 0, 2, 519 }, + { SUF_W|SUF_Z, 0, 0, 0, 0, {0, 0, 0}, 16, 0, 0, 1, {0x87, 0, 0}, 0, 2, 260 }, + { SUF_W|SUF_Z, 0, 0, 0, 0, {0, 0, 0}, 16, 0, 0, 1, {0x87, 0, 0}, 0, 2, 98 }, + { SUF_L|SUF_Z, ONLY_64, 0, 0, 0, {0, 0, 0}, 32, 0, 0, 1, {0x87, 0, 0}, 0, 2, 521 }, + { SUF_L|SUF_Z, 0, CPU_386, 0, 0, {0, 0, 0}, 32, 0, 0, 1, {0x90, 0, 0}, 0, 2, 523 }, + { SUF_L|SUF_Z, 0, CPU_386, 0, 0, {0, 0, 0}, 32, 0, 0, 1, {0x90, 0, 0}, 0, 2, 525 }, + { SUF_L|SUF_Z, 0, CPU_386, 0, 0, {0, 0, 0}, 32, 0, 0, 1, {0x87, 0, 0}, 0, 2, 266 }, + { SUF_L|SUF_Z, 0, CPU_386, 0, 0, {0, 0, 0}, 32, 0, 0, 1, {0x87, 0, 0}, 0, 2, 101 }, + { SUF_Q|SUF_Z, ONLY_64, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 1, {0x90, 0, 0}, 0, 2, 527 }, + { SUF_Q|SUF_Z, ONLY_64, 0, 0, 0, {0, 0, 0}, 64, 0, 0, 1, {0x90, 0, 0}, 0, 2, 356 }, + { SUF_Q|SUF_Z, ONLY_64, 0, 0, 0, {0, 0, 0}, 64, 0, 0, 1, {0x90, 0, 0}, 0, 2, 529 }, + { SUF_Q|SUF_Z, ONLY_64, 0, 0, 0, {0, 0, 0}, 64, 0, 0, 1, {0x87, 0, 0}, 0, 2, 272 }, + { SUF_Q|SUF_Z, ONLY_64, 0, 0, 0, {0, 0, 0}, 64, 0, 0, 1, {0x87, 0, 0}, 0, 2, 104 } +}; + +static const x86_insn_info in_insn[] = { + { SUF_B|SUF_Z, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 1, {0xE4, 0, 0}, 0, 2, 498 }, + { SUF_W|SUF_Z, 0, 0, 0, 0, {0, 0, 0}, 16, 0, 0, 1, {0xE5, 0, 0}, 0, 2, 500 }, + { SUF_L|SUF_Z, 0, CPU_386, 0, 0, {0, 0, 0}, 32, 0, 0, 1, {0xE5, 0, 0}, 0, 2, 617 }, + { SUF_B|SUF_Z, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 1, {0xEC, 0, 0}, 0, 2, 504 }, + { SUF_W|SUF_Z, 0, 0, 0, 0, {0, 0, 0}, 16, 0, 0, 1, {0xED, 0, 0}, 0, 2, 506 }, + { SUF_L|SUF_Z, 0, CPU_386, 0, 0, {0, 0, 0}, 32, 0, 0, 1, {0xED, 0, 0}, 0, 2, 502 }, + { GAS_ONLY|SUF_B|SUF_Z, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 1, {0xE4, 0, 0}, 0, 1, 3 }, + { GAS_ONLY|SUF_W|SUF_Z, 0, 0, 0, 0, {0, 0, 0}, 16, 0, 0, 1, {0xE5, 0, 0}, 0, 1, 3 }, + { GAS_ONLY|SUF_L|SUF_Z, 0, CPU_386, 0, 0, {0, 0, 0}, 32, 0, 0, 1, {0xE5, 0, 0}, 0, 1, 3 }, + { GAS_ONLY|SUF_B|SUF_Z, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 1, {0xEC, 0, 0}, 0, 1, 503 }, + { GAS_ONLY|SUF_W|SUF_Z, 0, 0, 0, 0, {0, 0, 0}, 16, 0, 0, 1, {0xED, 0, 0}, 0, 1, 503 }, + { GAS_ONLY|SUF_L|SUF_Z, 0, CPU_386, 0, 0, {0, 0, 0}, 32, 0, 0, 1, {0xED, 0, 0}, 0, 1, 503 } +}; + +static const x86_insn_info out_insn[] = { + { SUF_B|SUF_Z, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 1, {0xE6, 0, 0}, 0, 2, 497 }, + { SUF_W|SUF_Z, 0, 0, 0, 0, {0, 0, 0}, 16, 0, 0, 1, {0xE7, 0, 0}, 0, 2, 499 }, + { SUF_L|SUF_Z, 0, CPU_386, 0, 0, {0, 0, 0}, 32, 0, 0, 1, {0xE7, 0, 0}, 0, 2, 501 }, + { SUF_B|SUF_Z, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 1, {0xEE, 0, 0}, 0, 2, 503 }, + { SUF_W|SUF_Z, 0, 0, 0, 0, {0, 0, 0}, 16, 0, 0, 1, {0xEF, 0, 0}, 0, 2, 505 }, + { SUF_L|SUF_Z, 0, CPU_386, 0, 0, {0, 0, 0}, 32, 0, 0, 1, {0xEF, 0, 0}, 0, 2, 507 }, + { GAS_ONLY|SUF_B|SUF_Z, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 1, {0xE6, 0, 0}, 0, 1, 3 }, + { GAS_ONLY|SUF_W|SUF_Z, 0, 0, 0, 0, {0, 0, 0}, 16, 0, 0, 1, {0xE7, 0, 0}, 0, 1, 3 }, + { GAS_ONLY|SUF_L|SUF_Z, 0, CPU_386, 0, 0, {0, 0, 0}, 32, 0, 0, 1, {0xE7, 0, 0}, 0, 1, 3 }, + { GAS_ONLY|SUF_B|SUF_Z, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 1, {0xEE, 0, 0}, 0, 1, 503 }, + { GAS_ONLY|SUF_W|SUF_Z, 0, 0, 0, 0, {0, 0, 0}, 16, 0, 0, 1, {0xEF, 0, 0}, 0, 1, 503 }, + { GAS_ONLY|SUF_L|SUF_Z, 0, CPU_386, 0, 0, {0, 0, 0}, 32, 0, 0, 1, {0xEF, 0, 0}, 0, 1, 503 } +}; + +static const x86_insn_info lea_insn[] = { + { SUF_W|SUF_Z, 0, 0, 0, 0, {0, 0, 0}, 16, 0, 0, 1, {0x8D, 0, 0}, 0, 2, 531 }, + { SUF_L|SUF_Z, 0, CPU_386, 0, 0, {0, 0, 0}, 32, 0, 0, 1, {0x8D, 0, 0}, 0, 2, 533 }, + { SUF_Q|SUF_Z, ONLY_64, 0, 0, 0, {0, 0, 0}, 64, 0, 0, 1, {0x8D, 0, 0}, 0, 2, 535 } +}; + +static const x86_insn_info ldes_insn[] = { + { SUF_W|SUF_Z, NOT_64, 0, 0, 0, {MOD_Op0Add, 0, 0}, 16, 0, 0, 1, {0x00, 0, 0}, 0, 2, 531 }, + { SUF_L|SUF_Z, NOT_64, CPU_386, 0, 0, {MOD_Op0Add, 0, 0}, 32, 0, 0, 1, {0x00, 0, 0}, 0, 2, 533 } +}; + +static const x86_insn_info lfgss_insn[] = { + { SUF_W|SUF_Z, 0, CPU_386, 0, 0, {MOD_Op1Add, 0, 0}, 16, 0, 0, 2, {0x0F, 0x00, 0}, 0, 2, 531 }, + { SUF_L|SUF_Z, 0, CPU_386, 0, 0, {MOD_Op1Add, 0, 0}, 32, 0, 0, 2, {0x0F, 0x00, 0}, 0, 2, 533 }, + { SUF_Q|SUF_Z, ONLY_64, CPU_386, 0, 0, {MOD_Op1Add, 0, 0}, 64, 0, 0, 2, {0x0F, 0x00, 0}, 0, 2, 535 } +}; + +static const x86_insn_info arith_insn[] = { + { SUF_B|SUF_Z, 0, 0, 0, 0, {MOD_Op0Add, 0, 0}, 0, 0, 0, 1, {0x04, 0, 0}, 0, 2, 498 }, + { SUF_W|SUF_Z, 0, 0, 0, 0, {MOD_Op2Add, MOD_Op1AddSp, 0}, 16, 0, 0, 2, {0x83, 0xC0, 0x05}, 0, 2, 573 }, + { SUF_L|SUF_Z, 0, CPU_386, 0, 0, {MOD_Op2Add, MOD_Op1AddSp, 0}, 32, 0, 0, 2, {0x83, 0xC0, 0x05}, 0, 2, 575 }, + { SUF_Q|SUF_Z, ONLY_64, 0, 0, 0, {MOD_Op2Add, MOD_Op1AddSp, 0}, 64, 0, 0, 2, {0x83, 0xC0, 0x05}, 0, 2, 577 }, + { SUF_B|SUF_Z, 0, 0, 0, 0, {MOD_Gap, MOD_SpAdd, 0}, 0, 0, 0, 1, {0x80, 0, 0}, 0, 2, 421 }, + { SUF_B|SUF_Z, 0, 0, 0, 0, {MOD_Gap, MOD_SpAdd, 0}, 0, 0, 0, 1, {0x80, 0, 0}, 0, 2, 413 }, + { SUF_W|SUF_Z, 0, 0, 0, 0, {MOD_Gap, MOD_SpAdd, 0}, 16, 0, 0, 1, {0x83, 0, 0}, 0, 2, 579 }, + { GAS_ILLEGAL|SUF_Z, 0, 0, 0, 0, {MOD_Gap, MOD_SpAdd, 0}, 16, 0, 0, 1, {0x83, 0x81, 0}, 0, 2, 581 }, + { SUF_W|SUF_Z, 0, 0, 0, 0, {MOD_Gap, MOD_SpAdd, 0}, 16, 0, 0, 1, {0x83, 0x81, 0}, 0, 2, 583 }, + { SUF_L|SUF_Z, 0, CPU_386, 0, 0, {MOD_Gap, MOD_SpAdd, 0}, 32, 0, 0, 1, {0x83, 0, 0}, 0, 2, 585 }, + { GAS_ILLEGAL|SUF_Z, NOT_64, CPU_386, 0, 0, {MOD_Gap, MOD_SpAdd, 0}, 32, 0, 0, 1, {0x83, 0x81, 0}, 0, 2, 587 }, + { SUF_L|SUF_Z, 0, CPU_386, 0, 0, {MOD_Gap, MOD_SpAdd, 0}, 32, 0, 0, 1, {0x83, 0x81, 0}, 0, 2, 589 }, + { SUF_Q|SUF_Z, ONLY_64, 0, 0, 0, {MOD_Gap, MOD_SpAdd, 0}, 64, 0, 0, 1, {0x83, 0, 0}, 0, 2, 591 }, + { SUF_Q|SUF_Z, ONLY_64, 0, 0, 0, {MOD_Gap, MOD_SpAdd, 0}, 64, 0, 0, 1, {0x83, 0x81, 0}, 0, 2, 593 }, + { SUF_B|SUF_Z, 0, 0, 0, 0, {MOD_Op0Add, 0, 0}, 0, 0, 0, 1, {0x00, 0, 0}, 0, 2, 323 }, + { SUF_W|SUF_Z, 0, 0, 0, 0, {MOD_Op0Add, 0, 0}, 16, 0, 0, 1, {0x01, 0, 0}, 0, 2, 260 }, + { SUF_L|SUF_Z, 0, CPU_386, 0, 0, {MOD_Op0Add, 0, 0}, 32, 0, 0, 1, {0x01, 0, 0}, 0, 2, 266 }, + { SUF_Q|SUF_Z, ONLY_64, 0, 0, 0, {MOD_Op0Add, 0, 0}, 64, 0, 0, 1, {0x01, 0, 0}, 0, 2, 272 }, + { SUF_B|SUF_Z, 0, 0, 0, 0, {MOD_Op0Add, 0, 0}, 0, 0, 0, 1, {0x02, 0, 0}, 0, 2, 325 }, + { SUF_W|SUF_Z, 0, 0, 0, 0, {MOD_Op0Add, 0, 0}, 16, 0, 0, 1, {0x03, 0, 0}, 0, 2, 98 }, + { SUF_L|SUF_Z, 0, CPU_386, 0, 0, {MOD_Op0Add, 0, 0}, 32, 0, 0, 1, {0x03, 0, 0}, 0, 2, 101 }, + { SUF_Q|SUF_Z, ONLY_64, 0, 0, 0, {MOD_Op0Add, 0, 0}, 64, 0, 0, 1, {0x03, 0, 0}, 0, 2, 104 } +}; + +static const x86_insn_info incdec_insn[] = { + { SUF_B|SUF_Z, 0, 0, 0, 0, {MOD_Gap, MOD_SpAdd, 0}, 0, 0, 0, 1, {0xFE, 0, 0}, 0, 1, 421 }, + { SUF_W|SUF_Z, NOT_64, 0, 0, 0, {MOD_Op0Add, 0, 0}, 16, 0, 0, 1, {0x00, 0, 0}, 0, 1, 405 }, + { SUF_W|SUF_Z, 0, 0, 0, 0, {MOD_Gap, MOD_SpAdd, 0}, 16, 0, 0, 1, {0xFF, 0, 0}, 0, 1, 287 }, + { SUF_L|SUF_Z, NOT_64, CPU_386, 0, 0, {MOD_Op0Add, 0, 0}, 32, 0, 0, 1, {0x00, 0, 0}, 0, 1, 407 }, + { SUF_L|SUF_Z, 0, CPU_386, 0, 0, {MOD_Gap, MOD_SpAdd, 0}, 32, 0, 0, 1, {0xFF, 0, 0}, 0, 1, 283 }, + { SUF_Q|SUF_Z, ONLY_64, 0, 0, 0, {MOD_Gap, MOD_SpAdd, 0}, 64, 0, 0, 1, {0xFF, 0, 0}, 0, 1, 286 } +}; + +static const x86_insn_info f6_insn[] = { + { SUF_B|SUF_Z, 0, 0, 0, 0, {MOD_SpAdd, 0, 0}, 0, 0, 0, 1, {0xF6, 0, 0}, 0, 1, 421 }, + { SUF_W|SUF_Z, 0, 0, 0, 0, {MOD_SpAdd, 0, 0}, 16, 0, 0, 1, {0xF7, 0, 0}, 0, 1, 287 }, + { SUF_L|SUF_Z, 0, CPU_386, 0, 0, {MOD_SpAdd, 0, 0}, 32, 0, 0, 1, {0xF7, 0, 0}, 0, 1, 283 }, + { SUF_Q|SUF_Z, ONLY_64, 0, 0, 0, {MOD_SpAdd, 0, 0}, 64, 0, 0, 1, {0xF7, 0, 0}, 0, 1, 286 } +}; + +static const x86_insn_info div_insn[] = { + { SUF_B|SUF_Z, 0, 0, 0, 0, {MOD_SpAdd, 0, 0}, 0, 0, 0, 1, {0xF6, 0, 0}, 0, 1, 421 }, + { SUF_W|SUF_Z, 0, 0, 0, 0, {MOD_SpAdd, 0, 0}, 16, 0, 0, 1, {0xF7, 0, 0}, 0, 1, 287 }, + { SUF_L|SUF_Z, 0, CPU_386, 0, 0, {MOD_SpAdd, 0, 0}, 32, 0, 0, 1, {0xF7, 0, 0}, 0, 1, 283 }, + { SUF_Q|SUF_Z, ONLY_64, 0, 0, 0, {MOD_SpAdd, 0, 0}, 64, 0, 0, 1, {0xF7, 0, 0}, 0, 1, 286 }, + { SUF_B|SUF_Z, 0, 0, 0, 0, {MOD_SpAdd, 0, 0}, 0, 0, 0, 1, {0xF6, 0, 0}, 0, 2, 471 }, + { SUF_W|SUF_Z, 0, 0, 0, 0, {MOD_SpAdd, 0, 0}, 16, 0, 0, 1, {0xF7, 0, 0}, 0, 2, 473 }, + { SUF_L|SUF_Z, 0, CPU_386, 0, 0, {MOD_SpAdd, 0, 0}, 32, 0, 0, 1, {0xF7, 0, 0}, 0, 2, 475 }, + { SUF_Q|SUF_Z, ONLY_64, 0, 0, 0, {MOD_SpAdd, 0, 0}, 64, 0, 0, 1, {0xF7, 0, 0}, 0, 2, 477 } +}; + +static const x86_insn_info test_insn[] = { + { SUF_B|SUF_Z, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 1, {0xA8, 0, 0}, 0, 2, 498 }, + { SUF_W|SUF_Z, 0, 0, 0, 0, {0, 0, 0}, 16, 0, 0, 1, {0xA9, 0, 0}, 0, 2, 623 }, + { SUF_L|SUF_Z, 0, CPU_386, 0, 0, {0, 0, 0}, 32, 0, 0, 1, {0xA9, 0, 0}, 0, 2, 625 }, + { SUF_Q|SUF_Z, ONLY_64, 0, 0, 0, {0, 0, 0}, 64, 0, 0, 1, {0xA9, 0, 0}, 0, 2, 627 }, + { SUF_B|SUF_Z, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 1, {0xF6, 0, 0}, 0, 2, 421 }, + { SUF_B|SUF_Z, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 1, {0xF6, 0, 0}, 0, 2, 413 }, + { SUF_W|SUF_Z, 0, 0, 0, 0, {0, 0, 0}, 16, 0, 0, 1, {0xF7, 0, 0}, 0, 2, 423 }, + { SUF_W|SUF_Z, 0, 0, 0, 0, {0, 0, 0}, 16, 0, 0, 1, {0xF7, 0, 0}, 0, 2, 415 }, + { SUF_L|SUF_Z, 0, CPU_386, 0, 0, {0, 0, 0}, 32, 0, 0, 1, {0xF7, 0, 0}, 0, 2, 425 }, + { SUF_L|SUF_Z, 0, CPU_386, 0, 0, {0, 0, 0}, 32, 0, 0, 1, {0xF7, 0, 0}, 0, 2, 417 }, + { SUF_Q|SUF_Z, ONLY_64, 0, 0, 0, {0, 0, 0}, 64, 0, 0, 1, {0xF7, 0, 0}, 0, 2, 427 }, + { SUF_Q|SUF_Z, ONLY_64, 0, 0, 0, {0, 0, 0}, 64, 0, 0, 1, {0xF7, 0, 0}, 0, 2, 419 }, + { SUF_B|SUF_Z, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 1, {0x84, 0, 0}, 0, 2, 323 }, + { SUF_W|SUF_Z, 0, 0, 0, 0, {0, 0, 0}, 16, 0, 0, 1, {0x85, 0, 0}, 0, 2, 260 }, + { SUF_L|SUF_Z, 0, CPU_386, 0, 0, {0, 0, 0}, 32, 0, 0, 1, {0x85, 0, 0}, 0, 2, 266 }, + { SUF_Q|SUF_Z, ONLY_64, 0, 0, 0, {0, 0, 0}, 64, 0, 0, 1, {0x85, 0, 0}, 0, 2, 272 }, + { SUF_B|SUF_Z, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 1, {0x84, 0, 0}, 0, 2, 325 }, + { SUF_W|SUF_Z, 0, 0, 0, 0, {0, 0, 0}, 16, 0, 0, 1, {0x85, 0, 0}, 0, 2, 98 }, + { SUF_L|SUF_Z, 0, CPU_386, 0, 0, {0, 0, 0}, 32, 0, 0, 1, {0x85, 0, 0}, 0, 2, 101 }, + { SUF_Q|SUF_Z, ONLY_64, 0, 0, 0, {0, 0, 0}, 64, 0, 0, 1, {0x85, 0, 0}, 0, 2, 104 } +}; + +static const x86_insn_info aadm_insn[] = { + { SUF_Z, 0, 0, 0, 0, {MOD_Op0Add, 0, 0}, 0, 0, 0, 2, {0xD4, 0x0A, 0}, 0, 0, 0 }, + { SUF_Z, 0, 0, 0, 0, {MOD_Op0Add, 0, 0}, 0, 0, 0, 1, {0xD4, 0, 0}, 0, 1, 3 } +}; + +static const x86_insn_info imul_insn[] = { + { SUF_B|SUF_Z, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 1, {0xF6, 0, 0}, 5, 1, 421 }, + { SUF_W|SUF_Z, 0, 0, 0, 0, {0, 0, 0}, 16, 0, 0, 1, {0xF7, 0, 0}, 5, 1, 287 }, + { SUF_L|SUF_Z, 0, CPU_386, 0, 0, {0, 0, 0}, 32, 0, 0, 1, {0xF7, 0, 0}, 5, 1, 283 }, + { SUF_Q|SUF_Z, ONLY_64, 0, 0, 0, {0, 0, 0}, 64, 0, 0, 1, {0xF7, 0, 0}, 5, 1, 286 }, + { SUF_W|SUF_Z, 0, CPU_386, 0, 0, {0, 0, 0}, 16, 0, 0, 2, {0x0F, 0xAF, 0}, 0, 2, 98 }, + { SUF_L|SUF_Z, 0, CPU_386, 0, 0, {0, 0, 0}, 32, 0, 0, 2, {0x0F, 0xAF, 0}, 0, 2, 101 }, + { SUF_Q|SUF_Z, ONLY_64, CPU_386, 0, 0, {0, 0, 0}, 64, 0, 0, 2, {0x0F, 0xAF, 0}, 0, 2, 104 }, + { SUF_W|SUF_Z, 0, CPU_186, 0, 0, {0, 0, 0}, 16, 0, 0, 1, {0x6B, 0, 0}, 0, 3, 98 }, + { SUF_L|SUF_Z, 0, CPU_386, 0, 0, {0, 0, 0}, 32, 0, 0, 1, {0x6B, 0, 0}, 0, 3, 101 }, + { SUF_Q|SUF_Z, ONLY_64, CPU_186, 0, 0, {0, 0, 0}, 64, 0, 0, 1, {0x6B, 0, 0}, 0, 3, 104 }, + { SUF_W|SUF_Z, 0, CPU_186, 0, 0, {0, 0, 0}, 16, 0, 0, 1, {0x6B, 0, 0}, 0, 2, 303 }, + { SUF_L|SUF_Z, 0, CPU_386, 0, 0, {0, 0, 0}, 32, 0, 0, 1, {0x6B, 0, 0}, 0, 2, 305 }, + { SUF_Q|SUF_Z, ONLY_64, CPU_186, 0, 0, {0, 0, 0}, 64, 0, 0, 1, {0x6B, 0, 0}, 0, 2, 307 }, + { SUF_W|SUF_Z, 0, CPU_186, 0, 0, {0, 0, 0}, 16, 0, 0, 1, {0x6B, 0x69, 0}, 0, 3, 107 }, + { SUF_L|SUF_Z, 0, CPU_386, 0, 0, {0, 0, 0}, 32, 0, 0, 1, {0x6B, 0x69, 0}, 0, 3, 110 }, + { SUF_Q|SUF_Z, ONLY_64, CPU_186, 0, 0, {0, 0, 0}, 64, 0, 0, 1, {0x6B, 0x69, 0}, 0, 3, 113 }, + { SUF_W|SUF_Z, 0, CPU_186, 0, 0, {0, 0, 0}, 16, 0, 0, 1, {0x6B, 0x69, 0}, 0, 2, 309 }, + { SUF_L|SUF_Z, 0, CPU_386, 0, 0, {0, 0, 0}, 32, 0, 0, 1, {0x6B, 0x69, 0}, 0, 2, 311 }, + { SUF_Q|SUF_Z, ONLY_64, CPU_186, 0, 0, {0, 0, 0}, 64, 0, 0, 1, {0x6B, 0x69, 0}, 0, 2, 313 } +}; + +static const x86_insn_info shift_insn[] = { + { SUF_B|SUF_Z, 0, 0, 0, 0, {MOD_SpAdd, 0, 0}, 0, 0, 0, 1, {0xD2, 0, 0}, 0, 2, 551 }, + { SUF_B|SUF_Z, 0, 0, 0, 0, {MOD_SpAdd, 0, 0}, 0, 0, 0, 1, {0xD0, 0, 0}, 0, 2, 553 }, + { SUF_B|SUF_Z, 0, CPU_186, 0, 0, {MOD_SpAdd, 0, 0}, 0, 0, 0, 1, {0xC0, 0, 0}, 0, 2, 421 }, + { SUF_W|SUF_Z, 0, 0, 0, 0, {MOD_SpAdd, 0, 0}, 16, 0, 0, 1, {0xD3, 0, 0}, 0, 2, 555 }, + { SUF_W|SUF_Z, 0, 0, 0, 0, {MOD_SpAdd, 0, 0}, 16, 0, 0, 1, {0xD1, 0, 0}, 0, 2, 557 }, + { SUF_W|SUF_Z, 0, CPU_186, 0, 0, {MOD_SpAdd, 0, 0}, 16, 0, 0, 1, {0xC1, 0, 0}, 0, 2, 287 }, + { SUF_L|SUF_Z, 0, CPU_386, 0, 0, {MOD_SpAdd, 0, 0}, 32, 0, 0, 1, {0xD3, 0, 0}, 0, 2, 559 }, + { SUF_L|SUF_Z, 0, CPU_386, 0, 0, {MOD_SpAdd, 0, 0}, 32, 0, 0, 1, {0xD1, 0, 0}, 0, 2, 561 }, + { SUF_L|SUF_Z, 0, CPU_386, 0, 0, {MOD_SpAdd, 0, 0}, 32, 0, 0, 1, {0xC1, 0, 0}, 0, 2, 289 }, + { SUF_Q|SUF_Z, ONLY_64, 0, 0, 0, {MOD_SpAdd, 0, 0}, 64, 0, 0, 1, {0xD3, 0, 0}, 0, 2, 563 }, + { SUF_Q|SUF_Z, ONLY_64, 0, 0, 0, {MOD_SpAdd, 0, 0}, 64, 0, 0, 1, {0xD1, 0, 0}, 0, 2, 565 }, + { SUF_Q|SUF_Z, ONLY_64, CPU_186, 0, 0, {MOD_SpAdd, 0, 0}, 64, 0, 0, 1, {0xC1, 0, 0}, 0, 2, 291 }, + { GAS_ONLY|SUF_B|SUF_Z, 0, 0, 0, 0, {MOD_SpAdd, 0, 0}, 0, 0, 0, 1, {0xD0, 0, 0}, 0, 1, 421 }, + { GAS_ONLY|SUF_W|SUF_Z, 0, 0, 0, 0, {MOD_SpAdd, 0, 0}, 16, 0, 0, 1, {0xD1, 0, 0}, 0, 1, 287 }, + { GAS_ONLY|SUF_L|SUF_Z, 0, CPU_386, 0, 0, {MOD_SpAdd, 0, 0}, 32, 0, 0, 1, {0xD1, 0, 0}, 0, 1, 283 }, + { GAS_ONLY|SUF_Q|SUF_Z, ONLY_64, 0, 0, 0, {MOD_SpAdd, 0, 0}, 64, 0, 0, 1, {0xD1, 0, 0}, 0, 1, 286 } +}; + +static const x86_insn_info shlrd_insn[] = { + { SUF_W|SUF_Z, 0, CPU_386, 0, 0, {MOD_Op1Add, 0, 0}, 16, 0, 0, 2, {0x0F, 0x00, 0}, 0, 3, 260 }, + { SUF_W|SUF_Z, 0, CPU_386, 0, 0, {MOD_Op1Add, 0, 0}, 16, 0, 0, 2, {0x0F, 0x01, 0}, 0, 3, 263 }, + { SUF_L|SUF_Z, 0, CPU_386, 0, 0, {MOD_Op1Add, 0, 0}, 32, 0, 0, 2, {0x0F, 0x00, 0}, 0, 3, 266 }, + { SUF_L|SUF_Z, 0, CPU_386, 0, 0, {MOD_Op1Add, 0, 0}, 32, 0, 0, 2, {0x0F, 0x01, 0}, 0, 3, 269 }, + { SUF_Q|SUF_Z, ONLY_64, CPU_386, 0, 0, {MOD_Op1Add, 0, 0}, 64, 0, 0, 2, {0x0F, 0x00, 0}, 0, 3, 272 }, + { SUF_Q|SUF_Z, ONLY_64, CPU_386, 0, 0, {MOD_Op1Add, 0, 0}, 64, 0, 0, 2, {0x0F, 0x01, 0}, 0, 3, 275 }, + { GAS_ONLY|SUF_W|SUF_Z, 0, CPU_386, 0, 0, {MOD_Op1Add, 0, 0}, 16, 0, 0, 2, {0x0F, 0x01, 0}, 0, 2, 260 }, + { GAS_ONLY|SUF_L|SUF_Z, 0, CPU_386, 0, 0, {MOD_Op1Add, 0, 0}, 32, 0, 0, 2, {0x0F, 0x01, 0}, 0, 2, 266 }, + { GAS_ONLY|SUF_Q|SUF_Z, ONLY_64, CPU_386, 0, 0, {MOD_Op1Add, 0, 0}, 64, 0, 0, 2, {0x0F, 0x01, 0}, 0, 2, 272 } +}; + +static const x86_insn_info call_insn[] = { + { SUF_Z, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 0, {0, 0, 0}, 0, 1, 675 }, + { SUF_W|SUF_Z, 0, 0, 0, 0, {0, 0, 0}, 16, 0, 0, 0, {0, 0, 0}, 0, 1, 676 }, + { SUF_L|SUF_Z, NOT_64, CPU_386, 0, 0, {0, 0, 0}, 32, 0, 0, 0, {0, 0, 0}, 0, 1, 677 }, + { SUF_L|SUF_Q|SUF_Z, ONLY_64, 0, 0, 0, {0, 0, 0}, 64, 0, 0, 0, {0, 0, 0}, 0, 1, 677 }, + { SUF_Z, NOT_64, 0, 0, 0, {0, 0, 0}, 16, 0, 0, 1, {0xE8, 0, 0}, 0, 1, 678 }, + { SUF_Z, NOT_64, CPU_386, 0, 0, {0, 0, 0}, 32, 0, 0, 1, {0xE8, 0, 0}, 0, 1, 679 }, + { SUF_Z, ONLY_64, 0, 0, 0, {0, 0, 0}, 64, 64, 0, 1, {0xE8, 0, 0}, 0, 1, 679 }, + { SUF_Z, 0, 0, 0, 0, {0, 0, 0}, 0, 64, 0, 1, {0xE8, 0, 0}, 0, 1, 680 }, + { SUF_W, 0, 0, 0, 0, {0, 0, 0}, 16, 0, 0, 1, {0xFF, 0, 0}, 2, 1, 287 }, + { SUF_L, NOT_64, CPU_386, 0, 0, {0, 0, 0}, 32, 0, 0, 1, {0xFF, 0, 0}, 2, 1, 283 }, + { SUF_Q, ONLY_64, 0, 0, 0, {0, 0, 0}, 64, 64, 0, 1, {0xFF, 0, 0}, 2, 1, 286 }, + { GAS_ONLY|SUF_Z, 0, 0, 0, 0, {0, 0, 0}, 0, 64, 0, 1, {0xFF, 0, 0}, 2, 1, 681 }, + { SUF_Z, 0, 0, 0, 0, {0, 0, 0}, 0, 64, 0, 1, {0xFF, 0, 0}, 2, 1, 674 }, + { GAS_ILLEGAL|SUF_Z, 0, 0, 0, 0, {0, 0, 0}, 16, 64, 0, 1, {0xFF, 0, 0}, 2, 1, 682 }, + { GAS_ILLEGAL|SUF_Z, NOT_64, CPU_386, 0, 0, {0, 0, 0}, 32, 0, 0, 1, {0xFF, 0, 0}, 2, 1, 683 }, + { GAS_ILLEGAL|SUF_Z, ONLY_64, 0, 0, 0, {0, 0, 0}, 64, 64, 0, 1, {0xFF, 0, 0}, 2, 1, 684 }, + { GAS_ILLEGAL|SUF_Z, 0, 0, 0, 0, {0, 0, 0}, 0, 64, 0, 1, {0xFF, 0, 0}, 2, 1, 685 }, + { GAS_ILLEGAL|SUF_Z, 0, 0, 0, 0, {0, 0, 0}, 16, 0, 0, 1, {0xFF, 0, 0}, 3, 1, 686 }, + { GAS_ILLEGAL|SUF_Z, 0, CPU_386, 0, 0, {0, 0, 0}, 32, 0, 0, 1, {0xFF, 0, 0}, 3, 1, 687 }, + { GAS_ILLEGAL|SUF_Z, ONLY_64, 0, 0, 0, {0, 0, 0}, 64, 0, 0, 1, {0xFF, 0, 0}, 3, 1, 688 }, + { GAS_ILLEGAL|SUF_Z, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 1, {0xFF, 0, 0}, 3, 1, 689 }, + { GAS_ILLEGAL|SUF_Z, NOT_64, 0, 0, 0, {0, 0, 0}, 16, 0, 0, 1, {0x9A, 0, 0}, 0, 1, 690 }, + { GAS_ILLEGAL|SUF_Z, NOT_64, CPU_386, 0, 0, {0, 0, 0}, 32, 0, 0, 1, {0x9A, 0, 0}, 0, 1, 691 }, + { GAS_ILLEGAL|SUF_Z, NOT_64, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 1, {0x9A, 0, 0}, 0, 1, 692 }, + { GAS_ILLEGAL|SUF_Z, NOT_64, 0, 0, 0, {0, 0, 0}, 16, 0, 0, 1, {0x9A, 0, 0}, 0, 1, 693 }, + { GAS_ILLEGAL|SUF_Z, NOT_64, CPU_386, 0, 0, {0, 0, 0}, 32, 0, 0, 1, {0x9A, 0, 0}, 0, 1, 694 }, + { GAS_ILLEGAL|SUF_Z, NOT_64, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 1, {0x9A, 0, 0}, 0, 1, 695 }, + { GAS_ONLY|GAS_NO_REV|SUF_W, NOT_64, 0, 0, 0, {0, 0, 0}, 16, 0, 0, 1, {0x9A, 0, 0}, 0, 2, 567 }, + { GAS_ONLY|GAS_NO_REV|SUF_L, NOT_64, CPU_386, 0, 0, {0, 0, 0}, 32, 0, 0, 1, {0x9A, 0, 0}, 0, 2, 569 }, + { GAS_ONLY|GAS_NO_REV|SUF_Z, NOT_64, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 1, {0x9A, 0, 0}, 0, 2, 571 } +}; + +static const x86_insn_info jmp_insn[] = { + { SUF_Z, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 0, {0, 0, 0}, 0, 1, 675 }, + { SUF_W|SUF_Z, 0, 0, 0, 0, {0, 0, 0}, 16, 0, 0, 0, {0, 0, 0}, 0, 1, 676 }, + { SUF_L|SUF_Z, NOT_64, CPU_386, 0, 0, {0, 0, 0}, 32, 0, 0, 1, {0x00, 0, 0}, 0, 1, 677 }, + { SUF_L|SUF_Q|SUF_Z, ONLY_64, 0, 0, 0, {0, 0, 0}, 64, 0, 0, 1, {0x00, 0, 0}, 0, 1, 677 }, + { SUF_Z, 0, 0, 0, 0, {0, 0, 0}, 0, 64, 0, 1, {0xEB, 0, 0}, 0, 1, 483 }, + { SUF_Z, 0, 0, 0, 0, {0, 0, 0}, 16, 64, 0, 1, {0xE9, 0, 0}, 0, 1, 678 }, + { SUF_Z, NOT_64, CPU_386, 0, 0, {0, 0, 0}, 32, 0, 0, 1, {0xE9, 0, 0}, 0, 1, 679 }, + { SUF_Z, ONLY_64, 0, 0, 0, {0, 0, 0}, 64, 64, 0, 1, {0xE9, 0, 0}, 0, 1, 679 }, + { SUF_Z, 0, 0, 0, 0, {0, 0, 0}, 0, 64, 0, 1, {0xE9, 0, 0}, 0, 1, 680 }, + { SUF_W, 0, 0, 0, 0, {0, 0, 0}, 16, 64, 0, 1, {0xFF, 0, 0}, 4, 1, 287 }, + { SUF_L, NOT_64, CPU_386, 0, 0, {0, 0, 0}, 32, 0, 0, 1, {0xFF, 0, 0}, 4, 1, 283 }, + { SUF_Q, ONLY_64, 0, 0, 0, {0, 0, 0}, 64, 64, 0, 1, {0xFF, 0, 0}, 4, 1, 286 }, + { GAS_ONLY|SUF_Z, 0, 0, 0, 0, {0, 0, 0}, 0, 64, 0, 1, {0xFF, 0, 0}, 4, 1, 681 }, + { SUF_Z, 0, 0, 0, 0, {0, 0, 0}, 0, 64, 0, 1, {0xFF, 0, 0}, 4, 1, 674 }, + { GAS_ILLEGAL|SUF_Z, 0, 0, 0, 0, {0, 0, 0}, 16, 64, 0, 1, {0xFF, 0, 0}, 4, 1, 682 }, + { GAS_ILLEGAL|SUF_Z, NOT_64, CPU_386, 0, 0, {0, 0, 0}, 32, 0, 0, 1, {0xFF, 0, 0}, 4, 1, 683 }, + { GAS_ILLEGAL|SUF_Z, ONLY_64, 0, 0, 0, {0, 0, 0}, 64, 64, 0, 1, {0xFF, 0, 0}, 4, 1, 684 }, + { GAS_ILLEGAL|SUF_Z, 0, 0, 0, 0, {0, 0, 0}, 0, 64, 0, 1, {0xFF, 0, 0}, 4, 1, 685 }, + { SUF_Z, 0, 0, 0, 0, {0, 0, 0}, 16, 0, 0, 1, {0xFF, 0, 0}, 5, 1, 686 }, + { SUF_Z, 0, CPU_386, 0, 0, {0, 0, 0}, 32, 0, 0, 1, {0xFF, 0, 0}, 5, 1, 687 }, + { SUF_Z, ONLY_64, 0, 0, 0, {0, 0, 0}, 64, 0, 0, 1, {0xFF, 0, 0}, 5, 1, 688 }, + { SUF_Z, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 1, {0xFF, 0, 0}, 5, 1, 689 }, + { SUF_Z, NOT_64, 0, 0, 0, {0, 0, 0}, 16, 0, 0, 1, {0xEA, 0, 0}, 0, 1, 690 }, + { SUF_Z, NOT_64, CPU_386, 0, 0, {0, 0, 0}, 32, 0, 0, 1, {0xEA, 0, 0}, 0, 1, 691 }, + { SUF_Z, NOT_64, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 1, {0xEA, 0, 0}, 0, 1, 692 }, + { GAS_ILLEGAL|SUF_Z, NOT_64, 0, 0, 0, {0, 0, 0}, 16, 0, 0, 1, {0xEA, 0, 0}, 0, 1, 693 }, + { GAS_ILLEGAL|SUF_Z, NOT_64, CPU_386, 0, 0, {0, 0, 0}, 32, 0, 0, 1, {0xEA, 0, 0}, 0, 1, 694 }, + { GAS_ILLEGAL|SUF_Z, NOT_64, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 1, {0xEA, 0, 0}, 0, 1, 695 }, + { GAS_ONLY|GAS_NO_REV|SUF_W, NOT_64, 0, 0, 0, {0, 0, 0}, 16, 0, 0, 1, {0xEA, 0, 0}, 0, 2, 567 }, + { GAS_ONLY|GAS_NO_REV|SUF_L, NOT_64, CPU_386, 0, 0, {0, 0, 0}, 32, 0, 0, 1, {0xEA, 0, 0}, 0, 2, 569 }, + { GAS_ONLY|GAS_NO_REV|SUF_Z, NOT_64, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 1, {0xEA, 0, 0}, 0, 2, 571 } +}; + +static const x86_insn_info ljmpcall_insn[] = { + { SUF_W, 0, 0, 0, 0, {MOD_SpAdd, 0, 0}, 16, 0, 0, 1, {0xFF, 0, 0}, 0, 1, 34 }, + { SUF_L, 0, CPU_386, 0, 0, {MOD_SpAdd, 0, 0}, 32, 0, 0, 1, {0xFF, 0, 0}, 0, 1, 58 }, + { SUF_Q, ONLY_64, 0, 0, 0, {MOD_SpAdd, 0, 0}, 64, 0, 0, 1, {0xFF, 0, 0}, 0, 1, 6 }, + { SUF_Z, 0, 0, 0, 0, {MOD_SpAdd, 0, 0}, 0, 0, 0, 1, {0xFF, 0, 0}, 0, 1, 699 }, + { GAS_NO_REV|SUF_W, NOT_64, 0, 0, 0, {MOD_Gap, MOD_Op0Add, 0}, 16, 0, 0, 1, {0x00, 0, 0}, 0, 2, 567 }, + { GAS_NO_REV|SUF_L, NOT_64, CPU_386, 0, 0, {MOD_Gap, MOD_Op0Add, 0}, 32, 0, 0, 1, {0x00, 0, 0}, 0, 2, 569 }, + { GAS_NO_REV|SUF_Z, NOT_64, 0, 0, 0, {MOD_Gap, MOD_Op0Add, 0}, 0, 0, 0, 1, {0x00, 0, 0}, 0, 2, 571 } +}; + +static const x86_insn_info retnf_insn[] = { + { SUF_Z, NOT_64, 0, 0, 0, {MOD_Op0Add, 0, 0}, 0, 0, 0, 1, {0x01, 0, 0}, 0, 0, 0 }, + { SUF_Z, NOT_64, 0, 0, 0, {MOD_Op0Add, 0, 0}, 0, 0, 0, 1, {0x00, 0, 0}, 0, 1, 406 }, + { SUF_Z, ONLY_64, 0, 0, 0, {MOD_Op0Add, MOD_OpSizeR, 0}, 0, 0, 0, 1, {0x01, 0, 0}, 0, 0, 0 }, + { SUF_Z, ONLY_64, 0, 0, 0, {MOD_Op0Add, MOD_OpSizeR, 0}, 0, 0, 0, 1, {0x00, 0, 0}, 0, 1, 406 }, + { SUF_L|SUF_Q|SUF_W|SUF_Z, 0, 0, 0, 0, {MOD_Op0Add, MOD_OpSizeR, 0}, 0, 0, 0, 1, {0x01, 0, 0}, 0, 0, 0 }, + { SUF_L|SUF_Q|SUF_W|SUF_Z, 0, 0, 0, 0, {MOD_Op0Add, MOD_OpSizeR, 0}, 0, 0, 0, 1, {0x00, 0, 0}, 0, 1, 406 } +}; + +static const x86_insn_info enter_insn[] = { + { GAS_NO_REV|SUF_L|SUF_Z, NOT_64, CPU_186, 0, 0, {0, 0, 0}, 0, 0, 0, 1, {0xC8, 0, 0}, 0, 2, 645 }, + { GAS_NO_REV|SUF_Q|SUF_Z, ONLY_64, CPU_186, 0, 0, {0, 0, 0}, 64, 64, 0, 1, {0xC8, 0, 0}, 0, 2, 645 }, + { GAS_ONLY|GAS_NO_REV|SUF_W|SUF_Z, 0, CPU_186, 0, 0, {0, 0, 0}, 16, 0, 0, 1, {0xC8, 0, 0}, 0, 2, 645 } +}; + +static const x86_insn_info jcc_insn[] = { + { SUF_Z, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 0, {0, 0, 0}, 0, 1, 481 }, + { SUF_Z, 0, 0, 0, 0, {0, 0, 0}, 16, 0, 0, 0, {0, 0, 0}, 0, 1, 700 }, + { SUF_Z, NOT_64, CPU_386, 0, 0, {0, 0, 0}, 32, 0, 0, 0, {0, 0, 0}, 0, 1, 701 }, + { SUF_Z, ONLY_64, 0, 0, 0, {0, 0, 0}, 64, 0, 0, 0, {0, 0, 0}, 0, 1, 701 }, + { SUF_Z, 0, 0, 0, 0, {MOD_Op0Add, 0, 0}, 0, 64, 0, 1, {0x70, 0, 0}, 0, 1, 483 }, + { SUF_Z, 0, CPU_186, 0, 0, {MOD_Op1Add, 0, 0}, 16, 64, 0, 2, {0x0F, 0x80, 0}, 0, 1, 678 }, + { SUF_Z, NOT_64, CPU_386, 0, 0, {MOD_Op1Add, 0, 0}, 32, 0, 0, 2, {0x0F, 0x80, 0}, 0, 1, 679 }, + { SUF_Z, ONLY_64, 0, 0, 0, {MOD_Op1Add, 0, 0}, 64, 64, 0, 2, {0x0F, 0x80, 0}, 0, 1, 679 }, + { SUF_Z, 0, CPU_186, 0, 0, {MOD_Op1Add, 0, 0}, 0, 64, 0, 2, {0x0F, 0x80, 0}, 0, 1, 680 } +}; + +static const x86_insn_info jcxz_insn[] = { + { SUF_Z, 0, 0, 0, 0, {MOD_AdSizeR, 0, 0}, 0, 0, 0, 0, {0, 0, 0}, 0, 1, 481 }, + { SUF_Z, 0, 0, 0, 0, {MOD_AdSizeR, 0, 0}, 0, 64, 0, 1, {0xE3, 0, 0}, 0, 1, 483 } +}; + +static const x86_insn_info loop_insn[] = { + { SUF_Z, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 0, {0, 0, 0}, 0, 1, 481 }, + { SUF_Z, NOT_64, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 0, {0, 0, 0}, 0, 2, 493 }, + { SUF_Z, 0, CPU_386, 0, 0, {0, 0, 0}, 0, 64, 0, 0, {0, 0, 0}, 0, 2, 481 }, + { SUF_Z, ONLY_64, 0, 0, 0, {0, 0, 0}, 0, 64, 0, 0, {0, 0, 0}, 0, 2, 489 }, + { SUF_Z, NOT_64, 0, 0, 0, {MOD_Op0Add, 0, 0}, 0, 0, 0, 1, {0xE0, 0, 0}, 0, 1, 483 }, + { SUF_Z, 0, 0, 0, 0, {MOD_Op0Add, 0, 0}, 0, 64, 0, 1, {0xE0, 0, 0}, 0, 2, 495 }, + { SUF_Z, 0, CPU_386, 0, 0, {MOD_Op0Add, 0, 0}, 0, 64, 0, 1, {0xE0, 0, 0}, 0, 2, 483 }, + { SUF_Z, ONLY_64, 0, 0, 0, {MOD_Op0Add, 0, 0}, 0, 64, 0, 1, {0xE0, 0, 0}, 0, 2, 491 } +}; + +static const x86_insn_info loopw_insn[] = { + { SUF_Z, NOT_64, 0, 0, 0, {MOD_Gap, MOD_AdSizeR, 0}, 0, 64, 0, 0, {0, 0, 0}, 0, 1, 481 }, + { SUF_Z, NOT_64, 0, 0, 0, {MOD_Op0Add, MOD_AdSizeR, 0}, 0, 64, 0, 1, {0xE0, 0, 0}, 0, 1, 483 }, + { SUF_Z, NOT_64, 0, 0, 0, {0, 0, 0}, 0, 64, 0, 0, {0, 0, 0}, 0, 2, 493 }, + { SUF_Z, NOT_64, 0, 0, 0, {MOD_Op0Add, 0, 0}, 0, 64, 0, 1, {0xE0, 0, 0}, 0, 2, 495 } +}; + +static const x86_insn_info loopl_insn[] = { + { SUF_Z, 0, 0, 0, 0, {MOD_Gap, MOD_AdSizeR, 0}, 0, 64, 0, 0, {0, 0, 0}, 0, 1, 481 }, + { SUF_Z, 0, 0, 0, 0, {MOD_Op0Add, MOD_AdSizeR, 0}, 0, 64, 0, 1, {0xE0, 0, 0}, 0, 1, 483 }, + { SUF_Z, 0, CPU_386, 0, 0, {0, 0, 0}, 0, 64, 0, 0, {0, 0, 0}, 0, 2, 481 }, + { SUF_Z, 0, CPU_386, 0, 0, {MOD_Op0Add, 0, 0}, 0, 64, 0, 1, {0xE0, 0, 0}, 0, 2, 483 } +}; + +static const x86_insn_info loopq_insn[] = { + { SUF_Z, ONLY_64, 0, 0, 0, {MOD_Gap, MOD_AdSizeR, 0}, 0, 64, 0, 0, {0, 0, 0}, 0, 1, 481 }, + { SUF_Z, ONLY_64, 0, 0, 0, {MOD_Op0Add, MOD_AdSizeR, 0}, 0, 64, 0, 1, {0xE0, 0, 0}, 0, 1, 483 }, + { SUF_Z, ONLY_64, 0, 0, 0, {0, 0, 0}, 0, 64, 0, 0, {0, 0, 0}, 0, 2, 489 }, + { SUF_Z, ONLY_64, 0, 0, 0, {MOD_Op0Add, 0, 0}, 0, 64, 0, 1, {0xE0, 0, 0}, 0, 2, 491 } +}; + +static const x86_insn_info setcc_insn[] = { + { SUF_B|SUF_Z, 0, CPU_386, 0, 0, {MOD_Op1Add, 0, 0}, 0, 0, 0, 2, {0x0F, 0x90, 0}, 2, 1, 323 } +}; + +static const x86_insn_info cmpsd_insn[] = { + { GAS_ILLEGAL|SUF_Z, NOT_AVX, CPU_386, 0, 0, {0, 0, 0}, 32, 0, 0, 1, {0xA7, 0, 0}, 0, 0, 0 }, + { SUF_Z, 0, CPU_SSE2, 0, 0, {MOD_SetVEX, 0, 0}, 0, 0, 0xF2, 2, {0x0F, 0xC2, 0}, 0, 3, 92 }, + { SUF_Z, 0, CPU_SSE2, 0, 0, {MOD_SetVEX, 0, 0}, 0, 0, 0xF2, 2, {0x0F, 0xC2, 0}, 0, 3, 95 }, + { SUF_Z, ONLY_AVX, CPU_AVX, 0, 0, {0, 0, 0}, 0, 0, 0xC3, 2, {0x0F, 0xC2, 0}, 0, 4, 0 }, + { SUF_Z, ONLY_AVX, CPU_AVX, 0, 0, {0, 0, 0}, 0, 0, 0xC3, 2, {0x0F, 0xC2, 0}, 0, 4, 4 } +}; + +static const x86_insn_info movsd_insn[] = { + { SUF_Z, NOT_AVX, CPU_386, 0, 0, {0, 0, 0}, 32, 0, 0, 1, {0xA5, 0, 0}, 0, 0, 0 }, + { SUF_Z, 0, CPU_SSE2, 0, 0, {MOD_SetVEX, 0, 0}, 0, 0, 0xF2, 2, {0x0F, 0x10, 0}, 0, 2, 92 }, + { SUF_Z, 0, CPU_SSE2, 0, 0, {MOD_SetVEX, 0, 0}, 0, 0, 0xF2, 2, {0x0F, 0x10, 0}, 0, 2, 451 }, + { SUF_Z, 0, CPU_SSE2, 0, 0, {MOD_SetVEX, 0, 0}, 0, 0, 0xF2, 2, {0x0F, 0x11, 0}, 0, 2, 47 }, + { SUF_Z, ONLY_AVX, CPU_AVX, 0, 0, {0, 0, 0}, 0, 0, 0xC3, 2, {0x0F, 0x10, 0}, 0, 3, 0 } +}; + +static const x86_insn_info bittest_insn[] = { + { SUF_W|SUF_Z, 0, CPU_386, 0, 0, {MOD_Op1Add, 0, 0}, 16, 0, 0, 2, {0x0F, 0x00, 0}, 0, 2, 260 }, + { SUF_L|SUF_Z, 0, CPU_386, 0, 0, {MOD_Op1Add, 0, 0}, 32, 0, 0, 2, {0x0F, 0x00, 0}, 0, 2, 266 }, + { SUF_Q|SUF_Z, ONLY_64, CPU_386, 0, 0, {MOD_Op1Add, 0, 0}, 64, 0, 0, 2, {0x0F, 0x00, 0}, 0, 2, 272 }, + { SUF_W|SUF_Z, 0, CPU_386, 0, 0, {MOD_Gap, MOD_SpAdd, 0}, 16, 0, 0, 2, {0x0F, 0xBA, 0}, 0, 2, 287 }, + { SUF_L|SUF_Z, 0, CPU_386, 0, 0, {MOD_Gap, MOD_SpAdd, 0}, 32, 0, 0, 2, {0x0F, 0xBA, 0}, 0, 2, 289 }, + { SUF_Q|SUF_Z, ONLY_64, CPU_386, 0, 0, {MOD_Gap, MOD_SpAdd, 0}, 64, 0, 0, 2, {0x0F, 0xBA, 0}, 0, 2, 291 } +}; + +static const x86_insn_info bsfr_insn[] = { + { SUF_W|SUF_Z, 0, 0, 0, 0, {MOD_Op1Add, 0, 0}, 16, 0, 0, 2, {0x0F, 0x00, 0}, 0, 2, 98 }, + { SUF_L|SUF_Z, 0, CPU_386, 0, 0, {MOD_Op1Add, 0, 0}, 32, 0, 0, 2, {0x0F, 0x00, 0}, 0, 2, 101 }, + { SUF_Q|SUF_Z, ONLY_64, 0, 0, 0, {MOD_Op1Add, 0, 0}, 64, 0, 0, 2, {0x0F, 0x00, 0}, 0, 2, 104 } +}; + +static const x86_insn_info int_insn[] = { + { SUF_Z, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 1, {0xCD, 0, 0}, 0, 1, 3 } +}; + +static const x86_insn_info bound_insn[] = { + { SUF_W|SUF_Z, NOT_64, CPU_186, 0, 0, {0, 0, 0}, 16, 0, 0, 1, {0x62, 0, 0}, 0, 2, 465 }, + { SUF_L|SUF_Z, NOT_64, CPU_386, 0, 0, {0, 0, 0}, 32, 0, 0, 1, {0x62, 0, 0}, 0, 2, 359 } +}; + +static const x86_insn_info larlsl_insn[] = { + { SUF_W|SUF_Z, 0, 0, 0, 0, {MOD_Op1Add, 0, 0}, 16, 0, 0, 2, {0x0F, 0x00, 0}, 0, 2, 455 }, + { SUF_W|SUF_Z, 0, 0, 0, 0, {MOD_Op1Add, 0, 0}, 16, 0, 0, 2, {0x0F, 0x00, 0}, 0, 2, 98 }, + { SUF_L|SUF_Z, 0, CPU_386, 0, 0, {MOD_Op1Add, 0, 0}, 32, 0, 0, 2, {0x0F, 0x00, 0}, 0, 2, 457 }, + { SUF_L|SUF_Z, 0, CPU_386, 0, 0, {MOD_Op1Add, 0, 0}, 32, 0, 0, 2, {0x0F, 0x00, 0}, 0, 2, 459 }, + { SUF_Q|SUF_Z, ONLY_64, 0, 0, 0, {MOD_Op1Add, 0, 0}, 64, 0, 0, 2, {0x0F, 0x00, 0}, 0, 2, 461 }, + { SUF_Q|SUF_Z, ONLY_64, 0, 0, 0, {MOD_Op1Add, 0, 0}, 64, 0, 0, 2, {0x0F, 0x00, 0}, 0, 2, 463 } +}; + +static const x86_insn_info arpl_insn[] = { + { SUF_W|SUF_Z, NOT_64, CPU_286, CPU_Prot, 0, {0, 0, 0}, 0, 0, 0, 1, {0x63, 0, 0}, 0, 2, 260 } +}; + +static const x86_insn_info str_insn[] = { + { SUF_W|SUF_Z, 0, CPU_286, CPU_Prot, 0, {0, 0, 0}, 16, 0, 0, 2, {0x0F, 0x00, 0}, 1, 1, 395 }, + { SUF_L|SUF_Z, 0, CPU_386, CPU_Prot, 0, {0, 0, 0}, 32, 0, 0, 2, {0x0F, 0x00, 0}, 1, 1, 26 }, + { SUF_Q|SUF_Z, ONLY_64, CPU_286, CPU_Prot, 0, {0, 0, 0}, 64, 0, 0, 2, {0x0F, 0x00, 0}, 1, 1, 30 }, + { SUF_L|SUF_W|SUF_Z, 0, CPU_286, CPU_Prot, 0, {0, 0, 0}, 0, 0, 0, 2, {0x0F, 0x00, 0}, 1, 1, 99 } +}; + +static const x86_insn_info prot286_insn[] = { + { SUF_W|SUF_Z, 0, CPU_286, 0, 0, {MOD_SpAdd, MOD_Op1Add, 0}, 0, 0, 0, 2, {0x0F, 0x00, 0}, 0, 1, 99 } +}; + +static const x86_insn_info sldtmsw_insn[] = { + { SUF_W|SUF_Z, 0, CPU_286, 0, 0, {MOD_SpAdd, MOD_Op1Add, 0}, 0, 0, 0, 2, {0x0F, 0x00, 0}, 0, 1, 34 }, + { SUF_L|SUF_Z, 0, CPU_386, 0, 0, {MOD_SpAdd, MOD_Op1Add, 0}, 0, 0, 0, 2, {0x0F, 0x00, 0}, 0, 1, 58 }, + { SUF_Q|SUF_Z, ONLY_64, CPU_286, 0, 0, {MOD_SpAdd, MOD_Op1Add, 0}, 0, 0, 0, 2, {0x0F, 0x00, 0}, 0, 1, 6 }, + { SUF_W|SUF_Z, 0, CPU_286, 0, 0, {MOD_SpAdd, MOD_Op1Add, 0}, 16, 0, 0, 2, {0x0F, 0x00, 0}, 0, 1, 395 }, + { SUF_L|SUF_Z, 0, CPU_386, 0, 0, {MOD_SpAdd, MOD_Op1Add, 0}, 32, 0, 0, 2, {0x0F, 0x00, 0}, 0, 1, 26 }, + { SUF_Q|SUF_Z, ONLY_64, CPU_286, 0, 0, {MOD_SpAdd, MOD_Op1Add, 0}, 64, 0, 0, 2, {0x0F, 0x00, 0}, 0, 1, 30 } +}; + +static const x86_insn_info fld_insn[] = { + { SUF_S|SUF_Z, 0, CPU_FPU, 0, 0, {0, 0, 0}, 0, 0, 0, 1, {0xD9, 0, 0}, 0, 1, 654 }, + { SUF_L|SUF_Z, 0, CPU_FPU, 0, 0, {0, 0, 0}, 0, 0, 0, 1, {0xDD, 0, 0}, 0, 1, 212 }, + { SUF_Z, 0, CPU_FPU, 0, 0, {0, 0, 0}, 0, 0, 0, 1, {0xDB, 0, 0}, 5, 1, 656 }, + { SUF_Z, 0, CPU_FPU, 0, 0, {0, 0, 0}, 0, 0, 0, 2, {0xD9, 0xC0, 0}, 0, 1, 328 } +}; + +static const x86_insn_info fstp_insn[] = { + { SUF_S|SUF_Z, 0, CPU_FPU, 0, 0, {0, 0, 0}, 0, 0, 0, 1, {0xD9, 0, 0}, 3, 1, 654 }, + { SUF_L|SUF_Z, 0, CPU_FPU, 0, 0, {0, 0, 0}, 0, 0, 0, 1, {0xDD, 0, 0}, 3, 1, 212 }, + { SUF_Z, 0, CPU_FPU, 0, 0, {0, 0, 0}, 0, 0, 0, 1, {0xDB, 0, 0}, 7, 1, 656 }, + { SUF_Z, 0, CPU_FPU, 0, 0, {0, 0, 0}, 0, 0, 0, 2, {0xDD, 0xD8, 0}, 0, 1, 328 } +}; + +static const x86_insn_info fldstpt_insn[] = { + { SUF_Z, 0, CPU_FPU, 0, 0, {MOD_SpAdd, 0, 0}, 0, 0, 0, 1, {0xDB, 0, 0}, 0, 1, 619 } +}; + +static const x86_insn_info fildstp_insn[] = { + { SUF_S|SUF_Z, 0, CPU_FPU, 0, 0, {MOD_SpAdd, 0, 0}, 0, 0, 0, 1, {0xDF, 0, 0}, 0, 1, 653 }, + { SUF_L|SUF_Z, 0, CPU_FPU, 0, 0, {MOD_SpAdd, 0, 0}, 0, 0, 0, 1, {0xDB, 0, 0}, 0, 1, 654 }, + { SUF_Q|SUF_Z, 0, CPU_FPU, 0, 0, {MOD_Gap, MOD_Op0Add, MOD_SpAdd}, 0, 0, 0, 1, {0xDD, 0, 0}, 0, 1, 212 }, + { GAS_ONLY|SUF_Z, 0, CPU_FPU, 0, 0, {MOD_SpAdd, 0, 0}, 0, 0, 0, 1, {0xDF, 0, 0}, 0, 1, 34 } +}; + +static const x86_insn_info fbldstp_insn[] = { + { SUF_Z, 0, CPU_FPU, 0, 0, {MOD_SpAdd, 0, 0}, 0, 0, 0, 1, {0xDF, 0, 0}, 0, 1, 619 } +}; + +static const x86_insn_info fst_insn[] = { + { SUF_S|SUF_Z, 0, CPU_FPU, 0, 0, {0, 0, 0}, 0, 0, 0, 1, {0xD9, 0, 0}, 2, 1, 654 }, + { SUF_L|SUF_Z, 0, CPU_FPU, 0, 0, {0, 0, 0}, 0, 0, 0, 1, {0xDD, 0, 0}, 2, 1, 212 }, + { SUF_Z, 0, CPU_FPU, 0, 0, {0, 0, 0}, 0, 0, 0, 2, {0xDD, 0xD0, 0}, 0, 1, 328 } +}; + +static const x86_insn_info fxch_insn[] = { + { SUF_Z, 0, CPU_FPU, 0, 0, {0, 0, 0}, 0, 0, 0, 2, {0xD9, 0xC8, 0}, 0, 1, 328 }, + { SUF_Z, 0, CPU_FPU, 0, 0, {0, 0, 0}, 0, 0, 0, 2, {0xD9, 0xC8, 0}, 0, 2, 327 }, + { SUF_Z, 0, CPU_FPU, 0, 0, {0, 0, 0}, 0, 0, 0, 2, {0xD9, 0xC8, 0}, 0, 2, 329 }, + { SUF_Z, 0, CPU_FPU, 0, 0, {0, 0, 0}, 0, 0, 0, 2, {0xD9, 0xC9, 0}, 0, 0, 0 } +}; + +static const x86_insn_info fcom_insn[] = { + { SUF_S|SUF_Z, 0, CPU_FPU, 0, 0, {MOD_Gap, MOD_SpAdd, 0}, 0, 0, 0, 1, {0xD8, 0, 0}, 0, 1, 654 }, + { SUF_L|SUF_Z, 0, CPU_FPU, 0, 0, {MOD_Gap, MOD_SpAdd, 0}, 0, 0, 0, 1, {0xDC, 0, 0}, 0, 1, 212 }, + { SUF_Z, 0, CPU_FPU, 0, 0, {MOD_Op1Add, 0, 0}, 0, 0, 0, 2, {0xD8, 0x00, 0}, 0, 1, 328 }, + { GAS_ONLY|SUF_Z, 0, CPU_FPU, 0, 0, {MOD_Gap, MOD_SpAdd, 0}, 0, 0, 0, 1, {0xD8, 0, 0}, 0, 1, 58 }, + { GAS_ONLY|SUF_Z, 0, CPU_FPU, 0, 0, {MOD_Op1Add, 0, 0}, 0, 0, 0, 2, {0xD8, 0x01, 0}, 0, 0, 0 }, + { GAS_ILLEGAL|SUF_Z, 0, CPU_FPU, 0, 0, {MOD_Op1Add, 0, 0}, 0, 0, 0, 2, {0xD8, 0x00, 0}, 0, 2, 327 } +}; + +static const x86_insn_info fcom2_insn[] = { + { SUF_Z, 0, CPU_286, CPU_FPU, 0, {MOD_Op0Add, MOD_Op1Add, 0}, 0, 0, 0, 2, {0x00, 0x00, 0}, 0, 1, 328 }, + { SUF_Z, 0, CPU_286, CPU_FPU, 0, {MOD_Op0Add, MOD_Op1Add, 0}, 0, 0, 0, 2, {0x00, 0x00, 0}, 0, 2, 327 } +}; + +static const x86_insn_info farith_insn[] = { + { SUF_S|SUF_Z, 0, CPU_FPU, 0, 0, {MOD_Gap, MOD_Gap, MOD_SpAdd}, 0, 0, 0, 1, {0xD8, 0, 0}, 0, 1, 654 }, + { SUF_L|SUF_Z, 0, CPU_FPU, 0, 0, {MOD_Gap, MOD_Gap, MOD_SpAdd}, 0, 0, 0, 1, {0xDC, 0, 0}, 0, 1, 212 }, + { SUF_Z, 0, CPU_FPU, 0, 0, {MOD_Gap, MOD_Op1Add, 0}, 0, 0, 0, 2, {0xD8, 0x00, 0}, 0, 1, 328 }, + { SUF_Z, 0, CPU_FPU, 0, 0, {MOD_Gap, MOD_Op1Add, 0}, 0, 0, 0, 2, {0xD8, 0x00, 0}, 0, 2, 327 }, + { SUF_Z, 0, CPU_FPU, 0, 0, {MOD_Op1Add, 0, 0}, 0, 0, 0, 2, {0xDC, 0x00, 0}, 0, 1, 696 }, + { GAS_ILLEGAL|SUF_Z, 0, CPU_FPU, 0, 0, {MOD_Op1Add, 0, 0}, 0, 0, 0, 2, {0xDC, 0x00, 0}, 0, 2, 329 }, + { GAS_ONLY|SUF_Z, 0, CPU_FPU, 0, 0, {MOD_Gap, MOD_Op1Add, 0}, 0, 0, 0, 2, {0xDC, 0x00, 0}, 0, 2, 329 } +}; + +static const x86_insn_info farithp_insn[] = { + { SUF_Z, 0, CPU_FPU, 0, 0, {MOD_Op1Add, 0, 0}, 0, 0, 0, 2, {0xDE, 0x01, 0}, 0, 0, 0 }, + { SUF_Z, 0, CPU_FPU, 0, 0, {MOD_Op1Add, 0, 0}, 0, 0, 0, 2, {0xDE, 0x00, 0}, 0, 1, 328 }, + { SUF_Z, 0, CPU_FPU, 0, 0, {MOD_Op1Add, 0, 0}, 0, 0, 0, 2, {0xDE, 0x00, 0}, 0, 2, 329 } +}; + +static const x86_insn_info fiarith_insn[] = { + { SUF_S|SUF_Z, 0, CPU_FPU, 0, 0, {MOD_SpAdd, MOD_Op0Add, 0}, 0, 0, 0, 1, {0x04, 0, 0}, 0, 1, 653 }, + { SUF_L|SUF_Z, 0, CPU_FPU, 0, 0, {MOD_SpAdd, MOD_Op0Add, 0}, 0, 0, 0, 1, {0x00, 0, 0}, 0, 1, 654 } +}; + +static const x86_insn_info fldnstcw_insn[] = { + { SUF_W|SUF_Z, 0, CPU_FPU, 0, 0, {MOD_SpAdd, 0, 0}, 0, 0, 0, 1, {0xD9, 0, 0}, 0, 1, 34 } +}; + +static const x86_insn_info fstcw_insn[] = { + { SUF_W|SUF_Z, 0, CPU_FPU, 0, 0, {0, 0, 0}, 0, 0, 0, 2, {0x9B, 0xD9, 0}, 7, 1, 34 } +}; + +static const x86_insn_info fnstsw_insn[] = { + { SUF_W|SUF_Z, 0, CPU_FPU, 0, 0, {0, 0, 0}, 0, 0, 0, 1, {0xDD, 0, 0}, 7, 1, 34 }, + { SUF_W|SUF_Z, 0, CPU_FPU, 0, 0, {0, 0, 0}, 0, 0, 0, 2, {0xDF, 0xE0, 0}, 0, 1, 343 } +}; + +static const x86_insn_info fstsw_insn[] = { + { SUF_W|SUF_Z, 0, CPU_FPU, 0, 0, {0, 0, 0}, 0, 0, 0, 2, {0x9B, 0xDD, 0}, 7, 1, 34 }, + { SUF_W|SUF_Z, 0, CPU_FPU, 0, 0, {0, 0, 0}, 0, 0, 0, 3, {0x9B, 0xDF, 0xE0}, 0, 1, 343 } +}; + +static const x86_insn_info ffree_insn[] = { + { SUF_Z, 0, CPU_FPU, 0, 0, {MOD_Op0Add, 0, 0}, 0, 0, 0, 2, {0x00, 0xC0, 0}, 0, 1, 328 } +}; + +static const x86_insn_info bswap_insn[] = { + { SUF_L|SUF_Z, 0, CPU_486, 0, 0, {0, 0, 0}, 32, 0, 0, 2, {0x0F, 0xC8, 0}, 0, 1, 697 }, + { SUF_Q|SUF_Z, ONLY_64, 0, 0, 0, {0, 0, 0}, 64, 0, 0, 2, {0x0F, 0xC8, 0}, 0, 1, 698 } +}; + +static const x86_insn_info cmpxchgxadd_insn[] = { + { SUF_B|SUF_Z, 0, CPU_486, 0, 0, {MOD_Op1Add, 0, 0}, 0, 0, 0, 2, {0x0F, 0x00, 0}, 0, 2, 323 }, + { SUF_W|SUF_Z, 0, CPU_486, 0, 0, {MOD_Op1Add, 0, 0}, 16, 0, 0, 2, {0x0F, 0x01, 0}, 0, 2, 260 }, + { SUF_L|SUF_Z, 0, CPU_486, 0, 0, {MOD_Op1Add, 0, 0}, 32, 0, 0, 2, {0x0F, 0x01, 0}, 0, 2, 266 }, + { SUF_Q|SUF_Z, ONLY_64, CPU_486, 0, 0, {MOD_Op1Add, 0, 0}, 64, 0, 0, 2, {0x0F, 0x01, 0}, 0, 2, 272 } +}; + +static const x86_insn_info cmpxchg8b_insn[] = { + { SUF_Q|SUF_Z, 0, CPU_586, 0, 0, {0, 0, 0}, 0, 0, 0, 2, {0x0F, 0xC7, 0}, 1, 1, 6 } +}; + +static const x86_insn_info cmovcc_insn[] = { + { SUF_W|SUF_Z, 0, CPU_686, 0, 0, {MOD_Op1Add, 0, 0}, 16, 0, 0, 2, {0x0F, 0x40, 0}, 0, 2, 98 }, + { SUF_L|SUF_Z, 0, CPU_686, 0, 0, {MOD_Op1Add, 0, 0}, 32, 0, 0, 2, {0x0F, 0x40, 0}, 0, 2, 101 }, + { SUF_Q|SUF_Z, ONLY_64, CPU_686, 0, 0, {MOD_Op1Add, 0, 0}, 64, 0, 0, 2, {0x0F, 0x40, 0}, 0, 2, 104 } +}; + +static const x86_insn_info fcmovcc_insn[] = { + { SUF_Z, 0, CPU_686, CPU_FPU, 0, {MOD_Op0Add, MOD_Op1Add, 0}, 0, 0, 0, 2, {0x00, 0x00, 0}, 0, 2, 327 } +}; + +static const x86_insn_info movnti_insn[] = { + { SUF_L|SUF_Z, 0, CPU_P4, 0, 0, {0, 0, 0}, 0, 0, 0, 2, {0x0F, 0xC3, 0}, 0, 2, 337 }, + { SUF_Q|SUF_Z, ONLY_64, CPU_P4, 0, 0, {0, 0, 0}, 64, 0, 0, 2, {0x0F, 0xC3, 0}, 0, 2, 339 } +}; + +static const x86_insn_info clflush_insn[] = { + { SUF_Z, 0, CPU_P3, 0, 0, {0, 0, 0}, 0, 0, 0, 2, {0x0F, 0xAE, 0}, 7, 1, 50 } +}; + +static const x86_insn_info movd_insn[] = { + { SUF_Z, 0, CPU_386, CPU_MMX, 0, {0, 0, 0}, 0, 0, 0, 2, {0x0F, 0x6E, 0}, 0, 2, 293 }, + { SUF_Z, ONLY_64, CPU_MMX, 0, 0, {0, 0, 0}, 64, 0, 0, 2, {0x0F, 0x6E, 0}, 0, 2, 295 }, + { SUF_Z, 0, CPU_386, CPU_MMX, 0, {0, 0, 0}, 0, 0, 0, 2, {0x0F, 0x7E, 0}, 0, 2, 294 }, + { SUF_Z, ONLY_64, CPU_MMX, 0, 0, {0, 0, 0}, 64, 0, 0, 2, {0x0F, 0x7E, 0}, 0, 2, 297 }, + { SUF_Z, 0, CPU_386, CPU_SSE2, 0, {0, 0, 0}, 0, 0, 0x66, 2, {0x0F, 0x6E, 0}, 0, 2, 299 }, + { SUF_Z, ONLY_64, CPU_SSE2, 0, 0, {0, 0, 0}, 64, 0, 0x66, 2, {0x0F, 0x6E, 0}, 0, 2, 301 }, + { SUF_Z, 0, CPU_386, CPU_SSE2, 0, {0, 0, 0}, 0, 0, 0x66, 2, {0x0F, 0x7E, 0}, 0, 2, 188 }, + { SUF_Z, ONLY_64, CPU_SSE2, 0, 0, {0, 0, 0}, 64, 0, 0x66, 2, {0x0F, 0x7E, 0}, 0, 2, 182 } +}; + +static const x86_insn_info movq_insn[] = { + { GAS_ILLEGAL|SUF_Z, 0, CPU_MMX, 0, 0, {0, 0, 0}, 0, 0, 0, 2, {0x0F, 0x6F, 0}, 0, 2, 140 }, + { GAS_ILLEGAL|SUF_Z, ONLY_64, CPU_MMX, 0, 0, {0, 0, 0}, 64, 0, 0, 2, {0x0F, 0x6E, 0}, 0, 2, 295 }, + { GAS_ILLEGAL|SUF_Z, 0, CPU_MMX, 0, 0, {0, 0, 0}, 0, 0, 0, 2, {0x0F, 0x7F, 0}, 0, 2, 331 }, + { GAS_ILLEGAL|SUF_Z, ONLY_64, CPU_MMX, 0, 0, {0, 0, 0}, 64, 0, 0, 2, {0x0F, 0x7E, 0}, 0, 2, 297 }, + { GAS_ILLEGAL|SUF_Z, 0, CPU_SSE2, 0, 0, {0, 0, 0}, 0, 0, 0xF3, 2, {0x0F, 0x7E, 0}, 0, 2, 64 }, + { GAS_ILLEGAL|SUF_Z, 0, CPU_SSE2, 0, 0, {0, 0, 0}, 0, 0, 0xF3, 2, {0x0F, 0x7E, 0}, 0, 2, 333 }, + { GAS_ILLEGAL|SUF_Z, ONLY_64, CPU_SSE2, 0, 0, {0, 0, 0}, 64, 0, 0x66, 2, {0x0F, 0x6E, 0}, 0, 2, 301 }, + { GAS_ILLEGAL|SUF_Z, 0, CPU_SSE2, 0, 0, {0, 0, 0}, 0, 0, 0x66, 2, {0x0F, 0xD6, 0}, 0, 2, 335 }, + { GAS_ILLEGAL|SUF_Z, ONLY_64, CPU_SSE2, 0, 0, {0, 0, 0}, 64, 0, 0x66, 2, {0x0F, 0x7E, 0}, 0, 2, 182 } +}; + +static const x86_insn_info mmxsse2_insn[] = { + { SUF_Z, 0, CPU_MMX, 0, 0, {MOD_Op1Add, 0, 0}, 0, 0, 0, 2, {0x0F, 0x00, 0}, 0, 2, 140 }, + { SUF_Z, 0, CPU_SSE2, 0, 0, {MOD_Op1Add, 0, 0}, 0, 0, 0x66, 2, {0x0F, 0x00, 0}, 0, 2, 155 } +}; + +static const x86_insn_info pshift_insn[] = { + { SUF_Z, 0, CPU_MMX, 0, 0, {MOD_Op1Add, 0, 0}, 0, 0, 0, 2, {0x0F, 0x00, 0}, 0, 2, 140 }, + { SUF_Z, 0, CPU_MMX, 0, 0, {MOD_Gap, MOD_Op1Add, MOD_SpAdd}, 0, 0, 0, 2, {0x0F, 0x00, 0}, 0, 2, 162 }, + { SUF_Z, 0, CPU_SSE2, 0, 0, {MOD_Op1Add, 0, 0}, 0, 0, 0x66, 2, {0x0F, 0x00, 0}, 0, 2, 155 }, + { SUF_Z, 0, CPU_SSE2, 0, 0, {MOD_Gap, MOD_Op1Add, MOD_SpAdd}, 0, 0, 0x66, 2, {0x0F, 0x00, 0}, 0, 2, 2 } +}; + +static const x86_insn_info vpshift_insn[] = { + { SUF_Z, ONLY_AVX, CPU_AVX, 0, 0, {MOD_Op1Add, 0, 0}, 0, 0, 0xC1, 2, {0x0F, 0x00, 0}, 0, 2, 158 }, + { SUF_Z, ONLY_AVX, CPU_AVX, 0, 0, {MOD_Gap, MOD_Op1Add, MOD_SpAdd}, 0, 0, 0xC1, 2, {0x0F, 0x00, 0}, 0, 2, 511 }, + { SUF_Z, ONLY_AVX, CPU_AVX, 0, 0, {MOD_Op1Add, 0, 0}, 0, 0, 0xC1, 2, {0x0F, 0x00, 0}, 0, 3, 12 }, + { SUF_Z, ONLY_AVX, CPU_AVX, 0, 0, {MOD_Gap, MOD_Op1Add, MOD_SpAdd}, 0, 0, 0xC1, 2, {0x0F, 0x00, 0}, 0, 3, 1 }, + { SUF_Z, ONLY_AVX, CPU_AVX2, 0, 0, {MOD_Op1Add, 0, 0}, 0, 0, 0xC5, 2, {0x0F, 0x00, 0}, 0, 2, 639 }, + { SUF_Z, ONLY_AVX, CPU_AVX2, 0, 0, {MOD_Gap, MOD_Op1Add, MOD_SpAdd}, 0, 0, 0xC5, 2, {0x0F, 0x00, 0}, 0, 2, 513 }, + { SUF_Z, ONLY_AVX, CPU_AVX2, 0, 0, {MOD_Op1Add, 0, 0}, 0, 0, 0xC5, 2, {0x0F, 0x00, 0}, 0, 3, 8 }, + { SUF_Z, ONLY_AVX, CPU_AVX2, 0, 0, {MOD_Gap, MOD_Op1Add, MOD_SpAdd}, 0, 0, 0xC5, 2, {0x0F, 0x00, 0}, 0, 3, 200 } +}; + +static const x86_insn_info xmm_xmm128_256_insn[] = { + { SUF_Z, 0, CPU_SSE, 0, 0, {MOD_PreAdd, MOD_Op1Add, MOD_SetVEX}, 0, 0, 0x00, 2, {0x0F, 0x00, 0}, 0, 2, 158 }, + { SUF_Z, ONLY_AVX, CPU_AVX, 0, 0, {MOD_PreAdd, MOD_Op1Add, 0}, 0, 0, 0xC0, 2, {0x0F, 0x00, 0}, 0, 3, 12 }, + { SUF_Z, ONLY_AVX, CPU_AVX, 0, 0, {MOD_PreAdd, MOD_Op1Add, 0}, 0, 0, 0xC4, 2, {0x0F, 0x00, 0}, 0, 2, 197 }, + { SUF_Z, ONLY_AVX, CPU_AVX, 0, 0, {MOD_PreAdd, MOD_Op1Add, 0}, 0, 0, 0xC4, 2, {0x0F, 0x00, 0}, 0, 3, 16 } +}; + +static const x86_insn_info xmm_xmm128_256avx2_insn[] = { + { SUF_Z, 0, CPU_SSE, 0, 0, {MOD_PreAdd, MOD_Op1Add, MOD_SetVEX}, 0, 0, 0x00, 2, {0x0F, 0x00, 0}, 0, 2, 158 }, + { SUF_Z, ONLY_AVX, CPU_AVX, 0, 0, {MOD_PreAdd, MOD_Op1Add, 0}, 0, 0, 0xC0, 2, {0x0F, 0x00, 0}, 0, 3, 12 }, + { SUF_Z, ONLY_AVX, CPU_AVX2, 0, 0, {MOD_PreAdd, MOD_Op1Add, 0}, 0, 0, 0xC4, 2, {0x0F, 0x00, 0}, 0, 2, 197 }, + { SUF_Z, ONLY_AVX, CPU_AVX2, 0, 0, {MOD_PreAdd, MOD_Op1Add, 0}, 0, 0, 0xC4, 2, {0x0F, 0x00, 0}, 0, 3, 16 } +}; + +static const x86_insn_info xmm_xmm128_insn[] = { + { SUF_Z, 0, CPU_SSE, 0, 0, {MOD_PreAdd, MOD_Op1Add, MOD_SetVEX}, 0, 0, 0x00, 2, {0x0F, 0x00, 0}, 0, 2, 158 }, + { SUF_Z, ONLY_AVX, CPU_AVX, 0, 0, {MOD_PreAdd, MOD_Op1Add, 0}, 0, 0, 0xC0, 2, {0x0F, 0x00, 0}, 0, 3, 12 } +}; + +static const x86_insn_info cvt_rx_xmm32_insn[] = { + { SUF_L|SUF_Z, 0, CPU_386, CPU_SSE, 0, {MOD_PreAdd, MOD_Op1Add, MOD_SetVEX}, 0, 0, 0x00, 2, {0x0F, 0x00, 0}, 0, 2, 164 }, + { SUF_L|SUF_Z, 0, CPU_386, CPU_SSE, 0, {MOD_PreAdd, MOD_Op1Add, MOD_SetVEX}, 0, 0, 0x00, 2, {0x0F, 0x00, 0}, 0, 2, 359 }, + { SUF_Q|SUF_Z, ONLY_64, CPU_SSE, 0, 0, {MOD_PreAdd, MOD_Op1Add, MOD_SetVEX}, 64, 0, 0x00, 2, {0x0F, 0x00, 0}, 0, 2, 170 }, + { SUF_Q|SUF_Z, ONLY_64, CPU_SSE, 0, 0, {MOD_PreAdd, MOD_Op1Add, MOD_SetVEX}, 64, 0, 0x00, 2, {0x0F, 0x00, 0}, 0, 2, 361 } +}; + +static const x86_insn_info cvt_mm_xmm64_insn[] = { + { SUF_Z, 0, CPU_SSE, 0, 0, {MOD_Op1Add, 0, 0}, 0, 0, 0, 2, {0x0F, 0x00, 0}, 0, 2, 315 }, + { SUF_Z, 0, CPU_SSE, 0, 0, {MOD_Op1Add, 0, 0}, 0, 0, 0, 2, {0x0F, 0x00, 0}, 0, 2, 317 } +}; + +static const x86_insn_info cvt_xmm_mm_ps_insn[] = { + { SUF_Z, 0, CPU_SSE, 0, 0, {MOD_Op1Add, 0, 0}, 0, 0, 0, 2, {0x0F, 0x00, 0}, 0, 2, 333 } +}; + +static const x86_insn_info cvt_xmm_rmx_insn[] = { + { SUF_L|SUF_Z, 0, CPU_386, CPU_SSE, 0, {MOD_PreAdd, MOD_Op1Add, MOD_SetVEX}, 0, 0, 0x00, 2, {0x0F, 0x00, 0}, 0, 2, 649 }, + { SUF_L|SUF_Z, NOT_64, CPU_386, CPU_SSE, 0, {MOD_PreAdd, MOD_Op1Add, MOD_SetVEX}, 0, 0, 0x00, 2, {0x0F, 0x00, 0}, 0, 2, 239 }, + { SUF_Q|SUF_Z, ONLY_64, CPU_SSE, 0, 0, {MOD_PreAdd, MOD_Op1Add, MOD_SetVEX}, 64, 0, 0x00, 2, {0x0F, 0x00, 0}, 0, 2, 651 }, + { SUF_L|SUF_Z, ONLY_AVX|NOT_64, CPU_386, CPU_AVX, 0, {MOD_PreAdd, MOD_Op1Add, 0}, 0, 0, 0xC0, 2, {0x0F, 0x00, 0}, 0, 3, 88 }, + { SUF_L|SUF_Z, ONLY_AVX, CPU_386, CPU_AVX, 0, {MOD_PreAdd, MOD_Op1Add, 0}, 0, 0, 0xC0, 2, {0x0F, 0x00, 0}, 0, 3, 281 }, + { SUF_Q|SUF_Z, ONLY_64|ONLY_AVX, CPU_AVX, 0, 0, {MOD_PreAdd, MOD_Op1Add, 0}, 64, 0, 0xC0, 2, {0x0F, 0x00, 0}, 0, 3, 284 } +}; + +static const x86_insn_info xmm_xmm32_insn[] = { + { SUF_Z, 0, CPU_SSE, 0, 0, {MOD_PreAdd, MOD_Op1Add, MOD_SetVEX}, 0, 0, 0x00, 2, {0x0F, 0x00, 0}, 0, 2, 92 }, + { SUF_Z, 0, CPU_SSE, 0, 0, {MOD_PreAdd, MOD_Op1Add, MOD_SetVEX}, 0, 0, 0x00, 2, {0x0F, 0x00, 0}, 0, 2, 146 }, + { SUF_Z, ONLY_AVX, CPU_AVX, 0, 0, {MOD_PreAdd, MOD_Op1Add, 0}, 0, 0, 0xC0, 2, {0x0F, 0x00, 0}, 0, 3, 0 }, + { SUF_Z, ONLY_AVX, CPU_AVX, 0, 0, {MOD_PreAdd, MOD_Op1Add, 0}, 0, 0, 0xC0, 2, {0x0F, 0x00, 0}, 0, 3, 56 } +}; + +static const x86_insn_info ssecmp_128_insn[] = { + { SUF_Z, 0, CPU_SSE, 0, 0, {MOD_Imm8, MOD_PreAdd, MOD_SetVEX}, 0, 0, 0, 2, {0x0F, 0xC2, 0}, 0, 2, 158 }, + { SUF_Z, ONLY_AVX, CPU_AVX, 0, 0, {MOD_Imm8, MOD_PreAdd, 0}, 0, 0, 0xC0, 2, {0x0F, 0xC2, 0}, 0, 3, 12 }, + { SUF_Z, ONLY_AVX, CPU_AVX, 0, 0, {MOD_Imm8, MOD_PreAdd, 0}, 0, 0, 0xC4, 2, {0x0F, 0xC2, 0}, 0, 3, 16 } +}; + +static const x86_insn_info ssecmp_32_insn[] = { + { SUF_Z, 0, CPU_SSE, 0, 0, {MOD_Imm8, MOD_PreAdd, MOD_SetVEX}, 0, 0, 0x00, 2, {0x0F, 0xC2, 0}, 0, 2, 92 }, + { SUF_Z, 0, CPU_SSE, 0, 0, {MOD_Imm8, MOD_PreAdd, MOD_SetVEX}, 0, 0, 0x00, 2, {0x0F, 0xC2, 0}, 0, 2, 146 }, + { SUF_Z, ONLY_AVX, CPU_AVX, 0, 0, {MOD_Imm8, MOD_PreAdd, 0}, 0, 0, 0xC0, 2, {0x0F, 0xC2, 0}, 0, 3, 0 }, + { SUF_Z, ONLY_AVX, CPU_AVX, 0, 0, {MOD_Imm8, MOD_PreAdd, 0}, 0, 0, 0xC0, 2, {0x0F, 0xC2, 0}, 0, 3, 56 } +}; + +static const x86_insn_info xmm_xmm128_imm_insn[] = { + { SUF_Z, 0, CPU_SSE, 0, 0, {MOD_PreAdd, MOD_Op1Add, MOD_SetVEX}, 0, 0, 0, 2, {0x0F, 0x00, 0}, 0, 3, 185 } +}; + +static const x86_insn_info xmm_xmm128_imm_256avx2_insn[] = { + { SUF_Z, 0, CPU_SSE, 0, 0, {MOD_PreAdd, MOD_Op1Add, MOD_SetVEX}, 0, 0, 0, 2, {0x0F, 0x00, 0}, 0, 3, 185 }, + { SUF_Z, ONLY_AVX, CPU_AVX2, 0, 0, {MOD_PreAdd, MOD_Op1Add, 0}, 0, 0, 0xC4, 2, {0x0F, 0x00, 0}, 0, 3, 191 } +}; + +static const x86_insn_info xmm_xmm128_imm_256_insn[] = { + { SUF_Z, 0, CPU_SSE, 0, 0, {MOD_PreAdd, MOD_Op1Add, MOD_SetVEX}, 0, 0, 0, 2, {0x0F, 0x00, 0}, 0, 3, 158 }, + { SUF_Z, ONLY_AVX, CPU_AVX, 0, 0, {MOD_PreAdd, MOD_Op1Add, 0}, 0, 0, 0xC0, 2, {0x0F, 0x00, 0}, 0, 4, 60 }, + { SUF_Z, ONLY_AVX, CPU_AVX, 0, 0, {MOD_PreAdd, MOD_Op1Add, 0}, 0, 0, 0xC4, 2, {0x0F, 0x00, 0}, 0, 4, 20 } +}; + +static const x86_insn_info xmm_xmm32_imm_insn[] = { + { SUF_Z, 0, CPU_SSE, 0, 0, {MOD_PreAdd, MOD_Op1Add, MOD_SetVEX}, 0, 0, 0x00, 2, {0x0F, 0x00, 0}, 0, 3, 92 }, + { SUF_Z, 0, CPU_SSE, 0, 0, {MOD_PreAdd, MOD_Op1Add, MOD_SetVEX}, 0, 0, 0x00, 2, {0x0F, 0x00, 0}, 0, 3, 146 }, + { SUF_Z, ONLY_AVX, CPU_AVX, 0, 0, {MOD_PreAdd, MOD_Op1Add, 0}, 0, 0, 0xC0, 2, {0x0F, 0x00, 0}, 0, 4, 0 }, + { SUF_Z, ONLY_AVX, CPU_AVX, 0, 0, {MOD_PreAdd, MOD_Op1Add, 0}, 0, 0, 0xC0, 2, {0x0F, 0x00, 0}, 0, 4, 56 } +}; + +static const x86_insn_info ldstmxcsr_insn[] = { + { SUF_Z, 0, CPU_SSE, 0, 0, {MOD_SpAdd, MOD_SetVEX, 0}, 0, 0, 0, 2, {0x0F, 0xAE, 0}, 0, 1, 58 } +}; + +static const x86_insn_info maskmovq_insn[] = { + { SUF_Z, 0, CPU_MMX, CPU_P3, 0, {0, 0, 0}, 0, 0, 0, 2, {0x0F, 0xF7, 0}, 0, 2, 641 } +}; + +static const x86_insn_info movau_insn[] = { + { SUF_Z, NOT_AVX, CPU_SSE, 0, 0, {MOD_PreAdd, MOD_Op1Add, 0}, 0, 0, 0x00, 2, {0x0F, 0x00, 0}, 0, 2, 155 }, + { SUF_Z, NOT_AVX, CPU_SSE, 0, 0, {MOD_PreAdd, MOD_Op1Add, MOD_Op1Add}, 0, 0, 0x00, 2, {0x0F, 0x00, 0}, 0, 2, 485 }, + { SUF_Z, ONLY_AVX, CPU_AVX, 0, 0, {MOD_PreAdd, MOD_Op1Add, 0}, 0, 0, 0xC0, 2, {0x0F, 0x00, 0}, 0, 2, 155 }, + { SUF_Z, ONLY_AVX, CPU_AVX, 0, 0, {MOD_PreAdd, MOD_Op1Add, MOD_Op1Add}, 0, 0, 0xC0, 2, {0x0F, 0x00, 0}, 0, 2, 485 }, + { SUF_Z, ONLY_AVX, CPU_AVX, 0, 0, {MOD_PreAdd, MOD_Op1Add, 0}, 0, 0, 0xC4, 2, {0x0F, 0x00, 0}, 0, 2, 191 }, + { SUF_Z, ONLY_AVX, CPU_AVX, 0, 0, {MOD_PreAdd, MOD_Op1Add, MOD_Op1Add}, 0, 0, 0xC4, 2, {0x0F, 0x00, 0}, 0, 2, 487 } +}; + +static const x86_insn_info movhllhps_insn[] = { + { SUF_Z, 0, CPU_SSE, 0, 0, {MOD_Op1Add, MOD_SetVEX, 0}, 0, 0, 0, 2, {0x0F, 0x00, 0}, 0, 2, 92 }, + { SUF_Z, ONLY_AVX, CPU_AVX, 0, 0, {MOD_Op1Add, 0, 0}, 0, 0, 0xC0, 2, {0x0F, 0x00, 0}, 0, 3, 0 } +}; + +static const x86_insn_info movhlp_insn[] = { + { SUF_Z, 0, CPU_SSE, 0, 0, {MOD_PreAdd, MOD_Op1Add, MOD_SetVEX}, 0, 0, 0x00, 2, {0x0F, 0x00, 0}, 0, 2, 95 }, + { SUF_Z, 0, CPU_SSE, 0, 0, {MOD_PreAdd, MOD_Op1Add, MOD_SetVEX}, 0, 0, 0x00, 2, {0x0F, 0x01, 0}, 0, 2, 47 }, + { SUF_Z, ONLY_AVX, CPU_AVX, 0, 0, {MOD_PreAdd, MOD_Op1Add, 0}, 0, 0, 0xC0, 2, {0x0F, 0x00, 0}, 0, 3, 4 } +}; + +static const x86_insn_info movmsk_insn[] = { + { SUF_L|SUF_Z, 0, CPU_386, CPU_SSE, 0, {MOD_PreAdd, MOD_SetVEX, 0}, 0, 0, 0x00, 2, {0x0F, 0x50, 0}, 0, 2, 164 }, + { SUF_Q|SUF_Z, ONLY_64, CPU_SSE, 0, 0, {MOD_PreAdd, MOD_SetVEX, 0}, 64, 0, 0x00, 2, {0x0F, 0x50, 0}, 0, 2, 170 }, + { SUF_L|SUF_Z, ONLY_AVX, CPU_386, CPU_AVX, 0, {MOD_PreAdd, 0, 0}, 0, 0, 0xC4, 2, {0x0F, 0x50, 0}, 0, 2, 319 }, + { SUF_Q|SUF_Z, ONLY_64|ONLY_AVX, CPU_SSE, 0, 0, {MOD_PreAdd, 0, 0}, 64, 0, 0xC4, 2, {0x0F, 0x50, 0}, 0, 2, 321 } +}; + +static const x86_insn_info movnt_insn[] = { + { SUF_Z, 0, CPU_SSE, 0, 0, {MOD_PreAdd, MOD_Op1Add, MOD_SetVEX}, 0, 0, 0x00, 2, {0x0F, 0x00, 0}, 0, 2, 599 }, + { SUF_Z, ONLY_AVX, CPU_AVX, 0, 0, {MOD_PreAdd, MOD_Op1Add, 0}, 0, 0, 0xC4, 2, {0x0F, 0x00, 0}, 0, 2, 601 } +}; + +static const x86_insn_info movntq_insn[] = { + { SUF_Z, 0, CPU_SSE, 0, 0, {0, 0, 0}, 0, 0, 0, 2, {0x0F, 0xE7, 0}, 0, 2, 363 } +}; + +static const x86_insn_info movss_insn[] = { + { SUF_Z, 0, CPU_SSE, 0, 0, {MOD_SetVEX, 0, 0}, 0, 0, 0xF3, 2, {0x0F, 0x10, 0}, 0, 2, 92 }, + { SUF_Z, 0, CPU_SSE, 0, 0, {MOD_SetVEX, 0, 0}, 0, 0, 0xF3, 2, {0x0F, 0x10, 0}, 0, 2, 336 }, + { SUF_Z, 0, CPU_SSE, 0, 0, {MOD_SetVEX, 0, 0}, 0, 0, 0xF3, 2, {0x0F, 0x11, 0}, 0, 2, 450 }, + { SUF_Z, ONLY_AVX, CPU_AVX, 0, 0, {0, 0, 0}, 0, 0, 0xC2, 2, {0x0F, 0x10, 0}, 0, 3, 0 } +}; + +static const x86_insn_info pextrw_insn[] = { + { SUF_L|SUF_Z, NOT_AVX, CPU_MMX, CPU_P3, 0, {0, 0, 0}, 0, 0, 0, 2, {0x0F, 0xC5, 0}, 0, 3, 161 }, + { SUF_L|SUF_Z, 0, CPU_386, CPU_SSE2, 0, {MOD_SetVEX, 0, 0}, 0, 0, 0x66, 2, {0x0F, 0xC5, 0}, 0, 3, 164 }, + { SUF_Q|SUF_Z, ONLY_64|NOT_AVX, CPU_MMX, CPU_P3, 0, {0, 0, 0}, 64, 0, 0, 2, {0x0F, 0xC5, 0}, 0, 3, 167 }, + { SUF_Q|SUF_Z, ONLY_64, CPU_SSE2, 0, 0, {MOD_SetVEX, 0, 0}, 64, 0, 0x66, 2, {0x0F, 0xC5, 0}, 0, 3, 170 }, + { SUF_Z, 0, CPU_SSE41, 0, 0, {MOD_SetVEX, 0, 0}, 0, 0, 0x66, 3, {0x0F, 0x3A, 0x15}, 0, 3, 173 }, + { SUF_Z, 0, CPU_386, CPU_SSE41, 0, {MOD_SetVEX, 0, 0}, 32, 0, 0x66, 3, {0x0F, 0x3A, 0x15}, 0, 3, 176 }, + { SUF_Z, ONLY_64, CPU_SSE41, 0, 0, {MOD_SetVEX, 0, 0}, 64, 0, 0x66, 3, {0x0F, 0x3A, 0x15}, 0, 3, 179 } +}; + +static const x86_insn_info pinsrw_insn[] = { + { SUF_L|SUF_Z, NOT_AVX, CPU_MMX, CPU_P3, 0, {0, 0, 0}, 0, 0, 0, 2, {0x0F, 0xC4, 0}, 0, 3, 116 }, + { SUF_Q|SUF_Z, ONLY_64|NOT_AVX, CPU_MMX, CPU_P3, 0, {0, 0, 0}, 64, 64, 0, 2, {0x0F, 0xC4, 0}, 0, 3, 119 }, + { SUF_L|SUF_Z, NOT_AVX, CPU_MMX, CPU_P3, 0, {0, 0, 0}, 0, 0, 0, 2, {0x0F, 0xC4, 0}, 0, 3, 122 }, + { SUF_L|SUF_Z, 0, CPU_386, CPU_SSE2, 0, {MOD_SetVEX, 0, 0}, 0, 0, 0x66, 2, {0x0F, 0xC4, 0}, 0, 3, 125 }, + { SUF_Q|SUF_Z, ONLY_64, CPU_SSE2, 0, 0, {MOD_SetVEX, 0, 0}, 64, 64, 0x66, 2, {0x0F, 0xC4, 0}, 0, 3, 128 }, + { SUF_L|SUF_Z, 0, CPU_SSE2, 0, 0, {MOD_SetVEX, 0, 0}, 0, 0, 0x66, 2, {0x0F, 0xC4, 0}, 0, 3, 131 }, + { SUF_L|SUF_Z, ONLY_AVX, CPU_386, CPU_AVX, 0, {0, 0, 0}, 0, 0, 0xC1, 2, {0x0F, 0xC4, 0}, 0, 4, 24 }, + { SUF_Q|SUF_Z, ONLY_64|ONLY_AVX, CPU_AVX, 0, 0, {0, 0, 0}, 64, 64, 0xC1, 2, {0x0F, 0xC4, 0}, 0, 4, 28 }, + { SUF_L|SUF_Z, ONLY_AVX, CPU_AVX, 0, 0, {0, 0, 0}, 0, 0, 0xC1, 2, {0x0F, 0xC4, 0}, 0, 4, 32 } +}; + +static const x86_insn_info pmovmskb_insn[] = { + { SUF_L|SUF_Z, NOT_AVX, CPU_MMX, CPU_P3, 0, {0, 0, 0}, 0, 0, 0, 2, {0x0F, 0xD7, 0}, 0, 2, 161 }, + { SUF_L|SUF_Z, 0, CPU_386, CPU_SSE2, 0, {MOD_SetVEX, 0, 0}, 0, 0, 0x66, 2, {0x0F, 0xD7, 0}, 0, 2, 164 }, + { SUF_L|SUF_Z, ONLY_AVX, CPU_386, CPU_AVX2, 0, {0, 0, 0}, 0, 0, 0xC5, 2, {0x0F, 0xD7, 0}, 0, 2, 319 }, + { SUF_Q|SUF_Z, ONLY_64|NOT_AVX, CPU_MMX, CPU_P3, 0, {0, 0, 0}, 64, 64, 0, 2, {0x0F, 0xD7, 0}, 0, 2, 167 }, + { SUF_Q|SUF_Z, ONLY_64, CPU_SSE2, 0, 0, {MOD_SetVEX, 0, 0}, 64, 64, 0x66, 2, {0x0F, 0xD7, 0}, 0, 2, 170 }, + { SUF_Q|SUF_Z, ONLY_64|ONLY_AVX, CPU_SSE2, 0, 0, {0, 0, 0}, 64, 64, 0xC5, 2, {0x0F, 0xD7, 0}, 0, 2, 321 } +}; + +static const x86_insn_info pshufw_insn[] = { + { SUF_Z, 0, CPU_MMX, CPU_P3, 0, {0, 0, 0}, 0, 0, 0, 2, {0x0F, 0x70, 0}, 0, 3, 140 } +}; + +static const x86_insn_info xmm_xmm64_insn[] = { + { SUF_Z, 0, CPU_SSE2, 0, 0, {MOD_PreAdd, MOD_Op1Add, MOD_SetVEX}, 0, 0, 0x00, 2, {0x0F, 0x00, 0}, 0, 2, 92 }, + { SUF_Z, 0, CPU_SSE2, 0, 0, {MOD_PreAdd, MOD_Op1Add, MOD_SetVEX}, 0, 0, 0x00, 2, {0x0F, 0x00, 0}, 0, 2, 95 }, + { SUF_Z, ONLY_AVX, CPU_AVX, 0, 0, {MOD_PreAdd, MOD_Op1Add, 0}, 0, 0, 0xC0, 2, {0x0F, 0x00, 0}, 0, 3, 0 }, + { SUF_Z, ONLY_AVX, CPU_AVX, 0, 0, {MOD_PreAdd, MOD_Op1Add, 0}, 0, 0, 0xC0, 2, {0x0F, 0x00, 0}, 0, 3, 4 } +}; + +static const x86_insn_info ssecmp_64_insn[] = { + { SUF_Z, 0, CPU_SSE2, 0, 0, {MOD_Imm8, MOD_PreAdd, MOD_SetVEX}, 0, 0, 0x00, 2, {0x0F, 0xC2, 0}, 0, 2, 92 }, + { SUF_Z, 0, CPU_SSE2, 0, 0, {MOD_Imm8, MOD_PreAdd, MOD_SetVEX}, 0, 0, 0x00, 2, {0x0F, 0xC2, 0}, 0, 2, 95 }, + { SUF_Z, ONLY_AVX, CPU_AVX, 0, 0, {MOD_Imm8, MOD_PreAdd, 0}, 0, 0, 0xC0, 2, {0x0F, 0xC2, 0}, 0, 3, 0 }, + { SUF_Z, ONLY_AVX, CPU_AVX, 0, 0, {MOD_Imm8, MOD_PreAdd, 0}, 0, 0, 0xC0, 2, {0x0F, 0xC2, 0}, 0, 3, 4 } +}; + +static const x86_insn_info cvt_rx_xmm64_insn[] = { + { SUF_L|SUF_Z, 0, CPU_386, CPU_SSE2, 0, {MOD_PreAdd, MOD_Op1Add, MOD_SetVEX}, 0, 0, 0x00, 2, {0x0F, 0x00, 0}, 0, 2, 164 }, + { SUF_L|SUF_Z, 0, CPU_386, CPU_SSE2, 0, {MOD_PreAdd, MOD_Op1Add, MOD_SetVEX}, 0, 0, 0x00, 2, {0x0F, 0x00, 0}, 0, 2, 338 }, + { SUF_Q|SUF_Z, ONLY_64, CPU_SSE2, 0, 0, {MOD_PreAdd, MOD_Op1Add, MOD_SetVEX}, 64, 0, 0x00, 2, {0x0F, 0x00, 0}, 0, 2, 170 }, + { SUF_Q|SUF_Z, ONLY_64, CPU_SSE2, 0, 0, {MOD_PreAdd, MOD_Op1Add, MOD_SetVEX}, 64, 0, 0x00, 2, {0x0F, 0x00, 0}, 0, 2, 469 } +}; + +static const x86_insn_info cvt_mm_xmm_insn[] = { + { SUF_Z, 0, CPU_SSE2, 0, 0, {MOD_PreAdd, MOD_Op1Add, 0}, 0, 0, 0x00, 2, {0x0F, 0x00, 0}, 0, 2, 615 } +}; + +static const x86_insn_info cvt_xmm_mm_ss_insn[] = { + { SUF_Z, 0, CPU_SSE, 0, 0, {MOD_PreAdd, MOD_Op1Add, 0}, 0, 0, 0x00, 2, {0x0F, 0x00, 0}, 0, 2, 333 } +}; + +static const x86_insn_info eptvpid_insn[] = { + { SUF_L|SUF_Z, NOT_64, CPU_386, CPU_EPTVPID, 0, {MOD_Op2Add, 0, 0}, 32, 0, 0x66, 3, {0x0F, 0x38, 0x80}, 0, 2, 611 }, + { SUF_Q|SUF_Z, ONLY_64, CPU_EPTVPID, 0, 0, {MOD_Op2Add, 0, 0}, 64, 0, 0x66, 3, {0x0F, 0x38, 0x80}, 0, 2, 613 } +}; + +static const x86_insn_info vmxmemrd_insn[] = { + { SUF_L|SUF_Z, NOT_64, CPU_P4, 0, 0, {0, 0, 0}, 32, 0, 0, 2, {0x0F, 0x78, 0}, 0, 2, 266 }, + { SUF_Q|SUF_Z, ONLY_64, CPU_P4, 0, 0, {0, 0, 0}, 64, 64, 0, 2, {0x0F, 0x78, 0}, 0, 2, 272 } +}; + +static const x86_insn_info vmxmemwr_insn[] = { + { SUF_L|SUF_Z, NOT_64, CPU_P4, 0, 0, {0, 0, 0}, 32, 0, 0, 2, {0x0F, 0x79, 0}, 0, 2, 101 }, + { SUF_Q|SUF_Z, ONLY_64, CPU_P4, 0, 0, {0, 0, 0}, 64, 64, 0, 2, {0x0F, 0x79, 0}, 0, 2, 104 } +}; + +static const x86_insn_info vmxtwobytemem_insn[] = { + { SUF_Z, 0, CPU_P4, 0, 0, {MOD_SpAdd, 0, 0}, 0, 0, 0, 2, {0x0F, 0xC7, 0}, 0, 1, 6 } +}; + +static const x86_insn_info vmxthreebytemem_insn[] = { + { SUF_Z, 0, CPU_P4, 0, 0, {MOD_PreAdd, 0, 0}, 0, 0, 0x00, 2, {0x0F, 0xC7, 0}, 6, 1, 6 } +}; + +static const x86_insn_info maskmovdqu_insn[] = { + { SUF_Z, 0, CPU_SSE2, 0, 0, {MOD_SetVEX, 0, 0}, 0, 0, 0x66, 2, {0x0F, 0xF7, 0}, 0, 2, 64 } +}; + +static const x86_insn_info movdq2q_insn[] = { + { SUF_Z, 0, CPU_SSE2, 0, 0, {0, 0, 0}, 0, 0, 0xF2, 2, {0x0F, 0xD6, 0}, 0, 2, 315 } +}; + +static const x86_insn_info movq2dq_insn[] = { + { SUF_Z, 0, CPU_SSE2, 0, 0, {0, 0, 0}, 0, 0, 0xF3, 2, {0x0F, 0xD6, 0}, 0, 2, 445 } +}; + +static const x86_insn_info pslrldq_insn[] = { + { SUF_Z, 0, CPU_SSE2, 0, 0, {MOD_SpAdd, MOD_SetVEX, 0}, 0, 0, 0x66, 2, {0x0F, 0x73, 0}, 0, 2, 511 }, + { SUF_Z, 0, CPU_SSE2, 0, 0, {MOD_SpAdd, MOD_SetVEX, 0}, 0, 0, 0x66, 2, {0x0F, 0x73, 0}, 0, 3, 1 }, + { SUF_Z, ONLY_AVX, CPU_AVX2, 0, 0, {MOD_SpAdd, 0, 0}, 0, 0, 0xC5, 2, {0x0F, 0x73, 0}, 0, 2, 513 }, + { SUF_Z, ONLY_AVX, CPU_AVX2, 0, 0, {MOD_SpAdd, 0, 0}, 0, 0, 0xC5, 2, {0x0F, 0x73, 0}, 0, 3, 200 } +}; + +static const x86_insn_info lddqu_insn[] = { + { SUF_Z, 0, CPU_SSE3, 0, 0, {MOD_SetVEX, 0, 0}, 0, 0, 0xF2, 2, {0x0F, 0xF0, 0}, 0, 2, 595 }, + { SUF_Z, ONLY_AVX, CPU_AVX, 0, 0, {0, 0, 0}, 0, 0, 0xC7, 2, {0x0F, 0xF0, 0}, 0, 2, 597 } +}; + +static const x86_insn_info ssse3_insn[] = { + { SUF_Z, NOT_AVX, CPU_SSSE3, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0, 3, {0x0F, 0x38, 0x00}, 0, 2, 140 }, + { SUF_Z, 0, CPU_SSSE3, 0, 0, {MOD_Op2Add, MOD_SetVEX, 0}, 0, 0, 0x66, 3, {0x0F, 0x38, 0x00}, 0, 2, 158 }, + { SUF_Z, ONLY_AVX, CPU_AVX, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0xC1, 3, {0x0F, 0x38, 0x00}, 0, 3, 12 }, + { SUF_Z, ONLY_AVX, CPU_AVX2, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0xC5, 3, {0x0F, 0x38, 0x00}, 0, 2, 197 }, + { SUF_Z, ONLY_AVX, CPU_AVX2, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0xC5, 3, {0x0F, 0x38, 0x00}, 0, 3, 16 } +}; + +static const x86_insn_info ssse3imm_insn[] = { + { SUF_Z, 0, CPU_SSSE3, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0, 3, {0x0F, 0x3A, 0x00}, 0, 3, 140 }, + { SUF_Z, 0, CPU_SSSE3, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0x66, 3, {0x0F, 0x3A, 0x00}, 0, 3, 185 } +}; + +static const x86_insn_info sse4_insn[] = { + { SUF_Z, 0, CPU_SSE41, 0, 0, {MOD_Op2Add, MOD_SetVEX, 0}, 0, 0, 0x66, 3, {0x0F, 0x38, 0x00}, 0, 2, 155 }, + { SUF_Z, ONLY_AVX, CPU_AVX, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0xC5, 3, {0x0F, 0x38, 0x00}, 0, 2, 191 } +}; + +static const x86_insn_info sse4imm_256_insn[] = { + { SUF_Z, 0, CPU_SSE41, 0, 0, {MOD_Op2Add, MOD_SetVEX, 0}, 0, 0, 0x66, 3, {0x0F, 0x3A, 0x00}, 0, 3, 158 }, + { SUF_Z, ONLY_AVX, CPU_AVX, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0xC1, 3, {0x0F, 0x3A, 0x00}, 0, 4, 60 }, + { SUF_Z, ONLY_AVX, CPU_AVX, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0xC5, 3, {0x0F, 0x3A, 0x00}, 0, 3, 197 }, + { SUF_Z, ONLY_AVX, CPU_AVX, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0xC5, 3, {0x0F, 0x3A, 0x00}, 0, 4, 20 } +}; + +static const x86_insn_info sse4imm_256avx2_insn[] = { + { SUF_Z, 0, CPU_SSE41, 0, 0, {MOD_Op2Add, MOD_SetVEX, 0}, 0, 0, 0x66, 3, {0x0F, 0x3A, 0x00}, 0, 3, 158 }, + { SUF_Z, ONLY_AVX, CPU_AVX, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0xC1, 3, {0x0F, 0x3A, 0x00}, 0, 4, 60 }, + { SUF_Z, ONLY_AVX, CPU_AVX2, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0xC5, 3, {0x0F, 0x3A, 0x00}, 0, 3, 197 }, + { SUF_Z, ONLY_AVX, CPU_AVX2, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0xC5, 3, {0x0F, 0x3A, 0x00}, 0, 4, 20 } +}; + +static const x86_insn_info sse4imm_insn[] = { + { SUF_Z, 0, CPU_SSE41, 0, 0, {MOD_Op2Add, MOD_SetVEX, 0}, 0, 0, 0x66, 3, {0x0F, 0x3A, 0x00}, 0, 3, 158 }, + { SUF_Z, ONLY_AVX, CPU_AVX, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0xC1, 3, {0x0F, 0x3A, 0x00}, 0, 4, 60 } +}; + +static const x86_insn_info sse4m32imm_insn[] = { + { SUF_Z, 0, CPU_SSE41, 0, 0, {MOD_Op2Add, MOD_SetVEX, 0}, 0, 0, 0x66, 3, {0x0F, 0x3A, 0x00}, 0, 3, 92 }, + { SUF_Z, 0, CPU_SSE41, 0, 0, {MOD_Op2Add, MOD_SetVEX, 0}, 0, 0, 0x66, 3, {0x0F, 0x3A, 0x00}, 0, 3, 146 }, + { SUF_Z, ONLY_AVX, CPU_AVX, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0xC1, 3, {0x0F, 0x3A, 0x00}, 0, 4, 0 }, + { SUF_Z, ONLY_AVX, CPU_AVX, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0xC1, 3, {0x0F, 0x3A, 0x00}, 0, 4, 56 } +}; + +static const x86_insn_info sse4m64imm_insn[] = { + { SUF_Z, 0, CPU_SSE41, 0, 0, {MOD_Op2Add, MOD_SetVEX, 0}, 0, 0, 0x66, 3, {0x0F, 0x3A, 0x00}, 0, 3, 92 }, + { SUF_Z, 0, CPU_SSE41, 0, 0, {MOD_Op2Add, MOD_SetVEX, 0}, 0, 0, 0x66, 3, {0x0F, 0x3A, 0x00}, 0, 3, 95 }, + { SUF_Z, ONLY_AVX, CPU_AVX, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0xC1, 3, {0x0F, 0x3A, 0x00}, 0, 4, 0 }, + { SUF_Z, ONLY_AVX, CPU_AVX, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0xC1, 3, {0x0F, 0x3A, 0x00}, 0, 4, 4 } +}; + +static const x86_insn_info sse4xmm0_insn[] = { + { SUF_Z, 0, CPU_SSE41, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0x66, 3, {0x0F, 0x38, 0x00}, 0, 2, 155 }, + { SUF_Z, 0, CPU_SSE41, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0x66, 3, {0x0F, 0x38, 0x00}, 0, 3, 242 } +}; + +static const x86_insn_info avx_sse4xmm0_insn[] = { + { SUF_Z, ONLY_AVX, CPU_AVX, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0xC1, 3, {0x0F, 0x3A, 0x00}, 0, 4, 12 }, + { SUF_Z, ONLY_AVX, CPU_AVX, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0xC5, 3, {0x0F, 0x3A, 0x00}, 0, 4, 16 } +}; + +static const x86_insn_info avx2_sse4xmm0_insn[] = { + { SUF_Z, ONLY_AVX, CPU_AVX2, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0xC1, 3, {0x0F, 0x3A, 0x00}, 0, 4, 12 }, + { SUF_Z, ONLY_AVX, CPU_AVX2, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0xC5, 3, {0x0F, 0x3A, 0x00}, 0, 4, 16 } +}; + +static const x86_insn_info crc32_insn[] = { + { SUF_B|SUF_Z, 0, CPU_386, CPU_SSE42, 0, {0, 0, 0}, 0, 0, 0xF2, 3, {0x0F, 0x38, 0xF0}, 0, 2, 537 }, + { SUF_W|SUF_Z, 0, CPU_386, CPU_SSE42, 0, {0, 0, 0}, 16, 0, 0xF2, 3, {0x0F, 0x38, 0xF1}, 0, 2, 539 }, + { SUF_L|SUF_Z, 0, CPU_386, CPU_SSE42, 0, {0, 0, 0}, 32, 0, 0xF2, 3, {0x0F, 0x38, 0xF1}, 0, 2, 101 }, + { SUF_B|SUF_Z, ONLY_64, CPU_SSE42, 0, 0, {0, 0, 0}, 64, 0, 0xF2, 3, {0x0F, 0x38, 0xF0}, 0, 2, 541 }, + { SUF_Q|SUF_Z, ONLY_64, CPU_SSE42, 0, 0, {0, 0, 0}, 64, 0, 0xF2, 3, {0x0F, 0x38, 0xF1}, 0, 2, 104 } +}; + +static const x86_insn_info extractps_insn[] = { + { SUF_Z, 0, CPU_386, CPU_SSE41, 0, {MOD_SetVEX, 0, 0}, 0, 0, 0x66, 3, {0x0F, 0x3A, 0x17}, 0, 3, 188 }, + { SUF_Z, ONLY_64, CPU_SSE41, 0, 0, {MOD_SetVEX, 0, 0}, 64, 0, 0x66, 3, {0x0F, 0x3A, 0x17}, 0, 3, 179 } +}; + +static const x86_insn_info insertps_insn[] = { + { SUF_Z, 0, CPU_SSE41, 0, 0, {MOD_SetVEX, 0, 0}, 0, 0, 0x66, 3, {0x0F, 0x3A, 0x21}, 0, 3, 146 }, + { SUF_Z, 0, CPU_SSE41, 0, 0, {MOD_SetVEX, 0, 0}, 0, 0, 0x66, 3, {0x0F, 0x3A, 0x21}, 0, 3, 92 }, + { SUF_Z, ONLY_AVX, CPU_AVX, 0, 0, {0, 0, 0}, 0, 0, 0xC1, 3, {0x0F, 0x3A, 0x21}, 0, 4, 56 }, + { SUF_Z, ONLY_AVX, CPU_AVX, 0, 0, {0, 0, 0}, 0, 0, 0xC1, 3, {0x0F, 0x3A, 0x21}, 0, 4, 0 } +}; + +static const x86_insn_info movntdqa_insn[] = { + { SUF_Z, 0, CPU_SSE41, 0, 0, {MOD_SetVEX, 0, 0}, 0, 0, 0x66, 3, {0x0F, 0x38, 0x2A}, 0, 2, 595 }, + { SUF_Z, ONLY_AVX, CPU_AVX2, 0, 0, {0, 0, 0}, 0, 0, 0xC5, 3, {0x0F, 0x38, 0x2A}, 0, 2, 597 } +}; + +static const x86_insn_info sse4pcmpstr_insn[] = { + { SUF_Z, 0, CPU_SSE42, 0, 0, {MOD_Op2Add, MOD_SetVEX, 0}, 0, 0, 0x66, 3, {0x0F, 0x3A, 0x00}, 0, 3, 185 } +}; + +static const x86_insn_info pextrb_insn[] = { + { SUF_Z, 0, CPU_SSE41, 0, 0, {MOD_SetVEX, 0, 0}, 0, 0, 0x66, 3, {0x0F, 0x3A, 0x14}, 0, 3, 194 }, + { SUF_Z, 0, CPU_386, CPU_SSE41, 0, {MOD_SetVEX, 0, 0}, 0, 0, 0x66, 3, {0x0F, 0x3A, 0x14}, 0, 3, 176 }, + { SUF_Z, ONLY_64, CPU_SSE41, 0, 0, {MOD_SetVEX, 0, 0}, 64, 0, 0x66, 3, {0x0F, 0x3A, 0x14}, 0, 3, 179 } +}; + +static const x86_insn_info pextrd_insn[] = { + { SUF_Z, 0, CPU_386, CPU_SSE41, 0, {MOD_SetVEX, 0, 0}, 0, 0, 0x66, 3, {0x0F, 0x3A, 0x16}, 0, 3, 188 } +}; + +static const x86_insn_info pextrq_insn[] = { + { SUF_Z, ONLY_64, CPU_SSE41, 0, 0, {MOD_SetVEX, 0, 0}, 64, 0, 0x66, 3, {0x0F, 0x3A, 0x16}, 0, 3, 182 } +}; + +static const x86_insn_info pinsrb_insn[] = { + { SUF_Z, 0, CPU_SSE41, 0, 0, {MOD_SetVEX, 0, 0}, 0, 0, 0x66, 3, {0x0F, 0x3A, 0x20}, 0, 3, 143 }, + { SUF_Z, 0, CPU_386, CPU_SSE41, 0, {MOD_SetVEX, 0, 0}, 0, 0, 0x66, 3, {0x0F, 0x3A, 0x20}, 0, 3, 125 }, + { SUF_Z, ONLY_AVX, CPU_AVX, 0, 0, {0, 0, 0}, 0, 0, 0xC1, 3, {0x0F, 0x3A, 0x20}, 0, 4, 48 }, + { SUF_Z, ONLY_AVX, CPU_386, CPU_AVX, 0, {0, 0, 0}, 0, 0, 0xC1, 3, {0x0F, 0x3A, 0x20}, 0, 4, 52 } +}; + +static const x86_insn_info pinsrd_insn[] = { + { SUF_Z, 0, CPU_386, CPU_SSE41, 0, {MOD_SetVEX, 0, 0}, 0, 0, 0x66, 3, {0x0F, 0x3A, 0x22}, 0, 3, 239 }, + { SUF_Z, ONLY_AVX, CPU_386, CPU_AVX, 0, {0, 0, 0}, 0, 0, 0xC1, 3, {0x0F, 0x3A, 0x22}, 0, 4, 88 } +}; + +static const x86_insn_info pinsrq_insn[] = { + { SUF_Z, ONLY_64, CPU_SSE41, 0, 0, {MOD_SetVEX, 0, 0}, 64, 0, 0x66, 3, {0x0F, 0x3A, 0x22}, 0, 3, 227 }, + { SUF_Z, ONLY_64|ONLY_AVX, CPU_AVX, 0, 0, {0, 0, 0}, 64, 0, 0xC1, 3, {0x0F, 0x3A, 0x22}, 0, 4, 84 } +}; + +static const x86_insn_info sse4m16_insn[] = { + { SUF_Z, 0, CPU_SSE41, 0, 0, {MOD_Op2Add, MOD_SetVEX, 0}, 0, 0, 0x66, 3, {0x0F, 0x38, 0x00}, 0, 2, 447 }, + { SUF_Z, 0, CPU_SSE41, 0, 0, {MOD_Op2Add, MOD_SetVEX, 0}, 0, 0, 0x66, 3, {0x0F, 0x38, 0x00}, 0, 2, 64 }, + { SUF_Z, ONLY_AVX, CPU_AVX2, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0xC5, 3, {0x0F, 0x38, 0x00}, 0, 2, 449 }, + { SUF_Z, ONLY_AVX, CPU_AVX2, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0xC5, 3, {0x0F, 0x38, 0x00}, 0, 2, 208 } +}; + +static const x86_insn_info sse4m32_insn[] = { + { SUF_Z, 0, CPU_SSE41, 0, 0, {MOD_Op2Add, MOD_SetVEX, 0}, 0, 0, 0x66, 3, {0x0F, 0x38, 0x00}, 0, 2, 336 }, + { SUF_Z, 0, CPU_SSE41, 0, 0, {MOD_Op2Add, MOD_SetVEX, 0}, 0, 0, 0x66, 3, {0x0F, 0x38, 0x00}, 0, 2, 64 }, + { SUF_Z, ONLY_AVX, CPU_AVX2, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0xC5, 3, {0x0F, 0x38, 0x00}, 0, 2, 479 }, + { SUF_Z, ONLY_AVX, CPU_AVX2, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0xC5, 3, {0x0F, 0x38, 0x00}, 0, 2, 208 } +}; + +static const x86_insn_info sse4m64_insn[] = { + { SUF_Z, 0, CPU_SSE41, 0, 0, {MOD_Op2Add, MOD_SetVEX, 0}, 0, 0, 0x66, 3, {0x0F, 0x38, 0x00}, 0, 2, 451 }, + { SUF_Z, 0, CPU_SSE41, 0, 0, {MOD_Op2Add, MOD_SetVEX, 0}, 0, 0, 0x66, 3, {0x0F, 0x38, 0x00}, 0, 2, 64 }, + { SUF_Z, ONLY_AVX, CPU_AVX2, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0xC5, 3, {0x0F, 0x38, 0x00}, 0, 2, 509 }, + { SUF_Z, ONLY_AVX, CPU_AVX2, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0xC5, 3, {0x0F, 0x38, 0x00}, 0, 2, 208 } +}; + +static const x86_insn_info cnt_insn[] = { + { SUF_W|SUF_Z, 0, 0, 0, 0, {MOD_Op1Add, 0, 0}, 16, 0, 0xF3, 2, {0x0F, 0x00, 0}, 0, 2, 98 }, + { SUF_L|SUF_Z, 0, CPU_386, 0, 0, {MOD_Op1Add, 0, 0}, 32, 0, 0xF3, 2, {0x0F, 0x00, 0}, 0, 2, 101 }, + { SUF_Q|SUF_Z, ONLY_64, 0, 0, 0, {MOD_Op1Add, 0, 0}, 64, 0, 0xF3, 2, {0x0F, 0x00, 0}, 0, 2, 104 } +}; + +static const x86_insn_info vmovd_insn[] = { + { SUF_Z, ONLY_AVX, CPU_386, CPU_AVX, 0, {0, 0, 0}, 0, 0, 0xC1, 2, {0x0F, 0x6E, 0}, 0, 2, 299 }, + { SUF_Z, ONLY_AVX, CPU_386, CPU_AVX, 0, {0, 0, 0}, 0, 0, 0xC1, 2, {0x0F, 0x7E, 0}, 0, 2, 188 } +}; + +static const x86_insn_info vmovq_insn[] = { + { SUF_Z, ONLY_AVX, CPU_AVX, 0, 0, {0, 0, 0}, 0, 0, 0xC2, 2, {0x0F, 0x7E, 0}, 0, 2, 64 }, + { SUF_Z, ONLY_AVX, CPU_AVX, 0, 0, {0, 0, 0}, 0, 0, 0xC2, 2, {0x0F, 0x7E, 0}, 0, 2, 451 }, + { SUF_Z, ONLY_AVX, CPU_AVX, 0, 0, {0, 0, 0}, 0, 0, 0xC1, 2, {0x0F, 0xD6, 0}, 0, 2, 47 }, + { SUF_Z, ONLY_64|ONLY_AVX, CPU_AVX, 0, 0, {0, 0, 0}, 64, 0, 0xC1, 2, {0x0F, 0x6E, 0}, 0, 2, 301 }, + { SUF_Z, ONLY_64|ONLY_AVX, CPU_AVX, 0, 0, {0, 0, 0}, 64, 0, 0xC1, 2, {0x0F, 0x7E, 0}, 0, 2, 182 } +}; + +static const x86_insn_info avx_xmm_xmm128_insn[] = { + { SUF_Z, ONLY_AVX, CPU_AVX, 0, 0, {MOD_PreAdd, MOD_Op1Add, 0}, 0, 0, 0xC0, 2, {0x0F, 0x00, 0}, 0, 2, 155 }, + { SUF_Z, ONLY_AVX, CPU_AVX, 0, 0, {MOD_PreAdd, MOD_Op1Add, 0}, 0, 0, 0xC4, 2, {0x0F, 0x00, 0}, 0, 2, 191 } +}; + +static const x86_insn_info avx_sse4imm_insn[] = { + { SUF_Z, ONLY_AVX, CPU_SSE41, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0xC1, 3, {0x0F, 0x3A, 0x00}, 0, 3, 185 }, + { SUF_Z, ONLY_AVX, CPU_AVX, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0xC1, 3, {0x0F, 0x3A, 0x00}, 0, 3, 185 }, + { SUF_Z, ONLY_AVX, CPU_AVX, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0xC5, 3, {0x0F, 0x3A, 0x00}, 0, 3, 191 } +}; + +static const x86_insn_info vmovddup_insn[] = { + { SUF_Z, ONLY_AVX, CPU_AVX, 0, 0, {MOD_PreAdd, MOD_Op1Add, 0}, 0, 0, 0xC0, 2, {0x0F, 0x00, 0}, 0, 2, 64 }, + { SUF_Z, ONLY_AVX, CPU_AVX, 0, 0, {MOD_PreAdd, MOD_Op1Add, 0}, 0, 0, 0xC0, 2, {0x0F, 0x00, 0}, 0, 2, 451 }, + { SUF_Z, ONLY_AVX, CPU_AVX, 0, 0, {MOD_PreAdd, MOD_Op1Add, 0}, 0, 0, 0xC4, 2, {0x0F, 0x00, 0}, 0, 2, 191 } +}; + +static const x86_insn_info avx_xmm_xmm64_insn[] = { + { SUF_Z, ONLY_AVX, CPU_SSE2, 0, 0, {MOD_PreAdd, MOD_Op1Add, 0}, 0, 0, 0xC0, 2, {0x0F, 0x00, 0}, 0, 2, 64 }, + { SUF_Z, ONLY_AVX, CPU_SSE2, 0, 0, {MOD_PreAdd, MOD_Op1Add, 0}, 0, 0, 0xC0, 2, {0x0F, 0x00, 0}, 0, 2, 451 } +}; + +static const x86_insn_info avx_xmm_xmm32_insn[] = { + { SUF_Z, ONLY_AVX, CPU_SSE, 0, 0, {MOD_PreAdd, MOD_Op1Add, 0}, 0, 0, 0xC0, 2, {0x0F, 0x00, 0}, 0, 2, 64 }, + { SUF_Z, ONLY_AVX, CPU_SSE, 0, 0, {MOD_PreAdd, MOD_Op1Add, 0}, 0, 0, 0xC0, 2, {0x0F, 0x00, 0}, 0, 2, 336 } +}; + +static const x86_insn_info avx_cvt_xmm64_insn[] = { + { SUF_Z, ONLY_AVX, CPU_AVX, 0, 0, {MOD_PreAdd, MOD_Op1Add, 0}, 0, 0, 0xC0, 2, {0x0F, 0x00, 0}, 0, 2, 64 }, + { SUF_Z, ONLY_AVX, CPU_AVX, 0, 0, {MOD_PreAdd, MOD_Op1Add, 0}, 0, 0, 0xC0, 2, {0x0F, 0x00, 0}, 0, 2, 451 }, + { SUF_Z, ONLY_AVX, CPU_AVX, 0, 0, {MOD_PreAdd, MOD_Op1Add, 0}, 0, 0, 0xC4, 2, {0x0F, 0x00, 0}, 0, 2, 453 } +}; + +static const x86_insn_info avx_ssse3_2op_insn[] = { + { SUF_Z, ONLY_AVX, CPU_AVX, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0xC1, 3, {0x0F, 0x38, 0x00}, 0, 2, 155 } +}; + +static const x86_insn_info avx2_ssse3_2op_insn[] = { + { SUF_Z, ONLY_AVX, CPU_AVX, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0xC1, 3, {0x0F, 0x38, 0x00}, 0, 2, 155 }, + { SUF_Z, ONLY_AVX, CPU_AVX2, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0xC5, 3, {0x0F, 0x38, 0x00}, 0, 2, 191 } +}; + +static const x86_insn_info avx_cvt_xmm128_x_insn[] = { + { SUF_Z, ONLY_AVX, CPU_AVX, 0, 0, {MOD_PreAdd, MOD_Op1Add, 0}, 0, 0, 0xC0, 2, {0x0F, 0x00, 0}, 0, 2, 155 } +}; + +static const x86_insn_info avx_cvt_xmm128_y_insn[] = { + { SUF_Z, ONLY_AVX, CPU_AVX, 0, 0, {MOD_PreAdd, MOD_Op1Add, 0}, 0, 0, 0xC4, 2, {0x0F, 0x00, 0}, 0, 2, 205 } +}; + +static const x86_insn_info avx_cvt_xmm128_insn[] = { + { SUF_Z, ONLY_AVX, CPU_AVX, 0, 0, {MOD_PreAdd, MOD_Op1Add, 0}, 0, 0, 0xC0, 2, {0x0F, 0x00, 0}, 0, 2, 607 }, + { SUF_Z, ONLY_AVX, CPU_AVX, 0, 0, {MOD_PreAdd, MOD_Op1Add, 0}, 0, 0, 0xC4, 2, {0x0F, 0x00, 0}, 0, 2, 609 } +}; + +static const x86_insn_info vbroadcastss_insn[] = { + { SUF_Z, ONLY_AVX, CPU_AVX, 0, 0, {0, 0, 0}, 0, 0, 0xC1, 3, {0x0F, 0x38, 0x18}, 0, 2, 336 }, + { SUF_Z, ONLY_AVX, CPU_AVX, 0, 0, {0, 0, 0}, 0, 0, 0xC5, 3, {0x0F, 0x38, 0x18}, 0, 2, 449 }, + { SUF_Z, ONLY_AVX, CPU_AVX2, 0, 0, {0, 0, 0}, 0, 0, 0xC1, 3, {0x0F, 0x38, 0x18}, 0, 2, 64 }, + { SUF_Z, ONLY_AVX, CPU_AVX2, 0, 0, {0, 0, 0}, 0, 0, 0xC5, 3, {0x0F, 0x38, 0x18}, 0, 2, 208 } +}; + +static const x86_insn_info vbroadcastsd_insn[] = { + { SUF_Z, ONLY_AVX, CPU_AVX, 0, 0, {0, 0, 0}, 0, 0, 0xC5, 3, {0x0F, 0x38, 0x19}, 0, 2, 479 }, + { SUF_Z, ONLY_AVX, CPU_AVX2, 0, 0, {0, 0, 0}, 0, 0, 0xC5, 3, {0x0F, 0x38, 0x19}, 0, 2, 208 } +}; + +static const x86_insn_info vbroadcastif128_insn[] = { + { SUF_Z, ONLY_AVX, 0, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0xC5, 3, {0x0F, 0x38, 0x00}, 0, 2, 509 } +}; + +static const x86_insn_info vextractif128_insn[] = { + { SUF_Z, ONLY_AVX, 0, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0xC5, 3, {0x0F, 0x3A, 0x00}, 0, 3, 236 } +}; + +static const x86_insn_info vinsertif128_insn[] = { + { SUF_Z, ONLY_AVX, 0, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0xC5, 3, {0x0F, 0x3A, 0x00}, 0, 4, 8 } +}; + +static const x86_insn_info vzero_insn[] = { + { SUF_Z, 0, CPU_AVX, 0, 0, {MOD_SetVEX, 0, 0}, 0, 0, 0, 2, {0x0F, 0x77, 0}, 0, 0, 0 } +}; + +static const x86_insn_info vmaskmov_insn[] = { + { SUF_Z, ONLY_AVX, 0, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0xC1, 3, {0x0F, 0x38, 0x00}, 0, 3, 12 }, + { SUF_Z, ONLY_AVX, 0, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0xC5, 3, {0x0F, 0x38, 0x00}, 0, 3, 16 }, + { SUF_Z, ONLY_AVX, 0, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0xC1, 3, {0x0F, 0x38, 0x02}, 0, 3, 203 }, + { SUF_Z, ONLY_AVX, 0, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0xC5, 3, {0x0F, 0x38, 0x02}, 0, 3, 206 } +}; + +static const x86_insn_info vpermil_insn[] = { + { SUF_Z, ONLY_AVX, CPU_AVX, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0xC1, 3, {0x0F, 0x38, 0x08}, 0, 3, 12 }, + { SUF_Z, ONLY_AVX, CPU_AVX, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0xC5, 3, {0x0F, 0x38, 0x08}, 0, 3, 16 }, + { SUF_Z, ONLY_AVX, CPU_AVX, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0xC1, 3, {0x0F, 0x3A, 0x00}, 0, 3, 185 }, + { SUF_Z, ONLY_AVX, CPU_AVX, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0xC5, 3, {0x0F, 0x3A, 0x00}, 0, 3, 191 } +}; + +static const x86_insn_info vperm2f128_insn[] = { + { SUF_Z, ONLY_AVX, CPU_AVX, 0, 0, {0, 0, 0}, 0, 0, 0xC5, 3, {0x0F, 0x3A, 0x06}, 0, 4, 20 } +}; + +static const x86_insn_info vperm_var_avx2_insn[] = { + { SUF_Z, ONLY_AVX, CPU_AVX2, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0xC5, 3, {0x0F, 0x38, 0x00}, 0, 3, 16 } +}; + +static const x86_insn_info vperm_imm_avx2_insn[] = { + { SUF_Z, ONLY_AVX, CPU_AVX2, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0xCD, 3, {0x0F, 0x3A, 0x00}, 0, 3, 191 } +}; + +static const x86_insn_info vperm2i128_avx2_insn[] = { + { SUF_Z, ONLY_AVX, CPU_AVX2, 0, 0, {0, 0, 0}, 0, 0, 0xC5, 3, {0x0F, 0x3A, 0x46}, 0, 4, 20 } +}; + +static const x86_insn_info vpbroadcastb_avx2_insn[] = { + { SUF_Z, ONLY_AVX, CPU_AVX2, 0, 0, {0, 0, 0}, 0, 0, 0xC1, 3, {0x0F, 0x38, 0x78}, 0, 2, 543 }, + { SUF_Z, ONLY_AVX, CPU_AVX2, 0, 0, {0, 0, 0}, 0, 0, 0xC5, 3, {0x0F, 0x38, 0x78}, 0, 2, 545 }, + { SUF_Z, ONLY_AVX, CPU_AVX2, 0, 0, {0, 0, 0}, 0, 0, 0xC1, 3, {0x0F, 0x38, 0x78}, 0, 2, 635 }, + { SUF_Z, ONLY_AVX, CPU_AVX2, 0, 0, {0, 0, 0}, 0, 0, 0xC5, 3, {0x0F, 0x38, 0x78}, 0, 2, 637 } +}; + +static const x86_insn_info vpbroadcastw_avx2_insn[] = { + { SUF_Z, ONLY_AVX, CPU_AVX2, 0, 0, {0, 0, 0}, 0, 0, 0xC1, 3, {0x0F, 0x38, 0x79}, 0, 2, 543 }, + { SUF_Z, ONLY_AVX, CPU_AVX2, 0, 0, {0, 0, 0}, 0, 0, 0xC5, 3, {0x0F, 0x38, 0x79}, 0, 2, 545 }, + { SUF_Z, ONLY_AVX, CPU_AVX2, 0, 0, {0, 0, 0}, 0, 0, 0xC1, 3, {0x0F, 0x38, 0x79}, 0, 2, 547 }, + { SUF_Z, ONLY_AVX, CPU_AVX2, 0, 0, {0, 0, 0}, 0, 0, 0xC5, 3, {0x0F, 0x38, 0x79}, 0, 2, 549 } +}; + +static const x86_insn_info vpbroadcastd_avx2_insn[] = { + { SUF_Z, ONLY_AVX, CPU_AVX2, 0, 0, {0, 0, 0}, 0, 0, 0xC1, 3, {0x0F, 0x38, 0x58}, 0, 2, 543 }, + { SUF_Z, ONLY_AVX, CPU_AVX2, 0, 0, {0, 0, 0}, 0, 0, 0xC5, 3, {0x0F, 0x38, 0x58}, 0, 2, 545 }, + { SUF_Z, ONLY_AVX, CPU_386, CPU_AVX2, 0, {0, 0, 0}, 0, 0, 0xC1, 3, {0x0F, 0x38, 0x58}, 0, 2, 299 }, + { SUF_Z, ONLY_AVX, CPU_386, CPU_AVX2, 0, {0, 0, 0}, 0, 0, 0xC5, 3, {0x0F, 0x38, 0x58}, 0, 2, 643 } +}; + +static const x86_insn_info vpbroadcastq_avx2_insn[] = { + { SUF_Z, ONLY_AVX, CPU_AVX2, 0, 0, {0, 0, 0}, 0, 0, 0xC1, 3, {0x0F, 0x38, 0x59}, 0, 2, 543 }, + { SUF_Z, ONLY_AVX, CPU_AVX2, 0, 0, {0, 0, 0}, 0, 0, 0xC5, 3, {0x0F, 0x38, 0x59}, 0, 2, 545 }, + { SUF_Z, ONLY_AVX, CPU_AVX2, 0, 0, {0, 0, 0}, 0, 0, 0xC1, 3, {0x0F, 0x38, 0x59}, 0, 2, 333 }, + { SUF_Z, ONLY_AVX, CPU_AVX2, 0, 0, {0, 0, 0}, 0, 0, 0xC5, 3, {0x0F, 0x38, 0x59}, 0, 2, 621 } +}; + +static const x86_insn_info vpshiftv_vexw0_avx2_insn[] = { + { SUF_Z, ONLY_AVX, CPU_AVX2, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0xC1, 3, {0x0F, 0x38, 0x00}, 0, 3, 12 }, + { SUF_Z, ONLY_AVX, CPU_AVX2, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0xC5, 3, {0x0F, 0x38, 0x00}, 0, 3, 16 } +}; + +static const x86_insn_info vpshiftv_vexw1_avx2_insn[] = { + { SUF_Z, ONLY_AVX, CPU_AVX2, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0xC9, 3, {0x0F, 0x38, 0x00}, 0, 3, 12 }, + { SUF_Z, ONLY_AVX, CPU_AVX2, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0xCD, 3, {0x0F, 0x38, 0x00}, 0, 3, 16 } +}; + +static const x86_insn_info vmaskmov_vexw1_avx2_insn[] = { + { SUF_Z, ONLY_AVX, CPU_AVX2, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0xC9, 3, {0x0F, 0x38, 0x00}, 0, 3, 12 }, + { SUF_Z, ONLY_AVX, CPU_AVX2, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0xCD, 3, {0x0F, 0x38, 0x00}, 0, 3, 16 }, + { SUF_Z, ONLY_AVX, CPU_AVX2, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0xC9, 3, {0x0F, 0x38, 0x02}, 0, 3, 203 }, + { SUF_Z, ONLY_AVX, CPU_AVX2, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0xCD, 3, {0x0F, 0x38, 0x02}, 0, 3, 206 } +}; + +static const x86_insn_info vex_66_0F3A_imm8_avx2_insn[] = { + { SUF_Z, ONLY_AVX, CPU_AVX2, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0xC1, 3, {0x0F, 0x3A, 0x00}, 0, 4, 60 }, + { SUF_Z, ONLY_AVX, CPU_AVX2, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0xC5, 3, {0x0F, 0x3A, 0x00}, 0, 4, 20 } +}; + +static const x86_insn_info gather_64x_64x_insn[] = { + { SUF_Z, ONLY_AVX, CPU_AVX2, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0xC9, 3, {0x0F, 0x38, 0x00}, 0, 3, 221 }, + { SUF_Z, ONLY_AVX, CPU_AVX2, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0xCD, 3, {0x0F, 0x38, 0x00}, 0, 3, 224 } +}; + +static const x86_insn_info gather_64x_64y_insn[] = { + { SUF_Z, ONLY_AVX, CPU_AVX2, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0xC9, 3, {0x0F, 0x38, 0x00}, 0, 3, 221 }, + { SUF_Z, ONLY_AVX, CPU_AVX2, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0xCD, 3, {0x0F, 0x38, 0x00}, 0, 3, 278 } +}; + +static const x86_insn_info gather_32x_32y_insn[] = { + { SUF_Z, ONLY_AVX, CPU_AVX2, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0xC1, 3, {0x0F, 0x38, 0x00}, 0, 3, 245 }, + { SUF_Z, ONLY_AVX, CPU_AVX2, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0xC5, 3, {0x0F, 0x38, 0x00}, 0, 3, 251 } +}; + +static const x86_insn_info gather_32x_32y_128_insn[] = { + { SUF_Z, ONLY_AVX, CPU_AVX2, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0xC1, 3, {0x0F, 0x38, 0x00}, 0, 3, 245 }, + { SUF_Z, ONLY_AVX, CPU_AVX2, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0xC5, 3, {0x0F, 0x38, 0x00}, 0, 3, 248 } +}; + +static const x86_insn_info tsx_xabort_insn[] = { + { SUF_Z, 0, CPU_TSX, 0, 0, {0, 0, 0}, 0, 0, 0, 2, {0xC6, 0xF8, 0}, 0, 1, 3 } +}; + +static const x86_insn_info tsx_xbegin_insn[] = { + { SUF_Z, 0, CPU_386, CPU_TSX, 0, {0, 0, 0}, 0, 0, 0, 2, {0xC7, 0xF8, 0}, 0, 1, 679 }, + { SUF_Z, NOT_64, CPU_TSX, 0, 0, {0, 0, 0}, 16, 0, 0, 2, {0xC7, 0xF8, 0}, 0, 1, 678 } +}; + +static const x86_insn_info tsx_0x0F_0x01_insn[] = { + { SUF_Z, 0, CPU_TSX, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0, 3, {0x0F, 0x01, 0x00}, 0, 0, 0 } +}; + +static const x86_insn_info vfma_ps_insn[] = { + { SUF_Z, ONLY_AVX, CPU_FMA, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0xC1, 3, {0x0F, 0x38, 0x00}, 0, 3, 12 }, + { SUF_Z, ONLY_AVX, CPU_FMA, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0xC5, 3, {0x0F, 0x38, 0x00}, 0, 3, 16 } +}; + +static const x86_insn_info vfma_pd_insn[] = { + { SUF_Z, ONLY_AVX, CPU_FMA, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0xC9, 3, {0x0F, 0x38, 0x00}, 0, 3, 12 }, + { SUF_Z, ONLY_AVX, CPU_FMA, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0xCD, 3, {0x0F, 0x38, 0x00}, 0, 3, 16 } +}; + +static const x86_insn_info vfma_ss_insn[] = { + { SUF_Z, ONLY_AVX, CPU_FMA, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0xC1, 3, {0x0F, 0x38, 0x00}, 0, 3, 0 }, + { SUF_Z, ONLY_AVX, CPU_FMA, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0xC1, 3, {0x0F, 0x38, 0x00}, 0, 3, 56 } +}; + +static const x86_insn_info vfma_sd_insn[] = { + { SUF_Z, ONLY_AVX, CPU_FMA, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0xC9, 3, {0x0F, 0x38, 0x00}, 0, 3, 0 }, + { SUF_Z, ONLY_AVX, CPU_FMA, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0xC9, 3, {0x0F, 0x38, 0x00}, 0, 3, 4 } +}; + +static const x86_insn_info aes_insn[] = { + { SUF_Z, 0, CPU_AES, 0, 0, {MOD_Op1Add, MOD_Op2Add, MOD_SetVEX}, 0, 0, 0x66, 3, {0x0F, 0x00, 0x00}, 0, 2, 158 }, + { SUF_Z, ONLY_AVX, CPU_AES, CPU_AVX, 0, {MOD_Op1Add, MOD_Op2Add, 0}, 0, 0, 0xC1, 3, {0x0F, 0x00, 0x00}, 0, 3, 12 } +}; + +static const x86_insn_info aesimc_insn[] = { + { SUF_Z, 0, CPU_AES, 0, 0, {MOD_Op1Add, MOD_Op2Add, MOD_SetVEX}, 0, 0, 0x66, 3, {0x0F, 0x00, 0x00}, 0, 2, 155 } +}; + +static const x86_insn_info aes_imm_insn[] = { + { SUF_Z, 0, CPU_AES, 0, 0, {MOD_Op1Add, MOD_Op2Add, MOD_SetVEX}, 0, 0, 0x66, 3, {0x0F, 0x00, 0x00}, 0, 3, 185 } +}; + +static const x86_insn_info pclmulqdq_insn[] = { + { SUF_Z, 0, CPU_CLMUL, 0, 0, {MOD_Op1Add, MOD_Op2Add, MOD_SetVEX}, 0, 0, 0x66, 3, {0x0F, 0x00, 0x00}, 0, 3, 158 }, + { SUF_Z, ONLY_AVX, CPU_AVX, CPU_CLMUL, 0, {MOD_Op1Add, MOD_Op2Add, 0}, 0, 0, 0xC1, 3, {0x0F, 0x00, 0x00}, 0, 4, 60 } +}; + +static const x86_insn_info pclmulqdq_fixed_insn[] = { + { SUF_Z, 0, CPU_CLMUL, 0, 0, {MOD_Imm8, MOD_SetVEX, 0}, 0, 0, 0x66, 3, {0x0F, 0x3A, 0x44}, 0, 2, 158 }, + { SUF_Z, ONLY_AVX, CPU_AVX, CPU_CLMUL, 0, {MOD_Imm8, 0, 0}, 0, 0, 0xC1, 3, {0x0F, 0x3A, 0x44}, 0, 3, 12 } +}; + +static const x86_insn_info rdrand_insn[] = { + { SUF_Z, 0, 0, 0, 0, {MOD_SpAdd, 0, 0}, 16, 0, 0, 2, {0x0F, 0xC7, 0}, 0, 1, 395 }, + { SUF_Z, 0, CPU_386, 0, 0, {MOD_SpAdd, 0, 0}, 32, 0, 0, 2, {0x0F, 0xC7, 0}, 0, 1, 26 }, + { SUF_Z, ONLY_64, 0, 0, 0, {MOD_SpAdd, 0, 0}, 64, 0, 0, 2, {0x0F, 0xC7, 0}, 0, 1, 30 } +}; + +static const x86_insn_info fs_gs_base_insn[] = { + { SUF_Z, ONLY_64, CPU_FSGSBASE, 0, 0, {MOD_SpAdd, 0, 0}, 32, 0, 0xF3, 2, {0x0F, 0xAE, 0}, 0, 1, 26 }, + { SUF_Z, ONLY_64, CPU_FSGSBASE, 0, 0, {MOD_SpAdd, 0, 0}, 64, 0, 0xF3, 2, {0x0F, 0xAE, 0}, 0, 1, 30 } +}; + +static const x86_insn_info avx_cvtps2ph_insn[] = { + { SUF_Z, ONLY_AVX, CPU_AVX, CPU_F16C, 0, {MOD_PreAdd, MOD_Op2Add, 0}, 0, 0, 0xC0, 3, {0x0F, 0x3A, 0x00}, 0, 3, 209 }, + { SUF_Z, ONLY_AVX, CPU_AVX, CPU_F16C, 0, {MOD_PreAdd, MOD_Op2Add, 0}, 0, 0, 0xC0, 3, {0x0F, 0x3A, 0x00}, 0, 3, 212 }, + { SUF_Z, ONLY_AVX, CPU_AVX, CPU_F16C, 0, {MOD_PreAdd, MOD_Op2Add, 0}, 0, 0, 0xC4, 3, {0x0F, 0x3A, 0x00}, 0, 3, 215 }, + { SUF_Z, ONLY_AVX, CPU_AVX, CPU_F16C, 0, {MOD_PreAdd, MOD_Op2Add, 0}, 0, 0, 0xC4, 3, {0x0F, 0x3A, 0x00}, 0, 3, 218 } +}; + +static const x86_insn_info avx_cvtph2ps_insn[] = { + { SUF_Z, ONLY_AVX, CPU_AVX, CPU_F16C, 0, {MOD_PreAdd, MOD_Op2Add, 0}, 0, 0, 0xC0, 3, {0x0F, 0x38, 0x00}, 0, 2, 64 }, + { SUF_Z, ONLY_AVX, CPU_AVX, CPU_F16C, 0, {MOD_PreAdd, MOD_Op2Add, 0}, 0, 0, 0xC0, 3, {0x0F, 0x38, 0x00}, 0, 2, 631 }, + { SUF_Z, ONLY_AVX, CPU_AVX, CPU_F16C, 0, {MOD_PreAdd, MOD_Op2Add, 0}, 0, 0, 0xC4, 3, {0x0F, 0x38, 0x00}, 0, 2, 208 }, + { SUF_Z, ONLY_AVX, CPU_AVX, CPU_F16C, 0, {MOD_PreAdd, MOD_Op2Add, 0}, 0, 0, 0xC4, 3, {0x0F, 0x38, 0x00}, 0, 2, 633 } +}; + +static const x86_insn_info extrq_insn[] = { + { SUF_Z, 0, CPU_SSE4a, 0, 0, {0, 0, 0}, 0, 0, 0x66, 2, {0x0F, 0x78, 0}, 0, 3, 65 }, + { SUF_Z, 0, CPU_SSE4a, 0, 0, {0, 0, 0}, 0, 0, 0x66, 2, {0x0F, 0x79, 0}, 0, 2, 64 } +}; + +static const x86_insn_info insertq_insn[] = { + { SUF_Z, 0, CPU_SSE4a, 0, 0, {0, 0, 0}, 0, 0, 0xF2, 2, {0x0F, 0x78, 0}, 0, 4, 64 }, + { SUF_Z, 0, CPU_SSE4a, 0, 0, {0, 0, 0}, 0, 0, 0xF2, 2, {0x0F, 0x79, 0}, 0, 2, 64 } +}; + +static const x86_insn_info movntsd_insn[] = { + { SUF_Z, 0, CPU_SSE4a, 0, 0, {0, 0, 0}, 0, 0, 0xF2, 2, {0x0F, 0x2B, 0}, 0, 2, 47 } +}; + +static const x86_insn_info movntss_insn[] = { + { SUF_Z, 0, CPU_SSE4a, 0, 0, {0, 0, 0}, 0, 0, 0xF3, 2, {0x0F, 0x2B, 0}, 0, 2, 450 } +}; + +static const x86_insn_info vfrc_pdps_insn[] = { + { SUF_Z, 0, CPU_XOP, 0, 0, {MOD_Op1Add, 0, 0}, 0, 0, 0x80, 2, {0x09, 0x80, 0}, 0, 2, 155 }, + { SUF_Z, 0, CPU_XOP, 0, 0, {MOD_Op1Add, 0, 0}, 0, 0, 0x84, 2, {0x09, 0x80, 0}, 0, 2, 191 } +}; + +static const x86_insn_info vfrczsd_insn[] = { + { SUF_Z, 0, CPU_XOP, 0, 0, {0, 0, 0}, 0, 0, 0x80, 2, {0x09, 0x83, 0}, 0, 2, 64 }, + { SUF_Z, 0, CPU_XOP, 0, 0, {0, 0, 0}, 0, 0, 0x80, 2, {0x09, 0x83, 0}, 0, 2, 451 } +}; + +static const x86_insn_info vfrczss_insn[] = { + { SUF_Z, 0, CPU_XOP, 0, 0, {0, 0, 0}, 0, 0, 0x80, 2, {0x09, 0x82, 0}, 0, 2, 64 }, + { SUF_Z, 0, CPU_XOP, 0, 0, {0, 0, 0}, 0, 0, 0x80, 2, {0x09, 0x82, 0}, 0, 2, 336 } +}; + +static const x86_insn_info vpcmov_insn[] = { + { SUF_Z, 0, CPU_XOP, 0, 0, {0, 0, 0}, 0, 0, 0x80, 2, {0x08, 0xA2, 0}, 0, 4, 12 }, + { SUF_Z, 0, CPU_XOP, 0, 0, {0, 0, 0}, 0, 0, 0x88, 2, {0x08, 0xA2, 0}, 0, 4, 68 }, + { SUF_Z, 0, CPU_XOP, 0, 0, {0, 0, 0}, 0, 0, 0x84, 2, {0x08, 0xA2, 0}, 0, 4, 16 }, + { SUF_Z, 0, CPU_XOP, 0, 0, {0, 0, 0}, 0, 0, 0x8C, 2, {0x08, 0xA2, 0}, 0, 4, 72 } +}; + +static const x86_insn_info vpcom_insn[] = { + { SUF_Z, 0, CPU_XOP, 0, 0, {MOD_Op1Add, MOD_Imm8, 0}, 0, 0, 0x80, 2, {0x08, 0x00, 0}, 0, 3, 12 } +}; + +static const x86_insn_info vpcom_imm_insn[] = { + { SUF_Z, 0, CPU_XOP, 0, 0, {MOD_Op1Add, 0, 0}, 0, 0, 0x80, 2, {0x08, 0x00, 0}, 0, 4, 60 } +}; + +static const x86_insn_info vphaddsub_insn[] = { + { SUF_Z, 0, CPU_XOP, 0, 0, {MOD_Op1Add, 0, 0}, 0, 0, 0x80, 2, {0x09, 0x00, 0}, 0, 2, 155 } +}; + +static const x86_insn_info vpma_insn[] = { + { SUF_Z, 0, CPU_XOP, 0, 0, {MOD_Op1Add, 0, 0}, 0, 0, 0x80, 2, {0x08, 0x00, 0}, 0, 4, 12 } +}; + +static const x86_insn_info vpperm_insn[] = { + { SUF_Z, 0, CPU_XOP, 0, 0, {0, 0, 0}, 0, 0, 0x80, 2, {0x08, 0xA3, 0}, 0, 4, 12 }, + { SUF_Z, 0, CPU_XOP, 0, 0, {0, 0, 0}, 0, 0, 0x88, 2, {0x08, 0xA3, 0}, 0, 4, 68 } +}; + +static const x86_insn_info vprot_insn[] = { + { SUF_Z, 0, CPU_XOP, 0, 0, {MOD_Op1Add, 0, 0}, 0, 0, 0x80, 2, {0x09, 0x90, 0}, 0, 3, 155 }, + { SUF_Z, 0, CPU_XOP, 0, 0, {MOD_Op1Add, 0, 0}, 0, 0, 0x88, 2, {0x09, 0x90, 0}, 0, 3, 12 }, + { SUF_Z, 0, CPU_XOP, 0, 0, {MOD_Op1Add, 0, 0}, 0, 0, 0x80, 2, {0x08, 0xC0, 0}, 0, 3, 185 } +}; + +static const x86_insn_info amd_vpshift_insn[] = { + { SUF_Z, 0, CPU_XOP, 0, 0, {MOD_Op1Add, 0, 0}, 0, 0, 0x80, 2, {0x09, 0x00, 0}, 0, 3, 155 }, + { SUF_Z, 0, CPU_XOP, 0, 0, {MOD_Op1Add, 0, 0}, 0, 0, 0x88, 2, {0x09, 0x00, 0}, 0, 3, 12 } +}; + +static const x86_insn_info fma_128_256_insn[] = { + { SUF_Z, ONLY_AVX, CPU_FMA4, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0xC1, 3, {0x0F, 0x3A, 0x00}, 0, 4, 12 }, + { SUF_Z, ONLY_AVX, CPU_FMA4, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0xC9, 3, {0x0F, 0x3A, 0x00}, 0, 4, 68 }, + { SUF_Z, ONLY_AVX, CPU_FMA4, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0xC5, 3, {0x0F, 0x3A, 0x00}, 0, 4, 16 }, + { SUF_Z, ONLY_AVX, CPU_FMA4, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0xCD, 3, {0x0F, 0x3A, 0x00}, 0, 4, 72 } +}; + +static const x86_insn_info fma_128_m32_insn[] = { + { SUF_Z, ONLY_AVX, CPU_FMA4, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0xC1, 3, {0x0F, 0x3A, 0x00}, 0, 4, 36 }, + { SUF_Z, ONLY_AVX, CPU_FMA4, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0xC1, 3, {0x0F, 0x3A, 0x00}, 0, 4, 76 }, + { SUF_Z, ONLY_AVX, CPU_FMA4, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0xC9, 3, {0x0F, 0x3A, 0x00}, 0, 4, 80 } +}; + +static const x86_insn_info fma_128_m64_insn[] = { + { SUF_Z, ONLY_AVX, CPU_FMA4, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0xC1, 3, {0x0F, 0x3A, 0x00}, 0, 4, 36 }, + { SUF_Z, ONLY_AVX, CPU_FMA4, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0xC1, 3, {0x0F, 0x3A, 0x00}, 0, 4, 40 }, + { SUF_Z, ONLY_AVX, CPU_FMA4, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0xC9, 3, {0x0F, 0x3A, 0x00}, 0, 4, 44 } +}; + +static const x86_insn_info xsaveopt64_insn[] = { + { SUF_Z, ONLY_64, 0, 0, 0, {MOD_SpAdd, MOD_Op0Add, MOD_Op1Add}, 64, 0, 0, 2, {0x00, 0x00, 0}, 0, 1, 532 } +}; + +static const x86_insn_info movbe_insn[] = { + { SUF_Z, 0, CPU_MOVBE, 0, 0, {0, 0, 0}, 16, 0, 0, 3, {0x0F, 0x38, 0xF0}, 0, 2, 465 }, + { SUF_Z, 0, CPU_MOVBE, 0, 0, {0, 0, 0}, 16, 0, 0, 3, {0x0F, 0x38, 0xF1}, 0, 2, 467 }, + { SUF_Z, 0, CPU_386, CPU_MOVBE, 0, {0, 0, 0}, 32, 0, 0, 3, {0x0F, 0x38, 0xF0}, 0, 2, 359 }, + { SUF_Z, 0, CPU_386, CPU_MOVBE, 0, {0, 0, 0}, 32, 0, 0, 3, {0x0F, 0x38, 0xF1}, 0, 2, 337 }, + { SUF_Z, ONLY_64, CPU_MOVBE, 0, 0, {0, 0, 0}, 64, 0, 0, 3, {0x0F, 0x38, 0xF0}, 0, 2, 469 }, + { SUF_Z, ONLY_64, CPU_MOVBE, 0, 0, {0, 0, 0}, 64, 0, 0, 3, {0x0F, 0x38, 0xF1}, 0, 2, 339 } +}; + +static const x86_insn_info vex_gpr_ndd_rm_0F38_regext_insn[] = { + { SUF_L|SUF_Z, ONLY_AVX, CPU_386, 0, 0, {MOD_PreAdd, MOD_Op2Add, MOD_SpAdd}, 32, 0, 0xC0, 3, {0x0F, 0x38, 0x00}, 0, 2, 255 }, + { SUF_Q|SUF_Z, ONLY_64|ONLY_AVX, 0, 0, 0, {MOD_PreAdd, MOD_Op2Add, MOD_SpAdd}, 64, 0, 0xC0, 3, {0x0F, 0x38, 0x00}, 0, 2, 258 } +}; + +static const x86_insn_info vex_gpr_reg_rm_0F_imm8_insn[] = { + { SUF_L|SUF_Z, ONLY_AVX, CPU_386, 0, 0, {MOD_PreAdd, MOD_Op1Add, MOD_Op2Add}, 32, 0, 0xC0, 3, {0x0F, 0x00, 0x00}, 0, 3, 134 }, + { SUF_Q|SUF_Z, ONLY_64|ONLY_AVX, 0, 0, 0, {MOD_PreAdd, MOD_Op1Add, MOD_Op2Add}, 64, 0, 0xC0, 3, {0x0F, 0x00, 0x00}, 0, 3, 137 } +}; + +static const x86_insn_info vex_gpr_reg_nds_rm_0F_insn[] = { + { SUF_L|SUF_Z, ONLY_AVX, CPU_386, 0, 0, {MOD_PreAdd, MOD_Op1Add, MOD_Op2Add}, 32, 0, 0xC0, 3, {0x0F, 0x00, 0x00}, 0, 3, 254 }, + { SUF_Q|SUF_Z, ONLY_64|ONLY_AVX, 0, 0, 0, {MOD_PreAdd, MOD_Op1Add, MOD_Op2Add}, 64, 0, 0xC0, 3, {0x0F, 0x00, 0x00}, 0, 3, 257 } +}; + +static const x86_insn_info vex_gpr_reg_rm_nds_0F_insn[] = { + { SUF_L|SUF_Z, ONLY_AVX, CPU_386, 0, 0, {MOD_PreAdd, MOD_Op1Add, MOD_Op2Add}, 32, 0, 0xC0, 3, {0x0F, 0x00, 0x00}, 0, 3, 149 }, + { SUF_Q|SUF_Z, ONLY_64|ONLY_AVX, 0, 0, 0, {MOD_PreAdd, MOD_Op1Add, MOD_Op2Add}, 64, 0, 0xC0, 3, {0x0F, 0x00, 0x00}, 0, 3, 152 } +}; + +static const x86_insn_info bextr_insn[] = { + { SUF_L|SUF_Z, ONLY_AVX, CPU_386, CPU_BMI1, 0, {0, 0, 0}, 32, 0, 0xC0, 3, {0x0F, 0x38, 0xF7}, 0, 3, 149 }, + { SUF_L|SUF_Z, ONLY_AVX, CPU_386, CPU_TBM, 0, {0, 0, 0}, 32, 0, 0x80, 2, {0x0A, 0x10, 0}, 0, 3, 230 }, + { SUF_Q|SUF_Z, ONLY_64|ONLY_AVX, CPU_BMI1, 0, 0, {0, 0, 0}, 64, 0, 0xC0, 3, {0x0F, 0x38, 0xF7}, 0, 3, 152 }, + { SUF_Q|SUF_Z, ONLY_64|ONLY_AVX, CPU_TBM, 0, 0, {0, 0, 0}, 64, 0, 0x88, 2, {0x0A, 0x10, 0}, 0, 3, 233 } +}; + +static const x86_insn_info invpcid_insn[] = { + { SUF_Z, NOT_64, CPU_386, CPU_INVPCID, CPU_Priv, {0, 0, 0}, 0, 0, 0x66, 3, {0x0F, 0x38, 0x82}, 0, 2, 611 }, + { SUF_Z, ONLY_64, CPU_INVPCID, CPU_Priv, 0, {0, 0, 0}, 0, 64, 0x66, 3, {0x0F, 0x38, 0x82}, 0, 2, 613 } +}; + +static const x86_insn_info intel_SHA1MSG1_insn[] = { + { SUF_Z, 0, CPU_SHA, 0, 0, {0, 0, 0}, 0, 0, 0, 3, {0x0F, 0x38, 0xC9}, 0, 2, 155 } +}; + +static const x86_insn_info intel_SHA1MSG2_insn[] = { + { SUF_Z, 0, CPU_SHA, 0, 0, {0, 0, 0}, 0, 0, 0, 3, {0x0F, 0x38, 0xCA}, 0, 2, 155 } +}; + +static const x86_insn_info intel_SHA1NEXTE_insn[] = { + { SUF_Z, 0, CPU_SHA, 0, 0, {0, 0, 0}, 0, 0, 0, 3, {0x0F, 0x38, 0xC8}, 0, 2, 155 } +}; + +static const x86_insn_info intel_SHA1RNDS4_insn[] = { + { SUF_Z, 0, CPU_SHA, 0, 0, {0, 0, 0}, 0, 0, 0, 3, {0x0F, 0x3A, 0xCC}, 0, 3, 185 } +}; + +static const x86_insn_info intel_SHA256MSG1_insn[] = { + { SUF_Z, 0, CPU_SHA, 0, 0, {0, 0, 0}, 0, 0, 0, 3, {0x0F, 0x38, 0xCC}, 0, 2, 155 } +}; + +static const x86_insn_info intel_SHA256MSG2_insn[] = { + { SUF_Z, 0, CPU_SHA, 0, 0, {0, 0, 0}, 0, 0, 0, 3, {0x0F, 0x38, 0xCD}, 0, 2, 155 } +}; + +static const x86_insn_info intel_SHA256RNDS2_insn[] = { + { SUF_Z, 0, CPU_SHA, 0, 0, {0, 0, 0}, 0, 0, 0, 3, {0x0F, 0x38, 0xCB}, 0, 2, 64 } +}; + +static const x86_insn_info vex_gpr_ndd_rm_0F38_insn[] = { + { SUF_L|SUF_Z, 0, CPU_386, 0, 0, {MOD_PreAdd, MOD_Op2Add, 0}, 32, 0, 0x00, 3, {0x0F, 0x38, 0x00}, 0, 2, 101 }, + { SUF_Q|SUF_Z, ONLY_64, 0, 0, 0, {MOD_PreAdd, MOD_Op2Add, 0}, 64, 0, 0x00, 3, {0x0F, 0x38, 0x00}, 0, 2, 104 } +}; + +static const x86_insn_info xop_gpr_reg_rm_09_insn[] = { + { SUF_L|SUF_Z, 0, CPU_386, CPU_TBM, 0, {MOD_Op1Add, MOD_SpAdd, 0}, 32, 0, 0x80, 2, {0x09, 0x00, 0}, 0, 2, 255 }, + { SUF_Q|SUF_Z, ONLY_64, CPU_TBM, 0, 0, {MOD_Op1Add, MOD_SpAdd, 0}, 64, 0, 0x88, 2, {0x09, 0x00, 0}, 0, 2, 258 } +}; + +static const x86_insn_info now3d_insn[] = { + { SUF_Z, 0, CPU_3DNow, 0, 0, {MOD_Imm8, 0, 0}, 0, 0, 0, 2, {0x0F, 0x0F, 0}, 0, 2, 140 } +}; + +static const x86_insn_info cmpxchg16b_insn[] = { + { SUF_Z, ONLY_64, 0, 0, 0, {0, 0, 0}, 64, 0, 0, 2, {0x0F, 0xC7, 0}, 1, 1, 510 } +}; + +static const x86_insn_info invlpga_insn[] = { + { SUF_Z, 0, CPU_SVM, 0, 0, {0, 0, 0}, 0, 0, 0, 3, {0x0F, 0x01, 0xDF}, 0, 0, 0 }, + { SUF_Z, 0, CPU_386, CPU_SVM, 0, {0, 0, 0}, 0, 0, 0, 3, {0x0F, 0x01, 0xDF}, 0, 2, 515 } +}; + +static const x86_insn_info skinit_insn[] = { + { SUF_Z, 0, CPU_SVM, 0, 0, {0, 0, 0}, 0, 0, 0, 3, {0x0F, 0x01, 0xDE}, 0, 0, 0 }, + { SUF_Z, 0, CPU_SVM, 0, 0, {0, 0, 0}, 0, 0, 0, 3, {0x0F, 0x01, 0xDE}, 0, 1, 655 } +}; + +static const x86_insn_info svm_rax_insn[] = { + { SUF_Z, 0, CPU_SVM, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0, 3, {0x0F, 0x01, 0x00}, 0, 0, 0 }, + { SUF_Z, 0, CPU_SVM, 0, 0, {MOD_Op2Add, 0, 0}, 0, 0, 0, 3, {0x0F, 0x01, 0x00}, 0, 1, 515 } +}; + +static const x86_insn_info padlock_insn[] = { + { SUF_Z, 0, CPU_PadLock, 0, 0, {MOD_Imm8, MOD_PreAdd, MOD_Op1Add}, 0, 0, 0x00, 2, {0x0F, 0x00, 0}, 0, 0, 0 } +}; + +static const x86_insn_info cyrixmmx_insn[] = { + { SUF_Z, 0, CPU_Cyrix, CPU_MMX, 0, {MOD_Op1Add, 0, 0}, 0, 0, 0, 2, {0x0F, 0x00, 0}, 0, 2, 140 } +}; + +static const x86_insn_info pmachriw_insn[] = { + { SUF_Z, 0, CPU_Cyrix, CPU_MMX, 0, {0, 0, 0}, 0, 0, 0, 2, {0x0F, 0x5E, 0}, 0, 2, 317 } +}; + +static const x86_insn_info rdwrshr_insn[] = { + { SUF_Z, 0, CPU_686, CPU_Cyrix, CPU_SMM, {MOD_Op1Add, 0, 0}, 0, 0, 0, 2, {0x0F, 0x36, 0}, 0, 1, 90 } +}; + +static const x86_insn_info rsdc_insn[] = { + { SUF_Z, 0, CPU_486, CPU_Cyrix, CPU_SMM, {0, 0, 0}, 0, 0, 0, 2, {0x0F, 0x79, 0}, 0, 2, 629 } +}; + +static const x86_insn_info cyrixsmm_insn[] = { + { SUF_Z, 0, CPU_486, CPU_Cyrix, CPU_SMM, {MOD_Op1Add, 0, 0}, 0, 0, 0, 2, {0x0F, 0x00, 0}, 0, 1, 619 } +}; + +static const x86_insn_info svdc_insn[] = { + { SUF_Z, 0, CPU_486, CPU_Cyrix, CPU_SMM, {0, 0, 0}, 0, 0, 0, 2, {0x0F, 0x78, 0}, 0, 2, 619 } +}; + +static const x86_insn_info ibts_insn[] = { + { SUF_Z, 0, CPU_386, CPU_Obs, CPU_Undoc, {0, 0, 0}, 16, 0, 0, 2, {0x0F, 0xA7, 0}, 0, 2, 260 }, + { SUF_Z, 0, CPU_386, CPU_Obs, CPU_Undoc, {0, 0, 0}, 32, 0, 0, 2, {0x0F, 0xA7, 0}, 0, 2, 266 } +}; + +static const x86_insn_info umov_insn[] = { + { SUF_Z, 0, CPU_386, CPU_Undoc, 0, {0, 0, 0}, 0, 0, 0, 2, {0x0F, 0x10, 0}, 0, 2, 323 }, + { SUF_Z, 0, CPU_386, CPU_Undoc, 0, {0, 0, 0}, 16, 0, 0, 2, {0x0F, 0x11, 0}, 0, 2, 260 }, + { SUF_Z, 0, CPU_386, CPU_Undoc, 0, {0, 0, 0}, 32, 0, 0, 2, {0x0F, 0x11, 0}, 0, 2, 266 }, + { SUF_Z, 0, CPU_386, CPU_Undoc, 0, {0, 0, 0}, 0, 0, 0, 2, {0x0F, 0x12, 0}, 0, 2, 325 }, + { SUF_Z, 0, CPU_386, CPU_Undoc, 0, {0, 0, 0}, 16, 0, 0, 2, {0x0F, 0x13, 0}, 0, 2, 98 }, + { SUF_Z, 0, CPU_386, CPU_Undoc, 0, {0, 0, 0}, 32, 0, 0, 2, {0x0F, 0x13, 0}, 0, 2, 101 } +}; + +static const x86_insn_info xbts_insn[] = { + { SUF_Z, 0, CPU_386, CPU_Obs, CPU_Undoc, {0, 0, 0}, 16, 0, 0, 2, {0x0F, 0xA6, 0}, 0, 2, 465 }, + { SUF_Z, 0, CPU_386, CPU_Obs, CPU_Undoc, {0, 0, 0}, 32, 0, 0, 2, {0x0F, 0xA6, 0}, 0, 2, 359 } +}; + + diff --git a/contrib/tools/yasm/modules/x86regtmod.c b/contrib/tools/yasm/modules/x86regtmod.c new file mode 100644 index 0000000000..cdec3577e2 --- /dev/null +++ b/contrib/tools/yasm/modules/x86regtmod.c @@ -0,0 +1,261 @@ +/* ANSI-C code produced by genperf */ + +#include <util.h> + +#include <ctype.h> +#include <libyasm.h> +#include <libyasm/phash.h> + +#include "modules/arch/x86/x86arch.h" + +enum regtmod_type { + REG = 1, + REGGROUP, + SEGREG, + TARGETMOD +}; +struct regtmod_parse_data { + const char *name; + unsigned int type:8; /* regtmod_type */ + + /* REG: register size + * SEGREG: prefix encoding + * Others: 0 + */ + unsigned int size_prefix:8; + + /* REG: register index + * REGGROUP: register group type + * SEGREG: register encoding + * TARGETMOD: target modifier + */ + unsigned int data:8; + + /* REG: required bits setting + * SEGREG: BITS in which the segment is ignored + * Others: 0 + */ + unsigned int bits:8; +}; +static const struct regtmod_parse_data * +regtmod_find(const char *key, size_t len) +{ + static const struct regtmod_parse_data pd[152] = { + {"st6", REG, X86_FPUREG, 6, 0}, + {"ymm1", REG, X86_YMMREG, 1, 0}, + {"rsp", REG, X86_REG64, 4, 64}, + {"r10", REG, X86_REG64, 10, 64}, + {"bp", REG, X86_REG16, 5, 0}, + {"r10b", REG, X86_REG8, 10, 64}, + {"mm2", REG, X86_MMXREG, 2, 0}, + {"rdi", REG, X86_REG64, 7, 64}, + {"ymm12", REG, X86_YMMREG, 12, 64}, + {"r8", REG, X86_REG64, 8, 64}, + {"gs", SEGREG, 0x65, 0x05, 0}, + {"r10d", REG, X86_REG32, 10, 64}, + {"rsi", REG, X86_REG64, 6, 64}, + {"eax", REG, X86_REG32, 0, 0}, + {"mm3", REG, X86_MMXREG, 3, 0}, + {"tr6", REG, X86_TRREG, 6, 0}, + {"tr0", REG, X86_TRREG, 0, 0}, + {"ah", REG, X86_REG8, 4, 0}, + {"xmm6", REG, X86_XMMREG, 6, 0}, + {"dr6", REG, X86_DRREG, 6, 0}, + {"esp", REG, X86_REG32, 4, 0}, + {"bpl", REG, X86_REG8X, 5, 64}, + {"tr5", REG, X86_TRREG, 5, 0}, + {"ax", REG, X86_REG16, 0, 0}, + {"sp", REG, X86_REG16, 4, 0}, + {"r15b", REG, X86_REG8, 15, 64}, + {"xmm14", REG, X86_XMMREG, 14, 64}, + {"xmm12", REG, X86_XMMREG, 12, 64}, + {"r11", REG, X86_REG64, 11, 64}, + {"xmm", REGGROUP, 0, X86_XMMREG, 0}, + {"ymm2", REG, X86_YMMREG, 2, 0}, + {"ebp", REG, X86_REG32, 5, 0}, + {"xmm8", REG, X86_XMMREG, 8, 64}, + {"r12d", REG, X86_REG32, 12, 64}, + {"ymm4", REG, X86_YMMREG, 4, 0}, + {"ymm3", REG, X86_YMMREG, 3, 0}, + {"rax", REG, X86_REG64, 0, 64}, + {"xmm3", REG, X86_XMMREG, 3, 0}, + {"xmm0", REG, X86_XMMREG, 0, 0}, + {"dr7", REG, X86_DRREG, 7, 0}, + {"r14w", REG, X86_REG16, 14, 64}, + {"mm1", REG, X86_MMXREG, 1, 0}, + {"bl", REG, X86_REG8, 3, 0}, + {"r9w", REG, X86_REG16, 9, 64}, + {"ymm13", REG, X86_YMMREG, 13, 64}, + {"r9b", REG, X86_REG8, 9, 64}, + {"ymm8", REG, X86_YMMREG, 8, 64}, + {"dx", REG, X86_REG16, 2, 0}, + {"r12", REG, X86_REG64, 12, 64}, + {"r12w", REG, X86_REG16, 12, 64}, + {"r9", REG, X86_REG64, 9, 64}, + {"r15w", REG, X86_REG16, 15, 64}, + {"sil", REG, X86_REG8X, 6, 64}, + {"r10w", REG, X86_REG16, 10, 64}, + {"ymm6", REG, X86_YMMREG, 6, 0}, + {"ss", SEGREG, 0x36, 0x02, 64}, + {"tr4", REG, X86_TRREG, 4, 0}, + {"cr3", REG, X86_CRREG, 3, 0}, + {"r11w", REG, X86_REG16, 11, 64}, + {"xmm4", REG, X86_XMMREG, 4, 0}, + {"st0", REG, X86_FPUREG, 0, 0}, + {"dil", REG, X86_REG8X, 7, 64}, + {"tr3", REG, X86_TRREG, 3, 0}, + {"r13d", REG, X86_REG32, 13, 64}, + {"r8w", REG, X86_REG16, 8, 64}, + {"xmm13", REG, X86_XMMREG, 13, 64}, + {"st3", REG, X86_FPUREG, 3, 0}, + {"xmm15", REG, X86_XMMREG, 15, 64}, + {"xmm10", REG, X86_XMMREG, 10, 64}, + {"es", SEGREG, 0x26, 0x00, 64}, + {"cr8", REG, X86_CRREG, 8, 64}, + {"xmm7", REG, X86_XMMREG, 7, 0}, + {"spl", REG, X86_REG8X, 4, 64}, + {"r15", REG, X86_REG64, 15, 64}, + {"cr4", REG, X86_CRREG, 4, 0}, + {"fs", SEGREG, 0x64, 0x04, 0}, + {"rcx", REG, X86_REG64, 1, 64}, + {"mm0", REG, X86_MMXREG, 0, 0}, + {"mm", REGGROUP, 0, X86_MMXREG, 0}, + {"tr1", REG, X86_TRREG, 1, 0}, + {"short", TARGETMOD, 0, X86_SHORT, 0}, + {"st4", REG, X86_FPUREG, 4, 0}, + {"cr0", REG, X86_CRREG, 0, 0}, + {"xmm11", REG, X86_XMMREG, 11, 64}, + {"mm4", REG, X86_MMXREG, 4, 0}, + {"bh", REG, X86_REG8, 7, 0}, + {"r15d", REG, X86_REG32, 15, 64}, + {"dr2", REG, X86_DRREG, 2, 0}, + {"r8d", REG, X86_REG32, 8, 64}, + {"ymm7", REG, X86_YMMREG, 7, 0}, + {"xmm9", REG, X86_XMMREG, 9, 64}, + {"r12b", REG, X86_REG8, 12, 64}, + {"st2", REG, X86_FPUREG, 2, 0}, + {"ymm9", REG, X86_YMMREG, 9, 64}, + {"st7", REG, X86_FPUREG, 7, 0}, + {"bx", REG, X86_REG16, 3, 0}, + {"ymm11", REG, X86_YMMREG, 11, 64}, + {"ymm5", REG, X86_YMMREG, 5, 0}, + {"ymm15", REG, X86_YMMREG, 15, 64}, + {"rbp", REG, X86_REG64, 5, 64}, + {"r13", REG, X86_REG64, 13, 64}, + {"mm5", REG, X86_MMXREG, 5, 0}, + {"si", REG, X86_REG16, 6, 0}, + {"dl", REG, X86_REG8, 2, 0}, + {"di", REG, X86_REG16, 7, 0}, + {"cr2", REG, X86_CRREG, 2, 0}, + {"r14d", REG, X86_REG32, 14, 64}, + {"ymm14", REG, X86_YMMREG, 14, 64}, + {"tr7", REG, X86_TRREG, 7, 0}, + {"ds", SEGREG, 0x3e, 0x03, 64}, + {"cx", REG, X86_REG16, 1, 0}, + {"st", REGGROUP, 0, X86_FPUREG, 0}, + {"edi", REG, X86_REG32, 7, 0}, + {"al", REG, X86_REG8, 0, 0}, + {"mm7", REG, X86_MMXREG, 7, 0}, + {"ebx", REG, X86_REG32, 3, 0}, + {"xmm2", REG, X86_XMMREG, 2, 0}, + {"st5", REG, X86_FPUREG, 5, 0}, + {"rip", REG, X86_RIP, 0, 64}, + {"rbx", REG, X86_REG64, 3, 64}, + {"to", TARGETMOD, 0, X86_TO, 0}, + {"r11d", REG, X86_REG32, 11, 64}, + {"dr5", REG, X86_DRREG, 5, 0}, + {"dr1", REG, X86_DRREG, 1, 0}, + {"near", TARGETMOD, 0, X86_NEAR, 0}, + {"r14", REG, X86_REG64, 14, 64}, + {"dh", REG, X86_REG8, 6, 0}, + {"cl", REG, X86_REG8, 1, 0}, + {"dr4", REG, X86_DRREG, 4, 0}, + {"ymm10", REG, X86_YMMREG, 10, 64}, + {"dr3", REG, X86_DRREG, 3, 0}, + {"xmm5", REG, X86_XMMREG, 5, 0}, + {"mm6", REG, X86_MMXREG, 6, 0}, + {"r13w", REG, X86_REG16, 13, 64}, + {"far", TARGETMOD, 0, X86_FAR, 0}, + {"ymm0", REG, X86_YMMREG, 0, 0}, + {"ymm", REGGROUP, 0, X86_YMMREG, 0}, + {"ch", REG, X86_REG8, 5, 0}, + {"xmm1", REG, X86_XMMREG, 1, 0}, + {"esi", REG, X86_REG32, 6, 0}, + {"r14b", REG, X86_REG8, 14, 64}, + {"st1", REG, X86_FPUREG, 1, 0}, + {"r8b", REG, X86_REG8, 8, 64}, + {"r11b", REG, X86_REG8, 11, 64}, + {"r13b", REG, X86_REG8, 13, 64}, + {"ecx", REG, X86_REG32, 1, 0}, + {"tr2", REG, X86_TRREG, 2, 0}, + {"rdx", REG, X86_REG64, 2, 64}, + {"r9d", REG, X86_REG32, 9, 64}, + {"cs", SEGREG, 0x2e, 0x01, 0}, + {"dr0", REG, X86_DRREG, 0, 0}, + {"edx", REG, X86_REG32, 2, 0} + }; + static const unsigned char tab[] = { + 0,0,125,22,0,0,85,0,85,168,0,0,0,7,113,0, + 0,0,0,22,183,0,0,11,42,55,0,0,82,0,88,235, + 0,0,0,0,0,0,183,85,0,0,145,113,220,125,22,0, + 88,183,0,7,0,0,0,7,0,125,113,87,131,116,7,0, + 113,7,0,113,0,87,87,7,7,7,113,40,85,125,113,85, + 0,0,22,235,0,131,125,113,0,22,0,220,0,220,0,120, + 116,0,124,184,0,0,0,183,92,125,0,92,125,0,0,177, + 7,0,0,7,0,45,0,214,180,113,211,163,142,0,88,173, + }; + + const struct regtmod_parse_data *ret; + unsigned long rsl, val = phash_lookup(key, len, 0x9e3779b9UL); + rsl = ((val>>25)^tab[val&0x7f]); + if (rsl >= 152) return NULL; + ret = &pd[rsl]; + if (strcmp(key, ret->name) != 0) return NULL; + return ret; +} + + + +yasm_arch_regtmod +yasm_x86__parse_check_regtmod(yasm_arch *arch, const char *id, size_t id_len, + uintptr_t *data) +{ + yasm_arch_x86 *arch_x86 = (yasm_arch_x86 *)arch; + /*@null@*/ const struct regtmod_parse_data *pdata; + size_t i; + static char lcaseid[8]; + unsigned int bits; + yasm_arch_regtmod type; + + if (id_len > 7) + return YASM_ARCH_NOTREGTMOD; + for (i=0; i<id_len; i++) + lcaseid[i] = tolower(id[i]); + lcaseid[id_len] = '\0'; + + pdata = regtmod_find(lcaseid, id_len); + if (!pdata) + return YASM_ARCH_NOTREGTMOD; + + type = (yasm_arch_regtmod)pdata->type; + bits = pdata->bits; + + if (type == YASM_ARCH_REG && bits != 0 && arch_x86->mode_bits != bits) { + yasm_warn_set(YASM_WARN_GENERAL, + N_("`%s' is a register in %u-bit mode"), id, bits); + return YASM_ARCH_NOTREGTMOD; + } + + if (type == YASM_ARCH_SEGREG && bits != 0 && arch_x86->mode_bits == bits) { + yasm_warn_set(YASM_WARN_GENERAL, + N_("`%s' segment register ignored in %u-bit mode"), id, + bits); + } + + if (type == YASM_ARCH_SEGREG) + *data = (pdata->size_prefix<<8) | pdata->data; + else + *data = pdata->size_prefix | pdata->data; + return type; +} + diff --git a/contrib/tools/yasm/util.h b/contrib/tools/yasm/util.h new file mode 100644 index 0000000000..4174648a22 --- /dev/null +++ b/contrib/tools/yasm/util.h @@ -0,0 +1,167 @@ +/* + * YASM utility functions. + * + * Includes standard headers and defines prototypes for replacement functions + * if needed. + * + * 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_UTIL_H +#define YASM_UTIL_H + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#if defined(HAVE_GNU_C_LIBRARY) || defined(__MINGW32__) || defined(__DJGPP__) + +/* Work around glibc's non-defining of certain things when using gcc -ansi */ +# ifdef __STRICT_ANSI__ +# undef __STRICT_ANSI__ +# endif + +/* Work around glibc's string inlines (in bits/string2.h) if needed */ +# ifdef NO_STRING_INLINES +# define __NO_STRING_INLINES +# endif + +#endif + +#if !defined(lint) && !defined(NDEBUG) +# define NDEBUG +#endif + +#include <stdio.h> +#include <stdarg.h> + +#include <stddef.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> + +#ifdef HAVE_STRINGS_H +#include <strings.h> +#endif + +#if !defined(_musl_) +#if __linux__ && __x86_64__ +__asm__(".symver memcpy,memcpy@GLIBC_2.2.5"); +#endif +#endif + +#include <libyasm-stdint.h> +#include <libyasm/coretype.h> + +#ifdef lint +# define _(String) String +#else +# ifdef HAVE_LOCALE_H +# include <locale.h> +# endif + +# ifdef ENABLE_NLS +# include <libintl.h> +# define _(String) gettext(String) +# else +# define gettext(Msgid) (Msgid) +# define dgettext(Domainname, Msgid) (Msgid) +# define dcgettext(Domainname, Msgid, Category) (Msgid) +# define textdomain(Domainname) while (0) /* nothing */ +# define bindtextdomain(Domainname, Dirname) while (0) /* nothing */ +# define _(String) (String) +# endif +#endif + +#ifdef gettext_noop +# define N_(String) gettext_noop(String) +#else +# define N_(String) (String) +#endif + +#ifdef HAVE_MERGESORT +#define yasm__mergesort(a, b, c, d) mergesort(a, b, c, d) +#endif + +#ifdef HAVE_STRSEP +#define yasm__strsep(a, b) strsep(a, b) +#endif + +#ifdef HAVE_STRCASECMP +# define yasm__strcasecmp(x, y) strcasecmp(x, y) +# define yasm__strncasecmp(x, y, n) strncasecmp(x, y, n) +#elif HAVE_STRICMP +# define yasm__strcasecmp(x, y) stricmp(x, y) +# define yasm__strncasecmp(x, y, n) strnicmp(x, y, n) +#elif HAVE__STRICMP +# define yasm__strcasecmp(x, y) _stricmp(x, y) +# define yasm__strncasecmp(x, y, n) _strnicmp(x, y, n) +#elif HAVE_STRCMPI +# define yasm__strcasecmp(x, y) strcmpi(x, y) +# define yasm__strncasecmp(x, y, n) strncmpi(x, y, n) +#else +# define USE_OUR_OWN_STRCASECMP +#endif + +#include <libyasm/compat-queue.h> + +#ifdef WITH_DMALLOC +# include <dmalloc.h> +# define yasm__xstrdup(str) xstrdup(str) +# define yasm_xmalloc(size) xmalloc(size) +# define yasm_xcalloc(count, size) xcalloc(count, size) +# define yasm_xrealloc(ptr, size) xrealloc(ptr, size) +# define yasm_xfree(ptr) xfree(ptr) +#endif + +/* Bit-counting: used primarily by HAMT but also in a few other places. */ +#define BC_TWO(c) (0x1ul << (c)) +#define BC_MSK(c) (((unsigned long)(-1)) / (BC_TWO(BC_TWO(c)) + 1ul)) +#define BC_COUNT(x,c) ((x) & BC_MSK(c)) + (((x) >> (BC_TWO(c))) & BC_MSK(c)) +#define BitCount(d, s) do { \ + d = BC_COUNT(s, 0); \ + d = BC_COUNT(d, 1); \ + d = BC_COUNT(d, 2); \ + d = BC_COUNT(d, 3); \ + d = BC_COUNT(d, 4); \ + } while (0) + +/** Determine if a value is exactly a power of 2. Zero is treated as a power + * of two. + * \param x value + * \return Nonzero if x is a power of 2. + */ +#define is_exp2(x) ((x & (x - 1)) == 0) + +#ifndef NELEMS +/** Get the number of elements in an array. + * \internal + * \param array array + * \return Number of elements. + */ +#define NELEMS(array) (sizeof(array) / sizeof(array[0])) +#endif + +char * yasm_replace_path(const char* replace_map[], int size, const char* str, int pref_len); + +#endif diff --git a/contrib/tools/yasm/ya.make b/contrib/tools/yasm/ya.make new file mode 100644 index 0000000000..d1f8adc08f --- /dev/null +++ b/contrib/tools/yasm/ya.make @@ -0,0 +1,24 @@ +# Autogenerated for platforms: +# darwin-x86_64 +# linux-x86_64 +# windows-x86_64 + +OWNER( + somov + g:contrib + g:ymake +) + +VERSION(1.3.0) + +IF (USE_PREBUILT_TOOLS) + INCLUDE(${ARCADIA_ROOT}/build/prebuilt/contrib/tools/yasm/ya.make.prebuilt) +ENDIF() + +IF (NOT PREBUILT) + INCLUDE(${ARCADIA_ROOT}/contrib/tools/yasm/bin/ya.make) +ENDIF() + +RECURSE( + bin +) |