282 lines
8.9 KiB
Zig
282 lines
8.9 KiB
Zig
const std = @import("std");
|
|
const assert = std.debug.assert;
|
|
const equal = std.mem.eql;
|
|
|
|
const data_structures = @import("../data_structures.zig");
|
|
const Allocator = data_structures.Allocator;
|
|
const ArrayList = data_structures.ArrayList;
|
|
|
|
const emit = @import("emit.zig");
|
|
|
|
pub const Writer = struct {
|
|
bytes: ArrayList(u8),
|
|
allocator: Allocator,
|
|
|
|
pub fn init(allocator: Allocator) !Writer {
|
|
return .{
|
|
.bytes = try ArrayList(u8).initCapacity(allocator, 0x10000),
|
|
.allocator = allocator,
|
|
};
|
|
}
|
|
|
|
pub fn getHeader(writer: *Writer) *Header {
|
|
return @ptrCast(@alignCast(writer.bytes.items.ptr));
|
|
}
|
|
|
|
pub fn writeToMemory(writer: *Writer, image: *const emit.Result) !void {
|
|
const section_fields = @typeInfo(@TypeOf(image.sections)).Struct.fields;
|
|
const section_count = blk: {
|
|
var result: u16 = 0;
|
|
inline for (section_fields) |section_field| {
|
|
const section_size = @field(image.sections, section_field.name).index;
|
|
result += @intFromBool(section_size > 0);
|
|
}
|
|
break :blk result;
|
|
};
|
|
|
|
const program_header_count = section_count;
|
|
const program_start_offset = @sizeOf(Header) + program_header_count * @sizeOf(ProgramHeader);
|
|
|
|
var section_offsets: [section_fields.len]u32 = undefined;
|
|
|
|
const program_end_offset = blk: {
|
|
var result: u32 = program_start_offset;
|
|
inline for (section_fields, 0..) |section_field, section_index| {
|
|
const section = &@field(image.sections, section_field.name);
|
|
if (section.index > 0) {
|
|
const section_offset = std.mem.alignForward(u32, result, section.alignment);
|
|
section_offsets[section_index] = section_offset;
|
|
result = std.mem.alignForward(u32, section_offset + @as(u32, @intCast(section.index)), section.alignment);
|
|
}
|
|
}
|
|
|
|
break :blk result;
|
|
};
|
|
|
|
const elf_file_end_offset = program_end_offset + @sizeOf(SectionHeader) * section_count;
|
|
try writer.bytes.resize(writer.allocator, elf_file_end_offset);
|
|
|
|
const base_address = 0x200000;
|
|
|
|
writer.getHeader().* = Header{
|
|
.endianness = .little,
|
|
.machine = switch (image.target.cpu.arch) {
|
|
.x86_64 => .AMD64,
|
|
else => unreachable,
|
|
},
|
|
.os_abi = switch (image.target.os.tag) {
|
|
.linux => .systemv,
|
|
else => unreachable,
|
|
},
|
|
.entry = base_address + section_offsets[0] + image.entry_point,
|
|
.section_header_offset = program_end_offset,
|
|
.program_header_count = program_header_count,
|
|
.section_header_count = section_count,
|
|
.name_section_header_index = 0,
|
|
};
|
|
|
|
var program_header_offset: usize = @sizeOf(Header);
|
|
var section_header_offset = program_end_offset;
|
|
inline for (section_fields, section_offsets) |section_field, section_offset| {
|
|
const section_name = section_field.name;
|
|
const section = &@field(image.sections, section_name);
|
|
if (section.index > 0) {
|
|
const program_header: *ProgramHeader = @ptrCast(@alignCast(writer.bytes.items[program_header_offset..].ptr));
|
|
program_header.* = .{
|
|
.type = .load,
|
|
.flags = .{
|
|
.executable = equal(u8, section_name, "text"),
|
|
.writable = equal(u8, section_name, "data"),
|
|
.readable = true,
|
|
},
|
|
.offset = 0,
|
|
.virtual_address = base_address,
|
|
.physical_address = base_address,
|
|
.size_in_file = section.index,
|
|
.size_in_memory = section.index,
|
|
.alignment = 0,
|
|
};
|
|
|
|
const source = section.content[0..section.index];
|
|
const destination = writer.bytes.items[section_offset..][0..source.len];
|
|
@memcpy(destination, source);
|
|
|
|
const section_header: *SectionHeader = @ptrCast(@alignCast(writer.bytes.items[section_header_offset..].ptr));
|
|
section_header.* = .{
|
|
.name_offset = 0,
|
|
.type = .program_data,
|
|
.flags = .{
|
|
.alloc = equal(u8, section_name, "text"),
|
|
.executable = equal(u8, section_name, "text"),
|
|
.writable = equal(u8, section_name, "data"),
|
|
},
|
|
.address = base_address + section_offset,
|
|
.offset = section_offset,
|
|
.size = section.index,
|
|
.link = 0,
|
|
.info = 0,
|
|
.alignment = 0,
|
|
.entry_size = 0,
|
|
};
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn writeToFile(writer: *const Writer, file_path: []const u8) !void {
|
|
std.debug.print("Writing file to {s}\n", .{file_path});
|
|
const flags = switch (@import("builtin").os.tag) {
|
|
.windows => .{},
|
|
else => .{
|
|
.mode = 0o777,
|
|
},
|
|
};
|
|
const file_descriptor = try std.fs.cwd().createFile(file_path, flags);
|
|
try file_descriptor.writeAll(writer.bytes.items);
|
|
file_descriptor.close();
|
|
}
|
|
|
|
pub fn writeToFileAbsolute(writer: *const Writer, absolute_file_path: []const u8) !void {
|
|
const file = try std.fs.createFileAbsolute(absolute_file_path, .{});
|
|
defer file.close();
|
|
try file.writeAll(writer.bytes.items);
|
|
}
|
|
};
|
|
|
|
const Header = extern struct {
|
|
magic: u8 = 0x7f,
|
|
elf_id: [3]u8 = "ELF".*,
|
|
bit_count: BitCount = .@"64",
|
|
endianness: Endianness = .little,
|
|
header_version: u8 = 1,
|
|
os_abi: ABI,
|
|
abi_version: u8 = 0,
|
|
padding: [7]u8 = [_]u8{0} ** 7,
|
|
object_type: ObjectFileType = .executable, // e_type
|
|
machine: Machine,
|
|
version: u32 = 1,
|
|
entry: u64,
|
|
program_header_offset: u64 = std.mem.alignForward(u16, @sizeOf(Header), @alignOf(ProgramHeader)),
|
|
section_header_offset: u64,
|
|
flags: u32 = 0,
|
|
header_size: u16 = 0x40,
|
|
program_header_size: u16 = @sizeOf(ProgramHeader),
|
|
program_header_count: u16 = 1,
|
|
section_header_size: u16 = @sizeOf(SectionHeader),
|
|
section_header_count: u16,
|
|
name_section_header_index: u16,
|
|
|
|
const BitCount = enum(u8) {
|
|
@"32" = 1,
|
|
@"64" = 2,
|
|
};
|
|
|
|
const ABI = enum(u8) {
|
|
systemv = 0,
|
|
};
|
|
|
|
const ObjectFileType = enum(u16) {
|
|
none = 0,
|
|
relocatable = 1,
|
|
executable = 2,
|
|
dynamic = 3,
|
|
core = 4,
|
|
lo_os = 0xfe00,
|
|
hi_os = 0xfeff,
|
|
lo_proc = 0xff00,
|
|
hi_proc = 0xffff,
|
|
};
|
|
|
|
const Machine = enum(u16) {
|
|
AMD64 = 0x3e,
|
|
};
|
|
|
|
const Endianness = enum(u8) {
|
|
little = 1,
|
|
big = 2,
|
|
};
|
|
};
|
|
|
|
const ProgramHeader = extern struct {
|
|
type: Type = .load,
|
|
flags: Flags,
|
|
offset: u64,
|
|
virtual_address: u64,
|
|
physical_address: u64,
|
|
size_in_file: u64,
|
|
size_in_memory: u64,
|
|
alignment: u64 = 0,
|
|
|
|
const Type = enum(u32) {
|
|
null = 0,
|
|
load = 1,
|
|
dynamic = 2,
|
|
interpreter = 3,
|
|
note = 4,
|
|
shlib = 5, // reserved
|
|
program_header = 6,
|
|
tls = 7,
|
|
lo_os = 0x60000000,
|
|
hi_os = 0x6fffffff,
|
|
lo_proc = 0x70000000,
|
|
hi_proc = 0x7fffffff,
|
|
};
|
|
|
|
const Flags = packed struct(u32) {
|
|
executable: bool,
|
|
writable: bool,
|
|
readable: bool,
|
|
reserved: u29 = 0,
|
|
};
|
|
};
|
|
const SectionHeader = extern struct {
|
|
name_offset: u32,
|
|
type: Type,
|
|
flags: Flags,
|
|
address: u64,
|
|
offset: u64,
|
|
size: u64,
|
|
// section index
|
|
link: u32,
|
|
info: u32,
|
|
alignment: u64,
|
|
entry_size: u64,
|
|
|
|
// type
|
|
const Type = enum(u32) {
|
|
null = 0,
|
|
program_data = 1,
|
|
symbol_table = 2,
|
|
string_table = 3,
|
|
relocation_entries_addends = 4,
|
|
symbol_hash_table = 5,
|
|
dynamic_linking_info = 6,
|
|
notes = 7,
|
|
program_space_no_data = 8,
|
|
relocation_entries = 9,
|
|
reserved = 10,
|
|
dynamic_linker_symbol_table = 11,
|
|
array_of_constructors = 14,
|
|
array_of_destructors = 15,
|
|
array_of_pre_constructors = 16,
|
|
section_group = 17,
|
|
extended_section_indices = 18,
|
|
number_of_defined_types = 19,
|
|
start_os_specific = 0x60000000,
|
|
};
|
|
|
|
const Flags = packed struct(u64) {
|
|
writable: bool,
|
|
alloc: bool,
|
|
executable: bool,
|
|
reserved: bool = false,
|
|
mergeable: bool = false,
|
|
contains_null_terminated_strings: bool = false,
|
|
info_link: bool = false,
|
|
link_order: bool = false,
|
|
os_non_conforming: bool = false,
|
|
section_group: bool = false,
|
|
tls: bool = false,
|
|
_reserved: u53 = 0,
|
|
};
|
|
};
|