231 lines
10 KiB
C
231 lines
10 KiB
C
/*
|
|
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);
|
|
}
|
|
echo ("\033[1;33m");
|
|
echo (source [i - 2]);
|
|
echo ("\033[0m \033[1;34m");
|
|
echo (source [i - 1]);
|
|
echo ("\033[0m \033[1;35m");
|
|
echo (source [i]);
|
|
echo ("\033[0m --- ");
|
|
encode [FORMAT_REGISTER_REGISTER] [buffer [i - 2]] (buffer [i - 2], buffer [i - 1], buffer [i]);
|
|
data_echo ();
|
|
data_free ();
|
|
echo ("\n");
|
|
}
|
|
|
|
return (EXIT_SUCCESS);
|
|
}
|