| ... | ... | @@ -4,6 +4,8 @@ const std = @import("std"); |
| 4 | 4 | const Allocator = std.mem.Allocator; |
| 5 | 5 | const assert = std.debug.assert; |
| 6 | 6 | const fs = std.fs; |
| 7 | const log = std.log.scoped(.link); |
| 8 | const macho = std.macho; |
| 7 | 9 | |
| 8 | 10 | const Module = @import("../Module.zig"); |
| 9 | 11 | const link = @import("../link.zig"); |
| ... | ... | @@ -13,6 +15,8 @@ pub const base_tag: Tag = File.Tag.macho; |
| 13 | 15 | |
| 14 | 16 | base: File, |
| 15 | 17 | |
| 18 | entry_addr: ?u64 = null, |
| 19 | |
| 16 | 20 | error_flags: File.ErrorFlags = File.ErrorFlags{}, |
| 17 | 21 | |
| 18 | 22 | pub const TextBlock = struct { |
| ... | ... | @@ -67,13 +71,77 @@ fn openFile(allocator: *Allocator, file: fs.File, options: link.Options) !MachO |
| 67 | 71 | /// Returns an error if `file` is not already open with +read +write +seek abilities. |
| 68 | 72 | fn createFile(allocator: *Allocator, file: fs.File, options: link.Options) !MachO { |
| 69 | 73 | switch (options.output_mode) { |
| 70 | | .Exe => return error.TODOImplementWritingMachOExeFiles, |
| 71 | | .Obj => return error.TODOImplementWritingMachOObjFiles, |
| 74 | .Exe => {}, |
| 75 | .Obj => {}, |
| 72 | 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("flushing. no_entry_point_found = true\n", .{}); |
| 138 | self.error_flags.no_entry_point_found = true; |
| 139 | } else { |
| 140 | log.debug("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 | 146 | pub fn deinit(self: *MachO) void {} |
| 79 | 147 | |