authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-04-04 10:30:03+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-04-05 05:57:09+02:00
logf372995e1ef2a6dda4bc30eeaf817b0d947704e7
tree3c4e77ff374812eff4dd2db73cf9c6d5c9e00680
parent5ea6e78943453e145366c8860cb9c8f9684f9b31

macho: refactor adding GOT and stub entries

Don't special-case resolving of `dyld_stub_binder`.

1 files changed, 99 insertions(+), 330 deletions(-)

src/link/MachO.zig+99-330
...@@ -142,7 +142,7 @@ data_section_index: ?u8 = null,...@@ -142,7 +142,7 @@ data_section_index: ?u8 = null,
142locals: std.ArrayListUnmanaged(macho.nlist_64) = .{},142locals: std.ArrayListUnmanaged(macho.nlist_64) = .{},
143globals: std.ArrayListUnmanaged(SymbolWithLoc) = .{},143globals: std.ArrayListUnmanaged(SymbolWithLoc) = .{},
144resolver: std.StringHashMapUnmanaged(u32) = .{},144resolver: std.StringHashMapUnmanaged(u32) = .{},
145unresolved: std.AutoArrayHashMapUnmanaged(u32, bool) = .{},145unresolved: std.AutoArrayHashMapUnmanaged(u32, ResolveAction.Kind) = .{},
146146
147locals_free_list: std.ArrayListUnmanaged(u32) = .{},147locals_free_list: std.ArrayListUnmanaged(u32) = .{},
148globals_free_list: std.ArrayListUnmanaged(u32) = .{},148globals_free_list: std.ArrayListUnmanaged(u32) = .{},
...@@ -295,10 +295,15 @@ const UnnamedConstTable = std.AutoArrayHashMapUnmanaged(Module.Decl.Index, std.A...@@ -295,10 +295,15 @@ const UnnamedConstTable = std.AutoArrayHashMapUnmanaged(Module.Decl.Index, std.A
295const RebaseTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(u32));295const RebaseTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(u32));
296const RelocationTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(Relocation));296const RelocationTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(Relocation));
297297
298const PendingUpdate = union(enum) {298const ResolveAction = struct {
299 resolve_undef: u32,299 kind: Kind,
300 add_stub_entry: u32,300 target: SymbolWithLoc,
301 add_got_entry: u32,301
302 const Kind = enum {
303 none,
304 add_got,
305 add_stub,
306 };
302};307};
303308
304pub const SymbolWithLoc = struct {309pub const SymbolWithLoc = struct {
...@@ -603,16 +608,29 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No...@@ -603,16 +608,29 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
603 try self.parseDependentLibs(self.base.options.sysroot, &dependent_libs);608 try self.parseDependentLibs(self.base.options.sysroot, &dependent_libs);
604 }609 }
605610
611 if (self.dyld_stub_binder_index == null) {
612 self.dyld_stub_binder_index = try self.addUndefined("dyld_stub_binder", .add_got);
613 }
614
606 try self.createMhExecuteHeaderSymbol();615 try self.createMhExecuteHeaderSymbol();
607 try self.resolveDyldStubBinder();616
608 try self.createDyldPrivateAtom();617 var actions = std.ArrayList(ResolveAction).init(self.base.allocator);
609 try self.createStubHelperPreambleAtom();618 defer actions.deinit();
610 try self.resolveSymbolsInDylibs();619 try self.resolveSymbolsInDylibs(&actions);
611620
612 if (self.unresolved.count() > 0) {621 if (self.unresolved.count() > 0) {
613 return error.UndefinedSymbolReference;622 return error.UndefinedSymbolReference;
614 }623 }
615624
625 try self.createDyldPrivateAtom();
626 try self.createStubHelperPreambleAtom();
627
628 for (actions.items) |action| switch (action.kind) {
629 .none => {},
630 .add_got => try self.addGotEntry(action.target),
631 .add_stub => try self.addStubEntry(action.target),
632 };
633
616 try self.allocateSpecialSymbols();634 try self.allocateSpecialSymbols();
617635
618 for (self.relocs.keys()) |atom_index| {636 for (self.relocs.keys()) |atom_index| {
...@@ -1242,8 +1260,7 @@ pub fn createGotAtom(self: *MachO, target: SymbolWithLoc) !Atom.Index {...@@ -1242,8 +1260,7 @@ pub fn createGotAtom(self: *MachO, target: SymbolWithLoc) !Atom.Index {
1242 return atom_index;1260 return atom_index;
1243}1261}
12441262
1245pub fn createDyldPrivateAtom(self: *MachO) !void {1263fn createDyldPrivateAtom(self: *MachO) !void {
1246 if (self.dyld_stub_binder_index == null) return;
1247 if (self.dyld_private_atom_index != null) return;1264 if (self.dyld_private_atom_index != null) return;
12481265
1249 const atom_index = try self.createAtom();1266 const atom_index = try self.createAtom();
...@@ -1260,8 +1277,7 @@ pub fn createDyldPrivateAtom(self: *MachO) !void {...@@ -1260,8 +1277,7 @@ pub fn createDyldPrivateAtom(self: *MachO) !void {
1260 try self.writePtrWidthAtom(atom_index);1277 try self.writePtrWidthAtom(atom_index);
1261}1278}
12621279
1263pub fn createStubHelperPreambleAtom(self: *MachO) !void {1280fn createStubHelperPreambleAtom(self: *MachO) !void {
1264 if (self.dyld_stub_binder_index == null) return;
1265 if (self.stub_helper_preamble_atom_index != null) return;1281 if (self.stub_helper_preamble_atom_index != null) return;
12661282
1267 const gpa = self.base.allocator;1283 const gpa = self.base.allocator;
...@@ -1285,10 +1301,8 @@ pub fn createStubHelperPreambleAtom(self: *MachO) !void {...@@ -1285,10 +1301,8 @@ pub fn createStubHelperPreambleAtom(self: *MachO) !void {
1285 sym.n_type = macho.N_SECT;1301 sym.n_type = macho.N_SECT;
1286 sym.n_sect = self.stub_helper_section_index.? + 1;1302 sym.n_sect = self.stub_helper_section_index.? + 1;
12871303
1288 const dyld_private_sym_index = if (self.dyld_private_atom_index) |dyld_index|1304 const dyld_private = self.getAtom(self.dyld_private_atom_index.?).getSymbolWithLoc();
1289 self.getAtom(dyld_index).getSymbolIndex().?1305 const dyld_stub_binder = self.globals.items[self.dyld_stub_binder_index.?];
1290 else
1291 unreachable;
12921306
1293 const code = try gpa.alloc(u8, size);1307 const code = try gpa.alloc(u8, size);
1294 defer gpa.free(code);1308 defer gpa.free(code);
...@@ -1309,14 +1323,14 @@ pub fn createStubHelperPreambleAtom(self: *MachO) !void {...@@ -1309,14 +1323,14 @@ pub fn createStubHelperPreambleAtom(self: *MachO) !void {
13091323
1310 try Atom.addRelocations(self, atom_index, 2, .{ .{1324 try Atom.addRelocations(self, atom_index, 2, .{ .{
1311 .type = @enumToInt(macho.reloc_type_x86_64.X86_64_RELOC_SIGNED),1325 .type = @enumToInt(macho.reloc_type_x86_64.X86_64_RELOC_SIGNED),
1312 .target = .{ .sym_index = dyld_private_sym_index, .file = null },1326 .target = dyld_private,
1313 .offset = 3,1327 .offset = 3,
1314 .addend = 0,1328 .addend = 0,
1315 .pcrel = true,1329 .pcrel = true,
1316 .length = 2,1330 .length = 2,
1317 }, .{1331 }, .{
1318 .type = @enumToInt(macho.reloc_type_x86_64.X86_64_RELOC_GOT),1332 .type = @enumToInt(macho.reloc_type_x86_64.X86_64_RELOC_GOT),
1319 .target = .{ .sym_index = self.dyld_stub_binder_index.?, .file = null },1333 .target = dyld_stub_binder,
1320 .offset = 11,1334 .offset = 11,
1321 .addend = 0,1335 .addend = 0,
1322 .pcrel = true,1336 .pcrel = true,
...@@ -1349,28 +1363,28 @@ pub fn createStubHelperPreambleAtom(self: *MachO) !void {...@@ -1349,28 +1363,28 @@ pub fn createStubHelperPreambleAtom(self: *MachO) !void {
13491363
1350 try Atom.addRelocations(self, atom_index, 4, .{ .{1364 try Atom.addRelocations(self, atom_index, 4, .{ .{
1351 .type = @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_PAGE21),1365 .type = @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_PAGE21),
1352 .target = .{ .sym_index = dyld_private_sym_index, .file = null },1366 .target = dyld_private,
1353 .offset = 0,1367 .offset = 0,
1354 .addend = 0,1368 .addend = 0,
1355 .pcrel = true,1369 .pcrel = true,
1356 .length = 2,1370 .length = 2,
1357 }, .{1371 }, .{
1358 .type = @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_PAGEOFF12),1372 .type = @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_PAGEOFF12),
1359 .target = .{ .sym_index = dyld_private_sym_index, .file = null },1373 .target = dyld_private,
1360 .offset = 4,1374 .offset = 4,
1361 .addend = 0,1375 .addend = 0,
1362 .pcrel = false,1376 .pcrel = false,
1363 .length = 2,1377 .length = 2,
1364 }, .{1378 }, .{
1365 .type = @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_GOT_LOAD_PAGE21),1379 .type = @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_GOT_LOAD_PAGE21),
1366 .target = .{ .sym_index = self.dyld_stub_binder_index.?, .file = null },1380 .target = dyld_stub_binder,
1367 .offset = 12,1381 .offset = 12,
1368 .addend = 0,1382 .addend = 0,
1369 .pcrel = true,1383 .pcrel = true,
1370 .length = 2,1384 .length = 2,
1371 }, .{1385 }, .{
1372 .type = @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_GOT_LOAD_PAGEOFF12),1386 .type = @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_GOT_LOAD_PAGEOFF12),
1373 .target = .{ .sym_index = self.dyld_stub_binder_index.?, .file = null },1387 .target = dyld_stub_binder,
1374 .offset = 16,1388 .offset = 16,
1375 .addend = 0,1389 .addend = 0,
1376 .pcrel = false,1390 .pcrel = false,
...@@ -1387,7 +1401,7 @@ pub fn createStubHelperPreambleAtom(self: *MachO) !void {...@@ -1387,7 +1401,7 @@ pub fn createStubHelperPreambleAtom(self: *MachO) !void {
1387 try self.writeAtom(atom_index, code);1401 try self.writeAtom(atom_index, code);
1388}1402}
13891403
1390pub fn createStubHelperAtom(self: *MachO) !Atom.Index {1404fn createStubHelperAtom(self: *MachO) !Atom.Index {
1391 const gpa = self.base.allocator;1405 const gpa = self.base.allocator;
1392 const arch = self.base.options.target.cpu.arch;1406 const arch = self.base.options.target.cpu.arch;
1393 const size: u4 = switch (arch) {1407 const size: u4 = switch (arch) {
...@@ -1468,7 +1482,7 @@ pub fn createStubHelperAtom(self: *MachO) !Atom.Index {...@@ -1468,7 +1482,7 @@ pub fn createStubHelperAtom(self: *MachO) !Atom.Index {
1468 return atom_index;1482 return atom_index;
1469}1483}
14701484
1471pub fn createLazyPointerAtom(self: *MachO, stub_sym_index: u32, target: SymbolWithLoc) !Atom.Index {1485fn createLazyPointerAtom(self: *MachO, stub_sym_index: u32, target: SymbolWithLoc) !Atom.Index {
1472 const atom_index = try self.createAtom();1486 const atom_index = try self.createAtom();
1473 const atom = self.getAtomPtr(atom_index);1487 const atom = self.getAtomPtr(atom_index);
1474 atom.size = @sizeOf(u64);1488 atom.size = @sizeOf(u64);
...@@ -1502,7 +1516,7 @@ pub fn createLazyPointerAtom(self: *MachO, stub_sym_index: u32, target: SymbolWi...@@ -1502,7 +1516,7 @@ pub fn createLazyPointerAtom(self: *MachO, stub_sym_index: u32, target: SymbolWi
1502 return atom_index;1516 return atom_index;
1503}1517}
15041518
1505pub fn createStubAtom(self: *MachO, laptr_sym_index: u32) !Atom.Index {1519fn createStubAtom(self: *MachO, laptr_sym_index: u32) !Atom.Index {
1506 const gpa = self.base.allocator;1520 const gpa = self.base.allocator;
1507 const arch = self.base.options.target.cpu.arch;1521 const arch = self.base.options.target.cpu.arch;
1508 const size: u4 = switch (arch) {1522 const size: u4 = switch (arch) {
...@@ -1585,7 +1599,7 @@ pub fn createStubAtom(self: *MachO, laptr_sym_index: u32) !Atom.Index {...@@ -1585,7 +1599,7 @@ pub fn createStubAtom(self: *MachO, laptr_sym_index: u32) !Atom.Index {
1585 return atom_index;1599 return atom_index;
1586}1600}
15871601
1588pub fn createMhExecuteHeaderSymbol(self: *MachO) !void {1602fn createMhExecuteHeaderSymbol(self: *MachO) !void {
1589 if (self.base.options.output_mode != .Exe) return;1603 if (self.base.options.output_mode != .Exe) return;
1590 if (self.getGlobal("__mh_execute_header")) |global| {1604 if (self.getGlobal("__mh_execute_header")) |global| {
1591 const sym = self.getSymbol(global);1605 const sym = self.getSymbol(global);
...@@ -1608,7 +1622,7 @@ pub fn createMhExecuteHeaderSymbol(self: *MachO) !void {...@@ -1608,7 +1622,7 @@ pub fn createMhExecuteHeaderSymbol(self: *MachO) !void {
1608 gop.value_ptr.* = sym_loc;1622 gop.value_ptr.* = sym_loc;
1609}1623}
16101624
1611pub fn createDsoHandleSymbol(self: *MachO) !void {1625fn createDsoHandleSymbol(self: *MachO) !void {
1612 const global = self.getGlobalPtr("___dso_handle") orelse return;1626 const global = self.getGlobalPtr("___dso_handle") orelse return;
1613 if (!self.getSymbol(global.*).undf()) return;1627 if (!self.getSymbol(global.*).undf()) return;
16141628
...@@ -1636,7 +1650,7 @@ fn resolveGlobalSymbol(self: *MachO, current: SymbolWithLoc) !void {...@@ -1636,7 +1650,7 @@ fn resolveGlobalSymbol(self: *MachO, current: SymbolWithLoc) !void {
1636 if (!gop.found_existing) {1650 if (!gop.found_existing) {
1637 gop.value_ptr.* = current;1651 gop.value_ptr.* = current;
1638 if (sym.undf() and !sym.tentative()) {1652 if (sym.undf() and !sym.tentative()) {
1639 try self.unresolved.putNoClobber(gpa, self.getGlobalIndex(sym_name).?, false);1653 try self.unresolved.putNoClobber(gpa, self.getGlobalIndex(sym_name).?, .none);
1640 }1654 }
1641 return;1655 return;
1642 }1656 }
...@@ -1683,7 +1697,7 @@ fn resolveGlobalSymbol(self: *MachO, current: SymbolWithLoc) !void {...@@ -1683,7 +1697,7 @@ fn resolveGlobalSymbol(self: *MachO, current: SymbolWithLoc) !void {
1683 gop.value_ptr.* = current;1697 gop.value_ptr.* = current;
1684}1698}
16851699
1686pub fn resolveSymbolsInDylibs(self: *MachO) !void {1700fn resolveSymbolsInDylibs(self: *MachO, actions: *std.ArrayList(ResolveAction)) !void {
1687 if (self.dylibs.items.len == 0) return;1701 if (self.dylibs.items.len == 0) return;
16881702
1689 const gpa = self.base.allocator;1703 const gpa = self.base.allocator;
...@@ -1711,19 +1725,8 @@ pub fn resolveSymbolsInDylibs(self: *MachO) !void {...@@ -1711,19 +1725,8 @@ pub fn resolveSymbolsInDylibs(self: *MachO) !void {
1711 }1725 }
17121726
1713 if (self.unresolved.fetchSwapRemove(global_index)) |entry| blk: {1727 if (self.unresolved.fetchSwapRemove(global_index)) |entry| blk: {
1714 if (!entry.value) break :blk;
1715 if (!sym.undf()) break :blk;1728 if (!sym.undf()) break :blk;
1716 if (self.stubs_table.contains(global)) break :blk;1729 try actions.append(.{ .kind = entry.value, .target = global });
1717
1718 const stub_index = try self.allocateStubEntry(global);
1719 const stub_helper_atom_index = try self.createStubHelperAtom();
1720 const stub_helper_atom = self.getAtom(stub_helper_atom_index);
1721 const laptr_atom_index = try self.createLazyPointerAtom(stub_helper_atom.getSymbolIndex().?, global);
1722 const laptr_atom = self.getAtom(laptr_atom_index);
1723 const stub_atom_index = try self.createStubAtom(laptr_atom.getSymbolIndex().?);
1724 const stub_atom = self.getAtom(stub_atom_index);
1725 self.stubs.items[stub_index].sym_index = stub_atom.getSymbolIndex().?;
1726 self.markRelocsDirtyByTarget(global);
1727 }1730 }
17281731
1729 continue :loop;1732 continue :loop;
...@@ -1733,101 +1736,6 @@ pub fn resolveSymbolsInDylibs(self: *MachO) !void {...@@ -1733,101 +1736,6 @@ pub fn resolveSymbolsInDylibs(self: *MachO) !void {
1733 }1736 }
1734}1737}
17351738
1736pub fn resolveSymbolsAtLoading(self: *MachO) !void {
1737 const is_lib = self.base.options.output_mode == .Lib;
1738 const is_dyn_lib = self.base.options.link_mode == .Dynamic and is_lib;
1739 const allow_undef = is_dyn_lib and (self.base.options.allow_shlib_undefined orelse false);
1740
1741 var next_sym: usize = 0;
1742 while (next_sym < self.unresolved.count()) {
1743 const global_index = self.unresolved.keys()[next_sym];
1744 const global = self.globals.items[global_index];
1745 const sym = self.getSymbolPtr(global);
1746 const sym_name = self.getSymbolName(global);
1747
1748 if (sym.discarded()) {
1749 sym.* = .{
1750 .n_strx = 0,
1751 .n_type = macho.N_UNDF,
1752 .n_sect = 0,
1753 .n_desc = 0,
1754 .n_value = 0,
1755 };
1756 _ = self.unresolved.swapRemove(global_index);
1757 continue;
1758 } else if (allow_undef) {
1759 const n_desc = @bitCast(
1760 u16,
1761 macho.BIND_SPECIAL_DYLIB_FLAT_LOOKUP * @intCast(i16, macho.N_SYMBOL_RESOLVER),
1762 );
1763 // TODO allow_shlib_undefined is an ELF flag so figure out macOS specific flags too.
1764 sym.n_type = macho.N_EXT;
1765 sym.n_desc = n_desc;
1766 _ = self.unresolved.swapRemove(global_index);
1767 continue;
1768 }
1769
1770 log.err("undefined reference to symbol '{s}'", .{sym_name});
1771 if (global.file) |file| {
1772 log.err(" first referenced in '{s}'", .{self.objects.items[file].name});
1773 }
1774
1775 next_sym += 1;
1776 }
1777}
1778
1779pub fn resolveDyldStubBinder(self: *MachO) !void {
1780 if (self.dyld_stub_binder_index != null) return;
1781 if (self.unresolved.count() == 0) return; // no need for a stub binder if we don't have any imports
1782
1783 log.debug("resolving dyld_stub_binder", .{});
1784
1785 const gpa = self.base.allocator;
1786 const sym_index = try self.allocateSymbol();
1787 const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = null };
1788 const sym = self.getSymbolPtr(sym_loc);
1789 const sym_name = "dyld_stub_binder";
1790 sym.* = .{
1791 .n_strx = try self.strtab.insert(gpa, sym_name),
1792 .n_type = macho.N_UNDF,
1793 .n_sect = 0,
1794 .n_desc = 0,
1795 .n_value = 0,
1796 };
1797 const gop = try self.getOrPutGlobalPtr(sym_name);
1798 gop.value_ptr.* = sym_loc;
1799 const global = gop.value_ptr.*;
1800
1801 for (self.dylibs.items, 0..) |dylib, id| {
1802 if (!dylib.symbols.contains(sym_name)) continue;
1803
1804 const dylib_id = @intCast(u16, id);
1805 if (!self.referenced_dylibs.contains(dylib_id)) {
1806 try self.referenced_dylibs.putNoClobber(gpa, dylib_id, {});
1807 }
1808
1809 const ordinal = self.referenced_dylibs.getIndex(dylib_id) orelse unreachable;
1810 sym.n_type |= macho.N_EXT;
1811 sym.n_desc = @intCast(u16, ordinal + 1) * macho.N_SYMBOL_RESOLVER;
1812 self.dyld_stub_binder_index = sym_index;
1813
1814 break;
1815 }
1816
1817 if (self.dyld_stub_binder_index == null) {
1818 log.err("undefined reference to symbol '{s}'", .{sym_name});
1819 return error.UndefinedSymbolReference;
1820 }
1821
1822 // Add dyld_stub_binder as the final GOT entry.
1823 const got_index = try self.allocateGotEntry(global);
1824 const got_atom_index = try self.createGotAtom(global);
1825 const got_atom = self.getAtom(got_atom_index);
1826 self.got_entries.items[got_index].sym_index = got_atom.getSymbolIndex().?;
1827
1828 try self.writePtrWidthAtom(got_atom_index);
1829}
1830
1831pub fn deinit(self: *MachO) void {1739pub fn deinit(self: *MachO) void {
1832 const gpa = self.base.allocator;1740 const gpa = self.base.allocator;
18331741
...@@ -2016,7 +1924,7 @@ fn growAtom(self: *MachO, atom_index: Atom.Index, new_atom_size: u64, alignment:...@@ -2016,7 +1924,7 @@ fn growAtom(self: *MachO, atom_index: Atom.Index, new_atom_size: u64, alignment:
2016 return self.allocateAtom(atom_index, new_atom_size, alignment);1924 return self.allocateAtom(atom_index, new_atom_size, alignment);
2017}1925}
20181926
2019pub fn allocateSymbol(self: *MachO) !u32 {1927fn allocateSymbol(self: *MachO) !u32 {
2020 try self.locals.ensureUnusedCapacity(self.base.allocator, 1);1928 try self.locals.ensureUnusedCapacity(self.base.allocator, 1);
20211929
2022 const index = blk: {1930 const index = blk: {
...@@ -2065,7 +1973,7 @@ fn allocateGlobal(self: *MachO) !u32 {...@@ -2065,7 +1973,7 @@ fn allocateGlobal(self: *MachO) !u32 {
2065 return index;1973 return index;
2066}1974}
20671975
2068pub fn allocateGotEntry(self: *MachO, target: SymbolWithLoc) !u32 {1976fn allocateGotEntry(self: *MachO, target: SymbolWithLoc) !u32 {
2069 const gpa = self.base.allocator;1977 const gpa = self.base.allocator;
2070 try self.got_entries.ensureUnusedCapacity(gpa, 1);1978 try self.got_entries.ensureUnusedCapacity(gpa, 1);
20711979
...@@ -2087,7 +1995,17 @@ pub fn allocateGotEntry(self: *MachO, target: SymbolWithLoc) !u32 {...@@ -2087,7 +1995,17 @@ pub fn allocateGotEntry(self: *MachO, target: SymbolWithLoc) !u32 {
2087 return index;1995 return index;
2088}1996}
20891997
2090pub fn allocateStubEntry(self: *MachO, target: SymbolWithLoc) !u32 {1998fn addGotEntry(self: *MachO, target: SymbolWithLoc) !void {
1999 if (self.got_entries_table.contains(target)) return;
2000
2001 const got_index = try self.allocateGotEntry(target);
2002 const got_atom_index = try self.createGotAtom(target);
2003 const got_atom = self.getAtom(got_atom_index);
2004 self.got_entries.items[got_index].sym_index = got_atom.getSymbolIndex().?;
2005 try self.writePtrWidthAtom(got_atom_index);
2006}
2007
2008fn allocateStubEntry(self: *MachO, target: SymbolWithLoc) !u32 {
2091 try self.stubs.ensureUnusedCapacity(self.base.allocator, 1);2009 try self.stubs.ensureUnusedCapacity(self.base.allocator, 1);
20922010
2093 const index = blk: {2011 const index = blk: {
...@@ -2108,6 +2026,20 @@ pub fn allocateStubEntry(self: *MachO, target: SymbolWithLoc) !u32 {...@@ -2108,6 +2026,20 @@ pub fn allocateStubEntry(self: *MachO, target: SymbolWithLoc) !u32 {
2108 return index;2026 return index;
2109}2027}
21102028
2029fn addStubEntry(self: *MachO, target: SymbolWithLoc) !void {
2030 if (self.stubs_table.contains(target)) return;
2031
2032 const stub_index = try self.allocateStubEntry(target);
2033 const stub_helper_atom_index = try self.createStubHelperAtom();
2034 const stub_helper_atom = self.getAtom(stub_helper_atom_index);
2035 const laptr_atom_index = try self.createLazyPointerAtom(stub_helper_atom.getSymbolIndex().?, target);
2036 const laptr_atom = self.getAtom(laptr_atom_index);
2037 const stub_atom_index = try self.createStubAtom(laptr_atom.getSymbolIndex().?);
2038 const stub_atom = self.getAtom(stub_atom_index);
2039 self.stubs.items[stub_index].sym_index = stub_atom.getSymbolIndex().?;
2040 self.markRelocsDirtyByTarget(target);
2041}
2042
2111pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void {2043pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void {
2112 if (build_options.skip_non_native and builtin.object_format != .macho) {2044 if (build_options.skip_non_native and builtin.object_format != .macho) {
2113 @panic("Attempted to compile for object format that was disabled by build configuration");2045 @panic("Attempted to compile for object format that was disabled by build configuration");
...@@ -2376,13 +2308,7 @@ fn updateLazySymbolAtom(...@@ -2376,13 +2308,7 @@ fn updateLazySymbolAtom(
2376 atom.size = code.len;2308 atom.size = code.len;
2377 symbol.n_value = vaddr;2309 symbol.n_value = vaddr;
23782310
2379 const got_target = SymbolWithLoc{ .sym_index = local_sym_index, .file = null };2311 try self.addGotEntry(.{ .sym_index = local_sym_index });
2380 const got_index = try self.allocateGotEntry(got_target);
2381 const got_atom_index = try self.createGotAtom(got_target);
2382 const got_atom = self.getAtom(got_atom_index);
2383 self.got_entries.items[got_index].sym_index = got_atom.getSymbolIndex().?;
2384 try self.writePtrWidthAtom(got_atom_index);
2385
2386 self.markRelocsDirtyByTarget(atom.getSymbolWithLoc());2312 self.markRelocsDirtyByTarget(atom.getSymbolWithLoc());
2387 try self.writeAtom(atom_index, code);2313 try self.writeAtom(atom_index, code);
2388}2314}
...@@ -2445,114 +2371,6 @@ fn getDeclOutputSection(self: *MachO, decl_index: Module.Decl.Index) u8 {...@@ -2445,114 +2371,6 @@ fn getDeclOutputSection(self: *MachO, decl_index: Module.Decl.Index) u8 {
2445 return sect_id;2371 return sect_id;
2446}2372}
24472373
2448pub fn getOutputSection(self: *MachO, sect: macho.section_64) !?u8 {
2449 const segname = sect.segName();
2450 const sectname = sect.sectName();
2451 const sect_id: ?u8 = blk: {
2452 if (mem.eql(u8, "__LLVM", segname)) {
2453 log.debug("TODO LLVM section: type 0x{x}, name '{s},{s}'", .{
2454 sect.flags, segname, sectname,
2455 });
2456 break :blk null;
2457 }
2458
2459 if (sect.isCode()) {
2460 if (self.text_section_index == null) {
2461 self.text_section_index = try self.initSection("__TEXT", "__text", .{
2462 .flags = macho.S_REGULAR |
2463 macho.S_ATTR_PURE_INSTRUCTIONS |
2464 macho.S_ATTR_SOME_INSTRUCTIONS,
2465 });
2466 }
2467 break :blk self.text_section_index.?;
2468 }
2469
2470 if (sect.isDebug()) {
2471 // TODO debug attributes
2472 if (mem.eql(u8, "__LD", segname) and mem.eql(u8, "__compact_unwind", sectname)) {
2473 log.debug("TODO compact unwind section: type 0x{x}, name '{s},{s}'", .{
2474 sect.flags, segname, sectname,
2475 });
2476 }
2477 break :blk null;
2478 }
2479
2480 switch (sect.type()) {
2481 macho.S_4BYTE_LITERALS,
2482 macho.S_8BYTE_LITERALS,
2483 macho.S_16BYTE_LITERALS,
2484 => {
2485 if (self.getSectionByName("__TEXT", "__const")) |sect_id| break :blk sect_id;
2486 break :blk try self.initSection("__TEXT", "__const", .{});
2487 },
2488 macho.S_CSTRING_LITERALS => {
2489 if (mem.startsWith(u8, sectname, "__objc")) {
2490 if (self.getSectionByName(segname, sectname)) |sect_id| break :blk sect_id;
2491 break :blk try self.initSection(segname, sectname, .{});
2492 }
2493 if (self.getSectionByName("__TEXT", "__cstring")) |sect_id| break :blk sect_id;
2494 break :blk try self.initSection("__TEXT", "__cstring", .{
2495 .flags = macho.S_CSTRING_LITERALS,
2496 });
2497 },
2498 macho.S_MOD_INIT_FUNC_POINTERS,
2499 macho.S_MOD_TERM_FUNC_POINTERS,
2500 => {
2501 if (self.getSectionByName("__DATA_CONST", sectname)) |sect_id| break :blk sect_id;
2502 break :blk try self.initSection("__DATA_CONST", sectname, .{
2503 .flags = sect.flags,
2504 });
2505 },
2506 macho.S_LITERAL_POINTERS,
2507 macho.S_ZEROFILL,
2508 macho.S_THREAD_LOCAL_VARIABLES,
2509 macho.S_THREAD_LOCAL_VARIABLE_POINTERS,
2510 macho.S_THREAD_LOCAL_REGULAR,
2511 macho.S_THREAD_LOCAL_ZEROFILL,
2512 => {
2513 if (self.getSectionByName(segname, sectname)) |sect_id| break :blk sect_id;
2514 break :blk try self.initSection(segname, sectname, .{ .flags = sect.flags });
2515 },
2516 macho.S_COALESCED => {
2517 if (self.getSectionByName(segname, sectname)) |sect_id| break :blk sect_id;
2518 break :blk try self.initSection(segname, sectname, .{});
2519 },
2520 macho.S_REGULAR => {
2521 if (mem.eql(u8, segname, "__TEXT")) {
2522 if (mem.eql(u8, sectname, "__rodata") or
2523 mem.eql(u8, sectname, "__typelink") or
2524 mem.eql(u8, sectname, "__itablink") or
2525 mem.eql(u8, sectname, "__gosymtab") or
2526 mem.eql(u8, sectname, "__gopclntab"))
2527 {
2528 if (self.getSectionByName("__DATA_CONST", "__const")) |sect_id| break :blk sect_id;
2529 break :blk try self.initSection("__DATA_CONST", "__const", .{});
2530 }
2531 }
2532 if (mem.eql(u8, segname, "__DATA")) {
2533 if (mem.eql(u8, sectname, "__const") or
2534 mem.eql(u8, sectname, "__cfstring") or
2535 mem.eql(u8, sectname, "__objc_classlist") or
2536 mem.eql(u8, sectname, "__objc_imageinfo"))
2537 {
2538 if (self.getSectionByName("__DATA_CONST", sectname)) |sect_id| break :blk sect_id;
2539 break :blk try self.initSection("__DATA_CONST", sectname, .{});
2540 } else if (mem.eql(u8, sectname, "__data")) {
2541 if (self.data_section_index == null) {
2542 self.data_section_index = try self.initSection(segname, sectname, .{});
2543 }
2544 break :blk self.data_section_index.?;
2545 }
2546 }
2547 if (self.getSectionByName(segname, sectname)) |sect_id| break :blk sect_id;
2548 break :blk try self.initSection(segname, sectname, .{});
2549 },
2550 else => break :blk null,
2551 }
2552 };
2553 return sect_id;
2554}
2555
2556fn updateDeclCode(self: *MachO, decl_index: Module.Decl.Index, code: []u8) !u64 {2374fn updateDeclCode(self: *MachO, decl_index: Module.Decl.Index, code: []u8) !u64 {
2557 const gpa = self.base.allocator;2375 const gpa = self.base.allocator;
2558 const mod = self.base.options.module.?;2376 const mod = self.base.options.module.?;
...@@ -2619,12 +2437,7 @@ fn updateDeclCode(self: *MachO, decl_index: Module.Decl.Index, code: []u8) !u64...@@ -2619,12 +2437,7 @@ fn updateDeclCode(self: *MachO, decl_index: Module.Decl.Index, code: []u8) !u64
2619 self.getAtomPtr(atom_index).size = code_len;2437 self.getAtomPtr(atom_index).size = code_len;
2620 sym.n_value = vaddr;2438 sym.n_value = vaddr;
26212439
2622 const got_target = SymbolWithLoc{ .sym_index = sym_index, .file = null };2440 try self.addGotEntry(.{ .sym_index = sym_index });
2623 const got_index = try self.allocateGotEntry(got_target);
2624 const got_atom_index = try self.createGotAtom(got_target);
2625 const got_atom = self.getAtom(got_atom_index);
2626 self.got_entries.items[got_index].sym_index = got_atom.getSymbolIndex().?;
2627 try self.writePtrWidthAtom(got_atom_index);
2628 }2441 }
26292442
2630 self.markRelocsDirtyByTarget(atom.getSymbolWithLoc());2443 self.markRelocsDirtyByTarget(atom.getSymbolWithLoc());
...@@ -2837,7 +2650,7 @@ pub fn getDeclVAddr(self: *MachO, decl_index: Module.Decl.Index, reloc_info: Fil...@@ -2837,7 +2650,7 @@ pub fn getDeclVAddr(self: *MachO, decl_index: Module.Decl.Index, reloc_info: Fil
2837 return 0;2650 return 0;
2838}2651}
28392652
2840pub fn populateMissingMetadata(self: *MachO) !void {2653fn populateMissingMetadata(self: *MachO) !void {
2841 assert(self.mode == .incremental);2654 assert(self.mode == .incremental);
28422655
2843 const gpa = self.base.allocator;2656 const gpa = self.base.allocator;
...@@ -3273,79 +3086,12 @@ fn getSectionPrecedence(header: macho.section_64) u4 {...@@ -3273,79 +3086,12 @@ fn getSectionPrecedence(header: macho.section_64) u4 {
3273 }3086 }
3274}3087}
32753088
3276const InitSectionOpts = struct {
3277 flags: u32 = macho.S_REGULAR,
3278 reserved1: u32 = 0,
3279 reserved2: u32 = 0,
3280};
3281
3282pub fn initSection(self: *MachO, segname: []const u8, sectname: []const u8, opts: InitSectionOpts) !u8 {
3283 const segment_id = self.getSegmentByName(segname).?;
3284 const seg = &self.segments.items[segment_id];
3285 const index = try self.insertSection(segment_id, .{
3286 .sectname = makeStaticString(sectname),
3287 .segname = seg.segname,
3288 .flags = opts.flags,
3289 .reserved1 = opts.reserved1,
3290 .reserved2 = opts.reserved2,
3291 });
3292 seg.cmdsize += @sizeOf(macho.section_64);
3293 seg.nsects += 1;
3294 return index;
3295}
3296
3297fn insertSection(self: *MachO, segment_index: u8, header: macho.section_64) !u8 {
3298 const precedence = getSectionPrecedence(header);
3299 const indexes = self.getSectionIndexes(segment_index);
3300 const insertion_index = for (self.sections.items(.header)[indexes.start..indexes.end], 0..) |hdr, i| {
3301 if (getSectionPrecedence(hdr) > precedence) break @intCast(u8, i + indexes.start);
3302 } else indexes.end;
3303 log.debug("inserting section '{s},{s}' at index {d}", .{
3304 header.segName(),
3305 header.sectName(),
3306 insertion_index,
3307 });
3308 for (&[_]*?u8{
3309 &self.text_section_index,
3310 &self.stubs_section_index,
3311 &self.stub_helper_section_index,
3312 &self.got_section_index,
3313 &self.la_symbol_ptr_section_index,
3314 &self.data_section_index,
3315 }) |maybe_index| {
3316 const index = maybe_index.* orelse continue;
3317 if (insertion_index <= index) maybe_index.* = index + 1;
3318 }
3319 try self.sections.insert(self.base.allocator, insertion_index, .{
3320 .segment_index = segment_index,
3321 .header = header,
3322 });
3323 return insertion_index;
3324}
3325
3326pub fn getGlobalSymbol(self: *MachO, name: []const u8, lib_name: ?[]const u8) !u32 {3089pub fn getGlobalSymbol(self: *MachO, name: []const u8, lib_name: ?[]const u8) !u32 {
3327 _ = lib_name;3090 _ = lib_name;
3328 const gpa = self.base.allocator;3091 const gpa = self.base.allocator;
3329
3330 const sym_name = try std.fmt.allocPrint(gpa, "_{s}", .{name});3092 const sym_name = try std.fmt.allocPrint(gpa, "_{s}", .{name});
3331 defer gpa.free(sym_name);3093 defer gpa.free(sym_name);
3332 const gop = try self.getOrPutGlobalPtr(sym_name);3094 return self.addUndefined(sym_name, .add_stub);
3333 const global_index = self.getGlobalIndex(sym_name).?;
3334
3335 if (gop.found_existing) {
3336 return global_index;
3337 }
3338
3339 const sym_index = try self.allocateSymbol();
3340 const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = null };
3341 gop.value_ptr.* = sym_loc;
3342
3343 const sym = self.getSymbolPtr(sym_loc);
3344 sym.n_strx = try self.strtab.insert(gpa, sym_name);
3345
3346 try self.unresolved.putNoClobber(gpa, global_index, true);
3347
3348 return global_index;
3349}3095}
33503096
3351fn writeSegmentHeaders(self: *MachO, writer: anytype) !void {3097fn writeSegmentHeaders(self: *MachO, writer: anytype) !void {
...@@ -3953,6 +3699,29 @@ pub fn ptraceDetach(self: *MachO, pid: std.os.pid_t) !void {...@@ -3953,6 +3699,29 @@ pub fn ptraceDetach(self: *MachO, pid: std.os.pid_t) !void {
3953 self.hot_state.mach_task = null;3699 self.hot_state.mach_task = null;
3954}3700}
39553701
3702fn addUndefined(self: *MachO, name: []const u8, action: ResolveAction.Kind) !u32 {
3703 const gpa = self.base.allocator;
3704
3705 const gop = try self.getOrPutGlobalPtr(name);
3706 const global_index = self.getGlobalIndex(name).?;
3707
3708 if (gop.found_existing) {
3709 return global_index;
3710 }
3711
3712 const sym_index = try self.allocateSymbol();
3713 const sym_loc = SymbolWithLoc{ .sym_index = sym_index };
3714 gop.value_ptr.* = sym_loc;
3715
3716 const sym = self.getSymbolPtr(sym_loc);
3717 sym.n_strx = try self.strtab.insert(gpa, name);
3718 sym.n_type = macho.N_UNDF;
3719
3720 try self.unresolved.putNoClobber(gpa, global_index, action);
3721
3722 return global_index;
3723}
3724
3956pub fn makeStaticString(bytes: []const u8) [16]u8 {3725pub fn makeStaticString(bytes: []const u8) [16]u8 {
3957 var buf = [_]u8{0} ** 16;3726 var buf = [_]u8{0} ** 16;
3958 assert(bytes.len <= buf.len);3727 assert(bytes.len <= buf.len);