aboutsummaryrefslogtreecommitdiff
path: root/libyasm
diff options
context:
space:
mode:
authorTorne (Richard Coles) <torne@google.com>2013-03-28 15:33:02 +0000
committerTorne (Richard Coles) <torne@google.com>2013-03-28 15:33:02 +0000
commitc580f3c787d8ad2dcccceb4438b7572d9713a296 (patch)
treed8f5d6b20552cfe016f9af38440fd9caacf4a188 /libyasm
parent1fe0cccaa99357259c9ab42ce88626b95856b77c (diff)
parent53137eb420065ea05c21ae0728a67ead80f17e1f (diff)
downloadpatched-yasm-c580f3c787d8ad2dcccceb4438b7572d9713a296.tar.gz
This commit was generated by merge_to_master.py. Change-Id: I1975b1fce5e96446e4fa27feda7009fe340d4cff
Diffstat (limited to 'libyasm')
-rw-r--r--libyasm/Makefile.inc80
-rw-r--r--libyasm/arch.h495
-rw-r--r--libyasm/assocdat.c136
-rw-r--r--libyasm/assocdat.h76
-rw-r--r--libyasm/bc-align.c245
-rw-r--r--libyasm/bc-data.c600
-rw-r--r--libyasm/bc-incbin.c265
-rw-r--r--libyasm/bc-org.c152
-rw-r--r--libyasm/bc-reserve.c152
-rw-r--r--libyasm/bitvect.c4045
-rw-r--r--libyasm/bitvect.h666
-rw-r--r--libyasm/bytecode.c386
-rw-r--r--libyasm/bytecode.h633
-rw-r--r--libyasm/compat-queue.h456
-rw-r--r--libyasm/coretype.h393
-rw-r--r--libyasm/dbgfmt.h122
-rw-r--r--libyasm/errwarn.c529
-rw-r--r--libyasm/errwarn.h348
-rw-r--r--libyasm/expr.c1516
-rw-r--r--libyasm/expr.h386
-rw-r--r--libyasm/file.c672
-rw-r--r--libyasm/file.h525
-rw-r--r--libyasm/floatnum.c760
-rw-r--r--libyasm/floatnum.h131
-rw-r--r--libyasm/genmodule.c229
-rw-r--r--libyasm/hamt.c421
-rw-r--r--libyasm/hamt.h123
-rw-r--r--libyasm/insn.c295
-rw-r--r--libyasm/insn.h269
-rw-r--r--libyasm/intnum.c1096
-rw-r--r--libyasm/intnum.h340
-rw-r--r--libyasm/inttree.c891
-rw-r--r--libyasm/inttree.h70
-rw-r--r--libyasm/linemap.c293
-rw-r--r--libyasm/linemap.h141
-rw-r--r--libyasm/listfmt.h124
-rw-r--r--libyasm/md5.c309
-rw-r--r--libyasm/md5.h32
-rw-r--r--libyasm/mergesort.c361
-rw-r--r--libyasm/module.h82
-rw-r--r--libyasm/module.in179
-rw-r--r--libyasm/objfmt.h216
-rw-r--r--libyasm/parser.h67
-rw-r--r--libyasm/phash.c268
-rw-r--r--libyasm/phash.h19
-rw-r--r--libyasm/preproc.h210
-rw-r--r--libyasm/section.c1580
-rw-r--r--libyasm/section.h383
-rw-r--r--libyasm/strcasecmp.c94
-rw-r--r--libyasm/strsep.c85
-rw-r--r--libyasm/symrec.c714
-rw-r--r--libyasm/symrec.h433
-rw-r--r--libyasm/tests/1shl0.asm1
-rw-r--r--libyasm/tests/1shl0.hex4
-rw-r--r--libyasm/tests/Makefile.inc114
-rw-r--r--libyasm/tests/absloop-err.asm6
-rw-r--r--libyasm/tests/absloop-err.errwarn1
-rw-r--r--libyasm/tests/bitvect_test.c176
-rw-r--r--libyasm/tests/charconst64.asm3
-rw-r--r--libyasm/tests/charconst64.hex10
-rw-r--r--libyasm/tests/combpath_test.c139
-rw-r--r--libyasm/tests/data-rawvalue.asm3
-rw-r--r--libyasm/tests/data-rawvalue.hex13
-rw-r--r--libyasm/tests/duplabel-err.asm18
-rw-r--r--libyasm/tests/duplabel-err.errwarn4
-rw-r--r--libyasm/tests/emptydata.asm1
-rw-r--r--libyasm/tests/emptydata.hex0
-rw-r--r--libyasm/tests/equ-expand.asm9
-rw-r--r--libyasm/tests/equ-expand.hex10
-rw-r--r--libyasm/tests/expr-fold-level.asm4
-rw-r--r--libyasm/tests/expr-fold-level.hex4
-rw-r--r--libyasm/tests/expr-wide-ident.asm2
-rw-r--r--libyasm/tests/expr-wide-ident.hex9
-rw-r--r--libyasm/tests/externdef.asm2
-rw-r--r--libyasm/tests/externdef.errwarn2
-rw-r--r--libyasm/tests/externdef.hex0
-rw-r--r--libyasm/tests/floatnum_test.c453
-rw-r--r--libyasm/tests/incbin.asm18
-rw-r--r--libyasm/tests/incbin.hex23
-rw-r--r--libyasm/tests/jmpsize1-err.asm264
-rw-r--r--libyasm/tests/jmpsize1-err.errwarn2
-rw-r--r--libyasm/tests/jmpsize1.asm264
-rw-r--r--libyasm/tests/jmpsize1.hex265
-rw-r--r--libyasm/tests/leb128_test.c199
-rwxr-xr-xlibyasm/tests/libyasm_test.sh3
-rw-r--r--libyasm/tests/opt-align1.asm9
-rw-r--r--libyasm/tests/opt-align1.hex266
-rw-r--r--libyasm/tests/opt-align2.asm10
-rw-r--r--libyasm/tests/opt-align2.hex266
-rw-r--r--libyasm/tests/opt-align3.asm16
-rw-r--r--libyasm/tests/opt-align3.hex272
-rw-r--r--libyasm/tests/opt-circular1-err.asm2
-rw-r--r--libyasm/tests/opt-circular1-err.errwarn1
-rw-r--r--libyasm/tests/opt-circular2-err.asm2
-rw-r--r--libyasm/tests/opt-circular2-err.errwarn1
-rw-r--r--libyasm/tests/opt-circular3-err.asm7
-rw-r--r--libyasm/tests/opt-circular3-err.errwarn1
-rw-r--r--libyasm/tests/opt-gvmat64.asm514
-rw-r--r--libyasm/tests/opt-gvmat64.hex731
-rw-r--r--libyasm/tests/opt-immexpand.asm9
-rw-r--r--libyasm/tests/opt-immexpand.hex263
-rw-r--r--libyasm/tests/opt-immnoexpand.asm10
-rw-r--r--libyasm/tests/opt-immnoexpand.hex261
-rw-r--r--libyasm/tests/opt-oldalign.asm3
-rw-r--r--libyasm/tests/opt-oldalign.hex35
-rw-r--r--libyasm/tests/opt-struc.asm39
-rw-r--r--libyasm/tests/opt-struc.hex24
-rw-r--r--libyasm/tests/reserve-err1.asm15
-rw-r--r--libyasm/tests/reserve-err1.errwarn2
-rw-r--r--libyasm/tests/reserve-err2.asm15
-rw-r--r--libyasm/tests/reserve-err2.errwarn6
-rw-r--r--libyasm/tests/splitpath_test.c154
-rw-r--r--libyasm/tests/strucsize.asm23
-rw-r--r--libyasm/tests/strucsize.hex12
-rw-r--r--libyasm/tests/times-res.asm3
-rw-r--r--libyasm/tests/times-res.errwarn1
-rw-r--r--libyasm/tests/times-res.hex20
-rw-r--r--libyasm/tests/times0.asm1
-rw-r--r--libyasm/tests/times0.hex0
-rw-r--r--libyasm/tests/timesover-err.asm2
-rw-r--r--libyasm/tests/timesover-err.errwarn1
-rw-r--r--libyasm/tests/timesunder.asm3
-rw-r--r--libyasm/tests/timesunder.hex130
-rw-r--r--libyasm/tests/unary.asm5
-rw-r--r--libyasm/tests/unary.hex20
-rw-r--r--libyasm/tests/uncstring_test.c156
-rw-r--r--libyasm/tests/value-err.asm9
-rw-r--r--libyasm/tests/value-err.errwarn3
-rw-r--r--libyasm/tests/value-mask.asm5
-rw-r--r--libyasm/tests/value-mask.errwarn1
-rw-r--r--libyasm/tests/value-mask.hex2
-rw-r--r--libyasm/tests/value-samesym.asm2
-rw-r--r--libyasm/tests/value-samesym.errwarn1
-rw-r--r--libyasm/tests/value-samesym.hex8
-rw-r--r--libyasm/valparam.c385
-rw-r--r--libyasm/valparam.h408
-rw-r--r--libyasm/value.c771
-rw-r--r--libyasm/value.h172
-rw-r--r--libyasm/xmalloc.c114
-rw-r--r--libyasm/xstrdup.c68
140 files changed, 30379 insertions, 0 deletions
diff --git a/libyasm/Makefile.inc b/libyasm/Makefile.inc
new file mode 100644
index 0000000..042dd39
--- /dev/null
+++ b/libyasm/Makefile.inc
@@ -0,0 +1,80 @@
+libyasm_a_SOURCES += libyasm/assocdat.c
+libyasm_a_SOURCES += libyasm/bitvect.c
+libyasm_a_SOURCES += libyasm/bc-align.c
+libyasm_a_SOURCES += libyasm/bc-data.c
+libyasm_a_SOURCES += libyasm/bc-incbin.c
+libyasm_a_SOURCES += libyasm/bc-org.c
+libyasm_a_SOURCES += libyasm/bc-reserve.c
+libyasm_a_SOURCES += libyasm/bytecode.c
+libyasm_a_SOURCES += libyasm/errwarn.c
+libyasm_a_SOURCES += libyasm/expr.c
+libyasm_a_SOURCES += libyasm/file.c
+libyasm_a_SOURCES += libyasm/floatnum.c
+libyasm_a_SOURCES += libyasm/hamt.c
+libyasm_a_SOURCES += libyasm/insn.c
+libyasm_a_SOURCES += libyasm/intnum.c
+libyasm_a_SOURCES += libyasm/inttree.c
+libyasm_a_SOURCES += libyasm/linemap.c
+libyasm_a_SOURCES += libyasm/md5.c
+libyasm_a_SOURCES += libyasm/mergesort.c
+libyasm_a_SOURCES += libyasm/phash.c
+libyasm_a_SOURCES += libyasm/section.c
+libyasm_a_SOURCES += libyasm/strcasecmp.c
+libyasm_a_SOURCES += libyasm/strsep.c
+libyasm_a_SOURCES += libyasm/symrec.c
+libyasm_a_SOURCES += libyasm/valparam.c
+libyasm_a_SOURCES += libyasm/value.c
+libyasm_a_SOURCES += libyasm/xmalloc.c
+libyasm_a_SOURCES += libyasm/xstrdup.c
+nodist_libyasm_a_SOURCES += module.c
+
+module.c: $(top_srcdir)/libyasm/module.in genmodule$(EXEEXT) Makefile
+ $(top_builddir)/genmodule$(EXEEXT) $(top_srcdir)/libyasm/module.in Makefile
+
+CLEANFILES += module.c
+
+noinst_PROGRAMS += genmodule
+
+genmodule_SOURCES =
+EXTRA_DIST += libyasm/genmodule.c
+genmodule_LDADD = genmodule.$(OBJEXT)
+genmodule_LINK = $(CCLD_FOR_BUILD) -o $@
+
+genmodule.$(OBJEXT): libyasm/genmodule.c
+ $(CC_FOR_BUILD) $(DEFAULT_INCLUDES) $(INCLUDES) -c -o $@ `test -f libyasm/genmodule.c || echo '$(srcdir)/'`libyasm/genmodule.c
+
+EXTRA_DIST += libyasm/module.in
+
+modincludedir = $(includedir)/libyasm
+
+modinclude_HEADERS = libyasm/arch.h
+modinclude_HEADERS += libyasm/assocdat.h
+modinclude_HEADERS += libyasm/bitvect.h
+modinclude_HEADERS += libyasm/bytecode.h
+modinclude_HEADERS += libyasm/compat-queue.h
+modinclude_HEADERS += libyasm/coretype.h
+modinclude_HEADERS += libyasm/dbgfmt.h
+modinclude_HEADERS += libyasm/errwarn.h
+modinclude_HEADERS += libyasm/expr.h
+modinclude_HEADERS += libyasm/file.h
+modinclude_HEADERS += libyasm/floatnum.h
+modinclude_HEADERS += libyasm/hamt.h
+modinclude_HEADERS += libyasm/insn.h
+modinclude_HEADERS += libyasm/intnum.h
+modinclude_HEADERS += libyasm/inttree.h
+modinclude_HEADERS += libyasm/linemap.h
+modinclude_HEADERS += libyasm/listfmt.h
+modinclude_HEADERS += libyasm/md5.h
+modinclude_HEADERS += libyasm/module.h
+modinclude_HEADERS += libyasm/objfmt.h
+modinclude_HEADERS += libyasm/parser.h
+modinclude_HEADERS += libyasm/phash.h
+modinclude_HEADERS += libyasm/preproc.h
+modinclude_HEADERS += libyasm/section.h
+modinclude_HEADERS += libyasm/symrec.h
+modinclude_HEADERS += libyasm/valparam.h
+modinclude_HEADERS += libyasm/value.h
+
+EXTRA_DIST += libyasm/tests/Makefile.inc
+
+include libyasm/tests/Makefile.inc
diff --git a/libyasm/arch.h b/libyasm/arch.h
new file mode 100644
index 0000000..3da9f9f
--- /dev/null
+++ b/libyasm/arch.h
@@ -0,0 +1,495 @@
+/**
+ * \file libyasm/arch.h
+ * \brief YASM architecture interface.
+ *
+ * \license
+ * Copyright (C) 2002-2007 Peter Johnson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * \endlicense
+ */
+#ifndef YASM_ARCH_H
+#define YASM_ARCH_H
+
+/** Errors that may be returned by yasm_arch_module::create(). */
+typedef enum yasm_arch_create_error {
+ YASM_ARCH_CREATE_OK = 0, /**< No error. */
+ YASM_ARCH_CREATE_BAD_MACHINE, /**< Unrecognized machine name. */
+ YASM_ARCH_CREATE_BAD_PARSER /**< Unrecognized parser name. */
+} yasm_arch_create_error;
+
+/** Return values for yasm_arch_module::parse_check_insnprefix(). */
+typedef enum yasm_arch_insnprefix {
+ YASM_ARCH_NOTINSNPREFIX = 0, /**< Unrecognized */
+ YASM_ARCH_INSN, /**< An instruction */
+ YASM_ARCH_PREFIX /**< An instruction prefix */
+} yasm_arch_insnprefix;
+
+/** Types of registers / target modifiers that may be returned by
+ * yasm_arch_module::parse_check_regtmod().
+ */
+typedef enum yasm_arch_regtmod {
+ YASM_ARCH_NOTREGTMOD = 0, /**< Unrecognized */
+ YASM_ARCH_REG, /**< A "normal" register */
+ YASM_ARCH_REGGROUP, /**< A group of indexable registers */
+ YASM_ARCH_SEGREG, /**< A segment register */
+ YASM_ARCH_TARGETMOD /**< A target modifier (for jumps) */
+} yasm_arch_regtmod;
+
+#ifndef YASM_DOXYGEN
+/** Base #yasm_arch structure. Must be present as the first element in any
+ * #yasm_arch implementation.
+ */
+typedef struct yasm_arch_base {
+ /** #yasm_arch_module implementation for this architecture. */
+ const struct yasm_arch_module *module;
+} yasm_arch_base;
+#endif
+
+/** YASM machine subtype. A number of different machine types may be
+ * associated with a single architecture. These may be specific CPU's, but
+ * the ABI used to interface with the architecture should be the primary
+ * differentiator between machines. Some object formats (ELF) use the machine
+ * to determine parameters within the generated output.
+ */
+typedef struct yasm_arch_machine {
+ /** One-line description of the machine. */
+ const char *name;
+
+ /** Keyword used to select machine. */
+ const char *keyword;
+} yasm_arch_machine;
+
+/** YASM architecture module interface.
+ * \note All "data" in parser-related functions (yasm_arch_parse_*) needs to
+ * start the parse initialized to 0 to make it okay for a parser-related
+ * function to use/check previously stored data to see if it's been
+ * called before on the same piece of data.
+ */
+typedef struct yasm_arch_module {
+ /** One-line description of the architecture.
+ * Call yasm_arch_name() to get the name of a particular #yasm_arch.
+ */
+ const char *name;
+
+ /** Keyword used to select architecture.
+ * Call yasm_arch_keyword() to get the keyword of a particular #yasm_arch.
+ */
+ const char *keyword;
+
+ /** NULL-terminated list of directives. NULL if none. */
+ /*@null@*/ const yasm_directive *directives;
+
+ /** Create architecture.
+ * Module-level implementation of yasm_arch_create().
+ * Call yasm_arch_create() instead of calling this function.
+ */
+ /*@only@*/ yasm_arch * (*create) (const char *machine, const char *parser,
+ /*@out@*/ yasm_arch_create_error *error);
+
+ /** Module-level implementation of yasm_arch_destroy().
+ * Call yasm_arch_destroy() instead of calling this function.
+ */
+ void (*destroy) (/*@only@*/ yasm_arch *arch);
+
+ /** Module-level implementation of yasm_arch_get_machine().
+ * Call yasm_arch_get_machine() instead of calling this function.
+ */
+ const char * (*get_machine) (const yasm_arch *arch);
+
+ /** Module-level implementation of yasm_arch_get_address_size().
+ * Call yasm_arch_get_address_size() instead of calling this function.
+ */
+ unsigned int (*get_address_size) (const yasm_arch *arch);
+
+ /** Module-level implementation of yasm_arch_set_var().
+ * Call yasm_arch_set_var() instead of calling this function.
+ */
+ int (*set_var) (yasm_arch *arch, const char *var, unsigned long val);
+
+ /** Module-level implementation of yasm_arch_parse_check_insnprefix().
+ * Call yasm_arch_parse_check_insnprefix() instead of calling this function.
+ */
+ yasm_arch_insnprefix (*parse_check_insnprefix)
+ (yasm_arch *arch, const char *id, size_t id_len, unsigned long line,
+ /*@out@*/ /*@only@*/ yasm_bytecode **bc, /*@out@*/ uintptr_t *prefix);
+
+ /** Module-level implementation of yasm_arch_parse_check_regtmod().
+ * Call yasm_arch_parse_check_regtmod() instead of calling this function.
+ */
+ yasm_arch_regtmod (*parse_check_regtmod)
+ (yasm_arch *arch, const char *id, size_t id_len,
+ /*@out@*/ uintptr_t *data);
+
+ /** Module-level implementation of yasm_arch_get_fill().
+ * Call yasm_arch_get_fill() instead of calling this function.
+ */
+ const unsigned char ** (*get_fill) (const yasm_arch *arch);
+
+ /** Module-level implementation of yasm_arch_floatnum_tobytes().
+ * Call yasm_arch_floatnum_tobytes() instead of calling this function.
+ */
+ int (*floatnum_tobytes) (yasm_arch *arch, const yasm_floatnum *flt,
+ unsigned char *buf, size_t destsize,
+ size_t valsize, size_t shift, int warn);
+
+ /** Module-level implementation of yasm_arch_intnum_tobytes().
+ * Call yasm_arch_intnum_tobytes() instead of calling this function.
+ */
+ int (*intnum_tobytes) (yasm_arch *arch, const yasm_intnum *intn,
+ unsigned char *buf, size_t destsize, size_t valsize,
+ int shift, const yasm_bytecode *bc,
+ int warn);
+
+ /** Module-level implementation of yasm_arch_get_reg_size().
+ * Call yasm_arch_get_reg_size() instead of calling this function.
+ */
+ unsigned int (*get_reg_size) (yasm_arch *arch, uintptr_t reg);
+
+ /** Module-level implementation of yasm_arch_reggroup_get_reg().
+ * Call yasm_arch_reggroup_get_reg() instead of calling this function.
+ */
+ uintptr_t (*reggroup_get_reg) (yasm_arch *arch, uintptr_t reggroup,
+ unsigned long regindex);
+
+ /** Module-level implementation of yasm_arch_reg_print().
+ * Call yasm_arch_reg_print() instead of calling this function.
+ */
+ void (*reg_print) (yasm_arch *arch, uintptr_t reg, FILE *f);
+
+ /** Module-level implementation of yasm_arch_segreg_print().
+ * Call yasm_arch_segreg_print() instead of calling this function.
+ */
+ void (*segreg_print) (yasm_arch *arch, uintptr_t segreg, FILE *f);
+
+ /** Module-level implementation of yasm_arch_ea_create().
+ * Call yasm_arch_ea_create() instead of calling this function.
+ */
+ yasm_effaddr * (*ea_create) (yasm_arch *arch, /*@keep@*/ yasm_expr *e);
+
+ /** Module-level implementation of yasm_arch_ea_destroy().
+ * Call yasm_arch_ea_destroy() instead of calling this function.
+ */
+ void (*ea_destroy) (/*@only@*/ yasm_effaddr *ea);
+
+ /** Module-level implementation of yasm_arch_ea_print().
+ * Call yasm_arch_ea_print() instead of calling this function.
+ */
+ void (*ea_print) (const yasm_effaddr *ea, FILE *f, int indent_level);
+
+ /** Module-level implementation of yasm_arch_create_empty_insn().
+ * Call yasm_arch_create_empty_insn() instead of calling this function.
+ */
+ /*@only@*/ yasm_bytecode * (*create_empty_insn) (yasm_arch *arch,
+ unsigned long line);
+
+ /** NULL-terminated list of machines for this architecture.
+ * Call yasm_arch_get_machine() to get the active machine of a particular
+ * #yasm_arch.
+ */
+ const yasm_arch_machine *machines;
+
+ /** Default machine keyword.
+ * Call yasm_arch_get_machine() to get the active machine of a particular
+ * #yasm_arch.
+ */
+ const char *default_machine_keyword;
+
+ /** Canonical "word" size in bits.
+ * Call yasm_arch_wordsize() to get the word size of a particular
+ * #yasm_arch.
+ */
+ unsigned int wordsize;
+
+ /** Worst case minimum instruction length in bytes.
+ * Call yasm_arch_min_insn_len() to get the minimum instruction length of
+ * a particular #yasm_arch.
+ */
+ unsigned int min_insn_len;
+} yasm_arch_module;
+
+/** Get the one-line description of an architecture.
+ * \param arch architecture
+ * \return One-line description of architecture.
+ */
+const char *yasm_arch_name(const yasm_arch *arch);
+
+/** Get the keyword used to select an architecture.
+ * \param arch architecture
+ * \return Architecture keyword.
+ */
+const char *yasm_arch_keyword(const yasm_arch *arch);
+
+/** Get the word size of an architecture.
+ * \param arch architecture
+ * \return Word size (in bits).
+ */
+unsigned int yasm_arch_wordsize(const yasm_arch *arch);
+
+/** Get the minimum instruction length of an architecture.
+ * \param arch architecture
+ * \return Minimum instruction length (in bytes).
+ */
+unsigned int yasm_arch_min_insn_len(const yasm_arch *arch);
+
+/** Create architecture.
+ * \param module architecture module
+ * \param machine keyword of machine in use (must be one listed in
+ * #yasm_arch_module.machines)
+ * \param parser keyword of parser in use
+ * \param error error return value
+ * \return NULL on error (error returned in error parameter), otherwise new
+ * architecture.
+ */
+/*@only@*/ yasm_arch *yasm_arch_create(const yasm_arch_module *module,
+ const char *machine, const char *parser,
+ /*@out@*/ yasm_arch_create_error *error);
+
+/** Clean up, free any architecture-allocated memory.
+ * \param arch architecture
+ */
+void yasm_arch_destroy(/*@only@*/ yasm_arch *arch);
+
+/** Get architecture's active machine name.
+ * \param arch architecture
+ * \return Active machine name.
+ */
+const char *yasm_arch_get_machine(const yasm_arch *arch);
+
+/** Get architecture's active address size, in bits.
+ * \param arch architecture
+ * \return Active address size (in bits).
+ */
+unsigned int yasm_arch_get_address_size(const yasm_arch *arch);
+
+/** Set any arch-specific variables. For example, "mode_bits" in x86.
+ * \param arch architecture
+ * \param var variable name
+ * \param val value to set
+ * \return Zero on success, non-zero on failure (variable does not exist).
+ */
+int yasm_arch_set_var(yasm_arch *arch, const char *var, unsigned long val);
+
+/** Check an generic identifier to see if it matches architecture specific
+ * names for instructions or instruction prefixes. Unrecognized identifiers
+ * should return #YASM_ARCH_NOTINSNPREFIX so they can be treated as normal
+ * symbols. Any additional data beyond just the type (almost always necessary)
+ * should be returned into the space provided by the data parameter.
+ * \param arch architecture
+ * \param id identifier as in the input file
+ * \param id_len length of id string
+ * \param line virtual line
+ * \param bc for instructions, yasm_insn-based bytecode is returned
+ * (and NULL otherwise)
+ * \param prefix for prefixes, yasm_arch-specific value is returned
+ * (and 0 otherwise)
+ * \return Identifier type (#YASM_ARCH_NOTINSNPREFIX if unrecognized)
+ */
+yasm_arch_insnprefix yasm_arch_parse_check_insnprefix
+ (yasm_arch *arch, const char *id, size_t id_len, unsigned long line,
+ /*@out@*/ /*@only@*/ yasm_bytecode **bc, /*@out@*/ uintptr_t *prefix);
+
+/** Check an generic identifier to see if it matches architecture specific
+ * names for registers or target modifiers. Unrecognized identifiers should
+ * return #YASM_ARCH_NOTREGTMOD. Any additional data beyond just the type
+ * (almost always necessary) should be returned into the space provided by the
+ * data parameter.
+ * \param arch architecture
+ * \param id identifier as in the input file
+ * \param id_len length of id string
+ * \param data extra identification information (yasm_arch-specific)
+ * [output]
+ * \return Identifier type (#YASM_ARCH_NOTREGTMOD if unrecognized)
+ */
+yasm_arch_regtmod yasm_arch_parse_check_regtmod
+ (yasm_arch *arch, const char *id, size_t id_len,
+ /*@out@*/ uintptr_t *data);
+
+/** Get NOP fill patterns for 1-15 bytes of fill.
+ * \param arch architecture
+ * \return 16-entry array of arrays; [0] is unused, [1] - [15] point to arrays
+ * of 1-15 bytes (respectively) in length.
+ */
+const unsigned char **yasm_arch_get_fill(const yasm_arch *arch);
+
+/** Output #yasm_floatnum to buffer. Puts the value into the least
+ * significant bits of the destination, or may be shifted into more
+ * significant bits by the shift parameter. The destination bits are
+ * cleared before being set.
+ * Architecture-specific because of endianness.
+ * \param arch architecture
+ * \param flt floating point value
+ * \param buf buffer to write into
+ * \param destsize destination size (in bytes)
+ * \param valsize size (in bits)
+ * \param shift left shift (in bits)
+ * \param warn enables standard overflow/underflow warnings
+ * \return Nonzero on error.
+ */
+int yasm_arch_floatnum_tobytes(yasm_arch *arch, const yasm_floatnum *flt,
+ unsigned char *buf, size_t destsize,
+ size_t valsize, size_t shift, int warn);
+
+/** Output #yasm_intnum to buffer. Puts the value into the least
+ * significant bits of the destination, or may be shifted into more
+ * significant bits by the shift parameter. The destination bits are
+ * cleared before being set.
+ * \param arch architecture
+ * \param intn integer value
+ * \param buf buffer to write into
+ * \param destsize destination size (in bytes)
+ * \param valsize size (in bits)
+ * \param shift left shift (in bits); may be negative to specify right
+ * shift (standard warnings include truncation to boundary)
+ * \param bc bytecode being output ("parent" of value)
+ * \param warn enables standard warnings (value doesn't fit into
+ * valsize bits)
+ * \return Nonzero on error.
+ */
+int yasm_arch_intnum_tobytes(yasm_arch *arch, const yasm_intnum *intn,
+ unsigned char *buf, size_t destsize,
+ size_t valsize, int shift,
+ const yasm_bytecode *bc, int warn);
+
+/** Get the equivalent size of a register in bits.
+ * \param arch architecture
+ * \param reg register
+ * \return 0 if there is no suitable equivalent size, otherwise the size.
+ */
+unsigned int yasm_arch_get_reg_size(yasm_arch *arch, uintptr_t reg);
+
+/** Get a specific register of a register group, based on the register
+ * group and the index within the group.
+ * \param arch architecture
+ * \param reggroup register group
+ * \param regindex register index
+ * \return 0 if regindex is not valid for that register group, otherwise the
+ * specific register value.
+ */
+uintptr_t yasm_arch_reggroup_get_reg(yasm_arch *arch, uintptr_t reggroup,
+ unsigned long regindex);
+
+/** Print a register. For debugging purposes.
+ * \param arch architecture
+ * \param reg register
+ * \param f file
+ */
+void yasm_arch_reg_print(yasm_arch *arch, uintptr_t reg, FILE *f);
+
+/** Print a segment register. For debugging purposes.
+ * \param arch architecture
+ * \param segreg segment register
+ * \param f file
+ */
+void yasm_arch_segreg_print(yasm_arch *arch, uintptr_t segreg, FILE *f);
+
+/** Create an effective address from an expression.
+ * \param arch architecture
+ * \param e expression (kept, do not delete)
+ * \return Newly allocated effective address.
+ */
+yasm_effaddr *yasm_arch_ea_create(yasm_arch *arch, /*@keep@*/ yasm_expr *e);
+
+/** Delete (free allocated memory for) an effective address.
+ * \param arch architecture
+ * \param ea effective address (only pointer to it).
+ */
+void yasm_arch_ea_destroy(yasm_arch *arch, /*@only@*/ yasm_effaddr *ea);
+
+/** Print an effective address. For debugging purposes.
+ * \param arch architecture
+ * \param ea effective address
+ * \param f file
+ * \param indent_level indentation level
+ */
+void yasm_arch_ea_print(const yasm_arch *arch, const yasm_effaddr *ea,
+ FILE *f, int indent_level);
+
+/** Create a bytecode that represents a single empty (0 length) instruction.
+ * This is used for handling solitary prefixes.
+ * \param arch architecture
+ * \param line virtual line (from yasm_linemap)
+ * \return Newly allocated bytecode.
+ */
+/*@only@*/ yasm_bytecode *yasm_arch_create_empty_insn(yasm_arch *arch,
+ unsigned long line);
+
+#ifndef YASM_DOXYGEN
+
+/* Inline macro implementations for arch functions */
+
+#define yasm_arch_name(arch) \
+ (((yasm_arch_base *)arch)->module->name)
+#define yasm_arch_keyword(arch) \
+ (((yasm_arch_base *)arch)->module->keyword)
+#define yasm_arch_wordsize(arch) \
+ (((yasm_arch_base *)arch)->module->wordsize)
+#define yasm_arch_min_insn_len(arch) \
+ (((yasm_arch_base *)arch)->module->min_insn_len)
+
+#define yasm_arch_create(module, machine, parser, error) \
+ module->create(machine, parser, error)
+
+#define yasm_arch_destroy(arch) \
+ ((yasm_arch_base *)arch)->module->destroy(arch)
+#define yasm_arch_get_machine(arch) \
+ ((yasm_arch_base *)arch)->module->get_machine(arch)
+#define yasm_arch_get_address_size(arch) \
+ ((yasm_arch_base *)arch)->module->get_address_size(arch)
+#define yasm_arch_set_var(arch, var, val) \
+ ((yasm_arch_base *)arch)->module->set_var(arch, var, val)
+#define yasm_arch_parse_check_insnprefix(arch, id, id_len, line, bc, prefix) \
+ ((yasm_arch_base *)arch)->module->parse_check_insnprefix \
+ (arch, id, id_len, line, bc, prefix)
+#define yasm_arch_parse_check_regtmod(arch, id, id_len, data) \
+ ((yasm_arch_base *)arch)->module->parse_check_regtmod \
+ (arch, id, id_len, data)
+#define yasm_arch_get_fill(arch) \
+ ((yasm_arch_base *)arch)->module->get_fill(arch)
+#define yasm_arch_floatnum_tobytes(arch, flt, buf, destsize, valsize, shift, \
+ warn) \
+ ((yasm_arch_base *)arch)->module->floatnum_tobytes \
+ (arch, flt, buf, destsize, valsize, shift, warn)
+#define yasm_arch_intnum_tobytes(arch, intn, buf, destsize, valsize, shift, \
+ bc, warn) \
+ ((yasm_arch_base *)arch)->module->intnum_tobytes \
+ (arch, intn, buf, destsize, valsize, shift, bc, warn)
+#define yasm_arch_get_reg_size(arch, reg) \
+ ((yasm_arch_base *)arch)->module->get_reg_size(arch, reg)
+#define yasm_arch_reggroup_get_reg(arch, regg, regi) \
+ ((yasm_arch_base *)arch)->module->reggroup_get_reg(arch, regg, regi)
+#define yasm_arch_reg_print(arch, reg, f) \
+ ((yasm_arch_base *)arch)->module->reg_print(arch, reg, f)
+#define yasm_arch_segreg_print(arch, segreg, f) \
+ ((yasm_arch_base *)arch)->module->segreg_print(arch, segreg, f)
+#define yasm_arch_ea_create(arch, e) \
+ ((yasm_arch_base *)arch)->module->ea_create(arch, e)
+#define yasm_arch_ea_destroy(arch, ea) \
+ ((yasm_arch_base *)arch)->module->ea_destroy(ea)
+#define yasm_arch_ea_print(arch, ea, f, i) \
+ ((yasm_arch_base *)arch)->module->ea_print(ea, f, i)
+#define yasm_arch_create_empty_insn(arch, line) \
+ ((yasm_arch_base *)arch)->module->create_empty_insn(arch, line)
+
+#endif
+
+#endif
diff --git a/libyasm/assocdat.c b/libyasm/assocdat.c
new file mode 100644
index 0000000..cdcda62
--- /dev/null
+++ b/libyasm/assocdat.c
@@ -0,0 +1,136 @@
+/*
+ * YASM associated data storage (libyasm internal use)
+ *
+ * Copyright (C) 2003-2007 Peter Johnson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "util.h"
+
+#include "coretype.h"
+#include "assocdat.h"
+
+
+typedef struct assoc_data_item {
+ const yasm_assoc_data_callback *callback;
+ void *data;
+} assoc_data_item;
+
+struct yasm__assoc_data {
+ assoc_data_item *vector;
+ size_t size;
+ size_t alloc;
+};
+
+
+yasm__assoc_data *
+yasm__assoc_data_create(void)
+{
+ yasm__assoc_data *assoc_data = yasm_xmalloc(sizeof(yasm__assoc_data));
+
+ assoc_data->size = 0;
+ assoc_data->alloc = 2;
+ assoc_data->vector = yasm_xmalloc(assoc_data->alloc *
+ sizeof(assoc_data_item));
+
+ return assoc_data;
+}
+
+void *
+yasm__assoc_data_get(yasm__assoc_data *assoc_data,
+ const yasm_assoc_data_callback *callback)
+{
+ size_t i;
+
+ if (!assoc_data)
+ return NULL;
+
+ for (i=0; i<assoc_data->size; i++) {
+ if (assoc_data->vector[i].callback == callback)
+ return assoc_data->vector[i].data;
+ }
+ return NULL;
+}
+
+yasm__assoc_data *
+yasm__assoc_data_add(yasm__assoc_data *assoc_data_arg,
+ const yasm_assoc_data_callback *callback, void *data)
+{
+ yasm__assoc_data *assoc_data;
+ assoc_data_item *item = NULL;
+ size_t i;
+
+ /* Create a new assoc_data if necessary */
+ if (assoc_data_arg)
+ assoc_data = assoc_data_arg;
+ else
+ assoc_data = yasm__assoc_data_create();
+
+ /* See if there's already assocated data for this callback */
+ for (i=0; i<assoc_data->size; i++) {
+ if (assoc_data->vector[i].callback == callback)
+ item = &assoc_data->vector[i];
+ }
+
+ /* No? Then append a new one */
+ if (!item) {
+ assoc_data->size++;
+ if (assoc_data->size > assoc_data->alloc) {
+ assoc_data->alloc *= 2;
+ assoc_data->vector =
+ yasm_xrealloc(assoc_data->vector,
+ assoc_data->alloc * sizeof(assoc_data_item));
+ }
+ item = &assoc_data->vector[assoc_data->size-1];
+ item->callback = callback;
+ item->data = NULL;
+ }
+
+ /* Delete existing data (if any) */
+ if (item->data && item->data != data)
+ item->callback->destroy(item->data);
+
+ item->data = data;
+
+ return assoc_data;
+}
+
+void
+yasm__assoc_data_destroy(yasm__assoc_data *assoc_data)
+{
+ size_t i;
+
+ if (!assoc_data)
+ return;
+
+ for (i=0; i<assoc_data->size; i++)
+ assoc_data->vector[i].callback->destroy(assoc_data->vector[i].data);
+ yasm_xfree(assoc_data->vector);
+ yasm_xfree(assoc_data);
+}
+
+void
+yasm__assoc_data_print(const yasm__assoc_data *assoc_data, FILE *f,
+ int indent_level)
+{
+ /*TODO*/
+}
diff --git a/libyasm/assocdat.h b/libyasm/assocdat.h
new file mode 100644
index 0000000..cf42386
--- /dev/null
+++ b/libyasm/assocdat.h
@@ -0,0 +1,76 @@
+/**
+ * \file assocdat.h
+ * \brief YASM associated data storage (libyasm internal use)
+ *
+ * \license
+ * Copyright (C) 2003-2007 Peter Johnson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * \endlicense
+ */
+#ifndef YASM_ASSOCDAT_H
+#define YASM_ASSOCDAT_H
+
+#ifndef YASM_LIB_DECL
+#define YASM_LIB_DECL
+#endif
+
+/** Associated data container. */
+typedef struct yasm__assoc_data yasm__assoc_data;
+
+/** Create an associated data container. */
+YASM_LIB_DECL
+/*@only@*/ yasm__assoc_data *yasm__assoc_data_create(void);
+
+/** Get associated data for a data callback.
+ * \param assoc_data container of associated data
+ * \param callback callback used when adding data
+ * \return Associated data (NULL if none).
+ */
+YASM_LIB_DECL
+/*@dependent@*/ /*@null@*/ void *yasm__assoc_data_get
+ (/*@null@*/ yasm__assoc_data *assoc_data,
+ const yasm_assoc_data_callback *callback);
+
+/** Add associated data to a associated data container.
+ * \attention Deletes any existing associated data for that data callback.
+ * \param assoc_data container of associated data
+ * \param callback callback
+ * \param data data to associate
+ */
+YASM_LIB_DECL
+/*@only@*/ yasm__assoc_data *yasm__assoc_data_add
+ (/*@null@*/ /*@only@*/ yasm__assoc_data *assoc_data,
+ const yasm_assoc_data_callback *callback,
+ /*@only@*/ /*@null@*/ void *data);
+
+/** Destroy all associated data in a container. */
+YASM_LIB_DECL
+void yasm__assoc_data_destroy
+ (/*@null@*/ /*@only@*/ yasm__assoc_data *assoc_data);
+
+/** Print all associated data in a container. */
+YASM_LIB_DECL
+void yasm__assoc_data_print(const yasm__assoc_data *assoc_data, FILE *f,
+ int indent_level);
+
+#endif
diff --git a/libyasm/bc-align.c b/libyasm/bc-align.c
new file mode 100644
index 0000000..2a47882
--- /dev/null
+++ b/libyasm/bc-align.c
@@ -0,0 +1,245 @@
+/*
+ * Align bytecode
+ *
+ * Copyright (C) 2005-2007 Peter Johnson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "util.h"
+
+#include "libyasm-stdint.h"
+#include "coretype.h"
+
+#include "errwarn.h"
+#include "intnum.h"
+#include "expr.h"
+
+#include "bytecode.h"
+
+
+typedef struct bytecode_align {
+ /*@only@*/ yasm_expr *boundary; /* alignment boundary */
+
+ /* What to fill intervening locations with, NULL if using code_fill */
+ /*@only@*/ /*@null@*/ yasm_expr *fill;
+
+ /* Maximum number of bytes to skip, NULL if no maximum. */
+ /*@only@*/ /*@null@*/ yasm_expr *maxskip;
+
+ /* Code fill, NULL if using 0 fill */
+ /*@null@*/ const unsigned char **code_fill;
+} bytecode_align;
+
+static void bc_align_destroy(void *contents);
+static void bc_align_print(const void *contents, FILE *f, int indent_level);
+static void bc_align_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc);
+static int bc_align_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
+ void *add_span_data);
+static int bc_align_expand(yasm_bytecode *bc, int span, long old_val,
+ long new_val, /*@out@*/ long *neg_thres,
+ /*@out@*/ long *pos_thres);
+static int bc_align_tobytes(yasm_bytecode *bc, unsigned char **bufp,
+ unsigned char *bufstart, void *d,
+ yasm_output_value_func output_value,
+ /*@null@*/ yasm_output_reloc_func output_reloc);
+
+static const yasm_bytecode_callback bc_align_callback = {
+ bc_align_destroy,
+ bc_align_print,
+ bc_align_finalize,
+ NULL,
+ bc_align_calc_len,
+ bc_align_expand,
+ bc_align_tobytes,
+ YASM_BC_SPECIAL_OFFSET
+};
+
+
+static void
+bc_align_destroy(void *contents)
+{
+ bytecode_align *align = (bytecode_align *)contents;
+ if (align->boundary)
+ yasm_expr_destroy(align->boundary);
+ if (align->fill)
+ yasm_expr_destroy(align->fill);
+ if (align->maxskip)
+ yasm_expr_destroy(align->maxskip);
+ yasm_xfree(contents);
+}
+
+static void
+bc_align_print(const void *contents, FILE *f, int indent_level)
+{
+ const bytecode_align *align = (const bytecode_align *)contents;
+ fprintf(f, "%*s_Align_\n", indent_level, "");
+ fprintf(f, "%*sBoundary=", indent_level, "");
+ yasm_expr_print(align->boundary, f);
+ fprintf(f, "\n%*sFill=", indent_level, "");
+ yasm_expr_print(align->fill, f);
+ fprintf(f, "\n%*sMax Skip=", indent_level, "");
+ yasm_expr_print(align->maxskip, f);
+ fprintf(f, "\n");
+}
+
+static void
+bc_align_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc)
+{
+ bytecode_align *align = (bytecode_align *)bc->contents;
+ if (!yasm_expr_get_intnum(&align->boundary, 0))
+ yasm_error_set(YASM_ERROR_NOT_CONSTANT,
+ N_("align boundary must be a constant"));
+ if (align->fill && !yasm_expr_get_intnum(&align->fill, 0))
+ yasm_error_set(YASM_ERROR_NOT_CONSTANT,
+ N_("align fill must be a constant"));
+ if (align->maxskip && !yasm_expr_get_intnum(&align->maxskip, 0))
+ yasm_error_set(YASM_ERROR_NOT_CONSTANT,
+ N_("align maximum skip must be a constant"));
+}
+
+static int
+bc_align_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
+ void *add_span_data)
+{
+ long neg_thres = 0;
+ long pos_thres = 0;
+
+ if (bc_align_expand(bc, 0, 0, (long)bc->offset, &neg_thres,
+ &pos_thres) < 0)
+ return -1;
+
+ return 0;
+}
+
+static int
+bc_align_expand(yasm_bytecode *bc, int span, long old_val, long new_val,
+ /*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres)
+{
+ bytecode_align *align = (bytecode_align *)bc->contents;
+ unsigned long end;
+ unsigned long boundary =
+ yasm_intnum_get_uint(yasm_expr_get_intnum(&align->boundary, 0));
+
+ if (boundary == 0) {
+ bc->len = 0;
+ *pos_thres = new_val;
+ return 0;
+ }
+
+ end = (unsigned long)new_val;
+ if ((unsigned long)new_val & (boundary-1))
+ end = ((unsigned long)new_val & ~(boundary-1)) + boundary;
+
+ *pos_thres = (long)end;
+ bc->len = end - (unsigned long)new_val;
+
+ if (align->maxskip) {
+ unsigned long maxskip =
+ yasm_intnum_get_uint(yasm_expr_get_intnum(&align->maxskip, 0));
+ if (bc->len > maxskip) {
+ *pos_thres = (long)end-maxskip-1;
+ bc->len = 0;
+ }
+ }
+ return 1;
+}
+
+static int
+bc_align_tobytes(yasm_bytecode *bc, unsigned char **bufp,
+ unsigned char *bufstart, void *d,
+ yasm_output_value_func output_value,
+ /*@unused@*/ yasm_output_reloc_func output_reloc)
+{
+ bytecode_align *align = (bytecode_align *)bc->contents;
+ unsigned long len;
+ unsigned long boundary =
+ yasm_intnum_get_uint(yasm_expr_get_intnum(&align->boundary, 0));
+
+ if (boundary == 0)
+ return 0;
+ else {
+ unsigned long end = bc->offset;
+ if (bc->offset & (boundary-1))
+ end = (bc->offset & ~(boundary-1)) + boundary;
+ len = end - bc->offset;
+ if (len == 0)
+ return 0;
+ if (align->maxskip) {
+ unsigned long maxskip =
+ yasm_intnum_get_uint(yasm_expr_get_intnum(&align->maxskip, 0));
+ if (len > maxskip)
+ return 0;
+ }
+ }
+
+ if (align->fill) {
+ unsigned long v;
+ v = yasm_intnum_get_uint(yasm_expr_get_intnum(&align->fill, 0));
+ memset(*bufp, (int)v, len);
+ *bufp += len;
+ } else if (align->code_fill) {
+ unsigned long maxlen = 15;
+ while (!align->code_fill[maxlen] && maxlen>0)
+ maxlen--;
+ if (maxlen == 0) {
+ yasm_error_set(YASM_ERROR_GENERAL,
+ N_("could not find any code alignment size"));
+ return 1;
+ }
+
+ /* Fill with maximum code fill as much as possible */
+ while (len > maxlen) {
+ memcpy(*bufp, align->code_fill[maxlen], maxlen);
+ *bufp += maxlen;
+ len -= maxlen;
+ }
+
+ if (!align->code_fill[len]) {
+ yasm_error_set(YASM_ERROR_VALUE,
+ N_("invalid alignment size %d"), len);
+ return 1;
+ }
+ /* Handle rest of code fill */
+ memcpy(*bufp, align->code_fill[len], len);
+ *bufp += len;
+ } else {
+ /* Just fill with 0 */
+ memset(*bufp, 0, len);
+ *bufp += len;
+ }
+ return 0;
+}
+
+yasm_bytecode *
+yasm_bc_create_align(yasm_expr *boundary, yasm_expr *fill,
+ yasm_expr *maxskip, const unsigned char **code_fill,
+ unsigned long line)
+{
+ bytecode_align *align = yasm_xmalloc(sizeof(bytecode_align));
+
+ align->boundary = boundary;
+ align->fill = fill;
+ align->maxskip = maxskip;
+ align->code_fill = code_fill;
+
+ return yasm_bc_create_common(&bc_align_callback, align, line);
+}
diff --git a/libyasm/bc-data.c b/libyasm/bc-data.c
new file mode 100644
index 0000000..ebbdd6f
--- /dev/null
+++ b/libyasm/bc-data.c
@@ -0,0 +1,600 @@
+/*
+ * Data (and LEB128) bytecode
+ *
+ * Copyright (C) 2001-2007 Peter Johnson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "util.h"
+
+#include "libyasm-stdint.h"
+#include "coretype.h"
+
+#include "errwarn.h"
+#include "intnum.h"
+#include "expr.h"
+#include "value.h"
+
+#include "bytecode.h"
+#include "arch.h"
+
+
+struct yasm_dataval {
+ /*@reldef@*/ STAILQ_ENTRY(yasm_dataval) link;
+
+ enum { DV_EMPTY, DV_VALUE, DV_RAW, DV_ULEB128, DV_SLEB128, DV_RESERVE }
+ type;
+
+ union {
+ yasm_value val;
+ struct {
+ /*@only@*/ unsigned char *contents;
+ unsigned long len;
+ } raw;
+ } data;
+
+ /* number of times data is repeated, NULL=1. */
+ /*@only@*/ /*@null@*/ yasm_expr *multiple;
+};
+
+typedef struct bytecode_data {
+ /* converted data (linked list) */
+ yasm_datavalhead datahead;
+
+ int item_size;
+} bytecode_data;
+
+static void bc_data_destroy(void *contents);
+static void bc_data_print(const void *contents, FILE *f, int indent_level);
+static void bc_data_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc);
+static int bc_data_item_size(yasm_bytecode *bc);
+static int bc_data_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
+ void *add_span_data);
+static int bc_data_tobytes(yasm_bytecode *bc, unsigned char **bufp,
+ unsigned char *bufstart, void *d,
+ yasm_output_value_func output_value,
+ /*@null@*/ yasm_output_reloc_func output_reloc);
+
+static const yasm_bytecode_callback bc_data_callback = {
+ bc_data_destroy,
+ bc_data_print,
+ bc_data_finalize,
+ bc_data_item_size,
+ bc_data_calc_len,
+ yasm_bc_expand_common,
+ bc_data_tobytes,
+ 0
+};
+
+
+static void
+bc_data_destroy(void *contents)
+{
+ bytecode_data *bc_data = (bytecode_data *)contents;
+ yasm_dvs_delete(&bc_data->datahead);
+ yasm_xfree(contents);
+}
+
+static void
+bc_data_print(const void *contents, FILE *f, int indent_level)
+{
+ const bytecode_data *bc_data = (const bytecode_data *)contents;
+ fprintf(f, "%*s_Data_\n", indent_level, "");
+ fprintf(f, "%*sElements:\n", indent_level+1, "");
+ yasm_dvs_print(&bc_data->datahead, f, indent_level+2);
+}
+
+static void
+bc_data_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc)
+{
+ bytecode_data *bc_data = (bytecode_data *)bc->contents;
+ yasm_dataval *dv;
+ yasm_intnum *intn;
+
+ /* Convert values from simple expr to value. */
+ STAILQ_FOREACH(dv, &bc_data->datahead, link) {
+ switch (dv->type) {
+ case DV_VALUE:
+ if (yasm_value_finalize(&dv->data.val, prev_bc)) {
+ yasm_error_set(YASM_ERROR_TOO_COMPLEX,
+ N_("data expression too complex"));
+ return;
+ }
+ break;
+ case DV_ULEB128:
+ case DV_SLEB128:
+ intn = yasm_expr_get_intnum(&dv->data.val.abs, 0);
+ if (!intn) {
+ yasm_error_set(YASM_ERROR_NOT_CONSTANT,
+ N_("LEB128 requires constant values"));
+ return;
+ }
+ /* Warn for negative values in unsigned environment.
+ * This could be an error instead: the likelihood this is
+ * desired is very low!
+ */
+ if (yasm_intnum_sign(intn) == -1 && dv->type == DV_ULEB128)
+ yasm_warn_set(YASM_WARN_GENERAL,
+ N_("negative value in unsigned LEB128"));
+ break;
+ default:
+ break;
+ }
+ if (dv->multiple) {
+ yasm_value val;
+ if (yasm_value_finalize_expr(&val, dv->multiple, prev_bc, 0))
+ yasm_error_set(YASM_ERROR_TOO_COMPLEX,
+ N_("multiple expression too complex"));
+ else if (val.rel)
+ yasm_error_set(YASM_ERROR_NOT_ABSOLUTE,
+ N_("multiple expression not absolute"));
+ dv->multiple = val.abs;
+ }
+ }
+}
+
+static int
+bc_data_item_size(yasm_bytecode *bc)
+{
+ bytecode_data *bc_data = (bytecode_data *)bc->contents;
+ return bc_data->item_size;
+}
+
+static int
+bc_data_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
+ void *add_span_data)
+{
+ bytecode_data *bc_data = (bytecode_data *)bc->contents;
+ yasm_dataval *dv;
+ yasm_intnum *intn;
+ unsigned long len = 0;
+ unsigned long multiple;
+
+ /* Count up element sizes, rounding up string length. */
+ STAILQ_FOREACH(dv, &bc_data->datahead, link) {
+ switch (dv->type) {
+ case DV_EMPTY:
+ len = 0;
+ break;
+ case DV_VALUE:
+ len = dv->data.val.size/8;
+ break;
+ case DV_RAW:
+ len = dv->data.raw.len;
+ break;
+ case DV_ULEB128:
+ case DV_SLEB128:
+ intn = yasm_expr_get_intnum(&dv->data.val.abs, 0);
+ if (!intn)
+ yasm_internal_error(N_("non-constant in data_tobytes"));
+ len = yasm_intnum_size_leb128(intn, dv->type == DV_SLEB128);
+ break;
+ case DV_RESERVE:
+ len = dv->data.val.size/8;
+ break;
+ }
+
+ if (!yasm_dv_get_multiple(dv, &multiple))
+ len *= multiple;
+
+ bc->len += len;
+ }
+
+ return 0;
+}
+
+static int
+bc_data_tobytes(yasm_bytecode *bc, unsigned char **bufp,
+ unsigned char *bufstart, void *d,
+ yasm_output_value_func output_value,
+ /*@unused@*/ yasm_output_reloc_func output_reloc)
+{
+ bytecode_data *bc_data = (bytecode_data *)bc->contents;
+ yasm_dataval *dv;
+ yasm_intnum *intn;
+ unsigned int val_len;
+ unsigned long multiple, i;
+
+ STAILQ_FOREACH(dv, &bc_data->datahead, link) {
+ if (yasm_dv_get_multiple(dv, &multiple) || multiple == 0)
+ continue;
+ switch (dv->type) {
+ case DV_EMPTY:
+ break;
+ case DV_VALUE:
+ val_len = dv->data.val.size/8;
+ for (i=0; i<multiple; i++) {
+ if (output_value(&dv->data.val, *bufp, val_len,
+ (unsigned long)(*bufp-bufstart), bc, 1,
+ d))
+ return 1;
+ *bufp += val_len;
+ }
+ break;
+ case DV_RAW:
+ for (i=0; i<multiple; i++) {
+ memcpy(*bufp, dv->data.raw.contents, dv->data.raw.len);
+ *bufp += dv->data.raw.len;
+ }
+ break;
+ case DV_ULEB128:
+ case DV_SLEB128:
+ intn = yasm_expr_get_intnum(&dv->data.val.abs, 234);
+ if (!intn)
+ yasm_internal_error(N_("non-constant in data_tobytes"));
+ for (i=0; i<multiple; i++) {
+ *bufp +=
+ yasm_intnum_get_leb128(intn, *bufp,
+ dv->type == DV_SLEB128);
+ }
+ case DV_RESERVE:
+ val_len = dv->data.val.size/8;
+ for (i=0; i<multiple; i++) {
+ memset(*bufp, 0, val_len);
+ *bufp += val_len;
+ }
+ break;
+ }
+ }
+
+ return 0;
+}
+
+yasm_bytecode *
+yasm_bc_create_data(yasm_datavalhead *datahead, unsigned int size,
+ int append_zero, yasm_arch *arch, unsigned long line)
+{
+ bytecode_data *data = yasm_xmalloc(sizeof(bytecode_data));
+ yasm_bytecode *bc = yasm_bc_create_common(&bc_data_callback, data, line);
+ yasm_dataval *dv, *dv2, *dvo;
+ yasm_intnum *intn;
+ unsigned long len = 0, rlen, i;
+
+
+ yasm_dvs_initialize(&data->datahead);
+ data->item_size = size;
+
+ /* Prescan input data for length, etc. Careful: this needs to be
+ * precisely paired with the second loop.
+ */
+ STAILQ_FOREACH(dv, datahead, link) {
+ if (dv->multiple && dv->type != DV_EMPTY && len > 0) {
+ /* Flush previous data */
+ dvo = yasm_dv_create_raw(yasm_xmalloc(len), len);
+ STAILQ_INSERT_TAIL(&data->datahead, dvo, link);
+ len = 0;
+ }
+ switch (dv->type) {
+ case DV_EMPTY:
+ break;
+ case DV_VALUE:
+ case DV_ULEB128:
+ case DV_SLEB128:
+ intn = yasm_expr_get_intnum(&dv->data.val.abs, 0);
+ if (intn && dv->type == DV_VALUE && (arch || size == 1))
+ len += size;
+ else if (intn && dv->type == DV_ULEB128)
+ len += yasm_intnum_size_leb128(intn, 0);
+ else if (intn && dv->type == DV_SLEB128)
+ len += yasm_intnum_size_leb128(intn, 1);
+ else {
+ if (len > 0) {
+ /* Create bytecode for all previous len */
+ dvo = yasm_dv_create_raw(yasm_xmalloc(len), len);
+ STAILQ_INSERT_TAIL(&data->datahead, dvo, link);
+ len = 0;
+ }
+
+ /* Create bytecode for this value */
+ dvo = yasm_xmalloc(sizeof(yasm_dataval));
+ STAILQ_INSERT_TAIL(&data->datahead, dvo, link);
+ dvo->multiple = dv->multiple;
+ }
+ break;
+ case DV_RAW:
+ rlen = dv->data.raw.len;
+ /* find count, rounding up to nearest multiple of size */
+ rlen = (rlen + size - 1) / size;
+ len += rlen*size;
+ break;
+ case DV_RESERVE:
+ len += size;
+ break;
+ }
+
+ if (dv->multiple && dv->type != DV_EMPTY && len > 0) {
+ /* Flush this data */
+ dvo = yasm_dv_create_raw(yasm_xmalloc(len), len);
+ STAILQ_INSERT_TAIL(&data->datahead, dvo, link);
+ dvo->multiple = dv->multiple;
+ len = 0;
+ }
+
+ if (append_zero)
+ len++;
+ }
+
+ /* Create final dataval for any trailing length */
+ if (len > 0) {
+ dvo = yasm_dv_create_raw(yasm_xmalloc(len), len);
+ STAILQ_INSERT_TAIL(&data->datahead, dvo, link);
+ }
+
+ /* Second iteration: copy data and delete input datavals. */
+ dv = STAILQ_FIRST(datahead);
+ dvo = STAILQ_FIRST(&data->datahead);
+ len = 0;
+ while (dv && dvo) {
+ if (dv->multiple && dv->type != DV_EMPTY && len > 0) {
+ dvo = STAILQ_NEXT(dvo, link);
+ len = 0;
+ }
+ switch (dv->type) {
+ case DV_EMPTY:
+ break;
+ case DV_VALUE:
+ case DV_ULEB128:
+ case DV_SLEB128:
+ intn = yasm_expr_get_intnum(&dv->data.val.abs, 0);
+ if (intn && dv->type == DV_VALUE && (arch || size == 1)) {
+ if (size == 1)
+ yasm_intnum_get_sized(intn,
+ &dvo->data.raw.contents[len],
+ 1, 8, 0, 0, 1);
+ else
+ yasm_arch_intnum_tobytes(arch, intn,
+ &dvo->data.raw.contents[len],
+ size, size*8, 0, bc, 1);
+ yasm_value_delete(&dv->data.val);
+ len += size;
+ } else if (intn && dv->type == DV_ULEB128) {
+ len += yasm_intnum_get_leb128(intn,
+ &dvo->data.raw.contents[len],
+ 0);
+ yasm_value_delete(&dv->data.val);
+ } else if (intn && dv->type == DV_SLEB128) {
+ len += yasm_intnum_get_leb128(intn,
+ &dvo->data.raw.contents[len],
+ 1);
+ yasm_value_delete(&dv->data.val);
+ } else {
+ if (len > 0)
+ dvo = STAILQ_NEXT(dvo, link);
+ dvo->type = dv->type;
+ dvo->data.val = dv->data.val; /* structure copy */
+ dvo->data.val.size = size*8; /* remember size */
+ dvo = STAILQ_NEXT(dvo, link);
+ len = 0;
+ }
+ break;
+ case DV_RAW:
+ rlen = dv->data.raw.len;
+ memcpy(&dvo->data.raw.contents[len], dv->data.raw.contents,
+ rlen);
+ yasm_xfree(dv->data.raw.contents);
+ len += rlen;
+ /* pad with 0's to nearest multiple of size */
+ rlen %= size;
+ if (rlen > 0) {
+ rlen = size-rlen;
+ for (i=0; i<rlen; i++)
+ dvo->data.raw.contents[len++] = 0;
+ }
+ break;
+ case DV_RESERVE:
+ memset(&dvo->data.raw.contents[len], 0, size);
+ len += size;
+ break;
+ }
+
+ if (dv->multiple && dv->type != DV_EMPTY && len > 0) {
+ dvo = STAILQ_NEXT(dvo, link);
+ len = 0;
+ }
+
+ if (append_zero)
+ dvo->data.raw.contents[len++] = 0;
+ dv2 = STAILQ_NEXT(dv, link);
+ yasm_xfree(dv);
+ dv = dv2;
+ }
+
+ return bc;
+}
+
+yasm_bytecode *
+yasm_bc_create_leb128(yasm_datavalhead *datahead, int sign, unsigned long line)
+{
+ yasm_dataval *dv;
+
+ /* Convert all values into LEB type, error on strings/raws */
+ STAILQ_FOREACH(dv, datahead, link) {
+ switch (dv->type) {
+ case DV_VALUE:
+ dv->type = sign ? DV_SLEB128 : DV_ULEB128;
+ break;
+ case DV_RAW:
+ yasm_error_set(YASM_ERROR_VALUE,
+ N_("LEB128 does not allow string constants"));
+ break;
+ default:
+ break;
+ }
+ }
+
+ return yasm_bc_create_data(datahead, 0, 0, 0, line);
+}
+
+yasm_dataval *
+yasm_dv_create_expr(yasm_expr *e)
+{
+ yasm_dataval *retval = yasm_xmalloc(sizeof(yasm_dataval));
+
+ retval->type = DV_VALUE;
+ yasm_value_initialize(&retval->data.val, e, 0);
+ retval->multiple = NULL;
+
+ return retval;
+}
+
+yasm_dataval *
+yasm_dv_create_raw(unsigned char *contents, unsigned long len)
+{
+ yasm_dataval *retval = yasm_xmalloc(sizeof(yasm_dataval));
+
+ retval->type = DV_RAW;
+ retval->data.raw.contents = contents;
+ retval->data.raw.len = len;
+ retval->multiple = NULL;
+
+ return retval;
+}
+
+yasm_dataval *
+yasm_dv_create_reserve(void)
+{
+ yasm_dataval *retval = yasm_xmalloc(sizeof(yasm_dataval));
+
+ retval->type = DV_RESERVE;
+ retval->multiple = NULL;
+
+ return retval;
+}
+
+yasm_value *
+yasm_dv_get_value(yasm_dataval *dv)
+{
+ if (dv->type != DV_VALUE)
+ return NULL;
+ return &dv->data.val;
+}
+
+void
+yasm_dv_set_multiple(yasm_dataval *dv, yasm_expr *e)
+{
+ if (dv->multiple)
+ dv->multiple = yasm_expr_create_tree( dv->multiple, YASM_EXPR_MUL, e,
+ e->line);
+ else
+ dv->multiple = e;
+}
+
+int
+yasm_dv_get_multiple(yasm_dataval *dv, unsigned long *multiple)
+{
+ /*@dependent@*/ /*@null@*/ const yasm_intnum *num;
+
+ *multiple = 1;
+ if (dv->multiple) {
+ num = yasm_expr_get_intnum(&dv->multiple, 0);
+ if (!num) {
+ yasm_error_set(YASM_ERROR_VALUE,
+ N_("could not determine multiple"));
+ return 1;
+ }
+ if (yasm_intnum_sign(num) < 0) {
+ yasm_error_set(YASM_ERROR_VALUE, N_("multiple is negative"));
+ return 1;
+ }
+ *multiple = yasm_intnum_get_uint(num);
+ }
+ return 0;
+}
+
+void
+yasm_dvs_delete(yasm_datavalhead *headp)
+{
+ yasm_dataval *cur, *next;
+
+ cur = STAILQ_FIRST(headp);
+ while (cur) {
+ next = STAILQ_NEXT(cur, link);
+ switch (cur->type) {
+ case DV_VALUE:
+ yasm_value_delete(&cur->data.val);
+ break;
+ case DV_RAW:
+ yasm_xfree(cur->data.raw.contents);
+ break;
+ default:
+ break;
+ }
+ if (cur->multiple)
+ yasm_expr_destroy(cur->multiple);
+ yasm_xfree(cur);
+ cur = next;
+ }
+ STAILQ_INIT(headp);
+}
+
+yasm_dataval *
+yasm_dvs_append(yasm_datavalhead *headp, yasm_dataval *dv)
+{
+ if (dv) {
+ STAILQ_INSERT_TAIL(headp, dv, link);
+ return dv;
+ }
+ return (yasm_dataval *)NULL;
+}
+
+void
+yasm_dvs_print(const yasm_datavalhead *head, FILE *f, int indent_level)
+{
+ yasm_dataval *cur;
+ unsigned long i;
+
+ STAILQ_FOREACH(cur, head, link) {
+ fprintf(f, "%*sMultiple=", indent_level, "");
+ if (!cur->multiple)
+ fprintf(f, "nil (1)");
+ else
+ yasm_expr_print(cur->multiple, f);
+ switch (cur->type) {
+ case DV_EMPTY:
+ fprintf(f, "%*sEmpty\n", indent_level, "");
+ break;
+ case DV_VALUE:
+ fprintf(f, "%*sValue:\n", indent_level, "");
+ yasm_value_print(&cur->data.val, f, indent_level+1);
+ break;
+ case DV_RAW:
+ fprintf(f, "%*sLength=%lu\n", indent_level, "",
+ cur->data.raw.len);
+ fprintf(f, "%*sBytes=[", indent_level, "");
+ for (i=0; i<cur->data.raw.len; i++)
+ fprintf(f, "0x%02x, ", cur->data.raw.contents[i]);
+ fprintf(f, "]\n");
+ break;
+ case DV_ULEB128:
+ fprintf(f, "%*sULEB128 value:\n", indent_level, "");
+ yasm_value_print(&cur->data.val, f, indent_level+1);
+ break;
+ case DV_SLEB128:
+ fprintf(f, "%*sSLEB128 value:\n", indent_level, "");
+ yasm_value_print(&cur->data.val, f, indent_level+1);
+ break;
+ case DV_RESERVE:
+ fprintf(f, "%*sReserved\n", indent_level, "");
+ break;
+ }
+ }
+}
diff --git a/libyasm/bc-incbin.c b/libyasm/bc-incbin.c
new file mode 100644
index 0000000..a8fec7d
--- /dev/null
+++ b/libyasm/bc-incbin.c
@@ -0,0 +1,265 @@
+/*
+ * Incbin bytecode
+ *
+ * Copyright (C) 2001-2007 Peter Johnson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "util.h"
+
+#include "libyasm-stdint.h"
+#include "coretype.h"
+
+#include "linemap.h"
+
+#include "errwarn.h"
+#include "intnum.h"
+#include "expr.h"
+#include "value.h"
+
+#include "bytecode.h"
+
+#include "file.h"
+
+
+typedef struct bytecode_incbin {
+ /*@only@*/ char *filename; /* file to include data from */
+ const char *from; /* filename of what contained incbin */
+
+ /* starting offset to read from (NULL=0) */
+ /*@only@*/ /*@null@*/ yasm_expr *start;
+
+ /* maximum number of bytes to read (NULL=no limit) */
+ /*@only@*/ /*@null@*/ yasm_expr *maxlen;
+} bytecode_incbin;
+
+static void bc_incbin_destroy(void *contents);
+static void bc_incbin_print(const void *contents, FILE *f, int indent_level);
+static void bc_incbin_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc);
+static int bc_incbin_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
+ void *add_span_data);
+static int bc_incbin_tobytes(yasm_bytecode *bc, unsigned char **bufp,
+ unsigned char *bufstart, void *d,
+ yasm_output_value_func output_value,
+ /*@null@*/ yasm_output_reloc_func output_reloc);
+
+static const yasm_bytecode_callback bc_incbin_callback = {
+ bc_incbin_destroy,
+ bc_incbin_print,
+ bc_incbin_finalize,
+ NULL,
+ bc_incbin_calc_len,
+ yasm_bc_expand_common,
+ bc_incbin_tobytes,
+ 0
+};
+
+
+static void
+bc_incbin_destroy(void *contents)
+{
+ bytecode_incbin *incbin = (bytecode_incbin *)contents;
+ yasm_xfree(incbin->filename);
+ yasm_expr_destroy(incbin->start);
+ yasm_expr_destroy(incbin->maxlen);
+ yasm_xfree(contents);
+}
+
+static void
+bc_incbin_print(const void *contents, FILE *f, int indent_level)
+{
+ const bytecode_incbin *incbin = (const bytecode_incbin *)contents;
+ fprintf(f, "%*s_IncBin_\n", indent_level, "");
+ fprintf(f, "%*sFilename=`%s'\n", indent_level, "",
+ incbin->filename);
+ fprintf(f, "%*sStart=", indent_level, "");
+ if (!incbin->start)
+ fprintf(f, "nil (0)");
+ else
+ yasm_expr_print(incbin->start, f);
+ fprintf(f, "%*sMax Len=", indent_level, "");
+ if (!incbin->maxlen)
+ fprintf(f, "nil (unlimited)");
+ else
+ yasm_expr_print(incbin->maxlen, f);
+ fprintf(f, "\n");
+}
+
+static void
+bc_incbin_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc)
+{
+ bytecode_incbin *incbin = (bytecode_incbin *)bc->contents;
+ yasm_value val;
+
+ if (yasm_value_finalize_expr(&val, incbin->start, prev_bc, 0))
+ yasm_error_set(YASM_ERROR_TOO_COMPLEX,
+ N_("start expression too complex"));
+ else if (val.rel)
+ yasm_error_set(YASM_ERROR_NOT_ABSOLUTE,
+ N_("start expression not absolute"));
+ incbin->start = val.abs;
+
+ if (yasm_value_finalize_expr(&val, incbin->maxlen, prev_bc, 0))
+ yasm_error_set(YASM_ERROR_TOO_COMPLEX,
+ N_("maximum length expression too complex"));
+ else if (val.rel)
+ yasm_error_set(YASM_ERROR_NOT_ABSOLUTE,
+ N_("maximum length expression not absolute"));
+ incbin->maxlen = val.abs;
+}
+
+static int
+bc_incbin_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
+ void *add_span_data)
+{
+ bytecode_incbin *incbin = (bytecode_incbin *)bc->contents;
+ FILE *f;
+ /*@dependent@*/ /*@null@*/ const yasm_intnum *num;
+ unsigned long start = 0, maxlen = 0xFFFFFFFFUL, flen;
+
+ /* Try to convert start to integer value */
+ if (incbin->start) {
+ num = yasm_expr_get_intnum(&incbin->start, 0);
+ if (num)
+ start = yasm_intnum_get_uint(num);
+ if (!num) {
+ /* FIXME */
+ yasm_error_set(YASM_ERROR_NOT_IMPLEMENTED,
+ N_("incbin does not yet understand non-constant"));
+ return -1;
+ }
+ }
+
+ /* Try to convert maxlen to integer value */
+ if (incbin->maxlen) {
+ num = yasm_expr_get_intnum(&incbin->maxlen, 0);
+ if (num)
+ maxlen = yasm_intnum_get_uint(num);
+ if (!num) {
+ /* FIXME */
+ yasm_error_set(YASM_ERROR_NOT_IMPLEMENTED,
+ N_("incbin does not yet understand non-constant"));
+ return -1;
+ }
+ }
+
+ /* Open file and determine its length */
+ f = yasm_fopen_include(incbin->filename, incbin->from, "rb", NULL);
+ if (!f) {
+ yasm_error_set(YASM_ERROR_IO,
+ N_("`incbin': unable to open file `%s'"),
+ incbin->filename);
+ return -1;
+ }
+ if (fseek(f, 0L, SEEK_END) < 0) {
+ yasm_error_set(YASM_ERROR_IO,
+ N_("`incbin': unable to seek on file `%s'"),
+ incbin->filename);
+ return -1;
+ }
+ flen = (unsigned long)ftell(f);
+ fclose(f);
+
+ /* Compute length of incbin from start, maxlen, and len */
+ if (start > flen) {
+ yasm_warn_set(YASM_WARN_GENERAL,
+ N_("`incbin': start past end of file `%s'"),
+ incbin->filename);
+ start = flen;
+ }
+ flen -= start;
+ if (incbin->maxlen)
+ if (maxlen < flen)
+ flen = maxlen;
+ bc->len += flen;
+ return 0;
+}
+
+static int
+bc_incbin_tobytes(yasm_bytecode *bc, unsigned char **bufp,
+ unsigned char *bufstart, void *d,
+ yasm_output_value_func output_value,
+ /*@unused@*/ yasm_output_reloc_func output_reloc)
+{
+ bytecode_incbin *incbin = (bytecode_incbin *)bc->contents;
+ FILE *f;
+ /*@dependent@*/ /*@null@*/ const yasm_intnum *num;
+ unsigned long start = 0;
+
+ /* Convert start to integer value */
+ if (incbin->start) {
+ num = yasm_expr_get_intnum(&incbin->start, 0);
+ if (!num)
+ yasm_internal_error(
+ N_("could not determine start in bc_tobytes_incbin"));
+ start = yasm_intnum_get_uint(num);
+ }
+
+ /* Open file */
+ f = yasm_fopen_include(incbin->filename, incbin->from, "rb", NULL);
+ if (!f) {
+ yasm_error_set(YASM_ERROR_IO, N_("`incbin': unable to open file `%s'"),
+ incbin->filename);
+ return 1;
+ }
+
+ /* Seek to start of data */
+ if (fseek(f, (long)start, SEEK_SET) < 0) {
+ yasm_error_set(YASM_ERROR_IO,
+ N_("`incbin': unable to seek on file `%s'"),
+ incbin->filename);
+ fclose(f);
+ return 1;
+ }
+
+ /* Read len bytes */
+ if (fread(*bufp, 1, (size_t)bc->len, f) < (size_t)bc->len) {
+ yasm_error_set(YASM_ERROR_IO,
+ N_("`incbin': unable to read %lu bytes from file `%s'"),
+ bc->len, incbin->filename);
+ fclose(f);
+ return 1;
+ }
+
+ *bufp += bc->len;
+ fclose(f);
+ return 0;
+}
+
+yasm_bytecode *
+yasm_bc_create_incbin(char *filename, yasm_expr *start, yasm_expr *maxlen,
+ yasm_linemap *linemap, unsigned long line)
+{
+ bytecode_incbin *incbin = yasm_xmalloc(sizeof(bytecode_incbin));
+ unsigned long xline;
+
+ /* Find from filename based on line number */
+ yasm_linemap_lookup(linemap, line, &incbin->from, &xline);
+
+ /*@-mustfree@*/
+ incbin->filename = filename;
+ incbin->start = start;
+ incbin->maxlen = maxlen;
+ /*@=mustfree@*/
+
+ return yasm_bc_create_common(&bc_incbin_callback, incbin, line);
+}
diff --git a/libyasm/bc-org.c b/libyasm/bc-org.c
new file mode 100644
index 0000000..7ef96c8
--- /dev/null
+++ b/libyasm/bc-org.c
@@ -0,0 +1,152 @@
+/*
+ * ORG bytecode
+ *
+ * Copyright (C) 2005-2007 Peter Johnson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "util.h"
+
+#include "libyasm-stdint.h"
+#include "coretype.h"
+#include "file.h"
+
+#include "errwarn.h"
+#include "intnum.h"
+#include "expr.h"
+#include "value.h"
+
+#include "bytecode.h"
+
+
+typedef struct bytecode_org {
+ unsigned long start; /* target starting offset within section */
+ unsigned long fill; /* fill value */
+} bytecode_org;
+
+static void bc_org_destroy(void *contents);
+static void bc_org_print(const void *contents, FILE *f, int indent_level);
+static void bc_org_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc);
+static int bc_org_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
+ void *add_span_data);
+static int bc_org_expand(yasm_bytecode *bc, int span, long old_val,
+ long new_val, /*@out@*/ long *neg_thres,
+ /*@out@*/ long *pos_thres);
+static int bc_org_tobytes(yasm_bytecode *bc, unsigned char **bufp,
+ unsigned char *bufstart, void *d,
+ yasm_output_value_func output_value,
+ /*@null@*/ yasm_output_reloc_func output_reloc);
+
+static const yasm_bytecode_callback bc_org_callback = {
+ bc_org_destroy,
+ bc_org_print,
+ bc_org_finalize,
+ NULL,
+ bc_org_calc_len,
+ bc_org_expand,
+ bc_org_tobytes,
+ YASM_BC_SPECIAL_OFFSET
+};
+
+
+static void
+bc_org_destroy(void *contents)
+{
+ yasm_xfree(contents);
+}
+
+static void
+bc_org_print(const void *contents, FILE *f, int indent_level)
+{
+ const bytecode_org *org = (const bytecode_org *)contents;
+ fprintf(f, "%*s_Org_\n", indent_level, "");
+ fprintf(f, "%*sStart=%lu\n", indent_level, "", org->start);
+}
+
+static void
+bc_org_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc)
+{
+}
+
+static int
+bc_org_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
+ void *add_span_data)
+{
+ bytecode_org *org = (bytecode_org *)bc->contents;
+ long neg_thres = 0;
+ long pos_thres = org->start;
+
+ if (bc_org_expand(bc, 0, 0, (long)bc->offset, &neg_thres, &pos_thres) < 0)
+ return -1;
+
+ return 0;
+}
+
+static int
+bc_org_expand(yasm_bytecode *bc, int span, long old_val, long new_val,
+ /*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres)
+{
+ bytecode_org *org = (bytecode_org *)bc->contents;
+
+ /* Check for overrun */
+ if ((unsigned long)new_val > org->start) {
+ yasm_error_set(YASM_ERROR_GENERAL,
+ N_("ORG overlap with already existing data"));
+ return -1;
+ }
+
+ /* Generate space to start offset */
+ bc->len = org->start - new_val;
+ return 1;
+}
+
+static int
+bc_org_tobytes(yasm_bytecode *bc, unsigned char **bufp,
+ unsigned char *bufstart, void *d,
+ yasm_output_value_func output_value,
+ /*@unused@*/ yasm_output_reloc_func output_reloc)
+{
+ bytecode_org *org = (bytecode_org *)bc->contents;
+ unsigned long len, i;
+
+ /* Sanity check for overrun */
+ if (bc->offset > org->start) {
+ yasm_error_set(YASM_ERROR_GENERAL,
+ N_("ORG overlap with already existing data"));
+ return 1;
+ }
+ len = org->start - bc->offset;
+ for (i=0; i<len; i++)
+ YASM_WRITE_8(*bufp, org->fill); /* XXX: handle more than 8 bit? */
+ return 0;
+}
+
+yasm_bytecode *
+yasm_bc_create_org(unsigned long start, unsigned long fill, unsigned long line)
+{
+ bytecode_org *org = yasm_xmalloc(sizeof(bytecode_org));
+
+ org->start = start;
+ org->fill = fill;
+
+ return yasm_bc_create_common(&bc_org_callback, org, line);
+}
diff --git a/libyasm/bc-reserve.c b/libyasm/bc-reserve.c
new file mode 100644
index 0000000..197175b
--- /dev/null
+++ b/libyasm/bc-reserve.c
@@ -0,0 +1,152 @@
+/*
+ * Bytecode utility functions
+ *
+ * Copyright (C) 2001-2007 Peter Johnson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "util.h"
+
+#include "libyasm-stdint.h"
+#include "coretype.h"
+
+#include "errwarn.h"
+#include "intnum.h"
+#include "expr.h"
+#include "value.h"
+
+#include "bytecode.h"
+
+
+typedef struct bytecode_reserve {
+ /*@only@*/ /*@null@*/ yasm_expr *numitems; /* number of items to reserve */
+ unsigned int itemsize; /* size of each item (in bytes) */
+} bytecode_reserve;
+
+static void bc_reserve_destroy(void *contents);
+static void bc_reserve_print(const void *contents, FILE *f, int indent_level);
+static void bc_reserve_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc);
+static int bc_reserve_elem_size(yasm_bytecode *bc);
+static int bc_reserve_calc_len(yasm_bytecode *bc,
+ yasm_bc_add_span_func add_span,
+ void *add_span_data);
+static int bc_reserve_tobytes(yasm_bytecode *bc, unsigned char **bufp,
+ unsigned char *bufstart, void *d,
+ yasm_output_value_func output_value,
+ /*@null@*/ yasm_output_reloc_func output_reloc);
+
+static const yasm_bytecode_callback bc_reserve_callback = {
+ bc_reserve_destroy,
+ bc_reserve_print,
+ bc_reserve_finalize,
+ bc_reserve_elem_size,
+ bc_reserve_calc_len,
+ yasm_bc_expand_common,
+ bc_reserve_tobytes,
+ YASM_BC_SPECIAL_RESERVE
+};
+
+
+static void
+bc_reserve_destroy(void *contents)
+{
+ bytecode_reserve *reserve = (bytecode_reserve *)contents;
+ yasm_expr_destroy(reserve->numitems);
+ yasm_xfree(contents);
+}
+
+static void
+bc_reserve_print(const void *contents, FILE *f, int indent_level)
+{
+ const bytecode_reserve *reserve = (const bytecode_reserve *)contents;
+ fprintf(f, "%*s_Reserve_\n", indent_level, "");
+ fprintf(f, "%*sNum Items=", indent_level, "");
+ yasm_expr_print(reserve->numitems, f);
+ fprintf(f, "\n%*sItem Size=%u\n", indent_level, "", reserve->itemsize);
+}
+
+static void
+bc_reserve_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc)
+{
+ bytecode_reserve *reserve = (bytecode_reserve *)bc->contents;
+ /* multiply reserve expression into multiple */
+ if (!bc->multiple)
+ bc->multiple = reserve->numitems;
+ else
+ bc->multiple = yasm_expr_create_tree(bc->multiple, YASM_EXPR_MUL,
+ reserve->numitems, bc->line);
+ reserve->numitems = NULL;
+}
+
+static int
+bc_reserve_elem_size(yasm_bytecode *bc)
+{
+ bytecode_reserve *reserve = (bytecode_reserve *)bc->contents;
+ return reserve->itemsize;
+}
+
+static int
+bc_reserve_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
+ void *add_span_data)
+{
+ bytecode_reserve *reserve = (bytecode_reserve *)bc->contents;
+ bc->len += reserve->itemsize;
+ return 0;
+}
+
+static int
+bc_reserve_tobytes(yasm_bytecode *bc, unsigned char **bufp,
+ unsigned char *bufstart, void *d,
+ yasm_output_value_func output_value,
+ /*@unused@*/ yasm_output_reloc_func output_reloc)
+{
+ yasm_internal_error(N_("bc_reserve_tobytes called"));
+ /*@notreached@*/
+ return 1;
+}
+
+yasm_bytecode *
+yasm_bc_create_reserve(yasm_expr *numitems, unsigned int itemsize,
+ unsigned long line)
+{
+ bytecode_reserve *reserve = yasm_xmalloc(sizeof(bytecode_reserve));
+
+ /*@-mustfree@*/
+ reserve->numitems = numitems;
+ /*@=mustfree@*/
+ reserve->itemsize = itemsize;
+
+ return yasm_bc_create_common(&bc_reserve_callback, reserve, line);
+}
+
+const yasm_expr *
+yasm_bc_reserve_numitems(yasm_bytecode *bc, unsigned int *itemsize)
+{
+ bytecode_reserve *reserve;
+
+ if (bc->callback != &bc_reserve_callback)
+ return NULL;
+
+ reserve = (bytecode_reserve *)bc->contents;
+ *itemsize = reserve->itemsize;
+ return reserve->numitems;
+}
diff --git a/libyasm/bitvect.c b/libyasm/bitvect.c
new file mode 100644
index 0000000..dfb0825
--- /dev/null
+++ b/libyasm/bitvect.c
@@ -0,0 +1,4045 @@
+#include "util.h"
+
+#include "coretype.h"
+
+/*****************************************************************************/
+/* MODULE NAME: BitVector.c MODULE TYPE: (adt) */
+/*****************************************************************************/
+/* MODULE IMPORTS: */
+/*****************************************************************************/
+#include <ctype.h> /* MODULE TYPE: (sys) */
+#include <limits.h> /* MODULE TYPE: (sys) */
+#include <string.h> /* MODULE TYPE: (sys) */
+/*****************************************************************************/
+/* MODULE INTERFACE: */
+/*****************************************************************************/
+#include "bitvect.h"
+
+/* ToolBox.h */
+#define and && /* logical (boolean) operators: lower case */
+#define or ||
+#define not !
+
+#define AND & /* binary (bitwise) operators: UPPER CASE */
+#define OR |
+#define XOR ^
+#define NOT ~
+#define SHL <<
+#define SHR >>
+
+#ifdef ENABLE_MODULO
+#define mod % /* arithmetic operators */
+#endif
+
+#define blockdef(name,size) unsigned char name[size]
+#define blocktypedef(name,size) typedef unsigned char name[size]
+
+/*****************************************************************************/
+/* MODULE RESOURCES: */
+/*****************************************************************************/
+
+#define bits_(BitVector) *(BitVector-3)
+#define size_(BitVector) *(BitVector-2)
+#define mask_(BitVector) *(BitVector-1)
+
+#define ERRCODE_TYPE "sizeof(word) > sizeof(size_t)"
+#define ERRCODE_BITS "bits(word) != sizeof(word)*8"
+#define ERRCODE_WORD "bits(word) < 16"
+#define ERRCODE_LONG "bits(word) > bits(long)"
+#define ERRCODE_POWR "bits(word) != 2^x"
+#define ERRCODE_LOGA "bits(word) != 2^ld(bits(word))"
+#define ERRCODE_NULL "unable to allocate memory"
+#define ERRCODE_INDX "index out of range"
+#define ERRCODE_ORDR "minimum > maximum index"
+#define ERRCODE_SIZE "bit vector size mismatch"
+#define ERRCODE_PARS "input string syntax error"
+#define ERRCODE_OVFL "numeric overflow error"
+#define ERRCODE_SAME "result vector(s) must be distinct"
+#define ERRCODE_EXPO "exponent must be positive"
+#define ERRCODE_ZERO "division by zero error"
+#define ERRCODE_OOPS "unexpected internal error - please contact author"
+
+const N_int BitVector_BYTENORM[256] =
+{
+ 0x00, 0x01, 0x01, 0x02, 0x01, 0x02, 0x02, 0x03,
+ 0x01, 0x02, 0x02, 0x03, 0x02, 0x03, 0x03, 0x04, /* 0x00 */
+ 0x01, 0x02, 0x02, 0x03, 0x02, 0x03, 0x03, 0x04,
+ 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05, /* 0x10 */
+ 0x01, 0x02, 0x02, 0x03, 0x02, 0x03, 0x03, 0x04,
+ 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05, /* 0x20 */
+ 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05,
+ 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06, /* 0x30 */
+ 0x01, 0x02, 0x02, 0x03, 0x02, 0x03, 0x03, 0x04,
+ 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05, /* 0x40 */
+ 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05,
+ 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06, /* 0x50 */
+ 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05,
+ 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06, /* 0x60 */
+ 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06,
+ 0x04, 0x05, 0x05, 0x06, 0x05, 0x06, 0x06, 0x07, /* 0x70 */
+ 0x01, 0x02, 0x02, 0x03, 0x02, 0x03, 0x03, 0x04,
+ 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05, /* 0x80 */
+ 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05,
+ 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06, /* 0x90 */
+ 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05,
+ 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06, /* 0xA0 */
+ 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06,
+ 0x04, 0x05, 0x05, 0x06, 0x05, 0x06, 0x06, 0x07, /* 0xB0 */
+ 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05,
+ 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06, /* 0xC0 */
+ 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06,
+ 0x04, 0x05, 0x05, 0x06, 0x05, 0x06, 0x06, 0x07, /* 0xD0 */
+ 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06,
+ 0x04, 0x05, 0x05, 0x06, 0x05, 0x06, 0x06, 0x07, /* 0xE0 */
+ 0x04, 0x05, 0x05, 0x06, 0x05, 0x06, 0x06, 0x07,
+ 0x05, 0x06, 0x06, 0x07, 0x06, 0x07, 0x07, 0x08 /* 0xF0 */
+};
+
+/*****************************************************************************/
+/* MODULE IMPLEMENTATION: */
+/*****************************************************************************/
+
+ /**********************************************/
+ /* global implementation-intrinsic constants: */
+ /**********************************************/
+
+#define BIT_VECTOR_HIDDEN_WORDS 3
+
+ /*****************************************************************/
+ /* global machine-dependent constants (set by "BitVector_Boot"): */
+ /*****************************************************************/
+
+static N_word BITS; /* = # of bits in machine word (must be power of 2) */
+static N_word MODMASK; /* = BITS - 1 (mask for calculating modulo BITS) */
+static N_word LOGBITS; /* = ld(BITS) (logarithmus dualis) */
+static N_word FACTOR; /* = ld(BITS / 8) (ld of # of bytes) */
+
+static N_word LSB = 1; /* = mask for least significant bit */
+static N_word MSB; /* = mask for most significant bit */
+
+static N_word LONGBITS; /* = # of bits in unsigned long */
+
+static N_word LOG10; /* = logarithm to base 10 of BITS - 1 */
+static N_word EXP10; /* = largest possible power of 10 in signed int */
+
+ /********************************************************************/
+ /* global bit mask table for fast access (set by "BitVector_Boot"): */
+ /********************************************************************/
+
+static wordptr BITMASKTAB;
+
+ /*****************************/
+ /* global macro definitions: */
+ /*****************************/
+
+#define BIT_VECTOR_ZERO_WORDS(target,count) \
+ while (count-- > 0) *target++ = 0;
+
+#define BIT_VECTOR_FILL_WORDS(target,fill,count) \
+ while (count-- > 0) *target++ = fill;
+
+#define BIT_VECTOR_FLIP_WORDS(target,flip,count) \
+ while (count-- > 0) *target++ ^= flip;
+
+#define BIT_VECTOR_COPY_WORDS(target,source,count) \
+ while (count-- > 0) *target++ = *source++;
+
+#define BIT_VECTOR_BACK_WORDS(target,source,count) \
+ { target += count; source += count; while (count-- > 0) *--target = *--source; }
+
+#define BIT_VECTOR_CLR_BIT(address,index) \
+ *(address+(index>>LOGBITS)) &= NOT BITMASKTAB[index AND MODMASK];
+
+#define BIT_VECTOR_SET_BIT(address,index) \
+ *(address+(index>>LOGBITS)) |= BITMASKTAB[index AND MODMASK];
+
+#define BIT_VECTOR_TST_BIT(address,index) \
+ ((*(address+(index>>LOGBITS)) AND BITMASKTAB[index AND MODMASK]) != 0)
+
+#define BIT_VECTOR_FLP_BIT(address,index,mask) \
+ (mask = BITMASKTAB[index AND MODMASK]), \
+ (((*(addr+(index>>LOGBITS)) ^= mask) AND mask) != 0)
+
+#define BIT_VECTOR_DIGITIZE(type,value,digit) \
+ value = (type) ((digit = value) / 10); \
+ digit -= value * 10; \
+ digit += (type) '0';
+
+ /*********************************************************/
+ /* private low-level functions (potentially dangerous!): */
+ /*********************************************************/
+
+static N_word power10(N_word x)
+{
+ N_word y = 1;
+
+ while (x-- > 0) y *= 10;
+ return(y);
+}
+
+static void BIT_VECTOR_zro_words(wordptr addr, N_word count)
+{
+ BIT_VECTOR_ZERO_WORDS(addr,count)
+}
+
+static void BIT_VECTOR_cpy_words(wordptr target, wordptr source, N_word count)
+{
+ BIT_VECTOR_COPY_WORDS(target,source,count)
+}
+
+static void BIT_VECTOR_mov_words(wordptr target, wordptr source, N_word count)
+{
+ if (target != source)
+ {
+ if (target < source) BIT_VECTOR_COPY_WORDS(target,source,count)
+ else BIT_VECTOR_BACK_WORDS(target,source,count)
+ }
+}
+
+static void BIT_VECTOR_ins_words(wordptr addr, N_word total, N_word count,
+ boolean clear)
+{
+ N_word length;
+
+ if ((total > 0) and (count > 0))
+ {
+ if (count > total) count = total;
+ length = total - count;
+ if (length > 0) BIT_VECTOR_mov_words(addr+count,addr,length);
+ if (clear) BIT_VECTOR_zro_words(addr,count);
+ }
+}
+
+static void BIT_VECTOR_del_words(wordptr addr, N_word total, N_word count,
+ boolean clear)
+{
+ N_word length;
+
+ if ((total > 0) and (count > 0))
+ {
+ if (count > total) count = total;
+ length = total - count;
+ if (length > 0) BIT_VECTOR_mov_words(addr,addr+count,length);
+ if (clear) BIT_VECTOR_zro_words(addr+length,count);
+ }
+}
+
+static void BIT_VECTOR_reverse(charptr string, N_word length)
+{
+ charptr last;
+ N_char temp;
+
+ if (length > 1)
+ {
+ last = string + length - 1;
+ while (string < last)
+ {
+ temp = *string;
+ *string = *last;
+ *last = temp;
+ string++;
+ last--;
+ }
+ }
+}
+
+static N_word BIT_VECTOR_int2str(charptr string, N_word value)
+{
+ N_word length;
+ N_word digit;
+ charptr work;
+
+ work = string;
+ if (value > 0)
+ {
+ length = 0;
+ while (value > 0)
+ {
+ BIT_VECTOR_DIGITIZE(N_word,value,digit)
+ *work++ = (N_char) digit;
+ length++;
+ }
+ BIT_VECTOR_reverse(string,length);
+ }
+ else
+ {
+ length = 1;
+ *work++ = (N_char) '0';
+ }
+ return(length);
+}
+
+static N_word BIT_VECTOR_str2int(charptr string, N_word *value)
+{
+ N_word length;
+ N_word digit;
+
+ *value = 0;
+ length = 0;
+ digit = (N_word) *string++;
+ /* separate because isdigit() is likely a macro! */
+ while (isdigit((int)digit) != 0)
+ {
+ length++;
+ digit -= (N_word) '0';
+ if (*value) *value *= 10;
+ *value += digit;
+ digit = (N_word) *string++;
+ }
+ return(length);
+}
+
+ /********************************************/
+ /* routine to convert error code to string: */
+ /********************************************/
+
+const char * BitVector_Error(ErrCode error)
+{
+ switch (error)
+ {
+ case ErrCode_Ok: return( NULL ); break;
+ case ErrCode_Type: return( ERRCODE_TYPE ); break;
+ case ErrCode_Bits: return( ERRCODE_BITS ); break;
+ case ErrCode_Word: return( ERRCODE_WORD ); break;
+ case ErrCode_Long: return( ERRCODE_LONG ); break;
+ case ErrCode_Powr: return( ERRCODE_POWR ); break;
+ case ErrCode_Loga: return( ERRCODE_LOGA ); break;
+ case ErrCode_Null: return( ERRCODE_NULL ); break;
+ case ErrCode_Indx: return( ERRCODE_INDX ); break;
+ case ErrCode_Ordr: return( ERRCODE_ORDR ); break;
+ case ErrCode_Size: return( ERRCODE_SIZE ); break;
+ case ErrCode_Pars: return( ERRCODE_PARS ); break;
+ case ErrCode_Ovfl: return( ERRCODE_OVFL ); break;
+ case ErrCode_Same: return( ERRCODE_SAME ); break;
+ case ErrCode_Expo: return( ERRCODE_EXPO ); break;
+ case ErrCode_Zero: return( ERRCODE_ZERO ); break;
+ default: return( ERRCODE_OOPS ); break;
+ }
+}
+
+ /*****************************************/
+ /* automatic self-configuration routine: */
+ /*****************************************/
+
+ /*******************************************************/
+ /* */
+ /* MUST be called once prior to any other function */
+ /* to initialize the machine dependent constants */
+ /* of this package! (But call only ONCE, or you */
+ /* will suffer memory leaks!) */
+ /* */
+ /*******************************************************/
+
+ErrCode BitVector_Boot(void)
+{
+ N_long longsample = 1L;
+ N_word sample = LSB;
+ N_word lsb;
+
+ if (sizeof(N_word) > sizeof(size_t)) return(ErrCode_Type);
+
+ BITS = 1;
+ while (sample <<= 1) BITS++; /* determine # of bits in a machine word */
+
+ if (BITS != (sizeof(N_word) << 3)) return(ErrCode_Bits);
+
+ if (BITS < 16) return(ErrCode_Word);
+
+ LONGBITS = 1;
+ while (longsample <<= 1) LONGBITS++; /* = # of bits in an unsigned long */
+
+ if (BITS > LONGBITS) return(ErrCode_Long);
+
+ LOGBITS = 0;
+ sample = BITS;
+ lsb = (sample AND LSB);
+ while ((sample >>= 1) and (not lsb))
+ {
+ LOGBITS++;
+ lsb = (sample AND LSB);
+ }
+
+ if (sample) return(ErrCode_Powr); /* # of bits is not a power of 2! */
+
+ if (BITS != (LSB << LOGBITS)) return(ErrCode_Loga);
+
+ MODMASK = BITS - 1;
+ FACTOR = LOGBITS - 3; /* ld(BITS / 8) = ld(BITS) - ld(8) = ld(BITS) - 3 */
+ MSB = (LSB << MODMASK);
+
+ BITMASKTAB = (wordptr) yasm_xmalloc((size_t) (BITS << FACTOR));
+
+ if (BITMASKTAB == NULL) return(ErrCode_Null);
+
+ for ( sample = 0; sample < BITS; sample++ )
+ {
+ BITMASKTAB[sample] = (LSB << sample);
+ }
+
+ LOG10 = (N_word) (MODMASK * 0.30103); /* = (BITS - 1) * ( ln 2 / ln 10 ) */
+ EXP10 = power10(LOG10);
+
+ return(ErrCode_Ok);
+}
+
+void BitVector_Shutdown(void)
+{
+ if (BITMASKTAB) yasm_xfree(BITMASKTAB);
+}
+
+N_word BitVector_Size(N_int bits) /* bit vector size (# of words) */
+{
+ N_word size;
+
+ size = bits >> LOGBITS;
+ if (bits AND MODMASK) size++;
+ return(size);
+}
+
+N_word BitVector_Mask(N_int bits) /* bit vector mask (unused bits) */
+{
+ N_word mask;
+
+ mask = bits AND MODMASK;
+ if (mask) mask = (N_word) ~(~0L << mask); else mask = (N_word) ~0L;
+ return(mask);
+}
+
+const char * BitVector_Version(void)
+{
+ return("6.4");
+}
+
+N_int BitVector_Word_Bits(void)
+{
+ return(BITS);
+}
+
+N_int BitVector_Long_Bits(void)
+{
+ return(LONGBITS);
+}
+
+/********************************************************************/
+/* */
+/* WARNING: Do not "free()" constant character strings, i.e., */
+/* don't call "BitVector_Dispose()" for strings returned */
+/* by "BitVector_Error()" or "BitVector_Version()"! */
+/* */
+/* ONLY call this function for strings allocated with "malloc()", */
+/* i.e., the strings returned by the functions "BitVector_to_*()" */
+/* and "BitVector_Block_Read()"! */
+/* */
+/********************************************************************/
+
+void BitVector_Dispose(charptr string) /* free string */
+{
+ if (string != NULL) yasm_xfree((voidptr) string);
+}
+
+void BitVector_Destroy(wordptr addr) /* free bitvec */
+{
+ if (addr != NULL)
+ {
+ addr -= BIT_VECTOR_HIDDEN_WORDS;
+ yasm_xfree((voidptr) addr);
+ }
+}
+
+void BitVector_Destroy_List(listptr list, N_int count) /* free list */
+{
+ listptr slot;
+
+ if (list != NULL)
+ {
+ slot = list;
+ while (count-- > 0)
+ {
+ BitVector_Destroy(*slot++);
+ }
+ free((voidptr) list);
+ }
+}
+
+wordptr BitVector_Create(N_int bits, boolean clear) /* malloc */
+{
+ N_word size;
+ N_word mask;
+ N_word bytes;
+ wordptr addr;
+ wordptr zero;
+
+ size = BitVector_Size(bits);
+ mask = BitVector_Mask(bits);
+ bytes = (size + BIT_VECTOR_HIDDEN_WORDS) << FACTOR;
+ addr = (wordptr) yasm_xmalloc((size_t) bytes);
+ if (addr != NULL)
+ {
+ *addr++ = bits;
+ *addr++ = size;
+ *addr++ = mask;
+ if (clear)
+ {
+ zero = addr;
+ BIT_VECTOR_ZERO_WORDS(zero,size)
+ }
+ }
+ return(addr);
+}
+
+listptr BitVector_Create_List(N_int bits, boolean clear, N_int count)
+{
+ listptr list = NULL;
+ listptr slot;
+ wordptr addr;
+ N_int i;
+
+ if (count > 0)
+ {
+ list = (listptr) malloc(sizeof(wordptr) * count);
+ if (list != NULL)
+ {
+ slot = list;
+ for ( i = 0; i < count; i++ )
+ {
+ addr = BitVector_Create(bits,clear);
+ if (addr == NULL)
+ {
+ BitVector_Destroy_List(list,i);
+ return(NULL);
+ }
+ *slot++ = addr;
+ }
+ }
+ }
+ return(list);
+}
+
+wordptr BitVector_Resize(wordptr oldaddr, N_int bits) /* realloc */
+{
+ N_word bytes;
+ N_word oldsize;
+ N_word oldmask;
+ N_word newsize;
+ N_word newmask;
+ wordptr newaddr;
+ wordptr source;
+ wordptr target;
+
+ oldsize = size_(oldaddr);
+ oldmask = mask_(oldaddr);
+ newsize = BitVector_Size(bits);
+ newmask = BitVector_Mask(bits);
+ if (oldsize > 0) *(oldaddr+oldsize-1) &= oldmask;
+ if (newsize <= oldsize)
+ {
+ newaddr = oldaddr;
+ bits_(newaddr) = bits;
+ size_(newaddr) = newsize;
+ mask_(newaddr) = newmask;
+ if (newsize > 0) *(newaddr+newsize-1) &= newmask;
+ }
+ else
+ {
+ bytes = (newsize + BIT_VECTOR_HIDDEN_WORDS) << FACTOR;
+ newaddr = (wordptr) yasm_xmalloc((size_t) bytes);
+ if (newaddr != NULL)
+ {
+ *newaddr++ = bits;
+ *newaddr++ = newsize;
+ *newaddr++ = newmask;
+ target = newaddr;
+ source = oldaddr;
+ newsize -= oldsize;
+ BIT_VECTOR_COPY_WORDS(target,source,oldsize)
+ BIT_VECTOR_ZERO_WORDS(target,newsize)
+ }
+ BitVector_Destroy(oldaddr);
+ }
+ return(newaddr);
+}
+
+wordptr BitVector_Shadow(wordptr addr) /* makes new, same size but empty */
+{
+ return( BitVector_Create(bits_(addr),true) );
+}
+
+wordptr BitVector_Clone(wordptr addr) /* makes exact duplicate */
+{
+ N_word bits;
+ wordptr twin;
+
+ bits = bits_(addr);
+ twin = BitVector_Create(bits,false);
+ if ((twin != NULL) and (bits > 0))
+ BIT_VECTOR_cpy_words(twin,addr,size_(addr));
+ return(twin);
+}
+
+wordptr BitVector_Concat(wordptr X, wordptr Y) /* returns concatenation */
+{
+ /* BEWARE that X = most significant part, Y = least significant part! */
+
+ N_word bitsX;
+ N_word bitsY;
+ N_word bitsZ;
+ wordptr Z;
+
+ bitsX = bits_(X);
+ bitsY = bits_(Y);
+ bitsZ = bitsX + bitsY;
+ Z = BitVector_Create(bitsZ,false);
+ if ((Z != NULL) and (bitsZ > 0))
+ {
+ BIT_VECTOR_cpy_words(Z,Y,size_(Y));
+ BitVector_Interval_Copy(Z,X,bitsY,0,bitsX);
+ *(Z+size_(Z)-1) &= mask_(Z);
+ }
+ return(Z);
+}
+
+void BitVector_Copy(wordptr X, wordptr Y) /* X = Y */
+{
+ N_word sizeX = size_(X);
+ N_word sizeY = size_(Y);
+ N_word maskX = mask_(X);
+ N_word maskY = mask_(Y);
+ N_word fill = 0;
+ wordptr lastX;
+ wordptr lastY;
+
+ if ((X != Y) and (sizeX > 0))
+ {
+ lastX = X + sizeX - 1;
+ if (sizeY > 0)
+ {
+ lastY = Y + sizeY - 1;
+ if ( (*lastY AND (maskY AND NOT (maskY >> 1))) == 0 ) *lastY &= maskY;
+ else
+ {
+ fill = (N_word) ~0L;
+ *lastY |= NOT maskY;
+ }
+ while ((sizeX > 0) and (sizeY > 0))
+ {
+ *X++ = *Y++;
+ sizeX--;
+ sizeY--;
+ }
+ *lastY &= maskY;
+ }
+ while (sizeX-- > 0) *X++ = fill;
+ *lastX &= maskX;
+ }
+}
+
+void BitVector_Empty(wordptr addr) /* X = {} clr all */
+{
+ N_word size = size_(addr);
+
+ BIT_VECTOR_ZERO_WORDS(addr,size)
+}
+
+void BitVector_Fill(wordptr addr) /* X = ~{} set all */
+{
+ N_word size = size_(addr);
+ N_word mask = mask_(addr);
+ N_word fill = (N_word) ~0L;
+
+ if (size > 0)
+ {
+ BIT_VECTOR_FILL_WORDS(addr,fill,size)
+ *(--addr) &= mask;
+ }
+}
+
+void BitVector_Flip(wordptr addr) /* X = ~X flip all */
+{
+ N_word size = size_(addr);
+ N_word mask = mask_(addr);
+ N_word flip = (N_word) ~0L;
+
+ if (size > 0)
+ {
+ BIT_VECTOR_FLIP_WORDS(addr,flip,size)
+ *(--addr) &= mask;
+ }
+}
+
+void BitVector_Primes(wordptr addr)
+{
+ N_word bits = bits_(addr);
+ N_word size = size_(addr);
+ wordptr work;
+ N_word temp;
+ N_word i,j;
+
+ if (size > 0)
+ {
+ temp = 0xAAAA;
+ i = BITS >> 4;
+ while (--i > 0)
+ {
+ temp <<= 16;
+ temp |= 0xAAAA;
+ }
+ i = size;
+ work = addr;
+ *work++ = temp XOR 0x0006;
+ while (--i > 0) *work++ = temp;
+ for ( i = 3; (j = i * i) < bits; i += 2 )
+ {
+ for ( ; j < bits; j += i ) BIT_VECTOR_CLR_BIT(addr,j)
+ }
+ *(addr+size-1) &= mask_(addr);
+ }
+}
+
+void BitVector_Reverse(wordptr X, wordptr Y)
+{
+ N_word bits = bits_(X);
+ N_word mask;
+ N_word bit;
+ N_word value;
+
+ if (bits > 0)
+ {
+ if (X == Y) BitVector_Interval_Reverse(X,0,bits-1);
+ else if (bits == bits_(Y))
+ {
+/* mask = mask_(Y); */
+/* mask &= NOT (mask >> 1); */
+ mask = BITMASKTAB[(bits-1) AND MODMASK];
+ Y += size_(Y) - 1;
+ value = 0;
+ bit = LSB;
+ while (bits-- > 0)
+ {
+ if ((*Y AND mask) != 0)
+ {
+ value |= bit;
+ }
+ if (not (mask >>= 1))
+ {
+ Y--;
+ mask = MSB;
+ }
+ if (not (bit <<= 1))
+ {
+ *X++ = value;
+ value = 0;
+ bit = LSB;
+ }
+ }
+ if (bit > LSB) *X = value;
+ }
+ }
+}
+
+void BitVector_Interval_Empty(wordptr addr, N_int lower, N_int upper)
+{ /* X = X \ [lower..upper] */
+ N_word bits = bits_(addr);
+ N_word size = size_(addr);
+ wordptr loaddr;
+ wordptr hiaddr;
+ N_word lobase;
+ N_word hibase;
+ N_word lomask;
+ N_word himask;
+ N_word diff;
+
+ if ((size > 0) and (lower < bits) and (upper < bits) and (lower <= upper))
+ {
+ lobase = lower >> LOGBITS;
+ hibase = upper >> LOGBITS;
+ diff = hibase - lobase;
+ loaddr = addr + lobase;
+ hiaddr = addr + hibase;
+
+ lomask = (N_word) (~0L << (lower AND MODMASK));
+ himask = (N_word) ~((~0L << (upper AND MODMASK)) << 1);
+
+ if (diff == 0)
+ {
+ *loaddr &= NOT (lomask AND himask);
+ }
+ else
+ {
+ *loaddr++ &= NOT lomask;
+ while (--diff > 0)
+ {
+ *loaddr++ = 0;
+ }
+ *hiaddr &= NOT himask;
+ }
+ }
+}
+
+void BitVector_Interval_Fill(wordptr addr, N_int lower, N_int upper)
+{ /* X = X + [lower..upper] */
+ N_word bits = bits_(addr);
+ N_word size = size_(addr);
+ N_word fill = (N_word) ~0L;
+ wordptr loaddr;
+ wordptr hiaddr;
+ N_word lobase;
+ N_word hibase;
+ N_word lomask;
+ N_word himask;
+ N_word diff;
+
+ if ((size > 0) and (lower < bits) and (upper < bits) and (lower <= upper))
+ {
+ lobase = lower >> LOGBITS;
+ hibase = upper >> LOGBITS;
+ diff = hibase - lobase;
+ loaddr = addr + lobase;
+ hiaddr = addr + hibase;
+
+ lomask = (N_word) (~0L << (lower AND MODMASK));
+ himask = (N_word) ~((~0L << (upper AND MODMASK)) << 1);
+
+ if (diff == 0)
+ {
+ *loaddr |= (lomask AND himask);
+ }
+ else
+ {
+ *loaddr++ |= lomask;
+ while (--diff > 0)
+ {
+ *loaddr++ = fill;
+ }
+ *hiaddr |= himask;
+ }
+ *(addr+size-1) &= mask_(addr);
+ }
+}
+
+void BitVector_Interval_Flip(wordptr addr, N_int lower, N_int upper)
+{ /* X = X ^ [lower..upper] */
+ N_word bits = bits_(addr);
+ N_word size = size_(addr);
+ N_word flip = (N_word) ~0L;
+ wordptr loaddr;
+ wordptr hiaddr;
+ N_word lobase;
+ N_word hibase;
+ N_word lomask;
+ N_word himask;
+ N_word diff;
+
+ if ((size > 0) and (lower < bits) and (upper < bits) and (lower <= upper))
+ {
+ lobase = lower >> LOGBITS;
+ hibase = upper >> LOGBITS;
+ diff = hibase - lobase;
+ loaddr = addr + lobase;
+ hiaddr = addr + hibase;
+
+ lomask = (N_word) (~0L << (lower AND MODMASK));
+ himask = (N_word) ~((~0L << (upper AND MODMASK)) << 1);
+
+ if (diff == 0)
+ {
+ *loaddr ^= (lomask AND himask);
+ }
+ else
+ {
+ *loaddr++ ^= lomask;
+ while (--diff > 0)
+ {
+ *loaddr++ ^= flip;
+ }
+ *hiaddr ^= himask;
+ }
+ *(addr+size-1) &= mask_(addr);
+ }
+}
+
+void BitVector_Interval_Reverse(wordptr addr, N_int lower, N_int upper)
+{
+ N_word bits = bits_(addr);
+ wordptr loaddr;
+ wordptr hiaddr;
+ N_word lomask;
+ N_word himask;
+
+ if ((bits > 0) and (lower < bits) and (upper < bits) and (lower < upper))
+ {
+ loaddr = addr + (lower >> LOGBITS);
+ hiaddr = addr + (upper >> LOGBITS);
+ lomask = BITMASKTAB[lower AND MODMASK];
+ himask = BITMASKTAB[upper AND MODMASK];
+ for ( bits = upper - lower + 1; bits > 1; bits -= 2 )
+ {
+ if (((*loaddr AND lomask) != 0) XOR ((*hiaddr AND himask) != 0))
+ {
+ *loaddr ^= lomask; /* swap bits only if they differ! */
+ *hiaddr ^= himask;
+ }
+ if (not (lomask <<= 1))
+ {
+ lomask = LSB;
+ loaddr++;
+ }
+ if (not (himask >>= 1))
+ {
+ himask = MSB;
+ hiaddr--;
+ }
+ }
+ }
+}
+
+boolean BitVector_interval_scan_inc(wordptr addr, N_int start,
+ N_intptr min, N_intptr max)
+{
+ N_word size = size_(addr);
+ N_word mask = mask_(addr);
+ N_word offset;
+ N_word bitmask;
+ N_word value;
+ boolean empty;
+
+ if ((size == 0) or (start >= bits_(addr))) return(FALSE);
+
+ *min = start;
+ *max = start;
+
+ offset = start >> LOGBITS;
+
+ *(addr+size-1) &= mask;
+
+ addr += offset;
+ size -= offset;
+
+ bitmask = BITMASKTAB[start AND MODMASK];
+ mask = NOT (bitmask OR (bitmask - 1));
+
+ value = *addr++;
+ if ((value AND bitmask) == 0)
+ {
+ value &= mask;
+ if (value == 0)
+ {
+ offset++;
+ empty = TRUE;
+ while (empty and (--size > 0))
+ {
+ if ((value = *addr++)) empty = false; else offset++;
+ }
+ if (empty) return(FALSE);
+ }
+ start = offset << LOGBITS;
+ bitmask = LSB;
+ mask = value;
+ while (not (mask AND LSB))
+ {
+ bitmask <<= 1;
+ mask >>= 1;
+ start++;
+ }
+ mask = NOT (bitmask OR (bitmask - 1));
+ *min = start;
+ *max = start;
+ }
+ value = NOT value;
+ value &= mask;
+ if (value == 0)
+ {
+ offset++;
+ empty = TRUE;
+ while (empty and (--size > 0))
+ {
+ if ((value = NOT *addr++)) empty = false; else offset++;
+ }
+ if (empty) value = LSB;
+ }
+ start = offset << LOGBITS;
+ while (not (value AND LSB))
+ {
+ value >>= 1;
+ start++;
+ }
+ *max = --start;
+ return(TRUE);
+}
+
+boolean BitVector_interval_scan_dec(wordptr addr, N_int start,
+ N_intptr min, N_intptr max)
+{
+ N_word size = size_(addr);
+ N_word mask = mask_(addr);
+ N_word offset;
+ N_word bitmask;
+ N_word value;
+ boolean empty;
+
+ if ((size == 0) or (start >= bits_(addr))) return(FALSE);
+
+ *min = start;
+ *max = start;
+
+ offset = start >> LOGBITS;
+
+ if (offset >= size) return(FALSE);
+
+ *(addr+size-1) &= mask;
+
+ addr += offset;
+ size = ++offset;
+
+ bitmask = BITMASKTAB[start AND MODMASK];
+ mask = (bitmask - 1);
+
+ value = *addr--;
+ if ((value AND bitmask) == 0)
+ {
+ value &= mask;
+ if (value == 0)
+ {
+ offset--;
+ empty = TRUE;
+ while (empty and (--size > 0))
+ {
+ if ((value = *addr--)) empty = false; else offset--;
+ }
+ if (empty) return(FALSE);
+ }
+ start = offset << LOGBITS;
+ bitmask = MSB;
+ mask = value;
+ while (not (mask AND MSB))
+ {
+ bitmask >>= 1;
+ mask <<= 1;
+ start--;
+ }
+ mask = (bitmask - 1);
+ *max = --start;
+ *min = start;
+ }
+ value = NOT value;
+ value &= mask;
+ if (value == 0)
+ {
+ offset--;
+ empty = TRUE;
+ while (empty and (--size > 0))
+ {
+ if ((value = NOT *addr--)) empty = false; else offset--;
+ }
+ if (empty) value = MSB;
+ }
+ start = offset << LOGBITS;
+ while (not (value AND MSB))
+ {
+ value <<= 1;
+ start--;
+ }
+ *min = start;
+ return(TRUE);
+}
+
+void BitVector_Interval_Copy(wordptr X, wordptr Y, N_int Xoffset,
+ N_int Yoffset, N_int length)
+{
+ N_word bitsX = bits_(X);
+ N_word bitsY = bits_(Y);
+ N_word source = 0; /* silence compiler warning */
+ N_word target = 0; /* silence compiler warning */
+ N_word s_lo_base;
+ N_word s_hi_base;
+ N_word s_lo_bit;
+ N_word s_hi_bit;
+ N_word s_base;
+ N_word s_lower = 0; /* silence compiler warning */
+ N_word s_upper = 0; /* silence compiler warning */
+ N_word s_bits;
+ N_word s_min;
+ N_word s_max;
+ N_word t_lo_base;
+ N_word t_hi_base;
+ N_word t_lo_bit;
+ N_word t_hi_bit;
+ N_word t_base;
+ N_word t_lower = 0; /* silence compiler warning */
+ N_word t_upper = 0; /* silence compiler warning */
+ N_word t_bits;
+ N_word t_min;
+ N_word mask;
+ N_word bits;
+ N_word sel;
+ boolean ascending;
+ boolean notfirst;
+ wordptr Z = X;
+
+ if ((length > 0) and (Xoffset < bitsX) and (Yoffset < bitsY))
+ {
+ if ((Xoffset + length) > bitsX) length = bitsX - Xoffset;
+ if ((Yoffset + length) > bitsY) length = bitsY - Yoffset;
+
+ ascending = (Xoffset <= Yoffset);
+
+ s_lo_base = Yoffset >> LOGBITS;
+ s_lo_bit = Yoffset AND MODMASK;
+ Yoffset += --length;
+ s_hi_base = Yoffset >> LOGBITS;
+ s_hi_bit = Yoffset AND MODMASK;
+
+ t_lo_base = Xoffset >> LOGBITS;
+ t_lo_bit = Xoffset AND MODMASK;
+ Xoffset += length;
+ t_hi_base = Xoffset >> LOGBITS;
+ t_hi_bit = Xoffset AND MODMASK;
+
+ if (ascending)
+ {
+ s_base = s_lo_base;
+ t_base = t_lo_base;
+ }
+ else
+ {
+ s_base = s_hi_base;
+ t_base = t_hi_base;
+ }
+ s_bits = 0;
+ t_bits = 0;
+ Y += s_base;
+ X += t_base;
+ notfirst = FALSE;
+ while (TRUE)
+ {
+ if (t_bits == 0)
+ {
+ if (notfirst)
+ {
+ *X = target;
+ if (ascending)
+ {
+ if (t_base == t_hi_base) break;
+ t_base++;
+ X++;
+ }
+ else
+ {
+ if (t_base == t_lo_base) break;
+ t_base--;
+ X--;
+ }
+ }
+ sel = ((t_base == t_hi_base) << 1) OR (t_base == t_lo_base);
+ switch (sel)
+ {
+ case 0:
+ t_lower = 0;
+ t_upper = BITS - 1;
+ t_bits = BITS;
+ target = 0;
+ break;
+ case 1:
+ t_lower = t_lo_bit;
+ t_upper = BITS - 1;
+ t_bits = BITS - t_lo_bit;
+ mask = (N_word) (~0L << t_lower);
+ target = *X AND NOT mask;
+ break;
+ case 2:
+ t_lower = 0;
+ t_upper = t_hi_bit;
+ t_bits = t_hi_bit + 1;
+ mask = (N_word) ((~0L << t_upper) << 1);
+ target = *X AND mask;
+ break;
+ case 3:
+ t_lower = t_lo_bit;
+ t_upper = t_hi_bit;
+ t_bits = t_hi_bit - t_lo_bit + 1;
+ mask = (N_word) (~0L << t_lower);
+ mask &= (N_word) ~((~0L << t_upper) << 1);
+ target = *X AND NOT mask;
+ break;
+ }
+ }
+ if (s_bits == 0)
+ {
+ if (notfirst)
+ {
+ if (ascending)
+ {
+ if (s_base == s_hi_base) break;
+ s_base++;
+ Y++;
+ }
+ else
+ {
+ if (s_base == s_lo_base) break;
+ s_base--;
+ Y--;
+ }
+ }
+ source = *Y;
+ sel = ((s_base == s_hi_base) << 1) OR (s_base == s_lo_base);
+ switch (sel)
+ {
+ case 0:
+ s_lower = 0;
+ s_upper = BITS - 1;
+ s_bits = BITS;
+ break;
+ case 1:
+ s_lower = s_lo_bit;
+ s_upper = BITS - 1;
+ s_bits = BITS - s_lo_bit;
+ break;
+ case 2:
+ s_lower = 0;
+ s_upper = s_hi_bit;
+ s_bits = s_hi_bit + 1;
+ break;
+ case 3:
+ s_lower = s_lo_bit;
+ s_upper = s_hi_bit;
+ s_bits = s_hi_bit - s_lo_bit + 1;
+ break;
+ }
+ }
+ notfirst = TRUE;
+ if (s_bits > t_bits)
+ {
+ bits = t_bits - 1;
+ if (ascending)
+ {
+ s_min = s_lower;
+ s_max = s_lower + bits;
+ }
+ else
+ {
+ s_max = s_upper;
+ s_min = s_upper - bits;
+ }
+ t_min = t_lower;
+ }
+ else
+ {
+ bits = s_bits - 1;
+ if (ascending) t_min = t_lower;
+ else t_min = t_upper - bits;
+ s_min = s_lower;
+ s_max = s_upper;
+ }
+ bits++;
+ mask = (N_word) (~0L << s_min);
+ mask &= (N_word) ~((~0L << s_max) << 1);
+ if (s_min == t_min) target |= (source AND mask);
+ else
+ {
+ if (s_min < t_min) target |= (source AND mask) << (t_min-s_min);
+ else target |= (source AND mask) >> (s_min-t_min);
+ }
+ if (ascending)
+ {
+ s_lower += bits;
+ t_lower += bits;
+ }
+ else
+ {
+ s_upper -= bits;
+ t_upper -= bits;
+ }
+ s_bits -= bits;
+ t_bits -= bits;
+ }
+ *(Z+size_(Z)-1) &= mask_(Z);
+ }
+}
+
+
+wordptr BitVector_Interval_Substitute(wordptr X, wordptr Y,
+ N_int Xoffset, N_int Xlength,
+ N_int Yoffset, N_int Ylength)
+{
+ N_word Xbits = bits_(X);
+ N_word Ybits = bits_(Y);
+ N_word limit;
+ N_word diff;
+
+ if ((Xoffset <= Xbits) and (Yoffset <= Ybits))
+ {
+ limit = Xoffset + Xlength;
+ if (limit > Xbits)
+ {
+ limit = Xbits;
+ Xlength = Xbits - Xoffset;
+ }
+ if ((Yoffset + Ylength) > Ybits)
+ {
+ Ylength = Ybits - Yoffset;
+ }
+ if (Xlength == Ylength)
+ {
+ if ((Ylength > 0) and ((X != Y) or (Xoffset != Yoffset)))
+ {
+ BitVector_Interval_Copy(X,Y,Xoffset,Yoffset,Ylength);
+ }
+ }
+ else /* Xlength != Ylength */
+ {
+ if (Xlength > Ylength)
+ {
+ diff = Xlength - Ylength;
+ if (Ylength > 0) BitVector_Interval_Copy(X,Y,Xoffset,Yoffset,Ylength);
+ if (limit < Xbits) BitVector_Delete(X,Xoffset+Ylength,diff,FALSE);
+ if ((X = BitVector_Resize(X,Xbits-diff)) == NULL) return(NULL);
+ }
+ else /* Ylength > Xlength ==> Ylength > 0 */
+ {
+ diff = Ylength - Xlength;
+ if (X != Y)
+ {
+ if ((X = BitVector_Resize(X,Xbits+diff)) == NULL) return(NULL);
+ if (limit < Xbits) BitVector_Insert(X,limit,diff,FALSE);
+ BitVector_Interval_Copy(X,Y,Xoffset,Yoffset,Ylength);
+ }
+ else /* in-place */
+ {
+ if ((Y = X = BitVector_Resize(X,Xbits+diff)) == NULL) return(NULL);
+ if (limit >= Xbits)
+ {
+ BitVector_Interval_Copy(X,Y,Xoffset,Yoffset,Ylength);
+ }
+ else /* limit < Xbits */
+ {
+ BitVector_Insert(X,limit,diff,FALSE);
+ if ((Yoffset+Ylength) <= limit)
+ {
+ BitVector_Interval_Copy(X,Y,Xoffset,Yoffset,Ylength);
+ }
+ else /* overlaps or lies above critical area */
+ {
+ if (limit <= Yoffset)
+ {
+ Yoffset += diff;
+ BitVector_Interval_Copy(X,Y,Xoffset,Yoffset,Ylength);
+ }
+ else /* Yoffset < limit */
+ {
+ Xlength = limit - Yoffset;
+ BitVector_Interval_Copy(X,Y,Xoffset,Yoffset,Xlength);
+ Yoffset = Xoffset + Ylength; /* = limit + diff */
+ Xoffset += Xlength;
+ Ylength -= Xlength;
+ BitVector_Interval_Copy(X,Y,Xoffset,Yoffset,Ylength);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return(X);
+}
+
+boolean BitVector_is_empty(wordptr addr) /* X == {} ? */
+{
+ N_word size = size_(addr);
+ boolean r = TRUE;
+
+ if (size > 0)
+ {
+ *(addr+size-1) &= mask_(addr);
+ while (r and (size-- > 0)) r = ( *addr++ == 0 );
+ }
+ return(r);
+}
+
+boolean BitVector_is_full(wordptr addr) /* X == ~{} ? */
+{
+ N_word size = size_(addr);
+ N_word mask = mask_(addr);
+ boolean r = FALSE;
+ wordptr last;
+
+ if (size > 0)
+ {
+ r = TRUE;
+ last = addr + size - 1;
+ *last |= NOT mask;
+ while (r and (size-- > 0)) r = ( NOT *addr++ == 0 );
+ *last &= mask;
+ }
+ return(r);
+}
+
+boolean BitVector_equal(wordptr X, wordptr Y) /* X == Y ? */
+{
+ N_word size = size_(X);
+ N_word mask = mask_(X);
+ boolean r = FALSE;
+
+ if (bits_(X) == bits_(Y))
+ {
+ r = TRUE;
+ if (size > 0)
+ {
+ *(X+size-1) &= mask;
+ *(Y+size-1) &= mask;
+ while (r and (size-- > 0)) r = (*X++ == *Y++);
+ }
+ }
+ return(r);
+}
+
+Z_int BitVector_Lexicompare(wordptr X, wordptr Y) /* X <,=,> Y ? */
+{ /* unsigned */
+ N_word bitsX = bits_(X);
+ N_word bitsY = bits_(Y);
+ N_word size = size_(X);
+ boolean r = TRUE;
+
+ if (bitsX == bitsY)
+ {
+ if (size > 0)
+ {
+ X += size;
+ Y += size;
+ while (r and (size-- > 0)) r = (*(--X) == *(--Y));
+ }
+ if (r) return((Z_int) 0);
+ else
+ {
+ if (*X < *Y) return((Z_int) -1); else return((Z_int) 1);
+ }
+ }
+ else
+ {
+ if (bitsX < bitsY) return((Z_int) -1); else return((Z_int) 1);
+ }
+}
+
+Z_int BitVector_Compare(wordptr X, wordptr Y) /* X <,=,> Y ? */
+{ /* signed */
+ N_word bitsX = bits_(X);
+ N_word bitsY = bits_(Y);
+ N_word size = size_(X);
+ N_word mask = mask_(X);
+ N_word sign;
+ boolean r = TRUE;
+
+ if (bitsX == bitsY)
+ {
+ if (size > 0)
+ {
+ X += size;
+ Y += size;
+ mask &= NOT (mask >> 1);
+ if ((sign = (*(X-1) AND mask)) != (*(Y-1) AND mask))
+ {
+ if (sign) return((Z_int) -1); else return((Z_int) 1);
+ }
+ while (r and (size-- > 0)) r = (*(--X) == *(--Y));
+ }
+ if (r) return((Z_int) 0);
+ else
+ {
+ if (*X < *Y) return((Z_int) -1); else return((Z_int) 1);
+ }
+ }
+ else
+ {
+ if (bitsX < bitsY) return((Z_int) -1); else return((Z_int) 1);
+ }
+}
+
+charptr BitVector_to_Hex(wordptr addr)
+{
+ N_word bits = bits_(addr);
+ N_word size = size_(addr);
+ N_word value;
+ N_word count;
+ N_word digit;
+ N_word length;
+ charptr string;
+
+ length = bits >> 2;
+ if (bits AND 0x0003) length++;
+ string = (charptr) yasm_xmalloc((size_t) (length+1));
+ if (string == NULL) return(NULL);
+ string += length;
+ *string = (N_char) '\0';
+ if (size > 0)
+ {
+ *(addr+size-1) &= mask_(addr);
+ while ((size-- > 0) and (length > 0))
+ {
+ value = *addr++;
+ count = BITS >> 2;
+ while ((count-- > 0) and (length > 0))
+ {
+ digit = value AND 0x000F;
+ if (digit > 9) digit += (N_word) 'A' - 10;
+ else digit += (N_word) '0';
+ *(--string) = (N_char) digit; length--;
+ if ((count > 0) and (length > 0)) value >>= 4;
+ }
+ }
+ }
+ return(string);
+}
+
+ErrCode BitVector_from_Hex(wordptr addr, charptr string)
+{
+ N_word size = size_(addr);
+ N_word mask = mask_(addr);
+ boolean ok = TRUE;
+ size_t length;
+ N_word value;
+ N_word count;
+ int digit;
+
+ if (size > 0)
+ {
+ length = strlen((char *) string);
+ string += length;
+ while (size-- > 0)
+ {
+ value = 0;
+ for ( count = 0; (ok and (length > 0) and (count < BITS)); count += 4 )
+ {
+ digit = (int) *(--string); length--;
+ /* separate because toupper() is likely a macro! */
+ digit = toupper(digit);
+ if (digit == '_')
+ count -= 4;
+ else if ((ok = (isxdigit(digit) != 0)))
+ {
+ if (digit >= (int) 'A') digit -= (int) 'A' - 10;
+ else digit -= (int) '0';
+ value |= (((N_word) digit) << count);
+ }
+ }
+ *addr++ = value;
+ }
+ *(--addr) &= mask;
+ }
+ if (ok) return(ErrCode_Ok);
+ else return(ErrCode_Pars);
+}
+
+ErrCode BitVector_from_Oct(wordptr addr, charptr string)
+{
+ N_word size = size_(addr);
+ N_word mask = mask_(addr);
+ boolean ok = TRUE;
+ size_t length;
+ N_word value;
+ N_word value_fill = 0;
+ N_word count;
+ Z_word count_fill = 0;
+ int digit = 0;
+
+ if (size > 0)
+ {
+ length = strlen((char *) string);
+ string += length;
+ while (size-- > 0)
+ {
+ value = value_fill;
+ for ( count = count_fill; (ok and (length > 0) and (count < BITS)); count += 3 )
+ {
+ digit = (int) *(--string); length--;
+ if (digit == '_')
+ count -= 3;
+ else if ((ok = (isdigit(digit) && digit != '8' && digit != '9')) != 0)
+ {
+ digit -= (int) '0';
+ value |= (((N_word) digit) << count);
+ }
+ }
+ count_fill = (Z_word)count-(Z_word)BITS;
+ if (count_fill > 0)
+ value_fill = (((N_word) digit) >> (3-count_fill));
+ else
+ value_fill = 0;
+ *addr++ = value;
+ }
+ *(--addr) &= mask;
+ }
+ if (ok) return(ErrCode_Ok);
+ else return(ErrCode_Pars);
+}
+
+charptr BitVector_to_Bin(wordptr addr)
+{
+ N_word size = size_(addr);
+ N_word value;
+ N_word count;
+ N_word digit;
+ N_word length;
+ charptr string;
+
+ length = bits_(addr);
+ string = (charptr) yasm_xmalloc((size_t) (length+1));
+ if (string == NULL) return(NULL);
+ string += length;
+ *string = (N_char) '\0';
+ if (size > 0)
+ {
+ *(addr+size-1) &= mask_(addr);
+ while (size-- > 0)
+ {
+ value = *addr++;
+ count = BITS;
+ if (count > length) count = length;
+ while (count-- > 0)
+ {
+ digit = value AND 0x0001;
+ digit += (N_word) '0';
+ *(--string) = (N_char) digit; length--;
+ if (count > 0) value >>= 1;
+ }
+ }
+ }
+ return(string);
+}
+
+ErrCode BitVector_from_Bin(wordptr addr, charptr string)
+{
+ N_word size = size_(addr);
+ N_word mask = mask_(addr);
+ boolean ok = TRUE;
+ size_t length;
+ N_word value;
+ N_word count;
+ int digit;
+
+ if (size > 0)
+ {
+ length = strlen((char *) string);
+ string += length;
+ while (size-- > 0)
+ {
+ value = 0;
+ for ( count = 0; (ok and (length > 0) and (count < BITS)); count++ )
+ {
+ digit = (int) *(--string); length--;
+ switch (digit)
+ {
+ case (int) '0':
+ break;
+ case (int) '1':
+ value |= BITMASKTAB[count];
+ break;
+ case (int) '_':
+ count--;
+ break;
+ default:
+ ok = FALSE;
+ break;
+ }
+ }
+ *addr++ = value;
+ }
+ *(--addr) &= mask;
+ }
+ if (ok) return(ErrCode_Ok);
+ else return(ErrCode_Pars);
+}
+
+charptr BitVector_to_Dec(wordptr addr)
+{
+ N_word bits = bits_(addr);
+ N_word length;
+ N_word digits;
+ N_word count;
+ N_word q;
+ N_word r;
+ boolean loop;
+ charptr result;
+ charptr string;
+ wordptr quot;
+ wordptr rest;
+ wordptr temp;
+ wordptr base;
+ Z_int sign;
+
+ length = (N_word) (bits / 3.3); /* digits = bits * ln(2) / ln(10) */
+ length += 2; /* compensate for truncating & provide space for minus sign */
+ result = (charptr) yasm_xmalloc((size_t) (length+1)); /* remember the '\0'! */
+ if (result == NULL) return(NULL);
+ string = result;
+ sign = BitVector_Sign(addr);
+ if ((bits < 4) or (sign == 0))
+ {
+ if (bits > 0) digits = *addr; else digits = (N_word) 0;
+ if (sign < 0) digits = ((N_word)(-((Z_word)digits))) AND mask_(addr);
+ *string++ = (N_char) digits + (N_char) '0';
+ digits = 1;
+ }
+ else
+ {
+ quot = BitVector_Create(bits,FALSE);
+ if (quot == NULL)
+ {
+ BitVector_Dispose(result);
+ return(NULL);
+ }
+ rest = BitVector_Create(bits,FALSE);
+ if (rest == NULL)
+ {
+ BitVector_Dispose(result);
+ BitVector_Destroy(quot);
+ return(NULL);
+ }
+ temp = BitVector_Create(bits,FALSE);
+ if (temp == NULL)
+ {
+ BitVector_Dispose(result);
+ BitVector_Destroy(quot);
+ BitVector_Destroy(rest);
+ return(NULL);
+ }
+ base = BitVector_Create(bits,TRUE);
+ if (base == NULL)
+ {
+ BitVector_Dispose(result);
+ BitVector_Destroy(quot);
+ BitVector_Destroy(rest);
+ BitVector_Destroy(temp);
+ return(NULL);
+ }
+ if (sign < 0) BitVector_Negate(quot,addr);
+ else BitVector_Copy(quot,addr);
+ digits = 0;
+ *base = EXP10;
+ loop = (bits >= BITS);
+ do
+ {
+ if (loop)
+ {
+ BitVector_Copy(temp,quot);
+ if (BitVector_Div_Pos(quot,temp,base,rest))
+ {
+ BitVector_Dispose(result); /* emergency exit */
+ BitVector_Destroy(quot);
+ BitVector_Destroy(rest); /* should never occur */
+ BitVector_Destroy(temp); /* under normal operation */
+ BitVector_Destroy(base);
+ return(NULL);
+ }
+ loop = not BitVector_is_empty(quot);
+ q = *rest;
+ }
+ else q = *quot;
+ count = LOG10;
+ while (((loop and (count-- > 0)) or ((not loop) and (q != 0))) and
+ (digits < length))
+ {
+ if (q != 0)
+ {
+ BIT_VECTOR_DIGITIZE(N_word,q,r)
+ }
+ else r = (N_word) '0';
+ *string++ = (N_char) r;
+ digits++;
+ }
+ }
+ while (loop and (digits < length));
+ BitVector_Destroy(quot);
+ BitVector_Destroy(rest);
+ BitVector_Destroy(temp);
+ BitVector_Destroy(base);
+ }
+ if ((sign < 0) and (digits < length))
+ {
+ *string++ = (N_char) '-';
+ digits++;
+ }
+ *string = (N_char) '\0';
+ BIT_VECTOR_reverse(result,digits);
+ return(result);
+}
+
+struct BitVector_from_Dec_static_data {
+ wordptr term;
+ wordptr base;
+ wordptr prod;
+ wordptr rank;
+ wordptr temp;
+};
+
+BitVector_from_Dec_static_data *BitVector_from_Dec_static_Boot(N_word bits)
+{
+ BitVector_from_Dec_static_data *data;
+
+ data = yasm_xmalloc(sizeof(BitVector_from_Dec_static_data));
+
+ if (bits > 0)
+ {
+ data->term = BitVector_Create(BITS,FALSE);
+ data->base = BitVector_Create(BITS,FALSE);
+ data->prod = BitVector_Create(bits,FALSE);
+ data->rank = BitVector_Create(bits,FALSE);
+ data->temp = BitVector_Create(bits,FALSE);
+ } else {
+ data->term = NULL;
+ data->base = NULL;
+ data->prod = NULL;
+ data->rank = NULL;
+ data->temp = NULL;
+ }
+ return data;
+}
+
+void BitVector_from_Dec_static_Shutdown(BitVector_from_Dec_static_data *data)
+{
+ if (data) {
+ BitVector_Destroy(data->term);
+ BitVector_Destroy(data->base);
+ BitVector_Destroy(data->prod);
+ BitVector_Destroy(data->rank);
+ BitVector_Destroy(data->temp);
+ }
+ yasm_xfree(data);
+}
+
+ErrCode BitVector_from_Dec_static(BitVector_from_Dec_static_data *data,
+ wordptr addr, charptr string)
+{
+ ErrCode error = ErrCode_Ok;
+ N_word bits = bits_(addr);
+ N_word mask = mask_(addr);
+ boolean init = (bits > BITS);
+ boolean minus;
+ boolean shift;
+ boolean carry;
+ wordptr term;
+ wordptr base;
+ wordptr prod;
+ wordptr rank;
+ wordptr temp;
+ N_word accu;
+ N_word powr;
+ N_word count;
+ size_t length;
+ int digit;
+
+ if (bits > 0)
+ {
+ term = data->term;
+ base = data->base;
+ prod = data->prod;
+ rank = data->rank;
+ temp = data->temp;
+
+ length = strlen((char *) string);
+ if (length == 0) return(ErrCode_Pars);
+ digit = (int) *string;
+ if ((minus = (digit == (int) '-')) or
+ (digit == (int) '+'))
+ {
+ string++;
+ if (--length == 0) return(ErrCode_Pars);
+ }
+ string += length;
+ if (init)
+ {
+ BitVector_Empty(prod);
+ BitVector_Empty(rank);
+ }
+ BitVector_Empty(addr);
+ *base = EXP10;
+ shift = FALSE;
+ while ((not error) and (length > 0))
+ {
+ accu = 0;
+ powr = 1;
+ count = LOG10;
+ while ((not error) and (length > 0) and (count-- > 0))
+ {
+ digit = (int) *(--string); length--;
+ /* separate because isdigit() is likely a macro! */
+ if (isdigit(digit) != 0)
+ {
+ accu += ((N_word) digit - (N_word) '0') * powr;
+ powr *= 10;
+ }
+ else error = ErrCode_Pars;
+ }
+ if (not error)
+ {
+ if (shift)
+ {
+ *term = accu;
+ BitVector_Copy(temp,rank);
+ error = BitVector_Mul_Pos(prod,temp,term,FALSE);
+ }
+ else
+ {
+ *prod = accu;
+ if ((not init) and ((accu AND NOT mask) != 0)) error = ErrCode_Ovfl;
+ }
+ if (not error)
+ {
+ carry = FALSE;
+ BitVector_compute(addr,addr,prod,FALSE,&carry);
+ /* ignores sign change (= overflow) but not */
+ /* numbers too large (= carry) for resulting bit vector */
+ if (carry) error = ErrCode_Ovfl;
+ else
+ {
+ if (length > 0)
+ {
+ if (shift)
+ {
+ BitVector_Copy(temp,rank);
+ error = BitVector_Mul_Pos(rank,temp,base,FALSE);
+ }
+ else
+ {
+ *rank = *base;
+ shift = TRUE;
+ }
+ }
+ }
+ }
+ }
+ }
+ if (not error and minus)
+ {
+ BitVector_Negate(addr,addr);
+ if ((*(addr + size_(addr) - 1) AND mask AND NOT (mask >> 1)) == 0)
+ error = ErrCode_Ovfl;
+ }
+ }
+ return(error);
+}
+
+ErrCode BitVector_from_Dec(wordptr addr, charptr string)
+{
+ ErrCode error = ErrCode_Ok;
+ N_word bits = bits_(addr);
+ N_word mask = mask_(addr);
+ boolean init = (bits > BITS);
+ boolean minus;
+ boolean shift;
+ boolean carry;
+ wordptr term;
+ wordptr base;
+ wordptr prod;
+ wordptr rank;
+ wordptr temp;
+ N_word accu;
+ N_word powr;
+ N_word count;
+ size_t length;
+ int digit;
+
+ if (bits > 0)
+ {
+ length = strlen((char *) string);
+ if (length == 0) return(ErrCode_Pars);
+ digit = (int) *string;
+ if ((minus = (digit == (int) '-')) or
+ (digit == (int) '+'))
+ {
+ string++;
+ if (--length == 0) return(ErrCode_Pars);
+ }
+ string += length;
+ term = BitVector_Create(BITS,FALSE);
+ if (term == NULL)
+ {
+ return(ErrCode_Null);
+ }
+ base = BitVector_Create(BITS,FALSE);
+ if (base == NULL)
+ {
+ BitVector_Destroy(term);
+ return(ErrCode_Null);
+ }
+ prod = BitVector_Create(bits,init);
+ if (prod == NULL)
+ {
+ BitVector_Destroy(term);
+ BitVector_Destroy(base);
+ return(ErrCode_Null);
+ }
+ rank = BitVector_Create(bits,init);
+ if (rank == NULL)
+ {
+ BitVector_Destroy(term);
+ BitVector_Destroy(base);
+ BitVector_Destroy(prod);
+ return(ErrCode_Null);
+ }
+ temp = BitVector_Create(bits,FALSE);
+ if (temp == NULL)
+ {
+ BitVector_Destroy(term);
+ BitVector_Destroy(base);
+ BitVector_Destroy(prod);
+ BitVector_Destroy(rank);
+ return(ErrCode_Null);
+ }
+ BitVector_Empty(addr);
+ *base = EXP10;
+ shift = FALSE;
+ while ((not error) and (length > 0))
+ {
+ accu = 0;
+ powr = 1;
+ count = LOG10;
+ while ((not error) and (length > 0) and (count-- > 0))
+ {
+ digit = (int) *(--string); length--;
+ /* separate because isdigit() is likely a macro! */
+ if (isdigit(digit) != 0)
+ {
+ accu += ((N_word) digit - (N_word) '0') * powr;
+ powr *= 10;
+ }
+ else error = ErrCode_Pars;
+ }
+ if (not error)
+ {
+ if (shift)
+ {
+ *term = accu;
+ BitVector_Copy(temp,rank);
+ error = BitVector_Mul_Pos(prod,temp,term,FALSE);
+ }
+ else
+ {
+ *prod = accu;
+ if ((not init) and ((accu AND NOT mask) != 0)) error = ErrCode_Ovfl;
+ }
+ if (not error)
+ {
+ carry = FALSE;
+ BitVector_compute(addr,addr,prod,FALSE,&carry);
+ /* ignores sign change (= overflow) but not */
+ /* numbers too large (= carry) for resulting bit vector */
+ if (carry) error = ErrCode_Ovfl;
+ else
+ {
+ if (length > 0)
+ {
+ if (shift)
+ {
+ BitVector_Copy(temp,rank);
+ error = BitVector_Mul_Pos(rank,temp,base,FALSE);
+ }
+ else
+ {
+ *rank = *base;
+ shift = TRUE;
+ }
+ }
+ }
+ }
+ }
+ }
+ BitVector_Destroy(term);
+ BitVector_Destroy(base);
+ BitVector_Destroy(prod);
+ BitVector_Destroy(rank);
+ BitVector_Destroy(temp);
+ if (not error and minus)
+ {
+ BitVector_Negate(addr,addr);
+ if ((*(addr + size_(addr) - 1) AND mask AND NOT (mask >> 1)) == 0)
+ error = ErrCode_Ovfl;
+ }
+ }
+ return(error);
+}
+
+charptr BitVector_to_Enum(wordptr addr)
+{
+ N_word bits = bits_(addr);
+ N_word sample;
+ N_word length;
+ N_word digits;
+ N_word factor;
+ N_word power;
+ N_word start;
+ N_word min;
+ N_word max;
+ charptr string;
+ charptr target;
+ boolean comma;
+
+ if (bits > 0)
+ {
+ sample = bits - 1; /* greatest possible index */
+ length = 2; /* account for index 0 and terminating '\0' */
+ digits = 1; /* account for intervening dashes and commas */
+ factor = 1;
+ power = 10;
+ while (sample >= (power-1))
+ {
+ length += ++digits * factor * 6; /* 9,90,900,9000,... (9*2/3 = 6) */
+ factor = power;
+ power *= 10;
+ }
+ if (sample > --factor)
+ {
+ sample -= factor;
+ factor = (N_word) ( sample / 3 );
+ factor = (factor << 1) + (sample - (factor * 3));
+ length += ++digits * factor;
+ }
+ }
+ else length = 1;
+ string = (charptr) yasm_xmalloc((size_t) length);
+ if (string == NULL) return(NULL);
+ start = 0;
+ comma = FALSE;
+ target = string;
+ while ((start < bits) and BitVector_interval_scan_inc(addr,start,&min,&max))
+ {
+ start = max + 2;
+ if (comma) *target++ = (N_char) ',';
+ if (min == max)
+ {
+ target += BIT_VECTOR_int2str(target,min);
+ }
+ else
+ {
+ if (min+1 == max)
+ {
+ target += BIT_VECTOR_int2str(target,min);
+ *target++ = (N_char) ',';
+ target += BIT_VECTOR_int2str(target,max);
+ }
+ else
+ {
+ target += BIT_VECTOR_int2str(target,min);
+ *target++ = (N_char) '-';
+ target += BIT_VECTOR_int2str(target,max);
+ }
+ }
+ comma = TRUE;
+ }
+ *target = (N_char) '\0';
+ return(string);
+}
+
+ErrCode BitVector_from_Enum(wordptr addr, charptr string)
+{
+ ErrCode error = ErrCode_Ok;
+ N_word bits = bits_(addr);
+ N_word state = 1;
+ N_word token;
+ N_word indx = 0; /* silence compiler warning */
+ N_word start = 0; /* silence compiler warning */
+
+ if (bits > 0)
+ {
+ BitVector_Empty(addr);
+ while ((not error) and (state != 0))
+ {
+ token = (N_word) *string;
+ /* separate because isdigit() is likely a macro! */
+ if (isdigit((int)token) != 0)
+ {
+ string += BIT_VECTOR_str2int(string,&indx);
+ if (indx < bits) token = (N_word) '0';
+ else error = ErrCode_Indx;
+ }
+ else string++;
+ if (not error)
+ switch (state)
+ {
+ case 1:
+ switch (token)
+ {
+ case (N_word) '0':
+ state = 2;
+ break;
+ case (N_word) '\0':
+ state = 0;
+ break;
+ default:
+ error = ErrCode_Pars;
+ break;
+ }
+ break;
+ case 2:
+ switch (token)
+ {
+ case (N_word) '-':
+ start = indx;
+ state = 3;
+ break;
+ case (N_word) ',':
+ BIT_VECTOR_SET_BIT(addr,indx)
+ state = 5;
+ break;
+ case (N_word) '\0':
+ BIT_VECTOR_SET_BIT(addr,indx)
+ state = 0;
+ break;
+ default:
+ error = ErrCode_Pars;
+ break;
+ }
+ break;
+ case 3:
+ switch (token)
+ {
+ case (N_word) '0':
+ if (start < indx)
+ BitVector_Interval_Fill(addr,start,indx);
+ else if (start == indx)
+ BIT_VECTOR_SET_BIT(addr,indx)
+ else error = ErrCode_Ordr;
+ state = 4;
+ break;
+ default:
+ error = ErrCode_Pars;
+ break;
+ }
+ break;
+ case 4:
+ switch (token)
+ {
+ case (N_word) ',':
+ state = 5;
+ break;
+ case (N_word) '\0':
+ state = 0;
+ break;
+ default:
+ error = ErrCode_Pars;
+ break;
+ }
+ break;
+ case 5:
+ switch (token)
+ {
+ case (N_word) '0':
+ state = 2;
+ break;
+ default:
+ error = ErrCode_Pars;
+ break;
+ }
+ break;
+ }
+ }
+ }
+ return(error);
+}
+
+void BitVector_Bit_Off(wordptr addr, N_int indx) /* X = X \ {x} */
+{
+ if (indx < bits_(addr)) BIT_VECTOR_CLR_BIT(addr,indx)
+}
+
+void BitVector_Bit_On(wordptr addr, N_int indx) /* X = X + {x} */
+{
+ if (indx < bits_(addr)) BIT_VECTOR_SET_BIT(addr,indx)
+}
+
+boolean BitVector_bit_flip(wordptr addr, N_int indx) /* X=(X+{x})\(X*{x}) */
+{
+ N_word mask;
+
+ if (indx < bits_(addr)) return( BIT_VECTOR_FLP_BIT(addr,indx,mask) );
+ else return( FALSE );
+}
+
+boolean BitVector_bit_test(wordptr addr, N_int indx) /* {x} in X ? */
+{
+ if (indx < bits_(addr)) return( BIT_VECTOR_TST_BIT(addr,indx) );
+ else return( FALSE );
+}
+
+void BitVector_Bit_Copy(wordptr addr, N_int indx, boolean bit)
+{
+ if (indx < bits_(addr))
+ {
+ if (bit) BIT_VECTOR_SET_BIT(addr,indx)
+ else BIT_VECTOR_CLR_BIT(addr,indx)
+ }
+}
+
+void BitVector_LSB(wordptr addr, boolean bit)
+{
+ if (bits_(addr) > 0)
+ {
+ if (bit) *addr |= LSB;
+ else *addr &= NOT LSB;
+ }
+}
+
+void BitVector_MSB(wordptr addr, boolean bit)
+{
+ N_word size = size_(addr);
+ N_word mask = mask_(addr);
+
+ if (size-- > 0)
+ {
+ if (bit) *(addr+size) |= mask AND NOT (mask >> 1);
+ else *(addr+size) &= NOT mask OR (mask >> 1);
+ }
+}
+
+boolean BitVector_lsb_(wordptr addr)
+{
+ if (size_(addr) > 0) return( (*addr AND LSB) != 0 );
+ else return( FALSE );
+}
+
+boolean BitVector_msb_(wordptr addr)
+{
+ N_word size = size_(addr);
+ N_word mask = mask_(addr);
+
+ if (size-- > 0)
+ return( (*(addr+size) AND (mask AND NOT (mask >> 1))) != 0 );
+ else
+ return( FALSE );
+}
+
+boolean BitVector_rotate_left(wordptr addr)
+{
+ N_word size = size_(addr);
+ N_word mask = mask_(addr);
+ N_word msb;
+ boolean carry_in;
+ boolean carry_out = FALSE;
+
+ if (size > 0)
+ {
+ msb = mask AND NOT (mask >> 1);
+ carry_in = ((*(addr+size-1) AND msb) != 0);
+ while (size-- > 1)
+ {
+ carry_out = ((*addr AND MSB) != 0);
+ *addr <<= 1;
+ if (carry_in) *addr |= LSB;
+ carry_in = carry_out;
+ addr++;
+ }
+ carry_out = ((*addr AND msb) != 0);
+ *addr <<= 1;
+ if (carry_in) *addr |= LSB;
+ *addr &= mask;
+ }
+ return(carry_out);
+}
+
+boolean BitVector_rotate_right(wordptr addr)
+{
+ N_word size = size_(addr);
+ N_word mask = mask_(addr);
+ N_word msb;
+ boolean carry_in;
+ boolean carry_out = FALSE;
+
+ if (size > 0)
+ {
+ msb = mask AND NOT (mask >> 1);
+ carry_in = ((*addr AND LSB) != 0);
+ addr += size-1;
+ *addr &= mask;
+ carry_out = ((*addr AND LSB) != 0);
+ *addr >>= 1;
+ if (carry_in) *addr |= msb;
+ carry_in = carry_out;
+ addr--;
+ size--;
+ while (size-- > 0)
+ {
+ carry_out = ((*addr AND LSB) != 0);
+ *addr >>= 1;
+ if (carry_in) *addr |= MSB;
+ carry_in = carry_out;
+ addr--;
+ }
+ }
+ return(carry_out);
+}
+
+boolean BitVector_shift_left(wordptr addr, boolean carry_in)
+{
+ N_word size = size_(addr);
+ N_word mask = mask_(addr);
+ N_word msb;
+ boolean carry_out = carry_in;
+
+ if (size > 0)
+ {
+ msb = mask AND NOT (mask >> 1);
+ while (size-- > 1)
+ {
+ carry_out = ((*addr AND MSB) != 0);
+ *addr <<= 1;
+ if (carry_in) *addr |= LSB;
+ carry_in = carry_out;
+ addr++;
+ }
+ carry_out = ((*addr AND msb) != 0);
+ *addr <<= 1;
+ if (carry_in) *addr |= LSB;
+ *addr &= mask;
+ }
+ return(carry_out);
+}
+
+boolean BitVector_shift_right(wordptr addr, boolean carry_in)
+{
+ N_word size = size_(addr);
+ N_word mask = mask_(addr);
+ N_word msb;
+ boolean carry_out = carry_in;
+
+ if (size > 0)
+ {
+ msb = mask AND NOT (mask >> 1);
+ addr += size-1;
+ *addr &= mask;
+ carry_out = ((*addr AND LSB) != 0);
+ *addr >>= 1;
+ if (carry_in) *addr |= msb;
+ carry_in = carry_out;
+ addr--;
+ size--;
+ while (size-- > 0)
+ {
+ carry_out = ((*addr AND LSB) != 0);
+ *addr >>= 1;
+ if (carry_in) *addr |= MSB;
+ carry_in = carry_out;
+ addr--;
+ }
+ }
+ return(carry_out);
+}
+
+void BitVector_Move_Left(wordptr addr, N_int bits)
+{
+ N_word count;
+ N_word words;
+
+ if (bits > 0)
+ {
+ count = bits AND MODMASK;
+ words = bits >> LOGBITS;
+ if (bits >= bits_(addr)) BitVector_Empty(addr);
+ else
+ {
+ while (count-- > 0) BitVector_shift_left(addr,0);
+ BitVector_Word_Insert(addr,0,words,TRUE);
+ }
+ }
+}
+
+void BitVector_Move_Right(wordptr addr, N_int bits)
+{
+ N_word count;
+ N_word words;
+
+ if (bits > 0)
+ {
+ count = bits AND MODMASK;
+ words = bits >> LOGBITS;
+ if (bits >= bits_(addr)) BitVector_Empty(addr);
+ else
+ {
+ while (count-- > 0) BitVector_shift_right(addr,0);
+ BitVector_Word_Delete(addr,0,words,TRUE);
+ }
+ }
+}
+
+void BitVector_Insert(wordptr addr, N_int offset, N_int count, boolean clear)
+{
+ N_word bits = bits_(addr);
+ N_word last;
+
+ if ((count > 0) and (offset < bits))
+ {
+ last = offset + count;
+ if (last < bits)
+ {
+ BitVector_Interval_Copy(addr,addr,last,offset,(bits-last));
+ }
+ else last = bits;
+ if (clear) BitVector_Interval_Empty(addr,offset,(last-1));
+ }
+}
+
+void BitVector_Delete(wordptr addr, N_int offset, N_int count, boolean clear)
+{
+ N_word bits = bits_(addr);
+ N_word last;
+
+ if ((count > 0) and (offset < bits))
+ {
+ last = offset + count;
+ if (last < bits)
+ {
+ BitVector_Interval_Copy(addr,addr,offset,last,(bits-last));
+ }
+ else count = bits - offset;
+ if (clear) BitVector_Interval_Empty(addr,(bits-count),(bits-1));
+ }
+}
+
+boolean BitVector_increment(wordptr addr) /* X++ */
+{
+ N_word size = size_(addr);
+ N_word mask = mask_(addr);
+ wordptr last = addr + size - 1;
+ boolean carry = TRUE;
+
+ if (size > 0)
+ {
+ *last |= NOT mask;
+ while (carry and (size-- > 0))
+ {
+ carry = (++(*addr++) == 0);
+ }
+ *last &= mask;
+ }
+ return(carry);
+}
+
+boolean BitVector_decrement(wordptr addr) /* X-- */
+{
+ N_word size = size_(addr);
+ N_word mask = mask_(addr);
+ wordptr last = addr + size - 1;
+ boolean carry = TRUE;
+
+ if (size > 0)
+ {
+ *last &= mask;
+ while (carry and (size-- > 0))
+ {
+ carry = (*addr == 0);
+ --(*addr++);
+ }
+ *last &= mask;
+ }
+ return(carry);
+}
+
+boolean BitVector_compute(wordptr X, wordptr Y, wordptr Z, boolean minus, boolean *carry)
+{
+ N_word size = size_(X);
+ N_word mask = mask_(X);
+ N_word vv = 0;
+ N_word cc;
+ N_word mm;
+ N_word yy;
+ N_word zz;
+ N_word lo;
+ N_word hi;
+
+ if (size > 0)
+ {
+ if (minus) cc = (*carry == 0);
+ else cc = (*carry != 0);
+ /* deal with (size-1) least significant full words first: */
+ while (--size > 0)
+ {
+ yy = *Y++;
+ if (minus) zz = (N_word) NOT ( Z ? *Z++ : 0 );
+ else zz = (N_word) ( Z ? *Z++ : 0 );
+ lo = (yy AND LSB) + (zz AND LSB) + cc;
+ hi = (yy >> 1) + (zz >> 1) + (lo >> 1);
+ cc = ((hi AND MSB) != 0);
+ *X++ = (hi << 1) OR (lo AND LSB);
+ }
+ /* deal with most significant word (may be used only partially): */
+ yy = *Y AND mask;
+ if (minus) zz = (N_word) NOT ( Z ? *Z : 0 );
+ else zz = (N_word) ( Z ? *Z : 0 );
+ zz &= mask;
+ if (mask == LSB) /* special case, only one bit used */
+ {
+ vv = cc;
+ lo = yy + zz + cc;
+ cc = (lo >> 1);
+ vv ^= cc;
+ *X = lo AND LSB;
+ }
+ else
+ {
+ if (NOT mask) /* not all bits are used, but more than one */
+ {
+ mm = (mask >> 1);
+ vv = (yy AND mm) + (zz AND mm) + cc;
+ mm = mask AND NOT mm;
+ lo = yy + zz + cc;
+ cc = (lo >> 1);
+ vv ^= cc;
+ vv &= mm;
+ cc &= mm;
+ *X = lo AND mask;
+ }
+ else /* other special case, all bits are used */
+ {
+ mm = NOT MSB;
+ lo = (yy AND mm) + (zz AND mm) + cc;
+ vv = lo AND MSB;
+ hi = ((yy AND MSB) >> 1) + ((zz AND MSB) >> 1) + (vv >> 1);
+ cc = hi AND MSB;
+ vv ^= cc;
+ *X = (hi << 1) OR (lo AND mm);
+ }
+ }
+ if (minus) *carry = (cc == 0);
+ else *carry = (cc != 0);
+ }
+ return(vv != 0);
+}
+
+boolean BitVector_add(wordptr X, wordptr Y, wordptr Z, boolean *carry)
+{
+ return(BitVector_compute(X,Y,Z,FALSE,carry));
+}
+
+boolean BitVector_sub(wordptr X, wordptr Y, wordptr Z, boolean *carry)
+{
+ return(BitVector_compute(X,Y,Z,TRUE,carry));
+}
+
+boolean BitVector_inc(wordptr X, wordptr Y)
+{
+ boolean carry = TRUE;
+
+ return(BitVector_compute(X,Y,NULL,FALSE,&carry));
+}
+
+boolean BitVector_dec(wordptr X, wordptr Y)
+{
+ boolean carry = TRUE;
+
+ return(BitVector_compute(X,Y,NULL,TRUE,&carry));
+}
+
+void BitVector_Negate(wordptr X, wordptr Y)
+{
+ N_word size = size_(X);
+ N_word mask = mask_(X);
+ boolean carry = TRUE;
+
+ if (size > 0)
+ {
+ while (size-- > 0)
+ {
+ *X = NOT *Y++;
+ if (carry)
+ {
+ carry = (++(*X) == 0);
+ }
+ X++;
+ }
+ *(--X) &= mask;
+ }
+}
+
+void BitVector_Absolute(wordptr X, wordptr Y)
+{
+ N_word size = size_(Y);
+ N_word mask = mask_(Y);
+
+ if (size > 0)
+ {
+ if (*(Y+size-1) AND (mask AND NOT (mask >> 1))) BitVector_Negate(X,Y);
+ else BitVector_Copy(X,Y);
+ }
+}
+
+Z_int BitVector_Sign(wordptr addr)
+{
+ N_word size = size_(addr);
+ N_word mask = mask_(addr);
+ wordptr last = addr + size - 1;
+ boolean r = TRUE;
+
+ if (size > 0)
+ {
+ *last &= mask;
+ while (r and (size-- > 0)) r = ( *addr++ == 0 );
+ }
+ if (r) return((Z_int) 0);
+ else
+ {
+ if (*last AND (mask AND NOT (mask >> 1))) return((Z_int) -1);
+ else return((Z_int) 1);
+ }
+}
+
+ErrCode BitVector_Mul_Pos(wordptr X, wordptr Y, wordptr Z, boolean strict)
+{
+ N_word mask;
+ N_word limit;
+ N_word count;
+ Z_long last;
+ wordptr sign;
+ boolean carry;
+ boolean overflow;
+ boolean ok = TRUE;
+
+ /*
+ Requirements:
+ - X, Y and Z must be distinct
+ - X and Y must have equal sizes (whereas Z may be any size!)
+ - Z should always contain the SMALLER of the two factors Y and Z
+ Constraints:
+ - The contents of Y (and of X, of course) are destroyed
+ (only Z is preserved!)
+ */
+
+ if ((X == Y) or (X == Z) or (Y == Z)) return(ErrCode_Same);
+ if (bits_(X) != bits_(Y)) return(ErrCode_Size);
+ BitVector_Empty(X);
+ if (BitVector_is_empty(Y)) return(ErrCode_Ok); /* exit also taken if bits_(Y)==0 */
+ if ((last = Set_Max(Z)) < 0L) return(ErrCode_Ok);
+ limit = (N_word) last;
+ sign = Y + size_(Y) - 1;
+ mask = mask_(Y);
+ *sign &= mask;
+ mask &= NOT (mask >> 1);
+ for ( count = 0; (ok and (count <= limit)); count++ )
+ {
+ if ( BIT_VECTOR_TST_BIT(Z,count) )
+ {
+ carry = false;
+ overflow = BitVector_compute(X,X,Y,false,&carry);
+ if (strict) ok = not (carry or overflow);
+ else ok = not carry;
+ }
+ if (ok and (count < limit))
+ {
+ carry = BitVector_shift_left(Y,0);
+ if (strict)
+ {
+ overflow = ((*sign AND mask) != 0);
+ ok = not (carry or overflow);
+ }
+ else ok = not carry;
+ }
+ }
+ if (ok) return(ErrCode_Ok); else return(ErrCode_Ovfl);
+}
+
+ErrCode BitVector_Multiply(wordptr X, wordptr Y, wordptr Z)
+{
+ ErrCode error = ErrCode_Ok;
+ N_word bit_x = bits_(X);
+ N_word bit_y = bits_(Y);
+ N_word bit_z = bits_(Z);
+ N_word size;
+ N_word mask;
+ N_word msb;
+ wordptr ptr_y;
+ wordptr ptr_z;
+ boolean sgn_x;
+ boolean sgn_y;
+ boolean sgn_z;
+ boolean zero;
+ wordptr A;
+ wordptr B;
+
+ /*
+ Requirements:
+ - Y and Z must have equal sizes
+ - X must have at least the same size as Y and Z but may be larger (!)
+ Features:
+ - The contents of Y and Z are preserved
+ - X may be identical with Y or Z (or both!)
+ (in-place multiplication is possible!)
+ */
+
+ if ((bit_y != bit_z) or (bit_x < bit_y)) return(ErrCode_Size);
+ if (BitVector_is_empty(Y) or BitVector_is_empty(Z))
+ {
+ BitVector_Empty(X);
+ }
+ else
+ {
+ A = BitVector_Create(bit_y,FALSE);
+ if (A == NULL) return(ErrCode_Null);
+ B = BitVector_Create(bit_z,FALSE);
+ if (B == NULL) { BitVector_Destroy(A); return(ErrCode_Null); }
+ size = size_(Y);
+ mask = mask_(Y);
+ msb = (mask AND NOT (mask >> 1));
+ sgn_y = (((*(Y+size-1) &= mask) AND msb) != 0);
+ sgn_z = (((*(Z+size-1) &= mask) AND msb) != 0);
+ sgn_x = sgn_y XOR sgn_z;
+ if (sgn_y) BitVector_Negate(A,Y); else BitVector_Copy(A,Y);
+ if (sgn_z) BitVector_Negate(B,Z); else BitVector_Copy(B,Z);
+ ptr_y = A + size;
+ ptr_z = B + size;
+ zero = TRUE;
+ while (zero and (size-- > 0))
+ {
+ zero &= (*(--ptr_y) == 0);
+ zero &= (*(--ptr_z) == 0);
+ }
+ if (*ptr_y > *ptr_z)
+ {
+ if (bit_x > bit_y)
+ {
+ A = BitVector_Resize(A,bit_x);
+ if (A == NULL) { BitVector_Destroy(B); return(ErrCode_Null); }
+ }
+ error = BitVector_Mul_Pos(X,A,B,TRUE);
+ }
+ else
+ {
+ if (bit_x > bit_z)
+ {
+ B = BitVector_Resize(B,bit_x);
+ if (B == NULL) { BitVector_Destroy(A); return(ErrCode_Null); }
+ }
+ error = BitVector_Mul_Pos(X,B,A,TRUE);
+ }
+ if ((not error) and sgn_x) BitVector_Negate(X,X);
+ BitVector_Destroy(A);
+ BitVector_Destroy(B);
+ }
+ return(error);
+}
+
+ErrCode BitVector_Div_Pos(wordptr Q, wordptr X, wordptr Y, wordptr R)
+{
+ N_word bits = bits_(Q);
+ N_word mask;
+ wordptr addr;
+ Z_long last;
+ boolean flag;
+ boolean copy = FALSE; /* flags whether valid rest is in R (0) or X (1) */
+
+ /*
+ Requirements:
+ - All bit vectors must have equal sizes
+ - Q, X, Y and R must all be distinct bit vectors
+ - Y must be non-zero (of course!)
+ Constraints:
+ - The contents of X (and Q and R, of course) are destroyed
+ (only Y is preserved!)
+ */
+
+ if ((bits != bits_(X)) or (bits != bits_(Y)) or (bits != bits_(R)))
+ return(ErrCode_Size);
+ if ((Q == X) or (Q == Y) or (Q == R) or (X == Y) or (X == R) or (Y == R))
+ return(ErrCode_Same);
+ if (BitVector_is_empty(Y))
+ return(ErrCode_Zero);
+
+ BitVector_Empty(R);
+ BitVector_Copy(Q,X);
+ if ((last = Set_Max(Q)) < 0L) return(ErrCode_Ok);
+ bits = (N_word) ++last;
+ while (bits-- > 0)
+ {
+ addr = Q + (bits >> LOGBITS);
+ mask = BITMASKTAB[bits AND MODMASK];
+ flag = ((*addr AND mask) != 0);
+ if (copy)
+ {
+ BitVector_shift_left(X,flag);
+ flag = FALSE;
+ BitVector_compute(R,X,Y,TRUE,&flag);
+ }
+ else
+ {
+ BitVector_shift_left(R,flag);
+ flag = FALSE;
+ BitVector_compute(X,R,Y,TRUE,&flag);
+ }
+ if (flag) *addr &= NOT mask;
+ else
+ {
+ *addr |= mask;
+ copy = not copy;
+ }
+ }
+ if (copy) BitVector_Copy(R,X);
+ return(ErrCode_Ok);
+}
+
+ErrCode BitVector_Divide(wordptr Q, wordptr X, wordptr Y, wordptr R)
+{
+ ErrCode error = ErrCode_Ok;
+ N_word bits = bits_(Q);
+ N_word size = size_(Q);
+ N_word mask = mask_(Q);
+ N_word msb = (mask AND NOT (mask >> 1));
+ boolean sgn_q;
+ boolean sgn_x;
+ boolean sgn_y;
+ wordptr A;
+ wordptr B;
+
+ /*
+ Requirements:
+ - All bit vectors must have equal sizes
+ - Q and R must be two distinct bit vectors
+ - Y must be non-zero (of course!)
+ Features:
+ - The contents of X and Y are preserved
+ - Q may be identical with X or Y (or both)
+ (in-place division is possible!)
+ - R may be identical with X or Y (or both)
+ (but not identical with Q!)
+ */
+
+ if ((bits != bits_(X)) or (bits != bits_(Y)) or (bits != bits_(R)))
+ return(ErrCode_Size);
+ if (Q == R)
+ return(ErrCode_Same);
+ if (BitVector_is_empty(Y))
+ return(ErrCode_Zero);
+
+ if (BitVector_is_empty(X))
+ {
+ BitVector_Empty(Q);
+ BitVector_Empty(R);
+ }
+ else
+ {
+ A = BitVector_Create(bits,FALSE);
+ if (A == NULL) return(ErrCode_Null);
+ B = BitVector_Create(bits,FALSE);
+ if (B == NULL) { BitVector_Destroy(A); return(ErrCode_Null); }
+ size--;
+ sgn_x = (((*(X+size) &= mask) AND msb) != 0);
+ sgn_y = (((*(Y+size) &= mask) AND msb) != 0);
+ sgn_q = sgn_x XOR sgn_y;
+ if (sgn_x) BitVector_Negate(A,X); else BitVector_Copy(A,X);
+ if (sgn_y) BitVector_Negate(B,Y); else BitVector_Copy(B,Y);
+ if (not (error = BitVector_Div_Pos(Q,A,B,R)))
+ {
+ if (sgn_q) BitVector_Negate(Q,Q);
+ if (sgn_x) BitVector_Negate(R,R);
+ }
+ BitVector_Destroy(A);
+ BitVector_Destroy(B);
+ }
+ return(error);
+}
+
+ErrCode BitVector_GCD(wordptr X, wordptr Y, wordptr Z)
+{
+ ErrCode error = ErrCode_Ok;
+ N_word bits = bits_(X);
+ N_word size = size_(X);
+ N_word mask = mask_(X);
+ N_word msb = (mask AND NOT (mask >> 1));
+ boolean sgn_a;
+ boolean sgn_b;
+ boolean sgn_r;
+ wordptr Q;
+ wordptr R;
+ wordptr A;
+ wordptr B;
+ wordptr T;
+
+ /*
+ Requirements:
+ - All bit vectors must have equal sizes
+ Features:
+ - The contents of Y and Z are preserved
+ - X may be identical with Y or Z (or both)
+ (in-place is possible!)
+ - GCD(0,z) == GCD(z,0) == z
+ - negative values are handled correctly
+ */
+
+ if ((bits != bits_(Y)) or (bits != bits_(Z))) return(ErrCode_Size);
+ if (BitVector_is_empty(Y))
+ {
+ if (X != Z) BitVector_Copy(X,Z);
+ return(ErrCode_Ok);
+ }
+ if (BitVector_is_empty(Z))
+ {
+ if (X != Y) BitVector_Copy(X,Y);
+ return(ErrCode_Ok);
+ }
+ Q = BitVector_Create(bits,false);
+ if (Q == NULL)
+ {
+ return(ErrCode_Null);
+ }
+ R = BitVector_Create(bits,FALSE);
+ if (R == NULL)
+ {
+ BitVector_Destroy(Q);
+ return(ErrCode_Null);
+ }
+ A = BitVector_Create(bits,FALSE);
+ if (A == NULL)
+ {
+ BitVector_Destroy(Q);
+ BitVector_Destroy(R);
+ return(ErrCode_Null);
+ }
+ B = BitVector_Create(bits,FALSE);
+ if (B == NULL)
+ {
+ BitVector_Destroy(Q);
+ BitVector_Destroy(R);
+ BitVector_Destroy(A);
+ return(ErrCode_Null);
+ }
+ size--;
+ sgn_a = (((*(Y+size) &= mask) AND msb) != 0);
+ sgn_b = (((*(Z+size) &= mask) AND msb) != 0);
+ if (sgn_a) BitVector_Negate(A,Y); else BitVector_Copy(A,Y);
+ if (sgn_b) BitVector_Negate(B,Z); else BitVector_Copy(B,Z);
+ while (not error)
+ {
+ if (not (error = BitVector_Div_Pos(Q,A,B,R)))
+ {
+ if (BitVector_is_empty(R)) break;
+ T = A; sgn_r = sgn_a;
+ A = B; sgn_a = sgn_b;
+ B = R; sgn_b = sgn_r;
+ R = T;
+ }
+ }
+ if (not error)
+ {
+ if (sgn_b) BitVector_Negate(X,B); else BitVector_Copy(X,B);
+ }
+ BitVector_Destroy(Q);
+ BitVector_Destroy(R);
+ BitVector_Destroy(A);
+ BitVector_Destroy(B);
+ return(error);
+}
+
+ErrCode BitVector_GCD2(wordptr U, wordptr V, wordptr W, wordptr X, wordptr Y)
+{
+ ErrCode error = ErrCode_Ok;
+ N_word bits = bits_(U);
+ N_word size = size_(U);
+ N_word mask = mask_(U);
+ N_word msb = (mask AND NOT (mask >> 1));
+ boolean minus;
+ boolean carry;
+ boolean sgn_q;
+ boolean sgn_r;
+ boolean sgn_a;
+ boolean sgn_b;
+ boolean sgn_x;
+ boolean sgn_y;
+ listptr L;
+ wordptr Q;
+ wordptr R;
+ wordptr A;
+ wordptr B;
+ wordptr T;
+ wordptr X1;
+ wordptr X2;
+ wordptr X3;
+ wordptr Y1;
+ wordptr Y2;
+ wordptr Y3;
+ wordptr Z;
+
+ /*
+ Requirements:
+ - All bit vectors must have equal sizes
+ - U, V, and W must all be distinct bit vectors
+ Features:
+ - The contents of X and Y are preserved
+ - U, V and W may be identical with X or Y (or both,
+ provided that U, V and W are mutually distinct)
+ (i.e., in-place is possible!)
+ - GCD(0,z) == GCD(z,0) == z
+ - negative values are handled correctly
+ */
+
+ if ((bits != bits_(V)) or
+ (bits != bits_(W)) or
+ (bits != bits_(X)) or
+ (bits != bits_(Y)))
+ {
+ return(ErrCode_Size);
+ }
+ if ((U == V) or (U == W) or (V == W))
+ {
+ return(ErrCode_Same);
+ }
+ if (BitVector_is_empty(X))
+ {
+ if (U != Y) BitVector_Copy(U,Y);
+ BitVector_Empty(V);
+ BitVector_Empty(W);
+ *W = 1;
+ return(ErrCode_Ok);
+ }
+ if (BitVector_is_empty(Y))
+ {
+ if (U != X) BitVector_Copy(U,X);
+ BitVector_Empty(V);
+ BitVector_Empty(W);
+ *V = 1;
+ return(ErrCode_Ok);
+ }
+ if ((L = BitVector_Create_List(bits,false,11)) == NULL)
+ {
+ return(ErrCode_Null);
+ }
+ Q = L[0];
+ R = L[1];
+ A = L[2];
+ B = L[3];
+ X1 = L[4];
+ X2 = L[5];
+ X3 = L[6];
+ Y1 = L[7];
+ Y2 = L[8];
+ Y3 = L[9];
+ Z = L[10];
+ size--;
+ sgn_a = (((*(X+size) &= mask) AND msb) != 0);
+ sgn_b = (((*(Y+size) &= mask) AND msb) != 0);
+ if (sgn_a) BitVector_Negate(A,X); else BitVector_Copy(A,X);
+ if (sgn_b) BitVector_Negate(B,Y); else BitVector_Copy(B,Y);
+ BitVector_Empty(X1);
+ BitVector_Empty(X2);
+ *X1 = 1;
+ BitVector_Empty(Y1);
+ BitVector_Empty(Y2);
+ *Y2 = 1;
+ sgn_x = false;
+ sgn_y = false;
+ while (not error)
+ {
+ if ((error = BitVector_Div_Pos(Q,A,B,R)))
+ {
+ break;
+ }
+ if (BitVector_is_empty(R))
+ {
+ break;
+ }
+ sgn_q = sgn_a XOR sgn_b;
+
+ if (sgn_x) BitVector_Negate(Z,X2); else BitVector_Copy(Z,X2);
+ if ((error = BitVector_Mul_Pos(X3,Z,Q,true)))
+ {
+ break;
+ }
+ minus = not (sgn_x XOR sgn_q);
+ carry = 0;
+ if (BitVector_compute(X3,X1,X3,minus,&carry))
+ {
+ error = ErrCode_Ovfl;
+ break;
+ }
+ sgn_x = (((*(X3+size) &= mask) AND msb) != 0);
+
+ if (sgn_y) BitVector_Negate(Z,Y2); else BitVector_Copy(Z,Y2);
+ if ((error = BitVector_Mul_Pos(Y3,Z,Q,true)))
+ {
+ break;
+ }
+ minus = not (sgn_y XOR sgn_q);
+ carry = 0;
+ if (BitVector_compute(Y3,Y1,Y3,minus,&carry))
+ {
+ error = ErrCode_Ovfl;
+ break;
+ }
+ sgn_y = (((*(Y3+size) &= mask) AND msb) != 0);
+
+ T = A; sgn_r = sgn_a;
+ A = B; sgn_a = sgn_b;
+ B = R; sgn_b = sgn_r;
+ R = T;
+
+ T = X1;
+ X1 = X2;
+ X2 = X3;
+ X3 = T;
+
+ T = Y1;
+ Y1 = Y2;
+ Y2 = Y3;
+ Y3 = T;
+ }
+ if (not error)
+ {
+ if (sgn_b) BitVector_Negate(U,B); else BitVector_Copy(U,B);
+ BitVector_Copy(V,X2);
+ BitVector_Copy(W,Y2);
+ }
+ BitVector_Destroy_List(L,11);
+ return(error);
+}
+
+ErrCode BitVector_Power(wordptr X, wordptr Y, wordptr Z)
+{
+ ErrCode error = ErrCode_Ok;
+ N_word bits = bits_(X);
+ boolean first = TRUE;
+ Z_long last;
+ N_word limit;
+ N_word count;
+ wordptr T;
+
+ /*
+ Requirements:
+ - X must have at least the same size as Y but may be larger (!)
+ - X may not be identical with Z
+ - Z must be positive
+ Features:
+ - The contents of Y and Z are preserved
+ */
+
+ if (X == Z) return(ErrCode_Same);
+ if (bits < bits_(Y)) return(ErrCode_Size);
+ if (BitVector_msb_(Z)) return(ErrCode_Expo);
+ if ((last = Set_Max(Z)) < 0L)
+ {
+ if (bits < 2) return(ErrCode_Ovfl);
+ BitVector_Empty(X);
+ *X |= LSB;
+ return(ErrCode_Ok); /* anything ^ 0 == 1 */
+ }
+ if (BitVector_is_empty(Y))
+ {
+ if (X != Y) BitVector_Empty(X);
+ return(ErrCode_Ok); /* 0 ^ anything not zero == 0 */
+ }
+ T = BitVector_Create(bits,FALSE);
+ if (T == NULL) return(ErrCode_Null);
+ limit = (N_word) last;
+ for ( count = 0; ((!error) and (count <= limit)); count++ )
+ {
+ if ( BIT_VECTOR_TST_BIT(Z,count) )
+ {
+ if (first)
+ {
+ first = FALSE;
+ if (count) { BitVector_Copy(X,T); }
+ else { if (X != Y) BitVector_Copy(X,Y); }
+ }
+ else error = BitVector_Multiply(X,T,X); /* order important because T > X */
+ }
+ if ((!error) and (count < limit))
+ {
+ if (count) error = BitVector_Multiply(T,T,T);
+ else error = BitVector_Multiply(T,Y,Y);
+ }
+ }
+ BitVector_Destroy(T);
+ return(error);
+}
+
+void BitVector_Block_Store(wordptr addr, charptr buffer, N_int length)
+{
+ N_word size = size_(addr);
+ N_word mask = mask_(addr);
+ N_word value;
+ N_word count;
+
+ /* provide translation for independence of endian-ness: */
+ if (size > 0)
+ {
+ while (size-- > 0)
+ {
+ value = 0;
+ for ( count = 0; (length > 0) and (count < BITS); count += 8 )
+ {
+ value |= (((N_word) *buffer++) << count); length--;
+ }
+ *addr++ = value;
+ }
+ *(--addr) &= mask;
+ }
+}
+
+charptr BitVector_Block_Read(wordptr addr, N_intptr length)
+{
+ N_word size = size_(addr);
+ N_word value;
+ N_word count;
+ charptr buffer;
+ charptr target;
+
+ /* provide translation for independence of endian-ness: */
+ *length = size << FACTOR;
+ buffer = (charptr) yasm_xmalloc((size_t) ((*length)+1));
+ if (buffer == NULL) return(NULL);
+ target = buffer;
+ if (size > 0)
+ {
+ *(addr+size-1) &= mask_(addr);
+ while (size-- > 0)
+ {
+ value = *addr++;
+ count = BITS >> 3;
+ while (count-- > 0)
+ {
+ *target++ = (N_char) (value AND 0x00FF);
+ if (count > 0) value >>= 8;
+ }
+ }
+ }
+ *target = (N_char) '\0';
+ return(buffer);
+}
+
+void BitVector_Word_Store(wordptr addr, N_int offset, N_int value)
+{
+ N_word size = size_(addr);
+
+ if (size > 0)
+ {
+ if (offset < size) *(addr+offset) = value;
+ *(addr+size-1) &= mask_(addr);
+ }
+}
+
+N_int BitVector_Word_Read(wordptr addr, N_int offset)
+{
+ N_word size = size_(addr);
+
+ if (size > 0)
+ {
+ *(addr+size-1) &= mask_(addr);
+ if (offset < size) return( *(addr+offset) );
+ }
+ return( (N_int) 0 );
+}
+
+void BitVector_Word_Insert(wordptr addr, N_int offset, N_int count,
+ boolean clear)
+{
+ N_word size = size_(addr);
+ N_word mask = mask_(addr);
+ wordptr last = addr+size-1;
+
+ if (size > 0)
+ {
+ *last &= mask;
+ if (offset > size) offset = size;
+ BIT_VECTOR_ins_words(addr+offset,size-offset,count,clear);
+ *last &= mask;
+ }
+}
+
+void BitVector_Word_Delete(wordptr addr, N_int offset, N_int count,
+ boolean clear)
+{
+ N_word size = size_(addr);
+ N_word mask = mask_(addr);
+ wordptr last = addr+size-1;
+
+ if (size > 0)
+ {
+ *last &= mask;
+ if (offset > size) offset = size;
+ BIT_VECTOR_del_words(addr+offset,size-offset,count,clear);
+ *last &= mask;
+ }
+}
+
+void BitVector_Chunk_Store(wordptr addr, N_int chunksize, N_int offset,
+ N_long value)
+{
+ N_word bits = bits_(addr);
+ N_word mask;
+ N_word temp;
+
+ if ((chunksize > 0) and (offset < bits))
+ {
+ if (chunksize > LONGBITS) chunksize = LONGBITS;
+ if ((offset + chunksize) > bits) chunksize = bits - offset;
+ addr += offset >> LOGBITS;
+ offset &= MODMASK;
+ while (chunksize > 0)
+ {
+ mask = (N_word) (~0L << offset);
+ bits = offset + chunksize;
+ if (bits < BITS)
+ {
+ mask &= (N_word) ~(~0L << bits);
+ bits = chunksize;
+ }
+ else bits = BITS - offset;
+ temp = (N_word) (value << offset);
+ temp &= mask;
+ *addr &= NOT mask;
+ *addr++ |= temp;
+ value >>= bits;
+ chunksize -= bits;
+ offset = 0;
+ }
+ }
+}
+
+N_long BitVector_Chunk_Read(wordptr addr, N_int chunksize, N_int offset)
+{
+ N_word bits = bits_(addr);
+ N_word chunkbits = 0;
+ N_long value = 0L;
+ N_long temp;
+ N_word mask;
+
+ if ((chunksize > 0) and (offset < bits))
+ {
+ if (chunksize > LONGBITS) chunksize = LONGBITS;
+ if ((offset + chunksize) > bits) chunksize = bits - offset;
+ addr += offset >> LOGBITS;
+ offset &= MODMASK;
+ while (chunksize > 0)
+ {
+ bits = offset + chunksize;
+ if (bits < BITS)
+ {
+ mask = (N_word) ~(~0L << bits);
+ bits = chunksize;
+ }
+ else
+ {
+ mask = (N_word) ~0L;
+ bits = BITS - offset;
+ }
+ temp = (N_long) ((*addr++ AND mask) >> offset);
+ value |= temp << chunkbits;
+ chunkbits += bits;
+ chunksize -= bits;
+ offset = 0;
+ }
+ }
+ return(value);
+}
+
+ /*******************/
+ /* set operations: */
+ /*******************/
+
+void Set_Union(wordptr X, wordptr Y, wordptr Z) /* X = Y + Z */
+{
+ N_word bits = bits_(X);
+ N_word size = size_(X);
+ N_word mask = mask_(X);
+
+ if ((size > 0) and (bits == bits_(Y)) and (bits == bits_(Z)))
+ {
+ while (size-- > 0) *X++ = *Y++ OR *Z++;
+ *(--X) &= mask;
+ }
+}
+
+void Set_Intersection(wordptr X, wordptr Y, wordptr Z) /* X = Y * Z */
+{
+ N_word bits = bits_(X);
+ N_word size = size_(X);
+ N_word mask = mask_(X);
+
+ if ((size > 0) and (bits == bits_(Y)) and (bits == bits_(Z)))
+ {
+ while (size-- > 0) *X++ = *Y++ AND *Z++;
+ *(--X) &= mask;
+ }
+}
+
+void Set_Difference(wordptr X, wordptr Y, wordptr Z) /* X = Y \ Z */
+{
+ N_word bits = bits_(X);
+ N_word size = size_(X);
+ N_word mask = mask_(X);
+
+ if ((size > 0) and (bits == bits_(Y)) and (bits == bits_(Z)))
+ {
+ while (size-- > 0) *X++ = *Y++ AND NOT *Z++;
+ *(--X) &= mask;
+ }
+}
+
+void Set_ExclusiveOr(wordptr X, wordptr Y, wordptr Z) /* X=(Y+Z)\(Y*Z) */
+{
+ N_word bits = bits_(X);
+ N_word size = size_(X);
+ N_word mask = mask_(X);
+
+ if ((size > 0) and (bits == bits_(Y)) and (bits == bits_(Z)))
+ {
+ while (size-- > 0) *X++ = *Y++ XOR *Z++;
+ *(--X) &= mask;
+ }
+}
+
+void Set_Complement(wordptr X, wordptr Y) /* X = ~Y */
+{
+ N_word size = size_(X);
+ N_word mask = mask_(X);
+
+ if ((size > 0) and (bits_(X) == bits_(Y)))
+ {
+ while (size-- > 0) *X++ = NOT *Y++;
+ *(--X) &= mask;
+ }
+}
+
+ /******************/
+ /* set functions: */
+ /******************/
+
+boolean Set_subset(wordptr X, wordptr Y) /* X subset Y ? */
+{
+ N_word size = size_(X);
+ boolean r = FALSE;
+
+ if ((size > 0) and (bits_(X) == bits_(Y)))
+ {
+ r = TRUE;
+ while (r and (size-- > 0)) r = ((*X++ AND NOT *Y++) == 0);
+ }
+ return(r);
+}
+
+N_int Set_Norm(wordptr addr) /* = | X | */
+{
+ byteptr byte;
+ N_word bytes;
+ N_int n;
+
+ byte = (byteptr) addr;
+ bytes = size_(addr) << FACTOR;
+ n = 0;
+ while (bytes-- > 0)
+ {
+ n += BitVector_BYTENORM[*byte++];
+ }
+ return(n);
+}
+
+N_int Set_Norm2(wordptr addr) /* = | X | */
+{
+ N_word size = size_(addr);
+ N_word w0,w1;
+ N_int n,k;
+
+ n = 0;
+ while (size-- > 0)
+ {
+ k = 0;
+ w1 = NOT (w0 = *addr++);
+ while (w0 and w1)
+ {
+ w0 &= w0 - 1;
+ w1 &= w1 - 1;
+ k++;
+ }
+ if (w0 == 0) n += k;
+ else n += BITS - k;
+ }
+ return(n);
+}
+
+N_int Set_Norm3(wordptr addr) /* = | X | */
+{
+ N_word size = size_(addr);
+ N_int count = 0;
+ N_word c;
+
+ while (size-- > 0)
+ {
+ c = *addr++;
+ while (c)
+ {
+ c &= c - 1;
+ count++;
+ }
+ }
+ return(count);
+}
+
+Z_long Set_Min(wordptr addr) /* = min(X) */
+{
+ boolean empty = TRUE;
+ N_word size = size_(addr);
+ N_word i = 0;
+ N_word c = 0; /* silence compiler warning */
+
+ while (empty and (size-- > 0))
+ {
+ if ((c = *addr++)) empty = false; else i++;
+ }
+ if (empty) return((Z_long) LONG_MAX); /* plus infinity */
+ i <<= LOGBITS;
+ while (not (c AND LSB))
+ {
+ c >>= 1;
+ i++;
+ }
+ return((Z_long) i);
+}
+
+Z_long Set_Max(wordptr addr) /* = max(X) */
+{
+ boolean empty = TRUE;
+ N_word size = size_(addr);
+ N_word i = size;
+ N_word c = 0; /* silence compiler warning */
+
+ addr += size-1;
+ while (empty and (size-- > 0))
+ {
+ if ((c = *addr--)) empty = false; else i--;
+ }
+ if (empty) return((Z_long) LONG_MIN); /* minus infinity */
+ i <<= LOGBITS;
+ while (not (c AND MSB))
+ {
+ c <<= 1;
+ i--;
+ }
+ return((Z_long) --i);
+}
+
+ /**********************************/
+ /* matrix-of-booleans operations: */
+ /**********************************/
+
+void Matrix_Multiplication(wordptr X, N_int rowsX, N_int colsX,
+ wordptr Y, N_int rowsY, N_int colsY,
+ wordptr Z, N_int rowsZ, N_int colsZ)
+{
+ N_word i;
+ N_word j;
+ N_word k;
+ N_word indxX;
+ N_word indxY;
+ N_word indxZ;
+ N_word termX;
+ N_word termY;
+ N_word sum;
+
+ if ((colsY == rowsZ) and (rowsX == rowsY) and (colsX == colsZ) and
+ (bits_(X) == rowsX*colsX) and
+ (bits_(Y) == rowsY*colsY) and
+ (bits_(Z) == rowsZ*colsZ))
+ {
+ for ( i = 0; i < rowsY; i++ )
+ {
+ termX = i * colsX;
+ termY = i * colsY;
+ for ( j = 0; j < colsZ; j++ )
+ {
+ indxX = termX + j;
+ sum = 0;
+ for ( k = 0; k < colsY; k++ )
+ {
+ indxY = termY + k;
+ indxZ = k * colsZ + j;
+ if ( BIT_VECTOR_TST_BIT(Y,indxY) &&
+ BIT_VECTOR_TST_BIT(Z,indxZ) ) sum ^= 1;
+ }
+ if (sum) BIT_VECTOR_SET_BIT(X,indxX)
+ else BIT_VECTOR_CLR_BIT(X,indxX)
+ }
+ }
+ }
+}
+
+void Matrix_Product(wordptr X, N_int rowsX, N_int colsX,
+ wordptr Y, N_int rowsY, N_int colsY,
+ wordptr Z, N_int rowsZ, N_int colsZ)
+{
+ N_word i;
+ N_word j;
+ N_word k;
+ N_word indxX;
+ N_word indxY;
+ N_word indxZ;
+ N_word termX;
+ N_word termY;
+ N_word sum;
+
+ if ((colsY == rowsZ) and (rowsX == rowsY) and (colsX == colsZ) and
+ (bits_(X) == rowsX*colsX) and
+ (bits_(Y) == rowsY*colsY) and
+ (bits_(Z) == rowsZ*colsZ))
+ {
+ for ( i = 0; i < rowsY; i++ )
+ {
+ termX = i * colsX;
+ termY = i * colsY;
+ for ( j = 0; j < colsZ; j++ )
+ {
+ indxX = termX + j;
+ sum = 0;
+ for ( k = 0; k < colsY; k++ )
+ {
+ indxY = termY + k;
+ indxZ = k * colsZ + j;
+ if ( BIT_VECTOR_TST_BIT(Y,indxY) &&
+ BIT_VECTOR_TST_BIT(Z,indxZ) ) sum |= 1;
+ }
+ if (sum) BIT_VECTOR_SET_BIT(X,indxX)
+ else BIT_VECTOR_CLR_BIT(X,indxX)
+ }
+ }
+ }
+}
+
+void Matrix_Closure(wordptr addr, N_int rows, N_int cols)
+{
+ N_word i;
+ N_word j;
+ N_word k;
+ N_word ii;
+ N_word ij;
+ N_word ik;
+ N_word kj;
+ N_word termi;
+ N_word termk;
+
+ if ((rows == cols) and (bits_(addr) == rows*cols))
+ {
+ for ( i = 0; i < rows; i++ )
+ {
+ ii = i * cols + i;
+ BIT_VECTOR_SET_BIT(addr,ii)
+ }
+ for ( k = 0; k < rows; k++ )
+ {
+ termk = k * cols;
+ for ( i = 0; i < rows; i++ )
+ {
+ termi = i * cols;
+ ik = termi + k;
+ for ( j = 0; j < rows; j++ )
+ {
+ ij = termi + j;
+ kj = termk + j;
+ if ( BIT_VECTOR_TST_BIT(addr,ik) &&
+ BIT_VECTOR_TST_BIT(addr,kj) )
+ BIT_VECTOR_SET_BIT(addr,ij)
+ }
+ }
+ }
+ }
+}
+
+void Matrix_Transpose(wordptr X, N_int rowsX, N_int colsX,
+ wordptr Y, N_int rowsY, N_int colsY)
+{
+ N_word i;
+ N_word j;
+ N_word ii;
+ N_word ij;
+ N_word ji;
+ N_word addii;
+ N_word addij;
+ N_word addji;
+ N_word bitii;
+ N_word bitij;
+ N_word bitji;
+ N_word termi;
+ N_word termj;
+ boolean swap;
+
+ /* BEWARE that "in-place" is ONLY possible if the matrix is quadratic!! */
+
+ if ((rowsX == colsY) and (colsX == rowsY) and
+ (bits_(X) == rowsX*colsX) and
+ (bits_(Y) == rowsY*colsY))
+ {
+ if (rowsY == colsY) /* in-place is possible! */
+ {
+ for ( i = 0; i < rowsY; i++ )
+ {
+ termi = i * colsY;
+ for ( j = 0; j < i; j++ )
+ {
+ termj = j * colsX;
+ ij = termi + j;
+ ji = termj + i;
+ addij = ij >> LOGBITS;
+ addji = ji >> LOGBITS;
+ bitij = BITMASKTAB[ij AND MODMASK];
+ bitji = BITMASKTAB[ji AND MODMASK];
+ swap = ((*(Y+addij) AND bitij) != 0);
+ if ((*(Y+addji) AND bitji) != 0)
+ *(X+addij) |= bitij;
+ else
+ *(X+addij) &= NOT bitij;
+ if (swap)
+ *(X+addji) |= bitji;
+ else
+ *(X+addji) &= NOT bitji;
+ }
+ ii = termi + i;
+ addii = ii >> LOGBITS;
+ bitii = BITMASKTAB[ii AND MODMASK];
+ if ((*(Y+addii) AND bitii) != 0)
+ *(X+addii) |= bitii;
+ else
+ *(X+addii) &= NOT bitii;
+ }
+ }
+ else /* rowsX != colsX, in-place is NOT possible! */
+ {
+ for ( i = 0; i < rowsY; i++ )
+ {
+ termi = i * colsY;
+ for ( j = 0; j < colsY; j++ )
+ {
+ termj = j * colsX;
+ ij = termi + j;
+ ji = termj + i;
+ addij = ij >> LOGBITS;
+ addji = ji >> LOGBITS;
+ bitij = BITMASKTAB[ij AND MODMASK];
+ bitji = BITMASKTAB[ji AND MODMASK];
+ if ((*(Y+addij) AND bitij) != 0)
+ *(X+addji) |= bitji;
+ else
+ *(X+addji) &= NOT bitji;
+ }
+ }
+ }
+ }
+}
+
+/*****************************************************************************/
+/* VERSION: 6.4 */
+/*****************************************************************************/
+/* VERSION HISTORY: */
+/*****************************************************************************/
+/* */
+/* Version 6.4 03.10.04 Added C++ comp. directives. Improved "Norm()". */
+/* Version 6.3 28.09.02 Added "Create_List()" and "GCD2()". */
+/* Version 6.2 15.09.02 Overhauled error handling. Fixed "GCD()". */
+/* Version 6.1 08.10.01 Make VMS linker happy: _lsb,_msb => _lsb_,_msb_ */
+/* Version 6.0 08.10.00 Corrected overflow handling. */
+/* Version 5.8 14.07.00 Added "Power()". Changed "Copy()". */
+/* Version 5.7 19.05.99 Quickened "Div_Pos()". Added "Product()". */
+/* Version 5.6 02.11.98 Leading zeros eliminated in "to_Hex()". */
+/* Version 5.5 21.09.98 Fixed bug of uninitialized "error" in Multiply. */
+/* Version 5.4 07.09.98 Fixed bug of uninitialized "error" in Divide. */
+/* Version 5.3 12.05.98 Improved Norm. Completed history. */
+/* Version 5.2 31.03.98 Improved Norm. */
+/* Version 5.1 09.03.98 No changes. */
+/* Version 5.0 01.03.98 Major additions and rewrite. */
+/* Version 4.2 16.07.97 Added is_empty, is_full. */
+/* Version 4.1 30.06.97 Added word-ins/del, move-left/right, inc/dec. */
+/* Version 4.0 23.04.97 Rewrite. Added bit shift and bool. matrix ops. */
+/* Version 3.2 04.02.97 Added interval methods. */
+/* Version 3.1 21.01.97 Fixed bug on 64 bit machines. */
+/* Version 3.0 12.01.97 Added flip. */
+/* Version 2.0 14.12.96 Efficiency and consistency improvements. */
+/* Version 1.1 08.01.96 Added Resize and ExclusiveOr. */
+/* Version 1.0 14.12.95 First version under UNIX (with Perl module). */
+/* Version 0.9 01.11.93 First version of C library under MS-DOS. */
+/* Version 0.1 ??.??.89 First version in Turbo Pascal under CP/M. */
+/* */
+/*****************************************************************************/
+/* AUTHOR: */
+/*****************************************************************************/
+/* */
+/* Steffen Beyer */
+/* mailto:sb@engelschall.com */
+/* http://www.engelschall.com/u/sb/download/ */
+/* */
+/*****************************************************************************/
+/* COPYRIGHT: */
+/*****************************************************************************/
+/* */
+/* Copyright (c) 1995 - 2004 by Steffen Beyer. */
+/* All rights reserved. */
+/* */
+/*****************************************************************************/
+/* LICENSE: */
+/*****************************************************************************/
+/* This package is free software; you can use, modify and redistribute */
+/* it under the same terms as Perl itself, i.e., under the terms of */
+/* the "Artistic License" or the "GNU General Public License". */
+/* */
+/* The C library at the core of this Perl module can additionally */
+/* be used, modified and redistributed under the terms of the */
+/* "GNU Library General Public License". */
+/* */
+/*****************************************************************************/
+/* ARTISTIC LICENSE: */
+/*****************************************************************************/
+/*
+ The "Artistic License"
+
+ Preamble
+
+The intent of this document is to state the conditions under which a
+Package may be copied, such that the Copyright Holder maintains some
+semblance of artistic control over the development of the package,
+while giving the users of the package the right to use and distribute
+the Package in a more-or-less customary fashion, plus the right to make
+reasonable modifications.
+
+Definitions:
+
+ "Package" refers to the collection of files distributed by the
+ Copyright Holder, and derivatives of that collection of files
+ created through textual modification.
+
+ "Standard Version" refers to such a Package if it has not been
+ modified, or has been modified in accordance with the wishes
+ of the Copyright Holder as specified below.
+
+ "Copyright Holder" is whoever is named in the copyright or
+ copyrights for the package.
+
+ "You" is you, if you're thinking about copying or distributing
+ this Package.
+
+ "Reasonable copying fee" is whatever you can justify on the
+ basis of media cost, duplication charges, time of people involved,
+ and so on. (You will not be required to justify it to the
+ Copyright Holder, but only to the computing community at large
+ as a market that must bear the fee.)
+
+ "Freely Available" means that no fee is charged for the item
+ itself, though there may be fees involved in handling the item.
+ It also means that recipients of the item may redistribute it
+ under the same conditions they received it.
+
+1. You may make and give away verbatim copies of the source form of the
+Standard Version of this Package without restriction, provided that you
+duplicate all of the original copyright notices and associated disclaimers.
+
+2. You may apply bug fixes, portability fixes and other modifications
+derived from the Public Domain or from the Copyright Holder. A Package
+modified in such a way shall still be considered the Standard Version.
+
+3. You may otherwise modify your copy of this Package in any way, provided
+that you insert a prominent notice in each changed file stating how and
+when you changed that file, and provided that you do at least ONE of the
+following:
+
+ a) place your modifications in the Public Domain or otherwise make them
+ Freely Available, such as by posting said modifications to Usenet or
+ an equivalent medium, or placing the modifications on a major archive
+ site such as uunet.uu.net, or by allowing the Copyright Holder to include
+ your modifications in the Standard Version of the Package.
+
+ b) use the modified Package only within your corporation or organization.
+
+ c) rename any non-standard executables so the names do not conflict
+ with standard executables, which must also be provided, and provide
+ a separate manual page for each non-standard executable that clearly
+ documents how it differs from the Standard Version.
+
+ d) make other distribution arrangements with the Copyright Holder.
+
+4. You may distribute the programs of this Package in object code or
+executable form, provided that you do at least ONE of the following:
+
+ a) distribute a Standard Version of the executables and library files,
+ together with instructions (in the manual page or equivalent) on where
+ to get the Standard Version.
+
+ b) accompany the distribution with the machine-readable source of
+ the Package with your modifications.
+
+ c) give non-standard executables non-standard names, and clearly
+ document the differences in manual pages (or equivalent), together
+ with instructions on where to get the Standard Version.
+
+ d) make other distribution arrangements with the Copyright Holder.
+
+5. You may charge a reasonable copying fee for any distribution of this
+Package. You may charge any fee you choose for support of this
+Package. You may not charge a fee for this Package itself. However,
+you may distribute this Package in aggregate with other (possibly
+commercial) programs as part of a larger (possibly commercial) software
+distribution provided that you do not advertise this Package as a
+product of your own. You may embed this Package's interpreter within
+an executable of yours (by linking); this shall be construed as a mere
+form of aggregation, provided that the complete Standard Version of the
+interpreter is so embedded.
+
+6. The scripts and library files supplied as input to or produced as
+output from the programs of this Package do not automatically fall
+under the copyright of this Package, but belong to whoever generated
+them, and may be sold commercially, and may be aggregated with this
+Package. If such scripts or library files are aggregated with this
+Package via the so-called "undump" or "unexec" methods of producing a
+binary executable image, then distribution of such an image shall
+neither be construed as a distribution of this Package nor shall it
+fall under the restrictions of Paragraphs 3 and 4, provided that you do
+not represent such an executable image as a Standard Version of this
+Package.
+
+7. C subroutines (or comparably compiled subroutines in other
+languages) supplied by you and linked into this Package in order to
+emulate subroutines and variables of the language defined by this
+Package shall not be considered part of this Package, but are the
+equivalent of input as in Paragraph 6, provided these subroutines do
+not change the language in any way that would cause it to fail the
+regression tests for the language.
+
+8. Aggregation of this Package with a commercial distribution is always
+permitted provided that the use of this Package is embedded; that is,
+when no overt attempt is made to make this Package's interfaces visible
+to the end user of the commercial distribution. Such use shall not be
+construed as a distribution of this Package.
+
+9. The name of the Copyright Holder may not be used to endorse or promote
+products derived from this software without specific prior written permission.
+
+10. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+
+ The End
+*/
+/*****************************************************************************/
+/* GNU GENERAL PUBLIC LICENSE: */
+/*****************************************************************************/
+/* This program is free software; you can redistribute it and/or */
+/* modify it under the terms of the GNU General Public License */
+/* as published by the Free Software Foundation; either version 2 */
+/* of the License, or (at your option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the */
+/* Free Software Foundation, Inc., */
+/* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+/* */
+/*****************************************************************************/
+/* GNU LIBRARY GENERAL PUBLIC LICENSE: */
+/*****************************************************************************/
+/* This library is free software; you can redistribute it and/or */
+/* modify it under the terms of the GNU Library General Public */
+/* License as published by the Free Software Foundation; either */
+/* version 2 of the License, or (at your option) any later version. */
+/* */
+/* This library is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU */
+/* Library General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU Library General Public */
+/* License along with this library; if not, write to the */
+/* Free Software Foundation, Inc., */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+/* */
+/* or download a copy from ftp://ftp.gnu.org/pub/gnu/COPYING.LIB-2.0 */
+/* */
+/*****************************************************************************/
diff --git a/libyasm/bitvect.h b/libyasm/bitvect.h
new file mode 100644
index 0000000..3aee3a5
--- /dev/null
+++ b/libyasm/bitvect.h
@@ -0,0 +1,666 @@
+#ifndef YASM_BITVECT_H
+#define YASM_BITVECT_H
+/*****************************************************************************/
+/* MODULE NAME: BitVector.h MODULE TYPE: (adt) */
+/*****************************************************************************/
+/* MODULE IMPORTS: */
+/*****************************************************************************/
+
+/* ToolBox.h */
+/*****************************************************************************/
+/* NOTE: The type names that have been chosen here are somewhat weird on */
+/* purpose, in order to avoid name clashes with system header files */
+/* and your own application(s) which might - directly or indirectly - */
+/* include this definitions file. */
+/*****************************************************************************/
+#ifndef YASM_LIB_DECL
+#define YASM_LIB_DECL
+#endif
+
+typedef unsigned char N_char;
+typedef unsigned char N_byte;
+typedef unsigned short N_short;
+typedef unsigned short N_shortword;
+typedef unsigned int N_int;
+typedef unsigned int N_word;
+typedef unsigned long N_long;
+typedef unsigned long N_longword;
+
+/* Mnemonic 1: The natural numbers, N = { 0, 1, 2, 3, ... } */
+/* Mnemonic 2: Nnnn = u_N_signed, _N_ot signed */
+
+typedef signed char Z_char;
+typedef signed char Z_byte;
+typedef signed short Z_short;
+typedef signed short Z_shortword;
+typedef signed int Z_int;
+typedef signed int Z_word;
+typedef signed long Z_long;
+typedef signed long Z_longword;
+
+/* Mnemonic 1: The whole numbers, Z = { 0, -1, 1, -2, 2, -3, 3, ... } */
+/* Mnemonic 2: Zzzz = Ssss_igned */
+
+typedef void *voidptr;
+typedef N_char *charptr;
+typedef N_byte *byteptr;
+typedef N_short *shortptr;
+typedef N_shortword *shortwordptr;
+typedef N_int *intptr;
+typedef N_word *wordptr;
+typedef N_long *longptr;
+typedef N_longword *longwordptr;
+
+typedef N_char *N_charptr;
+typedef N_byte *N_byteptr;
+typedef N_short *N_shortptr;
+typedef N_shortword *N_shortwordptr;
+typedef N_int *N_intptr;
+typedef N_word *N_wordptr;
+typedef N_long *N_longptr;
+typedef N_longword *N_longwordptr;
+
+typedef Z_char *Z_charptr;
+typedef Z_byte *Z_byteptr;
+typedef Z_short *Z_shortptr;
+typedef Z_shortword *Z_shortwordptr;
+typedef Z_int *Z_intptr;
+typedef Z_word *Z_wordptr;
+typedef Z_long *Z_longptr;
+typedef Z_longword *Z_longwordptr;
+
+#ifndef FALSE
+#define FALSE (0!=0)
+#endif
+
+#ifndef TRUE
+#define TRUE (0==0)
+#endif
+
+#ifdef __cplusplus
+ typedef bool boolean;
+#else
+ #ifdef MACOS_TRADITIONAL
+ #define boolean Boolean
+ #else
+ typedef enum boolean { false = FALSE, true = TRUE } boolean;
+ #endif
+#endif
+
+/*****************************************************************************/
+/* MODULE INTERFACE: */
+/*****************************************************************************/
+
+typedef enum ErrCode
+ {
+ ErrCode_Ok = 0, /* everything went allright */
+
+ ErrCode_Type, /* types word and size_t have incompatible sizes */
+ ErrCode_Bits, /* bits of word and sizeof(word) are inconsistent */
+ ErrCode_Word, /* size of word is less than 16 bits */
+ ErrCode_Long, /* size of word is greater than size of long */
+ ErrCode_Powr, /* number of bits of word is not a power of two */
+ ErrCode_Loga, /* error in calculation of logarithm */
+
+ ErrCode_Null, /* unable to allocate memory */
+
+ ErrCode_Indx, /* index out of range */
+ ErrCode_Ordr, /* minimum > maximum index */
+ ErrCode_Size, /* bit vector size mismatch */
+ ErrCode_Pars, /* input string syntax error */
+ ErrCode_Ovfl, /* numeric overflow error */
+ ErrCode_Same, /* operands must be distinct */
+ ErrCode_Expo, /* exponent must be positive */
+ ErrCode_Zero /* division by zero error */
+ } ErrCode;
+
+typedef wordptr *listptr;
+
+/* ===> MISCELLANEOUS BASIC FUNCTIONS: <=== */
+
+YASM_LIB_DECL
+const char * BitVector_Error (ErrCode error); /* return string for err code */
+
+YASM_LIB_DECL
+ErrCode BitVector_Boot (void); /* 0 = ok, 1..7 = error */
+YASM_LIB_DECL
+void BitVector_Shutdown (void); /* undo Boot */
+
+YASM_LIB_DECL
+N_word BitVector_Size (N_int bits); /* bit vector size (# of words) */
+YASM_LIB_DECL
+N_word BitVector_Mask (N_int bits); /* bit vector mask (unused bits) */
+
+/* ===> CLASS METHODS: <=== */
+
+YASM_LIB_DECL
+const char * BitVector_Version (void); /* returns version string */
+
+YASM_LIB_DECL
+N_int BitVector_Word_Bits (void); /* return # of bits in machine word */
+YASM_LIB_DECL
+N_int BitVector_Long_Bits (void); /* return # of bits in unsigned long */
+
+/* ===> CONSTRUCTOR METHODS: <=== */
+
+YASM_LIB_DECL
+/*@only@*/ wordptr BitVector_Create (N_int bits, boolean clear); /* malloc */
+YASM_LIB_DECL
+listptr BitVector_Create_List(N_int bits, boolean clear, N_int count);
+
+YASM_LIB_DECL
+wordptr BitVector_Resize (wordptr oldaddr, N_int bits); /* realloc */
+
+YASM_LIB_DECL
+wordptr BitVector_Shadow (wordptr addr); /* make new same size but empty */
+YASM_LIB_DECL
+wordptr BitVector_Clone (wordptr addr); /* make exact duplicate */
+
+YASM_LIB_DECL
+wordptr BitVector_Concat (wordptr X, wordptr Y); /* return concatenation */
+
+/* ===> DESTRUCTOR METHODS: <=== */
+
+YASM_LIB_DECL
+void BitVector_Dispose (/*@only@*/ /*@out@*/ charptr string); /* string */
+YASM_LIB_DECL
+void BitVector_Destroy (/*@only@*/ wordptr addr); /* bitvec */
+YASM_LIB_DECL
+void BitVector_Destroy_List (listptr list, N_int count); /* list */
+
+/* ===> OBJECT METHODS: <=== */
+
+/* ===> bit vector copy function: */
+
+YASM_LIB_DECL
+void BitVector_Copy (wordptr X, wordptr Y); /* X = Y */
+
+/* ===> bit vector initialization: */
+
+YASM_LIB_DECL
+void BitVector_Empty (wordptr addr); /* X = {} */
+YASM_LIB_DECL
+void BitVector_Fill (wordptr addr); /* X = ~{} */
+YASM_LIB_DECL
+void BitVector_Flip (wordptr addr); /* X = ~X */
+
+YASM_LIB_DECL
+void BitVector_Primes (wordptr addr);
+
+/* ===> miscellaneous functions: */
+
+YASM_LIB_DECL
+void BitVector_Reverse (wordptr X, wordptr Y);
+
+/* ===> bit vector interval operations and functions: */
+
+YASM_LIB_DECL
+void BitVector_Interval_Empty (/*@out@*/ wordptr addr, N_int lower, N_int upper);
+YASM_LIB_DECL
+void BitVector_Interval_Fill (/*@out@*/ wordptr addr, N_int lower, N_int upper);
+YASM_LIB_DECL
+void BitVector_Interval_Flip (/*@out@*/ wordptr addr, N_int lower, N_int upper);
+YASM_LIB_DECL
+void BitVector_Interval_Reverse (/*@out@*/ wordptr addr, N_int lower, N_int upper);
+
+YASM_LIB_DECL
+boolean BitVector_interval_scan_inc (wordptr addr, N_int start,
+ N_intptr min, N_intptr max);
+YASM_LIB_DECL
+boolean BitVector_interval_scan_dec (wordptr addr, N_int start,
+ N_intptr min, N_intptr max);
+
+YASM_LIB_DECL
+void BitVector_Interval_Copy (/*@out@*/ wordptr X, wordptr Y, N_int Xoffset,
+ N_int Yoffset, N_int length);
+
+YASM_LIB_DECL
+wordptr BitVector_Interval_Substitute(/*@out@*/ wordptr X, wordptr Y,
+ N_int Xoffset, N_int Xlength,
+ N_int Yoffset, N_int Ylength);
+
+/* ===> bit vector test functions: */
+
+YASM_LIB_DECL
+boolean BitVector_is_empty (wordptr addr); /* X == {} ? */
+YASM_LIB_DECL
+boolean BitVector_is_full (wordptr addr); /* X == ~{} ? */
+
+YASM_LIB_DECL
+boolean BitVector_equal (wordptr X, wordptr Y); /* X == Y ? */
+YASM_LIB_DECL
+Z_int BitVector_Lexicompare(wordptr X, wordptr Y); /* X <,=,> Y ? */
+YASM_LIB_DECL
+Z_int BitVector_Compare (wordptr X, wordptr Y); /* X <,=,> Y ? */
+
+/* ===> bit vector string conversion functions: */
+
+YASM_LIB_DECL
+/*@only@*/ charptr BitVector_to_Hex (wordptr addr);
+YASM_LIB_DECL
+ErrCode BitVector_from_Hex (/*@out@*/wordptr addr, charptr string);
+
+YASM_LIB_DECL
+ErrCode BitVector_from_Oct(/*@out@*/ wordptr addr, charptr string);
+
+YASM_LIB_DECL
+/*@only@*/ charptr BitVector_to_Bin (wordptr addr);
+YASM_LIB_DECL
+ErrCode BitVector_from_Bin (/*@out@*/ wordptr addr, charptr string);
+
+YASM_LIB_DECL
+/*@only@*/ charptr BitVector_to_Dec (wordptr addr);
+YASM_LIB_DECL
+ErrCode BitVector_from_Dec (/*@out@*/ wordptr addr, charptr string);
+
+typedef struct BitVector_from_Dec_static_data BitVector_from_Dec_static_data;
+YASM_LIB_DECL
+BitVector_from_Dec_static_data *BitVector_from_Dec_static_Boot(N_word bits);
+YASM_LIB_DECL
+void BitVector_from_Dec_static_Shutdown(/*@null@*/ BitVector_from_Dec_static_data *data);
+YASM_LIB_DECL
+ErrCode BitVector_from_Dec_static(BitVector_from_Dec_static_data *data,
+ /*@out@*/ wordptr addr, charptr string);
+
+YASM_LIB_DECL
+/*@only@*/ charptr BitVector_to_Enum (wordptr addr);
+YASM_LIB_DECL
+ErrCode BitVector_from_Enum (/*@out@*/ wordptr addr, charptr string);
+
+/* ===> bit vector bit operations, functions & tests: */
+
+YASM_LIB_DECL
+void BitVector_Bit_Off (/*@out@*/ wordptr addr, N_int indx); /* X = X \ {x} */
+YASM_LIB_DECL
+void BitVector_Bit_On (/*@out@*/ wordptr addr, N_int indx); /* X = X + {x} */
+YASM_LIB_DECL
+boolean BitVector_bit_flip (/*@out@*/ wordptr addr, N_int indx); /* (X+{x})\(X*{x}) */
+
+YASM_LIB_DECL
+boolean BitVector_bit_test (wordptr addr, N_int indx); /* {x} in X ? */
+
+YASM_LIB_DECL
+void BitVector_Bit_Copy (/*@out@*/ wordptr addr, N_int indx, boolean bit);
+
+/* ===> bit vector bit shift & rotate functions: */
+
+YASM_LIB_DECL
+void BitVector_LSB (/*@out@*/ wordptr addr, boolean bit);
+YASM_LIB_DECL
+void BitVector_MSB (/*@out@*/ wordptr addr, boolean bit);
+YASM_LIB_DECL
+boolean BitVector_lsb_ (wordptr addr);
+YASM_LIB_DECL
+boolean BitVector_msb_ (wordptr addr);
+YASM_LIB_DECL
+boolean /*@alt void@*/ BitVector_rotate_left (wordptr addr);
+YASM_LIB_DECL
+boolean /*@alt void@*/ BitVector_rotate_right (wordptr addr);
+YASM_LIB_DECL
+boolean /*@alt void@*/ BitVector_shift_left (wordptr addr, boolean carry_in);
+YASM_LIB_DECL
+boolean /*@alt void@*/ BitVector_shift_right (wordptr addr, boolean carry_in);
+YASM_LIB_DECL
+void BitVector_Move_Left (wordptr addr, N_int bits);
+YASM_LIB_DECL
+void BitVector_Move_Right (wordptr addr, N_int bits);
+
+/* ===> bit vector insert/delete bits: */
+
+YASM_LIB_DECL
+void BitVector_Insert (wordptr addr, N_int offset, N_int count,
+ boolean clear);
+YASM_LIB_DECL
+void BitVector_Delete (wordptr addr, N_int offset, N_int count,
+ boolean clear);
+
+/* ===> bit vector arithmetic: */
+
+YASM_LIB_DECL
+boolean /*@alt void@*/ BitVector_increment (wordptr addr); /* X++ */
+YASM_LIB_DECL
+boolean /*@alt void@*/ BitVector_decrement (wordptr addr); /* X-- */
+
+YASM_LIB_DECL
+boolean /*@alt void@*/ BitVector_compute (wordptr X, wordptr Y, wordptr Z, boolean minus,
+ boolean *carry);
+YASM_LIB_DECL
+boolean /*@alt void@*/ BitVector_add (wordptr X, wordptr Y, wordptr Z, boolean *carry);
+YASM_LIB_DECL
+boolean /*@alt void@*/ BitVector_sub (wordptr X, wordptr Y, wordptr Z, boolean *carry);
+YASM_LIB_DECL
+boolean /*@alt void@*/ BitVector_inc (wordptr X, wordptr Y);
+YASM_LIB_DECL
+boolean /*@alt void@*/ BitVector_dec (wordptr X, wordptr Y);
+
+YASM_LIB_DECL
+void BitVector_Negate (wordptr X, wordptr Y);
+YASM_LIB_DECL
+void BitVector_Absolute (wordptr X, wordptr Y);
+YASM_LIB_DECL
+Z_int BitVector_Sign (wordptr addr);
+YASM_LIB_DECL
+ErrCode BitVector_Mul_Pos (wordptr X, wordptr Y, wordptr Z, boolean strict);
+YASM_LIB_DECL
+ErrCode BitVector_Multiply (wordptr X, wordptr Y, wordptr Z);
+YASM_LIB_DECL
+ErrCode BitVector_Div_Pos (wordptr Q, wordptr X, wordptr Y, wordptr R);
+YASM_LIB_DECL
+ErrCode BitVector_Divide (wordptr Q, wordptr X, wordptr Y, wordptr R);
+YASM_LIB_DECL
+ErrCode BitVector_GCD (wordptr X, wordptr Y, wordptr Z);
+YASM_LIB_DECL
+ErrCode BitVector_GCD2 (wordptr U, wordptr V, wordptr W, /* O */
+ wordptr X, wordptr Y); /* I */
+YASM_LIB_DECL
+ErrCode BitVector_Power (wordptr X, wordptr Y, wordptr Z);
+
+/* ===> direct memory access functions: */
+
+YASM_LIB_DECL
+void BitVector_Block_Store(wordptr addr, charptr buffer, N_int length);
+YASM_LIB_DECL
+charptr BitVector_Block_Read (wordptr addr, /*@out@*/ N_intptr length);
+
+/* ===> word array functions: */
+
+YASM_LIB_DECL
+void BitVector_Word_Store (wordptr addr, N_int offset, N_int value);
+YASM_LIB_DECL
+N_int BitVector_Word_Read (wordptr addr, N_int offset);
+
+YASM_LIB_DECL
+void BitVector_Word_Insert(wordptr addr, N_int offset, N_int count,
+ boolean clear);
+YASM_LIB_DECL
+void BitVector_Word_Delete(wordptr addr, N_int offset, N_int count,
+ boolean clear);
+
+/* ===> arbitrary size chunk functions: */
+
+YASM_LIB_DECL
+void BitVector_Chunk_Store(wordptr addr, N_int chunksize,
+ N_int offset, N_long value);
+YASM_LIB_DECL
+N_long BitVector_Chunk_Read (wordptr addr, N_int chunksize,
+ N_int offset);
+
+/* ===> set operations: */
+
+YASM_LIB_DECL
+void Set_Union (wordptr X, wordptr Y, wordptr Z); /* X = Y + Z */
+YASM_LIB_DECL
+void Set_Intersection (wordptr X, wordptr Y, wordptr Z); /* X = Y * Z */
+YASM_LIB_DECL
+void Set_Difference (wordptr X, wordptr Y, wordptr Z); /* X = Y \ Z */
+YASM_LIB_DECL
+void Set_ExclusiveOr (wordptr X, wordptr Y, wordptr Z); /*(Y+Z)\(Y*Z)*/
+YASM_LIB_DECL
+void Set_Complement (wordptr X, wordptr Y); /* X = ~Y */
+
+/* ===> set functions: */
+
+YASM_LIB_DECL
+boolean Set_subset (wordptr X, wordptr Y); /* X in Y ? */
+
+YASM_LIB_DECL
+N_int Set_Norm (wordptr addr); /* = | X | */
+YASM_LIB_DECL
+N_int Set_Norm2 (wordptr addr); /* = | X | */
+YASM_LIB_DECL
+N_int Set_Norm3 (wordptr addr); /* = | X | */
+YASM_LIB_DECL
+Z_long Set_Min (wordptr addr); /* = min(X) */
+YASM_LIB_DECL
+Z_long Set_Max (wordptr addr); /* = max(X) */
+
+/* ===> matrix-of-booleans operations: */
+
+YASM_LIB_DECL
+void Matrix_Multiplication(wordptr X, N_int rowsX, N_int colsX,
+ wordptr Y, N_int rowsY, N_int colsY,
+ wordptr Z, N_int rowsZ, N_int colsZ);
+
+YASM_LIB_DECL
+void Matrix_Product (wordptr X, N_int rowsX, N_int colsX,
+ wordptr Y, N_int rowsY, N_int colsY,
+ wordptr Z, N_int rowsZ, N_int colsZ);
+
+YASM_LIB_DECL
+void Matrix_Closure (wordptr addr, N_int rows, N_int cols);
+
+YASM_LIB_DECL
+void Matrix_Transpose (wordptr X, N_int rowsX, N_int colsX,
+ wordptr Y, N_int rowsY, N_int colsY);
+
+/*****************************************************************************/
+/* VERSION: 6.4 */
+/*****************************************************************************/
+/* VERSION HISTORY: */
+/*****************************************************************************/
+/* */
+/* Version 6.4 03.10.04 Added C++ comp. directives. Improved "Norm()". */
+/* Version 6.3 28.09.02 Added "Create_List()" and "GCD2()". */
+/* Version 6.2 15.09.02 Overhauled error handling. Fixed "GCD()". */
+/* Version 6.1 08.10.01 Make VMS linker happy: _lsb,_msb => _lsb_,_msb_ */
+/* Version 6.0 08.10.00 Corrected overflow handling. */
+/* Version 5.8 14.07.00 Added "Power()". Changed "Copy()". */
+/* Version 5.7 19.05.99 Quickened "Div_Pos()". Added "Product()". */
+/* Version 5.6 02.11.98 Leading zeros eliminated in "to_Hex()". */
+/* Version 5.5 21.09.98 Fixed bug of uninitialized "error" in Multiply. */
+/* Version 5.4 07.09.98 Fixed bug of uninitialized "error" in Divide. */
+/* Version 5.3 12.05.98 Improved Norm. Completed history. */
+/* Version 5.2 31.03.98 Improved Norm. */
+/* Version 5.1 09.03.98 No changes. */
+/* Version 5.0 01.03.98 Major additions and rewrite. */
+/* Version 4.2 16.07.97 Added is_empty, is_full. */
+/* Version 4.1 30.06.97 Added word-ins/del, move-left/right, inc/dec. */
+/* Version 4.0 23.04.97 Rewrite. Added bit shift and bool. matrix ops. */
+/* Version 3.2 04.02.97 Added interval methods. */
+/* Version 3.1 21.01.97 Fixed bug on 64 bit machines. */
+/* Version 3.0 12.01.97 Added flip. */
+/* Version 2.0 14.12.96 Efficiency and consistency improvements. */
+/* Version 1.1 08.01.96 Added Resize and ExclusiveOr. */
+/* Version 1.0 14.12.95 First version under UNIX (with Perl module). */
+/* Version 0.9 01.11.93 First version of C library under MS-DOS. */
+/* Version 0.1 ??.??.89 First version in Turbo Pascal under CP/M. */
+/* */
+/*****************************************************************************/
+/* AUTHOR: */
+/*****************************************************************************/
+/* */
+/* Steffen Beyer */
+/* mailto:sb@engelschall.com */
+/* http://www.engelschall.com/u/sb/download/ */
+/* */
+/*****************************************************************************/
+/* COPYRIGHT: */
+/*****************************************************************************/
+/* */
+/* Copyright (c) 1995 - 2004 by Steffen Beyer. */
+/* All rights reserved. */
+/* */
+/*****************************************************************************/
+/* LICENSE: */
+/*****************************************************************************/
+/* This package is free software; you can use, modify and redistribute */
+/* it under the same terms as Perl itself, i.e., under the terms of */
+/* the "Artistic License" or the "GNU General Public License". */
+/* */
+/* The C library at the core of this Perl module can additionally */
+/* be used, modified and redistributed under the terms of the */
+/* "GNU Library General Public License". */
+/* */
+/*****************************************************************************/
+/* ARTISTIC LICENSE: */
+/*****************************************************************************/
+/*
+ The "Artistic License"
+
+ Preamble
+
+The intent of this document is to state the conditions under which a
+Package may be copied, such that the Copyright Holder maintains some
+semblance of artistic control over the development of the package,
+while giving the users of the package the right to use and distribute
+the Package in a more-or-less customary fashion, plus the right to make
+reasonable modifications.
+
+Definitions:
+
+ "Package" refers to the collection of files distributed by the
+ Copyright Holder, and derivatives of that collection of files
+ created through textual modification.
+
+ "Standard Version" refers to such a Package if it has not been
+ modified, or has been modified in accordance with the wishes
+ of the Copyright Holder as specified below.
+
+ "Copyright Holder" is whoever is named in the copyright or
+ copyrights for the package.
+
+ "You" is you, if you're thinking about copying or distributing
+ this Package.
+
+ "Reasonable copying fee" is whatever you can justify on the
+ basis of media cost, duplication charges, time of people involved,
+ and so on. (You will not be required to justify it to the
+ Copyright Holder, but only to the computing community at large
+ as a market that must bear the fee.)
+
+ "Freely Available" means that no fee is charged for the item
+ itself, though there may be fees involved in handling the item.
+ It also means that recipients of the item may redistribute it
+ under the same conditions they received it.
+
+1. You may make and give away verbatim copies of the source form of the
+Standard Version of this Package without restriction, provided that you
+duplicate all of the original copyright notices and associated disclaimers.
+
+2. You may apply bug fixes, portability fixes and other modifications
+derived from the Public Domain or from the Copyright Holder. A Package
+modified in such a way shall still be considered the Standard Version.
+
+3. You may otherwise modify your copy of this Package in any way, provided
+that you insert a prominent notice in each changed file stating how and
+when you changed that file, and provided that you do at least ONE of the
+following:
+
+ a) place your modifications in the Public Domain or otherwise make them
+ Freely Available, such as by posting said modifications to Usenet or
+ an equivalent medium, or placing the modifications on a major archive
+ site such as uunet.uu.net, or by allowing the Copyright Holder to include
+ your modifications in the Standard Version of the Package.
+
+ b) use the modified Package only within your corporation or organization.
+
+ c) rename any non-standard executables so the names do not conflict
+ with standard executables, which must also be provided, and provide
+ a separate manual page for each non-standard executable that clearly
+ documents how it differs from the Standard Version.
+
+ d) make other distribution arrangements with the Copyright Holder.
+
+4. You may distribute the programs of this Package in object code or
+executable form, provided that you do at least ONE of the following:
+
+ a) distribute a Standard Version of the executables and library files,
+ together with instructions (in the manual page or equivalent) on where
+ to get the Standard Version.
+
+ b) accompany the distribution with the machine-readable source of
+ the Package with your modifications.
+
+ c) give non-standard executables non-standard names, and clearly
+ document the differences in manual pages (or equivalent), together
+ with instructions on where to get the Standard Version.
+
+ d) make other distribution arrangements with the Copyright Holder.
+
+5. You may charge a reasonable copying fee for any distribution of this
+Package. You may charge any fee you choose for support of this
+Package. You may not charge a fee for this Package itself. However,
+you may distribute this Package in aggregate with other (possibly
+commercial) programs as part of a larger (possibly commercial) software
+distribution provided that you do not advertise this Package as a
+product of your own. You may embed this Package's interpreter within
+an executable of yours (by linking); this shall be construed as a mere
+form of aggregation, provided that the complete Standard Version of the
+interpreter is so embedded.
+
+6. The scripts and library files supplied as input to or produced as
+output from the programs of this Package do not automatically fall
+under the copyright of this Package, but belong to whoever generated
+them, and may be sold commercially, and may be aggregated with this
+Package. If such scripts or library files are aggregated with this
+Package via the so-called "undump" or "unexec" methods of producing a
+binary executable image, then distribution of such an image shall
+neither be construed as a distribution of this Package nor shall it
+fall under the restrictions of Paragraphs 3 and 4, provided that you do
+not represent such an executable image as a Standard Version of this
+Package.
+
+7. C subroutines (or comparably compiled subroutines in other
+languages) supplied by you and linked into this Package in order to
+emulate subroutines and variables of the language defined by this
+Package shall not be considered part of this Package, but are the
+equivalent of input as in Paragraph 6, provided these subroutines do
+not change the language in any way that would cause it to fail the
+regression tests for the language.
+
+8. Aggregation of this Package with a commercial distribution is always
+permitted provided that the use of this Package is embedded; that is,
+when no overt attempt is made to make this Package's interfaces visible
+to the end user of the commercial distribution. Such use shall not be
+construed as a distribution of this Package.
+
+9. The name of the Copyright Holder may not be used to endorse or promote
+products derived from this software without specific prior written permission.
+
+10. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+
+ The End
+*/
+/*****************************************************************************/
+/* GNU GENERAL PUBLIC LICENSE: */
+/*****************************************************************************/
+/* This program is free software; you can redistribute it and/or */
+/* modify it under the terms of the GNU General Public License */
+/* as published by the Free Software Foundation; either version 2 */
+/* of the License, or (at your option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the */
+/* Free Software Foundation, Inc., */
+/* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+/* */
+/*****************************************************************************/
+/* GNU LIBRARY GENERAL PUBLIC LICENSE: */
+/*****************************************************************************/
+/* */
+/* This library is free software; you can redistribute it and/or */
+/* modify it under the terms of the GNU Library General Public */
+/* License as published by the Free Software Foundation; either */
+/* version 2 of the License, or (at your option) any later version. */
+/* */
+/* This library is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU */
+/* Library General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU Library General Public */
+/* License along with this library; if not, write to the */
+/* Free Software Foundation, Inc., */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+/* */
+/* or download a copy from ftp://ftp.gnu.org/pub/gnu/COPYING.LIB-2.0 */
+/* */
+/*****************************************************************************/
+#endif
diff --git a/libyasm/bytecode.c b/libyasm/bytecode.c
new file mode 100644
index 0000000..f864bae
--- /dev/null
+++ b/libyasm/bytecode.c
@@ -0,0 +1,386 @@
+/*
+ * Bytecode utility functions
+ *
+ * Copyright (C) 2001-2007 Peter Johnson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "util.h"
+
+#include "libyasm-stdint.h"
+#include "coretype.h"
+
+#include "errwarn.h"
+#include "intnum.h"
+#include "expr.h"
+#include "value.h"
+#include "symrec.h"
+
+#include "bytecode.h"
+
+
+void
+yasm_bc_set_multiple(yasm_bytecode *bc, yasm_expr *e)
+{
+ if (bc->multiple)
+ bc->multiple = yasm_expr_create_tree(bc->multiple, YASM_EXPR_MUL, e,
+ e->line);
+ else
+ bc->multiple = e;
+}
+
+void
+yasm_bc_finalize_common(yasm_bytecode *bc, yasm_bytecode *prev_bc)
+{
+}
+
+int
+yasm_bc_calc_len_common(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
+ void *add_span_data)
+{
+ yasm_internal_error(N_("bytecode length cannot be calculated"));
+ /*@unreached@*/
+ return 0;
+}
+
+int
+yasm_bc_expand_common(yasm_bytecode *bc, int span, long old_val, long new_val,
+ /*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres)
+{
+ yasm_internal_error(N_("bytecode does not have any dependent spans"));
+ /*@unreached@*/
+ return 0;
+}
+
+int
+yasm_bc_tobytes_common(yasm_bytecode *bc, unsigned char **buf,
+ unsigned char *bufstart, void *d,
+ yasm_output_value_func output_value,
+ /*@null@*/ yasm_output_reloc_func output_reloc)
+{
+ yasm_internal_error(N_("bytecode cannot be converted to bytes"));
+ /*@unreached@*/
+ return 0;
+}
+
+void
+yasm_bc_transform(yasm_bytecode *bc, const yasm_bytecode_callback *callback,
+ void *contents)
+{
+ if (bc->callback)
+ bc->callback->destroy(bc->contents);
+ bc->callback = callback;
+ bc->contents = contents;
+}
+
+yasm_bytecode *
+yasm_bc_create_common(const yasm_bytecode_callback *callback, void *contents,
+ unsigned long line)
+{
+ yasm_bytecode *bc = yasm_xmalloc(sizeof(yasm_bytecode));
+
+ bc->callback = callback;
+ bc->section = NULL;
+ bc->multiple = (yasm_expr *)NULL;
+ bc->len = 0;
+ bc->mult_int = 1;
+ bc->line = line;
+ bc->offset = ~0UL; /* obviously incorrect / uninitialized value */
+ bc->symrecs = NULL;
+ bc->contents = contents;
+
+ return bc;
+}
+
+yasm_section *
+yasm_bc_get_section(yasm_bytecode *bc)
+{
+ return bc->section;
+}
+
+void
+yasm_bc__add_symrec(yasm_bytecode *bc, yasm_symrec *sym)
+{
+ if (!bc->symrecs) {
+ bc->symrecs = yasm_xmalloc(2*sizeof(yasm_symrec *));
+ bc->symrecs[0] = sym;
+ bc->symrecs[1] = NULL;
+ } else {
+ /* Very inefficient implementation for large numbers of symbols. But
+ * that would be very unusual, so use the simple algorithm instead.
+ */
+ size_t count = 1;
+ while (bc->symrecs[count])
+ count++;
+ bc->symrecs = yasm_xrealloc(bc->symrecs,
+ (count+2)*sizeof(yasm_symrec *));
+ bc->symrecs[count] = sym;
+ bc->symrecs[count+1] = NULL;
+ }
+}
+
+void
+yasm_bc_destroy(yasm_bytecode *bc)
+{
+ if (!bc)
+ return;
+
+ if (bc->callback)
+ bc->callback->destroy(bc->contents);
+ yasm_expr_destroy(bc->multiple);
+ if (bc->symrecs)
+ yasm_xfree(bc->symrecs);
+ yasm_xfree(bc);
+}
+
+void
+yasm_bc_print(const yasm_bytecode *bc, FILE *f, int indent_level)
+{
+ if (!bc->callback)
+ fprintf(f, "%*s_Empty_\n", indent_level, "");
+ else
+ bc->callback->print(bc->contents, f, indent_level);
+ fprintf(f, "%*sMultiple=", indent_level, "");
+ if (!bc->multiple)
+ fprintf(f, "nil (1)");
+ else
+ yasm_expr_print(bc->multiple, f);
+ fprintf(f, "\n%*sLength=%lu\n", indent_level, "", bc->len);
+ fprintf(f, "%*sLine Index=%lu\n", indent_level, "", bc->line);
+ fprintf(f, "%*sOffset=%lx\n", indent_level, "", bc->offset);
+}
+
+void
+yasm_bc_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc)
+{
+ if (bc->callback)
+ bc->callback->finalize(bc, prev_bc);
+ if (bc->multiple) {
+ yasm_value val;
+
+ if (yasm_value_finalize_expr(&val, bc->multiple, prev_bc, 0))
+ yasm_error_set(YASM_ERROR_TOO_COMPLEX,
+ N_("multiple expression too complex"));
+ else if (val.rel)
+ yasm_error_set(YASM_ERROR_NOT_ABSOLUTE,
+ N_("multiple expression not absolute"));
+ /* Finalize creates NULL output if value=0, but bc->multiple is NULL
+ * if value=1 (this difference is to make the common case small).
+ * However, this means we need to set bc->multiple explicitly to 0
+ * here if val.abs is NULL.
+ */
+ if (val.abs)
+ bc->multiple = val.abs;
+ else
+ bc->multiple = yasm_expr_create_ident(
+ yasm_expr_int(yasm_intnum_create_uint(0)), bc->line);
+ }
+}
+
+/*@null@*/ yasm_intnum *
+yasm_calc_bc_dist(yasm_bytecode *precbc1, yasm_bytecode *precbc2)
+{
+ unsigned long dist2, dist1;
+ yasm_intnum *intn;
+
+ if (precbc1->section != precbc2->section)
+ return NULL;
+
+ dist1 = yasm_bc_next_offset(precbc1);
+ dist2 = yasm_bc_next_offset(precbc2);
+ if (dist2 < dist1) {
+ intn = yasm_intnum_create_uint(dist1 - dist2);
+ yasm_intnum_calc(intn, YASM_EXPR_NEG, NULL);
+ return intn;
+ }
+ dist2 -= dist1;
+ return yasm_intnum_create_uint(dist2);
+}
+
+unsigned long
+yasm_bc_next_offset(yasm_bytecode *precbc)
+{
+ return precbc->offset + precbc->len*precbc->mult_int;
+}
+
+int
+yasm_bc_elem_size(yasm_bytecode *bc)
+{
+ if (!bc->callback) {
+ yasm_internal_error(N_("got empty bytecode in yasm_bc_elem_size"));
+ return 0;
+ } else if (!bc->callback->elem_size)
+ return 0;
+ else
+ return bc->callback->elem_size(bc);
+}
+
+int
+yasm_bc_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
+ void *add_span_data)
+{
+ int retval = 0;
+
+ bc->len = 0;
+
+ if (!bc->callback)
+ yasm_internal_error(N_("got empty bytecode in yasm_bc_calc_len"));
+ else
+ retval = bc->callback->calc_len(bc, add_span, add_span_data);
+
+ /* Check for multiples */
+ bc->mult_int = 1;
+ if (bc->multiple) {
+ /*@dependent@*/ /*@null@*/ const yasm_intnum *num;
+
+ num = yasm_expr_get_intnum(&bc->multiple, 0);
+ if (num) {
+ if (yasm_intnum_sign(num) < 0) {
+ yasm_error_set(YASM_ERROR_VALUE, N_("multiple is negative"));
+ retval = -1;
+ } else
+ bc->mult_int = yasm_intnum_get_int(num);
+ } else {
+ if (yasm_expr__contains(bc->multiple, YASM_EXPR_FLOAT)) {
+ yasm_error_set(YASM_ERROR_VALUE,
+ N_("expression must not contain floating point value"));
+ retval = -1;
+ } else {
+ yasm_value value;
+ yasm_value_initialize(&value, bc->multiple, 0);
+ add_span(add_span_data, bc, 0, &value, 0, 0);
+ bc->mult_int = 0; /* assume 0 to start */
+ }
+ }
+ }
+
+ /* If we got an error somewhere along the line, clear out any calc len */
+ if (retval < 0)
+ bc->len = 0;
+
+ return retval;
+}
+
+int
+yasm_bc_expand(yasm_bytecode *bc, int span, long old_val, long new_val,
+ /*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres)
+{
+ if (span == 0) {
+ bc->mult_int = new_val;
+ return 1;
+ }
+ if (!bc->callback) {
+ yasm_internal_error(N_("got empty bytecode in yasm_bc_expand"));
+ /*@unreached@*/
+ return -1;
+ } else
+ return bc->callback->expand(bc, span, old_val, new_val, neg_thres,
+ pos_thres);
+}
+
+/*@null@*/ /*@only@*/ unsigned char *
+yasm_bc_tobytes(yasm_bytecode *bc, unsigned char *buf, unsigned long *bufsize,
+ /*@out@*/ int *gap, void *d,
+ yasm_output_value_func output_value,
+ /*@null@*/ yasm_output_reloc_func output_reloc)
+ /*@sets *buf@*/
+{
+ /*@only@*/ /*@null@*/ unsigned char *mybuf = NULL;
+ unsigned char *bufstart;
+ unsigned char *origbuf, *destbuf;
+ long i;
+ int error = 0;
+
+ long mult;
+ if (yasm_bc_get_multiple(bc, &mult, 1) || mult == 0) {
+ *bufsize = 0;
+ return NULL;
+ }
+ bc->mult_int = mult;
+
+ /* special case for reserve bytecodes */
+ if (bc->callback->special == YASM_BC_SPECIAL_RESERVE) {
+ *bufsize = bc->len*bc->mult_int;
+ *gap = 1;
+ return NULL; /* we didn't allocate a buffer */
+ }
+ *gap = 0;
+
+ if (*bufsize < bc->len*bc->mult_int) {
+ mybuf = yasm_xmalloc(bc->len*bc->mult_int);
+ destbuf = mybuf;
+ } else
+ destbuf = buf;
+ bufstart = destbuf;
+
+ *bufsize = bc->len*bc->mult_int;
+
+ if (!bc->callback)
+ yasm_internal_error(N_("got empty bytecode in bc_tobytes"));
+ else for (i=0; i<bc->mult_int; i++) {
+ origbuf = destbuf;
+ error = bc->callback->tobytes(bc, &destbuf, bufstart, d, output_value,
+ output_reloc);
+
+ if (!error && ((unsigned long)(destbuf - origbuf) != bc->len))
+ yasm_internal_error(
+ N_("written length does not match optimized length"));
+ }
+
+ return mybuf;
+}
+
+int
+yasm_bc_get_multiple(yasm_bytecode *bc, long *multiple, int calc_bc_dist)
+{
+ /*@dependent@*/ /*@null@*/ const yasm_intnum *num;
+
+ *multiple = 1;
+ if (bc->multiple) {
+ num = yasm_expr_get_intnum(&bc->multiple, calc_bc_dist);
+ if (!num) {
+ yasm_error_set(YASM_ERROR_VALUE,
+ N_("could not determine multiple"));
+ return 1;
+ }
+ if (yasm_intnum_sign(num) < 0) {
+ yasm_error_set(YASM_ERROR_VALUE, N_("multiple is negative"));
+ return 1;
+ }
+ *multiple = yasm_intnum_get_int(num);
+ }
+ return 0;
+}
+
+const yasm_expr *
+yasm_bc_get_multiple_expr(const yasm_bytecode *bc)
+{
+ return bc->multiple;
+}
+
+yasm_insn *
+yasm_bc_get_insn(yasm_bytecode *bc)
+{
+ if (bc->callback->special != YASM_BC_SPECIAL_INSN)
+ return NULL;
+ return (yasm_insn *)bc->contents;
+}
diff --git a/libyasm/bytecode.h b/libyasm/bytecode.h
new file mode 100644
index 0000000..4e8a801
--- /dev/null
+++ b/libyasm/bytecode.h
@@ -0,0 +1,633 @@
+/**
+ * \file libyasm/bytecode.h
+ * \brief YASM bytecode interface.
+ *
+ * \license
+ * Copyright (C) 2001-2007 Peter Johnson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * \endlicense
+ */
+#ifndef YASM_BYTECODE_H
+#define YASM_BYTECODE_H
+
+#ifndef YASM_LIB_DECL
+#define YASM_LIB_DECL
+#endif
+
+/** A data value (opaque type). */
+typedef struct yasm_dataval yasm_dataval;
+/** A list of data values. */
+typedef struct yasm_datavalhead yasm_datavalhead;
+
+/** Linked list of data values. */
+/*@reldef@*/ STAILQ_HEAD(yasm_datavalhead, yasm_dataval);
+
+/** Add a dependent span for a bytecode.
+ * \param add_span_data add_span_data passed into bc_calc_len()
+ * \param bc bytecode containing span
+ * \param id non-zero identifier for span; may be any non-zero value
+ * if <0, expand is called for any change;
+ * if >0, expand is only called when exceeds threshold
+ * \param value dependent value for bytecode expansion
+ * \param neg_thres negative threshold for long/short decision
+ * \param pos_thres positive threshold for long/short decision
+ */
+typedef void (*yasm_bc_add_span_func)
+ (void *add_span_data, yasm_bytecode *bc, int id, const yasm_value *value,
+ long neg_thres, long pos_thres);
+
+/** Bytecode callback structure. Any implementation of a specific bytecode
+ * must implement these functions and this callback structure. The bytecode
+ * implementation-specific data is stored in #yasm_bytecode.contents.
+ */
+typedef struct yasm_bytecode_callback {
+ /** Destroys the implementation-specific data.
+ * Called from yasm_bc_destroy().
+ * \param contents #yasm_bytecode.contents
+ */
+ void (*destroy) (/*@only@*/ void *contents);
+
+ /** Prints the implementation-specific data (for debugging purposes).
+ * Called from yasm_bc_print().
+ * \param contents #yasm_bytecode.contents
+ * \param f file
+ * \param indent_level indentation level
+ */
+ void (*print) (const void *contents, FILE *f, int indent_level);
+
+ /** Finalizes the bytecode after parsing. Called from yasm_bc_finalize().
+ * A generic fill-in for this is yasm_bc_finalize_common().
+ * \param bc bytecode
+ * \param prev_bc bytecode directly preceding bc
+ */
+ void (*finalize) (yasm_bytecode *bc, yasm_bytecode *prev_bc);
+
+ /** Return elements size of a data bytecode.
+ * This function should return the size of each elements of a data
+ * bytecode, for proper dereference of symbols attached to it.
+ * \param bc bytecode
+ * \return 0 if element size is unknown.
+ */
+ int (*elem_size) (yasm_bytecode *bc);
+
+ /** Calculates the minimum size of a bytecode.
+ * Called from yasm_bc_calc_len().
+ * A generic fill-in for this is yasm_bc_calc_len_common(), but as this
+ * function internal errors when called, be very careful when using it!
+ * This function should simply add to bc->len and not set it directly
+ * (it's initialized by yasm_bc_calc_len() prior to passing control to
+ * this function).
+ *
+ * \param bc bytecode
+ * \param add_span function to call to add a span
+ * \param add_span_data extra data to be passed to add_span function
+ * \return 0 if no error occurred, nonzero if there was an error
+ * recognized (and output) during execution.
+ * \note May store to bytecode updated expressions.
+ */
+ int (*calc_len) (yasm_bytecode *bc, yasm_bc_add_span_func add_span,
+ void *add_span_data);
+
+ /** Recalculates the bytecode's length based on an expanded span length.
+ * Called from yasm_bc_expand().
+ * A generic fill-in for this is yasm_bc_expand_common(), but as this
+ * function internal errors when called, if used, ensure that calc_len()
+ * never adds a span.
+ * This function should simply add to bc->len to increase the length by
+ * a delta amount.
+ * \param bc bytecode
+ * \param span span ID (as given to add_span in calc_len)
+ * \param old_val previous span value
+ * \param new_val new span value
+ * \param neg_thres negative threshold for long/short decision
+ * (returned)
+ * \param pos_thres positive threshold for long/short decision
+ * (returned)
+ * \return 0 if bc no longer dependent on this span's length, negative if
+ * there was an error recognized (and output) during execution,
+ * and positive if bc size may increase for this span further
+ * based on the new negative and positive thresholds returned.
+ * \note May store to bytecode updated expressions.
+ */
+ int (*expand) (yasm_bytecode *bc, int span, long old_val, long new_val,
+ /*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres);
+
+ /** Convert a bytecode into its byte representation.
+ * Called from yasm_bc_tobytes().
+ * A generic fill-in for this is yasm_bc_tobytes_common(), but as this
+ * function internal errors when called, be very careful when using it!
+ * \param bc bytecode
+ * \param bufp byte representation destination buffer;
+ * should be incremented as it's written to,
+ * so that on return its delta from the
+ * passed-in buf matches the bytecode length
+ * (it's okay not to do this if an error
+ * indication is returned)
+ * \param bufstart For calculating the correct offset parameter for
+ * the \a output_value calls: *bufp - bufstart.
+ * \param d data to pass to each call to
+ * output_value/output_reloc
+ * \param output_value function to call to convert values into their byte
+ * representation
+ * \param output_reloc function to call to output relocation entries
+ * for a single sym
+ * \return Nonzero on error, 0 on success.
+ * \note May result in non-reversible changes to the bytecode, but it's
+ * preferable if calling this function twice would result in the
+ * same output.
+ */
+ int (*tobytes) (yasm_bytecode *bc, unsigned char **bufp,
+ unsigned char *bufstart, void *d,
+ yasm_output_value_func output_value,
+ /*@null@*/ yasm_output_reloc_func output_reloc);
+
+ /** Special bytecode classifications. Most bytecode types should use
+ * #YASM_BC_SPECIAL_NONE. Others cause special handling to kick in
+ * in various parts of yasm.
+ */
+ enum yasm_bytecode_special_type {
+ YASM_BC_SPECIAL_NONE = 0,
+
+ /** Bytecode reserves space instead of outputting data. */
+ YASM_BC_SPECIAL_RESERVE,
+
+ /** Adjusts offset instead of calculating len. */
+ YASM_BC_SPECIAL_OFFSET,
+
+ /** Instruction bytecode. */
+ YASM_BC_SPECIAL_INSN
+ } special;
+} yasm_bytecode_callback;
+
+/** A bytecode. */
+struct yasm_bytecode {
+ /** Bytecodes are stored as a singly linked list, with tail insertion.
+ * \see section.h (#yasm_section).
+ */
+ /*@reldef@*/ STAILQ_ENTRY(yasm_bytecode) link;
+
+ /** The bytecode callback structure for this bytecode. May be NULL
+ * during partial initialization.
+ */
+ /*@null@*/ const yasm_bytecode_callback *callback;
+
+ /** Pointer to section containing bytecode; NULL if not part of a
+ * section.
+ */
+ /*@dependent@*/ /*@null@*/ yasm_section *section;
+
+ /** Number of times bytecode is repeated.
+ * NULL=1 (to save space in the common case).
+ */
+ /*@only@*/ /*@null@*/ yasm_expr *multiple;
+
+ /** Total length of entire bytecode (not including multiple copies). */
+ unsigned long len;
+
+ /** Number of copies, integer version. */
+ long mult_int;
+
+ /** Line number where bytecode was defined. */
+ unsigned long line;
+
+ /** Offset of bytecode from beginning of its section.
+ * 0-based, ~0UL (e.g. all 1 bits) if unknown.
+ */
+ unsigned long offset;
+
+ /** Unique integer index of bytecode. Used during optimization. */
+ unsigned long bc_index;
+
+ /** NULL-terminated array of labels that point to this bytecode (as the
+ * bytecode previous to the label). NULL if no labels point here.
+ */
+ /*@null@*/ yasm_symrec **symrecs;
+
+ /** Implementation-specific data (type identified by callback). */
+ void *contents;
+};
+
+/** Create a bytecode of any specified type.
+ * \param callback bytecode callback functions, if NULL, creates empty
+ * bytecode (may not be resolved or output)
+ * \param contents type-specific data
+ * \param line virtual line (from yasm_linemap)
+ * \return Newly allocated bytecode of the specified type.
+ */
+YASM_LIB_DECL
+/*@only@*/ yasm_bytecode *yasm_bc_create_common
+ (/*@null@*/ const yasm_bytecode_callback *callback,
+ /*@only@*/ /*@null@*/ void *contents, unsigned long line);
+
+/** Transform a bytecode of any type into a different type.
+ * \param bc bytecode to transform
+ * \param callback new bytecode callback function
+ * \param contents new type-specific data
+ */
+YASM_LIB_DECL
+void yasm_bc_transform(yasm_bytecode *bc,
+ const yasm_bytecode_callback *callback,
+ void *contents);
+
+/** Common bytecode callback finalize function, for where no finalization
+ * is ever required for this type of bytecode.
+ */
+YASM_LIB_DECL
+void yasm_bc_finalize_common(yasm_bytecode *bc, yasm_bytecode *prev_bc);
+
+/** Common bytecode callback calc_len function, for where the bytecode has
+ * no calculatable length. Causes an internal error if called.
+ */
+YASM_LIB_DECL
+int yasm_bc_calc_len_common(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
+ void *add_span_data);
+
+/** Common bytecode callback expand function, for where the bytecode is
+ * always short (calc_len never calls add_span). Causes an internal
+ * error if called.
+ */
+YASM_LIB_DECL
+int yasm_bc_expand_common
+ (yasm_bytecode *bc, int span, long old_val, long new_val,
+ /*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres);
+
+/** Common bytecode callback tobytes function, for where the bytecode
+ * cannot be converted to bytes. Causes an internal error if called.
+ */
+YASM_LIB_DECL
+int yasm_bc_tobytes_common
+ (yasm_bytecode *bc, unsigned char **bufp, unsigned char *bufstart, void *d,
+ yasm_output_value_func output_value,
+ /*@null@*/ yasm_output_reloc_func output_reloc);
+
+/** Get the next bytecode in a linked list of bytecodes.
+ * \param bc bytecode
+ * \return Next bytecode.
+ */
+#define yasm_bc__next(bc) STAILQ_NEXT(bc, link)
+
+/** Set multiple field of a bytecode.
+ * A bytecode can be repeated a number of times when output. This function
+ * sets that multiple.
+ * \param bc bytecode
+ * \param e multiple (kept, do not free)
+ */
+YASM_LIB_DECL
+void yasm_bc_set_multiple(yasm_bytecode *bc, /*@keep@*/ yasm_expr *e);
+
+/** Create a bytecode containing data value(s).
+ * \param datahead list of data values (kept, do not free)
+ * \param size storage size (in bytes) for each data value
+ * \param append_zero append a single zero byte after each data value
+ * (if non-zero)
+ * \param arch architecture (optional); if provided, data items
+ * are directly simplified to bytes if possible
+ * \param line virtual line (from yasm_linemap)
+ * \return Newly allocated bytecode.
+ */
+YASM_LIB_DECL
+/*@only@*/ yasm_bytecode *yasm_bc_create_data
+ (yasm_datavalhead *datahead, unsigned int size, int append_zero,
+ /*@null@*/ yasm_arch *arch, unsigned long line);
+
+/** Create a bytecode containing LEB128-encoded data value(s).
+ * \param datahead list of data values (kept, do not free)
+ * \param sign signedness (1=signed, 0=unsigned) of each data value
+ * \param line virtual line (from yasm_linemap)
+ * \return Newly allocated bytecode.
+ */
+YASM_LIB_DECL
+/*@only@*/ yasm_bytecode *yasm_bc_create_leb128
+ (yasm_datavalhead *datahead, int sign, unsigned long line);
+
+/** Create a bytecode reserving space.
+ * \param numitems number of reserve "items" (kept, do not free)
+ * \param itemsize reserved size (in bytes) for each item
+ * \param line virtual line (from yasm_linemap)
+ * \return Newly allocated bytecode.
+ */
+YASM_LIB_DECL
+/*@only@*/ yasm_bytecode *yasm_bc_create_reserve
+ (/*@only@*/ yasm_expr *numitems, unsigned int itemsize,
+ unsigned long line);
+
+/** Get the number of items and itemsize for a reserve bytecode. If bc
+ * is not a reserve bytecode, returns NULL.
+ * \param bc bytecode
+ * \param itemsize reserved size (in bytes) for each item (returned)
+ * \return NULL if bc is not a reserve bytecode, otherwise an expression
+ * for the number of items to reserve.
+ */
+YASM_LIB_DECL
+/*@null@*/ const yasm_expr *yasm_bc_reserve_numitems
+ (yasm_bytecode *bc, /*@out@*/ unsigned int *itemsize);
+
+/** Create a bytecode that includes a binary file verbatim.
+ * \param filename path to binary file (kept, do not free)
+ * \param start starting location in file (in bytes) to read data from
+ * (kept, do not free); may be NULL to indicate 0
+ * \param maxlen maximum number of bytes to read from the file (kept, do
+ * do not free); may be NULL to indicate no maximum
+ * \param linemap line mapping repository
+ * \param line virtual line (from yasm_linemap) for the bytecode
+ * \return Newly allocated bytecode.
+ */
+YASM_LIB_DECL
+/*@only@*/ yasm_bytecode *yasm_bc_create_incbin
+ (/*@only@*/ char *filename, /*@only@*/ /*@null@*/ yasm_expr *start,
+ /*@only@*/ /*@null@*/ yasm_expr *maxlen, yasm_linemap *linemap,
+ unsigned long line);
+
+/** Create a bytecode that aligns the following bytecode to a boundary.
+ * \param boundary byte alignment (must be a power of two)
+ * \param fill fill data (if NULL, code_fill or 0 is used)
+ * \param maxskip maximum number of bytes to skip
+ * \param code_fill code fill data (if NULL, 0 is used)
+ * \param line virtual line (from yasm_linemap)
+ * \return Newly allocated bytecode.
+ * \note The precedence on generated fill is as follows:
+ * - from fill parameter (if not NULL)
+ * - from code_fill parameter (if not NULL)
+ * - 0
+ */
+YASM_LIB_DECL
+/*@only@*/ yasm_bytecode *yasm_bc_create_align
+ (/*@keep@*/ yasm_expr *boundary, /*@keep@*/ /*@null@*/ yasm_expr *fill,
+ /*@keep@*/ /*@null@*/ yasm_expr *maxskip,
+ /*@null@*/ const unsigned char **code_fill, unsigned long line);
+
+/** Create a bytecode that puts the following bytecode at a fixed section
+ * offset.
+ * \param start section offset of following bytecode
+ * \param fill fill value
+ * \param line virtual line (from yasm_linemap)
+ * \return Newly allocated bytecode.
+ */
+YASM_LIB_DECL
+/*@only@*/ yasm_bytecode *yasm_bc_create_org
+ (unsigned long start, unsigned long fill, unsigned long line);
+
+/** Get the section that contains a particular bytecode.
+ * \param bc bytecode
+ * \return Section containing bc (can be NULL if bytecode is not part of a
+ * section).
+ */
+YASM_LIB_DECL
+/*@dependent@*/ /*@null@*/ yasm_section *yasm_bc_get_section
+ (yasm_bytecode *bc);
+
+/** Add to the list of symrecs that reference a bytecode. For symrec use
+ * only.
+ * \param bc bytecode
+ * \param sym symbol
+ */
+YASM_LIB_DECL
+void yasm_bc__add_symrec(yasm_bytecode *bc, /*@dependent@*/ yasm_symrec *sym);
+
+/** Delete (free allocated memory for) a bytecode.
+ * \param bc bytecode (only pointer to it); may be NULL
+ */
+YASM_LIB_DECL
+void yasm_bc_destroy(/*@only@*/ /*@null@*/ yasm_bytecode *bc);
+
+/** Print a bytecode. For debugging purposes.
+ * \param f file
+ * \param indent_level indentation level
+ * \param bc bytecode
+ */
+YASM_LIB_DECL
+void yasm_bc_print(const yasm_bytecode *bc, FILE *f, int indent_level);
+
+/** Finalize a bytecode after parsing.
+ * \param bc bytecode
+ * \param prev_bc bytecode directly preceding bc in a list of bytecodes
+ */
+YASM_LIB_DECL
+void yasm_bc_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc);
+
+/** Determine the distance between the starting offsets of two bytecodes.
+ * \param precbc1 preceding bytecode to the first bytecode
+ * \param precbc2 preceding bytecode to the second bytecode
+ * \return Distance in bytes between the two bytecodes (bc2-bc1), or NULL if
+ * the distance was indeterminate.
+ * \warning Only valid /after/ optimization.
+ */
+YASM_LIB_DECL
+/*@null@*/ /*@only@*/ yasm_intnum *yasm_calc_bc_dist
+ (yasm_bytecode *precbc1, yasm_bytecode *precbc2);
+
+/** Get the offset of the next bytecode (the next bytecode doesn't have to
+ * actually exist).
+ * \param precbc preceding bytecode
+ * \return Offset of the next bytecode in bytes.
+ * \warning Only valid /after/ optimization.
+ */
+YASM_LIB_DECL
+unsigned long yasm_bc_next_offset(yasm_bytecode *precbc);
+
+/** Return elemens size of a data bytecode.
+ * Returns the size of each elements of a data bytecode, for proper dereference
+ * of symbols attached to it.
+ * \param bc bytecode
+ * \return 0 if element size is unknown
+ */
+YASM_LIB_DECL
+int yasm_bc_elem_size(yasm_bytecode *bc);
+
+/** Resolve EQUs in a bytecode and calculate its minimum size.
+ * Generates dependent bytecode spans for cases where, if the length spanned
+ * increases, it could cause the bytecode size to increase.
+ * Any bytecode multiple is NOT included in the length or spans generation;
+ * this must be handled at a higher level.
+ * \param bc bytecode
+ * \param add_span function to call to add a span
+ * \param add_span_data extra data to be passed to add_span function
+ * \return 0 if no error occurred, nonzero if there was an error recognized
+ * (and output) during execution.
+ * \note May store to bytecode updated expressions and the short length.
+ */
+YASM_LIB_DECL
+int yasm_bc_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
+ void *add_span_data);
+
+/** Recalculate a bytecode's length based on an expanded span length.
+ * \param bc bytecode
+ * \param span span ID (as given to yasm_bc_add_span_func in
+ * yasm_bc_calc_len)
+ * \param old_val previous span value
+ * \param new_val new span value
+ * \param neg_thres negative threshold for long/short decision (returned)
+ * \param pos_thres positive threshold for long/short decision (returned)
+ * \return 0 if bc no longer dependent on this span's length, negative if
+ * there was an error recognized (and output) during execution, and
+ * positive if bc size may increase for this span further based on the
+ * new negative and positive thresholds returned.
+ * \note May store to bytecode updated expressions and the updated length.
+ */
+YASM_LIB_DECL
+int yasm_bc_expand(yasm_bytecode *bc, int span, long old_val, long new_val,
+ /*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres);
+
+/** Convert a bytecode into its byte representation.
+ * \param bc bytecode
+ * \param buf byte representation destination buffer
+ * \param bufsize size of buf (in bytes) prior to call; size of the
+ * generated data after call
+ * \param gap if nonzero, indicates the data does not really need to
+ * exist in the object file; if nonzero, contents of buf
+ * are undefined [output]
+ * \param d data to pass to each call to output_value/output_reloc
+ * \param output_value function to call to convert values into their byte
+ * representation
+ * \param output_reloc function to call to output relocation entries
+ * for a single sym
+ * \return Newly allocated buffer that should be used instead of buf for
+ * reading the byte representation, or NULL if buf was big enough to
+ * hold the entire byte representation.
+ * \note Calling twice on the same bytecode may \em not produce the same
+ * results on the second call, as calling this function may result in
+ * non-reversible changes to the bytecode.
+ */
+YASM_LIB_DECL
+/*@null@*/ /*@only@*/ unsigned char *yasm_bc_tobytes
+ (yasm_bytecode *bc, unsigned char *buf, unsigned long *bufsize,
+ /*@out@*/ int *gap, void *d, yasm_output_value_func output_value,
+ /*@null@*/ yasm_output_reloc_func output_reloc)
+ /*@sets *buf@*/;
+
+/** Get the bytecode multiple value as an integer.
+ * \param bc bytecode
+ * \param multiple multiple value (output)
+ * \param calc_bc_dist nonzero if distances between bytecodes should be
+ * calculated, 0 if error should be returned in this case
+ * \return 1 on error (set with yasm_error_set), 0 on success.
+ */
+YASM_LIB_DECL
+int yasm_bc_get_multiple(yasm_bytecode *bc, /*@out@*/ long *multiple,
+ int calc_bc_dist);
+
+/** Get the bytecode multiple value as an expression.
+ * \param bc bytecode
+ * \return Bytecode multiple, NULL if =1.
+ */
+YASM_LIB_DECL
+const yasm_expr *yasm_bc_get_multiple_expr(const yasm_bytecode *bc);
+
+/** Get a #yasm_insn structure from an instruction bytecode (if possible).
+ * \param bc bytecode
+ * \return Instruction details if bytecode is an instruction bytecode,
+ * otherwise NULL.
+ */
+YASM_LIB_DECL
+/*@dependent@*/ /*@null@*/ yasm_insn *yasm_bc_get_insn(yasm_bytecode *bc);
+
+/** Create a new data value from an expression.
+ * \param expn expression
+ * \return Newly allocated data value.
+ */
+YASM_LIB_DECL
+yasm_dataval *yasm_dv_create_expr(/*@keep@*/ yasm_expr *expn);
+
+/** Create a new data value from a string.
+ * \param contents string (may contain NULs)
+ * \param len length of string
+ * \return Newly allocated data value.
+ */
+yasm_dataval *yasm_dv_create_string(/*@keep@*/ char *contents, size_t len);
+
+/** Create a new data value from raw bytes data.
+ * \param contents raw data (may contain NULs)
+ * \param len length
+ * \return Newly allocated data value.
+ */
+YASM_LIB_DECL
+yasm_dataval *yasm_dv_create_raw(/*@keep@*/ unsigned char *contents,
+ unsigned long len);
+
+/** Create a new uninitialized data value.
+ * \return Newly allocated data value.
+ */
+yasm_dataval *yasm_dv_create_reserve(void);
+
+#ifndef YASM_DOXYGEN
+#define yasm_dv_create_string(s, l) yasm_dv_create_raw((unsigned char *)(s), \
+ (unsigned long)(l))
+#endif
+
+/** Get the underlying value of a data value.
+ * \param dv data value
+ * \return Value, or null if non-value (e.g. string or raw).
+ */
+yasm_value *yasm_dv_get_value(yasm_dataval *dv);
+
+/** Set multiple field of a data value.
+ * A data value can be repeated a number of times when output. This function
+ * sets that multiple.
+ * \param dv data value
+ * \param e multiple (kept, do not free)
+ */
+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
+ */
+void yasm_dvs_initialize(yasm_datavalhead *headp);
+#ifndef YASM_DOXYGEN
+#define yasm_dvs_initialize(headp) STAILQ_INIT(headp)
+#endif
+
+/** Delete (free allocated memory for) a list of data values.
+ * \param headp list of data values
+ */
+YASM_LIB_DECL
+void yasm_dvs_delete(yasm_datavalhead *headp);
+
+/** Add data value to the end of a list of data values.
+ * \note Does not make a copy of the data value; so don't pass this function
+ * static or local variables, and discard the dv pointer after calling
+ * this function.
+ * \param headp data value list
+ * \param dv data value (may be NULL)
+ * \return If data value was actually appended (it wasn't NULL), the data
+ * value; otherwise NULL.
+ */
+YASM_LIB_DECL
+/*@null@*/ yasm_dataval *yasm_dvs_append
+ (yasm_datavalhead *headp, /*@returned@*/ /*@null@*/ yasm_dataval *dv);
+
+/** Print a data value list. For debugging purposes.
+ * \param f file
+ * \param indent_level indentation level
+ * \param headp data value list
+ */
+YASM_LIB_DECL
+void yasm_dvs_print(const yasm_datavalhead *headp, FILE *f, int indent_level);
+
+#endif
diff --git a/libyasm/compat-queue.h b/libyasm/compat-queue.h
new file mode 100644
index 0000000..da9eff4
--- /dev/null
+++ b/libyasm/compat-queue.h
@@ -0,0 +1,456 @@
+/*
+ * <sys/queue.h> implementation for systems that don't have it.
+ *
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)queue.h 8.5 (Berkeley) 8/20/94
+ * $FreeBSD: src/sys/sys/queue.h,v 1.32.2.4 2001/03/31 03:33:39 hsu Exp $
+ */
+
+#ifndef SYS_QUEUE_H
+#define SYS_QUEUE_H
+
+/*
+ * This file defines four types of data structures: singly-linked lists,
+ * singly-linked tail queues, lists and tail queues.
+ *
+ * A singly-linked list is headed by a single forward pointer. The elements
+ * are singly linked for minimum space and pointer manipulation overhead at
+ * the expense of O(n) removal for arbitrary elements. New elements can be
+ * added to the list after an existing element or at the head of the list.
+ * Elements being removed from the head of the list should use the explicit
+ * macro for this purpose for optimum efficiency. A singly-linked list may
+ * only be traversed in the forward direction. Singly-linked lists are ideal
+ * for applications with large datasets and few or no removals or for
+ * implementing a LIFO queue.
+ *
+ * A singly-linked tail queue is headed by a pair of pointers, one to the
+ * head of the list and the other to the tail of the list. The elements are
+ * singly linked for minimum space and pointer manipulation overhead at the
+ * expense of O(n) removal for arbitrary elements. New elements can be added
+ * to the list after an existing element, at the head of the list, or at the
+ * end of the list. Elements being removed from the head of the tail queue
+ * should use the explicit macro for this purpose for optimum efficiency.
+ * A singly-linked tail queue may only be traversed in the forward direction.
+ * Singly-linked tail queues are ideal for applications with large datasets
+ * and few or no removals or for implementing a FIFO queue.
+ *
+ * A list is headed by a single forward pointer (or an array of forward
+ * pointers for a hash table header). The elements are doubly linked
+ * so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before
+ * or after an existing element or at the head of the list. A list
+ * may only be traversed in the forward direction.
+ *
+ * A tail queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are doubly
+ * linked so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before or
+ * after an existing element, at the head of the list, or at the end of
+ * the list. A tail queue may be traversed in either direction.
+ *
+ * For details on the use of these macros, see the queue(3) manual page.
+ *
+ *
+ * SLIST LIST STAILQ TAILQ
+ * _HEAD + + + +
+ * _HEAD_INITIALIZER + + + +
+ * _ENTRY + + + +
+ * _INIT + + + +
+ * _EMPTY + + + +
+ * _FIRST + + + +
+ * _NEXT + + + +
+ * _PREV - - - +
+ * _LAST - - + +
+ * _FOREACH + + + +
+ * _FOREACH_SAFE + + + +
+ * _FOREACH_REVERSE - - - +
+ * _FOREACH_REVERSE_SAFE - - - +
+ * _INSERT_HEAD + + + +
+ * _INSERT_BEFORE - + - +
+ * _INSERT_AFTER + + + +
+ * _INSERT_TAIL - - + +
+ * _CONCAT - - + +
+ * _REMOVE_HEAD + - + -
+ * _REMOVE + + + +
+ *
+ */
+
+/*
+ * Singly-linked List declarations.
+ */
+#define SLIST_HEAD(name, type) \
+struct name { \
+ struct type *slh_first; /* first element */ \
+}
+
+#define SLIST_HEAD_INITIALIZER(head) \
+ { NULL }
+
+#define SLIST_ENTRY(type) \
+struct { \
+ struct type *sle_next; /* next element */ \
+}
+
+/*
+ * Singly-linked List functions.
+ */
+#define SLIST_EMPTY(head) ((head)->slh_first == NULL)
+
+#define SLIST_FIRST(head) ((head)->slh_first)
+
+#define SLIST_FOREACH(var, head, field) \
+ for ((var) = SLIST_FIRST((head)); \
+ (var); \
+ (var) = SLIST_NEXT((var), field))
+
+#define SLIST_FOREACH_SAFE(var, head, field, tvar) \
+ for ((var) = SLIST_FIRST((head)); \
+ (var) && ((tvar) = SLIST_NEXT((var), field), 1); \
+ (var) = (tvar))
+
+#define SLIST_FOREACH_PREVPTR(var, varp, head, field) \
+ for ((varp) = &SLIST_FIRST((head)); \
+ ((var) = *(varp)) != NULL; \
+ (varp) = &SLIST_NEXT((var), field))
+
+#define SLIST_INIT(head) do { \
+ SLIST_FIRST((head)) = NULL; \
+} while (0)
+
+#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \
+ SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field); \
+ SLIST_NEXT((slistelm), field) = (elm); \
+} while (0)
+
+#define SLIST_INSERT_HEAD(head, elm, field) do { \
+ SLIST_NEXT((elm), field) = SLIST_FIRST((head)); \
+ SLIST_FIRST((head)) = (elm); \
+} while (0)
+
+#define SLIST_NEXT(elm, field) ((elm)->field.sle_next)
+
+#define SLIST_REMOVE(head, elm, type, field) do { \
+ if (SLIST_FIRST((head)) == (elm)) { \
+ SLIST_REMOVE_HEAD((head), field); \
+ } \
+ else { \
+ struct type *curelm = SLIST_FIRST((head)); \
+ while (SLIST_NEXT(curelm, field) != (elm)) \
+ curelm = SLIST_NEXT(curelm, field); \
+ SLIST_NEXT(curelm, field) = \
+ SLIST_NEXT(SLIST_NEXT(curelm, field), field); \
+ } \
+} while (0)
+
+#define SLIST_REMOVE_HEAD(head, field) do { \
+ SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field); \
+} while (0)
+
+/*
+ * Singly-linked Tail queue declarations.
+ */
+#define STAILQ_HEAD(name, type) \
+struct name { \
+ struct type *stqh_first;/* first element */ \
+ struct type **stqh_last;/* addr of last next element */ \
+}
+
+#define STAILQ_HEAD_INITIALIZER(head) \
+ { NULL, &(head).stqh_first }
+
+#define STAILQ_ENTRY(type) \
+struct { \
+ struct type *stqe_next; /* next element */ \
+}
+
+/*
+ * Singly-linked Tail queue functions.
+ */
+#define STAILQ_CONCAT(head1, head2) do { \
+ if (!STAILQ_EMPTY((head2))) { \
+ *(head1)->stqh_last = (head2)->stqh_first; \
+ (head1)->stqh_last = (head2)->stqh_last; \
+ STAILQ_INIT((head2)); \
+ } \
+} while (0)
+
+#define STAILQ_EMPTY(head) ((head)->stqh_first == NULL)
+
+#define STAILQ_FIRST(head) ((head)->stqh_first)
+
+#define STAILQ_FOREACH(var, head, field) \
+ for((var) = STAILQ_FIRST((head)); \
+ (var); \
+ (var) = STAILQ_NEXT((var), field))
+
+
+#define STAILQ_FOREACH_SAFE(var, head, field, tvar) \
+ for ((var) = STAILQ_FIRST((head)); \
+ (var) && ((tvar) = STAILQ_NEXT((var), field), 1); \
+ (var) = (tvar))
+
+#define STAILQ_INIT(head) do { \
+ STAILQ_FIRST((head)) = NULL; \
+ (head)->stqh_last = &STAILQ_FIRST((head)); \
+} while (0)
+
+#define STAILQ_INSERT_AFTER(head, tqelm, elm, field) do { \
+ if ((STAILQ_NEXT((elm), field) = STAILQ_NEXT((tqelm), field)) == NULL)\
+ (head)->stqh_last = &STAILQ_NEXT((elm), field); \
+ STAILQ_NEXT((tqelm), field) = (elm); \
+} while (0)
+
+#define STAILQ_INSERT_HEAD(head, elm, field) do { \
+ if ((STAILQ_NEXT((elm), field) = STAILQ_FIRST((head))) == NULL) \
+ (head)->stqh_last = &STAILQ_NEXT((elm), field); \
+ STAILQ_FIRST((head)) = (elm); \
+} while (0)
+
+#define STAILQ_INSERT_TAIL(head, elm, field) do { \
+ STAILQ_NEXT((elm), field) = NULL; \
+ *(head)->stqh_last = (elm); \
+ (head)->stqh_last = &STAILQ_NEXT((elm), field); \
+} while (0)
+
+#define STAILQ_LAST(head, type, field) \
+ (STAILQ_EMPTY((head)) ? \
+ NULL : \
+ ((struct type *) \
+ ((char *)((head)->stqh_last) - offsetof(struct type, field))))
+
+#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next)
+
+#define STAILQ_REMOVE(head, elm, type, field) do { \
+ if (STAILQ_FIRST((head)) == (elm)) { \
+ STAILQ_REMOVE_HEAD((head), field); \
+ } \
+ else { \
+ struct type *curelm = STAILQ_FIRST((head)); \
+ while (STAILQ_NEXT(curelm, field) != (elm)) \
+ curelm = STAILQ_NEXT(curelm, field); \
+ if ((STAILQ_NEXT(curelm, field) = \
+ STAILQ_NEXT(STAILQ_NEXT(curelm, field), field)) == NULL)\
+ (head)->stqh_last = &STAILQ_NEXT((curelm), field);\
+ } \
+} while (0)
+
+#define STAILQ_REMOVE_HEAD(head, field) do { \
+ if ((STAILQ_FIRST((head)) = \
+ STAILQ_NEXT(STAILQ_FIRST((head)), field)) == NULL) \
+ (head)->stqh_last = &STAILQ_FIRST((head)); \
+} while (0)
+
+#define STAILQ_REMOVE_HEAD_UNTIL(head, elm, field) do { \
+ if ((STAILQ_FIRST((head)) = STAILQ_NEXT((elm), field)) == NULL) \
+ (head)->stqh_last = &STAILQ_FIRST((head)); \
+} while (0)
+
+/*
+ * List declarations.
+ */
+#define LIST_HEAD(name, type) \
+struct name { \
+ struct type *lh_first; /* first element */ \
+}
+
+#define LIST_HEAD_INITIALIZER(head) \
+ { NULL }
+
+#define LIST_ENTRY(type) \
+struct { \
+ struct type *le_next; /* next element */ \
+ struct type **le_prev; /* address of previous next element */ \
+}
+
+/*
+ * List functions.
+ */
+
+#define LIST_EMPTY(head) ((head)->lh_first == NULL)
+
+#define LIST_FIRST(head) ((head)->lh_first)
+
+#define LIST_FOREACH(var, head, field) \
+ for ((var) = LIST_FIRST((head)); \
+ (var); \
+ (var) = LIST_NEXT((var), field))
+
+#define LIST_FOREACH_SAFE(var, head, field, tvar) \
+ for ((var) = LIST_FIRST((head)); \
+ (var) && ((tvar) = LIST_NEXT((var), field), 1); \
+ (var) = (tvar))
+
+#define LIST_INIT(head) do { \
+ LIST_FIRST((head)) = NULL; \
+} while (0)
+
+#define LIST_INSERT_AFTER(listelm, elm, field) do { \
+ if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) != NULL)\
+ LIST_NEXT((listelm), field)->field.le_prev = \
+ &LIST_NEXT((elm), field); \
+ LIST_NEXT((listelm), field) = (elm); \
+ (elm)->field.le_prev = &LIST_NEXT((listelm), field); \
+} while (0)
+
+#define LIST_INSERT_BEFORE(listelm, elm, field) do { \
+ (elm)->field.le_prev = (listelm)->field.le_prev; \
+ LIST_NEXT((elm), field) = (listelm); \
+ *(listelm)->field.le_prev = (elm); \
+ (listelm)->field.le_prev = &LIST_NEXT((elm), field); \
+} while (0)
+
+#define LIST_INSERT_HEAD(head, elm, field) do { \
+ if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL) \
+ LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field);\
+ LIST_FIRST((head)) = (elm); \
+ (elm)->field.le_prev = &LIST_FIRST((head)); \
+} while (0)
+
+#define LIST_NEXT(elm, field) ((elm)->field.le_next)
+
+#define LIST_REMOVE(elm, field) do { \
+ if (LIST_NEXT((elm), field) != NULL) \
+ LIST_NEXT((elm), field)->field.le_prev = \
+ (elm)->field.le_prev; \
+ *(elm)->field.le_prev = LIST_NEXT((elm), field); \
+} while (0)
+
+/*
+ * Tail queue declarations.
+ */
+#define TAILQ_HEAD(name, type) \
+struct name { \
+ struct type *tqh_first; /* first element */ \
+ struct type **tqh_last; /* addr of last next element */ \
+}
+
+#define TAILQ_HEAD_INITIALIZER(head) \
+ { NULL, &(head).tqh_first }
+
+#define TAILQ_ENTRY(type) \
+struct { \
+ struct type *tqe_next; /* next element */ \
+ struct type **tqe_prev; /* address of previous next element */ \
+}
+
+/*
+ * Tail queue functions.
+ */
+#define TAILQ_CONCAT(head1, head2, field) do { \
+ if (!TAILQ_EMPTY(head2)) { \
+ *(head1)->tqh_last = (head2)->tqh_first; \
+ (head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \
+ (head1)->tqh_last = (head2)->tqh_last; \
+ TAILQ_INIT((head2)); \
+ } \
+} while (0)
+
+#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL)
+
+#define TAILQ_FIRST(head) ((head)->tqh_first)
+
+#define TAILQ_FOREACH(var, head, field) \
+ for ((var) = TAILQ_FIRST((head)); \
+ (var); \
+ (var) = TAILQ_NEXT((var), field))
+
+#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \
+ for ((var) = TAILQ_FIRST((head)); \
+ (var) && ((tvar) = TAILQ_NEXT((var), field), 1); \
+ (var) = (tvar))
+
+#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \
+ for ((var) = TAILQ_LAST((head), headname); \
+ (var); \
+ (var) = TAILQ_PREV((var), headname, field))
+
+#define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \
+ for ((var) = TAILQ_LAST((head), headname); \
+ (var) && ((tvar) = TAILQ_PREV((var), headname, field), 1); \
+ (var) = (tvar))
+
+#define TAILQ_INIT(head) do { \
+ TAILQ_FIRST((head)) = NULL; \
+ (head)->tqh_last = &TAILQ_FIRST((head)); \
+} while (0)
+
+#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
+ if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) != NULL)\
+ TAILQ_NEXT((elm), field)->field.tqe_prev = \
+ &TAILQ_NEXT((elm), field); \
+ else { \
+ (head)->tqh_last = &TAILQ_NEXT((elm), field); \
+ } \
+ TAILQ_NEXT((listelm), field) = (elm); \
+ (elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field); \
+} while (0)
+
+#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
+ (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
+ TAILQ_NEXT((elm), field) = (listelm); \
+ *(listelm)->field.tqe_prev = (elm); \
+ (listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field); \
+} while (0)
+
+#define TAILQ_INSERT_HEAD(head, elm, field) do { \
+ if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL) \
+ TAILQ_FIRST((head))->field.tqe_prev = \
+ &TAILQ_NEXT((elm), field); \
+ else \
+ (head)->tqh_last = &TAILQ_NEXT((elm), field); \
+ TAILQ_FIRST((head)) = (elm); \
+ (elm)->field.tqe_prev = &TAILQ_FIRST((head)); \
+} while (0)
+
+#define TAILQ_INSERT_TAIL(head, elm, field) do { \
+ TAILQ_NEXT((elm), field) = NULL; \
+ (elm)->field.tqe_prev = (head)->tqh_last; \
+ *(head)->tqh_last = (elm); \
+ (head)->tqh_last = &TAILQ_NEXT((elm), field); \
+} while (0)
+
+#define TAILQ_LAST(head, headname) \
+ (*(((struct headname *)((head)->tqh_last))->tqh_last))
+
+#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
+
+#define TAILQ_PREV(elm, headname, field) \
+ (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
+
+#define TAILQ_REMOVE(head, elm, field) do { \
+ if ((TAILQ_NEXT((elm), field)) != NULL) \
+ TAILQ_NEXT((elm), field)->field.tqe_prev = \
+ (elm)->field.tqe_prev; \
+ else { \
+ (head)->tqh_last = (elm)->field.tqe_prev; \
+ } \
+ *(elm)->field.tqe_prev = TAILQ_NEXT((elm), field); \
+} while (0)
+
+#endif /* !SYS_QUEUE_H */
diff --git a/libyasm/coretype.h b/libyasm/coretype.h
new file mode 100644
index 0000000..624e3c4
--- /dev/null
+++ b/libyasm/coretype.h
@@ -0,0 +1,393 @@
+/**
+ * \file libyasm/coretype.h
+ * \brief YASM core types and utility functions.
+ *
+ * \license
+ * Copyright (C) 2001-2007 Peter Johnson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * \endlicense
+ */
+#ifndef YASM_CORETYPE_H
+#define YASM_CORETYPE_H
+
+#ifndef YASM_LIB_DECL
+#define YASM_LIB_DECL
+#endif
+
+/** Architecture instance (mostly opaque type). \see arch.h for details. */
+typedef struct yasm_arch yasm_arch;
+/** Preprocessor interface. \see preproc.h for details. */
+typedef struct yasm_preproc yasm_preproc;
+/** Parser instance (mostly opaque type). \see parser.h for details. */
+typedef struct yasm_parser yasm_parser;
+/** Object format interface. \see objfmt.h for details. */
+typedef struct yasm_objfmt yasm_objfmt;
+/** Debug format interface. \see dbgfmt.h for details. */
+typedef struct yasm_dbgfmt yasm_dbgfmt;
+/** List format interface. \see listfmt.h for details. */
+typedef struct yasm_listfmt yasm_listfmt;
+
+/** Object format module interface. \see objfmt.h for details. */
+typedef struct yasm_objfmt_module yasm_objfmt_module;
+/** Debug format module interface. \see dbgfmt.h for details. */
+typedef struct yasm_dbgfmt_module yasm_dbgfmt_module;
+
+/** Standard macro structure for modules that allows association of a set of
+ * standard macros with a parser/preprocessor combination.
+ * A NULL-terminated array of these structures is used in a number of module
+ * interfaces.
+ */
+typedef struct yasm_stdmac {
+ const char *parser; /**< Parser keyword */
+ const char *preproc; /**< Preprocessor keyword */
+
+ /** NULL-terminated array of standard macros. May be NULL if no standard
+ * macros should be added for this preprocessor.
+ */
+ const char **macros;
+} yasm_stdmac;
+
+/** YASM associated data callback structure. Many data structures can have
+ * arbitrary data associated with them.
+ */
+typedef struct yasm_assoc_data_callback {
+ /** Free memory allocated for associated data.
+ * \param data associated data
+ */
+ void (*destroy) (/*@only@*/ void *data);
+
+ /** Print a description of allocated data. For debugging purposes.
+ * \param data associated data
+ * \param f output file
+ * \param indent_level indentation level
+ */
+ void (*print) (void *data, FILE *f, int indent_level);
+} yasm_assoc_data_callback;
+
+/** Set of collected error/warnings (opaque type).
+ * \see errwarn.h for details.
+ */
+typedef struct yasm_errwarns yasm_errwarns;
+
+/** Bytecode. \see bytecode.h for details and related functions. */
+typedef struct yasm_bytecode yasm_bytecode;
+
+/** Object. \see section.h for details and related functions. */
+typedef struct yasm_object yasm_object;
+
+/** Section (opaque type). \see section.h for related functions. */
+typedef struct yasm_section yasm_section;
+
+/** Symbol table (opaque type). \see symrec.h for related functions. */
+typedef struct yasm_symtab yasm_symtab;
+
+/** Symbol record (opaque type). \see symrec.h for related functions. */
+typedef struct yasm_symrec yasm_symrec;
+
+/** Expression. \see expr.h for details and related functions. */
+typedef struct yasm_expr yasm_expr;
+/** Integer value (opaque type). \see intnum.h for related functions. */
+typedef struct yasm_intnum yasm_intnum;
+/** Floating point value (opaque type).
+ * \see floatnum.h for related functions.
+ */
+typedef struct yasm_floatnum yasm_floatnum;
+
+/** A value. May be absolute or relative. Outside the parser, yasm_expr
+ * should only be used for absolute exprs. Anything that could contain
+ * a relocatable value should use this structure instead.
+ * \see value.h for related functions.
+ */
+typedef struct yasm_value {
+ /** The absolute portion of the value. May contain *differences* between
+ * symrecs but not standalone symrecs. May be NULL if there is no
+ * absolute portion (e.g. the absolute portion is 0).
+ */
+ /*@null@*/ /*@only@*/ yasm_expr *abs;
+
+ /** The relative portion of the value. This is the portion that may
+ * need to generate a relocation. May be NULL if no relative portion.
+ */
+ /*@null@*/ /*@dependent@*/ yasm_symrec *rel;
+
+ /** What the relative portion is in reference to. NULL if the default. */
+ /*@null@*/ /*@dependent@*/ yasm_symrec *wrt;
+
+ /** If the segment of the relative portion should be used, not the
+ * relative portion itself. Boolean.
+ */
+ unsigned int seg_of : 1;
+
+ /** If the relative portion of the value should be shifted right
+ * (supported only by a few object formats). If just the absolute portion
+ * should be shifted, that must be in the abs expr, not here!
+ */
+ unsigned int rshift : 7;
+
+ /** Indicates the relative portion of the value should be relocated
+ * relative to the current assembly position rather than relative to the
+ * section start. "Current assembly position" here refers to the starting
+ * address of the bytecode containing this value. Boolean.
+ */
+ unsigned int curpos_rel : 1;
+
+ /** Indicates that curpos_rel was set due to IP-relative relocation;
+ * in some objfmt/arch combinations (e.g. win64/x86-amd64) this info
+ * is needed to generate special relocations.
+ */
+ unsigned int ip_rel : 1;
+
+ /** Indicates the value is a jump target address (rather than a simple
+ * data address). In some objfmt/arch combinations (e.g. macho/amd64)
+ * this info is needed to generate special relocations.
+ */
+ unsigned int jump_target : 1;
+
+ /** Indicates the relative portion of the value should be relocated
+ * relative to its own section start rather than relative to the
+ * section start of the bytecode containing this value. E.g. the value
+ * resulting from the relative portion should be the offset from its
+ * section start. Boolean.
+ */
+ unsigned int section_rel : 1;
+
+ /** Indicates overflow warnings have been disabled for this value. */
+ unsigned int no_warn : 1;
+
+ /** Sign of the value. Nonzero if the final value should be treated as
+ * signed, 0 if it should be treated as signed.
+ */
+ unsigned int sign : 1;
+
+ /** Size of the value, in bits. */
+ unsigned int size : 8;
+} yasm_value;
+
+/** Maximum value of #yasm_value.rshift */
+#define YASM_VALUE_RSHIFT_MAX 127
+
+/** Line number mapping repository (opaque type). \see linemap.h for related
+ * functions.
+ */
+typedef struct yasm_linemap yasm_linemap;
+
+/** Value/parameter pair (opaque type).
+ * \see valparam.h for related functions.
+ */
+typedef struct yasm_valparam yasm_valparam;
+/** List of value/parameters (opaque type).
+ * \see valparam.h for related functions.
+ */
+typedef struct yasm_valparamhead yasm_valparamhead;
+/** Directive list entry.
+ * \see valparam.h for details and related functions.
+ */
+typedef struct yasm_directive yasm_directive;
+
+/** An effective address.
+ * \see insn.h for related functions.
+ */
+typedef struct yasm_effaddr yasm_effaddr;
+
+/** An instruction.
+ * \see insn.h for related functions.
+ */
+typedef struct yasm_insn yasm_insn;
+
+/** Expression operators usable in #yasm_expr expressions. */
+typedef enum yasm_expr_op {
+ YASM_EXPR_IDENT, /**< No operation, just a value. */
+ YASM_EXPR_ADD, /**< Arithmetic addition (+). */
+ YASM_EXPR_SUB, /**< Arithmetic subtraction (-). */
+ YASM_EXPR_MUL, /**< Arithmetic multiplication (*). */
+ YASM_EXPR_DIV, /**< Arithmetic unsigned division. */
+ YASM_EXPR_SIGNDIV, /**< Arithmetic signed division. */
+ YASM_EXPR_MOD, /**< Arithmetic unsigned modulus. */
+ YASM_EXPR_SIGNMOD, /**< Arithmetic signed modulus. */
+ YASM_EXPR_NEG, /**< Arithmetic negation (-). */
+ YASM_EXPR_NOT, /**< Bitwise negation. */
+ YASM_EXPR_OR, /**< Bitwise OR. */
+ YASM_EXPR_AND, /**< Bitwise AND. */
+ YASM_EXPR_XOR, /**< Bitwise XOR. */
+ YASM_EXPR_XNOR, /**< Bitwise XNOR. */
+ YASM_EXPR_NOR, /**< Bitwise NOR. */
+ YASM_EXPR_SHL, /**< Shift left (logical). */
+ YASM_EXPR_SHR, /**< Shift right (logical). */
+ YASM_EXPR_LOR, /**< Logical OR. */
+ YASM_EXPR_LAND, /**< Logical AND. */
+ YASM_EXPR_LNOT, /**< Logical negation. */
+ YASM_EXPR_LXOR, /**< Logical XOR. */
+ YASM_EXPR_LXNOR, /**< Logical XNOR. */
+ YASM_EXPR_LNOR, /**< Logical NOR. */
+ YASM_EXPR_LT, /**< Less than comparison. */
+ YASM_EXPR_GT, /**< Greater than comparison. */
+ YASM_EXPR_EQ, /**< Equality comparison. */
+ YASM_EXPR_LE, /**< Less than or equal to comparison. */
+ YASM_EXPR_GE, /**< Greater than or equal to comparison. */
+ YASM_EXPR_NE, /**< Not equal comparison. */
+ YASM_EXPR_NONNUM, /**< Start of non-numeric operations (not an op). */
+ YASM_EXPR_SEG, /**< SEG operator (gets segment portion of address). */
+ YASM_EXPR_WRT, /**< WRT operator (gets offset of address relative to
+ * some other segment). */
+ YASM_EXPR_SEGOFF /**< The ':' in segment:offset. */
+} yasm_expr_op;
+
+/** Convert yasm_value to its byte representation. Usually implemented by
+ * object formats to keep track of relocations and verify legal expressions.
+ * Must put the value into the least significant bits of the destination,
+ * unless shifted into more significant bits by the shift parameter. The
+ * destination bits must be cleared before being set.
+ * \param value value
+ * \param buf buffer for byte representation
+ * \param destsize destination size (in bytes)
+ * \param offset offset (in bytes) of the expr contents from the start
+ * of the bytecode (needed for relative)
+ * \param bc current bytecode (usually passed into higher-level
+ * calling function)
+ * \param warn enables standard warnings: zero for none;
+ * nonzero for overflow/underflow floating point warnings
+ * \param d objfmt-specific data (passed into higher-level calling
+ * function)
+ * \return Nonzero if an error occurred, 0 otherwise.
+ */
+typedef int (*yasm_output_value_func)
+ (yasm_value *value, /*@out@*/ unsigned char *buf, unsigned int destsize,
+ unsigned long offset, yasm_bytecode *bc, int warn, /*@null@*/ void *d);
+
+/** Convert a symbol reference to its byte representation. Usually implemented
+ * by object formats and debug formats to keep track of relocations generated
+ * by themselves.
+ * \param sym symbol
+ * \param bc current bytecode (usually passed into higher-level
+ * calling function)
+ * \param buf buffer for byte representation
+ * \param destsize destination size (in bytes)
+ * \param valsize size (in bits)
+ * \param warn enables standard warnings: zero for none;
+ * nonzero for overflow/underflow floating point warnings;
+ * negative for signed integer warnings,
+ * positive for unsigned integer warnings
+ * \param d objfmt-specific data (passed into higher-level calling
+ * function)
+ * \return Nonzero if an error occurred, 0 otherwise.
+ */
+typedef int (*yasm_output_reloc_func)
+ (yasm_symrec *sym, yasm_bytecode *bc, unsigned char *buf,
+ unsigned int destsize, unsigned int valsize, int warn, void *d);
+
+/** Sort an array using merge sort algorithm.
+ * \internal
+ * \param base base of array
+ * \param nmemb number of elements in array
+ * \param size size of each array element
+ * \param compar element comparison function
+ */
+YASM_LIB_DECL
+int yasm__mergesort(void *base, size_t nmemb, size_t size,
+ int (*compar)(const void *, const void *));
+
+/** Separate string by delimiters.
+ * \internal
+ * \param stringp string
+ * \param delim set of 1 or more delimiters
+ * \return First/next substring.
+ */
+YASM_LIB_DECL
+/*@null@*/ char *yasm__strsep(char **stringp, const char *delim);
+
+/** Compare two strings, ignoring case differences.
+ * \internal
+ * \param s1 string 1
+ * \param s2 string 2
+ * \return 0 if strings are equal, -1 if s1<s2, 1 if s1>s2.
+ */
+YASM_LIB_DECL
+int yasm__strcasecmp(const char *s1, const char *s2);
+
+/** Compare portion of two strings, ignoring case differences.
+ * \internal
+ * \param s1 string 1
+ * \param s2 string 2
+ * \param n maximum number of characters to compare
+ * \return 0 if strings are equal, -1 if s1<s2, 1 if s1>s2.
+ */
+YASM_LIB_DECL
+int yasm__strncasecmp(const char *s1, const char *s2, size_t n);
+
+/** strdup() implementation using yasm_xmalloc().
+ * \internal
+ * \param str string
+ * \return Newly allocated duplicate string.
+ */
+YASM_LIB_DECL
+/*@only@*/ char *yasm__xstrdup(const char *str);
+
+/** strndup() implementation using yasm_xmalloc().
+ * \internal
+ * \param str string
+ * \param max maximum number of characters to copy
+ * \return Newly allocated duplicate string.
+ */
+YASM_LIB_DECL
+/*@only@*/ char *yasm__xstrndup(const char *str, size_t max);
+
+/** Error-checking memory allocation. A default implementation is provided
+ * that calls yasm_fatal() on allocation errors.
+ * A replacement should \em never return NULL.
+ * \param size number of bytes to allocate
+ * \return Allocated memory block.
+ */
+YASM_LIB_DECL
+extern /*@only@*/ /*@out@*/ void * (*yasm_xmalloc) (size_t size);
+
+/** Error-checking memory allocation (with clear-to-0). A default
+ * implementation is provided that calls yasm_fatal() on allocation errors.
+ * A replacement should \em never return NULL.
+ * \param size number of elements to allocate
+ * \param elsize size (in bytes) of each element
+ * \return Allocated and cleared memory block.
+ */
+YASM_LIB_DECL
+extern /*@only@*/ void * (*yasm_xcalloc) (size_t nelem, size_t elsize);
+
+/** Error-checking memory reallocation. A default implementation is provided
+ * that calls yasm_fatal() on allocation errors. A replacement should
+ * \em never return NULL.
+ * \param oldmem memory block to resize
+ * \param elsize new size, in bytes
+ * \return Re-allocated memory block.
+ */
+YASM_LIB_DECL
+extern /*@only@*/ void * (*yasm_xrealloc)
+ (/*@only@*/ /*@out@*/ /*@returned@*/ /*@null@*/ void *oldmem, size_t size)
+ /*@modifies oldmem@*/;
+
+/** Error-checking memory deallocation. A default implementation is provided
+ * that calls yasm_fatal() on allocation errors.
+ * \param p memory block to free
+ */
+YASM_LIB_DECL
+extern void (*yasm_xfree) (/*@only@*/ /*@out@*/ /*@null@*/ void *p)
+ /*@modifies p@*/;
+
+#endif
diff --git a/libyasm/dbgfmt.h b/libyasm/dbgfmt.h
new file mode 100644
index 0000000..8e038bb
--- /dev/null
+++ b/libyasm/dbgfmt.h
@@ -0,0 +1,122 @@
+/**
+ * \file libyasm/dbgfmt.h
+ * \brief YASM debug format interface.
+ *
+ * \license
+ * Copyright (C) 2002-2007 Peter Johnson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * \endlicense
+ */
+#ifndef YASM_DBGFMT_H
+#define YASM_DBGFMT_H
+
+#ifndef YASM_DOXYGEN
+/** Base #yasm_dbgfmt structure. Must be present as the first element in any
+ * #yasm_dbgfmt implementation.
+ */
+typedef struct yasm_dbgfmt_base {
+ /** #yasm_dbgfmt_module implementation for this debug format. */
+ const struct yasm_dbgfmt_module *module;
+} yasm_dbgfmt_base;
+#endif
+
+/** Debug format module interface. */
+struct yasm_dbgfmt_module {
+ /** One-line description of the debug format. */
+ const char *name;
+
+ /** Keyword used to select debug format. */
+ const char *keyword;
+
+ /** NULL-terminated list of directives. NULL if none. */
+ /*@null@*/ const yasm_directive *directives;
+
+ /** Create debug format.
+ * Module-level implementation of yasm_dbgfmt_create().
+ * The filenames are provided solely for informational purposes.
+ * \param object object
+ * \return NULL if object format does not provide needed support.
+ */
+ /*@null@*/ /*@only@*/ yasm_dbgfmt * (*create) (yasm_object *object);
+
+ /** Module-level implementation of yasm_dbgfmt_destroy().
+ * Call yasm_dbgfmt_destroy() instead of calling this function.
+ */
+ void (*destroy) (/*@only@*/ yasm_dbgfmt *dbgfmt);
+
+ /** Module-level implementation of yasm_dbgfmt_generate().
+ * Call yasm_dbgfmt_generate() instead of calling this function.
+ */
+ void (*generate) (yasm_object *object, yasm_linemap *linemap,
+ yasm_errwarns *errwarns);
+};
+
+/** Get the keyword used to select a debug format.
+ * \param dbgfmt debug format
+ * \return keyword
+ */
+const char *yasm_dbgfmt_keyword(const yasm_dbgfmt *dbgfmt);
+
+/** Initialize debug output for use. Must call before any other debug
+ * format functions. The filenames are provided solely for informational
+ * purposes.
+ * \param module debug format module
+ * \param object object to generate debugging information for
+ * \return NULL if object format does not provide needed support.
+ */
+/*@null@*/ /*@only@*/ yasm_dbgfmt *yasm_dbgfmt_create
+ (const yasm_dbgfmt_module *module, yasm_object *object);
+
+/** Cleans up any allocated debug format memory.
+ * \param dbgfmt debug format
+ */
+void yasm_dbgfmt_destroy(/*@only@*/ yasm_dbgfmt *dbgfmt);
+
+/** Generate debugging information bytecodes.
+ * \param object object
+ * \param linemap virtual/physical line mapping
+ * \param errwarns error/warning set
+ * \note Errors and warnings are stored into errwarns.
+ */
+void yasm_dbgfmt_generate(yasm_object *object, yasm_linemap *linemap,
+ yasm_errwarns *errwarns);
+
+#ifndef YASM_DOXYGEN
+
+/* Inline macro implementations for dbgfmt functions */
+
+#define yasm_dbgfmt_keyword(dbgfmt) \
+ (((yasm_dbgfmt_base *)dbgfmt)->module->keyword)
+
+#define yasm_dbgfmt_create(module, object) \
+ module->create(object)
+
+#define yasm_dbgfmt_destroy(dbgfmt) \
+ ((yasm_dbgfmt_base *)dbgfmt)->module->destroy(dbgfmt)
+#define yasm_dbgfmt_generate(object, linemap, ews) \
+ ((yasm_dbgfmt_base *)((object)->dbgfmt))->module->generate \
+ (object, linemap, ews)
+
+#endif
+
+#endif
diff --git a/libyasm/errwarn.c b/libyasm/errwarn.c
new file mode 100644
index 0000000..d51a0de
--- /dev/null
+++ b/libyasm/errwarn.c
@@ -0,0 +1,529 @@
+/*
+ * Error and warning reporting and related functions.
+ *
+ * Copyright (C) 2001-2007 Peter Johnson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "util.h"
+
+#include <ctype.h>
+#include <stdarg.h>
+
+#include "coretype.h"
+
+#include "linemap.h"
+#include "errwarn.h"
+
+
+#define MSG_MAXSIZE 1024
+
+#if !defined(HAVE_TOASCII) || defined(lint)
+# define toascii(c) ((c) & 0x7F)
+#endif
+
+/* Default handlers for replacable functions */
+static /*@exits@*/ void def_internal_error_
+ (const char *file, unsigned int line, const char *message);
+static /*@exits@*/ void def_fatal(const char *message, va_list va);
+static const char *def_gettext_hook(const char *msgid);
+
+/* Storage for errwarn's "extern" functions */
+/*@exits@*/ void (*yasm_internal_error_)
+ (const char *file, unsigned int line, const char *message)
+ = def_internal_error_;
+/*@exits@*/ void (*yasm_fatal) (const char *message, va_list va) = def_fatal;
+const char * (*yasm_gettext_hook) (const char *msgid) = def_gettext_hook;
+
+/* Error indicator */
+/* yasm_eclass is not static so that yasm_error_occurred macro can access it */
+yasm_error_class yasm_eclass;
+static /*@only@*/ /*@null@*/ char *yasm_estr;
+static unsigned long yasm_exrefline;
+static /*@only@*/ /*@null@*/ char *yasm_exrefstr;
+
+/* Warning indicator */
+typedef struct warn {
+ /*@reldef@*/ STAILQ_ENTRY(warn) link;
+
+ yasm_warn_class wclass;
+ /*@owned@*/ /*@null@*/ char *wstr;
+} warn;
+static STAILQ_HEAD(warn_head, warn) yasm_warns;
+
+/* Enabled warnings. See errwarn.h for a list. */
+static unsigned long warn_class_enabled;
+
+typedef struct errwarn_data {
+ /*@reldef@*/ SLIST_ENTRY(errwarn_data) link;
+
+ enum { WE_UNKNOWN, WE_ERROR, WE_WARNING, WE_PARSERERROR } type;
+
+ unsigned long line;
+ unsigned long xrefline;
+ /*@owned@*/ char *msg;
+ /*@owned@*/ char *xrefmsg;
+} errwarn_data;
+
+struct yasm_errwarns {
+ /*@reldef@*/ SLIST_HEAD(errwarn_head, errwarn_data) errwarns;
+
+ /* Total error count */
+ unsigned int ecount;
+
+ /* Total warning count */
+ unsigned int wcount;
+
+ /* Last inserted error/warning. Used to speed up insertions. */
+ /*@null@*/ errwarn_data *previous_we;
+};
+
+/* Static buffer for use by conv_unprint(). */
+static char unprint[5];
+
+
+static const char *
+def_gettext_hook(const char *msgid)
+{
+ return msgid;
+}
+
+void
+yasm_errwarn_initialize(void)
+{
+ /* Default enabled warnings. See errwarn.h for a list. */
+ warn_class_enabled =
+ (1UL<<YASM_WARN_GENERAL) | (1UL<<YASM_WARN_UNREC_CHAR) |
+ (1UL<<YASM_WARN_PREPROC) | (0UL<<YASM_WARN_ORPHAN_LABEL) |
+ (1UL<<YASM_WARN_UNINIT_CONTENTS) | (0UL<<YASM_WARN_SIZE_OVERRIDE) |
+ (1UL<<YASM_WARN_IMPLICIT_SIZE_OVERRIDE);
+
+ yasm_eclass = YASM_ERROR_NONE;
+ yasm_estr = NULL;
+ yasm_exrefline = 0;
+ yasm_exrefstr = NULL;
+
+ STAILQ_INIT(&yasm_warns);
+}
+
+void
+yasm_errwarn_cleanup(void)
+{
+ yasm_error_clear();
+ yasm_warn_clear();
+}
+
+/* Convert a possibly unprintable character into a printable string, using
+ * standard cat(1) convention for unprintable characters.
+ */
+char *
+yasm__conv_unprint(int ch)
+{
+ int pos = 0;
+
+ if (((ch & ~0x7F) != 0) /*!isascii(ch)*/ && !isprint(ch)) {
+ unprint[pos++] = 'M';
+ unprint[pos++] = '-';
+ ch &= toascii(ch);
+ }
+ if (iscntrl(ch)) {
+ unprint[pos++] = '^';
+ unprint[pos++] = (ch == '\177') ? '?' : ch | 0100;
+ } else
+ unprint[pos++] = ch;
+ unprint[pos] = '\0';
+
+ return unprint;
+}
+
+/* Report an internal error. Essentially a fatal error with trace info.
+ * Exit immediately because it's essentially an assert() trap.
+ */
+static void
+def_internal_error_(const char *file, unsigned int line, const char *message)
+{
+ fprintf(stderr,
+ yasm_gettext_hook(N_("INTERNAL ERROR at %s, line %u: %s\n")),
+ file, line, yasm_gettext_hook(message));
+#ifdef HAVE_ABORT
+ abort();
+#else
+ exit(EXIT_FAILURE);
+#endif
+}
+
+/* Report a fatal error. These are unrecoverable (such as running out of
+ * memory), so just exit immediately.
+ */
+static void
+def_fatal(const char *fmt, va_list va)
+{
+ fprintf(stderr, "%s: ", yasm_gettext_hook(N_("FATAL")));
+ vfprintf(stderr, yasm_gettext_hook(fmt), va);
+ fputc('\n', stderr);
+ exit(EXIT_FAILURE);
+}
+
+/* Create an errwarn structure in the correct linked list location.
+ * If replace_parser_error is nonzero, overwrites the last error if its
+ * type is WE_PARSERERROR.
+ */
+static errwarn_data *
+errwarn_data_new(yasm_errwarns *errwarns, unsigned long line,
+ int replace_parser_error)
+{
+ errwarn_data *first, *next, *ins_we, *we;
+ enum { INS_NONE, INS_HEAD, INS_AFTER } action = INS_NONE;
+
+ /* Find the entry with either line=line or the last one with line<line.
+ * Start with the last entry added to speed the search.
+ */
+ ins_we = errwarns->previous_we;
+ first = SLIST_FIRST(&errwarns->errwarns);
+ if (!ins_we || !first)
+ action = INS_HEAD;
+ while (action == INS_NONE) {
+ next = SLIST_NEXT(ins_we, link);
+ if (line < ins_we->line) {
+ if (ins_we == first)
+ action = INS_HEAD;
+ else
+ ins_we = first;
+ } else if (!next)
+ action = INS_AFTER;
+ else if (line >= ins_we->line && line < next->line)
+ action = INS_AFTER;
+ else
+ ins_we = next;
+ }
+
+ if (replace_parser_error && ins_we && ins_we->type == WE_PARSERERROR) {
+ /* overwrite last error */
+ we = ins_we;
+ } else {
+ /* add a new error */
+ we = yasm_xmalloc(sizeof(errwarn_data));
+
+ we->type = WE_UNKNOWN;
+ we->line = line;
+ we->xrefline = 0;
+ we->msg = NULL;
+ we->xrefmsg = NULL;
+
+ if (action == INS_HEAD)
+ SLIST_INSERT_HEAD(&errwarns->errwarns, we, link);
+ else if (action == INS_AFTER) {
+ assert(ins_we != NULL);
+ SLIST_INSERT_AFTER(ins_we, we, link);
+ } else
+ yasm_internal_error(N_("Unexpected errwarn insert action"));
+ }
+
+ /* Remember previous err/warn */
+ errwarns->previous_we = we;
+
+ return we;
+}
+
+void
+yasm_error_clear(void)
+{
+ if (yasm_estr)
+ yasm_xfree(yasm_estr);
+ if (yasm_exrefstr)
+ yasm_xfree(yasm_exrefstr);
+ yasm_eclass = YASM_ERROR_NONE;
+ yasm_estr = NULL;
+ yasm_exrefline = 0;
+ yasm_exrefstr = NULL;
+}
+
+int
+yasm_error_matches(yasm_error_class eclass)
+{
+ if (yasm_eclass == YASM_ERROR_NONE)
+ return eclass == YASM_ERROR_NONE;
+ if (yasm_eclass == YASM_ERROR_GENERAL)
+ return eclass == YASM_ERROR_GENERAL;
+ return (yasm_eclass & eclass) == eclass;
+}
+
+void
+yasm_error_set_va(yasm_error_class eclass, const char *format, va_list va)
+{
+ if (yasm_eclass != YASM_ERROR_NONE)
+ return;
+
+ yasm_eclass = eclass;
+ yasm_estr = yasm_xmalloc(MSG_MAXSIZE+1);
+#ifdef HAVE_VSNPRINTF
+ vsnprintf(yasm_estr, MSG_MAXSIZE, yasm_gettext_hook(format), va);
+#else
+ vsprintf(yasm_estr, yasm_gettext_hook(format), va);
+#endif
+}
+
+void
+yasm_error_set(yasm_error_class eclass, const char *format, ...)
+{
+ va_list va;
+ va_start(va, format);
+ yasm_error_set_va(eclass, format, va);
+ va_end(va);
+}
+
+void
+yasm_error_set_xref_va(unsigned long xrefline, const char *format, va_list va)
+{
+ if (yasm_eclass != YASM_ERROR_NONE)
+ return;
+
+ yasm_exrefline = xrefline;
+
+ yasm_exrefstr = yasm_xmalloc(MSG_MAXSIZE+1);
+#ifdef HAVE_VSNPRINTF
+ vsnprintf(yasm_exrefstr, MSG_MAXSIZE, yasm_gettext_hook(format), va);
+#else
+ vsprintf(yasm_exrefstr, yasm_gettext_hook(format), va);
+#endif
+}
+
+void
+yasm_error_set_xref(unsigned long xrefline, const char *format, ...)
+{
+ va_list va;
+ va_start(va, format);
+ yasm_error_set_xref_va(xrefline, format, va);
+ va_end(va);
+}
+
+void
+yasm_error_fetch(yasm_error_class *eclass, char **str, unsigned long *xrefline,
+ char **xrefstr)
+{
+ *eclass = yasm_eclass;
+ *str = yasm_estr;
+ *xrefline = yasm_exrefline;
+ *xrefstr = yasm_exrefstr;
+ yasm_eclass = YASM_ERROR_NONE;
+ yasm_estr = NULL;
+ yasm_exrefline = 0;
+ yasm_exrefstr = NULL;
+}
+
+void yasm_warn_clear(void)
+{
+ /* Delete all error/warnings */
+ while (!STAILQ_EMPTY(&yasm_warns)) {
+ warn *w = STAILQ_FIRST(&yasm_warns);
+
+ if (w->wstr)
+ yasm_xfree(w->wstr);
+
+ STAILQ_REMOVE_HEAD(&yasm_warns, link);
+ yasm_xfree(w);
+ }
+}
+
+yasm_warn_class
+yasm_warn_occurred(void)
+{
+ if (STAILQ_EMPTY(&yasm_warns))
+ return YASM_WARN_NONE;
+ return STAILQ_FIRST(&yasm_warns)->wclass;
+}
+
+void
+yasm_warn_set_va(yasm_warn_class wclass, const char *format, va_list va)
+{
+ warn *w;
+
+ if (!(warn_class_enabled & (1UL<<wclass)))
+ return; /* warning is part of disabled class */
+
+ w = yasm_xmalloc(sizeof(warn));
+ w->wclass = wclass;
+ w->wstr = yasm_xmalloc(MSG_MAXSIZE+1);
+#ifdef HAVE_VSNPRINTF
+ vsnprintf(w->wstr, MSG_MAXSIZE, yasm_gettext_hook(format), va);
+#else
+ vsprintf(w->wstr, yasm_gettext_hook(format), va);
+#endif
+ STAILQ_INSERT_TAIL(&yasm_warns, w, link);
+}
+
+void
+yasm_warn_set(yasm_warn_class wclass, const char *format, ...)
+{
+ va_list va;
+ va_start(va, format);
+ yasm_warn_set_va(wclass, format, va);
+ va_end(va);
+}
+
+void
+yasm_warn_fetch(yasm_warn_class *wclass, char **str)
+{
+ warn *w = STAILQ_FIRST(&yasm_warns);
+
+ if (!w) {
+ *wclass = YASM_WARN_NONE;
+ *str = NULL;
+ return;
+ }
+
+ *wclass = w->wclass;
+ *str = w->wstr;
+
+ STAILQ_REMOVE_HEAD(&yasm_warns, link);
+ yasm_xfree(w);
+}
+
+void
+yasm_warn_enable(yasm_warn_class num)
+{
+ warn_class_enabled |= (1UL<<num);
+}
+
+void
+yasm_warn_disable(yasm_warn_class num)
+{
+ warn_class_enabled &= ~(1UL<<num);
+}
+
+void
+yasm_warn_disable_all(void)
+{
+ warn_class_enabled = 0;
+}
+
+yasm_errwarns *
+yasm_errwarns_create(void)
+{
+ yasm_errwarns *errwarns = yasm_xmalloc(sizeof(yasm_errwarns));
+ SLIST_INIT(&errwarns->errwarns);
+ errwarns->ecount = 0;
+ errwarns->wcount = 0;
+ errwarns->previous_we = NULL;
+ return errwarns;
+}
+
+void
+yasm_errwarns_destroy(yasm_errwarns *errwarns)
+{
+ errwarn_data *we;
+
+ /* Delete all error/warnings */
+ while (!SLIST_EMPTY(&errwarns->errwarns)) {
+ we = SLIST_FIRST(&errwarns->errwarns);
+ if (we->msg)
+ yasm_xfree(we->msg);
+ if (we->xrefmsg)
+ yasm_xfree(we->xrefmsg);
+
+ SLIST_REMOVE_HEAD(&errwarns->errwarns, link);
+ yasm_xfree(we);
+ }
+
+ yasm_xfree(errwarns);
+}
+
+void
+yasm_errwarn_propagate(yasm_errwarns *errwarns, unsigned long line)
+{
+ if (yasm_eclass != YASM_ERROR_NONE) {
+ errwarn_data *we = errwarn_data_new(errwarns, line, 1);
+ yasm_error_class eclass;
+
+ yasm_error_fetch(&eclass, &we->msg, &we->xrefline, &we->xrefmsg);
+ if (eclass != YASM_ERROR_GENERAL
+ && (eclass & YASM_ERROR_PARSE) == YASM_ERROR_PARSE)
+ we->type = WE_PARSERERROR;
+ else
+ we->type = WE_ERROR;
+ errwarns->ecount++;
+ }
+
+ while (!STAILQ_EMPTY(&yasm_warns)) {
+ errwarn_data *we = errwarn_data_new(errwarns, line, 0);
+ yasm_warn_class wclass;
+
+ yasm_warn_fetch(&wclass, &we->msg);
+ we->type = WE_WARNING;
+ errwarns->wcount++;
+ }
+}
+
+unsigned int
+yasm_errwarns_num_errors(yasm_errwarns *errwarns, int warning_as_error)
+{
+ if (warning_as_error)
+ return errwarns->ecount+errwarns->wcount;
+ else
+ return errwarns->ecount;
+}
+
+void
+yasm_errwarns_output_all(yasm_errwarns *errwarns, yasm_linemap *lm,
+ int warning_as_error,
+ yasm_print_error_func print_error,
+ yasm_print_warning_func print_warning)
+{
+ errwarn_data *we;
+ const char *filename, *xref_filename;
+ unsigned long line, xref_line;
+
+ /* If we're treating warnings as errors, tell the user about it. */
+ if (warning_as_error && warning_as_error != 2) {
+ print_error("", 0,
+ yasm_gettext_hook(N_("warnings being treated as errors")),
+ NULL, 0, NULL);
+ warning_as_error = 2;
+ }
+
+ /* Output error/warnings. */
+ SLIST_FOREACH(we, &errwarns->errwarns, link) {
+ /* Output error/warning */
+ yasm_linemap_lookup(lm, we->line, &filename, &line);
+ if (we->xrefline)
+ yasm_linemap_lookup(lm, we->xrefline, &xref_filename, &xref_line);
+ else {
+ xref_filename = NULL;
+ xref_line = 0;
+ }
+ if (we->type == WE_ERROR || we->type == WE_PARSERERROR)
+ print_error(filename, line, we->msg, xref_filename, xref_line,
+ we->xrefmsg);
+ else
+ print_warning(filename, line, we->msg);
+ }
+}
+
+void
+yasm__fatal(const char *message, ...)
+{
+ va_list va;
+ va_start(va, message);
+ yasm_fatal(message, va);
+ /*@notreached@*/
+ va_end(va);
+}
diff --git a/libyasm/errwarn.h b/libyasm/errwarn.h
new file mode 100644
index 0000000..ede2f28
--- /dev/null
+++ b/libyasm/errwarn.h
@@ -0,0 +1,348 @@
+/**
+ * \file libyasm/errwarn.h
+ * \brief YASM error and warning reporting interface.
+ *
+ * \license
+ * Copyright (C) 2001-2007 Peter Johnson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * \endlicense
+ */
+#ifndef YASM_ERRWARN_H
+#define YASM_ERRWARN_H
+
+#ifndef YASM_LIB_DECL
+#define YASM_LIB_DECL
+#endif
+
+/** Warning classes (that may be enabled/disabled). */
+typedef enum yasm_warn_class {
+ YASM_WARN_NONE = 0, /**< No warning */
+ YASM_WARN_GENERAL, /**< Non-specific warnings */
+ YASM_WARN_UNREC_CHAR, /**< Unrecognized characters (while tokenizing) */
+ YASM_WARN_PREPROC, /**< Preprocessor warnings */
+ YASM_WARN_ORPHAN_LABEL, /**< Label alone on a line without a colon */
+ YASM_WARN_UNINIT_CONTENTS, /**< Uninitialized space in code/data section */
+ YASM_WARN_SIZE_OVERRIDE,/**< Double size override */
+ YASM_WARN_IMPLICIT_SIZE_OVERRIDE /**< Implicit size override */
+} yasm_warn_class;
+
+/** Error classes. Bitmask-based to support limited subclassing. */
+typedef enum yasm_error_class {
+ YASM_ERROR_NONE = 0x0000, /**< No error */
+ YASM_ERROR_GENERAL = 0xFFFF, /**< Non-specific */
+ YASM_ERROR_ARITHMETIC = 0x0001, /**< Arithmetic error (general) */
+ YASM_ERROR_OVERFLOW = 0x8001, /**< Arithmetic overflow */
+ YASM_ERROR_FLOATING_POINT = 0x4001, /**< Floating point error */
+ YASM_ERROR_ZERO_DIVISION = 0x2001, /**< Divide-by-zero */
+ YASM_ERROR_ASSERTION = 0x0002, /**< Assertion error */
+ YASM_ERROR_VALUE = 0x0004, /**< Value inappropriate
+ * (e.g. not in range) */
+ YASM_ERROR_NOT_ABSOLUTE = 0x8004, /**< Absolute expression required */
+ YASM_ERROR_TOO_COMPLEX = 0x4004, /**< Expression too complex */
+ YASM_ERROR_NOT_CONSTANT = 0x2004, /**< Constant expression required */
+ YASM_ERROR_IO = 0x0008, /**< I/O error */
+ YASM_ERROR_NOT_IMPLEMENTED = 0x0010, /**< Not implemented error */
+ YASM_ERROR_TYPE = 0x0020, /**< Type error */
+ YASM_ERROR_SYNTAX = 0x0040, /**< Syntax error */
+ YASM_ERROR_PARSE = 0x8040 /**< Parser error */
+} yasm_error_class;
+
+/** Initialize any internal data structures. */
+YASM_LIB_DECL
+void yasm_errwarn_initialize(void);
+
+/** Clean up any memory allocated by yasm_errwarn_initialize() or other
+ * functions.
+ */
+YASM_LIB_DECL
+void yasm_errwarn_cleanup(void);
+
+/** Reporting point of internal errors. These are usually due to sanity
+ * check failures in the code.
+ * \warning This function must NOT return to calling code; exit or longjmp
+ * instead.
+ * \param file source file (ala __FILE__)
+ * \param line source line (ala __LINE__)
+ * \param message internal error message
+ */
+YASM_LIB_DECL
+extern /*@exits@*/ void (*yasm_internal_error_)
+ (const char *file, unsigned int line, const char *message);
+
+/** Easily-callable version of yasm_internal_error_(). Automatically uses
+ * __FILE__ and __LINE__ as the file and line.
+ * \param message internal error message
+ */
+#define yasm_internal_error(message) \
+ yasm_internal_error_(__FILE__, __LINE__, message)
+
+/** Reporting point of fatal errors.
+ * \warning This function must NOT return to calling code; exit or longjmp
+ * instead.
+ * \param message fatal error message
+ * \param va va_list argument list for message
+ */
+YASM_LIB_DECL
+extern /*@exits@*/ void (*yasm_fatal) (const char *message, va_list va);
+
+/** Reporting point of fatal errors, with variable arguments (internal only).
+ * \warning This function calls #yasm_fatal, and thus does not return to the
+ * calling code.
+ * \param message fatal error message
+ * \param ... argument list for message
+ */
+YASM_LIB_DECL
+/*@exits@*/ void yasm__fatal(const char *message, ...);
+
+/** Unconditionally clear the error indicator, freeing any associated data.
+ * Has no effect if the error indicator is not set.
+ */
+YASM_LIB_DECL
+void yasm_error_clear(void);
+
+/** Get the error indicator. YASM_ERROR_NONE is returned if no error has
+ * been set. Note that as YASM_ERROR_NONE is 0, the return value can also
+ * be treated as a boolean value.
+ * \return Current error indicator.
+ */
+yasm_error_class yasm_error_occurred(void);
+
+/** Check the error indicator against an error class. To check if any error
+ * has been set, check against the YASM_ERROR_GENERAL class. This function
+ * properly checks error subclasses.
+ * \param eclass base error class to check against
+ * \return Nonzero if error indicator is set and a subclass of eclass, 0
+ * otherwise.
+ */
+YASM_LIB_DECL
+int yasm_error_matches(yasm_error_class eclass);
+
+#ifndef YASM_DOXYGEN
+YASM_LIB_DECL
+extern yasm_error_class yasm_eclass;
+#define yasm_error_occurred() yasm_eclass
+#endif
+
+/** Set the error indicator (va_list version). Has no effect if the error
+ * indicator is already set.
+ * \param eclass error class
+ * \param format printf format string
+ * \param va argument list for format
+ */
+YASM_LIB_DECL
+void yasm_error_set_va(yasm_error_class eclass, const char *format, va_list va);
+
+/** Set the error indicator. Has no effect if the error indicator is already
+ * set.
+ * \param eclass error class
+ * \param format printf format string
+ * \param ... argument list for format
+ */
+YASM_LIB_DECL
+void yasm_error_set(yasm_error_class eclass, const char *format, ...)
+ /*@printflike@*/;
+
+/** Set a cross-reference for a new error (va_list version). Has no effect
+ * if the error indicator is already set (e.g. with yasm_error_set()). This
+ * function must be called prior to its corresponding yasm_error_set() call.
+ * \param xrefline virtual line to cross-reference to (should not be 0)
+ * \param format printf format string
+ * \param va argument list for format
+ */
+YASM_LIB_DECL
+void yasm_error_set_xref_va(unsigned long xrefline, const char *format,
+ va_list va);
+
+/** Set a cross-reference for a new error. Has no effect if the error
+ * indicator is already set (e.g. with yasm_error_set()). This function
+ * must be called prior to its corresponding yasm_error_set() call.
+ * \param xrefline virtual line to cross-reference to (should not be 0)
+ * \param format printf format string
+ * \param ... argument list for format
+ */
+YASM_LIB_DECL
+void yasm_error_set_xref(unsigned long xrefline, const char *format, ...)
+ /*@printflike@*/;
+
+/** Fetch the error indicator and all associated data. If the error
+ * indicator is set, the output pointers are set to the current error
+ * indicator values, and the error indicator is cleared.
+ * The code using this function is then responsible for yasm_xfree()'ing
+ * str and xrefstr (if non-NULL). If the error indicator is not set,
+ * all output values are set to 0 (including eclass, which is set to
+ * YASM_ERROR_NONE).
+ * \param eclass error class (output)
+ * \param str error message
+ * \param xrefline virtual line used for cross-referencing (0 if no xref)
+ * \param xrefstr cross-reference error message (NULL if no xref)
+ */
+YASM_LIB_DECL
+void yasm_error_fetch(/*@out@*/ yasm_error_class *eclass,
+ /*@out@*/ /*@only@*/ /*@null@*/ char **str,
+ /*@out@*/ unsigned long *xrefline,
+ /*@out@*/ /*@only@*/ /*@null@*/ char **xrefstr);
+
+/** Unconditionally clear all warning indicators, freeing any associated data.
+ * Has no effect if no warning indicators have been set.
+ */
+YASM_LIB_DECL
+void yasm_warn_clear(void);
+
+/** Get the first warning indicator. YASM_WARN_NONE is returned if no warning
+ * has been set. Note that as YASM_WARN_NONE is 0, the return value can also
+ * be treated as a boolean value.
+ * \return First warning indicator.
+ */
+YASM_LIB_DECL
+yasm_warn_class yasm_warn_occurred(void);
+
+/** Add a warning indicator (va_list version).
+ * \param wclass warning class
+ * \param format printf format string
+ * \param va argument list for format
+ */
+YASM_LIB_DECL
+void yasm_warn_set_va(yasm_warn_class wclass, const char *format, va_list va);
+
+/** Add a warning indicator.
+ * \param wclass warning class
+ * \param format printf format string
+ * \param ... argument list for format
+ */
+YASM_LIB_DECL
+void yasm_warn_set(yasm_warn_class wclass, const char *format, ...)
+ /*@printflike@*/;
+
+/** Fetch the first warning indicator and all associated data. If there
+ * is at least one warning indicator, the output pointers are set to the
+ * first warning indicator values, and first warning indicator is removed.
+ * The code using this function is then responsible for yasm_xfree()'ing
+ * str and xrefstr (if non-NULL). If there is no warning indicator set,
+ * all output values are set to 0 (including wclass, which is set to
+ * YASM_WARN_NONE).
+ * \param wclass warning class (output)
+ * \param str warning message
+ */
+YASM_LIB_DECL
+void yasm_warn_fetch(/*@out@*/ yasm_warn_class *wclass,
+ /*@out@*/ /*@only@*/ char **str);
+
+/** Enable a class of warnings.
+ * \param wclass warning class
+ */
+YASM_LIB_DECL
+void yasm_warn_enable(yasm_warn_class wclass);
+
+/** Disable a class of warnings.
+ * \param wclass warning class
+ */
+YASM_LIB_DECL
+void yasm_warn_disable(yasm_warn_class wclass);
+
+/** Disable all classes of warnings. */
+YASM_LIB_DECL
+void yasm_warn_disable_all(void);
+
+/** Create an error/warning set for collection of multiple error/warnings.
+ * \return Newly allocated set.
+ */
+YASM_LIB_DECL
+/*@only@*/ yasm_errwarns *yasm_errwarns_create(void);
+
+/** Destroy an error/warning set.
+ * \param errwarns error/warning set
+ */
+YASM_LIB_DECL
+void yasm_errwarns_destroy(/*@only@*/ yasm_errwarns *errwarns);
+
+/** Propagate error indicator and warning indicator(s) to an error/warning set.
+ * Has no effect if the error indicator and warning indicator are not set.
+ * Does not print immediately; yasm_errwarn_output_all() outputs
+ * accumulated errors and warnings.
+ * Generally multiple errors on the same line will be reported, but errors
+ * of class YASM_ERROR_PARSE will get overwritten by any other class on the
+ * same line.
+ * \param errwarns error/warning set
+ * \param line virtual line
+ */
+YASM_LIB_DECL
+void yasm_errwarn_propagate(yasm_errwarns *errwarns, unsigned long line);
+
+/** Get total number of errors logged.
+ * \param errwarns error/warning set
+ * \param warning_as_error if nonzero, warnings are treated as errors.
+ * \return Number of errors.
+ */
+YASM_LIB_DECL
+unsigned int yasm_errwarns_num_errors(yasm_errwarns *errwarns,
+ int warning_as_error);
+
+/** Print out an error.
+ * \param fn filename of source file
+ * \param line line number
+ * \param msg error message
+ * \param xref_fn cross-referenced source filename
+ * \param xref_line cross-referenced line number
+ * \param xref_msg cross-referenced error message
+ */
+typedef void (*yasm_print_error_func)
+ (const char *fn, unsigned long line, const char *msg,
+ /*@null@*/ const char *xref_fn, unsigned long xref_line,
+ /*@null@*/ const char *xref_msg);
+
+/** Print out a warning.
+ * \param fn filename of source file
+ * \param line line number
+ * \param msg warning message
+ */
+typedef void (*yasm_print_warning_func)
+ (const char *fn, unsigned long line, const char *msg);
+
+/** Outputs error/warning set in sorted order (sorted by virtual line number).
+ * \param errwarns error/warning set
+ * \param lm line map (to convert virtual lines into filename/line pairs)
+ * \param warning_as_error if nonzero, treat warnings as errors.
+ * \param print_error function called to print out errors
+ * \param print_warning function called to print out warnings
+ */
+YASM_LIB_DECL
+void yasm_errwarns_output_all
+ (yasm_errwarns *errwarns, yasm_linemap *lm, int warning_as_error,
+ yasm_print_error_func print_error, yasm_print_warning_func print_warning);
+
+/** Convert a possibly unprintable character into a printable string.
+ * \internal
+ * \param ch possibly unprintable character
+ * \return Printable string representation (static buffer).
+ */
+YASM_LIB_DECL
+char *yasm__conv_unprint(int ch);
+
+/** Hook for library users to map to gettext() if GNU gettext is being used.
+ * \param msgid message catalog identifier
+ * \return Translated message.
+ */
+YASM_LIB_DECL
+extern const char * (*yasm_gettext_hook) (const char *msgid);
+
+#endif
diff --git a/libyasm/expr.c b/libyasm/expr.c
new file mode 100644
index 0000000..c2c868e
--- /dev/null
+++ b/libyasm/expr.c
@@ -0,0 +1,1516 @@
+/*
+ * Expression handling
+ *
+ * Copyright (C) 2001-2007 Michael Urman, Peter Johnson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "util.h"
+
+#include "libyasm-stdint.h"
+#include "coretype.h"
+#include "bitvect.h"
+
+#include "errwarn.h"
+#include "intnum.h"
+#include "floatnum.h"
+#include "expr.h"
+#include "symrec.h"
+
+#include "bytecode.h"
+#include "section.h"
+
+#include "arch.h"
+
+
+static /*@only@*/ yasm_expr *expr_level_op
+ (/*@returned@*/ /*@only@*/ yasm_expr *e, int fold_const,
+ int simplify_ident, int simplify_reg_mul);
+static int expr_traverse_nodes_post(/*@null@*/ yasm_expr *e,
+ /*@null@*/ void *d,
+ int (*func) (/*@null@*/ yasm_expr *e,
+ /*@null@*/ void *d));
+static void expr_delete_term(yasm_expr__item *term, int recurse);
+
+/* Bitmap of used items. We should really never need more than 2 at a time,
+ * so 31 is pretty much overkill.
+ */
+static unsigned long itempool_used = 0;
+static yasm_expr__item itempool[31];
+
+/* allocate a new expression node, with children as defined.
+ * If it's a unary operator, put the element in left and set right=NULL. */
+/*@-compmempass@*/
+yasm_expr *
+yasm_expr_create(yasm_expr_op op, yasm_expr__item *left,
+ yasm_expr__item *right, unsigned long line)
+{
+ yasm_expr *ptr, *sube;
+ unsigned long z;
+ ptr = yasm_xmalloc(sizeof(yasm_expr));
+
+ ptr->op = op;
+ ptr->numterms = 0;
+ ptr->terms[0].type = YASM_EXPR_NONE;
+ ptr->terms[1].type = YASM_EXPR_NONE;
+ if (left) {
+ ptr->terms[0] = *left; /* structure copy */
+ z = (unsigned long)(left-itempool);
+ if (z>=31)
+ yasm_internal_error(N_("could not find expritem in pool"));
+ itempool_used &= ~(1<<z);
+ ptr->numterms++;
+
+ /* Search downward until we find something *other* than an
+ * IDENT, then bring it up to the current level.
+ */
+ while (ptr->terms[0].type == YASM_EXPR_EXPR &&
+ ptr->terms[0].data.expn->op == YASM_EXPR_IDENT) {
+ sube = ptr->terms[0].data.expn;
+ ptr->terms[0] = sube->terms[0]; /* structure copy */
+ /*@-usereleased@*/
+ yasm_xfree(sube);
+ /*@=usereleased@*/
+ }
+ } else {
+ yasm_internal_error(N_("Right side of expression must exist"));
+ }
+
+ if (right) {
+ ptr->terms[1] = *right; /* structure copy */
+ z = (unsigned long)(right-itempool);
+ if (z>=31)
+ yasm_internal_error(N_("could not find expritem in pool"));
+ itempool_used &= ~(1<<z);
+ ptr->numterms++;
+
+ /* Search downward until we find something *other* than an
+ * IDENT, then bring it up to the current level.
+ */
+ while (ptr->terms[1].type == YASM_EXPR_EXPR &&
+ ptr->terms[1].data.expn->op == YASM_EXPR_IDENT) {
+ sube = ptr->terms[1].data.expn;
+ ptr->terms[1] = sube->terms[0]; /* structure copy */
+ /*@-usereleased@*/
+ yasm_xfree(sube);
+ /*@=usereleased@*/
+ }
+ }
+
+ ptr->line = line;
+
+ return expr_level_op(ptr, 1, 1, 0);
+}
+/*@=compmempass@*/
+
+/* helpers */
+static yasm_expr__item *
+expr_get_item(void)
+{
+ int z = 0;
+ unsigned long v = itempool_used & 0x7fffffff;
+
+ while (v & 1) {
+ v >>= 1;
+ z++;
+ }
+ if (z>=31)
+ yasm_internal_error(N_("too many expritems"));
+ itempool_used |= 1<<z;
+ return &itempool[z];
+}
+
+yasm_expr__item *
+yasm_expr_precbc(yasm_bytecode *precbc)
+{
+ yasm_expr__item *e = expr_get_item();
+ e->type = YASM_EXPR_PRECBC;
+ e->data.precbc = precbc;
+ return e;
+}
+
+yasm_expr__item *
+yasm_expr_sym(yasm_symrec *s)
+{
+ yasm_expr__item *e = expr_get_item();
+ e->type = YASM_EXPR_SYM;
+ e->data.sym = s;
+ return e;
+}
+
+yasm_expr__item *
+yasm_expr_expr(yasm_expr *x)
+{
+ yasm_expr__item *e = expr_get_item();
+ e->type = YASM_EXPR_EXPR;
+ e->data.expn = x;
+ return e;
+}
+
+yasm_expr__item *
+yasm_expr_int(yasm_intnum *i)
+{
+ yasm_expr__item *e = expr_get_item();
+ e->type = YASM_EXPR_INT;
+ e->data.intn = i;
+ return e;
+}
+
+yasm_expr__item *
+yasm_expr_float(yasm_floatnum *f)
+{
+ yasm_expr__item *e = expr_get_item();
+ e->type = YASM_EXPR_FLOAT;
+ e->data.flt = f;
+ return e;
+}
+
+yasm_expr__item *
+yasm_expr_reg(uintptr_t reg)
+{
+ yasm_expr__item *e = expr_get_item();
+ e->type = YASM_EXPR_REG;
+ e->data.reg = reg;
+ return e;
+}
+
+/* Transforms instances of symrec-symrec [symrec+(-1*symrec)] into single
+ * expritems if possible. Uses a simple n^2 algorithm because n is usually
+ * quite small. Also works for precbc-precbc (or symrec-precbc,
+ * precbc-symrec).
+ */
+static /*@only@*/ yasm_expr *
+expr_xform_bc_dist_base(/*@returned@*/ /*@only@*/ yasm_expr *e,
+ /*@null@*/ void *cbd,
+ int (*callback) (yasm_expr__item *ei,
+ yasm_bytecode *precbc,
+ yasm_bytecode *precbc2,
+ void *cbd))
+{
+ int i;
+ /*@dependent@*/ yasm_section *sect;
+ /*@dependent@*/ /*@null@*/ yasm_bytecode *precbc;
+ int numterms;
+
+ /* Handle symrec-symrec in ADD exprs by looking for (-1*symrec) and
+ * symrec term pairs (where both symrecs are in the same segment).
+ */
+ if (e->op != YASM_EXPR_ADD)
+ return e;
+
+ for (i=0; i<e->numterms; i++) {
+ int j;
+ yasm_expr *sube;
+ yasm_intnum *intn;
+ yasm_symrec *sym = NULL;
+ /*@dependent@*/ yasm_section *sect2;
+ /*@dependent@*/ /*@null@*/ yasm_bytecode *precbc2;
+
+ /* First look for an (-1*symrec) term */
+ if (e->terms[i].type != YASM_EXPR_EXPR)
+ continue;
+ sube = e->terms[i].data.expn;
+ if (sube->op != YASM_EXPR_MUL || sube->numterms != 2)
+ continue;
+
+ if (sube->terms[0].type == YASM_EXPR_INT &&
+ (sube->terms[1].type == YASM_EXPR_SYM ||
+ sube->terms[1].type == YASM_EXPR_PRECBC)) {
+ intn = sube->terms[0].data.intn;
+ if (sube->terms[1].type == YASM_EXPR_PRECBC)
+ precbc = sube->terms[1].data.precbc;
+ else
+ sym = sube->terms[1].data.sym;
+ } else if ((sube->terms[0].type == YASM_EXPR_SYM ||
+ sube->terms[0].type == YASM_EXPR_PRECBC) &&
+ sube->terms[1].type == YASM_EXPR_INT) {
+ if (sube->terms[0].type == YASM_EXPR_PRECBC)
+ precbc = sube->terms[0].data.precbc;
+ else
+ sym = sube->terms[0].data.sym;
+ intn = sube->terms[1].data.intn;
+ } else
+ continue;
+
+ if (!yasm_intnum_is_neg1(intn))
+ continue;
+
+ if (sym && !yasm_symrec_get_label(sym, &precbc))
+ continue;
+ sect2 = yasm_bc_get_section(precbc);
+
+ /* Now look for a symrec term in the same segment */
+ for (j=0; j<e->numterms; j++) {
+ if (((e->terms[j].type == YASM_EXPR_SYM &&
+ yasm_symrec_get_label(e->terms[j].data.sym, &precbc2)) ||
+ (e->terms[j].type == YASM_EXPR_PRECBC &&
+ (precbc2 = e->terms[j].data.precbc))) &&
+ (sect = yasm_bc_get_section(precbc2)) &&
+ sect == sect2 &&
+ callback(&e->terms[j], precbc, precbc2, cbd)) {
+ /* Delete the matching (-1*symrec) term */
+ yasm_expr_destroy(sube);
+ e->terms[i].type = YASM_EXPR_NONE;
+ break; /* stop looking for matching symrec term */
+ }
+ }
+ }
+
+ /* Clean up any deleted (EXPR_NONE) terms */
+ numterms = 0;
+ for (i=0; i<e->numterms; i++) {
+ if (e->terms[i].type != YASM_EXPR_NONE)
+ e->terms[numterms++] = e->terms[i]; /* structure copy */
+ }
+ if (e->numterms != numterms) {
+ e->numterms = numterms;
+ e = yasm_xrealloc(e, sizeof(yasm_expr)+((numterms<2) ? 0 :
+ sizeof(yasm_expr__item)*(numterms-2)));
+ if (numterms == 1)
+ e->op = YASM_EXPR_IDENT;
+ }
+
+ return e;
+}
+
+static int
+expr_xform_bc_dist_cb(yasm_expr__item *ei, yasm_bytecode *precbc,
+ yasm_bytecode *precbc2, /*@null@*/ void *d)
+{
+ yasm_intnum *dist = yasm_calc_bc_dist(precbc, precbc2);
+ if (!dist)
+ return 0;
+ /* Change the term to an integer */
+ ei->type = YASM_EXPR_INT;
+ ei->data.intn = dist;
+ return 1;
+}
+
+/* Transforms instances of symrec-symrec [symrec+(-1*symrec)] into integers if
+ * possible.
+ */
+static /*@only@*/ yasm_expr *
+expr_xform_bc_dist(/*@returned@*/ /*@only@*/ yasm_expr *e)
+{
+ return expr_xform_bc_dist_base(e, NULL, expr_xform_bc_dist_cb);
+}
+
+typedef struct bc_dist_subst_cbd {
+ void (*callback) (unsigned int subst, yasm_bytecode *precbc,
+ yasm_bytecode *precbc2, void *cbd);
+ void *cbd;
+ unsigned int subst;
+} bc_dist_subst_cbd;
+
+static int
+expr_bc_dist_subst_cb(yasm_expr__item *ei, yasm_bytecode *precbc,
+ yasm_bytecode *precbc2, /*@null@*/ void *d)
+{
+ bc_dist_subst_cbd *my_cbd = d;
+ assert(my_cbd != NULL);
+ /* Call higher-level callback */
+ my_cbd->callback(my_cbd->subst, precbc, precbc2, my_cbd->cbd);
+ /* Change the term to an subst */
+ ei->type = YASM_EXPR_SUBST;
+ ei->data.subst = my_cbd->subst;
+ my_cbd->subst++;
+ return 1;
+}
+
+static yasm_expr *
+expr_xform_bc_dist_subst(yasm_expr *e, void *d)
+{
+ return expr_xform_bc_dist_base(e, d, expr_bc_dist_subst_cb);
+}
+
+int
+yasm_expr__bc_dist_subst(yasm_expr **ep, void *cbd,
+ void (*callback) (unsigned int subst,
+ yasm_bytecode *precbc,
+ yasm_bytecode *precbc2,
+ void *cbd))
+{
+ bc_dist_subst_cbd my_cbd; /* callback info for low-level callback */
+ my_cbd.callback = callback;
+ my_cbd.cbd = cbd;
+ my_cbd.subst = 0;
+ *ep = yasm_expr__level_tree(*ep, 1, 1, 1, 0, &expr_xform_bc_dist_subst,
+ &my_cbd);
+ return my_cbd.subst;
+}
+
+/* Negate just a single ExprItem by building a -1*ei subexpression */
+static void
+expr_xform_neg_item(yasm_expr *e, yasm_expr__item *ei)
+{
+ yasm_expr *sube = yasm_xmalloc(sizeof(yasm_expr));
+
+ /* Build -1*ei subexpression */
+ sube->op = YASM_EXPR_MUL;
+ sube->line = e->line;
+ sube->numterms = 2;
+ sube->terms[0].type = YASM_EXPR_INT;
+ sube->terms[0].data.intn = yasm_intnum_create_int(-1);
+ sube->terms[1] = *ei; /* structure copy */
+
+ /* Replace original ExprItem with subexp */
+ ei->type = YASM_EXPR_EXPR;
+ ei->data.expn = sube;
+}
+
+/* Negates e by multiplying by -1, with distribution over lower-precedence
+ * operators (eg ADD) and special handling to simplify result w/ADD, NEG, and
+ * others.
+ *
+ * Returns a possibly reallocated e.
+ */
+static /*@only@*/ yasm_expr *
+expr_xform_neg_helper(/*@returned@*/ /*@only@*/ yasm_expr *e)
+{
+ yasm_expr *ne;
+ int i;
+
+ switch (e->op) {
+ case YASM_EXPR_ADD:
+ /* distribute (recursively if expr) over terms */
+ for (i=0; i<e->numterms; i++) {
+ if (e->terms[i].type == YASM_EXPR_EXPR)
+ e->terms[i].data.expn =
+ expr_xform_neg_helper(e->terms[i].data.expn);
+ else
+ expr_xform_neg_item(e, &e->terms[i]);
+ }
+ break;
+ case YASM_EXPR_SUB:
+ /* change op to ADD, and recursively negate left side (if expr) */
+ e->op = YASM_EXPR_ADD;
+ if (e->terms[0].type == YASM_EXPR_EXPR)
+ e->terms[0].data.expn =
+ expr_xform_neg_helper(e->terms[0].data.expn);
+ else
+ expr_xform_neg_item(e, &e->terms[0]);
+ break;
+ case YASM_EXPR_NEG:
+ /* Negating a negated value? Make it an IDENT. */
+ e->op = YASM_EXPR_IDENT;
+ break;
+ case YASM_EXPR_IDENT:
+ /* Negating an ident? Change it into a MUL w/ -1 if there's no
+ * floatnums present below; if there ARE floatnums, recurse.
+ */
+ if (e->terms[0].type == YASM_EXPR_FLOAT)
+ yasm_floatnum_calc(e->terms[0].data.flt, YASM_EXPR_NEG, NULL);
+ else if (e->terms[0].type == YASM_EXPR_INT)
+ yasm_intnum_calc(e->terms[0].data.intn, YASM_EXPR_NEG, NULL);
+ else if (e->terms[0].type == YASM_EXPR_EXPR &&
+ yasm_expr__contains(e->terms[0].data.expn, YASM_EXPR_FLOAT))
+ expr_xform_neg_helper(e->terms[0].data.expn);
+ else {
+ e->op = YASM_EXPR_MUL;
+ e->numterms = 2;
+ e->terms[1].type = YASM_EXPR_INT;
+ e->terms[1].data.intn = yasm_intnum_create_int(-1);
+ }
+ break;
+ default:
+ /* Everything else. MUL will be combined when it's leveled.
+ * Make a new expr (to replace e) with -1*e.
+ */
+ ne = yasm_xmalloc(sizeof(yasm_expr));
+ ne->op = YASM_EXPR_MUL;
+ ne->line = e->line;
+ ne->numterms = 2;
+ ne->terms[0].type = YASM_EXPR_INT;
+ ne->terms[0].data.intn = yasm_intnum_create_int(-1);
+ ne->terms[1].type = YASM_EXPR_EXPR;
+ ne->terms[1].data.expn = e;
+ return ne;
+ }
+ return e;
+}
+
+/* Transforms negatives into expressions that are easier to combine:
+ * -x -> -1*x
+ * a-b -> a+(-1*b)
+ *
+ * Call post-order on an expression tree to transform the entire tree.
+ *
+ * Returns a possibly reallocated e.
+ */
+static /*@only@*/ yasm_expr *
+expr_xform_neg(/*@returned@*/ /*@only@*/ yasm_expr *e)
+{
+ switch (e->op) {
+ case YASM_EXPR_NEG:
+ /* Turn -x into -1*x */
+ e->op = YASM_EXPR_IDENT;
+ return expr_xform_neg_helper(e);
+ case YASM_EXPR_SUB:
+ /* Turn a-b into a+(-1*b) */
+
+ /* change op to ADD, and recursively negate right side (if expr) */
+ e->op = YASM_EXPR_ADD;
+ if (e->terms[1].type == YASM_EXPR_EXPR)
+ e->terms[1].data.expn =
+ expr_xform_neg_helper(e->terms[1].data.expn);
+ else
+ expr_xform_neg_item(e, &e->terms[1]);
+ break;
+ default:
+ break;
+ }
+
+ return e;
+}
+
+/* Look for simple identities that make the entire result constant:
+ * 0*&x, -1|x, etc.
+ */
+static int
+expr_is_constant(yasm_expr_op op, yasm_intnum *intn)
+{
+ int iszero = yasm_intnum_is_zero(intn);
+ return ((iszero && op == YASM_EXPR_MUL) ||
+ (iszero && op == YASM_EXPR_AND) ||
+ (iszero && op == YASM_EXPR_LAND) ||
+ (yasm_intnum_is_neg1(intn) && op == YASM_EXPR_OR));
+}
+
+/* Look for simple "left" identities like 0+x, 1*x, etc. */
+static int
+expr_can_destroy_int_left(yasm_expr_op op, yasm_intnum *intn)
+{
+ int iszero = yasm_intnum_is_zero(intn);
+ return ((yasm_intnum_is_pos1(intn) && op == YASM_EXPR_MUL) ||
+ (iszero && op == YASM_EXPR_ADD) ||
+ (yasm_intnum_is_neg1(intn) && op == YASM_EXPR_AND) ||
+ (!iszero && op == YASM_EXPR_LAND) ||
+ (iszero && op == YASM_EXPR_OR) ||
+ (iszero && op == YASM_EXPR_LOR));
+}
+
+/* Look for simple "right" identities like x+|-0, x*&/1 */
+static int
+expr_can_destroy_int_right(yasm_expr_op op, yasm_intnum *intn)
+{
+ int iszero = yasm_intnum_is_zero(intn);
+ int ispos1 = yasm_intnum_is_pos1(intn);
+ return ((ispos1 && op == YASM_EXPR_MUL) ||
+ (ispos1 && op == YASM_EXPR_DIV) ||
+ (iszero && op == YASM_EXPR_ADD) ||
+ (iszero && op == YASM_EXPR_SUB) ||
+ (yasm_intnum_is_neg1(intn) && op == YASM_EXPR_AND) ||
+ (!iszero && op == YASM_EXPR_LAND) ||
+ (iszero && op == YASM_EXPR_OR) ||
+ (iszero && op == YASM_EXPR_LOR) ||
+ (iszero && op == YASM_EXPR_SHL) ||
+ (iszero && op == YASM_EXPR_SHR));
+}
+
+/* Check for and simplify identities. Returns new number of expr terms.
+ * Sets e->op = EXPR_IDENT if numterms ends up being 1.
+ * Uses numterms parameter instead of e->numterms for basis of "new" number
+ * of terms.
+ * Assumes int_term is *only* integer term in e.
+ * NOTE: Really designed to only be used by expr_level_op().
+ */
+static int
+expr_simplify_identity(yasm_expr *e, int numterms, int *int_term,
+ int simplify_reg_mul)
+{
+ int i;
+ int save_numterms;
+
+ /* Don't do this step if it's 1*REG. Save and restore numterms so
+ * yasm_expr__contains() works correctly.
+ */
+ save_numterms = e->numterms;
+ e->numterms = numterms;
+ if (simplify_reg_mul || e->op != YASM_EXPR_MUL
+ || !yasm_intnum_is_pos1(e->terms[*int_term].data.intn)
+ || !yasm_expr__contains(e, YASM_EXPR_REG)) {
+ /* Check for simple identities that delete the intnum.
+ * Don't delete if the intnum is the only thing in the expn.
+ */
+ if ((*int_term == 0 && numterms > 1 &&
+ expr_can_destroy_int_left(e->op, e->terms[0].data.intn)) ||
+ (*int_term > 0 &&
+ expr_can_destroy_int_right(e->op,
+ e->terms[*int_term].data.intn))) {
+ /* Delete the intnum */
+ yasm_intnum_destroy(e->terms[*int_term].data.intn);
+
+ /* Slide everything to its right over by 1 */
+ if (*int_term != numterms-1) /* if it wasn't last.. */
+ memmove(&e->terms[*int_term], &e->terms[*int_term+1],
+ (numterms-1-*int_term)*sizeof(yasm_expr__item));
+
+ /* Update numterms */
+ numterms--;
+ *int_term = -1; /* no longer an int term */
+ }
+ }
+ e->numterms = save_numterms;
+
+ /* Check for simple identites that delete everything BUT the intnum.
+ * Don't bother if the intnum is the only thing in the expn.
+ */
+ if (numterms > 1 && *int_term != -1 &&
+ expr_is_constant(e->op, e->terms[*int_term].data.intn)) {
+ /* Loop through, deleting everything but the integer term */
+ for (i=0; i<e->numterms; i++)
+ if (i != *int_term)
+ expr_delete_term(&e->terms[i], 1);
+
+ /* Move integer term to the first term (if not already there) */
+ if (*int_term != 0)
+ e->terms[0] = e->terms[*int_term]; /* structure copy */
+
+ /* Set numterms to 1 */
+ numterms = 1;
+ }
+
+ /* Compute NOT, NEG, and LNOT on single intnum. */
+ if (numterms == 1 && *int_term == 0 &&
+ (e->op == YASM_EXPR_NOT || e->op == YASM_EXPR_NEG ||
+ e->op == YASM_EXPR_LNOT))
+ yasm_intnum_calc(e->terms[0].data.intn, e->op, NULL);
+
+ /* Change expression to IDENT if possible. */
+ if (numterms == 1)
+ e->op = YASM_EXPR_IDENT;
+
+ /* Return the updated numterms */
+ return numterms;
+}
+
+/* Levels the expression tree starting at e. Eg:
+ * a+(b+c) -> a+b+c
+ * (a+b)+(c+d) -> a+b+c+d
+ * Naturally, only levels operators that allow more than two operand terms.
+ * NOTE: only does *one* level of leveling (no recursion). Should be called
+ * post-order on a tree to combine deeper levels.
+ * Also brings up any IDENT values into the current level (for ALL operators).
+ * Folds (combines by evaluation) *integer* constant values if fold_const != 0.
+ *
+ * Returns a possibly reallocated e.
+ */
+/*@-mustfree@*/
+static /*@only@*/ yasm_expr *
+expr_level_op(/*@returned@*/ /*@only@*/ yasm_expr *e, int fold_const,
+ int simplify_ident, int simplify_reg_mul)
+{
+ int i, j, o, fold_numterms, level_numterms, level_fold_numterms;
+ int first_int_term = -1;
+
+ /* Determine how many operands will need to be brought up (for leveling).
+ * Go ahead and bring up any IDENT'ed values.
+ */
+ while (e->op == YASM_EXPR_IDENT && e->terms[0].type == YASM_EXPR_EXPR) {
+ yasm_expr *sube = e->terms[0].data.expn;
+ yasm_xfree(e);
+ e = sube;
+ }
+
+ /* If non-numeric expression, don't fold constants. */
+ if (e->op > YASM_EXPR_NONNUM)
+ fold_const = 0;
+
+ level_numterms = e->numterms;
+ level_fold_numterms = 0;
+ for (i=0; i<e->numterms; i++) {
+ /* Search downward until we find something *other* than an
+ * IDENT, then bring it up to the current level.
+ */
+ while (e->terms[i].type == YASM_EXPR_EXPR &&
+ e->terms[i].data.expn->op == YASM_EXPR_IDENT) {
+ yasm_expr *sube = e->terms[i].data.expn;
+ e->terms[i] = sube->terms[0];
+ yasm_xfree(sube);
+ }
+
+ if (e->terms[i].type == YASM_EXPR_EXPR &&
+ e->terms[i].data.expn->op == e->op) {
+ /* It's an expression w/the same operator, add in its numterms.
+ * But don't forget to subtract one for the expr itself!
+ */
+ level_numterms += e->terms[i].data.expn->numterms - 1;
+
+ /* If we're folding constants, count up the number of constants
+ * that will be merged in.
+ */
+ if (fold_const)
+ for (j=0; j<e->terms[i].data.expn->numterms; j++)
+ if (e->terms[i].data.expn->terms[j].type ==
+ YASM_EXPR_INT)
+ level_fold_numterms++;
+ }
+
+ /* Find the first integer term (if one is present) if we're folding
+ * constants.
+ */
+ if (fold_const && first_int_term == -1 &&
+ e->terms[i].type == YASM_EXPR_INT)
+ first_int_term = i;
+ }
+
+ /* Look for other integer terms if there's one and combine.
+ * Also eliminate empty spaces when combining and adjust numterms
+ * variables.
+ */
+ fold_numterms = e->numterms;
+ if (first_int_term != -1) {
+ for (i=first_int_term+1, o=first_int_term+1; i<e->numterms; i++) {
+ if (e->terms[i].type == YASM_EXPR_INT) {
+ yasm_intnum_calc(e->terms[first_int_term].data.intn, e->op,
+ e->terms[i].data.intn);
+ fold_numterms--;
+ level_numterms--;
+ /* make sure to delete folded intnum */
+ yasm_intnum_destroy(e->terms[i].data.intn);
+ } else if (o != i) {
+ /* copy term if it changed places */
+ e->terms[o++] = e->terms[i];
+ } else
+ o++;
+ }
+
+ if (simplify_ident) {
+ int new_fold_numterms;
+ /* Simplify identities and make IDENT if possible. */
+ new_fold_numterms =
+ expr_simplify_identity(e, fold_numterms, &first_int_term,
+ simplify_reg_mul);
+ level_numterms -= fold_numterms-new_fold_numterms;
+ fold_numterms = new_fold_numterms;
+ }
+ if (fold_numterms == 1)
+ e->op = YASM_EXPR_IDENT;
+ }
+
+ /* Only level operators that allow more than two operand terms.
+ * Also don't bother leveling if it's not necessary to bring up any terms.
+ */
+ if ((e->op != YASM_EXPR_ADD && e->op != YASM_EXPR_MUL &&
+ e->op != YASM_EXPR_OR && e->op != YASM_EXPR_AND &&
+ e->op != YASM_EXPR_LOR && e->op != YASM_EXPR_LAND &&
+ e->op != YASM_EXPR_LXOR && e->op != YASM_EXPR_XOR) ||
+ level_numterms <= fold_numterms) {
+ /* Downsize e if necessary */
+ if (fold_numterms < e->numterms && e->numterms > 2)
+ e = yasm_xrealloc(e, sizeof(yasm_expr)+((fold_numterms<2) ? 0 :
+ sizeof(yasm_expr__item)*(fold_numterms-2)));
+ /* Update numterms */
+ e->numterms = fold_numterms;
+ return e;
+ }
+
+ /* Adjust numterms for constant folding from terms being "pulled up".
+ * Careful: if there's no integer term in e, then save space for it.
+ */
+ if (fold_const) {
+ level_numterms -= level_fold_numterms;
+ if (first_int_term == -1 && level_fold_numterms != 0)
+ level_numterms++;
+ }
+
+ /* Alloc more (or conceivably less, but not usually) space for e */
+ e = yasm_xrealloc(e, sizeof(yasm_expr)+((level_numterms<2) ? 0 :
+ sizeof(yasm_expr__item)*(level_numterms-2)));
+
+ /* Copy up ExprItem's. Iterate from right to left to keep the same
+ * ordering as was present originally.
+ * Combine integer terms as necessary.
+ */
+ for (i=fold_numterms-1, o=level_numterms-1; i>=0; i--) {
+ if (e->terms[i].type == YASM_EXPR_EXPR &&
+ e->terms[i].data.expn->op == e->op) {
+ /* bring up subexpression */
+ yasm_expr *sube = e->terms[i].data.expn;
+
+ /* copy terms right to left */
+ for (j=sube->numterms-1; j>=0; j--) {
+ if (fold_const && sube->terms[j].type == YASM_EXPR_INT) {
+ /* Need to fold it in.. but if there's no int term already,
+ * just copy into a new one.
+ */
+ if (first_int_term == -1) {
+ first_int_term = o--;
+ e->terms[first_int_term] = sube->terms[j]; /* struc */
+ } else {
+ yasm_intnum_calc(e->terms[first_int_term].data.intn,
+ e->op, sube->terms[j].data.intn);
+ /* make sure to delete folded intnum */
+ yasm_intnum_destroy(sube->terms[j].data.intn);
+ }
+ } else {
+ if (o == first_int_term)
+ o--;
+ e->terms[o--] = sube->terms[j]; /* structure copy */
+ }
+ }
+
+ /* delete subexpression, but *don't delete nodes* (as we've just
+ * copied them!)
+ */
+ yasm_xfree(sube);
+ } else if (o != i) {
+ /* copy operand if it changed places */
+ if (o == first_int_term)
+ o--;
+ e->terms[o] = e->terms[i];
+ /* If we moved the first_int_term, change first_int_num too */
+ if (i == first_int_term)
+ first_int_term = o;
+ o--;
+ } else
+ o--;
+ }
+
+ /* Simplify identities, make IDENT if possible, and save to e->numterms. */
+ if (simplify_ident && first_int_term != -1) {
+ e->numterms = expr_simplify_identity(e, level_numterms,
+ &first_int_term, simplify_reg_mul);
+ } else {
+ e->numterms = level_numterms;
+ if (level_numterms == 1)
+ e->op = YASM_EXPR_IDENT;
+ }
+
+ return e;
+}
+/*@=mustfree@*/
+
+typedef SLIST_HEAD(yasm__exprhead, yasm__exprentry) yasm__exprhead;
+typedef struct yasm__exprentry {
+ /*@reldef@*/ SLIST_ENTRY(yasm__exprentry) next;
+ /*@null@*/ const yasm_expr *e;
+} yasm__exprentry;
+
+static yasm_expr *
+expr_expand_equ(yasm_expr *e, yasm__exprhead *eh)
+{
+ int i;
+ yasm__exprentry ee;
+
+ /* traverse terms */
+ for (i=0; i<e->numterms; i++) {
+ const yasm_expr *equ_expr;
+
+ /* Expand equ's. */
+ if (e->terms[i].type == YASM_EXPR_SYM &&
+ (equ_expr = yasm_symrec_get_equ(e->terms[i].data.sym))) {
+ yasm__exprentry *np;
+
+ /* Check for circular reference */
+ SLIST_FOREACH(np, eh, next) {
+ if (np->e == equ_expr) {
+ yasm_error_set(YASM_ERROR_TOO_COMPLEX,
+ N_("circular reference detected"));
+ return e;
+ }
+ }
+
+ e->terms[i].type = YASM_EXPR_EXPR;
+ e->terms[i].data.expn = yasm_expr_copy(equ_expr);
+
+ /* Remember we saw this equ and recurse */
+ ee.e = equ_expr;
+ SLIST_INSERT_HEAD(eh, &ee, next);
+ e->terms[i].data.expn = expr_expand_equ(e->terms[i].data.expn, eh);
+ SLIST_REMOVE_HEAD(eh, next);
+ } else if (e->terms[i].type == YASM_EXPR_EXPR)
+ /* Recurse */
+ e->terms[i].data.expn = expr_expand_equ(e->terms[i].data.expn, eh);
+ }
+
+ return e;
+}
+
+static yasm_expr *
+expr_level_tree(yasm_expr *e, int fold_const, int simplify_ident,
+ int simplify_reg_mul, int calc_bc_dist,
+ yasm_expr_xform_func expr_xform_extra,
+ void *expr_xform_extra_data)
+{
+ int i;
+
+ e = expr_xform_neg(e);
+
+ /* traverse terms */
+ for (i=0; i<e->numterms; i++) {
+ /* Recurse */
+ if (e->terms[i].type == YASM_EXPR_EXPR)
+ e->terms[i].data.expn =
+ expr_level_tree(e->terms[i].data.expn, fold_const,
+ simplify_ident, simplify_reg_mul, calc_bc_dist,
+ expr_xform_extra, expr_xform_extra_data);
+ }
+
+ /* Check for SEG of SEG:OFF, if we match, simplify to just the segment */
+ if (e->op == YASM_EXPR_SEG && e->terms[0].type == YASM_EXPR_EXPR &&
+ e->terms[0].data.expn->op == YASM_EXPR_SEGOFF) {
+ e->op = YASM_EXPR_IDENT;
+ e->terms[0].data.expn->op = YASM_EXPR_IDENT;
+ /* Destroy the second (offset) term */
+ e->terms[0].data.expn->numterms = 1;
+ expr_delete_term(&e->terms[0].data.expn->terms[1], 1);
+ }
+
+ /* do callback */
+ e = expr_level_op(e, fold_const, simplify_ident, simplify_reg_mul);
+ if (calc_bc_dist || expr_xform_extra) {
+ if (calc_bc_dist)
+ e = expr_xform_bc_dist(e);
+ if (expr_xform_extra)
+ e = expr_xform_extra(e, expr_xform_extra_data);
+ e = expr_level_tree(e, fold_const, simplify_ident, simplify_reg_mul,
+ 0, NULL, NULL);
+ }
+ return e;
+}
+
+/* Level an entire expn tree, expanding equ's as we go */
+yasm_expr *
+yasm_expr__level_tree(yasm_expr *e, int fold_const, int simplify_ident,
+ int simplify_reg_mul, int calc_bc_dist,
+ yasm_expr_xform_func expr_xform_extra,
+ void *expr_xform_extra_data)
+{
+ yasm__exprhead eh;
+ SLIST_INIT(&eh);
+
+ if (!e)
+ return 0;
+
+ e = expr_expand_equ(e, &eh);
+ e = expr_level_tree(e, fold_const, simplify_ident, simplify_reg_mul,
+ calc_bc_dist, expr_xform_extra, expr_xform_extra_data);
+
+ return e;
+}
+
+/* Comparison function for expr_order_terms().
+ * Assumes ExprType enum is in canonical order.
+ */
+static int
+expr_order_terms_compare(const void *va, const void *vb)
+{
+ const yasm_expr__item *a = va, *b = vb;
+ return (a->type - b->type);
+}
+
+/* Reorder terms of e into canonical order. Only reorders if reordering
+ * doesn't change meaning of expression. (eg, doesn't reorder SUB).
+ * Canonical order: REG, INT, FLOAT, SYM, EXPR.
+ * Multiple terms of a single type are kept in the same order as in
+ * the original expression.
+ * NOTE: Only performs reordering on *one* level (no recursion).
+ */
+void
+yasm_expr__order_terms(yasm_expr *e)
+{
+ /* don't bother reordering if only one element */
+ if (e->numterms == 1)
+ return;
+
+ /* only reorder some types of operations */
+ switch (e->op) {
+ case YASM_EXPR_ADD:
+ case YASM_EXPR_MUL:
+ case YASM_EXPR_OR:
+ case YASM_EXPR_AND:
+ case YASM_EXPR_XOR:
+ case YASM_EXPR_LOR:
+ case YASM_EXPR_LAND:
+ case YASM_EXPR_LXOR:
+ /* Use mergesort to sort. It's fast on already sorted values and a
+ * stable sort (multiple terms of same type are kept in the same
+ * order).
+ */
+ yasm__mergesort(e->terms, (size_t)e->numterms,
+ sizeof(yasm_expr__item), expr_order_terms_compare);
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+expr_item_copy(yasm_expr__item *dest, const yasm_expr__item *src)
+{
+ dest->type = src->type;
+ switch (src->type) {
+ case YASM_EXPR_SYM:
+ /* Symbols don't need to be copied */
+ dest->data.sym = src->data.sym;
+ break;
+ case YASM_EXPR_PRECBC:
+ /* Nor do direct bytecode references */
+ dest->data.precbc = src->data.precbc;
+ break;
+ case YASM_EXPR_EXPR:
+ dest->data.expn = yasm_expr__copy_except(src->data.expn, -1);
+ break;
+ case YASM_EXPR_INT:
+ dest->data.intn = yasm_intnum_copy(src->data.intn);
+ break;
+ case YASM_EXPR_FLOAT:
+ dest->data.flt = yasm_floatnum_copy(src->data.flt);
+ break;
+ case YASM_EXPR_REG:
+ dest->data.reg = src->data.reg;
+ break;
+ case YASM_EXPR_SUBST:
+ dest->data.subst = src->data.subst;
+ break;
+ default:
+ break;
+ }
+}
+
+/* Copy entire expression EXCEPT for index "except" at *top level only*. */
+yasm_expr *
+yasm_expr__copy_except(const yasm_expr *e, int except)
+{
+ yasm_expr *n;
+ int i;
+
+ n = yasm_xmalloc(sizeof(yasm_expr) +
+ sizeof(yasm_expr__item)*(e->numterms<2?0:e->numterms-2));
+
+ n->op = e->op;
+ n->line = e->line;
+ n->numterms = e->numterms;
+ for (i=0; i<e->numterms; i++) {
+ if (i != except)
+ expr_item_copy(&n->terms[i], &e->terms[i]);
+ }
+
+ return n;
+}
+
+static void
+expr_delete_term(yasm_expr__item *term, int recurse)
+{
+ switch (term->type) {
+ case YASM_EXPR_INT:
+ yasm_intnum_destroy(term->data.intn);
+ break;
+ case YASM_EXPR_FLOAT:
+ yasm_floatnum_destroy(term->data.flt);
+ break;
+ case YASM_EXPR_EXPR:
+ if (recurse)
+ yasm_expr_destroy(term->data.expn);
+ break;
+ default:
+ break;
+ }
+}
+
+static int
+expr_destroy_each(/*@only@*/ yasm_expr *e, /*@unused@*/ void *d)
+{
+ int i;
+ for (i=0; i<e->numterms; i++)
+ expr_delete_term(&e->terms[i], 0);
+ yasm_xfree(e); /* free ourselves */
+ return 0; /* don't stop recursion */
+}
+
+/*@-mustfree@*/
+void
+yasm_expr_destroy(yasm_expr *e)
+{
+ expr_traverse_nodes_post(e, NULL, expr_destroy_each);
+}
+/*@=mustfree@*/
+
+int
+yasm_expr_is_op(const yasm_expr *e, yasm_expr_op op)
+{
+ return (e->op == op);
+}
+
+static int
+expr_contains_callback(const yasm_expr__item *ei, void *d)
+{
+ yasm_expr__type *t = d;
+ return (ei->type & *t);
+}
+
+int
+yasm_expr__contains(const yasm_expr *e, yasm_expr__type t)
+{
+ return yasm_expr__traverse_leaves_in_const(e, &t, expr_contains_callback);
+}
+
+typedef struct subst_cbd {
+ unsigned int num_items;
+ const yasm_expr__item *items;
+} subst_cbd;
+
+static int
+expr_subst_callback(yasm_expr__item *ei, void *d)
+{
+ subst_cbd *cbd = d;
+ if (ei->type != YASM_EXPR_SUBST)
+ return 0;
+ if (ei->data.subst >= cbd->num_items)
+ return 1; /* error */
+ expr_item_copy(ei, &cbd->items[ei->data.subst]);
+ return 0;
+}
+
+int
+yasm_expr__subst(yasm_expr *e, unsigned int num_items,
+ const yasm_expr__item *items)
+{
+ subst_cbd cbd;
+ cbd.num_items = num_items;
+ cbd.items = items;
+ return yasm_expr__traverse_leaves_in(e, &cbd, expr_subst_callback);
+}
+
+/* Traverse over expression tree, calling func for each operation AFTER the
+ * branches (if expressions) have been traversed (eg, postorder
+ * traversal). The data pointer d is passed to each func call.
+ *
+ * Stops early (and returns 1) if func returns 1. Otherwise returns 0.
+ */
+static int
+expr_traverse_nodes_post(yasm_expr *e, void *d,
+ int (*func) (/*@null@*/ yasm_expr *e,
+ /*@null@*/ void *d))
+{
+ int i;
+
+ if (!e)
+ return 0;
+
+ /* traverse terms */
+ for (i=0; i<e->numterms; i++) {
+ if (e->terms[i].type == YASM_EXPR_EXPR &&
+ expr_traverse_nodes_post(e->terms[i].data.expn, d, func))
+ return 1;
+ }
+
+ /* do callback */
+ return func(e, d);
+}
+
+/* Traverse over expression tree in order, calling func for each leaf
+ * (non-operation). The data pointer d is passed to each func call.
+ *
+ * Stops early (and returns 1) if func returns 1. Otherwise returns 0.
+ */
+int
+yasm_expr__traverse_leaves_in_const(const yasm_expr *e, void *d,
+ int (*func) (/*@null@*/ const yasm_expr__item *ei, /*@null@*/ void *d))
+{
+ int i;
+
+ if (!e)
+ return 0;
+
+ for (i=0; i<e->numterms; i++) {
+ if (e->terms[i].type == YASM_EXPR_EXPR) {
+ if (yasm_expr__traverse_leaves_in_const(e->terms[i].data.expn, d,
+ func))
+ return 1;
+ } else {
+ if (func(&e->terms[i], d))
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/* Traverse over expression tree in order, calling func for each leaf
+ * (non-operation). The data pointer d is passed to each func call.
+ *
+ * Stops early (and returns 1) if func returns 1. Otherwise returns 0.
+ */
+int
+yasm_expr__traverse_leaves_in(yasm_expr *e, void *d,
+ int (*func) (/*@null@*/ yasm_expr__item *ei, /*@null@*/ void *d))
+{
+ int i;
+
+ if (!e)
+ return 0;
+
+ for (i=0; i<e->numterms; i++) {
+ if (e->terms[i].type == YASM_EXPR_EXPR) {
+ if (yasm_expr__traverse_leaves_in(e->terms[i].data.expn, d, func))
+ return 1;
+ } else {
+ if (func(&e->terms[i], d))
+ return 1;
+ }
+ }
+ return 0;
+}
+
+yasm_expr *
+yasm_expr_extract_deep_segoff(yasm_expr **ep)
+{
+ yasm_expr *retval;
+ yasm_expr *e = *ep;
+ int i;
+
+ /* Try to extract at this level */
+ retval = yasm_expr_extract_segoff(ep);
+ if (retval)
+ return retval;
+
+ /* Not at this level? Search any expr children. */
+ for (i=0; i<e->numterms; i++) {
+ if (e->terms[i].type == YASM_EXPR_EXPR) {
+ retval = yasm_expr_extract_deep_segoff(&e->terms[i].data.expn);
+ if (retval)
+ return retval;
+ }
+ }
+
+ /* Didn't find one */
+ return NULL;
+}
+
+yasm_expr *
+yasm_expr_extract_segoff(yasm_expr **ep)
+{
+ yasm_expr *retval;
+ yasm_expr *e = *ep;
+
+ /* If not SEG:OFF, we can't do this transformation */
+ if (e->op != YASM_EXPR_SEGOFF)
+ return NULL;
+
+ /* Extract the SEG portion out to its own expression */
+ if (e->terms[0].type == YASM_EXPR_EXPR)
+ retval = e->terms[0].data.expn;
+ else {
+ /* Need to build IDENT expression to hold non-expression contents */
+ retval = yasm_xmalloc(sizeof(yasm_expr));
+ retval->op = YASM_EXPR_IDENT;
+ retval->numterms = 1;
+ retval->terms[0] = e->terms[0]; /* structure copy */
+ }
+
+ /* Delete the SEG: portion by changing the expression into an IDENT */
+ e->op = YASM_EXPR_IDENT;
+ e->numterms = 1;
+ e->terms[0] = e->terms[1]; /* structure copy */
+
+ return retval;
+}
+
+yasm_expr *
+yasm_expr_extract_wrt(yasm_expr **ep)
+{
+ yasm_expr *retval;
+ yasm_expr *e = *ep;
+
+ /* If not WRT, we can't do this transformation */
+ if (e->op != YASM_EXPR_WRT)
+ return NULL;
+
+ /* Extract the right side portion out to its own expression */
+ if (e->terms[1].type == YASM_EXPR_EXPR)
+ retval = e->terms[1].data.expn;
+ else {
+ /* Need to build IDENT expression to hold non-expression contents */
+ retval = yasm_xmalloc(sizeof(yasm_expr));
+ retval->op = YASM_EXPR_IDENT;
+ retval->numterms = 1;
+ retval->terms[0] = e->terms[1]; /* structure copy */
+ }
+
+ /* Delete the right side portion by changing the expr into an IDENT */
+ e->op = YASM_EXPR_IDENT;
+ e->numterms = 1;
+
+ return retval;
+}
+
+/*@-unqualifiedtrans -nullderef -nullstate -onlytrans@*/
+yasm_intnum *
+yasm_expr_get_intnum(yasm_expr **ep, int calc_bc_dist)
+{
+ *ep = yasm_expr_simplify(*ep, calc_bc_dist);
+
+ if ((*ep)->op == YASM_EXPR_IDENT && (*ep)->terms[0].type == YASM_EXPR_INT)
+ return (*ep)->terms[0].data.intn;
+ else
+ return (yasm_intnum *)NULL;
+}
+/*@=unqualifiedtrans =nullderef -nullstate -onlytrans@*/
+
+/*@-unqualifiedtrans -nullderef -nullstate -onlytrans@*/
+const yasm_symrec *
+yasm_expr_get_symrec(yasm_expr **ep, int simplify)
+{
+ if (simplify)
+ *ep = yasm_expr_simplify(*ep, 0);
+
+ if ((*ep)->op == YASM_EXPR_IDENT && (*ep)->terms[0].type == YASM_EXPR_SYM)
+ return (*ep)->terms[0].data.sym;
+ else
+ return (yasm_symrec *)NULL;
+}
+/*@=unqualifiedtrans =nullderef -nullstate -onlytrans@*/
+
+/*@-unqualifiedtrans -nullderef -nullstate -onlytrans@*/
+const uintptr_t *
+yasm_expr_get_reg(yasm_expr **ep, int simplify)
+{
+ if (simplify)
+ *ep = yasm_expr_simplify(*ep, 0);
+
+ if ((*ep)->op == YASM_EXPR_IDENT && (*ep)->terms[0].type == YASM_EXPR_REG)
+ return &((*ep)->terms[0].data.reg);
+ else
+ return NULL;
+}
+/*@=unqualifiedtrans =nullderef -nullstate -onlytrans@*/
+
+void
+yasm_expr_print(const yasm_expr *e, FILE *f)
+{
+ char opstr[8];
+ int i;
+
+ if (!e) {
+ fprintf(f, "(nil)");
+ return;
+ }
+
+ switch (e->op) {
+ case YASM_EXPR_ADD:
+ strcpy(opstr, "+");
+ break;
+ case YASM_EXPR_SUB:
+ strcpy(opstr, "-");
+ break;
+ case YASM_EXPR_MUL:
+ strcpy(opstr, "*");
+ break;
+ case YASM_EXPR_DIV:
+ strcpy(opstr, "/");
+ break;
+ case YASM_EXPR_SIGNDIV:
+ strcpy(opstr, "//");
+ break;
+ case YASM_EXPR_MOD:
+ strcpy(opstr, "%");
+ break;
+ case YASM_EXPR_SIGNMOD:
+ strcpy(opstr, "%%");
+ break;
+ case YASM_EXPR_NEG:
+ fprintf(f, "-");
+ opstr[0] = 0;
+ break;
+ case YASM_EXPR_NOT:
+ fprintf(f, "~");
+ opstr[0] = 0;
+ break;
+ case YASM_EXPR_OR:
+ strcpy(opstr, "|");
+ break;
+ case YASM_EXPR_AND:
+ strcpy(opstr, "&");
+ break;
+ case YASM_EXPR_XOR:
+ strcpy(opstr, "^");
+ break;
+ case YASM_EXPR_XNOR:
+ strcpy(opstr, "XNOR");
+ break;
+ case YASM_EXPR_NOR:
+ strcpy(opstr, "NOR");
+ break;
+ case YASM_EXPR_SHL:
+ strcpy(opstr, "<<");
+ break;
+ case YASM_EXPR_SHR:
+ strcpy(opstr, ">>");
+ break;
+ case YASM_EXPR_LOR:
+ strcpy(opstr, "||");
+ break;
+ case YASM_EXPR_LAND:
+ strcpy(opstr, "&&");
+ break;
+ case YASM_EXPR_LNOT:
+ strcpy(opstr, "!");
+ break;
+ case YASM_EXPR_LXOR:
+ strcpy(opstr, "^^");
+ break;
+ case YASM_EXPR_LXNOR:
+ strcpy(opstr, "LXNOR");
+ break;
+ case YASM_EXPR_LNOR:
+ strcpy(opstr, "LNOR");
+ break;
+ case YASM_EXPR_LT:
+ strcpy(opstr, "<");
+ break;
+ case YASM_EXPR_GT:
+ strcpy(opstr, ">");
+ break;
+ case YASM_EXPR_LE:
+ strcpy(opstr, "<=");
+ break;
+ case YASM_EXPR_GE:
+ strcpy(opstr, ">=");
+ break;
+ case YASM_EXPR_NE:
+ strcpy(opstr, "!=");
+ break;
+ case YASM_EXPR_EQ:
+ strcpy(opstr, "==");
+ break;
+ case YASM_EXPR_SEG:
+ fprintf(f, "SEG ");
+ opstr[0] = 0;
+ break;
+ case YASM_EXPR_WRT:
+ strcpy(opstr, " WRT ");
+ break;
+ case YASM_EXPR_SEGOFF:
+ strcpy(opstr, ":");
+ break;
+ case YASM_EXPR_IDENT:
+ opstr[0] = 0;
+ break;
+ default:
+ strcpy(opstr, " !UNK! ");
+ break;
+ }
+ for (i=0; i<e->numterms; i++) {
+ switch (e->terms[i].type) {
+ case YASM_EXPR_PRECBC:
+ fprintf(f, "{%lx}",
+ yasm_bc_next_offset(e->terms[i].data.precbc));
+ break;
+ case YASM_EXPR_SYM:
+ fprintf(f, "%s", yasm_symrec_get_name(e->terms[i].data.sym));
+ break;
+ case YASM_EXPR_EXPR:
+ fprintf(f, "(");
+ yasm_expr_print(e->terms[i].data.expn, f);
+ fprintf(f, ")");
+ break;
+ case YASM_EXPR_INT:
+ yasm_intnum_print(e->terms[i].data.intn, f);
+ break;
+ case YASM_EXPR_FLOAT:
+ yasm_floatnum_print(e->terms[i].data.flt, f);
+ break;
+ case YASM_EXPR_REG:
+ /* FIXME */
+ /*yasm_arch_reg_print(arch, e->terms[i].data.reg, f);*/
+ break;
+ case YASM_EXPR_SUBST:
+ fprintf(f, "[%u]", e->terms[i].data.subst);
+ break;
+ case YASM_EXPR_NONE:
+ break;
+ }
+ if (i < e->numterms-1)
+ fprintf(f, "%s", opstr);
+ }
+}
+
+unsigned int
+yasm_expr_size(const yasm_expr *e)
+{
+ int i;
+ int seen = 0;
+ unsigned int size = 0, newsize;
+
+ if (e->op == YASM_EXPR_IDENT) {
+ if (e->terms[0].type == YASM_EXPR_SYM)
+ return yasm_symrec_get_size(e->terms[0].data.sym);
+ return 0;
+ }
+ if (e->op != YASM_EXPR_ADD && e->op != YASM_EXPR_SUB)
+ return 0;
+
+ for (i=0; i<e->numterms; i++) {
+ newsize = 0;
+ switch (e->terms[i].type) {
+ case YASM_EXPR_EXPR:
+ newsize = yasm_expr_size(e->terms[i].data.expn);
+ break;
+ case YASM_EXPR_SYM:
+ newsize = yasm_symrec_get_size(e->terms[i].data.sym);
+ break;
+ default:
+ break;
+ }
+ if (newsize) {
+ size = newsize;
+ if (seen)
+ /* either sum of idents (?!) or substract of idents */
+ return 0;
+ seen = 1;
+ }
+ }
+ /* exactly one offset */
+ return size;
+}
+
+const char *
+yasm_expr_segment(const yasm_expr *e)
+{
+ int i;
+ int seen = 0;
+ const char *segment = NULL;
+
+ if (e->op == YASM_EXPR_IDENT) {
+ if (e->terms[0].type == YASM_EXPR_SYM)
+ return yasm_symrec_get_segment(e->terms[0].data.sym);
+ return NULL;
+ }
+ if (e->op != YASM_EXPR_ADD && e->op != YASM_EXPR_SUB)
+ return NULL;
+
+ for (i=0; i<e->numterms; i++) {
+ if ((e->op == YASM_EXPR_ADD || !i) &&
+ e->terms[i].type == YASM_EXPR_EXPR) {
+ if ((segment = yasm_expr_segment(e->terms[i].data.expn))) {
+ if (seen) {
+ /* either sum of idents (?!) or substract of idents */
+ return NULL;
+ }
+ seen = 1;
+ }
+ }
+ }
+ /* exactly one offset */
+ return segment;
+}
diff --git a/libyasm/expr.h b/libyasm/expr.h
new file mode 100644
index 0000000..2b06cd3
--- /dev/null
+++ b/libyasm/expr.h
@@ -0,0 +1,386 @@
+/**
+ * \file libyasm/expr.h
+ * \brief YASM expression interface.
+ *
+ * \license
+ * Copyright (C) 2001-2007 Michael Urman, Peter Johnson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * \endlicense
+ */
+#ifndef YASM_EXPR_H
+#define YASM_EXPR_H
+
+#ifndef YASM_LIB_DECL
+#define YASM_LIB_DECL
+#endif
+
+/** Type of an expression item. Types are listed in canonical sorting order.
+ * See expr_order_terms().
+ * Note #YASM_EXPR_PRECBC must be used carefully (in a-b pairs), as only
+ * symrecs can become the relative term in a #yasm_value.
+ */
+typedef enum yasm_expr__type {
+ YASM_EXPR_NONE = 0, /**< Nothing */
+ YASM_EXPR_REG = 1<<0, /**< Register */
+ YASM_EXPR_INT = 1<<1, /**< Integer value */
+ YASM_EXPR_SUBST = 1<<2, /**< Substitution placeholder */
+ YASM_EXPR_FLOAT = 1<<3, /**< Floating point value */
+ YASM_EXPR_SYM = 1<<4, /**< Symbol */
+ YASM_EXPR_PRECBC = 1<<5,/**< Direct bytecode ref (rather than via sym) */
+ YASM_EXPR_EXPR = 1<<6 /**< Subexpression */
+} yasm_expr__type;
+
+/** Expression item. */
+typedef struct yasm_expr__item {
+ yasm_expr__type type; /**< Type */
+
+ /** Expression item data. Correct value depends on type. */
+ union {
+ yasm_bytecode *precbc; /**< Direct bytecode ref (YASM_EXPR_PRECBC) */
+ yasm_symrec *sym; /**< Symbol (YASM_EXPR_SYM) */
+ yasm_expr *expn; /**< Subexpression (YASM_EXPR_EXPR) */
+ yasm_intnum *intn; /**< Integer value (YASM_EXPR_INT) */
+ yasm_floatnum *flt; /**< Floating point value (YASM_EXPR_FLOAT) */
+ uintptr_t reg; /**< Register (YASM_EXPR_REG) */
+ unsigned int subst; /**< Subst placeholder (YASM_EXPR_SUBST) */
+ } data;
+} yasm_expr__item;
+
+/** Expression. */
+struct yasm_expr {
+ yasm_expr_op op; /**< Operation. */
+ unsigned long line; /**< Line number where expression was defined. */
+ int numterms; /**< Number of terms in the expression. */
+
+ /** Terms of the expression. Structure may be extended to include more
+ * terms, as some operations may allow more than two operand terms
+ * (ADD, MUL, OR, AND, XOR).
+ */
+ yasm_expr__item terms[2];
+};
+
+/** Create a new expression e=a op b.
+ * \param op operation
+ * \param a expression item a
+ * \param b expression item b (optional depending on op)
+ * \param line virtual line (where expression defined)
+ * \return Newly allocated expression.
+ */
+YASM_LIB_DECL
+/*@only@*/ yasm_expr *yasm_expr_create
+ (yasm_expr_op op, /*@only@*/ yasm_expr__item *a,
+ /*@only@*/ /*@null@*/ yasm_expr__item *b, unsigned long line);
+
+/** Create a new preceding-bytecode expression item.
+ * \param precbc preceding bytecode
+ * \return Newly allocated expression item.
+ */
+YASM_LIB_DECL
+/*@only@*/ yasm_expr__item *yasm_expr_precbc(/*@keep@*/ yasm_bytecode *precbc);
+
+/** Create a new symbol expression item.
+ * \param sym symbol
+ * \return Newly allocated expression item.
+ */
+YASM_LIB_DECL
+/*@only@*/ yasm_expr__item *yasm_expr_sym(/*@keep@*/ yasm_symrec *sym);
+
+/** Create a new expression expression item.
+ * \param e expression
+ * \return Newly allocated expression item.
+ */
+YASM_LIB_DECL
+/*@only@*/ yasm_expr__item *yasm_expr_expr(/*@keep@*/ yasm_expr *e);
+
+/** Create a new intnum expression item.
+ * \param intn intnum
+ * \return Newly allocated expression item.
+ */
+YASM_LIB_DECL
+/*@only@*/ yasm_expr__item *yasm_expr_int(/*@keep@*/ yasm_intnum *intn);
+
+/** Create a new floatnum expression item.
+ * \param flt floatnum
+ * \return Newly allocated expression item.
+ */
+YASM_LIB_DECL
+/*@only@*/ yasm_expr__item *yasm_expr_float(/*@keep@*/ yasm_floatnum *flt);
+
+/** Create a new register expression item.
+ * \param reg register
+ * \return Newly allocated expression item.
+ */
+YASM_LIB_DECL
+/*@only@*/ yasm_expr__item *yasm_expr_reg(uintptr_t reg);
+
+/** Create a new expression tree e=l op r.
+ * \param l expression for left side of new expression
+ * \param o operation
+ * \param r expression for right side of new expression
+ * \param i line index
+ * \return Newly allocated expression.
+ */
+#define yasm_expr_create_tree(l,o,r,i) \
+ yasm_expr_create ((o), yasm_expr_expr(l), yasm_expr_expr(r), i)
+
+/** Create a new expression branch e=op r.
+ * \param o operation
+ * \param r expression for right side of new expression
+ * \param i line index
+ * \return Newly allocated expression.
+ */
+#define yasm_expr_create_branch(o,r,i) \
+ yasm_expr_create ((o), yasm_expr_expr(r), (yasm_expr__item *)NULL, i)
+
+/** Create a new expression identity e=r.
+ * \param r expression for identity within new expression
+ * \param i line index
+ * \return Newly allocated expression.
+ */
+#define yasm_expr_create_ident(r,i) \
+ yasm_expr_create (YASM_EXPR_IDENT, (r), (yasm_expr__item *)NULL, i)
+
+/** Duplicate an expression.
+ * \param e expression
+ * \return Newly allocated expression identical to e.
+ */
+yasm_expr *yasm_expr_copy(const yasm_expr *e);
+#ifndef YASM_DOXYGEN
+#define yasm_expr_copy(e) yasm_expr__copy_except(e, -1)
+#endif
+
+/** Destroy (free allocated memory for) an expression.
+ * \param e expression
+ */
+YASM_LIB_DECL
+void yasm_expr_destroy(/*@only@*/ /*@null@*/ yasm_expr *e);
+
+/** Determine if an expression is a specified operation (at the top level).
+ * \param e expression
+ * \param op operator
+ * \return Nonzero if the expression was the specified operation at the top
+ * level, zero otherwise.
+ */
+YASM_LIB_DECL
+int yasm_expr_is_op(const yasm_expr *e, yasm_expr_op op);
+
+/** Extra transformation function for yasm_expr__level_tree().
+ * \param e expression being simplified
+ * \param d data provided as expr_xform_extra_data to
+ * yasm_expr__level_tree()
+ * \return Transformed e.
+ */
+typedef /*@only@*/ yasm_expr * (*yasm_expr_xform_func)
+ (/*@returned@*/ /*@only@*/ yasm_expr *e, /*@null@*/ void *d);
+
+/** Level an entire expression tree.
+ * \internal
+ * \param e expression
+ * \param fold_const enable constant folding if nonzero
+ * \param simplify_ident simplify identities
+ * \param simplify_reg_mul simplify REG*1 identities
+ * \param calc_bc_dist nonzero if distances between bytecodes should be
+ * calculated, 0 if they should be left intact
+ * \param expr_xform_extra extra transformation function
+ * \param expr_xform_extra_data data to pass to expr_xform_extra
+ * \return Leveled expression.
+ */
+YASM_LIB_DECL
+/*@only@*/ /*@null@*/ yasm_expr *yasm_expr__level_tree
+ (/*@returned@*/ /*@only@*/ /*@null@*/ yasm_expr *e, int fold_const,
+ int simplify_ident, int simplify_reg_mul, int calc_bc_dist,
+ /*@null@*/ yasm_expr_xform_func expr_xform_extra,
+ /*@null@*/ void *expr_xform_extra_data);
+
+/** Simplify an expression as much as possible. Eliminates extraneous
+ * branches and simplifies integer-only subexpressions. Simplified version
+ * of yasm_expr__level_tree().
+ * \param e expression
+ * \param cbd if distance between bytecodes should be calculated
+ * \return Simplified expression.
+ */
+#define yasm_expr_simplify(e, cbd) \
+ yasm_expr__level_tree(e, 1, 1, 1, cbd, NULL, NULL)
+
+/** Extract the segment portion of an expression containing SEG:OFF, leaving
+ * the offset.
+ * \param ep expression (pointer to)
+ * \return NULL if unable to extract a segment (expr does not contain a
+ * YASM_EXPR_SEGOFF operator), otherwise the segment expression.
+ * The input expression is modified such that on return, it's the
+ * offset expression.
+ */
+YASM_LIB_DECL
+/*@only@*/ /*@null@*/ yasm_expr *yasm_expr_extract_deep_segoff(yasm_expr **ep);
+
+/** Extract the segment portion of a SEG:OFF expression, leaving the offset.
+ * \param ep expression (pointer to)
+ * \return NULL if unable to extract a segment (YASM_EXPR_SEGOFF not the
+ * top-level operator), otherwise the segment expression. The input
+ * expression is modified such that on return, it's the offset
+ * expression.
+ */
+YASM_LIB_DECL
+/*@only@*/ /*@null@*/ yasm_expr *yasm_expr_extract_segoff(yasm_expr **ep);
+
+/** Extract the right portion (y) of a x WRT y expression, leaving the left
+ * portion (x).
+ * \param ep expression (pointer to)
+ * \return NULL if unable to extract (YASM_EXPR_WRT not the top-level
+ * operator), otherwise the right side of the WRT expression. The
+ * input expression is modified such that on return, it's the left side
+ * of the WRT expression.
+ */
+YASM_LIB_DECL
+/*@only@*/ /*@null@*/ yasm_expr *yasm_expr_extract_wrt(yasm_expr **ep);
+
+/** Get the integer value of an expression if it's just an integer.
+ * \param ep expression (pointer to)
+ * \param calc_bc_dist nonzero if distances between bytecodes should be
+ * calculated, 0 if NULL should be returned in this case
+ * \return NULL if the expression is too complex (contains anything other than
+ * integers, ie floats, non-valued labels, registers); otherwise the
+ * intnum value of the expression.
+ */
+YASM_LIB_DECL
+/*@dependent@*/ /*@null@*/ yasm_intnum *yasm_expr_get_intnum
+ (yasm_expr **ep, int calc_bc_dist);
+
+/** Get the symbol value of an expression if it's just a symbol.
+ * \param ep expression (pointer to)
+ * \param simplify if nonzero, simplify the expression first
+ * \return NULL if the expression is too complex; otherwise the symbol value of
+ * the expression.
+ */
+YASM_LIB_DECL
+/*@dependent@*/ /*@null@*/ const yasm_symrec *yasm_expr_get_symrec
+ (yasm_expr **ep, int simplify);
+
+/** Get the register value of an expression if it's just a register.
+ * \param ep expression (pointer to)
+ * \param simplify if nonzero, simplify the expression first
+ * \return NULL if the expression is too complex; otherwise the register value
+ * of the expression.
+ */
+YASM_LIB_DECL
+/*@dependent@*/ /*@null@*/ const uintptr_t *yasm_expr_get_reg
+ (yasm_expr **ep, int simplify);
+
+/** Print an expression. For debugging purposes.
+ * \param e expression
+ * \param f file
+ */
+YASM_LIB_DECL
+void yasm_expr_print(/*@null@*/ const yasm_expr *e, FILE *f);
+
+/** Return the size of an expression, if the user provided it
+ * \param e expression
+ */
+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
+ * \param d data passed to each call to func
+ * \param func callback function
+ * \return Stops early (and returns 1) if func returns 1.
+ * Otherwise returns 0.
+ */
+YASM_LIB_DECL
+int yasm_expr__traverse_leaves_in_const
+ (const yasm_expr *e, /*@null@*/ void *d,
+ int (*func) (/*@null@*/ const yasm_expr__item *ei, /*@null@*/ void *d));
+
+/** Traverse over expression tree in order.
+ * Calls func for each leaf (non-operation).
+ * \param e expression
+ * \param d data passed to each call to func
+ * \param func callback function
+ * \return Stops early (and returns 1) if func returns 1.
+ * Otherwise returns 0.
+ */
+YASM_LIB_DECL
+int yasm_expr__traverse_leaves_in
+ (yasm_expr *e, /*@null@*/ void *d,
+ int (*func) (/*@null@*/ yasm_expr__item *ei, /*@null@*/ void *d));
+
+/** Reorder terms of e into canonical order. Only reorders if reordering
+ * doesn't change meaning of expression. (eg, doesn't reorder SUB).
+ * Canonical order: REG, INT, FLOAT, SYM, EXPR.
+ * Multiple terms of a single type are kept in the same order as in
+ * the original expression.
+ * \param e expression
+ * \note Only performs reordering on *one* level (no recursion).
+ */
+YASM_LIB_DECL
+void yasm_expr__order_terms(yasm_expr *e);
+
+/** Copy entire expression EXCEPT for index "except" at *top level only*.
+ * \param e expression
+ * \param except term index not to copy; -1 to copy all terms
+ * \return Newly allocated copy of expression.
+ */
+YASM_LIB_DECL
+yasm_expr *yasm_expr__copy_except(const yasm_expr *e, int except);
+
+/** Test if expression contains an item. Searches recursively into
+ * subexpressions.
+ * \param e expression
+ * \param t type of item to look for
+ * \return Nonzero if expression contains an item of type t, zero if not.
+ */
+YASM_LIB_DECL
+int yasm_expr__contains(const yasm_expr *e, yasm_expr__type t);
+
+/** Transform symrec-symrec terms in expression into #YASM_EXPR_SUBST items.
+ * Calls the callback function for each symrec-symrec term.
+ * \param ep expression (pointer to)
+ * \param cbd callback data passed to callback function
+ * \param callback callback function: given subst index for bytecode
+ * pair, bytecode pair (bc2-bc1), and cbd (callback data)
+ * \return Number of transformations made.
+ */
+YASM_LIB_DECL
+int yasm_expr__bc_dist_subst(yasm_expr **ep, void *cbd,
+ void (*callback) (unsigned int subst,
+ yasm_bytecode *precbc,
+ yasm_bytecode *precbc2,
+ void *cbd));
+
+/** Substitute items into expr YASM_EXPR_SUBST items (by index). Items are
+ * copied, so caller is responsible for freeing array of items.
+ * \param e expression
+ * \param num_items number of items in items array
+ * \param items items array
+ * \return 1 on error (index out of range).
+ */
+YASM_LIB_DECL
+int yasm_expr__subst(yasm_expr *e, unsigned int num_items,
+ const yasm_expr__item *items);
+
+#endif
diff --git a/libyasm/file.c b/libyasm/file.c
new file mode 100644
index 0000000..fc7dab6
--- /dev/null
+++ b/libyasm/file.c
@@ -0,0 +1,672 @@
+/*
+ * File helper functions.
+ *
+ * Copyright (C) 2001-2007 Peter Johnson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <util.h>
+
+/* Need either unistd.h or direct.h to prototype getcwd() and mkdir() */
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef HAVE_DIRECT_H
+#include <direct.h>
+#endif
+
+#ifdef _WIN32
+#include <io.h>
+#endif
+
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+
+#include <ctype.h>
+#include <errno.h>
+
+#include "errwarn.h"
+#include "file.h"
+
+#define BSIZE 8192 /* Fill block size */
+
+
+void
+yasm_scanner_initialize(yasm_scanner *s)
+{
+ s->bot = NULL;
+ s->tok = NULL;
+ s->ptr = NULL;
+ s->cur = NULL;
+ s->lim = NULL;
+ s->top = NULL;
+ s->eof = NULL;
+}
+
+void
+yasm_scanner_delete(yasm_scanner *s)
+{
+ if (s->bot) {
+ yasm_xfree(s->bot);
+ s->bot = NULL;
+ }
+}
+
+int
+yasm_fill_helper(yasm_scanner *s, unsigned char **cursor,
+ size_t (*input_func) (void *d, unsigned char *buf,
+ size_t max),
+ void *input_func_data)
+{
+ size_t cnt;
+ int first = 0;
+
+ if (s->eof)
+ return 0;
+
+ cnt = s->tok - s->bot;
+ if (cnt > 0) {
+ memmove(s->bot, s->tok, (size_t)(s->lim - s->tok));
+ s->tok = s->bot;
+ s->ptr -= cnt;
+ *cursor -= cnt;
+ s->lim -= cnt;
+ }
+ if (!s->bot)
+ first = 1;
+ if ((s->top - s->lim) < BSIZE) {
+ unsigned char *buf = yasm_xmalloc((size_t)(s->lim - s->bot) + BSIZE);
+ memcpy(buf, s->tok, (size_t)(s->lim - s->tok));
+ s->tok = buf;
+ s->ptr = &buf[s->ptr - s->bot];
+ *cursor = &buf[*cursor - s->bot];
+ s->lim = &buf[s->lim - s->bot];
+ s->top = &s->lim[BSIZE];
+ if (s->bot)
+ yasm_xfree(s->bot);
+ s->bot = buf;
+ }
+ if ((cnt = input_func(input_func_data, s->lim, BSIZE)) == 0) {
+ s->eof = &s->lim[cnt];
+ *s->eof++ = '\n';
+ }
+ s->lim += cnt;
+ return first;
+}
+
+void
+yasm_unescape_cstring(unsigned char *str, size_t *len)
+{
+ unsigned char *s = str;
+ unsigned char *o = str;
+ unsigned char t[4];
+
+ while ((size_t)(s-str)<*len) {
+ if (*s == '\\' && (size_t)(&s[1]-str)<*len) {
+ s++;
+ switch (*s) {
+ case 'b': *o = '\b'; s++; break;
+ case 'f': *o = '\f'; s++; break;
+ case 'n': *o = '\n'; s++; break;
+ case 'r': *o = '\r'; s++; break;
+ case 't': *o = '\t'; s++; break;
+ case 'x':
+ /* hex escape; grab last two digits */
+ s++;
+ while ((size_t)(&s[2]-str)<*len && isxdigit(s[0])
+ && isxdigit(s[1]) && isxdigit(s[2]))
+ s++;
+ if ((size_t)(s-str)<*len && isxdigit(*s)) {
+ t[0] = *s++;
+ t[1] = '\0';
+ t[2] = '\0';
+ if ((size_t)(s-str)<*len && isxdigit(*s))
+ t[1] = *s++;
+ *o = (unsigned char)strtoul((char *)t, NULL, 16);
+ } else
+ *o = '\0';
+ break;
+ default:
+ if (isdigit(*s)) {
+ int warn = 0;
+ /* octal escape */
+ if (*s > '7')
+ warn = 1;
+ *o = *s++ - '0';
+ if ((size_t)(s-str)<*len && isdigit(*s)) {
+ if (*s > '7')
+ warn = 1;
+ *o <<= 3;
+ *o += *s++ - '0';
+ if ((size_t)(s-str)<*len && isdigit(*s)) {
+ if (*s > '7')
+ warn = 1;
+ *o <<= 3;
+ *o += *s++ - '0';
+ }
+ }
+ if (warn)
+ yasm_warn_set(YASM_WARN_GENERAL,
+ N_("octal value out of range"));
+ } else
+ *o = *s++;
+ break;
+ }
+ o++;
+ } else
+ *o++ = *s++;
+ }
+ *len = o-str;
+}
+
+size_t
+yasm__splitpath_unix(const char *path, /*@out@*/ const char **tail)
+{
+ const char *s;
+ s = strrchr(path, '/');
+ if (!s) {
+ /* No head */
+ *tail = path;
+ return 0;
+ }
+ *tail = s+1;
+ /* Strip trailing ./ on path */
+ while ((s-1)>=path && *(s-1) == '.' && *s == '/'
+ && !((s-2)>=path && *(s-2) == '.'))
+ s -= 2;
+ /* Strip trailing slashes on path (except leading) */
+ while (s>path && *s == '/')
+ s--;
+ /* Return length of head */
+ return s-path+1;
+}
+
+size_t
+yasm__splitpath_win(const char *path, /*@out@*/ const char **tail)
+{
+ const char *basepath = path;
+ const char *s;
+
+ /* split off drive letter first, if any */
+ if (isalpha(path[0]) && path[1] == ':')
+ basepath += 2;
+
+ s = basepath;
+ while (*s != '\0')
+ s++;
+ while (s >= basepath && *s != '\\' && *s != '/')
+ s--;
+ if (s < basepath) {
+ *tail = basepath;
+ if (path == basepath)
+ return 0; /* No head */
+ else
+ return 2; /* Drive letter is head */
+ }
+ *tail = s+1;
+ /* Strip trailing .\ or ./ on path */
+ while ((s-1)>=basepath && *(s-1) == '.' && (*s == '/' || *s == '\\')
+ && !((s-2)>=basepath && *(s-2) == '.'))
+ s -= 2;
+ /* Strip trailing slashes on path (except leading) */
+ while (s>basepath && (*s == '/' || *s == '\\'))
+ s--;
+ /* Return length of head */
+ return s-path+1;
+}
+
+char *
+yasm__getcwd(void)
+{
+ char *buf;
+ size_t size;
+
+ size = 1024;
+ buf = yasm_xmalloc(size);
+
+ if (getenv("YASM_TEST_SUITE")) {
+ strcpy(buf, "./");
+ return buf;
+ }
+
+ while (getcwd(buf, size-1) == NULL) {
+ if (errno != ERANGE) {
+ yasm__fatal(N_("could not determine current working directory"));
+ yasm_xfree(buf);
+ return NULL;
+ }
+ size *= 2;
+ buf = yasm_xrealloc(buf, size);
+ }
+
+ /* append a '/' if not already present */
+ size = strlen(buf);
+ if (buf[size-1] != '\\' && buf[size-1] != '/') {
+ buf[size] = '/';
+ buf[size+1] = '\0';
+ }
+ return buf;
+}
+
+char *
+yasm__abspath(const char *path)
+{
+ char *curdir, *abspath;
+
+ curdir = yasm__getcwd();
+ abspath = yasm__combpath(curdir, path);
+ yasm_xfree(curdir);
+
+ return abspath;
+}
+
+char *
+yasm__combpath_unix(const char *from, const char *to)
+{
+ const char *tail;
+ size_t pathlen, i, j;
+ char *out;
+
+ if (to[0] == '/') {
+ /* absolute "to" */
+ out = yasm_xmalloc(strlen(to)+1);
+ /* Combine any double slashes when copying */
+ for (j=0; *to; to++) {
+ if (*to == '/' && *(to+1) == '/')
+ continue;
+ out[j++] = *to;
+ }
+ out[j++] = '\0';
+ return out;
+ }
+
+ /* Get path component; note this strips trailing slash */
+ pathlen = yasm__splitpath_unix(from, &tail);
+
+ out = yasm_xmalloc(pathlen+strlen(to)+2); /* worst case maximum len */
+
+ /* Combine any double slashes when copying */
+ for (i=0, j=0; i<pathlen; i++) {
+ if (i<pathlen-1 && from[i] == '/' && from[i+1] == '/')
+ continue;
+ out[j++] = from[i];
+ }
+ pathlen = j;
+
+ /* Add trailing slash back in */
+ if (pathlen > 0 && out[pathlen-1] != '/')
+ out[pathlen++] = '/';
+
+ /* Now scan from left to right through "to", stripping off "." and "..";
+ * if we see "..", back up one directory in out unless last directory in
+ * out is also "..".
+ *
+ * Note this does NOT back through ..'s in the "from" path; this is just
+ * as well as that could skip symlinks (e.g. "foo/bar/.." might not be
+ * the same as "foo").
+ */
+ for (;;) {
+ if (to[0] == '.' && to[1] == '/') {
+ to += 2; /* current directory */
+ while (*to == '/')
+ to++; /* strip off any additional slashes */
+ } else if (pathlen == 0)
+ break; /* no more "from" path left, we're done */
+ else if (to[0] == '.' && to[1] == '.' && to[2] == '/') {
+ if (pathlen >= 3 && out[pathlen-1] == '/' && out[pathlen-2] == '.'
+ && out[pathlen-3] == '.') {
+ /* can't ".." against a "..", so we're done. */
+ break;
+ }
+
+ to += 3; /* throw away "../" */
+ while (*to == '/')
+ to++; /* strip off any additional slashes */
+
+ /* and back out last directory in "out" if not already at root */
+ if (pathlen > 1) {
+ pathlen--; /* strip off trailing '/' */
+ while (pathlen > 0 && out[pathlen-1] != '/')
+ pathlen--;
+ }
+ } else
+ break;
+ }
+
+ /* Copy "to" to tail of output, and we're done */
+ /* Combine any double slashes when copying */
+ for (j=pathlen; *to; to++) {
+ if (*to == '/' && *(to+1) == '/')
+ continue;
+ out[j++] = *to;
+ }
+ out[j++] = '\0';
+
+ return out;
+}
+
+char *
+yasm__combpath_win(const char *from, const char *to)
+{
+ const char *tail;
+ size_t pathlen, i, j;
+ char *out;
+
+ if ((isalpha(to[0]) && to[1] == ':') || (to[0] == '/' || to[0] == '\\')) {
+ /* absolute or drive letter "to" */
+ out = yasm_xmalloc(strlen(to)+1);
+ /* Combine any double slashes when copying */
+ for (j=0; *to; to++) {
+ if ((*to == '/' || *to == '\\')
+ && (*(to+1) == '/' || *(to+1) == '\\'))
+ continue;
+ if (*to == '/')
+ out[j++] = '\\';
+ else
+ out[j++] = *to;
+ }
+ out[j++] = '\0';
+ return out;
+ }
+
+ /* Get path component; note this strips trailing slash */
+ pathlen = yasm__splitpath_win(from, &tail);
+
+ out = yasm_xmalloc(pathlen+strlen(to)+2); /* worst case maximum len */
+
+ /* Combine any double slashes when copying */
+ for (i=0, j=0; i<pathlen; i++) {
+ if (i<pathlen-1 && (from[i] == '/' || from[i] == '\\')
+ && (from[i+1] == '/' || from[i+1] == '\\'))
+ continue;
+ if (from[i] == '/')
+ out[j++] = '\\';
+ else
+ out[j++] = from[i];
+ }
+ pathlen = j;
+
+ /* Add trailing slash back in, unless it's only a raw drive letter */
+ if (pathlen > 0 && out[pathlen-1] != '\\'
+ && !(pathlen == 2 && isalpha(out[0]) && out[1] == ':'))
+ out[pathlen++] = '\\';
+
+ /* Now scan from left to right through "to", stripping off "." and "..";
+ * if we see "..", back up one directory in out unless last directory in
+ * out is also "..".
+ *
+ * Note this does NOT back through ..'s in the "from" path; this is just
+ * as well as that could skip symlinks (e.g. "foo/bar/.." might not be
+ * the same as "foo").
+ */
+ for (;;) {
+ if (to[0] == '.' && (to[1] == '/' || to[1] == '\\')) {
+ to += 2; /* current directory */
+ while (*to == '/' || *to == '\\')
+ to++; /* strip off any additional slashes */
+ } else if (pathlen == 0
+ || (pathlen == 2 && isalpha(out[0]) && out[1] == ':'))
+ break; /* no more "from" path left, we're done */
+ else if (to[0] == '.' && to[1] == '.'
+ && (to[2] == '/' || to[2] == '\\')) {
+ if (pathlen >= 3 && out[pathlen-1] == '\\'
+ && out[pathlen-2] == '.' && out[pathlen-3] == '.') {
+ /* can't ".." against a "..", so we're done. */
+ break;
+ }
+
+ to += 3; /* throw away "../" (or "..\") */
+ while (*to == '/' || *to == '\\')
+ to++; /* strip off any additional slashes */
+
+ /* and back out last directory in "out" if not already at root */
+ if (pathlen > 1) {
+ pathlen--; /* strip off trailing '/' */
+ while (pathlen > 0 && out[pathlen-1] != '\\')
+ pathlen--;
+ }
+ } else
+ break;
+ }
+
+ /* Copy "to" to tail of output, and we're done */
+ /* Combine any double slashes when copying */
+ for (j=pathlen; *to; to++) {
+ if ((*to == '/' || *to == '\\') && (*(to+1) == '/' || *(to+1) == '\\'))
+ continue;
+ if (*to == '/')
+ out[j++] = '\\';
+ else
+ out[j++] = *to;
+ }
+ out[j++] = '\0';
+
+ return out;
+}
+
+size_t
+yasm__createpath_common(const char *path, int win)
+{
+ const char *pp = path, *pe;
+ char *ts, *tp;
+ size_t len, lth;
+
+ lth = len = strlen(path);
+ ts = tp = (char *) malloc(len + 1);
+ pe = pp + len;
+ while (pe > pp) {
+ if ((win && *pe == '\\') || *pe == '/')
+ break;
+ --pe;
+ --lth;
+ }
+
+ while (pp <= pe) {
+ if (pp == pe || (win && *pp == '\\') || *pp == '/') {
+#ifdef _WIN32
+ struct _finddata_t fi;
+ intptr_t h;
+#elif defined(HAVE_SYS_STAT_H)
+ struct stat fi;
+#endif
+ *tp = '\0';
+
+#ifdef _WIN32
+ h = _findfirst(ts, &fi);
+ if (h != -1) {
+ if (fi.attrib != _A_SUBDIR) {
+ _findclose(h);
+ break;
+ }
+ } else if (errno == ENOENT) {
+ if (_mkdir(ts) == -1) {
+ _findclose(h);
+ lth = -1;
+ break;
+ }
+ }
+ _findclose(h);
+#elif defined(HAVE_SYS_STAT_H)
+ if (stat(ts, &fi) != -1) {
+ if (!S_ISDIR(fi.st_mode))
+ break;
+ } else if (errno == ENOENT) {
+ if (mkdir(ts, 0755) == -1) {
+ lth = 0;
+ break;
+ }
+ }
+#else
+ break;
+#endif
+ }
+ *tp++ = *pp++;
+ }
+ free(ts);
+ return lth;
+}
+
+typedef struct incpath {
+ STAILQ_ENTRY(incpath) link;
+ /*@owned@*/ char *path;
+} incpath;
+
+STAILQ_HEAD(incpath_head, incpath) incpaths = STAILQ_HEAD_INITIALIZER(incpaths);
+
+FILE *
+yasm_fopen_include(const char *iname, const char *from, const char *mode,
+ char **oname)
+{
+ FILE *f;
+ char *combine;
+ incpath *np;
+
+ /* Try directly relative to from first, then each of the include paths */
+ if (from) {
+ combine = yasm__combpath(from, iname);
+ f = fopen(combine, mode);
+ if (f) {
+ if (oname)
+ *oname = combine;
+ else
+ yasm_xfree(combine);
+ return f;
+ }
+ yasm_xfree(combine);
+ }
+
+ STAILQ_FOREACH(np, &incpaths, link) {
+ combine = yasm__combpath(np->path, iname);
+ f = fopen(combine, mode);
+ if (f) {
+ if (oname)
+ *oname = combine;
+ else
+ yasm_xfree(combine);
+ return f;
+ }
+ yasm_xfree(combine);
+ }
+
+ if (oname)
+ *oname = NULL;
+ return NULL;
+}
+
+void
+yasm_delete_include_paths(void)
+{
+ incpath *n1, *n2;
+
+ n1 = STAILQ_FIRST(&incpaths);
+ while (n1) {
+ n2 = STAILQ_NEXT(n1, link);
+ yasm_xfree(n1->path);
+ yasm_xfree(n1);
+ n1 = n2;
+ }
+ STAILQ_INIT(&incpaths);
+}
+
+const char *
+yasm_get_include_dir(void **iter)
+{
+ incpath *p = (incpath *)*iter;
+
+ if (!p)
+ p = STAILQ_FIRST(&incpaths);
+ else
+ p = STAILQ_NEXT(p, link);
+
+ *iter = p;
+ if (p)
+ return p->path;
+ else
+ return NULL;
+}
+
+void
+yasm_add_include_path(const char *path)
+{
+ incpath *np = yasm_xmalloc(sizeof(incpath));
+ size_t len = strlen(path);
+
+ np->path = yasm_xmalloc(len+2);
+ memcpy(np->path, path, len+1);
+ /* Add trailing slash if it is missing */
+ if (path[len-1] != '\\' && path[len-1] != '/') {
+ np->path[len] = '/';
+ np->path[len+1] = '\0';
+ }
+
+ STAILQ_INSERT_TAIL(&incpaths, np, link);
+}
+
+size_t
+yasm_fwrite_16_l(unsigned short val, FILE *f)
+{
+ if (fputc(val & 0xFF, f) == EOF)
+ return 0;
+ if (fputc((val >> 8) & 0xFF, f) == EOF)
+ return 0;
+ return 1;
+}
+
+size_t
+yasm_fwrite_32_l(unsigned long val, FILE *f)
+{
+ if (fputc((int)(val & 0xFF), f) == EOF)
+ return 0;
+ if (fputc((int)((val >> 8) & 0xFF), f) == EOF)
+ return 0;
+ if (fputc((int)((val >> 16) & 0xFF), f) == EOF)
+ return 0;
+ if (fputc((int)((val >> 24) & 0xFF), f) == EOF)
+ return 0;
+ return 1;
+}
+
+size_t
+yasm_fwrite_16_b(unsigned short val, FILE *f)
+{
+ if (fputc((val >> 8) & 0xFF, f) == EOF)
+ return 0;
+ if (fputc(val & 0xFF, f) == EOF)
+ return 0;
+ return 1;
+}
+
+size_t
+yasm_fwrite_32_b(unsigned long val, FILE *f)
+{
+ if (fputc((int)((val >> 24) & 0xFF), f) == EOF)
+ return 0;
+ if (fputc((int)((val >> 16) & 0xFF), f) == EOF)
+ return 0;
+ if (fputc((int)((val >> 8) & 0xFF), f) == EOF)
+ return 0;
+ if (fputc((int)(val & 0xFF), f) == EOF)
+ return 0;
+ return 1;
+}
diff --git a/libyasm/file.h b/libyasm/file.h
new file mode 100644
index 0000000..1e9b87b
--- /dev/null
+++ b/libyasm/file.h
@@ -0,0 +1,525 @@
+/**
+ * \file libyasm/file.h
+ * \brief YASM file helpers.
+ *
+ * \license
+ * Copyright (C) 2001-2007 Peter Johnson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * \endlicense
+ */
+#ifndef YASM_FILE_H
+#define YASM_FILE_H
+
+#ifndef YASM_LIB_DECL
+#define YASM_LIB_DECL
+#endif
+
+/** Re2c scanner state. */
+typedef struct yasm_scanner {
+ unsigned char *bot; /**< Bottom of scan buffer */
+ unsigned char *tok; /**< Start of token */
+ unsigned char *ptr; /**< Scan marker */
+ unsigned char *cur; /**< Cursor (1 past end of token) */
+ unsigned char *lim; /**< Limit of good data */
+ unsigned char *top; /**< Top of scan buffer */
+ unsigned char *eof; /**< End of file */
+} yasm_scanner;
+
+/** Initialize scanner state.
+ * \param scanner Re2c scanner state
+ */
+YASM_LIB_DECL
+void yasm_scanner_initialize(yasm_scanner *scanner);
+
+/** Frees any memory used by scanner state; does not free state itself.
+ * \param scanner Re2c scanner state
+ */
+YASM_LIB_DECL
+void yasm_scanner_delete(yasm_scanner *scanner);
+
+/** Fill a scanner state structure with data coming from an input function.
+ * \param scanner Re2c scanner state
+ * \param cursor Re2c scan cursor
+ * \param input_func Input function to read data; takes buffer and maximum
+ * number of bytes, returns number of bytes read.
+ * \param input_func_data Data to pass as the first parameter to input_func
+ * \return 1 if this was the first time this function was called on this
+ * scanner state, 0 otherwise.
+ */
+YASM_LIB_DECL
+int yasm_fill_helper
+ (yasm_scanner *scanner, unsigned char **cursor,
+ size_t (*input_func) (void *d, unsigned char *buf, size_t max),
+ void *input_func_data);
+
+/** Unescape a string with C-style escapes. Handles b, f, n, r, t, and hex
+ * and octal escapes. String is updated in-place.
+ * Edge cases:
+ * - hex escapes: reads as many hex digits as possible, takes last 2 as value.
+ * - oct escapes: takes up to 3 digits 0-9 and scales appropriately, with
+ * warning.
+ * \param str C-style string (updated in place)
+ * \param len length of string (updated with new length)
+ */
+YASM_LIB_DECL
+void yasm_unescape_cstring(unsigned char *str, size_t *len);
+
+/** Split a UNIX pathname into head (directory) and tail (base filename)
+ * portions.
+ * \internal
+ * \param path pathname
+ * \param tail (returned) base filename
+ * \return Length of head (directory).
+ */
+YASM_LIB_DECL
+size_t yasm__splitpath_unix(const char *path, /*@out@*/ const char **tail);
+
+/** Split a Windows pathname into head (directory) and tail (base filename)
+ * portions.
+ * \internal
+ * \param path pathname
+ * \param tail (returned) base filename
+ * \return Length of head (directory).
+ */
+YASM_LIB_DECL
+size_t yasm__splitpath_win(const char *path, /*@out@*/ const char **tail);
+
+/** Split a pathname into head (directory) and tail (base filename) portions.
+ * Unless otherwise defined, defaults to yasm__splitpath_unix().
+ * \internal
+ * \param path pathname
+ * \param tail (returned) base filename
+ * \return Length of head (directory).
+ */
+#ifndef yasm__splitpath
+# if defined (_WIN32) || defined (WIN32) || defined (__MSDOS__) || \
+ defined (__DJGPP__) || defined (__OS2__)
+# define yasm__splitpath(path, tail) yasm__splitpath_win(path, tail)
+# else
+# define yasm__splitpath(path, tail) yasm__splitpath_unix(path, tail)
+# endif
+#endif
+
+/** Get the current working directory.
+ * \internal
+ * \return Current working directory pathname (newly allocated).
+ */
+YASM_LIB_DECL
+/*@only@*/ char *yasm__getcwd(void);
+
+/** Convert a relative or absolute pathname into an absolute pathname.
+ * \internal
+ * \param path pathname
+ * \return Absolute version of path (newly allocated).
+ */
+YASM_LIB_DECL
+/*@only@*/ char *yasm__abspath(const char *path);
+
+/** Build a UNIX pathname that is equivalent to accessing the "to" pathname
+ * when you're in the directory containing "from". Result is relative if both
+ * from and to are relative.
+ * \internal
+ * \param from from pathname
+ * \param to to pathname
+ * \return Combined path (newly allocated).
+ */
+YASM_LIB_DECL
+char *yasm__combpath_unix(const char *from, const char *to);
+
+/** Build a Windows pathname that is equivalent to accessing the "to" pathname
+ * when you're in the directory containing "from". Result is relative if both
+ * from and to are relative.
+ * \internal
+ * \param from from pathname
+ * \param to to pathname
+ * \return Combined path (newly allocated).
+ */
+YASM_LIB_DECL
+char *yasm__combpath_win(const char *from, const char *to);
+
+/** Build a pathname that is equivalent to accessing the "to" pathname
+ * when you're in the directory containing "from". Result is relative if both
+ * from and to are relative.
+ * Unless otherwise defined, defaults to yasm__combpath_unix().
+ * \internal
+ * \param from from pathname
+ * \param to to pathname
+ * \return Combined path (newly allocated).
+ */
+#ifndef yasm__combpath
+# if defined (_WIN32) || defined (WIN32) || defined (__MSDOS__) || \
+ defined (__DJGPP__) || defined (__OS2__)
+# define yasm__combpath(from, to) yasm__combpath_win(from, to)
+# else
+# define yasm__combpath(from, to) yasm__combpath_unix(from, to)
+# endif
+#endif
+
+/** Recursively create tree of directories needed for pathname.
+ * \internal
+ * \param path pathname
+ * \param win handle windows paths
+ * \return Length of directory portion of pathname.
+ */
+YASM_LIB_DECL
+size_t yasm__createpath_common(const char *path, int win);
+
+/** Recursively create tree of directories needed for pathname.
+ * Unless otherwise defined, defaults to yasm__createpath_unix().
+ * \internal
+ * \param path pathname
+ * \return Length of directory portion of pathname.
+ */
+#ifndef yasm__createpath
+# if defined (_WIN32) || defined (WIN32) || defined (__MSDOS__) || \
+ defined (__DJGPP__) || defined (__OS2__)
+# define yasm__createpath(path) yasm__createpath_common(path, 1)
+# else
+# define yasm__createpath(path) yasm__createpath_common(path, 0)
+# endif
+#endif
+
+/** Try to find and open an include file, searching through include paths.
+ * First iname is looked for relative to the directory containing "from", then
+ * it's looked for relative to each of the include paths.
+ *
+ * All pathnames may be either absolute or relative; from, oname, and
+ * include paths, if relative, are relative from the current working directory.
+ *
+ * First match wins; the full pathname (newly allocated) to the opened file
+ * is saved into oname, and the fopen'ed FILE * is returned. If not found,
+ * NULL is returned.
+ *
+ * \param iname file to include
+ * \param from file doing the including
+ * \param mode fopen mode string
+ * \param oname full pathname of included file (may be relative). NULL
+ * may be passed if this is unwanted.
+ * \return fopen'ed include file, or NULL if not found.
+ */
+YASM_LIB_DECL
+/*@null@*/ FILE *yasm_fopen_include
+ (const char *iname, const char *from, const char *mode,
+ /*@null@*/ /*@out@*/ /*@only@*/ char **oname);
+
+/** Delete any stored include paths added by yasm_add_include_path().
+ */
+YASM_LIB_DECL
+void yasm_delete_include_paths(void);
+
+/** Iterate through include paths.
+*/
+YASM_LIB_DECL
+const char * yasm_get_include_dir(void **iter);
+
+/** Add an include path for use by yasm_fopen_include().
+ * If path is relative, it is treated by yasm_fopen_include() as relative to
+ * the current working directory.
+ *
+ * \param path path to add
+ */
+YASM_LIB_DECL
+void yasm_add_include_path(const char *path);
+
+/** Write an 8-bit value to a buffer, incrementing buffer pointer.
+ * \note Only works properly if ptr is an (unsigned char *).
+ * \param ptr buffer
+ * \param val 8-bit value
+ */
+#define YASM_WRITE_8(ptr, val) \
+ *((ptr)++) = (unsigned char)((val) & 0xFF)
+
+/** Write a 16-bit value to a buffer in little endian, incrementing buffer
+ * pointer.
+ * \note Only works properly if ptr is an (unsigned char *).
+ * \param ptr buffer
+ * \param val 16-bit value
+ */
+#define YASM_WRITE_16_L(ptr, val) \
+ do { \
+ *((ptr)++) = (unsigned char)((val) & 0xFF); \
+ *((ptr)++) = (unsigned char)(((val) >> 8) & 0xFF); \
+ } while (0)
+
+/** Write a 32-bit value to a buffer in little endian, incrementing buffer
+ * pointer.
+ * \note Only works properly if ptr is an (unsigned char *).
+ * \param ptr buffer
+ * \param val 32-bit value
+ */
+#define YASM_WRITE_32_L(ptr, val) \
+ do { \
+ *((ptr)++) = (unsigned char)((val) & 0xFF); \
+ *((ptr)++) = (unsigned char)(((val) >> 8) & 0xFF); \
+ *((ptr)++) = (unsigned char)(((val) >> 16) & 0xFF); \
+ *((ptr)++) = (unsigned char)(((val) >> 24) & 0xFF); \
+ } while (0)
+
+/** Write a 16-bit value to a buffer in big endian, incrementing buffer
+ * pointer.
+ * \note Only works properly if ptr is an (unsigned char *).
+ * \param ptr buffer
+ * \param val 16-bit value
+ */
+#define YASM_WRITE_16_B(ptr, val) \
+ do { \
+ *((ptr)++) = (unsigned char)(((val) >> 8) & 0xFF); \
+ *((ptr)++) = (unsigned char)((val) & 0xFF); \
+ } while (0)
+
+/** Write a 32-bit value to a buffer in big endian, incrementing buffer
+ * pointer.
+ * \note Only works properly if ptr is an (unsigned char *).
+ * \param ptr buffer
+ * \param val 32-bit value
+ */
+#define YASM_WRITE_32_B(ptr, val) \
+ do { \
+ *((ptr)++) = (unsigned char)(((val) >> 24) & 0xFF); \
+ *((ptr)++) = (unsigned char)(((val) >> 16) & 0xFF); \
+ *((ptr)++) = (unsigned char)(((val) >> 8) & 0xFF); \
+ *((ptr)++) = (unsigned char)((val) & 0xFF); \
+ } while (0)
+
+
+/** Write an 8-bit value to a buffer. Does not increment buffer pointer.
+ * \note Only works properly if ptr is an (unsigned char *).
+ * \param ptr buffer
+ * \param val 8-bit value
+ */
+#define YASM_SAVE_8(ptr, val) \
+ *(ptr) = (unsigned char)((val) & 0xFF)
+
+/** Write a 16-bit value to a buffer in little endian. Does not increment
+ * buffer pointer.
+ * \note Only works properly if ptr is an (unsigned char *).
+ * \param ptr buffer
+ * \param val 16-bit value
+ */
+#define YASM_SAVE_16_L(ptr, val) \
+ do { \
+ *(ptr) = (unsigned char)((val) & 0xFF); \
+ *((ptr)+1) = (unsigned char)(((val) >> 8) & 0xFF); \
+ } while (0)
+
+/** Write a 32-bit value to a buffer in little endian. Does not increment
+ * buffer pointer.
+ * \note Only works properly if ptr is an (unsigned char *).
+ * \param ptr buffer
+ * \param val 32-bit value
+ */
+#define YASM_SAVE_32_L(ptr, val) \
+ do { \
+ *(ptr) = (unsigned char)((val) & 0xFF); \
+ *((ptr)+1) = (unsigned char)(((val) >> 8) & 0xFF); \
+ *((ptr)+2) = (unsigned char)(((val) >> 16) & 0xFF); \
+ *((ptr)+3) = (unsigned char)(((val) >> 24) & 0xFF); \
+ } while (0)
+
+/** Write a 16-bit value to a buffer in big endian. Does not increment buffer
+ * pointer.
+ * \note Only works properly if ptr is an (unsigned char *).
+ * \param ptr buffer
+ * \param val 16-bit value
+ */
+#define YASM_SAVE_16_B(ptr, val) \
+ do { \
+ *(ptr) = (unsigned char)(((val) >> 8) & 0xFF); \
+ *((ptr)+1) = (unsigned char)((val) & 0xFF); \
+ } while (0)
+
+/** Write a 32-bit value to a buffer in big endian. Does not increment buffer
+ * pointer.
+ * \note Only works properly if ptr is an (unsigned char *).
+ * \param ptr buffer
+ * \param val 32-bit value
+ */
+#define YASM_SAVE_32_B(ptr, val) \
+ do { \
+ *(ptr) = (unsigned char)(((val) >> 24) & 0xFF); \
+ *((ptr)+1) = (unsigned char)(((val) >> 16) & 0xFF); \
+ *((ptr)+2) = (unsigned char)(((val) >> 8) & 0xFF); \
+ *((ptr)+3) = (unsigned char)((val) & 0xFF); \
+ } while (0)
+
+/** Direct-to-file version of YASM_SAVE_16_L().
+ * \note Using the macro multiple times with a single fwrite() call will
+ * probably be faster than calling this function many times.
+ * \param val 16-bit value
+ * \param f file
+ * \return 1 if the write was successful, 0 if not (just like fwrite()).
+ */
+YASM_LIB_DECL
+size_t yasm_fwrite_16_l(unsigned short val, FILE *f);
+
+/** Direct-to-file version of YASM_SAVE_32_L().
+ * \note Using the macro multiple times with a single fwrite() call will
+ * probably be faster than calling this function many times.
+ * \param val 32-bit value
+ * \param f file
+ * \return 1 if the write was successful, 0 if not (just like fwrite()).
+ */
+YASM_LIB_DECL
+size_t yasm_fwrite_32_l(unsigned long val, FILE *f);
+
+/** Direct-to-file version of YASM_SAVE_16_B().
+ * \note Using the macro multiple times with a single fwrite() call will
+ * probably be faster than calling this function many times.
+ * \param val 16-bit value
+ * \param f file
+ * \return 1 if the write was successful, 0 if not (just like fwrite()).
+ */
+YASM_LIB_DECL
+size_t yasm_fwrite_16_b(unsigned short val, FILE *f);
+
+/** Direct-to-file version of YASM_SAVE_32_B().
+ * \note Using the macro multiple times with a single fwrite() call will
+ * probably be faster than calling this function many times.
+ * \param val 32-bit value
+ * \param f file
+ * \return 1 if the write was successful, 0 if not (just like fwrite()).
+ */
+YASM_LIB_DECL
+size_t yasm_fwrite_32_b(unsigned long val, FILE *f);
+
+/** Read an 8-bit value from a buffer, incrementing buffer pointer.
+ * \note Only works properly if ptr is an (unsigned char *).
+ * \param ptr buffer
+ * \param val 8-bit value
+ */
+#define YASM_READ_8(val, ptr) \
+ (val) = *((ptr)++) & 0xFF
+
+/** Read a 16-bit value from a buffer in little endian, incrementing buffer
+ * pointer.
+ * \note Only works properly if ptr is an (unsigned char *).
+ * \param ptr buffer
+ * \param val 16-bit value
+ */
+#define YASM_READ_16_L(val, ptr) \
+ do { \
+ (val) = *((ptr)++) & 0xFF; \
+ (val) |= (*((ptr)++) & 0xFF) << 8; \
+ } while (0)
+
+/** Read a 32-bit value from a buffer in little endian, incrementing buffer
+ * pointer.
+ * \note Only works properly if ptr is an (unsigned char *).
+ * \param ptr buffer
+ * \param val 32-bit value
+ */
+#define YASM_READ_32_L(val, ptr) \
+ do { \
+ (val) = *((ptr)++) & 0xFF; \
+ (val) |= (*((ptr)++) & 0xFF) << 8; \
+ (val) |= (*((ptr)++) & 0xFF) << 16; \
+ (val) |= (*((ptr)++) & 0xFF) << 24; \
+ } while (0)
+
+/** Read a 16-bit value from a buffer in big endian, incrementing buffer
+ * pointer.
+ * \note Only works properly if ptr is an (unsigned char *).
+ * \param ptr buffer
+ * \param val 16-bit value
+ */
+#define YASM_READ_16_B(val, ptr) \
+ do { \
+ (val) = (*((ptr)++) & 0xFF) << 8; \
+ (val) |= *((ptr)++) & 0xFF; \
+ } while (0)
+
+/** Read a 32-bit value from a buffer in big endian, incrementing buffer
+ * pointer.
+ * \note Only works properly if ptr is an (unsigned char *).
+ * \param ptr buffer
+ * \param val 32-bit value
+ */
+#define YASM_READ_32_B(val, ptr) \
+ do { \
+ (val) = (*((ptr)++) & 0xFF) << 24; \
+ (val) |= (*((ptr)++) & 0xFF) << 16; \
+ (val) |= (*((ptr)++) & 0xFF) << 8; \
+ (val) |= *((ptr)++) & 0xFF; \
+ } while (0)
+
+/** Read an 8-bit value from a buffer. Does not increment buffer pointer.
+ * \note Only works properly if ptr is an (unsigned char *).
+ * \param ptr buffer
+ * \param val 8-bit value
+ */
+#define YASM_LOAD_8(val, ptr) \
+ (val) = *(ptr) & 0xFF
+
+/** Read a 16-bit value from a buffer in little endian. Does not increment
+ * buffer pointer.
+ * \note Only works properly if ptr is an (unsigned char *).
+ * \param ptr buffer
+ * \param val 16-bit value
+ */
+#define YASM_LOAD_16_L(val, ptr) \
+ do { \
+ (val) = *(ptr) & 0xFF; \
+ (val) |= (*((ptr)+1) & 0xFF) << 8; \
+ } while (0)
+
+/** Read a 32-bit value from a buffer in little endian. Does not increment
+ * buffer pointer.
+ * \note Only works properly if ptr is an (unsigned char *).
+ * \param ptr buffer
+ * \param val 32-bit value
+ */
+#define YASM_LOAD_32_L(val, ptr) \
+ do { \
+ (val) = (unsigned long)(*(ptr) & 0xFF); \
+ (val) |= (unsigned long)((*((ptr)+1) & 0xFF) << 8); \
+ (val) |= (unsigned long)((*((ptr)+2) & 0xFF) << 16); \
+ (val) |= (unsigned long)((*((ptr)+3) & 0xFF) << 24); \
+ } while (0)
+
+/** Read a 16-bit value from a buffer in big endian. Does not increment buffer
+ * pointer.
+ * \note Only works properly if ptr is an (unsigned char *).
+ * \param ptr buffer
+ * \param val 16-bit value
+ */
+#define YASM_LOAD_16_B(val, ptr) \
+ do { \
+ (val) = (*(ptr) & 0xFF) << 8; \
+ (val) |= *((ptr)+1) & 0xFF; \
+ } while (0)
+
+/** Read a 32-bit value from a buffer in big endian. Does not increment buffer
+ * pointer.
+ * \note Only works properly if ptr is an (unsigned char *).
+ * \param ptr buffer
+ * \param val 32-bit value
+ */
+#define YASM_LOAD_32_B(val, ptr) \
+ do { \
+ (val) = (unsigned long)((*(ptr) & 0xFF) << 24); \
+ (val) |= (unsigned long)((*((ptr)+1) & 0xFF) << 16); \
+ (val) |= (unsigned long)((*((ptr)+2) & 0xFF) << 8); \
+ (val) |= (unsigned long)(*((ptr)+3) & 0xFF); \
+ } while (0)
+
+#endif
diff --git a/libyasm/floatnum.c b/libyasm/floatnum.c
new file mode 100644
index 0000000..ab67c2b
--- /dev/null
+++ b/libyasm/floatnum.c
@@ -0,0 +1,760 @@
+/*
+ * Floating point number functions.
+ *
+ * Copyright (C) 2001-2007 Peter Johnson
+ *
+ * Based on public-domain x86 assembly code by Randall Hyde (8/28/91).
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "util.h"
+
+#include <ctype.h>
+
+#include "coretype.h"
+#include "bitvect.h"
+#include "file.h"
+
+#include "errwarn.h"
+#include "floatnum.h"
+
+
+/* 97-bit internal floating point format:
+ * 0000000s eeeeeeee eeeeeeee m.....................................m
+ * Sign exponent mantissa (80 bits)
+ * 79 0
+ *
+ * Only L.O. bit of Sign byte is significant. The rest is zero.
+ * Exponent is bias 32767.
+ * Mantissa does NOT have an implied one bit (it's explicit).
+ */
+struct yasm_floatnum {
+ /*@only@*/ wordptr mantissa; /* Allocated to MANT_BITS bits */
+ unsigned short exponent;
+ unsigned char sign;
+ unsigned char flags;
+};
+
+/* constants describing parameters of internal floating point format */
+#define MANT_BITS 80
+#define MANT_BYTES 10
+#define MANT_SIGDIGITS 24
+#define EXP_BIAS 0x7FFF
+#define EXP_INF 0xFFFF
+#define EXP_MAX 0xFFFE
+#define EXP_MIN 1
+#define EXP_ZERO 0
+
+/* Flag settings for flags field */
+#define FLAG_ISZERO 1<<0
+
+/* Note this structure integrates the floatnum structure */
+typedef struct POT_Entry_s {
+ yasm_floatnum f;
+ int dec_exponent;
+} POT_Entry;
+
+/* "Source" for POT_Entry. */
+typedef struct POT_Entry_Source_s {
+ unsigned char mantissa[MANT_BYTES]; /* little endian mantissa */
+ unsigned short exponent; /* Bias 32767 exponent */
+} POT_Entry_Source;
+
+/* Power of ten tables used by the floating point I/O routines.
+ * The POT_Table? arrays are built from the POT_Table?_Source arrays at
+ * runtime by POT_Table_Init().
+ */
+
+/* This table contains the powers of ten raised to negative powers of two:
+ *
+ * entry[12-n] = 10 ** (-2 ** n) for 0 <= n <= 12.
+ * entry[13] = 1.0
+ */
+static /*@only@*/ POT_Entry *POT_TableN;
+static POT_Entry_Source POT_TableN_Source[] = {
+ {{0xe3,0x2d,0xde,0x9f,0xce,0xd2,0xc8,0x04,0xdd,0xa6},0x4ad8}, /* 1e-4096 */
+ {{0x25,0x49,0xe4,0x2d,0x36,0x34,0x4f,0x53,0xae,0xce},0x656b}, /* 1e-2048 */
+ {{0xa6,0x87,0xbd,0xc0,0x57,0xda,0xa5,0x82,0xa6,0xa2},0x72b5}, /* 1e-1024 */
+ {{0x33,0x71,0x1c,0xd2,0x23,0xdb,0x32,0xee,0x49,0x90},0x795a}, /* 1e-512 */
+ {{0x91,0xfa,0x39,0x19,0x7a,0x63,0x25,0x43,0x31,0xc0},0x7cac}, /* 1e-256 */
+ {{0x7d,0xac,0xa0,0xe4,0xbc,0x64,0x7c,0x46,0xd0,0xdd},0x7e55}, /* 1e-128 */
+ {{0x24,0x3f,0xa5,0xe9,0x39,0xa5,0x27,0xea,0x7f,0xa8},0x7f2a}, /* 1e-64 */
+ {{0xde,0x67,0xba,0x94,0x39,0x45,0xad,0x1e,0xb1,0xcf},0x7f94}, /* 1e-32 */
+ {{0x2f,0x4c,0x5b,0xe1,0x4d,0xc4,0xbe,0x94,0x95,0xe6},0x7fc9}, /* 1e-16 */
+ {{0xc2,0xfd,0xfc,0xce,0x61,0x84,0x11,0x77,0xcc,0xab},0x7fe4}, /* 1e-8 */
+ {{0xc3,0xd3,0x2b,0x65,0x19,0xe2,0x58,0x17,0xb7,0xd1},0x7ff1}, /* 1e-4 */
+ {{0x71,0x3d,0x0a,0xd7,0xa3,0x70,0x3d,0x0a,0xd7,0xa3},0x7ff8}, /* 1e-2 */
+ {{0xcd,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc},0x7ffb}, /* 1e-1 */
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80},0x7fff}, /* 1e-0 */
+};
+
+/* This table contains the powers of ten raised to positive powers of two:
+ *
+ * entry[12-n] = 10 ** (2 ** n) for 0 <= n <= 12.
+ * entry[13] = 1.0
+ * entry[-1] = entry[0];
+ *
+ * There is a -1 entry since it is possible for the algorithm to back up
+ * before the table. This -1 entry is created at runtime by duplicating the
+ * 0 entry.
+ */
+static /*@only@*/ POT_Entry *POT_TableP;
+static POT_Entry_Source POT_TableP_Source[] = {
+ {{0x4c,0xc9,0x9a,0x97,0x20,0x8a,0x02,0x52,0x60,0xc4},0xb525}, /* 1e+4096 */
+ {{0x4d,0xa7,0xe4,0x5d,0x3d,0xc5,0x5d,0x3b,0x8b,0x9e},0x9a92}, /* 1e+2048 */
+ {{0x0d,0x65,0x17,0x0c,0x75,0x81,0x86,0x75,0x76,0xc9},0x8d48}, /* 1e+1024 */
+ {{0x65,0xcc,0xc6,0x91,0x0e,0xa6,0xae,0xa0,0x19,0xe3},0x86a3}, /* 1e+512 */
+ {{0xbc,0xdd,0x8d,0xde,0xf9,0x9d,0xfb,0xeb,0x7e,0xaa},0x8351}, /* 1e+256 */
+ {{0x6f,0xc6,0xdf,0x8c,0xe9,0x80,0xc9,0x47,0xba,0x93},0x81a8}, /* 1e+128 */
+ {{0xbf,0x3c,0xd5,0xa6,0xcf,0xff,0x49,0x1f,0x78,0xc2},0x80d3}, /* 1e+64 */
+ {{0x20,0xf0,0x9d,0xb5,0x70,0x2b,0xa8,0xad,0xc5,0x9d},0x8069}, /* 1e+32 */
+ {{0x00,0x00,0x00,0x00,0x00,0x04,0xbf,0xc9,0x1b,0x8e},0x8034}, /* 1e+16 */
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0xbc,0xbe},0x8019}, /* 1e+8 */
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x9c},0x800c}, /* 1e+4 */
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc8},0x8005}, /* 1e+2 */
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0},0x8002}, /* 1e+1 */
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80},0x7fff}, /* 1e+0 */
+};
+
+
+static void
+POT_Table_Init_Entry(/*@out@*/ POT_Entry *e, POT_Entry_Source *s, int dec_exp)
+{
+ /* Save decimal exponent */
+ e->dec_exponent = dec_exp;
+
+ /* Initialize mantissa */
+ e->f.mantissa = BitVector_Create(MANT_BITS, FALSE);
+ BitVector_Block_Store(e->f.mantissa, s->mantissa, MANT_BYTES);
+
+ /* Initialize exponent */
+ e->f.exponent = s->exponent;
+
+ /* Set sign to 0 (positive) */
+ e->f.sign = 0;
+
+ /* Clear flags */
+ e->f.flags = 0;
+}
+
+/*@-compdef@*/
+void
+yasm_floatnum_initialize(void)
+/*@globals undef POT_TableN, undef POT_TableP, POT_TableP_Source,
+ POT_TableN_Source @*/
+{
+ int dec_exp = 1;
+ int i;
+
+ /* Allocate space for two POT tables */
+ POT_TableN = yasm_xmalloc(14*sizeof(POT_Entry));
+ POT_TableP = yasm_xmalloc(15*sizeof(POT_Entry)); /* note 1 extra for -1 */
+
+ /* Initialize entry[0..12] */
+ for (i=12; i>=0; i--) {
+ POT_Table_Init_Entry(&POT_TableN[i], &POT_TableN_Source[i], 0-dec_exp);
+ POT_Table_Init_Entry(&POT_TableP[i+1], &POT_TableP_Source[i], dec_exp);
+ dec_exp *= 2; /* Update decimal exponent */
+ }
+
+ /* Initialize entry[13] */
+ POT_Table_Init_Entry(&POT_TableN[13], &POT_TableN_Source[13], 0);
+ POT_Table_Init_Entry(&POT_TableP[14], &POT_TableP_Source[13], 0);
+
+ /* Initialize entry[-1] for POT_TableP */
+ POT_Table_Init_Entry(&POT_TableP[0], &POT_TableP_Source[0], 4096);
+
+ /* Offset POT_TableP so that [0] becomes [-1] */
+ POT_TableP++;
+}
+/*@=compdef@*/
+
+/*@-globstate@*/
+void
+yasm_floatnum_cleanup(void)
+{
+ int i;
+
+ /* Un-offset POT_TableP */
+ POT_TableP--;
+
+ for (i=0; i<14; i++) {
+ BitVector_Destroy(POT_TableN[i].f.mantissa);
+ BitVector_Destroy(POT_TableP[i].f.mantissa);
+ }
+ BitVector_Destroy(POT_TableP[14].f.mantissa);
+
+ yasm_xfree(POT_TableN);
+ yasm_xfree(POT_TableP);
+}
+/*@=globstate@*/
+
+static void
+floatnum_normalize(yasm_floatnum *flt)
+{
+ long norm_amt;
+
+ if (BitVector_is_empty(flt->mantissa)) {
+ flt->exponent = 0;
+ return;
+ }
+
+ /* Look for the highest set bit, shift to make it the MSB, and adjust
+ * exponent. Don't let exponent go negative. */
+ norm_amt = (MANT_BITS-1)-Set_Max(flt->mantissa);
+ if (norm_amt > (long)flt->exponent)
+ norm_amt = (long)flt->exponent;
+ BitVector_Move_Left(flt->mantissa, (N_int)norm_amt);
+ flt->exponent -= (unsigned short)norm_amt;
+}
+
+/* acc *= op */
+static void
+floatnum_mul(yasm_floatnum *acc, const yasm_floatnum *op)
+{
+ long expon;
+ wordptr product, op1, op2;
+ long norm_amt;
+
+ /* Compute the new sign */
+ acc->sign ^= op->sign;
+
+ /* Check for multiply by 0 */
+ if (BitVector_is_empty(acc->mantissa) || BitVector_is_empty(op->mantissa)) {
+ BitVector_Empty(acc->mantissa);
+ acc->exponent = EXP_ZERO;
+ return;
+ }
+
+ /* Add exponents, checking for overflow/underflow. */
+ expon = (((int)acc->exponent)-EXP_BIAS) + (((int)op->exponent)-EXP_BIAS);
+ expon += EXP_BIAS;
+ if (expon > EXP_MAX) {
+ /* Overflow; return infinity. */
+ BitVector_Empty(acc->mantissa);
+ acc->exponent = EXP_INF;
+ return;
+ } else if (expon < EXP_MIN) {
+ /* Underflow; return zero. */
+ BitVector_Empty(acc->mantissa);
+ acc->exponent = EXP_ZERO;
+ return;
+ }
+
+ /* Add one to the final exponent, as the multiply shifts one extra time. */
+ acc->exponent = (unsigned short)(expon+1);
+
+ /* Allocate space for the multiply result */
+ product = BitVector_Create((N_int)((MANT_BITS+1)*2), FALSE);
+
+ /* Allocate 1-bit-longer fields to force the operands to be unsigned */
+ op1 = BitVector_Create((N_int)(MANT_BITS+1), FALSE);
+ op2 = BitVector_Create((N_int)(MANT_BITS+1), FALSE);
+
+ /* Make the operands unsigned after copying from original operands */
+ BitVector_Copy(op1, acc->mantissa);
+ BitVector_MSB(op1, 0);
+ BitVector_Copy(op2, op->mantissa);
+ BitVector_MSB(op2, 0);
+
+ /* Compute the product of the mantissas */
+ BitVector_Multiply(product, op1, op2);
+
+ /* Normalize the product. Note: we know the product is non-zero because
+ * both of the original operands were non-zero.
+ *
+ * Look for the highest set bit, shift to make it the MSB, and adjust
+ * exponent. Don't let exponent go negative.
+ */
+ norm_amt = (MANT_BITS*2-1)-Set_Max(product);
+ if (norm_amt > (long)acc->exponent)
+ norm_amt = (long)acc->exponent;
+ BitVector_Move_Left(product, (N_int)norm_amt);
+ acc->exponent -= (unsigned short)norm_amt;
+
+ /* Store the highest bits of the result */
+ BitVector_Interval_Copy(acc->mantissa, product, 0, MANT_BITS, MANT_BITS);
+
+ /* Free allocated variables */
+ BitVector_Destroy(product);
+ BitVector_Destroy(op1);
+ BitVector_Destroy(op2);
+}
+
+yasm_floatnum *
+yasm_floatnum_create(const char *str)
+{
+ yasm_floatnum *flt;
+ int dec_exponent, dec_exp_add; /* decimal (powers of 10) exponent */
+ int POT_index;
+ wordptr operand[2];
+ int sig_digits;
+ int decimal_pt;
+ boolean carry;
+
+ flt = yasm_xmalloc(sizeof(yasm_floatnum));
+
+ flt->mantissa = BitVector_Create(MANT_BITS, TRUE);
+
+ /* allocate and initialize calculation variables */
+ operand[0] = BitVector_Create(MANT_BITS, TRUE);
+ operand[1] = BitVector_Create(MANT_BITS, TRUE);
+ dec_exponent = 0;
+ sig_digits = 0;
+ decimal_pt = 1;
+
+ /* set initial flags to 0 */
+ flt->flags = 0;
+
+ /* check for + or - character and skip */
+ if (*str == '-') {
+ flt->sign = 1;
+ str++;
+ } else if (*str == '+') {
+ flt->sign = 0;
+ str++;
+ } else
+ flt->sign = 0;
+
+ /* eliminate any leading zeros (which do not count as significant digits) */
+ while (*str == '0')
+ str++;
+
+ /* When we reach the end of the leading zeros, first check for a decimal
+ * point. If the number is of the form "0---0.0000" we need to get rid
+ * of the zeros after the decimal point and not count them as significant
+ * digits.
+ */
+ if (*str == '.') {
+ str++;
+ while (*str == '0') {
+ str++;
+ dec_exponent--;
+ }
+ } else {
+ /* The number is of the form "yyy.xxxx" (where y <> 0). */
+ while (isdigit(*str)) {
+ /* See if we've processed more than the max significant digits: */
+ if (sig_digits < MANT_SIGDIGITS) {
+ /* Multiply mantissa by 10 [x = (x<<1)+(x<<3)] */
+ BitVector_shift_left(flt->mantissa, 0);
+ BitVector_Copy(operand[0], flt->mantissa);
+ BitVector_Move_Left(flt->mantissa, 2);
+ carry = 0;
+ BitVector_add(operand[1], operand[0], flt->mantissa, &carry);
+
+ /* Add in current digit */
+ BitVector_Empty(operand[0]);
+ BitVector_Chunk_Store(operand[0], 4, 0, (N_long)(*str-'0'));
+ carry = 0;
+ BitVector_add(flt->mantissa, operand[1], operand[0], &carry);
+ } else {
+ /* Can't integrate more digits with mantissa, so instead just
+ * raise by a power of ten.
+ */
+ dec_exponent++;
+ }
+ sig_digits++;
+ str++;
+ }
+
+ if (*str == '.')
+ str++;
+ else
+ decimal_pt = 0;
+ }
+
+ if (decimal_pt) {
+ /* Process the digits to the right of the decimal point. */
+ while (isdigit(*str)) {
+ /* See if we've processed more than 19 significant digits: */
+ if (sig_digits < 19) {
+ /* Raise by a power of ten */
+ dec_exponent--;
+
+ /* Multiply mantissa by 10 [x = (x<<1)+(x<<3)] */
+ BitVector_shift_left(flt->mantissa, 0);
+ BitVector_Copy(operand[0], flt->mantissa);
+ BitVector_Move_Left(flt->mantissa, 2);
+ carry = 0;
+ BitVector_add(operand[1], operand[0], flt->mantissa, &carry);
+
+ /* Add in current digit */
+ BitVector_Empty(operand[0]);
+ BitVector_Chunk_Store(operand[0], 4, 0, (N_long)(*str-'0'));
+ carry = 0;
+ BitVector_add(flt->mantissa, operand[1], operand[0], &carry);
+ }
+ sig_digits++;
+ str++;
+ }
+ }
+
+ if (*str == 'e' || *str == 'E') {
+ str++;
+ /* We just saw the "E" character, now read in the exponent value and
+ * add it into dec_exponent.
+ */
+ dec_exp_add = 0;
+ sscanf(str, "%d", &dec_exp_add);
+ dec_exponent += dec_exp_add;
+ }
+
+ /* Free calculation variables. */
+ BitVector_Destroy(operand[1]);
+ BitVector_Destroy(operand[0]);
+
+ /* Normalize the number, checking for 0 first. */
+ if (BitVector_is_empty(flt->mantissa)) {
+ /* Mantissa is 0, zero exponent too. */
+ flt->exponent = 0;
+ /* Set zero flag so output functions don't see 0 value as underflow. */
+ flt->flags |= FLAG_ISZERO;
+ /* Return 0 value. */
+ return flt;
+ }
+ /* Exponent if already norm. */
+ flt->exponent = (unsigned short)(0x7FFF+(MANT_BITS-1));
+ floatnum_normalize(flt);
+
+ /* The number is normalized. Now multiply by 10 the number of times
+ * specified in DecExponent. This uses the power of ten tables to speed
+ * up this operation (and make it more accurate).
+ */
+ if (dec_exponent > 0) {
+ POT_index = 0;
+ /* Until we hit 1.0 or finish exponent or overflow */
+ while ((POT_index < 14) && (dec_exponent != 0) &&
+ (flt->exponent != EXP_INF)) {
+ /* Find the first power of ten in the table which is just less than
+ * the exponent.
+ */
+ while (dec_exponent < POT_TableP[POT_index].dec_exponent)
+ POT_index++;
+
+ if (POT_index < 14) {
+ /* Subtract out what we're multiplying in from exponent */
+ dec_exponent -= POT_TableP[POT_index].dec_exponent;
+
+ /* Multiply by current power of 10 */
+ floatnum_mul(flt, &POT_TableP[POT_index].f);
+ }
+ }
+ } else if (dec_exponent < 0) {
+ POT_index = 0;
+ /* Until we hit 1.0 or finish exponent or underflow */
+ while ((POT_index < 14) && (dec_exponent != 0) &&
+ (flt->exponent != EXP_ZERO)) {
+ /* Find the first power of ten in the table which is just less than
+ * the exponent.
+ */
+ while (dec_exponent > POT_TableN[POT_index].dec_exponent)
+ POT_index++;
+
+ if (POT_index < 14) {
+ /* Subtract out what we're multiplying in from exponent */
+ dec_exponent -= POT_TableN[POT_index].dec_exponent;
+
+ /* Multiply by current power of 10 */
+ floatnum_mul(flt, &POT_TableN[POT_index].f);
+ }
+ }
+ }
+
+ /* Round the result. (Don't round underflow or overflow). Also don't
+ * increment if this would cause the mantissa to wrap.
+ */
+ if ((flt->exponent != EXP_INF) && (flt->exponent != EXP_ZERO) &&
+ !BitVector_is_full(flt->mantissa))
+ BitVector_increment(flt->mantissa);
+
+ return flt;
+}
+
+yasm_floatnum *
+yasm_floatnum_copy(const yasm_floatnum *flt)
+{
+ yasm_floatnum *f = yasm_xmalloc(sizeof(yasm_floatnum));
+
+ f->mantissa = BitVector_Clone(flt->mantissa);
+ f->exponent = flt->exponent;
+ f->sign = flt->sign;
+ f->flags = flt->flags;
+
+ return f;
+}
+
+void
+yasm_floatnum_destroy(yasm_floatnum *flt)
+{
+ BitVector_Destroy(flt->mantissa);
+ yasm_xfree(flt);
+}
+
+int
+yasm_floatnum_calc(yasm_floatnum *acc, yasm_expr_op op,
+ /*@unused@*/ yasm_floatnum *operand)
+{
+ if (op != YASM_EXPR_NEG) {
+ yasm_error_set(YASM_ERROR_FLOATING_POINT,
+ N_("Unsupported floating-point arithmetic operation"));
+ return 1;
+ }
+ acc->sign ^= 1;
+ return 0;
+}
+
+int
+yasm_floatnum_get_int(const yasm_floatnum *flt, unsigned long *ret_val)
+{
+ unsigned char t[4];
+
+ if (yasm_floatnum_get_sized(flt, t, 4, 32, 0, 0, 0)) {
+ *ret_val = 0xDEADBEEFUL; /* Obviously incorrect return value */
+ return 1;
+ }
+
+ YASM_LOAD_32_L(*ret_val, &t[0]);
+ return 0;
+}
+
+/* Function used by conversion routines to actually perform the conversion.
+ *
+ * ptr -> the array to return the little-endian floating point value into.
+ * flt -> the floating point value to convert.
+ * byte_size -> the size in bytes of the output format.
+ * mant_bits -> the size in bits of the output mantissa.
+ * implicit1 -> does the output format have an implicit 1? 1=yes, 0=no.
+ * exp_bits -> the size in bits of the output exponent.
+ *
+ * Returns 0 on success, 1 if overflow, -1 if underflow.
+ */
+static int
+floatnum_get_common(const yasm_floatnum *flt, /*@out@*/ unsigned char *ptr,
+ N_int byte_size, N_int mant_bits, int implicit1,
+ N_int exp_bits)
+{
+ long exponent = (long)flt->exponent;
+ wordptr output;
+ charptr buf;
+ unsigned int len;
+ unsigned int overflow = 0, underflow = 0;
+ int retval = 0;
+ long exp_bias = (1<<(exp_bits-1))-1;
+ long exp_inf = (1<<exp_bits)-1;
+
+ output = BitVector_Create(byte_size*8, TRUE);
+
+ /* copy mantissa */
+ BitVector_Interval_Copy(output, flt->mantissa, 0,
+ (N_int)((MANT_BITS-implicit1)-mant_bits),
+ mant_bits);
+
+ /* round mantissa */
+ if (BitVector_bit_test(flt->mantissa, (MANT_BITS-implicit1)-(mant_bits+1)))
+ BitVector_increment(output);
+
+ if (BitVector_bit_test(output, mant_bits)) {
+ /* overflowed, so zero mantissa (and set explicit bit if necessary) */
+ BitVector_Empty(output);
+ BitVector_Bit_Copy(output, mant_bits-1, !implicit1);
+ /* and up the exponent (checking for overflow) */
+ if (exponent+1 >= EXP_INF)
+ overflow = 1;
+ else
+ exponent++;
+ }
+
+ /* adjust the exponent to the output bias, checking for overflow */
+ exponent -= EXP_BIAS-exp_bias;
+ if (exponent >= exp_inf)
+ overflow = 1;
+ else if (exponent <= 0)
+ underflow = 1;
+
+ /* underflow and overflow both set!? */
+ if (underflow && overflow)
+ yasm_internal_error(N_("Both underflow and overflow set"));
+
+ /* check for underflow or overflow and set up appropriate output */
+ if (underflow) {
+ BitVector_Empty(output);
+ exponent = 0;
+ if (!(flt->flags & FLAG_ISZERO))
+ retval = -1;
+ } else if (overflow) {
+ BitVector_Empty(output);
+ exponent = exp_inf;
+ retval = 1;
+ }
+
+ /* move exponent into place */
+ BitVector_Chunk_Store(output, exp_bits, mant_bits, (N_long)exponent);
+
+ /* merge in sign bit */
+ BitVector_Bit_Copy(output, byte_size*8-1, flt->sign);
+
+ /* get little-endian bytes */
+ buf = BitVector_Block_Read(output, &len);
+ if (len < byte_size)
+ yasm_internal_error(
+ N_("Byte length of BitVector does not match bit length"));
+
+ /* copy to output */
+ memcpy(ptr, buf, byte_size*sizeof(unsigned char));
+
+ /* free allocated resources */
+ yasm_xfree(buf);
+
+ BitVector_Destroy(output);
+
+ return retval;
+}
+
+/* IEEE-754r "half precision" format:
+ * 16 bits:
+ * 15 9 Bit 0
+ * | | |
+ * seee eemm mmmm mmmm
+ *
+ * e = bias 15 exponent
+ * s = sign bit
+ * m = mantissa bits, bit 10 is an implied one bit.
+ *
+ * IEEE-754 (Intel) "single precision" format:
+ * 32 bits:
+ * Bit 31 Bit 22 Bit 0
+ * | | |
+ * seeeeeee emmmmmmm mmmmmmmm mmmmmmmm
+ *
+ * e = bias 127 exponent
+ * s = sign bit
+ * m = mantissa bits, bit 23 is an implied one bit.
+ *
+ * IEEE-754 (Intel) "double precision" format:
+ * 64 bits:
+ * bit 63 bit 51 bit 0
+ * | | |
+ * seeeeeee eeeemmmm mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm
+ *
+ * e = bias 1023 exponent.
+ * s = sign bit.
+ * m = mantissa bits. Bit 52 is an implied one bit.
+ *
+ * IEEE-754 (Intel) "extended precision" format:
+ * 80 bits:
+ * bit 79 bit 63 bit 0
+ * | | |
+ * seeeeeee eeeeeeee mmmmmmmm m...m m...m m...m m...m m...m
+ *
+ * e = bias 16383 exponent
+ * m = 64 bit mantissa with NO implied bit!
+ * s = sign (for mantissa)
+ */
+int
+yasm_floatnum_get_sized(const yasm_floatnum *flt, unsigned char *ptr,
+ size_t destsize, size_t valsize, size_t shift,
+ int bigendian, int warn)
+{
+ int retval;
+ if (destsize*8 != valsize || shift>0 || bigendian) {
+ /* TODO */
+ yasm_internal_error(N_("unsupported floatnum functionality"));
+ }
+ switch (destsize) {
+ case 2:
+ retval = floatnum_get_common(flt, ptr, 2, 10, 1, 5);
+ break;
+ case 4:
+ retval = floatnum_get_common(flt, ptr, 4, 23, 1, 8);
+ break;
+ case 8:
+ retval = floatnum_get_common(flt, ptr, 8, 52, 1, 11);
+ break;
+ case 10:
+ retval = floatnum_get_common(flt, ptr, 10, 64, 0, 15);
+ break;
+ default:
+ yasm_internal_error(N_("Invalid float conversion size"));
+ /*@notreached@*/
+ return 1;
+ }
+ if (warn) {
+ if (retval < 0)
+ yasm_warn_set(YASM_WARN_GENERAL,
+ N_("underflow in floating point expression"));
+ else if (retval > 0)
+ yasm_warn_set(YASM_WARN_GENERAL,
+ N_("overflow in floating point expression"));
+ }
+ return retval;
+}
+
+/* 1 if the size is valid, 0 if it isn't */
+int
+yasm_floatnum_check_size(/*@unused@*/ const yasm_floatnum *flt, size_t size)
+{
+ switch (size) {
+ case 16:
+ case 32:
+ case 64:
+ case 80:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+void
+yasm_floatnum_print(const yasm_floatnum *flt, FILE *f)
+{
+ unsigned char out[10];
+ unsigned char *str;
+ int i;
+
+ /* Internal format */
+ str = BitVector_to_Hex(flt->mantissa);
+ fprintf(f, "%c %s *2^%04x\n", flt->sign?'-':'+', (char *)str,
+ flt->exponent);
+ yasm_xfree(str);
+
+ /* 32-bit (single precision) format */
+ fprintf(f, "32-bit: %d: ",
+ yasm_floatnum_get_sized(flt, out, 4, 32, 0, 0, 0));
+ for (i=0; i<4; i++)
+ fprintf(f, "%02x ", out[i]);
+ fprintf(f, "\n");
+
+ /* 64-bit (double precision) format */
+ fprintf(f, "64-bit: %d: ",
+ yasm_floatnum_get_sized(flt, out, 8, 64, 0, 0, 0));
+ for (i=0; i<8; i++)
+ fprintf(f, "%02x ", out[i]);
+ fprintf(f, "\n");
+
+ /* 80-bit (extended precision) format */
+ fprintf(f, "80-bit: %d: ",
+ yasm_floatnum_get_sized(flt, out, 10, 80, 0, 0, 0));
+ for (i=0; i<10; i++)
+ fprintf(f, "%02x ", out[i]);
+ fprintf(f, "\n");
+}
diff --git a/libyasm/floatnum.h b/libyasm/floatnum.h
new file mode 100644
index 0000000..d2c7042
--- /dev/null
+++ b/libyasm/floatnum.h
@@ -0,0 +1,131 @@
+/**
+ * \file libyasm/floatnum.h
+ * \brief YASM floating point (IEEE) interface.
+ *
+ * \license
+ * Copyright (C) 2001-2007 Peter Johnson
+ *
+ * Based on public-domain x86 assembly code by Randall Hyde (8/28/91).
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * \endlicense
+ */
+#ifndef YASM_FLOATNUM_H
+#define YASM_FLOATNUM_H
+
+#ifndef YASM_LIB_DECL
+#define YASM_LIB_DECL
+#endif
+
+/** Initialize floatnum internal data structures. */
+YASM_LIB_DECL
+void yasm_floatnum_initialize(void);
+
+/** Clean up internal floatnum allocations. */
+YASM_LIB_DECL
+void yasm_floatnum_cleanup(void);
+
+/** Create a new floatnum from a decimal string. The input string must be in
+ * standard C representation ([+-]123.456e[-+]789).
+ * \param str floating point decimal string
+ * \return Newly allocated floatnum.
+ */
+YASM_LIB_DECL
+/*@only@*/ yasm_floatnum *yasm_floatnum_create(const char *str);
+
+/** Duplicate a floatnum.
+ * \param flt floatnum
+ * \return Newly allocated floatnum with the same value as flt.
+ */
+YASM_LIB_DECL
+/*@only@*/ yasm_floatnum *yasm_floatnum_copy(const yasm_floatnum *flt);
+
+/** Destroy (free allocated memory for) a floatnum.
+ * \param flt floatnum
+ */
+YASM_LIB_DECL
+void yasm_floatnum_destroy(/*@only@*/ yasm_floatnum *flt);
+
+/** Floating point calculation function: acc = acc op operand.
+ * \note Not all operations in yasm_expr_op may be supported; unsupported
+ * operations will result in an error.
+ * \param acc floatnum accumulator
+ * \param op operation
+ * \param operand floatnum operand
+ * \return Nonzero on error.
+ */
+YASM_LIB_DECL
+int yasm_floatnum_calc(yasm_floatnum *acc, yasm_expr_op op,
+ yasm_floatnum *operand);
+
+/** Convert a floatnum to single-precision and return as 32-bit value.
+ * The 32-bit value is a "standard" C value (eg, of unknown endian).
+ * \param flt floatnum
+ * \param ret_val pointer to storage for 32-bit output
+ * \return Nonzero if flt can't fit into single precision: -1 if underflow
+ * occurred, 1 if overflow occurred.
+ */
+YASM_LIB_DECL
+int yasm_floatnum_get_int(const yasm_floatnum *flt,
+ /*@out@*/ unsigned long *ret_val);
+
+/** Output a #yasm_floatnum to buffer in little-endian or big-endian. Puts the
+ * value into the least significant bits of the destination, or may be shifted
+ * into more significant bits by the shift parameter. The destination bits are
+ * cleared before being set. [0] should be the first byte output to the file.
+ * \note Not all sizes are valid. Currently, only 32 (single-precision), 64
+ * (double-precision), and 80 (extended-precision) are valid sizes.
+ * Use yasm_floatnum_check_size() to check for supported sizes.
+ * \param flt floatnum
+ * \param ptr pointer to storage for size bytes of output
+ * \param destsize destination size (in bytes)
+ * \param valsize size (in bits)
+ * \param shift left shift (in bits)
+ * \param bigendian endianness (nonzero=big, zero=little)
+ * \param warn enables standard overflow/underflow warnings
+ * \return Nonzero if flt can't fit into the specified precision: -1 if
+ * underflow occurred, 1 if overflow occurred.
+ */
+YASM_LIB_DECL
+int yasm_floatnum_get_sized(const yasm_floatnum *flt, unsigned char *ptr,
+ size_t destsize, size_t valsize, size_t shift,
+ int bigendian, int warn);
+
+/** Basic check to see if size is valid for flt conversion (using
+ * yasm_floatnum_get_sized()). Doesn't actually check for underflow/overflow
+ * but rather checks for size=32,64,80
+ * (at present).
+ * \param flt floatnum
+ * \param size number of bits of output space
+ * \return 1 if valid size, 0 if invalid size.
+ */
+YASM_LIB_DECL
+int yasm_floatnum_check_size(const yasm_floatnum *flt, size_t size);
+
+/** Print various representations of a floatnum. For debugging purposes only.
+ * \param f file
+ * \param flt floatnum
+ */
+YASM_LIB_DECL
+void yasm_floatnum_print(const yasm_floatnum *flt, FILE *f);
+
+#endif
diff --git a/libyasm/genmodule.c b/libyasm/genmodule.c
new file mode 100644
index 0000000..a9be08a
--- /dev/null
+++ b/libyasm/genmodule.c
@@ -0,0 +1,229 @@
+/*
+ *
+ * Generate module.c from module.in and Makefile.am or Makefile.
+ *
+ * Copyright (C) 2004-2007 Peter Johnson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "compat-queue.h"
+
+#define MAXNAME 128
+#define MAXLINE 1024
+#define MAXMODULES 128
+#define MAXINCLUDES 256
+
+typedef struct include {
+ STAILQ_ENTRY(include) link;
+ char *filename;
+} include;
+
+int
+main(int argc, char *argv[])
+{
+ FILE *in, *out;
+ char *str;
+ int i;
+ size_t len;
+ char *strp;
+ char *modules[MAXMODULES];
+ int num_modules = 0;
+ STAILQ_HEAD(includehead, include) includes =
+ STAILQ_HEAD_INITIALIZER(includes);
+ include *inc;
+ int isam = 0;
+ int linecont = 0;
+ char *outfile;
+
+ if (argc != 4) {
+ fprintf(stderr, "Usage: %s <module.in> <Makefile[.am]> <outfile>\n", argv[0]);
+ return EXIT_FAILURE;
+ }
+
+ outfile = argv[3];
+ str = malloc(MAXLINE);
+
+ /* Starting with initial input Makefile, look for include <file> or
+ * YASM_MODULES += <module>. Note this currently doesn't handle
+ * a relative starting path.
+ */
+ len = strlen(argv[2]);
+ inc = malloc(sizeof(include));
+ inc->filename = malloc(len+1);
+ strcpy(inc->filename, argv[2]);
+ STAILQ_INSERT_TAIL(&includes, inc, link);
+
+ isam = argv[2][len-2] == 'a' && argv[2][len-1] == 'm';
+
+ while (!STAILQ_EMPTY(&includes)) {
+ inc = STAILQ_FIRST(&includes);
+ STAILQ_REMOVE_HEAD(&includes, link);
+ in = fopen(inc->filename, "rt");
+ if (!in) {
+ fprintf(stderr, "Could not open `%s'.\n", inc->filename);
+ return EXIT_FAILURE;
+ }
+ free(inc->filename);
+ free(inc);
+
+ while (fgets(str, MAXLINE, in)) {
+ /* Strip off any trailing whitespace */
+ len = strlen(str);
+ if (len > 0) {
+ strp = &str[len-1];
+ while (len > 0 && isspace(*strp)) {
+ *strp-- = '\0';
+ len--;
+ }
+ }
+
+ strp = str;
+
+ /* Skip whitespace */
+ while (isspace(*strp))
+ strp++;
+
+ /* Skip comments */
+ if (*strp == '#')
+ continue;
+
+ /* If line continuation, skip to continue copy */
+ if (linecont)
+ goto keepgoing;
+
+ /* Check for include if original input is .am file */
+ if (isam && strncmp(strp, "include", 7) == 0 && isspace(strp[7])) {
+ strp += 7;
+ while (isspace(*strp))
+ strp++;
+ /* Build new include and add to end of list */
+ inc = malloc(sizeof(include));
+ inc->filename = malloc(strlen(strp)+1);
+ strcpy(inc->filename, strp);
+ STAILQ_INSERT_TAIL(&includes, inc, link);
+ continue;
+ }
+
+ /* Check for YASM_MODULES = or += */
+ if (strncmp(strp, "YASM_MODULES", 12) != 0)
+ continue;
+ strp += 12;
+ while (isspace(*strp))
+ strp++;
+ if (strncmp(strp, "+=", 2) != 0 && *strp != '=')
+ continue;
+ if (*strp == '+')
+ strp++;
+ strp++;
+ while (isspace(*strp))
+ strp++;
+
+keepgoing:
+ /* Check for continuation */
+ if (len > 0 && str[len-1] == '\\') {
+ str[len-1] = '\0';
+ while (isspace(*strp))
+ *strp-- = '\0';
+ linecont = 1;
+ } else
+ linecont = 0;
+
+ while (*strp != '\0') {
+ /* Copy module name */
+ modules[num_modules] = malloc(MAXNAME);
+ len = 0;
+ while (*strp != '\0' && !isspace(*strp))
+ modules[num_modules][len++] = *strp++;
+ modules[num_modules][len] = '\0';
+ num_modules++;
+
+ while (isspace(*strp))
+ strp++;
+ }
+ }
+ fclose(in);
+ }
+
+ out = fopen(outfile, "wt");
+
+ if (!out) {
+ fprintf(stderr, "Could not open `%s'.\n", outfile);
+ return EXIT_FAILURE;
+ }
+
+ fprintf(out, "/* This file auto-generated by genmodule.c"
+ " - don't edit it */\n\n");
+
+ in = fopen(argv[1], "rt");
+ if (!in) {
+ fprintf(stderr, "Could not open `%s'.\n", argv[1]);
+ fclose(out);
+ remove(outfile);
+ return EXIT_FAILURE;
+ }
+
+ len = 0;
+ while (fgets(str, MAXLINE, in)) {
+ if (strncmp(str, "MODULES_", 8) == 0) {
+ len = 0;
+ strp = str+8;
+ while (*strp != '\0' && *strp != '_') {
+ len++;
+ strp++;
+ }
+ *strp = '\0';
+
+ for (i=0; i<num_modules; i++) {
+ if (strncmp(modules[i], str+8, len) == 0) {
+ fprintf(out, " {\"%s\", &yasm_%s_LTX_%s},\n",
+ modules[i]+len+1, modules[i]+len+1, str+8);
+ }
+ }
+ } else if (strncmp(str, "EXTERN_LIST", 11) == 0) {
+ for (i=0; i<num_modules; i++) {
+ strcpy(str, modules[i]);
+ strp = str;
+ while (*strp != '\0' && *strp != '_')
+ strp++;
+ *strp++ = '\0';
+
+ fprintf(out, "extern yasm_%s_module yasm_%s_LTX_%s;\n",
+ str, strp, str);
+ }
+ } else
+ fputs(str, out);
+ }
+
+ fclose(in);
+ fclose(out);
+
+ for (i=0; i<num_modules; i++)
+ free(modules[i]);
+ free(str);
+
+ return EXIT_SUCCESS;
+}
diff --git a/libyasm/hamt.c b/libyasm/hamt.c
new file mode 100644
index 0000000..59b7592
--- /dev/null
+++ b/libyasm/hamt.c
@@ -0,0 +1,421 @@
+/*
+ * Hash Array Mapped Trie (HAMT) implementation
+ *
+ * Copyright (C) 2001-2007 Peter Johnson
+ *
+ * Based on the paper "Ideal Hash Tries" by Phil Bagwell [2000].
+ * One algorithmic change from that described in the paper: we use the LSB's
+ * of the key to index the root table and move upward in the key rather than
+ * use the MSBs as described in the paper. The LSBs have more entropy.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "util.h"
+
+#include <ctype.h>
+
+#include "libyasm-stdint.h"
+#include "coretype.h"
+#include "hamt.h"
+
+struct HAMTEntry {
+ STAILQ_ENTRY(HAMTEntry) next; /* next hash table entry */
+ /*@dependent@*/ const char *str; /* string being hashed */
+ /*@owned@*/ void *data; /* data pointer being stored */
+};
+
+typedef struct HAMTNode {
+ unsigned long BitMapKey; /* 32 bits, bitmap or hash key */
+ uintptr_t BaseValue; /* Base of HAMTNode list or value */
+} HAMTNode;
+
+struct HAMT {
+ STAILQ_HEAD(HAMTEntryHead, HAMTEntry) entries;
+ HAMTNode *root;
+ /*@exits@*/ void (*error_func) (const char *file, unsigned int line,
+ const char *message);
+ unsigned long (*HashKey) (const char *key);
+ unsigned long (*ReHashKey) (const char *key, int Level);
+ int (*CmpKey) (const char *s1, const char *s2);
+};
+
+/* XXX make a portable version of this. This depends on the pointer being
+ * 4 or 2-byte aligned (as it uses the LSB of the pointer variable to store
+ * the subtrie flag!
+ */
+#define IsSubTrie(n) ((n)->BaseValue & 1)
+#define SetSubTrie(h, n, v) do { \
+ if ((uintptr_t)(v) & 1) \
+ h->error_func(__FILE__, __LINE__, \
+ N_("Subtrie is seen as subtrie before flag is set (misaligned?)")); \
+ (n)->BaseValue = (uintptr_t)(v) | 1; \
+ } while (0)
+#define SetValue(h, n, v) do { \
+ if ((uintptr_t)(v) & 1) \
+ h->error_func(__FILE__, __LINE__, \
+ N_("Value is seen as subtrie (misaligned?)")); \
+ (n)->BaseValue = (uintptr_t)(v); \
+ } while (0)
+#define GetSubTrie(n) (HAMTNode *)(((n)->BaseValue | 1) ^ 1)
+
+static unsigned long
+HashKey(const char *key)
+{
+ unsigned long a=31415, b=27183, vHash;
+ for (vHash=0; *key; key++, a*=b)
+ vHash = a*vHash + *key;
+ return vHash;
+}
+
+static unsigned long
+ReHashKey(const char *key, int Level)
+{
+ unsigned long a=31415, b=27183, vHash;
+ for (vHash=0; *key; key++, a*=b)
+ vHash = a*vHash*(unsigned long)Level + *key;
+ return vHash;
+}
+
+static unsigned long
+HashKey_nocase(const char *key)
+{
+ unsigned long a=31415, b=27183, vHash;
+ for (vHash=0; *key; key++, a*=b)
+ vHash = a*vHash + tolower(*key);
+ return vHash;
+}
+
+static unsigned long
+ReHashKey_nocase(const char *key, int Level)
+{
+ unsigned long a=31415, b=27183, vHash;
+ for (vHash=0; *key; key++, a*=b)
+ vHash = a*vHash*(unsigned long)Level + tolower(*key);
+ return vHash;
+}
+
+HAMT *
+HAMT_create(int nocase, /*@exits@*/ void (*error_func)
+ (const char *file, unsigned int line, const char *message))
+{
+ /*@out@*/ HAMT *hamt = yasm_xmalloc(sizeof(HAMT));
+ int i;
+
+ STAILQ_INIT(&hamt->entries);
+ hamt->root = yasm_xmalloc(32*sizeof(HAMTNode));
+
+ for (i=0; i<32; i++) {
+ hamt->root[i].BitMapKey = 0;
+ hamt->root[i].BaseValue = 0;
+ }
+
+ hamt->error_func = error_func;
+ if (nocase) {
+ hamt->HashKey = HashKey_nocase;
+ hamt->ReHashKey = ReHashKey_nocase;
+ hamt->CmpKey = yasm__strcasecmp;
+ } else {
+ hamt->HashKey = HashKey;
+ hamt->ReHashKey = ReHashKey;
+ hamt->CmpKey = strcmp;
+ }
+
+ return hamt;
+}
+
+static void
+HAMT_delete_trie(HAMTNode *node)
+{
+ if (IsSubTrie(node)) {
+ unsigned long i, Size;
+
+ /* Count total number of bits in bitmap to determine size */
+ BitCount(Size, node->BitMapKey);
+ Size &= 0x1F;
+ if (Size == 0)
+ Size = 32;
+
+ for (i=0; i<Size; i++)
+ HAMT_delete_trie(&(GetSubTrie(node))[i]);
+ yasm_xfree(GetSubTrie(node));
+ }
+}
+
+void
+HAMT_destroy(HAMT *hamt, void (*deletefunc) (/*@only@*/ void *data))
+{
+ int i;
+
+ /* delete entries */
+ while (!STAILQ_EMPTY(&hamt->entries)) {
+ HAMTEntry *entry;
+ entry = STAILQ_FIRST(&hamt->entries);
+ STAILQ_REMOVE_HEAD(&hamt->entries, next);
+ deletefunc(entry->data);
+ yasm_xfree(entry);
+ }
+
+ /* delete trie */
+ for (i=0; i<32; i++)
+ HAMT_delete_trie(&hamt->root[i]);
+
+ yasm_xfree(hamt->root);
+ yasm_xfree(hamt);
+}
+
+int
+HAMT_traverse(HAMT *hamt, void *d,
+ int (*func) (/*@dependent@*/ /*@null@*/ void *node,
+ /*@null@*/ void *d))
+{
+ HAMTEntry *entry;
+ STAILQ_FOREACH(entry, &hamt->entries, next) {
+ int retval = func(entry->data, d);
+ if (retval != 0)
+ return retval;
+ }
+ return 0;
+}
+
+const HAMTEntry *
+HAMT_first(const HAMT *hamt)
+{
+ return STAILQ_FIRST(&hamt->entries);
+}
+
+const HAMTEntry *
+HAMT_next(const HAMTEntry *prev)
+{
+ return STAILQ_NEXT(prev, next);
+}
+
+void *
+HAMTEntry_get_data(const HAMTEntry *entry)
+{
+ return entry->data;
+}
+
+/*@-temptrans -kepttrans -mustfree@*/
+void *
+HAMT_insert(HAMT *hamt, const char *str, void *data, int *replace,
+ void (*deletefunc) (/*@only@*/ void *data))
+{
+ HAMTNode *node, *newnodes;
+ HAMTEntry *entry;
+ unsigned long key, keypart, Map;
+ int keypartbits = 0;
+ int level = 0;
+
+ key = hamt->HashKey(str);
+ keypart = key & 0x1F;
+ node = &hamt->root[keypart];
+
+ if (!node->BaseValue) {
+ node->BitMapKey = key;
+ entry = yasm_xmalloc(sizeof(HAMTEntry));
+ entry->str = str;
+ entry->data = data;
+ STAILQ_INSERT_TAIL(&hamt->entries, entry, next);
+ SetValue(hamt, node, entry);
+ if (IsSubTrie(node))
+ hamt->error_func(__FILE__, __LINE__,
+ N_("Data is seen as subtrie (misaligned?)"));
+ *replace = 1;
+ return data;
+ }
+
+ for (;;) {
+ if (!(IsSubTrie(node))) {
+ if (node->BitMapKey == key
+ && hamt->CmpKey(((HAMTEntry *)(node->BaseValue))->str,
+ str) == 0) {
+ /*@-branchstate@*/
+ if (*replace) {
+ deletefunc(((HAMTEntry *)(node->BaseValue))->data);
+ ((HAMTEntry *)(node->BaseValue))->str = str;
+ ((HAMTEntry *)(node->BaseValue))->data = data;
+ } else
+ deletefunc(data);
+ /*@=branchstate@*/
+ return ((HAMTEntry *)(node->BaseValue))->data;
+ } else {
+ unsigned long key2 = node->BitMapKey;
+ /* build tree downward until keys differ */
+ for (;;) {
+ unsigned long keypart2;
+
+ /* replace node with subtrie */
+ keypartbits += 5;
+ if (keypartbits > 30) {
+ /* Exceeded 32 bits: rehash */
+ key = hamt->ReHashKey(str, level);
+ key2 = hamt->ReHashKey(
+ ((HAMTEntry *)(node->BaseValue))->str, level);
+ keypartbits = 0;
+ }
+ keypart = (key >> keypartbits) & 0x1F;
+ keypart2 = (key2 >> keypartbits) & 0x1F;
+
+ if (keypart == keypart2) {
+ /* Still equal, build one-node subtrie and continue
+ * downward.
+ */
+ newnodes = yasm_xmalloc(sizeof(HAMTNode));
+ newnodes[0].BitMapKey = key2;
+ newnodes[0].BaseValue = node->BaseValue;
+ node->BitMapKey = 1<<keypart;
+ SetSubTrie(hamt, node, newnodes);
+ node = &newnodes[0];
+ level++;
+ } else {
+ /* partitioned: allocate two-node subtrie */
+ newnodes = yasm_xmalloc(2*sizeof(HAMTNode));
+
+ entry = yasm_xmalloc(sizeof(HAMTEntry));
+ entry->str = str;
+ entry->data = data;
+ STAILQ_INSERT_TAIL(&hamt->entries, entry, next);
+
+ /* Copy nodes into subtrie based on order */
+ if (keypart2 < keypart) {
+ newnodes[0].BitMapKey = key2;
+ newnodes[0].BaseValue = node->BaseValue;
+ newnodes[1].BitMapKey = key;
+ SetValue(hamt, &newnodes[1], entry);
+ } else {
+ newnodes[0].BitMapKey = key;
+ SetValue(hamt, &newnodes[0], entry);
+ newnodes[1].BitMapKey = key2;
+ newnodes[1].BaseValue = node->BaseValue;
+ }
+
+ /* Set bits in bitmap corresponding to keys */
+ node->BitMapKey = (1UL<<keypart) | (1UL<<keypart2);
+ SetSubTrie(hamt, node, newnodes);
+ *replace = 1;
+ return data;
+ }
+ }
+ }
+ }
+
+ /* Subtrie: look up in bitmap */
+ keypartbits += 5;
+ if (keypartbits > 30) {
+ /* Exceeded 32 bits of current key: rehash */
+ key = hamt->ReHashKey(str, level);
+ keypartbits = 0;
+ }
+ keypart = (key >> keypartbits) & 0x1F;
+ if (!(node->BitMapKey & (1<<keypart))) {
+ /* bit is 0 in bitmap -> add node to table */
+ unsigned long Size;
+
+ /* set bit to 1 */
+ node->BitMapKey |= 1<<keypart;
+
+ /* Count total number of bits in bitmap to determine new size */
+ BitCount(Size, node->BitMapKey);
+ Size &= 0x1F;
+ if (Size == 0)
+ Size = 32;
+ newnodes = yasm_xmalloc(Size*sizeof(HAMTNode));
+
+ /* Count bits below to find where to insert new node at */
+ BitCount(Map, node->BitMapKey & ~((~0UL)<<keypart));
+ Map &= 0x1F; /* Clamp to <32 */
+ /* Copy existing nodes leaving gap for new node */
+ memcpy(newnodes, GetSubTrie(node), Map*sizeof(HAMTNode));
+ memcpy(&newnodes[Map+1], &(GetSubTrie(node))[Map],
+ (Size-Map-1)*sizeof(HAMTNode));
+ /* Delete old subtrie */
+ yasm_xfree(GetSubTrie(node));
+ /* Set up new node */
+ newnodes[Map].BitMapKey = key;
+ entry = yasm_xmalloc(sizeof(HAMTEntry));
+ entry->str = str;
+ entry->data = data;
+ STAILQ_INSERT_TAIL(&hamt->entries, entry, next);
+ SetValue(hamt, &newnodes[Map], entry);
+ SetSubTrie(hamt, node, newnodes);
+
+ *replace = 1;
+ return data;
+ }
+
+ /* Count bits below */
+ BitCount(Map, node->BitMapKey & ~((~0UL)<<keypart));
+ Map &= 0x1F; /* Clamp to <32 */
+
+ /* Go down a level */
+ level++;
+ node = &(GetSubTrie(node))[Map];
+ }
+}
+/*@=temptrans =kepttrans =mustfree@*/
+
+void *
+HAMT_search(HAMT *hamt, const char *str)
+{
+ HAMTNode *node;
+ unsigned long key, keypart, Map;
+ int keypartbits = 0;
+ int level = 0;
+
+ key = hamt->HashKey(str);
+ keypart = key & 0x1F;
+ node = &hamt->root[keypart];
+
+ if (!node->BaseValue)
+ return NULL;
+
+ for (;;) {
+ if (!(IsSubTrie(node))) {
+ if (node->BitMapKey == key
+ && hamt->CmpKey(((HAMTEntry *)(node->BaseValue))->str,
+ str) == 0)
+ return ((HAMTEntry *)(node->BaseValue))->data;
+ else
+ return NULL;
+ }
+
+ /* Subtree: look up in bitmap */
+ keypartbits += 5;
+ if (keypartbits > 30) {
+ /* Exceeded 32 bits of current key: rehash */
+ key = hamt->ReHashKey(str, level);
+ keypartbits = 0;
+ }
+ keypart = (key >> keypartbits) & 0x1F;
+ if (!(node->BitMapKey & (1<<keypart)))
+ return NULL; /* bit is 0 in bitmap -> no match */
+
+ /* Count bits below */
+ BitCount(Map, node->BitMapKey & ~((~0UL)<<keypart));
+ Map &= 0x1F; /* Clamp to <32 */
+
+ /* Go down a level */
+ level++;
+ node = &(GetSubTrie(node))[Map];
+ }
+}
+
diff --git a/libyasm/hamt.h b/libyasm/hamt.h
new file mode 100644
index 0000000..1ce9b77
--- /dev/null
+++ b/libyasm/hamt.h
@@ -0,0 +1,123 @@
+/**
+ * \file libyasm/hamt.h
+ * \brief Hash Array Mapped Trie (HAMT) functions.
+ *
+ * \license
+ * Copyright (C) 2001-2007 Peter Johnson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * \endlicense
+ */
+#ifndef YASM_HAMT_H
+#define YASM_HAMT_H
+
+#ifndef YASM_LIB_DECL
+#define YASM_LIB_DECL
+#endif
+
+/** Hash array mapped trie data structure (opaque type). */
+typedef struct HAMT HAMT;
+/** Hash array mapped trie entry (opaque type). */
+typedef struct HAMTEntry HAMTEntry;
+
+/** Create new, empty, HAMT. error_func() is called when an internal error is
+ * encountered--it should NOT return to the calling function.
+ * \param nocase nonzero if HAMT should be case-insensitive
+ * \param error_func function called on internal error
+ * \return New, empty, hash array mapped trie.
+ */
+YASM_LIB_DECL
+HAMT *HAMT_create(int nocase, /*@exits@*/ void (*error_func)
+ (const char *file, unsigned int line, const char *message));
+
+/** Delete HAMT and all data associated with it. Uses deletefunc() to delete
+ * each data item.
+ * \param hamt Hash array mapped trie
+ * \param deletefunc Data deletion function
+ */
+YASM_LIB_DECL
+void HAMT_destroy(/*@only@*/ HAMT *hamt,
+ void (*deletefunc) (/*@only@*/ void *data));
+
+/** Insert key into HAMT, associating it with data.
+ * If the key is not present in the HAMT, inserts it, sets *replace to 1, and
+ * returns the data passed in.
+ * If the key is already present and *replace is 0, deletes the data passed
+ * in using deletefunc() and returns the data currently associated with the
+ * key.
+ * If the key is already present and *replace is 1, deletes the data currently
+ * associated with the key using deletefunc() and replaces it with the data
+ * passed in.
+ * \param hamt Hash array mapped trie
+ * \param str Key
+ * \param data Data to associate with key
+ * \param replace See above description
+ * \param deletefunc Data deletion function if data is replaced
+ * \return Data now associated with key.
+ */
+YASM_LIB_DECL
+/*@dependent@*/ void *HAMT_insert(HAMT *hamt, /*@dependent@*/ const char *str,
+ /*@only@*/ void *data, int *replace,
+ void (*deletefunc) (/*@only@*/ void *data));
+
+/** Search for the data associated with a key in the HAMT.
+ * \param hamt Hash array mapped trie
+ * \param str Key
+ * \return NULL if key/data not present in HAMT, otherwise associated data.
+ */
+YASM_LIB_DECL
+/*@dependent@*/ /*@null@*/ void *HAMT_search(HAMT *hamt, const char *str);
+
+/** Traverse over all keys in HAMT, calling function on each data item.
+ * \param hamt Hash array mapped trie
+ * \param d Data to pass to each call to func.
+ * \param func Function to call
+ * \return Stops early (and returns func's return value) if func returns a
+ * nonzero value; otherwise 0.
+ */
+YASM_LIB_DECL
+int HAMT_traverse(HAMT *hamt, /*@null@*/ void *d,
+ int (*func) (/*@dependent@*/ /*@null@*/ void *node,
+ /*@null@*/ void *d));
+
+/** Get the first entry in a HAMT.
+ * \param hamt Hash array mapped trie
+ * \return First entry in HAMT, or NULL if HAMT is empty.
+ */
+YASM_LIB_DECL
+const HAMTEntry *HAMT_first(const HAMT *hamt);
+
+/** Get the next entry in a HAMT.
+ * \param prev Previous entry in HAMT
+ * \return Next entry in HAMT, or NULL if no more entries.
+ */
+YASM_LIB_DECL
+/*@null@*/ const HAMTEntry *HAMT_next(const HAMTEntry *prev);
+
+/** Get the corresponding data for a HAMT entry.
+ * \param entry HAMT entry (as returned by HAMT_first() and HAMT_next())
+ * \return Corresponding data item.
+ */
+YASM_LIB_DECL
+void *HAMTEntry_get_data(const HAMTEntry *entry);
+
+#endif
diff --git a/libyasm/insn.c b/libyasm/insn.c
new file mode 100644
index 0000000..8f7a4c1
--- /dev/null
+++ b/libyasm/insn.c
@@ -0,0 +1,295 @@
+/*
+ * Mnemonic instruction bytecode
+ *
+ * Copyright (C) 2005-2007 Peter Johnson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "util.h"
+
+#include "libyasm-stdint.h"
+#include "coretype.h"
+
+#include "errwarn.h"
+#include "expr.h"
+#include "value.h"
+
+#include "bytecode.h"
+#include "insn.h"
+#include "arch.h"
+
+
+void
+yasm_ea_set_segreg(yasm_effaddr *ea, uintptr_t segreg)
+{
+ if (!ea)
+ return;
+
+ if (segreg != 0 && ea->segreg != 0)
+ yasm_warn_set(YASM_WARN_GENERAL,
+ N_("multiple segment overrides, using leftmost"));
+
+ ea->segreg = segreg;
+}
+
+yasm_insn_operand *
+yasm_operand_create_reg(uintptr_t reg)
+{
+ yasm_insn_operand *retval = yasm_xmalloc(sizeof(yasm_insn_operand));
+
+ retval->type = YASM_INSN__OPERAND_REG;
+ retval->data.reg = reg;
+ retval->seg = 0;
+ retval->targetmod = 0;
+ retval->size = 0;
+ retval->deref = 0;
+ retval->strict = 0;
+
+ return retval;
+}
+
+yasm_insn_operand *
+yasm_operand_create_segreg(uintptr_t segreg)
+{
+ yasm_insn_operand *retval = yasm_xmalloc(sizeof(yasm_insn_operand));
+
+ retval->type = YASM_INSN__OPERAND_SEGREG;
+ retval->data.reg = segreg;
+ retval->seg = 0;
+ retval->targetmod = 0;
+ retval->size = 0;
+ retval->deref = 0;
+ retval->strict = 0;
+
+ return retval;
+}
+
+yasm_insn_operand *
+yasm_operand_create_mem(/*@only@*/ yasm_effaddr *ea)
+{
+ yasm_insn_operand *retval = yasm_xmalloc(sizeof(yasm_insn_operand));
+
+ retval->type = YASM_INSN__OPERAND_MEMORY;
+ retval->data.ea = ea;
+ retval->seg = 0;
+ retval->targetmod = 0;
+ retval->size = 0;
+ retval->deref = 0;
+ retval->strict = 0;
+ retval->size = ea->data_len * 8;
+
+ return retval;
+}
+
+yasm_insn_operand *
+yasm_operand_create_imm(/*@only@*/ yasm_expr *val)
+{
+ yasm_insn_operand *retval;
+ const uintptr_t *reg;
+
+ reg = yasm_expr_get_reg(&val, 0);
+ if (reg) {
+ retval = yasm_operand_create_reg(*reg);
+ yasm_expr_destroy(val);
+ } else {
+ retval = yasm_xmalloc(sizeof(yasm_insn_operand));
+ retval->type = YASM_INSN__OPERAND_IMM;
+ retval->data.val = val;
+ retval->seg = 0;
+ retval->targetmod = 0;
+ retval->size = 0;
+ retval->deref = 0;
+ retval->strict = 0;
+ }
+
+ return retval;
+}
+
+yasm_insn_operand *
+yasm_insn_ops_append(yasm_insn *insn, yasm_insn_operand *op)
+{
+ if (op) {
+ insn->num_operands++;
+ STAILQ_INSERT_TAIL(&insn->operands, op, link);
+ return op;
+ }
+ return (yasm_insn_operand *)NULL;
+}
+
+void
+yasm_insn_add_prefix(yasm_insn *insn, uintptr_t prefix)
+{
+ insn->prefixes =
+ yasm_xrealloc(insn->prefixes,
+ (insn->num_prefixes+1)*sizeof(uintptr_t));
+ insn->prefixes[insn->num_prefixes] = prefix;
+ insn->num_prefixes++;
+}
+
+void
+yasm_insn_add_seg_prefix(yasm_insn *insn, uintptr_t segreg)
+{
+ insn->segregs =
+ yasm_xrealloc(insn->segregs, (insn->num_segregs+1)*sizeof(uintptr_t));
+ insn->segregs[insn->num_segregs] = segreg;
+ insn->num_segregs++;
+}
+
+void
+yasm_insn_initialize(yasm_insn *insn)
+{
+ STAILQ_INIT(&insn->operands);
+
+ insn->prefixes = NULL;
+ insn->segregs = NULL;
+
+ insn->num_operands = 0;
+ insn->num_prefixes = 0;
+ insn->num_segregs = 0;
+}
+
+void
+yasm_insn_delete(yasm_insn *insn,
+ void (*ea_destroy) (/*@only@*/ yasm_effaddr *))
+{
+ if (insn->num_operands > 0) {
+ yasm_insn_operand *cur, *next;
+
+ cur = STAILQ_FIRST(&insn->operands);
+ while (cur) {
+ next = STAILQ_NEXT(cur, link);
+ switch (cur->type) {
+ case YASM_INSN__OPERAND_MEMORY:
+ ea_destroy(cur->data.ea);
+ break;
+ case YASM_INSN__OPERAND_IMM:
+ yasm_expr_destroy(cur->data.val);
+ break;
+ default:
+ break;
+ }
+ yasm_xfree(cur);
+ cur = next;
+ }
+ }
+ if (insn->num_prefixes > 0)
+ yasm_xfree(insn->prefixes);
+ if (insn->num_segregs > 0)
+ yasm_xfree(insn->segregs);
+}
+
+void
+yasm_insn_print(const yasm_insn *insn, FILE *f, int indent_level)
+{
+ const yasm_insn_operand *op;
+
+ STAILQ_FOREACH (op, &insn->operands, link) {
+ switch (op->type) {
+ case YASM_INSN__OPERAND_REG:
+ fprintf(f, "%*sReg=", indent_level, "");
+ /*yasm_arch_reg_print(arch, op->data.reg, f);*/
+ fprintf(f, "\n");
+ break;
+ case YASM_INSN__OPERAND_SEGREG:
+ fprintf(f, "%*sSegReg=", indent_level, "");
+ /*yasm_arch_segreg_print(arch, op->data.reg, f);*/
+ fprintf(f, "\n");
+ break;
+ case YASM_INSN__OPERAND_MEMORY:
+ fprintf(f, "%*sMemory=\n", indent_level, "");
+ /*yasm_arch_ea_print(arch, op->data.ea, f, indent_level);*/
+ break;
+ case YASM_INSN__OPERAND_IMM:
+ fprintf(f, "%*sImm=", indent_level, "");
+ yasm_expr_print(op->data.val, f);
+ fprintf(f, "\n");
+ break;
+ }
+ fprintf(f, "%*sTargetMod=%lx\n", indent_level+1, "",
+ (unsigned long)op->targetmod);
+ fprintf(f, "%*sSize=%u\n", indent_level+1, "", op->size);
+ fprintf(f, "%*sDeref=%d, Strict=%d\n", indent_level+1, "",
+ (int)op->deref, (int)op->strict);
+ }
+}
+
+void
+yasm_insn_finalize(yasm_insn *insn)
+{
+ unsigned int i;
+ yasm_insn_operand *op;
+ yasm_error_class eclass;
+ char *str, *xrefstr;
+ unsigned long xrefline;
+
+ /* Simplify the operands' expressions first. */
+ for (i = 0, op = yasm_insn_ops_first(insn);
+ op && i<insn->num_operands; op = yasm_insn_op_next(op), i++) {
+ /* Check operand type */
+ switch (op->type) {
+ case YASM_INSN__OPERAND_MEMORY:
+ /* Don't get over-ambitious here; some archs' memory expr
+ * parser are sensitive to the presence of *1, etc, so don't
+ * simplify reg*1 identities.
+ */
+ if (op->data.ea)
+ op->data.ea->disp.abs =
+ yasm_expr__level_tree(op->data.ea->disp.abs, 1, 1, 0,
+ 0, NULL, NULL);
+ if (yasm_error_occurred()) {
+ /* Add a pointer to where it was used to the error */
+ yasm_error_fetch(&eclass, &str, &xrefline, &xrefstr);
+ if (xrefstr) {
+ yasm_error_set_xref(xrefline, "%s", xrefstr);
+ yasm_xfree(xrefstr);
+ }
+ if (str) {
+ yasm_error_set(eclass, "%s in memory expression", str);
+ yasm_xfree(str);
+ }
+ return;
+ }
+ break;
+ case YASM_INSN__OPERAND_IMM:
+ op->data.val =
+ yasm_expr__level_tree(op->data.val, 1, 1, 1, 0, NULL,
+ NULL);
+ if (yasm_error_occurred()) {
+ /* Add a pointer to where it was used to the error */
+ yasm_error_fetch(&eclass, &str, &xrefline, &xrefstr);
+ if (xrefstr) {
+ yasm_error_set_xref(xrefline, "%s", xrefstr);
+ yasm_xfree(xrefstr);
+ }
+ if (str) {
+ yasm_error_set(eclass, "%s in immediate expression",
+ str);
+ yasm_xfree(str);
+ }
+ return;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+}
diff --git a/libyasm/insn.h b/libyasm/insn.h
new file mode 100644
index 0000000..d2d175d
--- /dev/null
+++ b/libyasm/insn.h
@@ -0,0 +1,269 @@
+/**
+ * \file libyasm/insn.h
+ * \brief YASM mnenomic instruction.
+ *
+ * \license
+ * Copyright (C) 2002-2007 Peter Johnson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * \endlicense
+ */
+#ifndef YASM_INSN_H
+#define YASM_INSN_H
+
+#ifndef YASM_LIB_DECL
+#define YASM_LIB_DECL
+#endif
+
+/** Base structure for an effective address. As with all base
+ * structures, must be present as the first element in any
+ * #yasm_arch implementation of an effective address.
+ */
+struct yasm_effaddr {
+ yasm_value disp; /**< address displacement */
+
+ /** Segment register override (0 if none). */
+ uintptr_t segreg;
+
+ /** 1 if length of disp must be >0. */
+ unsigned int need_nonzero_len:1;
+
+ /** 1 if a displacement should be present in the output. */
+ unsigned int need_disp:1;
+
+ /** 1 if reg*2 should not be split into reg+reg. (0 if not).
+ * This flag indicates (for architectures that support complex effective
+ * addresses such as x86) if various types of complex effective addresses
+ * can be split into different forms in order to minimize instruction
+ * length.
+ */
+ unsigned int nosplit:1;
+
+ /** 1 if effective address is /definitely/ an effective address.
+ * This is used in e.g. the GAS parser to differentiate
+ * between "expr" (which might or might not be an effective address) and
+ * "expr(,1)" (which is definitely an effective address).
+ */
+ unsigned int strong:1;
+
+ /** 1 if effective address is forced PC-relative. */
+ unsigned int pc_rel:1;
+
+ /** 1 if effective address is forced non-PC-relative. */
+ unsigned int not_pc_rel:1;
+
+ /** length of pointed data (in bytes), 0 if unknown. */
+ unsigned int data_len;
+};
+
+/** An instruction operand (opaque type). */
+typedef struct yasm_insn_operand yasm_insn_operand;
+
+/** The type of an instruction operand. */
+typedef enum yasm_insn_operand_type {
+ YASM_INSN__OPERAND_REG = 1, /**< A register. */
+ YASM_INSN__OPERAND_SEGREG, /**< A segment register. */
+ YASM_INSN__OPERAND_MEMORY, /**< An effective address
+ * (memory reference). */
+ YASM_INSN__OPERAND_IMM /**< An immediate or jump target. */
+} yasm_insn_operand_type;
+
+/** An instruction operand. */
+struct yasm_insn_operand {
+ /** Link for building linked list of operands. \internal */
+ /*@reldef@*/ STAILQ_ENTRY(yasm_insn_operand) link;
+
+ /** Operand data. */
+ union {
+ uintptr_t reg; /**< Arch data for reg/segreg. */
+ yasm_effaddr *ea; /**< Effective address for memory references. */
+ yasm_expr *val; /**< Value of immediate or jump target. */
+ } data;
+
+ yasm_expr *seg; /**< Segment expression */
+
+ uintptr_t targetmod; /**< Arch target modifier, 0 if none. */
+
+ /** Specified size of the operand, in bits. 0 if not user-specified. */
+ unsigned int size:16;
+
+ /** Nonzero if dereference. Used for "*foo" in GAS.
+ * The reason for this is that by default in GAS, an unprefixed value
+ * is a memory address, except for jumps/calls, in which case it needs a
+ * "*" prefix to become a memory address (otherwise it's an immediate).
+ * This isn't knowable in the parser stage, so the parser sets this flag
+ * to indicate the "*" prefix has been used, and the arch needs to adjust
+ * the operand type appropriately depending on the instruction type.
+ */
+ unsigned int deref:1;
+
+ /** Nonzero if strict. Used for "strict foo" in NASM.
+ * This is used to inhibit optimization on otherwise "sized" values.
+ * For example, the user may just want to be explicit with the size on
+ * "push dword 4", but not actually want to force the immediate size to
+ * 4 bytes (rather wanting the optimizer to optimize it down to 1 byte as
+ * though "dword" was not specified). To indicate the immediate should
+ * actually be forced to 4 bytes, the user needs to write
+ * "push strict dword 4", which sets this flag.
+ */
+ unsigned int strict:1;
+
+ /** Operand type. */
+ unsigned int type:4;
+};
+
+/** Base structure for "instruction" bytecodes. These are the mnenomic
+ * (rather than raw) representation of instructions. As with all base
+ * structures, must be present as the first element in any
+ * #yasm_arch implementation of mnenomic instruction bytecodes.
+ */
+struct yasm_insn {
+ /** Linked list of operands. */
+ /*@reldef@*/ STAILQ_HEAD(yasm_insn_operands, yasm_insn_operand) operands;
+
+ /** Array of prefixes. */
+ /*@null@*/ uintptr_t *prefixes;
+
+ /** Array of segment prefixes. */
+ /*@null@*/ uintptr_t *segregs;
+
+ unsigned int num_operands; /**< Number of operands. */
+ unsigned int num_prefixes; /**< Number of prefixes. */
+ unsigned int num_segregs; /**< Number of segment prefixes. */
+};
+
+/** Set segment override for an effective address.
+ * Some architectures (such as x86) support segment overrides on effective
+ * addresses. A override of an override will result in a warning.
+ * \param ea effective address
+ * \param segreg segment register (0 if none)
+ */
+YASM_LIB_DECL
+void yasm_ea_set_segreg(yasm_effaddr *ea, uintptr_t segreg);
+
+/** Create an instruction operand from a register.
+ * \param reg register
+ * \return Newly allocated operand.
+ */
+YASM_LIB_DECL
+yasm_insn_operand *yasm_operand_create_reg(uintptr_t reg);
+
+/** Create an instruction operand from a segment register.
+ * \param segreg segment register
+ * \return Newly allocated operand.
+ */
+YASM_LIB_DECL
+yasm_insn_operand *yasm_operand_create_segreg(uintptr_t segreg);
+
+/** Create an instruction operand from an effective address.
+ * \param ea effective address
+ * \return Newly allocated operand.
+ */
+YASM_LIB_DECL
+yasm_insn_operand *yasm_operand_create_mem(/*@only@*/ yasm_effaddr *ea);
+
+/** Create an instruction operand from an immediate expression.
+ * Looks for cases of a single register and creates a register variant of
+ * #yasm_insn_operand.
+ * \param val immediate expression
+ * \return Newly allocated operand.
+ */
+YASM_LIB_DECL
+yasm_insn_operand *yasm_operand_create_imm(/*@only@*/ yasm_expr *val);
+
+/** Get the first operand in an instruction.
+ * \param insn instruction
+ * \return First operand (NULL if no operands).
+ */
+yasm_insn_operand *yasm_insn_ops_first(yasm_insn *insn);
+#define yasm_insn_ops_first(insn) STAILQ_FIRST(&((insn)->operands))
+
+/** Get the next operand in an instruction.
+ * \param op previous operand
+ * \return Next operand (NULL if op was the last operand).
+ */
+yasm_insn_operand *yasm_insn_op_next(yasm_insn_operand *op);
+#define yasm_insn_op_next(cur) STAILQ_NEXT(cur, link)
+
+/** Add operand to the end of an instruction.
+ * \note Does not make a copy of the operand; so don't pass this function
+ * static or local variables, and discard the op pointer after calling
+ * this function.
+ * \param insn instruction
+ * \param op operand (may be NULL)
+ * \return If operand was actually appended (it wasn't NULL), the operand;
+ * otherwise NULL.
+ */
+YASM_LIB_DECL
+/*@null@*/ yasm_insn_operand *yasm_insn_ops_append
+ (yasm_insn *insn,
+ /*@returned@*/ /*@null@*/ yasm_insn_operand *op);
+
+/** Associate a prefix with an instruction.
+ * \param insn instruction
+ * \param prefix data that identifies the prefix
+ */
+YASM_LIB_DECL
+void yasm_insn_add_prefix(yasm_insn *insn, uintptr_t prefix);
+
+/** Associate a segment prefix with an instruction.
+ * \param insn instruction
+ * \param segreg data that identifies the segment register
+ */
+YASM_LIB_DECL
+void yasm_insn_add_seg_prefix(yasm_insn *insn, uintptr_t segreg);
+
+/** Initialize the common parts of an instruction.
+ * \internal For use by yasm_arch implementations only.
+ * \param insn instruction
+ */
+YASM_LIB_DECL
+void yasm_insn_initialize(/*@out@*/ yasm_insn *insn);
+
+/** Delete the common parts of an instruction.
+ * \internal For use by yasm_arch implementations only.
+ * \param insn instruction
+ * \param content if nonzero, deletes content of each operand
+ * \param arch architecture
+ */
+YASM_LIB_DECL
+void yasm_insn_delete(yasm_insn *insn,
+ void (*ea_destroy) (/*@only@*/ yasm_effaddr *));
+
+/** Print a list of instruction operands. For debugging purposes.
+ * \internal For use by yasm_arch implementations only.
+ * \param insn instruction
+ * \param f file
+ * \param indent_level indentation level
+ * \param arch architecture
+ */
+YASM_LIB_DECL
+void yasm_insn_print(const yasm_insn *insn, FILE *f, int indent_level);
+
+/** Finalize the common parts of an instruction.
+ * \internal For use by yasm_arch implementations only.
+ * \param insn instruction
+ */
+YASM_LIB_DECL
+void yasm_insn_finalize(yasm_insn *insn);
+
+#endif
diff --git a/libyasm/intnum.c b/libyasm/intnum.c
new file mode 100644
index 0000000..6feba33
--- /dev/null
+++ b/libyasm/intnum.c
@@ -0,0 +1,1096 @@
+/*
+ * Integer number functions.
+ *
+ * Copyright (C) 2001-2007 Peter Johnson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "util.h"
+
+#include <ctype.h>
+#include <limits.h>
+
+#include "coretype.h"
+#include "bitvect.h"
+#include "file.h"
+
+#include "errwarn.h"
+#include "intnum.h"
+
+
+/* "Native" "word" size for intnum calculations. */
+#define BITVECT_NATIVE_SIZE 256
+
+struct yasm_intnum {
+ union val {
+ long l; /* integer value (for integers <32 bits) */
+ wordptr bv; /* bit vector (for integers >=32 bits) */
+ } val;
+ enum { INTNUM_L, INTNUM_BV } type;
+};
+
+/* static bitvect used for conversions */
+static /*@only@*/ wordptr conv_bv;
+
+/* static bitvects used for computation */
+static /*@only@*/ wordptr result, spare, op1static, op2static;
+
+static /*@only@*/ BitVector_from_Dec_static_data *from_dec_data;
+
+
+void
+yasm_intnum_initialize(void)
+{
+ conv_bv = BitVector_Create(BITVECT_NATIVE_SIZE, FALSE);
+ result = BitVector_Create(BITVECT_NATIVE_SIZE, FALSE);
+ spare = BitVector_Create(BITVECT_NATIVE_SIZE, FALSE);
+ op1static = BitVector_Create(BITVECT_NATIVE_SIZE, FALSE);
+ op2static = BitVector_Create(BITVECT_NATIVE_SIZE, FALSE);
+ from_dec_data = BitVector_from_Dec_static_Boot(BITVECT_NATIVE_SIZE);
+}
+
+void
+yasm_intnum_cleanup(void)
+{
+ BitVector_from_Dec_static_Shutdown(from_dec_data);
+ BitVector_Destroy(op2static);
+ BitVector_Destroy(op1static);
+ BitVector_Destroy(spare);
+ BitVector_Destroy(result);
+ BitVector_Destroy(conv_bv);
+}
+
+/* Compress a bitvector into intnum storage.
+ * If saved as a bitvector, clones the passed bitvector.
+ * Can modify the passed bitvector.
+ */
+static void
+intnum_frombv(/*@out@*/ yasm_intnum *intn, wordptr bv)
+{
+ if (Set_Max(bv) < 31) {
+ intn->type = INTNUM_L;
+ intn->val.l = (long)BitVector_Chunk_Read(bv, 31, 0);
+ } else if (BitVector_msb_(bv)) {
+ /* Negative, negate and see if we'll fit into a long. */
+ unsigned long ul;
+ BitVector_Negate(bv, bv);
+ if (Set_Max(bv) >= 32 ||
+ ((ul = BitVector_Chunk_Read(bv, 32, 0)) & 0x80000000)) {
+ /* too negative */
+ BitVector_Negate(bv, bv);
+ intn->type = INTNUM_BV;
+ intn->val.bv = BitVector_Clone(bv);
+ } else {
+ intn->type = INTNUM_L;
+ intn->val.l = -((long)ul);
+ }
+ } else {
+ intn->type = INTNUM_BV;
+ intn->val.bv = BitVector_Clone(bv);
+ }
+}
+
+/* If intnum is a BV, returns its bitvector directly.
+ * If not, converts into passed bv and returns that instead.
+ */
+static wordptr
+intnum_tobv(/*@returned@*/ wordptr bv, const yasm_intnum *intn)
+{
+ if (intn->type == INTNUM_BV)
+ return intn->val.bv;
+
+ BitVector_Empty(bv);
+ if (intn->val.l >= 0)
+ BitVector_Chunk_Store(bv, 32, 0, (unsigned long)intn->val.l);
+ else {
+ BitVector_Chunk_Store(bv, 32, 0, (unsigned long)-intn->val.l);
+ BitVector_Negate(bv, bv);
+ }
+ return bv;
+}
+
+yasm_intnum *
+yasm_intnum_create_dec(char *str)
+{
+ yasm_intnum *intn = yasm_xmalloc(sizeof(yasm_intnum));
+
+ switch (BitVector_from_Dec_static(from_dec_data, conv_bv,
+ (unsigned char *)str)) {
+ case ErrCode_Pars:
+ yasm_error_set(YASM_ERROR_VALUE, N_("invalid decimal literal"));
+ break;
+ case ErrCode_Ovfl:
+ yasm_error_set(YASM_ERROR_OVERFLOW,
+ N_("Numeric constant too large for internal format"));
+ break;
+ default:
+ break;
+ }
+ intnum_frombv(intn, conv_bv);
+ return intn;
+}
+
+yasm_intnum *
+yasm_intnum_create_bin(char *str)
+{
+ yasm_intnum *intn = yasm_xmalloc(sizeof(yasm_intnum));
+
+ switch (BitVector_from_Bin(conv_bv, (unsigned char *)str)) {
+ case ErrCode_Pars:
+ yasm_error_set(YASM_ERROR_VALUE, N_("invalid binary literal"));
+ break;
+ case ErrCode_Ovfl:
+ yasm_error_set(YASM_ERROR_OVERFLOW,
+ N_("Numeric constant too large for internal format"));
+ break;
+ default:
+ break;
+ }
+ intnum_frombv(intn, conv_bv);
+ return intn;
+}
+
+yasm_intnum *
+yasm_intnum_create_oct(char *str)
+{
+ yasm_intnum *intn = yasm_xmalloc(sizeof(yasm_intnum));
+
+ switch (BitVector_from_Oct(conv_bv, (unsigned char *)str)) {
+ case ErrCode_Pars:
+ yasm_error_set(YASM_ERROR_VALUE, N_("invalid octal literal"));
+ break;
+ case ErrCode_Ovfl:
+ yasm_error_set(YASM_ERROR_OVERFLOW,
+ N_("Numeric constant too large for internal format"));
+ break;
+ default:
+ break;
+ }
+ intnum_frombv(intn, conv_bv);
+ return intn;
+}
+
+yasm_intnum *
+yasm_intnum_create_hex(char *str)
+{
+ yasm_intnum *intn = yasm_xmalloc(sizeof(yasm_intnum));
+
+ switch (BitVector_from_Hex(conv_bv, (unsigned char *)str)) {
+ case ErrCode_Pars:
+ yasm_error_set(YASM_ERROR_VALUE, N_("invalid hex literal"));
+ break;
+ case ErrCode_Ovfl:
+ yasm_error_set(YASM_ERROR_OVERFLOW,
+ N_("Numeric constant too large for internal format"));
+ break;
+ default:
+ break;
+ }
+ intnum_frombv(intn, conv_bv);
+ return intn;
+}
+
+/*@-usedef -compdef -uniondef@*/
+yasm_intnum *
+yasm_intnum_create_charconst_nasm(const char *str)
+{
+ yasm_intnum *intn = yasm_xmalloc(sizeof(yasm_intnum));
+ size_t len = strlen(str);
+
+ if(len*8 > BITVECT_NATIVE_SIZE)
+ yasm_error_set(YASM_ERROR_OVERFLOW,
+ N_("Character constant too large for internal format"));
+
+ /* be conservative in choosing bitvect in case MSB is set */
+ if (len > 3) {
+ BitVector_Empty(conv_bv);
+ intn->type = INTNUM_BV;
+ } else {
+ intn->val.l = 0;
+ intn->type = INTNUM_L;
+ }
+
+ switch (len) {
+ case 3:
+ intn->val.l |= ((unsigned long)str[2]) & 0xff;
+ intn->val.l <<= 8;
+ /*@fallthrough@*/
+ case 2:
+ intn->val.l |= ((unsigned long)str[1]) & 0xff;
+ intn->val.l <<= 8;
+ /*@fallthrough@*/
+ case 1:
+ intn->val.l |= ((unsigned long)str[0]) & 0xff;
+ case 0:
+ break;
+ default:
+ /* >=32 bit conversion */
+ while (len) {
+ BitVector_Move_Left(conv_bv, 8);
+ BitVector_Chunk_Store(conv_bv, 8, 0,
+ ((unsigned long)str[--len]) & 0xff);
+ }
+ intn->val.bv = BitVector_Clone(conv_bv);
+ }
+
+ return intn;
+}
+
+yasm_intnum *
+yasm_intnum_create_charconst_tasm(const char *str)
+{
+ yasm_intnum *intn = yasm_xmalloc(sizeof(yasm_intnum));
+ size_t len = strlen(str);
+ size_t i;
+
+ if(len*8 > BITVECT_NATIVE_SIZE)
+ yasm_error_set(YASM_ERROR_OVERFLOW,
+ N_("Character constant too large for internal format"));
+
+ /* be conservative in choosing bitvect in case MSB is set */
+ if (len > 3) {
+ BitVector_Empty(conv_bv);
+ intn->type = INTNUM_BV;
+ } else {
+ intn->val.l = 0;
+ intn->type = INTNUM_L;
+ }
+
+ /* tasm uses big endian notation */
+ i = 0;
+ switch (len) {
+ case 3:
+ intn->val.l |= ((unsigned long)str[i++]) & 0xff;
+ intn->val.l <<= 8;
+ /*@fallthrough@*/
+ case 2:
+ intn->val.l |= ((unsigned long)str[i++]) & 0xff;
+ intn->val.l <<= 8;
+ /*@fallthrough@*/
+ case 1:
+ intn->val.l |= ((unsigned long)str[i++]) & 0xff;
+ case 0:
+ break;
+ default:
+ /* >=32 bit conversion */
+ while (i < len) {
+ BitVector_Chunk_Store(conv_bv, 8, (len-i-1)*8,
+ ((unsigned long)str[i]) & 0xff);
+ i++;
+ }
+ intn->val.bv = BitVector_Clone(conv_bv);
+ }
+
+ return intn;
+}
+/*@=usedef =compdef =uniondef@*/
+
+yasm_intnum *
+yasm_intnum_create_uint(unsigned long i)
+{
+ yasm_intnum *intn = yasm_xmalloc(sizeof(yasm_intnum));
+
+ if (i > LONG_MAX) {
+ /* Too big, store as bitvector */
+ intn->val.bv = BitVector_Create(BITVECT_NATIVE_SIZE, TRUE);
+ intn->type = INTNUM_BV;
+ BitVector_Chunk_Store(intn->val.bv, 32, 0, i);
+ } else {
+ intn->val.l = (long)i;
+ intn->type = INTNUM_L;
+ }
+
+ return intn;
+}
+
+yasm_intnum *
+yasm_intnum_create_int(long i)
+{
+ yasm_intnum *intn = yasm_xmalloc(sizeof(yasm_intnum));
+
+ intn->val.l = i;
+ intn->type = INTNUM_L;
+
+ return intn;
+}
+
+yasm_intnum *
+yasm_intnum_create_leb128(const unsigned char *ptr, int sign,
+ unsigned long *size)
+{
+ yasm_intnum *intn = yasm_xmalloc(sizeof(yasm_intnum));
+ const unsigned char *ptr_orig = ptr;
+ unsigned long i = 0;
+
+ BitVector_Empty(conv_bv);
+ for (;;) {
+ BitVector_Chunk_Store(conv_bv, 7, i, *ptr);
+ i += 7;
+ if ((*ptr & 0x80) != 0x80)
+ break;
+ ptr++;
+ }
+
+ *size = (unsigned long)(ptr-ptr_orig)+1;
+
+ if(i > BITVECT_NATIVE_SIZE)
+ yasm_error_set(YASM_ERROR_OVERFLOW,
+ N_("Numeric constant too large for internal format"));
+ else if (sign && (*ptr & 0x40) == 0x40)
+ BitVector_Interval_Fill(conv_bv, i, BITVECT_NATIVE_SIZE-1);
+
+ intnum_frombv(intn, conv_bv);
+ return intn;
+}
+
+yasm_intnum *
+yasm_intnum_create_sized(unsigned char *ptr, int sign, size_t srcsize,
+ int bigendian)
+{
+ yasm_intnum *intn = yasm_xmalloc(sizeof(yasm_intnum));
+ unsigned long i = 0;
+
+ if (srcsize*8 > BITVECT_NATIVE_SIZE)
+ yasm_error_set(YASM_ERROR_OVERFLOW,
+ N_("Numeric constant too large for internal format"));
+
+ /* Read the buffer into a bitvect */
+ BitVector_Empty(conv_bv);
+ if (bigendian) {
+ /* TODO */
+ yasm_internal_error(N_("big endian not implemented"));
+ } else {
+ for (i = 0; i < srcsize; i++)
+ BitVector_Chunk_Store(conv_bv, 8, i*8, ptr[i]);
+ }
+
+ /* Sign extend if needed */
+ if (srcsize*8 < BITVECT_NATIVE_SIZE && sign && (ptr[i-1] & 0x80) == 0x80)
+ BitVector_Interval_Fill(conv_bv, i*8, BITVECT_NATIVE_SIZE-1);
+
+ intnum_frombv(intn, conv_bv);
+ return intn;
+}
+
+yasm_intnum *
+yasm_intnum_copy(const yasm_intnum *intn)
+{
+ yasm_intnum *n = yasm_xmalloc(sizeof(yasm_intnum));
+
+ switch (intn->type) {
+ case INTNUM_L:
+ n->val.l = intn->val.l;
+ break;
+ case INTNUM_BV:
+ n->val.bv = BitVector_Clone(intn->val.bv);
+ break;
+ }
+ n->type = intn->type;
+
+ return n;
+}
+
+void
+yasm_intnum_destroy(yasm_intnum *intn)
+{
+ if (intn->type == INTNUM_BV)
+ BitVector_Destroy(intn->val.bv);
+ yasm_xfree(intn);
+}
+
+/*@-nullderef -nullpass -branchstate@*/
+int
+yasm_intnum_calc(yasm_intnum *acc, yasm_expr_op op, yasm_intnum *operand)
+{
+ boolean carry = 0;
+ wordptr op1, op2 = NULL;
+ N_int count;
+
+ /* Always do computations with in full bit vector.
+ * Bit vector results must be calculated through intermediate storage.
+ */
+ op1 = intnum_tobv(op1static, acc);
+ if (operand)
+ op2 = intnum_tobv(op2static, operand);
+
+ if (!operand && op != YASM_EXPR_NEG && op != YASM_EXPR_NOT &&
+ op != YASM_EXPR_LNOT) {
+ yasm_error_set(YASM_ERROR_ARITHMETIC,
+ N_("operation needs an operand"));
+ BitVector_Empty(result);
+ return 1;
+ }
+
+ /* A operation does a bitvector computation if result is allocated. */
+ switch (op) {
+ case YASM_EXPR_ADD:
+ BitVector_add(result, op1, op2, &carry);
+ break;
+ case YASM_EXPR_SUB:
+ BitVector_sub(result, op1, op2, &carry);
+ break;
+ case YASM_EXPR_MUL:
+ BitVector_Multiply(result, op1, op2);
+ break;
+ case YASM_EXPR_DIV:
+ /* TODO: make sure op1 and op2 are unsigned */
+ if (BitVector_is_empty(op2)) {
+ yasm_error_set(YASM_ERROR_ZERO_DIVISION, N_("divide by zero"));
+ BitVector_Empty(result);
+ return 1;
+ } else
+ BitVector_Divide(result, op1, op2, spare);
+ break;
+ case YASM_EXPR_SIGNDIV:
+ if (BitVector_is_empty(op2)) {
+ yasm_error_set(YASM_ERROR_ZERO_DIVISION, N_("divide by zero"));
+ BitVector_Empty(result);
+ return 1;
+ } else
+ BitVector_Divide(result, op1, op2, spare);
+ break;
+ case YASM_EXPR_MOD:
+ /* TODO: make sure op1 and op2 are unsigned */
+ if (BitVector_is_empty(op2)) {
+ yasm_error_set(YASM_ERROR_ZERO_DIVISION, N_("divide by zero"));
+ BitVector_Empty(result);
+ return 1;
+ } else
+ BitVector_Divide(spare, op1, op2, result);
+ break;
+ case YASM_EXPR_SIGNMOD:
+ if (BitVector_is_empty(op2)) {
+ yasm_error_set(YASM_ERROR_ZERO_DIVISION, N_("divide by zero"));
+ BitVector_Empty(result);
+ return 1;
+ } else
+ BitVector_Divide(spare, op1, op2, result);
+ break;
+ case YASM_EXPR_NEG:
+ BitVector_Negate(result, op1);
+ break;
+ case YASM_EXPR_NOT:
+ Set_Complement(result, op1);
+ break;
+ case YASM_EXPR_OR:
+ Set_Union(result, op1, op2);
+ break;
+ case YASM_EXPR_AND:
+ Set_Intersection(result, op1, op2);
+ break;
+ case YASM_EXPR_XOR:
+ Set_ExclusiveOr(result, op1, op2);
+ break;
+ case YASM_EXPR_XNOR:
+ Set_ExclusiveOr(result, op1, op2);
+ Set_Complement(result, result);
+ break;
+ case YASM_EXPR_NOR:
+ Set_Union(result, op1, op2);
+ Set_Complement(result, result);
+ break;
+ case YASM_EXPR_SHL:
+ if (operand->type == INTNUM_L && operand->val.l >= 0) {
+ BitVector_Copy(result, op1);
+ BitVector_Move_Left(result, (N_int)operand->val.l);
+ } else /* don't even bother, just zero result */
+ BitVector_Empty(result);
+ break;
+ case YASM_EXPR_SHR:
+ if (operand->type == INTNUM_L && operand->val.l >= 0) {
+ BitVector_Copy(result, op1);
+ carry = BitVector_msb_(op1);
+ count = (N_int)operand->val.l;
+ while (count-- > 0)
+ BitVector_shift_right(result, carry);
+ } else /* don't even bother, just zero result */
+ BitVector_Empty(result);
+ break;
+ case YASM_EXPR_LOR:
+ BitVector_Empty(result);
+ BitVector_LSB(result, !BitVector_is_empty(op1) ||
+ !BitVector_is_empty(op2));
+ break;
+ case YASM_EXPR_LAND:
+ BitVector_Empty(result);
+ BitVector_LSB(result, !BitVector_is_empty(op1) &&
+ !BitVector_is_empty(op2));
+ break;
+ case YASM_EXPR_LNOT:
+ BitVector_Empty(result);
+ BitVector_LSB(result, BitVector_is_empty(op1));
+ break;
+ case YASM_EXPR_LXOR:
+ BitVector_Empty(result);
+ BitVector_LSB(result, !BitVector_is_empty(op1) ^
+ !BitVector_is_empty(op2));
+ break;
+ case YASM_EXPR_LXNOR:
+ BitVector_Empty(result);
+ BitVector_LSB(result, !(!BitVector_is_empty(op1) ^
+ !BitVector_is_empty(op2)));
+ break;
+ case YASM_EXPR_LNOR:
+ BitVector_Empty(result);
+ BitVector_LSB(result, !(!BitVector_is_empty(op1) ||
+ !BitVector_is_empty(op2)));
+ break;
+ case YASM_EXPR_EQ:
+ BitVector_Empty(result);
+ BitVector_LSB(result, BitVector_equal(op1, op2));
+ break;
+ case YASM_EXPR_LT:
+ BitVector_Empty(result);
+ BitVector_LSB(result, BitVector_Compare(op1, op2) < 0);
+ break;
+ case YASM_EXPR_GT:
+ BitVector_Empty(result);
+ BitVector_LSB(result, BitVector_Compare(op1, op2) > 0);
+ break;
+ case YASM_EXPR_LE:
+ BitVector_Empty(result);
+ BitVector_LSB(result, BitVector_Compare(op1, op2) <= 0);
+ break;
+ case YASM_EXPR_GE:
+ BitVector_Empty(result);
+ BitVector_LSB(result, BitVector_Compare(op1, op2) >= 0);
+ break;
+ case YASM_EXPR_NE:
+ BitVector_Empty(result);
+ BitVector_LSB(result, !BitVector_equal(op1, op2));
+ break;
+ case YASM_EXPR_SEG:
+ yasm_error_set(YASM_ERROR_ARITHMETIC, N_("invalid use of '%s'"),
+ "SEG");
+ break;
+ case YASM_EXPR_WRT:
+ yasm_error_set(YASM_ERROR_ARITHMETIC, N_("invalid use of '%s'"),
+ "WRT");
+ break;
+ case YASM_EXPR_SEGOFF:
+ yasm_error_set(YASM_ERROR_ARITHMETIC, N_("invalid use of '%s'"),
+ ":");
+ break;
+ case YASM_EXPR_IDENT:
+ if (result)
+ BitVector_Copy(result, op1);
+ break;
+ default:
+ yasm_error_set(YASM_ERROR_ARITHMETIC,
+ N_("invalid operation in intnum calculation"));
+ BitVector_Empty(result);
+ return 1;
+ }
+
+ /* Try to fit the result into 32 bits if possible */
+ if (acc->type == INTNUM_BV)
+ BitVector_Destroy(acc->val.bv);
+ intnum_frombv(acc, result);
+ return 0;
+}
+/*@=nullderef =nullpass =branchstate@*/
+
+int
+yasm_intnum_compare(const yasm_intnum *intn1, const yasm_intnum *intn2)
+{
+ wordptr op1, op2;
+
+ if (intn1->type == INTNUM_L && intn2->type == INTNUM_L) {
+ if (intn1->val.l < intn2->val.l)
+ return -1;
+ if (intn1->val.l > intn2->val.l)
+ return 1;
+ return 0;
+ }
+
+ op1 = intnum_tobv(op1static, intn1);
+ op2 = intnum_tobv(op2static, intn2);
+ return BitVector_Compare(op1, op2);
+}
+
+void
+yasm_intnum_zero(yasm_intnum *intn)
+{
+ yasm_intnum_set_int(intn, 0);
+}
+
+void
+yasm_intnum_set(yasm_intnum *intn, const yasm_intnum *val)
+{
+ if (intn->type == val->type) {
+ switch (val->type) {
+ case INTNUM_L:
+ intn->val.l = val->val.l;
+ break;
+ case INTNUM_BV:
+ BitVector_Copy(intn->val.bv, val->val.bv);
+ break;
+ }
+ } else {
+ switch (val->type) {
+ case INTNUM_L:
+ BitVector_Destroy(intn->val.bv);
+ intn->val.l = val->val.l;
+ break;
+ case INTNUM_BV:
+ intn->val.bv = BitVector_Clone(val->val.bv);
+ break;
+ }
+ intn->type = val->type;
+ }
+}
+
+void
+yasm_intnum_set_uint(yasm_intnum *intn, unsigned long val)
+{
+ if (val > LONG_MAX) {
+ if (intn->type != INTNUM_BV) {
+ intn->val.bv = BitVector_Create(BITVECT_NATIVE_SIZE, TRUE);
+ intn->type = INTNUM_BV;
+ }
+ BitVector_Chunk_Store(intn->val.bv, 32, 0, val);
+ } else {
+ if (intn->type == INTNUM_BV) {
+ BitVector_Destroy(intn->val.bv);
+ intn->type = INTNUM_L;
+ }
+ intn->val.l = (long)val;
+ }
+}
+
+void
+yasm_intnum_set_int(yasm_intnum *intn, long val)
+{
+ if (intn->type == INTNUM_BV)
+ BitVector_Destroy(intn->val.bv);
+ intn->type = INTNUM_L;
+ intn->val.l = val;
+}
+
+int
+yasm_intnum_is_zero(const yasm_intnum *intn)
+{
+ return (intn->type == INTNUM_L && intn->val.l == 0);
+}
+
+int
+yasm_intnum_is_pos1(const yasm_intnum *intn)
+{
+ return (intn->type == INTNUM_L && intn->val.l == 1);
+}
+
+int
+yasm_intnum_is_neg1(const yasm_intnum *intn)
+{
+ return (intn->type == INTNUM_L && intn->val.l == -1);
+}
+
+int
+yasm_intnum_sign(const yasm_intnum *intn)
+{
+ if (intn->type == INTNUM_L) {
+ if (intn->val.l == 0)
+ return 0;
+ else if (intn->val.l < 0)
+ return -1;
+ else
+ return 1;
+ } else
+ return BitVector_Sign(intn->val.bv);
+}
+
+unsigned long
+yasm_intnum_get_uint(const yasm_intnum *intn)
+{
+ switch (intn->type) {
+ case INTNUM_L:
+ if (intn->val.l < 0)
+ return 0;
+ return (unsigned long)intn->val.l;
+ case INTNUM_BV:
+ if (BitVector_msb_(intn->val.bv))
+ return 0;
+ if (Set_Max(intn->val.bv) > 32)
+ return ULONG_MAX;
+ return BitVector_Chunk_Read(intn->val.bv, 32, 0);
+ default:
+ yasm_internal_error(N_("unknown intnum type"));
+ /*@notreached@*/
+ return 0;
+ }
+}
+
+long
+yasm_intnum_get_int(const yasm_intnum *intn)
+{
+ switch (intn->type) {
+ case INTNUM_L:
+ return intn->val.l;
+ case INTNUM_BV:
+ if (BitVector_msb_(intn->val.bv)) {
+ /* it's negative: negate the bitvector to get a positive
+ * number, then negate the positive number.
+ */
+ unsigned long ul;
+
+ BitVector_Negate(conv_bv, intn->val.bv);
+ if (Set_Max(conv_bv) >= 32) {
+ /* too negative */
+ return LONG_MIN;
+ }
+ ul = BitVector_Chunk_Read(conv_bv, 32, 0);
+ /* check for too negative */
+ return (ul & 0x80000000) ? LONG_MIN : -((long)ul);
+ }
+
+ /* it's positive, and since it's a BV, it must be >0x7FFFFFFF */
+ return LONG_MAX;
+ default:
+ yasm_internal_error(N_("unknown intnum type"));
+ /*@notreached@*/
+ return 0;
+ }
+}
+
+void
+yasm_intnum_get_sized(const yasm_intnum *intn, unsigned char *ptr,
+ size_t destsize, size_t valsize, int shift,
+ int bigendian, int warn)
+{
+ wordptr op1 = op1static, op2;
+ unsigned char *buf;
+ unsigned int len;
+ size_t rshift = shift < 0 ? (size_t)(-shift) : 0;
+ int carry_in;
+
+ /* Currently don't support destinations larger than our native size */
+ if (destsize*8 > BITVECT_NATIVE_SIZE)
+ yasm_internal_error(N_("destination too large"));
+
+ /* General size warnings */
+ if (warn<0 && !yasm_intnum_check_size(intn, valsize, rshift, 1))
+ yasm_warn_set(YASM_WARN_GENERAL,
+ N_("value does not fit in signed %d bit field"),
+ valsize);
+ if (warn>0 && !yasm_intnum_check_size(intn, valsize, rshift, 2))
+ yasm_warn_set(YASM_WARN_GENERAL,
+ N_("value does not fit in %d bit field"), valsize);
+
+ /* Read the original data into a bitvect */
+ if (bigendian) {
+ /* TODO */
+ yasm_internal_error(N_("big endian not implemented"));
+ } else
+ BitVector_Block_Store(op1, ptr, (N_int)destsize);
+
+ /* If not already a bitvect, convert value to be written to a bitvect */
+ op2 = intnum_tobv(op2static, intn);
+
+ /* Check low bits if right shifting and warnings enabled */
+ if (warn && rshift > 0) {
+ BitVector_Copy(conv_bv, op2);
+ BitVector_Move_Left(conv_bv, (N_int)(BITVECT_NATIVE_SIZE-rshift));
+ if (!BitVector_is_empty(conv_bv))
+ yasm_warn_set(YASM_WARN_GENERAL,
+ N_("misaligned value, truncating to boundary"));
+ }
+
+ /* Shift right if needed */
+ if (rshift > 0) {
+ carry_in = BitVector_msb_(op2);
+ while (rshift-- > 0)
+ BitVector_shift_right(op2, carry_in);
+ shift = 0;
+ }
+
+ /* Write the new value into the destination bitvect */
+ BitVector_Interval_Copy(op1, op2, (unsigned int)shift, 0, (N_int)valsize);
+
+ /* Write out the new data */
+ buf = BitVector_Block_Read(op1, &len);
+ if (bigendian) {
+ /* TODO */
+ yasm_internal_error(N_("big endian not implemented"));
+ } else
+ memcpy(ptr, buf, destsize);
+ yasm_xfree(buf);
+}
+
+/* Return 1 if okay size, 0 if not */
+int
+yasm_intnum_check_size(const yasm_intnum *intn, size_t size, size_t rshift,
+ int rangetype)
+{
+ wordptr val;
+
+ /* If not already a bitvect, convert value to a bitvect */
+ if (intn->type == INTNUM_BV) {
+ if (rshift > 0) {
+ val = conv_bv;
+ BitVector_Copy(val, intn->val.bv);
+ } else
+ val = intn->val.bv;
+ } else
+ val = intnum_tobv(conv_bv, intn);
+
+ if (size >= BITVECT_NATIVE_SIZE)
+ return 1;
+
+ if (rshift > 0) {
+ int carry_in = BitVector_msb_(val);
+ while (rshift-- > 0)
+ BitVector_shift_right(val, carry_in);
+ }
+
+ if (rangetype > 0) {
+ if (BitVector_msb_(val)) {
+ /* it's negative */
+ int retval;
+
+ BitVector_Negate(conv_bv, val);
+ BitVector_dec(conv_bv, conv_bv);
+ retval = Set_Max(conv_bv) < (long)size-1;
+
+ return retval;
+ }
+
+ if (rangetype == 1)
+ size--;
+ }
+ return (Set_Max(val) < (long)size);
+}
+
+int
+yasm_intnum_in_range(const yasm_intnum *intn, long low, long high)
+{
+ wordptr val = intnum_tobv(result, intn);
+ wordptr lval = op1static;
+ wordptr hval = op2static;
+
+ /* Convert high and low to bitvects */
+ BitVector_Empty(lval);
+ if (low >= 0)
+ BitVector_Chunk_Store(lval, 32, 0, (unsigned long)low);
+ else {
+ BitVector_Chunk_Store(lval, 32, 0, (unsigned long)(-low));
+ BitVector_Negate(lval, lval);
+ }
+
+ BitVector_Empty(hval);
+ if (high >= 0)
+ BitVector_Chunk_Store(hval, 32, 0, (unsigned long)high);
+ else {
+ BitVector_Chunk_Store(hval, 32, 0, (unsigned long)(-high));
+ BitVector_Negate(hval, hval);
+ }
+
+ /* Compare! */
+ return (BitVector_Compare(val, lval) >= 0
+ && BitVector_Compare(val, hval) <= 0);
+}
+
+static unsigned long
+get_leb128(wordptr val, unsigned char *ptr, int sign)
+{
+ unsigned long i, size;
+ unsigned char *ptr_orig = ptr;
+
+ if (sign) {
+ /* Signed mode */
+ if (BitVector_msb_(val)) {
+ /* Negative */
+ BitVector_Negate(conv_bv, val);
+ size = Set_Max(conv_bv)+2;
+ } else {
+ /* Positive */
+ size = Set_Max(val)+2;
+ }
+ } else {
+ /* Unsigned mode */
+ size = Set_Max(val)+1;
+ }
+
+ /* Positive/Unsigned write */
+ for (i=0; i<size; i += 7) {
+ *ptr = (unsigned char)BitVector_Chunk_Read(val, 7, i);
+ *ptr |= 0x80;
+ ptr++;
+ }
+ *(ptr-1) &= 0x7F; /* Clear MSB of last byte */
+ return (unsigned long)(ptr-ptr_orig);
+}
+
+static unsigned long
+size_leb128(wordptr val, int sign)
+{
+ if (sign) {
+ /* Signed mode */
+ if (BitVector_msb_(val)) {
+ /* Negative */
+ BitVector_Negate(conv_bv, val);
+ return (Set_Max(conv_bv)+8)/7;
+ } else {
+ /* Positive */
+ return (Set_Max(val)+8)/7;
+ }
+ } else {
+ /* Unsigned mode */
+ return (Set_Max(val)+7)/7;
+ }
+}
+
+unsigned long
+yasm_intnum_get_leb128(const yasm_intnum *intn, unsigned char *ptr, int sign)
+{
+ wordptr val;
+
+ /* Shortcut 0 */
+ if (intn->type == INTNUM_L && intn->val.l == 0) {
+ *ptr = 0;
+ return 1;
+ }
+
+ /* If not already a bitvect, convert value to be written to a bitvect */
+ val = intnum_tobv(op1static, intn);
+
+ return get_leb128(val, ptr, sign);
+}
+
+unsigned long
+yasm_intnum_size_leb128(const yasm_intnum *intn, int sign)
+{
+ wordptr val;
+
+ /* Shortcut 0 */
+ if (intn->type == INTNUM_L && intn->val.l == 0) {
+ return 1;
+ }
+
+ /* If not already a bitvect, convert value to a bitvect */
+ val = intnum_tobv(op1static, intn);
+
+ return size_leb128(val, sign);
+}
+
+unsigned long
+yasm_get_sleb128(long v, unsigned char *ptr)
+{
+ wordptr val = op1static;
+
+ /* Shortcut 0 */
+ if (v == 0) {
+ *ptr = 0;
+ return 1;
+ }
+
+ BitVector_Empty(val);
+ if (v >= 0)
+ BitVector_Chunk_Store(val, 32, 0, (unsigned long)v);
+ else {
+ BitVector_Chunk_Store(val, 32, 0, (unsigned long)(-v));
+ BitVector_Negate(val, val);
+ }
+ return get_leb128(val, ptr, 1);
+}
+
+unsigned long
+yasm_size_sleb128(long v)
+{
+ wordptr val = op1static;
+
+ if (v == 0)
+ return 1;
+
+ BitVector_Empty(val);
+ if (v >= 0)
+ BitVector_Chunk_Store(val, 32, 0, (unsigned long)v);
+ else {
+ BitVector_Chunk_Store(val, 32, 0, (unsigned long)(-v));
+ BitVector_Negate(val, val);
+ }
+ return size_leb128(val, 1);
+}
+
+unsigned long
+yasm_get_uleb128(unsigned long v, unsigned char *ptr)
+{
+ wordptr val = op1static;
+
+ /* Shortcut 0 */
+ if (v == 0) {
+ *ptr = 0;
+ return 1;
+ }
+
+ BitVector_Empty(val);
+ BitVector_Chunk_Store(val, 32, 0, v);
+ return get_leb128(val, ptr, 0);
+}
+
+unsigned long
+yasm_size_uleb128(unsigned long v)
+{
+ wordptr val = op1static;
+
+ if (v == 0)
+ return 1;
+
+ BitVector_Empty(val);
+ BitVector_Chunk_Store(val, 32, 0, v);
+ return size_leb128(val, 0);
+}
+
+char *
+yasm_intnum_get_str(const yasm_intnum *intn)
+{
+ unsigned char *s;
+
+ switch (intn->type) {
+ case INTNUM_L:
+ s = yasm_xmalloc(16);
+ sprintf((char *)s, "%ld", intn->val.l);
+ return (char *)s;
+ break;
+ case INTNUM_BV:
+ return (char *)BitVector_to_Dec(intn->val.bv);
+ break;
+ }
+ /*@notreached@*/
+ return NULL;
+}
+
+void
+yasm_intnum_print(const yasm_intnum *intn, FILE *f)
+{
+ unsigned char *s;
+
+ switch (intn->type) {
+ case INTNUM_L:
+ fprintf(f, "0x%lx", intn->val.l);
+ break;
+ case INTNUM_BV:
+ s = BitVector_to_Hex(intn->val.bv);
+ fprintf(f, "0x%s", (char *)s);
+ yasm_xfree(s);
+ break;
+ }
+}
diff --git a/libyasm/intnum.h b/libyasm/intnum.h
new file mode 100644
index 0000000..bec832c
--- /dev/null
+++ b/libyasm/intnum.h
@@ -0,0 +1,340 @@
+/**
+ * \file libyasm/intnum.h
+ * \brief YASM integer number interface.
+ *
+ * \license
+ * Copyright (C) 2001-2007 Peter Johnson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * \endlicense
+ */
+#ifndef YASM_INTNUM_H
+#define YASM_INTNUM_H
+
+#ifndef YASM_LIB_DECL
+#define YASM_LIB_DECL
+#endif
+
+/** Initialize intnum internal data structures. */
+YASM_LIB_DECL
+void yasm_intnum_initialize(void);
+
+/** Clean up internal intnum allocations. */
+YASM_LIB_DECL
+void yasm_intnum_cleanup(void);
+
+/** Create a new intnum from a decimal string.
+ * \param str decimal string
+ * \return Newly allocated intnum.
+ */
+YASM_LIB_DECL
+/*@only@*/ yasm_intnum *yasm_intnum_create_dec(char *str);
+
+/** Create a new intnum from a binary string.
+ * \param str binary string
+ * \return Newly allocated intnum.
+ */
+YASM_LIB_DECL
+/*@only@*/ yasm_intnum *yasm_intnum_create_bin(char *str);
+
+/** Create a new intnum from an octal string.
+ * \param str octal string
+ * \return Newly allocated intnum.
+ */
+YASM_LIB_DECL
+/*@only@*/ yasm_intnum *yasm_intnum_create_oct(char *str);
+
+/** Create a new intnum from a hexidecimal string.
+ * \param str hexidecimal string
+ * \return Newly allocated intnum.
+ */
+YASM_LIB_DECL
+/*@only@*/ yasm_intnum *yasm_intnum_create_hex(char *str);
+
+/** Convert character constant to integer value, using NASM rules. NASM syntax
+ * supports automatic conversion from strings such as 'abcd' to a 32-bit
+ * integer value (little endian order). This function performs those conversions.
+ * \param str character constant string
+ * \return Newly allocated intnum.
+ */
+YASM_LIB_DECL
+/*@only@*/ yasm_intnum *yasm_intnum_create_charconst_nasm(const char *str);
+
+/** Convert character constant to integer value, using TASM rules. TASM syntax
+ * supports automatic conversion from strings such as 'abcd' to a 32-bit
+ * integer value (big endian order). This function performs those conversions.
+ * \param str character constant string
+ * \return Newly allocated intnum.
+ */
+YASM_LIB_DECL
+/*@only@*/ yasm_intnum *yasm_intnum_create_charconst_tasm(const char *str);
+
+/** Create a new intnum from an unsigned integer value.
+ * \param i unsigned integer value
+ * \return Newly allocated intnum.
+ */
+YASM_LIB_DECL
+/*@only@*/ yasm_intnum *yasm_intnum_create_uint(unsigned long i);
+
+/** Create a new intnum from an signed integer value.
+ * \param i signed integer value
+ * \return Newly allocated intnum.
+ */
+YASM_LIB_DECL
+/*@only@*/ yasm_intnum *yasm_intnum_create_int(long i);
+
+/** Create a new intnum from LEB128-encoded form.
+ * \param ptr pointer to start of LEB128 encoded form
+ * \param sign signed (1) or unsigned (0) LEB128 format
+ * \param size number of bytes read from ptr (output)
+ * \return Newly allocated intnum. Number of bytes read returned into
+ * bytes_read parameter.
+ */
+YASM_LIB_DECL
+/*@only@*/ yasm_intnum *yasm_intnum_create_leb128
+ (const unsigned char *ptr, int sign, /*@out@*/ unsigned long *size);
+
+/** Create a new intnum from a little-endian or big-endian buffer.
+ * In little endian, the LSB is in ptr[0].
+ * \param ptr pointer to start of buffer
+ * \param sign signed (1) or unsigned (0) source
+ * \param srcsize source buffer size (in bytes)
+ * \param bigendian endianness (nonzero=big, zero=little)
+ */
+YASM_LIB_DECL
+/*@only@*/ yasm_intnum *yasm_intnum_create_sized
+ (unsigned char *ptr, int sign, size_t srcsize, int bigendian);
+
+/** Duplicate an intnum.
+ * \param intn intnum
+ * \return Newly allocated intnum with the same value as intn.
+ */
+YASM_LIB_DECL
+/*@only@*/ yasm_intnum *yasm_intnum_copy(const yasm_intnum *intn);
+
+/** Destroy (free allocated memory for) an intnum.
+ * \param intn intnum
+ */
+YASM_LIB_DECL
+void yasm_intnum_destroy(/*@only@*/ yasm_intnum *intn);
+
+/** Floating point calculation function: acc = acc op operand.
+ * \note Not all operations in yasm_expr_op may be supported; unsupported
+ * operations will result in an error.
+ * \param acc intnum accumulator
+ * \param op operation
+ * \param operand intnum operand
+ * \return Nonzero if error occurred.
+ */
+YASM_LIB_DECL
+int yasm_intnum_calc(yasm_intnum *acc, yasm_expr_op op, yasm_intnum *operand);
+
+/** Compare two intnums.
+ * \param intn1 first intnum
+ * \param intn2 second intnum
+ * \return -1 if intn1 < intn2, 0 if intn1 == intn2, 1 if intn1 > intn2.
+ */
+YASM_LIB_DECL
+int yasm_intnum_compare(const yasm_intnum *intn1, const yasm_intnum *intn2);
+
+/** Zero an intnum.
+ * \param intn intnum
+ */
+YASM_LIB_DECL
+void yasm_intnum_zero(yasm_intnum *intn);
+
+/** Set an intnum to the value of another intnum.
+ * \param intn intnum
+ * \param val intnum to get value from
+ */
+YASM_LIB_DECL
+void yasm_intnum_set(yasm_intnum *intn, const yasm_intnum *val);
+
+/** Set an intnum to an unsigned integer.
+ * \param intn intnum
+ * \param val integer value
+ */
+YASM_LIB_DECL
+void yasm_intnum_set_uint(yasm_intnum *intn, unsigned long val);
+
+/** Set an intnum to an signed integer.
+ * \param intn intnum
+ * \param val integer value
+ */
+YASM_LIB_DECL
+void yasm_intnum_set_int(yasm_intnum *intn, long val);
+
+/** Simple value check for 0.
+ * \param acc intnum
+ * \return Nonzero if acc==0.
+ */
+YASM_LIB_DECL
+int yasm_intnum_is_zero(const yasm_intnum *acc);
+
+/** Simple value check for 1.
+ * \param acc intnum
+ * \return Nonzero if acc==1.
+ */
+YASM_LIB_DECL
+int yasm_intnum_is_pos1(const yasm_intnum *acc);
+
+/** Simple value check for -1.
+ * \param acc intnum
+ * \return Nonzero if acc==-1.
+ */
+YASM_LIB_DECL
+int yasm_intnum_is_neg1(const yasm_intnum *acc);
+
+/** Simple sign check.
+ * \param acc intnum
+ * \return -1 if negative, 0 if zero, +1 if positive
+ */
+YASM_LIB_DECL
+int yasm_intnum_sign(const yasm_intnum *acc);
+
+/** Convert an intnum to an unsigned 32-bit value. The value is in "standard"
+ * C format (eg, of unknown endian).
+ * \note Parameter intnum is truncated to fit into 32 bits. Use
+ * intnum_check_size() to check for overflow.
+ * \param intn intnum
+ * \return Unsigned 32-bit value of intn.
+ */
+YASM_LIB_DECL
+unsigned long yasm_intnum_get_uint(const yasm_intnum *intn);
+
+/** Convert an intnum to a signed 32-bit value. The value is in "standard" C
+ * format (eg, of unknown endian).
+ * \note Parameter intnum is truncated to fit into 32 bits. Use
+ * intnum_check_size() to check for overflow.
+ * \param intn intnum
+ * \return Signed 32-bit value of intn.
+ */
+YASM_LIB_DECL
+long yasm_intnum_get_int(const yasm_intnum *intn);
+
+/** Output #yasm_intnum to buffer in little-endian or big-endian. Puts the
+ * value into the least significant bits of the destination, or may be shifted
+ * into more significant bits by the shift parameter. The destination bits are
+ * cleared before being set. [0] should be the first byte output to the file.
+ * \param intn intnum
+ * \param ptr pointer to storage for size bytes of output
+ * \param destsize destination size (in bytes)
+ * \param valsize size (in bits)
+ * \param shift left shift (in bits); may be negative to specify right
+ * shift (standard warnings include truncation to boundary)
+ * \param bigendian endianness (nonzero=big, zero=little)
+ * \param warn enables standard warnings (value doesn't fit into valsize
+ * bits): <0=signed warnings, >0=unsigned warnings, 0=no warn
+ */
+YASM_LIB_DECL
+void yasm_intnum_get_sized(const yasm_intnum *intn, unsigned char *ptr,
+ size_t destsize, size_t valsize, int shift,
+ int bigendian, int warn);
+
+/** Check to see if intnum will fit without overflow into size bits.
+ * \param intn intnum
+ * \param size number of bits of output space
+ * \param rshift right shift
+ * \param rangetype signed/unsigned range selection:
+ * 0 => (0, unsigned max);
+ * 1 => (signed min, signed max);
+ * 2 => (signed min, unsigned max)
+ * \return Nonzero if intnum will fit.
+ */
+YASM_LIB_DECL
+int yasm_intnum_check_size(const yasm_intnum *intn, size_t size,
+ size_t rshift, int rangetype);
+
+/** Check to see if intnum will fit into a particular numeric range.
+ * \param intn intnum
+ * \param low low end of range (inclusive)
+ * \param high high end of range (inclusive)
+ * \return Nonzero if intnum is within range.
+ */
+YASM_LIB_DECL
+int yasm_intnum_in_range(const yasm_intnum *intn, long low, long high);
+
+/** Output #yasm_intnum to buffer in LEB128-encoded form.
+ * \param intn intnum
+ * \param ptr pointer to storage for output bytes
+ * \param sign signedness of LEB128 encoding (0=unsigned, 1=signed)
+ * \return Number of bytes generated.
+ */
+YASM_LIB_DECL
+unsigned long yasm_intnum_get_leb128(const yasm_intnum *intn,
+ unsigned char *ptr, int sign);
+
+/** Calculate number of bytes LEB128-encoded form of #yasm_intnum will take.
+ * \param intn intnum
+ * \param sign signedness of LEB128 encoding (0=unsigned, 1=signed)
+ * \return Number of bytes.
+ */
+YASM_LIB_DECL
+unsigned long yasm_intnum_size_leb128(const yasm_intnum *intn, int sign);
+
+/** Output integer to buffer in signed LEB128-encoded form.
+ * \param v integer
+ * \param ptr pointer to storage for output bytes
+ * \return Number of bytes generated.
+ */
+YASM_LIB_DECL
+unsigned long yasm_get_sleb128(long v, unsigned char *ptr);
+
+/** Calculate number of bytes signed LEB128-encoded form of integer will take.
+ * \param v integer
+ * \return Number of bytes.
+ */
+YASM_LIB_DECL
+unsigned long yasm_size_sleb128(long v);
+
+/** Output integer to buffer in unsigned LEB128-encoded form.
+ * \param v integer
+ * \param ptr pointer to storage for output bytes
+ * \return Number of bytes generated.
+ */
+YASM_LIB_DECL
+unsigned long yasm_get_uleb128(unsigned long v, unsigned char *ptr);
+
+/** Calculate number of bytes unsigned LEB128-encoded form of integer will take.
+ * \param v integer
+ * \return Number of bytes.
+ */
+YASM_LIB_DECL
+unsigned long yasm_size_uleb128(unsigned long v);
+
+/** Get an intnum as a signed decimal string. The returned string will
+ * contain a leading '-' if the intnum is negative.
+ * \param intn intnum
+ * \return Newly allocated string containing the decimal representation of
+ * the intnum.
+ */
+YASM_LIB_DECL
+/*@only@*/ char *yasm_intnum_get_str(const yasm_intnum *intn);
+
+/** Print an intnum. For debugging purposes.
+ * \param f file
+ * \param intn intnum
+ */
+YASM_LIB_DECL
+void yasm_intnum_print(const yasm_intnum *intn, FILE *f);
+
+#endif
diff --git a/libyasm/inttree.c b/libyasm/inttree.c
new file mode 100644
index 0000000..2ae10e9
--- /dev/null
+++ b/libyasm/inttree.c
@@ -0,0 +1,891 @@
+#include "util.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <limits.h>
+#include <math.h>
+#include "coretype.h"
+#include "inttree.h"
+
+#define VERIFY(condition) \
+if (!(condition)) { \
+fprintf(stderr, "Assumption \"%s\"\nFailed in file %s: at line:%i\n", \
+#condition,__FILE__,__LINE__); \
+abort();}
+
+/*#define DEBUG_ASSERT 1*/
+
+#ifdef DEBUG_ASSERT
+static void Assert(int assertion, const char *error)
+{
+ if (!assertion) {
+ fprintf(stderr, "Assertion Failed: %s\n", error);
+ abort();
+ }
+}
+#endif
+
+/* If the symbol CHECK_INTERVAL_TREE_ASSUMPTIONS is defined then the
+ * code does a lot of extra checking to make sure certain assumptions
+ * are satisfied. This only needs to be done if you suspect bugs are
+ * present or if you make significant changes and want to make sure
+ * your changes didn't mess anything up.
+ */
+/*#define CHECK_INTERVAL_TREE_ASSUMPTIONS 1*/
+
+static IntervalTreeNode *ITN_create(long low, long high, void *data);
+
+static void LeftRotate(IntervalTree *, IntervalTreeNode *);
+static void RightRotate(IntervalTree *, IntervalTreeNode *);
+static void TreeInsertHelp(IntervalTree *, IntervalTreeNode *);
+static void TreePrintHelper(const IntervalTree *, IntervalTreeNode *);
+static void FixUpMaxHigh(IntervalTree *, IntervalTreeNode *);
+static void DeleteFixUp(IntervalTree *, IntervalTreeNode *);
+#ifdef CHECK_INTERVAL_TREE_ASSUMPTIONS
+static void CheckMaxHighFields(const IntervalTree *, IntervalTreeNode *);
+static int CheckMaxHighFieldsHelper(const IntervalTree *, IntervalTreeNode *y,
+ const int currentHigh, int match);
+static void IT_CheckAssumptions(const IntervalTree *);
+#endif
+
+/* define a function to find the maximum of two objects. */
+#define ITMax(a, b) ( (a > b) ? a : b )
+
+IntervalTreeNode *
+ITN_create(long low, long high, void *data)
+{
+ IntervalTreeNode *itn = yasm_xmalloc(sizeof(IntervalTreeNode));
+ itn->data = data;
+ if (low < high) {
+ itn->low = low;
+ itn->high = high;
+ } else {
+ itn->low = high;
+ itn->high = low;
+ }
+ itn->maxHigh = high;
+ return itn;
+}
+
+IntervalTree *
+IT_create(void)
+{
+ IntervalTree *it = yasm_xmalloc(sizeof(IntervalTree));
+
+ it->nil = ITN_create(LONG_MIN, LONG_MIN, NULL);
+ it->nil->left = it->nil;
+ it->nil->right = it->nil;
+ it->nil->parent = it->nil;
+ it->nil->red = 0;
+
+ it->root = ITN_create(LONG_MAX, LONG_MAX, NULL);
+ it->root->left = it->nil;
+ it->root->right = it->nil;
+ it->root->parent = it->nil;
+ it->root->red = 0;
+
+ /* the following are used for the Enumerate function */
+ it->recursionNodeStackSize = 128;
+ it->recursionNodeStack = (it_recursion_node *)
+ yasm_xmalloc(it->recursionNodeStackSize*sizeof(it_recursion_node));
+ it->recursionNodeStackTop = 1;
+ it->recursionNodeStack[0].start_node = NULL;
+
+ return it;
+}
+
+/***********************************************************************/
+/* FUNCTION: LeftRotate */
+/**/
+/* INPUTS: the node to rotate on */
+/**/
+/* OUTPUT: None */
+/**/
+/* Modifies Input: this, x */
+/**/
+/* EFFECTS: Rotates as described in _Introduction_To_Algorithms by */
+/* Cormen, Leiserson, Rivest (Chapter 14). Basically this */
+/* makes the parent of x be to the left of x, x the parent of */
+/* its parent before the rotation and fixes other pointers */
+/* accordingly. Also updates the maxHigh fields of x and y */
+/* after rotation. */
+/***********************************************************************/
+
+static void
+LeftRotate(IntervalTree *it, IntervalTreeNode *x)
+{
+ IntervalTreeNode *y;
+
+ /* I originally wrote this function to use the sentinel for
+ * nil to avoid checking for nil. However this introduces a
+ * very subtle bug because sometimes this function modifies
+ * the parent pointer of nil. This can be a problem if a
+ * function which calls LeftRotate also uses the nil sentinel
+ * and expects the nil sentinel's parent pointer to be unchanged
+ * after calling this function. For example, when DeleteFixUP
+ * calls LeftRotate it expects the parent pointer of nil to be
+ * unchanged.
+ */
+
+ y=x->right;
+ x->right=y->left;
+
+ if (y->left != it->nil)
+ y->left->parent=x; /* used to use sentinel here */
+ /* and do an unconditional assignment instead of testing for nil */
+
+ y->parent=x->parent;
+
+ /* Instead of checking if x->parent is the root as in the book, we
+ * count on the root sentinel to implicitly take care of this case
+ */
+ if (x == x->parent->left)
+ x->parent->left=y;
+ else
+ x->parent->right=y;
+ y->left=x;
+ x->parent=y;
+
+ x->maxHigh=ITMax(x->left->maxHigh,ITMax(x->right->maxHigh,x->high));
+ y->maxHigh=ITMax(x->maxHigh,ITMax(y->right->maxHigh,y->high));
+#ifdef CHECK_INTERVAL_TREE_ASSUMPTIONS
+ IT_CheckAssumptions(it);
+#elif defined(DEBUG_ASSERT)
+ Assert(!it->nil->red,"nil not red in ITLeftRotate");
+ Assert((it->nil->maxHigh=LONG_MIN),
+ "nil->maxHigh != LONG_MIN in ITLeftRotate");
+#endif
+}
+
+
+/***********************************************************************/
+/* FUNCTION: RightRotate */
+/**/
+/* INPUTS: node to rotate on */
+/**/
+/* OUTPUT: None */
+/**/
+/* Modifies Input?: this, y */
+/**/
+/* EFFECTS: Rotates as described in _Introduction_To_Algorithms by */
+/* Cormen, Leiserson, Rivest (Chapter 14). Basically this */
+/* makes the parent of x be to the left of x, x the parent of */
+/* its parent before the rotation and fixes other pointers */
+/* accordingly. Also updates the maxHigh fields of x and y */
+/* after rotation. */
+/***********************************************************************/
+
+
+static void
+RightRotate(IntervalTree *it, IntervalTreeNode *y)
+{
+ IntervalTreeNode *x;
+
+ /* I originally wrote this function to use the sentinel for
+ * nil to avoid checking for nil. However this introduces a
+ * very subtle bug because sometimes this function modifies
+ * the parent pointer of nil. This can be a problem if a
+ * function which calls LeftRotate also uses the nil sentinel
+ * and expects the nil sentinel's parent pointer to be unchanged
+ * after calling this function. For example, when DeleteFixUP
+ * calls LeftRotate it expects the parent pointer of nil to be
+ * unchanged.
+ */
+
+ x=y->left;
+ y->left=x->right;
+
+ if (it->nil != x->right)
+ x->right->parent=y; /*used to use sentinel here */
+ /* and do an unconditional assignment instead of testing for nil */
+
+ /* Instead of checking if x->parent is the root as in the book, we
+ * count on the root sentinel to implicitly take care of this case
+ */
+ x->parent=y->parent;
+ if (y == y->parent->left)
+ y->parent->left=x;
+ else
+ y->parent->right=x;
+ x->right=y;
+ y->parent=x;
+
+ y->maxHigh=ITMax(y->left->maxHigh,ITMax(y->right->maxHigh,y->high));
+ x->maxHigh=ITMax(x->left->maxHigh,ITMax(y->maxHigh,x->high));
+#ifdef CHECK_INTERVAL_TREE_ASSUMPTIONS
+ IT_CheckAssumptions(it);
+#elif defined(DEBUG_ASSERT)
+ Assert(!it->nil->red,"nil not red in ITRightRotate");
+ Assert((it->nil->maxHigh=LONG_MIN),
+ "nil->maxHigh != LONG_MIN in ITRightRotate");
+#endif
+}
+
+/***********************************************************************/
+/* FUNCTION: TreeInsertHelp */
+/**/
+/* INPUTS: z is the node to insert */
+/**/
+/* OUTPUT: none */
+/**/
+/* Modifies Input: this, z */
+/**/
+/* EFFECTS: Inserts z into the tree as if it were a regular binary tree */
+/* using the algorithm described in _Introduction_To_Algorithms_ */
+/* by Cormen et al. This funciton is only intended to be called */
+/* by the InsertTree function and not by the user */
+/***********************************************************************/
+
+static void
+TreeInsertHelp(IntervalTree *it, IntervalTreeNode *z)
+{
+ /* This function should only be called by InsertITTree (see above) */
+ IntervalTreeNode* x;
+ IntervalTreeNode* y;
+
+ z->left=z->right=it->nil;
+ y=it->root;
+ x=it->root->left;
+ while( x != it->nil) {
+ y=x;
+ if (x->low > z->low)
+ x=x->left;
+ else /* x->low <= z->low */
+ x=x->right;
+ }
+ z->parent=y;
+ if ((y == it->root) || (y->low > z->low))
+ y->left=z;
+ else
+ y->right=z;
+
+#if defined(DEBUG_ASSERT)
+ Assert(!it->nil->red,"nil not red in ITTreeInsertHelp");
+ Assert((it->nil->maxHigh=INT_MIN),
+ "nil->maxHigh != INT_MIN in ITTreeInsertHelp");
+#endif
+}
+
+
+/***********************************************************************/
+/* FUNCTION: FixUpMaxHigh */
+/**/
+/* INPUTS: x is the node to start from*/
+/**/
+/* OUTPUT: none */
+/**/
+/* Modifies Input: this */
+/**/
+/* EFFECTS: Travels up to the root fixing the maxHigh fields after */
+/* an insertion or deletion */
+/***********************************************************************/
+
+static void
+FixUpMaxHigh(IntervalTree *it, IntervalTreeNode *x)
+{
+ while(x != it->root) {
+ x->maxHigh=ITMax(x->high,ITMax(x->left->maxHigh,x->right->maxHigh));
+ x=x->parent;
+ }
+#ifdef CHECK_INTERVAL_TREE_ASSUMPTIONS
+ IT_CheckAssumptions(it);
+#endif
+}
+
+/* Before calling InsertNode the node x should have its key set */
+
+/***********************************************************************/
+/* FUNCTION: InsertNode */
+/**/
+/* INPUTS: newInterval is the interval to insert*/
+/**/
+/* OUTPUT: This function returns a pointer to the newly inserted node */
+/* which is guarunteed to be valid until this node is deleted. */
+/* What this means is if another data structure stores this */
+/* pointer then the tree does not need to be searched when this */
+/* is to be deleted. */
+/**/
+/* Modifies Input: tree */
+/**/
+/* EFFECTS: Creates a node node which contains the appropriate key and */
+/* info pointers and inserts it into the tree. */
+/***********************************************************************/
+
+IntervalTreeNode *
+IT_insert(IntervalTree *it, long low, long high, void *data)
+{
+ IntervalTreeNode *x, *y, *newNode;
+
+ x = ITN_create(low, high, data);
+ TreeInsertHelp(it, x);
+ FixUpMaxHigh(it, x->parent);
+ newNode = x;
+ x->red=1;
+ while(x->parent->red) { /* use sentinel instead of checking for root */
+ if (x->parent == x->parent->parent->left) {
+ y=x->parent->parent->right;
+ if (y->red) {
+ x->parent->red=0;
+ y->red=0;
+ x->parent->parent->red=1;
+ x=x->parent->parent;
+ } else {
+ if (x == x->parent->right) {
+ x=x->parent;
+ LeftRotate(it, x);
+ }
+ x->parent->red=0;
+ x->parent->parent->red=1;
+ RightRotate(it, x->parent->parent);
+ }
+ } else { /* case for x->parent == x->parent->parent->right */
+ /* this part is just like the section above with */
+ /* left and right interchanged */
+ y=x->parent->parent->left;
+ if (y->red) {
+ x->parent->red=0;
+ y->red=0;
+ x->parent->parent->red=1;
+ x=x->parent->parent;
+ } else {
+ if (x == x->parent->left) {
+ x=x->parent;
+ RightRotate(it, x);
+ }
+ x->parent->red=0;
+ x->parent->parent->red=1;
+ LeftRotate(it, x->parent->parent);
+ }
+ }
+ }
+ it->root->left->red=0;
+
+#ifdef CHECK_INTERVAL_TREE_ASSUMPTIONS
+ IT_CheckAssumptions(it);
+#elif defined(DEBUG_ASSERT)
+ Assert(!it->nil->red,"nil not red in ITTreeInsert");
+ Assert(!it->root->red,"root not red in ITTreeInsert");
+ Assert((it->nil->maxHigh=LONG_MIN),
+ "nil->maxHigh != LONG_MIN in ITTreeInsert");
+#endif
+ return newNode;
+}
+
+/***********************************************************************/
+/* FUNCTION: GetSuccessorOf */
+/**/
+/* INPUTS: x is the node we want the succesor of */
+/**/
+/* OUTPUT: This function returns the successor of x or NULL if no */
+/* successor exists. */
+/**/
+/* Modifies Input: none */
+/**/
+/* Note: uses the algorithm in _Introduction_To_Algorithms_ */
+/***********************************************************************/
+
+IntervalTreeNode *
+IT_get_successor(const IntervalTree *it, IntervalTreeNode *x)
+{
+ IntervalTreeNode *y;
+
+ if (it->nil != (y = x->right)) { /* assignment to y is intentional */
+ while(y->left != it->nil) /* returns the minium of the right subtree of x */
+ y=y->left;
+ return y;
+ } else {
+ y=x->parent;
+ while(x == y->right) { /* sentinel used instead of checking for nil */
+ x=y;
+ y=y->parent;
+ }
+ if (y == it->root)
+ return(it->nil);
+ return y;
+ }
+}
+
+/***********************************************************************/
+/* FUNCTION: GetPredecessorOf */
+/**/
+/* INPUTS: x is the node to get predecessor of */
+/**/
+/* OUTPUT: This function returns the predecessor of x or NULL if no */
+/* predecessor exists. */
+/**/
+/* Modifies Input: none */
+/**/
+/* Note: uses the algorithm in _Introduction_To_Algorithms_ */
+/***********************************************************************/
+
+IntervalTreeNode *
+IT_get_predecessor(const IntervalTree *it, IntervalTreeNode *x)
+{
+ IntervalTreeNode *y;
+
+ if (it->nil != (y = x->left)) { /* assignment to y is intentional */
+ while(y->right != it->nil) /* returns the maximum of the left subtree of x */
+ y=y->right;
+ return y;
+ } else {
+ y=x->parent;
+ while(x == y->left) {
+ if (y == it->root)
+ return(it->nil);
+ x=y;
+ y=y->parent;
+ }
+ return y;
+ }
+}
+
+/***********************************************************************/
+/* FUNCTION: Print */
+/**/
+/* INPUTS: none */
+/**/
+/* OUTPUT: none */
+/**/
+/* EFFECTS: This function recursively prints the nodes of the tree */
+/* inorder. */
+/**/
+/* Modifies Input: none */
+/**/
+/* Note: This function should only be called from ITTreePrint */
+/***********************************************************************/
+
+static void
+ITN_print(const IntervalTreeNode *itn, IntervalTreeNode *nil,
+ IntervalTreeNode *root)
+{
+ printf(", l=%li, h=%li, mH=%li", itn->low, itn->high, itn->maxHigh);
+ printf(" l->low=");
+ if (itn->left == nil)
+ printf("NULL");
+ else
+ printf("%li", itn->left->low);
+ printf(" r->low=");
+ if (itn->right == nil)
+ printf("NULL");
+ else
+ printf("%li", itn->right->low);
+ printf(" p->low=");
+ if (itn->parent == root)
+ printf("NULL");
+ else
+ printf("%li", itn->parent->low);
+ printf(" red=%i\n", itn->red);
+}
+
+static void
+TreePrintHelper(const IntervalTree *it, IntervalTreeNode *x)
+{
+ if (x != it->nil) {
+ TreePrintHelper(it, x->left);
+ ITN_print(x, it->nil, it->root);
+ TreePrintHelper(it, x->right);
+ }
+}
+
+void
+IT_destroy(IntervalTree *it)
+{
+ IntervalTreeNode *x = it->root->left;
+ SLIST_HEAD(node_head, nodeent)
+ stuffToFree = SLIST_HEAD_INITIALIZER(stuffToFree);
+ struct nodeent {
+ SLIST_ENTRY(nodeent) link;
+ struct IntervalTreeNode *node;
+ } *np;
+
+ if (x != it->nil) {
+ if (x->left != it->nil) {
+ np = yasm_xmalloc(sizeof(struct nodeent));
+ np->node = x->left;
+ SLIST_INSERT_HEAD(&stuffToFree, np, link);
+ }
+ if (x->right != it->nil) {
+ np = yasm_xmalloc(sizeof(struct nodeent));
+ np->node = x->right;
+ SLIST_INSERT_HEAD(&stuffToFree, np, link);
+ }
+ yasm_xfree(x);
+ while (!SLIST_EMPTY(&stuffToFree)) {
+ np = SLIST_FIRST(&stuffToFree);
+ x = np->node;
+ SLIST_REMOVE_HEAD(&stuffToFree, link);
+ yasm_xfree(np);
+
+ if (x->left != it->nil) {
+ np = yasm_xmalloc(sizeof(struct nodeent));
+ np->node = x->left;
+ SLIST_INSERT_HEAD(&stuffToFree, np, link);
+ }
+ if (x->right != it->nil) {
+ np = yasm_xmalloc(sizeof(struct nodeent));
+ np->node = x->right;
+ SLIST_INSERT_HEAD(&stuffToFree, np, link);
+ }
+ yasm_xfree(x);
+ }
+ }
+
+ yasm_xfree(it->nil);
+ yasm_xfree(it->root);
+ yasm_xfree(it->recursionNodeStack);
+ yasm_xfree(it);
+}
+
+
+/***********************************************************************/
+/* FUNCTION: Print */
+/**/
+/* INPUTS: none */
+/**/
+/* OUTPUT: none */
+/**/
+/* EFFECT: This function recursively prints the nodes of the tree */
+/* inorder. */
+/**/
+/* Modifies Input: none */
+/**/
+/***********************************************************************/
+
+void
+IT_print(const IntervalTree *it)
+{
+ TreePrintHelper(it, it->root->left);
+}
+
+/***********************************************************************/
+/* FUNCTION: DeleteFixUp */
+/**/
+/* INPUTS: x is the child of the spliced */
+/* out node in DeleteNode. */
+/**/
+/* OUTPUT: none */
+/**/
+/* EFFECT: Performs rotations and changes colors to restore red-black */
+/* properties after a node is deleted */
+/**/
+/* Modifies Input: this, x */
+/**/
+/* The algorithm from this function is from _Introduction_To_Algorithms_ */
+/***********************************************************************/
+
+static void
+DeleteFixUp(IntervalTree *it, IntervalTreeNode *x)
+{
+ IntervalTreeNode *w;
+ IntervalTreeNode *rootLeft = it->root->left;
+
+ while ((!x->red) && (rootLeft != x)) {
+ if (x == x->parent->left) {
+ w=x->parent->right;
+ if (w->red) {
+ w->red=0;
+ x->parent->red=1;
+ LeftRotate(it, x->parent);
+ w=x->parent->right;
+ }
+ if ( (!w->right->red) && (!w->left->red) ) {
+ w->red=1;
+ x=x->parent;
+ } else {
+ if (!w->right->red) {
+ w->left->red=0;
+ w->red=1;
+ RightRotate(it, w);
+ w=x->parent->right;
+ }
+ w->red=x->parent->red;
+ x->parent->red=0;
+ w->right->red=0;
+ LeftRotate(it, x->parent);
+ x=rootLeft; /* this is to exit while loop */
+ }
+ } else { /* the code below is has left and right switched from above */
+ w=x->parent->left;
+ if (w->red) {
+ w->red=0;
+ x->parent->red=1;
+ RightRotate(it, x->parent);
+ w=x->parent->left;
+ }
+ if ((!w->right->red) && (!w->left->red)) {
+ w->red=1;
+ x=x->parent;
+ } else {
+ if (!w->left->red) {
+ w->right->red=0;
+ w->red=1;
+ LeftRotate(it, w);
+ w=x->parent->left;
+ }
+ w->red=x->parent->red;
+ x->parent->red=0;
+ w->left->red=0;
+ RightRotate(it, x->parent);
+ x=rootLeft; /* this is to exit while loop */
+ }
+ }
+ }
+ x->red=0;
+
+#ifdef CHECK_INTERVAL_TREE_ASSUMPTIONS
+ IT_CheckAssumptions(it);
+#elif defined(DEBUG_ASSERT)
+ Assert(!it->nil->red,"nil not black in ITDeleteFixUp");
+ Assert((it->nil->maxHigh=LONG_MIN),
+ "nil->maxHigh != LONG_MIN in ITDeleteFixUp");
+#endif
+}
+
+
+/***********************************************************************/
+/* FUNCTION: DeleteNode */
+/**/
+/* INPUTS: tree is the tree to delete node z from */
+/**/
+/* OUTPUT: returns the Interval stored at deleted node */
+/**/
+/* EFFECT: Deletes z from tree and but don't call destructor */
+/* Then calls FixUpMaxHigh to fix maxHigh fields then calls */
+/* ITDeleteFixUp to restore red-black properties */
+/**/
+/* Modifies Input: z */
+/**/
+/* The algorithm from this function is from _Introduction_To_Algorithms_ */
+/***********************************************************************/
+
+void *
+IT_delete_node(IntervalTree *it, IntervalTreeNode *z, long *low, long *high)
+{
+ IntervalTreeNode *x, *y;
+ void *returnValue = z->data;
+ if (low)
+ *low = z->low;
+ if (high)
+ *high = z->high;
+
+ y= ((z->left == it->nil) || (z->right == it->nil)) ?
+ z : IT_get_successor(it, z);
+ x= (y->left == it->nil) ? y->right : y->left;
+ if (it->root == (x->parent = y->parent))
+ /* assignment of y->p to x->p is intentional */
+ it->root->left=x;
+ else {
+ if (y == y->parent->left)
+ y->parent->left=x;
+ else
+ y->parent->right=x;
+ }
+ if (y != z) { /* y should not be nil in this case */
+
+#ifdef DEBUG_ASSERT
+ Assert( (y!=it->nil),"y is nil in DeleteNode \n");
+#endif
+ /* y is the node to splice out and x is its child */
+
+ y->maxHigh = INT_MIN;
+ y->left=z->left;
+ y->right=z->right;
+ y->parent=z->parent;
+ z->left->parent=z->right->parent=y;
+ if (z == z->parent->left)
+ z->parent->left=y;
+ else
+ z->parent->right=y;
+ FixUpMaxHigh(it, x->parent);
+ if (!(y->red)) {
+ y->red = z->red;
+ DeleteFixUp(it, x);
+ } else
+ y->red = z->red;
+ yasm_xfree(z);
+#ifdef CHECK_INTERVAL_TREE_ASSUMPTIONS
+ IT_CheckAssumptions(it);
+#elif defined(DEBUG_ASSERT)
+ Assert(!it->nil->red,"nil not black in ITDelete");
+ Assert((it->nil->maxHigh=LONG_MIN),"nil->maxHigh != LONG_MIN in ITDelete");
+#endif
+ } else {
+ FixUpMaxHigh(it, x->parent);
+ if (!(y->red))
+ DeleteFixUp(it, x);
+ yasm_xfree(y);
+#ifdef CHECK_INTERVAL_TREE_ASSUMPTIONS
+ IT_CheckAssumptions(it);
+#elif defined(DEBUG_ASSERT)
+ Assert(!it->nil->red,"nil not black in ITDelete");
+ Assert((it->nil->maxHigh=LONG_MIN),"nil->maxHigh != LONG_MIN in ITDelete");
+#endif
+ }
+ return returnValue;
+}
+
+
+/***********************************************************************/
+/* FUNCTION: Overlap */
+/**/
+/* INPUTS: [a1,a2] and [b1,b2] are the low and high endpoints of two */
+/* closed intervals. */
+/**/
+/* OUTPUT: stack containing pointers to the nodes between [low,high] */
+/**/
+/* Modifies Input: none */
+/**/
+/* EFFECT: returns 1 if the intervals overlap, and 0 otherwise */
+/***********************************************************************/
+
+static int
+Overlap(int a1, int a2, int b1, int b2)
+{
+ if (a1 <= b1)
+ return (b1 <= a2);
+ else
+ return (a1 <= b2);
+}
+
+
+/***********************************************************************/
+/* FUNCTION: Enumerate */
+/**/
+/* INPUTS: tree is the tree to look for intervals overlapping the */
+/* closed interval [low,high] */
+/**/
+/* OUTPUT: stack containing pointers to the nodes overlapping */
+/* [low,high] */
+/**/
+/* Modifies Input: none */
+/**/
+/* EFFECT: Returns a stack containing pointers to nodes containing */
+/* intervals which overlap [low,high] in O(max(N,k*log(N))) */
+/* where N is the number of intervals in the tree and k is */
+/* the number of overlapping intervals */
+/**/
+/* Note: This basic idea for this function comes from the */
+/* _Introduction_To_Algorithms_ book by Cormen et al, but */
+/* modifications were made to return all overlapping intervals */
+/* instead of just the first overlapping interval as in the */
+/* book. The natural way to do this would require recursive */
+/* calls of a basic search function. I translated the */
+/* recursive version into an interative version with a stack */
+/* as described below. */
+/***********************************************************************/
+
+
+
+/* The basic idea for the function below is to take the IntervalSearch
+ * function from the book and modify to find all overlapping intervals
+ * instead of just one. This means that any time we take the left
+ * branch down the tree we must also check the right branch if and only if
+ * we find an overlapping interval in that left branch. Note this is a
+ * recursive condition because if we go left at the root then go left
+ * again at the first left child and find an overlap in the left subtree
+ * of the left child of root we must recursively check the right subtree
+ * of the left child of root as well as the right child of root.
+ */
+void
+IT_enumerate(IntervalTree *it, long low, long high, void *cbd,
+ void (*callback) (IntervalTreeNode *node, void *cbd))
+{
+ IntervalTreeNode *x=it->root->left;
+ int stuffToDo = (x != it->nil);
+
+ /* Possible speed up: add min field to prune right searches */
+
+#ifdef DEBUG_ASSERT
+ Assert((it->recursionNodeStackTop == 1),
+ "recursionStack not empty when entering IntervalTree::Enumerate");
+#endif
+ it->currentParent = 0;
+
+ while (stuffToDo) {
+ if (Overlap(low,high,x->low,x->high) ) {
+ callback(x, cbd);
+ it->recursionNodeStack[it->currentParent].tryRightBranch=1;
+ }
+ if(x->left->maxHigh >= low) { /* implies x != nil */
+ if (it->recursionNodeStackTop == it->recursionNodeStackSize) {
+ it->recursionNodeStackSize *= 2;
+ it->recursionNodeStack = (it_recursion_node *)
+ yasm_xrealloc(it->recursionNodeStack,
+ it->recursionNodeStackSize * sizeof(it_recursion_node));
+ }
+ it->recursionNodeStack[it->recursionNodeStackTop].start_node = x;
+ it->recursionNodeStack[it->recursionNodeStackTop].tryRightBranch = 0;
+ it->recursionNodeStack[it->recursionNodeStackTop].parentIndex = it->currentParent;
+ it->currentParent = it->recursionNodeStackTop++;
+ x = x->left;
+ } else {
+ x = x->right;
+ }
+ stuffToDo = (x != it->nil);
+ while (!stuffToDo && (it->recursionNodeStackTop > 1)) {
+ if (it->recursionNodeStack[--it->recursionNodeStackTop].tryRightBranch) {
+ x=it->recursionNodeStack[it->recursionNodeStackTop].start_node->right;
+ it->currentParent=it->recursionNodeStack[it->recursionNodeStackTop].parentIndex;
+ it->recursionNodeStack[it->currentParent].tryRightBranch=1;
+ stuffToDo = (x != it->nil);
+ }
+ }
+ }
+#ifdef DEBUG_ASSERT
+ Assert((it->recursionNodeStackTop == 1),
+ "recursionStack not empty when exiting IntervalTree::Enumerate");
+#endif
+}
+
+#ifdef CHECK_INTERVAL_TREE_ASSUMPTIONS
+
+static int
+CheckMaxHighFieldsHelper(const IntervalTree *it, IntervalTreeNode *y,
+ int currentHigh, int match)
+{
+ if (y != it->nil) {
+ match = CheckMaxHighFieldsHelper(it, y->left, currentHigh, match) ?
+ 1 : match;
+ VERIFY(y->high <= currentHigh);
+ if (y->high == currentHigh)
+ match = 1;
+ match = CheckMaxHighFieldsHelper(it, y->right, currentHigh, match) ?
+ 1 : match;
+ }
+ return match;
+}
+
+
+
+/* Make sure the maxHigh fields for everything makes sense. *
+ * If something is wrong, print a warning and exit */
+static void
+CheckMaxHighFields(const IntervalTree *it, IntervalTreeNode *x)
+{
+ if (x != it->nil) {
+ CheckMaxHighFields(it, x->left);
+ if(!(CheckMaxHighFieldsHelper(it, x, x->maxHigh, 0) > 0)) {
+ fprintf(stderr, "error found in CheckMaxHighFields.\n");
+ abort();
+ }
+ CheckMaxHighFields(it, x->right);
+ }
+}
+
+static void
+IT_CheckAssumptions(const IntervalTree *it)
+{
+ VERIFY(it->nil->low == INT_MIN);
+ VERIFY(it->nil->high == INT_MIN);
+ VERIFY(it->nil->maxHigh == INT_MIN);
+ VERIFY(it->root->low == INT_MAX);
+ VERIFY(it->root->high == INT_MAX);
+ VERIFY(it->root->maxHigh == INT_MAX);
+ VERIFY(it->nil->data == NULL);
+ VERIFY(it->root->data == NULL);
+ VERIFY(it->nil->red == 0);
+ VERIFY(it->root->red == 0);
+ CheckMaxHighFields(it, it->root->left);
+}
+#endif
+
diff --git a/libyasm/inttree.h b/libyasm/inttree.h
new file mode 100644
index 0000000..f7a7651
--- /dev/null
+++ b/libyasm/inttree.h
@@ -0,0 +1,70 @@
+#ifndef YASM_INTTREE_H
+#define YASM_INTTREE_H
+
+#ifndef YASM_LIB_DECL
+#define YASM_LIB_DECL
+#endif
+
+/* The interval_tree.h and interval_tree.cc files contain code for
+ * interval trees implemented using red-black-trees as described in
+ * the book _Introduction_To_Algorithms_ by Cormen, Leisserson,
+ * and Rivest.
+ */
+
+typedef struct IntervalTreeNode {
+ struct IntervalTreeNode *left, *right, *parent;
+ void *data;
+ long low;
+ long high;
+ long maxHigh;
+ int red; /* if red=0 then the node is black */
+} IntervalTreeNode;
+
+typedef struct it_recursion_node {
+ /* This structure stores the information needed when we take the
+ * right branch in searching for intervals but possibly come back
+ * and check the left branch as well.
+ */
+ IntervalTreeNode *start_node;
+ unsigned int parentIndex;
+ int tryRightBranch;
+} it_recursion_node;
+
+typedef struct IntervalTree {
+ /* A sentinel is used for root and for nil. These sentinels are
+ * created when ITTreeCreate is called. root->left should always
+ * point to the node which is the root of the tree. nil points to a
+ * node which should always be black but has aribtrary children and
+ * parent and no key or info. The point of using these sentinels is so
+ * that the root and nil nodes do not require special cases in the code
+ */
+ IntervalTreeNode *root;
+ IntervalTreeNode *nil;
+
+/*private:*/
+ unsigned int recursionNodeStackSize;
+ it_recursion_node * recursionNodeStack;
+ unsigned int currentParent;
+ unsigned int recursionNodeStackTop;
+} IntervalTree;
+
+YASM_LIB_DECL
+IntervalTree *IT_create(void);
+YASM_LIB_DECL
+void IT_destroy(IntervalTree *);
+YASM_LIB_DECL
+void IT_print(const IntervalTree *);
+YASM_LIB_DECL
+void *IT_delete_node(IntervalTree *, IntervalTreeNode *, long *low,
+ long *high);
+YASM_LIB_DECL
+IntervalTreeNode *IT_insert(IntervalTree *, long low, long high, void *data);
+YASM_LIB_DECL
+IntervalTreeNode *IT_get_predecessor(const IntervalTree *, IntervalTreeNode *);
+YASM_LIB_DECL
+IntervalTreeNode *IT_get_successor(const IntervalTree *, IntervalTreeNode *);
+YASM_LIB_DECL
+void IT_enumerate(IntervalTree *, long low, long high, void *cbd,
+ void (*callback) (IntervalTreeNode *node, void *cbd));
+
+#endif
diff --git a/libyasm/linemap.c b/libyasm/linemap.c
new file mode 100644
index 0000000..42201d3
--- /dev/null
+++ b/libyasm/linemap.c
@@ -0,0 +1,293 @@
+/*
+ * YASM assembler virtual line mapping handling (for parse stage)
+ *
+ * Copyright (C) 2002-2007 Peter Johnson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "util.h"
+
+#include "coretype.h"
+#include "hamt.h"
+
+#include "errwarn.h"
+#include "linemap.h"
+
+
+typedef struct line_mapping {
+ /* monotonically increasing virtual line */
+ unsigned long line;
+
+ /* related info */
+ /* "original" source filename */
+ /*@null@*/ /*@dependent@*/ const char *filename;
+ /* "original" source base line number */
+ unsigned long file_line;
+ /* "original" source line number increment (for following lines) */
+ unsigned long line_inc;
+} line_mapping;
+
+typedef struct line_source_info {
+ /* first bytecode on line; NULL if no bytecodes on line */
+ /*@null@*/ /*@dependent@*/ yasm_bytecode *bc;
+
+ /* source code line */
+ /*@owned@*/ char *source;
+} line_source_info;
+
+struct yasm_linemap {
+ /* Shared storage for filenames */
+ /*@only@*/ /*@null@*/ HAMT *filenames;
+
+ /* Current virtual line number. */
+ unsigned long current;
+
+ /* Mappings from virtual to physical line numbers */
+ struct line_mapping *map_vector;
+ unsigned long map_size;
+ unsigned long map_allocated;
+
+ /* Bytecode and source line information */
+ /*@only@*/ line_source_info *source_info;
+ size_t source_info_size;
+};
+
+static void
+filename_delete_one(/*@only@*/ void *d)
+{
+ yasm_xfree(d);
+}
+
+void
+yasm_linemap_set(yasm_linemap *linemap, const char *filename,
+ unsigned long virtual_line, unsigned long file_line,
+ unsigned long line_inc)
+{
+ char *copy;
+ unsigned long i;
+ int replace = 0;
+ line_mapping *mapping = NULL;
+
+ if (virtual_line == 0) {
+ virtual_line = linemap->current;
+ }
+
+ /* Replace all existing mappings that have line numbers >= this one. */
+ for (i = linemap->map_size; i > 0; i--) {
+ if (linemap->map_vector[i-1].line < virtual_line) {
+ if (i < linemap->map_size) {
+ mapping = &linemap->map_vector[i];
+ linemap->map_size = i + 1;
+ }
+ break;
+ }
+ }
+
+ if (mapping == NULL) {
+ /* Create a new mapping in the map */
+ if (linemap->map_size >= linemap->map_allocated) {
+ /* allocate another size bins when full for 2x space */
+ linemap->map_vector = yasm_xrealloc(linemap->map_vector,
+ 2*linemap->map_allocated*sizeof(line_mapping));
+ linemap->map_allocated *= 2;
+ }
+ mapping = &linemap->map_vector[linemap->map_size];
+ linemap->map_size++;
+ }
+
+ /* Fill it */
+
+ if (!filename) {
+ if (linemap->map_size >= 2)
+ mapping->filename =
+ linemap->map_vector[linemap->map_size-2].filename;
+ else
+ filename = "unknown";
+ }
+ if (filename) {
+ /* Copy the filename (via shared storage) */
+ copy = yasm__xstrdup(filename);
+ /*@-aliasunique@*/
+ mapping->filename = HAMT_insert(linemap->filenames, copy, copy,
+ &replace, filename_delete_one);
+ /*@=aliasunique@*/
+ }
+
+ mapping->line = virtual_line;
+ mapping->file_line = file_line;
+ mapping->line_inc = line_inc;
+}
+
+unsigned long
+yasm_linemap_poke(yasm_linemap *linemap, const char *filename,
+ unsigned long file_line)
+{
+ unsigned long line;
+ line_mapping *mapping;
+
+ linemap->current++;
+ yasm_linemap_set(linemap, filename, 0, file_line, 0);
+
+ mapping = &linemap->map_vector[linemap->map_size-1];
+
+ line = linemap->current;
+
+ linemap->current++;
+ yasm_linemap_set(linemap, mapping->filename, 0,
+ mapping->file_line +
+ mapping->line_inc*(linemap->current-2-mapping->line),
+ mapping->line_inc);
+
+ return line;
+}
+
+yasm_linemap *
+yasm_linemap_create(void)
+{
+ size_t i;
+ yasm_linemap *linemap = yasm_xmalloc(sizeof(yasm_linemap));
+
+ linemap->filenames = HAMT_create(0, yasm_internal_error_);
+
+ linemap->current = 1;
+
+ /* initialize mapping vector */
+ linemap->map_vector = yasm_xmalloc(8*sizeof(line_mapping));
+ linemap->map_size = 0;
+ linemap->map_allocated = 8;
+
+ /* initialize source line information array */
+ linemap->source_info_size = 2;
+ linemap->source_info = yasm_xmalloc(linemap->source_info_size *
+ sizeof(line_source_info));
+ for (i=0; i<linemap->source_info_size; i++) {
+ linemap->source_info[i].bc = NULL;
+ linemap->source_info[i].source = NULL;
+ }
+
+ return linemap;
+}
+
+void
+yasm_linemap_destroy(yasm_linemap *linemap)
+{
+ size_t i;
+ for (i=0; i<linemap->source_info_size; i++) {
+ if (linemap->source_info[i].source)
+ yasm_xfree(linemap->source_info[i].source);
+ }
+ yasm_xfree(linemap->source_info);
+
+ yasm_xfree(linemap->map_vector);
+
+ if (linemap->filenames)
+ HAMT_destroy(linemap->filenames, filename_delete_one);
+
+ yasm_xfree(linemap);
+}
+
+unsigned long
+yasm_linemap_get_current(yasm_linemap *linemap)
+{
+ return linemap->current;
+}
+
+void
+yasm_linemap_add_source(yasm_linemap *linemap, yasm_bytecode *bc,
+ const char *source)
+{
+ size_t i;
+
+ while (linemap->current > linemap->source_info_size) {
+ /* allocate another size bins when full for 2x space */
+ linemap->source_info = yasm_xrealloc(linemap->source_info,
+ 2*linemap->source_info_size*sizeof(line_source_info));
+ for (i=linemap->source_info_size; i<linemap->source_info_size*2; i++) {
+ linemap->source_info[i].bc = NULL;
+ linemap->source_info[i].source = NULL;
+ }
+ linemap->source_info_size *= 2;
+ }
+
+ /* Delete existing info for that line (if any) */
+ if (linemap->source_info[linemap->current-1].source)
+ yasm_xfree(linemap->source_info[linemap->current-1].source);
+
+ linemap->source_info[linemap->current-1].bc = bc;
+ linemap->source_info[linemap->current-1].source = yasm__xstrdup(source);
+}
+
+unsigned long
+yasm_linemap_goto_next(yasm_linemap *linemap)
+{
+ return ++(linemap->current);
+}
+
+void
+yasm_linemap_lookup(yasm_linemap *linemap, unsigned long line,
+ const char **filename, unsigned long *file_line)
+{
+ line_mapping *mapping;
+ unsigned long vindex, step;
+
+ assert(line <= linemap->current);
+
+ /* Binary search through map to find highest line_index <= index */
+ vindex = 0;
+ /* start step as the greatest power of 2 <= size */
+ step = 1;
+ while (step*2<=linemap->map_size)
+ step*=2;
+ while (step>0) {
+ if (vindex+step < linemap->map_size
+ && linemap->map_vector[vindex+step].line <= line)
+ vindex += step;
+ step /= 2;
+ }
+ mapping = &linemap->map_vector[vindex];
+
+ *filename = mapping->filename;
+ *file_line = (line ? mapping->file_line + mapping->line_inc*(line-mapping->line) : 0);
+}
+
+int
+yasm_linemap_traverse_filenames(yasm_linemap *linemap, /*@null@*/ void *d,
+ int (*func) (const char *filename, void *d))
+{
+ return HAMT_traverse(linemap->filenames, d, (int (*) (void *, void *))func);
+}
+
+int
+yasm_linemap_get_source(yasm_linemap *linemap, unsigned long line,
+ yasm_bytecode **bcp, const char **sourcep)
+{
+ if (line > linemap->source_info_size) {
+ *bcp = NULL;
+ *sourcep = NULL;
+ return 1;
+ }
+
+ *bcp = linemap->source_info[line-1].bc;
+ *sourcep = linemap->source_info[line-1].source;
+
+ return (!(*sourcep));
+}
diff --git a/libyasm/linemap.h b/libyasm/linemap.h
new file mode 100644
index 0000000..1c5aa46
--- /dev/null
+++ b/libyasm/linemap.h
@@ -0,0 +1,141 @@
+/**
+ * \file libyasm/linemap.h
+ * \brief YASM virtual line mapping interface.
+ *
+ * \license
+ * Copyright (C) 2002-2007 Peter Johnson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * \endlicense
+ */
+#ifndef YASM_LINEMAP_H
+#define YASM_LINEMAP_H
+
+#ifndef YASM_LIB_DECL
+#define YASM_LIB_DECL
+#endif
+
+/** Create a new line mapping repository.
+ * \return New repository.
+ */
+YASM_LIB_DECL
+yasm_linemap *yasm_linemap_create(void);
+
+/** Clean up any memory allocated for a repository.
+ * \param linemap line mapping repository
+ */
+YASM_LIB_DECL
+void yasm_linemap_destroy(yasm_linemap *linemap);
+
+/** Get the current line position in a repository.
+ * \param linemap line mapping repository
+ * \return Current virtual line.
+ */
+YASM_LIB_DECL
+unsigned long yasm_linemap_get_current(yasm_linemap *linemap);
+
+/** Get bytecode and source line information, if any, for a virtual line.
+ * \param linemap line mapping repository
+ * \param line virtual line
+ * \param bcp pointer to return bytecode into
+ * \param sourcep pointer to return source code line pointer into
+ * \return Zero if source line information available for line, nonzero if not.
+ * \note If source line information is not available, bcp and sourcep targets
+ * are set to NULL.
+ */
+YASM_LIB_DECL
+int yasm_linemap_get_source(yasm_linemap *linemap, unsigned long line,
+ /*@null@*/ yasm_bytecode **bcp,
+ const char **sourcep);
+
+/** Add bytecode and source line information to the current virtual line.
+ * \attention Deletes any existing bytecode and source line information for
+ * the current virtual line.
+ * \param linemap line mapping repository
+ * \param bc bytecode (if any)
+ * \param source source code line
+ * \note The source code line pointer is NOT kept, it is strdup'ed.
+ */
+YASM_LIB_DECL
+void yasm_linemap_add_source(yasm_linemap *linemap,
+ /*@null@*/ yasm_bytecode *bc,
+ const char *source);
+
+/** Go to the next line (increments the current virtual line).
+ * \param linemap line mapping repository
+ * \return The current (new) virtual line.
+ */
+YASM_LIB_DECL
+unsigned long yasm_linemap_goto_next(yasm_linemap *linemap);
+
+/** Set a new file/line physical association starting point at the specified
+ * virtual line. line_inc indicates how much the "real" line is incremented
+ * by for each virtual line increment (0 is perfectly legal).
+ * \param linemap line mapping repository
+ * \param filename physical file name (if NULL, not changed)
+ * \param virtual_line virtual line number (if 0, linemap->current is used)
+ * \param file_line physical line number
+ * \param line_inc line increment
+ */
+YASM_LIB_DECL
+void yasm_linemap_set(yasm_linemap *linemap, /*@null@*/ const char *filename,
+ unsigned long virtual_line, unsigned long file_line,
+ unsigned long line_inc);
+
+/** Poke a single file/line association, restoring the original physical
+ * association starting point. Caution: increments the current virtual line
+ * twice.
+ * \param linemap line mapping repository
+ * \param filename physical file name (if NULL, not changed)
+ * \param file_line physical line number
+ * \return The virtual line number of the poked association.
+ */
+YASM_LIB_DECL
+unsigned long yasm_linemap_poke(yasm_linemap *linemap,
+ /*@null@*/ const char *filename,
+ unsigned long file_line);
+
+/** Look up the associated physical file and line for a virtual line.
+ * \param linemap line mapping repository
+ * \param line virtual line
+ * \param filename physical file name (output)
+ * \param file_line physical line number (output)
+ */
+YASM_LIB_DECL
+void yasm_linemap_lookup(yasm_linemap *linemap, unsigned long line,
+ /*@out@*/ const char **filename,
+ /*@out@*/ unsigned long *file_line);
+
+/** Traverses all filenames used in a linemap, calling a function on each
+ * filename.
+ * \param linemap line mapping repository
+ * \param d data pointer passed to func on each call
+ * \param func function
+ * \return Stops early (and returns func's return value) if func returns a
+ * nonzero value; otherwise 0.
+ */
+YASM_LIB_DECL
+int yasm_linemap_traverse_filenames
+ (yasm_linemap *linemap, /*@null@*/ void *d,
+ int (*func) (const char *filename, void *d));
+
+#endif
diff --git a/libyasm/listfmt.h b/libyasm/listfmt.h
new file mode 100644
index 0000000..945f28e
--- /dev/null
+++ b/libyasm/listfmt.h
@@ -0,0 +1,124 @@
+/**
+ * \file libyasm/listfmt.h
+ * \brief YASM list format interface.
+ *
+ * \license
+ * Copyright (C) 2004-2007 Peter Johnson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * \endlicense
+ */
+#ifndef YASM_LISTFMT_H
+#define YASM_LISTFMT_H
+
+#ifndef YASM_DOXYGEN
+/** Base #yasm_listfmt structure. Must be present as the first element in any
+ * #yasm_listfmt implementation.
+ */
+typedef struct yasm_listfmt_base {
+ /** #yasm_listfmt_module implementation for this list format. */
+ const struct yasm_listfmt_module *module;
+} yasm_listfmt_base;
+#endif
+
+/** YASM list format module interface. */
+typedef struct yasm_listfmt_module {
+ /** One-line description of the list format. */
+ const char *name;
+
+ /** Keyword used to select list format. */
+ const char *keyword;
+
+ /** Create list format.
+ * Module-level implementation of yasm_listfmt_create().
+ * The filenames are provided solely for informational purposes.
+ * \param in_filename primary input filename
+ * \param obj_filename object filename
+ * \return NULL if unable to initialize.
+ */
+ /*@null@*/ /*@only@*/ yasm_listfmt * (*create)
+ (const char *in_filename, const char *obj_filename);
+
+ /** Module-level implementation of yasm_listfmt_destroy().
+ * Call yasm_listfmt_destroy() instead of calling this function.
+ */
+ void (*destroy) (/*@only@*/ yasm_listfmt *listfmt);
+
+ /** Module-level implementation of yasm_listfmt_output().
+ * Call yasm_listfmt_output() instead of calling this function.
+ */
+ void (*output) (yasm_listfmt *listfmt, FILE *f, yasm_linemap *linemap,
+ yasm_arch *arch);
+} yasm_listfmt_module;
+
+/** Get the keyword used to select a list format.
+ * \param listfmt list format
+ * \return keyword
+ */
+const char *yasm_listfmt_keyword(const yasm_listfmt *listfmt);
+
+/** Initialize list format for use. Must call before any other list
+ * format functions. The filenames are provided solely for informational
+ * purposes.
+ * \param module list format module
+ * \param in_filename primary input filename
+ * \param obj_filename object filename
+ * \return NULL if object format does not provide needed support.
+ */
+/*@null@*/ /*@only@*/ yasm_listfmt *yasm_listfmt_create
+ (const yasm_listfmt_module *module, const char *in_filename,
+ const char *obj_filename);
+
+/** Cleans up any allocated list format memory.
+ * \param listfmt list format
+ */
+void yasm_listfmt_destroy(/*@only@*/ yasm_listfmt *listfmt);
+
+/** Write out list to the list file.
+ * This function may call all read-only yasm_* functions as necessary.
+ * \param listfmt list format
+ * \param f output list file
+ * \param linemap line mapping repository
+ * \param arch architecture
+ */
+void yasm_listfmt_output(yasm_listfmt *listfmt, FILE *f,
+ yasm_linemap *linemap, yasm_arch *arch);
+
+#ifndef YASM_DOXYGEN
+
+/* Inline macro implementations for listfmt functions */
+
+#define yasm_listfmt_keyword(listfmt) \
+ (((yasm_listfmt_base *)listfmt)->module->keyword)
+
+#define yasm_listfmt_create(module, in_filename, obj_filename) \
+ module->create(in_filename, obj_filename)
+
+#define yasm_listfmt_destroy(listfmt) \
+ ((yasm_listfmt_base *)listfmt)->module->destroy(listfmt)
+
+#define yasm_listfmt_output(listfmt, f, linemap, a) \
+ ((yasm_listfmt_base *)listfmt)->module->output(listfmt, f, linemap, a)
+
+#endif
+
+#endif
diff --git a/libyasm/md5.c b/libyasm/md5.c
new file mode 100644
index 0000000..ba1a307
--- /dev/null
+++ b/libyasm/md5.c
@@ -0,0 +1,309 @@
+/*
+ * This code implements the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest. This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD5Context structure, pass it to MD5Init, call MD5Update as
+ * needed on buffers full of bytes, and then call MD5Final, which
+ * will fill a supplied 16-byte array with the digest.
+ */
+
+/* This code was modified in 1997 by Jim Kingdon of Cyclic Software to
+ not require an integer type which is exactly 32 bits. This work
+ draws on the changes for the same purpose by Tatu Ylonen
+ <ylo@cs.hut.fi> as part of SSH, but since I didn't actually use
+ that code, there is no copyright issue. I hereby disclaim
+ copyright in any changes I have made; this code remains in the
+ public domain. */
+
+/* Note regarding cvs_* namespace: this avoids potential conflicts
+ with libraries such as some versions of Kerberos. No particular
+ need to worry about whether the system supplies an MD5 library, as
+ this file is only about 3k of object code. */
+
+#include <util.h>
+
+#include "md5.h"
+
+/* Little-endian byte-swapping routines. Note that these do not
+ depend on the size of datatypes such as cvs_uint32, nor do they require
+ us to detect the endianness of the machine we are running on. It
+ is possible they should be macros for speed, but I would be
+ surprised if they were a performance bottleneck for MD5. */
+
+static unsigned long
+getu32(const unsigned char *addr)
+{
+ return (((((unsigned long)addr[3] << 8) | addr[2]) << 8)
+ | addr[1]) << 8 | addr[0];
+}
+
+static void
+putu32(unsigned long data, unsigned char *addr)
+{
+ addr[0] = (unsigned char)data;
+ addr[1] = (unsigned char)(data >> 8);
+ addr[2] = (unsigned char)(data >> 16);
+ addr[3] = (unsigned char)(data >> 24);
+}
+
+/*
+ * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
+ * initialization constants.
+ */
+void
+yasm_md5_init(yasm_md5_context *ctx)
+{
+ ctx->buf[0] = 0x67452301;
+ ctx->buf[1] = 0xefcdab89;
+ ctx->buf[2] = 0x98badcfe;
+ ctx->buf[3] = 0x10325476;
+
+ ctx->bits[0] = 0;
+ ctx->bits[1] = 0;
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+void
+yasm_md5_update(yasm_md5_context *ctx, unsigned char const *buf,
+ unsigned long len)
+{
+ unsigned long t;
+
+ /* Update bitcount */
+
+ t = ctx->bits[0];
+ if ((ctx->bits[0] = (t + ((unsigned long)len << 3)) & 0xffffffff) < t)
+ ctx->bits[1]++; /* Carry from low to high */
+ ctx->bits[1] += len >> 29;
+
+ t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
+
+ /* Handle any leading odd-sized chunks */
+
+ if ( t ) {
+ unsigned char *p = ctx->in + t;
+
+ t = 64-t;
+ if (len < t) {
+ memcpy(p, buf, len);
+ return;
+ }
+ memcpy(p, buf, t);
+ yasm_md5_transform (ctx->buf, ctx->in);
+ buf += t;
+ len -= t;
+ }
+
+ /* Process data in 64-byte chunks */
+
+ while (len >= 64) {
+ memcpy(ctx->in, buf, 64);
+ yasm_md5_transform (ctx->buf, ctx->in);
+ buf += 64;
+ len -= 64;
+ }
+
+ /* Handle any remaining bytes of data. */
+
+ memcpy(ctx->in, buf, len);
+}
+
+/*
+ * Final wrapup - pad to 64-byte boundary with the bit pattern
+ * 1 0* (64-bit count of bits processed, MSB-first)
+ */
+void
+yasm_md5_final(unsigned char digest[16], yasm_md5_context *ctx)
+{
+ unsigned count;
+ unsigned char *p;
+
+ /* Compute number of bytes mod 64 */
+ count = (ctx->bits[0] >> 3) & 0x3F;
+
+ /* Set the first char of padding to 0x80. This is safe since there is
+ always at least one byte free */
+ p = ctx->in + count;
+ *p++ = 0x80;
+
+ /* Bytes of padding needed to make 64 bytes */
+ count = 64 - 1 - count;
+
+ /* Pad out to 56 mod 64 */
+ if (count < 8) {
+ /* Two lots of padding: Pad the first block to 64 bytes */
+ memset(p, 0, count);
+ yasm_md5_transform (ctx->buf, ctx->in);
+
+ /* Now fill the next block with 56 bytes */
+ memset(ctx->in, 0, 56);
+ } else {
+ /* Pad block to 56 bytes */
+ memset(p, 0, count-8);
+ }
+
+ /* Append length in bits and transform */
+ putu32(ctx->bits[0], ctx->in + 56);
+ putu32(ctx->bits[1], ctx->in + 60);
+
+ yasm_md5_transform (ctx->buf, ctx->in);
+ putu32(ctx->buf[0], digest);
+ putu32(ctx->buf[1], digest + 4);
+ putu32(ctx->buf[2], digest + 8);
+ putu32(ctx->buf[3], digest + 12);
+ memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */
+}
+
+#ifndef ASM_MD5
+
+/* The four core functions - F1 is optimized somewhat */
+
+/* #define F1(x, y, z) (x & y | ~x & z) */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+/* This is the central step in the MD5 algorithm. */
+#define MD5STEP(f, w, x, y, z, data, s) \
+ ( w += f(x, y, z) + data, w &= 0xffffffff, w = w<<s | w>>(32-s), w += x )
+
+/*
+ * The core of the MD5 algorithm, this alters an existing MD5 hash to
+ * reflect the addition of 16 longwords of new data. MD5Update blocks
+ * the data and converts bytes into longwords for this routine.
+ */
+void
+yasm_md5_transform(unsigned long buf[4], const unsigned char inraw[64])
+{
+ register unsigned long a, b, c, d;
+ unsigned long in[16];
+ int i;
+
+ for (i = 0; i < 16; ++i)
+ in[i] = getu32 (inraw + 4 * i);
+
+ a = buf[0];
+ b = buf[1];
+ c = buf[2];
+ d = buf[3];
+
+ MD5STEP(F1, a, b, c, d, in[ 0]+0xd76aa478, 7);
+ MD5STEP(F1, d, a, b, c, in[ 1]+0xe8c7b756, 12);
+ MD5STEP(F1, c, d, a, b, in[ 2]+0x242070db, 17);
+ MD5STEP(F1, b, c, d, a, in[ 3]+0xc1bdceee, 22);
+ MD5STEP(F1, a, b, c, d, in[ 4]+0xf57c0faf, 7);
+ MD5STEP(F1, d, a, b, c, in[ 5]+0x4787c62a, 12);
+ MD5STEP(F1, c, d, a, b, in[ 6]+0xa8304613, 17);
+ MD5STEP(F1, b, c, d, a, in[ 7]+0xfd469501, 22);
+ MD5STEP(F1, a, b, c, d, in[ 8]+0x698098d8, 7);
+ MD5STEP(F1, d, a, b, c, in[ 9]+0x8b44f7af, 12);
+ MD5STEP(F1, c, d, a, b, in[10]+0xffff5bb1, 17);
+ MD5STEP(F1, b, c, d, a, in[11]+0x895cd7be, 22);
+ MD5STEP(F1, a, b, c, d, in[12]+0x6b901122, 7);
+ MD5STEP(F1, d, a, b, c, in[13]+0xfd987193, 12);
+ MD5STEP(F1, c, d, a, b, in[14]+0xa679438e, 17);
+ MD5STEP(F1, b, c, d, a, in[15]+0x49b40821, 22);
+
+ MD5STEP(F2, a, b, c, d, in[ 1]+0xf61e2562, 5);
+ MD5STEP(F2, d, a, b, c, in[ 6]+0xc040b340, 9);
+ MD5STEP(F2, c, d, a, b, in[11]+0x265e5a51, 14);
+ MD5STEP(F2, b, c, d, a, in[ 0]+0xe9b6c7aa, 20);
+ MD5STEP(F2, a, b, c, d, in[ 5]+0xd62f105d, 5);
+ MD5STEP(F2, d, a, b, c, in[10]+0x02441453, 9);
+ MD5STEP(F2, c, d, a, b, in[15]+0xd8a1e681, 14);
+ MD5STEP(F2, b, c, d, a, in[ 4]+0xe7d3fbc8, 20);
+ MD5STEP(F2, a, b, c, d, in[ 9]+0x21e1cde6, 5);
+ MD5STEP(F2, d, a, b, c, in[14]+0xc33707d6, 9);
+ MD5STEP(F2, c, d, a, b, in[ 3]+0xf4d50d87, 14);
+ MD5STEP(F2, b, c, d, a, in[ 8]+0x455a14ed, 20);
+ MD5STEP(F2, a, b, c, d, in[13]+0xa9e3e905, 5);
+ MD5STEP(F2, d, a, b, c, in[ 2]+0xfcefa3f8, 9);
+ MD5STEP(F2, c, d, a, b, in[ 7]+0x676f02d9, 14);
+ MD5STEP(F2, b, c, d, a, in[12]+0x8d2a4c8a, 20);
+
+ MD5STEP(F3, a, b, c, d, in[ 5]+0xfffa3942, 4);
+ MD5STEP(F3, d, a, b, c, in[ 8]+0x8771f681, 11);
+ MD5STEP(F3, c, d, a, b, in[11]+0x6d9d6122, 16);
+ MD5STEP(F3, b, c, d, a, in[14]+0xfde5380c, 23);
+ MD5STEP(F3, a, b, c, d, in[ 1]+0xa4beea44, 4);
+ MD5STEP(F3, d, a, b, c, in[ 4]+0x4bdecfa9, 11);
+ MD5STEP(F3, c, d, a, b, in[ 7]+0xf6bb4b60, 16);
+ MD5STEP(F3, b, c, d, a, in[10]+0xbebfbc70, 23);
+ MD5STEP(F3, a, b, c, d, in[13]+0x289b7ec6, 4);
+ MD5STEP(F3, d, a, b, c, in[ 0]+0xeaa127fa, 11);
+ MD5STEP(F3, c, d, a, b, in[ 3]+0xd4ef3085, 16);
+ MD5STEP(F3, b, c, d, a, in[ 6]+0x04881d05, 23);
+ MD5STEP(F3, a, b, c, d, in[ 9]+0xd9d4d039, 4);
+ MD5STEP(F3, d, a, b, c, in[12]+0xe6db99e5, 11);
+ MD5STEP(F3, c, d, a, b, in[15]+0x1fa27cf8, 16);
+ MD5STEP(F3, b, c, d, a, in[ 2]+0xc4ac5665, 23);
+
+ MD5STEP(F4, a, b, c, d, in[ 0]+0xf4292244, 6);
+ MD5STEP(F4, d, a, b, c, in[ 7]+0x432aff97, 10);
+ MD5STEP(F4, c, d, a, b, in[14]+0xab9423a7, 15);
+ MD5STEP(F4, b, c, d, a, in[ 5]+0xfc93a039, 21);
+ MD5STEP(F4, a, b, c, d, in[12]+0x655b59c3, 6);
+ MD5STEP(F4, d, a, b, c, in[ 3]+0x8f0ccc92, 10);
+ MD5STEP(F4, c, d, a, b, in[10]+0xffeff47d, 15);
+ MD5STEP(F4, b, c, d, a, in[ 1]+0x85845dd1, 21);
+ MD5STEP(F4, a, b, c, d, in[ 8]+0x6fa87e4f, 6);
+ MD5STEP(F4, d, a, b, c, in[15]+0xfe2ce6e0, 10);
+ MD5STEP(F4, c, d, a, b, in[ 6]+0xa3014314, 15);
+ MD5STEP(F4, b, c, d, a, in[13]+0x4e0811a1, 21);
+ MD5STEP(F4, a, b, c, d, in[ 4]+0xf7537e82, 6);
+ MD5STEP(F4, d, a, b, c, in[11]+0xbd3af235, 10);
+ MD5STEP(F4, c, d, a, b, in[ 2]+0x2ad7d2bb, 15);
+ MD5STEP(F4, b, c, d, a, in[ 9]+0xeb86d391, 21);
+
+ buf[0] += a;
+ buf[1] += b;
+ buf[2] += c;
+ buf[3] += d;
+}
+#endif
+
+#ifdef TEST
+/* Simple test program. Can use it to manually run the tests from
+ RFC1321 for example. */
+#include <stdio.h>
+
+int
+main (int argc, char **argv)
+{
+ yasm_md5_context context;
+ unsigned char checksum[16];
+ int i;
+ int j;
+
+ if (argc < 2)
+ {
+ fprintf (stderr, "usage: %s string-to-hash\n", argv[0]);
+ exit (1);
+ }
+ for (j = 1; j < argc; ++j)
+ {
+ printf ("MD5 (\"%s\") = ", argv[j]);
+ yasm_md5_init (&context);
+ yasm_md5_update (&context, argv[j], strlen (argv[j]));
+ yasm_md5_final (checksum, &context);
+ for (i = 0; i < 16; i++)
+ {
+ printf ("%02x", (unsigned int) checksum[i]);
+ }
+ printf ("\n");
+ }
+ return 0;
+}
+#endif /* TEST */
diff --git a/libyasm/md5.h b/libyasm/md5.h
new file mode 100644
index 0000000..7872fda
--- /dev/null
+++ b/libyasm/md5.h
@@ -0,0 +1,32 @@
+/* See md5.c for explanation and copyright information. */
+
+#ifndef YASM_MD5_H
+#define YASM_MD5_H
+
+#ifndef YASM_LIB_DECL
+#define YASM_LIB_DECL
+#endif
+
+/* Unlike previous versions of this code, uint32 need not be exactly
+ 32 bits, merely 32 bits or more. Choosing a data type which is 32
+ bits instead of 64 is not important; speed is considerably more
+ important. ANSI guarantees that "unsigned long" will be big enough,
+ and always using it seems to have few disadvantages. */
+
+typedef struct yasm_md5_context {
+ unsigned long buf[4];
+ unsigned long bits[2];
+ unsigned char in[64];
+} yasm_md5_context;
+
+YASM_LIB_DECL
+void yasm_md5_init(yasm_md5_context *context);
+YASM_LIB_DECL
+void yasm_md5_update(yasm_md5_context *context, unsigned char const *buf,
+ unsigned long len);
+YASM_LIB_DECL
+void yasm_md5_final(unsigned char digest[16], yasm_md5_context *context);
+YASM_LIB_DECL
+void yasm_md5_transform(unsigned long buf[4], const unsigned char in[64]);
+
+#endif /* !YASM_MD5_H */
diff --git a/libyasm/mergesort.c b/libyasm/mergesort.c
new file mode 100644
index 0000000..3eeaa82
--- /dev/null
+++ b/libyasm/mergesort.c
@@ -0,0 +1,361 @@
+/*
+ * mergesort() implementation for systems that don't have it.
+ *
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Peter McIlroy.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#include "util.h"
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)merge.c 8.2 (Berkeley) 2/14/94";
+#endif /* LIBC_SCCS and not lint */
+
+#ifdef HAVE_MERGESORT
+#undef yasm__mergesort
+#endif
+
+#ifndef HAVE_MERGESORT
+/*
+ * Hybrid exponential search/linear search merge sort with hybrid
+ * natural/pairwise first pass. Requires about .3% more comparisons
+ * for random data than LSMS with pairwise first pass alone.
+ * It works for objects as small as two bytes.
+ */
+
+#define NATURAL
+#define THRESHOLD 16 /* Best choice for natural merge cut-off. */
+
+/* #define NATURAL to get hybrid natural merge.
+ * (The default is pairwise merging.)
+ */
+
+#include <errno.h>
+#include <string.h>
+
+static void setup(unsigned char *, unsigned char *, size_t, size_t,
+ int (*)(const void *, const void *));
+static void insertionsort(unsigned char *, size_t, size_t,
+ int (*)(const void *, const void *));
+
+#define ISIZE sizeof(int)
+#define PSIZE sizeof(unsigned char *)
+#define ICOPY_LIST(src, dst, last) \
+ do \
+ *(int*)dst = *(int*)src, src += ISIZE, dst += ISIZE; \
+ while(src < last)
+#define ICOPY_ELT(src, dst, i) \
+ do \
+ *(int*) dst = *(int*) src, src += ISIZE, dst += ISIZE; \
+ while (i -= ISIZE)
+
+#define CCOPY_LIST(src, dst, last) \
+ do \
+ *dst++ = *src++; \
+ while (src < last)
+#define CCOPY_ELT(src, dst, i) \
+ do \
+ *dst++ = *src++; \
+ while (i -= 1)
+
+/*
+ * Find the next possible pointer head. (Trickery for forcing an array
+ * to do double duty as a linked list when objects do not align with word
+ * boundaries.
+ */
+/* Assumption: PSIZE is a power of 2. */
+#define EVAL(p) (unsigned char **) \
+ ((unsigned char *)0 + \
+ (((unsigned char *)p + PSIZE - 1 - (unsigned char *) 0) & ~(PSIZE - 1)))
+#endif /*HAVE_MERGESORT*/
+
+/*
+ * Arguments are as for qsort.
+ */
+int
+yasm__mergesort(void *base, size_t nmemb, size_t size,
+ int (*cmp)(const void *, const void *))
+{
+#ifdef HAVE_MERGESORT
+ return mergesort(base, nmemb, size, cmp);
+#else
+ size_t i;
+ int sense;
+ int big, iflag;
+ unsigned char *f1, *f2, *t, *b, *tp2, *q, *l1, *l2;
+ unsigned char *list2, *list1, *p2, *p, *last, **p1;
+
+ if (size < PSIZE / 2) { /* Pointers must fit into 2 * size. */
+#ifdef EINVAL
+ errno = EINVAL;
+#endif
+ return (-1);
+ }
+
+ if (nmemb == 0)
+ return (0);
+
+ /*
+ * XXX
+ * Stupid subtraction for the Cray.
+ */
+ iflag = 0;
+ if (!(size % ISIZE) && !(((char *)base - (char *)0) % ISIZE))
+ iflag = 1;
+
+ if ((list2 = yasm_xmalloc(nmemb * size + PSIZE)) == NULL)
+ return (-1);
+
+ list1 = base;
+ setup(list1, list2, nmemb, size, cmp);
+ last = list2 + nmemb * size;
+ i = 0;
+ big = 0;
+ while (*EVAL(list2) != last) {
+ l2 = list1;
+ p1 = EVAL(list1);
+ for (tp2 = p2 = list2; p2 != last; p1 = EVAL(l2)) {
+ p2 = *EVAL(p2);
+ f1 = l2;
+ f2 = l1 = list1 + (p2 - list2);
+ if (p2 != last)
+ p2 = *EVAL(p2);
+ l2 = list1 + (p2 - list2);
+ while (f1 < l1 && f2 < l2) {
+ if ((*cmp)(f1, f2) <= 0) {
+ q = f2;
+ b = f1, t = l1;
+ sense = -1;
+ } else {
+ q = f1;
+ b = f2, t = l2;
+ sense = 0;
+ }
+ if (!big) { /* here i = 0 */
+ while ((b += size) < t && cmp(q, b) >sense)
+ if (++i == 6) {
+ big = 1;
+ goto EXPONENTIAL;
+ }
+ } else {
+EXPONENTIAL: for (i = size; ; i <<= 1)
+ if ((p = (b + i)) >= t) {
+ if ((p = t - size) > b &&
+ (*cmp)(q, p) <= sense)
+ t = p;
+ else
+ b = p;
+ break;
+ } else if ((*cmp)(q, p) <= sense) {
+ t = p;
+ if (i == size)
+ big = 0;
+ goto FASTCASE;
+ } else
+ b = p;
+ while (t > b+size) {
+ i = (((t - b) / size) >> 1) * size;
+ if ((*cmp)(q, p = b + i) <= sense)
+ t = p;
+ else
+ b = p;
+ }
+ goto COPY;
+FASTCASE: while (i > size)
+ if ((*cmp)(q,
+ p = b + (i >>= 1)) <= sense)
+ t = p;
+ else
+ b = p;
+COPY: b = t;
+ }
+ i = size;
+ if (q == f1) {
+ if (iflag) {
+ ICOPY_LIST(f2, tp2, b);
+ ICOPY_ELT(f1, tp2, i);
+ } else {
+ CCOPY_LIST(f2, tp2, b);
+ CCOPY_ELT(f1, tp2, i);
+ }
+ } else {
+ if (iflag) {
+ ICOPY_LIST(f1, tp2, b);
+ ICOPY_ELT(f2, tp2, i);
+ } else {
+ CCOPY_LIST(f1, tp2, b);
+ CCOPY_ELT(f2, tp2, i);
+ }
+ }
+ }
+ if (f2 < l2) {
+ if (iflag)
+ ICOPY_LIST(f2, tp2, l2);
+ else
+ CCOPY_LIST(f2, tp2, l2);
+ } else if (f1 < l1) {
+ if (iflag)
+ ICOPY_LIST(f1, tp2, l1);
+ else
+ CCOPY_LIST(f1, tp2, l1);
+ }
+ *p1 = l2;
+ }
+ tp2 = list1; /* swap list1, list2 */
+ list1 = list2;
+ list2 = tp2;
+ last = list2 + nmemb*size;
+ }
+ if (base == list2) {
+ memmove(list2, list1, nmemb*size);
+ list2 = list1;
+ }
+ yasm_xfree(list2);
+ return (0);
+#endif /*HAVE_MERGESORT*/
+}
+
+#ifndef HAVE_MERGESORT
+
+#define swap(a, b) { \
+ s = b; \
+ i = size; \
+ do { \
+ tmp = *a; *a++ = *s; *s++ = tmp; \
+ } while (--i); \
+ a -= size; \
+ }
+#define reverse(bot, top) { \
+ s = top; \
+ do { \
+ i = size; \
+ do { \
+ tmp = *bot; *bot++ = *s; *s++ = tmp; \
+ } while (--i); \
+ s -= size2; \
+ } while(bot < s); \
+}
+
+/*
+ * Optional hybrid natural/pairwise first pass. Eats up list1 in runs of
+ * increasing order, list2 in a corresponding linked list. Checks for runs
+ * when THRESHOLD/2 pairs compare with same sense. (Only used when NATURAL
+ * is defined. Otherwise simple pairwise merging is used.)
+ */
+void
+setup(unsigned char *list1, unsigned char *list2, size_t n, size_t size,
+ int (*cmp)(const void *, const void *))
+{
+ size_t i;
+ unsigned int tmp;
+ int length, sense;
+ size_t size2;
+ unsigned char *f1, *f2, *s, *l2, *last, *p2;
+
+ size2 = size*2;
+ if (n <= 5) {
+ insertionsort(list1, n, size, cmp);
+ *EVAL(list2) = (unsigned char*) list2 + n*size;
+ return;
+ }
+ /*
+ * Avoid running pointers out of bounds; limit n to evens
+ * for simplicity.
+ */
+ i = 4 + (n & 1);
+ insertionsort(list1 + (n - i) * size, i, size, cmp);
+ last = list1 + size * (n - i);
+ *EVAL(list2 + (last - list1)) = list2 + n * size;
+
+#ifdef NATURAL
+ p2 = list2;
+ f1 = list1;
+ sense = (cmp(f1, f1 + size) > 0);
+ for (; f1 < last; sense = !sense) {
+ length = 2;
+ /* Find pairs with same sense. */
+ for (f2 = f1 + size2; f2 < last; f2 += size2) {
+ if ((cmp(f2, f2+ size) > 0) != sense)
+ break;
+ length += 2;
+ }
+ if (length < THRESHOLD) { /* Pairwise merge */
+ do {
+ p2 = *EVAL(p2) = f1 + size2 - list1 + list2;
+ if (sense > 0)
+ swap (f1, f1 + size);
+ } while ((f1 += size2) < f2);
+ } else { /* Natural merge */
+ l2 = f2;
+ for (f2 = f1 + size2; f2 < l2; f2 += size2) {
+ if ((cmp(f2-size, f2) > 0) != sense) {
+ p2 = *EVAL(p2) = f2 - list1 + list2;
+ if (sense > 0)
+ reverse(f1, f2-size);
+ f1 = f2;
+ }
+ }
+ if (sense > 0)
+ reverse (f1, f2-size);
+ f1 = f2;
+ if (f2 < last || cmp(f2 - size, f2) > 0)
+ p2 = *EVAL(p2) = f2 - list1 + list2;
+ else
+ p2 = *EVAL(p2) = list2 + n*size;
+ }
+ }
+#else /* pairwise merge only. */
+ for (f1 = list1, p2 = list2; f1 < last; f1 += size2) {
+ p2 = *EVAL(p2) = p2 + size2;
+ if (cmp (f1, f1 + size) > 0)
+ swap(f1, f1 + size);
+ }
+#endif /* NATURAL */
+}
+
+/*
+ * This is to avoid out-of-bounds addresses in sorting the
+ * last 4 elements.
+ */
+static void
+insertionsort(unsigned char *a, size_t n, size_t size,
+ int (*cmp)(const void *, const void *))
+{
+ unsigned char *ai, *s, *t, *u, tmp;
+ size_t i;
+
+ for (ai = a+size; --n >= 1; ai += size)
+ for (t = ai; t > a; t -= size) {
+ u = t - size;
+ if (cmp(u, t) <= 0)
+ break;
+ swap(u, t);
+ }
+}
+#endif /*HAVE_MERGESORT*/
diff --git a/libyasm/module.h b/libyasm/module.h
new file mode 100644
index 0000000..220017d
--- /dev/null
+++ b/libyasm/module.h
@@ -0,0 +1,82 @@
+/*
+ * YASM module loader header file
+ *
+ * Copyright (C) 2002-2007 Peter Johnson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef YASM_MODULE_H
+#define YASM_MODULE_H
+
+#ifndef YASM_LIB_DECL
+#define YASM_LIB_DECL
+#endif
+
+typedef enum yasm_module_type {
+ YASM_MODULE_ARCH = 0,
+ YASM_MODULE_DBGFMT,
+ YASM_MODULE_OBJFMT,
+ YASM_MODULE_LISTFMT,
+ YASM_MODULE_PARSER,
+ YASM_MODULE_PREPROC
+} yasm_module_type;
+
+YASM_LIB_DECL
+/*@dependent@*/ /*@null@*/ void *yasm_load_module
+ (yasm_module_type type, const char *keyword);
+
+#define yasm_load_arch(keyword) \
+ yasm_load_module(YASM_MODULE_ARCH, keyword)
+#define yasm_load_dbgfmt(keyword) \
+ yasm_load_module(YASM_MODULE_DBGFMT, keyword)
+#define yasm_load_objfmt(keyword) \
+ yasm_load_module(YASM_MODULE_OBJFMT, keyword)
+#define yasm_load_listfmt(keyword) \
+ yasm_load_module(YASM_MODULE_LISTFMT, keyword)
+#define yasm_load_parser(keyword) \
+ yasm_load_module(YASM_MODULE_PARSER, keyword)
+#define yasm_load_preproc(keyword) \
+ yasm_load_module(YASM_MODULE_PREPROC, keyword)
+
+YASM_LIB_DECL
+void yasm_list_modules
+ (yasm_module_type type,
+ void (*printfunc) (const char *name, const char *keyword));
+
+#define yasm_list_arch(func) \
+ yasm_list_modules(YASM_MODULE_ARCH, func)
+#define yasm_list_dbgfmt(func) \
+ yasm_list_modules(YASM_MODULE_DBGFMT, func)
+#define yasm_list_objfmt(func) \
+ yasm_list_modules(YASM_MODULE_OBJFMT, func)
+#define yasm_list_listfmt(func) \
+ yasm_list_modules(YASM_MODULE_LISTFMT, func)
+#define yasm_list_parser(func) \
+ yasm_list_modules(YASM_MODULE_PARSER, func)
+#define yasm_list_preproc(func) \
+ yasm_list_modules(YASM_MODULE_PREPROC, func)
+
+YASM_LIB_DECL
+void yasm_register_module(yasm_module_type type, const char *keyword,
+ void *data);
+
+#endif
diff --git a/libyasm/module.in b/libyasm/module.in
new file mode 100644
index 0000000..a18778b
--- /dev/null
+++ b/libyasm/module.in
@@ -0,0 +1,179 @@
+/*
+ * YASM module loader
+ *
+ * Copyright (C) 2004-2007 Peter Johnson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <util.h>
+
+#include <libyasm.h>
+
+
+typedef struct module {
+ const char *keyword; /* module keyword */
+ void *data; /* associated data */
+} module;
+
+EXTERN_LIST
+
+static module arch_modules[] = {
+MODULES_arch_
+};
+
+static module dbgfmt_modules[] = {
+MODULES_dbgfmt_
+};
+
+static module objfmt_modules[] = {
+MODULES_objfmt_
+};
+
+static module listfmt_modules[] = {
+MODULES_listfmt_
+};
+
+static module parser_modules[] = {
+MODULES_parser_
+};
+
+static module preproc_modules[] = {
+MODULES_preproc_
+};
+
+static struct {
+ module *m;
+ size_t n;
+} module_types[] = {
+ {arch_modules, sizeof(arch_modules)/sizeof(module)},
+ {dbgfmt_modules, sizeof(dbgfmt_modules)/sizeof(module)},
+ {objfmt_modules, sizeof(objfmt_modules)/sizeof(module)},
+ {listfmt_modules, sizeof(listfmt_modules)/sizeof(module)},
+ {parser_modules, sizeof(parser_modules)/sizeof(module)},
+ {preproc_modules, sizeof(preproc_modules)/sizeof(module)},
+};
+
+typedef struct loaded_module {
+ yasm_module_type type; /* module type */
+ const char *keyword; /* module keyword */
+ void *data; /* associated data */
+} loaded_module;
+
+static loaded_module *loaded_modules = NULL;
+static size_t num_loaded_modules = 0;
+
+void *
+yasm_load_module(yasm_module_type type, const char *keyword)
+{
+ size_t i;
+ module *modules;
+ size_t n;
+
+ /* Look for the module/symbol, first in loaded modules */
+ if (loaded_modules) {
+ for (i=0; i<num_loaded_modules; i++) {
+ if (loaded_modules[i].type == type &&
+ yasm__strcasecmp(loaded_modules[i].keyword, keyword) == 0)
+ return loaded_modules[i].data;
+ }
+ }
+
+ modules = module_types[type].m;
+ n = module_types[type].n;
+ for (i=0; i<n; i++) {
+ if (yasm__strcasecmp(modules[i].keyword, keyword) == 0)
+ return modules[i].data;
+ }
+
+ return NULL;
+}
+
+void
+yasm_register_module(yasm_module_type type, const char *keyword, void *data)
+{
+ loaded_modules =
+ yasm_xrealloc(loaded_modules,
+ (num_loaded_modules+1)*sizeof(loaded_module));
+ loaded_modules[num_loaded_modules].type = type;
+ loaded_modules[num_loaded_modules].keyword = keyword;
+ loaded_modules[num_loaded_modules].data = data;
+ num_loaded_modules++;
+}
+
+static void
+yasm_list_one_module(yasm_module_type type, void *data,
+ void (*printfunc) (const char *name, const char *keyword))
+{
+ yasm_arch_module *arch;
+ yasm_dbgfmt_module *dbgfmt;
+ yasm_objfmt_module *objfmt;
+ yasm_listfmt_module *listfmt;
+ yasm_parser_module *parser;
+ yasm_preproc_module *preproc;
+
+ switch (type) {
+ case YASM_MODULE_ARCH:
+ arch = data;
+ printfunc(arch->name, arch->keyword);
+ break;
+ case YASM_MODULE_DBGFMT:
+ dbgfmt = data;
+ printfunc(dbgfmt->name, dbgfmt->keyword);
+ break;
+ case YASM_MODULE_OBJFMT:
+ objfmt = data;
+ printfunc(objfmt->name, objfmt->keyword);
+ break;
+ case YASM_MODULE_LISTFMT:
+ listfmt = data;
+ printfunc(listfmt->name, listfmt->keyword);
+ break;
+ case YASM_MODULE_PARSER:
+ parser = data;
+ printfunc(parser->name, parser->keyword);
+ break;
+ case YASM_MODULE_PREPROC:
+ preproc = data;
+ printfunc(preproc->name, preproc->keyword);
+ break;
+ }
+}
+
+void
+yasm_list_modules(yasm_module_type type,
+ void (*printfunc) (const char *name, const char *keyword))
+{
+ size_t i;
+ module *modules;
+ size_t n;;
+
+ /* Go through available list, and try to load each one */
+ if (loaded_modules) {
+ for (i=0; i<num_loaded_modules; i++)
+ yasm_list_one_module(type, loaded_modules[i].data, printfunc);
+ }
+
+ modules = module_types[type].m;
+ n = module_types[type].n;
+ for (i=0; i<n; i++)
+ yasm_list_one_module(type, modules[i].data, printfunc);
+}
diff --git a/libyasm/objfmt.h b/libyasm/objfmt.h
new file mode 100644
index 0000000..840296a
--- /dev/null
+++ b/libyasm/objfmt.h
@@ -0,0 +1,216 @@
+/**
+ * \file libyasm/objfmt.h
+ * \brief YASM object format module interface.
+ *
+ * \license
+ * Copyright (C) 2001-2007 Peter Johnson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * \endlicense
+ */
+#ifndef YASM_OBJFMT_H
+#define YASM_OBJFMT_H
+
+#ifndef YASM_DOXYGEN
+/** Base #yasm_objfmt structure. Must be present as the first element in any
+ * #yasm_objfmt implementation.
+ */
+typedef struct yasm_objfmt_base {
+ /** #yasm_objfmt_module implementation for this object format. */
+ const struct yasm_objfmt_module *module;
+} yasm_objfmt_base;
+#endif
+
+/** Object format module interface. */
+struct yasm_objfmt_module {
+ /** One-line description of the object format. */
+ const char *name;
+
+ /** Keyword used to select object format. */
+ const char *keyword;
+
+ /** Default output file extension (without the '.').
+ * NULL means no extension, with no '.', while "" includes the '.'.
+ */
+ /*@null@*/ const char *extension;
+
+ /** Default (starting) x86 BITS setting. This only appies to the x86
+ * architecture; other architectures ignore this setting.
+ */
+ const unsigned char default_x86_mode_bits;
+
+ /** If @ signs should be legal in identifiers. */
+ const unsigned char id_at_ok;
+
+ /** NULL-terminated list of debug format (yasm_dbgfmt) keywords that are
+ * valid to use with this object format. The null debug format
+ * (null_dbgfmt, "null") should always be in this list so it's possible to
+ * have no debug output.
+ */
+ const char **dbgfmt_keywords;
+
+ /** Default debug format keyword (set even if there's only one available to
+ * use).
+ */
+ const char *default_dbgfmt_keyword;
+
+ /** NULL-terminated list of directives. NULL if none. */
+ /*@null@*/ const yasm_directive *directives;
+
+ /** NULL-terminated list of standard macro lookups. NULL if none. */
+ const yasm_stdmac *stdmacs;
+
+ /** Create object format.
+ * Module-level implementation of yasm_objfmt_create().
+ * Call yasm_objfmt_create() instead of calling this function.
+ * \param object object
+ * \param a architecture in use
+ * \return NULL if architecture/machine combination not supported.
+ */
+ /*@null@*/ /*@only@*/ yasm_objfmt * (*create) (yasm_object *object);
+
+ /** Module-level implementation of yasm_objfmt_output().
+ * Call yasm_objfmt_output() instead of calling this function.
+ */
+ void (*output) (yasm_object *o, FILE *f, int all_syms,
+ yasm_errwarns *errwarns);
+
+ /** Module-level implementation of yasm_objfmt_destroy().
+ * Call yasm_objfmt_destroy() instead of calling this function.
+ */
+ void (*destroy) (/*@only@*/ yasm_objfmt *objfmt);
+
+ /** Module-level implementation of yasm_objfmt_add_default_section().
+ * Call yasm_objfmt_add_default_section() instead of calling this function.
+ */
+ yasm_section * (*add_default_section) (yasm_object *object);
+
+ /** Module-level implementation of yasm_objfmt_init_new_section().
+ * Call yasm_objfmt_init_new_section() instead of calling this function.
+ */
+ void (*init_new_section) (yasm_section *section, unsigned long line);
+
+ /** Module-level implementation of yasm_objfmt_section_switch().
+ * Call yasm_objfmt_section_switch() instead of calling this function.
+ */
+ /*@observer@*/ /*@null@*/ yasm_section *
+ (*section_switch)(yasm_object *object, yasm_valparamhead *valparams,
+ /*@null@*/ yasm_valparamhead *objext_valparams,
+ unsigned long line);
+
+ /** Module-level implementation of yasm_objfmt_get_special_sym().
+ * Call yasm_objfmt_get_special_sym() instead of calling this function.
+ */
+ /*@observer@*/ /*@null@*/ yasm_symrec *
+ (*get_special_sym)(yasm_object *object, const char *name,
+ const char *parser);
+};
+
+/** Create object format.
+ * \param module object format module
+ * \param object object
+ * \return NULL if architecture/machine combination not supported.
+ */
+/*@null@*/ /*@only@*/ yasm_objfmt *yasm_objfmt_create
+ (const yasm_objfmt_module *module, yasm_object *object);
+
+/** Write out (post-optimized) sections to the object file.
+ * This function may call yasm_symrec_* functions as necessary (including
+ * yasm_symrec_traverse()) to retrieve symbolic information.
+ * \param object object
+ * \param f output object file
+ * \param all_syms if nonzero, all symbols should be included in
+ * the object file
+ * \param errwarns error/warning set
+ * \note Errors and warnings are stored into errwarns.
+ */
+void yasm_objfmt_output(yasm_object *object, FILE *f, int all_syms,
+ yasm_errwarns *errwarns);
+
+/** Cleans up any allocated object format memory.
+ * \param objfmt object format
+ */
+void yasm_objfmt_destroy(/*@only@*/ yasm_objfmt *objfmt);
+
+/** Add a default section to an object.
+ * \param object object
+ * \return Default section.
+ */
+yasm_section *yasm_objfmt_add_default_section(yasm_object *object);
+
+/** Initialize the object-format specific portion of a section. Called
+ * by yasm_object_get_general(); in general should not be directly called.
+ * \param section section
+ * \param line virtual line (from yasm_linemap)
+ */
+void yasm_objfmt_init_new_section(yasm_object *object, unsigned long line);
+
+/** Switch object file sections. The first val of the valparams should
+ * be the section name. Calls yasm_object_get_general() to actually get
+ * the section.
+ * \param object object
+ * \param valparams value/parameters
+ * \param objext_valparams object format-specific value/parameters
+ * \param line virtual line (from yasm_linemap)
+ * \return NULL on error, otherwise new section.
+ */
+/*@observer@*/ /*@null@*/ yasm_section *yasm_objfmt_section_switch
+ (yasm_object *object, yasm_valparamhead *valparams,
+ /*@null@*/ yasm_valparamhead *objext_valparams, unsigned long line);
+
+/** Get a special symbol. Special symbols are generally used to generate
+ * special relocation types via the WRT mechanism.
+ * \param object object
+ * \param name symbol name (not including any parser-specific prefix)
+ * \param parser parser keyword
+ * \return NULL if unrecognized, otherwise special symbol.
+ */
+/*@observer@*/ /*@null@*/ yasm_symrec *yasm_objfmt_get_special_sym
+ (yasm_object *object, const char *name, const char *parser);
+
+#ifndef YASM_DOXYGEN
+
+/* Inline macro implementations for objfmt functions */
+
+#define yasm_objfmt_create(module, object) module->create(object)
+
+#define yasm_objfmt_output(object, f, all_syms, ews) \
+ ((yasm_objfmt_base *)((object)->objfmt))->module->output \
+ (object, f, all_syms, ews)
+#define yasm_objfmt_destroy(objfmt) \
+ ((yasm_objfmt_base *)objfmt)->module->destroy(objfmt)
+#define yasm_objfmt_section_switch(object, vpms, oe_vpms, line) \
+ ((yasm_objfmt_base *)((object)->objfmt))->module->section_switch \
+ (object, vpms, oe_vpms, line)
+#define yasm_objfmt_add_default_section(object) \
+ ((yasm_objfmt_base *)((object)->objfmt))->module->add_default_section \
+ (object)
+#define yasm_objfmt_init_new_section(section, line) \
+ ((yasm_objfmt_base *)((object)->objfmt))->module->init_new_section \
+ (section, line)
+#define yasm_objfmt_get_special_sym(object, name, parser) \
+ ((yasm_objfmt_base *)((object)->objfmt))->module->get_special_sym \
+ (object, name, parser)
+
+#endif
+
+#endif
diff --git a/libyasm/parser.h b/libyasm/parser.h
new file mode 100644
index 0000000..93d4d33
--- /dev/null
+++ b/libyasm/parser.h
@@ -0,0 +1,67 @@
+/**
+ * \file libyasm/parser.h
+ * \brief YASM parser module interface.
+ *
+ * \license
+ * Copyright (C) 2001-2007 Peter Johnson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * \endlicense
+ */
+#ifndef YASM_PARSER_H
+#define YASM_PARSER_H
+
+/** YASM parser module interface. The "front end" of the assembler. */
+typedef struct yasm_parser_module {
+ /** One-line description of the parser */
+ const char *name;
+
+ /** Keyword used to select parser on the command line */
+ const char *keyword;
+
+ /** NULL-terminated list of preprocessors that are valid to use with this
+ * parser. The raw preprocessor (raw_preproc) should always be in this
+ * list so it's always possible to have no preprocessing done.
+ */
+ const char **preproc_keywords;
+
+ /** Default preprocessor. */
+ const char *default_preproc_keyword;
+
+ /** NULL-terminated list of standard macro lookups. NULL if none. */
+ const yasm_stdmac *stdmacs;
+
+ /** Parse a source file into an object.
+ * \param object object to parse into (already created)
+ * \param pp preprocessor
+ * \param save_input nonzero if the parser should save the original
+ * lines of source into the object's linemap (via
+ * yasm_linemap_add_data()).
+ * \param errwarns error/warning set
+ * \note Parse errors and warnings are stored into errwarns.
+ */
+ void (*do_parse)
+ (yasm_object *object, yasm_preproc *pp, int save_input,
+ yasm_linemap *linemap, yasm_errwarns *errwarns);
+} yasm_parser_module;
+
+#endif
diff --git a/libyasm/phash.c b/libyasm/phash.c
new file mode 100644
index 0000000..cef8c78
--- /dev/null
+++ b/libyasm/phash.c
@@ -0,0 +1,268 @@
+/* Modified for use with yasm by Peter Johnson. */
+#include "util.h"
+
+/*
+--------------------------------------------------------------------
+lookupa.c, by Bob Jenkins, December 1996. Same as lookup2.c
+Use this code however you wish. Public Domain. No warranty.
+Source is http://burtleburtle.net/bob/c/lookupa.c
+--------------------------------------------------------------------
+*/
+#include "phash.h"
+
+#define ub4 unsigned long
+
+#define hashsize(n) ((ub4)1<<(n))
+#define hashmask(n) (hashsize(n)-1)
+
+/*
+--------------------------------------------------------------------
+mix -- mix 3 32-bit values reversibly.
+For every delta with one or two bit set, and the deltas of all three
+ high bits or all three low bits, whether the original value of a,b,c
+ is almost all zero or is uniformly distributed,
+* If mix() is run forward or backward, at least 32 bits in a,b,c
+ have at least 1/4 probability of changing.
+* If mix() is run forward, every bit of c will change between 1/3 and
+ 2/3 of the time. (Well, 22/100 and 78/100 for some 2-bit deltas.)
+mix() was built out of 36 single-cycle latency instructions in a
+ structure that could supported 2x parallelism, like so:
+ a -= b;
+ a -= c; x = (c>>13);
+ b -= c; a ^= x;
+ b -= a; x = (a<<8);
+ c -= a; b ^= x;
+ c -= b; x = (b>>13);
+ ...
+ Unfortunately, superscalar Pentiums and Sparcs can't take advantage
+ of that parallelism. They've also turned some of those single-cycle
+ latency instructions into multi-cycle latency instructions. Still,
+ this is the fastest good hash I could find. There were about 2^^68
+ to choose from. I only looked at a billion or so.
+--------------------------------------------------------------------
+*/
+#define mix(a,b,c) \
+{ \
+ a -= b; a -= c; a ^= (c>>13); \
+ a &= 0xffffffff; \
+ b -= c; b -= a; b ^= (a<<8); \
+ b &= 0xffffffff; \
+ c -= a; c -= b; c ^= (b>>13); \
+ c &= 0xffffffff; \
+ a -= b; a -= c; a ^= (c>>12); \
+ a &= 0xffffffff; \
+ b -= c; b -= a; b ^= (a<<16); \
+ b &= 0xffffffff; \
+ c -= a; c -= b; c ^= (b>>5); \
+ c &= 0xffffffff; \
+ a -= b; a -= c; a ^= (c>>3); \
+ a &= 0xffffffff; \
+ b -= c; b -= a; b ^= (a<<10); \
+ b &= 0xffffffff; \
+ c -= a; c -= b; c ^= (b>>15); \
+ c &= 0xffffffff; \
+}
+
+/*
+--------------------------------------------------------------------
+lookup() -- hash a variable-length key into a 32-bit value
+ k : the key (the unaligned variable-length array of bytes)
+ len : the length of the key, counting by bytes
+ level : can be any 4-byte value
+Returns a 32-bit value. Every bit of the key affects every bit of
+the return value. Every 1-bit and 2-bit delta achieves avalanche.
+About 6len+35 instructions.
+
+The best hash table sizes are powers of 2. There is no need to do
+mod a prime (mod is sooo slow!). If you need less than 32 bits,
+use a bitmask. For example, if you need only 10 bits, do
+ h = (h & hashmask(10));
+In which case, the hash table should have hashsize(10) elements.
+
+If you are hashing n strings (ub1 **)k, do it like this:
+ for (i=0, h=0; i<n; ++i) h = lookup( k[i], len[i], h);
+
+By Bob Jenkins, 1996. bob_jenkins@burtleburtle.net. You may use this
+code any way you wish, private, educational, or commercial.
+
+See http://burtleburtle.net/bob/hash/evahash.html
+Use for hash table lookup, or anything where one collision in 2^32 is
+acceptable. Do NOT use for cryptographic purposes.
+--------------------------------------------------------------------
+*/
+
+unsigned long
+phash_lookup(
+ register const char *sk, /* the key */
+ register size_t length, /* the length of the key */
+ register unsigned long level) /* the previous hash, or an arbitrary value */
+{
+ register unsigned long a,b,c;
+ register size_t len;
+ register const unsigned char *k = (const unsigned char *)sk;
+
+ /* Set up the internal state */
+ len = length;
+ a = b = 0x9e3779b9; /* the golden ratio; an arbitrary value */
+ c = level; /* the previous hash value */
+
+ /*---------------------------------------- handle most of the key */
+ while (len >= 12)
+ {
+ a += (k[0] +((ub4)k[1]<<8) +((ub4)k[2]<<16) +((ub4)k[3]<<24));
+ a &= 0xffffffff;
+ b += (k[4] +((ub4)k[5]<<8) +((ub4)k[6]<<16) +((ub4)k[7]<<24));
+ b &= 0xffffffff;
+ c += (k[8] +((ub4)k[9]<<8) +((ub4)k[10]<<16)+((ub4)k[11]<<24));
+ c &= 0xffffffff;
+ mix(a,b,c);
+ k += 12; len -= 12;
+ }
+
+ /*------------------------------------- handle the last 11 bytes */
+ c += (ub4)length;
+ switch(len) /* all the case statements fall through */
+ {
+ case 11: c+=((ub4)k[10]<<24);
+ case 10: c+=((ub4)k[9]<<16);
+ case 9 : c+=((ub4)k[8]<<8);
+ c &= 0xffffffff;
+ /* the first byte of c is reserved for the length */
+ case 8 : b+=((ub4)k[7]<<24);
+ case 7 : b+=((ub4)k[6]<<16);
+ case 6 : b+=((ub4)k[5]<<8);
+ case 5 : b+=k[4];
+ b &= 0xffffffff;
+ case 4 : a+=((ub4)k[3]<<24);
+ case 3 : a+=((ub4)k[2]<<16);
+ case 2 : a+=((ub4)k[1]<<8);
+ case 1 : a+=k[0];
+ a &= 0xffffffff;
+ /* case 0: nothing left to add */
+ }
+ mix(a,b,c);
+ /*-------------------------------------------- report the result */
+ return c;
+}
+
+
+/*
+--------------------------------------------------------------------
+mixc -- mixc 8 4-bit values as quickly and thoroughly as possible.
+Repeating mix() three times achieves avalanche.
+Repeating mix() four times eliminates all funnels and all
+ characteristics stronger than 2^{-11}.
+--------------------------------------------------------------------
+*/
+#define mixc(a,b,c,d,e,f,g,h) \
+{ \
+ a^=b<<11; d+=a; b+=c; \
+ b^=c>>2; e+=b; c+=d; \
+ c^=d<<8; f+=c; d+=e; \
+ d^=e>>16; g+=d; e+=f; \
+ e^=f<<10; h+=e; f+=g; \
+ f^=g>>4; a+=f; g+=h; \
+ g^=h<<8; b+=g; h+=a; \
+ h^=a>>9; c+=h; a+=b; \
+}
+
+/*
+--------------------------------------------------------------------
+checksum() -- hash a variable-length key into a 256-bit value
+ k : the key (the unaligned variable-length array of bytes)
+ len : the length of the key, counting by bytes
+ state : an array of CHECKSTATE 4-byte values (256 bits)
+The state is the checksum. Every bit of the key affects every bit of
+the state. There are no funnels. About 112+6.875len instructions.
+
+If you are hashing n strings (ub1 **)k, do it like this:
+ for (i=0; i<8; ++i) state[i] = 0x9e3779b9;
+ for (i=0, h=0; i<n; ++i) checksum( k[i], len[i], state);
+
+(c) Bob Jenkins, 1996. bob_jenkins@burtleburtle.net. You may use this
+code any way you wish, private, educational, or commercial, as long
+as this whole comment accompanies it.
+
+See http://burtleburtle.net/bob/hash/evahash.html
+Use to detect changes between revisions of documents, assuming nobody
+is trying to cause collisions. Do NOT use for cryptography.
+--------------------------------------------------------------------
+*/
+void
+phash_checksum(
+ register const char *sk,
+ register size_t len,
+ register unsigned long *state)
+{
+ register unsigned long a,b,c,d,e,f,g,h;
+ register size_t length;
+ register const unsigned char *k = (const unsigned char *)sk;
+
+ /* Use the length and level; add in the golden ratio. */
+ length = len;
+ a=state[0]; b=state[1]; c=state[2]; d=state[3];
+ e=state[4]; f=state[5]; g=state[6]; h=state[7];
+
+ /*---------------------------------------- handle most of the key */
+ while (len >= 32)
+ {
+ a += (k[0] +(k[1]<<8) +(k[2]<<16) +(k[3]<<24));
+ b += (k[4] +(k[5]<<8) +(k[6]<<16) +(k[7]<<24));
+ c += (k[8] +(k[9]<<8) +(k[10]<<16)+(k[11]<<24));
+ d += (k[12]+(k[13]<<8)+(k[14]<<16)+(k[15]<<24));
+ e += (k[16]+(k[17]<<8)+(k[18]<<16)+(k[19]<<24));
+ f += (k[20]+(k[21]<<8)+(k[22]<<16)+(k[23]<<24));
+ g += (k[24]+(k[25]<<8)+(k[26]<<16)+(k[27]<<24));
+ h += (k[28]+(k[29]<<8)+(k[30]<<16)+(k[31]<<24));
+ mixc(a,b,c,d,e,f,g,h);
+ mixc(a,b,c,d,e,f,g,h);
+ mixc(a,b,c,d,e,f,g,h);
+ mixc(a,b,c,d,e,f,g,h);
+ k += 32; len -= 32;
+ }
+
+ /*------------------------------------- handle the last 31 bytes */
+ h += (ub4)length;
+ switch(len)
+ {
+ case 31: h+=(k[30]<<24);
+ case 30: h+=(k[29]<<16);
+ case 29: h+=(k[28]<<8);
+ case 28: g+=(k[27]<<24);
+ case 27: g+=(k[26]<<16);
+ case 26: g+=(k[25]<<8);
+ case 25: g+=k[24];
+ case 24: f+=(k[23]<<24);
+ case 23: f+=(k[22]<<16);
+ case 22: f+=(k[21]<<8);
+ case 21: f+=k[20];
+ case 20: e+=(k[19]<<24);
+ case 19: e+=(k[18]<<16);
+ case 18: e+=(k[17]<<8);
+ case 17: e+=k[16];
+ case 16: d+=(k[15]<<24);
+ case 15: d+=(k[14]<<16);
+ case 14: d+=(k[13]<<8);
+ case 13: d+=k[12];
+ case 12: c+=(k[11]<<24);
+ case 11: c+=(k[10]<<16);
+ case 10: c+=(k[9]<<8);
+ case 9 : c+=k[8];
+ case 8 : b+=(k[7]<<24);
+ case 7 : b+=(k[6]<<16);
+ case 6 : b+=(k[5]<<8);
+ case 5 : b+=k[4];
+ case 4 : a+=(k[3]<<24);
+ case 3 : a+=(k[2]<<16);
+ case 2 : a+=(k[1]<<8);
+ case 1 : a+=k[0];
+ }
+ mixc(a,b,c,d,e,f,g,h);
+ mixc(a,b,c,d,e,f,g,h);
+ mixc(a,b,c,d,e,f,g,h);
+ mixc(a,b,c,d,e,f,g,h);
+
+ /*-------------------------------------------- report the result */
+ state[0]=a; state[1]=b; state[2]=c; state[3]=d;
+ state[4]=e; state[5]=f; state[6]=g; state[7]=h;
+}
diff --git a/libyasm/phash.h b/libyasm/phash.h
new file mode 100644
index 0000000..2273a5d
--- /dev/null
+++ b/libyasm/phash.h
@@ -0,0 +1,19 @@
+/* Modified for use with yasm by Peter Johnson. */
+/*
+------------------------------------------------------------------------------
+By Bob Jenkins, September 1996.
+lookupa.h, a hash function for table lookup, same function as lookup.c.
+Use this code in any way you wish. Public Domain. It has no warranty.
+Source is http://burtleburtle.net/bob/c/lookupa.h
+------------------------------------------------------------------------------
+*/
+
+#ifndef YASM_LIB_DECL
+#define YASM_LIB_DECL
+#endif
+
+YASM_LIB_DECL
+unsigned long phash_lookup(const char *k, size_t length,
+ unsigned long level);
+YASM_LIB_DECL
+void phash_checksum(const char *k, size_t length, unsigned long *state);
diff --git a/libyasm/preproc.h b/libyasm/preproc.h
new file mode 100644
index 0000000..751b19e
--- /dev/null
+++ b/libyasm/preproc.h
@@ -0,0 +1,210 @@
+/**
+ * \file libyasm/preproc.h
+ * \brief YASM preprocessor module interface.
+ *
+ * \license
+ * Copyright (C) 2001-2007 Peter Johnson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * \endlicense
+ */
+#ifndef YASM_PREPROC_H
+#define YASM_PREPROC_H
+
+#ifndef YASM_DOXYGEN
+/** Base #yasm_preproc structure. Must be present as the first element in any
+ * #yasm_preproc implementation.
+ */
+typedef struct yasm_preproc_base {
+ /** #yasm_preproc_module implementation for this preprocessor. */
+ const struct yasm_preproc_module *module;
+} yasm_preproc_base;
+#endif
+
+/** YASM preprocesor module interface. */
+typedef struct yasm_preproc_module {
+ /** One-line description of the preprocessor. */
+ const char *name;
+
+ /** Keyword used to select preprocessor on the command line. */
+ const char *keyword;
+
+ /** Create preprocessor.
+ * Module-level implementation of yasm_preproc_create().
+ * Call yasm_preproc_create() instead of calling this function.
+ *
+ * \param in_filename initial starting filename, or "-" to read from
+ * stdin
+ * \param symtab symbol table (may be NULL if none)
+ * \param lm line mapping repository
+ * \param errwarns error/warnning set.
+ * \return New preprocessor.
+ *
+ * \note Any preprocessor errors and warnings are stored into errwarns.
+ */
+ /*@only@*/ yasm_preproc * (*create) (const char *in_filename,
+ yasm_symtab *symtab,
+ yasm_linemap *lm,
+ yasm_errwarns *errwarns);
+
+ /** Module-level implementation of yasm_preproc_destroy().
+ * Call yasm_preproc_destroy() instead of calling this function.
+ */
+ void (*destroy) (/*@only@*/ yasm_preproc *preproc);
+
+ /** Module-level implementation of yasm_preproc_get_line().
+ * Call yasm_preproc_get_line() instead of calling this function.
+ */
+ char * (*get_line) (yasm_preproc *preproc);
+
+ /** Module-level implementation of yasm_preproc_get_included_file().
+ * Call yasm_preproc_get_included_file() instead of calling this function.
+ */
+ size_t (*get_included_file) (yasm_preproc *preproc, /*@out@*/ char *buf,
+ size_t max_size);
+
+ /** Module-level implementation of yasm_preproc_add_include_file().
+ * Call yasm_preproc_add_include_file() instead of calling this function.
+ */
+ void (*add_include_file) (yasm_preproc *preproc, const char *filename);
+
+ /** Module-level implementation of yasm_preproc_predefine_macro().
+ * Call yasm_preproc_predefine_macro() instead of calling this function.
+ */
+ void (*predefine_macro) (yasm_preproc *preproc, const char *macronameval);
+
+ /** Module-level implementation of yasm_preproc_undefine_macro().
+ * Call yasm_preproc_undefine_macro() instead of calling this function.
+ */
+ void (*undefine_macro) (yasm_preproc *preproc, const char *macroname);
+
+ /** Module-level implementation of yasm_preproc_builtin_define().
+ * Call yasm_preproc_builtin_define() instead of calling this function.
+ */
+ void (*define_builtin) (yasm_preproc *preproc, const char *macronameval);
+
+ /** Module-level implementation of yasm_preproc_add_standard().
+ * Call yasm_preproc_add_standard() instead of calling this function.
+ */
+ void (*add_standard) (yasm_preproc *preproc, const char **macros);
+} yasm_preproc_module;
+
+/** Initialize preprocessor.
+ * The preprocessor needs access to the object format module to find out
+ * any output format specific macros.
+ * \param module preprocessor module
+ * \param in_filename initial starting filename, or "-" to read from stdin
+ * \param symtab symbol table (may be NULL if none)
+ * \param lm line mapping repository
+ * \param errwarns error/warning set
+ * \return New preprocessor.
+ * \note Errors/warnings are stored into errwarns.
+ */
+/*@only@*/ yasm_preproc *yasm_preproc_create
+ (yasm_preproc_module *module, const char *in_filename,
+ yasm_symtab *symtab, yasm_linemap *lm, yasm_errwarns *errwarns);
+
+/** Cleans up any allocated preproc memory.
+ * \param preproc preprocessor
+ */
+void yasm_preproc_destroy(/*@only@*/ yasm_preproc *preproc);
+
+/** Gets a single line of preprocessed source code.
+ * \param preproc preprocessor
+ * \return Allocated line of code, without the trailing \n.
+ */
+char *yasm_preproc_get_line(yasm_preproc *preproc);
+
+/** Get the next filename included by the source code.
+ * \param preproc preprocessor
+ * \param buf destination buffer for filename
+ * \param max_size maximum number of bytes that can be returned in buf
+ * \return Actual number of bytes returned in buf.
+ */
+size_t yasm_preproc_get_included_file(yasm_preproc *preproc,
+ /*@out@*/ char *buf, size_t max_size);
+
+/** Pre-include a file.
+ * \param preproc preprocessor
+ * \param filename filename
+ */
+void yasm_preproc_add_include_file(yasm_preproc *preproc,
+ const char *filename);
+
+/** Pre-define a macro.
+ * \param preproc preprocessor
+ * \param macronameval "name=value" string
+ */
+void yasm_preproc_predefine_macro(yasm_preproc *preproc,
+ const char *macronameval);
+
+/** Un-define a macro.
+ * \param preproc preprocessor
+ * \param macroname macro name
+ */
+void yasm_preproc_undefine_macro(yasm_preproc *preproc, const char *macroname);
+
+/** Define a builtin macro, preprocessed before the "standard" macros.
+ * \param preproc preprocessor
+ * \param macronameval "name=value" string
+ */
+void yasm_preproc_define_builtin(yasm_preproc *preproc,
+ const char *macronameval);
+
+/** Define additional standard macros, preprocessed after the builtins but
+ * prior to any user-defined macros.
+ * \param preproc preprocessor
+ * \param macros NULL-terminated array of macro strings
+ */
+void yasm_preproc_add_standard(yasm_preproc *preproc,
+ const char **macros);
+
+#ifndef YASM_DOXYGEN
+
+/* Inline macro implementations for preproc functions */
+
+#define yasm_preproc_create(module, in_filename, symtab, lm, ews) \
+ module->create(in_filename, symtab, lm, ews)
+
+#define yasm_preproc_destroy(preproc) \
+ ((yasm_preproc_base *)preproc)->module->destroy(preproc)
+#define yasm_preproc_get_line(preproc) \
+ ((yasm_preproc_base *)preproc)->module->get_line(preproc)
+#define yasm_preproc_get_included_file(preproc, buf, max_size) \
+ ((yasm_preproc_base *)preproc)->module->get_included_file(preproc, buf, max_size)
+#define yasm_preproc_add_include_file(preproc, filename) \
+ ((yasm_preproc_base *)preproc)->module->add_include_file(preproc, filename)
+#define yasm_preproc_predefine_macro(preproc, macronameval) \
+ ((yasm_preproc_base *)preproc)->module->predefine_macro(preproc, \
+ macronameval)
+#define yasm_preproc_undefine_macro(preproc, macroname) \
+ ((yasm_preproc_base *)preproc)->module->undefine_macro(preproc, macroname)
+#define yasm_preproc_define_builtin(preproc, macronameval) \
+ ((yasm_preproc_base *)preproc)->module->define_builtin(preproc, \
+ macronameval)
+#define yasm_preproc_add_standard(preproc, macros) \
+ ((yasm_preproc_base *)preproc)->module->add_standard(preproc, \
+ macros)
+
+#endif
+
+#endif
diff --git a/libyasm/section.c b/libyasm/section.c
new file mode 100644
index 0000000..9242fb0
--- /dev/null
+++ b/libyasm/section.c
@@ -0,0 +1,1580 @@
+/*
+ * Section utility functions
+ *
+ * Copyright (C) 2001-2007 Peter Johnson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "util.h"
+
+#include <limits.h>
+
+#include "libyasm-stdint.h"
+#include "coretype.h"
+#include "hamt.h"
+#include "valparam.h"
+#include "assocdat.h"
+
+#include "linemap.h"
+#include "errwarn.h"
+#include "intnum.h"
+#include "expr.h"
+#include "value.h"
+#include "symrec.h"
+
+#include "bytecode.h"
+#include "arch.h"
+#include "section.h"
+
+#include "dbgfmt.h"
+#include "objfmt.h"
+
+#include "inttree.h"
+
+
+struct yasm_section {
+ /*@reldef@*/ STAILQ_ENTRY(yasm_section) link;
+
+ /*@dependent@*/ yasm_object *object; /* Pointer to parent object */
+
+ /*@owned@*/ char *name; /* strdup()'ed name (given by user) */
+
+ /* associated data; NULL if none */
+ /*@null@*/ /*@only@*/ yasm__assoc_data *assoc_data;
+
+ unsigned long align; /* Section alignment */
+
+ unsigned long opt_flags; /* storage for optimizer flags */
+
+ int code; /* section contains code (instructions) */
+ int res_only; /* allow only resb family of bytecodes? */
+ int def; /* "default" section, e.g. not specified by
+ using section directive */
+
+ /* the bytecodes for the section's contents */
+ /*@reldef@*/ STAILQ_HEAD(yasm_bytecodehead, yasm_bytecode) bcs;
+
+ /* the relocations for the section */
+ /*@reldef@*/ STAILQ_HEAD(yasm_relochead, yasm_reloc) relocs;
+
+ void (*destroy_reloc) (/*@only@*/ void *reloc);
+};
+
+static void yasm_section_destroy(/*@only@*/ yasm_section *sect);
+
+/* Wrapper around directive for HAMT insertion */
+typedef struct yasm_directive_wrap {
+ const yasm_directive *directive;
+} yasm_directive_wrap;
+
+/*
+ * Standard "builtin" object directives.
+ */
+
+static void
+dir_extern(yasm_object *object, yasm_valparamhead *valparams,
+ yasm_valparamhead *objext_valparams, unsigned long line)
+{
+ yasm_valparam *vp = yasm_vps_first(valparams);
+ yasm_symrec *sym;
+ sym = yasm_symtab_declare(object->symtab, yasm_vp_id(vp), YASM_SYM_EXTERN,
+ line);
+ if (objext_valparams) {
+ yasm_valparamhead *vps = yasm_vps_create();
+ *vps = *objext_valparams; /* structure copy */
+ yasm_vps_initialize(objext_valparams); /* don't double-free */
+ yasm_symrec_set_objext_valparams(sym, vps);
+ }
+}
+
+static void
+dir_global(yasm_object *object, yasm_valparamhead *valparams,
+ yasm_valparamhead *objext_valparams, unsigned long line)
+{
+ yasm_valparam *vp = yasm_vps_first(valparams);
+ yasm_symrec *sym;
+ sym = yasm_symtab_declare(object->symtab, yasm_vp_id(vp), YASM_SYM_GLOBAL,
+ line);
+ if (objext_valparams) {
+ yasm_valparamhead *vps = yasm_vps_create();
+ *vps = *objext_valparams; /* structure copy */
+ yasm_vps_initialize(objext_valparams); /* don't double-free */
+ yasm_symrec_set_objext_valparams(sym, vps);
+ }
+}
+
+static void
+dir_common(yasm_object *object, yasm_valparamhead *valparams,
+ yasm_valparamhead *objext_valparams, unsigned long line)
+{
+ yasm_valparam *vp = yasm_vps_first(valparams);
+ yasm_valparam *vp2 = yasm_vps_next(vp);
+ yasm_expr *size = yasm_vp_expr(vp2, object->symtab, line);
+ yasm_symrec *sym;
+
+ if (!size) {
+ yasm_error_set(YASM_ERROR_SYNTAX,
+ N_("no size specified in %s declaration"), "COMMON");
+ return;
+ }
+ sym = yasm_symtab_declare(object->symtab, yasm_vp_id(vp), YASM_SYM_COMMON,
+ line);
+ yasm_symrec_set_common_size(sym, size);
+ if (objext_valparams) {
+ yasm_valparamhead *vps = yasm_vps_create();
+ *vps = *objext_valparams; /* structure copy */
+ yasm_vps_initialize(objext_valparams); /* don't double-free */
+ yasm_symrec_set_objext_valparams(sym, vps);
+ }
+}
+
+static void
+dir_section(yasm_object *object, yasm_valparamhead *valparams,
+ yasm_valparamhead *objext_valparams, unsigned long line)
+{
+ yasm_section *new_section =
+ yasm_objfmt_section_switch(object, valparams, objext_valparams, line);
+ if (new_section)
+ object->cur_section = new_section;
+ else
+ yasm_error_set(YASM_ERROR_SYNTAX,
+ N_("invalid argument to directive `%s'"), "SECTION");
+}
+
+static const yasm_directive object_directives[] = {
+ { ".extern", "gas", dir_extern, YASM_DIR_ID_REQUIRED },
+ { ".global", "gas", dir_global, YASM_DIR_ID_REQUIRED },
+ { ".globl", "gas", dir_global, YASM_DIR_ID_REQUIRED },
+ { "extern", "nasm", dir_extern, YASM_DIR_ID_REQUIRED },
+ { "global", "nasm", dir_global, YASM_DIR_ID_REQUIRED },
+ { "common", "nasm", dir_common, YASM_DIR_ID_REQUIRED },
+ { "section", "nasm", dir_section, YASM_DIR_ARG_REQUIRED },
+ { "segment", "nasm", dir_section, YASM_DIR_ARG_REQUIRED },
+ { NULL, NULL, NULL, 0 }
+};
+
+static void
+directive_level2_delete(/*@only@*/ void *data)
+{
+ yasm_xfree(data);
+}
+
+static void
+directive_level1_delete(/*@only@*/ void *data)
+{
+ HAMT_destroy(data, directive_level2_delete);
+}
+
+static void
+directives_add(yasm_object *object, /*@null@*/ const yasm_directive *dir)
+{
+ if (!dir)
+ return;
+
+ while (dir->name) {
+ HAMT *level2 = HAMT_search(object->directives, dir->parser);
+ int replace;
+ yasm_directive_wrap *wrap = yasm_xmalloc(sizeof(yasm_directive_wrap));
+
+ if (!level2) {
+ replace = 0;
+ level2 = HAMT_insert(object->directives, dir->parser,
+ HAMT_create(1, yasm_internal_error_),
+ &replace, directive_level1_delete);
+ }
+ replace = 0;
+ wrap->directive = dir;
+ HAMT_insert(level2, dir->name, wrap, &replace,
+ directive_level2_delete);
+ dir++;
+ }
+}
+
+/*@-compdestroy@*/
+yasm_object *
+yasm_object_create(const char *src_filename, const char *obj_filename,
+ /*@kept@*/ yasm_arch *arch,
+ const yasm_objfmt_module *objfmt_module,
+ const yasm_dbgfmt_module *dbgfmt_module)
+{
+ yasm_object *object = yasm_xmalloc(sizeof(yasm_object));
+ int matched, i;
+
+ object->src_filename = yasm__xstrdup(src_filename);
+ object->obj_filename = yasm__xstrdup(obj_filename);
+
+ /* No prefix/suffix */
+ object->global_prefix = yasm__xstrdup("");
+ object->global_suffix = yasm__xstrdup("");
+
+ /* Create empty symbol table */
+ object->symtab = yasm_symtab_create();
+
+ /* Initialize sections linked list */
+ STAILQ_INIT(&object->sections);
+
+ /* Create directives HAMT */
+ object->directives = HAMT_create(1, yasm_internal_error_);
+
+ /* Initialize the target architecture */
+ object->arch = arch;
+
+ /* Initialize things to NULL in case of error */
+ object->dbgfmt = NULL;
+
+ /* Initialize the object format */
+ object->objfmt = yasm_objfmt_create(objfmt_module, object);
+ if (!object->objfmt) {
+ yasm_error_set(YASM_ERROR_GENERAL,
+ N_("object format `%s' does not support architecture `%s' machine `%s'"),
+ objfmt_module->keyword, ((yasm_arch_base *)arch)->module->keyword,
+ yasm_arch_get_machine(arch));
+ goto error;
+ }
+
+ /* Get a fresh copy of objfmt_module as it may have changed. */
+ objfmt_module = ((yasm_objfmt_base *)object->objfmt)->module;
+
+ /* Add an initial "default" section to object */
+ object->cur_section = yasm_objfmt_add_default_section(object);
+
+ /* Check to see if the requested debug format is in the allowed list
+ * for the active object format.
+ */
+ matched = 0;
+ for (i=0; objfmt_module->dbgfmt_keywords[i]; i++)
+ if (yasm__strcasecmp(objfmt_module->dbgfmt_keywords[i],
+ dbgfmt_module->keyword) == 0)
+ matched = 1;
+ if (!matched) {
+ yasm_error_set(YASM_ERROR_GENERAL,
+ N_("`%s' is not a valid debug format for object format `%s'"),
+ dbgfmt_module->keyword, objfmt_module->keyword);
+ goto error;
+ }
+
+ /* Initialize the debug format */
+ object->dbgfmt = yasm_dbgfmt_create(dbgfmt_module, object);
+ if (!object->dbgfmt) {
+ yasm_error_set(YASM_ERROR_GENERAL,
+ N_("debug format `%s' does not work with object format `%s'"),
+ dbgfmt_module->keyword, objfmt_module->keyword);
+ goto error;
+ }
+
+ /* Add directives to HAMT. Note ordering here determines priority. */
+ directives_add(object,
+ ((yasm_objfmt_base *)object->objfmt)->module->directives);
+ directives_add(object,
+ ((yasm_dbgfmt_base *)object->dbgfmt)->module->directives);
+ directives_add(object,
+ ((yasm_arch_base *)object->arch)->module->directives);
+ directives_add(object, object_directives);
+
+ return object;
+
+error:
+ yasm_object_destroy(object);
+ return NULL;
+}
+/*@=compdestroy@*/
+
+/*@-onlytrans@*/
+yasm_section *
+yasm_object_get_general(yasm_object *object, const char *name,
+ unsigned long align, int code, int res_only,
+ int *isnew, unsigned long line)
+{
+ yasm_section *s;
+ yasm_bytecode *bc;
+
+ /* Search through current sections to see if we already have one with
+ * that name.
+ */
+ STAILQ_FOREACH(s, &object->sections, link) {
+ if (strcmp(s->name, name) == 0) {
+ *isnew = 0;
+ return s;
+ }
+ }
+
+ /* No: we have to allocate and create a new one. */
+
+ /* Okay, the name is valid; now allocate and initialize */
+ s = yasm_xcalloc(1, sizeof(yasm_section));
+ STAILQ_INSERT_TAIL(&object->sections, s, link);
+
+ s->object = object;
+ s->name = yasm__xstrdup(name);
+ s->assoc_data = NULL;
+ s->align = align;
+
+ /* Initialize bytecodes with one empty bytecode (acts as "prior" for first
+ * real bytecode in section.
+ */
+ STAILQ_INIT(&s->bcs);
+ bc = yasm_bc_create_common(NULL, NULL, 0);
+ bc->section = s;
+ bc->offset = 0;
+ STAILQ_INSERT_TAIL(&s->bcs, bc, link);
+
+ /* Initialize relocs */
+ STAILQ_INIT(&s->relocs);
+ s->destroy_reloc = NULL;
+
+ s->code = code;
+ s->res_only = res_only;
+ s->def = 0;
+
+ /* Initialize object format specific data */
+ yasm_objfmt_init_new_section(s, line);
+
+ *isnew = 1;
+ return s;
+}
+/*@=onlytrans@*/
+
+int
+yasm_object_directive(yasm_object *object, const char *name,
+ const char *parser, yasm_valparamhead *valparams,
+ yasm_valparamhead *objext_valparams,
+ unsigned long line)
+{
+ HAMT *level2;
+ yasm_directive_wrap *wrap;
+
+ level2 = HAMT_search(object->directives, parser);
+ if (!level2)
+ return 1;
+
+ wrap = HAMT_search(level2, name);
+ if (!wrap)
+ return 1;
+
+ yasm_call_directive(wrap->directive, object, valparams, objext_valparams,
+ line);
+ return 0;
+}
+
+void
+yasm_object_set_source_fn(yasm_object *object, const char *src_filename)
+{
+ yasm_xfree(object->src_filename);
+ object->src_filename = yasm__xstrdup(src_filename);
+}
+
+void
+yasm_object_set_global_prefix(yasm_object *object, const char *prefix)
+{
+ yasm_xfree(object->global_prefix);
+ object->global_prefix = yasm__xstrdup(prefix);
+}
+
+void
+yasm_object_set_global_suffix(yasm_object *object, const char *suffix)
+{
+ yasm_xfree(object->global_suffix);
+ object->global_suffix = yasm__xstrdup(suffix);
+}
+
+int
+yasm_section_is_code(yasm_section *sect)
+{
+ return sect->code;
+}
+
+unsigned long
+yasm_section_get_opt_flags(const yasm_section *sect)
+{
+ return sect->opt_flags;
+}
+
+void
+yasm_section_set_opt_flags(yasm_section *sect, unsigned long opt_flags)
+{
+ sect->opt_flags = opt_flags;
+}
+
+int
+yasm_section_is_default(const yasm_section *sect)
+{
+ return sect->def;
+}
+
+void
+yasm_section_set_default(yasm_section *sect, int def)
+{
+ sect->def = def;
+}
+
+yasm_object *
+yasm_section_get_object(const yasm_section *sect)
+{
+ return sect->object;
+}
+
+void *
+yasm_section_get_data(yasm_section *sect,
+ const yasm_assoc_data_callback *callback)
+{
+ return yasm__assoc_data_get(sect->assoc_data, callback);
+}
+
+void
+yasm_section_add_data(yasm_section *sect,
+ const yasm_assoc_data_callback *callback, void *data)
+{
+ sect->assoc_data = yasm__assoc_data_add(sect->assoc_data, callback, data);
+}
+
+void
+yasm_object_destroy(yasm_object *object)
+{
+ yasm_section *cur, *next;
+
+ /* Delete object format, debug format, and arch. This can be called
+ * due to an error in yasm_object_create(), so look out for NULLs.
+ */
+ if (object->objfmt)
+ yasm_objfmt_destroy(object->objfmt);
+ if (object->dbgfmt)
+ yasm_dbgfmt_destroy(object->dbgfmt);
+
+ /* Delete sections */
+ cur = STAILQ_FIRST(&object->sections);
+ while (cur) {
+ next = STAILQ_NEXT(cur, link);
+ yasm_section_destroy(cur);
+ cur = next;
+ }
+
+ /* Delete directives HAMT */
+ HAMT_destroy(object->directives, directive_level1_delete);
+
+ /* Delete prefix/suffix */
+ yasm_xfree(object->global_prefix);
+ yasm_xfree(object->global_suffix);
+
+ /* Delete associated filenames */
+ yasm_xfree(object->src_filename);
+ yasm_xfree(object->obj_filename);
+
+ /* Delete symbol table */
+ yasm_symtab_destroy(object->symtab);
+
+ /* Delete architecture */
+ if (object->arch)
+ yasm_arch_destroy(object->arch);
+
+ yasm_xfree(object);
+}
+
+void
+yasm_object_print(const yasm_object *object, FILE *f, int indent_level)
+{
+ yasm_section *cur;
+
+ /* Print symbol table */
+ fprintf(f, "%*sSymbol Table:\n", indent_level, "");
+ yasm_symtab_print(object->symtab, f, indent_level+1);
+
+ /* Print sections and bytecodes */
+ STAILQ_FOREACH(cur, &object->sections, link) {
+ fprintf(f, "%*sSection:\n", indent_level, "");
+ yasm_section_print(cur, f, indent_level+1, 1);
+ }
+}
+
+void
+yasm_object_finalize(yasm_object *object, yasm_errwarns *errwarns)
+{
+ yasm_section *sect;
+
+ /* Iterate through sections */
+ STAILQ_FOREACH(sect, &object->sections, link) {
+ yasm_bytecode *cur = STAILQ_FIRST(&sect->bcs);
+ yasm_bytecode *prev;
+
+ /* Skip our locally created empty bytecode first. */
+ prev = cur;
+ cur = STAILQ_NEXT(cur, link);
+
+ /* Iterate through the remainder, if any. */
+ while (cur) {
+ /* Finalize */
+ yasm_bc_finalize(cur, prev);
+ yasm_errwarn_propagate(errwarns, cur->line);
+ prev = cur;
+ cur = STAILQ_NEXT(cur, link);
+ }
+ }
+}
+
+int
+yasm_object_sections_traverse(yasm_object *object, /*@null@*/ void *d,
+ int (*func) (yasm_section *sect,
+ /*@null@*/ void *d))
+{
+ yasm_section *cur;
+
+ STAILQ_FOREACH(cur, &object->sections, link) {
+ int retval = func(cur, d);
+ if (retval != 0)
+ return retval;
+ }
+ return 0;
+}
+
+/*@-onlytrans@*/
+yasm_section *
+yasm_object_find_general(yasm_object *object, const char *name)
+{
+ yasm_section *cur;
+
+ STAILQ_FOREACH(cur, &object->sections, link) {
+ if (strcmp(cur->name, name) == 0)
+ return cur;
+ }
+ return NULL;
+}
+/*@=onlytrans@*/
+
+void
+yasm_section_add_reloc(yasm_section *sect, yasm_reloc *reloc,
+ void (*destroy_func) (/*@only@*/ void *reloc))
+{
+ STAILQ_INSERT_TAIL(&sect->relocs, reloc, link);
+ if (!destroy_func)
+ yasm_internal_error(N_("NULL destroy function given to add_reloc"));
+ else if (sect->destroy_reloc && destroy_func != sect->destroy_reloc)
+ yasm_internal_error(N_("different destroy function given to add_reloc"));
+ sect->destroy_reloc = destroy_func;
+}
+
+/*@null@*/ yasm_reloc *
+yasm_section_relocs_first(yasm_section *sect)
+{
+ return STAILQ_FIRST(&sect->relocs);
+}
+
+#undef yasm_section_reloc_next
+/*@null@*/ yasm_reloc *
+yasm_section_reloc_next(yasm_reloc *reloc)
+{
+ return STAILQ_NEXT(reloc, link);
+}
+
+void
+yasm_reloc_get(yasm_reloc *reloc, yasm_intnum **addrp, yasm_symrec **symp)
+{
+ *addrp = reloc->addr;
+ *symp = reloc->sym;
+}
+
+
+yasm_bytecode *
+yasm_section_bcs_first(yasm_section *sect)
+{
+ return STAILQ_FIRST(&sect->bcs);
+}
+
+yasm_bytecode *
+yasm_section_bcs_last(yasm_section *sect)
+{
+ return STAILQ_LAST(&sect->bcs, yasm_bytecode, link);
+}
+
+yasm_bytecode *
+yasm_section_bcs_append(yasm_section *sect, yasm_bytecode *bc)
+{
+ if (bc) {
+ if (bc->callback) {
+ bc->section = sect; /* record parent section */
+ STAILQ_INSERT_TAIL(&sect->bcs, bc, link);
+ return bc;
+ } else
+ yasm_xfree(bc);
+ }
+ return (yasm_bytecode *)NULL;
+}
+
+int
+yasm_section_bcs_traverse(yasm_section *sect,
+ /*@null@*/ yasm_errwarns *errwarns,
+ /*@null@*/ void *d,
+ int (*func) (yasm_bytecode *bc, /*@null@*/ void *d))
+{
+ yasm_bytecode *cur = STAILQ_FIRST(&sect->bcs);
+
+ /* Skip our locally created empty bytecode first. */
+ cur = STAILQ_NEXT(cur, link);
+
+ /* Iterate through the remainder, if any. */
+ while (cur) {
+ int retval = func(cur, d);
+ if (errwarns)
+ yasm_errwarn_propagate(errwarns, cur->line);
+ if (retval != 0)
+ return retval;
+ cur = STAILQ_NEXT(cur, link);
+ }
+ return 0;
+}
+
+const char *
+yasm_section_get_name(const yasm_section *sect)
+{
+ return sect->name;
+}
+
+void
+yasm_section_set_align(yasm_section *sect, unsigned long align,
+ unsigned long line)
+{
+ sect->align = align;
+}
+
+unsigned long
+yasm_section_get_align(const yasm_section *sect)
+{
+ return sect->align;
+}
+
+static void
+yasm_section_destroy(yasm_section *sect)
+{
+ yasm_bytecode *cur, *next;
+ yasm_reloc *r_cur, *r_next;
+
+ if (!sect)
+ return;
+
+ yasm_xfree(sect->name);
+ yasm__assoc_data_destroy(sect->assoc_data);
+
+ /* Delete bytecodes */
+ cur = STAILQ_FIRST(&sect->bcs);
+ while (cur) {
+ next = STAILQ_NEXT(cur, link);
+ yasm_bc_destroy(cur);
+ cur = next;
+ }
+
+ /* Delete relocations */
+ r_cur = STAILQ_FIRST(&sect->relocs);
+ while (r_cur) {
+ r_next = STAILQ_NEXT(r_cur, link);
+ yasm_intnum_destroy(r_cur->addr);
+ sect->destroy_reloc(r_cur);
+ r_cur = r_next;
+ }
+
+ yasm_xfree(sect);
+}
+
+void
+yasm_section_print(const yasm_section *sect, FILE *f, int indent_level,
+ int print_bcs)
+{
+ if (!sect) {
+ fprintf(f, "%*s(none)\n", indent_level, "");
+ return;
+ }
+
+ fprintf(f, "%*sname=%s\n", indent_level, "", sect->name);
+
+ if (sect->assoc_data) {
+ fprintf(f, "%*sAssociated data:\n", indent_level, "");
+ yasm__assoc_data_print(sect->assoc_data, f, indent_level+1);
+ }
+
+ if (print_bcs) {
+ yasm_bytecode *cur;
+
+ fprintf(f, "%*sBytecodes:\n", indent_level, "");
+
+ STAILQ_FOREACH(cur, &sect->bcs, link) {
+ fprintf(f, "%*sNext Bytecode:\n", indent_level+1, "");
+ yasm_bc_print(cur, f, indent_level+2);
+ }
+ }
+}
+
+/*
+ * Robertson (1977) optimizer
+ * Based (somewhat loosely) on the algorithm given in:
+ * MRC Technical Summary Report # 1779
+ * CODE GENERATION FOR SHORT/LONG ADDRESS MACHINES
+ * Edward L. Robertson
+ * Mathematics Research Center
+ * University of Wisconsin-Madison
+ * 610 Walnut Street
+ * Madison, Wisconsin 53706
+ * August 1977
+ *
+ * Key components of algorithm:
+ * - start assuming all short forms
+ * - build spans for short->long transition dependencies
+ * - if a long form is needed, walk the dependencies and update
+ * Major differences from Robertson's algorithm:
+ * - detection of cycles
+ * - any difference of two locations is allowed
+ * - handling of alignment/org gaps (offset setting)
+ * - handling of multiples
+ *
+ * Data structures:
+ * - Interval tree to store spans and associated data
+ * - Queues QA and QB
+ *
+ * Each span keeps track of:
+ * - Associated bytecode (bytecode that depends on the span length)
+ * - Active/inactive state (starts out active)
+ * - Sign (negative/positive; negative being "backwards" in address)
+ * - Current length in bytes
+ * - New length in bytes
+ * - Negative/Positive thresholds
+ * - Span ID (unique within each bytecode)
+ *
+ * How org and align and any other offset-based bytecodes are handled:
+ *
+ * Some portions are critical values that must not depend on any bytecode
+ * offset (either relative or absolute).
+ *
+ * All offset-setters (ORG and ALIGN) are put into a linked list in section
+ * order (e.g. increasing offset order). Each span keeps track of the next
+ * offset-setter following the span's associated bytecode.
+ *
+ * When a bytecode is expanded, the next offset-setter is examined. The
+ * offset-setter may be able to absorb the expansion (e.g. any offset
+ * following it would not change), or it may have to move forward (in the
+ * case of align) or error (in the case of org). If it has to move forward,
+ * following offset-setters must also be examined for absorption or moving
+ * forward. In either case, the ongoing offset is updated as well as the
+ * lengths of any spans dependent on the offset-setter.
+ *
+ * Alignment/ORG value is critical value.
+ * Cannot be combined with TIMES.
+ *
+ * How times is handled:
+ *
+ * TIMES: Handled separately from bytecode "raw" size. If not span-dependent,
+ * trivial (just multiplied in at any bytecode size increase). Span
+ * dependent times update on any change (span ID 0). If the resultant
+ * next bytecode offset would be less than the old next bytecode offset,
+ * error. Otherwise increase offset and update dependent spans.
+ *
+ * To reduce interval tree size, a first expansion pass is performed
+ * before the spans are added to the tree.
+ *
+ * Basic algorithm outline:
+ *
+ * 1. Initialization:
+ * a. Number bytecodes sequentially (via bc_index) and calculate offsets
+ * of all bytecodes assuming minimum length, building a list of all
+ * dependent spans as we go.
+ * "minimum" here means absolute minimum:
+ * - align/org (offset-based) bumps offset as normal
+ * - times values (with span-dependent values) assumed to be 0
+ * b. Iterate over spans. Set span length based on bytecode offsets
+ * determined in 1a. If span is "certainly" long because the span
+ * is an absolute reference to another section (or external) or the
+ * distance calculated based on the minimum length is greater than the
+ * span's threshold, expand the span's bytecode, and if no further
+ * expansion can result, mark span as inactive.
+ * c. Iterate over bytecodes to update all bytecode offsets based on new
+ * (expanded) lengths calculated in 1b.
+ * d. Iterate over active spans. Add span to interval tree. Update span's
+ * length based on new bytecode offsets determined in 1c. If span's
+ * length exceeds long threshold, add that span to Q.
+ * 2. Main loop:
+ * While Q not empty:
+ * Expand BC dependent on span at head of Q (and remove span from Q).
+ * Update span:
+ * If BC no longer dependent on span, mark span as inactive.
+ * If BC has new thresholds for span, update span.
+ * If BC increased in size, for each active span that contains BC:
+ * Increase span length by difference between short and long BC length.
+ * If span exceeds long threshold (or is flagged to recalculate on any
+ * change), add it to tail of Q.
+ * 3. Final pass over bytecodes to generate final offsets.
+ */
+
+typedef struct yasm_span yasm_span;
+
+typedef struct yasm_offset_setter {
+ /* Linked list in section order (e.g. offset order) */
+ /*@reldef@*/ STAILQ_ENTRY(yasm_offset_setter) link;
+
+ /*@dependent@*/ yasm_bytecode *bc;
+
+ unsigned long cur_val, new_val;
+ unsigned long thres;
+} yasm_offset_setter;
+
+typedef struct yasm_span_term {
+ yasm_bytecode *precbc, *precbc2;
+ yasm_span *span; /* span this term is a member of */
+ long cur_val, new_val;
+ unsigned int subst;
+} yasm_span_term;
+
+struct yasm_span {
+ /*@reldef@*/ TAILQ_ENTRY(yasm_span) link; /* for allocation tracking */
+ /*@reldef@*/ STAILQ_ENTRY(yasm_span) linkq; /* for Q */
+
+ /*@dependent@*/ yasm_bytecode *bc;
+
+ yasm_value depval;
+
+ /* span term for relative portion of value */
+ yasm_span_term *rel_term;
+ /* span terms in absolute portion of value */
+ yasm_span_term *terms;
+ yasm_expr__item *items;
+ unsigned int num_terms;
+
+ long cur_val;
+ long new_val;
+
+ long neg_thres;
+ long pos_thres;
+
+ int id;
+
+ int active;
+
+ /* NULL-terminated array of spans that led to this span. Used only for
+ * checking for circular references (cycles) with id=0 spans.
+ */
+ yasm_span **backtrace;
+ int backtrace_size;
+
+ /* First offset setter following this span's bytecode */
+ yasm_offset_setter *os;
+};
+
+typedef struct optimize_data {
+ /*@reldef@*/ TAILQ_HEAD(yasm_span_head, yasm_span) spans;
+ /*@reldef@*/ STAILQ_HEAD(yasm_span_shead, yasm_span) QA, QB;
+ /*@only@*/ IntervalTree *itree;
+ /*@reldef@*/ STAILQ_HEAD(offset_setters_head, yasm_offset_setter)
+ offset_setters;
+ long len_diff; /* used only for optimize_term_expand */
+ yasm_span *span; /* used only for check_cycle */
+ yasm_offset_setter *os;
+} optimize_data;
+
+static yasm_span *
+create_span(yasm_bytecode *bc, int id, /*@null@*/ const yasm_value *value,
+ long neg_thres, long pos_thres, yasm_offset_setter *os)
+{
+ yasm_span *span = yasm_xmalloc(sizeof(yasm_span));
+
+ span->bc = bc;
+ if (value)
+ yasm_value_init_copy(&span->depval, value);
+ else
+ yasm_value_initialize(&span->depval, NULL, 0);
+ span->rel_term = NULL;
+ span->terms = NULL;
+ span->items = NULL;
+ span->num_terms = 0;
+ span->cur_val = 0;
+ span->new_val = 0;
+ span->neg_thres = neg_thres;
+ span->pos_thres = pos_thres;
+ span->id = id;
+ span->active = 1;
+ span->backtrace = NULL;
+ span->backtrace_size = 0;
+ span->os = os;
+
+ return span;
+}
+
+static void
+optimize_add_span(void *add_span_data, yasm_bytecode *bc, int id,
+ const yasm_value *value, long neg_thres, long pos_thres)
+{
+ optimize_data *optd = (optimize_data *)add_span_data;
+ yasm_span *span;
+ span = create_span(bc, id, value, neg_thres, pos_thres, optd->os);
+ TAILQ_INSERT_TAIL(&optd->spans, span, link);
+}
+
+static void
+add_span_term(unsigned int subst, yasm_bytecode *precbc,
+ yasm_bytecode *precbc2, void *d)
+{
+ yasm_span *span = d;
+ yasm_intnum *intn;
+
+ if (subst >= span->num_terms) {
+ /* Linear expansion since total number is essentially always small */
+ span->num_terms = subst+1;
+ span->terms = yasm_xrealloc(span->terms,
+ span->num_terms*sizeof(yasm_span_term));
+ }
+ span->terms[subst].precbc = precbc;
+ span->terms[subst].precbc2 = precbc2;
+ span->terms[subst].span = span;
+ span->terms[subst].subst = subst;
+
+ intn = yasm_calc_bc_dist(precbc, precbc2);
+ if (!intn)
+ yasm_internal_error(N_("could not calculate bc distance"));
+ span->terms[subst].cur_val = 0;
+ span->terms[subst].new_val = yasm_intnum_get_int(intn);
+ yasm_intnum_destroy(intn);
+}
+
+static void
+span_create_terms(yasm_span *span)
+{
+ unsigned int i;
+
+ /* Split out sym-sym terms in absolute portion of dependent value */
+ if (span->depval.abs) {
+ span->num_terms = yasm_expr__bc_dist_subst(&span->depval.abs, span,
+ add_span_term);
+ if (span->num_terms > 0) {
+ span->items = yasm_xmalloc(span->num_terms*sizeof(yasm_expr__item));
+ for (i=0; i<span->num_terms; i++) {
+ /* Create items with dummy value */
+ span->items[i].type = YASM_EXPR_INT;
+ span->items[i].data.intn = yasm_intnum_create_int(0);
+
+ /* Check for circular references */
+ if (span->id <= 0 &&
+ ((span->bc->bc_index > span->terms[i].precbc->bc_index &&
+ span->bc->bc_index <= span->terms[i].precbc2->bc_index) ||
+ (span->bc->bc_index > span->terms[i].precbc2->bc_index &&
+ span->bc->bc_index <= span->terms[i].precbc->bc_index)))
+ yasm_error_set(YASM_ERROR_VALUE,
+ N_("circular reference detected"));
+ }
+ }
+ }
+
+ /* Create term for relative portion of dependent value */
+ if (span->depval.rel) {
+ yasm_bytecode *rel_precbc;
+ int sym_local;
+
+ sym_local = yasm_symrec_get_label(span->depval.rel, &rel_precbc);
+ if (span->depval.wrt || span->depval.seg_of || span->depval.section_rel
+ || !sym_local)
+ return; /* we can't handle SEG, WRT, or external symbols */
+ if (rel_precbc->section != span->bc->section)
+ return; /* not in this section */
+ if (!span->depval.curpos_rel)
+ return; /* not PC-relative */
+
+ span->rel_term = yasm_xmalloc(sizeof(yasm_span_term));
+ span->rel_term->precbc = NULL;
+ span->rel_term->precbc2 = rel_precbc;
+ span->rel_term->span = span;
+ span->rel_term->subst = ~0U;
+
+ span->rel_term->cur_val = 0;
+ span->rel_term->new_val = yasm_bc_next_offset(rel_precbc) -
+ span->bc->offset;
+ }
+}
+
+/* Recalculate span value based on current span replacement values.
+ * Returns 1 if span needs expansion (e.g. exceeded thresholds).
+ */
+static int
+recalc_normal_span(yasm_span *span)
+{
+ span->new_val = 0;
+
+ if (span->depval.abs) {
+ yasm_expr *abs_copy = yasm_expr_copy(span->depval.abs);
+ /*@null@*/ /*@dependent@*/ yasm_intnum *num;
+
+ /* Update sym-sym terms and substitute back into expr */
+ unsigned int i;
+ for (i=0; i<span->num_terms; i++)
+ yasm_intnum_set_int(span->items[i].data.intn,
+ span->terms[i].new_val);
+ yasm_expr__subst(abs_copy, span->num_terms, span->items);
+ num = yasm_expr_get_intnum(&abs_copy, 0);
+ if (num)
+ span->new_val = yasm_intnum_get_int(num);
+ else
+ span->new_val = LONG_MAX; /* too complex; force to longest form */
+ yasm_expr_destroy(abs_copy);
+ }
+
+ if (span->rel_term) {
+ if (span->new_val != LONG_MAX && span->rel_term->new_val != LONG_MAX)
+ span->new_val += span->rel_term->new_val >> span->depval.rshift;
+ else
+ span->new_val = LONG_MAX; /* too complex; force to longest form */
+ } else if (span->depval.rel)
+ span->new_val = LONG_MAX; /* too complex; force to longest form */
+
+ if (span->new_val == LONG_MAX)
+ span->active = 0;
+
+ /* If id<=0, flag update on any change */
+ if (span->id <= 0)
+ return (span->new_val != span->cur_val);
+
+ return (span->new_val < span->neg_thres
+ || span->new_val > span->pos_thres);
+}
+
+/* Updates all bytecode offsets. For offset-based bytecodes, calls expand
+ * to determine new length.
+ */
+static int
+update_all_bc_offsets(yasm_object *object, yasm_errwarns *errwarns)
+{
+ yasm_section *sect;
+ int saw_error = 0;
+
+ STAILQ_FOREACH(sect, &object->sections, link) {
+ unsigned long offset = 0;
+
+ yasm_bytecode *bc = STAILQ_FIRST(&sect->bcs);
+ yasm_bytecode *prevbc;
+
+ /* Skip our locally created empty bytecode first. */
+ prevbc = bc;
+ bc = STAILQ_NEXT(bc, link);
+
+ /* Iterate through the remainder, if any. */
+ while (bc) {
+ if (bc->callback->special == YASM_BC_SPECIAL_OFFSET) {
+ /* Recalculate/adjust len of offset-based bytecodes here */
+ long neg_thres = 0;
+ long pos_thres = (long)yasm_bc_next_offset(bc);
+ int retval = yasm_bc_expand(bc, 1, 0,
+ (long)yasm_bc_next_offset(prevbc),
+ &neg_thres, &pos_thres);
+ yasm_errwarn_propagate(errwarns, bc->line);
+ if (retval < 0)
+ saw_error = 1;
+ }
+ bc->offset = offset;
+ offset += bc->len*bc->mult_int;
+ prevbc = bc;
+ bc = STAILQ_NEXT(bc, link);
+ }
+ }
+ return saw_error;
+}
+
+static void
+span_destroy(/*@only@*/ yasm_span *span)
+{
+ unsigned int i;
+
+ yasm_value_delete(&span->depval);
+ if (span->rel_term)
+ yasm_xfree(span->rel_term);
+ if (span->terms)
+ yasm_xfree(span->terms);
+ if (span->items) {
+ for (i=0; i<span->num_terms; i++)
+ yasm_intnum_destroy(span->items[i].data.intn);
+ yasm_xfree(span->items);
+ }
+ if (span->backtrace)
+ yasm_xfree(span->backtrace);
+ yasm_xfree(span);
+}
+
+static void
+optimize_cleanup(optimize_data *optd)
+{
+ yasm_span *s1, *s2;
+ yasm_offset_setter *os1, *os2;
+
+ IT_destroy(optd->itree);
+
+ s1 = TAILQ_FIRST(&optd->spans);
+ while (s1) {
+ s2 = TAILQ_NEXT(s1, link);
+ span_destroy(s1);
+ s1 = s2;
+ }
+
+ os1 = STAILQ_FIRST(&optd->offset_setters);
+ while (os1) {
+ os2 = STAILQ_NEXT(os1, link);
+ yasm_xfree(os1);
+ os1 = os2;
+ }
+}
+
+static void
+optimize_itree_add(IntervalTree *itree, yasm_span *span, yasm_span_term *term)
+{
+ long precbc_index, precbc2_index;
+ unsigned long low, high;
+
+ /* Update term length */
+ if (term->precbc)
+ precbc_index = term->precbc->bc_index;
+ else
+ precbc_index = span->bc->bc_index-1;
+
+ if (term->precbc2)
+ precbc2_index = term->precbc2->bc_index;
+ else
+ precbc2_index = span->bc->bc_index-1;
+
+ if (precbc_index < precbc2_index) {
+ low = precbc_index+1;
+ high = precbc2_index;
+ } else if (precbc_index > precbc2_index) {
+ low = precbc2_index+1;
+ high = precbc_index;
+ } else
+ return; /* difference is same bc - always 0! */
+
+ IT_insert(itree, (long)low, (long)high, term);
+}
+
+static void
+check_cycle(IntervalTreeNode *node, void *d)
+{
+ optimize_data *optd = d;
+ yasm_span_term *term = node->data;
+ yasm_span *depspan = term->span;
+ int i;
+ int depspan_bt_alloc;
+
+ /* Only check for cycles in id=0 spans */
+ if (depspan->id > 0)
+ return;
+
+ /* Check for a circular reference by looking to see if this dependent
+ * span is in our backtrace.
+ */
+ if (optd->span->backtrace) {
+ for (i=0; i<optd->span->backtrace_size; i++) {
+ if (optd->span->backtrace[i] == depspan)
+ yasm_error_set(YASM_ERROR_VALUE,
+ N_("circular reference detected"));
+ }
+ }
+
+ /* Add our complete backtrace and ourselves to backtrace of dependent
+ * span.
+ */
+ if (!depspan->backtrace) {
+ depspan->backtrace = yasm_xmalloc((optd->span->backtrace_size+1)*
+ sizeof(yasm_span *));
+ if (optd->span->backtrace_size > 0)
+ memcpy(depspan->backtrace, optd->span->backtrace,
+ optd->span->backtrace_size*sizeof(yasm_span *));
+ depspan->backtrace[optd->span->backtrace_size] = optd->span;
+ depspan->backtrace_size = optd->span->backtrace_size+1;
+ return;
+ }
+
+ /* Add our complete backtrace, checking for duplicates */
+ depspan_bt_alloc = depspan->backtrace_size;
+ for (i=0; i<optd->span->backtrace_size; i++) {
+ int present = 0;
+ int j;
+ for (j=0; j<depspan->backtrace_size; j++) {
+ if (optd->span->backtrace[i] == optd->span->backtrace[j]) {
+ present = 1;
+ break;
+ }
+ }
+ if (present)
+ continue;
+ /* Not already in array; add it. */
+ if (depspan->backtrace_size >= depspan_bt_alloc)
+ {
+ depspan_bt_alloc *= 2;
+ depspan->backtrace =
+ yasm_xrealloc(depspan->backtrace,
+ depspan_bt_alloc*sizeof(yasm_span *));
+ }
+ depspan->backtrace[depspan->backtrace_size] = optd->span->backtrace[i];
+ depspan->backtrace_size++;
+ }
+
+ /* Add ourselves. */
+ if (depspan->backtrace_size >= depspan_bt_alloc)
+ {
+ depspan_bt_alloc++;
+ depspan->backtrace =
+ yasm_xrealloc(depspan->backtrace,
+ depspan_bt_alloc*sizeof(yasm_span *));
+ }
+ depspan->backtrace[depspan->backtrace_size] = optd->span;
+ depspan->backtrace_size++;
+}
+
+static void
+optimize_term_expand(IntervalTreeNode *node, void *d)
+{
+ optimize_data *optd = d;
+ yasm_span_term *term = node->data;
+ yasm_span *span = term->span;
+ long len_diff = optd->len_diff;
+ long precbc_index, precbc2_index;
+
+ /* Don't expand inactive spans */
+ if (!span->active)
+ return;
+
+ /* Update term length */
+ if (term->precbc)
+ precbc_index = term->precbc->bc_index;
+ else
+ precbc_index = span->bc->bc_index-1;
+
+ if (term->precbc2)
+ precbc2_index = term->precbc2->bc_index;
+ else
+ precbc2_index = span->bc->bc_index-1;
+
+ if (precbc_index < precbc2_index)
+ term->new_val += len_diff;
+ else
+ term->new_val -= len_diff;
+
+ /* If already on Q, don't re-add */
+ if (span->active == 2)
+ return;
+
+ /* Update term and check against thresholds */
+ if (!recalc_normal_span(span))
+ return; /* didn't exceed thresholds, we're done */
+
+ /* Exceeded thresholds, need to add to Q for expansion */
+ if (span->id <= 0)
+ STAILQ_INSERT_TAIL(&optd->QA, span, linkq);
+ else
+ STAILQ_INSERT_TAIL(&optd->QB, span, linkq);
+ span->active = 2; /* Mark as being in Q */
+}
+
+void
+yasm_object_optimize(yasm_object *object, yasm_errwarns *errwarns)
+{
+ yasm_section *sect;
+ unsigned long bc_index = 0;
+ int saw_error = 0;
+ optimize_data optd;
+ yasm_span *span, *span_temp;
+ yasm_offset_setter *os;
+ int retval;
+ unsigned int i;
+
+ TAILQ_INIT(&optd.spans);
+ STAILQ_INIT(&optd.offset_setters);
+ optd.itree = IT_create();
+
+ /* Create an placeholder offset setter for spans to point to; this will
+ * get updated if/when we actually run into one.
+ */
+ os = yasm_xmalloc(sizeof(yasm_offset_setter));
+ os->bc = NULL;
+ os->cur_val = 0;
+ os->new_val = 0;
+ os->thres = 0;
+ STAILQ_INSERT_TAIL(&optd.offset_setters, os, link);
+ optd.os = os;
+
+ /* Step 1a */
+ STAILQ_FOREACH(sect, &object->sections, link) {
+ unsigned long offset = 0;
+
+ yasm_bytecode *bc = STAILQ_FIRST(&sect->bcs);
+ yasm_bytecode *prevbc;
+
+ bc->bc_index = bc_index++;
+
+ /* Skip our locally created empty bytecode first. */
+ prevbc = bc;
+ bc = STAILQ_NEXT(bc, link);
+
+ /* Iterate through the remainder, if any. */
+ while (bc) {
+ bc->bc_index = bc_index++;
+ bc->offset = offset;
+
+ retval = yasm_bc_calc_len(bc, optimize_add_span, &optd);
+ yasm_errwarn_propagate(errwarns, bc->line);
+ if (retval)
+ saw_error = 1;
+ else {
+ if (bc->callback->special == YASM_BC_SPECIAL_OFFSET) {
+ /* Remember it as offset setter */
+ os->bc = bc;
+ os->thres = yasm_bc_next_offset(bc);
+
+ /* Create new placeholder */
+ os = yasm_xmalloc(sizeof(yasm_offset_setter));
+ os->bc = NULL;
+ os->cur_val = 0;
+ os->new_val = 0;
+ os->thres = 0;
+ STAILQ_INSERT_TAIL(&optd.offset_setters, os, link);
+ optd.os = os;
+
+ if (bc->multiple) {
+ yasm_error_set(YASM_ERROR_VALUE,
+ N_("cannot combine multiples and setting assembly position"));
+ yasm_errwarn_propagate(errwarns, bc->line);
+ saw_error = 1;
+ }
+ }
+
+ offset += bc->len*bc->mult_int;
+ }
+
+ prevbc = bc;
+ bc = STAILQ_NEXT(bc, link);
+ }
+ }
+
+ if (saw_error) {
+ optimize_cleanup(&optd);
+ return;
+ }
+
+ /* Step 1b */
+ TAILQ_FOREACH_SAFE(span, &optd.spans, link, span_temp) {
+ span_create_terms(span);
+ if (yasm_error_occurred()) {
+ yasm_errwarn_propagate(errwarns, span->bc->line);
+ saw_error = 1;
+ } else if (recalc_normal_span(span)) {
+ retval = yasm_bc_expand(span->bc, span->id, span->cur_val,
+ span->new_val, &span->neg_thres,
+ &span->pos_thres);
+ yasm_errwarn_propagate(errwarns, span->bc->line);
+ if (retval < 0)
+ saw_error = 1;
+ else if (retval > 0) {
+ if (!span->active) {
+ yasm_error_set(YASM_ERROR_VALUE,
+ N_("secondary expansion of an external/complex value"));
+ yasm_errwarn_propagate(errwarns, span->bc->line);
+ saw_error = 1;
+ }
+ } else {
+ TAILQ_REMOVE(&optd.spans, span, link);
+ span_destroy(span);
+ continue;
+ }
+ }
+ span->cur_val = span->new_val;
+ }
+
+ if (saw_error) {
+ optimize_cleanup(&optd);
+ return;
+ }
+
+ /* Step 1c */
+ if (update_all_bc_offsets(object, errwarns)) {
+ optimize_cleanup(&optd);
+ return;
+ }
+
+ /* Step 1d */
+ STAILQ_INIT(&optd.QB);
+ TAILQ_FOREACH(span, &optd.spans, link) {
+ yasm_intnum *intn;
+
+ /* Update span terms based on new bc offsets */
+ for (i=0; i<span->num_terms; i++) {
+ intn = yasm_calc_bc_dist(span->terms[i].precbc,
+ span->terms[i].precbc2);
+ if (!intn)
+ yasm_internal_error(N_("could not calculate bc distance"));
+ span->terms[i].cur_val = span->terms[i].new_val;
+ span->terms[i].new_val = yasm_intnum_get_int(intn);
+ yasm_intnum_destroy(intn);
+ }
+ if (span->rel_term) {
+ span->rel_term->cur_val = span->rel_term->new_val;
+ if (span->rel_term->precbc2)
+ span->rel_term->new_val =
+ yasm_bc_next_offset(span->rel_term->precbc2) -
+ span->bc->offset;
+ else
+ span->rel_term->new_val = span->bc->offset -
+ yasm_bc_next_offset(span->rel_term->precbc);
+ }
+
+ if (recalc_normal_span(span)) {
+ /* Exceeded threshold, add span to QB */
+ STAILQ_INSERT_TAIL(&optd.QB, span, linkq);
+ span->active = 2;
+ }
+ }
+
+ /* Do we need step 2? If not, go ahead and exit. */
+ if (STAILQ_EMPTY(&optd.QB)) {
+ optimize_cleanup(&optd);
+ return;
+ }
+
+ /* Update offset-setters values */
+ STAILQ_FOREACH(os, &optd.offset_setters, link) {
+ if (!os->bc)
+ continue;
+ os->thres = yasm_bc_next_offset(os->bc);
+ os->new_val = os->bc->offset;
+ os->cur_val = os->new_val;
+ }
+
+ /* Build up interval tree */
+ TAILQ_FOREACH(span, &optd.spans, link) {
+ for (i=0; i<span->num_terms; i++)
+ optimize_itree_add(optd.itree, span, &span->terms[i]);
+ if (span->rel_term)
+ optimize_itree_add(optd.itree, span, span->rel_term);
+ }
+
+ /* Look for cycles in times expansion (span.id==0) */
+ TAILQ_FOREACH(span, &optd.spans, link) {
+ if (span->id > 0)
+ continue;
+ optd.span = span;
+ IT_enumerate(optd.itree, (long)span->bc->bc_index,
+ (long)span->bc->bc_index, &optd, check_cycle);
+ if (yasm_error_occurred()) {
+ yasm_errwarn_propagate(errwarns, span->bc->line);
+ saw_error = 1;
+ }
+ }
+
+ if (saw_error) {
+ optimize_cleanup(&optd);
+ return;
+ }
+
+ /* Step 2 */
+ STAILQ_INIT(&optd.QA);
+ while (!STAILQ_EMPTY(&optd.QA) || !(STAILQ_EMPTY(&optd.QB))) {
+ unsigned long orig_len;
+ long offset_diff;
+
+ /* QA is for TIMES, update those first, then update non-TIMES.
+ * This is so that TIMES can absorb increases before we look at
+ * expanding non-TIMES BCs.
+ */
+ if (!STAILQ_EMPTY(&optd.QA)) {
+ span = STAILQ_FIRST(&optd.QA);
+ STAILQ_REMOVE_HEAD(&optd.QA, linkq);
+ } else {
+ span = STAILQ_FIRST(&optd.QB);
+ STAILQ_REMOVE_HEAD(&optd.QB, linkq);
+ }
+
+ if (!span->active)
+ continue;
+ span->active = 1; /* no longer in Q */
+
+ /* Make sure we ended up ultimately exceeding thresholds; due to
+ * offset BCs we may have been placed on Q and then reduced in size
+ * again.
+ */
+ if (!recalc_normal_span(span))
+ continue;
+
+ orig_len = span->bc->len * span->bc->mult_int;
+
+ retval = yasm_bc_expand(span->bc, span->id, span->cur_val,
+ span->new_val, &span->neg_thres,
+ &span->pos_thres);
+ yasm_errwarn_propagate(errwarns, span->bc->line);
+
+ if (retval < 0) {
+ /* error */
+ saw_error = 1;
+ continue;
+ } else if (retval > 0) {
+ /* another threshold, keep active */
+ for (i=0; i<span->num_terms; i++)
+ span->terms[i].cur_val = span->terms[i].new_val;
+ if (span->rel_term)
+ span->rel_term->cur_val = span->rel_term->new_val;
+ span->cur_val = span->new_val;
+ } else
+ span->active = 0; /* we're done with this span */
+
+ optd.len_diff = span->bc->len * span->bc->mult_int - orig_len;
+ if (optd.len_diff == 0)
+ continue; /* didn't increase in size */
+
+ /* Iterate over all spans dependent across the bc just expanded */
+ IT_enumerate(optd.itree, (long)span->bc->bc_index,
+ (long)span->bc->bc_index, &optd, optimize_term_expand);
+
+ /* Iterate over offset-setters that follow the bc just expanded.
+ * Stop iteration if:
+ * - no more offset-setters in this section
+ * - offset-setter didn't move its following offset
+ */
+ os = span->os;
+ offset_diff = optd.len_diff;
+ while (os->bc && os->bc->section == span->bc->section
+ && offset_diff != 0) {
+ unsigned long old_next_offset = os->cur_val + os->bc->len;
+ long neg_thres_temp;
+
+ if (offset_diff < 0 && (unsigned long)(-offset_diff) > os->new_val)
+ yasm_internal_error(N_("org/align went to negative offset"));
+ os->new_val += offset_diff;
+
+ orig_len = os->bc->len;
+ retval = yasm_bc_expand(os->bc, 1, (long)os->cur_val,
+ (long)os->new_val, &neg_thres_temp,
+ (long *)&os->thres);
+ yasm_errwarn_propagate(errwarns, os->bc->line);
+
+ offset_diff = os->new_val + os->bc->len - old_next_offset;
+ optd.len_diff = os->bc->len - orig_len;
+ if (optd.len_diff != 0)
+ IT_enumerate(optd.itree, (long)os->bc->bc_index,
+ (long)os->bc->bc_index, &optd, optimize_term_expand);
+
+ os->cur_val = os->new_val;
+ os = STAILQ_NEXT(os, link);
+ }
+ }
+
+ if (saw_error) {
+ optimize_cleanup(&optd);
+ return;
+ }
+
+ /* Step 3 */
+ update_all_bc_offsets(object, errwarns);
+ optimize_cleanup(&optd);
+}
diff --git a/libyasm/section.h b/libyasm/section.h
new file mode 100644
index 0000000..2c7faa4
--- /dev/null
+++ b/libyasm/section.h
@@ -0,0 +1,383 @@
+/**
+ * \file libyasm/section.h
+ * \brief YASM section interface.
+ *
+ * \license
+ * Copyright (C) 2001-2007 Peter Johnson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * \endlicense
+ */
+#ifndef YASM_SECTION_H
+#define YASM_SECTION_H
+
+#ifndef YASM_LIB_DECL
+#define YASM_LIB_DECL
+#endif
+
+/** Basic YASM relocation. Object formats will need to extend this
+ * structure with additional fields for relocation type, etc.
+ */
+typedef struct yasm_reloc yasm_reloc;
+
+struct yasm_reloc {
+ /*@reldef@*/ STAILQ_ENTRY(yasm_reloc) link; /**< Link to next reloc */
+ yasm_intnum *addr; /**< Offset (address) within section */
+ /*@dependent@*/ yasm_symrec *sym; /**< Relocated symbol */
+};
+
+/** An object. This is the internal representation of an object file. */
+struct yasm_object {
+ /*@owned@*/ char *src_filename; /**< Source filename */
+ /*@owned@*/ char *obj_filename; /**< Object filename */
+
+ /*@owned@*/ yasm_symtab *symtab; /**< Symbol table */
+ /*@owned@*/ yasm_arch *arch; /**< Target architecture */
+ /*@owned@*/ yasm_objfmt *objfmt; /**< Object format */
+ /*@owned@*/ yasm_dbgfmt *dbgfmt; /**< Debug format */
+
+ /** Currently active section. Used by some directives. NULL if no
+ * section active.
+ */
+ /*@dependent@*/ /*@null@*/ yasm_section *cur_section;
+
+ /** Linked list of sections. */
+ /*@reldef@*/ STAILQ_HEAD(yasm_sectionhead, yasm_section) sections;
+
+ /** Directives, organized as two level HAMT; first level is parser,
+ * second level is directive name.
+ */
+ /*@owned@*/ struct HAMT *directives;
+
+ /** Prefix prepended to externally-visible symbols (empty string if none) */
+ /*@owned@*/ char *global_prefix;
+
+ /** Suffix appended to externally-visible symbols (empty string if none) */
+ /*@owned@*/ char *global_suffix;
+};
+
+/** Create a new object. A default section is created as the first section.
+ * An empty symbol table (yasm_symtab) and line mapping (yasm_linemap) are
+ * automatically created.
+ * \param src_filename source filename (e.g. "file.asm")
+ * \param obj_filename object filename (e.g. "file.o")
+ * \param arch architecture
+ * \param objfmt_module object format module
+ * \param dbgfmt_module debug format module
+ * \return Newly allocated object, or NULL on error.
+ */
+YASM_LIB_DECL
+/*@null@*/ /*@only@*/ yasm_object *yasm_object_create
+ (const char *src_filename, const char *obj_filename,
+ /*@kept@*/ yasm_arch *arch,
+ const yasm_objfmt_module *objfmt_module,
+ const yasm_dbgfmt_module *dbgfmt_module);
+
+/** Create a new, or continue an existing, general section. The section is
+ * added to the object if there's not already a section by that name.
+ * \param object object
+ * \param name section name
+ * \param align alignment in bytes (0 if none)
+ * \param code if nonzero, section is intended to contain code
+ * (e.g. alignment should be made with NOP instructions, not 0)
+ * \param res_only if nonzero, only space-reserving bytecodes are allowed in
+ * the section (ignored if section already exists)
+ * \param isnew output; set to nonzero if section did not already exist
+ * \param line virtual line of section declaration (ignored if section
+ * already exists)
+ * \return New section.
+ */
+YASM_LIB_DECL
+/*@dependent@*/ yasm_section *yasm_object_get_general
+ (yasm_object *object, const char *name, unsigned long align, int code,
+ int res_only, /*@out@*/ int *isnew, unsigned long line);
+
+/** Handle a directive. Passed down to object format, debug format, or
+ * architecture as appropriate.
+ * \param object object
+ * \param name directive name
+ * \param parser parser keyword
+ * \param valparams value/parameters
+ * \param objext_valparams "object format-specific" value/parameters
+ * \param line virtual line (from yasm_linemap)
+ * \return 0 if directive recognized, nonzero if unrecognized.
+ */
+YASM_LIB_DECL
+int yasm_object_directive(yasm_object *object, const char *name,
+ const char *parser, yasm_valparamhead *valparams,
+ yasm_valparamhead *objext_valparams,
+ unsigned long line);
+
+/** Delete (free allocated memory for) an object. All sections in the
+ * object and all bytecodes within those sections are also deleted.
+ * \param object object
+ */
+YASM_LIB_DECL
+void yasm_object_destroy(/*@only@*/ yasm_object *object);
+
+/** Print an object. For debugging purposes.
+ * \param object object
+ * \param f file
+ * \param indent_level indentation level
+ */
+YASM_LIB_DECL
+void yasm_object_print(const yasm_object *object, FILE *f, int indent_level);
+
+/** Finalize an object after parsing.
+ * \param object object
+ * \param errwarns error/warning set
+ * \note Errors/warnings are stored into errwarns.
+ */
+YASM_LIB_DECL
+void yasm_object_finalize(yasm_object *object, yasm_errwarns *errwarns);
+
+/** Traverses all sections in an object, calling a function on each section.
+ * \param object object
+ * \param d data pointer passed to func on each call
+ * \param func function
+ * \return Stops early (and returns func's return value) if func returns a
+ * nonzero value; otherwise 0.
+ */
+YASM_LIB_DECL
+int yasm_object_sections_traverse
+ (yasm_object *object, /*@null@*/ void *d,
+ int (*func) (yasm_section *sect, /*@null@*/ void *d));
+
+/** Find a general section in an object, based on its name.
+ * \param object object
+ * \param name section name
+ * \return Section matching name, or NULL if no match found.
+ */
+YASM_LIB_DECL
+/*@dependent@*/ /*@null@*/ yasm_section *yasm_object_find_general
+ (yasm_object *object, const char *name);
+
+/** Change the source filename for an object.
+ * \param object object
+ * \param src_filename new source filename (e.g. "file.asm")
+ */
+YASM_LIB_DECL
+void yasm_object_set_source_fn(yasm_object *object, const char *src_filename);
+
+/** Change the prefix used for externally-visible symbols.
+ * \param object object
+ * \param prefix new prefix
+ */
+YASM_LIB_DECL
+void yasm_object_set_global_prefix(yasm_object *object, const char *prefix);
+
+/** Change the suffix used for externally-visible symbols.
+ * \param object object
+ * \param suffix new suffix
+ */
+YASM_LIB_DECL
+void yasm_object_set_global_suffix(yasm_object *object, const char *suffix);
+
+/** Optimize an object. Takes the unoptimized object and optimizes it.
+ * If successful, the object is ready for output to an object file.
+ * \param object object
+ * \param errwarns error/warning set
+ * \note Optimization failures are stored into errwarns.
+ */
+YASM_LIB_DECL
+void yasm_object_optimize(yasm_object *object, yasm_errwarns *errwarns);
+
+/** Determine if a section is flagged to contain code.
+ * \param sect section
+ * \return Nonzero if section is flagged to contain code.
+ */
+YASM_LIB_DECL
+int yasm_section_is_code(yasm_section *sect);
+
+/** Get yasm_optimizer-specific flags. For yasm_optimizer use only.
+ * \param sect section
+ * \return Optimizer-specific flags.
+ */
+YASM_LIB_DECL
+unsigned long yasm_section_get_opt_flags(const yasm_section *sect);
+
+/** Set yasm_optimizer-specific flags. For yasm_optimizer use only.
+ * \param sect section
+ * \param opt_flags optimizer-specific flags.
+ */
+YASM_LIB_DECL
+void yasm_section_set_opt_flags(yasm_section *sect, unsigned long opt_flags);
+
+/** Determine if a section was declared as the "default" section (e.g. not
+ * created through a section directive).
+ * \param sect section
+ * \return Nonzero if section was declared as default.
+ */
+YASM_LIB_DECL
+int yasm_section_is_default(const yasm_section *sect);
+
+/** Set section "default" flag to a new value.
+ * \param sect section
+ * \param def new value of default flag
+ */
+YASM_LIB_DECL
+void yasm_section_set_default(yasm_section *sect, int def);
+
+/** Get object owner of a section.
+ * \param sect section
+ * \return Object this section is a part of.
+ */
+YASM_LIB_DECL
+yasm_object *yasm_section_get_object(const yasm_section *sect);
+
+/** Get assocated data for a section and data callback.
+ * \param sect section
+ * \param callback callback used when adding data
+ * \return Associated data (NULL if none).
+ */
+YASM_LIB_DECL
+/*@dependent@*/ /*@null@*/ void *yasm_section_get_data
+ (yasm_section *sect, const yasm_assoc_data_callback *callback);
+
+/** Add associated data to a section.
+ * \attention Deletes any existing associated data for that data callback.
+ * \param sect section
+ * \param callback callback
+ * \param data data to associate
+ */
+YASM_LIB_DECL
+void yasm_section_add_data(yasm_section *sect,
+ const yasm_assoc_data_callback *callback,
+ /*@null@*/ /*@only@*/ void *data);
+
+/** Add a relocation to a section.
+ * \param sect section
+ * \param reloc relocation
+ * \param destroy_func function that can destroy the relocation
+ * \note Does not make a copy of reloc. The same destroy_func must be
+ * used for all relocations in a section or an internal error will occur.
+ * The section will destroy the relocation address; it is the caller's
+ * responsibility to destroy any other allocated data.
+ */
+YASM_LIB_DECL
+void yasm_section_add_reloc(yasm_section *sect, yasm_reloc *reloc,
+ void (*destroy_func) (/*@only@*/ void *reloc));
+
+/** Get the first relocation for a section.
+ * \param sect section
+ * \return First relocation for section. NULL if no relocations.
+ */
+YASM_LIB_DECL
+/*@null@*/ yasm_reloc *yasm_section_relocs_first(yasm_section *sect);
+
+/** Get the next relocation for a section.
+ * \param reloc previous relocation
+ * \return Next relocation for section. NULL if no more relocations.
+ */
+/*@null@*/ yasm_reloc *yasm_section_reloc_next(yasm_reloc *reloc);
+#ifndef YASM_DOXYGEN
+#define yasm_section_reloc_next(x) STAILQ_NEXT((x), link)
+#endif
+
+/** Get the basic relocation information for a relocation.
+ * \param reloc relocation
+ * \param addrp address of relocation within section (returned)
+ * \param symp relocated symbol (returned)
+ */
+YASM_LIB_DECL
+void yasm_reloc_get(yasm_reloc *reloc, yasm_intnum **addrp,
+ /*@dependent@*/ yasm_symrec **symp);
+
+/** Get the first bytecode in a section.
+ * \param sect section
+ * \return First bytecode in section (at least one empty bytecode is always
+ * present).
+ */
+YASM_LIB_DECL
+yasm_bytecode *yasm_section_bcs_first(yasm_section *sect);
+
+/** Get the last bytecode in a section.
+ * \param sect section
+ * \return Last bytecode in section (at least one empty bytecode is always
+ * present).
+ */
+YASM_LIB_DECL
+yasm_bytecode *yasm_section_bcs_last(yasm_section *sect);
+
+/** Add bytecode to the end of a section.
+ * \note Does not make a copy of bc; so don't pass this function static or
+ * local variables, and discard the bc pointer after calling this
+ * function.
+ * \param sect section
+ * \param bc bytecode (may be NULL)
+ * \return If bytecode was actually appended (it wasn't NULL or empty), the
+ * bytecode; otherwise NULL.
+ */
+YASM_LIB_DECL
+/*@only@*/ /*@null@*/ yasm_bytecode *yasm_section_bcs_append
+ (yasm_section *sect,
+ /*@returned@*/ /*@only@*/ /*@null@*/ yasm_bytecode *bc);
+
+/** Traverses all bytecodes in a section, calling a function on each bytecode.
+ * \param sect section
+ * \param errwarns error/warning set (may be NULL)
+ * \param d data pointer passed to func on each call (may be NULL)
+ * \param func function
+ * \return Stops early (and returns func's return value) if func returns a
+ * nonzero value; otherwise 0.
+ * \note If errwarns is non-NULL, yasm_errwarn_propagate() is called after
+ * each call to func (with the bytecode's line number).
+ */
+YASM_LIB_DECL
+int yasm_section_bcs_traverse
+ (yasm_section *sect, /*@null@*/ yasm_errwarns *errwarns,
+ /*@null@*/ void *d, int (*func) (yasm_bytecode *bc, /*@null@*/ void *d));
+
+/** Get name of a section.
+ * \param sect section
+ * \return Section name.
+ */
+YASM_LIB_DECL
+/*@observer@*/ const char *yasm_section_get_name(const yasm_section *sect);
+
+/** Change alignment of a section.
+ * \param sect section
+ * \param align alignment in bytes
+ * \param line virtual line
+ */
+YASM_LIB_DECL
+void yasm_section_set_align(yasm_section *sect, unsigned long align,
+ unsigned long line);
+
+/** Get alignment of a section.
+ * \param sect section
+ * \return Alignment in bytes (0 if none).
+ */
+YASM_LIB_DECL
+unsigned long yasm_section_get_align(const yasm_section *sect);
+
+/** Print a section. For debugging purposes.
+ * \param f file
+ * \param indent_level indentation level
+ * \param sect section
+ * \param print_bcs if nonzero, print bytecodes within section
+ */
+YASM_LIB_DECL
+void yasm_section_print(/*@null@*/ const yasm_section *sect, FILE *f,
+ int indent_level, int print_bcs);
+
+#endif
diff --git a/libyasm/strcasecmp.c b/libyasm/strcasecmp.c
new file mode 100644
index 0000000..a87bd88
--- /dev/null
+++ b/libyasm/strcasecmp.c
@@ -0,0 +1,94 @@
+/*
+ * strcasecmp() implementation for systems that don't have it or stricmp()
+ * or strcmpi().
+ *
+ * Copyright (c) 1987, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#include "util.h"
+
+#ifndef USE_OUR_OWN_STRCASECMP
+#undef yasm__strcasecmp
+#undef yasm__strncasecmp
+#endif
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)strcasecmp.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+
+#include <ctype.h>
+
+int
+yasm__strcasecmp(const char *s1, const char *s2)
+{
+#ifdef HAVE_STRCASECMP
+ return strcasecmp(s1, s2);
+#elif HAVE_STRICMP
+ return stricmp(s1, s2);
+#elif HAVE__STRICMP
+ return _stricmp(s1, s2);
+#elif HAVE_STRCMPI
+ return strcmpi(s1, s2);
+#else
+ const unsigned char
+ *us1 = (const unsigned char *)s1,
+ *us2 = (const unsigned char *)s2;
+
+ while (tolower(*us1) == tolower(*us2++))
+ if (*us1++ == '\0')
+ return (0);
+ return (tolower(*us1) - tolower(*--us2));
+#endif
+}
+
+int
+yasm__strncasecmp(const char *s1, const char *s2, size_t n)
+{
+#ifdef HAVE_STRCASECMP
+ return strncasecmp(s1, s2, n);
+#elif HAVE_STRICMP
+ return strnicmp(s1, s2, n);
+#elif HAVE__STRNICMP
+ return _strnicmp(s1, s2, n);
+#elif HAVE_STRCMPI
+ return strncmpi(s1, s2, n);
+#else
+ const unsigned char
+ *us1 = (const unsigned char *)s1,
+ *us2 = (const unsigned char *)s2;
+
+ if (n != 0) {
+ do {
+ if (tolower(*us1) != tolower(*us2++))
+ return (tolower(*us1) - tolower(*--us2));
+ if (*us1++ == '\0')
+ break;
+ } while (--n != 0);
+ }
+ return (0);
+#endif
+}
diff --git a/libyasm/strsep.c b/libyasm/strsep.c
new file mode 100644
index 0000000..0fecd47
--- /dev/null
+++ b/libyasm/strsep.c
@@ -0,0 +1,85 @@
+/*
+ * strsep() implementation for systems that don't have it.
+ *
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#define NO_STRING_INLINES
+#include "util.h"
+
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)strsep.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+
+#ifdef HAVE_STRSEP
+#undef yasm__strsep
+#endif
+
+/*
+ * Get next token from string *stringp, where tokens are possibly-empty
+ * strings separated by characters from delim.
+ *
+ * Writes NULs into the string at *stringp to end tokens.
+ * delim need not remain constant from call to call.
+ * On return, *stringp points past the last NUL written (if there might
+ * be further tokens), or is NULL (if there are definitely no more tokens).
+ *
+ * If *stringp is NULL, strsep returns NULL.
+ */
+/*@-nullstate@*/
+char *
+yasm__strsep(char **stringp, const char *delim)
+{
+#ifdef HAVE_STRSEP
+ return strsep(stringp, delim);
+#else
+ register char *s;
+ register const char *spanp;
+ register int c, sc;
+ char *tok;
+
+ if ((s = *stringp) == NULL)
+ return (NULL);
+ for (tok = s;;) {
+ c = *s++;
+ spanp = delim;
+ do {
+ if ((sc = *spanp++) == c) {
+ if (c == 0)
+ s = NULL;
+ else
+ s[-1] = 0;
+ *stringp = s;
+ return (tok);
+ }
+ } while (sc != 0);
+ }
+ /* NOTREACHED */
+#endif
+}
+/*@=nullstate@*/
diff --git a/libyasm/symrec.c b/libyasm/symrec.c
new file mode 100644
index 0000000..694f0c6
--- /dev/null
+++ b/libyasm/symrec.c
@@ -0,0 +1,714 @@
+/*
+ * Symbol table handling
+ *
+ * Copyright (C) 2001-2007 Michael Urman, Peter Johnson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "util.h"
+
+#include <limits.h>
+#include <ctype.h>
+
+#include "libyasm-stdint.h"
+#include "coretype.h"
+#include "valparam.h"
+#include "hamt.h"
+#include "assocdat.h"
+
+#include "errwarn.h"
+#include "intnum.h"
+#include "floatnum.h"
+#include "expr.h"
+#include "symrec.h"
+
+#include "bytecode.h"
+#include "section.h"
+#include "objfmt.h"
+
+
+typedef enum {
+ SYM_UNKNOWN, /* for unknown type (COMMON/EXTERN) */
+ SYM_EQU, /* for EQU defined symbols (expressions) */
+ SYM_LABEL, /* for labels */
+ SYM_CURPOS, /* for labels representing the current
+ assembly position */
+ SYM_SPECIAL /* for special symbols that need to be in
+ the symbol table but otherwise have no
+ purpose */
+} sym_type;
+
+struct yasm_symrec {
+ char *name;
+ sym_type type;
+ yasm_sym_status status;
+ yasm_sym_vis visibility;
+ unsigned long def_line; /* line where symbol was first defined */
+ unsigned long decl_line; /* line where symbol was first declared */
+ unsigned long use_line; /* line where symbol was first used */
+ union {
+ yasm_expr *expn; /* equ value */
+
+ /* bytecode immediately preceding a label */
+ /*@dependent@*/ yasm_bytecode *precbc;
+ } value;
+ unsigned int size; /* 0 if not user-defined */
+ const char *segment; /* for segmented systems like DOS */
+
+ /* associated data; NULL if none */
+ /*@null@*/ /*@only@*/ yasm__assoc_data *assoc_data;
+};
+
+/* Linked list of symbols not in the symbol table. */
+typedef struct non_table_symrec_s {
+ /*@reldef@*/ SLIST_ENTRY(non_table_symrec_s) link;
+ /*@owned@*/ yasm_symrec *rec;
+} non_table_symrec;
+
+struct yasm_symtab {
+ /* The symbol table: a hash array mapped trie (HAMT). */
+ /*@only@*/ HAMT *sym_table;
+ /* Symbols not in the table */
+ SLIST_HEAD(nontablesymhead_s, non_table_symrec_s) non_table_syms;
+
+ int case_sensitive;
+};
+
+static void
+objext_valparams_destroy(void *data)
+{
+ yasm_vps_destroy((yasm_valparamhead *)data);
+}
+
+static void
+objext_valparams_print(void *data, FILE *f, int indent_level)
+{
+ yasm_vps_print((yasm_valparamhead *)data, f);
+}
+
+static yasm_assoc_data_callback objext_valparams_cb = {
+ objext_valparams_destroy,
+ objext_valparams_print
+};
+
+static void
+common_size_destroy(void *data)
+{
+ yasm_expr **e = (yasm_expr **)data;
+ yasm_expr_destroy(*e);
+ yasm_xfree(data);
+}
+
+static void
+common_size_print(void *data, FILE *f, int indent_level)
+{
+ yasm_expr **e = (yasm_expr **)data;
+ yasm_expr_print(*e, f);
+}
+
+static yasm_assoc_data_callback common_size_cb = {
+ common_size_destroy,
+ common_size_print
+};
+
+yasm_symtab *
+yasm_symtab_create(void)
+{
+ yasm_symtab *symtab = yasm_xmalloc(sizeof(yasm_symtab));
+ symtab->sym_table = HAMT_create(0, yasm_internal_error_);
+ SLIST_INIT(&symtab->non_table_syms);
+ symtab->case_sensitive = 1;
+ return symtab;
+}
+
+void
+yasm_symtab_set_case_sensitive(yasm_symtab *symtab, int sensitive)
+{
+ symtab->case_sensitive = sensitive;
+}
+
+static void
+symrec_destroy_one(/*@only@*/ void *d)
+{
+ yasm_symrec *sym = d;
+ yasm_xfree(sym->name);
+ if (sym->type == SYM_EQU && (sym->status & YASM_SYM_VALUED))
+ yasm_expr_destroy(sym->value.expn);
+ yasm__assoc_data_destroy(sym->assoc_data);
+ yasm_xfree(sym);
+}
+
+static /*@partial@*/ yasm_symrec *
+symrec_new_common(/*@keep@*/ char *name, int case_sensitive)
+{
+ yasm_symrec *rec = yasm_xmalloc(sizeof(yasm_symrec));
+
+ if (!case_sensitive) {
+ char *c;
+ for (c=name; *c; c++)
+ *c = tolower(*c);
+ }
+
+ rec->name = name;
+ rec->type = SYM_UNKNOWN;
+ rec->def_line = 0;
+ rec->decl_line = 0;
+ rec->use_line = 0;
+ rec->visibility = YASM_SYM_LOCAL;
+ rec->size = 0;
+ rec->segment = NULL;
+ rec->assoc_data = NULL;
+ return rec;
+}
+
+static /*@partial@*/ /*@dependent@*/ yasm_symrec *
+symtab_get_or_new_in_table(yasm_symtab *symtab, /*@only@*/ char *name)
+{
+ yasm_symrec *rec = symrec_new_common(name, symtab->case_sensitive);
+ int replace = 0;
+
+ rec->status = YASM_SYM_NOSTATUS;
+
+ if (!symtab->case_sensitive) {
+ char *c;
+ for (c=name; *c; c++)
+ *c = tolower(*c);
+ }
+
+ return HAMT_insert(symtab->sym_table, name, rec, &replace,
+ symrec_destroy_one);
+}
+
+static /*@partial@*/ /*@dependent@*/ yasm_symrec *
+symtab_get_or_new_not_in_table(yasm_symtab *symtab, /*@only@*/ char *name)
+{
+ non_table_symrec *sym = yasm_xmalloc(sizeof(non_table_symrec));
+ sym->rec = symrec_new_common(name, symtab->case_sensitive);
+
+ sym->rec->status = YASM_SYM_NOTINTABLE;
+
+ SLIST_INSERT_HEAD(&symtab->non_table_syms, sym, link);
+
+ return sym->rec;
+}
+
+/* create a new symrec */
+/*@-freshtrans -mustfree@*/
+static /*@partial@*/ /*@dependent@*/ yasm_symrec *
+symtab_get_or_new(yasm_symtab *symtab, const char *name, int in_table)
+{
+ char *symname = yasm__xstrdup(name);
+
+ if (in_table)
+ return symtab_get_or_new_in_table(symtab, symname);
+ else
+ return symtab_get_or_new_not_in_table(symtab, symname);
+}
+/*@=freshtrans =mustfree@*/
+
+int
+yasm_symtab_traverse(yasm_symtab *symtab, void *d,
+ int (*func) (yasm_symrec *sym, void *d))
+{
+ return HAMT_traverse(symtab->sym_table, d, (int (*) (void *, void *))func);
+}
+
+const yasm_symtab_iter *
+yasm_symtab_first(const yasm_symtab *symtab)
+{
+ return (const yasm_symtab_iter *)HAMT_first(symtab->sym_table);
+}
+
+/*@null@*/ const yasm_symtab_iter *
+yasm_symtab_next(const yasm_symtab_iter *prev)
+{
+ return (const yasm_symtab_iter *)HAMT_next((const HAMTEntry *)prev);
+}
+
+yasm_symrec *
+yasm_symtab_iter_value(const yasm_symtab_iter *cur)
+{
+ return (yasm_symrec *)HAMTEntry_get_data((const HAMTEntry *)cur);
+}
+
+yasm_symrec *
+yasm_symtab_abs_sym(yasm_symtab *symtab)
+{
+ yasm_symrec *rec = symtab_get_or_new(symtab, "", 1);
+ rec->def_line = 0;
+ rec->decl_line = 0;
+ rec->use_line = 0;
+ rec->type = SYM_EQU;
+ rec->value.expn =
+ yasm_expr_create_ident(yasm_expr_int(yasm_intnum_create_uint(0)), 0);
+ rec->status |= YASM_SYM_DEFINED|YASM_SYM_VALUED|YASM_SYM_USED;
+ return rec;
+}
+
+yasm_symrec *
+yasm_symtab_use(yasm_symtab *symtab, const char *name, unsigned long line)
+{
+ yasm_symrec *rec = symtab_get_or_new(symtab, name, 1);
+ if (rec->use_line == 0)
+ rec->use_line = line; /* set line number of first use */
+ rec->status |= YASM_SYM_USED;
+ return rec;
+}
+
+yasm_symrec *
+yasm_symtab_get(yasm_symtab *symtab, const char *name)
+{
+ if (!symtab->case_sensitive) {
+ char *_name = yasm__xstrdup(name);
+ char *c;
+ yasm_symrec *ret;
+ for (c=_name; *c; c++)
+ *c = tolower(*c);
+ ret = HAMT_search(symtab->sym_table, _name);
+ yasm_xfree(_name);
+ return ret;
+ } else
+ return HAMT_search(symtab->sym_table, name);
+}
+
+static /*@dependent@*/ yasm_symrec *
+symtab_define(yasm_symtab *symtab, const char *name, sym_type type,
+ int in_table, unsigned long line)
+{
+ yasm_symrec *rec = symtab_get_or_new(symtab, name, in_table);
+
+ /* Has it been defined before (either by DEFINED or COMMON/EXTERN)? */
+ if (rec->status & YASM_SYM_DEFINED) {
+ yasm_error_set_xref(rec->def_line!=0 ? rec->def_line : rec->decl_line,
+ N_("`%s' previously defined here"), name);
+ yasm_error_set(YASM_ERROR_GENERAL, N_("redefinition of `%s'"),
+ name);
+ } else {
+ if (rec->visibility & YASM_SYM_EXTERN)
+ yasm_warn_set(YASM_WARN_GENERAL,
+ N_("`%s' both defined and declared extern"), name);
+ rec->def_line = line; /* set line number of definition */
+ rec->type = type;
+ rec->status |= YASM_SYM_DEFINED;
+ rec->size = 0;
+ rec->segment = NULL;
+ }
+ return rec;
+}
+
+yasm_symrec *
+yasm_symtab_define_equ(yasm_symtab *symtab, const char *name, yasm_expr *e,
+ unsigned long line)
+{
+ yasm_symrec *rec = symtab_define(symtab, name, SYM_EQU, 1, line);
+ if (yasm_error_occurred())
+ return rec;
+ rec->value.expn = e;
+ rec->status |= YASM_SYM_VALUED;
+ return rec;
+}
+
+yasm_symrec *
+yasm_symtab_define_label(yasm_symtab *symtab, const char *name,
+ yasm_bytecode *precbc, int in_table,
+ unsigned long line)
+{
+ yasm_symrec *rec = symtab_define(symtab, name, SYM_LABEL, in_table, line);
+ if (yasm_error_occurred())
+ return rec;
+ rec->value.precbc = precbc;
+ if (in_table && precbc)
+ yasm_bc__add_symrec(precbc, rec);
+ return rec;
+}
+
+yasm_symrec *
+yasm_symtab_define_curpos(yasm_symtab *symtab, const char *name,
+ yasm_bytecode *precbc, unsigned long line)
+{
+ yasm_symrec *rec = symtab_define(symtab, name, SYM_CURPOS, 0, line);
+ if (yasm_error_occurred())
+ return rec;
+ rec->value.precbc = precbc;
+ return rec;
+}
+
+yasm_symrec *
+yasm_symtab_define_special(yasm_symtab *symtab, const char *name,
+ yasm_sym_vis vis)
+{
+ yasm_symrec *rec = symtab_define(symtab, name, SYM_SPECIAL, 1, 0);
+ if (yasm_error_occurred())
+ return rec;
+ rec->status |= YASM_SYM_VALUED;
+ rec->visibility = vis;
+ return rec;
+}
+
+yasm_symrec *
+yasm_symtab_declare(yasm_symtab *symtab, const char *name, yasm_sym_vis vis,
+ unsigned long line)
+{
+ yasm_symrec *rec = symtab_get_or_new(symtab, name, 1);
+ yasm_symrec_declare(rec, vis, line);
+ return rec;
+}
+
+void
+yasm_symrec_declare(yasm_symrec *rec, yasm_sym_vis vis, unsigned long line)
+{
+ /* Allowable combinations:
+ * Existing State-------------- vis New State-------------------
+ * DEFINED GLOBAL COMMON EXTERN GCE DEFINED GLOBAL COMMON EXTERN
+ * 0 - 0 0 GCE 0 G C E
+ * 0 - 0 1 GE 0 G 0 E
+ * 0 - 1 0 GC 0 G C 0
+ * X 0 - 1 1
+ * 1 - 0 0 G 1 G 0 0
+ * X 1 - - 1
+ * X 1 - 1 -
+ */
+ if ((vis == YASM_SYM_GLOBAL) ||
+ (!(rec->status & YASM_SYM_DEFINED) &&
+ (!(rec->visibility & (YASM_SYM_COMMON | YASM_SYM_EXTERN)) ||
+ ((rec->visibility & YASM_SYM_COMMON) && (vis == YASM_SYM_COMMON)) ||
+ ((rec->visibility & YASM_SYM_EXTERN) && (vis == YASM_SYM_EXTERN))))) {
+ rec->decl_line = line;
+ rec->visibility |= vis;
+ } else
+ yasm_error_set(YASM_ERROR_GENERAL,
+ N_("duplicate definition of `%s'; first defined on line %lu"),
+ rec->name, rec->def_line!=0 ? rec->def_line : rec->decl_line);
+}
+
+typedef struct symtab_finalize_info {
+ unsigned long firstundef_line;
+ int undef_extern;
+ yasm_errwarns *errwarns;
+} symtab_finalize_info;
+
+static int
+symtab_parser_finalize_checksym(yasm_symrec *sym, /*@null@*/ void *d)
+{
+ symtab_finalize_info *info = (symtab_finalize_info *)d;
+
+ /* error if a symbol is used but never defined or extern/common declared */
+ if ((sym->status & YASM_SYM_USED) && !(sym->status & YASM_SYM_DEFINED) &&
+ !(sym->visibility & (YASM_SYM_EXTERN | YASM_SYM_COMMON))) {
+ if (info->undef_extern)
+ sym->visibility |= YASM_SYM_EXTERN;
+ else {
+ yasm_error_set(YASM_ERROR_GENERAL,
+ N_("undefined symbol `%s' (first use)"), sym->name);
+ yasm_errwarn_propagate(info->errwarns, sym->use_line);
+ if (sym->use_line < info->firstundef_line)
+ info->firstundef_line = sym->use_line;
+ }
+ }
+
+ return 0;
+}
+
+void
+yasm_symtab_parser_finalize(yasm_symtab *symtab, int undef_extern,
+ yasm_errwarns *errwarns)
+{
+ symtab_finalize_info info;
+ info.firstundef_line = ULONG_MAX;
+ info.undef_extern = undef_extern;
+ info.errwarns = errwarns;
+ yasm_symtab_traverse(symtab, &info, symtab_parser_finalize_checksym);
+ if (info.firstundef_line < ULONG_MAX) {
+ yasm_error_set(YASM_ERROR_GENERAL,
+ N_(" (Each undefined symbol is reported only once.)"));
+ yasm_errwarn_propagate(errwarns, info.firstundef_line);
+ }
+}
+
+void
+yasm_symtab_destroy(yasm_symtab *symtab)
+{
+ HAMT_destroy(symtab->sym_table, symrec_destroy_one);
+
+ while (!SLIST_EMPTY(&symtab->non_table_syms)) {
+ non_table_symrec *sym = SLIST_FIRST(&symtab->non_table_syms);
+ SLIST_REMOVE_HEAD(&symtab->non_table_syms, link);
+ symrec_destroy_one(sym->rec);
+ yasm_xfree(sym);
+ }
+
+ yasm_xfree(symtab);
+}
+
+typedef struct symrec_print_data {
+ FILE *f;
+ int indent_level;
+} symrec_print_data;
+
+/*@+voidabstract@*/
+static int
+symrec_print_wrapper(yasm_symrec *sym, /*@null@*/ void *d)
+{
+ symrec_print_data *data = (symrec_print_data *)d;
+ assert(data != NULL);
+ fprintf(data->f, "%*sSymbol `%s'\n", data->indent_level, "", sym->name);
+ yasm_symrec_print(sym, data->f, data->indent_level+1);
+ return 0;
+}
+
+void
+yasm_symtab_print(yasm_symtab *symtab, FILE *f, int indent_level)
+{
+ symrec_print_data data;
+ data.f = f;
+ data.indent_level = indent_level;
+ yasm_symtab_traverse(symtab, &data, symrec_print_wrapper);
+}
+/*@=voidabstract@*/
+
+const char *
+yasm_symrec_get_name(const yasm_symrec *sym)
+{
+ return sym->name;
+}
+
+char *
+yasm_symrec_get_global_name(const yasm_symrec *sym, const yasm_object *object)
+{
+ if (sym->visibility & (YASM_SYM_GLOBAL|YASM_SYM_COMMON|YASM_SYM_EXTERN)) {
+ char *name = yasm_xmalloc(strlen(object->global_prefix) +
+ strlen(sym->name) +
+ strlen(object->global_suffix) + 1);
+ strcpy(name, object->global_prefix);
+ strcat(name, sym->name);
+ strcat(name, object->global_suffix);
+ return name;
+ }
+ return yasm__xstrdup(sym->name);
+}
+
+yasm_sym_vis
+yasm_symrec_get_visibility(const yasm_symrec *sym)
+{
+ return sym->visibility;
+}
+
+yasm_sym_status
+yasm_symrec_get_status(const yasm_symrec *sym)
+{
+ return sym->status;
+}
+
+unsigned long
+yasm_symrec_get_def_line(const yasm_symrec *sym)
+{
+ return sym->def_line;
+}
+
+unsigned long
+yasm_symrec_get_decl_line(const yasm_symrec *sym)
+{
+ return sym->decl_line;
+}
+
+unsigned long
+yasm_symrec_get_use_line(const yasm_symrec *sym)
+{
+ return sym->use_line;
+}
+
+const yasm_expr *
+yasm_symrec_get_equ(const yasm_symrec *sym)
+{
+ if (sym->type == SYM_EQU && (sym->status & YASM_SYM_VALUED))
+ return sym->value.expn;
+ return (const yasm_expr *)NULL;
+}
+
+int
+yasm_symrec_get_label(const yasm_symrec *sym,
+ yasm_symrec_get_label_bytecodep *precbc)
+{
+ if (!(sym->type == SYM_LABEL || sym->type == SYM_CURPOS)
+ || !sym->value.precbc) {
+ *precbc = (yasm_symrec_get_label_bytecodep)0xDEADBEEF;
+ return 0;
+ }
+ *precbc = sym->value.precbc;
+ return 1;
+}
+
+void
+yasm_symrec_set_size(yasm_symrec *sym, int size)
+{
+ sym->size = size;
+}
+
+int
+yasm_symrec_get_size(const yasm_symrec *sym)
+{
+ return sym->size;
+}
+
+void
+yasm_symrec_set_segment(yasm_symrec *sym, const char *segment)
+{
+ sym->segment = segment;
+}
+
+const char *
+yasm_symrec_get_segment(const yasm_symrec *sym)
+{
+ return sym->segment;
+}
+
+int
+yasm_symrec_is_abs(const yasm_symrec *sym)
+{
+ return (sym->def_line == 0 && sym->type == SYM_EQU &&
+ sym->name[0] == '\0');
+}
+
+int
+yasm_symrec_is_special(const yasm_symrec *sym)
+{
+ return (sym->type == SYM_SPECIAL);
+}
+
+int
+yasm_symrec_is_curpos(const yasm_symrec *sym)
+{
+ return (sym->type == SYM_CURPOS);
+}
+
+void
+yasm_symrec_set_objext_valparams(yasm_symrec *sym,
+ /*@only@*/ yasm_valparamhead *objext_valparams)
+{
+ yasm_symrec_add_data(sym, &objext_valparams_cb, objext_valparams);
+}
+
+yasm_valparamhead *
+yasm_symrec_get_objext_valparams(yasm_symrec *sym)
+{
+ return yasm_symrec_get_data(sym, &objext_valparams_cb);
+}
+
+void
+yasm_symrec_set_common_size(yasm_symrec *sym,
+ /*@only@*/ yasm_expr *common_size)
+{
+ yasm_expr **ep = yasm_xmalloc(sizeof(yasm_expr *));
+ *ep = common_size;
+ yasm_symrec_add_data(sym, &common_size_cb, ep);
+}
+
+yasm_expr **
+yasm_symrec_get_common_size(yasm_symrec *sym)
+{
+ return (yasm_expr **)yasm_symrec_get_data(sym, &common_size_cb);
+}
+
+void *
+yasm_symrec_get_data(yasm_symrec *sym,
+ const yasm_assoc_data_callback *callback)
+{
+ return yasm__assoc_data_get(sym->assoc_data, callback);
+}
+
+void
+yasm_symrec_add_data(yasm_symrec *sym,
+ const yasm_assoc_data_callback *callback, void *data)
+{
+ sym->assoc_data = yasm__assoc_data_add(sym->assoc_data, callback, data);
+}
+
+void
+yasm_symrec_print(const yasm_symrec *sym, FILE *f, int indent_level)
+{
+ switch (sym->type) {
+ case SYM_UNKNOWN:
+ fprintf(f, "%*s-Unknown (Common/Extern)-\n", indent_level, "");
+ break;
+ case SYM_EQU:
+ fprintf(f, "%*s_EQU_\n", indent_level, "");
+ fprintf(f, "%*sExpn=", indent_level, "");
+ if (sym->status & YASM_SYM_VALUED)
+ yasm_expr_print(sym->value.expn, f);
+ else
+ fprintf(f, "***UNVALUED***");
+ fprintf(f, "\n");
+ break;
+ case SYM_LABEL:
+ case SYM_CURPOS:
+ fprintf(f, "%*s_%s_\n%*sSection:\n", indent_level, "",
+ sym->type == SYM_LABEL ? "Label" : "CurPos",
+ indent_level, "");
+ yasm_section_print(yasm_bc_get_section(sym->value.precbc), f,
+ indent_level+1, 0);
+ fprintf(f, "%*sPreceding bytecode:\n", indent_level, "");
+ yasm_bc_print(sym->value.precbc, f, indent_level+1);
+ break;
+ case SYM_SPECIAL:
+ fprintf(f, "%*s-Special-\n", indent_level, "");
+ break;
+ }
+
+ fprintf(f, "%*sStatus=", indent_level, "");
+ if (sym->status == YASM_SYM_NOSTATUS)
+ fprintf(f, "None\n");
+ else {
+ if (sym->status & YASM_SYM_USED)
+ fprintf(f, "Used,");
+ if (sym->status & YASM_SYM_DEFINED)
+ fprintf(f, "Defined,");
+ if (sym->status & YASM_SYM_VALUED)
+ fprintf(f, "Valued,");
+ if (sym->status & YASM_SYM_NOTINTABLE)
+ fprintf(f, "Not in Table,");
+ fprintf(f, "\n");
+ }
+
+ fprintf(f, "%*sVisibility=", indent_level, "");
+ if (sym->visibility == YASM_SYM_LOCAL)
+ fprintf(f, "Local\n");
+ else {
+ if (sym->visibility & YASM_SYM_GLOBAL)
+ fprintf(f, "Global,");
+ if (sym->visibility & YASM_SYM_COMMON)
+ fprintf(f, "Common,");
+ if (sym->visibility & YASM_SYM_EXTERN)
+ fprintf(f, "Extern,");
+ fprintf(f, "\n");
+ }
+
+ if (sym->assoc_data) {
+ fprintf(f, "%*sAssociated data:\n", indent_level, "");
+ yasm__assoc_data_print(sym->assoc_data, f, indent_level+1);
+ }
+
+ fprintf(f, "%*sLine Index (Defined)=%lu\n", indent_level, "",
+ sym->def_line);
+ fprintf(f, "%*sLine Index (Declared)=%lu\n", indent_level, "",
+ sym->decl_line);
+ fprintf(f, "%*sLine Index (Used)=%lu\n", indent_level, "", sym->use_line);
+}
diff --git a/libyasm/symrec.h b/libyasm/symrec.h
new file mode 100644
index 0000000..6207158
--- /dev/null
+++ b/libyasm/symrec.h
@@ -0,0 +1,433 @@
+/**
+ * \file libyasm/symrec.h
+ * \brief YASM symbol table interface.
+ *
+ * \license
+ * Copyright (C) 2001-2007 Michael Urman, Peter Johnson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * \endlicense
+ */
+#ifndef YASM_SYMREC_H
+#define YASM_SYMREC_H
+
+#ifndef YASM_LIB_DECL
+#define YASM_LIB_DECL
+#endif
+
+/** Symbol status. YASM_SYM_DEFINED is set by yasm_symtab_define_label(),
+ * yasm_symtab_define_equ(), or yasm_symtab_declare()/yasm_symrec_declare()
+ * with a visibility of #YASM_SYM_EXTERN or #YASM_SYM_COMMON.
+ */
+typedef enum yasm_sym_status {
+ YASM_SYM_NOSTATUS = 0, /**< no status */
+ YASM_SYM_USED = 1 << 0, /**< for use before definition */
+ YASM_SYM_DEFINED = 1 << 1, /**< once it's been defined in the file */
+ YASM_SYM_VALUED = 1 << 2, /**< once its value has been determined */
+ YASM_SYM_NOTINTABLE = 1 << 3 /**< if it's not in sym_table (ex. '$') */
+} yasm_sym_status;
+
+/** Symbol record visibility.
+ * \note YASM_SYM_EXTERN and YASM_SYM_COMMON are mutually exclusive.
+ */
+typedef enum yasm_sym_vis {
+ YASM_SYM_LOCAL = 0, /**< Default, local only */
+ YASM_SYM_GLOBAL = 1 << 0, /**< If symbol is declared GLOBAL */
+ YASM_SYM_COMMON = 1 << 1, /**< If symbol is declared COMMON */
+ YASM_SYM_EXTERN = 1 << 2, /**< If symbol is declared EXTERN */
+ YASM_SYM_DLOCAL = 1 << 3 /**< If symbol is explicitly declared LOCAL */
+} yasm_sym_vis;
+
+/** Create a new symbol table. */
+YASM_LIB_DECL
+yasm_symtab *yasm_symtab_create(void);
+
+/** Destroy a symbol table and all internal symbols.
+ * \param symtab symbol table
+ * \warning All yasm_symrec *'s into this symbol table become invalid after
+ * this is called!
+ */
+YASM_LIB_DECL
+void yasm_symtab_destroy(/*@only@*/ yasm_symtab *symtab);
+
+/** Set the symbol table to be case sensitive or not.
+ * Should be called before adding any symbol.
+ * \param symtab symbol table
+ * \param sensitive whether the symbol table should be case sensitive.
+ */
+YASM_LIB_DECL
+void yasm_symtab_set_case_sensitive(yasm_symtab *symtab, int sensitive);
+
+/** Get a reference to the symbol table's "absolute" symbol. This is
+ * essentially an EQU with no name and value 0, and is used for relocating
+ * absolute current-position-relative values.
+ * \see yasm_value_set_curpos_rel().
+ * \param symtab symbol table
+ * \return Absolute symbol (dependent pointer, do not free).
+ */
+YASM_LIB_DECL
+/*@dependent@*/ yasm_symrec *yasm_symtab_abs_sym(yasm_symtab *symtab);
+
+/** Get a reference to (use) a symbol. The symbol does not necessarily need to
+ * be defined before it is used.
+ * \param symtab symbol table
+ * \param name symbol name
+ * \param line virtual line where referenced
+ * \return Symbol (dependent pointer, do not free).
+ */
+YASM_LIB_DECL
+/*@dependent@*/ yasm_symrec *yasm_symtab_use
+ (yasm_symtab *symtab, const char *name, unsigned long line);
+
+/** Get a reference to a symbol, without "using" it. Should be used for cases
+ * when an internal assembler usage of a symbol shouldn't be treated like a
+ * normal user symbol usage.
+ * \param symtab symbol table
+ * \param name symbol name
+ * \return Symbol (dependent pointer, do not free). May be NULL if symbol
+ * doesn't exist.
+ */
+YASM_LIB_DECL
+/*@null@*/ /*@dependent@*/ yasm_symrec *yasm_symtab_get
+ (yasm_symtab *symtab, const char *name);
+
+/** Define a symbol as an EQU value.
+ * \param symtab symbol table
+ * \param name symbol (EQU) name
+ * \param e EQU value (expression)
+ * \param line virtual line of EQU
+ * \return Symbol (dependent pointer, do not free).
+ */
+YASM_LIB_DECL
+/*@dependent@*/ yasm_symrec *yasm_symtab_define_equ
+ (yasm_symtab *symtab, const char *name, /*@keep@*/ yasm_expr *e,
+ unsigned long line);
+
+/** Define a symbol as a label.
+ * \param symtab symbol table
+ * \param name symbol (label) name
+ * \param precbc bytecode preceding label
+ * \param in_table nonzero if the label should be inserted into the symbol
+ * table (some specially-generated ones should not be)
+ * \param line virtual line of label
+ * \return Symbol (dependent pointer, do not free).
+ */
+YASM_LIB_DECL
+/*@dependent@*/ yasm_symrec *yasm_symtab_define_label
+ (yasm_symtab *symtab, const char *name,
+ /*@dependent@*/ yasm_bytecode *precbc, int in_table, unsigned long line);
+
+/** Define a symbol as a label representing the current assembly position.
+ * This should be used for this purpose instead of yasm_symtab_define_label()
+ * as value_finalize_scan() looks for usage of this symbol type for special
+ * handling. The symbol created is not inserted into the symbol table.
+ * \param symtab symbol table
+ * \param name symbol (label) name
+ * \param precbc bytecode preceding label
+ * \param line virtual line of label
+ * \return Symbol (dependent pointer, do not free).
+ */
+YASM_LIB_DECL
+/*@dependent@*/ yasm_symrec *yasm_symtab_define_curpos
+ (yasm_symtab *symtab, const char *name,
+ /*@dependent@*/ yasm_bytecode *precbc, unsigned long line);
+
+/** Define a special symbol that will appear in the symbol table and have a
+ * defined name, but have no other data associated with it within the
+ * standard symrec.
+ * \param symtab symbol table
+ * \param name symbol name
+ * \param vis symbol visibility
+ * \return Symbol (dependent pointer, do not free).
+ */
+YASM_LIB_DECL
+/*@dependent@*/ yasm_symrec *yasm_symtab_define_special
+ (yasm_symtab *symtab, const char *name, yasm_sym_vis vis);
+
+/** Declare external visibility of a symbol.
+ * \note Not all visibility combinations are allowed.
+ * \param symtab symbol table
+ * \param name symbol name
+ * \param vis visibility
+ * \param line virtual line of visibility-setting
+ * \return Symbol (dependent pointer, do not free).
+ */
+YASM_LIB_DECL
+/*@dependent@*/ yasm_symrec *yasm_symtab_declare
+ (yasm_symtab *symtab, const char *name, yasm_sym_vis vis,
+ unsigned long line);
+
+/** Declare external visibility of a symbol.
+ * \note Not all visibility combinations are allowed.
+ * \param symrec symbol
+ * \param vis visibility
+ * \param line virtual line of visibility-setting
+ */
+YASM_LIB_DECL
+void yasm_symrec_declare(yasm_symrec *symrec, yasm_sym_vis vis,
+ unsigned long line);
+
+/** Callback function for yasm_symrec_traverse().
+ * \param sym symbol
+ * \param d data passed into yasm_symrec_traverse()
+ * \return Nonzero to stop symbol traversal.
+ */
+typedef int (*yasm_symtab_traverse_callback)
+ (yasm_symrec *sym, /*@null@*/ void *d);
+
+/** Traverse all symbols in the symbol table.
+ * \param symtab symbol table
+ * \param d data to pass to each call of callback function
+ * \param func callback function called on each symbol
+ * \return Nonzero value returned by callback function if it ever returned
+ * nonzero.
+ */
+YASM_LIB_DECL
+int /*@alt void@*/ yasm_symtab_traverse
+ (yasm_symtab *symtab, /*@null@*/ void *d,
+ yasm_symtab_traverse_callback func);
+
+/** Symbol table iterator (opaque type). */
+typedef struct yasm_symtab_iter yasm_symtab_iter;
+
+/** Get an iterator pointing to the first symbol in the symbol table.
+ * \param symtab symbol table
+ * \return Iterator for the symbol table.
+ */
+YASM_LIB_DECL
+const yasm_symtab_iter *yasm_symtab_first(const yasm_symtab *symtab);
+
+/** Move a symbol table iterator to the next symbol in the symbol table.
+ * \param prev Previous iterator value
+ * \return Next iterator value, or NULL if no more symbols in the table.
+ */
+YASM_LIB_DECL
+/*@null@*/ const yasm_symtab_iter *yasm_symtab_next
+ (const yasm_symtab_iter *prev);
+
+/** Get the symbol corresponding to the current symbol table iterator value.
+ * \param cur iterator value
+ * \return Corresponding symbol.
+ */
+YASM_LIB_DECL
+yasm_symrec *yasm_symtab_iter_value(const yasm_symtab_iter *cur);
+
+/** Finalize symbol table after parsing stage. Checks for symbols that are
+ * used but never defined or declared #YASM_SYM_EXTERN or #YASM_SYM_COMMON.
+ * \param symtab symbol table
+ * \param undef_extern if nonzero, all undef syms should be declared extern
+ * \param errwarns error/warning set
+ * \note Errors/warnings are stored into errwarns.
+ */
+YASM_LIB_DECL
+void yasm_symtab_parser_finalize(yasm_symtab *symtab, int undef_extern,
+ yasm_errwarns *errwarns);
+
+/** Print the symbol table. For debugging purposes.
+ * \param symtab symbol table
+ * \param f file
+ * \param indent_level indentation level
+ */
+YASM_LIB_DECL
+void yasm_symtab_print(yasm_symtab *symtab, FILE *f, int indent_level);
+
+/** Get the name of a symbol.
+ * \param sym symbol
+ * \return Symbol name.
+ */
+YASM_LIB_DECL
+/*@observer@*/ const char *yasm_symrec_get_name(const yasm_symrec *sym);
+
+/** Get the externally-visible (global) name of a symbol.
+ * \param sym symbol
+ * \param object object
+ * \return Externally-visible symbol name (allocated, caller must free).
+ */
+YASM_LIB_DECL
+/*@only@*/ char *yasm_symrec_get_global_name(const yasm_symrec *sym,
+ const yasm_object *object);
+
+/** Get the visibility of a symbol.
+ * \param sym symbol
+ * \return Symbol visibility.
+ */
+YASM_LIB_DECL
+yasm_sym_vis yasm_symrec_get_visibility(const yasm_symrec *sym);
+
+/** Get the status of a symbol.
+ * \param sym symbol
+ * \return Symbol status.
+ */
+YASM_LIB_DECL
+yasm_sym_status yasm_symrec_get_status(const yasm_symrec *sym);
+
+/** Get the virtual line of where a symbol was first defined.
+ * \param sym symbol
+ * \return line virtual line
+ */
+YASM_LIB_DECL
+unsigned long yasm_symrec_get_def_line(const yasm_symrec *sym);
+
+/** Get the virtual line of where a symbol was first declared.
+ * \param sym symbol
+ * \return line virtual line
+ */
+YASM_LIB_DECL
+unsigned long yasm_symrec_get_decl_line(const yasm_symrec *sym);
+
+/** Get the virtual line of where a symbol was first used.
+ * \param sym symbol
+ * \return line virtual line
+ */
+YASM_LIB_DECL
+unsigned long yasm_symrec_get_use_line(const yasm_symrec *sym);
+
+/** Get EQU value of a symbol.
+ * \param sym symbol
+ * \return EQU value, or NULL if symbol is not an EQU or is not defined.
+ */
+YASM_LIB_DECL
+/*@observer@*/ /*@null@*/ const yasm_expr *yasm_symrec_get_equ
+ (const yasm_symrec *sym);
+
+/** Dependent pointer to a bytecode. */
+typedef /*@dependent@*/ yasm_bytecode *yasm_symrec_get_label_bytecodep;
+
+/** Get the label location of a symbol.
+ * \param sym symbol
+ * \param precbc bytecode preceding label (output)
+ * \return 0 if not symbol is not a label or if the symbol's visibility is
+ * #YASM_SYM_EXTERN or #YASM_SYM_COMMON (not defined in the file).
+ */
+YASM_LIB_DECL
+int yasm_symrec_get_label(const yasm_symrec *sym,
+ /*@out@*/ yasm_symrec_get_label_bytecodep *precbc);
+
+/** Set the size of a symbol.
+ * \param sym symbol
+ * \param size size to be set
+ */
+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
+ * \return 0 if symbol is not the "absolute" symbol, nonzero otherwise.
+ */
+YASM_LIB_DECL
+int yasm_symrec_is_abs(const yasm_symrec *sym);
+
+/** Determine if symbol is a special symbol.
+ * \param sym symbol
+ * \return 0 if symbol is not a special symbol, nonzero otherwise.
+ */
+YASM_LIB_DECL
+int yasm_symrec_is_special(const yasm_symrec *sym);
+
+/** Determine if symbol is a label representing the current assembly position.
+ * \param sym symbol
+ * \return 0 if symbol is not a current position label, nonzero otherwise.
+ */
+YASM_LIB_DECL
+int yasm_symrec_is_curpos(const yasm_symrec *sym);
+
+/** Set object-extended valparams.
+ * \param sym symbol
+ * \param objext_valparams object-extended valparams
+ */
+YASM_LIB_DECL
+void yasm_symrec_set_objext_valparams
+ (yasm_symrec *sym, /*@only@*/ yasm_valparamhead *objext_valparams);
+
+/** Get object-extended valparams, if any, associated with symbol's
+ * declaration.
+ * \param sym symbol
+ * \return Object-extended valparams (NULL if none).
+ */
+YASM_LIB_DECL
+/*@null@*/ /*@dependent@*/ yasm_valparamhead *yasm_symrec_get_objext_valparams
+ (yasm_symrec *sym);
+
+/** Set common size of symbol.
+ * \param sym symbol
+ * \param common_size common size expression
+ */
+YASM_LIB_DECL
+void yasm_symrec_set_common_size
+ (yasm_symrec *sym, /*@only@*/ yasm_expr *common_size);
+
+/** Get common size of symbol, if symbol is declared COMMON and a size was set
+ * for it.
+ * \param sym symbol
+ * \return Common size (NULL if none).
+ */
+YASM_LIB_DECL
+/*@dependent@*/ /*@null@*/ yasm_expr **yasm_symrec_get_common_size
+ (yasm_symrec *sym);
+
+/** Get associated data for a symbol and data callback.
+ * \param sym symbol
+ * \param callback callback used when adding data
+ * \return Associated data (NULL if none).
+ */
+YASM_LIB_DECL
+/*@dependent@*/ /*@null@*/ void *yasm_symrec_get_data
+ (yasm_symrec *sym, const yasm_assoc_data_callback *callback);
+
+/** Add associated data to a symbol.
+ * \attention Deletes any existing associated data for that data callback.
+ * \param sym symbol
+ * \param callback callback
+ * \param data data to associate
+ */
+YASM_LIB_DECL
+void yasm_symrec_add_data(yasm_symrec *sym,
+ const yasm_assoc_data_callback *callback,
+ /*@only@*/ /*@null@*/ void *data);
+
+/** Print a symbol. For debugging purposes.
+ * \param f file
+ * \param indent_level indentation level
+ * \param sym symbol
+ */
+YASM_LIB_DECL
+void yasm_symrec_print(const yasm_symrec *sym, FILE *f, int indent_level);
+
+#endif
diff --git a/libyasm/tests/1shl0.asm b/libyasm/tests/1shl0.asm
new file mode 100644
index 0000000..d69930a
--- /dev/null
+++ b/libyasm/tests/1shl0.asm
@@ -0,0 +1 @@
+dd (1<<0)
diff --git a/libyasm/tests/1shl0.hex b/libyasm/tests/1shl0.hex
new file mode 100644
index 0000000..607fb55
--- /dev/null
+++ b/libyasm/tests/1shl0.hex
@@ -0,0 +1,4 @@
+01
+00
+00
+00
diff --git a/libyasm/tests/Makefile.inc b/libyasm/tests/Makefile.inc
new file mode 100644
index 0000000..9c038a1
--- /dev/null
+++ b/libyasm/tests/Makefile.inc
@@ -0,0 +1,114 @@
+TESTS += bitvect_test
+TESTS += floatnum_test
+TESTS += leb128_test
+TESTS += splitpath_test
+TESTS += combpath_test
+TESTS += uncstring_test
+TESTS += libyasm/tests/libyasm_test.sh
+
+EXTRA_DIST += libyasm/tests/libyasm_test.sh
+EXTRA_DIST += libyasm/tests/1shl0.asm
+EXTRA_DIST += libyasm/tests/1shl0.hex
+EXTRA_DIST += libyasm/tests/absloop-err.asm
+EXTRA_DIST += libyasm/tests/absloop-err.errwarn
+EXTRA_DIST += libyasm/tests/charconst64.asm
+EXTRA_DIST += libyasm/tests/charconst64.hex
+EXTRA_DIST += libyasm/tests/data-rawvalue.asm
+EXTRA_DIST += libyasm/tests/data-rawvalue.hex
+EXTRA_DIST += libyasm/tests/duplabel-err.asm
+EXTRA_DIST += libyasm/tests/duplabel-err.errwarn
+EXTRA_DIST += libyasm/tests/emptydata.asm
+EXTRA_DIST += libyasm/tests/emptydata.hex
+EXTRA_DIST += libyasm/tests/equ-expand.asm
+EXTRA_DIST += libyasm/tests/equ-expand.hex
+EXTRA_DIST += libyasm/tests/expr-fold-level.asm
+EXTRA_DIST += libyasm/tests/expr-fold-level.hex
+EXTRA_DIST += libyasm/tests/expr-simplify-identity.asm
+EXTRA_DIST += libyasm/tests/expr-simplify-identity.hex
+EXTRA_DIST += libyasm/tests/expr-wide-ident.asm
+EXTRA_DIST += libyasm/tests/expr-wide-ident.hex
+EXTRA_DIST += libyasm/tests/externdef.asm
+EXTRA_DIST += libyasm/tests/externdef.errwarn
+EXTRA_DIST += libyasm/tests/externdef.hex
+EXTRA_DIST += libyasm/tests/incbin.asm
+EXTRA_DIST += libyasm/tests/incbin.hex
+EXTRA_DIST += libyasm/tests/jmpsize1.asm
+EXTRA_DIST += libyasm/tests/jmpsize1.hex
+EXTRA_DIST += libyasm/tests/jmpsize1-err.asm
+EXTRA_DIST += libyasm/tests/jmpsize1-err.errwarn
+EXTRA_DIST += libyasm/tests/opt-align1.asm
+EXTRA_DIST += libyasm/tests/opt-align1.hex
+EXTRA_DIST += libyasm/tests/opt-align2.asm
+EXTRA_DIST += libyasm/tests/opt-align2.hex
+EXTRA_DIST += libyasm/tests/opt-align3.asm
+EXTRA_DIST += libyasm/tests/opt-align3.hex
+EXTRA_DIST += libyasm/tests/opt-circular1-err.asm
+EXTRA_DIST += libyasm/tests/opt-circular1-err.errwarn
+EXTRA_DIST += libyasm/tests/opt-circular2-err.asm
+EXTRA_DIST += libyasm/tests/opt-circular2-err.errwarn
+EXTRA_DIST += libyasm/tests/opt-circular3-err.asm
+EXTRA_DIST += libyasm/tests/opt-circular3-err.errwarn
+EXTRA_DIST += libyasm/tests/opt-gvmat64.asm
+EXTRA_DIST += libyasm/tests/opt-gvmat64.hex
+EXTRA_DIST += libyasm/tests/opt-immexpand.asm
+EXTRA_DIST += libyasm/tests/opt-immexpand.hex
+EXTRA_DIST += libyasm/tests/opt-immnoexpand.asm
+EXTRA_DIST += libyasm/tests/opt-immnoexpand.hex
+EXTRA_DIST += libyasm/tests/opt-oldalign.asm
+EXTRA_DIST += libyasm/tests/opt-oldalign.hex
+EXTRA_DIST += libyasm/tests/opt-struc.asm
+EXTRA_DIST += libyasm/tests/opt-struc.hex
+EXTRA_DIST += libyasm/tests/reserve-err1.asm
+EXTRA_DIST += libyasm/tests/reserve-err1.errwarn
+EXTRA_DIST += libyasm/tests/reserve-err2.asm
+EXTRA_DIST += libyasm/tests/reserve-err2.errwarn
+EXTRA_DIST += libyasm/tests/strucsize.asm
+EXTRA_DIST += libyasm/tests/strucsize.hex
+EXTRA_DIST += libyasm/tests/times0.asm
+EXTRA_DIST += libyasm/tests/times0.hex
+EXTRA_DIST += libyasm/tests/timesfwd.asm
+EXTRA_DIST += libyasm/tests/timesfwd.hex
+EXTRA_DIST += libyasm/tests/timesover-err.asm
+EXTRA_DIST += libyasm/tests/timesover-err.errwarn
+EXTRA_DIST += libyasm/tests/timesunder.asm
+EXTRA_DIST += libyasm/tests/timesunder.hex
+EXTRA_DIST += libyasm/tests/times-res.asm
+EXTRA_DIST += libyasm/tests/times-res.errwarn
+EXTRA_DIST += libyasm/tests/times-res.hex
+EXTRA_DIST += libyasm/tests/unary.asm
+EXTRA_DIST += libyasm/tests/unary.hex
+EXTRA_DIST += libyasm/tests/value-err.asm
+EXTRA_DIST += libyasm/tests/value-err.errwarn
+EXTRA_DIST += libyasm/tests/value-samesym.asm
+EXTRA_DIST += libyasm/tests/value-samesym.errwarn
+EXTRA_DIST += libyasm/tests/value-samesym.hex
+EXTRA_DIST += libyasm/tests/value-mask.asm
+EXTRA_DIST += libyasm/tests/value-mask.errwarn
+EXTRA_DIST += libyasm/tests/value-mask.hex
+EXTRA_DIST += libyasm/tests/value-shr-symexpr.asm
+EXTRA_DIST += libyasm/tests/value-shr-symexpr.hex
+
+check_PROGRAMS += bitvect_test
+check_PROGRAMS += floatnum_test
+check_PROGRAMS += leb128_test
+check_PROGRAMS += splitpath_test
+check_PROGRAMS += combpath_test
+check_PROGRAMS += uncstring_test
+
+bitvect_test_SOURCES = libyasm/tests/bitvect_test.c
+bitvect_test_LDADD = libyasm.a $(INTLLIBS)
+
+floatnum_test_SOURCES = libyasm/tests/floatnum_test.c
+floatnum_test_LDADD = libyasm.a $(INTLLIBS)
+
+leb128_test_SOURCES = libyasm/tests/leb128_test.c
+leb128_test_LDADD = libyasm.a $(INTLLIBS)
+
+splitpath_test_SOURCES = libyasm/tests/splitpath_test.c
+splitpath_test_LDADD = libyasm.a $(INTLLIBS)
+
+combpath_test_SOURCES = libyasm/tests/combpath_test.c
+combpath_test_LDADD = libyasm.a $(INTLLIBS)
+
+uncstring_test_SOURCES = libyasm/tests/uncstring_test.c
+uncstring_test_LDADD = libyasm.a $(INTLLIBS)
diff --git a/libyasm/tests/absloop-err.asm b/libyasm/tests/absloop-err.asm
new file mode 100644
index 0000000..27e88a0
--- /dev/null
+++ b/libyasm/tests/absloop-err.asm
@@ -0,0 +1,6 @@
+[absolute x]
+label1:
+[absolute label1]
+x:
+[section .text]
+mov ax, [x]
diff --git a/libyasm/tests/absloop-err.errwarn b/libyasm/tests/absloop-err.errwarn
new file mode 100644
index 0000000..29d3a33
--- /dev/null
+++ b/libyasm/tests/absloop-err.errwarn
@@ -0,0 +1 @@
+-:6: error: circular reference detected in memory expression
diff --git a/libyasm/tests/bitvect_test.c b/libyasm/tests/bitvect_test.c
new file mode 100644
index 0000000..f7b3413
--- /dev/null
+++ b/libyasm/tests/bitvect_test.c
@@ -0,0 +1,176 @@
+/*
+ *
+ * Copyright (C) 2001-2007 Peter Johnson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "libyasm/bitvect.h"
+
+static int
+test_boot(void)
+{
+ if (BitVector_Boot() != ErrCode_Ok)
+ return 1;
+ return 0;
+}
+
+typedef struct Val_s {
+ const char *ascii;
+ unsigned char result[10]; /* 80 bit result, little endian */
+} Val;
+
+Val oct_small_vals[] = {
+ { "0",
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
+ },
+ { "1",
+ {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
+ },
+ { "77",
+ {0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
+ },
+};
+
+Val oct_large_vals[] = {
+ { "7654321076543210",
+ {0x88, 0xC6, 0xFA, 0x88, 0xC6, 0xFA, 0x00, 0x00, 0x00, 0x00}
+ },
+ { "12634727612534126530214",
+ {0x8C, 0xB0, 0x5A, 0xE1, 0xAA, 0xF8, 0x3A, 0x67, 0x05, 0x00}
+ },
+ { "61076543210",
+ {0x88, 0xC6, 0xFA, 0x88, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00}
+ },
+};
+
+wordptr testval;
+
+static void
+num_family_setup(void)
+{
+ BitVector_Boot();
+ testval = BitVector_Create(80, FALSE);
+}
+
+static void
+num_family_teardown(void)
+{
+ BitVector_Destroy(testval);
+}
+
+static char result_msg[1024];
+
+static int
+num_check(Val *val)
+{
+ unsigned char ascii[64], *result;
+ unsigned int len;
+ int i;
+ int ret = 0;
+
+ strcpy((char *)ascii, val->ascii);
+ strcpy(result_msg, "parser failure");
+ if(BitVector_from_Oct(testval, ascii) != ErrCode_Ok)
+ return 1;
+
+ result = BitVector_Block_Read(testval, &len);
+
+ for (i=0; i<10; i++)
+ if (result[i] != val->result[i])
+ ret = 1;
+
+ if (ret) {
+ strcpy(result_msg, val->ascii);
+ for (i=0; i<10; i++)
+ sprintf((char *)ascii+3*i, "%02x ", result[i]);
+ strcat(result_msg, ": ");
+ strcat(result_msg, (char *)ascii);
+ }
+ free(result);
+
+ return ret;
+}
+
+static int
+test_oct_small_num(void)
+{
+ Val *vals = oct_small_vals;
+ int i, num = sizeof(oct_small_vals)/sizeof(Val);
+
+ for (i=0; i<num; i++) {
+ if (num_check(&vals[i]) != 0)
+ return 1;
+ }
+ return 0;
+}
+
+static int
+test_oct_large_num(void)
+{
+ Val *vals = oct_large_vals;
+ int i, num = sizeof(oct_large_vals)/sizeof(Val);
+
+ for (i=0; i<num; i++) {
+ if (num_check(&vals[i]) != 0)
+ return 1;
+ }
+ return 0;
+}
+
+char failed[1000];
+
+static int
+runtest_(const char *testname, int (*testfunc)(void), void (*setup)(void),
+ void (*teardown)(void))
+{
+ int nf;
+ if (setup)
+ setup();
+ nf = testfunc();
+ if (teardown)
+ teardown();
+ printf("%c", nf>0 ? 'F':'.');
+ fflush(stdout);
+ if (nf > 0)
+ sprintf(failed, "%s ** F: %s failed!\n", failed, testname);
+ return nf;
+}
+#define runtest(x,y,z) runtest_(#x,test_##x,y,z)
+
+int
+main(void)
+{
+ int nf = 0;
+
+ failed[0] = '\0';
+ printf("Test bitvect_test: ");
+ nf += runtest(boot, NULL, NULL);
+ nf += runtest(oct_small_num, num_family_setup, num_family_teardown);
+ nf += runtest(oct_large_num, num_family_setup, num_family_teardown);
+ printf(" +%d-%d/3 %d%%\n%s",
+ 3-nf, nf, 100*(3-nf)/3, failed);
+ return (nf == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/libyasm/tests/charconst64.asm b/libyasm/tests/charconst64.asm
new file mode 100644
index 0000000..57856c0
--- /dev/null
+++ b/libyasm/tests/charconst64.asm
@@ -0,0 +1,3 @@
+[bits 64]
+
+mov rax, '12345678'
diff --git a/libyasm/tests/charconst64.hex b/libyasm/tests/charconst64.hex
new file mode 100644
index 0000000..66b893c
--- /dev/null
+++ b/libyasm/tests/charconst64.hex
@@ -0,0 +1,10 @@
+48
+b8
+31
+32
+33
+34
+35
+36
+37
+38
diff --git a/libyasm/tests/combpath_test.c b/libyasm/tests/combpath_test.c
new file mode 100644
index 0000000..90f2e24
--- /dev/null
+++ b/libyasm/tests/combpath_test.c
@@ -0,0 +1,139 @@
+/*
+ *
+ * Copyright (C) 2006-2007 Peter Johnson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "libyasm/file.h"
+#include "libyasm/coretype.h"
+
+typedef struct Test_Entry {
+ /* combpath function to test */
+ char * (*combpath) (const char *from, const char *to);
+
+ /* input "from" path */
+ const char *from;
+
+ /* input "to" path */
+ const char *to;
+
+ /* correct path returned */
+ const char *out;
+} Test_Entry;
+
+static Test_Entry tests[] = {
+ /* UNIX */
+ {yasm__combpath_unix, "file1", "file2", "file2"},
+ {yasm__combpath_unix, "./file1.ext", "./file2.ext", "file2.ext"},
+ {yasm__combpath_unix, "/file1", "file2", "/file2"},
+ {yasm__combpath_unix, "file1", "/file2", "/file2"},
+ {yasm__combpath_unix, "/foo/file1", "../../file2", "/file2"},
+ {yasm__combpath_unix, "/foo//file1", "../../file2", "/file2"},
+ {yasm__combpath_unix, "foo/bar/file1", "../file2", "foo/file2"},
+ {yasm__combpath_unix, "foo/bar/file1", "../../../file2", "../file2"},
+ {yasm__combpath_unix, "foo/bar//file1", "../..//..//file2", "../file2"},
+ {yasm__combpath_unix, "foo/bar/", "file2", "foo/bar/file2"},
+ {yasm__combpath_unix, "../../file1", "../../file2", "../../../../file2"},
+ {yasm__combpath_unix, "../foo/bar/../file1", "../../file2", "../foo/bar/../../../file2"},
+ {yasm__combpath_unix, "/", "../file2", "/file2"},
+ {yasm__combpath_unix, "../foo/", "../file2", "../file2"},
+ {yasm__combpath_unix, "../foo/file1", "../../bar/file2", "../../bar/file2"},
+
+ /* Windows */
+ {yasm__combpath_win, "file1", "file2", "file2"},
+ {yasm__combpath_win, "./file1.ext", "./file2.ext", "file2.ext"},
+ {yasm__combpath_win, "./file1.ext", ".\\file2.ext", "file2.ext"},
+ {yasm__combpath_win, ".\\file1.ext", "./file2.ext", "file2.ext"},
+ {yasm__combpath_win, "/file1", "file2", "\\file2"},
+ {yasm__combpath_win, "\\file1", "file2", "\\file2"},
+ {yasm__combpath_win, "file1", "/file2", "\\file2"},
+ {yasm__combpath_win, "file1", "\\file2", "\\file2"},
+ {yasm__combpath_win, "/foo\\file1", "../../file2", "\\file2"},
+ {yasm__combpath_win, "\\foo\\\\file1", "..\\../file2", "\\file2"},
+ {yasm__combpath_win, "foo/bar/file1", "../file2", "foo\\file2"},
+ {yasm__combpath_win, "foo/bar/file1", "../..\\../file2", "..\\file2"},
+ {yasm__combpath_win, "foo/bar//file1", "../..\\\\..//file2", "..\\file2"},
+ {yasm__combpath_win, "foo/bar/", "file2", "foo\\bar\\file2"},
+ {yasm__combpath_win, "..\\../file1", "../..\\file2", "..\\..\\..\\..\\file2"},
+ {yasm__combpath_win, "../foo/bar\\\\../file1", "../..\\file2", "..\\foo\\bar\\..\\..\\..\\file2"},
+ {yasm__combpath_win, "/", "../file2", "\\file2"},
+ {yasm__combpath_win, "../foo/", "../file2", "..\\file2"},
+ {yasm__combpath_win, "../foo/file1", "../..\\bar\\file2", "..\\..\\bar\\file2"},
+ {yasm__combpath_win, "c:/file1.ext", "./file2.ext", "c:\\file2.ext"},
+ {yasm__combpath_win, "e:\\path\\to/file1.ext", ".\\file2.ext", "e:\\path\\to\\file2.ext"},
+ {yasm__combpath_win, ".\\file1.ext", "g:file2.ext", "g:file2.ext"},
+};
+
+static char failed[1000];
+static char failmsg[100];
+
+static int
+run_test(Test_Entry *test)
+{
+ char *out;
+ const char *funcname;
+
+ if (test->combpath == &yasm__combpath_unix)
+ funcname = "unix";
+ else
+ funcname = "win";
+
+ out = test->combpath(test->from, test->to);
+
+ if (strcmp(out, test->out) != 0) {
+ sprintf(failmsg,
+ "combpath_%s(\"%s\", \"%s\"): expected \"%s\", got \"%s\"!",
+ funcname, test->from, test->to, test->out, out);
+ yasm_xfree(out);
+ return 1;
+ }
+
+ yasm_xfree(out);
+ return 0;
+}
+
+int
+main(void)
+{
+ int nf = 0;
+ int numtests = sizeof(tests)/sizeof(Test_Entry);
+ int i;
+
+ failed[0] = '\0';
+ printf("Test combpath_test: ");
+ for (i=0; i<numtests; i++) {
+ int fail = run_test(&tests[i]);
+ printf("%c", fail>0 ? 'F':'.');
+ fflush(stdout);
+ if (fail)
+ sprintf(failed, "%s ** F: %s\n", failed, failmsg);
+ nf += fail;
+ }
+
+ printf(" +%d-%d/%d %d%%\n%s",
+ numtests-nf, nf, numtests, 100*(numtests-nf)/numtests, failed);
+ return (nf == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/libyasm/tests/data-rawvalue.asm b/libyasm/tests/data-rawvalue.asm
new file mode 100644
index 0000000..3ebc7d0
--- /dev/null
+++ b/libyasm/tests/data-rawvalue.asm
@@ -0,0 +1,3 @@
+x db 0
+dd 0,x,0
+
diff --git a/libyasm/tests/data-rawvalue.hex b/libyasm/tests/data-rawvalue.hex
new file mode 100644
index 0000000..089b49c
--- /dev/null
+++ b/libyasm/tests/data-rawvalue.hex
@@ -0,0 +1,13 @@
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
diff --git a/libyasm/tests/duplabel-err.asm b/libyasm/tests/duplabel-err.asm
new file mode 100644
index 0000000..3d666b3
--- /dev/null
+++ b/libyasm/tests/duplabel-err.asm
@@ -0,0 +1,18 @@
+%macro TESTMAC 0
+label:
+ mov ax, 5
+ mov dx, 4
+ mov cx, 3
+%endmacro
+
+db 6
+
+db 7
+
+TESTMAC
+
+db 8
+db 9
+TESTMAC
+db 10
+TESTMAC
diff --git a/libyasm/tests/duplabel-err.errwarn b/libyasm/tests/duplabel-err.errwarn
new file mode 100644
index 0000000..4ce13bf
--- /dev/null
+++ b/libyasm/tests/duplabel-err.errwarn
@@ -0,0 +1,4 @@
+-:16: error: redefinition of `label'
+-:12: error: `label' previously defined here
+-:18: error: redefinition of `label'
+-:12: error: `label' previously defined here
diff --git a/libyasm/tests/emptydata.asm b/libyasm/tests/emptydata.asm
new file mode 100644
index 0000000..27b5651
--- /dev/null
+++ b/libyasm/tests/emptydata.asm
@@ -0,0 +1 @@
+db ''
diff --git a/libyasm/tests/emptydata.hex b/libyasm/tests/emptydata.hex
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/libyasm/tests/emptydata.hex
diff --git a/libyasm/tests/equ-expand.asm b/libyasm/tests/equ-expand.asm
new file mode 100644
index 0000000..eaa9421
--- /dev/null
+++ b/libyasm/tests/equ-expand.asm
@@ -0,0 +1,9 @@
+nop
+end1:
+
+line_out equ end1+258 ;length = 1 + 263
+real_end equ end1+258+264
+
+ cmp bx,(real_end-line_out)/4
+ cmp bx,((end1+258+264)-(end1+258))/4
+ cmp bx,(end1+258+264-end1-258)/4
diff --git a/libyasm/tests/equ-expand.hex b/libyasm/tests/equ-expand.hex
new file mode 100644
index 0000000..54a04f3
--- /dev/null
+++ b/libyasm/tests/equ-expand.hex
@@ -0,0 +1,10 @@
+90
+83
+fb
+42
+83
+fb
+42
+83
+fb
+42
diff --git a/libyasm/tests/expr-fold-level.asm b/libyasm/tests/expr-fold-level.asm
new file mode 100644
index 0000000..814a62c
--- /dev/null
+++ b/libyasm/tests/expr-fold-level.asm
@@ -0,0 +1,4 @@
+begin
+A equ 09000h
+a dd (A+(end-begin)+3)
+end
diff --git a/libyasm/tests/expr-fold-level.hex b/libyasm/tests/expr-fold-level.hex
new file mode 100644
index 0000000..aba10f6
--- /dev/null
+++ b/libyasm/tests/expr-fold-level.hex
@@ -0,0 +1,4 @@
+07
+90
+00
+00
diff --git a/libyasm/tests/expr-wide-ident.asm b/libyasm/tests/expr-wide-ident.asm
new file mode 100644
index 0000000..8a60e78
--- /dev/null
+++ b/libyasm/tests/expr-wide-ident.asm
@@ -0,0 +1,2 @@
+lea edx, [lentry+edx+ecx]
+lentry:
diff --git a/libyasm/tests/expr-wide-ident.hex b/libyasm/tests/expr-wide-ident.hex
new file mode 100644
index 0000000..f8d54ff
--- /dev/null
+++ b/libyasm/tests/expr-wide-ident.hex
@@ -0,0 +1,9 @@
+67
+66
+8d
+94
+0a
+09
+00
+00
+00
diff --git a/libyasm/tests/externdef.asm b/libyasm/tests/externdef.asm
new file mode 100644
index 0000000..3663af3
--- /dev/null
+++ b/libyasm/tests/externdef.asm
@@ -0,0 +1,2 @@
+extern foo
+foo:
diff --git a/libyasm/tests/externdef.errwarn b/libyasm/tests/externdef.errwarn
new file mode 100644
index 0000000..8ff4a7e
--- /dev/null
+++ b/libyasm/tests/externdef.errwarn
@@ -0,0 +1,2 @@
+-:1: warning: binary object format does not support extern variables
+-:2: warning: `foo' both defined and declared extern
diff --git a/libyasm/tests/externdef.hex b/libyasm/tests/externdef.hex
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/libyasm/tests/externdef.hex
diff --git a/libyasm/tests/floatnum_test.c b/libyasm/tests/floatnum_test.c
new file mode 100644
index 0000000..30b8d6c
--- /dev/null
+++ b/libyasm/tests/floatnum_test.c
@@ -0,0 +1,453 @@
+/*
+ *
+ * Copyright (C) 2001-2007 Peter Johnson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "libyasm/floatnum.c"
+
+/* constants describing parameters of internal floating point format.
+ * (these should match those in src/floatnum.c !)
+ */
+#define MANT_BITS 80
+#define MANT_BYTES 10
+
+typedef struct Init_Entry_s {
+ /* input ASCII value */
+ const char *ascii;
+
+ /* correct output from ASCII conversion */
+ unsigned char mantissa[MANT_BYTES]; /* little endian mantissa - first
+ byte is not checked for
+ correctness. */
+ unsigned short exponent; /* bias 32767 exponent */
+ unsigned char sign;
+ unsigned char flags;
+
+ /* correct output conversions - these should be *exact* matches */
+ int ret32;
+ unsigned char result32[4];
+ int ret64;
+ unsigned char result64[8];
+ int ret80;
+ unsigned char result80[10];
+} Init_Entry;
+
+/* Values used for normalized tests */
+static Init_Entry normalized_vals[] = {
+ { "3.141592653589793",
+ {0xc6,0x0d,0xe9,0xbd,0x68,0x21,0xa2,0xda,0x0f,0xc9},0x8000,0,0,
+ 0, {0xdb,0x0f,0x49,0x40},
+ 0, {0x18,0x2d,0x44,0x54,0xfb,0x21,0x09,0x40},
+ 0, {0xe9,0xbd,0x68,0x21,0xa2,0xda,0x0f,0xc9,0x00,0x40}
+ },
+ { "-3.141592653589793",
+ {0xc6,0x0d,0xe9,0xbd,0x68,0x21,0xa2,0xda,0x0f,0xc9},0x8000,1,0,
+ 0, {0xdb,0x0f,0x49,0xc0},
+ 0, {0x18,0x2d,0x44,0x54,0xfb,0x21,0x09,0xc0},
+ 0, {0xe9,0xbd,0x68,0x21,0xa2,0xda,0x0f,0xc9,0x00,0xc0}
+ },
+ { "1.e16",
+ {0x00,0x00,0x00,0x00,0x00,0x04,0xbf,0xc9,0x1b,0x8e},0x8034,0,0,
+ 0, {0xca,0x1b,0x0e,0x5a},
+ 0, {0x00,0x80,0xe0,0x37,0x79,0xc3,0x41,0x43},
+ 0, {0x00,0x00,0x00,0x04,0xbf,0xc9,0x1b,0x8e,0x34,0x40}
+ },
+ { "1.6e-20",
+ {0xf6,0xd3,0xee,0x7b,0xda,0x74,0x50,0xa0,0x1d,0x97},0x7fbd,0,0,
+ 0, {0xa0,0x1d,0x97,0x1e},
+ 0, {0x4f,0x9b,0x0e,0x0a,0xb4,0xe3,0xd2,0x3b},
+ 0, {0xef,0x7b,0xda,0x74,0x50,0xa0,0x1d,0x97,0xbd,0x3f}
+ },
+ { "-5876.",
+ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0xb7},0x800b,1,0,
+ 0, {0x00,0xa0,0xb7,0xc5},
+ 0, {0x00,0x00,0x00,0x00,0x00,0xf4,0xb6,0xc0},
+ 0, {0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0xb7,0x0b,0xc0}
+ },
+ /* Edge cases for rounding wrap. */
+ { "1.00000",
+ {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff},0x7ffe,0,0,
+ 0, {0x00,0x00,0x80,0x3f},
+ 0, {0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0x3f},
+ 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xff,0x3f}
+ },
+ { "1.000000",
+ {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff},0x7ffe,0,0,
+ 0, {0x00,0x00,0x80,0x3f},
+ 0, {0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0x3f},
+ 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xff,0x3f}
+ },
+};
+
+/* Still normalized values, but edge cases of various sizes, testing underflow/
+ * overflow checks as well.
+ */
+static Init_Entry normalized_edgecase_vals[] = {
+ /* 32-bit edges */
+ { "1.1754943508222875e-38",
+ {0xd5,0xf2,0x82,0xff,0xff,0xff,0xff,0xff,0xff,0xff},0x7f80,0,0,
+ 0, {0x00,0x00,0x80,0x00},
+ 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x38},
+ 0, {0x83,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x80,0x3f}
+ },
+ { "3.4028234663852886e+38",
+ {0x21,0x35,0x0a,0x00,0x00,0x00,0x00,0xff,0xff,0xff},0x807e,0,0,
+ 0, {0xff,0xff,0x7f,0x7f},
+ 0, {0x00,0x00,0x00,0xe0,0xff,0xff,0xef,0x47},
+ 0, {0x0a,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0x7e,0x40}
+ },
+ /* 64-bit edges */
+ { "2.2250738585072014E-308",
+ {0x26,0x18,0x46,0x00,0x00,0x00,0x00,0x00,0x00,0x80},0x7c01,0,0,
+ -1, {0x00,0x00,0x00,0x00},
+ 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00},
+ 0, {0x46,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x01,0x3c}
+ },
+ { "1.7976931348623157E+308",
+ {0x26,0x6b,0xac,0xf7,0xff,0xff,0xff,0xff,0xff,0xff},0x83fe,0,0,
+ 1, {0x00,0x00,0x80,0x7f},
+ 0, {0xff,0xff,0xff,0xff,0xff,0xff,0xef,0x7f},
+ 0, {0xac,0xf7,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0x43}
+ },
+ /* 80-bit edges */
+/* { "3.3621E-4932",
+ {},,0,0,
+ -1, {0x00,0x00,0x00,0x00},
+ -1, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
+ 0, {}
+ },
+ { "1.1897E+4932",
+ {},,0,0,
+ 1, {0x00,0x00,0x80,0x7f},
+ 1, {},
+ 0, {}
+ },*/
+ /* internal format edges */
+/* {
+ },
+ {
+ },*/
+};
+
+static yasm_floatnum *flt;
+
+/* failure messages */
+static char ret_msg[1024], result_msg[1024];
+
+static void
+new_setup(Init_Entry *vals, int i)
+{
+ flt = yasm_floatnum_create(vals[i].ascii);
+ strcpy(result_msg, vals[i].ascii);
+ strcat(result_msg, ": incorrect ");
+}
+
+static int
+new_check_flt(Init_Entry *val)
+{
+ unsigned char *mantissa;
+ int i, result = 0;
+ unsigned int len;
+
+ mantissa = BitVector_Block_Read(flt->mantissa, &len);
+ for (i=1;i<MANT_BYTES;i++) /* don't compare first byte */
+ if (mantissa[i] != val->mantissa[i])
+ result = 1;
+ free(mantissa);
+ if (result) {
+ strcat(result_msg, "mantissa");
+ return 1;
+ }
+
+ if (flt->exponent != val->exponent) {
+ strcat(result_msg, "exponent");
+ return 1;
+ }
+ if (flt->sign != val->sign) {
+ strcat(result_msg, "sign");
+ return 1;
+ }
+ if (flt->flags != val->flags) {
+ strcat(result_msg, "flags");
+ return 1;
+ }
+ return 0;
+}
+
+static int
+test_new_normalized(void)
+{
+ Init_Entry *vals = normalized_vals;
+ int i, num = sizeof(normalized_vals)/sizeof(Init_Entry);
+
+ for (i=0; i<num; i++) {
+ new_setup(vals, i);
+ if (new_check_flt(&vals[i]) != 0)
+ return 1;
+ yasm_floatnum_destroy(flt);
+ }
+ return 0;
+}
+
+static int
+test_new_normalized_edgecase(void)
+{
+ Init_Entry *vals = normalized_edgecase_vals;
+ int i, num = sizeof(normalized_edgecase_vals)/sizeof(Init_Entry);
+
+ for (i=0; i<num; i++) {
+ new_setup(vals, i);
+ if (new_check_flt(&vals[i]) != 0)
+ return 1;
+ yasm_floatnum_destroy(flt);
+ }
+ return 0;
+}
+
+static void
+get_family_setup(void)
+{
+ flt = malloc(sizeof(yasm_floatnum));
+ flt->mantissa = BitVector_Create(MANT_BITS, TRUE);
+}
+
+static void
+get_family_teardown(void)
+{
+ BitVector_Destroy(flt->mantissa);
+ free(flt);
+}
+
+static void
+get_common_setup(Init_Entry *vals, int i)
+{
+ /* set up flt */
+ BitVector_Block_Store(flt->mantissa, vals[i].mantissa, MANT_BYTES);
+ flt->sign = vals[i].sign;
+ flt->exponent = vals[i].exponent;
+ flt->flags = vals[i].flags;
+
+ /* set failure messages */
+ strcpy(ret_msg, vals[i].ascii);
+ strcat(ret_msg, ": incorrect return value");
+ strcpy(result_msg, vals[i].ascii);
+ strcat(result_msg, ": incorrect result generated");
+}
+#if 0
+static void
+append_get_return_value(int val)
+{
+ char str[64];
+ sprintf(str, ": %d", val);
+ strcat(ret_msg, str);
+}
+#endif
+static int
+get_common_check_result(int len, const unsigned char *val,
+ const unsigned char *correct)
+{
+ char str[64];
+ int i;
+ int result = 0;
+
+ for (i=0;i<len;i++)
+ if (val[i] != correct[i])
+ result = 1;
+
+ if (result) {
+ for (i=0; i<len; i++)
+ sprintf(str+3*i, "%02x ", val[i]);
+ strcat(result_msg, ": ");
+ strcat(result_msg, str);
+ }
+
+ return result;
+}
+
+/*
+ * get_single tests
+ */
+
+static int
+test_get_single_normalized(void)
+{
+ unsigned char outval[4];
+ Init_Entry *vals = normalized_vals;
+ int i, num = sizeof(normalized_vals)/sizeof(Init_Entry);
+
+ for (i=0; i<num; i++) {
+ get_common_setup(vals, i);
+ if (yasm_floatnum_get_sized(flt, outval, 4, 32, 0, 0, 0) !=
+ vals[i].ret32)
+ return 1;
+ if (get_common_check_result(4, outval, vals[i].result32) != 0)
+ return 1;
+ }
+ return 0;
+}
+
+static int
+test_get_single_normalized_edgecase(void)
+{
+ unsigned char outval[4];
+ Init_Entry *vals = normalized_edgecase_vals;
+ int i, num = sizeof(normalized_edgecase_vals)/sizeof(Init_Entry);
+
+ for (i=0; i<num; i++) {
+ get_common_setup(vals, i);
+ if (yasm_floatnum_get_sized(flt, outval, 4, 32, 0, 0, 0) !=
+ vals[i].ret32)
+ return 1;
+ if (get_common_check_result(4, outval, vals[i].result32) != 0)
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * get_double tests
+ */
+
+static int
+test_get_double_normalized(void)
+{
+ unsigned char outval[8];
+ Init_Entry *vals = normalized_vals;
+ int i, num = sizeof(normalized_vals)/sizeof(Init_Entry);
+
+ for (i=0; i<num; i++) {
+ get_common_setup(vals, i);
+ if (yasm_floatnum_get_sized(flt, outval, 8, 64, 0, 0, 0) !=
+ vals[i].ret64)
+ return 1;
+ if (get_common_check_result(8, outval, vals[i].result64) != 0)
+ return 1;
+ }
+ return 0;
+}
+
+static int
+test_get_double_normalized_edgecase(void)
+{
+ unsigned char outval[8];
+ Init_Entry *vals = normalized_edgecase_vals;
+ int i, num = sizeof(normalized_edgecase_vals)/sizeof(Init_Entry);
+
+ for (i=0; i<num; i++) {
+ get_common_setup(vals, i);
+ if (yasm_floatnum_get_sized(flt, outval, 8, 64, 0, 0, 0) !=
+ vals[i].ret64)
+ return 1;
+ if (get_common_check_result(8, outval, vals[i].result64) != 0)
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * get_extended tests
+ */
+
+static int
+test_get_extended_normalized(void)
+{
+ unsigned char outval[10];
+ Init_Entry *vals = normalized_vals;
+ int i, num = sizeof(normalized_vals)/sizeof(Init_Entry);
+
+ for (i=0; i<num; i++) {
+ get_common_setup(vals, i);
+ if (yasm_floatnum_get_sized(flt, outval, 10, 80, 0, 0, 0) !=
+ vals[i].ret80)
+ return 1;
+ if (get_common_check_result(10, outval, vals[i].result80) != 0)
+ return 1;
+ }
+ return 0;
+}
+
+static int
+test_get_extended_normalized_edgecase(void)
+{
+ unsigned char outval[10];
+ Init_Entry *vals = normalized_edgecase_vals;
+ int i, num = sizeof(normalized_edgecase_vals)/sizeof(Init_Entry);
+
+ for (i=0; i<num; i++) {
+ get_common_setup(vals, i);
+ if (yasm_floatnum_get_sized(flt, outval, 10, 80, 0, 0, 0) !=
+ vals[i].ret80)
+ return 1;
+ if (get_common_check_result(10, outval, vals[i].result80) != 0)
+ return 1;
+ }
+ return 0;
+}
+
+char failed[1000];
+
+static int
+runtest_(const char *testname, int (*testfunc)(void), void (*setup)(void),
+ void (*teardown)(void))
+{
+ int nf;
+ if (setup)
+ setup();
+ nf = testfunc();
+ if (teardown)
+ teardown();
+ printf("%c", nf>0 ? 'F':'.');
+ fflush(stdout);
+ if (nf > 0)
+ sprintf(failed, "%s ** F: %s failed: %s!\n", failed, testname,
+ result_msg);
+ return nf;
+}
+#define runtest(x,y,z) runtest_(#x,test_##x,y,z)
+
+int
+main(void)
+{
+ int nf = 0;
+ if (BitVector_Boot() != ErrCode_Ok)
+ return EXIT_FAILURE;
+ yasm_floatnum_initialize();
+
+ failed[0] = '\0';
+ printf("Test floatnum_test: ");
+ nf += runtest(new_normalized, NULL, NULL);
+ nf += runtest(new_normalized_edgecase, NULL, NULL);
+ nf += runtest(get_single_normalized, get_family_setup, get_family_teardown);
+ nf += runtest(get_single_normalized_edgecase, get_family_setup, get_family_teardown);
+ nf += runtest(get_double_normalized, get_family_setup, get_family_teardown);
+ nf += runtest(get_double_normalized_edgecase, get_family_setup, get_family_teardown);
+ nf += runtest(get_extended_normalized, get_family_setup, get_family_teardown);
+ nf += runtest(get_extended_normalized_edgecase, get_family_setup, get_family_teardown);
+ printf(" +%d-%d/8 %d%%\n%s",
+ 8-nf, nf, 100*(8-nf)/8, failed);
+ return (nf == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/libyasm/tests/incbin.asm b/libyasm/tests/incbin.asm
new file mode 100644
index 0000000..bd6d1a9
--- /dev/null
+++ b/libyasm/tests/incbin.asm
@@ -0,0 +1,18 @@
+incbin "stamp-h1"
+; 1024 x's to bump above 1024 byte default bytecode buffer size
+;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
diff --git a/libyasm/tests/incbin.hex b/libyasm/tests/incbin.hex
new file mode 100644
index 0000000..7a26ed8
--- /dev/null
+++ b/libyasm/tests/incbin.hex
@@ -0,0 +1,23 @@
+74
+69
+6d
+65
+73
+74
+61
+6d
+70
+20
+66
+6f
+72
+20
+63
+6f
+6e
+66
+69
+67
+2e
+68
+0a
diff --git a/libyasm/tests/jmpsize1-err.asm b/libyasm/tests/jmpsize1-err.asm
new file mode 100644
index 0000000..a0df3e2
--- /dev/null
+++ b/libyasm/tests/jmpsize1-err.asm
@@ -0,0 +1,264 @@
+jmp x ; short
+nop
+w:
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+x:
+jmp w ; short
+jmp short y ; must be near; forcing short should error
+nop
+z:
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+y:
+jmp short z ; must be near; forcing short should error
+
diff --git a/libyasm/tests/jmpsize1-err.errwarn b/libyasm/tests/jmpsize1-err.errwarn
new file mode 100644
index 0000000..276b1eb
--- /dev/null
+++ b/libyasm/tests/jmpsize1-err.errwarn
@@ -0,0 +1,2 @@
+-:132: error: short jump out of range
+-:263: error: short jump out of range
diff --git a/libyasm/tests/jmpsize1.asm b/libyasm/tests/jmpsize1.asm
new file mode 100644
index 0000000..821b245
--- /dev/null
+++ b/libyasm/tests/jmpsize1.asm
@@ -0,0 +1,264 @@
+jmp x ; short
+nop
+w:
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+x:
+jmp w ; short
+jmp y ; near
+nop
+z:
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+y:
+jmp z ; near
+
diff --git a/libyasm/tests/jmpsize1.hex b/libyasm/tests/jmpsize1.hex
new file mode 100644
index 0000000..d885f86
--- /dev/null
+++ b/libyasm/tests/jmpsize1.hex
@@ -0,0 +1,265 @@
+eb
+7f
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+eb
+80
+e9
+80
+00
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+e9
+7e
+ff
diff --git a/libyasm/tests/leb128_test.c b/libyasm/tests/leb128_test.c
new file mode 100644
index 0000000..87fc8d9
--- /dev/null
+++ b/libyasm/tests/leb128_test.c
@@ -0,0 +1,199 @@
+/*
+ *
+ * Copyright (C) 2005-2007 Peter Johnson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "libyasm/intnum.c"
+
+typedef struct Test_Entry {
+ /* signedness (0=unsigned, 1=signed) */
+ int sign;
+
+ /* whether input value should be negated */
+ int negate;
+
+ /* input value (as hex string) */
+ const char *input;
+
+ /* correct size returned from both size_leb128 and get_leb128 */
+ unsigned long outsize;
+
+ /* correct return data from get_leb128 */
+ const unsigned char *result;
+} Test_Entry;
+
+static Test_Entry tests[] = {
+ /* Unsigned values */
+ {0, 0, "0", 1, (const unsigned char *)"\x00"},
+ {0, 0, "2", 1, (const unsigned char *)"\x02"},
+ {0, 0, "7F", 1, (const unsigned char *)"\x7F"},
+ {0, 0, "80", 2, (const unsigned char *)"\x80\x01"},
+ {0, 0, "81", 2, (const unsigned char *)"\x81\x01"},
+ {0, 0, "82", 2, (const unsigned char *)"\x82\x01"},
+ {0, 0, "3239", 2, (const unsigned char *)"\xB9\x64"},
+ /* Signed zero value */
+ {1, 0, "0", 1, (const unsigned char *)"\x00"},
+ /* Signed positive values */
+ {1, 0, "2", 1, (const unsigned char *)"\x02"},
+ {1, 0, "7F", 2, (const unsigned char *)"\xFF\x00"},
+ {1, 0, "80", 2, (const unsigned char *)"\x80\x01"},
+ {1, 0, "81", 2, (const unsigned char *)"\x81\x01"},
+ /* Signed negative values */
+ {1, 1, "2", 1, (const unsigned char *)"\x7E"},
+ {1, 1, "7F", 2, (const unsigned char *)"\x81\x7F"},
+ {1, 1, "80", 2, (const unsigned char *)"\x80\x7F"},
+ {1, 1, "81", 2, (const unsigned char *)"\xFF\x7E"},
+};
+
+static char failed[1000];
+static char failmsg[100];
+
+static int
+run_output_test(Test_Entry *test)
+{
+ char *valstr = yasm__xstrdup(test->input);
+ yasm_intnum *intn = yasm_intnum_create_hex(valstr);
+ unsigned long size, i;
+ unsigned char out[100];
+ int bad;
+
+ yasm_xfree(valstr);
+
+ if (test->negate)
+ yasm_intnum_calc(intn, YASM_EXPR_NEG, NULL);
+
+ size = yasm_intnum_size_leb128(intn, test->sign);
+ if (size != test->outsize) {
+ yasm_intnum_destroy(intn);
+ sprintf(failmsg, "%ssigned %s%s size() bad size: expected %lu, got %lu!",
+ test->sign?"":"un", test->negate?"-":"", test->input,
+ test->outsize, size);
+ return 1;
+ }
+
+ for (i=0; i<sizeof(out); i++)
+ out[i] = 0xFF;
+ size = yasm_intnum_get_leb128(intn, out, test->sign);
+ if (size != test->outsize) {
+ yasm_intnum_destroy(intn);
+ sprintf(failmsg, "%ssigned %s%s get() bad size: expected %lu, got %lu!",
+ test->sign?"":"un", test->negate?"-":"", test->input,
+ test->outsize, size);
+ return 1;
+ }
+
+ bad = 0;
+ for (i=0; i<test->outsize && !bad; i++) {
+ if (out[i] != test->result[i])
+ bad = 1;
+ }
+ if (bad) {
+ yasm_intnum_destroy(intn);
+ sprintf(failmsg, "%ssigned %s%s get() bad output!",
+ test->sign?"":"un", test->negate?"-":"", test->input);
+ return 1;
+ }
+
+ yasm_intnum_destroy(intn);
+ return 0;
+}
+
+static int
+run_input_test(Test_Entry *test)
+{
+ char *valstr = yasm__xstrdup(test->input);
+ yasm_intnum *intn = yasm_intnum_create_hex(valstr);
+ yasm_intnum *testn;
+ unsigned long size;
+
+ yasm_xfree(valstr);
+
+ if (test->negate)
+ yasm_intnum_calc(intn, YASM_EXPR_NEG, NULL);
+
+ testn = yasm_intnum_create_leb128(test->result, test->sign, &size);
+ if (size != test->outsize) {
+ yasm_intnum_destroy(testn);
+ yasm_intnum_destroy(intn);
+ sprintf(failmsg, "%ssigned %s%s create() bad size: expected %lu, got %lu!",
+ test->sign?"":"un", test->negate?"-":"", test->input,
+ test->outsize, size);
+ return 1;
+ }
+
+ yasm_intnum_calc(intn, YASM_EXPR_EQ, testn);
+ if (!yasm_intnum_is_pos1(intn)) {
+ yasm_intnum_destroy(testn);
+ yasm_intnum_destroy(intn);
+ sprintf(failmsg, "%ssigned %s%s create() bad output!",
+ test->sign?"":"un", test->negate?"-":"", test->input);
+ return 1;
+ }
+
+ yasm_intnum_destroy(testn);
+ yasm_intnum_destroy(intn);
+ return 0;
+}
+
+int
+main(void)
+{
+ int nf = 0;
+ int numtests = sizeof(tests)/sizeof(Test_Entry);
+ int i;
+
+ if (BitVector_Boot() != ErrCode_Ok)
+ return EXIT_FAILURE;
+ yasm_intnum_initialize();
+
+ failed[0] = '\0';
+ printf("Test leb128_test: ");
+ for (i=0; i<numtests; i++) {
+ int fail;
+
+ fail = run_output_test(&tests[i]);
+ printf("%c", fail>0 ? 'F':'.');
+ fflush(stdout);
+ if (fail)
+ sprintf(failed, "%s ** F: %s\n", failed, failmsg);
+ nf += fail;
+
+ fail = run_input_test(&tests[i]);
+ printf("%c", fail>0 ? 'F':'.');
+ fflush(stdout);
+ if (fail)
+ sprintf(failed, "%s ** F: %s\n", failed, failmsg);
+ nf += fail;
+ }
+
+ yasm_intnum_cleanup();
+
+ printf(" +%d-%d/%d %d%%\n%s",
+ numtests*2-nf, nf, numtests*2, 100*(numtests*2-nf)/(numtests*2),
+ failed);
+ return (nf == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/libyasm/tests/libyasm_test.sh b/libyasm/tests/libyasm_test.sh
new file mode 100755
index 0000000..37f8717
--- /dev/null
+++ b/libyasm/tests/libyasm_test.sh
@@ -0,0 +1,3 @@
+#! /bin/sh
+${srcdir}/out_test.sh libyasm_test libyasm/tests "libyasm" "-f bin" ""
+exit $?
diff --git a/libyasm/tests/opt-align1.asm b/libyasm/tests/opt-align1.asm
new file mode 100644
index 0000000..2005c06
--- /dev/null
+++ b/libyasm/tests/opt-align1.asm
@@ -0,0 +1,9 @@
+je label1
+times 4 nop
+je label1
+align 8
+times 118 nop
+je label2
+label1:
+times 128 nop
+label2:
diff --git a/libyasm/tests/opt-align1.hex b/libyasm/tests/opt-align1.hex
new file mode 100644
index 0000000..7785147
--- /dev/null
+++ b/libyasm/tests/opt-align1.hex
@@ -0,0 +1,266 @@
+0f
+84
+86
+00
+90
+90
+90
+90
+0f
+84
+7e
+00
+8d
+b4
+00
+00
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+0f
+84
+80
+00
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
diff --git a/libyasm/tests/opt-align2.asm b/libyasm/tests/opt-align2.asm
new file mode 100644
index 0000000..d93bd8e
--- /dev/null
+++ b/libyasm/tests/opt-align2.asm
@@ -0,0 +1,10 @@
+je label1
+je label1
+times 4 nop
+times 8 nop
+align 8
+times 110 nop
+je label2
+label1:
+times 128 nop
+label2:
diff --git a/libyasm/tests/opt-align2.hex b/libyasm/tests/opt-align2.hex
new file mode 100644
index 0000000..38a8cc8
--- /dev/null
+++ b/libyasm/tests/opt-align2.hex
@@ -0,0 +1,266 @@
+0f
+84
+86
+00
+0f
+84
+82
+00
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+8d
+b4
+00
+00
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+0f
+84
+80
+00
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
diff --git a/libyasm/tests/opt-align3.asm b/libyasm/tests/opt-align3.asm
new file mode 100644
index 0000000..747fa5c
--- /dev/null
+++ b/libyasm/tests/opt-align3.asm
@@ -0,0 +1,16 @@
+je label1a
+je label1b
+je label1c
+jmp label1d
+align 4
+times 112 nop
+je label2
+label1a:
+times 4 nop
+label1b:
+times 4 nop
+label1c:
+times 4 nop
+label1d:
+times 128 nop
+label2:
diff --git a/libyasm/tests/opt-align3.hex b/libyasm/tests/opt-align3.hex
new file mode 100644
index 0000000..c44bfe4
--- /dev/null
+++ b/libyasm/tests/opt-align3.hex
@@ -0,0 +1,272 @@
+0f
+84
+80
+00
+0f
+84
+80
+00
+0f
+84
+80
+00
+e9
+81
+00
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+0f
+84
+8c
+00
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
diff --git a/libyasm/tests/opt-circular1-err.asm b/libyasm/tests/opt-circular1-err.asm
new file mode 100644
index 0000000..dc96746
--- /dev/null
+++ b/libyasm/tests/opt-circular1-err.asm
@@ -0,0 +1,2 @@
+ times (label-$) db 0
+label: db 'Where am I?'
diff --git a/libyasm/tests/opt-circular1-err.errwarn b/libyasm/tests/opt-circular1-err.errwarn
new file mode 100644
index 0000000..9b09e1c
--- /dev/null
+++ b/libyasm/tests/opt-circular1-err.errwarn
@@ -0,0 +1 @@
+-:1: error: circular reference detected
diff --git a/libyasm/tests/opt-circular2-err.asm b/libyasm/tests/opt-circular2-err.asm
new file mode 100644
index 0000000..ea558ae
--- /dev/null
+++ b/libyasm/tests/opt-circular2-err.asm
@@ -0,0 +1,2 @@
+ times (label-$+1) db 0
+label: db 'NOW where am I?'
diff --git a/libyasm/tests/opt-circular2-err.errwarn b/libyasm/tests/opt-circular2-err.errwarn
new file mode 100644
index 0000000..9b09e1c
--- /dev/null
+++ b/libyasm/tests/opt-circular2-err.errwarn
@@ -0,0 +1 @@
+-:1: error: circular reference detected
diff --git a/libyasm/tests/opt-circular3-err.asm b/libyasm/tests/opt-circular3-err.asm
new file mode 100644
index 0000000..61f818a
--- /dev/null
+++ b/libyasm/tests/opt-circular3-err.asm
@@ -0,0 +1,7 @@
+label1:
+times label4-label3+1 db 0
+label2:
+db 0
+label3:
+times label2-label1+1 db 0
+label4:
diff --git a/libyasm/tests/opt-circular3-err.errwarn b/libyasm/tests/opt-circular3-err.errwarn
new file mode 100644
index 0000000..041cbba
--- /dev/null
+++ b/libyasm/tests/opt-circular3-err.errwarn
@@ -0,0 +1 @@
+-:6: error: circular reference detected
diff --git a/libyasm/tests/opt-gvmat64.asm b/libyasm/tests/opt-gvmat64.asm
new file mode 100644
index 0000000..35ac7ac
--- /dev/null
+++ b/libyasm/tests/opt-gvmat64.asm
@@ -0,0 +1,514 @@
+;uInt longest_match_x64(
+; deflate_state *s,
+; IPos cur_match); /* current match */
+
+; gvmat64.asm -- Asm portion of the optimized longest_match for 32 bits x86
+; Copyright (C) 1995-2005 Jean-loup Gailly, Brian Raiter and Gilles Vollant.
+;
+; File written by Gilles Vollant, by converting to assembly the longest_match
+; from Jean-loup Gailly in deflate.c of zLib and infoZip zip.
+;
+; and by taking inspiration on asm686 with masm, optimised assembly code
+; from Brian Raiter, written 1998
+;
+; http://www.zlib.net
+; http://www.winimage.com/zLibDll
+; http://www.muppetlabs.com/~breadbox/software/assembly.html
+;
+; to compile this file for infozip Zip, I use option:
+; ml64.exe /Flgvmat64 /c /Zi /DINFOZIP gvmat64.asm
+;
+; to compile this file for zLib, I use option:
+; ml64.exe /Flgvmat64 /c /Zi gvmat64.asm
+; Be carrefull to adapt zlib1222add below to your version of zLib
+; (if you use a version of zLib before 1.0.4 or after 1.2.2.2, change
+; value of zlib1222add later)
+;
+; This file compile with Microsoft Macro Assembler (x64) for AMD64
+;
+; ml64.exe is given with Visual Studio 2005 and Windows 2003 server DDK
+;
+; (you can get Windows 2003 server DDK with ml64 and cl for AMD64 from
+; http://www.microsoft.com/whdc/devtools/ddk/default.mspx for low price)
+;
+
+
+;uInt longest_match(s, cur_match)
+; deflate_state *s;
+; IPos cur_match; /* current match */
+bits 64
+ section .text
+
+longest_match: ; PROC
+
+
+;%define LocalVarsSize 88
+ %define LocalVarsSize 72
+
+; register used : rax,rbx,rcx,rdx,rsi,rdi,r8,r9,r10,r11,r12
+; free register : r14,r15
+; register can be saved : rsp
+
+ %define chainlenwmask rsp + 8 - LocalVarsSize ; high word: current chain len
+ ; low word: s->wmask
+;%define window rsp + xx - LocalVarsSize ; local copy of s->window ; stored in r10
+;%define windowbestlen rsp + xx - LocalVarsSize ; s->window + bestlen , use r10+r11
+;%define scanstart rsp + xx - LocalVarsSize ; first two bytes of string ; stored in r12w
+;%define scanend rsp + xx - LocalVarsSize ; last two bytes of string use ebx
+;%define scanalign rsp + xx - LocalVarsSize ; dword-misalignment of string r13
+;%define bestlen rsp + xx - LocalVarsSize ; size of best match so far -> r11d
+;%define scan rsp + xx - LocalVarsSize ; ptr to string wanting match -> r9
+%ifdef INFOZIP
+%else
+ %define nicematch (rsp + 16 - LocalVarsSize) ; a good enough match size
+%endif
+
+%define save_rdi rsp + 24 - LocalVarsSize
+%define save_rsi rsp + 32 - LocalVarsSize
+%define save_rbx rsp + 40 - LocalVarsSize
+%define save_rbp rsp + 48 - LocalVarsSize
+%define save_r12 rsp + 56 - LocalVarsSize
+%define save_r13 rsp + 64 - LocalVarsSize
+;%define save_r14 rsp + 72 - LocalVarsSize
+;%define save_r15 rsp + 80 - LocalVarsSize
+
+
+
+; all the +4 offsets are due to the addition of pending_buf_size (in zlib
+; in the deflate_state structure since the asm code was first written
+; (if you compile with zlib 1.0.4 or older, remove the +4).
+; Note : these value are good with a 8 bytes boundary pack structure
+
+
+ %define MAX_MATCH 258
+ %define MIN_MATCH 3
+ %define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
+
+
+;;; Offsets for fields in the deflate_state structure. These numbers
+;;; are calculated from the definition of deflate_state, with the
+;;; assumption that the compiler will dword-align the fields. (Thus,
+;;; changing the definition of deflate_state could easily cause this
+;;; program to crash horribly, without so much as a warning at
+;;; compile time. Sigh.)
+
+; all the +zlib1222add offsets are due to the addition of fields
+; in zlib in the deflate_state structure since the asm code was first written
+; (if you compile with zlib 1.0.4 or older, use "%define zlib1222add (-4)").
+; (if you compile with zlib between 1.0.5 and 1.2.2.1, use "%define zlib1222add 0").
+; if you compile with zlib 1.2.2.2 or later , use "%define zlib1222add 8").
+
+%ifdef INFOZIP
+ section .data
+
+extern window_size:DWORD
+; WMask ; 7fff
+extern window:BYTE:010040H
+extern prev:WORD:08000H
+; MatchLen : unused
+; PrevMatch : unused
+extern strstart:DWORD
+extern match_start:DWORD
+; Lookahead : ignore
+extern prev_length:DWORD ; PrevLen
+extern max_chain_length:DWORD
+extern good_match:DWORD
+extern nice_match:DWORD
+%define prev_ad OFFSET prev
+%define window_ad OFFSET window
+%define nicematch nice_match
+
+%define WMask 07fffh
+
+%else
+
+ %ifndef zlib1222add
+ %define zlib1222add 8
+ %endif
+%define dsWSize 56+zlib1222add+(zlib1222add/2)
+%define dsWMask 64+zlib1222add+(zlib1222add/2)
+%define dsWindow 72+zlib1222add
+%define dsPrev 88+zlib1222add
+%define dsMatchLen 128+zlib1222add
+%define dsPrevMatch 132+zlib1222add
+%define dsStrStart 140+zlib1222add
+%define dsMatchStart 144+zlib1222add
+%define dsLookahead 148+zlib1222add
+%define dsPrevLen 152+zlib1222add
+%define dsMaxChainLen 156+zlib1222add
+%define dsGoodMatch 172+zlib1222add
+%define dsNiceMatch 176+zlib1222add
+
+%define window_size [ rcx + dsWSize]
+%define WMask [ rcx + dsWMask]
+%define window_ad [ rcx + dsWindow]
+%define prev_ad [ rcx + dsPrev]
+%define strstart [ rcx + dsStrStart]
+%define match_start [ rcx + dsMatchStart]
+%define Lookahead [ rcx + dsLookahead] ; 0ffffffffh on infozip
+%define prev_length [ rcx + dsPrevLen]
+%define max_chain_length [ rcx + dsMaxChainLen]
+%define good_match [ rcx + dsGoodMatch]
+%define nice_match [ rcx + dsNiceMatch]
+%endif
+
+; parameter 1 in r8(deflate state s), param 2 in rdx (cur match)
+
+; see http://weblogs.asp.net/oldnewthing/archive/2004/01/14/58579.aspx and
+; http://msdn.microsoft.com/library/en-us/kmarch/hh/kmarch/64bitAMD_8e951dd2-ee77-4728-8702-55ce4b5dd24a.xml.asp
+;
+; All registers must be preserved across the call, except for
+; rax, rcx, rdx, r8, r9, r10, and r11, which are scratch.
+
+ section .text
+
+;;; Save registers that the compiler may be using, and adjust esp to
+;;; make room for our stack frame.
+
+
+;;; Retrieve the function arguments. r8d will hold cur_match
+;;; throughout the entire function. edx will hold the pointer to the
+;;; deflate_state structure during the function's setup (before
+;;; entering the main loop.
+
+; parameter 1 in rcx (deflate_state* s), param 2 in edx -> r8 (cur match)
+
+; this clear high 32 bits of r8, which can be garbage in both r8 and rdx
+
+ mov [save_rdi],rdi
+ mov [save_rsi],rsi
+ mov [save_rbx],rbx
+ mov [save_rbp],rbp
+%ifdef INFOZIP
+ mov r8d,ecx
+%else
+ mov r8d,edx
+%endif
+ mov [save_r12],r12
+ mov [save_r13],r13
+; mov [save_r14],r14
+; mov [save_r15],r15
+
+
+;;; uInt wmask = s->w_mask;
+;;; unsigned chain_length = s->max_chain_length;
+;;; if (s->prev_length >= s->good_match) {
+;;; chain_length >>= 2;
+;;; }
+
+ mov edi, prev_length
+ mov esi, good_match
+ mov eax, WMask
+ mov ebx, max_chain_length
+ cmp edi, esi
+ jl LastMatchGood
+ shr ebx, 2
+LastMatchGood:
+
+;;; chainlen is decremented once beforehand so that the function can
+;;; use the sign flag instead of the zero flag for the exit test.
+;;; It is then shifted into the high word, to make room for the wmask
+;;; value, which it will always accompany.
+
+ dec ebx
+ shl ebx, 16
+ or ebx, eax
+
+;;; on zlib only
+;;; if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead;
+
+%ifdef INFOZIP
+ mov [chainlenwmask], ebx
+; on infozip nice_match = [nice_match]
+%else
+ mov eax, nice_match
+ mov [chainlenwmask], ebx
+ mov r10d, Lookahead
+ cmp r10d, eax
+ cmovnl r10d, eax
+ mov [nicematch],r10d
+%endif
+
+;;; register Bytef *scan = s->window + s->strstart;
+ mov r10, window_ad
+ mov ebp, strstart
+ lea r13, [r10 + rbp]
+
+;;; Determine how many bytes the scan ptr is off from being
+;;; dword-aligned.
+
+ mov r9,r13
+ neg r13
+ and r13,3
+
+;;; IPos limit = s->strstart > (IPos)MAX_DIST(s) ?
+;;; s->strstart - (IPos)MAX_DIST(s) : NIL;
+%ifdef INFOZIP
+ mov eax,07efah ; MAX_DIST = (WSIZE-MIN_LOOKAHEAD) (0x8000-(3+8+1))
+%else
+ mov eax, window_size
+ sub eax, MIN_LOOKAHEAD
+%endif
+ xor edi,edi
+ sub ebp, eax
+
+ mov r11d, prev_length
+
+ cmovng ebp,edi
+
+;;; int best_len = s->prev_length;
+
+
+;;; Store the sum of s->window + best_len in esi locally, and in esi.
+
+ lea rsi,[r10+r11]
+
+;;; register ush scan_start = *(ushf*)scan;
+;;; register ush scan_end = *(ushf*)(scan+best_len-1);
+;;; Posf *prev = s->prev;
+
+ movzx r12d,word [r9]
+ movzx ebx, word [r9 + r11 - 1]
+
+ mov rdi, prev_ad
+
+;;; Jump into the main loop.
+
+ mov edx, [chainlenwmask]
+
+ cmp bx,word [rsi + r8 - 1]
+ jz LookupLoopIsZero
+
+LookupLoop1:
+ and r8d, edx
+
+ movzx r8d, word [rdi + r8*2]
+ cmp r8d, ebp
+ jbe LeaveNow
+ sub edx, 00010000h
+ js LeaveNow
+
+LoopEntry1:
+ cmp bx,word [rsi + r8 - 1]
+ jz LookupLoopIsZero
+
+LookupLoop2:
+ and r8d, edx
+
+ movzx r8d, word [rdi + r8*2]
+ cmp r8d, ebp
+ jbe LeaveNow
+ sub edx, 00010000h
+ js LeaveNow
+
+LoopEntry2:
+ cmp bx,word [rsi + r8 - 1]
+ jz LookupLoopIsZero
+
+LookupLoop4:
+ and r8d, edx
+
+ movzx r8d, word [rdi + r8*2]
+ cmp r8d, ebp
+ jbe LeaveNow
+ sub edx, 00010000h
+ js LeaveNow
+
+LoopEntry4:
+
+ cmp bx,word [rsi + r8 - 1]
+ jnz LookupLoop1
+ jmp LookupLoopIsZero
+
+
+;;; do {
+;;; match = s->window + cur_match;
+;;; if (*(ushf*)(match+best_len-1) != scan_end ||
+;;; *(ushf*)match != scan_start) continue;
+;;; [...]
+;;; } while ((cur_match = prev[cur_match & wmask]) > limit
+;;; && --chain_length != 0);
+;;;
+;;; Here is the inner loop of the function. The function will spend the
+;;; majority of its time in this loop, and majority of that time will
+;;; be spent in the first ten instructions.
+;;;
+;;; Within this loop:
+;;; ebx = scanend
+;;; r8d = curmatch
+;;; edx = chainlenwmask - i.e., ((chainlen << 16) | wmask)
+;;; esi = windowbestlen - i.e., (window + bestlen)
+;;; edi = prev
+;;; ebp = limit
+
+LookupLoop:
+ and r8d, edx
+
+ movzx r8d, word [rdi + r8*2]
+ cmp r8d, ebp
+ jbe LeaveNow
+ sub edx, 00010000h
+ js LeaveNow
+
+LoopEntry:
+
+ cmp bx,word [rsi + r8 - 1]
+ jnz LookupLoop1
+LookupLoopIsZero:
+ cmp r12w, word [r10 + r8]
+ jnz LookupLoop1
+
+
+;;; Store the current value of chainlen.
+ mov [chainlenwmask], edx
+
+;;; Point edi to the string under scrutiny, and esi to the string we
+;;; are hoping to match it up with. In actuality, esi and edi are
+;;; both pointed (MAX_MATCH_8 - scanalign) bytes ahead, and edx is
+;;; initialized to -(MAX_MATCH_8 - scanalign).
+
+ lea rsi,[r8+r10]
+ mov rdx, 0fffffffffffffef8h; -(MAX_MATCH_8)
+ lea rsi, [rsi + r13 + 0108h] ;MAX_MATCH_8]
+ lea rdi, [r9 + r13 + 0108h] ;MAX_MATCH_8]
+
+ prefetcht1 [rsi+rdx]
+ prefetcht1 [rdi+rdx]
+
+
+;;; Test the strings %define for ality, 8 bytes at a time. At the end,
+;;; adjust rdx so that it is offset to the exact byte that mismatched.
+;;;
+;;; We already know at this point that the first three bytes of the
+;;; strings match each other, and they can be safely passed over before
+;;; starting the compare loop. So what this code does is skip over 0-3
+;;; bytes, as much as necessary in order to dword-align the edi
+;;; pointer. (rsi will still be misaligned three times out of four.)
+;;;
+;;; It should be confessed that this loop usually does not represent
+;;; much of the total running time. Replacing it with a more
+;;; straightforward "rep cmpsb" would not drastically degrade
+;;; performance.
+
+LoopCmps:
+ mov rax, [rsi + rdx]
+ xor rax, [rdi + rdx]
+ jnz LeaveLoopCmps
+
+ mov rax, [rsi + rdx + 8]
+ xor rax, [rdi + rdx + 8]
+ jnz LeaveLoopCmps8
+
+
+ mov rax, [rsi + rdx + 8+8]
+ xor rax, [rdi + rdx + 8+8]
+ jnz LeaveLoopCmps16
+
+ add rdx,8+8+8
+
+ jmp short LoopCmps
+LeaveLoopCmps16: add rdx,8
+LeaveLoopCmps8: add rdx,8
+LeaveLoopCmps:
+
+ test eax, 0000FFFFh
+ jnz LenLower
+
+ test eax,0ffffffffh
+
+ jnz LenLower32
+
+ add rdx,4
+ shr rax,32
+ or ax,ax
+ jnz LenLower
+
+LenLower32:
+ shr eax,16
+ add rdx,2
+LenLower: sub al, 1
+ adc rdx, 0
+;;; Calculate the length of the match. If it is longer than MAX_MATCH,
+;;; then automatically accept it as the best possible match and leave.
+
+ lea rax, [rdi + rdx]
+ sub rax, r9
+ cmp eax, MAX_MATCH
+ jge LenMaximum
+
+;;; If the length of the match is not longer than the best match we
+;;; have so far, then forget it and return to the lookup loop.
+;///////////////////////////////////
+
+ cmp eax, r11d
+ jg LongerMatch
+
+ lea rsi,[r10+r11]
+
+ mov rdi, prev_ad
+ mov edx, [chainlenwmask]
+ jmp LookupLoop
+
+;;; s->match_start = cur_match;
+;;; best_len = len;
+;;; if (len >= nice_match) break;
+;;; scan_end = *(ushf*)(scan+best_len-1);
+
+LongerMatch:
+ mov r11d, eax
+ mov match_start, r8d
+ cmp eax, [nicematch]
+ jge LeaveNow
+
+ lea rsi,[r10+rax]
+
+ movzx ebx, word [r9 + rax - 1]
+ mov rdi, prev_ad
+ mov edx, [chainlenwmask]
+ jmp LookupLoop
+
+;;; Accept the current string, with the maximum possible length.
+
+LenMaximum:
+ mov r11d,MAX_MATCH
+ mov match_start, r8d
+;;; if ((uInt)best_len <= s->lookahead) return (uInt)best_len;
+;;; return s->lookahead;
+
+LeaveNow:
+%ifdef INFOZIP
+ mov eax,r11d
+%else
+ mov eax, Lookahead
+ cmp r11d, eax
+ cmovng eax, r11d
+%endif
+
+;;; Restore the stack and return from whence we came.
+
+ mov rsi,[save_rsi]
+ mov rdi,[save_rdi]
+ mov rbx,[save_rbx]
+ mov rbp,[save_rbp]
+ mov r12,[save_r12]
+ mov r13,[save_r13]
+; mov r14,[save_r14]
+; mov r15,[save_r15]
+
+
+ ret 0
+; please don't remove this string !
+; Your can freely use gvmat64 in any free or externercial app
+; but it is far better don't remove the string in the binary!
+ db 0dh,0ah,"asm686 with masm, optimised assembly code from Brian Raiter, written 1998, converted to amd 64 by Gilles Vollant 2005",0dh,0ah,0
+%if 0
+longest_match ENDP
+%endif
+
+match_init: ; PROC
+ ret 0
+ %if 0
+match_init ENDP
+%endif
+
+END
diff --git a/libyasm/tests/opt-gvmat64.hex b/libyasm/tests/opt-gvmat64.hex
new file mode 100644
index 0000000..b2432d6
--- /dev/null
+++ b/libyasm/tests/opt-gvmat64.hex
@@ -0,0 +1,731 @@
+48
+89
+7c
+24
+d0
+48
+89
+74
+24
+d8
+48
+89
+5c
+24
+e0
+48
+89
+6c
+24
+e8
+41
+89
+d0
+4c
+89
+64
+24
+f0
+4c
+89
+6c
+24
+f8
+8b
+b9
+a0
+00
+00
+00
+8b
+b1
+b4
+00
+00
+00
+8b
+41
+4c
+8b
+99
+a4
+00
+00
+00
+39
+f7
+7c
+03
+c1
+eb
+02
+ff
+cb
+c1
+e3
+10
+09
+c3
+8b
+81
+b8
+00
+00
+00
+89
+5c
+24
+c0
+44
+8b
+91
+9c
+00
+00
+00
+41
+39
+c2
+44
+0f
+4d
+d0
+44
+89
+54
+24
+c8
+4c
+8b
+51
+50
+8b
+a9
+94
+00
+00
+00
+4d
+8d
+2c
+2a
+4d
+89
+e9
+49
+f7
+dd
+49
+83
+e5
+03
+8b
+41
+44
+2d
+06
+01
+00
+00
+31
+ff
+29
+c5
+44
+8b
+99
+a0
+00
+00
+00
+0f
+4e
+ef
+4b
+8d
+34
+1a
+45
+0f
+b7
+21
+43
+0f
+b7
+5c
+19
+ff
+48
+8b
+79
+60
+8b
+54
+24
+c0
+66
+42
+3b
+5c
+06
+ff
+0f
+84
+9a
+00
+00
+00
+41
+21
+d0
+46
+0f
+b7
+04
+47
+41
+39
+e8
+0f
+86
+6e
+01
+00
+00
+81
+ea
+00
+00
+01
+00
+0f
+88
+62
+01
+00
+00
+66
+42
+3b
+5c
+06
+ff
+74
+75
+41
+21
+d0
+46
+0f
+b7
+04
+47
+41
+39
+e8
+0f
+86
+49
+01
+00
+00
+81
+ea
+00
+00
+01
+00
+0f
+88
+3d
+01
+00
+00
+66
+42
+3b
+5c
+06
+ff
+74
+50
+41
+21
+d0
+46
+0f
+b7
+04
+47
+41
+39
+e8
+0f
+86
+24
+01
+00
+00
+81
+ea
+00
+00
+01
+00
+0f
+88
+18
+01
+00
+00
+66
+42
+3b
+5c
+06
+ff
+75
+91
+eb
+29
+41
+21
+d0
+46
+0f
+b7
+04
+47
+41
+39
+e8
+0f
+86
+fd
+00
+00
+00
+81
+ea
+00
+00
+01
+00
+0f
+88
+f1
+00
+00
+00
+66
+42
+3b
+5c
+06
+ff
+0f
+85
+66
+ff
+ff
+ff
+66
+47
+3b
+24
+02
+0f
+85
+5b
+ff
+ff
+ff
+89
+54
+24
+c0
+4b
+8d
+34
+10
+48
+ba
+f8
+fe
+ff
+ff
+ff
+ff
+ff
+ff
+4a
+8d
+b4
+2e
+08
+01
+00
+00
+4b
+8d
+bc
+29
+08
+01
+00
+00
+0f
+18
+14
+16
+0f
+18
+14
+17
+48
+8b
+04
+16
+48
+33
+04
+17
+75
+26
+48
+8b
+44
+16
+08
+48
+33
+44
+17
+08
+75
+16
+48
+8b
+44
+16
+10
+48
+33
+44
+17
+10
+75
+06
+48
+83
+c2
+18
+eb
+d8
+48
+83
+c2
+08
+48
+83
+c2
+08
+a9
+ff
+ff
+00
+00
+75
+1b
+a9
+ff
+ff
+ff
+ff
+75
+0d
+48
+83
+c2
+04
+48
+c1
+e8
+20
+66
+09
+c0
+75
+07
+c1
+e8
+10
+48
+83
+c2
+02
+2c
+01
+48
+83
+d2
+00
+48
+8d
+04
+17
+4c
+29
+c8
+3d
+02
+01
+00
+00
+7d
+3d
+44
+39
+d8
+7f
+11
+4b
+8d
+34
+1a
+48
+8b
+79
+60
+8b
+54
+24
+c0
+e9
+26
+ff
+ff
+ff
+41
+89
+c3
+44
+89
+81
+98
+00
+00
+00
+3b
+44
+24
+c8
+7d
+24
+49
+8d
+34
+02
+41
+0f
+b7
+5c
+01
+ff
+48
+8b
+79
+60
+8b
+54
+24
+c0
+e9
+ff
+fe
+ff
+ff
+41
+bb
+02
+01
+00
+00
+44
+89
+81
+98
+00
+00
+00
+8b
+81
+9c
+00
+00
+00
+41
+39
+c3
+41
+0f
+4e
+c3
+48
+8b
+74
+24
+d8
+48
+8b
+7c
+24
+d0
+48
+8b
+5c
+24
+e0
+48
+8b
+6c
+24
+e8
+4c
+8b
+64
+24
+f0
+4c
+8b
+6c
+24
+f8
+c2
+00
+00
+0d
+0a
+61
+73
+6d
+36
+38
+36
+20
+77
+69
+74
+68
+20
+6d
+61
+73
+6d
+2c
+20
+6f
+70
+74
+69
+6d
+69
+73
+65
+64
+20
+61
+73
+73
+65
+6d
+62
+6c
+79
+20
+63
+6f
+64
+65
+20
+66
+72
+6f
+6d
+20
+42
+72
+69
+61
+6e
+20
+52
+61
+69
+74
+65
+72
+2c
+20
+77
+72
+69
+74
+74
+65
+6e
+20
+31
+39
+39
+38
+2c
+20
+63
+6f
+6e
+76
+65
+72
+74
+65
+64
+20
+74
+6f
+20
+61
+6d
+64
+20
+36
+34
+20
+62
+79
+20
+47
+69
+6c
+6c
+65
+73
+20
+56
+6f
+6c
+6c
+61
+6e
+74
+20
+32
+30
+30
+35
+0d
+0a
+00
+c2
+00
+00
diff --git a/libyasm/tests/opt-immexpand.asm b/libyasm/tests/opt-immexpand.asm
new file mode 100644
index 0000000..55d8097
--- /dev/null
+++ b/libyasm/tests/opt-immexpand.asm
@@ -0,0 +1,9 @@
+label1:
+je label3
+times 124 nop
+label2:
+je label4
+label3:
+times 128 nop
+label4:
+push label2-label1
diff --git a/libyasm/tests/opt-immexpand.hex b/libyasm/tests/opt-immexpand.hex
new file mode 100644
index 0000000..f57024e
--- /dev/null
+++ b/libyasm/tests/opt-immexpand.hex
@@ -0,0 +1,263 @@
+0f
+84
+80
+00
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+0f
+84
+80
+00
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+68
+80
+00
diff --git a/libyasm/tests/opt-immnoexpand.asm b/libyasm/tests/opt-immnoexpand.asm
new file mode 100644
index 0000000..e126f80
--- /dev/null
+++ b/libyasm/tests/opt-immnoexpand.asm
@@ -0,0 +1,10 @@
+label1:
+times 2 nop
+je label3
+times 123 nop
+label2:
+je label4
+label3:
+times 128 nop
+label4:
+push label2-label1
diff --git a/libyasm/tests/opt-immnoexpand.hex b/libyasm/tests/opt-immnoexpand.hex
new file mode 100644
index 0000000..c465806
--- /dev/null
+++ b/libyasm/tests/opt-immnoexpand.hex
@@ -0,0 +1,261 @@
+90
+90
+74
+7f
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+0f
+84
+80
+00
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+6a
+7f
diff --git a/libyasm/tests/opt-oldalign.asm b/libyasm/tests/opt-oldalign.asm
new file mode 100644
index 0000000..013a5c8
--- /dev/null
+++ b/libyasm/tests/opt-oldalign.asm
@@ -0,0 +1,3 @@
+mov ax, 5
+times ($$-$) & 1Fh nop ; Long word alignment
+mov bx, 5
diff --git a/libyasm/tests/opt-oldalign.hex b/libyasm/tests/opt-oldalign.hex
new file mode 100644
index 0000000..dfbb9da
--- /dev/null
+++ b/libyasm/tests/opt-oldalign.hex
@@ -0,0 +1,35 @@
+b8
+05
+00
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+bb
+05
+00
diff --git a/libyasm/tests/opt-struc.asm b/libyasm/tests/opt-struc.asm
new file mode 100644
index 0000000..4986f3b
--- /dev/null
+++ b/libyasm/tests/opt-struc.asm
@@ -0,0 +1,39 @@
+[absolute 0]
+HOSTENT:
+.Name resd 1
+.Aliases resd 1
+
+.AddrList resd 1
+
+HOSTENT_size:
+
+[section .bss]
+STRING_MAX equ 256
+HOSTENT_ALIASES_MAX equ 16
+HOSTENT_ADDRLIST_MAX equ 16
+
+HostEnt_Name_static resb STRING_MAX
+HostEnt_Aliases_static resd HOSTENT_ALIASES_MAX
+HostEnt_AddrList_static resd HOSTENT_ADDRLIST_MAX
+HostEnt_Aliases_data resb STRING_MAX*HOSTENT_ALIASES_MAX
+HostEnt_AddrList_data resd HOSTENT_ADDRLIST_MAX
+
+[section .data]
+HostEnt_static :
+..@44.strucstart:
+times HOSTENT.Name-($-..@44.strucstart) db 0
+dd HostEnt_Name_static
+times HOSTENT.Aliases-($-..@44.strucstart) db 0
+dd HostEnt_Aliases_static
+times HOSTENT.AddrList-($-..@44.strucstart) db 0
+dd HostEnt_AddrList_static
+times HOSTENT_size-($-..@44.strucstart) db 0
+
+HostEnt_static2 :
+..@45.strucstart:
+times HOSTENT.Name-($-..@45.strucstart) db 0
+dd HostEnt_Name_static
+times HOSTENT.Aliases-($-..@45.strucstart) db 0
+dd HostEnt_Aliases_static
+times HOSTENT_size-($-..@45.strucstart) db 0
+
diff --git a/libyasm/tests/opt-struc.hex b/libyasm/tests/opt-struc.hex
new file mode 100644
index 0000000..c8e792a
--- /dev/null
+++ b/libyasm/tests/opt-struc.hex
@@ -0,0 +1,24 @@
+18
+00
+00
+00
+18
+01
+00
+00
+58
+01
+00
+00
+18
+00
+00
+00
+18
+01
+00
+00
+00
+00
+00
+00
diff --git a/libyasm/tests/reserve-err1.asm b/libyasm/tests/reserve-err1.asm
new file mode 100644
index 0000000..ad6e31a
--- /dev/null
+++ b/libyasm/tests/reserve-err1.asm
@@ -0,0 +1,15 @@
+; Test res* family errors
+a:
+resb -5
+resw 1.2
+resd -1.2
+resq 0xffffffff
+rest a
+
+[section .bss]
+resb -5
+resw 1.2
+resd -1.2
+resq 0xffffffff
+rest a
+
diff --git a/libyasm/tests/reserve-err1.errwarn b/libyasm/tests/reserve-err1.errwarn
new file mode 100644
index 0000000..e53fe3c
--- /dev/null
+++ b/libyasm/tests/reserve-err1.errwarn
@@ -0,0 +1,2 @@
+-:7: error: multiple expression not absolute
+-:14: error: multiple expression not absolute
diff --git a/libyasm/tests/reserve-err2.asm b/libyasm/tests/reserve-err2.asm
new file mode 100644
index 0000000..190f66b
--- /dev/null
+++ b/libyasm/tests/reserve-err2.asm
@@ -0,0 +1,15 @@
+; Test res* family errors
+a:
+resb -5
+resw 1.2
+resd -1.2
+resq 0xffffffff
+;rest a
+
+[section .bss]
+resb -5
+resw 1.2
+resd -1.2
+resq 0xffffffff
+;rest a
+
diff --git a/libyasm/tests/reserve-err2.errwarn b/libyasm/tests/reserve-err2.errwarn
new file mode 100644
index 0000000..d3fbbab
--- /dev/null
+++ b/libyasm/tests/reserve-err2.errwarn
@@ -0,0 +1,6 @@
+-:3: error: multiple is negative
+-:4: error: expression must not contain floating point value
+-:5: error: expression must not contain floating point value
+-:10: error: multiple is negative
+-:11: error: expression must not contain floating point value
+-:12: error: expression must not contain floating point value
diff --git a/libyasm/tests/splitpath_test.c b/libyasm/tests/splitpath_test.c
new file mode 100644
index 0000000..7f873a4
--- /dev/null
+++ b/libyasm/tests/splitpath_test.c
@@ -0,0 +1,154 @@
+/*
+ *
+ * Copyright (C) 2006-2007 Peter Johnson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "libyasm/file.h"
+
+typedef struct Test_Entry {
+ /* splitpath function to test */
+ size_t (*splitpath) (const char *path, const char **tail);
+
+ /* input path */
+ const char *input;
+
+ /* correct head length returned */
+ size_t headlen;
+
+ /* correct tail returned */
+ const char *tail;
+} Test_Entry;
+
+static Test_Entry tests[] = {
+ /* UNIX split */
+ {yasm__splitpath_unix, "", 0, ""},
+ {yasm__splitpath_unix, "./file.ext", 0, "file.ext"},
+ {yasm__splitpath_unix, "../../file.ext", 5, "file.ext"},
+ {yasm__splitpath_unix, "file.ext", 0, "file.ext"},
+ {yasm__splitpath_unix, "/file.ext", 1, "file.ext"},
+ {yasm__splitpath_unix, "/foo/file.ext", 4, "file.ext"},
+ {yasm__splitpath_unix, "/foo/bar/file.ext", 8, "file.ext"},
+ {yasm__splitpath_unix, "foo/file.ext", 3, "file.ext"},
+ {yasm__splitpath_unix, "foo/bar/file.ext", 7, "file.ext"},
+ {yasm__splitpath_unix, "foo/bar//file.ext", 7, "file.ext"},
+ {yasm__splitpath_unix, "/", 1, ""},
+ {yasm__splitpath_unix, "/foo/", 4, ""},
+ {yasm__splitpath_unix, "/foo/bar/", 8, ""},
+ {yasm__splitpath_unix, "foo/", 3, ""},
+ {yasm__splitpath_unix, "foo/bar/", 7, ""},
+ {yasm__splitpath_unix, "foo/bar//", 7, ""},
+ /* Windows split */
+ {yasm__splitpath_win, "", 0, ""},
+ {yasm__splitpath_win, "file.ext", 0, "file.ext"},
+ {yasm__splitpath_win, "./file.ext", 0, "file.ext"},
+ {yasm__splitpath_win, "/file.ext", 1, "file.ext"},
+ {yasm__splitpath_win, "/foo/file.ext", 4, "file.ext"},
+ {yasm__splitpath_win, "/foo/bar/file.ext", 8, "file.ext"},
+ {yasm__splitpath_win, "foo/file.ext", 3, "file.ext"},
+ {yasm__splitpath_win, "foo/bar/file.ext", 7, "file.ext"},
+ {yasm__splitpath_win, "foo/bar//file.ext", 7, "file.ext"},
+ {yasm__splitpath_win, "..\\..\\file.ext", 5, "file.ext"},
+ {yasm__splitpath_win, "c:file.ext", 2, "file.ext"},
+ {yasm__splitpath_win, "c:.\\file.ext", 2, "file.ext"},
+ {yasm__splitpath_win, "d:/file.ext", 3, "file.ext"},
+ {yasm__splitpath_win, "e:/foo/file.ext", 6, "file.ext"},
+ {yasm__splitpath_win, "f:/foo/bar/file.ext", 10, "file.ext"},
+ {yasm__splitpath_win, "g:foo/file.ext", 5, "file.ext"},
+ {yasm__splitpath_win, "h:foo/bar/file.ext", 9, "file.ext"},
+ {yasm__splitpath_win, "i:foo/bar//file.ext", 9, "file.ext"},
+ {yasm__splitpath_win, "d:\\file.ext", 3, "file.ext"},
+ {yasm__splitpath_win, "e:\\foo/file.ext", 6, "file.ext"},
+ {yasm__splitpath_win, "f:/foo\\bar\\file.ext", 10, "file.ext"},
+ {yasm__splitpath_win, "g:foo\\file.ext", 5, "file.ext"},
+ {yasm__splitpath_win, "h:foo/bar\\file.ext", 9, "file.ext"},
+ {yasm__splitpath_win, "i:foo\\bar//\\file.ext", 9, "file.ext"},
+ {yasm__splitpath_win, "\\", 1, ""},
+ {yasm__splitpath_win, "c:", 2, ""},
+ {yasm__splitpath_win, "d:\\", 3, ""},
+ {yasm__splitpath_win, "e:\\foo/", 6, ""},
+ {yasm__splitpath_win, "f:/foo\\bar\\", 10, ""},
+ {yasm__splitpath_win, "g:foo\\", 5, ""},
+ {yasm__splitpath_win, "h:foo/bar\\", 9, ""},
+ {yasm__splitpath_win, "i:foo\\bar//\\", 9, ""},
+};
+
+static char failed[1000];
+static char failmsg[100];
+
+static int
+run_test(Test_Entry *test)
+{
+ size_t headlen;
+ const char *tail;
+ const char *funcname;
+
+ if (test->splitpath == &yasm__splitpath_unix)
+ funcname = "unix";
+ else
+ funcname = "win";
+
+ headlen = test->splitpath(test->input, &tail);
+ if (headlen != test->headlen) {
+ sprintf(failmsg,
+ "splitpath_%s(\"%s\") bad head len: expected %lu, got %lu!",
+ funcname, test->input, (unsigned long)test->headlen,
+ (unsigned long)headlen);
+ return 1;
+ }
+
+ if (strcmp(tail, test->tail) != 0) {
+ sprintf(failmsg,
+ "splitpath_%s(\"%s\") bad tail: expected \"%s\", got \"%s\"!",
+ funcname, test->input, test->tail, tail);
+ return 1;
+ }
+
+ return 0;
+}
+
+int
+main(void)
+{
+ int nf = 0;
+ int numtests = sizeof(tests)/sizeof(Test_Entry);
+ int i;
+
+ failed[0] = '\0';
+ printf("Test splitpath_test: ");
+ for (i=0; i<numtests; i++) {
+ int fail = run_test(&tests[i]);
+ printf("%c", fail>0 ? 'F':'.');
+ fflush(stdout);
+ if (fail)
+ sprintf(failed, "%s ** F: %s\n", failed, failmsg);
+ nf += fail;
+ }
+
+ printf(" +%d-%d/%d %d%%\n%s",
+ numtests-nf, nf, numtests, 100*(numtests-nf)/numtests, failed);
+ return (nf == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/libyasm/tests/strucsize.asm b/libyasm/tests/strucsize.asm
new file mode 100644
index 0000000..5f5fc24
--- /dev/null
+++ b/libyasm/tests/strucsize.asm
@@ -0,0 +1,23 @@
+struc TST1
+ .a resd 2
+endstruc
+
+struc TST2
+ .b resb TST1_size
+endstruc
+
+tst2:
+istruc TST2
+at TST2.b
+
+ istruc TST1
+
+ at TST1.a
+ dd 1, 2
+
+ iend
+
+iend
+
+dw TST1_size
+dw TST2_size
diff --git a/libyasm/tests/strucsize.hex b/libyasm/tests/strucsize.hex
new file mode 100644
index 0000000..448779e
--- /dev/null
+++ b/libyasm/tests/strucsize.hex
@@ -0,0 +1,12 @@
+01
+00
+00
+00
+02
+00
+00
+00
+08
+00
+08
+00
diff --git a/libyasm/tests/times-res.asm b/libyasm/tests/times-res.asm
new file mode 100644
index 0000000..307a826
--- /dev/null
+++ b/libyasm/tests/times-res.asm
@@ -0,0 +1,3 @@
+times 5 resb 4
+times 0 resb 2
+times 1 resb 0
diff --git a/libyasm/tests/times-res.errwarn b/libyasm/tests/times-res.errwarn
new file mode 100644
index 0000000..ceb76cf
--- /dev/null
+++ b/libyasm/tests/times-res.errwarn
@@ -0,0 +1 @@
+-:1: warning: uninitialized space declared in code/data section: zeroing
diff --git a/libyasm/tests/times-res.hex b/libyasm/tests/times-res.hex
new file mode 100644
index 0000000..b1c8b27
--- /dev/null
+++ b/libyasm/tests/times-res.hex
@@ -0,0 +1,20 @@
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
diff --git a/libyasm/tests/times0.asm b/libyasm/tests/times0.asm
new file mode 100644
index 0000000..ea642d7
--- /dev/null
+++ b/libyasm/tests/times0.asm
@@ -0,0 +1 @@
+times 0 db 1
diff --git a/libyasm/tests/times0.hex b/libyasm/tests/times0.hex
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/libyasm/tests/times0.hex
diff --git a/libyasm/tests/timesover-err.asm b/libyasm/tests/timesover-err.asm
new file mode 100644
index 0000000..6b3b7f9
--- /dev/null
+++ b/libyasm/tests/timesover-err.asm
@@ -0,0 +1,2 @@
+times 512 db 0
+times 01FEh-($-$$) db 0
diff --git a/libyasm/tests/timesover-err.errwarn b/libyasm/tests/timesover-err.errwarn
new file mode 100644
index 0000000..81441ac
--- /dev/null
+++ b/libyasm/tests/timesover-err.errwarn
@@ -0,0 +1 @@
+-:2: error: multiple is negative
diff --git a/libyasm/tests/timesunder.asm b/libyasm/tests/timesunder.asm
new file mode 100644
index 0000000..aceafa3
--- /dev/null
+++ b/libyasm/tests/timesunder.asm
@@ -0,0 +1,3 @@
+je label
+times 82h-($-$$) nop
+label:
diff --git a/libyasm/tests/timesunder.hex b/libyasm/tests/timesunder.hex
new file mode 100644
index 0000000..e3efd14
--- /dev/null
+++ b/libyasm/tests/timesunder.hex
@@ -0,0 +1,130 @@
+0f
+84
+7e
+00
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
+90
diff --git a/libyasm/tests/unary.asm b/libyasm/tests/unary.asm
new file mode 100644
index 0000000..e0bcc17
--- /dev/null
+++ b/libyasm/tests/unary.asm
@@ -0,0 +1,5 @@
+[bits 32]
+mov eax, ~0
+mov eax, ~5
+mov ebx, -0
+mov ebx, -5
diff --git a/libyasm/tests/unary.hex b/libyasm/tests/unary.hex
new file mode 100644
index 0000000..ed29c52
--- /dev/null
+++ b/libyasm/tests/unary.hex
@@ -0,0 +1,20 @@
+b8
+ff
+ff
+ff
+ff
+b8
+fa
+ff
+ff
+ff
+bb
+00
+00
+00
+00
+bb
+fb
+ff
+ff
+ff
diff --git a/libyasm/tests/uncstring_test.c b/libyasm/tests/uncstring_test.c
new file mode 100644
index 0000000..7303764
--- /dev/null
+++ b/libyasm/tests/uncstring_test.c
@@ -0,0 +1,156 @@
+/*
+ *
+ * Copyright (C) 2006-2007 Peter Johnson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "util.h"
+#include "libyasm/errwarn.h"
+#include "libyasm/file.h"
+
+typedef struct Test_Entry {
+ /* input string */
+ const char *input;
+
+ /* input length */
+ size_t in_len;
+
+ /* correct output string */
+ const char *result;
+
+ /* correct output length */
+ size_t result_len;
+
+ /* expected warning, if any */
+ const char *warn;
+} Test_Entry;
+
+static Test_Entry tests[] = {
+ {"noescape", 8, "noescape", 8, NULL},
+ {"noescape2", 10, "noescape2", 10, NULL}, /* includes trailing zero */
+ {"\\\\\\b\\f\\n\\r\\t\\\"", 14, "\\\b\f\n\r\t\"", 7, NULL},
+ {"\\a", 2, "a", 1, NULL},
+ /* hex tests */
+ {"\\x", 2, "\x00", 1, NULL},
+ {"\\x12", 4, "\x12", 1, NULL},
+ {"\\x1234", 6, "\x34", 1, NULL},
+ {"\\xg", 3, "\x00g", 2, NULL},
+ {"\\xaga", 5, "\x0aga", 3, NULL},
+ {"\\xaag", 5, "\xaag", 2, NULL},
+ {"\\xaaa", 5, "\xaa", 1, NULL},
+ {"\\x55559", 7, "\x59", 1, NULL},
+
+ /* oct tests */
+ {"\\778", 4, "\000", 1, "octal value out of range"},
+ {"\\779", 4, "\001", 1, "octal value out of range"},
+ {"\\1x", 3, "\001x", 2, NULL},
+ {"\\7779", 5, "\xff" "9", 2, NULL},
+ {"\\7999", 5, "\x11" "9", 2, "octal value out of range"},
+ {"\\77a", 4, "\077a", 2, NULL},
+ {"\\5555555", 8, "\x6d" "5555", 5, NULL},
+ {"\\9999", 5, "\x91" "9", 2, "octal value out of range"},
+};
+
+static char failed[1000];
+static char failmsg[100];
+
+static int
+run_test(Test_Entry *test)
+{
+ char str[256];
+ size_t len;
+ yasm_warn_class wclass;
+ char *wstr;
+
+ strncpy(str, test->input, test->in_len);
+ len = test->in_len;
+
+ yasm_unescape_cstring((unsigned char *)str, &len);
+ if (len != test->result_len) {
+ sprintf(failmsg,
+ "unescape_cstring(\"%s\", %lu) bad output len: expected %lu, got %lu!",
+ test->input, (unsigned long)test->in_len,
+ (unsigned long)test->result_len, (unsigned long)len);
+ return 1;
+ }
+
+ if (strncmp(str, test->result, len) != 0) {
+ sprintf(failmsg,
+ "unescape_cstring(\"%s\", %lu) bad output: expected \"%s\", got \"%s\"!",
+ test->input, (unsigned long)test->in_len, test->result, str);
+ return 1;
+ }
+
+ yasm_warn_fetch(&wclass, &wstr);
+ if (wstr != NULL && test->warn == NULL) {
+ sprintf(failmsg,
+ "unescape_cstring(\"%s\", %lu) unexpected warning: %s!",
+ test->input, (unsigned long)test->in_len, wstr);
+ return 1;
+ }
+ if (wstr == NULL && test->warn != NULL) {
+ sprintf(failmsg,
+ "unescape_cstring(\"%s\", %lu) expected warning: %s, did not get it!",
+ test->input, (unsigned long)test->in_len, test->warn);
+ return 1;
+ }
+ if (wstr && test->warn && strcmp(wstr, test->warn) != 0) {
+ sprintf(failmsg,
+ "unescape_cstring(\"%s\", %lu) expected warning: %s, got %s!",
+ test->input, (unsigned long)test->in_len, test->warn, wstr);
+ return 1;
+ }
+ yasm_xfree(wstr);
+
+ return 0;
+}
+
+int
+main(void)
+{
+ int nf = 0;
+ int numtests = sizeof(tests)/sizeof(Test_Entry);
+ int i;
+
+ yasm_errwarn_initialize();
+
+ failed[0] = '\0';
+ printf("Test uncstring_test: ");
+ for (i=0; i<numtests; i++) {
+ int fail = run_test(&tests[i]);
+ printf("%c", fail>0 ? 'F':'.');
+ fflush(stdout);
+ if (fail)
+ sprintf(failed, "%s ** F: %s\n", failed, failmsg);
+ nf += fail;
+ }
+
+ printf(" +%d-%d/%d %d%%\n%s",
+ numtests-nf, nf, numtests, 100*(numtests-nf)/numtests, failed);
+
+ yasm_errwarn_cleanup();
+ return (nf == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/libyasm/tests/value-err.asm b/libyasm/tests/value-err.asm
new file mode 100644
index 0000000..883fa6f
--- /dev/null
+++ b/libyasm/tests/value-err.asm
@@ -0,0 +1,9 @@
+label:
+mov [label/2+1], ax
+mov ax, label*2
+mov [label+5], ax
+mov ax, label wrt foo
+foo:
+dd label
+dd label<<5
+dd label>>2
diff --git a/libyasm/tests/value-err.errwarn b/libyasm/tests/value-err.errwarn
new file mode 100644
index 0000000..a949cd8
--- /dev/null
+++ b/libyasm/tests/value-err.errwarn
@@ -0,0 +1,3 @@
+-:2: error: effective address too complex
+-:3: error: immediate expression too complex
+-:8: error: data expression too complex
diff --git a/libyasm/tests/value-mask.asm b/libyasm/tests/value-mask.asm
new file mode 100644
index 0000000..3e93952
--- /dev/null
+++ b/libyasm/tests/value-mask.asm
@@ -0,0 +1,5 @@
+db label
+db label & 0xff
+section .bss
+resb 500
+label:
diff --git a/libyasm/tests/value-mask.errwarn b/libyasm/tests/value-mask.errwarn
new file mode 100644
index 0000000..9df5a66
--- /dev/null
+++ b/libyasm/tests/value-mask.errwarn
@@ -0,0 +1 @@
+-:1: warning: value does not fit in 8 bit field
diff --git a/libyasm/tests/value-mask.hex b/libyasm/tests/value-mask.hex
new file mode 100644
index 0000000..8cae27c
--- /dev/null
+++ b/libyasm/tests/value-mask.hex
@@ -0,0 +1,2 @@
+f8
+f8
diff --git a/libyasm/tests/value-samesym.asm b/libyasm/tests/value-samesym.asm
new file mode 100644
index 0000000..da32599
--- /dev/null
+++ b/libyasm/tests/value-samesym.asm
@@ -0,0 +1,2 @@
+extern RW
+mov [eax + (RW + 22032) - (RW + 23056)], eax
diff --git a/libyasm/tests/value-samesym.errwarn b/libyasm/tests/value-samesym.errwarn
new file mode 100644
index 0000000..58c850b
--- /dev/null
+++ b/libyasm/tests/value-samesym.errwarn
@@ -0,0 +1 @@
+-:1: warning: binary object format does not support extern variables
diff --git a/libyasm/tests/value-samesym.hex b/libyasm/tests/value-samesym.hex
new file mode 100644
index 0000000..4bab16b
--- /dev/null
+++ b/libyasm/tests/value-samesym.hex
@@ -0,0 +1,8 @@
+67
+66
+89
+80
+00
+fc
+ff
+ff
diff --git a/libyasm/valparam.c b/libyasm/valparam.c
new file mode 100644
index 0000000..88e41a7
--- /dev/null
+++ b/libyasm/valparam.c
@@ -0,0 +1,385 @@
+/*
+ * Value/Parameter type functions
+ *
+ * Copyright (C) 2001-2007 Peter Johnson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "util.h"
+
+#include "libyasm-stdint.h"
+#include "coretype.h"
+#include "valparam.h"
+
+#include "errwarn.h"
+#include "intnum.h"
+#include "expr.h"
+#include "symrec.h"
+
+#include "section.h"
+
+void
+yasm_call_directive(const yasm_directive *directive, yasm_object *object,
+ yasm_valparamhead *valparams,
+ yasm_valparamhead *objext_valparams, unsigned long line)
+{
+ yasm_valparam *vp;
+
+ if ((directive->flags & (YASM_DIR_ARG_REQUIRED|YASM_DIR_ID_REQUIRED)) &&
+ (!valparams || !yasm_vps_first(valparams))) {
+ yasm_error_set(YASM_ERROR_SYNTAX,
+ N_("directive `%s' requires an argument"),
+ directive->name);
+ return;
+ }
+ if (valparams) {
+ vp = yasm_vps_first(valparams);
+ if ((directive->flags & YASM_DIR_ID_REQUIRED) &&
+ vp->type != YASM_PARAM_ID) {
+ yasm_error_set(YASM_ERROR_SYNTAX,
+ N_("directive `%s' requires an identifier parameter"),
+ directive->name);
+ return;
+ }
+ }
+ directive->handler(object, valparams, objext_valparams, line);
+}
+
+yasm_valparam *
+yasm_vp_create_id(/*@keep@*/ char *v, /*@keep@*/ char *p, int id_prefix)
+{
+ yasm_valparam *r = yasm_xmalloc(sizeof(yasm_valparam));
+ r->val = v;
+ r->type = YASM_PARAM_ID;
+ r->param.id = p;
+ r->id_prefix = (char)id_prefix;
+ return r;
+}
+
+yasm_valparam *
+yasm_vp_create_string(/*@keep@*/ char *v, /*@keep@*/ char *p)
+{
+ yasm_valparam *r = yasm_xmalloc(sizeof(yasm_valparam));
+ r->val = v;
+ r->type = YASM_PARAM_STRING;
+ r->param.str = p;
+ r->id_prefix = '\0';
+ return r;
+}
+
+yasm_valparam *
+yasm_vp_create_expr(/*@keep@*/ char *v, /*@keep@*/ yasm_expr *p)
+{
+ yasm_valparam *r = yasm_xmalloc(sizeof(yasm_valparam));
+ r->val = v;
+ r->type = YASM_PARAM_EXPR;
+ r->param.e = p;
+ r->id_prefix = '\0';
+ return r;
+}
+
+/*@null@*/ /*@only@*/ yasm_expr *
+yasm_vp_expr(const yasm_valparam *vp, yasm_symtab *symtab, unsigned long line)
+{
+ if (!vp)
+ return NULL;
+ switch (vp->type) {
+ case YASM_PARAM_ID:
+ return yasm_expr_create_ident(yasm_expr_sym(
+ yasm_symtab_use(symtab, yasm_vp_id(vp), line)), line);
+ case YASM_PARAM_EXPR:
+ return yasm_expr_copy(vp->param.e);
+ default:
+ return NULL;
+ }
+}
+
+/*@null@*/ /*@dependent@*/ const char *
+yasm_vp_string(const yasm_valparam *vp)
+{
+ if (!vp)
+ return NULL;
+ switch (vp->type) {
+ case YASM_PARAM_ID:
+ return vp->param.id;
+ case YASM_PARAM_STRING:
+ return vp->param.str;
+ default:
+ return NULL;
+ }
+}
+
+/*@null@*/ /*@dependent@*/ const char *
+yasm_vp_id(const yasm_valparam *vp)
+{
+ if (!vp)
+ return NULL;
+ if (vp->type == YASM_PARAM_ID) {
+ if (vp->param.id[0] == vp->id_prefix)
+ return &vp->param.id[1];
+ else
+ return vp->param.id;
+ }
+ return NULL;
+}
+
+void
+yasm_vps_delete(yasm_valparamhead *headp)
+{
+ yasm_valparam *cur, *next;
+
+ cur = STAILQ_FIRST(headp);
+ while (cur) {
+ next = STAILQ_NEXT(cur, link);
+ if (cur->val)
+ yasm_xfree(cur->val);
+ switch (cur->type) {
+ case YASM_PARAM_ID:
+ yasm_xfree(cur->param.id);
+ break;
+ case YASM_PARAM_STRING:
+ yasm_xfree(cur->param.str);
+ break;
+ case YASM_PARAM_EXPR:
+ yasm_expr_destroy(cur->param.e);
+ break;
+ }
+ yasm_xfree(cur);
+ cur = next;
+ }
+ STAILQ_INIT(headp);
+}
+
+void
+yasm_vps_print(const yasm_valparamhead *headp, FILE *f)
+{
+ const yasm_valparam *vp;
+
+ if(!headp) {
+ fprintf(f, "(none)");
+ return;
+ }
+
+ yasm_vps_foreach(vp, headp) {
+ if (vp->val)
+ fprintf(f, "(\"%s\",", vp->val);
+ else
+ fprintf(f, "((nil),");
+ switch (vp->type) {
+ case YASM_PARAM_ID:
+ fprintf(f, "%s", vp->param.id);
+ break;
+ case YASM_PARAM_STRING:
+ fprintf(f, "\"%s\"", vp->param.str);
+ break;
+ case YASM_PARAM_EXPR:
+ yasm_expr_print(vp->param.e, f);
+ break;
+ }
+ fprintf(f, ")");
+ if (yasm_vps_next(vp))
+ fprintf(f, ",");
+ }
+}
+
+yasm_valparamhead *
+yasm_vps_create(void)
+{
+ yasm_valparamhead *headp = yasm_xmalloc(sizeof(yasm_valparamhead));
+ yasm_vps_initialize(headp);
+ return headp;
+}
+
+void
+yasm_vps_destroy(yasm_valparamhead *headp)
+{
+ yasm_vps_delete(headp);
+ yasm_xfree(headp);
+}
+
+int
+yasm_dir_helper(void *obj, yasm_valparam *vp_first, unsigned long line,
+ const yasm_dir_help *help, size_t nhelp, void *data,
+ int (*helper_valparam) (void *obj, yasm_valparam *vp,
+ unsigned long line, void *data))
+{
+ yasm_valparam *vp = vp_first;
+ int anymatched = 0;
+ int matched;
+
+ if (!vp)
+ return 0;
+
+ do {
+ const char *s;
+ size_t i;
+
+ matched = 0;
+ if (!vp->val && (s = yasm_vp_id(vp))) {
+ for (i=0; i<nhelp; i++) {
+ if (help[i].needsparam == 0 &&
+ yasm__strcasecmp(s, help[i].name) == 0) {
+ if (help[i].helper(obj, vp, line,
+ ((char *)data)+help[i].off,
+ help[i].arg) != 0)
+ return -1;
+ matched = 1;
+ anymatched = 1;
+ break;
+ }
+ }
+ } else if (vp->val) {
+ for (i=0; i<nhelp; i++) {
+ if (help[i].needsparam == 1 &&
+ yasm__strcasecmp(vp->val, help[i].name) == 0) {
+ if (help[i].helper(obj, vp, line,
+ ((char *)data)+help[i].off,
+ help[i].arg) != 0)
+ return -1;
+ matched = 1;
+ anymatched = 1;
+ break;
+ }
+ }
+ }
+
+ if (!matched) {
+ int final = helper_valparam(obj, vp, line, data);
+ if (final < 0)
+ return -1;
+ if (final > 0)
+ anymatched = 1;
+ }
+ } while((vp = yasm_vps_next(vp)));
+
+ return anymatched;
+}
+
+int
+yasm_dir_helper_flag_or(void *obj, yasm_valparam *vp, unsigned long line,
+ void *d, uintptr_t flag)
+{
+ unsigned long *flags = (unsigned long *)d;
+ *flags |= flag;
+ return 0;
+}
+
+int
+yasm_dir_helper_flag_and(void *obj, yasm_valparam *vp, unsigned long line,
+ void *d, uintptr_t flag)
+{
+ unsigned long *flags = (unsigned long *)d;
+ *flags &= ~flag;
+ return 0;
+}
+
+int
+yasm_dir_helper_flag_set(void *obj, yasm_valparam *vp, unsigned long line,
+ void *d, uintptr_t flag)
+{
+ unsigned long *flags = (unsigned long *)d;
+ *flags = flag;
+ return 0;
+}
+
+int
+yasm_dir_helper_expr(void *obj, yasm_valparam *vp, unsigned long line,
+ void *data, uintptr_t arg)
+{
+ yasm_object *object = (yasm_object *)obj;
+ yasm_expr **expr = (yasm_expr **)data;
+
+ if (*expr)
+ yasm_expr_destroy(*expr);
+ if (!(*expr = yasm_vp_expr(vp, object->symtab, line))) {
+ yasm_error_set(YASM_ERROR_VALUE, N_("argument to `%s' is not an expression"),
+ vp->val);
+ return -1;
+ }
+ return 0;
+}
+
+int
+yasm_dir_helper_intn(void *obj, yasm_valparam *vp, unsigned long line,
+ void *data, uintptr_t arg)
+{
+ yasm_object *object = (yasm_object *)obj;
+ /*@only@*/ /*@null@*/ yasm_expr *e;
+ /*@dependent@*/ /*@null@*/ yasm_intnum *local;
+ yasm_intnum **intn = (yasm_intnum **)data;
+
+ if (*intn)
+ yasm_intnum_destroy(*intn);
+ if (!(e = yasm_vp_expr(vp, object->symtab, line)) ||
+ !(local = yasm_expr_get_intnum(&e, 0))) {
+ yasm_error_set(YASM_ERROR_NOT_CONSTANT,
+ N_("argument to `%s' is not an integer"),
+ vp->val);
+ if (e)
+ yasm_expr_destroy(e);
+ return -1;
+ }
+ *intn = yasm_intnum_copy(local);
+ yasm_expr_destroy(e);
+ return 0;
+}
+
+int
+yasm_dir_helper_string(void *obj, yasm_valparam *vp, unsigned long line,
+ void *data, uintptr_t arg)
+{
+ /*@dependent@*/ /*@null@*/ const char *local;
+ char **s = (char **)data;
+
+ if (*s)
+ yasm_xfree(*s);
+ if (!(local = yasm_vp_string(vp))) {
+ yasm_error_set(YASM_ERROR_VALUE,
+ N_("argument to `%s' is not a string or identifier"),
+ vp->val);
+ return -1;
+ }
+ *s = yasm__xstrdup(local);
+ return 0;
+}
+
+int
+yasm_dir_helper_valparam_warn(void *obj, yasm_valparam *vp,
+ unsigned long line, void *data)
+{
+ const char *s;
+
+ if (vp->val) {
+ yasm_warn_set(YASM_WARN_GENERAL, N_("Unrecognized qualifier `%s'"),
+ vp->val);
+ return 0;
+ }
+
+ if ((s = yasm_vp_id(vp)))
+ yasm_warn_set(YASM_WARN_GENERAL, N_("Unrecognized qualifier `%s'"), s);
+ else if (vp->type == YASM_PARAM_STRING)
+ yasm_warn_set(YASM_WARN_GENERAL, N_("Unrecognized string qualifier"));
+ else
+ yasm_warn_set(YASM_WARN_GENERAL, N_("Unrecognized numeric qualifier"));
+
+ return 0;
+}
diff --git a/libyasm/valparam.h b/libyasm/valparam.h
new file mode 100644
index 0000000..d7343d4
--- /dev/null
+++ b/libyasm/valparam.h
@@ -0,0 +1,408 @@
+/**
+ * \file libyasm/valparam.h
+ * \brief YASM value/parameter interface.
+ *
+ * \license
+ * Copyright (C) 2001-2007 Peter Johnson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * \endlicense
+ */
+#ifndef YASM_VALPARAM_H
+#define YASM_VALPARAM_H
+
+#ifndef YASM_LIB_DECL
+#define YASM_LIB_DECL
+#endif
+
+/** Value/parameter pair. \internal */
+struct yasm_valparam {
+ /*@reldef@*/ STAILQ_ENTRY(yasm_valparam) link; /**< Next pair in list */
+ /*@owned@*/ /*@null@*/ char *val; /**< Value */
+
+ /** Parameter type. */
+ enum yasm_param_type {
+ YASM_PARAM_ID, /**< Identifier */
+ YASM_PARAM_STRING, /**< String */
+ YASM_PARAM_EXPR /**< Expression */
+ } type; /**< Parameter type */
+
+ /** Parameter value. */
+ union yasm_param {
+ /*@owned@*/ char *id; /**< Identifier */
+ /*@owned@*/ char *str; /**< String */
+ /*@owned@*/ yasm_expr *e; /**< Expression */
+ } param; /**< Parameter */
+
+ /** Prefix character that indicates a raw identifier. When
+ * yasm_vp_string() is called on a #YASM_PARAM_ID, all characters are
+ * returned. When yasm_vp_id() is called on a #YASM_PARAM_ID, if the
+ * identifier begins with this character, this character is stripped
+ * from the returned value.
+ */
+ char id_prefix;
+};
+
+/** Linked list of value/parameter pairs. \internal */
+/*@reldef@*/ STAILQ_HEAD(yasm_valparamhead, yasm_valparam);
+
+/** Directive list entry structure. */
+struct yasm_directive {
+ /** Directive name. GAS directives should include the ".", NASM
+ * directives should just be the raw name (not including the []).
+ * NULL entry required to terminate list of directives.
+ */
+ /*@null@*/ const char *name;
+
+ const char *parser; /**< Parser keyword */
+
+ /** Handler callback function for the directive.
+ * \param object object
+ * \param valparams value/parameters
+ * \param objext_valparams object format-specific value/parameters
+ * \param line virtual line (from yasm_linemap)
+ */
+ void (*handler) (yasm_object *object, yasm_valparamhead *valparams,
+ yasm_valparamhead *objext_valparams, unsigned long line);
+
+ /** Flags for pre-handler parameter checking. */
+ enum yasm_directive_flags {
+ YASM_DIR_ANY = 0, /**< Any valparams accepted */
+ YASM_DIR_ARG_REQUIRED = 1, /**< Require at least 1 valparam */
+ YASM_DIR_ID_REQUIRED = 2 /**< First valparam must be ID */
+ } flags;
+};
+
+/** Call a directive. Performs any valparam checks asked for by the
+ * directive prior to call. Note that for a variety of reasons, a directive
+ * can generate an error.
+ * \param directive directive
+ * \param object object
+ * \param valparams value/parameters
+ * \param objext_valparams object format-specific value/parameters
+ * \param line virtual line (from yasm_linemap)
+ */
+YASM_LIB_DECL
+void yasm_call_directive(const yasm_directive *directive, yasm_object *object,
+ yasm_valparamhead *valparams,
+ yasm_valparamhead *objext_valparams,
+ unsigned long line);
+
+/** Create a new valparam with identifier parameter.
+ * \param v value
+ * \param p parameter
+ * \param id_prefix identifier prefix for raw identifiers
+ * \return Newly allocated valparam.
+ */
+YASM_LIB_DECL
+yasm_valparam *yasm_vp_create_id(/*@keep@*/ char *v, /*@keep@*/ char *p,
+ int id_prefix);
+
+/** Create a new valparam with string parameter.
+ * \param v value
+ * \param p parameter
+ * \return Newly allocated valparam.
+ */
+YASM_LIB_DECL
+yasm_valparam *yasm_vp_create_string(/*@keep@*/ char *v, /*@keep@*/ char *p);
+
+/** Create a new valparam with expression parameter.
+ * \param v value
+ * \param p parameter
+ * \return Newly allocated valparam.
+ */
+YASM_LIB_DECL
+yasm_valparam *yasm_vp_create_expr(/*@keep@*/ char *v,
+ /*@keep@*/ yasm_expr *p);
+
+/** Get a valparam parameter as an expr. If the parameter is an identifier,
+ * it's treated as a symbol (yasm_symtab_use() is called to convert it).
+ * \param vp valparam
+ * \param symtab symbol table
+ * \param line virtual line
+ * \return Expression, or NULL if vp is NULL or the parameter cannot be
+ * converted to an expression.
+ */
+YASM_LIB_DECL
+/*@null@*/ /*@only@*/ yasm_expr *yasm_vp_expr
+ (const yasm_valparam *vp, yasm_symtab *symtab, unsigned long line);
+
+/** Get a valparam parameter as a string. If the parameter is an identifier,
+ * it's treated as a string.
+ * \param vp valparam
+ * \return String, or NULL if vp is NULL or the parameter cannot be realized
+ * as a string.
+ */
+YASM_LIB_DECL
+/*@null@*/ /*@dependent@*/ const char *yasm_vp_string(const yasm_valparam *vp);
+
+/** Get a valparam parameter as an identifier.
+ * \param vp valparam
+ * \return Identifier (string), or NULL if vp is NULL or the parameter is not
+ * an identifier.
+ */
+YASM_LIB_DECL
+/*@null@*/ /*@dependent@*/ const char *yasm_vp_id(const yasm_valparam *vp);
+
+/** Create a new linked list of valparams.
+ * \return Newly allocated valparam list.
+ */
+YASM_LIB_DECL
+yasm_valparamhead *yasm_vps_create(void);
+
+/** Destroy a list of valparams (created with yasm_vps_create).
+ * \param headp list of valparams
+ */
+YASM_LIB_DECL
+void yasm_vps_destroy(yasm_valparamhead *headp);
+
+/** Initialize linked list of valparams.
+ * \param headp linked list
+ */
+void yasm_vps_initialize(/*@out@*/ yasm_valparamhead *headp);
+#ifndef YASM_DOXYGEN
+#define yasm_vps_initialize(headp) STAILQ_INIT(headp)
+#endif
+
+/** Destroy (free allocated memory for) linked list of valparams (created with
+ * yasm_vps_initialize).
+ * \warning Deletes val/params.
+ * \param headp linked list
+ */
+YASM_LIB_DECL
+void yasm_vps_delete(yasm_valparamhead *headp);
+
+/** Append valparam to tail of linked list.
+ * \param headp linked list
+ * \param vp valparam
+ */
+void yasm_vps_append(yasm_valparamhead *headp, /*@keep@*/ yasm_valparam *vp);
+#ifndef YASM_DOXYGEN
+#define yasm_vps_append(headp, vp) do { \
+ if (vp) \
+ STAILQ_INSERT_TAIL(headp, vp, link); \
+ } while(0)
+#endif
+
+/** Get first valparam in linked list.
+ * \param headp linked list
+ * \return First valparam in linked list.
+ */
+/*@null@*/ /*@dependent@*/ yasm_valparam *yasm_vps_first
+ (yasm_valparamhead *headp);
+#ifndef YASM_DOXYGEN
+#define yasm_vps_first(headp) STAILQ_FIRST(headp)
+#endif
+
+/** Get next valparam in linked list.
+ * \param cur previous valparam in linked list
+ * \return Next valparam in linked list.
+ */
+/*@null@*/ /*@dependent@*/ yasm_valparam *yasm_vps_next(yasm_valparam *cur);
+#ifndef YASM_DOXYGEN
+#define yasm_vps_next(cur) STAILQ_NEXT(cur, link)
+#endif
+
+/** Iterate through linked list of valparams.
+ * \internal
+ * \param iter iterator variable
+ * \param headp linked list
+ */
+#ifndef YASM_DOXYGEN
+#define yasm_vps_foreach(iter, headp) STAILQ_FOREACH(iter, headp, link)
+#endif
+
+/** Print linked list of valparams. For debugging purposes.
+ * \param f file
+ * \param headp linked list
+ */
+YASM_LIB_DECL
+void yasm_vps_print(/*@null@*/ const yasm_valparamhead *headp, FILE *f);
+
+/** Directive valparam parse helper structure. */
+typedef struct yasm_dir_help {
+ /** Value portion of val=param (if needsparam=1), or standalone identifier
+ * (if needsparam=0).
+ */
+ const char *name;
+
+ /** 1 if value requires parameter, 0 if it must not have a parameter. */
+ int needsparam;
+
+ /** Helper callback function if name and parameter existence match.
+ * \param obj obj passed into yasm_dir_helper()
+ * \param vp value/parameter
+ * \param line line passed into yasm_dir_helper()
+ * \param data data passed into yasm_dir_helper() plus
+ #yasm_dir_help.off offset
+ * \param arg #yasm_dir_help.arg argument
+ * \return -1 on error, 0 otherwise.
+ */
+ int (*helper) (void *obj, yasm_valparam *vp, unsigned long line,
+ void *data, uintptr_t arg);
+
+ /** Offset added to data pointer passed into yasm_dir_helper() before
+ * data pointer is given to #yasm_dir_help.helper(). This is so that
+ * a structure can be passed into yasm_dir_helper() and this can be an
+ * offsetof() to point the helper function to a specific structure
+ * member.
+ */
+ size_t off;
+
+ /** Argument to pass in as the arg parameter to #yasm_dir_help.helper().
+ */
+ uintptr_t arg;
+} yasm_dir_help;
+
+/** Help parse a list of directive value/parameters. Takes an array of
+ * #yasm_dir_help structures and tries to match val=param (or just val)
+ * against the passed value/parameters. When no match is found in the
+ * array of help structures, calls helper_valparam.
+ * \param obj object to be passed to yasm_dir_help.helper() or
+ * helper_valparam() callback
+ * \param vp_first first value/parameter to examine
+ * \param line virtual line number; passed down to helper callback
+ * \param help array of #yasm_dir_help structures
+ * \param nhelp number of array elements
+ * \param data base data pointer; if a match is found,
+ * the respective #yasm_dir_help.off is added to this
+ * prior to it being passed to the helper callback
+ * \param helper_valparam catch-all callback; should return -1 on error,
+ * 0 if not matched, 1 if matched.
+ * \return -1 on error, 1 if any arguments matched (including via
+ * catch-all callback), 0 if no match.
+ */
+YASM_LIB_DECL
+int yasm_dir_helper(void *obj, yasm_valparam *vp_first, unsigned long line,
+ const yasm_dir_help *help, size_t nhelp, void *data,
+ int (*helper_valparam) (void *object,
+ yasm_valparam *vp,
+ unsigned long line,
+ void *data));
+
+/** Standard helper for yasm_dir_helper() that simply sets a flag when called.
+ * It does not look at the vp; rather, it uses the value of the arg parameter,
+ * and stores an unsigned long value to data.
+ * \param obj unused
+ * \param vp unused
+ * \param line unused
+ * \param data pointer to an unsigned long
+ * \param arg flag to set
+ * \return 0
+ */
+YASM_LIB_DECL
+int yasm_dir_helper_flag_set(void *obj, yasm_valparam *vp, unsigned long line,
+ void *data, uintptr_t arg);
+
+/** Standard helper for yasm_dir_helper() that simply ORs a flag when called.
+ * It does not look at the vp; rather, it uses the value of the arg parameter,
+ * and ORs it with the unsigned long value in data.
+ * \param obj unused
+ * \param vp unused
+ * \param line unused
+ * \param data pointer to an unsigned long
+ * \param arg flag to OR
+ * \return 0
+ */
+YASM_LIB_DECL
+int yasm_dir_helper_flag_or(void *obj, yasm_valparam *vp, unsigned long line,
+ void *data, uintptr_t arg);
+
+/** Standard helper for yasm_dir_helper() that simply ANDs a flag when called.
+ * It does not look at the vp; rather, it uses the value of the arg parameter,
+ * and ANDs its inverse (~) with the unsigned long value in data.
+ * \param obj unused
+ * \param vp unused
+ * \param line unused
+ * \param data pointer to an unsigned long
+ * \param arg flag to AND
+ * \return 0
+ */
+YASM_LIB_DECL
+int yasm_dir_helper_flag_and(void *obj, yasm_valparam *vp, unsigned long line,
+ void *data, uintptr_t arg);
+
+/** Standard helper for yasm_dir_helper() that parses an expr parameter.
+ * The #yasm_dir_help structure that uses this function should have
+ * needsparam=1. The obj parameter to yasm_dir_helper() when this helper
+ * is used MUST point to a #yasm_object. In addition, the data parameter
+ * that is ultimately passed to this function (e.g. yasm_dir_helper() data
+ * parameter plus #yasm_dir_help.off) must point to a #yasm_expr *
+ * initialized to NULL.
+ * \param obj object; must be #yasm_object
+ * \param vp valparam
+ * \param line virtual line number
+ * \param data pointer to #yasm_expr *
+ * \param arg unused argument
+ * \return -1 on error, 0 otherwise.
+ */
+YASM_LIB_DECL
+int yasm_dir_helper_expr(void *obj, yasm_valparam *vp, unsigned long line,
+ void *data, uintptr_t arg);
+
+/** Standard helper for yasm_dir_helper() that parses an intnum parameter.
+ * The #yasm_dir_help structure that uses this function should have
+ * needsparam=1. The obj parameter to yasm_dir_helper() when this helper
+ * is used MUST point to a #yasm_object. In addition, the data parameter
+ * that is ultimately passed to this function (e.g. yasm_dir_helper() data
+ * parameter plus #yasm_dir_help.off) must point to a #yasm_intnum *
+ * initialized to NULL.
+ * \param obj object; must be #yasm_object
+ * \param vp valparam
+ * \param line virtual line number
+ * \param data pointer to #yasm_intnum *
+ * \param arg unused argument
+ * \return -1 on error, 0 otherwise.
+ */
+YASM_LIB_DECL
+int yasm_dir_helper_intn(void *obj, yasm_valparam *vp, unsigned long line,
+ void *data, uintptr_t arg);
+
+/** Standard helper for yasm_dir_helper() that parses an string (or
+ * standalone identifier) parameter.
+ * The #yasm_dir_help structure that uses this function should have
+ * needsparam=1. The data parameter that is ultimately passed to this
+ * function (e.g. yasm_dir_helper() data parameter plus #yasm_dir_help.off)
+ * must point to a char * initialized to NULL.
+ * \param obj unused
+ * \param vp valparam
+ * \param line unused
+ * \param data pointer to char *
+ * \param arg unused
+ * \return -1 on error, 0 otherwise.
+ */
+YASM_LIB_DECL
+int yasm_dir_helper_string(void *obj, yasm_valparam *vp, unsigned long line,
+ void *data, uintptr_t arg);
+
+/** Standard catch-all callback fro yasm_dir_helper(). Generates standard
+ * warning for all valparams.
+ * \param obj unused
+ * \param vp valparam
+ * \param line unused
+ * \param data unused
+ * \return 0
+ */
+YASM_LIB_DECL
+int yasm_dir_helper_valparam_warn(void *obj, yasm_valparam *vp,
+ unsigned long line, void *data);
+#endif
diff --git a/libyasm/value.c b/libyasm/value.c
new file mode 100644
index 0000000..3ab73c1
--- /dev/null
+++ b/libyasm/value.c
@@ -0,0 +1,771 @@
+/*
+ * Value handling
+ *
+ * Copyright (C) 2006-2007 Peter Johnson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "util.h"
+
+#include "libyasm-stdint.h"
+#include "coretype.h"
+#include "bitvect.h"
+
+#include "errwarn.h"
+#include "intnum.h"
+#include "floatnum.h"
+#include "expr.h"
+#include "value.h"
+#include "symrec.h"
+
+#include "bytecode.h"
+#include "section.h"
+
+#include "arch.h"
+
+
+void
+yasm_value_initialize(/*@out@*/ yasm_value *value,
+ /*@null@*/ /*@kept@*/ yasm_expr *e, unsigned int size)
+{
+ value->abs = e;
+ value->rel = NULL;
+ value->wrt = NULL;
+ value->seg_of = 0;
+ value->rshift = 0;
+ value->curpos_rel = 0;
+ value->ip_rel = 0;
+ value->jump_target = 0;
+ value->section_rel = 0;
+ value->no_warn = 0;
+ value->sign = 0;
+ value->size = size;
+}
+
+void
+yasm_value_init_sym(/*@out@*/ yasm_value *value, /*@null@*/ yasm_symrec *sym,
+ unsigned int size)
+{
+ value->abs = NULL;
+ value->rel = sym;
+ value->wrt = NULL;
+ value->seg_of = 0;
+ value->rshift = 0;
+ value->curpos_rel = 0;
+ value->ip_rel = 0;
+ value->jump_target = 0;
+ value->section_rel = 0;
+ value->no_warn = 0;
+ value->sign = 0;
+ value->size = size;
+}
+
+void
+yasm_value_init_copy(yasm_value *value, const yasm_value *orig)
+{
+ value->abs = orig->abs ? yasm_expr_copy(orig->abs) : NULL;
+ value->rel = orig->rel;
+ value->wrt = orig->wrt;
+ value->seg_of = orig->seg_of;
+ value->rshift = orig->rshift;
+ value->curpos_rel = orig->curpos_rel;
+ value->ip_rel = orig->ip_rel;
+ value->jump_target = orig->jump_target;
+ value->section_rel = orig->section_rel;
+ value->no_warn = orig->no_warn;
+ value->sign = orig->sign;
+ value->size = orig->size;
+}
+
+void
+yasm_value_delete(yasm_value *value)
+{
+ if (value->abs)
+ yasm_expr_destroy(value->abs);
+ value->abs = NULL;
+ value->rel = NULL;
+}
+
+void
+yasm_value_set_curpos_rel(yasm_value *value, yasm_bytecode *bc,
+ unsigned int ip_rel)
+{
+ value->curpos_rel = 1;
+ value->ip_rel = ip_rel;
+ /* In order for us to correctly output curpos-relative values, we must
+ * have a relative portion of the value. If one doesn't exist, point
+ * to a custom absolute symbol.
+ */
+ if (!value->rel) {
+ yasm_object *object = yasm_section_get_object(yasm_bc_get_section(bc));
+ value->rel = yasm_symtab_abs_sym(object->symtab);
+ }
+}
+
+static int
+value_finalize_scan(yasm_value *value, yasm_expr *e,
+ /*@null@*/ yasm_bytecode *expr_precbc, int ssym_not_ok)
+{
+ int i;
+ /*@dependent@*/ yasm_section *sect;
+ /*@dependent@*/ /*@null@*/ yasm_bytecode *precbc;
+
+ unsigned long shamt; /* for SHR */
+
+ /* Yes, this has a maximum upper bound on 32 terms, based on an
+ * "insane number of terms" (and ease of implementation) WAG.
+ * The right way to do this would be a stack-based alloca, but that's
+ * not ISO C. We really don't want to malloc here as this function is
+ * hit a lot!
+ *
+ * This is a bitmask to keep things small, as this is a recursive
+ * routine and we don't want to eat up stack space.
+ */
+ unsigned long used; /* for ADD */
+
+ /* Thanks to this running after a simplify, we don't need to iterate
+ * down through IDENTs or handle SUB.
+ *
+ * We scan for a single symrec, gathering info along the way. After
+ * we've found the symrec, we keep scanning but error if we find
+ * another one. We pull out the single symrec and any legal operations
+ * performed on it.
+ *
+ * Also, if we find a float anywhere, we don't allow mixing of a single
+ * symrec with it.
+ */
+ switch (e->op) {
+ case YASM_EXPR_ADD:
+ /* Okay for single symrec anywhere in expr.
+ * Check for single symrec anywhere.
+ * Handle symrec-symrec by checking for (-1*symrec)
+ * and symrec term pairs (where both symrecs are in the same
+ * segment).
+ */
+ if (e->numterms > 32)
+ yasm__fatal(N_("expression on line %d has too many add terms;"
+ " internal limit of 32"), e->line);
+
+ used = 0;
+
+ for (i=0; i<e->numterms; i++) {
+ int j;
+ yasm_expr *sube;
+ yasm_intnum *intn;
+ yasm_symrec *sym;
+ /*@dependent@*/ yasm_section *sect2;
+ /*@dependent@*/ /*@null@*/ yasm_bytecode *precbc2;
+
+ /* First look for an (-1*symrec) term */
+ if (e->terms[i].type != YASM_EXPR_EXPR)
+ continue;
+ sube = e->terms[i].data.expn;
+
+ if (sube->op != YASM_EXPR_MUL || sube->numterms != 2) {
+ /* recurse instead */
+ if (value_finalize_scan(value, sube, expr_precbc,
+ ssym_not_ok))
+ return 1;
+ continue;
+ }
+
+ if (sube->terms[0].type == YASM_EXPR_INT &&
+ sube->terms[1].type == YASM_EXPR_SYM) {
+ intn = sube->terms[0].data.intn;
+ sym = sube->terms[1].data.sym;
+ } else if (sube->terms[0].type == YASM_EXPR_SYM &&
+ sube->terms[1].type == YASM_EXPR_INT) {
+ sym = sube->terms[0].data.sym;
+ intn = sube->terms[1].data.intn;
+ } else {
+ if (value_finalize_scan(value, sube, expr_precbc,
+ ssym_not_ok))
+ return 1;
+ continue;
+ }
+
+ if (!yasm_intnum_is_neg1(intn)) {
+ if (value_finalize_scan(value, sube, expr_precbc,
+ ssym_not_ok))
+ return 1;
+ continue;
+ }
+
+ /* Look for the same symrec term; even if both are external,
+ * they should cancel out.
+ */
+ for (j=0; j<e->numterms; j++) {
+ if (e->terms[j].type == YASM_EXPR_SYM
+ && e->terms[j].data.sym == sym
+ && (used & (1<<j)) == 0) {
+ /* Mark as used */
+ used |= 1<<j;
+
+ /* Replace both symrec portions with 0 */
+ yasm_expr_destroy(sube);
+ e->terms[i].type = YASM_EXPR_INT;
+ e->terms[i].data.intn = yasm_intnum_create_uint(0);
+ e->terms[j].type = YASM_EXPR_INT;
+ e->terms[j].data.intn = yasm_intnum_create_uint(0);
+
+ break; /* stop looking */
+ }
+ }
+ if (j != e->numterms)
+ continue;
+
+ if (!yasm_symrec_get_label(sym, &precbc)) {
+ if (value_finalize_scan(value, sube, expr_precbc,
+ ssym_not_ok))
+ return 1;
+ continue;
+ }
+ sect2 = yasm_bc_get_section(precbc);
+
+ /* Now look for a unused symrec term in the same segment */
+ for (j=0; j<e->numterms; j++) {
+ if (e->terms[j].type == YASM_EXPR_SYM
+ && yasm_symrec_get_label(e->terms[j].data.sym,
+ &precbc2)
+ && (sect = yasm_bc_get_section(precbc2))
+ && sect == sect2
+ && (used & (1<<j)) == 0) {
+ /* Mark as used */
+ used |= 1<<j;
+ break; /* stop looking */
+ }
+ }
+
+ /* We didn't match in the same segment. If the
+ * -1*symrec is actually -1*curpos, we can match
+ * unused symrec terms in other segments and generate
+ * a curpos-relative reloc.
+ *
+ * Similarly, handle -1*symrec in other segment via the
+ * following transformation:
+ * other-this = (other-.)+(.-this)
+ * We can only do this transformation if "this" is in
+ * this expr's segment.
+ *
+ * Don't do this if we've already become curpos-relative.
+ * The unmatched symrec will be caught below.
+ */
+ if (j == e->numterms && !value->curpos_rel
+ && (yasm_symrec_is_curpos(sym)
+ || (expr_precbc
+ && sect2 == yasm_bc_get_section(expr_precbc)))) {
+ for (j=0; j<e->numterms; j++) {
+ if (e->terms[j].type == YASM_EXPR_SYM
+ && !yasm_symrec_get_equ(e->terms[j].data.sym)
+ && !yasm_symrec_is_special(e->terms[j].data.sym)
+ && (used & (1<<j)) == 0) {
+ /* Mark as used */
+ used |= 1<<j;
+ /* Mark value as curpos-relative */
+ if (value->rel || ssym_not_ok)
+ return 1;
+ value->rel = e->terms[j].data.sym;
+ value->curpos_rel = 1;
+ if (yasm_symrec_is_curpos(sym)) {
+ /* Replace both symrec portions with 0 */
+ yasm_expr_destroy(sube);
+ e->terms[i].type = YASM_EXPR_INT;
+ e->terms[i].data.intn =
+ yasm_intnum_create_uint(0);
+ e->terms[j].type = YASM_EXPR_INT;
+ e->terms[j].data.intn =
+ yasm_intnum_create_uint(0);
+ } else {
+ /* Replace positive portion with curpos */
+ yasm_object *object =
+ yasm_section_get_object(sect2);
+ yasm_symtab *symtab = object->symtab;
+ e->terms[j].data.sym =
+ yasm_symtab_define_curpos
+ (symtab, ".", expr_precbc, e->line);
+ }
+ break; /* stop looking */
+ }
+ }
+ }
+
+
+ if (j == e->numterms)
+ return 1; /* We didn't find a match! */
+ }
+
+ /* Look for unmatched symrecs. If we've already found one or
+ * we don't WANT to find one, error out.
+ */
+ for (i=0; i<e->numterms; i++) {
+ if (e->terms[i].type == YASM_EXPR_SYM
+ && (used & (1<<i)) == 0) {
+ if (value->rel || ssym_not_ok)
+ return 1;
+ value->rel = e->terms[i].data.sym;
+ /* and replace with 0 */
+ e->terms[i].type = YASM_EXPR_INT;
+ e->terms[i].data.intn = yasm_intnum_create_uint(0);
+ }
+ }
+ break;
+ case YASM_EXPR_SHR:
+ /* Okay for single symrec in LHS and constant on RHS.
+ * Single symrecs are not okay on RHS.
+ * If RHS is non-constant, don't allow single symrec on LHS.
+ * XXX: should rshift be an expr instead??
+ */
+
+ /* Check for single sym on LHS */
+ if (e->terms[0].type != YASM_EXPR_SYM)
+ break;
+
+ /* If we already have a sym, we can't take another one */
+ if (value->rel || ssym_not_ok)
+ return 1;
+
+ /* RHS must be a positive integer */
+ if (e->terms[1].type != YASM_EXPR_INT)
+ return 1; /* can't shift sym by non-constant integer */
+ shamt = yasm_intnum_get_uint(e->terms[1].data.intn);
+ if ((shamt + value->rshift) > YASM_VALUE_RSHIFT_MAX)
+ return 1; /* total shift would be too large */
+
+ /* Update value */
+ value->rshift += shamt;
+ value->rel = e->terms[0].data.sym;
+
+ /* Replace symbol with 0 */
+ e->terms[0].type = YASM_EXPR_INT;
+ e->terms[0].data.intn = yasm_intnum_create_uint(0);
+
+ /* Just leave SHR in place */
+ break;
+ case YASM_EXPR_SEG:
+ /* Okay for single symrec (can only be done once).
+ * Not okay for anything BUT a single symrec as an immediate
+ * child.
+ */
+ if (e->terms[0].type != YASM_EXPR_SYM)
+ return 1;
+
+ if (value->seg_of)
+ return 1; /* multiple SEG not legal */
+ value->seg_of = 1;
+
+ if (value->rel || ssym_not_ok)
+ return 1; /* got a relative portion somewhere else? */
+ value->rel = e->terms[0].data.sym;
+
+ /* replace with ident'ed 0 */
+ e->op = YASM_EXPR_IDENT;
+ e->terms[0].type = YASM_EXPR_INT;
+ e->terms[0].data.intn = yasm_intnum_create_uint(0);
+ break;
+ case YASM_EXPR_WRT:
+ /* Okay for single symrec in LHS and either a register or single
+ * symrec (as an immediate child) on RHS.
+ * If a single symrec on RHS, can only be done once.
+ * WRT reg is left in expr for arch to look at.
+ */
+
+ /* Handle RHS */
+ switch (e->terms[1].type) {
+ case YASM_EXPR_SYM:
+ if (value->wrt)
+ return 1;
+ value->wrt = e->terms[1].data.sym;
+ /* and drop the WRT portion */
+ e->op = YASM_EXPR_IDENT;
+ e->numterms = 1;
+ break;
+ case YASM_EXPR_REG:
+ break; /* ignore */
+ default:
+ return 1;
+ }
+
+ /* Handle LHS */
+ switch (e->terms[0].type) {
+ case YASM_EXPR_SYM:
+ if (value->rel || ssym_not_ok)
+ return 1;
+ value->rel = e->terms[0].data.sym;
+ /* and replace with 0 */
+ e->terms[0].type = YASM_EXPR_INT;
+ e->terms[0].data.intn = yasm_intnum_create_uint(0);
+ break;
+ case YASM_EXPR_EXPR:
+ /* recurse */
+ return value_finalize_scan(value, e->terms[0].data.expn,
+ expr_precbc, ssym_not_ok);
+ default:
+ break; /* ignore */
+ }
+
+ break;
+ default:
+ /* Single symrec not allowed anywhere */
+ for (i=0; i<e->numterms; i++) {
+ switch (e->terms[i].type) {
+ case YASM_EXPR_SYM:
+ return 1;
+ case YASM_EXPR_EXPR:
+ /* recurse */
+ return value_finalize_scan(value,
+ e->terms[i].data.expn,
+ expr_precbc, 1);
+ default:
+ break;
+ }
+ }
+ break;
+ }
+
+ return 0;
+}
+
+int
+yasm_value_finalize_expr(yasm_value *value, yasm_expr *e,
+ yasm_bytecode *precbc, unsigned int size)
+{
+ if (!e) {
+ yasm_value_initialize(value, NULL, size);
+ return 0;
+ }
+ yasm_value_initialize(value, e, size);
+ return yasm_value_finalize(value, precbc);
+}
+
+int
+yasm_value_finalize(yasm_value *value, yasm_bytecode *precbc)
+{
+ if (!value->abs)
+ return 0;
+
+ value->abs = yasm_expr__level_tree(value->abs, 1, 1, 0, 0, NULL, NULL);
+
+ /* quit early if there was an issue in simplify() */
+ if (yasm_error_occurred())
+ return 1;
+
+ /* Strip top-level AND masking to an all-1s mask the same size
+ * of the value size. This allows forced avoidance of overflow warnings.
+ */
+ if (value->abs->op == YASM_EXPR_AND) {
+ int term;
+
+ /* Calculate 1<<size - 1 value */
+ yasm_intnum *mask = yasm_intnum_create_uint(1);
+ yasm_intnum *mask_tmp = yasm_intnum_create_uint(value->size);
+ yasm_intnum_calc(mask, YASM_EXPR_SHL, mask_tmp);
+ yasm_intnum_set_uint(mask_tmp, 1);
+ yasm_intnum_calc(mask, YASM_EXPR_SUB, mask_tmp);
+ yasm_intnum_destroy(mask_tmp);
+
+ /* Walk terms and delete matching masks */
+ for (term=value->abs->numterms-1; term>=0; term--) {
+ if (value->abs->terms[term].type == YASM_EXPR_INT &&
+ yasm_intnum_compare(value->abs->terms[term].data.intn,
+ mask) == 0) {
+ /* Delete the intnum */
+ yasm_intnum_destroy(value->abs->terms[term].data.intn);
+
+ /* Slide everything to its right over by 1 */
+ if (term != value->abs->numterms-1) /* if it wasn't last.. */
+ memmove(&value->abs->terms[term],
+ &value->abs->terms[term+1],
+ (value->abs->numterms-1-term)*
+ sizeof(yasm_expr__item));
+
+ /* Update numterms */
+ value->abs->numterms--;
+
+ /* Indicate warnings have been disabled */
+ value->no_warn = 1;
+ }
+ }
+ if (value->abs->numterms == 1)
+ value->abs->op = YASM_EXPR_IDENT;
+ yasm_intnum_destroy(mask);
+ }
+
+ /* Handle trivial (IDENT) cases immediately */
+ if (value->abs->op == YASM_EXPR_IDENT) {
+ switch (value->abs->terms[0].type) {
+ case YASM_EXPR_INT:
+ if (yasm_intnum_is_zero(value->abs->terms[0].data.intn)) {
+ yasm_expr_destroy(value->abs);
+ value->abs = NULL;
+ }
+ return 0;
+ case YASM_EXPR_REG:
+ case YASM_EXPR_FLOAT:
+ return 0;
+ case YASM_EXPR_SYM:
+ value->rel = value->abs->terms[0].data.sym;
+ yasm_expr_destroy(value->abs);
+ value->abs = NULL;
+ return 0;
+ case YASM_EXPR_EXPR:
+ /* Bring up lower values. */
+ while (value->abs->op == YASM_EXPR_IDENT
+ && value->abs->terms[0].type == YASM_EXPR_EXPR) {
+ yasm_expr *sube = value->abs->terms[0].data.expn;
+ yasm_xfree(value->abs);
+ value->abs = sube;
+ }
+ break;
+ default:
+ yasm_internal_error(N_("unexpected expr term type"));
+ }
+ }
+
+ if (value_finalize_scan(value, value->abs, precbc, 0))
+ return 1;
+
+ value->abs = yasm_expr__level_tree(value->abs, 1, 1, 0, 0, NULL, NULL);
+
+ /* Simplify 0 in abs to NULL */
+ if (value->abs->op == YASM_EXPR_IDENT
+ && value->abs->terms[0].type == YASM_EXPR_INT
+ && yasm_intnum_is_zero(value->abs->terms[0].data.intn)) {
+ yasm_expr_destroy(value->abs);
+ value->abs = NULL;
+ }
+ return 0;
+}
+
+yasm_intnum *
+yasm_value_get_intnum(yasm_value *value, yasm_bytecode *bc, int calc_bc_dist)
+{
+ /*@dependent@*/ /*@null@*/ yasm_intnum *intn = NULL;
+ /*@only@*/ yasm_intnum *outval;
+ int sym_local;
+
+ if (value->abs) {
+ /* Handle integer expressions, if non-integer or too complex, return
+ * NULL.
+ */
+ intn = yasm_expr_get_intnum(&value->abs, calc_bc_dist);
+ if (!intn)
+ return NULL;
+ }
+
+ if (value->rel) {
+ /* If relative portion is not in bc section, return NULL.
+ * Otherwise get the relative portion's offset.
+ */
+ /*@dependent@*/ yasm_bytecode *rel_prevbc;
+ unsigned long dist;
+
+ if (!bc)
+ return NULL; /* Can't calculate relative value */
+
+ sym_local = yasm_symrec_get_label(value->rel, &rel_prevbc);
+ if (value->wrt || value->seg_of || value->section_rel || !sym_local)
+ return NULL; /* we can't handle SEG, WRT, or external symbols */
+ if (rel_prevbc->section != bc->section)
+ return NULL; /* not in this section */
+ if (!value->curpos_rel)
+ return NULL; /* not PC-relative */
+
+ /* Calculate value relative to current assembly position */
+ dist = yasm_bc_next_offset(rel_prevbc);
+ if (dist < bc->offset) {
+ outval = yasm_intnum_create_uint(bc->offset - dist);
+ yasm_intnum_calc(outval, YASM_EXPR_NEG, NULL);
+ } else {
+ dist -= bc->offset;
+ outval = yasm_intnum_create_uint(dist);
+ }
+
+ if (value->rshift > 0) {
+ /*@only@*/ yasm_intnum *shamt =
+ yasm_intnum_create_uint((unsigned long)value->rshift);
+ yasm_intnum_calc(outval, YASM_EXPR_SHR, shamt);
+ yasm_intnum_destroy(shamt);
+ }
+ /* Add in absolute portion */
+ if (intn)
+ yasm_intnum_calc(outval, YASM_EXPR_ADD, intn);
+ return outval;
+ }
+
+ if (intn)
+ return yasm_intnum_copy(intn);
+
+ /* No absolute or relative portions: output 0 */
+ return yasm_intnum_create_uint(0);
+}
+
+int
+yasm_value_output_basic(yasm_value *value, /*@out@*/ unsigned char *buf,
+ size_t destsize, yasm_bytecode *bc, int warn,
+ yasm_arch *arch)
+{
+ /*@dependent@*/ /*@null@*/ yasm_intnum *intn = NULL;
+ /*@only@*/ yasm_intnum *outval;
+ int sym_local;
+ int retval = 1;
+ unsigned int valsize = value->size;
+
+ if (value->no_warn)
+ warn = 0;
+
+ if (value->abs) {
+ /* Handle floating point expressions */
+ if (!value->rel && value->abs->op == YASM_EXPR_IDENT
+ && value->abs->terms[0].type == YASM_EXPR_FLOAT) {
+ if (yasm_arch_floatnum_tobytes(arch, value->abs->terms[0].data.flt,
+ buf, destsize, valsize, 0, warn))
+ return -1;
+ else
+ return 1;
+ }
+
+ /* Check for complex float expressions */
+ if (yasm_expr__contains(value->abs, YASM_EXPR_FLOAT)) {
+ yasm_error_set(YASM_ERROR_FLOATING_POINT,
+ N_("floating point expression too complex"));
+ return -1;
+ }
+
+ /* Handle normal integer expressions */
+ intn = yasm_expr_get_intnum(&value->abs, 1);
+
+ if (!intn) {
+ /* Second try before erroring: yasm_expr_get_intnum doesn't handle
+ * SEG:OFF, so try simplifying out any to just the OFF portion,
+ * then getting the intnum again.
+ */
+ yasm_expr *seg = yasm_expr_extract_deep_segoff(&value->abs);
+ if (seg)
+ yasm_expr_destroy(seg);
+ intn = yasm_expr_get_intnum(&value->abs, 1);
+ }
+
+ if (!intn) {
+ /* Still don't have an integer! */
+ yasm_error_set(YASM_ERROR_TOO_COMPLEX,
+ N_("expression too complex"));
+ return -1;
+ }
+ }
+
+ /* Adjust warn for signed/unsigned integer warnings */
+ if (warn != 0)
+ warn = value->sign ? -1 : 1;
+
+ if (value->rel) {
+ /* If relative portion is not in bc section, don't try to handle it
+ * here. Otherwise get the relative portion's offset.
+ */
+ /*@dependent@*/ yasm_bytecode *rel_prevbc;
+ unsigned long dist;
+
+ sym_local = yasm_symrec_get_label(value->rel, &rel_prevbc);
+ if (value->wrt || value->seg_of || value->section_rel || !sym_local)
+ return 0; /* we can't handle SEG, WRT, or external symbols */
+ if (rel_prevbc->section != bc->section)
+ return 0; /* not in this section */
+ if (!value->curpos_rel)
+ return 0; /* not PC-relative */
+
+ /* Calculate value relative to current assembly position */
+ dist = yasm_bc_next_offset(rel_prevbc);
+ if (dist < bc->offset) {
+ outval = yasm_intnum_create_uint(bc->offset - dist);
+ yasm_intnum_calc(outval, YASM_EXPR_NEG, NULL);
+ } else {
+ dist -= bc->offset;
+ outval = yasm_intnum_create_uint(dist);
+ }
+
+ if (value->rshift > 0) {
+ /*@only@*/ yasm_intnum *shamt =
+ yasm_intnum_create_uint((unsigned long)value->rshift);
+ yasm_intnum_calc(outval, YASM_EXPR_SHR, shamt);
+ yasm_intnum_destroy(shamt);
+ }
+ /* Add in absolute portion */
+ if (intn)
+ yasm_intnum_calc(outval, YASM_EXPR_ADD, intn);
+ /* Output! */
+ if (yasm_arch_intnum_tobytes(arch, outval, buf, destsize, valsize, 0,
+ bc, warn))
+ retval = -1;
+ yasm_intnum_destroy(outval);
+ return retval;
+ }
+
+ if (value->seg_of || value->rshift || value->curpos_rel || value->ip_rel
+ || value->section_rel)
+ return 0; /* We can't handle this with just an absolute */
+
+ if (intn) {
+ /* Output just absolute portion */
+ if (yasm_arch_intnum_tobytes(arch, intn, buf, destsize, valsize, 0, bc,
+ warn))
+ retval = -1;
+ } else {
+ /* No absolute or relative portions: output 0 */
+ outval = yasm_intnum_create_uint(0);
+ if (yasm_arch_intnum_tobytes(arch, outval, buf, destsize, valsize, 0,
+ bc, warn))
+ retval = -1;
+ yasm_intnum_destroy(outval);
+ }
+ return retval;
+}
+
+void
+yasm_value_print(const yasm_value *value, FILE *f, int indent_level)
+{
+ fprintf(f, "%*s%u-bit, %ssigned", indent_level, "", value->size,
+ value->sign ? "" : "un");
+ fprintf(f, "%*sAbsolute portion=", indent_level, "");
+ yasm_expr_print(value->abs, f);
+ fprintf(f, "\n");
+ if (value->rel) {
+ fprintf(f, "%*sRelative to=%s%s\n", indent_level, "",
+ value->seg_of ? "SEG " : "",
+ yasm_symrec_get_name(value->rel));
+ if (value->wrt)
+ fprintf(f, "%*s(With respect to=%s)\n", indent_level, "",
+ yasm_symrec_get_name(value->wrt));
+ if (value->rshift > 0)
+ fprintf(f, "%*s(Right shifted by=%u)\n", indent_level, "",
+ value->rshift);
+ if (value->curpos_rel)
+ fprintf(f, "%*s(Relative to current position)\n", indent_level,
+ "");
+ if (value->ip_rel)
+ fprintf(f, "%*s(IP-relative)\n", indent_level, "");
+ if (value->jump_target)
+ fprintf(f, "%*s(Jump target)\n", indent_level, "");
+ if (value->section_rel)
+ fprintf(f, "%*s(Section-relative)\n", indent_level, "");
+ if (value->no_warn)
+ fprintf(f, "%*s(Overflow warnings disabled)\n", indent_level, "");
+ }
+}
diff --git a/libyasm/value.h b/libyasm/value.h
new file mode 100644
index 0000000..4dc294b
--- /dev/null
+++ b/libyasm/value.h
@@ -0,0 +1,172 @@
+/**
+ * \file libyasm/value.h
+ * \brief YASM value interface.
+ *
+ * \license
+ * Copyright (C) 2006-2007 Peter Johnson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * \endlicense
+ */
+#ifndef YASM_VALUE_H
+#define YASM_VALUE_H
+
+#ifndef YASM_LIB_DECL
+#define YASM_LIB_DECL
+#endif
+
+/** Initialize a #yasm_value with just an expression. No processing is
+ * performed, the expression is simply stuck into value.abs and the other
+ * fields are initialized. Use yasm_expr_extract_value() to perform "smart"
+ * processing into a #yasm_value. This function is intended for use during
+ * parsing simply to ensure all fields of the value are initialized; after
+ * the parse is complete, yasm_value_extract() should be called to finalize
+ * the value. The value defaults to unsigned.
+ * \param value value to be initialized
+ * \param e expression (kept)
+ * \param size value size (in bits)
+ */
+YASM_LIB_DECL
+void yasm_value_initialize(/*@out@*/ yasm_value *value,
+ /*@null@*/ /*@kept@*/ yasm_expr *e,
+ unsigned int size);
+
+/** Initialize a #yasm_value with just a symrec. No processing is performed,
+ * the symrec is simply stuck into value.rel and the other fields are
+ * initialized.
+ * \param value value to be initialized
+ * \param sym symrec
+ * \param size value size (in bits)
+ */
+YASM_LIB_DECL
+void yasm_value_init_sym(/*@out@*/ yasm_value *value,
+ /*@null@*/ yasm_symrec *sym, unsigned int size);
+
+/** Initialize a #yasm_value as a copy of another yasm_value. Any expressions
+ * within orig are copied, so it's safe to delete the copy.
+ * \param value value (copy to create)
+ * \param orig original value
+ */
+YASM_LIB_DECL
+void yasm_value_init_copy(yasm_value *value, const yasm_value *orig);
+
+/** Frees any memory inside value; does not free value itself.
+ * \param value value
+ */
+YASM_LIB_DECL
+void yasm_value_delete(yasm_value *value);
+
+/** Set a value to be relative to the current assembly position rather than
+ * relative to the section start.
+ * \param value value
+ * \param bc bytecode containing value
+ * \param ip_rel if nonzero, indicates IP-relative data relocation,
+ * sometimes used to generate special relocations
+ * \note If value is just an absolute value, will get an absolute symrec to
+ * reference to (via bc's symbol table).
+ */
+YASM_LIB_DECL
+void yasm_value_set_curpos_rel(yasm_value *value, yasm_bytecode *bc,
+ unsigned int ip_rel);
+
+/** Perform yasm_value_finalize_expr() on a value that already exists from
+ * being initialized with yasm_value_initialize().
+ * \param value value
+ * \param precbc previous bytecode to bytecode containing value
+ * \return Nonzero if value could not be split.
+ */
+YASM_LIB_DECL
+int yasm_value_finalize(yasm_value *value, /*@null@*/ yasm_bytecode *precbc);
+
+/** Break a #yasm_expr into a #yasm_value constituent parts. Extracts
+ * the relative portion of the value, SEG and WRT portions, and top-level
+ * right shift, if any. Places the remaining expr into the absolute
+ * portion of the value. Essentially a combination of yasm_value_initialize()
+ * and yasm_value_finalize(). First expands references to symrecs in
+ * absolute sections by expanding with the absolute section start plus the
+ * symrec offset within the absolute section.
+ * \param value value to store split portions into
+ * \param e expression input
+ * \param precbc previous bytecode to bytecode containing expression
+ * \param size value size (in bits)
+ * \return Nonzero if the expr could not be split into a value for some
+ * reason (e.g. the relative portion was not added, but multiplied,
+ * etc).
+ * \warning Do not use e after this call. Even if an error is returned, e
+ * is stored into value.
+ * \note This should only be called after the parse is complete. Calling
+ * before the parse is complete will usually result in an error return.
+ */
+YASM_LIB_DECL
+int yasm_value_finalize_expr(/*@out@*/ yasm_value *value,
+ /*@null@*/ /*@kept@*/ yasm_expr *e,
+ /*@null@*/ yasm_bytecode *precbc,
+ unsigned int size);
+
+/** Get value if absolute or PC-relative section-local relative. Returns NULL
+ * otherwise.
+ * \param value value
+ * \param bc current bytecode (for PC-relative calculation); if
+ * NULL, NULL is returned for PC-relative values.
+ * \param calc_bc_dist if nonzero, calculates bytecode distances in absolute
+ * portion of value
+ * \note Adds in value.rel (correctly) if PC-relative and in the same section
+ * as bc (and there is no WRT or SEG).
+ * \return Intnum if can be resolved to integer value, otherwise NULL.
+ */
+YASM_LIB_DECL
+/*@null@*/ /*@only@*/ yasm_intnum *yasm_value_get_intnum
+ (yasm_value *value, /*@null@*/ yasm_bytecode *bc, int calc_bc_dist);
+
+/** Output value if constant or PC-relative section-local. This should be
+ * used from objfmt yasm_output_value_func() functions.
+ * functions.
+ * \param value value
+ * \param buf buffer for byte representation
+ * \param destsize destination size (in bytes)
+ * \param bc current bytecode (usually passed into higher-level
+ * calling function)
+ * \param warn enables standard warnings: zero for none;
+ * nonzero for overflow/underflow floating point and
+ * integer warnings
+ * \param arch architecture
+ * \note Adds in value.rel (correctly) if PC-relative and in the same section
+ * as bc (and there is no WRT or SEG); if this is not the desired
+ * behavior, e.g. a reloc is needed in this case, don't use this
+ * function!
+ * \return 0 if no value output due to value needing relocation;
+ * 1 if value output; -1 if error.
+ */
+YASM_LIB_DECL
+int yasm_value_output_basic
+ (yasm_value *value, /*@out@*/ unsigned char *buf, size_t destsize,
+ yasm_bytecode *bc, int warn, yasm_arch *arch);
+
+/** Print a value. For debugging purposes.
+ * \param value value
+ * \param indent_level indentation level
+ * \param f file
+ */
+YASM_LIB_DECL
+void yasm_value_print(const yasm_value *value, FILE *f, int indent_level);
+
+#endif
diff --git a/libyasm/xmalloc.c b/libyasm/xmalloc.c
new file mode 100644
index 0000000..81b608c
--- /dev/null
+++ b/libyasm/xmalloc.c
@@ -0,0 +1,114 @@
+/*
+ * Memory allocation routines with error checking. Idea from GNU libiberty.
+ *
+ * Copyright (C) 2001-2007 Peter Johnson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "util.h"
+
+#include "coretype.h"
+#include "errwarn.h"
+
+
+#ifdef WITH_DMALLOC
+#undef yasm_xmalloc
+#undef yasm_xcalloc
+#undef yasm_xrealloc
+#undef yasm_xfree
+#endif
+
+static /*@only@*/ /*@out@*/ void *def_xmalloc(size_t size);
+static /*@only@*/ void *def_xcalloc(size_t nelem, size_t elsize);
+static /*@only@*/ void *def_xrealloc
+ (/*@only@*/ /*@out@*/ /*@returned@*/ /*@null@*/ void *oldmem, size_t size)
+ /*@modifies oldmem@*/;
+static void def_xfree(/*@only@*/ /*@out@*/ /*@null@*/ void *p)
+ /*@modifies p@*/;
+
+/* storage for global function pointers */
+YASM_LIB_DECL
+/*@only@*/ /*@out@*/ void * (*yasm_xmalloc) (size_t size) = def_xmalloc;
+YASM_LIB_DECL
+/*@only@*/ void * (*yasm_xcalloc) (size_t nelem, size_t elsize) = def_xcalloc;
+YASM_LIB_DECL
+/*@only@*/ void * (*yasm_xrealloc)
+ (/*@only@*/ /*@out@*/ /*@returned@*/ /*@null@*/ void *oldmem, size_t size)
+ /*@modifies oldmem@*/ = def_xrealloc;
+YASM_LIB_DECL
+void (*yasm_xfree) (/*@only@*/ /*@out@*/ /*@null@*/ void *p)
+ /*@modifies p@*/ = def_xfree;
+
+
+static void *
+def_xmalloc(size_t size)
+{
+ void *newmem;
+
+ if (size == 0)
+ size = 1;
+ newmem = malloc(size);
+ if (!newmem)
+ yasm__fatal(N_("out of memory"));
+
+ return newmem;
+}
+
+static void *
+def_xcalloc(size_t nelem, size_t elsize)
+{
+ void *newmem;
+
+ if (nelem == 0 || elsize == 0)
+ nelem = elsize = 1;
+
+ newmem = calloc(nelem, elsize);
+ if (!newmem)
+ yasm__fatal(N_("out of memory"));
+
+ return newmem;
+}
+
+static void *
+def_xrealloc(void *oldmem, size_t size)
+{
+ void *newmem;
+
+ if (size == 0)
+ size = 1;
+ if (!oldmem)
+ newmem = malloc(size);
+ else
+ newmem = realloc(oldmem, size);
+ if (!newmem)
+ yasm__fatal(N_("out of memory"));
+
+ return newmem;
+}
+
+static void
+def_xfree(void *p)
+{
+ if (!p)
+ return;
+ free(p);
+}
diff --git a/libyasm/xstrdup.c b/libyasm/xstrdup.c
new file mode 100644
index 0000000..b187704
--- /dev/null
+++ b/libyasm/xstrdup.c
@@ -0,0 +1,68 @@
+/*
+ * strdup() implementation with error checking (using xmalloc).
+ *
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#include "util.h"
+
+#include "coretype.h"
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)strdup.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+
+
+#ifdef WITH_DMALLOC
+#undef yasm__xstrdup
+#endif
+
+char *
+yasm__xstrdup(const char *str)
+{
+ size_t len;
+ char *copy;
+
+ len = strlen(str) + 1;
+ copy = yasm_xmalloc(len);
+ memcpy(copy, str, len);
+ return (copy);
+}
+
+char *
+yasm__xstrndup(const char *str, size_t max)
+{
+ size_t len = 0;
+ char *copy;
+
+ while (len < max && str[len] != '\0')
+ len++;
+ copy = yasm_xmalloc(len+1);
+ memcpy(copy, str, len);
+ copy[len] = '\0';
+ return (copy);
+}