authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2020-08-18 17:45:04+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2020-08-18 23:35:31+02:00
loge4b3da27203e0117ac29cceb03d7fe396f3931a7
treeb6f030d5ee91564d7e3d5368315abc7f860a6c5d
parentd139e44cfae68ace32458ff4d804dc6331b1ec8e

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>

3 files changed, 83 insertions(+), 4 deletions(-)

lib/std/macho.zig+12
...@@ -703,3 +703,15 @@ pub const cpu_type_t = integer_t;...@@ -703,3 +703,15 @@ pub const cpu_type_t = integer_t;
703pub const cpu_subtype_t = integer_t;703pub const cpu_subtype_t = integer_t;
704pub const integer_t = c_int;704pub const integer_t = c_int;
705pub const vm_prot_t = c_int;705pub const vm_prot_t = c_int;
706
707/// CPU type targeting 64-bit Intel-based Macs
708pub const CPU_TYPE_X86_64: cpu_type_t = 0x01000007;
709
710/// CPU type targeting 64-bit ARM-based Macs
711pub const CPU_TYPE_ARM64: cpu_type_t = 0x0100000C;
712
713/// All Intel-based Macs
714pub const CPU_SUBTYPE_X86_64_ALL: cpu_subtype_t = 0x3;
715
716/// All ARM-based Macs
717pub const CPU_SUBTYPE_ARM_ALL: cpu_subtype_t = 0x0;
src-self-hosted/link.zig-1
...@@ -40,7 +40,6 @@ pub const Options = struct {...@@ -40,7 +40,6 @@ pub const Options = struct {
40 program_code_size_hint: u64 = 256 * 1024,40 program_code_size_hint: u64 = 256 * 1024,
41};41};
4242
43
44pub const File = struct {43pub const File = struct {
45 pub const LinkBlock = union {44 pub const LinkBlock = union {
46 elf: Elf.TextBlock,45 elf: Elf.TextBlock,
src-self-hosted/link/MachO.zig+71-3
...@@ -4,6 +4,8 @@ const std = @import("std");...@@ -4,6 +4,8 @@ const std = @import("std");
4const Allocator = std.mem.Allocator;4const Allocator = std.mem.Allocator;
5const assert = std.debug.assert;5const assert = std.debug.assert;
6const fs = std.fs;6const fs = std.fs;
7const log = std.log;
8const macho = std.macho;
79
8const Module = @import("../Module.zig");10const Module = @import("../Module.zig");
9const link = @import("../link.zig");11const link = @import("../link.zig");
...@@ -13,6 +15,8 @@ pub const base_tag: Tag = File.Tag.macho;...@@ -13,6 +15,8 @@ pub const base_tag: Tag = File.Tag.macho;
1315
14base: File,16base: File,
1517
18entry_addr: ?u64 = null,
19
16error_flags: File.ErrorFlags = File.ErrorFlags{},20error_flags: File.ErrorFlags = File.ErrorFlags{},
1721
18pub const TextBlock = struct {22pub const TextBlock = struct {
...@@ -67,13 +71,77 @@ fn openFile(allocator: *Allocator, file: fs.File, options: link.Options) !MachO...@@ -67,13 +71,77 @@ fn openFile(allocator: *Allocator, file: fs.File, options: link.Options) !MachO
67/// Returns an error if `file` is not already open with +read +write +seek abilities.71/// Returns an error if `file` is not already open with +read +write +seek abilities.
68fn createFile(allocator: *Allocator, file: fs.File, options: link.Options) !MachO {72fn createFile(allocator: *Allocator, file: fs.File, options: link.Options) !MachO {
69 switch (options.output_mode) {73 switch (options.output_mode) {
70 .Exe => return error.TODOImplementWritingMachOExeFiles,74 .Exe => {},
71 .Obj => return error.TODOImplementWritingMachOObjFiles,75 .Obj => {},
72 .Lib => return error.TODOImplementWritingLibFiles,76 .Lib => return error.TODOImplementWritingLibFiles,
73 }77 }
78
79 var self: MachO = .{
80 .base = .{
81 .file = file,
82 .tag = .macho,
83 .options = options,
84 .allocator = allocator,
85 },
86 };
87 errdefer self.deinit();
88
89 return self;
74}90}
7591
76pub fn flush(self: *MachO, module: *Module) !void {}92fn writeMachOHeader(self: *MachO) !void {
93 var hdr: macho.mach_header_64 = undefined;
94 hdr.magic = macho.MH_MAGIC_64;
95
96 const CpuInfo = struct {
97 cpu_type: macho.cpu_type_t,
98 cpu_subtype: macho.cpu_subtype_t,
99 };
100
101 const cpu_info: CpuInfo = switch (self.base.options.target.cpu.arch) {
102 .aarch64 => .{
103 .cpu_type = macho.CPU_TYPE_ARM64,
104 .cpu_subtype = macho.CPU_SUBTYPE_ARM_ALL,
105 },
106 .x86_64 => .{
107 .cpu_type = macho.CPU_TYPE_X86_64,
108 .cpu_subtype = macho.CPU_SUBTYPE_X86_64_ALL,
109 },
110 else => return error.UnsupportedMachOArchitecture,
111 };
112 hdr.cputype = cpu_info.cpu_type;
113 hdr.cpusubtype = cpu_info.cpu_subtype;
114
115 const filetype: u32 = switch (self.base.options.output_mode) {
116 .Exe => macho.MH_EXECUTE,
117 .Obj => macho.MH_OBJECT,
118 .Lib => switch (self.base.options.link_mode) {
119 .Static => return error.TODOStaticLibMachOType,
120 .Dynamic => macho.MH_DYLIB,
121 },
122 };
123 hdr.filetype = filetype;
124
125 // TODO the rest of the header
126 hdr.ncmds = 0;
127 hdr.sizeofcmds = 0;
128 hdr.flags = 0;
129 hdr.reserved = 0;
130
131 try self.base.file.?.pwriteAll(@ptrCast([*]const u8, &hdr)[0..@sizeOf(macho.mach_header_64)], 0);
132}
133
134pub fn flush(self: *MachO, module: *Module) !void {
135 // TODO implement flush
136 if (self.entry_addr == null and self.base.options.output_mode == .Exe) {
137 log.debug(.link, "flushing. no_entry_point_found = true\n", .{});
138 self.error_flags.no_entry_point_found = true;
139 } else {
140 log.debug(.link, "flushing. no_entry_point_found = false\n", .{});
141 self.error_flags.no_entry_point_found = false;
142 try self.writeMachOHeader();
143 }
144}
77145
78pub fn deinit(self: *MachO) void {}146pub fn deinit(self: *MachO) void {}
79147