using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.IO; namespace Lost.JIT.AMD64 { [Serializable] public abstract class ProcessorInstruction { public const byte OperandSizeOverride = 0x66; public const byte AddressSizeOverride = 0x67; public abstract int? Size { get; } public abstract string ToFASM(); public abstract string OpCodeFASM { get; } public abstract void Compile(Stream destStream); public override string ToString() { return ToFASM(); } public static Rex NeedsRex(MemoryOperand memory) { if (memory.RipBased) return Rex.None; if (memory.RequiresSIB()) { Rex result = Rex.None; if ((memory.Base != null) && memory.Base.Register.IsNew()) result |= Rex.NewRegBase; if ((memory.Index != null) && memory.Index.Register.IsNew()) result |= Rex.NewRegIndex; return result; } if (memory.Index == null) { Rex result = Rex.None; if ((memory.Base != null) && memory.Base.Register.IsNew()) result |= Rex.NewRegBase; return result; } throw new NotImplementedException(); } [Obsolete("Use WriteOperand(opcode_ext, dest, destStream)")] public static byte ModRM(int ext, Registers dest) { int result = 0xC0; result += ext << 3; result += dest.GetIndex(); return (byte)result; } [Obsolete("Use WriteOperands(reg, memory, destStream)")] public static void ModRM(Registers reg, int disp32, Stream destStream) { int result = 0; result += reg == Registers.None? 0: reg.GetIndex() << 3; result += 5; destStream.WriteByte(result); destStream.WriteInt(disp32); } [Obsolete("Use WriteOperand(opcode_ext, memory, destStream)")] public static void SIB(int opcode_ext, MemoryOperand memory, Stream destStream) { int result; switch (memory.DisplacementSize) { case 0: result = 0; break; case 1: result = 1; break; //case 2: // result = 2; // break; case 4: result = 2; break; default: throw new NotSupportedException("нет текста ошибки"); } result <<= 6; result += opcode_ext << 3; result += 4; destStream.WriteByte(result); destStream.WriteByte(SIB(memory.Scale, memory.Index, memory.Base)); switch (memory.DisplacementSize) { case 0: break; case 1: destStream.WriteByte(memory.Displacement); break; //case 2: // destStream.WriteShort(disp); // break; case 4: destStream.WriteInt(memory.Displacement); break; default: throw new NotSupportedException(); } } [Obsolete("Use WriteOperands(reg, memory, destStream)")] public static void SIB(Registers reg, MemoryOperand memory, Stream destStream) { SIB(reg.GetIndex(), memory, destStream); } private static byte ModRM(int mode, int reg, int rm) { if (mode < 0 || mode >= 4) throw new ArgumentOutOfRangeException("mode", mode.ToString()); if (reg < 0 || reg >= 8) throw new ArgumentOutOfRangeException("reg", reg.ToString()); if (rm < 0 || rm >= 8) throw new ArgumentOutOfRangeException("rm", rm.ToString()); return (byte)((mode << 6) + (reg << 3) + rm); } private static byte ModRM(int mode, Registers reg, Registers rm) { return ModRM(mode, reg.GetIndex(), rm.GetIndex()); } private static byte ModRM(int mode, int opcode_ext, Registers rm) { return ModRM(mode, opcode_ext, rm.GetIndex()); } private static byte SIB(int scale, GeneralPurposeRegister index, GeneralPurposeRegister base_reg) { if (scale.BitIndex() >= 4) throw new ArgumentOutOfRangeException("scale", scale.ToString()); int result = scale.BitIndex() << 6; result += index == null? 4 << 3: index.Register.GetIndex() << 3; result += base_reg.Register.GetIndex(); return checked((byte)result); } public static void WriteOperand(int opcode_ext, MemoryOperand memory, Stream destStream) { #region RIP-based if (memory.RipBased) { destStream.WriteByte(ModRM(0, opcode_ext, Binary(101))); destStream.WriteInt(memory.Displacement); return; } #endregion #region SIB if (memory.RequiresSIB()) { if ((memory.Base != null) && (memory.Base.Register == Registers.SP)) memory.Index = GeneralPurposeRegister.SP; if (GeneralPurposeRegister.RSP.Equals(memory.Index)) if (memory.Scale == 1) { var tmp = memory.Index; memory.Index = memory.Base; memory.Base = tmp; } else throw new NotSupportedException(); int mode; switch (memory.DisplacementSize) { case 0: mode = 0; break; case 1: mode = 1; break; //case 2: // result = 2; // break; case 4: mode = 2; break; default: throw new NotSupportedException("нет текста ошибки"); } destStream.WriteByte(ModRM(mode, opcode_ext, Binary(100))); destStream.WriteByte(SIB(memory.Scale, memory.Index, memory.Base)); switch (memory.DisplacementSize) { case 0: break; case 1: destStream.WriteByte(memory.Displacement); break; //case 2: // destStream.WriteShort(disp); // break; case 4: destStream.WriteInt(memory.Displacement); break; default: throw new NotSupportedException(); } return; } #endregion #region [REG]+disp if (memory.Index == null) { if (memory.Displacement == 0) { destStream.WriteByte(ModRM(0, opcode_ext, memory.Base.Register)); return; } int mode = 0; switch (memory.DisplacementSize) { case 1: mode = Binary(01); break; case 4: mode = Binary(10); break; default: throw new NotImplementedException(); } destStream.WriteByte(ModRM(mode, opcode_ext, memory.Base.Register)); switch (memory.DisplacementSize) { case 1: destStream.WriteByte(memory.Displacement); break; case 4: destStream.WriteInt(memory.Displacement); break; default: throw new NotImplementedException(); } return; } #endregion throw new NotImplementedException(); } public static void WriteOperand(int opcode_ext, Registers rm, Stream destStream) { destStream.WriteByte(ModRM(3, opcode_ext, rm.GetIndex())); } public static void WriteOperands(Registers dest, Registers source, Stream destStream) { destStream.WriteByte(ModRM(3, dest, source)); } public static void WriteOperands(GeneralPurposeRegister reg, MemoryOperand memory, Stream destStream) { WriteOperand(reg.Register.GetIndex(), memory, destStream); } static byte Binary(int value) { int result = 0; for (int bit = 0; value > 0; bit++, value /= 10) switch (value % 10) { case 0: break; case 1: result += 1 << bit; break; default: throw new ArgumentException("value"); } return (byte)result; } protected static class MOD { /// /// регистр-регистр /// public const int RegReg = 0x3; /// /// Адресация без смещения /// public const int SBI = 0x00; /// /// Адресация с 8-ми битным смещением /// public const int D8 = 0x1; /// /// Адресация со смещением 16 или 32 /// public const int DX = 0x2; } protected static class RM { /// /// Используется SIB если RM == UseSIB /// public const int UseSIB = 0x04; } } static class AMDAssemblerStreamExtensions { public static void WriteRex(this Stream stream, Rex value) { stream.WriteByte((byte)value); } } }