authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-09-03 00:21:45+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-09-03 00:21:45+02:00
log4b07da7090542292f77a11bcfe1ef79e8baf1e97
tree363a82d20ba8e2f2b293a6abbc43b7ff97ec219e
parent5af13f35f98c75d063cadf5e5607d066cbdb3e0e

macho: remove all Zld codepaths


1 files changed, 68 insertions(+), 696 deletions(-)

src/link/MachO.zig+68-696
......@@ -761,43 +761,34 @@ pub fn flush(self: *MachO, comp: *Compilation) !void {
761761 try self.addDataInCodeLC();
762762 try self.addCodeSignatureLC();
763763
764 if (use_stage1) {
765 try self.parseTextBlocks();
766 try self.allocateTextSegment();
767 try self.allocateDataConstSegment();
768 try self.allocateDataSegment();
769 self.allocateLinkeditSegment();
770 try self.allocateTextBlocks();
771 try self.flushZld();
772 } else {
773 try self.parseTextBlocks();
774 try self.allocateGlobalSymbols();
775 {
776 log.debug("locals:", .{});
777 for (self.locals.items) |sym| {
778 log.debug(" {s}: {}", .{ self.getString(sym.n_strx), sym });
779 }
780 log.debug("globals:", .{});
781 for (self.globals.items) |sym| {
782 log.debug(" {s}: {}", .{ self.getString(sym.n_strx), sym });
783 }
784 log.debug("undefs:", .{});
785 for (self.undefs.items) |sym| {
786 log.debug(" {s}: {}", .{ self.getString(sym.n_strx), sym });
787 }
788 log.debug("unresolved:", .{});
789 for (self.unresolved.keys()) |key| {
790 log.debug(" {d} => {s}", .{ key, self.unresolved.get(key).? });
791 }
792 log.debug("resolved:", .{});
793 var it = self.symbol_resolver.iterator();
794 while (it.next()) |entry| {
795 log.debug(" {s} => {}", .{ self.getString(entry.key_ptr.*), entry.value_ptr.* });
796 }
764 try self.parseTextBlocks();
765 try self.allocateGlobalSymbols();
766 {
767 log.debug("locals:", .{});
768 for (self.locals.items) |sym| {
769 log.debug(" {s}: {}", .{ self.getString(sym.n_strx), sym });
770 }
771 log.debug("globals:", .{});
772 for (self.globals.items) |sym| {
773 log.debug(" {s}: {}", .{ self.getString(sym.n_strx), sym });
774 }
775 log.debug("undefs:", .{});
776 for (self.undefs.items) |sym| {
777 log.debug(" {s}: {}", .{ self.getString(sym.n_strx), sym });
778 }
779 log.debug("unresolved:", .{});
780 for (self.unresolved.keys()) |key| {
781 log.debug(" {d} => {s}", .{ key, self.unresolved.get(key).? });
782 }
783 log.debug("resolved:", .{});
784 var it = self.symbol_resolver.iterator();
785 while (it.next()) |entry| {
786 log.debug(" {s} => {}", .{ self.getString(entry.key_ptr.*), entry.value_ptr.* });
797787 }
798 try self.writeAtoms();
799 try self.flushModule(comp);
800788 }
789 try self.writeAtoms();
790 try self.writeDices();
791 try self.flushModule(comp);
801792 }
802793
803794 if (!self.base.options.disable_lld_caching) {
......@@ -1638,248 +1629,6 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
16381629 return res;
16391630}
16401631
1641fn allocateTextSegment(self: *MachO) !void {
1642 const seg = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;
1643 const base_vmaddr = self.load_commands.items[self.pagezero_segment_cmd_index.?].Segment.inner.vmsize;
1644 seg.inner.fileoff = 0;
1645 seg.inner.vmaddr = base_vmaddr;
1646
1647 var sizeofcmds: u64 = 0;
1648 for (self.load_commands.items) |lc| {
1649 sizeofcmds += lc.cmdsize();
1650 }
1651
1652 try self.allocateSegment(self.text_segment_cmd_index.?, @sizeOf(macho.mach_header_64) + sizeofcmds);
1653
1654 // Shift all sections to the back to minimize jump size between __TEXT and __DATA segments.
1655 var min_alignment: u32 = 0;
1656 for (seg.sections.items) |sect| {
1657 const alignment = try math.powi(u32, 2, sect.@"align");
1658 min_alignment = math.max(min_alignment, alignment);
1659 }
1660
1661 assert(min_alignment > 0);
1662 const last_sect_idx = seg.sections.items.len - 1;
1663 const last_sect = seg.sections.items[last_sect_idx];
1664 const shift: u32 = blk: {
1665 const diff = seg.inner.filesize - last_sect.offset - last_sect.size;
1666 const factor = @divTrunc(diff, min_alignment);
1667 break :blk @intCast(u32, factor * min_alignment);
1668 };
1669
1670 if (shift > 0) {
1671 for (seg.sections.items) |*sect| {
1672 sect.offset += shift;
1673 sect.addr += shift;
1674 }
1675 }
1676}
1677
1678fn allocateDataConstSegment(self: *MachO) !void {
1679 const seg = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
1680 const text_seg = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
1681 seg.inner.fileoff = text_seg.inner.fileoff + text_seg.inner.filesize;
1682 seg.inner.vmaddr = text_seg.inner.vmaddr + text_seg.inner.vmsize;
1683 try self.allocateSegment(self.data_const_segment_cmd_index.?, 0);
1684}
1685
1686fn allocateDataSegment(self: *MachO) !void {
1687 const seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
1688 const data_const_seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
1689 seg.inner.fileoff = data_const_seg.inner.fileoff + data_const_seg.inner.filesize;
1690 seg.inner.vmaddr = data_const_seg.inner.vmaddr + data_const_seg.inner.vmsize;
1691 try self.allocateSegment(self.data_segment_cmd_index.?, 0);
1692}
1693
1694fn allocateLinkeditSegment(self: *MachO) void {
1695 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
1696 const data_seg = self.load_commands.items[self.data_segment_cmd_index.?].Segment;
1697 seg.inner.fileoff = data_seg.inner.fileoff + data_seg.inner.filesize;
1698 seg.inner.vmaddr = data_seg.inner.vmaddr + data_seg.inner.vmsize;
1699}
1700
1701fn allocateSegment(self: *MachO, index: u16, offset: u64) !void {
1702 const seg = &self.load_commands.items[index].Segment;
1703
1704 // Allocate the sections according to their alignment at the beginning of the segment.
1705 var start: u64 = offset;
1706 for (seg.sections.items) |*sect, sect_id| {
1707 const alignment = try math.powi(u32, 2, sect.@"align");
1708 const start_aligned = mem.alignForwardGeneric(u64, start, alignment);
1709 const end_aligned = mem.alignForwardGeneric(u64, start_aligned + sect.size, alignment);
1710 const file_offset = @intCast(u32, seg.inner.fileoff + start_aligned);
1711
1712 blk: {
1713 if (index == self.data_segment_cmd_index.?) {
1714 if (self.bss_section_index) |idx| {
1715 if (sect_id == idx) {
1716 self.bss_file_offset = file_offset;
1717 break :blk;
1718 }
1719 }
1720 if (self.tlv_bss_section_index) |idx| {
1721 if (sect_id == idx) {
1722 self.tlv_bss_file_offset = file_offset;
1723 break :blk;
1724 }
1725 }
1726 }
1727 sect.offset = @intCast(u32, seg.inner.fileoff + start_aligned);
1728 }
1729
1730 sect.addr = seg.inner.vmaddr + start_aligned;
1731 start = end_aligned;
1732 }
1733
1734 const seg_size_aligned = mem.alignForwardGeneric(u64, start, self.page_size);
1735 seg.inner.filesize = seg_size_aligned;
1736 seg.inner.vmsize = seg_size_aligned;
1737}
1738
1739fn allocateTextBlocks(self: *MachO) !void {
1740 var it = self.blocks.iterator();
1741 while (it.next()) |entry| {
1742 const match = entry.key_ptr.*;
1743 var block: *TextBlock = entry.value_ptr.*;
1744
1745 // Find the first block
1746 while (block.prev) |prev| {
1747 block = prev;
1748 }
1749
1750 const seg = self.load_commands.items[match.seg].Segment;
1751 const sect = seg.sections.items[match.sect];
1752
1753 var base_addr: u64 = sect.addr;
1754 const n_sect = @intCast(u8, self.section_ordinals.getIndex(match).? + 1);
1755
1756 log.debug(" within section {s},{s}", .{ commands.segmentName(sect), commands.sectionName(sect) });
1757 log.debug(" {}", .{sect});
1758
1759 while (true) {
1760 const block_alignment = try math.powi(u32, 2, block.alignment);
1761 base_addr = mem.alignForwardGeneric(u64, base_addr, block_alignment);
1762
1763 const sym = &self.locals.items[block.local_sym_index];
1764 sym.n_value = base_addr;
1765 sym.n_sect = n_sect;
1766
1767 log.debug(" {s}: start=0x{x}, end=0x{x}, size={}, align={}", .{
1768 self.getString(sym.n_strx),
1769 base_addr,
1770 base_addr + block.size,
1771 block.size,
1772 block.alignment,
1773 });
1774
1775 // Update each alias (if any)
1776 for (block.aliases.items) |index| {
1777 const alias_sym = &self.locals.items[index];
1778 alias_sym.n_value = base_addr;
1779 alias_sym.n_sect = n_sect;
1780 }
1781
1782 // Update each symbol contained within the TextBlock
1783 for (block.contained.items) |sym_at_off| {
1784 const contained_sym = &self.locals.items[sym_at_off.local_sym_index];
1785 contained_sym.n_value = base_addr + sym_at_off.offset;
1786 contained_sym.n_sect = n_sect;
1787 }
1788
1789 base_addr += block.size;
1790
1791 if (block.next) |next| {
1792 block = next;
1793 } else break;
1794 }
1795 }
1796
1797 // Update globals
1798 {
1799 var sym_it = self.symbol_resolver.valueIterator();
1800 while (sym_it.next()) |resolv| {
1801 if (resolv.where != .global) continue;
1802
1803 assert(resolv.local_sym_index != 0);
1804 const local_sym = self.locals.items[resolv.local_sym_index];
1805 const sym = &self.globals.items[resolv.where_index];
1806 sym.n_value = local_sym.n_value;
1807 sym.n_sect = local_sym.n_sect;
1808 }
1809 }
1810}
1811
1812fn writeTextBlocks(self: *MachO) !void {
1813 var it = self.blocks.iterator();
1814 while (it.next()) |entry| {
1815 const match = entry.key_ptr.*;
1816 var block: *TextBlock = entry.value_ptr.*;
1817
1818 while (block.prev) |prev| {
1819 block = prev;
1820 }
1821
1822 const seg = self.load_commands.items[match.seg].Segment;
1823 const sect = seg.sections.items[match.sect];
1824 const sect_type = commands.sectionType(sect);
1825
1826 log.debug(" for section {s},{s}", .{ commands.segmentName(sect), commands.sectionName(sect) });
1827 log.debug(" {}", .{sect});
1828
1829 var code = try self.base.allocator.alloc(u8, sect.size);
1830 defer self.base.allocator.free(code);
1831
1832 const file_offset: u64 = blk: {
1833 if (self.data_segment_cmd_index.? == match.seg) {
1834 if (self.bss_section_index) |idx| {
1835 if (idx == match.sect) break :blk self.bss_file_offset.?;
1836 }
1837 if (self.tlv_bss_section_index) |idx| {
1838 if (idx == match.sect) break :blk self.tlv_bss_file_offset.?;
1839 }
1840 }
1841 break :blk sect.offset;
1842 };
1843
1844 if (sect_type == macho.S_ZEROFILL or sect_type == macho.S_THREAD_LOCAL_ZEROFILL) {
1845 mem.set(u8, code, 0);
1846 } else {
1847 var base_off: u64 = 0;
1848
1849 while (true) {
1850 const block_alignment = try math.powi(u32, 2, block.alignment);
1851 const aligned_base_off = mem.alignForwardGeneric(u64, base_off, block_alignment);
1852
1853 const sym = self.locals.items[block.local_sym_index];
1854 log.debug(" {s}: start=0x{x}, end=0x{x}, size={}, align={}", .{
1855 self.getString(sym.n_strx),
1856 aligned_base_off,
1857 aligned_base_off + block.size,
1858 block.size,
1859 block.alignment,
1860 });
1861
1862 try block.resolveRelocs(self);
1863 mem.copy(u8, code[aligned_base_off..][0..block.size], block.code.items);
1864
1865 // TODO NOP for machine code instead of just zeroing out
1866 const padding_len = aligned_base_off - base_off;
1867 mem.set(u8, code[base_off..][0..padding_len], 0);
1868
1869 base_off = aligned_base_off + block.size;
1870
1871 if (block.next) |next| {
1872 block = next;
1873 } else break;
1874 }
1875
1876 mem.set(u8, code[base_off..], 0);
1877 }
1878
1879 try self.base.file.?.pwriteAll(code, file_offset);
1880 }
1881}
1882
18831632pub fn createEmptyAtom(self: *MachO, local_sym_index: u32, size: u64, alignment: u32) !*TextBlock {
18841633 const code = try self.base.allocator.alloc(u8, size);
18851634 defer self.base.allocator.free(code);
......@@ -2920,17 +2669,23 @@ fn parseTextBlocks(self: *MachO) !void {
29202669}
29212670
29222671fn addDataInCodeLC(self: *MachO) !void {
2923 if (self.data_in_code_cmd_index == null) {
2924 self.data_in_code_cmd_index = @intCast(u16, self.load_commands.items.len);
2925 try self.load_commands.append(self.base.allocator, .{
2926 .LinkeditData = .{
2927 .cmd = macho.LC_DATA_IN_CODE,
2928 .cmdsize = @sizeOf(macho.linkedit_data_command),
2929 .dataoff = 0,
2930 .datasize = 0,
2931 },
2932 });
2933 }
2672 if (self.data_in_code_cmd_index != null) return;
2673 self.data_in_code_cmd_index = @intCast(u16, self.load_commands.items.len);
2674 try self.load_commands.append(self.base.allocator, .{
2675 .LinkeditData = .{
2676 .cmd = macho.LC_DATA_IN_CODE,
2677 .cmdsize = @sizeOf(macho.linkedit_data_command),
2678 .dataoff = 0,
2679 .datasize = 0,
2680 },
2681 });
2682 const dice_cmd = &self.load_commands.items[self.data_in_code_cmd_index.?].LinkeditData;
2683 const needed_size = 10 * @sizeOf(macho.data_in_code_entry);
2684 const dataoff = self.findFreeSpaceLinkedit(needed_size, @alignOf(macho.data_in_code_entry), null);
2685 log.debug("found data-in-code free space 0x{x} to 0x{x}", .{ dataoff, dataoff + needed_size });
2686 dice_cmd.dataoff = @intCast(u32, dataoff);
2687 dice_cmd.datasize = needed_size;
2688 self.load_commands_dirty = true;
29342689}
29352690
29362691fn addCodeSignatureLC(self: *MachO) !void {
......@@ -2982,42 +2737,6 @@ fn addLoadDylibLCs(self: *MachO) !void {
29822737 }
29832738}
29842739
2985fn flushZld(self: *MachO) !void {
2986 try self.writeTextBlocks();
2987 try self.setEntryPoint();
2988 try self.writeRebaseInfoTableZld();
2989 try self.writeBindInfoTableZld();
2990 try self.writeLazyBindInfoTableZld();
2991 try self.writeExportInfoZld();
2992 try self.writeDices();
2993
2994 {
2995 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
2996 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;
2997 symtab.symoff = @intCast(u32, seg.inner.fileoff + seg.inner.filesize);
2998 }
2999
3000 try self.writeSymbolTable();
3001 try self.writeStringTableZld();
3002
3003 {
3004 // Seal __LINKEDIT size
3005 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
3006 seg.inner.vmsize = mem.alignForwardGeneric(u64, seg.inner.filesize, self.page_size);
3007 }
3008
3009 if (self.requires_adhoc_codesig) {
3010 try self.writeCodeSignaturePadding();
3011 }
3012
3013 try self.writeLoadCommands();
3014 try self.writeHeader();
3015
3016 if (self.requires_adhoc_codesig) {
3017 try self.writeCodeSignature();
3018 }
3019}
3020
30212740fn setEntryPoint(self: *MachO) !void {
30222741 if (self.base.options.output_mode != .Exe) return;
30232742
......@@ -3039,343 +2758,6 @@ fn setEntryPoint(self: *MachO) !void {
30392758 self.load_commands_dirty = true;
30402759}
30412760
3042fn writeRebaseInfoTableZld(self: *MachO) !void {
3043 var pointers = std.ArrayList(bind.Pointer).init(self.base.allocator);
3044 defer pointers.deinit();
3045
3046 {
3047 var it = self.blocks.iterator();
3048 while (it.next()) |entry| {
3049 const match = entry.key_ptr.*;
3050 var block: *TextBlock = entry.value_ptr.*;
3051
3052 if (match.seg == self.text_segment_cmd_index.?) continue; // __TEXT is non-writable
3053
3054 const seg = self.load_commands.items[match.seg].Segment;
3055
3056 while (true) {
3057 const sym = self.locals.items[block.local_sym_index];
3058 const base_offset = sym.n_value - seg.inner.vmaddr;
3059
3060 for (block.rebases.items) |offset| {
3061 try pointers.append(.{
3062 .offset = base_offset + offset,
3063 .segment_id = match.seg,
3064 });
3065 }
3066
3067 if (block.prev) |prev| {
3068 block = prev;
3069 } else break;
3070 }
3071 }
3072 }
3073
3074 const size = try bind.rebaseInfoSize(pointers.items);
3075 var buffer = try self.base.allocator.alloc(u8, @intCast(usize, size));
3076 defer self.base.allocator.free(buffer);
3077
3078 var stream = std.io.fixedBufferStream(buffer);
3079 try bind.writeRebaseInfo(pointers.items, stream.writer());
3080
3081 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
3082 const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly;
3083 dyld_info.rebase_off = @intCast(u32, seg.inner.fileoff);
3084 dyld_info.rebase_size = @intCast(u32, mem.alignForwardGeneric(u64, buffer.len, @sizeOf(u64)));
3085 seg.inner.filesize += dyld_info.rebase_size;
3086
3087 log.debug("writing rebase info from 0x{x} to 0x{x}", .{ dyld_info.rebase_off, dyld_info.rebase_off + dyld_info.rebase_size });
3088
3089 try self.base.file.?.pwriteAll(buffer, dyld_info.rebase_off);
3090}
3091
3092fn writeBindInfoTableZld(self: *MachO) !void {
3093 var pointers = std.ArrayList(bind.Pointer).init(self.base.allocator);
3094 defer pointers.deinit();
3095
3096 {
3097 var it = self.blocks.iterator();
3098 while (it.next()) |entry| {
3099 const match = entry.key_ptr.*;
3100 var block: *TextBlock = entry.value_ptr.*;
3101
3102 if (match.seg == self.text_segment_cmd_index.?) continue; // __TEXT is non-writable
3103
3104 const seg = self.load_commands.items[match.seg].Segment;
3105
3106 while (true) {
3107 const sym = self.locals.items[block.local_sym_index];
3108 const base_offset = sym.n_value - seg.inner.vmaddr;
3109
3110 for (block.bindings.items) |binding| {
3111 const bind_sym = self.undefs.items[binding.local_sym_index];
3112 try pointers.append(.{
3113 .offset = binding.offset + base_offset,
3114 .segment_id = match.seg,
3115 .dylib_ordinal = @divExact(bind_sym.n_desc, macho.N_SYMBOL_RESOLVER),
3116 .name = self.getString(bind_sym.n_strx),
3117 });
3118 }
3119
3120 if (block.prev) |prev| {
3121 block = prev;
3122 } else break;
3123 }
3124 }
3125 }
3126
3127 const size = try bind.bindInfoSize(pointers.items);
3128 var buffer = try self.base.allocator.alloc(u8, @intCast(usize, size));
3129 defer self.base.allocator.free(buffer);
3130
3131 var stream = std.io.fixedBufferStream(buffer);
3132 try bind.writeBindInfo(pointers.items, stream.writer());
3133
3134 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
3135 const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly;
3136 dyld_info.bind_off = @intCast(u32, seg.inner.fileoff + seg.inner.filesize);
3137 dyld_info.bind_size = @intCast(u32, mem.alignForwardGeneric(u64, buffer.len, @alignOf(u64)));
3138 seg.inner.filesize += dyld_info.bind_size;
3139
3140 log.debug("writing binding info from 0x{x} to 0x{x}", .{ dyld_info.bind_off, dyld_info.bind_off + dyld_info.bind_size });
3141
3142 try self.base.file.?.pwriteAll(buffer, dyld_info.bind_off);
3143}
3144
3145fn writeLazyBindInfoTableZld(self: *MachO) !void {
3146 var pointers = std.ArrayList(bind.Pointer).init(self.base.allocator);
3147 defer pointers.deinit();
3148
3149 if (self.la_symbol_ptr_section_index) |sect| blk: {
3150 var atom = self.blocks.get(.{
3151 .seg = self.data_segment_cmd_index.?,
3152 .sect = sect,
3153 }) orelse break :blk;
3154 const seg = self.load_commands.items[self.data_segment_cmd_index.?].Segment;
3155
3156 while (true) {
3157 const sym = self.locals.items[atom.local_sym_index];
3158 const base_offset = sym.n_value - seg.inner.vmaddr;
3159
3160 for (atom.lazy_bindings.items) |binding| {
3161 const bind_sym = self.undefs.items[binding.local_sym_index];
3162 try pointers.append(.{
3163 .offset = binding.offset + base_offset,
3164 .segment_id = self.data_segment_cmd_index.?,
3165 .dylib_ordinal = @divExact(bind_sym.n_desc, macho.N_SYMBOL_RESOLVER),
3166 .name = self.getString(bind_sym.n_strx),
3167 });
3168 }
3169 if (atom.prev) |prev| {
3170 atom = prev;
3171 } else break;
3172 }
3173 }
3174
3175 const size = try bind.lazyBindInfoSize(pointers.items);
3176 var buffer = try self.base.allocator.alloc(u8, @intCast(usize, size));
3177 defer self.base.allocator.free(buffer);
3178
3179 var stream = std.io.fixedBufferStream(buffer);
3180 try bind.writeLazyBindInfo(pointers.items, stream.writer());
3181
3182 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
3183 const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly;
3184 dyld_info.lazy_bind_off = @intCast(u32, seg.inner.fileoff + seg.inner.filesize);
3185 dyld_info.lazy_bind_size = @intCast(u32, mem.alignForwardGeneric(u64, buffer.len, @alignOf(u64)));
3186 seg.inner.filesize += dyld_info.lazy_bind_size;
3187
3188 log.debug("writing lazy binding info from 0x{x} to 0x{x}", .{ dyld_info.lazy_bind_off, dyld_info.lazy_bind_off + dyld_info.lazy_bind_size });
3189
3190 try self.base.file.?.pwriteAll(buffer, dyld_info.lazy_bind_off);
3191 try self.populateLazyBindOffsetsInStubHelper(buffer);
3192}
3193
3194fn writeExportInfoZld(self: *MachO) !void {
3195 var trie: Trie = .{};
3196 defer trie.deinit(self.base.allocator);
3197
3198 const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
3199 const base_address = text_segment.inner.vmaddr;
3200
3201 // TODO handle macho.EXPORT_SYMBOL_FLAGS_REEXPORT and macho.EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER.
3202 log.debug("writing export trie", .{});
3203
3204 for (self.globals.items) |sym| {
3205 const sym_name = self.getString(sym.n_strx);
3206 log.debug(" | putting '{s}' defined at 0x{x}", .{ sym_name, sym.n_value });
3207
3208 try trie.put(self.base.allocator, .{
3209 .name = sym_name,
3210 .vmaddr_offset = sym.n_value - base_address,
3211 .export_flags = macho.EXPORT_SYMBOL_FLAGS_KIND_REGULAR,
3212 });
3213 }
3214
3215 try trie.finalize(self.base.allocator);
3216
3217 var buffer = try self.base.allocator.alloc(u8, @intCast(usize, trie.size));
3218 defer self.base.allocator.free(buffer);
3219
3220 var stream = std.io.fixedBufferStream(buffer);
3221 const nwritten = try trie.write(stream.writer());
3222 assert(nwritten == trie.size);
3223
3224 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
3225 const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly;
3226 dyld_info.export_off = @intCast(u32, seg.inner.fileoff + seg.inner.filesize);
3227 dyld_info.export_size = @intCast(u32, mem.alignForwardGeneric(u64, buffer.len, @alignOf(u64)));
3228 seg.inner.filesize += dyld_info.export_size;
3229
3230 log.debug("writing export info from 0x{x} to 0x{x}", .{ dyld_info.export_off, dyld_info.export_off + dyld_info.export_size });
3231
3232 try self.base.file.?.pwriteAll(buffer, dyld_info.export_off);
3233}
3234
3235fn writeSymbolTable(self: *MachO) !void {
3236 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
3237 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;
3238
3239 var locals = std.ArrayList(macho.nlist_64).init(self.base.allocator);
3240 defer locals.deinit();
3241 try locals.appendSlice(self.locals.items);
3242
3243 if (self.has_stabs) {
3244 for (self.objects.items) |object| {
3245 if (object.debug_info == null) continue;
3246
3247 // Open scope
3248 try locals.ensureUnusedCapacity(3);
3249 locals.appendAssumeCapacity(.{
3250 .n_strx = try self.makeString(object.tu_comp_dir.?),
3251 .n_type = macho.N_SO,
3252 .n_sect = 0,
3253 .n_desc = 0,
3254 .n_value = 0,
3255 });
3256 locals.appendAssumeCapacity(.{
3257 .n_strx = try self.makeString(object.tu_name.?),
3258 .n_type = macho.N_SO,
3259 .n_sect = 0,
3260 .n_desc = 0,
3261 .n_value = 0,
3262 });
3263 locals.appendAssumeCapacity(.{
3264 .n_strx = try self.makeString(object.name),
3265 .n_type = macho.N_OSO,
3266 .n_sect = 0,
3267 .n_desc = 1,
3268 .n_value = object.mtime orelse 0,
3269 });
3270
3271 for (object.text_blocks.items) |block| {
3272 if (block.stab) |stab| {
3273 const nlists = try stab.asNlists(block.local_sym_index, self);
3274 defer self.base.allocator.free(nlists);
3275 try locals.appendSlice(nlists);
3276 } else {
3277 for (block.contained.items) |sym_at_off| {
3278 const stab = sym_at_off.stab orelse continue;
3279 const nlists = try stab.asNlists(sym_at_off.local_sym_index, self);
3280 defer self.base.allocator.free(nlists);
3281 try locals.appendSlice(nlists);
3282 }
3283 }
3284 }
3285
3286 // Close scope
3287 try locals.append(.{
3288 .n_strx = 0,
3289 .n_type = macho.N_SO,
3290 .n_sect = 0,
3291 .n_desc = 0,
3292 .n_value = 0,
3293 });
3294 }
3295 }
3296
3297 const nlocals = locals.items.len;
3298 const nexports = self.globals.items.len;
3299 const nundefs = self.undefs.items.len;
3300
3301 const locals_off = symtab.symoff;
3302 const locals_size = nlocals * @sizeOf(macho.nlist_64);
3303 log.debug("writing local symbols from 0x{x} to 0x{x}", .{ locals_off, locals_size + locals_off });
3304 try self.base.file.?.pwriteAll(mem.sliceAsBytes(locals.items), locals_off);
3305
3306 const exports_off = locals_off + locals_size;
3307 const exports_size = nexports * @sizeOf(macho.nlist_64);
3308 log.debug("writing exported symbols from 0x{x} to 0x{x}", .{ exports_off, exports_size + exports_off });
3309 try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.globals.items), exports_off);
3310
3311 const undefs_off = exports_off + exports_size;
3312 const undefs_size = nundefs * @sizeOf(macho.nlist_64);
3313 log.debug("writing undefined symbols from 0x{x} to 0x{x}", .{ undefs_off, undefs_size + undefs_off });
3314 try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.undefs.items), undefs_off);
3315
3316 symtab.nsyms = @intCast(u32, nlocals + nexports + nundefs);
3317 seg.inner.filesize += locals_size + exports_size + undefs_size;
3318
3319 // Update dynamic symbol table.
3320 const dysymtab = &self.load_commands.items[self.dysymtab_cmd_index.?].Dysymtab;
3321 dysymtab.nlocalsym = @intCast(u32, nlocals);
3322 dysymtab.iextdefsym = dysymtab.nlocalsym;
3323 dysymtab.nextdefsym = @intCast(u32, nexports);
3324 dysymtab.iundefsym = dysymtab.nlocalsym + dysymtab.nextdefsym;
3325 dysymtab.nundefsym = @intCast(u32, nundefs);
3326
3327 const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;
3328 const stubs = &text_segment.sections.items[self.stubs_section_index.?];
3329 const data_const_segment = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
3330 const got = &data_const_segment.sections.items[self.got_section_index.?];
3331 const data_segment = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
3332 const la_symbol_ptr = &data_segment.sections.items[self.la_symbol_ptr_section_index.?];
3333
3334 const nstubs = @intCast(u32, self.stubs_map.keys().len);
3335 const ngot_entries = @intCast(u32, self.got_entries_map.keys().len);
3336
3337 dysymtab.indirectsymoff = @intCast(u32, seg.inner.fileoff + seg.inner.filesize);
3338 dysymtab.nindirectsyms = nstubs * 2 + ngot_entries;
3339
3340 const needed_size = dysymtab.nindirectsyms * @sizeOf(u32);
3341 seg.inner.filesize += needed_size;
3342
3343 log.debug("writing indirect symbol table from 0x{x} to 0x{x}", .{
3344 dysymtab.indirectsymoff,
3345 dysymtab.indirectsymoff + needed_size,
3346 });
3347
3348 var buf = try self.base.allocator.alloc(u8, needed_size);
3349 defer self.base.allocator.free(buf);
3350
3351 var stream = std.io.fixedBufferStream(buf);
3352 var writer = stream.writer();
3353
3354 stubs.reserved1 = 0;
3355 for (self.stubs_map.keys()) |key| {
3356 try writer.writeIntLittle(u32, dysymtab.iundefsym + key);
3357 }
3358
3359 got.reserved1 = nstubs;
3360 for (self.got_entries_map.keys()) |key| {
3361 switch (key.where) {
3362 .undef => {
3363 try writer.writeIntLittle(u32, dysymtab.iundefsym + key.where_index);
3364 },
3365 .local => {
3366 try writer.writeIntLittle(u32, macho.INDIRECT_SYMBOL_LOCAL);
3367 },
3368 }
3369 }
3370
3371 la_symbol_ptr.reserved1 = got.reserved1 + ngot_entries;
3372 for (self.stubs_map.keys()) |key| {
3373 try writer.writeIntLittle(u32, dysymtab.iundefsym + key);
3374 }
3375
3376 try self.base.file.?.pwriteAll(buf, dysymtab.indirectsymoff);
3377}
3378
33792761pub fn deinit(self: *MachO) void {
33802762 if (build_options.have_llvm) {
33812763 if (self.llvm_object) |llvm_object| llvm_object.destroy(self.base.allocator);
......@@ -3812,12 +3194,6 @@ fn placeDecl(self: *MachO, decl: *Module.Decl, code_len: usize) !*macho.nlist_64
38123194 try ds.writeLocalSymbol(decl.link.macho.local_sym_index);
38133195 }
38143196
3815 // // Resolve relocations
3816 // try decl.link.macho.resolveRelocs(self);
3817 // // TODO this requires further investigation: should we dispose of resolved relocs, or keep them
3818 // // so that we can reapply them when moving/growing sections?
3819 // decl.link.macho.relocs.clearAndFree(self.base.allocator);
3820
38213197 return symbol;
38223198}
38233199
......@@ -5003,9 +4379,8 @@ fn writeIndirectSymbolTable(self: *MachO) !void {
50034379fn writeDices(self: *MachO) !void {
50044380 if (!self.has_dices) return;
50054381
5006 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
5007 const dice_cmd = &self.load_commands.items[self.data_in_code_cmd_index.?].LinkeditData;
5008 const fileoff = seg.inner.fileoff + seg.inner.filesize;
4382 const tracy = trace(@src());
4383 defer tracy.end();
50094384
50104385 var buf = std.ArrayList(u8).init(self.base.allocator);
50114386 defer buf.deinit();
......@@ -5043,15 +4418,26 @@ fn writeDices(self: *MachO) !void {
50434418 } else break;
50444419 }
50454420
5046 const datasize = @intCast(u32, buf.items.len);
5047
5048 dice_cmd.dataoff = @intCast(u32, fileoff);
5049 dice_cmd.datasize = datasize;
5050 seg.inner.filesize += datasize;
4421 const dice_cmd = &self.load_commands.items[self.data_in_code_cmd_index.?].LinkeditData;
4422 const allocated_size = self.allocatedSizeLinkedit(dice_cmd.dataoff);
4423 const needed_size = @intCast(u32, buf.items.len);
50514424
5052 log.debug("writing data-in-code from 0x{x} to 0x{x}", .{ fileoff, fileoff + datasize });
4425 if (needed_size > allocated_size) {
4426 dice_cmd.datasize = 0;
4427 dice_cmd.dataoff = @intCast(u32, self.findFreeSpaceLinkedit(
4428 needed_size,
4429 @alignOf(macho.data_in_code_entry),
4430 dice_cmd.dataoff,
4431 ));
4432 }
4433 dice_cmd.datasize = needed_size;
4434 log.debug("writing data-in-code from 0x{x} to 0x{x}", .{
4435 dice_cmd.dataoff,
4436 dice_cmd.dataoff + dice_cmd.datasize,
4437 });
50534438
5054 try self.base.file.?.pwriteAll(buf.items, fileoff);
4439 try self.base.file.?.pwriteAll(buf.items, dice_cmd.dataoff);
4440 self.load_commands_dirty = true;
50554441}
50564442
50574443fn writeCodeSignaturePadding(self: *MachO) !void {
......@@ -5130,7 +4516,7 @@ fn writeExportInfo(self: *MachO) !void {
51304516
51314517 for (self.globals.items) |sym| {
51324518 const sym_name = self.getString(sym.n_strx);
5133 log.debug(" | putting '{s}' defined at 0x{x}", .{ sym_name, sym.n_value });
4519 log.debug(" (putting '{s}' defined at 0x{x})", .{ sym_name, sym.n_value });
51344520
51354521 try trie.put(self.base.allocator, .{
51364522 .name = sym_name,
......@@ -5453,30 +4839,16 @@ fn writeStringTable(self: *MachO) !void {
54534839 self.strtab_needs_relocation = false;
54544840 }
54554841 symtab.strsize = @intCast(u32, needed_size);
5456 log.debug("writing string table from 0x{x} to 0x{x}", .{ symtab.stroff, symtab.stroff + symtab.strsize });
4842 log.debug("writing string table from 0x{x} to 0x{x}", .{
4843 symtab.stroff,
4844 symtab.stroff + symtab.strsize,
4845 });
54574846
54584847 try self.base.file.?.pwriteAll(self.strtab.items, symtab.stroff);
54594848 self.load_commands_dirty = true;
54604849 self.strtab_dirty = false;
54614850}
54624851
5463fn writeStringTableZld(self: *MachO) !void {
5464 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
5465 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;
5466 symtab.stroff = @intCast(u32, seg.inner.fileoff + seg.inner.filesize);
5467 symtab.strsize = @intCast(u32, mem.alignForwardGeneric(u64, self.strtab.items.len, @alignOf(u64)));
5468 seg.inner.filesize += symtab.strsize;
5469
5470 log.debug("writing string table from 0x{x} to 0x{x}", .{ symtab.stroff, symtab.stroff + symtab.strsize });
5471
5472 try self.base.file.?.pwriteAll(self.strtab.items, symtab.stroff);
5473
5474 if (symtab.strsize > self.strtab.items.len) {
5475 // This is potentially the last section, so we need to pad it out.
5476 try self.base.file.?.pwriteAll(&[_]u8{0}, seg.inner.fileoff + seg.inner.filesize - 1);
5477 }
5478}
5479
54804852fn updateLinkeditSegmentSizes(self: *MachO) !void {
54814853 if (!self.load_commands_dirty) return;
54824854