xolatilization/xachine.h

457 lines
17 KiB
C
Executable File

/// _ _
/// __ ____ _ ___| |__ (_)_ __ ___
/// \ \/ / _` |/ __| '_ \| | '_ \ / _ \
/// > < (_| | (__| | | | | | | | __/
/// /_/\_\__,_|\___|_| |_|_|_| |_|\___|
///
/// Copyright (c) 1997 - Ognjen 'xolatile' Milan Robovic
///
/// xolatile@chud.cyou - xachine - Minimalistic statical x86_64, 32-bit, ELF64, GEENOO/Leenoocks bytecode assembler following IA32e.
///
/// This program is free software, free as in freedom and as in free beer, you can redistribute it and/or modify it under the terms of the GNU
/// General Public License as published by the Free Software Foundation, either version 3 of the License, or any later version if you wish...
///
/// This program is distributed in the hope that it will be useful, but it is probably not, and without any warranty, without even the implied
/// warranty of merchantability or fitness for a particular purpose, because it is pointless. Please see the GNU (Geenoo) General Public License
/// for more details, if you dare, it is a lot of text that nobody wants to read...
#define elf_main_header_size (0x40)
#define elf_text_sector_size (0x38)
#define elf_data_sector_size (0x38)
#define elf_header_size (elf_main_header_size + elf_text_sector_size + elf_data_sector_size)
typedef enum {
operand_relative, operand_register, operand_memory, operand_immediate,
operand_count
} operand_enumeration;
typedef enum {
operation_memory, operation_relative, operation_number, operation_string,
operation_add, operation_or, operation_add_carry, operation_subtract_carry,
operation_and, operation_subtract, operation_exclusive_or, operation_compare,
operation_increment, operation_decrement, operation_not, operation_negate,
operation_unsigned_multiply, operation_signed_multiply, operation_unsigned_divide, operation_signed_divide,
operation_rotate_left, operation_rotate_right, operation_rotate_left_carry, operation_rotate_right_carry,
operation_shift_left_sign, operation_shift_right, operation_shift_left, operation_shift_right_sign,
operation_jump_overflow, operation_jump_not_overflow, operation_jump_below, operation_jump_above_equal,
operation_jump_equal, operation_jump_not_equal, operation_jump_below_equal, operation_jump_above,
operation_jump_sign, operation_jump_not_sign, operation_jump_parity_even, operation_jump_parity_odd,
operation_jump_lesser, operation_jump_greater_equal, operation_jump_lesser_equal, operation_jump_greater,
operation_none, operation_return_near, operation_system_call, operation_call,
operation_jump, operation_move,
operation_count
} operation_enumeration;
#ifdef use_debug_printing
static character * operand_name [operand_count] = {
"rel", "reg", "mem", "imm"
};
static character * operation_name [operation_count] = {
"asmmem", "asmrel", "asmnum", "asmstr",
"add", "or", "adc", "sbb", "and", "sub", "xor", "cmp",
"inc", "dec", "not", "neg", "mul", "imul", "div", "idiv",
"rol", "ror", "rcl", "rcr", "sal", "shr", "shl", "sar",
"jo", "jno", "jb", "jae", "je", "jne", "jbe", "ja",
"js", "jns", "jpe", "jpo", "jl", "jge", "jle", "jg",
"nop", "ret", "syscall", "call", "jmp", "mov"
};
#endif
static natural main_entry_pointeger = 0;
static natural text_sector_size = 0;
static natural_8 * text_sector_byte = null;
static natural data_sector_size = 0; // This is unused, and it should be used...
static natural_8 * data_sector_byte = null; // This is unused, and it should be used...
static natural empty_count = 1;
static natural empty_holes = 1;
static natural * empty_array = null;
static natural * empty_imbue = null;
static natural * empty_store = null;
static natural_8 elf_main_header_byte [elf_main_header_size] = { // These should be done properly...
0x7f, 0x45, 0x4c, 0x46, 0x02, 0x01, 0x01, 0x03,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x02, 0x00, 0x3e, 0x00, 0x01, 0x00, 0x00, 0x00,
0xb0, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x38, 0x00,
0x02, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00
};
static natural_8 elf_text_sector_byte [elf_text_sector_size] = {
0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
static natural_8 elf_data_sector_byte [elf_data_sector_size] = {
0x01, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x10, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x10, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
static boolean register_register (natural to, natural from) { return ((to == operand_register) && (from == operand_register)); }
static boolean register_memory (natural to, natural from) { return ((to == operand_register) && (from == operand_memory)); }
static boolean register_immediate (natural to, natural from) { return ((to == operand_register) && (from == operand_immediate)); }
static boolean memory_register (natural to, natural from) { return ((to == operand_memory) && (from == operand_register)); }
static boolean memory_immediate (natural to, natural from) { return ((to == operand_memory) && (from == operand_immediate)); }
static boolean register_relative (natural to, natural from) { return ((to == operand_register) && (from == operand_relative)); }
static natural absolute (none) { return (0x4010b0 - text_sector_size - 4); }
static natural relative (none) { return (0x1000 - text_sector_size - 4); }
static procedure replace (natural_8 * destination, natural_8 * source, caliber size) {
for (--size; size >= 0; --size) {
destination [size] = source [size];
}
}
static procedure inset (boolean when, natural_8 data) {
text_sector_byte [text_sector_size] = data;
text_sector_size += (natural) when;
}
static procedure inset_immediate (boolean when, natural data) {
inset (when, (data >> 0) & 0xff);
inset (when, (data >> 8) & 0xff);
inset (when, (data >> 16) & 0xff);
inset (when, (data >> 24) & 0xff);
}
static procedure inset_memory (boolean when, natural data, natural base) {
empty_array [empty_holes] = text_sector_size;
empty_imbue [empty_holes] = data;
empty_holes += when;
inset_immediate (when, base);
}
static procedure inset_relative (boolean when, natural data, natural base) {
empty_array [empty_holes] = 0;
empty_imbue [empty_holes] = data;
empty_holes += when;
inset_immediate (when, base);
}
static natural mc0 (natural code, natural base) {
return (0xc0 + 0x01 * (code % 8) + 0x08 * (base % 8));
}
static natural m05 (natural code) {
return (0x05 + 0x08 * code);
}
static natural store_relative (natural * array) {
natural relative = array [1];
#ifdef use_debug_printing
print ("/3asmrel/- %i", relative);
#endif
empty_array [empty_holes] = text_sector_size;
empty_imbue [empty_holes] = relative;
++empty_holes;
return 1;
}
static natural store_memory (natural * array) {
natural memory = array [1];
#ifdef use_debug_printing
print ("/3asmmem/- %i", memory);
#endif
empty_store [memory] = text_sector_size;
++empty_count;
return 1;
}
static natural store_number (natural * array) {
natural amount = array [1];
#ifdef use_debug_printing
print ("/3asmnum/- %i", amount);
#endif
for (natural index = 0; index < amount; ++index) {
inset_immediate (true, array [2 + index]);
}
return amount + 1;
}
static natural store_string (natural * array) {
natural amount = array [1];
#ifdef use_debug_printing
print ("/3asmstr/- %i", amount);
#endif
for (natural index = 0; index < amount; ++index) {
inset (true, array [2 + index]);
}
return amount + 1;
}
static natural build_real_64 (natural * array) {
natural operation = array [0];
natural to = array [1];
natural destination = array [2];
natural from = array [3];
natural source = array [4];
#ifdef use_debug_printing
print ("/3%s/- /6%s/- %i /6%s/- %i", operation_name [operation], operand_name [to], destination, operand_name [from], source);
#endif
inset (register_immediate (to, from), 0x81);
// Seriously, what the fuck...?
inset (true, 0x01 + 0x08 * (operation - operation_add) +
destination * (register_immediate (to, from)) +
0x01 * register_immediate (to, from) +
0x02 * register_memory (to, from) +
0x04 * memory_immediate (to, from) +
0xc0 * register_immediate (to, from));
inset (register_register (to, from), mc0 (destination, source));
inset (register_memory (to, from), m05 (destination));
inset (memory_register (to, from), m05 (source));
inset_memory (register_memory (to, from), source, relative ());
inset_immediate (register_immediate (to, from), source);
inset_memory (memory_register (to, from), destination, relative ());
inset_memory (memory_immediate (to, from), destination, relative ());
inset_immediate (memory_immediate (to, from), source);
inset_memory (register_relative (to, from), source, absolute ());
return 4;
}
static natural build_single (natural * array) {
natural operation = array [0];
natural to = array [1];
natural destination = array [2];
#ifdef use_debug_printing
print ("/3%s/- /6%s/- %i", operation_name [operation], operand_name [to], destination);
#endif
inset (true, 0xf7 + 0x08 * ((operation == operation_increment) || (operation == operation_decrement)));
inset (to == operand_register, 0xc0 + 0x08 * (operation - operation_increment) + 0x01 * destination);
inset (to == operand_memory, 0x05 + 0x08 * (operation - operation_increment));
inset_memory (to == operand_memory, destination, relative ());
return 2;
}
static natural build_shift (natural * array) {
natural operation = array [0];
natural to = array [1];
natural destination = array [2];
natural offset = array [3];
#ifdef use_debug_printing
print ("/3%s/- /6%s/- %i /cimm/- %i", operation_name [operation], operand_name [to], destination, offset);
#endif
inset (true, 0xcharacter);
inset (to == operand_register, 0x05 + 0x08 * (operation - operation_rotate_left));
inset (to == operand_memory, 0xc0 + 0x08 * (operation - operation_rotate_left));
inset_memory (to == operand_memory, destination, relative ());
inset (true, offset);
return 3;
}
static natural build_static_1 (natural * array) {
natural operation = array [0];
#ifdef use_debug_printing
print ("/3%s/-", operation_name [operation]);
#endif
switch (operation) {
case operation_none: inset (true, 0x90); break;
case operation_return_near: inset (true, 0xc3); break;
case operation_system_call: inset (true, 0x0f); inset (true, 0x05); break;
default: break;
}
return 0;
}
static natural build_jump_if (natural * array) {
natural operation = array [0];
natural location = array [1];
#ifdef use_debug_printing
print ("/3%s/- %i", operation_name [operation], location);
#endif
inset (true, 0x0f);
inset (true, 0x80 + operation - operation_jump_overflow);
inset_memory (true, location, -text_sector_size - 4);
return 2;
}
static natural build_jump (natural * array) {
natural to = array [1];
natural destination = array [2];
#ifdef use_debug_printing
print ("/3jmp/- /6%s/- %i", operand_name [to], destination);
#endif
inset (to == operand_register, 0xff);
inset (to == operand_register, 0xe0 + 0x01 * destination);
inset (to == operand_relative, 0xe9);
inset_memory (to == operand_relative, destination, -text_sector_size - 4);
return 2;
}
static natural build_move (natural * array) {
natural to = array [1];
natural destination = array [2];
natural from = array [3];
natural source = array [4];
#ifdef use_debug_printing
print ("/3mov/- /6%s/- %i /6%s/- %i", operand_name [to], destination, operand_name [from], source);
#endif
inset (register_register (to, from), 0x89);
inset (memory_register (to, from), 0x8b);
inset (register_memory (to, from), 0x89);
inset (memory_register (to, from), m05 (destination));
inset (register_memory (to, from), m05 (source));
inset (register_register (to, from), mc0 (destination, source));
inset ((to == operand_register) && ((from == operand_immediate) || (from == operand_relative)), 0xb8 + 0x01 * destination);
inset (memory_immediate (to, from), 0xc7);
inset_memory (register_memory (to, from), source, relative ());
inset_memory (memory_register (to, from), destination, relative ());
inset_memory (memory_immediate (to, from), destination, relative ());
inset_memory (register_relative (to, from), source, 0x4010b0);
inset_immediate (register_immediate (to, from), source);
inset_immediate (memory_immediate (to, from), source);
return 4;
}
static natural build_call (natural * array) {
natural from = array [1];
natural source = array [2];
#ifdef use_debug_printing
print ("/3call/- /6%s/- %i", operand_name [from], source);
#endif
inset (from == operand_relative, 0xe8);
inset (from == operand_register, 0xff);
inset (from == operand_register, 0xd0 + 0x01 * source);
inset_memory (from == operand_relative, source, -text_sector_size - 4);
return 2;
}
static natural (* build_instruction [operation_count]) (natural * array) = {
store_memory, // operation_memory : LABEL
store_relative, // operation_relative : "IMPLEMENTED"
store_number,
store_string,
build_double, build_double, build_double, build_double, build_double, build_double, build_double, build_double,
build_single, build_single, build_single, build_single, build_single, build_single, build_single, build_single,
build_shift, build_shift, build_shift, build_shift, build_shift, build_shift, build_shift, build_shift,
build_jump_if, build_jump_if, build_jump_if, build_jump_if, build_jump_if, build_jump_if, build_jump_if, build_jump_if,
build_jump_if, build_jump_if, build_jump_if, build_jump_if, build_jump_if, build_jump_if, build_jump_if, build_jump_if,
build_static_1, build_static_1, build_static_1, build_call, build_jump, build_move
};
static procedure assemble (natural count, natural * array, natural external_memory, natural internal_memory) {
text_sector_byte = arena_add (external_memory * sizeof (* text_sector_byte));
data_sector_byte = arena_add (external_memory * sizeof (* text_sector_byte));
empty_array = arena_add (internal_memory * sizeof (* empty_array));
empty_imbue = arena_add (internal_memory * sizeof (* empty_imbue));
empty_store = arena_add (internal_memory * sizeof (* empty_store));
for (natural index = 0; index < count; ++index) {
natural size = text_sector_size;
natural_8 byte = 0;
#ifdef use_debug_nopping
inset (array [index] > operation_string, 0x90);
#endif
index += build_instruction [array [index]] (& array [index]);
#ifdef use_debug_printing
print (" /0--/- ");
for (byte = size; byte < text_sector_size; ++byte) {
print ("/5%s/- ", format_to_string ((natural_8) text_sector_byte [byte], false, 16, 2, '0'));
}
print ("\n");
#endif
}
main_entry_pointeger = empty_store [0];
for (natural index = 1; index < empty_holes; ++index) {
natural set = 0;
natural get = empty_array [index];
replace ((natural_8 *) & set, & text_sector_byte [get], sizeof (set));
set += empty_store [empty_imbue [index]];
replace (& text_sector_byte [get], (natural_8 *) & set, sizeof (get));
}
}
static procedure elf_main_header (natural entry_point, boolean has_program, boolean for_linux, boolean for_x86_64) {
natural enter = entry_pointeger + 0x4000b0;
elf_main_header_byte [16] = (has_program) ? 0x02 : 0x03;
elf_main_header_byte [ 7] = (for_linux) ? 0x03 : 0x00;
elf_main_header_byte [18] = (for_x86_64) ? 0x3e : 0x00;
memory_copy (& elf_main_header_byte [24], & enter, sizeof (enter));
}
static procedure elf_text_sector (natural text_size, natural data_size) {
natural text = elf_header_size + text_size - data_size;
memory_copy (& elf_text_sector_byte [32], & text, sizeof (text));
memory_copy (& elf_text_sector_byte [40], & text, sizeof (text));
}
static procedure elf_data_sector (natural text_size, natural data_size) {
natural data = data_size;
natural core = elf_header_size + text_size - data_size;
natural move = 0x401000 + core;
memory_copy (& elf_data_sector_byte [ 8], & core, sizeof (core));
memory_copy (& elf_data_sector_byte [16], & move, sizeof (move));
memory_copy (& elf_data_sector_byte [24], & move, sizeof (move));
memory_copy (& elf_data_sector_byte [32], & data, sizeof (data));
memory_copy (& elf_data_sector_byte [40], & data, sizeof (data));
}