authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-09-13 13:19:08+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-09-13 13:19:08+02:00
log1965465ced82dc9c0fb93ea9182f196e6d6f4409
treee11f7269da691b2715629f86781f60b3619e2aff
parent7aa6064638322286b5aed940c17da1c8f8fad81a

macho: split resolveSymbols into standalone functions


1 files changed, 185 insertions(+), 177 deletions(-)

src/link/MachO.zig+185-177
...@@ -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}) = .{},
150tentatives: std.AutoArrayHashMapUnmanaged(u32, void) = .{},
150151
151locals_free_list: std.ArrayListUnmanaged(u32) = .{},152locals_free_list: std.ArrayListUnmanaged(u32) = .{},
152globals_free_list: std.ArrayListUnmanaged(u32) = .{},153globals_free_list: std.ArrayListUnmanaged(u32) = .{},
153154
154dyld_private_sym_index: ?u32 = null,
155dyld_stub_binder_index: ?u32 = null,155dyld_stub_binder_index: ?u32 = null,
156stub_preamble_sym_index: ?u32 = null,156dyld_private_atom: ?*Atom = null,
157stub_helper_preamble_atom: ?*Atom = null,
157158
158strtab: std.ArrayListUnmanaged(u8) = .{},159strtab: std.ArrayListUnmanaged(u8) = .{},
159strtab_dir: std.HashMapUnmanaged(u32, u32, StringIndexContext, std.hash_map.default_max_load_percentage) = .{},160strtab_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 }
779780
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();
783792
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);
10561078
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 }
10601083
...@@ -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}
17911814
1792fn createDyldPrivateAtom(self: *MachO) !*Atom {1815fn 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}
18041837
1805fn createStubHelperPreambleAtom(self: *MachO) !*Atom {1838fn 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}
19371981
1938pub fn createStubHelperAtom(self: *MachO) !*Atom {1982pub 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}
21102154
2111fn resolveSymbolsInObject(2155fn 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
2195fn 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
2247fn resolveSymbolsInObject(self: *MachO, object_id: u16) !void {
2116 const object = &self.objects.items[object_id];2248 const object = &self.objects.items[object_id];
21172249
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];
21852317
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)) and2320 } 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 };
22422374
...@@ -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}
23002432
2301fn resolveSymbols(self: *MachO) !void {2433fn 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();
23042435
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);
23282453
2329 continue :loop;2454 continue :loop;
2330 }2455 }
23312456
2332 next_sym += 1;2457 next_sym += 1;
2333 }2458 }
2459}
23342460
2335 // Convert any tentative definition into a regular symbol and allocate2461fn 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 }
23922463
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 {
24012471
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 }
24062477
...@@ -2468,69 +2539,6 @@ fn resolveSymbols(self: *MachO) !void {...@@ -2468,69 +2539,6 @@ fn resolveSymbols(self: *MachO) !void {
24682539
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}
25352543
2536fn resolveDyldStubBinder(self: *MachO) !void {2544fn resolveDyldStubBinder(self: *MachO) !void {
...@@ -2557,6 +2565,7 @@ fn resolveDyldStubBinder(self: *MachO) !void {...@@ -2557,6 +2565,7 @@ fn resolveDyldStubBinder(self: *MachO) !void {
25572565
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 }
25622571
...@@ -2733,6 +2742,21 @@ fn parseObjectsIntoAtoms(self: *MachO) !void {...@@ -2733,6 +2742,21 @@ fn parseObjectsIntoAtoms(self: *MachO) !void {
2733 }2742 }
2734}2743}
27352744
2745fn 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
2736fn addCodeSignatureLC(self: *MachO) !void {2760fn 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}
27492773
2750fn 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
2767fn setEntryPoint(self: *MachO) !void {2774fn setEntryPoint(self: *MachO) !void {
2768 if (self.base.options.output_mode != .Exe) return;2775 if (self.base.options.output_mode != .Exe) return;
27692776
...@@ -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);
28102818
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;
44214429
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.