| ... | ... | @@ -123,6 +123,8 @@ string_table: std.ArrayListUnmanaged(u8) = .{}, |
| 123 | 123 | /// Table of trampolines to the actual symbols in __text section. |
| 124 | 124 | offset_table: std.ArrayListUnmanaged(u64) = .{}, |
| 125 | 125 | |
| 126 | /// Table of rebase info entries. |
| 127 | rebase_info_table: RebaseInfoTable = .{}, |
| 126 | 128 | /// Table of binding info entries. |
| 127 | 129 | binding_info_table: BindingInfoTable = .{}, |
| 128 | 130 | /// Table of lazy binding info entries. |
| ... | ... | @@ -133,6 +135,7 @@ error_flags: File.ErrorFlags = File.ErrorFlags{}, |
| 133 | 135 | offset_table_count_dirty: bool = false, |
| 134 | 136 | header_dirty: bool = false, |
| 135 | 137 | load_commands_dirty: bool = false, |
| 138 | rebase_info_dirty: bool = false, |
| 136 | 139 | binding_info_dirty: bool = false, |
| 137 | 140 | lazy_binding_info_dirty: bool = false, |
| 138 | 141 | export_info_dirty: bool = false, |
| ... | ... | @@ -400,6 +403,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { |
| 400 | 403 | main_cmd.entryoff = addr - text_segment.inner.vmaddr; |
| 401 | 404 | self.load_commands_dirty = true; |
| 402 | 405 | } |
| 406 | try self.writeRebaseInfoTable(); |
| 403 | 407 | try self.writeBindingInfoTable(); |
| 404 | 408 | try self.writeLazyBindingInfoTable(); |
| 405 | 409 | try self.writeExportTrie(); |
| ... | ... | @@ -425,6 +429,11 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { |
| 425 | 429 | .Lib => return error.TODOImplementWritingLibFiles, |
| 426 | 430 | } |
| 427 | 431 | |
| 432 | { |
| 433 | const dysymtab = &self.load_commands.items[self.dysymtab_cmd_index.?].Dysymtab; |
| 434 | dysymtab.nindirectsyms = 0; |
| 435 | } |
| 436 | |
| 428 | 437 | try self.writeLoadCommands(); |
| 429 | 438 | try self.writeHeader(); |
| 430 | 439 | |
| ... | ... | @@ -439,6 +448,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { |
| 439 | 448 | assert(!self.offset_table_count_dirty); |
| 440 | 449 | assert(!self.header_dirty); |
| 441 | 450 | assert(!self.load_commands_dirty); |
| 451 | assert(!self.rebase_info_dirty); |
| 442 | 452 | assert(!self.binding_info_dirty); |
| 443 | 453 | assert(!self.lazy_binding_info_dirty); |
| 444 | 454 | assert(!self.export_info_dirty); |
| ... | ... | @@ -1289,6 +1299,12 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { |
| 1289 | 1299 | mem.writeIntLittle(u32, cccode[8..12], 0); |
| 1290 | 1300 | try self.base.file.?.pwriteAll(&cccode, self.next_stub_helper_off.?); |
| 1291 | 1301 | self.next_stub_helper_off = self.next_stub_helper_off.? + 3 * @sizeOf(u32); |
| 1302 | |
| 1303 | try self.rebase_info_table.symbols.append(self.base.allocator, .{ |
| 1304 | .segment = 3, |
| 1305 | .offset = 0, |
| 1306 | }); |
| 1307 | self.rebase_info_dirty = true; |
| 1292 | 1308 | } |
| 1293 | 1309 | |
| 1294 | 1310 | const text_section = text_segment.sections.items[self.text_section_index.?]; |
| ... | ... | @@ -1821,12 +1837,6 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1821 | 1837 | if (self.dyld_info_cmd_index == null) { |
| 1822 | 1838 | self.dyld_info_cmd_index = @intCast(u16, self.load_commands.items.len); |
| 1823 | 1839 | |
| 1824 | | // TODO Preallocate rebase, binding, and lazy binding info. |
| 1825 | | const export_size = 2; |
| 1826 | | const export_off = self.findFreeSpaceLinkedit(export_size, 1); |
| 1827 | | |
| 1828 | | log.debug("found export info free space 0x{x} to 0x{x}", .{ export_off, export_off + export_size }); |
| 1829 | | |
| 1830 | 1840 | try self.load_commands.append(self.base.allocator, .{ |
| 1831 | 1841 | .DyldInfoOnly = .{ |
| 1832 | 1842 | .cmd = macho.LC_DYLD_INFO_ONLY, |
| ... | ... | @@ -1839,37 +1849,67 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1839 | 1849 | .weak_bind_size = 0, |
| 1840 | 1850 | .lazy_bind_off = 0, |
| 1841 | 1851 | .lazy_bind_size = 0, |
| 1842 | | .export_off = @intCast(u32, export_off), |
| 1843 | | .export_size = export_size, |
| 1852 | .export_off = 0, |
| 1853 | .export_size = 0, |
| 1844 | 1854 | }, |
| 1845 | 1855 | }); |
| 1856 | |
| 1857 | const dyld = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly; |
| 1858 | |
| 1859 | // Preallocate rebase, binding, lazy binding info, and export info. |
| 1860 | const expected_size = 48; // TODO This is totally random. |
| 1861 | const rebase_off = self.findFreeSpaceLinkedit(expected_size, 1); |
| 1862 | log.debug("found rebase info free space 0x{x} to 0x{x}", .{ rebase_off, rebase_off + expected_size }); |
| 1863 | dyld.rebase_off = @intCast(u32, rebase_off); |
| 1864 | dyld.rebase_size = expected_size; |
| 1865 | |
| 1866 | const bind_off = self.findFreeSpaceLinkedit(expected_size, 1); |
| 1867 | log.debug("found binding info free space 0x{x} to 0x{x}", .{ bind_off, bind_off + expected_size }); |
| 1868 | dyld.bind_off = @intCast(u32, bind_off); |
| 1869 | dyld.bind_size = expected_size; |
| 1870 | |
| 1871 | const lazy_bind_off = self.findFreeSpaceLinkedit(expected_size, 1); |
| 1872 | log.debug("found lazy binding info free space 0x{x} to 0x{x}", .{ lazy_bind_off, lazy_bind_off + expected_size }); |
| 1873 | dyld.lazy_bind_off = @intCast(u32, lazy_bind_off); |
| 1874 | dyld.lazy_bind_size = expected_size; |
| 1875 | |
| 1876 | const export_off = self.findFreeSpaceLinkedit(expected_size, 1); |
| 1877 | log.debug("found export info free space 0x{x} to 0x{x}", .{ export_off, export_off + expected_size }); |
| 1878 | dyld.export_off = @intCast(u32, export_off); |
| 1879 | dyld.export_size = expected_size; |
| 1880 | |
| 1846 | 1881 | self.header_dirty = true; |
| 1847 | 1882 | self.load_commands_dirty = true; |
| 1848 | 1883 | } |
| 1849 | 1884 | if (self.symtab_cmd_index == null) { |
| 1850 | 1885 | self.symtab_cmd_index = @intCast(u16, self.load_commands.items.len); |
| 1851 | 1886 | |
| 1887 | try self.load_commands.append(self.base.allocator, .{ |
| 1888 | .Symtab = .{ |
| 1889 | .cmd = macho.LC_SYMTAB, |
| 1890 | .cmdsize = @sizeOf(macho.symtab_command), |
| 1891 | .symoff = 0, |
| 1892 | .nsyms = 0, |
| 1893 | .stroff = 0, |
| 1894 | .strsize = 0, |
| 1895 | }, |
| 1896 | }); |
| 1897 | |
| 1898 | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab; |
| 1899 | |
| 1852 | 1900 | const symtab_size = self.base.options.symbol_count_hint * @sizeOf(macho.nlist_64); |
| 1853 | 1901 | const symtab_off = self.findFreeSpaceLinkedit(symtab_size, @sizeOf(macho.nlist_64)); |
| 1854 | | |
| 1855 | 1902 | log.debug("found symbol table free space 0x{x} to 0x{x}", .{ symtab_off, symtab_off + symtab_size }); |
| 1903 | symtab.symoff = @intCast(u32, symtab_off); |
| 1904 | symtab.nsyms = @intCast(u32, self.base.options.symbol_count_hint); |
| 1856 | 1905 | |
| 1857 | 1906 | try self.string_table.append(self.base.allocator, 0); // Need a null at position 0. |
| 1858 | 1907 | const strtab_size = self.string_table.items.len; |
| 1859 | 1908 | const strtab_off = self.findFreeSpaceLinkedit(strtab_size, 1); |
| 1860 | | |
| 1861 | 1909 | log.debug("found string table free space 0x{x} to 0x{x}", .{ strtab_off, strtab_off + strtab_size }); |
| 1910 | symtab.stroff = @intCast(u32, strtab_off); |
| 1911 | symtab.strsize = @intCast(u32, strtab_size); |
| 1862 | 1912 | |
| 1863 | | try self.load_commands.append(self.base.allocator, .{ |
| 1864 | | .Symtab = .{ |
| 1865 | | .cmd = macho.LC_SYMTAB, |
| 1866 | | .cmdsize = @sizeOf(macho.symtab_command), |
| 1867 | | .symoff = @intCast(u32, symtab_off), |
| 1868 | | .nsyms = @intCast(u32, self.base.options.symbol_count_hint), |
| 1869 | | .stroff = @intCast(u32, strtab_off), |
| 1870 | | .strsize = @intCast(u32, strtab_size), |
| 1871 | | }, |
| 1872 | | }); |
| 1873 | 1913 | self.header_dirty = true; |
| 1874 | 1914 | self.load_commands_dirty = true; |
| 1875 | 1915 | self.string_table_dirty = true; |
| ... | ... | @@ -1877,7 +1917,11 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1877 | 1917 | if (self.dysymtab_cmd_index == null) { |
| 1878 | 1918 | self.dysymtab_cmd_index = @intCast(u16, self.load_commands.items.len); |
| 1879 | 1919 | |
| 1880 | | // TODO Preallocate space for indirect symbol table. |
| 1920 | // Preallocate space for indirect symbol table. |
| 1921 | const indsymtab_size = self.base.options.symbol_count_hint * @sizeOf(u64); // Each entry is just a u64. |
| 1922 | const indsymtab_off = self.findFreeSpaceLinkedit(indsymtab_size, @sizeOf(u64)); |
| 1923 | |
| 1924 | log.debug("found indirect symbol table free space 0x{x} to 0x{x}", .{ indsymtab_off, indsymtab_off + indsymtab_size }); |
| 1881 | 1925 | |
| 1882 | 1926 | try self.load_commands.append(self.base.allocator, .{ |
| 1883 | 1927 | .Dysymtab = .{ |
| ... | ... | @@ -1895,8 +1939,8 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1895 | 1939 | .nmodtab = 0, |
| 1896 | 1940 | .extrefsymoff = 0, |
| 1897 | 1941 | .nextrefsyms = 0, |
| 1898 | | .indirectsymoff = 0, |
| 1899 | | .nindirectsyms = 0, |
| 1942 | .indirectsymoff = @intCast(u32, indsymtab_off), |
| 1943 | .nindirectsyms = @intCast(u32, self.base.options.symbol_count_hint), |
| 1900 | 1944 | .extreloff = 0, |
| 1901 | 1945 | .nextrel = 0, |
| 1902 | 1946 | .locreloff = 0, |
| ... | ... | @@ -2565,6 +2609,37 @@ fn writeExportTrie(self: *MachO) !void { |
| 2565 | 2609 | self.export_info_dirty = false; |
| 2566 | 2610 | } |
| 2567 | 2611 | |
| 2612 | fn writeRebaseInfoTable(self: *MachO) !void { |
| 2613 | if (!self.rebase_info_dirty) return; |
| 2614 | |
| 2615 | const tracy = trace(@src()); |
| 2616 | defer tracy.end(); |
| 2617 | |
| 2618 | const size = try self.rebase_info_table.calcSize(); |
| 2619 | var buffer = try self.base.allocator.alloc(u8, @intCast(usize, size)); |
| 2620 | defer self.base.allocator.free(buffer); |
| 2621 | |
| 2622 | var stream = std.io.fixedBufferStream(buffer); |
| 2623 | try self.rebase_info_table.write(stream.writer()); |
| 2624 | |
| 2625 | const linkedit_segment = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; |
| 2626 | const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly; |
| 2627 | const allocated_size = self.allocatedSizeLinkedit(dyld_info.rebase_off); |
| 2628 | const needed_size = mem.alignForwardGeneric(u64, buffer.len, @alignOf(u64)); |
| 2629 | |
| 2630 | if (needed_size > allocated_size) { |
| 2631 | dyld_info.rebase_off = 0; |
| 2632 | dyld_info.rebase_off = @intCast(u32, self.findFreeSpaceLinkedit(needed_size, 1)); |
| 2633 | } |
| 2634 | |
| 2635 | dyld_info.rebase_size = @intCast(u32, needed_size); |
| 2636 | log.debug("writing rebase info from 0x{x} to 0x{x}", .{ dyld_info.rebase_off, dyld_info.rebase_off + dyld_info.rebase_size }); |
| 2637 | |
| 2638 | try self.base.file.?.pwriteAll(buffer, dyld_info.rebase_off); |
| 2639 | self.load_commands_dirty = true; |
| 2640 | self.rebase_info_dirty = false; |
| 2641 | } |
| 2642 | |
| 2568 | 2643 | fn writeBindingInfoTable(self: *MachO) !void { |
| 2569 | 2644 | if (!self.binding_info_dirty) return; |
| 2570 | 2645 | |