457 lines
17 KiB
C
Executable File
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));
|
|
}
|