c0e157e3b2
One must build yasm (included in the yasm directory) before building GMP, if building on an x86_64 machine. Note: make test and make tune do not currently build.
255 lines
9.9 KiB
C
255 lines
9.9 KiB
C
/**
|
|
* \file libyasm/insn.h
|
|
* \brief YASM mnenomic instruction.
|
|
*
|
|
* \rcs
|
|
* $Id: insn.h 2028 2008-01-19 08:59:19Z peter $
|
|
* \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
|
|
|
|
/** 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;
|
|
};
|
|
|
|
/** 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)
|
|
*/
|
|
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_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_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_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_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.
|
|
*/
|
|
/*@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
|
|
*/
|
|
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
|
|
*/
|
|
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
|
|
*/
|
|
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
|
|
*/
|
|
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
|
|
*/
|
|
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
|
|
*/
|
|
void yasm_insn_finalize(yasm_insn *insn);
|
|
|
|
#endif
|