2023-11-20 09:36:04 -06:00

268 lines
8.2 KiB
Zig

const std = @import("std");
const assert = std.debug.assert;
const Allocator = std.mem.Allocator;
const data_structures = @import("../data_structures.zig");
const ArrayList = data_structures.ArrayList;
const emit = @import("emit.zig");
pub const Writer = struct {
in_file: []const u8,
items: []u8,
index: usize = 0,
allocator: Allocator,
pub fn init(allocator: Allocator) !Writer {
const file = try std.fs.cwd().readFileAlloc(allocator, "main.exe", 0xfffffffffffff);
const len = std.mem.alignForward(usize, file.len, 0x1000);
return Writer{
.in_file = file,
.items = try data_structures.mmap(len, .{}),
.allocator = allocator,
};
}
pub fn writeToMemory(writer: *Writer, image: *const emit.Result) !void {
//print("File len: {}", .{writer.in_file.len});
const dos_header: *const ImageDosHeader = @ptrCast(@alignCast(writer.in_file.ptr));
//print("File address: {}", .{dos_header.file_address_of_new_exe_header});
//print("File: {s}", .{writer.in_file[0x40..]});
for (writer.in_file[0x40..], 0..) |byte, index| {
_ = index;
if (byte == 'T') {
//print("Index: {}", .{index});
break;
}
}
assert(dos_header.magic_number == ImageDosHeader.magic);
// assert(dos_header.file_address_of_new_exe_header == @sizeOf(ImageDosHeader));
//print("{}", .{dos_header});
const file_header: *const ImageFileHeader = @ptrCast(@alignCast(writer.in_file[dos_header.file_address_of_new_exe_header + 4 ..].ptr));
_ = file_header;
//print("File header: {}", .{file_header});
writer.append(std.mem.asBytes(&ImageDosHeader{
.file_address_of_new_exe_header = 208,
}));
while (writer.index < 208) : (writer.index += 1) {
writer.append(&.{0});
}
writer.append(std.mem.asBytes(&image_NT_signature));
writer.append(std.mem.asBytes(&ImageFileHeader{
.machine = switch (image.target.cpu.arch) {
.x86_64 => .amd64,
.aarch64 => .arm64,
else => @panic("Architecture"),
},
.section_count = 3,
.time_date_stamp = @intCast(std.time.timestamp()),
}));
const kernel32 = blk: {
var library = Library{
.name = "KERNEL32.DLL",
};
try library.symbols.append(writer.allocator, Symbol{
.name = "ExitProcess",
});
break :blk library;
};
const libraries = &[_]Library{kernel32};
_ = libraries;
const code = &.{
0x48, 0x83, 0xec, 0x28, //subq $40, %rsp
0xb9, 0x2a, 0x00, 0x00, 0x00, //movl $42, %ecx
0xff, 0x15, 0xf1, 0x0f, 0x00, 0x00, //callq *4081(%rip) # 0x140002000
0xcc,
};
_ = code;
const pdata = &.{
0x00, 0x10,
0x00, 0x00,
0x10, 0x10,
0x00, 0x00,
0x28, 0x21,
0x00, 0x00,
};
_ = pdata;
// TODO
// writer.append(std.mem.asBytes(ImageOptionalHeader{
// .magic = ImageOptionalHeader.magic,
// .size_of_code = code.len,
// }));
unreachable;
}
fn append(writer: *Writer, bytes: []const u8) void {
const destination = writer.items[writer.index..][0..bytes.len];
const source = bytes;
@memcpy(destination, source);
writer.index += bytes.len;
}
pub fn writeToFile(writer: *Writer, executable_relative_path: []const u8) !void {
_ = writer;
_ = executable_relative_path;
unreachable;
}
};
const ImageDosHeader = extern struct {
magic_number: u16 = magic,
bytes_last_page_of_file: u16 = 0,
pages_in_file: u16 = 0,
relocations: u16 = 0,
size_of_header_in_paragraphs: u16 = 0,
minimum_extra_paragraphs: u16 = 0,
maximum_extra_paragraphs: u16 = 0,
initial_ss_value: u16 = 0,
initial_sp_value: u16 = 0,
cheksum: u16 = 0,
initial_ip_value: u16 = 0,
initial_cs_value: u16 = 0,
file_address_of_relocation_table: u16 = 0,
overlay_number: u16 = 0,
reserved_words: [4]u16 = .{0} ** 4,
oem_id: u16 = 0,
oem_info: u16 = 0,
reserved_words2: [10]u16 = .{0} ** 10,
file_address_of_new_exe_header: u32 = @sizeOf(ImageDosHeader),
const magic = 0x5a4d;
comptime {
assert(@sizeOf(ImageDosHeader) == 64);
}
};
const image_NT_signature: u32 = 0x00004550;
/// COFF header format
const ImageFileHeader = extern struct {
machine: ImageFileMachine,
section_count: u16,
time_date_stamp: u32,
symbol_table_offset: u32 = 0,
symbol_count: u32 = 0,
size_of_optional_header: u16 = @sizeOf(ImageOptionalHeader),
characteristics: Characteristics = .{},
const Characteristics = packed struct(u16) {
relocations_stripped: bool = false,
executable_image: bool = true,
stripped_line_count: bool = false,
stripped_local_symbols: bool = false,
aggressive_ws_trim: bool = false,
large_address_aware: bool = true,
reserved: u1 = 0,
bytes_reversed_lo: bool = false,
machine_32bit: bool = false,
stripped_debug: bool = false,
removable_run_from_swap: bool = false,
net_run_from_swap: bool = false,
system: bool = false,
dll: bool = false,
up_systems_only: bool = false,
bytes_reversed_hi: bool = false,
};
};
const ImageFileMachine = enum(u16) {
unknown = 0,
target_host = 0x0001, // Useful for indicating we want to interact with the host and not a WoW guest.
i386 = 0x014c, // Intel 386.
r3000 = 0x0162, // MIPS little-endian, 0x160 big-endian
r4000 = 0x0166, // MIPS little-endian
r10000 = 0x0168, // MIPS little-endian
wcemipsv2 = 0x0169, // MIPS little-endian WCE v2
alpha = 0x0184, // Alpha_AXP
sh3 = 0x01a2, // SH3 little-endian
sh3dsp = 0x01a3,
sh3e = 0x01a4, // SH3E little-endian
sh4 = 0x01a6, // SH4 little-endian
sh5 = 0x01a8, // SH5
arm = 0x01c0, // ARM Little-Endian
thumb = 0x01c2, // ARM Thumb/Thumb-2 Little-Endian
armnt = 0x01c4, // ARM Thumb-2 Little-Endian
am33 = 0x01d3,
powerpc = 0x01F0, // IBM PowerPC Little-Endian
powerpcfp = 0x01f1,
ia64 = 0x0200, // Intel 64
mips16 = 0x0266, // MIPS
alpha64 = 0x0284, // ALPHA64
mipsfpu = 0x0366, // MIPS
mipsfpu16 = 0x0466, // MIPS
tricore = 0x0520, // Infineon
cef = 0x0CEF,
ebc = 0x0EBC, // EFI Byte Code
amd64 = 0x8664, // AMD64 (K8)
m32r = 0x9041, // M32R little-endian
arm64 = 0xAA64, // ARM64 Little-Endian
cee = 0xC0EE,
const axp64 = ImageFileMachine.alpha64;
};
const ImageOptionalHeader = extern struct {
magic: u16 = magic,
major_linker_version: u8 = 0,
minor_linker_version: u8 = 0,
size_of_code: u32,
size_of_initialized_data: u32,
size_of_uninitialized_data: u32,
address_of_entry_point: u32,
base_of_code: u32,
image_base: u64,
section_alignment: u32,
file_alignment: u32,
major_os_version: u16,
minor_os_version: u16,
major_image_version: u16,
minor_image_version: u16,
major_subsystem_version: u16,
minor_subsystem_version: u16,
win32_version_value: u32,
size_of_image: u32,
size_of_headers: u32,
checksum: u32,
subsystem: u16,
dll_characteristics: u16,
size_of_stack_reserve: u64,
size_of_stack_commit: u64,
size_of_heap_reserve: u64,
size_of_heap_commit: u64,
loader_flags: u32,
number_of_RVA_and_sizes: u32,
data_directory: [image_number_of_directory_entries]ImageDataDirectory,
const magic = 0x20b;
comptime {
assert(@sizeOf(ImageOptionalHeader) == 0xf0);
}
};
const ImageDataDirectory = extern struct {
virtual_address: u32,
size: u32,
};
const image_number_of_directory_entries = 0x10;
const Library = struct {
symbols: ArrayList(Symbol) = .{},
name: []const u8,
name_virtual_address: u32 = 0,
virtual_address: u32 = 0,
image_thunk_virtual_address: u32 = 0,
};
const Symbol = struct {
name: []const u8,
name_virtual_address: u32 = 0,
offset_in_data: u32 = 0,
};