| ... | @@ -25,55 +25,9 @@ const Trie = @import("MachO/Trie.zig"); | ... | @@ -25,55 +25,9 @@ const Trie = @import("MachO/Trie.zig"); |
| 25 | const CodeSignature = @import("MachO/CodeSignature.zig"); | 25 | const CodeSignature = @import("MachO/CodeSignature.zig"); |
| 26 | const Parser = @import("MachO/Parser.zig"); | 26 | const Parser = @import("MachO/Parser.zig"); |
| 27 | | 27 | |
| 28 | pub const base_tag: File.Tag = File.Tag.macho; | 28 | usingnamespace @import("MachO/commands.zig"); |
| 29 | | | |
| 30 | const LoadCommand = union(enum) { | | |
| 31 | Segment: macho.segment_command_64, | | |
| 32 | LinkeditData: macho.linkedit_data_command, | | |
| 33 | Symtab: macho.symtab_command, | | |
| 34 | Dysymtab: macho.dysymtab_command, | | |
| 35 | DyldInfo: macho.dyld_info_command, | | |
| 36 | Dylinker: macho.dylinker_command, | | |
| 37 | Dylib: macho.dylib_command, | | |
| 38 | EntryPoint: macho.entry_point_command, | | |
| 39 | MinVersion: macho.version_min_command, | | |
| 40 | SourceVersion: macho.source_version_command, | | |
| 41 | | | |
| 42 | pub fn cmdsize(self: LoadCommand) u32 { | | |
| 43 | return switch (self) { | | |
| 44 | .Segment => |x| x.cmdsize, | | |
| 45 | .LinkeditData => |x| x.cmdsize, | | |
| 46 | .Symtab => |x| x.cmdsize, | | |
| 47 | .Dysymtab => |x| x.cmdsize, | | |
| 48 | .DyldInfo => |x| x.cmdsize, | | |
| 49 | .Dylinker => |x| x.cmdsize, | | |
| 50 | .Dylib => |x| x.cmdsize, | | |
| 51 | .EntryPoint => |x| x.cmdsize, | | |
| 52 | .MinVersion => |x| x.cmdsize, | | |
| 53 | .SourceVersion => |x| x.cmdsize, | | |
| 54 | }; | | |
| 55 | } | | |
| 56 | | | |
| 57 | pub fn write(self: LoadCommand, file: *fs.File, offset: u64) !void { | | |
| 58 | return switch (self) { | | |
| 59 | .Segment => |cmd| writeGeneric(cmd, file, offset), | | |
| 60 | .LinkeditData => |cmd| writeGeneric(cmd, file, offset), | | |
| 61 | .Symtab => |cmd| writeGeneric(cmd, file, offset), | | |
| 62 | .Dysymtab => |cmd| writeGeneric(cmd, file, offset), | | |
| 63 | .DyldInfo => |cmd| writeGeneric(cmd, file, offset), | | |
| 64 | .Dylinker => |cmd| writeGeneric(cmd, file, offset), | | |
| 65 | .Dylib => |cmd| writeGeneric(cmd, file, offset), | | |
| 66 | .EntryPoint => |cmd| writeGeneric(cmd, file, offset), | | |
| 67 | .MinVersion => |cmd| writeGeneric(cmd, file, offset), | | |
| 68 | .SourceVersion => |cmd| writeGeneric(cmd, file, offset), | | |
| 69 | }; | | |
| 70 | } | | |
| 71 | | 29 | |
| 72 | fn writeGeneric(cmd: anytype, file: *fs.File, offset: u64) !void { | 30 | pub const base_tag: File.Tag = File.Tag.macho; |
| 73 | const slice = [1]@TypeOf(cmd){cmd}; | | |
| 74 | return file.pwriteAll(mem.sliceAsBytes(slice[0..1]), offset); | | |
| 75 | } | | |
| 76 | }; | | |
| 77 | | 31 | |
| 78 | base: File, | 32 | base: File, |
| 79 | | 33 | |
| ... | @@ -116,18 +70,14 @@ source_version_cmd_index: ?u16 = null, | ... | @@ -116,18 +70,14 @@ source_version_cmd_index: ?u16 = null, |
| 116 | /// Code signature | 70 | /// Code signature |
| 117 | code_signature_cmd_index: ?u16 = null, | 71 | code_signature_cmd_index: ?u16 = null, |
| 118 | | 72 | |
| 119 | /// Table of all sections | 73 | /// Index into __TEXT,__text section. |
| 120 | sections: std.ArrayListUnmanaged(macho.section_64) = .{}, | | |
| 121 | | | |
| 122 | /// __TEXT,__text section | | |
| 123 | text_section_index: ?u16 = null, | 74 | text_section_index: ?u16 = null, |
| 124 | | 75 | /// Index into __TEXT,__got section. |
| 125 | /// __DATA,__got section | | |
| 126 | got_section_index: ?u16 = null, | 76 | got_section_index: ?u16 = null, |
| 127 | | 77 | /// The absolute address of the entry point. |
| 128 | entry_addr: ?u64 = null, | 78 | entry_addr: ?u64 = null, |
| 129 | | 79 | |
| 130 | // TODO move this into each Segment aggregator | 80 | /// TODO move this into each Segment aggregator |
| 131 | linkedit_segment_next_offset: ?u32 = null, | 81 | linkedit_segment_next_offset: ?u32 = null, |
| 132 | | 82 | |
| 133 | /// Table of all local symbols | 83 | /// Table of all local symbols |
| ... | @@ -356,40 +306,12 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { | ... | @@ -356,40 +306,12 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { |
| 356 | if (self.entry_addr) |addr| { | 306 | if (self.entry_addr) |addr| { |
| 357 | // Update LC_MAIN with entry offset. | 307 | // Update LC_MAIN with entry offset. |
| 358 | const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment; | 308 | const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 359 | const main_cmd = &self.load_commands.items[self.main_cmd_index.?].EntryPoint; | 309 | const main_cmd = &self.load_commands.items[self.main_cmd_index.?].Main; |
| 360 | main_cmd.entryoff = addr - text_segment.vmaddr; | 310 | main_cmd.entryoff = addr - text_segment.inner.vmaddr; |
| 361 | } | | |
| 362 | if (self.dylinker_cmd_dirty) { | | |
| 363 | // Write path to dyld loader. | | |
| 364 | var off: usize = @sizeOf(macho.mach_header_64); | | |
| 365 | for (self.load_commands.items) |cmd| { | | |
| 366 | if (cmd == .Dylinker) break; | | |
| 367 | off += cmd.cmdsize(); | | |
| 368 | } | | |
| 369 | const cmd = &self.load_commands.items[self.dylinker_cmd_index.?].Dylinker; | | |
| 370 | off += cmd.name; | | |
| 371 | log.debug("writing LC_LOAD_DYLINKER path to dyld at 0x{x}\n", .{off}); | | |
| 372 | try self.base.file.?.pwriteAll(mem.spanZ(DEFAULT_DYLD_PATH), off); | | |
| 373 | self.dylinker_cmd_dirty = false; | | |
| 374 | } | 311 | } |
| 375 | if (self.libsystem_cmd_dirty) { | | |
| 376 | // Write path to libSystem. | | |
| 377 | var off: usize = @sizeOf(macho.mach_header_64); | | |
| 378 | for (self.load_commands.items) |cmd| { | | |
| 379 | if (cmd == .Dylib) break; | | |
| 380 | off += cmd.cmdsize(); | | |
| 381 | } | | |
| 382 | const cmd = &self.load_commands.items[self.libsystem_cmd_index.?].Dylib; | | |
| 383 | off += cmd.dylib.name; | | |
| 384 | log.debug("writing LC_LOAD_DYLIB path to libSystem at 0x{x}\n", .{off}); | | |
| 385 | try self.base.file.?.pwriteAll(mem.spanZ(LIB_SYSTEM_PATH), off); | | |
| 386 | self.libsystem_cmd_dirty = false; | | |
| 387 | } | | |
| 388 | | | |
| 389 | try self.writeExportTrie(); | 312 | try self.writeExportTrie(); |
| 390 | try self.writeSymbolTable(); | 313 | try self.writeSymbolTable(); |
| 391 | try self.writeStringTable(); | 314 | try self.writeStringTable(); |
| 392 | | | |
| 393 | // Preallocate space for the code signature. | 315 | // Preallocate space for the code signature. |
| 394 | // We need to do this at this stage so that we have the load commands with proper values | 316 | // We need to do this at this stage so that we have the load commands with proper values |
| 395 | // written out to the file. | 317 | // written out to the file. |
| ... | @@ -402,7 +324,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { | ... | @@ -402,7 +324,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { |
| 402 | } | 324 | } |
| 403 | | 325 | |
| 404 | if (self.cmd_table_dirty) { | 326 | if (self.cmd_table_dirty) { |
| 405 | try self.writeCmdHeaders(); | 327 | try self.writeLoadCommands(); |
| 406 | try self.writeMachOHeader(); | 328 | try self.writeMachOHeader(); |
| 407 | self.cmd_table_dirty = false; | 329 | self.cmd_table_dirty = false; |
| 408 | } | 330 | } |
| ... | @@ -416,8 +338,6 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { | ... | @@ -416,8 +338,6 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { |
| 416 | } | 338 | } |
| 417 | | 339 | |
| 418 | assert(!self.cmd_table_dirty); | 340 | assert(!self.cmd_table_dirty); |
| 419 | assert(!self.dylinker_cmd_dirty); | | |
| 420 | assert(!self.libsystem_cmd_dirty); | | |
| 421 | | 341 | |
| 422 | switch (self.base.options.output_mode) { | 342 | switch (self.base.options.output_mode) { |
| 423 | .Exe, .Lib => try self.writeCodeSignature(), // code signing always comes last | 343 | .Exe, .Lib => try self.writeCodeSignature(), // code signing always comes last |
| ... | @@ -921,7 +841,9 @@ pub fn deinit(self: *MachO) void { | ... | @@ -921,7 +841,9 @@ pub fn deinit(self: *MachO) void { |
| 921 | self.global_symbol_free_list.deinit(self.base.allocator); | 841 | self.global_symbol_free_list.deinit(self.base.allocator); |
| 922 | self.local_symbols.deinit(self.base.allocator); | 842 | self.local_symbols.deinit(self.base.allocator); |
| 923 | self.local_symbol_free_list.deinit(self.base.allocator); | 843 | self.local_symbol_free_list.deinit(self.base.allocator); |
| 924 | self.sections.deinit(self.base.allocator); | 844 | for (self.load_commands.items) |*lc| { |
| | 845 | lc.deinit(self.base.allocator); |
| | 846 | } |
| 925 | self.load_commands.deinit(self.base.allocator); | 847 | self.load_commands.deinit(self.base.allocator); |
| 926 | } | 848 | } |
| 927 | | 849 | |
| ... | @@ -1075,7 +997,8 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { | ... | @@ -1075,7 +997,8 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { |
| 1075 | } | 997 | } |
| 1076 | | 998 | |
| 1077 | // Perform PIE fixups (if any) | 999 | // Perform PIE fixups (if any) |
| 1078 | const got_section = self.sections.items[self.got_section_index.?]; | 1000 | const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| | 1001 | const got_section = text_segment.sections.items[self.got_section_index.?]; |
| 1079 | while (self.pie_fixups.popOrNull()) |fixup| { | 1002 | while (self.pie_fixups.popOrNull()) |fixup| { |
| 1080 | const target_addr = fixup.address; | 1003 | const target_addr = fixup.address; |
| 1081 | const this_addr = symbol.n_value + fixup.start; | 1004 | const this_addr = symbol.n_value + fixup.start; |
| ... | @@ -1094,7 +1017,7 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { | ... | @@ -1094,7 +1017,7 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { |
| 1094 | } | 1017 | } |
| 1095 | } | 1018 | } |
| 1096 | | 1019 | |
| 1097 | const text_section = self.sections.items[self.text_section_index.?]; | 1020 | const text_section = text_segment.sections.items[self.text_section_index.?]; |
| 1098 | const section_offset = symbol.n_value - text_section.addr; | 1021 | const section_offset = symbol.n_value - text_section.addr; |
| 1099 | const file_offset = text_section.offset + section_offset; | 1022 | const file_offset = text_section.offset + section_offset; |
| 1100 | try self.base.file.?.pwriteAll(code, file_offset); | 1023 | try self.base.file.?.pwriteAll(code, file_offset); |
| ... | @@ -1212,7 +1135,7 @@ pub fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -1212,7 +1135,7 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1212 | if (self.pagezero_segment_cmd_index == null) { | 1135 | if (self.pagezero_segment_cmd_index == null) { |
| 1213 | self.pagezero_segment_cmd_index = @intCast(u16, self.load_commands.items.len); | 1136 | self.pagezero_segment_cmd_index = @intCast(u16, self.load_commands.items.len); |
| 1214 | try self.load_commands.append(self.base.allocator, .{ | 1137 | try self.load_commands.append(self.base.allocator, .{ |
| 1215 | .Segment = .{ | 1138 | .Segment = SegmentCommand.empty(.{ |
| 1216 | .cmd = macho.LC_SEGMENT_64, | 1139 | .cmd = macho.LC_SEGMENT_64, |
| 1217 | .cmdsize = @sizeOf(macho.segment_command_64), | 1140 | .cmdsize = @sizeOf(macho.segment_command_64), |
| 1218 | .segname = makeStaticString("__PAGEZERO"), | 1141 | .segname = makeStaticString("__PAGEZERO"), |
| ... | @@ -1224,7 +1147,7 @@ pub fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -1224,7 +1147,7 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1224 | .initprot = 0, | 1147 | .initprot = 0, |
| 1225 | .nsects = 0, | 1148 | .nsects = 0, |
| 1226 | .flags = 0, | 1149 | .flags = 0, |
| 1227 | }, | 1150 | }), |
| 1228 | }); | 1151 | }); |
| 1229 | self.cmd_table_dirty = true; | 1152 | self.cmd_table_dirty = true; |
| 1230 | } | 1153 | } |
| ... | @@ -1233,7 +1156,7 @@ pub fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -1233,7 +1156,7 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1233 | const maxprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE | macho.VM_PROT_EXECUTE; | 1156 | const maxprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE | macho.VM_PROT_EXECUTE; |
| 1234 | const initprot = macho.VM_PROT_READ | macho.VM_PROT_EXECUTE; | 1157 | const initprot = macho.VM_PROT_READ | macho.VM_PROT_EXECUTE; |
| 1235 | try self.load_commands.append(self.base.allocator, .{ | 1158 | try self.load_commands.append(self.base.allocator, .{ |
| 1236 | .Segment = .{ | 1159 | .Segment = SegmentCommand.empty(.{ |
| 1237 | .cmd = macho.LC_SEGMENT_64, | 1160 | .cmd = macho.LC_SEGMENT_64, |
| 1238 | .cmdsize = @sizeOf(macho.segment_command_64), | 1161 | .cmdsize = @sizeOf(macho.segment_command_64), |
| 1239 | .segname = makeStaticString("__TEXT"), | 1162 | .segname = makeStaticString("__TEXT"), |
| ... | @@ -1245,45 +1168,45 @@ pub fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -1245,45 +1168,45 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1245 | .initprot = initprot, | 1168 | .initprot = initprot, |
| 1246 | .nsects = 0, | 1169 | .nsects = 0, |
| 1247 | .flags = 0, | 1170 | .flags = 0, |
| 1248 | }, | 1171 | }), |
| 1249 | }); | 1172 | }); |
| 1250 | self.cmd_table_dirty = true; | 1173 | self.cmd_table_dirty = true; |
| 1251 | } | 1174 | } |
| 1252 | if (self.text_section_index == null) { | 1175 | if (self.text_section_index == null) { |
| 1253 | self.text_section_index = @intCast(u16, self.sections.items.len); | | |
| 1254 | const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; | 1176 | const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| | 1177 | self.text_section_index = @intCast(u16, text_segment.sections.items.len); |
| 1255 | | 1178 | |
| 1256 | const program_code_size_hint = self.base.options.program_code_size_hint; | 1179 | const program_code_size_hint = self.base.options.program_code_size_hint; |
| 1257 | const file_size = mem.alignForwardGeneric(u64, program_code_size_hint, self.page_size); | 1180 | const file_size = mem.alignForwardGeneric(u64, program_code_size_hint, self.page_size); |
| 1258 | const off = @intCast(u32, self.findFreeSpace(file_size, self.page_size)); // TODO maybe findFreeSpace should return u32 directly? | 1181 | const off = @intCast(u32, self.findFreeSpace(file_size, self.page_size)); // TODO maybe findFreeSpace should return u32 directly? |
| 1259 | const flags = macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS; | | |
| 1260 | | 1182 | |
| 1261 | log.debug("found __text section free space 0x{x} to 0x{x}\n", .{ off, off + file_size }); | 1183 | log.debug("found __text section free space 0x{x} to 0x{x}\n", .{ off, off + file_size }); |
| 1262 | | 1184 | |
| 1263 | try self.sections.append(self.base.allocator, .{ | 1185 | try text_segment.sections.append(self.base.allocator, .{ |
| 1264 | .sectname = makeStaticString("__text"), | 1186 | .sectname = makeStaticString("__text"), |
| 1265 | .segname = makeStaticString("__TEXT"), | 1187 | .segname = makeStaticString("__TEXT"), |
| 1266 | .addr = text_segment.vmaddr + off, | 1188 | .addr = text_segment.inner.vmaddr + off, |
| 1267 | .size = file_size, | 1189 | .size = file_size, |
| 1268 | .offset = off, | 1190 | .offset = off, |
| 1269 | .@"align" = if (self.base.options.target.cpu.arch == .aarch64) 2 else 0, // 2^2 for aarch64, 2^0 for x86_64 | 1191 | .@"align" = if (self.base.options.target.cpu.arch == .aarch64) 2 else 0, // 2^2 for aarch64, 2^0 for x86_64 |
| 1270 | .reloff = 0, | 1192 | .reloff = 0, |
| 1271 | .nreloc = 0, | 1193 | .nreloc = 0, |
| 1272 | .flags = flags, | 1194 | .flags = macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS, |
| 1273 | .reserved1 = 0, | 1195 | .reserved1 = 0, |
| 1274 | .reserved2 = 0, | 1196 | .reserved2 = 0, |
| 1275 | .reserved3 = 0, | 1197 | .reserved3 = 0, |
| 1276 | }); | 1198 | }); |
| 1277 | | 1199 | |
| 1278 | text_segment.vmsize = file_size + off; // We add off here since __TEXT segment includes everything prior to __text section. | 1200 | text_segment.inner.vmsize = file_size + off; // We add off here since __TEXT segment includes everything prior to __text section. |
| 1279 | text_segment.filesize = file_size + off; | 1201 | text_segment.inner.filesize = file_size + off; |
| 1280 | text_segment.cmdsize += @sizeOf(macho.section_64); | 1202 | text_segment.inner.cmdsize += @sizeOf(macho.section_64); |
| 1281 | text_segment.nsects += 1; | 1203 | text_segment.inner.nsects += 1; |
| 1282 | self.cmd_table_dirty = true; | 1204 | self.cmd_table_dirty = true; |
| 1283 | } | 1205 | } |
| 1284 | if (self.got_section_index == null) { | 1206 | if (self.got_section_index == null) { |
| 1285 | self.got_section_index = @intCast(u16, self.sections.items.len); | 1207 | const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 1286 | const text_section = &self.sections.items[self.text_section_index.?]; | 1208 | const text_section = &text_segment.sections.items[self.text_section_index.?]; |
| | 1209 | self.got_section_index = @intCast(u16, text_segment.sections.items.len); |
| 1287 | | 1210 | |
| 1288 | const file_size = @sizeOf(u64) * self.base.options.symbol_count_hint; | 1211 | const file_size = @sizeOf(u64) * self.base.options.symbol_count_hint; |
| 1289 | // TODO looking for free space should be done *within* a segment it belongs to | 1212 | // TODO looking for free space should be done *within* a segment it belongs to |
| ... | @@ -1291,7 +1214,7 @@ pub fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -1291,7 +1214,7 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1291 | | 1214 | |
| 1292 | log.debug("found __got section free space 0x{x} to 0x{x}\n", .{ off, off + file_size }); | 1215 | log.debug("found __got section free space 0x{x} to 0x{x}\n", .{ off, off + file_size }); |
| 1293 | | 1216 | |
| 1294 | try self.sections.append(self.base.allocator, .{ | 1217 | try text_segment.sections.append(self.base.allocator, .{ |
| 1295 | .sectname = makeStaticString("__got"), | 1218 | .sectname = makeStaticString("__got"), |
| 1296 | .segname = makeStaticString("__TEXT"), | 1219 | .segname = makeStaticString("__TEXT"), |
| 1297 | .addr = text_section.addr + text_section.size, | 1220 | .addr = text_section.addr + text_section.size, |
| ... | @@ -1300,18 +1223,17 @@ pub fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -1300,18 +1223,17 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1300 | .@"align" = if (self.base.options.target.cpu.arch == .aarch64) 2 else 0, | 1223 | .@"align" = if (self.base.options.target.cpu.arch == .aarch64) 2 else 0, |
| 1301 | .reloff = 0, | 1224 | .reloff = 0, |
| 1302 | .nreloc = 0, | 1225 | .nreloc = 0, |
| 1303 | .flags = macho.S_REGULAR, | 1226 | .flags = macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS, |
| 1304 | .reserved1 = 0, | 1227 | .reserved1 = 0, |
| 1305 | .reserved2 = 0, | 1228 | .reserved2 = 0, |
| 1306 | .reserved3 = 0, | 1229 | .reserved3 = 0, |
| 1307 | }); | 1230 | }); |
| 1308 | | 1231 | |
| 1309 | const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; | | |
| 1310 | const added_size = mem.alignForwardGeneric(u64, file_size, self.page_size); | 1232 | const added_size = mem.alignForwardGeneric(u64, file_size, self.page_size); |
| 1311 | text_segment.vmsize += added_size; | 1233 | text_segment.inner.vmsize += added_size; |
| 1312 | text_segment.filesize += added_size; | 1234 | text_segment.inner.filesize += added_size; |
| 1313 | text_segment.cmdsize += @sizeOf(macho.section_64); | 1235 | text_segment.inner.cmdsize += @sizeOf(macho.section_64); |
| 1314 | text_segment.nsects += 1; | 1236 | text_segment.inner.nsects += 1; |
| 1315 | self.cmd_table_dirty = true; | 1237 | self.cmd_table_dirty = true; |
| 1316 | } | 1238 | } |
| 1317 | if (self.linkedit_segment_cmd_index == null) { | 1239 | if (self.linkedit_segment_cmd_index == null) { |
| ... | @@ -1319,13 +1241,13 @@ pub fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -1319,13 +1241,13 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1319 | const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; | 1241 | const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 1320 | const maxprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE | macho.VM_PROT_EXECUTE; | 1242 | const maxprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE | macho.VM_PROT_EXECUTE; |
| 1321 | const initprot = macho.VM_PROT_READ; | 1243 | const initprot = macho.VM_PROT_READ; |
| 1322 | const off = text_segment.fileoff + text_segment.filesize; | 1244 | const off = text_segment.inner.fileoff + text_segment.inner.filesize; |
| 1323 | try self.load_commands.append(self.base.allocator, .{ | 1245 | try self.load_commands.append(self.base.allocator, .{ |
| 1324 | .Segment = .{ | 1246 | .Segment = SegmentCommand.empty(.{ |
| 1325 | .cmd = macho.LC_SEGMENT_64, | 1247 | .cmd = macho.LC_SEGMENT_64, |
| 1326 | .cmdsize = @sizeOf(macho.segment_command_64), | 1248 | .cmdsize = @sizeOf(macho.segment_command_64), |
| 1327 | .segname = makeStaticString("__LINKEDIT"), | 1249 | .segname = makeStaticString("__LINKEDIT"), |
| 1328 | .vmaddr = text_segment.vmaddr + text_segment.vmsize, | 1250 | .vmaddr = text_segment.inner.vmaddr + text_segment.inner.vmsize, |
| 1329 | .vmsize = 0, | 1251 | .vmsize = 0, |
| 1330 | .fileoff = off, | 1252 | .fileoff = off, |
| 1331 | .filesize = 0, | 1253 | .filesize = 0, |
| ... | @@ -1333,7 +1255,7 @@ pub fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -1333,7 +1255,7 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1333 | .initprot = initprot, | 1255 | .initprot = initprot, |
| 1334 | .nsects = 0, | 1256 | .nsects = 0, |
| 1335 | .flags = 0, | 1257 | .flags = 0, |
| 1336 | }, | 1258 | }), |
| 1337 | }); | 1259 | }); |
| 1338 | self.linkedit_segment_next_offset = @intCast(u32, off); | 1260 | self.linkedit_segment_next_offset = @intCast(u32, off); |
| 1339 | self.cmd_table_dirty = true; | 1261 | self.cmd_table_dirty = true; |
| ... | @@ -1341,7 +1263,7 @@ pub fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -1341,7 +1263,7 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1341 | if (self.dyld_info_cmd_index == null) { | 1263 | if (self.dyld_info_cmd_index == null) { |
| 1342 | self.dyld_info_cmd_index = @intCast(u16, self.load_commands.items.len); | 1264 | self.dyld_info_cmd_index = @intCast(u16, self.load_commands.items.len); |
| 1343 | try self.load_commands.append(self.base.allocator, .{ | 1265 | try self.load_commands.append(self.base.allocator, .{ |
| 1344 | .DyldInfo = .{ | 1266 | .DyldInfoOnly = .{ |
| 1345 | .cmd = macho.LC_DYLD_INFO_ONLY, | 1267 | .cmd = macho.LC_DYLD_INFO_ONLY, |
| 1346 | .cmdsize = @sizeOf(macho.dyld_info_command), | 1268 | .cmdsize = @sizeOf(macho.dyld_info_command), |
| 1347 | .rebase_off = 0, | 1269 | .rebase_off = 0, |
| ... | @@ -1403,15 +1325,16 @@ pub fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -1403,15 +1325,16 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1403 | if (self.dylinker_cmd_index == null) { | 1325 | if (self.dylinker_cmd_index == null) { |
| 1404 | self.dylinker_cmd_index = @intCast(u16, self.load_commands.items.len); | 1326 | self.dylinker_cmd_index = @intCast(u16, self.load_commands.items.len); |
| 1405 | const cmdsize = mem.alignForwardGeneric(u64, @sizeOf(macho.dylinker_command) + mem.lenZ(DEFAULT_DYLD_PATH), @sizeOf(u64)); | 1327 | const cmdsize = mem.alignForwardGeneric(u64, @sizeOf(macho.dylinker_command) + mem.lenZ(DEFAULT_DYLD_PATH), @sizeOf(u64)); |
| 1406 | try self.load_commands.append(self.base.allocator, .{ | 1328 | var dylinker_cmd = emptyGenericCommandWithData(macho.dylinker_command{ |
| 1407 | .Dylinker = .{ | 1329 | .cmd = macho.LC_LOAD_DYLINKER, |
| 1408 | .cmd = macho.LC_LOAD_DYLINKER, | 1330 | .cmdsize = @intCast(u32, cmdsize), |
| 1409 | .cmdsize = @intCast(u32, cmdsize), | 1331 | .name = @sizeOf(macho.dylinker_command), |
| 1410 | .name = @sizeOf(macho.dylinker_command), | | |
| 1411 | }, | | |
| 1412 | }); | 1332 | }); |
| | 1333 | dylinker_cmd.data = try self.base.allocator.alloc(u8, cmdsize - dylinker_cmd.inner.name); |
| | 1334 | mem.set(u8, dylinker_cmd.data, 0); |
| | 1335 | mem.copy(u8, dylinker_cmd.data, mem.spanZ(DEFAULT_DYLD_PATH)); |
| | 1336 | try self.load_commands.append(self.base.allocator, .{ .Dylinker = dylinker_cmd }); |
| 1413 | self.cmd_table_dirty = true; | 1337 | self.cmd_table_dirty = true; |
| 1414 | self.dylinker_cmd_dirty = true; | | |
| 1415 | } | 1338 | } |
| 1416 | if (self.libsystem_cmd_index == null) { | 1339 | if (self.libsystem_cmd_index == null) { |
| 1417 | self.libsystem_cmd_index = @intCast(u16, self.load_commands.items.len); | 1340 | self.libsystem_cmd_index = @intCast(u16, self.load_commands.items.len); |
| ... | @@ -1419,26 +1342,26 @@ pub fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -1419,26 +1342,26 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1419 | // TODO Find a way to work out runtime version from the OS version triple stored in std.Target. | 1342 | // TODO Find a way to work out runtime version from the OS version triple stored in std.Target. |
| 1420 | // In the meantime, we're gonna hardcode to the minimum compatibility version of 0.0.0. | 1343 | // In the meantime, we're gonna hardcode to the minimum compatibility version of 0.0.0. |
| 1421 | const min_version = 0x0; | 1344 | const min_version = 0x0; |
| 1422 | const dylib = .{ | 1345 | var dylib_cmd = emptyGenericCommandWithData(macho.dylib_command{ |
| 1423 | .name = @sizeOf(macho.dylib_command), | 1346 | .cmd = macho.LC_LOAD_DYLIB, |
| 1424 | .timestamp = 2, // not sure why not simply 0; this is reverse engineered from Mach-O files | 1347 | .cmdsize = @intCast(u32, cmdsize), |
| 1425 | .current_version = min_version, | 1348 | .dylib = .{ |
| 1426 | .compatibility_version = min_version, | 1349 | .name = @sizeOf(macho.dylib_command), |
| 1427 | }; | 1350 | .timestamp = 2, // not sure why not simply 0; this is reverse engineered from Mach-O files |
| 1428 | try self.load_commands.append(self.base.allocator, .{ | 1351 | .current_version = min_version, |
| 1429 | .Dylib = .{ | 1352 | .compatibility_version = min_version, |
| 1430 | .cmd = macho.LC_LOAD_DYLIB, | | |
| 1431 | .cmdsize = @intCast(u32, cmdsize), | | |
| 1432 | .dylib = dylib, | | |
| 1433 | }, | 1353 | }, |
| 1434 | }); | 1354 | }); |
| | 1355 | dylib_cmd.data = try self.base.allocator.alloc(u8, cmdsize - dylib_cmd.inner.dylib.name); |
| | 1356 | mem.set(u8, dylib_cmd.data, 0); |
| | 1357 | mem.copy(u8, dylib_cmd.data, mem.spanZ(LIB_SYSTEM_PATH)); |
| | 1358 | try self.load_commands.append(self.base.allocator, .{ .Dylib = dylib_cmd }); |
| 1435 | self.cmd_table_dirty = true; | 1359 | self.cmd_table_dirty = true; |
| 1436 | self.libsystem_cmd_dirty = true; | | |
| 1437 | } | 1360 | } |
| 1438 | if (self.main_cmd_index == null) { | 1361 | if (self.main_cmd_index == null) { |
| 1439 | self.main_cmd_index = @intCast(u16, self.load_commands.items.len); | 1362 | self.main_cmd_index = @intCast(u16, self.load_commands.items.len); |
| 1440 | try self.load_commands.append(self.base.allocator, .{ | 1363 | try self.load_commands.append(self.base.allocator, .{ |
| 1441 | .EntryPoint = .{ | 1364 | .Main = .{ |
| 1442 | .cmd = macho.LC_MAIN, | 1365 | .cmd = macho.LC_MAIN, |
| 1443 | .cmdsize = @sizeOf(macho.entry_point_command), | 1366 | .cmdsize = @sizeOf(macho.entry_point_command), |
| 1444 | .entryoff = 0x0, | 1367 | .entryoff = 0x0, |
| ... | @@ -1459,7 +1382,7 @@ pub fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -1459,7 +1382,7 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1459 | const ver = self.base.options.target.os.version_range.semver.min; | 1382 | const ver = self.base.options.target.os.version_range.semver.min; |
| 1460 | const version = ver.major << 16 | ver.minor << 8 | ver.patch; | 1383 | const version = ver.major << 16 | ver.minor << 8 | ver.patch; |
| 1461 | try self.load_commands.append(self.base.allocator, .{ | 1384 | try self.load_commands.append(self.base.allocator, .{ |
| 1462 | .MinVersion = .{ | 1385 | .VersionMin = .{ |
| 1463 | .cmd = cmd, | 1386 | .cmd = cmd, |
| 1464 | .cmdsize = @sizeOf(macho.version_min_command), | 1387 | .cmdsize = @sizeOf(macho.version_min_command), |
| 1465 | .version = version, | 1388 | .version = version, |
| ... | @@ -1502,7 +1425,8 @@ pub fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -1502,7 +1425,8 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1502 | } | 1425 | } |
| 1503 | | 1426 | |
| 1504 | fn allocateTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64, alignment: u64) !u64 { | 1427 | fn allocateTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64, alignment: u64) !u64 { |
| 1505 | const text_section = &self.sections.items[self.text_section_index.?]; | 1428 | const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| | 1429 | const text_section = &text_segment.sections.items[self.text_section_index.?]; |
| 1506 | const new_block_ideal_capacity = new_block_size * alloc_num / alloc_den; | 1430 | const new_block_ideal_capacity = new_block_size * alloc_num / alloc_den; |
| 1507 | | 1431 | |
| 1508 | // We use these to indicate our intention to update metadata, placing the new block, | 1432 | // We use these to indicate our intention to update metadata, placing the new block, |
| ... | @@ -1644,15 +1568,18 @@ fn detectAllocCollision(self: *MachO, start: u64, size: u64) ?u64 { | ... | @@ -1644,15 +1568,18 @@ fn detectAllocCollision(self: *MachO, start: u64, size: u64) ?u64 { |
| 1644 | return test_end; | 1568 | return test_end; |
| 1645 | } | 1569 | } |
| 1646 | } | 1570 | } |
| 1647 | for (self.sections.items) |section| { | 1571 | if (self.text_segment_cmd_index) |text_index| { |
| 1648 | const increased_size = satMul(section.size, alloc_num) / alloc_den; | 1572 | const text_segment = self.load_commands.items[text_index].Segment; |
| 1649 | const test_end = section.offset + increased_size; | 1573 | for (text_segment.sections.items) |section| { |
| 1650 | if (end > section.offset and start < test_end) { | 1574 | const increased_size = satMul(section.size, alloc_num) / alloc_den; |
| 1651 | return test_end; | 1575 | const test_end = section.offset + increased_size; |
| | 1576 | if (end > section.offset and start < test_end) { |
| | 1577 | return test_end; |
| | 1578 | } |
| 1652 | } | 1579 | } |
| 1653 | } | 1580 | } |
| 1654 | if (self.dyld_info_cmd_index) |dyld_info_index| { | 1581 | if (self.dyld_info_cmd_index) |dyld_info_index| { |
| 1655 | const dyld_info = self.load_commands.items[dyld_info_index].DyldInfo; | 1582 | const dyld_info = self.load_commands.items[dyld_info_index].DyldInfoOnly; |
| 1656 | const tight_size = dyld_info.export_size; | 1583 | const tight_size = dyld_info.export_size; |
| 1657 | const increased_size = satMul(tight_size, alloc_num) / alloc_den; | 1584 | const increased_size = satMul(tight_size, alloc_num) / alloc_den; |
| 1658 | const test_end = dyld_info.export_off + increased_size; | 1585 | const test_end = dyld_info.export_off + increased_size; |
| ... | @@ -1689,12 +1616,15 @@ fn allocatedSize(self: *MachO, start: u64) u64 { | ... | @@ -1689,12 +1616,15 @@ fn allocatedSize(self: *MachO, start: u64) u64 { |
| 1689 | const off = @sizeOf(macho.mach_header_64); | 1616 | const off = @sizeOf(macho.mach_header_64); |
| 1690 | if (off > start and off < min_pos) min_pos = off; | 1617 | if (off > start and off < min_pos) min_pos = off; |
| 1691 | } | 1618 | } |
| 1692 | for (self.sections.items) |section| { | 1619 | if (self.text_segment_cmd_index) |text_index| { |
| 1693 | if (section.offset <= start) continue; | 1620 | const text_segment = self.load_commands.items[text_index].Segment; |
| 1694 | if (section.offset < min_pos) min_pos = section.offset; | 1621 | for (text_segment.sections.items) |section| { |
| | 1622 | if (section.offset <= start) continue; |
| | 1623 | if (section.offset < min_pos) min_pos = section.offset; |
| | 1624 | } |
| 1695 | } | 1625 | } |
| 1696 | if (self.dyld_info_cmd_index) |dyld_info_index| { | 1626 | if (self.dyld_info_cmd_index) |dyld_info_index| { |
| 1697 | const dyld_info = self.load_commands.items[dyld_info_index].DyldInfo; | 1627 | const dyld_info = self.load_commands.items[dyld_info_index].DyldInfoOnly; |
| 1698 | if (dyld_info.export_off > start and dyld_info.export_off < min_pos) min_pos = dyld_info.export_off; | 1628 | if (dyld_info.export_off > start and dyld_info.export_off < min_pos) min_pos = dyld_info.export_off; |
| 1699 | } | 1629 | } |
| 1700 | if (self.symtab_cmd_index) |symtab_index| { | 1630 | if (self.symtab_cmd_index) |symtab_index| { |
| ... | @@ -1714,7 +1644,8 @@ fn findFreeSpace(self: *MachO, object_size: u64, min_alignment: u16) u64 { | ... | @@ -1714,7 +1644,8 @@ fn findFreeSpace(self: *MachO, object_size: u64, min_alignment: u16) u64 { |
| 1714 | } | 1644 | } |
| 1715 | | 1645 | |
| 1716 | fn writeOffsetTableEntry(self: *MachO, index: usize) !void { | 1646 | fn writeOffsetTableEntry(self: *MachO, index: usize) !void { |
| 1717 | const sect = &self.sections.items[self.got_section_index.?]; | 1647 | const text_semgent = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| | 1648 | const sect = &text_semgent.sections.items[self.got_section_index.?]; |
| 1718 | const off = sect.offset + @sizeOf(u64) * index; | 1649 | const off = sect.offset + @sizeOf(u64) * index; |
| 1719 | const vmaddr = sect.addr + @sizeOf(u64) * index; | 1650 | const vmaddr = sect.addr + @sizeOf(u64) * index; |
| 1720 | | 1651 | |
| ... | @@ -1782,9 +1713,9 @@ fn writeSymbolTable(self: *MachO) !void { | ... | @@ -1782,9 +1713,9 @@ fn writeSymbolTable(self: *MachO) !void { |
| 1782 | | 1713 | |
| 1783 | // Advance size of __LINKEDIT segment | 1714 | // Advance size of __LINKEDIT segment |
| 1784 | const linkedit = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; | 1715 | const linkedit = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; |
| 1785 | linkedit.filesize += symtab.nsyms * @sizeOf(macho.nlist_64); | 1716 | linkedit.inner.filesize += symtab.nsyms * @sizeOf(macho.nlist_64); |
| 1786 | if (linkedit.vmsize < linkedit.filesize) { | 1717 | if (linkedit.inner.vmsize < linkedit.inner.filesize) { |
| 1787 | linkedit.vmsize = mem.alignForwardGeneric(u64, linkedit.filesize, self.page_size); | 1718 | linkedit.inner.vmsize = mem.alignForwardGeneric(u64, linkedit.inner.filesize, self.page_size); |
| 1788 | } | 1719 | } |
| 1789 | self.cmd_table_dirty = true; | 1720 | self.cmd_table_dirty = true; |
| 1790 | } | 1721 | } |
| ... | @@ -1799,9 +1730,9 @@ fn writeCodeSignaturePadding(self: *MachO) !void { | ... | @@ -1799,9 +1730,9 @@ fn writeCodeSignaturePadding(self: *MachO) !void { |
| 1799 | self.linkedit_segment_next_offset = fileoff + datasize; | 1730 | self.linkedit_segment_next_offset = fileoff + datasize; |
| 1800 | // Advance size of __LINKEDIT segment | 1731 | // Advance size of __LINKEDIT segment |
| 1801 | const linkedit = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; | 1732 | const linkedit = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; |
| 1802 | linkedit.filesize += datasize; | 1733 | linkedit.inner.filesize += datasize; |
| 1803 | if (linkedit.vmsize < linkedit.filesize) { | 1734 | if (linkedit.inner.vmsize < linkedit.inner.filesize) { |
| 1804 | linkedit.vmsize = mem.alignForwardGeneric(u64, linkedit.filesize, self.page_size); | 1735 | linkedit.inner.vmsize = mem.alignForwardGeneric(u64, linkedit.inner.filesize, self.page_size); |
| 1805 | } | 1736 | } |
| 1806 | log.debug("writing code signature padding from 0x{x} to 0x{x}\n", .{ fileoff, fileoff + datasize }); | 1737 | log.debug("writing code signature padding from 0x{x} to 0x{x}\n", .{ fileoff, fileoff + datasize }); |
| 1807 | // Pad out the space. We need to do this to calculate valid hashes for everything in the file | 1738 | // Pad out the space. We need to do this to calculate valid hashes for everything in the file |
| ... | @@ -1836,10 +1767,10 @@ fn writeExportTrie(self: *MachO) !void { | ... | @@ -1836,10 +1767,10 @@ fn writeExportTrie(self: *MachO) !void { |
| 1836 | for (self.global_symbols.items) |symbol| { | 1767 | for (self.global_symbols.items) |symbol| { |
| 1837 | // TODO figure out if we should put all global symbols into the export trie | 1768 | // TODO figure out if we should put all global symbols into the export trie |
| 1838 | const name = self.getString(symbol.n_strx); | 1769 | const name = self.getString(symbol.n_strx); |
| 1839 | assert(symbol.n_value >= text_segment.vmaddr); | 1770 | assert(symbol.n_value >= text_segment.inner.vmaddr); |
| 1840 | try trie.put(self.base.allocator, .{ | 1771 | try trie.put(self.base.allocator, .{ |
| 1841 | .name = name, | 1772 | .name = name, |
| 1842 | .vmaddr_offset = symbol.n_value - text_segment.vmaddr, | 1773 | .vmaddr_offset = symbol.n_value - text_segment.inner.vmaddr, |
| 1843 | .export_flags = 0, // TODO workout creation of export flags | 1774 | .export_flags = 0, // TODO workout creation of export flags |
| 1844 | }); | 1775 | }); |
| 1845 | } | 1776 | } |
| ... | @@ -1849,7 +1780,7 @@ fn writeExportTrie(self: *MachO) !void { | ... | @@ -1849,7 +1780,7 @@ fn writeExportTrie(self: *MachO) !void { |
| 1849 | | 1780 | |
| 1850 | try trie.writeULEB128Mem(self.base.allocator, &buffer); | 1781 | try trie.writeULEB128Mem(self.base.allocator, &buffer); |
| 1851 | | 1782 | |
| 1852 | const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfo; | 1783 | const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly; |
| 1853 | const export_size = @intCast(u32, mem.alignForward(buffer.items.len, @sizeOf(u64))); | 1784 | const export_size = @intCast(u32, mem.alignForward(buffer.items.len, @sizeOf(u64))); |
| 1854 | dyld_info.export_off = self.linkedit_segment_next_offset.?; | 1785 | dyld_info.export_off = self.linkedit_segment_next_offset.?; |
| 1855 | dyld_info.export_size = export_size; | 1786 | dyld_info.export_size = export_size; |
| ... | @@ -1865,9 +1796,9 @@ fn writeExportTrie(self: *MachO) !void { | ... | @@ -1865,9 +1796,9 @@ fn writeExportTrie(self: *MachO) !void { |
| 1865 | self.linkedit_segment_next_offset = dyld_info.export_off + dyld_info.export_size; | 1796 | self.linkedit_segment_next_offset = dyld_info.export_off + dyld_info.export_size; |
| 1866 | // Advance size of __LINKEDIT segment | 1797 | // Advance size of __LINKEDIT segment |
| 1867 | const linkedit = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; | 1798 | const linkedit = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; |
| 1868 | linkedit.filesize += dyld_info.export_size; | 1799 | linkedit.inner.filesize += dyld_info.export_size; |
| 1869 | if (linkedit.vmsize < linkedit.filesize) { | 1800 | if (linkedit.inner.vmsize < linkedit.inner.filesize) { |
| 1870 | linkedit.vmsize = mem.alignForwardGeneric(u64, linkedit.filesize, self.page_size); | 1801 | linkedit.inner.vmsize = mem.alignForwardGeneric(u64, linkedit.inner.filesize, self.page_size); |
| 1871 | } | 1802 | } |
| 1872 | self.cmd_table_dirty = true; | 1803 | self.cmd_table_dirty = true; |
| 1873 | } | 1804 | } |
| ... | @@ -1890,49 +1821,31 @@ fn writeStringTable(self: *MachO) !void { | ... | @@ -1890,49 +1821,31 @@ fn writeStringTable(self: *MachO) !void { |
| 1890 | self.linkedit_segment_next_offset = symtab.stroff + symtab.strsize; | 1821 | self.linkedit_segment_next_offset = symtab.stroff + symtab.strsize; |
| 1891 | // Advance size of __LINKEDIT segment | 1822 | // Advance size of __LINKEDIT segment |
| 1892 | const linkedit = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; | 1823 | const linkedit = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; |
| 1893 | linkedit.filesize += symtab.strsize; | 1824 | linkedit.inner.filesize += symtab.strsize; |
| 1894 | if (linkedit.vmsize < linkedit.filesize) { | 1825 | if (linkedit.inner.vmsize < linkedit.inner.filesize) { |
| 1895 | linkedit.vmsize = mem.alignForwardGeneric(u64, linkedit.filesize, self.page_size); | 1826 | linkedit.inner.vmsize = mem.alignForwardGeneric(u64, linkedit.inner.filesize, self.page_size); |
| 1896 | } | 1827 | } |
| 1897 | self.cmd_table_dirty = true; | 1828 | self.cmd_table_dirty = true; |
| 1898 | } | 1829 | } |
| 1899 | | 1830 | |
| 1900 | fn writeCmdHeaders(self: *MachO) !void { | 1831 | /// Writes all load commands and section headers. |
| 1901 | assert(self.cmd_table_dirty); | 1832 | fn writeLoadCommands(self: *MachO) !void { |
| 1902 | | 1833 | var sizeofcmds: usize = 0; |
| 1903 | // Write all load command headers first. | 1834 | for (self.load_commands.items) |lc| { |
| 1904 | // Since command sizes are up-to-date and accurate, we will correctly | 1835 | sizeofcmds += lc.cmdsize(); |
| 1905 | // leave space for any section headers that any of the segment load | | |
| 1906 | // commands might consist of. | | |
| 1907 | var last_cmd_offset: usize = @sizeOf(macho.mach_header_64); | | |
| 1908 | for (self.load_commands.items) |cmd| { | | |
| 1909 | try cmd.write(&self.base.file.?, last_cmd_offset); | | |
| 1910 | last_cmd_offset += cmd.cmdsize(); | | |
| 1911 | } | 1836 | } |
| 1912 | { | 1837 | |
| 1913 | const off = if (self.text_segment_cmd_index) |text_segment_index| blk: { | 1838 | var buffer = try self.base.allocator.alloc(u8, sizeofcmds); |
| 1914 | var i: usize = 0; | 1839 | defer self.base.allocator.free(buffer); |
| 1915 | var cmdsize: usize = @sizeOf(macho.mach_header_64) + @sizeOf(macho.segment_command_64); | 1840 | var writer = std.io.fixedBufferStream(buffer).writer(); |
| 1916 | while (i < text_segment_index) : (i += 1) { | 1841 | for (self.load_commands.items) |lc| { |
| 1917 | cmdsize += self.load_commands.items[i].cmdsize(); | 1842 | try lc.write(writer); |
| 1918 | } | | |
| 1919 | break :blk cmdsize; | | |
| 1920 | } else { | | |
| 1921 | // If we've landed in here, we are building a MachO object file, so we have | | |
| 1922 | // only one, noname segment to append this section header to. | | |
| 1923 | return error.TODOImplementWritingObjFiles; | | |
| 1924 | }; | | |
| 1925 | // write sections belonging to __TEXT segment | | |
| 1926 | // TODO section indices should belong to each Segment, and we should iterate dynamically. | | |
| 1927 | const id = self.text_section_index.?; | | |
| 1928 | log.debug("writing __TEXT section headers at 0x{x}\n", .{off}); | | |
| 1929 | try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.sections.items[id .. id + 2]), off); | | |
| 1930 | } | 1843 | } |
| | 1844 | |
| | 1845 | try self.base.file.?.pwriteAll(buffer, @sizeOf(macho.mach_header_64)); |
| 1931 | } | 1846 | } |
| 1932 | | 1847 | |
| 1933 | /// Writes Mach-O file header. | 1848 | /// Writes Mach-O file header. |
| 1934 | /// Should be invoked last as it needs up-to-date values of ncmds and sizeof_cmds bookkeeping | | |
| 1935 | /// variables. | | |
| 1936 | fn writeMachOHeader(self: *MachO) !void { | 1849 | fn writeMachOHeader(self: *MachO) !void { |
| 1937 | var hdr: macho.mach_header_64 = undefined; | 1850 | var hdr: macho.mach_header_64 = undefined; |
| 1938 | hdr.magic = macho.MH_MAGIC_64; | 1851 | hdr.magic = macho.MH_MAGIC_64; |
| ... | @@ -1994,10 +1907,3 @@ fn satMul(a: anytype, b: anytype) @TypeOf(a, b) { | ... | @@ -1994,10 +1907,3 @@ fn satMul(a: anytype, b: anytype) @TypeOf(a, b) { |
| 1994 | const T = @TypeOf(a, b); | 1907 | const T = @TypeOf(a, b); |
| 1995 | return std.math.mul(T, a, b) catch std.math.maxInt(T); | 1908 | return std.math.mul(T, a, b) catch std.math.maxInt(T); |
| 1996 | } | 1909 | } |
| 1997 | | | |
| 1998 | test "" { | | |
| 1999 | // TODO surprisingly this causes a linking error: | | |
| 2000 | // _linkWithLLD symbol missing for arch | | |
| 2001 | // _ = std.testing.refAllDecls(@This()); | | |
| 2002 | _ = std.testing.refAllDecls(@import("MachO/commands.zig")); | | |
| 2003 | } | | |