diff options
author | somov <somov@yandex-team.ru> | 2022-02-10 16:45:47 +0300 |
---|---|---|
committer | Daniil Cherednik <dcherednik@yandex-team.ru> | 2022-02-10 16:45:47 +0300 |
commit | a5950576e397b1909261050b8c7da16db58f10b1 (patch) | |
tree | 7ba7677f6a4c3e19e2cefab34d16df2c8963b4d4 /contrib/tools/yasm/libyasm | |
parent | 81eddc8c0b55990194e112b02d127b87d54164a9 (diff) | |
download | ydb-a5950576e397b1909261050b8c7da16db58f10b1.tar.gz |
Restoring authorship annotation for <somov@yandex-team.ru>. Commit 1 of 2.
Diffstat (limited to 'contrib/tools/yasm/libyasm')
57 files changed, 24875 insertions, 24875 deletions
diff --git a/contrib/tools/yasm/libyasm/arch.h b/contrib/tools/yasm/libyasm/arch.h index 3da9f9fca3..1e7ee0c8ba 100644 --- a/contrib/tools/yasm/libyasm/arch.h +++ b/contrib/tools/yasm/libyasm/arch.h @@ -1,495 +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 +/** + * \file libyasm/arch.h + * \brief YASM architecture interface. + * + * \license + * Copyright (C) 2002-2007 Peter Johnson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * \endlicense + */ +#ifndef YASM_ARCH_H +#define YASM_ARCH_H + +/** Errors that may be returned by yasm_arch_module::create(). */ +typedef enum yasm_arch_create_error { + YASM_ARCH_CREATE_OK = 0, /**< No error. */ + YASM_ARCH_CREATE_BAD_MACHINE, /**< Unrecognized machine name. */ + YASM_ARCH_CREATE_BAD_PARSER /**< Unrecognized parser name. */ +} yasm_arch_create_error; + +/** Return values for yasm_arch_module::parse_check_insnprefix(). */ +typedef enum yasm_arch_insnprefix { + YASM_ARCH_NOTINSNPREFIX = 0, /**< Unrecognized */ + YASM_ARCH_INSN, /**< An instruction */ + YASM_ARCH_PREFIX /**< An instruction prefix */ +} yasm_arch_insnprefix; + +/** Types of registers / target modifiers that may be returned by + * yasm_arch_module::parse_check_regtmod(). + */ +typedef enum yasm_arch_regtmod { + YASM_ARCH_NOTREGTMOD = 0, /**< Unrecognized */ + YASM_ARCH_REG, /**< A "normal" register */ + YASM_ARCH_REGGROUP, /**< A group of indexable registers */ + YASM_ARCH_SEGREG, /**< A segment register */ + YASM_ARCH_TARGETMOD /**< A target modifier (for jumps) */ +} yasm_arch_regtmod; + +#ifndef YASM_DOXYGEN +/** Base #yasm_arch structure. Must be present as the first element in any + * #yasm_arch implementation. + */ +typedef struct yasm_arch_base { + /** #yasm_arch_module implementation for this architecture. */ + const struct yasm_arch_module *module; +} yasm_arch_base; +#endif + +/** YASM machine subtype. A number of different machine types may be + * associated with a single architecture. These may be specific CPU's, but + * the ABI used to interface with the architecture should be the primary + * differentiator between machines. Some object formats (ELF) use the machine + * to determine parameters within the generated output. + */ +typedef struct yasm_arch_machine { + /** One-line description of the machine. */ + const char *name; + + /** Keyword used to select machine. */ + const char *keyword; +} yasm_arch_machine; + +/** YASM architecture module interface. + * \note All "data" in parser-related functions (yasm_arch_parse_*) needs to + * start the parse initialized to 0 to make it okay for a parser-related + * function to use/check previously stored data to see if it's been + * called before on the same piece of data. + */ +typedef struct yasm_arch_module { + /** One-line description of the architecture. + * Call yasm_arch_name() to get the name of a particular #yasm_arch. + */ + const char *name; + + /** Keyword used to select architecture. + * Call yasm_arch_keyword() to get the keyword of a particular #yasm_arch. + */ + const char *keyword; + + /** NULL-terminated list of directives. NULL if none. */ + /*@null@*/ const yasm_directive *directives; + + /** Create architecture. + * Module-level implementation of yasm_arch_create(). + * Call yasm_arch_create() instead of calling this function. + */ + /*@only@*/ yasm_arch * (*create) (const char *machine, const char *parser, + /*@out@*/ yasm_arch_create_error *error); + + /** Module-level implementation of yasm_arch_destroy(). + * Call yasm_arch_destroy() instead of calling this function. + */ + void (*destroy) (/*@only@*/ yasm_arch *arch); + + /** Module-level implementation of yasm_arch_get_machine(). + * Call yasm_arch_get_machine() instead of calling this function. + */ + const char * (*get_machine) (const yasm_arch *arch); + + /** Module-level implementation of yasm_arch_get_address_size(). + * Call yasm_arch_get_address_size() instead of calling this function. + */ + unsigned int (*get_address_size) (const yasm_arch *arch); + + /** Module-level implementation of yasm_arch_set_var(). + * Call yasm_arch_set_var() instead of calling this function. + */ + int (*set_var) (yasm_arch *arch, const char *var, unsigned long val); + + /** Module-level implementation of yasm_arch_parse_check_insnprefix(). + * Call yasm_arch_parse_check_insnprefix() instead of calling this function. + */ + yasm_arch_insnprefix (*parse_check_insnprefix) + (yasm_arch *arch, const char *id, size_t id_len, unsigned long line, + /*@out@*/ /*@only@*/ yasm_bytecode **bc, /*@out@*/ uintptr_t *prefix); + + /** Module-level implementation of yasm_arch_parse_check_regtmod(). + * Call yasm_arch_parse_check_regtmod() instead of calling this function. + */ + yasm_arch_regtmod (*parse_check_regtmod) + (yasm_arch *arch, const char *id, size_t id_len, + /*@out@*/ uintptr_t *data); + + /** Module-level implementation of yasm_arch_get_fill(). + * Call yasm_arch_get_fill() instead of calling this function. + */ + const unsigned char ** (*get_fill) (const yasm_arch *arch); + + /** Module-level implementation of yasm_arch_floatnum_tobytes(). + * Call yasm_arch_floatnum_tobytes() instead of calling this function. + */ + int (*floatnum_tobytes) (yasm_arch *arch, const yasm_floatnum *flt, + unsigned char *buf, size_t destsize, + size_t valsize, size_t shift, int warn); + + /** Module-level implementation of yasm_arch_intnum_tobytes(). + * Call yasm_arch_intnum_tobytes() instead of calling this function. + */ + int (*intnum_tobytes) (yasm_arch *arch, const yasm_intnum *intn, + unsigned char *buf, size_t destsize, size_t valsize, + int shift, const yasm_bytecode *bc, + int warn); + + /** Module-level implementation of yasm_arch_get_reg_size(). + * Call yasm_arch_get_reg_size() instead of calling this function. + */ + unsigned int (*get_reg_size) (yasm_arch *arch, uintptr_t reg); + + /** Module-level implementation of yasm_arch_reggroup_get_reg(). + * Call yasm_arch_reggroup_get_reg() instead of calling this function. + */ + uintptr_t (*reggroup_get_reg) (yasm_arch *arch, uintptr_t reggroup, + unsigned long regindex); + + /** Module-level implementation of yasm_arch_reg_print(). + * Call yasm_arch_reg_print() instead of calling this function. + */ + void (*reg_print) (yasm_arch *arch, uintptr_t reg, FILE *f); + + /** Module-level implementation of yasm_arch_segreg_print(). + * Call yasm_arch_segreg_print() instead of calling this function. + */ + void (*segreg_print) (yasm_arch *arch, uintptr_t segreg, FILE *f); + + /** Module-level implementation of yasm_arch_ea_create(). + * Call yasm_arch_ea_create() instead of calling this function. + */ + yasm_effaddr * (*ea_create) (yasm_arch *arch, /*@keep@*/ yasm_expr *e); + + /** Module-level implementation of yasm_arch_ea_destroy(). + * Call yasm_arch_ea_destroy() instead of calling this function. + */ + void (*ea_destroy) (/*@only@*/ yasm_effaddr *ea); + + /** Module-level implementation of yasm_arch_ea_print(). + * Call yasm_arch_ea_print() instead of calling this function. + */ + void (*ea_print) (const yasm_effaddr *ea, FILE *f, int indent_level); + + /** Module-level implementation of yasm_arch_create_empty_insn(). + * Call yasm_arch_create_empty_insn() instead of calling this function. + */ + /*@only@*/ yasm_bytecode * (*create_empty_insn) (yasm_arch *arch, + unsigned long line); + + /** NULL-terminated list of machines for this architecture. + * Call yasm_arch_get_machine() to get the active machine of a particular + * #yasm_arch. + */ + const yasm_arch_machine *machines; + + /** Default machine keyword. + * Call yasm_arch_get_machine() to get the active machine of a particular + * #yasm_arch. + */ + const char *default_machine_keyword; + + /** Canonical "word" size in bits. + * Call yasm_arch_wordsize() to get the word size of a particular + * #yasm_arch. + */ + unsigned int wordsize; + + /** Worst case minimum instruction length in bytes. + * Call yasm_arch_min_insn_len() to get the minimum instruction length of + * a particular #yasm_arch. + */ + unsigned int min_insn_len; +} yasm_arch_module; + +/** Get the one-line description of an architecture. + * \param arch architecture + * \return One-line description of architecture. + */ +const char *yasm_arch_name(const yasm_arch *arch); + +/** Get the keyword used to select an architecture. + * \param arch architecture + * \return Architecture keyword. + */ +const char *yasm_arch_keyword(const yasm_arch *arch); + +/** Get the word size of an architecture. + * \param arch architecture + * \return Word size (in bits). + */ +unsigned int yasm_arch_wordsize(const yasm_arch *arch); + +/** Get the minimum instruction length of an architecture. + * \param arch architecture + * \return Minimum instruction length (in bytes). + */ +unsigned int yasm_arch_min_insn_len(const yasm_arch *arch); + +/** Create architecture. + * \param module architecture module + * \param machine keyword of machine in use (must be one listed in + * #yasm_arch_module.machines) + * \param parser keyword of parser in use + * \param error error return value + * \return NULL on error (error returned in error parameter), otherwise new + * architecture. + */ +/*@only@*/ yasm_arch *yasm_arch_create(const yasm_arch_module *module, + const char *machine, const char *parser, + /*@out@*/ yasm_arch_create_error *error); + +/** Clean up, free any architecture-allocated memory. + * \param arch architecture + */ +void yasm_arch_destroy(/*@only@*/ yasm_arch *arch); + +/** Get architecture's active machine name. + * \param arch architecture + * \return Active machine name. + */ +const char *yasm_arch_get_machine(const yasm_arch *arch); + +/** Get architecture's active address size, in bits. + * \param arch architecture + * \return Active address size (in bits). + */ +unsigned int yasm_arch_get_address_size(const yasm_arch *arch); + +/** Set any arch-specific variables. For example, "mode_bits" in x86. + * \param arch architecture + * \param var variable name + * \param val value to set + * \return Zero on success, non-zero on failure (variable does not exist). + */ +int yasm_arch_set_var(yasm_arch *arch, const char *var, unsigned long val); + +/** Check an generic identifier to see if it matches architecture specific + * names for instructions or instruction prefixes. Unrecognized identifiers + * should return #YASM_ARCH_NOTINSNPREFIX so they can be treated as normal + * symbols. Any additional data beyond just the type (almost always necessary) + * should be returned into the space provided by the data parameter. + * \param arch architecture + * \param id identifier as in the input file + * \param id_len length of id string + * \param line virtual line + * \param bc for instructions, yasm_insn-based bytecode is returned + * (and NULL otherwise) + * \param prefix for prefixes, yasm_arch-specific value is returned + * (and 0 otherwise) + * \return Identifier type (#YASM_ARCH_NOTINSNPREFIX if unrecognized) + */ +yasm_arch_insnprefix yasm_arch_parse_check_insnprefix + (yasm_arch *arch, const char *id, size_t id_len, unsigned long line, + /*@out@*/ /*@only@*/ yasm_bytecode **bc, /*@out@*/ uintptr_t *prefix); + +/** Check an generic identifier to see if it matches architecture specific + * names for registers or target modifiers. Unrecognized identifiers should + * return #YASM_ARCH_NOTREGTMOD. Any additional data beyond just the type + * (almost always necessary) should be returned into the space provided by the + * data parameter. + * \param arch architecture + * \param id identifier as in the input file + * \param id_len length of id string + * \param data extra identification information (yasm_arch-specific) + * [output] + * \return Identifier type (#YASM_ARCH_NOTREGTMOD if unrecognized) + */ +yasm_arch_regtmod yasm_arch_parse_check_regtmod + (yasm_arch *arch, const char *id, size_t id_len, + /*@out@*/ uintptr_t *data); + +/** Get NOP fill patterns for 1-15 bytes of fill. + * \param arch architecture + * \return 16-entry array of arrays; [0] is unused, [1] - [15] point to arrays + * of 1-15 bytes (respectively) in length. + */ +const unsigned char **yasm_arch_get_fill(const yasm_arch *arch); + +/** Output #yasm_floatnum to buffer. Puts the value into the least + * significant bits of the destination, or may be shifted into more + * significant bits by the shift parameter. The destination bits are + * cleared before being set. + * Architecture-specific because of endianness. + * \param arch architecture + * \param flt floating point value + * \param buf buffer to write into + * \param destsize destination size (in bytes) + * \param valsize size (in bits) + * \param shift left shift (in bits) + * \param warn enables standard overflow/underflow warnings + * \return Nonzero on error. + */ +int yasm_arch_floatnum_tobytes(yasm_arch *arch, const yasm_floatnum *flt, + unsigned char *buf, size_t destsize, + size_t valsize, size_t shift, int warn); + +/** Output #yasm_intnum to buffer. Puts the value into the least + * significant bits of the destination, or may be shifted into more + * significant bits by the shift parameter. The destination bits are + * cleared before being set. + * \param arch architecture + * \param intn integer value + * \param buf buffer to write into + * \param destsize destination size (in bytes) + * \param valsize size (in bits) + * \param shift left shift (in bits); may be negative to specify right + * shift (standard warnings include truncation to boundary) + * \param bc bytecode being output ("parent" of value) + * \param warn enables standard warnings (value doesn't fit into + * valsize bits) + * \return Nonzero on error. + */ +int yasm_arch_intnum_tobytes(yasm_arch *arch, const yasm_intnum *intn, + unsigned char *buf, size_t destsize, + size_t valsize, int shift, + const yasm_bytecode *bc, int warn); + +/** Get the equivalent size of a register in bits. + * \param arch architecture + * \param reg register + * \return 0 if there is no suitable equivalent size, otherwise the size. + */ +unsigned int yasm_arch_get_reg_size(yasm_arch *arch, uintptr_t reg); + +/** Get a specific register of a register group, based on the register + * group and the index within the group. + * \param arch architecture + * \param reggroup register group + * \param regindex register index + * \return 0 if regindex is not valid for that register group, otherwise the + * specific register value. + */ +uintptr_t yasm_arch_reggroup_get_reg(yasm_arch *arch, uintptr_t reggroup, + unsigned long regindex); + +/** Print a register. For debugging purposes. + * \param arch architecture + * \param reg register + * \param f file + */ +void yasm_arch_reg_print(yasm_arch *arch, uintptr_t reg, FILE *f); + +/** Print a segment register. For debugging purposes. + * \param arch architecture + * \param segreg segment register + * \param f file + */ +void yasm_arch_segreg_print(yasm_arch *arch, uintptr_t segreg, FILE *f); + +/** Create an effective address from an expression. + * \param arch architecture + * \param e expression (kept, do not delete) + * \return Newly allocated effective address. + */ +yasm_effaddr *yasm_arch_ea_create(yasm_arch *arch, /*@keep@*/ yasm_expr *e); + +/** Delete (free allocated memory for) an effective address. + * \param arch architecture + * \param ea effective address (only pointer to it). + */ +void yasm_arch_ea_destroy(yasm_arch *arch, /*@only@*/ yasm_effaddr *ea); + +/** Print an effective address. For debugging purposes. + * \param arch architecture + * \param ea effective address + * \param f file + * \param indent_level indentation level + */ +void yasm_arch_ea_print(const yasm_arch *arch, const yasm_effaddr *ea, + FILE *f, int indent_level); + +/** Create a bytecode that represents a single empty (0 length) instruction. + * This is used for handling solitary prefixes. + * \param arch architecture + * \param line virtual line (from yasm_linemap) + * \return Newly allocated bytecode. + */ +/*@only@*/ yasm_bytecode *yasm_arch_create_empty_insn(yasm_arch *arch, + unsigned long line); + +#ifndef YASM_DOXYGEN + +/* Inline macro implementations for arch functions */ + +#define yasm_arch_name(arch) \ + (((yasm_arch_base *)arch)->module->name) +#define yasm_arch_keyword(arch) \ + (((yasm_arch_base *)arch)->module->keyword) +#define yasm_arch_wordsize(arch) \ + (((yasm_arch_base *)arch)->module->wordsize) +#define yasm_arch_min_insn_len(arch) \ + (((yasm_arch_base *)arch)->module->min_insn_len) + +#define yasm_arch_create(module, machine, parser, error) \ + module->create(machine, parser, error) + +#define yasm_arch_destroy(arch) \ + ((yasm_arch_base *)arch)->module->destroy(arch) +#define yasm_arch_get_machine(arch) \ + ((yasm_arch_base *)arch)->module->get_machine(arch) +#define yasm_arch_get_address_size(arch) \ + ((yasm_arch_base *)arch)->module->get_address_size(arch) +#define yasm_arch_set_var(arch, var, val) \ + ((yasm_arch_base *)arch)->module->set_var(arch, var, val) +#define yasm_arch_parse_check_insnprefix(arch, id, id_len, line, bc, prefix) \ + ((yasm_arch_base *)arch)->module->parse_check_insnprefix \ + (arch, id, id_len, line, bc, prefix) +#define yasm_arch_parse_check_regtmod(arch, id, id_len, data) \ + ((yasm_arch_base *)arch)->module->parse_check_regtmod \ + (arch, id, id_len, data) +#define yasm_arch_get_fill(arch) \ + ((yasm_arch_base *)arch)->module->get_fill(arch) +#define yasm_arch_floatnum_tobytes(arch, flt, buf, destsize, valsize, shift, \ + warn) \ + ((yasm_arch_base *)arch)->module->floatnum_tobytes \ + (arch, flt, buf, destsize, valsize, shift, warn) +#define yasm_arch_intnum_tobytes(arch, intn, buf, destsize, valsize, shift, \ + bc, warn) \ + ((yasm_arch_base *)arch)->module->intnum_tobytes \ + (arch, intn, buf, destsize, valsize, shift, bc, warn) +#define yasm_arch_get_reg_size(arch, reg) \ + ((yasm_arch_base *)arch)->module->get_reg_size(arch, reg) +#define yasm_arch_reggroup_get_reg(arch, regg, regi) \ + ((yasm_arch_base *)arch)->module->reggroup_get_reg(arch, regg, regi) +#define yasm_arch_reg_print(arch, reg, f) \ + ((yasm_arch_base *)arch)->module->reg_print(arch, reg, f) +#define yasm_arch_segreg_print(arch, segreg, f) \ + ((yasm_arch_base *)arch)->module->segreg_print(arch, segreg, f) +#define yasm_arch_ea_create(arch, e) \ + ((yasm_arch_base *)arch)->module->ea_create(arch, e) +#define yasm_arch_ea_destroy(arch, ea) \ + ((yasm_arch_base *)arch)->module->ea_destroy(ea) +#define yasm_arch_ea_print(arch, ea, f, i) \ + ((yasm_arch_base *)arch)->module->ea_print(ea, f, i) +#define yasm_arch_create_empty_insn(arch, line) \ + ((yasm_arch_base *)arch)->module->create_empty_insn(arch, line) + +#endif + +#endif diff --git a/contrib/tools/yasm/libyasm/assocdat.c b/contrib/tools/yasm/libyasm/assocdat.c index 560093685e..527c678fc1 100644 --- a/contrib/tools/yasm/libyasm/assocdat.c +++ b/contrib/tools/yasm/libyasm/assocdat.c @@ -1,138 +1,138 @@ -/* - * YASM associated data storage (libyasm internal use) - * - * Copyright (C) 2003-2007 Peter Johnson - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ -#include "util.h" - -#include "coretype.h" -#include "assocdat.h" - - -typedef struct assoc_data_item { - const yasm_assoc_data_callback *callback; - void *data; -} assoc_data_item; - -struct yasm__assoc_data { - assoc_data_item *vector; - size_t size; - size_t alloc; -}; - - -yasm__assoc_data * -yasm__assoc_data_create(void) -{ - yasm__assoc_data *assoc_data = yasm_xmalloc(sizeof(yasm__assoc_data)); - - assoc_data->size = 0; - assoc_data->alloc = 2; - assoc_data->vector = yasm_xmalloc(assoc_data->alloc * - sizeof(assoc_data_item)); - - return assoc_data; -} - -void * -yasm__assoc_data_get(yasm__assoc_data *assoc_data, - const yasm_assoc_data_callback *callback) -{ - size_t i; - - if (!assoc_data) - return NULL; - - for (i=0; i<assoc_data->size; i++) { - if (assoc_data->vector[i].callback == callback) - return assoc_data->vector[i].data; - } - return NULL; -} - -yasm__assoc_data * -yasm__assoc_data_add(yasm__assoc_data *assoc_data_arg, - const yasm_assoc_data_callback *callback, void *data) -{ - yasm__assoc_data *assoc_data; - assoc_data_item *item = NULL; - size_t i; - - /* Create a new assoc_data if necessary */ - if (assoc_data_arg) - assoc_data = assoc_data_arg; - else - assoc_data = yasm__assoc_data_create(); - - /* See if there's already assocated data for this callback */ - for (i=0; i<assoc_data->size; i++) { - if (assoc_data->vector[i].callback == callback) { - item = &assoc_data->vector[i]; - break; - } - } - - /* No? Then append a new one */ - if (!item) { - assoc_data->size++; - if (assoc_data->size > assoc_data->alloc) { - assoc_data->alloc *= 2; - assoc_data->vector = - yasm_xrealloc(assoc_data->vector, - assoc_data->alloc * sizeof(assoc_data_item)); - } - item = &assoc_data->vector[assoc_data->size-1]; - item->callback = callback; - item->data = NULL; - } - - /* Delete existing data (if any) */ - if (item->data && item->data != data) - item->callback->destroy(item->data); - - item->data = data; - - return assoc_data; -} - -void -yasm__assoc_data_destroy(yasm__assoc_data *assoc_data) -{ - size_t i; - - if (!assoc_data) - return; - - for (i=0; i<assoc_data->size; i++) - assoc_data->vector[i].callback->destroy(assoc_data->vector[i].data); - yasm_xfree(assoc_data->vector); - yasm_xfree(assoc_data); -} - -void -yasm__assoc_data_print(const yasm__assoc_data *assoc_data, FILE *f, - int indent_level) -{ - /*TODO*/ -} +/* + * YASM associated data storage (libyasm internal use) + * + * Copyright (C) 2003-2007 Peter Johnson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include "util.h" + +#include "coretype.h" +#include "assocdat.h" + + +typedef struct assoc_data_item { + const yasm_assoc_data_callback *callback; + void *data; +} assoc_data_item; + +struct yasm__assoc_data { + assoc_data_item *vector; + size_t size; + size_t alloc; +}; + + +yasm__assoc_data * +yasm__assoc_data_create(void) +{ + yasm__assoc_data *assoc_data = yasm_xmalloc(sizeof(yasm__assoc_data)); + + assoc_data->size = 0; + assoc_data->alloc = 2; + assoc_data->vector = yasm_xmalloc(assoc_data->alloc * + sizeof(assoc_data_item)); + + return assoc_data; +} + +void * +yasm__assoc_data_get(yasm__assoc_data *assoc_data, + const yasm_assoc_data_callback *callback) +{ + size_t i; + + if (!assoc_data) + return NULL; + + for (i=0; i<assoc_data->size; i++) { + if (assoc_data->vector[i].callback == callback) + return assoc_data->vector[i].data; + } + return NULL; +} + +yasm__assoc_data * +yasm__assoc_data_add(yasm__assoc_data *assoc_data_arg, + const yasm_assoc_data_callback *callback, void *data) +{ + yasm__assoc_data *assoc_data; + assoc_data_item *item = NULL; + size_t i; + + /* Create a new assoc_data if necessary */ + if (assoc_data_arg) + assoc_data = assoc_data_arg; + else + assoc_data = yasm__assoc_data_create(); + + /* See if there's already assocated data for this callback */ + for (i=0; i<assoc_data->size; i++) { + if (assoc_data->vector[i].callback == callback) { + item = &assoc_data->vector[i]; + break; + } + } + + /* No? Then append a new one */ + if (!item) { + assoc_data->size++; + if (assoc_data->size > assoc_data->alloc) { + assoc_data->alloc *= 2; + assoc_data->vector = + yasm_xrealloc(assoc_data->vector, + assoc_data->alloc * sizeof(assoc_data_item)); + } + item = &assoc_data->vector[assoc_data->size-1]; + item->callback = callback; + item->data = NULL; + } + + /* Delete existing data (if any) */ + if (item->data && item->data != data) + item->callback->destroy(item->data); + + item->data = data; + + return assoc_data; +} + +void +yasm__assoc_data_destroy(yasm__assoc_data *assoc_data) +{ + size_t i; + + if (!assoc_data) + return; + + for (i=0; i<assoc_data->size; i++) + assoc_data->vector[i].callback->destroy(assoc_data->vector[i].data); + yasm_xfree(assoc_data->vector); + yasm_xfree(assoc_data); +} + +void +yasm__assoc_data_print(const yasm__assoc_data *assoc_data, FILE *f, + int indent_level) +{ + /*TODO*/ +} diff --git a/contrib/tools/yasm/libyasm/assocdat.h b/contrib/tools/yasm/libyasm/assocdat.h index cf42386775..79876335d2 100644 --- a/contrib/tools/yasm/libyasm/assocdat.h +++ b/contrib/tools/yasm/libyasm/assocdat.h @@ -1,76 +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 +/** + * \file assocdat.h + * \brief YASM associated data storage (libyasm internal use) + * + * \license + * Copyright (C) 2003-2007 Peter Johnson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * \endlicense + */ +#ifndef YASM_ASSOCDAT_H +#define YASM_ASSOCDAT_H + +#ifndef YASM_LIB_DECL +#define YASM_LIB_DECL +#endif + +/** Associated data container. */ +typedef struct yasm__assoc_data yasm__assoc_data; + +/** Create an associated data container. */ +YASM_LIB_DECL +/*@only@*/ yasm__assoc_data *yasm__assoc_data_create(void); + +/** Get associated data for a data callback. + * \param assoc_data container of associated data + * \param callback callback used when adding data + * \return Associated data (NULL if none). + */ +YASM_LIB_DECL +/*@dependent@*/ /*@null@*/ void *yasm__assoc_data_get + (/*@null@*/ yasm__assoc_data *assoc_data, + const yasm_assoc_data_callback *callback); + +/** Add associated data to a associated data container. + * \attention Deletes any existing associated data for that data callback. + * \param assoc_data container of associated data + * \param callback callback + * \param data data to associate + */ +YASM_LIB_DECL +/*@only@*/ yasm__assoc_data *yasm__assoc_data_add + (/*@null@*/ /*@only@*/ yasm__assoc_data *assoc_data, + const yasm_assoc_data_callback *callback, + /*@only@*/ /*@null@*/ void *data); + +/** Destroy all associated data in a container. */ +YASM_LIB_DECL +void yasm__assoc_data_destroy + (/*@null@*/ /*@only@*/ yasm__assoc_data *assoc_data); + +/** Print all associated data in a container. */ +YASM_LIB_DECL +void yasm__assoc_data_print(const yasm__assoc_data *assoc_data, FILE *f, + int indent_level); + +#endif diff --git a/contrib/tools/yasm/libyasm/bc-align.c b/contrib/tools/yasm/libyasm/bc-align.c index 2a47882ef0..42a9cc4671 100644 --- a/contrib/tools/yasm/libyasm/bc-align.c +++ b/contrib/tools/yasm/libyasm/bc-align.c @@ -1,245 +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); -} +/* + * Align bytecode + * + * Copyright (C) 2005-2007 Peter Johnson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include "util.h" + +#include "libyasm-stdint.h" +#include "coretype.h" + +#include "errwarn.h" +#include "intnum.h" +#include "expr.h" + +#include "bytecode.h" + + +typedef struct bytecode_align { + /*@only@*/ yasm_expr *boundary; /* alignment boundary */ + + /* What to fill intervening locations with, NULL if using code_fill */ + /*@only@*/ /*@null@*/ yasm_expr *fill; + + /* Maximum number of bytes to skip, NULL if no maximum. */ + /*@only@*/ /*@null@*/ yasm_expr *maxskip; + + /* Code fill, NULL if using 0 fill */ + /*@null@*/ const unsigned char **code_fill; +} bytecode_align; + +static void bc_align_destroy(void *contents); +static void bc_align_print(const void *contents, FILE *f, int indent_level); +static void bc_align_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc); +static int bc_align_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span, + void *add_span_data); +static int bc_align_expand(yasm_bytecode *bc, int span, long old_val, + long new_val, /*@out@*/ long *neg_thres, + /*@out@*/ long *pos_thres); +static int bc_align_tobytes(yasm_bytecode *bc, unsigned char **bufp, + unsigned char *bufstart, void *d, + yasm_output_value_func output_value, + /*@null@*/ yasm_output_reloc_func output_reloc); + +static const yasm_bytecode_callback bc_align_callback = { + bc_align_destroy, + bc_align_print, + bc_align_finalize, + NULL, + bc_align_calc_len, + bc_align_expand, + bc_align_tobytes, + YASM_BC_SPECIAL_OFFSET +}; + + +static void +bc_align_destroy(void *contents) +{ + bytecode_align *align = (bytecode_align *)contents; + if (align->boundary) + yasm_expr_destroy(align->boundary); + if (align->fill) + yasm_expr_destroy(align->fill); + if (align->maxskip) + yasm_expr_destroy(align->maxskip); + yasm_xfree(contents); +} + +static void +bc_align_print(const void *contents, FILE *f, int indent_level) +{ + const bytecode_align *align = (const bytecode_align *)contents; + fprintf(f, "%*s_Align_\n", indent_level, ""); + fprintf(f, "%*sBoundary=", indent_level, ""); + yasm_expr_print(align->boundary, f); + fprintf(f, "\n%*sFill=", indent_level, ""); + yasm_expr_print(align->fill, f); + fprintf(f, "\n%*sMax Skip=", indent_level, ""); + yasm_expr_print(align->maxskip, f); + fprintf(f, "\n"); +} + +static void +bc_align_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc) +{ + bytecode_align *align = (bytecode_align *)bc->contents; + if (!yasm_expr_get_intnum(&align->boundary, 0)) + yasm_error_set(YASM_ERROR_NOT_CONSTANT, + N_("align boundary must be a constant")); + if (align->fill && !yasm_expr_get_intnum(&align->fill, 0)) + yasm_error_set(YASM_ERROR_NOT_CONSTANT, + N_("align fill must be a constant")); + if (align->maxskip && !yasm_expr_get_intnum(&align->maxskip, 0)) + yasm_error_set(YASM_ERROR_NOT_CONSTANT, + N_("align maximum skip must be a constant")); +} + +static int +bc_align_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span, + void *add_span_data) +{ + long neg_thres = 0; + long pos_thres = 0; + + if (bc_align_expand(bc, 0, 0, (long)bc->offset, &neg_thres, + &pos_thres) < 0) + return -1; + + return 0; +} + +static int +bc_align_expand(yasm_bytecode *bc, int span, long old_val, long new_val, + /*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres) +{ + bytecode_align *align = (bytecode_align *)bc->contents; + unsigned long end; + unsigned long boundary = + yasm_intnum_get_uint(yasm_expr_get_intnum(&align->boundary, 0)); + + if (boundary == 0) { + bc->len = 0; + *pos_thres = new_val; + return 0; + } + + end = (unsigned long)new_val; + if ((unsigned long)new_val & (boundary-1)) + end = ((unsigned long)new_val & ~(boundary-1)) + boundary; + + *pos_thres = (long)end; + bc->len = end - (unsigned long)new_val; + + if (align->maxskip) { + unsigned long maxskip = + yasm_intnum_get_uint(yasm_expr_get_intnum(&align->maxskip, 0)); + if (bc->len > maxskip) { + *pos_thres = (long)end-maxskip-1; + bc->len = 0; + } + } + return 1; +} + +static int +bc_align_tobytes(yasm_bytecode *bc, unsigned char **bufp, + unsigned char *bufstart, void *d, + yasm_output_value_func output_value, + /*@unused@*/ yasm_output_reloc_func output_reloc) +{ + bytecode_align *align = (bytecode_align *)bc->contents; + unsigned long len; + unsigned long boundary = + yasm_intnum_get_uint(yasm_expr_get_intnum(&align->boundary, 0)); + + if (boundary == 0) + return 0; + else { + unsigned long end = bc->offset; + if (bc->offset & (boundary-1)) + end = (bc->offset & ~(boundary-1)) + boundary; + len = end - bc->offset; + if (len == 0) + return 0; + if (align->maxskip) { + unsigned long maxskip = + yasm_intnum_get_uint(yasm_expr_get_intnum(&align->maxskip, 0)); + if (len > maxskip) + return 0; + } + } + + if (align->fill) { + unsigned long v; + v = yasm_intnum_get_uint(yasm_expr_get_intnum(&align->fill, 0)); + memset(*bufp, (int)v, len); + *bufp += len; + } else if (align->code_fill) { + unsigned long maxlen = 15; + while (!align->code_fill[maxlen] && maxlen>0) + maxlen--; + if (maxlen == 0) { + yasm_error_set(YASM_ERROR_GENERAL, + N_("could not find any code alignment size")); + return 1; + } + + /* Fill with maximum code fill as much as possible */ + while (len > maxlen) { + memcpy(*bufp, align->code_fill[maxlen], maxlen); + *bufp += maxlen; + len -= maxlen; + } + + if (!align->code_fill[len]) { + yasm_error_set(YASM_ERROR_VALUE, + N_("invalid alignment size %d"), len); + return 1; + } + /* Handle rest of code fill */ + memcpy(*bufp, align->code_fill[len], len); + *bufp += len; + } else { + /* Just fill with 0 */ + memset(*bufp, 0, len); + *bufp += len; + } + return 0; +} + +yasm_bytecode * +yasm_bc_create_align(yasm_expr *boundary, yasm_expr *fill, + yasm_expr *maxskip, const unsigned char **code_fill, + unsigned long line) +{ + bytecode_align *align = yasm_xmalloc(sizeof(bytecode_align)); + + align->boundary = boundary; + align->fill = fill; + align->maxskip = maxskip; + align->code_fill = code_fill; + + return yasm_bc_create_common(&bc_align_callback, align, line); +} diff --git a/contrib/tools/yasm/libyasm/bc-data.c b/contrib/tools/yasm/libyasm/bc-data.c index ebbdd6f97d..7c115a8b50 100644 --- a/contrib/tools/yasm/libyasm/bc-data.c +++ b/contrib/tools/yasm/libyasm/bc-data.c @@ -1,600 +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; - } - } -} +/* + * Data (and LEB128) bytecode + * + * Copyright (C) 2001-2007 Peter Johnson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include "util.h" + +#include "libyasm-stdint.h" +#include "coretype.h" + +#include "errwarn.h" +#include "intnum.h" +#include "expr.h" +#include "value.h" + +#include "bytecode.h" +#include "arch.h" + + +struct yasm_dataval { + /*@reldef@*/ STAILQ_ENTRY(yasm_dataval) link; + + enum { DV_EMPTY, DV_VALUE, DV_RAW, DV_ULEB128, DV_SLEB128, DV_RESERVE } + type; + + union { + yasm_value val; + struct { + /*@only@*/ unsigned char *contents; + unsigned long len; + } raw; + } data; + + /* number of times data is repeated, NULL=1. */ + /*@only@*/ /*@null@*/ yasm_expr *multiple; +}; + +typedef struct bytecode_data { + /* converted data (linked list) */ + yasm_datavalhead datahead; + + int item_size; +} bytecode_data; + +static void bc_data_destroy(void *contents); +static void bc_data_print(const void *contents, FILE *f, int indent_level); +static void bc_data_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc); +static int bc_data_item_size(yasm_bytecode *bc); +static int bc_data_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span, + void *add_span_data); +static int bc_data_tobytes(yasm_bytecode *bc, unsigned char **bufp, + unsigned char *bufstart, void *d, + yasm_output_value_func output_value, + /*@null@*/ yasm_output_reloc_func output_reloc); + +static const yasm_bytecode_callback bc_data_callback = { + bc_data_destroy, + bc_data_print, + bc_data_finalize, + bc_data_item_size, + bc_data_calc_len, + yasm_bc_expand_common, + bc_data_tobytes, + 0 +}; + + +static void +bc_data_destroy(void *contents) +{ + bytecode_data *bc_data = (bytecode_data *)contents; + yasm_dvs_delete(&bc_data->datahead); + yasm_xfree(contents); +} + +static void +bc_data_print(const void *contents, FILE *f, int indent_level) +{ + const bytecode_data *bc_data = (const bytecode_data *)contents; + fprintf(f, "%*s_Data_\n", indent_level, ""); + fprintf(f, "%*sElements:\n", indent_level+1, ""); + yasm_dvs_print(&bc_data->datahead, f, indent_level+2); +} + +static void +bc_data_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc) +{ + bytecode_data *bc_data = (bytecode_data *)bc->contents; + yasm_dataval *dv; + yasm_intnum *intn; + + /* Convert values from simple expr to value. */ + STAILQ_FOREACH(dv, &bc_data->datahead, link) { + switch (dv->type) { + case DV_VALUE: + if (yasm_value_finalize(&dv->data.val, prev_bc)) { + yasm_error_set(YASM_ERROR_TOO_COMPLEX, + N_("data expression too complex")); + return; + } + break; + case DV_ULEB128: + case DV_SLEB128: + intn = yasm_expr_get_intnum(&dv->data.val.abs, 0); + if (!intn) { + yasm_error_set(YASM_ERROR_NOT_CONSTANT, + N_("LEB128 requires constant values")); + return; + } + /* Warn for negative values in unsigned environment. + * This could be an error instead: the likelihood this is + * desired is very low! + */ + if (yasm_intnum_sign(intn) == -1 && dv->type == DV_ULEB128) + yasm_warn_set(YASM_WARN_GENERAL, + N_("negative value in unsigned LEB128")); + break; + default: + break; + } + if (dv->multiple) { + yasm_value val; + if (yasm_value_finalize_expr(&val, dv->multiple, prev_bc, 0)) + yasm_error_set(YASM_ERROR_TOO_COMPLEX, + N_("multiple expression too complex")); + else if (val.rel) + yasm_error_set(YASM_ERROR_NOT_ABSOLUTE, + N_("multiple expression not absolute")); + dv->multiple = val.abs; + } + } +} + +static int +bc_data_item_size(yasm_bytecode *bc) +{ + bytecode_data *bc_data = (bytecode_data *)bc->contents; + return bc_data->item_size; +} + +static int +bc_data_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span, + void *add_span_data) +{ + bytecode_data *bc_data = (bytecode_data *)bc->contents; + yasm_dataval *dv; + yasm_intnum *intn; + unsigned long len = 0; + unsigned long multiple; + + /* Count up element sizes, rounding up string length. */ + STAILQ_FOREACH(dv, &bc_data->datahead, link) { + switch (dv->type) { + case DV_EMPTY: + len = 0; + break; + case DV_VALUE: + len = dv->data.val.size/8; + break; + case DV_RAW: + len = dv->data.raw.len; + break; + case DV_ULEB128: + case DV_SLEB128: + intn = yasm_expr_get_intnum(&dv->data.val.abs, 0); + if (!intn) + yasm_internal_error(N_("non-constant in data_tobytes")); + len = yasm_intnum_size_leb128(intn, dv->type == DV_SLEB128); + break; + case DV_RESERVE: + len = dv->data.val.size/8; + break; + } + + if (!yasm_dv_get_multiple(dv, &multiple)) + len *= multiple; + + bc->len += len; + } + + return 0; +} + +static int +bc_data_tobytes(yasm_bytecode *bc, unsigned char **bufp, + unsigned char *bufstart, void *d, + yasm_output_value_func output_value, + /*@unused@*/ yasm_output_reloc_func output_reloc) +{ + bytecode_data *bc_data = (bytecode_data *)bc->contents; + yasm_dataval *dv; + yasm_intnum *intn; + unsigned int val_len; + unsigned long multiple, i; + + STAILQ_FOREACH(dv, &bc_data->datahead, link) { + if (yasm_dv_get_multiple(dv, &multiple) || multiple == 0) + continue; + switch (dv->type) { + case DV_EMPTY: + break; + case DV_VALUE: + val_len = dv->data.val.size/8; + for (i=0; i<multiple; i++) { + if (output_value(&dv->data.val, *bufp, val_len, + (unsigned long)(*bufp-bufstart), bc, 1, + d)) + return 1; + *bufp += val_len; + } + break; + case DV_RAW: + for (i=0; i<multiple; i++) { + memcpy(*bufp, dv->data.raw.contents, dv->data.raw.len); + *bufp += dv->data.raw.len; + } + break; + case DV_ULEB128: + case DV_SLEB128: + intn = yasm_expr_get_intnum(&dv->data.val.abs, 234); + if (!intn) + yasm_internal_error(N_("non-constant in data_tobytes")); + for (i=0; i<multiple; i++) { + *bufp += + yasm_intnum_get_leb128(intn, *bufp, + dv->type == DV_SLEB128); + } + case DV_RESERVE: + val_len = dv->data.val.size/8; + for (i=0; i<multiple; i++) { + memset(*bufp, 0, val_len); + *bufp += val_len; + } + break; + } + } + + return 0; +} + +yasm_bytecode * +yasm_bc_create_data(yasm_datavalhead *datahead, unsigned int size, + int append_zero, yasm_arch *arch, unsigned long line) +{ + bytecode_data *data = yasm_xmalloc(sizeof(bytecode_data)); + yasm_bytecode *bc = yasm_bc_create_common(&bc_data_callback, data, line); + yasm_dataval *dv, *dv2, *dvo; + yasm_intnum *intn; + unsigned long len = 0, rlen, i; + + + yasm_dvs_initialize(&data->datahead); + data->item_size = size; + + /* Prescan input data for length, etc. Careful: this needs to be + * precisely paired with the second loop. + */ + STAILQ_FOREACH(dv, datahead, link) { + if (dv->multiple && dv->type != DV_EMPTY && len > 0) { + /* Flush previous data */ + dvo = yasm_dv_create_raw(yasm_xmalloc(len), len); + STAILQ_INSERT_TAIL(&data->datahead, dvo, link); + len = 0; + } + switch (dv->type) { + case DV_EMPTY: + break; + case DV_VALUE: + case DV_ULEB128: + case DV_SLEB128: + intn = yasm_expr_get_intnum(&dv->data.val.abs, 0); + if (intn && dv->type == DV_VALUE && (arch || size == 1)) + len += size; + else if (intn && dv->type == DV_ULEB128) + len += yasm_intnum_size_leb128(intn, 0); + else if (intn && dv->type == DV_SLEB128) + len += yasm_intnum_size_leb128(intn, 1); + else { + if (len > 0) { + /* Create bytecode for all previous len */ + dvo = yasm_dv_create_raw(yasm_xmalloc(len), len); + STAILQ_INSERT_TAIL(&data->datahead, dvo, link); + len = 0; + } + + /* Create bytecode for this value */ + dvo = yasm_xmalloc(sizeof(yasm_dataval)); + STAILQ_INSERT_TAIL(&data->datahead, dvo, link); + dvo->multiple = dv->multiple; + } + break; + case DV_RAW: + rlen = dv->data.raw.len; + /* find count, rounding up to nearest multiple of size */ + rlen = (rlen + size - 1) / size; + len += rlen*size; + break; + case DV_RESERVE: + len += size; + break; + } + + if (dv->multiple && dv->type != DV_EMPTY && len > 0) { + /* Flush this data */ + dvo = yasm_dv_create_raw(yasm_xmalloc(len), len); + STAILQ_INSERT_TAIL(&data->datahead, dvo, link); + dvo->multiple = dv->multiple; + len = 0; + } + + if (append_zero) + len++; + } + + /* Create final dataval for any trailing length */ + if (len > 0) { + dvo = yasm_dv_create_raw(yasm_xmalloc(len), len); + STAILQ_INSERT_TAIL(&data->datahead, dvo, link); + } + + /* Second iteration: copy data and delete input datavals. */ + dv = STAILQ_FIRST(datahead); + dvo = STAILQ_FIRST(&data->datahead); + len = 0; + while (dv && dvo) { + if (dv->multiple && dv->type != DV_EMPTY && len > 0) { + dvo = STAILQ_NEXT(dvo, link); + len = 0; + } + switch (dv->type) { + case DV_EMPTY: + break; + case DV_VALUE: + case DV_ULEB128: + case DV_SLEB128: + intn = yasm_expr_get_intnum(&dv->data.val.abs, 0); + if (intn && dv->type == DV_VALUE && (arch || size == 1)) { + if (size == 1) + yasm_intnum_get_sized(intn, + &dvo->data.raw.contents[len], + 1, 8, 0, 0, 1); + else + yasm_arch_intnum_tobytes(arch, intn, + &dvo->data.raw.contents[len], + size, size*8, 0, bc, 1); + yasm_value_delete(&dv->data.val); + len += size; + } else if (intn && dv->type == DV_ULEB128) { + len += yasm_intnum_get_leb128(intn, + &dvo->data.raw.contents[len], + 0); + yasm_value_delete(&dv->data.val); + } else if (intn && dv->type == DV_SLEB128) { + len += yasm_intnum_get_leb128(intn, + &dvo->data.raw.contents[len], + 1); + yasm_value_delete(&dv->data.val); + } else { + if (len > 0) + dvo = STAILQ_NEXT(dvo, link); + dvo->type = dv->type; + dvo->data.val = dv->data.val; /* structure copy */ + dvo->data.val.size = size*8; /* remember size */ + dvo = STAILQ_NEXT(dvo, link); + len = 0; + } + break; + case DV_RAW: + rlen = dv->data.raw.len; + memcpy(&dvo->data.raw.contents[len], dv->data.raw.contents, + rlen); + yasm_xfree(dv->data.raw.contents); + len += rlen; + /* pad with 0's to nearest multiple of size */ + rlen %= size; + if (rlen > 0) { + rlen = size-rlen; + for (i=0; i<rlen; i++) + dvo->data.raw.contents[len++] = 0; + } + break; + case DV_RESERVE: + memset(&dvo->data.raw.contents[len], 0, size); + len += size; + break; + } + + if (dv->multiple && dv->type != DV_EMPTY && len > 0) { + dvo = STAILQ_NEXT(dvo, link); + len = 0; + } + + if (append_zero) + dvo->data.raw.contents[len++] = 0; + dv2 = STAILQ_NEXT(dv, link); + yasm_xfree(dv); + dv = dv2; + } + + return bc; +} + +yasm_bytecode * +yasm_bc_create_leb128(yasm_datavalhead *datahead, int sign, unsigned long line) +{ + yasm_dataval *dv; + + /* Convert all values into LEB type, error on strings/raws */ + STAILQ_FOREACH(dv, datahead, link) { + switch (dv->type) { + case DV_VALUE: + dv->type = sign ? DV_SLEB128 : DV_ULEB128; + break; + case DV_RAW: + yasm_error_set(YASM_ERROR_VALUE, + N_("LEB128 does not allow string constants")); + break; + default: + break; + } + } + + return yasm_bc_create_data(datahead, 0, 0, 0, line); +} + +yasm_dataval * +yasm_dv_create_expr(yasm_expr *e) +{ + yasm_dataval *retval = yasm_xmalloc(sizeof(yasm_dataval)); + + retval->type = DV_VALUE; + yasm_value_initialize(&retval->data.val, e, 0); + retval->multiple = NULL; + + return retval; +} + +yasm_dataval * +yasm_dv_create_raw(unsigned char *contents, unsigned long len) +{ + yasm_dataval *retval = yasm_xmalloc(sizeof(yasm_dataval)); + + retval->type = DV_RAW; + retval->data.raw.contents = contents; + retval->data.raw.len = len; + retval->multiple = NULL; + + return retval; +} + +yasm_dataval * +yasm_dv_create_reserve(void) +{ + yasm_dataval *retval = yasm_xmalloc(sizeof(yasm_dataval)); + + retval->type = DV_RESERVE; + retval->multiple = NULL; + + return retval; +} + +yasm_value * +yasm_dv_get_value(yasm_dataval *dv) +{ + if (dv->type != DV_VALUE) + return NULL; + return &dv->data.val; +} + +void +yasm_dv_set_multiple(yasm_dataval *dv, yasm_expr *e) +{ + if (dv->multiple) + dv->multiple = yasm_expr_create_tree( dv->multiple, YASM_EXPR_MUL, e, + e->line); + else + dv->multiple = e; +} + +int +yasm_dv_get_multiple(yasm_dataval *dv, unsigned long *multiple) +{ + /*@dependent@*/ /*@null@*/ const yasm_intnum *num; + + *multiple = 1; + if (dv->multiple) { + num = yasm_expr_get_intnum(&dv->multiple, 0); + if (!num) { + yasm_error_set(YASM_ERROR_VALUE, + N_("could not determine multiple")); + return 1; + } + if (yasm_intnum_sign(num) < 0) { + yasm_error_set(YASM_ERROR_VALUE, N_("multiple is negative")); + return 1; + } + *multiple = yasm_intnum_get_uint(num); + } + return 0; +} + +void +yasm_dvs_delete(yasm_datavalhead *headp) +{ + yasm_dataval *cur, *next; + + cur = STAILQ_FIRST(headp); + while (cur) { + next = STAILQ_NEXT(cur, link); + switch (cur->type) { + case DV_VALUE: + yasm_value_delete(&cur->data.val); + break; + case DV_RAW: + yasm_xfree(cur->data.raw.contents); + break; + default: + break; + } + if (cur->multiple) + yasm_expr_destroy(cur->multiple); + yasm_xfree(cur); + cur = next; + } + STAILQ_INIT(headp); +} + +yasm_dataval * +yasm_dvs_append(yasm_datavalhead *headp, yasm_dataval *dv) +{ + if (dv) { + STAILQ_INSERT_TAIL(headp, dv, link); + return dv; + } + return (yasm_dataval *)NULL; +} + +void +yasm_dvs_print(const yasm_datavalhead *head, FILE *f, int indent_level) +{ + yasm_dataval *cur; + unsigned long i; + + STAILQ_FOREACH(cur, head, link) { + fprintf(f, "%*sMultiple=", indent_level, ""); + if (!cur->multiple) + fprintf(f, "nil (1)"); + else + yasm_expr_print(cur->multiple, f); + switch (cur->type) { + case DV_EMPTY: + fprintf(f, "%*sEmpty\n", indent_level, ""); + break; + case DV_VALUE: + fprintf(f, "%*sValue:\n", indent_level, ""); + yasm_value_print(&cur->data.val, f, indent_level+1); + break; + case DV_RAW: + fprintf(f, "%*sLength=%lu\n", indent_level, "", + cur->data.raw.len); + fprintf(f, "%*sBytes=[", indent_level, ""); + for (i=0; i<cur->data.raw.len; i++) + fprintf(f, "0x%02x, ", cur->data.raw.contents[i]); + fprintf(f, "]\n"); + break; + case DV_ULEB128: + fprintf(f, "%*sULEB128 value:\n", indent_level, ""); + yasm_value_print(&cur->data.val, f, indent_level+1); + break; + case DV_SLEB128: + fprintf(f, "%*sSLEB128 value:\n", indent_level, ""); + yasm_value_print(&cur->data.val, f, indent_level+1); + break; + case DV_RESERVE: + fprintf(f, "%*sReserved\n", indent_level, ""); + break; + } + } +} diff --git a/contrib/tools/yasm/libyasm/bc-incbin.c b/contrib/tools/yasm/libyasm/bc-incbin.c index a8fec7d6ce..efa098dad7 100644 --- a/contrib/tools/yasm/libyasm/bc-incbin.c +++ b/contrib/tools/yasm/libyasm/bc-incbin.c @@ -1,265 +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); -} +/* + * Incbin bytecode + * + * Copyright (C) 2001-2007 Peter Johnson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include "util.h" + +#include "libyasm-stdint.h" +#include "coretype.h" + +#include "linemap.h" + +#include "errwarn.h" +#include "intnum.h" +#include "expr.h" +#include "value.h" + +#include "bytecode.h" + +#include "file.h" + + +typedef struct bytecode_incbin { + /*@only@*/ char *filename; /* file to include data from */ + const char *from; /* filename of what contained incbin */ + + /* starting offset to read from (NULL=0) */ + /*@only@*/ /*@null@*/ yasm_expr *start; + + /* maximum number of bytes to read (NULL=no limit) */ + /*@only@*/ /*@null@*/ yasm_expr *maxlen; +} bytecode_incbin; + +static void bc_incbin_destroy(void *contents); +static void bc_incbin_print(const void *contents, FILE *f, int indent_level); +static void bc_incbin_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc); +static int bc_incbin_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span, + void *add_span_data); +static int bc_incbin_tobytes(yasm_bytecode *bc, unsigned char **bufp, + unsigned char *bufstart, void *d, + yasm_output_value_func output_value, + /*@null@*/ yasm_output_reloc_func output_reloc); + +static const yasm_bytecode_callback bc_incbin_callback = { + bc_incbin_destroy, + bc_incbin_print, + bc_incbin_finalize, + NULL, + bc_incbin_calc_len, + yasm_bc_expand_common, + bc_incbin_tobytes, + 0 +}; + + +static void +bc_incbin_destroy(void *contents) +{ + bytecode_incbin *incbin = (bytecode_incbin *)contents; + yasm_xfree(incbin->filename); + yasm_expr_destroy(incbin->start); + yasm_expr_destroy(incbin->maxlen); + yasm_xfree(contents); +} + +static void +bc_incbin_print(const void *contents, FILE *f, int indent_level) +{ + const bytecode_incbin *incbin = (const bytecode_incbin *)contents; + fprintf(f, "%*s_IncBin_\n", indent_level, ""); + fprintf(f, "%*sFilename=`%s'\n", indent_level, "", + incbin->filename); + fprintf(f, "%*sStart=", indent_level, ""); + if (!incbin->start) + fprintf(f, "nil (0)"); + else + yasm_expr_print(incbin->start, f); + fprintf(f, "%*sMax Len=", indent_level, ""); + if (!incbin->maxlen) + fprintf(f, "nil (unlimited)"); + else + yasm_expr_print(incbin->maxlen, f); + fprintf(f, "\n"); +} + +static void +bc_incbin_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc) +{ + bytecode_incbin *incbin = (bytecode_incbin *)bc->contents; + yasm_value val; + + if (yasm_value_finalize_expr(&val, incbin->start, prev_bc, 0)) + yasm_error_set(YASM_ERROR_TOO_COMPLEX, + N_("start expression too complex")); + else if (val.rel) + yasm_error_set(YASM_ERROR_NOT_ABSOLUTE, + N_("start expression not absolute")); + incbin->start = val.abs; + + if (yasm_value_finalize_expr(&val, incbin->maxlen, prev_bc, 0)) + yasm_error_set(YASM_ERROR_TOO_COMPLEX, + N_("maximum length expression too complex")); + else if (val.rel) + yasm_error_set(YASM_ERROR_NOT_ABSOLUTE, + N_("maximum length expression not absolute")); + incbin->maxlen = val.abs; +} + +static int +bc_incbin_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span, + void *add_span_data) +{ + bytecode_incbin *incbin = (bytecode_incbin *)bc->contents; + FILE *f; + /*@dependent@*/ /*@null@*/ const yasm_intnum *num; + unsigned long start = 0, maxlen = 0xFFFFFFFFUL, flen; + + /* Try to convert start to integer value */ + if (incbin->start) { + num = yasm_expr_get_intnum(&incbin->start, 0); + if (num) + start = yasm_intnum_get_uint(num); + if (!num) { + /* FIXME */ + yasm_error_set(YASM_ERROR_NOT_IMPLEMENTED, + N_("incbin does not yet understand non-constant")); + return -1; + } + } + + /* Try to convert maxlen to integer value */ + if (incbin->maxlen) { + num = yasm_expr_get_intnum(&incbin->maxlen, 0); + if (num) + maxlen = yasm_intnum_get_uint(num); + if (!num) { + /* FIXME */ + yasm_error_set(YASM_ERROR_NOT_IMPLEMENTED, + N_("incbin does not yet understand non-constant")); + return -1; + } + } + + /* Open file and determine its length */ + f = yasm_fopen_include(incbin->filename, incbin->from, "rb", NULL); + if (!f) { + yasm_error_set(YASM_ERROR_IO, + N_("`incbin': unable to open file `%s'"), + incbin->filename); + return -1; + } + if (fseek(f, 0L, SEEK_END) < 0) { + yasm_error_set(YASM_ERROR_IO, + N_("`incbin': unable to seek on file `%s'"), + incbin->filename); + return -1; + } + flen = (unsigned long)ftell(f); + fclose(f); + + /* Compute length of incbin from start, maxlen, and len */ + if (start > flen) { + yasm_warn_set(YASM_WARN_GENERAL, + N_("`incbin': start past end of file `%s'"), + incbin->filename); + start = flen; + } + flen -= start; + if (incbin->maxlen) + if (maxlen < flen) + flen = maxlen; + bc->len += flen; + return 0; +} + +static int +bc_incbin_tobytes(yasm_bytecode *bc, unsigned char **bufp, + unsigned char *bufstart, void *d, + yasm_output_value_func output_value, + /*@unused@*/ yasm_output_reloc_func output_reloc) +{ + bytecode_incbin *incbin = (bytecode_incbin *)bc->contents; + FILE *f; + /*@dependent@*/ /*@null@*/ const yasm_intnum *num; + unsigned long start = 0; + + /* Convert start to integer value */ + if (incbin->start) { + num = yasm_expr_get_intnum(&incbin->start, 0); + if (!num) + yasm_internal_error( + N_("could not determine start in bc_tobytes_incbin")); + start = yasm_intnum_get_uint(num); + } + + /* Open file */ + f = yasm_fopen_include(incbin->filename, incbin->from, "rb", NULL); + if (!f) { + yasm_error_set(YASM_ERROR_IO, N_("`incbin': unable to open file `%s'"), + incbin->filename); + return 1; + } + + /* Seek to start of data */ + if (fseek(f, (long)start, SEEK_SET) < 0) { + yasm_error_set(YASM_ERROR_IO, + N_("`incbin': unable to seek on file `%s'"), + incbin->filename); + fclose(f); + return 1; + } + + /* Read len bytes */ + if (fread(*bufp, 1, (size_t)bc->len, f) < (size_t)bc->len) { + yasm_error_set(YASM_ERROR_IO, + N_("`incbin': unable to read %lu bytes from file `%s'"), + bc->len, incbin->filename); + fclose(f); + return 1; + } + + *bufp += bc->len; + fclose(f); + return 0; +} + +yasm_bytecode * +yasm_bc_create_incbin(char *filename, yasm_expr *start, yasm_expr *maxlen, + yasm_linemap *linemap, unsigned long line) +{ + bytecode_incbin *incbin = yasm_xmalloc(sizeof(bytecode_incbin)); + unsigned long xline; + + /* Find from filename based on line number */ + yasm_linemap_lookup(linemap, line, &incbin->from, &xline); + + /*@-mustfree@*/ + incbin->filename = filename; + incbin->start = start; + incbin->maxlen = maxlen; + /*@=mustfree@*/ + + return yasm_bc_create_common(&bc_incbin_callback, incbin, line); +} diff --git a/contrib/tools/yasm/libyasm/bc-org.c b/contrib/tools/yasm/libyasm/bc-org.c index 7ef96c8412..36dc255343 100644 --- a/contrib/tools/yasm/libyasm/bc-org.c +++ b/contrib/tools/yasm/libyasm/bc-org.c @@ -1,152 +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); -} +/* + * ORG bytecode + * + * Copyright (C) 2005-2007 Peter Johnson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include "util.h" + +#include "libyasm-stdint.h" +#include "coretype.h" +#include "file.h" + +#include "errwarn.h" +#include "intnum.h" +#include "expr.h" +#include "value.h" + +#include "bytecode.h" + + +typedef struct bytecode_org { + unsigned long start; /* target starting offset within section */ + unsigned long fill; /* fill value */ +} bytecode_org; + +static void bc_org_destroy(void *contents); +static void bc_org_print(const void *contents, FILE *f, int indent_level); +static void bc_org_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc); +static int bc_org_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span, + void *add_span_data); +static int bc_org_expand(yasm_bytecode *bc, int span, long old_val, + long new_val, /*@out@*/ long *neg_thres, + /*@out@*/ long *pos_thres); +static int bc_org_tobytes(yasm_bytecode *bc, unsigned char **bufp, + unsigned char *bufstart, void *d, + yasm_output_value_func output_value, + /*@null@*/ yasm_output_reloc_func output_reloc); + +static const yasm_bytecode_callback bc_org_callback = { + bc_org_destroy, + bc_org_print, + bc_org_finalize, + NULL, + bc_org_calc_len, + bc_org_expand, + bc_org_tobytes, + YASM_BC_SPECIAL_OFFSET +}; + + +static void +bc_org_destroy(void *contents) +{ + yasm_xfree(contents); +} + +static void +bc_org_print(const void *contents, FILE *f, int indent_level) +{ + const bytecode_org *org = (const bytecode_org *)contents; + fprintf(f, "%*s_Org_\n", indent_level, ""); + fprintf(f, "%*sStart=%lu\n", indent_level, "", org->start); +} + +static void +bc_org_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc) +{ +} + +static int +bc_org_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span, + void *add_span_data) +{ + bytecode_org *org = (bytecode_org *)bc->contents; + long neg_thres = 0; + long pos_thres = org->start; + + if (bc_org_expand(bc, 0, 0, (long)bc->offset, &neg_thres, &pos_thres) < 0) + return -1; + + return 0; +} + +static int +bc_org_expand(yasm_bytecode *bc, int span, long old_val, long new_val, + /*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres) +{ + bytecode_org *org = (bytecode_org *)bc->contents; + + /* Check for overrun */ + if ((unsigned long)new_val > org->start) { + yasm_error_set(YASM_ERROR_GENERAL, + N_("ORG overlap with already existing data")); + return -1; + } + + /* Generate space to start offset */ + bc->len = org->start - new_val; + return 1; +} + +static int +bc_org_tobytes(yasm_bytecode *bc, unsigned char **bufp, + unsigned char *bufstart, void *d, + yasm_output_value_func output_value, + /*@unused@*/ yasm_output_reloc_func output_reloc) +{ + bytecode_org *org = (bytecode_org *)bc->contents; + unsigned long len, i; + + /* Sanity check for overrun */ + if (bc->offset > org->start) { + yasm_error_set(YASM_ERROR_GENERAL, + N_("ORG overlap with already existing data")); + return 1; + } + len = org->start - bc->offset; + for (i=0; i<len; i++) + YASM_WRITE_8(*bufp, org->fill); /* XXX: handle more than 8 bit? */ + return 0; +} + +yasm_bytecode * +yasm_bc_create_org(unsigned long start, unsigned long fill, unsigned long line) +{ + bytecode_org *org = yasm_xmalloc(sizeof(bytecode_org)); + + org->start = start; + org->fill = fill; + + return yasm_bc_create_common(&bc_org_callback, org, line); +} diff --git a/contrib/tools/yasm/libyasm/bc-reserve.c b/contrib/tools/yasm/libyasm/bc-reserve.c index 197175b4e5..f687f1410f 100644 --- a/contrib/tools/yasm/libyasm/bc-reserve.c +++ b/contrib/tools/yasm/libyasm/bc-reserve.c @@ -1,152 +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; -} +/* + * Bytecode utility functions + * + * Copyright (C) 2001-2007 Peter Johnson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include "util.h" + +#include "libyasm-stdint.h" +#include "coretype.h" + +#include "errwarn.h" +#include "intnum.h" +#include "expr.h" +#include "value.h" + +#include "bytecode.h" + + +typedef struct bytecode_reserve { + /*@only@*/ /*@null@*/ yasm_expr *numitems; /* number of items to reserve */ + unsigned int itemsize; /* size of each item (in bytes) */ +} bytecode_reserve; + +static void bc_reserve_destroy(void *contents); +static void bc_reserve_print(const void *contents, FILE *f, int indent_level); +static void bc_reserve_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc); +static int bc_reserve_elem_size(yasm_bytecode *bc); +static int bc_reserve_calc_len(yasm_bytecode *bc, + yasm_bc_add_span_func add_span, + void *add_span_data); +static int bc_reserve_tobytes(yasm_bytecode *bc, unsigned char **bufp, + unsigned char *bufstart, void *d, + yasm_output_value_func output_value, + /*@null@*/ yasm_output_reloc_func output_reloc); + +static const yasm_bytecode_callback bc_reserve_callback = { + bc_reserve_destroy, + bc_reserve_print, + bc_reserve_finalize, + bc_reserve_elem_size, + bc_reserve_calc_len, + yasm_bc_expand_common, + bc_reserve_tobytes, + YASM_BC_SPECIAL_RESERVE +}; + + +static void +bc_reserve_destroy(void *contents) +{ + bytecode_reserve *reserve = (bytecode_reserve *)contents; + yasm_expr_destroy(reserve->numitems); + yasm_xfree(contents); +} + +static void +bc_reserve_print(const void *contents, FILE *f, int indent_level) +{ + const bytecode_reserve *reserve = (const bytecode_reserve *)contents; + fprintf(f, "%*s_Reserve_\n", indent_level, ""); + fprintf(f, "%*sNum Items=", indent_level, ""); + yasm_expr_print(reserve->numitems, f); + fprintf(f, "\n%*sItem Size=%u\n", indent_level, "", reserve->itemsize); +} + +static void +bc_reserve_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc) +{ + bytecode_reserve *reserve = (bytecode_reserve *)bc->contents; + /* multiply reserve expression into multiple */ + if (!bc->multiple) + bc->multiple = reserve->numitems; + else + bc->multiple = yasm_expr_create_tree(bc->multiple, YASM_EXPR_MUL, + reserve->numitems, bc->line); + reserve->numitems = NULL; +} + +static int +bc_reserve_elem_size(yasm_bytecode *bc) +{ + bytecode_reserve *reserve = (bytecode_reserve *)bc->contents; + return reserve->itemsize; +} + +static int +bc_reserve_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span, + void *add_span_data) +{ + bytecode_reserve *reserve = (bytecode_reserve *)bc->contents; + bc->len += reserve->itemsize; + return 0; +} + +static int +bc_reserve_tobytes(yasm_bytecode *bc, unsigned char **bufp, + unsigned char *bufstart, void *d, + yasm_output_value_func output_value, + /*@unused@*/ yasm_output_reloc_func output_reloc) +{ + yasm_internal_error(N_("bc_reserve_tobytes called")); + /*@notreached@*/ + return 1; +} + +yasm_bytecode * +yasm_bc_create_reserve(yasm_expr *numitems, unsigned int itemsize, + unsigned long line) +{ + bytecode_reserve *reserve = yasm_xmalloc(sizeof(bytecode_reserve)); + + /*@-mustfree@*/ + reserve->numitems = numitems; + /*@=mustfree@*/ + reserve->itemsize = itemsize; + + return yasm_bc_create_common(&bc_reserve_callback, reserve, line); +} + +const yasm_expr * +yasm_bc_reserve_numitems(yasm_bytecode *bc, unsigned int *itemsize) +{ + bytecode_reserve *reserve; + + if (bc->callback != &bc_reserve_callback) + return NULL; + + reserve = (bytecode_reserve *)bc->contents; + *itemsize = reserve->itemsize; + return reserve->numitems; +} diff --git a/contrib/tools/yasm/libyasm/bitvect.c b/contrib/tools/yasm/libyasm/bitvect.c index dfb08252b0..b1d5bdae11 100644 --- a/contrib/tools/yasm/libyasm/bitvect.c +++ b/contrib/tools/yasm/libyasm/bitvect.c @@ -1,4045 +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 */ -/* */ -/*****************************************************************************/ +#include "util.h" + +#include "coretype.h" + +/*****************************************************************************/ +/* MODULE NAME: BitVector.c MODULE TYPE: (adt) */ +/*****************************************************************************/ +/* MODULE IMPORTS: */ +/*****************************************************************************/ +#include <ctype.h> /* MODULE TYPE: (sys) */ +#include <limits.h> /* MODULE TYPE: (sys) */ +#include <string.h> /* MODULE TYPE: (sys) */ +/*****************************************************************************/ +/* MODULE INTERFACE: */ +/*****************************************************************************/ +#include "bitvect.h" + +/* ToolBox.h */ +#define and && /* logical (boolean) operators: lower case */ +#define or || +#define not ! + +#define AND & /* binary (bitwise) operators: UPPER CASE */ +#define OR | +#define XOR ^ +#define NOT ~ +#define SHL << +#define SHR >> + +#ifdef ENABLE_MODULO +#define mod % /* arithmetic operators */ +#endif + +#define blockdef(name,size) unsigned char name[size] +#define blocktypedef(name,size) typedef unsigned char name[size] + +/*****************************************************************************/ +/* MODULE RESOURCES: */ +/*****************************************************************************/ + +#define bits_(BitVector) *(BitVector-3) +#define size_(BitVector) *(BitVector-2) +#define mask_(BitVector) *(BitVector-1) + +#define ERRCODE_TYPE "sizeof(word) > sizeof(size_t)" +#define ERRCODE_BITS "bits(word) != sizeof(word)*8" +#define ERRCODE_WORD "bits(word) < 16" +#define ERRCODE_LONG "bits(word) > bits(long)" +#define ERRCODE_POWR "bits(word) != 2^x" +#define ERRCODE_LOGA "bits(word) != 2^ld(bits(word))" +#define ERRCODE_NULL "unable to allocate memory" +#define ERRCODE_INDX "index out of range" +#define ERRCODE_ORDR "minimum > maximum index" +#define ERRCODE_SIZE "bit vector size mismatch" +#define ERRCODE_PARS "input string syntax error" +#define ERRCODE_OVFL "numeric overflow error" +#define ERRCODE_SAME "result vector(s) must be distinct" +#define ERRCODE_EXPO "exponent must be positive" +#define ERRCODE_ZERO "division by zero error" +#define ERRCODE_OOPS "unexpected internal error - please contact author" + +const N_int BitVector_BYTENORM[256] = +{ + 0x00, 0x01, 0x01, 0x02, 0x01, 0x02, 0x02, 0x03, + 0x01, 0x02, 0x02, 0x03, 0x02, 0x03, 0x03, 0x04, /* 0x00 */ + 0x01, 0x02, 0x02, 0x03, 0x02, 0x03, 0x03, 0x04, + 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05, /* 0x10 */ + 0x01, 0x02, 0x02, 0x03, 0x02, 0x03, 0x03, 0x04, + 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05, /* 0x20 */ + 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05, + 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06, /* 0x30 */ + 0x01, 0x02, 0x02, 0x03, 0x02, 0x03, 0x03, 0x04, + 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05, /* 0x40 */ + 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05, + 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06, /* 0x50 */ + 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05, + 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06, /* 0x60 */ + 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06, + 0x04, 0x05, 0x05, 0x06, 0x05, 0x06, 0x06, 0x07, /* 0x70 */ + 0x01, 0x02, 0x02, 0x03, 0x02, 0x03, 0x03, 0x04, + 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05, /* 0x80 */ + 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05, + 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06, /* 0x90 */ + 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05, + 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06, /* 0xA0 */ + 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06, + 0x04, 0x05, 0x05, 0x06, 0x05, 0x06, 0x06, 0x07, /* 0xB0 */ + 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05, + 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06, /* 0xC0 */ + 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06, + 0x04, 0x05, 0x05, 0x06, 0x05, 0x06, 0x06, 0x07, /* 0xD0 */ + 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06, + 0x04, 0x05, 0x05, 0x06, 0x05, 0x06, 0x06, 0x07, /* 0xE0 */ + 0x04, 0x05, 0x05, 0x06, 0x05, 0x06, 0x06, 0x07, + 0x05, 0x06, 0x06, 0x07, 0x06, 0x07, 0x07, 0x08 /* 0xF0 */ +}; + +/*****************************************************************************/ +/* MODULE IMPLEMENTATION: */ +/*****************************************************************************/ + + /**********************************************/ + /* global implementation-intrinsic constants: */ + /**********************************************/ + +#define BIT_VECTOR_HIDDEN_WORDS 3 + + /*****************************************************************/ + /* global machine-dependent constants (set by "BitVector_Boot"): */ + /*****************************************************************/ + +static N_word BITS; /* = # of bits in machine word (must be power of 2) */ +static N_word MODMASK; /* = BITS - 1 (mask for calculating modulo BITS) */ +static N_word LOGBITS; /* = ld(BITS) (logarithmus dualis) */ +static N_word FACTOR; /* = ld(BITS / 8) (ld of # of bytes) */ + +static N_word LSB = 1; /* = mask for least significant bit */ +static N_word MSB; /* = mask for most significant bit */ + +static N_word LONGBITS; /* = # of bits in unsigned long */ + +static N_word LOG10; /* = logarithm to base 10 of BITS - 1 */ +static N_word EXP10; /* = largest possible power of 10 in signed int */ + + /********************************************************************/ + /* global bit mask table for fast access (set by "BitVector_Boot"): */ + /********************************************************************/ + +static wordptr BITMASKTAB; + + /*****************************/ + /* global macro definitions: */ + /*****************************/ + +#define BIT_VECTOR_ZERO_WORDS(target,count) \ + while (count-- > 0) *target++ = 0; + +#define BIT_VECTOR_FILL_WORDS(target,fill,count) \ + while (count-- > 0) *target++ = fill; + +#define BIT_VECTOR_FLIP_WORDS(target,flip,count) \ + while (count-- > 0) *target++ ^= flip; + +#define BIT_VECTOR_COPY_WORDS(target,source,count) \ + while (count-- > 0) *target++ = *source++; + +#define BIT_VECTOR_BACK_WORDS(target,source,count) \ + { target += count; source += count; while (count-- > 0) *--target = *--source; } + +#define BIT_VECTOR_CLR_BIT(address,index) \ + *(address+(index>>LOGBITS)) &= NOT BITMASKTAB[index AND MODMASK]; + +#define BIT_VECTOR_SET_BIT(address,index) \ + *(address+(index>>LOGBITS)) |= BITMASKTAB[index AND MODMASK]; + +#define BIT_VECTOR_TST_BIT(address,index) \ + ((*(address+(index>>LOGBITS)) AND BITMASKTAB[index AND MODMASK]) != 0) + +#define BIT_VECTOR_FLP_BIT(address,index,mask) \ + (mask = BITMASKTAB[index AND MODMASK]), \ + (((*(addr+(index>>LOGBITS)) ^= mask) AND mask) != 0) + +#define BIT_VECTOR_DIGITIZE(type,value,digit) \ + value = (type) ((digit = value) / 10); \ + digit -= value * 10; \ + digit += (type) '0'; + + /*********************************************************/ + /* private low-level functions (potentially dangerous!): */ + /*********************************************************/ + +static N_word power10(N_word x) +{ + N_word y = 1; + + while (x-- > 0) y *= 10; + return(y); +} + +static void BIT_VECTOR_zro_words(wordptr addr, N_word count) +{ + BIT_VECTOR_ZERO_WORDS(addr,count) +} + +static void BIT_VECTOR_cpy_words(wordptr target, wordptr source, N_word count) +{ + BIT_VECTOR_COPY_WORDS(target,source,count) +} + +static void BIT_VECTOR_mov_words(wordptr target, wordptr source, N_word count) +{ + if (target != source) + { + if (target < source) BIT_VECTOR_COPY_WORDS(target,source,count) + else BIT_VECTOR_BACK_WORDS(target,source,count) + } +} + +static void BIT_VECTOR_ins_words(wordptr addr, N_word total, N_word count, + boolean clear) +{ + N_word length; + + if ((total > 0) and (count > 0)) + { + if (count > total) count = total; + length = total - count; + if (length > 0) BIT_VECTOR_mov_words(addr+count,addr,length); + if (clear) BIT_VECTOR_zro_words(addr,count); + } +} + +static void BIT_VECTOR_del_words(wordptr addr, N_word total, N_word count, + boolean clear) +{ + N_word length; + + if ((total > 0) and (count > 0)) + { + if (count > total) count = total; + length = total - count; + if (length > 0) BIT_VECTOR_mov_words(addr,addr+count,length); + if (clear) BIT_VECTOR_zro_words(addr+length,count); + } +} + +static void BIT_VECTOR_reverse(charptr string, N_word length) +{ + charptr last; + N_char temp; + + if (length > 1) + { + last = string + length - 1; + while (string < last) + { + temp = *string; + *string = *last; + *last = temp; + string++; + last--; + } + } +} + +static N_word BIT_VECTOR_int2str(charptr string, N_word value) +{ + N_word length; + N_word digit; + charptr work; + + work = string; + if (value > 0) + { + length = 0; + while (value > 0) + { + BIT_VECTOR_DIGITIZE(N_word,value,digit) + *work++ = (N_char) digit; + length++; + } + BIT_VECTOR_reverse(string,length); + } + else + { + length = 1; + *work++ = (N_char) '0'; + } + return(length); +} + +static N_word BIT_VECTOR_str2int(charptr string, N_word *value) +{ + N_word length; + N_word digit; + + *value = 0; + length = 0; + digit = (N_word) *string++; + /* separate because isdigit() is likely a macro! */ + while (isdigit((int)digit) != 0) + { + length++; + digit -= (N_word) '0'; + if (*value) *value *= 10; + *value += digit; + digit = (N_word) *string++; + } + return(length); +} + + /********************************************/ + /* routine to convert error code to string: */ + /********************************************/ + +const char * BitVector_Error(ErrCode error) +{ + switch (error) + { + case ErrCode_Ok: return( NULL ); break; + case ErrCode_Type: return( ERRCODE_TYPE ); break; + case ErrCode_Bits: return( ERRCODE_BITS ); break; + case ErrCode_Word: return( ERRCODE_WORD ); break; + case ErrCode_Long: return( ERRCODE_LONG ); break; + case ErrCode_Powr: return( ERRCODE_POWR ); break; + case ErrCode_Loga: return( ERRCODE_LOGA ); break; + case ErrCode_Null: return( ERRCODE_NULL ); break; + case ErrCode_Indx: return( ERRCODE_INDX ); break; + case ErrCode_Ordr: return( ERRCODE_ORDR ); break; + case ErrCode_Size: return( ERRCODE_SIZE ); break; + case ErrCode_Pars: return( ERRCODE_PARS ); break; + case ErrCode_Ovfl: return( ERRCODE_OVFL ); break; + case ErrCode_Same: return( ERRCODE_SAME ); break; + case ErrCode_Expo: return( ERRCODE_EXPO ); break; + case ErrCode_Zero: return( ERRCODE_ZERO ); break; + default: return( ERRCODE_OOPS ); break; + } +} + + /*****************************************/ + /* automatic self-configuration routine: */ + /*****************************************/ + + /*******************************************************/ + /* */ + /* MUST be called once prior to any other function */ + /* to initialize the machine dependent constants */ + /* of this package! (But call only ONCE, or you */ + /* will suffer memory leaks!) */ + /* */ + /*******************************************************/ + +ErrCode BitVector_Boot(void) +{ + N_long longsample = 1L; + N_word sample = LSB; + N_word lsb; + + if (sizeof(N_word) > sizeof(size_t)) return(ErrCode_Type); + + BITS = 1; + while (sample <<= 1) BITS++; /* determine # of bits in a machine word */ + + if (BITS != (sizeof(N_word) << 3)) return(ErrCode_Bits); + + if (BITS < 16) return(ErrCode_Word); + + LONGBITS = 1; + while (longsample <<= 1) LONGBITS++; /* = # of bits in an unsigned long */ + + if (BITS > LONGBITS) return(ErrCode_Long); + + LOGBITS = 0; + sample = BITS; + lsb = (sample AND LSB); + while ((sample >>= 1) and (not lsb)) + { + LOGBITS++; + lsb = (sample AND LSB); + } + + if (sample) return(ErrCode_Powr); /* # of bits is not a power of 2! */ + + if (BITS != (LSB << LOGBITS)) return(ErrCode_Loga); + + MODMASK = BITS - 1; + FACTOR = LOGBITS - 3; /* ld(BITS / 8) = ld(BITS) - ld(8) = ld(BITS) - 3 */ + MSB = (LSB << MODMASK); + + BITMASKTAB = (wordptr) yasm_xmalloc((size_t) (BITS << FACTOR)); + + if (BITMASKTAB == NULL) return(ErrCode_Null); + + for ( sample = 0; sample < BITS; sample++ ) + { + BITMASKTAB[sample] = (LSB << sample); + } + + LOG10 = (N_word) (MODMASK * 0.30103); /* = (BITS - 1) * ( ln 2 / ln 10 ) */ + EXP10 = power10(LOG10); + + return(ErrCode_Ok); +} + +void BitVector_Shutdown(void) +{ + if (BITMASKTAB) yasm_xfree(BITMASKTAB); +} + +N_word BitVector_Size(N_int bits) /* bit vector size (# of words) */ +{ + N_word size; + + size = bits >> LOGBITS; + if (bits AND MODMASK) size++; + return(size); +} + +N_word BitVector_Mask(N_int bits) /* bit vector mask (unused bits) */ +{ + N_word mask; + + mask = bits AND MODMASK; + if (mask) mask = (N_word) ~(~0L << mask); else mask = (N_word) ~0L; + return(mask); +} + +const char * BitVector_Version(void) +{ + return("6.4"); +} + +N_int BitVector_Word_Bits(void) +{ + return(BITS); +} + +N_int BitVector_Long_Bits(void) +{ + return(LONGBITS); +} + +/********************************************************************/ +/* */ +/* WARNING: Do not "free()" constant character strings, i.e., */ +/* don't call "BitVector_Dispose()" for strings returned */ +/* by "BitVector_Error()" or "BitVector_Version()"! */ +/* */ +/* ONLY call this function for strings allocated with "malloc()", */ +/* i.e., the strings returned by the functions "BitVector_to_*()" */ +/* and "BitVector_Block_Read()"! */ +/* */ +/********************************************************************/ + +void BitVector_Dispose(charptr string) /* free string */ +{ + if (string != NULL) yasm_xfree((voidptr) string); +} + +void BitVector_Destroy(wordptr addr) /* free bitvec */ +{ + if (addr != NULL) + { + addr -= BIT_VECTOR_HIDDEN_WORDS; + yasm_xfree((voidptr) addr); + } +} + +void BitVector_Destroy_List(listptr list, N_int count) /* free list */ +{ + listptr slot; + + if (list != NULL) + { + slot = list; + while (count-- > 0) + { + BitVector_Destroy(*slot++); + } + free((voidptr) list); + } +} + +wordptr BitVector_Create(N_int bits, boolean clear) /* malloc */ +{ + N_word size; + N_word mask; + N_word bytes; + wordptr addr; + wordptr zero; + + size = BitVector_Size(bits); + mask = BitVector_Mask(bits); + bytes = (size + BIT_VECTOR_HIDDEN_WORDS) << FACTOR; + addr = (wordptr) yasm_xmalloc((size_t) bytes); + if (addr != NULL) + { + *addr++ = bits; + *addr++ = size; + *addr++ = mask; + if (clear) + { + zero = addr; + BIT_VECTOR_ZERO_WORDS(zero,size) + } + } + return(addr); +} + +listptr BitVector_Create_List(N_int bits, boolean clear, N_int count) +{ + listptr list = NULL; + listptr slot; + wordptr addr; + N_int i; + + if (count > 0) + { + list = (listptr) malloc(sizeof(wordptr) * count); + if (list != NULL) + { + slot = list; + for ( i = 0; i < count; i++ ) + { + addr = BitVector_Create(bits,clear); + if (addr == NULL) + { + BitVector_Destroy_List(list,i); + return(NULL); + } + *slot++ = addr; + } + } + } + return(list); +} + +wordptr BitVector_Resize(wordptr oldaddr, N_int bits) /* realloc */ +{ + N_word bytes; + N_word oldsize; + N_word oldmask; + N_word newsize; + N_word newmask; + wordptr newaddr; + wordptr source; + wordptr target; + + oldsize = size_(oldaddr); + oldmask = mask_(oldaddr); + newsize = BitVector_Size(bits); + newmask = BitVector_Mask(bits); + if (oldsize > 0) *(oldaddr+oldsize-1) &= oldmask; + if (newsize <= oldsize) + { + newaddr = oldaddr; + bits_(newaddr) = bits; + size_(newaddr) = newsize; + mask_(newaddr) = newmask; + if (newsize > 0) *(newaddr+newsize-1) &= newmask; + } + else + { + bytes = (newsize + BIT_VECTOR_HIDDEN_WORDS) << FACTOR; + newaddr = (wordptr) yasm_xmalloc((size_t) bytes); + if (newaddr != NULL) + { + *newaddr++ = bits; + *newaddr++ = newsize; + *newaddr++ = newmask; + target = newaddr; + source = oldaddr; + newsize -= oldsize; + BIT_VECTOR_COPY_WORDS(target,source,oldsize) + BIT_VECTOR_ZERO_WORDS(target,newsize) + } + BitVector_Destroy(oldaddr); + } + return(newaddr); +} + +wordptr BitVector_Shadow(wordptr addr) /* makes new, same size but empty */ +{ + return( BitVector_Create(bits_(addr),true) ); +} + +wordptr BitVector_Clone(wordptr addr) /* makes exact duplicate */ +{ + N_word bits; + wordptr twin; + + bits = bits_(addr); + twin = BitVector_Create(bits,false); + if ((twin != NULL) and (bits > 0)) + BIT_VECTOR_cpy_words(twin,addr,size_(addr)); + return(twin); +} + +wordptr BitVector_Concat(wordptr X, wordptr Y) /* returns concatenation */ +{ + /* BEWARE that X = most significant part, Y = least significant part! */ + + N_word bitsX; + N_word bitsY; + N_word bitsZ; + wordptr Z; + + bitsX = bits_(X); + bitsY = bits_(Y); + bitsZ = bitsX + bitsY; + Z = BitVector_Create(bitsZ,false); + if ((Z != NULL) and (bitsZ > 0)) + { + BIT_VECTOR_cpy_words(Z,Y,size_(Y)); + BitVector_Interval_Copy(Z,X,bitsY,0,bitsX); + *(Z+size_(Z)-1) &= mask_(Z); + } + return(Z); +} + +void BitVector_Copy(wordptr X, wordptr Y) /* X = Y */ +{ + N_word sizeX = size_(X); + N_word sizeY = size_(Y); + N_word maskX = mask_(X); + N_word maskY = mask_(Y); + N_word fill = 0; + wordptr lastX; + wordptr lastY; + + if ((X != Y) and (sizeX > 0)) + { + lastX = X + sizeX - 1; + if (sizeY > 0) + { + lastY = Y + sizeY - 1; + if ( (*lastY AND (maskY AND NOT (maskY >> 1))) == 0 ) *lastY &= maskY; + else + { + fill = (N_word) ~0L; + *lastY |= NOT maskY; + } + while ((sizeX > 0) and (sizeY > 0)) + { + *X++ = *Y++; + sizeX--; + sizeY--; + } + *lastY &= maskY; + } + while (sizeX-- > 0) *X++ = fill; + *lastX &= maskX; + } +} + +void BitVector_Empty(wordptr addr) /* X = {} clr all */ +{ + N_word size = size_(addr); + + BIT_VECTOR_ZERO_WORDS(addr,size) +} + +void BitVector_Fill(wordptr addr) /* X = ~{} set all */ +{ + N_word size = size_(addr); + N_word mask = mask_(addr); + N_word fill = (N_word) ~0L; + + if (size > 0) + { + BIT_VECTOR_FILL_WORDS(addr,fill,size) + *(--addr) &= mask; + } +} + +void BitVector_Flip(wordptr addr) /* X = ~X flip all */ +{ + N_word size = size_(addr); + N_word mask = mask_(addr); + N_word flip = (N_word) ~0L; + + if (size > 0) + { + BIT_VECTOR_FLIP_WORDS(addr,flip,size) + *(--addr) &= mask; + } +} + +void BitVector_Primes(wordptr addr) +{ + N_word bits = bits_(addr); + N_word size = size_(addr); + wordptr work; + N_word temp; + N_word i,j; + + if (size > 0) + { + temp = 0xAAAA; + i = BITS >> 4; + while (--i > 0) + { + temp <<= 16; + temp |= 0xAAAA; + } + i = size; + work = addr; + *work++ = temp XOR 0x0006; + while (--i > 0) *work++ = temp; + for ( i = 3; (j = i * i) < bits; i += 2 ) + { + for ( ; j < bits; j += i ) BIT_VECTOR_CLR_BIT(addr,j) + } + *(addr+size-1) &= mask_(addr); + } +} + +void BitVector_Reverse(wordptr X, wordptr Y) +{ + N_word bits = bits_(X); + N_word mask; + N_word bit; + N_word value; + + if (bits > 0) + { + if (X == Y) BitVector_Interval_Reverse(X,0,bits-1); + else if (bits == bits_(Y)) + { +/* mask = mask_(Y); */ +/* mask &= NOT (mask >> 1); */ + mask = BITMASKTAB[(bits-1) AND MODMASK]; + Y += size_(Y) - 1; + value = 0; + bit = LSB; + while (bits-- > 0) + { + if ((*Y AND mask) != 0) + { + value |= bit; + } + if (not (mask >>= 1)) + { + Y--; + mask = MSB; + } + if (not (bit <<= 1)) + { + *X++ = value; + value = 0; + bit = LSB; + } + } + if (bit > LSB) *X = value; + } + } +} + +void BitVector_Interval_Empty(wordptr addr, N_int lower, N_int upper) +{ /* X = X \ [lower..upper] */ + N_word bits = bits_(addr); + N_word size = size_(addr); + wordptr loaddr; + wordptr hiaddr; + N_word lobase; + N_word hibase; + N_word lomask; + N_word himask; + N_word diff; + + if ((size > 0) and (lower < bits) and (upper < bits) and (lower <= upper)) + { + lobase = lower >> LOGBITS; + hibase = upper >> LOGBITS; + diff = hibase - lobase; + loaddr = addr + lobase; + hiaddr = addr + hibase; + + lomask = (N_word) (~0L << (lower AND MODMASK)); + himask = (N_word) ~((~0L << (upper AND MODMASK)) << 1); + + if (diff == 0) + { + *loaddr &= NOT (lomask AND himask); + } + else + { + *loaddr++ &= NOT lomask; + while (--diff > 0) + { + *loaddr++ = 0; + } + *hiaddr &= NOT himask; + } + } +} + +void BitVector_Interval_Fill(wordptr addr, N_int lower, N_int upper) +{ /* X = X + [lower..upper] */ + N_word bits = bits_(addr); + N_word size = size_(addr); + N_word fill = (N_word) ~0L; + wordptr loaddr; + wordptr hiaddr; + N_word lobase; + N_word hibase; + N_word lomask; + N_word himask; + N_word diff; + + if ((size > 0) and (lower < bits) and (upper < bits) and (lower <= upper)) + { + lobase = lower >> LOGBITS; + hibase = upper >> LOGBITS; + diff = hibase - lobase; + loaddr = addr + lobase; + hiaddr = addr + hibase; + + lomask = (N_word) (~0L << (lower AND MODMASK)); + himask = (N_word) ~((~0L << (upper AND MODMASK)) << 1); + + if (diff == 0) + { + *loaddr |= (lomask AND himask); + } + else + { + *loaddr++ |= lomask; + while (--diff > 0) + { + *loaddr++ = fill; + } + *hiaddr |= himask; + } + *(addr+size-1) &= mask_(addr); + } +} + +void BitVector_Interval_Flip(wordptr addr, N_int lower, N_int upper) +{ /* X = X ^ [lower..upper] */ + N_word bits = bits_(addr); + N_word size = size_(addr); + N_word flip = (N_word) ~0L; + wordptr loaddr; + wordptr hiaddr; + N_word lobase; + N_word hibase; + N_word lomask; + N_word himask; + N_word diff; + + if ((size > 0) and (lower < bits) and (upper < bits) and (lower <= upper)) + { + lobase = lower >> LOGBITS; + hibase = upper >> LOGBITS; + diff = hibase - lobase; + loaddr = addr + lobase; + hiaddr = addr + hibase; + + lomask = (N_word) (~0L << (lower AND MODMASK)); + himask = (N_word) ~((~0L << (upper AND MODMASK)) << 1); + + if (diff == 0) + { + *loaddr ^= (lomask AND himask); + } + else + { + *loaddr++ ^= lomask; + while (--diff > 0) + { + *loaddr++ ^= flip; + } + *hiaddr ^= himask; + } + *(addr+size-1) &= mask_(addr); + } +} + +void BitVector_Interval_Reverse(wordptr addr, N_int lower, N_int upper) +{ + N_word bits = bits_(addr); + wordptr loaddr; + wordptr hiaddr; + N_word lomask; + N_word himask; + + if ((bits > 0) and (lower < bits) and (upper < bits) and (lower < upper)) + { + loaddr = addr + (lower >> LOGBITS); + hiaddr = addr + (upper >> LOGBITS); + lomask = BITMASKTAB[lower AND MODMASK]; + himask = BITMASKTAB[upper AND MODMASK]; + for ( bits = upper - lower + 1; bits > 1; bits -= 2 ) + { + if (((*loaddr AND lomask) != 0) XOR ((*hiaddr AND himask) != 0)) + { + *loaddr ^= lomask; /* swap bits only if they differ! */ + *hiaddr ^= himask; + } + if (not (lomask <<= 1)) + { + lomask = LSB; + loaddr++; + } + if (not (himask >>= 1)) + { + himask = MSB; + hiaddr--; + } + } + } +} + +boolean BitVector_interval_scan_inc(wordptr addr, N_int start, + N_intptr min, N_intptr max) +{ + N_word size = size_(addr); + N_word mask = mask_(addr); + N_word offset; + N_word bitmask; + N_word value; + boolean empty; + + if ((size == 0) or (start >= bits_(addr))) return(FALSE); + + *min = start; + *max = start; + + offset = start >> LOGBITS; + + *(addr+size-1) &= mask; + + addr += offset; + size -= offset; + + bitmask = BITMASKTAB[start AND MODMASK]; + mask = NOT (bitmask OR (bitmask - 1)); + + value = *addr++; + if ((value AND bitmask) == 0) + { + value &= mask; + if (value == 0) + { + offset++; + empty = TRUE; + while (empty and (--size > 0)) + { + if ((value = *addr++)) empty = false; else offset++; + } + if (empty) return(FALSE); + } + start = offset << LOGBITS; + bitmask = LSB; + mask = value; + while (not (mask AND LSB)) + { + bitmask <<= 1; + mask >>= 1; + start++; + } + mask = NOT (bitmask OR (bitmask - 1)); + *min = start; + *max = start; + } + value = NOT value; + value &= mask; + if (value == 0) + { + offset++; + empty = TRUE; + while (empty and (--size > 0)) + { + if ((value = NOT *addr++)) empty = false; else offset++; + } + if (empty) value = LSB; + } + start = offset << LOGBITS; + while (not (value AND LSB)) + { + value >>= 1; + start++; + } + *max = --start; + return(TRUE); +} + +boolean BitVector_interval_scan_dec(wordptr addr, N_int start, + N_intptr min, N_intptr max) +{ + N_word size = size_(addr); + N_word mask = mask_(addr); + N_word offset; + N_word bitmask; + N_word value; + boolean empty; + + if ((size == 0) or (start >= bits_(addr))) return(FALSE); + + *min = start; + *max = start; + + offset = start >> LOGBITS; + + if (offset >= size) return(FALSE); + + *(addr+size-1) &= mask; + + addr += offset; + size = ++offset; + + bitmask = BITMASKTAB[start AND MODMASK]; + mask = (bitmask - 1); + + value = *addr--; + if ((value AND bitmask) == 0) + { + value &= mask; + if (value == 0) + { + offset--; + empty = TRUE; + while (empty and (--size > 0)) + { + if ((value = *addr--)) empty = false; else offset--; + } + if (empty) return(FALSE); + } + start = offset << LOGBITS; + bitmask = MSB; + mask = value; + while (not (mask AND MSB)) + { + bitmask >>= 1; + mask <<= 1; + start--; + } + mask = (bitmask - 1); + *max = --start; + *min = start; + } + value = NOT value; + value &= mask; + if (value == 0) + { + offset--; + empty = TRUE; + while (empty and (--size > 0)) + { + if ((value = NOT *addr--)) empty = false; else offset--; + } + if (empty) value = MSB; + } + start = offset << LOGBITS; + while (not (value AND MSB)) + { + value <<= 1; + start--; + } + *min = start; + return(TRUE); +} + +void BitVector_Interval_Copy(wordptr X, wordptr Y, N_int Xoffset, + N_int Yoffset, N_int length) +{ + N_word bitsX = bits_(X); + N_word bitsY = bits_(Y); + N_word source = 0; /* silence compiler warning */ + N_word target = 0; /* silence compiler warning */ + N_word s_lo_base; + N_word s_hi_base; + N_word s_lo_bit; + N_word s_hi_bit; + N_word s_base; + N_word s_lower = 0; /* silence compiler warning */ + N_word s_upper = 0; /* silence compiler warning */ + N_word s_bits; + N_word s_min; + N_word s_max; + N_word t_lo_base; + N_word t_hi_base; + N_word t_lo_bit; + N_word t_hi_bit; + N_word t_base; + N_word t_lower = 0; /* silence compiler warning */ + N_word t_upper = 0; /* silence compiler warning */ + N_word t_bits; + N_word t_min; + N_word mask; + N_word bits; + N_word sel; + boolean ascending; + boolean notfirst; + wordptr Z = X; + + if ((length > 0) and (Xoffset < bitsX) and (Yoffset < bitsY)) + { + if ((Xoffset + length) > bitsX) length = bitsX - Xoffset; + if ((Yoffset + length) > bitsY) length = bitsY - Yoffset; + + ascending = (Xoffset <= Yoffset); + + s_lo_base = Yoffset >> LOGBITS; + s_lo_bit = Yoffset AND MODMASK; + Yoffset += --length; + s_hi_base = Yoffset >> LOGBITS; + s_hi_bit = Yoffset AND MODMASK; + + t_lo_base = Xoffset >> LOGBITS; + t_lo_bit = Xoffset AND MODMASK; + Xoffset += length; + t_hi_base = Xoffset >> LOGBITS; + t_hi_bit = Xoffset AND MODMASK; + + if (ascending) + { + s_base = s_lo_base; + t_base = t_lo_base; + } + else + { + s_base = s_hi_base; + t_base = t_hi_base; + } + s_bits = 0; + t_bits = 0; + Y += s_base; + X += t_base; + notfirst = FALSE; + while (TRUE) + { + if (t_bits == 0) + { + if (notfirst) + { + *X = target; + if (ascending) + { + if (t_base == t_hi_base) break; + t_base++; + X++; + } + else + { + if (t_base == t_lo_base) break; + t_base--; + X--; + } + } + sel = ((t_base == t_hi_base) << 1) OR (t_base == t_lo_base); + switch (sel) + { + case 0: + t_lower = 0; + t_upper = BITS - 1; + t_bits = BITS; + target = 0; + break; + case 1: + t_lower = t_lo_bit; + t_upper = BITS - 1; + t_bits = BITS - t_lo_bit; + mask = (N_word) (~0L << t_lower); + target = *X AND NOT mask; + break; + case 2: + t_lower = 0; + t_upper = t_hi_bit; + t_bits = t_hi_bit + 1; + mask = (N_word) ((~0L << t_upper) << 1); + target = *X AND mask; + break; + case 3: + t_lower = t_lo_bit; + t_upper = t_hi_bit; + t_bits = t_hi_bit - t_lo_bit + 1; + mask = (N_word) (~0L << t_lower); + mask &= (N_word) ~((~0L << t_upper) << 1); + target = *X AND NOT mask; + break; + } + } + if (s_bits == 0) + { + if (notfirst) + { + if (ascending) + { + if (s_base == s_hi_base) break; + s_base++; + Y++; + } + else + { + if (s_base == s_lo_base) break; + s_base--; + Y--; + } + } + source = *Y; + sel = ((s_base == s_hi_base) << 1) OR (s_base == s_lo_base); + switch (sel) + { + case 0: + s_lower = 0; + s_upper = BITS - 1; + s_bits = BITS; + break; + case 1: + s_lower = s_lo_bit; + s_upper = BITS - 1; + s_bits = BITS - s_lo_bit; + break; + case 2: + s_lower = 0; + s_upper = s_hi_bit; + s_bits = s_hi_bit + 1; + break; + case 3: + s_lower = s_lo_bit; + s_upper = s_hi_bit; + s_bits = s_hi_bit - s_lo_bit + 1; + break; + } + } + notfirst = TRUE; + if (s_bits > t_bits) + { + bits = t_bits - 1; + if (ascending) + { + s_min = s_lower; + s_max = s_lower + bits; + } + else + { + s_max = s_upper; + s_min = s_upper - bits; + } + t_min = t_lower; + } + else + { + bits = s_bits - 1; + if (ascending) t_min = t_lower; + else t_min = t_upper - bits; + s_min = s_lower; + s_max = s_upper; + } + bits++; + mask = (N_word) (~0L << s_min); + mask &= (N_word) ~((~0L << s_max) << 1); + if (s_min == t_min) target |= (source AND mask); + else + { + if (s_min < t_min) target |= (source AND mask) << (t_min-s_min); + else target |= (source AND mask) >> (s_min-t_min); + } + if (ascending) + { + s_lower += bits; + t_lower += bits; + } + else + { + s_upper -= bits; + t_upper -= bits; + } + s_bits -= bits; + t_bits -= bits; + } + *(Z+size_(Z)-1) &= mask_(Z); + } +} + + +wordptr BitVector_Interval_Substitute(wordptr X, wordptr Y, + N_int Xoffset, N_int Xlength, + N_int Yoffset, N_int Ylength) +{ + N_word Xbits = bits_(X); + N_word Ybits = bits_(Y); + N_word limit; + N_word diff; + + if ((Xoffset <= Xbits) and (Yoffset <= Ybits)) + { + limit = Xoffset + Xlength; + if (limit > Xbits) + { + limit = Xbits; + Xlength = Xbits - Xoffset; + } + if ((Yoffset + Ylength) > Ybits) + { + Ylength = Ybits - Yoffset; + } + if (Xlength == Ylength) + { + if ((Ylength > 0) and ((X != Y) or (Xoffset != Yoffset))) + { + BitVector_Interval_Copy(X,Y,Xoffset,Yoffset,Ylength); + } + } + else /* Xlength != Ylength */ + { + if (Xlength > Ylength) + { + diff = Xlength - Ylength; + if (Ylength > 0) BitVector_Interval_Copy(X,Y,Xoffset,Yoffset,Ylength); + if (limit < Xbits) BitVector_Delete(X,Xoffset+Ylength,diff,FALSE); + if ((X = BitVector_Resize(X,Xbits-diff)) == NULL) return(NULL); + } + else /* Ylength > Xlength ==> Ylength > 0 */ + { + diff = Ylength - Xlength; + if (X != Y) + { + if ((X = BitVector_Resize(X,Xbits+diff)) == NULL) return(NULL); + if (limit < Xbits) BitVector_Insert(X,limit,diff,FALSE); + BitVector_Interval_Copy(X,Y,Xoffset,Yoffset,Ylength); + } + else /* in-place */ + { + if ((Y = X = BitVector_Resize(X,Xbits+diff)) == NULL) return(NULL); + if (limit >= Xbits) + { + BitVector_Interval_Copy(X,Y,Xoffset,Yoffset,Ylength); + } + else /* limit < Xbits */ + { + BitVector_Insert(X,limit,diff,FALSE); + if ((Yoffset+Ylength) <= limit) + { + BitVector_Interval_Copy(X,Y,Xoffset,Yoffset,Ylength); + } + else /* overlaps or lies above critical area */ + { + if (limit <= Yoffset) + { + Yoffset += diff; + BitVector_Interval_Copy(X,Y,Xoffset,Yoffset,Ylength); + } + else /* Yoffset < limit */ + { + Xlength = limit - Yoffset; + BitVector_Interval_Copy(X,Y,Xoffset,Yoffset,Xlength); + Yoffset = Xoffset + Ylength; /* = limit + diff */ + Xoffset += Xlength; + Ylength -= Xlength; + BitVector_Interval_Copy(X,Y,Xoffset,Yoffset,Ylength); + } + } + } + } + } + } + } + return(X); +} + +boolean BitVector_is_empty(wordptr addr) /* X == {} ? */ +{ + N_word size = size_(addr); + boolean r = TRUE; + + if (size > 0) + { + *(addr+size-1) &= mask_(addr); + while (r and (size-- > 0)) r = ( *addr++ == 0 ); + } + return(r); +} + +boolean BitVector_is_full(wordptr addr) /* X == ~{} ? */ +{ + N_word size = size_(addr); + N_word mask = mask_(addr); + boolean r = FALSE; + wordptr last; + + if (size > 0) + { + r = TRUE; + last = addr + size - 1; + *last |= NOT mask; + while (r and (size-- > 0)) r = ( NOT *addr++ == 0 ); + *last &= mask; + } + return(r); +} + +boolean BitVector_equal(wordptr X, wordptr Y) /* X == Y ? */ +{ + N_word size = size_(X); + N_word mask = mask_(X); + boolean r = FALSE; + + if (bits_(X) == bits_(Y)) + { + r = TRUE; + if (size > 0) + { + *(X+size-1) &= mask; + *(Y+size-1) &= mask; + while (r and (size-- > 0)) r = (*X++ == *Y++); + } + } + return(r); +} + +Z_int BitVector_Lexicompare(wordptr X, wordptr Y) /* X <,=,> Y ? */ +{ /* unsigned */ + N_word bitsX = bits_(X); + N_word bitsY = bits_(Y); + N_word size = size_(X); + boolean r = TRUE; + + if (bitsX == bitsY) + { + if (size > 0) + { + X += size; + Y += size; + while (r and (size-- > 0)) r = (*(--X) == *(--Y)); + } + if (r) return((Z_int) 0); + else + { + if (*X < *Y) return((Z_int) -1); else return((Z_int) 1); + } + } + else + { + if (bitsX < bitsY) return((Z_int) -1); else return((Z_int) 1); + } +} + +Z_int BitVector_Compare(wordptr X, wordptr Y) /* X <,=,> Y ? */ +{ /* signed */ + N_word bitsX = bits_(X); + N_word bitsY = bits_(Y); + N_word size = size_(X); + N_word mask = mask_(X); + N_word sign; + boolean r = TRUE; + + if (bitsX == bitsY) + { + if (size > 0) + { + X += size; + Y += size; + mask &= NOT (mask >> 1); + if ((sign = (*(X-1) AND mask)) != (*(Y-1) AND mask)) + { + if (sign) return((Z_int) -1); else return((Z_int) 1); + } + while (r and (size-- > 0)) r = (*(--X) == *(--Y)); + } + if (r) return((Z_int) 0); + else + { + if (*X < *Y) return((Z_int) -1); else return((Z_int) 1); + } + } + else + { + if (bitsX < bitsY) return((Z_int) -1); else return((Z_int) 1); + } +} + +charptr BitVector_to_Hex(wordptr addr) +{ + N_word bits = bits_(addr); + N_word size = size_(addr); + N_word value; + N_word count; + N_word digit; + N_word length; + charptr string; + + length = bits >> 2; + if (bits AND 0x0003) length++; + string = (charptr) yasm_xmalloc((size_t) (length+1)); + if (string == NULL) return(NULL); + string += length; + *string = (N_char) '\0'; + if (size > 0) + { + *(addr+size-1) &= mask_(addr); + while ((size-- > 0) and (length > 0)) + { + value = *addr++; + count = BITS >> 2; + while ((count-- > 0) and (length > 0)) + { + digit = value AND 0x000F; + if (digit > 9) digit += (N_word) 'A' - 10; + else digit += (N_word) '0'; + *(--string) = (N_char) digit; length--; + if ((count > 0) and (length > 0)) value >>= 4; + } + } + } + return(string); +} + +ErrCode BitVector_from_Hex(wordptr addr, charptr string) +{ + N_word size = size_(addr); + N_word mask = mask_(addr); + boolean ok = TRUE; + size_t length; + N_word value; + N_word count; + int digit; + + if (size > 0) + { + length = strlen((char *) string); + string += length; + while (size-- > 0) + { + value = 0; + for ( count = 0; (ok and (length > 0) and (count < BITS)); count += 4 ) + { + digit = (int) *(--string); length--; + /* separate because toupper() is likely a macro! */ + digit = toupper(digit); + if (digit == '_') + count -= 4; + else if ((ok = (isxdigit(digit) != 0))) + { + if (digit >= (int) 'A') digit -= (int) 'A' - 10; + else digit -= (int) '0'; + value |= (((N_word) digit) << count); + } + } + *addr++ = value; + } + *(--addr) &= mask; + } + if (ok) return(ErrCode_Ok); + else return(ErrCode_Pars); +} + +ErrCode BitVector_from_Oct(wordptr addr, charptr string) +{ + N_word size = size_(addr); + N_word mask = mask_(addr); + boolean ok = TRUE; + size_t length; + N_word value; + N_word value_fill = 0; + N_word count; + Z_word count_fill = 0; + int digit = 0; + + if (size > 0) + { + length = strlen((char *) string); + string += length; + while (size-- > 0) + { + value = value_fill; + for ( count = count_fill; (ok and (length > 0) and (count < BITS)); count += 3 ) + { + digit = (int) *(--string); length--; + if (digit == '_') + count -= 3; + else if ((ok = (isdigit(digit) && digit != '8' && digit != '9')) != 0) + { + digit -= (int) '0'; + value |= (((N_word) digit) << count); + } + } + count_fill = (Z_word)count-(Z_word)BITS; + if (count_fill > 0) + value_fill = (((N_word) digit) >> (3-count_fill)); + else + value_fill = 0; + *addr++ = value; + } + *(--addr) &= mask; + } + if (ok) return(ErrCode_Ok); + else return(ErrCode_Pars); +} + +charptr BitVector_to_Bin(wordptr addr) +{ + N_word size = size_(addr); + N_word value; + N_word count; + N_word digit; + N_word length; + charptr string; + + length = bits_(addr); + string = (charptr) yasm_xmalloc((size_t) (length+1)); + if (string == NULL) return(NULL); + string += length; + *string = (N_char) '\0'; + if (size > 0) + { + *(addr+size-1) &= mask_(addr); + while (size-- > 0) + { + value = *addr++; + count = BITS; + if (count > length) count = length; + while (count-- > 0) + { + digit = value AND 0x0001; + digit += (N_word) '0'; + *(--string) = (N_char) digit; length--; + if (count > 0) value >>= 1; + } + } + } + return(string); +} + +ErrCode BitVector_from_Bin(wordptr addr, charptr string) +{ + N_word size = size_(addr); + N_word mask = mask_(addr); + boolean ok = TRUE; + size_t length; + N_word value; + N_word count; + int digit; + + if (size > 0) + { + length = strlen((char *) string); + string += length; + while (size-- > 0) + { + value = 0; + for ( count = 0; (ok and (length > 0) and (count < BITS)); count++ ) + { + digit = (int) *(--string); length--; + switch (digit) + { + case (int) '0': + break; + case (int) '1': + value |= BITMASKTAB[count]; + break; + case (int) '_': + count--; + break; + default: + ok = FALSE; + break; + } + } + *addr++ = value; + } + *(--addr) &= mask; + } + if (ok) return(ErrCode_Ok); + else return(ErrCode_Pars); +} + +charptr BitVector_to_Dec(wordptr addr) +{ + N_word bits = bits_(addr); + N_word length; + N_word digits; + N_word count; + N_word q; + N_word r; + boolean loop; + charptr result; + charptr string; + wordptr quot; + wordptr rest; + wordptr temp; + wordptr base; + Z_int sign; + + length = (N_word) (bits / 3.3); /* digits = bits * ln(2) / ln(10) */ + length += 2; /* compensate for truncating & provide space for minus sign */ + result = (charptr) yasm_xmalloc((size_t) (length+1)); /* remember the '\0'! */ + if (result == NULL) return(NULL); + string = result; + sign = BitVector_Sign(addr); + if ((bits < 4) or (sign == 0)) + { + if (bits > 0) digits = *addr; else digits = (N_word) 0; + if (sign < 0) digits = ((N_word)(-((Z_word)digits))) AND mask_(addr); + *string++ = (N_char) digits + (N_char) '0'; + digits = 1; + } + else + { + quot = BitVector_Create(bits,FALSE); + if (quot == NULL) + { + BitVector_Dispose(result); + return(NULL); + } + rest = BitVector_Create(bits,FALSE); + if (rest == NULL) + { + BitVector_Dispose(result); + BitVector_Destroy(quot); + return(NULL); + } + temp = BitVector_Create(bits,FALSE); + if (temp == NULL) + { + BitVector_Dispose(result); + BitVector_Destroy(quot); + BitVector_Destroy(rest); + return(NULL); + } + base = BitVector_Create(bits,TRUE); + if (base == NULL) + { + BitVector_Dispose(result); + BitVector_Destroy(quot); + BitVector_Destroy(rest); + BitVector_Destroy(temp); + return(NULL); + } + if (sign < 0) BitVector_Negate(quot,addr); + else BitVector_Copy(quot,addr); + digits = 0; + *base = EXP10; + loop = (bits >= BITS); + do + { + if (loop) + { + BitVector_Copy(temp,quot); + if (BitVector_Div_Pos(quot,temp,base,rest)) + { + BitVector_Dispose(result); /* emergency exit */ + BitVector_Destroy(quot); + BitVector_Destroy(rest); /* should never occur */ + BitVector_Destroy(temp); /* under normal operation */ + BitVector_Destroy(base); + return(NULL); + } + loop = not BitVector_is_empty(quot); + q = *rest; + } + else q = *quot; + count = LOG10; + while (((loop and (count-- > 0)) or ((not loop) and (q != 0))) and + (digits < length)) + { + if (q != 0) + { + BIT_VECTOR_DIGITIZE(N_word,q,r) + } + else r = (N_word) '0'; + *string++ = (N_char) r; + digits++; + } + } + while (loop and (digits < length)); + BitVector_Destroy(quot); + BitVector_Destroy(rest); + BitVector_Destroy(temp); + BitVector_Destroy(base); + } + if ((sign < 0) and (digits < length)) + { + *string++ = (N_char) '-'; + digits++; + } + *string = (N_char) '\0'; + BIT_VECTOR_reverse(result,digits); + return(result); +} + +struct BitVector_from_Dec_static_data { + wordptr term; + wordptr base; + wordptr prod; + wordptr rank; + wordptr temp; +}; + +BitVector_from_Dec_static_data *BitVector_from_Dec_static_Boot(N_word bits) +{ + BitVector_from_Dec_static_data *data; + + data = yasm_xmalloc(sizeof(BitVector_from_Dec_static_data)); + + if (bits > 0) + { + data->term = BitVector_Create(BITS,FALSE); + data->base = BitVector_Create(BITS,FALSE); + data->prod = BitVector_Create(bits,FALSE); + data->rank = BitVector_Create(bits,FALSE); + data->temp = BitVector_Create(bits,FALSE); + } else { + data->term = NULL; + data->base = NULL; + data->prod = NULL; + data->rank = NULL; + data->temp = NULL; + } + return data; +} + +void BitVector_from_Dec_static_Shutdown(BitVector_from_Dec_static_data *data) +{ + if (data) { + BitVector_Destroy(data->term); + BitVector_Destroy(data->base); + BitVector_Destroy(data->prod); + BitVector_Destroy(data->rank); + BitVector_Destroy(data->temp); + } + yasm_xfree(data); +} + +ErrCode BitVector_from_Dec_static(BitVector_from_Dec_static_data *data, + wordptr addr, charptr string) +{ + ErrCode error = ErrCode_Ok; + N_word bits = bits_(addr); + N_word mask = mask_(addr); + boolean init = (bits > BITS); + boolean minus; + boolean shift; + boolean carry; + wordptr term; + wordptr base; + wordptr prod; + wordptr rank; + wordptr temp; + N_word accu; + N_word powr; + N_word count; + size_t length; + int digit; + + if (bits > 0) + { + term = data->term; + base = data->base; + prod = data->prod; + rank = data->rank; + temp = data->temp; + + length = strlen((char *) string); + if (length == 0) return(ErrCode_Pars); + digit = (int) *string; + if ((minus = (digit == (int) '-')) or + (digit == (int) '+')) + { + string++; + if (--length == 0) return(ErrCode_Pars); + } + string += length; + if (init) + { + BitVector_Empty(prod); + BitVector_Empty(rank); + } + BitVector_Empty(addr); + *base = EXP10; + shift = FALSE; + while ((not error) and (length > 0)) + { + accu = 0; + powr = 1; + count = LOG10; + while ((not error) and (length > 0) and (count-- > 0)) + { + digit = (int) *(--string); length--; + /* separate because isdigit() is likely a macro! */ + if (isdigit(digit) != 0) + { + accu += ((N_word) digit - (N_word) '0') * powr; + powr *= 10; + } + else error = ErrCode_Pars; + } + if (not error) + { + if (shift) + { + *term = accu; + BitVector_Copy(temp,rank); + error = BitVector_Mul_Pos(prod,temp,term,FALSE); + } + else + { + *prod = accu; + if ((not init) and ((accu AND NOT mask) != 0)) error = ErrCode_Ovfl; + } + if (not error) + { + carry = FALSE; + BitVector_compute(addr,addr,prod,FALSE,&carry); + /* ignores sign change (= overflow) but not */ + /* numbers too large (= carry) for resulting bit vector */ + if (carry) error = ErrCode_Ovfl; + else + { + if (length > 0) + { + if (shift) + { + BitVector_Copy(temp,rank); + error = BitVector_Mul_Pos(rank,temp,base,FALSE); + } + else + { + *rank = *base; + shift = TRUE; + } + } + } + } + } + } + if (not error and minus) + { + BitVector_Negate(addr,addr); + if ((*(addr + size_(addr) - 1) AND mask AND NOT (mask >> 1)) == 0) + error = ErrCode_Ovfl; + } + } + return(error); +} + +ErrCode BitVector_from_Dec(wordptr addr, charptr string) +{ + ErrCode error = ErrCode_Ok; + N_word bits = bits_(addr); + N_word mask = mask_(addr); + boolean init = (bits > BITS); + boolean minus; + boolean shift; + boolean carry; + wordptr term; + wordptr base; + wordptr prod; + wordptr rank; + wordptr temp; + N_word accu; + N_word powr; + N_word count; + size_t length; + int digit; + + if (bits > 0) + { + length = strlen((char *) string); + if (length == 0) return(ErrCode_Pars); + digit = (int) *string; + if ((minus = (digit == (int) '-')) or + (digit == (int) '+')) + { + string++; + if (--length == 0) return(ErrCode_Pars); + } + string += length; + term = BitVector_Create(BITS,FALSE); + if (term == NULL) + { + return(ErrCode_Null); + } + base = BitVector_Create(BITS,FALSE); + if (base == NULL) + { + BitVector_Destroy(term); + return(ErrCode_Null); + } + prod = BitVector_Create(bits,init); + if (prod == NULL) + { + BitVector_Destroy(term); + BitVector_Destroy(base); + return(ErrCode_Null); + } + rank = BitVector_Create(bits,init); + if (rank == NULL) + { + BitVector_Destroy(term); + BitVector_Destroy(base); + BitVector_Destroy(prod); + return(ErrCode_Null); + } + temp = BitVector_Create(bits,FALSE); + if (temp == NULL) + { + BitVector_Destroy(term); + BitVector_Destroy(base); + BitVector_Destroy(prod); + BitVector_Destroy(rank); + return(ErrCode_Null); + } + BitVector_Empty(addr); + *base = EXP10; + shift = FALSE; + while ((not error) and (length > 0)) + { + accu = 0; + powr = 1; + count = LOG10; + while ((not error) and (length > 0) and (count-- > 0)) + { + digit = (int) *(--string); length--; + /* separate because isdigit() is likely a macro! */ + if (isdigit(digit) != 0) + { + accu += ((N_word) digit - (N_word) '0') * powr; + powr *= 10; + } + else error = ErrCode_Pars; + } + if (not error) + { + if (shift) + { + *term = accu; + BitVector_Copy(temp,rank); + error = BitVector_Mul_Pos(prod,temp,term,FALSE); + } + else + { + *prod = accu; + if ((not init) and ((accu AND NOT mask) != 0)) error = ErrCode_Ovfl; + } + if (not error) + { + carry = FALSE; + BitVector_compute(addr,addr,prod,FALSE,&carry); + /* ignores sign change (= overflow) but not */ + /* numbers too large (= carry) for resulting bit vector */ + if (carry) error = ErrCode_Ovfl; + else + { + if (length > 0) + { + if (shift) + { + BitVector_Copy(temp,rank); + error = BitVector_Mul_Pos(rank,temp,base,FALSE); + } + else + { + *rank = *base; + shift = TRUE; + } + } + } + } + } + } + BitVector_Destroy(term); + BitVector_Destroy(base); + BitVector_Destroy(prod); + BitVector_Destroy(rank); + BitVector_Destroy(temp); + if (not error and minus) + { + BitVector_Negate(addr,addr); + if ((*(addr + size_(addr) - 1) AND mask AND NOT (mask >> 1)) == 0) + error = ErrCode_Ovfl; + } + } + return(error); +} + +charptr BitVector_to_Enum(wordptr addr) +{ + N_word bits = bits_(addr); + N_word sample; + N_word length; + N_word digits; + N_word factor; + N_word power; + N_word start; + N_word min; + N_word max; + charptr string; + charptr target; + boolean comma; + + if (bits > 0) + { + sample = bits - 1; /* greatest possible index */ + length = 2; /* account for index 0 and terminating '\0' */ + digits = 1; /* account for intervening dashes and commas */ + factor = 1; + power = 10; + while (sample >= (power-1)) + { + length += ++digits * factor * 6; /* 9,90,900,9000,... (9*2/3 = 6) */ + factor = power; + power *= 10; + } + if (sample > --factor) + { + sample -= factor; + factor = (N_word) ( sample / 3 ); + factor = (factor << 1) + (sample - (factor * 3)); + length += ++digits * factor; + } + } + else length = 1; + string = (charptr) yasm_xmalloc((size_t) length); + if (string == NULL) return(NULL); + start = 0; + comma = FALSE; + target = string; + while ((start < bits) and BitVector_interval_scan_inc(addr,start,&min,&max)) + { + start = max + 2; + if (comma) *target++ = (N_char) ','; + if (min == max) + { + target += BIT_VECTOR_int2str(target,min); + } + else + { + if (min+1 == max) + { + target += BIT_VECTOR_int2str(target,min); + *target++ = (N_char) ','; + target += BIT_VECTOR_int2str(target,max); + } + else + { + target += BIT_VECTOR_int2str(target,min); + *target++ = (N_char) '-'; + target += BIT_VECTOR_int2str(target,max); + } + } + comma = TRUE; + } + *target = (N_char) '\0'; + return(string); +} + +ErrCode BitVector_from_Enum(wordptr addr, charptr string) +{ + ErrCode error = ErrCode_Ok; + N_word bits = bits_(addr); + N_word state = 1; + N_word token; + N_word indx = 0; /* silence compiler warning */ + N_word start = 0; /* silence compiler warning */ + + if (bits > 0) + { + BitVector_Empty(addr); + while ((not error) and (state != 0)) + { + token = (N_word) *string; + /* separate because isdigit() is likely a macro! */ + if (isdigit((int)token) != 0) + { + string += BIT_VECTOR_str2int(string,&indx); + if (indx < bits) token = (N_word) '0'; + else error = ErrCode_Indx; + } + else string++; + if (not error) + switch (state) + { + case 1: + switch (token) + { + case (N_word) '0': + state = 2; + break; + case (N_word) '\0': + state = 0; + break; + default: + error = ErrCode_Pars; + break; + } + break; + case 2: + switch (token) + { + case (N_word) '-': + start = indx; + state = 3; + break; + case (N_word) ',': + BIT_VECTOR_SET_BIT(addr,indx) + state = 5; + break; + case (N_word) '\0': + BIT_VECTOR_SET_BIT(addr,indx) + state = 0; + break; + default: + error = ErrCode_Pars; + break; + } + break; + case 3: + switch (token) + { + case (N_word) '0': + if (start < indx) + BitVector_Interval_Fill(addr,start,indx); + else if (start == indx) + BIT_VECTOR_SET_BIT(addr,indx) + else error = ErrCode_Ordr; + state = 4; + break; + default: + error = ErrCode_Pars; + break; + } + break; + case 4: + switch (token) + { + case (N_word) ',': + state = 5; + break; + case (N_word) '\0': + state = 0; + break; + default: + error = ErrCode_Pars; + break; + } + break; + case 5: + switch (token) + { + case (N_word) '0': + state = 2; + break; + default: + error = ErrCode_Pars; + break; + } + break; + } + } + } + return(error); +} + +void BitVector_Bit_Off(wordptr addr, N_int indx) /* X = X \ {x} */ +{ + if (indx < bits_(addr)) BIT_VECTOR_CLR_BIT(addr,indx) +} + +void BitVector_Bit_On(wordptr addr, N_int indx) /* X = X + {x} */ +{ + if (indx < bits_(addr)) BIT_VECTOR_SET_BIT(addr,indx) +} + +boolean BitVector_bit_flip(wordptr addr, N_int indx) /* X=(X+{x})\(X*{x}) */ +{ + N_word mask; + + if (indx < bits_(addr)) return( BIT_VECTOR_FLP_BIT(addr,indx,mask) ); + else return( FALSE ); +} + +boolean BitVector_bit_test(wordptr addr, N_int indx) /* {x} in X ? */ +{ + if (indx < bits_(addr)) return( BIT_VECTOR_TST_BIT(addr,indx) ); + else return( FALSE ); +} + +void BitVector_Bit_Copy(wordptr addr, N_int indx, boolean bit) +{ + if (indx < bits_(addr)) + { + if (bit) BIT_VECTOR_SET_BIT(addr,indx) + else BIT_VECTOR_CLR_BIT(addr,indx) + } +} + +void BitVector_LSB(wordptr addr, boolean bit) +{ + if (bits_(addr) > 0) + { + if (bit) *addr |= LSB; + else *addr &= NOT LSB; + } +} + +void BitVector_MSB(wordptr addr, boolean bit) +{ + N_word size = size_(addr); + N_word mask = mask_(addr); + + if (size-- > 0) + { + if (bit) *(addr+size) |= mask AND NOT (mask >> 1); + else *(addr+size) &= NOT mask OR (mask >> 1); + } +} + +boolean BitVector_lsb_(wordptr addr) +{ + if (size_(addr) > 0) return( (*addr AND LSB) != 0 ); + else return( FALSE ); +} + +boolean BitVector_msb_(wordptr addr) +{ + N_word size = size_(addr); + N_word mask = mask_(addr); + + if (size-- > 0) + return( (*(addr+size) AND (mask AND NOT (mask >> 1))) != 0 ); + else + return( FALSE ); +} + +boolean BitVector_rotate_left(wordptr addr) +{ + N_word size = size_(addr); + N_word mask = mask_(addr); + N_word msb; + boolean carry_in; + boolean carry_out = FALSE; + + if (size > 0) + { + msb = mask AND NOT (mask >> 1); + carry_in = ((*(addr+size-1) AND msb) != 0); + while (size-- > 1) + { + carry_out = ((*addr AND MSB) != 0); + *addr <<= 1; + if (carry_in) *addr |= LSB; + carry_in = carry_out; + addr++; + } + carry_out = ((*addr AND msb) != 0); + *addr <<= 1; + if (carry_in) *addr |= LSB; + *addr &= mask; + } + return(carry_out); +} + +boolean BitVector_rotate_right(wordptr addr) +{ + N_word size = size_(addr); + N_word mask = mask_(addr); + N_word msb; + boolean carry_in; + boolean carry_out = FALSE; + + if (size > 0) + { + msb = mask AND NOT (mask >> 1); + carry_in = ((*addr AND LSB) != 0); + addr += size-1; + *addr &= mask; + carry_out = ((*addr AND LSB) != 0); + *addr >>= 1; + if (carry_in) *addr |= msb; + carry_in = carry_out; + addr--; + size--; + while (size-- > 0) + { + carry_out = ((*addr AND LSB) != 0); + *addr >>= 1; + if (carry_in) *addr |= MSB; + carry_in = carry_out; + addr--; + } + } + return(carry_out); +} + +boolean BitVector_shift_left(wordptr addr, boolean carry_in) +{ + N_word size = size_(addr); + N_word mask = mask_(addr); + N_word msb; + boolean carry_out = carry_in; + + if (size > 0) + { + msb = mask AND NOT (mask >> 1); + while (size-- > 1) + { + carry_out = ((*addr AND MSB) != 0); + *addr <<= 1; + if (carry_in) *addr |= LSB; + carry_in = carry_out; + addr++; + } + carry_out = ((*addr AND msb) != 0); + *addr <<= 1; + if (carry_in) *addr |= LSB; + *addr &= mask; + } + return(carry_out); +} + +boolean BitVector_shift_right(wordptr addr, boolean carry_in) +{ + N_word size = size_(addr); + N_word mask = mask_(addr); + N_word msb; + boolean carry_out = carry_in; + + if (size > 0) + { + msb = mask AND NOT (mask >> 1); + addr += size-1; + *addr &= mask; + carry_out = ((*addr AND LSB) != 0); + *addr >>= 1; + if (carry_in) *addr |= msb; + carry_in = carry_out; + addr--; + size--; + while (size-- > 0) + { + carry_out = ((*addr AND LSB) != 0); + *addr >>= 1; + if (carry_in) *addr |= MSB; + carry_in = carry_out; + addr--; + } + } + return(carry_out); +} + +void BitVector_Move_Left(wordptr addr, N_int bits) +{ + N_word count; + N_word words; + + if (bits > 0) + { + count = bits AND MODMASK; + words = bits >> LOGBITS; + if (bits >= bits_(addr)) BitVector_Empty(addr); + else + { + while (count-- > 0) BitVector_shift_left(addr,0); + BitVector_Word_Insert(addr,0,words,TRUE); + } + } +} + +void BitVector_Move_Right(wordptr addr, N_int bits) +{ + N_word count; + N_word words; + + if (bits > 0) + { + count = bits AND MODMASK; + words = bits >> LOGBITS; + if (bits >= bits_(addr)) BitVector_Empty(addr); + else + { + while (count-- > 0) BitVector_shift_right(addr,0); + BitVector_Word_Delete(addr,0,words,TRUE); + } + } +} + +void BitVector_Insert(wordptr addr, N_int offset, N_int count, boolean clear) +{ + N_word bits = bits_(addr); + N_word last; + + if ((count > 0) and (offset < bits)) + { + last = offset + count; + if (last < bits) + { + BitVector_Interval_Copy(addr,addr,last,offset,(bits-last)); + } + else last = bits; + if (clear) BitVector_Interval_Empty(addr,offset,(last-1)); + } +} + +void BitVector_Delete(wordptr addr, N_int offset, N_int count, boolean clear) +{ + N_word bits = bits_(addr); + N_word last; + + if ((count > 0) and (offset < bits)) + { + last = offset + count; + if (last < bits) + { + BitVector_Interval_Copy(addr,addr,offset,last,(bits-last)); + } + else count = bits - offset; + if (clear) BitVector_Interval_Empty(addr,(bits-count),(bits-1)); + } +} + +boolean BitVector_increment(wordptr addr) /* X++ */ +{ + N_word size = size_(addr); + N_word mask = mask_(addr); + wordptr last = addr + size - 1; + boolean carry = TRUE; + + if (size > 0) + { + *last |= NOT mask; + while (carry and (size-- > 0)) + { + carry = (++(*addr++) == 0); + } + *last &= mask; + } + return(carry); +} + +boolean BitVector_decrement(wordptr addr) /* X-- */ +{ + N_word size = size_(addr); + N_word mask = mask_(addr); + wordptr last = addr + size - 1; + boolean carry = TRUE; + + if (size > 0) + { + *last &= mask; + while (carry and (size-- > 0)) + { + carry = (*addr == 0); + --(*addr++); + } + *last &= mask; + } + return(carry); +} + +boolean BitVector_compute(wordptr X, wordptr Y, wordptr Z, boolean minus, boolean *carry) +{ + N_word size = size_(X); + N_word mask = mask_(X); + N_word vv = 0; + N_word cc; + N_word mm; + N_word yy; + N_word zz; + N_word lo; + N_word hi; + + if (size > 0) + { + if (minus) cc = (*carry == 0); + else cc = (*carry != 0); + /* deal with (size-1) least significant full words first: */ + while (--size > 0) + { + yy = *Y++; + if (minus) zz = (N_word) NOT ( Z ? *Z++ : 0 ); + else zz = (N_word) ( Z ? *Z++ : 0 ); + lo = (yy AND LSB) + (zz AND LSB) + cc; + hi = (yy >> 1) + (zz >> 1) + (lo >> 1); + cc = ((hi AND MSB) != 0); + *X++ = (hi << 1) OR (lo AND LSB); + } + /* deal with most significant word (may be used only partially): */ + yy = *Y AND mask; + if (minus) zz = (N_word) NOT ( Z ? *Z : 0 ); + else zz = (N_word) ( Z ? *Z : 0 ); + zz &= mask; + if (mask == LSB) /* special case, only one bit used */ + { + vv = cc; + lo = yy + zz + cc; + cc = (lo >> 1); + vv ^= cc; + *X = lo AND LSB; + } + else + { + if (NOT mask) /* not all bits are used, but more than one */ + { + mm = (mask >> 1); + vv = (yy AND mm) + (zz AND mm) + cc; + mm = mask AND NOT mm; + lo = yy + zz + cc; + cc = (lo >> 1); + vv ^= cc; + vv &= mm; + cc &= mm; + *X = lo AND mask; + } + else /* other special case, all bits are used */ + { + mm = NOT MSB; + lo = (yy AND mm) + (zz AND mm) + cc; + vv = lo AND MSB; + hi = ((yy AND MSB) >> 1) + ((zz AND MSB) >> 1) + (vv >> 1); + cc = hi AND MSB; + vv ^= cc; + *X = (hi << 1) OR (lo AND mm); + } + } + if (minus) *carry = (cc == 0); + else *carry = (cc != 0); + } + return(vv != 0); +} + +boolean BitVector_add(wordptr X, wordptr Y, wordptr Z, boolean *carry) +{ + return(BitVector_compute(X,Y,Z,FALSE,carry)); +} + +boolean BitVector_sub(wordptr X, wordptr Y, wordptr Z, boolean *carry) +{ + return(BitVector_compute(X,Y,Z,TRUE,carry)); +} + +boolean BitVector_inc(wordptr X, wordptr Y) +{ + boolean carry = TRUE; + + return(BitVector_compute(X,Y,NULL,FALSE,&carry)); +} + +boolean BitVector_dec(wordptr X, wordptr Y) +{ + boolean carry = TRUE; + + return(BitVector_compute(X,Y,NULL,TRUE,&carry)); +} + +void BitVector_Negate(wordptr X, wordptr Y) +{ + N_word size = size_(X); + N_word mask = mask_(X); + boolean carry = TRUE; + + if (size > 0) + { + while (size-- > 0) + { + *X = NOT *Y++; + if (carry) + { + carry = (++(*X) == 0); + } + X++; + } + *(--X) &= mask; + } +} + +void BitVector_Absolute(wordptr X, wordptr Y) +{ + N_word size = size_(Y); + N_word mask = mask_(Y); + + if (size > 0) + { + if (*(Y+size-1) AND (mask AND NOT (mask >> 1))) BitVector_Negate(X,Y); + else BitVector_Copy(X,Y); + } +} + +Z_int BitVector_Sign(wordptr addr) +{ + N_word size = size_(addr); + N_word mask = mask_(addr); + wordptr last = addr + size - 1; + boolean r = TRUE; + + if (size > 0) + { + *last &= mask; + while (r and (size-- > 0)) r = ( *addr++ == 0 ); + } + if (r) return((Z_int) 0); + else + { + if (*last AND (mask AND NOT (mask >> 1))) return((Z_int) -1); + else return((Z_int) 1); + } +} + +ErrCode BitVector_Mul_Pos(wordptr X, wordptr Y, wordptr Z, boolean strict) +{ + N_word mask; + N_word limit; + N_word count; + Z_long last; + wordptr sign; + boolean carry; + boolean overflow; + boolean ok = TRUE; + + /* + Requirements: + - X, Y and Z must be distinct + - X and Y must have equal sizes (whereas Z may be any size!) + - Z should always contain the SMALLER of the two factors Y and Z + Constraints: + - The contents of Y (and of X, of course) are destroyed + (only Z is preserved!) + */ + + if ((X == Y) or (X == Z) or (Y == Z)) return(ErrCode_Same); + if (bits_(X) != bits_(Y)) return(ErrCode_Size); + BitVector_Empty(X); + if (BitVector_is_empty(Y)) return(ErrCode_Ok); /* exit also taken if bits_(Y)==0 */ + if ((last = Set_Max(Z)) < 0L) return(ErrCode_Ok); + limit = (N_word) last; + sign = Y + size_(Y) - 1; + mask = mask_(Y); + *sign &= mask; + mask &= NOT (mask >> 1); + for ( count = 0; (ok and (count <= limit)); count++ ) + { + if ( BIT_VECTOR_TST_BIT(Z,count) ) + { + carry = false; + overflow = BitVector_compute(X,X,Y,false,&carry); + if (strict) ok = not (carry or overflow); + else ok = not carry; + } + if (ok and (count < limit)) + { + carry = BitVector_shift_left(Y,0); + if (strict) + { + overflow = ((*sign AND mask) != 0); + ok = not (carry or overflow); + } + else ok = not carry; + } + } + if (ok) return(ErrCode_Ok); else return(ErrCode_Ovfl); +} + +ErrCode BitVector_Multiply(wordptr X, wordptr Y, wordptr Z) +{ + ErrCode error = ErrCode_Ok; + N_word bit_x = bits_(X); + N_word bit_y = bits_(Y); + N_word bit_z = bits_(Z); + N_word size; + N_word mask; + N_word msb; + wordptr ptr_y; + wordptr ptr_z; + boolean sgn_x; + boolean sgn_y; + boolean sgn_z; + boolean zero; + wordptr A; + wordptr B; + + /* + Requirements: + - Y and Z must have equal sizes + - X must have at least the same size as Y and Z but may be larger (!) + Features: + - The contents of Y and Z are preserved + - X may be identical with Y or Z (or both!) + (in-place multiplication is possible!) + */ + + if ((bit_y != bit_z) or (bit_x < bit_y)) return(ErrCode_Size); + if (BitVector_is_empty(Y) or BitVector_is_empty(Z)) + { + BitVector_Empty(X); + } + else + { + A = BitVector_Create(bit_y,FALSE); + if (A == NULL) return(ErrCode_Null); + B = BitVector_Create(bit_z,FALSE); + if (B == NULL) { BitVector_Destroy(A); return(ErrCode_Null); } + size = size_(Y); + mask = mask_(Y); + msb = (mask AND NOT (mask >> 1)); + sgn_y = (((*(Y+size-1) &= mask) AND msb) != 0); + sgn_z = (((*(Z+size-1) &= mask) AND msb) != 0); + sgn_x = sgn_y XOR sgn_z; + if (sgn_y) BitVector_Negate(A,Y); else BitVector_Copy(A,Y); + if (sgn_z) BitVector_Negate(B,Z); else BitVector_Copy(B,Z); + ptr_y = A + size; + ptr_z = B + size; + zero = TRUE; + while (zero and (size-- > 0)) + { + zero &= (*(--ptr_y) == 0); + zero &= (*(--ptr_z) == 0); + } + if (*ptr_y > *ptr_z) + { + if (bit_x > bit_y) + { + A = BitVector_Resize(A,bit_x); + if (A == NULL) { BitVector_Destroy(B); return(ErrCode_Null); } + } + error = BitVector_Mul_Pos(X,A,B,TRUE); + } + else + { + if (bit_x > bit_z) + { + B = BitVector_Resize(B,bit_x); + if (B == NULL) { BitVector_Destroy(A); return(ErrCode_Null); } + } + error = BitVector_Mul_Pos(X,B,A,TRUE); + } + if ((not error) and sgn_x) BitVector_Negate(X,X); + BitVector_Destroy(A); + BitVector_Destroy(B); + } + return(error); +} + +ErrCode BitVector_Div_Pos(wordptr Q, wordptr X, wordptr Y, wordptr R) +{ + N_word bits = bits_(Q); + N_word mask; + wordptr addr; + Z_long last; + boolean flag; + boolean copy = FALSE; /* flags whether valid rest is in R (0) or X (1) */ + + /* + Requirements: + - All bit vectors must have equal sizes + - Q, X, Y and R must all be distinct bit vectors + - Y must be non-zero (of course!) + Constraints: + - The contents of X (and Q and R, of course) are destroyed + (only Y is preserved!) + */ + + if ((bits != bits_(X)) or (bits != bits_(Y)) or (bits != bits_(R))) + return(ErrCode_Size); + if ((Q == X) or (Q == Y) or (Q == R) or (X == Y) or (X == R) or (Y == R)) + return(ErrCode_Same); + if (BitVector_is_empty(Y)) + return(ErrCode_Zero); + + BitVector_Empty(R); + BitVector_Copy(Q,X); + if ((last = Set_Max(Q)) < 0L) return(ErrCode_Ok); + bits = (N_word) ++last; + while (bits-- > 0) + { + addr = Q + (bits >> LOGBITS); + mask = BITMASKTAB[bits AND MODMASK]; + flag = ((*addr AND mask) != 0); + if (copy) + { + BitVector_shift_left(X,flag); + flag = FALSE; + BitVector_compute(R,X,Y,TRUE,&flag); + } + else + { + BitVector_shift_left(R,flag); + flag = FALSE; + BitVector_compute(X,R,Y,TRUE,&flag); + } + if (flag) *addr &= NOT mask; + else + { + *addr |= mask; + copy = not copy; + } + } + if (copy) BitVector_Copy(R,X); + return(ErrCode_Ok); +} + +ErrCode BitVector_Divide(wordptr Q, wordptr X, wordptr Y, wordptr R) +{ + ErrCode error = ErrCode_Ok; + N_word bits = bits_(Q); + N_word size = size_(Q); + N_word mask = mask_(Q); + N_word msb = (mask AND NOT (mask >> 1)); + boolean sgn_q; + boolean sgn_x; + boolean sgn_y; + wordptr A; + wordptr B; + + /* + Requirements: + - All bit vectors must have equal sizes + - Q and R must be two distinct bit vectors + - Y must be non-zero (of course!) + Features: + - The contents of X and Y are preserved + - Q may be identical with X or Y (or both) + (in-place division is possible!) + - R may be identical with X or Y (or both) + (but not identical with Q!) + */ + + if ((bits != bits_(X)) or (bits != bits_(Y)) or (bits != bits_(R))) + return(ErrCode_Size); + if (Q == R) + return(ErrCode_Same); + if (BitVector_is_empty(Y)) + return(ErrCode_Zero); + + if (BitVector_is_empty(X)) + { + BitVector_Empty(Q); + BitVector_Empty(R); + } + else + { + A = BitVector_Create(bits,FALSE); + if (A == NULL) return(ErrCode_Null); + B = BitVector_Create(bits,FALSE); + if (B == NULL) { BitVector_Destroy(A); return(ErrCode_Null); } + size--; + sgn_x = (((*(X+size) &= mask) AND msb) != 0); + sgn_y = (((*(Y+size) &= mask) AND msb) != 0); + sgn_q = sgn_x XOR sgn_y; + if (sgn_x) BitVector_Negate(A,X); else BitVector_Copy(A,X); + if (sgn_y) BitVector_Negate(B,Y); else BitVector_Copy(B,Y); + if (not (error = BitVector_Div_Pos(Q,A,B,R))) + { + if (sgn_q) BitVector_Negate(Q,Q); + if (sgn_x) BitVector_Negate(R,R); + } + BitVector_Destroy(A); + BitVector_Destroy(B); + } + return(error); +} + +ErrCode BitVector_GCD(wordptr X, wordptr Y, wordptr Z) +{ + ErrCode error = ErrCode_Ok; + N_word bits = bits_(X); + N_word size = size_(X); + N_word mask = mask_(X); + N_word msb = (mask AND NOT (mask >> 1)); + boolean sgn_a; + boolean sgn_b; + boolean sgn_r; + wordptr Q; + wordptr R; + wordptr A; + wordptr B; + wordptr T; + + /* + Requirements: + - All bit vectors must have equal sizes + Features: + - The contents of Y and Z are preserved + - X may be identical with Y or Z (or both) + (in-place is possible!) + - GCD(0,z) == GCD(z,0) == z + - negative values are handled correctly + */ + + if ((bits != bits_(Y)) or (bits != bits_(Z))) return(ErrCode_Size); + if (BitVector_is_empty(Y)) + { + if (X != Z) BitVector_Copy(X,Z); + return(ErrCode_Ok); + } + if (BitVector_is_empty(Z)) + { + if (X != Y) BitVector_Copy(X,Y); + return(ErrCode_Ok); + } + Q = BitVector_Create(bits,false); + if (Q == NULL) + { + return(ErrCode_Null); + } + R = BitVector_Create(bits,FALSE); + if (R == NULL) + { + BitVector_Destroy(Q); + return(ErrCode_Null); + } + A = BitVector_Create(bits,FALSE); + if (A == NULL) + { + BitVector_Destroy(Q); + BitVector_Destroy(R); + return(ErrCode_Null); + } + B = BitVector_Create(bits,FALSE); + if (B == NULL) + { + BitVector_Destroy(Q); + BitVector_Destroy(R); + BitVector_Destroy(A); + return(ErrCode_Null); + } + size--; + sgn_a = (((*(Y+size) &= mask) AND msb) != 0); + sgn_b = (((*(Z+size) &= mask) AND msb) != 0); + if (sgn_a) BitVector_Negate(A,Y); else BitVector_Copy(A,Y); + if (sgn_b) BitVector_Negate(B,Z); else BitVector_Copy(B,Z); + while (not error) + { + if (not (error = BitVector_Div_Pos(Q,A,B,R))) + { + if (BitVector_is_empty(R)) break; + T = A; sgn_r = sgn_a; + A = B; sgn_a = sgn_b; + B = R; sgn_b = sgn_r; + R = T; + } + } + if (not error) + { + if (sgn_b) BitVector_Negate(X,B); else BitVector_Copy(X,B); + } + BitVector_Destroy(Q); + BitVector_Destroy(R); + BitVector_Destroy(A); + BitVector_Destroy(B); + return(error); +} + +ErrCode BitVector_GCD2(wordptr U, wordptr V, wordptr W, wordptr X, wordptr Y) +{ + ErrCode error = ErrCode_Ok; + N_word bits = bits_(U); + N_word size = size_(U); + N_word mask = mask_(U); + N_word msb = (mask AND NOT (mask >> 1)); + boolean minus; + boolean carry; + boolean sgn_q; + boolean sgn_r; + boolean sgn_a; + boolean sgn_b; + boolean sgn_x; + boolean sgn_y; + listptr L; + wordptr Q; + wordptr R; + wordptr A; + wordptr B; + wordptr T; + wordptr X1; + wordptr X2; + wordptr X3; + wordptr Y1; + wordptr Y2; + wordptr Y3; + wordptr Z; + + /* + Requirements: + - All bit vectors must have equal sizes + - U, V, and W must all be distinct bit vectors + Features: + - The contents of X and Y are preserved + - U, V and W may be identical with X or Y (or both, + provided that U, V and W are mutually distinct) + (i.e., in-place is possible!) + - GCD(0,z) == GCD(z,0) == z + - negative values are handled correctly + */ + + if ((bits != bits_(V)) or + (bits != bits_(W)) or + (bits != bits_(X)) or + (bits != bits_(Y))) + { + return(ErrCode_Size); + } + if ((U == V) or (U == W) or (V == W)) + { + return(ErrCode_Same); + } + if (BitVector_is_empty(X)) + { + if (U != Y) BitVector_Copy(U,Y); + BitVector_Empty(V); + BitVector_Empty(W); + *W = 1; + return(ErrCode_Ok); + } + if (BitVector_is_empty(Y)) + { + if (U != X) BitVector_Copy(U,X); + BitVector_Empty(V); + BitVector_Empty(W); + *V = 1; + return(ErrCode_Ok); + } + if ((L = BitVector_Create_List(bits,false,11)) == NULL) + { + return(ErrCode_Null); + } + Q = L[0]; + R = L[1]; + A = L[2]; + B = L[3]; + X1 = L[4]; + X2 = L[5]; + X3 = L[6]; + Y1 = L[7]; + Y2 = L[8]; + Y3 = L[9]; + Z = L[10]; + size--; + sgn_a = (((*(X+size) &= mask) AND msb) != 0); + sgn_b = (((*(Y+size) &= mask) AND msb) != 0); + if (sgn_a) BitVector_Negate(A,X); else BitVector_Copy(A,X); + if (sgn_b) BitVector_Negate(B,Y); else BitVector_Copy(B,Y); + BitVector_Empty(X1); + BitVector_Empty(X2); + *X1 = 1; + BitVector_Empty(Y1); + BitVector_Empty(Y2); + *Y2 = 1; + sgn_x = false; + sgn_y = false; + while (not error) + { + if ((error = BitVector_Div_Pos(Q,A,B,R))) + { + break; + } + if (BitVector_is_empty(R)) + { + break; + } + sgn_q = sgn_a XOR sgn_b; + + if (sgn_x) BitVector_Negate(Z,X2); else BitVector_Copy(Z,X2); + if ((error = BitVector_Mul_Pos(X3,Z,Q,true))) + { + break; + } + minus = not (sgn_x XOR sgn_q); + carry = 0; + if (BitVector_compute(X3,X1,X3,minus,&carry)) + { + error = ErrCode_Ovfl; + break; + } + sgn_x = (((*(X3+size) &= mask) AND msb) != 0); + + if (sgn_y) BitVector_Negate(Z,Y2); else BitVector_Copy(Z,Y2); + if ((error = BitVector_Mul_Pos(Y3,Z,Q,true))) + { + break; + } + minus = not (sgn_y XOR sgn_q); + carry = 0; + if (BitVector_compute(Y3,Y1,Y3,minus,&carry)) + { + error = ErrCode_Ovfl; + break; + } + sgn_y = (((*(Y3+size) &= mask) AND msb) != 0); + + T = A; sgn_r = sgn_a; + A = B; sgn_a = sgn_b; + B = R; sgn_b = sgn_r; + R = T; + + T = X1; + X1 = X2; + X2 = X3; + X3 = T; + + T = Y1; + Y1 = Y2; + Y2 = Y3; + Y3 = T; + } + if (not error) + { + if (sgn_b) BitVector_Negate(U,B); else BitVector_Copy(U,B); + BitVector_Copy(V,X2); + BitVector_Copy(W,Y2); + } + BitVector_Destroy_List(L,11); + return(error); +} + +ErrCode BitVector_Power(wordptr X, wordptr Y, wordptr Z) +{ + ErrCode error = ErrCode_Ok; + N_word bits = bits_(X); + boolean first = TRUE; + Z_long last; + N_word limit; + N_word count; + wordptr T; + + /* + Requirements: + - X must have at least the same size as Y but may be larger (!) + - X may not be identical with Z + - Z must be positive + Features: + - The contents of Y and Z are preserved + */ + + if (X == Z) return(ErrCode_Same); + if (bits < bits_(Y)) return(ErrCode_Size); + if (BitVector_msb_(Z)) return(ErrCode_Expo); + if ((last = Set_Max(Z)) < 0L) + { + if (bits < 2) return(ErrCode_Ovfl); + BitVector_Empty(X); + *X |= LSB; + return(ErrCode_Ok); /* anything ^ 0 == 1 */ + } + if (BitVector_is_empty(Y)) + { + if (X != Y) BitVector_Empty(X); + return(ErrCode_Ok); /* 0 ^ anything not zero == 0 */ + } + T = BitVector_Create(bits,FALSE); + if (T == NULL) return(ErrCode_Null); + limit = (N_word) last; + for ( count = 0; ((!error) and (count <= limit)); count++ ) + { + if ( BIT_VECTOR_TST_BIT(Z,count) ) + { + if (first) + { + first = FALSE; + if (count) { BitVector_Copy(X,T); } + else { if (X != Y) BitVector_Copy(X,Y); } + } + else error = BitVector_Multiply(X,T,X); /* order important because T > X */ + } + if ((!error) and (count < limit)) + { + if (count) error = BitVector_Multiply(T,T,T); + else error = BitVector_Multiply(T,Y,Y); + } + } + BitVector_Destroy(T); + return(error); +} + +void BitVector_Block_Store(wordptr addr, charptr buffer, N_int length) +{ + N_word size = size_(addr); + N_word mask = mask_(addr); + N_word value; + N_word count; + + /* provide translation for independence of endian-ness: */ + if (size > 0) + { + while (size-- > 0) + { + value = 0; + for ( count = 0; (length > 0) and (count < BITS); count += 8 ) + { + value |= (((N_word) *buffer++) << count); length--; + } + *addr++ = value; + } + *(--addr) &= mask; + } +} + +charptr BitVector_Block_Read(wordptr addr, N_intptr length) +{ + N_word size = size_(addr); + N_word value; + N_word count; + charptr buffer; + charptr target; + + /* provide translation for independence of endian-ness: */ + *length = size << FACTOR; + buffer = (charptr) yasm_xmalloc((size_t) ((*length)+1)); + if (buffer == NULL) return(NULL); + target = buffer; + if (size > 0) + { + *(addr+size-1) &= mask_(addr); + while (size-- > 0) + { + value = *addr++; + count = BITS >> 3; + while (count-- > 0) + { + *target++ = (N_char) (value AND 0x00FF); + if (count > 0) value >>= 8; + } + } + } + *target = (N_char) '\0'; + return(buffer); +} + +void BitVector_Word_Store(wordptr addr, N_int offset, N_int value) +{ + N_word size = size_(addr); + + if (size > 0) + { + if (offset < size) *(addr+offset) = value; + *(addr+size-1) &= mask_(addr); + } +} + +N_int BitVector_Word_Read(wordptr addr, N_int offset) +{ + N_word size = size_(addr); + + if (size > 0) + { + *(addr+size-1) &= mask_(addr); + if (offset < size) return( *(addr+offset) ); + } + return( (N_int) 0 ); +} + +void BitVector_Word_Insert(wordptr addr, N_int offset, N_int count, + boolean clear) +{ + N_word size = size_(addr); + N_word mask = mask_(addr); + wordptr last = addr+size-1; + + if (size > 0) + { + *last &= mask; + if (offset > size) offset = size; + BIT_VECTOR_ins_words(addr+offset,size-offset,count,clear); + *last &= mask; + } +} + +void BitVector_Word_Delete(wordptr addr, N_int offset, N_int count, + boolean clear) +{ + N_word size = size_(addr); + N_word mask = mask_(addr); + wordptr last = addr+size-1; + + if (size > 0) + { + *last &= mask; + if (offset > size) offset = size; + BIT_VECTOR_del_words(addr+offset,size-offset,count,clear); + *last &= mask; + } +} + +void BitVector_Chunk_Store(wordptr addr, N_int chunksize, N_int offset, + N_long value) +{ + N_word bits = bits_(addr); + N_word mask; + N_word temp; + + if ((chunksize > 0) and (offset < bits)) + { + if (chunksize > LONGBITS) chunksize = LONGBITS; + if ((offset + chunksize) > bits) chunksize = bits - offset; + addr += offset >> LOGBITS; + offset &= MODMASK; + while (chunksize > 0) + { + mask = (N_word) (~0L << offset); + bits = offset + chunksize; + if (bits < BITS) + { + mask &= (N_word) ~(~0L << bits); + bits = chunksize; + } + else bits = BITS - offset; + temp = (N_word) (value << offset); + temp &= mask; + *addr &= NOT mask; + *addr++ |= temp; + value >>= bits; + chunksize -= bits; + offset = 0; + } + } +} + +N_long BitVector_Chunk_Read(wordptr addr, N_int chunksize, N_int offset) +{ + N_word bits = bits_(addr); + N_word chunkbits = 0; + N_long value = 0L; + N_long temp; + N_word mask; + + if ((chunksize > 0) and (offset < bits)) + { + if (chunksize > LONGBITS) chunksize = LONGBITS; + if ((offset + chunksize) > bits) chunksize = bits - offset; + addr += offset >> LOGBITS; + offset &= MODMASK; + while (chunksize > 0) + { + bits = offset + chunksize; + if (bits < BITS) + { + mask = (N_word) ~(~0L << bits); + bits = chunksize; + } + else + { + mask = (N_word) ~0L; + bits = BITS - offset; + } + temp = (N_long) ((*addr++ AND mask) >> offset); + value |= temp << chunkbits; + chunkbits += bits; + chunksize -= bits; + offset = 0; + } + } + return(value); +} + + /*******************/ + /* set operations: */ + /*******************/ + +void Set_Union(wordptr X, wordptr Y, wordptr Z) /* X = Y + Z */ +{ + N_word bits = bits_(X); + N_word size = size_(X); + N_word mask = mask_(X); + + if ((size > 0) and (bits == bits_(Y)) and (bits == bits_(Z))) + { + while (size-- > 0) *X++ = *Y++ OR *Z++; + *(--X) &= mask; + } +} + +void Set_Intersection(wordptr X, wordptr Y, wordptr Z) /* X = Y * Z */ +{ + N_word bits = bits_(X); + N_word size = size_(X); + N_word mask = mask_(X); + + if ((size > 0) and (bits == bits_(Y)) and (bits == bits_(Z))) + { + while (size-- > 0) *X++ = *Y++ AND *Z++; + *(--X) &= mask; + } +} + +void Set_Difference(wordptr X, wordptr Y, wordptr Z) /* X = Y \ Z */ +{ + N_word bits = bits_(X); + N_word size = size_(X); + N_word mask = mask_(X); + + if ((size > 0) and (bits == bits_(Y)) and (bits == bits_(Z))) + { + while (size-- > 0) *X++ = *Y++ AND NOT *Z++; + *(--X) &= mask; + } +} + +void Set_ExclusiveOr(wordptr X, wordptr Y, wordptr Z) /* X=(Y+Z)\(Y*Z) */ +{ + N_word bits = bits_(X); + N_word size = size_(X); + N_word mask = mask_(X); + + if ((size > 0) and (bits == bits_(Y)) and (bits == bits_(Z))) + { + while (size-- > 0) *X++ = *Y++ XOR *Z++; + *(--X) &= mask; + } +} + +void Set_Complement(wordptr X, wordptr Y) /* X = ~Y */ +{ + N_word size = size_(X); + N_word mask = mask_(X); + + if ((size > 0) and (bits_(X) == bits_(Y))) + { + while (size-- > 0) *X++ = NOT *Y++; + *(--X) &= mask; + } +} + + /******************/ + /* set functions: */ + /******************/ + +boolean Set_subset(wordptr X, wordptr Y) /* X subset Y ? */ +{ + N_word size = size_(X); + boolean r = FALSE; + + if ((size > 0) and (bits_(X) == bits_(Y))) + { + r = TRUE; + while (r and (size-- > 0)) r = ((*X++ AND NOT *Y++) == 0); + } + return(r); +} + +N_int Set_Norm(wordptr addr) /* = | X | */ +{ + byteptr byte; + N_word bytes; + N_int n; + + byte = (byteptr) addr; + bytes = size_(addr) << FACTOR; + n = 0; + while (bytes-- > 0) + { + n += BitVector_BYTENORM[*byte++]; + } + return(n); +} + +N_int Set_Norm2(wordptr addr) /* = | X | */ +{ + N_word size = size_(addr); + N_word w0,w1; + N_int n,k; + + n = 0; + while (size-- > 0) + { + k = 0; + w1 = NOT (w0 = *addr++); + while (w0 and w1) + { + w0 &= w0 - 1; + w1 &= w1 - 1; + k++; + } + if (w0 == 0) n += k; + else n += BITS - k; + } + return(n); +} + +N_int Set_Norm3(wordptr addr) /* = | X | */ +{ + N_word size = size_(addr); + N_int count = 0; + N_word c; + + while (size-- > 0) + { + c = *addr++; + while (c) + { + c &= c - 1; + count++; + } + } + return(count); +} + +Z_long Set_Min(wordptr addr) /* = min(X) */ +{ + boolean empty = TRUE; + N_word size = size_(addr); + N_word i = 0; + N_word c = 0; /* silence compiler warning */ + + while (empty and (size-- > 0)) + { + if ((c = *addr++)) empty = false; else i++; + } + if (empty) return((Z_long) LONG_MAX); /* plus infinity */ + i <<= LOGBITS; + while (not (c AND LSB)) + { + c >>= 1; + i++; + } + return((Z_long) i); +} + +Z_long Set_Max(wordptr addr) /* = max(X) */ +{ + boolean empty = TRUE; + N_word size = size_(addr); + N_word i = size; + N_word c = 0; /* silence compiler warning */ + + addr += size-1; + while (empty and (size-- > 0)) + { + if ((c = *addr--)) empty = false; else i--; + } + if (empty) return((Z_long) LONG_MIN); /* minus infinity */ + i <<= LOGBITS; + while (not (c AND MSB)) + { + c <<= 1; + i--; + } + return((Z_long) --i); +} + + /**********************************/ + /* matrix-of-booleans operations: */ + /**********************************/ + +void Matrix_Multiplication(wordptr X, N_int rowsX, N_int colsX, + wordptr Y, N_int rowsY, N_int colsY, + wordptr Z, N_int rowsZ, N_int colsZ) +{ + N_word i; + N_word j; + N_word k; + N_word indxX; + N_word indxY; + N_word indxZ; + N_word termX; + N_word termY; + N_word sum; + + if ((colsY == rowsZ) and (rowsX == rowsY) and (colsX == colsZ) and + (bits_(X) == rowsX*colsX) and + (bits_(Y) == rowsY*colsY) and + (bits_(Z) == rowsZ*colsZ)) + { + for ( i = 0; i < rowsY; i++ ) + { + termX = i * colsX; + termY = i * colsY; + for ( j = 0; j < colsZ; j++ ) + { + indxX = termX + j; + sum = 0; + for ( k = 0; k < colsY; k++ ) + { + indxY = termY + k; + indxZ = k * colsZ + j; + if ( BIT_VECTOR_TST_BIT(Y,indxY) && + BIT_VECTOR_TST_BIT(Z,indxZ) ) sum ^= 1; + } + if (sum) BIT_VECTOR_SET_BIT(X,indxX) + else BIT_VECTOR_CLR_BIT(X,indxX) + } + } + } +} + +void Matrix_Product(wordptr X, N_int rowsX, N_int colsX, + wordptr Y, N_int rowsY, N_int colsY, + wordptr Z, N_int rowsZ, N_int colsZ) +{ + N_word i; + N_word j; + N_word k; + N_word indxX; + N_word indxY; + N_word indxZ; + N_word termX; + N_word termY; + N_word sum; + + if ((colsY == rowsZ) and (rowsX == rowsY) and (colsX == colsZ) and + (bits_(X) == rowsX*colsX) and + (bits_(Y) == rowsY*colsY) and + (bits_(Z) == rowsZ*colsZ)) + { + for ( i = 0; i < rowsY; i++ ) + { + termX = i * colsX; + termY = i * colsY; + for ( j = 0; j < colsZ; j++ ) + { + indxX = termX + j; + sum = 0; + for ( k = 0; k < colsY; k++ ) + { + indxY = termY + k; + indxZ = k * colsZ + j; + if ( BIT_VECTOR_TST_BIT(Y,indxY) && + BIT_VECTOR_TST_BIT(Z,indxZ) ) sum |= 1; + } + if (sum) BIT_VECTOR_SET_BIT(X,indxX) + else BIT_VECTOR_CLR_BIT(X,indxX) + } + } + } +} + +void Matrix_Closure(wordptr addr, N_int rows, N_int cols) +{ + N_word i; + N_word j; + N_word k; + N_word ii; + N_word ij; + N_word ik; + N_word kj; + N_word termi; + N_word termk; + + if ((rows == cols) and (bits_(addr) == rows*cols)) + { + for ( i = 0; i < rows; i++ ) + { + ii = i * cols + i; + BIT_VECTOR_SET_BIT(addr,ii) + } + for ( k = 0; k < rows; k++ ) + { + termk = k * cols; + for ( i = 0; i < rows; i++ ) + { + termi = i * cols; + ik = termi + k; + for ( j = 0; j < rows; j++ ) + { + ij = termi + j; + kj = termk + j; + if ( BIT_VECTOR_TST_BIT(addr,ik) && + BIT_VECTOR_TST_BIT(addr,kj) ) + BIT_VECTOR_SET_BIT(addr,ij) + } + } + } + } +} + +void Matrix_Transpose(wordptr X, N_int rowsX, N_int colsX, + wordptr Y, N_int rowsY, N_int colsY) +{ + N_word i; + N_word j; + N_word ii; + N_word ij; + N_word ji; + N_word addii; + N_word addij; + N_word addji; + N_word bitii; + N_word bitij; + N_word bitji; + N_word termi; + N_word termj; + boolean swap; + + /* BEWARE that "in-place" is ONLY possible if the matrix is quadratic!! */ + + if ((rowsX == colsY) and (colsX == rowsY) and + (bits_(X) == rowsX*colsX) and + (bits_(Y) == rowsY*colsY)) + { + if (rowsY == colsY) /* in-place is possible! */ + { + for ( i = 0; i < rowsY; i++ ) + { + termi = i * colsY; + for ( j = 0; j < i; j++ ) + { + termj = j * colsX; + ij = termi + j; + ji = termj + i; + addij = ij >> LOGBITS; + addji = ji >> LOGBITS; + bitij = BITMASKTAB[ij AND MODMASK]; + bitji = BITMASKTAB[ji AND MODMASK]; + swap = ((*(Y+addij) AND bitij) != 0); + if ((*(Y+addji) AND bitji) != 0) + *(X+addij) |= bitij; + else + *(X+addij) &= NOT bitij; + if (swap) + *(X+addji) |= bitji; + else + *(X+addji) &= NOT bitji; + } + ii = termi + i; + addii = ii >> LOGBITS; + bitii = BITMASKTAB[ii AND MODMASK]; + if ((*(Y+addii) AND bitii) != 0) + *(X+addii) |= bitii; + else + *(X+addii) &= NOT bitii; + } + } + else /* rowsX != colsX, in-place is NOT possible! */ + { + for ( i = 0; i < rowsY; i++ ) + { + termi = i * colsY; + for ( j = 0; j < colsY; j++ ) + { + termj = j * colsX; + ij = termi + j; + ji = termj + i; + addij = ij >> LOGBITS; + addji = ji >> LOGBITS; + bitij = BITMASKTAB[ij AND MODMASK]; + bitji = BITMASKTAB[ji AND MODMASK]; + if ((*(Y+addij) AND bitij) != 0) + *(X+addji) |= bitji; + else + *(X+addji) &= NOT bitji; + } + } + } + } +} + +/*****************************************************************************/ +/* VERSION: 6.4 */ +/*****************************************************************************/ +/* VERSION HISTORY: */ +/*****************************************************************************/ +/* */ +/* Version 6.4 03.10.04 Added C++ comp. directives. Improved "Norm()". */ +/* Version 6.3 28.09.02 Added "Create_List()" and "GCD2()". */ +/* Version 6.2 15.09.02 Overhauled error handling. Fixed "GCD()". */ +/* Version 6.1 08.10.01 Make VMS linker happy: _lsb,_msb => _lsb_,_msb_ */ +/* Version 6.0 08.10.00 Corrected overflow handling. */ +/* Version 5.8 14.07.00 Added "Power()". Changed "Copy()". */ +/* Version 5.7 19.05.99 Quickened "Div_Pos()". Added "Product()". */ +/* Version 5.6 02.11.98 Leading zeros eliminated in "to_Hex()". */ +/* Version 5.5 21.09.98 Fixed bug of uninitialized "error" in Multiply. */ +/* Version 5.4 07.09.98 Fixed bug of uninitialized "error" in Divide. */ +/* Version 5.3 12.05.98 Improved Norm. Completed history. */ +/* Version 5.2 31.03.98 Improved Norm. */ +/* Version 5.1 09.03.98 No changes. */ +/* Version 5.0 01.03.98 Major additions and rewrite. */ +/* Version 4.2 16.07.97 Added is_empty, is_full. */ +/* Version 4.1 30.06.97 Added word-ins/del, move-left/right, inc/dec. */ +/* Version 4.0 23.04.97 Rewrite. Added bit shift and bool. matrix ops. */ +/* Version 3.2 04.02.97 Added interval methods. */ +/* Version 3.1 21.01.97 Fixed bug on 64 bit machines. */ +/* Version 3.0 12.01.97 Added flip. */ +/* Version 2.0 14.12.96 Efficiency and consistency improvements. */ +/* Version 1.1 08.01.96 Added Resize and ExclusiveOr. */ +/* Version 1.0 14.12.95 First version under UNIX (with Perl module). */ +/* Version 0.9 01.11.93 First version of C library under MS-DOS. */ +/* Version 0.1 ??.??.89 First version in Turbo Pascal under CP/M. */ +/* */ +/*****************************************************************************/ +/* AUTHOR: */ +/*****************************************************************************/ +/* */ +/* Steffen Beyer */ +/* mailto:sb@engelschall.com */ +/* http://www.engelschall.com/u/sb/download/ */ +/* */ +/*****************************************************************************/ +/* COPYRIGHT: */ +/*****************************************************************************/ +/* */ +/* Copyright (c) 1995 - 2004 by Steffen Beyer. */ +/* All rights reserved. */ +/* */ +/*****************************************************************************/ +/* LICENSE: */ +/*****************************************************************************/ +/* This package is free software; you can use, modify and redistribute */ +/* it under the same terms as Perl itself, i.e., under the terms of */ +/* the "Artistic License" or the "GNU General Public License". */ +/* */ +/* The C library at the core of this Perl module can additionally */ +/* be used, modified and redistributed under the terms of the */ +/* "GNU Library General Public License". */ +/* */ +/*****************************************************************************/ +/* ARTISTIC LICENSE: */ +/*****************************************************************************/ +/* + The "Artistic License" + + Preamble + +The intent of this document is to state the conditions under which a +Package may be copied, such that the Copyright Holder maintains some +semblance of artistic control over the development of the package, +while giving the users of the package the right to use and distribute +the Package in a more-or-less customary fashion, plus the right to make +reasonable modifications. + +Definitions: + + "Package" refers to the collection of files distributed by the + Copyright Holder, and derivatives of that collection of files + created through textual modification. + + "Standard Version" refers to such a Package if it has not been + modified, or has been modified in accordance with the wishes + of the Copyright Holder as specified below. + + "Copyright Holder" is whoever is named in the copyright or + copyrights for the package. + + "You" is you, if you're thinking about copying or distributing + this Package. + + "Reasonable copying fee" is whatever you can justify on the + basis of media cost, duplication charges, time of people involved, + and so on. (You will not be required to justify it to the + Copyright Holder, but only to the computing community at large + as a market that must bear the fee.) + + "Freely Available" means that no fee is charged for the item + itself, though there may be fees involved in handling the item. + It also means that recipients of the item may redistribute it + under the same conditions they received it. + +1. You may make and give away verbatim copies of the source form of the +Standard Version of this Package without restriction, provided that you +duplicate all of the original copyright notices and associated disclaimers. + +2. You may apply bug fixes, portability fixes and other modifications +derived from the Public Domain or from the Copyright Holder. A Package +modified in such a way shall still be considered the Standard Version. + +3. You may otherwise modify your copy of this Package in any way, provided +that you insert a prominent notice in each changed file stating how and +when you changed that file, and provided that you do at least ONE of the +following: + + a) place your modifications in the Public Domain or otherwise make them + Freely Available, such as by posting said modifications to Usenet or + an equivalent medium, or placing the modifications on a major archive + site such as uunet.uu.net, or by allowing the Copyright Holder to include + your modifications in the Standard Version of the Package. + + b) use the modified Package only within your corporation or organization. + + c) rename any non-standard executables so the names do not conflict + with standard executables, which must also be provided, and provide + a separate manual page for each non-standard executable that clearly + documents how it differs from the Standard Version. + + d) make other distribution arrangements with the Copyright Holder. + +4. You may distribute the programs of this Package in object code or +executable form, provided that you do at least ONE of the following: + + a) distribute a Standard Version of the executables and library files, + together with instructions (in the manual page or equivalent) on where + to get the Standard Version. + + b) accompany the distribution with the machine-readable source of + the Package with your modifications. + + c) give non-standard executables non-standard names, and clearly + document the differences in manual pages (or equivalent), together + with instructions on where to get the Standard Version. + + d) make other distribution arrangements with the Copyright Holder. + +5. You may charge a reasonable copying fee for any distribution of this +Package. You may charge any fee you choose for support of this +Package. You may not charge a fee for this Package itself. However, +you may distribute this Package in aggregate with other (possibly +commercial) programs as part of a larger (possibly commercial) software +distribution provided that you do not advertise this Package as a +product of your own. You may embed this Package's interpreter within +an executable of yours (by linking); this shall be construed as a mere +form of aggregation, provided that the complete Standard Version of the +interpreter is so embedded. + +6. The scripts and library files supplied as input to or produced as +output from the programs of this Package do not automatically fall +under the copyright of this Package, but belong to whoever generated +them, and may be sold commercially, and may be aggregated with this +Package. If such scripts or library files are aggregated with this +Package via the so-called "undump" or "unexec" methods of producing a +binary executable image, then distribution of such an image shall +neither be construed as a distribution of this Package nor shall it +fall under the restrictions of Paragraphs 3 and 4, provided that you do +not represent such an executable image as a Standard Version of this +Package. + +7. C subroutines (or comparably compiled subroutines in other +languages) supplied by you and linked into this Package in order to +emulate subroutines and variables of the language defined by this +Package shall not be considered part of this Package, but are the +equivalent of input as in Paragraph 6, provided these subroutines do +not change the language in any way that would cause it to fail the +regression tests for the language. + +8. Aggregation of this Package with a commercial distribution is always +permitted provided that the use of this Package is embedded; that is, +when no overt attempt is made to make this Package's interfaces visible +to the end user of the commercial distribution. Such use shall not be +construed as a distribution of this Package. + +9. The name of the Copyright Holder may not be used to endorse or promote +products derived from this software without specific prior written permission. + +10. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED +WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + + The End +*/ +/*****************************************************************************/ +/* GNU GENERAL PUBLIC LICENSE: */ +/*****************************************************************************/ +/* This program is free software; you can redistribute it and/or */ +/* modify it under the terms of the GNU General Public License */ +/* as published by the Free Software Foundation; either version 2 */ +/* of the License, or (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU General Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License */ +/* along with this program; if not, write to the */ +/* Free Software Foundation, Inc., */ +/* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* */ +/*****************************************************************************/ +/* GNU LIBRARY GENERAL PUBLIC LICENSE: */ +/*****************************************************************************/ +/* This library is free software; you can redistribute it and/or */ +/* modify it under the terms of the GNU Library General Public */ +/* License as published by the Free Software Foundation; either */ +/* version 2 of the License, or (at your option) any later version. */ +/* */ +/* This library is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU */ +/* Library General Public License for more details. */ +/* */ +/* You should have received a copy of the GNU Library General Public */ +/* License along with this library; if not, write to the */ +/* Free Software Foundation, Inc., */ +/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* */ +/* or download a copy from ftp://ftp.gnu.org/pub/gnu/COPYING.LIB-2.0 */ +/* */ +/*****************************************************************************/ diff --git a/contrib/tools/yasm/libyasm/bitvect.h b/contrib/tools/yasm/libyasm/bitvect.h index 3aee3a5319..df4914adf4 100644 --- a/contrib/tools/yasm/libyasm/bitvect.h +++ b/contrib/tools/yasm/libyasm/bitvect.h @@ -1,666 +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 +#ifndef YASM_BITVECT_H +#define YASM_BITVECT_H +/*****************************************************************************/ +/* MODULE NAME: BitVector.h MODULE TYPE: (adt) */ +/*****************************************************************************/ +/* MODULE IMPORTS: */ +/*****************************************************************************/ + +/* ToolBox.h */ +/*****************************************************************************/ +/* NOTE: The type names that have been chosen here are somewhat weird on */ +/* purpose, in order to avoid name clashes with system header files */ +/* and your own application(s) which might - directly or indirectly - */ +/* include this definitions file. */ +/*****************************************************************************/ +#ifndef YASM_LIB_DECL +#define YASM_LIB_DECL +#endif + +typedef unsigned char N_char; +typedef unsigned char N_byte; +typedef unsigned short N_short; +typedef unsigned short N_shortword; +typedef unsigned int N_int; +typedef unsigned int N_word; +typedef unsigned long N_long; +typedef unsigned long N_longword; + +/* Mnemonic 1: The natural numbers, N = { 0, 1, 2, 3, ... } */ +/* Mnemonic 2: Nnnn = u_N_signed, _N_ot signed */ + +typedef signed char Z_char; +typedef signed char Z_byte; +typedef signed short Z_short; +typedef signed short Z_shortword; +typedef signed int Z_int; +typedef signed int Z_word; +typedef signed long Z_long; +typedef signed long Z_longword; + +/* Mnemonic 1: The whole numbers, Z = { 0, -1, 1, -2, 2, -3, 3, ... } */ +/* Mnemonic 2: Zzzz = Ssss_igned */ + +typedef void *voidptr; +typedef N_char *charptr; +typedef N_byte *byteptr; +typedef N_short *shortptr; +typedef N_shortword *shortwordptr; +typedef N_int *intptr; +typedef N_word *wordptr; +typedef N_long *longptr; +typedef N_longword *longwordptr; + +typedef N_char *N_charptr; +typedef N_byte *N_byteptr; +typedef N_short *N_shortptr; +typedef N_shortword *N_shortwordptr; +typedef N_int *N_intptr; +typedef N_word *N_wordptr; +typedef N_long *N_longptr; +typedef N_longword *N_longwordptr; + +typedef Z_char *Z_charptr; +typedef Z_byte *Z_byteptr; +typedef Z_short *Z_shortptr; +typedef Z_shortword *Z_shortwordptr; +typedef Z_int *Z_intptr; +typedef Z_word *Z_wordptr; +typedef Z_long *Z_longptr; +typedef Z_longword *Z_longwordptr; + +#ifndef FALSE +#define FALSE (0!=0) +#endif + +#ifndef TRUE +#define TRUE (0==0) +#endif + +#ifdef __cplusplus + typedef bool boolean; +#else + #ifdef MACOS_TRADITIONAL + #define boolean Boolean + #else + typedef enum boolean { false = FALSE, true = TRUE } boolean; + #endif +#endif + +/*****************************************************************************/ +/* MODULE INTERFACE: */ +/*****************************************************************************/ + +typedef enum ErrCode + { + ErrCode_Ok = 0, /* everything went allright */ + + ErrCode_Type, /* types word and size_t have incompatible sizes */ + ErrCode_Bits, /* bits of word and sizeof(word) are inconsistent */ + ErrCode_Word, /* size of word is less than 16 bits */ + ErrCode_Long, /* size of word is greater than size of long */ + ErrCode_Powr, /* number of bits of word is not a power of two */ + ErrCode_Loga, /* error in calculation of logarithm */ + + ErrCode_Null, /* unable to allocate memory */ + + ErrCode_Indx, /* index out of range */ + ErrCode_Ordr, /* minimum > maximum index */ + ErrCode_Size, /* bit vector size mismatch */ + ErrCode_Pars, /* input string syntax error */ + ErrCode_Ovfl, /* numeric overflow error */ + ErrCode_Same, /* operands must be distinct */ + ErrCode_Expo, /* exponent must be positive */ + ErrCode_Zero /* division by zero error */ + } ErrCode; + +typedef wordptr *listptr; + +/* ===> MISCELLANEOUS BASIC FUNCTIONS: <=== */ + +YASM_LIB_DECL +const char * BitVector_Error (ErrCode error); /* return string for err code */ + +YASM_LIB_DECL +ErrCode BitVector_Boot (void); /* 0 = ok, 1..7 = error */ +YASM_LIB_DECL +void BitVector_Shutdown (void); /* undo Boot */ + +YASM_LIB_DECL +N_word BitVector_Size (N_int bits); /* bit vector size (# of words) */ +YASM_LIB_DECL +N_word BitVector_Mask (N_int bits); /* bit vector mask (unused bits) */ + +/* ===> CLASS METHODS: <=== */ + +YASM_LIB_DECL +const char * BitVector_Version (void); /* returns version string */ + +YASM_LIB_DECL +N_int BitVector_Word_Bits (void); /* return # of bits in machine word */ +YASM_LIB_DECL +N_int BitVector_Long_Bits (void); /* return # of bits in unsigned long */ + +/* ===> CONSTRUCTOR METHODS: <=== */ + +YASM_LIB_DECL +/*@only@*/ wordptr BitVector_Create (N_int bits, boolean clear); /* malloc */ +YASM_LIB_DECL +listptr BitVector_Create_List(N_int bits, boolean clear, N_int count); + +YASM_LIB_DECL +wordptr BitVector_Resize (wordptr oldaddr, N_int bits); /* realloc */ + +YASM_LIB_DECL +wordptr BitVector_Shadow (wordptr addr); /* make new same size but empty */ +YASM_LIB_DECL +wordptr BitVector_Clone (wordptr addr); /* make exact duplicate */ + +YASM_LIB_DECL +wordptr BitVector_Concat (wordptr X, wordptr Y); /* return concatenation */ + +/* ===> DESTRUCTOR METHODS: <=== */ + +YASM_LIB_DECL +void BitVector_Dispose (/*@only@*/ /*@out@*/ charptr string); /* string */ +YASM_LIB_DECL +void BitVector_Destroy (/*@only@*/ wordptr addr); /* bitvec */ +YASM_LIB_DECL +void BitVector_Destroy_List (listptr list, N_int count); /* list */ + +/* ===> OBJECT METHODS: <=== */ + +/* ===> bit vector copy function: */ + +YASM_LIB_DECL +void BitVector_Copy (wordptr X, wordptr Y); /* X = Y */ + +/* ===> bit vector initialization: */ + +YASM_LIB_DECL +void BitVector_Empty (wordptr addr); /* X = {} */ +YASM_LIB_DECL +void BitVector_Fill (wordptr addr); /* X = ~{} */ +YASM_LIB_DECL +void BitVector_Flip (wordptr addr); /* X = ~X */ + +YASM_LIB_DECL +void BitVector_Primes (wordptr addr); + +/* ===> miscellaneous functions: */ + +YASM_LIB_DECL +void BitVector_Reverse (wordptr X, wordptr Y); + +/* ===> bit vector interval operations and functions: */ + +YASM_LIB_DECL +void BitVector_Interval_Empty (/*@out@*/ wordptr addr, N_int lower, N_int upper); +YASM_LIB_DECL +void BitVector_Interval_Fill (/*@out@*/ wordptr addr, N_int lower, N_int upper); +YASM_LIB_DECL +void BitVector_Interval_Flip (/*@out@*/ wordptr addr, N_int lower, N_int upper); +YASM_LIB_DECL +void BitVector_Interval_Reverse (/*@out@*/ wordptr addr, N_int lower, N_int upper); + +YASM_LIB_DECL +boolean BitVector_interval_scan_inc (wordptr addr, N_int start, + N_intptr min, N_intptr max); +YASM_LIB_DECL +boolean BitVector_interval_scan_dec (wordptr addr, N_int start, + N_intptr min, N_intptr max); + +YASM_LIB_DECL +void BitVector_Interval_Copy (/*@out@*/ wordptr X, wordptr Y, N_int Xoffset, + N_int Yoffset, N_int length); + +YASM_LIB_DECL +wordptr BitVector_Interval_Substitute(/*@out@*/ wordptr X, wordptr Y, + N_int Xoffset, N_int Xlength, + N_int Yoffset, N_int Ylength); + +/* ===> bit vector test functions: */ + +YASM_LIB_DECL +boolean BitVector_is_empty (wordptr addr); /* X == {} ? */ +YASM_LIB_DECL +boolean BitVector_is_full (wordptr addr); /* X == ~{} ? */ + +YASM_LIB_DECL +boolean BitVector_equal (wordptr X, wordptr Y); /* X == Y ? */ +YASM_LIB_DECL +Z_int BitVector_Lexicompare(wordptr X, wordptr Y); /* X <,=,> Y ? */ +YASM_LIB_DECL +Z_int BitVector_Compare (wordptr X, wordptr Y); /* X <,=,> Y ? */ + +/* ===> bit vector string conversion functions: */ + +YASM_LIB_DECL +/*@only@*/ charptr BitVector_to_Hex (wordptr addr); +YASM_LIB_DECL +ErrCode BitVector_from_Hex (/*@out@*/wordptr addr, charptr string); + +YASM_LIB_DECL +ErrCode BitVector_from_Oct(/*@out@*/ wordptr addr, charptr string); + +YASM_LIB_DECL +/*@only@*/ charptr BitVector_to_Bin (wordptr addr); +YASM_LIB_DECL +ErrCode BitVector_from_Bin (/*@out@*/ wordptr addr, charptr string); + +YASM_LIB_DECL +/*@only@*/ charptr BitVector_to_Dec (wordptr addr); +YASM_LIB_DECL +ErrCode BitVector_from_Dec (/*@out@*/ wordptr addr, charptr string); + +typedef struct BitVector_from_Dec_static_data BitVector_from_Dec_static_data; +YASM_LIB_DECL +BitVector_from_Dec_static_data *BitVector_from_Dec_static_Boot(N_word bits); +YASM_LIB_DECL +void BitVector_from_Dec_static_Shutdown(/*@null@*/ BitVector_from_Dec_static_data *data); +YASM_LIB_DECL +ErrCode BitVector_from_Dec_static(BitVector_from_Dec_static_data *data, + /*@out@*/ wordptr addr, charptr string); + +YASM_LIB_DECL +/*@only@*/ charptr BitVector_to_Enum (wordptr addr); +YASM_LIB_DECL +ErrCode BitVector_from_Enum (/*@out@*/ wordptr addr, charptr string); + +/* ===> bit vector bit operations, functions & tests: */ + +YASM_LIB_DECL +void BitVector_Bit_Off (/*@out@*/ wordptr addr, N_int indx); /* X = X \ {x} */ +YASM_LIB_DECL +void BitVector_Bit_On (/*@out@*/ wordptr addr, N_int indx); /* X = X + {x} */ +YASM_LIB_DECL +boolean BitVector_bit_flip (/*@out@*/ wordptr addr, N_int indx); /* (X+{x})\(X*{x}) */ + +YASM_LIB_DECL +boolean BitVector_bit_test (wordptr addr, N_int indx); /* {x} in X ? */ + +YASM_LIB_DECL +void BitVector_Bit_Copy (/*@out@*/ wordptr addr, N_int indx, boolean bit); + +/* ===> bit vector bit shift & rotate functions: */ + +YASM_LIB_DECL +void BitVector_LSB (/*@out@*/ wordptr addr, boolean bit); +YASM_LIB_DECL +void BitVector_MSB (/*@out@*/ wordptr addr, boolean bit); +YASM_LIB_DECL +boolean BitVector_lsb_ (wordptr addr); +YASM_LIB_DECL +boolean BitVector_msb_ (wordptr addr); +YASM_LIB_DECL +boolean /*@alt void@*/ BitVector_rotate_left (wordptr addr); +YASM_LIB_DECL +boolean /*@alt void@*/ BitVector_rotate_right (wordptr addr); +YASM_LIB_DECL +boolean /*@alt void@*/ BitVector_shift_left (wordptr addr, boolean carry_in); +YASM_LIB_DECL +boolean /*@alt void@*/ BitVector_shift_right (wordptr addr, boolean carry_in); +YASM_LIB_DECL +void BitVector_Move_Left (wordptr addr, N_int bits); +YASM_LIB_DECL +void BitVector_Move_Right (wordptr addr, N_int bits); + +/* ===> bit vector insert/delete bits: */ + +YASM_LIB_DECL +void BitVector_Insert (wordptr addr, N_int offset, N_int count, + boolean clear); +YASM_LIB_DECL +void BitVector_Delete (wordptr addr, N_int offset, N_int count, + boolean clear); + +/* ===> bit vector arithmetic: */ + +YASM_LIB_DECL +boolean /*@alt void@*/ BitVector_increment (wordptr addr); /* X++ */ +YASM_LIB_DECL +boolean /*@alt void@*/ BitVector_decrement (wordptr addr); /* X-- */ + +YASM_LIB_DECL +boolean /*@alt void@*/ BitVector_compute (wordptr X, wordptr Y, wordptr Z, boolean minus, + boolean *carry); +YASM_LIB_DECL +boolean /*@alt void@*/ BitVector_add (wordptr X, wordptr Y, wordptr Z, boolean *carry); +YASM_LIB_DECL +boolean /*@alt void@*/ BitVector_sub (wordptr X, wordptr Y, wordptr Z, boolean *carry); +YASM_LIB_DECL +boolean /*@alt void@*/ BitVector_inc (wordptr X, wordptr Y); +YASM_LIB_DECL +boolean /*@alt void@*/ BitVector_dec (wordptr X, wordptr Y); + +YASM_LIB_DECL +void BitVector_Negate (wordptr X, wordptr Y); +YASM_LIB_DECL +void BitVector_Absolute (wordptr X, wordptr Y); +YASM_LIB_DECL +Z_int BitVector_Sign (wordptr addr); +YASM_LIB_DECL +ErrCode BitVector_Mul_Pos (wordptr X, wordptr Y, wordptr Z, boolean strict); +YASM_LIB_DECL +ErrCode BitVector_Multiply (wordptr X, wordptr Y, wordptr Z); +YASM_LIB_DECL +ErrCode BitVector_Div_Pos (wordptr Q, wordptr X, wordptr Y, wordptr R); +YASM_LIB_DECL +ErrCode BitVector_Divide (wordptr Q, wordptr X, wordptr Y, wordptr R); +YASM_LIB_DECL +ErrCode BitVector_GCD (wordptr X, wordptr Y, wordptr Z); +YASM_LIB_DECL +ErrCode BitVector_GCD2 (wordptr U, wordptr V, wordptr W, /* O */ + wordptr X, wordptr Y); /* I */ +YASM_LIB_DECL +ErrCode BitVector_Power (wordptr X, wordptr Y, wordptr Z); + +/* ===> direct memory access functions: */ + +YASM_LIB_DECL +void BitVector_Block_Store(wordptr addr, charptr buffer, N_int length); +YASM_LIB_DECL +charptr BitVector_Block_Read (wordptr addr, /*@out@*/ N_intptr length); + +/* ===> word array functions: */ + +YASM_LIB_DECL +void BitVector_Word_Store (wordptr addr, N_int offset, N_int value); +YASM_LIB_DECL +N_int BitVector_Word_Read (wordptr addr, N_int offset); + +YASM_LIB_DECL +void BitVector_Word_Insert(wordptr addr, N_int offset, N_int count, + boolean clear); +YASM_LIB_DECL +void BitVector_Word_Delete(wordptr addr, N_int offset, N_int count, + boolean clear); + +/* ===> arbitrary size chunk functions: */ + +YASM_LIB_DECL +void BitVector_Chunk_Store(wordptr addr, N_int chunksize, + N_int offset, N_long value); +YASM_LIB_DECL +N_long BitVector_Chunk_Read (wordptr addr, N_int chunksize, + N_int offset); + +/* ===> set operations: */ + +YASM_LIB_DECL +void Set_Union (wordptr X, wordptr Y, wordptr Z); /* X = Y + Z */ +YASM_LIB_DECL +void Set_Intersection (wordptr X, wordptr Y, wordptr Z); /* X = Y * Z */ +YASM_LIB_DECL +void Set_Difference (wordptr X, wordptr Y, wordptr Z); /* X = Y \ Z */ +YASM_LIB_DECL +void Set_ExclusiveOr (wordptr X, wordptr Y, wordptr Z); /*(Y+Z)\(Y*Z)*/ +YASM_LIB_DECL +void Set_Complement (wordptr X, wordptr Y); /* X = ~Y */ + +/* ===> set functions: */ + +YASM_LIB_DECL +boolean Set_subset (wordptr X, wordptr Y); /* X in Y ? */ + +YASM_LIB_DECL +N_int Set_Norm (wordptr addr); /* = | X | */ +YASM_LIB_DECL +N_int Set_Norm2 (wordptr addr); /* = | X | */ +YASM_LIB_DECL +N_int Set_Norm3 (wordptr addr); /* = | X | */ +YASM_LIB_DECL +Z_long Set_Min (wordptr addr); /* = min(X) */ +YASM_LIB_DECL +Z_long Set_Max (wordptr addr); /* = max(X) */ + +/* ===> matrix-of-booleans operations: */ + +YASM_LIB_DECL +void Matrix_Multiplication(wordptr X, N_int rowsX, N_int colsX, + wordptr Y, N_int rowsY, N_int colsY, + wordptr Z, N_int rowsZ, N_int colsZ); + +YASM_LIB_DECL +void Matrix_Product (wordptr X, N_int rowsX, N_int colsX, + wordptr Y, N_int rowsY, N_int colsY, + wordptr Z, N_int rowsZ, N_int colsZ); + +YASM_LIB_DECL +void Matrix_Closure (wordptr addr, N_int rows, N_int cols); + +YASM_LIB_DECL +void Matrix_Transpose (wordptr X, N_int rowsX, N_int colsX, + wordptr Y, N_int rowsY, N_int colsY); + +/*****************************************************************************/ +/* VERSION: 6.4 */ +/*****************************************************************************/ +/* VERSION HISTORY: */ +/*****************************************************************************/ +/* */ +/* Version 6.4 03.10.04 Added C++ comp. directives. Improved "Norm()". */ +/* Version 6.3 28.09.02 Added "Create_List()" and "GCD2()". */ +/* Version 6.2 15.09.02 Overhauled error handling. Fixed "GCD()". */ +/* Version 6.1 08.10.01 Make VMS linker happy: _lsb,_msb => _lsb_,_msb_ */ +/* Version 6.0 08.10.00 Corrected overflow handling. */ +/* Version 5.8 14.07.00 Added "Power()". Changed "Copy()". */ +/* Version 5.7 19.05.99 Quickened "Div_Pos()". Added "Product()". */ +/* Version 5.6 02.11.98 Leading zeros eliminated in "to_Hex()". */ +/* Version 5.5 21.09.98 Fixed bug of uninitialized "error" in Multiply. */ +/* Version 5.4 07.09.98 Fixed bug of uninitialized "error" in Divide. */ +/* Version 5.3 12.05.98 Improved Norm. Completed history. */ +/* Version 5.2 31.03.98 Improved Norm. */ +/* Version 5.1 09.03.98 No changes. */ +/* Version 5.0 01.03.98 Major additions and rewrite. */ +/* Version 4.2 16.07.97 Added is_empty, is_full. */ +/* Version 4.1 30.06.97 Added word-ins/del, move-left/right, inc/dec. */ +/* Version 4.0 23.04.97 Rewrite. Added bit shift and bool. matrix ops. */ +/* Version 3.2 04.02.97 Added interval methods. */ +/* Version 3.1 21.01.97 Fixed bug on 64 bit machines. */ +/* Version 3.0 12.01.97 Added flip. */ +/* Version 2.0 14.12.96 Efficiency and consistency improvements. */ +/* Version 1.1 08.01.96 Added Resize and ExclusiveOr. */ +/* Version 1.0 14.12.95 First version under UNIX (with Perl module). */ +/* Version 0.9 01.11.93 First version of C library under MS-DOS. */ +/* Version 0.1 ??.??.89 First version in Turbo Pascal under CP/M. */ +/* */ +/*****************************************************************************/ +/* AUTHOR: */ +/*****************************************************************************/ +/* */ +/* Steffen Beyer */ +/* mailto:sb@engelschall.com */ +/* http://www.engelschall.com/u/sb/download/ */ +/* */ +/*****************************************************************************/ +/* COPYRIGHT: */ +/*****************************************************************************/ +/* */ +/* Copyright (c) 1995 - 2004 by Steffen Beyer. */ +/* All rights reserved. */ +/* */ +/*****************************************************************************/ +/* LICENSE: */ +/*****************************************************************************/ +/* This package is free software; you can use, modify and redistribute */ +/* it under the same terms as Perl itself, i.e., under the terms of */ +/* the "Artistic License" or the "GNU General Public License". */ +/* */ +/* The C library at the core of this Perl module can additionally */ +/* be used, modified and redistributed under the terms of the */ +/* "GNU Library General Public License". */ +/* */ +/*****************************************************************************/ +/* ARTISTIC LICENSE: */ +/*****************************************************************************/ +/* + The "Artistic License" + + Preamble + +The intent of this document is to state the conditions under which a +Package may be copied, such that the Copyright Holder maintains some +semblance of artistic control over the development of the package, +while giving the users of the package the right to use and distribute +the Package in a more-or-less customary fashion, plus the right to make +reasonable modifications. + +Definitions: + + "Package" refers to the collection of files distributed by the + Copyright Holder, and derivatives of that collection of files + created through textual modification. + + "Standard Version" refers to such a Package if it has not been + modified, or has been modified in accordance with the wishes + of the Copyright Holder as specified below. + + "Copyright Holder" is whoever is named in the copyright or + copyrights for the package. + + "You" is you, if you're thinking about copying or distributing + this Package. + + "Reasonable copying fee" is whatever you can justify on the + basis of media cost, duplication charges, time of people involved, + and so on. (You will not be required to justify it to the + Copyright Holder, but only to the computing community at large + as a market that must bear the fee.) + + "Freely Available" means that no fee is charged for the item + itself, though there may be fees involved in handling the item. + It also means that recipients of the item may redistribute it + under the same conditions they received it. + +1. You may make and give away verbatim copies of the source form of the +Standard Version of this Package without restriction, provided that you +duplicate all of the original copyright notices and associated disclaimers. + +2. You may apply bug fixes, portability fixes and other modifications +derived from the Public Domain or from the Copyright Holder. A Package +modified in such a way shall still be considered the Standard Version. + +3. You may otherwise modify your copy of this Package in any way, provided +that you insert a prominent notice in each changed file stating how and +when you changed that file, and provided that you do at least ONE of the +following: + + a) place your modifications in the Public Domain or otherwise make them + Freely Available, such as by posting said modifications to Usenet or + an equivalent medium, or placing the modifications on a major archive + site such as uunet.uu.net, or by allowing the Copyright Holder to include + your modifications in the Standard Version of the Package. + + b) use the modified Package only within your corporation or organization. + + c) rename any non-standard executables so the names do not conflict + with standard executables, which must also be provided, and provide + a separate manual page for each non-standard executable that clearly + documents how it differs from the Standard Version. + + d) make other distribution arrangements with the Copyright Holder. + +4. You may distribute the programs of this Package in object code or +executable form, provided that you do at least ONE of the following: + + a) distribute a Standard Version of the executables and library files, + together with instructions (in the manual page or equivalent) on where + to get the Standard Version. + + b) accompany the distribution with the machine-readable source of + the Package with your modifications. + + c) give non-standard executables non-standard names, and clearly + document the differences in manual pages (or equivalent), together + with instructions on where to get the Standard Version. + + d) make other distribution arrangements with the Copyright Holder. + +5. You may charge a reasonable copying fee for any distribution of this +Package. You may charge any fee you choose for support of this +Package. You may not charge a fee for this Package itself. However, +you may distribute this Package in aggregate with other (possibly +commercial) programs as part of a larger (possibly commercial) software +distribution provided that you do not advertise this Package as a +product of your own. You may embed this Package's interpreter within +an executable of yours (by linking); this shall be construed as a mere +form of aggregation, provided that the complete Standard Version of the +interpreter is so embedded. + +6. The scripts and library files supplied as input to or produced as +output from the programs of this Package do not automatically fall +under the copyright of this Package, but belong to whoever generated +them, and may be sold commercially, and may be aggregated with this +Package. If such scripts or library files are aggregated with this +Package via the so-called "undump" or "unexec" methods of producing a +binary executable image, then distribution of such an image shall +neither be construed as a distribution of this Package nor shall it +fall under the restrictions of Paragraphs 3 and 4, provided that you do +not represent such an executable image as a Standard Version of this +Package. + +7. C subroutines (or comparably compiled subroutines in other +languages) supplied by you and linked into this Package in order to +emulate subroutines and variables of the language defined by this +Package shall not be considered part of this Package, but are the +equivalent of input as in Paragraph 6, provided these subroutines do +not change the language in any way that would cause it to fail the +regression tests for the language. + +8. Aggregation of this Package with a commercial distribution is always +permitted provided that the use of this Package is embedded; that is, +when no overt attempt is made to make this Package's interfaces visible +to the end user of the commercial distribution. Such use shall not be +construed as a distribution of this Package. + +9. The name of the Copyright Holder may not be used to endorse or promote +products derived from this software without specific prior written permission. + +10. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED +WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + + The End +*/ +/*****************************************************************************/ +/* GNU GENERAL PUBLIC LICENSE: */ +/*****************************************************************************/ +/* This program is free software; you can redistribute it and/or */ +/* modify it under the terms of the GNU General Public License */ +/* as published by the Free Software Foundation; either version 2 */ +/* of the License, or (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU General Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License */ +/* along with this program; if not, write to the */ +/* Free Software Foundation, Inc., */ +/* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* */ +/*****************************************************************************/ +/* GNU LIBRARY GENERAL PUBLIC LICENSE: */ +/*****************************************************************************/ +/* */ +/* This library is free software; you can redistribute it and/or */ +/* modify it under the terms of the GNU Library General Public */ +/* License as published by the Free Software Foundation; either */ +/* version 2 of the License, or (at your option) any later version. */ +/* */ +/* This library is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU */ +/* Library General Public License for more details. */ +/* */ +/* You should have received a copy of the GNU Library General Public */ +/* License along with this library; if not, write to the */ +/* Free Software Foundation, Inc., */ +/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* */ +/* or download a copy from ftp://ftp.gnu.org/pub/gnu/COPYING.LIB-2.0 */ +/* */ +/*****************************************************************************/ +#endif diff --git a/contrib/tools/yasm/libyasm/bytecode.c b/contrib/tools/yasm/libyasm/bytecode.c index f864bae0aa..ee28c2b0d9 100644 --- a/contrib/tools/yasm/libyasm/bytecode.c +++ b/contrib/tools/yasm/libyasm/bytecode.c @@ -1,386 +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; -} +/* + * Bytecode utility functions + * + * Copyright (C) 2001-2007 Peter Johnson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include "util.h" + +#include "libyasm-stdint.h" +#include "coretype.h" + +#include "errwarn.h" +#include "intnum.h" +#include "expr.h" +#include "value.h" +#include "symrec.h" + +#include "bytecode.h" + + +void +yasm_bc_set_multiple(yasm_bytecode *bc, yasm_expr *e) +{ + if (bc->multiple) + bc->multiple = yasm_expr_create_tree(bc->multiple, YASM_EXPR_MUL, e, + e->line); + else + bc->multiple = e; +} + +void +yasm_bc_finalize_common(yasm_bytecode *bc, yasm_bytecode *prev_bc) +{ +} + +int +yasm_bc_calc_len_common(yasm_bytecode *bc, yasm_bc_add_span_func add_span, + void *add_span_data) +{ + yasm_internal_error(N_("bytecode length cannot be calculated")); + /*@unreached@*/ + return 0; +} + +int +yasm_bc_expand_common(yasm_bytecode *bc, int span, long old_val, long new_val, + /*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres) +{ + yasm_internal_error(N_("bytecode does not have any dependent spans")); + /*@unreached@*/ + return 0; +} + +int +yasm_bc_tobytes_common(yasm_bytecode *bc, unsigned char **buf, + unsigned char *bufstart, void *d, + yasm_output_value_func output_value, + /*@null@*/ yasm_output_reloc_func output_reloc) +{ + yasm_internal_error(N_("bytecode cannot be converted to bytes")); + /*@unreached@*/ + return 0; +} + +void +yasm_bc_transform(yasm_bytecode *bc, const yasm_bytecode_callback *callback, + void *contents) +{ + if (bc->callback) + bc->callback->destroy(bc->contents); + bc->callback = callback; + bc->contents = contents; +} + +yasm_bytecode * +yasm_bc_create_common(const yasm_bytecode_callback *callback, void *contents, + unsigned long line) +{ + yasm_bytecode *bc = yasm_xmalloc(sizeof(yasm_bytecode)); + + bc->callback = callback; + bc->section = NULL; + bc->multiple = (yasm_expr *)NULL; + bc->len = 0; + bc->mult_int = 1; + bc->line = line; + bc->offset = ~0UL; /* obviously incorrect / uninitialized value */ + bc->symrecs = NULL; + bc->contents = contents; + + return bc; +} + +yasm_section * +yasm_bc_get_section(yasm_bytecode *bc) +{ + return bc->section; +} + +void +yasm_bc__add_symrec(yasm_bytecode *bc, yasm_symrec *sym) +{ + if (!bc->symrecs) { + bc->symrecs = yasm_xmalloc(2*sizeof(yasm_symrec *)); + bc->symrecs[0] = sym; + bc->symrecs[1] = NULL; + } else { + /* Very inefficient implementation for large numbers of symbols. But + * that would be very unusual, so use the simple algorithm instead. + */ + size_t count = 1; + while (bc->symrecs[count]) + count++; + bc->symrecs = yasm_xrealloc(bc->symrecs, + (count+2)*sizeof(yasm_symrec *)); + bc->symrecs[count] = sym; + bc->symrecs[count+1] = NULL; + } +} + +void +yasm_bc_destroy(yasm_bytecode *bc) +{ + if (!bc) + return; + + if (bc->callback) + bc->callback->destroy(bc->contents); + yasm_expr_destroy(bc->multiple); + if (bc->symrecs) + yasm_xfree(bc->symrecs); + yasm_xfree(bc); +} + +void +yasm_bc_print(const yasm_bytecode *bc, FILE *f, int indent_level) +{ + if (!bc->callback) + fprintf(f, "%*s_Empty_\n", indent_level, ""); + else + bc->callback->print(bc->contents, f, indent_level); + fprintf(f, "%*sMultiple=", indent_level, ""); + if (!bc->multiple) + fprintf(f, "nil (1)"); + else + yasm_expr_print(bc->multiple, f); + fprintf(f, "\n%*sLength=%lu\n", indent_level, "", bc->len); + fprintf(f, "%*sLine Index=%lu\n", indent_level, "", bc->line); + fprintf(f, "%*sOffset=%lx\n", indent_level, "", bc->offset); +} + +void +yasm_bc_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc) +{ + if (bc->callback) + bc->callback->finalize(bc, prev_bc); + if (bc->multiple) { + yasm_value val; + + if (yasm_value_finalize_expr(&val, bc->multiple, prev_bc, 0)) + yasm_error_set(YASM_ERROR_TOO_COMPLEX, + N_("multiple expression too complex")); + else if (val.rel) + yasm_error_set(YASM_ERROR_NOT_ABSOLUTE, + N_("multiple expression not absolute")); + /* Finalize creates NULL output if value=0, but bc->multiple is NULL + * if value=1 (this difference is to make the common case small). + * However, this means we need to set bc->multiple explicitly to 0 + * here if val.abs is NULL. + */ + if (val.abs) + bc->multiple = val.abs; + else + bc->multiple = yasm_expr_create_ident( + yasm_expr_int(yasm_intnum_create_uint(0)), bc->line); + } +} + +/*@null@*/ yasm_intnum * +yasm_calc_bc_dist(yasm_bytecode *precbc1, yasm_bytecode *precbc2) +{ + unsigned long dist2, dist1; + yasm_intnum *intn; + + if (precbc1->section != precbc2->section) + return NULL; + + dist1 = yasm_bc_next_offset(precbc1); + dist2 = yasm_bc_next_offset(precbc2); + if (dist2 < dist1) { + intn = yasm_intnum_create_uint(dist1 - dist2); + yasm_intnum_calc(intn, YASM_EXPR_NEG, NULL); + return intn; + } + dist2 -= dist1; + return yasm_intnum_create_uint(dist2); +} + +unsigned long +yasm_bc_next_offset(yasm_bytecode *precbc) +{ + return precbc->offset + precbc->len*precbc->mult_int; +} + +int +yasm_bc_elem_size(yasm_bytecode *bc) +{ + if (!bc->callback) { + yasm_internal_error(N_("got empty bytecode in yasm_bc_elem_size")); + return 0; + } else if (!bc->callback->elem_size) + return 0; + else + return bc->callback->elem_size(bc); +} + +int +yasm_bc_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span, + void *add_span_data) +{ + int retval = 0; + + bc->len = 0; + + if (!bc->callback) + yasm_internal_error(N_("got empty bytecode in yasm_bc_calc_len")); + else + retval = bc->callback->calc_len(bc, add_span, add_span_data); + + /* Check for multiples */ + bc->mult_int = 1; + if (bc->multiple) { + /*@dependent@*/ /*@null@*/ const yasm_intnum *num; + + num = yasm_expr_get_intnum(&bc->multiple, 0); + if (num) { + if (yasm_intnum_sign(num) < 0) { + yasm_error_set(YASM_ERROR_VALUE, N_("multiple is negative")); + retval = -1; + } else + bc->mult_int = yasm_intnum_get_int(num); + } else { + if (yasm_expr__contains(bc->multiple, YASM_EXPR_FLOAT)) { + yasm_error_set(YASM_ERROR_VALUE, + N_("expression must not contain floating point value")); + retval = -1; + } else { + yasm_value value; + yasm_value_initialize(&value, bc->multiple, 0); + add_span(add_span_data, bc, 0, &value, 0, 0); + bc->mult_int = 0; /* assume 0 to start */ + } + } + } + + /* If we got an error somewhere along the line, clear out any calc len */ + if (retval < 0) + bc->len = 0; + + return retval; +} + +int +yasm_bc_expand(yasm_bytecode *bc, int span, long old_val, long new_val, + /*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres) +{ + if (span == 0) { + bc->mult_int = new_val; + return 1; + } + if (!bc->callback) { + yasm_internal_error(N_("got empty bytecode in yasm_bc_expand")); + /*@unreached@*/ + return -1; + } else + return bc->callback->expand(bc, span, old_val, new_val, neg_thres, + pos_thres); +} + +/*@null@*/ /*@only@*/ unsigned char * +yasm_bc_tobytes(yasm_bytecode *bc, unsigned char *buf, unsigned long *bufsize, + /*@out@*/ int *gap, void *d, + yasm_output_value_func output_value, + /*@null@*/ yasm_output_reloc_func output_reloc) + /*@sets *buf@*/ +{ + /*@only@*/ /*@null@*/ unsigned char *mybuf = NULL; + unsigned char *bufstart; + unsigned char *origbuf, *destbuf; + long i; + int error = 0; + + long mult; + if (yasm_bc_get_multiple(bc, &mult, 1) || mult == 0) { + *bufsize = 0; + return NULL; + } + bc->mult_int = mult; + + /* special case for reserve bytecodes */ + if (bc->callback->special == YASM_BC_SPECIAL_RESERVE) { + *bufsize = bc->len*bc->mult_int; + *gap = 1; + return NULL; /* we didn't allocate a buffer */ + } + *gap = 0; + + if (*bufsize < bc->len*bc->mult_int) { + mybuf = yasm_xmalloc(bc->len*bc->mult_int); + destbuf = mybuf; + } else + destbuf = buf; + bufstart = destbuf; + + *bufsize = bc->len*bc->mult_int; + + if (!bc->callback) + yasm_internal_error(N_("got empty bytecode in bc_tobytes")); + else for (i=0; i<bc->mult_int; i++) { + origbuf = destbuf; + error = bc->callback->tobytes(bc, &destbuf, bufstart, d, output_value, + output_reloc); + + if (!error && ((unsigned long)(destbuf - origbuf) != bc->len)) + yasm_internal_error( + N_("written length does not match optimized length")); + } + + return mybuf; +} + +int +yasm_bc_get_multiple(yasm_bytecode *bc, long *multiple, int calc_bc_dist) +{ + /*@dependent@*/ /*@null@*/ const yasm_intnum *num; + + *multiple = 1; + if (bc->multiple) { + num = yasm_expr_get_intnum(&bc->multiple, calc_bc_dist); + if (!num) { + yasm_error_set(YASM_ERROR_VALUE, + N_("could not determine multiple")); + return 1; + } + if (yasm_intnum_sign(num) < 0) { + yasm_error_set(YASM_ERROR_VALUE, N_("multiple is negative")); + return 1; + } + *multiple = yasm_intnum_get_int(num); + } + return 0; +} + +const yasm_expr * +yasm_bc_get_multiple_expr(const yasm_bytecode *bc) +{ + return bc->multiple; +} + +yasm_insn * +yasm_bc_get_insn(yasm_bytecode *bc) +{ + if (bc->callback->special != YASM_BC_SPECIAL_INSN) + return NULL; + return (yasm_insn *)bc->contents; +} diff --git a/contrib/tools/yasm/libyasm/bytecode.h b/contrib/tools/yasm/libyasm/bytecode.h index 47cd26244b..fc75e57d0e 100644 --- a/contrib/tools/yasm/libyasm/bytecode.h +++ b/contrib/tools/yasm/libyasm/bytecode.h @@ -1,638 +1,638 @@ -/** - * \file libyasm/bytecode.h - * \brief YASM bytecode interface. - * - * \license - * Copyright (C) 2001-2007 Peter Johnson - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * \endlicense - */ -#ifndef YASM_BYTECODE_H -#define YASM_BYTECODE_H - -#ifndef YASM_LIB_DECL -#define YASM_LIB_DECL -#endif - -/** A data value (opaque type). */ -typedef struct yasm_dataval yasm_dataval; -/** A list of data values. */ -typedef struct yasm_datavalhead yasm_datavalhead; - -/** Linked list of data values. */ -/*@reldef@*/ STAILQ_HEAD(yasm_datavalhead, yasm_dataval); - -/** Add a dependent span for a bytecode. - * \param add_span_data add_span_data passed into bc_calc_len() - * \param bc bytecode containing span - * \param id non-zero identifier for span; may be any non-zero value - * if <0, expand is called for any change; - * if >0, expand is only called when exceeds threshold - * \param value dependent value for bytecode expansion - * \param neg_thres negative threshold for long/short decision - * \param pos_thres positive threshold for long/short decision - */ -typedef void (*yasm_bc_add_span_func) - (void *add_span_data, yasm_bytecode *bc, int id, const yasm_value *value, - long neg_thres, long pos_thres); - -/** Bytecode callback structure. Any implementation of a specific bytecode - * must implement these functions and this callback structure. The bytecode - * implementation-specific data is stored in #yasm_bytecode.contents. - */ -typedef struct yasm_bytecode_callback { - /** Destroys the implementation-specific data. - * Called from yasm_bc_destroy(). - * \param contents #yasm_bytecode.contents - */ - void (*destroy) (/*@only@*/ void *contents); - - /** Prints the implementation-specific data (for debugging purposes). - * Called from yasm_bc_print(). - * \param contents #yasm_bytecode.contents - * \param f file - * \param indent_level indentation level - */ - void (*print) (const void *contents, FILE *f, int indent_level); - - /** Finalizes the bytecode after parsing. Called from yasm_bc_finalize(). - * A generic fill-in for this is yasm_bc_finalize_common(). - * \param bc bytecode - * \param prev_bc bytecode directly preceding bc - */ - void (*finalize) (yasm_bytecode *bc, yasm_bytecode *prev_bc); - - /** Return elements size of a data bytecode. - * This function should return the size of each elements of a data - * bytecode, for proper dereference of symbols attached to it. - * \param bc bytecode - * \return 0 if element size is unknown. - */ - int (*elem_size) (yasm_bytecode *bc); - - /** Calculates the minimum size of a bytecode. - * Called from yasm_bc_calc_len(). - * A generic fill-in for this is yasm_bc_calc_len_common(), but as this - * function internal errors when called, be very careful when using it! - * This function should simply add to bc->len and not set it directly - * (it's initialized by yasm_bc_calc_len() prior to passing control to - * this function). - * - * \param bc bytecode - * \param add_span function to call to add a span - * \param add_span_data extra data to be passed to add_span function - * \return 0 if no error occurred, nonzero if there was an error - * recognized (and output) during execution. - * \note May store to bytecode updated expressions. - */ - int (*calc_len) (yasm_bytecode *bc, yasm_bc_add_span_func add_span, - void *add_span_data); - - /** Recalculates the bytecode's length based on an expanded span length. - * Called from yasm_bc_expand(). - * A generic fill-in for this is yasm_bc_expand_common(), but as this - * function internal errors when called, if used, ensure that calc_len() - * never adds a span. - * This function should simply add to bc->len to increase the length by - * a delta amount. - * \param bc bytecode - * \param span span ID (as given to add_span in calc_len) - * \param old_val previous span value - * \param new_val new span value - * \param neg_thres negative threshold for long/short decision - * (returned) - * \param pos_thres positive threshold for long/short decision - * (returned) - * \return 0 if bc no longer dependent on this span's length, negative if - * there was an error recognized (and output) during execution, - * and positive if bc size may increase for this span further - * based on the new negative and positive thresholds returned. - * \note May store to bytecode updated expressions. - */ - int (*expand) (yasm_bytecode *bc, int span, long old_val, long new_val, - /*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres); - - /** Convert a bytecode into its byte representation. - * Called from yasm_bc_tobytes(). - * A generic fill-in for this is yasm_bc_tobytes_common(), but as this - * function internal errors when called, be very careful when using it! - * \param bc bytecode - * \param bufp byte representation destination buffer; - * should be incremented as it's written to, - * so that on return its delta from the - * passed-in buf matches the bytecode length - * (it's okay not to do this if an error - * indication is returned) - * \param bufstart For calculating the correct offset parameter for - * the \a output_value calls: *bufp - bufstart. - * \param d data to pass to each call to - * output_value/output_reloc - * \param output_value function to call to convert values into their byte - * representation - * \param output_reloc function to call to output relocation entries - * for a single sym - * \return Nonzero on error, 0 on success. - * \note May result in non-reversible changes to the bytecode, but it's - * preferable if calling this function twice would result in the - * same output. - */ - int (*tobytes) (yasm_bytecode *bc, unsigned char **bufp, - unsigned char *bufstart, void *d, - yasm_output_value_func output_value, - /*@null@*/ yasm_output_reloc_func output_reloc); - - /** Special bytecode classifications. Most bytecode types should use - * #YASM_BC_SPECIAL_NONE. Others cause special handling to kick in - * in various parts of yasm. - */ - enum yasm_bytecode_special_type { - YASM_BC_SPECIAL_NONE = 0, - - /** Bytecode reserves space instead of outputting data. */ - YASM_BC_SPECIAL_RESERVE, - - /** Adjusts offset instead of calculating len. */ - YASM_BC_SPECIAL_OFFSET, - - /** Instruction bytecode. */ - YASM_BC_SPECIAL_INSN - } special; -} yasm_bytecode_callback; - -/** A bytecode. */ -struct yasm_bytecode { - /** Bytecodes are stored as a singly linked list, with tail insertion. - * \see section.h (#yasm_section). - */ - /*@reldef@*/ STAILQ_ENTRY(yasm_bytecode) link; - - /** The bytecode callback structure for this bytecode. May be NULL - * during partial initialization. - */ - /*@null@*/ const yasm_bytecode_callback *callback; - - /** Pointer to section containing bytecode; NULL if not part of a - * section. - */ - /*@dependent@*/ /*@null@*/ yasm_section *section; - - /** Number of times bytecode is repeated. - * NULL=1 (to save space in the common case). - */ - /*@only@*/ /*@null@*/ yasm_expr *multiple; - - /** Total length of entire bytecode (not including multiple copies). */ - unsigned long len; - - /** Number of copies, integer version. */ - long mult_int; - - /** Line number where bytecode was defined. */ - unsigned long line; - - /** Offset of bytecode from beginning of its section. - * 0-based, ~0UL (e.g. all 1 bits) if unknown. - */ - unsigned long offset; - - /** Unique integer index of bytecode. Used during optimization. */ - unsigned long bc_index; - - /** NULL-terminated array of labels that point to this bytecode (as the - * bytecode previous to the label). NULL if no labels point here. - */ - /*@null@*/ yasm_symrec **symrecs; - - /** Implementation-specific data (type identified by callback). */ - void *contents; -}; - -/** Create a bytecode of any specified type. - * \param callback bytecode callback functions, if NULL, creates empty - * bytecode (may not be resolved or output) - * \param contents type-specific data - * \param line virtual line (from yasm_linemap) - * \return Newly allocated bytecode of the specified type. - */ -YASM_LIB_DECL -/*@only@*/ yasm_bytecode *yasm_bc_create_common - (/*@null@*/ const yasm_bytecode_callback *callback, - /*@only@*/ /*@null@*/ void *contents, unsigned long line); - -/** Transform a bytecode of any type into a different type. - * \param bc bytecode to transform - * \param callback new bytecode callback function - * \param contents new type-specific data - */ -YASM_LIB_DECL -void yasm_bc_transform(yasm_bytecode *bc, - const yasm_bytecode_callback *callback, - void *contents); - -/** Common bytecode callback finalize function, for where no finalization - * is ever required for this type of bytecode. - */ -YASM_LIB_DECL -void yasm_bc_finalize_common(yasm_bytecode *bc, yasm_bytecode *prev_bc); - -/** Common bytecode callback calc_len function, for where the bytecode has - * no calculatable length. Causes an internal error if called. - */ -YASM_LIB_DECL -int yasm_bc_calc_len_common(yasm_bytecode *bc, yasm_bc_add_span_func add_span, - void *add_span_data); - -/** Common bytecode callback expand function, for where the bytecode is - * always short (calc_len never calls add_span). Causes an internal - * error if called. - */ -YASM_LIB_DECL -int yasm_bc_expand_common - (yasm_bytecode *bc, int span, long old_val, long new_val, - /*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres); - -/** Common bytecode callback tobytes function, for where the bytecode - * cannot be converted to bytes. Causes an internal error if called. - */ -YASM_LIB_DECL -int yasm_bc_tobytes_common - (yasm_bytecode *bc, unsigned char **bufp, unsigned char *bufstart, void *d, - yasm_output_value_func output_value, - /*@null@*/ yasm_output_reloc_func output_reloc); - -/** Get the next bytecode in a linked list of bytecodes. - * \param bc bytecode - * \return Next bytecode. - */ -#define yasm_bc__next(bc) STAILQ_NEXT(bc, link) - -/** Set multiple field of a bytecode. - * A bytecode can be repeated a number of times when output. This function - * sets that multiple. - * \param bc bytecode - * \param e multiple (kept, do not free) - */ -YASM_LIB_DECL -void yasm_bc_set_multiple(yasm_bytecode *bc, /*@keep@*/ yasm_expr *e); - -/** Create a bytecode containing data value(s). - * \param datahead list of data values (kept, do not free) - * \param size storage size (in bytes) for each data value - * \param append_zero append a single zero byte after each data value - * (if non-zero) - * \param arch architecture (optional); if provided, data items - * are directly simplified to bytes if possible - * \param line virtual line (from yasm_linemap) - * \return Newly allocated bytecode. - */ -YASM_LIB_DECL -/*@only@*/ yasm_bytecode *yasm_bc_create_data - (yasm_datavalhead *datahead, unsigned int size, int append_zero, - /*@null@*/ yasm_arch *arch, unsigned long line); - -/** Create a bytecode containing LEB128-encoded data value(s). - * \param datahead list of data values (kept, do not free) - * \param sign signedness (1=signed, 0=unsigned) of each data value - * \param line virtual line (from yasm_linemap) - * \return Newly allocated bytecode. - */ -YASM_LIB_DECL -/*@only@*/ yasm_bytecode *yasm_bc_create_leb128 - (yasm_datavalhead *datahead, int sign, unsigned long line); - -/** Create a bytecode reserving space. - * \param numitems number of reserve "items" (kept, do not free) - * \param itemsize reserved size (in bytes) for each item - * \param line virtual line (from yasm_linemap) - * \return Newly allocated bytecode. - */ -YASM_LIB_DECL -/*@only@*/ yasm_bytecode *yasm_bc_create_reserve - (/*@only@*/ yasm_expr *numitems, unsigned int itemsize, - unsigned long line); - -/** Get the number of items and itemsize for a reserve bytecode. If bc - * is not a reserve bytecode, returns NULL. - * \param bc bytecode - * \param itemsize reserved size (in bytes) for each item (returned) - * \return NULL if bc is not a reserve bytecode, otherwise an expression - * for the number of items to reserve. - */ -YASM_LIB_DECL -/*@null@*/ const yasm_expr *yasm_bc_reserve_numitems - (yasm_bytecode *bc, /*@out@*/ unsigned int *itemsize); - -/** Create a bytecode that includes a binary file verbatim. - * \param filename path to binary file (kept, do not free) - * \param start starting location in file (in bytes) to read data from - * (kept, do not free); may be NULL to indicate 0 - * \param maxlen maximum number of bytes to read from the file (kept, do - * do not free); may be NULL to indicate no maximum - * \param linemap line mapping repository - * \param line virtual line (from yasm_linemap) for the bytecode - * \return Newly allocated bytecode. - */ -YASM_LIB_DECL -/*@only@*/ yasm_bytecode *yasm_bc_create_incbin - (/*@only@*/ char *filename, /*@only@*/ /*@null@*/ yasm_expr *start, - /*@only@*/ /*@null@*/ yasm_expr *maxlen, yasm_linemap *linemap, - unsigned long line); - -/** Create a bytecode that aligns the following bytecode to a boundary. - * \param boundary byte alignment (must be a power of two) - * \param fill fill data (if NULL, code_fill or 0 is used) - * \param maxskip maximum number of bytes to skip - * \param code_fill code fill data (if NULL, 0 is used) - * \param line virtual line (from yasm_linemap) - * \return Newly allocated bytecode. - * \note The precedence on generated fill is as follows: - * - from fill parameter (if not NULL) - * - from code_fill parameter (if not NULL) - * - 0 - */ -YASM_LIB_DECL -/*@only@*/ yasm_bytecode *yasm_bc_create_align - (/*@keep@*/ yasm_expr *boundary, /*@keep@*/ /*@null@*/ yasm_expr *fill, - /*@keep@*/ /*@null@*/ yasm_expr *maxskip, - /*@null@*/ const unsigned char **code_fill, unsigned long line); - -/** Create a bytecode that puts the following bytecode at a fixed section - * offset. - * \param start section offset of following bytecode - * \param fill fill value - * \param line virtual line (from yasm_linemap) - * \return Newly allocated bytecode. - */ -YASM_LIB_DECL -/*@only@*/ yasm_bytecode *yasm_bc_create_org - (unsigned long start, unsigned long fill, unsigned long line); - -/** Get the section that contains a particular bytecode. - * \param bc bytecode - * \return Section containing bc (can be NULL if bytecode is not part of a - * section). - */ -YASM_LIB_DECL -/*@dependent@*/ /*@null@*/ yasm_section *yasm_bc_get_section - (yasm_bytecode *bc); - -/** Add to the list of symrecs that reference a bytecode. For symrec use - * only. - * \param bc bytecode - * \param sym symbol - */ -YASM_LIB_DECL -void yasm_bc__add_symrec(yasm_bytecode *bc, /*@dependent@*/ yasm_symrec *sym); - -/** Delete (free allocated memory for) a bytecode. - * \param bc bytecode (only pointer to it); may be NULL - */ -YASM_LIB_DECL -void yasm_bc_destroy(/*@only@*/ /*@null@*/ yasm_bytecode *bc); - -/** Print a bytecode. For debugging purposes. - * \param f file - * \param indent_level indentation level - * \param bc bytecode - */ -YASM_LIB_DECL -void yasm_bc_print(const yasm_bytecode *bc, FILE *f, int indent_level); - -/** Finalize a bytecode after parsing. - * \param bc bytecode - * \param prev_bc bytecode directly preceding bc in a list of bytecodes - */ -YASM_LIB_DECL -void yasm_bc_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc); - -/** Determine the distance between the starting offsets of two bytecodes. - * \param precbc1 preceding bytecode to the first bytecode - * \param precbc2 preceding bytecode to the second bytecode - * \return Distance in bytes between the two bytecodes (bc2-bc1), or NULL if - * the distance was indeterminate. - * \warning Only valid /after/ optimization. - */ -YASM_LIB_DECL -/*@null@*/ /*@only@*/ yasm_intnum *yasm_calc_bc_dist - (yasm_bytecode *precbc1, yasm_bytecode *precbc2); - -/** Get the offset of the next bytecode (the next bytecode doesn't have to - * actually exist). - * \param precbc preceding bytecode - * \return Offset of the next bytecode in bytes. - * \warning Only valid /after/ optimization. - */ -YASM_LIB_DECL -unsigned long yasm_bc_next_offset(yasm_bytecode *precbc); - -/** Return elemens size of a data bytecode. - * Returns the size of each elements of a data bytecode, for proper dereference - * of symbols attached to it. - * \param bc bytecode - * \return 0 if element size is unknown - */ -YASM_LIB_DECL -int yasm_bc_elem_size(yasm_bytecode *bc); - -/** Resolve EQUs in a bytecode and calculate its minimum size. - * Generates dependent bytecode spans for cases where, if the length spanned - * increases, it could cause the bytecode size to increase. - * Any bytecode multiple is NOT included in the length or spans generation; - * this must be handled at a higher level. - * \param bc bytecode - * \param add_span function to call to add a span - * \param add_span_data extra data to be passed to add_span function - * \return 0 if no error occurred, nonzero if there was an error recognized - * (and output) during execution. - * \note May store to bytecode updated expressions and the short length. - */ -YASM_LIB_DECL -int yasm_bc_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span, - void *add_span_data); - -/** Recalculate a bytecode's length based on an expanded span length. - * \param bc bytecode - * \param span span ID (as given to yasm_bc_add_span_func in - * yasm_bc_calc_len) - * \param old_val previous span value - * \param new_val new span value - * \param neg_thres negative threshold for long/short decision (returned) - * \param pos_thres positive threshold for long/short decision (returned) - * \return 0 if bc no longer dependent on this span's length, negative if - * there was an error recognized (and output) during execution, and - * positive if bc size may increase for this span further based on the - * new negative and positive thresholds returned. - * \note May store to bytecode updated expressions and the updated length. - */ -YASM_LIB_DECL -int yasm_bc_expand(yasm_bytecode *bc, int span, long old_val, long new_val, - /*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres); - -/** Convert a bytecode into its byte representation. - * \param bc bytecode - * \param buf byte representation destination buffer - * \param bufsize size of buf (in bytes) prior to call; size of the - * generated data after call - * \param gap if nonzero, indicates the data does not really need to - * exist in the object file; if nonzero, contents of buf - * are undefined [output] - * \param d data to pass to each call to output_value/output_reloc - * \param output_value function to call to convert values into their byte - * representation - * \param output_reloc function to call to output relocation entries - * for a single sym - * \return Newly allocated buffer that should be used instead of buf for - * reading the byte representation, or NULL if buf was big enough to - * hold the entire byte representation. - * \note Calling twice on the same bytecode may \em not produce the same - * results on the second call, as calling this function may result in - * non-reversible changes to the bytecode. - */ -YASM_LIB_DECL -/*@null@*/ /*@only@*/ unsigned char *yasm_bc_tobytes - (yasm_bytecode *bc, unsigned char *buf, unsigned long *bufsize, - /*@out@*/ int *gap, void *d, yasm_output_value_func output_value, - /*@null@*/ yasm_output_reloc_func output_reloc) - /*@sets *buf@*/; - -/** Get the bytecode multiple value as an integer. - * \param bc bytecode - * \param multiple multiple value (output) - * \param calc_bc_dist nonzero if distances between bytecodes should be - * calculated, 0 if error should be returned in this case - * \return 1 on error (set with yasm_error_set), 0 on success. - */ -YASM_LIB_DECL -int yasm_bc_get_multiple(yasm_bytecode *bc, /*@out@*/ long *multiple, - int calc_bc_dist); - -/** Get the bytecode multiple value as an expression. - * \param bc bytecode - * \return Bytecode multiple, NULL if =1. - */ -YASM_LIB_DECL -const yasm_expr *yasm_bc_get_multiple_expr(const yasm_bytecode *bc); - -/** Get a #yasm_insn structure from an instruction bytecode (if possible). - * \param bc bytecode - * \return Instruction details if bytecode is an instruction bytecode, - * otherwise NULL. - */ -YASM_LIB_DECL -/*@dependent@*/ /*@null@*/ yasm_insn *yasm_bc_get_insn(yasm_bytecode *bc); - -/** Create a new data value from an expression. - * \param expn expression - * \return Newly allocated data value. - */ -YASM_LIB_DECL -yasm_dataval *yasm_dv_create_expr(/*@keep@*/ yasm_expr *expn); - -/** Create a new data value from a string. - * \param contents string (may contain NULs) - * \param len length of string - * \return Newly allocated data value. - */ -YASM_LIB_DECL -yasm_dataval *yasm_dv_create_string(/*@keep@*/ char *contents, size_t len); - -/** Create a new data value from raw bytes data. - * \param contents raw data (may contain NULs) - * \param len length - * \return Newly allocated data value. - */ -YASM_LIB_DECL -yasm_dataval *yasm_dv_create_raw(/*@keep@*/ unsigned char *contents, - unsigned long len); - -/** Create a new uninitialized data value. - * \return Newly allocated data value. - */ -YASM_LIB_DECL -yasm_dataval *yasm_dv_create_reserve(void); - -#ifndef YASM_DOXYGEN -#define yasm_dv_create_string(s, l) yasm_dv_create_raw((unsigned char *)(s), \ - (unsigned long)(l)) -#endif - -/** Get the underlying value of a data value. - * \param dv data value - * \return Value, or null if non-value (e.g. string or raw). - */ -YASM_LIB_DECL -yasm_value *yasm_dv_get_value(yasm_dataval *dv); - -/** Set multiple field of a data value. - * A data value can be repeated a number of times when output. This function - * sets that multiple. - * \param dv data value - * \param e multiple (kept, do not free) - */ -YASM_LIB_DECL -void yasm_dv_set_multiple(yasm_dataval *dv, /*@keep@*/ yasm_expr *e); - -/** Get the data value multiple value as an unsigned long integer. - * \param dv data value - * \param multiple multiple value (output) - * \return 1 on error (set with yasm_error_set), 0 on success. - */ -YASM_LIB_DECL -int yasm_dv_get_multiple(yasm_dataval *dv, /*@out@*/ unsigned long *multiple); - -/** Initialize a list of data values. - * \param headp list of data values - */ -void yasm_dvs_initialize(yasm_datavalhead *headp); -#ifndef YASM_DOXYGEN -#define yasm_dvs_initialize(headp) STAILQ_INIT(headp) -#endif - -/** Delete (free allocated memory for) a list of data values. - * \param headp list of data values - */ -YASM_LIB_DECL -void yasm_dvs_delete(yasm_datavalhead *headp); - -/** Add data value to the end of a list of data values. - * \note Does not make a copy of the data value; so don't pass this function - * static or local variables, and discard the dv pointer after calling - * this function. - * \param headp data value list - * \param dv data value (may be NULL) - * \return If data value was actually appended (it wasn't NULL), the data - * value; otherwise NULL. - */ -YASM_LIB_DECL -/*@null@*/ yasm_dataval *yasm_dvs_append - (yasm_datavalhead *headp, /*@returned@*/ /*@null@*/ yasm_dataval *dv); - -/** Print a data value list. For debugging purposes. - * \param f file - * \param indent_level indentation level - * \param headp data value list - */ -YASM_LIB_DECL -void yasm_dvs_print(const yasm_datavalhead *headp, FILE *f, int indent_level); - -#endif +/** + * \file libyasm/bytecode.h + * \brief YASM bytecode interface. + * + * \license + * Copyright (C) 2001-2007 Peter Johnson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * \endlicense + */ +#ifndef YASM_BYTECODE_H +#define YASM_BYTECODE_H + +#ifndef YASM_LIB_DECL +#define YASM_LIB_DECL +#endif + +/** A data value (opaque type). */ +typedef struct yasm_dataval yasm_dataval; +/** A list of data values. */ +typedef struct yasm_datavalhead yasm_datavalhead; + +/** Linked list of data values. */ +/*@reldef@*/ STAILQ_HEAD(yasm_datavalhead, yasm_dataval); + +/** Add a dependent span for a bytecode. + * \param add_span_data add_span_data passed into bc_calc_len() + * \param bc bytecode containing span + * \param id non-zero identifier for span; may be any non-zero value + * if <0, expand is called for any change; + * if >0, expand is only called when exceeds threshold + * \param value dependent value for bytecode expansion + * \param neg_thres negative threshold for long/short decision + * \param pos_thres positive threshold for long/short decision + */ +typedef void (*yasm_bc_add_span_func) + (void *add_span_data, yasm_bytecode *bc, int id, const yasm_value *value, + long neg_thres, long pos_thres); + +/** Bytecode callback structure. Any implementation of a specific bytecode + * must implement these functions and this callback structure. The bytecode + * implementation-specific data is stored in #yasm_bytecode.contents. + */ +typedef struct yasm_bytecode_callback { + /** Destroys the implementation-specific data. + * Called from yasm_bc_destroy(). + * \param contents #yasm_bytecode.contents + */ + void (*destroy) (/*@only@*/ void *contents); + + /** Prints the implementation-specific data (for debugging purposes). + * Called from yasm_bc_print(). + * \param contents #yasm_bytecode.contents + * \param f file + * \param indent_level indentation level + */ + void (*print) (const void *contents, FILE *f, int indent_level); + + /** Finalizes the bytecode after parsing. Called from yasm_bc_finalize(). + * A generic fill-in for this is yasm_bc_finalize_common(). + * \param bc bytecode + * \param prev_bc bytecode directly preceding bc + */ + void (*finalize) (yasm_bytecode *bc, yasm_bytecode *prev_bc); + + /** Return elements size of a data bytecode. + * This function should return the size of each elements of a data + * bytecode, for proper dereference of symbols attached to it. + * \param bc bytecode + * \return 0 if element size is unknown. + */ + int (*elem_size) (yasm_bytecode *bc); + + /** Calculates the minimum size of a bytecode. + * Called from yasm_bc_calc_len(). + * A generic fill-in for this is yasm_bc_calc_len_common(), but as this + * function internal errors when called, be very careful when using it! + * This function should simply add to bc->len and not set it directly + * (it's initialized by yasm_bc_calc_len() prior to passing control to + * this function). + * + * \param bc bytecode + * \param add_span function to call to add a span + * \param add_span_data extra data to be passed to add_span function + * \return 0 if no error occurred, nonzero if there was an error + * recognized (and output) during execution. + * \note May store to bytecode updated expressions. + */ + int (*calc_len) (yasm_bytecode *bc, yasm_bc_add_span_func add_span, + void *add_span_data); + + /** Recalculates the bytecode's length based on an expanded span length. + * Called from yasm_bc_expand(). + * A generic fill-in for this is yasm_bc_expand_common(), but as this + * function internal errors when called, if used, ensure that calc_len() + * never adds a span. + * This function should simply add to bc->len to increase the length by + * a delta amount. + * \param bc bytecode + * \param span span ID (as given to add_span in calc_len) + * \param old_val previous span value + * \param new_val new span value + * \param neg_thres negative threshold for long/short decision + * (returned) + * \param pos_thres positive threshold for long/short decision + * (returned) + * \return 0 if bc no longer dependent on this span's length, negative if + * there was an error recognized (and output) during execution, + * and positive if bc size may increase for this span further + * based on the new negative and positive thresholds returned. + * \note May store to bytecode updated expressions. + */ + int (*expand) (yasm_bytecode *bc, int span, long old_val, long new_val, + /*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres); + + /** Convert a bytecode into its byte representation. + * Called from yasm_bc_tobytes(). + * A generic fill-in for this is yasm_bc_tobytes_common(), but as this + * function internal errors when called, be very careful when using it! + * \param bc bytecode + * \param bufp byte representation destination buffer; + * should be incremented as it's written to, + * so that on return its delta from the + * passed-in buf matches the bytecode length + * (it's okay not to do this if an error + * indication is returned) + * \param bufstart For calculating the correct offset parameter for + * the \a output_value calls: *bufp - bufstart. + * \param d data to pass to each call to + * output_value/output_reloc + * \param output_value function to call to convert values into their byte + * representation + * \param output_reloc function to call to output relocation entries + * for a single sym + * \return Nonzero on error, 0 on success. + * \note May result in non-reversible changes to the bytecode, but it's + * preferable if calling this function twice would result in the + * same output. + */ + int (*tobytes) (yasm_bytecode *bc, unsigned char **bufp, + unsigned char *bufstart, void *d, + yasm_output_value_func output_value, + /*@null@*/ yasm_output_reloc_func output_reloc); + + /** Special bytecode classifications. Most bytecode types should use + * #YASM_BC_SPECIAL_NONE. Others cause special handling to kick in + * in various parts of yasm. + */ + enum yasm_bytecode_special_type { + YASM_BC_SPECIAL_NONE = 0, + + /** Bytecode reserves space instead of outputting data. */ + YASM_BC_SPECIAL_RESERVE, + + /** Adjusts offset instead of calculating len. */ + YASM_BC_SPECIAL_OFFSET, + + /** Instruction bytecode. */ + YASM_BC_SPECIAL_INSN + } special; +} yasm_bytecode_callback; + +/** A bytecode. */ +struct yasm_bytecode { + /** Bytecodes are stored as a singly linked list, with tail insertion. + * \see section.h (#yasm_section). + */ + /*@reldef@*/ STAILQ_ENTRY(yasm_bytecode) link; + + /** The bytecode callback structure for this bytecode. May be NULL + * during partial initialization. + */ + /*@null@*/ const yasm_bytecode_callback *callback; + + /** Pointer to section containing bytecode; NULL if not part of a + * section. + */ + /*@dependent@*/ /*@null@*/ yasm_section *section; + + /** Number of times bytecode is repeated. + * NULL=1 (to save space in the common case). + */ + /*@only@*/ /*@null@*/ yasm_expr *multiple; + + /** Total length of entire bytecode (not including multiple copies). */ + unsigned long len; + + /** Number of copies, integer version. */ + long mult_int; + + /** Line number where bytecode was defined. */ + unsigned long line; + + /** Offset of bytecode from beginning of its section. + * 0-based, ~0UL (e.g. all 1 bits) if unknown. + */ + unsigned long offset; + + /** Unique integer index of bytecode. Used during optimization. */ + unsigned long bc_index; + + /** NULL-terminated array of labels that point to this bytecode (as the + * bytecode previous to the label). NULL if no labels point here. + */ + /*@null@*/ yasm_symrec **symrecs; + + /** Implementation-specific data (type identified by callback). */ + void *contents; +}; + +/** Create a bytecode of any specified type. + * \param callback bytecode callback functions, if NULL, creates empty + * bytecode (may not be resolved or output) + * \param contents type-specific data + * \param line virtual line (from yasm_linemap) + * \return Newly allocated bytecode of the specified type. + */ +YASM_LIB_DECL +/*@only@*/ yasm_bytecode *yasm_bc_create_common + (/*@null@*/ const yasm_bytecode_callback *callback, + /*@only@*/ /*@null@*/ void *contents, unsigned long line); + +/** Transform a bytecode of any type into a different type. + * \param bc bytecode to transform + * \param callback new bytecode callback function + * \param contents new type-specific data + */ +YASM_LIB_DECL +void yasm_bc_transform(yasm_bytecode *bc, + const yasm_bytecode_callback *callback, + void *contents); + +/** Common bytecode callback finalize function, for where no finalization + * is ever required for this type of bytecode. + */ +YASM_LIB_DECL +void yasm_bc_finalize_common(yasm_bytecode *bc, yasm_bytecode *prev_bc); + +/** Common bytecode callback calc_len function, for where the bytecode has + * no calculatable length. Causes an internal error if called. + */ +YASM_LIB_DECL +int yasm_bc_calc_len_common(yasm_bytecode *bc, yasm_bc_add_span_func add_span, + void *add_span_data); + +/** Common bytecode callback expand function, for where the bytecode is + * always short (calc_len never calls add_span). Causes an internal + * error if called. + */ +YASM_LIB_DECL +int yasm_bc_expand_common + (yasm_bytecode *bc, int span, long old_val, long new_val, + /*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres); + +/** Common bytecode callback tobytes function, for where the bytecode + * cannot be converted to bytes. Causes an internal error if called. + */ +YASM_LIB_DECL +int yasm_bc_tobytes_common + (yasm_bytecode *bc, unsigned char **bufp, unsigned char *bufstart, void *d, + yasm_output_value_func output_value, + /*@null@*/ yasm_output_reloc_func output_reloc); + +/** Get the next bytecode in a linked list of bytecodes. + * \param bc bytecode + * \return Next bytecode. + */ +#define yasm_bc__next(bc) STAILQ_NEXT(bc, link) + +/** Set multiple field of a bytecode. + * A bytecode can be repeated a number of times when output. This function + * sets that multiple. + * \param bc bytecode + * \param e multiple (kept, do not free) + */ +YASM_LIB_DECL +void yasm_bc_set_multiple(yasm_bytecode *bc, /*@keep@*/ yasm_expr *e); + +/** Create a bytecode containing data value(s). + * \param datahead list of data values (kept, do not free) + * \param size storage size (in bytes) for each data value + * \param append_zero append a single zero byte after each data value + * (if non-zero) + * \param arch architecture (optional); if provided, data items + * are directly simplified to bytes if possible + * \param line virtual line (from yasm_linemap) + * \return Newly allocated bytecode. + */ +YASM_LIB_DECL +/*@only@*/ yasm_bytecode *yasm_bc_create_data + (yasm_datavalhead *datahead, unsigned int size, int append_zero, + /*@null@*/ yasm_arch *arch, unsigned long line); + +/** Create a bytecode containing LEB128-encoded data value(s). + * \param datahead list of data values (kept, do not free) + * \param sign signedness (1=signed, 0=unsigned) of each data value + * \param line virtual line (from yasm_linemap) + * \return Newly allocated bytecode. + */ +YASM_LIB_DECL +/*@only@*/ yasm_bytecode *yasm_bc_create_leb128 + (yasm_datavalhead *datahead, int sign, unsigned long line); + +/** Create a bytecode reserving space. + * \param numitems number of reserve "items" (kept, do not free) + * \param itemsize reserved size (in bytes) for each item + * \param line virtual line (from yasm_linemap) + * \return Newly allocated bytecode. + */ +YASM_LIB_DECL +/*@only@*/ yasm_bytecode *yasm_bc_create_reserve + (/*@only@*/ yasm_expr *numitems, unsigned int itemsize, + unsigned long line); + +/** Get the number of items and itemsize for a reserve bytecode. If bc + * is not a reserve bytecode, returns NULL. + * \param bc bytecode + * \param itemsize reserved size (in bytes) for each item (returned) + * \return NULL if bc is not a reserve bytecode, otherwise an expression + * for the number of items to reserve. + */ +YASM_LIB_DECL +/*@null@*/ const yasm_expr *yasm_bc_reserve_numitems + (yasm_bytecode *bc, /*@out@*/ unsigned int *itemsize); + +/** Create a bytecode that includes a binary file verbatim. + * \param filename path to binary file (kept, do not free) + * \param start starting location in file (in bytes) to read data from + * (kept, do not free); may be NULL to indicate 0 + * \param maxlen maximum number of bytes to read from the file (kept, do + * do not free); may be NULL to indicate no maximum + * \param linemap line mapping repository + * \param line virtual line (from yasm_linemap) for the bytecode + * \return Newly allocated bytecode. + */ +YASM_LIB_DECL +/*@only@*/ yasm_bytecode *yasm_bc_create_incbin + (/*@only@*/ char *filename, /*@only@*/ /*@null@*/ yasm_expr *start, + /*@only@*/ /*@null@*/ yasm_expr *maxlen, yasm_linemap *linemap, + unsigned long line); + +/** Create a bytecode that aligns the following bytecode to a boundary. + * \param boundary byte alignment (must be a power of two) + * \param fill fill data (if NULL, code_fill or 0 is used) + * \param maxskip maximum number of bytes to skip + * \param code_fill code fill data (if NULL, 0 is used) + * \param line virtual line (from yasm_linemap) + * \return Newly allocated bytecode. + * \note The precedence on generated fill is as follows: + * - from fill parameter (if not NULL) + * - from code_fill parameter (if not NULL) + * - 0 + */ +YASM_LIB_DECL +/*@only@*/ yasm_bytecode *yasm_bc_create_align + (/*@keep@*/ yasm_expr *boundary, /*@keep@*/ /*@null@*/ yasm_expr *fill, + /*@keep@*/ /*@null@*/ yasm_expr *maxskip, + /*@null@*/ const unsigned char **code_fill, unsigned long line); + +/** Create a bytecode that puts the following bytecode at a fixed section + * offset. + * \param start section offset of following bytecode + * \param fill fill value + * \param line virtual line (from yasm_linemap) + * \return Newly allocated bytecode. + */ +YASM_LIB_DECL +/*@only@*/ yasm_bytecode *yasm_bc_create_org + (unsigned long start, unsigned long fill, unsigned long line); + +/** Get the section that contains a particular bytecode. + * \param bc bytecode + * \return Section containing bc (can be NULL if bytecode is not part of a + * section). + */ +YASM_LIB_DECL +/*@dependent@*/ /*@null@*/ yasm_section *yasm_bc_get_section + (yasm_bytecode *bc); + +/** Add to the list of symrecs that reference a bytecode. For symrec use + * only. + * \param bc bytecode + * \param sym symbol + */ +YASM_LIB_DECL +void yasm_bc__add_symrec(yasm_bytecode *bc, /*@dependent@*/ yasm_symrec *sym); + +/** Delete (free allocated memory for) a bytecode. + * \param bc bytecode (only pointer to it); may be NULL + */ +YASM_LIB_DECL +void yasm_bc_destroy(/*@only@*/ /*@null@*/ yasm_bytecode *bc); + +/** Print a bytecode. For debugging purposes. + * \param f file + * \param indent_level indentation level + * \param bc bytecode + */ +YASM_LIB_DECL +void yasm_bc_print(const yasm_bytecode *bc, FILE *f, int indent_level); + +/** Finalize a bytecode after parsing. + * \param bc bytecode + * \param prev_bc bytecode directly preceding bc in a list of bytecodes + */ +YASM_LIB_DECL +void yasm_bc_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc); + +/** Determine the distance between the starting offsets of two bytecodes. + * \param precbc1 preceding bytecode to the first bytecode + * \param precbc2 preceding bytecode to the second bytecode + * \return Distance in bytes between the two bytecodes (bc2-bc1), or NULL if + * the distance was indeterminate. + * \warning Only valid /after/ optimization. + */ +YASM_LIB_DECL +/*@null@*/ /*@only@*/ yasm_intnum *yasm_calc_bc_dist + (yasm_bytecode *precbc1, yasm_bytecode *precbc2); + +/** Get the offset of the next bytecode (the next bytecode doesn't have to + * actually exist). + * \param precbc preceding bytecode + * \return Offset of the next bytecode in bytes. + * \warning Only valid /after/ optimization. + */ +YASM_LIB_DECL +unsigned long yasm_bc_next_offset(yasm_bytecode *precbc); + +/** Return elemens size of a data bytecode. + * Returns the size of each elements of a data bytecode, for proper dereference + * of symbols attached to it. + * \param bc bytecode + * \return 0 if element size is unknown + */ +YASM_LIB_DECL +int yasm_bc_elem_size(yasm_bytecode *bc); + +/** Resolve EQUs in a bytecode and calculate its minimum size. + * Generates dependent bytecode spans for cases where, if the length spanned + * increases, it could cause the bytecode size to increase. + * Any bytecode multiple is NOT included in the length or spans generation; + * this must be handled at a higher level. + * \param bc bytecode + * \param add_span function to call to add a span + * \param add_span_data extra data to be passed to add_span function + * \return 0 if no error occurred, nonzero if there was an error recognized + * (and output) during execution. + * \note May store to bytecode updated expressions and the short length. + */ +YASM_LIB_DECL +int yasm_bc_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span, + void *add_span_data); + +/** Recalculate a bytecode's length based on an expanded span length. + * \param bc bytecode + * \param span span ID (as given to yasm_bc_add_span_func in + * yasm_bc_calc_len) + * \param old_val previous span value + * \param new_val new span value + * \param neg_thres negative threshold for long/short decision (returned) + * \param pos_thres positive threshold for long/short decision (returned) + * \return 0 if bc no longer dependent on this span's length, negative if + * there was an error recognized (and output) during execution, and + * positive if bc size may increase for this span further based on the + * new negative and positive thresholds returned. + * \note May store to bytecode updated expressions and the updated length. + */ +YASM_LIB_DECL +int yasm_bc_expand(yasm_bytecode *bc, int span, long old_val, long new_val, + /*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres); + +/** Convert a bytecode into its byte representation. + * \param bc bytecode + * \param buf byte representation destination buffer + * \param bufsize size of buf (in bytes) prior to call; size of the + * generated data after call + * \param gap if nonzero, indicates the data does not really need to + * exist in the object file; if nonzero, contents of buf + * are undefined [output] + * \param d data to pass to each call to output_value/output_reloc + * \param output_value function to call to convert values into their byte + * representation + * \param output_reloc function to call to output relocation entries + * for a single sym + * \return Newly allocated buffer that should be used instead of buf for + * reading the byte representation, or NULL if buf was big enough to + * hold the entire byte representation. + * \note Calling twice on the same bytecode may \em not produce the same + * results on the second call, as calling this function may result in + * non-reversible changes to the bytecode. + */ +YASM_LIB_DECL +/*@null@*/ /*@only@*/ unsigned char *yasm_bc_tobytes + (yasm_bytecode *bc, unsigned char *buf, unsigned long *bufsize, + /*@out@*/ int *gap, void *d, yasm_output_value_func output_value, + /*@null@*/ yasm_output_reloc_func output_reloc) + /*@sets *buf@*/; + +/** Get the bytecode multiple value as an integer. + * \param bc bytecode + * \param multiple multiple value (output) + * \param calc_bc_dist nonzero if distances between bytecodes should be + * calculated, 0 if error should be returned in this case + * \return 1 on error (set with yasm_error_set), 0 on success. + */ +YASM_LIB_DECL +int yasm_bc_get_multiple(yasm_bytecode *bc, /*@out@*/ long *multiple, + int calc_bc_dist); + +/** Get the bytecode multiple value as an expression. + * \param bc bytecode + * \return Bytecode multiple, NULL if =1. + */ +YASM_LIB_DECL +const yasm_expr *yasm_bc_get_multiple_expr(const yasm_bytecode *bc); + +/** Get a #yasm_insn structure from an instruction bytecode (if possible). + * \param bc bytecode + * \return Instruction details if bytecode is an instruction bytecode, + * otherwise NULL. + */ +YASM_LIB_DECL +/*@dependent@*/ /*@null@*/ yasm_insn *yasm_bc_get_insn(yasm_bytecode *bc); + +/** Create a new data value from an expression. + * \param expn expression + * \return Newly allocated data value. + */ +YASM_LIB_DECL +yasm_dataval *yasm_dv_create_expr(/*@keep@*/ yasm_expr *expn); + +/** Create a new data value from a string. + * \param contents string (may contain NULs) + * \param len length of string + * \return Newly allocated data value. + */ +YASM_LIB_DECL +yasm_dataval *yasm_dv_create_string(/*@keep@*/ char *contents, size_t len); + +/** Create a new data value from raw bytes data. + * \param contents raw data (may contain NULs) + * \param len length + * \return Newly allocated data value. + */ +YASM_LIB_DECL +yasm_dataval *yasm_dv_create_raw(/*@keep@*/ unsigned char *contents, + unsigned long len); + +/** Create a new uninitialized data value. + * \return Newly allocated data value. + */ +YASM_LIB_DECL +yasm_dataval *yasm_dv_create_reserve(void); + +#ifndef YASM_DOXYGEN +#define yasm_dv_create_string(s, l) yasm_dv_create_raw((unsigned char *)(s), \ + (unsigned long)(l)) +#endif + +/** Get the underlying value of a data value. + * \param dv data value + * \return Value, or null if non-value (e.g. string or raw). + */ +YASM_LIB_DECL +yasm_value *yasm_dv_get_value(yasm_dataval *dv); + +/** Set multiple field of a data value. + * A data value can be repeated a number of times when output. This function + * sets that multiple. + * \param dv data value + * \param e multiple (kept, do not free) + */ +YASM_LIB_DECL +void yasm_dv_set_multiple(yasm_dataval *dv, /*@keep@*/ yasm_expr *e); + +/** Get the data value multiple value as an unsigned long integer. + * \param dv data value + * \param multiple multiple value (output) + * \return 1 on error (set with yasm_error_set), 0 on success. + */ +YASM_LIB_DECL +int yasm_dv_get_multiple(yasm_dataval *dv, /*@out@*/ unsigned long *multiple); + +/** Initialize a list of data values. + * \param headp list of data values + */ +void yasm_dvs_initialize(yasm_datavalhead *headp); +#ifndef YASM_DOXYGEN +#define yasm_dvs_initialize(headp) STAILQ_INIT(headp) +#endif + +/** Delete (free allocated memory for) a list of data values. + * \param headp list of data values + */ +YASM_LIB_DECL +void yasm_dvs_delete(yasm_datavalhead *headp); + +/** Add data value to the end of a list of data values. + * \note Does not make a copy of the data value; so don't pass this function + * static or local variables, and discard the dv pointer after calling + * this function. + * \param headp data value list + * \param dv data value (may be NULL) + * \return If data value was actually appended (it wasn't NULL), the data + * value; otherwise NULL. + */ +YASM_LIB_DECL +/*@null@*/ yasm_dataval *yasm_dvs_append + (yasm_datavalhead *headp, /*@returned@*/ /*@null@*/ yasm_dataval *dv); + +/** Print a data value list. For debugging purposes. + * \param f file + * \param indent_level indentation level + * \param headp data value list + */ +YASM_LIB_DECL +void yasm_dvs_print(const yasm_datavalhead *headp, FILE *f, int indent_level); + +#endif diff --git a/contrib/tools/yasm/libyasm/cmake-module.c b/contrib/tools/yasm/libyasm/cmake-module.c index 2ee39ca88f..6ddf9e317f 100644 --- a/contrib/tools/yasm/libyasm/cmake-module.c +++ b/contrib/tools/yasm/libyasm/cmake-module.c @@ -1,126 +1,126 @@ -/* - * YASM module loader - * - * Copyright (C) 2004-2007 Peter Johnson - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ -#include <util.h> - -#include <libyasm.h> - - -typedef struct loaded_module { - const char *keyword; /* module keyword */ - void *data; /* associated data */ -} loaded_module; - -static HAMT *loaded_modules[] = {NULL, NULL, NULL, NULL, NULL, NULL}; - -static void -load_module_destroy(/*@only@*/ void *data) -{ - /* do nothing */ -} - -void * -yasm_load_module(yasm_module_type type, const char *keyword) -{ - if (!loaded_modules[type]) - return NULL; - return HAMT_search(loaded_modules[type], keyword); -} - -void -yasm_register_module(yasm_module_type type, const char *keyword, void *data) -{ - int replace = 1; - - assert(type < sizeof(loaded_modules)); - - if (!loaded_modules[type]) - loaded_modules[type] = HAMT_create(0, yasm_internal_error_); - - HAMT_insert(loaded_modules[type], keyword, data, &replace, - load_module_destroy); -} - -typedef struct { - yasm_module_type type; - void (*printfunc) (const char *name, const char *keyword); -} list_one_data; - -static int -yasm_list_one_module(void *node, void *d) -{ - list_one_data *data = (list_one_data *)d; - yasm_arch_module *arch; - yasm_dbgfmt_module *dbgfmt; - yasm_objfmt_module *objfmt; - yasm_listfmt_module *listfmt; - yasm_parser_module *parser; - yasm_preproc_module *preproc; - - switch (data->type) { - case YASM_MODULE_ARCH: - arch = node; - data->printfunc(arch->name, arch->keyword); - break; - case YASM_MODULE_DBGFMT: - dbgfmt = node; - data->printfunc(dbgfmt->name, dbgfmt->keyword); - break; - case YASM_MODULE_OBJFMT: - objfmt = node; - data->printfunc(objfmt->name, objfmt->keyword); - break; - case YASM_MODULE_LISTFMT: - listfmt = node; - data->printfunc(listfmt->name, listfmt->keyword); - break; - case YASM_MODULE_PARSER: - parser = node; - data->printfunc(parser->name, parser->keyword); - break; - case YASM_MODULE_PREPROC: - preproc = node; - data->printfunc(preproc->name, preproc->keyword); - break; - } - return 0; -} - -void -yasm_list_modules(yasm_module_type type, - void (*printfunc) (const char *name, const char *keyword)) -{ - list_one_data data; - - /* Go through available list, and try to load each one */ - if (!loaded_modules[type]) - return; - - data.type = type; - data.printfunc = printfunc; - - HAMT_traverse(loaded_modules[type], &data, yasm_list_one_module); -} +/* + * YASM module loader + * + * Copyright (C) 2004-2007 Peter Johnson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include <util.h> + +#include <libyasm.h> + + +typedef struct loaded_module { + const char *keyword; /* module keyword */ + void *data; /* associated data */ +} loaded_module; + +static HAMT *loaded_modules[] = {NULL, NULL, NULL, NULL, NULL, NULL}; + +static void +load_module_destroy(/*@only@*/ void *data) +{ + /* do nothing */ +} + +void * +yasm_load_module(yasm_module_type type, const char *keyword) +{ + if (!loaded_modules[type]) + return NULL; + return HAMT_search(loaded_modules[type], keyword); +} + +void +yasm_register_module(yasm_module_type type, const char *keyword, void *data) +{ + int replace = 1; + + assert(type < sizeof(loaded_modules)); + + if (!loaded_modules[type]) + loaded_modules[type] = HAMT_create(0, yasm_internal_error_); + + HAMT_insert(loaded_modules[type], keyword, data, &replace, + load_module_destroy); +} + +typedef struct { + yasm_module_type type; + void (*printfunc) (const char *name, const char *keyword); +} list_one_data; + +static int +yasm_list_one_module(void *node, void *d) +{ + list_one_data *data = (list_one_data *)d; + yasm_arch_module *arch; + yasm_dbgfmt_module *dbgfmt; + yasm_objfmt_module *objfmt; + yasm_listfmt_module *listfmt; + yasm_parser_module *parser; + yasm_preproc_module *preproc; + + switch (data->type) { + case YASM_MODULE_ARCH: + arch = node; + data->printfunc(arch->name, arch->keyword); + break; + case YASM_MODULE_DBGFMT: + dbgfmt = node; + data->printfunc(dbgfmt->name, dbgfmt->keyword); + break; + case YASM_MODULE_OBJFMT: + objfmt = node; + data->printfunc(objfmt->name, objfmt->keyword); + break; + case YASM_MODULE_LISTFMT: + listfmt = node; + data->printfunc(listfmt->name, listfmt->keyword); + break; + case YASM_MODULE_PARSER: + parser = node; + data->printfunc(parser->name, parser->keyword); + break; + case YASM_MODULE_PREPROC: + preproc = node; + data->printfunc(preproc->name, preproc->keyword); + break; + } + return 0; +} + +void +yasm_list_modules(yasm_module_type type, + void (*printfunc) (const char *name, const char *keyword)) +{ + list_one_data data; + + /* Go through available list, and try to load each one */ + if (!loaded_modules[type]) + return; + + data.type = type; + data.printfunc = printfunc; + + HAMT_traverse(loaded_modules[type], &data, yasm_list_one_module); +} diff --git a/contrib/tools/yasm/libyasm/compat-queue.h b/contrib/tools/yasm/libyasm/compat-queue.h index da9eff4694..bd0c930f69 100644 --- a/contrib/tools/yasm/libyasm/compat-queue.h +++ b/contrib/tools/yasm/libyasm/compat-queue.h @@ -1,456 +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 */ +/* + * <sys/queue.h> implementation for systems that don't have it. + * + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)queue.h 8.5 (Berkeley) 8/20/94 + * $FreeBSD: src/sys/sys/queue.h,v 1.32.2.4 2001/03/31 03:33:39 hsu Exp $ + */ + +#ifndef SYS_QUEUE_H +#define SYS_QUEUE_H + +/* + * This file defines four types of data structures: singly-linked lists, + * singly-linked tail queues, lists and tail queues. + * + * A singly-linked list is headed by a single forward pointer. The elements + * are singly linked for minimum space and pointer manipulation overhead at + * the expense of O(n) removal for arbitrary elements. New elements can be + * added to the list after an existing element or at the head of the list. + * Elements being removed from the head of the list should use the explicit + * macro for this purpose for optimum efficiency. A singly-linked list may + * only be traversed in the forward direction. Singly-linked lists are ideal + * for applications with large datasets and few or no removals or for + * implementing a LIFO queue. + * + * A singly-linked tail queue is headed by a pair of pointers, one to the + * head of the list and the other to the tail of the list. The elements are + * singly linked for minimum space and pointer manipulation overhead at the + * expense of O(n) removal for arbitrary elements. New elements can be added + * to the list after an existing element, at the head of the list, or at the + * end of the list. Elements being removed from the head of the tail queue + * should use the explicit macro for this purpose for optimum efficiency. + * A singly-linked tail queue may only be traversed in the forward direction. + * Singly-linked tail queues are ideal for applications with large datasets + * and few or no removals or for implementing a FIFO queue. + * + * A list is headed by a single forward pointer (or an array of forward + * pointers for a hash table header). The elements are doubly linked + * so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before + * or after an existing element or at the head of the list. A list + * may only be traversed in the forward direction. + * + * A tail queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or + * after an existing element, at the head of the list, or at the end of + * the list. A tail queue may be traversed in either direction. + * + * For details on the use of these macros, see the queue(3) manual page. + * + * + * SLIST LIST STAILQ TAILQ + * _HEAD + + + + + * _HEAD_INITIALIZER + + + + + * _ENTRY + + + + + * _INIT + + + + + * _EMPTY + + + + + * _FIRST + + + + + * _NEXT + + + + + * _PREV - - - + + * _LAST - - + + + * _FOREACH + + + + + * _FOREACH_SAFE + + + + + * _FOREACH_REVERSE - - - + + * _FOREACH_REVERSE_SAFE - - - + + * _INSERT_HEAD + + + + + * _INSERT_BEFORE - + - + + * _INSERT_AFTER + + + + + * _INSERT_TAIL - - + + + * _CONCAT - - + + + * _REMOVE_HEAD + - + - + * _REMOVE + + + + + * + */ + +/* + * Singly-linked List declarations. + */ +#define SLIST_HEAD(name, type) \ +struct name { \ + struct type *slh_first; /* first element */ \ +} + +#define SLIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define SLIST_ENTRY(type) \ +struct { \ + struct type *sle_next; /* next element */ \ +} + +/* + * Singly-linked List functions. + */ +#define SLIST_EMPTY(head) ((head)->slh_first == NULL) + +#define SLIST_FIRST(head) ((head)->slh_first) + +#define SLIST_FOREACH(var, head, field) \ + for ((var) = SLIST_FIRST((head)); \ + (var); \ + (var) = SLIST_NEXT((var), field)) + +#define SLIST_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = SLIST_FIRST((head)); \ + (var) && ((tvar) = SLIST_NEXT((var), field), 1); \ + (var) = (tvar)) + +#define SLIST_FOREACH_PREVPTR(var, varp, head, field) \ + for ((varp) = &SLIST_FIRST((head)); \ + ((var) = *(varp)) != NULL; \ + (varp) = &SLIST_NEXT((var), field)) + +#define SLIST_INIT(head) do { \ + SLIST_FIRST((head)) = NULL; \ +} while (0) + +#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ + SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field); \ + SLIST_NEXT((slistelm), field) = (elm); \ +} while (0) + +#define SLIST_INSERT_HEAD(head, elm, field) do { \ + SLIST_NEXT((elm), field) = SLIST_FIRST((head)); \ + SLIST_FIRST((head)) = (elm); \ +} while (0) + +#define SLIST_NEXT(elm, field) ((elm)->field.sle_next) + +#define SLIST_REMOVE(head, elm, type, field) do { \ + if (SLIST_FIRST((head)) == (elm)) { \ + SLIST_REMOVE_HEAD((head), field); \ + } \ + else { \ + struct type *curelm = SLIST_FIRST((head)); \ + while (SLIST_NEXT(curelm, field) != (elm)) \ + curelm = SLIST_NEXT(curelm, field); \ + SLIST_NEXT(curelm, field) = \ + SLIST_NEXT(SLIST_NEXT(curelm, field), field); \ + } \ +} while (0) + +#define SLIST_REMOVE_HEAD(head, field) do { \ + SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field); \ +} while (0) + +/* + * Singly-linked Tail queue declarations. + */ +#define STAILQ_HEAD(name, type) \ +struct name { \ + struct type *stqh_first;/* first element */ \ + struct type **stqh_last;/* addr of last next element */ \ +} + +#define STAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).stqh_first } + +#define STAILQ_ENTRY(type) \ +struct { \ + struct type *stqe_next; /* next element */ \ +} + +/* + * Singly-linked Tail queue functions. + */ +#define STAILQ_CONCAT(head1, head2) do { \ + if (!STAILQ_EMPTY((head2))) { \ + *(head1)->stqh_last = (head2)->stqh_first; \ + (head1)->stqh_last = (head2)->stqh_last; \ + STAILQ_INIT((head2)); \ + } \ +} while (0) + +#define STAILQ_EMPTY(head) ((head)->stqh_first == NULL) + +#define STAILQ_FIRST(head) ((head)->stqh_first) + +#define STAILQ_FOREACH(var, head, field) \ + for((var) = STAILQ_FIRST((head)); \ + (var); \ + (var) = STAILQ_NEXT((var), field)) + + +#define STAILQ_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = STAILQ_FIRST((head)); \ + (var) && ((tvar) = STAILQ_NEXT((var), field), 1); \ + (var) = (tvar)) + +#define STAILQ_INIT(head) do { \ + STAILQ_FIRST((head)) = NULL; \ + (head)->stqh_last = &STAILQ_FIRST((head)); \ +} while (0) + +#define STAILQ_INSERT_AFTER(head, tqelm, elm, field) do { \ + if ((STAILQ_NEXT((elm), field) = STAILQ_NEXT((tqelm), field)) == NULL)\ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ + STAILQ_NEXT((tqelm), field) = (elm); \ +} while (0) + +#define STAILQ_INSERT_HEAD(head, elm, field) do { \ + if ((STAILQ_NEXT((elm), field) = STAILQ_FIRST((head))) == NULL) \ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ + STAILQ_FIRST((head)) = (elm); \ +} while (0) + +#define STAILQ_INSERT_TAIL(head, elm, field) do { \ + STAILQ_NEXT((elm), field) = NULL; \ + *(head)->stqh_last = (elm); \ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ +} while (0) + +#define STAILQ_LAST(head, type, field) \ + (STAILQ_EMPTY((head)) ? \ + NULL : \ + ((struct type *) \ + ((char *)((head)->stqh_last) - offsetof(struct type, field)))) + +#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next) + +#define STAILQ_REMOVE(head, elm, type, field) do { \ + if (STAILQ_FIRST((head)) == (elm)) { \ + STAILQ_REMOVE_HEAD((head), field); \ + } \ + else { \ + struct type *curelm = STAILQ_FIRST((head)); \ + while (STAILQ_NEXT(curelm, field) != (elm)) \ + curelm = STAILQ_NEXT(curelm, field); \ + if ((STAILQ_NEXT(curelm, field) = \ + STAILQ_NEXT(STAILQ_NEXT(curelm, field), field)) == NULL)\ + (head)->stqh_last = &STAILQ_NEXT((curelm), field);\ + } \ +} while (0) + +#define STAILQ_REMOVE_HEAD(head, field) do { \ + if ((STAILQ_FIRST((head)) = \ + STAILQ_NEXT(STAILQ_FIRST((head)), field)) == NULL) \ + (head)->stqh_last = &STAILQ_FIRST((head)); \ +} while (0) + +#define STAILQ_REMOVE_HEAD_UNTIL(head, elm, field) do { \ + if ((STAILQ_FIRST((head)) = STAILQ_NEXT((elm), field)) == NULL) \ + (head)->stqh_last = &STAILQ_FIRST((head)); \ +} while (0) + +/* + * List declarations. + */ +#define LIST_HEAD(name, type) \ +struct name { \ + struct type *lh_first; /* first element */ \ +} + +#define LIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define LIST_ENTRY(type) \ +struct { \ + struct type *le_next; /* next element */ \ + struct type **le_prev; /* address of previous next element */ \ +} + +/* + * List functions. + */ + +#define LIST_EMPTY(head) ((head)->lh_first == NULL) + +#define LIST_FIRST(head) ((head)->lh_first) + +#define LIST_FOREACH(var, head, field) \ + for ((var) = LIST_FIRST((head)); \ + (var); \ + (var) = LIST_NEXT((var), field)) + +#define LIST_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = LIST_FIRST((head)); \ + (var) && ((tvar) = LIST_NEXT((var), field), 1); \ + (var) = (tvar)) + +#define LIST_INIT(head) do { \ + LIST_FIRST((head)) = NULL; \ +} while (0) + +#define LIST_INSERT_AFTER(listelm, elm, field) do { \ + if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) != NULL)\ + LIST_NEXT((listelm), field)->field.le_prev = \ + &LIST_NEXT((elm), field); \ + LIST_NEXT((listelm), field) = (elm); \ + (elm)->field.le_prev = &LIST_NEXT((listelm), field); \ +} while (0) + +#define LIST_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.le_prev = (listelm)->field.le_prev; \ + LIST_NEXT((elm), field) = (listelm); \ + *(listelm)->field.le_prev = (elm); \ + (listelm)->field.le_prev = &LIST_NEXT((elm), field); \ +} while (0) + +#define LIST_INSERT_HEAD(head, elm, field) do { \ + if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL) \ + LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field);\ + LIST_FIRST((head)) = (elm); \ + (elm)->field.le_prev = &LIST_FIRST((head)); \ +} while (0) + +#define LIST_NEXT(elm, field) ((elm)->field.le_next) + +#define LIST_REMOVE(elm, field) do { \ + if (LIST_NEXT((elm), field) != NULL) \ + LIST_NEXT((elm), field)->field.le_prev = \ + (elm)->field.le_prev; \ + *(elm)->field.le_prev = LIST_NEXT((elm), field); \ +} while (0) + +/* + * Tail queue declarations. + */ +#define TAILQ_HEAD(name, type) \ +struct name { \ + struct type *tqh_first; /* first element */ \ + struct type **tqh_last; /* addr of last next element */ \ +} + +#define TAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).tqh_first } + +#define TAILQ_ENTRY(type) \ +struct { \ + struct type *tqe_next; /* next element */ \ + struct type **tqe_prev; /* address of previous next element */ \ +} + +/* + * Tail queue functions. + */ +#define TAILQ_CONCAT(head1, head2, field) do { \ + if (!TAILQ_EMPTY(head2)) { \ + *(head1)->tqh_last = (head2)->tqh_first; \ + (head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \ + (head1)->tqh_last = (head2)->tqh_last; \ + TAILQ_INIT((head2)); \ + } \ +} while (0) + +#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL) + +#define TAILQ_FIRST(head) ((head)->tqh_first) + +#define TAILQ_FOREACH(var, head, field) \ + for ((var) = TAILQ_FIRST((head)); \ + (var); \ + (var) = TAILQ_NEXT((var), field)) + +#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = TAILQ_FIRST((head)); \ + (var) && ((tvar) = TAILQ_NEXT((var), field), 1); \ + (var) = (tvar)) + +#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ + for ((var) = TAILQ_LAST((head), headname); \ + (var); \ + (var) = TAILQ_PREV((var), headname, field)) + +#define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \ + for ((var) = TAILQ_LAST((head), headname); \ + (var) && ((tvar) = TAILQ_PREV((var), headname, field), 1); \ + (var) = (tvar)) + +#define TAILQ_INIT(head) do { \ + TAILQ_FIRST((head)) = NULL; \ + (head)->tqh_last = &TAILQ_FIRST((head)); \ +} while (0) + +#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) != NULL)\ + TAILQ_NEXT((elm), field)->field.tqe_prev = \ + &TAILQ_NEXT((elm), field); \ + else { \ + (head)->tqh_last = &TAILQ_NEXT((elm), field); \ + } \ + TAILQ_NEXT((listelm), field) = (elm); \ + (elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field); \ +} while (0) + +#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ + TAILQ_NEXT((elm), field) = (listelm); \ + *(listelm)->field.tqe_prev = (elm); \ + (listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field); \ +} while (0) + +#define TAILQ_INSERT_HEAD(head, elm, field) do { \ + if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL) \ + TAILQ_FIRST((head))->field.tqe_prev = \ + &TAILQ_NEXT((elm), field); \ + else \ + (head)->tqh_last = &TAILQ_NEXT((elm), field); \ + TAILQ_FIRST((head)) = (elm); \ + (elm)->field.tqe_prev = &TAILQ_FIRST((head)); \ +} while (0) + +#define TAILQ_INSERT_TAIL(head, elm, field) do { \ + TAILQ_NEXT((elm), field) = NULL; \ + (elm)->field.tqe_prev = (head)->tqh_last; \ + *(head)->tqh_last = (elm); \ + (head)->tqh_last = &TAILQ_NEXT((elm), field); \ +} while (0) + +#define TAILQ_LAST(head, headname) \ + (*(((struct headname *)((head)->tqh_last))->tqh_last)) + +#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) + +#define TAILQ_PREV(elm, headname, field) \ + (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) + +#define TAILQ_REMOVE(head, elm, field) do { \ + if ((TAILQ_NEXT((elm), field)) != NULL) \ + TAILQ_NEXT((elm), field)->field.tqe_prev = \ + (elm)->field.tqe_prev; \ + else { \ + (head)->tqh_last = (elm)->field.tqe_prev; \ + } \ + *(elm)->field.tqe_prev = TAILQ_NEXT((elm), field); \ +} while (0) + +#endif /* !SYS_QUEUE_H */ diff --git a/contrib/tools/yasm/libyasm/coretype.h b/contrib/tools/yasm/libyasm/coretype.h index 624e3c445c..ead8f1d480 100644 --- a/contrib/tools/yasm/libyasm/coretype.h +++ b/contrib/tools/yasm/libyasm/coretype.h @@ -1,393 +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 +/** + * \file libyasm/coretype.h + * \brief YASM core types and utility functions. + * + * \license + * Copyright (C) 2001-2007 Peter Johnson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * \endlicense + */ +#ifndef YASM_CORETYPE_H +#define YASM_CORETYPE_H + +#ifndef YASM_LIB_DECL +#define YASM_LIB_DECL +#endif + +/** Architecture instance (mostly opaque type). \see arch.h for details. */ +typedef struct yasm_arch yasm_arch; +/** Preprocessor interface. \see preproc.h for details. */ +typedef struct yasm_preproc yasm_preproc; +/** Parser instance (mostly opaque type). \see parser.h for details. */ +typedef struct yasm_parser yasm_parser; +/** Object format interface. \see objfmt.h for details. */ +typedef struct yasm_objfmt yasm_objfmt; +/** Debug format interface. \see dbgfmt.h for details. */ +typedef struct yasm_dbgfmt yasm_dbgfmt; +/** List format interface. \see listfmt.h for details. */ +typedef struct yasm_listfmt yasm_listfmt; + +/** Object format module interface. \see objfmt.h for details. */ +typedef struct yasm_objfmt_module yasm_objfmt_module; +/** Debug format module interface. \see dbgfmt.h for details. */ +typedef struct yasm_dbgfmt_module yasm_dbgfmt_module; + +/** Standard macro structure for modules that allows association of a set of + * standard macros with a parser/preprocessor combination. + * A NULL-terminated array of these structures is used in a number of module + * interfaces. + */ +typedef struct yasm_stdmac { + const char *parser; /**< Parser keyword */ + const char *preproc; /**< Preprocessor keyword */ + + /** NULL-terminated array of standard macros. May be NULL if no standard + * macros should be added for this preprocessor. + */ + const char **macros; +} yasm_stdmac; + +/** YASM associated data callback structure. Many data structures can have + * arbitrary data associated with them. + */ +typedef struct yasm_assoc_data_callback { + /** Free memory allocated for associated data. + * \param data associated data + */ + void (*destroy) (/*@only@*/ void *data); + + /** Print a description of allocated data. For debugging purposes. + * \param data associated data + * \param f output file + * \param indent_level indentation level + */ + void (*print) (void *data, FILE *f, int indent_level); +} yasm_assoc_data_callback; + +/** Set of collected error/warnings (opaque type). + * \see errwarn.h for details. + */ +typedef struct yasm_errwarns yasm_errwarns; + +/** Bytecode. \see bytecode.h for details and related functions. */ +typedef struct yasm_bytecode yasm_bytecode; + +/** Object. \see section.h for details and related functions. */ +typedef struct yasm_object yasm_object; + +/** Section (opaque type). \see section.h for related functions. */ +typedef struct yasm_section yasm_section; + +/** Symbol table (opaque type). \see symrec.h for related functions. */ +typedef struct yasm_symtab yasm_symtab; + +/** Symbol record (opaque type). \see symrec.h for related functions. */ +typedef struct yasm_symrec yasm_symrec; + +/** Expression. \see expr.h for details and related functions. */ +typedef struct yasm_expr yasm_expr; +/** Integer value (opaque type). \see intnum.h for related functions. */ +typedef struct yasm_intnum yasm_intnum; +/** Floating point value (opaque type). + * \see floatnum.h for related functions. + */ +typedef struct yasm_floatnum yasm_floatnum; + +/** A value. May be absolute or relative. Outside the parser, yasm_expr + * should only be used for absolute exprs. Anything that could contain + * a relocatable value should use this structure instead. + * \see value.h for related functions. + */ +typedef struct yasm_value { + /** The absolute portion of the value. May contain *differences* between + * symrecs but not standalone symrecs. May be NULL if there is no + * absolute portion (e.g. the absolute portion is 0). + */ + /*@null@*/ /*@only@*/ yasm_expr *abs; + + /** The relative portion of the value. This is the portion that may + * need to generate a relocation. May be NULL if no relative portion. + */ + /*@null@*/ /*@dependent@*/ yasm_symrec *rel; + + /** What the relative portion is in reference to. NULL if the default. */ + /*@null@*/ /*@dependent@*/ yasm_symrec *wrt; + + /** If the segment of the relative portion should be used, not the + * relative portion itself. Boolean. + */ + unsigned int seg_of : 1; + + /** If the relative portion of the value should be shifted right + * (supported only by a few object formats). If just the absolute portion + * should be shifted, that must be in the abs expr, not here! + */ + unsigned int rshift : 7; + + /** Indicates the relative portion of the value should be relocated + * relative to the current assembly position rather than relative to the + * section start. "Current assembly position" here refers to the starting + * address of the bytecode containing this value. Boolean. + */ + unsigned int curpos_rel : 1; + + /** Indicates that curpos_rel was set due to IP-relative relocation; + * in some objfmt/arch combinations (e.g. win64/x86-amd64) this info + * is needed to generate special relocations. + */ + unsigned int ip_rel : 1; + + /** Indicates the value is a jump target address (rather than a simple + * data address). In some objfmt/arch combinations (e.g. macho/amd64) + * this info is needed to generate special relocations. + */ + unsigned int jump_target : 1; + + /** Indicates the relative portion of the value should be relocated + * relative to its own section start rather than relative to the + * section start of the bytecode containing this value. E.g. the value + * resulting from the relative portion should be the offset from its + * section start. Boolean. + */ + unsigned int section_rel : 1; + + /** Indicates overflow warnings have been disabled for this value. */ + unsigned int no_warn : 1; + + /** Sign of the value. Nonzero if the final value should be treated as + * signed, 0 if it should be treated as signed. + */ + unsigned int sign : 1; + + /** Size of the value, in bits. */ + unsigned int size : 8; +} yasm_value; + +/** Maximum value of #yasm_value.rshift */ +#define YASM_VALUE_RSHIFT_MAX 127 + +/** Line number mapping repository (opaque type). \see linemap.h for related + * functions. + */ +typedef struct yasm_linemap yasm_linemap; + +/** Value/parameter pair (opaque type). + * \see valparam.h for related functions. + */ +typedef struct yasm_valparam yasm_valparam; +/** List of value/parameters (opaque type). + * \see valparam.h for related functions. + */ +typedef struct yasm_valparamhead yasm_valparamhead; +/** Directive list entry. + * \see valparam.h for details and related functions. + */ +typedef struct yasm_directive yasm_directive; + +/** An effective address. + * \see insn.h for related functions. + */ +typedef struct yasm_effaddr yasm_effaddr; + +/** An instruction. + * \see insn.h for related functions. + */ +typedef struct yasm_insn yasm_insn; + +/** Expression operators usable in #yasm_expr expressions. */ +typedef enum yasm_expr_op { + YASM_EXPR_IDENT, /**< No operation, just a value. */ + YASM_EXPR_ADD, /**< Arithmetic addition (+). */ + YASM_EXPR_SUB, /**< Arithmetic subtraction (-). */ + YASM_EXPR_MUL, /**< Arithmetic multiplication (*). */ + YASM_EXPR_DIV, /**< Arithmetic unsigned division. */ + YASM_EXPR_SIGNDIV, /**< Arithmetic signed division. */ + YASM_EXPR_MOD, /**< Arithmetic unsigned modulus. */ + YASM_EXPR_SIGNMOD, /**< Arithmetic signed modulus. */ + YASM_EXPR_NEG, /**< Arithmetic negation (-). */ + YASM_EXPR_NOT, /**< Bitwise negation. */ + YASM_EXPR_OR, /**< Bitwise OR. */ + YASM_EXPR_AND, /**< Bitwise AND. */ + YASM_EXPR_XOR, /**< Bitwise XOR. */ + YASM_EXPR_XNOR, /**< Bitwise XNOR. */ + YASM_EXPR_NOR, /**< Bitwise NOR. */ + YASM_EXPR_SHL, /**< Shift left (logical). */ + YASM_EXPR_SHR, /**< Shift right (logical). */ + YASM_EXPR_LOR, /**< Logical OR. */ + YASM_EXPR_LAND, /**< Logical AND. */ + YASM_EXPR_LNOT, /**< Logical negation. */ + YASM_EXPR_LXOR, /**< Logical XOR. */ + YASM_EXPR_LXNOR, /**< Logical XNOR. */ + YASM_EXPR_LNOR, /**< Logical NOR. */ + YASM_EXPR_LT, /**< Less than comparison. */ + YASM_EXPR_GT, /**< Greater than comparison. */ + YASM_EXPR_EQ, /**< Equality comparison. */ + YASM_EXPR_LE, /**< Less than or equal to comparison. */ + YASM_EXPR_GE, /**< Greater than or equal to comparison. */ + YASM_EXPR_NE, /**< Not equal comparison. */ + YASM_EXPR_NONNUM, /**< Start of non-numeric operations (not an op). */ + YASM_EXPR_SEG, /**< SEG operator (gets segment portion of address). */ + YASM_EXPR_WRT, /**< WRT operator (gets offset of address relative to + * some other segment). */ + YASM_EXPR_SEGOFF /**< The ':' in segment:offset. */ +} yasm_expr_op; + +/** Convert yasm_value to its byte representation. Usually implemented by + * object formats to keep track of relocations and verify legal expressions. + * Must put the value into the least significant bits of the destination, + * unless shifted into more significant bits by the shift parameter. The + * destination bits must be cleared before being set. + * \param value value + * \param buf buffer for byte representation + * \param destsize destination size (in bytes) + * \param offset offset (in bytes) of the expr contents from the start + * of the bytecode (needed for relative) + * \param bc current bytecode (usually passed into higher-level + * calling function) + * \param warn enables standard warnings: zero for none; + * nonzero for overflow/underflow floating point warnings + * \param d objfmt-specific data (passed into higher-level calling + * function) + * \return Nonzero if an error occurred, 0 otherwise. + */ +typedef int (*yasm_output_value_func) + (yasm_value *value, /*@out@*/ unsigned char *buf, unsigned int destsize, + unsigned long offset, yasm_bytecode *bc, int warn, /*@null@*/ void *d); + +/** Convert a symbol reference to its byte representation. Usually implemented + * by object formats and debug formats to keep track of relocations generated + * by themselves. + * \param sym symbol + * \param bc current bytecode (usually passed into higher-level + * calling function) + * \param buf buffer for byte representation + * \param destsize destination size (in bytes) + * \param valsize size (in bits) + * \param warn enables standard warnings: zero for none; + * nonzero for overflow/underflow floating point warnings; + * negative for signed integer warnings, + * positive for unsigned integer warnings + * \param d objfmt-specific data (passed into higher-level calling + * function) + * \return Nonzero if an error occurred, 0 otherwise. + */ +typedef int (*yasm_output_reloc_func) + (yasm_symrec *sym, yasm_bytecode *bc, unsigned char *buf, + unsigned int destsize, unsigned int valsize, int warn, void *d); + +/** Sort an array using merge sort algorithm. + * \internal + * \param base base of array + * \param nmemb number of elements in array + * \param size size of each array element + * \param compar element comparison function + */ +YASM_LIB_DECL +int yasm__mergesort(void *base, size_t nmemb, size_t size, + int (*compar)(const void *, const void *)); + +/** Separate string by delimiters. + * \internal + * \param stringp string + * \param delim set of 1 or more delimiters + * \return First/next substring. + */ +YASM_LIB_DECL +/*@null@*/ char *yasm__strsep(char **stringp, const char *delim); + +/** Compare two strings, ignoring case differences. + * \internal + * \param s1 string 1 + * \param s2 string 2 + * \return 0 if strings are equal, -1 if s1<s2, 1 if s1>s2. + */ +YASM_LIB_DECL +int yasm__strcasecmp(const char *s1, const char *s2); + +/** Compare portion of two strings, ignoring case differences. + * \internal + * \param s1 string 1 + * \param s2 string 2 + * \param n maximum number of characters to compare + * \return 0 if strings are equal, -1 if s1<s2, 1 if s1>s2. + */ +YASM_LIB_DECL +int yasm__strncasecmp(const char *s1, const char *s2, size_t n); + +/** strdup() implementation using yasm_xmalloc(). + * \internal + * \param str string + * \return Newly allocated duplicate string. + */ +YASM_LIB_DECL +/*@only@*/ char *yasm__xstrdup(const char *str); + +/** strndup() implementation using yasm_xmalloc(). + * \internal + * \param str string + * \param max maximum number of characters to copy + * \return Newly allocated duplicate string. + */ +YASM_LIB_DECL +/*@only@*/ char *yasm__xstrndup(const char *str, size_t max); + +/** Error-checking memory allocation. A default implementation is provided + * that calls yasm_fatal() on allocation errors. + * A replacement should \em never return NULL. + * \param size number of bytes to allocate + * \return Allocated memory block. + */ +YASM_LIB_DECL +extern /*@only@*/ /*@out@*/ void * (*yasm_xmalloc) (size_t size); + +/** Error-checking memory allocation (with clear-to-0). A default + * implementation is provided that calls yasm_fatal() on allocation errors. + * A replacement should \em never return NULL. + * \param size number of elements to allocate + * \param elsize size (in bytes) of each element + * \return Allocated and cleared memory block. + */ +YASM_LIB_DECL +extern /*@only@*/ void * (*yasm_xcalloc) (size_t nelem, size_t elsize); + +/** Error-checking memory reallocation. A default implementation is provided + * that calls yasm_fatal() on allocation errors. A replacement should + * \em never return NULL. + * \param oldmem memory block to resize + * \param elsize new size, in bytes + * \return Re-allocated memory block. + */ +YASM_LIB_DECL +extern /*@only@*/ void * (*yasm_xrealloc) + (/*@only@*/ /*@out@*/ /*@returned@*/ /*@null@*/ void *oldmem, size_t size) + /*@modifies oldmem@*/; + +/** Error-checking memory deallocation. A default implementation is provided + * that calls yasm_fatal() on allocation errors. + * \param p memory block to free + */ +YASM_LIB_DECL +extern void (*yasm_xfree) (/*@only@*/ /*@out@*/ /*@null@*/ void *p) + /*@modifies p@*/; + +#endif diff --git a/contrib/tools/yasm/libyasm/dbgfmt.h b/contrib/tools/yasm/libyasm/dbgfmt.h index 2e5ea867ee..97e3470d20 100644 --- a/contrib/tools/yasm/libyasm/dbgfmt.h +++ b/contrib/tools/yasm/libyasm/dbgfmt.h @@ -1,74 +1,74 @@ -/** - * \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); +/** + * \file libyasm/dbgfmt.h + * \brief YASM debug format interface. + * + * \license + * Copyright (C) 2002-2007 Peter Johnson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * \endlicense + */ +#ifndef YASM_DBGFMT_H +#define YASM_DBGFMT_H + +#ifndef YASM_DOXYGEN +/** Base #yasm_dbgfmt structure. Must be present as the first element in any + * #yasm_dbgfmt implementation. + */ +typedef struct yasm_dbgfmt_base { + /** #yasm_dbgfmt_module implementation for this debug format. */ + const struct yasm_dbgfmt_module *module; +} yasm_dbgfmt_base; +#endif + +/** Debug format module interface. */ +struct yasm_dbgfmt_module { + /** One-line description of the debug format. */ + const char *name; + + /** Keyword used to select debug format. */ + const char *keyword; + + /** NULL-terminated list of directives. NULL if none. */ + /*@null@*/ const yasm_directive *directives; + + /** Create debug format. + * Module-level implementation of yasm_dbgfmt_create(). + * The filenames are provided solely for informational purposes. + * \param object object + * \return NULL if object format does not provide needed support. + */ + /*@null@*/ /*@only@*/ yasm_dbgfmt * (*create) (yasm_object *object); + + /** Module-level implementation of yasm_dbgfmt_destroy(). + * Call yasm_dbgfmt_destroy() instead of calling this function. + */ + void (*destroy) (/*@only@*/ yasm_dbgfmt *dbgfmt); + + /** Module-level implementation of yasm_dbgfmt_generate(). + * Call yasm_dbgfmt_generate() instead of calling this function. + */ + void (*generate) (yasm_object *object, yasm_linemap *linemap, + yasm_errwarns *errwarns); /** * --replace params @@ -78,54 +78,54 @@ struct yasm_dbgfmt_module { * Number of elements in replace_map */ int replace_map_size; -}; - -/** Get the keyword used to select a debug format. - * \param dbgfmt debug format - * \return keyword - */ -const char *yasm_dbgfmt_keyword(const yasm_dbgfmt *dbgfmt); - -/** Initialize debug output for use. Must call before any other debug - * format functions. The filenames are provided solely for informational - * purposes. - * \param module debug format module - * \param object object to generate debugging information for - * \return NULL if object format does not provide needed support. - */ -/*@null@*/ /*@only@*/ yasm_dbgfmt *yasm_dbgfmt_create - (const yasm_dbgfmt_module *module, yasm_object *object); - -/** Cleans up any allocated debug format memory. - * \param dbgfmt debug format - */ -void yasm_dbgfmt_destroy(/*@only@*/ yasm_dbgfmt *dbgfmt); - -/** Generate debugging information bytecodes. - * \param object object - * \param linemap virtual/physical line mapping - * \param errwarns error/warning set - * \note Errors and warnings are stored into errwarns. - */ -void yasm_dbgfmt_generate(yasm_object *object, yasm_linemap *linemap, - yasm_errwarns *errwarns); - -#ifndef YASM_DOXYGEN - -/* Inline macro implementations for dbgfmt functions */ - -#define yasm_dbgfmt_keyword(dbgfmt) \ - (((yasm_dbgfmt_base *)dbgfmt)->module->keyword) - -#define yasm_dbgfmt_create(module, object) \ - module->create(object) - -#define yasm_dbgfmt_destroy(dbgfmt) \ - ((yasm_dbgfmt_base *)dbgfmt)->module->destroy(dbgfmt) -#define yasm_dbgfmt_generate(object, linemap, ews) \ - ((yasm_dbgfmt_base *)((object)->dbgfmt))->module->generate \ - (object, linemap, ews) - -#endif - -#endif +}; + +/** Get the keyword used to select a debug format. + * \param dbgfmt debug format + * \return keyword + */ +const char *yasm_dbgfmt_keyword(const yasm_dbgfmt *dbgfmt); + +/** Initialize debug output for use. Must call before any other debug + * format functions. The filenames are provided solely for informational + * purposes. + * \param module debug format module + * \param object object to generate debugging information for + * \return NULL if object format does not provide needed support. + */ +/*@null@*/ /*@only@*/ yasm_dbgfmt *yasm_dbgfmt_create + (const yasm_dbgfmt_module *module, yasm_object *object); + +/** Cleans up any allocated debug format memory. + * \param dbgfmt debug format + */ +void yasm_dbgfmt_destroy(/*@only@*/ yasm_dbgfmt *dbgfmt); + +/** Generate debugging information bytecodes. + * \param object object + * \param linemap virtual/physical line mapping + * \param errwarns error/warning set + * \note Errors and warnings are stored into errwarns. + */ +void yasm_dbgfmt_generate(yasm_object *object, yasm_linemap *linemap, + yasm_errwarns *errwarns); + +#ifndef YASM_DOXYGEN + +/* Inline macro implementations for dbgfmt functions */ + +#define yasm_dbgfmt_keyword(dbgfmt) \ + (((yasm_dbgfmt_base *)dbgfmt)->module->keyword) + +#define yasm_dbgfmt_create(module, object) \ + module->create(object) + +#define yasm_dbgfmt_destroy(dbgfmt) \ + ((yasm_dbgfmt_base *)dbgfmt)->module->destroy(dbgfmt) +#define yasm_dbgfmt_generate(object, linemap, ews) \ + ((yasm_dbgfmt_base *)((object)->dbgfmt))->module->generate \ + (object, linemap, ews) + +#endif + +#endif diff --git a/contrib/tools/yasm/libyasm/errwarn.c b/contrib/tools/yasm/libyasm/errwarn.c index f759cf8f71..4266253bbc 100644 --- a/contrib/tools/yasm/libyasm/errwarn.c +++ b/contrib/tools/yasm/libyasm/errwarn.c @@ -1,533 +1,533 @@ -/* - * 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> +/* + * Error and warning reporting and related functions. + * + * Copyright (C) 2001-2007 Peter Johnson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include "util.h" + +#include <ctype.h> #include <errno.h> -#include <stdarg.h> - -#include "coretype.h" - -#include "linemap.h" -#include "errwarn.h" - - -#define MSG_MAXSIZE 1024 - -#if !defined(HAVE_TOASCII) || defined(lint) -# define toascii(c) ((c) & 0x7F) -#endif - -/* Default handlers for replacable functions */ -static /*@exits@*/ void def_internal_error_ - (const char *file, unsigned int line, const char *message); -static /*@exits@*/ void def_fatal(const char *message, va_list va); -static const char *def_gettext_hook(const char *msgid); - -/* Storage for errwarn's "extern" functions */ -/*@exits@*/ void (*yasm_internal_error_) - (const char *file, unsigned int line, const char *message) - = def_internal_error_; -/*@exits@*/ void (*yasm_fatal) (const char *message, va_list va) = def_fatal; -const char * (*yasm_gettext_hook) (const char *msgid) = def_gettext_hook; - -/* Error indicator */ -/* yasm_eclass is not static so that yasm_error_occurred macro can access it */ -yasm_error_class yasm_eclass; -static /*@only@*/ /*@null@*/ char *yasm_estr; -static unsigned long yasm_exrefline; -static /*@only@*/ /*@null@*/ char *yasm_exrefstr; - -/* Warning indicator */ -typedef struct warn { - /*@reldef@*/ STAILQ_ENTRY(warn) link; - - yasm_warn_class wclass; - /*@owned@*/ /*@null@*/ char *wstr; -} warn; -static STAILQ_HEAD(warn_head, warn) yasm_warns; - -/* Enabled warnings. See errwarn.h for a list. */ -static unsigned long warn_class_enabled; - -typedef struct errwarn_data { - /*@reldef@*/ SLIST_ENTRY(errwarn_data) link; - - enum { WE_UNKNOWN, WE_ERROR, WE_WARNING, WE_PARSERERROR } type; - - unsigned long line; - unsigned long xrefline; - /*@owned@*/ char *msg; - /*@owned@*/ char *xrefmsg; -} errwarn_data; - -struct yasm_errwarns { - /*@reldef@*/ SLIST_HEAD(errwarn_head, errwarn_data) errwarns; - - /* Total error count */ - unsigned int ecount; - - /* Total warning count */ - unsigned int wcount; - - /* Last inserted error/warning. Used to speed up insertions. */ - /*@null@*/ errwarn_data *previous_we; -}; - -/* Static buffer for use by conv_unprint(). */ -static char unprint[5]; - - -static const char * -def_gettext_hook(const char *msgid) -{ - return msgid; -} - -void -yasm_errwarn_initialize(void) -{ - /* Default enabled warnings. See errwarn.h for a list. */ - warn_class_enabled = - (1UL<<YASM_WARN_GENERAL) | (1UL<<YASM_WARN_UNREC_CHAR) | - (1UL<<YASM_WARN_PREPROC) | (0UL<<YASM_WARN_ORPHAN_LABEL) | - (1UL<<YASM_WARN_UNINIT_CONTENTS) | (0UL<<YASM_WARN_SIZE_OVERRIDE) | - (1UL<<YASM_WARN_IMPLICIT_SIZE_OVERRIDE); - - yasm_eclass = YASM_ERROR_NONE; - yasm_estr = NULL; - yasm_exrefline = 0; - yasm_exrefstr = NULL; - - STAILQ_INIT(&yasm_warns); -} - -void -yasm_errwarn_cleanup(void) -{ - yasm_error_clear(); - yasm_warn_clear(); -} - -/* Convert a possibly unprintable character into a printable string, using - * standard cat(1) convention for unprintable characters. - */ -char * -yasm__conv_unprint(int ch) -{ - int pos = 0; - - if (((ch & ~0x7F) != 0) /*!isascii(ch)*/ && !isprint(ch)) { - unprint[pos++] = 'M'; - unprint[pos++] = '-'; - ch &= toascii(ch); - } - if (iscntrl(ch)) { - unprint[pos++] = '^'; - unprint[pos++] = (ch == '\177') ? '?' : ch | 0100; - } else - unprint[pos++] = ch; - unprint[pos] = '\0'; - - return unprint; -} - -/* Report an internal error. Essentially a fatal error with trace info. - * Exit immediately because it's essentially an assert() trap. - */ -static void -def_internal_error_(const char *file, unsigned int line, const char *message) -{ - fprintf(stderr, - yasm_gettext_hook(N_("INTERNAL ERROR at %s, line %u: %s\n")), - file, line, yasm_gettext_hook(message)); -#ifdef HAVE_ABORT - abort(); -#else - exit(EXIT_FAILURE); -#endif -} - -/* Report a fatal error. These are unrecoverable (such as running out of - * memory), so just exit immediately. - */ -static void -def_fatal(const char *fmt, va_list va) -{ - fprintf(stderr, "%s: ", yasm_gettext_hook(N_("FATAL"))); - vfprintf(stderr, yasm_gettext_hook(fmt), va); - fputc('\n', stderr); - exit(EXIT_FAILURE); -} - -/* Create an errwarn structure in the correct linked list location. - * If replace_parser_error is nonzero, overwrites the last error if its - * type is WE_PARSERERROR. - */ -static errwarn_data * -errwarn_data_new(yasm_errwarns *errwarns, unsigned long line, - int replace_parser_error) -{ - errwarn_data *first, *next, *ins_we, *we; - enum { INS_NONE, INS_HEAD, INS_AFTER } action = INS_NONE; - - /* Find the entry with either line=line or the last one with line<line. - * Start with the last entry added to speed the search. - */ - ins_we = errwarns->previous_we; - first = SLIST_FIRST(&errwarns->errwarns); - if (!ins_we || !first) - action = INS_HEAD; - while (action == INS_NONE) { - next = SLIST_NEXT(ins_we, link); - if (line < ins_we->line) { - if (ins_we == first) - action = INS_HEAD; - else - ins_we = first; - } else if (!next) - action = INS_AFTER; - else if (line >= ins_we->line && line < next->line) - action = INS_AFTER; - else - ins_we = next; - } - - if (replace_parser_error && ins_we && ins_we->type == WE_PARSERERROR) { - /* overwrite last error */ - we = ins_we; - } else { - /* add a new error */ - we = yasm_xmalloc(sizeof(errwarn_data)); - - we->type = WE_UNKNOWN; - we->line = line; - we->xrefline = 0; - we->msg = NULL; - we->xrefmsg = NULL; - - if (action == INS_HEAD) - SLIST_INSERT_HEAD(&errwarns->errwarns, we, link); - else if (action == INS_AFTER) { - assert(ins_we != NULL); - SLIST_INSERT_AFTER(ins_we, we, link); - } else - yasm_internal_error(N_("Unexpected errwarn insert action")); - } - - /* Remember previous err/warn */ - errwarns->previous_we = we; - - return we; -} - -void -yasm_error_clear(void) -{ - if (yasm_estr) - yasm_xfree(yasm_estr); - if (yasm_exrefstr) - yasm_xfree(yasm_exrefstr); - yasm_eclass = YASM_ERROR_NONE; - yasm_estr = NULL; - yasm_exrefline = 0; - yasm_exrefstr = NULL; -} - -int -yasm_error_matches(yasm_error_class eclass) -{ - if (yasm_eclass == YASM_ERROR_NONE) - return eclass == YASM_ERROR_NONE; - if (yasm_eclass == YASM_ERROR_GENERAL) - return eclass == YASM_ERROR_GENERAL; - return (yasm_eclass & eclass) == eclass; -} - -void -yasm_error_set_va(yasm_error_class eclass, const char *format, va_list va) -{ - if (yasm_eclass != YASM_ERROR_NONE) - return; - - yasm_eclass = eclass; - yasm_estr = yasm_xmalloc(MSG_MAXSIZE+1); -#ifdef HAVE_VSNPRINTF - vsnprintf(yasm_estr, MSG_MAXSIZE, yasm_gettext_hook(format), va); -#else - vsprintf(yasm_estr, yasm_gettext_hook(format), va); -#endif -} - -void -yasm_error_set(yasm_error_class eclass, const char *format, ...) -{ - va_list va; - va_start(va, format); - yasm_error_set_va(eclass, format, va); - va_end(va); -} - -void -yasm_error_set_xref_va(unsigned long xrefline, const char *format, va_list va) -{ - if (yasm_eclass != YASM_ERROR_NONE) - return; - - yasm_exrefline = xrefline; - - yasm_exrefstr = yasm_xmalloc(MSG_MAXSIZE+1); -#ifdef HAVE_VSNPRINTF - vsnprintf(yasm_exrefstr, MSG_MAXSIZE, yasm_gettext_hook(format), va); -#else - vsprintf(yasm_exrefstr, yasm_gettext_hook(format), va); -#endif -} - -void -yasm_error_set_xref(unsigned long xrefline, const char *format, ...) -{ - va_list va; - va_start(va, format); - yasm_error_set_xref_va(xrefline, format, va); - va_end(va); -} - -void -yasm_error_fetch(yasm_error_class *eclass, char **str, unsigned long *xrefline, - char **xrefstr) -{ - *eclass = yasm_eclass; - *str = yasm_estr; - *xrefline = yasm_exrefline; - *xrefstr = yasm_exrefstr; - yasm_eclass = YASM_ERROR_NONE; - yasm_estr = NULL; - yasm_exrefline = 0; - yasm_exrefstr = NULL; -} - -void yasm_warn_clear(void) -{ - /* Delete all error/warnings */ - while (!STAILQ_EMPTY(&yasm_warns)) { - warn *w = STAILQ_FIRST(&yasm_warns); - - if (w->wstr) - yasm_xfree(w->wstr); - - STAILQ_REMOVE_HEAD(&yasm_warns, link); - yasm_xfree(w); - } -} - -yasm_warn_class -yasm_warn_occurred(void) -{ - if (STAILQ_EMPTY(&yasm_warns)) - return YASM_WARN_NONE; - return STAILQ_FIRST(&yasm_warns)->wclass; -} - -void -yasm_warn_set_va(yasm_warn_class wclass, const char *format, va_list va) -{ - warn *w; - - if (!(warn_class_enabled & (1UL<<wclass))) - return; /* warning is part of disabled class */ - - w = yasm_xmalloc(sizeof(warn)); - w->wclass = wclass; - w->wstr = yasm_xmalloc(MSG_MAXSIZE+1); -#ifdef HAVE_VSNPRINTF - vsnprintf(w->wstr, MSG_MAXSIZE, yasm_gettext_hook(format), va); -#else - vsprintf(w->wstr, yasm_gettext_hook(format), va); -#endif - STAILQ_INSERT_TAIL(&yasm_warns, w, link); -} - -void -yasm_warn_set(yasm_warn_class wclass, const char *format, ...) -{ - va_list va; - va_start(va, format); - yasm_warn_set_va(wclass, format, va); - va_end(va); -} - -void -yasm_warn_fetch(yasm_warn_class *wclass, char **str) -{ - warn *w = STAILQ_FIRST(&yasm_warns); - - if (!w) { - *wclass = YASM_WARN_NONE; - *str = NULL; - return; - } - - *wclass = w->wclass; - *str = w->wstr; - - STAILQ_REMOVE_HEAD(&yasm_warns, link); - yasm_xfree(w); -} - -void -yasm_warn_enable(yasm_warn_class num) -{ - warn_class_enabled |= (1UL<<num); -} - -void -yasm_warn_disable(yasm_warn_class num) -{ - warn_class_enabled &= ~(1UL<<num); -} - -void -yasm_warn_disable_all(void) -{ - warn_class_enabled = 0; -} - -yasm_errwarns * -yasm_errwarns_create(void) -{ - yasm_errwarns *errwarns = yasm_xmalloc(sizeof(yasm_errwarns)); - SLIST_INIT(&errwarns->errwarns); - errwarns->ecount = 0; - errwarns->wcount = 0; - errwarns->previous_we = NULL; - return errwarns; -} - -void -yasm_errwarns_destroy(yasm_errwarns *errwarns) -{ - errwarn_data *we; - - /* Delete all error/warnings */ - while (!SLIST_EMPTY(&errwarns->errwarns)) { - we = SLIST_FIRST(&errwarns->errwarns); - if (we->msg) - yasm_xfree(we->msg); - if (we->xrefmsg) - yasm_xfree(we->xrefmsg); - - SLIST_REMOVE_HEAD(&errwarns->errwarns, link); - yasm_xfree(we); - } - - yasm_xfree(errwarns); -} - -void -yasm_errwarn_propagate(yasm_errwarns *errwarns, unsigned long line) -{ - if (yasm_eclass != YASM_ERROR_NONE) { - errwarn_data *we = errwarn_data_new(errwarns, line, 1); - yasm_error_class eclass; - - yasm_error_fetch(&eclass, &we->msg, &we->xrefline, &we->xrefmsg); - if (eclass != YASM_ERROR_GENERAL - && (eclass & YASM_ERROR_PARSE) == YASM_ERROR_PARSE) - we->type = WE_PARSERERROR; - else - we->type = WE_ERROR; - errwarns->ecount++; - } - - while (!STAILQ_EMPTY(&yasm_warns)) { - errwarn_data *we = errwarn_data_new(errwarns, line, 0); - yasm_warn_class wclass; - - yasm_warn_fetch(&wclass, &we->msg); - we->type = WE_WARNING; - errwarns->wcount++; - } -} - -unsigned int -yasm_errwarns_num_errors(yasm_errwarns *errwarns, int warning_as_error) -{ - if (warning_as_error) - return errwarns->ecount+errwarns->wcount; - else - return errwarns->ecount; -} - -void -yasm_errwarns_output_all(yasm_errwarns *errwarns, yasm_linemap *lm, - int warning_as_error, - yasm_print_error_func print_error, - yasm_print_warning_func print_warning) -{ - errwarn_data *we; - const char *filename, *xref_filename; - unsigned long line, xref_line; - - /* If we're treating warnings as errors, tell the user about it. */ - if (warning_as_error && warning_as_error != 2) { - print_error("", 0, - yasm_gettext_hook(N_("warnings being treated as errors")), - NULL, 0, NULL); - warning_as_error = 2; - } - - /* Output error/warnings. */ - SLIST_FOREACH(we, &errwarns->errwarns, link) { - /* Output error/warning */ - yasm_linemap_lookup(lm, we->line, &filename, &line); - if (we->xrefline) - yasm_linemap_lookup(lm, we->xrefline, &xref_filename, &xref_line); - else { - xref_filename = NULL; - xref_line = 0; - } - if (we->type == WE_ERROR || we->type == WE_PARSERERROR) - print_error(filename, line, we->msg, xref_filename, xref_line, - we->xrefmsg); - else - print_warning(filename, line, we->msg); - } -} - -void -yasm__fatal(const char *message, ...) -{ - va_list va; - va_start(va, message); - yasm_fatal(message, va); - /*@notreached@*/ - va_end(va); -} +#include <stdarg.h> + +#include "coretype.h" + +#include "linemap.h" +#include "errwarn.h" + + +#define MSG_MAXSIZE 1024 + +#if !defined(HAVE_TOASCII) || defined(lint) +# define toascii(c) ((c) & 0x7F) +#endif + +/* Default handlers for replacable functions */ +static /*@exits@*/ void def_internal_error_ + (const char *file, unsigned int line, const char *message); +static /*@exits@*/ void def_fatal(const char *message, va_list va); +static const char *def_gettext_hook(const char *msgid); + +/* Storage for errwarn's "extern" functions */ +/*@exits@*/ void (*yasm_internal_error_) + (const char *file, unsigned int line, const char *message) + = def_internal_error_; +/*@exits@*/ void (*yasm_fatal) (const char *message, va_list va) = def_fatal; +const char * (*yasm_gettext_hook) (const char *msgid) = def_gettext_hook; + +/* Error indicator */ +/* yasm_eclass is not static so that yasm_error_occurred macro can access it */ +yasm_error_class yasm_eclass; +static /*@only@*/ /*@null@*/ char *yasm_estr; +static unsigned long yasm_exrefline; +static /*@only@*/ /*@null@*/ char *yasm_exrefstr; + +/* Warning indicator */ +typedef struct warn { + /*@reldef@*/ STAILQ_ENTRY(warn) link; + + yasm_warn_class wclass; + /*@owned@*/ /*@null@*/ char *wstr; +} warn; +static STAILQ_HEAD(warn_head, warn) yasm_warns; + +/* Enabled warnings. See errwarn.h for a list. */ +static unsigned long warn_class_enabled; + +typedef struct errwarn_data { + /*@reldef@*/ SLIST_ENTRY(errwarn_data) link; + + enum { WE_UNKNOWN, WE_ERROR, WE_WARNING, WE_PARSERERROR } type; + + unsigned long line; + unsigned long xrefline; + /*@owned@*/ char *msg; + /*@owned@*/ char *xrefmsg; +} errwarn_data; + +struct yasm_errwarns { + /*@reldef@*/ SLIST_HEAD(errwarn_head, errwarn_data) errwarns; + + /* Total error count */ + unsigned int ecount; + + /* Total warning count */ + unsigned int wcount; + + /* Last inserted error/warning. Used to speed up insertions. */ + /*@null@*/ errwarn_data *previous_we; +}; + +/* Static buffer for use by conv_unprint(). */ +static char unprint[5]; + + +static const char * +def_gettext_hook(const char *msgid) +{ + return msgid; +} + +void +yasm_errwarn_initialize(void) +{ + /* Default enabled warnings. See errwarn.h for a list. */ + warn_class_enabled = + (1UL<<YASM_WARN_GENERAL) | (1UL<<YASM_WARN_UNREC_CHAR) | + (1UL<<YASM_WARN_PREPROC) | (0UL<<YASM_WARN_ORPHAN_LABEL) | + (1UL<<YASM_WARN_UNINIT_CONTENTS) | (0UL<<YASM_WARN_SIZE_OVERRIDE) | + (1UL<<YASM_WARN_IMPLICIT_SIZE_OVERRIDE); + + yasm_eclass = YASM_ERROR_NONE; + yasm_estr = NULL; + yasm_exrefline = 0; + yasm_exrefstr = NULL; + + STAILQ_INIT(&yasm_warns); +} + +void +yasm_errwarn_cleanup(void) +{ + yasm_error_clear(); + yasm_warn_clear(); +} + +/* Convert a possibly unprintable character into a printable string, using + * standard cat(1) convention for unprintable characters. + */ +char * +yasm__conv_unprint(int ch) +{ + int pos = 0; + + if (((ch & ~0x7F) != 0) /*!isascii(ch)*/ && !isprint(ch)) { + unprint[pos++] = 'M'; + unprint[pos++] = '-'; + ch &= toascii(ch); + } + if (iscntrl(ch)) { + unprint[pos++] = '^'; + unprint[pos++] = (ch == '\177') ? '?' : ch | 0100; + } else + unprint[pos++] = ch; + unprint[pos] = '\0'; + + return unprint; +} + +/* Report an internal error. Essentially a fatal error with trace info. + * Exit immediately because it's essentially an assert() trap. + */ +static void +def_internal_error_(const char *file, unsigned int line, const char *message) +{ + fprintf(stderr, + yasm_gettext_hook(N_("INTERNAL ERROR at %s, line %u: %s\n")), + file, line, yasm_gettext_hook(message)); +#ifdef HAVE_ABORT + abort(); +#else + exit(EXIT_FAILURE); +#endif +} + +/* Report a fatal error. These are unrecoverable (such as running out of + * memory), so just exit immediately. + */ +static void +def_fatal(const char *fmt, va_list va) +{ + fprintf(stderr, "%s: ", yasm_gettext_hook(N_("FATAL"))); + vfprintf(stderr, yasm_gettext_hook(fmt), va); + fputc('\n', stderr); + exit(EXIT_FAILURE); +} + +/* Create an errwarn structure in the correct linked list location. + * If replace_parser_error is nonzero, overwrites the last error if its + * type is WE_PARSERERROR. + */ +static errwarn_data * +errwarn_data_new(yasm_errwarns *errwarns, unsigned long line, + int replace_parser_error) +{ + errwarn_data *first, *next, *ins_we, *we; + enum { INS_NONE, INS_HEAD, INS_AFTER } action = INS_NONE; + + /* Find the entry with either line=line or the last one with line<line. + * Start with the last entry added to speed the search. + */ + ins_we = errwarns->previous_we; + first = SLIST_FIRST(&errwarns->errwarns); + if (!ins_we || !first) + action = INS_HEAD; + while (action == INS_NONE) { + next = SLIST_NEXT(ins_we, link); + if (line < ins_we->line) { + if (ins_we == first) + action = INS_HEAD; + else + ins_we = first; + } else if (!next) + action = INS_AFTER; + else if (line >= ins_we->line && line < next->line) + action = INS_AFTER; + else + ins_we = next; + } + + if (replace_parser_error && ins_we && ins_we->type == WE_PARSERERROR) { + /* overwrite last error */ + we = ins_we; + } else { + /* add a new error */ + we = yasm_xmalloc(sizeof(errwarn_data)); + + we->type = WE_UNKNOWN; + we->line = line; + we->xrefline = 0; + we->msg = NULL; + we->xrefmsg = NULL; + + if (action == INS_HEAD) + SLIST_INSERT_HEAD(&errwarns->errwarns, we, link); + else if (action == INS_AFTER) { + assert(ins_we != NULL); + SLIST_INSERT_AFTER(ins_we, we, link); + } else + yasm_internal_error(N_("Unexpected errwarn insert action")); + } + + /* Remember previous err/warn */ + errwarns->previous_we = we; + + return we; +} + +void +yasm_error_clear(void) +{ + if (yasm_estr) + yasm_xfree(yasm_estr); + if (yasm_exrefstr) + yasm_xfree(yasm_exrefstr); + yasm_eclass = YASM_ERROR_NONE; + yasm_estr = NULL; + yasm_exrefline = 0; + yasm_exrefstr = NULL; +} + +int +yasm_error_matches(yasm_error_class eclass) +{ + if (yasm_eclass == YASM_ERROR_NONE) + return eclass == YASM_ERROR_NONE; + if (yasm_eclass == YASM_ERROR_GENERAL) + return eclass == YASM_ERROR_GENERAL; + return (yasm_eclass & eclass) == eclass; +} + +void +yasm_error_set_va(yasm_error_class eclass, const char *format, va_list va) +{ + if (yasm_eclass != YASM_ERROR_NONE) + return; + + yasm_eclass = eclass; + yasm_estr = yasm_xmalloc(MSG_MAXSIZE+1); +#ifdef HAVE_VSNPRINTF + vsnprintf(yasm_estr, MSG_MAXSIZE, yasm_gettext_hook(format), va); +#else + vsprintf(yasm_estr, yasm_gettext_hook(format), va); +#endif +} + +void +yasm_error_set(yasm_error_class eclass, const char *format, ...) +{ + va_list va; + va_start(va, format); + yasm_error_set_va(eclass, format, va); + va_end(va); +} + +void +yasm_error_set_xref_va(unsigned long xrefline, const char *format, va_list va) +{ + if (yasm_eclass != YASM_ERROR_NONE) + return; + + yasm_exrefline = xrefline; + + yasm_exrefstr = yasm_xmalloc(MSG_MAXSIZE+1); +#ifdef HAVE_VSNPRINTF + vsnprintf(yasm_exrefstr, MSG_MAXSIZE, yasm_gettext_hook(format), va); +#else + vsprintf(yasm_exrefstr, yasm_gettext_hook(format), va); +#endif +} + +void +yasm_error_set_xref(unsigned long xrefline, const char *format, ...) +{ + va_list va; + va_start(va, format); + yasm_error_set_xref_va(xrefline, format, va); + va_end(va); +} + +void +yasm_error_fetch(yasm_error_class *eclass, char **str, unsigned long *xrefline, + char **xrefstr) +{ + *eclass = yasm_eclass; + *str = yasm_estr; + *xrefline = yasm_exrefline; + *xrefstr = yasm_exrefstr; + yasm_eclass = YASM_ERROR_NONE; + yasm_estr = NULL; + yasm_exrefline = 0; + yasm_exrefstr = NULL; +} + +void yasm_warn_clear(void) +{ + /* Delete all error/warnings */ + while (!STAILQ_EMPTY(&yasm_warns)) { + warn *w = STAILQ_FIRST(&yasm_warns); + + if (w->wstr) + yasm_xfree(w->wstr); + + STAILQ_REMOVE_HEAD(&yasm_warns, link); + yasm_xfree(w); + } +} + +yasm_warn_class +yasm_warn_occurred(void) +{ + if (STAILQ_EMPTY(&yasm_warns)) + return YASM_WARN_NONE; + return STAILQ_FIRST(&yasm_warns)->wclass; +} + +void +yasm_warn_set_va(yasm_warn_class wclass, const char *format, va_list va) +{ + warn *w; + + if (!(warn_class_enabled & (1UL<<wclass))) + return; /* warning is part of disabled class */ + + w = yasm_xmalloc(sizeof(warn)); + w->wclass = wclass; + w->wstr = yasm_xmalloc(MSG_MAXSIZE+1); +#ifdef HAVE_VSNPRINTF + vsnprintf(w->wstr, MSG_MAXSIZE, yasm_gettext_hook(format), va); +#else + vsprintf(w->wstr, yasm_gettext_hook(format), va); +#endif + STAILQ_INSERT_TAIL(&yasm_warns, w, link); +} + +void +yasm_warn_set(yasm_warn_class wclass, const char *format, ...) +{ + va_list va; + va_start(va, format); + yasm_warn_set_va(wclass, format, va); + va_end(va); +} + +void +yasm_warn_fetch(yasm_warn_class *wclass, char **str) +{ + warn *w = STAILQ_FIRST(&yasm_warns); + + if (!w) { + *wclass = YASM_WARN_NONE; + *str = NULL; + return; + } + + *wclass = w->wclass; + *str = w->wstr; + + STAILQ_REMOVE_HEAD(&yasm_warns, link); + yasm_xfree(w); +} + +void +yasm_warn_enable(yasm_warn_class num) +{ + warn_class_enabled |= (1UL<<num); +} + +void +yasm_warn_disable(yasm_warn_class num) +{ + warn_class_enabled &= ~(1UL<<num); +} + +void +yasm_warn_disable_all(void) +{ + warn_class_enabled = 0; +} + +yasm_errwarns * +yasm_errwarns_create(void) +{ + yasm_errwarns *errwarns = yasm_xmalloc(sizeof(yasm_errwarns)); + SLIST_INIT(&errwarns->errwarns); + errwarns->ecount = 0; + errwarns->wcount = 0; + errwarns->previous_we = NULL; + return errwarns; +} + +void +yasm_errwarns_destroy(yasm_errwarns *errwarns) +{ + errwarn_data *we; + + /* Delete all error/warnings */ + while (!SLIST_EMPTY(&errwarns->errwarns)) { + we = SLIST_FIRST(&errwarns->errwarns); + if (we->msg) + yasm_xfree(we->msg); + if (we->xrefmsg) + yasm_xfree(we->xrefmsg); + + SLIST_REMOVE_HEAD(&errwarns->errwarns, link); + yasm_xfree(we); + } + + yasm_xfree(errwarns); +} + +void +yasm_errwarn_propagate(yasm_errwarns *errwarns, unsigned long line) +{ + if (yasm_eclass != YASM_ERROR_NONE) { + errwarn_data *we = errwarn_data_new(errwarns, line, 1); + yasm_error_class eclass; + + yasm_error_fetch(&eclass, &we->msg, &we->xrefline, &we->xrefmsg); + if (eclass != YASM_ERROR_GENERAL + && (eclass & YASM_ERROR_PARSE) == YASM_ERROR_PARSE) + we->type = WE_PARSERERROR; + else + we->type = WE_ERROR; + errwarns->ecount++; + } + + while (!STAILQ_EMPTY(&yasm_warns)) { + errwarn_data *we = errwarn_data_new(errwarns, line, 0); + yasm_warn_class wclass; + + yasm_warn_fetch(&wclass, &we->msg); + we->type = WE_WARNING; + errwarns->wcount++; + } +} + +unsigned int +yasm_errwarns_num_errors(yasm_errwarns *errwarns, int warning_as_error) +{ + if (warning_as_error) + return errwarns->ecount+errwarns->wcount; + else + return errwarns->ecount; +} + +void +yasm_errwarns_output_all(yasm_errwarns *errwarns, yasm_linemap *lm, + int warning_as_error, + yasm_print_error_func print_error, + yasm_print_warning_func print_warning) +{ + errwarn_data *we; + const char *filename, *xref_filename; + unsigned long line, xref_line; + + /* If we're treating warnings as errors, tell the user about it. */ + if (warning_as_error && warning_as_error != 2) { + print_error("", 0, + yasm_gettext_hook(N_("warnings being treated as errors")), + NULL, 0, NULL); + warning_as_error = 2; + } + + /* Output error/warnings. */ + SLIST_FOREACH(we, &errwarns->errwarns, link) { + /* Output error/warning */ + yasm_linemap_lookup(lm, we->line, &filename, &line); + if (we->xrefline) + yasm_linemap_lookup(lm, we->xrefline, &xref_filename, &xref_line); + else { + xref_filename = NULL; + xref_line = 0; + } + if (we->type == WE_ERROR || we->type == WE_PARSERERROR) + print_error(filename, line, we->msg, xref_filename, xref_line, + we->xrefmsg); + else + print_warning(filename, line, we->msg); + } +} + +void +yasm__fatal(const char *message, ...) +{ + va_list va; + va_start(va, message); + yasm_fatal(message, va); + /*@notreached@*/ + va_end(va); +} void yasm__fatal_missing_input_file(const char *message, const char *filename) diff --git a/contrib/tools/yasm/libyasm/errwarn.h b/contrib/tools/yasm/libyasm/errwarn.h index f8e4f10ec3..4333528ce8 100644 --- a/contrib/tools/yasm/libyasm/errwarn.h +++ b/contrib/tools/yasm/libyasm/errwarn.h @@ -1,351 +1,351 @@ -/** - * \file libyasm/errwarn.h - * \brief YASM error and warning reporting interface. - * - * \license - * Copyright (C) 2001-2007 Peter Johnson - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * \endlicense - */ -#ifndef YASM_ERRWARN_H -#define YASM_ERRWARN_H - -#ifndef YASM_LIB_DECL -#define YASM_LIB_DECL -#endif - -/** Warning classes (that may be enabled/disabled). */ -typedef enum yasm_warn_class { - YASM_WARN_NONE = 0, /**< No warning */ - YASM_WARN_GENERAL, /**< Non-specific warnings */ - YASM_WARN_UNREC_CHAR, /**< Unrecognized characters (while tokenizing) */ - YASM_WARN_PREPROC, /**< Preprocessor warnings */ - YASM_WARN_ORPHAN_LABEL, /**< Label alone on a line without a colon */ - YASM_WARN_UNINIT_CONTENTS, /**< Uninitialized space in code/data section */ - YASM_WARN_SIZE_OVERRIDE,/**< Double size override */ - YASM_WARN_IMPLICIT_SIZE_OVERRIDE /**< Implicit size override */ -} yasm_warn_class; - -/** Error classes. Bitmask-based to support limited subclassing. */ -typedef enum yasm_error_class { - YASM_ERROR_NONE = 0x0000, /**< No error */ - YASM_ERROR_GENERAL = 0xFFFF, /**< Non-specific */ - YASM_ERROR_ARITHMETIC = 0x0001, /**< Arithmetic error (general) */ - YASM_ERROR_OVERFLOW = 0x8001, /**< Arithmetic overflow */ - YASM_ERROR_FLOATING_POINT = 0x4001, /**< Floating point error */ - YASM_ERROR_ZERO_DIVISION = 0x2001, /**< Divide-by-zero */ - YASM_ERROR_ASSERTION = 0x0002, /**< Assertion error */ - YASM_ERROR_VALUE = 0x0004, /**< Value inappropriate - * (e.g. not in range) */ - YASM_ERROR_NOT_ABSOLUTE = 0x8004, /**< Absolute expression required */ - YASM_ERROR_TOO_COMPLEX = 0x4004, /**< Expression too complex */ - YASM_ERROR_NOT_CONSTANT = 0x2004, /**< Constant expression required */ - YASM_ERROR_IO = 0x0008, /**< I/O error */ - YASM_ERROR_NOT_IMPLEMENTED = 0x0010, /**< Not implemented error */ - YASM_ERROR_TYPE = 0x0020, /**< Type error */ - YASM_ERROR_SYNTAX = 0x0040, /**< Syntax error */ - YASM_ERROR_PARSE = 0x8040 /**< Parser error */ -} yasm_error_class; - -/** Initialize any internal data structures. */ -YASM_LIB_DECL -void yasm_errwarn_initialize(void); - -/** Clean up any memory allocated by yasm_errwarn_initialize() or other - * functions. - */ -YASM_LIB_DECL -void yasm_errwarn_cleanup(void); - -/** Reporting point of internal errors. These are usually due to sanity - * check failures in the code. - * \warning This function must NOT return to calling code; exit or longjmp - * instead. - * \param file source file (ala __FILE__) - * \param line source line (ala __LINE__) - * \param message internal error message - */ -YASM_LIB_DECL -extern /*@exits@*/ void (*yasm_internal_error_) - (const char *file, unsigned int line, const char *message); - -/** Easily-callable version of yasm_internal_error_(). Automatically uses - * __FILE__ and __LINE__ as the file and line. - * \param message internal error message - */ -#define yasm_internal_error(message) \ - yasm_internal_error_(__FILE__, __LINE__, message) - -/** Reporting point of fatal errors. - * \warning This function must NOT return to calling code; exit or longjmp - * instead. - * \param message fatal error message - * \param va va_list argument list for message - */ -YASM_LIB_DECL -extern /*@exits@*/ void (*yasm_fatal) (const char *message, va_list va); - -/** Reporting point of fatal errors, with variable arguments (internal only). - * \warning This function calls #yasm_fatal, and thus does not return to the - * calling code. - * \param message fatal error message - * \param ... argument list for message - */ -YASM_LIB_DECL -/*@exits@*/ void yasm__fatal(const char *message, ...); - +/** + * \file libyasm/errwarn.h + * \brief YASM error and warning reporting interface. + * + * \license + * Copyright (C) 2001-2007 Peter Johnson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * \endlicense + */ +#ifndef YASM_ERRWARN_H +#define YASM_ERRWARN_H + +#ifndef YASM_LIB_DECL +#define YASM_LIB_DECL +#endif + +/** Warning classes (that may be enabled/disabled). */ +typedef enum yasm_warn_class { + YASM_WARN_NONE = 0, /**< No warning */ + YASM_WARN_GENERAL, /**< Non-specific warnings */ + YASM_WARN_UNREC_CHAR, /**< Unrecognized characters (while tokenizing) */ + YASM_WARN_PREPROC, /**< Preprocessor warnings */ + YASM_WARN_ORPHAN_LABEL, /**< Label alone on a line without a colon */ + YASM_WARN_UNINIT_CONTENTS, /**< Uninitialized space in code/data section */ + YASM_WARN_SIZE_OVERRIDE,/**< Double size override */ + YASM_WARN_IMPLICIT_SIZE_OVERRIDE /**< Implicit size override */ +} yasm_warn_class; + +/** Error classes. Bitmask-based to support limited subclassing. */ +typedef enum yasm_error_class { + YASM_ERROR_NONE = 0x0000, /**< No error */ + YASM_ERROR_GENERAL = 0xFFFF, /**< Non-specific */ + YASM_ERROR_ARITHMETIC = 0x0001, /**< Arithmetic error (general) */ + YASM_ERROR_OVERFLOW = 0x8001, /**< Arithmetic overflow */ + YASM_ERROR_FLOATING_POINT = 0x4001, /**< Floating point error */ + YASM_ERROR_ZERO_DIVISION = 0x2001, /**< Divide-by-zero */ + YASM_ERROR_ASSERTION = 0x0002, /**< Assertion error */ + YASM_ERROR_VALUE = 0x0004, /**< Value inappropriate + * (e.g. not in range) */ + YASM_ERROR_NOT_ABSOLUTE = 0x8004, /**< Absolute expression required */ + YASM_ERROR_TOO_COMPLEX = 0x4004, /**< Expression too complex */ + YASM_ERROR_NOT_CONSTANT = 0x2004, /**< Constant expression required */ + YASM_ERROR_IO = 0x0008, /**< I/O error */ + YASM_ERROR_NOT_IMPLEMENTED = 0x0010, /**< Not implemented error */ + YASM_ERROR_TYPE = 0x0020, /**< Type error */ + YASM_ERROR_SYNTAX = 0x0040, /**< Syntax error */ + YASM_ERROR_PARSE = 0x8040 /**< Parser error */ +} yasm_error_class; + +/** Initialize any internal data structures. */ +YASM_LIB_DECL +void yasm_errwarn_initialize(void); + +/** Clean up any memory allocated by yasm_errwarn_initialize() or other + * functions. + */ +YASM_LIB_DECL +void yasm_errwarn_cleanup(void); + +/** Reporting point of internal errors. These are usually due to sanity + * check failures in the code. + * \warning This function must NOT return to calling code; exit or longjmp + * instead. + * \param file source file (ala __FILE__) + * \param line source line (ala __LINE__) + * \param message internal error message + */ +YASM_LIB_DECL +extern /*@exits@*/ void (*yasm_internal_error_) + (const char *file, unsigned int line, const char *message); + +/** Easily-callable version of yasm_internal_error_(). Automatically uses + * __FILE__ and __LINE__ as the file and line. + * \param message internal error message + */ +#define yasm_internal_error(message) \ + yasm_internal_error_(__FILE__, __LINE__, message) + +/** Reporting point of fatal errors. + * \warning This function must NOT return to calling code; exit or longjmp + * instead. + * \param message fatal error message + * \param va va_list argument list for message + */ +YASM_LIB_DECL +extern /*@exits@*/ void (*yasm_fatal) (const char *message, va_list va); + +/** Reporting point of fatal errors, with variable arguments (internal only). + * \warning This function calls #yasm_fatal, and thus does not return to the + * calling code. + * \param message fatal error message + * \param ... argument list for message + */ +YASM_LIB_DECL +/*@exits@*/ void yasm__fatal(const char *message, ...); + YASM_LIB_DECL /*@exits@*/ void yasm__fatal_missing_input_file(const char *message, const char *filename); -/** Unconditionally clear the error indicator, freeing any associated data. - * Has no effect if the error indicator is not set. - */ -YASM_LIB_DECL -void yasm_error_clear(void); - -/** Get the error indicator. YASM_ERROR_NONE is returned if no error has - * been set. Note that as YASM_ERROR_NONE is 0, the return value can also - * be treated as a boolean value. - * \return Current error indicator. - */ -yasm_error_class yasm_error_occurred(void); - -/** Check the error indicator against an error class. To check if any error - * has been set, check against the YASM_ERROR_GENERAL class. This function - * properly checks error subclasses. - * \param eclass base error class to check against - * \return Nonzero if error indicator is set and a subclass of eclass, 0 - * otherwise. - */ -YASM_LIB_DECL -int yasm_error_matches(yasm_error_class eclass); - -#ifndef YASM_DOXYGEN -YASM_LIB_DECL -extern yasm_error_class yasm_eclass; -#define yasm_error_occurred() yasm_eclass -#endif - -/** Set the error indicator (va_list version). Has no effect if the error - * indicator is already set. - * \param eclass error class - * \param format printf format string - * \param va argument list for format - */ -YASM_LIB_DECL -void yasm_error_set_va(yasm_error_class eclass, const char *format, va_list va); - -/** Set the error indicator. Has no effect if the error indicator is already - * set. - * \param eclass error class - * \param format printf format string - * \param ... argument list for format - */ -YASM_LIB_DECL -void yasm_error_set(yasm_error_class eclass, const char *format, ...) - /*@printflike@*/; - -/** Set a cross-reference for a new error (va_list version). Has no effect - * if the error indicator is already set (e.g. with yasm_error_set()). This - * function must be called prior to its corresponding yasm_error_set() call. - * \param xrefline virtual line to cross-reference to (should not be 0) - * \param format printf format string - * \param va argument list for format - */ -YASM_LIB_DECL -void yasm_error_set_xref_va(unsigned long xrefline, const char *format, - va_list va); - -/** Set a cross-reference for a new error. Has no effect if the error - * indicator is already set (e.g. with yasm_error_set()). This function - * must be called prior to its corresponding yasm_error_set() call. - * \param xrefline virtual line to cross-reference to (should not be 0) - * \param format printf format string - * \param ... argument list for format - */ -YASM_LIB_DECL -void yasm_error_set_xref(unsigned long xrefline, const char *format, ...) - /*@printflike@*/; - -/** Fetch the error indicator and all associated data. If the error - * indicator is set, the output pointers are set to the current error - * indicator values, and the error indicator is cleared. - * The code using this function is then responsible for yasm_xfree()'ing - * str and xrefstr (if non-NULL). If the error indicator is not set, - * all output values are set to 0 (including eclass, which is set to - * YASM_ERROR_NONE). - * \param eclass error class (output) - * \param str error message - * \param xrefline virtual line used for cross-referencing (0 if no xref) - * \param xrefstr cross-reference error message (NULL if no xref) - */ -YASM_LIB_DECL -void yasm_error_fetch(/*@out@*/ yasm_error_class *eclass, - /*@out@*/ /*@only@*/ /*@null@*/ char **str, - /*@out@*/ unsigned long *xrefline, - /*@out@*/ /*@only@*/ /*@null@*/ char **xrefstr); - -/** Unconditionally clear all warning indicators, freeing any associated data. - * Has no effect if no warning indicators have been set. - */ -YASM_LIB_DECL -void yasm_warn_clear(void); - -/** Get the first warning indicator. YASM_WARN_NONE is returned if no warning - * has been set. Note that as YASM_WARN_NONE is 0, the return value can also - * be treated as a boolean value. - * \return First warning indicator. - */ -YASM_LIB_DECL -yasm_warn_class yasm_warn_occurred(void); - -/** Add a warning indicator (va_list version). - * \param wclass warning class - * \param format printf format string - * \param va argument list for format - */ -YASM_LIB_DECL -void yasm_warn_set_va(yasm_warn_class wclass, const char *format, va_list va); - -/** Add a warning indicator. - * \param wclass warning class - * \param format printf format string - * \param ... argument list for format - */ -YASM_LIB_DECL -void yasm_warn_set(yasm_warn_class wclass, const char *format, ...) - /*@printflike@*/; - -/** Fetch the first warning indicator and all associated data. If there - * is at least one warning indicator, the output pointers are set to the - * first warning indicator values, and first warning indicator is removed. - * The code using this function is then responsible for yasm_xfree()'ing - * str and xrefstr (if non-NULL). If there is no warning indicator set, - * all output values are set to 0 (including wclass, which is set to - * YASM_WARN_NONE). - * \param wclass warning class (output) - * \param str warning message - */ -YASM_LIB_DECL -void yasm_warn_fetch(/*@out@*/ yasm_warn_class *wclass, - /*@out@*/ /*@only@*/ char **str); - -/** Enable a class of warnings. - * \param wclass warning class - */ -YASM_LIB_DECL -void yasm_warn_enable(yasm_warn_class wclass); - -/** Disable a class of warnings. - * \param wclass warning class - */ -YASM_LIB_DECL -void yasm_warn_disable(yasm_warn_class wclass); - -/** Disable all classes of warnings. */ -YASM_LIB_DECL -void yasm_warn_disable_all(void); - -/** Create an error/warning set for collection of multiple error/warnings. - * \return Newly allocated set. - */ -YASM_LIB_DECL -/*@only@*/ yasm_errwarns *yasm_errwarns_create(void); - -/** Destroy an error/warning set. - * \param errwarns error/warning set - */ -YASM_LIB_DECL -void yasm_errwarns_destroy(/*@only@*/ yasm_errwarns *errwarns); - -/** Propagate error indicator and warning indicator(s) to an error/warning set. - * Has no effect if the error indicator and warning indicator are not set. - * Does not print immediately; yasm_errwarn_output_all() outputs - * accumulated errors and warnings. - * Generally multiple errors on the same line will be reported, but errors - * of class YASM_ERROR_PARSE will get overwritten by any other class on the - * same line. - * \param errwarns error/warning set - * \param line virtual line - */ -YASM_LIB_DECL -void yasm_errwarn_propagate(yasm_errwarns *errwarns, unsigned long line); - -/** Get total number of errors logged. - * \param errwarns error/warning set - * \param warning_as_error if nonzero, warnings are treated as errors. - * \return Number of errors. - */ -YASM_LIB_DECL -unsigned int yasm_errwarns_num_errors(yasm_errwarns *errwarns, - int warning_as_error); - -/** Print out an error. - * \param fn filename of source file - * \param line line number - * \param msg error message - * \param xref_fn cross-referenced source filename - * \param xref_line cross-referenced line number - * \param xref_msg cross-referenced error message - */ -typedef void (*yasm_print_error_func) - (const char *fn, unsigned long line, const char *msg, - /*@null@*/ const char *xref_fn, unsigned long xref_line, - /*@null@*/ const char *xref_msg); - -/** Print out a warning. - * \param fn filename of source file - * \param line line number - * \param msg warning message - */ -typedef void (*yasm_print_warning_func) - (const char *fn, unsigned long line, const char *msg); - -/** Outputs error/warning set in sorted order (sorted by virtual line number). - * \param errwarns error/warning set - * \param lm line map (to convert virtual lines into filename/line pairs) - * \param warning_as_error if nonzero, treat warnings as errors. - * \param print_error function called to print out errors - * \param print_warning function called to print out warnings - */ -YASM_LIB_DECL -void yasm_errwarns_output_all - (yasm_errwarns *errwarns, yasm_linemap *lm, int warning_as_error, - yasm_print_error_func print_error, yasm_print_warning_func print_warning); - -/** Convert a possibly unprintable character into a printable string. - * \internal - * \param ch possibly unprintable character - * \return Printable string representation (static buffer). - */ -YASM_LIB_DECL -char *yasm__conv_unprint(int ch); - -/** Hook for library users to map to gettext() if GNU gettext is being used. - * \param msgid message catalog identifier - * \return Translated message. - */ -YASM_LIB_DECL -extern const char * (*yasm_gettext_hook) (const char *msgid); - -#endif +/** Unconditionally clear the error indicator, freeing any associated data. + * Has no effect if the error indicator is not set. + */ +YASM_LIB_DECL +void yasm_error_clear(void); + +/** Get the error indicator. YASM_ERROR_NONE is returned if no error has + * been set. Note that as YASM_ERROR_NONE is 0, the return value can also + * be treated as a boolean value. + * \return Current error indicator. + */ +yasm_error_class yasm_error_occurred(void); + +/** Check the error indicator against an error class. To check if any error + * has been set, check against the YASM_ERROR_GENERAL class. This function + * properly checks error subclasses. + * \param eclass base error class to check against + * \return Nonzero if error indicator is set and a subclass of eclass, 0 + * otherwise. + */ +YASM_LIB_DECL +int yasm_error_matches(yasm_error_class eclass); + +#ifndef YASM_DOXYGEN +YASM_LIB_DECL +extern yasm_error_class yasm_eclass; +#define yasm_error_occurred() yasm_eclass +#endif + +/** Set the error indicator (va_list version). Has no effect if the error + * indicator is already set. + * \param eclass error class + * \param format printf format string + * \param va argument list for format + */ +YASM_LIB_DECL +void yasm_error_set_va(yasm_error_class eclass, const char *format, va_list va); + +/** Set the error indicator. Has no effect if the error indicator is already + * set. + * \param eclass error class + * \param format printf format string + * \param ... argument list for format + */ +YASM_LIB_DECL +void yasm_error_set(yasm_error_class eclass, const char *format, ...) + /*@printflike@*/; + +/** Set a cross-reference for a new error (va_list version). Has no effect + * if the error indicator is already set (e.g. with yasm_error_set()). This + * function must be called prior to its corresponding yasm_error_set() call. + * \param xrefline virtual line to cross-reference to (should not be 0) + * \param format printf format string + * \param va argument list for format + */ +YASM_LIB_DECL +void yasm_error_set_xref_va(unsigned long xrefline, const char *format, + va_list va); + +/** Set a cross-reference for a new error. Has no effect if the error + * indicator is already set (e.g. with yasm_error_set()). This function + * must be called prior to its corresponding yasm_error_set() call. + * \param xrefline virtual line to cross-reference to (should not be 0) + * \param format printf format string + * \param ... argument list for format + */ +YASM_LIB_DECL +void yasm_error_set_xref(unsigned long xrefline, const char *format, ...) + /*@printflike@*/; + +/** Fetch the error indicator and all associated data. If the error + * indicator is set, the output pointers are set to the current error + * indicator values, and the error indicator is cleared. + * The code using this function is then responsible for yasm_xfree()'ing + * str and xrefstr (if non-NULL). If the error indicator is not set, + * all output values are set to 0 (including eclass, which is set to + * YASM_ERROR_NONE). + * \param eclass error class (output) + * \param str error message + * \param xrefline virtual line used for cross-referencing (0 if no xref) + * \param xrefstr cross-reference error message (NULL if no xref) + */ +YASM_LIB_DECL +void yasm_error_fetch(/*@out@*/ yasm_error_class *eclass, + /*@out@*/ /*@only@*/ /*@null@*/ char **str, + /*@out@*/ unsigned long *xrefline, + /*@out@*/ /*@only@*/ /*@null@*/ char **xrefstr); + +/** Unconditionally clear all warning indicators, freeing any associated data. + * Has no effect if no warning indicators have been set. + */ +YASM_LIB_DECL +void yasm_warn_clear(void); + +/** Get the first warning indicator. YASM_WARN_NONE is returned if no warning + * has been set. Note that as YASM_WARN_NONE is 0, the return value can also + * be treated as a boolean value. + * \return First warning indicator. + */ +YASM_LIB_DECL +yasm_warn_class yasm_warn_occurred(void); + +/** Add a warning indicator (va_list version). + * \param wclass warning class + * \param format printf format string + * \param va argument list for format + */ +YASM_LIB_DECL +void yasm_warn_set_va(yasm_warn_class wclass, const char *format, va_list va); + +/** Add a warning indicator. + * \param wclass warning class + * \param format printf format string + * \param ... argument list for format + */ +YASM_LIB_DECL +void yasm_warn_set(yasm_warn_class wclass, const char *format, ...) + /*@printflike@*/; + +/** Fetch the first warning indicator and all associated data. If there + * is at least one warning indicator, the output pointers are set to the + * first warning indicator values, and first warning indicator is removed. + * The code using this function is then responsible for yasm_xfree()'ing + * str and xrefstr (if non-NULL). If there is no warning indicator set, + * all output values are set to 0 (including wclass, which is set to + * YASM_WARN_NONE). + * \param wclass warning class (output) + * \param str warning message + */ +YASM_LIB_DECL +void yasm_warn_fetch(/*@out@*/ yasm_warn_class *wclass, + /*@out@*/ /*@only@*/ char **str); + +/** Enable a class of warnings. + * \param wclass warning class + */ +YASM_LIB_DECL +void yasm_warn_enable(yasm_warn_class wclass); + +/** Disable a class of warnings. + * \param wclass warning class + */ +YASM_LIB_DECL +void yasm_warn_disable(yasm_warn_class wclass); + +/** Disable all classes of warnings. */ +YASM_LIB_DECL +void yasm_warn_disable_all(void); + +/** Create an error/warning set for collection of multiple error/warnings. + * \return Newly allocated set. + */ +YASM_LIB_DECL +/*@only@*/ yasm_errwarns *yasm_errwarns_create(void); + +/** Destroy an error/warning set. + * \param errwarns error/warning set + */ +YASM_LIB_DECL +void yasm_errwarns_destroy(/*@only@*/ yasm_errwarns *errwarns); + +/** Propagate error indicator and warning indicator(s) to an error/warning set. + * Has no effect if the error indicator and warning indicator are not set. + * Does not print immediately; yasm_errwarn_output_all() outputs + * accumulated errors and warnings. + * Generally multiple errors on the same line will be reported, but errors + * of class YASM_ERROR_PARSE will get overwritten by any other class on the + * same line. + * \param errwarns error/warning set + * \param line virtual line + */ +YASM_LIB_DECL +void yasm_errwarn_propagate(yasm_errwarns *errwarns, unsigned long line); + +/** Get total number of errors logged. + * \param errwarns error/warning set + * \param warning_as_error if nonzero, warnings are treated as errors. + * \return Number of errors. + */ +YASM_LIB_DECL +unsigned int yasm_errwarns_num_errors(yasm_errwarns *errwarns, + int warning_as_error); + +/** Print out an error. + * \param fn filename of source file + * \param line line number + * \param msg error message + * \param xref_fn cross-referenced source filename + * \param xref_line cross-referenced line number + * \param xref_msg cross-referenced error message + */ +typedef void (*yasm_print_error_func) + (const char *fn, unsigned long line, const char *msg, + /*@null@*/ const char *xref_fn, unsigned long xref_line, + /*@null@*/ const char *xref_msg); + +/** Print out a warning. + * \param fn filename of source file + * \param line line number + * \param msg warning message + */ +typedef void (*yasm_print_warning_func) + (const char *fn, unsigned long line, const char *msg); + +/** Outputs error/warning set in sorted order (sorted by virtual line number). + * \param errwarns error/warning set + * \param lm line map (to convert virtual lines into filename/line pairs) + * \param warning_as_error if nonzero, treat warnings as errors. + * \param print_error function called to print out errors + * \param print_warning function called to print out warnings + */ +YASM_LIB_DECL +void yasm_errwarns_output_all + (yasm_errwarns *errwarns, yasm_linemap *lm, int warning_as_error, + yasm_print_error_func print_error, yasm_print_warning_func print_warning); + +/** Convert a possibly unprintable character into a printable string. + * \internal + * \param ch possibly unprintable character + * \return Printable string representation (static buffer). + */ +YASM_LIB_DECL +char *yasm__conv_unprint(int ch); + +/** Hook for library users to map to gettext() if GNU gettext is being used. + * \param msgid message catalog identifier + * \return Translated message. + */ +YASM_LIB_DECL +extern const char * (*yasm_gettext_hook) (const char *msgid); + +#endif diff --git a/contrib/tools/yasm/libyasm/expr.c b/contrib/tools/yasm/libyasm/expr.c index c2c868ede2..4c9958449d 100644 --- a/contrib/tools/yasm/libyasm/expr.c +++ b/contrib/tools/yasm/libyasm/expr.c @@ -1,1516 +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; -} +/* + * Expression handling + * + * Copyright (C) 2001-2007 Michael Urman, Peter Johnson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include "util.h" + +#include "libyasm-stdint.h" +#include "coretype.h" +#include "bitvect.h" + +#include "errwarn.h" +#include "intnum.h" +#include "floatnum.h" +#include "expr.h" +#include "symrec.h" + +#include "bytecode.h" +#include "section.h" + +#include "arch.h" + + +static /*@only@*/ yasm_expr *expr_level_op + (/*@returned@*/ /*@only@*/ yasm_expr *e, int fold_const, + int simplify_ident, int simplify_reg_mul); +static int expr_traverse_nodes_post(/*@null@*/ yasm_expr *e, + /*@null@*/ void *d, + int (*func) (/*@null@*/ yasm_expr *e, + /*@null@*/ void *d)); +static void expr_delete_term(yasm_expr__item *term, int recurse); + +/* Bitmap of used items. We should really never need more than 2 at a time, + * so 31 is pretty much overkill. + */ +static unsigned long itempool_used = 0; +static yasm_expr__item itempool[31]; + +/* allocate a new expression node, with children as defined. + * If it's a unary operator, put the element in left and set right=NULL. */ +/*@-compmempass@*/ +yasm_expr * +yasm_expr_create(yasm_expr_op op, yasm_expr__item *left, + yasm_expr__item *right, unsigned long line) +{ + yasm_expr *ptr, *sube; + unsigned long z; + ptr = yasm_xmalloc(sizeof(yasm_expr)); + + ptr->op = op; + ptr->numterms = 0; + ptr->terms[0].type = YASM_EXPR_NONE; + ptr->terms[1].type = YASM_EXPR_NONE; + if (left) { + ptr->terms[0] = *left; /* structure copy */ + z = (unsigned long)(left-itempool); + if (z>=31) + yasm_internal_error(N_("could not find expritem in pool")); + itempool_used &= ~(1<<z); + ptr->numterms++; + + /* Search downward until we find something *other* than an + * IDENT, then bring it up to the current level. + */ + while (ptr->terms[0].type == YASM_EXPR_EXPR && + ptr->terms[0].data.expn->op == YASM_EXPR_IDENT) { + sube = ptr->terms[0].data.expn; + ptr->terms[0] = sube->terms[0]; /* structure copy */ + /*@-usereleased@*/ + yasm_xfree(sube); + /*@=usereleased@*/ + } + } else { + yasm_internal_error(N_("Right side of expression must exist")); + } + + if (right) { + ptr->terms[1] = *right; /* structure copy */ + z = (unsigned long)(right-itempool); + if (z>=31) + yasm_internal_error(N_("could not find expritem in pool")); + itempool_used &= ~(1<<z); + ptr->numterms++; + + /* Search downward until we find something *other* than an + * IDENT, then bring it up to the current level. + */ + while (ptr->terms[1].type == YASM_EXPR_EXPR && + ptr->terms[1].data.expn->op == YASM_EXPR_IDENT) { + sube = ptr->terms[1].data.expn; + ptr->terms[1] = sube->terms[0]; /* structure copy */ + /*@-usereleased@*/ + yasm_xfree(sube); + /*@=usereleased@*/ + } + } + + ptr->line = line; + + return expr_level_op(ptr, 1, 1, 0); +} +/*@=compmempass@*/ + +/* helpers */ +static yasm_expr__item * +expr_get_item(void) +{ + int z = 0; + unsigned long v = itempool_used & 0x7fffffff; + + while (v & 1) { + v >>= 1; + z++; + } + if (z>=31) + yasm_internal_error(N_("too many expritems")); + itempool_used |= 1<<z; + return &itempool[z]; +} + +yasm_expr__item * +yasm_expr_precbc(yasm_bytecode *precbc) +{ + yasm_expr__item *e = expr_get_item(); + e->type = YASM_EXPR_PRECBC; + e->data.precbc = precbc; + return e; +} + +yasm_expr__item * +yasm_expr_sym(yasm_symrec *s) +{ + yasm_expr__item *e = expr_get_item(); + e->type = YASM_EXPR_SYM; + e->data.sym = s; + return e; +} + +yasm_expr__item * +yasm_expr_expr(yasm_expr *x) +{ + yasm_expr__item *e = expr_get_item(); + e->type = YASM_EXPR_EXPR; + e->data.expn = x; + return e; +} + +yasm_expr__item * +yasm_expr_int(yasm_intnum *i) +{ + yasm_expr__item *e = expr_get_item(); + e->type = YASM_EXPR_INT; + e->data.intn = i; + return e; +} + +yasm_expr__item * +yasm_expr_float(yasm_floatnum *f) +{ + yasm_expr__item *e = expr_get_item(); + e->type = YASM_EXPR_FLOAT; + e->data.flt = f; + return e; +} + +yasm_expr__item * +yasm_expr_reg(uintptr_t reg) +{ + yasm_expr__item *e = expr_get_item(); + e->type = YASM_EXPR_REG; + e->data.reg = reg; + return e; +} + +/* Transforms instances of symrec-symrec [symrec+(-1*symrec)] into single + * expritems if possible. Uses a simple n^2 algorithm because n is usually + * quite small. Also works for precbc-precbc (or symrec-precbc, + * precbc-symrec). + */ +static /*@only@*/ yasm_expr * +expr_xform_bc_dist_base(/*@returned@*/ /*@only@*/ yasm_expr *e, + /*@null@*/ void *cbd, + int (*callback) (yasm_expr__item *ei, + yasm_bytecode *precbc, + yasm_bytecode *precbc2, + void *cbd)) +{ + int i; + /*@dependent@*/ yasm_section *sect; + /*@dependent@*/ /*@null@*/ yasm_bytecode *precbc; + int numterms; + + /* Handle symrec-symrec in ADD exprs by looking for (-1*symrec) and + * symrec term pairs (where both symrecs are in the same segment). + */ + if (e->op != YASM_EXPR_ADD) + return e; + + for (i=0; i<e->numterms; i++) { + int j; + yasm_expr *sube; + yasm_intnum *intn; + yasm_symrec *sym = NULL; + /*@dependent@*/ yasm_section *sect2; + /*@dependent@*/ /*@null@*/ yasm_bytecode *precbc2; + + /* First look for an (-1*symrec) term */ + if (e->terms[i].type != YASM_EXPR_EXPR) + continue; + sube = e->terms[i].data.expn; + if (sube->op != YASM_EXPR_MUL || sube->numterms != 2) + continue; + + if (sube->terms[0].type == YASM_EXPR_INT && + (sube->terms[1].type == YASM_EXPR_SYM || + sube->terms[1].type == YASM_EXPR_PRECBC)) { + intn = sube->terms[0].data.intn; + if (sube->terms[1].type == YASM_EXPR_PRECBC) + precbc = sube->terms[1].data.precbc; + else + sym = sube->terms[1].data.sym; + } else if ((sube->terms[0].type == YASM_EXPR_SYM || + sube->terms[0].type == YASM_EXPR_PRECBC) && + sube->terms[1].type == YASM_EXPR_INT) { + if (sube->terms[0].type == YASM_EXPR_PRECBC) + precbc = sube->terms[0].data.precbc; + else + sym = sube->terms[0].data.sym; + intn = sube->terms[1].data.intn; + } else + continue; + + if (!yasm_intnum_is_neg1(intn)) + continue; + + if (sym && !yasm_symrec_get_label(sym, &precbc)) + continue; + sect2 = yasm_bc_get_section(precbc); + + /* Now look for a symrec term in the same segment */ + for (j=0; j<e->numterms; j++) { + if (((e->terms[j].type == YASM_EXPR_SYM && + yasm_symrec_get_label(e->terms[j].data.sym, &precbc2)) || + (e->terms[j].type == YASM_EXPR_PRECBC && + (precbc2 = e->terms[j].data.precbc))) && + (sect = yasm_bc_get_section(precbc2)) && + sect == sect2 && + callback(&e->terms[j], precbc, precbc2, cbd)) { + /* Delete the matching (-1*symrec) term */ + yasm_expr_destroy(sube); + e->terms[i].type = YASM_EXPR_NONE; + break; /* stop looking for matching symrec term */ + } + } + } + + /* Clean up any deleted (EXPR_NONE) terms */ + numterms = 0; + for (i=0; i<e->numterms; i++) { + if (e->terms[i].type != YASM_EXPR_NONE) + e->terms[numterms++] = e->terms[i]; /* structure copy */ + } + if (e->numterms != numterms) { + e->numterms = numterms; + e = yasm_xrealloc(e, sizeof(yasm_expr)+((numterms<2) ? 0 : + sizeof(yasm_expr__item)*(numterms-2))); + if (numterms == 1) + e->op = YASM_EXPR_IDENT; + } + + return e; +} + +static int +expr_xform_bc_dist_cb(yasm_expr__item *ei, yasm_bytecode *precbc, + yasm_bytecode *precbc2, /*@null@*/ void *d) +{ + yasm_intnum *dist = yasm_calc_bc_dist(precbc, precbc2); + if (!dist) + return 0; + /* Change the term to an integer */ + ei->type = YASM_EXPR_INT; + ei->data.intn = dist; + return 1; +} + +/* Transforms instances of symrec-symrec [symrec+(-1*symrec)] into integers if + * possible. + */ +static /*@only@*/ yasm_expr * +expr_xform_bc_dist(/*@returned@*/ /*@only@*/ yasm_expr *e) +{ + return expr_xform_bc_dist_base(e, NULL, expr_xform_bc_dist_cb); +} + +typedef struct bc_dist_subst_cbd { + void (*callback) (unsigned int subst, yasm_bytecode *precbc, + yasm_bytecode *precbc2, void *cbd); + void *cbd; + unsigned int subst; +} bc_dist_subst_cbd; + +static int +expr_bc_dist_subst_cb(yasm_expr__item *ei, yasm_bytecode *precbc, + yasm_bytecode *precbc2, /*@null@*/ void *d) +{ + bc_dist_subst_cbd *my_cbd = d; + assert(my_cbd != NULL); + /* Call higher-level callback */ + my_cbd->callback(my_cbd->subst, precbc, precbc2, my_cbd->cbd); + /* Change the term to an subst */ + ei->type = YASM_EXPR_SUBST; + ei->data.subst = my_cbd->subst; + my_cbd->subst++; + return 1; +} + +static yasm_expr * +expr_xform_bc_dist_subst(yasm_expr *e, void *d) +{ + return expr_xform_bc_dist_base(e, d, expr_bc_dist_subst_cb); +} + +int +yasm_expr__bc_dist_subst(yasm_expr **ep, void *cbd, + void (*callback) (unsigned int subst, + yasm_bytecode *precbc, + yasm_bytecode *precbc2, + void *cbd)) +{ + bc_dist_subst_cbd my_cbd; /* callback info for low-level callback */ + my_cbd.callback = callback; + my_cbd.cbd = cbd; + my_cbd.subst = 0; + *ep = yasm_expr__level_tree(*ep, 1, 1, 1, 0, &expr_xform_bc_dist_subst, + &my_cbd); + return my_cbd.subst; +} + +/* Negate just a single ExprItem by building a -1*ei subexpression */ +static void +expr_xform_neg_item(yasm_expr *e, yasm_expr__item *ei) +{ + yasm_expr *sube = yasm_xmalloc(sizeof(yasm_expr)); + + /* Build -1*ei subexpression */ + sube->op = YASM_EXPR_MUL; + sube->line = e->line; + sube->numterms = 2; + sube->terms[0].type = YASM_EXPR_INT; + sube->terms[0].data.intn = yasm_intnum_create_int(-1); + sube->terms[1] = *ei; /* structure copy */ + + /* Replace original ExprItem with subexp */ + ei->type = YASM_EXPR_EXPR; + ei->data.expn = sube; +} + +/* Negates e by multiplying by -1, with distribution over lower-precedence + * operators (eg ADD) and special handling to simplify result w/ADD, NEG, and + * others. + * + * Returns a possibly reallocated e. + */ +static /*@only@*/ yasm_expr * +expr_xform_neg_helper(/*@returned@*/ /*@only@*/ yasm_expr *e) +{ + yasm_expr *ne; + int i; + + switch (e->op) { + case YASM_EXPR_ADD: + /* distribute (recursively if expr) over terms */ + for (i=0; i<e->numterms; i++) { + if (e->terms[i].type == YASM_EXPR_EXPR) + e->terms[i].data.expn = + expr_xform_neg_helper(e->terms[i].data.expn); + else + expr_xform_neg_item(e, &e->terms[i]); + } + break; + case YASM_EXPR_SUB: + /* change op to ADD, and recursively negate left side (if expr) */ + e->op = YASM_EXPR_ADD; + if (e->terms[0].type == YASM_EXPR_EXPR) + e->terms[0].data.expn = + expr_xform_neg_helper(e->terms[0].data.expn); + else + expr_xform_neg_item(e, &e->terms[0]); + break; + case YASM_EXPR_NEG: + /* Negating a negated value? Make it an IDENT. */ + e->op = YASM_EXPR_IDENT; + break; + case YASM_EXPR_IDENT: + /* Negating an ident? Change it into a MUL w/ -1 if there's no + * floatnums present below; if there ARE floatnums, recurse. + */ + if (e->terms[0].type == YASM_EXPR_FLOAT) + yasm_floatnum_calc(e->terms[0].data.flt, YASM_EXPR_NEG, NULL); + else if (e->terms[0].type == YASM_EXPR_INT) + yasm_intnum_calc(e->terms[0].data.intn, YASM_EXPR_NEG, NULL); + else if (e->terms[0].type == YASM_EXPR_EXPR && + yasm_expr__contains(e->terms[0].data.expn, YASM_EXPR_FLOAT)) + expr_xform_neg_helper(e->terms[0].data.expn); + else { + e->op = YASM_EXPR_MUL; + e->numterms = 2; + e->terms[1].type = YASM_EXPR_INT; + e->terms[1].data.intn = yasm_intnum_create_int(-1); + } + break; + default: + /* Everything else. MUL will be combined when it's leveled. + * Make a new expr (to replace e) with -1*e. + */ + ne = yasm_xmalloc(sizeof(yasm_expr)); + ne->op = YASM_EXPR_MUL; + ne->line = e->line; + ne->numterms = 2; + ne->terms[0].type = YASM_EXPR_INT; + ne->terms[0].data.intn = yasm_intnum_create_int(-1); + ne->terms[1].type = YASM_EXPR_EXPR; + ne->terms[1].data.expn = e; + return ne; + } + return e; +} + +/* Transforms negatives into expressions that are easier to combine: + * -x -> -1*x + * a-b -> a+(-1*b) + * + * Call post-order on an expression tree to transform the entire tree. + * + * Returns a possibly reallocated e. + */ +static /*@only@*/ yasm_expr * +expr_xform_neg(/*@returned@*/ /*@only@*/ yasm_expr *e) +{ + switch (e->op) { + case YASM_EXPR_NEG: + /* Turn -x into -1*x */ + e->op = YASM_EXPR_IDENT; + return expr_xform_neg_helper(e); + case YASM_EXPR_SUB: + /* Turn a-b into a+(-1*b) */ + + /* change op to ADD, and recursively negate right side (if expr) */ + e->op = YASM_EXPR_ADD; + if (e->terms[1].type == YASM_EXPR_EXPR) + e->terms[1].data.expn = + expr_xform_neg_helper(e->terms[1].data.expn); + else + expr_xform_neg_item(e, &e->terms[1]); + break; + default: + break; + } + + return e; +} + +/* Look for simple identities that make the entire result constant: + * 0*&x, -1|x, etc. + */ +static int +expr_is_constant(yasm_expr_op op, yasm_intnum *intn) +{ + int iszero = yasm_intnum_is_zero(intn); + return ((iszero && op == YASM_EXPR_MUL) || + (iszero && op == YASM_EXPR_AND) || + (iszero && op == YASM_EXPR_LAND) || + (yasm_intnum_is_neg1(intn) && op == YASM_EXPR_OR)); +} + +/* Look for simple "left" identities like 0+x, 1*x, etc. */ +static int +expr_can_destroy_int_left(yasm_expr_op op, yasm_intnum *intn) +{ + int iszero = yasm_intnum_is_zero(intn); + return ((yasm_intnum_is_pos1(intn) && op == YASM_EXPR_MUL) || + (iszero && op == YASM_EXPR_ADD) || + (yasm_intnum_is_neg1(intn) && op == YASM_EXPR_AND) || + (!iszero && op == YASM_EXPR_LAND) || + (iszero && op == YASM_EXPR_OR) || + (iszero && op == YASM_EXPR_LOR)); +} + +/* Look for simple "right" identities like x+|-0, x*&/1 */ +static int +expr_can_destroy_int_right(yasm_expr_op op, yasm_intnum *intn) +{ + int iszero = yasm_intnum_is_zero(intn); + int ispos1 = yasm_intnum_is_pos1(intn); + return ((ispos1 && op == YASM_EXPR_MUL) || + (ispos1 && op == YASM_EXPR_DIV) || + (iszero && op == YASM_EXPR_ADD) || + (iszero && op == YASM_EXPR_SUB) || + (yasm_intnum_is_neg1(intn) && op == YASM_EXPR_AND) || + (!iszero && op == YASM_EXPR_LAND) || + (iszero && op == YASM_EXPR_OR) || + (iszero && op == YASM_EXPR_LOR) || + (iszero && op == YASM_EXPR_SHL) || + (iszero && op == YASM_EXPR_SHR)); +} + +/* Check for and simplify identities. Returns new number of expr terms. + * Sets e->op = EXPR_IDENT if numterms ends up being 1. + * Uses numterms parameter instead of e->numterms for basis of "new" number + * of terms. + * Assumes int_term is *only* integer term in e. + * NOTE: Really designed to only be used by expr_level_op(). + */ +static int +expr_simplify_identity(yasm_expr *e, int numterms, int *int_term, + int simplify_reg_mul) +{ + int i; + int save_numterms; + + /* Don't do this step if it's 1*REG. Save and restore numterms so + * yasm_expr__contains() works correctly. + */ + save_numterms = e->numterms; + e->numterms = numterms; + if (simplify_reg_mul || e->op != YASM_EXPR_MUL + || !yasm_intnum_is_pos1(e->terms[*int_term].data.intn) + || !yasm_expr__contains(e, YASM_EXPR_REG)) { + /* Check for simple identities that delete the intnum. + * Don't delete if the intnum is the only thing in the expn. + */ + if ((*int_term == 0 && numterms > 1 && + expr_can_destroy_int_left(e->op, e->terms[0].data.intn)) || + (*int_term > 0 && + expr_can_destroy_int_right(e->op, + e->terms[*int_term].data.intn))) { + /* Delete the intnum */ + yasm_intnum_destroy(e->terms[*int_term].data.intn); + + /* Slide everything to its right over by 1 */ + if (*int_term != numterms-1) /* if it wasn't last.. */ + memmove(&e->terms[*int_term], &e->terms[*int_term+1], + (numterms-1-*int_term)*sizeof(yasm_expr__item)); + + /* Update numterms */ + numterms--; + *int_term = -1; /* no longer an int term */ + } + } + e->numterms = save_numterms; + + /* Check for simple identites that delete everything BUT the intnum. + * Don't bother if the intnum is the only thing in the expn. + */ + if (numterms > 1 && *int_term != -1 && + expr_is_constant(e->op, e->terms[*int_term].data.intn)) { + /* Loop through, deleting everything but the integer term */ + for (i=0; i<e->numterms; i++) + if (i != *int_term) + expr_delete_term(&e->terms[i], 1); + + /* Move integer term to the first term (if not already there) */ + if (*int_term != 0) + e->terms[0] = e->terms[*int_term]; /* structure copy */ + + /* Set numterms to 1 */ + numterms = 1; + } + + /* Compute NOT, NEG, and LNOT on single intnum. */ + if (numterms == 1 && *int_term == 0 && + (e->op == YASM_EXPR_NOT || e->op == YASM_EXPR_NEG || + e->op == YASM_EXPR_LNOT)) + yasm_intnum_calc(e->terms[0].data.intn, e->op, NULL); + + /* Change expression to IDENT if possible. */ + if (numterms == 1) + e->op = YASM_EXPR_IDENT; + + /* Return the updated numterms */ + return numterms; +} + +/* Levels the expression tree starting at e. Eg: + * a+(b+c) -> a+b+c + * (a+b)+(c+d) -> a+b+c+d + * Naturally, only levels operators that allow more than two operand terms. + * NOTE: only does *one* level of leveling (no recursion). Should be called + * post-order on a tree to combine deeper levels. + * Also brings up any IDENT values into the current level (for ALL operators). + * Folds (combines by evaluation) *integer* constant values if fold_const != 0. + * + * Returns a possibly reallocated e. + */ +/*@-mustfree@*/ +static /*@only@*/ yasm_expr * +expr_level_op(/*@returned@*/ /*@only@*/ yasm_expr *e, int fold_const, + int simplify_ident, int simplify_reg_mul) +{ + int i, j, o, fold_numterms, level_numterms, level_fold_numterms; + int first_int_term = -1; + + /* Determine how many operands will need to be brought up (for leveling). + * Go ahead and bring up any IDENT'ed values. + */ + while (e->op == YASM_EXPR_IDENT && e->terms[0].type == YASM_EXPR_EXPR) { + yasm_expr *sube = e->terms[0].data.expn; + yasm_xfree(e); + e = sube; + } + + /* If non-numeric expression, don't fold constants. */ + if (e->op > YASM_EXPR_NONNUM) + fold_const = 0; + + level_numterms = e->numterms; + level_fold_numterms = 0; + for (i=0; i<e->numterms; i++) { + /* Search downward until we find something *other* than an + * IDENT, then bring it up to the current level. + */ + while (e->terms[i].type == YASM_EXPR_EXPR && + e->terms[i].data.expn->op == YASM_EXPR_IDENT) { + yasm_expr *sube = e->terms[i].data.expn; + e->terms[i] = sube->terms[0]; + yasm_xfree(sube); + } + + if (e->terms[i].type == YASM_EXPR_EXPR && + e->terms[i].data.expn->op == e->op) { + /* It's an expression w/the same operator, add in its numterms. + * But don't forget to subtract one for the expr itself! + */ + level_numterms += e->terms[i].data.expn->numterms - 1; + + /* If we're folding constants, count up the number of constants + * that will be merged in. + */ + if (fold_const) + for (j=0; j<e->terms[i].data.expn->numterms; j++) + if (e->terms[i].data.expn->terms[j].type == + YASM_EXPR_INT) + level_fold_numterms++; + } + + /* Find the first integer term (if one is present) if we're folding + * constants. + */ + if (fold_const && first_int_term == -1 && + e->terms[i].type == YASM_EXPR_INT) + first_int_term = i; + } + + /* Look for other integer terms if there's one and combine. + * Also eliminate empty spaces when combining and adjust numterms + * variables. + */ + fold_numterms = e->numterms; + if (first_int_term != -1) { + for (i=first_int_term+1, o=first_int_term+1; i<e->numterms; i++) { + if (e->terms[i].type == YASM_EXPR_INT) { + yasm_intnum_calc(e->terms[first_int_term].data.intn, e->op, + e->terms[i].data.intn); + fold_numterms--; + level_numterms--; + /* make sure to delete folded intnum */ + yasm_intnum_destroy(e->terms[i].data.intn); + } else if (o != i) { + /* copy term if it changed places */ + e->terms[o++] = e->terms[i]; + } else + o++; + } + + if (simplify_ident) { + int new_fold_numterms; + /* Simplify identities and make IDENT if possible. */ + new_fold_numterms = + expr_simplify_identity(e, fold_numterms, &first_int_term, + simplify_reg_mul); + level_numterms -= fold_numterms-new_fold_numterms; + fold_numterms = new_fold_numterms; + } + if (fold_numterms == 1) + e->op = YASM_EXPR_IDENT; + } + + /* Only level operators that allow more than two operand terms. + * Also don't bother leveling if it's not necessary to bring up any terms. + */ + if ((e->op != YASM_EXPR_ADD && e->op != YASM_EXPR_MUL && + e->op != YASM_EXPR_OR && e->op != YASM_EXPR_AND && + e->op != YASM_EXPR_LOR && e->op != YASM_EXPR_LAND && + e->op != YASM_EXPR_LXOR && e->op != YASM_EXPR_XOR) || + level_numterms <= fold_numterms) { + /* Downsize e if necessary */ + if (fold_numterms < e->numterms && e->numterms > 2) + e = yasm_xrealloc(e, sizeof(yasm_expr)+((fold_numterms<2) ? 0 : + sizeof(yasm_expr__item)*(fold_numterms-2))); + /* Update numterms */ + e->numterms = fold_numterms; + return e; + } + + /* Adjust numterms for constant folding from terms being "pulled up". + * Careful: if there's no integer term in e, then save space for it. + */ + if (fold_const) { + level_numterms -= level_fold_numterms; + if (first_int_term == -1 && level_fold_numterms != 0) + level_numterms++; + } + + /* Alloc more (or conceivably less, but not usually) space for e */ + e = yasm_xrealloc(e, sizeof(yasm_expr)+((level_numterms<2) ? 0 : + sizeof(yasm_expr__item)*(level_numterms-2))); + + /* Copy up ExprItem's. Iterate from right to left to keep the same + * ordering as was present originally. + * Combine integer terms as necessary. + */ + for (i=fold_numterms-1, o=level_numterms-1; i>=0; i--) { + if (e->terms[i].type == YASM_EXPR_EXPR && + e->terms[i].data.expn->op == e->op) { + /* bring up subexpression */ + yasm_expr *sube = e->terms[i].data.expn; + + /* copy terms right to left */ + for (j=sube->numterms-1; j>=0; j--) { + if (fold_const && sube->terms[j].type == YASM_EXPR_INT) { + /* Need to fold it in.. but if there's no int term already, + * just copy into a new one. + */ + if (first_int_term == -1) { + first_int_term = o--; + e->terms[first_int_term] = sube->terms[j]; /* struc */ + } else { + yasm_intnum_calc(e->terms[first_int_term].data.intn, + e->op, sube->terms[j].data.intn); + /* make sure to delete folded intnum */ + yasm_intnum_destroy(sube->terms[j].data.intn); + } + } else { + if (o == first_int_term) + o--; + e->terms[o--] = sube->terms[j]; /* structure copy */ + } + } + + /* delete subexpression, but *don't delete nodes* (as we've just + * copied them!) + */ + yasm_xfree(sube); + } else if (o != i) { + /* copy operand if it changed places */ + if (o == first_int_term) + o--; + e->terms[o] = e->terms[i]; + /* If we moved the first_int_term, change first_int_num too */ + if (i == first_int_term) + first_int_term = o; + o--; + } else + o--; + } + + /* Simplify identities, make IDENT if possible, and save to e->numterms. */ + if (simplify_ident && first_int_term != -1) { + e->numterms = expr_simplify_identity(e, level_numterms, + &first_int_term, simplify_reg_mul); + } else { + e->numterms = level_numterms; + if (level_numterms == 1) + e->op = YASM_EXPR_IDENT; + } + + return e; +} +/*@=mustfree@*/ + +typedef SLIST_HEAD(yasm__exprhead, yasm__exprentry) yasm__exprhead; +typedef struct yasm__exprentry { + /*@reldef@*/ SLIST_ENTRY(yasm__exprentry) next; + /*@null@*/ const yasm_expr *e; +} yasm__exprentry; + +static yasm_expr * +expr_expand_equ(yasm_expr *e, yasm__exprhead *eh) +{ + int i; + yasm__exprentry ee; + + /* traverse terms */ + for (i=0; i<e->numterms; i++) { + const yasm_expr *equ_expr; + + /* Expand equ's. */ + if (e->terms[i].type == YASM_EXPR_SYM && + (equ_expr = yasm_symrec_get_equ(e->terms[i].data.sym))) { + yasm__exprentry *np; + + /* Check for circular reference */ + SLIST_FOREACH(np, eh, next) { + if (np->e == equ_expr) { + yasm_error_set(YASM_ERROR_TOO_COMPLEX, + N_("circular reference detected")); + return e; + } + } + + e->terms[i].type = YASM_EXPR_EXPR; + e->terms[i].data.expn = yasm_expr_copy(equ_expr); + + /* Remember we saw this equ and recurse */ + ee.e = equ_expr; + SLIST_INSERT_HEAD(eh, &ee, next); + e->terms[i].data.expn = expr_expand_equ(e->terms[i].data.expn, eh); + SLIST_REMOVE_HEAD(eh, next); + } else if (e->terms[i].type == YASM_EXPR_EXPR) + /* Recurse */ + e->terms[i].data.expn = expr_expand_equ(e->terms[i].data.expn, eh); + } + + return e; +} + +static yasm_expr * +expr_level_tree(yasm_expr *e, int fold_const, int simplify_ident, + int simplify_reg_mul, int calc_bc_dist, + yasm_expr_xform_func expr_xform_extra, + void *expr_xform_extra_data) +{ + int i; + + e = expr_xform_neg(e); + + /* traverse terms */ + for (i=0; i<e->numterms; i++) { + /* Recurse */ + if (e->terms[i].type == YASM_EXPR_EXPR) + e->terms[i].data.expn = + expr_level_tree(e->terms[i].data.expn, fold_const, + simplify_ident, simplify_reg_mul, calc_bc_dist, + expr_xform_extra, expr_xform_extra_data); + } + + /* Check for SEG of SEG:OFF, if we match, simplify to just the segment */ + if (e->op == YASM_EXPR_SEG && e->terms[0].type == YASM_EXPR_EXPR && + e->terms[0].data.expn->op == YASM_EXPR_SEGOFF) { + e->op = YASM_EXPR_IDENT; + e->terms[0].data.expn->op = YASM_EXPR_IDENT; + /* Destroy the second (offset) term */ + e->terms[0].data.expn->numterms = 1; + expr_delete_term(&e->terms[0].data.expn->terms[1], 1); + } + + /* do callback */ + e = expr_level_op(e, fold_const, simplify_ident, simplify_reg_mul); + if (calc_bc_dist || expr_xform_extra) { + if (calc_bc_dist) + e = expr_xform_bc_dist(e); + if (expr_xform_extra) + e = expr_xform_extra(e, expr_xform_extra_data); + e = expr_level_tree(e, fold_const, simplify_ident, simplify_reg_mul, + 0, NULL, NULL); + } + return e; +} + +/* Level an entire expn tree, expanding equ's as we go */ +yasm_expr * +yasm_expr__level_tree(yasm_expr *e, int fold_const, int simplify_ident, + int simplify_reg_mul, int calc_bc_dist, + yasm_expr_xform_func expr_xform_extra, + void *expr_xform_extra_data) +{ + yasm__exprhead eh; + SLIST_INIT(&eh); + + if (!e) + return 0; + + e = expr_expand_equ(e, &eh); + e = expr_level_tree(e, fold_const, simplify_ident, simplify_reg_mul, + calc_bc_dist, expr_xform_extra, expr_xform_extra_data); + + return e; +} + +/* Comparison function for expr_order_terms(). + * Assumes ExprType enum is in canonical order. + */ +static int +expr_order_terms_compare(const void *va, const void *vb) +{ + const yasm_expr__item *a = va, *b = vb; + return (a->type - b->type); +} + +/* Reorder terms of e into canonical order. Only reorders if reordering + * doesn't change meaning of expression. (eg, doesn't reorder SUB). + * Canonical order: REG, INT, FLOAT, SYM, EXPR. + * Multiple terms of a single type are kept in the same order as in + * the original expression. + * NOTE: Only performs reordering on *one* level (no recursion). + */ +void +yasm_expr__order_terms(yasm_expr *e) +{ + /* don't bother reordering if only one element */ + if (e->numterms == 1) + return; + + /* only reorder some types of operations */ + switch (e->op) { + case YASM_EXPR_ADD: + case YASM_EXPR_MUL: + case YASM_EXPR_OR: + case YASM_EXPR_AND: + case YASM_EXPR_XOR: + case YASM_EXPR_LOR: + case YASM_EXPR_LAND: + case YASM_EXPR_LXOR: + /* Use mergesort to sort. It's fast on already sorted values and a + * stable sort (multiple terms of same type are kept in the same + * order). + */ + yasm__mergesort(e->terms, (size_t)e->numterms, + sizeof(yasm_expr__item), expr_order_terms_compare); + break; + default: + break; + } +} + +static void +expr_item_copy(yasm_expr__item *dest, const yasm_expr__item *src) +{ + dest->type = src->type; + switch (src->type) { + case YASM_EXPR_SYM: + /* Symbols don't need to be copied */ + dest->data.sym = src->data.sym; + break; + case YASM_EXPR_PRECBC: + /* Nor do direct bytecode references */ + dest->data.precbc = src->data.precbc; + break; + case YASM_EXPR_EXPR: + dest->data.expn = yasm_expr__copy_except(src->data.expn, -1); + break; + case YASM_EXPR_INT: + dest->data.intn = yasm_intnum_copy(src->data.intn); + break; + case YASM_EXPR_FLOAT: + dest->data.flt = yasm_floatnum_copy(src->data.flt); + break; + case YASM_EXPR_REG: + dest->data.reg = src->data.reg; + break; + case YASM_EXPR_SUBST: + dest->data.subst = src->data.subst; + break; + default: + break; + } +} + +/* Copy entire expression EXCEPT for index "except" at *top level only*. */ +yasm_expr * +yasm_expr__copy_except(const yasm_expr *e, int except) +{ + yasm_expr *n; + int i; + + n = yasm_xmalloc(sizeof(yasm_expr) + + sizeof(yasm_expr__item)*(e->numterms<2?0:e->numterms-2)); + + n->op = e->op; + n->line = e->line; + n->numterms = e->numterms; + for (i=0; i<e->numterms; i++) { + if (i != except) + expr_item_copy(&n->terms[i], &e->terms[i]); + } + + return n; +} + +static void +expr_delete_term(yasm_expr__item *term, int recurse) +{ + switch (term->type) { + case YASM_EXPR_INT: + yasm_intnum_destroy(term->data.intn); + break; + case YASM_EXPR_FLOAT: + yasm_floatnum_destroy(term->data.flt); + break; + case YASM_EXPR_EXPR: + if (recurse) + yasm_expr_destroy(term->data.expn); + break; + default: + break; + } +} + +static int +expr_destroy_each(/*@only@*/ yasm_expr *e, /*@unused@*/ void *d) +{ + int i; + for (i=0; i<e->numterms; i++) + expr_delete_term(&e->terms[i], 0); + yasm_xfree(e); /* free ourselves */ + return 0; /* don't stop recursion */ +} + +/*@-mustfree@*/ +void +yasm_expr_destroy(yasm_expr *e) +{ + expr_traverse_nodes_post(e, NULL, expr_destroy_each); +} +/*@=mustfree@*/ + +int +yasm_expr_is_op(const yasm_expr *e, yasm_expr_op op) +{ + return (e->op == op); +} + +static int +expr_contains_callback(const yasm_expr__item *ei, void *d) +{ + yasm_expr__type *t = d; + return (ei->type & *t); +} + +int +yasm_expr__contains(const yasm_expr *e, yasm_expr__type t) +{ + return yasm_expr__traverse_leaves_in_const(e, &t, expr_contains_callback); +} + +typedef struct subst_cbd { + unsigned int num_items; + const yasm_expr__item *items; +} subst_cbd; + +static int +expr_subst_callback(yasm_expr__item *ei, void *d) +{ + subst_cbd *cbd = d; + if (ei->type != YASM_EXPR_SUBST) + return 0; + if (ei->data.subst >= cbd->num_items) + return 1; /* error */ + expr_item_copy(ei, &cbd->items[ei->data.subst]); + return 0; +} + +int +yasm_expr__subst(yasm_expr *e, unsigned int num_items, + const yasm_expr__item *items) +{ + subst_cbd cbd; + cbd.num_items = num_items; + cbd.items = items; + return yasm_expr__traverse_leaves_in(e, &cbd, expr_subst_callback); +} + +/* Traverse over expression tree, calling func for each operation AFTER the + * branches (if expressions) have been traversed (eg, postorder + * traversal). The data pointer d is passed to each func call. + * + * Stops early (and returns 1) if func returns 1. Otherwise returns 0. + */ +static int +expr_traverse_nodes_post(yasm_expr *e, void *d, + int (*func) (/*@null@*/ yasm_expr *e, + /*@null@*/ void *d)) +{ + int i; + + if (!e) + return 0; + + /* traverse terms */ + for (i=0; i<e->numterms; i++) { + if (e->terms[i].type == YASM_EXPR_EXPR && + expr_traverse_nodes_post(e->terms[i].data.expn, d, func)) + return 1; + } + + /* do callback */ + return func(e, d); +} + +/* Traverse over expression tree in order, calling func for each leaf + * (non-operation). The data pointer d is passed to each func call. + * + * Stops early (and returns 1) if func returns 1. Otherwise returns 0. + */ +int +yasm_expr__traverse_leaves_in_const(const yasm_expr *e, void *d, + int (*func) (/*@null@*/ const yasm_expr__item *ei, /*@null@*/ void *d)) +{ + int i; + + if (!e) + return 0; + + for (i=0; i<e->numterms; i++) { + if (e->terms[i].type == YASM_EXPR_EXPR) { + if (yasm_expr__traverse_leaves_in_const(e->terms[i].data.expn, d, + func)) + return 1; + } else { + if (func(&e->terms[i], d)) + return 1; + } + } + return 0; +} + +/* Traverse over expression tree in order, calling func for each leaf + * (non-operation). The data pointer d is passed to each func call. + * + * Stops early (and returns 1) if func returns 1. Otherwise returns 0. + */ +int +yasm_expr__traverse_leaves_in(yasm_expr *e, void *d, + int (*func) (/*@null@*/ yasm_expr__item *ei, /*@null@*/ void *d)) +{ + int i; + + if (!e) + return 0; + + for (i=0; i<e->numterms; i++) { + if (e->terms[i].type == YASM_EXPR_EXPR) { + if (yasm_expr__traverse_leaves_in(e->terms[i].data.expn, d, func)) + return 1; + } else { + if (func(&e->terms[i], d)) + return 1; + } + } + return 0; +} + +yasm_expr * +yasm_expr_extract_deep_segoff(yasm_expr **ep) +{ + yasm_expr *retval; + yasm_expr *e = *ep; + int i; + + /* Try to extract at this level */ + retval = yasm_expr_extract_segoff(ep); + if (retval) + return retval; + + /* Not at this level? Search any expr children. */ + for (i=0; i<e->numterms; i++) { + if (e->terms[i].type == YASM_EXPR_EXPR) { + retval = yasm_expr_extract_deep_segoff(&e->terms[i].data.expn); + if (retval) + return retval; + } + } + + /* Didn't find one */ + return NULL; +} + +yasm_expr * +yasm_expr_extract_segoff(yasm_expr **ep) +{ + yasm_expr *retval; + yasm_expr *e = *ep; + + /* If not SEG:OFF, we can't do this transformation */ + if (e->op != YASM_EXPR_SEGOFF) + return NULL; + + /* Extract the SEG portion out to its own expression */ + if (e->terms[0].type == YASM_EXPR_EXPR) + retval = e->terms[0].data.expn; + else { + /* Need to build IDENT expression to hold non-expression contents */ + retval = yasm_xmalloc(sizeof(yasm_expr)); + retval->op = YASM_EXPR_IDENT; + retval->numterms = 1; + retval->terms[0] = e->terms[0]; /* structure copy */ + } + + /* Delete the SEG: portion by changing the expression into an IDENT */ + e->op = YASM_EXPR_IDENT; + e->numterms = 1; + e->terms[0] = e->terms[1]; /* structure copy */ + + return retval; +} + +yasm_expr * +yasm_expr_extract_wrt(yasm_expr **ep) +{ + yasm_expr *retval; + yasm_expr *e = *ep; + + /* If not WRT, we can't do this transformation */ + if (e->op != YASM_EXPR_WRT) + return NULL; + + /* Extract the right side portion out to its own expression */ + if (e->terms[1].type == YASM_EXPR_EXPR) + retval = e->terms[1].data.expn; + else { + /* Need to build IDENT expression to hold non-expression contents */ + retval = yasm_xmalloc(sizeof(yasm_expr)); + retval->op = YASM_EXPR_IDENT; + retval->numterms = 1; + retval->terms[0] = e->terms[1]; /* structure copy */ + } + + /* Delete the right side portion by changing the expr into an IDENT */ + e->op = YASM_EXPR_IDENT; + e->numterms = 1; + + return retval; +} + +/*@-unqualifiedtrans -nullderef -nullstate -onlytrans@*/ +yasm_intnum * +yasm_expr_get_intnum(yasm_expr **ep, int calc_bc_dist) +{ + *ep = yasm_expr_simplify(*ep, calc_bc_dist); + + if ((*ep)->op == YASM_EXPR_IDENT && (*ep)->terms[0].type == YASM_EXPR_INT) + return (*ep)->terms[0].data.intn; + else + return (yasm_intnum *)NULL; +} +/*@=unqualifiedtrans =nullderef -nullstate -onlytrans@*/ + +/*@-unqualifiedtrans -nullderef -nullstate -onlytrans@*/ +const yasm_symrec * +yasm_expr_get_symrec(yasm_expr **ep, int simplify) +{ + if (simplify) + *ep = yasm_expr_simplify(*ep, 0); + + if ((*ep)->op == YASM_EXPR_IDENT && (*ep)->terms[0].type == YASM_EXPR_SYM) + return (*ep)->terms[0].data.sym; + else + return (yasm_symrec *)NULL; +} +/*@=unqualifiedtrans =nullderef -nullstate -onlytrans@*/ + +/*@-unqualifiedtrans -nullderef -nullstate -onlytrans@*/ +const uintptr_t * +yasm_expr_get_reg(yasm_expr **ep, int simplify) +{ + if (simplify) + *ep = yasm_expr_simplify(*ep, 0); + + if ((*ep)->op == YASM_EXPR_IDENT && (*ep)->terms[0].type == YASM_EXPR_REG) + return &((*ep)->terms[0].data.reg); + else + return NULL; +} +/*@=unqualifiedtrans =nullderef -nullstate -onlytrans@*/ + +void +yasm_expr_print(const yasm_expr *e, FILE *f) +{ + char opstr[8]; + int i; + + if (!e) { + fprintf(f, "(nil)"); + return; + } + + switch (e->op) { + case YASM_EXPR_ADD: + strcpy(opstr, "+"); + break; + case YASM_EXPR_SUB: + strcpy(opstr, "-"); + break; + case YASM_EXPR_MUL: + strcpy(opstr, "*"); + break; + case YASM_EXPR_DIV: + strcpy(opstr, "/"); + break; + case YASM_EXPR_SIGNDIV: + strcpy(opstr, "//"); + break; + case YASM_EXPR_MOD: + strcpy(opstr, "%"); + break; + case YASM_EXPR_SIGNMOD: + strcpy(opstr, "%%"); + break; + case YASM_EXPR_NEG: + fprintf(f, "-"); + opstr[0] = 0; + break; + case YASM_EXPR_NOT: + fprintf(f, "~"); + opstr[0] = 0; + break; + case YASM_EXPR_OR: + strcpy(opstr, "|"); + break; + case YASM_EXPR_AND: + strcpy(opstr, "&"); + break; + case YASM_EXPR_XOR: + strcpy(opstr, "^"); + break; + case YASM_EXPR_XNOR: + strcpy(opstr, "XNOR"); + break; + case YASM_EXPR_NOR: + strcpy(opstr, "NOR"); + break; + case YASM_EXPR_SHL: + strcpy(opstr, "<<"); + break; + case YASM_EXPR_SHR: + strcpy(opstr, ">>"); + break; + case YASM_EXPR_LOR: + strcpy(opstr, "||"); + break; + case YASM_EXPR_LAND: + strcpy(opstr, "&&"); + break; + case YASM_EXPR_LNOT: + strcpy(opstr, "!"); + break; + case YASM_EXPR_LXOR: + strcpy(opstr, "^^"); + break; + case YASM_EXPR_LXNOR: + strcpy(opstr, "LXNOR"); + break; + case YASM_EXPR_LNOR: + strcpy(opstr, "LNOR"); + break; + case YASM_EXPR_LT: + strcpy(opstr, "<"); + break; + case YASM_EXPR_GT: + strcpy(opstr, ">"); + break; + case YASM_EXPR_LE: + strcpy(opstr, "<="); + break; + case YASM_EXPR_GE: + strcpy(opstr, ">="); + break; + case YASM_EXPR_NE: + strcpy(opstr, "!="); + break; + case YASM_EXPR_EQ: + strcpy(opstr, "=="); + break; + case YASM_EXPR_SEG: + fprintf(f, "SEG "); + opstr[0] = 0; + break; + case YASM_EXPR_WRT: + strcpy(opstr, " WRT "); + break; + case YASM_EXPR_SEGOFF: + strcpy(opstr, ":"); + break; + case YASM_EXPR_IDENT: + opstr[0] = 0; + break; + default: + strcpy(opstr, " !UNK! "); + break; + } + for (i=0; i<e->numterms; i++) { + switch (e->terms[i].type) { + case YASM_EXPR_PRECBC: + fprintf(f, "{%lx}", + yasm_bc_next_offset(e->terms[i].data.precbc)); + break; + case YASM_EXPR_SYM: + fprintf(f, "%s", yasm_symrec_get_name(e->terms[i].data.sym)); + break; + case YASM_EXPR_EXPR: + fprintf(f, "("); + yasm_expr_print(e->terms[i].data.expn, f); + fprintf(f, ")"); + break; + case YASM_EXPR_INT: + yasm_intnum_print(e->terms[i].data.intn, f); + break; + case YASM_EXPR_FLOAT: + yasm_floatnum_print(e->terms[i].data.flt, f); + break; + case YASM_EXPR_REG: + /* FIXME */ + /*yasm_arch_reg_print(arch, e->terms[i].data.reg, f);*/ + break; + case YASM_EXPR_SUBST: + fprintf(f, "[%u]", e->terms[i].data.subst); + break; + case YASM_EXPR_NONE: + break; + } + if (i < e->numterms-1) + fprintf(f, "%s", opstr); + } +} + +unsigned int +yasm_expr_size(const yasm_expr *e) +{ + int i; + int seen = 0; + unsigned int size = 0, newsize; + + if (e->op == YASM_EXPR_IDENT) { + if (e->terms[0].type == YASM_EXPR_SYM) + return yasm_symrec_get_size(e->terms[0].data.sym); + return 0; + } + if (e->op != YASM_EXPR_ADD && e->op != YASM_EXPR_SUB) + return 0; + + for (i=0; i<e->numterms; i++) { + newsize = 0; + switch (e->terms[i].type) { + case YASM_EXPR_EXPR: + newsize = yasm_expr_size(e->terms[i].data.expn); + break; + case YASM_EXPR_SYM: + newsize = yasm_symrec_get_size(e->terms[i].data.sym); + break; + default: + break; + } + if (newsize) { + size = newsize; + if (seen) + /* either sum of idents (?!) or substract of idents */ + return 0; + seen = 1; + } + } + /* exactly one offset */ + return size; +} + +const char * +yasm_expr_segment(const yasm_expr *e) +{ + int i; + int seen = 0; + const char *segment = NULL; + + if (e->op == YASM_EXPR_IDENT) { + if (e->terms[0].type == YASM_EXPR_SYM) + return yasm_symrec_get_segment(e->terms[0].data.sym); + return NULL; + } + if (e->op != YASM_EXPR_ADD && e->op != YASM_EXPR_SUB) + return NULL; + + for (i=0; i<e->numterms; i++) { + if ((e->op == YASM_EXPR_ADD || !i) && + e->terms[i].type == YASM_EXPR_EXPR) { + if ((segment = yasm_expr_segment(e->terms[i].data.expn))) { + if (seen) { + /* either sum of idents (?!) or substract of idents */ + return NULL; + } + seen = 1; + } + } + } + /* exactly one offset */ + return segment; +} diff --git a/contrib/tools/yasm/libyasm/expr.h b/contrib/tools/yasm/libyasm/expr.h index 0de62dfed7..b68bff0c81 100644 --- a/contrib/tools/yasm/libyasm/expr.h +++ b/contrib/tools/yasm/libyasm/expr.h @@ -1,388 +1,388 @@ -/** - * \file libyasm/expr.h - * \brief YASM expression interface. - * - * \license - * Copyright (C) 2001-2007 Michael Urman, Peter Johnson - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * \endlicense - */ -#ifndef YASM_EXPR_H -#define YASM_EXPR_H - -#ifndef YASM_LIB_DECL -#define YASM_LIB_DECL -#endif - -/** Type of an expression item. Types are listed in canonical sorting order. - * See expr_order_terms(). - * Note #YASM_EXPR_PRECBC must be used carefully (in a-b pairs), as only - * symrecs can become the relative term in a #yasm_value. - */ -typedef enum yasm_expr__type { - YASM_EXPR_NONE = 0, /**< Nothing */ - YASM_EXPR_REG = 1<<0, /**< Register */ - YASM_EXPR_INT = 1<<1, /**< Integer value */ - YASM_EXPR_SUBST = 1<<2, /**< Substitution placeholder */ - YASM_EXPR_FLOAT = 1<<3, /**< Floating point value */ - YASM_EXPR_SYM = 1<<4, /**< Symbol */ - YASM_EXPR_PRECBC = 1<<5,/**< Direct bytecode ref (rather than via sym) */ - YASM_EXPR_EXPR = 1<<6 /**< Subexpression */ -} yasm_expr__type; - -/** Expression item. */ -typedef struct yasm_expr__item { - yasm_expr__type type; /**< Type */ - - /** Expression item data. Correct value depends on type. */ - union { - yasm_bytecode *precbc; /**< Direct bytecode ref (YASM_EXPR_PRECBC) */ - yasm_symrec *sym; /**< Symbol (YASM_EXPR_SYM) */ - yasm_expr *expn; /**< Subexpression (YASM_EXPR_EXPR) */ - yasm_intnum *intn; /**< Integer value (YASM_EXPR_INT) */ - yasm_floatnum *flt; /**< Floating point value (YASM_EXPR_FLOAT) */ - uintptr_t reg; /**< Register (YASM_EXPR_REG) */ - unsigned int subst; /**< Subst placeholder (YASM_EXPR_SUBST) */ - } data; -} yasm_expr__item; - -/** Expression. */ -struct yasm_expr { - yasm_expr_op op; /**< Operation. */ - unsigned long line; /**< Line number where expression was defined. */ - int numterms; /**< Number of terms in the expression. */ - - /** Terms of the expression. Structure may be extended to include more - * terms, as some operations may allow more than two operand terms - * (ADD, MUL, OR, AND, XOR). - */ - yasm_expr__item terms[2]; -}; - -/** Create a new expression e=a op b. - * \param op operation - * \param a expression item a - * \param b expression item b (optional depending on op) - * \param line virtual line (where expression defined) - * \return Newly allocated expression. - */ -YASM_LIB_DECL -/*@only@*/ yasm_expr *yasm_expr_create - (yasm_expr_op op, /*@only@*/ yasm_expr__item *a, - /*@only@*/ /*@null@*/ yasm_expr__item *b, unsigned long line); - -/** Create a new preceding-bytecode expression item. - * \param precbc preceding bytecode - * \return Newly allocated expression item. - */ -YASM_LIB_DECL -/*@only@*/ yasm_expr__item *yasm_expr_precbc(/*@keep@*/ yasm_bytecode *precbc); - -/** Create a new symbol expression item. - * \param sym symbol - * \return Newly allocated expression item. - */ -YASM_LIB_DECL -/*@only@*/ yasm_expr__item *yasm_expr_sym(/*@keep@*/ yasm_symrec *sym); - -/** Create a new expression expression item. - * \param e expression - * \return Newly allocated expression item. - */ -YASM_LIB_DECL -/*@only@*/ yasm_expr__item *yasm_expr_expr(/*@keep@*/ yasm_expr *e); - -/** Create a new intnum expression item. - * \param intn intnum - * \return Newly allocated expression item. - */ -YASM_LIB_DECL -/*@only@*/ yasm_expr__item *yasm_expr_int(/*@keep@*/ yasm_intnum *intn); - -/** Create a new floatnum expression item. - * \param flt floatnum - * \return Newly allocated expression item. - */ -YASM_LIB_DECL -/*@only@*/ yasm_expr__item *yasm_expr_float(/*@keep@*/ yasm_floatnum *flt); - -/** Create a new register expression item. - * \param reg register - * \return Newly allocated expression item. - */ -YASM_LIB_DECL -/*@only@*/ yasm_expr__item *yasm_expr_reg(uintptr_t reg); - -/** Create a new expression tree e=l op r. - * \param l expression for left side of new expression - * \param o operation - * \param r expression for right side of new expression - * \param i line index - * \return Newly allocated expression. - */ -#define yasm_expr_create_tree(l,o,r,i) \ - yasm_expr_create ((o), yasm_expr_expr(l), yasm_expr_expr(r), i) - -/** Create a new expression branch e=op r. - * \param o operation - * \param r expression for right side of new expression - * \param i line index - * \return Newly allocated expression. - */ -#define yasm_expr_create_branch(o,r,i) \ - yasm_expr_create ((o), yasm_expr_expr(r), (yasm_expr__item *)NULL, i) - -/** Create a new expression identity e=r. - * \param r expression for identity within new expression - * \param i line index - * \return Newly allocated expression. - */ -#define yasm_expr_create_ident(r,i) \ - yasm_expr_create (YASM_EXPR_IDENT, (r), (yasm_expr__item *)NULL, i) - -/** Duplicate an expression. - * \param e expression - * \return Newly allocated expression identical to e. - */ -yasm_expr *yasm_expr_copy(const yasm_expr *e); -#ifndef YASM_DOXYGEN -#define yasm_expr_copy(e) yasm_expr__copy_except(e, -1) -#endif - -/** Destroy (free allocated memory for) an expression. - * \param e expression - */ -YASM_LIB_DECL -void yasm_expr_destroy(/*@only@*/ /*@null@*/ yasm_expr *e); - -/** Determine if an expression is a specified operation (at the top level). - * \param e expression - * \param op operator - * \return Nonzero if the expression was the specified operation at the top - * level, zero otherwise. - */ -YASM_LIB_DECL -int yasm_expr_is_op(const yasm_expr *e, yasm_expr_op op); - -/** Extra transformation function for yasm_expr__level_tree(). - * \param e expression being simplified - * \param d data provided as expr_xform_extra_data to - * yasm_expr__level_tree() - * \return Transformed e. - */ -typedef /*@only@*/ yasm_expr * (*yasm_expr_xform_func) - (/*@returned@*/ /*@only@*/ yasm_expr *e, /*@null@*/ void *d); - -/** Level an entire expression tree. - * \internal - * \param e expression - * \param fold_const enable constant folding if nonzero - * \param simplify_ident simplify identities - * \param simplify_reg_mul simplify REG*1 identities - * \param calc_bc_dist nonzero if distances between bytecodes should be - * calculated, 0 if they should be left intact - * \param expr_xform_extra extra transformation function - * \param expr_xform_extra_data data to pass to expr_xform_extra - * \return Leveled expression. - */ -YASM_LIB_DECL -/*@only@*/ /*@null@*/ yasm_expr *yasm_expr__level_tree - (/*@returned@*/ /*@only@*/ /*@null@*/ yasm_expr *e, int fold_const, - int simplify_ident, int simplify_reg_mul, int calc_bc_dist, - /*@null@*/ yasm_expr_xform_func expr_xform_extra, - /*@null@*/ void *expr_xform_extra_data); - -/** Simplify an expression as much as possible. Eliminates extraneous - * branches and simplifies integer-only subexpressions. Simplified version - * of yasm_expr__level_tree(). - * \param e expression - * \param cbd if distance between bytecodes should be calculated - * \return Simplified expression. - */ -#define yasm_expr_simplify(e, cbd) \ - yasm_expr__level_tree(e, 1, 1, 1, cbd, NULL, NULL) - -/** Extract the segment portion of an expression containing SEG:OFF, leaving - * the offset. - * \param ep expression (pointer to) - * \return NULL if unable to extract a segment (expr does not contain a - * YASM_EXPR_SEGOFF operator), otherwise the segment expression. - * The input expression is modified such that on return, it's the - * offset expression. - */ -YASM_LIB_DECL -/*@only@*/ /*@null@*/ yasm_expr *yasm_expr_extract_deep_segoff(yasm_expr **ep); - -/** Extract the segment portion of a SEG:OFF expression, leaving the offset. - * \param ep expression (pointer to) - * \return NULL if unable to extract a segment (YASM_EXPR_SEGOFF not the - * top-level operator), otherwise the segment expression. The input - * expression is modified such that on return, it's the offset - * expression. - */ -YASM_LIB_DECL -/*@only@*/ /*@null@*/ yasm_expr *yasm_expr_extract_segoff(yasm_expr **ep); - -/** Extract the right portion (y) of a x WRT y expression, leaving the left - * portion (x). - * \param ep expression (pointer to) - * \return NULL if unable to extract (YASM_EXPR_WRT not the top-level - * operator), otherwise the right side of the WRT expression. The - * input expression is modified such that on return, it's the left side - * of the WRT expression. - */ -YASM_LIB_DECL -/*@only@*/ /*@null@*/ yasm_expr *yasm_expr_extract_wrt(yasm_expr **ep); - -/** Get the integer value of an expression if it's just an integer. - * \param ep expression (pointer to) - * \param calc_bc_dist nonzero if distances between bytecodes should be - * calculated, 0 if NULL should be returned in this case - * \return NULL if the expression is too complex (contains anything other than - * integers, ie floats, non-valued labels, registers); otherwise the - * intnum value of the expression. - */ -YASM_LIB_DECL -/*@dependent@*/ /*@null@*/ yasm_intnum *yasm_expr_get_intnum - (yasm_expr **ep, int calc_bc_dist); - -/** Get the symbol value of an expression if it's just a symbol. - * \param ep expression (pointer to) - * \param simplify if nonzero, simplify the expression first - * \return NULL if the expression is too complex; otherwise the symbol value of - * the expression. - */ -YASM_LIB_DECL -/*@dependent@*/ /*@null@*/ const yasm_symrec *yasm_expr_get_symrec - (yasm_expr **ep, int simplify); - -/** Get the register value of an expression if it's just a register. - * \param ep expression (pointer to) - * \param simplify if nonzero, simplify the expression first - * \return NULL if the expression is too complex; otherwise the register value - * of the expression. - */ -YASM_LIB_DECL -/*@dependent@*/ /*@null@*/ const uintptr_t *yasm_expr_get_reg - (yasm_expr **ep, int simplify); - -/** Print an expression. For debugging purposes. - * \param e expression - * \param f file - */ -YASM_LIB_DECL -void yasm_expr_print(/*@null@*/ const yasm_expr *e, FILE *f); - -/** Return the size of an expression, if the user provided it - * \param e expression - */ -YASM_LIB_DECL -unsigned int yasm_expr_size(const yasm_expr *e); - -/** Return the segment of an expression, if the user provided it - * \param e expression - */ -YASM_LIB_DECL -const char *yasm_expr_segment(const yasm_expr *e); - -/** Traverse over expression tree in order (const version). - * Calls func for each leaf (non-operation). - * \param e expression - * \param d data passed to each call to func - * \param func callback function - * \return Stops early (and returns 1) if func returns 1. - * Otherwise returns 0. - */ -YASM_LIB_DECL -int yasm_expr__traverse_leaves_in_const - (const yasm_expr *e, /*@null@*/ void *d, - int (*func) (/*@null@*/ const yasm_expr__item *ei, /*@null@*/ void *d)); - -/** Traverse over expression tree in order. - * Calls func for each leaf (non-operation). - * \param e expression - * \param d data passed to each call to func - * \param func callback function - * \return Stops early (and returns 1) if func returns 1. - * Otherwise returns 0. - */ -YASM_LIB_DECL -int yasm_expr__traverse_leaves_in - (yasm_expr *e, /*@null@*/ void *d, - int (*func) (/*@null@*/ yasm_expr__item *ei, /*@null@*/ void *d)); - -/** Reorder terms of e into canonical order. Only reorders if reordering - * doesn't change meaning of expression. (eg, doesn't reorder SUB). - * Canonical order: REG, INT, FLOAT, SYM, EXPR. - * Multiple terms of a single type are kept in the same order as in - * the original expression. - * \param e expression - * \note Only performs reordering on *one* level (no recursion). - */ -YASM_LIB_DECL -void yasm_expr__order_terms(yasm_expr *e); - -/** Copy entire expression EXCEPT for index "except" at *top level only*. - * \param e expression - * \param except term index not to copy; -1 to copy all terms - * \return Newly allocated copy of expression. - */ -YASM_LIB_DECL -yasm_expr *yasm_expr__copy_except(const yasm_expr *e, int except); - -/** Test if expression contains an item. Searches recursively into - * subexpressions. - * \param e expression - * \param t type of item to look for - * \return Nonzero if expression contains an item of type t, zero if not. - */ -YASM_LIB_DECL -int yasm_expr__contains(const yasm_expr *e, yasm_expr__type t); - -/** Transform symrec-symrec terms in expression into #YASM_EXPR_SUBST items. - * Calls the callback function for each symrec-symrec term. - * \param ep expression (pointer to) - * \param cbd callback data passed to callback function - * \param callback callback function: given subst index for bytecode - * pair, bytecode pair (bc2-bc1), and cbd (callback data) - * \return Number of transformations made. - */ -YASM_LIB_DECL -int yasm_expr__bc_dist_subst(yasm_expr **ep, void *cbd, - void (*callback) (unsigned int subst, - yasm_bytecode *precbc, - yasm_bytecode *precbc2, - void *cbd)); - -/** Substitute items into expr YASM_EXPR_SUBST items (by index). Items are - * copied, so caller is responsible for freeing array of items. - * \param e expression - * \param num_items number of items in items array - * \param items items array - * \return 1 on error (index out of range). - */ -YASM_LIB_DECL -int yasm_expr__subst(yasm_expr *e, unsigned int num_items, - const yasm_expr__item *items); - -#endif +/** + * \file libyasm/expr.h + * \brief YASM expression interface. + * + * \license + * Copyright (C) 2001-2007 Michael Urman, Peter Johnson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * \endlicense + */ +#ifndef YASM_EXPR_H +#define YASM_EXPR_H + +#ifndef YASM_LIB_DECL +#define YASM_LIB_DECL +#endif + +/** Type of an expression item. Types are listed in canonical sorting order. + * See expr_order_terms(). + * Note #YASM_EXPR_PRECBC must be used carefully (in a-b pairs), as only + * symrecs can become the relative term in a #yasm_value. + */ +typedef enum yasm_expr__type { + YASM_EXPR_NONE = 0, /**< Nothing */ + YASM_EXPR_REG = 1<<0, /**< Register */ + YASM_EXPR_INT = 1<<1, /**< Integer value */ + YASM_EXPR_SUBST = 1<<2, /**< Substitution placeholder */ + YASM_EXPR_FLOAT = 1<<3, /**< Floating point value */ + YASM_EXPR_SYM = 1<<4, /**< Symbol */ + YASM_EXPR_PRECBC = 1<<5,/**< Direct bytecode ref (rather than via sym) */ + YASM_EXPR_EXPR = 1<<6 /**< Subexpression */ +} yasm_expr__type; + +/** Expression item. */ +typedef struct yasm_expr__item { + yasm_expr__type type; /**< Type */ + + /** Expression item data. Correct value depends on type. */ + union { + yasm_bytecode *precbc; /**< Direct bytecode ref (YASM_EXPR_PRECBC) */ + yasm_symrec *sym; /**< Symbol (YASM_EXPR_SYM) */ + yasm_expr *expn; /**< Subexpression (YASM_EXPR_EXPR) */ + yasm_intnum *intn; /**< Integer value (YASM_EXPR_INT) */ + yasm_floatnum *flt; /**< Floating point value (YASM_EXPR_FLOAT) */ + uintptr_t reg; /**< Register (YASM_EXPR_REG) */ + unsigned int subst; /**< Subst placeholder (YASM_EXPR_SUBST) */ + } data; +} yasm_expr__item; + +/** Expression. */ +struct yasm_expr { + yasm_expr_op op; /**< Operation. */ + unsigned long line; /**< Line number where expression was defined. */ + int numterms; /**< Number of terms in the expression. */ + + /** Terms of the expression. Structure may be extended to include more + * terms, as some operations may allow more than two operand terms + * (ADD, MUL, OR, AND, XOR). + */ + yasm_expr__item terms[2]; +}; + +/** Create a new expression e=a op b. + * \param op operation + * \param a expression item a + * \param b expression item b (optional depending on op) + * \param line virtual line (where expression defined) + * \return Newly allocated expression. + */ +YASM_LIB_DECL +/*@only@*/ yasm_expr *yasm_expr_create + (yasm_expr_op op, /*@only@*/ yasm_expr__item *a, + /*@only@*/ /*@null@*/ yasm_expr__item *b, unsigned long line); + +/** Create a new preceding-bytecode expression item. + * \param precbc preceding bytecode + * \return Newly allocated expression item. + */ +YASM_LIB_DECL +/*@only@*/ yasm_expr__item *yasm_expr_precbc(/*@keep@*/ yasm_bytecode *precbc); + +/** Create a new symbol expression item. + * \param sym symbol + * \return Newly allocated expression item. + */ +YASM_LIB_DECL +/*@only@*/ yasm_expr__item *yasm_expr_sym(/*@keep@*/ yasm_symrec *sym); + +/** Create a new expression expression item. + * \param e expression + * \return Newly allocated expression item. + */ +YASM_LIB_DECL +/*@only@*/ yasm_expr__item *yasm_expr_expr(/*@keep@*/ yasm_expr *e); + +/** Create a new intnum expression item. + * \param intn intnum + * \return Newly allocated expression item. + */ +YASM_LIB_DECL +/*@only@*/ yasm_expr__item *yasm_expr_int(/*@keep@*/ yasm_intnum *intn); + +/** Create a new floatnum expression item. + * \param flt floatnum + * \return Newly allocated expression item. + */ +YASM_LIB_DECL +/*@only@*/ yasm_expr__item *yasm_expr_float(/*@keep@*/ yasm_floatnum *flt); + +/** Create a new register expression item. + * \param reg register + * \return Newly allocated expression item. + */ +YASM_LIB_DECL +/*@only@*/ yasm_expr__item *yasm_expr_reg(uintptr_t reg); + +/** Create a new expression tree e=l op r. + * \param l expression for left side of new expression + * \param o operation + * \param r expression for right side of new expression + * \param i line index + * \return Newly allocated expression. + */ +#define yasm_expr_create_tree(l,o,r,i) \ + yasm_expr_create ((o), yasm_expr_expr(l), yasm_expr_expr(r), i) + +/** Create a new expression branch e=op r. + * \param o operation + * \param r expression for right side of new expression + * \param i line index + * \return Newly allocated expression. + */ +#define yasm_expr_create_branch(o,r,i) \ + yasm_expr_create ((o), yasm_expr_expr(r), (yasm_expr__item *)NULL, i) + +/** Create a new expression identity e=r. + * \param r expression for identity within new expression + * \param i line index + * \return Newly allocated expression. + */ +#define yasm_expr_create_ident(r,i) \ + yasm_expr_create (YASM_EXPR_IDENT, (r), (yasm_expr__item *)NULL, i) + +/** Duplicate an expression. + * \param e expression + * \return Newly allocated expression identical to e. + */ +yasm_expr *yasm_expr_copy(const yasm_expr *e); +#ifndef YASM_DOXYGEN +#define yasm_expr_copy(e) yasm_expr__copy_except(e, -1) +#endif + +/** Destroy (free allocated memory for) an expression. + * \param e expression + */ +YASM_LIB_DECL +void yasm_expr_destroy(/*@only@*/ /*@null@*/ yasm_expr *e); + +/** Determine if an expression is a specified operation (at the top level). + * \param e expression + * \param op operator + * \return Nonzero if the expression was the specified operation at the top + * level, zero otherwise. + */ +YASM_LIB_DECL +int yasm_expr_is_op(const yasm_expr *e, yasm_expr_op op); + +/** Extra transformation function for yasm_expr__level_tree(). + * \param e expression being simplified + * \param d data provided as expr_xform_extra_data to + * yasm_expr__level_tree() + * \return Transformed e. + */ +typedef /*@only@*/ yasm_expr * (*yasm_expr_xform_func) + (/*@returned@*/ /*@only@*/ yasm_expr *e, /*@null@*/ void *d); + +/** Level an entire expression tree. + * \internal + * \param e expression + * \param fold_const enable constant folding if nonzero + * \param simplify_ident simplify identities + * \param simplify_reg_mul simplify REG*1 identities + * \param calc_bc_dist nonzero if distances between bytecodes should be + * calculated, 0 if they should be left intact + * \param expr_xform_extra extra transformation function + * \param expr_xform_extra_data data to pass to expr_xform_extra + * \return Leveled expression. + */ +YASM_LIB_DECL +/*@only@*/ /*@null@*/ yasm_expr *yasm_expr__level_tree + (/*@returned@*/ /*@only@*/ /*@null@*/ yasm_expr *e, int fold_const, + int simplify_ident, int simplify_reg_mul, int calc_bc_dist, + /*@null@*/ yasm_expr_xform_func expr_xform_extra, + /*@null@*/ void *expr_xform_extra_data); + +/** Simplify an expression as much as possible. Eliminates extraneous + * branches and simplifies integer-only subexpressions. Simplified version + * of yasm_expr__level_tree(). + * \param e expression + * \param cbd if distance between bytecodes should be calculated + * \return Simplified expression. + */ +#define yasm_expr_simplify(e, cbd) \ + yasm_expr__level_tree(e, 1, 1, 1, cbd, NULL, NULL) + +/** Extract the segment portion of an expression containing SEG:OFF, leaving + * the offset. + * \param ep expression (pointer to) + * \return NULL if unable to extract a segment (expr does not contain a + * YASM_EXPR_SEGOFF operator), otherwise the segment expression. + * The input expression is modified such that on return, it's the + * offset expression. + */ +YASM_LIB_DECL +/*@only@*/ /*@null@*/ yasm_expr *yasm_expr_extract_deep_segoff(yasm_expr **ep); + +/** Extract the segment portion of a SEG:OFF expression, leaving the offset. + * \param ep expression (pointer to) + * \return NULL if unable to extract a segment (YASM_EXPR_SEGOFF not the + * top-level operator), otherwise the segment expression. The input + * expression is modified such that on return, it's the offset + * expression. + */ +YASM_LIB_DECL +/*@only@*/ /*@null@*/ yasm_expr *yasm_expr_extract_segoff(yasm_expr **ep); + +/** Extract the right portion (y) of a x WRT y expression, leaving the left + * portion (x). + * \param ep expression (pointer to) + * \return NULL if unable to extract (YASM_EXPR_WRT not the top-level + * operator), otherwise the right side of the WRT expression. The + * input expression is modified such that on return, it's the left side + * of the WRT expression. + */ +YASM_LIB_DECL +/*@only@*/ /*@null@*/ yasm_expr *yasm_expr_extract_wrt(yasm_expr **ep); + +/** Get the integer value of an expression if it's just an integer. + * \param ep expression (pointer to) + * \param calc_bc_dist nonzero if distances between bytecodes should be + * calculated, 0 if NULL should be returned in this case + * \return NULL if the expression is too complex (contains anything other than + * integers, ie floats, non-valued labels, registers); otherwise the + * intnum value of the expression. + */ +YASM_LIB_DECL +/*@dependent@*/ /*@null@*/ yasm_intnum *yasm_expr_get_intnum + (yasm_expr **ep, int calc_bc_dist); + +/** Get the symbol value of an expression if it's just a symbol. + * \param ep expression (pointer to) + * \param simplify if nonzero, simplify the expression first + * \return NULL if the expression is too complex; otherwise the symbol value of + * the expression. + */ +YASM_LIB_DECL +/*@dependent@*/ /*@null@*/ const yasm_symrec *yasm_expr_get_symrec + (yasm_expr **ep, int simplify); + +/** Get the register value of an expression if it's just a register. + * \param ep expression (pointer to) + * \param simplify if nonzero, simplify the expression first + * \return NULL if the expression is too complex; otherwise the register value + * of the expression. + */ +YASM_LIB_DECL +/*@dependent@*/ /*@null@*/ const uintptr_t *yasm_expr_get_reg + (yasm_expr **ep, int simplify); + +/** Print an expression. For debugging purposes. + * \param e expression + * \param f file + */ +YASM_LIB_DECL +void yasm_expr_print(/*@null@*/ const yasm_expr *e, FILE *f); + +/** Return the size of an expression, if the user provided it + * \param e expression + */ +YASM_LIB_DECL +unsigned int yasm_expr_size(const yasm_expr *e); + +/** Return the segment of an expression, if the user provided it + * \param e expression + */ +YASM_LIB_DECL +const char *yasm_expr_segment(const yasm_expr *e); + +/** Traverse over expression tree in order (const version). + * Calls func for each leaf (non-operation). + * \param e expression + * \param d data passed to each call to func + * \param func callback function + * \return Stops early (and returns 1) if func returns 1. + * Otherwise returns 0. + */ +YASM_LIB_DECL +int yasm_expr__traverse_leaves_in_const + (const yasm_expr *e, /*@null@*/ void *d, + int (*func) (/*@null@*/ const yasm_expr__item *ei, /*@null@*/ void *d)); + +/** Traverse over expression tree in order. + * Calls func for each leaf (non-operation). + * \param e expression + * \param d data passed to each call to func + * \param func callback function + * \return Stops early (and returns 1) if func returns 1. + * Otherwise returns 0. + */ +YASM_LIB_DECL +int yasm_expr__traverse_leaves_in + (yasm_expr *e, /*@null@*/ void *d, + int (*func) (/*@null@*/ yasm_expr__item *ei, /*@null@*/ void *d)); + +/** Reorder terms of e into canonical order. Only reorders if reordering + * doesn't change meaning of expression. (eg, doesn't reorder SUB). + * Canonical order: REG, INT, FLOAT, SYM, EXPR. + * Multiple terms of a single type are kept in the same order as in + * the original expression. + * \param e expression + * \note Only performs reordering on *one* level (no recursion). + */ +YASM_LIB_DECL +void yasm_expr__order_terms(yasm_expr *e); + +/** Copy entire expression EXCEPT for index "except" at *top level only*. + * \param e expression + * \param except term index not to copy; -1 to copy all terms + * \return Newly allocated copy of expression. + */ +YASM_LIB_DECL +yasm_expr *yasm_expr__copy_except(const yasm_expr *e, int except); + +/** Test if expression contains an item. Searches recursively into + * subexpressions. + * \param e expression + * \param t type of item to look for + * \return Nonzero if expression contains an item of type t, zero if not. + */ +YASM_LIB_DECL +int yasm_expr__contains(const yasm_expr *e, yasm_expr__type t); + +/** Transform symrec-symrec terms in expression into #YASM_EXPR_SUBST items. + * Calls the callback function for each symrec-symrec term. + * \param ep expression (pointer to) + * \param cbd callback data passed to callback function + * \param callback callback function: given subst index for bytecode + * pair, bytecode pair (bc2-bc1), and cbd (callback data) + * \return Number of transformations made. + */ +YASM_LIB_DECL +int yasm_expr__bc_dist_subst(yasm_expr **ep, void *cbd, + void (*callback) (unsigned int subst, + yasm_bytecode *precbc, + yasm_bytecode *precbc2, + void *cbd)); + +/** Substitute items into expr YASM_EXPR_SUBST items (by index). Items are + * copied, so caller is responsible for freeing array of items. + * \param e expression + * \param num_items number of items in items array + * \param items items array + * \return 1 on error (index out of range). + */ +YASM_LIB_DECL +int yasm_expr__subst(yasm_expr *e, unsigned int num_items, + const yasm_expr__item *items); + +#endif diff --git a/contrib/tools/yasm/libyasm/file.c b/contrib/tools/yasm/libyasm/file.c index fc7dab6c17..c4adde0a3a 100644 --- a/contrib/tools/yasm/libyasm/file.c +++ b/contrib/tools/yasm/libyasm/file.c @@ -1,672 +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; +/* + * 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) - 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; -} + if (stat(ts, &fi) != -1) { + if (!S_ISDIR(fi.st_mode)) + break; + } else if (errno == ENOENT) { + if (mkdir(ts, 0755) == -1) { + lth = 0; + break; + } + } +#else + break; +#endif + } + *tp++ = *pp++; + } + free(ts); + return lth; +} + +typedef struct incpath { + STAILQ_ENTRY(incpath) link; + /*@owned@*/ char *path; +} incpath; + +STAILQ_HEAD(incpath_head, incpath) incpaths = STAILQ_HEAD_INITIALIZER(incpaths); + +FILE * +yasm_fopen_include(const char *iname, const char *from, const char *mode, + char **oname) +{ + FILE *f; + char *combine; + incpath *np; + + /* Try directly relative to from first, then each of the include paths */ + if (from) { + combine = yasm__combpath(from, iname); + f = fopen(combine, mode); + if (f) { + if (oname) + *oname = combine; + else + yasm_xfree(combine); + return f; + } + yasm_xfree(combine); + } + + STAILQ_FOREACH(np, &incpaths, link) { + combine = yasm__combpath(np->path, iname); + f = fopen(combine, mode); + if (f) { + if (oname) + *oname = combine; + else + yasm_xfree(combine); + return f; + } + yasm_xfree(combine); + } + + if (oname) + *oname = NULL; + return NULL; +} + +void +yasm_delete_include_paths(void) +{ + incpath *n1, *n2; + + n1 = STAILQ_FIRST(&incpaths); + while (n1) { + n2 = STAILQ_NEXT(n1, link); + yasm_xfree(n1->path); + yasm_xfree(n1); + n1 = n2; + } + STAILQ_INIT(&incpaths); +} + +const char * +yasm_get_include_dir(void **iter) +{ + incpath *p = (incpath *)*iter; + + if (!p) + p = STAILQ_FIRST(&incpaths); + else + p = STAILQ_NEXT(p, link); + + *iter = p; + if (p) + return p->path; + else + return NULL; +} + +void +yasm_add_include_path(const char *path) +{ + incpath *np = yasm_xmalloc(sizeof(incpath)); + size_t len = strlen(path); + + np->path = yasm_xmalloc(len+2); + memcpy(np->path, path, len+1); + /* Add trailing slash if it is missing */ + if (path[len-1] != '\\' && path[len-1] != '/') { + np->path[len] = '/'; + np->path[len+1] = '\0'; + } + + STAILQ_INSERT_TAIL(&incpaths, np, link); +} + +size_t +yasm_fwrite_16_l(unsigned short val, FILE *f) +{ + if (fputc(val & 0xFF, f) == EOF) + return 0; + if (fputc((val >> 8) & 0xFF, f) == EOF) + return 0; + return 1; +} + +size_t +yasm_fwrite_32_l(unsigned long val, FILE *f) +{ + if (fputc((int)(val & 0xFF), f) == EOF) + return 0; + if (fputc((int)((val >> 8) & 0xFF), f) == EOF) + return 0; + if (fputc((int)((val >> 16) & 0xFF), f) == EOF) + return 0; + if (fputc((int)((val >> 24) & 0xFF), f) == EOF) + return 0; + return 1; +} + +size_t +yasm_fwrite_16_b(unsigned short val, FILE *f) +{ + if (fputc((val >> 8) & 0xFF, f) == EOF) + return 0; + if (fputc(val & 0xFF, f) == EOF) + return 0; + return 1; +} + +size_t +yasm_fwrite_32_b(unsigned long val, FILE *f) +{ + if (fputc((int)((val >> 24) & 0xFF), f) == EOF) + return 0; + if (fputc((int)((val >> 16) & 0xFF), f) == EOF) + return 0; + if (fputc((int)((val >> 8) & 0xFF), f) == EOF) + return 0; + if (fputc((int)(val & 0xFF), f) == EOF) + return 0; + return 1; +} diff --git a/contrib/tools/yasm/libyasm/file.h b/contrib/tools/yasm/libyasm/file.h index 1e9b87b0d5..01bca80cdc 100644 --- a/contrib/tools/yasm/libyasm/file.h +++ b/contrib/tools/yasm/libyasm/file.h @@ -1,525 +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 +/** + * \file libyasm/file.h + * \brief YASM file helpers. + * + * \license + * Copyright (C) 2001-2007 Peter Johnson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * \endlicense + */ +#ifndef YASM_FILE_H +#define YASM_FILE_H + +#ifndef YASM_LIB_DECL +#define YASM_LIB_DECL +#endif + +/** Re2c scanner state. */ +typedef struct yasm_scanner { + unsigned char *bot; /**< Bottom of scan buffer */ + unsigned char *tok; /**< Start of token */ + unsigned char *ptr; /**< Scan marker */ + unsigned char *cur; /**< Cursor (1 past end of token) */ + unsigned char *lim; /**< Limit of good data */ + unsigned char *top; /**< Top of scan buffer */ + unsigned char *eof; /**< End of file */ +} yasm_scanner; + +/** Initialize scanner state. + * \param scanner Re2c scanner state + */ +YASM_LIB_DECL +void yasm_scanner_initialize(yasm_scanner *scanner); + +/** Frees any memory used by scanner state; does not free state itself. + * \param scanner Re2c scanner state + */ +YASM_LIB_DECL +void yasm_scanner_delete(yasm_scanner *scanner); + +/** Fill a scanner state structure with data coming from an input function. + * \param scanner Re2c scanner state + * \param cursor Re2c scan cursor + * \param input_func Input function to read data; takes buffer and maximum + * number of bytes, returns number of bytes read. + * \param input_func_data Data to pass as the first parameter to input_func + * \return 1 if this was the first time this function was called on this + * scanner state, 0 otherwise. + */ +YASM_LIB_DECL +int yasm_fill_helper + (yasm_scanner *scanner, unsigned char **cursor, + size_t (*input_func) (void *d, unsigned char *buf, size_t max), + void *input_func_data); + +/** Unescape a string with C-style escapes. Handles b, f, n, r, t, and hex + * and octal escapes. String is updated in-place. + * Edge cases: + * - hex escapes: reads as many hex digits as possible, takes last 2 as value. + * - oct escapes: takes up to 3 digits 0-9 and scales appropriately, with + * warning. + * \param str C-style string (updated in place) + * \param len length of string (updated with new length) + */ +YASM_LIB_DECL +void yasm_unescape_cstring(unsigned char *str, size_t *len); + +/** Split a UNIX pathname into head (directory) and tail (base filename) + * portions. + * \internal + * \param path pathname + * \param tail (returned) base filename + * \return Length of head (directory). + */ +YASM_LIB_DECL +size_t yasm__splitpath_unix(const char *path, /*@out@*/ const char **tail); + +/** Split a Windows pathname into head (directory) and tail (base filename) + * portions. + * \internal + * \param path pathname + * \param tail (returned) base filename + * \return Length of head (directory). + */ +YASM_LIB_DECL +size_t yasm__splitpath_win(const char *path, /*@out@*/ const char **tail); + +/** Split a pathname into head (directory) and tail (base filename) portions. + * Unless otherwise defined, defaults to yasm__splitpath_unix(). + * \internal + * \param path pathname + * \param tail (returned) base filename + * \return Length of head (directory). + */ +#ifndef yasm__splitpath +# if defined (_WIN32) || defined (WIN32) || defined (__MSDOS__) || \ + defined (__DJGPP__) || defined (__OS2__) +# define yasm__splitpath(path, tail) yasm__splitpath_win(path, tail) +# else +# define yasm__splitpath(path, tail) yasm__splitpath_unix(path, tail) +# endif +#endif + +/** Get the current working directory. + * \internal + * \return Current working directory pathname (newly allocated). + */ +YASM_LIB_DECL +/*@only@*/ char *yasm__getcwd(void); + +/** Convert a relative or absolute pathname into an absolute pathname. + * \internal + * \param path pathname + * \return Absolute version of path (newly allocated). + */ +YASM_LIB_DECL +/*@only@*/ char *yasm__abspath(const char *path); + +/** Build a UNIX pathname that is equivalent to accessing the "to" pathname + * when you're in the directory containing "from". Result is relative if both + * from and to are relative. + * \internal + * \param from from pathname + * \param to to pathname + * \return Combined path (newly allocated). + */ +YASM_LIB_DECL +char *yasm__combpath_unix(const char *from, const char *to); + +/** Build a Windows pathname that is equivalent to accessing the "to" pathname + * when you're in the directory containing "from". Result is relative if both + * from and to are relative. + * \internal + * \param from from pathname + * \param to to pathname + * \return Combined path (newly allocated). + */ +YASM_LIB_DECL +char *yasm__combpath_win(const char *from, const char *to); + +/** Build a pathname that is equivalent to accessing the "to" pathname + * when you're in the directory containing "from". Result is relative if both + * from and to are relative. + * Unless otherwise defined, defaults to yasm__combpath_unix(). + * \internal + * \param from from pathname + * \param to to pathname + * \return Combined path (newly allocated). + */ +#ifndef yasm__combpath +# if defined (_WIN32) || defined (WIN32) || defined (__MSDOS__) || \ + defined (__DJGPP__) || defined (__OS2__) +# define yasm__combpath(from, to) yasm__combpath_win(from, to) +# else +# define yasm__combpath(from, to) yasm__combpath_unix(from, to) +# endif +#endif + +/** Recursively create tree of directories needed for pathname. + * \internal + * \param path pathname + * \param win handle windows paths + * \return Length of directory portion of pathname. + */ +YASM_LIB_DECL +size_t yasm__createpath_common(const char *path, int win); + +/** Recursively create tree of directories needed for pathname. + * Unless otherwise defined, defaults to yasm__createpath_unix(). + * \internal + * \param path pathname + * \return Length of directory portion of pathname. + */ +#ifndef yasm__createpath +# if defined (_WIN32) || defined (WIN32) || defined (__MSDOS__) || \ + defined (__DJGPP__) || defined (__OS2__) +# define yasm__createpath(path) yasm__createpath_common(path, 1) +# else +# define yasm__createpath(path) yasm__createpath_common(path, 0) +# endif +#endif + +/** Try to find and open an include file, searching through include paths. + * First iname is looked for relative to the directory containing "from", then + * it's looked for relative to each of the include paths. + * + * All pathnames may be either absolute or relative; from, oname, and + * include paths, if relative, are relative from the current working directory. + * + * First match wins; the full pathname (newly allocated) to the opened file + * is saved into oname, and the fopen'ed FILE * is returned. If not found, + * NULL is returned. + * + * \param iname file to include + * \param from file doing the including + * \param mode fopen mode string + * \param oname full pathname of included file (may be relative). NULL + * may be passed if this is unwanted. + * \return fopen'ed include file, or NULL if not found. + */ +YASM_LIB_DECL +/*@null@*/ FILE *yasm_fopen_include + (const char *iname, const char *from, const char *mode, + /*@null@*/ /*@out@*/ /*@only@*/ char **oname); + +/** Delete any stored include paths added by yasm_add_include_path(). + */ +YASM_LIB_DECL +void yasm_delete_include_paths(void); + +/** Iterate through include paths. +*/ +YASM_LIB_DECL +const char * yasm_get_include_dir(void **iter); + +/** Add an include path for use by yasm_fopen_include(). + * If path is relative, it is treated by yasm_fopen_include() as relative to + * the current working directory. + * + * \param path path to add + */ +YASM_LIB_DECL +void yasm_add_include_path(const char *path); + +/** Write an 8-bit value to a buffer, incrementing buffer pointer. + * \note Only works properly if ptr is an (unsigned char *). + * \param ptr buffer + * \param val 8-bit value + */ +#define YASM_WRITE_8(ptr, val) \ + *((ptr)++) = (unsigned char)((val) & 0xFF) + +/** Write a 16-bit value to a buffer in little endian, incrementing buffer + * pointer. + * \note Only works properly if ptr is an (unsigned char *). + * \param ptr buffer + * \param val 16-bit value + */ +#define YASM_WRITE_16_L(ptr, val) \ + do { \ + *((ptr)++) = (unsigned char)((val) & 0xFF); \ + *((ptr)++) = (unsigned char)(((val) >> 8) & 0xFF); \ + } while (0) + +/** Write a 32-bit value to a buffer in little endian, incrementing buffer + * pointer. + * \note Only works properly if ptr is an (unsigned char *). + * \param ptr buffer + * \param val 32-bit value + */ +#define YASM_WRITE_32_L(ptr, val) \ + do { \ + *((ptr)++) = (unsigned char)((val) & 0xFF); \ + *((ptr)++) = (unsigned char)(((val) >> 8) & 0xFF); \ + *((ptr)++) = (unsigned char)(((val) >> 16) & 0xFF); \ + *((ptr)++) = (unsigned char)(((val) >> 24) & 0xFF); \ + } while (0) + +/** Write a 16-bit value to a buffer in big endian, incrementing buffer + * pointer. + * \note Only works properly if ptr is an (unsigned char *). + * \param ptr buffer + * \param val 16-bit value + */ +#define YASM_WRITE_16_B(ptr, val) \ + do { \ + *((ptr)++) = (unsigned char)(((val) >> 8) & 0xFF); \ + *((ptr)++) = (unsigned char)((val) & 0xFF); \ + } while (0) + +/** Write a 32-bit value to a buffer in big endian, incrementing buffer + * pointer. + * \note Only works properly if ptr is an (unsigned char *). + * \param ptr buffer + * \param val 32-bit value + */ +#define YASM_WRITE_32_B(ptr, val) \ + do { \ + *((ptr)++) = (unsigned char)(((val) >> 24) & 0xFF); \ + *((ptr)++) = (unsigned char)(((val) >> 16) & 0xFF); \ + *((ptr)++) = (unsigned char)(((val) >> 8) & 0xFF); \ + *((ptr)++) = (unsigned char)((val) & 0xFF); \ + } while (0) + + +/** Write an 8-bit value to a buffer. Does not increment buffer pointer. + * \note Only works properly if ptr is an (unsigned char *). + * \param ptr buffer + * \param val 8-bit value + */ +#define YASM_SAVE_8(ptr, val) \ + *(ptr) = (unsigned char)((val) & 0xFF) + +/** Write a 16-bit value to a buffer in little endian. Does not increment + * buffer pointer. + * \note Only works properly if ptr is an (unsigned char *). + * \param ptr buffer + * \param val 16-bit value + */ +#define YASM_SAVE_16_L(ptr, val) \ + do { \ + *(ptr) = (unsigned char)((val) & 0xFF); \ + *((ptr)+1) = (unsigned char)(((val) >> 8) & 0xFF); \ + } while (0) + +/** Write a 32-bit value to a buffer in little endian. Does not increment + * buffer pointer. + * \note Only works properly if ptr is an (unsigned char *). + * \param ptr buffer + * \param val 32-bit value + */ +#define YASM_SAVE_32_L(ptr, val) \ + do { \ + *(ptr) = (unsigned char)((val) & 0xFF); \ + *((ptr)+1) = (unsigned char)(((val) >> 8) & 0xFF); \ + *((ptr)+2) = (unsigned char)(((val) >> 16) & 0xFF); \ + *((ptr)+3) = (unsigned char)(((val) >> 24) & 0xFF); \ + } while (0) + +/** Write a 16-bit value to a buffer in big endian. Does not increment buffer + * pointer. + * \note Only works properly if ptr is an (unsigned char *). + * \param ptr buffer + * \param val 16-bit value + */ +#define YASM_SAVE_16_B(ptr, val) \ + do { \ + *(ptr) = (unsigned char)(((val) >> 8) & 0xFF); \ + *((ptr)+1) = (unsigned char)((val) & 0xFF); \ + } while (0) + +/** Write a 32-bit value to a buffer in big endian. Does not increment buffer + * pointer. + * \note Only works properly if ptr is an (unsigned char *). + * \param ptr buffer + * \param val 32-bit value + */ +#define YASM_SAVE_32_B(ptr, val) \ + do { \ + *(ptr) = (unsigned char)(((val) >> 24) & 0xFF); \ + *((ptr)+1) = (unsigned char)(((val) >> 16) & 0xFF); \ + *((ptr)+2) = (unsigned char)(((val) >> 8) & 0xFF); \ + *((ptr)+3) = (unsigned char)((val) & 0xFF); \ + } while (0) + +/** Direct-to-file version of YASM_SAVE_16_L(). + * \note Using the macro multiple times with a single fwrite() call will + * probably be faster than calling this function many times. + * \param val 16-bit value + * \param f file + * \return 1 if the write was successful, 0 if not (just like fwrite()). + */ +YASM_LIB_DECL +size_t yasm_fwrite_16_l(unsigned short val, FILE *f); + +/** Direct-to-file version of YASM_SAVE_32_L(). + * \note Using the macro multiple times with a single fwrite() call will + * probably be faster than calling this function many times. + * \param val 32-bit value + * \param f file + * \return 1 if the write was successful, 0 if not (just like fwrite()). + */ +YASM_LIB_DECL +size_t yasm_fwrite_32_l(unsigned long val, FILE *f); + +/** Direct-to-file version of YASM_SAVE_16_B(). + * \note Using the macro multiple times with a single fwrite() call will + * probably be faster than calling this function many times. + * \param val 16-bit value + * \param f file + * \return 1 if the write was successful, 0 if not (just like fwrite()). + */ +YASM_LIB_DECL +size_t yasm_fwrite_16_b(unsigned short val, FILE *f); + +/** Direct-to-file version of YASM_SAVE_32_B(). + * \note Using the macro multiple times with a single fwrite() call will + * probably be faster than calling this function many times. + * \param val 32-bit value + * \param f file + * \return 1 if the write was successful, 0 if not (just like fwrite()). + */ +YASM_LIB_DECL +size_t yasm_fwrite_32_b(unsigned long val, FILE *f); + +/** Read an 8-bit value from a buffer, incrementing buffer pointer. + * \note Only works properly if ptr is an (unsigned char *). + * \param ptr buffer + * \param val 8-bit value + */ +#define YASM_READ_8(val, ptr) \ + (val) = *((ptr)++) & 0xFF + +/** Read a 16-bit value from a buffer in little endian, incrementing buffer + * pointer. + * \note Only works properly if ptr is an (unsigned char *). + * \param ptr buffer + * \param val 16-bit value + */ +#define YASM_READ_16_L(val, ptr) \ + do { \ + (val) = *((ptr)++) & 0xFF; \ + (val) |= (*((ptr)++) & 0xFF) << 8; \ + } while (0) + +/** Read a 32-bit value from a buffer in little endian, incrementing buffer + * pointer. + * \note Only works properly if ptr is an (unsigned char *). + * \param ptr buffer + * \param val 32-bit value + */ +#define YASM_READ_32_L(val, ptr) \ + do { \ + (val) = *((ptr)++) & 0xFF; \ + (val) |= (*((ptr)++) & 0xFF) << 8; \ + (val) |= (*((ptr)++) & 0xFF) << 16; \ + (val) |= (*((ptr)++) & 0xFF) << 24; \ + } while (0) + +/** Read a 16-bit value from a buffer in big endian, incrementing buffer + * pointer. + * \note Only works properly if ptr is an (unsigned char *). + * \param ptr buffer + * \param val 16-bit value + */ +#define YASM_READ_16_B(val, ptr) \ + do { \ + (val) = (*((ptr)++) & 0xFF) << 8; \ + (val) |= *((ptr)++) & 0xFF; \ + } while (0) + +/** Read a 32-bit value from a buffer in big endian, incrementing buffer + * pointer. + * \note Only works properly if ptr is an (unsigned char *). + * \param ptr buffer + * \param val 32-bit value + */ +#define YASM_READ_32_B(val, ptr) \ + do { \ + (val) = (*((ptr)++) & 0xFF) << 24; \ + (val) |= (*((ptr)++) & 0xFF) << 16; \ + (val) |= (*((ptr)++) & 0xFF) << 8; \ + (val) |= *((ptr)++) & 0xFF; \ + } while (0) + +/** Read an 8-bit value from a buffer. Does not increment buffer pointer. + * \note Only works properly if ptr is an (unsigned char *). + * \param ptr buffer + * \param val 8-bit value + */ +#define YASM_LOAD_8(val, ptr) \ + (val) = *(ptr) & 0xFF + +/** Read a 16-bit value from a buffer in little endian. Does not increment + * buffer pointer. + * \note Only works properly if ptr is an (unsigned char *). + * \param ptr buffer + * \param val 16-bit value + */ +#define YASM_LOAD_16_L(val, ptr) \ + do { \ + (val) = *(ptr) & 0xFF; \ + (val) |= (*((ptr)+1) & 0xFF) << 8; \ + } while (0) + +/** Read a 32-bit value from a buffer in little endian. Does not increment + * buffer pointer. + * \note Only works properly if ptr is an (unsigned char *). + * \param ptr buffer + * \param val 32-bit value + */ +#define YASM_LOAD_32_L(val, ptr) \ + do { \ + (val) = (unsigned long)(*(ptr) & 0xFF); \ + (val) |= (unsigned long)((*((ptr)+1) & 0xFF) << 8); \ + (val) |= (unsigned long)((*((ptr)+2) & 0xFF) << 16); \ + (val) |= (unsigned long)((*((ptr)+3) & 0xFF) << 24); \ + } while (0) + +/** Read a 16-bit value from a buffer in big endian. Does not increment buffer + * pointer. + * \note Only works properly if ptr is an (unsigned char *). + * \param ptr buffer + * \param val 16-bit value + */ +#define YASM_LOAD_16_B(val, ptr) \ + do { \ + (val) = (*(ptr) & 0xFF) << 8; \ + (val) |= *((ptr)+1) & 0xFF; \ + } while (0) + +/** Read a 32-bit value from a buffer in big endian. Does not increment buffer + * pointer. + * \note Only works properly if ptr is an (unsigned char *). + * \param ptr buffer + * \param val 32-bit value + */ +#define YASM_LOAD_32_B(val, ptr) \ + do { \ + (val) = (unsigned long)((*(ptr) & 0xFF) << 24); \ + (val) |= (unsigned long)((*((ptr)+1) & 0xFF) << 16); \ + (val) |= (unsigned long)((*((ptr)+2) & 0xFF) << 8); \ + (val) |= (unsigned long)(*((ptr)+3) & 0xFF); \ + } while (0) + +#endif diff --git a/contrib/tools/yasm/libyasm/floatnum.c b/contrib/tools/yasm/libyasm/floatnum.c index ab67c2b2e4..98eabeebcf 100644 --- a/contrib/tools/yasm/libyasm/floatnum.c +++ b/contrib/tools/yasm/libyasm/floatnum.c @@ -1,760 +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"); -} +/* + * Floating point number functions. + * + * Copyright (C) 2001-2007 Peter Johnson + * + * Based on public-domain x86 assembly code by Randall Hyde (8/28/91). + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include "util.h" + +#include <ctype.h> + +#include "coretype.h" +#include "bitvect.h" +#include "file.h" + +#include "errwarn.h" +#include "floatnum.h" + + +/* 97-bit internal floating point format: + * 0000000s eeeeeeee eeeeeeee m.....................................m + * Sign exponent mantissa (80 bits) + * 79 0 + * + * Only L.O. bit of Sign byte is significant. The rest is zero. + * Exponent is bias 32767. + * Mantissa does NOT have an implied one bit (it's explicit). + */ +struct yasm_floatnum { + /*@only@*/ wordptr mantissa; /* Allocated to MANT_BITS bits */ + unsigned short exponent; + unsigned char sign; + unsigned char flags; +}; + +/* constants describing parameters of internal floating point format */ +#define MANT_BITS 80 +#define MANT_BYTES 10 +#define MANT_SIGDIGITS 24 +#define EXP_BIAS 0x7FFF +#define EXP_INF 0xFFFF +#define EXP_MAX 0xFFFE +#define EXP_MIN 1 +#define EXP_ZERO 0 + +/* Flag settings for flags field */ +#define FLAG_ISZERO 1<<0 + +/* Note this structure integrates the floatnum structure */ +typedef struct POT_Entry_s { + yasm_floatnum f; + int dec_exponent; +} POT_Entry; + +/* "Source" for POT_Entry. */ +typedef struct POT_Entry_Source_s { + unsigned char mantissa[MANT_BYTES]; /* little endian mantissa */ + unsigned short exponent; /* Bias 32767 exponent */ +} POT_Entry_Source; + +/* Power of ten tables used by the floating point I/O routines. + * The POT_Table? arrays are built from the POT_Table?_Source arrays at + * runtime by POT_Table_Init(). + */ + +/* This table contains the powers of ten raised to negative powers of two: + * + * entry[12-n] = 10 ** (-2 ** n) for 0 <= n <= 12. + * entry[13] = 1.0 + */ +static /*@only@*/ POT_Entry *POT_TableN; +static POT_Entry_Source POT_TableN_Source[] = { + {{0xe3,0x2d,0xde,0x9f,0xce,0xd2,0xc8,0x04,0xdd,0xa6},0x4ad8}, /* 1e-4096 */ + {{0x25,0x49,0xe4,0x2d,0x36,0x34,0x4f,0x53,0xae,0xce},0x656b}, /* 1e-2048 */ + {{0xa6,0x87,0xbd,0xc0,0x57,0xda,0xa5,0x82,0xa6,0xa2},0x72b5}, /* 1e-1024 */ + {{0x33,0x71,0x1c,0xd2,0x23,0xdb,0x32,0xee,0x49,0x90},0x795a}, /* 1e-512 */ + {{0x91,0xfa,0x39,0x19,0x7a,0x63,0x25,0x43,0x31,0xc0},0x7cac}, /* 1e-256 */ + {{0x7d,0xac,0xa0,0xe4,0xbc,0x64,0x7c,0x46,0xd0,0xdd},0x7e55}, /* 1e-128 */ + {{0x24,0x3f,0xa5,0xe9,0x39,0xa5,0x27,0xea,0x7f,0xa8},0x7f2a}, /* 1e-64 */ + {{0xde,0x67,0xba,0x94,0x39,0x45,0xad,0x1e,0xb1,0xcf},0x7f94}, /* 1e-32 */ + {{0x2f,0x4c,0x5b,0xe1,0x4d,0xc4,0xbe,0x94,0x95,0xe6},0x7fc9}, /* 1e-16 */ + {{0xc2,0xfd,0xfc,0xce,0x61,0x84,0x11,0x77,0xcc,0xab},0x7fe4}, /* 1e-8 */ + {{0xc3,0xd3,0x2b,0x65,0x19,0xe2,0x58,0x17,0xb7,0xd1},0x7ff1}, /* 1e-4 */ + {{0x71,0x3d,0x0a,0xd7,0xa3,0x70,0x3d,0x0a,0xd7,0xa3},0x7ff8}, /* 1e-2 */ + {{0xcd,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc},0x7ffb}, /* 1e-1 */ + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80},0x7fff}, /* 1e-0 */ +}; + +/* This table contains the powers of ten raised to positive powers of two: + * + * entry[12-n] = 10 ** (2 ** n) for 0 <= n <= 12. + * entry[13] = 1.0 + * entry[-1] = entry[0]; + * + * There is a -1 entry since it is possible for the algorithm to back up + * before the table. This -1 entry is created at runtime by duplicating the + * 0 entry. + */ +static /*@only@*/ POT_Entry *POT_TableP; +static POT_Entry_Source POT_TableP_Source[] = { + {{0x4c,0xc9,0x9a,0x97,0x20,0x8a,0x02,0x52,0x60,0xc4},0xb525}, /* 1e+4096 */ + {{0x4d,0xa7,0xe4,0x5d,0x3d,0xc5,0x5d,0x3b,0x8b,0x9e},0x9a92}, /* 1e+2048 */ + {{0x0d,0x65,0x17,0x0c,0x75,0x81,0x86,0x75,0x76,0xc9},0x8d48}, /* 1e+1024 */ + {{0x65,0xcc,0xc6,0x91,0x0e,0xa6,0xae,0xa0,0x19,0xe3},0x86a3}, /* 1e+512 */ + {{0xbc,0xdd,0x8d,0xde,0xf9,0x9d,0xfb,0xeb,0x7e,0xaa},0x8351}, /* 1e+256 */ + {{0x6f,0xc6,0xdf,0x8c,0xe9,0x80,0xc9,0x47,0xba,0x93},0x81a8}, /* 1e+128 */ + {{0xbf,0x3c,0xd5,0xa6,0xcf,0xff,0x49,0x1f,0x78,0xc2},0x80d3}, /* 1e+64 */ + {{0x20,0xf0,0x9d,0xb5,0x70,0x2b,0xa8,0xad,0xc5,0x9d},0x8069}, /* 1e+32 */ + {{0x00,0x00,0x00,0x00,0x00,0x04,0xbf,0xc9,0x1b,0x8e},0x8034}, /* 1e+16 */ + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0xbc,0xbe},0x8019}, /* 1e+8 */ + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x9c},0x800c}, /* 1e+4 */ + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc8},0x8005}, /* 1e+2 */ + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0},0x8002}, /* 1e+1 */ + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80},0x7fff}, /* 1e+0 */ +}; + + +static void +POT_Table_Init_Entry(/*@out@*/ POT_Entry *e, POT_Entry_Source *s, int dec_exp) +{ + /* Save decimal exponent */ + e->dec_exponent = dec_exp; + + /* Initialize mantissa */ + e->f.mantissa = BitVector_Create(MANT_BITS, FALSE); + BitVector_Block_Store(e->f.mantissa, s->mantissa, MANT_BYTES); + + /* Initialize exponent */ + e->f.exponent = s->exponent; + + /* Set sign to 0 (positive) */ + e->f.sign = 0; + + /* Clear flags */ + e->f.flags = 0; +} + +/*@-compdef@*/ +void +yasm_floatnum_initialize(void) +/*@globals undef POT_TableN, undef POT_TableP, POT_TableP_Source, + POT_TableN_Source @*/ +{ + int dec_exp = 1; + int i; + + /* Allocate space for two POT tables */ + POT_TableN = yasm_xmalloc(14*sizeof(POT_Entry)); + POT_TableP = yasm_xmalloc(15*sizeof(POT_Entry)); /* note 1 extra for -1 */ + + /* Initialize entry[0..12] */ + for (i=12; i>=0; i--) { + POT_Table_Init_Entry(&POT_TableN[i], &POT_TableN_Source[i], 0-dec_exp); + POT_Table_Init_Entry(&POT_TableP[i+1], &POT_TableP_Source[i], dec_exp); + dec_exp *= 2; /* Update decimal exponent */ + } + + /* Initialize entry[13] */ + POT_Table_Init_Entry(&POT_TableN[13], &POT_TableN_Source[13], 0); + POT_Table_Init_Entry(&POT_TableP[14], &POT_TableP_Source[13], 0); + + /* Initialize entry[-1] for POT_TableP */ + POT_Table_Init_Entry(&POT_TableP[0], &POT_TableP_Source[0], 4096); + + /* Offset POT_TableP so that [0] becomes [-1] */ + POT_TableP++; +} +/*@=compdef@*/ + +/*@-globstate@*/ +void +yasm_floatnum_cleanup(void) +{ + int i; + + /* Un-offset POT_TableP */ + POT_TableP--; + + for (i=0; i<14; i++) { + BitVector_Destroy(POT_TableN[i].f.mantissa); + BitVector_Destroy(POT_TableP[i].f.mantissa); + } + BitVector_Destroy(POT_TableP[14].f.mantissa); + + yasm_xfree(POT_TableN); + yasm_xfree(POT_TableP); +} +/*@=globstate@*/ + +static void +floatnum_normalize(yasm_floatnum *flt) +{ + long norm_amt; + + if (BitVector_is_empty(flt->mantissa)) { + flt->exponent = 0; + return; + } + + /* Look for the highest set bit, shift to make it the MSB, and adjust + * exponent. Don't let exponent go negative. */ + norm_amt = (MANT_BITS-1)-Set_Max(flt->mantissa); + if (norm_amt > (long)flt->exponent) + norm_amt = (long)flt->exponent; + BitVector_Move_Left(flt->mantissa, (N_int)norm_amt); + flt->exponent -= (unsigned short)norm_amt; +} + +/* acc *= op */ +static void +floatnum_mul(yasm_floatnum *acc, const yasm_floatnum *op) +{ + long expon; + wordptr product, op1, op2; + long norm_amt; + + /* Compute the new sign */ + acc->sign ^= op->sign; + + /* Check for multiply by 0 */ + if (BitVector_is_empty(acc->mantissa) || BitVector_is_empty(op->mantissa)) { + BitVector_Empty(acc->mantissa); + acc->exponent = EXP_ZERO; + return; + } + + /* Add exponents, checking for overflow/underflow. */ + expon = (((int)acc->exponent)-EXP_BIAS) + (((int)op->exponent)-EXP_BIAS); + expon += EXP_BIAS; + if (expon > EXP_MAX) { + /* Overflow; return infinity. */ + BitVector_Empty(acc->mantissa); + acc->exponent = EXP_INF; + return; + } else if (expon < EXP_MIN) { + /* Underflow; return zero. */ + BitVector_Empty(acc->mantissa); + acc->exponent = EXP_ZERO; + return; + } + + /* Add one to the final exponent, as the multiply shifts one extra time. */ + acc->exponent = (unsigned short)(expon+1); + + /* Allocate space for the multiply result */ + product = BitVector_Create((N_int)((MANT_BITS+1)*2), FALSE); + + /* Allocate 1-bit-longer fields to force the operands to be unsigned */ + op1 = BitVector_Create((N_int)(MANT_BITS+1), FALSE); + op2 = BitVector_Create((N_int)(MANT_BITS+1), FALSE); + + /* Make the operands unsigned after copying from original operands */ + BitVector_Copy(op1, acc->mantissa); + BitVector_MSB(op1, 0); + BitVector_Copy(op2, op->mantissa); + BitVector_MSB(op2, 0); + + /* Compute the product of the mantissas */ + BitVector_Multiply(product, op1, op2); + + /* Normalize the product. Note: we know the product is non-zero because + * both of the original operands were non-zero. + * + * Look for the highest set bit, shift to make it the MSB, and adjust + * exponent. Don't let exponent go negative. + */ + norm_amt = (MANT_BITS*2-1)-Set_Max(product); + if (norm_amt > (long)acc->exponent) + norm_amt = (long)acc->exponent; + BitVector_Move_Left(product, (N_int)norm_amt); + acc->exponent -= (unsigned short)norm_amt; + + /* Store the highest bits of the result */ + BitVector_Interval_Copy(acc->mantissa, product, 0, MANT_BITS, MANT_BITS); + + /* Free allocated variables */ + BitVector_Destroy(product); + BitVector_Destroy(op1); + BitVector_Destroy(op2); +} + +yasm_floatnum * +yasm_floatnum_create(const char *str) +{ + yasm_floatnum *flt; + int dec_exponent, dec_exp_add; /* decimal (powers of 10) exponent */ + int POT_index; + wordptr operand[2]; + int sig_digits; + int decimal_pt; + boolean carry; + + flt = yasm_xmalloc(sizeof(yasm_floatnum)); + + flt->mantissa = BitVector_Create(MANT_BITS, TRUE); + + /* allocate and initialize calculation variables */ + operand[0] = BitVector_Create(MANT_BITS, TRUE); + operand[1] = BitVector_Create(MANT_BITS, TRUE); + dec_exponent = 0; + sig_digits = 0; + decimal_pt = 1; + + /* set initial flags to 0 */ + flt->flags = 0; + + /* check for + or - character and skip */ + if (*str == '-') { + flt->sign = 1; + str++; + } else if (*str == '+') { + flt->sign = 0; + str++; + } else + flt->sign = 0; + + /* eliminate any leading zeros (which do not count as significant digits) */ + while (*str == '0') + str++; + + /* When we reach the end of the leading zeros, first check for a decimal + * point. If the number is of the form "0---0.0000" we need to get rid + * of the zeros after the decimal point and not count them as significant + * digits. + */ + if (*str == '.') { + str++; + while (*str == '0') { + str++; + dec_exponent--; + } + } else { + /* The number is of the form "yyy.xxxx" (where y <> 0). */ + while (isdigit(*str)) { + /* See if we've processed more than the max significant digits: */ + if (sig_digits < MANT_SIGDIGITS) { + /* Multiply mantissa by 10 [x = (x<<1)+(x<<3)] */ + BitVector_shift_left(flt->mantissa, 0); + BitVector_Copy(operand[0], flt->mantissa); + BitVector_Move_Left(flt->mantissa, 2); + carry = 0; + BitVector_add(operand[1], operand[0], flt->mantissa, &carry); + + /* Add in current digit */ + BitVector_Empty(operand[0]); + BitVector_Chunk_Store(operand[0], 4, 0, (N_long)(*str-'0')); + carry = 0; + BitVector_add(flt->mantissa, operand[1], operand[0], &carry); + } else { + /* Can't integrate more digits with mantissa, so instead just + * raise by a power of ten. + */ + dec_exponent++; + } + sig_digits++; + str++; + } + + if (*str == '.') + str++; + else + decimal_pt = 0; + } + + if (decimal_pt) { + /* Process the digits to the right of the decimal point. */ + while (isdigit(*str)) { + /* See if we've processed more than 19 significant digits: */ + if (sig_digits < 19) { + /* Raise by a power of ten */ + dec_exponent--; + + /* Multiply mantissa by 10 [x = (x<<1)+(x<<3)] */ + BitVector_shift_left(flt->mantissa, 0); + BitVector_Copy(operand[0], flt->mantissa); + BitVector_Move_Left(flt->mantissa, 2); + carry = 0; + BitVector_add(operand[1], operand[0], flt->mantissa, &carry); + + /* Add in current digit */ + BitVector_Empty(operand[0]); + BitVector_Chunk_Store(operand[0], 4, 0, (N_long)(*str-'0')); + carry = 0; + BitVector_add(flt->mantissa, operand[1], operand[0], &carry); + } + sig_digits++; + str++; + } + } + + if (*str == 'e' || *str == 'E') { + str++; + /* We just saw the "E" character, now read in the exponent value and + * add it into dec_exponent. + */ + dec_exp_add = 0; + sscanf(str, "%d", &dec_exp_add); + dec_exponent += dec_exp_add; + } + + /* Free calculation variables. */ + BitVector_Destroy(operand[1]); + BitVector_Destroy(operand[0]); + + /* Normalize the number, checking for 0 first. */ + if (BitVector_is_empty(flt->mantissa)) { + /* Mantissa is 0, zero exponent too. */ + flt->exponent = 0; + /* Set zero flag so output functions don't see 0 value as underflow. */ + flt->flags |= FLAG_ISZERO; + /* Return 0 value. */ + return flt; + } + /* Exponent if already norm. */ + flt->exponent = (unsigned short)(0x7FFF+(MANT_BITS-1)); + floatnum_normalize(flt); + + /* The number is normalized. Now multiply by 10 the number of times + * specified in DecExponent. This uses the power of ten tables to speed + * up this operation (and make it more accurate). + */ + if (dec_exponent > 0) { + POT_index = 0; + /* Until we hit 1.0 or finish exponent or overflow */ + while ((POT_index < 14) && (dec_exponent != 0) && + (flt->exponent != EXP_INF)) { + /* Find the first power of ten in the table which is just less than + * the exponent. + */ + while (dec_exponent < POT_TableP[POT_index].dec_exponent) + POT_index++; + + if (POT_index < 14) { + /* Subtract out what we're multiplying in from exponent */ + dec_exponent -= POT_TableP[POT_index].dec_exponent; + + /* Multiply by current power of 10 */ + floatnum_mul(flt, &POT_TableP[POT_index].f); + } + } + } else if (dec_exponent < 0) { + POT_index = 0; + /* Until we hit 1.0 or finish exponent or underflow */ + while ((POT_index < 14) && (dec_exponent != 0) && + (flt->exponent != EXP_ZERO)) { + /* Find the first power of ten in the table which is just less than + * the exponent. + */ + while (dec_exponent > POT_TableN[POT_index].dec_exponent) + POT_index++; + + if (POT_index < 14) { + /* Subtract out what we're multiplying in from exponent */ + dec_exponent -= POT_TableN[POT_index].dec_exponent; + + /* Multiply by current power of 10 */ + floatnum_mul(flt, &POT_TableN[POT_index].f); + } + } + } + + /* Round the result. (Don't round underflow or overflow). Also don't + * increment if this would cause the mantissa to wrap. + */ + if ((flt->exponent != EXP_INF) && (flt->exponent != EXP_ZERO) && + !BitVector_is_full(flt->mantissa)) + BitVector_increment(flt->mantissa); + + return flt; +} + +yasm_floatnum * +yasm_floatnum_copy(const yasm_floatnum *flt) +{ + yasm_floatnum *f = yasm_xmalloc(sizeof(yasm_floatnum)); + + f->mantissa = BitVector_Clone(flt->mantissa); + f->exponent = flt->exponent; + f->sign = flt->sign; + f->flags = flt->flags; + + return f; +} + +void +yasm_floatnum_destroy(yasm_floatnum *flt) +{ + BitVector_Destroy(flt->mantissa); + yasm_xfree(flt); +} + +int +yasm_floatnum_calc(yasm_floatnum *acc, yasm_expr_op op, + /*@unused@*/ yasm_floatnum *operand) +{ + if (op != YASM_EXPR_NEG) { + yasm_error_set(YASM_ERROR_FLOATING_POINT, + N_("Unsupported floating-point arithmetic operation")); + return 1; + } + acc->sign ^= 1; + return 0; +} + +int +yasm_floatnum_get_int(const yasm_floatnum *flt, unsigned long *ret_val) +{ + unsigned char t[4]; + + if (yasm_floatnum_get_sized(flt, t, 4, 32, 0, 0, 0)) { + *ret_val = 0xDEADBEEFUL; /* Obviously incorrect return value */ + return 1; + } + + YASM_LOAD_32_L(*ret_val, &t[0]); + return 0; +} + +/* Function used by conversion routines to actually perform the conversion. + * + * ptr -> the array to return the little-endian floating point value into. + * flt -> the floating point value to convert. + * byte_size -> the size in bytes of the output format. + * mant_bits -> the size in bits of the output mantissa. + * implicit1 -> does the output format have an implicit 1? 1=yes, 0=no. + * exp_bits -> the size in bits of the output exponent. + * + * Returns 0 on success, 1 if overflow, -1 if underflow. + */ +static int +floatnum_get_common(const yasm_floatnum *flt, /*@out@*/ unsigned char *ptr, + N_int byte_size, N_int mant_bits, int implicit1, + N_int exp_bits) +{ + long exponent = (long)flt->exponent; + wordptr output; + charptr buf; + unsigned int len; + unsigned int overflow = 0, underflow = 0; + int retval = 0; + long exp_bias = (1<<(exp_bits-1))-1; + long exp_inf = (1<<exp_bits)-1; + + output = BitVector_Create(byte_size*8, TRUE); + + /* copy mantissa */ + BitVector_Interval_Copy(output, flt->mantissa, 0, + (N_int)((MANT_BITS-implicit1)-mant_bits), + mant_bits); + + /* round mantissa */ + if (BitVector_bit_test(flt->mantissa, (MANT_BITS-implicit1)-(mant_bits+1))) + BitVector_increment(output); + + if (BitVector_bit_test(output, mant_bits)) { + /* overflowed, so zero mantissa (and set explicit bit if necessary) */ + BitVector_Empty(output); + BitVector_Bit_Copy(output, mant_bits-1, !implicit1); + /* and up the exponent (checking for overflow) */ + if (exponent+1 >= EXP_INF) + overflow = 1; + else + exponent++; + } + + /* adjust the exponent to the output bias, checking for overflow */ + exponent -= EXP_BIAS-exp_bias; + if (exponent >= exp_inf) + overflow = 1; + else if (exponent <= 0) + underflow = 1; + + /* underflow and overflow both set!? */ + if (underflow && overflow) + yasm_internal_error(N_("Both underflow and overflow set")); + + /* check for underflow or overflow and set up appropriate output */ + if (underflow) { + BitVector_Empty(output); + exponent = 0; + if (!(flt->flags & FLAG_ISZERO)) + retval = -1; + } else if (overflow) { + BitVector_Empty(output); + exponent = exp_inf; + retval = 1; + } + + /* move exponent into place */ + BitVector_Chunk_Store(output, exp_bits, mant_bits, (N_long)exponent); + + /* merge in sign bit */ + BitVector_Bit_Copy(output, byte_size*8-1, flt->sign); + + /* get little-endian bytes */ + buf = BitVector_Block_Read(output, &len); + if (len < byte_size) + yasm_internal_error( + N_("Byte length of BitVector does not match bit length")); + + /* copy to output */ + memcpy(ptr, buf, byte_size*sizeof(unsigned char)); + + /* free allocated resources */ + yasm_xfree(buf); + + BitVector_Destroy(output); + + return retval; +} + +/* IEEE-754r "half precision" format: + * 16 bits: + * 15 9 Bit 0 + * | | | + * seee eemm mmmm mmmm + * + * e = bias 15 exponent + * s = sign bit + * m = mantissa bits, bit 10 is an implied one bit. + * + * IEEE-754 (Intel) "single precision" format: + * 32 bits: + * Bit 31 Bit 22 Bit 0 + * | | | + * seeeeeee emmmmmmm mmmmmmmm mmmmmmmm + * + * e = bias 127 exponent + * s = sign bit + * m = mantissa bits, bit 23 is an implied one bit. + * + * IEEE-754 (Intel) "double precision" format: + * 64 bits: + * bit 63 bit 51 bit 0 + * | | | + * seeeeeee eeeemmmm mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm + * + * e = bias 1023 exponent. + * s = sign bit. + * m = mantissa bits. Bit 52 is an implied one bit. + * + * IEEE-754 (Intel) "extended precision" format: + * 80 bits: + * bit 79 bit 63 bit 0 + * | | | + * seeeeeee eeeeeeee mmmmmmmm m...m m...m m...m m...m m...m + * + * e = bias 16383 exponent + * m = 64 bit mantissa with NO implied bit! + * s = sign (for mantissa) + */ +int +yasm_floatnum_get_sized(const yasm_floatnum *flt, unsigned char *ptr, + size_t destsize, size_t valsize, size_t shift, + int bigendian, int warn) +{ + int retval; + if (destsize*8 != valsize || shift>0 || bigendian) { + /* TODO */ + yasm_internal_error(N_("unsupported floatnum functionality")); + } + switch (destsize) { + case 2: + retval = floatnum_get_common(flt, ptr, 2, 10, 1, 5); + break; + case 4: + retval = floatnum_get_common(flt, ptr, 4, 23, 1, 8); + break; + case 8: + retval = floatnum_get_common(flt, ptr, 8, 52, 1, 11); + break; + case 10: + retval = floatnum_get_common(flt, ptr, 10, 64, 0, 15); + break; + default: + yasm_internal_error(N_("Invalid float conversion size")); + /*@notreached@*/ + return 1; + } + if (warn) { + if (retval < 0) + yasm_warn_set(YASM_WARN_GENERAL, + N_("underflow in floating point expression")); + else if (retval > 0) + yasm_warn_set(YASM_WARN_GENERAL, + N_("overflow in floating point expression")); + } + return retval; +} + +/* 1 if the size is valid, 0 if it isn't */ +int +yasm_floatnum_check_size(/*@unused@*/ const yasm_floatnum *flt, size_t size) +{ + switch (size) { + case 16: + case 32: + case 64: + case 80: + return 1; + default: + return 0; + } +} + +void +yasm_floatnum_print(const yasm_floatnum *flt, FILE *f) +{ + unsigned char out[10]; + unsigned char *str; + int i; + + /* Internal format */ + str = BitVector_to_Hex(flt->mantissa); + fprintf(f, "%c %s *2^%04x\n", flt->sign?'-':'+', (char *)str, + flt->exponent); + yasm_xfree(str); + + /* 32-bit (single precision) format */ + fprintf(f, "32-bit: %d: ", + yasm_floatnum_get_sized(flt, out, 4, 32, 0, 0, 0)); + for (i=0; i<4; i++) + fprintf(f, "%02x ", out[i]); + fprintf(f, "\n"); + + /* 64-bit (double precision) format */ + fprintf(f, "64-bit: %d: ", + yasm_floatnum_get_sized(flt, out, 8, 64, 0, 0, 0)); + for (i=0; i<8; i++) + fprintf(f, "%02x ", out[i]); + fprintf(f, "\n"); + + /* 80-bit (extended precision) format */ + fprintf(f, "80-bit: %d: ", + yasm_floatnum_get_sized(flt, out, 10, 80, 0, 0, 0)); + for (i=0; i<10; i++) + fprintf(f, "%02x ", out[i]); + fprintf(f, "\n"); +} diff --git a/contrib/tools/yasm/libyasm/floatnum.h b/contrib/tools/yasm/libyasm/floatnum.h index d2c7042097..78739519c4 100644 --- a/contrib/tools/yasm/libyasm/floatnum.h +++ b/contrib/tools/yasm/libyasm/floatnum.h @@ -1,131 +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 +/** + * \file libyasm/floatnum.h + * \brief YASM floating point (IEEE) interface. + * + * \license + * Copyright (C) 2001-2007 Peter Johnson + * + * Based on public-domain x86 assembly code by Randall Hyde (8/28/91). + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * \endlicense + */ +#ifndef YASM_FLOATNUM_H +#define YASM_FLOATNUM_H + +#ifndef YASM_LIB_DECL +#define YASM_LIB_DECL +#endif + +/** Initialize floatnum internal data structures. */ +YASM_LIB_DECL +void yasm_floatnum_initialize(void); + +/** Clean up internal floatnum allocations. */ +YASM_LIB_DECL +void yasm_floatnum_cleanup(void); + +/** Create a new floatnum from a decimal string. The input string must be in + * standard C representation ([+-]123.456e[-+]789). + * \param str floating point decimal string + * \return Newly allocated floatnum. + */ +YASM_LIB_DECL +/*@only@*/ yasm_floatnum *yasm_floatnum_create(const char *str); + +/** Duplicate a floatnum. + * \param flt floatnum + * \return Newly allocated floatnum with the same value as flt. + */ +YASM_LIB_DECL +/*@only@*/ yasm_floatnum *yasm_floatnum_copy(const yasm_floatnum *flt); + +/** Destroy (free allocated memory for) a floatnum. + * \param flt floatnum + */ +YASM_LIB_DECL +void yasm_floatnum_destroy(/*@only@*/ yasm_floatnum *flt); + +/** Floating point calculation function: acc = acc op operand. + * \note Not all operations in yasm_expr_op may be supported; unsupported + * operations will result in an error. + * \param acc floatnum accumulator + * \param op operation + * \param operand floatnum operand + * \return Nonzero on error. + */ +YASM_LIB_DECL +int yasm_floatnum_calc(yasm_floatnum *acc, yasm_expr_op op, + yasm_floatnum *operand); + +/** Convert a floatnum to single-precision and return as 32-bit value. + * The 32-bit value is a "standard" C value (eg, of unknown endian). + * \param flt floatnum + * \param ret_val pointer to storage for 32-bit output + * \return Nonzero if flt can't fit into single precision: -1 if underflow + * occurred, 1 if overflow occurred. + */ +YASM_LIB_DECL +int yasm_floatnum_get_int(const yasm_floatnum *flt, + /*@out@*/ unsigned long *ret_val); + +/** Output a #yasm_floatnum to buffer in little-endian or big-endian. Puts the + * value into the least significant bits of the destination, or may be shifted + * into more significant bits by the shift parameter. The destination bits are + * cleared before being set. [0] should be the first byte output to the file. + * \note Not all sizes are valid. Currently, only 32 (single-precision), 64 + * (double-precision), and 80 (extended-precision) are valid sizes. + * Use yasm_floatnum_check_size() to check for supported sizes. + * \param flt floatnum + * \param ptr pointer to storage for size bytes of output + * \param destsize destination size (in bytes) + * \param valsize size (in bits) + * \param shift left shift (in bits) + * \param bigendian endianness (nonzero=big, zero=little) + * \param warn enables standard overflow/underflow warnings + * \return Nonzero if flt can't fit into the specified precision: -1 if + * underflow occurred, 1 if overflow occurred. + */ +YASM_LIB_DECL +int yasm_floatnum_get_sized(const yasm_floatnum *flt, unsigned char *ptr, + size_t destsize, size_t valsize, size_t shift, + int bigendian, int warn); + +/** Basic check to see if size is valid for flt conversion (using + * yasm_floatnum_get_sized()). Doesn't actually check for underflow/overflow + * but rather checks for size=32,64,80 + * (at present). + * \param flt floatnum + * \param size number of bits of output space + * \return 1 if valid size, 0 if invalid size. + */ +YASM_LIB_DECL +int yasm_floatnum_check_size(const yasm_floatnum *flt, size_t size); + +/** Print various representations of a floatnum. For debugging purposes only. + * \param f file + * \param flt floatnum + */ +YASM_LIB_DECL +void yasm_floatnum_print(const yasm_floatnum *flt, FILE *f); + +#endif diff --git a/contrib/tools/yasm/libyasm/genmodule.c b/contrib/tools/yasm/libyasm/genmodule.c index 867d93a5b2..7ada3504c6 100644 --- a/contrib/tools/yasm/libyasm/genmodule.c +++ b/contrib/tools/yasm/libyasm/genmodule.c @@ -1,228 +1,228 @@ -/* - * - * Generate module.c from module.in and Makefile.am or Makefile. - * - * Copyright (C) 2004-2007 Peter Johnson - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <ctype.h> - -#include "compat-queue.h" - -#define OUTPUT "module.c" -#define MAXNAME 128 -#define MAXLINE 1024 -#define MAXMODULES 128 -#define MAXINCLUDES 256 - -typedef struct include { - STAILQ_ENTRY(include) link; - char *filename; -} include; - -int -main(int argc, char *argv[]) -{ - FILE *in, *out; - char *str; - int i; - size_t len; - char *strp; - char *modules[MAXMODULES]; - int num_modules = 0; - STAILQ_HEAD(includehead, include) includes = - STAILQ_HEAD_INITIALIZER(includes); - include *inc; - int isam = 0; - int linecont = 0; - - if (argc != 3) { - fprintf(stderr, "Usage: %s <module.in> <Makefile[.am]>\n", argv[0]); - return EXIT_FAILURE; - } - - str = malloc(MAXLINE); - - /* Starting with initial input Makefile, look for include <file> or - * YASM_MODULES += <module>. Note this currently doesn't handle - * a relative starting path. - */ - len = strlen(argv[2]); - inc = malloc(sizeof(include)); - inc->filename = malloc(len+1); - strcpy(inc->filename, argv[2]); - STAILQ_INSERT_TAIL(&includes, inc, link); - - isam = argv[2][len-2] == 'a' && argv[2][len-1] == 'm'; - - while (!STAILQ_EMPTY(&includes)) { - inc = STAILQ_FIRST(&includes); - STAILQ_REMOVE_HEAD(&includes, link); - in = fopen(inc->filename, "rt"); - if (!in) { - fprintf(stderr, "Could not open `%s'.\n", inc->filename); - return EXIT_FAILURE; - } - free(inc->filename); - free(inc); - - while (fgets(str, MAXLINE, in)) { - /* Strip off any trailing whitespace */ - len = strlen(str); - if (len > 0) { - strp = &str[len-1]; - while (len > 0 && isspace(*strp)) { - *strp-- = '\0'; - len--; - } - } - - strp = str; - - /* Skip whitespace */ - while (isspace(*strp)) - strp++; - - /* Skip comments */ - if (*strp == '#') - continue; - - /* If line continuation, skip to continue copy */ - if (linecont) - goto keepgoing; - - /* Check for include if original input is .am file */ - if (isam && strncmp(strp, "include", 7) == 0 && isspace(strp[7])) { - strp += 7; - while (isspace(*strp)) - strp++; - /* Build new include and add to end of list */ - inc = malloc(sizeof(include)); - inc->filename = malloc(strlen(strp)+1); - strcpy(inc->filename, strp); - STAILQ_INSERT_TAIL(&includes, inc, link); - continue; - } - - /* Check for YASM_MODULES = or += */ - if (strncmp(strp, "YASM_MODULES", 12) != 0) - continue; - strp += 12; - while (isspace(*strp)) - strp++; - if (strncmp(strp, "+=", 2) != 0 && *strp != '=') - continue; - if (*strp == '+') - strp++; - strp++; - while (isspace(*strp)) - strp++; - -keepgoing: - /* Check for continuation */ - if (len > 0 && str[len-1] == '\\') { - str[len-1] = '\0'; - while (isspace(*strp)) - *strp-- = '\0'; - linecont = 1; - } else - linecont = 0; - - while (*strp != '\0') { - /* Copy module name */ - modules[num_modules] = malloc(MAXNAME); - len = 0; - while (*strp != '\0' && !isspace(*strp)) - modules[num_modules][len++] = *strp++; - modules[num_modules][len] = '\0'; - num_modules++; - - while (isspace(*strp)) - strp++; - } - } - fclose(in); - } - - out = fopen(OUTPUT, "wt"); - - if (!out) { - fprintf(stderr, "Could not open `%s'.\n", OUTPUT); - return EXIT_FAILURE; - } - - fprintf(out, "/* This file auto-generated by genmodule.c" - " - don't edit it */\n\n"); - - in = fopen(argv[1], "rt"); - if (!in) { - fprintf(stderr, "Could not open `%s'.\n", argv[1]); - fclose(out); - remove(OUTPUT); - return EXIT_FAILURE; - } - - len = 0; - while (fgets(str, MAXLINE, in)) { - if (strncmp(str, "MODULES_", 8) == 0) { - len = 0; - strp = str+8; - while (*strp != '\0' && *strp != '_') { - len++; - strp++; - } - *strp = '\0'; - - for (i=0; i<num_modules; i++) { - if (strncmp(modules[i], str+8, len) == 0) { - fprintf(out, " {\"%s\", &yasm_%s_LTX_%s},\n", - modules[i]+len+1, modules[i]+len+1, str+8); - } - } - } else if (strncmp(str, "EXTERN_LIST", 11) == 0) { - for (i=0; i<num_modules; i++) { - strcpy(str, modules[i]); - strp = str; - while (*strp != '\0' && *strp != '_') - strp++; - *strp++ = '\0'; - - fprintf(out, "extern yasm_%s_module yasm_%s_LTX_%s;\n", - str, strp, str); - } - } else - fputs(str, out); - } - - fclose(in); - fclose(out); - - for (i=0; i<num_modules; i++) - free(modules[i]); - free(str); - - return EXIT_SUCCESS; -} +/* + * + * Generate module.c from module.in and Makefile.am or Makefile. + * + * Copyright (C) 2004-2007 Peter Johnson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> + +#include "compat-queue.h" + +#define OUTPUT "module.c" +#define MAXNAME 128 +#define MAXLINE 1024 +#define MAXMODULES 128 +#define MAXINCLUDES 256 + +typedef struct include { + STAILQ_ENTRY(include) link; + char *filename; +} include; + +int +main(int argc, char *argv[]) +{ + FILE *in, *out; + char *str; + int i; + size_t len; + char *strp; + char *modules[MAXMODULES]; + int num_modules = 0; + STAILQ_HEAD(includehead, include) includes = + STAILQ_HEAD_INITIALIZER(includes); + include *inc; + int isam = 0; + int linecont = 0; + + if (argc != 3) { + fprintf(stderr, "Usage: %s <module.in> <Makefile[.am]>\n", argv[0]); + return EXIT_FAILURE; + } + + str = malloc(MAXLINE); + + /* Starting with initial input Makefile, look for include <file> or + * YASM_MODULES += <module>. Note this currently doesn't handle + * a relative starting path. + */ + len = strlen(argv[2]); + inc = malloc(sizeof(include)); + inc->filename = malloc(len+1); + strcpy(inc->filename, argv[2]); + STAILQ_INSERT_TAIL(&includes, inc, link); + + isam = argv[2][len-2] == 'a' && argv[2][len-1] == 'm'; + + while (!STAILQ_EMPTY(&includes)) { + inc = STAILQ_FIRST(&includes); + STAILQ_REMOVE_HEAD(&includes, link); + in = fopen(inc->filename, "rt"); + if (!in) { + fprintf(stderr, "Could not open `%s'.\n", inc->filename); + return EXIT_FAILURE; + } + free(inc->filename); + free(inc); + + while (fgets(str, MAXLINE, in)) { + /* Strip off any trailing whitespace */ + len = strlen(str); + if (len > 0) { + strp = &str[len-1]; + while (len > 0 && isspace(*strp)) { + *strp-- = '\0'; + len--; + } + } + + strp = str; + + /* Skip whitespace */ + while (isspace(*strp)) + strp++; + + /* Skip comments */ + if (*strp == '#') + continue; + + /* If line continuation, skip to continue copy */ + if (linecont) + goto keepgoing; + + /* Check for include if original input is .am file */ + if (isam && strncmp(strp, "include", 7) == 0 && isspace(strp[7])) { + strp += 7; + while (isspace(*strp)) + strp++; + /* Build new include and add to end of list */ + inc = malloc(sizeof(include)); + inc->filename = malloc(strlen(strp)+1); + strcpy(inc->filename, strp); + STAILQ_INSERT_TAIL(&includes, inc, link); + continue; + } + + /* Check for YASM_MODULES = or += */ + if (strncmp(strp, "YASM_MODULES", 12) != 0) + continue; + strp += 12; + while (isspace(*strp)) + strp++; + if (strncmp(strp, "+=", 2) != 0 && *strp != '=') + continue; + if (*strp == '+') + strp++; + strp++; + while (isspace(*strp)) + strp++; + +keepgoing: + /* Check for continuation */ + if (len > 0 && str[len-1] == '\\') { + str[len-1] = '\0'; + while (isspace(*strp)) + *strp-- = '\0'; + linecont = 1; + } else + linecont = 0; + + while (*strp != '\0') { + /* Copy module name */ + modules[num_modules] = malloc(MAXNAME); + len = 0; + while (*strp != '\0' && !isspace(*strp)) + modules[num_modules][len++] = *strp++; + modules[num_modules][len] = '\0'; + num_modules++; + + while (isspace(*strp)) + strp++; + } + } + fclose(in); + } + + out = fopen(OUTPUT, "wt"); + + if (!out) { + fprintf(stderr, "Could not open `%s'.\n", OUTPUT); + return EXIT_FAILURE; + } + + fprintf(out, "/* This file auto-generated by genmodule.c" + " - don't edit it */\n\n"); + + in = fopen(argv[1], "rt"); + if (!in) { + fprintf(stderr, "Could not open `%s'.\n", argv[1]); + fclose(out); + remove(OUTPUT); + return EXIT_FAILURE; + } + + len = 0; + while (fgets(str, MAXLINE, in)) { + if (strncmp(str, "MODULES_", 8) == 0) { + len = 0; + strp = str+8; + while (*strp != '\0' && *strp != '_') { + len++; + strp++; + } + *strp = '\0'; + + for (i=0; i<num_modules; i++) { + if (strncmp(modules[i], str+8, len) == 0) { + fprintf(out, " {\"%s\", &yasm_%s_LTX_%s},\n", + modules[i]+len+1, modules[i]+len+1, str+8); + } + } + } else if (strncmp(str, "EXTERN_LIST", 11) == 0) { + for (i=0; i<num_modules; i++) { + strcpy(str, modules[i]); + strp = str; + while (*strp != '\0' && *strp != '_') + strp++; + *strp++ = '\0'; + + fprintf(out, "extern yasm_%s_module yasm_%s_LTX_%s;\n", + str, strp, str); + } + } else + fputs(str, out); + } + + fclose(in); + fclose(out); + + for (i=0; i<num_modules; i++) + free(modules[i]); + free(str); + + return EXIT_SUCCESS; +} diff --git a/contrib/tools/yasm/libyasm/hamt.c b/contrib/tools/yasm/libyasm/hamt.c index 59b7592109..d5f3f05f2b 100644 --- a/contrib/tools/yasm/libyasm/hamt.c +++ b/contrib/tools/yasm/libyasm/hamt.c @@ -1,421 +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]; - } -} - +/* + * Hash Array Mapped Trie (HAMT) implementation + * + * Copyright (C) 2001-2007 Peter Johnson + * + * Based on the paper "Ideal Hash Tries" by Phil Bagwell [2000]. + * One algorithmic change from that described in the paper: we use the LSB's + * of the key to index the root table and move upward in the key rather than + * use the MSBs as described in the paper. The LSBs have more entropy. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include "util.h" + +#include <ctype.h> + +#include "libyasm-stdint.h" +#include "coretype.h" +#include "hamt.h" + +struct HAMTEntry { + STAILQ_ENTRY(HAMTEntry) next; /* next hash table entry */ + /*@dependent@*/ const char *str; /* string being hashed */ + /*@owned@*/ void *data; /* data pointer being stored */ +}; + +typedef struct HAMTNode { + unsigned long BitMapKey; /* 32 bits, bitmap or hash key */ + uintptr_t BaseValue; /* Base of HAMTNode list or value */ +} HAMTNode; + +struct HAMT { + STAILQ_HEAD(HAMTEntryHead, HAMTEntry) entries; + HAMTNode *root; + /*@exits@*/ void (*error_func) (const char *file, unsigned int line, + const char *message); + unsigned long (*HashKey) (const char *key); + unsigned long (*ReHashKey) (const char *key, int Level); + int (*CmpKey) (const char *s1, const char *s2); +}; + +/* XXX make a portable version of this. This depends on the pointer being + * 4 or 2-byte aligned (as it uses the LSB of the pointer variable to store + * the subtrie flag! + */ +#define IsSubTrie(n) ((n)->BaseValue & 1) +#define SetSubTrie(h, n, v) do { \ + if ((uintptr_t)(v) & 1) \ + h->error_func(__FILE__, __LINE__, \ + N_("Subtrie is seen as subtrie before flag is set (misaligned?)")); \ + (n)->BaseValue = (uintptr_t)(v) | 1; \ + } while (0) +#define SetValue(h, n, v) do { \ + if ((uintptr_t)(v) & 1) \ + h->error_func(__FILE__, __LINE__, \ + N_("Value is seen as subtrie (misaligned?)")); \ + (n)->BaseValue = (uintptr_t)(v); \ + } while (0) +#define GetSubTrie(n) (HAMTNode *)(((n)->BaseValue | 1) ^ 1) + +static unsigned long +HashKey(const char *key) +{ + unsigned long a=31415, b=27183, vHash; + for (vHash=0; *key; key++, a*=b) + vHash = a*vHash + *key; + return vHash; +} + +static unsigned long +ReHashKey(const char *key, int Level) +{ + unsigned long a=31415, b=27183, vHash; + for (vHash=0; *key; key++, a*=b) + vHash = a*vHash*(unsigned long)Level + *key; + return vHash; +} + +static unsigned long +HashKey_nocase(const char *key) +{ + unsigned long a=31415, b=27183, vHash; + for (vHash=0; *key; key++, a*=b) + vHash = a*vHash + tolower(*key); + return vHash; +} + +static unsigned long +ReHashKey_nocase(const char *key, int Level) +{ + unsigned long a=31415, b=27183, vHash; + for (vHash=0; *key; key++, a*=b) + vHash = a*vHash*(unsigned long)Level + tolower(*key); + return vHash; +} + +HAMT * +HAMT_create(int nocase, /*@exits@*/ void (*error_func) + (const char *file, unsigned int line, const char *message)) +{ + /*@out@*/ HAMT *hamt = yasm_xmalloc(sizeof(HAMT)); + int i; + + STAILQ_INIT(&hamt->entries); + hamt->root = yasm_xmalloc(32*sizeof(HAMTNode)); + + for (i=0; i<32; i++) { + hamt->root[i].BitMapKey = 0; + hamt->root[i].BaseValue = 0; + } + + hamt->error_func = error_func; + if (nocase) { + hamt->HashKey = HashKey_nocase; + hamt->ReHashKey = ReHashKey_nocase; + hamt->CmpKey = yasm__strcasecmp; + } else { + hamt->HashKey = HashKey; + hamt->ReHashKey = ReHashKey; + hamt->CmpKey = strcmp; + } + + return hamt; +} + +static void +HAMT_delete_trie(HAMTNode *node) +{ + if (IsSubTrie(node)) { + unsigned long i, Size; + + /* Count total number of bits in bitmap to determine size */ + BitCount(Size, node->BitMapKey); + Size &= 0x1F; + if (Size == 0) + Size = 32; + + for (i=0; i<Size; i++) + HAMT_delete_trie(&(GetSubTrie(node))[i]); + yasm_xfree(GetSubTrie(node)); + } +} + +void +HAMT_destroy(HAMT *hamt, void (*deletefunc) (/*@only@*/ void *data)) +{ + int i; + + /* delete entries */ + while (!STAILQ_EMPTY(&hamt->entries)) { + HAMTEntry *entry; + entry = STAILQ_FIRST(&hamt->entries); + STAILQ_REMOVE_HEAD(&hamt->entries, next); + deletefunc(entry->data); + yasm_xfree(entry); + } + + /* delete trie */ + for (i=0; i<32; i++) + HAMT_delete_trie(&hamt->root[i]); + + yasm_xfree(hamt->root); + yasm_xfree(hamt); +} + +int +HAMT_traverse(HAMT *hamt, void *d, + int (*func) (/*@dependent@*/ /*@null@*/ void *node, + /*@null@*/ void *d)) +{ + HAMTEntry *entry; + STAILQ_FOREACH(entry, &hamt->entries, next) { + int retval = func(entry->data, d); + if (retval != 0) + return retval; + } + return 0; +} + +const HAMTEntry * +HAMT_first(const HAMT *hamt) +{ + return STAILQ_FIRST(&hamt->entries); +} + +const HAMTEntry * +HAMT_next(const HAMTEntry *prev) +{ + return STAILQ_NEXT(prev, next); +} + +void * +HAMTEntry_get_data(const HAMTEntry *entry) +{ + return entry->data; +} + +/*@-temptrans -kepttrans -mustfree@*/ +void * +HAMT_insert(HAMT *hamt, const char *str, void *data, int *replace, + void (*deletefunc) (/*@only@*/ void *data)) +{ + HAMTNode *node, *newnodes; + HAMTEntry *entry; + unsigned long key, keypart, Map; + int keypartbits = 0; + int level = 0; + + key = hamt->HashKey(str); + keypart = key & 0x1F; + node = &hamt->root[keypart]; + + if (!node->BaseValue) { + node->BitMapKey = key; + entry = yasm_xmalloc(sizeof(HAMTEntry)); + entry->str = str; + entry->data = data; + STAILQ_INSERT_TAIL(&hamt->entries, entry, next); + SetValue(hamt, node, entry); + if (IsSubTrie(node)) + hamt->error_func(__FILE__, __LINE__, + N_("Data is seen as subtrie (misaligned?)")); + *replace = 1; + return data; + } + + for (;;) { + if (!(IsSubTrie(node))) { + if (node->BitMapKey == key + && hamt->CmpKey(((HAMTEntry *)(node->BaseValue))->str, + str) == 0) { + /*@-branchstate@*/ + if (*replace) { + deletefunc(((HAMTEntry *)(node->BaseValue))->data); + ((HAMTEntry *)(node->BaseValue))->str = str; + ((HAMTEntry *)(node->BaseValue))->data = data; + } else + deletefunc(data); + /*@=branchstate@*/ + return ((HAMTEntry *)(node->BaseValue))->data; + } else { + unsigned long key2 = node->BitMapKey; + /* build tree downward until keys differ */ + for (;;) { + unsigned long keypart2; + + /* replace node with subtrie */ + keypartbits += 5; + if (keypartbits > 30) { + /* Exceeded 32 bits: rehash */ + key = hamt->ReHashKey(str, level); + key2 = hamt->ReHashKey( + ((HAMTEntry *)(node->BaseValue))->str, level); + keypartbits = 0; + } + keypart = (key >> keypartbits) & 0x1F; + keypart2 = (key2 >> keypartbits) & 0x1F; + + if (keypart == keypart2) { + /* Still equal, build one-node subtrie and continue + * downward. + */ + newnodes = yasm_xmalloc(sizeof(HAMTNode)); + newnodes[0].BitMapKey = key2; + newnodes[0].BaseValue = node->BaseValue; + node->BitMapKey = 1<<keypart; + SetSubTrie(hamt, node, newnodes); + node = &newnodes[0]; + level++; + } else { + /* partitioned: allocate two-node subtrie */ + newnodes = yasm_xmalloc(2*sizeof(HAMTNode)); + + entry = yasm_xmalloc(sizeof(HAMTEntry)); + entry->str = str; + entry->data = data; + STAILQ_INSERT_TAIL(&hamt->entries, entry, next); + + /* Copy nodes into subtrie based on order */ + if (keypart2 < keypart) { + newnodes[0].BitMapKey = key2; + newnodes[0].BaseValue = node->BaseValue; + newnodes[1].BitMapKey = key; + SetValue(hamt, &newnodes[1], entry); + } else { + newnodes[0].BitMapKey = key; + SetValue(hamt, &newnodes[0], entry); + newnodes[1].BitMapKey = key2; + newnodes[1].BaseValue = node->BaseValue; + } + + /* Set bits in bitmap corresponding to keys */ + node->BitMapKey = (1UL<<keypart) | (1UL<<keypart2); + SetSubTrie(hamt, node, newnodes); + *replace = 1; + return data; + } + } + } + } + + /* Subtrie: look up in bitmap */ + keypartbits += 5; + if (keypartbits > 30) { + /* Exceeded 32 bits of current key: rehash */ + key = hamt->ReHashKey(str, level); + keypartbits = 0; + } + keypart = (key >> keypartbits) & 0x1F; + if (!(node->BitMapKey & (1<<keypart))) { + /* bit is 0 in bitmap -> add node to table */ + unsigned long Size; + + /* set bit to 1 */ + node->BitMapKey |= 1<<keypart; + + /* Count total number of bits in bitmap to determine new size */ + BitCount(Size, node->BitMapKey); + Size &= 0x1F; + if (Size == 0) + Size = 32; + newnodes = yasm_xmalloc(Size*sizeof(HAMTNode)); + + /* Count bits below to find where to insert new node at */ + BitCount(Map, node->BitMapKey & ~((~0UL)<<keypart)); + Map &= 0x1F; /* Clamp to <32 */ + /* Copy existing nodes leaving gap for new node */ + memcpy(newnodes, GetSubTrie(node), Map*sizeof(HAMTNode)); + memcpy(&newnodes[Map+1], &(GetSubTrie(node))[Map], + (Size-Map-1)*sizeof(HAMTNode)); + /* Delete old subtrie */ + yasm_xfree(GetSubTrie(node)); + /* Set up new node */ + newnodes[Map].BitMapKey = key; + entry = yasm_xmalloc(sizeof(HAMTEntry)); + entry->str = str; + entry->data = data; + STAILQ_INSERT_TAIL(&hamt->entries, entry, next); + SetValue(hamt, &newnodes[Map], entry); + SetSubTrie(hamt, node, newnodes); + + *replace = 1; + return data; + } + + /* Count bits below */ + BitCount(Map, node->BitMapKey & ~((~0UL)<<keypart)); + Map &= 0x1F; /* Clamp to <32 */ + + /* Go down a level */ + level++; + node = &(GetSubTrie(node))[Map]; + } +} +/*@=temptrans =kepttrans =mustfree@*/ + +void * +HAMT_search(HAMT *hamt, const char *str) +{ + HAMTNode *node; + unsigned long key, keypart, Map; + int keypartbits = 0; + int level = 0; + + key = hamt->HashKey(str); + keypart = key & 0x1F; + node = &hamt->root[keypart]; + + if (!node->BaseValue) + return NULL; + + for (;;) { + if (!(IsSubTrie(node))) { + if (node->BitMapKey == key + && hamt->CmpKey(((HAMTEntry *)(node->BaseValue))->str, + str) == 0) + return ((HAMTEntry *)(node->BaseValue))->data; + else + return NULL; + } + + /* Subtree: look up in bitmap */ + keypartbits += 5; + if (keypartbits > 30) { + /* Exceeded 32 bits of current key: rehash */ + key = hamt->ReHashKey(str, level); + keypartbits = 0; + } + keypart = (key >> keypartbits) & 0x1F; + if (!(node->BitMapKey & (1<<keypart))) + return NULL; /* bit is 0 in bitmap -> no match */ + + /* Count bits below */ + BitCount(Map, node->BitMapKey & ~((~0UL)<<keypart)); + Map &= 0x1F; /* Clamp to <32 */ + + /* Go down a level */ + level++; + node = &(GetSubTrie(node))[Map]; + } +} + diff --git a/contrib/tools/yasm/libyasm/hamt.h b/contrib/tools/yasm/libyasm/hamt.h index 1ce9b77536..0964f83350 100644 --- a/contrib/tools/yasm/libyasm/hamt.h +++ b/contrib/tools/yasm/libyasm/hamt.h @@ -1,123 +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 +/** + * \file libyasm/hamt.h + * \brief Hash Array Mapped Trie (HAMT) functions. + * + * \license + * Copyright (C) 2001-2007 Peter Johnson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * \endlicense + */ +#ifndef YASM_HAMT_H +#define YASM_HAMT_H + +#ifndef YASM_LIB_DECL +#define YASM_LIB_DECL +#endif + +/** Hash array mapped trie data structure (opaque type). */ +typedef struct HAMT HAMT; +/** Hash array mapped trie entry (opaque type). */ +typedef struct HAMTEntry HAMTEntry; + +/** Create new, empty, HAMT. error_func() is called when an internal error is + * encountered--it should NOT return to the calling function. + * \param nocase nonzero if HAMT should be case-insensitive + * \param error_func function called on internal error + * \return New, empty, hash array mapped trie. + */ +YASM_LIB_DECL +HAMT *HAMT_create(int nocase, /*@exits@*/ void (*error_func) + (const char *file, unsigned int line, const char *message)); + +/** Delete HAMT and all data associated with it. Uses deletefunc() to delete + * each data item. + * \param hamt Hash array mapped trie + * \param deletefunc Data deletion function + */ +YASM_LIB_DECL +void HAMT_destroy(/*@only@*/ HAMT *hamt, + void (*deletefunc) (/*@only@*/ void *data)); + +/** Insert key into HAMT, associating it with data. + * If the key is not present in the HAMT, inserts it, sets *replace to 1, and + * returns the data passed in. + * If the key is already present and *replace is 0, deletes the data passed + * in using deletefunc() and returns the data currently associated with the + * key. + * If the key is already present and *replace is 1, deletes the data currently + * associated with the key using deletefunc() and replaces it with the data + * passed in. + * \param hamt Hash array mapped trie + * \param str Key + * \param data Data to associate with key + * \param replace See above description + * \param deletefunc Data deletion function if data is replaced + * \return Data now associated with key. + */ +YASM_LIB_DECL +/*@dependent@*/ void *HAMT_insert(HAMT *hamt, /*@dependent@*/ const char *str, + /*@only@*/ void *data, int *replace, + void (*deletefunc) (/*@only@*/ void *data)); + +/** Search for the data associated with a key in the HAMT. + * \param hamt Hash array mapped trie + * \param str Key + * \return NULL if key/data not present in HAMT, otherwise associated data. + */ +YASM_LIB_DECL +/*@dependent@*/ /*@null@*/ void *HAMT_search(HAMT *hamt, const char *str); + +/** Traverse over all keys in HAMT, calling function on each data item. + * \param hamt Hash array mapped trie + * \param d Data to pass to each call to func. + * \param func Function to call + * \return Stops early (and returns func's return value) if func returns a + * nonzero value; otherwise 0. + */ +YASM_LIB_DECL +int HAMT_traverse(HAMT *hamt, /*@null@*/ void *d, + int (*func) (/*@dependent@*/ /*@null@*/ void *node, + /*@null@*/ void *d)); + +/** Get the first entry in a HAMT. + * \param hamt Hash array mapped trie + * \return First entry in HAMT, or NULL if HAMT is empty. + */ +YASM_LIB_DECL +const HAMTEntry *HAMT_first(const HAMT *hamt); + +/** Get the next entry in a HAMT. + * \param prev Previous entry in HAMT + * \return Next entry in HAMT, or NULL if no more entries. + */ +YASM_LIB_DECL +/*@null@*/ const HAMTEntry *HAMT_next(const HAMTEntry *prev); + +/** Get the corresponding data for a HAMT entry. + * \param entry HAMT entry (as returned by HAMT_first() and HAMT_next()) + * \return Corresponding data item. + */ +YASM_LIB_DECL +void *HAMTEntry_get_data(const HAMTEntry *entry); + +#endif diff --git a/contrib/tools/yasm/libyasm/insn.c b/contrib/tools/yasm/libyasm/insn.c index 8f7a4c1978..a1ebbfc568 100644 --- a/contrib/tools/yasm/libyasm/insn.c +++ b/contrib/tools/yasm/libyasm/insn.c @@ -1,295 +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; - } - } -} +/* + * Mnemonic instruction bytecode + * + * Copyright (C) 2005-2007 Peter Johnson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include "util.h" + +#include "libyasm-stdint.h" +#include "coretype.h" + +#include "errwarn.h" +#include "expr.h" +#include "value.h" + +#include "bytecode.h" +#include "insn.h" +#include "arch.h" + + +void +yasm_ea_set_segreg(yasm_effaddr *ea, uintptr_t segreg) +{ + if (!ea) + return; + + if (segreg != 0 && ea->segreg != 0) + yasm_warn_set(YASM_WARN_GENERAL, + N_("multiple segment overrides, using leftmost")); + + ea->segreg = segreg; +} + +yasm_insn_operand * +yasm_operand_create_reg(uintptr_t reg) +{ + yasm_insn_operand *retval = yasm_xmalloc(sizeof(yasm_insn_operand)); + + retval->type = YASM_INSN__OPERAND_REG; + retval->data.reg = reg; + retval->seg = 0; + retval->targetmod = 0; + retval->size = 0; + retval->deref = 0; + retval->strict = 0; + + return retval; +} + +yasm_insn_operand * +yasm_operand_create_segreg(uintptr_t segreg) +{ + yasm_insn_operand *retval = yasm_xmalloc(sizeof(yasm_insn_operand)); + + retval->type = YASM_INSN__OPERAND_SEGREG; + retval->data.reg = segreg; + retval->seg = 0; + retval->targetmod = 0; + retval->size = 0; + retval->deref = 0; + retval->strict = 0; + + return retval; +} + +yasm_insn_operand * +yasm_operand_create_mem(/*@only@*/ yasm_effaddr *ea) +{ + yasm_insn_operand *retval = yasm_xmalloc(sizeof(yasm_insn_operand)); + + retval->type = YASM_INSN__OPERAND_MEMORY; + retval->data.ea = ea; + retval->seg = 0; + retval->targetmod = 0; + retval->size = 0; + retval->deref = 0; + retval->strict = 0; + retval->size = ea->data_len * 8; + + return retval; +} + +yasm_insn_operand * +yasm_operand_create_imm(/*@only@*/ yasm_expr *val) +{ + yasm_insn_operand *retval; + const uintptr_t *reg; + + reg = yasm_expr_get_reg(&val, 0); + if (reg) { + retval = yasm_operand_create_reg(*reg); + yasm_expr_destroy(val); + } else { + retval = yasm_xmalloc(sizeof(yasm_insn_operand)); + retval->type = YASM_INSN__OPERAND_IMM; + retval->data.val = val; + retval->seg = 0; + retval->targetmod = 0; + retval->size = 0; + retval->deref = 0; + retval->strict = 0; + } + + return retval; +} + +yasm_insn_operand * +yasm_insn_ops_append(yasm_insn *insn, yasm_insn_operand *op) +{ + if (op) { + insn->num_operands++; + STAILQ_INSERT_TAIL(&insn->operands, op, link); + return op; + } + return (yasm_insn_operand *)NULL; +} + +void +yasm_insn_add_prefix(yasm_insn *insn, uintptr_t prefix) +{ + insn->prefixes = + yasm_xrealloc(insn->prefixes, + (insn->num_prefixes+1)*sizeof(uintptr_t)); + insn->prefixes[insn->num_prefixes] = prefix; + insn->num_prefixes++; +} + +void +yasm_insn_add_seg_prefix(yasm_insn *insn, uintptr_t segreg) +{ + insn->segregs = + yasm_xrealloc(insn->segregs, (insn->num_segregs+1)*sizeof(uintptr_t)); + insn->segregs[insn->num_segregs] = segreg; + insn->num_segregs++; +} + +void +yasm_insn_initialize(yasm_insn *insn) +{ + STAILQ_INIT(&insn->operands); + + insn->prefixes = NULL; + insn->segregs = NULL; + + insn->num_operands = 0; + insn->num_prefixes = 0; + insn->num_segregs = 0; +} + +void +yasm_insn_delete(yasm_insn *insn, + void (*ea_destroy) (/*@only@*/ yasm_effaddr *)) +{ + if (insn->num_operands > 0) { + yasm_insn_operand *cur, *next; + + cur = STAILQ_FIRST(&insn->operands); + while (cur) { + next = STAILQ_NEXT(cur, link); + switch (cur->type) { + case YASM_INSN__OPERAND_MEMORY: + ea_destroy(cur->data.ea); + break; + case YASM_INSN__OPERAND_IMM: + yasm_expr_destroy(cur->data.val); + break; + default: + break; + } + yasm_xfree(cur); + cur = next; + } + } + if (insn->num_prefixes > 0) + yasm_xfree(insn->prefixes); + if (insn->num_segregs > 0) + yasm_xfree(insn->segregs); +} + +void +yasm_insn_print(const yasm_insn *insn, FILE *f, int indent_level) +{ + const yasm_insn_operand *op; + + STAILQ_FOREACH (op, &insn->operands, link) { + switch (op->type) { + case YASM_INSN__OPERAND_REG: + fprintf(f, "%*sReg=", indent_level, ""); + /*yasm_arch_reg_print(arch, op->data.reg, f);*/ + fprintf(f, "\n"); + break; + case YASM_INSN__OPERAND_SEGREG: + fprintf(f, "%*sSegReg=", indent_level, ""); + /*yasm_arch_segreg_print(arch, op->data.reg, f);*/ + fprintf(f, "\n"); + break; + case YASM_INSN__OPERAND_MEMORY: + fprintf(f, "%*sMemory=\n", indent_level, ""); + /*yasm_arch_ea_print(arch, op->data.ea, f, indent_level);*/ + break; + case YASM_INSN__OPERAND_IMM: + fprintf(f, "%*sImm=", indent_level, ""); + yasm_expr_print(op->data.val, f); + fprintf(f, "\n"); + break; + } + fprintf(f, "%*sTargetMod=%lx\n", indent_level+1, "", + (unsigned long)op->targetmod); + fprintf(f, "%*sSize=%u\n", indent_level+1, "", op->size); + fprintf(f, "%*sDeref=%d, Strict=%d\n", indent_level+1, "", + (int)op->deref, (int)op->strict); + } +} + +void +yasm_insn_finalize(yasm_insn *insn) +{ + unsigned int i; + yasm_insn_operand *op; + yasm_error_class eclass; + char *str, *xrefstr; + unsigned long xrefline; + + /* Simplify the operands' expressions first. */ + for (i = 0, op = yasm_insn_ops_first(insn); + op && i<insn->num_operands; op = yasm_insn_op_next(op), i++) { + /* Check operand type */ + switch (op->type) { + case YASM_INSN__OPERAND_MEMORY: + /* Don't get over-ambitious here; some archs' memory expr + * parser are sensitive to the presence of *1, etc, so don't + * simplify reg*1 identities. + */ + if (op->data.ea) + op->data.ea->disp.abs = + yasm_expr__level_tree(op->data.ea->disp.abs, 1, 1, 0, + 0, NULL, NULL); + if (yasm_error_occurred()) { + /* Add a pointer to where it was used to the error */ + yasm_error_fetch(&eclass, &str, &xrefline, &xrefstr); + if (xrefstr) { + yasm_error_set_xref(xrefline, "%s", xrefstr); + yasm_xfree(xrefstr); + } + if (str) { + yasm_error_set(eclass, "%s in memory expression", str); + yasm_xfree(str); + } + return; + } + break; + case YASM_INSN__OPERAND_IMM: + op->data.val = + yasm_expr__level_tree(op->data.val, 1, 1, 1, 0, NULL, + NULL); + if (yasm_error_occurred()) { + /* Add a pointer to where it was used to the error */ + yasm_error_fetch(&eclass, &str, &xrefline, &xrefstr); + if (xrefstr) { + yasm_error_set_xref(xrefline, "%s", xrefstr); + yasm_xfree(xrefstr); + } + if (str) { + yasm_error_set(eclass, "%s in immediate expression", + str); + yasm_xfree(str); + } + return; + } + break; + default: + break; + } + } +} diff --git a/contrib/tools/yasm/libyasm/insn.h b/contrib/tools/yasm/libyasm/insn.h index d2d175d039..7400afbc88 100644 --- a/contrib/tools/yasm/libyasm/insn.h +++ b/contrib/tools/yasm/libyasm/insn.h @@ -1,269 +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 +/** + * \file libyasm/insn.h + * \brief YASM mnenomic instruction. + * + * \license + * Copyright (C) 2002-2007 Peter Johnson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * \endlicense + */ +#ifndef YASM_INSN_H +#define YASM_INSN_H + +#ifndef YASM_LIB_DECL +#define YASM_LIB_DECL +#endif + +/** Base structure for an effective address. As with all base + * structures, must be present as the first element in any + * #yasm_arch implementation of an effective address. + */ +struct yasm_effaddr { + yasm_value disp; /**< address displacement */ + + /** Segment register override (0 if none). */ + uintptr_t segreg; + + /** 1 if length of disp must be >0. */ + unsigned int need_nonzero_len:1; + + /** 1 if a displacement should be present in the output. */ + unsigned int need_disp:1; + + /** 1 if reg*2 should not be split into reg+reg. (0 if not). + * This flag indicates (for architectures that support complex effective + * addresses such as x86) if various types of complex effective addresses + * can be split into different forms in order to minimize instruction + * length. + */ + unsigned int nosplit:1; + + /** 1 if effective address is /definitely/ an effective address. + * This is used in e.g. the GAS parser to differentiate + * between "expr" (which might or might not be an effective address) and + * "expr(,1)" (which is definitely an effective address). + */ + unsigned int strong:1; + + /** 1 if effective address is forced PC-relative. */ + unsigned int pc_rel:1; + + /** 1 if effective address is forced non-PC-relative. */ + unsigned int not_pc_rel:1; + + /** length of pointed data (in bytes), 0 if unknown. */ + unsigned int data_len; +}; + +/** An instruction operand (opaque type). */ +typedef struct yasm_insn_operand yasm_insn_operand; + +/** The type of an instruction operand. */ +typedef enum yasm_insn_operand_type { + YASM_INSN__OPERAND_REG = 1, /**< A register. */ + YASM_INSN__OPERAND_SEGREG, /**< A segment register. */ + YASM_INSN__OPERAND_MEMORY, /**< An effective address + * (memory reference). */ + YASM_INSN__OPERAND_IMM /**< An immediate or jump target. */ +} yasm_insn_operand_type; + +/** An instruction operand. */ +struct yasm_insn_operand { + /** Link for building linked list of operands. \internal */ + /*@reldef@*/ STAILQ_ENTRY(yasm_insn_operand) link; + + /** Operand data. */ + union { + uintptr_t reg; /**< Arch data for reg/segreg. */ + yasm_effaddr *ea; /**< Effective address for memory references. */ + yasm_expr *val; /**< Value of immediate or jump target. */ + } data; + + yasm_expr *seg; /**< Segment expression */ + + uintptr_t targetmod; /**< Arch target modifier, 0 if none. */ + + /** Specified size of the operand, in bits. 0 if not user-specified. */ + unsigned int size:16; + + /** Nonzero if dereference. Used for "*foo" in GAS. + * The reason for this is that by default in GAS, an unprefixed value + * is a memory address, except for jumps/calls, in which case it needs a + * "*" prefix to become a memory address (otherwise it's an immediate). + * This isn't knowable in the parser stage, so the parser sets this flag + * to indicate the "*" prefix has been used, and the arch needs to adjust + * the operand type appropriately depending on the instruction type. + */ + unsigned int deref:1; + + /** Nonzero if strict. Used for "strict foo" in NASM. + * This is used to inhibit optimization on otherwise "sized" values. + * For example, the user may just want to be explicit with the size on + * "push dword 4", but not actually want to force the immediate size to + * 4 bytes (rather wanting the optimizer to optimize it down to 1 byte as + * though "dword" was not specified). To indicate the immediate should + * actually be forced to 4 bytes, the user needs to write + * "push strict dword 4", which sets this flag. + */ + unsigned int strict:1; + + /** Operand type. */ + unsigned int type:4; +}; + +/** Base structure for "instruction" bytecodes. These are the mnenomic + * (rather than raw) representation of instructions. As with all base + * structures, must be present as the first element in any + * #yasm_arch implementation of mnenomic instruction bytecodes. + */ +struct yasm_insn { + /** Linked list of operands. */ + /*@reldef@*/ STAILQ_HEAD(yasm_insn_operands, yasm_insn_operand) operands; + + /** Array of prefixes. */ + /*@null@*/ uintptr_t *prefixes; + + /** Array of segment prefixes. */ + /*@null@*/ uintptr_t *segregs; + + unsigned int num_operands; /**< Number of operands. */ + unsigned int num_prefixes; /**< Number of prefixes. */ + unsigned int num_segregs; /**< Number of segment prefixes. */ +}; + +/** Set segment override for an effective address. + * Some architectures (such as x86) support segment overrides on effective + * addresses. A override of an override will result in a warning. + * \param ea effective address + * \param segreg segment register (0 if none) + */ +YASM_LIB_DECL +void yasm_ea_set_segreg(yasm_effaddr *ea, uintptr_t segreg); + +/** Create an instruction operand from a register. + * \param reg register + * \return Newly allocated operand. + */ +YASM_LIB_DECL +yasm_insn_operand *yasm_operand_create_reg(uintptr_t reg); + +/** Create an instruction operand from a segment register. + * \param segreg segment register + * \return Newly allocated operand. + */ +YASM_LIB_DECL +yasm_insn_operand *yasm_operand_create_segreg(uintptr_t segreg); + +/** Create an instruction operand from an effective address. + * \param ea effective address + * \return Newly allocated operand. + */ +YASM_LIB_DECL +yasm_insn_operand *yasm_operand_create_mem(/*@only@*/ yasm_effaddr *ea); + +/** Create an instruction operand from an immediate expression. + * Looks for cases of a single register and creates a register variant of + * #yasm_insn_operand. + * \param val immediate expression + * \return Newly allocated operand. + */ +YASM_LIB_DECL +yasm_insn_operand *yasm_operand_create_imm(/*@only@*/ yasm_expr *val); + +/** Get the first operand in an instruction. + * \param insn instruction + * \return First operand (NULL if no operands). + */ +yasm_insn_operand *yasm_insn_ops_first(yasm_insn *insn); +#define yasm_insn_ops_first(insn) STAILQ_FIRST(&((insn)->operands)) + +/** Get the next operand in an instruction. + * \param op previous operand + * \return Next operand (NULL if op was the last operand). + */ +yasm_insn_operand *yasm_insn_op_next(yasm_insn_operand *op); +#define yasm_insn_op_next(cur) STAILQ_NEXT(cur, link) + +/** Add operand to the end of an instruction. + * \note Does not make a copy of the operand; so don't pass this function + * static or local variables, and discard the op pointer after calling + * this function. + * \param insn instruction + * \param op operand (may be NULL) + * \return If operand was actually appended (it wasn't NULL), the operand; + * otherwise NULL. + */ +YASM_LIB_DECL +/*@null@*/ yasm_insn_operand *yasm_insn_ops_append + (yasm_insn *insn, + /*@returned@*/ /*@null@*/ yasm_insn_operand *op); + +/** Associate a prefix with an instruction. + * \param insn instruction + * \param prefix data that identifies the prefix + */ +YASM_LIB_DECL +void yasm_insn_add_prefix(yasm_insn *insn, uintptr_t prefix); + +/** Associate a segment prefix with an instruction. + * \param insn instruction + * \param segreg data that identifies the segment register + */ +YASM_LIB_DECL +void yasm_insn_add_seg_prefix(yasm_insn *insn, uintptr_t segreg); + +/** Initialize the common parts of an instruction. + * \internal For use by yasm_arch implementations only. + * \param insn instruction + */ +YASM_LIB_DECL +void yasm_insn_initialize(/*@out@*/ yasm_insn *insn); + +/** Delete the common parts of an instruction. + * \internal For use by yasm_arch implementations only. + * \param insn instruction + * \param content if nonzero, deletes content of each operand + * \param arch architecture + */ +YASM_LIB_DECL +void yasm_insn_delete(yasm_insn *insn, + void (*ea_destroy) (/*@only@*/ yasm_effaddr *)); + +/** Print a list of instruction operands. For debugging purposes. + * \internal For use by yasm_arch implementations only. + * \param insn instruction + * \param f file + * \param indent_level indentation level + * \param arch architecture + */ +YASM_LIB_DECL +void yasm_insn_print(const yasm_insn *insn, FILE *f, int indent_level); + +/** Finalize the common parts of an instruction. + * \internal For use by yasm_arch implementations only. + * \param insn instruction + */ +YASM_LIB_DECL +void yasm_insn_finalize(yasm_insn *insn); + +#endif diff --git a/contrib/tools/yasm/libyasm/intnum.c b/contrib/tools/yasm/libyasm/intnum.c index 6feba33481..961bf31394 100644 --- a/contrib/tools/yasm/libyasm/intnum.c +++ b/contrib/tools/yasm/libyasm/intnum.c @@ -1,1096 +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; - } -} +/* + * Integer number functions. + * + * Copyright (C) 2001-2007 Peter Johnson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include "util.h" + +#include <ctype.h> +#include <limits.h> + +#include "coretype.h" +#include "bitvect.h" +#include "file.h" + +#include "errwarn.h" +#include "intnum.h" + + +/* "Native" "word" size for intnum calculations. */ +#define BITVECT_NATIVE_SIZE 256 + +struct yasm_intnum { + union val { + long l; /* integer value (for integers <32 bits) */ + wordptr bv; /* bit vector (for integers >=32 bits) */ + } val; + enum { INTNUM_L, INTNUM_BV } type; +}; + +/* static bitvect used for conversions */ +static /*@only@*/ wordptr conv_bv; + +/* static bitvects used for computation */ +static /*@only@*/ wordptr result, spare, op1static, op2static; + +static /*@only@*/ BitVector_from_Dec_static_data *from_dec_data; + + +void +yasm_intnum_initialize(void) +{ + conv_bv = BitVector_Create(BITVECT_NATIVE_SIZE, FALSE); + result = BitVector_Create(BITVECT_NATIVE_SIZE, FALSE); + spare = BitVector_Create(BITVECT_NATIVE_SIZE, FALSE); + op1static = BitVector_Create(BITVECT_NATIVE_SIZE, FALSE); + op2static = BitVector_Create(BITVECT_NATIVE_SIZE, FALSE); + from_dec_data = BitVector_from_Dec_static_Boot(BITVECT_NATIVE_SIZE); +} + +void +yasm_intnum_cleanup(void) +{ + BitVector_from_Dec_static_Shutdown(from_dec_data); + BitVector_Destroy(op2static); + BitVector_Destroy(op1static); + BitVector_Destroy(spare); + BitVector_Destroy(result); + BitVector_Destroy(conv_bv); +} + +/* Compress a bitvector into intnum storage. + * If saved as a bitvector, clones the passed bitvector. + * Can modify the passed bitvector. + */ +static void +intnum_frombv(/*@out@*/ yasm_intnum *intn, wordptr bv) +{ + if (Set_Max(bv) < 31) { + intn->type = INTNUM_L; + intn->val.l = (long)BitVector_Chunk_Read(bv, 31, 0); + } else if (BitVector_msb_(bv)) { + /* Negative, negate and see if we'll fit into a long. */ + unsigned long ul; + BitVector_Negate(bv, bv); + if (Set_Max(bv) >= 32 || + ((ul = BitVector_Chunk_Read(bv, 32, 0)) & 0x80000000)) { + /* too negative */ + BitVector_Negate(bv, bv); + intn->type = INTNUM_BV; + intn->val.bv = BitVector_Clone(bv); + } else { + intn->type = INTNUM_L; + intn->val.l = -((long)ul); + } + } else { + intn->type = INTNUM_BV; + intn->val.bv = BitVector_Clone(bv); + } +} + +/* If intnum is a BV, returns its bitvector directly. + * If not, converts into passed bv and returns that instead. + */ +static wordptr +intnum_tobv(/*@returned@*/ wordptr bv, const yasm_intnum *intn) +{ + if (intn->type == INTNUM_BV) + return intn->val.bv; + + BitVector_Empty(bv); + if (intn->val.l >= 0) + BitVector_Chunk_Store(bv, 32, 0, (unsigned long)intn->val.l); + else { + BitVector_Chunk_Store(bv, 32, 0, (unsigned long)-intn->val.l); + BitVector_Negate(bv, bv); + } + return bv; +} + +yasm_intnum * +yasm_intnum_create_dec(char *str) +{ + yasm_intnum *intn = yasm_xmalloc(sizeof(yasm_intnum)); + + switch (BitVector_from_Dec_static(from_dec_data, conv_bv, + (unsigned char *)str)) { + case ErrCode_Pars: + yasm_error_set(YASM_ERROR_VALUE, N_("invalid decimal literal")); + break; + case ErrCode_Ovfl: + yasm_error_set(YASM_ERROR_OVERFLOW, + N_("Numeric constant too large for internal format")); + break; + default: + break; + } + intnum_frombv(intn, conv_bv); + return intn; +} + +yasm_intnum * +yasm_intnum_create_bin(char *str) +{ + yasm_intnum *intn = yasm_xmalloc(sizeof(yasm_intnum)); + + switch (BitVector_from_Bin(conv_bv, (unsigned char *)str)) { + case ErrCode_Pars: + yasm_error_set(YASM_ERROR_VALUE, N_("invalid binary literal")); + break; + case ErrCode_Ovfl: + yasm_error_set(YASM_ERROR_OVERFLOW, + N_("Numeric constant too large for internal format")); + break; + default: + break; + } + intnum_frombv(intn, conv_bv); + return intn; +} + +yasm_intnum * +yasm_intnum_create_oct(char *str) +{ + yasm_intnum *intn = yasm_xmalloc(sizeof(yasm_intnum)); + + switch (BitVector_from_Oct(conv_bv, (unsigned char *)str)) { + case ErrCode_Pars: + yasm_error_set(YASM_ERROR_VALUE, N_("invalid octal literal")); + break; + case ErrCode_Ovfl: + yasm_error_set(YASM_ERROR_OVERFLOW, + N_("Numeric constant too large for internal format")); + break; + default: + break; + } + intnum_frombv(intn, conv_bv); + return intn; +} + +yasm_intnum * +yasm_intnum_create_hex(char *str) +{ + yasm_intnum *intn = yasm_xmalloc(sizeof(yasm_intnum)); + + switch (BitVector_from_Hex(conv_bv, (unsigned char *)str)) { + case ErrCode_Pars: + yasm_error_set(YASM_ERROR_VALUE, N_("invalid hex literal")); + break; + case ErrCode_Ovfl: + yasm_error_set(YASM_ERROR_OVERFLOW, + N_("Numeric constant too large for internal format")); + break; + default: + break; + } + intnum_frombv(intn, conv_bv); + return intn; +} + +/*@-usedef -compdef -uniondef@*/ +yasm_intnum * +yasm_intnum_create_charconst_nasm(const char *str) +{ + yasm_intnum *intn = yasm_xmalloc(sizeof(yasm_intnum)); + size_t len = strlen(str); + + if(len*8 > BITVECT_NATIVE_SIZE) + yasm_error_set(YASM_ERROR_OVERFLOW, + N_("Character constant too large for internal format")); + + /* be conservative in choosing bitvect in case MSB is set */ + if (len > 3) { + BitVector_Empty(conv_bv); + intn->type = INTNUM_BV; + } else { + intn->val.l = 0; + intn->type = INTNUM_L; + } + + switch (len) { + case 3: + intn->val.l |= ((unsigned long)str[2]) & 0xff; + intn->val.l <<= 8; + /*@fallthrough@*/ + case 2: + intn->val.l |= ((unsigned long)str[1]) & 0xff; + intn->val.l <<= 8; + /*@fallthrough@*/ + case 1: + intn->val.l |= ((unsigned long)str[0]) & 0xff; + case 0: + break; + default: + /* >=32 bit conversion */ + while (len) { + BitVector_Move_Left(conv_bv, 8); + BitVector_Chunk_Store(conv_bv, 8, 0, + ((unsigned long)str[--len]) & 0xff); + } + intn->val.bv = BitVector_Clone(conv_bv); + } + + return intn; +} + +yasm_intnum * +yasm_intnum_create_charconst_tasm(const char *str) +{ + yasm_intnum *intn = yasm_xmalloc(sizeof(yasm_intnum)); + size_t len = strlen(str); + size_t i; + + if(len*8 > BITVECT_NATIVE_SIZE) + yasm_error_set(YASM_ERROR_OVERFLOW, + N_("Character constant too large for internal format")); + + /* be conservative in choosing bitvect in case MSB is set */ + if (len > 3) { + BitVector_Empty(conv_bv); + intn->type = INTNUM_BV; + } else { + intn->val.l = 0; + intn->type = INTNUM_L; + } + + /* tasm uses big endian notation */ + i = 0; + switch (len) { + case 3: + intn->val.l |= ((unsigned long)str[i++]) & 0xff; + intn->val.l <<= 8; + /*@fallthrough@*/ + case 2: + intn->val.l |= ((unsigned long)str[i++]) & 0xff; + intn->val.l <<= 8; + /*@fallthrough@*/ + case 1: + intn->val.l |= ((unsigned long)str[i++]) & 0xff; + case 0: + break; + default: + /* >=32 bit conversion */ + while (i < len) { + BitVector_Chunk_Store(conv_bv, 8, (len-i-1)*8, + ((unsigned long)str[i]) & 0xff); + i++; + } + intn->val.bv = BitVector_Clone(conv_bv); + } + + return intn; +} +/*@=usedef =compdef =uniondef@*/ + +yasm_intnum * +yasm_intnum_create_uint(unsigned long i) +{ + yasm_intnum *intn = yasm_xmalloc(sizeof(yasm_intnum)); + + if (i > LONG_MAX) { + /* Too big, store as bitvector */ + intn->val.bv = BitVector_Create(BITVECT_NATIVE_SIZE, TRUE); + intn->type = INTNUM_BV; + BitVector_Chunk_Store(intn->val.bv, 32, 0, i); + } else { + intn->val.l = (long)i; + intn->type = INTNUM_L; + } + + return intn; +} + +yasm_intnum * +yasm_intnum_create_int(long i) +{ + yasm_intnum *intn = yasm_xmalloc(sizeof(yasm_intnum)); + + intn->val.l = i; + intn->type = INTNUM_L; + + return intn; +} + +yasm_intnum * +yasm_intnum_create_leb128(const unsigned char *ptr, int sign, + unsigned long *size) +{ + yasm_intnum *intn = yasm_xmalloc(sizeof(yasm_intnum)); + const unsigned char *ptr_orig = ptr; + unsigned long i = 0; + + BitVector_Empty(conv_bv); + for (;;) { + BitVector_Chunk_Store(conv_bv, 7, i, *ptr); + i += 7; + if ((*ptr & 0x80) != 0x80) + break; + ptr++; + } + + *size = (unsigned long)(ptr-ptr_orig)+1; + + if(i > BITVECT_NATIVE_SIZE) + yasm_error_set(YASM_ERROR_OVERFLOW, + N_("Numeric constant too large for internal format")); + else if (sign && (*ptr & 0x40) == 0x40) + BitVector_Interval_Fill(conv_bv, i, BITVECT_NATIVE_SIZE-1); + + intnum_frombv(intn, conv_bv); + return intn; +} + +yasm_intnum * +yasm_intnum_create_sized(unsigned char *ptr, int sign, size_t srcsize, + int bigendian) +{ + yasm_intnum *intn = yasm_xmalloc(sizeof(yasm_intnum)); + unsigned long i = 0; + + if (srcsize*8 > BITVECT_NATIVE_SIZE) + yasm_error_set(YASM_ERROR_OVERFLOW, + N_("Numeric constant too large for internal format")); + + /* Read the buffer into a bitvect */ + BitVector_Empty(conv_bv); + if (bigendian) { + /* TODO */ + yasm_internal_error(N_("big endian not implemented")); + } else { + for (i = 0; i < srcsize; i++) + BitVector_Chunk_Store(conv_bv, 8, i*8, ptr[i]); + } + + /* Sign extend if needed */ + if (srcsize*8 < BITVECT_NATIVE_SIZE && sign && (ptr[i-1] & 0x80) == 0x80) + BitVector_Interval_Fill(conv_bv, i*8, BITVECT_NATIVE_SIZE-1); + + intnum_frombv(intn, conv_bv); + return intn; +} + +yasm_intnum * +yasm_intnum_copy(const yasm_intnum *intn) +{ + yasm_intnum *n = yasm_xmalloc(sizeof(yasm_intnum)); + + switch (intn->type) { + case INTNUM_L: + n->val.l = intn->val.l; + break; + case INTNUM_BV: + n->val.bv = BitVector_Clone(intn->val.bv); + break; + } + n->type = intn->type; + + return n; +} + +void +yasm_intnum_destroy(yasm_intnum *intn) +{ + if (intn->type == INTNUM_BV) + BitVector_Destroy(intn->val.bv); + yasm_xfree(intn); +} + +/*@-nullderef -nullpass -branchstate@*/ +int +yasm_intnum_calc(yasm_intnum *acc, yasm_expr_op op, yasm_intnum *operand) +{ + boolean carry = 0; + wordptr op1, op2 = NULL; + N_int count; + + /* Always do computations with in full bit vector. + * Bit vector results must be calculated through intermediate storage. + */ + op1 = intnum_tobv(op1static, acc); + if (operand) + op2 = intnum_tobv(op2static, operand); + + if (!operand && op != YASM_EXPR_NEG && op != YASM_EXPR_NOT && + op != YASM_EXPR_LNOT) { + yasm_error_set(YASM_ERROR_ARITHMETIC, + N_("operation needs an operand")); + BitVector_Empty(result); + return 1; + } + + /* A operation does a bitvector computation if result is allocated. */ + switch (op) { + case YASM_EXPR_ADD: + BitVector_add(result, op1, op2, &carry); + break; + case YASM_EXPR_SUB: + BitVector_sub(result, op1, op2, &carry); + break; + case YASM_EXPR_MUL: + BitVector_Multiply(result, op1, op2); + break; + case YASM_EXPR_DIV: + /* TODO: make sure op1 and op2 are unsigned */ + if (BitVector_is_empty(op2)) { + yasm_error_set(YASM_ERROR_ZERO_DIVISION, N_("divide by zero")); + BitVector_Empty(result); + return 1; + } else + BitVector_Divide(result, op1, op2, spare); + break; + case YASM_EXPR_SIGNDIV: + if (BitVector_is_empty(op2)) { + yasm_error_set(YASM_ERROR_ZERO_DIVISION, N_("divide by zero")); + BitVector_Empty(result); + return 1; + } else + BitVector_Divide(result, op1, op2, spare); + break; + case YASM_EXPR_MOD: + /* TODO: make sure op1 and op2 are unsigned */ + if (BitVector_is_empty(op2)) { + yasm_error_set(YASM_ERROR_ZERO_DIVISION, N_("divide by zero")); + BitVector_Empty(result); + return 1; + } else + BitVector_Divide(spare, op1, op2, result); + break; + case YASM_EXPR_SIGNMOD: + if (BitVector_is_empty(op2)) { + yasm_error_set(YASM_ERROR_ZERO_DIVISION, N_("divide by zero")); + BitVector_Empty(result); + return 1; + } else + BitVector_Divide(spare, op1, op2, result); + break; + case YASM_EXPR_NEG: + BitVector_Negate(result, op1); + break; + case YASM_EXPR_NOT: + Set_Complement(result, op1); + break; + case YASM_EXPR_OR: + Set_Union(result, op1, op2); + break; + case YASM_EXPR_AND: + Set_Intersection(result, op1, op2); + break; + case YASM_EXPR_XOR: + Set_ExclusiveOr(result, op1, op2); + break; + case YASM_EXPR_XNOR: + Set_ExclusiveOr(result, op1, op2); + Set_Complement(result, result); + break; + case YASM_EXPR_NOR: + Set_Union(result, op1, op2); + Set_Complement(result, result); + break; + case YASM_EXPR_SHL: + if (operand->type == INTNUM_L && operand->val.l >= 0) { + BitVector_Copy(result, op1); + BitVector_Move_Left(result, (N_int)operand->val.l); + } else /* don't even bother, just zero result */ + BitVector_Empty(result); + break; + case YASM_EXPR_SHR: + if (operand->type == INTNUM_L && operand->val.l >= 0) { + BitVector_Copy(result, op1); + carry = BitVector_msb_(op1); + count = (N_int)operand->val.l; + while (count-- > 0) + BitVector_shift_right(result, carry); + } else /* don't even bother, just zero result */ + BitVector_Empty(result); + break; + case YASM_EXPR_LOR: + BitVector_Empty(result); + BitVector_LSB(result, !BitVector_is_empty(op1) || + !BitVector_is_empty(op2)); + break; + case YASM_EXPR_LAND: + BitVector_Empty(result); + BitVector_LSB(result, !BitVector_is_empty(op1) && + !BitVector_is_empty(op2)); + break; + case YASM_EXPR_LNOT: + BitVector_Empty(result); + BitVector_LSB(result, BitVector_is_empty(op1)); + break; + case YASM_EXPR_LXOR: + BitVector_Empty(result); + BitVector_LSB(result, !BitVector_is_empty(op1) ^ + !BitVector_is_empty(op2)); + break; + case YASM_EXPR_LXNOR: + BitVector_Empty(result); + BitVector_LSB(result, !(!BitVector_is_empty(op1) ^ + !BitVector_is_empty(op2))); + break; + case YASM_EXPR_LNOR: + BitVector_Empty(result); + BitVector_LSB(result, !(!BitVector_is_empty(op1) || + !BitVector_is_empty(op2))); + break; + case YASM_EXPR_EQ: + BitVector_Empty(result); + BitVector_LSB(result, BitVector_equal(op1, op2)); + break; + case YASM_EXPR_LT: + BitVector_Empty(result); + BitVector_LSB(result, BitVector_Compare(op1, op2) < 0); + break; + case YASM_EXPR_GT: + BitVector_Empty(result); + BitVector_LSB(result, BitVector_Compare(op1, op2) > 0); + break; + case YASM_EXPR_LE: + BitVector_Empty(result); + BitVector_LSB(result, BitVector_Compare(op1, op2) <= 0); + break; + case YASM_EXPR_GE: + BitVector_Empty(result); + BitVector_LSB(result, BitVector_Compare(op1, op2) >= 0); + break; + case YASM_EXPR_NE: + BitVector_Empty(result); + BitVector_LSB(result, !BitVector_equal(op1, op2)); + break; + case YASM_EXPR_SEG: + yasm_error_set(YASM_ERROR_ARITHMETIC, N_("invalid use of '%s'"), + "SEG"); + break; + case YASM_EXPR_WRT: + yasm_error_set(YASM_ERROR_ARITHMETIC, N_("invalid use of '%s'"), + "WRT"); + break; + case YASM_EXPR_SEGOFF: + yasm_error_set(YASM_ERROR_ARITHMETIC, N_("invalid use of '%s'"), + ":"); + break; + case YASM_EXPR_IDENT: + if (result) + BitVector_Copy(result, op1); + break; + default: + yasm_error_set(YASM_ERROR_ARITHMETIC, + N_("invalid operation in intnum calculation")); + BitVector_Empty(result); + return 1; + } + + /* Try to fit the result into 32 bits if possible */ + if (acc->type == INTNUM_BV) + BitVector_Destroy(acc->val.bv); + intnum_frombv(acc, result); + return 0; +} +/*@=nullderef =nullpass =branchstate@*/ + +int +yasm_intnum_compare(const yasm_intnum *intn1, const yasm_intnum *intn2) +{ + wordptr op1, op2; + + if (intn1->type == INTNUM_L && intn2->type == INTNUM_L) { + if (intn1->val.l < intn2->val.l) + return -1; + if (intn1->val.l > intn2->val.l) + return 1; + return 0; + } + + op1 = intnum_tobv(op1static, intn1); + op2 = intnum_tobv(op2static, intn2); + return BitVector_Compare(op1, op2); +} + +void +yasm_intnum_zero(yasm_intnum *intn) +{ + yasm_intnum_set_int(intn, 0); +} + +void +yasm_intnum_set(yasm_intnum *intn, const yasm_intnum *val) +{ + if (intn->type == val->type) { + switch (val->type) { + case INTNUM_L: + intn->val.l = val->val.l; + break; + case INTNUM_BV: + BitVector_Copy(intn->val.bv, val->val.bv); + break; + } + } else { + switch (val->type) { + case INTNUM_L: + BitVector_Destroy(intn->val.bv); + intn->val.l = val->val.l; + break; + case INTNUM_BV: + intn->val.bv = BitVector_Clone(val->val.bv); + break; + } + intn->type = val->type; + } +} + +void +yasm_intnum_set_uint(yasm_intnum *intn, unsigned long val) +{ + if (val > LONG_MAX) { + if (intn->type != INTNUM_BV) { + intn->val.bv = BitVector_Create(BITVECT_NATIVE_SIZE, TRUE); + intn->type = INTNUM_BV; + } + BitVector_Chunk_Store(intn->val.bv, 32, 0, val); + } else { + if (intn->type == INTNUM_BV) { + BitVector_Destroy(intn->val.bv); + intn->type = INTNUM_L; + } + intn->val.l = (long)val; + } +} + +void +yasm_intnum_set_int(yasm_intnum *intn, long val) +{ + if (intn->type == INTNUM_BV) + BitVector_Destroy(intn->val.bv); + intn->type = INTNUM_L; + intn->val.l = val; +} + +int +yasm_intnum_is_zero(const yasm_intnum *intn) +{ + return (intn->type == INTNUM_L && intn->val.l == 0); +} + +int +yasm_intnum_is_pos1(const yasm_intnum *intn) +{ + return (intn->type == INTNUM_L && intn->val.l == 1); +} + +int +yasm_intnum_is_neg1(const yasm_intnum *intn) +{ + return (intn->type == INTNUM_L && intn->val.l == -1); +} + +int +yasm_intnum_sign(const yasm_intnum *intn) +{ + if (intn->type == INTNUM_L) { + if (intn->val.l == 0) + return 0; + else if (intn->val.l < 0) + return -1; + else + return 1; + } else + return BitVector_Sign(intn->val.bv); +} + +unsigned long +yasm_intnum_get_uint(const yasm_intnum *intn) +{ + switch (intn->type) { + case INTNUM_L: + if (intn->val.l < 0) + return 0; + return (unsigned long)intn->val.l; + case INTNUM_BV: + if (BitVector_msb_(intn->val.bv)) + return 0; + if (Set_Max(intn->val.bv) > 32) + return ULONG_MAX; + return BitVector_Chunk_Read(intn->val.bv, 32, 0); + default: + yasm_internal_error(N_("unknown intnum type")); + /*@notreached@*/ + return 0; + } +} + +long +yasm_intnum_get_int(const yasm_intnum *intn) +{ + switch (intn->type) { + case INTNUM_L: + return intn->val.l; + case INTNUM_BV: + if (BitVector_msb_(intn->val.bv)) { + /* it's negative: negate the bitvector to get a positive + * number, then negate the positive number. + */ + unsigned long ul; + + BitVector_Negate(conv_bv, intn->val.bv); + if (Set_Max(conv_bv) >= 32) { + /* too negative */ + return LONG_MIN; + } + ul = BitVector_Chunk_Read(conv_bv, 32, 0); + /* check for too negative */ + return (ul & 0x80000000) ? LONG_MIN : -((long)ul); + } + + /* it's positive, and since it's a BV, it must be >0x7FFFFFFF */ + return LONG_MAX; + default: + yasm_internal_error(N_("unknown intnum type")); + /*@notreached@*/ + return 0; + } +} + +void +yasm_intnum_get_sized(const yasm_intnum *intn, unsigned char *ptr, + size_t destsize, size_t valsize, int shift, + int bigendian, int warn) +{ + wordptr op1 = op1static, op2; + unsigned char *buf; + unsigned int len; + size_t rshift = shift < 0 ? (size_t)(-shift) : 0; + int carry_in; + + /* Currently don't support destinations larger than our native size */ + if (destsize*8 > BITVECT_NATIVE_SIZE) + yasm_internal_error(N_("destination too large")); + + /* General size warnings */ + if (warn<0 && !yasm_intnum_check_size(intn, valsize, rshift, 1)) + yasm_warn_set(YASM_WARN_GENERAL, + N_("value does not fit in signed %d bit field"), + valsize); + if (warn>0 && !yasm_intnum_check_size(intn, valsize, rshift, 2)) + yasm_warn_set(YASM_WARN_GENERAL, + N_("value does not fit in %d bit field"), valsize); + + /* Read the original data into a bitvect */ + if (bigendian) { + /* TODO */ + yasm_internal_error(N_("big endian not implemented")); + } else + BitVector_Block_Store(op1, ptr, (N_int)destsize); + + /* If not already a bitvect, convert value to be written to a bitvect */ + op2 = intnum_tobv(op2static, intn); + + /* Check low bits if right shifting and warnings enabled */ + if (warn && rshift > 0) { + BitVector_Copy(conv_bv, op2); + BitVector_Move_Left(conv_bv, (N_int)(BITVECT_NATIVE_SIZE-rshift)); + if (!BitVector_is_empty(conv_bv)) + yasm_warn_set(YASM_WARN_GENERAL, + N_("misaligned value, truncating to boundary")); + } + + /* Shift right if needed */ + if (rshift > 0) { + carry_in = BitVector_msb_(op2); + while (rshift-- > 0) + BitVector_shift_right(op2, carry_in); + shift = 0; + } + + /* Write the new value into the destination bitvect */ + BitVector_Interval_Copy(op1, op2, (unsigned int)shift, 0, (N_int)valsize); + + /* Write out the new data */ + buf = BitVector_Block_Read(op1, &len); + if (bigendian) { + /* TODO */ + yasm_internal_error(N_("big endian not implemented")); + } else + memcpy(ptr, buf, destsize); + yasm_xfree(buf); +} + +/* Return 1 if okay size, 0 if not */ +int +yasm_intnum_check_size(const yasm_intnum *intn, size_t size, size_t rshift, + int rangetype) +{ + wordptr val; + + /* If not already a bitvect, convert value to a bitvect */ + if (intn->type == INTNUM_BV) { + if (rshift > 0) { + val = conv_bv; + BitVector_Copy(val, intn->val.bv); + } else + val = intn->val.bv; + } else + val = intnum_tobv(conv_bv, intn); + + if (size >= BITVECT_NATIVE_SIZE) + return 1; + + if (rshift > 0) { + int carry_in = BitVector_msb_(val); + while (rshift-- > 0) + BitVector_shift_right(val, carry_in); + } + + if (rangetype > 0) { + if (BitVector_msb_(val)) { + /* it's negative */ + int retval; + + BitVector_Negate(conv_bv, val); + BitVector_dec(conv_bv, conv_bv); + retval = Set_Max(conv_bv) < (long)size-1; + + return retval; + } + + if (rangetype == 1) + size--; + } + return (Set_Max(val) < (long)size); +} + +int +yasm_intnum_in_range(const yasm_intnum *intn, long low, long high) +{ + wordptr val = intnum_tobv(result, intn); + wordptr lval = op1static; + wordptr hval = op2static; + + /* Convert high and low to bitvects */ + BitVector_Empty(lval); + if (low >= 0) + BitVector_Chunk_Store(lval, 32, 0, (unsigned long)low); + else { + BitVector_Chunk_Store(lval, 32, 0, (unsigned long)(-low)); + BitVector_Negate(lval, lval); + } + + BitVector_Empty(hval); + if (high >= 0) + BitVector_Chunk_Store(hval, 32, 0, (unsigned long)high); + else { + BitVector_Chunk_Store(hval, 32, 0, (unsigned long)(-high)); + BitVector_Negate(hval, hval); + } + + /* Compare! */ + return (BitVector_Compare(val, lval) >= 0 + && BitVector_Compare(val, hval) <= 0); +} + +static unsigned long +get_leb128(wordptr val, unsigned char *ptr, int sign) +{ + unsigned long i, size; + unsigned char *ptr_orig = ptr; + + if (sign) { + /* Signed mode */ + if (BitVector_msb_(val)) { + /* Negative */ + BitVector_Negate(conv_bv, val); + size = Set_Max(conv_bv)+2; + } else { + /* Positive */ + size = Set_Max(val)+2; + } + } else { + /* Unsigned mode */ + size = Set_Max(val)+1; + } + + /* Positive/Unsigned write */ + for (i=0; i<size; i += 7) { + *ptr = (unsigned char)BitVector_Chunk_Read(val, 7, i); + *ptr |= 0x80; + ptr++; + } + *(ptr-1) &= 0x7F; /* Clear MSB of last byte */ + return (unsigned long)(ptr-ptr_orig); +} + +static unsigned long +size_leb128(wordptr val, int sign) +{ + if (sign) { + /* Signed mode */ + if (BitVector_msb_(val)) { + /* Negative */ + BitVector_Negate(conv_bv, val); + return (Set_Max(conv_bv)+8)/7; + } else { + /* Positive */ + return (Set_Max(val)+8)/7; + } + } else { + /* Unsigned mode */ + return (Set_Max(val)+7)/7; + } +} + +unsigned long +yasm_intnum_get_leb128(const yasm_intnum *intn, unsigned char *ptr, int sign) +{ + wordptr val; + + /* Shortcut 0 */ + if (intn->type == INTNUM_L && intn->val.l == 0) { + *ptr = 0; + return 1; + } + + /* If not already a bitvect, convert value to be written to a bitvect */ + val = intnum_tobv(op1static, intn); + + return get_leb128(val, ptr, sign); +} + +unsigned long +yasm_intnum_size_leb128(const yasm_intnum *intn, int sign) +{ + wordptr val; + + /* Shortcut 0 */ + if (intn->type == INTNUM_L && intn->val.l == 0) { + return 1; + } + + /* If not already a bitvect, convert value to a bitvect */ + val = intnum_tobv(op1static, intn); + + return size_leb128(val, sign); +} + +unsigned long +yasm_get_sleb128(long v, unsigned char *ptr) +{ + wordptr val = op1static; + + /* Shortcut 0 */ + if (v == 0) { + *ptr = 0; + return 1; + } + + BitVector_Empty(val); + if (v >= 0) + BitVector_Chunk_Store(val, 32, 0, (unsigned long)v); + else { + BitVector_Chunk_Store(val, 32, 0, (unsigned long)(-v)); + BitVector_Negate(val, val); + } + return get_leb128(val, ptr, 1); +} + +unsigned long +yasm_size_sleb128(long v) +{ + wordptr val = op1static; + + if (v == 0) + return 1; + + BitVector_Empty(val); + if (v >= 0) + BitVector_Chunk_Store(val, 32, 0, (unsigned long)v); + else { + BitVector_Chunk_Store(val, 32, 0, (unsigned long)(-v)); + BitVector_Negate(val, val); + } + return size_leb128(val, 1); +} + +unsigned long +yasm_get_uleb128(unsigned long v, unsigned char *ptr) +{ + wordptr val = op1static; + + /* Shortcut 0 */ + if (v == 0) { + *ptr = 0; + return 1; + } + + BitVector_Empty(val); + BitVector_Chunk_Store(val, 32, 0, v); + return get_leb128(val, ptr, 0); +} + +unsigned long +yasm_size_uleb128(unsigned long v) +{ + wordptr val = op1static; + + if (v == 0) + return 1; + + BitVector_Empty(val); + BitVector_Chunk_Store(val, 32, 0, v); + return size_leb128(val, 0); +} + +char * +yasm_intnum_get_str(const yasm_intnum *intn) +{ + unsigned char *s; + + switch (intn->type) { + case INTNUM_L: + s = yasm_xmalloc(16); + sprintf((char *)s, "%ld", intn->val.l); + return (char *)s; + break; + case INTNUM_BV: + return (char *)BitVector_to_Dec(intn->val.bv); + break; + } + /*@notreached@*/ + return NULL; +} + +void +yasm_intnum_print(const yasm_intnum *intn, FILE *f) +{ + unsigned char *s; + + switch (intn->type) { + case INTNUM_L: + fprintf(f, "0x%lx", intn->val.l); + break; + case INTNUM_BV: + s = BitVector_to_Hex(intn->val.bv); + fprintf(f, "0x%s", (char *)s); + yasm_xfree(s); + break; + } +} diff --git a/contrib/tools/yasm/libyasm/intnum.h b/contrib/tools/yasm/libyasm/intnum.h index bec832cf31..b035fc451b 100644 --- a/contrib/tools/yasm/libyasm/intnum.h +++ b/contrib/tools/yasm/libyasm/intnum.h @@ -1,340 +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 +/** + * \file libyasm/intnum.h + * \brief YASM integer number interface. + * + * \license + * Copyright (C) 2001-2007 Peter Johnson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * \endlicense + */ +#ifndef YASM_INTNUM_H +#define YASM_INTNUM_H + +#ifndef YASM_LIB_DECL +#define YASM_LIB_DECL +#endif + +/** Initialize intnum internal data structures. */ +YASM_LIB_DECL +void yasm_intnum_initialize(void); + +/** Clean up internal intnum allocations. */ +YASM_LIB_DECL +void yasm_intnum_cleanup(void); + +/** Create a new intnum from a decimal string. + * \param str decimal string + * \return Newly allocated intnum. + */ +YASM_LIB_DECL +/*@only@*/ yasm_intnum *yasm_intnum_create_dec(char *str); + +/** Create a new intnum from a binary string. + * \param str binary string + * \return Newly allocated intnum. + */ +YASM_LIB_DECL +/*@only@*/ yasm_intnum *yasm_intnum_create_bin(char *str); + +/** Create a new intnum from an octal string. + * \param str octal string + * \return Newly allocated intnum. + */ +YASM_LIB_DECL +/*@only@*/ yasm_intnum *yasm_intnum_create_oct(char *str); + +/** Create a new intnum from a hexidecimal string. + * \param str hexidecimal string + * \return Newly allocated intnum. + */ +YASM_LIB_DECL +/*@only@*/ yasm_intnum *yasm_intnum_create_hex(char *str); + +/** Convert character constant to integer value, using NASM rules. NASM syntax + * supports automatic conversion from strings such as 'abcd' to a 32-bit + * integer value (little endian order). This function performs those conversions. + * \param str character constant string + * \return Newly allocated intnum. + */ +YASM_LIB_DECL +/*@only@*/ yasm_intnum *yasm_intnum_create_charconst_nasm(const char *str); + +/** Convert character constant to integer value, using TASM rules. TASM syntax + * supports automatic conversion from strings such as 'abcd' to a 32-bit + * integer value (big endian order). This function performs those conversions. + * \param str character constant string + * \return Newly allocated intnum. + */ +YASM_LIB_DECL +/*@only@*/ yasm_intnum *yasm_intnum_create_charconst_tasm(const char *str); + +/** Create a new intnum from an unsigned integer value. + * \param i unsigned integer value + * \return Newly allocated intnum. + */ +YASM_LIB_DECL +/*@only@*/ yasm_intnum *yasm_intnum_create_uint(unsigned long i); + +/** Create a new intnum from an signed integer value. + * \param i signed integer value + * \return Newly allocated intnum. + */ +YASM_LIB_DECL +/*@only@*/ yasm_intnum *yasm_intnum_create_int(long i); + +/** Create a new intnum from LEB128-encoded form. + * \param ptr pointer to start of LEB128 encoded form + * \param sign signed (1) or unsigned (0) LEB128 format + * \param size number of bytes read from ptr (output) + * \return Newly allocated intnum. Number of bytes read returned into + * bytes_read parameter. + */ +YASM_LIB_DECL +/*@only@*/ yasm_intnum *yasm_intnum_create_leb128 + (const unsigned char *ptr, int sign, /*@out@*/ unsigned long *size); + +/** Create a new intnum from a little-endian or big-endian buffer. + * In little endian, the LSB is in ptr[0]. + * \param ptr pointer to start of buffer + * \param sign signed (1) or unsigned (0) source + * \param srcsize source buffer size (in bytes) + * \param bigendian endianness (nonzero=big, zero=little) + */ +YASM_LIB_DECL +/*@only@*/ yasm_intnum *yasm_intnum_create_sized + (unsigned char *ptr, int sign, size_t srcsize, int bigendian); + +/** Duplicate an intnum. + * \param intn intnum + * \return Newly allocated intnum with the same value as intn. + */ +YASM_LIB_DECL +/*@only@*/ yasm_intnum *yasm_intnum_copy(const yasm_intnum *intn); + +/** Destroy (free allocated memory for) an intnum. + * \param intn intnum + */ +YASM_LIB_DECL +void yasm_intnum_destroy(/*@only@*/ yasm_intnum *intn); + +/** Floating point calculation function: acc = acc op operand. + * \note Not all operations in yasm_expr_op may be supported; unsupported + * operations will result in an error. + * \param acc intnum accumulator + * \param op operation + * \param operand intnum operand + * \return Nonzero if error occurred. + */ +YASM_LIB_DECL +int yasm_intnum_calc(yasm_intnum *acc, yasm_expr_op op, yasm_intnum *operand); + +/** Compare two intnums. + * \param intn1 first intnum + * \param intn2 second intnum + * \return -1 if intn1 < intn2, 0 if intn1 == intn2, 1 if intn1 > intn2. + */ +YASM_LIB_DECL +int yasm_intnum_compare(const yasm_intnum *intn1, const yasm_intnum *intn2); + +/** Zero an intnum. + * \param intn intnum + */ +YASM_LIB_DECL +void yasm_intnum_zero(yasm_intnum *intn); + +/** Set an intnum to the value of another intnum. + * \param intn intnum + * \param val intnum to get value from + */ +YASM_LIB_DECL +void yasm_intnum_set(yasm_intnum *intn, const yasm_intnum *val); + +/** Set an intnum to an unsigned integer. + * \param intn intnum + * \param val integer value + */ +YASM_LIB_DECL +void yasm_intnum_set_uint(yasm_intnum *intn, unsigned long val); + +/** Set an intnum to an signed integer. + * \param intn intnum + * \param val integer value + */ +YASM_LIB_DECL +void yasm_intnum_set_int(yasm_intnum *intn, long val); + +/** Simple value check for 0. + * \param acc intnum + * \return Nonzero if acc==0. + */ +YASM_LIB_DECL +int yasm_intnum_is_zero(const yasm_intnum *acc); + +/** Simple value check for 1. + * \param acc intnum + * \return Nonzero if acc==1. + */ +YASM_LIB_DECL +int yasm_intnum_is_pos1(const yasm_intnum *acc); + +/** Simple value check for -1. + * \param acc intnum + * \return Nonzero if acc==-1. + */ +YASM_LIB_DECL +int yasm_intnum_is_neg1(const yasm_intnum *acc); + +/** Simple sign check. + * \param acc intnum + * \return -1 if negative, 0 if zero, +1 if positive + */ +YASM_LIB_DECL +int yasm_intnum_sign(const yasm_intnum *acc); + +/** Convert an intnum to an unsigned 32-bit value. The value is in "standard" + * C format (eg, of unknown endian). + * \note Parameter intnum is truncated to fit into 32 bits. Use + * intnum_check_size() to check for overflow. + * \param intn intnum + * \return Unsigned 32-bit value of intn. + */ +YASM_LIB_DECL +unsigned long yasm_intnum_get_uint(const yasm_intnum *intn); + +/** Convert an intnum to a signed 32-bit value. The value is in "standard" C + * format (eg, of unknown endian). + * \note Parameter intnum is truncated to fit into 32 bits. Use + * intnum_check_size() to check for overflow. + * \param intn intnum + * \return Signed 32-bit value of intn. + */ +YASM_LIB_DECL +long yasm_intnum_get_int(const yasm_intnum *intn); + +/** Output #yasm_intnum to buffer in little-endian or big-endian. Puts the + * value into the least significant bits of the destination, or may be shifted + * into more significant bits by the shift parameter. The destination bits are + * cleared before being set. [0] should be the first byte output to the file. + * \param intn intnum + * \param ptr pointer to storage for size bytes of output + * \param destsize destination size (in bytes) + * \param valsize size (in bits) + * \param shift left shift (in bits); may be negative to specify right + * shift (standard warnings include truncation to boundary) + * \param bigendian endianness (nonzero=big, zero=little) + * \param warn enables standard warnings (value doesn't fit into valsize + * bits): <0=signed warnings, >0=unsigned warnings, 0=no warn + */ +YASM_LIB_DECL +void yasm_intnum_get_sized(const yasm_intnum *intn, unsigned char *ptr, + size_t destsize, size_t valsize, int shift, + int bigendian, int warn); + +/** Check to see if intnum will fit without overflow into size bits. + * \param intn intnum + * \param size number of bits of output space + * \param rshift right shift + * \param rangetype signed/unsigned range selection: + * 0 => (0, unsigned max); + * 1 => (signed min, signed max); + * 2 => (signed min, unsigned max) + * \return Nonzero if intnum will fit. + */ +YASM_LIB_DECL +int yasm_intnum_check_size(const yasm_intnum *intn, size_t size, + size_t rshift, int rangetype); + +/** Check to see if intnum will fit into a particular numeric range. + * \param intn intnum + * \param low low end of range (inclusive) + * \param high high end of range (inclusive) + * \return Nonzero if intnum is within range. + */ +YASM_LIB_DECL +int yasm_intnum_in_range(const yasm_intnum *intn, long low, long high); + +/** Output #yasm_intnum to buffer in LEB128-encoded form. + * \param intn intnum + * \param ptr pointer to storage for output bytes + * \param sign signedness of LEB128 encoding (0=unsigned, 1=signed) + * \return Number of bytes generated. + */ +YASM_LIB_DECL +unsigned long yasm_intnum_get_leb128(const yasm_intnum *intn, + unsigned char *ptr, int sign); + +/** Calculate number of bytes LEB128-encoded form of #yasm_intnum will take. + * \param intn intnum + * \param sign signedness of LEB128 encoding (0=unsigned, 1=signed) + * \return Number of bytes. + */ +YASM_LIB_DECL +unsigned long yasm_intnum_size_leb128(const yasm_intnum *intn, int sign); + +/** Output integer to buffer in signed LEB128-encoded form. + * \param v integer + * \param ptr pointer to storage for output bytes + * \return Number of bytes generated. + */ +YASM_LIB_DECL +unsigned long yasm_get_sleb128(long v, unsigned char *ptr); + +/** Calculate number of bytes signed LEB128-encoded form of integer will take. + * \param v integer + * \return Number of bytes. + */ +YASM_LIB_DECL +unsigned long yasm_size_sleb128(long v); + +/** Output integer to buffer in unsigned LEB128-encoded form. + * \param v integer + * \param ptr pointer to storage for output bytes + * \return Number of bytes generated. + */ +YASM_LIB_DECL +unsigned long yasm_get_uleb128(unsigned long v, unsigned char *ptr); + +/** Calculate number of bytes unsigned LEB128-encoded form of integer will take. + * \param v integer + * \return Number of bytes. + */ +YASM_LIB_DECL +unsigned long yasm_size_uleb128(unsigned long v); + +/** Get an intnum as a signed decimal string. The returned string will + * contain a leading '-' if the intnum is negative. + * \param intn intnum + * \return Newly allocated string containing the decimal representation of + * the intnum. + */ +YASM_LIB_DECL +/*@only@*/ char *yasm_intnum_get_str(const yasm_intnum *intn); + +/** Print an intnum. For debugging purposes. + * \param f file + * \param intn intnum + */ +YASM_LIB_DECL +void yasm_intnum_print(const yasm_intnum *intn, FILE *f); + +#endif diff --git a/contrib/tools/yasm/libyasm/inttree.c b/contrib/tools/yasm/libyasm/inttree.c index 2ae10e9b9c..1c21b3ce02 100644 --- a/contrib/tools/yasm/libyasm/inttree.c +++ b/contrib/tools/yasm/libyasm/inttree.c @@ -1,891 +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 */ +#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; - 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); + /* 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); } - } 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); + if (x->right != it->nil) { + np = yasm_xmalloc(sizeof(struct nodeent)); + np->node = x->right; + SLIST_INSERT_HEAD(&stuffToFree, np, link); } - } - } - 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) + 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) { - 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 + 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; - 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 - + DeleteFixUp(it, x); + } else + y->red = z->red; + yasm_xfree(z); +#ifdef CHECK_INTERVAL_TREE_ASSUMPTIONS + IT_CheckAssumptions(it); +#elif defined(DEBUG_ASSERT) + Assert(!it->nil->red,"nil not black in ITDelete"); + Assert((it->nil->maxHigh=LONG_MIN),"nil->maxHigh != LONG_MIN in ITDelete"); +#endif + } else { + FixUpMaxHigh(it, x->parent); + if (!(y->red)) + DeleteFixUp(it, x); + yasm_xfree(y); +#ifdef CHECK_INTERVAL_TREE_ASSUMPTIONS + IT_CheckAssumptions(it); +#elif defined(DEBUG_ASSERT) + Assert(!it->nil->red,"nil not black in ITDelete"); + Assert((it->nil->maxHigh=LONG_MIN),"nil->maxHigh != LONG_MIN in ITDelete"); +#endif + } + return returnValue; +} + + +/***********************************************************************/ +/* FUNCTION: Overlap */ +/**/ +/* INPUTS: [a1,a2] and [b1,b2] are the low and high endpoints of two */ +/* closed intervals. */ +/**/ +/* OUTPUT: stack containing pointers to the nodes between [low,high] */ +/**/ +/* Modifies Input: none */ +/**/ +/* EFFECT: returns 1 if the intervals overlap, and 0 otherwise */ +/***********************************************************************/ + +static int +Overlap(int a1, int a2, int b1, int b2) +{ + if (a1 <= b1) + return (b1 <= a2); + else + return (a1 <= b2); +} + + +/***********************************************************************/ +/* FUNCTION: Enumerate */ +/**/ +/* INPUTS: tree is the tree to look for intervals overlapping the */ +/* closed interval [low,high] */ +/**/ +/* OUTPUT: stack containing pointers to the nodes overlapping */ +/* [low,high] */ +/**/ +/* Modifies Input: none */ +/**/ +/* EFFECT: Returns a stack containing pointers to nodes containing */ +/* intervals which overlap [low,high] in O(max(N,k*log(N))) */ +/* where N is the number of intervals in the tree and k is */ +/* the number of overlapping intervals */ +/**/ +/* Note: This basic idea for this function comes from the */ +/* _Introduction_To_Algorithms_ book by Cormen et al, but */ +/* modifications were made to return all overlapping intervals */ +/* instead of just the first overlapping interval as in the */ +/* book. The natural way to do this would require recursive */ +/* calls of a basic search function. I translated the */ +/* recursive version into an interative version with a stack */ +/* as described below. */ +/***********************************************************************/ + + + +/* The basic idea for the function below is to take the IntervalSearch + * function from the book and modify to find all overlapping intervals + * instead of just one. This means that any time we take the left + * branch down the tree we must also check the right branch if and only if + * we find an overlapping interval in that left branch. Note this is a + * recursive condition because if we go left at the root then go left + * again at the first left child and find an overlap in the left subtree + * of the left child of root we must recursively check the right subtree + * of the left child of root as well as the right child of root. + */ +void +IT_enumerate(IntervalTree *it, long low, long high, void *cbd, + void (*callback) (IntervalTreeNode *node, void *cbd)) +{ + IntervalTreeNode *x=it->root->left; + int stuffToDo = (x != it->nil); + + /* Possible speed up: add min field to prune right searches */ + +#ifdef DEBUG_ASSERT + Assert((it->recursionNodeStackTop == 1), + "recursionStack not empty when entering IntervalTree::Enumerate"); +#endif + it->currentParent = 0; + + while (stuffToDo) { + if (Overlap(low,high,x->low,x->high) ) { + callback(x, cbd); + it->recursionNodeStack[it->currentParent].tryRightBranch=1; + } + if(x->left->maxHigh >= low) { /* implies x != nil */ + if (it->recursionNodeStackTop == it->recursionNodeStackSize) { + it->recursionNodeStackSize *= 2; + it->recursionNodeStack = (it_recursion_node *) + yasm_xrealloc(it->recursionNodeStack, + it->recursionNodeStackSize * sizeof(it_recursion_node)); + } + it->recursionNodeStack[it->recursionNodeStackTop].start_node = x; + it->recursionNodeStack[it->recursionNodeStackTop].tryRightBranch = 0; + it->recursionNodeStack[it->recursionNodeStackTop].parentIndex = it->currentParent; + it->currentParent = it->recursionNodeStackTop++; + x = x->left; + } else { + x = x->right; + } + stuffToDo = (x != it->nil); + while (!stuffToDo && (it->recursionNodeStackTop > 1)) { + if (it->recursionNodeStack[--it->recursionNodeStackTop].tryRightBranch) { + x=it->recursionNodeStack[it->recursionNodeStackTop].start_node->right; + it->currentParent=it->recursionNodeStack[it->recursionNodeStackTop].parentIndex; + it->recursionNodeStack[it->currentParent].tryRightBranch=1; + stuffToDo = (x != it->nil); + } + } + } +#ifdef DEBUG_ASSERT + Assert((it->recursionNodeStackTop == 1), + "recursionStack not empty when exiting IntervalTree::Enumerate"); +#endif +} + +#ifdef CHECK_INTERVAL_TREE_ASSUMPTIONS + +static int +CheckMaxHighFieldsHelper(const IntervalTree *it, IntervalTreeNode *y, + int currentHigh, int match) +{ + if (y != it->nil) { + match = CheckMaxHighFieldsHelper(it, y->left, currentHigh, match) ? + 1 : match; + VERIFY(y->high <= currentHigh); + if (y->high == currentHigh) + match = 1; + match = CheckMaxHighFieldsHelper(it, y->right, currentHigh, match) ? + 1 : match; + } + return match; +} + + + +/* Make sure the maxHigh fields for everything makes sense. * + * If something is wrong, print a warning and exit */ +static void +CheckMaxHighFields(const IntervalTree *it, IntervalTreeNode *x) +{ + if (x != it->nil) { + CheckMaxHighFields(it, x->left); + if(!(CheckMaxHighFieldsHelper(it, x, x->maxHigh, 0) > 0)) { + fprintf(stderr, "error found in CheckMaxHighFields.\n"); + abort(); + } + CheckMaxHighFields(it, x->right); + } +} + +static void +IT_CheckAssumptions(const IntervalTree *it) +{ + VERIFY(it->nil->low == INT_MIN); + VERIFY(it->nil->high == INT_MIN); + VERIFY(it->nil->maxHigh == INT_MIN); + VERIFY(it->root->low == INT_MAX); + VERIFY(it->root->high == INT_MAX); + VERIFY(it->root->maxHigh == INT_MAX); + VERIFY(it->nil->data == NULL); + VERIFY(it->root->data == NULL); + VERIFY(it->nil->red == 0); + VERIFY(it->root->red == 0); + CheckMaxHighFields(it, it->root->left); +} +#endif + diff --git a/contrib/tools/yasm/libyasm/inttree.h b/contrib/tools/yasm/libyasm/inttree.h index f7a7651512..44d45527ec 100644 --- a/contrib/tools/yasm/libyasm/inttree.h +++ b/contrib/tools/yasm/libyasm/inttree.h @@ -1,70 +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 +#ifndef YASM_INTTREE_H +#define YASM_INTTREE_H + +#ifndef YASM_LIB_DECL +#define YASM_LIB_DECL +#endif + +/* The interval_tree.h and interval_tree.cc files contain code for + * interval trees implemented using red-black-trees as described in + * the book _Introduction_To_Algorithms_ by Cormen, Leisserson, + * and Rivest. + */ + +typedef struct IntervalTreeNode { + struct IntervalTreeNode *left, *right, *parent; + void *data; + long low; + long high; + long maxHigh; + int red; /* if red=0 then the node is black */ +} IntervalTreeNode; + +typedef struct it_recursion_node { + /* This structure stores the information needed when we take the + * right branch in searching for intervals but possibly come back + * and check the left branch as well. + */ + IntervalTreeNode *start_node; + unsigned int parentIndex; + int tryRightBranch; +} it_recursion_node; + +typedef struct IntervalTree { + /* A sentinel is used for root and for nil. These sentinels are + * created when ITTreeCreate is called. root->left should always + * point to the node which is the root of the tree. nil points to a + * node which should always be black but has aribtrary children and + * parent and no key or info. The point of using these sentinels is so + * that the root and nil nodes do not require special cases in the code + */ + IntervalTreeNode *root; + IntervalTreeNode *nil; + +/*private:*/ + unsigned int recursionNodeStackSize; + it_recursion_node * recursionNodeStack; + unsigned int currentParent; + unsigned int recursionNodeStackTop; +} IntervalTree; + +YASM_LIB_DECL +IntervalTree *IT_create(void); +YASM_LIB_DECL +void IT_destroy(IntervalTree *); +YASM_LIB_DECL +void IT_print(const IntervalTree *); +YASM_LIB_DECL +void *IT_delete_node(IntervalTree *, IntervalTreeNode *, long *low, + long *high); +YASM_LIB_DECL +IntervalTreeNode *IT_insert(IntervalTree *, long low, long high, void *data); +YASM_LIB_DECL +IntervalTreeNode *IT_get_predecessor(const IntervalTree *, IntervalTreeNode *); +YASM_LIB_DECL +IntervalTreeNode *IT_get_successor(const IntervalTree *, IntervalTreeNode *); +YASM_LIB_DECL +void IT_enumerate(IntervalTree *, long low, long high, void *cbd, + void (*callback) (IntervalTreeNode *node, void *cbd)); + +#endif diff --git a/contrib/tools/yasm/libyasm/linemap.c b/contrib/tools/yasm/libyasm/linemap.c index 42201d3c07..859407ba5e 100644 --- a/contrib/tools/yasm/libyasm/linemap.c +++ b/contrib/tools/yasm/libyasm/linemap.c @@ -1,293 +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)); -} +/* + * YASM assembler virtual line mapping handling (for parse stage) + * + * Copyright (C) 2002-2007 Peter Johnson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include "util.h" + +#include "coretype.h" +#include "hamt.h" + +#include "errwarn.h" +#include "linemap.h" + + +typedef struct line_mapping { + /* monotonically increasing virtual line */ + unsigned long line; + + /* related info */ + /* "original" source filename */ + /*@null@*/ /*@dependent@*/ const char *filename; + /* "original" source base line number */ + unsigned long file_line; + /* "original" source line number increment (for following lines) */ + unsigned long line_inc; +} line_mapping; + +typedef struct line_source_info { + /* first bytecode on line; NULL if no bytecodes on line */ + /*@null@*/ /*@dependent@*/ yasm_bytecode *bc; + + /* source code line */ + /*@owned@*/ char *source; +} line_source_info; + +struct yasm_linemap { + /* Shared storage for filenames */ + /*@only@*/ /*@null@*/ HAMT *filenames; + + /* Current virtual line number. */ + unsigned long current; + + /* Mappings from virtual to physical line numbers */ + struct line_mapping *map_vector; + unsigned long map_size; + unsigned long map_allocated; + + /* Bytecode and source line information */ + /*@only@*/ line_source_info *source_info; + size_t source_info_size; +}; + +static void +filename_delete_one(/*@only@*/ void *d) +{ + yasm_xfree(d); +} + +void +yasm_linemap_set(yasm_linemap *linemap, const char *filename, + unsigned long virtual_line, unsigned long file_line, + unsigned long line_inc) +{ + char *copy; + unsigned long i; + int replace = 0; + line_mapping *mapping = NULL; + + if (virtual_line == 0) { + virtual_line = linemap->current; + } + + /* Replace all existing mappings that have line numbers >= this one. */ + for (i = linemap->map_size; i > 0; i--) { + if (linemap->map_vector[i-1].line < virtual_line) { + if (i < linemap->map_size) { + mapping = &linemap->map_vector[i]; + linemap->map_size = i + 1; + } + break; + } + } + + if (mapping == NULL) { + /* Create a new mapping in the map */ + if (linemap->map_size >= linemap->map_allocated) { + /* allocate another size bins when full for 2x space */ + linemap->map_vector = yasm_xrealloc(linemap->map_vector, + 2*linemap->map_allocated*sizeof(line_mapping)); + linemap->map_allocated *= 2; + } + mapping = &linemap->map_vector[linemap->map_size]; + linemap->map_size++; + } + + /* Fill it */ + + if (!filename) { + if (linemap->map_size >= 2) + mapping->filename = + linemap->map_vector[linemap->map_size-2].filename; + else + filename = "unknown"; + } + if (filename) { + /* Copy the filename (via shared storage) */ + copy = yasm__xstrdup(filename); + /*@-aliasunique@*/ + mapping->filename = HAMT_insert(linemap->filenames, copy, copy, + &replace, filename_delete_one); + /*@=aliasunique@*/ + } + + mapping->line = virtual_line; + mapping->file_line = file_line; + mapping->line_inc = line_inc; +} + +unsigned long +yasm_linemap_poke(yasm_linemap *linemap, const char *filename, + unsigned long file_line) +{ + unsigned long line; + line_mapping *mapping; + + linemap->current++; + yasm_linemap_set(linemap, filename, 0, file_line, 0); + + mapping = &linemap->map_vector[linemap->map_size-1]; + + line = linemap->current; + + linemap->current++; + yasm_linemap_set(linemap, mapping->filename, 0, + mapping->file_line + + mapping->line_inc*(linemap->current-2-mapping->line), + mapping->line_inc); + + return line; +} + +yasm_linemap * +yasm_linemap_create(void) +{ + size_t i; + yasm_linemap *linemap = yasm_xmalloc(sizeof(yasm_linemap)); + + linemap->filenames = HAMT_create(0, yasm_internal_error_); + + linemap->current = 1; + + /* initialize mapping vector */ + linemap->map_vector = yasm_xmalloc(8*sizeof(line_mapping)); + linemap->map_size = 0; + linemap->map_allocated = 8; + + /* initialize source line information array */ + linemap->source_info_size = 2; + linemap->source_info = yasm_xmalloc(linemap->source_info_size * + sizeof(line_source_info)); + for (i=0; i<linemap->source_info_size; i++) { + linemap->source_info[i].bc = NULL; + linemap->source_info[i].source = NULL; + } + + return linemap; +} + +void +yasm_linemap_destroy(yasm_linemap *linemap) +{ + size_t i; + for (i=0; i<linemap->source_info_size; i++) { + if (linemap->source_info[i].source) + yasm_xfree(linemap->source_info[i].source); + } + yasm_xfree(linemap->source_info); + + yasm_xfree(linemap->map_vector); + + if (linemap->filenames) + HAMT_destroy(linemap->filenames, filename_delete_one); + + yasm_xfree(linemap); +} + +unsigned long +yasm_linemap_get_current(yasm_linemap *linemap) +{ + return linemap->current; +} + +void +yasm_linemap_add_source(yasm_linemap *linemap, yasm_bytecode *bc, + const char *source) +{ + size_t i; + + while (linemap->current > linemap->source_info_size) { + /* allocate another size bins when full for 2x space */ + linemap->source_info = yasm_xrealloc(linemap->source_info, + 2*linemap->source_info_size*sizeof(line_source_info)); + for (i=linemap->source_info_size; i<linemap->source_info_size*2; i++) { + linemap->source_info[i].bc = NULL; + linemap->source_info[i].source = NULL; + } + linemap->source_info_size *= 2; + } + + /* Delete existing info for that line (if any) */ + if (linemap->source_info[linemap->current-1].source) + yasm_xfree(linemap->source_info[linemap->current-1].source); + + linemap->source_info[linemap->current-1].bc = bc; + linemap->source_info[linemap->current-1].source = yasm__xstrdup(source); +} + +unsigned long +yasm_linemap_goto_next(yasm_linemap *linemap) +{ + return ++(linemap->current); +} + +void +yasm_linemap_lookup(yasm_linemap *linemap, unsigned long line, + const char **filename, unsigned long *file_line) +{ + line_mapping *mapping; + unsigned long vindex, step; + + assert(line <= linemap->current); + + /* Binary search through map to find highest line_index <= index */ + vindex = 0; + /* start step as the greatest power of 2 <= size */ + step = 1; + while (step*2<=linemap->map_size) + step*=2; + while (step>0) { + if (vindex+step < linemap->map_size + && linemap->map_vector[vindex+step].line <= line) + vindex += step; + step /= 2; + } + mapping = &linemap->map_vector[vindex]; + + *filename = mapping->filename; + *file_line = (line ? mapping->file_line + mapping->line_inc*(line-mapping->line) : 0); +} + +int +yasm_linemap_traverse_filenames(yasm_linemap *linemap, /*@null@*/ void *d, + int (*func) (const char *filename, void *d)) +{ + return HAMT_traverse(linemap->filenames, d, (int (*) (void *, void *))func); +} + +int +yasm_linemap_get_source(yasm_linemap *linemap, unsigned long line, + yasm_bytecode **bcp, const char **sourcep) +{ + if (line > linemap->source_info_size) { + *bcp = NULL; + *sourcep = NULL; + return 1; + } + + *bcp = linemap->source_info[line-1].bc; + *sourcep = linemap->source_info[line-1].source; + + return (!(*sourcep)); +} diff --git a/contrib/tools/yasm/libyasm/linemap.h b/contrib/tools/yasm/libyasm/linemap.h index 1c5aa4626a..2a9b140e42 100644 --- a/contrib/tools/yasm/libyasm/linemap.h +++ b/contrib/tools/yasm/libyasm/linemap.h @@ -1,141 +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 +/** + * \file libyasm/linemap.h + * \brief YASM virtual line mapping interface. + * + * \license + * Copyright (C) 2002-2007 Peter Johnson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * \endlicense + */ +#ifndef YASM_LINEMAP_H +#define YASM_LINEMAP_H + +#ifndef YASM_LIB_DECL +#define YASM_LIB_DECL +#endif + +/** Create a new line mapping repository. + * \return New repository. + */ +YASM_LIB_DECL +yasm_linemap *yasm_linemap_create(void); + +/** Clean up any memory allocated for a repository. + * \param linemap line mapping repository + */ +YASM_LIB_DECL +void yasm_linemap_destroy(yasm_linemap *linemap); + +/** Get the current line position in a repository. + * \param linemap line mapping repository + * \return Current virtual line. + */ +YASM_LIB_DECL +unsigned long yasm_linemap_get_current(yasm_linemap *linemap); + +/** Get bytecode and source line information, if any, for a virtual line. + * \param linemap line mapping repository + * \param line virtual line + * \param bcp pointer to return bytecode into + * \param sourcep pointer to return source code line pointer into + * \return Zero if source line information available for line, nonzero if not. + * \note If source line information is not available, bcp and sourcep targets + * are set to NULL. + */ +YASM_LIB_DECL +int yasm_linemap_get_source(yasm_linemap *linemap, unsigned long line, + /*@null@*/ yasm_bytecode **bcp, + const char **sourcep); + +/** Add bytecode and source line information to the current virtual line. + * \attention Deletes any existing bytecode and source line information for + * the current virtual line. + * \param linemap line mapping repository + * \param bc bytecode (if any) + * \param source source code line + * \note The source code line pointer is NOT kept, it is strdup'ed. + */ +YASM_LIB_DECL +void yasm_linemap_add_source(yasm_linemap *linemap, + /*@null@*/ yasm_bytecode *bc, + const char *source); + +/** Go to the next line (increments the current virtual line). + * \param linemap line mapping repository + * \return The current (new) virtual line. + */ +YASM_LIB_DECL +unsigned long yasm_linemap_goto_next(yasm_linemap *linemap); + +/** Set a new file/line physical association starting point at the specified + * virtual line. line_inc indicates how much the "real" line is incremented + * by for each virtual line increment (0 is perfectly legal). + * \param linemap line mapping repository + * \param filename physical file name (if NULL, not changed) + * \param virtual_line virtual line number (if 0, linemap->current is used) + * \param file_line physical line number + * \param line_inc line increment + */ +YASM_LIB_DECL +void yasm_linemap_set(yasm_linemap *linemap, /*@null@*/ const char *filename, + unsigned long virtual_line, unsigned long file_line, + unsigned long line_inc); + +/** Poke a single file/line association, restoring the original physical + * association starting point. Caution: increments the current virtual line + * twice. + * \param linemap line mapping repository + * \param filename physical file name (if NULL, not changed) + * \param file_line physical line number + * \return The virtual line number of the poked association. + */ +YASM_LIB_DECL +unsigned long yasm_linemap_poke(yasm_linemap *linemap, + /*@null@*/ const char *filename, + unsigned long file_line); + +/** Look up the associated physical file and line for a virtual line. + * \param linemap line mapping repository + * \param line virtual line + * \param filename physical file name (output) + * \param file_line physical line number (output) + */ +YASM_LIB_DECL +void yasm_linemap_lookup(yasm_linemap *linemap, unsigned long line, + /*@out@*/ const char **filename, + /*@out@*/ unsigned long *file_line); + +/** Traverses all filenames used in a linemap, calling a function on each + * filename. + * \param linemap line mapping repository + * \param d data pointer passed to func on each call + * \param func function + * \return Stops early (and returns func's return value) if func returns a + * nonzero value; otherwise 0. + */ +YASM_LIB_DECL +int yasm_linemap_traverse_filenames + (yasm_linemap *linemap, /*@null@*/ void *d, + int (*func) (const char *filename, void *d)); + +#endif diff --git a/contrib/tools/yasm/libyasm/listfmt.h b/contrib/tools/yasm/libyasm/listfmt.h index 945f28e58b..c428de3628 100644 --- a/contrib/tools/yasm/libyasm/listfmt.h +++ b/contrib/tools/yasm/libyasm/listfmt.h @@ -1,124 +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 +/** + * \file libyasm/listfmt.h + * \brief YASM list format interface. + * + * \license + * Copyright (C) 2004-2007 Peter Johnson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * \endlicense + */ +#ifndef YASM_LISTFMT_H +#define YASM_LISTFMT_H + +#ifndef YASM_DOXYGEN +/** Base #yasm_listfmt structure. Must be present as the first element in any + * #yasm_listfmt implementation. + */ +typedef struct yasm_listfmt_base { + /** #yasm_listfmt_module implementation for this list format. */ + const struct yasm_listfmt_module *module; +} yasm_listfmt_base; +#endif + +/** YASM list format module interface. */ +typedef struct yasm_listfmt_module { + /** One-line description of the list format. */ + const char *name; + + /** Keyword used to select list format. */ + const char *keyword; + + /** Create list format. + * Module-level implementation of yasm_listfmt_create(). + * The filenames are provided solely for informational purposes. + * \param in_filename primary input filename + * \param obj_filename object filename + * \return NULL if unable to initialize. + */ + /*@null@*/ /*@only@*/ yasm_listfmt * (*create) + (const char *in_filename, const char *obj_filename); + + /** Module-level implementation of yasm_listfmt_destroy(). + * Call yasm_listfmt_destroy() instead of calling this function. + */ + void (*destroy) (/*@only@*/ yasm_listfmt *listfmt); + + /** Module-level implementation of yasm_listfmt_output(). + * Call yasm_listfmt_output() instead of calling this function. + */ + void (*output) (yasm_listfmt *listfmt, FILE *f, yasm_linemap *linemap, + yasm_arch *arch); +} yasm_listfmt_module; + +/** Get the keyword used to select a list format. + * \param listfmt list format + * \return keyword + */ +const char *yasm_listfmt_keyword(const yasm_listfmt *listfmt); + +/** Initialize list format for use. Must call before any other list + * format functions. The filenames are provided solely for informational + * purposes. + * \param module list format module + * \param in_filename primary input filename + * \param obj_filename object filename + * \return NULL if object format does not provide needed support. + */ +/*@null@*/ /*@only@*/ yasm_listfmt *yasm_listfmt_create + (const yasm_listfmt_module *module, const char *in_filename, + const char *obj_filename); + +/** Cleans up any allocated list format memory. + * \param listfmt list format + */ +void yasm_listfmt_destroy(/*@only@*/ yasm_listfmt *listfmt); + +/** Write out list to the list file. + * This function may call all read-only yasm_* functions as necessary. + * \param listfmt list format + * \param f output list file + * \param linemap line mapping repository + * \param arch architecture + */ +void yasm_listfmt_output(yasm_listfmt *listfmt, FILE *f, + yasm_linemap *linemap, yasm_arch *arch); + +#ifndef YASM_DOXYGEN + +/* Inline macro implementations for listfmt functions */ + +#define yasm_listfmt_keyword(listfmt) \ + (((yasm_listfmt_base *)listfmt)->module->keyword) + +#define yasm_listfmt_create(module, in_filename, obj_filename) \ + module->create(in_filename, obj_filename) + +#define yasm_listfmt_destroy(listfmt) \ + ((yasm_listfmt_base *)listfmt)->module->destroy(listfmt) + +#define yasm_listfmt_output(listfmt, f, linemap, a) \ + ((yasm_listfmt_base *)listfmt)->module->output(listfmt, f, linemap, a) + +#endif + +#endif diff --git a/contrib/tools/yasm/libyasm/md5.c b/contrib/tools/yasm/libyasm/md5.c index b009842f5c..c188c453e7 100644 --- a/contrib/tools/yasm/libyasm/md5.c +++ b/contrib/tools/yasm/libyasm/md5.c @@ -1,309 +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]) -{ +/* + * This code implements the MD5 message-digest algorithm. + * The algorithm is due to Ron Rivest. This code was + * written by Colin Plumb in 1993, no copyright is claimed. + * This code is in the public domain; do with it what you wish. + * + * Equivalent code is available from RSA Data Security, Inc. + * This code has been tested against that, and is equivalent, + * except that you don't need to include two pages of legalese + * with every copy. + * + * To compute the message digest of a chunk of bytes, declare an + * MD5Context structure, pass it to MD5Init, call MD5Update as + * needed on buffers full of bytes, and then call MD5Final, which + * will fill a supplied 16-byte array with the digest. + */ + +/* This code was modified in 1997 by Jim Kingdon of Cyclic Software to + not require an integer type which is exactly 32 bits. This work + draws on the changes for the same purpose by Tatu Ylonen + <ylo@cs.hut.fi> as part of SSH, but since I didn't actually use + that code, there is no copyright issue. I hereby disclaim + copyright in any changes I have made; this code remains in the + public domain. */ + +/* Note regarding cvs_* namespace: this avoids potential conflicts + with libraries such as some versions of Kerberos. No particular + need to worry about whether the system supplies an MD5 library, as + this file is only about 3k of object code. */ + +#include <util.h> + +#include "md5.h" + +/* Little-endian byte-swapping routines. Note that these do not + depend on the size of datatypes such as cvs_uint32, nor do they require + us to detect the endianness of the machine we are running on. It + is possible they should be macros for speed, but I would be + surprised if they were a performance bottleneck for MD5. */ + +static unsigned long +getu32(const unsigned char *addr) +{ + return (((((unsigned long)addr[3] << 8) | addr[2]) << 8) + | addr[1]) << 8 | addr[0]; +} + +static void +putu32(unsigned long data, unsigned char *addr) +{ + addr[0] = (unsigned char)data; + addr[1] = (unsigned char)(data >> 8); + addr[2] = (unsigned char)(data >> 16); + addr[3] = (unsigned char)(data >> 24); +} + +/* + * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious + * initialization constants. + */ +void +yasm_md5_init(yasm_md5_context *ctx) +{ + ctx->buf[0] = 0x67452301; + ctx->buf[1] = 0xefcdab89; + ctx->buf[2] = 0x98badcfe; + ctx->buf[3] = 0x10325476; + + ctx->bits[0] = 0; + ctx->bits[1] = 0; +} + +/* + * Update context to reflect the concatenation of another buffer full + * of bytes. + */ +void +yasm_md5_update(yasm_md5_context *ctx, unsigned char const *buf, + unsigned long len) +{ + unsigned long t; + + /* Update bitcount */ + + t = ctx->bits[0]; + if ((ctx->bits[0] = (t + ((unsigned long)len << 3)) & 0xffffffff) < t) + ctx->bits[1]++; /* Carry from low to high */ + ctx->bits[1] += len >> 29; + + t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ + + /* Handle any leading odd-sized chunks */ + + if ( t ) { + unsigned char *p = ctx->in + t; + + t = 64-t; + if (len < t) { + memcpy(p, buf, len); + return; + } + memcpy(p, buf, t); + yasm_md5_transform (ctx->buf, ctx->in); + buf += t; + len -= t; + } + + /* Process data in 64-byte chunks */ + + while (len >= 64) { + memcpy(ctx->in, buf, 64); + yasm_md5_transform (ctx->buf, ctx->in); + buf += 64; + len -= 64; + } + + /* Handle any remaining bytes of data. */ + + memcpy(ctx->in, buf, len); +} + +/* + * Final wrapup - pad to 64-byte boundary with the bit pattern + * 1 0* (64-bit count of bits processed, MSB-first) + */ +void +yasm_md5_final(unsigned char digest[16], yasm_md5_context *ctx) +{ + unsigned count; + unsigned char *p; + + /* Compute number of bytes mod 64 */ + count = (ctx->bits[0] >> 3) & 0x3F; + + /* Set the first char of padding to 0x80. This is safe since there is + always at least one byte free */ + p = ctx->in + count; + *p++ = 0x80; + + /* Bytes of padding needed to make 64 bytes */ + count = 64 - 1 - count; + + /* Pad out to 56 mod 64 */ + if (count < 8) { + /* Two lots of padding: Pad the first block to 64 bytes */ + memset(p, 0, count); + yasm_md5_transform (ctx->buf, ctx->in); + + /* Now fill the next block with 56 bytes */ + memset(ctx->in, 0, 56); + } else { + /* Pad block to 56 bytes */ + memset(p, 0, count-8); + } + + /* Append length in bits and transform */ + putu32(ctx->bits[0], ctx->in + 56); + putu32(ctx->bits[1], ctx->in + 60); + + yasm_md5_transform (ctx->buf, ctx->in); + putu32(ctx->buf[0], digest); + putu32(ctx->buf[1], digest + 4); + putu32(ctx->buf[2], digest + 8); + putu32(ctx->buf[3], digest + 12); + memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */ +} + +#ifndef ASM_MD5 + +/* The four core functions - F1 is optimized somewhat */ + +/* #define F1(x, y, z) (x & y | ~x & z) */ +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + +/* This is the central step in the MD5 algorithm. */ +#define MD5STEP(f, w, x, y, z, data, s) \ + ( w += f(x, y, z) + data, w &= 0xffffffff, w = w<<s | w>>(32-s), w += x ) + +/* + * The core of the MD5 algorithm, this alters an existing MD5 hash to + * reflect the addition of 16 longwords of new data. MD5Update blocks + * the data and converts bytes into longwords for this routine. + */ +void +yasm_md5_transform(unsigned long buf[4], const unsigned char inraw[64]) +{ unsigned long a, b, c, d; - unsigned long in[16]; - int i; - - for (i = 0; i < 16; ++i) - in[i] = getu32 (inraw + 4 * i); - - a = buf[0]; - b = buf[1]; - c = buf[2]; - d = buf[3]; - - MD5STEP(F1, a, b, c, d, in[ 0]+0xd76aa478, 7); - MD5STEP(F1, d, a, b, c, in[ 1]+0xe8c7b756, 12); - MD5STEP(F1, c, d, a, b, in[ 2]+0x242070db, 17); - MD5STEP(F1, b, c, d, a, in[ 3]+0xc1bdceee, 22); - MD5STEP(F1, a, b, c, d, in[ 4]+0xf57c0faf, 7); - MD5STEP(F1, d, a, b, c, in[ 5]+0x4787c62a, 12); - MD5STEP(F1, c, d, a, b, in[ 6]+0xa8304613, 17); - MD5STEP(F1, b, c, d, a, in[ 7]+0xfd469501, 22); - MD5STEP(F1, a, b, c, d, in[ 8]+0x698098d8, 7); - MD5STEP(F1, d, a, b, c, in[ 9]+0x8b44f7af, 12); - MD5STEP(F1, c, d, a, b, in[10]+0xffff5bb1, 17); - MD5STEP(F1, b, c, d, a, in[11]+0x895cd7be, 22); - MD5STEP(F1, a, b, c, d, in[12]+0x6b901122, 7); - MD5STEP(F1, d, a, b, c, in[13]+0xfd987193, 12); - MD5STEP(F1, c, d, a, b, in[14]+0xa679438e, 17); - MD5STEP(F1, b, c, d, a, in[15]+0x49b40821, 22); - - MD5STEP(F2, a, b, c, d, in[ 1]+0xf61e2562, 5); - MD5STEP(F2, d, a, b, c, in[ 6]+0xc040b340, 9); - MD5STEP(F2, c, d, a, b, in[11]+0x265e5a51, 14); - MD5STEP(F2, b, c, d, a, in[ 0]+0xe9b6c7aa, 20); - MD5STEP(F2, a, b, c, d, in[ 5]+0xd62f105d, 5); - MD5STEP(F2, d, a, b, c, in[10]+0x02441453, 9); - MD5STEP(F2, c, d, a, b, in[15]+0xd8a1e681, 14); - MD5STEP(F2, b, c, d, a, in[ 4]+0xe7d3fbc8, 20); - MD5STEP(F2, a, b, c, d, in[ 9]+0x21e1cde6, 5); - MD5STEP(F2, d, a, b, c, in[14]+0xc33707d6, 9); - MD5STEP(F2, c, d, a, b, in[ 3]+0xf4d50d87, 14); - MD5STEP(F2, b, c, d, a, in[ 8]+0x455a14ed, 20); - MD5STEP(F2, a, b, c, d, in[13]+0xa9e3e905, 5); - MD5STEP(F2, d, a, b, c, in[ 2]+0xfcefa3f8, 9); - MD5STEP(F2, c, d, a, b, in[ 7]+0x676f02d9, 14); - MD5STEP(F2, b, c, d, a, in[12]+0x8d2a4c8a, 20); - - MD5STEP(F3, a, b, c, d, in[ 5]+0xfffa3942, 4); - MD5STEP(F3, d, a, b, c, in[ 8]+0x8771f681, 11); - MD5STEP(F3, c, d, a, b, in[11]+0x6d9d6122, 16); - MD5STEP(F3, b, c, d, a, in[14]+0xfde5380c, 23); - MD5STEP(F3, a, b, c, d, in[ 1]+0xa4beea44, 4); - MD5STEP(F3, d, a, b, c, in[ 4]+0x4bdecfa9, 11); - MD5STEP(F3, c, d, a, b, in[ 7]+0xf6bb4b60, 16); - MD5STEP(F3, b, c, d, a, in[10]+0xbebfbc70, 23); - MD5STEP(F3, a, b, c, d, in[13]+0x289b7ec6, 4); - MD5STEP(F3, d, a, b, c, in[ 0]+0xeaa127fa, 11); - MD5STEP(F3, c, d, a, b, in[ 3]+0xd4ef3085, 16); - MD5STEP(F3, b, c, d, a, in[ 6]+0x04881d05, 23); - MD5STEP(F3, a, b, c, d, in[ 9]+0xd9d4d039, 4); - MD5STEP(F3, d, a, b, c, in[12]+0xe6db99e5, 11); - MD5STEP(F3, c, d, a, b, in[15]+0x1fa27cf8, 16); - MD5STEP(F3, b, c, d, a, in[ 2]+0xc4ac5665, 23); - - MD5STEP(F4, a, b, c, d, in[ 0]+0xf4292244, 6); - MD5STEP(F4, d, a, b, c, in[ 7]+0x432aff97, 10); - MD5STEP(F4, c, d, a, b, in[14]+0xab9423a7, 15); - MD5STEP(F4, b, c, d, a, in[ 5]+0xfc93a039, 21); - MD5STEP(F4, a, b, c, d, in[12]+0x655b59c3, 6); - MD5STEP(F4, d, a, b, c, in[ 3]+0x8f0ccc92, 10); - MD5STEP(F4, c, d, a, b, in[10]+0xffeff47d, 15); - MD5STEP(F4, b, c, d, a, in[ 1]+0x85845dd1, 21); - MD5STEP(F4, a, b, c, d, in[ 8]+0x6fa87e4f, 6); - MD5STEP(F4, d, a, b, c, in[15]+0xfe2ce6e0, 10); - MD5STEP(F4, c, d, a, b, in[ 6]+0xa3014314, 15); - MD5STEP(F4, b, c, d, a, in[13]+0x4e0811a1, 21); - MD5STEP(F4, a, b, c, d, in[ 4]+0xf7537e82, 6); - MD5STEP(F4, d, a, b, c, in[11]+0xbd3af235, 10); - MD5STEP(F4, c, d, a, b, in[ 2]+0x2ad7d2bb, 15); - MD5STEP(F4, b, c, d, a, in[ 9]+0xeb86d391, 21); - - buf[0] += a; - buf[1] += b; - buf[2] += c; - buf[3] += d; -} -#endif - -#ifdef TEST -/* Simple test program. Can use it to manually run the tests from - RFC1321 for example. */ -#include <stdio.h> - -int -main (int argc, char **argv) -{ - yasm_md5_context context; - unsigned char checksum[16]; - int i; - int j; - - if (argc < 2) - { - fprintf (stderr, "usage: %s string-to-hash\n", argv[0]); - exit (1); - } - for (j = 1; j < argc; ++j) - { - printf ("MD5 (\"%s\") = ", argv[j]); - yasm_md5_init (&context); - yasm_md5_update (&context, argv[j], strlen (argv[j])); - yasm_md5_final (checksum, &context); - for (i = 0; i < 16; i++) - { - printf ("%02x", (unsigned int) checksum[i]); - } - printf ("\n"); - } - return 0; -} -#endif /* TEST */ + unsigned long in[16]; + int i; + + for (i = 0; i < 16; ++i) + in[i] = getu32 (inraw + 4 * i); + + a = buf[0]; + b = buf[1]; + c = buf[2]; + d = buf[3]; + + MD5STEP(F1, a, b, c, d, in[ 0]+0xd76aa478, 7); + MD5STEP(F1, d, a, b, c, in[ 1]+0xe8c7b756, 12); + MD5STEP(F1, c, d, a, b, in[ 2]+0x242070db, 17); + MD5STEP(F1, b, c, d, a, in[ 3]+0xc1bdceee, 22); + MD5STEP(F1, a, b, c, d, in[ 4]+0xf57c0faf, 7); + MD5STEP(F1, d, a, b, c, in[ 5]+0x4787c62a, 12); + MD5STEP(F1, c, d, a, b, in[ 6]+0xa8304613, 17); + MD5STEP(F1, b, c, d, a, in[ 7]+0xfd469501, 22); + MD5STEP(F1, a, b, c, d, in[ 8]+0x698098d8, 7); + MD5STEP(F1, d, a, b, c, in[ 9]+0x8b44f7af, 12); + MD5STEP(F1, c, d, a, b, in[10]+0xffff5bb1, 17); + MD5STEP(F1, b, c, d, a, in[11]+0x895cd7be, 22); + MD5STEP(F1, a, b, c, d, in[12]+0x6b901122, 7); + MD5STEP(F1, d, a, b, c, in[13]+0xfd987193, 12); + MD5STEP(F1, c, d, a, b, in[14]+0xa679438e, 17); + MD5STEP(F1, b, c, d, a, in[15]+0x49b40821, 22); + + MD5STEP(F2, a, b, c, d, in[ 1]+0xf61e2562, 5); + MD5STEP(F2, d, a, b, c, in[ 6]+0xc040b340, 9); + MD5STEP(F2, c, d, a, b, in[11]+0x265e5a51, 14); + MD5STEP(F2, b, c, d, a, in[ 0]+0xe9b6c7aa, 20); + MD5STEP(F2, a, b, c, d, in[ 5]+0xd62f105d, 5); + MD5STEP(F2, d, a, b, c, in[10]+0x02441453, 9); + MD5STEP(F2, c, d, a, b, in[15]+0xd8a1e681, 14); + MD5STEP(F2, b, c, d, a, in[ 4]+0xe7d3fbc8, 20); + MD5STEP(F2, a, b, c, d, in[ 9]+0x21e1cde6, 5); + MD5STEP(F2, d, a, b, c, in[14]+0xc33707d6, 9); + MD5STEP(F2, c, d, a, b, in[ 3]+0xf4d50d87, 14); + MD5STEP(F2, b, c, d, a, in[ 8]+0x455a14ed, 20); + MD5STEP(F2, a, b, c, d, in[13]+0xa9e3e905, 5); + MD5STEP(F2, d, a, b, c, in[ 2]+0xfcefa3f8, 9); + MD5STEP(F2, c, d, a, b, in[ 7]+0x676f02d9, 14); + MD5STEP(F2, b, c, d, a, in[12]+0x8d2a4c8a, 20); + + MD5STEP(F3, a, b, c, d, in[ 5]+0xfffa3942, 4); + MD5STEP(F3, d, a, b, c, in[ 8]+0x8771f681, 11); + MD5STEP(F3, c, d, a, b, in[11]+0x6d9d6122, 16); + MD5STEP(F3, b, c, d, a, in[14]+0xfde5380c, 23); + MD5STEP(F3, a, b, c, d, in[ 1]+0xa4beea44, 4); + MD5STEP(F3, d, a, b, c, in[ 4]+0x4bdecfa9, 11); + MD5STEP(F3, c, d, a, b, in[ 7]+0xf6bb4b60, 16); + MD5STEP(F3, b, c, d, a, in[10]+0xbebfbc70, 23); + MD5STEP(F3, a, b, c, d, in[13]+0x289b7ec6, 4); + MD5STEP(F3, d, a, b, c, in[ 0]+0xeaa127fa, 11); + MD5STEP(F3, c, d, a, b, in[ 3]+0xd4ef3085, 16); + MD5STEP(F3, b, c, d, a, in[ 6]+0x04881d05, 23); + MD5STEP(F3, a, b, c, d, in[ 9]+0xd9d4d039, 4); + MD5STEP(F3, d, a, b, c, in[12]+0xe6db99e5, 11); + MD5STEP(F3, c, d, a, b, in[15]+0x1fa27cf8, 16); + MD5STEP(F3, b, c, d, a, in[ 2]+0xc4ac5665, 23); + + MD5STEP(F4, a, b, c, d, in[ 0]+0xf4292244, 6); + MD5STEP(F4, d, a, b, c, in[ 7]+0x432aff97, 10); + MD5STEP(F4, c, d, a, b, in[14]+0xab9423a7, 15); + MD5STEP(F4, b, c, d, a, in[ 5]+0xfc93a039, 21); + MD5STEP(F4, a, b, c, d, in[12]+0x655b59c3, 6); + MD5STEP(F4, d, a, b, c, in[ 3]+0x8f0ccc92, 10); + MD5STEP(F4, c, d, a, b, in[10]+0xffeff47d, 15); + MD5STEP(F4, b, c, d, a, in[ 1]+0x85845dd1, 21); + MD5STEP(F4, a, b, c, d, in[ 8]+0x6fa87e4f, 6); + MD5STEP(F4, d, a, b, c, in[15]+0xfe2ce6e0, 10); + MD5STEP(F4, c, d, a, b, in[ 6]+0xa3014314, 15); + MD5STEP(F4, b, c, d, a, in[13]+0x4e0811a1, 21); + MD5STEP(F4, a, b, c, d, in[ 4]+0xf7537e82, 6); + MD5STEP(F4, d, a, b, c, in[11]+0xbd3af235, 10); + MD5STEP(F4, c, d, a, b, in[ 2]+0x2ad7d2bb, 15); + MD5STEP(F4, b, c, d, a, in[ 9]+0xeb86d391, 21); + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} +#endif + +#ifdef TEST +/* Simple test program. Can use it to manually run the tests from + RFC1321 for example. */ +#include <stdio.h> + +int +main (int argc, char **argv) +{ + yasm_md5_context context; + unsigned char checksum[16]; + int i; + int j; + + if (argc < 2) + { + fprintf (stderr, "usage: %s string-to-hash\n", argv[0]); + exit (1); + } + for (j = 1; j < argc; ++j) + { + printf ("MD5 (\"%s\") = ", argv[j]); + yasm_md5_init (&context); + yasm_md5_update (&context, argv[j], strlen (argv[j])); + yasm_md5_final (checksum, &context); + for (i = 0; i < 16; i++) + { + printf ("%02x", (unsigned int) checksum[i]); + } + printf ("\n"); + } + return 0; +} +#endif /* TEST */ diff --git a/contrib/tools/yasm/libyasm/md5.h b/contrib/tools/yasm/libyasm/md5.h index 7872fda7a1..20b4de5e7a 100644 --- a/contrib/tools/yasm/libyasm/md5.h +++ b/contrib/tools/yasm/libyasm/md5.h @@ -1,32 +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 */ +/* See md5.c for explanation and copyright information. */ + +#ifndef YASM_MD5_H +#define YASM_MD5_H + +#ifndef YASM_LIB_DECL +#define YASM_LIB_DECL +#endif + +/* Unlike previous versions of this code, uint32 need not be exactly + 32 bits, merely 32 bits or more. Choosing a data type which is 32 + bits instead of 64 is not important; speed is considerably more + important. ANSI guarantees that "unsigned long" will be big enough, + and always using it seems to have few disadvantages. */ + +typedef struct yasm_md5_context { + unsigned long buf[4]; + unsigned long bits[2]; + unsigned char in[64]; +} yasm_md5_context; + +YASM_LIB_DECL +void yasm_md5_init(yasm_md5_context *context); +YASM_LIB_DECL +void yasm_md5_update(yasm_md5_context *context, unsigned char const *buf, + unsigned long len); +YASM_LIB_DECL +void yasm_md5_final(unsigned char digest[16], yasm_md5_context *context); +YASM_LIB_DECL +void yasm_md5_transform(unsigned long buf[4], const unsigned char in[64]); + +#endif /* !YASM_MD5_H */ diff --git a/contrib/tools/yasm/libyasm/mergesort.c b/contrib/tools/yasm/libyasm/mergesort.c index 3eeaa8273b..8b4a7d250d 100644 --- a/contrib/tools/yasm/libyasm/mergesort.c +++ b/contrib/tools/yasm/libyasm/mergesort.c @@ -1,361 +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*/ +/* + * mergesort() implementation for systems that don't have it. + * + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Peter McIlroy. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include "util.h" + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)merge.c 8.2 (Berkeley) 2/14/94"; +#endif /* LIBC_SCCS and not lint */ + +#ifdef HAVE_MERGESORT +#undef yasm__mergesort +#endif + +#ifndef HAVE_MERGESORT +/* + * Hybrid exponential search/linear search merge sort with hybrid + * natural/pairwise first pass. Requires about .3% more comparisons + * for random data than LSMS with pairwise first pass alone. + * It works for objects as small as two bytes. + */ + +#define NATURAL +#define THRESHOLD 16 /* Best choice for natural merge cut-off. */ + +/* #define NATURAL to get hybrid natural merge. + * (The default is pairwise merging.) + */ + +#include <errno.h> +#include <string.h> + +static void setup(unsigned char *, unsigned char *, size_t, size_t, + int (*)(const void *, const void *)); +static void insertionsort(unsigned char *, size_t, size_t, + int (*)(const void *, const void *)); + +#define ISIZE sizeof(int) +#define PSIZE sizeof(unsigned char *) +#define ICOPY_LIST(src, dst, last) \ + do \ + *(int*)dst = *(int*)src, src += ISIZE, dst += ISIZE; \ + while(src < last) +#define ICOPY_ELT(src, dst, i) \ + do \ + *(int*) dst = *(int*) src, src += ISIZE, dst += ISIZE; \ + while (i -= ISIZE) + +#define CCOPY_LIST(src, dst, last) \ + do \ + *dst++ = *src++; \ + while (src < last) +#define CCOPY_ELT(src, dst, i) \ + do \ + *dst++ = *src++; \ + while (i -= 1) + +/* + * Find the next possible pointer head. (Trickery for forcing an array + * to do double duty as a linked list when objects do not align with word + * boundaries. + */ +/* Assumption: PSIZE is a power of 2. */ +#define EVAL(p) (unsigned char **) \ + ((unsigned char *)0 + \ + (((unsigned char *)p + PSIZE - 1 - (unsigned char *) 0) & ~(PSIZE - 1))) +#endif /*HAVE_MERGESORT*/ + +/* + * Arguments are as for qsort. + */ +int +yasm__mergesort(void *base, size_t nmemb, size_t size, + int (*cmp)(const void *, const void *)) +{ +#ifdef HAVE_MERGESORT + return mergesort(base, nmemb, size, cmp); +#else + size_t i; + int sense; + int big, iflag; + unsigned char *f1, *f2, *t, *b, *tp2, *q, *l1, *l2; + unsigned char *list2, *list1, *p2, *p, *last, **p1; + + if (size < PSIZE / 2) { /* Pointers must fit into 2 * size. */ +#ifdef EINVAL + errno = EINVAL; +#endif + return (-1); + } + + if (nmemb == 0) + return (0); + + /* + * XXX + * Stupid subtraction for the Cray. + */ + iflag = 0; + if (!(size % ISIZE) && !(((char *)base - (char *)0) % ISIZE)) + iflag = 1; + + if ((list2 = yasm_xmalloc(nmemb * size + PSIZE)) == NULL) + return (-1); + + list1 = base; + setup(list1, list2, nmemb, size, cmp); + last = list2 + nmemb * size; + i = 0; + big = 0; + while (*EVAL(list2) != last) { + l2 = list1; + p1 = EVAL(list1); + for (tp2 = p2 = list2; p2 != last; p1 = EVAL(l2)) { + p2 = *EVAL(p2); + f1 = l2; + f2 = l1 = list1 + (p2 - list2); + if (p2 != last) + p2 = *EVAL(p2); + l2 = list1 + (p2 - list2); + while (f1 < l1 && f2 < l2) { + if ((*cmp)(f1, f2) <= 0) { + q = f2; + b = f1, t = l1; + sense = -1; + } else { + q = f1; + b = f2, t = l2; + sense = 0; + } + if (!big) { /* here i = 0 */ + while ((b += size) < t && cmp(q, b) >sense) + if (++i == 6) { + big = 1; + goto EXPONENTIAL; + } + } else { +EXPONENTIAL: for (i = size; ; i <<= 1) + if ((p = (b + i)) >= t) { + if ((p = t - size) > b && + (*cmp)(q, p) <= sense) + t = p; + else + b = p; + break; + } else if ((*cmp)(q, p) <= sense) { + t = p; + if (i == size) + big = 0; + goto FASTCASE; + } else + b = p; + while (t > b+size) { + i = (((t - b) / size) >> 1) * size; + if ((*cmp)(q, p = b + i) <= sense) + t = p; + else + b = p; + } + goto COPY; +FASTCASE: while (i > size) + if ((*cmp)(q, + p = b + (i >>= 1)) <= sense) + t = p; + else + b = p; +COPY: b = t; + } + i = size; + if (q == f1) { + if (iflag) { + ICOPY_LIST(f2, tp2, b); + ICOPY_ELT(f1, tp2, i); + } else { + CCOPY_LIST(f2, tp2, b); + CCOPY_ELT(f1, tp2, i); + } + } else { + if (iflag) { + ICOPY_LIST(f1, tp2, b); + ICOPY_ELT(f2, tp2, i); + } else { + CCOPY_LIST(f1, tp2, b); + CCOPY_ELT(f2, tp2, i); + } + } + } + if (f2 < l2) { + if (iflag) + ICOPY_LIST(f2, tp2, l2); + else + CCOPY_LIST(f2, tp2, l2); + } else if (f1 < l1) { + if (iflag) + ICOPY_LIST(f1, tp2, l1); + else + CCOPY_LIST(f1, tp2, l1); + } + *p1 = l2; + } + tp2 = list1; /* swap list1, list2 */ + list1 = list2; + list2 = tp2; + last = list2 + nmemb*size; + } + if (base == list2) { + memmove(list2, list1, nmemb*size); + list2 = list1; + } + yasm_xfree(list2); + return (0); +#endif /*HAVE_MERGESORT*/ +} + +#ifndef HAVE_MERGESORT + +#define swap(a, b) { \ + s = b; \ + i = size; \ + do { \ + tmp = *a; *a++ = *s; *s++ = tmp; \ + } while (--i); \ + a -= size; \ + } +#define reverse(bot, top) { \ + s = top; \ + do { \ + i = size; \ + do { \ + tmp = *bot; *bot++ = *s; *s++ = tmp; \ + } while (--i); \ + s -= size2; \ + } while(bot < s); \ +} + +/* + * Optional hybrid natural/pairwise first pass. Eats up list1 in runs of + * increasing order, list2 in a corresponding linked list. Checks for runs + * when THRESHOLD/2 pairs compare with same sense. (Only used when NATURAL + * is defined. Otherwise simple pairwise merging is used.) + */ +void +setup(unsigned char *list1, unsigned char *list2, size_t n, size_t size, + int (*cmp)(const void *, const void *)) +{ + size_t i; + unsigned int tmp; + int length, sense; + size_t size2; + unsigned char *f1, *f2, *s, *l2, *last, *p2; + + size2 = size*2; + if (n <= 5) { + insertionsort(list1, n, size, cmp); + *EVAL(list2) = (unsigned char*) list2 + n*size; + return; + } + /* + * Avoid running pointers out of bounds; limit n to evens + * for simplicity. + */ + i = 4 + (n & 1); + insertionsort(list1 + (n - i) * size, i, size, cmp); + last = list1 + size * (n - i); + *EVAL(list2 + (last - list1)) = list2 + n * size; + +#ifdef NATURAL + p2 = list2; + f1 = list1; + sense = (cmp(f1, f1 + size) > 0); + for (; f1 < last; sense = !sense) { + length = 2; + /* Find pairs with same sense. */ + for (f2 = f1 + size2; f2 < last; f2 += size2) { + if ((cmp(f2, f2+ size) > 0) != sense) + break; + length += 2; + } + if (length < THRESHOLD) { /* Pairwise merge */ + do { + p2 = *EVAL(p2) = f1 + size2 - list1 + list2; + if (sense > 0) + swap (f1, f1 + size); + } while ((f1 += size2) < f2); + } else { /* Natural merge */ + l2 = f2; + for (f2 = f1 + size2; f2 < l2; f2 += size2) { + if ((cmp(f2-size, f2) > 0) != sense) { + p2 = *EVAL(p2) = f2 - list1 + list2; + if (sense > 0) + reverse(f1, f2-size); + f1 = f2; + } + } + if (sense > 0) + reverse (f1, f2-size); + f1 = f2; + if (f2 < last || cmp(f2 - size, f2) > 0) + p2 = *EVAL(p2) = f2 - list1 + list2; + else + p2 = *EVAL(p2) = list2 + n*size; + } + } +#else /* pairwise merge only. */ + for (f1 = list1, p2 = list2; f1 < last; f1 += size2) { + p2 = *EVAL(p2) = p2 + size2; + if (cmp (f1, f1 + size) > 0) + swap(f1, f1 + size); + } +#endif /* NATURAL */ +} + +/* + * This is to avoid out-of-bounds addresses in sorting the + * last 4 elements. + */ +static void +insertionsort(unsigned char *a, size_t n, size_t size, + int (*cmp)(const void *, const void *)) +{ + unsigned char *ai, *s, *t, *u, tmp; + size_t i; + + for (ai = a+size; --n >= 1; ai += size) + for (t = ai; t > a; t -= size) { + u = t - size; + if (cmp(u, t) <= 0) + break; + swap(u, t); + } +} +#endif /*HAVE_MERGESORT*/ diff --git a/contrib/tools/yasm/libyasm/module.h b/contrib/tools/yasm/libyasm/module.h index 220017deec..5e19e26ab1 100644 --- a/contrib/tools/yasm/libyasm/module.h +++ b/contrib/tools/yasm/libyasm/module.h @@ -1,82 +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 +/* + * YASM module loader header file + * + * Copyright (C) 2002-2007 Peter Johnson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef YASM_MODULE_H +#define YASM_MODULE_H + +#ifndef YASM_LIB_DECL +#define YASM_LIB_DECL +#endif + +typedef enum yasm_module_type { + YASM_MODULE_ARCH = 0, + YASM_MODULE_DBGFMT, + YASM_MODULE_OBJFMT, + YASM_MODULE_LISTFMT, + YASM_MODULE_PARSER, + YASM_MODULE_PREPROC +} yasm_module_type; + +YASM_LIB_DECL +/*@dependent@*/ /*@null@*/ void *yasm_load_module + (yasm_module_type type, const char *keyword); + +#define yasm_load_arch(keyword) \ + yasm_load_module(YASM_MODULE_ARCH, keyword) +#define yasm_load_dbgfmt(keyword) \ + yasm_load_module(YASM_MODULE_DBGFMT, keyword) +#define yasm_load_objfmt(keyword) \ + yasm_load_module(YASM_MODULE_OBJFMT, keyword) +#define yasm_load_listfmt(keyword) \ + yasm_load_module(YASM_MODULE_LISTFMT, keyword) +#define yasm_load_parser(keyword) \ + yasm_load_module(YASM_MODULE_PARSER, keyword) +#define yasm_load_preproc(keyword) \ + yasm_load_module(YASM_MODULE_PREPROC, keyword) + +YASM_LIB_DECL +void yasm_list_modules + (yasm_module_type type, + void (*printfunc) (const char *name, const char *keyword)); + +#define yasm_list_arch(func) \ + yasm_list_modules(YASM_MODULE_ARCH, func) +#define yasm_list_dbgfmt(func) \ + yasm_list_modules(YASM_MODULE_DBGFMT, func) +#define yasm_list_objfmt(func) \ + yasm_list_modules(YASM_MODULE_OBJFMT, func) +#define yasm_list_listfmt(func) \ + yasm_list_modules(YASM_MODULE_LISTFMT, func) +#define yasm_list_parser(func) \ + yasm_list_modules(YASM_MODULE_PARSER, func) +#define yasm_list_preproc(func) \ + yasm_list_modules(YASM_MODULE_PREPROC, func) + +YASM_LIB_DECL +void yasm_register_module(yasm_module_type type, const char *keyword, + void *data); + +#endif diff --git a/contrib/tools/yasm/libyasm/objfmt.h b/contrib/tools/yasm/libyasm/objfmt.h index a8b5f8a161..624d698a99 100644 --- a/contrib/tools/yasm/libyasm/objfmt.h +++ b/contrib/tools/yasm/libyasm/objfmt.h @@ -1,128 +1,128 @@ -/** - * \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); +/** + * \file libyasm/objfmt.h + * \brief YASM object format module interface. + * + * \license + * Copyright (C) 2001-2007 Peter Johnson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * \endlicense + */ +#ifndef YASM_OBJFMT_H +#define YASM_OBJFMT_H + +#ifndef YASM_DOXYGEN +/** Base #yasm_objfmt structure. Must be present as the first element in any + * #yasm_objfmt implementation. + */ +typedef struct yasm_objfmt_base { + /** #yasm_objfmt_module implementation for this object format. */ + const struct yasm_objfmt_module *module; +} yasm_objfmt_base; +#endif + +/** Object format module interface. */ +struct yasm_objfmt_module { + /** One-line description of the object format. */ + const char *name; + + /** Keyword used to select object format. */ + const char *keyword; + + /** Default output file extension (without the '.'). + * NULL means no extension, with no '.', while "" includes the '.'. + */ + /*@null@*/ const char *extension; + + /** Default (starting) x86 BITS setting. This only appies to the x86 + * architecture; other architectures ignore this setting. + */ + const unsigned char default_x86_mode_bits; + + /** If @ signs should be legal in identifiers. */ + const unsigned char id_at_ok; + + /** NULL-terminated list of debug format (yasm_dbgfmt) keywords that are + * valid to use with this object format. The null debug format + * (null_dbgfmt, "null") should always be in this list so it's possible to + * have no debug output. + */ + const char **dbgfmt_keywords; + + /** Default debug format keyword (set even if there's only one available to + * use). + */ + const char *default_dbgfmt_keyword; + + /** NULL-terminated list of directives. NULL if none. */ + /*@null@*/ const yasm_directive *directives; + + /** NULL-terminated list of standard macro lookups. NULL if none. */ + const yasm_stdmac *stdmacs; + + /** Create object format. + * Module-level implementation of yasm_objfmt_create(). + * Call yasm_objfmt_create() instead of calling this function. + * \param object object + * \param a architecture in use + * \return NULL if architecture/machine combination not supported. + */ + /*@null@*/ /*@only@*/ yasm_objfmt * (*create) (yasm_object *object); + + /** Module-level implementation of yasm_objfmt_output(). + * Call yasm_objfmt_output() instead of calling this function. + */ + void (*output) (yasm_object *o, FILE *f, int all_syms, + yasm_errwarns *errwarns); + + /** Module-level implementation of yasm_objfmt_destroy(). + * Call yasm_objfmt_destroy() instead of calling this function. + */ + void (*destroy) (/*@only@*/ yasm_objfmt *objfmt); + + /** Module-level implementation of yasm_objfmt_add_default_section(). + * Call yasm_objfmt_add_default_section() instead of calling this function. + */ + yasm_section * (*add_default_section) (yasm_object *object); + + /** Module-level implementation of yasm_objfmt_init_new_section(). + * Call yasm_objfmt_init_new_section() instead of calling this function. + */ + void (*init_new_section) (yasm_section *section, unsigned long line); + + /** Module-level implementation of yasm_objfmt_section_switch(). + * Call yasm_objfmt_section_switch() instead of calling this function. + */ + /*@observer@*/ /*@null@*/ yasm_section * + (*section_switch)(yasm_object *object, yasm_valparamhead *valparams, + /*@null@*/ yasm_valparamhead *objext_valparams, + unsigned long line); + + /** Module-level implementation of yasm_objfmt_get_special_sym(). + * Call yasm_objfmt_get_special_sym() instead of calling this function. + */ + /*@observer@*/ /*@null@*/ yasm_symrec * + (*get_special_sym)(yasm_object *object, const char *name, + const char *parser); /** * --replace params @@ -132,94 +132,94 @@ struct yasm_objfmt_module { * Number of elements in replace_map */ int replace_map_size; -}; - -/** Create object format. - * \param module object format module - * \param object object - * \return NULL if architecture/machine combination not supported. - */ -/*@null@*/ /*@only@*/ yasm_objfmt *yasm_objfmt_create - (const yasm_objfmt_module *module, yasm_object *object); - -/** Write out (post-optimized) sections to the object file. - * This function may call yasm_symrec_* functions as necessary (including - * yasm_symrec_traverse()) to retrieve symbolic information. - * \param object object - * \param f output object file - * \param all_syms if nonzero, all symbols should be included in - * the object file - * \param errwarns error/warning set - * \note Errors and warnings are stored into errwarns. - */ -void yasm_objfmt_output(yasm_object *object, FILE *f, int all_syms, - yasm_errwarns *errwarns); - -/** Cleans up any allocated object format memory. - * \param objfmt object format - */ -void yasm_objfmt_destroy(/*@only@*/ yasm_objfmt *objfmt); - -/** Add a default section to an object. - * \param object object - * \return Default section. - */ -yasm_section *yasm_objfmt_add_default_section(yasm_object *object); - -/** Initialize the object-format specific portion of a section. Called - * by yasm_object_get_general(); in general should not be directly called. - * \param section section - * \param line virtual line (from yasm_linemap) - */ -void yasm_objfmt_init_new_section(yasm_object *object, unsigned long line); - -/** Switch object file sections. The first val of the valparams should - * be the section name. Calls yasm_object_get_general() to actually get - * the section. - * \param object object - * \param valparams value/parameters - * \param objext_valparams object format-specific value/parameters - * \param line virtual line (from yasm_linemap) - * \return NULL on error, otherwise new section. - */ -/*@observer@*/ /*@null@*/ yasm_section *yasm_objfmt_section_switch - (yasm_object *object, yasm_valparamhead *valparams, - /*@null@*/ yasm_valparamhead *objext_valparams, unsigned long line); - -/** Get a special symbol. Special symbols are generally used to generate - * special relocation types via the WRT mechanism. - * \param object object - * \param name symbol name (not including any parser-specific prefix) - * \param parser parser keyword - * \return NULL if unrecognized, otherwise special symbol. - */ -/*@observer@*/ /*@null@*/ yasm_symrec *yasm_objfmt_get_special_sym - (yasm_object *object, const char *name, const char *parser); - -#ifndef YASM_DOXYGEN - -/* Inline macro implementations for objfmt functions */ - -#define yasm_objfmt_create(module, object) module->create(object) - -#define yasm_objfmt_output(object, f, all_syms, ews) \ - ((yasm_objfmt_base *)((object)->objfmt))->module->output \ - (object, f, all_syms, ews) -#define yasm_objfmt_destroy(objfmt) \ - ((yasm_objfmt_base *)objfmt)->module->destroy(objfmt) -#define yasm_objfmt_section_switch(object, vpms, oe_vpms, line) \ - ((yasm_objfmt_base *)((object)->objfmt))->module->section_switch \ - (object, vpms, oe_vpms, line) -#define yasm_objfmt_add_default_section(object) \ - ((yasm_objfmt_base *)((object)->objfmt))->module->add_default_section \ - (object) -#define yasm_objfmt_init_new_section(section, line) \ - ((yasm_objfmt_base *)((object)->objfmt))->module->init_new_section \ - (section, line) -#define yasm_objfmt_get_special_sym(object, name, parser) \ - ((yasm_objfmt_base *)((object)->objfmt))->module->get_special_sym \ - (object, name, parser) - -#endif - -#endif +}; + +/** Create object format. + * \param module object format module + * \param object object + * \return NULL if architecture/machine combination not supported. + */ +/*@null@*/ /*@only@*/ yasm_objfmt *yasm_objfmt_create + (const yasm_objfmt_module *module, yasm_object *object); + +/** Write out (post-optimized) sections to the object file. + * This function may call yasm_symrec_* functions as necessary (including + * yasm_symrec_traverse()) to retrieve symbolic information. + * \param object object + * \param f output object file + * \param all_syms if nonzero, all symbols should be included in + * the object file + * \param errwarns error/warning set + * \note Errors and warnings are stored into errwarns. + */ +void yasm_objfmt_output(yasm_object *object, FILE *f, int all_syms, + yasm_errwarns *errwarns); + +/** Cleans up any allocated object format memory. + * \param objfmt object format + */ +void yasm_objfmt_destroy(/*@only@*/ yasm_objfmt *objfmt); + +/** Add a default section to an object. + * \param object object + * \return Default section. + */ +yasm_section *yasm_objfmt_add_default_section(yasm_object *object); + +/** Initialize the object-format specific portion of a section. Called + * by yasm_object_get_general(); in general should not be directly called. + * \param section section + * \param line virtual line (from yasm_linemap) + */ +void yasm_objfmt_init_new_section(yasm_object *object, unsigned long line); + +/** Switch object file sections. The first val of the valparams should + * be the section name. Calls yasm_object_get_general() to actually get + * the section. + * \param object object + * \param valparams value/parameters + * \param objext_valparams object format-specific value/parameters + * \param line virtual line (from yasm_linemap) + * \return NULL on error, otherwise new section. + */ +/*@observer@*/ /*@null@*/ yasm_section *yasm_objfmt_section_switch + (yasm_object *object, yasm_valparamhead *valparams, + /*@null@*/ yasm_valparamhead *objext_valparams, unsigned long line); + +/** Get a special symbol. Special symbols are generally used to generate + * special relocation types via the WRT mechanism. + * \param object object + * \param name symbol name (not including any parser-specific prefix) + * \param parser parser keyword + * \return NULL if unrecognized, otherwise special symbol. + */ +/*@observer@*/ /*@null@*/ yasm_symrec *yasm_objfmt_get_special_sym + (yasm_object *object, const char *name, const char *parser); + +#ifndef YASM_DOXYGEN + +/* Inline macro implementations for objfmt functions */ + +#define yasm_objfmt_create(module, object) module->create(object) + +#define yasm_objfmt_output(object, f, all_syms, ews) \ + ((yasm_objfmt_base *)((object)->objfmt))->module->output \ + (object, f, all_syms, ews) +#define yasm_objfmt_destroy(objfmt) \ + ((yasm_objfmt_base *)objfmt)->module->destroy(objfmt) +#define yasm_objfmt_section_switch(object, vpms, oe_vpms, line) \ + ((yasm_objfmt_base *)((object)->objfmt))->module->section_switch \ + (object, vpms, oe_vpms, line) +#define yasm_objfmt_add_default_section(object) \ + ((yasm_objfmt_base *)((object)->objfmt))->module->add_default_section \ + (object) +#define yasm_objfmt_init_new_section(section, line) \ + ((yasm_objfmt_base *)((object)->objfmt))->module->init_new_section \ + (section, line) +#define yasm_objfmt_get_special_sym(object, name, parser) \ + ((yasm_objfmt_base *)((object)->objfmt))->module->get_special_sym \ + (object, name, parser) + +#endif + +#endif diff --git a/contrib/tools/yasm/libyasm/parser.h b/contrib/tools/yasm/libyasm/parser.h index 93d4d33232..568560f671 100644 --- a/contrib/tools/yasm/libyasm/parser.h +++ b/contrib/tools/yasm/libyasm/parser.h @@ -1,67 +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 +/** + * \file libyasm/parser.h + * \brief YASM parser module interface. + * + * \license + * Copyright (C) 2001-2007 Peter Johnson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * \endlicense + */ +#ifndef YASM_PARSER_H +#define YASM_PARSER_H + +/** YASM parser module interface. The "front end" of the assembler. */ +typedef struct yasm_parser_module { + /** One-line description of the parser */ + const char *name; + + /** Keyword used to select parser on the command line */ + const char *keyword; + + /** NULL-terminated list of preprocessors that are valid to use with this + * parser. The raw preprocessor (raw_preproc) should always be in this + * list so it's always possible to have no preprocessing done. + */ + const char **preproc_keywords; + + /** Default preprocessor. */ + const char *default_preproc_keyword; + + /** NULL-terminated list of standard macro lookups. NULL if none. */ + const yasm_stdmac *stdmacs; + + /** Parse a source file into an object. + * \param object object to parse into (already created) + * \param pp preprocessor + * \param save_input nonzero if the parser should save the original + * lines of source into the object's linemap (via + * yasm_linemap_add_data()). + * \param errwarns error/warning set + * \note Parse errors and warnings are stored into errwarns. + */ + void (*do_parse) + (yasm_object *object, yasm_preproc *pp, int save_input, + yasm_linemap *linemap, yasm_errwarns *errwarns); +} yasm_parser_module; + +#endif diff --git a/contrib/tools/yasm/libyasm/phash.c b/contrib/tools/yasm/libyasm/phash.c index 29e073aae1..518d5d38cc 100644 --- a/contrib/tools/yasm/libyasm/phash.c +++ b/contrib/tools/yasm/libyasm/phash.c @@ -1,268 +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 */ -{ +/* Modified for use with yasm by Peter Johnson. */ +#include "util.h" + +/* +-------------------------------------------------------------------- +lookupa.c, by Bob Jenkins, December 1996. Same as lookup2.c +Use this code however you wish. Public Domain. No warranty. +Source is http://burtleburtle.net/bob/c/lookupa.c +-------------------------------------------------------------------- +*/ +#include "phash.h" + +#define ub4 unsigned long + +#define hashsize(n) ((ub4)1<<(n)) +#define hashmask(n) (hashsize(n)-1) + +/* +-------------------------------------------------------------------- +mix -- mix 3 32-bit values reversibly. +For every delta with one or two bit set, and the deltas of all three + high bits or all three low bits, whether the original value of a,b,c + is almost all zero or is uniformly distributed, +* If mix() is run forward or backward, at least 32 bits in a,b,c + have at least 1/4 probability of changing. +* If mix() is run forward, every bit of c will change between 1/3 and + 2/3 of the time. (Well, 22/100 and 78/100 for some 2-bit deltas.) +mix() was built out of 36 single-cycle latency instructions in a + structure that could supported 2x parallelism, like so: + a -= b; + a -= c; x = (c>>13); + b -= c; a ^= x; + b -= a; x = (a<<8); + c -= a; b ^= x; + c -= b; x = (b>>13); + ... + Unfortunately, superscalar Pentiums and Sparcs can't take advantage + of that parallelism. They've also turned some of those single-cycle + latency instructions into multi-cycle latency instructions. Still, + this is the fastest good hash I could find. There were about 2^^68 + to choose from. I only looked at a billion or so. +-------------------------------------------------------------------- +*/ +#define mix(a,b,c) \ +{ \ + a -= b; a -= c; a ^= (c>>13); \ + a &= 0xffffffff; \ + b -= c; b -= a; b ^= (a<<8); \ + b &= 0xffffffff; \ + c -= a; c -= b; c ^= (b>>13); \ + c &= 0xffffffff; \ + a -= b; a -= c; a ^= (c>>12); \ + a &= 0xffffffff; \ + b -= c; b -= a; b ^= (a<<16); \ + b &= 0xffffffff; \ + c -= a; c -= b; c ^= (b>>5); \ + c &= 0xffffffff; \ + a -= b; a -= c; a ^= (c>>3); \ + a &= 0xffffffff; \ + b -= c; b -= a; b ^= (a<<10); \ + b &= 0xffffffff; \ + c -= a; c -= b; c ^= (b>>15); \ + c &= 0xffffffff; \ +} + +/* +-------------------------------------------------------------------- +lookup() -- hash a variable-length key into a 32-bit value + k : the key (the unaligned variable-length array of bytes) + len : the length of the key, counting by bytes + level : can be any 4-byte value +Returns a 32-bit value. Every bit of the key affects every bit of +the return value. Every 1-bit and 2-bit delta achieves avalanche. +About 6len+35 instructions. + +The best hash table sizes are powers of 2. There is no need to do +mod a prime (mod is sooo slow!). If you need less than 32 bits, +use a bitmask. For example, if you need only 10 bits, do + h = (h & hashmask(10)); +In which case, the hash table should have hashsize(10) elements. + +If you are hashing n strings (ub1 **)k, do it like this: + for (i=0, h=0; i<n; ++i) h = lookup( k[i], len[i], h); + +By Bob Jenkins, 1996. bob_jenkins@burtleburtle.net. You may use this +code any way you wish, private, educational, or commercial. + +See http://burtleburtle.net/bob/hash/evahash.html +Use for hash table lookup, or anything where one collision in 2^32 is +acceptable. Do NOT use for cryptographic purposes. +-------------------------------------------------------------------- +*/ + +unsigned long +phash_lookup( + register const char *sk, /* the key */ + register size_t length, /* the length of the key */ + register unsigned long level) /* the previous hash, or an arbitrary value */ +{ unsigned long a,b,c; size_t len; const unsigned char *k = (const unsigned char *)sk; - - /* Set up the internal state */ - len = length; - a = b = 0x9e3779b9; /* the golden ratio; an arbitrary value */ - c = level; /* the previous hash value */ - - /*---------------------------------------- handle most of the key */ - while (len >= 12) - { - a += (k[0] +((ub4)k[1]<<8) +((ub4)k[2]<<16) +((ub4)k[3]<<24)); - a &= 0xffffffff; - b += (k[4] +((ub4)k[5]<<8) +((ub4)k[6]<<16) +((ub4)k[7]<<24)); - b &= 0xffffffff; - c += (k[8] +((ub4)k[9]<<8) +((ub4)k[10]<<16)+((ub4)k[11]<<24)); - c &= 0xffffffff; - mix(a,b,c); - k += 12; len -= 12; - } - - /*------------------------------------- handle the last 11 bytes */ - c += (ub4)length; - switch(len) /* all the case statements fall through */ - { - case 11: c+=((ub4)k[10]<<24); - case 10: c+=((ub4)k[9]<<16); - case 9 : c+=((ub4)k[8]<<8); - c &= 0xffffffff; - /* the first byte of c is reserved for the length */ - case 8 : b+=((ub4)k[7]<<24); - case 7 : b+=((ub4)k[6]<<16); - case 6 : b+=((ub4)k[5]<<8); - case 5 : b+=k[4]; - b &= 0xffffffff; - case 4 : a+=((ub4)k[3]<<24); - case 3 : a+=((ub4)k[2]<<16); - case 2 : a+=((ub4)k[1]<<8); - case 1 : a+=k[0]; - a &= 0xffffffff; - /* case 0: nothing left to add */ - } - mix(a,b,c); - /*-------------------------------------------- report the result */ - return c; -} - - -/* --------------------------------------------------------------------- -mixc -- mixc 8 4-bit values as quickly and thoroughly as possible. -Repeating mix() three times achieves avalanche. -Repeating mix() four times eliminates all funnels and all - characteristics stronger than 2^{-11}. --------------------------------------------------------------------- -*/ -#define mixc(a,b,c,d,e,f,g,h) \ -{ \ - a^=b<<11; d+=a; b+=c; \ - b^=c>>2; e+=b; c+=d; \ - c^=d<<8; f+=c; d+=e; \ - d^=e>>16; g+=d; e+=f; \ - e^=f<<10; h+=e; f+=g; \ - f^=g>>4; a+=f; g+=h; \ - g^=h<<8; b+=g; h+=a; \ - h^=a>>9; c+=h; a+=b; \ -} - -/* --------------------------------------------------------------------- -checksum() -- hash a variable-length key into a 256-bit value - k : the key (the unaligned variable-length array of bytes) - len : the length of the key, counting by bytes - state : an array of CHECKSTATE 4-byte values (256 bits) -The state is the checksum. Every bit of the key affects every bit of -the state. There are no funnels. About 112+6.875len instructions. - -If you are hashing n strings (ub1 **)k, do it like this: - for (i=0; i<8; ++i) state[i] = 0x9e3779b9; - for (i=0, h=0; i<n; ++i) checksum( k[i], len[i], state); - -(c) Bob Jenkins, 1996. bob_jenkins@burtleburtle.net. You may use this -code any way you wish, private, educational, or commercial, as long -as this whole comment accompanies it. - -See http://burtleburtle.net/bob/hash/evahash.html -Use to detect changes between revisions of documents, assuming nobody -is trying to cause collisions. Do NOT use for cryptography. --------------------------------------------------------------------- -*/ -void -phash_checksum( - register const char *sk, - register size_t len, - register unsigned long *state) -{ + + /* Set up the internal state */ + len = length; + a = b = 0x9e3779b9; /* the golden ratio; an arbitrary value */ + c = level; /* the previous hash value */ + + /*---------------------------------------- handle most of the key */ + while (len >= 12) + { + a += (k[0] +((ub4)k[1]<<8) +((ub4)k[2]<<16) +((ub4)k[3]<<24)); + a &= 0xffffffff; + b += (k[4] +((ub4)k[5]<<8) +((ub4)k[6]<<16) +((ub4)k[7]<<24)); + b &= 0xffffffff; + c += (k[8] +((ub4)k[9]<<8) +((ub4)k[10]<<16)+((ub4)k[11]<<24)); + c &= 0xffffffff; + mix(a,b,c); + k += 12; len -= 12; + } + + /*------------------------------------- handle the last 11 bytes */ + c += (ub4)length; + switch(len) /* all the case statements fall through */ + { + case 11: c+=((ub4)k[10]<<24); + case 10: c+=((ub4)k[9]<<16); + case 9 : c+=((ub4)k[8]<<8); + c &= 0xffffffff; + /* the first byte of c is reserved for the length */ + case 8 : b+=((ub4)k[7]<<24); + case 7 : b+=((ub4)k[6]<<16); + case 6 : b+=((ub4)k[5]<<8); + case 5 : b+=k[4]; + b &= 0xffffffff; + case 4 : a+=((ub4)k[3]<<24); + case 3 : a+=((ub4)k[2]<<16); + case 2 : a+=((ub4)k[1]<<8); + case 1 : a+=k[0]; + a &= 0xffffffff; + /* case 0: nothing left to add */ + } + mix(a,b,c); + /*-------------------------------------------- report the result */ + return c; +} + + +/* +-------------------------------------------------------------------- +mixc -- mixc 8 4-bit values as quickly and thoroughly as possible. +Repeating mix() three times achieves avalanche. +Repeating mix() four times eliminates all funnels and all + characteristics stronger than 2^{-11}. +-------------------------------------------------------------------- +*/ +#define mixc(a,b,c,d,e,f,g,h) \ +{ \ + a^=b<<11; d+=a; b+=c; \ + b^=c>>2; e+=b; c+=d; \ + c^=d<<8; f+=c; d+=e; \ + d^=e>>16; g+=d; e+=f; \ + e^=f<<10; h+=e; f+=g; \ + f^=g>>4; a+=f; g+=h; \ + g^=h<<8; b+=g; h+=a; \ + h^=a>>9; c+=h; a+=b; \ +} + +/* +-------------------------------------------------------------------- +checksum() -- hash a variable-length key into a 256-bit value + k : the key (the unaligned variable-length array of bytes) + len : the length of the key, counting by bytes + state : an array of CHECKSTATE 4-byte values (256 bits) +The state is the checksum. Every bit of the key affects every bit of +the state. There are no funnels. About 112+6.875len instructions. + +If you are hashing n strings (ub1 **)k, do it like this: + for (i=0; i<8; ++i) state[i] = 0x9e3779b9; + for (i=0, h=0; i<n; ++i) checksum( k[i], len[i], state); + +(c) Bob Jenkins, 1996. bob_jenkins@burtleburtle.net. You may use this +code any way you wish, private, educational, or commercial, as long +as this whole comment accompanies it. + +See http://burtleburtle.net/bob/hash/evahash.html +Use to detect changes between revisions of documents, assuming nobody +is trying to cause collisions. Do NOT use for cryptography. +-------------------------------------------------------------------- +*/ +void +phash_checksum( + register const char *sk, + register size_t len, + register unsigned long *state) +{ unsigned long a,b,c,d,e,f,g,h; size_t length; const unsigned char *k = (const unsigned char *)sk; - - /* Use the length and level; add in the golden ratio. */ - length = len; - a=state[0]; b=state[1]; c=state[2]; d=state[3]; - e=state[4]; f=state[5]; g=state[6]; h=state[7]; - - /*---------------------------------------- handle most of the key */ - while (len >= 32) - { - a += (k[0] +(k[1]<<8) +(k[2]<<16) +(k[3]<<24)); - b += (k[4] +(k[5]<<8) +(k[6]<<16) +(k[7]<<24)); - c += (k[8] +(k[9]<<8) +(k[10]<<16)+(k[11]<<24)); - d += (k[12]+(k[13]<<8)+(k[14]<<16)+(k[15]<<24)); - e += (k[16]+(k[17]<<8)+(k[18]<<16)+(k[19]<<24)); - f += (k[20]+(k[21]<<8)+(k[22]<<16)+(k[23]<<24)); - g += (k[24]+(k[25]<<8)+(k[26]<<16)+(k[27]<<24)); - h += (k[28]+(k[29]<<8)+(k[30]<<16)+(k[31]<<24)); - mixc(a,b,c,d,e,f,g,h); - mixc(a,b,c,d,e,f,g,h); - mixc(a,b,c,d,e,f,g,h); - mixc(a,b,c,d,e,f,g,h); - k += 32; len -= 32; - } - - /*------------------------------------- handle the last 31 bytes */ - h += (ub4)length; - switch(len) - { - case 31: h+=(k[30]<<24); - case 30: h+=(k[29]<<16); - case 29: h+=(k[28]<<8); - case 28: g+=(k[27]<<24); - case 27: g+=(k[26]<<16); - case 26: g+=(k[25]<<8); - case 25: g+=k[24]; - case 24: f+=(k[23]<<24); - case 23: f+=(k[22]<<16); - case 22: f+=(k[21]<<8); - case 21: f+=k[20]; - case 20: e+=(k[19]<<24); - case 19: e+=(k[18]<<16); - case 18: e+=(k[17]<<8); - case 17: e+=k[16]; - case 16: d+=(k[15]<<24); - case 15: d+=(k[14]<<16); - case 14: d+=(k[13]<<8); - case 13: d+=k[12]; - case 12: c+=(k[11]<<24); - case 11: c+=(k[10]<<16); - case 10: c+=(k[9]<<8); - case 9 : c+=k[8]; - case 8 : b+=(k[7]<<24); - case 7 : b+=(k[6]<<16); - case 6 : b+=(k[5]<<8); - case 5 : b+=k[4]; - case 4 : a+=(k[3]<<24); - case 3 : a+=(k[2]<<16); - case 2 : a+=(k[1]<<8); - case 1 : a+=k[0]; - } - mixc(a,b,c,d,e,f,g,h); - mixc(a,b,c,d,e,f,g,h); - mixc(a,b,c,d,e,f,g,h); - mixc(a,b,c,d,e,f,g,h); - - /*-------------------------------------------- report the result */ - state[0]=a; state[1]=b; state[2]=c; state[3]=d; - state[4]=e; state[5]=f; state[6]=g; state[7]=h; -} + + /* Use the length and level; add in the golden ratio. */ + length = len; + a=state[0]; b=state[1]; c=state[2]; d=state[3]; + e=state[4]; f=state[5]; g=state[6]; h=state[7]; + + /*---------------------------------------- handle most of the key */ + while (len >= 32) + { + a += (k[0] +(k[1]<<8) +(k[2]<<16) +(k[3]<<24)); + b += (k[4] +(k[5]<<8) +(k[6]<<16) +(k[7]<<24)); + c += (k[8] +(k[9]<<8) +(k[10]<<16)+(k[11]<<24)); + d += (k[12]+(k[13]<<8)+(k[14]<<16)+(k[15]<<24)); + e += (k[16]+(k[17]<<8)+(k[18]<<16)+(k[19]<<24)); + f += (k[20]+(k[21]<<8)+(k[22]<<16)+(k[23]<<24)); + g += (k[24]+(k[25]<<8)+(k[26]<<16)+(k[27]<<24)); + h += (k[28]+(k[29]<<8)+(k[30]<<16)+(k[31]<<24)); + mixc(a,b,c,d,e,f,g,h); + mixc(a,b,c,d,e,f,g,h); + mixc(a,b,c,d,e,f,g,h); + mixc(a,b,c,d,e,f,g,h); + k += 32; len -= 32; + } + + /*------------------------------------- handle the last 31 bytes */ + h += (ub4)length; + switch(len) + { + case 31: h+=(k[30]<<24); + case 30: h+=(k[29]<<16); + case 29: h+=(k[28]<<8); + case 28: g+=(k[27]<<24); + case 27: g+=(k[26]<<16); + case 26: g+=(k[25]<<8); + case 25: g+=k[24]; + case 24: f+=(k[23]<<24); + case 23: f+=(k[22]<<16); + case 22: f+=(k[21]<<8); + case 21: f+=k[20]; + case 20: e+=(k[19]<<24); + case 19: e+=(k[18]<<16); + case 18: e+=(k[17]<<8); + case 17: e+=k[16]; + case 16: d+=(k[15]<<24); + case 15: d+=(k[14]<<16); + case 14: d+=(k[13]<<8); + case 13: d+=k[12]; + case 12: c+=(k[11]<<24); + case 11: c+=(k[10]<<16); + case 10: c+=(k[9]<<8); + case 9 : c+=k[8]; + case 8 : b+=(k[7]<<24); + case 7 : b+=(k[6]<<16); + case 6 : b+=(k[5]<<8); + case 5 : b+=k[4]; + case 4 : a+=(k[3]<<24); + case 3 : a+=(k[2]<<16); + case 2 : a+=(k[1]<<8); + case 1 : a+=k[0]; + } + mixc(a,b,c,d,e,f,g,h); + mixc(a,b,c,d,e,f,g,h); + mixc(a,b,c,d,e,f,g,h); + mixc(a,b,c,d,e,f,g,h); + + /*-------------------------------------------- report the result */ + state[0]=a; state[1]=b; state[2]=c; state[3]=d; + state[4]=e; state[5]=f; state[6]=g; state[7]=h; +} diff --git a/contrib/tools/yasm/libyasm/phash.h b/contrib/tools/yasm/libyasm/phash.h index 2273a5df20..5bf105f0dd 100644 --- a/contrib/tools/yasm/libyasm/phash.h +++ b/contrib/tools/yasm/libyasm/phash.h @@ -1,19 +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); +/* Modified for use with yasm by Peter Johnson. */ +/* +------------------------------------------------------------------------------ +By Bob Jenkins, September 1996. +lookupa.h, a hash function for table lookup, same function as lookup.c. +Use this code in any way you wish. Public Domain. It has no warranty. +Source is http://burtleburtle.net/bob/c/lookupa.h +------------------------------------------------------------------------------ +*/ + +#ifndef YASM_LIB_DECL +#define YASM_LIB_DECL +#endif + +YASM_LIB_DECL +unsigned long phash_lookup(const char *k, size_t length, + unsigned long level); +YASM_LIB_DECL +void phash_checksum(const char *k, size_t length, unsigned long *state); diff --git a/contrib/tools/yasm/libyasm/preproc.h b/contrib/tools/yasm/libyasm/preproc.h index 751b19e4b0..7c0845c431 100644 --- a/contrib/tools/yasm/libyasm/preproc.h +++ b/contrib/tools/yasm/libyasm/preproc.h @@ -1,210 +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 +/** + * \file libyasm/preproc.h + * \brief YASM preprocessor module interface. + * + * \license + * Copyright (C) 2001-2007 Peter Johnson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * \endlicense + */ +#ifndef YASM_PREPROC_H +#define YASM_PREPROC_H + +#ifndef YASM_DOXYGEN +/** Base #yasm_preproc structure. Must be present as the first element in any + * #yasm_preproc implementation. + */ +typedef struct yasm_preproc_base { + /** #yasm_preproc_module implementation for this preprocessor. */ + const struct yasm_preproc_module *module; +} yasm_preproc_base; +#endif + +/** YASM preprocesor module interface. */ +typedef struct yasm_preproc_module { + /** One-line description of the preprocessor. */ + const char *name; + + /** Keyword used to select preprocessor on the command line. */ + const char *keyword; + + /** Create preprocessor. + * Module-level implementation of yasm_preproc_create(). + * Call yasm_preproc_create() instead of calling this function. + * + * \param in_filename initial starting filename, or "-" to read from + * stdin + * \param symtab symbol table (may be NULL if none) + * \param lm line mapping repository + * \param errwarns error/warnning set. + * \return New preprocessor. + * + * \note Any preprocessor errors and warnings are stored into errwarns. + */ + /*@only@*/ yasm_preproc * (*create) (const char *in_filename, + yasm_symtab *symtab, + yasm_linemap *lm, + yasm_errwarns *errwarns); + + /** Module-level implementation of yasm_preproc_destroy(). + * Call yasm_preproc_destroy() instead of calling this function. + */ + void (*destroy) (/*@only@*/ yasm_preproc *preproc); + + /** Module-level implementation of yasm_preproc_get_line(). + * Call yasm_preproc_get_line() instead of calling this function. + */ + char * (*get_line) (yasm_preproc *preproc); + + /** Module-level implementation of yasm_preproc_get_included_file(). + * Call yasm_preproc_get_included_file() instead of calling this function. + */ + size_t (*get_included_file) (yasm_preproc *preproc, /*@out@*/ char *buf, + size_t max_size); + + /** Module-level implementation of yasm_preproc_add_include_file(). + * Call yasm_preproc_add_include_file() instead of calling this function. + */ + void (*add_include_file) (yasm_preproc *preproc, const char *filename); + + /** Module-level implementation of yasm_preproc_predefine_macro(). + * Call yasm_preproc_predefine_macro() instead of calling this function. + */ + void (*predefine_macro) (yasm_preproc *preproc, const char *macronameval); + + /** Module-level implementation of yasm_preproc_undefine_macro(). + * Call yasm_preproc_undefine_macro() instead of calling this function. + */ + void (*undefine_macro) (yasm_preproc *preproc, const char *macroname); + + /** Module-level implementation of yasm_preproc_builtin_define(). + * Call yasm_preproc_builtin_define() instead of calling this function. + */ + void (*define_builtin) (yasm_preproc *preproc, const char *macronameval); + + /** Module-level implementation of yasm_preproc_add_standard(). + * Call yasm_preproc_add_standard() instead of calling this function. + */ + void (*add_standard) (yasm_preproc *preproc, const char **macros); +} yasm_preproc_module; + +/** Initialize preprocessor. + * The preprocessor needs access to the object format module to find out + * any output format specific macros. + * \param module preprocessor module + * \param in_filename initial starting filename, or "-" to read from stdin + * \param symtab symbol table (may be NULL if none) + * \param lm line mapping repository + * \param errwarns error/warning set + * \return New preprocessor. + * \note Errors/warnings are stored into errwarns. + */ +/*@only@*/ yasm_preproc *yasm_preproc_create + (yasm_preproc_module *module, const char *in_filename, + yasm_symtab *symtab, yasm_linemap *lm, yasm_errwarns *errwarns); + +/** Cleans up any allocated preproc memory. + * \param preproc preprocessor + */ +void yasm_preproc_destroy(/*@only@*/ yasm_preproc *preproc); + +/** Gets a single line of preprocessed source code. + * \param preproc preprocessor + * \return Allocated line of code, without the trailing \n. + */ +char *yasm_preproc_get_line(yasm_preproc *preproc); + +/** Get the next filename included by the source code. + * \param preproc preprocessor + * \param buf destination buffer for filename + * \param max_size maximum number of bytes that can be returned in buf + * \return Actual number of bytes returned in buf. + */ +size_t yasm_preproc_get_included_file(yasm_preproc *preproc, + /*@out@*/ char *buf, size_t max_size); + +/** Pre-include a file. + * \param preproc preprocessor + * \param filename filename + */ +void yasm_preproc_add_include_file(yasm_preproc *preproc, + const char *filename); + +/** Pre-define a macro. + * \param preproc preprocessor + * \param macronameval "name=value" string + */ +void yasm_preproc_predefine_macro(yasm_preproc *preproc, + const char *macronameval); + +/** Un-define a macro. + * \param preproc preprocessor + * \param macroname macro name + */ +void yasm_preproc_undefine_macro(yasm_preproc *preproc, const char *macroname); + +/** Define a builtin macro, preprocessed before the "standard" macros. + * \param preproc preprocessor + * \param macronameval "name=value" string + */ +void yasm_preproc_define_builtin(yasm_preproc *preproc, + const char *macronameval); + +/** Define additional standard macros, preprocessed after the builtins but + * prior to any user-defined macros. + * \param preproc preprocessor + * \param macros NULL-terminated array of macro strings + */ +void yasm_preproc_add_standard(yasm_preproc *preproc, + const char **macros); + +#ifndef YASM_DOXYGEN + +/* Inline macro implementations for preproc functions */ + +#define yasm_preproc_create(module, in_filename, symtab, lm, ews) \ + module->create(in_filename, symtab, lm, ews) + +#define yasm_preproc_destroy(preproc) \ + ((yasm_preproc_base *)preproc)->module->destroy(preproc) +#define yasm_preproc_get_line(preproc) \ + ((yasm_preproc_base *)preproc)->module->get_line(preproc) +#define yasm_preproc_get_included_file(preproc, buf, max_size) \ + ((yasm_preproc_base *)preproc)->module->get_included_file(preproc, buf, max_size) +#define yasm_preproc_add_include_file(preproc, filename) \ + ((yasm_preproc_base *)preproc)->module->add_include_file(preproc, filename) +#define yasm_preproc_predefine_macro(preproc, macronameval) \ + ((yasm_preproc_base *)preproc)->module->predefine_macro(preproc, \ + macronameval) +#define yasm_preproc_undefine_macro(preproc, macroname) \ + ((yasm_preproc_base *)preproc)->module->undefine_macro(preproc, macroname) +#define yasm_preproc_define_builtin(preproc, macronameval) \ + ((yasm_preproc_base *)preproc)->module->define_builtin(preproc, \ + macronameval) +#define yasm_preproc_add_standard(preproc, macros) \ + ((yasm_preproc_base *)preproc)->module->add_standard(preproc, \ + macros) + +#endif + +#endif diff --git a/contrib/tools/yasm/libyasm/section.c b/contrib/tools/yasm/libyasm/section.c index 729d7770a4..e43a5395f6 100644 --- a/contrib/tools/yasm/libyasm/section.c +++ b/contrib/tools/yasm/libyasm/section.c @@ -1,1585 +1,1585 @@ -/* - * Section utility functions - * - * Copyright (C) 2001-2007 Peter Johnson - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ -#include "util.h" - -#include <limits.h> - -#include "libyasm-stdint.h" -#include "coretype.h" -#include "hamt.h" -#include "valparam.h" -#include "assocdat.h" - -#include "linemap.h" -#include "errwarn.h" -#include "intnum.h" -#include "expr.h" -#include "value.h" -#include "symrec.h" - -#include "bytecode.h" -#include "arch.h" -#include "section.h" - -#include "dbgfmt.h" -#include "objfmt.h" - -#include "inttree.h" - - -struct yasm_section { - /*@reldef@*/ STAILQ_ENTRY(yasm_section) link; - - /*@dependent@*/ yasm_object *object; /* Pointer to parent object */ - - /*@owned@*/ char *name; /* strdup()'ed name (given by user) */ - - /* associated data; NULL if none */ - /*@null@*/ /*@only@*/ yasm__assoc_data *assoc_data; - - unsigned long align; /* Section alignment */ - - unsigned long opt_flags; /* storage for optimizer flags */ - - int code; /* section contains code (instructions) */ - int res_only; /* allow only resb family of bytecodes? */ - int def; /* "default" section, e.g. not specified by - using section directive */ - - /* the bytecodes for the section's contents */ - /*@reldef@*/ STAILQ_HEAD(yasm_bytecodehead, yasm_bytecode) bcs; - - /* the relocations for the section */ - /*@reldef@*/ STAILQ_HEAD(yasm_relochead, yasm_reloc) relocs; - - void (*destroy_reloc) (/*@only@*/ void *reloc); -}; - -static void yasm_section_destroy(/*@only@*/ yasm_section *sect); - -/* Wrapper around directive for HAMT insertion */ -typedef struct yasm_directive_wrap { - const yasm_directive *directive; -} yasm_directive_wrap; - -/* - * Standard "builtin" object directives. - */ - -static void -dir_extern(yasm_object *object, yasm_valparamhead *valparams, - yasm_valparamhead *objext_valparams, unsigned long line) -{ - yasm_valparam *vp = yasm_vps_first(valparams); - yasm_symrec *sym; - sym = yasm_symtab_declare(object->symtab, yasm_vp_id(vp), YASM_SYM_EXTERN, - line); - if (objext_valparams) { - yasm_valparamhead *vps = yasm_vps_create(); - *vps = *objext_valparams; /* structure copy */ - yasm_vps_initialize(objext_valparams); /* don't double-free */ - yasm_symrec_set_objext_valparams(sym, vps); - } -} - -static void -dir_global(yasm_object *object, yasm_valparamhead *valparams, - yasm_valparamhead *objext_valparams, unsigned long line) -{ - yasm_valparam *vp = yasm_vps_first(valparams); - yasm_symrec *sym; - sym = yasm_symtab_declare(object->symtab, yasm_vp_id(vp), YASM_SYM_GLOBAL, - line); - if (objext_valparams) { - yasm_valparamhead *vps = yasm_vps_create(); - *vps = *objext_valparams; /* structure copy */ - yasm_vps_initialize(objext_valparams); /* don't double-free */ - yasm_symrec_set_objext_valparams(sym, vps); - } -} - -static void -dir_common(yasm_object *object, yasm_valparamhead *valparams, - yasm_valparamhead *objext_valparams, unsigned long line) -{ - yasm_valparam *vp = yasm_vps_first(valparams); - yasm_valparam *vp2 = yasm_vps_next(vp); - yasm_expr *size = yasm_vp_expr(vp2, object->symtab, line); - yasm_symrec *sym; - - if (!size) { - yasm_error_set(YASM_ERROR_SYNTAX, - N_("no size specified in %s declaration"), "COMMON"); - return; - } - sym = yasm_symtab_declare(object->symtab, yasm_vp_id(vp), YASM_SYM_COMMON, - line); - yasm_symrec_set_common_size(sym, size); - if (objext_valparams) { - yasm_valparamhead *vps = yasm_vps_create(); - *vps = *objext_valparams; /* structure copy */ - yasm_vps_initialize(objext_valparams); /* don't double-free */ - yasm_symrec_set_objext_valparams(sym, vps); - } -} - -static void -dir_section(yasm_object *object, yasm_valparamhead *valparams, - yasm_valparamhead *objext_valparams, unsigned long line) -{ - yasm_section *new_section = - yasm_objfmt_section_switch(object, valparams, objext_valparams, line); - if (new_section) - object->cur_section = new_section; - else - yasm_error_set(YASM_ERROR_SYNTAX, - N_("invalid argument to directive `%s'"), "SECTION"); -} - -static const yasm_directive object_directives[] = { - { ".extern", "gas", dir_extern, YASM_DIR_ID_REQUIRED }, - { ".global", "gas", dir_global, YASM_DIR_ID_REQUIRED }, - { ".globl", "gas", dir_global, YASM_DIR_ID_REQUIRED }, - { "extern", "nasm", dir_extern, YASM_DIR_ID_REQUIRED }, - { "global", "nasm", dir_global, YASM_DIR_ID_REQUIRED }, - { "common", "nasm", dir_common, YASM_DIR_ID_REQUIRED }, - { "section", "nasm", dir_section, YASM_DIR_ARG_REQUIRED }, - { "segment", "nasm", dir_section, YASM_DIR_ARG_REQUIRED }, - { NULL, NULL, NULL, 0 } -}; - -static void -directive_level2_delete(/*@only@*/ void *data) -{ - yasm_xfree(data); -} - -static void -directive_level1_delete(/*@only@*/ void *data) -{ - HAMT_destroy(data, directive_level2_delete); -} - -static void -directives_add(yasm_object *object, /*@null@*/ const yasm_directive *dir) -{ - if (!dir) - return; - - while (dir->name) { - HAMT *level2 = HAMT_search(object->directives, dir->parser); - int replace; - yasm_directive_wrap *wrap = yasm_xmalloc(sizeof(yasm_directive_wrap)); - - if (!level2) { - replace = 0; - level2 = HAMT_insert(object->directives, dir->parser, - HAMT_create(1, yasm_internal_error_), - &replace, directive_level1_delete); - } - replace = 0; - wrap->directive = dir; - HAMT_insert(level2, dir->name, wrap, &replace, - directive_level2_delete); - dir++; - } -} - -/*@-compdestroy@*/ -yasm_object * -yasm_object_create(const char *src_filename, const char *obj_filename, - /*@kept@*/ yasm_arch *arch, - const yasm_objfmt_module *objfmt_module, - const yasm_dbgfmt_module *dbgfmt_module) -{ - yasm_object *object = yasm_xmalloc(sizeof(yasm_object)); - int matched, i; - - object->src_filename = yasm__xstrdup(src_filename); +/* + * Section utility functions + * + * Copyright (C) 2001-2007 Peter Johnson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include "util.h" + +#include <limits.h> + +#include "libyasm-stdint.h" +#include "coretype.h" +#include "hamt.h" +#include "valparam.h" +#include "assocdat.h" + +#include "linemap.h" +#include "errwarn.h" +#include "intnum.h" +#include "expr.h" +#include "value.h" +#include "symrec.h" + +#include "bytecode.h" +#include "arch.h" +#include "section.h" + +#include "dbgfmt.h" +#include "objfmt.h" + +#include "inttree.h" + + +struct yasm_section { + /*@reldef@*/ STAILQ_ENTRY(yasm_section) link; + + /*@dependent@*/ yasm_object *object; /* Pointer to parent object */ + + /*@owned@*/ char *name; /* strdup()'ed name (given by user) */ + + /* associated data; NULL if none */ + /*@null@*/ /*@only@*/ yasm__assoc_data *assoc_data; + + unsigned long align; /* Section alignment */ + + unsigned long opt_flags; /* storage for optimizer flags */ + + int code; /* section contains code (instructions) */ + int res_only; /* allow only resb family of bytecodes? */ + int def; /* "default" section, e.g. not specified by + using section directive */ + + /* the bytecodes for the section's contents */ + /*@reldef@*/ STAILQ_HEAD(yasm_bytecodehead, yasm_bytecode) bcs; + + /* the relocations for the section */ + /*@reldef@*/ STAILQ_HEAD(yasm_relochead, yasm_reloc) relocs; + + void (*destroy_reloc) (/*@only@*/ void *reloc); +}; + +static void yasm_section_destroy(/*@only@*/ yasm_section *sect); + +/* Wrapper around directive for HAMT insertion */ +typedef struct yasm_directive_wrap { + const yasm_directive *directive; +} yasm_directive_wrap; + +/* + * Standard "builtin" object directives. + */ + +static void +dir_extern(yasm_object *object, yasm_valparamhead *valparams, + yasm_valparamhead *objext_valparams, unsigned long line) +{ + yasm_valparam *vp = yasm_vps_first(valparams); + yasm_symrec *sym; + sym = yasm_symtab_declare(object->symtab, yasm_vp_id(vp), YASM_SYM_EXTERN, + line); + if (objext_valparams) { + yasm_valparamhead *vps = yasm_vps_create(); + *vps = *objext_valparams; /* structure copy */ + yasm_vps_initialize(objext_valparams); /* don't double-free */ + yasm_symrec_set_objext_valparams(sym, vps); + } +} + +static void +dir_global(yasm_object *object, yasm_valparamhead *valparams, + yasm_valparamhead *objext_valparams, unsigned long line) +{ + yasm_valparam *vp = yasm_vps_first(valparams); + yasm_symrec *sym; + sym = yasm_symtab_declare(object->symtab, yasm_vp_id(vp), YASM_SYM_GLOBAL, + line); + if (objext_valparams) { + yasm_valparamhead *vps = yasm_vps_create(); + *vps = *objext_valparams; /* structure copy */ + yasm_vps_initialize(objext_valparams); /* don't double-free */ + yasm_symrec_set_objext_valparams(sym, vps); + } +} + +static void +dir_common(yasm_object *object, yasm_valparamhead *valparams, + yasm_valparamhead *objext_valparams, unsigned long line) +{ + yasm_valparam *vp = yasm_vps_first(valparams); + yasm_valparam *vp2 = yasm_vps_next(vp); + yasm_expr *size = yasm_vp_expr(vp2, object->symtab, line); + yasm_symrec *sym; + + if (!size) { + yasm_error_set(YASM_ERROR_SYNTAX, + N_("no size specified in %s declaration"), "COMMON"); + return; + } + sym = yasm_symtab_declare(object->symtab, yasm_vp_id(vp), YASM_SYM_COMMON, + line); + yasm_symrec_set_common_size(sym, size); + if (objext_valparams) { + yasm_valparamhead *vps = yasm_vps_create(); + *vps = *objext_valparams; /* structure copy */ + yasm_vps_initialize(objext_valparams); /* don't double-free */ + yasm_symrec_set_objext_valparams(sym, vps); + } +} + +static void +dir_section(yasm_object *object, yasm_valparamhead *valparams, + yasm_valparamhead *objext_valparams, unsigned long line) +{ + yasm_section *new_section = + yasm_objfmt_section_switch(object, valparams, objext_valparams, line); + if (new_section) + object->cur_section = new_section; + else + yasm_error_set(YASM_ERROR_SYNTAX, + N_("invalid argument to directive `%s'"), "SECTION"); +} + +static const yasm_directive object_directives[] = { + { ".extern", "gas", dir_extern, YASM_DIR_ID_REQUIRED }, + { ".global", "gas", dir_global, YASM_DIR_ID_REQUIRED }, + { ".globl", "gas", dir_global, YASM_DIR_ID_REQUIRED }, + { "extern", "nasm", dir_extern, YASM_DIR_ID_REQUIRED }, + { "global", "nasm", dir_global, YASM_DIR_ID_REQUIRED }, + { "common", "nasm", dir_common, YASM_DIR_ID_REQUIRED }, + { "section", "nasm", dir_section, YASM_DIR_ARG_REQUIRED }, + { "segment", "nasm", dir_section, YASM_DIR_ARG_REQUIRED }, + { NULL, NULL, NULL, 0 } +}; + +static void +directive_level2_delete(/*@only@*/ void *data) +{ + yasm_xfree(data); +} + +static void +directive_level1_delete(/*@only@*/ void *data) +{ + HAMT_destroy(data, directive_level2_delete); +} + +static void +directives_add(yasm_object *object, /*@null@*/ const yasm_directive *dir) +{ + if (!dir) + return; + + while (dir->name) { + HAMT *level2 = HAMT_search(object->directives, dir->parser); + int replace; + yasm_directive_wrap *wrap = yasm_xmalloc(sizeof(yasm_directive_wrap)); + + if (!level2) { + replace = 0; + level2 = HAMT_insert(object->directives, dir->parser, + HAMT_create(1, yasm_internal_error_), + &replace, directive_level1_delete); + } + replace = 0; + wrap->directive = dir; + HAMT_insert(level2, dir->name, wrap, &replace, + directive_level2_delete); + dir++; + } +} + +/*@-compdestroy@*/ +yasm_object * +yasm_object_create(const char *src_filename, const char *obj_filename, + /*@kept@*/ yasm_arch *arch, + const yasm_objfmt_module *objfmt_module, + const yasm_dbgfmt_module *dbgfmt_module) +{ + yasm_object *object = yasm_xmalloc(sizeof(yasm_object)); + int matched, i; + + object->src_filename = yasm__xstrdup(src_filename); object->deb_filename = NULL; - object->obj_filename = yasm__xstrdup(obj_filename); - - /* No prefix/suffix */ - object->global_prefix = yasm__xstrdup(""); - object->global_suffix = yasm__xstrdup(""); - - /* Create empty symbol table */ - object->symtab = yasm_symtab_create(); - - /* Initialize sections linked list */ - STAILQ_INIT(&object->sections); - - /* Create directives HAMT */ - object->directives = HAMT_create(1, yasm_internal_error_); - - /* Initialize the target architecture */ - object->arch = arch; - - /* Initialize things to NULL in case of error */ - object->dbgfmt = NULL; - - /* Initialize the object format */ - object->objfmt = yasm_objfmt_create(objfmt_module, object); - if (!object->objfmt) { - yasm_error_set(YASM_ERROR_GENERAL, - N_("object format `%s' does not support architecture `%s' machine `%s'"), - objfmt_module->keyword, ((yasm_arch_base *)arch)->module->keyword, - yasm_arch_get_machine(arch)); - goto error; - } - - /* Get a fresh copy of objfmt_module as it may have changed. */ - objfmt_module = ((yasm_objfmt_base *)object->objfmt)->module; - - /* Add an initial "default" section to object */ - object->cur_section = yasm_objfmt_add_default_section(object); - - /* Check to see if the requested debug format is in the allowed list - * for the active object format. - */ - matched = 0; - for (i=0; objfmt_module->dbgfmt_keywords[i]; i++) { - if (yasm__strcasecmp(objfmt_module->dbgfmt_keywords[i], - dbgfmt_module->keyword) == 0) { - matched = 1; - break; - } - } - - if (!matched) { - yasm_error_set(YASM_ERROR_GENERAL, - N_("`%s' is not a valid debug format for object format `%s'"), - dbgfmt_module->keyword, objfmt_module->keyword); - goto error; - } - - /* Initialize the debug format */ - object->dbgfmt = yasm_dbgfmt_create(dbgfmt_module, object); - if (!object->dbgfmt) { - yasm_error_set(YASM_ERROR_GENERAL, - N_("debug format `%s' does not work with object format `%s'"), - dbgfmt_module->keyword, objfmt_module->keyword); - goto error; - } - - /* Add directives to HAMT. Note ordering here determines priority. */ - directives_add(object, - ((yasm_objfmt_base *)object->objfmt)->module->directives); - directives_add(object, - ((yasm_dbgfmt_base *)object->dbgfmt)->module->directives); - directives_add(object, - ((yasm_arch_base *)object->arch)->module->directives); - directives_add(object, object_directives); - - return object; - -error: - yasm_object_destroy(object); - return NULL; -} -/*@=compdestroy@*/ - -/*@-onlytrans@*/ -yasm_section * -yasm_object_get_general(yasm_object *object, const char *name, - unsigned long align, int code, int res_only, - int *isnew, unsigned long line) -{ - yasm_section *s; - yasm_bytecode *bc; - - /* Search through current sections to see if we already have one with - * that name. - */ - STAILQ_FOREACH(s, &object->sections, link) { - if (strcmp(s->name, name) == 0) { - *isnew = 0; - return s; - } - } - - /* No: we have to allocate and create a new one. */ - - /* Okay, the name is valid; now allocate and initialize */ - s = yasm_xcalloc(1, sizeof(yasm_section)); - STAILQ_INSERT_TAIL(&object->sections, s, link); - - s->object = object; - s->name = yasm__xstrdup(name); - s->assoc_data = NULL; - s->align = align; - - /* Initialize bytecodes with one empty bytecode (acts as "prior" for first - * real bytecode in section. - */ - STAILQ_INIT(&s->bcs); - bc = yasm_bc_create_common(NULL, NULL, 0); - bc->section = s; - bc->offset = 0; - STAILQ_INSERT_TAIL(&s->bcs, bc, link); - - /* Initialize relocs */ - STAILQ_INIT(&s->relocs); - s->destroy_reloc = NULL; - - s->code = code; - s->res_only = res_only; - s->def = 0; - - /* Initialize object format specific data */ - yasm_objfmt_init_new_section(s, line); - - *isnew = 1; - return s; -} -/*@=onlytrans@*/ - -int -yasm_object_directive(yasm_object *object, const char *name, - const char *parser, yasm_valparamhead *valparams, - yasm_valparamhead *objext_valparams, - unsigned long line) -{ - HAMT *level2; - yasm_directive_wrap *wrap; - - level2 = HAMT_search(object->directives, parser); - if (!level2) - return 1; - - wrap = HAMT_search(level2, name); - if (!wrap) - return 1; - - yasm_call_directive(wrap->directive, object, valparams, objext_valparams, - line); - return 0; -} - -void -yasm_object_set_source_fn(yasm_object *object, const char *src_filename) -{ - yasm_xfree(object->src_filename); - object->src_filename = yasm__xstrdup(src_filename); + object->obj_filename = yasm__xstrdup(obj_filename); + + /* No prefix/suffix */ + object->global_prefix = yasm__xstrdup(""); + object->global_suffix = yasm__xstrdup(""); + + /* Create empty symbol table */ + object->symtab = yasm_symtab_create(); + + /* Initialize sections linked list */ + STAILQ_INIT(&object->sections); + + /* Create directives HAMT */ + object->directives = HAMT_create(1, yasm_internal_error_); + + /* Initialize the target architecture */ + object->arch = arch; + + /* Initialize things to NULL in case of error */ + object->dbgfmt = NULL; + + /* Initialize the object format */ + object->objfmt = yasm_objfmt_create(objfmt_module, object); + if (!object->objfmt) { + yasm_error_set(YASM_ERROR_GENERAL, + N_("object format `%s' does not support architecture `%s' machine `%s'"), + objfmt_module->keyword, ((yasm_arch_base *)arch)->module->keyword, + yasm_arch_get_machine(arch)); + goto error; + } + + /* Get a fresh copy of objfmt_module as it may have changed. */ + objfmt_module = ((yasm_objfmt_base *)object->objfmt)->module; + + /* Add an initial "default" section to object */ + object->cur_section = yasm_objfmt_add_default_section(object); + + /* Check to see if the requested debug format is in the allowed list + * for the active object format. + */ + matched = 0; + for (i=0; objfmt_module->dbgfmt_keywords[i]; i++) { + if (yasm__strcasecmp(objfmt_module->dbgfmt_keywords[i], + dbgfmt_module->keyword) == 0) { + matched = 1; + break; + } + } + + if (!matched) { + yasm_error_set(YASM_ERROR_GENERAL, + N_("`%s' is not a valid debug format for object format `%s'"), + dbgfmt_module->keyword, objfmt_module->keyword); + goto error; + } + + /* Initialize the debug format */ + object->dbgfmt = yasm_dbgfmt_create(dbgfmt_module, object); + if (!object->dbgfmt) { + yasm_error_set(YASM_ERROR_GENERAL, + N_("debug format `%s' does not work with object format `%s'"), + dbgfmt_module->keyword, objfmt_module->keyword); + goto error; + } + + /* Add directives to HAMT. Note ordering here determines priority. */ + directives_add(object, + ((yasm_objfmt_base *)object->objfmt)->module->directives); + directives_add(object, + ((yasm_dbgfmt_base *)object->dbgfmt)->module->directives); + directives_add(object, + ((yasm_arch_base *)object->arch)->module->directives); + directives_add(object, object_directives); + + return object; + +error: + yasm_object_destroy(object); + return NULL; +} +/*@=compdestroy@*/ + +/*@-onlytrans@*/ +yasm_section * +yasm_object_get_general(yasm_object *object, const char *name, + unsigned long align, int code, int res_only, + int *isnew, unsigned long line) +{ + yasm_section *s; + yasm_bytecode *bc; + + /* Search through current sections to see if we already have one with + * that name. + */ + STAILQ_FOREACH(s, &object->sections, link) { + if (strcmp(s->name, name) == 0) { + *isnew = 0; + return s; + } + } + + /* No: we have to allocate and create a new one. */ + + /* Okay, the name is valid; now allocate and initialize */ + s = yasm_xcalloc(1, sizeof(yasm_section)); + STAILQ_INSERT_TAIL(&object->sections, s, link); + + s->object = object; + s->name = yasm__xstrdup(name); + s->assoc_data = NULL; + s->align = align; + + /* Initialize bytecodes with one empty bytecode (acts as "prior" for first + * real bytecode in section. + */ + STAILQ_INIT(&s->bcs); + bc = yasm_bc_create_common(NULL, NULL, 0); + bc->section = s; + bc->offset = 0; + STAILQ_INSERT_TAIL(&s->bcs, bc, link); + + /* Initialize relocs */ + STAILQ_INIT(&s->relocs); + s->destroy_reloc = NULL; + + s->code = code; + s->res_only = res_only; + s->def = 0; + + /* Initialize object format specific data */ + yasm_objfmt_init_new_section(s, line); + + *isnew = 1; + return s; +} +/*@=onlytrans@*/ + +int +yasm_object_directive(yasm_object *object, const char *name, + const char *parser, yasm_valparamhead *valparams, + yasm_valparamhead *objext_valparams, + unsigned long line) +{ + HAMT *level2; + yasm_directive_wrap *wrap; + + level2 = HAMT_search(object->directives, parser); + if (!level2) + return 1; + + wrap = HAMT_search(level2, name); + if (!wrap) + return 1; + + yasm_call_directive(wrap->directive, object, valparams, objext_valparams, + line); + return 0; +} + +void +yasm_object_set_source_fn(yasm_object *object, const char *src_filename) +{ + yasm_xfree(object->src_filename); + object->src_filename = yasm__xstrdup(src_filename); yasm_xfree(object->deb_filename); object->deb_filename = NULL; -} - -void -yasm_object_set_global_prefix(yasm_object *object, const char *prefix) -{ - yasm_xfree(object->global_prefix); - object->global_prefix = yasm__xstrdup(prefix); -} - -void -yasm_object_set_global_suffix(yasm_object *object, const char *suffix) -{ - yasm_xfree(object->global_suffix); - object->global_suffix = yasm__xstrdup(suffix); -} - -int -yasm_section_is_code(yasm_section *sect) -{ - return sect->code; -} - -unsigned long -yasm_section_get_opt_flags(const yasm_section *sect) -{ - return sect->opt_flags; -} - -void -yasm_section_set_opt_flags(yasm_section *sect, unsigned long opt_flags) -{ - sect->opt_flags = opt_flags; -} - -int -yasm_section_is_default(const yasm_section *sect) -{ - return sect->def; -} - -void -yasm_section_set_default(yasm_section *sect, int def) -{ - sect->def = def; -} - -yasm_object * -yasm_section_get_object(const yasm_section *sect) -{ - return sect->object; -} - -void * -yasm_section_get_data(yasm_section *sect, - const yasm_assoc_data_callback *callback) -{ - return yasm__assoc_data_get(sect->assoc_data, callback); -} - -void -yasm_section_add_data(yasm_section *sect, - const yasm_assoc_data_callback *callback, void *data) -{ - sect->assoc_data = yasm__assoc_data_add(sect->assoc_data, callback, data); -} - -void -yasm_object_destroy(yasm_object *object) -{ - yasm_section *cur, *next; - - /* Delete object format, debug format, and arch. This can be called - * due to an error in yasm_object_create(), so look out for NULLs. - */ - if (object->objfmt) - yasm_objfmt_destroy(object->objfmt); - if (object->dbgfmt) - yasm_dbgfmt_destroy(object->dbgfmt); - - /* Delete sections */ - cur = STAILQ_FIRST(&object->sections); - while (cur) { - next = STAILQ_NEXT(cur, link); - yasm_section_destroy(cur); - cur = next; - } - - /* Delete directives HAMT */ - HAMT_destroy(object->directives, directive_level1_delete); - - /* Delete prefix/suffix */ - yasm_xfree(object->global_prefix); - yasm_xfree(object->global_suffix); - - /* Delete associated filenames */ - yasm_xfree(object->src_filename); +} + +void +yasm_object_set_global_prefix(yasm_object *object, const char *prefix) +{ + yasm_xfree(object->global_prefix); + object->global_prefix = yasm__xstrdup(prefix); +} + +void +yasm_object_set_global_suffix(yasm_object *object, const char *suffix) +{ + yasm_xfree(object->global_suffix); + object->global_suffix = yasm__xstrdup(suffix); +} + +int +yasm_section_is_code(yasm_section *sect) +{ + return sect->code; +} + +unsigned long +yasm_section_get_opt_flags(const yasm_section *sect) +{ + return sect->opt_flags; +} + +void +yasm_section_set_opt_flags(yasm_section *sect, unsigned long opt_flags) +{ + sect->opt_flags = opt_flags; +} + +int +yasm_section_is_default(const yasm_section *sect) +{ + return sect->def; +} + +void +yasm_section_set_default(yasm_section *sect, int def) +{ + sect->def = def; +} + +yasm_object * +yasm_section_get_object(const yasm_section *sect) +{ + return sect->object; +} + +void * +yasm_section_get_data(yasm_section *sect, + const yasm_assoc_data_callback *callback) +{ + return yasm__assoc_data_get(sect->assoc_data, callback); +} + +void +yasm_section_add_data(yasm_section *sect, + const yasm_assoc_data_callback *callback, void *data) +{ + sect->assoc_data = yasm__assoc_data_add(sect->assoc_data, callback, data); +} + +void +yasm_object_destroy(yasm_object *object) +{ + yasm_section *cur, *next; + + /* Delete object format, debug format, and arch. This can be called + * due to an error in yasm_object_create(), so look out for NULLs. + */ + if (object->objfmt) + yasm_objfmt_destroy(object->objfmt); + if (object->dbgfmt) + yasm_dbgfmt_destroy(object->dbgfmt); + + /* Delete sections */ + cur = STAILQ_FIRST(&object->sections); + while (cur) { + next = STAILQ_NEXT(cur, link); + yasm_section_destroy(cur); + cur = next; + } + + /* Delete directives HAMT */ + HAMT_destroy(object->directives, directive_level1_delete); + + /* Delete prefix/suffix */ + yasm_xfree(object->global_prefix); + yasm_xfree(object->global_suffix); + + /* Delete associated filenames */ + yasm_xfree(object->src_filename); yasm_xfree(object->deb_filename); - yasm_xfree(object->obj_filename); - - /* Delete symbol table */ - yasm_symtab_destroy(object->symtab); - - /* Delete architecture */ - if (object->arch) - yasm_arch_destroy(object->arch); - - yasm_xfree(object); -} - -void -yasm_object_print(const yasm_object *object, FILE *f, int indent_level) -{ - yasm_section *cur; - - /* Print symbol table */ - fprintf(f, "%*sSymbol Table:\n", indent_level, ""); - yasm_symtab_print(object->symtab, f, indent_level+1); - - /* Print sections and bytecodes */ - STAILQ_FOREACH(cur, &object->sections, link) { - fprintf(f, "%*sSection:\n", indent_level, ""); - yasm_section_print(cur, f, indent_level+1, 1); - } -} - -void -yasm_object_finalize(yasm_object *object, yasm_errwarns *errwarns) -{ - yasm_section *sect; - - /* Iterate through sections */ - STAILQ_FOREACH(sect, &object->sections, link) { - yasm_bytecode *cur = STAILQ_FIRST(§->bcs); - yasm_bytecode *prev; - - /* Skip our locally created empty bytecode first. */ - prev = cur; - cur = STAILQ_NEXT(cur, link); - - /* Iterate through the remainder, if any. */ - while (cur) { - /* Finalize */ - yasm_bc_finalize(cur, prev); - yasm_errwarn_propagate(errwarns, cur->line); - prev = cur; - cur = STAILQ_NEXT(cur, link); - } - } -} - -int -yasm_object_sections_traverse(yasm_object *object, /*@null@*/ void *d, - int (*func) (yasm_section *sect, - /*@null@*/ void *d)) -{ - yasm_section *cur; - - STAILQ_FOREACH(cur, &object->sections, link) { - int retval = func(cur, d); - if (retval != 0) - return retval; - } - return 0; -} - -/*@-onlytrans@*/ -yasm_section * -yasm_object_find_general(yasm_object *object, const char *name) -{ - yasm_section *cur; - - STAILQ_FOREACH(cur, &object->sections, link) { - if (strcmp(cur->name, name) == 0) - return cur; - } - return NULL; -} -/*@=onlytrans@*/ - -void -yasm_section_add_reloc(yasm_section *sect, yasm_reloc *reloc, - void (*destroy_func) (/*@only@*/ void *reloc)) -{ - STAILQ_INSERT_TAIL(§->relocs, reloc, link); - if (!destroy_func) - yasm_internal_error(N_("NULL destroy function given to add_reloc")); - else if (sect->destroy_reloc && destroy_func != sect->destroy_reloc) - yasm_internal_error(N_("different destroy function given to add_reloc")); - sect->destroy_reloc = destroy_func; -} - -/*@null@*/ yasm_reloc * -yasm_section_relocs_first(yasm_section *sect) -{ - return STAILQ_FIRST(§->relocs); -} - -#undef yasm_section_reloc_next -/*@null@*/ yasm_reloc * -yasm_section_reloc_next(yasm_reloc *reloc) -{ - return STAILQ_NEXT(reloc, link); -} - -void -yasm_reloc_get(yasm_reloc *reloc, yasm_intnum **addrp, yasm_symrec **symp) -{ - *addrp = reloc->addr; - *symp = reloc->sym; -} - - -yasm_bytecode * -yasm_section_bcs_first(yasm_section *sect) -{ - return STAILQ_FIRST(§->bcs); -} - -yasm_bytecode * -yasm_section_bcs_last(yasm_section *sect) -{ - return STAILQ_LAST(§->bcs, yasm_bytecode, link); -} - -yasm_bytecode * -yasm_section_bcs_append(yasm_section *sect, yasm_bytecode *bc) -{ - if (bc) { - if (bc->callback) { - bc->section = sect; /* record parent section */ - STAILQ_INSERT_TAIL(§->bcs, bc, link); - return bc; - } else - yasm_xfree(bc); - } - return (yasm_bytecode *)NULL; -} - -int -yasm_section_bcs_traverse(yasm_section *sect, - /*@null@*/ yasm_errwarns *errwarns, - /*@null@*/ void *d, - int (*func) (yasm_bytecode *bc, /*@null@*/ void *d)) -{ - yasm_bytecode *cur = STAILQ_FIRST(§->bcs); - - /* Skip our locally created empty bytecode first. */ - cur = STAILQ_NEXT(cur, link); - - /* Iterate through the remainder, if any. */ - while (cur) { - int retval = func(cur, d); - if (errwarns) - yasm_errwarn_propagate(errwarns, cur->line); - if (retval != 0) - return retval; - cur = STAILQ_NEXT(cur, link); - } - return 0; -} - -const char * -yasm_section_get_name(const yasm_section *sect) -{ - return sect->name; -} - -void -yasm_section_set_align(yasm_section *sect, unsigned long align, - unsigned long line) -{ - sect->align = align; -} - -unsigned long -yasm_section_get_align(const yasm_section *sect) -{ - return sect->align; -} - -static void -yasm_section_destroy(yasm_section *sect) -{ - yasm_bytecode *cur, *next; - yasm_reloc *r_cur, *r_next; - - if (!sect) - return; - - yasm_xfree(sect->name); - yasm__assoc_data_destroy(sect->assoc_data); - - /* Delete bytecodes */ - cur = STAILQ_FIRST(§->bcs); - while (cur) { - next = STAILQ_NEXT(cur, link); - yasm_bc_destroy(cur); - cur = next; - } - - /* Delete relocations */ - r_cur = STAILQ_FIRST(§->relocs); - while (r_cur) { - r_next = STAILQ_NEXT(r_cur, link); - yasm_intnum_destroy(r_cur->addr); - sect->destroy_reloc(r_cur); - r_cur = r_next; - } - - yasm_xfree(sect); -} - -void -yasm_section_print(const yasm_section *sect, FILE *f, int indent_level, - int print_bcs) -{ - if (!sect) { - fprintf(f, "%*s(none)\n", indent_level, ""); - return; - } - - fprintf(f, "%*sname=%s\n", indent_level, "", sect->name); - - if (sect->assoc_data) { - fprintf(f, "%*sAssociated data:\n", indent_level, ""); - yasm__assoc_data_print(sect->assoc_data, f, indent_level+1); - } - - if (print_bcs) { - yasm_bytecode *cur; - - fprintf(f, "%*sBytecodes:\n", indent_level, ""); - - STAILQ_FOREACH(cur, §->bcs, link) { - fprintf(f, "%*sNext Bytecode:\n", indent_level+1, ""); - yasm_bc_print(cur, f, indent_level+2); - } - } -} - -/* - * Robertson (1977) optimizer - * Based (somewhat loosely) on the algorithm given in: - * MRC Technical Summary Report # 1779 - * CODE GENERATION FOR SHORT/LONG ADDRESS MACHINES - * Edward L. Robertson - * Mathematics Research Center - * University of Wisconsin-Madison - * 610 Walnut Street - * Madison, Wisconsin 53706 - * August 1977 - * - * Key components of algorithm: - * - start assuming all short forms - * - build spans for short->long transition dependencies - * - if a long form is needed, walk the dependencies and update - * Major differences from Robertson's algorithm: - * - detection of cycles - * - any difference of two locations is allowed - * - handling of alignment/org gaps (offset setting) - * - handling of multiples - * - * Data structures: - * - Interval tree to store spans and associated data - * - Queues QA and QB - * - * Each span keeps track of: - * - Associated bytecode (bytecode that depends on the span length) - * - Active/inactive state (starts out active) - * - Sign (negative/positive; negative being "backwards" in address) - * - Current length in bytes - * - New length in bytes - * - Negative/Positive thresholds - * - Span ID (unique within each bytecode) - * - * How org and align and any other offset-based bytecodes are handled: - * - * Some portions are critical values that must not depend on any bytecode - * offset (either relative or absolute). - * - * All offset-setters (ORG and ALIGN) are put into a linked list in section - * order (e.g. increasing offset order). Each span keeps track of the next - * offset-setter following the span's associated bytecode. - * - * When a bytecode is expanded, the next offset-setter is examined. The - * offset-setter may be able to absorb the expansion (e.g. any offset - * following it would not change), or it may have to move forward (in the - * case of align) or error (in the case of org). If it has to move forward, - * following offset-setters must also be examined for absorption or moving - * forward. In either case, the ongoing offset is updated as well as the - * lengths of any spans dependent on the offset-setter. - * - * Alignment/ORG value is critical value. - * Cannot be combined with TIMES. - * - * How times is handled: - * - * TIMES: Handled separately from bytecode "raw" size. If not span-dependent, - * trivial (just multiplied in at any bytecode size increase). Span - * dependent times update on any change (span ID 0). If the resultant - * next bytecode offset would be less than the old next bytecode offset, - * error. Otherwise increase offset and update dependent spans. - * - * To reduce interval tree size, a first expansion pass is performed - * before the spans are added to the tree. - * - * Basic algorithm outline: - * - * 1. Initialization: - * a. Number bytecodes sequentially (via bc_index) and calculate offsets - * of all bytecodes assuming minimum length, building a list of all - * dependent spans as we go. - * "minimum" here means absolute minimum: - * - align/org (offset-based) bumps offset as normal - * - times values (with span-dependent values) assumed to be 0 - * b. Iterate over spans. Set span length based on bytecode offsets - * determined in 1a. If span is "certainly" long because the span - * is an absolute reference to another section (or external) or the - * distance calculated based on the minimum length is greater than the - * span's threshold, expand the span's bytecode, and if no further - * expansion can result, mark span as inactive. - * c. Iterate over bytecodes to update all bytecode offsets based on new - * (expanded) lengths calculated in 1b. - * d. Iterate over active spans. Add span to interval tree. Update span's - * length based on new bytecode offsets determined in 1c. If span's - * length exceeds long threshold, add that span to Q. - * 2. Main loop: - * While Q not empty: - * Expand BC dependent on span at head of Q (and remove span from Q). - * Update span: - * If BC no longer dependent on span, mark span as inactive. - * If BC has new thresholds for span, update span. - * If BC increased in size, for each active span that contains BC: - * Increase span length by difference between short and long BC length. - * If span exceeds long threshold (or is flagged to recalculate on any - * change), add it to tail of Q. - * 3. Final pass over bytecodes to generate final offsets. - */ - -typedef struct yasm_span yasm_span; - -typedef struct yasm_offset_setter { - /* Linked list in section order (e.g. offset order) */ - /*@reldef@*/ STAILQ_ENTRY(yasm_offset_setter) link; - - /*@dependent@*/ yasm_bytecode *bc; - - unsigned long cur_val, new_val; - unsigned long thres; -} yasm_offset_setter; - -typedef struct yasm_span_term { - yasm_bytecode *precbc, *precbc2; - yasm_span *span; /* span this term is a member of */ - long cur_val, new_val; - unsigned int subst; -} yasm_span_term; - -struct yasm_span { - /*@reldef@*/ TAILQ_ENTRY(yasm_span) link; /* for allocation tracking */ - /*@reldef@*/ STAILQ_ENTRY(yasm_span) linkq; /* for Q */ - - /*@dependent@*/ yasm_bytecode *bc; - - yasm_value depval; - - /* span term for relative portion of value */ - yasm_span_term *rel_term; - /* span terms in absolute portion of value */ - yasm_span_term *terms; - yasm_expr__item *items; - unsigned int num_terms; - - long cur_val; - long new_val; - - long neg_thres; - long pos_thres; - - int id; - - int active; - - /* NULL-terminated array of spans that led to this span. Used only for - * checking for circular references (cycles) with id=0 spans. - */ - yasm_span **backtrace; - int backtrace_size; - - /* First offset setter following this span's bytecode */ - yasm_offset_setter *os; -}; - -typedef struct optimize_data { - /*@reldef@*/ TAILQ_HEAD(yasm_span_head, yasm_span) spans; - /*@reldef@*/ STAILQ_HEAD(yasm_span_shead, yasm_span) QA, QB; - /*@only@*/ IntervalTree *itree; - /*@reldef@*/ STAILQ_HEAD(offset_setters_head, yasm_offset_setter) - offset_setters; - long len_diff; /* used only for optimize_term_expand */ - yasm_span *span; /* used only for check_cycle */ - yasm_offset_setter *os; -} optimize_data; - -static yasm_span * -create_span(yasm_bytecode *bc, int id, /*@null@*/ const yasm_value *value, - long neg_thres, long pos_thres, yasm_offset_setter *os) -{ - yasm_span *span = yasm_xmalloc(sizeof(yasm_span)); - - span->bc = bc; - if (value) - yasm_value_init_copy(&span->depval, value); - else - yasm_value_initialize(&span->depval, NULL, 0); - span->rel_term = NULL; - span->terms = NULL; - span->items = NULL; - span->num_terms = 0; - span->cur_val = 0; - span->new_val = 0; - span->neg_thres = neg_thres; - span->pos_thres = pos_thres; - span->id = id; - span->active = 1; - span->backtrace = NULL; - span->backtrace_size = 0; - span->os = os; - - return span; -} - -static void -optimize_add_span(void *add_span_data, yasm_bytecode *bc, int id, - const yasm_value *value, long neg_thres, long pos_thres) -{ - optimize_data *optd = (optimize_data *)add_span_data; - yasm_span *span; - span = create_span(bc, id, value, neg_thres, pos_thres, optd->os); - TAILQ_INSERT_TAIL(&optd->spans, span, link); -} - -static void -add_span_term(unsigned int subst, yasm_bytecode *precbc, - yasm_bytecode *precbc2, void *d) -{ - yasm_span *span = d; - yasm_intnum *intn; - - if (subst >= span->num_terms) { - /* Linear expansion since total number is essentially always small */ - span->num_terms = subst+1; - span->terms = yasm_xrealloc(span->terms, - span->num_terms*sizeof(yasm_span_term)); - } - span->terms[subst].precbc = precbc; - span->terms[subst].precbc2 = precbc2; - span->terms[subst].span = span; - span->terms[subst].subst = subst; - - intn = yasm_calc_bc_dist(precbc, precbc2); - if (!intn) - yasm_internal_error(N_("could not calculate bc distance")); - span->terms[subst].cur_val = 0; - span->terms[subst].new_val = yasm_intnum_get_int(intn); - yasm_intnum_destroy(intn); -} - -static void -span_create_terms(yasm_span *span) -{ - unsigned int i; - - /* Split out sym-sym terms in absolute portion of dependent value */ - if (span->depval.abs) { - span->num_terms = yasm_expr__bc_dist_subst(&span->depval.abs, span, - add_span_term); - if (span->num_terms > 0) { - span->items = yasm_xmalloc(span->num_terms*sizeof(yasm_expr__item)); - for (i=0; i<span->num_terms; i++) { - /* Create items with dummy value */ - span->items[i].type = YASM_EXPR_INT; - span->items[i].data.intn = yasm_intnum_create_int(0); - - /* Check for circular references */ - if (span->id <= 0 && - ((span->bc->bc_index > span->terms[i].precbc->bc_index && - span->bc->bc_index <= span->terms[i].precbc2->bc_index) || - (span->bc->bc_index > span->terms[i].precbc2->bc_index && - span->bc->bc_index <= span->terms[i].precbc->bc_index))) - yasm_error_set(YASM_ERROR_VALUE, - N_("circular reference detected")); - } - } - } - - /* Create term for relative portion of dependent value */ - if (span->depval.rel) { - yasm_bytecode *rel_precbc; - int sym_local; - - sym_local = yasm_symrec_get_label(span->depval.rel, &rel_precbc); - if (span->depval.wrt || span->depval.seg_of || span->depval.section_rel - || !sym_local) - return; /* we can't handle SEG, WRT, or external symbols */ - if (rel_precbc->section != span->bc->section) - return; /* not in this section */ - if (!span->depval.curpos_rel) - return; /* not PC-relative */ - - span->rel_term = yasm_xmalloc(sizeof(yasm_span_term)); - span->rel_term->precbc = NULL; - span->rel_term->precbc2 = rel_precbc; - span->rel_term->span = span; - span->rel_term->subst = ~0U; - - span->rel_term->cur_val = 0; - span->rel_term->new_val = yasm_bc_next_offset(rel_precbc) - - span->bc->offset; - } -} - -/* Recalculate span value based on current span replacement values. - * Returns 1 if span needs expansion (e.g. exceeded thresholds). - */ -static int -recalc_normal_span(yasm_span *span) -{ - span->new_val = 0; - - if (span->depval.abs) { - yasm_expr *abs_copy = yasm_expr_copy(span->depval.abs); - /*@null@*/ /*@dependent@*/ yasm_intnum *num; - - /* Update sym-sym terms and substitute back into expr */ - unsigned int i; - for (i=0; i<span->num_terms; i++) - yasm_intnum_set_int(span->items[i].data.intn, - span->terms[i].new_val); - yasm_expr__subst(abs_copy, span->num_terms, span->items); - num = yasm_expr_get_intnum(&abs_copy, 0); - if (num) - span->new_val = yasm_intnum_get_int(num); - else - span->new_val = LONG_MAX; /* too complex; force to longest form */ - yasm_expr_destroy(abs_copy); - } - - if (span->rel_term) { - if (span->new_val != LONG_MAX && span->rel_term->new_val != LONG_MAX) - span->new_val += span->rel_term->new_val >> span->depval.rshift; - else - span->new_val = LONG_MAX; /* too complex; force to longest form */ - } else if (span->depval.rel) - span->new_val = LONG_MAX; /* too complex; force to longest form */ - - if (span->new_val == LONG_MAX) - span->active = 0; - - /* If id<=0, flag update on any change */ - if (span->id <= 0) - return (span->new_val != span->cur_val); - - return (span->new_val < span->neg_thres - || span->new_val > span->pos_thres); -} - -/* Updates all bytecode offsets. For offset-based bytecodes, calls expand - * to determine new length. - */ -static int -update_all_bc_offsets(yasm_object *object, yasm_errwarns *errwarns) -{ - yasm_section *sect; - int saw_error = 0; - - STAILQ_FOREACH(sect, &object->sections, link) { - unsigned long offset = 0; - - yasm_bytecode *bc = STAILQ_FIRST(§->bcs); - yasm_bytecode *prevbc; - - /* Skip our locally created empty bytecode first. */ - prevbc = bc; - bc = STAILQ_NEXT(bc, link); - - /* Iterate through the remainder, if any. */ - while (bc) { - if (bc->callback->special == YASM_BC_SPECIAL_OFFSET) { - /* Recalculate/adjust len of offset-based bytecodes here */ - long neg_thres = 0; - long pos_thres = (long)yasm_bc_next_offset(bc); - int retval = yasm_bc_expand(bc, 1, 0, - (long)yasm_bc_next_offset(prevbc), - &neg_thres, &pos_thres); - yasm_errwarn_propagate(errwarns, bc->line); - if (retval < 0) - saw_error = 1; - } - bc->offset = offset; - offset += bc->len*bc->mult_int; - prevbc = bc; - bc = STAILQ_NEXT(bc, link); - } - } - return saw_error; -} - -static void -span_destroy(/*@only@*/ yasm_span *span) -{ - unsigned int i; - - yasm_value_delete(&span->depval); - if (span->rel_term) - yasm_xfree(span->rel_term); - if (span->terms) - yasm_xfree(span->terms); - if (span->items) { - for (i=0; i<span->num_terms; i++) - yasm_intnum_destroy(span->items[i].data.intn); - yasm_xfree(span->items); - } - if (span->backtrace) - yasm_xfree(span->backtrace); - yasm_xfree(span); -} - -static void -optimize_cleanup(optimize_data *optd) -{ - yasm_span *s1, *s2; - yasm_offset_setter *os1, *os2; - - IT_destroy(optd->itree); - - s1 = TAILQ_FIRST(&optd->spans); - while (s1) { - s2 = TAILQ_NEXT(s1, link); - span_destroy(s1); - s1 = s2; - } - - os1 = STAILQ_FIRST(&optd->offset_setters); - while (os1) { - os2 = STAILQ_NEXT(os1, link); - yasm_xfree(os1); - os1 = os2; - } -} - -static void -optimize_itree_add(IntervalTree *itree, yasm_span *span, yasm_span_term *term) -{ - long precbc_index, precbc2_index; - unsigned long low, high; - - /* Update term length */ - if (term->precbc) - precbc_index = term->precbc->bc_index; - else - precbc_index = span->bc->bc_index-1; - - if (term->precbc2) - precbc2_index = term->precbc2->bc_index; - else - precbc2_index = span->bc->bc_index-1; - - if (precbc_index < precbc2_index) { - low = precbc_index+1; - high = precbc2_index; - } else if (precbc_index > precbc2_index) { - low = precbc2_index+1; - high = precbc_index; - } else - return; /* difference is same bc - always 0! */ - - IT_insert(itree, (long)low, (long)high, term); -} - -static void -check_cycle(IntervalTreeNode *node, void *d) -{ - optimize_data *optd = d; - yasm_span_term *term = node->data; - yasm_span *depspan = term->span; - int i; - int depspan_bt_alloc; - - /* Only check for cycles in id=0 spans */ - if (depspan->id > 0) - return; - - /* Check for a circular reference by looking to see if this dependent - * span is in our backtrace. - */ - if (optd->span->backtrace) { - for (i=0; i<optd->span->backtrace_size; i++) { - if (optd->span->backtrace[i] == depspan) - yasm_error_set(YASM_ERROR_VALUE, - N_("circular reference detected")); - } - } - - /* Add our complete backtrace and ourselves to backtrace of dependent - * span. - */ - if (!depspan->backtrace) { - depspan->backtrace = yasm_xmalloc((optd->span->backtrace_size+1)* - sizeof(yasm_span *)); - if (optd->span->backtrace_size > 0) - memcpy(depspan->backtrace, optd->span->backtrace, - optd->span->backtrace_size*sizeof(yasm_span *)); - depspan->backtrace[optd->span->backtrace_size] = optd->span; - depspan->backtrace_size = optd->span->backtrace_size+1; - return; - } - - /* Add our complete backtrace, checking for duplicates */ - depspan_bt_alloc = depspan->backtrace_size; - for (i=0; i<optd->span->backtrace_size; i++) { - int present = 0; - int j; - for (j=0; j<depspan->backtrace_size; j++) { - if (optd->span->backtrace[i] == optd->span->backtrace[j]) { - present = 1; - break; - } - } - if (present) - continue; - /* Not already in array; add it. */ - if (depspan->backtrace_size >= depspan_bt_alloc) - { - depspan_bt_alloc *= 2; - depspan->backtrace = - yasm_xrealloc(depspan->backtrace, - depspan_bt_alloc*sizeof(yasm_span *)); - } - depspan->backtrace[depspan->backtrace_size] = optd->span->backtrace[i]; - depspan->backtrace_size++; - } - - /* Add ourselves. */ - if (depspan->backtrace_size >= depspan_bt_alloc) - { - depspan_bt_alloc++; - depspan->backtrace = - yasm_xrealloc(depspan->backtrace, - depspan_bt_alloc*sizeof(yasm_span *)); - } - depspan->backtrace[depspan->backtrace_size] = optd->span; - depspan->backtrace_size++; -} - -static void -optimize_term_expand(IntervalTreeNode *node, void *d) -{ - optimize_data *optd = d; - yasm_span_term *term = node->data; - yasm_span *span = term->span; - long len_diff = optd->len_diff; - long precbc_index, precbc2_index; - - /* Don't expand inactive spans */ - if (!span->active) - return; - - /* Update term length */ - if (term->precbc) - precbc_index = term->precbc->bc_index; - else - precbc_index = span->bc->bc_index-1; - - if (term->precbc2) - precbc2_index = term->precbc2->bc_index; - else - precbc2_index = span->bc->bc_index-1; - - if (precbc_index < precbc2_index) - term->new_val += len_diff; - else - term->new_val -= len_diff; - - /* If already on Q, don't re-add */ - if (span->active == 2) - return; - - /* Update term and check against thresholds */ - if (!recalc_normal_span(span)) - return; /* didn't exceed thresholds, we're done */ - - /* Exceeded thresholds, need to add to Q for expansion */ - if (span->id <= 0) - STAILQ_INSERT_TAIL(&optd->QA, span, linkq); - else - STAILQ_INSERT_TAIL(&optd->QB, span, linkq); - span->active = 2; /* Mark as being in Q */ -} - -void -yasm_object_optimize(yasm_object *object, yasm_errwarns *errwarns) -{ - yasm_section *sect; - unsigned long bc_index = 0; - int saw_error = 0; - optimize_data optd; - yasm_span *span, *span_temp; - yasm_offset_setter *os; - int retval; - unsigned int i; - - TAILQ_INIT(&optd.spans); - STAILQ_INIT(&optd.offset_setters); - optd.itree = IT_create(); - - /* Create an placeholder offset setter for spans to point to; this will - * get updated if/when we actually run into one. - */ - os = yasm_xmalloc(sizeof(yasm_offset_setter)); - os->bc = NULL; - os->cur_val = 0; - os->new_val = 0; - os->thres = 0; - STAILQ_INSERT_TAIL(&optd.offset_setters, os, link); - optd.os = os; - - /* Step 1a */ - STAILQ_FOREACH(sect, &object->sections, link) { - unsigned long offset = 0; - - yasm_bytecode *bc = STAILQ_FIRST(§->bcs); - - bc->bc_index = bc_index++; - - /* Skip our locally created empty bytecode first. */ - bc = STAILQ_NEXT(bc, link); - - /* Iterate through the remainder, if any. */ - while (bc) { - bc->bc_index = bc_index++; - bc->offset = offset; - - retval = yasm_bc_calc_len(bc, optimize_add_span, &optd); - yasm_errwarn_propagate(errwarns, bc->line); - if (retval) - saw_error = 1; - else { - if (bc->callback->special == YASM_BC_SPECIAL_OFFSET) { - /* Remember it as offset setter */ - os->bc = bc; - os->thres = yasm_bc_next_offset(bc); - - /* Create new placeholder */ - os = yasm_xmalloc(sizeof(yasm_offset_setter)); - os->bc = NULL; - os->cur_val = 0; - os->new_val = 0; - os->thres = 0; - STAILQ_INSERT_TAIL(&optd.offset_setters, os, link); - optd.os = os; - - if (bc->multiple) { - yasm_error_set(YASM_ERROR_VALUE, - N_("cannot combine multiples and setting assembly position")); - yasm_errwarn_propagate(errwarns, bc->line); - saw_error = 1; - } - } - - offset += bc->len*bc->mult_int; - } - - bc = STAILQ_NEXT(bc, link); - } - } - - if (saw_error) { - optimize_cleanup(&optd); - return; - } - - /* Step 1b */ - TAILQ_FOREACH_SAFE(span, &optd.spans, link, span_temp) { - span_create_terms(span); - if (yasm_error_occurred()) { - yasm_errwarn_propagate(errwarns, span->bc->line); - saw_error = 1; - } else if (recalc_normal_span(span)) { - retval = yasm_bc_expand(span->bc, span->id, span->cur_val, - span->new_val, &span->neg_thres, - &span->pos_thres); - yasm_errwarn_propagate(errwarns, span->bc->line); - if (retval < 0) - saw_error = 1; - else if (retval > 0) { - if (!span->active) { - yasm_error_set(YASM_ERROR_VALUE, - N_("secondary expansion of an external/complex value")); - yasm_errwarn_propagate(errwarns, span->bc->line); - saw_error = 1; - } - } else { - TAILQ_REMOVE(&optd.spans, span, link); - span_destroy(span); - continue; - } - } - span->cur_val = span->new_val; - } - - if (saw_error) { - optimize_cleanup(&optd); - return; - } - - /* Step 1c */ - if (update_all_bc_offsets(object, errwarns)) { - optimize_cleanup(&optd); - return; - } - - /* Step 1d */ - STAILQ_INIT(&optd.QB); - TAILQ_FOREACH(span, &optd.spans, link) { - yasm_intnum *intn; - - /* Update span terms based on new bc offsets */ - for (i=0; i<span->num_terms; i++) { - intn = yasm_calc_bc_dist(span->terms[i].precbc, - span->terms[i].precbc2); - if (!intn) - yasm_internal_error(N_("could not calculate bc distance")); - span->terms[i].cur_val = span->terms[i].new_val; - span->terms[i].new_val = yasm_intnum_get_int(intn); - yasm_intnum_destroy(intn); - } - if (span->rel_term) { - span->rel_term->cur_val = span->rel_term->new_val; - if (span->rel_term->precbc2) - span->rel_term->new_val = - yasm_bc_next_offset(span->rel_term->precbc2) - - span->bc->offset; - else - span->rel_term->new_val = span->bc->offset - - yasm_bc_next_offset(span->rel_term->precbc); - } - - if (recalc_normal_span(span)) { - /* Exceeded threshold, add span to QB */ - STAILQ_INSERT_TAIL(&optd.QB, span, linkq); - span->active = 2; - } - } - - /* Do we need step 2? If not, go ahead and exit. */ - if (STAILQ_EMPTY(&optd.QB)) { - optimize_cleanup(&optd); - return; - } - - /* Update offset-setters values */ - STAILQ_FOREACH(os, &optd.offset_setters, link) { - if (!os->bc) - continue; - os->thres = yasm_bc_next_offset(os->bc); - os->new_val = os->bc->offset; - os->cur_val = os->new_val; - } - - /* Build up interval tree */ - TAILQ_FOREACH(span, &optd.spans, link) { - for (i=0; i<span->num_terms; i++) - optimize_itree_add(optd.itree, span, &span->terms[i]); - if (span->rel_term) - optimize_itree_add(optd.itree, span, span->rel_term); - } - - /* Look for cycles in times expansion (span.id==0) */ - TAILQ_FOREACH(span, &optd.spans, link) { - if (span->id > 0) - continue; - optd.span = span; - IT_enumerate(optd.itree, (long)span->bc->bc_index, - (long)span->bc->bc_index, &optd, check_cycle); - if (yasm_error_occurred()) { - yasm_errwarn_propagate(errwarns, span->bc->line); - saw_error = 1; - } - } - - if (saw_error) { - optimize_cleanup(&optd); - return; - } - - /* Step 2 */ - STAILQ_INIT(&optd.QA); - while (!STAILQ_EMPTY(&optd.QA) || !(STAILQ_EMPTY(&optd.QB))) { - unsigned long orig_len; - long offset_diff; - - /* QA is for TIMES, update those first, then update non-TIMES. - * This is so that TIMES can absorb increases before we look at - * expanding non-TIMES BCs. - */ - if (!STAILQ_EMPTY(&optd.QA)) { - span = STAILQ_FIRST(&optd.QA); - STAILQ_REMOVE_HEAD(&optd.QA, linkq); - } else { - span = STAILQ_FIRST(&optd.QB); - STAILQ_REMOVE_HEAD(&optd.QB, linkq); - } - - if (!span->active) - continue; - span->active = 1; /* no longer in Q */ - - /* Make sure we ended up ultimately exceeding thresholds; due to - * offset BCs we may have been placed on Q and then reduced in size - * again. - */ - if (!recalc_normal_span(span)) - continue; - - orig_len = span->bc->len * span->bc->mult_int; - - retval = yasm_bc_expand(span->bc, span->id, span->cur_val, - span->new_val, &span->neg_thres, - &span->pos_thres); - yasm_errwarn_propagate(errwarns, span->bc->line); - - if (retval < 0) { - /* error */ - saw_error = 1; - continue; - } else if (retval > 0) { - /* another threshold, keep active */ - for (i=0; i<span->num_terms; i++) - span->terms[i].cur_val = span->terms[i].new_val; - if (span->rel_term) - span->rel_term->cur_val = span->rel_term->new_val; - span->cur_val = span->new_val; - } else - span->active = 0; /* we're done with this span */ - - optd.len_diff = span->bc->len * span->bc->mult_int - orig_len; - if (optd.len_diff == 0) - continue; /* didn't increase in size */ - - /* Iterate over all spans dependent across the bc just expanded */ - IT_enumerate(optd.itree, (long)span->bc->bc_index, - (long)span->bc->bc_index, &optd, optimize_term_expand); - - /* Iterate over offset-setters that follow the bc just expanded. - * Stop iteration if: - * - no more offset-setters in this section - * - offset-setter didn't move its following offset - */ - os = span->os; - offset_diff = optd.len_diff; - while (os->bc && os->bc->section == span->bc->section - && offset_diff != 0) { - unsigned long old_next_offset = os->cur_val + os->bc->len; - long neg_thres_temp; - - if (offset_diff < 0 && (unsigned long)(-offset_diff) > os->new_val) - yasm_internal_error(N_("org/align went to negative offset")); - os->new_val += offset_diff; - - orig_len = os->bc->len; - retval = yasm_bc_expand(os->bc, 1, (long)os->cur_val, - (long)os->new_val, &neg_thres_temp, - (long *)&os->thres); - yasm_errwarn_propagate(errwarns, os->bc->line); - - offset_diff = os->new_val + os->bc->len - old_next_offset; - optd.len_diff = os->bc->len - orig_len; - if (optd.len_diff != 0) - IT_enumerate(optd.itree, (long)os->bc->bc_index, - (long)os->bc->bc_index, &optd, optimize_term_expand); - - os->cur_val = os->new_val; - os = STAILQ_NEXT(os, link); - } - } - - if (saw_error) { - optimize_cleanup(&optd); - return; - } - - /* Step 3 */ - update_all_bc_offsets(object, errwarns); - optimize_cleanup(&optd); -} + yasm_xfree(object->obj_filename); + + /* Delete symbol table */ + yasm_symtab_destroy(object->symtab); + + /* Delete architecture */ + if (object->arch) + yasm_arch_destroy(object->arch); + + yasm_xfree(object); +} + +void +yasm_object_print(const yasm_object *object, FILE *f, int indent_level) +{ + yasm_section *cur; + + /* Print symbol table */ + fprintf(f, "%*sSymbol Table:\n", indent_level, ""); + yasm_symtab_print(object->symtab, f, indent_level+1); + + /* Print sections and bytecodes */ + STAILQ_FOREACH(cur, &object->sections, link) { + fprintf(f, "%*sSection:\n", indent_level, ""); + yasm_section_print(cur, f, indent_level+1, 1); + } +} + +void +yasm_object_finalize(yasm_object *object, yasm_errwarns *errwarns) +{ + yasm_section *sect; + + /* Iterate through sections */ + STAILQ_FOREACH(sect, &object->sections, link) { + yasm_bytecode *cur = STAILQ_FIRST(§->bcs); + yasm_bytecode *prev; + + /* Skip our locally created empty bytecode first. */ + prev = cur; + cur = STAILQ_NEXT(cur, link); + + /* Iterate through the remainder, if any. */ + while (cur) { + /* Finalize */ + yasm_bc_finalize(cur, prev); + yasm_errwarn_propagate(errwarns, cur->line); + prev = cur; + cur = STAILQ_NEXT(cur, link); + } + } +} + +int +yasm_object_sections_traverse(yasm_object *object, /*@null@*/ void *d, + int (*func) (yasm_section *sect, + /*@null@*/ void *d)) +{ + yasm_section *cur; + + STAILQ_FOREACH(cur, &object->sections, link) { + int retval = func(cur, d); + if (retval != 0) + return retval; + } + return 0; +} + +/*@-onlytrans@*/ +yasm_section * +yasm_object_find_general(yasm_object *object, const char *name) +{ + yasm_section *cur; + + STAILQ_FOREACH(cur, &object->sections, link) { + if (strcmp(cur->name, name) == 0) + return cur; + } + return NULL; +} +/*@=onlytrans@*/ + +void +yasm_section_add_reloc(yasm_section *sect, yasm_reloc *reloc, + void (*destroy_func) (/*@only@*/ void *reloc)) +{ + STAILQ_INSERT_TAIL(§->relocs, reloc, link); + if (!destroy_func) + yasm_internal_error(N_("NULL destroy function given to add_reloc")); + else if (sect->destroy_reloc && destroy_func != sect->destroy_reloc) + yasm_internal_error(N_("different destroy function given to add_reloc")); + sect->destroy_reloc = destroy_func; +} + +/*@null@*/ yasm_reloc * +yasm_section_relocs_first(yasm_section *sect) +{ + return STAILQ_FIRST(§->relocs); +} + +#undef yasm_section_reloc_next +/*@null@*/ yasm_reloc * +yasm_section_reloc_next(yasm_reloc *reloc) +{ + return STAILQ_NEXT(reloc, link); +} + +void +yasm_reloc_get(yasm_reloc *reloc, yasm_intnum **addrp, yasm_symrec **symp) +{ + *addrp = reloc->addr; + *symp = reloc->sym; +} + + +yasm_bytecode * +yasm_section_bcs_first(yasm_section *sect) +{ + return STAILQ_FIRST(§->bcs); +} + +yasm_bytecode * +yasm_section_bcs_last(yasm_section *sect) +{ + return STAILQ_LAST(§->bcs, yasm_bytecode, link); +} + +yasm_bytecode * +yasm_section_bcs_append(yasm_section *sect, yasm_bytecode *bc) +{ + if (bc) { + if (bc->callback) { + bc->section = sect; /* record parent section */ + STAILQ_INSERT_TAIL(§->bcs, bc, link); + return bc; + } else + yasm_xfree(bc); + } + return (yasm_bytecode *)NULL; +} + +int +yasm_section_bcs_traverse(yasm_section *sect, + /*@null@*/ yasm_errwarns *errwarns, + /*@null@*/ void *d, + int (*func) (yasm_bytecode *bc, /*@null@*/ void *d)) +{ + yasm_bytecode *cur = STAILQ_FIRST(§->bcs); + + /* Skip our locally created empty bytecode first. */ + cur = STAILQ_NEXT(cur, link); + + /* Iterate through the remainder, if any. */ + while (cur) { + int retval = func(cur, d); + if (errwarns) + yasm_errwarn_propagate(errwarns, cur->line); + if (retval != 0) + return retval; + cur = STAILQ_NEXT(cur, link); + } + return 0; +} + +const char * +yasm_section_get_name(const yasm_section *sect) +{ + return sect->name; +} + +void +yasm_section_set_align(yasm_section *sect, unsigned long align, + unsigned long line) +{ + sect->align = align; +} + +unsigned long +yasm_section_get_align(const yasm_section *sect) +{ + return sect->align; +} + +static void +yasm_section_destroy(yasm_section *sect) +{ + yasm_bytecode *cur, *next; + yasm_reloc *r_cur, *r_next; + + if (!sect) + return; + + yasm_xfree(sect->name); + yasm__assoc_data_destroy(sect->assoc_data); + + /* Delete bytecodes */ + cur = STAILQ_FIRST(§->bcs); + while (cur) { + next = STAILQ_NEXT(cur, link); + yasm_bc_destroy(cur); + cur = next; + } + + /* Delete relocations */ + r_cur = STAILQ_FIRST(§->relocs); + while (r_cur) { + r_next = STAILQ_NEXT(r_cur, link); + yasm_intnum_destroy(r_cur->addr); + sect->destroy_reloc(r_cur); + r_cur = r_next; + } + + yasm_xfree(sect); +} + +void +yasm_section_print(const yasm_section *sect, FILE *f, int indent_level, + int print_bcs) +{ + if (!sect) { + fprintf(f, "%*s(none)\n", indent_level, ""); + return; + } + + fprintf(f, "%*sname=%s\n", indent_level, "", sect->name); + + if (sect->assoc_data) { + fprintf(f, "%*sAssociated data:\n", indent_level, ""); + yasm__assoc_data_print(sect->assoc_data, f, indent_level+1); + } + + if (print_bcs) { + yasm_bytecode *cur; + + fprintf(f, "%*sBytecodes:\n", indent_level, ""); + + STAILQ_FOREACH(cur, §->bcs, link) { + fprintf(f, "%*sNext Bytecode:\n", indent_level+1, ""); + yasm_bc_print(cur, f, indent_level+2); + } + } +} + +/* + * Robertson (1977) optimizer + * Based (somewhat loosely) on the algorithm given in: + * MRC Technical Summary Report # 1779 + * CODE GENERATION FOR SHORT/LONG ADDRESS MACHINES + * Edward L. Robertson + * Mathematics Research Center + * University of Wisconsin-Madison + * 610 Walnut Street + * Madison, Wisconsin 53706 + * August 1977 + * + * Key components of algorithm: + * - start assuming all short forms + * - build spans for short->long transition dependencies + * - if a long form is needed, walk the dependencies and update + * Major differences from Robertson's algorithm: + * - detection of cycles + * - any difference of two locations is allowed + * - handling of alignment/org gaps (offset setting) + * - handling of multiples + * + * Data structures: + * - Interval tree to store spans and associated data + * - Queues QA and QB + * + * Each span keeps track of: + * - Associated bytecode (bytecode that depends on the span length) + * - Active/inactive state (starts out active) + * - Sign (negative/positive; negative being "backwards" in address) + * - Current length in bytes + * - New length in bytes + * - Negative/Positive thresholds + * - Span ID (unique within each bytecode) + * + * How org and align and any other offset-based bytecodes are handled: + * + * Some portions are critical values that must not depend on any bytecode + * offset (either relative or absolute). + * + * All offset-setters (ORG and ALIGN) are put into a linked list in section + * order (e.g. increasing offset order). Each span keeps track of the next + * offset-setter following the span's associated bytecode. + * + * When a bytecode is expanded, the next offset-setter is examined. The + * offset-setter may be able to absorb the expansion (e.g. any offset + * following it would not change), or it may have to move forward (in the + * case of align) or error (in the case of org). If it has to move forward, + * following offset-setters must also be examined for absorption or moving + * forward. In either case, the ongoing offset is updated as well as the + * lengths of any spans dependent on the offset-setter. + * + * Alignment/ORG value is critical value. + * Cannot be combined with TIMES. + * + * How times is handled: + * + * TIMES: Handled separately from bytecode "raw" size. If not span-dependent, + * trivial (just multiplied in at any bytecode size increase). Span + * dependent times update on any change (span ID 0). If the resultant + * next bytecode offset would be less than the old next bytecode offset, + * error. Otherwise increase offset and update dependent spans. + * + * To reduce interval tree size, a first expansion pass is performed + * before the spans are added to the tree. + * + * Basic algorithm outline: + * + * 1. Initialization: + * a. Number bytecodes sequentially (via bc_index) and calculate offsets + * of all bytecodes assuming minimum length, building a list of all + * dependent spans as we go. + * "minimum" here means absolute minimum: + * - align/org (offset-based) bumps offset as normal + * - times values (with span-dependent values) assumed to be 0 + * b. Iterate over spans. Set span length based on bytecode offsets + * determined in 1a. If span is "certainly" long because the span + * is an absolute reference to another section (or external) or the + * distance calculated based on the minimum length is greater than the + * span's threshold, expand the span's bytecode, and if no further + * expansion can result, mark span as inactive. + * c. Iterate over bytecodes to update all bytecode offsets based on new + * (expanded) lengths calculated in 1b. + * d. Iterate over active spans. Add span to interval tree. Update span's + * length based on new bytecode offsets determined in 1c. If span's + * length exceeds long threshold, add that span to Q. + * 2. Main loop: + * While Q not empty: + * Expand BC dependent on span at head of Q (and remove span from Q). + * Update span: + * If BC no longer dependent on span, mark span as inactive. + * If BC has new thresholds for span, update span. + * If BC increased in size, for each active span that contains BC: + * Increase span length by difference between short and long BC length. + * If span exceeds long threshold (or is flagged to recalculate on any + * change), add it to tail of Q. + * 3. Final pass over bytecodes to generate final offsets. + */ + +typedef struct yasm_span yasm_span; + +typedef struct yasm_offset_setter { + /* Linked list in section order (e.g. offset order) */ + /*@reldef@*/ STAILQ_ENTRY(yasm_offset_setter) link; + + /*@dependent@*/ yasm_bytecode *bc; + + unsigned long cur_val, new_val; + unsigned long thres; +} yasm_offset_setter; + +typedef struct yasm_span_term { + yasm_bytecode *precbc, *precbc2; + yasm_span *span; /* span this term is a member of */ + long cur_val, new_val; + unsigned int subst; +} yasm_span_term; + +struct yasm_span { + /*@reldef@*/ TAILQ_ENTRY(yasm_span) link; /* for allocation tracking */ + /*@reldef@*/ STAILQ_ENTRY(yasm_span) linkq; /* for Q */ + + /*@dependent@*/ yasm_bytecode *bc; + + yasm_value depval; + + /* span term for relative portion of value */ + yasm_span_term *rel_term; + /* span terms in absolute portion of value */ + yasm_span_term *terms; + yasm_expr__item *items; + unsigned int num_terms; + + long cur_val; + long new_val; + + long neg_thres; + long pos_thres; + + int id; + + int active; + + /* NULL-terminated array of spans that led to this span. Used only for + * checking for circular references (cycles) with id=0 spans. + */ + yasm_span **backtrace; + int backtrace_size; + + /* First offset setter following this span's bytecode */ + yasm_offset_setter *os; +}; + +typedef struct optimize_data { + /*@reldef@*/ TAILQ_HEAD(yasm_span_head, yasm_span) spans; + /*@reldef@*/ STAILQ_HEAD(yasm_span_shead, yasm_span) QA, QB; + /*@only@*/ IntervalTree *itree; + /*@reldef@*/ STAILQ_HEAD(offset_setters_head, yasm_offset_setter) + offset_setters; + long len_diff; /* used only for optimize_term_expand */ + yasm_span *span; /* used only for check_cycle */ + yasm_offset_setter *os; +} optimize_data; + +static yasm_span * +create_span(yasm_bytecode *bc, int id, /*@null@*/ const yasm_value *value, + long neg_thres, long pos_thres, yasm_offset_setter *os) +{ + yasm_span *span = yasm_xmalloc(sizeof(yasm_span)); + + span->bc = bc; + if (value) + yasm_value_init_copy(&span->depval, value); + else + yasm_value_initialize(&span->depval, NULL, 0); + span->rel_term = NULL; + span->terms = NULL; + span->items = NULL; + span->num_terms = 0; + span->cur_val = 0; + span->new_val = 0; + span->neg_thres = neg_thres; + span->pos_thres = pos_thres; + span->id = id; + span->active = 1; + span->backtrace = NULL; + span->backtrace_size = 0; + span->os = os; + + return span; +} + +static void +optimize_add_span(void *add_span_data, yasm_bytecode *bc, int id, + const yasm_value *value, long neg_thres, long pos_thres) +{ + optimize_data *optd = (optimize_data *)add_span_data; + yasm_span *span; + span = create_span(bc, id, value, neg_thres, pos_thres, optd->os); + TAILQ_INSERT_TAIL(&optd->spans, span, link); +} + +static void +add_span_term(unsigned int subst, yasm_bytecode *precbc, + yasm_bytecode *precbc2, void *d) +{ + yasm_span *span = d; + yasm_intnum *intn; + + if (subst >= span->num_terms) { + /* Linear expansion since total number is essentially always small */ + span->num_terms = subst+1; + span->terms = yasm_xrealloc(span->terms, + span->num_terms*sizeof(yasm_span_term)); + } + span->terms[subst].precbc = precbc; + span->terms[subst].precbc2 = precbc2; + span->terms[subst].span = span; + span->terms[subst].subst = subst; + + intn = yasm_calc_bc_dist(precbc, precbc2); + if (!intn) + yasm_internal_error(N_("could not calculate bc distance")); + span->terms[subst].cur_val = 0; + span->terms[subst].new_val = yasm_intnum_get_int(intn); + yasm_intnum_destroy(intn); +} + +static void +span_create_terms(yasm_span *span) +{ + unsigned int i; + + /* Split out sym-sym terms in absolute portion of dependent value */ + if (span->depval.abs) { + span->num_terms = yasm_expr__bc_dist_subst(&span->depval.abs, span, + add_span_term); + if (span->num_terms > 0) { + span->items = yasm_xmalloc(span->num_terms*sizeof(yasm_expr__item)); + for (i=0; i<span->num_terms; i++) { + /* Create items with dummy value */ + span->items[i].type = YASM_EXPR_INT; + span->items[i].data.intn = yasm_intnum_create_int(0); + + /* Check for circular references */ + if (span->id <= 0 && + ((span->bc->bc_index > span->terms[i].precbc->bc_index && + span->bc->bc_index <= span->terms[i].precbc2->bc_index) || + (span->bc->bc_index > span->terms[i].precbc2->bc_index && + span->bc->bc_index <= span->terms[i].precbc->bc_index))) + yasm_error_set(YASM_ERROR_VALUE, + N_("circular reference detected")); + } + } + } + + /* Create term for relative portion of dependent value */ + if (span->depval.rel) { + yasm_bytecode *rel_precbc; + int sym_local; + + sym_local = yasm_symrec_get_label(span->depval.rel, &rel_precbc); + if (span->depval.wrt || span->depval.seg_of || span->depval.section_rel + || !sym_local) + return; /* we can't handle SEG, WRT, or external symbols */ + if (rel_precbc->section != span->bc->section) + return; /* not in this section */ + if (!span->depval.curpos_rel) + return; /* not PC-relative */ + + span->rel_term = yasm_xmalloc(sizeof(yasm_span_term)); + span->rel_term->precbc = NULL; + span->rel_term->precbc2 = rel_precbc; + span->rel_term->span = span; + span->rel_term->subst = ~0U; + + span->rel_term->cur_val = 0; + span->rel_term->new_val = yasm_bc_next_offset(rel_precbc) - + span->bc->offset; + } +} + +/* Recalculate span value based on current span replacement values. + * Returns 1 if span needs expansion (e.g. exceeded thresholds). + */ +static int +recalc_normal_span(yasm_span *span) +{ + span->new_val = 0; + + if (span->depval.abs) { + yasm_expr *abs_copy = yasm_expr_copy(span->depval.abs); + /*@null@*/ /*@dependent@*/ yasm_intnum *num; + + /* Update sym-sym terms and substitute back into expr */ + unsigned int i; + for (i=0; i<span->num_terms; i++) + yasm_intnum_set_int(span->items[i].data.intn, + span->terms[i].new_val); + yasm_expr__subst(abs_copy, span->num_terms, span->items); + num = yasm_expr_get_intnum(&abs_copy, 0); + if (num) + span->new_val = yasm_intnum_get_int(num); + else + span->new_val = LONG_MAX; /* too complex; force to longest form */ + yasm_expr_destroy(abs_copy); + } + + if (span->rel_term) { + if (span->new_val != LONG_MAX && span->rel_term->new_val != LONG_MAX) + span->new_val += span->rel_term->new_val >> span->depval.rshift; + else + span->new_val = LONG_MAX; /* too complex; force to longest form */ + } else if (span->depval.rel) + span->new_val = LONG_MAX; /* too complex; force to longest form */ + + if (span->new_val == LONG_MAX) + span->active = 0; + + /* If id<=0, flag update on any change */ + if (span->id <= 0) + return (span->new_val != span->cur_val); + + return (span->new_val < span->neg_thres + || span->new_val > span->pos_thres); +} + +/* Updates all bytecode offsets. For offset-based bytecodes, calls expand + * to determine new length. + */ +static int +update_all_bc_offsets(yasm_object *object, yasm_errwarns *errwarns) +{ + yasm_section *sect; + int saw_error = 0; + + STAILQ_FOREACH(sect, &object->sections, link) { + unsigned long offset = 0; + + yasm_bytecode *bc = STAILQ_FIRST(§->bcs); + yasm_bytecode *prevbc; + + /* Skip our locally created empty bytecode first. */ + prevbc = bc; + bc = STAILQ_NEXT(bc, link); + + /* Iterate through the remainder, if any. */ + while (bc) { + if (bc->callback->special == YASM_BC_SPECIAL_OFFSET) { + /* Recalculate/adjust len of offset-based bytecodes here */ + long neg_thres = 0; + long pos_thres = (long)yasm_bc_next_offset(bc); + int retval = yasm_bc_expand(bc, 1, 0, + (long)yasm_bc_next_offset(prevbc), + &neg_thres, &pos_thres); + yasm_errwarn_propagate(errwarns, bc->line); + if (retval < 0) + saw_error = 1; + } + bc->offset = offset; + offset += bc->len*bc->mult_int; + prevbc = bc; + bc = STAILQ_NEXT(bc, link); + } + } + return saw_error; +} + +static void +span_destroy(/*@only@*/ yasm_span *span) +{ + unsigned int i; + + yasm_value_delete(&span->depval); + if (span->rel_term) + yasm_xfree(span->rel_term); + if (span->terms) + yasm_xfree(span->terms); + if (span->items) { + for (i=0; i<span->num_terms; i++) + yasm_intnum_destroy(span->items[i].data.intn); + yasm_xfree(span->items); + } + if (span->backtrace) + yasm_xfree(span->backtrace); + yasm_xfree(span); +} + +static void +optimize_cleanup(optimize_data *optd) +{ + yasm_span *s1, *s2; + yasm_offset_setter *os1, *os2; + + IT_destroy(optd->itree); + + s1 = TAILQ_FIRST(&optd->spans); + while (s1) { + s2 = TAILQ_NEXT(s1, link); + span_destroy(s1); + s1 = s2; + } + + os1 = STAILQ_FIRST(&optd->offset_setters); + while (os1) { + os2 = STAILQ_NEXT(os1, link); + yasm_xfree(os1); + os1 = os2; + } +} + +static void +optimize_itree_add(IntervalTree *itree, yasm_span *span, yasm_span_term *term) +{ + long precbc_index, precbc2_index; + unsigned long low, high; + + /* Update term length */ + if (term->precbc) + precbc_index = term->precbc->bc_index; + else + precbc_index = span->bc->bc_index-1; + + if (term->precbc2) + precbc2_index = term->precbc2->bc_index; + else + precbc2_index = span->bc->bc_index-1; + + if (precbc_index < precbc2_index) { + low = precbc_index+1; + high = precbc2_index; + } else if (precbc_index > precbc2_index) { + low = precbc2_index+1; + high = precbc_index; + } else + return; /* difference is same bc - always 0! */ + + IT_insert(itree, (long)low, (long)high, term); +} + +static void +check_cycle(IntervalTreeNode *node, void *d) +{ + optimize_data *optd = d; + yasm_span_term *term = node->data; + yasm_span *depspan = term->span; + int i; + int depspan_bt_alloc; + + /* Only check for cycles in id=0 spans */ + if (depspan->id > 0) + return; + + /* Check for a circular reference by looking to see if this dependent + * span is in our backtrace. + */ + if (optd->span->backtrace) { + for (i=0; i<optd->span->backtrace_size; i++) { + if (optd->span->backtrace[i] == depspan) + yasm_error_set(YASM_ERROR_VALUE, + N_("circular reference detected")); + } + } + + /* Add our complete backtrace and ourselves to backtrace of dependent + * span. + */ + if (!depspan->backtrace) { + depspan->backtrace = yasm_xmalloc((optd->span->backtrace_size+1)* + sizeof(yasm_span *)); + if (optd->span->backtrace_size > 0) + memcpy(depspan->backtrace, optd->span->backtrace, + optd->span->backtrace_size*sizeof(yasm_span *)); + depspan->backtrace[optd->span->backtrace_size] = optd->span; + depspan->backtrace_size = optd->span->backtrace_size+1; + return; + } + + /* Add our complete backtrace, checking for duplicates */ + depspan_bt_alloc = depspan->backtrace_size; + for (i=0; i<optd->span->backtrace_size; i++) { + int present = 0; + int j; + for (j=0; j<depspan->backtrace_size; j++) { + if (optd->span->backtrace[i] == optd->span->backtrace[j]) { + present = 1; + break; + } + } + if (present) + continue; + /* Not already in array; add it. */ + if (depspan->backtrace_size >= depspan_bt_alloc) + { + depspan_bt_alloc *= 2; + depspan->backtrace = + yasm_xrealloc(depspan->backtrace, + depspan_bt_alloc*sizeof(yasm_span *)); + } + depspan->backtrace[depspan->backtrace_size] = optd->span->backtrace[i]; + depspan->backtrace_size++; + } + + /* Add ourselves. */ + if (depspan->backtrace_size >= depspan_bt_alloc) + { + depspan_bt_alloc++; + depspan->backtrace = + yasm_xrealloc(depspan->backtrace, + depspan_bt_alloc*sizeof(yasm_span *)); + } + depspan->backtrace[depspan->backtrace_size] = optd->span; + depspan->backtrace_size++; +} + +static void +optimize_term_expand(IntervalTreeNode *node, void *d) +{ + optimize_data *optd = d; + yasm_span_term *term = node->data; + yasm_span *span = term->span; + long len_diff = optd->len_diff; + long precbc_index, precbc2_index; + + /* Don't expand inactive spans */ + if (!span->active) + return; + + /* Update term length */ + if (term->precbc) + precbc_index = term->precbc->bc_index; + else + precbc_index = span->bc->bc_index-1; + + if (term->precbc2) + precbc2_index = term->precbc2->bc_index; + else + precbc2_index = span->bc->bc_index-1; + + if (precbc_index < precbc2_index) + term->new_val += len_diff; + else + term->new_val -= len_diff; + + /* If already on Q, don't re-add */ + if (span->active == 2) + return; + + /* Update term and check against thresholds */ + if (!recalc_normal_span(span)) + return; /* didn't exceed thresholds, we're done */ + + /* Exceeded thresholds, need to add to Q for expansion */ + if (span->id <= 0) + STAILQ_INSERT_TAIL(&optd->QA, span, linkq); + else + STAILQ_INSERT_TAIL(&optd->QB, span, linkq); + span->active = 2; /* Mark as being in Q */ +} + +void +yasm_object_optimize(yasm_object *object, yasm_errwarns *errwarns) +{ + yasm_section *sect; + unsigned long bc_index = 0; + int saw_error = 0; + optimize_data optd; + yasm_span *span, *span_temp; + yasm_offset_setter *os; + int retval; + unsigned int i; + + TAILQ_INIT(&optd.spans); + STAILQ_INIT(&optd.offset_setters); + optd.itree = IT_create(); + + /* Create an placeholder offset setter for spans to point to; this will + * get updated if/when we actually run into one. + */ + os = yasm_xmalloc(sizeof(yasm_offset_setter)); + os->bc = NULL; + os->cur_val = 0; + os->new_val = 0; + os->thres = 0; + STAILQ_INSERT_TAIL(&optd.offset_setters, os, link); + optd.os = os; + + /* Step 1a */ + STAILQ_FOREACH(sect, &object->sections, link) { + unsigned long offset = 0; + + yasm_bytecode *bc = STAILQ_FIRST(§->bcs); + + bc->bc_index = bc_index++; + + /* Skip our locally created empty bytecode first. */ + bc = STAILQ_NEXT(bc, link); + + /* Iterate through the remainder, if any. */ + while (bc) { + bc->bc_index = bc_index++; + bc->offset = offset; + + retval = yasm_bc_calc_len(bc, optimize_add_span, &optd); + yasm_errwarn_propagate(errwarns, bc->line); + if (retval) + saw_error = 1; + else { + if (bc->callback->special == YASM_BC_SPECIAL_OFFSET) { + /* Remember it as offset setter */ + os->bc = bc; + os->thres = yasm_bc_next_offset(bc); + + /* Create new placeholder */ + os = yasm_xmalloc(sizeof(yasm_offset_setter)); + os->bc = NULL; + os->cur_val = 0; + os->new_val = 0; + os->thres = 0; + STAILQ_INSERT_TAIL(&optd.offset_setters, os, link); + optd.os = os; + + if (bc->multiple) { + yasm_error_set(YASM_ERROR_VALUE, + N_("cannot combine multiples and setting assembly position")); + yasm_errwarn_propagate(errwarns, bc->line); + saw_error = 1; + } + } + + offset += bc->len*bc->mult_int; + } + + bc = STAILQ_NEXT(bc, link); + } + } + + if (saw_error) { + optimize_cleanup(&optd); + return; + } + + /* Step 1b */ + TAILQ_FOREACH_SAFE(span, &optd.spans, link, span_temp) { + span_create_terms(span); + if (yasm_error_occurred()) { + yasm_errwarn_propagate(errwarns, span->bc->line); + saw_error = 1; + } else if (recalc_normal_span(span)) { + retval = yasm_bc_expand(span->bc, span->id, span->cur_val, + span->new_val, &span->neg_thres, + &span->pos_thres); + yasm_errwarn_propagate(errwarns, span->bc->line); + if (retval < 0) + saw_error = 1; + else if (retval > 0) { + if (!span->active) { + yasm_error_set(YASM_ERROR_VALUE, + N_("secondary expansion of an external/complex value")); + yasm_errwarn_propagate(errwarns, span->bc->line); + saw_error = 1; + } + } else { + TAILQ_REMOVE(&optd.spans, span, link); + span_destroy(span); + continue; + } + } + span->cur_val = span->new_val; + } + + if (saw_error) { + optimize_cleanup(&optd); + return; + } + + /* Step 1c */ + if (update_all_bc_offsets(object, errwarns)) { + optimize_cleanup(&optd); + return; + } + + /* Step 1d */ + STAILQ_INIT(&optd.QB); + TAILQ_FOREACH(span, &optd.spans, link) { + yasm_intnum *intn; + + /* Update span terms based on new bc offsets */ + for (i=0; i<span->num_terms; i++) { + intn = yasm_calc_bc_dist(span->terms[i].precbc, + span->terms[i].precbc2); + if (!intn) + yasm_internal_error(N_("could not calculate bc distance")); + span->terms[i].cur_val = span->terms[i].new_val; + span->terms[i].new_val = yasm_intnum_get_int(intn); + yasm_intnum_destroy(intn); + } + if (span->rel_term) { + span->rel_term->cur_val = span->rel_term->new_val; + if (span->rel_term->precbc2) + span->rel_term->new_val = + yasm_bc_next_offset(span->rel_term->precbc2) - + span->bc->offset; + else + span->rel_term->new_val = span->bc->offset - + yasm_bc_next_offset(span->rel_term->precbc); + } + + if (recalc_normal_span(span)) { + /* Exceeded threshold, add span to QB */ + STAILQ_INSERT_TAIL(&optd.QB, span, linkq); + span->active = 2; + } + } + + /* Do we need step 2? If not, go ahead and exit. */ + if (STAILQ_EMPTY(&optd.QB)) { + optimize_cleanup(&optd); + return; + } + + /* Update offset-setters values */ + STAILQ_FOREACH(os, &optd.offset_setters, link) { + if (!os->bc) + continue; + os->thres = yasm_bc_next_offset(os->bc); + os->new_val = os->bc->offset; + os->cur_val = os->new_val; + } + + /* Build up interval tree */ + TAILQ_FOREACH(span, &optd.spans, link) { + for (i=0; i<span->num_terms; i++) + optimize_itree_add(optd.itree, span, &span->terms[i]); + if (span->rel_term) + optimize_itree_add(optd.itree, span, span->rel_term); + } + + /* Look for cycles in times expansion (span.id==0) */ + TAILQ_FOREACH(span, &optd.spans, link) { + if (span->id > 0) + continue; + optd.span = span; + IT_enumerate(optd.itree, (long)span->bc->bc_index, + (long)span->bc->bc_index, &optd, check_cycle); + if (yasm_error_occurred()) { + yasm_errwarn_propagate(errwarns, span->bc->line); + saw_error = 1; + } + } + + if (saw_error) { + optimize_cleanup(&optd); + return; + } + + /* Step 2 */ + STAILQ_INIT(&optd.QA); + while (!STAILQ_EMPTY(&optd.QA) || !(STAILQ_EMPTY(&optd.QB))) { + unsigned long orig_len; + long offset_diff; + + /* QA is for TIMES, update those first, then update non-TIMES. + * This is so that TIMES can absorb increases before we look at + * expanding non-TIMES BCs. + */ + if (!STAILQ_EMPTY(&optd.QA)) { + span = STAILQ_FIRST(&optd.QA); + STAILQ_REMOVE_HEAD(&optd.QA, linkq); + } else { + span = STAILQ_FIRST(&optd.QB); + STAILQ_REMOVE_HEAD(&optd.QB, linkq); + } + + if (!span->active) + continue; + span->active = 1; /* no longer in Q */ + + /* Make sure we ended up ultimately exceeding thresholds; due to + * offset BCs we may have been placed on Q and then reduced in size + * again. + */ + if (!recalc_normal_span(span)) + continue; + + orig_len = span->bc->len * span->bc->mult_int; + + retval = yasm_bc_expand(span->bc, span->id, span->cur_val, + span->new_val, &span->neg_thres, + &span->pos_thres); + yasm_errwarn_propagate(errwarns, span->bc->line); + + if (retval < 0) { + /* error */ + saw_error = 1; + continue; + } else if (retval > 0) { + /* another threshold, keep active */ + for (i=0; i<span->num_terms; i++) + span->terms[i].cur_val = span->terms[i].new_val; + if (span->rel_term) + span->rel_term->cur_val = span->rel_term->new_val; + span->cur_val = span->new_val; + } else + span->active = 0; /* we're done with this span */ + + optd.len_diff = span->bc->len * span->bc->mult_int - orig_len; + if (optd.len_diff == 0) + continue; /* didn't increase in size */ + + /* Iterate over all spans dependent across the bc just expanded */ + IT_enumerate(optd.itree, (long)span->bc->bc_index, + (long)span->bc->bc_index, &optd, optimize_term_expand); + + /* Iterate over offset-setters that follow the bc just expanded. + * Stop iteration if: + * - no more offset-setters in this section + * - offset-setter didn't move its following offset + */ + os = span->os; + offset_diff = optd.len_diff; + while (os->bc && os->bc->section == span->bc->section + && offset_diff != 0) { + unsigned long old_next_offset = os->cur_val + os->bc->len; + long neg_thres_temp; + + if (offset_diff < 0 && (unsigned long)(-offset_diff) > os->new_val) + yasm_internal_error(N_("org/align went to negative offset")); + os->new_val += offset_diff; + + orig_len = os->bc->len; + retval = yasm_bc_expand(os->bc, 1, (long)os->cur_val, + (long)os->new_val, &neg_thres_temp, + (long *)&os->thres); + yasm_errwarn_propagate(errwarns, os->bc->line); + + offset_diff = os->new_val + os->bc->len - old_next_offset; + optd.len_diff = os->bc->len - orig_len; + if (optd.len_diff != 0) + IT_enumerate(optd.itree, (long)os->bc->bc_index, + (long)os->bc->bc_index, &optd, optimize_term_expand); + + os->cur_val = os->new_val; + os = STAILQ_NEXT(os, link); + } + } + + if (saw_error) { + optimize_cleanup(&optd); + return; + } + + /* Step 3 */ + update_all_bc_offsets(object, errwarns); + optimize_cleanup(&optd); +} diff --git a/contrib/tools/yasm/libyasm/section.h b/contrib/tools/yasm/libyasm/section.h index 521031f3a5..dd88117348 100644 --- a/contrib/tools/yasm/libyasm/section.h +++ b/contrib/tools/yasm/libyasm/section.h @@ -1,384 +1,384 @@ -/** - * \file libyasm/section.h - * \brief YASM section interface. - * - * \license - * Copyright (C) 2001-2007 Peter Johnson - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * \endlicense - */ -#ifndef YASM_SECTION_H -#define YASM_SECTION_H - -#ifndef YASM_LIB_DECL -#define YASM_LIB_DECL -#endif - -/** Basic YASM relocation. Object formats will need to extend this - * structure with additional fields for relocation type, etc. - */ -typedef struct yasm_reloc yasm_reloc; - -struct yasm_reloc { - /*@reldef@*/ STAILQ_ENTRY(yasm_reloc) link; /**< Link to next reloc */ - yasm_intnum *addr; /**< Offset (address) within section */ - /*@dependent@*/ yasm_symrec *sym; /**< Relocated symbol */ -}; - -/** An object. This is the internal representation of an object file. */ -struct yasm_object { - /*@owned@*/ char *src_filename; /**< Source filename */ +/** + * \file libyasm/section.h + * \brief YASM section interface. + * + * \license + * Copyright (C) 2001-2007 Peter Johnson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * \endlicense + */ +#ifndef YASM_SECTION_H +#define YASM_SECTION_H + +#ifndef YASM_LIB_DECL +#define YASM_LIB_DECL +#endif + +/** Basic YASM relocation. Object formats will need to extend this + * structure with additional fields for relocation type, etc. + */ +typedef struct yasm_reloc yasm_reloc; + +struct yasm_reloc { + /*@reldef@*/ STAILQ_ENTRY(yasm_reloc) link; /**< Link to next reloc */ + yasm_intnum *addr; /**< Offset (address) within section */ + /*@dependent@*/ yasm_symrec *sym; /**< Relocated symbol */ +}; + +/** An object. This is the internal representation of an object file. */ +struct yasm_object { + /*@owned@*/ char *src_filename; /**< Source filename */ /*@owned@*/ char *deb_filename; /**< Debug filename */ - /*@owned@*/ char *obj_filename; /**< Object filename */ - - /*@owned@*/ yasm_symtab *symtab; /**< Symbol table */ - /*@owned@*/ yasm_arch *arch; /**< Target architecture */ - /*@owned@*/ yasm_objfmt *objfmt; /**< Object format */ - /*@owned@*/ yasm_dbgfmt *dbgfmt; /**< Debug format */ - - /** Currently active section. Used by some directives. NULL if no - * section active. - */ - /*@dependent@*/ /*@null@*/ yasm_section *cur_section; - - /** Linked list of sections. */ - /*@reldef@*/ STAILQ_HEAD(yasm_sectionhead, yasm_section) sections; - - /** Directives, organized as two level HAMT; first level is parser, - * second level is directive name. - */ - /*@owned@*/ struct HAMT *directives; - - /** Prefix prepended to externally-visible symbols (empty string if none) */ - /*@owned@*/ char *global_prefix; - - /** Suffix appended to externally-visible symbols (empty string if none) */ - /*@owned@*/ char *global_suffix; -}; - -/** Create a new object. A default section is created as the first section. - * An empty symbol table (yasm_symtab) and line mapping (yasm_linemap) are - * automatically created. - * \param src_filename source filename (e.g. "file.asm") - * \param obj_filename object filename (e.g. "file.o") - * \param arch architecture - * \param objfmt_module object format module - * \param dbgfmt_module debug format module - * \return Newly allocated object, or NULL on error. - */ -YASM_LIB_DECL -/*@null@*/ /*@only@*/ yasm_object *yasm_object_create - (const char *src_filename, const char *obj_filename, - /*@kept@*/ yasm_arch *arch, - const yasm_objfmt_module *objfmt_module, - const yasm_dbgfmt_module *dbgfmt_module); - -/** Create a new, or continue an existing, general section. The section is - * added to the object if there's not already a section by that name. - * \param object object - * \param name section name - * \param align alignment in bytes (0 if none) - * \param code if nonzero, section is intended to contain code - * (e.g. alignment should be made with NOP instructions, not 0) - * \param res_only if nonzero, only space-reserving bytecodes are allowed in - * the section (ignored if section already exists) - * \param isnew output; set to nonzero if section did not already exist - * \param line virtual line of section declaration (ignored if section - * already exists) - * \return New section. - */ -YASM_LIB_DECL -/*@dependent@*/ yasm_section *yasm_object_get_general - (yasm_object *object, const char *name, unsigned long align, int code, - int res_only, /*@out@*/ int *isnew, unsigned long line); - -/** Handle a directive. Passed down to object format, debug format, or - * architecture as appropriate. - * \param object object - * \param name directive name - * \param parser parser keyword - * \param valparams value/parameters - * \param objext_valparams "object format-specific" value/parameters - * \param line virtual line (from yasm_linemap) - * \return 0 if directive recognized, nonzero if unrecognized. - */ -YASM_LIB_DECL -int yasm_object_directive(yasm_object *object, const char *name, - const char *parser, yasm_valparamhead *valparams, - yasm_valparamhead *objext_valparams, - unsigned long line); - -/** Delete (free allocated memory for) an object. All sections in the - * object and all bytecodes within those sections are also deleted. - * \param object object - */ -YASM_LIB_DECL -void yasm_object_destroy(/*@only@*/ yasm_object *object); - -/** Print an object. For debugging purposes. - * \param object object - * \param f file - * \param indent_level indentation level - */ -YASM_LIB_DECL -void yasm_object_print(const yasm_object *object, FILE *f, int indent_level); - -/** Finalize an object after parsing. - * \param object object - * \param errwarns error/warning set - * \note Errors/warnings are stored into errwarns. - */ -YASM_LIB_DECL -void yasm_object_finalize(yasm_object *object, yasm_errwarns *errwarns); - -/** Traverses all sections in an object, calling a function on each section. - * \param object object - * \param d data pointer passed to func on each call - * \param func function - * \return Stops early (and returns func's return value) if func returns a - * nonzero value; otherwise 0. - */ -YASM_LIB_DECL -int yasm_object_sections_traverse - (yasm_object *object, /*@null@*/ void *d, - int (*func) (yasm_section *sect, /*@null@*/ void *d)); - -/** Find a general section in an object, based on its name. - * \param object object - * \param name section name - * \return Section matching name, or NULL if no match found. - */ -YASM_LIB_DECL -/*@dependent@*/ /*@null@*/ yasm_section *yasm_object_find_general - (yasm_object *object, const char *name); - -/** Change the source filename for an object. - * \param object object - * \param src_filename new source filename (e.g. "file.asm") - */ -YASM_LIB_DECL -void yasm_object_set_source_fn(yasm_object *object, const char *src_filename); - -/** Change the prefix used for externally-visible symbols. - * \param object object - * \param prefix new prefix - */ -YASM_LIB_DECL -void yasm_object_set_global_prefix(yasm_object *object, const char *prefix); - -/** Change the suffix used for externally-visible symbols. - * \param object object - * \param suffix new suffix - */ -YASM_LIB_DECL -void yasm_object_set_global_suffix(yasm_object *object, const char *suffix); - -/** Optimize an object. Takes the unoptimized object and optimizes it. - * If successful, the object is ready for output to an object file. - * \param object object - * \param errwarns error/warning set - * \note Optimization failures are stored into errwarns. - */ -YASM_LIB_DECL -void yasm_object_optimize(yasm_object *object, yasm_errwarns *errwarns); - -/** Determine if a section is flagged to contain code. - * \param sect section - * \return Nonzero if section is flagged to contain code. - */ -YASM_LIB_DECL -int yasm_section_is_code(yasm_section *sect); - -/** Get yasm_optimizer-specific flags. For yasm_optimizer use only. - * \param sect section - * \return Optimizer-specific flags. - */ -YASM_LIB_DECL -unsigned long yasm_section_get_opt_flags(const yasm_section *sect); - -/** Set yasm_optimizer-specific flags. For yasm_optimizer use only. - * \param sect section - * \param opt_flags optimizer-specific flags. - */ -YASM_LIB_DECL -void yasm_section_set_opt_flags(yasm_section *sect, unsigned long opt_flags); - -/** Determine if a section was declared as the "default" section (e.g. not - * created through a section directive). - * \param sect section - * \return Nonzero if section was declared as default. - */ -YASM_LIB_DECL -int yasm_section_is_default(const yasm_section *sect); - -/** Set section "default" flag to a new value. - * \param sect section - * \param def new value of default flag - */ -YASM_LIB_DECL -void yasm_section_set_default(yasm_section *sect, int def); - -/** Get object owner of a section. - * \param sect section - * \return Object this section is a part of. - */ -YASM_LIB_DECL -yasm_object *yasm_section_get_object(const yasm_section *sect); - -/** Get assocated data for a section and data callback. - * \param sect section - * \param callback callback used when adding data - * \return Associated data (NULL if none). - */ -YASM_LIB_DECL -/*@dependent@*/ /*@null@*/ void *yasm_section_get_data - (yasm_section *sect, const yasm_assoc_data_callback *callback); - -/** Add associated data to a section. - * \attention Deletes any existing associated data for that data callback. - * \param sect section - * \param callback callback - * \param data data to associate - */ -YASM_LIB_DECL -void yasm_section_add_data(yasm_section *sect, - const yasm_assoc_data_callback *callback, - /*@null@*/ /*@only@*/ void *data); - -/** Add a relocation to a section. - * \param sect section - * \param reloc relocation - * \param destroy_func function that can destroy the relocation - * \note Does not make a copy of reloc. The same destroy_func must be - * used for all relocations in a section or an internal error will occur. - * The section will destroy the relocation address; it is the caller's - * responsibility to destroy any other allocated data. - */ -YASM_LIB_DECL -void yasm_section_add_reloc(yasm_section *sect, yasm_reloc *reloc, - void (*destroy_func) (/*@only@*/ void *reloc)); - -/** Get the first relocation for a section. - * \param sect section - * \return First relocation for section. NULL if no relocations. - */ -YASM_LIB_DECL -/*@null@*/ yasm_reloc *yasm_section_relocs_first(yasm_section *sect); - -/** Get the next relocation for a section. - * \param reloc previous relocation - * \return Next relocation for section. NULL if no more relocations. - */ -/*@null@*/ yasm_reloc *yasm_section_reloc_next(yasm_reloc *reloc); -#ifndef YASM_DOXYGEN -#define yasm_section_reloc_next(x) STAILQ_NEXT((x), link) -#endif - -/** Get the basic relocation information for a relocation. - * \param reloc relocation - * \param addrp address of relocation within section (returned) - * \param symp relocated symbol (returned) - */ -YASM_LIB_DECL -void yasm_reloc_get(yasm_reloc *reloc, yasm_intnum **addrp, - /*@dependent@*/ yasm_symrec **symp); - -/** Get the first bytecode in a section. - * \param sect section - * \return First bytecode in section (at least one empty bytecode is always - * present). - */ -YASM_LIB_DECL -yasm_bytecode *yasm_section_bcs_first(yasm_section *sect); - -/** Get the last bytecode in a section. - * \param sect section - * \return Last bytecode in section (at least one empty bytecode is always - * present). - */ -YASM_LIB_DECL -yasm_bytecode *yasm_section_bcs_last(yasm_section *sect); - -/** Add bytecode to the end of a section. - * \note Does not make a copy of bc; so don't pass this function static or - * local variables, and discard the bc pointer after calling this - * function. - * \param sect section - * \param bc bytecode (may be NULL) - * \return If bytecode was actually appended (it wasn't NULL or empty), the - * bytecode; otherwise NULL. - */ -YASM_LIB_DECL -/*@only@*/ /*@null@*/ yasm_bytecode *yasm_section_bcs_append - (yasm_section *sect, - /*@returned@*/ /*@only@*/ /*@null@*/ yasm_bytecode *bc); - -/** Traverses all bytecodes in a section, calling a function on each bytecode. - * \param sect section - * \param errwarns error/warning set (may be NULL) - * \param d data pointer passed to func on each call (may be NULL) - * \param func function - * \return Stops early (and returns func's return value) if func returns a - * nonzero value; otherwise 0. - * \note If errwarns is non-NULL, yasm_errwarn_propagate() is called after - * each call to func (with the bytecode's line number). - */ -YASM_LIB_DECL -int yasm_section_bcs_traverse - (yasm_section *sect, /*@null@*/ yasm_errwarns *errwarns, - /*@null@*/ void *d, int (*func) (yasm_bytecode *bc, /*@null@*/ void *d)); - -/** Get name of a section. - * \param sect section - * \return Section name. - */ -YASM_LIB_DECL -/*@observer@*/ const char *yasm_section_get_name(const yasm_section *sect); - -/** Change alignment of a section. - * \param sect section - * \param align alignment in bytes - * \param line virtual line - */ -YASM_LIB_DECL -void yasm_section_set_align(yasm_section *sect, unsigned long align, - unsigned long line); - -/** Get alignment of a section. - * \param sect section - * \return Alignment in bytes (0 if none). - */ -YASM_LIB_DECL -unsigned long yasm_section_get_align(const yasm_section *sect); - -/** Print a section. For debugging purposes. - * \param f file - * \param indent_level indentation level - * \param sect section - * \param print_bcs if nonzero, print bytecodes within section - */ -YASM_LIB_DECL -void yasm_section_print(/*@null@*/ const yasm_section *sect, FILE *f, - int indent_level, int print_bcs); - -#endif + /*@owned@*/ char *obj_filename; /**< Object filename */ + + /*@owned@*/ yasm_symtab *symtab; /**< Symbol table */ + /*@owned@*/ yasm_arch *arch; /**< Target architecture */ + /*@owned@*/ yasm_objfmt *objfmt; /**< Object format */ + /*@owned@*/ yasm_dbgfmt *dbgfmt; /**< Debug format */ + + /** Currently active section. Used by some directives. NULL if no + * section active. + */ + /*@dependent@*/ /*@null@*/ yasm_section *cur_section; + + /** Linked list of sections. */ + /*@reldef@*/ STAILQ_HEAD(yasm_sectionhead, yasm_section) sections; + + /** Directives, organized as two level HAMT; first level is parser, + * second level is directive name. + */ + /*@owned@*/ struct HAMT *directives; + + /** Prefix prepended to externally-visible symbols (empty string if none) */ + /*@owned@*/ char *global_prefix; + + /** Suffix appended to externally-visible symbols (empty string if none) */ + /*@owned@*/ char *global_suffix; +}; + +/** Create a new object. A default section is created as the first section. + * An empty symbol table (yasm_symtab) and line mapping (yasm_linemap) are + * automatically created. + * \param src_filename source filename (e.g. "file.asm") + * \param obj_filename object filename (e.g. "file.o") + * \param arch architecture + * \param objfmt_module object format module + * \param dbgfmt_module debug format module + * \return Newly allocated object, or NULL on error. + */ +YASM_LIB_DECL +/*@null@*/ /*@only@*/ yasm_object *yasm_object_create + (const char *src_filename, const char *obj_filename, + /*@kept@*/ yasm_arch *arch, + const yasm_objfmt_module *objfmt_module, + const yasm_dbgfmt_module *dbgfmt_module); + +/** Create a new, or continue an existing, general section. The section is + * added to the object if there's not already a section by that name. + * \param object object + * \param name section name + * \param align alignment in bytes (0 if none) + * \param code if nonzero, section is intended to contain code + * (e.g. alignment should be made with NOP instructions, not 0) + * \param res_only if nonzero, only space-reserving bytecodes are allowed in + * the section (ignored if section already exists) + * \param isnew output; set to nonzero if section did not already exist + * \param line virtual line of section declaration (ignored if section + * already exists) + * \return New section. + */ +YASM_LIB_DECL +/*@dependent@*/ yasm_section *yasm_object_get_general + (yasm_object *object, const char *name, unsigned long align, int code, + int res_only, /*@out@*/ int *isnew, unsigned long line); + +/** Handle a directive. Passed down to object format, debug format, or + * architecture as appropriate. + * \param object object + * \param name directive name + * \param parser parser keyword + * \param valparams value/parameters + * \param objext_valparams "object format-specific" value/parameters + * \param line virtual line (from yasm_linemap) + * \return 0 if directive recognized, nonzero if unrecognized. + */ +YASM_LIB_DECL +int yasm_object_directive(yasm_object *object, const char *name, + const char *parser, yasm_valparamhead *valparams, + yasm_valparamhead *objext_valparams, + unsigned long line); + +/** Delete (free allocated memory for) an object. All sections in the + * object and all bytecodes within those sections are also deleted. + * \param object object + */ +YASM_LIB_DECL +void yasm_object_destroy(/*@only@*/ yasm_object *object); + +/** Print an object. For debugging purposes. + * \param object object + * \param f file + * \param indent_level indentation level + */ +YASM_LIB_DECL +void yasm_object_print(const yasm_object *object, FILE *f, int indent_level); + +/** Finalize an object after parsing. + * \param object object + * \param errwarns error/warning set + * \note Errors/warnings are stored into errwarns. + */ +YASM_LIB_DECL +void yasm_object_finalize(yasm_object *object, yasm_errwarns *errwarns); + +/** Traverses all sections in an object, calling a function on each section. + * \param object object + * \param d data pointer passed to func on each call + * \param func function + * \return Stops early (and returns func's return value) if func returns a + * nonzero value; otherwise 0. + */ +YASM_LIB_DECL +int yasm_object_sections_traverse + (yasm_object *object, /*@null@*/ void *d, + int (*func) (yasm_section *sect, /*@null@*/ void *d)); + +/** Find a general section in an object, based on its name. + * \param object object + * \param name section name + * \return Section matching name, or NULL if no match found. + */ +YASM_LIB_DECL +/*@dependent@*/ /*@null@*/ yasm_section *yasm_object_find_general + (yasm_object *object, const char *name); + +/** Change the source filename for an object. + * \param object object + * \param src_filename new source filename (e.g. "file.asm") + */ +YASM_LIB_DECL +void yasm_object_set_source_fn(yasm_object *object, const char *src_filename); + +/** Change the prefix used for externally-visible symbols. + * \param object object + * \param prefix new prefix + */ +YASM_LIB_DECL +void yasm_object_set_global_prefix(yasm_object *object, const char *prefix); + +/** Change the suffix used for externally-visible symbols. + * \param object object + * \param suffix new suffix + */ +YASM_LIB_DECL +void yasm_object_set_global_suffix(yasm_object *object, const char *suffix); + +/** Optimize an object. Takes the unoptimized object and optimizes it. + * If successful, the object is ready for output to an object file. + * \param object object + * \param errwarns error/warning set + * \note Optimization failures are stored into errwarns. + */ +YASM_LIB_DECL +void yasm_object_optimize(yasm_object *object, yasm_errwarns *errwarns); + +/** Determine if a section is flagged to contain code. + * \param sect section + * \return Nonzero if section is flagged to contain code. + */ +YASM_LIB_DECL +int yasm_section_is_code(yasm_section *sect); + +/** Get yasm_optimizer-specific flags. For yasm_optimizer use only. + * \param sect section + * \return Optimizer-specific flags. + */ +YASM_LIB_DECL +unsigned long yasm_section_get_opt_flags(const yasm_section *sect); + +/** Set yasm_optimizer-specific flags. For yasm_optimizer use only. + * \param sect section + * \param opt_flags optimizer-specific flags. + */ +YASM_LIB_DECL +void yasm_section_set_opt_flags(yasm_section *sect, unsigned long opt_flags); + +/** Determine if a section was declared as the "default" section (e.g. not + * created through a section directive). + * \param sect section + * \return Nonzero if section was declared as default. + */ +YASM_LIB_DECL +int yasm_section_is_default(const yasm_section *sect); + +/** Set section "default" flag to a new value. + * \param sect section + * \param def new value of default flag + */ +YASM_LIB_DECL +void yasm_section_set_default(yasm_section *sect, int def); + +/** Get object owner of a section. + * \param sect section + * \return Object this section is a part of. + */ +YASM_LIB_DECL +yasm_object *yasm_section_get_object(const yasm_section *sect); + +/** Get assocated data for a section and data callback. + * \param sect section + * \param callback callback used when adding data + * \return Associated data (NULL if none). + */ +YASM_LIB_DECL +/*@dependent@*/ /*@null@*/ void *yasm_section_get_data + (yasm_section *sect, const yasm_assoc_data_callback *callback); + +/** Add associated data to a section. + * \attention Deletes any existing associated data for that data callback. + * \param sect section + * \param callback callback + * \param data data to associate + */ +YASM_LIB_DECL +void yasm_section_add_data(yasm_section *sect, + const yasm_assoc_data_callback *callback, + /*@null@*/ /*@only@*/ void *data); + +/** Add a relocation to a section. + * \param sect section + * \param reloc relocation + * \param destroy_func function that can destroy the relocation + * \note Does not make a copy of reloc. The same destroy_func must be + * used for all relocations in a section or an internal error will occur. + * The section will destroy the relocation address; it is the caller's + * responsibility to destroy any other allocated data. + */ +YASM_LIB_DECL +void yasm_section_add_reloc(yasm_section *sect, yasm_reloc *reloc, + void (*destroy_func) (/*@only@*/ void *reloc)); + +/** Get the first relocation for a section. + * \param sect section + * \return First relocation for section. NULL if no relocations. + */ +YASM_LIB_DECL +/*@null@*/ yasm_reloc *yasm_section_relocs_first(yasm_section *sect); + +/** Get the next relocation for a section. + * \param reloc previous relocation + * \return Next relocation for section. NULL if no more relocations. + */ +/*@null@*/ yasm_reloc *yasm_section_reloc_next(yasm_reloc *reloc); +#ifndef YASM_DOXYGEN +#define yasm_section_reloc_next(x) STAILQ_NEXT((x), link) +#endif + +/** Get the basic relocation information for a relocation. + * \param reloc relocation + * \param addrp address of relocation within section (returned) + * \param symp relocated symbol (returned) + */ +YASM_LIB_DECL +void yasm_reloc_get(yasm_reloc *reloc, yasm_intnum **addrp, + /*@dependent@*/ yasm_symrec **symp); + +/** Get the first bytecode in a section. + * \param sect section + * \return First bytecode in section (at least one empty bytecode is always + * present). + */ +YASM_LIB_DECL +yasm_bytecode *yasm_section_bcs_first(yasm_section *sect); + +/** Get the last bytecode in a section. + * \param sect section + * \return Last bytecode in section (at least one empty bytecode is always + * present). + */ +YASM_LIB_DECL +yasm_bytecode *yasm_section_bcs_last(yasm_section *sect); + +/** Add bytecode to the end of a section. + * \note Does not make a copy of bc; so don't pass this function static or + * local variables, and discard the bc pointer after calling this + * function. + * \param sect section + * \param bc bytecode (may be NULL) + * \return If bytecode was actually appended (it wasn't NULL or empty), the + * bytecode; otherwise NULL. + */ +YASM_LIB_DECL +/*@only@*/ /*@null@*/ yasm_bytecode *yasm_section_bcs_append + (yasm_section *sect, + /*@returned@*/ /*@only@*/ /*@null@*/ yasm_bytecode *bc); + +/** Traverses all bytecodes in a section, calling a function on each bytecode. + * \param sect section + * \param errwarns error/warning set (may be NULL) + * \param d data pointer passed to func on each call (may be NULL) + * \param func function + * \return Stops early (and returns func's return value) if func returns a + * nonzero value; otherwise 0. + * \note If errwarns is non-NULL, yasm_errwarn_propagate() is called after + * each call to func (with the bytecode's line number). + */ +YASM_LIB_DECL +int yasm_section_bcs_traverse + (yasm_section *sect, /*@null@*/ yasm_errwarns *errwarns, + /*@null@*/ void *d, int (*func) (yasm_bytecode *bc, /*@null@*/ void *d)); + +/** Get name of a section. + * \param sect section + * \return Section name. + */ +YASM_LIB_DECL +/*@observer@*/ const char *yasm_section_get_name(const yasm_section *sect); + +/** Change alignment of a section. + * \param sect section + * \param align alignment in bytes + * \param line virtual line + */ +YASM_LIB_DECL +void yasm_section_set_align(yasm_section *sect, unsigned long align, + unsigned long line); + +/** Get alignment of a section. + * \param sect section + * \return Alignment in bytes (0 if none). + */ +YASM_LIB_DECL +unsigned long yasm_section_get_align(const yasm_section *sect); + +/** Print a section. For debugging purposes. + * \param f file + * \param indent_level indentation level + * \param sect section + * \param print_bcs if nonzero, print bytecodes within section + */ +YASM_LIB_DECL +void yasm_section_print(/*@null@*/ const yasm_section *sect, FILE *f, + int indent_level, int print_bcs); + +#endif diff --git a/contrib/tools/yasm/libyasm/strcasecmp.c b/contrib/tools/yasm/libyasm/strcasecmp.c index a87bd88bc9..a905ec7724 100644 --- a/contrib/tools/yasm/libyasm/strcasecmp.c +++ b/contrib/tools/yasm/libyasm/strcasecmp.c @@ -1,94 +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 -} +/* + * strcasecmp() implementation for systems that don't have it or stricmp() + * or strcmpi(). + * + * Copyright (c) 1987, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include "util.h" + +#ifndef USE_OUR_OWN_STRCASECMP +#undef yasm__strcasecmp +#undef yasm__strncasecmp +#endif + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)strcasecmp.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ + +#include <ctype.h> + +int +yasm__strcasecmp(const char *s1, const char *s2) +{ +#ifdef HAVE_STRCASECMP + return strcasecmp(s1, s2); +#elif HAVE_STRICMP + return stricmp(s1, s2); +#elif HAVE__STRICMP + return _stricmp(s1, s2); +#elif HAVE_STRCMPI + return strcmpi(s1, s2); +#else + const unsigned char + *us1 = (const unsigned char *)s1, + *us2 = (const unsigned char *)s2; + + while (tolower(*us1) == tolower(*us2++)) + if (*us1++ == '\0') + return (0); + return (tolower(*us1) - tolower(*--us2)); +#endif +} + +int +yasm__strncasecmp(const char *s1, const char *s2, size_t n) +{ +#ifdef HAVE_STRCASECMP + return strncasecmp(s1, s2, n); +#elif HAVE_STRICMP + return strnicmp(s1, s2, n); +#elif HAVE__STRNICMP + return _strnicmp(s1, s2, n); +#elif HAVE_STRCMPI + return strncmpi(s1, s2, n); +#else + const unsigned char + *us1 = (const unsigned char *)s1, + *us2 = (const unsigned char *)s2; + + if (n != 0) { + do { + if (tolower(*us1) != tolower(*us2++)) + return (tolower(*us1) - tolower(*--us2)); + if (*us1++ == '\0') + break; + } while (--n != 0); + } + return (0); +#endif +} diff --git a/contrib/tools/yasm/libyasm/strsep.c b/contrib/tools/yasm/libyasm/strsep.c index 5688a60879..8320acf056 100644 --- a/contrib/tools/yasm/libyasm/strsep.c +++ b/contrib/tools/yasm/libyasm/strsep.c @@ -1,85 +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 +/* + * strsep() implementation for systems that don't have it. + * + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#define NO_STRING_INLINES +#include "util.h" + + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)strsep.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ + +#ifdef HAVE_STRSEP +#undef yasm__strsep +#endif + +/* + * Get next token from string *stringp, where tokens are possibly-empty + * strings separated by characters from delim. + * + * Writes NULs into the string at *stringp to end tokens. + * delim need not remain constant from call to call. + * On return, *stringp points past the last NUL written (if there might + * be further tokens), or is NULL (if there are definitely no more tokens). + * + * If *stringp is NULL, strsep returns NULL. + */ +/*@-nullstate@*/ +char * +yasm__strsep(char **stringp, const char *delim) +{ +#ifdef HAVE_STRSEP + return strsep(stringp, delim); +#else char *s; const char *spanp; int c, sc; - char *tok; - - if ((s = *stringp) == NULL) - return (NULL); - for (tok = s;;) { - c = *s++; - spanp = delim; - do { - if ((sc = *spanp++) == c) { - if (c == 0) - s = NULL; - else - s[-1] = 0; - *stringp = s; - return (tok); - } - } while (sc != 0); - } - /* NOTREACHED */ -#endif -} -/*@=nullstate@*/ + char *tok; + + if ((s = *stringp) == NULL) + return (NULL); + for (tok = s;;) { + c = *s++; + spanp = delim; + do { + if ((sc = *spanp++) == c) { + if (c == 0) + s = NULL; + else + s[-1] = 0; + *stringp = s; + return (tok); + } + } while (sc != 0); + } + /* NOTREACHED */ +#endif +} +/*@=nullstate@*/ diff --git a/contrib/tools/yasm/libyasm/symrec.c b/contrib/tools/yasm/libyasm/symrec.c index 694f0c6768..1c188c99d8 100644 --- a/contrib/tools/yasm/libyasm/symrec.c +++ b/contrib/tools/yasm/libyasm/symrec.c @@ -1,714 +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); -} +/* + * Symbol table handling + * + * Copyright (C) 2001-2007 Michael Urman, Peter Johnson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include "util.h" + +#include <limits.h> +#include <ctype.h> + +#include "libyasm-stdint.h" +#include "coretype.h" +#include "valparam.h" +#include "hamt.h" +#include "assocdat.h" + +#include "errwarn.h" +#include "intnum.h" +#include "floatnum.h" +#include "expr.h" +#include "symrec.h" + +#include "bytecode.h" +#include "section.h" +#include "objfmt.h" + + +typedef enum { + SYM_UNKNOWN, /* for unknown type (COMMON/EXTERN) */ + SYM_EQU, /* for EQU defined symbols (expressions) */ + SYM_LABEL, /* for labels */ + SYM_CURPOS, /* for labels representing the current + assembly position */ + SYM_SPECIAL /* for special symbols that need to be in + the symbol table but otherwise have no + purpose */ +} sym_type; + +struct yasm_symrec { + char *name; + sym_type type; + yasm_sym_status status; + yasm_sym_vis visibility; + unsigned long def_line; /* line where symbol was first defined */ + unsigned long decl_line; /* line where symbol was first declared */ + unsigned long use_line; /* line where symbol was first used */ + union { + yasm_expr *expn; /* equ value */ + + /* bytecode immediately preceding a label */ + /*@dependent@*/ yasm_bytecode *precbc; + } value; + unsigned int size; /* 0 if not user-defined */ + const char *segment; /* for segmented systems like DOS */ + + /* associated data; NULL if none */ + /*@null@*/ /*@only@*/ yasm__assoc_data *assoc_data; +}; + +/* Linked list of symbols not in the symbol table. */ +typedef struct non_table_symrec_s { + /*@reldef@*/ SLIST_ENTRY(non_table_symrec_s) link; + /*@owned@*/ yasm_symrec *rec; +} non_table_symrec; + +struct yasm_symtab { + /* The symbol table: a hash array mapped trie (HAMT). */ + /*@only@*/ HAMT *sym_table; + /* Symbols not in the table */ + SLIST_HEAD(nontablesymhead_s, non_table_symrec_s) non_table_syms; + + int case_sensitive; +}; + +static void +objext_valparams_destroy(void *data) +{ + yasm_vps_destroy((yasm_valparamhead *)data); +} + +static void +objext_valparams_print(void *data, FILE *f, int indent_level) +{ + yasm_vps_print((yasm_valparamhead *)data, f); +} + +static yasm_assoc_data_callback objext_valparams_cb = { + objext_valparams_destroy, + objext_valparams_print +}; + +static void +common_size_destroy(void *data) +{ + yasm_expr **e = (yasm_expr **)data; + yasm_expr_destroy(*e); + yasm_xfree(data); +} + +static void +common_size_print(void *data, FILE *f, int indent_level) +{ + yasm_expr **e = (yasm_expr **)data; + yasm_expr_print(*e, f); +} + +static yasm_assoc_data_callback common_size_cb = { + common_size_destroy, + common_size_print +}; + +yasm_symtab * +yasm_symtab_create(void) +{ + yasm_symtab *symtab = yasm_xmalloc(sizeof(yasm_symtab)); + symtab->sym_table = HAMT_create(0, yasm_internal_error_); + SLIST_INIT(&symtab->non_table_syms); + symtab->case_sensitive = 1; + return symtab; +} + +void +yasm_symtab_set_case_sensitive(yasm_symtab *symtab, int sensitive) +{ + symtab->case_sensitive = sensitive; +} + +static void +symrec_destroy_one(/*@only@*/ void *d) +{ + yasm_symrec *sym = d; + yasm_xfree(sym->name); + if (sym->type == SYM_EQU && (sym->status & YASM_SYM_VALUED)) + yasm_expr_destroy(sym->value.expn); + yasm__assoc_data_destroy(sym->assoc_data); + yasm_xfree(sym); +} + +static /*@partial@*/ yasm_symrec * +symrec_new_common(/*@keep@*/ char *name, int case_sensitive) +{ + yasm_symrec *rec = yasm_xmalloc(sizeof(yasm_symrec)); + + if (!case_sensitive) { + char *c; + for (c=name; *c; c++) + *c = tolower(*c); + } + + rec->name = name; + rec->type = SYM_UNKNOWN; + rec->def_line = 0; + rec->decl_line = 0; + rec->use_line = 0; + rec->visibility = YASM_SYM_LOCAL; + rec->size = 0; + rec->segment = NULL; + rec->assoc_data = NULL; + return rec; +} + +static /*@partial@*/ /*@dependent@*/ yasm_symrec * +symtab_get_or_new_in_table(yasm_symtab *symtab, /*@only@*/ char *name) +{ + yasm_symrec *rec = symrec_new_common(name, symtab->case_sensitive); + int replace = 0; + + rec->status = YASM_SYM_NOSTATUS; + + if (!symtab->case_sensitive) { + char *c; + for (c=name; *c; c++) + *c = tolower(*c); + } + + return HAMT_insert(symtab->sym_table, name, rec, &replace, + symrec_destroy_one); +} + +static /*@partial@*/ /*@dependent@*/ yasm_symrec * +symtab_get_or_new_not_in_table(yasm_symtab *symtab, /*@only@*/ char *name) +{ + non_table_symrec *sym = yasm_xmalloc(sizeof(non_table_symrec)); + sym->rec = symrec_new_common(name, symtab->case_sensitive); + + sym->rec->status = YASM_SYM_NOTINTABLE; + + SLIST_INSERT_HEAD(&symtab->non_table_syms, sym, link); + + return sym->rec; +} + +/* create a new symrec */ +/*@-freshtrans -mustfree@*/ +static /*@partial@*/ /*@dependent@*/ yasm_symrec * +symtab_get_or_new(yasm_symtab *symtab, const char *name, int in_table) +{ + char *symname = yasm__xstrdup(name); + + if (in_table) + return symtab_get_or_new_in_table(symtab, symname); + else + return symtab_get_or_new_not_in_table(symtab, symname); +} +/*@=freshtrans =mustfree@*/ + +int +yasm_symtab_traverse(yasm_symtab *symtab, void *d, + int (*func) (yasm_symrec *sym, void *d)) +{ + return HAMT_traverse(symtab->sym_table, d, (int (*) (void *, void *))func); +} + +const yasm_symtab_iter * +yasm_symtab_first(const yasm_symtab *symtab) +{ + return (const yasm_symtab_iter *)HAMT_first(symtab->sym_table); +} + +/*@null@*/ const yasm_symtab_iter * +yasm_symtab_next(const yasm_symtab_iter *prev) +{ + return (const yasm_symtab_iter *)HAMT_next((const HAMTEntry *)prev); +} + +yasm_symrec * +yasm_symtab_iter_value(const yasm_symtab_iter *cur) +{ + return (yasm_symrec *)HAMTEntry_get_data((const HAMTEntry *)cur); +} + +yasm_symrec * +yasm_symtab_abs_sym(yasm_symtab *symtab) +{ + yasm_symrec *rec = symtab_get_or_new(symtab, "", 1); + rec->def_line = 0; + rec->decl_line = 0; + rec->use_line = 0; + rec->type = SYM_EQU; + rec->value.expn = + yasm_expr_create_ident(yasm_expr_int(yasm_intnum_create_uint(0)), 0); + rec->status |= YASM_SYM_DEFINED|YASM_SYM_VALUED|YASM_SYM_USED; + return rec; +} + +yasm_symrec * +yasm_symtab_use(yasm_symtab *symtab, const char *name, unsigned long line) +{ + yasm_symrec *rec = symtab_get_or_new(symtab, name, 1); + if (rec->use_line == 0) + rec->use_line = line; /* set line number of first use */ + rec->status |= YASM_SYM_USED; + return rec; +} + +yasm_symrec * +yasm_symtab_get(yasm_symtab *symtab, const char *name) +{ + if (!symtab->case_sensitive) { + char *_name = yasm__xstrdup(name); + char *c; + yasm_symrec *ret; + for (c=_name; *c; c++) + *c = tolower(*c); + ret = HAMT_search(symtab->sym_table, _name); + yasm_xfree(_name); + return ret; + } else + return HAMT_search(symtab->sym_table, name); +} + +static /*@dependent@*/ yasm_symrec * +symtab_define(yasm_symtab *symtab, const char *name, sym_type type, + int in_table, unsigned long line) +{ + yasm_symrec *rec = symtab_get_or_new(symtab, name, in_table); + + /* Has it been defined before (either by DEFINED or COMMON/EXTERN)? */ + if (rec->status & YASM_SYM_DEFINED) { + yasm_error_set_xref(rec->def_line!=0 ? rec->def_line : rec->decl_line, + N_("`%s' previously defined here"), name); + yasm_error_set(YASM_ERROR_GENERAL, N_("redefinition of `%s'"), + name); + } else { + if (rec->visibility & YASM_SYM_EXTERN) + yasm_warn_set(YASM_WARN_GENERAL, + N_("`%s' both defined and declared extern"), name); + rec->def_line = line; /* set line number of definition */ + rec->type = type; + rec->status |= YASM_SYM_DEFINED; + rec->size = 0; + rec->segment = NULL; + } + return rec; +} + +yasm_symrec * +yasm_symtab_define_equ(yasm_symtab *symtab, const char *name, yasm_expr *e, + unsigned long line) +{ + yasm_symrec *rec = symtab_define(symtab, name, SYM_EQU, 1, line); + if (yasm_error_occurred()) + return rec; + rec->value.expn = e; + rec->status |= YASM_SYM_VALUED; + return rec; +} + +yasm_symrec * +yasm_symtab_define_label(yasm_symtab *symtab, const char *name, + yasm_bytecode *precbc, int in_table, + unsigned long line) +{ + yasm_symrec *rec = symtab_define(symtab, name, SYM_LABEL, in_table, line); + if (yasm_error_occurred()) + return rec; + rec->value.precbc = precbc; + if (in_table && precbc) + yasm_bc__add_symrec(precbc, rec); + return rec; +} + +yasm_symrec * +yasm_symtab_define_curpos(yasm_symtab *symtab, const char *name, + yasm_bytecode *precbc, unsigned long line) +{ + yasm_symrec *rec = symtab_define(symtab, name, SYM_CURPOS, 0, line); + if (yasm_error_occurred()) + return rec; + rec->value.precbc = precbc; + return rec; +} + +yasm_symrec * +yasm_symtab_define_special(yasm_symtab *symtab, const char *name, + yasm_sym_vis vis) +{ + yasm_symrec *rec = symtab_define(symtab, name, SYM_SPECIAL, 1, 0); + if (yasm_error_occurred()) + return rec; + rec->status |= YASM_SYM_VALUED; + rec->visibility = vis; + return rec; +} + +yasm_symrec * +yasm_symtab_declare(yasm_symtab *symtab, const char *name, yasm_sym_vis vis, + unsigned long line) +{ + yasm_symrec *rec = symtab_get_or_new(symtab, name, 1); + yasm_symrec_declare(rec, vis, line); + return rec; +} + +void +yasm_symrec_declare(yasm_symrec *rec, yasm_sym_vis vis, unsigned long line) +{ + /* Allowable combinations: + * Existing State-------------- vis New State------------------- + * DEFINED GLOBAL COMMON EXTERN GCE DEFINED GLOBAL COMMON EXTERN + * 0 - 0 0 GCE 0 G C E + * 0 - 0 1 GE 0 G 0 E + * 0 - 1 0 GC 0 G C 0 + * X 0 - 1 1 + * 1 - 0 0 G 1 G 0 0 + * X 1 - - 1 + * X 1 - 1 - + */ + if ((vis == YASM_SYM_GLOBAL) || + (!(rec->status & YASM_SYM_DEFINED) && + (!(rec->visibility & (YASM_SYM_COMMON | YASM_SYM_EXTERN)) || + ((rec->visibility & YASM_SYM_COMMON) && (vis == YASM_SYM_COMMON)) || + ((rec->visibility & YASM_SYM_EXTERN) && (vis == YASM_SYM_EXTERN))))) { + rec->decl_line = line; + rec->visibility |= vis; + } else + yasm_error_set(YASM_ERROR_GENERAL, + N_("duplicate definition of `%s'; first defined on line %lu"), + rec->name, rec->def_line!=0 ? rec->def_line : rec->decl_line); +} + +typedef struct symtab_finalize_info { + unsigned long firstundef_line; + int undef_extern; + yasm_errwarns *errwarns; +} symtab_finalize_info; + +static int +symtab_parser_finalize_checksym(yasm_symrec *sym, /*@null@*/ void *d) +{ + symtab_finalize_info *info = (symtab_finalize_info *)d; + + /* error if a symbol is used but never defined or extern/common declared */ + if ((sym->status & YASM_SYM_USED) && !(sym->status & YASM_SYM_DEFINED) && + !(sym->visibility & (YASM_SYM_EXTERN | YASM_SYM_COMMON))) { + if (info->undef_extern) + sym->visibility |= YASM_SYM_EXTERN; + else { + yasm_error_set(YASM_ERROR_GENERAL, + N_("undefined symbol `%s' (first use)"), sym->name); + yasm_errwarn_propagate(info->errwarns, sym->use_line); + if (sym->use_line < info->firstundef_line) + info->firstundef_line = sym->use_line; + } + } + + return 0; +} + +void +yasm_symtab_parser_finalize(yasm_symtab *symtab, int undef_extern, + yasm_errwarns *errwarns) +{ + symtab_finalize_info info; + info.firstundef_line = ULONG_MAX; + info.undef_extern = undef_extern; + info.errwarns = errwarns; + yasm_symtab_traverse(symtab, &info, symtab_parser_finalize_checksym); + if (info.firstundef_line < ULONG_MAX) { + yasm_error_set(YASM_ERROR_GENERAL, + N_(" (Each undefined symbol is reported only once.)")); + yasm_errwarn_propagate(errwarns, info.firstundef_line); + } +} + +void +yasm_symtab_destroy(yasm_symtab *symtab) +{ + HAMT_destroy(symtab->sym_table, symrec_destroy_one); + + while (!SLIST_EMPTY(&symtab->non_table_syms)) { + non_table_symrec *sym = SLIST_FIRST(&symtab->non_table_syms); + SLIST_REMOVE_HEAD(&symtab->non_table_syms, link); + symrec_destroy_one(sym->rec); + yasm_xfree(sym); + } + + yasm_xfree(symtab); +} + +typedef struct symrec_print_data { + FILE *f; + int indent_level; +} symrec_print_data; + +/*@+voidabstract@*/ +static int +symrec_print_wrapper(yasm_symrec *sym, /*@null@*/ void *d) +{ + symrec_print_data *data = (symrec_print_data *)d; + assert(data != NULL); + fprintf(data->f, "%*sSymbol `%s'\n", data->indent_level, "", sym->name); + yasm_symrec_print(sym, data->f, data->indent_level+1); + return 0; +} + +void +yasm_symtab_print(yasm_symtab *symtab, FILE *f, int indent_level) +{ + symrec_print_data data; + data.f = f; + data.indent_level = indent_level; + yasm_symtab_traverse(symtab, &data, symrec_print_wrapper); +} +/*@=voidabstract@*/ + +const char * +yasm_symrec_get_name(const yasm_symrec *sym) +{ + return sym->name; +} + +char * +yasm_symrec_get_global_name(const yasm_symrec *sym, const yasm_object *object) +{ + if (sym->visibility & (YASM_SYM_GLOBAL|YASM_SYM_COMMON|YASM_SYM_EXTERN)) { + char *name = yasm_xmalloc(strlen(object->global_prefix) + + strlen(sym->name) + + strlen(object->global_suffix) + 1); + strcpy(name, object->global_prefix); + strcat(name, sym->name); + strcat(name, object->global_suffix); + return name; + } + return yasm__xstrdup(sym->name); +} + +yasm_sym_vis +yasm_symrec_get_visibility(const yasm_symrec *sym) +{ + return sym->visibility; +} + +yasm_sym_status +yasm_symrec_get_status(const yasm_symrec *sym) +{ + return sym->status; +} + +unsigned long +yasm_symrec_get_def_line(const yasm_symrec *sym) +{ + return sym->def_line; +} + +unsigned long +yasm_symrec_get_decl_line(const yasm_symrec *sym) +{ + return sym->decl_line; +} + +unsigned long +yasm_symrec_get_use_line(const yasm_symrec *sym) +{ + return sym->use_line; +} + +const yasm_expr * +yasm_symrec_get_equ(const yasm_symrec *sym) +{ + if (sym->type == SYM_EQU && (sym->status & YASM_SYM_VALUED)) + return sym->value.expn; + return (const yasm_expr *)NULL; +} + +int +yasm_symrec_get_label(const yasm_symrec *sym, + yasm_symrec_get_label_bytecodep *precbc) +{ + if (!(sym->type == SYM_LABEL || sym->type == SYM_CURPOS) + || !sym->value.precbc) { + *precbc = (yasm_symrec_get_label_bytecodep)0xDEADBEEF; + return 0; + } + *precbc = sym->value.precbc; + return 1; +} + +void +yasm_symrec_set_size(yasm_symrec *sym, int size) +{ + sym->size = size; +} + +int +yasm_symrec_get_size(const yasm_symrec *sym) +{ + return sym->size; +} + +void +yasm_symrec_set_segment(yasm_symrec *sym, const char *segment) +{ + sym->segment = segment; +} + +const char * +yasm_symrec_get_segment(const yasm_symrec *sym) +{ + return sym->segment; +} + +int +yasm_symrec_is_abs(const yasm_symrec *sym) +{ + return (sym->def_line == 0 && sym->type == SYM_EQU && + sym->name[0] == '\0'); +} + +int +yasm_symrec_is_special(const yasm_symrec *sym) +{ + return (sym->type == SYM_SPECIAL); +} + +int +yasm_symrec_is_curpos(const yasm_symrec *sym) +{ + return (sym->type == SYM_CURPOS); +} + +void +yasm_symrec_set_objext_valparams(yasm_symrec *sym, + /*@only@*/ yasm_valparamhead *objext_valparams) +{ + yasm_symrec_add_data(sym, &objext_valparams_cb, objext_valparams); +} + +yasm_valparamhead * +yasm_symrec_get_objext_valparams(yasm_symrec *sym) +{ + return yasm_symrec_get_data(sym, &objext_valparams_cb); +} + +void +yasm_symrec_set_common_size(yasm_symrec *sym, + /*@only@*/ yasm_expr *common_size) +{ + yasm_expr **ep = yasm_xmalloc(sizeof(yasm_expr *)); + *ep = common_size; + yasm_symrec_add_data(sym, &common_size_cb, ep); +} + +yasm_expr ** +yasm_symrec_get_common_size(yasm_symrec *sym) +{ + return (yasm_expr **)yasm_symrec_get_data(sym, &common_size_cb); +} + +void * +yasm_symrec_get_data(yasm_symrec *sym, + const yasm_assoc_data_callback *callback) +{ + return yasm__assoc_data_get(sym->assoc_data, callback); +} + +void +yasm_symrec_add_data(yasm_symrec *sym, + const yasm_assoc_data_callback *callback, void *data) +{ + sym->assoc_data = yasm__assoc_data_add(sym->assoc_data, callback, data); +} + +void +yasm_symrec_print(const yasm_symrec *sym, FILE *f, int indent_level) +{ + switch (sym->type) { + case SYM_UNKNOWN: + fprintf(f, "%*s-Unknown (Common/Extern)-\n", indent_level, ""); + break; + case SYM_EQU: + fprintf(f, "%*s_EQU_\n", indent_level, ""); + fprintf(f, "%*sExpn=", indent_level, ""); + if (sym->status & YASM_SYM_VALUED) + yasm_expr_print(sym->value.expn, f); + else + fprintf(f, "***UNVALUED***"); + fprintf(f, "\n"); + break; + case SYM_LABEL: + case SYM_CURPOS: + fprintf(f, "%*s_%s_\n%*sSection:\n", indent_level, "", + sym->type == SYM_LABEL ? "Label" : "CurPos", + indent_level, ""); + yasm_section_print(yasm_bc_get_section(sym->value.precbc), f, + indent_level+1, 0); + fprintf(f, "%*sPreceding bytecode:\n", indent_level, ""); + yasm_bc_print(sym->value.precbc, f, indent_level+1); + break; + case SYM_SPECIAL: + fprintf(f, "%*s-Special-\n", indent_level, ""); + break; + } + + fprintf(f, "%*sStatus=", indent_level, ""); + if (sym->status == YASM_SYM_NOSTATUS) + fprintf(f, "None\n"); + else { + if (sym->status & YASM_SYM_USED) + fprintf(f, "Used,"); + if (sym->status & YASM_SYM_DEFINED) + fprintf(f, "Defined,"); + if (sym->status & YASM_SYM_VALUED) + fprintf(f, "Valued,"); + if (sym->status & YASM_SYM_NOTINTABLE) + fprintf(f, "Not in Table,"); + fprintf(f, "\n"); + } + + fprintf(f, "%*sVisibility=", indent_level, ""); + if (sym->visibility == YASM_SYM_LOCAL) + fprintf(f, "Local\n"); + else { + if (sym->visibility & YASM_SYM_GLOBAL) + fprintf(f, "Global,"); + if (sym->visibility & YASM_SYM_COMMON) + fprintf(f, "Common,"); + if (sym->visibility & YASM_SYM_EXTERN) + fprintf(f, "Extern,"); + fprintf(f, "\n"); + } + + if (sym->assoc_data) { + fprintf(f, "%*sAssociated data:\n", indent_level, ""); + yasm__assoc_data_print(sym->assoc_data, f, indent_level+1); + } + + fprintf(f, "%*sLine Index (Defined)=%lu\n", indent_level, "", + sym->def_line); + fprintf(f, "%*sLine Index (Declared)=%lu\n", indent_level, "", + sym->decl_line); + fprintf(f, "%*sLine Index (Used)=%lu\n", indent_level, "", sym->use_line); +} diff --git a/contrib/tools/yasm/libyasm/symrec.h b/contrib/tools/yasm/libyasm/symrec.h index b1f797c647..3ff464e688 100644 --- a/contrib/tools/yasm/libyasm/symrec.h +++ b/contrib/tools/yasm/libyasm/symrec.h @@ -1,437 +1,437 @@ -/** - * \file libyasm/symrec.h - * \brief YASM symbol table interface. - * - * \license - * Copyright (C) 2001-2007 Michael Urman, Peter Johnson - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * \endlicense - */ -#ifndef YASM_SYMREC_H -#define YASM_SYMREC_H - -#ifndef YASM_LIB_DECL -#define YASM_LIB_DECL -#endif - -/** Symbol status. YASM_SYM_DEFINED is set by yasm_symtab_define_label(), - * yasm_symtab_define_equ(), or yasm_symtab_declare()/yasm_symrec_declare() - * with a visibility of #YASM_SYM_EXTERN or #YASM_SYM_COMMON. - */ -typedef enum yasm_sym_status { - YASM_SYM_NOSTATUS = 0, /**< no status */ - YASM_SYM_USED = 1 << 0, /**< for use before definition */ - YASM_SYM_DEFINED = 1 << 1, /**< once it's been defined in the file */ - YASM_SYM_VALUED = 1 << 2, /**< once its value has been determined */ - YASM_SYM_NOTINTABLE = 1 << 3 /**< if it's not in sym_table (ex. '$') */ -} yasm_sym_status; - -/** Symbol record visibility. - * \note YASM_SYM_EXTERN and YASM_SYM_COMMON are mutually exclusive. - */ -typedef enum yasm_sym_vis { - YASM_SYM_LOCAL = 0, /**< Default, local only */ - YASM_SYM_GLOBAL = 1 << 0, /**< If symbol is declared GLOBAL */ - YASM_SYM_COMMON = 1 << 1, /**< If symbol is declared COMMON */ - YASM_SYM_EXTERN = 1 << 2, /**< If symbol is declared EXTERN */ - YASM_SYM_DLOCAL = 1 << 3 /**< If symbol is explicitly declared LOCAL */ -} yasm_sym_vis; - -/** Create a new symbol table. */ -YASM_LIB_DECL -yasm_symtab *yasm_symtab_create(void); - -/** Destroy a symbol table and all internal symbols. - * \param symtab symbol table - * \warning All yasm_symrec *'s into this symbol table become invalid after - * this is called! - */ -YASM_LIB_DECL -void yasm_symtab_destroy(/*@only@*/ yasm_symtab *symtab); - -/** Set the symbol table to be case sensitive or not. - * Should be called before adding any symbol. - * \param symtab symbol table - * \param sensitive whether the symbol table should be case sensitive. - */ -YASM_LIB_DECL -void yasm_symtab_set_case_sensitive(yasm_symtab *symtab, int sensitive); - -/** Get a reference to the symbol table's "absolute" symbol. This is - * essentially an EQU with no name and value 0, and is used for relocating - * absolute current-position-relative values. - * \see yasm_value_set_curpos_rel(). - * \param symtab symbol table - * \return Absolute symbol (dependent pointer, do not free). - */ -YASM_LIB_DECL -/*@dependent@*/ yasm_symrec *yasm_symtab_abs_sym(yasm_symtab *symtab); - -/** Get a reference to (use) a symbol. The symbol does not necessarily need to - * be defined before it is used. - * \param symtab symbol table - * \param name symbol name - * \param line virtual line where referenced - * \return Symbol (dependent pointer, do not free). - */ -YASM_LIB_DECL -/*@dependent@*/ yasm_symrec *yasm_symtab_use - (yasm_symtab *symtab, const char *name, unsigned long line); - -/** Get a reference to a symbol, without "using" it. Should be used for cases - * when an internal assembler usage of a symbol shouldn't be treated like a - * normal user symbol usage. - * \param symtab symbol table - * \param name symbol name - * \return Symbol (dependent pointer, do not free). May be NULL if symbol - * doesn't exist. - */ -YASM_LIB_DECL -/*@null@*/ /*@dependent@*/ yasm_symrec *yasm_symtab_get - (yasm_symtab *symtab, const char *name); - -/** Define a symbol as an EQU value. - * \param symtab symbol table - * \param name symbol (EQU) name - * \param e EQU value (expression) - * \param line virtual line of EQU - * \return Symbol (dependent pointer, do not free). - */ -YASM_LIB_DECL -/*@dependent@*/ yasm_symrec *yasm_symtab_define_equ - (yasm_symtab *symtab, const char *name, /*@keep@*/ yasm_expr *e, - unsigned long line); - -/** Define a symbol as a label. - * \param symtab symbol table - * \param name symbol (label) name - * \param precbc bytecode preceding label - * \param in_table nonzero if the label should be inserted into the symbol - * table (some specially-generated ones should not be) - * \param line virtual line of label - * \return Symbol (dependent pointer, do not free). - */ -YASM_LIB_DECL -/*@dependent@*/ yasm_symrec *yasm_symtab_define_label - (yasm_symtab *symtab, const char *name, - /*@dependent@*/ yasm_bytecode *precbc, int in_table, unsigned long line); - -/** Define a symbol as a label representing the current assembly position. - * This should be used for this purpose instead of yasm_symtab_define_label() - * as value_finalize_scan() looks for usage of this symbol type for special - * handling. The symbol created is not inserted into the symbol table. - * \param symtab symbol table - * \param name symbol (label) name - * \param precbc bytecode preceding label - * \param line virtual line of label - * \return Symbol (dependent pointer, do not free). - */ -YASM_LIB_DECL -/*@dependent@*/ yasm_symrec *yasm_symtab_define_curpos - (yasm_symtab *symtab, const char *name, - /*@dependent@*/ yasm_bytecode *precbc, unsigned long line); - -/** Define a special symbol that will appear in the symbol table and have a - * defined name, but have no other data associated with it within the - * standard symrec. - * \param symtab symbol table - * \param name symbol name - * \param vis symbol visibility - * \return Symbol (dependent pointer, do not free). - */ -YASM_LIB_DECL -/*@dependent@*/ yasm_symrec *yasm_symtab_define_special - (yasm_symtab *symtab, const char *name, yasm_sym_vis vis); - -/** Declare external visibility of a symbol. - * \note Not all visibility combinations are allowed. - * \param symtab symbol table - * \param name symbol name - * \param vis visibility - * \param line virtual line of visibility-setting - * \return Symbol (dependent pointer, do not free). - */ -YASM_LIB_DECL -/*@dependent@*/ yasm_symrec *yasm_symtab_declare - (yasm_symtab *symtab, const char *name, yasm_sym_vis vis, - unsigned long line); - -/** Declare external visibility of a symbol. - * \note Not all visibility combinations are allowed. - * \param symrec symbol - * \param vis visibility - * \param line virtual line of visibility-setting - */ -YASM_LIB_DECL -void yasm_symrec_declare(yasm_symrec *symrec, yasm_sym_vis vis, - unsigned long line); - -/** Callback function for yasm_symrec_traverse(). - * \param sym symbol - * \param d data passed into yasm_symrec_traverse() - * \return Nonzero to stop symbol traversal. - */ -typedef int (*yasm_symtab_traverse_callback) - (yasm_symrec *sym, /*@null@*/ void *d); - -/** Traverse all symbols in the symbol table. - * \param symtab symbol table - * \param d data to pass to each call of callback function - * \param func callback function called on each symbol - * \return Nonzero value returned by callback function if it ever returned - * nonzero. - */ -YASM_LIB_DECL -int /*@alt void@*/ yasm_symtab_traverse - (yasm_symtab *symtab, /*@null@*/ void *d, - yasm_symtab_traverse_callback func); - -/** Symbol table iterator (opaque type). */ -typedef struct yasm_symtab_iter yasm_symtab_iter; - -/** Get an iterator pointing to the first symbol in the symbol table. - * \param symtab symbol table - * \return Iterator for the symbol table. - */ -YASM_LIB_DECL -const yasm_symtab_iter *yasm_symtab_first(const yasm_symtab *symtab); - -/** Move a symbol table iterator to the next symbol in the symbol table. - * \param prev Previous iterator value - * \return Next iterator value, or NULL if no more symbols in the table. - */ -YASM_LIB_DECL -/*@null@*/ const yasm_symtab_iter *yasm_symtab_next - (const yasm_symtab_iter *prev); - -/** Get the symbol corresponding to the current symbol table iterator value. - * \param cur iterator value - * \return Corresponding symbol. - */ -YASM_LIB_DECL -yasm_symrec *yasm_symtab_iter_value(const yasm_symtab_iter *cur); - -/** Finalize symbol table after parsing stage. Checks for symbols that are - * used but never defined or declared #YASM_SYM_EXTERN or #YASM_SYM_COMMON. - * \param symtab symbol table - * \param undef_extern if nonzero, all undef syms should be declared extern - * \param errwarns error/warning set - * \note Errors/warnings are stored into errwarns. - */ -YASM_LIB_DECL -void yasm_symtab_parser_finalize(yasm_symtab *symtab, int undef_extern, - yasm_errwarns *errwarns); - -/** Print the symbol table. For debugging purposes. - * \param symtab symbol table - * \param f file - * \param indent_level indentation level - */ -YASM_LIB_DECL -void yasm_symtab_print(yasm_symtab *symtab, FILE *f, int indent_level); - -/** Get the name of a symbol. - * \param sym symbol - * \return Symbol name. - */ -YASM_LIB_DECL -/*@observer@*/ const char *yasm_symrec_get_name(const yasm_symrec *sym); - -/** Get the externally-visible (global) name of a symbol. - * \param sym symbol - * \param object object - * \return Externally-visible symbol name (allocated, caller must free). - */ -YASM_LIB_DECL -/*@only@*/ char *yasm_symrec_get_global_name(const yasm_symrec *sym, - const yasm_object *object); - -/** Get the visibility of a symbol. - * \param sym symbol - * \return Symbol visibility. - */ -YASM_LIB_DECL -yasm_sym_vis yasm_symrec_get_visibility(const yasm_symrec *sym); - -/** Get the status of a symbol. - * \param sym symbol - * \return Symbol status. - */ -YASM_LIB_DECL -yasm_sym_status yasm_symrec_get_status(const yasm_symrec *sym); - -/** Get the virtual line of where a symbol was first defined. - * \param sym symbol - * \return line virtual line - */ -YASM_LIB_DECL -unsigned long yasm_symrec_get_def_line(const yasm_symrec *sym); - -/** Get the virtual line of where a symbol was first declared. - * \param sym symbol - * \return line virtual line - */ -YASM_LIB_DECL -unsigned long yasm_symrec_get_decl_line(const yasm_symrec *sym); - -/** Get the virtual line of where a symbol was first used. - * \param sym symbol - * \return line virtual line - */ -YASM_LIB_DECL -unsigned long yasm_symrec_get_use_line(const yasm_symrec *sym); - -/** Get EQU value of a symbol. - * \param sym symbol - * \return EQU value, or NULL if symbol is not an EQU or is not defined. - */ -YASM_LIB_DECL -/*@observer@*/ /*@null@*/ const yasm_expr *yasm_symrec_get_equ - (const yasm_symrec *sym); - -/** Dependent pointer to a bytecode. */ -typedef /*@dependent@*/ yasm_bytecode *yasm_symrec_get_label_bytecodep; - -/** Get the label location of a symbol. - * \param sym symbol - * \param precbc bytecode preceding label (output) - * \return 0 if not symbol is not a label or if the symbol's visibility is - * #YASM_SYM_EXTERN or #YASM_SYM_COMMON (not defined in the file). - */ -YASM_LIB_DECL -int yasm_symrec_get_label(const yasm_symrec *sym, - /*@out@*/ yasm_symrec_get_label_bytecodep *precbc); - -/** Set the size of a symbol. - * \param sym symbol - * \param size size to be set - */ -YASM_LIB_DECL -void yasm_symrec_set_size(yasm_symrec *sym, int size); - -/** Get the size of a symbol. - * \param sym symbol - * \return size of the symbol, 0 if none specified by the user. - */ -YASM_LIB_DECL -int yasm_symrec_get_size(const yasm_symrec *sym); - -/** Set the segment of a symbol. - * \param sym symbol - * \param segment segment to be set - */ -YASM_LIB_DECL -void yasm_symrec_set_segment(yasm_symrec *sym, const char *segment); - -/** Get the segment of a symbol. - * \param sym symbol - * \return segment of the symbol, NULL if none specified by the user. - */ -YASM_LIB_DECL -const char *yasm_symrec_get_segment(const yasm_symrec *sym); - -/** Determine if symbol is the "absolute" symbol created by - * yasm_symtab_abs_sym(). - * \param sym symbol - * \return 0 if symbol is not the "absolute" symbol, nonzero otherwise. - */ -YASM_LIB_DECL -int yasm_symrec_is_abs(const yasm_symrec *sym); - -/** Determine if symbol is a special symbol. - * \param sym symbol - * \return 0 if symbol is not a special symbol, nonzero otherwise. - */ -YASM_LIB_DECL -int yasm_symrec_is_special(const yasm_symrec *sym); - -/** Determine if symbol is a label representing the current assembly position. - * \param sym symbol - * \return 0 if symbol is not a current position label, nonzero otherwise. - */ -YASM_LIB_DECL -int yasm_symrec_is_curpos(const yasm_symrec *sym); - -/** Set object-extended valparams. - * \param sym symbol - * \param objext_valparams object-extended valparams - */ -YASM_LIB_DECL -void yasm_symrec_set_objext_valparams - (yasm_symrec *sym, /*@only@*/ yasm_valparamhead *objext_valparams); - -/** Get object-extended valparams, if any, associated with symbol's - * declaration. - * \param sym symbol - * \return Object-extended valparams (NULL if none). - */ -YASM_LIB_DECL -/*@null@*/ /*@dependent@*/ yasm_valparamhead *yasm_symrec_get_objext_valparams - (yasm_symrec *sym); - -/** Set common size of symbol. - * \param sym symbol - * \param common_size common size expression - */ -YASM_LIB_DECL -void yasm_symrec_set_common_size - (yasm_symrec *sym, /*@only@*/ yasm_expr *common_size); - -/** Get common size of symbol, if symbol is declared COMMON and a size was set - * for it. - * \param sym symbol - * \return Common size (NULL if none). - */ -YASM_LIB_DECL -/*@dependent@*/ /*@null@*/ yasm_expr **yasm_symrec_get_common_size - (yasm_symrec *sym); - -/** Get associated data for a symbol and data callback. - * \param sym symbol - * \param callback callback used when adding data - * \return Associated data (NULL if none). - */ -YASM_LIB_DECL -/*@dependent@*/ /*@null@*/ void *yasm_symrec_get_data - (yasm_symrec *sym, const yasm_assoc_data_callback *callback); - -/** Add associated data to a symbol. - * \attention Deletes any existing associated data for that data callback. - * \param sym symbol - * \param callback callback - * \param data data to associate - */ -YASM_LIB_DECL -void yasm_symrec_add_data(yasm_symrec *sym, - const yasm_assoc_data_callback *callback, - /*@only@*/ /*@null@*/ void *data); - -/** Print a symbol. For debugging purposes. - * \param f file - * \param indent_level indentation level - * \param sym symbol - */ -YASM_LIB_DECL -void yasm_symrec_print(const yasm_symrec *sym, FILE *f, int indent_level); - -#endif +/** + * \file libyasm/symrec.h + * \brief YASM symbol table interface. + * + * \license + * Copyright (C) 2001-2007 Michael Urman, Peter Johnson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * \endlicense + */ +#ifndef YASM_SYMREC_H +#define YASM_SYMREC_H + +#ifndef YASM_LIB_DECL +#define YASM_LIB_DECL +#endif + +/** Symbol status. YASM_SYM_DEFINED is set by yasm_symtab_define_label(), + * yasm_symtab_define_equ(), or yasm_symtab_declare()/yasm_symrec_declare() + * with a visibility of #YASM_SYM_EXTERN or #YASM_SYM_COMMON. + */ +typedef enum yasm_sym_status { + YASM_SYM_NOSTATUS = 0, /**< no status */ + YASM_SYM_USED = 1 << 0, /**< for use before definition */ + YASM_SYM_DEFINED = 1 << 1, /**< once it's been defined in the file */ + YASM_SYM_VALUED = 1 << 2, /**< once its value has been determined */ + YASM_SYM_NOTINTABLE = 1 << 3 /**< if it's not in sym_table (ex. '$') */ +} yasm_sym_status; + +/** Symbol record visibility. + * \note YASM_SYM_EXTERN and YASM_SYM_COMMON are mutually exclusive. + */ +typedef enum yasm_sym_vis { + YASM_SYM_LOCAL = 0, /**< Default, local only */ + YASM_SYM_GLOBAL = 1 << 0, /**< If symbol is declared GLOBAL */ + YASM_SYM_COMMON = 1 << 1, /**< If symbol is declared COMMON */ + YASM_SYM_EXTERN = 1 << 2, /**< If symbol is declared EXTERN */ + YASM_SYM_DLOCAL = 1 << 3 /**< If symbol is explicitly declared LOCAL */ +} yasm_sym_vis; + +/** Create a new symbol table. */ +YASM_LIB_DECL +yasm_symtab *yasm_symtab_create(void); + +/** Destroy a symbol table and all internal symbols. + * \param symtab symbol table + * \warning All yasm_symrec *'s into this symbol table become invalid after + * this is called! + */ +YASM_LIB_DECL +void yasm_symtab_destroy(/*@only@*/ yasm_symtab *symtab); + +/** Set the symbol table to be case sensitive or not. + * Should be called before adding any symbol. + * \param symtab symbol table + * \param sensitive whether the symbol table should be case sensitive. + */ +YASM_LIB_DECL +void yasm_symtab_set_case_sensitive(yasm_symtab *symtab, int sensitive); + +/** Get a reference to the symbol table's "absolute" symbol. This is + * essentially an EQU with no name and value 0, and is used for relocating + * absolute current-position-relative values. + * \see yasm_value_set_curpos_rel(). + * \param symtab symbol table + * \return Absolute symbol (dependent pointer, do not free). + */ +YASM_LIB_DECL +/*@dependent@*/ yasm_symrec *yasm_symtab_abs_sym(yasm_symtab *symtab); + +/** Get a reference to (use) a symbol. The symbol does not necessarily need to + * be defined before it is used. + * \param symtab symbol table + * \param name symbol name + * \param line virtual line where referenced + * \return Symbol (dependent pointer, do not free). + */ +YASM_LIB_DECL +/*@dependent@*/ yasm_symrec *yasm_symtab_use + (yasm_symtab *symtab, const char *name, unsigned long line); + +/** Get a reference to a symbol, without "using" it. Should be used for cases + * when an internal assembler usage of a symbol shouldn't be treated like a + * normal user symbol usage. + * \param symtab symbol table + * \param name symbol name + * \return Symbol (dependent pointer, do not free). May be NULL if symbol + * doesn't exist. + */ +YASM_LIB_DECL +/*@null@*/ /*@dependent@*/ yasm_symrec *yasm_symtab_get + (yasm_symtab *symtab, const char *name); + +/** Define a symbol as an EQU value. + * \param symtab symbol table + * \param name symbol (EQU) name + * \param e EQU value (expression) + * \param line virtual line of EQU + * \return Symbol (dependent pointer, do not free). + */ +YASM_LIB_DECL +/*@dependent@*/ yasm_symrec *yasm_symtab_define_equ + (yasm_symtab *symtab, const char *name, /*@keep@*/ yasm_expr *e, + unsigned long line); + +/** Define a symbol as a label. + * \param symtab symbol table + * \param name symbol (label) name + * \param precbc bytecode preceding label + * \param in_table nonzero if the label should be inserted into the symbol + * table (some specially-generated ones should not be) + * \param line virtual line of label + * \return Symbol (dependent pointer, do not free). + */ +YASM_LIB_DECL +/*@dependent@*/ yasm_symrec *yasm_symtab_define_label + (yasm_symtab *symtab, const char *name, + /*@dependent@*/ yasm_bytecode *precbc, int in_table, unsigned long line); + +/** Define a symbol as a label representing the current assembly position. + * This should be used for this purpose instead of yasm_symtab_define_label() + * as value_finalize_scan() looks for usage of this symbol type for special + * handling. The symbol created is not inserted into the symbol table. + * \param symtab symbol table + * \param name symbol (label) name + * \param precbc bytecode preceding label + * \param line virtual line of label + * \return Symbol (dependent pointer, do not free). + */ +YASM_LIB_DECL +/*@dependent@*/ yasm_symrec *yasm_symtab_define_curpos + (yasm_symtab *symtab, const char *name, + /*@dependent@*/ yasm_bytecode *precbc, unsigned long line); + +/** Define a special symbol that will appear in the symbol table and have a + * defined name, but have no other data associated with it within the + * standard symrec. + * \param symtab symbol table + * \param name symbol name + * \param vis symbol visibility + * \return Symbol (dependent pointer, do not free). + */ +YASM_LIB_DECL +/*@dependent@*/ yasm_symrec *yasm_symtab_define_special + (yasm_symtab *symtab, const char *name, yasm_sym_vis vis); + +/** Declare external visibility of a symbol. + * \note Not all visibility combinations are allowed. + * \param symtab symbol table + * \param name symbol name + * \param vis visibility + * \param line virtual line of visibility-setting + * \return Symbol (dependent pointer, do not free). + */ +YASM_LIB_DECL +/*@dependent@*/ yasm_symrec *yasm_symtab_declare + (yasm_symtab *symtab, const char *name, yasm_sym_vis vis, + unsigned long line); + +/** Declare external visibility of a symbol. + * \note Not all visibility combinations are allowed. + * \param symrec symbol + * \param vis visibility + * \param line virtual line of visibility-setting + */ +YASM_LIB_DECL +void yasm_symrec_declare(yasm_symrec *symrec, yasm_sym_vis vis, + unsigned long line); + +/** Callback function for yasm_symrec_traverse(). + * \param sym symbol + * \param d data passed into yasm_symrec_traverse() + * \return Nonzero to stop symbol traversal. + */ +typedef int (*yasm_symtab_traverse_callback) + (yasm_symrec *sym, /*@null@*/ void *d); + +/** Traverse all symbols in the symbol table. + * \param symtab symbol table + * \param d data to pass to each call of callback function + * \param func callback function called on each symbol + * \return Nonzero value returned by callback function if it ever returned + * nonzero. + */ +YASM_LIB_DECL +int /*@alt void@*/ yasm_symtab_traverse + (yasm_symtab *symtab, /*@null@*/ void *d, + yasm_symtab_traverse_callback func); + +/** Symbol table iterator (opaque type). */ +typedef struct yasm_symtab_iter yasm_symtab_iter; + +/** Get an iterator pointing to the first symbol in the symbol table. + * \param symtab symbol table + * \return Iterator for the symbol table. + */ +YASM_LIB_DECL +const yasm_symtab_iter *yasm_symtab_first(const yasm_symtab *symtab); + +/** Move a symbol table iterator to the next symbol in the symbol table. + * \param prev Previous iterator value + * \return Next iterator value, or NULL if no more symbols in the table. + */ +YASM_LIB_DECL +/*@null@*/ const yasm_symtab_iter *yasm_symtab_next + (const yasm_symtab_iter *prev); + +/** Get the symbol corresponding to the current symbol table iterator value. + * \param cur iterator value + * \return Corresponding symbol. + */ +YASM_LIB_DECL +yasm_symrec *yasm_symtab_iter_value(const yasm_symtab_iter *cur); + +/** Finalize symbol table after parsing stage. Checks for symbols that are + * used but never defined or declared #YASM_SYM_EXTERN or #YASM_SYM_COMMON. + * \param symtab symbol table + * \param undef_extern if nonzero, all undef syms should be declared extern + * \param errwarns error/warning set + * \note Errors/warnings are stored into errwarns. + */ +YASM_LIB_DECL +void yasm_symtab_parser_finalize(yasm_symtab *symtab, int undef_extern, + yasm_errwarns *errwarns); + +/** Print the symbol table. For debugging purposes. + * \param symtab symbol table + * \param f file + * \param indent_level indentation level + */ +YASM_LIB_DECL +void yasm_symtab_print(yasm_symtab *symtab, FILE *f, int indent_level); + +/** Get the name of a symbol. + * \param sym symbol + * \return Symbol name. + */ +YASM_LIB_DECL +/*@observer@*/ const char *yasm_symrec_get_name(const yasm_symrec *sym); + +/** Get the externally-visible (global) name of a symbol. + * \param sym symbol + * \param object object + * \return Externally-visible symbol name (allocated, caller must free). + */ +YASM_LIB_DECL +/*@only@*/ char *yasm_symrec_get_global_name(const yasm_symrec *sym, + const yasm_object *object); + +/** Get the visibility of a symbol. + * \param sym symbol + * \return Symbol visibility. + */ +YASM_LIB_DECL +yasm_sym_vis yasm_symrec_get_visibility(const yasm_symrec *sym); + +/** Get the status of a symbol. + * \param sym symbol + * \return Symbol status. + */ +YASM_LIB_DECL +yasm_sym_status yasm_symrec_get_status(const yasm_symrec *sym); + +/** Get the virtual line of where a symbol was first defined. + * \param sym symbol + * \return line virtual line + */ +YASM_LIB_DECL +unsigned long yasm_symrec_get_def_line(const yasm_symrec *sym); + +/** Get the virtual line of where a symbol was first declared. + * \param sym symbol + * \return line virtual line + */ +YASM_LIB_DECL +unsigned long yasm_symrec_get_decl_line(const yasm_symrec *sym); + +/** Get the virtual line of where a symbol was first used. + * \param sym symbol + * \return line virtual line + */ +YASM_LIB_DECL +unsigned long yasm_symrec_get_use_line(const yasm_symrec *sym); + +/** Get EQU value of a symbol. + * \param sym symbol + * \return EQU value, or NULL if symbol is not an EQU or is not defined. + */ +YASM_LIB_DECL +/*@observer@*/ /*@null@*/ const yasm_expr *yasm_symrec_get_equ + (const yasm_symrec *sym); + +/** Dependent pointer to a bytecode. */ +typedef /*@dependent@*/ yasm_bytecode *yasm_symrec_get_label_bytecodep; + +/** Get the label location of a symbol. + * \param sym symbol + * \param precbc bytecode preceding label (output) + * \return 0 if not symbol is not a label or if the symbol's visibility is + * #YASM_SYM_EXTERN or #YASM_SYM_COMMON (not defined in the file). + */ +YASM_LIB_DECL +int yasm_symrec_get_label(const yasm_symrec *sym, + /*@out@*/ yasm_symrec_get_label_bytecodep *precbc); + +/** Set the size of a symbol. + * \param sym symbol + * \param size size to be set + */ +YASM_LIB_DECL +void yasm_symrec_set_size(yasm_symrec *sym, int size); + +/** Get the size of a symbol. + * \param sym symbol + * \return size of the symbol, 0 if none specified by the user. + */ +YASM_LIB_DECL +int yasm_symrec_get_size(const yasm_symrec *sym); + +/** Set the segment of a symbol. + * \param sym symbol + * \param segment segment to be set + */ +YASM_LIB_DECL +void yasm_symrec_set_segment(yasm_symrec *sym, const char *segment); + +/** Get the segment of a symbol. + * \param sym symbol + * \return segment of the symbol, NULL if none specified by the user. + */ +YASM_LIB_DECL +const char *yasm_symrec_get_segment(const yasm_symrec *sym); + +/** Determine if symbol is the "absolute" symbol created by + * yasm_symtab_abs_sym(). + * \param sym symbol + * \return 0 if symbol is not the "absolute" symbol, nonzero otherwise. + */ +YASM_LIB_DECL +int yasm_symrec_is_abs(const yasm_symrec *sym); + +/** Determine if symbol is a special symbol. + * \param sym symbol + * \return 0 if symbol is not a special symbol, nonzero otherwise. + */ +YASM_LIB_DECL +int yasm_symrec_is_special(const yasm_symrec *sym); + +/** Determine if symbol is a label representing the current assembly position. + * \param sym symbol + * \return 0 if symbol is not a current position label, nonzero otherwise. + */ +YASM_LIB_DECL +int yasm_symrec_is_curpos(const yasm_symrec *sym); + +/** Set object-extended valparams. + * \param sym symbol + * \param objext_valparams object-extended valparams + */ +YASM_LIB_DECL +void yasm_symrec_set_objext_valparams + (yasm_symrec *sym, /*@only@*/ yasm_valparamhead *objext_valparams); + +/** Get object-extended valparams, if any, associated with symbol's + * declaration. + * \param sym symbol + * \return Object-extended valparams (NULL if none). + */ +YASM_LIB_DECL +/*@null@*/ /*@dependent@*/ yasm_valparamhead *yasm_symrec_get_objext_valparams + (yasm_symrec *sym); + +/** Set common size of symbol. + * \param sym symbol + * \param common_size common size expression + */ +YASM_LIB_DECL +void yasm_symrec_set_common_size + (yasm_symrec *sym, /*@only@*/ yasm_expr *common_size); + +/** Get common size of symbol, if symbol is declared COMMON and a size was set + * for it. + * \param sym symbol + * \return Common size (NULL if none). + */ +YASM_LIB_DECL +/*@dependent@*/ /*@null@*/ yasm_expr **yasm_symrec_get_common_size + (yasm_symrec *sym); + +/** Get associated data for a symbol and data callback. + * \param sym symbol + * \param callback callback used when adding data + * \return Associated data (NULL if none). + */ +YASM_LIB_DECL +/*@dependent@*/ /*@null@*/ void *yasm_symrec_get_data + (yasm_symrec *sym, const yasm_assoc_data_callback *callback); + +/** Add associated data to a symbol. + * \attention Deletes any existing associated data for that data callback. + * \param sym symbol + * \param callback callback + * \param data data to associate + */ +YASM_LIB_DECL +void yasm_symrec_add_data(yasm_symrec *sym, + const yasm_assoc_data_callback *callback, + /*@only@*/ /*@null@*/ void *data); + +/** Print a symbol. For debugging purposes. + * \param f file + * \param indent_level indentation level + * \param sym symbol + */ +YASM_LIB_DECL +void yasm_symrec_print(const yasm_symrec *sym, FILE *f, int indent_level); + +#endif diff --git a/contrib/tools/yasm/libyasm/valparam.c b/contrib/tools/yasm/libyasm/valparam.c index 88e41a7c5d..a1e2acdd1a 100644 --- a/contrib/tools/yasm/libyasm/valparam.c +++ b/contrib/tools/yasm/libyasm/valparam.c @@ -1,385 +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; -} +/* + * Value/Parameter type functions + * + * Copyright (C) 2001-2007 Peter Johnson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include "util.h" + +#include "libyasm-stdint.h" +#include "coretype.h" +#include "valparam.h" + +#include "errwarn.h" +#include "intnum.h" +#include "expr.h" +#include "symrec.h" + +#include "section.h" + +void +yasm_call_directive(const yasm_directive *directive, yasm_object *object, + yasm_valparamhead *valparams, + yasm_valparamhead *objext_valparams, unsigned long line) +{ + yasm_valparam *vp; + + if ((directive->flags & (YASM_DIR_ARG_REQUIRED|YASM_DIR_ID_REQUIRED)) && + (!valparams || !yasm_vps_first(valparams))) { + yasm_error_set(YASM_ERROR_SYNTAX, + N_("directive `%s' requires an argument"), + directive->name); + return; + } + if (valparams) { + vp = yasm_vps_first(valparams); + if ((directive->flags & YASM_DIR_ID_REQUIRED) && + vp->type != YASM_PARAM_ID) { + yasm_error_set(YASM_ERROR_SYNTAX, + N_("directive `%s' requires an identifier parameter"), + directive->name); + return; + } + } + directive->handler(object, valparams, objext_valparams, line); +} + +yasm_valparam * +yasm_vp_create_id(/*@keep@*/ char *v, /*@keep@*/ char *p, int id_prefix) +{ + yasm_valparam *r = yasm_xmalloc(sizeof(yasm_valparam)); + r->val = v; + r->type = YASM_PARAM_ID; + r->param.id = p; + r->id_prefix = (char)id_prefix; + return r; +} + +yasm_valparam * +yasm_vp_create_string(/*@keep@*/ char *v, /*@keep@*/ char *p) +{ + yasm_valparam *r = yasm_xmalloc(sizeof(yasm_valparam)); + r->val = v; + r->type = YASM_PARAM_STRING; + r->param.str = p; + r->id_prefix = '\0'; + return r; +} + +yasm_valparam * +yasm_vp_create_expr(/*@keep@*/ char *v, /*@keep@*/ yasm_expr *p) +{ + yasm_valparam *r = yasm_xmalloc(sizeof(yasm_valparam)); + r->val = v; + r->type = YASM_PARAM_EXPR; + r->param.e = p; + r->id_prefix = '\0'; + return r; +} + +/*@null@*/ /*@only@*/ yasm_expr * +yasm_vp_expr(const yasm_valparam *vp, yasm_symtab *symtab, unsigned long line) +{ + if (!vp) + return NULL; + switch (vp->type) { + case YASM_PARAM_ID: + return yasm_expr_create_ident(yasm_expr_sym( + yasm_symtab_use(symtab, yasm_vp_id(vp), line)), line); + case YASM_PARAM_EXPR: + return yasm_expr_copy(vp->param.e); + default: + return NULL; + } +} + +/*@null@*/ /*@dependent@*/ const char * +yasm_vp_string(const yasm_valparam *vp) +{ + if (!vp) + return NULL; + switch (vp->type) { + case YASM_PARAM_ID: + return vp->param.id; + case YASM_PARAM_STRING: + return vp->param.str; + default: + return NULL; + } +} + +/*@null@*/ /*@dependent@*/ const char * +yasm_vp_id(const yasm_valparam *vp) +{ + if (!vp) + return NULL; + if (vp->type == YASM_PARAM_ID) { + if (vp->param.id[0] == vp->id_prefix) + return &vp->param.id[1]; + else + return vp->param.id; + } + return NULL; +} + +void +yasm_vps_delete(yasm_valparamhead *headp) +{ + yasm_valparam *cur, *next; + + cur = STAILQ_FIRST(headp); + while (cur) { + next = STAILQ_NEXT(cur, link); + if (cur->val) + yasm_xfree(cur->val); + switch (cur->type) { + case YASM_PARAM_ID: + yasm_xfree(cur->param.id); + break; + case YASM_PARAM_STRING: + yasm_xfree(cur->param.str); + break; + case YASM_PARAM_EXPR: + yasm_expr_destroy(cur->param.e); + break; + } + yasm_xfree(cur); + cur = next; + } + STAILQ_INIT(headp); +} + +void +yasm_vps_print(const yasm_valparamhead *headp, FILE *f) +{ + const yasm_valparam *vp; + + if(!headp) { + fprintf(f, "(none)"); + return; + } + + yasm_vps_foreach(vp, headp) { + if (vp->val) + fprintf(f, "(\"%s\",", vp->val); + else + fprintf(f, "((nil),"); + switch (vp->type) { + case YASM_PARAM_ID: + fprintf(f, "%s", vp->param.id); + break; + case YASM_PARAM_STRING: + fprintf(f, "\"%s\"", vp->param.str); + break; + case YASM_PARAM_EXPR: + yasm_expr_print(vp->param.e, f); + break; + } + fprintf(f, ")"); + if (yasm_vps_next(vp)) + fprintf(f, ","); + } +} + +yasm_valparamhead * +yasm_vps_create(void) +{ + yasm_valparamhead *headp = yasm_xmalloc(sizeof(yasm_valparamhead)); + yasm_vps_initialize(headp); + return headp; +} + +void +yasm_vps_destroy(yasm_valparamhead *headp) +{ + yasm_vps_delete(headp); + yasm_xfree(headp); +} + +int +yasm_dir_helper(void *obj, yasm_valparam *vp_first, unsigned long line, + const yasm_dir_help *help, size_t nhelp, void *data, + int (*helper_valparam) (void *obj, yasm_valparam *vp, + unsigned long line, void *data)) +{ + yasm_valparam *vp = vp_first; + int anymatched = 0; + int matched; + + if (!vp) + return 0; + + do { + const char *s; + size_t i; + + matched = 0; + if (!vp->val && (s = yasm_vp_id(vp))) { + for (i=0; i<nhelp; i++) { + if (help[i].needsparam == 0 && + yasm__strcasecmp(s, help[i].name) == 0) { + if (help[i].helper(obj, vp, line, + ((char *)data)+help[i].off, + help[i].arg) != 0) + return -1; + matched = 1; + anymatched = 1; + break; + } + } + } else if (vp->val) { + for (i=0; i<nhelp; i++) { + if (help[i].needsparam == 1 && + yasm__strcasecmp(vp->val, help[i].name) == 0) { + if (help[i].helper(obj, vp, line, + ((char *)data)+help[i].off, + help[i].arg) != 0) + return -1; + matched = 1; + anymatched = 1; + break; + } + } + } + + if (!matched) { + int final = helper_valparam(obj, vp, line, data); + if (final < 0) + return -1; + if (final > 0) + anymatched = 1; + } + } while((vp = yasm_vps_next(vp))); + + return anymatched; +} + +int +yasm_dir_helper_flag_or(void *obj, yasm_valparam *vp, unsigned long line, + void *d, uintptr_t flag) +{ + unsigned long *flags = (unsigned long *)d; + *flags |= flag; + return 0; +} + +int +yasm_dir_helper_flag_and(void *obj, yasm_valparam *vp, unsigned long line, + void *d, uintptr_t flag) +{ + unsigned long *flags = (unsigned long *)d; + *flags &= ~flag; + return 0; +} + +int +yasm_dir_helper_flag_set(void *obj, yasm_valparam *vp, unsigned long line, + void *d, uintptr_t flag) +{ + unsigned long *flags = (unsigned long *)d; + *flags = flag; + return 0; +} + +int +yasm_dir_helper_expr(void *obj, yasm_valparam *vp, unsigned long line, + void *data, uintptr_t arg) +{ + yasm_object *object = (yasm_object *)obj; + yasm_expr **expr = (yasm_expr **)data; + + if (*expr) + yasm_expr_destroy(*expr); + if (!(*expr = yasm_vp_expr(vp, object->symtab, line))) { + yasm_error_set(YASM_ERROR_VALUE, N_("argument to `%s' is not an expression"), + vp->val); + return -1; + } + return 0; +} + +int +yasm_dir_helper_intn(void *obj, yasm_valparam *vp, unsigned long line, + void *data, uintptr_t arg) +{ + yasm_object *object = (yasm_object *)obj; + /*@only@*/ /*@null@*/ yasm_expr *e; + /*@dependent@*/ /*@null@*/ yasm_intnum *local; + yasm_intnum **intn = (yasm_intnum **)data; + + if (*intn) + yasm_intnum_destroy(*intn); + if (!(e = yasm_vp_expr(vp, object->symtab, line)) || + !(local = yasm_expr_get_intnum(&e, 0))) { + yasm_error_set(YASM_ERROR_NOT_CONSTANT, + N_("argument to `%s' is not an integer"), + vp->val); + if (e) + yasm_expr_destroy(e); + return -1; + } + *intn = yasm_intnum_copy(local); + yasm_expr_destroy(e); + return 0; +} + +int +yasm_dir_helper_string(void *obj, yasm_valparam *vp, unsigned long line, + void *data, uintptr_t arg) +{ + /*@dependent@*/ /*@null@*/ const char *local; + char **s = (char **)data; + + if (*s) + yasm_xfree(*s); + if (!(local = yasm_vp_string(vp))) { + yasm_error_set(YASM_ERROR_VALUE, + N_("argument to `%s' is not a string or identifier"), + vp->val); + return -1; + } + *s = yasm__xstrdup(local); + return 0; +} + +int +yasm_dir_helper_valparam_warn(void *obj, yasm_valparam *vp, + unsigned long line, void *data) +{ + const char *s; + + if (vp->val) { + yasm_warn_set(YASM_WARN_GENERAL, N_("Unrecognized qualifier `%s'"), + vp->val); + return 0; + } + + if ((s = yasm_vp_id(vp))) + yasm_warn_set(YASM_WARN_GENERAL, N_("Unrecognized qualifier `%s'"), s); + else if (vp->type == YASM_PARAM_STRING) + yasm_warn_set(YASM_WARN_GENERAL, N_("Unrecognized string qualifier")); + else + yasm_warn_set(YASM_WARN_GENERAL, N_("Unrecognized numeric qualifier")); + + return 0; +} diff --git a/contrib/tools/yasm/libyasm/valparam.h b/contrib/tools/yasm/libyasm/valparam.h index d7343d4955..0167558540 100644 --- a/contrib/tools/yasm/libyasm/valparam.h +++ b/contrib/tools/yasm/libyasm/valparam.h @@ -1,408 +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 +/** + * \file libyasm/valparam.h + * \brief YASM value/parameter interface. + * + * \license + * Copyright (C) 2001-2007 Peter Johnson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * \endlicense + */ +#ifndef YASM_VALPARAM_H +#define YASM_VALPARAM_H + +#ifndef YASM_LIB_DECL +#define YASM_LIB_DECL +#endif + +/** Value/parameter pair. \internal */ +struct yasm_valparam { + /*@reldef@*/ STAILQ_ENTRY(yasm_valparam) link; /**< Next pair in list */ + /*@owned@*/ /*@null@*/ char *val; /**< Value */ + + /** Parameter type. */ + enum yasm_param_type { + YASM_PARAM_ID, /**< Identifier */ + YASM_PARAM_STRING, /**< String */ + YASM_PARAM_EXPR /**< Expression */ + } type; /**< Parameter type */ + + /** Parameter value. */ + union yasm_param { + /*@owned@*/ char *id; /**< Identifier */ + /*@owned@*/ char *str; /**< String */ + /*@owned@*/ yasm_expr *e; /**< Expression */ + } param; /**< Parameter */ + + /** Prefix character that indicates a raw identifier. When + * yasm_vp_string() is called on a #YASM_PARAM_ID, all characters are + * returned. When yasm_vp_id() is called on a #YASM_PARAM_ID, if the + * identifier begins with this character, this character is stripped + * from the returned value. + */ + char id_prefix; +}; + +/** Linked list of value/parameter pairs. \internal */ +/*@reldef@*/ STAILQ_HEAD(yasm_valparamhead, yasm_valparam); + +/** Directive list entry structure. */ +struct yasm_directive { + /** Directive name. GAS directives should include the ".", NASM + * directives should just be the raw name (not including the []). + * NULL entry required to terminate list of directives. + */ + /*@null@*/ const char *name; + + const char *parser; /**< Parser keyword */ + + /** Handler callback function for the directive. + * \param object object + * \param valparams value/parameters + * \param objext_valparams object format-specific value/parameters + * \param line virtual line (from yasm_linemap) + */ + void (*handler) (yasm_object *object, yasm_valparamhead *valparams, + yasm_valparamhead *objext_valparams, unsigned long line); + + /** Flags for pre-handler parameter checking. */ + enum yasm_directive_flags { + YASM_DIR_ANY = 0, /**< Any valparams accepted */ + YASM_DIR_ARG_REQUIRED = 1, /**< Require at least 1 valparam */ + YASM_DIR_ID_REQUIRED = 2 /**< First valparam must be ID */ + } flags; +}; + +/** Call a directive. Performs any valparam checks asked for by the + * directive prior to call. Note that for a variety of reasons, a directive + * can generate an error. + * \param directive directive + * \param object object + * \param valparams value/parameters + * \param objext_valparams object format-specific value/parameters + * \param line virtual line (from yasm_linemap) + */ +YASM_LIB_DECL +void yasm_call_directive(const yasm_directive *directive, yasm_object *object, + yasm_valparamhead *valparams, + yasm_valparamhead *objext_valparams, + unsigned long line); + +/** Create a new valparam with identifier parameter. + * \param v value + * \param p parameter + * \param id_prefix identifier prefix for raw identifiers + * \return Newly allocated valparam. + */ +YASM_LIB_DECL +yasm_valparam *yasm_vp_create_id(/*@keep@*/ char *v, /*@keep@*/ char *p, + int id_prefix); + +/** Create a new valparam with string parameter. + * \param v value + * \param p parameter + * \return Newly allocated valparam. + */ +YASM_LIB_DECL +yasm_valparam *yasm_vp_create_string(/*@keep@*/ char *v, /*@keep@*/ char *p); + +/** Create a new valparam with expression parameter. + * \param v value + * \param p parameter + * \return Newly allocated valparam. + */ +YASM_LIB_DECL +yasm_valparam *yasm_vp_create_expr(/*@keep@*/ char *v, + /*@keep@*/ yasm_expr *p); + +/** Get a valparam parameter as an expr. If the parameter is an identifier, + * it's treated as a symbol (yasm_symtab_use() is called to convert it). + * \param vp valparam + * \param symtab symbol table + * \param line virtual line + * \return Expression, or NULL if vp is NULL or the parameter cannot be + * converted to an expression. + */ +YASM_LIB_DECL +/*@null@*/ /*@only@*/ yasm_expr *yasm_vp_expr + (const yasm_valparam *vp, yasm_symtab *symtab, unsigned long line); + +/** Get a valparam parameter as a string. If the parameter is an identifier, + * it's treated as a string. + * \param vp valparam + * \return String, or NULL if vp is NULL or the parameter cannot be realized + * as a string. + */ +YASM_LIB_DECL +/*@null@*/ /*@dependent@*/ const char *yasm_vp_string(const yasm_valparam *vp); + +/** Get a valparam parameter as an identifier. + * \param vp valparam + * \return Identifier (string), or NULL if vp is NULL or the parameter is not + * an identifier. + */ +YASM_LIB_DECL +/*@null@*/ /*@dependent@*/ const char *yasm_vp_id(const yasm_valparam *vp); + +/** Create a new linked list of valparams. + * \return Newly allocated valparam list. + */ +YASM_LIB_DECL +yasm_valparamhead *yasm_vps_create(void); + +/** Destroy a list of valparams (created with yasm_vps_create). + * \param headp list of valparams + */ +YASM_LIB_DECL +void yasm_vps_destroy(yasm_valparamhead *headp); + +/** Initialize linked list of valparams. + * \param headp linked list + */ +void yasm_vps_initialize(/*@out@*/ yasm_valparamhead *headp); +#ifndef YASM_DOXYGEN +#define yasm_vps_initialize(headp) STAILQ_INIT(headp) +#endif + +/** Destroy (free allocated memory for) linked list of valparams (created with + * yasm_vps_initialize). + * \warning Deletes val/params. + * \param headp linked list + */ +YASM_LIB_DECL +void yasm_vps_delete(yasm_valparamhead *headp); + +/** Append valparam to tail of linked list. + * \param headp linked list + * \param vp valparam + */ +void yasm_vps_append(yasm_valparamhead *headp, /*@keep@*/ yasm_valparam *vp); +#ifndef YASM_DOXYGEN +#define yasm_vps_append(headp, vp) do { \ + if (vp) \ + STAILQ_INSERT_TAIL(headp, vp, link); \ + } while(0) +#endif + +/** Get first valparam in linked list. + * \param headp linked list + * \return First valparam in linked list. + */ +/*@null@*/ /*@dependent@*/ yasm_valparam *yasm_vps_first + (yasm_valparamhead *headp); +#ifndef YASM_DOXYGEN +#define yasm_vps_first(headp) STAILQ_FIRST(headp) +#endif + +/** Get next valparam in linked list. + * \param cur previous valparam in linked list + * \return Next valparam in linked list. + */ +/*@null@*/ /*@dependent@*/ yasm_valparam *yasm_vps_next(yasm_valparam *cur); +#ifndef YASM_DOXYGEN +#define yasm_vps_next(cur) STAILQ_NEXT(cur, link) +#endif + +/** Iterate through linked list of valparams. + * \internal + * \param iter iterator variable + * \param headp linked list + */ +#ifndef YASM_DOXYGEN +#define yasm_vps_foreach(iter, headp) STAILQ_FOREACH(iter, headp, link) +#endif + +/** Print linked list of valparams. For debugging purposes. + * \param f file + * \param headp linked list + */ +YASM_LIB_DECL +void yasm_vps_print(/*@null@*/ const yasm_valparamhead *headp, FILE *f); + +/** Directive valparam parse helper structure. */ +typedef struct yasm_dir_help { + /** Value portion of val=param (if needsparam=1), or standalone identifier + * (if needsparam=0). + */ + const char *name; + + /** 1 if value requires parameter, 0 if it must not have a parameter. */ + int needsparam; + + /** Helper callback function if name and parameter existence match. + * \param obj obj passed into yasm_dir_helper() + * \param vp value/parameter + * \param line line passed into yasm_dir_helper() + * \param data data passed into yasm_dir_helper() plus + #yasm_dir_help.off offset + * \param arg #yasm_dir_help.arg argument + * \return -1 on error, 0 otherwise. + */ + int (*helper) (void *obj, yasm_valparam *vp, unsigned long line, + void *data, uintptr_t arg); + + /** Offset added to data pointer passed into yasm_dir_helper() before + * data pointer is given to #yasm_dir_help.helper(). This is so that + * a structure can be passed into yasm_dir_helper() and this can be an + * offsetof() to point the helper function to a specific structure + * member. + */ + size_t off; + + /** Argument to pass in as the arg parameter to #yasm_dir_help.helper(). + */ + uintptr_t arg; +} yasm_dir_help; + +/** Help parse a list of directive value/parameters. Takes an array of + * #yasm_dir_help structures and tries to match val=param (or just val) + * against the passed value/parameters. When no match is found in the + * array of help structures, calls helper_valparam. + * \param obj object to be passed to yasm_dir_help.helper() or + * helper_valparam() callback + * \param vp_first first value/parameter to examine + * \param line virtual line number; passed down to helper callback + * \param help array of #yasm_dir_help structures + * \param nhelp number of array elements + * \param data base data pointer; if a match is found, + * the respective #yasm_dir_help.off is added to this + * prior to it being passed to the helper callback + * \param helper_valparam catch-all callback; should return -1 on error, + * 0 if not matched, 1 if matched. + * \return -1 on error, 1 if any arguments matched (including via + * catch-all callback), 0 if no match. + */ +YASM_LIB_DECL +int yasm_dir_helper(void *obj, yasm_valparam *vp_first, unsigned long line, + const yasm_dir_help *help, size_t nhelp, void *data, + int (*helper_valparam) (void *object, + yasm_valparam *vp, + unsigned long line, + void *data)); + +/** Standard helper for yasm_dir_helper() that simply sets a flag when called. + * It does not look at the vp; rather, it uses the value of the arg parameter, + * and stores an unsigned long value to data. + * \param obj unused + * \param vp unused + * \param line unused + * \param data pointer to an unsigned long + * \param arg flag to set + * \return 0 + */ +YASM_LIB_DECL +int yasm_dir_helper_flag_set(void *obj, yasm_valparam *vp, unsigned long line, + void *data, uintptr_t arg); + +/** Standard helper for yasm_dir_helper() that simply ORs a flag when called. + * It does not look at the vp; rather, it uses the value of the arg parameter, + * and ORs it with the unsigned long value in data. + * \param obj unused + * \param vp unused + * \param line unused + * \param data pointer to an unsigned long + * \param arg flag to OR + * \return 0 + */ +YASM_LIB_DECL +int yasm_dir_helper_flag_or(void *obj, yasm_valparam *vp, unsigned long line, + void *data, uintptr_t arg); + +/** Standard helper for yasm_dir_helper() that simply ANDs a flag when called. + * It does not look at the vp; rather, it uses the value of the arg parameter, + * and ANDs its inverse (~) with the unsigned long value in data. + * \param obj unused + * \param vp unused + * \param line unused + * \param data pointer to an unsigned long + * \param arg flag to AND + * \return 0 + */ +YASM_LIB_DECL +int yasm_dir_helper_flag_and(void *obj, yasm_valparam *vp, unsigned long line, + void *data, uintptr_t arg); + +/** Standard helper for yasm_dir_helper() that parses an expr parameter. + * The #yasm_dir_help structure that uses this function should have + * needsparam=1. The obj parameter to yasm_dir_helper() when this helper + * is used MUST point to a #yasm_object. In addition, the data parameter + * that is ultimately passed to this function (e.g. yasm_dir_helper() data + * parameter plus #yasm_dir_help.off) must point to a #yasm_expr * + * initialized to NULL. + * \param obj object; must be #yasm_object + * \param vp valparam + * \param line virtual line number + * \param data pointer to #yasm_expr * + * \param arg unused argument + * \return -1 on error, 0 otherwise. + */ +YASM_LIB_DECL +int yasm_dir_helper_expr(void *obj, yasm_valparam *vp, unsigned long line, + void *data, uintptr_t arg); + +/** Standard helper for yasm_dir_helper() that parses an intnum parameter. + * The #yasm_dir_help structure that uses this function should have + * needsparam=1. The obj parameter to yasm_dir_helper() when this helper + * is used MUST point to a #yasm_object. In addition, the data parameter + * that is ultimately passed to this function (e.g. yasm_dir_helper() data + * parameter plus #yasm_dir_help.off) must point to a #yasm_intnum * + * initialized to NULL. + * \param obj object; must be #yasm_object + * \param vp valparam + * \param line virtual line number + * \param data pointer to #yasm_intnum * + * \param arg unused argument + * \return -1 on error, 0 otherwise. + */ +YASM_LIB_DECL +int yasm_dir_helper_intn(void *obj, yasm_valparam *vp, unsigned long line, + void *data, uintptr_t arg); + +/** Standard helper for yasm_dir_helper() that parses an string (or + * standalone identifier) parameter. + * The #yasm_dir_help structure that uses this function should have + * needsparam=1. The data parameter that is ultimately passed to this + * function (e.g. yasm_dir_helper() data parameter plus #yasm_dir_help.off) + * must point to a char * initialized to NULL. + * \param obj unused + * \param vp valparam + * \param line unused + * \param data pointer to char * + * \param arg unused + * \return -1 on error, 0 otherwise. + */ +YASM_LIB_DECL +int yasm_dir_helper_string(void *obj, yasm_valparam *vp, unsigned long line, + void *data, uintptr_t arg); + +/** Standard catch-all callback fro yasm_dir_helper(). Generates standard + * warning for all valparams. + * \param obj unused + * \param vp valparam + * \param line unused + * \param data unused + * \return 0 + */ +YASM_LIB_DECL +int yasm_dir_helper_valparam_warn(void *obj, yasm_valparam *vp, + unsigned long line, void *data); +#endif diff --git a/contrib/tools/yasm/libyasm/value.c b/contrib/tools/yasm/libyasm/value.c index 3ab73c1cec..714b80f0c4 100644 --- a/contrib/tools/yasm/libyasm/value.c +++ b/contrib/tools/yasm/libyasm/value.c @@ -1,771 +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, ""); - } -} +/* + * Value handling + * + * Copyright (C) 2006-2007 Peter Johnson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include "util.h" + +#include "libyasm-stdint.h" +#include "coretype.h" +#include "bitvect.h" + +#include "errwarn.h" +#include "intnum.h" +#include "floatnum.h" +#include "expr.h" +#include "value.h" +#include "symrec.h" + +#include "bytecode.h" +#include "section.h" + +#include "arch.h" + + +void +yasm_value_initialize(/*@out@*/ yasm_value *value, + /*@null@*/ /*@kept@*/ yasm_expr *e, unsigned int size) +{ + value->abs = e; + value->rel = NULL; + value->wrt = NULL; + value->seg_of = 0; + value->rshift = 0; + value->curpos_rel = 0; + value->ip_rel = 0; + value->jump_target = 0; + value->section_rel = 0; + value->no_warn = 0; + value->sign = 0; + value->size = size; +} + +void +yasm_value_init_sym(/*@out@*/ yasm_value *value, /*@null@*/ yasm_symrec *sym, + unsigned int size) +{ + value->abs = NULL; + value->rel = sym; + value->wrt = NULL; + value->seg_of = 0; + value->rshift = 0; + value->curpos_rel = 0; + value->ip_rel = 0; + value->jump_target = 0; + value->section_rel = 0; + value->no_warn = 0; + value->sign = 0; + value->size = size; +} + +void +yasm_value_init_copy(yasm_value *value, const yasm_value *orig) +{ + value->abs = orig->abs ? yasm_expr_copy(orig->abs) : NULL; + value->rel = orig->rel; + value->wrt = orig->wrt; + value->seg_of = orig->seg_of; + value->rshift = orig->rshift; + value->curpos_rel = orig->curpos_rel; + value->ip_rel = orig->ip_rel; + value->jump_target = orig->jump_target; + value->section_rel = orig->section_rel; + value->no_warn = orig->no_warn; + value->sign = orig->sign; + value->size = orig->size; +} + +void +yasm_value_delete(yasm_value *value) +{ + if (value->abs) + yasm_expr_destroy(value->abs); + value->abs = NULL; + value->rel = NULL; +} + +void +yasm_value_set_curpos_rel(yasm_value *value, yasm_bytecode *bc, + unsigned int ip_rel) +{ + value->curpos_rel = 1; + value->ip_rel = ip_rel; + /* In order for us to correctly output curpos-relative values, we must + * have a relative portion of the value. If one doesn't exist, point + * to a custom absolute symbol. + */ + if (!value->rel) { + yasm_object *object = yasm_section_get_object(yasm_bc_get_section(bc)); + value->rel = yasm_symtab_abs_sym(object->symtab); + } +} + +static int +value_finalize_scan(yasm_value *value, yasm_expr *e, + /*@null@*/ yasm_bytecode *expr_precbc, int ssym_not_ok) +{ + int i; + /*@dependent@*/ yasm_section *sect; + /*@dependent@*/ /*@null@*/ yasm_bytecode *precbc; + + unsigned long shamt; /* for SHR */ + + /* Yes, this has a maximum upper bound on 32 terms, based on an + * "insane number of terms" (and ease of implementation) WAG. + * The right way to do this would be a stack-based alloca, but that's + * not ISO C. We really don't want to malloc here as this function is + * hit a lot! + * + * This is a bitmask to keep things small, as this is a recursive + * routine and we don't want to eat up stack space. + */ + unsigned long used; /* for ADD */ + + /* Thanks to this running after a simplify, we don't need to iterate + * down through IDENTs or handle SUB. + * + * We scan for a single symrec, gathering info along the way. After + * we've found the symrec, we keep scanning but error if we find + * another one. We pull out the single symrec and any legal operations + * performed on it. + * + * Also, if we find a float anywhere, we don't allow mixing of a single + * symrec with it. + */ + switch (e->op) { + case YASM_EXPR_ADD: + /* Okay for single symrec anywhere in expr. + * Check for single symrec anywhere. + * Handle symrec-symrec by checking for (-1*symrec) + * and symrec term pairs (where both symrecs are in the same + * segment). + */ + if (e->numterms > 32) + yasm__fatal(N_("expression on line %d has too many add terms;" + " internal limit of 32"), e->line); + + used = 0; + + for (i=0; i<e->numterms; i++) { + int j; + yasm_expr *sube; + yasm_intnum *intn; + yasm_symrec *sym; + /*@dependent@*/ yasm_section *sect2; + /*@dependent@*/ /*@null@*/ yasm_bytecode *precbc2; + + /* First look for an (-1*symrec) term */ + if (e->terms[i].type != YASM_EXPR_EXPR) + continue; + sube = e->terms[i].data.expn; + + if (sube->op != YASM_EXPR_MUL || sube->numterms != 2) { + /* recurse instead */ + if (value_finalize_scan(value, sube, expr_precbc, + ssym_not_ok)) + return 1; + continue; + } + + if (sube->terms[0].type == YASM_EXPR_INT && + sube->terms[1].type == YASM_EXPR_SYM) { + intn = sube->terms[0].data.intn; + sym = sube->terms[1].data.sym; + } else if (sube->terms[0].type == YASM_EXPR_SYM && + sube->terms[1].type == YASM_EXPR_INT) { + sym = sube->terms[0].data.sym; + intn = sube->terms[1].data.intn; + } else { + if (value_finalize_scan(value, sube, expr_precbc, + ssym_not_ok)) + return 1; + continue; + } + + if (!yasm_intnum_is_neg1(intn)) { + if (value_finalize_scan(value, sube, expr_precbc, + ssym_not_ok)) + return 1; + continue; + } + + /* Look for the same symrec term; even if both are external, + * they should cancel out. + */ + for (j=0; j<e->numterms; j++) { + if (e->terms[j].type == YASM_EXPR_SYM + && e->terms[j].data.sym == sym + && (used & (1<<j)) == 0) { + /* Mark as used */ + used |= 1<<j; + + /* Replace both symrec portions with 0 */ + yasm_expr_destroy(sube); + e->terms[i].type = YASM_EXPR_INT; + e->terms[i].data.intn = yasm_intnum_create_uint(0); + e->terms[j].type = YASM_EXPR_INT; + e->terms[j].data.intn = yasm_intnum_create_uint(0); + + break; /* stop looking */ + } + } + if (j != e->numterms) + continue; + + if (!yasm_symrec_get_label(sym, &precbc)) { + if (value_finalize_scan(value, sube, expr_precbc, + ssym_not_ok)) + return 1; + continue; + } + sect2 = yasm_bc_get_section(precbc); + + /* Now look for a unused symrec term in the same segment */ + for (j=0; j<e->numterms; j++) { + if (e->terms[j].type == YASM_EXPR_SYM + && yasm_symrec_get_label(e->terms[j].data.sym, + &precbc2) + && (sect = yasm_bc_get_section(precbc2)) + && sect == sect2 + && (used & (1<<j)) == 0) { + /* Mark as used */ + used |= 1<<j; + break; /* stop looking */ + } + } + + /* We didn't match in the same segment. If the + * -1*symrec is actually -1*curpos, we can match + * unused symrec terms in other segments and generate + * a curpos-relative reloc. + * + * Similarly, handle -1*symrec in other segment via the + * following transformation: + * other-this = (other-.)+(.-this) + * We can only do this transformation if "this" is in + * this expr's segment. + * + * Don't do this if we've already become curpos-relative. + * The unmatched symrec will be caught below. + */ + if (j == e->numterms && !value->curpos_rel + && (yasm_symrec_is_curpos(sym) + || (expr_precbc + && sect2 == yasm_bc_get_section(expr_precbc)))) { + for (j=0; j<e->numterms; j++) { + if (e->terms[j].type == YASM_EXPR_SYM + && !yasm_symrec_get_equ(e->terms[j].data.sym) + && !yasm_symrec_is_special(e->terms[j].data.sym) + && (used & (1<<j)) == 0) { + /* Mark as used */ + used |= 1<<j; + /* Mark value as curpos-relative */ + if (value->rel || ssym_not_ok) + return 1; + value->rel = e->terms[j].data.sym; + value->curpos_rel = 1; + if (yasm_symrec_is_curpos(sym)) { + /* Replace both symrec portions with 0 */ + yasm_expr_destroy(sube); + e->terms[i].type = YASM_EXPR_INT; + e->terms[i].data.intn = + yasm_intnum_create_uint(0); + e->terms[j].type = YASM_EXPR_INT; + e->terms[j].data.intn = + yasm_intnum_create_uint(0); + } else { + /* Replace positive portion with curpos */ + yasm_object *object = + yasm_section_get_object(sect2); + yasm_symtab *symtab = object->symtab; + e->terms[j].data.sym = + yasm_symtab_define_curpos + (symtab, ".", expr_precbc, e->line); + } + break; /* stop looking */ + } + } + } + + + if (j == e->numterms) + return 1; /* We didn't find a match! */ + } + + /* Look for unmatched symrecs. If we've already found one or + * we don't WANT to find one, error out. + */ + for (i=0; i<e->numterms; i++) { + if (e->terms[i].type == YASM_EXPR_SYM + && (used & (1<<i)) == 0) { + if (value->rel || ssym_not_ok) + return 1; + value->rel = e->terms[i].data.sym; + /* and replace with 0 */ + e->terms[i].type = YASM_EXPR_INT; + e->terms[i].data.intn = yasm_intnum_create_uint(0); + } + } + break; + case YASM_EXPR_SHR: + /* Okay for single symrec in LHS and constant on RHS. + * Single symrecs are not okay on RHS. + * If RHS is non-constant, don't allow single symrec on LHS. + * XXX: should rshift be an expr instead?? + */ + + /* Check for single sym on LHS */ + if (e->terms[0].type != YASM_EXPR_SYM) + break; + + /* If we already have a sym, we can't take another one */ + if (value->rel || ssym_not_ok) + return 1; + + /* RHS must be a positive integer */ + if (e->terms[1].type != YASM_EXPR_INT) + return 1; /* can't shift sym by non-constant integer */ + shamt = yasm_intnum_get_uint(e->terms[1].data.intn); + if ((shamt + value->rshift) > YASM_VALUE_RSHIFT_MAX) + return 1; /* total shift would be too large */ + + /* Update value */ + value->rshift += shamt; + value->rel = e->terms[0].data.sym; + + /* Replace symbol with 0 */ + e->terms[0].type = YASM_EXPR_INT; + e->terms[0].data.intn = yasm_intnum_create_uint(0); + + /* Just leave SHR in place */ + break; + case YASM_EXPR_SEG: + /* Okay for single symrec (can only be done once). + * Not okay for anything BUT a single symrec as an immediate + * child. + */ + if (e->terms[0].type != YASM_EXPR_SYM) + return 1; + + if (value->seg_of) + return 1; /* multiple SEG not legal */ + value->seg_of = 1; + + if (value->rel || ssym_not_ok) + return 1; /* got a relative portion somewhere else? */ + value->rel = e->terms[0].data.sym; + + /* replace with ident'ed 0 */ + e->op = YASM_EXPR_IDENT; + e->terms[0].type = YASM_EXPR_INT; + e->terms[0].data.intn = yasm_intnum_create_uint(0); + break; + case YASM_EXPR_WRT: + /* Okay for single symrec in LHS and either a register or single + * symrec (as an immediate child) on RHS. + * If a single symrec on RHS, can only be done once. + * WRT reg is left in expr for arch to look at. + */ + + /* Handle RHS */ + switch (e->terms[1].type) { + case YASM_EXPR_SYM: + if (value->wrt) + return 1; + value->wrt = e->terms[1].data.sym; + /* and drop the WRT portion */ + e->op = YASM_EXPR_IDENT; + e->numterms = 1; + break; + case YASM_EXPR_REG: + break; /* ignore */ + default: + return 1; + } + + /* Handle LHS */ + switch (e->terms[0].type) { + case YASM_EXPR_SYM: + if (value->rel || ssym_not_ok) + return 1; + value->rel = e->terms[0].data.sym; + /* and replace with 0 */ + e->terms[0].type = YASM_EXPR_INT; + e->terms[0].data.intn = yasm_intnum_create_uint(0); + break; + case YASM_EXPR_EXPR: + /* recurse */ + return value_finalize_scan(value, e->terms[0].data.expn, + expr_precbc, ssym_not_ok); + default: + break; /* ignore */ + } + + break; + default: + /* Single symrec not allowed anywhere */ + for (i=0; i<e->numterms; i++) { + switch (e->terms[i].type) { + case YASM_EXPR_SYM: + return 1; + case YASM_EXPR_EXPR: + /* recurse */ + return value_finalize_scan(value, + e->terms[i].data.expn, + expr_precbc, 1); + default: + break; + } + } + break; + } + + return 0; +} + +int +yasm_value_finalize_expr(yasm_value *value, yasm_expr *e, + yasm_bytecode *precbc, unsigned int size) +{ + if (!e) { + yasm_value_initialize(value, NULL, size); + return 0; + } + yasm_value_initialize(value, e, size); + return yasm_value_finalize(value, precbc); +} + +int +yasm_value_finalize(yasm_value *value, yasm_bytecode *precbc) +{ + if (!value->abs) + return 0; + + value->abs = yasm_expr__level_tree(value->abs, 1, 1, 0, 0, NULL, NULL); + + /* quit early if there was an issue in simplify() */ + if (yasm_error_occurred()) + return 1; + + /* Strip top-level AND masking to an all-1s mask the same size + * of the value size. This allows forced avoidance of overflow warnings. + */ + if (value->abs->op == YASM_EXPR_AND) { + int term; + + /* Calculate 1<<size - 1 value */ + yasm_intnum *mask = yasm_intnum_create_uint(1); + yasm_intnum *mask_tmp = yasm_intnum_create_uint(value->size); + yasm_intnum_calc(mask, YASM_EXPR_SHL, mask_tmp); + yasm_intnum_set_uint(mask_tmp, 1); + yasm_intnum_calc(mask, YASM_EXPR_SUB, mask_tmp); + yasm_intnum_destroy(mask_tmp); + + /* Walk terms and delete matching masks */ + for (term=value->abs->numterms-1; term>=0; term--) { + if (value->abs->terms[term].type == YASM_EXPR_INT && + yasm_intnum_compare(value->abs->terms[term].data.intn, + mask) == 0) { + /* Delete the intnum */ + yasm_intnum_destroy(value->abs->terms[term].data.intn); + + /* Slide everything to its right over by 1 */ + if (term != value->abs->numterms-1) /* if it wasn't last.. */ + memmove(&value->abs->terms[term], + &value->abs->terms[term+1], + (value->abs->numterms-1-term)* + sizeof(yasm_expr__item)); + + /* Update numterms */ + value->abs->numterms--; + + /* Indicate warnings have been disabled */ + value->no_warn = 1; + } + } + if (value->abs->numterms == 1) + value->abs->op = YASM_EXPR_IDENT; + yasm_intnum_destroy(mask); + } + + /* Handle trivial (IDENT) cases immediately */ + if (value->abs->op == YASM_EXPR_IDENT) { + switch (value->abs->terms[0].type) { + case YASM_EXPR_INT: + if (yasm_intnum_is_zero(value->abs->terms[0].data.intn)) { + yasm_expr_destroy(value->abs); + value->abs = NULL; + } + return 0; + case YASM_EXPR_REG: + case YASM_EXPR_FLOAT: + return 0; + case YASM_EXPR_SYM: + value->rel = value->abs->terms[0].data.sym; + yasm_expr_destroy(value->abs); + value->abs = NULL; + return 0; + case YASM_EXPR_EXPR: + /* Bring up lower values. */ + while (value->abs->op == YASM_EXPR_IDENT + && value->abs->terms[0].type == YASM_EXPR_EXPR) { + yasm_expr *sube = value->abs->terms[0].data.expn; + yasm_xfree(value->abs); + value->abs = sube; + } + break; + default: + yasm_internal_error(N_("unexpected expr term type")); + } + } + + if (value_finalize_scan(value, value->abs, precbc, 0)) + return 1; + + value->abs = yasm_expr__level_tree(value->abs, 1, 1, 0, 0, NULL, NULL); + + /* Simplify 0 in abs to NULL */ + if (value->abs->op == YASM_EXPR_IDENT + && value->abs->terms[0].type == YASM_EXPR_INT + && yasm_intnum_is_zero(value->abs->terms[0].data.intn)) { + yasm_expr_destroy(value->abs); + value->abs = NULL; + } + return 0; +} + +yasm_intnum * +yasm_value_get_intnum(yasm_value *value, yasm_bytecode *bc, int calc_bc_dist) +{ + /*@dependent@*/ /*@null@*/ yasm_intnum *intn = NULL; + /*@only@*/ yasm_intnum *outval; + int sym_local; + + if (value->abs) { + /* Handle integer expressions, if non-integer or too complex, return + * NULL. + */ + intn = yasm_expr_get_intnum(&value->abs, calc_bc_dist); + if (!intn) + return NULL; + } + + if (value->rel) { + /* If relative portion is not in bc section, return NULL. + * Otherwise get the relative portion's offset. + */ + /*@dependent@*/ yasm_bytecode *rel_prevbc; + unsigned long dist; + + if (!bc) + return NULL; /* Can't calculate relative value */ + + sym_local = yasm_symrec_get_label(value->rel, &rel_prevbc); + if (value->wrt || value->seg_of || value->section_rel || !sym_local) + return NULL; /* we can't handle SEG, WRT, or external symbols */ + if (rel_prevbc->section != bc->section) + return NULL; /* not in this section */ + if (!value->curpos_rel) + return NULL; /* not PC-relative */ + + /* Calculate value relative to current assembly position */ + dist = yasm_bc_next_offset(rel_prevbc); + if (dist < bc->offset) { + outval = yasm_intnum_create_uint(bc->offset - dist); + yasm_intnum_calc(outval, YASM_EXPR_NEG, NULL); + } else { + dist -= bc->offset; + outval = yasm_intnum_create_uint(dist); + } + + if (value->rshift > 0) { + /*@only@*/ yasm_intnum *shamt = + yasm_intnum_create_uint((unsigned long)value->rshift); + yasm_intnum_calc(outval, YASM_EXPR_SHR, shamt); + yasm_intnum_destroy(shamt); + } + /* Add in absolute portion */ + if (intn) + yasm_intnum_calc(outval, YASM_EXPR_ADD, intn); + return outval; + } + + if (intn) + return yasm_intnum_copy(intn); + + /* No absolute or relative portions: output 0 */ + return yasm_intnum_create_uint(0); +} + +int +yasm_value_output_basic(yasm_value *value, /*@out@*/ unsigned char *buf, + size_t destsize, yasm_bytecode *bc, int warn, + yasm_arch *arch) +{ + /*@dependent@*/ /*@null@*/ yasm_intnum *intn = NULL; + /*@only@*/ yasm_intnum *outval; + int sym_local; + int retval = 1; + unsigned int valsize = value->size; + + if (value->no_warn) + warn = 0; + + if (value->abs) { + /* Handle floating point expressions */ + if (!value->rel && value->abs->op == YASM_EXPR_IDENT + && value->abs->terms[0].type == YASM_EXPR_FLOAT) { + if (yasm_arch_floatnum_tobytes(arch, value->abs->terms[0].data.flt, + buf, destsize, valsize, 0, warn)) + return -1; + else + return 1; + } + + /* Check for complex float expressions */ + if (yasm_expr__contains(value->abs, YASM_EXPR_FLOAT)) { + yasm_error_set(YASM_ERROR_FLOATING_POINT, + N_("floating point expression too complex")); + return -1; + } + + /* Handle normal integer expressions */ + intn = yasm_expr_get_intnum(&value->abs, 1); + + if (!intn) { + /* Second try before erroring: yasm_expr_get_intnum doesn't handle + * SEG:OFF, so try simplifying out any to just the OFF portion, + * then getting the intnum again. + */ + yasm_expr *seg = yasm_expr_extract_deep_segoff(&value->abs); + if (seg) + yasm_expr_destroy(seg); + intn = yasm_expr_get_intnum(&value->abs, 1); + } + + if (!intn) { + /* Still don't have an integer! */ + yasm_error_set(YASM_ERROR_TOO_COMPLEX, + N_("expression too complex")); + return -1; + } + } + + /* Adjust warn for signed/unsigned integer warnings */ + if (warn != 0) + warn = value->sign ? -1 : 1; + + if (value->rel) { + /* If relative portion is not in bc section, don't try to handle it + * here. Otherwise get the relative portion's offset. + */ + /*@dependent@*/ yasm_bytecode *rel_prevbc; + unsigned long dist; + + sym_local = yasm_symrec_get_label(value->rel, &rel_prevbc); + if (value->wrt || value->seg_of || value->section_rel || !sym_local) + return 0; /* we can't handle SEG, WRT, or external symbols */ + if (rel_prevbc->section != bc->section) + return 0; /* not in this section */ + if (!value->curpos_rel) + return 0; /* not PC-relative */ + + /* Calculate value relative to current assembly position */ + dist = yasm_bc_next_offset(rel_prevbc); + if (dist < bc->offset) { + outval = yasm_intnum_create_uint(bc->offset - dist); + yasm_intnum_calc(outval, YASM_EXPR_NEG, NULL); + } else { + dist -= bc->offset; + outval = yasm_intnum_create_uint(dist); + } + + if (value->rshift > 0) { + /*@only@*/ yasm_intnum *shamt = + yasm_intnum_create_uint((unsigned long)value->rshift); + yasm_intnum_calc(outval, YASM_EXPR_SHR, shamt); + yasm_intnum_destroy(shamt); + } + /* Add in absolute portion */ + if (intn) + yasm_intnum_calc(outval, YASM_EXPR_ADD, intn); + /* Output! */ + if (yasm_arch_intnum_tobytes(arch, outval, buf, destsize, valsize, 0, + bc, warn)) + retval = -1; + yasm_intnum_destroy(outval); + return retval; + } + + if (value->seg_of || value->rshift || value->curpos_rel || value->ip_rel + || value->section_rel) + return 0; /* We can't handle this with just an absolute */ + + if (intn) { + /* Output just absolute portion */ + if (yasm_arch_intnum_tobytes(arch, intn, buf, destsize, valsize, 0, bc, + warn)) + retval = -1; + } else { + /* No absolute or relative portions: output 0 */ + outval = yasm_intnum_create_uint(0); + if (yasm_arch_intnum_tobytes(arch, outval, buf, destsize, valsize, 0, + bc, warn)) + retval = -1; + yasm_intnum_destroy(outval); + } + return retval; +} + +void +yasm_value_print(const yasm_value *value, FILE *f, int indent_level) +{ + fprintf(f, "%*s%u-bit, %ssigned", indent_level, "", value->size, + value->sign ? "" : "un"); + fprintf(f, "%*sAbsolute portion=", indent_level, ""); + yasm_expr_print(value->abs, f); + fprintf(f, "\n"); + if (value->rel) { + fprintf(f, "%*sRelative to=%s%s\n", indent_level, "", + value->seg_of ? "SEG " : "", + yasm_symrec_get_name(value->rel)); + if (value->wrt) + fprintf(f, "%*s(With respect to=%s)\n", indent_level, "", + yasm_symrec_get_name(value->wrt)); + if (value->rshift > 0) + fprintf(f, "%*s(Right shifted by=%u)\n", indent_level, "", + value->rshift); + if (value->curpos_rel) + fprintf(f, "%*s(Relative to current position)\n", indent_level, + ""); + if (value->ip_rel) + fprintf(f, "%*s(IP-relative)\n", indent_level, ""); + if (value->jump_target) + fprintf(f, "%*s(Jump target)\n", indent_level, ""); + if (value->section_rel) + fprintf(f, "%*s(Section-relative)\n", indent_level, ""); + if (value->no_warn) + fprintf(f, "%*s(Overflow warnings disabled)\n", indent_level, ""); + } +} diff --git a/contrib/tools/yasm/libyasm/value.h b/contrib/tools/yasm/libyasm/value.h index 4dc294bcc3..8582bf1add 100644 --- a/contrib/tools/yasm/libyasm/value.h +++ b/contrib/tools/yasm/libyasm/value.h @@ -1,172 +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 +/** + * \file libyasm/value.h + * \brief YASM value interface. + * + * \license + * Copyright (C) 2006-2007 Peter Johnson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * \endlicense + */ +#ifndef YASM_VALUE_H +#define YASM_VALUE_H + +#ifndef YASM_LIB_DECL +#define YASM_LIB_DECL +#endif + +/** Initialize a #yasm_value with just an expression. No processing is + * performed, the expression is simply stuck into value.abs and the other + * fields are initialized. Use yasm_expr_extract_value() to perform "smart" + * processing into a #yasm_value. This function is intended for use during + * parsing simply to ensure all fields of the value are initialized; after + * the parse is complete, yasm_value_extract() should be called to finalize + * the value. The value defaults to unsigned. + * \param value value to be initialized + * \param e expression (kept) + * \param size value size (in bits) + */ +YASM_LIB_DECL +void yasm_value_initialize(/*@out@*/ yasm_value *value, + /*@null@*/ /*@kept@*/ yasm_expr *e, + unsigned int size); + +/** Initialize a #yasm_value with just a symrec. No processing is performed, + * the symrec is simply stuck into value.rel and the other fields are + * initialized. + * \param value value to be initialized + * \param sym symrec + * \param size value size (in bits) + */ +YASM_LIB_DECL +void yasm_value_init_sym(/*@out@*/ yasm_value *value, + /*@null@*/ yasm_symrec *sym, unsigned int size); + +/** Initialize a #yasm_value as a copy of another yasm_value. Any expressions + * within orig are copied, so it's safe to delete the copy. + * \param value value (copy to create) + * \param orig original value + */ +YASM_LIB_DECL +void yasm_value_init_copy(yasm_value *value, const yasm_value *orig); + +/** Frees any memory inside value; does not free value itself. + * \param value value + */ +YASM_LIB_DECL +void yasm_value_delete(yasm_value *value); + +/** Set a value to be relative to the current assembly position rather than + * relative to the section start. + * \param value value + * \param bc bytecode containing value + * \param ip_rel if nonzero, indicates IP-relative data relocation, + * sometimes used to generate special relocations + * \note If value is just an absolute value, will get an absolute symrec to + * reference to (via bc's symbol table). + */ +YASM_LIB_DECL +void yasm_value_set_curpos_rel(yasm_value *value, yasm_bytecode *bc, + unsigned int ip_rel); + +/** Perform yasm_value_finalize_expr() on a value that already exists from + * being initialized with yasm_value_initialize(). + * \param value value + * \param precbc previous bytecode to bytecode containing value + * \return Nonzero if value could not be split. + */ +YASM_LIB_DECL +int yasm_value_finalize(yasm_value *value, /*@null@*/ yasm_bytecode *precbc); + +/** Break a #yasm_expr into a #yasm_value constituent parts. Extracts + * the relative portion of the value, SEG and WRT portions, and top-level + * right shift, if any. Places the remaining expr into the absolute + * portion of the value. Essentially a combination of yasm_value_initialize() + * and yasm_value_finalize(). First expands references to symrecs in + * absolute sections by expanding with the absolute section start plus the + * symrec offset within the absolute section. + * \param value value to store split portions into + * \param e expression input + * \param precbc previous bytecode to bytecode containing expression + * \param size value size (in bits) + * \return Nonzero if the expr could not be split into a value for some + * reason (e.g. the relative portion was not added, but multiplied, + * etc). + * \warning Do not use e after this call. Even if an error is returned, e + * is stored into value. + * \note This should only be called after the parse is complete. Calling + * before the parse is complete will usually result in an error return. + */ +YASM_LIB_DECL +int yasm_value_finalize_expr(/*@out@*/ yasm_value *value, + /*@null@*/ /*@kept@*/ yasm_expr *e, + /*@null@*/ yasm_bytecode *precbc, + unsigned int size); + +/** Get value if absolute or PC-relative section-local relative. Returns NULL + * otherwise. + * \param value value + * \param bc current bytecode (for PC-relative calculation); if + * NULL, NULL is returned for PC-relative values. + * \param calc_bc_dist if nonzero, calculates bytecode distances in absolute + * portion of value + * \note Adds in value.rel (correctly) if PC-relative and in the same section + * as bc (and there is no WRT or SEG). + * \return Intnum if can be resolved to integer value, otherwise NULL. + */ +YASM_LIB_DECL +/*@null@*/ /*@only@*/ yasm_intnum *yasm_value_get_intnum + (yasm_value *value, /*@null@*/ yasm_bytecode *bc, int calc_bc_dist); + +/** Output value if constant or PC-relative section-local. This should be + * used from objfmt yasm_output_value_func() functions. + * functions. + * \param value value + * \param buf buffer for byte representation + * \param destsize destination size (in bytes) + * \param bc current bytecode (usually passed into higher-level + * calling function) + * \param warn enables standard warnings: zero for none; + * nonzero for overflow/underflow floating point and + * integer warnings + * \param arch architecture + * \note Adds in value.rel (correctly) if PC-relative and in the same section + * as bc (and there is no WRT or SEG); if this is not the desired + * behavior, e.g. a reloc is needed in this case, don't use this + * function! + * \return 0 if no value output due to value needing relocation; + * 1 if value output; -1 if error. + */ +YASM_LIB_DECL +int yasm_value_output_basic + (yasm_value *value, /*@out@*/ unsigned char *buf, size_t destsize, + yasm_bytecode *bc, int warn, yasm_arch *arch); + +/** Print a value. For debugging purposes. + * \param value value + * \param indent_level indentation level + * \param f file + */ +YASM_LIB_DECL +void yasm_value_print(const yasm_value *value, FILE *f, int indent_level); + +#endif diff --git a/contrib/tools/yasm/libyasm/xmalloc.c b/contrib/tools/yasm/libyasm/xmalloc.c index 81b608c078..8931a42b30 100644 --- a/contrib/tools/yasm/libyasm/xmalloc.c +++ b/contrib/tools/yasm/libyasm/xmalloc.c @@ -1,114 +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); -} +/* + * Memory allocation routines with error checking. Idea from GNU libiberty. + * + * Copyright (C) 2001-2007 Peter Johnson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include "util.h" + +#include "coretype.h" +#include "errwarn.h" + + +#ifdef WITH_DMALLOC +#undef yasm_xmalloc +#undef yasm_xcalloc +#undef yasm_xrealloc +#undef yasm_xfree +#endif + +static /*@only@*/ /*@out@*/ void *def_xmalloc(size_t size); +static /*@only@*/ void *def_xcalloc(size_t nelem, size_t elsize); +static /*@only@*/ void *def_xrealloc + (/*@only@*/ /*@out@*/ /*@returned@*/ /*@null@*/ void *oldmem, size_t size) + /*@modifies oldmem@*/; +static void def_xfree(/*@only@*/ /*@out@*/ /*@null@*/ void *p) + /*@modifies p@*/; + +/* storage for global function pointers */ +YASM_LIB_DECL +/*@only@*/ /*@out@*/ void * (*yasm_xmalloc) (size_t size) = def_xmalloc; +YASM_LIB_DECL +/*@only@*/ void * (*yasm_xcalloc) (size_t nelem, size_t elsize) = def_xcalloc; +YASM_LIB_DECL +/*@only@*/ void * (*yasm_xrealloc) + (/*@only@*/ /*@out@*/ /*@returned@*/ /*@null@*/ void *oldmem, size_t size) + /*@modifies oldmem@*/ = def_xrealloc; +YASM_LIB_DECL +void (*yasm_xfree) (/*@only@*/ /*@out@*/ /*@null@*/ void *p) + /*@modifies p@*/ = def_xfree; + + +static void * +def_xmalloc(size_t size) +{ + void *newmem; + + if (size == 0) + size = 1; + newmem = malloc(size); + if (!newmem) + yasm__fatal(N_("out of memory")); + + return newmem; +} + +static void * +def_xcalloc(size_t nelem, size_t elsize) +{ + void *newmem; + + if (nelem == 0 || elsize == 0) + nelem = elsize = 1; + + newmem = calloc(nelem, elsize); + if (!newmem) + yasm__fatal(N_("out of memory")); + + return newmem; +} + +static void * +def_xrealloc(void *oldmem, size_t size) +{ + void *newmem; + + if (size == 0) + size = 1; + if (!oldmem) + newmem = malloc(size); + else + newmem = realloc(oldmem, size); + if (!newmem) + yasm__fatal(N_("out of memory")); + + return newmem; +} + +static void +def_xfree(void *p) +{ + if (!p) + return; + free(p); +} diff --git a/contrib/tools/yasm/libyasm/xstrdup.c b/contrib/tools/yasm/libyasm/xstrdup.c index b187704f0e..5932efcbdf 100644 --- a/contrib/tools/yasm/libyasm/xstrdup.c +++ b/contrib/tools/yasm/libyasm/xstrdup.c @@ -1,68 +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); -} +/* + * 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); +} |