| ... | ... | @@ -135,6 +135,8 @@ lazy_binding_info_dirty: bool = false, |
| 135 | 135 | export_info_dirty: bool = false, |
| 136 | 136 | string_table_dirty: bool = false, |
| 137 | 137 | |
| 138 | string_table_needs_relocation: bool = false, |
| 139 | |
| 138 | 140 | /// A list of text blocks that have surplus capacity. This list can have false |
| 139 | 141 | /// positives, as functions grow and shrink over time, only sometimes being added |
| 140 | 142 | /// or removed from the freelist. |
| ... | ... | @@ -454,6 +456,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { |
| 454 | 456 | assert(!self.lazy_binding_info_dirty); |
| 455 | 457 | assert(!self.export_info_dirty); |
| 456 | 458 | assert(!self.string_table_dirty); |
| 459 | assert(!self.string_table_needs_relocation); |
| 457 | 460 | |
| 458 | 461 | if (target.cpu.arch == .aarch64) { |
| 459 | 462 | switch (output_mode) { |
| ... | ... | @@ -1824,22 +1827,22 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1824 | 1827 | |
| 1825 | 1828 | // Preallocate rebase, binding, lazy binding info, and export info. |
| 1826 | 1829 | const expected_size = 48; // TODO This is totally random. |
| 1827 | | const rebase_off = self.findFreeSpaceLinkedit(expected_size, 1); |
| 1830 | const rebase_off = self.findFreeSpaceLinkedit(expected_size, 1, null); |
| 1828 | 1831 | log.debug("found rebase info free space 0x{x} to 0x{x}", .{ rebase_off, rebase_off + expected_size }); |
| 1829 | 1832 | dyld.rebase_off = @intCast(u32, rebase_off); |
| 1830 | 1833 | dyld.rebase_size = expected_size; |
| 1831 | 1834 | |
| 1832 | | const bind_off = self.findFreeSpaceLinkedit(expected_size, 1); |
| 1835 | const bind_off = self.findFreeSpaceLinkedit(expected_size, 1, null); |
| 1833 | 1836 | log.debug("found binding info free space 0x{x} to 0x{x}", .{ bind_off, bind_off + expected_size }); |
| 1834 | 1837 | dyld.bind_off = @intCast(u32, bind_off); |
| 1835 | 1838 | dyld.bind_size = expected_size; |
| 1836 | 1839 | |
| 1837 | | const lazy_bind_off = self.findFreeSpaceLinkedit(expected_size, 1); |
| 1840 | const lazy_bind_off = self.findFreeSpaceLinkedit(expected_size, 1, null); |
| 1838 | 1841 | log.debug("found lazy binding info free space 0x{x} to 0x{x}", .{ lazy_bind_off, lazy_bind_off + expected_size }); |
| 1839 | 1842 | dyld.lazy_bind_off = @intCast(u32, lazy_bind_off); |
| 1840 | 1843 | dyld.lazy_bind_size = expected_size; |
| 1841 | 1844 | |
| 1842 | | const export_off = self.findFreeSpaceLinkedit(expected_size, 1); |
| 1845 | const export_off = self.findFreeSpaceLinkedit(expected_size, 1, null); |
| 1843 | 1846 | log.debug("found export info free space 0x{x} to 0x{x}", .{ export_off, export_off + expected_size }); |
| 1844 | 1847 | dyld.export_off = @intCast(u32, export_off); |
| 1845 | 1848 | dyld.export_size = expected_size; |
| ... | ... | @@ -1864,14 +1867,14 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1864 | 1867 | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab; |
| 1865 | 1868 | |
| 1866 | 1869 | const symtab_size = self.base.options.symbol_count_hint * @sizeOf(macho.nlist_64); |
| 1867 | | const symtab_off = self.findFreeSpaceLinkedit(symtab_size, @sizeOf(macho.nlist_64)); |
| 1870 | const symtab_off = self.findFreeSpaceLinkedit(symtab_size, @sizeOf(macho.nlist_64), null); |
| 1868 | 1871 | log.debug("found symbol table free space 0x{x} to 0x{x}", .{ symtab_off, symtab_off + symtab_size }); |
| 1869 | 1872 | symtab.symoff = @intCast(u32, symtab_off); |
| 1870 | 1873 | symtab.nsyms = @intCast(u32, self.base.options.symbol_count_hint); |
| 1871 | 1874 | |
| 1872 | 1875 | try self.string_table.append(self.base.allocator, 0); // Need a null at position 0. |
| 1873 | 1876 | const strtab_size = self.string_table.items.len; |
| 1874 | | const strtab_off = self.findFreeSpaceLinkedit(strtab_size, 1); |
| 1877 | const strtab_off = self.findFreeSpaceLinkedit(strtab_size, 1, symtab_off); |
| 1875 | 1878 | log.debug("found string table free space 0x{x} to 0x{x}", .{ strtab_off, strtab_off + strtab_size }); |
| 1876 | 1879 | symtab.stroff = @intCast(u32, strtab_off); |
| 1877 | 1880 | symtab.strsize = @intCast(u32, strtab_size); |
| ... | ... | @@ -1885,7 +1888,7 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1885 | 1888 | |
| 1886 | 1889 | // Preallocate space for indirect symbol table. |
| 1887 | 1890 | const indsymtab_size = self.base.options.symbol_count_hint * @sizeOf(u64); // Each entry is just a u64. |
| 1888 | | const indsymtab_off = self.findFreeSpaceLinkedit(indsymtab_size, @sizeOf(u64)); |
| 1891 | const indsymtab_off = self.findFreeSpaceLinkedit(indsymtab_size, @sizeOf(u64), null); |
| 1889 | 1892 | |
| 1890 | 1893 | log.debug("found indirect symbol table free space 0x{x} to 0x{x}", .{ indsymtab_off, indsymtab_off + indsymtab_size }); |
| 1891 | 1894 | |
| ... | ... | @@ -2383,13 +2386,13 @@ fn detectAllocCollisionLinkedit(self: *MachO, start: u64, size: u64) ?u64 { |
| 2383 | 2386 | return null; |
| 2384 | 2387 | } |
| 2385 | 2388 | |
| 2386 | | fn findFreeSpaceLinkedit(self: *MachO, object_size: u64, min_alignment: u16) u64 { |
| 2389 | fn findFreeSpaceLinkedit(self: *MachO, object_size: u64, min_alignment: u16, start: ?u64) u64 { |
| 2387 | 2390 | const linkedit = self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; |
| 2388 | | var start: u64 = linkedit.inner.fileoff; |
| 2389 | | while (self.detectAllocCollisionLinkedit(start, object_size)) |item_end| { |
| 2390 | | start = mem.alignForwardGeneric(u64, item_end, min_alignment); |
| 2391 | var st: u64 = start orelse linkedit.inner.fileoff; |
| 2392 | while (self.detectAllocCollisionLinkedit(st, object_size)) |item_end| { |
| 2393 | st = mem.alignForwardGeneric(u64, item_end, min_alignment); |
| 2391 | 2394 | } |
| 2392 | | return start; |
| 2395 | return st; |
| 2393 | 2396 | } |
| 2394 | 2397 | |
| 2395 | 2398 | /// Saturating multiplication |
| ... | ... | @@ -2535,7 +2538,7 @@ fn relocateSymbolTable(self: *MachO) !void { |
| 2535 | 2538 | const needed_size = nsyms * @sizeOf(macho.nlist_64); |
| 2536 | 2539 | if (needed_size > self.allocatedSizeLinkedit(symtab.symoff)) { |
| 2537 | 2540 | // Move the entire symbol table to a new location |
| 2538 | | const new_symoff = self.findFreeSpaceLinkedit(needed_size, @alignOf(macho.nlist_64)); |
| 2541 | const new_symoff = self.findFreeSpaceLinkedit(needed_size, @alignOf(macho.nlist_64), null); |
| 2539 | 2542 | const existing_size = symtab.nsyms * @sizeOf(macho.nlist_64); |
| 2540 | 2543 | |
| 2541 | 2544 | log.debug("relocating symbol table from 0x{x}-0x{x} to 0x{x}-0x{x}", .{ |
| ... | ... | @@ -2548,6 +2551,7 @@ fn relocateSymbolTable(self: *MachO) !void { |
| 2548 | 2551 | const amt = try self.base.file.?.copyRangeAll(symtab.symoff, self.base.file.?, new_symoff, existing_size); |
| 2549 | 2552 | if (amt != existing_size) return error.InputOutput; |
| 2550 | 2553 | symtab.symoff = @intCast(u32, new_symoff); |
| 2554 | self.string_table_needs_relocation = true; |
| 2551 | 2555 | } |
| 2552 | 2556 | symtab.nsyms = @intCast(u32, nsyms); |
| 2553 | 2557 | self.load_commands_dirty = true; |
| ... | ... | @@ -2757,7 +2761,8 @@ fn writeExportTrie(self: *MachO) !void { |
| 2757 | 2761 | |
| 2758 | 2762 | if (needed_size > allocated_size) { |
| 2759 | 2763 | dyld_info.export_off = 0; |
| 2760 | | dyld_info.export_off = @intCast(u32, self.findFreeSpaceLinkedit(needed_size, 1)); |
| 2764 | dyld_info.export_off = @intCast(u32, self.findFreeSpaceLinkedit(needed_size, 1, null)); |
| 2765 | // TODO this might require relocating all following LC_DYLD_INFO_ONLY sections too. |
| 2761 | 2766 | } |
| 2762 | 2767 | dyld_info.export_size = @intCast(u32, needed_size); |
| 2763 | 2768 | log.debug("writing export info from 0x{x} to 0x{x}", .{ dyld_info.export_off, dyld_info.export_off + dyld_info.export_size }); |
| ... | ... | @@ -2794,7 +2799,8 @@ fn writeRebaseInfoTable(self: *MachO) !void { |
| 2794 | 2799 | |
| 2795 | 2800 | if (needed_size > allocated_size) { |
| 2796 | 2801 | dyld_info.rebase_off = 0; |
| 2797 | | dyld_info.rebase_off = @intCast(u32, self.findFreeSpaceLinkedit(needed_size, 1)); |
| 2802 | dyld_info.rebase_off = @intCast(u32, self.findFreeSpaceLinkedit(needed_size, 1, null)); |
| 2803 | // TODO this might require relocating all following LC_DYLD_INFO_ONLY sections too. |
| 2798 | 2804 | } |
| 2799 | 2805 | |
| 2800 | 2806 | dyld_info.rebase_size = @intCast(u32, needed_size); |
| ... | ... | @@ -2832,7 +2838,8 @@ fn writeBindingInfoTable(self: *MachO) !void { |
| 2832 | 2838 | |
| 2833 | 2839 | if (needed_size > allocated_size) { |
| 2834 | 2840 | dyld_info.bind_off = 0; |
| 2835 | | dyld_info.bind_off = @intCast(u32, self.findFreeSpaceLinkedit(needed_size, 1)); |
| 2841 | dyld_info.bind_off = @intCast(u32, self.findFreeSpaceLinkedit(needed_size, 1, null)); |
| 2842 | // TODO this might require relocating all following LC_DYLD_INFO_ONLY sections too. |
| 2836 | 2843 | } |
| 2837 | 2844 | |
| 2838 | 2845 | dyld_info.bind_size = @intCast(u32, needed_size); |
| ... | ... | @@ -2867,7 +2874,8 @@ fn writeLazyBindingInfoTable(self: *MachO) !void { |
| 2867 | 2874 | |
| 2868 | 2875 | if (needed_size > allocated_size) { |
| 2869 | 2876 | dyld_info.lazy_bind_off = 0; |
| 2870 | | dyld_info.lazy_bind_off = @intCast(u32, self.findFreeSpaceLinkedit(needed_size, 1)); |
| 2877 | dyld_info.lazy_bind_off = @intCast(u32, self.findFreeSpaceLinkedit(needed_size, 1, null)); |
| 2878 | // TODO this might require relocating all following LC_DYLD_INFO_ONLY sections too. |
| 2871 | 2879 | } |
| 2872 | 2880 | |
| 2873 | 2881 | dyld_info.lazy_bind_size = @intCast(u32, needed_size); |
| ... | ... | @@ -2956,9 +2964,10 @@ fn writeStringTable(self: *MachO) !void { |
| 2956 | 2964 | const allocated_size = self.allocatedSizeLinkedit(symtab.stroff); |
| 2957 | 2965 | const needed_size = mem.alignForwardGeneric(u64, self.string_table.items.len, @alignOf(u64)); |
| 2958 | 2966 | |
| 2959 | | if (needed_size > allocated_size) { |
| 2967 | if (needed_size > allocated_size or self.string_table_needs_relocation) { |
| 2960 | 2968 | symtab.strsize = 0; |
| 2961 | | symtab.stroff = @intCast(u32, self.findFreeSpaceLinkedit(needed_size, 1)); |
| 2969 | symtab.stroff = @intCast(u32, self.findFreeSpaceLinkedit(needed_size, 1, symtab.symoff)); |
| 2970 | self.string_table_needs_relocation = false; |
| 2962 | 2971 | } |
| 2963 | 2972 | symtab.strsize = @intCast(u32, needed_size); |
| 2964 | 2973 | log.debug("writing string table from 0x{x} to 0x{x}", .{ symtab.stroff, symtab.stroff + symtab.strsize }); |