| ... | ... | @@ -84,9 +84,6 @@ got_section_index: ?u16 = null, |
| 84 | 84 | /// The absolute address of the entry point. |
| 85 | 85 | entry_addr: ?u64 = null, |
| 86 | 86 | |
| 87 | | /// TODO move this into each Segment aggregator |
| 88 | | linkedit_segment_next_offset: ?u32 = null, |
| 89 | | |
| 90 | 87 | /// Table of all local symbols |
| 91 | 88 | /// Internally references string table for names (which are optional). |
| 92 | 89 | local_symbols: std.ArrayListUnmanaged(macho.nlist_64) = .{}, |
| ... | ... | @@ -319,10 +316,12 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { |
| 319 | 316 | const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 320 | 317 | const main_cmd = &self.load_commands.items[self.main_cmd_index.?].Main; |
| 321 | 318 | main_cmd.entryoff = addr - text_segment.inner.vmaddr; |
| 319 | self.cmd_table_dirty = true; |
| 322 | 320 | } |
| 323 | 321 | try self.writeExportTrie(); |
| 324 | | try self.writeSymbolTable(); |
| 322 | try self.writeAllGlobalAndUndefSymbols(); |
| 325 | 323 | try self.writeStringTable(); |
| 324 | try self.updateLinkeditSegmentSizes(); |
| 326 | 325 | |
| 327 | 326 | if (target.cpu.arch == .aarch64) { |
| 328 | 327 | // Preallocate space for the code signature. |
| ... | ... | @@ -870,9 +869,6 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { |
| 870 | 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 | 872 | // Add code signature load command |
| 877 | 873 | self.code_signature_cmd_index = @intCast(u16, self.load_commands.items.len); |
| 878 | 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 | 1069 | symbol.n_type = macho.N_SECT; |
| 1074 | 1070 | symbol.n_sect = @intCast(u8, self.text_section_index.?) + 1; |
| 1075 | 1071 | symbol.n_desc = 0; |
| 1072 | |
| 1073 | try self.writeLocalSymbol(decl.link.macho.local_sym_index); |
| 1076 | 1074 | } else { |
| 1077 | 1075 | const decl_name = mem.spanZ(decl.name); |
| 1078 | 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 | 1086 | .n_value = addr, |
| 1089 | 1087 | }; |
| 1090 | 1088 | self.offset_table.items[decl.link.macho.offset_table_index] = addr; |
| 1089 | |
| 1090 | try self.writeLocalSymbol(decl.link.macho.local_sym_index); |
| 1091 | 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 | 1361 | |
| 1362 | 1362 | const flags = macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS; |
| 1363 | 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 | 1365 | assert(off + needed_size <= text_segment.inner.fileoff + text_segment.inner.filesize); // TODO Must expand __TEXT segment. |
| 1366 | 1366 | |
| 1367 | 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 | 1406 | .flags = 0, |
| 1407 | 1407 | }), |
| 1408 | 1408 | }); |
| 1409 | | self.linkedit_segment_next_offset = @intCast(u32, address_and_offset.offset); |
| 1410 | 1409 | self.cmd_table_dirty = true; |
| 1411 | 1410 | } |
| 1412 | 1411 | if (self.dyld_info_cmd_index == null) { |
| ... | ... | @@ -1431,8 +1430,8 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1431 | 1430 | .weak_bind_size = 0, |
| 1432 | 1431 | .lazy_bind_off = 0, |
| 1433 | 1432 | .lazy_bind_size = 0, |
| 1434 | | .export_off = 0, |
| 1435 | | .export_size = 0, |
| 1433 | .export_off = @intCast(u32, export_off), |
| 1434 | .export_size = export_size, |
| 1436 | 1435 | }, |
| 1437 | 1436 | }); |
| 1438 | 1437 | self.cmd_table_dirty = true; |
| ... | ... | @@ -1446,7 +1445,8 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1446 | 1445 | |
| 1447 | 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 | 1450 | const strtab_off = self.findFreeSpace(&linkedit_segment, strtab_size, 1); |
| 1451 | 1451 | |
| 1452 | 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 | 1455 | .Symtab = .{ |
| 1456 | 1456 | .cmd = macho.LC_SYMTAB, |
| 1457 | 1457 | .cmdsize = @sizeOf(macho.symtab_command), |
| 1458 | | .symoff = 0, |
| 1459 | | .nsyms = 0, |
| 1460 | | .stroff = 0, |
| 1461 | | .strsize = 0, |
| 1458 | .symoff = @intCast(u32, symtab_off), |
| 1459 | .nsyms = @intCast(u32, self.base.options.symbol_count_hint), |
| 1460 | .stroff = @intCast(u32, strtab_off), |
| 1461 | .strsize = @intCast(u32, strtab_size), |
| 1462 | 1462 | }, |
| 1463 | 1463 | }); |
| 1464 | 1464 | self.cmd_table_dirty = true; |
| 1465 | try self.writeLocalSymbol(0); |
| 1465 | 1466 | } |
| 1466 | 1467 | if (self.dysymtab_cmd_index == null) { |
| 1467 | 1468 | self.dysymtab_cmd_index = @intCast(u16, self.load_commands.items.len); |
| ... | ... | @@ -1577,12 +1578,6 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1577 | 1578 | if (self.code_signature_cmd_index == null) { |
| 1578 | 1579 | self.code_signature_cmd_index = @intCast(u16, self.load_commands.items.len); |
| 1579 | 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 | 1581 | try self.load_commands.append(self.base.allocator, .{ |
| 1587 | 1582 | .LinkeditData = .{ |
| 1588 | 1583 | .cmd = macho.LC_CODE_SIGNATURE, |
| ... | ... | @@ -1767,42 +1762,37 @@ fn allocatedSize(self: *MachO, segment: *const SegmentCommand, start: u64) u64 { |
| 1767 | 1762 | // special-case it. |
| 1768 | 1763 | if (self.dyld_info_cmd_index) |idx| { |
| 1769 | 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; |
| 1771 | | if (dyld_info.bind_off > start and dyld_info.bind_off < min_pos) min_pos = off; |
| 1772 | | if (dyld_info.weak_bind_off > start and dyld_info.weak_bind_off < min_pos) min_pos = off; |
| 1773 | | if (dyld_info.lazy_bind_off > start and dyld_info.lazy_bind_off < min_pos) min_pos = off; |
| 1774 | | if (dyld_info.export_off > start and dyld_info.export_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; |
| 1766 | if (dyld_info.bind_off > start and dyld_info.bind_off < min_pos) min_pos = dyld_info.bind_off; |
| 1767 | if (dyld_info.weak_bind_off > start and dyld_info.weak_bind_off < min_pos) min_pos = dyld_info.weak_bind_off; |
| 1768 | if (dyld_info.lazy_bind_off > start and dyld_info.lazy_bind_off < min_pos) min_pos = dyld_info.lazy_bind_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 | 1772 | if (self.function_starts_cmd_index) |idx| { |
| 1778 | 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 | 1777 | if (self.data_in_code_cmd_index) |idx| { |
| 1783 | 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 | 1782 | if (self.dysymtab_cmd_index) |idx| { |
| 1788 | 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 | 1785 | // TODO Handle more dynamic symbol table sections. |
| 1791 | 1786 | } |
| 1792 | 1787 | |
| 1793 | 1788 | if (self.symtab_cmd_index) |idx| { |
| 1794 | 1789 | const symtab = self.load_commands.items[idx].Symtab; |
| 1795 | | if (symtab.symoff > start and symtab.symoff < min_pos) min_pos = off; |
| 1796 | | if (symtab.stroff > start and symtab.stroff < min_pos) min_pos = off; |
| 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; |
| 1790 | if (symtab.symoff > start and symtab.symoff < min_pos) min_pos = symtab.symoff; |
| 1791 | if (symtab.stroff > start and symtab.stroff < min_pos) min_pos = symtab.stroff; |
| 1802 | 1792 | } |
| 1803 | 1793 | } else { |
| 1804 | 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 | 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 | 1882 | } else { |
| 1901 | 1883 | for (segment.sections.items) |section| { |
| 1902 | 1884 | if (checkForCollision(start, end, section.offset, section.size)) |pos| { |
| ... | ... | @@ -1958,14 +1940,79 @@ fn writeOffsetTableEntry(self: *MachO, index: usize) !void { |
| 1958 | 1940 | try self.base.file.?.pwriteAll(&code, off); |
| 1959 | 1941 | } |
| 1960 | 1942 | |
| 1961 | | fn writeSymbolTable(self: *MachO) !void { |
| 1962 | | // TODO workout how we can cache these so that we only overwrite symbols that were updated |
| 1943 | fn writeLocalSymbol(self: *MachO, index: usize) !void { |
| 1944 | const tracy = trace(@src()); |
| 1945 | defer tracy.end(); |
| 1946 | |
| 1963 | 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 | 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 | 2017 | const globals_off = locals_off + locals_size; |
| 1971 | 2018 | const globals_size = self.global_symbols.items.len * @sizeOf(macho.nlist_64); |
| ... | ... | @@ -1977,44 +2024,31 @@ fn writeSymbolTable(self: *MachO) !void { |
| 1977 | 2024 | log.debug("writing undef symbols from 0x{x} to 0x{x}\n", .{ undefs_off, undefs_size + undefs_off }); |
| 1978 | 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 | 2027 | // Update dynamic symbol table. |
| 1989 | 2028 | const dysymtab = &self.load_commands.items[self.dysymtab_cmd_index.?].Dysymtab; |
| 1990 | | dysymtab.nlocalsym = nlocals; |
| 1991 | | dysymtab.iextdefsym = nlocals; |
| 1992 | | dysymtab.nextdefsym = nglobals; |
| 1993 | | dysymtab.iundefsym = nlocals + nglobals; |
| 1994 | | dysymtab.nundefsym = 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 | | } |
| 2029 | dysymtab.nlocalsym = @intCast(u32, nlocals); |
| 2030 | dysymtab.iextdefsym = @intCast(u32, nlocals); |
| 2031 | dysymtab.nextdefsym = @intCast(u32, nglobals); |
| 2032 | dysymtab.iundefsym = @intCast(u32, nlocals + nglobals); |
| 2033 | dysymtab.nundefsym = @intCast(u32, nundefs); |
| 2002 | 2034 | self.cmd_table_dirty = true; |
| 2003 | 2035 | } |
| 2004 | 2036 | |
| 2005 | 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 | 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 | 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 | 2046 | code_sig_cmd.datasize = datasize; |
| 2011 | 2047 | |
| 2012 | | self.linkedit_segment_next_offset = fileoff + datasize; |
| 2013 | 2048 | // Advance size of __LINKEDIT segment |
| 2014 | | const linkedit = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; |
| 2015 | | linkedit.inner.filesize += datasize; |
| 2016 | | if (linkedit.inner.vmsize < linkedit.inner.filesize) { |
| 2017 | | linkedit.inner.vmsize = mem.alignForwardGeneric(u64, linkedit.inner.filesize, self.page_size); |
| 2049 | linkedit_segment.inner.filesize += datasize; |
| 2050 | if (linkedit_segment.inner.vmsize < linkedit_segment.inner.filesize) { |
| 2051 | linkedit_segment.inner.vmsize = mem.alignForwardGeneric(u64, linkedit_segment.inner.filesize, self.page_size); |
| 2018 | 2052 | } |
| 2019 | 2053 | log.debug("writing code signature padding from 0x{x} to 0x{x}\n", .{ fileoff, fileoff + datasize }); |
| 2020 | 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 | 2057 | } |
| 2024 | 2058 | |
| 2025 | 2059 | fn writeCodeSignature(self: *MachO) !void { |
| 2060 | const tracy = trace(@src()); |
| 2061 | defer tracy.end(); |
| 2062 | |
| 2026 | 2063 | const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 2027 | 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 | 2085 | fn writeExportTrie(self: *MachO) !void { |
| 2049 | 2086 | if (self.global_symbols.items.len == 0) return; |
| 2050 | 2087 | |
| 2088 | const tracy = trace(@src()); |
| 2089 | defer tracy.end(); |
| 2090 | |
| 2051 | 2091 | var trie = Trie.init(self.base.allocator); |
| 2052 | 2092 | defer trie.deinit(); |
| 2053 | 2093 | |
| ... | ... | @@ -2070,26 +2110,19 @@ fn writeExportTrie(self: *MachO) !void { |
| 2070 | 2110 | const nwritten = try trie.write(stream.writer()); |
| 2071 | 2111 | assert(nwritten == trie.size); |
| 2072 | 2112 | |
| 2113 | const linkedit_segment = self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; |
| 2073 | 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))); |
| 2075 | | dyld_info.export_off = self.linkedit_segment_next_offset.?; |
| 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 }); |
| 2115 | const allocated_size = self.allocatedSize(&linkedit_segment, dyld_info.export_off); |
| 2116 | const needed_size = mem.alignForwardGeneric(u64, buffer.len, @alignOf(u64)); |
| 2079 | 2117 | |
| 2080 | | if (export_size > buffer.len) { |
| 2081 | | // Pad out to align(8). |
| 2082 | | try self.base.file.?.pwriteAll(&[_]u8{0}, dyld_info.export_off + export_size); |
| 2118 | if (needed_size > allocated_size) { |
| 2119 | dyld_info.export_off = 0; |
| 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; |
| 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 | | } |
| 2125 | try self.base.file.?.pwriteAll(buffer, dyld_info.export_off); |
| 2093 | 2126 | self.cmd_table_dirty = true; |
| 2094 | 2127 | } |
| 2095 | 2128 | |
| ... | ... | @@ -2156,30 +2189,68 @@ fn writeLazyBindingInfoTable(self: *MachO) !void { |
| 2156 | 2189 | } |
| 2157 | 2190 | |
| 2158 | 2191 | fn writeStringTable(self: *MachO) !void { |
| 2159 | | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab; |
| 2160 | | const needed_size = self.string_table.items.len; |
| 2192 | const tracy = trace(@src()); |
| 2193 | defer tracy.end(); |
| 2161 | 2194 | |
| 2162 | | symtab.stroff = self.linkedit_segment_next_offset.?; |
| 2163 | | symtab.strsize = @intCast(u32, mem.alignForward(needed_size, @sizeOf(u64))); |
| 2195 | const linkedit_segment = self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; |
| 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 | 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 | 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 | 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 | 2254 | /// Writes all load commands and section headers. |
| 2184 | 2255 | fn writeLoadCommands(self: *MachO) !void { |
| 2185 | 2256 | var sizeofcmds: usize = 0; |