Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

270 lines (230 sloc) 10.123 kb
/**
* \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
Jump to Line
Something went wrong with that request. Please try again.