| ... | @@ -76,7 +76,6 @@ text_segment_cmd_index: ?u16 = null, | ... | @@ -76,7 +76,6 @@ text_segment_cmd_index: ?u16 = null, |
| 76 | data_segment_cmd_index: ?u16 = null, | 76 | data_segment_cmd_index: ?u16 = null, |
| 77 | /// __LINKEDIT segment | 77 | /// __LINKEDIT segment |
| 78 | linkedit_segment_cmd_index: ?u16 = null, | 78 | linkedit_segment_cmd_index: ?u16 = null, |
| 79 | segment_cmd_index: ?u16 = null, | | |
| 80 | /// Dyld info | 79 | /// Dyld info |
| 81 | dyld_info_cmd_index: ?u16 = null, | 80 | dyld_info_cmd_index: ?u16 = null, |
| 82 | /// Symbol table | 81 | /// Symbol table |
| ... | @@ -107,9 +106,10 @@ got_section_index: ?u16 = null, | ... | @@ -107,9 +106,10 @@ got_section_index: ?u16 = null, |
| 107 | | 106 | |
| 108 | entry_addr: ?u64 = null, | 107 | entry_addr: ?u64 = null, |
| 109 | | 108 | |
| 110 | /// Table of all symbols used. | 109 | /// Table of all local symbols used. |
| 111 | /// Internally references string table for names (which are optional). | 110 | /// Internally references string table for names (which are optional). |
| 112 | symbol_table: std.ArrayListUnmanaged(macho.nlist_64) = .{}, | 111 | local_symbols: std.ArrayListUnmanaged(macho.nlist_64) = .{}, |
| | 112 | global_symbols: std.ArrayListUnmanaged(macho.nlist_64) = .{}, |
| 113 | | 113 | |
| 114 | /// Table of symbol names aka the string table. | 114 | /// Table of symbol names aka the string table. |
| 115 | string_table: std.ArrayListUnmanaged(u8) = .{}, | 115 | string_table: std.ArrayListUnmanaged(u8) = .{}, |
| ... | @@ -227,87 +227,82 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { | ... | @@ -227,87 +227,82 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { |
| 227 | defer tracy.end(); | 227 | defer tracy.end(); |
| 228 | | 228 | |
| 229 | switch (self.base.options.output_mode) { | 229 | switch (self.base.options.output_mode) { |
| 230 | .Exe => { | 230 | .Exe => {}, |
| 231 | var last_cmd_offset: usize = @sizeOf(macho.mach_header_64); | 231 | .Obj => return error.TODOImplementWritingObjFiles, |
| 232 | { | 232 | .Lib => return error.TODOImplementWritingLibFiles, |
| 233 | // Specify path to dynamic linker dyld | 233 | } |
| 234 | const cmdsize = commandSize(@sizeOf(macho.dylinker_command) + mem.lenZ(DEFAULT_DYLD_PATH)); | | |
| 235 | const load_dylinker = [1]macho.dylinker_command{ | | |
| 236 | .{ | | |
| 237 | .cmd = macho.LC_LOAD_DYLINKER, | | |
| 238 | .cmdsize = cmdsize, | | |
| 239 | .name = @sizeOf(macho.dylinker_command), | | |
| 240 | }, | | |
| 241 | }; | | |
| 242 | | | |
| 243 | try self.base.file.?.pwriteAll(mem.sliceAsBytes(load_dylinker[0..1]), last_cmd_offset); | | |
| 244 | | | |
| 245 | const file_offset = last_cmd_offset + @sizeOf(macho.dylinker_command); | | |
| 246 | try self.addPadding(cmdsize - @sizeOf(macho.dylinker_command), file_offset); | | |
| 247 | | | |
| 248 | try self.base.file.?.pwriteAll(mem.spanZ(DEFAULT_DYLD_PATH), file_offset); | | |
| 249 | last_cmd_offset += cmdsize; | | |
| 250 | } | | |
| 251 | | 234 | |
| 252 | { | 235 | // Unfortunately these have to be buffered and done at the end because ELF does not allow |
| 253 | // Link against libSystem | 236 | // mixing local and global symbols within a symbol table. |
| 254 | const cmdsize = commandSize(@sizeOf(macho.dylib_command) + mem.lenZ(LIB_SYSTEM_PATH)); | 237 | try self.writeAllGlobalSymbols(); |
| 255 | // TODO Find a way to work out runtime version from the OS version triple stored in std.Target. | | |
| 256 | // In the meantime, we're gonna hardcode to the minimum compatibility version of 1.0.0. | | |
| 257 | const min_version = 0x10000; | | |
| 258 | const dylib = .{ | | |
| 259 | .name = @sizeOf(macho.dylib_command), | | |
| 260 | .timestamp = 2, // not sure why not simply 0; this is reverse engineered from Mach-O files | | |
| 261 | .current_version = min_version, | | |
| 262 | .compatibility_version = min_version, | | |
| 263 | }; | | |
| 264 | const load_dylib = [1]macho.dylib_command{ | | |
| 265 | .{ | | |
| 266 | .cmd = macho.LC_LOAD_DYLIB, | | |
| 267 | .cmdsize = cmdsize, | | |
| 268 | .dylib = dylib, | | |
| 269 | }, | | |
| 270 | }; | | |
| 271 | | | |
| 272 | try self.base.file.?.pwriteAll(mem.sliceAsBytes(load_dylib[0..1]), last_cmd_offset); | | |
| 273 | | | |
| 274 | const file_offset = last_cmd_offset + @sizeOf(macho.dylib_command); | | |
| 275 | try self.addPadding(cmdsize - @sizeOf(macho.dylib_command), file_offset); | | |
| 276 | | | |
| 277 | try self.base.file.?.pwriteAll(mem.spanZ(LIB_SYSTEM_PATH), file_offset); | | |
| 278 | last_cmd_offset += cmdsize; | | |
| 279 | } | | |
| 280 | }, | | |
| 281 | .Obj => { | | |
| 282 | { | | |
| 283 | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab; | | |
| 284 | symtab.nsyms = @intCast(u32, self.symbol_table.items.len); | | |
| 285 | const allocated_size = self.allocatedSize(symtab.stroff); | | |
| 286 | const needed_size = self.string_table.items.len; | | |
| 287 | log.debug("allocated_size = 0x{x}, needed_size = 0x{x}\n", .{ allocated_size, needed_size }); | | |
| 288 | | | |
| 289 | if (needed_size > allocated_size) { | | |
| 290 | symtab.strsize = 0; | | |
| 291 | symtab.stroff = @intCast(u32, self.findFreeSpace(needed_size, 1)); | | |
| 292 | } | | |
| 293 | symtab.strsize = @intCast(u32, needed_size); | | |
| 294 | | 238 | |
| 295 | log.debug("writing string table from 0x{x} to 0x{x}\n", .{ symtab.stroff, symtab.stroff + symtab.strsize }); | 239 | { |
| | 240 | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab; |
| | 241 | symtab.nsyms = @intCast(u32, self.local_symbols.items.len + self.global_symbols.items.len); |
| | 242 | const allocated_size = self.allocatedSize(symtab.stroff); |
| | 243 | const needed_size = self.string_table.items.len; |
| | 244 | log.debug("allocated_size = 0x{x}, needed_size = 0x{x}\n", .{ allocated_size, needed_size }); |
| | 245 | |
| | 246 | if (needed_size > allocated_size) { |
| | 247 | symtab.strsize = 0; |
| | 248 | symtab.stroff = @intCast(u32, self.findFreeSpace(needed_size, 1)); |
| | 249 | } |
| | 250 | symtab.strsize = @intCast(u32, needed_size); |
| 296 | | 251 | |
| 297 | try self.base.file.?.pwriteAll(self.string_table.items, symtab.stroff); | 252 | log.debug("writing string table from 0x{x} to 0x{x}\n", .{ symtab.stroff, symtab.stroff + symtab.strsize }); |
| 298 | } | | |
| 299 | | 253 | |
| 300 | var last_cmd_offset: usize = @sizeOf(macho.mach_header_64); | 254 | try self.base.file.?.pwriteAll(self.string_table.items, symtab.stroff); |
| 301 | for (self.load_commands.items) |cmd| { | 255 | } |
| 302 | try cmd.write(&self.base.file.?, last_cmd_offset); | 256 | { |
| 303 | last_cmd_offset += cmd.cmdsize(); | 257 | var last_cmd_offset: usize = @sizeOf(macho.mach_header_64); |
| 304 | } | 258 | for (self.load_commands.items) |cmd| { |
| 305 | const off = @sizeOf(macho.mach_header_64) + @sizeOf(macho.segment_command_64); | 259 | try cmd.write(&self.base.file.?, last_cmd_offset); |
| 306 | try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.sections.items), off); | 260 | last_cmd_offset += cmd.cmdsize(); |
| 307 | }, | 261 | } |
| 308 | .Lib => return error.TODOImplementWritingLibFiles, | 262 | } |
| | 263 | { |
| | 264 | // write __text section |
| | 265 | const off = @sizeOf(macho.mach_header_64) + @sizeOf(macho.segment_command_64) * 2; |
| | 266 | log.debug("writing text section {} at 0x{x}\n", .{ self.sections.items[0..1], off }); |
| | 267 | try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.sections.items[0..1]), off); |
| | 268 | } |
| | 269 | { |
| | 270 | // write __got section |
| | 271 | const text = &self.load_commands.items[self.text_segment_cmd_index.?]; |
| | 272 | const off = @sizeOf(macho.mach_header_64) + @sizeOf(macho.segment_command_64) * 2 + text.cmdsize(); |
| | 273 | log.debug("writing got section {} at 0x{x}\n", .{ self.sections.items[1..2], off }); |
| | 274 | try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.sections.items[1..2]), off); |
| | 275 | } |
| | 276 | { |
| | 277 | // write path to dyld |
| | 278 | var off: usize = @sizeOf(macho.mach_header_64); |
| | 279 | for (self.load_commands.items) |cmd| { |
| | 280 | if (cmd == .Dylinker) break; |
| | 281 | off += cmd.cmdsize(); |
| | 282 | } |
| | 283 | const cmd = &self.load_commands.items[self.dylinker_cmd_index.?].Dylinker; |
| | 284 | off += cmd.name; |
| | 285 | const padding = cmd.cmdsize - @sizeOf(macho.dylinker_command); |
| | 286 | log.debug("writing LC_LOAD_DYLINKER padding of size {} at 0x{x}\n", .{ padding, off }); |
| | 287 | try self.addPadding(padding, off); |
| | 288 | log.debug("writing LC_LOAD_DYLINKER path to dyld at 0x{x}\n", .{off}); |
| | 289 | try self.base.file.?.pwriteAll(mem.spanZ(DEFAULT_DYLD_PATH), off); |
| | 290 | } |
| | 291 | { |
| | 292 | // write path to libSystem |
| | 293 | var off: usize = @sizeOf(macho.mach_header_64); |
| | 294 | for (self.load_commands.items) |cmd| { |
| | 295 | if (cmd == .Dylib) break; |
| | 296 | off += cmd.cmdsize(); |
| | 297 | } |
| | 298 | const cmd = &self.load_commands.items[self.libsystem_cmd_index.?].Dylib; |
| | 299 | off += cmd.dylib.name; |
| | 300 | const padding = cmd.cmdsize - @sizeOf(macho.dylib_command); |
| | 301 | log.debug("writing LC_LOAD_DYLIB padding of size {} at 0x{x}\n", .{ padding, off }); |
| | 302 | try self.addPadding(padding, off); |
| | 303 | log.debug("writing LC_LOAD_DYLIB path to libSystem at 0x{x}\n", .{off}); |
| | 304 | try self.base.file.?.pwriteAll(mem.spanZ(LIB_SYSTEM_PATH), off); |
| 309 | } | 305 | } |
| 310 | | | |
| 311 | if (self.entry_addr == null and self.base.options.output_mode == .Exe) { | 306 | if (self.entry_addr == null and self.base.options.output_mode == .Exe) { |
| 312 | log.debug("flushing. no_entry_point_found = true\n", .{}); | 307 | log.debug("flushing. no_entry_point_found = true\n", .{}); |
| 313 | self.error_flags.no_entry_point_found = true; | 308 | self.error_flags.no_entry_point_found = true; |
| ... | @@ -699,7 +694,8 @@ fn darwinArchString(arch: std.Target.Cpu.Arch) []const u8 { | ... | @@ -699,7 +694,8 @@ fn darwinArchString(arch: std.Target.Cpu.Arch) []const u8 { |
| 699 | pub fn deinit(self: *MachO) void { | 694 | pub fn deinit(self: *MachO) void { |
| 700 | self.offset_table.deinit(self.base.allocator); | 695 | self.offset_table.deinit(self.base.allocator); |
| 701 | self.string_table.deinit(self.base.allocator); | 696 | self.string_table.deinit(self.base.allocator); |
| 702 | self.symbol_table.deinit(self.base.allocator); | 697 | self.global_symbols.deinit(self.base.allocator); |
| | 698 | self.local_symbols.deinit(self.base.allocator); |
| 703 | self.sections.deinit(self.base.allocator); | 699 | self.sections.deinit(self.base.allocator); |
| 704 | self.load_commands.deinit(self.base.allocator); | 700 | self.load_commands.deinit(self.base.allocator); |
| 705 | } | 701 | } |
| ... | @@ -707,17 +703,17 @@ pub fn deinit(self: *MachO) void { | ... | @@ -707,17 +703,17 @@ pub fn deinit(self: *MachO) void { |
| 707 | pub fn allocateDeclIndexes(self: *MachO, decl: *Module.Decl) !void { | 703 | pub fn allocateDeclIndexes(self: *MachO, decl: *Module.Decl) !void { |
| 708 | if (decl.link.macho.symbol_table_index) |_| return; | 704 | if (decl.link.macho.symbol_table_index) |_| return; |
| 709 | | 705 | |
| 710 | try self.symbol_table.ensureCapacity(self.base.allocator, self.symbol_table.items.len + 1); | 706 | try self.local_symbols.ensureCapacity(self.base.allocator, self.local_symbols.items.len + 1); |
| 711 | try self.offset_table.ensureCapacity(self.base.allocator, self.offset_table.items.len + 1); | 707 | try self.offset_table.ensureCapacity(self.base.allocator, self.offset_table.items.len + 1); |
| 712 | | 708 | |
| 713 | log.debug("allocating symbol index {} for {}\n", .{ self.symbol_table.items.len, decl.name }); | 709 | log.debug("allocating symbol index {} for {}\n", .{ self.local_symbols.items.len, decl.name }); |
| 714 | decl.link.macho.symbol_table_index = @intCast(u32, self.symbol_table.items.len); | 710 | decl.link.macho.symbol_table_index = @intCast(u32, self.local_symbols.items.len); |
| 715 | _ = self.symbol_table.addOneAssumeCapacity(); | 711 | _ = self.local_symbols.addOneAssumeCapacity(); |
| 716 | | 712 | |
| 717 | decl.link.macho.offset_table_index = @intCast(u32, self.offset_table.items.len); | 713 | decl.link.macho.offset_table_index = @intCast(u32, self.offset_table.items.len); |
| 718 | _ = self.offset_table.addOneAssumeCapacity(); | 714 | _ = self.offset_table.addOneAssumeCapacity(); |
| 719 | | 715 | |
| 720 | self.symbol_table.items[decl.link.macho.symbol_table_index.?] = .{ | 716 | self.local_symbols.items[decl.link.macho.symbol_table_index.?] = .{ |
| 721 | .n_strx = 0, | 717 | .n_strx = 0, |
| 722 | .n_type = 0, | 718 | .n_type = 0, |
| 723 | .n_sect = 0, | 719 | .n_sect = 0, |
| ... | @@ -749,7 +745,7 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { | ... | @@ -749,7 +745,7 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { |
| 749 | log.debug("generated code {}\n", .{code}); | 745 | log.debug("generated code {}\n", .{code}); |
| 750 | | 746 | |
| 751 | const required_alignment = typed_value.ty.abiAlignment(self.base.options.target); | 747 | const required_alignment = typed_value.ty.abiAlignment(self.base.options.target); |
| 752 | const symbol = &self.symbol_table.items[decl.link.macho.symbol_table_index.?]; | 748 | const symbol = &self.local_symbols.items[decl.link.macho.symbol_table_index.?]; |
| 753 | | 749 | |
| 754 | const decl_name = mem.spanZ(decl.name); | 750 | const decl_name = mem.spanZ(decl.name); |
| 755 | const name_str_index = try self.makeString(decl_name); | 751 | const name_str_index = try self.makeString(decl_name); |
| ... | @@ -766,9 +762,6 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { | ... | @@ -766,9 +762,6 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { |
| 766 | }; | 762 | }; |
| 767 | self.offset_table.items[decl.link.macho.offset_table_index.?] = addr; | 763 | self.offset_table.items[decl.link.macho.offset_table_index.?] = addr; |
| 768 | | 764 | |
| 769 | // Since we updated the vaddr and the size, each corresponding export symbol also needs to be updated. | | |
| 770 | const decl_exports = module.decl_exports.get(decl) orelse &[0]*Module.Export{}; | | |
| 771 | try self.updateDeclExports(module, decl, decl_exports); | | |
| 772 | try self.writeSymbol(decl.link.macho.symbol_table_index.?); | 765 | try self.writeSymbol(decl.link.macho.symbol_table_index.?); |
| 773 | try self.writeOffsetTableEntry(decl.link.macho.offset_table_index.?); | 766 | try self.writeOffsetTableEntry(decl.link.macho.offset_table_index.?); |
| 774 | | 767 | |
| ... | @@ -778,6 +771,10 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { | ... | @@ -778,6 +771,10 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { |
| 778 | log.debug("file_offset 0x{x}\n", .{file_offset}); | 771 | log.debug("file_offset 0x{x}\n", .{file_offset}); |
| 779 | | 772 | |
| 780 | try self.base.file.?.pwriteAll(code, file_offset); | 773 | try self.base.file.?.pwriteAll(code, file_offset); |
| | 774 | |
| | 775 | // Since we updated the vaddr and the size, each corresponding export symbol also needs to be updated. |
| | 776 | const decl_exports = module.decl_exports.get(decl) orelse &[0]*Module.Export{}; |
| | 777 | try self.updateDeclExports(module, decl, decl_exports); |
| 781 | } | 778 | } |
| 782 | | 779 | |
| 783 | pub fn updateDeclLineNumber(self: *MachO, module: *Module, decl: *const Module.Decl) !void {} | 780 | pub fn updateDeclLineNumber(self: *MachO, module: *Module, decl: *const Module.Decl) !void {} |
| ... | @@ -791,22 +788,72 @@ pub fn updateDeclExports( | ... | @@ -791,22 +788,72 @@ pub fn updateDeclExports( |
| 791 | const tracy = trace(@src()); | 788 | const tracy = trace(@src()); |
| 792 | defer tracy.end(); | 789 | defer tracy.end(); |
| 793 | | 790 | |
| | 791 | try self.global_symbols.ensureCapacity(self.base.allocator, self.global_symbols.items.len + exports.len); |
| 794 | if (decl.link.macho.symbol_table_index == null) return; | 792 | if (decl.link.macho.symbol_table_index == null) return; |
| 795 | | 793 | const decl_sym = &self.local_symbols.items[decl.link.macho.symbol_table_index.?]; |
| 796 | const decl_sym = &self.symbol_table.items[decl.link.macho.symbol_table_index.?]; | 794 | |
| 797 | // TODO implement | 795 | for (exports) |exp| { |
| 798 | if (exports.len == 0) return; | 796 | if (exp.options.section) |section_name| { |
| 799 | | 797 | if (!mem.eql(u8, section_name, "__text")) { |
| 800 | const exp = exports[0]; | 798 | try module.failed_exports.ensureCapacity(module.gpa, module.failed_exports.items().len + 1); |
| 801 | self.entry_addr = decl_sym.n_value; | 799 | module.failed_exports.putAssumeCapacityNoClobber( |
| 802 | decl_sym.n_type |= macho.N_EXT; | 800 | exp, |
| 803 | exp.link.sym_index = 0; | 801 | try Module.ErrorMsg.create(self.base.allocator, 0, "Unimplemented: ExportOptions.section", .{}), |
| | 802 | ); |
| | 803 | continue; |
| | 804 | } |
| | 805 | } |
| | 806 | const n_desc = switch (exp.options.linkage) { |
| | 807 | .Internal => macho.REFERENCE_FLAG_PRIVATE_DEFINED, |
| | 808 | .Strong => blk: { |
| | 809 | if (mem.eql(u8, exp.options.name, "_start")) { |
| | 810 | self.entry_addr = decl_sym.n_value; |
| | 811 | const cmd = &self.load_commands.items[self.main_cmd_index.?].EntryPoint; |
| | 812 | cmd.entryoff = decl_sym.n_value; |
| | 813 | } |
| | 814 | break :blk macho.REFERENCE_FLAG_DEFINED; |
| | 815 | }, |
| | 816 | .Weak => macho.N_WEAK_REF, |
| | 817 | .LinkOnce => { |
| | 818 | try module.failed_exports.ensureCapacity(module.gpa, module.failed_exports.items().len + 1); |
| | 819 | module.failed_exports.putAssumeCapacityNoClobber( |
| | 820 | exp, |
| | 821 | try Module.ErrorMsg.create(self.base.allocator, 0, "Unimplemented: GlobalLinkage.LinkOnce", .{}), |
| | 822 | ); |
| | 823 | continue; |
| | 824 | }, |
| | 825 | }; |
| | 826 | const n_type = decl_sym.n_type | macho.N_EXT; |
| | 827 | if (exp.link.sym_index) |i| { |
| | 828 | const sym = &self.global_symbols.items[i]; |
| | 829 | sym.* = .{ |
| | 830 | .n_strx = try self.updateString(sym.n_strx, exp.options.name), |
| | 831 | .n_type = n_type, |
| | 832 | .n_sect = @intCast(u8, self.text_section_index.?) + 1, |
| | 833 | .n_desc = n_desc, |
| | 834 | .n_value = decl_sym.n_value, |
| | 835 | }; |
| | 836 | } else { |
| | 837 | const name_str_index = try self.makeString(exp.options.name); |
| | 838 | _ = self.global_symbols.addOneAssumeCapacity(); |
| | 839 | const i = self.global_symbols.items.len - 1; |
| | 840 | self.global_symbols.items[i] = .{ |
| | 841 | .n_strx = name_str_index, |
| | 842 | .n_type = n_type, |
| | 843 | .n_sect = @intCast(u8, self.text_section_index.?) + 1, |
| | 844 | .n_desc = n_desc, |
| | 845 | .n_value = decl_sym.n_value, |
| | 846 | }; |
| | 847 | |
| | 848 | exp.link.sym_index = @intCast(u32, i); |
| | 849 | } |
| | 850 | } |
| 804 | } | 851 | } |
| 805 | | 852 | |
| 806 | pub fn freeDecl(self: *MachO, decl: *Module.Decl) void {} | 853 | pub fn freeDecl(self: *MachO, decl: *Module.Decl) void {} |
| 807 | | 854 | |
| 808 | pub fn getDeclVAddr(self: *MachO, decl: *const Module.Decl) u64 { | 855 | pub fn getDeclVAddr(self: *MachO, decl: *const Module.Decl) u64 { |
| 809 | return self.symbol_table.items[decl.link.macho.symbol_table_index.?].n_value; | 856 | return self.local_symbols.items[decl.link.macho.symbol_table_index.?].n_value; |
| 810 | } | 857 | } |
| 811 | | 858 | |
| 812 | pub fn populateMissingMetadata(self: *MachO) !void { | 859 | pub fn populateMissingMetadata(self: *MachO) !void { |
| ... | @@ -818,7 +865,7 @@ pub fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -818,7 +865,7 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 818 | .cmdsize = @sizeOf(macho.segment_command_64), | 865 | .cmdsize = @sizeOf(macho.segment_command_64), |
| 819 | .segname = makeStaticString("__PAGEZERO"), | 866 | .segname = makeStaticString("__PAGEZERO"), |
| 820 | .vmaddr = 0, | 867 | .vmaddr = 0, |
| 821 | .vmsize = 0x1000, // size always set to 4GB | 868 | .vmsize = 0x100000000, // size always set to 4GB |
| 822 | .fileoff = 0, | 869 | .fileoff = 0, |
| 823 | .filesize = 0, | 870 | .filesize = 0, |
| 824 | .maxprot = 0, | 871 | .maxprot = 0, |
| ... | @@ -829,47 +876,34 @@ pub fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -829,47 +876,34 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 829 | }); | 876 | }); |
| 830 | self.cmd_table_dirty = true; | 877 | self.cmd_table_dirty = true; |
| 831 | } | 878 | } |
| 832 | if (self.segment_cmd_index == null) { | 879 | if (self.text_segment_cmd_index == null) { |
| 833 | self.segment_cmd_index = @intCast(u16, self.load_commands.items.len); | 880 | self.text_segment_cmd_index = @intCast(u16, self.load_commands.items.len); |
| | 881 | const prot = macho.VM_PROT_READ | macho.VM_PROT_EXECUTE; |
| 834 | try self.load_commands.append(self.base.allocator, .{ | 882 | try self.load_commands.append(self.base.allocator, .{ |
| 835 | .Segment = .{ | 883 | .Segment = .{ |
| 836 | .cmd = macho.LC_SEGMENT_64, | 884 | .cmd = macho.LC_SEGMENT_64, |
| 837 | .cmdsize = @sizeOf(macho.segment_command_64), | 885 | .cmdsize = @sizeOf(macho.segment_command_64), |
| 838 | .segname = makeStaticString(""), | 886 | .segname = makeStaticString("__TEXT"), |
| 839 | .vmaddr = 0, | 887 | .vmaddr = 0x100000000, // always starts at 4GB |
| 840 | .vmsize = 0, | 888 | .vmsize = 0, |
| 841 | .fileoff = 0, | 889 | .fileoff = 0, |
| 842 | .filesize = 0, | 890 | .filesize = 0, |
| 843 | .maxprot = 0, | 891 | .maxprot = prot, |
| 844 | .initprot = 0, | 892 | .initprot = prot, |
| 845 | .nsects = 0, | 893 | .nsects = 0, |
| 846 | .flags = 0, | 894 | .flags = 0, |
| 847 | }, | 895 | }, |
| 848 | }); | 896 | }); |
| 849 | self.cmd_table_dirty = true; | 897 | self.cmd_table_dirty = true; |
| 850 | } | 898 | } |
| 851 | if (self.symtab_cmd_index == null) { | | |
| 852 | self.symtab_cmd_index = @intCast(u16, self.load_commands.items.len); | | |
| 853 | try self.load_commands.append(self.base.allocator, .{ | | |
| 854 | .Symtab = .{ | | |
| 855 | .cmd = macho.LC_SYMTAB, | | |
| 856 | .cmdsize = @sizeOf(macho.symtab_command), | | |
| 857 | .symoff = 0, | | |
| 858 | .nsyms = 0, | | |
| 859 | .stroff = 0, | | |
| 860 | .strsize = 0, | | |
| 861 | }, | | |
| 862 | }); | | |
| 863 | self.cmd_table_dirty = true; | | |
| 864 | } | | |
| 865 | if (self.text_section_index == null) { | 899 | if (self.text_section_index == null) { |
| 866 | self.text_section_index = @intCast(u16, self.sections.items.len); | 900 | self.text_section_index = @intCast(u16, self.sections.items.len); |
| 867 | const segment = &self.load_commands.items[self.segment_cmd_index.?].Segment; | 901 | const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 868 | segment.cmdsize += @sizeOf(macho.section_64); | 902 | text_segment.cmdsize += @sizeOf(macho.section_64); |
| 869 | segment.nsects += 1; | 903 | text_segment.nsects += 1; |
| 870 | | 904 | |
| 871 | const file_size = self.base.options.program_code_size_hint; | 905 | const file_size = self.base.options.program_code_size_hint; |
| 872 | const off = @intCast(u32, self.findFreeSpace(file_size, 64)); | 906 | const off = @intCast(u32, self.findFreeSpace(file_size, 0x1000)); // TODO maybe findFreeSpace should return u32 directly? |
| 873 | const flags = macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS; | 907 | const flags = macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS; |
| 874 | | 908 | |
| 875 | log.debug("found __text section free space 0x{x} to 0x{x}\n", .{ off, off + file_size }); | 909 | log.debug("found __text section free space 0x{x} to 0x{x}\n", .{ off, off + file_size }); |
| ... | @@ -877,7 +911,7 @@ pub fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -877,7 +911,7 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 877 | try self.sections.append(self.base.allocator, .{ | 911 | try self.sections.append(self.base.allocator, .{ |
| 878 | .sectname = makeStaticString("__text"), | 912 | .sectname = makeStaticString("__text"), |
| 879 | .segname = makeStaticString("__TEXT"), | 913 | .segname = makeStaticString("__TEXT"), |
| 880 | .addr = 0, | 914 | .addr = text_segment.vmaddr + off, |
| 881 | .size = file_size, | 915 | .size = file_size, |
| 882 | .offset = off, | 916 | .offset = off, |
| 883 | .@"align" = 12, | 917 | .@"align" = 12, |
| ... | @@ -889,32 +923,48 @@ pub fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -889,32 +923,48 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 889 | .reserved3 = 0, | 923 | .reserved3 = 0, |
| 890 | }); | 924 | }); |
| 891 | | 925 | |
| 892 | segment.vmsize += file_size; | 926 | text_segment.vmsize = file_size + off; |
| 893 | segment.filesize += file_size; | 927 | text_segment.filesize = file_size + off; |
| 894 | segment.fileoff = off; | | |
| 895 | | 928 | |
| 896 | log.debug("initial text section {}\n", .{self.sections.items[self.text_section_index.?]}); | 929 | log.debug("initial text section {}\n", .{self.sections.items[self.text_section_index.?]}); |
| 897 | log.debug("update segment {}\n", .{segment}); | 930 | log.debug("updated text segment {}\n", .{text_segment}); |
| | 931 | } |
| | 932 | if (self.data_segment_cmd_index == null) { |
| | 933 | self.data_segment_cmd_index = @intCast(u16, self.load_commands.items.len); |
| | 934 | const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| | 935 | const prot = macho.VM_PROT_READ | macho.VM_PROT_WRITE; |
| | 936 | try self.load_commands.append(self.base.allocator, .{ |
| | 937 | .Segment = .{ |
| | 938 | .cmd = macho.LC_SEGMENT_64, |
| | 939 | .cmdsize = @sizeOf(macho.segment_command_64), |
| | 940 | .segname = makeStaticString("__DATA"), |
| | 941 | .vmaddr = text_segment.vmaddr + text_segment.vmsize, // TODO this should be found when running findFreeSpace |
| | 942 | .vmsize = 0, |
| | 943 | .fileoff = 0, |
| | 944 | .filesize = 0, |
| | 945 | .maxprot = prot, |
| | 946 | .initprot = prot, |
| | 947 | .nsects = 0, |
| | 948 | .flags = 0, |
| | 949 | }, |
| | 950 | }); |
| | 951 | self.cmd_table_dirty = true; |
| 898 | } | 952 | } |
| 899 | if (self.got_section_index == null) { | 953 | if (self.got_section_index == null) { |
| 900 | self.got_section_index = @intCast(u16, self.sections.items.len); | 954 | self.got_section_index = @intCast(u16, self.sections.items.len); |
| 901 | const segment = &self.load_commands.items[self.segment_cmd_index.?].Segment; | 955 | const data_segment = &self.load_commands.items[self.data_segment_cmd_index.?].Segment; |
| 902 | const text_sect = &self.sections.items[self.text_section_index.?]; | 956 | data_segment.cmdsize += @sizeOf(macho.section_64); |
| 903 | segment.cmdsize += @sizeOf(macho.section_64); | 957 | data_segment.nsects += 1; |
| 904 | segment.nsects += 1; | | |
| 905 | | 958 | |
| 906 | const p_align = @sizeOf(u64); | 959 | const file_size = @sizeOf(u64) * self.base.options.symbol_count_hint; |
| 907 | const file_size = p_align * self.base.options.symbol_count_hint; | 960 | const off = @intCast(u32, self.findFreeSpace(file_size, 0x1000)); |
| 908 | const off = @intCast(u32, self.findFreeSpace(file_size, p_align)); | | |
| 909 | | 961 | |
| 910 | log.debug("found __got section free space 0x{x} to 0x{x}\n", .{ off, off + file_size }); | 962 | log.debug("found __got section free space 0x{x} to 0x{x}\n", .{ off, off + file_size }); |
| 911 | | 963 | |
| 912 | const padding_size = off - text_sect.offset - text_sect.size; | | |
| 913 | | | |
| 914 | try self.sections.append(self.base.allocator, .{ | 964 | try self.sections.append(self.base.allocator, .{ |
| 915 | .sectname = makeStaticString("__got"), | 965 | .sectname = makeStaticString("__got"), |
| 916 | .segname = makeStaticString("__DATA"), | 966 | .segname = makeStaticString("__DATA"), |
| 917 | .addr = text_sect.addr + text_sect.size + padding_size, | 967 | .addr = data_segment.vmaddr, |
| 918 | .size = file_size, | 968 | .size = file_size, |
| 919 | .offset = off, | 969 | .offset = off, |
| 920 | .@"align" = 3, | 970 | .@"align" = 3, |
| ... | @@ -926,46 +976,140 @@ pub fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -926,46 +976,140 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 926 | .reserved3 = 0, | 976 | .reserved3 = 0, |
| 927 | }); | 977 | }); |
| 928 | | 978 | |
| 929 | segment.vmsize += file_size + padding_size; | 979 | data_segment.vmsize = file_size; |
| 930 | segment.filesize += file_size + padding_size; | 980 | data_segment.filesize = file_size; |
| | 981 | data_segment.fileoff = off; |
| 931 | | 982 | |
| 932 | log.debug("initial got section {}\n", .{self.sections.items[self.got_section_index.?]}); | 983 | log.debug("initial got section {}\n", .{self.sections.items[self.got_section_index.?]}); |
| 933 | log.debug("update segment {}\n", .{segment}); | 984 | log.debug("updated data segment {}\n", .{data_segment}); |
| | 985 | } |
| | 986 | if (self.linkedit_segment_cmd_index == null) { |
| | 987 | self.linkedit_segment_cmd_index = @intCast(u16, self.load_commands.items.len); |
| | 988 | const data_segment = &self.load_commands.items[self.data_segment_cmd_index.?].Segment; |
| | 989 | const prot = macho.VM_PROT_READ | macho.VM_PROT_WRITE | macho.VM_PROT_EXECUTE; |
| | 990 | try self.load_commands.append(self.base.allocator, .{ |
| | 991 | .Segment = .{ |
| | 992 | .cmd = macho.LC_SEGMENT_64, |
| | 993 | .cmdsize = @sizeOf(macho.segment_command_64), |
| | 994 | .segname = makeStaticString("__LINKEDIT"), |
| | 995 | .vmaddr = data_segment.vmaddr + data_segment.vmsize, // TODO this should be found when running findFreeSpace |
| | 996 | .vmsize = 0, |
| | 997 | .fileoff = 0, |
| | 998 | .filesize = 0, |
| | 999 | .maxprot = prot, |
| | 1000 | .initprot = prot, |
| | 1001 | .nsects = 0, |
| | 1002 | .flags = 0, |
| | 1003 | }, |
| | 1004 | }); |
| | 1005 | self.cmd_table_dirty = true; |
| | 1006 | } |
| | 1007 | if (self.symtab_cmd_index == null) { |
| | 1008 | self.symtab_cmd_index = @intCast(u16, self.load_commands.items.len); |
| | 1009 | try self.load_commands.append(self.base.allocator, .{ |
| | 1010 | .Symtab = .{ |
| | 1011 | .cmd = macho.LC_SYMTAB, |
| | 1012 | .cmdsize = @sizeOf(macho.symtab_command), |
| | 1013 | .symoff = 0, |
| | 1014 | .nsyms = 0, |
| | 1015 | .stroff = 0, |
| | 1016 | .strsize = 0, |
| | 1017 | }, |
| | 1018 | }); |
| | 1019 | self.cmd_table_dirty = true; |
| | 1020 | } |
| | 1021 | if (self.dylinker_cmd_index == null) { |
| | 1022 | self.dylinker_cmd_index = @intCast(u16, self.load_commands.items.len); |
| | 1023 | const cmdsize = commandSize(@sizeOf(macho.dylinker_command) + mem.lenZ(DEFAULT_DYLD_PATH)); |
| | 1024 | try self.load_commands.append(self.base.allocator, .{ |
| | 1025 | .Dylinker = .{ |
| | 1026 | .cmd = macho.LC_LOAD_DYLINKER, |
| | 1027 | .cmdsize = cmdsize, |
| | 1028 | .name = @sizeOf(macho.dylinker_command), |
| | 1029 | }, |
| | 1030 | }); |
| | 1031 | self.cmd_table_dirty = true; |
| | 1032 | } |
| | 1033 | if (self.libsystem_cmd_index == null) { |
| | 1034 | self.libsystem_cmd_index = @intCast(u16, self.load_commands.items.len); |
| | 1035 | const cmdsize = commandSize(@sizeOf(macho.dylib_command) + mem.lenZ(LIB_SYSTEM_PATH)); |
| | 1036 | // TODO Find a way to work out runtime version from the OS version triple stored in std.Target. |
| | 1037 | // In the meantime, we're gonna hardcode to the minimum compatibility version of 1.0.0. |
| | 1038 | const min_version = 0x10000; |
| | 1039 | const dylib = .{ |
| | 1040 | .name = @sizeOf(macho.dylib_command), |
| | 1041 | .timestamp = 2, // not sure why not simply 0; this is reverse engineered from Mach-O files |
| | 1042 | .current_version = min_version, |
| | 1043 | .compatibility_version = min_version, |
| | 1044 | }; |
| | 1045 | try self.load_commands.append(self.base.allocator, .{ |
| | 1046 | .Dylib = .{ |
| | 1047 | .cmd = macho.LC_LOAD_DYLIB, |
| | 1048 | .cmdsize = cmdsize, |
| | 1049 | .dylib = dylib, |
| | 1050 | }, |
| | 1051 | }); |
| | 1052 | self.cmd_table_dirty = true; |
| | 1053 | } |
| | 1054 | if (self.main_cmd_index == null) { |
| | 1055 | self.main_cmd_index = @intCast(u16, self.load_commands.items.len); |
| | 1056 | try self.load_commands.append(self.base.allocator, .{ |
| | 1057 | .EntryPoint = .{ |
| | 1058 | .cmd = macho.LC_MAIN, |
| | 1059 | .cmdsize = @sizeOf(macho.entry_point_command), |
| | 1060 | .entryoff = 0x0, |
| | 1061 | .stacksize = 0, |
| | 1062 | }, |
| | 1063 | }); |
| | 1064 | self.cmd_table_dirty = true; |
| 934 | } | 1065 | } |
| 935 | { | 1066 | { |
| | 1067 | const linkedit = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; |
| 936 | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab; | 1068 | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab; |
| 937 | if (symtab.symoff == 0) { | 1069 | if (symtab.symoff == 0) { |
| 938 | const p_align = @sizeOf(macho.nlist_64); | | |
| 939 | const nsyms = self.base.options.symbol_count_hint; | 1070 | const nsyms = self.base.options.symbol_count_hint; |
| 940 | const file_size = p_align * nsyms; | 1071 | const file_size = @sizeOf(macho.nlist_64) * nsyms; |
| 941 | const off = @intCast(u32, self.findFreeSpace(file_size, p_align)); | 1072 | const off = @intCast(u32, self.findFreeSpace(file_size, 0x1000)); |
| 942 | log.debug("found symbol table free space 0x{x} to 0x{x}\n", .{ off, off + file_size }); | 1073 | log.debug("found symbol table free space 0x{x} to 0x{x}\n", .{ off, off + file_size }); |
| 943 | symtab.symoff = off; | 1074 | symtab.symoff = off; |
| 944 | symtab.nsyms = @intCast(u32, nsyms); | 1075 | symtab.nsyms = @intCast(u32, nsyms); |
| | 1076 | |
| | 1077 | linkedit.vmsize += file_size; |
| | 1078 | linkedit.fileoff = off; |
| | 1079 | linkedit.filesize += file_size; |
| | 1080 | |
| | 1081 | log.debug("updated linkedit segment {}\n", .{linkedit}); |
| 945 | } | 1082 | } |
| 946 | if (symtab.stroff == 0) { | 1083 | if (symtab.stroff == 0) { |
| 947 | try self.string_table.append(self.base.allocator, 0); | 1084 | try self.string_table.append(self.base.allocator, 0); |
| 948 | const file_size = @intCast(u32, self.string_table.items.len); | 1085 | const file_size = @intCast(u32, self.string_table.items.len); |
| 949 | const off = @intCast(u32, self.findFreeSpace(file_size, 1)); | 1086 | const off = @intCast(u32, self.findFreeSpace(file_size, 0x1000)); |
| 950 | log.debug("found string table free space 0x{x} to 0x{x}\n", .{ off, off + file_size }); | 1087 | log.debug("found string table free space 0x{x} to 0x{x}\n", .{ off, off + file_size }); |
| 951 | symtab.stroff = off; | 1088 | symtab.stroff = off; |
| 952 | symtab.strsize = file_size; | 1089 | symtab.strsize = file_size; |
| | 1090 | |
| | 1091 | linkedit.vmsize += file_size; |
| | 1092 | linkedit.filesize += file_size; |
| | 1093 | |
| | 1094 | log.debug("updated linkedit segment {}\n", .{linkedit}); |
| 953 | } | 1095 | } |
| 954 | } | 1096 | } |
| 955 | } | 1097 | } |
| 956 | | 1098 | |
| 957 | fn allocateTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64, alignment: u64) !u64 { | 1099 | fn allocateTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64, alignment: u64) !u64 { |
| 958 | const segment = &self.load_commands.items[self.segment_cmd_index.?].Segment; | | |
| 959 | const text_section = &self.sections.items[self.text_section_index.?]; | 1100 | const text_section = &self.sections.items[self.text_section_index.?]; |
| 960 | const new_block_ideal_capacity = new_block_size * alloc_num / alloc_den; | 1101 | const new_block_ideal_capacity = new_block_size * alloc_num / alloc_den; |
| 961 | | 1102 | |
| 962 | var block_placement: ?*TextBlock = null; | 1103 | var block_placement: ?*TextBlock = null; |
| 963 | const addr = blk: { | 1104 | const addr = blk: { |
| 964 | if (self.last_text_block) |last| { | 1105 | if (self.last_text_block) |last| { |
| 965 | const last_symbol = self.symbol_table.items[last.symbol_table_index.?]; | 1106 | const last_symbol = self.local_symbols.items[last.symbol_table_index.?]; |
| 966 | const ideal_capacity = last.size * alloc_num / alloc_den; | 1107 | // TODO pad out with NOPs and reenable |
| 967 | const ideal_capacity_end_addr = last_symbol.n_value + ideal_capacity; | 1108 | // const ideal_capacity = last.size * alloc_num / alloc_den; |
| 968 | const new_start_addr = mem.alignForwardGeneric(u64, ideal_capacity_end_addr, alignment); | 1109 | // const ideal_capacity_end_addr = last_symbol.n_value + ideal_capacity; |
| | 1110 | // const new_start_addr = mem.alignForwardGeneric(u64, ideal_capacity_end_addr, alignment); |
| | 1111 | const end_addr = last_symbol.n_value + last.size; |
| | 1112 | const new_start_addr = mem.alignForwardGeneric(u64, end_addr, alignment); |
| 969 | block_placement = last; | 1113 | block_placement = last; |
| 970 | break :blk new_start_addr; | 1114 | break :blk new_start_addr; |
| 971 | } else { | 1115 | } else { |
| ... | @@ -982,6 +1126,7 @@ fn allocateTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64, | ... | @@ -982,6 +1126,7 @@ fn allocateTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64, |
| 982 | assert(needed_size <= text_capacity); // TODO handle growth | 1126 | assert(needed_size <= text_capacity); // TODO handle growth |
| 983 | | 1127 | |
| 984 | self.last_text_block = text_block; | 1128 | self.last_text_block = text_block; |
| | 1129 | text_section.size = needed_size; // TODO temp until we pad out with NOPs |
| 985 | } | 1130 | } |
| 986 | text_block.size = new_block_size; | 1131 | text_block.size = new_block_size; |
| 987 | | 1132 | |
| ... | @@ -1019,6 +1164,19 @@ fn makeString(self: *MachO, bytes: []const u8) !u32 { | ... | @@ -1019,6 +1164,19 @@ fn makeString(self: *MachO, bytes: []const u8) !u32 { |
| 1019 | return @intCast(u32, result); | 1164 | return @intCast(u32, result); |
| 1020 | } | 1165 | } |
| 1021 | | 1166 | |
| | 1167 | fn getString(self: *MachO, str_off: u32) []const u8 { |
| | 1168 | assert(str_off < self.string_table.items.len); |
| | 1169 | return mem.spanZ(@ptrCast([*:0]const u8, self.string_table.items.ptr + str_off)); |
| | 1170 | } |
| | 1171 | |
| | 1172 | fn updateString(self: *MachO, old_str_off: u32, new_name: []const u8) !u32 { |
| | 1173 | const existing_name = self.getString(old_str_off); |
| | 1174 | if (mem.eql(u8, existing_name, new_name)) { |
| | 1175 | return old_str_off; |
| | 1176 | } |
| | 1177 | return self.makeString(new_name); |
| | 1178 | } |
| | 1179 | |
| 1022 | fn alignSize(comptime Int: type, min_size: anytype, alignment: Int) Int { | 1180 | fn alignSize(comptime Int: type, min_size: anytype, alignment: Int) Int { |
| 1023 | const size = @intCast(Int, min_size); | 1181 | const size = @intCast(Int, min_size); |
| 1024 | if (size % alignment == 0) return size; | 1182 | if (size % alignment == 0) return size; |
| ... | @@ -1119,7 +1277,7 @@ fn writeSymbol(self: *MachO, index: usize) !void { | ... | @@ -1119,7 +1277,7 @@ fn writeSymbol(self: *MachO, index: usize) !void { |
| 1119 | defer tracy.end(); | 1277 | defer tracy.end(); |
| 1120 | | 1278 | |
| 1121 | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab; | 1279 | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab; |
| 1122 | const sym = [1]macho.nlist_64{self.symbol_table.items[index]}; | 1280 | const sym = [1]macho.nlist_64{self.local_symbols.items[index]}; |
| 1123 | const off = symtab.symoff + @sizeOf(macho.nlist_64) * index; | 1281 | const off = symtab.symoff + @sizeOf(macho.nlist_64) * index; |
| 1124 | log.debug("writing symbol {} at 0x{x}\n", .{ sym[0], off }); | 1282 | log.debug("writing symbol {} at 0x{x}\n", .{ sym[0], off }); |
| 1125 | try self.base.file.?.pwriteAll(mem.sliceAsBytes(sym[0..1]), off); | 1283 | try self.base.file.?.pwriteAll(mem.sliceAsBytes(sym[0..1]), off); |
| ... | @@ -1135,6 +1293,13 @@ fn writeOffsetTableEntry(self: *MachO, index: usize) !void { | ... | @@ -1135,6 +1293,13 @@ fn writeOffsetTableEntry(self: *MachO, index: usize) !void { |
| 1135 | try self.base.file.?.pwriteAll(&buf, off); | 1293 | try self.base.file.?.pwriteAll(&buf, off); |
| 1136 | } | 1294 | } |
| 1137 | | 1295 | |
| | 1296 | fn writeAllGlobalSymbols(self: *MachO) !void { |
| | 1297 | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab; |
| | 1298 | const off = symtab.symoff + self.local_symbols.items.len * @sizeOf(macho.nlist_64); |
| | 1299 | log.debug("writing global symbols from 0x{x} to 0x{x}\n", .{ off, self.global_symbols.items.len + off }); |
| | 1300 | try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.global_symbols.items), off); |
| | 1301 | } |
| | 1302 | |
| 1138 | /// Writes Mach-O file header. | 1303 | /// Writes Mach-O file header. |
| 1139 | /// Should be invoked last as it needs up-to-date values of ncmds and sizeof_cmds bookkeeping | 1304 | /// Should be invoked last as it needs up-to-date values of ncmds and sizeof_cmds bookkeeping |
| 1140 | /// variables. | 1305 | /// variables. |