Write out Mach-O header

This commit write out Mach-O header in the linker's `flush`
method. The header currently only populates the magic number,
filetype, and cpu info.

Signed-off-by: Jakub Konka <kubkon@jakubkonka.com>
This commit is contained in:
Jakub Konka 2020-08-18 17:45:04 +02:00
parent d139e44cfa
commit e4b3da2720
3 changed files with 83 additions and 4 deletions

View File

@ -703,3 +703,15 @@ pub const cpu_type_t = integer_t;
pub const cpu_subtype_t = integer_t;
pub const integer_t = c_int;
pub const vm_prot_t = c_int;
/// CPU type targeting 64-bit Intel-based Macs
pub const CPU_TYPE_X86_64: cpu_type_t = 0x01000007;
/// CPU type targeting 64-bit ARM-based Macs
pub const CPU_TYPE_ARM64: cpu_type_t = 0x0100000C;
/// All Intel-based Macs
pub const CPU_SUBTYPE_X86_64_ALL: cpu_subtype_t = 0x3;
/// All ARM-based Macs
pub const CPU_SUBTYPE_ARM_ALL: cpu_subtype_t = 0x0;

View File

@ -40,7 +40,6 @@ pub const Options = struct {
program_code_size_hint: u64 = 256 * 1024,
};
pub const File = struct {
pub const LinkBlock = union {
elf: Elf.TextBlock,

View File

@ -4,6 +4,8 @@ const std = @import("std");
const Allocator = std.mem.Allocator;
const assert = std.debug.assert;
const fs = std.fs;
const log = std.log;
const macho = std.macho;
const Module = @import("../Module.zig");
const link = @import("../link.zig");
@ -13,6 +15,8 @@ pub const base_tag: Tag = File.Tag.macho;
base: File,
entry_addr: ?u64 = null,
error_flags: File.ErrorFlags = File.ErrorFlags{},
pub const TextBlock = struct {
@ -67,13 +71,77 @@ fn openFile(allocator: *Allocator, file: fs.File, options: link.Options) !MachO
/// Returns an error if `file` is not already open with +read +write +seek abilities.
fn createFile(allocator: *Allocator, file: fs.File, options: link.Options) !MachO {
switch (options.output_mode) {
.Exe => return error.TODOImplementWritingMachOExeFiles,
.Obj => return error.TODOImplementWritingMachOObjFiles,
.Exe => {},
.Obj => {},
.Lib => return error.TODOImplementWritingLibFiles,
}
var self: MachO = .{
.base = .{
.file = file,
.tag = .macho,
.options = options,
.allocator = allocator,
},
};
errdefer self.deinit();
return self;
}
pub fn flush(self: *MachO, module: *Module) !void {}
fn writeMachOHeader(self: *MachO) !void {
var hdr: macho.mach_header_64 = undefined;
hdr.magic = macho.MH_MAGIC_64;
const CpuInfo = struct {
cpu_type: macho.cpu_type_t,
cpu_subtype: macho.cpu_subtype_t,
};
const cpu_info: CpuInfo = switch (self.base.options.target.cpu.arch) {
.aarch64 => .{
.cpu_type = macho.CPU_TYPE_ARM64,
.cpu_subtype = macho.CPU_SUBTYPE_ARM_ALL,
},
.x86_64 => .{
.cpu_type = macho.CPU_TYPE_X86_64,
.cpu_subtype = macho.CPU_SUBTYPE_X86_64_ALL,
},
else => return error.UnsupportedMachOArchitecture,
};
hdr.cputype = cpu_info.cpu_type;
hdr.cpusubtype = cpu_info.cpu_subtype;
const filetype: u32 = switch (self.base.options.output_mode) {
.Exe => macho.MH_EXECUTE,
.Obj => macho.MH_OBJECT,
.Lib => switch (self.base.options.link_mode) {
.Static => return error.TODOStaticLibMachOType,
.Dynamic => macho.MH_DYLIB,
},
};
hdr.filetype = filetype;
// TODO the rest of the header
hdr.ncmds = 0;
hdr.sizeofcmds = 0;
hdr.flags = 0;
hdr.reserved = 0;
try self.base.file.?.pwriteAll(@ptrCast([*]const u8, &hdr)[0..@sizeOf(macho.mach_header_64)], 0);
}
pub fn flush(self: *MachO, module: *Module) !void {
// TODO implement flush
if (self.entry_addr == null and self.base.options.output_mode == .Exe) {
log.debug(.link, "flushing. no_entry_point_found = true\n", .{});
self.error_flags.no_entry_point_found = true;
} else {
log.debug(.link, "flushing. no_entry_point_found = false\n", .{});
self.error_flags.no_entry_point_found = false;
try self.writeMachOHeader();
}
}
pub fn deinit(self: *MachO) void {}