Skip to content

Instantly share code, notes, and snippets.

@pervognsen
Created May 14, 2016 20:31
Show Gist options
  • Save pervognsen/a460b1135ccd7840959de02b15e43eb2 to your computer and use it in GitHub Desktop.
Save pervognsen/a460b1135ccd7840959de02b15e43eb2 to your computer and use it in GitHub Desktop.
x64 machine code emitter
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <windows.h>
#include <stdint.h>
#define Assert(x) \
if (!(x)) { MessageBoxA(0, #x, "Assertion Failure", MB_OK); __debugbreak(); }
enum Register {
RAX = 0,
RCX = 1,
RDX = 2,
RBX = 3,
RSP = 4,
RBP = 5,
RSI = 6,
RDI = 7,
R8 = 8,
R9 = 9,
R10 = 10,
R11 = 11,
R12 = 12,
R13 = 13,
R14 = 14,
R15 = 15
};
enum Scale {
X1 = 0,
X2 = 1,
X4 = 2,
X8 = 3
};
enum Mode {
INDIRECT = 0,
INDIRECT_BYTE_DISPLACED = 1,
INDIRECT_DISPLACED = 2,
DIRECT = 3,
};
enum ConditionCode {
O,
NO,
B,
NB,
E,
NE,
NA,
A,
S,
NS,
P,
NP,
L,
NL,
NG,
G,
NAE = B,
C = B,
AE = NB,
NC = NB,
Z = E,
NZ = NE,
BE = NA,
NBE = A,
PE = P,
PO = NP,
NGE = L,
GE = NL,
LE = NG,
NLE = G
};
uint8_t code[1024 * 1024];
uint8_t *next_code = code;
void Emit(uint8_t value) {
*next_code = value;
next_code++;
}
void Emit4(uint32_t value) {
Emit(value & 0xFF);
Emit((value >> 8) & 0xFF);
Emit((value >> 16) & 0xFF);
Emit((value >> 24) & 0xFF);
}
void Emit8(uint64_t value) {
Emit(value & 0xFF);
Emit((value >> 8) & 0xFF);
Emit((value >> 16) & 0xFF);
Emit((value >> 24) & 0xFF);
Emit((value >> 32) & 0xFF);
Emit((value >> 40) & 0xFF);
Emit((value >> 48) & 0xFF);
Emit((value >> 56) & 0xFF);
}
void EmitModRxRm(uint8_t mod, uint8_t rx, uint8_t rm) {
Assert(mod < 4);
Assert(rx < 16);
Assert(rm < 16);
Emit((mod << 6) | ((rx & 7) << 3) | (rm & 7));
}
void EmitRexIndexed(uint8_t rx, uint8_t base, uint8_t index) {
Emit(0x48 | (base >> 3) | ((index >> 3) << 1) | ((rx >> 3) << 2));
}
void EmitRex(uint8_t rx, uint8_t base) {
EmitRexIndexed(rx, base, 0);
}
// op rax, rcx
// rx = RAX, reg = RCX
void EmitDirect(uint8_t rx, Register reg) {
EmitModRxRm(DIRECT, rx, reg);
}
// op rax, [rcx]
// rx = RAX, base = RCX
void EmitIndirect(uint8_t rx, Register base) {
Assert((base & 7) != RSP);
Assert((base & 7) != RBP);
EmitModRxRm(INDIRECT, rx, base);
}
// op rax, [rip + 0x12345678]
// rx = RAX, displacement = 0x12345678
void EmitIndirectDisplacedRip(uint8_t rx, int32_t displacement) {
EmitModRxRm(INDIRECT, rx, RBP);
Emit4(displacement);
}
// op rax, [rcx + 0x12]
// rx = RAX, base = RCX, displacement = 0x12
void EmitIndirectByteDisplaced(uint8_t rx, Register base, int8_t displacement) {
Assert((base & 7) != RSP);
EmitModRxRm(INDIRECT_BYTE_DISPLACED, rx, base);
Emit(displacement);
}
// op rax, [rcx + 0x12345678]
// rx = RAX, base = RCX, displacement = 0x12345678
void EmitIndirectDisplaced(uint8_t rx, Register base, int32_t displacement) {
Assert((base & 7) != RSP);
EmitModRxRm(INDIRECT_DISPLACED, rx, base);
Emit4(displacement);
}
// op rax, [rcx + 4*rdx]
// rx = RAX, base = RCX, index = RDX, scale = X4
void EmitIndirectIndexed(uint8_t rx, Register base, Register index, Scale scale) {
Assert((base & 7) != RBP);
EmitModRxRm(INDIRECT, rx, RSP);
EmitModRxRm(scale, index, base);
}
// op rax, [rcx + 4*rdx + 0x12]
// rx = RAX, base = RCX, index = RDX, scale = X4, displacement = 0x12
void EmitIndirectIndexedByteDisplaced(uint8_t rx, Register base, Register index, Scale scale, int8_t displacement) {
EmitModRxRm(INDIRECT_BYTE_DISPLACED, rx, RSP);
EmitModRxRm(scale, index, base);
Emit(displacement);
}
// op rax, [rcx + 4*rdx + 0x12345678]
// rx = RAX, base = RCX, index = RDX, scale = X4, displacement = 0x12345678
void EmitIndirectIndexedDisplaced(uint8_t rx, Register base, Register index, Scale scale, int32_t displacement) {
EmitModRxRm(INDIRECT_DISPLACED, rx, RSP);
EmitModRxRm(scale, index, base);
Emit4(displacement);
}
// op rax, [0x12345678]
// rx = RAX, displacement = 0x12345678
void EmitDisplaced(uint8_t rx, int32_t displacement) {
EmitModRxRm(INDIRECT, rx, RSP);
EmitModRxRm(X1, RSP, RBP);
Emit4(displacement);
}
#define EMIT_I(operation, source_immediate) \
EmitRex(0, 0); \
Emit_##operation##_I(); \
Emit4(source_immediate)
#define EMIT_MOV_R_I(destination, source_immediate) \
EmitRex(destination, 0); \
Emit(0xB8); \
Emit8(source_immediate)
#define EMIT_MOV_RAX_OFF(source_offset) \
EmitRex(0, 0); \
Emit(0xA1); \
Emit8(source_offset)
#define EMIT_MOV_OFF_RAX(destination_offset) \
EmitRex(0, 0); \
Emit(0xA3); \
Emit8(destination_offset)
#define EMIT_R_R(operation, destination, source) \
EmitRex(destination, source); \
Emit_##operation##_R(); \
EmitDirect(destination, source)
#define EMIT_R_RIPD(operation, destination, source_displacement) \
EmitRex(destination, 0); \
Emit_##operation##_R(); \
EmitIndirectDisplacedRip(destination, source_displacement);
#define EMIT_R_D(operation, destination, source_displacement) \
EmitRex(destination, 0); \
Emit_##operation##_R(); \
EmitDisplaced(destination, source_displacement)
#define EMIT_R_M(operation, destination, source) \
EmitRex(destination, source); \
Emit_##operation##_R(); \
EmitIndirect(destination, source)
#define EMIT_R_MD1(operation, destination, source, source_displacement) \
EmitRex(destination, source); \
Emit_##operation##_R(); \
EmitIndirectByteDisplaced(destination, source, source_displacement)
#define EMIT_R_MD(operation, destination, source, source_displacement) \
EmitRex(destination, source); \
Emit_##operation##_R(); \
EmitIndirectDisplaced(destination, source, source_displacement)
#define EMIT_R_SIB(operation, destination, source_base, source_scale, source_index) \
EmitRexIndexed(destination, source_base, source_index); \
Emit_##operation##_R(); \
EmitIndirectIndexed(destination, source_base, source_index, source_scale)
#define EMIT_R_SIBD1(operation, destination, source_base, source_scale, source_index, source_displacement) \
EmitRexIndexed(destination, source_base, source_index); \
Emit_##operation##_R(); \
EmitIndirectIndexedByteDisplaced(destination, source_base, source_index, source_scale, source_displacement)
#define EMIT_R_SIBD(operation, destination, source_base, source_scale, source_index, source_displacement) \
EmitRexIndexed(destination, source_base, source_index); \
Emit_##operation##_R(); \
EmitIndirectIndexedDisplaced(destination, source_base, source_index, source_scale, source_displacement)
#define EMIT_M_R(operation, destination, source) \
EmitRex(source, destination); \
Emit_##operation##_M(); \
EmitIndirect(source, destination)
#define EMIT_D_R(operation, destination_displacement, source) \
EmitRex(source, 0); \
Emit_##operation##_M(); \
EmitDisplaced(source, destination_displacement)
#define EMIT_RIPD_R(operation, destination_displacement, source) \
EmitRex(source, 0); \
Emit_##operation##_M(); \
EmitIndirectDisplacedRip(source, destination_displacement);
#define EMIT_MD1_R(operation, destination, destination_displacement, source) \
EmitRex(source, destination); \
Emit_##operation##_M(); \
EmitIndirectByteDisplaced(source, destination, destination_displacement)
#define EMIT_MD_R(operation, destination, destination_displacement, source) \
EmitRex(source, destination); \
Emit_##operation##_M(); \
EmitIndirectDisplaced(source, destination, destination_displacement)
#define EMIT_SIB_R(operation, destination_base, destination_scale, destination_index, source) \
EmitRexIndexed(source, destination_base, destination_index); \
Emit_##operation##_M(); \
EmitIndirectIndexed(source, destination_base, destination_index, destination_scale)
#define EMIT_SIBD1_R(operation, destination_base, destination_scale, destination_index, destination_displacement, source) \
EmitRexIndexed(source, destination_base, destination_index); \
Emit_##operation##_M(); \
EmitIndirectIndexedByteDisplaced(source, destination_base, destination_index, destination_scale, destination_displacement)
#define EMIT_SIBD_R(operation, destination_base, destination_scale, destination_index, destination_displacement, source) \
EmitRexIndexed(source, destination_base, destination_index); \
Emit_##operation##_M(); \
EmitIndirectIndexedDisplaced(source, destination_base, destination_index, destination_scale, destination_displacement)
#define EMIT_R_I(operation, destination, source_immediate) \
EmitRex(0, destination); \
Emit_##operation##_I(); \
EmitDirect(extension_##operation##_I, destination); \
Emit4(source_immediate)
#define EMIT_M_I(operation, destination, source_immediate) \
EmitRex(0, destination); \
Emit_##operation##_I(); \
EmitIndirect(extension_##operation##_I, destination); \
Emit4(source_immediate)
#define EMIT_D_I(operation, destination_displacement, source_immediate) \
EmitRex(0, 0); \
Emit_##operation##_I(); \
EmitDisplaced(extension_##operation##_I, destination_displacement); \
Emit4(source_immediate)
#define EMIT_RIPD_I(operation, destination_displacement, source_immediate) \
EmitRex(0, 0); \
Emit_##operation##_I(); \
EmitIndirectDisplacedRip(extension_##operation##_I, destination_displacement); \
Emit4(source_immediate)
#define EMIT_MD1_I(operation, destination, destination_displacement, source_immediate) \
EmitRex(0, destination); \
Emit_##operation##_I(); \
EmitIndirectByteDisplaced(extension_##operation##_I, destination, destination_displacement); \
Emit4(source_immediate)
#define EMIT_MD_I(operation, destination, destination_displacement, source_immediate) \
EmitRex(0, destination); \
Emit_##operation##_I(); \
EmitIndirectDisplaced(extension_##operation##_I, destination, destination_displacement); \
Emit4(source_immediate)
#define EMIT_SIB_I(operation, destination_base, destination_scale, destination_index, source_immediate) \
EmitRexIndexed(0, destination_base, destination_index); \
Emit_##operation##_I(); \
EmitIndirectIndexed(extension_##operation##_I, destination_base, destination_index, destination_scale); \
Emit4(source_immediate)
#define EMIT_SIBD1_I(operation, destination_base, destination_scale, destination_index, destination_displacement, source_immediate) \
EmitRexIndexed(0, destination_base, destination_index); \
Emit_##operation##_I(); \
EmitIndirectIndexedByteDisplaced(extension_##operation##_I, destination_base, destination_index, destination_scale, destination_displacement); \
Emit4(source_immediate)
#define EMIT_SIBD_I(operation, destination_base, destination_scale, destination_index, destination_displacement, source_immediate) \
EmitRexIndexed(0, destination_base, destination_index); \
Emit_##operation##_I(); \
EmitIndirectIndexedDisplaced(extension_##operation##_I, destination_base, destination_index, destination_scale, destination_displacement); \
Emit4(source_immediate)
#define EMIT_X_R(operation, source) \
EmitRex(0, source); \
Emit_##operation##_X(); \
EmitDirect(extension_##operation##_X, source)
#define EMIT_X_RIPD(operation, source_displacement) \
EmitRex(0, 0); \
Emit_##operation##_X(); \
EmitIndirectDisplacedRip(extension_##operation##_X, source_displacement);
#define EMIT_X_D(operation, source_displacement) \
EmitRex(0, 0); \
Emit_##operation##_X(); \
EmitDisplaced(extension_##operation##_X, source_displacement)
#define EMIT_X_M(operation, source) \
EmitRex(0, source); \
Emit_##operation##_X(); \
EmitIndirect(extension_##operation##_X, source)
#define EMIT_X_MD1(operation, source, source_displacement) \
EmitRex(0, source); \
Emit_##operation##_X(); \
EmitIndirectByteDisplaced(extension_##operation##_X, source, source_displacement)
#define EMIT_X_MD(operation, source, source_displacement) \
EmitRex(0, source); \
Emit_##operation##_X(); \
EmitIndirectDisplaced(extension_##operation##_X, source, source_displacement)
#define EMIT_X_SIB(operation, source_base, source_scale, source_index) \
EmitRexIndexed(0, source_base, source_index); \
Emit_##operation##_X(); \
EmitIndirectIndexed(extension_##operation##_X, source_base, source_index, source_scale)
#define EMIT_X_SIBD1(operation, source_base, source_scale, source_index, source_displacement) \
EmitRexIndexed(0, source_base, source_index); \
Emit_##operation##_X(); \
EmitIndirectIndexedByteDisplaced(extension_##operation##_X, source_base, source_index, source_scale, source_displacement)
#define EMIT_X_SIBD(operation, source_base, source_scale, source_index, source_displacement) \
EmitRexIndexed(0, source_base, source_index); \
Emit_##operation##_X(); \
EmitIndirectIndexedDisplaced(extension_##operation##_X, source_base, source_index, source_scale, source_displacement)
#define EMIT_C_I(operation, condition_code, source_immediate) \
Emit_##operation##_C_I(condition_code); \
Emit4(source_immediate)
#define OP1R(operation, opcode) \
void Emit_##operation##_R() { \
Emit(opcode); \
}
#define OP1M(operation, opcode) \
void Emit_##operation##_M() { \
Emit(opcode); \
}
#define OP1I(operation, opcode, extension) \
void Emit_##operation##_I() { \
Emit(opcode); \
} \
enum { extension_##operation##_I = extension };
#define OP1X(operation, opcode, extension) \
void Emit_##operation##_X() { \
Emit(opcode); \
} \
enum { extension_##operation##_X = extension };
#define OP2CI(operation, opcode) \
void Emit_##operation##_C_I(ConditionCode condition_code) { \
Emit(0x0F); \
Emit(opcode + condition_code); \
}
// Instructions
OP1R(MOV, 0x8B)
OP1M(MOV, 0x89)
OP1R(ADD, 0x03)
OP1M(ADD, 0x01)
OP1I(ADD, 0x81, 0x00)
OP1R(AND, 0x23)
OP1M(AND, 0x21)
OP1I(AND, 0x81, 0x04)
OP1X(MUL, 0xF7, 0x04)
OP1I(JMP, 0xE9, 0x00)
OP2CI(J, 0x80)
// Tests
extern "C" void assembly_test();
int main(int argc, char **argv) {
EMIT_MOV_R_I(RBX, 0x12345678deadbeefull);
EMIT_MOV_RAX_OFF(0x12345678deadbeefull);
EMIT_MOV_OFF_RAX(0x12345678deadbeefull);
EMIT_R_R(MOV, RAX, R10);
EMIT_M_R(MOV, RAX, R10);
EMIT_I(JMP, 0x1234);
EMIT_C_I(J, NZ, 0x1234);
EMIT_C_I(J, NZ, 0x1234);
EMIT_C_I(J, NZ, 0x1234);
EMIT_D_I(ADD, 0x1234578, 0xDEADBEEF);
EMIT_RIPD_I(ADD, 0x1234578, 0xDEADBEEF);
for (uint8_t d = RAX; d <= R15; d++) {
Register destination = (Register)d;
EMIT_X_R(MUL, destination);
if ((destination & 7) != RSP) {
EMIT_X_MD1(MUL, destination, 0x12);
EMIT_X_MD(MUL, destination, 0x12345678);
if ((destination & 7) != RBP) {
EMIT_X_M(MUL, destination);
EMIT_X_SIB(MUL, destination, X4, R8);
EMIT_X_SIBD1(MUL, destination, X4, R8, 0x12);
EMIT_X_SIBD(MUL, destination, X4, R8, 0x12345678);
}
}
EMIT_R_I(ADD, destination, 0xDEADBEEF);
if ((destination & 7) != RSP) {
EMIT_MD1_I(ADD, destination, 0x12, 0xDEADBEEF);
EMIT_MD_I(ADD, destination, 0x12345678, 0xDEAFBEEF);
if ((destination & 7) != RBP) {
EMIT_SIB_I(ADD, destination, X4, R8, 0xDEADBEEF);
}
}
EMIT_R_RIPD(ADD, destination, 0x1235678);
EMIT_R_D(ADD, destination, 0x1235678);
EMIT_RIPD_R(ADD, 0x1235678, destination);
EMIT_D_R(ADD, 0x1235678, destination);
for (uint8_t s = RAX; s <= R15; s++) {
Register source = (Register)s;
EMIT_R_R(ADD, destination, source);
if ((source & 7) != RBP) {
EMIT_R_SIB(ADD, destination, source, X4, destination);
EMIT_R_SIBD1(ADD, destination, source, X4, destination, 0x12);
EMIT_R_SIBD(ADD, destination, source, X4, destination, 0x12345678);
}
if ((destination & 7) != RBP) {
EMIT_SIB_R(ADD, destination, X4, source, source);
EMIT_SIBD1_R(ADD, destination, X4, source, 0x12, source);
EMIT_SIBD_R(ADD, destination, X4, source, 0x12345678, source);
}
if ((source & 7) != RSP && (source & 7) != RBP) {
EMIT_R_M(ADD, destination, source);
EMIT_R_MD1(ADD, destination, source, 0x12);
EMIT_R_MD(ADD, destination, source, 0x12345678);
}
if ((destination & 7) != RSP && (destination & 7) != RBP) {
EMIT_M_R(ADD, destination, source);
EMIT_MD1_R(ADD, destination, 0x12, source);
EMIT_MD_R(ADD, destination, 0x12345678, source);
}
if ((source & 7) == RSP) {
EMIT_R_SIB(ADD, destination, source, X1, RSP);
#if 0
EmitRex(destination, source);
EmitAddToRegister();
EmitIndirectIndexed(destination, source, RSP, X1);
#endif
}
}
}
FILE *file = fopen("d:\\be\\test.bin", "wb");
fwrite(code, next_code - code, 1, file);
fclose(file);
// assembly_test();
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment