| ... | @@ -84,9 +84,6 @@ got_section_index: ?u16 = null, | ... | @@ -84,9 +84,6 @@ got_section_index: ?u16 = null, |
| 84 | /// The absolute address of the entry point. | 84 | /// The absolute address of the entry point. |
| 85 | entry_addr: ?u64 = null, | 85 | entry_addr: ?u64 = null, |
| 86 | | 86 | |
| 87 | /// TODO move this into each Segment aggregator | | |
| 88 | linkedit_segment_next_offset: ?u32 = null, | | |
| 89 | | | |
| 90 | /// Table of all local symbols | 87 | /// Table of all local symbols |
| 91 | /// Internally references string table for names (which are optional). | 88 | /// Internally references string table for names (which are optional). |
| 92 | local_symbols: std.ArrayListUnmanaged(macho.nlist_64) = .{}, | 89 | local_symbols: std.ArrayListUnmanaged(macho.nlist_64) = .{}, |
| ... | @@ -319,10 +316,12 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { | ... | @@ -319,10 +316,12 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { |
| 319 | const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment; | 316 | const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 320 | const main_cmd = &self.load_commands.items[self.main_cmd_index.?].Main; | 317 | const main_cmd = &self.load_commands.items[self.main_cmd_index.?].Main; |
| 321 | main_cmd.entryoff = addr - text_segment.inner.vmaddr; | 318 | main_cmd.entryoff = addr - text_segment.inner.vmaddr; |
| | 319 | self.cmd_table_dirty = true; |
| 322 | } | 320 | } |
| 323 | try self.writeExportTrie(); | 321 | try self.writeExportTrie(); |
| 324 | try self.writeSymbolTable(); | 322 | try self.writeAllGlobalAndUndefSymbols(); |
| 325 | try self.writeStringTable(); | 323 | try self.writeStringTable(); |
| | 324 | try self.updateLinkeditSegmentSizes(); |
| 326 | | 325 | |
| 327 | if (target.cpu.arch == .aarch64) { | 326 | if (target.cpu.arch == .aarch64) { |
| 328 | // Preallocate space for the code signature. | 327 | // Preallocate space for the code signature. |
| ... | @@ -870,9 +869,6 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { | ... | @@ -870,9 +869,6 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { |
| 870 | return error.NotEnoughPadding; | 869 | return error.NotEnoughPadding; |
| 871 | } | 870 | } |
| 872 | | 871 | |
| 873 | const linkedit_segment = self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; | | |
| 874 | // TODO This is clunky. | | |
| 875 | self.linkedit_segment_next_offset = @intCast(u32, mem.alignForwardGeneric(u64, linkedit_segment.inner.fileoff + linkedit_segment.inner.filesize, @sizeOf(u64))); | | |
| 876 | // Add code signature load command | 872 | // Add code signature load command |
| 877 | self.code_signature_cmd_index = @intCast(u16, self.load_commands.items.len); | 873 | self.code_signature_cmd_index = @intCast(u16, self.load_commands.items.len); |
| 878 | try self.load_commands.append(self.base.allocator, .{ | 874 | try self.load_commands.append(self.base.allocator, .{ |
| ... | @@ -1073,6 +1069,8 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { | ... | @@ -1073,6 +1069,8 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { |
| 1073 | symbol.n_type = macho.N_SECT; | 1069 | symbol.n_type = macho.N_SECT; |
| 1074 | symbol.n_sect = @intCast(u8, self.text_section_index.?) + 1; | 1070 | symbol.n_sect = @intCast(u8, self.text_section_index.?) + 1; |
| 1075 | symbol.n_desc = 0; | 1071 | symbol.n_desc = 0; |
| | 1072 | |
| | 1073 | try self.writeLocalSymbol(decl.link.macho.local_sym_index); |
| 1076 | } else { | 1074 | } else { |
| 1077 | const decl_name = mem.spanZ(decl.name); | 1075 | const decl_name = mem.spanZ(decl.name); |
| 1078 | const name_str_index = try self.makeString(decl_name); | 1076 | const name_str_index = try self.makeString(decl_name); |
| ... | @@ -1088,6 +1086,8 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { | ... | @@ -1088,6 +1086,8 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { |
| 1088 | .n_value = addr, | 1086 | .n_value = addr, |
| 1089 | }; | 1087 | }; |
| 1090 | self.offset_table.items[decl.link.macho.offset_table_index] = addr; | 1088 | self.offset_table.items[decl.link.macho.offset_table_index] = addr; |
| | 1089 | |
| | 1090 | try self.writeLocalSymbol(decl.link.macho.local_sym_index); |
| 1091 | try self.writeOffsetTableEntry(decl.link.macho.offset_table_index); | 1091 | try self.writeOffsetTableEntry(decl.link.macho.offset_table_index); |
| 1092 | } | 1092 | } |
| 1093 | | 1093 | |
| ... | @@ -1361,7 +1361,7 @@ pub fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -1361,7 +1361,7 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1361 | | 1361 | |
| 1362 | const flags = macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS; | 1362 | const flags = macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS; |
| 1363 | const needed_size = @sizeOf(u64) * self.base.options.symbol_count_hint; | 1363 | const needed_size = @sizeOf(u64) * self.base.options.symbol_count_hint; |
| 1364 | const off = self.findFreeSpace(text_segment, needed_size, @sizeOf(u64)); | 1364 | const off = self.findFreeSpace(text_segment, needed_size, @alignOf(u64)); |
| 1365 | assert(off + needed_size <= text_segment.inner.fileoff + text_segment.inner.filesize); // TODO Must expand __TEXT segment. | 1365 | assert(off + needed_size <= text_segment.inner.fileoff + text_segment.inner.filesize); // TODO Must expand __TEXT segment. |
| 1366 | | 1366 | |
| 1367 | log.debug("found __ziggot section free space 0x{x} to 0x{x}\n", .{ off, off + needed_size }); | 1367 | log.debug("found __ziggot section free space 0x{x} to 0x{x}\n", .{ off, off + needed_size }); |
| ... | @@ -1406,7 +1406,6 @@ pub fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -1406,7 +1406,6 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1406 | .flags = 0, | 1406 | .flags = 0, |
| 1407 | }), | 1407 | }), |
| 1408 | }); | 1408 | }); |
| 1409 | self.linkedit_segment_next_offset = @intCast(u32, address_and_offset.offset); | | |
| 1410 | self.cmd_table_dirty = true; | 1409 | self.cmd_table_dirty = true; |
| 1411 | } | 1410 | } |
| 1412 | if (self.dyld_info_cmd_index == null) { | 1411 | if (self.dyld_info_cmd_index == null) { |
| ... | @@ -1431,8 +1430,8 @@ pub fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -1431,8 +1430,8 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1431 | .weak_bind_size = 0, | 1430 | .weak_bind_size = 0, |
| 1432 | .lazy_bind_off = 0, | 1431 | .lazy_bind_off = 0, |
| 1433 | .lazy_bind_size = 0, | 1432 | .lazy_bind_size = 0, |
| 1434 | .export_off = 0, | 1433 | .export_off = @intCast(u32, export_off), |
| 1435 | .export_size = 0, | 1434 | .export_size = export_size, |
| 1436 | }, | 1435 | }, |
| 1437 | }); | 1436 | }); |
| 1438 | self.cmd_table_dirty = true; | 1437 | self.cmd_table_dirty = true; |
| ... | @@ -1446,7 +1445,8 @@ pub fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -1446,7 +1445,8 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1446 | | 1445 | |
| 1447 | log.debug("found symbol table free space 0x{x} to 0x{x}\n", .{ symtab_off, symtab_off + symtab_size }); | 1446 | log.debug("found symbol table free space 0x{x} to 0x{x}\n", .{ symtab_off, symtab_off + symtab_size }); |
| 1448 | | 1447 | |
| 1449 | const strtab_size = 1; | 1448 | try self.string_table.append(self.base.allocator, 0); // Need a null at position 0. |
| | 1449 | const strtab_size = self.string_table.items.len; |
| 1450 | const strtab_off = self.findFreeSpace(&linkedit_segment, strtab_size, 1); | 1450 | const strtab_off = self.findFreeSpace(&linkedit_segment, strtab_size, 1); |
| 1451 | | 1451 | |
| 1452 | log.debug("found string table free space 0x{x} to 0x{x}\n", .{ strtab_off, strtab_off + strtab_size }); | 1452 | log.debug("found string table free space 0x{x} to 0x{x}\n", .{ strtab_off, strtab_off + strtab_size }); |
| ... | @@ -1455,13 +1455,14 @@ pub fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -1455,13 +1455,14 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1455 | .Symtab = .{ | 1455 | .Symtab = .{ |
| 1456 | .cmd = macho.LC_SYMTAB, | 1456 | .cmd = macho.LC_SYMTAB, |
| 1457 | .cmdsize = @sizeOf(macho.symtab_command), | 1457 | .cmdsize = @sizeOf(macho.symtab_command), |
| 1458 | .symoff = 0, | 1458 | .symoff = @intCast(u32, symtab_off), |
| 1459 | .nsyms = 0, | 1459 | .nsyms = @intCast(u32, self.base.options.symbol_count_hint), |
| 1460 | .stroff = 0, | 1460 | .stroff = @intCast(u32, strtab_off), |
| 1461 | .strsize = 0, | 1461 | .strsize = @intCast(u32, strtab_size), |
| 1462 | }, | 1462 | }, |
| 1463 | }); | 1463 | }); |
| 1464 | self.cmd_table_dirty = true; | 1464 | self.cmd_table_dirty = true; |
| | 1465 | try self.writeLocalSymbol(0); |
| 1465 | } | 1466 | } |
| 1466 | if (self.dysymtab_cmd_index == null) { | 1467 | if (self.dysymtab_cmd_index == null) { |
| 1467 | self.dysymtab_cmd_index = @intCast(u16, self.load_commands.items.len); | 1468 | self.dysymtab_cmd_index = @intCast(u16, self.load_commands.items.len); |
| ... | @@ -1577,12 +1578,6 @@ pub fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -1577,12 +1578,6 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1577 | if (self.code_signature_cmd_index == null) { | 1578 | if (self.code_signature_cmd_index == null) { |
| 1578 | self.code_signature_cmd_index = @intCast(u16, self.load_commands.items.len); | 1579 | self.code_signature_cmd_index = @intCast(u16, self.load_commands.items.len); |
| 1579 | const linkedit_segment = self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; | 1580 | const linkedit_segment = self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; |
| 1580 | | | |
| 1581 | const codesig_size = 1; | | |
| 1582 | const codesig_off = self.findFreeSpace(&linkedit_segment, codesig_size, @sizeOf(u64)); | | |
| 1583 | | | |
| 1584 | log.debug("found code signature free space 0x{x} to 0x{x}\n", .{ codesig_off, codesig_off + codesig_size }); | | |
| 1585 | | | |
| 1586 | try self.load_commands.append(self.base.allocator, .{ | 1581 | try self.load_commands.append(self.base.allocator, .{ |
| 1587 | .LinkeditData = .{ | 1582 | .LinkeditData = .{ |
| 1588 | .cmd = macho.LC_CODE_SIGNATURE, | 1583 | .cmd = macho.LC_CODE_SIGNATURE, |
| ... | @@ -1767,42 +1762,37 @@ fn allocatedSize(self: *MachO, segment: *const SegmentCommand, start: u64) u64 { | ... | @@ -1767,42 +1762,37 @@ fn allocatedSize(self: *MachO, segment: *const SegmentCommand, start: u64) u64 { |
| 1767 | // special-case it. | 1762 | // special-case it. |
| 1768 | if (self.dyld_info_cmd_index) |idx| { | 1763 | if (self.dyld_info_cmd_index) |idx| { |
| 1769 | const dyld_info = self.load_commands.items[idx].DyldInfoOnly; | 1764 | const dyld_info = self.load_commands.items[idx].DyldInfoOnly; |
| 1770 | if (dyld_info.rebase_off > start and dyld_info.rebase_off < min_pos) min_pos = off; | 1765 | if (dyld_info.rebase_off > start and dyld_info.rebase_off < min_pos) min_pos = dyld_info.rebase_off; |
| 1771 | if (dyld_info.bind_off > start and dyld_info.bind_off < min_pos) min_pos = off; | 1766 | if (dyld_info.bind_off > start and dyld_info.bind_off < min_pos) min_pos = dyld_info.bind_off; |
| 1772 | if (dyld_info.weak_bind_off > start and dyld_info.weak_bind_off < min_pos) min_pos = off; | 1767 | if (dyld_info.weak_bind_off > start and dyld_info.weak_bind_off < min_pos) min_pos = dyld_info.weak_bind_off; |
| 1773 | if (dyld_info.lazy_bind_off > start and dyld_info.lazy_bind_off < min_pos) min_pos = off; | 1768 | if (dyld_info.lazy_bind_off > start and dyld_info.lazy_bind_off < min_pos) min_pos = dyld_info.lazy_bind_off; |
| 1774 | if (dyld_info.export_off > start and dyld_info.export_off < min_pos) min_pos = off; | 1769 | if (dyld_info.export_off > start and dyld_info.export_off < min_pos) min_pos = dyld_info.export_off; |
| 1775 | } | 1770 | } |
| 1776 | | 1771 | |
| 1777 | if (self.function_starts_cmd_index) |idx| { | 1772 | if (self.function_starts_cmd_index) |idx| { |
| 1778 | const fstart = self.load_commands.items[idx].LinkeditData; | 1773 | const fstart = self.load_commands.items[idx].LinkeditData; |
| 1779 | if (fstart.dataoff > start and fstart.dataoff < min_pos) min_pos = off; | 1774 | if (fstart.dataoff > start and fstart.dataoff < min_pos) min_pos = fstart.dataoff; |
| 1780 | } | 1775 | } |
| 1781 | | 1776 | |
| 1782 | if (self.data_in_code_cmd_index) |idx| { | 1777 | if (self.data_in_code_cmd_index) |idx| { |
| 1783 | const dic = self.load_commands.items[idx].LinkeditData; | 1778 | const dic = self.load_commands.items[idx].LinkeditData; |
| 1784 | if (dic.dataoff > start and dic.dataoff < min_pos) min_pos = off; | 1779 | if (dic.dataoff > start and dic.dataoff < min_pos) min_pos = dic.dataoff; |
| 1785 | } | 1780 | } |
| 1786 | | 1781 | |
| 1787 | if (self.dysymtab_cmd_index) |idx| { | 1782 | if (self.dysymtab_cmd_index) |idx| { |
| 1788 | const dysymtab = self.load_commands.items[idx].Dysymtab; | 1783 | const dysymtab = self.load_commands.items[idx].Dysymtab; |
| 1789 | if (dysymtab.indirectsymoff > start and dysymtab.indirectsymoff < min_pos) min_pos = off; | 1784 | if (dysymtab.indirectsymoff > start and dysymtab.indirectsymoff < min_pos) min_pos = dysymtab.indirectsymoff; |
| 1790 | // TODO Handle more dynamic symbol table sections. | 1785 | // TODO Handle more dynamic symbol table sections. |
| 1791 | } | 1786 | } |
| 1792 | | 1787 | |
| 1793 | if (self.symtab_cmd_index) |idx| { | 1788 | if (self.symtab_cmd_index) |idx| { |
| 1794 | const symtab = self.load_commands.items[idx].Symtab; | 1789 | const symtab = self.load_commands.items[idx].Symtab; |
| 1795 | if (symtab.symoff > start and symtab.symoff < min_pos) min_pos = off; | 1790 | if (symtab.symoff > start and symtab.symoff < min_pos) min_pos = symtab.symoff; |
| 1796 | if (symtab.stroff > start and symtab.stroff < min_pos) min_pos = off; | 1791 | if (symtab.stroff > start and symtab.stroff < min_pos) min_pos = symtab.stroff; |
| 1797 | } | | |
| 1798 | | | |
| 1799 | if (self.code_signature_cmd_index) |idx| { | | |
| 1800 | const codesig = self.load_commands.items[idx].LinkeditData; | | |
| 1801 | if (codesig.dataoff > start and codesig.dataoff < min_pos) min_pos = off; | | |
| 1802 | } | 1792 | } |
| 1803 | } else { | 1793 | } else { |
| 1804 | for (segment.sections.items) |section| { | 1794 | for (segment.sections.items) |section| { |
| 1805 | if (section.offset > start and sections.offset < min_pos) min_pos = off; | 1795 | if (section.offset > start and section.offset < min_pos) min_pos = section.offset; |
| 1806 | } | 1796 | } |
| 1807 | } | 1797 | } |
| 1808 | | 1798 | |
| ... | @@ -1889,14 +1879,6 @@ fn detectAllocCollision(self: *MachO, segment: *const SegmentCommand, start: u64 | ... | @@ -1889,14 +1879,6 @@ fn detectAllocCollision(self: *MachO, segment: *const SegmentCommand, start: u64 |
| 1889 | return pos; | 1879 | return pos; |
| 1890 | } | 1880 | } |
| 1891 | } | 1881 | } |
| 1892 | | | |
| 1893 | if (self.code_signature_cmd_index) |idx| outer: { | | |
| 1894 | if (self.load_commands.items.len == idx) break :outer; | | |
| 1895 | const codesig = self.load_commands.items[idx].LinkeditData; | | |
| 1896 | if (checkForCollision(start, end, codesig.dataoff, codesig.datasize)) |pos| { | | |
| 1897 | return pos; | | |
| 1898 | } | | |
| 1899 | } | | |
| 1900 | } else { | 1882 | } else { |
| 1901 | for (segment.sections.items) |section| { | 1883 | for (segment.sections.items) |section| { |
| 1902 | if (checkForCollision(start, end, section.offset, section.size)) |pos| { | 1884 | if (checkForCollision(start, end, section.offset, section.size)) |pos| { |
| ... | @@ -1958,14 +1940,79 @@ fn writeOffsetTableEntry(self: *MachO, index: usize) !void { | ... | @@ -1958,14 +1940,79 @@ fn writeOffsetTableEntry(self: *MachO, index: usize) !void { |
| 1958 | try self.base.file.?.pwriteAll(&code, off); | 1940 | try self.base.file.?.pwriteAll(&code, off); |
| 1959 | } | 1941 | } |
| 1960 | | 1942 | |
| 1961 | fn writeSymbolTable(self: *MachO) !void { | 1943 | fn writeLocalSymbol(self: *MachO, index: usize) !void { |
| 1962 | // TODO workout how we can cache these so that we only overwrite symbols that were updated | 1944 | const tracy = trace(@src()); |
| | 1945 | defer tracy.end(); |
| | 1946 | |
| 1963 | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab; | 1947 | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab; |
| | 1948 | const nlocals = self.local_symbols.items.len; |
| | 1949 | const nglobals = self.global_symbols.items.len; |
| | 1950 | const nundefs = self.undef_symbols.items.len; |
| | 1951 | const nsyms = nlocals + nglobals + nundefs; |
| 1964 | | 1952 | |
| 1965 | const locals_off = self.linkedit_segment_next_offset.?; | 1953 | if (symtab.nsyms < nsyms) { |
| | 1954 | const linkedit_segment = self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; |
| | 1955 | const needed_size = nsyms * @sizeOf(macho.nlist_64); |
| | 1956 | if (needed_size > self.allocatedSize(&linkedit_segment, symtab.symoff)) { |
| | 1957 | // Move the entire symbol table to a new location |
| | 1958 | const new_symoff = self.findFreeSpace(&linkedit_segment, needed_size, @alignOf(macho.nlist_64)); |
| | 1959 | const existing_size = symtab.nsyms * @sizeOf(macho.nlist_64); |
| | 1960 | |
| | 1961 | log.debug("relocating symbol table from 0x{x}-0x{x} to 0x{x}-0x{x}", .{ |
| | 1962 | symtab.symoff, |
| | 1963 | symtab.symoff + existing_size, |
| | 1964 | new_symoff, |
| | 1965 | new_symoff + existing_size, |
| | 1966 | }); |
| | 1967 | |
| | 1968 | const amt = try self.base.file.?.copyRangeAll(symtab.symoff, self.base.file.?, new_symoff, existing_size); |
| | 1969 | if (amt != existing_size) return error.InputOutput; |
| | 1970 | symtab.symoff = @intCast(u32, new_symoff); |
| | 1971 | } |
| | 1972 | symtab.nsyms = @intCast(u32, nsyms); |
| | 1973 | self.cmd_table_dirty = true; |
| | 1974 | } |
| | 1975 | |
| | 1976 | const off = symtab.symoff + @sizeOf(macho.nlist_64) * index; |
| | 1977 | log.debug("writing local symbol {} at 0x{x}", .{ index, off }); |
| | 1978 | try self.base.file.?.pwriteAll(mem.asBytes(&self.local_symbols.items[index]), off); |
| | 1979 | } |
| | 1980 | |
| | 1981 | fn writeAllGlobalAndUndefSymbols(self: *MachO) !void { |
| | 1982 | const tracy = trace(@src()); |
| | 1983 | defer tracy.end(); |
| | 1984 | |
| | 1985 | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab; |
| | 1986 | const nlocals = self.local_symbols.items.len; |
| | 1987 | const nglobals = self.global_symbols.items.len; |
| | 1988 | const nundefs = self.undef_symbols.items.len; |
| | 1989 | const nsyms = nlocals + nglobals + nundefs; |
| | 1990 | |
| | 1991 | if (symtab.nsyms < nsyms) { |
| | 1992 | const linkedit_segment = self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; |
| | 1993 | const needed_size = nsyms * @sizeOf(macho.nlist_64); |
| | 1994 | if (needed_size > self.allocatedSize(&linkedit_segment, symtab.symoff)) { |
| | 1995 | // Move the entire symbol table to a new location |
| | 1996 | const new_symoff = self.findFreeSpace(&linkedit_segment, needed_size, @alignOf(macho.nlist_64)); |
| | 1997 | const existing_size = symtab.nsyms * @sizeOf(macho.nlist_64); |
| | 1998 | |
| | 1999 | log.debug("relocating symbol table from 0x{x}-0x{x} to 0x{x}-0x{x}", .{ |
| | 2000 | symtab.symoff, |
| | 2001 | symtab.symoff + existing_size, |
| | 2002 | new_symoff, |
| | 2003 | new_symoff + existing_size, |
| | 2004 | }); |
| | 2005 | |
| | 2006 | const amt = try self.base.file.?.copyRangeAll(symtab.symoff, self.base.file.?, new_symoff, existing_size); |
| | 2007 | if (amt != existing_size) return error.InputOutput; |
| | 2008 | symtab.symoff = @intCast(u32, new_symoff); |
| | 2009 | } |
| | 2010 | symtab.nsyms = @intCast(u32, nsyms); |
| | 2011 | self.cmd_table_dirty = true; |
| | 2012 | } |
| | 2013 | |
| | 2014 | const locals_off = symtab.symoff; |
| 1966 | const locals_size = self.local_symbols.items.len * @sizeOf(macho.nlist_64); | 2015 | const locals_size = self.local_symbols.items.len * @sizeOf(macho.nlist_64); |
| 1967 | log.debug("writing local symbols from 0x{x} to 0x{x}\n", .{ locals_off, locals_size + locals_off }); | | |
| 1968 | try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.local_symbols.items), locals_off); | | |
| 1969 | | 2016 | |
| 1970 | const globals_off = locals_off + locals_size; | 2017 | const globals_off = locals_off + locals_size; |
| 1971 | const globals_size = self.global_symbols.items.len * @sizeOf(macho.nlist_64); | 2018 | const globals_size = self.global_symbols.items.len * @sizeOf(macho.nlist_64); |
| ... | @@ -1977,44 +2024,31 @@ fn writeSymbolTable(self: *MachO) !void { | ... | @@ -1977,44 +2024,31 @@ fn writeSymbolTable(self: *MachO) !void { |
| 1977 | log.debug("writing undef symbols from 0x{x} to 0x{x}\n", .{ undefs_off, undefs_size + undefs_off }); | 2024 | log.debug("writing undef symbols from 0x{x} to 0x{x}\n", .{ undefs_off, undefs_size + undefs_off }); |
| 1978 | try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.undef_symbols.items), undefs_off); | 2025 | try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.undef_symbols.items), undefs_off); |
| 1979 | | 2026 | |
| 1980 | // Update symbol table. | | |
| 1981 | const nlocals = @intCast(u32, self.local_symbols.items.len); | | |
| 1982 | const nglobals = @intCast(u32, self.global_symbols.items.len); | | |
| 1983 | const nundefs = @intCast(u32, self.undef_symbols.items.len); | | |
| 1984 | symtab.symoff = self.linkedit_segment_next_offset.?; | | |
| 1985 | symtab.nsyms = nlocals + nglobals + nundefs; | | |
| 1986 | self.linkedit_segment_next_offset = symtab.symoff + symtab.nsyms * @sizeOf(macho.nlist_64); | | |
| 1987 | | | |
| 1988 | // Update dynamic symbol table. | 2027 | // Update dynamic symbol table. |
| 1989 | const dysymtab = &self.load_commands.items[self.dysymtab_cmd_index.?].Dysymtab; | 2028 | const dysymtab = &self.load_commands.items[self.dysymtab_cmd_index.?].Dysymtab; |
| 1990 | dysymtab.nlocalsym = nlocals; | 2029 | dysymtab.nlocalsym = @intCast(u32, nlocals); |
| 1991 | dysymtab.iextdefsym = nlocals; | 2030 | dysymtab.iextdefsym = @intCast(u32, nlocals); |
| 1992 | dysymtab.nextdefsym = nglobals; | 2031 | dysymtab.nextdefsym = @intCast(u32, nglobals); |
| 1993 | dysymtab.iundefsym = nlocals + nglobals; | 2032 | dysymtab.iundefsym = @intCast(u32, nlocals + nglobals); |
| 1994 | dysymtab.nundefsym = nundefs; | 2033 | dysymtab.nundefsym = @intCast(u32, nundefs); |
| 1995 | | | |
| 1996 | // Advance size of __LINKEDIT segment | | |
| 1997 | const linkedit = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; | | |
| 1998 | linkedit.inner.filesize += symtab.nsyms * @sizeOf(macho.nlist_64); | | |
| 1999 | if (linkedit.inner.vmsize < linkedit.inner.filesize) { | | |
| 2000 | linkedit.inner.vmsize = mem.alignForwardGeneric(u64, linkedit.inner.filesize, self.page_size); | | |
| 2001 | } | | |
| 2002 | self.cmd_table_dirty = true; | 2034 | self.cmd_table_dirty = true; |
| 2003 | } | 2035 | } |
| 2004 | | 2036 | |
| 2005 | fn writeCodeSignaturePadding(self: *MachO) !void { | 2037 | fn writeCodeSignaturePadding(self: *MachO) !void { |
| | 2038 | const tracy = trace(@src()); |
| | 2039 | defer tracy.end(); |
| | 2040 | |
| | 2041 | const linkedit_segment = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; |
| 2006 | const code_sig_cmd = &self.load_commands.items[self.code_signature_cmd_index.?].LinkeditData; | 2042 | const code_sig_cmd = &self.load_commands.items[self.code_signature_cmd_index.?].LinkeditData; |
| 2007 | const fileoff = self.linkedit_segment_next_offset.?; | 2043 | const fileoff = linkedit_segment.inner.fileoff + linkedit_segment.inner.filesize; |
| 2008 | const datasize = CodeSignature.calcCodeSignaturePadding(self.base.options.emit.?.sub_path, fileoff); | 2044 | const datasize = CodeSignature.calcCodeSignaturePadding(self.base.options.emit.?.sub_path, fileoff); |
| 2009 | code_sig_cmd.dataoff = fileoff; | 2045 | code_sig_cmd.dataoff = @intCast(u32, fileoff); |
| 2010 | code_sig_cmd.datasize = datasize; | 2046 | code_sig_cmd.datasize = datasize; |
| 2011 | | 2047 | |
| 2012 | self.linkedit_segment_next_offset = fileoff + datasize; | | |
| 2013 | // Advance size of __LINKEDIT segment | 2048 | // Advance size of __LINKEDIT segment |
| 2014 | const linkedit = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; | 2049 | linkedit_segment.inner.filesize += datasize; |
| 2015 | linkedit.inner.filesize += datasize; | 2050 | if (linkedit_segment.inner.vmsize < linkedit_segment.inner.filesize) { |
| 2016 | if (linkedit.inner.vmsize < linkedit.inner.filesize) { | 2051 | linkedit_segment.inner.vmsize = mem.alignForwardGeneric(u64, linkedit_segment.inner.filesize, self.page_size); |
| 2017 | linkedit.inner.vmsize = mem.alignForwardGeneric(u64, linkedit.inner.filesize, self.page_size); | | |
| 2018 | } | 2052 | } |
| 2019 | log.debug("writing code signature padding from 0x{x} to 0x{x}\n", .{ fileoff, fileoff + datasize }); | 2053 | log.debug("writing code signature padding from 0x{x} to 0x{x}\n", .{ fileoff, fileoff + datasize }); |
| 2020 | // Pad out the space. We need to do this to calculate valid hashes for everything in the file | 2054 | // Pad out the space. We need to do this to calculate valid hashes for everything in the file |
| ... | @@ -2023,6 +2057,9 @@ fn writeCodeSignaturePadding(self: *MachO) !void { | ... | @@ -2023,6 +2057,9 @@ fn writeCodeSignaturePadding(self: *MachO) !void { |
| 2023 | } | 2057 | } |
| 2024 | | 2058 | |
| 2025 | fn writeCodeSignature(self: *MachO) !void { | 2059 | fn writeCodeSignature(self: *MachO) !void { |
| | 2060 | const tracy = trace(@src()); |
| | 2061 | defer tracy.end(); |
| | 2062 | |
| 2026 | const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment; | 2063 | const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 2027 | const code_sig_cmd = self.load_commands.items[self.code_signature_cmd_index.?].LinkeditData; | 2064 | const code_sig_cmd = self.load_commands.items[self.code_signature_cmd_index.?].LinkeditData; |
| 2028 | | 2065 | |
| ... | @@ -2048,6 +2085,9 @@ fn writeCodeSignature(self: *MachO) !void { | ... | @@ -2048,6 +2085,9 @@ fn writeCodeSignature(self: *MachO) !void { |
| 2048 | fn writeExportTrie(self: *MachO) !void { | 2085 | fn writeExportTrie(self: *MachO) !void { |
| 2049 | if (self.global_symbols.items.len == 0) return; | 2086 | if (self.global_symbols.items.len == 0) return; |
| 2050 | | 2087 | |
| | 2088 | const tracy = trace(@src()); |
| | 2089 | defer tracy.end(); |
| | 2090 | |
| 2051 | var trie = Trie.init(self.base.allocator); | 2091 | var trie = Trie.init(self.base.allocator); |
| 2052 | defer trie.deinit(); | 2092 | defer trie.deinit(); |
| 2053 | | 2093 | |
| ... | @@ -2070,26 +2110,19 @@ fn writeExportTrie(self: *MachO) !void { | ... | @@ -2070,26 +2110,19 @@ fn writeExportTrie(self: *MachO) !void { |
| 2070 | const nwritten = try trie.write(stream.writer()); | 2110 | const nwritten = try trie.write(stream.writer()); |
| 2071 | assert(nwritten == trie.size); | 2111 | assert(nwritten == trie.size); |
| 2072 | | 2112 | |
| | 2113 | const linkedit_segment = self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; |
| 2073 | const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly; | 2114 | const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly; |
| 2074 | const export_size = @intCast(u32, mem.alignForward(buffer.len, @sizeOf(u64))); | 2115 | const allocated_size = self.allocatedSize(&linkedit_segment, dyld_info.export_off); |
| 2075 | dyld_info.export_off = self.linkedit_segment_next_offset.?; | 2116 | const needed_size = mem.alignForwardGeneric(u64, buffer.len, @alignOf(u64)); |
| 2076 | dyld_info.export_size = export_size; | | |
| 2077 | | | |
| 2078 | log.debug("writing export trie from 0x{x} to 0x{x}\n", .{ dyld_info.export_off, dyld_info.export_off + export_size }); | | |
| 2079 | | 2117 | |
| 2080 | if (export_size > buffer.len) { | 2118 | if (needed_size > allocated_size) { |
| 2081 | // Pad out to align(8). | 2119 | dyld_info.export_off = 0; |
| 2082 | try self.base.file.?.pwriteAll(&[_]u8{0}, dyld_info.export_off + export_size); | 2120 | dyld_info.export_off = @intCast(u32, self.findFreeSpace(&linkedit_segment, needed_size, 1)); |
| 2083 | } | 2121 | } |
| 2084 | try self.base.file.?.pwriteAll(buffer, dyld_info.export_off); | 2122 | dyld_info.export_size = @intCast(u32, needed_size); |
| | 2123 | log.debug("writing export trie from 0x{x} to 0x{x}\n", .{ dyld_info.export_off, dyld_info.export_off + dyld_info.export_size }); |
| 2085 | | 2124 | |
| 2086 | self.linkedit_segment_next_offset = dyld_info.export_off + dyld_info.export_size; | 2125 | try self.base.file.?.pwriteAll(buffer, dyld_info.export_off); |
| 2087 | // Advance size of __LINKEDIT segment | | |
| 2088 | const linkedit = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; | | |
| 2089 | linkedit.inner.filesize += dyld_info.export_size; | | |
| 2090 | if (linkedit.inner.vmsize < linkedit.inner.filesize) { | | |
| 2091 | linkedit.inner.vmsize = mem.alignForwardGeneric(u64, linkedit.inner.filesize, self.page_size); | | |
| 2092 | } | | |
| 2093 | self.cmd_table_dirty = true; | 2126 | self.cmd_table_dirty = true; |
| 2094 | } | 2127 | } |
| 2095 | | 2128 | |
| ... | @@ -2156,30 +2189,68 @@ fn writeLazyBindingInfoTable(self: *MachO) !void { | ... | @@ -2156,30 +2189,68 @@ fn writeLazyBindingInfoTable(self: *MachO) !void { |
| 2156 | } | 2189 | } |
| 2157 | | 2190 | |
| 2158 | fn writeStringTable(self: *MachO) !void { | 2191 | fn writeStringTable(self: *MachO) !void { |
| 2159 | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab; | 2192 | const tracy = trace(@src()); |
| 2160 | const needed_size = self.string_table.items.len; | 2193 | defer tracy.end(); |
| 2161 | | 2194 | |
| 2162 | symtab.stroff = self.linkedit_segment_next_offset.?; | 2195 | const linkedit_segment = self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; |
| 2163 | symtab.strsize = @intCast(u32, mem.alignForward(needed_size, @sizeOf(u64))); | 2196 | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab; |
| | 2197 | const allocated_size = self.allocatedSize(&linkedit_segment, symtab.stroff); |
| | 2198 | const needed_size = mem.alignForwardGeneric(u64, self.string_table.items.len, @alignOf(u64)); |
| 2164 | | 2199 | |
| | 2200 | if (needed_size > allocated_size) { |
| | 2201 | symtab.strsize = 0; |
| | 2202 | symtab.stroff = @intCast(u32, self.findFreeSpace(&linkedit_segment, needed_size, 1)); |
| | 2203 | } |
| | 2204 | symtab.strsize = @intCast(u32, needed_size); |
| 2165 | log.debug("writing string table from 0x{x} to 0x{x}\n", .{ symtab.stroff, symtab.stroff + symtab.strsize }); | 2205 | log.debug("writing string table from 0x{x} to 0x{x}\n", .{ symtab.stroff, symtab.stroff + symtab.strsize }); |
| 2166 | | 2206 | |
| 2167 | if (symtab.strsize > needed_size) { | | |
| 2168 | // Pad out to align(8); | | |
| 2169 | try self.base.file.?.pwriteAll(&[_]u8{0}, symtab.stroff + symtab.strsize); | | |
| 2170 | } | | |
| 2171 | try self.base.file.?.pwriteAll(self.string_table.items, symtab.stroff); | 2207 | try self.base.file.?.pwriteAll(self.string_table.items, symtab.stroff); |
| 2172 | | | |
| 2173 | self.linkedit_segment_next_offset = symtab.stroff + symtab.strsize; | | |
| 2174 | // Advance size of __LINKEDIT segment | | |
| 2175 | const linkedit = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; | | |
| 2176 | linkedit.inner.filesize += symtab.strsize; | | |
| 2177 | if (linkedit.inner.vmsize < linkedit.inner.filesize) { | | |
| 2178 | linkedit.inner.vmsize = mem.alignForwardGeneric(u64, linkedit.inner.filesize, self.page_size); | | |
| 2179 | } | | |
| 2180 | self.cmd_table_dirty = true; | 2208 | self.cmd_table_dirty = true; |
| 2181 | } | 2209 | } |
| 2182 | | 2210 | |
| | 2211 | fn updateLinkeditSegmentSizes(self: *MachO) !void { |
| | 2212 | const tracy = trace(@src()); |
| | 2213 | defer tracy.end(); |
| | 2214 | |
| | 2215 | // Now, we are in position to update __LINKEDIT segment sizes. |
| | 2216 | // TODO Add checkpointing so that we don't have to do this every single time. |
| | 2217 | const linkedit_segment = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; |
| | 2218 | var final_offset = linkedit_segment.inner.fileoff; |
| | 2219 | |
| | 2220 | if (self.dyld_info_cmd_index) |idx| { |
| | 2221 | const dyld_info = self.load_commands.items[idx].DyldInfoOnly; |
| | 2222 | final_offset = std.math.max(final_offset, dyld_info.rebase_off + dyld_info.rebase_size); |
| | 2223 | final_offset = std.math.max(final_offset, dyld_info.bind_off + dyld_info.bind_size); |
| | 2224 | final_offset = std.math.max(final_offset, dyld_info.weak_bind_off + dyld_info.weak_bind_size); |
| | 2225 | final_offset = std.math.max(final_offset, dyld_info.lazy_bind_off + dyld_info.lazy_bind_size); |
| | 2226 | final_offset = std.math.max(final_offset, dyld_info.export_off + dyld_info.export_size); |
| | 2227 | } |
| | 2228 | if (self.function_starts_cmd_index) |idx| { |
| | 2229 | const fstart = self.load_commands.items[idx].LinkeditData; |
| | 2230 | final_offset = std.math.max(final_offset, fstart.dataoff + fstart.datasize); |
| | 2231 | } |
| | 2232 | if (self.data_in_code_cmd_index) |idx| { |
| | 2233 | const dic = self.load_commands.items[idx].LinkeditData; |
| | 2234 | final_offset = std.math.max(final_offset, dic.dataoff + dic.datasize); |
| | 2235 | } |
| | 2236 | if (self.dysymtab_cmd_index) |idx| { |
| | 2237 | const dysymtab = self.load_commands.items[idx].Dysymtab; |
| | 2238 | const nindirectsize = dysymtab.nindirectsyms * @sizeOf(u32); |
| | 2239 | final_offset = std.math.max(final_offset, dysymtab.indirectsymoff + nindirectsize); |
| | 2240 | // TODO Handle more dynamic symbol table sections. |
| | 2241 | } |
| | 2242 | if (self.symtab_cmd_index) |idx| { |
| | 2243 | const symtab = self.load_commands.items[idx].Symtab; |
| | 2244 | const symsize = symtab.nsyms * @sizeOf(macho.nlist_64); |
| | 2245 | final_offset = std.math.max(final_offset, symtab.symoff + symsize); |
| | 2246 | final_offset = std.math.max(final_offset, symtab.stroff + symtab.strsize); |
| | 2247 | } |
| | 2248 | |
| | 2249 | const filesize = final_offset - linkedit_segment.inner.fileoff; |
| | 2250 | linkedit_segment.inner.filesize = filesize; |
| | 2251 | linkedit_segment.inner.vmsize = mem.alignForwardGeneric(u64, filesize, self.page_size); |
| | 2252 | } |
| | 2253 | |
| 2183 | /// Writes all load commands and section headers. | 2254 | /// Writes all load commands and section headers. |
| 2184 | fn writeLoadCommands(self: *MachO) !void { | 2255 | fn writeLoadCommands(self: *MachO) !void { |
| 2185 | var sizeofcmds: usize = 0; | 2256 | var sizeofcmds: usize = 0; |