mirror of https://github.com/icedland/iced.git
1642 lines
72 KiB
C#
1642 lines
72 KiB
C#
/*
|
|
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;
|
|
using System.Diagnostics;
|
|
using System.Runtime.CompilerServices;
|
|
using Iced.Intel.InstructionInfoInternal;
|
|
|
|
namespace Iced.Intel {
|
|
/// <summary>
|
|
/// Instruction info options
|
|
/// </summary>
|
|
[Flags]
|
|
public enum InstructionInfoOptions : uint {
|
|
/// <summary>
|
|
/// No option is enabled
|
|
/// </summary>
|
|
None = 0,
|
|
|
|
/// <summary>
|
|
/// Don't include memory usage, eg. <see cref="InstructionInfo.GetUsedMemory"/> will return an empty iterator. All
|
|
/// registers that are used by memory operands are still returned by <see cref="InstructionInfo.GetUsedRegisters"/>.
|
|
/// </summary>
|
|
NoMemoryUsage = 0x00000001,
|
|
|
|
/// <summary>
|
|
/// Don't include register usage, eg. <see cref="InstructionInfo.GetUsedRegisters"/> will return an empty iterator
|
|
/// </summary>
|
|
NoRegisterUsage = 0x00000002,
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates <see cref="InstructionInfo"/>s but minimizes allocations
|
|
/// </summary>
|
|
public sealed class InstructionInfoFactory {
|
|
const int defaultRegisterArrayCount = 2;
|
|
const int defaultMemoryArrayCount = 1;
|
|
|
|
SimpleList<UsedRegister> usedRegisters;
|
|
SimpleList<UsedMemory> usedMemoryLocations;
|
|
|
|
[Flags]
|
|
enum Flags : uint {
|
|
None = 0,
|
|
NoMemoryUsage = 0x00000001,
|
|
NoRegisterUsage = 0x00000002,
|
|
Is64Bit = 0x00000004,
|
|
ZeroExtVecRegs = 0x00000008,
|
|
}
|
|
|
|
/// <summary>
|
|
/// Constructor
|
|
/// </summary>
|
|
public InstructionInfoFactory() {
|
|
usedRegisters = new SimpleList<UsedRegister>(new UsedRegister[10]);
|
|
usedMemoryLocations = new SimpleList<UsedMemory>(new UsedMemory[8]);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates an <see cref="InstructionInfo"/>. The return value is only valid until this instance creates a new <see cref="InstructionInfo"/> value.
|
|
/// </summary>
|
|
/// <param name="instruction">Instruction</param>
|
|
/// <returns></returns>
|
|
public InstructionInfo GetInfo(ref Instruction instruction) =>
|
|
Create(ref instruction, ref usedRegisters, ref usedMemoryLocations, InstructionInfoOptions.None);
|
|
|
|
/// <summary>
|
|
/// Creates an <see cref="InstructionInfo"/>. The return value is only valid until this instance creates a new <see cref="InstructionInfo"/> value.
|
|
/// </summary>
|
|
/// <param name="instruction">Instruction</param>
|
|
/// <param name="options">Options</param>
|
|
/// <returns></returns>
|
|
public InstructionInfo GetInfo(ref Instruction instruction, InstructionInfoOptions options) =>
|
|
Create(ref instruction, ref usedRegisters, ref usedMemoryLocations, options);
|
|
|
|
internal unsafe static InstructionInfo Create(ref Instruction instruction, ref SimpleList<UsedRegister> usedRegisters, ref SimpleList<UsedMemory> usedMemoryLocations, InstructionInfoOptions options) {
|
|
usedRegisters.ValidLength = 0;
|
|
usedMemoryLocations.ValidLength = 0;
|
|
|
|
var code = instruction.Code;
|
|
var index = (int)code << 1;
|
|
var flags1 = InfoHandlers.Data[index];
|
|
var flags2 = InfoHandlers.Data[index + 1];
|
|
|
|
if (instruction.Op1Kind == OpKind.Register && (code == Code.VEX_Vbroadcastss_xmm_xmmm32 || code == Code.VEX_Vbroadcastss_ymm_xmmm32 || code == Code.VEX_Vbroadcastsd_ymm_xmmm64)) {
|
|
flags2 = (flags2 & ~((uint)InfoFlags2.CpuidFeatureMask << (int)InfoFlags2.CpuidFeatureShift)) |
|
|
((uint)CpuidFeature.AVX2 << (int)InfoFlags2.CpuidFeatureShift);
|
|
}
|
|
|
|
var codeSize = instruction.CodeSize;
|
|
Debug.Assert((uint)InstructionInfoOptions.NoMemoryUsage == (uint)Flags.NoMemoryUsage);
|
|
Debug.Assert((uint)InstructionInfoOptions.NoRegisterUsage == (uint)Flags.NoRegisterUsage);
|
|
var flags = (Flags)options & (Flags.NoMemoryUsage | Flags.NoRegisterUsage);
|
|
if (codeSize == CodeSize.Code64 || codeSize == CodeSize.Unknown)
|
|
flags |= Flags.Is64Bit;
|
|
if ((flags2 & ((uint)InfoFlags2.EncodingMask << (int)InfoFlags2.EncodingShift)) != ((uint)EncodingKind.Legacy << (int)InfoFlags2.EncodingShift))
|
|
flags |= Flags.ZeroExtVecRegs;
|
|
|
|
OpAccess op0Access;
|
|
switch ((OpInfo0)(flags2 & (uint)InfoFlags2.OpInfo0Mask)) {
|
|
default:
|
|
case OpInfo0.None:
|
|
op0Access = OpAccess.None;
|
|
break;
|
|
|
|
case OpInfo0.Read:
|
|
op0Access = OpAccess.Read;
|
|
break;
|
|
|
|
case OpInfo0.Write:
|
|
if (instruction.HasOpMask && instruction.MergingMasking)
|
|
op0Access = OpAccess.ReadWrite;
|
|
else
|
|
op0Access = OpAccess.Write;
|
|
break;
|
|
|
|
case OpInfo0.WriteForce:
|
|
op0Access = OpAccess.Write;
|
|
break;
|
|
|
|
case OpInfo0.CondWrite:
|
|
op0Access = OpAccess.CondWrite;
|
|
break;
|
|
|
|
case OpInfo0.CondWrite32_ReadWrite64:
|
|
if ((flags & Flags.Is64Bit) != 0)
|
|
op0Access = OpAccess.ReadWrite;
|
|
else
|
|
op0Access = OpAccess.CondWrite;
|
|
break;
|
|
|
|
case OpInfo0.ReadWrite:
|
|
op0Access = OpAccess.ReadWrite;
|
|
break;
|
|
|
|
case OpInfo0.ReadCondWrite:
|
|
op0Access = OpAccess.ReadCondWrite;
|
|
break;
|
|
|
|
case OpInfo0.NoMemAccess:
|
|
op0Access = OpAccess.NoMemAccess;
|
|
break;
|
|
|
|
case OpInfo0.WriteMem_ReadWriteReg:
|
|
if (instruction.Op0Kind != OpKind.Register || instruction.Op1Kind != OpKind.Register)
|
|
op0Access = OpAccess.Write;
|
|
else
|
|
op0Access = OpAccess.ReadWrite;
|
|
break;
|
|
}
|
|
|
|
var rflagsInfo = (RflagsInfo)((flags1 >> (int)InfoFlags1.RflagsInfoShift) & (uint)InfoFlags1.RflagsInfoMask);
|
|
|
|
var op1info = (OpInfo1)((flags2 >> (int)InfoFlags2.OpInfo1Shift) & (uint)InfoFlags2.OpInfo1Mask);
|
|
Debug.Assert(instruction.OpCount <= DecoderConstants.MaxOpCount);
|
|
var accesses = stackalloc OpAccess[DecoderConstants.MaxOpCount] {
|
|
op0Access,
|
|
InfoHandlers.Op1Accesses[(int)op1info],
|
|
InfoHandlers.Op2Accesses[(int)((flags2 >> (int)InfoFlags2.OpInfo2Shift) & (uint)InfoFlags2.OpInfo2Mask)],
|
|
InfoHandlers.Op3Accesses[(int)((flags2 >> (int)InfoFlags2.OpInfo3Shift) & (uint)InfoFlags2.OpInfo3Mask)],
|
|
InfoHandlers.Op4Accesses[(int)((flags2 >> (int)InfoFlags2.OpInfo4Shift) & (uint)InfoFlags2.OpInfo4Mask)],
|
|
};
|
|
|
|
int opCount = instruction.OpCount;
|
|
for (int i = 0; i < opCount; i++) {
|
|
var access = accesses[i];
|
|
if (access == OpAccess.None)
|
|
continue;
|
|
|
|
switch (instruction.GetOpKind(i)) {
|
|
case OpKind.Register:
|
|
if (access == OpAccess.NoMemAccess) {
|
|
access = OpAccess.Read;
|
|
accesses[i] = OpAccess.Read;
|
|
}
|
|
if ((flags & Flags.NoRegisterUsage) == 0) {
|
|
if (i == 1 && op1info == OpInfo1.ReadP3) {
|
|
var reg = instruction.Op1Register;
|
|
Debug.Assert(Register.XMM0 <= reg && reg <= InstructionInfoConstants.VMM_last);
|
|
reg = InstructionInfoConstants.VMM_first + ((reg - InstructionInfoConstants.VMM_first) & ~3);
|
|
for (int j = 0; j < 4; j++)
|
|
AddRegister(flags, ref usedRegisters, reg + j, access);
|
|
}
|
|
else
|
|
AddRegister(flags, ref usedRegisters, instruction.GetOpRegister(i), access);
|
|
}
|
|
break;
|
|
|
|
case OpKind.Memory64:
|
|
if ((flags & Flags.NoMemoryUsage) == 0)
|
|
AddMemory(flags, ref usedMemoryLocations, instruction.MemorySegment, Register.None, Register.None, 1, instruction.MemoryAddress64, instruction.MemorySize, access);
|
|
if ((flags & Flags.NoRegisterUsage) == 0)
|
|
AddMemorySegmentRegister(flags, ref usedRegisters, instruction.MemorySegment, OpAccess.Read);
|
|
break;
|
|
|
|
case OpKind.Memory:
|
|
Debug.Assert((uint)InfoFlags1.NoSegmentRead == (1U << 31));
|
|
Debug.Assert(Register.None == 0);
|
|
var segReg = (Register)((uint)instruction.MemorySegment & ~(uint)((int)flags1 >> 31));
|
|
var baseReg = instruction.MemoryBase;
|
|
if (baseReg == Register.RIP) {
|
|
if ((flags & Flags.NoMemoryUsage) == 0)
|
|
AddMemory(flags, ref usedMemoryLocations, segReg, Register.None, Register.None, 1, instruction.NextIP64 + (ulong)(int)instruction.MemoryDisplacement, instruction.MemorySize, access);
|
|
if ((flags & Flags.NoRegisterUsage) == 0 && segReg != Register.None)
|
|
AddMemorySegmentRegister(flags, ref usedRegisters, segReg, OpAccess.Read);
|
|
}
|
|
else if (baseReg == Register.EIP) {
|
|
if ((flags & Flags.NoMemoryUsage) == 0)
|
|
AddMemory(flags, ref usedMemoryLocations, segReg, Register.None, Register.None, 1, instruction.NextIP32 + instruction.MemoryDisplacement, instruction.MemorySize, access);
|
|
if ((flags & Flags.NoRegisterUsage) == 0 && segReg != Register.None)
|
|
AddMemorySegmentRegister(flags, ref usedRegisters, segReg, OpAccess.Read);
|
|
}
|
|
else {
|
|
ulong displ;
|
|
var indexReg = instruction.MemoryIndex;
|
|
if (InstructionUtils.GetAddressSizeInBytes(baseReg, indexReg, instruction.MemoryDisplSize, codeSize) == 8)
|
|
displ = (ulong)(int)instruction.MemoryDisplacement;
|
|
else
|
|
displ = instruction.MemoryDisplacement;
|
|
if ((flags & Flags.NoMemoryUsage) == 0)
|
|
AddMemory(flags, ref usedMemoryLocations, segReg, baseReg, indexReg, instruction.MemoryIndexScale, displ, instruction.MemorySize, access);
|
|
if ((flags & Flags.NoRegisterUsage) == 0) {
|
|
if (segReg != Register.None)
|
|
AddMemorySegmentRegister(flags, ref usedRegisters, segReg, OpAccess.Read);
|
|
if (baseReg != Register.None)
|
|
AddRegister(flags, ref usedRegisters, baseReg, OpAccess.Read);
|
|
if (indexReg != Register.None)
|
|
AddRegister(flags, ref usedRegisters, indexReg, OpAccess.Read);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
var codeInfo = (CodeInfo)((flags1 >> (int)InfoFlags1.CodeInfoShift) & (uint)InfoFlags1.CodeInfoMask);
|
|
if (codeInfo != CodeInfo.None)
|
|
CodeInfoHandler(codeInfo, ref instruction, ref usedRegisters, ref usedMemoryLocations, ref rflagsInfo, flags, accesses);
|
|
|
|
if (instruction.HasOpMask && (flags & Flags.NoRegisterUsage) == 0)
|
|
AddRegister(flags, ref usedRegisters, instruction.OpMask, (flags2 & (uint)InfoFlags2.OpMaskRegReadWrite) != 0 ? OpAccess.ReadWrite : OpAccess.Read);
|
|
|
|
uint opMaskFlags = (uint)accesses[0] |
|
|
((uint)accesses[1] << (int)InstructionInfo.OpMaskFlags.Op1AccessShift) |
|
|
((uint)accesses[2] << (int)InstructionInfo.OpMaskFlags.Op2AccessShift) |
|
|
((uint)accesses[3] << (int)InstructionInfo.OpMaskFlags.Op3AccessShift) |
|
|
((uint)accesses[4] << (int)InstructionInfo.OpMaskFlags.Op4AccessShift);
|
|
|
|
return new InstructionInfo(ref usedRegisters, ref usedMemoryLocations, opMaskFlags, rflagsInfo, flags1, flags2);
|
|
}
|
|
|
|
static Register GetXSP(CodeSize codeSize, out ulong xspMask) {
|
|
if (codeSize == CodeSize.Code64 || codeSize == CodeSize.Unknown) {
|
|
xspMask = ulong.MaxValue;
|
|
return Register.RSP;
|
|
}
|
|
if (codeSize == CodeSize.Code32) {
|
|
xspMask = uint.MaxValue;
|
|
return Register.ESP;
|
|
}
|
|
Debug.Assert(codeSize == CodeSize.Code16);
|
|
xspMask = ushort.MaxValue;
|
|
return Register.SP;
|
|
}
|
|
|
|
static unsafe void CodeInfoHandler(CodeInfo codeInfo, ref Instruction instruction, ref SimpleList<UsedRegister> usedRegisters, ref SimpleList<UsedMemory> usedMemoryLocations, ref RflagsInfo rflagsInfo, Flags flags, OpAccess* accesses) {
|
|
Debug.Assert(codeInfo != CodeInfo.None);
|
|
ulong xspMask;
|
|
ulong displ;
|
|
Register xsp;
|
|
Register baseReg;
|
|
MemorySize memSize;
|
|
Code code;
|
|
switch (codeInfo) {
|
|
case CodeInfo.RW_AX:
|
|
if ((flags & Flags.NoRegisterUsage) == 0)
|
|
AddRegister(flags, ref usedRegisters, Register.AX, OpAccess.ReadWrite);
|
|
break;
|
|
|
|
case CodeInfo.RW_AL:
|
|
if ((flags & Flags.NoRegisterUsage) == 0)
|
|
AddRegister(flags, ref usedRegisters, Register.AL, OpAccess.ReadWrite);
|
|
break;
|
|
|
|
case CodeInfo.Salc:
|
|
if ((flags & Flags.NoRegisterUsage) == 0)
|
|
AddRegister(flags, ref usedRegisters, Register.AL, OpAccess.Write);
|
|
break;
|
|
|
|
case CodeInfo.R_AL_W_AH:
|
|
if ((flags & Flags.NoRegisterUsage) == 0) {
|
|
AddRegister(flags, ref usedRegisters, Register.AL, OpAccess.Read);
|
|
AddRegister(flags, ref usedRegisters, Register.AH, OpAccess.Write);
|
|
}
|
|
break;
|
|
|
|
case CodeInfo.R_AL_W_AX:
|
|
if ((flags & Flags.NoRegisterUsage) == 0) {
|
|
AddRegister(flags, ref usedRegisters, Register.AL, OpAccess.Read);
|
|
AddRegister(flags, ref usedRegisters, Register.AX, OpAccess.Write);
|
|
}
|
|
break;
|
|
|
|
case CodeInfo.Cwde:
|
|
if ((flags & Flags.NoRegisterUsage) == 0) {
|
|
AddRegister(flags, ref usedRegisters, Register.AX, OpAccess.Read);
|
|
AddRegister(flags, ref usedRegisters, Register.EAX, OpAccess.Write);
|
|
}
|
|
break;
|
|
|
|
case CodeInfo.Cdqe:
|
|
if ((flags & Flags.NoRegisterUsage) == 0) {
|
|
AddRegister(flags, ref usedRegisters, Register.EAX, OpAccess.Read);
|
|
AddRegister(flags, ref usedRegisters, Register.RAX, OpAccess.Write);
|
|
}
|
|
break;
|
|
|
|
case CodeInfo.Cwd:
|
|
if ((flags & Flags.NoRegisterUsage) == 0) {
|
|
AddRegister(flags, ref usedRegisters, Register.AX, OpAccess.Read);
|
|
AddRegister(flags, ref usedRegisters, Register.DX, OpAccess.Write);
|
|
}
|
|
break;
|
|
|
|
case CodeInfo.Cdq:
|
|
if ((flags & Flags.NoRegisterUsage) == 0) {
|
|
AddRegister(flags, ref usedRegisters, Register.EAX, OpAccess.Read);
|
|
AddRegister(flags, ref usedRegisters, Register.EDX, OpAccess.Write);
|
|
}
|
|
break;
|
|
|
|
case CodeInfo.Cqo:
|
|
if ((flags & Flags.NoRegisterUsage) == 0) {
|
|
AddRegister(flags, ref usedRegisters, Register.RAX, OpAccess.Read);
|
|
AddRegister(flags, ref usedRegisters, Register.RDX, OpAccess.Write);
|
|
}
|
|
break;
|
|
|
|
case CodeInfo.R_XMM0:
|
|
if ((flags & Flags.NoRegisterUsage) == 0)
|
|
AddRegister(flags, ref usedRegisters, Register.XMM0, OpAccess.Read);
|
|
break;
|
|
|
|
case CodeInfo.Push_2:
|
|
xsp = GetXSP(instruction.CodeSize, out xspMask);
|
|
if ((flags & Flags.NoRegisterUsage) == 0) {
|
|
if ((flags & Flags.Is64Bit) == 0)
|
|
AddRegister(flags, ref usedRegisters, Register.SS, OpAccess.Read);
|
|
AddRegister(flags, ref usedRegisters, xsp, OpAccess.ReadWrite);
|
|
}
|
|
if ((flags & Flags.NoMemoryUsage) == 0)
|
|
AddMemory(flags, ref usedMemoryLocations, Register.SS, xsp, Register.None, 1, 0xFFFF_FFFF_FFFF_FFFE & xspMask, MemorySize.UInt16, OpAccess.Write);
|
|
break;
|
|
|
|
case CodeInfo.Push_4:
|
|
xsp = GetXSP(instruction.CodeSize, out xspMask);
|
|
if ((flags & Flags.NoRegisterUsage) == 0) {
|
|
if ((flags & Flags.Is64Bit) == 0)
|
|
AddRegister(flags, ref usedRegisters, Register.SS, OpAccess.Read);
|
|
AddRegister(flags, ref usedRegisters, xsp, OpAccess.ReadWrite);
|
|
}
|
|
if ((flags & Flags.NoMemoryUsage) == 0)
|
|
AddMemory(flags, ref usedMemoryLocations, Register.SS, xsp, Register.None, 1, 0xFFFF_FFFF_FFFF_FFFC & xspMask, MemorySize.UInt32, OpAccess.Write);
|
|
break;
|
|
|
|
case CodeInfo.Push_8:
|
|
xsp = GetXSP(instruction.CodeSize, out xspMask);
|
|
if ((flags & Flags.NoRegisterUsage) == 0) {
|
|
if ((flags & Flags.Is64Bit) == 0)
|
|
AddRegister(flags, ref usedRegisters, Register.SS, OpAccess.Read);
|
|
AddRegister(flags, ref usedRegisters, xsp, OpAccess.ReadWrite);
|
|
}
|
|
if ((flags & Flags.NoMemoryUsage) == 0)
|
|
AddMemory(flags, ref usedMemoryLocations, Register.SS, xsp, Register.None, 1, 0xFFFF_FFFF_FFFF_FFF8 & xspMask, MemorySize.UInt64, OpAccess.Write);
|
|
break;
|
|
|
|
case CodeInfo.Push_2_2:
|
|
xsp = GetXSP(instruction.CodeSize, out xspMask);
|
|
if ((flags & Flags.NoRegisterUsage) == 0) {
|
|
if ((flags & Flags.Is64Bit) == 0)
|
|
AddRegister(flags, ref usedRegisters, Register.SS, OpAccess.Read);
|
|
AddRegister(flags, ref usedRegisters, xsp, OpAccess.ReadWrite);
|
|
}
|
|
if ((flags & Flags.NoMemoryUsage) == 0) {
|
|
AddMemory(flags, ref usedMemoryLocations, Register.SS, xsp, Register.None, 1, 0xFFFF_FFFF_FFFF_FFFE & xspMask, MemorySize.UInt16, OpAccess.Write);
|
|
AddMemory(flags, ref usedMemoryLocations, Register.SS, xsp, Register.None, 1, 0xFFFF_FFFF_FFFF_FFFC & xspMask, MemorySize.UInt16, OpAccess.Write);
|
|
}
|
|
break;
|
|
|
|
case CodeInfo.Push_4_4:
|
|
xsp = GetXSP(instruction.CodeSize, out xspMask);
|
|
if ((flags & Flags.NoRegisterUsage) == 0) {
|
|
if ((flags & Flags.Is64Bit) == 0)
|
|
AddRegister(flags, ref usedRegisters, Register.SS, OpAccess.Read);
|
|
AddRegister(flags, ref usedRegisters, xsp, OpAccess.ReadWrite);
|
|
}
|
|
if ((flags & Flags.NoMemoryUsage) == 0) {
|
|
AddMemory(flags, ref usedMemoryLocations, Register.SS, xsp, Register.None, 1, 0xFFFF_FFFF_FFFF_FFFC & xspMask, MemorySize.UInt32, OpAccess.Write);
|
|
AddMemory(flags, ref usedMemoryLocations, Register.SS, xsp, Register.None, 1, 0xFFFF_FFFF_FFFF_FFF8 & xspMask, MemorySize.UInt32, OpAccess.Write);
|
|
}
|
|
break;
|
|
|
|
case CodeInfo.Push_8_8:
|
|
xsp = GetXSP(instruction.CodeSize, out xspMask);
|
|
if ((flags & Flags.NoRegisterUsage) == 0) {
|
|
if ((flags & Flags.Is64Bit) == 0)
|
|
AddRegister(flags, ref usedRegisters, Register.SS, OpAccess.Read);
|
|
AddRegister(flags, ref usedRegisters, xsp, OpAccess.ReadWrite);
|
|
}
|
|
if ((flags & Flags.NoMemoryUsage) == 0) {
|
|
AddMemory(flags, ref usedMemoryLocations, Register.SS, xsp, Register.None, 1, 0xFFFF_FFFF_FFFF_FFF8 & xspMask, MemorySize.UInt64, OpAccess.Write);
|
|
AddMemory(flags, ref usedMemoryLocations, Register.SS, xsp, Register.None, 1, 0xFFFF_FFFF_FFFF_FFF0 & xspMask, MemorySize.UInt64, OpAccess.Write);
|
|
}
|
|
break;
|
|
|
|
case CodeInfo.Pop_2:
|
|
xsp = GetXSP(instruction.CodeSize, out xspMask);
|
|
if ((flags & Flags.NoRegisterUsage) == 0) {
|
|
if ((flags & Flags.Is64Bit) == 0)
|
|
AddRegister(flags, ref usedRegisters, Register.SS, OpAccess.Read);
|
|
AddRegister(flags, ref usedRegisters, xsp, OpAccess.ReadWrite);
|
|
}
|
|
if ((flags & Flags.NoMemoryUsage) == 0)
|
|
AddMemory(flags, ref usedMemoryLocations, Register.SS, xsp, Register.None, 1, 0, MemorySize.UInt16, OpAccess.Read);
|
|
break;
|
|
|
|
case CodeInfo.Pop_4:
|
|
xsp = GetXSP(instruction.CodeSize, out xspMask);
|
|
if ((flags & Flags.NoRegisterUsage) == 0) {
|
|
if ((flags & Flags.Is64Bit) == 0)
|
|
AddRegister(flags, ref usedRegisters, Register.SS, OpAccess.Read);
|
|
AddRegister(flags, ref usedRegisters, xsp, OpAccess.ReadWrite);
|
|
}
|
|
if ((flags & Flags.NoMemoryUsage) == 0)
|
|
AddMemory(flags, ref usedMemoryLocations, Register.SS, xsp, Register.None, 1, 0, MemorySize.UInt32, OpAccess.Read);
|
|
break;
|
|
|
|
case CodeInfo.Pop_8:
|
|
xsp = GetXSP(instruction.CodeSize, out xspMask);
|
|
if ((flags & Flags.NoRegisterUsage) == 0) {
|
|
if ((flags & Flags.Is64Bit) == 0)
|
|
AddRegister(flags, ref usedRegisters, Register.SS, OpAccess.Read);
|
|
AddRegister(flags, ref usedRegisters, xsp, OpAccess.ReadWrite);
|
|
}
|
|
if ((flags & Flags.NoMemoryUsage) == 0)
|
|
AddMemory(flags, ref usedMemoryLocations, Register.SS, xsp, Register.None, 1, 0, MemorySize.UInt64, OpAccess.Read);
|
|
break;
|
|
|
|
case CodeInfo.Pop_2_2:
|
|
xsp = GetXSP(instruction.CodeSize, out xspMask);
|
|
if ((flags & Flags.NoRegisterUsage) == 0) {
|
|
if ((flags & Flags.Is64Bit) == 0)
|
|
AddRegister(flags, ref usedRegisters, Register.SS, OpAccess.Read);
|
|
AddRegister(flags, ref usedRegisters, xsp, OpAccess.ReadWrite);
|
|
}
|
|
if ((flags & Flags.NoMemoryUsage) == 0) {
|
|
AddMemory(flags, ref usedMemoryLocations, Register.SS, xsp, Register.None, 1, 0, MemorySize.UInt16, OpAccess.Read);
|
|
AddMemory(flags, ref usedMemoryLocations, Register.SS, xsp, Register.None, 1, 2, MemorySize.UInt16, OpAccess.Read);
|
|
}
|
|
break;
|
|
|
|
case CodeInfo.Pop_4_4:
|
|
xsp = GetXSP(instruction.CodeSize, out xspMask);
|
|
if ((flags & Flags.NoRegisterUsage) == 0) {
|
|
if ((flags & Flags.Is64Bit) == 0)
|
|
AddRegister(flags, ref usedRegisters, Register.SS, OpAccess.Read);
|
|
AddRegister(flags, ref usedRegisters, xsp, OpAccess.ReadWrite);
|
|
}
|
|
if ((flags & Flags.NoMemoryUsage) == 0) {
|
|
AddMemory(flags, ref usedMemoryLocations, Register.SS, xsp, Register.None, 1, 0, MemorySize.UInt32, OpAccess.Read);
|
|
AddMemory(flags, ref usedMemoryLocations, Register.SS, xsp, Register.None, 1, 4, MemorySize.UInt32, OpAccess.Read);
|
|
}
|
|
break;
|
|
|
|
case CodeInfo.Pop_8_8:
|
|
xsp = GetXSP(instruction.CodeSize, out xspMask);
|
|
if ((flags & Flags.NoRegisterUsage) == 0) {
|
|
if ((flags & Flags.Is64Bit) == 0)
|
|
AddRegister(flags, ref usedRegisters, Register.SS, OpAccess.Read);
|
|
AddRegister(flags, ref usedRegisters, xsp, OpAccess.ReadWrite);
|
|
}
|
|
if ((flags & Flags.NoMemoryUsage) == 0) {
|
|
AddMemory(flags, ref usedMemoryLocations, Register.SS, xsp, Register.None, 1, 0, MemorySize.UInt64, OpAccess.Read);
|
|
AddMemory(flags, ref usedMemoryLocations, Register.SS, xsp, Register.None, 1, 8, MemorySize.UInt64, OpAccess.Read);
|
|
}
|
|
break;
|
|
|
|
case CodeInfo.Pop_Ev:
|
|
xsp = GetXSP(instruction.CodeSize, out xspMask);
|
|
if ((flags & Flags.NoRegisterUsage) == 0) {
|
|
if ((flags & Flags.Is64Bit) == 0)
|
|
AddRegister(flags, ref usedRegisters, Register.SS, OpAccess.Read);
|
|
AddRegister(flags, ref usedRegisters, xsp, OpAccess.ReadWrite);
|
|
}
|
|
if ((flags & Flags.NoMemoryUsage) == 0) {
|
|
code = instruction.Code;
|
|
uint size;
|
|
if (code == Code.Pop_rm64) {
|
|
memSize = MemorySize.UInt64;
|
|
size = 8;
|
|
}
|
|
else if (code == Code.Pop_rm32) {
|
|
memSize = MemorySize.UInt32;
|
|
size = 4;
|
|
}
|
|
else {
|
|
Debug.Assert(instruction.Code == Code.Pop_rm16);
|
|
memSize = MemorySize.UInt16;
|
|
size = 2;
|
|
}
|
|
if (instruction.Op0Kind == OpKind.Memory) {
|
|
Debug.Assert(usedMemoryLocations.ValidLength == 1);
|
|
if (instruction.MemoryBase == Register.RSP || instruction.MemoryBase == Register.ESP) {
|
|
ref var mem = ref usedMemoryLocations.Array[0];
|
|
displ = mem.Displacement + size;
|
|
if (instruction.MemoryBase == Register.ESP)
|
|
displ = (uint)displ;
|
|
usedMemoryLocations.Array[0] = new UsedMemory(mem.Segment, mem.Base, mem.Index, mem.Scale, displ, mem.MemorySize, mem.Access);
|
|
}
|
|
}
|
|
AddMemory(flags, ref usedMemoryLocations, Register.SS, xsp, Register.None, 1, 0, memSize, OpAccess.Read);
|
|
}
|
|
break;
|
|
|
|
case CodeInfo.Pusha:
|
|
xsp = GetXSP(instruction.CodeSize, out xspMask);
|
|
if ((flags & Flags.NoRegisterUsage) == 0) {
|
|
if ((flags & Flags.Is64Bit) == 0)
|
|
AddRegister(flags, ref usedRegisters, Register.SS, OpAccess.Read);
|
|
AddRegister(flags, ref usedRegisters, xsp, OpAccess.ReadWrite);
|
|
}
|
|
if (instruction.Code == Code.Pushad) {
|
|
displ = 0xFFFF_FFFF_FFFF_FFFC;
|
|
memSize = MemorySize.UInt32;
|
|
baseReg = Register.EAX;
|
|
}
|
|
else {
|
|
Debug.Assert(instruction.Code == Code.Pushaw);
|
|
displ = 0xFFFF_FFFF_FFFF_FFFE;
|
|
memSize = MemorySize.UInt16;
|
|
baseReg = Register.AX;
|
|
}
|
|
for (int i = 0; i < 8; i++) {
|
|
if ((flags & Flags.NoRegisterUsage) == 0)
|
|
AddRegister(flags, ref usedRegisters, baseReg + i, OpAccess.Read);
|
|
if ((flags & Flags.NoMemoryUsage) == 0)
|
|
AddMemory(flags, ref usedMemoryLocations, Register.SS, xsp, Register.None, 1, (ulong)((long)displ * (i + 1)) & xspMask, memSize, OpAccess.Write);
|
|
}
|
|
break;
|
|
|
|
case CodeInfo.Popa:
|
|
xsp = GetXSP(instruction.CodeSize, out xspMask);
|
|
if ((flags & Flags.NoRegisterUsage) == 0) {
|
|
if ((flags & Flags.Is64Bit) == 0)
|
|
AddRegister(flags, ref usedRegisters, Register.SS, OpAccess.Read);
|
|
AddRegister(flags, ref usedRegisters, xsp, OpAccess.ReadWrite);
|
|
}
|
|
if (instruction.Code == Code.Popad) {
|
|
displ = 4;
|
|
memSize = MemorySize.UInt32;
|
|
baseReg = Register.EAX;
|
|
}
|
|
else {
|
|
Debug.Assert(instruction.Code == Code.Popaw);
|
|
displ = 2;
|
|
memSize = MemorySize.UInt16;
|
|
baseReg = Register.AX;
|
|
}
|
|
for (int i = 0; i < 8; i++) {
|
|
// Ignore eSP
|
|
if (i != 3) {
|
|
if ((flags & Flags.NoRegisterUsage) == 0)
|
|
AddRegister(flags, ref usedRegisters, baseReg + 7 - i, OpAccess.Write);
|
|
if ((flags & Flags.NoMemoryUsage) == 0)
|
|
AddMemory(flags, ref usedMemoryLocations, Register.SS, xsp, Register.None, 1, displ * (uint)i & xspMask, memSize, OpAccess.Read);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case CodeInfo.Ins:
|
|
if (instruction.Internal_HasPrefixRepeOrRepne) {
|
|
accesses[0] = OpAccess.CondWrite;
|
|
accesses[1] = OpAccess.CondRead;
|
|
Debug.Assert(OpKind.MemoryESDI + 1 == OpKind.MemoryESEDI);
|
|
Debug.Assert(OpKind.MemoryESDI + 2 == OpKind.MemoryESRDI);
|
|
Debug.Assert(Register.DI + 16 == Register.EDI);
|
|
Debug.Assert(Register.DI + 32 == Register.RDI);
|
|
Debug.Assert(Register.CX + 16 == Register.ECX);
|
|
Debug.Assert(Register.CX + 32 == Register.RCX);
|
|
baseReg = ((instruction.Op0Kind - OpKind.MemoryESDI) << 4) + Register.DI;
|
|
if ((flags & Flags.NoMemoryUsage) == 0)
|
|
AddMemory(flags, ref usedMemoryLocations, Register.ES, baseReg, Register.None, 1, 0, MemorySize.Unknown, OpAccess.CondWrite);
|
|
if ((flags & Flags.NoRegisterUsage) == 0) {
|
|
Debug.Assert(usedRegisters.ValidLength == 1);
|
|
usedRegisters.Array[0] = new UsedRegister(Register.DX, OpAccess.CondRead);
|
|
AddRegister(flags, ref usedRegisters, ((instruction.Op0Kind - OpKind.MemoryESDI) << 4) + Register.CX, OpAccess.ReadCondWrite);
|
|
if ((flags & Flags.Is64Bit) == 0)
|
|
AddRegister(flags, ref usedRegisters, Register.ES, OpAccess.CondRead);
|
|
AddRegister(flags, ref usedRegisters, baseReg, OpAccess.CondRead);
|
|
AddRegister(flags, ref usedRegisters, baseReg, OpAccess.CondWrite);
|
|
}
|
|
}
|
|
else {
|
|
Debug.Assert(OpKind.MemoryESDI + 1 == OpKind.MemoryESEDI);
|
|
Debug.Assert(OpKind.MemoryESDI + 2 == OpKind.MemoryESRDI);
|
|
Debug.Assert(Register.DI + 16 == Register.EDI);
|
|
Debug.Assert(Register.DI + 32 == Register.RDI);
|
|
baseReg = ((instruction.Op0Kind - OpKind.MemoryESDI) << 4) + Register.DI;
|
|
if ((flags & Flags.NoMemoryUsage) == 0)
|
|
AddMemory(flags, ref usedMemoryLocations, Register.ES, baseReg, Register.None, 1, 0, instruction.MemorySize, OpAccess.Write);
|
|
if ((flags & Flags.NoRegisterUsage) == 0) {
|
|
if ((flags & Flags.Is64Bit) == 0)
|
|
AddRegister(flags, ref usedRegisters, Register.ES, OpAccess.Read);
|
|
AddRegister(flags, ref usedRegisters, baseReg, OpAccess.ReadWrite);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case CodeInfo.Outs:
|
|
if (instruction.Internal_HasPrefixRepeOrRepne) {
|
|
accesses[0] = OpAccess.CondRead;
|
|
accesses[1] = OpAccess.CondRead;
|
|
Debug.Assert(OpKind.MemorySegSI + 1 == OpKind.MemorySegESI);
|
|
Debug.Assert(OpKind.MemorySegSI + 2 == OpKind.MemorySegRSI);
|
|
Debug.Assert(Register.SI + 16 == Register.ESI);
|
|
Debug.Assert(Register.SI + 32 == Register.RSI);
|
|
Debug.Assert(Register.CX + 16 == Register.ECX);
|
|
Debug.Assert(Register.CX + 32 == Register.RCX);
|
|
baseReg = ((instruction.Op1Kind - OpKind.MemorySegSI) << 4) + Register.SI;
|
|
if ((flags & Flags.NoMemoryUsage) == 0)
|
|
AddMemory(flags, ref usedMemoryLocations, instruction.MemorySegment, baseReg, Register.None, 1, 0, MemorySize.Unknown, OpAccess.CondRead);
|
|
if ((flags & Flags.NoRegisterUsage) == 0) {
|
|
Debug.Assert(usedRegisters.ValidLength == 1);
|
|
usedRegisters.Array[0] = new UsedRegister(Register.DX, OpAccess.CondRead);
|
|
AddRegister(flags, ref usedRegisters, ((instruction.Op1Kind - OpKind.MemorySegSI) << 4) + Register.CX, OpAccess.ReadCondWrite);
|
|
AddMemorySegmentRegister(flags, ref usedRegisters, instruction.MemorySegment, OpAccess.CondRead);
|
|
AddRegister(flags, ref usedRegisters, baseReg, OpAccess.CondRead);
|
|
AddRegister(flags, ref usedRegisters, baseReg, OpAccess.CondWrite);
|
|
}
|
|
}
|
|
else {
|
|
Debug.Assert(OpKind.MemorySegSI + 1 == OpKind.MemorySegESI);
|
|
Debug.Assert(OpKind.MemorySegSI + 2 == OpKind.MemorySegRSI);
|
|
Debug.Assert(Register.SI + 16 == Register.ESI);
|
|
Debug.Assert(Register.SI + 32 == Register.RSI);
|
|
baseReg = ((instruction.Op1Kind - OpKind.MemorySegSI) << 4) + Register.SI;
|
|
if ((flags & Flags.NoMemoryUsage) == 0)
|
|
AddMemory(flags, ref usedMemoryLocations, instruction.MemorySegment, baseReg, Register.None, 1, 0, instruction.MemorySize, OpAccess.Read);
|
|
if ((flags & Flags.NoRegisterUsage) == 0) {
|
|
AddMemorySegmentRegister(flags, ref usedRegisters, instruction.MemorySegment, OpAccess.Read);
|
|
AddRegister(flags, ref usedRegisters, baseReg, OpAccess.ReadWrite);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case CodeInfo.Movs:
|
|
if (instruction.Internal_HasPrefixRepeOrRepne) {
|
|
accesses[0] = OpAccess.CondWrite;
|
|
accesses[1] = OpAccess.CondRead;
|
|
Debug.Assert(OpKind.MemoryESDI + 1 == OpKind.MemoryESEDI);
|
|
Debug.Assert(OpKind.MemoryESDI + 2 == OpKind.MemoryESRDI);
|
|
Debug.Assert(Register.DI + 16 == Register.EDI);
|
|
Debug.Assert(Register.DI + 32 == Register.RDI);
|
|
Debug.Assert(Register.CX + 16 == Register.ECX);
|
|
Debug.Assert(Register.CX + 32 == Register.RCX);
|
|
baseReg = ((instruction.Op0Kind - OpKind.MemoryESDI) << 4) + Register.DI;
|
|
if ((flags & Flags.NoMemoryUsage) == 0)
|
|
AddMemory(flags, ref usedMemoryLocations, Register.ES, baseReg, Register.None, 1, 0, MemorySize.Unknown, OpAccess.CondWrite);
|
|
if ((flags & Flags.NoRegisterUsage) == 0) {
|
|
AddRegister(flags, ref usedRegisters, ((instruction.Op0Kind - OpKind.MemoryESDI) << 4) + Register.CX, OpAccess.ReadCondWrite);
|
|
if ((flags & Flags.Is64Bit) == 0)
|
|
AddRegister(flags, ref usedRegisters, Register.ES, OpAccess.CondRead);
|
|
AddRegister(flags, ref usedRegisters, baseReg, OpAccess.CondRead);
|
|
AddRegister(flags, ref usedRegisters, baseReg, OpAccess.CondWrite);
|
|
}
|
|
Debug.Assert(OpKind.MemorySegSI + 1 == OpKind.MemorySegESI);
|
|
Debug.Assert(OpKind.MemorySegSI + 2 == OpKind.MemorySegRSI);
|
|
Debug.Assert(Register.SI + 16 == Register.ESI);
|
|
Debug.Assert(Register.SI + 32 == Register.RSI);
|
|
baseReg = ((instruction.Op1Kind - OpKind.MemorySegSI) << 4) + Register.SI;
|
|
if ((flags & Flags.NoMemoryUsage) == 0)
|
|
AddMemory(flags, ref usedMemoryLocations, instruction.MemorySegment, baseReg, Register.None, 1, 0, MemorySize.Unknown, OpAccess.CondRead);
|
|
if ((flags & Flags.NoRegisterUsage) == 0) {
|
|
AddMemorySegmentRegister(flags, ref usedRegisters, instruction.MemorySegment, OpAccess.CondRead);
|
|
AddRegister(flags, ref usedRegisters, baseReg, OpAccess.CondRead);
|
|
AddRegister(flags, ref usedRegisters, baseReg, OpAccess.CondWrite);
|
|
}
|
|
}
|
|
else {
|
|
Debug.Assert(OpKind.MemoryESDI + 1 == OpKind.MemoryESEDI);
|
|
Debug.Assert(OpKind.MemoryESDI + 2 == OpKind.MemoryESRDI);
|
|
Debug.Assert(Register.DI + 16 == Register.EDI);
|
|
Debug.Assert(Register.DI + 32 == Register.RDI);
|
|
baseReg = ((instruction.Op0Kind - OpKind.MemoryESDI) << 4) + Register.DI;
|
|
if ((flags & Flags.NoMemoryUsage) == 0)
|
|
AddMemory(flags, ref usedMemoryLocations, Register.ES, baseReg, Register.None, 1, 0, instruction.MemorySize, OpAccess.Write);
|
|
if ((flags & Flags.NoRegisterUsage) == 0) {
|
|
if ((flags & Flags.Is64Bit) == 0)
|
|
AddRegister(flags, ref usedRegisters, Register.ES, OpAccess.Read);
|
|
AddRegister(flags, ref usedRegisters, baseReg, OpAccess.ReadWrite);
|
|
}
|
|
Debug.Assert(OpKind.MemorySegSI + 1 == OpKind.MemorySegESI);
|
|
Debug.Assert(OpKind.MemorySegSI + 2 == OpKind.MemorySegRSI);
|
|
Debug.Assert(Register.SI + 16 == Register.ESI);
|
|
Debug.Assert(Register.SI + 32 == Register.RSI);
|
|
baseReg = ((instruction.Op1Kind - OpKind.MemorySegSI) << 4) + Register.SI;
|
|
if ((flags & Flags.NoMemoryUsage) == 0)
|
|
AddMemory(flags, ref usedMemoryLocations, instruction.MemorySegment, baseReg, Register.None, 1, 0, instruction.MemorySize, OpAccess.Read);
|
|
if ((flags & Flags.NoRegisterUsage) == 0) {
|
|
AddMemorySegmentRegister(flags, ref usedRegisters, instruction.MemorySegment, OpAccess.Read);
|
|
AddRegister(flags, ref usedRegisters, baseReg, OpAccess.ReadWrite);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case CodeInfo.Cmps:
|
|
if (instruction.Internal_HasPrefixRepeOrRepne) {
|
|
accesses[0] = OpAccess.CondRead;
|
|
accesses[1] = OpAccess.CondRead;
|
|
Debug.Assert(OpKind.MemorySegSI + 1 == OpKind.MemorySegESI);
|
|
Debug.Assert(OpKind.MemorySegSI + 2 == OpKind.MemorySegRSI);
|
|
Debug.Assert(Register.SI + 16 == Register.ESI);
|
|
Debug.Assert(Register.SI + 32 == Register.RSI);
|
|
Debug.Assert(Register.CX + 16 == Register.ECX);
|
|
Debug.Assert(Register.CX + 32 == Register.RCX);
|
|
baseReg = ((instruction.Op0Kind - OpKind.MemorySegSI) << 4) + Register.SI;
|
|
if ((flags & Flags.NoMemoryUsage) == 0)
|
|
AddMemory(flags, ref usedMemoryLocations, instruction.MemorySegment, baseReg, Register.None, 1, 0, MemorySize.Unknown, OpAccess.CondRead);
|
|
if ((flags & Flags.NoRegisterUsage) == 0) {
|
|
AddRegister(flags, ref usedRegisters, ((instruction.Op0Kind - OpKind.MemorySegSI) << 4) + Register.CX, OpAccess.ReadCondWrite);
|
|
AddMemorySegmentRegister(flags, ref usedRegisters, instruction.MemorySegment, OpAccess.CondRead);
|
|
AddRegister(flags, ref usedRegisters, baseReg, OpAccess.CondRead);
|
|
AddRegister(flags, ref usedRegisters, baseReg, OpAccess.CondWrite);
|
|
}
|
|
Debug.Assert(OpKind.MemoryESDI + 1 == OpKind.MemoryESEDI);
|
|
Debug.Assert(OpKind.MemoryESDI + 2 == OpKind.MemoryESRDI);
|
|
Debug.Assert(Register.DI + 16 == Register.EDI);
|
|
Debug.Assert(Register.DI + 32 == Register.RDI);
|
|
baseReg = ((instruction.Op1Kind - OpKind.MemoryESDI) << 4) + Register.DI;
|
|
if ((flags & Flags.NoMemoryUsage) == 0)
|
|
AddMemory(flags, ref usedMemoryLocations, Register.ES, baseReg, Register.None, 1, 0, MemorySize.Unknown, OpAccess.CondRead);
|
|
if ((flags & Flags.NoRegisterUsage) == 0) {
|
|
if ((flags & Flags.Is64Bit) == 0)
|
|
AddRegister(flags, ref usedRegisters, Register.ES, OpAccess.CondRead);
|
|
AddRegister(flags, ref usedRegisters, baseReg, OpAccess.CondRead);
|
|
AddRegister(flags, ref usedRegisters, baseReg, OpAccess.CondWrite);
|
|
}
|
|
}
|
|
else {
|
|
Debug.Assert(OpKind.MemorySegSI + 1 == OpKind.MemorySegESI);
|
|
Debug.Assert(OpKind.MemorySegSI + 2 == OpKind.MemorySegRSI);
|
|
Debug.Assert(Register.SI + 16 == Register.ESI);
|
|
Debug.Assert(Register.SI + 32 == Register.RSI);
|
|
baseReg = ((instruction.Op0Kind - OpKind.MemorySegSI) << 4) + Register.SI;
|
|
if ((flags & Flags.NoMemoryUsage) == 0)
|
|
AddMemory(flags, ref usedMemoryLocations, instruction.MemorySegment, baseReg, Register.None, 1, 0, instruction.MemorySize, OpAccess.Read);
|
|
if ((flags & Flags.NoRegisterUsage) == 0) {
|
|
AddMemorySegmentRegister(flags, ref usedRegisters, instruction.MemorySegment, OpAccess.Read);
|
|
AddRegister(flags, ref usedRegisters, baseReg, OpAccess.ReadWrite);
|
|
}
|
|
Debug.Assert(OpKind.MemoryESDI + 1 == OpKind.MemoryESEDI);
|
|
Debug.Assert(OpKind.MemoryESDI + 2 == OpKind.MemoryESRDI);
|
|
Debug.Assert(Register.DI + 16 == Register.EDI);
|
|
Debug.Assert(Register.DI + 32 == Register.RDI);
|
|
baseReg = ((instruction.Op1Kind - OpKind.MemoryESDI) << 4) + Register.DI;
|
|
if ((flags & Flags.NoMemoryUsage) == 0)
|
|
AddMemory(flags, ref usedMemoryLocations, Register.ES, baseReg, Register.None, 1, 0, instruction.MemorySize, OpAccess.Read);
|
|
if ((flags & Flags.NoRegisterUsage) == 0) {
|
|
if ((flags & Flags.Is64Bit) == 0)
|
|
AddRegister(flags, ref usedRegisters, Register.ES, OpAccess.Read);
|
|
AddRegister(flags, ref usedRegisters, baseReg, OpAccess.ReadWrite);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case CodeInfo.Stos:
|
|
if (instruction.Internal_HasPrefixRepeOrRepne) {
|
|
accesses[0] = OpAccess.CondWrite;
|
|
accesses[1] = OpAccess.CondRead;
|
|
Debug.Assert(OpKind.MemoryESDI + 1 == OpKind.MemoryESEDI);
|
|
Debug.Assert(OpKind.MemoryESDI + 2 == OpKind.MemoryESRDI);
|
|
Debug.Assert(Register.DI + 16 == Register.EDI);
|
|
Debug.Assert(Register.DI + 32 == Register.RDI);
|
|
Debug.Assert(Register.CX + 16 == Register.ECX);
|
|
Debug.Assert(Register.CX + 32 == Register.RCX);
|
|
baseReg = ((instruction.Op0Kind - OpKind.MemoryESDI) << 4) + Register.DI;
|
|
if ((flags & Flags.NoMemoryUsage) == 0)
|
|
AddMemory(flags, ref usedMemoryLocations, Register.ES, baseReg, Register.None, 1, 0, MemorySize.Unknown, OpAccess.CondWrite);
|
|
if ((flags & Flags.NoRegisterUsage) == 0) {
|
|
Debug.Assert(usedRegisters.ValidLength == 1);
|
|
usedRegisters.Array[0] = new UsedRegister(usedRegisters.Array[0].Register, OpAccess.CondRead);
|
|
AddRegister(flags, ref usedRegisters, ((instruction.Op0Kind - OpKind.MemoryESDI) << 4) + Register.CX, OpAccess.ReadCondWrite);
|
|
if ((flags & Flags.Is64Bit) == 0)
|
|
AddRegister(flags, ref usedRegisters, Register.ES, OpAccess.CondRead);
|
|
AddRegister(flags, ref usedRegisters, baseReg, OpAccess.CondRead);
|
|
AddRegister(flags, ref usedRegisters, baseReg, OpAccess.CondWrite);
|
|
}
|
|
}
|
|
else {
|
|
Debug.Assert(OpKind.MemoryESDI + 1 == OpKind.MemoryESEDI);
|
|
Debug.Assert(OpKind.MemoryESDI + 2 == OpKind.MemoryESRDI);
|
|
Debug.Assert(Register.DI + 16 == Register.EDI);
|
|
Debug.Assert(Register.DI + 32 == Register.RDI);
|
|
baseReg = ((instruction.Op0Kind - OpKind.MemoryESDI) << 4) + Register.DI;
|
|
if ((flags & Flags.NoMemoryUsage) == 0)
|
|
AddMemory(flags, ref usedMemoryLocations, Register.ES, baseReg, Register.None, 1, 0, instruction.MemorySize, OpAccess.Write);
|
|
if ((flags & Flags.NoRegisterUsage) == 0) {
|
|
if ((flags & Flags.Is64Bit) == 0)
|
|
AddRegister(flags, ref usedRegisters, Register.ES, OpAccess.Read);
|
|
AddRegister(flags, ref usedRegisters, baseReg, OpAccess.ReadWrite);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case CodeInfo.Lods:
|
|
if (instruction.Internal_HasPrefixRepeOrRepne) {
|
|
accesses[0] = OpAccess.CondWrite;
|
|
accesses[1] = OpAccess.CondRead;
|
|
Debug.Assert(OpKind.MemorySegSI + 1 == OpKind.MemorySegESI);
|
|
Debug.Assert(OpKind.MemorySegSI + 2 == OpKind.MemorySegRSI);
|
|
Debug.Assert(Register.SI + 16 == Register.ESI);
|
|
Debug.Assert(Register.SI + 32 == Register.RSI);
|
|
Debug.Assert(Register.CX + 16 == Register.ECX);
|
|
Debug.Assert(Register.CX + 32 == Register.RCX);
|
|
baseReg = ((instruction.Op1Kind - OpKind.MemorySegSI) << 4) + Register.SI;
|
|
if ((flags & Flags.NoMemoryUsage) == 0)
|
|
AddMemory(flags, ref usedMemoryLocations, instruction.MemorySegment, baseReg, Register.None, 1, 0, MemorySize.Unknown, OpAccess.CondRead);
|
|
if ((flags & Flags.NoRegisterUsage) == 0) {
|
|
Debug.Assert(usedRegisters.ValidLength == 1);
|
|
usedRegisters.Array[0] = new UsedRegister(usedRegisters.Array[0].Register, OpAccess.CondWrite);
|
|
AddRegister(flags, ref usedRegisters, ((instruction.Op1Kind - OpKind.MemorySegSI) << 4) + Register.CX, OpAccess.ReadCondWrite);
|
|
AddMemorySegmentRegister(flags, ref usedRegisters, instruction.MemorySegment, OpAccess.CondRead);
|
|
AddRegister(flags, ref usedRegisters, baseReg, OpAccess.CondRead);
|
|
AddRegister(flags, ref usedRegisters, baseReg, OpAccess.CondWrite);
|
|
}
|
|
}
|
|
else {
|
|
Debug.Assert(OpKind.MemorySegSI + 1 == OpKind.MemorySegESI);
|
|
Debug.Assert(OpKind.MemorySegSI + 2 == OpKind.MemorySegRSI);
|
|
Debug.Assert(Register.SI + 16 == Register.ESI);
|
|
Debug.Assert(Register.SI + 32 == Register.RSI);
|
|
baseReg = ((instruction.Op1Kind - OpKind.MemorySegSI) << 4) + Register.SI;
|
|
if ((flags & Flags.NoMemoryUsage) == 0)
|
|
AddMemory(flags, ref usedMemoryLocations, instruction.MemorySegment, baseReg, Register.None, 1, 0, instruction.MemorySize, OpAccess.Read);
|
|
if ((flags & Flags.NoRegisterUsage) == 0) {
|
|
AddMemorySegmentRegister(flags, ref usedRegisters, instruction.MemorySegment, OpAccess.Read);
|
|
AddRegister(flags, ref usedRegisters, baseReg, OpAccess.ReadWrite);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case CodeInfo.Scas:
|
|
if (instruction.Internal_HasPrefixRepeOrRepne) {
|
|
accesses[0] = OpAccess.CondRead;
|
|
accesses[1] = OpAccess.CondRead;
|
|
Debug.Assert(OpKind.MemoryESDI + 1 == OpKind.MemoryESEDI);
|
|
Debug.Assert(OpKind.MemoryESDI + 2 == OpKind.MemoryESRDI);
|
|
Debug.Assert(Register.DI + 16 == Register.EDI);
|
|
Debug.Assert(Register.DI + 32 == Register.RDI);
|
|
Debug.Assert(Register.CX + 16 == Register.ECX);
|
|
Debug.Assert(Register.CX + 32 == Register.RCX);
|
|
baseReg = ((instruction.Op1Kind - OpKind.MemoryESDI) << 4) + Register.DI;
|
|
if ((flags & Flags.NoMemoryUsage) == 0)
|
|
AddMemory(flags, ref usedMemoryLocations, Register.ES, baseReg, Register.None, 1, 0, MemorySize.Unknown, OpAccess.CondRead);
|
|
if ((flags & Flags.NoRegisterUsage) == 0) {
|
|
Debug.Assert(usedRegisters.ValidLength == 1);
|
|
usedRegisters.Array[0] = new UsedRegister(usedRegisters.Array[0].Register, OpAccess.CondRead);
|
|
AddRegister(flags, ref usedRegisters, ((instruction.Op1Kind - OpKind.MemoryESDI) << 4) + Register.CX, OpAccess.ReadCondWrite);
|
|
if ((flags & Flags.Is64Bit) == 0)
|
|
AddRegister(flags, ref usedRegisters, Register.ES, OpAccess.CondRead);
|
|
AddRegister(flags, ref usedRegisters, baseReg, OpAccess.CondRead);
|
|
AddRegister(flags, ref usedRegisters, baseReg, OpAccess.CondWrite);
|
|
}
|
|
}
|
|
else {
|
|
Debug.Assert(OpKind.MemoryESDI + 1 == OpKind.MemoryESEDI);
|
|
Debug.Assert(OpKind.MemoryESDI + 2 == OpKind.MemoryESRDI);
|
|
Debug.Assert(Register.DI + 16 == Register.EDI);
|
|
Debug.Assert(Register.DI + 32 == Register.RDI);
|
|
baseReg = ((instruction.Op1Kind - OpKind.MemoryESDI) << 4) + Register.DI;
|
|
if ((flags & Flags.NoMemoryUsage) == 0)
|
|
AddMemory(flags, ref usedMemoryLocations, Register.ES, baseReg, Register.None, 1, 0, instruction.MemorySize, OpAccess.Read);
|
|
if ((flags & Flags.NoRegisterUsage) == 0) {
|
|
if ((flags & Flags.Is64Bit) == 0)
|
|
AddRegister(flags, ref usedRegisters, Register.ES, OpAccess.Read);
|
|
AddRegister(flags, ref usedRegisters, baseReg, OpAccess.ReadWrite);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case CodeInfo.Cmpxchg:
|
|
if ((flags & Flags.NoRegisterUsage) == 0) {
|
|
code = instruction.Code;
|
|
if (code == Code.Cmpxchg_rm64_r64)
|
|
AddRegister(flags, ref usedRegisters, Register.RAX, OpAccess.ReadCondWrite);
|
|
else if (code == Code.Cmpxchg_rm32_r32)
|
|
AddRegister(flags, ref usedRegisters, Register.EAX, OpAccess.ReadCondWrite);
|
|
else if (code == Code.Cmpxchg_rm16_r16)
|
|
AddRegister(flags, ref usedRegisters, Register.AX, OpAccess.ReadCondWrite);
|
|
else {
|
|
Debug.Assert(code == Code.Cmpxchg_rm8_r8);
|
|
AddRegister(flags, ref usedRegisters, Register.AL, OpAccess.ReadCondWrite);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case CodeInfo.Cmpxchg8b:
|
|
if ((flags & Flags.NoRegisterUsage) == 0) {
|
|
if (instruction.Code == Code.Cmpxchg16b_m128) {
|
|
AddRegister(flags, ref usedRegisters, Register.RDX, OpAccess.ReadCondWrite);
|
|
AddRegister(flags, ref usedRegisters, Register.RAX, OpAccess.ReadCondWrite);
|
|
AddRegister(flags, ref usedRegisters, Register.RCX, OpAccess.CondRead);
|
|
AddRegister(flags, ref usedRegisters, Register.RBX, OpAccess.CondRead);
|
|
}
|
|
else {
|
|
Debug.Assert(instruction.Code == Code.Cmpxchg8b_m64);
|
|
AddRegister(flags, ref usedRegisters, Register.EDX, OpAccess.ReadCondWrite);
|
|
AddRegister(flags, ref usedRegisters, Register.EAX, OpAccess.ReadCondWrite);
|
|
AddRegister(flags, ref usedRegisters, Register.ECX, OpAccess.CondRead);
|
|
AddRegister(flags, ref usedRegisters, Register.EBX, OpAccess.CondRead);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case CodeInfo.Cpuid:
|
|
if ((flags & Flags.NoRegisterUsage) == 0) {
|
|
AddRegister(flags, ref usedRegisters, Register.EAX, OpAccess.ReadWrite);
|
|
AddRegister(flags, ref usedRegisters, Register.ECX, OpAccess.CondRead);
|
|
AddRegister(flags, ref usedRegisters, Register.ECX, OpAccess.Write);
|
|
AddRegister(flags, ref usedRegisters, Register.EDX, OpAccess.Write);
|
|
AddRegister(flags, ref usedRegisters, Register.EBX, OpAccess.Write);
|
|
}
|
|
break;
|
|
|
|
case CodeInfo.Div:
|
|
if ((flags & Flags.NoRegisterUsage) == 0) {
|
|
code = instruction.Code;
|
|
if (code == Code.Idiv_rm64 || code == Code.Div_rm64) {
|
|
AddRegister(flags, ref usedRegisters, Register.RDX, OpAccess.ReadWrite);
|
|
AddRegister(flags, ref usedRegisters, Register.RAX, OpAccess.ReadWrite);
|
|
}
|
|
else if (code == Code.Idiv_rm32 || code == Code.Div_rm32) {
|
|
AddRegister(flags, ref usedRegisters, Register.EDX, OpAccess.ReadWrite);
|
|
AddRegister(flags, ref usedRegisters, Register.EAX, OpAccess.ReadWrite);
|
|
}
|
|
else if (code == Code.Idiv_rm16 || code == Code.Div_rm16) {
|
|
AddRegister(flags, ref usedRegisters, Register.DX, OpAccess.ReadWrite);
|
|
AddRegister(flags, ref usedRegisters, Register.AX, OpAccess.ReadWrite);
|
|
}
|
|
else {
|
|
Debug.Assert(code == Code.Idiv_rm8 || code == Code.Div_rm8);
|
|
AddRegister(flags, ref usedRegisters, Register.AX, OpAccess.ReadWrite);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case CodeInfo.Mul:
|
|
if ((flags & Flags.NoRegisterUsage) == 0) {
|
|
code = instruction.Code;
|
|
if (code == Code.Imul_rm64 || code == Code.Mul_rm64) {
|
|
AddRegister(flags, ref usedRegisters, Register.RAX, OpAccess.ReadWrite);
|
|
AddRegister(flags, ref usedRegisters, Register.RDX, OpAccess.Write);
|
|
}
|
|
else if (code == Code.Imul_rm32 || code == Code.Mul_rm32) {
|
|
AddRegister(flags, ref usedRegisters, Register.EAX, OpAccess.ReadWrite);
|
|
AddRegister(flags, ref usedRegisters, Register.EDX, OpAccess.Write);
|
|
}
|
|
else if (code == Code.Imul_rm16 || code == Code.Mul_rm16) {
|
|
AddRegister(flags, ref usedRegisters, Register.AX, OpAccess.ReadWrite);
|
|
AddRegister(flags, ref usedRegisters, Register.DX, OpAccess.Write);
|
|
}
|
|
else {
|
|
Debug.Assert(code == Code.Imul_rm8 || code == Code.Mul_rm8);
|
|
AddRegister(flags, ref usedRegisters, Register.AL, OpAccess.Read);
|
|
AddRegister(flags, ref usedRegisters, Register.AX, OpAccess.Write);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case CodeInfo.Enter:
|
|
xsp = GetXSP(instruction.CodeSize, out xspMask);
|
|
if ((flags & Flags.NoRegisterUsage) == 0) {
|
|
if ((flags & Flags.Is64Bit) == 0)
|
|
AddRegister(flags, ref usedRegisters, Register.SS, OpAccess.Read);
|
|
AddRegister(flags, ref usedRegisters, xsp, OpAccess.ReadWrite);
|
|
}
|
|
|
|
uint opSize;
|
|
code = instruction.Code;
|
|
Register rSP;
|
|
if (code == Code.Enterq_imm16_imm8) {
|
|
opSize = 8;
|
|
memSize = MemorySize.UInt64;
|
|
rSP = Register.RSP;
|
|
}
|
|
else if (code == Code.Enterd_imm16_imm8) {
|
|
opSize = 4;
|
|
memSize = MemorySize.UInt32;
|
|
rSP = Register.ESP;
|
|
}
|
|
else {
|
|
Debug.Assert(code == Code.Enterw_imm16_imm8);
|
|
opSize = 2;
|
|
memSize = MemorySize.UInt16;
|
|
rSP = Register.SP;
|
|
}
|
|
|
|
if (rSP != xsp && (flags & Flags.NoRegisterUsage) == 0)
|
|
AddRegister(flags, ref usedRegisters, rSP, OpAccess.ReadWrite);
|
|
|
|
int nestingLevel = instruction.Immediate8_2nd & 0x1F;
|
|
|
|
ulong xspOffset = 0;
|
|
// push rBP
|
|
if ((flags & Flags.NoRegisterUsage) == 0)
|
|
AddRegister(flags, ref usedRegisters, rSP + 1, OpAccess.ReadWrite);
|
|
if ((flags & Flags.NoMemoryUsage) == 0)
|
|
AddMemory(flags, ref usedMemoryLocations, Register.SS, xsp, Register.None, 1, (xspOffset -= opSize) & xspMask, memSize, OpAccess.Write);
|
|
|
|
if (nestingLevel != 0) {
|
|
var xbp = xsp + 1;// rBP immediately follows rSP
|
|
ulong xbpOffset = 0;
|
|
for (int i = 1; i < nestingLevel; i++) {
|
|
if (i == 1 && rSP + 1 != xbp && (flags & Flags.NoRegisterUsage) == 0)
|
|
AddRegister(flags, ref usedRegisters, xbp, OpAccess.ReadWrite);
|
|
// push [xbp]
|
|
if ((flags & Flags.NoMemoryUsage) == 0) {
|
|
AddMemory(flags, ref usedMemoryLocations, Register.SS, xbp, Register.None, 1, (xbpOffset -= opSize) & xspMask, memSize, OpAccess.Read);
|
|
AddMemory(flags, ref usedMemoryLocations, Register.SS, xsp, Register.None, 1, (xspOffset -= opSize) & xspMask, memSize, OpAccess.Write);
|
|
}
|
|
}
|
|
// push frameTemp
|
|
if ((flags & Flags.NoMemoryUsage) == 0)
|
|
AddMemory(flags, ref usedMemoryLocations, Register.SS, xsp, Register.None, 1, (xspOffset -= opSize) & xspMask, memSize, OpAccess.Write);
|
|
}
|
|
break;
|
|
|
|
case CodeInfo.Leave:
|
|
xsp = GetXSP(instruction.CodeSize, out xspMask);
|
|
if ((flags & Flags.NoRegisterUsage) == 0) {
|
|
if ((flags & Flags.Is64Bit) == 0)
|
|
AddRegister(flags, ref usedRegisters, Register.SS, OpAccess.Read);
|
|
AddRegister(flags, ref usedRegisters, xsp, OpAccess.Write);
|
|
}
|
|
|
|
code = instruction.Code;
|
|
if (code == Code.Leaveq) {
|
|
if ((flags & Flags.NoMemoryUsage) == 0)
|
|
AddMemory(flags, ref usedMemoryLocations, Register.SS, xsp + 1, Register.None, 1, 0, MemorySize.UInt64, OpAccess.Read);
|
|
if ((flags & Flags.NoRegisterUsage) == 0) {
|
|
if (xsp + 1 == Register.RBP)
|
|
AddRegister(flags, ref usedRegisters, Register.RBP, OpAccess.ReadWrite);
|
|
else {
|
|
AddRegister(flags, ref usedRegisters, xsp + 1, OpAccess.Read);
|
|
AddRegister(flags, ref usedRegisters, Register.RBP, OpAccess.Write);
|
|
}
|
|
}
|
|
}
|
|
else if (code == Code.Leaved) {
|
|
if ((flags & Flags.NoMemoryUsage) == 0)
|
|
AddMemory(flags, ref usedMemoryLocations, Register.SS, xsp + 1, Register.None, 1, 0, MemorySize.UInt32, OpAccess.Read);
|
|
if ((flags & Flags.NoRegisterUsage) == 0) {
|
|
if (xsp + 1 == Register.EBP)
|
|
AddRegister(flags, ref usedRegisters, Register.EBP, OpAccess.ReadWrite);
|
|
else {
|
|
AddRegister(flags, ref usedRegisters, xsp + 1, OpAccess.Read);
|
|
AddRegister(flags, ref usedRegisters, Register.EBP, OpAccess.Write);
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
Debug.Assert(code == Code.Leavew);
|
|
if ((flags & Flags.NoMemoryUsage) == 0)
|
|
AddMemory(flags, ref usedMemoryLocations, Register.SS, xsp + 1, Register.None, 1, 0, MemorySize.UInt16, OpAccess.Read);
|
|
if ((flags & Flags.NoRegisterUsage) == 0) {
|
|
if (xsp + 1 == Register.BP)
|
|
AddRegister(flags, ref usedRegisters, Register.BP, OpAccess.ReadWrite);
|
|
else {
|
|
AddRegister(flags, ref usedRegisters, xsp + 1, OpAccess.Read);
|
|
AddRegister(flags, ref usedRegisters, Register.BP, OpAccess.Write);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case CodeInfo.Iret:
|
|
xsp = GetXSP(instruction.CodeSize, out xspMask);
|
|
if ((flags & Flags.NoRegisterUsage) == 0) {
|
|
AddRegister(flags, ref usedRegisters, Register.SS, (flags & Flags.Is64Bit) != 0 ? OpAccess.Write : OpAccess.Read);
|
|
AddRegister(flags, ref usedRegisters, xsp, OpAccess.ReadWrite);
|
|
}
|
|
|
|
if ((flags & Flags.NoMemoryUsage) == 0) {
|
|
code = instruction.Code;
|
|
if (code == Code.Iretq) {
|
|
AddMemory(flags, ref usedMemoryLocations, Register.SS, xsp, Register.None, 1, 0 * 8, MemorySize.UInt64, OpAccess.Read);
|
|
AddMemory(flags, ref usedMemoryLocations, Register.SS, xsp, Register.None, 1, 1 * 8, MemorySize.UInt64, OpAccess.Read);
|
|
AddMemory(flags, ref usedMemoryLocations, Register.SS, xsp, Register.None, 1, 2 * 8, MemorySize.UInt64, OpAccess.Read);
|
|
AddMemory(flags, ref usedMemoryLocations, Register.SS, xsp, Register.None, 1, 3 * 8, MemorySize.UInt64, OpAccess.Read);
|
|
AddMemory(flags, ref usedMemoryLocations, Register.SS, xsp, Register.None, 1, 4 * 8, MemorySize.UInt64, OpAccess.Read);
|
|
}
|
|
else if (code == Code.Iretd) {
|
|
AddMemory(flags, ref usedMemoryLocations, Register.SS, xsp, Register.None, 1, 0 * 4, MemorySize.UInt32, OpAccess.Read);
|
|
AddMemory(flags, ref usedMemoryLocations, Register.SS, xsp, Register.None, 1, 1 * 4, MemorySize.UInt32, OpAccess.Read);
|
|
AddMemory(flags, ref usedMemoryLocations, Register.SS, xsp, Register.None, 1, 2 * 4, MemorySize.UInt32, OpAccess.Read);
|
|
if (instruction.CodeSize == CodeSize.Code64) {
|
|
AddMemory(flags, ref usedMemoryLocations, Register.SS, xsp, Register.None, 1, 3 * 4, MemorySize.UInt32, OpAccess.Read);
|
|
AddMemory(flags, ref usedMemoryLocations, Register.SS, xsp, Register.None, 1, 4 * 4, MemorySize.UInt32, OpAccess.Read);
|
|
}
|
|
}
|
|
else {
|
|
Debug.Assert(code == Code.Iretw);
|
|
AddMemory(flags, ref usedMemoryLocations, Register.SS, xsp, Register.None, 1, 0 * 2, MemorySize.UInt16, OpAccess.Read);
|
|
AddMemory(flags, ref usedMemoryLocations, Register.SS, xsp, Register.None, 1, 1 * 2, MemorySize.UInt16, OpAccess.Read);
|
|
AddMemory(flags, ref usedMemoryLocations, Register.SS, xsp, Register.None, 1, 2 * 2, MemorySize.UInt16, OpAccess.Read);
|
|
if (instruction.CodeSize == CodeSize.Code64) {
|
|
AddMemory(flags, ref usedMemoryLocations, Register.SS, xsp, Register.None, 1, 3 * 2, MemorySize.UInt16, OpAccess.Read);
|
|
AddMemory(flags, ref usedMemoryLocations, Register.SS, xsp, Register.None, 1, 4 * 2, MemorySize.UInt16, OpAccess.Read);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case CodeInfo.Vzeroall:
|
|
if ((flags & Flags.NoRegisterUsage) == 0) {
|
|
OpAccess access;
|
|
if (instruction.Code == Code.VEX_Vzeroupper)
|
|
access = OpAccess.ReadWrite;
|
|
else {
|
|
Debug.Assert(instruction.Code == Code.VEX_Vzeroall);
|
|
access = OpAccess.Write;
|
|
}
|
|
int maxVecRegs;
|
|
if ((flags & Flags.Is64Bit) != 0)
|
|
maxVecRegs = InstructionInfoConstants.VMM_last - InstructionInfoConstants.VMM_first + 1;
|
|
else
|
|
maxVecRegs = 8;
|
|
for (int i = 0; i < maxVecRegs; i++)
|
|
AddRegister(flags, ref usedRegisters, InstructionInfoConstants.VMM_first + i, access);
|
|
}
|
|
break;
|
|
|
|
case CodeInfo.Jrcxz:
|
|
if ((flags & Flags.NoRegisterUsage) == 0) {
|
|
code = instruction.Code;
|
|
if (code == Code.Jrcxz_rel8_64)
|
|
AddRegister(flags, ref usedRegisters, Register.RCX, OpAccess.Read);
|
|
else if (code == Code.Jecxz_rel8_64 || code == Code.Jecxz_rel8_32 || code == Code.Jecxz_rel8_16)
|
|
AddRegister(flags, ref usedRegisters, Register.ECX, OpAccess.Read);
|
|
else {
|
|
Debug.Assert(code == Code.Jcxz_rel8_32 || code == Code.Jcxz_rel8_16);
|
|
AddRegister(flags, ref usedRegisters, Register.CX, OpAccess.Read);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case CodeInfo.Loop:
|
|
if ((flags & Flags.NoRegisterUsage) == 0) {
|
|
code = instruction.Code;
|
|
if (code == Code.Loopne_rel8_64_RCX || code == Code.Loope_rel8_64_RCX || code == Code.Loop_rel8_64_RCX)
|
|
AddRegister(flags, ref usedRegisters, Register.RCX, OpAccess.ReadWrite);
|
|
else if (code == Code.Loopne_rel8_16_ECX || code == Code.Loopne_rel8_32_ECX || code == Code.Loopne_rel8_64_ECX ||
|
|
code == Code.Loope_rel8_16_ECX || code == Code.Loope_rel8_32_ECX || code == Code.Loope_rel8_64_ECX ||
|
|
code == Code.Loop_rel8_16_ECX || code == Code.Loop_rel8_32_ECX || code == Code.Loop_rel8_64_ECX)
|
|
AddRegister(flags, ref usedRegisters, Register.ECX, OpAccess.ReadWrite);
|
|
else {
|
|
Debug.Assert(code == Code.Loopne_rel8_16_CX || code == Code.Loopne_rel8_32_CX ||
|
|
code == Code.Loope_rel8_16_CX || code == Code.Loope_rel8_32_CX ||
|
|
code == Code.Loop_rel8_16_CX || code == Code.Loop_rel8_32_CX);
|
|
AddRegister(flags, ref usedRegisters, Register.CX, OpAccess.ReadWrite);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case CodeInfo.Lahf:
|
|
if ((flags & Flags.NoRegisterUsage) == 0)
|
|
AddRegister(flags, ref usedRegisters, Register.AH, instruction.Code == Code.Sahf ? OpAccess.Read : OpAccess.Write);
|
|
break;
|
|
|
|
case CodeInfo.Lds:
|
|
if ((flags & Flags.NoRegisterUsage) == 0) {
|
|
code = instruction.Code;
|
|
if (Code.Lfs_r16_m32 <= code && code <= Code.Lfs_r64_m80)
|
|
AddRegister(flags, ref usedRegisters, Register.FS, OpAccess.Write);
|
|
else if (Code.Lgs_r16_m32 <= code && code <= Code.Lgs_r64_m80)
|
|
AddRegister(flags, ref usedRegisters, Register.GS, OpAccess.Write);
|
|
else if (Code.Lss_r16_m32 <= code && code <= Code.Lss_r64_m80)
|
|
AddRegister(flags, ref usedRegisters, Register.SS, OpAccess.Write);
|
|
else if (Code.Lds_r16_m32 <= code && code <= Code.Lds_r32_m48)
|
|
AddRegister(flags, ref usedRegisters, Register.DS, OpAccess.Write);
|
|
else {
|
|
Debug.Assert(Code.Les_r16_m32 <= code && code <= Code.Les_r32_m48);
|
|
AddRegister(flags, ref usedRegisters, Register.ES, OpAccess.Write);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case CodeInfo.Maskmovq:
|
|
switch (instruction.Op0Kind) {
|
|
case OpKind.MemorySegDI:
|
|
baseReg = Register.DI;
|
|
break;
|
|
|
|
case OpKind.MemorySegEDI:
|
|
baseReg = Register.EDI;
|
|
break;
|
|
|
|
default:
|
|
Debug.Assert(instruction.Op0Kind == OpKind.MemorySegRDI);
|
|
baseReg = Register.RDI;
|
|
break;
|
|
}
|
|
if ((flags & Flags.NoMemoryUsage) == 0)
|
|
AddMemory(flags, ref usedMemoryLocations, instruction.MemorySegment, baseReg, Register.None, 1, 0, instruction.MemorySize, OpAccess.Write);
|
|
if ((flags & Flags.NoRegisterUsage) == 0) {
|
|
AddMemorySegmentRegister(flags, ref usedRegisters, instruction.MemorySegment, OpAccess.Read);
|
|
AddRegister(flags, ref usedRegisters, baseReg, OpAccess.Read);
|
|
}
|
|
break;
|
|
|
|
case CodeInfo.Monitor:
|
|
code = instruction.Code;
|
|
if (code == Code.Monitorq || code == Code.Monitorxq)
|
|
baseReg = Register.RAX;
|
|
else if (code == Code.Monitord || code == Code.Monitorxd)
|
|
baseReg = Register.EAX;
|
|
else {
|
|
Debug.Assert(code == Code.Monitorw || code == Code.Monitorxw);
|
|
baseReg = Register.AX;
|
|
}
|
|
var seg = instruction.PrefixSegment;
|
|
if (seg == Register.None)
|
|
seg = Register.DS;
|
|
if ((flags & Flags.NoMemoryUsage) == 0)
|
|
AddMemory(flags, ref usedMemoryLocations, seg, baseReg, Register.None, 1, 0, MemorySize.Unknown, OpAccess.Read);
|
|
if ((flags & Flags.NoRegisterUsage) == 0) {
|
|
AddMemorySegmentRegister(flags, ref usedRegisters, seg, OpAccess.Read);
|
|
AddRegister(flags, ref usedRegisters, baseReg, OpAccess.Read);
|
|
if ((flags & Flags.Is64Bit) != 0) {
|
|
AddRegister(flags, ref usedRegisters, Register.RCX, OpAccess.Read);
|
|
AddRegister(flags, ref usedRegisters, Register.RDX, OpAccess.Read);
|
|
}
|
|
else {
|
|
AddRegister(flags, ref usedRegisters, Register.ECX, OpAccess.Read);
|
|
AddRegister(flags, ref usedRegisters, Register.EDX, OpAccess.Read);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case CodeInfo.Mwait:
|
|
if ((flags & Flags.NoRegisterUsage) == 0) {
|
|
if ((flags & Flags.Is64Bit) != 0) {
|
|
AddRegister(flags, ref usedRegisters, Register.RAX, OpAccess.Read);
|
|
AddRegister(flags, ref usedRegisters, Register.RCX, OpAccess.Read);
|
|
}
|
|
else {
|
|
AddRegister(flags, ref usedRegisters, Register.EAX, OpAccess.Read);
|
|
AddRegister(flags, ref usedRegisters, Register.ECX, OpAccess.Read);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case CodeInfo.Mwaitx:
|
|
if ((flags & Flags.NoRegisterUsage) == 0) {
|
|
if ((flags & Flags.Is64Bit) != 0) {
|
|
AddRegister(flags, ref usedRegisters, Register.RAX, OpAccess.Read);
|
|
AddRegister(flags, ref usedRegisters, Register.RCX, OpAccess.Read);
|
|
AddRegister(flags, ref usedRegisters, Register.RBX, OpAccess.CondRead);
|
|
}
|
|
else {
|
|
AddRegister(flags, ref usedRegisters, Register.EAX, OpAccess.Read);
|
|
AddRegister(flags, ref usedRegisters, Register.ECX, OpAccess.Read);
|
|
AddRegister(flags, ref usedRegisters, Register.EBX, OpAccess.CondRead);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case CodeInfo.Mulx:
|
|
if ((flags & Flags.NoRegisterUsage) == 0) {
|
|
if (instruction.Code == Code.VEX_Mulx_r32_r32_rm32)
|
|
AddRegister(flags, ref usedRegisters, Register.EDX, OpAccess.Read);
|
|
else {
|
|
Debug.Assert(instruction.Code == Code.VEX_Mulx_r64_r64_rm64);
|
|
AddRegister(flags, ref usedRegisters, Register.RDX, OpAccess.Read);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case CodeInfo.PcmpXstrY:
|
|
if ((flags & Flags.NoRegisterUsage) == 0) {
|
|
code = instruction.Code;
|
|
if (code == Code.Pcmpestrm_xmm_xmmm128_imm8 || code == Code.VEX_Vpcmpestrm_xmm_xmmm128_imm8 ||
|
|
code == Code.Pcmpestri_xmm_xmmm128_imm8 || code == Code.VEX_Vpcmpestri_xmm_xmmm128_imm8) {
|
|
AddRegister(flags, ref usedRegisters, Register.EAX, OpAccess.Read);
|
|
AddRegister(flags, ref usedRegisters, Register.EDX, OpAccess.Read);
|
|
}
|
|
else if (code == Code.Pcmpestrm64_xmm_xmmm128_imm8 || code == Code.VEX_Vpcmpestrm64_xmm_xmmm128_imm8 ||
|
|
code == Code.Pcmpestri64_xmm_xmmm128_imm8 || code == Code.VEX_Vpcmpestri64_xmm_xmmm128_imm8) {
|
|
AddRegister(flags, ref usedRegisters, Register.RAX, OpAccess.Read);
|
|
AddRegister(flags, ref usedRegisters, Register.RDX, OpAccess.Read);
|
|
}
|
|
|
|
if (code == Code.Pcmpestrm_xmm_xmmm128_imm8 || code == Code.VEX_Vpcmpestrm_xmm_xmmm128_imm8 ||
|
|
code == Code.Pcmpestrm64_xmm_xmmm128_imm8 || code == Code.VEX_Vpcmpestrm64_xmm_xmmm128_imm8 ||
|
|
code == Code.Pcmpistrm_xmm_xmmm128_imm8 || code == Code.VEX_Vpcmpistrm_xmm_xmmm128_imm8) {
|
|
AddRegister(flags, ref usedRegisters, Register.XMM0, OpAccess.Write);
|
|
}
|
|
else {
|
|
Debug.Assert(code == Code.Pcmpestri_xmm_xmmm128_imm8 || code == Code.VEX_Vpcmpestri_xmm_xmmm128_imm8 ||
|
|
code == Code.Pcmpestri64_xmm_xmmm128_imm8 || code == Code.VEX_Vpcmpestri64_xmm_xmmm128_imm8 ||
|
|
code == Code.Pcmpistri_xmm_xmmm128_imm8 || code == Code.VEX_Vpcmpistri_xmm_xmmm128_imm8);
|
|
AddRegister(flags, ref usedRegisters, Register.ECX, OpAccess.Write);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case CodeInfo.Shift_Ib_MASK1FMOD9:
|
|
if ((instruction.Immediate8 & 0x1F) % 9 == 0)
|
|
rflagsInfo = RflagsInfo.None;
|
|
break;
|
|
|
|
case CodeInfo.Shift_Ib_MASK1FMOD11:
|
|
if ((instruction.Immediate8 & 0x1F) % 17 == 0)
|
|
rflagsInfo = RflagsInfo.None;
|
|
break;
|
|
|
|
case CodeInfo.Shift_Ib_MASK1F:
|
|
if ((instruction.Immediate8 & 0x1F) == 0)
|
|
rflagsInfo = RflagsInfo.None;
|
|
break;
|
|
|
|
case CodeInfo.Shift_Ib_MASK3F:
|
|
if ((instruction.Immediate8 & 0x3F) == 0)
|
|
rflagsInfo = RflagsInfo.None;
|
|
break;
|
|
|
|
case CodeInfo.R_EAX_EDX:
|
|
if ((flags & Flags.NoRegisterUsage) == 0) {
|
|
AddRegister(flags, ref usedRegisters, Register.EAX, OpAccess.Read);
|
|
AddRegister(flags, ref usedRegisters, Register.EDX, OpAccess.Read);
|
|
}
|
|
break;
|
|
|
|
case CodeInfo.R_ECX_W_EAX_EDX:
|
|
if ((flags & Flags.NoRegisterUsage) == 0) {
|
|
AddRegister(flags, ref usedRegisters, Register.EAX, OpAccess.Write);
|
|
AddRegister(flags, ref usedRegisters, Register.ECX, OpAccess.Read);
|
|
AddRegister(flags, ref usedRegisters, Register.EDX, OpAccess.Write);
|
|
}
|
|
break;
|
|
|
|
case CodeInfo.R_EAX_ECX_EDX:
|
|
if ((flags & Flags.NoRegisterUsage) == 0) {
|
|
AddRegister(flags, ref usedRegisters, Register.EAX, OpAccess.Read);
|
|
AddRegister(flags, ref usedRegisters, Register.ECX, OpAccess.Read);
|
|
AddRegister(flags, ref usedRegisters, Register.EDX, OpAccess.Read);
|
|
}
|
|
break;
|
|
|
|
case CodeInfo.W_EAX_EDX:
|
|
if ((flags & Flags.NoRegisterUsage) == 0) {
|
|
AddRegister(flags, ref usedRegisters, Register.EAX, OpAccess.Write);
|
|
AddRegister(flags, ref usedRegisters, Register.EDX, OpAccess.Write);
|
|
}
|
|
break;
|
|
|
|
case CodeInfo.W_EAX_ECX_EDX:
|
|
if ((flags & Flags.NoRegisterUsage) == 0) {
|
|
AddRegister(flags, ref usedRegisters, Register.EAX, OpAccess.Write);
|
|
AddRegister(flags, ref usedRegisters, Register.ECX, OpAccess.Write);
|
|
AddRegister(flags, ref usedRegisters, Register.EDX, OpAccess.Write);
|
|
}
|
|
break;
|
|
|
|
case CodeInfo.Syscall:
|
|
if ((flags & Flags.NoRegisterUsage) == 0) {
|
|
code = instruction.Code;
|
|
if (code == Code.Syscall) {
|
|
AddRegister(flags, ref usedRegisters, Register.RCX, OpAccess.Write);
|
|
AddRegister(flags, ref usedRegisters, Register.R11, OpAccess.Write);
|
|
}
|
|
else if (code == Code.Sysenter)
|
|
AddRegister(flags, ref usedRegisters, (flags & Flags.Is64Bit) != 0 ? Register.RSP : Register.ESP, OpAccess.Write);
|
|
else if (code == Code.Sysretq) {
|
|
AddRegister(flags, ref usedRegisters, Register.RCX, OpAccess.Read);
|
|
AddRegister(flags, ref usedRegisters, Register.R11, OpAccess.Read);
|
|
}
|
|
else if (code == Code.Sysexitq) {
|
|
AddRegister(flags, ref usedRegisters, Register.RCX, OpAccess.Read);
|
|
AddRegister(flags, ref usedRegisters, Register.RDX, OpAccess.Read);
|
|
AddRegister(flags, ref usedRegisters, Register.RSP, OpAccess.Write);
|
|
}
|
|
else if (code == Code.Sysretd) {
|
|
AddRegister(flags, ref usedRegisters, Register.ECX, OpAccess.Read);
|
|
AddRegister(flags, ref usedRegisters, Register.R11, OpAccess.Read);
|
|
}
|
|
else {
|
|
Debug.Assert(code == Code.Sysexitd);
|
|
AddRegister(flags, ref usedRegisters, Register.ECX, OpAccess.Read);
|
|
AddRegister(flags, ref usedRegisters, Register.EDX, OpAccess.Read);
|
|
AddRegister(flags, ref usedRegisters, (flags & Flags.Is64Bit) != 0 ? Register.RSP : Register.ESP, OpAccess.Write);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case CodeInfo.Encls:
|
|
if ((flags & Flags.NoRegisterUsage) == 0) {
|
|
baseReg = (flags & Flags.Is64Bit) != 0 ? Register.RAX : Register.EAX;
|
|
AddRegister(flags, ref usedRegisters, Register.EAX, OpAccess.Read);
|
|
// rcx/ecx
|
|
AddRegister(flags, ref usedRegisters, baseReg + 1, OpAccess.CondRead);
|
|
AddRegister(flags, ref usedRegisters, baseReg + 1, OpAccess.CondWrite);
|
|
// rdx/edx
|
|
AddRegister(flags, ref usedRegisters, baseReg + 2, OpAccess.CondRead);
|
|
AddRegister(flags, ref usedRegisters, baseReg + 2, OpAccess.CondWrite);
|
|
// rbx/ebx
|
|
AddRegister(flags, ref usedRegisters, baseReg + 3, OpAccess.CondRead);
|
|
AddRegister(flags, ref usedRegisters, baseReg + 3, OpAccess.CondWrite);
|
|
}
|
|
break;
|
|
|
|
case CodeInfo.Vmfunc:
|
|
if ((flags & Flags.NoRegisterUsage) == 0) {
|
|
AddRegister(flags, ref usedRegisters, Register.EAX, OpAccess.Read);
|
|
AddRegister(flags, ref usedRegisters, Register.ECX, OpAccess.Read);
|
|
}
|
|
break;
|
|
|
|
case CodeInfo.Vmload:
|
|
code = instruction.Code;
|
|
if (code == Code.Vmloadq || code == Code.Vmsaveq || code == Code.Vmrunq)
|
|
baseReg = Register.RAX;
|
|
else if (code == Code.Vmloadd || code == Code.Vmsaved || code == Code.Vmrund)
|
|
baseReg = Register.EAX;
|
|
else {
|
|
Debug.Assert(code == Code.Vmloadw || code == Code.Vmsavew || code == Code.Vmrunw);
|
|
baseReg = Register.AX;
|
|
}
|
|
if ((flags & Flags.NoRegisterUsage) == 0) {
|
|
if ((flags & Flags.Is64Bit) == 0)
|
|
AddRegister(flags, ref usedRegisters, Register.DS, OpAccess.Read);
|
|
AddRegister(flags, ref usedRegisters, baseReg, OpAccess.Read);
|
|
}
|
|
if ((flags & Flags.NoMemoryUsage) == 0) {
|
|
AddMemory(flags, ref usedMemoryLocations, Register.DS, baseReg, Register.None, 1, 0,
|
|
MemorySize.Unknown, code == Code.Vmsaveq || code == Code.Vmsaved || code == Code.Vmsavew ? OpAccess.Write : OpAccess.Read);
|
|
}
|
|
break;
|
|
|
|
case CodeInfo.R_CR0:
|
|
if ((flags & Flags.NoRegisterUsage) == 0)
|
|
AddRegister(flags, ref usedRegisters, Register.CR0, OpAccess.Read);
|
|
break;
|
|
|
|
case CodeInfo.RW_CR0:
|
|
if ((flags & Flags.NoRegisterUsage) == 0)
|
|
AddRegister(flags, ref usedRegisters, Register.CR0, OpAccess.ReadWrite);
|
|
break;
|
|
|
|
case CodeInfo.RW_ST0:
|
|
if ((flags & Flags.NoRegisterUsage) == 0)
|
|
AddRegister(flags, ref usedRegisters, Register.ST0, OpAccess.ReadWrite);
|
|
break;
|
|
|
|
case CodeInfo.R_ST0:
|
|
if ((flags & Flags.NoRegisterUsage) == 0)
|
|
AddRegister(flags, ref usedRegisters, Register.ST0, OpAccess.Read);
|
|
break;
|
|
|
|
case CodeInfo.W_ST0:
|
|
if ((flags & Flags.NoRegisterUsage) == 0)
|
|
AddRegister(flags, ref usedRegisters, Register.ST0, OpAccess.Write);
|
|
break;
|
|
|
|
case CodeInfo.R_ST0_ST1:
|
|
if ((flags & Flags.NoRegisterUsage) == 0) {
|
|
AddRegister(flags, ref usedRegisters, Register.ST0, OpAccess.Read);
|
|
AddRegister(flags, ref usedRegisters, Register.ST1, OpAccess.Read);
|
|
}
|
|
break;
|
|
|
|
case CodeInfo.R_ST0_R_ST1:
|
|
if ((flags & Flags.NoRegisterUsage) == 0) {
|
|
AddRegister(flags, ref usedRegisters, Register.ST0, OpAccess.Read);
|
|
AddRegister(flags, ref usedRegisters, Register.ST1, OpAccess.Read);
|
|
}
|
|
break;
|
|
|
|
case CodeInfo.R_ST0_RW_ST1:
|
|
if ((flags & Flags.NoRegisterUsage) == 0) {
|
|
AddRegister(flags, ref usedRegisters, Register.ST0, OpAccess.Read);
|
|
AddRegister(flags, ref usedRegisters, Register.ST1, OpAccess.ReadWrite);
|
|
}
|
|
break;
|
|
|
|
case CodeInfo.RW_ST0_R_ST1:
|
|
if ((flags & Flags.NoRegisterUsage) == 0) {
|
|
AddRegister(flags, ref usedRegisters, Register.ST0, OpAccess.ReadWrite);
|
|
AddRegister(flags, ref usedRegisters, Register.ST1, OpAccess.Read);
|
|
}
|
|
break;
|
|
|
|
case CodeInfo.Clzero:
|
|
if ((flags & Flags.NoRegisterUsage) == 0) {
|
|
code = instruction.Code;
|
|
if (code == Code.Clzeroq)
|
|
baseReg = Register.RAX;
|
|
else if (code == Code.Clzerod)
|
|
baseReg = Register.EAX;
|
|
else {
|
|
Debug.Assert(code == Code.Clzerow);
|
|
baseReg = Register.AX;
|
|
}
|
|
AddRegister(flags, ref usedRegisters, baseReg, OpAccess.Read);
|
|
}
|
|
break;
|
|
|
|
case CodeInfo.Invlpga:
|
|
if ((flags & Flags.NoRegisterUsage) == 0) {
|
|
code = instruction.Code;
|
|
if (code == Code.Invlpgaq)
|
|
baseReg = Register.RAX;
|
|
else if (code == Code.Invlpgad)
|
|
baseReg = Register.EAX;
|
|
else {
|
|
Debug.Assert(code == Code.Invlpgaw);
|
|
baseReg = Register.AX;
|
|
}
|
|
if ((flags & Flags.Is64Bit) == 0)
|
|
AddRegister(flags, ref usedRegisters, Register.DS, OpAccess.Read);
|
|
AddRegister(flags, ref usedRegisters, baseReg, OpAccess.Read);
|
|
AddRegister(flags, ref usedRegisters, Register.ECX, OpAccess.Read);
|
|
}
|
|
break;
|
|
|
|
case CodeInfo.Llwpcb:
|
|
if ((flags & (Flags.NoRegisterUsage | Flags.Is64Bit)) == 0)
|
|
AddRegister(flags, ref usedRegisters, Register.DS, OpAccess.Read);
|
|
if ((flags & Flags.NoMemoryUsage) == 0)
|
|
AddMemory(flags, ref usedMemoryLocations, Register.DS, instruction.Op0Register, Register.None, 1, 0, MemorySize.Unknown, OpAccess.Read);
|
|
break;
|
|
|
|
case CodeInfo.None:
|
|
default:
|
|
throw new InvalidOperationException();
|
|
}
|
|
}
|
|
|
|
static void AddMemory(Flags flags, ref SimpleList<UsedMemory> usedMemoryLocations, Register segReg, Register baseReg, Register indexReg, int scale, ulong displ, MemorySize memorySize, OpAccess access) {
|
|
Debug.Assert((flags & Flags.NoMemoryUsage) == 0, "Caller should check flags before calling this method");
|
|
if (access != OpAccess.NoMemAccess) {
|
|
int arrayLength = usedMemoryLocations.Array.Length;
|
|
int validLen = usedMemoryLocations.ValidLength;
|
|
if (arrayLength == 0)
|
|
usedMemoryLocations.Array = new UsedMemory[defaultMemoryArrayCount];
|
|
else if (arrayLength == validLen)
|
|
Array.Resize(ref usedMemoryLocations.Array, arrayLength * 2);
|
|
usedMemoryLocations.Array[validLen] = new UsedMemory(segReg, baseReg, indexReg, scale, displ, memorySize, access);
|
|
usedMemoryLocations.ValidLength = validLen + 1;
|
|
}
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
static void AddMemorySegmentRegister(Flags flags, ref SimpleList<UsedRegister> regs, Register seg, OpAccess access) {
|
|
Debug.Assert(Register.ES <= seg && seg <= Register.GS);
|
|
// Ignore es,cs,ss,ds memory operand segment registers in 64-bit mode
|
|
if ((flags & Flags.Is64Bit) == 0 || seg >= Register.FS)
|
|
AddRegister(flags, ref regs, seg, access);
|
|
}
|
|
|
|
static void AddRegister(Flags flags, ref SimpleList<UsedRegister> regs, Register reg, OpAccess access) {
|
|
Debug.Assert((flags & Flags.NoRegisterUsage) == 0, "Caller should check flags before calling this method");
|
|
|
|
var writeReg = reg;
|
|
if ((flags & (Flags.Is64Bit | Flags.ZeroExtVecRegs)) != 0) {
|
|
Debug.Assert(OpAccess.Write + 1 == OpAccess.CondWrite);
|
|
Debug.Assert(OpAccess.Write + 2 == OpAccess.ReadWrite);
|
|
Debug.Assert(OpAccess.Write + 3 == OpAccess.ReadCondWrite);
|
|
if ((uint)(access - OpAccess.Write) <= 3) {
|
|
int index;
|
|
Debug.Assert(InstructionInfoConstants.VMM_first == Register.ZMM0);
|
|
const uint VecRegCount = InstructionInfoConstants.VMM_last - InstructionInfoConstants.VMM_first + 1;
|
|
Debug.Assert((VecRegCount & (VecRegCount - 1)) == 0);// Verify that it's a power of 2
|
|
if ((flags & Flags.Is64Bit) != 0 && (uint)(index = reg - Register.EAX) <= (Register.R15D - Register.EAX))
|
|
writeReg = Register.RAX + index;
|
|
else if ((flags & Flags.ZeroExtVecRegs) != 0 && (uint)(index = reg - Register.XMM0) <= InstructionInfoConstants.VMM_last - Register.XMM0)
|
|
writeReg = Register.ZMM0 + (index & ((int)VecRegCount - 1));
|
|
if (access != OpAccess.ReadWrite && access != OpAccess.ReadCondWrite)
|
|
reg = writeReg;
|
|
}
|
|
}
|
|
|
|
var array = regs.Array;
|
|
int validLen = regs.ValidLength;
|
|
int arrayLength = array.Length;
|
|
if (arrayLength == 0) {
|
|
// The code below that resizes the array assumes there's at least 2 new free elements, so the minimum array length is 2.
|
|
Debug.Assert(defaultRegisterArrayCount >= 2);
|
|
regs.Array = array = new UsedRegister[defaultRegisterArrayCount];
|
|
}
|
|
else {
|
|
int numRegs = writeReg == reg ? 1 : 2;
|
|
if (validLen + numRegs > arrayLength) {
|
|
Debug.Assert(arrayLength * 2 >= arrayLength + numRegs);
|
|
Array.Resize(ref regs.Array, arrayLength * 2);
|
|
array = regs.Array;
|
|
}
|
|
}
|
|
|
|
if (writeReg == reg) {
|
|
array[validLen] = new UsedRegister(reg, access);
|
|
regs.ValidLength = validLen + 1;
|
|
}
|
|
else {
|
|
Debug.Assert(access == OpAccess.ReadWrite || access == OpAccess.ReadCondWrite);
|
|
array[validLen] = new UsedRegister(reg, OpAccess.Read);
|
|
validLen++;
|
|
var lastAccess = access == OpAccess.ReadWrite ? OpAccess.Write : OpAccess.CondWrite;
|
|
array[validLen] = new UsedRegister(writeReg, lastAccess);
|
|
regs.ValidLength = validLen + 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif
|