mirror of https://github.com/icedland/iced.git
Move Instruction Create() and info code to new files
This commit is contained in:
parent
fa5f5630d9
commit
13661dd077
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,359 @@
|
|||
/*
|
||||
Copyright (C) 2018 de4dot@gmail.com
|
||||
|
||||
This file is part of Iced.
|
||||
|
||||
Iced is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Iced is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with Iced. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#if !NO_INSTR_INFO
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Iced.Intel {
|
||||
partial struct Instruction {
|
||||
/// <summary>
|
||||
/// Gets the number of bytes added to SP/ESP/RSP or 0 if it's not an instruction that pushes or pops data. This method
|
||||
/// assumes the instruction doesn't change privilege (eg. iret/d/q). If it's the leave instruction, this method returns 0.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public int StackPointerIncrement {
|
||||
get {
|
||||
switch (Code) {
|
||||
case Code.Pushw_ES:
|
||||
case Code.Pushw_CS:
|
||||
case Code.Pushw_SS:
|
||||
case Code.Pushw_DS:
|
||||
case Code.Push_r16:
|
||||
case Code.Push_imm16:
|
||||
case Code.Pushw_imm8:
|
||||
case Code.Pushfw:
|
||||
case Code.Push_rm16:
|
||||
case Code.Pushw_FS:
|
||||
case Code.Pushw_GS:
|
||||
return -2;
|
||||
|
||||
case Code.Pushd_ES:
|
||||
case Code.Pushd_CS:
|
||||
case Code.Pushd_SS:
|
||||
case Code.Pushd_DS:
|
||||
case Code.Push_r32:
|
||||
case Code.Pushd_imm32:
|
||||
case Code.Pushd_imm8:
|
||||
case Code.Pushfd:
|
||||
case Code.Push_rm32:
|
||||
case Code.Pushd_FS:
|
||||
case Code.Pushd_GS:
|
||||
return -4;
|
||||
|
||||
case Code.Push_r64:
|
||||
case Code.Pushq_imm32:
|
||||
case Code.Pushq_imm8:
|
||||
case Code.Pushfq:
|
||||
case Code.Push_rm64:
|
||||
case Code.Pushq_FS:
|
||||
case Code.Pushq_GS:
|
||||
return -8;
|
||||
|
||||
case Code.Pushaw:
|
||||
return -2 * 8;
|
||||
|
||||
case Code.Pushad:
|
||||
return -4 * 8;
|
||||
|
||||
case Code.Popw_ES:
|
||||
case Code.Popw_SS:
|
||||
case Code.Popw_DS:
|
||||
case Code.Pop_r16:
|
||||
case Code.Pop_rm16:
|
||||
case Code.Popfw:
|
||||
case Code.Popw_FS:
|
||||
case Code.Popw_GS:
|
||||
return 2;
|
||||
|
||||
case Code.Popd_ES:
|
||||
case Code.Popd_SS:
|
||||
case Code.Popd_DS:
|
||||
case Code.Pop_r32:
|
||||
case Code.Pop_rm32:
|
||||
case Code.Popfd:
|
||||
case Code.Popd_FS:
|
||||
case Code.Popd_GS:
|
||||
return 4;
|
||||
|
||||
case Code.Pop_r64:
|
||||
case Code.Pop_rm64:
|
||||
case Code.Popfq:
|
||||
case Code.Popq_FS:
|
||||
case Code.Popq_GS:
|
||||
return 8;
|
||||
|
||||
case Code.Popaw:
|
||||
return 2 * 8;
|
||||
|
||||
case Code.Popad:
|
||||
return 4 * 8;
|
||||
|
||||
case Code.Call_ptr1616:
|
||||
case Code.Call_m1616:
|
||||
return -(2 + 2);
|
||||
|
||||
case Code.Call_ptr3216:
|
||||
case Code.Call_m3216:
|
||||
return -(4 + 4);
|
||||
|
||||
case Code.Call_m6416:
|
||||
return -(8 + 8);
|
||||
|
||||
case Code.Call_rel16:
|
||||
case Code.Call_rm16:
|
||||
return -2;
|
||||
|
||||
case Code.Call_rel32_32:
|
||||
case Code.Call_rm32:
|
||||
return -4;
|
||||
|
||||
case Code.Call_rel32_64:
|
||||
case Code.Call_rm64:
|
||||
return -8;
|
||||
|
||||
case Code.Retnw_imm16:
|
||||
return 2 + Immediate16;
|
||||
|
||||
case Code.Retnd_imm16:
|
||||
return 4 + Immediate16;
|
||||
|
||||
case Code.Retnq_imm16:
|
||||
return 8 + Immediate16;
|
||||
|
||||
case Code.Retnw:
|
||||
return 2;
|
||||
|
||||
case Code.Retnd:
|
||||
return 4;
|
||||
|
||||
case Code.Retnq:
|
||||
return 8;
|
||||
|
||||
case Code.Retfw_imm16:
|
||||
return 2 + 2 + Immediate16;
|
||||
|
||||
case Code.Retfd_imm16:
|
||||
return 4 + 4 + Immediate16;
|
||||
|
||||
case Code.Retfq_imm16:
|
||||
return 8 + 8 + Immediate16;
|
||||
|
||||
case Code.Retfw:
|
||||
return 2 + 2;
|
||||
|
||||
case Code.Retfd:
|
||||
return 4 + 4;
|
||||
|
||||
case Code.Retfq:
|
||||
return 8 + 8;
|
||||
|
||||
case Code.Iretw:
|
||||
if (CodeSize == CodeSize.Code64)
|
||||
return 2 * 5;
|
||||
return 2 * 3;
|
||||
|
||||
case Code.Iretd:
|
||||
if (CodeSize == CodeSize.Code64)
|
||||
return 4 * 5;
|
||||
return 4 * 3;
|
||||
|
||||
case Code.Iretq:
|
||||
return 8 * 5;
|
||||
|
||||
case Code.Enterw_imm16_imm8:
|
||||
return -(2 + (Immediate8_2nd & 0x1F) * 2 + Immediate16);
|
||||
|
||||
case Code.Enterd_imm16_imm8:
|
||||
return -(4 + (Immediate8_2nd & 0x1F) * 4 + Immediate16);
|
||||
|
||||
case Code.Enterq_imm16_imm8:
|
||||
return -(8 + (Immediate8_2nd & 0x1F) * 8 + Immediate16);
|
||||
|
||||
case Code.Leavew:
|
||||
case Code.Leaved:
|
||||
case Code.Leaveq:
|
||||
return 0;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// (This method allocates and is slower than using an <see cref="InstructionInfoFactory"/>.)
|
||||
///
|
||||
/// Gets instruction info such as which register is read and written etc.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public InstructionInfo GetInfo() {
|
||||
var usedRegisters = InstructionInfoInternal.SimpleList<UsedRegister>.Empty;
|
||||
var usedMemoryLocations = InstructionInfoInternal.SimpleList<UsedMemory>.Empty;
|
||||
return InstructionInfoFactory.Create(ref this, ref usedRegisters, ref usedMemoryLocations, InstructionInfoOptions.None);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// (This method allocates and is slower than using an <see cref="InstructionInfoFactory"/>.)
|
||||
///
|
||||
/// Gets instruction info such as which register is read and written etc.
|
||||
/// </summary>
|
||||
/// <param name="options">Options</param>
|
||||
/// <returns></returns>
|
||||
public InstructionInfo GetInfo(InstructionInfoOptions options) {
|
||||
var usedRegisters = InstructionInfoInternal.SimpleList<UsedRegister>.Empty;
|
||||
var usedMemoryLocations = InstructionInfoInternal.SimpleList<UsedMemory>.Empty;
|
||||
return InstructionInfoFactory.Create(ref this, ref usedRegisters, ref usedMemoryLocations, options);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// (This method allocates and is slower than using an <see cref="InstructionInfoFactory"/>.)
|
||||
///
|
||||
/// Gets a struct iterator that returns all read and written registers. There are some exceptions, this method doesn't return all used registers:
|
||||
///
|
||||
/// 1) If <see cref="SaveRestoreInstruction"/> is true, or
|
||||
///
|
||||
/// 2) If it's a <see cref="FlowControl.Call"/> or <see cref="FlowControl.Interrupt"/> instruction (call, sysenter, int n etc), it can read and write any register (including RFLAGS).
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public InstructionInfo.UsedRegisterIterator GetUsedRegisters() {
|
||||
var usedRegisters = InstructionInfoInternal.SimpleList<UsedRegister>.Empty;
|
||||
var usedMemoryLocations = InstructionInfoInternal.SimpleList<UsedMemory>.Empty;
|
||||
return InstructionInfoFactory.Create(ref this, ref usedRegisters, ref usedMemoryLocations, InstructionInfoOptions.NoMemoryUsage).GetUsedRegisters();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// (This method allocates and is slower than using an <see cref="InstructionInfoFactory"/>.)
|
||||
///
|
||||
/// Gets a struct iterator that returns all read and written memory locations
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public InstructionInfo.UsedMemoryIterator GetUsedMemory() {
|
||||
var usedRegisters = InstructionInfoInternal.SimpleList<UsedRegister>.Empty;
|
||||
var usedMemoryLocations = InstructionInfoInternal.SimpleList<UsedMemory>.Empty;
|
||||
return InstructionInfoFactory.Create(ref this, ref usedRegisters, ref usedMemoryLocations, InstructionInfoOptions.NoRegisterUsage).GetUsedMemory();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Instruction encoding, eg. legacy, VEX, EVEX, ...
|
||||
/// </summary>
|
||||
public EncodingKind Encoding => Code.Encoding();
|
||||
|
||||
/// <summary>
|
||||
/// CPU or CPUID feature flag
|
||||
/// </summary>
|
||||
public CpuidFeature CpuidFeature {
|
||||
get {
|
||||
var code = Code;
|
||||
var cpuidFeature = code.CpuidFeature();
|
||||
if (cpuidFeature == CpuidFeature.AVX && Op1Kind == OpKind.Register && (code == Code.VEX_Vbroadcastss_xmm_xmmm32 || code == Code.VEX_Vbroadcastss_ymm_xmmm32 || code == Code.VEX_Vbroadcastsd_ymm_xmmm64))
|
||||
return CpuidFeature.AVX2;
|
||||
return cpuidFeature;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Flow control info
|
||||
/// </summary>
|
||||
public FlowControl FlowControl => Code.FlowControl();
|
||||
|
||||
/// <summary>
|
||||
/// true if the instruction isn't available in real mode or virtual 8086 mode
|
||||
/// </summary>
|
||||
public bool ProtectedMode => Code.ProtectedMode();
|
||||
|
||||
/// <summary>
|
||||
/// true if this is a privileged instruction
|
||||
/// </summary>
|
||||
public bool Privileged => Code.Privileged();
|
||||
|
||||
/// <summary>
|
||||
/// true if this is an instruction that implicitly uses the stack pointer (SP/ESP/RSP), eg. call, push, pop, ret, etc.
|
||||
/// See also <see cref="StackPointerIncrement"/>
|
||||
/// </summary>
|
||||
public bool StackInstruction => Code.StackInstruction();
|
||||
|
||||
/// <summary>
|
||||
/// true if it's an instruction that saves or restores too many registers (eg. fxrstor, xsave, etc).
|
||||
/// </summary>
|
||||
public bool SaveRestoreInstruction => Code.SaveRestoreInstruction();
|
||||
|
||||
InstructionInfoInternal.RflagsInfo GetRflagsInfo() {
|
||||
var flags1 = InstructionInfoInternal.InfoHandlers.Data[(int)Code << 1];
|
||||
var codeInfo = (InstructionInfoInternal.CodeInfo)((flags1 >> (int)InstructionInfoInternal.InfoFlags1.CodeInfoShift) & (uint)InstructionInfoInternal.InfoFlags1.CodeInfoMask);
|
||||
Debug.Assert(InstructionInfoInternal.CodeInfo.Shift_Ib_MASK1FMOD9 + 1 == InstructionInfoInternal.CodeInfo.Shift_Ib_MASK1FMOD11);
|
||||
Debug.Assert(InstructionInfoInternal.CodeInfo.Shift_Ib_MASK1FMOD9 + 2 == InstructionInfoInternal.CodeInfo.Shift_Ib_MASK1F);
|
||||
Debug.Assert(InstructionInfoInternal.CodeInfo.Shift_Ib_MASK1FMOD9 + 3 == InstructionInfoInternal.CodeInfo.Shift_Ib_MASK3F);
|
||||
if ((uint)(codeInfo - InstructionInfoInternal.CodeInfo.Shift_Ib_MASK1FMOD9) <= 3) {
|
||||
switch (codeInfo) {
|
||||
case InstructionInfoInternal.CodeInfo.Shift_Ib_MASK1FMOD9:
|
||||
if ((Immediate8 & 0x1F) % 9 == 0)
|
||||
return InstructionInfoInternal.RflagsInfo.None;
|
||||
break;
|
||||
|
||||
case InstructionInfoInternal.CodeInfo.Shift_Ib_MASK1FMOD11:
|
||||
if ((Immediate8 & 0x1F) % 17 == 0)
|
||||
return InstructionInfoInternal.RflagsInfo.None;
|
||||
break;
|
||||
|
||||
case InstructionInfoInternal.CodeInfo.Shift_Ib_MASK1F:
|
||||
if ((Immediate8 & 0x1F) == 0)
|
||||
return InstructionInfoInternal.RflagsInfo.None;
|
||||
break;
|
||||
|
||||
case InstructionInfoInternal.CodeInfo.Shift_Ib_MASK3F:
|
||||
if ((Immediate8 & 0x3F) == 0)
|
||||
return InstructionInfoInternal.RflagsInfo.None;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return (InstructionInfoInternal.RflagsInfo)((flags1 >> (int)InstructionInfoInternal.InfoFlags1.RflagsInfoShift) & (uint)InstructionInfoInternal.InfoFlags1.RflagsInfoMask);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// All flags that are read by the CPU when executing the instruction
|
||||
/// </summary>
|
||||
public RflagsBits RflagsRead => (RflagsBits)InstructionInfoInternal.RflagsInfoConstants.flagsRead[(int)GetRflagsInfo()];
|
||||
|
||||
/// <summary>
|
||||
/// All flags that are written by the CPU, except those flags that are known to be undefined, always set or always cleared. See also <see cref="RflagsModified"/>
|
||||
/// </summary>
|
||||
public RflagsBits RflagsWritten => (RflagsBits)InstructionInfoInternal.RflagsInfoConstants.flagsWritten[(int)GetRflagsInfo()];
|
||||
|
||||
/// <summary>
|
||||
/// All flags that are always cleared by the CPU
|
||||
/// </summary>
|
||||
public RflagsBits RflagsCleared => (RflagsBits)InstructionInfoInternal.RflagsInfoConstants.flagsCleared[(int)GetRflagsInfo()];
|
||||
|
||||
/// <summary>
|
||||
/// All flags that are always set by the CPU
|
||||
/// </summary>
|
||||
public RflagsBits RflagsSet => (RflagsBits)InstructionInfoInternal.RflagsInfoConstants.flagsSet[(int)GetRflagsInfo()];
|
||||
|
||||
/// <summary>
|
||||
/// All flags that are undefined after executing the instruction
|
||||
/// </summary>
|
||||
public RflagsBits RflagsUndefined => (RflagsBits)InstructionInfoInternal.RflagsInfoConstants.flagsUndefined[(int)GetRflagsInfo()];
|
||||
|
||||
/// <summary>
|
||||
/// All flags that are modified by the CPU. This is <see cref="RflagsWritten"/> + <see cref="RflagsCleared"/> + <see cref="RflagsSet"/> + <see cref="RflagsUndefined"/>
|
||||
/// </summary>
|
||||
public RflagsBits RflagsModified => (RflagsBits)InstructionInfoInternal.RflagsInfoConstants.flagsModified[(int)GetRflagsInfo()];
|
||||
}
|
||||
}
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue