| ... | @@ -4,6 +4,8 @@ const std = @import("std"); | ... | @@ -4,6 +4,8 @@ const std = @import("std"); |
| 4 | const Allocator = std.mem.Allocator; | 4 | const Allocator = std.mem.Allocator; |
| 5 | const assert = std.debug.assert; | 5 | const assert = std.debug.assert; |
| 6 | const fs = std.fs; | 6 | const fs = std.fs; |
| | 7 | const log = std.log; |
| | 8 | const macho = std.macho; |
| 7 | | 9 | |
| 8 | const Module = @import("../Module.zig"); | 10 | const Module = @import("../Module.zig"); |
| 9 | const link = @import("../link.zig"); | 11 | const 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; |
| 13 | | 15 | |
| 14 | base: File, | 16 | base: File, |
| 15 | | 17 | |
| | 18 | entry_addr: ?u64 = null, |
| | 19 | |
| 16 | error_flags: File.ErrorFlags = File.ErrorFlags{}, | 20 | error_flags: File.ErrorFlags = File.ErrorFlags{}, |
| 17 | | 21 | |
| 18 | pub const TextBlock = struct { | 22 | pub 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. |
| 68 | fn createFile(allocator: *Allocator, file: fs.File, options: link.Options) !MachO { | 72 | fn 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 | } |
| 75 | | 91 | |
| 76 | pub fn flush(self: *MachO, module: *Module) !void {} | 92 | fn 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 | |
| | 134 | pub 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 | } |
| 77 | | 145 | |
| 78 | pub fn deinit(self: *MachO) void {} | 146 | pub fn deinit(self: *MachO) void {} |
| 79 | | 147 | |