mirror of https://github.com/yasm/yasm.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
273 lines
9.9 KiB
273 lines
9.9 KiB
/** |
|
* \file libyasm/insn.h |
|
* \brief YASM mnenomic instruction. |
|
* |
|
* \rcs |
|
* $Id$ |
|
* \endrcs |
|
* |
|
* \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
|
|
|