| ... | @@ -133,8 +133,8 @@ objc_selrefs_section_index: ?u16 = null, | ... | @@ -133,8 +133,8 @@ objc_selrefs_section_index: ?u16 = null, |
| 133 | objc_classrefs_section_index: ?u16 = null, | 133 | objc_classrefs_section_index: ?u16 = null, |
| 134 | objc_data_section_index: ?u16 = null, | 134 | objc_data_section_index: ?u16 = null, |
| 135 | | 135 | |
| 136 | bss_file_offset: ?u64 = null, | 136 | bss_file_offset: ?u32 = null, |
| 137 | tlv_bss_file_offset: ?u64 = null, | 137 | tlv_bss_file_offset: ?u32 = null, |
| 138 | | 138 | |
| 139 | locals: std.ArrayListUnmanaged(macho.nlist_64) = .{}, | 139 | locals: std.ArrayListUnmanaged(macho.nlist_64) = .{}, |
| 140 | globals: std.ArrayListUnmanaged(macho.nlist_64) = .{}, | 140 | globals: std.ArrayListUnmanaged(macho.nlist_64) = .{}, |
| ... | @@ -1693,6 +1693,84 @@ pub fn allocateAtom(self: *MachO, atom: *TextBlock, match: MatchingSection) !u64 | ... | @@ -1693,6 +1693,84 @@ pub fn allocateAtom(self: *MachO, atom: *TextBlock, match: MatchingSection) !u64 |
| 1693 | const padding: ?u64 = if (match.seg == self.text_segment_cmd_index.?) self.header_pad else null; | 1693 | const padding: ?u64 = if (match.seg == self.text_segment_cmd_index.?) self.header_pad else null; |
| 1694 | const atom_alignment = try math.powi(u64, 2, atom.alignment); | 1694 | const atom_alignment = try math.powi(u64, 2, atom.alignment); |
| 1695 | const new_offset = @intCast(u32, seg.findFreeSpace(needed_size, atom_alignment, padding)); | 1695 | const new_offset = @intCast(u32, seg.findFreeSpace(needed_size, atom_alignment, padding)); |
| | 1696 | |
| | 1697 | if (new_offset + needed_size >= seg.inner.fileoff + seg.inner.filesize) { |
| | 1698 | // Bummer, need to move all segments below down... |
| | 1699 | // TODO is this the right estimate? |
| | 1700 | const new_seg_size = mem.alignForwardGeneric( |
| | 1701 | u64, |
| | 1702 | padToIdeal(seg.inner.filesize + needed_size), |
| | 1703 | self.page_size, |
| | 1704 | ); |
| | 1705 | // TODO actually, we're always required to move in a number of pages so I guess all we need |
| | 1706 | // to know here is the number of pages to shift downwards. |
| | 1707 | const offset_amt = @intCast(u32, @intCast(i64, new_seg_size) - @intCast(i64, seg.inner.filesize)); |
| | 1708 | seg.inner.filesize = new_seg_size; |
| | 1709 | seg.inner.vmsize = new_seg_size; |
| | 1710 | log.debug(" (new {s} segment file offsets from 0x{x} to 0x{x} (in memory 0x{x} to 0x{x}))", .{ |
| | 1711 | seg.inner.segname, |
| | 1712 | seg.inner.fileoff, |
| | 1713 | seg.inner.fileoff + seg.inner.filesize, |
| | 1714 | seg.inner.vmaddr, |
| | 1715 | seg.inner.vmaddr + seg.inner.vmsize, |
| | 1716 | }); |
| | 1717 | // TODO We should probably nop the expanded by distance, or put 0s. |
| | 1718 | |
| | 1719 | // TODO copyRangeAll doesn't automatically extend the file on macOS. |
| | 1720 | const ledit_seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; |
| | 1721 | const new_filesize = offset_amt + ledit_seg.inner.fileoff + ledit_seg.inner.filesize; |
| | 1722 | try self.base.file.?.pwriteAll(&[_]u8{0}, new_filesize - 1); |
| | 1723 | |
| | 1724 | var next: usize = match.seg + 1; |
| | 1725 | while (next < self.linkedit_segment_cmd_index.? + 1) : (next += 1) { |
| | 1726 | const next_seg = &self.load_commands.items[next].Segment; |
| | 1727 | _ = try self.base.file.?.copyRangeAll( |
| | 1728 | next_seg.inner.fileoff, |
| | 1729 | self.base.file.?, |
| | 1730 | next_seg.inner.fileoff + offset_amt, |
| | 1731 | next_seg.inner.filesize, |
| | 1732 | ); |
| | 1733 | next_seg.inner.fileoff += offset_amt; |
| | 1734 | next_seg.inner.vmaddr += offset_amt; |
| | 1735 | log.debug(" (new {s} segment file offsets from 0x{x} to 0x{x} (in memory 0x{x} to 0x{x}))", .{ |
| | 1736 | next_seg.inner.segname, |
| | 1737 | next_seg.inner.fileoff, |
| | 1738 | next_seg.inner.fileoff + next_seg.inner.filesize, |
| | 1739 | next_seg.inner.vmaddr, |
| | 1740 | next_seg.inner.vmaddr + next_seg.inner.vmsize, |
| | 1741 | }); |
| | 1742 | |
| | 1743 | for (next_seg.sections.items) |*moved_sect, moved_sect_id| { |
| | 1744 | // TODO put below snippet in a function. |
| | 1745 | const moved_sect_offset = blk: { |
| | 1746 | if (self.data_segment_cmd_index.? == next) { |
| | 1747 | if (self.bss_section_index) |idx| { |
| | 1748 | if (idx == moved_sect_id) break :blk &self.bss_file_offset.?; |
| | 1749 | } |
| | 1750 | if (self.tlv_bss_section_index) |idx| { |
| | 1751 | if (idx == moved_sect_id) break :blk &self.tlv_bss_file_offset.?; |
| | 1752 | } |
| | 1753 | } |
| | 1754 | break :blk &moved_sect.offset; |
| | 1755 | }; |
| | 1756 | moved_sect_offset.* += offset_amt; |
| | 1757 | moved_sect.addr += offset_amt; |
| | 1758 | log.debug(" (new {s},{s} file offsets from 0x{x} to 0x{x} (in memory 0x{x} to 0x{x}))", .{ |
| | 1759 | commands.segmentName(moved_sect.*), |
| | 1760 | commands.sectionName(moved_sect.*), |
| | 1761 | moved_sect_offset.*, |
| | 1762 | moved_sect_offset.* + moved_sect.size, |
| | 1763 | moved_sect.addr, |
| | 1764 | moved_sect.addr + moved_sect.size, |
| | 1765 | }); |
| | 1766 | |
| | 1767 | try self.allocateLocalSymbols(.{ |
| | 1768 | .seg = @intCast(u16, next), |
| | 1769 | .sect = @intCast(u16, moved_sect_id), |
| | 1770 | }, offset_amt); |
| | 1771 | } |
| | 1772 | } |
| | 1773 | } |
| 1696 | sect.offset = new_offset; | 1774 | sect.offset = new_offset; |
| 1697 | sect.addr = seg.inner.vmaddr + sect.offset - seg.inner.fileoff; | 1775 | sect.addr = seg.inner.vmaddr + sect.offset - seg.inner.fileoff; |
| 1698 | log.debug(" (found new {s},{s} free space from 0x{x} to 0x{x})", .{ | 1776 | log.debug(" (found new {s},{s} free space from 0x{x} to 0x{x})", .{ |
| ... | @@ -1701,11 +1779,9 @@ pub fn allocateAtom(self: *MachO, atom: *TextBlock, match: MatchingSection) !u64 | ... | @@ -1701,11 +1779,9 @@ pub fn allocateAtom(self: *MachO, atom: *TextBlock, match: MatchingSection) !u64 |
| 1701 | new_offset, | 1779 | new_offset, |
| 1702 | new_offset + needed_size, | 1780 | new_offset + needed_size, |
| 1703 | }); | 1781 | }); |
| 1704 | try self.allocateLocalSymbols(match, old_base_addr); | 1782 | const offset_amt = @intCast(i64, sect.addr) - @intCast(i64, old_base_addr); |
| 1705 | vaddr = @intCast( | 1783 | try self.allocateLocalSymbols(match, offset_amt); |
| 1706 | u64, | 1784 | vaddr = @intCast(u64, @intCast(i64, vaddr) + offset_amt); |
| 1707 | @intCast(i64, vaddr) + @intCast(i64, sect.addr) - @intCast(i64, old_base_addr), | | |
| 1708 | ); | | |
| 1709 | } | 1785 | } |
| 1710 | | 1786 | |
| 1711 | sect.size = needed_size; | 1787 | sect.size = needed_size; |
| ... | @@ -1761,11 +1837,8 @@ pub fn writeAtom(self: *MachO, atom: *TextBlock, match: MatchingSection) !void { | ... | @@ -1761,11 +1837,8 @@ pub fn writeAtom(self: *MachO, atom: *TextBlock, match: MatchingSection) !void { |
| 1761 | try self.base.file.?.pwriteAll(atom.code.items, file_offset); | 1837 | try self.base.file.?.pwriteAll(atom.code.items, file_offset); |
| 1762 | } | 1838 | } |
| 1763 | | 1839 | |
| 1764 | fn allocateLocalSymbols(self: *MachO, match: MatchingSection, old_base_addr: u64) !void { | 1840 | fn allocateLocalSymbols(self: *MachO, match: MatchingSection, offset: i64) !void { |
| 1765 | var atom = self.blocks.get(match) orelse return; | 1841 | var atom = self.blocks.get(match) orelse return; |
| 1766 | const seg = self.load_commands.items[match.seg].Segment; | | |
| 1767 | const sect = seg.sections.items[match.sect]; | | |
| 1768 | const offset = @intCast(i64, sect.addr) - @intCast(i64, old_base_addr); | | |
| 1769 | | 1842 | |
| 1770 | while (true) { | 1843 | while (true) { |
| 1771 | const atom_sym = &self.locals.items[atom.local_sym_index]; | 1844 | const atom_sym = &self.locals.items[atom.local_sym_index]; |
| ... | @@ -3317,9 +3390,8 @@ pub fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -3317,9 +3390,8 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 3317 | if (self.text_segment_cmd_index == null) { | 3390 | if (self.text_segment_cmd_index == null) { |
| 3318 | self.text_segment_cmd_index = @intCast(u16, self.load_commands.items.len); | 3391 | self.text_segment_cmd_index = @intCast(u16, self.load_commands.items.len); |
| 3319 | const program_code_size_hint = self.base.options.program_code_size_hint; | 3392 | const program_code_size_hint = self.base.options.program_code_size_hint; |
| 3320 | // const program_code_size_hint = 10; | | |
| 3321 | const got_size_hint = @sizeOf(u64) * self.base.options.symbol_count_hint; | 3393 | const got_size_hint = @sizeOf(u64) * self.base.options.symbol_count_hint; |
| 3322 | const ideal_size = self.header_pad + (program_code_size_hint + got_size_hint) * 5; | 3394 | const ideal_size = self.header_pad + program_code_size_hint + got_size_hint; |
| 3323 | const needed_size = mem.alignForwardGeneric(u64, padToIdeal(ideal_size), self.page_size); | 3395 | const needed_size = mem.alignForwardGeneric(u64, padToIdeal(ideal_size), self.page_size); |
| 3324 | | 3396 | |
| 3325 | log.debug("found __TEXT segment free space 0x{x} to 0x{x}", .{ 0, needed_size }); | 3397 | log.debug("found __TEXT segment free space 0x{x} to 0x{x}", .{ 0, needed_size }); |
| ... | @@ -3413,7 +3485,7 @@ pub fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -3413,7 +3485,7 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 3413 | if (self.data_const_segment_cmd_index == null) { | 3485 | if (self.data_const_segment_cmd_index == null) { |
| 3414 | self.data_const_segment_cmd_index = @intCast(u16, self.load_commands.items.len); | 3486 | self.data_const_segment_cmd_index = @intCast(u16, self.load_commands.items.len); |
| 3415 | const address_and_offset = self.nextSegmentAddressAndOffset(); | 3487 | const address_and_offset = self.nextSegmentAddressAndOffset(); |
| 3416 | const ideal_size = @sizeOf(u64) * self.base.options.symbol_count_hint * 1000; | 3488 | const ideal_size = @sizeOf(u64) * self.base.options.symbol_count_hint; |
| 3417 | const needed_size = mem.alignForwardGeneric(u64, padToIdeal(ideal_size), self.page_size); | 3489 | const needed_size = mem.alignForwardGeneric(u64, padToIdeal(ideal_size), self.page_size); |
| 3418 | | 3490 | |
| 3419 | log.debug("found __DATA_CONST segment free space 0x{x} to 0x{x}", .{ | 3491 | log.debug("found __DATA_CONST segment free space 0x{x} to 0x{x}", .{ |
| ... | @@ -3454,7 +3526,7 @@ pub fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -3454,7 +3526,7 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 3454 | if (self.data_segment_cmd_index == null) { | 3526 | if (self.data_segment_cmd_index == null) { |
| 3455 | self.data_segment_cmd_index = @intCast(u16, self.load_commands.items.len); | 3527 | self.data_segment_cmd_index = @intCast(u16, self.load_commands.items.len); |
| 3456 | const address_and_offset = self.nextSegmentAddressAndOffset(); | 3528 | const address_and_offset = self.nextSegmentAddressAndOffset(); |
| 3457 | const ideal_size = 2 * @sizeOf(u64) * self.base.options.symbol_count_hint * 1000; | 3529 | const ideal_size = 2 * @sizeOf(u64) * self.base.options.symbol_count_hint; |
| 3458 | const needed_size = mem.alignForwardGeneric(u64, padToIdeal(ideal_size), self.page_size); | 3530 | const needed_size = mem.alignForwardGeneric(u64, padToIdeal(ideal_size), self.page_size); |
| 3459 | | 3531 | |
| 3460 | log.debug("found __DATA segment free space 0x{x} to 0x{x}", .{ address_and_offset.offset, address_and_offset.offset + needed_size }); | 3532 | log.debug("found __DATA segment free space 0x{x} to 0x{x}", .{ address_and_offset.offset, address_and_offset.offset + needed_size }); |
| ... | @@ -3905,20 +3977,99 @@ fn allocateTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64, | ... | @@ -3905,20 +3977,99 @@ fn allocateTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64, |
| 3905 | const old_base_addr = text_section.addr; | 3977 | const old_base_addr = text_section.addr; |
| 3906 | text_section.size = 0; | 3978 | text_section.size = 0; |
| 3907 | const new_offset = @intCast(u32, text_segment.findFreeSpace(needed_size, alignment, self.header_pad)); | 3979 | const new_offset = @intCast(u32, text_segment.findFreeSpace(needed_size, alignment, self.header_pad)); |
| | 3980 | |
| | 3981 | if (new_offset + needed_size >= text_segment.inner.fileoff + text_segment.inner.filesize) { |
| | 3982 | // Bummer, need to move all segments below down... |
| | 3983 | // TODO is this the right estimate? |
| | 3984 | const new_seg_size = mem.alignForwardGeneric( |
| | 3985 | u64, |
| | 3986 | padToIdeal(text_segment.inner.filesize + needed_size), |
| | 3987 | self.page_size, |
| | 3988 | ); |
| | 3989 | // TODO actually, we're always required to move in a number of pages so I guess all we need |
| | 3990 | // to know here is the number of pages to shift downwards. |
| | 3991 | const offset_amt = @intCast( |
| | 3992 | u32, |
| | 3993 | @intCast(i64, new_seg_size) - @intCast(i64, text_segment.inner.filesize), |
| | 3994 | ); |
| | 3995 | text_segment.inner.filesize = new_seg_size; |
| | 3996 | text_segment.inner.vmsize = new_seg_size; |
| | 3997 | log.debug(" (new __TEXT segment file offsets from 0x{x} to 0x{x} (in memory 0x{x} to 0x{x}))", .{ |
| | 3998 | text_segment.inner.fileoff, |
| | 3999 | text_segment.inner.fileoff + text_segment.inner.filesize, |
| | 4000 | text_segment.inner.vmaddr, |
| | 4001 | text_segment.inner.vmaddr + text_segment.inner.vmsize, |
| | 4002 | }); |
| | 4003 | // TODO We should probably nop the expanded by distance, or put 0s. |
| | 4004 | |
| | 4005 | // TODO copyRangeAll doesn't automatically extend the file on macOS. |
| | 4006 | const ledit_seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; |
| | 4007 | const new_filesize = offset_amt + ledit_seg.inner.fileoff + ledit_seg.inner.filesize; |
| | 4008 | try self.base.file.?.pwriteAll(&[_]u8{0}, new_filesize - 1); |
| | 4009 | |
| | 4010 | var next: usize = match.seg + 1; |
| | 4011 | while (next < self.linkedit_segment_cmd_index.? + 1) : (next += 1) { |
| | 4012 | const next_seg = &self.load_commands.items[next].Segment; |
| | 4013 | _ = try self.base.file.?.copyRangeAll( |
| | 4014 | next_seg.inner.fileoff, |
| | 4015 | self.base.file.?, |
| | 4016 | next_seg.inner.fileoff + offset_amt, |
| | 4017 | next_seg.inner.filesize, |
| | 4018 | ); |
| | 4019 | next_seg.inner.fileoff += offset_amt; |
| | 4020 | next_seg.inner.vmaddr += offset_amt; |
| | 4021 | log.debug(" (new {s} segment file offsets from 0x{x} to 0x{x} (in memory 0x{x} to 0x{x}))", .{ |
| | 4022 | next_seg.inner.segname, |
| | 4023 | next_seg.inner.fileoff, |
| | 4024 | next_seg.inner.fileoff + next_seg.inner.filesize, |
| | 4025 | next_seg.inner.vmaddr, |
| | 4026 | next_seg.inner.vmaddr + next_seg.inner.vmsize, |
| | 4027 | }); |
| | 4028 | |
| | 4029 | for (next_seg.sections.items) |*moved_sect, moved_sect_id| { |
| | 4030 | // TODO put below snippet in a function. |
| | 4031 | const moved_sect_offset = blk: { |
| | 4032 | if (self.data_segment_cmd_index.? == next) { |
| | 4033 | if (self.bss_section_index) |idx| { |
| | 4034 | if (idx == moved_sect_id) break :blk &self.bss_file_offset.?; |
| | 4035 | } |
| | 4036 | if (self.tlv_bss_section_index) |idx| { |
| | 4037 | if (idx == moved_sect_id) break :blk &self.tlv_bss_file_offset.?; |
| | 4038 | } |
| | 4039 | } |
| | 4040 | break :blk &moved_sect.offset; |
| | 4041 | }; |
| | 4042 | moved_sect_offset.* += offset_amt; |
| | 4043 | moved_sect.addr += offset_amt; |
| | 4044 | log.debug(" (new {s},{s} file offsets from 0x{x} to 0x{x} (in memory 0x{x} to 0x{x}))", .{ |
| | 4045 | commands.segmentName(moved_sect.*), |
| | 4046 | commands.sectionName(moved_sect.*), |
| | 4047 | moved_sect_offset.*, |
| | 4048 | moved_sect_offset.* + moved_sect.size, |
| | 4049 | moved_sect.addr, |
| | 4050 | moved_sect.addr + moved_sect.size, |
| | 4051 | }); |
| | 4052 | |
| | 4053 | try self.allocateLocalSymbols(.{ |
| | 4054 | .seg = @intCast(u16, next), |
| | 4055 | .sect = @intCast(u16, moved_sect_id), |
| | 4056 | }, offset_amt); |
| | 4057 | } |
| | 4058 | } |
| | 4059 | } |
| | 4060 | |
| 3908 | text_section.offset = new_offset; | 4061 | text_section.offset = new_offset; |
| 3909 | text_section.addr = text_segment.inner.vmaddr + text_section.offset - text_segment.inner.fileoff; | 4062 | text_section.addr = text_segment.inner.vmaddr + text_section.offset - text_segment.inner.fileoff; |
| 3910 | log.debug(" (found new __TEXT,__text free space from 0x{x} to 0x{x})", .{ | 4063 | log.debug(" (found new __TEXT,__text free space from 0x{x} to 0x{x})", .{ |
| 3911 | new_offset, | 4064 | new_offset, |
| 3912 | new_offset + needed_size, | 4065 | new_offset + needed_size, |
| 3913 | }); | 4066 | }); |
| | 4067 | const offset_amt = @intCast(i64, text_section.addr) - @intCast(i64, old_base_addr); |
| 3914 | try self.allocateLocalSymbols(.{ | 4068 | try self.allocateLocalSymbols(.{ |
| 3915 | .seg = self.text_segment_cmd_index.?, | 4069 | .seg = self.text_segment_cmd_index.?, |
| 3916 | .sect = self.text_section_index.?, | 4070 | .sect = self.text_section_index.?, |
| 3917 | }, old_base_addr); | 4071 | }, offset_amt); |
| 3918 | vaddr = @intCast( | 4072 | vaddr = @intCast(u64, @intCast(i64, vaddr) + offset_amt); |
| 3919 | u64, | | |
| 3920 | @intCast(i64, vaddr) + @intCast(i64, text_section.addr) - @intCast(i64, old_base_addr), | | |
| 3921 | ); | | |
| 3922 | } | 4073 | } |
| 3923 | | 4074 | |
| 3924 | text_section.size = needed_size; | 4075 | text_section.size = needed_size; |