From 1e77ce6c40f369c01672c915ed4afd57eb2a6283 Mon Sep 17 00:00:00 2001 From: Peter Johnson Date: Tue, 7 Oct 2008 05:38:11 +0000 Subject: [PATCH] Add core TASM syntax support. Contributed by: Samuel Thibault It is built on top of the NASM parser and preproc, with the following notable extensions for TASM syntax: - case insensitive symbols and filenames, - support for segment and size of labels, which permits to avoid giving them on each memory dereference, - support for data reservation (i.e. e.g. "var dd ?"), - support for multiples (i.e. e.g. "var dd 1 dup 10"), - little endian string integer constants, - additional expression operators: shl, shr, and, or, low, high, - additional offset keyword, - additional fword and df, - support for doubled quotes within quotes, - support for array-like and structure-like notations: t[eax] and [var].field, - support for tasm directives: macro, rept, irp, locals, proc, struc, segment, assume. Notes: - Almost all extensions are only effective when tasm_compatible_mode is set, so we should have very reduced possible breakage. - Because the "and" keyword can be an expression operator and an instruction name, the data pseudo-instructions explicitly switch the lexer state to INSTRUCTION state to fix the ambiguity. - In gen_x86_insn.py, several instructions (namely lds and lea) now take relaxed memory sizes. The reason is that in the case of tasm, the size of the actual pointed data is passed up to there, and thus any type of data should be accepted. With all of this, loadlin can be compiled by yasm with quite reduced modifications. A new TASM-like frontend is also included. svn path=/trunk/yasm/; revision=2130 --- configure.ac | 2 +- frontends/CMakeLists.txt | 1 + frontends/Makefile.inc | 2 + frontends/tasm/Makefile.inc | 9 + frontends/tasm/tasm-options.c | 140 +++ frontends/tasm/tasm-options.h | 69 ++ frontends/tasm/tasm.c | 1003 +++++++++++++++++ libyasm/bc-align.c | 1 + libyasm/bc-data.c | 168 ++- libyasm/bc-incbin.c | 1 + libyasm/bc-org.c | 1 + libyasm/bc-reserve.c | 9 + libyasm/bytecode.c | 12 + libyasm/bytecode.h | 37 + libyasm/errwarn.c | 3 +- libyasm/errwarn.h | 3 +- libyasm/expr.c | 70 ++ libyasm/expr.h | 10 + libyasm/insn.c | 1 + libyasm/insn.h | 3 + libyasm/intnum.c | 51 +- libyasm/intnum.h | 11 +- libyasm/symrec.c | 71 +- libyasm/symrec.h | 32 + modules/arch/lc3b/lc3bbc.c | 1 + modules/arch/lc3b/lc3bid.re | 1 + modules/arch/x86/gen_x86_insn.py | 8 +- modules/arch/x86/tests/Makefile.inc | 4 +- modules/arch/x86/tests/lds-err.errwarn | 4 - .../arch/x86/tests/{lds-err.asm => lds.asm} | 0 modules/arch/x86/tests/lds.hex | 27 + modules/arch/x86/x86arch.c | 2 + modules/arch/x86/x86arch.h | 3 +- modules/arch/x86/x86bc.c | 6 + modules/arch/x86/x86expr.c | 2 +- modules/arch/x86/x86id.c | 4 + modules/dbgfmts/codeview/cv-symline.c | 4 + modules/dbgfmts/codeview/cv-type.c | 1 + modules/dbgfmts/dwarf2/dwarf2-dbgfmt.c | 1 + modules/dbgfmts/dwarf2/dwarf2-info.c | 1 + modules/dbgfmts/dwarf2/dwarf2-line.c | 2 + modules/dbgfmts/stabs/stabs-dbgfmt.c | 2 + modules/objfmts/bin/Makefile.inc | 2 +- modules/objfmts/bin/bin-objfmt.c | 160 ++- modules/objfmts/coff/coff-objfmt.c | 1 + modules/objfmts/coff/win64-except.c | 2 + modules/objfmts/win64/tests/win64-dataref.hex | 20 +- modules/parsers/Makefile.inc | 1 + modules/parsers/nasm/Makefile.inc | 2 +- modules/parsers/nasm/nasm-parse.c | 324 +++++- modules/parsers/nasm/nasm-parser.c | 35 + modules/parsers/nasm/nasm-parser.h | 5 + modules/parsers/nasm/nasm-token.re | 129 ++- modules/parsers/tasm/Makefile.inc | 5 + modules/parsers/tasm/tests/Makefile.inc | 46 + modules/parsers/tasm/tests/array.asm | 2 + modules/parsers/tasm/tests/array.hex | 6 + modules/parsers/tasm/tests/case.asm | 3 + modules/parsers/tasm/tests/case.hex | 5 + modules/parsers/tasm/tests/charstr.asm | 1 + modules/parsers/tasm/tests/charstr.hex | 6 + modules/parsers/tasm/tests/dup.asm | 1 + modules/parsers/tasm/tests/dup.hex | 10 + modules/parsers/tasm/tests/equal.asm | 1 + modules/parsers/tasm/tests/equal.hex | 0 modules/parsers/tasm/tests/exe/Makefile.inc | 8 + modules/parsers/tasm/tests/exe/exe.asm | 4 + modules/parsers/tasm/tests/exe/exe.hex | 515 +++++++++ .../parsers/tasm/tests/exe/tasm_exe_test.sh | 4 + modules/parsers/tasm/tests/expr.asm | 1 + modules/parsers/tasm/tests/expr.hex | 1 + modules/parsers/tasm/tests/irp.asm | 3 + modules/parsers/tasm/tests/irp.hex | 9 + modules/parsers/tasm/tests/label.asm | 2 + modules/parsers/tasm/tests/label.hex | 3 + modules/parsers/tasm/tests/les.asm | 2 + modules/parsers/tasm/tests/les.hex | 5 + modules/parsers/tasm/tests/lidt.asm | 3 + modules/parsers/tasm/tests/lidt.hex | 11 + modules/parsers/tasm/tests/macro.asm | 6 + modules/parsers/tasm/tests/macro.hex | 6 + modules/parsers/tasm/tests/offset.asm | 3 + modules/parsers/tasm/tests/offset.hex | 7 + modules/parsers/tasm/tests/quote.asm | 2 + modules/parsers/tasm/tests/quote.hex | 6 + modules/parsers/tasm/tests/res.asm | 2 + modules/parsers/tasm/tests/res.errwarn | 2 + modules/parsers/tasm/tests/res.hex | 3 + modules/parsers/tasm/tests/segment.asm | 8 + modules/parsers/tasm/tests/segment.hex | 7 + modules/parsers/tasm/tests/size.asm | 2 + modules/parsers/tasm/tests/size.hex | 6 + modules/parsers/tasm/tests/struc.asm | 8 + modules/parsers/tasm/tests/struc.errwarn | 1 + modules/parsers/tasm/tests/struc.hex | 5 + modules/parsers/tasm/tests/tasm_test.sh | 4 + modules/preprocs/nasm/Makefile.inc | 2 +- modules/preprocs/nasm/nasm-pp.c | 660 ++++++++++- modules/preprocs/nasm/nasm-preproc.c | 24 + modules/preprocs/nasm/nasm.h | 3 + 100 files changed, 3761 insertions(+), 127 deletions(-) create mode 100644 frontends/tasm/Makefile.inc create mode 100644 frontends/tasm/tasm-options.c create mode 100644 frontends/tasm/tasm-options.h create mode 100644 frontends/tasm/tasm.c delete mode 100644 modules/arch/x86/tests/lds-err.errwarn rename modules/arch/x86/tests/{lds-err.asm => lds.asm} (100%) create mode 100644 modules/arch/x86/tests/lds.hex create mode 100644 modules/parsers/tasm/Makefile.inc create mode 100644 modules/parsers/tasm/tests/Makefile.inc create mode 100644 modules/parsers/tasm/tests/array.asm create mode 100644 modules/parsers/tasm/tests/array.hex create mode 100644 modules/parsers/tasm/tests/case.asm create mode 100644 modules/parsers/tasm/tests/case.hex create mode 100644 modules/parsers/tasm/tests/charstr.asm create mode 100644 modules/parsers/tasm/tests/charstr.hex create mode 100644 modules/parsers/tasm/tests/dup.asm create mode 100644 modules/parsers/tasm/tests/dup.hex create mode 100644 modules/parsers/tasm/tests/equal.asm create mode 100644 modules/parsers/tasm/tests/equal.hex create mode 100644 modules/parsers/tasm/tests/exe/Makefile.inc create mode 100644 modules/parsers/tasm/tests/exe/exe.asm create mode 100644 modules/parsers/tasm/tests/exe/exe.hex create mode 100755 modules/parsers/tasm/tests/exe/tasm_exe_test.sh create mode 100644 modules/parsers/tasm/tests/expr.asm create mode 100644 modules/parsers/tasm/tests/expr.hex create mode 100644 modules/parsers/tasm/tests/irp.asm create mode 100644 modules/parsers/tasm/tests/irp.hex create mode 100644 modules/parsers/tasm/tests/label.asm create mode 100644 modules/parsers/tasm/tests/label.hex create mode 100644 modules/parsers/tasm/tests/les.asm create mode 100644 modules/parsers/tasm/tests/les.hex create mode 100644 modules/parsers/tasm/tests/lidt.asm create mode 100644 modules/parsers/tasm/tests/lidt.hex create mode 100644 modules/parsers/tasm/tests/macro.asm create mode 100644 modules/parsers/tasm/tests/macro.hex create mode 100644 modules/parsers/tasm/tests/offset.asm create mode 100644 modules/parsers/tasm/tests/offset.hex create mode 100644 modules/parsers/tasm/tests/quote.asm create mode 100644 modules/parsers/tasm/tests/quote.hex create mode 100644 modules/parsers/tasm/tests/res.asm create mode 100644 modules/parsers/tasm/tests/res.errwarn create mode 100644 modules/parsers/tasm/tests/res.hex create mode 100644 modules/parsers/tasm/tests/segment.asm create mode 100644 modules/parsers/tasm/tests/segment.hex create mode 100644 modules/parsers/tasm/tests/size.asm create mode 100644 modules/parsers/tasm/tests/size.hex create mode 100644 modules/parsers/tasm/tests/struc.asm create mode 100644 modules/parsers/tasm/tests/struc.errwarn create mode 100644 modules/parsers/tasm/tests/struc.hex create mode 100755 modules/parsers/tasm/tests/tasm_test.sh diff --git a/configure.ac b/configure.ac index 97510622..40d99510 100644 --- a/configure.ac +++ b/configure.ac @@ -125,7 +125,7 @@ AX_CREATE_STDINT_H([libyasm-stdint.h]) # AC_CHECK_FUNCS([abort toascii vsnprintf]) AC_CHECK_FUNCS([strsep mergesort getcwd]) -AC_CHECK_FUNCS([popen]) +AC_CHECK_FUNCS([popen ftruncate]) # Look for the case-insensitive comparison functions AC_CHECK_FUNCS([strcasecmp strncasecmp stricmp _stricmp strcmpi]) diff --git a/frontends/CMakeLists.txt b/frontends/CMakeLists.txt index b8b55d2d..0d117734 100644 --- a/frontends/CMakeLists.txt +++ b/frontends/CMakeLists.txt @@ -1 +1,2 @@ ADD_SUBDIRECTORY(yasm) +ADD_SUBDIRECTORY(tasm) diff --git a/frontends/Makefile.inc b/frontends/Makefile.inc index 832a2f0b..0e1552fa 100644 --- a/frontends/Makefile.inc +++ b/frontends/Makefile.inc @@ -1,5 +1,7 @@ # $Id$ EXTRA_DIST += frontends/yasm/Makefile.inc +EXTRA_DIST += frontends/tasm/Makefile.inc include frontends/yasm/Makefile.inc +include frontends/tasm/Makefile.inc diff --git a/frontends/tasm/Makefile.inc b/frontends/tasm/Makefile.inc new file mode 100644 index 00000000..69ec826c --- /dev/null +++ b/frontends/tasm/Makefile.inc @@ -0,0 +1,9 @@ +# $Id: Makefile.inc 1463 2006-04-05 05:39:23Z peter $ + +bin_PROGRAMS += tasm + +tasm_SOURCES = frontends/tasm/tasm.c +tasm_SOURCES += frontends/tasm/tasm-options.c +tasm_SOURCES += frontends/tasm/tasm-options.h + +tasm_LDADD = libyasm.a $(INTLLIBS) diff --git a/frontends/tasm/tasm-options.c b/frontends/tasm/tasm-options.c new file mode 100644 index 00000000..945e5c06 --- /dev/null +++ b/frontends/tasm/tasm-options.c @@ -0,0 +1,140 @@ +/* + * Generic Options Support Header File + * + * Copyright (c) 2001 Stanislav Karchebny + * + * 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 +#include +/*@unused@*/ RCSID("$Id: tasm-options.c 1197 2005-01-24 06:44:25Z peter $"); + +#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 lower[3]; + unsigned len; + + lower[0] = tolower(argv[0][1]); + if (!argv[0][2]) { + lower[1] = '\0'; + } else { + lower[1] = tolower(argv[0][2]); + lower[2] = '\0'; + } + + len = strlen(options[i].opt); + if (!strncmp(lower, options[i].opt, len)) { + char *cmd = &argv[0][1]; + 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], optopt[100]; + size_t i; + + printf("%s", gettext(msg)); + + for (i = 0; i < nopts; i++) { + optbuf[0] = 0; + optopt[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/frontends/tasm/tasm-options.h b/frontends/tasm/tasm-options.h new file mode 100644 index 00000000..6f2e7419 --- /dev/null +++ b/frontends/tasm/tasm-options.h @@ -0,0 +1,69 @@ +/* $Id: tasm-options.h 1137 2004-09-04 01:24:57Z peter $ + * Generic Options Support Header File + * + * Copyright (c) 2001 Stanislav Karchebny + * + * 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 or --lopt= + */ +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/frontends/tasm/tasm.c b/frontends/tasm/tasm.c new file mode 100644 index 00000000..695681ff --- /dev/null +++ b/frontends/tasm/tasm.c @@ -0,0 +1,1003 @@ +/* + * 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 +/*@unused@*/ RCSID("$Id: tasm.c 1523 2006-05-06 16:11:56Z peter $"); + +#include +#include +#include +#include +#include + +#ifdef HAVE_LIBGEN_H +#include +#endif + +#include "tasm-options.h" + +#ifdef CMAKE_BUILD +#include "yasm-plugin.h" +#endif + +#include "license.c" + +#define DEFAULT_OBJFMT_MODULE "bin" + +/*@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_NAME " " PACKAGE_INTVER "." PACKAGE_BUILD, + "Compiled on " __DATE__ ".", + "Copyright (c) 2001-2008 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, 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 */ + if (!load_plugin("yasmstd")) { + print_error(_("%s: could not load standard modules"), _("FATAL")); + return EXIT_FAILURE; + } +#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; idefault_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); +#ifdef CMAKE_BUILD + 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[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/libyasm/bc-align.c b/libyasm/bc-align.c index e4e6b648..fd7c8f52 100644 --- a/libyasm/bc-align.c +++ b/libyasm/bc-align.c @@ -66,6 +66,7 @@ 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, diff --git a/libyasm/bc-data.c b/libyasm/bc-data.c index 8560da31..bdbf7b6b 100644 --- a/libyasm/bc-data.c +++ b/libyasm/bc-data.c @@ -42,7 +42,8 @@ struct yasm_dataval { /*@reldef@*/ STAILQ_ENTRY(yasm_dataval) link; - enum { DV_EMPTY, DV_VALUE, DV_RAW, DV_ULEB128, DV_SLEB128 } type; + enum { DV_EMPTY, DV_VALUE, DV_RAW, DV_ULEB128, DV_SLEB128, DV_RESERVE } + type; union { yasm_value val; @@ -51,16 +52,22 @@ struct yasm_dataval { 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, void *d, @@ -71,6 +78,7 @@ 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, @@ -131,9 +139,26 @@ bc_data_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc) 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) @@ -141,27 +166,37 @@ bc_data_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span, bytecode_data *bc_data = (bytecode_data *)bc->contents; yasm_dataval *dv; yasm_intnum *intn; + int len; + 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: - bc->len += dv->data.val.size/8; + len = dv->data.val.size/8; break; case DV_RAW: - bc->len += dv->data.raw.len; + 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")); - bc->len += - yasm_intnum_size_leb128(intn, dv->type == DV_SLEB128); + 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; @@ -177,29 +212,47 @@ bc_data_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d, unsigned char *bufp_orig = *bufp; 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; - if (output_value(&dv->data.val, *bufp, val_len, - (unsigned long)(*bufp-bufp_orig), bc, 1, d)) - return 1; - *bufp += val_len; + for (i=0; idata.val, *bufp, val_len, + (unsigned long)(*bufp-bufp_orig), bc, 1, + d)) + return 1; + *bufp += val_len; + } break; case DV_RAW: - memcpy(*bufp, dv->data.raw.contents, dv->data.raw.len); - *bufp += dv->data.raw.len; + for (i=0; idata.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")); - *bufp += - yasm_intnum_get_leb128(intn, *bufp, dv->type == DV_SLEB128); + for (i=0; itype == DV_SLEB128); + } + case DV_RESERVE: + val_len = dv->data.val.size/8; + for (i=0; idatahead); + 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; @@ -247,6 +307,7 @@ yasm_bc_create_data(yasm_datavalhead *datahead, unsigned int size, /* 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: @@ -255,7 +316,19 @@ yasm_bc_create_data(yasm_datavalhead *datahead, unsigned int 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++; } @@ -271,6 +344,10 @@ yasm_bc_create_data(yasm_datavalhead *datahead, unsigned int size, 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; @@ -323,7 +400,17 @@ yasm_bc_create_data(yasm_datavalhead *datahead, unsigned int size, 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); @@ -364,6 +451,7 @@ yasm_dv_create_expr(yasm_expr *e) retval->type = DV_VALUE; yasm_value_initialize(&retval->data.val, e, 0); + retval->multiple = NULL; return retval; } @@ -376,10 +464,54 @@ yasm_dv_create_raw(unsigned char *contents, unsigned long len) 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; } +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) { @@ -398,6 +530,8 @@ yasm_dvs_delete(yasm_datavalhead *headp) default: break; } + if (cur->multiple) + yasm_expr_destroy(cur->multiple); yasm_xfree(cur); cur = next; } @@ -421,6 +555,11 @@ yasm_dvs_print(const yasm_datavalhead *head, FILE *f, int indent_level) 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, ""); @@ -445,6 +584,9 @@ yasm_dvs_print(const yasm_datavalhead *head, FILE *f, int indent_level) 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/libyasm/bc-incbin.c b/libyasm/bc-incbin.c index 55634468..f2bee743 100644 --- a/libyasm/bc-incbin.c +++ b/libyasm/bc-incbin.c @@ -66,6 +66,7 @@ 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, diff --git a/libyasm/bc-org.c b/libyasm/bc-org.c index ae0497a2..b6f101cc 100644 --- a/libyasm/bc-org.c +++ b/libyasm/bc-org.c @@ -60,6 +60,7 @@ 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, diff --git a/libyasm/bc-reserve.c b/libyasm/bc-reserve.c index 32f524f9..5cfd38a0 100644 --- a/libyasm/bc-reserve.c +++ b/libyasm/bc-reserve.c @@ -46,6 +46,7 @@ typedef struct 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); @@ -57,6 +58,7 @@ 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, @@ -95,6 +97,13 @@ bc_reserve_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc) 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) diff --git a/libyasm/bytecode.c b/libyasm/bytecode.c index b8386f79..df3cc9d5 100644 --- a/libyasm/bytecode.c +++ b/libyasm/bytecode.c @@ -222,6 +222,18 @@ 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) diff --git a/libyasm/bytecode.h b/libyasm/bytecode.h index bff958f8..d5a98995 100644 --- a/libyasm/bytecode.h +++ b/libyasm/bytecode.h @@ -86,6 +86,14 @@ typedef struct yasm_bytecode_callback { */ 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 @@ -438,6 +446,15 @@ YASM_LIB_DECL 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. @@ -548,11 +565,31 @@ 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_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 +/** 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) + */ +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. + */ +int yasm_dv_get_multiple(yasm_dataval *dv, /*@out@*/ unsigned long *multiple); + /** Initialize a list of data values. * \param headp list of data values */ diff --git a/libyasm/errwarn.c b/libyasm/errwarn.c index 26d7f072..644d7d27 100644 --- a/libyasm/errwarn.c +++ b/libyasm/errwarn.c @@ -115,7 +115,8 @@ yasm_errwarn_initialize(void) warn_class_enabled = (1UL<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; inumterms; 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; inumterms; 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/libyasm/expr.h b/libyasm/expr.h index 96d1796c..ee43fca6 100644 --- a/libyasm/expr.h +++ b/libyasm/expr.h @@ -297,6 +297,16 @@ YASM_LIB_DECL 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 + */ +unsigned int yasm_expr_size(const yasm_expr *e); + +/** Return the segment of an expression, if the user provided it + * \param e expression + */ +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 diff --git a/libyasm/insn.c b/libyasm/insn.c index 46a78dbe..c4c26867 100644 --- a/libyasm/insn.c +++ b/libyasm/insn.c @@ -96,6 +96,7 @@ yasm_operand_create_mem(/*@only@*/ yasm_effaddr *ea) retval->size = 0; retval->deref = 0; retval->strict = 0; + retval->size = ea->data_len * 8; return retval; } diff --git a/libyasm/insn.h b/libyasm/insn.h index 9fdf0ebb..99bcb841 100644 --- a/libyasm/insn.h +++ b/libyasm/insn.h @@ -74,6 +74,9 @@ struct yasm_effaddr { /** 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). */ diff --git a/libyasm/intnum.c b/libyasm/intnum.c index 47173c7e..dab359ab 100644 --- a/libyasm/intnum.c +++ b/libyasm/intnum.c @@ -244,11 +244,58 @@ yasm_intnum_create_charconst_nasm(const char *str) case 0: break; default: - /* >32 bit conversion */ + /* >=32 bit conversion */ while (len) { BitVector_Move_Left(conv_bv, 8); BitVector_Chunk_Store(conv_bv, 8, 0, - (unsigned long)str[--len]); + ((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); + + 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 */ + int 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); } diff --git a/libyasm/intnum.h b/libyasm/intnum.h index 8e1529fc..132e8b00 100644 --- a/libyasm/intnum.h +++ b/libyasm/intnum.h @@ -76,13 +76,22 @@ YASM_LIB_DECL /** 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. This function performs those conversions. + * 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. diff --git a/libyasm/symrec.c b/libyasm/symrec.c index 4ea0ca7e..6ebfc1c6 100644 --- a/libyasm/symrec.c +++ b/libyasm/symrec.c @@ -28,6 +28,7 @@ /*@unused@*/ RCSID("$Id$"); #include +#include #include "libyasm-stdint.h" #include "coretype.h" @@ -71,6 +72,8 @@ struct yasm_symrec { /* 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; @@ -87,6 +90,8 @@ struct yasm_symtab { /*@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 @@ -132,9 +137,16 @@ 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) { @@ -147,15 +159,24 @@ symrec_destroy_one(/*@only@*/ void *d) } static /*@partial@*/ yasm_symrec * -symrec_new_common(/*@keep@*/ char *name) +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; } @@ -163,11 +184,17 @@ symrec_new_common(/*@keep@*/ char *name) static /*@partial@*/ /*@dependent@*/ yasm_symrec * symtab_get_or_new_in_table(yasm_symtab *symtab, /*@only@*/ char *name) { - yasm_symrec *rec = symrec_new_common(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); } @@ -176,7 +203,7 @@ 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); + sym->rec = symrec_new_common(name, symtab->case_sensitive); sym->rec->status = YASM_SYM_NOTINTABLE; @@ -251,7 +278,17 @@ yasm_symtab_use(yasm_symtab *symtab, const char *name, unsigned long line) yasm_symrec * yasm_symtab_get(yasm_symtab *symtab, const char *name) { - return HAMT_search(symtab->sym_table, 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 * @@ -273,6 +310,8 @@ symtab_define(yasm_symtab *symtab, const char *name, sym_type type, 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; } @@ -519,6 +558,30 @@ yasm_symrec_get_label(const yasm_symrec *sym, 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) { diff --git a/libyasm/symrec.h b/libyasm/symrec.h index 94dca89d..0eac87bf 100644 --- a/libyasm/symrec.h +++ b/libyasm/symrec.h @@ -73,6 +73,14 @@ yasm_symtab *yasm_symtab_create(void); 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. @@ -318,6 +326,30 @@ 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 + */ +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. + */ +int yasm_symrec_get_size(const yasm_symrec *sym); + +/** Set the segment of a symbol. + * \param sym symbol + * \param segment segment to be set + */ +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. + */ +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 diff --git a/modules/arch/lc3b/lc3bbc.c b/modules/arch/lc3b/lc3bbc.c index 35965248..a5d0192b 100644 --- a/modules/arch/lc3b/lc3bbc.c +++ b/modules/arch/lc3b/lc3bbc.c @@ -53,6 +53,7 @@ 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, diff --git a/modules/arch/lc3b/lc3bid.re b/modules/arch/lc3b/lc3bid.re index bfbf78b2..de8a2bdf 100644 --- a/modules/arch/lc3b/lc3bid.re +++ b/modules/arch/lc3b/lc3bid.re @@ -128,6 +128,7 @@ 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, diff --git a/modules/arch/x86/gen_x86_insn.py b/modules/arch/x86/gen_x86_insn.py index 4a7c715c..6397d9c9 100755 --- a/modules/arch/x86/gen_x86_insn.py +++ b/modules/arch/x86/gen_x86_insn.py @@ -671,7 +671,7 @@ add_group("twobytemem", modifiers=["SpAdd", "Op0Add", "Op1Add"], opcode=[0x00, 0x00], spare=0, - operands=[Operand(type="Mem", dest="EA")]) + operands=[Operand(type="Mem", relaxed=True, dest="EA")]) # # mov @@ -1666,7 +1666,7 @@ for sfx, sz in zip("wlq", [16, 32, 64]): opersize=sz, opcode=[0x8D], operands=[Operand(type="Reg", size=sz, dest="Spare"), - Operand(type="Mem", size=sz, relaxed=True, dest="EA")]) + Operand(type="Mem", relaxed=True, dest="EA")]) add_insn("lea", "lea") @@ -1681,7 +1681,7 @@ for sfx, sz in zip("wl", [16, 32]): opersize=sz, opcode=[0x00], operands=[Operand(type="Reg", size=sz, dest="Spare"), - Operand(type="Mem", dest="EA")]) + Operand(type="Mem", relaxed=True, dest="EA")]) add_insn("lds", "ldes", modifiers=[0xC5]) add_insn("les", "ldes", modifiers=[0xC4]) @@ -1694,7 +1694,7 @@ for sfx, sz in zip("wl", [16, 32]): opersize=sz, opcode=[0x0F, 0x00], operands=[Operand(type="Reg", size=sz, dest="Spare"), - Operand(type="Mem", dest="EA")]) + Operand(type="Mem", relaxed=True, dest="EA")]) add_insn("lfs", "lfgss", modifiers=[0xB4]) add_insn("lgs", "lfgss", modifiers=[0xB5]) diff --git a/modules/arch/x86/tests/Makefile.inc b/modules/arch/x86/tests/Makefile.inc index a324aa53..4f83c1ed 100644 --- a/modules/arch/x86/tests/Makefile.inc +++ b/modules/arch/x86/tests/Makefile.inc @@ -84,8 +84,8 @@ EXTRA_DIST += modules/arch/x86/tests/jmp64-6.asm EXTRA_DIST += modules/arch/x86/tests/jmp64-6.hex EXTRA_DIST += modules/arch/x86/tests/jmpfar.asm EXTRA_DIST += modules/arch/x86/tests/jmpfar.hex -EXTRA_DIST += modules/arch/x86/tests/lds-err.asm -EXTRA_DIST += modules/arch/x86/tests/lds-err.errwarn +EXTRA_DIST += modules/arch/x86/tests/lds.asm +EXTRA_DIST += modules/arch/x86/tests/lds.hex EXTRA_DIST += modules/arch/x86/tests/loopadsz.asm EXTRA_DIST += modules/arch/x86/tests/loopadsz.hex EXTRA_DIST += modules/arch/x86/tests/lsahf.asm diff --git a/modules/arch/x86/tests/lds-err.errwarn b/modules/arch/x86/tests/lds-err.errwarn deleted file mode 100644 index e29dc728..00000000 --- a/modules/arch/x86/tests/lds-err.errwarn +++ /dev/null @@ -1,4 +0,0 @@ --:2: error: invalid size for operand 2 --:3: error: invalid size for operand 2 --:5: error: invalid size for operand 2 --:6: error: invalid size for operand 2 diff --git a/modules/arch/x86/tests/lds-err.asm b/modules/arch/x86/tests/lds.asm similarity index 100% rename from modules/arch/x86/tests/lds-err.asm rename to modules/arch/x86/tests/lds.asm diff --git a/modules/arch/x86/tests/lds.hex b/modules/arch/x86/tests/lds.hex new file mode 100644 index 00000000..c3909546 --- /dev/null +++ b/modules/arch/x86/tests/lds.hex @@ -0,0 +1,27 @@ +c5 +06 +01 +00 +c5 +06 +01 +00 +c5 +06 +01 +00 +66 +c5 +06 +01 +00 +66 +c5 +06 +01 +00 +66 +c5 +06 +01 +00 diff --git a/modules/arch/x86/x86arch.c b/modules/arch/x86/x86arch.c index 9ad3cda0..1b272f4b 100644 --- a/modules/arch/x86/x86arch.c +++ b/modules/arch/x86/x86arch.c @@ -71,6 +71,8 @@ x86_create(const char *machine, const char *parser, 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; diff --git a/modules/arch/x86/x86arch.h b/modules/arch/x86/x86arch.h index 2491b3bc..adcc87ea 100644 --- a/modules/arch/x86/x86arch.h +++ b/modules/arch/x86/x86arch.h @@ -82,7 +82,8 @@ typedef struct yasm_arch_x86 { unsigned int amd64_machine; enum { X86_PARSER_NASM = 0, - X86_PARSER_GAS = 1 + X86_PARSER_TASM = 1, + X86_PARSER_GAS = 2 } parser; unsigned int mode_bits; unsigned int force_strict; diff --git a/modules/arch/x86/x86bc.c b/modules/arch/x86/x86bc.c index 5f542432..adf08c9a 100644 --- a/modules/arch/x86/x86bc.c +++ b/modules/arch/x86/x86bc.c @@ -76,6 +76,7 @@ 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, @@ -86,6 +87,7 @@ 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, @@ -96,6 +98,7 @@ 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, @@ -192,6 +195,7 @@ ea_create(void) 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->modrm = 0; x86_ea->valid_modrm = 0; x86_ea->need_modrm = 0; @@ -254,6 +258,8 @@ yasm_x86__ea_create_expr(yasm_arch *arch, yasm_expr *e) */ x86_ea->need_sib = 0xff; + x86_ea->ea.data_len = 0; + return (yasm_effaddr *)x86_ea; } diff --git a/modules/arch/x86/x86expr.c b/modules/arch/x86/x86expr.c index f7ace08a..b141a121 100644 --- a/modules/arch/x86/x86expr.c +++ b/modules/arch/x86/x86expr.c @@ -422,7 +422,7 @@ x86_checkea_calc_displen(x86_effaddr *x86_ea, unsigned int wordsize, int noreg, * EA. With no registers, we must have a 16/32 value. */ if (noreg) { - yasm_warn_set(YASM_WARN_GENERAL, + yasm_warn_set(YASM_WARN_IMPLICIT_SIZE_OVERRIDE, N_("invalid displacement size; fixed")); x86_ea->ea.disp.size = wordsize; } else diff --git a/modules/arch/x86/x86id.c b/modules/arch/x86/x86id.c index 2e51a433..29926ada 100644 --- a/modules/arch/x86/x86id.c +++ b/modules/arch/x86/x86id.c @@ -350,6 +350,7 @@ 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, @@ -1733,6 +1734,9 @@ yasm_x86__parse_check_insnprefix(yasm_arch *arch, const char *id, 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; diff --git a/modules/dbgfmts/codeview/cv-symline.c b/modules/dbgfmts/codeview/cv-symline.c index ab14b143..0a806226 100644 --- a/modules/dbgfmts/codeview/cv-symline.c +++ b/modules/dbgfmts/codeview/cv-symline.c @@ -201,6 +201,7 @@ 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, @@ -211,6 +212,7 @@ 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, @@ -221,6 +223,7 @@ 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, @@ -231,6 +234,7 @@ 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, diff --git a/modules/dbgfmts/codeview/cv-type.c b/modules/dbgfmts/codeview/cv-type.c index 0f2fd5d4..862bea43 100644 --- a/modules/dbgfmts/codeview/cv-type.c +++ b/modules/dbgfmts/codeview/cv-type.c @@ -492,6 +492,7 @@ 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, diff --git a/modules/dbgfmts/dwarf2/dwarf2-dbgfmt.c b/modules/dbgfmts/dwarf2/dwarf2-dbgfmt.c index 6e89a13d..d015f5c3 100644 --- a/modules/dbgfmts/dwarf2/dwarf2-dbgfmt.c +++ b/modules/dbgfmts/dwarf2/dwarf2-dbgfmt.c @@ -55,6 +55,7 @@ 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, diff --git a/modules/dbgfmts/dwarf2/dwarf2-info.c b/modules/dbgfmts/dwarf2/dwarf2-info.c index 556ca926..dd48098b 100644 --- a/modules/dbgfmts/dwarf2/dwarf2-info.c +++ b/modules/dbgfmts/dwarf2/dwarf2-info.c @@ -207,6 +207,7 @@ 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, diff --git a/modules/dbgfmts/dwarf2/dwarf2-line.c b/modules/dbgfmts/dwarf2/dwarf2-line.c index d3fa76f2..3f7b96ed 100644 --- a/modules/dbgfmts/dwarf2/dwarf2-line.c +++ b/modules/dbgfmts/dwarf2/dwarf2-line.c @@ -149,6 +149,7 @@ 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, @@ -159,6 +160,7 @@ 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, diff --git a/modules/dbgfmts/stabs/stabs-dbgfmt.c b/modules/dbgfmts/stabs/stabs-dbgfmt.c index 88d573ab..247639ea 100644 --- a/modules/dbgfmts/stabs/stabs-dbgfmt.c +++ b/modules/dbgfmts/stabs/stabs-dbgfmt.c @@ -139,6 +139,7 @@ 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, @@ -149,6 +150,7 @@ 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, diff --git a/modules/objfmts/bin/Makefile.inc b/modules/objfmts/bin/Makefile.inc index 4d38b539..a7539fe8 100644 --- a/modules/objfmts/bin/Makefile.inc +++ b/modules/objfmts/bin/Makefile.inc @@ -2,7 +2,7 @@ libyasm_a_SOURCES += modules/objfmts/bin/bin-objfmt.c -YASM_MODULES += objfmt_bin +YASM_MODULES += objfmt_bin objfmt_dosexe EXTRA_DIST += modules/objfmts/bin/tests/Makefile.inc diff --git a/modules/objfmts/bin/bin-objfmt.c b/modules/objfmts/bin/bin-objfmt.c index fc283d71..e05a5acb 100644 --- a/modules/objfmts/bin/bin-objfmt.c +++ b/modules/objfmts/bin/bin-objfmt.c @@ -27,6 +27,9 @@ #include /*@unused@*/ RCSID("$Id$"); +#ifdef HAVE_UNISTD_H +#include +#endif #include @@ -1071,7 +1074,8 @@ bin_objfmt_output_section(yasm_section *sect, /*@null@*/ void *d) yasm_errwarn_propagate(info->errwarns, 0); return 0; } - if (fseek(info->f, yasm_intnum_get_int(info->tmp_intn), SEEK_SET) < 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); @@ -1106,6 +1110,8 @@ bin_objfmt_output(yasm_object *object, FILE *f, /*@unused@*/ int all_syms, 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); @@ -1782,6 +1788,7 @@ static const char *bin_nasm_stdmac[] = { static const yasm_stdmac bin_objfmt_stdmacs[] = { { "nasm", "nasm", bin_nasm_stdmac }, + { "tasm", "tasm", bin_nasm_stdmac }, { NULL, NULL, NULL } }; @@ -1802,3 +1809,154 @@ yasm_objfmt_module yasm_bin_LTX_objfmt = { 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, + 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_section_switch, + bin_objfmt_get_special_sym +}; diff --git a/modules/objfmts/coff/coff-objfmt.c b/modules/objfmts/coff/coff-objfmt.c index 46f6d1eb..448682e2 100644 --- a/modules/objfmts/coff/coff-objfmt.c +++ b/modules/objfmts/coff/coff-objfmt.c @@ -234,6 +234,7 @@ 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, diff --git a/modules/objfmts/coff/win64-except.c b/modules/objfmts/coff/win64-except.c index 11ea4bde..5596eac3 100644 --- a/modules/objfmts/coff/win64-except.c +++ b/modules/objfmts/coff/win64-except.c @@ -72,6 +72,7 @@ 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, @@ -82,6 +83,7 @@ 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, diff --git a/modules/objfmts/win64/tests/win64-dataref.hex b/modules/objfmts/win64/tests/win64-dataref.hex index 3af07864..fa604a6f 100644 --- a/modules/objfmts/win64/tests/win64-dataref.hex +++ b/modules/objfmts/win64/tests/win64-dataref.hex @@ -1364,7 +1364,7 @@ f8 00 00 00 -17 +16 00 00 00 @@ -1374,7 +1374,7 @@ f8 00 00 00 -17 +16 00 00 00 @@ -1999,36 +1999,36 @@ a0 03 00 78 -70 -74 -72 00 00 00 00 -40 00 00 00 -02 00 00 00 -03 00 -78 +03 00 00 00 +03 00 +78 +70 +74 +72 00 00 00 00 +40 00 00 00 -03 +02 00 00 00 diff --git a/modules/parsers/Makefile.inc b/modules/parsers/Makefile.inc index 89bfd35b..a2ab23f3 100644 --- a/modules/parsers/Makefile.inc +++ b/modules/parsers/Makefile.inc @@ -5,6 +5,7 @@ EXTRA_DIST += modules/parsers/nasm/Makefile.inc include modules/parsers/gas/Makefile.inc include modules/parsers/nasm/Makefile.inc +include modules/parsers/tasm/Makefile.inc dist_man_MANS += yasm_parsers.7 diff --git a/modules/parsers/nasm/Makefile.inc b/modules/parsers/nasm/Makefile.inc index ac174ca0..7149959d 100644 --- a/modules/parsers/nasm/Makefile.inc +++ b/modules/parsers/nasm/Makefile.inc @@ -5,7 +5,7 @@ libyasm_a_SOURCES += modules/parsers/nasm/nasm-parser.h libyasm_a_SOURCES += modules/parsers/nasm/nasm-parse.c nodist_libyasm_a_SOURCES += nasm-token.c -YASM_MODULES += parser_nasm +YASM_MODULES += parser_nasm parser_tasm nasm-token.c: $(srcdir)/modules/parsers/nasm/nasm-token.re re2c$(EXEEXT) $(top_builddir)/re2c$(EXEEXT) -b -o $@ $(srcdir)/modules/parsers/nasm/nasm-token.re diff --git a/modules/parsers/nasm/nasm-parse.c b/modules/parsers/nasm/nasm-parse.c index cba949f8..7afd0086 100644 --- a/modules/parsers/nasm/nasm-parse.c +++ b/modules/parsers/nasm/nasm-parse.c @@ -32,6 +32,7 @@ RCSID("$Id$"); #include #include "modules/parsers/nasm/nasm-parser.h" +#include "modules/preprocs/nasm/nasm.h" typedef enum { NORM_EXPR, @@ -62,7 +63,23 @@ static void nasm_parser_directive /*@null@*/ yasm_valparamhead *valparams, /*@null@*/ yasm_valparamhead *objext_valparams); static void define_label(yasm_parser_nasm *parser_nasm, /*@only@*/ char *name, - int local); + unsigned int size, int local); + +static void yasm_ea_set_implicit_size_segment(yasm_parser_nasm *parser_nasm, + yasm_effaddr *ea, yasm_expr *e) +{ + if (tasm_compatible_mode) { + 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) @@ -242,11 +259,12 @@ nasm_parser_parse(yasm_parser_nasm *parser_nasm) yasm_bc_destroy(bc); } temp_bc = NULL; - } else { + } 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) @@ -355,23 +373,33 @@ parse_line(yasm_parser_nasm *parser_nasm) case LOCAL_ID: { char *name = ID_val; - int local = (curtok != ID); + int local = tasm_compatible_mode + ? (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")); - define_label(parser_nasm, name, local); + define_label(parser_nasm, name, 0, local); return NULL; } if (curtok == ':') get_next_token(); - if (curtok == EQU) { + if (curtok == EQU || (tasm_compatible_mode && curtok == '=')) { /* label EQU expr */ yasm_expr *e; get_next_token(); + + if (tasm_compatible_mode && 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, @@ -384,17 +412,30 @@ parse_line(yasm_parser_nasm *parser_nasm) return NULL; } - define_label(parser_nasm, name, local); - if (is_eol()) + if (tasm_compatible_mode && curtok == LABEL) + get_next_token(); + + if (tasm_compatible_mode && curtok == SIZE_OVERRIDE) { + size = SIZE_OVERRIDE_val; + get_next_token(); + } + + if (is_eol()) { + define_label(parser_nasm, name, size, local); return NULL; + } if (curtok == TIMES) { + define_label(parser_nasm, name, size, local); get_next_token(); return parse_times(parser_nasm); } bc = parse_exp(parser_nasm); - if (!bc) + if (!tasm_compatible_mode && !bc) yasm_error_set(YASM_ERROR_SYNTAX, N_("instruction expected after label")); + if (tasm_compatible_mode && bc && !size) + size = yasm_bc_elem_size(bc); + define_label(parser_nasm, name, size, local); return bc; } default: @@ -510,7 +551,7 @@ parse_exp(yasm_parser_nasm *parser_nasm) unsigned int size = DECLARE_DATA_val/8; yasm_datavalhead dvs; yasm_dataval *dv; - yasm_expr *e; + yasm_expr *e, *e2; get_next_token(); @@ -529,14 +570,68 @@ parse_exp(yasm_parser_nasm *parser_nasm) goto dv_done; } } - if ((e = parse_bexpr(parser_nasm, DV_EXPR))) - dv = yasm_dv_create_expr(e); - else { + 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()) @@ -699,12 +794,104 @@ parse_operand(yasm_parser_nasm *parser_nasm) N_("memory address expected")); return NULL; } + + if (tasm_compatible_mode && !is_eol() && curtok != ',') { + yasm_expr *e, *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(); + 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: - op = yasm_operand_create_segreg(SEGREG_val); + { + uintptr_t segreg = SEGREG_val; get_next_token(); + if (tasm_compatible_mode && 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_ea_set_implicit_size_segment(parser_nasm, ea, op->data.val); + yasm_insn_operand *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(); @@ -756,13 +943,51 @@ parse_operand(yasm_parser_nasm *parser_nasm) op->targetmod = tmod; return op; } + case ID: + case LOCAL_ID: + case NONLOCAL_ID: + if (tasm_compatible_mode) { + 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 != ':') - return yasm_operand_create_imm(e); + if (tasm_compatible_mode && 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 + return yasm_operand_create_imm(e); else { yasm_expr *off; get_next_token(); @@ -836,10 +1061,12 @@ parse_memaddr(yasm_parser_nasm *parser_nasm) yasm_expr *e = parse_bexpr(parser_nasm, NORM_EXPR); if (!e) return NULL; - if (curtok != ':') - return yasm_operand_create_mem( - yasm_arch_ea_create(p_object->arch, e)); - else { + 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); @@ -847,8 +1074,9 @@ parse_memaddr(yasm_parser_nasm *parser_nasm) yasm_expr_destroy(e); return NULL; } - op = yasm_operand_create_mem( - yasm_arch_ea_create(p_object->arch, off)); + 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; } @@ -1094,6 +1322,30 @@ parse_expr6(yasm_parser_nasm *parser_nasm, expr_type type) 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); @@ -1132,10 +1384,16 @@ parse_expr6(yasm_parser_nasm *parser_nasm, expr_type type) e = p_expr_new_ident(yasm_expr_reg(REG_val)); break; case STRING: - e = p_expr_new_ident(yasm_expr_int( - yasm_intnum_create_charconst_nasm(STRING_val.contents))); + { + yasm_intnum *intn; + if (tasm_compatible_mode) + 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) { @@ -1179,9 +1437,12 @@ parse_expr6(yasm_parser_nasm *parser_nasm, expr_type type) } static void -define_label(yasm_parser_nasm *parser_nasm, char *name, int local) +define_label(yasm_parser_nasm *parser_nasm, char *name, unsigned int size, + int local) { - if (!local) { + yasm_symrec *symrec; + + if ((!tasm_compatible_mode || tasm_locals) && !local) { if (parser_nasm->locallabel_base) yasm_xfree(parser_nasm->locallabel_base); parser_nasm->locallabel_base_len = strlen(name); @@ -1191,11 +1452,16 @@ define_label(yasm_parser_nasm *parser_nasm, char *name, int local) } if (parser_nasm->abspos) - yasm_symtab_define_equ(p_symtab, name, - yasm_expr_copy(parser_nasm->abspos), cur_line); + symrec = yasm_symtab_define_equ(p_symtab, name, + yasm_expr_copy(parser_nasm->abspos), + cur_line); else - yasm_symtab_define_label(p_symtab, name, parser_nasm->prev_bc, 1, - cur_line); + 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); } diff --git a/modules/parsers/nasm/nasm-parser.c b/modules/parsers/nasm/nasm-parser.c index ac10de37..12070061 100644 --- a/modules/parsers/nasm/nasm-parser.c +++ b/modules/parsers/nasm/nasm-parser.c @@ -31,6 +31,8 @@ #include "nasm-parser.h" +#include "modules/preprocs/nasm/nasm.h" + static void nasm_parser_do_parse(yasm_object *object, yasm_preproc *pp, @@ -100,3 +102,36 @@ yasm_parser_module yasm_nasm_LTX_parser = { 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) +{ + tasm_compatible_mode = 1; + yasm_symtab_set_case_sensitive(object->symtab, 0); + yasm_warn_disable(YASM_WARN_IMPLICIT_SIZE_OVERRIDE); + nasm_parser_do_parse(object, pp, save_input, linemap, errwarns); +} + +/* 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/modules/parsers/nasm/nasm-parser.h b/modules/parsers/nasm/nasm-parser.h index c6148a7b..63127589 100644 --- a/modules/parsers/nasm/nasm-parser.h +++ b/modules/parsers/nasm/nasm-parser.h @@ -38,11 +38,14 @@ enum tokentype { FILENAME, STRING, SIZE_OVERRIDE, + OFFSET, DECLARE_DATA, RESERVE_SPACE, + LABEL, INCBIN, EQU, TIMES, + DUP, SEG, WRT, ABS, @@ -56,6 +59,8 @@ enum tokentype { TARGETMOD, LEFT_OP, RIGHT_OP, + LOW, + HIGH, SIGNDIV, SIGNMOD, START_SECTION_ID, diff --git a/modules/parsers/nasm/nasm-token.re b/modules/parsers/nasm/nasm-token.re index cc589b18..72e15080 100644 --- a/modules/parsers/nasm/nasm-token.re +++ b/modules/parsers/nasm/nasm-token.re @@ -32,6 +32,7 @@ RCSID("$Id$"); #include #include "modules/parsers/nasm/nasm-parser.h" +#include "modules/preprocs/nasm/nasm.h" #define YYCURSOR cursor @@ -76,13 +77,22 @@ handle_dot_label(YYSTYPE *lvalp, char *tok, size_t toklen, size_t zeropos, { /* check for special non-local labels like ..start */ if (tok[zeropos+1] == '.') { - lvalp->str_val = yasm__xstrndup(tok+zeropos, toklen-zeropos); + lvalp->str_val = yasm__xstrndup(tok+zeropos+(tasm_compatible_mode?2:0), + toklen-zeropos-(tasm_compatible_mode?2:0)); /* check for special non-local ..@label */ if (lvalp->str_val[zeropos+2] == '@') return NONLOCAL_ID; return SPECIAL_ID; } - + if (tasm_compatible_mode && (!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, @@ -242,65 +252,95 @@ scan: } /* pseudo-instructions */ - 'db' { lvalp->int_info = 8; RETURN(DECLARE_DATA); } + 'db' { + lvalp->int_info = 8; + parser_nasm->state = INSTRUCTION; + RETURN(DECLARE_DATA); + } 'dhw' { lvalp->int_info = yasm_arch_wordsize(p_object->arch)/2; + parser_nasm->state = INSTRUCTION; RETURN(DECLARE_DATA); } 'dw' { lvalp->int_info = yasm_arch_wordsize(p_object->arch); + parser_nasm->state = INSTRUCTION; RETURN(DECLARE_DATA); } 'dd' { lvalp->int_info = yasm_arch_wordsize(p_object->arch)*2; + parser_nasm->state = INSTRUCTION; RETURN(DECLARE_DATA); } 'dq' { lvalp->int_info = yasm_arch_wordsize(p_object->arch)*4; + parser_nasm->state = INSTRUCTION; + RETURN(DECLARE_DATA); + } + 'dt' { + lvalp->int_info = 80; + parser_nasm->state = INSTRUCTION; RETURN(DECLARE_DATA); } - 'dt' { lvalp->int_info = 80; RETURN(DECLARE_DATA); } 'ddq' { lvalp->int_info = yasm_arch_wordsize(p_object->arch)*8; + parser_nasm->state = INSTRUCTION; RETURN(DECLARE_DATA); } 'do' { lvalp->int_info = yasm_arch_wordsize(p_object->arch)*8; + parser_nasm->state = INSTRUCTION; RETURN(DECLARE_DATA); } 'dy' { lvalp->int_info = 256; + parser_nasm->state = INSTRUCTION; RETURN(DECLARE_DATA); } - 'resb' { lvalp->int_info = 8; RETURN(RESERVE_SPACE); } + 'resb' { + lvalp->int_info = 8; + parser_nasm->state = INSTRUCTION; + RETURN(RESERVE_SPACE); + } 'reshw' { lvalp->int_info = yasm_arch_wordsize(p_object->arch)/2; + parser_nasm->state = INSTRUCTION; RETURN(RESERVE_SPACE); } 'resw' { lvalp->int_info = yasm_arch_wordsize(p_object->arch); + parser_nasm->state = INSTRUCTION; RETURN(RESERVE_SPACE); } 'resd' { lvalp->int_info = yasm_arch_wordsize(p_object->arch)*2; + parser_nasm->state = INSTRUCTION; RETURN(RESERVE_SPACE); } 'resq' { lvalp->int_info = yasm_arch_wordsize(p_object->arch)*4; + parser_nasm->state = INSTRUCTION; + RETURN(RESERVE_SPACE); + } + 'rest' { + lvalp->int_info = 80; + parser_nasm->state = INSTRUCTION; RETURN(RESERVE_SPACE); } - 'rest' { lvalp->int_info = 80; RETURN(RESERVE_SPACE); } 'resdq' { lvalp->int_info = yasm_arch_wordsize(p_object->arch)*8; + parser_nasm->state = INSTRUCTION; RETURN(RESERVE_SPACE); } 'reso' { lvalp->int_info = yasm_arch_wordsize(p_object->arch)*8; + parser_nasm->state = INSTRUCTION; RETURN(RESERVE_SPACE); } 'resy' { lvalp->int_info = 256; + parser_nasm->state = INSTRUCTION; RETURN(RESERVE_SPACE); } @@ -325,17 +365,18 @@ scan: "//" { RETURN(SIGNDIV); } "%%" { RETURN(SIGNMOD); } "$$" { RETURN(START_SECTION_ID); } - [-+|^*&/%~$():=,\[] { RETURN(s->tok[0]); } + [-+|^*&/%~$():=,\[?] { RETURN(s->tok[0]); } "]" { RETURN(s->tok[0]); } /* local label (.label) */ - "." [a-zA-Z0-9_$#@~.?]+ { + ("." | "@@") [a-zA-Z0-9_$#@~.?]+ { RETURN(handle_dot_label(lvalp, TOK, TOKLEN, 0, parser_nasm)); } /* forced identifier */ "$" [a-zA-Z0-9_$#@~.?]+ { - if (TOK[1] == '.') { + if (TOK[1] == '.' || + (tasm_compatible_mode && TOK[1] == '@' && TOK[2] == '@')) { /* handle like .label */ RETURN(handle_dot_label(lvalp, TOK, TOKLEN, 1, parser_nasm)); } @@ -376,11 +417,61 @@ scan: s->tok[TOKLEN] = savech; RETURN(TARGETMOD); default: + break; + } + if (tasm_compatible_mode) { + if (!strcasecmp(TOK, "shl")) { + s->tok[TOKLEN] = savech; + RETURN(LEFT_OP); + } + if (!strcasecmp(TOK, "shr")) { + s->tok[TOKLEN] = savech; + RETURN(RIGHT_OP); + } + if (!strcasecmp(TOK, "and")) { + s->tok[TOKLEN] = savech; + RETURN('&'); + } + if (!strcasecmp(TOK, "or")) { + s->tok[TOKLEN] = savech; + RETURN('|'); + } + if (!strcasecmp(TOK, "low")) { + s->tok[TOKLEN] = savech; + RETURN(LOW); + } + if (!strcasecmp(TOK, "high")) { s->tok[TOKLEN] = savech; + RETURN(HIGH); + } + if (!strcasecmp(TOK, "offset")) { + s->tok[TOKLEN] = savech; + RETURN(OFFSET); + } + if (!strcasecmp(TOK, "fword")) { + s->tok[TOKLEN] = savech; + lvalp->int_info = yasm_arch_wordsize(p_object->arch)*2; + RETURN(SIZE_OVERRIDE); + } + if (!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 (!strcasecmp(TOK, "label")) { + s->tok[TOKLEN] = savech; + RETURN(LABEL); + } + if (!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); } @@ -638,6 +729,26 @@ stringconst_scan: /*!re2c [\000] { goto stringconst_error; } + "''" | '""' { + 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 (!tasm_compatible_mode) { + 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; + } + any { if (s->tok[0] == endch) goto stringconst_end; diff --git a/modules/parsers/tasm/Makefile.inc b/modules/parsers/tasm/Makefile.inc new file mode 100644 index 00000000..e7589585 --- /dev/null +++ b/modules/parsers/tasm/Makefile.inc @@ -0,0 +1,5 @@ +# $Id: Makefile.inc 2082 2008-05-09 06:46:02Z peter $ + +EXTRA_DIST += modules/parsers/tasm/tests/Makefile.inc + +include modules/parsers/tasm/tests/Makefile.inc diff --git a/modules/parsers/tasm/tests/Makefile.inc b/modules/parsers/tasm/tests/Makefile.inc new file mode 100644 index 00000000..64dececf --- /dev/null +++ b/modules/parsers/tasm/tests/Makefile.inc @@ -0,0 +1,46 @@ +# $Id: Makefile.inc 2063 2008-04-12 08:30:22Z peter $ + +TESTS += modules/parsers/tasm/tests/tasm_test.sh + +EXTRA_DIST += modules/parsers/tasm/tests/tasm_test.sh +EXTRA_DIST += modules/parsers/tasm/tests/array.asm +EXTRA_DIST += modules/parsers/tasm/tests/array.hex +EXTRA_DIST += modules/parsers/tasm/tests/case.asm +EXTRA_DIST += modules/parsers/tasm/tests/case.hex +EXTRA_DIST += modules/parsers/tasm/tests/charstr.asm +EXTRA_DIST += modules/parsers/tasm/tests/charstr.hex +EXTRA_DIST += modules/parsers/tasm/tests/dup.asm +EXTRA_DIST += modules/parsers/tasm/tests/dup.hex +EXTRA_DIST += modules/parsers/tasm/tests/equal.asm +EXTRA_DIST += modules/parsers/tasm/tests/equal.hex +EXTRA_DIST += modules/parsers/tasm/tests/expr.asm +EXTRA_DIST += modules/parsers/tasm/tests/expr.hex +EXTRA_DIST += modules/parsers/tasm/tests/irp.asm +EXTRA_DIST += modules/parsers/tasm/tests/irp.hex +EXTRA_DIST += modules/parsers/tasm/tests/label.asm +EXTRA_DIST += modules/parsers/tasm/tests/label.hex +EXTRA_DIST += modules/parsers/tasm/tests/les.asm +EXTRA_DIST += modules/parsers/tasm/tests/les.hex +EXTRA_DIST += modules/parsers/tasm/tests/lidt.asm +EXTRA_DIST += modules/parsers/tasm/tests/lidt.hex +EXTRA_DIST += modules/parsers/tasm/tests/macro.asm +EXTRA_DIST += modules/parsers/tasm/tests/macro.hex +EXTRA_DIST += modules/parsers/tasm/tests/offset.asm +EXTRA_DIST += modules/parsers/tasm/tests/offset.hex +EXTRA_DIST += modules/parsers/tasm/tests/quote.asm +EXTRA_DIST += modules/parsers/tasm/tests/quote.hex +EXTRA_DIST += modules/parsers/tasm/tests/res.asm +EXTRA_DIST += modules/parsers/tasm/tests/res.errwarn +EXTRA_DIST += modules/parsers/tasm/tests/res.hex +EXTRA_DIST += modules/parsers/tasm/tests/segment.asm +EXTRA_DIST += modules/parsers/tasm/tests/segment.hex +EXTRA_DIST += modules/parsers/tasm/tests/size.asm +EXTRA_DIST += modules/parsers/tasm/tests/size.hex +EXTRA_DIST += modules/parsers/tasm/tests/struc.asm +EXTRA_DIST += modules/parsers/tasm/tests/struc.errwarn +EXTRA_DIST += modules/parsers/tasm/tests/struc.hex +EXTRA_DIST += modules/parsers/tasm/tests/ + +EXTRA_DIST += modules/parsers/tasm/tests/exe/Makefile.inc + +include modules/parsers/tasm/tests/exe/Makefile.inc diff --git a/modules/parsers/tasm/tests/array.asm b/modules/parsers/tasm/tests/array.asm new file mode 100644 index 00000000..44842678 --- /dev/null +++ b/modules/parsers/tasm/tests/array.asm @@ -0,0 +1,2 @@ +t db 0,1,2 +mov al,t[1] diff --git a/modules/parsers/tasm/tests/array.hex b/modules/parsers/tasm/tests/array.hex new file mode 100644 index 00000000..97758932 --- /dev/null +++ b/modules/parsers/tasm/tests/array.hex @@ -0,0 +1,6 @@ +00 +01 +02 +a0 +01 +00 diff --git a/modules/parsers/tasm/tests/case.asm b/modules/parsers/tasm/tests/case.asm new file mode 100644 index 00000000..1549d4bf --- /dev/null +++ b/modules/parsers/tasm/tests/case.asm @@ -0,0 +1,3 @@ +a db 0 +B dw A +c dw b diff --git a/modules/parsers/tasm/tests/case.hex b/modules/parsers/tasm/tests/case.hex new file mode 100644 index 00000000..e2092e09 --- /dev/null +++ b/modules/parsers/tasm/tests/case.hex @@ -0,0 +1,5 @@ +00 +00 +00 +01 +00 diff --git a/modules/parsers/tasm/tests/charstr.asm b/modules/parsers/tasm/tests/charstr.asm new file mode 100644 index 00000000..a753716c --- /dev/null +++ b/modules/parsers/tasm/tests/charstr.asm @@ -0,0 +1 @@ +mov eax,"1234" diff --git a/modules/parsers/tasm/tests/charstr.hex b/modules/parsers/tasm/tests/charstr.hex new file mode 100644 index 00000000..42deac41 --- /dev/null +++ b/modules/parsers/tasm/tests/charstr.hex @@ -0,0 +1,6 @@ +66 +b8 +34 +33 +32 +31 diff --git a/modules/parsers/tasm/tests/dup.asm b/modules/parsers/tasm/tests/dup.asm new file mode 100644 index 00000000..c19ea762 --- /dev/null +++ b/modules/parsers/tasm/tests/dup.asm @@ -0,0 +1 @@ +a db 10 dup(1) diff --git a/modules/parsers/tasm/tests/dup.hex b/modules/parsers/tasm/tests/dup.hex new file mode 100644 index 00000000..5a51766a --- /dev/null +++ b/modules/parsers/tasm/tests/dup.hex @@ -0,0 +1,10 @@ +01 +01 +01 +01 +01 +01 +01 +01 +01 +01 diff --git a/modules/parsers/tasm/tests/equal.asm b/modules/parsers/tasm/tests/equal.asm new file mode 100644 index 00000000..4b8919dc --- /dev/null +++ b/modules/parsers/tasm/tests/equal.asm @@ -0,0 +1 @@ +a = byte 1 diff --git a/modules/parsers/tasm/tests/equal.hex b/modules/parsers/tasm/tests/equal.hex new file mode 100644 index 00000000..e69de29b diff --git a/modules/parsers/tasm/tests/exe/Makefile.inc b/modules/parsers/tasm/tests/exe/Makefile.inc new file mode 100644 index 00000000..faed7f57 --- /dev/null +++ b/modules/parsers/tasm/tests/exe/Makefile.inc @@ -0,0 +1,8 @@ +# $Id: Makefile.inc 2063 2008-04-12 08:30:22Z peter $ + +TESTS += modules/parsers/tasm/tests/exe/tasm_exe_test.sh + +EXTRA_DIST += modules/parsers/tasm/tests/exe/tasm_exe_test.sh +EXTRA_DIST += modules/parsers/tasm/tests/exe/exe.asm +EXTRA_DIST += modules/parsers/tasm/tests/exe/exe.hex + diff --git a/modules/parsers/tasm/tests/exe/exe.asm b/modules/parsers/tasm/tests/exe/exe.asm new file mode 100644 index 00000000..f040a1cf --- /dev/null +++ b/modules/parsers/tasm/tests/exe/exe.asm @@ -0,0 +1,4 @@ +a db 1 +start proc +int 22 +start endp diff --git a/modules/parsers/tasm/tests/exe/exe.hex b/modules/parsers/tasm/tests/exe/exe.hex new file mode 100644 index 00000000..4547fbc7 --- /dev/null +++ b/modules/parsers/tasm/tests/exe/exe.hex @@ -0,0 +1,515 @@ +4d +5a +03 +00 +02 +00 +00 +00 +20 +00 +00 +00 +ff +ff +00 +00 +00 +00 +00 +00 +01 +00 +00 +00 +22 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +01 +cd +16 diff --git a/modules/parsers/tasm/tests/exe/tasm_exe_test.sh b/modules/parsers/tasm/tests/exe/tasm_exe_test.sh new file mode 100755 index 00000000..47645e3e --- /dev/null +++ b/modules/parsers/tasm/tests/exe/tasm_exe_test.sh @@ -0,0 +1,4 @@ +#! /bin/sh +# $Id: tasm_test.sh 1137 2004-09-04 01:24:57Z peter $ +${srcdir}/out_test.sh tasm_test modules/parsers/tasm/tests/exe "tasm-compat parser" "-f dosexe -p tasm" "" +exit $? diff --git a/modules/parsers/tasm/tests/expr.asm b/modules/parsers/tasm/tests/expr.asm new file mode 100644 index 00000000..53198852 --- /dev/null +++ b/modules/parsers/tasm/tests/expr.asm @@ -0,0 +1 @@ +a db low ((1 shl 2) and (16 shr 2) or (high 0x5034)) diff --git a/modules/parsers/tasm/tests/expr.hex b/modules/parsers/tasm/tests/expr.hex new file mode 100644 index 00000000..d3c4f66b --- /dev/null +++ b/modules/parsers/tasm/tests/expr.hex @@ -0,0 +1 @@ +54 diff --git a/modules/parsers/tasm/tests/irp.asm b/modules/parsers/tasm/tests/irp.asm new file mode 100644 index 00000000..d24cd29f --- /dev/null +++ b/modules/parsers/tasm/tests/irp.asm @@ -0,0 +1,3 @@ +irp i,<1,2,3> + mov ax,i +endm diff --git a/modules/parsers/tasm/tests/irp.hex b/modules/parsers/tasm/tests/irp.hex new file mode 100644 index 00000000..7bf091db --- /dev/null +++ b/modules/parsers/tasm/tests/irp.hex @@ -0,0 +1,9 @@ +b8 +01 +00 +b8 +02 +00 +b8 +03 +00 diff --git a/modules/parsers/tasm/tests/label.asm b/modules/parsers/tasm/tests/label.asm new file mode 100644 index 00000000..ff72ba3e --- /dev/null +++ b/modules/parsers/tasm/tests/label.asm @@ -0,0 +1,2 @@ +a label byte +mov ax,offset a diff --git a/modules/parsers/tasm/tests/label.hex b/modules/parsers/tasm/tests/label.hex new file mode 100644 index 00000000..b74f90bd --- /dev/null +++ b/modules/parsers/tasm/tests/label.hex @@ -0,0 +1,3 @@ +b8 +00 +00 diff --git a/modules/parsers/tasm/tests/les.asm b/modules/parsers/tasm/tests/les.asm new file mode 100644 index 00000000..bbcfd90a --- /dev/null +++ b/modules/parsers/tasm/tests/les.asm @@ -0,0 +1,2 @@ +a db 1 +les ax,a diff --git a/modules/parsers/tasm/tests/les.hex b/modules/parsers/tasm/tests/les.hex new file mode 100644 index 00000000..032eee74 --- /dev/null +++ b/modules/parsers/tasm/tests/les.hex @@ -0,0 +1,5 @@ +01 +c4 +06 +00 +00 diff --git a/modules/parsers/tasm/tests/lidt.asm b/modules/parsers/tasm/tests/lidt.asm new file mode 100644 index 00000000..11cf0c6a --- /dev/null +++ b/modules/parsers/tasm/tests/lidt.asm @@ -0,0 +1,3 @@ +idtr dw 0 + dd 0 +lidt fword ptr idtr diff --git a/modules/parsers/tasm/tests/lidt.hex b/modules/parsers/tasm/tests/lidt.hex new file mode 100644 index 00000000..97fb3b73 --- /dev/null +++ b/modules/parsers/tasm/tests/lidt.hex @@ -0,0 +1,11 @@ +00 +00 +00 +00 +00 +00 +0f +01 +1e +00 +00 diff --git a/modules/parsers/tasm/tests/macro.asm b/modules/parsers/tasm/tests/macro.asm new file mode 100644 index 00000000..75902391 --- /dev/null +++ b/modules/parsers/tasm/tests/macro.asm @@ -0,0 +1,6 @@ +a macro reg,i + mov reg,i + endm + +a ax,0 +a bx,1 diff --git a/modules/parsers/tasm/tests/macro.hex b/modules/parsers/tasm/tests/macro.hex new file mode 100644 index 00000000..92b4e4ae --- /dev/null +++ b/modules/parsers/tasm/tests/macro.hex @@ -0,0 +1,6 @@ +b8 +00 +00 +bb +01 +00 diff --git a/modules/parsers/tasm/tests/offset.asm b/modules/parsers/tasm/tests/offset.asm new file mode 100644 index 00000000..417fd2c3 --- /dev/null +++ b/modules/parsers/tasm/tests/offset.asm @@ -0,0 +1,3 @@ +a db 1 +mov ax,offset a +mov ax,offset[a] diff --git a/modules/parsers/tasm/tests/offset.hex b/modules/parsers/tasm/tests/offset.hex new file mode 100644 index 00000000..3def1cf9 --- /dev/null +++ b/modules/parsers/tasm/tests/offset.hex @@ -0,0 +1,7 @@ +01 +b8 +00 +00 +b8 +00 +00 diff --git a/modules/parsers/tasm/tests/quote.asm b/modules/parsers/tasm/tests/quote.asm new file mode 100644 index 00000000..a269ba37 --- /dev/null +++ b/modules/parsers/tasm/tests/quote.asm @@ -0,0 +1,2 @@ +a db 'don''t' +b db """" diff --git a/modules/parsers/tasm/tests/quote.hex b/modules/parsers/tasm/tests/quote.hex new file mode 100644 index 00000000..eb41f7b4 --- /dev/null +++ b/modules/parsers/tasm/tests/quote.hex @@ -0,0 +1,6 @@ +64 +6f +6e +27 +74 +22 diff --git a/modules/parsers/tasm/tests/res.asm b/modules/parsers/tasm/tests/res.asm new file mode 100644 index 00000000..8cf0829a --- /dev/null +++ b/modules/parsers/tasm/tests/res.asm @@ -0,0 +1,2 @@ +a db ? +b db 2 dup (?) diff --git a/modules/parsers/tasm/tests/res.errwarn b/modules/parsers/tasm/tests/res.errwarn new file mode 100644 index 00000000..490e1ad7 --- /dev/null +++ b/modules/parsers/tasm/tests/res.errwarn @@ -0,0 +1,2 @@ +-:1: warning: uninitialized space declared in code/data section: zeroing +-:2: warning: uninitialized space declared in code/data section: zeroing diff --git a/modules/parsers/tasm/tests/res.hex b/modules/parsers/tasm/tests/res.hex new file mode 100644 index 00000000..47f99ba3 --- /dev/null +++ b/modules/parsers/tasm/tests/res.hex @@ -0,0 +1,3 @@ +00 +00 +00 diff --git a/modules/parsers/tasm/tests/segment.asm b/modules/parsers/tasm/tests/segment.asm new file mode 100644 index 00000000..f0563ebd --- /dev/null +++ b/modules/parsers/tasm/tests/segment.asm @@ -0,0 +1,8 @@ +data segment + a db 0 +data ends + +assume es:data +code segment + mov byte ptr [a],1 +code ends diff --git a/modules/parsers/tasm/tests/segment.hex b/modules/parsers/tasm/tests/segment.hex new file mode 100644 index 00000000..667a69b2 --- /dev/null +++ b/modules/parsers/tasm/tests/segment.hex @@ -0,0 +1,7 @@ +00 +26 +c6 +06 +00 +00 +01 diff --git a/modules/parsers/tasm/tests/size.asm b/modules/parsers/tasm/tests/size.asm new file mode 100644 index 00000000..405cc407 --- /dev/null +++ b/modules/parsers/tasm/tests/size.asm @@ -0,0 +1,2 @@ +a db 0 +mov a,1 diff --git a/modules/parsers/tasm/tests/size.hex b/modules/parsers/tasm/tests/size.hex new file mode 100644 index 00000000..401266a1 --- /dev/null +++ b/modules/parsers/tasm/tests/size.hex @@ -0,0 +1,6 @@ +00 +c6 +06 +00 +00 +01 diff --git a/modules/parsers/tasm/tests/struc.asm b/modules/parsers/tasm/tests/struc.asm new file mode 100644 index 00000000..5a88b615 --- /dev/null +++ b/modules/parsers/tasm/tests/struc.asm @@ -0,0 +1,8 @@ +s struc + a db ? + b db ? +s ends + +v s <1,?> + +mov al,[v].b diff --git a/modules/parsers/tasm/tests/struc.errwarn b/modules/parsers/tasm/tests/struc.errwarn new file mode 100644 index 00000000..4e188892 --- /dev/null +++ b/modules/parsers/tasm/tests/struc.errwarn @@ -0,0 +1 @@ +-:6: warning: uninitialized space declared in code/data section: zeroing diff --git a/modules/parsers/tasm/tests/struc.hex b/modules/parsers/tasm/tests/struc.hex new file mode 100644 index 00000000..d2ad9563 --- /dev/null +++ b/modules/parsers/tasm/tests/struc.hex @@ -0,0 +1,5 @@ +01 +00 +a0 +01 +00 diff --git a/modules/parsers/tasm/tests/tasm_test.sh b/modules/parsers/tasm/tests/tasm_test.sh new file mode 100755 index 00000000..531e03e8 --- /dev/null +++ b/modules/parsers/tasm/tests/tasm_test.sh @@ -0,0 +1,4 @@ +#! /bin/sh +# $Id: tasm_test.sh 1137 2004-09-04 01:24:57Z peter $ +${srcdir}/out_test.sh tasm_test modules/parsers/tasm/tests "tasm-compat parser" "-f bin -p tasm" "" +exit $? diff --git a/modules/preprocs/nasm/Makefile.inc b/modules/preprocs/nasm/Makefile.inc index f9aa9d5e..922b887c 100644 --- a/modules/preprocs/nasm/Makefile.inc +++ b/modules/preprocs/nasm/Makefile.inc @@ -9,7 +9,7 @@ libyasm_a_SOURCES += modules/preprocs/nasm/nasmlib.c libyasm_a_SOURCES += modules/preprocs/nasm/nasm-eval.h libyasm_a_SOURCES += modules/preprocs/nasm/nasm-eval.c -YASM_MODULES += preproc_nasm +YASM_MODULES += preproc_nasm preproc_tasm $(top_srcdir)/modules/preprocs/nasm/nasm-preproc.c: nasm-version.c diff --git a/modules/preprocs/nasm/nasm-pp.c b/modules/preprocs/nasm/nasm-pp.c index 2d5e7d21..3f6e2961 100644 --- a/modules/preprocs/nasm/nasm-pp.c +++ b/modules/preprocs/nasm/nasm-pp.c @@ -324,7 +324,9 @@ static int is_condition(int arg) enum { TM_ARG, TM_ELIF, TM_ELSE, TM_ENDIF, TM_IF, TM_IFDEF, TM_IFDIFI, - TM_IFNDEF, TM_INCLUDE, TM_LOCAL + TM_IFNDEF, TM_INCLUDE, TM_LOCAL, + TM_REPT, TM_IRP, TM_MACRO, + TM_STRUC, TM_SEGMENT }; static const char *tasm_directives[] = { @@ -393,10 +395,53 @@ static const char *tasm_compat_macros[] = { "%idefine IDEAL", "%idefine JUMPS", - "%idefine P386", - "%idefine P486", - "%idefine P586", "%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 }; @@ -428,6 +473,7 @@ 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) @@ -442,69 +488,555 @@ static Token *delete_Token(Token * t); * 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; - char *p = line, *oldline, oldchar; + size_t len, len2; + char *p, *oldline, oldchar, *q, oldchar2; + TMEndItem *end; + + if ((p = strchr(line, ';'))) + *p = '\0'; + + p = line; /* Skip whitespace */ while (isspace(*p) && *p != 0) p++; + /* Ignore nasm directives */ + if (*p == '%') + return line; + /* Binary search for the directive name */ - i = -1; - j = elements(tasm_directives); len = 0; while (!isspace(p[len]) && p[len] != 0) len++; - if (len) + if (!len) + return line; + + oldchar = p[len]; + p[len] = 0; + i = -1; + j = elements(tasm_directives); + while (j - i > 1) { - oldchar = p[len]; - p[len] = 0; - while (j - i > 1) + k = (j + i) / 2; + m = nasm_stricmp(p, tasm_directives[k]); + if (m == 0) { - 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) { - /* 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. + /* 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. */ - p[len] = oldchar; + 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); - oldline = line; + line = nasm_malloc(1 + 7 + 1 + 1 + len + 1 + 1); + sprintf(line, "%%include \"%s\"", p); + } + else + { line = nasm_malloc(len + 2); line[0] = '%'; - 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. - */ - strcpy(line + 1, "ifdef BOGUS"); + 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 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 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 ", q + len2); + p = strchr(q + len2 + 1, '<'); + if (!p) + error(ERR_FATAL, "%s: expected ", 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 = 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 = strdup(oldchar2?q+len2+1:""); + if (tasm_segment) { + error(ERR_FATAL, "SEGMENT: already in a segment context"); + return line; + } + tasm_segment = 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 strdup("endstruc"); + case TM_SEGMENT: + /* XXX: yes, we leak memory here, but that permits labels + * to avoid strduping... */ + tasm_segment = NULL; + return 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 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) { + p = q; + for (; *q && *q != ':' && !isspace(*q); q++); + if (!*q) + break; + /* segment register name */ + for (assume = TAssumes; assume->segreg; assume++) + if (strlen(assume->segreg) == q-p && + !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 != ':' && 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 != ',' && !isspace(*q); q++); + assume->segment = nasm_strndup(p, q-p); + for (; *q && isspace(*q); q++); + if (*q && *q != ',') + error(ERR_FATAL, "expected `,' instead of `%c'", *q); + + for (q++; *q && isspace(*q); q++); + } + TAssumes[i].segreg = NULL; + TAssumes = nasm_realloc(TAssumes, (i+1)*sizeof(*TAssumes)); + nasm_free(line); + return strdup(""); + } else if (inTstruc) { + struct TStrucField *field; + /* TODO: handle unnamed data */ + field = nasm_malloc(sizeof(*field)); + field->name = strdup(p); + /* TODO: type struc ! */ + field->type = 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 (!strcasecmp(q, struc->name)) { + char *r = q + len2 + 1, *s, *t, tasm_param[6]; + struct TStrucField *field = struc->fields; + int size, n, m; + if (!oldchar2) { + error(ERR_FATAL, "Expected struc field initializer after %s %s", p, q); + return line; } - else - { - memcpy(line + 1, p, len + 1); + 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; + while (1) { + m = snprintf(line + n, size - n, "%s.%s: at .%s, %s %s\n", p, field->name, field->name, field->type, r + 1); + if (m + 1 <= size - n) + break; + size *= 2; + line = nasm_realloc(line, size); + } + n += m; + r = s; + field = field->next; } + /* complete with last initializer and '?' */ + while(field) { + while (1) { + m = snprintf(line + n, size - n, "%s.%s: at .%s, %s %s\n", p, field->name, field->name, field->type, r ? r + 1: "?"); + if (m + 1 <= size - n) + break; + size *= 2; + line = nasm_realloc(line, size); + } + n += m; + r = NULL; + field = field->next; + } + line = nasm_realloc(line, n + 5); + sprintf(line + n, "iend"); nasm_free(oldline); return line; } - else if (m < 0) - { - j = k; - } - else - i = k; } - p[len] = oldchar; } + + q[len2] = oldchar2; + p[len] = oldchar; + return line; } +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" @@ -517,6 +1049,8 @@ prepreproc(char *line) int lineno; size_t fnlen; char *fname, *oldline; + char *c, *d, *ret; + Line *l, **lp; if (line[0] == '#' && line[1] == ' ') { @@ -532,8 +1066,30 @@ prepreproc(char *line) nasm_free(oldline); } if (tasm_compatible_mode) - return check_tasm_directive(line); - return line; + 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; } /* @@ -1231,7 +1787,7 @@ static FILE * inc_fopen(char *file, char **newname) { FILE *fp; - char *combine = NULL; + char *combine = NULL, *c; char *pb, *p1, *p2, *file2 = NULL; /* Try to expand all %ENVVAR% in filename. Warn, and leave %string% @@ -1281,6 +1837,27 @@ inc_fopen(char *file, char **newname) 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); @@ -4420,6 +4997,9 @@ pp_getline(void) /* * 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; diff --git a/modules/preprocs/nasm/nasm-preproc.c b/modules/preprocs/nasm/nasm-preproc.c index bb4c7a74..fa2b91e7 100644 --- a/modules/preprocs/nasm/nasm-preproc.c +++ b/modules/preprocs/nasm/nasm-preproc.c @@ -47,6 +47,8 @@ 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" @@ -314,3 +316,25 @@ yasm_preproc_module yasm_nasm_LTX_preproc = { 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/modules/preprocs/nasm/nasm.h b/modules/preprocs/nasm/nasm.h index 792877b0..b3382ffe 100644 --- a/modules/preprocs/nasm/nasm.h +++ b/modules/preprocs/nasm/nasm.h @@ -276,5 +276,8 @@ enum { #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 -- 2.40.0