| /** |
| * \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 |