|
|
@@ -0,0 +1,224 @@ |
|
|
|
/* |
|
|
|
Copyright (c) 2023 : Ognjen 'xolatile' Milan Robovic |
|
|
|
|
|
|
|
Xiasma is free software! You will redistribute it or modify it under the terms of the GNU General Public License by Free Software Foundation. |
|
|
|
And when you do redistribute it or modify it, it will use either version 3 of the License, or (at yours truly opinion) any later version. |
|
|
|
It is distributed in the hope that it will be useful or harmful, it really depends... But no warranty what so ever, seriously. See GNU/GPLv3. |
|
|
|
*/ |
|
|
|
|
|
|
|
#include <xolatile/xtandard.c> |
|
|
|
|
|
|
|
enum { |
|
|
|
FORMAT_NULL, |
|
|
|
FORMAT_REGISTER, FORMAT_VARIABLE, FORMAT_CONSTANT, FORMAT_VARIADIC, |
|
|
|
FORMAT_REGISTER_REGISTER, FORMAT_REGISTER_VARIABLE, FORMAT_REGISTER_CONSTANT, FORMAT_VARIABLE_REGISTER, |
|
|
|
FORMAT_VARIABLE_CONSTANT, FORMAT_VARIADIC_REGISTER, FORMAT_VARIADIC_VARIABLE, FORMAT_VARIADIC_CONSTANT, |
|
|
|
FORMAT_COUNT |
|
|
|
}; |
|
|
|
|
|
|
|
enum { |
|
|
|
INSTRUCTION_NO_OPERATION, INSTRUCTION_MOVE, INSTRUCTION_CALL, INSTRUCTION_RETURN, |
|
|
|
INSTRUCTION_SYSTEM_ENTER, INSTRUCTION_SYSTEM_EXIT, INSTRUCTION_SYSTEM_CALL, INSTRUCTION_SYSTEM_RETURN, |
|
|
|
INSTRUCTION_ADD, INSTRUCTION_BIT_OR, INSTRUCTION_ADD_CARRY, INSTRUCTION_SUBTRACT_CARRY, |
|
|
|
INSTRUCTION_BIT_AND, INSTRUCTION_SUBTRACT, INSTRUCTION_BIT_EXCLUSIVE_OR, INSTRUCTION_COMPARE, |
|
|
|
INSTRUCTION_COUNT |
|
|
|
}; |
|
|
|
|
|
|
|
enum { |
|
|
|
REGISTER_0_64, REGISTER_1_64, REGISTER_2_64, REGISTER_3_64, REGISTER_4_64, REGISTER_5_64, REGISTER_6_64, REGISTER_7_64, |
|
|
|
REGISTER_8_64, REGISTER_9_64, REGISTER_A_64, REGISTER_B_64, REGISTER_C_64, REGISTER_D_64, REGISTER_E_64, REGISTER_F_64, |
|
|
|
REGISTER_0_32, REGISTER_1_32, REGISTER_2_32, REGISTER_3_32, REGISTER_4_32, REGISTER_5_32, REGISTER_6_32, REGISTER_7_32, |
|
|
|
REGISTER_8_32, REGISTER_9_32, REGISTER_A_32, REGISTER_B_32, REGISTER_C_32, REGISTER_D_32, REGISTER_E_32, REGISTER_F_32, |
|
|
|
REGISTER_0_16, REGISTER_1_16, REGISTER_2_16, REGISTER_3_16, REGISTER_4_16, REGISTER_5_16, REGISTER_6_16, REGISTER_7_16, |
|
|
|
REGISTER_8_16, REGISTER_9_16, REGISTER_A_16, REGISTER_B_16, REGISTER_C_16, REGISTER_D_16, REGISTER_E_16, REGISTER_F_16, |
|
|
|
REGISTER_0_8, REGISTER_1_8, REGISTER_2_8, REGISTER_3_8, REGISTER_4_8, REGISTER_5_8, REGISTER_6_8, REGISTER_7_8, |
|
|
|
REGISTER_8_8, REGISTER_9_8, REGISTER_A_8, REGISTER_B_8, REGISTER_C_8, REGISTER_D_8, REGISTER_E_8, REGISTER_F_8, |
|
|
|
REGISTER_0_8X, REGISTER_1_8X, REGISTER_2_8X, REGISTER_3_8X, |
|
|
|
REGISTER_COUNT |
|
|
|
}; |
|
|
|
|
|
|
|
static void (* encode [FORMAT_COUNT] [INSTRUCTION_COUNT]) (int instruction, int left, int right); |
|
|
|
|
|
|
|
static int data [16] = { 0 }; |
|
|
|
|
|
|
|
static void data_push (int byte) { data [0]++; data [data [0]] = byte; } |
|
|
|
static void data_pop (void) { data [data [0]] = 0X00; data [0]--; } |
|
|
|
static int data_look (int look) { return (data [look]); } |
|
|
|
static int data_size (void) { return (data [0]); } |
|
|
|
static void data_free (void) { data [0] = 0; } |
|
|
|
|
|
|
|
static void data_echo (void) { |
|
|
|
char byte [4] = " "; |
|
|
|
int i; |
|
|
|
|
|
|
|
for (i = 0; i != data [0]; ++i) { |
|
|
|
byte [0] = "0123456789ABCDEF" [data [i + 1] / 16]; |
|
|
|
byte [1] = "0123456789ABCDEF" [data [i + 1] % 16]; |
|
|
|
echo (byte); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
static void unimplemented (int instruction, int left, int right) { |
|
|
|
(void) instruction; |
|
|
|
(void) left; |
|
|
|
(void) right; |
|
|
|
|
|
|
|
fatal_failure (1, "Unimplemented..."); |
|
|
|
} |
|
|
|
|
|
|
|
static int register_word (char * name) { |
|
|
|
char * register_name [REGISTER_COUNT] = { |
|
|
|
"rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi", |
|
|
|
"r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", |
|
|
|
"eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi", |
|
|
|
"r8d", "r9d", "r10d", "r11d", "r12d", "r13d", "r14d", "r15d", |
|
|
|
"ax", "cx", "dx", "bx", "sp", "bp", "si", "di", |
|
|
|
"r8w", "r9w", "r10w", "r11w", "r12w", "r13w", "r14w", "r15w", |
|
|
|
"al", "cl", "dl", "bl", "spl", "bpl", "sil", "dil", |
|
|
|
"r8b", "r9b", "r10b", "r11b", "r12b", "r13b", "r14b", "r15b", |
|
|
|
"ah", "ch", "dh", "bh" |
|
|
|
}; |
|
|
|
|
|
|
|
int i; |
|
|
|
|
|
|
|
for (i = 0; i != REGISTER_COUNT; ++i) { |
|
|
|
if (string_compare (name, register_name [i]) != 0) { |
|
|
|
return (i); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return (-1); |
|
|
|
} |
|
|
|
|
|
|
|
static int instruction_word (char * name) { |
|
|
|
char * instruction_name [INSTRUCTION_COUNT] = { |
|
|
|
"nop", "mov", "call", "ret", "sysenter", "sysexit", "syscall", "sysret", |
|
|
|
"add", "or", "adc", "sbb", "and", "sub", "xor", "cmp" |
|
|
|
}; |
|
|
|
|
|
|
|
int i; |
|
|
|
|
|
|
|
for (i = 0; i != INSTRUCTION_COUNT; ++i) { |
|
|
|
if (string_compare (name, instruction_name [i]) != 0) { |
|
|
|
return (i); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return (-1); |
|
|
|
} |
|
|
|
|
|
|
|
static void prefix_register_size (int left, int right) { |
|
|
|
if ((left >= REGISTER_0_64) && (left <= REGISTER_7_64) && (right >= REGISTER_0_64) && (right <= REGISTER_7_64)) { |
|
|
|
data_push (0X48); |
|
|
|
} else if ((left >= REGISTER_8_64) && (left <= REGISTER_F_64) && (right >= REGISTER_0_64) && (right <= REGISTER_7_64)) { |
|
|
|
data_push (0X49); |
|
|
|
} else if ((left >= REGISTER_0_64) && (left <= REGISTER_7_64) && (right >= REGISTER_8_64) && (right <= REGISTER_F_64)) { |
|
|
|
data_push (0X4C); |
|
|
|
} else if ((left >= REGISTER_8_64) && (left <= REGISTER_F_64) && (right >= REGISTER_8_64) && (right <= REGISTER_F_64)) { |
|
|
|
data_push (0X4D); |
|
|
|
} else if ((left >= REGISTER_0_16) && (left <= REGISTER_7_16)) { |
|
|
|
data_push (0X66); |
|
|
|
} else if ((left >= REGISTER_8_16) && (left <= REGISTER_F_16)) { |
|
|
|
data_push (0X67); |
|
|
|
} else { |
|
|
|
fatal_failure (1, "prefix_register_size"); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
static void infix_regular_instruction (int instruction) { |
|
|
|
switch (instruction) { |
|
|
|
case INSTRUCTION_ADD: data_push (0X01); break; |
|
|
|
case INSTRUCTION_BIT_OR: data_push (0X09); break; |
|
|
|
case INSTRUCTION_ADD_CARRY: data_push (0X11); break; |
|
|
|
case INSTRUCTION_SUBTRACT_CARRY: data_push (0X19); break; |
|
|
|
case INSTRUCTION_BIT_AND: data_push (0X21); break; |
|
|
|
case INSTRUCTION_SUBTRACT: data_push (0X29); break; |
|
|
|
case INSTRUCTION_BIT_EXCLUSIVE_OR: data_push (0X31); break; |
|
|
|
case INSTRUCTION_COMPARE: data_push (0X39); break; |
|
|
|
case INSTRUCTION_MOVE: data_push (0X89); break; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
static void suffix_register_combination (int left, int right) { |
|
|
|
data_push (((0X0C + ((right % 8) / 2)) << 4) | ((right % 2) * 8 + (left % 8))); |
|
|
|
} |
|
|
|
|
|
|
|
static void encode_regular_register_register (int instruction, int left, int right) { |
|
|
|
prefix_register_size (left, right); |
|
|
|
infix_regular_instruction (instruction); |
|
|
|
suffix_register_combination (left, right); |
|
|
|
} |
|
|
|
|
|
|
|
int main (void) { |
|
|
|
/* Won't be hardcoded, will use multiple files like 'gnatmake'... */ |
|
|
|
char * source [48] = { |
|
|
|
"add", "rax", "r15", |
|
|
|
"or", "rcx", "r15", |
|
|
|
"adc", "rdx", "r15", |
|
|
|
"sbb", "rbx", "r15", |
|
|
|
"and", "rsp", "r15", |
|
|
|
"sub", "rbp", "r15", |
|
|
|
"xor", "rsi", "r15", |
|
|
|
"cmp", "rdi", "r15", |
|
|
|
"mov", "r8", "r15", |
|
|
|
"mov", "r9", "r15", |
|
|
|
"mov", "r10", "r15", |
|
|
|
"mov", "r11", "r15", |
|
|
|
"mov", "r12", "r15", |
|
|
|
"mov", "r13", "r15", |
|
|
|
"mov", "r14", "r15", |
|
|
|
"mov", "r15", "r15" |
|
|
|
}; |
|
|
|
|
|
|
|
int buffer [48]; |
|
|
|
|
|
|
|
int i, j; |
|
|
|
|
|
|
|
for (i = 0; i != FORMAT_COUNT; ++i) { |
|
|
|
for (j = 0; j != INSTRUCTION_COUNT; ++j) { |
|
|
|
encode [i] [j] = unimplemented; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
encode [FORMAT_REGISTER_REGISTER] [INSTRUCTION_ADD] = encode_regular_register_register; |
|
|
|
encode [FORMAT_REGISTER_REGISTER] [INSTRUCTION_BIT_OR] = encode_regular_register_register; |
|
|
|
encode [FORMAT_REGISTER_REGISTER] [INSTRUCTION_ADD_CARRY] = encode_regular_register_register; |
|
|
|
encode [FORMAT_REGISTER_REGISTER] [INSTRUCTION_SUBTRACT_CARRY] = encode_regular_register_register; |
|
|
|
encode [FORMAT_REGISTER_REGISTER] [INSTRUCTION_BIT_AND] = encode_regular_register_register; |
|
|
|
encode [FORMAT_REGISTER_REGISTER] [INSTRUCTION_SUBTRACT] = encode_regular_register_register; |
|
|
|
encode [FORMAT_REGISTER_REGISTER] [INSTRUCTION_BIT_EXCLUSIVE_OR] = encode_regular_register_register; |
|
|
|
encode [FORMAT_REGISTER_REGISTER] [INSTRUCTION_COMPARE] = encode_regular_register_register; |
|
|
|
encode [FORMAT_REGISTER_REGISTER] [INSTRUCTION_MOVE] = encode_regular_register_register; |
|
|
|
|
|
|
|
for (i = 0; i != 48; ++i) { |
|
|
|
/* These depend on format, will not assume IRR... */ |
|
|
|
if ((buffer [i] = instruction_word (source [i])) == -1) { |
|
|
|
echo ("Word must be an instruction!\n"); |
|
|
|
echo ("This '"); |
|
|
|
echo (source [i]); |
|
|
|
echo ("' is not an instruction...\n"); |
|
|
|
exit (EXIT_FAILURE); |
|
|
|
} ++i; |
|
|
|
if ((buffer [i] = register_word (source [i])) == -1) { |
|
|
|
echo ("Word must be a register!\n"); |
|
|
|
echo ("This '"); |
|
|
|
echo (source [i]); |
|
|
|
echo ("' is not a register...\n"); |
|
|
|
exit (EXIT_FAILURE); |
|
|
|
} ++i; |
|
|
|
if ((buffer [i] = register_word (source [i])) == -1) { |
|
|
|
echo ("Word must be a register!\n"); |
|
|
|
echo ("This '"); |
|
|
|
echo (source [i]); |
|
|
|
echo ("' is not a register...\n"); |
|
|
|
exit (EXIT_FAILURE); |
|
|
|
} |
|
|
|
printf ("\033[1;33m%s\033[0m \033[1;34m%s\033[0m \033[1;35m%s\033[0m", source [i - 2], source [i - 1], source [i]); |
|
|
|
encode [FORMAT_REGISTER_REGISTER] [buffer [i - 2]] (buffer [i - 2], buffer [i - 1], buffer [i]); |
|
|
|
data_echo (); |
|
|
|
data_free (); |
|
|
|
printf ("\n"); |
|
|
|
} |
|
|
|
|
|
|
|
return (EXIT_SUCCESS); |
|
|
|
} |