mirror of
https://github.com/danbulant/Cosmos
synced 2026-05-27 22:12:25 +00:00
[-] some unnecessary overloads [+] overloaded operators in order to allow defining memory operands easily [+] overloaded automatic conversions to allow operands [+] Labels support [+] code generator based on F# started
308 lines
7.9 KiB
C#
308 lines
7.9 KiB
C#
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
|
||
{
|
||
/// <summary>
|
||
/// регистр-регистр
|
||
/// </summary>
|
||
public const int RegReg = 0x3;
|
||
/// <summary>
|
||
/// Адресация без смещения
|
||
/// </summary>
|
||
public const int SBI = 0x00;
|
||
/// <summary>
|
||
/// Адресация с 8-ми битным смещением
|
||
/// </summary>
|
||
public const int D8 = 0x1;
|
||
/// <summary>
|
||
/// Адресация со смещением 16 или 32
|
||
/// </summary>
|
||
public const int DX = 0x2;
|
||
}
|
||
protected static class RM
|
||
{
|
||
/// <summary>
|
||
/// Используется SIB если RM == UseSIB
|
||
/// </summary>
|
||
public const int UseSIB = 0x04;
|
||
}
|
||
}
|
||
|
||
static class AMDAssemblerStreamExtensions
|
||
{
|
||
public static void WriteRex(this Stream stream, Rex value)
|
||
{
|
||
stream.WriteByte((byte)value);
|
||
}
|
||
}
|
||
}
|