authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-10-29 17:47:58+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-10-29 18:55:58+01:00
loga7a95ce9c4e11e8b3ab887481a7f0e7e8294a87c
tree3b4f7d71604291b606974c61ad53ee7d7da493de
parenteaca72534c6d57acf85b7f20e76fd31302785a5e

macho: implement exporting anon decls


2 files changed, 73 insertions(+), 53 deletions(-)

src/link/MachO.zig+67-51
......@@ -130,7 +130,7 @@ bindings: BindingTable = .{},
130130lazy_syms: LazySymbolTable = .{},
131131
132132/// Table of tracked Decls.
133decls: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, DeclMetadata) = .{},
133decls: DeclTable = .{},
134134
135135/// Table of threadlocal variables descriptors.
136136/// They are emitted in the `__thread_vars` section.
......@@ -1904,6 +1904,7 @@ pub fn deinit(self: *MachO) void {
19041904 m.exports.deinit(gpa);
19051905 }
19061906 self.decls.deinit(gpa);
1907
19071908 self.lazy_syms.deinit(gpa);
19081909 self.tlv_table.deinit(gpa);
19091910
......@@ -1911,7 +1912,14 @@ pub fn deinit(self: *MachO) void {
19111912 atoms.deinit(gpa);
19121913 }
19131914 self.unnamed_const_atoms.deinit(gpa);
1914 self.anon_decls.deinit(gpa);
1915
1916 {
1917 var it = self.anon_decls.iterator();
1918 while (it.next()) |entry| {
1919 entry.value_ptr.exports.deinit(gpa);
1920 }
1921 self.anon_decls.deinit(gpa);
1922 }
19151923
19161924 self.atom_by_index_table.deinit(gpa);
19171925
......@@ -2689,18 +2697,30 @@ pub fn updateExports(
26892697
26902698 const gpa = self.base.allocator;
26912699
2692 const decl_index = switch (exported) {
2693 .decl_index => |i| i,
2694 .value => |val| {
2695 _ = val;
2696 @panic("TODO: implement MachO linker code for exporting a constant value");
2700 const metadata = switch (exported) {
2701 .decl_index => |decl_index| blk: {
2702 _ = try self.getOrCreateAtomForDecl(decl_index);
2703 break :blk self.decls.getPtr(decl_index).?;
2704 },
2705 .value => |value| self.anon_decls.getPtr(value) orelse blk: {
2706 const first_exp = exports[0];
2707 const res = try self.lowerAnonDecl(value, .none, first_exp.getSrcLoc(mod));
2708 switch (res) {
2709 .ok => {},
2710 .fail => |em| {
2711 // TODO maybe it's enough to return an error here and let Module.processExportsInner
2712 // handle the error?
2713 try mod.failed_exports.ensureUnusedCapacity(mod.gpa, 1);
2714 mod.failed_exports.putAssumeCapacityNoClobber(first_exp, em);
2715 return;
2716 },
2717 }
2718 break :blk self.anon_decls.getPtr(value).?;
26972719 },
26982720 };
2699 const decl = mod.declPtr(decl_index);
2700 const atom_index = try self.getOrCreateAtomForDecl(decl_index);
2721 const atom_index = metadata.atom;
27012722 const atom = self.getAtom(atom_index);
2702 const decl_sym = atom.getSymbol(self);
2703 const decl_metadata = self.decls.getPtr(decl_index).?;
2723 const sym = atom.getSymbol(self);
27042724
27052725 for (exports) |exp| {
27062726 const exp_name = try std.fmt.allocPrint(gpa, "_{}", .{
......@@ -2712,73 +2732,65 @@ pub fn updateExports(
27122732
27132733 if (exp.opts.section.unwrap()) |section_name| {
27142734 if (!mod.intern_pool.stringEqlSlice(section_name, "__text")) {
2715 try mod.failed_exports.putNoClobber(
2716 mod.gpa,
2717 exp,
2718 try Module.ErrorMsg.create(
2719 gpa,
2720 decl.srcLoc(mod),
2721 "Unimplemented: ExportOptions.section",
2722 .{},
2723 ),
2724 );
2735 try mod.failed_exports.putNoClobber(mod.gpa, exp, try Module.ErrorMsg.create(
2736 gpa,
2737 exp.getSrcLoc(mod),
2738 "Unimplemented: ExportOptions.section",
2739 .{},
2740 ));
27252741 continue;
27262742 }
27272743 }
27282744
27292745 if (exp.opts.linkage == .LinkOnce) {
2730 try mod.failed_exports.putNoClobber(
2731 mod.gpa,
2732 exp,
2733 try Module.ErrorMsg.create(
2734 gpa,
2735 decl.srcLoc(mod),
2736 "Unimplemented: GlobalLinkage.LinkOnce",
2737 .{},
2738 ),
2739 );
2746 try mod.failed_exports.putNoClobber(mod.gpa, exp, try Module.ErrorMsg.create(
2747 gpa,
2748 exp.getSrcLoc(mod),
2749 "Unimplemented: GlobalLinkage.LinkOnce",
2750 .{},
2751 ));
27402752 continue;
27412753 }
27422754
2743 const sym_index = decl_metadata.getExport(self, exp_name) orelse blk: {
2744 const sym_index = try self.allocateSymbol();
2745 try decl_metadata.exports.append(gpa, sym_index);
2746 break :blk sym_index;
2755 const global_sym_index = metadata.getExport(self, exp_name) orelse blk: {
2756 const global_sym_index = try self.allocateSymbol();
2757 try metadata.exports.append(gpa, global_sym_index);
2758 break :blk global_sym_index;
27472759 };
2748 const sym_loc = SymbolWithLoc{ .sym_index = sym_index };
2749 const sym = self.getSymbolPtr(sym_loc);
2750 sym.* = .{
2760 const global_sym_loc = SymbolWithLoc{ .sym_index = global_sym_index };
2761 const global_sym = self.getSymbolPtr(global_sym_loc);
2762 global_sym.* = .{
27512763 .n_strx = try self.strtab.insert(gpa, exp_name),
27522764 .n_type = macho.N_SECT | macho.N_EXT,
2753 .n_sect = self.text_section_index.? + 1, // TODO what if we export a variable?
2765 .n_sect = metadata.section + 1,
27542766 .n_desc = 0,
2755 .n_value = decl_sym.n_value,
2767 .n_value = sym.n_value,
27562768 };
27572769
27582770 switch (exp.opts.linkage) {
27592771 .Internal => {
27602772 // Symbol should be hidden, or in MachO lingo, private extern.
27612773 // We should also mark the symbol as Weak: n_desc == N_WEAK_DEF.
2762 sym.n_type |= macho.N_PEXT;
2763 sym.n_desc |= macho.N_WEAK_DEF;
2774 global_sym.n_type |= macho.N_PEXT;
2775 global_sym.n_desc |= macho.N_WEAK_DEF;
27642776 },
27652777 .Strong => {},
27662778 .Weak => {
27672779 // Weak linkage is specified as part of n_desc field.
27682780 // Symbol's n_type is like for a symbol with strong linkage.
2769 sym.n_desc |= macho.N_WEAK_DEF;
2781 global_sym.n_desc |= macho.N_WEAK_DEF;
27702782 },
27712783 else => unreachable,
27722784 }
27732785
2774 self.resolveGlobalSymbol(sym_loc) catch |err| switch (err) {
2786 self.resolveGlobalSymbol(global_sym_loc) catch |err| switch (err) {
27752787 error.MultipleSymbolDefinitions => {
27762788 // TODO: this needs rethinking
27772789 const global = self.getGlobal(exp_name).?;
2778 if (sym_loc.sym_index != global.sym_index and global.getFile() != null) {
2790 if (global_sym_loc.sym_index != global.sym_index and global.getFile() != null) {
27792791 _ = try mod.failed_exports.put(mod.gpa, exp, try Module.ErrorMsg.create(
27802792 gpa,
2781 decl.srcLoc(mod),
2793 exp.getSrcLoc(mod),
27822794 \\LinkError: symbol '{s}' defined multiple times
27832795 ,
27842796 .{exp_name},
......@@ -2886,8 +2898,8 @@ pub fn lowerAnonDecl(
28862898 .none => ty.abiAlignment(mod),
28872899 else => explicit_alignment,
28882900 };
2889 if (self.anon_decls.get(decl_val)) |atom_index| {
2890 const existing_addr = self.getAtom(atom_index).getSymbol(self).n_value;
2901 if (self.anon_decls.get(decl_val)) |metadata| {
2902 const existing_addr = self.getAtom(metadata.atom).getSymbol(self).n_value;
28912903 if (decl_alignment.check(existing_addr))
28922904 return .ok;
28932905 }
......@@ -2917,14 +2929,17 @@ pub fn lowerAnonDecl(
29172929 .ok => |atom_index| atom_index,
29182930 .fail => |em| return .{ .fail = em },
29192931 };
2920 try self.anon_decls.put(gpa, decl_val, atom_index);
2932 try self.anon_decls.put(gpa, decl_val, .{
2933 .atom = atom_index,
2934 .section = self.data_const_section_index.?,
2935 });
29212936 return .ok;
29222937}
29232938
29242939pub fn getAnonDeclVAddr(self: *MachO, decl_val: InternPool.Index, reloc_info: link.File.RelocInfo) !u64 {
29252940 assert(self.llvm_object == null);
29262941
2927 const this_atom_index = self.anon_decls.get(decl_val).?;
2942 const this_atom_index = self.anon_decls.get(decl_val).?.atom;
29282943 const sym_index = self.getAtom(this_atom_index).getSymbolIndex().?;
29292944 const atom_index = self.getAtomIndexForSymbol(.{ .sym_index = reloc_info.parent_atom_index }).?;
29302945 try Atom.addRelocation(self, atom_index, .{
......@@ -5489,7 +5504,8 @@ const DeclMetadata = struct {
54895504 }
54905505};
54915506
5492const AnonDeclTable = std.AutoHashMapUnmanaged(InternPool.Index, Atom.Index);
5507const DeclTable = std.AutoArrayHashMapUnmanaged(Module.Decl.Index, DeclMetadata);
5508const AnonDeclTable = std.AutoHashMapUnmanaged(InternPool.Index, DeclMetadata);
54935509const BindingTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(Atom.Binding));
54945510const UnnamedConstTable = std.AutoArrayHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(Atom.Index));
54955511const RebaseTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(u32));
test/behavior/export_builtin.zig+6-2
......@@ -54,7 +54,9 @@ test "exporting using field access" {
5454test "exporting comptime-known value" {
5555 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
5656 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
57 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
57 if (builtin.zig_backend == .stage2_x86_64 and
58 (builtin.target.ofmt != .elf and
59 builtin.target.ofmt != .macho)) return error.SkipZigTest;
5860 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
5961 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
6062 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
......@@ -70,7 +72,9 @@ test "exporting comptime-known value" {
7072test "exporting comptime var" {
7173 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
7274 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
73 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
75 if (builtin.zig_backend == .stage2_x86_64 and
76 (builtin.target.ofmt != .elf and
77 builtin.target.ofmt != .macho)) return error.SkipZigTest;
7478 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
7579 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
7680 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;