| ... | ... | @@ -147,13 +147,14 @@ unresolved: std.AutoArrayHashMapUnmanaged(u32, enum { |
| 147 | 147 | stub, |
| 148 | 148 | got, |
| 149 | 149 | }) = .{}, |
| 150 | tentatives: std.AutoArrayHashMapUnmanaged(u32, void) = .{}, |
| 150 | 151 | |
| 151 | 152 | locals_free_list: std.ArrayListUnmanaged(u32) = .{}, |
| 152 | 153 | globals_free_list: std.ArrayListUnmanaged(u32) = .{}, |
| 153 | 154 | |
| 154 | | dyld_private_sym_index: ?u32 = null, |
| 155 | 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 | 159 | strtab: std.ArrayListUnmanaged(u8) = .{}, |
| 159 | 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 | 778 | sect.offset = self.tlv_bss_file_offset; |
| 778 | 779 | } |
| 779 | 780 | |
| 780 | | try self.resolveSymbols(); |
| 781 | | try self.addLoadDylibLCs(); |
| 781 | for (self.objects.items) |_, object_id| { |
| 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 | 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 | 806 | try self.parseObjectsIntoAtoms(); |
| 785 | 807 | try self.allocateGlobalSymbols(); |
| 786 | 808 | try self.writeAtoms(); |
| ... | ... | @@ -1055,6 +1077,7 @@ pub fn parseDylib(self: *MachO, path: []const u8, opts: DylibCreateOpts) ParseDy |
| 1055 | 1077 | try self.dylibs_map.putNoClobber(self.base.allocator, dylib.id.?.name, dylib_id); |
| 1056 | 1078 | |
| 1057 | 1079 | if (!(opts.is_dependent or self.referenced_dylibs.contains(dylib_id))) { |
| 1080 | try self.addLoadDylibLC(dylib_id); |
| 1058 | 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 | 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 | 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 | 1820 | .n_strx = try self.makeString("l_zld_dyld_private"), |
| 1796 | 1821 | .n_type = macho.N_SECT, |
| 1797 | 1822 | .n_sect = 0, |
| 1798 | 1823 | .n_desc = 0, |
| 1799 | 1824 | .n_value = 0, |
| 1800 | | }); |
| 1801 | | self.dyld_private_sym_index = local_sym_index; |
| 1802 | | return self.createEmptyAtom(local_sym_index, @sizeOf(u64), 3); |
| 1825 | }; |
| 1826 | const atom = try 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 | 1840 | const arch = self.base.options.target.cpu.arch; |
| 1807 | 1841 | const size: u64 = switch (arch) { |
| 1808 | 1842 | .x86_64 => 15, |
| ... | ... | @@ -1815,14 +1849,16 @@ fn createStubHelperPreambleAtom(self: *MachO) !*Atom { |
| 1815 | 1849 | else => unreachable, |
| 1816 | 1850 | }; |
| 1817 | 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 | 1854 | .n_strx = try self.makeString("l_zld_stub_preamble"), |
| 1820 | 1855 | .n_type = macho.N_SECT, |
| 1821 | 1856 | .n_sect = 0, |
| 1822 | 1857 | .n_desc = 0, |
| 1823 | 1858 | .n_value = 0, |
| 1824 | | }); |
| 1859 | }; |
| 1825 | 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 | 1862 | switch (arch) { |
| 1827 | 1863 | .x86_64 => { |
| 1828 | 1864 | try atom.relocs.ensureUnusedCapacity(self.base.allocator, 2); |
| ... | ... | @@ -1833,7 +1869,7 @@ fn createStubHelperPreambleAtom(self: *MachO) !*Atom { |
| 1833 | 1869 | atom.relocs.appendAssumeCapacity(.{ |
| 1834 | 1870 | .offset = 3, |
| 1835 | 1871 | .where = .local, |
| 1836 | | .where_index = self.dyld_private_sym_index.?, |
| 1872 | .where_index = dyld_private_sym_index, |
| 1837 | 1873 | .payload = .{ |
| 1838 | 1874 | .signed = .{ |
| 1839 | 1875 | .addend = 0, |
| ... | ... | @@ -1866,7 +1902,7 @@ fn createStubHelperPreambleAtom(self: *MachO) !*Atom { |
| 1866 | 1902 | atom.relocs.appendAssumeCapacity(.{ |
| 1867 | 1903 | .offset = 0, |
| 1868 | 1904 | .where = .local, |
| 1869 | | .where_index = self.dyld_private_sym_index.?, |
| 1905 | .where_index = dyld_private_sym_index, |
| 1870 | 1906 | .payload = .{ |
| 1871 | 1907 | .page = .{ |
| 1872 | 1908 | .kind = .page, |
| ... | ... | @@ -1879,7 +1915,7 @@ fn createStubHelperPreambleAtom(self: *MachO) !*Atom { |
| 1879 | 1915 | atom.relocs.appendAssumeCapacity(.{ |
| 1880 | 1916 | .offset = 4, |
| 1881 | 1917 | .where = .local, |
| 1882 | | .where_index = self.dyld_private_sym_index.?, |
| 1918 | .where_index = dyld_private_sym_index, |
| 1883 | 1919 | .payload = .{ |
| 1884 | 1920 | .page_off = .{ |
| 1885 | 1921 | .kind = .page, |
| ... | ... | @@ -1931,8 +1967,16 @@ fn createStubHelperPreambleAtom(self: *MachO) !*Atom { |
| 1931 | 1967 | }, |
| 1932 | 1968 | else => unreachable, |
| 1933 | 1969 | } |
| 1934 | | self.stub_preamble_sym_index = local_sym_index; |
| 1935 | | return atom; |
| 1970 | self.stub_helper_preamble_atom = 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 | 1982 | pub fn createStubHelperAtom(self: *MachO) !*Atom { |
| ... | ... | @@ -1968,7 +2012,7 @@ pub fn createStubHelperAtom(self: *MachO) !*Atom { |
| 1968 | 2012 | atom.relocs.appendAssumeCapacity(.{ |
| 1969 | 2013 | .offset = 6, |
| 1970 | 2014 | .where = .local, |
| 1971 | | .where_index = self.stub_preamble_sym_index.?, |
| 2015 | .where_index = self.stub_helper_preamble_atom.?.local_sym_index, |
| 1972 | 2016 | .payload = .{ |
| 1973 | 2017 | .branch = .{ .arch = arch }, |
| 1974 | 2018 | }, |
| ... | ... | @@ -1988,7 +2032,7 @@ pub fn createStubHelperAtom(self: *MachO) !*Atom { |
| 1988 | 2032 | atom.relocs.appendAssumeCapacity(.{ |
| 1989 | 2033 | .offset = 4, |
| 1990 | 2034 | .where = .local, |
| 1991 | | .where_index = self.stub_preamble_sym_index.?, |
| 2035 | .where_index = self.stub_helper_preamble_atom.?.local_sym_index, |
| 1992 | 2036 | .payload = .{ |
| 1993 | 2037 | .branch = .{ .arch = arch }, |
| 1994 | 2038 | }, |
| ... | ... | @@ -2108,11 +2152,99 @@ pub fn createStubAtom(self: *MachO, laptr_sym_index: u32) !*Atom { |
| 2108 | 2152 | return atom; |
| 2109 | 2153 | } |
| 2110 | 2154 | |
| 2111 | | fn resolveSymbolsInObject( |
| 2112 | | self: *MachO, |
| 2113 | | object_id: u16, |
| 2114 | | tentatives: *std.AutoArrayHashMap(u32, void), |
| 2115 | | ) !void { |
| 2155 | fn createTentativeDefAtoms(self: *MachO) !void { |
| 2156 | if (self.tentatives.count() == 0) return; |
| 2157 | // Convert any tentative definition into a regular symbol and allocate |
| 2158 | // text blocks for each tentative defintion. |
| 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 | 2248 | const object = &self.objects.items[object_id]; |
| 2117 | 2249 | |
| 2118 | 2250 | log.debug("resolving symbols in '{s}'", .{object.name}); |
| ... | ... | @@ -2184,7 +2316,7 @@ fn resolveSymbolsInObject( |
| 2184 | 2316 | const global = &self.globals.items[resolv.where_index]; |
| 2185 | 2317 | |
| 2186 | 2318 | if (symbolIsTentative(global.*)) { |
| 2187 | | _ = tentatives.fetchSwapRemove(resolv.where_index); |
| 2319 | _ = self.tentatives.fetchSwapRemove(resolv.where_index); |
| 2188 | 2320 | } else if (!(symbolIsWeakDef(sym) or symbolIsPext(sym)) and |
| 2189 | 2321 | !(symbolIsWeakDef(global.*) or symbolIsPext(global.*))) |
| 2190 | 2322 | { |
| ... | ... | @@ -2236,7 +2368,7 @@ fn resolveSymbolsInObject( |
| 2236 | 2368 | .where_index = global_sym_index, |
| 2237 | 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 | 2372 | continue; |
| 2241 | 2373 | }; |
| 2242 | 2374 | |
| ... | ... | @@ -2260,7 +2392,7 @@ fn resolveSymbolsInObject( |
| 2260 | 2392 | .n_desc = sym.n_desc, |
| 2261 | 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 | 2396 | resolv.* = .{ |
| 2265 | 2397 | .where = .global, |
| 2266 | 2398 | .where_index = global_sym_index, |
| ... | ... | @@ -2298,16 +2430,9 @@ fn resolveSymbolsInObject( |
| 2298 | 2430 | } |
| 2299 | 2431 | } |
| 2300 | 2432 | |
| 2301 | | fn resolveSymbols(self: *MachO) !void { |
| 2302 | | var tentatives = std.AutoArrayHashMap(u32, void).init(self.base.allocator); |
| 2303 | | defer tentatives.deinit(); |
| 2433 | fn resolveSymbolsInArchives(self: *MachO) !void { |
| 2434 | if (self.archives.items.len == 0) return; |
| 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 | 2436 | var next_sym: usize = 0; |
| 2312 | 2437 | loop: while (next_sym < self.unresolved.count()) { |
| 2313 | 2438 | const sym = self.undefs.items[self.unresolved.keys()[next_sym]]; |
| ... | ... | @@ -2324,74 +2449,19 @@ fn resolveSymbols(self: *MachO) !void { |
| 2324 | 2449 | const object_id = @intCast(u16, self.objects.items.len); |
| 2325 | 2450 | const object = try self.objects.addOne(self.base.allocator); |
| 2326 | 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 | 2454 | continue :loop; |
| 2330 | 2455 | } |
| 2331 | 2456 | |
| 2332 | 2457 | next_sym += 1; |
| 2333 | 2458 | } |
| 2459 | } |
| 2334 | 2460 | |
| 2335 | | // Convert any tentative definition into a regular symbol and allocate |
| 2336 | | // text blocks for each tentative defintion. |
| 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 | | } |
| 2461 | fn resolveSymbolsInDylibs(self: *MachO) !void { |
| 2462 | if (self.dylibs.items.len == 0) return; |
| 2392 | 2463 | |
| 2393 | | // Third pass, resolve symbols in dynamic libraries. |
| 2394 | | next_sym = 0; |
| 2464 | var next_sym: usize = 0; |
| 2395 | 2465 | loop: while (next_sym < self.unresolved.count()) { |
| 2396 | 2466 | const sym = self.undefs.items[self.unresolved.keys()[next_sym]]; |
| 2397 | 2467 | const sym_name = self.getString(sym.n_strx); |
| ... | ... | @@ -2401,6 +2471,7 @@ fn resolveSymbols(self: *MachO) !void { |
| 2401 | 2471 | |
| 2402 | 2472 | const dylib_id = @intCast(u16, id); |
| 2403 | 2473 | if (!self.referenced_dylibs.contains(dylib_id)) { |
| 2474 | try self.addLoadDylibLC(dylib_id); |
| 2404 | 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 | 2539 | |
| 2469 | 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 | 2544 | fn resolveDyldStubBinder(self: *MachO) !void { |
| ... | ... | @@ -2557,6 +2565,7 @@ fn resolveDyldStubBinder(self: *MachO) !void { |
| 2557 | 2565 | |
| 2558 | 2566 | const dylib_id = @intCast(u16, id); |
| 2559 | 2567 | if (!self.referenced_dylibs.contains(dylib_id)) { |
| 2568 | try self.addLoadDylibLC(dylib_id); |
| 2560 | 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 | 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 | 2760 | fn addCodeSignatureLC(self: *MachO) !void { |
| 2737 | 2761 | if (self.code_signature_cmd_index != null or !self.requires_adhoc_codesig) return; |
| 2738 | 2762 | self.code_signature_cmd_index = @intCast(u16, self.load_commands.items.len); |
| ... | ... | @@ -2747,23 +2771,6 @@ fn addCodeSignatureLC(self: *MachO) !void { |
| 2747 | 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 | 2774 | fn setEntryPoint(self: *MachO) !void { |
| 2768 | 2775 | if (self.base.options.output_mode != .Exe) return; |
| 2769 | 2776 | |
| ... | ... | @@ -2807,6 +2814,7 @@ pub fn deinit(self: *MachO) void { |
| 2807 | 2814 | self.locals_free_list.deinit(self.base.allocator); |
| 2808 | 2815 | self.symbol_resolver.deinit(self.base.allocator); |
| 2809 | 2816 | self.unresolved.deinit(self.base.allocator); |
| 2817 | self.tentatives.deinit(self.base.allocator); |
| 2810 | 2818 | |
| 2811 | 2819 | for (self.objects.items) |*object| { |
| 2812 | 2820 | object.deinit(self.base.allocator); |
| ... | ... | @@ -4417,7 +4425,7 @@ fn populateLazyBindOffsetsInStubHelper(self: *MachO, buffer: []const u8) !void { |
| 4417 | 4425 | .seg = self.text_segment_cmd_index.?, |
| 4418 | 4426 | .sect = self.stub_helper_section_index.?, |
| 4419 | 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 | 4430 | // Because we insert lazy binding opcodes in reverse order (from last to the first atom), |
| 4423 | 4431 | // we need reverse the order of atom traversal here as well. |