authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-09-09 21:18:39+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-09-09 22:10:27+02:00
log8d44e031618a956a1b31c36b4c096a3000678a6b
treec19a3285f655e1130735f97f3ebc70e1bc675a9c
parent56b96cd61b0bdb7f5b11a5283fe6dd5b585ef10e

macho: use globals free list like in COFF linker


4 files changed, 150 insertions(+), 98 deletions(-)

src/link/MachO.zig+143-91
...@@ -131,17 +131,12 @@ la_symbol_ptr_section_index: ?u8 = null,...@@ -131,17 +131,12 @@ la_symbol_ptr_section_index: ?u8 = null,
131data_section_index: ?u8 = null,131data_section_index: ?u8 = null,
132132
133locals: std.ArrayListUnmanaged(macho.nlist_64) = .{},133locals: std.ArrayListUnmanaged(macho.nlist_64) = .{},
134globals: std.StringArrayHashMapUnmanaged(SymbolWithLoc) = .{},134globals: std.ArrayListUnmanaged(SymbolWithLoc) = .{},
135// FIXME Jakub135resolver: std.StringHashMapUnmanaged(u32) = .{},
136// TODO storing index into globals might be dangerous if we delete a global
137// while not having everything resolved. Actually, perhaps `unresolved`
138// should not be stored at the global scope? Is this possible?
139// Otherwise, audit if this can be a problem.
140// An alternative, which I still need to investigate for perf reasons is to
141// store all global names in an adapted with context strtab.
142unresolved: std.AutoArrayHashMapUnmanaged(u32, bool) = .{},136unresolved: std.AutoArrayHashMapUnmanaged(u32, bool) = .{},
143137
144locals_free_list: std.ArrayListUnmanaged(u32) = .{},138locals_free_list: std.ArrayListUnmanaged(u32) = .{},
139globals_free_list: std.ArrayListUnmanaged(u32) = .{},
145140
146dyld_stub_binder_index: ?u32 = null,141dyld_stub_binder_index: ?u32 = null,
147dyld_private_atom: ?*Atom = null,142dyld_private_atom: ?*Atom = null,
...@@ -1917,7 +1912,7 @@ fn allocateSpecialSymbols(self: *MachO) !void {...@@ -1917,7 +1912,7 @@ fn allocateSpecialSymbols(self: *MachO) !void {
1917 "___dso_handle",1912 "___dso_handle",
1918 "__mh_execute_header",1913 "__mh_execute_header",
1919 }) |name| {1914 }) |name| {
1920 const global = self.globals.get(name) orelse continue;1915 const global = self.getGlobal(name) orelse continue;
1921 if (global.file != null) continue;1916 if (global.file != null) continue;
1922 const sym = self.getSymbolPtr(global);1917 const sym = self.getSymbolPtr(global);
1923 const seg = self.segments.items[self.text_segment_cmd_index.?];1918 const seg = self.segments.items[self.text_segment_cmd_index.?];
...@@ -2074,7 +2069,7 @@ pub fn createGotAtom(self: *MachO, target: SymbolWithLoc) !*Atom {...@@ -2074,7 +2069,7 @@ pub fn createGotAtom(self: *MachO, target: SymbolWithLoc) !*Atom {
20742069
2075 const target_sym = self.getSymbol(target);2070 const target_sym = self.getSymbol(target);
2076 if (target_sym.undf()) {2071 if (target_sym.undf()) {
2077 const global = self.globals.get(self.getSymbolName(target)).?;2072 const global = self.getGlobal(self.getSymbolName(target)).?;
2078 try atom.bindings.append(gpa, .{2073 try atom.bindings.append(gpa, .{
2079 .target = global,2074 .target = global,
2080 .offset = 0,2075 .offset = 0,
...@@ -2106,7 +2101,7 @@ pub fn createTlvPtrAtom(self: *MachO, target: SymbolWithLoc) !*Atom {...@@ -2106,7 +2101,7 @@ pub fn createTlvPtrAtom(self: *MachO, target: SymbolWithLoc) !*Atom {
2106 const target_sym = self.getSymbol(target);2101 const target_sym = self.getSymbol(target);
2107 assert(target_sym.undf());2102 assert(target_sym.undf());
21082103
2109 const global = self.globals.get(self.getSymbolName(target)).?;2104 const global = self.getGlobal(self.getSymbolName(target)).?;
2110 try atom.bindings.append(gpa, .{2105 try atom.bindings.append(gpa, .{
2111 .target = global,2106 .target = global,
2112 .offset = 0,2107 .offset = 0,
...@@ -2376,7 +2371,7 @@ pub fn createLazyPointerAtom(self: *MachO, stub_sym_index: u32, target: SymbolWi...@@ -2376,7 +2371,7 @@ pub fn createLazyPointerAtom(self: *MachO, stub_sym_index: u32, target: SymbolWi
2376 });2371 });
2377 try atom.rebases.append(gpa, 0);2372 try atom.rebases.append(gpa, 0);
23782373
2379 const global = self.globals.get(self.getSymbolName(target)).?;2374 const global = self.getGlobal(self.getSymbolName(target)).?;
2380 try atom.lazy_bindings.append(gpa, .{2375 try atom.lazy_bindings.append(gpa, .{
2381 .target = global,2376 .target = global,
2382 .offset = 0,2377 .offset = 0,
...@@ -2472,7 +2467,7 @@ pub fn createStubAtom(self: *MachO, laptr_sym_index: u32) !*Atom {...@@ -2472,7 +2467,7 @@ pub fn createStubAtom(self: *MachO, laptr_sym_index: u32) !*Atom {
2472fn createTentativeDefAtoms(self: *MachO) !void {2467fn createTentativeDefAtoms(self: *MachO) !void {
2473 const gpa = self.base.allocator;2468 const gpa = self.base.allocator;
24742469
2475 for (self.globals.values()) |global| {2470 for (self.globals.items) |global| {
2476 const sym = self.getSymbolPtr(global);2471 const sym = self.getSymbolPtr(global);
2477 if (!sym.tentative()) continue;2472 if (!sym.tentative()) continue;
24782473
...@@ -2516,25 +2511,22 @@ fn createTentativeDefAtoms(self: *MachO) !void {...@@ -2516,25 +2511,22 @@ fn createTentativeDefAtoms(self: *MachO) !void {
25162511
2517fn createMhExecuteHeaderSymbol(self: *MachO) !void {2512fn createMhExecuteHeaderSymbol(self: *MachO) !void {
2518 if (self.base.options.output_mode != .Exe) return;2513 if (self.base.options.output_mode != .Exe) return;
2519 if (self.globals.get("__mh_execute_header")) |global| {2514 if (self.getGlobal("__mh_execute_header")) |global| {
2520 const sym = self.getSymbol(global);2515 const sym = self.getSymbol(global);
2521 if (!sym.undf() and !(sym.pext() or sym.weakDef())) return;2516 if (!sym.undf() and !(sym.pext() or sym.weakDef())) return;
2522 }2517 }
25232518
2524 const gpa = self.base.allocator;2519 const gpa = self.base.allocator;
2525 const n_strx = try self.strtab.insert(gpa, "__mh_execute_header");2520 const sym_index = try self.allocateSymbol();
2526 const sym_index = @intCast(u32, self.locals.items.len);2521 self.locals.items[sym_index] = .{
2527 try self.locals.append(gpa, .{2522 .n_strx = try self.strtab.insert(gpa, "__mh_execute_header"),
2528 .n_strx = n_strx,
2529 .n_type = macho.N_SECT | macho.N_EXT,2523 .n_type = macho.N_SECT | macho.N_EXT,
2530 .n_sect = 0,2524 .n_sect = 0,
2531 .n_desc = macho.REFERENCED_DYNAMICALLY,2525 .n_desc = macho.REFERENCED_DYNAMICALLY,
2532 .n_value = 0,2526 .n_value = 0,
2533 });2527 };
25342528
2535 const name = try gpa.dupe(u8, "__mh_execute_header");2529 const gop = try self.getOrPutGlobalPtr("__mh_execute_header");
2536 const gop = try self.globals.getOrPut(gpa, name);
2537 defer if (gop.found_existing) gpa.free(name);
2538 gop.value_ptr.* = .{2530 gop.value_ptr.* = .{
2539 .sym_index = sym_index,2531 .sym_index = sym_index,
2540 .file = null,2532 .file = null,
...@@ -2542,25 +2534,24 @@ fn createMhExecuteHeaderSymbol(self: *MachO) !void {...@@ -2542,25 +2534,24 @@ fn createMhExecuteHeaderSymbol(self: *MachO) !void {
2542}2534}
25432535
2544fn createDsoHandleSymbol(self: *MachO) !void {2536fn createDsoHandleSymbol(self: *MachO) !void {
2545 const global = self.globals.getPtr("___dso_handle") orelse return;2537 const global = self.getGlobalPtr("___dso_handle") orelse return;
2546 const sym = self.getSymbolPtr(global.*);2538 const sym = self.getSymbolPtr(global.*);
2547 if (!sym.undf()) return;2539 if (!sym.undf()) return;
25482540
2549 const gpa = self.base.allocator;2541 const gpa = self.base.allocator;
2550 const n_strx = try self.strtab.insert(gpa, "___dso_handle");2542 const sym_index = try self.allocateSymbol();
2551 const sym_index = @intCast(u32, self.locals.items.len);2543 self.locals.items[sym_index] = .{
2552 try self.locals.append(gpa, .{2544 .n_strx = try self.strtab.insert(gpa, "___dso_handle"),
2553 .n_strx = n_strx,
2554 .n_type = macho.N_SECT | macho.N_EXT,2545 .n_type = macho.N_SECT | macho.N_EXT,
2555 .n_sect = 0,2546 .n_sect = 0,
2556 .n_desc = macho.N_WEAK_DEF,2547 .n_desc = macho.N_WEAK_DEF,
2557 .n_value = 0,2548 .n_value = 0,
2558 });2549 };
2559 global.* = .{2550 global.* = .{
2560 .sym_index = sym_index,2551 .sym_index = sym_index,
2561 .file = null,2552 .file = null,
2562 };2553 };
2563 _ = self.unresolved.swapRemove(@intCast(u32, self.globals.getIndex("___dso_handle").?));2554 _ = self.unresolved.swapRemove(self.getGlobalIndex("___dso_handle").?);
2564}2555}
25652556
2566fn resolveGlobalSymbol(self: *MachO, current: SymbolWithLoc) !void {2557fn resolveGlobalSymbol(self: *MachO, current: SymbolWithLoc) !void {
...@@ -2568,19 +2559,14 @@ fn resolveGlobalSymbol(self: *MachO, current: SymbolWithLoc) !void {...@@ -2568,19 +2559,14 @@ fn resolveGlobalSymbol(self: *MachO, current: SymbolWithLoc) !void {
2568 const sym = self.getSymbol(current);2559 const sym = self.getSymbol(current);
2569 const sym_name = self.getSymbolName(current);2560 const sym_name = self.getSymbolName(current);
25702561
2571 const name = try gpa.dupe(u8, sym_name);2562 const gop = try self.getOrPutGlobalPtr(sym_name);
2572 const global_index = @intCast(u32, self.globals.values().len);
2573 const gop = try self.globals.getOrPut(gpa, name);
2574 defer if (gop.found_existing) gpa.free(name);
2575
2576 if (!gop.found_existing) {2563 if (!gop.found_existing) {
2577 gop.value_ptr.* = current;2564 gop.value_ptr.* = current;
2578 if (sym.undf() and !sym.tentative()) {2565 if (sym.undf() and !sym.tentative()) {
2579 try self.unresolved.putNoClobber(gpa, global_index, false);2566 try self.unresolved.putNoClobber(gpa, self.getGlobalIndex(sym_name).?, false);
2580 }2567 }
2581 return;2568 return;
2582 }2569 }
2583
2584 const global = gop.value_ptr.*;2570 const global = gop.value_ptr.*;
2585 const global_sym = self.getSymbol(global);2571 const global_sym = self.getSymbol(global);
25862572
...@@ -2619,7 +2605,7 @@ fn resolveGlobalSymbol(self: *MachO, current: SymbolWithLoc) !void {...@@ -2619,7 +2605,7 @@ fn resolveGlobalSymbol(self: *MachO, current: SymbolWithLoc) !void {
2619 }2605 }
2620 if (sym.undf() and !sym.tentative()) return;2606 if (sym.undf() and !sym.tentative()) return;
26212607
2622 _ = self.unresolved.swapRemove(@intCast(u32, self.globals.getIndex(name).?));2608 _ = self.unresolved.swapRemove(self.getGlobalIndex(sym_name).?);
26232609
2624 gop.value_ptr.* = current;2610 gop.value_ptr.* = current;
2625}2611}
...@@ -2664,7 +2650,7 @@ fn resolveSymbolsInObject(self: *MachO, object_id: u16) !void {...@@ -2664,7 +2650,7 @@ fn resolveSymbolsInObject(self: *MachO, object_id: u16) !void {
2664 const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = object_id };2650 const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = object_id };
2665 self.resolveGlobalSymbol(sym_loc) catch |err| switch (err) {2651 self.resolveGlobalSymbol(sym_loc) catch |err| switch (err) {
2666 error.MultipleSymbolDefinitions => {2652 error.MultipleSymbolDefinitions => {
2667 const global = self.globals.get(sym_name).?;2653 const global = self.getGlobal(sym_name).?;
2668 log.err("symbol '{s}' defined multiple times", .{sym_name});2654 log.err("symbol '{s}' defined multiple times", .{sym_name});
2669 if (global.file) |file| {2655 if (global.file) |file| {
2670 log.err(" first definition in '{s}'", .{self.objects.items[file].name});2656 log.err(" first definition in '{s}'", .{self.objects.items[file].name});
...@@ -2684,7 +2670,8 @@ fn resolveSymbolsInArchives(self: *MachO) !void {...@@ -2684,7 +2670,8 @@ fn resolveSymbolsInArchives(self: *MachO) !void {
2684 const cpu_arch = self.base.options.target.cpu.arch;2670 const cpu_arch = self.base.options.target.cpu.arch;
2685 var next_sym: usize = 0;2671 var next_sym: usize = 0;
2686 loop: while (next_sym < self.unresolved.count()) {2672 loop: while (next_sym < self.unresolved.count()) {
2687 const global = self.globals.values()[self.unresolved.keys()[next_sym]];2673 const global_index = self.unresolved.keys()[next_sym];
2674 const global = self.globals.items[global_index];
2688 const sym_name = self.getSymbolName(global);2675 const sym_name = self.getSymbolName(global);
26892676
2690 for (self.archives.items) |archive| {2677 for (self.archives.items) |archive| {
...@@ -2710,10 +2697,11 @@ fn resolveSymbolsInArchives(self: *MachO) !void {...@@ -2710,10 +2697,11 @@ fn resolveSymbolsInArchives(self: *MachO) !void {
2710fn resolveSymbolsInDylibs(self: *MachO) !void {2697fn resolveSymbolsInDylibs(self: *MachO) !void {
2711 if (self.dylibs.items.len == 0) return;2698 if (self.dylibs.items.len == 0) return;
27122699
2700 const gpa = self.base.allocator;
2713 var next_sym: usize = 0;2701 var next_sym: usize = 0;
2714 loop: while (next_sym < self.unresolved.count()) {2702 loop: while (next_sym < self.unresolved.count()) {
2715 const global_index = self.unresolved.keys()[next_sym];2703 const global_index = self.unresolved.keys()[next_sym];
2716 const global = self.globals.values()[global_index];2704 const global = self.globals.items[global_index];
2717 const sym = self.getSymbolPtr(global);2705 const sym = self.getSymbolPtr(global);
2718 const sym_name = self.getSymbolName(global);2706 const sym_name = self.getSymbolName(global);
27192707
...@@ -2722,7 +2710,7 @@ fn resolveSymbolsInDylibs(self: *MachO) !void {...@@ -2722,7 +2710,7 @@ fn resolveSymbolsInDylibs(self: *MachO) !void {
27222710
2723 const dylib_id = @intCast(u16, id);2711 const dylib_id = @intCast(u16, id);
2724 if (!self.referenced_dylibs.contains(dylib_id)) {2712 if (!self.referenced_dylibs.contains(dylib_id)) {
2725 try self.referenced_dylibs.putNoClobber(self.base.allocator, dylib_id, {});2713 try self.referenced_dylibs.putNoClobber(gpa, dylib_id, {});
2726 }2714 }
27272715
2728 const ordinal = self.referenced_dylibs.getIndex(dylib_id) orelse unreachable;2716 const ordinal = self.referenced_dylibs.getIndex(dylib_id) orelse unreachable;
...@@ -2760,7 +2748,7 @@ fn resolveSymbolsAtLoading(self: *MachO) !void {...@@ -2760,7 +2748,7 @@ fn resolveSymbolsAtLoading(self: *MachO) !void {
2760 var next_sym: usize = 0;2748 var next_sym: usize = 0;
2761 while (next_sym < self.unresolved.count()) {2749 while (next_sym < self.unresolved.count()) {
2762 const global_index = self.unresolved.keys()[next_sym];2750 const global_index = self.unresolved.keys()[next_sym];
2763 const global = self.globals.values()[global_index];2751 const global = self.globals.items[global_index];
2764 const sym = self.getSymbolPtr(global);2752 const sym = self.getSymbolPtr(global);
2765 const sym_name = self.getSymbolName(global);2753 const sym_name = self.getSymbolName(global);
27662754
...@@ -2800,26 +2788,29 @@ fn resolveDyldStubBinder(self: *MachO) !void {...@@ -2800,26 +2788,29 @@ fn resolveDyldStubBinder(self: *MachO) !void {
2800 if (self.unresolved.count() == 0) return; // no need for a stub binder if we don't have any imports2788 if (self.unresolved.count() == 0) return; // no need for a stub binder if we don't have any imports
28012789
2802 const gpa = self.base.allocator;2790 const gpa = self.base.allocator;
2803 const n_strx = try self.strtab.insert(gpa, "dyld_stub_binder");2791 const sym_index = try self.allocateSymbol();
2804 const sym_index = @intCast(u32, self.locals.items.len);2792 const sym = &self.locals.items[sym_index];
2805 try self.locals.append(gpa, .{2793 const sym_name = "dyld_stub_binder";
2806 .n_strx = n_strx,2794 sym.* = .{
2795 .n_strx = try self.strtab.insert(gpa, sym_name),
2807 .n_type = macho.N_UNDF,2796 .n_type = macho.N_UNDF,
2808 .n_sect = 0,2797 .n_sect = 0,
2809 .n_desc = 0,2798 .n_desc = 0,
2810 .n_value = 0,2799 .n_value = 0,
2811 });2800 };
2812 const sym_name = try gpa.dupe(u8, "dyld_stub_binder");2801 const gop = try self.getOrPutGlobalPtr(sym_name);
2813 const global = SymbolWithLoc{ .sym_index = sym_index, .file = null };2802 gop.value_ptr.* = .{
2814 try self.globals.putNoClobber(gpa, sym_name, global);2803 .sym_index = sym_index,
2815 const sym = &self.locals.items[sym_index];2804 .file = null,
2805 };
2806 const global = gop.value_ptr.*;
28162807
2817 for (self.dylibs.items) |dylib, id| {2808 for (self.dylibs.items) |dylib, id| {
2818 if (!dylib.symbols.contains(sym_name)) continue;2809 if (!dylib.symbols.contains(sym_name)) continue;
28192810
2820 const dylib_id = @intCast(u16, id);2811 const dylib_id = @intCast(u16, id);
2821 if (!self.referenced_dylibs.contains(dylib_id)) {2812 if (!self.referenced_dylibs.contains(dylib_id)) {
2822 try self.referenced_dylibs.putNoClobber(self.base.allocator, dylib_id, {});2813 try self.referenced_dylibs.putNoClobber(gpa, dylib_id, {});
2823 }2814 }
28242815
2825 const ordinal = self.referenced_dylibs.getIndex(dylib_id) orelse unreachable;2816 const ordinal = self.referenced_dylibs.getIndex(dylib_id) orelse unreachable;
...@@ -3050,14 +3041,20 @@ pub fn deinit(self: *MachO) void {...@@ -3050,14 +3041,20 @@ pub fn deinit(self: *MachO) void {
3050 self.stubs_free_list.deinit(gpa);3041 self.stubs_free_list.deinit(gpa);
3051 self.stubs_table.deinit(gpa);3042 self.stubs_table.deinit(gpa);
3052 self.strtab.deinit(gpa);3043 self.strtab.deinit(gpa);
3044
3053 self.locals.deinit(gpa);3045 self.locals.deinit(gpa);
3046 self.globals.deinit(gpa);
3054 self.locals_free_list.deinit(gpa);3047 self.locals_free_list.deinit(gpa);
3048 self.globals_free_list.deinit(gpa);
3055 self.unresolved.deinit(gpa);3049 self.unresolved.deinit(gpa);
30563050
3057 for (self.globals.keys()) |key| {3051 {
3058 gpa.free(key);3052 var it = self.resolver.keyIterator();
3053 while (it.next()) |key_ptr| {
3054 gpa.free(key_ptr.*);
3055 }
3056 self.resolver.deinit(gpa);
3059 }3057 }
3060 self.globals.deinit(gpa);
30613058
3062 for (self.objects.items) |*object| {3059 for (self.objects.items) |*object| {
3063 object.deinit(gpa);3060 object.deinit(gpa);
...@@ -3211,6 +3208,29 @@ fn allocateSymbol(self: *MachO) !u32 {...@@ -3211,6 +3208,29 @@ fn allocateSymbol(self: *MachO) !u32 {
3211 return index;3208 return index;
3212}3209}
32133210
3211fn allocateGlobal(self: *MachO) !u32 {
3212 try self.globals.ensureUnusedCapacity(self.base.allocator, 1);
3213
3214 const index = blk: {
3215 if (self.globals_free_list.popOrNull()) |index| {
3216 log.debug(" (reusing global index {d})", .{index});
3217 break :blk index;
3218 } else {
3219 log.debug(" (allocating symbol index {d})", .{self.globals.items.len});
3220 const index = @intCast(u32, self.globals.items.len);
3221 _ = self.globals.addOneAssumeCapacity();
3222 break :blk index;
3223 }
3224 };
3225
3226 self.globals.items[index] = .{
3227 .sym_index = 0,
3228 .file = null,
3229 };
3230
3231 return index;
3232}
3233
3214pub fn allocateGotEntry(self: *MachO, target: SymbolWithLoc) !u32 {3234pub fn allocateGotEntry(self: *MachO, target: SymbolWithLoc) !u32 {
3215 const gpa = self.base.allocator;3235 const gpa = self.base.allocator;
3216 try self.got_entries.ensureUnusedCapacity(gpa, 1);3236 try self.got_entries.ensureUnusedCapacity(gpa, 1);
...@@ -3832,7 +3852,7 @@ pub fn updateDeclExports(...@@ -3832,7 +3852,7 @@ pub fn updateDeclExports(
38323852
3833 self.resolveGlobalSymbol(sym_loc) catch |err| switch (err) {3853 self.resolveGlobalSymbol(sym_loc) catch |err| switch (err) {
3834 error.MultipleSymbolDefinitions => {3854 error.MultipleSymbolDefinitions => {
3835 const global = self.globals.get(exp_name).?;3855 const global = self.getGlobal(exp_name).?;
3836 if (sym_loc.sym_index != global.sym_index and global.file != null) {3856 if (sym_loc.sym_index != global.sym_index and global.file != null) {
3837 _ = try module.failed_exports.put(module.gpa, exp, try Module.ErrorMsg.create(3857 _ = try module.failed_exports.put(module.gpa, exp, try Module.ErrorMsg.create(
3838 gpa,3858 gpa,
...@@ -3869,11 +3889,13 @@ pub fn deleteExport(self: *MachO, exp: Export) void {...@@ -3869,11 +3889,13 @@ pub fn deleteExport(self: *MachO, exp: Export) void {
3869 };3889 };
3870 self.locals_free_list.append(gpa, sym_index) catch {};3890 self.locals_free_list.append(gpa, sym_index) catch {};
38713891
3872 if (self.globals.get(sym_name)) |global| blk: {3892 if (self.resolver.fetchRemove(sym_name)) |entry| {
3873 if (global.sym_index != sym_index) break :blk;3893 defer gpa.free(entry.key);
3874 if (global.file != null) break :blk;3894 self.globals_free_list.append(gpa, entry.value) catch {};
3875 const kv = self.globals.fetchSwapRemove(sym_name);3895 self.globals.items[entry.value] = .{
3876 gpa.free(kv.?.key);3896 .sym_index = 0,
3897 .file = null,
3898 };
3877 }3899 }
3878}3900}
38793901
...@@ -4864,30 +4886,23 @@ pub fn addAtomToSection(self: *MachO, atom: *Atom, sect_id: u8) !void {...@@ -4864,30 +4886,23 @@ pub fn addAtomToSection(self: *MachO, atom: *Atom, sect_id: u8) !void {
48644886
4865pub fn getGlobalSymbol(self: *MachO, name: []const u8) !u32 {4887pub fn getGlobalSymbol(self: *MachO, name: []const u8) !u32 {
4866 const gpa = self.base.allocator;4888 const gpa = self.base.allocator;
4889
4867 const sym_name = try std.fmt.allocPrint(gpa, "_{s}", .{name});4890 const sym_name = try std.fmt.allocPrint(gpa, "_{s}", .{name});
4868 const global_index = @intCast(u32, self.globals.values().len);4891 defer gpa.free(sym_name);
4869 const gop = try self.globals.getOrPut(gpa, sym_name);4892 const gop = try self.getOrPutGlobalPtr(sym_name);
4870 defer if (gop.found_existing) gpa.free(sym_name);
48714893
4872 if (gop.found_existing) {4894 if (gop.found_existing) {
4873 // TODO audit this: can we ever reference anything from outside the Zig module?
4874 assert(gop.value_ptr.file == null);
4875 return gop.value_ptr.sym_index;4895 return gop.value_ptr.sym_index;
4876 }4896 }
48774897
4878 const sym_index = @intCast(u32, self.locals.items.len);4898 const sym_index = try self.allocateSymbol();
4879 try self.locals.append(gpa, .{4899 const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = null };
4880 .n_strx = try self.strtab.insert(gpa, sym_name),4900 gop.value_ptr.* = sym_loc;
4881 .n_type = macho.N_UNDF,4901
4882 .n_sect = 0,4902 const sym = self.getSymbolPtr(sym_loc);
4883 .n_desc = 0,4903 sym.n_strx = try self.strtab.insert(gpa, sym_name);
4884 .n_value = 0,4904
4885 });4905 try self.unresolved.putNoClobber(gpa, self.getGlobalIndex(sym_name).?, true);
4886 gop.value_ptr.* = .{
4887 .sym_index = sym_index,
4888 .file = null,
4889 };
4890 try self.unresolved.putNoClobber(gpa, global_index, true);
48914906
4892 return sym_index;4907 return sym_index;
4893}4908}
...@@ -5055,7 +5070,7 @@ fn writeDyldInfoData(self: *MachO, ncmds: *u32, lc_writer: anytype) !void {...@@ -5055,7 +5070,7 @@ fn writeDyldInfoData(self: *MachO, ncmds: *u32, lc_writer: anytype) !void {
5055 if (self.base.options.output_mode == .Exe) {5070 if (self.base.options.output_mode == .Exe) {
5056 for (&[_]SymbolWithLoc{5071 for (&[_]SymbolWithLoc{
5057 try self.getEntryPoint(),5072 try self.getEntryPoint(),
5058 self.globals.get("__mh_execute_header").?,5073 self.getGlobal("__mh_execute_header").?,
5059 }) |global| {5074 }) |global| {
5060 const sym = self.getSymbol(global);5075 const sym = self.getSymbol(global);
5061 const sym_name = self.getSymbolName(global);5076 const sym_name = self.getSymbolName(global);
...@@ -5068,7 +5083,7 @@ fn writeDyldInfoData(self: *MachO, ncmds: *u32, lc_writer: anytype) !void {...@@ -5068,7 +5083,7 @@ fn writeDyldInfoData(self: *MachO, ncmds: *u32, lc_writer: anytype) !void {
5068 }5083 }
5069 } else {5084 } else {
5070 assert(self.base.options.output_mode == .Lib);5085 assert(self.base.options.output_mode == .Lib);
5071 for (self.globals.values()) |global| {5086 for (self.globals.items) |global| {
5072 const sym = self.getSymbol(global);5087 const sym = self.getSymbol(global);
50735088
5074 if (sym.undf()) continue;5089 if (sym.undf()) continue;
...@@ -5271,9 +5286,9 @@ fn writeFunctionStarts(self: *MachO, ncmds: *u32, lc_writer: anytype) !void {...@@ -5271,9 +5286,9 @@ fn writeFunctionStarts(self: *MachO, ncmds: *u32, lc_writer: anytype) !void {
5271 // We need to sort by address first5286 // We need to sort by address first
5272 var addresses = std.ArrayList(u64).init(gpa);5287 var addresses = std.ArrayList(u64).init(gpa);
5273 defer addresses.deinit();5288 defer addresses.deinit();
5274 try addresses.ensureTotalCapacityPrecise(self.globals.count());5289 try addresses.ensureTotalCapacityPrecise(self.globals.items.len);
52755290
5276 for (self.globals.values()) |global| {5291 for (self.globals.items) |global| {
5277 const sym = self.getSymbol(global);5292 const sym = self.getSymbol(global);
5278 if (sym.undf()) continue;5293 if (sym.undf()) continue;
5279 if (sym.n_desc == N_DESC_GCED) continue;5294 if (sym.n_desc == N_DESC_GCED) continue;
...@@ -5453,7 +5468,7 @@ fn writeSymtab(self: *MachO, lc: *macho.symtab_command) !SymtabCtx {...@@ -5453,7 +5468,7 @@ fn writeSymtab(self: *MachO, lc: *macho.symtab_command) !SymtabCtx {
5453 if (sym.n_desc == N_DESC_GCED) continue; // GCed, skip5468 if (sym.n_desc == N_DESC_GCED) continue; // GCed, skip
5454 const sym_loc = SymbolWithLoc{ .sym_index = @intCast(u32, sym_id), .file = null };5469 const sym_loc = SymbolWithLoc{ .sym_index = @intCast(u32, sym_id), .file = null };
5455 if (self.symbolIsTemp(sym_loc)) continue; // local temp symbol, skip5470 if (self.symbolIsTemp(sym_loc)) continue; // local temp symbol, skip
5456 if (self.globals.contains(self.getSymbolName(sym_loc))) continue; // global symbol is either an export or import, skip5471 if (self.getGlobal(self.getSymbolName(sym_loc)) != null) continue; // global symbol is either an export or import, skip
5457 try locals.append(sym);5472 try locals.append(sym);
5458 }5473 }
54595474
...@@ -5463,7 +5478,7 @@ fn writeSymtab(self: *MachO, lc: *macho.symtab_command) !SymtabCtx {...@@ -5463,7 +5478,7 @@ fn writeSymtab(self: *MachO, lc: *macho.symtab_command) !SymtabCtx {
5463 if (sym.n_desc == N_DESC_GCED) continue; // GCed, skip5478 if (sym.n_desc == N_DESC_GCED) continue; // GCed, skip
5464 const sym_loc = SymbolWithLoc{ .sym_index = @intCast(u32, sym_id), .file = @intCast(u32, object_id) };5479 const sym_loc = SymbolWithLoc{ .sym_index = @intCast(u32, sym_id), .file = @intCast(u32, object_id) };
5465 if (self.symbolIsTemp(sym_loc)) continue; // local temp symbol, skip5480 if (self.symbolIsTemp(sym_loc)) continue; // local temp symbol, skip
5466 if (self.globals.contains(self.getSymbolName(sym_loc))) continue; // global symbol is either an export or import, skip5481 if (self.getGlobal(self.getSymbolName(sym_loc)) != null) continue; // global symbol is either an export or import, skip
5467 var out_sym = sym;5482 var out_sym = sym;
5468 out_sym.n_strx = try self.strtab.insert(gpa, self.getSymbolName(sym_loc));5483 out_sym.n_strx = try self.strtab.insert(gpa, self.getSymbolName(sym_loc));
5469 try locals.append(out_sym);5484 try locals.append(out_sym);
...@@ -5477,7 +5492,7 @@ fn writeSymtab(self: *MachO, lc: *macho.symtab_command) !SymtabCtx {...@@ -5477,7 +5492,7 @@ fn writeSymtab(self: *MachO, lc: *macho.symtab_command) !SymtabCtx {
5477 var exports = std.ArrayList(macho.nlist_64).init(gpa);5492 var exports = std.ArrayList(macho.nlist_64).init(gpa);
5478 defer exports.deinit();5493 defer exports.deinit();
54795494
5480 for (self.globals.values()) |global| {5495 for (self.globals.items) |global| {
5481 const sym = self.getSymbol(global);5496 const sym = self.getSymbol(global);
5482 if (sym.undf()) continue; // import, skip5497 if (sym.undf()) continue; // import, skip
5483 if (sym.n_desc == N_DESC_GCED) continue; // GCed, skip5498 if (sym.n_desc == N_DESC_GCED) continue; // GCed, skip
...@@ -5491,7 +5506,7 @@ fn writeSymtab(self: *MachO, lc: *macho.symtab_command) !SymtabCtx {...@@ -5491,7 +5506,7 @@ fn writeSymtab(self: *MachO, lc: *macho.symtab_command) !SymtabCtx {
54915506
5492 var imports_table = std.AutoHashMap(SymbolWithLoc, u32).init(gpa);5507 var imports_table = std.AutoHashMap(SymbolWithLoc, u32).init(gpa);
54935508
5494 for (self.globals.values()) |global| {5509 for (self.globals.items) |global| {
5495 const sym = self.getSymbol(global);5510 const sym = self.getSymbol(global);
5496 if (sym.n_strx == 0) continue; // no name, skip5511 if (sym.n_strx == 0) continue; // no name, skip
5497 if (!sym.undf()) continue; // not an import, skip5512 if (!sym.undf()) continue; // not an import, skip
...@@ -5798,6 +5813,43 @@ pub fn getSymbolName(self: *MachO, sym_with_loc: SymbolWithLoc) []const u8 {...@@ -5798,6 +5813,43 @@ pub fn getSymbolName(self: *MachO, sym_with_loc: SymbolWithLoc) []const u8 {
5798 }5813 }
5799}5814}
58005815
5816/// Returns pointer to the global entry for `name` if one exists.
5817pub fn getGlobalPtr(self: *MachO, name: []const u8) ?*SymbolWithLoc {
5818 const global_index = self.resolver.get(name) orelse return null;
5819 return &self.globals.items[global_index];
5820}
5821
5822/// Returns the global entry for `name` if one exists.
5823pub fn getGlobal(self: *const MachO, name: []const u8) ?SymbolWithLoc {
5824 const global_index = self.resolver.get(name) orelse return null;
5825 return self.globals.items[global_index];
5826}
5827
5828/// Returns the index of the global entry for `name` if one exists.
5829pub fn getGlobalIndex(self: *const MachO, name: []const u8) ?u32 {
5830 return self.resolver.get(name);
5831}
5832
5833const GetOrPutGlobalPtrResult = struct {
5834 found_existing: bool,
5835 value_ptr: *SymbolWithLoc,
5836};
5837
5838/// Return pointer to the global entry for `name` if one exists.
5839/// Puts a new global entry for `name` if one doesn't exist, and
5840/// returns a pointer to it.
5841pub fn getOrPutGlobalPtr(self: *MachO, name: []const u8) !GetOrPutGlobalPtrResult {
5842 if (self.getGlobalPtr(name)) |ptr| {
5843 return GetOrPutGlobalPtrResult{ .found_existing = true, .value_ptr = ptr };
5844 }
5845 const gpa = self.base.allocator;
5846 const global_index = try self.allocateGlobal();
5847 const global_name = try gpa.dupe(u8, name);
5848 _ = try self.resolver.put(gpa, global_name, global_index);
5849 const ptr = &self.globals.items[global_index];
5850 return GetOrPutGlobalPtrResult{ .found_existing = false, .value_ptr = ptr };
5851}
5852
5801/// Returns atom if there is an atom referenced by the symbol described by `sym_with_loc` descriptor.5853/// Returns atom if there is an atom referenced by the symbol described by `sym_with_loc` descriptor.
5802/// Returns null on failure.5854/// Returns null on failure.
5803pub fn getAtomForSymbol(self: *MachO, sym_with_loc: SymbolWithLoc) ?*Atom {5855pub fn getAtomForSymbol(self: *MachO, sym_with_loc: SymbolWithLoc) ?*Atom {
...@@ -5834,7 +5886,7 @@ pub fn getTlvPtrAtomForSymbol(self: *MachO, sym_with_loc: SymbolWithLoc) ?*Atom...@@ -5834,7 +5886,7 @@ pub fn getTlvPtrAtomForSymbol(self: *MachO, sym_with_loc: SymbolWithLoc) ?*Atom
5834/// Asserts output mode is executable.5886/// Asserts output mode is executable.
5835pub fn getEntryPoint(self: MachO) error{MissingMainEntrypoint}!SymbolWithLoc {5887pub fn getEntryPoint(self: MachO) error{MissingMainEntrypoint}!SymbolWithLoc {
5836 const entry_name = self.base.options.entry orelse "_main";5888 const entry_name = self.base.options.entry orelse "_main";
5837 const global = self.globals.get(entry_name) orelse {5889 const global = self.getGlobal(entry_name) orelse {
5838 log.err("entrypoint '{s}' not found", .{entry_name});5890 log.err("entrypoint '{s}' not found", .{entry_name});
5839 return error.MissingMainEntrypoint;5891 return error.MissingMainEntrypoint;
5840 };5892 };
...@@ -6342,9 +6394,9 @@ fn logSymtab(self: *MachO) void {...@@ -6342,9 +6394,9 @@ fn logSymtab(self: *MachO) void {
6342 }6394 }
63436395
6344 log.debug("globals table:", .{});6396 log.debug("globals table:", .{});
6345 for (self.globals.keys()) |name, id| {6397 for (self.globals.items) |global| {
6346 const value = self.globals.values()[id];6398 const name = self.getSymbolName(global);
6347 log.debug(" {s} => %{d} in object({?d})", .{ name, value.sym_index, value.file });6399 log.debug(" {s} => %{d} in object({?d})", .{ name, global.sym_index, global.file });
6348 }6400 }
63496401
6350 log.debug("GOT entries:", .{});6402 log.debug("GOT entries:", .{});
src/link/MachO/Atom.zig+3-3
...@@ -272,7 +272,7 @@ pub fn parseRelocs(self: *Atom, relocs: []align(1) const macho.relocation_info,...@@ -272,7 +272,7 @@ pub fn parseRelocs(self: *Atom, relocs: []align(1) const macho.relocation_info,
272 subtractor = sym_loc;272 subtractor = sym_loc;
273 } else {273 } else {
274 const sym_name = context.macho_file.getSymbolName(sym_loc);274 const sym_name = context.macho_file.getSymbolName(sym_loc);
275 subtractor = context.macho_file.globals.get(sym_name).?;275 subtractor = context.macho_file.getGlobal(sym_name).?;
276 }276 }
277 // Verify that *_SUBTRACTOR is followed by *_UNSIGNED.277 // Verify that *_SUBTRACTOR is followed by *_UNSIGNED.
278 if (relocs.len <= i + 1) {278 if (relocs.len <= i + 1) {
...@@ -339,7 +339,7 @@ pub fn parseRelocs(self: *Atom, relocs: []align(1) const macho.relocation_info,...@@ -339,7 +339,7 @@ pub fn parseRelocs(self: *Atom, relocs: []align(1) const macho.relocation_info,
339 break :target sym_loc;339 break :target sym_loc;
340 } else {340 } else {
341 const sym_name = context.macho_file.getSymbolName(sym_loc);341 const sym_name = context.macho_file.getSymbolName(sym_loc);
342 break :target context.macho_file.globals.get(sym_name).?;342 break :target context.macho_file.getGlobal(sym_name).?;
343 }343 }
344 };344 };
345 const offset = @intCast(u32, rel.r_address - context.base_offset);345 const offset = @intCast(u32, rel.r_address - context.base_offset);
...@@ -579,7 +579,7 @@ pub fn resolveRelocs(self: *Atom, macho_file: *MachO) !void {...@@ -579,7 +579,7 @@ pub fn resolveRelocs(self: *Atom, macho_file: *MachO) !void {
579 // If there is no atom for target, we still need to check for special, atom-less579 // If there is no atom for target, we still need to check for special, atom-less
580 // symbols such as `___dso_handle`.580 // symbols such as `___dso_handle`.
581 const target_name = macho_file.getSymbolName(rel.target);581 const target_name = macho_file.getSymbolName(rel.target);
582 assert(macho_file.globals.contains(target_name));582 assert(macho_file.getGlobal(target_name) != null);
583 const atomless_sym = macho_file.getSymbol(rel.target);583 const atomless_sym = macho_file.getSymbol(rel.target);
584 log.debug(" | atomless target '{s}'", .{target_name});584 log.debug(" | atomless target '{s}'", .{target_name});
585 break :blk atomless_sym.n_value;585 break :blk atomless_sym.n_value;
src/link/MachO/DebugSymbols.zig+2-2
...@@ -480,7 +480,7 @@ fn writeSymtab(self: *DebugSymbols, lc: *macho.symtab_command) !void {...@@ -480,7 +480,7 @@ fn writeSymtab(self: *DebugSymbols, lc: *macho.symtab_command) !void {
480 if (sym.n_desc == MachO.N_DESC_GCED) continue; // GCed, skip480 if (sym.n_desc == MachO.N_DESC_GCED) continue; // GCed, skip
481 const sym_loc = MachO.SymbolWithLoc{ .sym_index = @intCast(u32, sym_id), .file = null };481 const sym_loc = MachO.SymbolWithLoc{ .sym_index = @intCast(u32, sym_id), .file = null };
482 if (self.base.symbolIsTemp(sym_loc)) continue; // local temp symbol, skip482 if (self.base.symbolIsTemp(sym_loc)) continue; // local temp symbol, skip
483 if (self.base.globals.contains(self.base.getSymbolName(sym_loc))) continue; // global symbol is either an export or import, skip483 if (self.base.getGlobal(self.base.getSymbolName(sym_loc)) != null) continue; // global symbol is either an export or import, skip
484 var out_sym = sym;484 var out_sym = sym;
485 out_sym.n_strx = try self.strtab.insert(gpa, self.base.getSymbolName(sym_loc));485 out_sym.n_strx = try self.strtab.insert(gpa, self.base.getSymbolName(sym_loc));
486 try locals.append(out_sym);486 try locals.append(out_sym);
...@@ -489,7 +489,7 @@ fn writeSymtab(self: *DebugSymbols, lc: *macho.symtab_command) !void {...@@ -489,7 +489,7 @@ fn writeSymtab(self: *DebugSymbols, lc: *macho.symtab_command) !void {
489 var exports = std.ArrayList(macho.nlist_64).init(gpa);489 var exports = std.ArrayList(macho.nlist_64).init(gpa);
490 defer exports.deinit();490 defer exports.deinit();
491491
492 for (self.base.globals.values()) |global| {492 for (self.base.globals.items) |global| {
493 const sym = self.base.getSymbol(global);493 const sym = self.base.getSymbol(global);
494 if (sym.undf()) continue; // import, skip494 if (sym.undf()) continue; // import, skip
495 if (sym.n_desc == MachO.N_DESC_GCED) continue; // GCed, skip495 if (sym.n_desc == MachO.N_DESC_GCED) continue; // GCed, skip
src/link/MachO/dead_strip.zig+2-2
...@@ -62,7 +62,7 @@ fn collectRoots(roots: *std.AutoHashMap(*Atom, void), macho_file: *MachO) !void...@@ -62,7 +62,7 @@ fn collectRoots(roots: *std.AutoHashMap(*Atom, void), macho_file: *MachO) !void
62 else => |other| {62 else => |other| {
63 assert(other == .Lib);63 assert(other == .Lib);
64 // Add exports as GC roots64 // Add exports as GC roots
65 for (macho_file.globals.values()) |global| {65 for (macho_file.globals.items) |global| {
66 const sym = macho_file.getSymbol(global);66 const sym = macho_file.getSymbol(global);
67 if (!sym.sect()) continue;67 if (!sym.sect()) continue;
68 const atom = macho_file.getAtomForSymbol(global) orelse {68 const atom = macho_file.getAtomForSymbol(global) orelse {
...@@ -77,7 +77,7 @@ fn collectRoots(roots: *std.AutoHashMap(*Atom, void), macho_file: *MachO) !void...@@ -77,7 +77,7 @@ fn collectRoots(roots: *std.AutoHashMap(*Atom, void), macho_file: *MachO) !void
77 }77 }
7878
79 // TODO just a temp until we learn how to parse unwind records79 // TODO just a temp until we learn how to parse unwind records
80 if (macho_file.globals.get("___gxx_personality_v0")) |global| {80 if (macho_file.getGlobal("___gxx_personality_v0")) |global| {
81 if (macho_file.getAtomForSymbol(global)) |atom| {81 if (macho_file.getAtomForSymbol(global)) |atom| {
82 _ = try roots.getOrPut(atom);82 _ = try roots.getOrPut(atom);
83 log.debug("adding root", .{});83 log.debug("adding root", .{});