| ... | @@ -147,13 +147,14 @@ unresolved: std.AutoArrayHashMapUnmanaged(u32, enum { | ... | @@ -147,13 +147,14 @@ unresolved: std.AutoArrayHashMapUnmanaged(u32, enum { |
| 147 | stub, | 147 | stub, |
| 148 | got, | 148 | got, |
| 149 | }) = .{}, | 149 | }) = .{}, |
| | 150 | tentatives: std.AutoArrayHashMapUnmanaged(u32, void) = .{}, |
| 150 | | 151 | |
| 151 | locals_free_list: std.ArrayListUnmanaged(u32) = .{}, | 152 | locals_free_list: std.ArrayListUnmanaged(u32) = .{}, |
| 152 | globals_free_list: std.ArrayListUnmanaged(u32) = .{}, | 153 | globals_free_list: std.ArrayListUnmanaged(u32) = .{}, |
| 153 | | 154 | |
| 154 | dyld_private_sym_index: ?u32 = null, | | |
| 155 | dyld_stub_binder_index: ?u32 = null, | 155 | dyld_stub_binder_index: ?u32 = null, |
| 156 | stub_preamble_sym_index: ?u32 = null, | 156 | dyld_private_atom: ?*Atom = null, |
| | 157 | stub_helper_preamble_atom: ?*Atom = null, |
| 157 | | 158 | |
| 158 | strtab: std.ArrayListUnmanaged(u8) = .{}, | 159 | strtab: std.ArrayListUnmanaged(u8) = .{}, |
| 159 | strtab_dir: std.HashMapUnmanaged(u32, u32, StringIndexContext, std.hash_map.default_max_load_percentage) = .{}, | 160 | strtab_dir: std.HashMapUnmanaged(u32, u32, StringIndexContext, std.hash_map.default_max_load_percentage) = .{}, |
| ... | @@ -777,10 +778,31 @@ pub fn flush(self: *MachO, comp: *Compilation) !void { | ... | @@ -777,10 +778,31 @@ pub fn flush(self: *MachO, comp: *Compilation) !void { |
| 777 | sect.offset = self.tlv_bss_file_offset; | 778 | sect.offset = self.tlv_bss_file_offset; |
| 778 | } | 779 | } |
| 779 | | 780 | |
| 780 | try self.resolveSymbols(); | 781 | for (self.objects.items) |_, object_id| { |
| 781 | try self.addLoadDylibLCs(); | 782 | try self.resolveSymbolsInObject(@intCast(u16, object_id)); |
| | 783 | } |
| | 784 | |
| | 785 | try self.resolveSymbolsInArchives(); |
| | 786 | try self.resolveDyldStubBinder(); |
| | 787 | try self.createDyldPrivateAtom(); |
| | 788 | try self.createStubHelperPreambleAtom(); |
| | 789 | try self.resolveSymbolsInDylibs(); |
| | 790 | try self.createDsoHandleAtom(); |
| 782 | try self.addCodeSignatureLC(); | 791 | try self.addCodeSignatureLC(); |
| 783 | | 792 | |
| | 793 | for (self.unresolved.keys()) |index| { |
| | 794 | const sym = self.undefs.items[index]; |
| | 795 | const sym_name = self.getString(sym.n_strx); |
| | 796 | const resolv = self.symbol_resolver.get(sym.n_strx) orelse unreachable; |
| | 797 | |
| | 798 | log.err("undefined reference to symbol '{s}'", .{sym_name}); |
| | 799 | log.err(" first referenced in '{s}'", .{self.objects.items[resolv.file].name}); |
| | 800 | } |
| | 801 | if (self.unresolved.count() > 0) { |
| | 802 | return error.UndefinedSymbolReference; |
| | 803 | } |
| | 804 | |
| | 805 | try self.createTentativeDefAtoms(); |
| 784 | try self.parseObjectsIntoAtoms(); | 806 | try self.parseObjectsIntoAtoms(); |
| 785 | try self.allocateGlobalSymbols(); | 807 | try self.allocateGlobalSymbols(); |
| 786 | try self.writeAtoms(); | 808 | try self.writeAtoms(); |
| ... | @@ -1055,6 +1077,7 @@ pub fn parseDylib(self: *MachO, path: []const u8, opts: DylibCreateOpts) ParseDy | ... | @@ -1055,6 +1077,7 @@ pub fn parseDylib(self: *MachO, path: []const u8, opts: DylibCreateOpts) ParseDy |
| 1055 | try self.dylibs_map.putNoClobber(self.base.allocator, dylib.id.?.name, dylib_id); | 1077 | try self.dylibs_map.putNoClobber(self.base.allocator, dylib.id.?.name, dylib_id); |
| 1056 | | 1078 | |
| 1057 | if (!(opts.is_dependent or self.referenced_dylibs.contains(dylib_id))) { | 1079 | if (!(opts.is_dependent or self.referenced_dylibs.contains(dylib_id))) { |
| | 1080 | try self.addLoadDylibLC(dylib_id); |
| 1058 | try self.referenced_dylibs.putNoClobber(self.base.allocator, dylib_id, {}); | 1081 | try self.referenced_dylibs.putNoClobber(self.base.allocator, dylib_id, {}); |
| 1059 | } | 1082 | } |
| 1060 | | 1083 | |
| ... | @@ -1789,20 +1812,31 @@ pub fn createGotAtom(self: *MachO, key: GotIndirectionKey) !*Atom { | ... | @@ -1789,20 +1812,31 @@ pub fn createGotAtom(self: *MachO, key: GotIndirectionKey) !*Atom { |
| 1789 | return atom; | 1812 | return atom; |
| 1790 | } | 1813 | } |
| 1791 | | 1814 | |
| 1792 | fn createDyldPrivateAtom(self: *MachO) !*Atom { | 1815 | fn createDyldPrivateAtom(self: *MachO) !void { |
| | 1816 | if (self.dyld_private_atom != null) return; |
| 1793 | const local_sym_index = @intCast(u32, self.locals.items.len); | 1817 | const local_sym_index = @intCast(u32, self.locals.items.len); |
| 1794 | try self.locals.append(self.base.allocator, .{ | 1818 | const sym = try self.locals.addOne(self.base.allocator); |
| | 1819 | sym.* = .{ |
| 1795 | .n_strx = try self.makeString("l_zld_dyld_private"), | 1820 | .n_strx = try self.makeString("l_zld_dyld_private"), |
| 1796 | .n_type = macho.N_SECT, | 1821 | .n_type = macho.N_SECT, |
| 1797 | .n_sect = 0, | 1822 | .n_sect = 0, |
| 1798 | .n_desc = 0, | 1823 | .n_desc = 0, |
| 1799 | .n_value = 0, | 1824 | .n_value = 0, |
| 1800 | }); | 1825 | }; |
| 1801 | self.dyld_private_sym_index = local_sym_index; | 1826 | const atom = try self.createEmptyAtom(local_sym_index, @sizeOf(u64), 3); |
| 1802 | return self.createEmptyAtom(local_sym_index, @sizeOf(u64), 3); | 1827 | self.dyld_private_atom = atom; |
| | 1828 | const match = MatchingSection{ |
| | 1829 | .seg = self.data_segment_cmd_index.?, |
| | 1830 | .sect = self.data_section_index.?, |
| | 1831 | }; |
| | 1832 | const vaddr = try self.allocateAtom(atom, @sizeOf(u64), 8, match); |
| | 1833 | sym.n_value = vaddr; |
| | 1834 | sym.n_sect = @intCast(u8, self.section_ordinals.getIndex(match).? + 1); |
| | 1835 | log.debug("allocated {s} atom at 0x{x}", .{ self.getString(sym.n_strx), vaddr }); |
| 1803 | } | 1836 | } |
| 1804 | | 1837 | |
| 1805 | fn createStubHelperPreambleAtom(self: *MachO) !*Atom { | 1838 | fn createStubHelperPreambleAtom(self: *MachO) !void { |
| | 1839 | if (self.stub_helper_preamble_atom != null) return; |
| 1806 | const arch = self.base.options.target.cpu.arch; | 1840 | const arch = self.base.options.target.cpu.arch; |
| 1807 | const size: u64 = switch (arch) { | 1841 | const size: u64 = switch (arch) { |
| 1808 | .x86_64 => 15, | 1842 | .x86_64 => 15, |
| ... | @@ -1815,14 +1849,16 @@ fn createStubHelperPreambleAtom(self: *MachO) !*Atom { | ... | @@ -1815,14 +1849,16 @@ fn createStubHelperPreambleAtom(self: *MachO) !*Atom { |
| 1815 | else => unreachable, | 1849 | else => unreachable, |
| 1816 | }; | 1850 | }; |
| 1817 | const local_sym_index = @intCast(u32, self.locals.items.len); | 1851 | const local_sym_index = @intCast(u32, self.locals.items.len); |
| 1818 | try self.locals.append(self.base.allocator, .{ | 1852 | const sym = try self.locals.addOne(self.base.allocator); |
| | 1853 | sym.* = .{ |
| 1819 | .n_strx = try self.makeString("l_zld_stub_preamble"), | 1854 | .n_strx = try self.makeString("l_zld_stub_preamble"), |
| 1820 | .n_type = macho.N_SECT, | 1855 | .n_type = macho.N_SECT, |
| 1821 | .n_sect = 0, | 1856 | .n_sect = 0, |
| 1822 | .n_desc = 0, | 1857 | .n_desc = 0, |
| 1823 | .n_value = 0, | 1858 | .n_value = 0, |
| 1824 | }); | 1859 | }; |
| 1825 | const atom = try self.createEmptyAtom(local_sym_index, size, alignment); | 1860 | const atom = try self.createEmptyAtom(local_sym_index, size, alignment); |
| | 1861 | const dyld_private_sym_index = self.dyld_private_atom.?.local_sym_index; |
| 1826 | switch (arch) { | 1862 | switch (arch) { |
| 1827 | .x86_64 => { | 1863 | .x86_64 => { |
| 1828 | try atom.relocs.ensureUnusedCapacity(self.base.allocator, 2); | 1864 | try atom.relocs.ensureUnusedCapacity(self.base.allocator, 2); |
| ... | @@ -1833,7 +1869,7 @@ fn createStubHelperPreambleAtom(self: *MachO) !*Atom { | ... | @@ -1833,7 +1869,7 @@ fn createStubHelperPreambleAtom(self: *MachO) !*Atom { |
| 1833 | atom.relocs.appendAssumeCapacity(.{ | 1869 | atom.relocs.appendAssumeCapacity(.{ |
| 1834 | .offset = 3, | 1870 | .offset = 3, |
| 1835 | .where = .local, | 1871 | .where = .local, |
| 1836 | .where_index = self.dyld_private_sym_index.?, | 1872 | .where_index = dyld_private_sym_index, |
| 1837 | .payload = .{ | 1873 | .payload = .{ |
| 1838 | .signed = .{ | 1874 | .signed = .{ |
| 1839 | .addend = 0, | 1875 | .addend = 0, |
| ... | @@ -1866,7 +1902,7 @@ fn createStubHelperPreambleAtom(self: *MachO) !*Atom { | ... | @@ -1866,7 +1902,7 @@ fn createStubHelperPreambleAtom(self: *MachO) !*Atom { |
| 1866 | atom.relocs.appendAssumeCapacity(.{ | 1902 | atom.relocs.appendAssumeCapacity(.{ |
| 1867 | .offset = 0, | 1903 | .offset = 0, |
| 1868 | .where = .local, | 1904 | .where = .local, |
| 1869 | .where_index = self.dyld_private_sym_index.?, | 1905 | .where_index = dyld_private_sym_index, |
| 1870 | .payload = .{ | 1906 | .payload = .{ |
| 1871 | .page = .{ | 1907 | .page = .{ |
| 1872 | .kind = .page, | 1908 | .kind = .page, |
| ... | @@ -1879,7 +1915,7 @@ fn createStubHelperPreambleAtom(self: *MachO) !*Atom { | ... | @@ -1879,7 +1915,7 @@ fn createStubHelperPreambleAtom(self: *MachO) !*Atom { |
| 1879 | atom.relocs.appendAssumeCapacity(.{ | 1915 | atom.relocs.appendAssumeCapacity(.{ |
| 1880 | .offset = 4, | 1916 | .offset = 4, |
| 1881 | .where = .local, | 1917 | .where = .local, |
| 1882 | .where_index = self.dyld_private_sym_index.?, | 1918 | .where_index = dyld_private_sym_index, |
| 1883 | .payload = .{ | 1919 | .payload = .{ |
| 1884 | .page_off = .{ | 1920 | .page_off = .{ |
| 1885 | .kind = .page, | 1921 | .kind = .page, |
| ... | @@ -1931,8 +1967,16 @@ fn createStubHelperPreambleAtom(self: *MachO) !*Atom { | ... | @@ -1931,8 +1967,16 @@ fn createStubHelperPreambleAtom(self: *MachO) !*Atom { |
| 1931 | }, | 1967 | }, |
| 1932 | else => unreachable, | 1968 | else => unreachable, |
| 1933 | } | 1969 | } |
| 1934 | self.stub_preamble_sym_index = local_sym_index; | 1970 | self.stub_helper_preamble_atom = atom; |
| 1935 | return atom; | 1971 | const match = MatchingSection{ |
| | 1972 | .seg = self.text_segment_cmd_index.?, |
| | 1973 | .sect = self.stub_helper_section_index.?, |
| | 1974 | }; |
| | 1975 | const alignment_pow_2 = try math.powi(u32, 2, atom.alignment); |
| | 1976 | const vaddr = try self.allocateAtom(atom, atom.size, alignment_pow_2, match); |
| | 1977 | sym.n_value = vaddr; |
| | 1978 | sym.n_sect = @intCast(u8, self.section_ordinals.getIndex(match).? + 1); |
| | 1979 | log.debug("allocated {s} atom at 0x{x}", .{ self.getString(sym.n_strx), vaddr }); |
| 1936 | } | 1980 | } |
| 1937 | | 1981 | |
| 1938 | pub fn createStubHelperAtom(self: *MachO) !*Atom { | 1982 | pub fn createStubHelperAtom(self: *MachO) !*Atom { |
| ... | @@ -1968,7 +2012,7 @@ pub fn createStubHelperAtom(self: *MachO) !*Atom { | ... | @@ -1968,7 +2012,7 @@ pub fn createStubHelperAtom(self: *MachO) !*Atom { |
| 1968 | atom.relocs.appendAssumeCapacity(.{ | 2012 | atom.relocs.appendAssumeCapacity(.{ |
| 1969 | .offset = 6, | 2013 | .offset = 6, |
| 1970 | .where = .local, | 2014 | .where = .local, |
| 1971 | .where_index = self.stub_preamble_sym_index.?, | 2015 | .where_index = self.stub_helper_preamble_atom.?.local_sym_index, |
| 1972 | .payload = .{ | 2016 | .payload = .{ |
| 1973 | .branch = .{ .arch = arch }, | 2017 | .branch = .{ .arch = arch }, |
| 1974 | }, | 2018 | }, |
| ... | @@ -1988,7 +2032,7 @@ pub fn createStubHelperAtom(self: *MachO) !*Atom { | ... | @@ -1988,7 +2032,7 @@ pub fn createStubHelperAtom(self: *MachO) !*Atom { |
| 1988 | atom.relocs.appendAssumeCapacity(.{ | 2032 | atom.relocs.appendAssumeCapacity(.{ |
| 1989 | .offset = 4, | 2033 | .offset = 4, |
| 1990 | .where = .local, | 2034 | .where = .local, |
| 1991 | .where_index = self.stub_preamble_sym_index.?, | 2035 | .where_index = self.stub_helper_preamble_atom.?.local_sym_index, |
| 1992 | .payload = .{ | 2036 | .payload = .{ |
| 1993 | .branch = .{ .arch = arch }, | 2037 | .branch = .{ .arch = arch }, |
| 1994 | }, | 2038 | }, |
| ... | @@ -2108,11 +2152,99 @@ pub fn createStubAtom(self: *MachO, laptr_sym_index: u32) !*Atom { | ... | @@ -2108,11 +2152,99 @@ pub fn createStubAtom(self: *MachO, laptr_sym_index: u32) !*Atom { |
| 2108 | return atom; | 2152 | return atom; |
| 2109 | } | 2153 | } |
| 2110 | | 2154 | |
| 2111 | fn resolveSymbolsInObject( | 2155 | fn createTentativeDefAtoms(self: *MachO) !void { |
| 2112 | self: *MachO, | 2156 | if (self.tentatives.count() == 0) return; |
| 2113 | object_id: u16, | 2157 | // Convert any tentative definition into a regular symbol and allocate |
| 2114 | tentatives: *std.AutoArrayHashMap(u32, void), | 2158 | // text blocks for each tentative defintion. |
| 2115 | ) !void { | 2159 | while (self.tentatives.popOrNull()) |entry| { |
| | 2160 | const match = MatchingSection{ |
| | 2161 | .seg = self.data_segment_cmd_index.?, |
| | 2162 | .sect = self.bss_section_index.?, |
| | 2163 | }; |
| | 2164 | _ = try self.section_ordinals.getOrPut(self.base.allocator, match); |
| | 2165 | |
| | 2166 | const global_sym = &self.globals.items[entry.key]; |
| | 2167 | const size = global_sym.n_value; |
| | 2168 | const alignment = (global_sym.n_desc >> 8) & 0x0f; |
| | 2169 | |
| | 2170 | global_sym.n_value = 0; |
| | 2171 | global_sym.n_desc = 0; |
| | 2172 | global_sym.n_sect = @intCast(u8, self.section_ordinals.getIndex(match).? + 1); |
| | 2173 | |
| | 2174 | const local_sym_index = @intCast(u32, self.locals.items.len); |
| | 2175 | const local_sym = try self.locals.addOne(self.base.allocator); |
| | 2176 | local_sym.* = .{ |
| | 2177 | .n_strx = global_sym.n_strx, |
| | 2178 | .n_type = macho.N_SECT, |
| | 2179 | .n_sect = global_sym.n_sect, |
| | 2180 | .n_desc = 0, |
| | 2181 | .n_value = 0, |
| | 2182 | }; |
| | 2183 | |
| | 2184 | const resolv = self.symbol_resolver.getPtr(local_sym.n_strx) orelse unreachable; |
| | 2185 | resolv.local_sym_index = local_sym_index; |
| | 2186 | |
| | 2187 | const atom = try self.createEmptyAtom(local_sym_index, size, alignment); |
| | 2188 | const alignment_pow_2 = try math.powi(u32, 2, alignment); |
| | 2189 | const vaddr = try self.allocateAtom(atom, size, alignment_pow_2, match); |
| | 2190 | local_sym.n_value = vaddr; |
| | 2191 | global_sym.n_value = vaddr; |
| | 2192 | } |
| | 2193 | } |
| | 2194 | |
| | 2195 | fn createDsoHandleAtom(self: *MachO) !void { |
| | 2196 | if (self.strtab_dir.getAdapted(@as([]const u8, "___dso_handle"), StringSliceAdapter{ |
| | 2197 | .strtab = &self.strtab, |
| | 2198 | })) |n_strx| blk: { |
| | 2199 | const resolv = self.symbol_resolver.getPtr(n_strx) orelse break :blk; |
| | 2200 | if (resolv.where != .undef) break :blk; |
| | 2201 | |
| | 2202 | const undef = &self.undefs.items[resolv.where_index]; |
| | 2203 | const match: MatchingSection = .{ |
| | 2204 | .seg = self.text_segment_cmd_index.?, |
| | 2205 | .sect = self.text_section_index.?, |
| | 2206 | }; |
| | 2207 | const local_sym_index = @intCast(u32, self.locals.items.len); |
| | 2208 | var nlist = macho.nlist_64{ |
| | 2209 | .n_strx = undef.n_strx, |
| | 2210 | .n_type = macho.N_SECT, |
| | 2211 | .n_sect = @intCast(u8, self.section_ordinals.getIndex(match).? + 1), |
| | 2212 | .n_desc = 0, |
| | 2213 | .n_value = 0, |
| | 2214 | }; |
| | 2215 | try self.locals.append(self.base.allocator, nlist); |
| | 2216 | const global_sym_index = @intCast(u32, self.globals.items.len); |
| | 2217 | nlist.n_type |= macho.N_EXT; |
| | 2218 | nlist.n_desc = macho.N_WEAK_DEF; |
| | 2219 | try self.globals.append(self.base.allocator, nlist); |
| | 2220 | |
| | 2221 | _ = self.unresolved.fetchSwapRemove(resolv.where_index); |
| | 2222 | |
| | 2223 | undef.* = .{ |
| | 2224 | .n_strx = 0, |
| | 2225 | .n_type = macho.N_UNDF, |
| | 2226 | .n_sect = 0, |
| | 2227 | .n_desc = 0, |
| | 2228 | .n_value = 0, |
| | 2229 | }; |
| | 2230 | resolv.* = .{ |
| | 2231 | .where = .global, |
| | 2232 | .where_index = global_sym_index, |
| | 2233 | .local_sym_index = local_sym_index, |
| | 2234 | }; |
| | 2235 | |
| | 2236 | // We create an empty atom for this symbol. |
| | 2237 | // TODO perhaps we should special-case special symbols? Create a separate |
| | 2238 | // linked list of atoms? |
| | 2239 | const atom = try self.createEmptyAtom(local_sym_index, 0, 0); |
| | 2240 | const sym = &self.locals.items[local_sym_index]; |
| | 2241 | const vaddr = try self.allocateAtom(atom, 0, 1, match); |
| | 2242 | sym.n_value = vaddr; |
| | 2243 | atom.dirty = false; // We don't really want to write it to file. |
| | 2244 | } |
| | 2245 | } |
| | 2246 | |
| | 2247 | fn resolveSymbolsInObject(self: *MachO, object_id: u16) !void { |
| 2116 | const object = &self.objects.items[object_id]; | 2248 | const object = &self.objects.items[object_id]; |
| 2117 | | 2249 | |
| 2118 | log.debug("resolving symbols in '{s}'", .{object.name}); | 2250 | log.debug("resolving symbols in '{s}'", .{object.name}); |
| ... | @@ -2184,7 +2316,7 @@ fn resolveSymbolsInObject( | ... | @@ -2184,7 +2316,7 @@ fn resolveSymbolsInObject( |
| 2184 | const global = &self.globals.items[resolv.where_index]; | 2316 | const global = &self.globals.items[resolv.where_index]; |
| 2185 | | 2317 | |
| 2186 | if (symbolIsTentative(global.*)) { | 2318 | if (symbolIsTentative(global.*)) { |
| 2187 | _ = tentatives.fetchSwapRemove(resolv.where_index); | 2319 | _ = self.tentatives.fetchSwapRemove(resolv.where_index); |
| 2188 | } else if (!(symbolIsWeakDef(sym) or symbolIsPext(sym)) and | 2320 | } else if (!(symbolIsWeakDef(sym) or symbolIsPext(sym)) and |
| 2189 | !(symbolIsWeakDef(global.*) or symbolIsPext(global.*))) | 2321 | !(symbolIsWeakDef(global.*) or symbolIsPext(global.*))) |
| 2190 | { | 2322 | { |
| ... | @@ -2236,7 +2368,7 @@ fn resolveSymbolsInObject( | ... | @@ -2236,7 +2368,7 @@ fn resolveSymbolsInObject( |
| 2236 | .where_index = global_sym_index, | 2368 | .where_index = global_sym_index, |
| 2237 | .file = object_id, | 2369 | .file = object_id, |
| 2238 | }); | 2370 | }); |
| 2239 | _ = try tentatives.getOrPut(global_sym_index); | 2371 | _ = try self.tentatives.getOrPut(self.base.allocator, global_sym_index); |
| 2240 | continue; | 2372 | continue; |
| 2241 | }; | 2373 | }; |
| 2242 | | 2374 | |
| ... | @@ -2260,7 +2392,7 @@ fn resolveSymbolsInObject( | ... | @@ -2260,7 +2392,7 @@ fn resolveSymbolsInObject( |
| 2260 | .n_desc = sym.n_desc, | 2392 | .n_desc = sym.n_desc, |
| 2261 | .n_value = sym.n_value, | 2393 | .n_value = sym.n_value, |
| 2262 | }); | 2394 | }); |
| 2263 | _ = try tentatives.getOrPut(global_sym_index); | 2395 | _ = try self.tentatives.getOrPut(self.base.allocator, global_sym_index); |
| 2264 | resolv.* = .{ | 2396 | resolv.* = .{ |
| 2265 | .where = .global, | 2397 | .where = .global, |
| 2266 | .where_index = global_sym_index, | 2398 | .where_index = global_sym_index, |
| ... | @@ -2298,16 +2430,9 @@ fn resolveSymbolsInObject( | ... | @@ -2298,16 +2430,9 @@ fn resolveSymbolsInObject( |
| 2298 | } | 2430 | } |
| 2299 | } | 2431 | } |
| 2300 | | 2432 | |
| 2301 | fn resolveSymbols(self: *MachO) !void { | 2433 | fn resolveSymbolsInArchives(self: *MachO) !void { |
| 2302 | var tentatives = std.AutoArrayHashMap(u32, void).init(self.base.allocator); | 2434 | if (self.archives.items.len == 0) return; |
| 2303 | defer tentatives.deinit(); | | |
| 2304 | | 2435 | |
| 2305 | // First pass, resolve symbols in provided objects. | | |
| 2306 | for (self.objects.items) |_, object_id| { | | |
| 2307 | try self.resolveSymbolsInObject(@intCast(u16, object_id), &tentatives); | | |
| 2308 | } | | |
| 2309 | | | |
| 2310 | // Second pass, resolve symbols in static libraries. | | |
| 2311 | var next_sym: usize = 0; | 2436 | var next_sym: usize = 0; |
| 2312 | loop: while (next_sym < self.unresolved.count()) { | 2437 | loop: while (next_sym < self.unresolved.count()) { |
| 2313 | const sym = self.undefs.items[self.unresolved.keys()[next_sym]]; | 2438 | const sym = self.undefs.items[self.unresolved.keys()[next_sym]]; |
| ... | @@ -2324,74 +2449,19 @@ fn resolveSymbols(self: *MachO) !void { | ... | @@ -2324,74 +2449,19 @@ fn resolveSymbols(self: *MachO) !void { |
| 2324 | const object_id = @intCast(u16, self.objects.items.len); | 2449 | const object_id = @intCast(u16, self.objects.items.len); |
| 2325 | const object = try self.objects.addOne(self.base.allocator); | 2450 | const object = try self.objects.addOne(self.base.allocator); |
| 2326 | object.* = try archive.parseObject(self.base.allocator, self.base.options.target, offsets.items[0]); | 2451 | object.* = try archive.parseObject(self.base.allocator, self.base.options.target, offsets.items[0]); |
| 2327 | try self.resolveSymbolsInObject(object_id, &tentatives); | 2452 | try self.resolveSymbolsInObject(object_id); |
| 2328 | | 2453 | |
| 2329 | continue :loop; | 2454 | continue :loop; |
| 2330 | } | 2455 | } |
| 2331 | | 2456 | |
| 2332 | next_sym += 1; | 2457 | next_sym += 1; |
| 2333 | } | 2458 | } |
| | 2459 | } |
| 2334 | | 2460 | |
| 2335 | // Convert any tentative definition into a regular symbol and allocate | 2461 | fn resolveSymbolsInDylibs(self: *MachO) !void { |
| 2336 | // text blocks for each tentative defintion. | 2462 | if (self.dylibs.items.len == 0) return; |
| 2337 | while (tentatives.popOrNull()) |entry| { | | |
| 2338 | const sym = &self.globals.items[entry.key]; | | |
| 2339 | const match = MatchingSection{ | | |
| 2340 | .seg = self.data_segment_cmd_index.?, | | |
| 2341 | .sect = self.bss_section_index.?, | | |
| 2342 | }; | | |
| 2343 | _ = try self.section_ordinals.getOrPut(self.base.allocator, match); | | |
| 2344 | | | |
| 2345 | const size = sym.n_value; | | |
| 2346 | const alignment = (sym.n_desc >> 8) & 0x0f; | | |
| 2347 | | | |
| 2348 | sym.n_value = 0; | | |
| 2349 | sym.n_desc = 0; | | |
| 2350 | sym.n_sect = @intCast(u8, self.section_ordinals.getIndex(match).? + 1); | | |
| 2351 | var local_sym = sym.*; | | |
| 2352 | local_sym.n_type = macho.N_SECT; | | |
| 2353 | | | |
| 2354 | const local_sym_index = @intCast(u32, self.locals.items.len); | | |
| 2355 | try self.locals.append(self.base.allocator, local_sym); | | |
| 2356 | | | |
| 2357 | const resolv = self.symbol_resolver.getPtr(sym.n_strx) orelse unreachable; | | |
| 2358 | resolv.local_sym_index = local_sym_index; | | |
| 2359 | | | |
| 2360 | const atom = try self.createEmptyAtom(local_sym_index, size, alignment); | | |
| 2361 | const alignment_pow_2 = try math.powi(u32, 2, alignment); | | |
| 2362 | const vaddr = try self.allocateAtom(atom, size, alignment_pow_2, match); | | |
| 2363 | sym.n_value = vaddr; | | |
| 2364 | } | | |
| 2365 | | | |
| 2366 | try self.resolveDyldStubBinder(); | | |
| 2367 | { | | |
| 2368 | const match = MatchingSection{ | | |
| 2369 | .seg = self.data_segment_cmd_index.?, | | |
| 2370 | .sect = self.data_section_index.?, | | |
| 2371 | }; | | |
| 2372 | const atom = try self.createDyldPrivateAtom(); | | |
| 2373 | const sym = &self.locals.items[atom.local_sym_index]; | | |
| 2374 | const vaddr = try self.allocateAtom(atom, @sizeOf(u64), 8, match); | | |
| 2375 | sym.n_value = vaddr; | | |
| 2376 | sym.n_sect = @intCast(u8, self.section_ordinals.getIndex(match).? + 1); | | |
| 2377 | log.debug("allocated {s} atom at 0x{x}", .{ self.getString(sym.n_strx), vaddr }); | | |
| 2378 | } | | |
| 2379 | { | | |
| 2380 | const match = MatchingSection{ | | |
| 2381 | .seg = self.text_segment_cmd_index.?, | | |
| 2382 | .sect = self.stub_helper_section_index.?, | | |
| 2383 | }; | | |
| 2384 | const atom = try self.createStubHelperPreambleAtom(); | | |
| 2385 | const sym = &self.locals.items[atom.local_sym_index]; | | |
| 2386 | const alignment = try math.powi(u32, 2, atom.alignment); | | |
| 2387 | const vaddr = try self.allocateAtom(atom, atom.size, alignment, match); | | |
| 2388 | sym.n_value = vaddr; | | |
| 2389 | sym.n_sect = @intCast(u8, self.section_ordinals.getIndex(match).? + 1); | | |
| 2390 | log.debug("allocated {s} atom at 0x{x}", .{ self.getString(sym.n_strx), vaddr }); | | |
| 2391 | } | | |
| 2392 | | 2463 | |
| 2393 | // Third pass, resolve symbols in dynamic libraries. | 2464 | var next_sym: usize = 0; |
| 2394 | next_sym = 0; | | |
| 2395 | loop: while (next_sym < self.unresolved.count()) { | 2465 | loop: while (next_sym < self.unresolved.count()) { |
| 2396 | const sym = self.undefs.items[self.unresolved.keys()[next_sym]]; | 2466 | const sym = self.undefs.items[self.unresolved.keys()[next_sym]]; |
| 2397 | const sym_name = self.getString(sym.n_strx); | 2467 | const sym_name = self.getString(sym.n_strx); |
| ... | @@ -2401,6 +2471,7 @@ fn resolveSymbols(self: *MachO) !void { | ... | @@ -2401,6 +2471,7 @@ fn resolveSymbols(self: *MachO) !void { |
| 2401 | | 2471 | |
| 2402 | const dylib_id = @intCast(u16, id); | 2472 | const dylib_id = @intCast(u16, id); |
| 2403 | if (!self.referenced_dylibs.contains(dylib_id)) { | 2473 | if (!self.referenced_dylibs.contains(dylib_id)) { |
| | 2474 | try self.addLoadDylibLC(dylib_id); |
| 2404 | try self.referenced_dylibs.putNoClobber(self.base.allocator, dylib_id, {}); | 2475 | try self.referenced_dylibs.putNoClobber(self.base.allocator, dylib_id, {}); |
| 2405 | } | 2476 | } |
| 2406 | | 2477 | |
| ... | @@ -2468,69 +2539,6 @@ fn resolveSymbols(self: *MachO) !void { | ... | @@ -2468,69 +2539,6 @@ fn resolveSymbols(self: *MachO) !void { |
| 2468 | | 2539 | |
| 2469 | next_sym += 1; | 2540 | next_sym += 1; |
| 2470 | } | 2541 | } |
| 2471 | | | |
| 2472 | // Fourth pass, handle synthetic symbols and flag any undefined references. | | |
| 2473 | if (self.strtab_dir.getAdapted(@as([]const u8, "___dso_handle"), StringSliceAdapter{ | | |
| 2474 | .strtab = &self.strtab, | | |
| 2475 | })) |n_strx| blk: { | | |
| 2476 | const resolv = self.symbol_resolver.getPtr(n_strx) orelse break :blk; | | |
| 2477 | if (resolv.where != .undef) break :blk; | | |
| 2478 | | | |
| 2479 | const undef = &self.undefs.items[resolv.where_index]; | | |
| 2480 | const match: MatchingSection = .{ | | |
| 2481 | .seg = self.text_segment_cmd_index.?, | | |
| 2482 | .sect = self.text_section_index.?, | | |
| 2483 | }; | | |
| 2484 | const local_sym_index = @intCast(u32, self.locals.items.len); | | |
| 2485 | var nlist = macho.nlist_64{ | | |
| 2486 | .n_strx = undef.n_strx, | | |
| 2487 | .n_type = macho.N_SECT, | | |
| 2488 | .n_sect = @intCast(u8, self.section_ordinals.getIndex(match).? + 1), | | |
| 2489 | .n_desc = 0, | | |
| 2490 | .n_value = 0, | | |
| 2491 | }; | | |
| 2492 | try self.locals.append(self.base.allocator, nlist); | | |
| 2493 | const global_sym_index = @intCast(u32, self.globals.items.len); | | |
| 2494 | nlist.n_type |= macho.N_EXT; | | |
| 2495 | nlist.n_desc = macho.N_WEAK_DEF; | | |
| 2496 | try self.globals.append(self.base.allocator, nlist); | | |
| 2497 | | | |
| 2498 | _ = self.unresolved.fetchSwapRemove(resolv.where_index); | | |
| 2499 | | | |
| 2500 | undef.* = .{ | | |
| 2501 | .n_strx = 0, | | |
| 2502 | .n_type = macho.N_UNDF, | | |
| 2503 | .n_sect = 0, | | |
| 2504 | .n_desc = 0, | | |
| 2505 | .n_value = 0, | | |
| 2506 | }; | | |
| 2507 | resolv.* = .{ | | |
| 2508 | .where = .global, | | |
| 2509 | .where_index = global_sym_index, | | |
| 2510 | .local_sym_index = local_sym_index, | | |
| 2511 | }; | | |
| 2512 | | | |
| 2513 | // We create an empty atom for this symbol. | | |
| 2514 | // TODO perhaps we should special-case special symbols? Create a separate | | |
| 2515 | // linked list of atoms? | | |
| 2516 | const atom = try self.createEmptyAtom(local_sym_index, 0, 0); | | |
| 2517 | const sym = &self.locals.items[local_sym_index]; | | |
| 2518 | const vaddr = try self.allocateAtom(atom, 0, 1, match); | | |
| 2519 | sym.n_value = vaddr; | | |
| 2520 | atom.dirty = false; // We don't really want to write it to file. | | |
| 2521 | } | | |
| 2522 | | | |
| 2523 | for (self.unresolved.keys()) |index| { | | |
| 2524 | const sym = self.undefs.items[index]; | | |
| 2525 | const sym_name = self.getString(sym.n_strx); | | |
| 2526 | const resolv = self.symbol_resolver.get(sym.n_strx) orelse unreachable; | | |
| 2527 | | | |
| 2528 | log.err("undefined reference to symbol '{s}'", .{sym_name}); | | |
| 2529 | log.err(" first referenced in '{s}'", .{self.objects.items[resolv.file].name}); | | |
| 2530 | } | | |
| 2531 | | | |
| 2532 | if (self.unresolved.count() > 0) | | |
| 2533 | return error.UndefinedSymbolReference; | | |
| 2534 | } | 2542 | } |
| 2535 | | 2543 | |
| 2536 | fn resolveDyldStubBinder(self: *MachO) !void { | 2544 | fn resolveDyldStubBinder(self: *MachO) !void { |
| ... | @@ -2557,6 +2565,7 @@ fn resolveDyldStubBinder(self: *MachO) !void { | ... | @@ -2557,6 +2565,7 @@ fn resolveDyldStubBinder(self: *MachO) !void { |
| 2557 | | 2565 | |
| 2558 | const dylib_id = @intCast(u16, id); | 2566 | const dylib_id = @intCast(u16, id); |
| 2559 | if (!self.referenced_dylibs.contains(dylib_id)) { | 2567 | if (!self.referenced_dylibs.contains(dylib_id)) { |
| | 2568 | try self.addLoadDylibLC(dylib_id); |
| 2560 | try self.referenced_dylibs.putNoClobber(self.base.allocator, dylib_id, {}); | 2569 | try self.referenced_dylibs.putNoClobber(self.base.allocator, dylib_id, {}); |
| 2561 | } | 2570 | } |
| 2562 | | 2571 | |
| ... | @@ -2733,6 +2742,21 @@ fn parseObjectsIntoAtoms(self: *MachO) !void { | ... | @@ -2733,6 +2742,21 @@ fn parseObjectsIntoAtoms(self: *MachO) !void { |
| 2733 | } | 2742 | } |
| 2734 | } | 2743 | } |
| 2735 | | 2744 | |
| | 2745 | fn addLoadDylibLC(self: *MachO, id: u16) !void { |
| | 2746 | const dylib = self.dylibs.items[id]; |
| | 2747 | const dylib_id = dylib.id orelse unreachable; |
| | 2748 | var dylib_cmd = try commands.createLoadDylibCommand( |
| | 2749 | self.base.allocator, |
| | 2750 | dylib_id.name, |
| | 2751 | dylib_id.timestamp, |
| | 2752 | dylib_id.current_version, |
| | 2753 | dylib_id.compatibility_version, |
| | 2754 | ); |
| | 2755 | errdefer dylib_cmd.deinit(self.base.allocator); |
| | 2756 | try self.load_commands.append(self.base.allocator, .{ .Dylib = dylib_cmd }); |
| | 2757 | self.load_commands_dirty = true; |
| | 2758 | } |
| | 2759 | |
| 2736 | fn addCodeSignatureLC(self: *MachO) !void { | 2760 | fn addCodeSignatureLC(self: *MachO) !void { |
| 2737 | if (self.code_signature_cmd_index != null or !self.requires_adhoc_codesig) return; | 2761 | if (self.code_signature_cmd_index != null or !self.requires_adhoc_codesig) return; |
| 2738 | self.code_signature_cmd_index = @intCast(u16, self.load_commands.items.len); | 2762 | self.code_signature_cmd_index = @intCast(u16, self.load_commands.items.len); |
| ... | @@ -2747,23 +2771,6 @@ fn addCodeSignatureLC(self: *MachO) !void { | ... | @@ -2747,23 +2771,6 @@ fn addCodeSignatureLC(self: *MachO) !void { |
| 2747 | self.load_commands_dirty = true; | 2771 | self.load_commands_dirty = true; |
| 2748 | } | 2772 | } |
| 2749 | | 2773 | |
| 2750 | fn addLoadDylibLCs(self: *MachO) !void { | | |
| 2751 | for (self.referenced_dylibs.keys()) |id| { | | |
| 2752 | const dylib = self.dylibs.items[id]; | | |
| 2753 | const dylib_id = dylib.id orelse unreachable; | | |
| 2754 | var dylib_cmd = try commands.createLoadDylibCommand( | | |
| 2755 | self.base.allocator, | | |
| 2756 | dylib_id.name, | | |
| 2757 | dylib_id.timestamp, | | |
| 2758 | dylib_id.current_version, | | |
| 2759 | dylib_id.compatibility_version, | | |
| 2760 | ); | | |
| 2761 | errdefer dylib_cmd.deinit(self.base.allocator); | | |
| 2762 | try self.load_commands.append(self.base.allocator, .{ .Dylib = dylib_cmd }); | | |
| 2763 | self.load_commands_dirty = true; | | |
| 2764 | } | | |
| 2765 | } | | |
| 2766 | | | |
| 2767 | fn setEntryPoint(self: *MachO) !void { | 2774 | fn setEntryPoint(self: *MachO) !void { |
| 2768 | if (self.base.options.output_mode != .Exe) return; | 2775 | if (self.base.options.output_mode != .Exe) return; |
| 2769 | | 2776 | |
| ... | @@ -2807,6 +2814,7 @@ pub fn deinit(self: *MachO) void { | ... | @@ -2807,6 +2814,7 @@ pub fn deinit(self: *MachO) void { |
| 2807 | self.locals_free_list.deinit(self.base.allocator); | 2814 | self.locals_free_list.deinit(self.base.allocator); |
| 2808 | self.symbol_resolver.deinit(self.base.allocator); | 2815 | self.symbol_resolver.deinit(self.base.allocator); |
| 2809 | self.unresolved.deinit(self.base.allocator); | 2816 | self.unresolved.deinit(self.base.allocator); |
| | 2817 | self.tentatives.deinit(self.base.allocator); |
| 2810 | | 2818 | |
| 2811 | for (self.objects.items) |*object| { | 2819 | for (self.objects.items) |*object| { |
| 2812 | object.deinit(self.base.allocator); | 2820 | object.deinit(self.base.allocator); |
| ... | @@ -4417,7 +4425,7 @@ fn populateLazyBindOffsetsInStubHelper(self: *MachO, buffer: []const u8) !void { | ... | @@ -4417,7 +4425,7 @@ fn populateLazyBindOffsetsInStubHelper(self: *MachO, buffer: []const u8) !void { |
| 4417 | .seg = self.text_segment_cmd_index.?, | 4425 | .seg = self.text_segment_cmd_index.?, |
| 4418 | .sect = self.stub_helper_section_index.?, | 4426 | .sect = self.stub_helper_section_index.?, |
| 4419 | }) orelse return; | 4427 | }) orelse return; |
| 4420 | if (last_atom.local_sym_index == self.stub_preamble_sym_index.?) return; | 4428 | if (last_atom == self.stub_helper_preamble_atom.?) return; |
| 4421 | | 4429 | |
| 4422 | // Because we insert lazy binding opcodes in reverse order (from last to the first atom), | 4430 | // Because we insert lazy binding opcodes in reverse order (from last to the first atom), |
| 4423 | // we need reverse the order of atom traversal here as well. | 4431 | // we need reverse the order of atom traversal here as well. |