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 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));
|
|
}
|