Skip to content

Commit

Permalink
add modrm generation
Browse files Browse the repository at this point in the history
  • Loading branch information
cetio committed May 21, 2024
1 parent dca9adc commit e8b02c0
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 1 deletion.
79 changes: 79 additions & 0 deletions source/fnc/emission/x86.d
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import fnc.emission.ir;
import fnc.symbols;
import std.typecons;
import std.traits;
import std.bitmanip;

public enum CRID
{
Expand Down Expand Up @@ -363,6 +364,84 @@ enum ubyte ds = 0x3e;
enum ubyte fs = 0x64;
enum ubyte gs = 0x65;

private enum Mode
{
Memory,
MemoryOffset8,
MemoryOffsetExt,
Register
}

private union ModRM
{
public:
final:
struct
{
mixin(bitfields!(
ubyte, "src", 3,
ubyte, "dst", 3,
ubyte, "mod", 2
));
}
ubyte b;
alias b this;
}

ubyte[] generateModRM(ubyte OP)(Marker src, Marker dst, Mode mod = Mode.Register)
{
if (src.kind == Kind.REGISTER && dst.kind == Kind.REGISTER)
{
ModRM ret;
ret.src = (src.index % 8);
ret.dst = (dst.index % 8) | OP;
ret.mod = cast(ubyte)mod;
return [ret];
}
else if (src.kind == Kind.ALLOCATION && dst.kind == Kind.REGISTER)
{
if (src.size == 0)
return generateModRM!OP(Marker(dst.size, src.register, false), dst, Mode.Memory)~0x25~(cast(ubyte*)&src.offset)[0..uint.sizeof];
else
{
if (src.offset == 0)
return generateModRM!OP(Marker(dst.size, src.register, false), dst, Mode.Memory);
else
{
// TODO: SIB?
if (src.offset >= ubyte.max)
return generateModRM!OP(Marker(dst.size, src.register, false), dst, Mode.MemoryOffset8)~cast(ubyte)src.offset;
else
return generateModRM!OP(Marker(dst.size, src.register, false), dst, Mode.MemoryOffsetExt)~(cast(ubyte*)&src.offset)[0..uint.sizeof];
}
}
}
else if (src.kind == Kind.ALLOCATION && dst.kind == Kind.ALLOCATION)
return generateModRM!OP(Marker(dst.size, dst.register, false), Marker(src.size, src.register, false));
else if (src.kind == Kind.REGISTER && dst.kind == Kind.ALLOCATION)
return generateModRM!OP(dst, src);
}

enum M = 0;
// Used for generating instructions with directly encoded registers.
enum NRM = 1;
// Used for generating instructions without REX prefixes.
enum NP = 2;
enum VEX = 3;
// Used for generating integer VEX instructions.
enum VEXI = 4;
enum EVEX = 5;
enum MVEX = 6;
// Exactly the same as NP except flips dst and src.
enum SSE = 7;

// map_select
enum XOP = 0;
enum DEFAULT = 1;
enum F38 = 2;
enum F3A = 3;
enum MSR = 7;

public class Stager : IStager
{
public:
Expand Down
4 changes: 3 additions & 1 deletion source/fnc/symbols.d
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import tern.algorithm.mutation : insert, alienate;
import tern.algorithm.searching : contains, indexOf;

// All symbols may have their children accessed at comptime using `->` followed by the child name, alignment is internally align and marker is not visible.
// TODO: Interface passing as argument, alias this. Inheriting and declaring as a field?
// Guarantee order of fields in a type from inheriting.

/// The global glob from which all symbols should originate.
public static Glob glob;
Expand All @@ -18,7 +20,7 @@ shared static this()

public enum SymAttr : ulong
{
// TODO: Make sure Fern can automatically infer long from shifting
// TODO: Make sure Fern can automatically infer long from shifting,
// D doesn't do this so 1 << 32 throws an error about the fact that 1 is assumed to be int.

// Top-Level Kind
Expand Down

0 comments on commit e8b02c0

Please sign in to comment.