/// _ /// __ _(_) __ _ ___ _ __ ___ __ _ /// \ \/ / |/ _` / __| '_ ` _ \ / _` | /// > <| | (_| \__ \ | | | | | (_| | /// /_/\_\_|\__,_|___/_| |_| |_|\__,_| /// /// Copyright (c) 1997 - Ognjen 'xolatile' Milan Robovic /// /// xolatile@chud.cyou - xiasma - Less minimalistic statical x86_64, 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 double_begin (add) #define single_begin (increment) #define static_1_begin (none) #define static_2_begin (system_call) #define jump_if_begin (jump_overflow) #define move_if_begin (move_overflow) #define set_if_begin (set_overflow) #define float_begin (float_add) #define shift_begin (rotate_left) #define jump_not_even (jump_odd) #define jump_not_odd (jump_even) #define jump_not_below (jump_above_equal) #define jump_not_below_equal (jump_above) #define jump_not_above (jump_below_equal) #define jump_not_above_equal (jump_below) #define jump_not_lesser (jump_greater_equal) #define jump_not_lesser_equal (jump_greater) #define jump_not_greater (jump_lesser_equal) #define jump_not_greater_equal (jump_lesser) #define move_not_even (move_odd) #define move_not_odd (move_even) #define move_not_below (move_above_equal) #define move_not_below_equal (move_above) #define move_not_above (move_below_equal) #define move_not_above_equal (move_below) #define move_not_lesser (move_greater_equal) #define move_not_lesser_equal (move_greater) #define move_not_greater (move_lesser_equal) #define move_not_greater_equal (move_lesser) #define set_not_even (set_odd) #define set_not_odd (set_even) #define set_not_below (set_above_equal) #define set_not_below_equal (set_above) #define set_not_above (set_below_equal) #define set_not_above_equal (set_below) #define set_not_lesser (set_greater_equal) #define set_not_lesser_equal (set_greater) #define set_not_greater (set_lesser_equal) #define set_not_greater_equal (set_lesser) #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) enum { size_8, size_16, size_32, size_64 }; enum { for_relative, for_register, for_memory, for_immediate }; enum { new_memory, new_relative, new_immediate, add, or, carry_add, carry_subtract, and, subtract, xor, compare, increment, decrement, not, negate, multiply, sign_multiply, divide, sign_divide, float_add, float_multiply, float_compare, float_compare_pop, float_subtract, float_unsubtract, float_divide, float_undivide, carry_rotate_left, carry_rotate_right, rotate_left, rotate_right, shift_left, shift_right, sign_shift_left, sign_shift_right, none, near_return, far_return, leave, pop_flags, push_flags, system_call, cpu_identification, float_none, float_change_sign, float_absolute, float_test, float_examine, float_push_1, float_push_log2_10, float_push_log2_e, float_push_pi, float_push_log10_2, float_push_ln_2, float_push_0, float_2xm1, float_yl2x, float_tangent, float_arctangent, float_extract, float_modulus_push_1, float_decrement, float_increment, float_modulus, float_yl2xp1, float_square_root, float_sine_cosine, float_random, float_scale, float_sine, float_cosine, enter, call, in, out, jump, move, pop, push, jump_overflow, jump_not_overflow, jump_below, jump_above_equal, jump_equal, jump_not_equal, jump_below_equal, jump_above, jump_sign, jump_not_sign, jump_even, jump_odd, jump_lesser, jump_greater_equal, jump_lesser_equal, jump_greater, move_overflow, move_not_overflow, move_below, move_above_equal, move_equal, move_not_equal, move_below_equal, move_above, move_sign, move_not_sign, move_even, move_odd, move_lesser, move_greater_equal, move_lesser_equal, move_greater, set_overflow, set_not_overflow, set_below, set_above_equal, set_equal, set_not_equal, set_below_equal, set_above, set_sign, set_not_sign, set_even, set_odd, set_lesser, set_greater_equal, set_lesser_equal, set_greater, byte_swap, test, exchange, load_address, bit_scan_forward, bit_scan_reverse, repeat, repeat_equal, repeat_not_equal, repeat_zero, repeat_not_zero, loop, loop_equal, loop_not_equal }; enum { register_0, register_1, register_2, register_3, register_4, register_5, register_6, register_7, register_8, register_9, register_10, register_11, register_12, register_13, register_14, register_15 }; static int empty_count = 0; static int empty_holes = 1; static int * empty_array = null; static int * empty_imbue = null; static int * empty_store = null; static int text_sector_size = 0; static int data_sector_size = 0; static unsigned char * text_sector_byte = null; static unsigned char * data_sector_byte = null; static unsigned char elf_main_header_byte [elf_main_header_size] = { 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 unsigned char 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 unsigned char 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 int front (int data) { return ((data >= register_4) && (data <= register_7)); } static int lower (int data) { return ((data >= register_0) && (data <= register_7)); } static int upper (int data) { return ((data >= register_8) && (data <= register_15)); } static int far (int label) { return (label && 1); } static int near (int label) { return (label && 0); } static void inset (int when, int data) { text_sector_byte [text_sector_size] = (unsigned char) data; text_sector_size += (unsigned int) when; } static void inset_immediate (int when, int size, int data) { inset ((when), (data >> 0) & 0xff); inset ((when) && (size >= size_16), (data >> 8) & 0xff); inset ((when) && (size >= size_32), (data >> 16) & 0xff); inset ((when) && (size >= size_32), (data >> 24) & 0xff); } static void inset_memory (int when, int size, int data, int base) { empty_array [empty_holes] = text_sector_size; empty_imbue [empty_holes] = data; empty_holes += (int) when; inset_immediate (when, size, base); } static int store_relative (int * array) { int relative = array [1]; empty_array [empty_holes] = text_sector_size; empty_imbue [empty_holes] = relative; ++empty_holes; return (1); } static int store_memory (int * array) { int operation = array [0], memory = array [1]; empty_store [memory] = text_sector_size; ++empty_count; return (1); } static int store_immediate (int * array) { int index = 0, operation = array [0], size = array [1], amount = array [2]; for (index = 0; index < amount; ++index) { inset_immediate (true, size, array [3 + index]); } return (amount + 2); } static void short_prefix (int size) { inset (size == size_16, 0x66); } static void long_prefix (int size, int to, int destination, int from, int source) { int to_upper = (to == for_register) && (upper (destination)), from_upper = (from == for_register) && (upper (source)), extension = (size == size_64); inset (extension || to_upper || from_upper, 0x40 + 0x01 * to_upper + 0x04 * from_upper + 0x08 * extension); } static void modify_registers (int to, int destination, int from, int source) { int to_register_from_register = ((to == for_register) && (from == for_register)); inset (to_register_from_register, 0xc0 + 0x01 * (destination & 0x07) + 0x08 * (source & 0x07)); } static void modify_memory (int operation, int to, int from) { int to_register_from_memory = ((to == for_register) && (from == for_memory)), to_memory_from_register = ((to == for_memory) && (from == for_register)), to_memory_from_immediate = ((to == for_memory) && (from == for_immediate)); inset (to_register_from_memory || to_memory_from_register, 0x05 + 0x08 * operation * to_memory_from_immediate); } static int build_double (int * array) { int operation = array [0], size = array [1], to = array [2], destination = array [3], from = array [4], source = array [5]; int to_register_from_register = ((to == for_register) && (from == for_register)), to_register_from_memory = ((to == for_register) && (from == for_memory)), to_register_from_immediate = ((to == for_register) && (from == for_immediate)), to_register_from_relative = ((to == for_register) && (from == for_relative)), to_memory_from_register = ((to == for_memory) && (from == for_register)), to_memory_from_immediate = ((to == for_memory) && (from == for_immediate)); short_prefix (size); long_prefix (size, to, destination, from, source); inset (to_register_from_immediate, 0x80 + 0x01 * (size != size_8)); inset (to_register_from_immediate, 0xc0 + 0x08 * (operation - double_begin) + 0x01 * (destination & 0x07)); modify_registers (to, destination, from, source); modify_memory (destination, to, from); modify_memory (source, to, from); inset_memory (to_register_from_memory, size_32, source, 0x1000 - text_sector_size - 4); inset_memory (to_memory_from_register, size_32, destination, 0x1000 - text_sector_size - 4); inset_memory (to_memory_from_immediate, size_32, destination, 0x1000 - text_sector_size - 4); inset_memory (to_register_from_relative, size_32, source, 0x4010b0 - text_sector_size - 4); inset_immediate (to_register_from_immediate, size, source); inset_immediate (to_memory_from_immediate, size, source); return (5); } static int build_single (int * array) { int operation = array [0], size = array [1], to = array [2], destination = array [3]; int irregularity = ((operation == increment) || (operation == decrement)); short_prefix (size); long_prefix (size, to, destination, 0, 0); inset ((size == size_8) && (to == for_register) && front (destination), 0x40); inset (true, 0xf7 + 0x08 * irregularity - 0x01 * (size == size_8)); inset (to == for_register, 0xc0 + 0x08 * (operation - single_begin) + 0x01 * (destination & 0x07)); inset (to == for_memory, 0x05 + 0x08 * (operation - single_begin)); inset_memory (to == for_memory, size_32, destination, 0x1000 - (text_sector_size + 4)); return (3); } static int build_static_1 (int * array) { int operation = array [0]; unsigned char data [] = { 0x90, 0xc3, 0xcb, 0xc9, 0x9d, 0x9c }; inset (true, data [operation - static_1_begin]); return (0); } static int build_static_2 (int * array) { int operation = array [0]; unsigned short data [] = { 0x050f, 0xa20f, 0xd0d9, 0xe0d9, 0xe1d9, 0xe4d9, 0xe5d9, 0xe8d9, 0xe9d9, 0xead9, 0xebd9, 0xecd9, 0xedd9, 0xeed9, 0xf0d9, 0xf1d9, 0xf2d9, 0xf3d9, 0xf4d9, 0xf5d9, 0xf6d9, 0xf7d9, 0xf8d9, 0xf9d9, 0xfad9, 0xfbd9, 0xfcd9, 0xfdd9, 0xfed9, 0xffd9 }; inset_immediate (true, size_16, data [operation - static_2_begin]); return (0); } static int build_jump_if (int * array) { int operation = array [0], size = array [1], location = array [3]; inset (far (location) && (size == size_32), 0x0f); inset (far (location), 0x80 + operation - jump_if_begin); inset (near (location), 0x70 + operation - jump_if_begin); inset_memory (true, size_32, location, -(text_sector_size + 4)); return (3); } static int build_move_if (int * array) { int operation = array [0], size = array [1], to = array [2], destination = array [3], from = array [4], source = array [5]; short_prefix (size); long_prefix (size, to, destination, from, source); inset (true, 0x0f); inset (true, 0x40 + operation - move_if_begin); modify_registers (to, destination, from, source); modify_memory (destination, to, from); return (5); } static int build_set_if (int * array) { int operation = array [0], to = array [2], destination = array [3]; inset ((to == for_register) && (front (destination)), 0x40); inset ((to == for_register) && (upper (destination)), 0x41); inset (true, 0x0f); inset (true, 0x90 + operation - set_if_begin); inset (to == for_register, 0xc0 + 0x01 * (destination & 0x07)); inset (to == for_memory, 0x05); inset_memory (to == for_memory, size_32, destination, 0x1000 - (text_sector_size + 4)); return (3); } static int build_jump (int * array) { int operation = array [0], size = array [1], to = array [2], destination = array [3]; inset ((to == for_register) && upper (destination), 0X41); inset (to == for_relative, 0xe9 + 0x02 * (size == size_8)); inset (to == for_register, 0xff); inset (to == for_register, 0xe0 + 0x01 * (destination & 0x07)); inset (to == for_memory, 0xff); inset (to == for_memory, 0x25); inset_memory (to == for_relative, size_32, destination, -(text_sector_size + 4)); inset_memory (to == for_memory, size_32, destination, 0x4010b0); return (3); } static int build_move (int * array) { int operation = array [0], size = array [1], to = array [2], destination = array [3], from = array [4], source = array [5], extension = array [6]; short_prefix (size); long_prefix (size, to, destination, from, source); inset ((to == for_register) && (from == for_register), 0x88 + 0x01 * (size != size_8)); inset ((to == for_register) && (from == for_memory), 0x8a + 0x01 * (size != size_8)); inset ((to == for_memory) && (from == for_register), 0x88 + 0x01 * (size != size_8)); modify_memory (destination, to, from); modify_memory (source, to, from); modify_registers (to, destination, from, source); inset ((to == for_register) && ((from == for_immediate) || (from == for_relative)), 0xb0 + 0x08 * (size != size_8) + 0x01 * (destination & 0x07)); inset ((to == for_memory) && (from == for_immediate), 0xc6 + 0x01 * (size != size_8)); inset ((to == for_memory) && (from == for_immediate), 0x05); inset_memory ((to == for_register) && (from == for_memory), size_32, source, 0x1000 - text_sector_size - 4); inset_memory ((to == for_memory) && (from == for_register), size_32, destination, 0x1000 - text_sector_size - 4); inset_memory ((to == for_memory) && (from == for_immediate), size_32, destination, 0x1000 - text_sector_size - 4); inset_memory ((to == for_register) && (from == for_relative), size_32, source, 0x4010b0); inset_immediate ((to == for_register) && (from == for_immediate) && (size != size_64), size, source); inset_immediate ((to == for_memory) && (from == for_immediate) && (size != size_64), size, source); inset_immediate ((to == for_register) && (from == for_immediate) && (size == size_64), size_32, source); inset_immediate ((to == for_register) && (from == for_immediate) && (size == size_64), size_32, extension); inset_immediate ((to == for_register) && (from == for_immediate) && (size == size_64), size_32, 0); return (5 + (size == size_64)); } static int build_call (int * array) { int operation = array [0], from = array [1], source = array [2]; inset ((from == for_register) && (upper (source)), 0x41); inset (from == for_relative, 0xe8); inset (from == for_register, 0xff); inset_memory (from == for_relative, size_32, source, -(text_sector_size + 4)); inset (from == for_register, (0xd0 + 0x01 * (source & 0x07))); return (2); } static int build_enter (int * array) { int operation = array [0], dynamic_storage = array [1], nesting_level = array [2]; inset (true, 0xc8); inset_immediate (true, size_16, dynamic_storage); inset_immediate (true, size_8, nesting_level & 0x1f); return (2); } static int build_float (int * array) { int operation = array [0], size = array [1], from = array [2], source = array [3]; inset (from == for_memory, 0xd8 + 0x04 * (size == size_64)); modify_memory (operation, 0, from); inset_memory (from == for_memory, size, source, 0); return (3); } static int build_shift (int * array) { int operation = array [0], size = array [1], to = array [2], destination = array [3], offset = array [5]; short_prefix (size); long_prefix (size, to, destination, 0, 0); inset (true, 0xc0 + 0x01 * (size != size_8)); inset (to == for_register, 0x05 + 0x08 * (operation & 7)); inset (to == for_memory, 0xc0 + 0x08 * (operation & 7)); inset_memory (to == for_memory, size_32, destination, 0x1000 - text_sector_size - 4); inset_immediate (true, size_8, offset); return (5); } static int build_in_out (int * array) { int move = array [0], size = array [1], type = array [2], port = array [3]; short_prefix (size); inset (true, 0xe4 + 0x01 * (size != size_8) + 0x02 * (move != out) + 0x08 * (type == for_register)); inset_immediate (type == for_immediate, size_8, port); return (3); } static int build_pop (int * array) { int operation = array [0], size = array [1], to = array [2], destination = array [3]; short_prefix (size); inset ((to == for_register) && (upper (destination)), 0x41); inset (to == for_register, 0x58 + 0x01 * (destination & 0x07)); inset (to == for_memory, 0x8f); inset (to == for_memory, 0x05); inset_memory (to == for_memory, size_32, destination, 0); return (3); } static int build_push (int * array) { int operation = array [0], size = array [1], from = array [2], source = array [3]; short_prefix (size); inset ((from == for_register) && (upper (source)), 0x41); inset (from == for_register, 0x50 + 0x01 * (source & 0x07)); inset (from == for_memory, 0xff); inset (from == for_memory, 0x35); inset (from == for_immediate, 0x68 + 0x02 * (size == size_8)); inset_memory (from == for_memory, size_32, source, 0); inset_immediate (from == for_immediate, size, source); return (3); } static int build_swap (int * array) { int operation = array [0], size = array [1], destination = array [3]; long_prefix (size, for_register, destination, 0, 0); inset (true, 0x0f); inset (true, 0xc8 + 0x01 * (destination & 0x07)); return (3); } static int build_bit_scan (int * array) { int operation = array [0], size = array [1], destination = array [3], from = array [4], source = array [5]; short_prefix (size); long_prefix (size, for_register, destination, from, source); inset_immediate (true, size_16, 0xbc0f); modify_registers (for_register, destination, from, source); inset (from == for_memory, 0x05 + 0x08 * destination); inset_memory (from == for_memory, size_32, source, 0x1000 - (text_sector_size + 4)); return (5); } static int build_loop (int * array) { int operation = array [0], location = array [3]; inset (operation == loop_not_equal, 0xe0); inset (operation == loop_equal, 0xe1); inset (operation == loop, 0xe2); inset_memory (1, size_8, location, -(text_sector_size + 1)); return (3); } static void elf_main_header (void) { int enter = empty_store [0] + 0x4000b0; elf_main_header_byte [16] = 0x02; elf_main_header_byte [ 7] = 0x03; elf_main_header_byte [18] = 0x3e; memory_copy (& elf_main_header_byte [24], & enter, sizeof (enter)); } static void elf_text_sector (unsigned long text_size, unsigned long data_size) { unsigned long text = elf_header_size + text_size - data_size; memory_copy (& elf_text_sector_byte [32], & text, (int) sizeof (text)); memory_copy (& elf_text_sector_byte [40], & text, (int) sizeof (text)); } static void elf_data_sector (unsigned long text_size, unsigned long data_size) { unsigned long data = data_size; unsigned long core = elf_header_size + text_size - data_size; unsigned long move = 0x401000 + core; memory_copy (& elf_data_sector_byte [ 8], & core, (int) sizeof (core)); memory_copy (& elf_data_sector_byte [16], & move, (int) sizeof (move)); memory_copy (& elf_data_sector_byte [24], & move, (int) sizeof (move)); memory_copy (& elf_data_sector_byte [32], & data, (int) sizeof (data)); memory_copy (& elf_data_sector_byte [40], & data, (int) sizeof (data)); } static int (* build_instruction []) (int * array) = { store_memory, store_relative, store_immediate, 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_float, build_float, build_float, build_float, build_float, build_float, build_float, build_float, build_shift, build_shift, build_shift, build_shift, build_shift, build_shift, build_shift, build_shift, build_static_1, build_static_1, build_static_1, build_static_1, build_static_1, build_static_1, build_static_2, build_static_2, build_static_2, build_static_2, build_static_2, build_static_2, build_static_2, build_static_2, build_static_2, build_static_2, build_static_2, build_static_2, build_static_2, build_static_2, build_static_2, build_static_2, build_static_2, build_static_2, build_static_2, build_static_2, build_static_2, build_static_2, build_static_2, build_static_2, build_static_2, build_static_2, build_static_2, build_static_2, build_static_2, build_static_2, build_enter, build_call, build_in_out, build_in_out, build_jump, build_move, build_pop, build_push, 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_move_if, build_move_if, build_move_if, build_move_if, build_move_if, build_move_if, build_move_if, build_move_if, build_move_if, build_move_if, build_move_if, build_move_if, build_move_if, build_move_if, build_move_if, build_move_if, build_set_if, build_set_if, build_set_if, build_set_if, build_set_if, build_set_if, build_set_if, build_set_if, build_set_if, build_set_if, build_set_if, build_set_if, build_set_if, build_set_if, build_set_if, build_set_if, build_swap, build_bit_scan, build_bit_scan, build_loop, build_loop, build_loop }; static int assemble (int count, int * array) { for (uint index = 0; index < count; ++index) { index += build_instruction [array [index]] (& array [index]); } for (uint index = 1; index < empty_holes; ++index) { int set = 0; int get = empty_array [index]; memory_copy ((char *) & set, (char *) & text_sector_byte [get], (int) sizeof (set)); set += empty_store [empty_imbue [index]]; memory_copy ((char *) & text_sector_byte [get], (char *) & set, (int) sizeof (set)); } return (log_success); }