| ... | @@ -123,6 +123,8 @@ string_table: std.ArrayListUnmanaged(u8) = .{}, | ... | @@ -123,6 +123,8 @@ string_table: std.ArrayListUnmanaged(u8) = .{}, |
| 123 | /// Table of trampolines to the actual symbols in __text section. | 123 | /// Table of trampolines to the actual symbols in __text section. |
| 124 | offset_table: std.ArrayListUnmanaged(u64) = .{}, | 124 | offset_table: std.ArrayListUnmanaged(u64) = .{}, |
| 125 | | 125 | |
| | 126 | /// Table of rebase info entries. |
| | 127 | rebase_info_table: RebaseInfoTable = .{}, |
| 126 | /// Table of binding info entries. | 128 | /// Table of binding info entries. |
| 127 | binding_info_table: BindingInfoTable = .{}, | 129 | binding_info_table: BindingInfoTable = .{}, |
| 128 | /// Table of lazy binding info entries. | 130 | /// Table of lazy binding info entries. |
| ... | @@ -133,6 +135,7 @@ error_flags: File.ErrorFlags = File.ErrorFlags{}, | ... | @@ -133,6 +135,7 @@ error_flags: File.ErrorFlags = File.ErrorFlags{}, |
| 133 | offset_table_count_dirty: bool = false, | 135 | offset_table_count_dirty: bool = false, |
| 134 | header_dirty: bool = false, | 136 | header_dirty: bool = false, |
| 135 | load_commands_dirty: bool = false, | 137 | load_commands_dirty: bool = false, |
| | 138 | rebase_info_dirty: bool = false, |
| 136 | binding_info_dirty: bool = false, | 139 | binding_info_dirty: bool = false, |
| 137 | lazy_binding_info_dirty: bool = false, | 140 | lazy_binding_info_dirty: bool = false, |
| 138 | export_info_dirty: bool = false, | 141 | export_info_dirty: bool = false, |
| ... | @@ -400,6 +403,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { | ... | @@ -400,6 +403,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { |
| 400 | main_cmd.entryoff = addr - text_segment.inner.vmaddr; | 403 | main_cmd.entryoff = addr - text_segment.inner.vmaddr; |
| 401 | self.load_commands_dirty = true; | 404 | self.load_commands_dirty = true; |
| 402 | } | 405 | } |
| | 406 | try self.writeRebaseInfoTable(); |
| 403 | try self.writeBindingInfoTable(); | 407 | try self.writeBindingInfoTable(); |
| 404 | try self.writeLazyBindingInfoTable(); | 408 | try self.writeLazyBindingInfoTable(); |
| 405 | try self.writeExportTrie(); | 409 | try self.writeExportTrie(); |
| ... | @@ -425,6 +429,11 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { | ... | @@ -425,6 +429,11 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { |
| 425 | .Lib => return error.TODOImplementWritingLibFiles, | 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 | try self.writeLoadCommands(); | 437 | try self.writeLoadCommands(); |
| 429 | try self.writeHeader(); | 438 | try self.writeHeader(); |
| 430 | | 439 | |
| ... | @@ -439,6 +448,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { | ... | @@ -439,6 +448,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { |
| 439 | assert(!self.offset_table_count_dirty); | 448 | assert(!self.offset_table_count_dirty); |
| 440 | assert(!self.header_dirty); | 449 | assert(!self.header_dirty); |
| 441 | assert(!self.load_commands_dirty); | 450 | assert(!self.load_commands_dirty); |
| | 451 | assert(!self.rebase_info_dirty); |
| 442 | assert(!self.binding_info_dirty); | 452 | assert(!self.binding_info_dirty); |
| 443 | assert(!self.lazy_binding_info_dirty); | 453 | assert(!self.lazy_binding_info_dirty); |
| 444 | assert(!self.export_info_dirty); | 454 | assert(!self.export_info_dirty); |
| ... | @@ -1289,6 +1299,12 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { | ... | @@ -1289,6 +1299,12 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { |
| 1289 | mem.writeIntLittle(u32, cccode[8..12], 0); | 1299 | mem.writeIntLittle(u32, cccode[8..12], 0); |
| 1290 | try self.base.file.?.pwriteAll(&cccode, self.next_stub_helper_off.?); | 1300 | try self.base.file.?.pwriteAll(&cccode, self.next_stub_helper_off.?); |
| 1291 | self.next_stub_helper_off = self.next_stub_helper_off.? + 3 * @sizeOf(u32); | 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 | const text_section = text_segment.sections.items[self.text_section_index.?]; | 1310 | const text_section = text_segment.sections.items[self.text_section_index.?]; |
| ... | @@ -1821,12 +1837,6 @@ pub fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -1821,12 +1837,6 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1821 | if (self.dyld_info_cmd_index == null) { | 1837 | if (self.dyld_info_cmd_index == null) { |
| 1822 | self.dyld_info_cmd_index = @intCast(u16, self.load_commands.items.len); | 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 | try self.load_commands.append(self.base.allocator, .{ | 1840 | try self.load_commands.append(self.base.allocator, .{ |
| 1831 | .DyldInfoOnly = .{ | 1841 | .DyldInfoOnly = .{ |
| 1832 | .cmd = macho.LC_DYLD_INFO_ONLY, | 1842 | .cmd = macho.LC_DYLD_INFO_ONLY, |
| ... | @@ -1839,37 +1849,67 @@ pub fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -1839,37 +1849,67 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1839 | .weak_bind_size = 0, | 1849 | .weak_bind_size = 0, |
| 1840 | .lazy_bind_off = 0, | 1850 | .lazy_bind_off = 0, |
| 1841 | .lazy_bind_size = 0, | 1851 | .lazy_bind_size = 0, |
| 1842 | .export_off = @intCast(u32, export_off), | 1852 | .export_off = 0, |
| 1843 | .export_size = export_size, | 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 | self.header_dirty = true; | 1881 | self.header_dirty = true; |
| 1847 | self.load_commands_dirty = true; | 1882 | self.load_commands_dirty = true; |
| 1848 | } | 1883 | } |
| 1849 | if (self.symtab_cmd_index == null) { | 1884 | if (self.symtab_cmd_index == null) { |
| 1850 | self.symtab_cmd_index = @intCast(u16, self.load_commands.items.len); | 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 | const symtab_size = self.base.options.symbol_count_hint * @sizeOf(macho.nlist_64); | 1900 | const symtab_size = self.base.options.symbol_count_hint * @sizeOf(macho.nlist_64); |
| 1853 | const symtab_off = self.findFreeSpaceLinkedit(symtab_size, @sizeOf(macho.nlist_64)); | 1901 | const symtab_off = self.findFreeSpaceLinkedit(symtab_size, @sizeOf(macho.nlist_64)); |
| 1854 | | | |
| 1855 | log.debug("found symbol table free space 0x{x} to 0x{x}", .{ symtab_off, symtab_off + symtab_size }); | 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 | try self.string_table.append(self.base.allocator, 0); // Need a null at position 0. | 1906 | try self.string_table.append(self.base.allocator, 0); // Need a null at position 0. |
| 1858 | const strtab_size = self.string_table.items.len; | 1907 | const strtab_size = self.string_table.items.len; |
| 1859 | const strtab_off = self.findFreeSpaceLinkedit(strtab_size, 1); | 1908 | const strtab_off = self.findFreeSpaceLinkedit(strtab_size, 1); |
| 1860 | | | |
| 1861 | log.debug("found string table free space 0x{x} to 0x{x}", .{ strtab_off, strtab_off + strtab_size }); | 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 | self.header_dirty = true; | 1913 | self.header_dirty = true; |
| 1874 | self.load_commands_dirty = true; | 1914 | self.load_commands_dirty = true; |
| 1875 | self.string_table_dirty = true; | 1915 | self.string_table_dirty = true; |
| ... | @@ -1877,7 +1917,11 @@ pub fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -1877,7 +1917,11 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1877 | if (self.dysymtab_cmd_index == null) { | 1917 | if (self.dysymtab_cmd_index == null) { |
| 1878 | self.dysymtab_cmd_index = @intCast(u16, self.load_commands.items.len); | 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 | try self.load_commands.append(self.base.allocator, .{ | 1926 | try self.load_commands.append(self.base.allocator, .{ |
| 1883 | .Dysymtab = .{ | 1927 | .Dysymtab = .{ |
| ... | @@ -1895,8 +1939,8 @@ pub fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -1895,8 +1939,8 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1895 | .nmodtab = 0, | 1939 | .nmodtab = 0, |
| 1896 | .extrefsymoff = 0, | 1940 | .extrefsymoff = 0, |
| 1897 | .nextrefsyms = 0, | 1941 | .nextrefsyms = 0, |
| 1898 | .indirectsymoff = 0, | 1942 | .indirectsymoff = @intCast(u32, indsymtab_off), |
| 1899 | .nindirectsyms = 0, | 1943 | .nindirectsyms = @intCast(u32, self.base.options.symbol_count_hint), |
| 1900 | .extreloff = 0, | 1944 | .extreloff = 0, |
| 1901 | .nextrel = 0, | 1945 | .nextrel = 0, |
| 1902 | .locreloff = 0, | 1946 | .locreloff = 0, |
| ... | @@ -2565,6 +2609,37 @@ fn writeExportTrie(self: *MachO) !void { | ... | @@ -2565,6 +2609,37 @@ fn writeExportTrie(self: *MachO) !void { |
| 2565 | self.export_info_dirty = false; | 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 | fn writeBindingInfoTable(self: *MachO) !void { | 2643 | fn writeBindingInfoTable(self: *MachO) !void { |
| 2569 | if (!self.binding_info_dirty) return; | 2644 | if (!self.binding_info_dirty) return; |
| 2570 | | 2645 | |