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