Commit e4b3da2720

Jakub Konka <kubkon@jakubkonka.com>
2020-08-18 17:45:04
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>
1 parent d139e44
Changed files (3)
lib
src-self-hosted
lib/std/macho.zig
@@ -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;
src-self-hosted/link/MachO.zig
@@ -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 {}
 
src-self-hosted/link.zig
@@ -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,