Очевидная вещь, которую нужно сделать, - это создать набор абстракций, которые представляют генерацию интересующих вас машинных инструкций, а затем составить вызовы, чтобы получить нужные режимы инструкций / адресации. Если вы генерируете широкий спектр кода, вы можете в итоге кодировать весь набор команд таким образом.
Затем, чтобы сгенерировать инструкцию MOV, вы можете написать код, который выглядит следующим образом:
ObjectCodeEmitMovRegister32ScaledRegister32OffsetRegister32(EAX,EDX,4,-LowerBound*4,ESP);
Ты можешь сказать, что мне нравятся длинные имена. (По крайней мере, я никогда не забуду, что они делают.)
Вот некоторые кусочки генератора кода, поддерживающего это, который я реализовал в Си давным-давно. Это охватывает вид самой сложной части, которая является генерацией байтов MOD и SIB. Следуя этому стилю, вы можете реализовать столько инструкций, сколько захотите. Этот пример только для x32, поэтому OP придется расширять и модифицировать соответственно. Определение генератора команд MOV в конце не работает.
#define Register32T enum Register32Type
enum Register32Type {EAX=0,ECX=1,EDX=2,EBX=3,ESP=4,EBP=5,ESI=6,EDI=7};
inline
byte ObjectCodeEmitModRM32Register32(Register32T Register32,Register32T BaseRegister32)
// Send ModRM32Bytes for register-register mode to object file
{ byte ModRM32Byte=0xC0+Register32*0x8+BaseRegister32;
ObjectCodeEmitByte(ModRM32Byte);
return ModRM32Byte;
}
inline
byte ObjectCodeEmitModRM32Direct(Register32T Register32)
// Send ModRM32Bytes for direct address mode to object file
{ byte ModRM32Byte=Register32*0x8+0x05;
ObjectCodeEmitByte(ModRM32Byte);
return ModRM32Byte;
}
inline
void ObjectCodeEmitSIB(Register32T ScaledRegister32,
natural Scale,
Register32T BaseRegister32)
// send SIB byte to object file
// Note: Use ESP for ScaledRegister32 to disable scaling; only useful when using ESP for BASE.
{ if (ScaledRegister32==ESP && BaseRegister32!=ESP) CompilerFault(31);
if (Scale==1) ObjectCodeEmitByte((byte)(0x00+ScaledRegister32*0x8+BaseRegister32));
else if (Scale==2) ObjectCodeEmitByte((byte)(0x40+ScaledRegister32*0x8+BaseRegister32));
else if (Scale==4) ObjectCodeEmitByte((byte)(0x80+ScaledRegister32*0x8+BaseRegister32));
else if (Scale==8) ObjectCodeEmitByte((byte)(0xC0+ScaledRegister32*0x8+BaseRegister32));
else CompilerFault(32);
}
inline
byte ObjectCodeEmitModRM32OffsetRegister32(Register32T Register32,
integer Offset,
Register32T BaseRegister32)
// Send ModRM32Bytes for indexed address mode to object file
// Returns 1st byte of ModRM32 for possible use in EmittedPushRM32 peephole optimization
{ byte ModRM32Byte;
if (Offset==0 && BaseRegister32!=EBP)
{ ModRM32Byte=0x00+Register32*0x8+BaseRegister32;
ObjectCodeEmitByte(ModRM32Byte);
if (BaseRegister32==ESP) ObjectCodeEmitSIB(ESP,1,ESP);
}
else if (Offset>=-128 && Offset<=127)
{ ModRM32Byte=0x40+Register32*0x8+BaseRegister32;
ObjectCodeEmitByte(ModRM32Byte);
if (BaseRegister32==ESP) ObjectCodeEmitSIB(ESP,1,ESP);
ObjectCodeEmitByte((byte)Offset);
}
else { // large offset
ModRM32Byte=0x80+Register32*0x8+BaseRegister32;
ObjectCodeEmitByte(ModRM32Byte);
if (BaseRegister32==ESP) ObjectCodeEmitSIB(ESP,1,ESP);
ObjectCodeEmitDword(Offset);
}
return ModRM32Byte;
}
inline
byte ObjectCodeEmitModRM32OffsetScaledRegister32(Register32T Register32,
integer Offset,
Register32T ScaledRegister32,
natural Scale)
// Send ModRM32Bytes for indexing by a scaled register with no base register to object file
// Returns 1st byte of ModRM32 for possible use in EmittedPushRM32 peephole optimization
{ byte ModRM32Byte=0x00+Register32*0x8+ESP;
ObjectCodeEmitByte(ModRM32Byte); // MOD=00 --> SIB does disp32[index]
ObjectCodeEmitSIB(ScaledRegister32,Scale,EBP);
ObjectCodeEmitDword(Offset);
return ModRM32Byte;
}
inline
byte ObjectCodeEmitModRM32ScaledRegister32OffsetRegister32(Register32T Register32,
Register32T ScaledRegister32,
natural Scale,
integer Offset,
Register32T BaseRegister32)
// Send ModRM32Bytes for indexed address mode to object file
// Returns 1st byte of ModRM32 for possible use in EmittedPushRM32 peephole optimization
// If Scale==0, leave scale and scaled register out of the computation
{ byte ModRM32Byte;
if (Scale==0) ObjectCodeEmitModRM32OffsetRegister32(Register32,Offset,BaseRegister32);
else if (Offset==0 && BaseRegister32!=EBP)
{ ModRM32Byte=0x00+Register32*0x8+ESP;
ObjectCodeEmitByte(ModRM32Byte);
ObjectCodeEmitSIB(ScaledRegister32,Scale,BaseRegister32);
}
else if (Offset>=-128 && Offset<=127)
{ ModRM32Byte=0x40+Register32*0x8+ESP;
ObjectCodeEmitByte(ModRM32Byte);
ObjectCodeEmitSIB(ScaledRegister32,Scale,BaseRegister32);
ObjectCodeEmitByte((byte)Offset);
}
else { // large offset
ModRM32Byte=0x80+Register32*0x8+ESP;
ObjectCodeEmitByte(ModRM32Byte);
ObjectCodeEmitSIB(ScaledRegister32,Scale,BaseRegister32);
ObjectCodeEmitDword(Offset);
}
return ModRM32Byte;
}
inline
void ObjectCodeEmitLeaRegister32OffsetRegister32ScaledPlusBase32(
Register32T Register32Destination,
integer Offset,
Register32T Register32Source,
natural Scale, // 1,2,4 or 8
Register32T Base)
// send "LEA Register32,offset[Register32*Scale+Base]" to object file
{ ObjectCodeEmitLeaOpcode();
ObjectCodeEmitModRM32ScaledRegister32OffsetRegister32(
Register32Destination,Register32Source,Scale,Offset,Base);
}
inline
void ObjectCodeEmitMovRegister32ScaledRegister32OffsetRegister32(Register32T DestinationRegister32,
Register32T ScaledRegister32,
natural Scale,
integer Offset,
Register32T BaseRegister32)
// Emit Mov R32 using scaled index addressing
{ ObjectCodeEmitMovRegister32Opcode();
ObjectCodeEmitModRM32ScaledRegister32OffsetRegister32(DestinationRegister32,
ScaledRegister32,
Scale,
Offset,
BaseRegister32);
}