blob: 430057498668dce1ac55fd2172c94887fcbcc720 [file] [log] [blame]
/*
* 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
*/
#ifndef __ENC_PRVT_H_INCLUDED__
#define __ENC_PRVT_H_INCLUDED__
#include "enc_base.h"
ENCODER_NAMESPACE_START
/*
* @file
* @brief Contains some definitions/constants and other stuff used by the
* Encoder internally.
*/
enum OpcodeByteKind {
//OpcodeByteKind_Opcode = 0x0000,
OpcodeByteKind_ZeroOpcodeByte = 0x0100,
//
// The names _SlashR, _SlahsNum, _ib, _iw, etc
// represent the appropriate abbreviations used
// in the mnemonic descriptions in the Intel's arch manual.
//
OpcodeByteKind_SlashR = 0x0200,
OpcodeByteKind_SlashNum = 0x0300,
OpcodeByteKind_ib = 0x0400,
OpcodeByteKind_iw = 0x0500,
OpcodeByteKind_id = 0x0600,
#ifdef _EM64T_
OpcodeByteKind_io = 0x0700,
#endif
OpcodeByteKind_cb = 0x0800,
OpcodeByteKind_cw = 0x0900,
OpcodeByteKind_cd = 0x0A00,
//OpcodeByteKind_cp = 0x0B00,
//OpcodeByteKind_co = 0x0C00,
//OpcodeByteKind_ct = 0x0D00,
OpcodeByteKind_rb = 0x0E00,
OpcodeByteKind_rw = 0x0F00,
OpcodeByteKind_rd = 0x1000,
#ifdef _EM64T_
OpcodeByteKind_ro = 0x1100,
//OpcodeByteKind_REX = 0x1200,
OpcodeByteKind_REX_W = 0x1300,
#endif
OpcodeByteKind_plus_i = 0x1400,
/**
* a special marker, means 'no opcode on the given position'
* used in opcodes array, to specify the empty slot, say
* to fill an em64t-specific opcode on ia32.
* last 'e' made lowercase to avoid a mess with 'F' in
* OpcodeByteKind_LAST .
*/
OpcodeByteKind_EMPTY = 0xFFFE,
/**
* a special marker, means 'no more opcodes in the array'
* used in in opcodes array to show that there are no more
* opcodes in the array for a given mnemonic.
*/
OpcodeByteKind_LAST = 0xFFFF,
/**
* a mask to extract the OpcodeByteKind
*/
OpcodeByteKind_KindMask = 0xFF00,
/**
* a mask to extract the opcode byte when presented
*/
OpcodeByteKind_OpcodeMask = 0x00FF
};
#ifdef USE_ENCODER_DEFINES
#define N {0, 0, 0, 0 }
#define U {1, 0, 1, OpndRole_Use }
#define D {1, 1, 0, OpndRole_Def }
#define DU {1, 1, 1, OpndRole_Def|OpndRole_Use }
#define U_U {2, 0, 2, OpndRole_Use<<2 | OpndRole_Use }
#define D_U {2, 1, 1, OpndRole_Def<<2 | OpndRole_Use }
#define D_DU {2, 2, 1, OpndRole_Def<<2 | (OpndRole_Def|OpndRole_Use) }
#define DU_U {2, 1, 2, ((OpndRole_Def|OpndRole_Use)<<2 | OpndRole_Use) }
#define DU_DU {2, 2, 2, ((OpndRole_Def|OpndRole_Use)<<2 | (OpndRole_Def|OpndRole_Use)) }
#define DU_DU_DU {3, 3, 3, ((OpndRole_Def|OpndRole_Use)<<4) | ((OpndRole_Def|OpndRole_Use)<<2) | (OpndRole_Def|OpndRole_Use) }
#define DU_DU_U {3, 2, 3, (((OpndRole_Def|OpndRole_Use)<<4) | ((OpndRole_Def|OpndRole_Use)<<2) | OpndRole_Use) }
#define D_DU_U {3, 2, 2, (((OpndRole_Def)<<4) | ((OpndRole_Def|OpndRole_Use)<<2) | OpndRole_Use) }
#define D_U_U {3, 1, 2, (((OpndRole_Def)<<4) | ((OpndRole_Use)<<2) | OpndRole_Use) }
// Special encoding of 0x00 opcode byte. Note: it's all O-s, not zeros.
#define OxOO OpcodeByteKind_ZeroOpcodeByte
#define Size16 InstPrefix_OpndSize
#define _r OpcodeByteKind_SlashR
#define _0 OpcodeByteKind_SlashNum|0
#define _1 OpcodeByteKind_SlashNum|1
#define _2 OpcodeByteKind_SlashNum|2
#define _3 OpcodeByteKind_SlashNum|3
#define _4 OpcodeByteKind_SlashNum|4
#define _5 OpcodeByteKind_SlashNum|5
#define _6 OpcodeByteKind_SlashNum|6
#define _7 OpcodeByteKind_SlashNum|7
// '+i' for floating-point instructions
#define _i OpcodeByteKind_plus_i
#define ib OpcodeByteKind_ib
#define iw OpcodeByteKind_iw
#define id OpcodeByteKind_id
#define cb OpcodeByteKind_cb
#define cw OpcodeByteKind_cw
#define cd OpcodeByteKind_cd
#define rb OpcodeByteKind_rb
#define rw OpcodeByteKind_rw
#define rd OpcodeByteKind_rd
#define AL {OpndKind_GPReg, OpndSize_8, OpndExt_Any, RegName_AL}
#define AH {OpndKind_GPReg, OpndSize_8, OpndExt_Any, RegName_AH}
#define AX {OpndKind_GPReg, OpndSize_16, OpndExt_Any, RegName_AX}
#define EAX {OpndKind_GPReg, OpndSize_32, OpndExt_Any, RegName_EAX}
#ifdef _EM64T_
#define RAX {OpndKind_GPReg, OpndSize_64, OpndExt_Any, RegName_RAX }
#endif
#define CL {OpndKind_GPReg, OpndSize_8, OpndExt_Any, RegName_CL}
#define ECX {OpndKind_GPReg, OpndSize_32, OpndExt_Any, RegName_ECX}
#ifdef _EM64T_
#define RCX {OpndKind_GPReg, OpndSize_64, OpndExt_Any, RegName_RCX}
#endif
#define DX {OpndKind_GPReg, OpndSize_16, OpndExt_Any, RegName_DX}
#define EDX {OpndKind_GPReg, OpndSize_32, OpndExt_Any, RegName_EDX}
#ifdef _EM64T_
#define RDX { OpndKind_GPReg, OpndSize_64, OpndExt_Any, RegName_RDX }
#endif
#define ESI {OpndKind_GPReg, OpndSize_32, OpndExt_Any, RegName_ESI}
#ifdef _EM64T_
#define RSI { OpndKind_GPReg, OpndSize_64, OpndExt_Any, RegName_RSI }
#endif
#define EDI {OpndKind_GPReg, OpndSize_32, OpndExt_Any, RegName_EDI}
#ifdef _EM64T_
#define RDI { OpndKind_GPReg, OpndSize_64, OpndExt_Any, RegName_RDI }
#endif
#define r8 {OpndKind_GPReg, OpndSize_8, OpndExt_Any, RegName_Null}
#define r16 {OpndKind_GPReg, OpndSize_16, OpndExt_Any, RegName_Null}
#define r32 {OpndKind_GPReg, OpndSize_32, OpndExt_Any, RegName_Null}
#ifdef _EM64T_
#define r64 { OpndKind_GPReg, OpndSize_64, OpndExt_Any, RegName_Null }
#endif
#define r_m8 {(OpndKind)(OpndKind_GPReg|OpndKind_Mem), OpndSize_8, OpndExt_Any, RegName_Null}
#define r_m16 {(OpndKind)(OpndKind_GPReg|OpndKind_Mem), OpndSize_16, OpndExt_Any, RegName_Null}
#define r_m32 {(OpndKind)(OpndKind_GPReg|OpndKind_Mem), OpndSize_32, OpndExt_Any, RegName_Null}
#define r_m8s {(OpndKind)(OpndKind_GPReg|OpndKind_Mem), OpndSize_8, OpndExt_Signed, RegName_Null}
#define r_m16s {(OpndKind)(OpndKind_GPReg|OpndKind_Mem), OpndSize_16, OpndExt_Signed, RegName_Null}
#define r_m32s {(OpndKind)(OpndKind_GPReg|OpndKind_Mem), OpndSize_32, OpndExt_Signed, RegName_Null}
#define r_m8u {(OpndKind)(OpndKind_GPReg|OpndKind_Mem), OpndSize_8, OpndExt_Zero, RegName_Null}
#define r_m16u {(OpndKind)(OpndKind_GPReg|OpndKind_Mem), OpndSize_16, OpndExt_Zero, RegName_Null}
#define r_m32u {(OpndKind)(OpndKind_GPReg|OpndKind_Mem), OpndSize_32, OpndExt_Zero, RegName_Null}
//'m' was only used in LEA mnemonic, but is replaced with
// set of exact sizes. See more comments for LEA instruction in TheTable.
//#define m {OpndKind_Mem, OpndSize_Null, RegName_Null}
#define m8 {OpndKind_Mem, OpndSize_8, OpndExt_Any, RegName_Null}
#define m16 {OpndKind_Mem, OpndSize_16, OpndExt_Any, RegName_Null}
#define m32 {OpndKind_Mem, OpndSize_32, OpndExt_Any, RegName_Null}
#define m64 {OpndKind_Mem, OpndSize_64, OpndExt_Any, RegName_Null}
#ifdef _EM64T_
#define r_m64 { (OpndKind)(OpndKind_GPReg|OpndKind_Mem), OpndSize_64, OpndExt_Any, RegName_Null }
#endif
#define imm8 {OpndKind_Imm, OpndSize_8, OpndExt_Any, RegName_Null}
#define imm16 {OpndKind_Imm, OpndSize_16, OpndExt_Any, RegName_Null}
#define imm32 {OpndKind_Imm, OpndSize_32, OpndExt_Any, RegName_Null}
#define imm8s {OpndKind_Imm, OpndSize_8, OpndExt_Signed, RegName_Null}
#define imm16s {OpndKind_Imm, OpndSize_16, OpndExt_Signed, RegName_Null}
#define imm32s {OpndKind_Imm, OpndSize_32, OpndExt_Signed, RegName_Null}
#define imm8u {OpndKind_Imm, OpndSize_8, OpndExt_Zero, RegName_Null}
#define imm16u {OpndKind_Imm, OpndSize_16, OpndExt_Zero, RegName_Null}
#define imm32u {OpndKind_Imm, OpndSize_32, OpndExt_Zero, RegName_Null}
#ifdef _EM64T_
#define imm64 {OpndKind_Imm, OpndSize_64, OpndExt_Any, RegName_Null }
#endif
//FIXME: moff-s are in fact memory refs, but presented as immediate.
// Need to specify this in OpndDesc.
#define moff8 {OpndKind_Imm, OpndSize_32, OpndExt_Any, RegName_Null}
#define moff16 {OpndKind_Imm, OpndSize_32, OpndExt_Any, RegName_Null}
#define moff32 {OpndKind_Imm, OpndSize_32, OpndExt_Any, RegName_Null}
#ifdef _EM64T_
#define moff64 {OpndKind_Imm, OpndSize_64, OpndExt_Any, RegName_Null}
#endif
#define rel8 {OpndKind_Imm, OpndSize_8, OpndExt_Any, RegName_Null}
#define rel16 {OpndKind_Imm, OpndSize_16, OpndExt_Any, RegName_Null}
#define rel32 {OpndKind_Imm, OpndSize_32, OpndExt_Any, RegName_Null}
#define mm64 {OpndKind_MMXReg, OpndSize_64, OpndExt_Any, RegName_Null}
#define mm_m64 {(OpndKind)(OpndKind_MMXReg|OpndKind_Mem), OpndSize_64, OpndExt_Any, RegName_Null}
#define xmm64 {OpndKind_XMMReg, OpndSize_64, OpndExt_Any, RegName_Null}
#define xmm_m64 {(OpndKind)(OpndKind_XMMReg|OpndKind_Mem), OpndSize_64, OpndExt_Any, RegName_Null}
#define xmm32 {OpndKind_XMMReg, OpndSize_32, OpndExt_Any, RegName_Null}
#define xmm_m32 {(OpndKind)(OpndKind_XMMReg|OpndKind_Mem), OpndSize_32, OpndExt_Any, RegName_Null}
#define FP0S {OpndKind_FPReg, OpndSize_32, OpndExt_Any, RegName_FP0S}
#define FP0D {OpndKind_FPReg, OpndSize_64, OpndExt_Any, RegName_FP0D}
#define FP1S {OpndKind_FPReg, OpndSize_32, OpndExt_Any, RegName_FP1S}
#define FP1D {OpndKind_FPReg, OpndSize_64, OpndExt_Any, RegName_FP1D}
#define fp32 {OpndKind_FPReg, OpndSize_32, OpndExt_Any, RegName_Null}
#define fp64 {OpndKind_FPReg, OpndSize_64, OpndExt_Any, RegName_Null}
#ifdef _EM64T_
#define io OpcodeByteKind_io
#define REX_W OpcodeByteKind_REX_W
#endif
#endif // USE_ENCODER_DEFINES
/**
* @brief Represents the REX part of instruction.
*/
struct Rex {
unsigned char b : 1;
unsigned char x : 1;
unsigned char r : 1;
unsigned char w : 1;
unsigned char dummy : 4; // must be '0100'b
unsigned int :24;
};
/**
* @brief Describes SIB (scale,index,base) byte.
*/
struct SIB {
unsigned char base:3;
unsigned char index:3;
unsigned char scale:2;
unsigned int padding:24;
};
/**
* @brief Describes ModRM byte.
*/
struct ModRM
{
unsigned char rm:3;
unsigned char reg:3;
unsigned char mod:2;
unsigned int padding:24;
};
/**
* exactly the same as EncoderBase::OpcodeDesc, but also holds info about
* platform on which the opcode is applicable.
*/
struct OpcodeInfo {
enum platform {
/// an opcode is valid on all platforms
all,
// opcode is valid on IA-32 only
em64t,
// opcode is valid on Intel64 only
ia32,
// opcode is added for the sake of disassembling, should not be used in encoding
decoder,
// only appears in master table, replaced with 'decoder' in hashed version
decoder32,
// only appears in master table, replaced with 'decoder' in hashed version
decoder64,
};
platform platf;
unsigned opcode[4+1+1];
EncoderBase::OpndDesc opnds[3];
EncoderBase::OpndRolesDesc roles;
};
/**
* @defgroup MF_ Mnemonic flags
*/
/**
* Operation has no special properties.
*/
#define MF_NONE (0x00000000)
/**
* Operation affects flags
*/
#define MF_AFFECTS_FLAGS (0x00000001)
/**
* Operation uses flags - conditional operations, ADC/SBB/ETC
*/
#define MF_USES_FLAGS (0x00000002)
/**
* Operation is conditional - MOVcc/SETcc/Jcc/ETC
*/
#define MF_CONDITIONAL (0x00000004)
/**
* Operation is symmetric - its args can be swapped (ADD/MUL/etc).
*/
#define MF_SYMMETRIC (0x00000008)
/**
* Operation is XOR-like - XOR, SUB - operations of 'arg,arg' is pure def,
* without use.
*/
#define MF_SAME_ARG_NO_USE (0x00000010)
///@} // ~MNF
/**
* @see same structure as EncoderBase::MnemonicDesc, but carries
* MnemonicInfo::OpcodeInfo[] instead of OpcodeDesc[].
* Only used during prebuilding the encoding tables, thus it's hidden under
* the appropriate define.
*/
struct MnemonicInfo {
/**
* The mnemonic itself
*/
Mnemonic mn;
/**
* Various characteristics of mnemonic.
* @see MF_
*/
unsigned flags;
/**
* Number of args/des/uses/roles for the operation. For the operations
* which may use different number of operands (i.e. IMUL/SHL) use the
* most common value, or leave '0' if you are sure this info is not
* required.
*/
EncoderBase::OpndRolesDesc roles;
/**
* Print name of the mnemonic
*/
const char * name;
/**
* Array of opcodes.
* The terminating opcode description always have OpcodeByteKind_LAST
* at the opcodes[i].opcode[0].
* The size of '25' has nothing behind it, just counted the max
* number of opcodes currently used (MOV instruction).
*/
OpcodeInfo opcodes[25];
};
ENCODER_NAMESPACE_END
#endif // ~__ENC_PRVT_H_INCLUDED__