| ... | ... | @@ -6,6 +6,8 @@ const assert = std.debug.assert; |
| 6 | 6 | const fs = std.fs; |
| 7 | 7 | const log = std.log.scoped(.link); |
| 8 | 8 | const macho = std.macho; |
| 9 | const math = std.math; |
| 10 | const mem = std.mem; |
| 9 | 11 | |
| 10 | 12 | const Module = @import("../Module.zig"); |
| 11 | 13 | const link = @import("../link.zig"); |
| ... | ... | @@ -15,6 +17,14 @@ pub const base_tag: Tag = File.Tag.macho; |
| 15 | 17 | |
| 16 | 18 | base: File, |
| 17 | 19 | |
| 20 | /// Stored in native-endian format, depending on target endianness needs to be bswapped on read/write. |
| 21 | /// Same order as in the file. |
| 22 | segment_cmds: std.ArrayListUnmanaged(macho.segment_command_64) = std.ArrayListUnmanaged(macho.segment_command_64){}, |
| 23 | |
| 24 | /// Stored in native-endian format, depending on target endianness needs to be bswapped on read/write. |
| 25 | /// Same order as in the file. |
| 26 | sections: std.ArrayListUnmanaged(macho.@"section_64") = std.ArrayListUnmanaged(macho.@"section_64"){}, |
| 27 | |
| 18 | 28 | entry_addr: ?u64 = null, |
| 19 | 29 | |
| 20 | 30 | error_flags: File.ErrorFlags = File.ErrorFlags{}, |
| ... | ... | @@ -86,9 +96,34 @@ fn createFile(allocator: *Allocator, file: fs.File, options: link.Options) !Mach |
| 86 | 96 | }; |
| 87 | 97 | errdefer self.deinit(); |
| 88 | 98 | |
| 99 | if (options.output_mode == .Exe) { |
| 100 | // The first segment command for executables is always a __PAGEZERO segment. |
| 101 | try self.segment_cmds.append(allocator, .{ |
| 102 | .cmd = macho.LC_SEGMENT_64, |
| 103 | .cmdsize = @sizeOf(macho.segment_command_64), |
| 104 | .segname = self.makeString("__PAGEZERO"), |
| 105 | .vmaddr = 0, |
| 106 | .vmsize = 0, |
| 107 | .fileoff = 0, |
| 108 | .filesize = 0, |
| 109 | .maxprot = 0, |
| 110 | .initprot = 0, |
| 111 | .nsects = 0, |
| 112 | .flags = 0, |
| 113 | }); |
| 114 | } |
| 115 | |
| 89 | 116 | return self; |
| 90 | 117 | } |
| 91 | 118 | |
| 119 | fn makeString(self: *MachO, comptime bytes: []const u8) [16]u8 { |
| 120 | if (bytes.len > 16) @compileError("MachO segment/section name too long"); |
| 121 | |
| 122 | var buf: [16]u8 = undefined; |
| 123 | mem.copy(u8, buf[0..], bytes); |
| 124 | return buf; |
| 125 | } |
| 126 | |
| 92 | 127 | fn writeMachOHeader(self: *MachO) !void { |
| 93 | 128 | var hdr: macho.mach_header_64 = undefined; |
| 94 | 129 | hdr.magic = macho.MH_MAGIC_64; |
| ... | ... | @@ -122,9 +157,12 @@ fn writeMachOHeader(self: *MachO) !void { |
| 122 | 157 | }; |
| 123 | 158 | hdr.filetype = filetype; |
| 124 | 159 | |
| 125 | | // TODO the rest of the header |
| 126 | | hdr.ncmds = 0; |
| 127 | | hdr.sizeofcmds = 0; |
| 160 | // TODO consider other commands |
| 161 | const ncmds = try math.cast(u32, self.segment_cmds.items.len); |
| 162 | hdr.ncmds = ncmds; |
| 163 | hdr.sizeofcmds = ncmds * @sizeOf(macho.segment_command_64); |
| 164 | |
| 165 | // TODO should these be set to something else? |
| 128 | 166 | hdr.flags = 0; |
| 129 | 167 | hdr.reserved = 0; |
| 130 | 168 | |
| ... | ... | @@ -133,6 +171,17 @@ fn writeMachOHeader(self: *MachO) !void { |
| 133 | 171 | |
| 134 | 172 | pub fn flush(self: *MachO, module: *Module) !void { |
| 135 | 173 | // TODO implement flush |
| 174 | { |
| 175 | const buf = try self.base.allocator.alloc(macho.segment_command_64, self.segment_cmds.items.len); |
| 176 | defer self.base.allocator.free(buf); |
| 177 | |
| 178 | for (buf) |*seg, i| { |
| 179 | seg.* = self.segment_cmds.items[i]; |
| 180 | } |
| 181 | |
| 182 | try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), @sizeOf(macho.mach_header_64)); |
| 183 | } |
| 184 | |
| 136 | 185 | if (self.entry_addr == null and self.base.options.output_mode == .Exe) { |
| 137 | 186 | log.debug("flushing. no_entry_point_found = true\n", .{}); |
| 138 | 187 | self.error_flags.no_entry_point_found = true; |
| ... | ... | @@ -143,7 +192,10 @@ pub fn flush(self: *MachO, module: *Module) !void { |
| 143 | 192 | } |
| 144 | 193 | } |
| 145 | 194 | |
| 146 | | pub fn deinit(self: *MachO) void {} |
| 195 | pub fn deinit(self: *MachO) void { |
| 196 | self.segment_cmds.deinit(self.base.allocator); |
| 197 | self.@"sections".deinit(self.base.allocator); |
| 198 | } |
| 147 | 199 | |
| 148 | 200 | pub fn allocateDeclIndexes(self: *MachO, decl: *Module.Decl) !void {} |
| 149 | 201 | |