/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @author Alexander V. Astapchuk
*/
/**
* @file
* @brief Simple interface for generating processor instructions.
*
* The interface works for both IA32 and EM64T. By default, only IA32
* capabilities are presented. To enable EM64T feature, the _EM64T_ macro
* must be defined (and, of course, a proper library version to be used).
*
* The interface is based on the original ia32.h encoder interface,
* with some simplifications and add-ons - EM64T-specific, SSE and SSE2.
*
* The interface mostly intended for existing legacy code like LIL code
* generator. From the implementation point of view, it's just a wrapper
* around the EncoderBase functionality.
*/
#ifndef _VM_ENCODER_H_
#define _VM_ENCODER_H_
#include <limits.h>
#include "enc_base.h"
//#include "open/types.h"
#ifdef _EM64T_
// size of general-purpose value on the stack in bytes
#define GR_STACK_SIZE 8
// size of floating-point value on the stack in bytes
#define FR_STACK_SIZE 8
#if defined(WIN32) || defined(_WIN64)
// maximum number of GP registers for inputs
const int MAX_GR = 4;
// maximum number of FP registers for inputs
const int MAX_FR = 4;
// WIN64 reserves 4 words for shadow space
const int SHADOW = 4 * GR_STACK_SIZE;
#else
// maximum number of GP registers for inputs
const int MAX_GR = 6;
// maximum number of FP registers for inputs
const int MAX_FR = 8;
// Linux x64 doesn't reserve shadow space
const int SHADOW = 0;
#endif
#else
// size of general-purpose value on the stack in bytes
#define GR_STACK_SIZE 4
// size of general-purpose value on the stack in bytes
#define FR_STACK_SIZE 8
// maximum number of GP registers for inputs
const int MAX_GR = 0;
// maximum number of FP registers for inputs
const int MAX_FR = 0;
#endif
typedef enum Reg_No {
#ifdef _EM64T_
rax_reg = 0,rbx_reg, rcx_reg, rdx_reg,
rdi_reg, rsi_reg, rsp_reg, rbp_reg,
r8_reg, r9_reg, r10_reg, r11_reg,
r12_reg, r13_reg, r14_reg, r15_reg,
xmm0_reg, xmm1_reg, xmm2_reg, xmm3_reg,
xmm4_reg, xmm5_reg, xmm6_reg, xmm7_reg,
xmm8_reg, xmm9_reg, xmm10_reg, xmm11_reg,
xmm12_reg, xmm13_reg, xmm14_reg, xmm15_reg,
#else // !defined(_EM64T_)
eax_reg = 0,ebx_reg, ecx_reg, edx_reg,
edi_reg, esi_reg, esp_reg, ebp_reg,
xmm0_reg, xmm1_reg, xmm2_reg, xmm3_reg,
xmm4_reg, xmm5_reg, xmm6_reg, xmm7_reg,
fs_reg,
#endif
/** @brief Total number of registers.*/
n_reg
} Reg_No;
//
// instruction operand sizes: 8,16,32,64 bits
//
typedef enum Opnd_Size {
size_8 = 0,
size_16,
size_32,
size_64,
n_size,
#ifdef _EM64T_
size_platf = size_64
#else
size_platf = size_32
#endif
} Opnd_Size;
//
// opcodes for alu instructions
//
typedef enum ALU_Opcode {
add_opc = 0,or_opc, adc_opc, sbb_opc,
and_opc, sub_opc, xor_opc, cmp_opc,
n_alu
} ALU_Opcode;
//
// opcodes for shift instructions
//
typedef enum Shift_Opcode {
shld_opc, shrd_opc, shl_opc, shr_opc,
sar_opc, ror_opc, max_shift_opcode=6, n_shift = 6
} Shift_Opcode;
typedef enum ConditionCode {
Condition_O = 0,
Condition_NO = 1,
Condition_B = 2,
Condition_NAE = Condition_B,
Condition_C = Condition_B,
Condition_NB = 3,
Condition_AE = Condition_NB,
Condition_NC = Condition_NB,
Condition_Z = 4,
Condition_E = Condition_Z,
Condition_NZ = 5,
Condition_NE = Condition_NZ,
Condition_BE = 6,
Condition_NA = Condition_BE,
Condition_NBE = 7,
Condition_A = Condition_NBE,
Condition_S = 8,
Condition_NS = 9,
Condition_P = 10,
Condition_PE = Condition_P,
Condition_NP = 11,
Condition_PO = Condition_NP,
Condition_L = 12,
Condition_NGE = Condition_L,
Condition_NL = 13,
Condition_GE = Condition_NL,
Condition_LE = 14,
Condition_NG = Condition_LE,
Condition_NLE = 15,
Condition_G = Condition_NLE,
Condition_Count = 16
} ConditionCode;
//
// prefix code
//
typedef enum InstrPrefix {
no_prefix,
lock_prefix = 0xF0,
hint_branch_taken_prefix = 0x2E,
hint_branch_not_taken_prefix = 0x3E,
prefix_repne = 0xF2,
prefix_repnz = prefix_repne,
prefix_repe = 0xF3,
prefix_repz = prefix_repe,
prefix_rep = 0xF3,
prefix_cs = 0x2E,
prefix_ss = 0x36,
prefix_ds = 0x3E,
prefix_es = 0x26,
prefix_fs = 0x64,
prefix_gs = 0x65
} InstrPrefix;
//
// an instruction operand
//
class Opnd {
protected:
enum Tag { SignedImm, UnsignedImm, Reg, Mem, FP, XMM };
const Tag tag;
Opnd(Tag t): tag(t) {}
public:
void * operator new(size_t, void * mem) {
return mem;
}
void operator delete(void *) {}
void operator delete(void *, void *) {}
private:
// disallow copying
Opnd(const Opnd &): tag(Mem) { assert(false); }
Opnd& operator=(const Opnd &) { assert(false); return *this; }
};
typedef int I_32;
class Imm_Opnd: public Opnd {
protected:
union {
#ifdef _EM64T_
int64 value;
unsigned char bytes[8];
#else
I_32 value;
unsigned char bytes[4];
#endif
};
Opnd_Size size;
public:
Imm_Opnd(I_32 val, bool isSigned = true):
Opnd(isSigned ? SignedImm : UnsignedImm), value(val), size(size_32) {
if (isSigned) {
if (CHAR_MIN <= val && val <= CHAR_MAX) {
size = size_8;
} else if (SHRT_MIN <= val && val <= SHRT_MAX) {
size = size_16;
}
} else {
assert(val >= 0);
if (val <= UCHAR_MAX) {
size = size_8;
} else if (val <= USHRT_MAX) {
size = size_16;
}
}
}
Imm_Opnd(const Imm_Opnd& that): Opnd(that.tag), value(that.value), size(that.size) {};
#ifdef _EM64T_
Imm_Opnd(Opnd_Size sz, int64 val, bool isSigned = true):
Opnd(isSigned ? SignedImm : UnsignedImm), value(val), size(sz) {
#ifndef NDEBUG
switch (size) {
case size_8:
assert(val == (int64)(I_8)val);
break;
case size_16:
assert(val == (int64)(int16)val);
break;
case size_32:
assert(val == (int64)(I_32)val);
break;
case size_64:
break;
case n_size:
assert(false);
break;
}
#endif // NDEBUG
}
int64 get_value() const { return value; }
#else
Imm_Opnd(Opnd_Size sz, I_32 val, int isSigned = true):
Opnd(isSigned ? SignedImm : UnsignedImm), value(val), size(sz) {
#ifndef NDEBUG
switch (size) {
case size_8:
assert((I_32)val == (I_32)(I_8)val);
break;
case size_16:
assert((I_32)val == (I_32)(int16)val);
break;
case size_32:
break;
case size_64:
case n_size:
assert(false);
break;
}
#endif // NDEBUG
}
I_32 get_value() const { return value; }
#endif
Opnd_Size get_size() const { return size; }
bool is_signed() const { return tag == SignedImm; }
};
class RM_Opnd: public Opnd {
public:
bool is_reg() const { return tag != SignedImm && tag != UnsignedImm && tag != Mem; }
protected:
RM_Opnd(Tag t): Opnd(t) {}
private:
// disallow copying
RM_Opnd(const RM_Opnd &): Opnd(Reg) { assert(false); }
};
class R_Opnd: public RM_Opnd {
protected:
Reg_No _reg_no;
public:
R_Opnd(Reg_No r): RM_Opnd(Reg), _reg_no(r) {}
Reg_No reg_no() const { return _reg_no; }
private:
// disallow copying
R_Opnd(const R_Opnd &): RM_Opnd(Reg) { assert(false); }
};
//
// a memory operand with displacement
// Can also serve as a full memory operand with base,index, displacement and scale.
// Use n_reg to specify 'no register', say, for index.
class M_Opnd: public RM_Opnd {
protected:
Imm_Opnd m_disp;
Imm_Opnd m_scale;
R_Opnd m_index;
R_Opnd m_base;
public:
//M_Opnd(Opnd_Size sz): RM_Opnd(Mem, K_M, sz), m_disp(0), m_scale(0), m_index(n_reg), m_base(n_reg) {}
M_Opnd(I_32 disp):
RM_Opnd(Mem), m_disp(disp), m_scale(0), m_index(n_reg), m_base(n_reg) {}
M_Opnd(Reg_No rbase, I_32 rdisp):
RM_Opnd(Mem), m_disp(rdisp), m_scale(0), m_index(n_reg), m_base(rbase) {}
M_Opnd(I_32 disp, Reg_No rbase, Reg_No rindex, unsigned scale):
RM_Opnd(Mem), m_disp(disp), m_scale(scale), m_index(rindex), m_base(rbase) {}
M_Opnd(const M_Opnd & that) : RM_Opnd(Mem),
m_disp((int)that.m_disp.get_value()), m_scale((int)that.m_scale.get_value()),
m_index(that.m_index.reg_no()), m_base(that.m_base.reg_no())
{}
//
inline const R_Opnd & base(void) const { return m_base; }
inline const R_Opnd & index(void) const { return m_index; }
inline const Imm_Opnd & scale(void) const { return m_scale; }
inline const Imm_Opnd & disp(void) const { return m_disp; }
};
//
// a memory operand with base register and displacement
//
class M_Base_Opnd: public M_Opnd {
public:
M_Base_Opnd(Reg_No base, I_32 disp) : M_Opnd(disp, base, n_reg, 0) {}
private:
// disallow copying - but it leads to ICC errors #734 in encoder.inl
// M_Base_Opnd(const M_Base_Opnd &): M_Opnd(0) { assert(false); }
};
//
// a memory operand with base register, scaled index register
// and displacement.
//
class M_Index_Opnd : public M_Opnd {
public:
M_Index_Opnd(Reg_No base, Reg_No index, I_32 disp, unsigned scale):
M_Opnd(disp, base, index, scale) {}
private:
// disallow copying - but it leads to ICC errors #734 in encoder.inl
// M_Index_Opnd(const M_Index_Opnd &): M_Opnd(0) { assert(false); }
};
class XMM_Opnd : public Opnd {
protected:
unsigned m_idx;
public:
XMM_Opnd(unsigned _idx): Opnd(XMM), m_idx(_idx) {};
unsigned get_idx( void ) const { return m_idx; };
private:
// disallow copying
XMM_Opnd(const XMM_Opnd &): Opnd(XMM) { assert(false); }
};
//
// operand structures for ia32 registers
//
#ifdef _EM64T_
extern R_Opnd rax_opnd;
extern R_Opnd rcx_opnd;
extern R_Opnd rdx_opnd;
extern R_Opnd rbx_opnd;
extern R_Opnd rdi_opnd;
extern R_Opnd rsi_opnd;
extern R_Opnd rsp_opnd;
extern R_Opnd rbp_opnd;
extern R_Opnd r8_opnd;
extern R_Opnd r9_opnd;
extern R_Opnd r10_opnd;
extern R_Opnd r11_opnd;
extern R_Opnd r12_opnd;
extern R_Opnd r13_opnd;
extern R_Opnd r14_opnd;
extern R_Opnd r15_opnd;
extern XMM_Opnd xmm8_opnd;
extern XMM_Opnd xmm9_opnd;
extern XMM_Opnd xmm10_opnd;
extern XMM_Opnd xmm11_opnd;
extern XMM_Opnd xmm12_opnd;
extern XMM_Opnd xmm13_opnd;
extern XMM_Opnd xmm14_opnd;
extern XMM_Opnd xmm15_opnd;
#else
extern R_Opnd eax_opnd;
extern R_Opnd ecx_opnd;
extern R_Opnd edx_opnd;
extern R_Opnd ebx_opnd;
extern R_Opnd esp_opnd;
extern R_Opnd ebp_opnd;
extern R_Opnd esi_opnd;
extern R_Opnd edi_opnd;
#endif // _EM64T_
extern XMM_Opnd xmm0_opnd;
extern XMM_Opnd xmm1_opnd;
extern XMM_Opnd xmm2_opnd;
extern XMM_Opnd xmm3_opnd;
extern XMM_Opnd xmm4_opnd;
extern XMM_Opnd xmm5_opnd;
extern XMM_Opnd xmm6_opnd;
extern XMM_Opnd xmm7_opnd;
#ifdef NO_ENCODER_INLINE
#define ENCODER_DECLARE_EXPORT
#else
#define ENCODER_DECLARE_EXPORT inline
#include "encoder.inl"
#endif
// prefix
ENCODER_DECLARE_EXPORT char * prefix(char * stream, InstrPrefix p);
// stack push and pop instructions
ENCODER_DECLARE_EXPORT char * push(char * stream, const RM_Opnd & rm, Opnd_Size sz = size_platf);
ENCODER_DECLARE_EXPORT char * push(char * stream, const Imm_Opnd & imm);
ENCODER_DECLARE_EXPORT char * pop(char * stream, const RM_Opnd & rm, Opnd_Size sz = size_platf);
// cmpxchg or xchg
ENCODER_DECLARE_EXPORT char * cmpxchg(char * stream, const RM_Opnd & rm, const R_Opnd & r, Opnd_Size sz = size_platf);
ENCODER_DECLARE_EXPORT char * xchg(char * stream, const RM_Opnd & rm, const R_Opnd & r, Opnd_Size sz = size_platf);
// inc(rement), dec(rement), not, neg(ate) instructions
ENCODER_DECLARE_EXPORT char * inc(char * stream, const RM_Opnd & rm, Opnd_Size sz = size_platf);
ENCODER_DECLARE_EXPORT char * dec(char * stream, const RM_Opnd & rm, Opnd_Size sz = size_platf);
ENCODER_DECLARE_EXPORT char * _not(char * stream, const RM_Opnd & rm, Opnd_Size sz = size_platf);
ENCODER_DECLARE_EXPORT char * neg(char * stream, const RM_Opnd & rm, Opnd_Size sz = size_platf);
ENCODER_DECLARE_EXPORT char * nop(char * stream);
ENCODER_DECLARE_EXPORT char * int3(char * stream);
// alu instructions: add, or, adc, sbb, and, sub, xor, cmp
ENCODER_DECLARE_EXPORT char * alu(char * stream, ALU_Opcode opc, const RM_Opnd & rm, const Imm_Opnd & imm, Opnd_Size sz = size_platf);
ENCODER_DECLARE_EXPORT char * alu(char * stream, ALU_Opcode opc, const M_Opnd & m, const R_Opnd & r, Opnd_Size sz = size_platf);
ENCODER_DECLARE_EXPORT char * alu(char * stream, ALU_Opcode opc, const R_Opnd & r, const RM_Opnd & rm, Opnd_Size sz = size_platf);
// test instruction
ENCODER_DECLARE_EXPORT char * test(char * stream, const RM_Opnd & rm, const Imm_Opnd & imm, Opnd_Size sz = size_platf);
ENCODER_DECLARE_EXPORT char * test(char * stream, const RM_Opnd & rm, const R_Opnd & r, Opnd_Size sz = size_platf);
// shift instructions: shl, shr, sar, shld, shrd, ror
ENCODER_DECLARE_EXPORT char * shift(char * stream, Shift_Opcode opc, const RM_Opnd & rm, const Imm_Opnd & imm, Opnd_Size sz = size_platf);
ENCODER_DECLARE_EXPORT char * shift(char * stream, Shift_Opcode opc, const RM_Opnd & rm, Opnd_Size sz = size_platf);
ENCODER_DECLARE_EXPORT char * shift(char * stream, Shift_Opcode opc, const RM_Opnd & rm, const R_Opnd & r, const Imm_Opnd & imm, Opnd_Size sz = size_platf);
ENCODER_DECLARE_EXPORT char * shift(char * stream, Shift_Opcode opc, const RM_Opnd & rm, const R_Opnd & r, Opnd_Size sz = size_platf);
// multiply instructions: mul, imul
ENCODER_DECLARE_EXPORT char * mul(char * stream, const RM_Opnd & rm, Opnd_Size sz = size_platf);
ENCODER_DECLARE_EXPORT char * imul(char * stream, const R_Opnd & r, const RM_Opnd & rm, Opnd_Size sz = size_platf);
ENCODER_DECLARE_EXPORT char * imul(char * stream, const R_Opnd & r, const Imm_Opnd & imm, Opnd_Size sz = size_platf);
ENCODER_DECLARE_EXPORT char * imul(char * stream, const R_Opnd & r, const RM_Opnd & rm, const Imm_Opnd& imm, Opnd_Size sz = size_platf);
// divide instructions: div, idiv
ENCODER_DECLARE_EXPORT char * idiv(char * stream, const RM_Opnd & rm, Opnd_Size sz = size_platf);
// data movement: mov
ENCODER_DECLARE_EXPORT char * mov(char * stream, const M_Opnd & m, const R_Opnd & r, Opnd_Size sz = size_platf);
ENCODER_DECLARE_EXPORT char * mov(char * stream, const R_Opnd & r, const RM_Opnd & rm, Opnd_Size sz = size_platf);
ENCODER_DECLARE_EXPORT char * mov(char * stream, const RM_Opnd & rm, const Imm_Opnd & imm, Opnd_Size sz = size_platf);
ENCODER_DECLARE_EXPORT char * movsx( char * stream, const R_Opnd & r, const RM_Opnd & rm, Opnd_Size sz = size_platf);
ENCODER_DECLARE_EXPORT char * movzx( char * stream, const R_Opnd & r, const RM_Opnd & rm, Opnd_Size sz = size_platf);
ENCODER_DECLARE_EXPORT char * movd(char * stream, const RM_Opnd & rm, const XMM_Opnd & xmm);
ENCODER_DECLARE_EXPORT char * movd(char * stream, const XMM_Opnd & xmm, const RM_Opnd & rm);
ENCODER_DECLARE_EXPORT char * movq(char * stream, const RM_Opnd & rm, const XMM_Opnd & xmm);
ENCODER_DECLARE_EXPORT char * movq(char * stream, const XMM_Opnd & xmm, const RM_Opnd & rm);
// sse mov
ENCODER_DECLARE_EXPORT char * sse_mov(char * stream, const XMM_Opnd & xmm, const M_Opnd & mem, bool dbl);
ENCODER_DECLARE_EXPORT char * sse_mov(char * stream, const M_Opnd & mem, const XMM_Opnd & xmm, bool dbl);
ENCODER_DECLARE_EXPORT char * sse_mov(char * stream, const XMM_Opnd & xmm0, const XMM_Opnd & xmm1, bool dbl);
// sse add, sub, mul, div
ENCODER_DECLARE_EXPORT char * sse_add(char * stream, const XMM_Opnd & xmm, const M_Opnd & mem, bool dbl);
ENCODER_DECLARE_EXPORT char * sse_add(char * stream, const XMM_Opnd & xmm0, const XMM_Opnd & xmm1, bool dbl);
ENCODER_DECLARE_EXPORT char * sse_sub(char * stream, const XMM_Opnd & xmm, const M_Opnd & mem, bool dbl);
ENCODER_DECLARE_EXPORT char * sse_sub(char * stream, const XMM_Opnd & xmm0, const XMM_Opnd & xmm1, bool dbl);
ENCODER_DECLARE_EXPORT char * sse_mul(char * stream, const XMM_Opnd & xmm, const M_Opnd & mem, bool dbl);
ENCODER_DECLARE_EXPORT char * sse_mul(char * stream, const XMM_Opnd & xmm0, const XMM_Opnd & xmm1, bool dbl);
ENCODER_DECLARE_EXPORT char * sse_div(char * stream, const XMM_Opnd & xmm, const M_Opnd & mem, bool dbl);
ENCODER_DECLARE_EXPORT char * sse_div(char * stream, const XMM_Opnd & xmm0, const XMM_Opnd & xmm1, bool dbl);
// xor, compare
ENCODER_DECLARE_EXPORT char * sse_xor(char * stream, const XMM_Opnd & xmm0, const XMM_Opnd & xmm1);
ENCODER_DECLARE_EXPORT char * sse_compare(char * stream, const XMM_Opnd & xmm0, const XMM_Opnd & xmm1, bool dbl);
ENCODER_DECLARE_EXPORT char * sse_compare(char * stream, const XMM_Opnd & xmm0, const M_Opnd & mem, bool dbl);
// sse conversions
ENCODER_DECLARE_EXPORT char * sse_cvt_si(char * stream, const XMM_Opnd & xmm, const M_Opnd & mem, bool dbl);
ENCODER_DECLARE_EXPORT char * sse_cvtt2si(char * stream, const R_Opnd & reg, const M_Opnd & mem, bool dbl);
ENCODER_DECLARE_EXPORT char * sse_cvtt2si(char * stream, const R_Opnd & reg, const XMM_Opnd & xmm, bool dbl);
ENCODER_DECLARE_EXPORT char * sse_cvt_fp2dq(char * stream, const XMM_Opnd & xmm0, const XMM_Opnd & xmm1, bool dbl);
ENCODER_DECLARE_EXPORT char * sse_cvt_dq2fp(char * stream, const XMM_Opnd & xmm0, const XMM_Opnd & xmm1, bool dbl);
ENCODER_DECLARE_EXPORT char * sse_d2s(char * stream, const XMM_Opnd & xmm0, const M_Opnd & mem64);
ENCODER_DECLARE_EXPORT char * sse_d2s(char * stream, const XMM_Opnd & xmm0, const XMM_Opnd & xmm1);
ENCODER_DECLARE_EXPORT char * sse_s2d(char * stream, const XMM_Opnd & xmm0, const M_Opnd & mem32);
ENCODER_DECLARE_EXPORT char * sse_s2d(char * stream, const XMM_Opnd & xmm0, const XMM_Opnd & xmm1);
// condition operations
ENCODER_DECLARE_EXPORT char * cmov(char * stream, ConditionCode cc, const R_Opnd & r, const RM_Opnd & rm, Opnd_Size sz = size_platf);
ENCODER_DECLARE_EXPORT char * setcc(char * stream, ConditionCode cc, const RM_Opnd & rm8);
// load effective address: lea
ENCODER_DECLARE_EXPORT char * lea(char * stream, const R_Opnd & r, const M_Opnd & m, Opnd_Size sz = size_platf);
ENCODER_DECLARE_EXPORT char * cdq(char * stream);
ENCODER_DECLARE_EXPORT char * wait(char * stream);
// control-flow instructions
ENCODER_DECLARE_EXPORT char * loop(char * stream, const Imm_Opnd & imm);
// jump with 8-bit relative
ENCODER_DECLARE_EXPORT char * jump8(char * stream, const Imm_Opnd & imm);
// jump with 32-bit relative
ENCODER_DECLARE_EXPORT char * jump32(char * stream, const Imm_Opnd & imm);
// register indirect jump
ENCODER_DECLARE_EXPORT char * jump(char * stream, const RM_Opnd & rm, Opnd_Size sz = size_platf);
// jump to target address
ENCODER_DECLARE_EXPORT char *jump(char * stream, char *target);
// jump with displacement
//char * jump(char * stream, I_32 disp);
// conditional branch with 8-bit branch offset
ENCODER_DECLARE_EXPORT char * branch8(char * stream, ConditionCode cc, const Imm_Opnd & imm, InstrPrefix prefix = no_prefix);
// conditional branch with 32-bit branch offset
ENCODER_DECLARE_EXPORT char * branch32(char * stream, ConditionCode cc, const Imm_Opnd & imm, InstrPrefix prefix = no_prefix);
// conditional branch with target label address
//char * branch(char * stream, ConditionCode cc, const char * target, InstrPrefix prefix = no_prefix);
// conditional branch with displacement immediate
ENCODER_DECLARE_EXPORT char * branch(char * stream, ConditionCode cc, I_32 disp, InstrPrefix prefix = no_prefix);
// call with displacement
ENCODER_DECLARE_EXPORT char * call(char * stream, const Imm_Opnd & imm);
// indirect call through register or memory location
ENCODER_DECLARE_EXPORT char * call(char * stream, const RM_Opnd & rm, Opnd_Size sz = size_platf);
// call target address
ENCODER_DECLARE_EXPORT char * call(char * stream, const char * target);
// return instruction
ENCODER_DECLARE_EXPORT char * ret(char * stream);
ENCODER_DECLARE_EXPORT char * ret(char * stream, unsigned short pop);
ENCODER_DECLARE_EXPORT char * ret(char * stream, const Imm_Opnd & imm);
// string operations
ENCODER_DECLARE_EXPORT char * set_d(char * stream, bool set);
ENCODER_DECLARE_EXPORT char * scas(char * stream, unsigned char prefix);
ENCODER_DECLARE_EXPORT char * stos(char * stream, unsigned char prefix);
// floating-point instructions
// st(0) = st(0) fp_op m{32,64}real
//!char * fp_op_mem(char * stream, FP_Opcode opc,const M_Opnd& mem,int is_double);
// st(0) = st(0) fp_op st(i)
//!char *fp_op(char * stream, FP_Opcode opc,unsigned i);
// st(i) = st(i) fp_op st(0) ; optionally pop stack
//!char * fp_op(char * stream, FP_Opcode opc,unsigned i,unsigned pop_stk);
// compare st(0),st(1) and pop stack twice
//!char * fcompp(char * stream);
ENCODER_DECLARE_EXPORT char * fldcw(char * stream, const M_Opnd & mem);
ENCODER_DECLARE_EXPORT char * fnstcw(char * stream, const M_Opnd & mem);
ENCODER_DECLARE_EXPORT char * fnstsw(char * stream);
//!char * fchs(char * stream);
//!char * frem(char * stream);
//!char * fxch(char * stream,unsigned i);
//!char * fcomip(char * stream, unsigned i);
// load from memory (as fp) into fp register stack
ENCODER_DECLARE_EXPORT char * fld(char * stream, const M_Opnd & m, bool is_double);
//!char *fld80(char * stream,const M_Opnd& mem);
// load from memory (as int) into fp register stack
//!char * fild(char * stream,const M_Opnd& mem,int is_long);
// push st(i) onto fp register stack
//!char * fld(char * stream,unsigned i);
// push the constants 0.0 and 1.0 onto the fp register stack
//!char * fldz(char * stream);
//!char * fld1(char * stream);
// store stack to memory (as int), always popping the stack
ENCODER_DECLARE_EXPORT char * fist(char * stream, const M_Opnd & mem, bool is_long, bool pop_stk);
// store stack to to memory (as fp), optionally popping the stack
ENCODER_DECLARE_EXPORT char * fst(char * stream, const M_Opnd & m, bool is_double, bool pop_stk);
// store ST(0) to ST(i), optionally popping the stack. Takes 1 clock
ENCODER_DECLARE_EXPORT char * fst(char * stream, unsigned i, bool pop_stk);
//!char * pushad(char * stream);
//!char * pushfd(char * stream);
//!char * popad(char * stream);
//!char * popfd(char * stream);
// stack frame allocation instructions: enter & leave
//
// enter frame_size
//
// is equivalent to:
//
// push ebp
// mov ebp,esp
// sub esp,frame_size
//
//!char *enter(char * stream,const Imm_Opnd& imm);
// leave
// is equivalent to:
//
// mov esp,ebp
// pop ebp
//!char *leave(char * stream);
// sahf loads SF, ZF, AF, PF, and CF flags from eax
//!char *sahf(char * stream);
// Intrinsic FP math functions
//!char *math_fsin(char * stream);
//!char *math_fcos(char * stream);
//!char *math_fabs(char * stream);
//!char *math_fpatan(char * stream);
ENCODER_DECLARE_EXPORT char * fprem(char * stream);
ENCODER_DECLARE_EXPORT char * fprem1(char * stream);
//!char *math_frndint(char * stream);
//!char *math_fptan(char * stream);
//
// Add 1-7 bytes padding, with as few instructions as possible,
// with no effect on the processor state (e.g., registers, flags)
//
//!char *padding(char * stream, unsigned num);
// prolog and epilog code generation
//- char *prolog(char * stream,unsigned frame_size,unsigned reg_save_mask);
//- char *epilog(char * stream,unsigned reg_save_mask);
//!extern R_Opnd reg_operand_array[];
// fsave and frstor
//!char *fsave(char * stream);
//!char *frstor(char * stream);
// lahf : Load Status Flags into AH Register
//!char *lahf(char * stream);
// mfence : Memory Fence
//!char *mfence(char * stream);
#endif // _VM_ENCODER_H_