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