/// _ _ /// __ ____ _ ___| |__ (_)_ __ ___ /// \ \/ / _` |/ __| '_ \| | '_ \ / _ \ /// > < (_| | (__| | | | | | | | __/ /// /_/\_\__,_|\___|_| |_|_|_| |_|\___| /// /// 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 char * operand_name [operand_count] = { "rel", "reg", "mem", "imm" }; static char * 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 uint main_entry_point = 0; static uint text_sector_size = 0; static uchar * text_sector_byte = null; static uint data_sector_size = 0; // This is unused, and it should be used... static uchar * data_sector_byte = null; // This is unused, and it should be used... static uint empty_count = 1; static uint empty_holes = 1; static uint * empty_array = null; static uint * empty_imbue = null; static uint * empty_store = null; static uchar 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 uchar 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 uchar 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 bool register_register (uint to, uint from) { return ((to == operand_register) && (from == operand_register)); } static bool register_memory (uint to, uint from) { return ((to == operand_register) && (from == operand_memory)); } static bool register_immediate (uint to, uint from) { return ((to == operand_register) && (from == operand_immediate)); } static bool memory_register (uint to, uint from) { return ((to == operand_memory) && (from == operand_register)); } static bool memory_immediate (uint to, uint from) { return ((to == operand_memory) && (from == operand_immediate)); } static bool register_relative (uint to, uint from) { return ((to == operand_register) && (from == operand_relative)); } static uint absolute (void) { return (0x4010b0 - text_sector_size - 4); } static uint relative (void) { return (0x1000 - text_sector_size - 4); } static void replace (uchar * destination, uchar * source, ulong size) { for (--size; size >= 0; --size) { destination [size] = source [size]; } } static void inset (bool when, uchar data) { text_sector_byte [text_sector_size] = data; text_sector_size += (uint) when; } static void inset_immediate (bool when, uint data) { inset (when, (data >> 0) & 0xff); inset (when, (data >> 8) & 0xff); inset (when, (data >> 16) & 0xff); inset (when, (data >> 24) & 0xff); } static void inset_memory (bool when, uint data, uint base) { empty_array [empty_holes] = text_sector_size; empty_imbue [empty_holes] = data; empty_holes += when; inset_immediate (when, base); } static void inset_relative (bool when, uint data, uint base) { empty_array [empty_holes] = 0; empty_imbue [empty_holes] = data; empty_holes += when; inset_immediate (when, base); } static uint mc0 (uint code, uint base) { return (0xc0 + 0x01 * (code % 8) + 0x08 * (base % 8)); } static uint m05 (uint code) { return (0x05 + 0x08 * code); } static uint store_relative (uint * array) { uint 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 uint store_memory (uint * array) { uint memory = array [1]; #ifdef use_debug_printing print ("/3asmmem/- %i", memory); #endif empty_store [memory] = text_sector_size; ++empty_count; return 1; } static uint store_number (uint * array) { uint amount = array [1]; #ifdef use_debug_printing print ("/3asmnum/- %i", amount); #endif for (uint index = 0; index < amount; ++index) { inset_immediate (true, array [2 + index]); } return amount + 1; } static uint store_string (uint * array) { uint amount = array [1]; #ifdef use_debug_printing print ("/3asmstr/- %i", amount); #endif for (uint index = 0; index < amount; ++index) { inset (true, array [2 + index]); } return amount + 1; } static uint build_double (uint * array) { uint operation = array [0]; uint to = array [1]; uint destination = array [2]; uint from = array [3]; uint 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 uint build_single (uint * array) { uint operation = array [0]; uint to = array [1]; uint 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 uint build_shift (uint * array) { uint operation = array [0]; uint to = array [1]; uint destination = array [2]; uint 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, 0xc1); 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 uint build_static_1 (uint * array) { uint 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 uint build_jump_if (uint * array) { uint operation = array [0]; uint 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 uint build_jump (uint * array) { uint to = array [1]; uint 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 uint build_move (uint * array) { uint to = array [1]; uint destination = array [2]; uint from = array [3]; uint 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 uint build_call (uint * array) { uint from = array [1]; uint 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 uint (* build_instruction [operation_count]) (uint * 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 void assemble (uint count, uint * array, uint external_memory, uint 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 (uint index = 0; index < count; ++index) { uint size = text_sector_size; uchar 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 ((uchar) text_sector_byte [byte], false, 16, 2, '0')); } print ("\n"); #endif } main_entry_point = empty_store [0]; for (uint index = 1; index < empty_holes; ++index) { uint set = 0; uint get = empty_array [index]; replace ((uchar *) & set, & text_sector_byte [get], sizeof (set)); set += empty_store [empty_imbue [index]]; replace (& text_sector_byte [get], (uchar *) & set, sizeof (get)); } } static void elf_main_header (uint entry_point, bool has_program, bool for_linux, bool for_x86_64) { uint enter = entry_point + 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 void elf_text_sector (uint text_size, uint data_size) { uint 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 void elf_data_sector (uint text_size, uint data_size) { uint data = data_size; uint core = elf_header_size + text_size - data_size; uint 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)); }