Cosmos/source/Lost/Assembler/JIT/AMD64/ProcessorInstruction.cs
LostTheBlack_cp 3060b02e0c AMD64 assembler:
[-] 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
2008-05-09 11:29:38 +00:00

308 lines
7.9 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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);
}
}
}