| ... | ... | @@ -133,8 +133,8 @@ objc_selrefs_section_index: ?u16 = null, |
| 133 | 133 | objc_classrefs_section_index: ?u16 = null, |
| 134 | 134 | objc_data_section_index: ?u16 = null, |
| 135 | 135 | |
| 136 | | bss_file_offset: ?u64 = null, |
| 137 | | tlv_bss_file_offset: ?u64 = null, |
| 136 | bss_file_offset: ?u32 = null, |
| 137 | tlv_bss_file_offset: ?u32 = null, |
| 138 | 138 | |
| 139 | 139 | locals: std.ArrayListUnmanaged(macho.nlist_64) = .{}, |
| 140 | 140 | globals: std.ArrayListUnmanaged(macho.nlist_64) = .{}, |
| ... | ... | @@ -1693,6 +1693,84 @@ pub fn allocateAtom(self: *MachO, atom: *TextBlock, match: MatchingSection) !u64 |
| 1693 | 1693 | const padding: ?u64 = if (match.seg == self.text_segment_cmd_index.?) self.header_pad else null; |
| 1694 | 1694 | const atom_alignment = try math.powi(u64, 2, atom.alignment); |
| 1695 | 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 | 1774 | sect.offset = new_offset; |
| 1697 | 1775 | sect.addr = seg.inner.vmaddr + sect.offset - seg.inner.fileoff; |
| 1698 | 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 | 1779 | new_offset, |
| 1702 | 1780 | new_offset + needed_size, |
| 1703 | 1781 | }); |
| 1704 | | try self.allocateLocalSymbols(match, old_base_addr); |
| 1705 | | vaddr = @intCast( |
| 1706 | | u64, |
| 1707 | | @intCast(i64, vaddr) + @intCast(i64, sect.addr) - @intCast(i64, old_base_addr), |
| 1708 | | ); |
| 1782 | const offset_amt = @intCast(i64, sect.addr) - @intCast(i64, old_base_addr); |
| 1783 | try self.allocateLocalSymbols(match, offset_amt); |
| 1784 | vaddr = @intCast(u64, @intCast(i64, vaddr) + offset_amt); |
| 1709 | 1785 | } |
| 1710 | 1786 | |
| 1711 | 1787 | sect.size = needed_size; |
| ... | ... | @@ -1761,11 +1837,8 @@ pub fn writeAtom(self: *MachO, atom: *TextBlock, match: MatchingSection) !void { |
| 1761 | 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 | 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 | 1843 | while (true) { |
| 1771 | 1844 | const atom_sym = &self.locals.items[atom.local_sym_index]; |
| ... | ... | @@ -3317,9 +3390,8 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 3317 | 3390 | if (self.text_segment_cmd_index == null) { |
| 3318 | 3391 | self.text_segment_cmd_index = @intCast(u16, self.load_commands.items.len); |
| 3319 | 3392 | const program_code_size_hint = self.base.options.program_code_size_hint; |
| 3320 | | // const program_code_size_hint = 10; |
| 3321 | 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 | 3395 | const needed_size = mem.alignForwardGeneric(u64, padToIdeal(ideal_size), self.page_size); |
| 3324 | 3396 | |
| 3325 | 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 | 3485 | if (self.data_const_segment_cmd_index == null) { |
| 3414 | 3486 | self.data_const_segment_cmd_index = @intCast(u16, self.load_commands.items.len); |
| 3415 | 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 | 3489 | const needed_size = mem.alignForwardGeneric(u64, padToIdeal(ideal_size), self.page_size); |
| 3418 | 3490 | |
| 3419 | 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 | 3526 | if (self.data_segment_cmd_index == null) { |
| 3455 | 3527 | self.data_segment_cmd_index = @intCast(u16, self.load_commands.items.len); |
| 3456 | 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 | 3530 | const needed_size = mem.alignForwardGeneric(u64, padToIdeal(ideal_size), self.page_size); |
| 3459 | 3531 | |
| 3460 | 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 | 3977 | const old_base_addr = text_section.addr; |
| 3906 | 3978 | text_section.size = 0; |
| 3907 | 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 | 4061 | text_section.offset = new_offset; |
| 3909 | 4062 | text_section.addr = text_segment.inner.vmaddr + text_section.offset - text_segment.inner.fileoff; |
| 3910 | 4063 | log.debug(" (found new __TEXT,__text free space from 0x{x} to 0x{x})", .{ |
| 3911 | 4064 | new_offset, |
| 3912 | 4065 | new_offset + needed_size, |
| 3913 | 4066 | }); |
| 4067 | const offset_amt = @intCast(i64, text_section.addr) - @intCast(i64, old_base_addr); |
| 3914 | 4068 | try self.allocateLocalSymbols(.{ |
| 3915 | 4069 | .seg = self.text_segment_cmd_index.?, |
| 3916 | 4070 | .sect = self.text_section_index.?, |
| 3917 | | }, old_base_addr); |
| 3918 | | vaddr = @intCast( |
| 3919 | | u64, |
| 3920 | | @intCast(i64, vaddr) + @intCast(i64, text_section.addr) - @intCast(i64, old_base_addr), |
| 3921 | | ); |
| 4071 | }, offset_amt); |
| 4072 | vaddr = @intCast(u64, @intCast(i64, vaddr) + offset_amt); |
| 3922 | 4073 | } |
| 3923 | 4074 | |
| 3924 | 4075 | text_section.size = needed_size; |