| author | |
| committer | |
| log | 8d03e4fc6b361e6cf96865acc05820556ae33863 |
| tree | 1f6d431c2f2aef13df992f3d571f6291c66f5e7e |
| parent | 359b61aec3494197aaca336dabaa39d0515706ff |
5 files changed, 101 insertions(+), 38 deletions(-)
src/arch/wasm/CodeGen.zig+14-7| ... | ... | @@ -1737,7 +1737,12 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. |
| 1737 | 1737 | var func_type = try genFunctype(self.gpa, ext_decl.ty.fnInfo(), self.target); |
| 1738 | 1738 | defer func_type.deinit(self.gpa); |
| 1739 | 1739 | ext_decl.fn_link.wasm.type_index = try self.bin_file.putOrGetFuncType(func_type); |
| 1740 | try self.bin_file.addOrUpdateImport(ext_decl); | |
| 1740 | try self.bin_file.addOrUpdateImport( | |
| 1741 | mem.sliceTo(ext_decl.name, 0), | |
| 1742 | ext_decl.link.wasm.sym_index, | |
| 1743 | ext_decl.getExternFn().?.lib_name, | |
| 1744 | ext_decl.fn_link.wasm.type_index, | |
| 1745 | ); | |
| 1741 | 1746 | break :blk ext_decl; |
| 1742 | 1747 | } else if (func_val.castTag(.decl_ref)) |decl_ref| { |
| 1743 | 1748 | break :blk module.declPtr(decl_ref.data); |
| ... | ... | @@ -5107,13 +5112,15 @@ fn callIntrinsic( |
| 5107 | 5112 | args: []const WValue, |
| 5108 | 5113 | ) InnerError!WValue { |
| 5109 | 5114 | assert(param_types.len == args.len); |
| 5110 | const symbol_index = @intCast(u32, try self.bin_file.getIntrinsicSymbol(name)); | |
| 5111 | var pt_tmp = try self.gpa.dupe(Type, param_types); | |
| 5112 | defer self.gpa.free(pt_tmp); | |
| 5115 | const symbol_index = self.bin_file.base.getGlobalSymbol(name) catch |err| { | |
| 5116 | return self.fail("Could not find or create global symbol '{s}'", .{@errorName(err)}); | |
| 5117 | }; | |
| 5113 | 5118 | |
| 5114 | 5119 | // TODO: have genFunctype accept individual params so we don't, |
| 5115 | 5120 | // need to initialize a fake Fn.Data instance. |
| 5116 | const func_type = try genFunctype(self.base.allocator, .{ | |
| 5121 | var pt_tmp = try self.gpa.dupe(Type, param_types); | |
| 5122 | defer self.gpa.free(pt_tmp); | |
| 5123 | var func_type = try genFunctype(self.gpa, .{ | |
| 5117 | 5124 | .param_types = pt_tmp, |
| 5118 | 5125 | .comptime_params = undefined, |
| 5119 | 5126 | .return_type = return_type, |
| ... | ... | @@ -5122,9 +5129,9 @@ fn callIntrinsic( |
| 5122 | 5129 | .is_var_args = false, |
| 5123 | 5130 | .is_generic = false, |
| 5124 | 5131 | }, self.target); |
| 5125 | defer func_type.deinit(self.base.allocator); | |
| 5132 | defer func_type.deinit(self.gpa); | |
| 5126 | 5133 | const func_type_index = try self.bin_file.putOrGetFuncType(func_type); |
| 5127 | try self.bin_file.addOrUpdateImport(symbol_index, func_type_index); | |
| 5134 | try self.bin_file.addOrUpdateImport(name, symbol_index, null, func_type_index); | |
| 5128 | 5135 | |
| 5129 | 5136 | const want_sret_param = firstParamSRet(.C, return_type, self.target); |
| 5130 | 5137 | // if we want return as first param, we allocate a pointer to stack, |
src/link.zig+18| ... | ... | @@ -438,6 +438,24 @@ pub const File = struct { |
| 438 | 438 | } |
| 439 | 439 | } |
| 440 | 440 | |
| 441 | /// Called from within CodeGen to retrieve the symbol index of a global symbol. | |
| 442 | /// If no symbol exists yet with this name, a new one will be created instead. | |
| 443 | pub fn getGlobalSymbol(base: *File, name: []const u8) UpdateDeclError!u32 { | |
| 444 | log.debug("getGlobalSymbol '{s}'", .{name}); | |
| 445 | switch (base.tag) { | |
| 446 | // zig fmt: off | |
| 447 | .coff => unreachable, | |
| 448 | .elf => unreachable, | |
| 449 | .macho => unreachable, | |
| 450 | .plan9 => unreachable, | |
| 451 | .spirv => unreachable, | |
| 452 | .c => unreachable, | |
| 453 | .wasm => return @fieldParentPtr(Wasm, "base", base).getGlobalSymbol(name), | |
| 454 | .nvptx => unreachable, | |
| 455 | // zig fmt: on | |
| 456 | } | |
| 457 | } | |
| 458 | ||
| 441 | 459 | /// May be called before or after updateDeclExports but must be called |
| 442 | 460 | /// after allocateDeclIndexes for any given Decl. |
| 443 | 461 | pub fn updateDecl(base: *File, module: *Module, decl_index: Module.Decl.Index) UpdateDeclError!void { |
src/link/Wasm.zig+41-23| ... | ... | @@ -433,6 +433,13 @@ fn resolveSymbolsInObject(self: *Wasm, object_index: u16) !void { |
| 433 | 433 | continue; // Do not overwrite defined symbols with undefined symbols |
| 434 | 434 | } |
| 435 | 435 | |
| 436 | if (symbol.tag != existing_sym.tag) { | |
| 437 | log.err("symbol '{s}' mismatching type '{s}", .{ sym_name, @tagName(symbol.tag) }); | |
| 438 | log.err(" first definition in '{s}'", .{existing_file_path}); | |
| 439 | log.err(" next definition in '{s}'", .{object.name}); | |
| 440 | return error.SymbolMismatchingType; | |
| 441 | } | |
| 442 | ||
| 436 | 443 | // when both symbols are weak, we skip overwriting |
| 437 | 444 | if (existing_sym.isWeak() and symbol.isWeak()) { |
| 438 | 445 | continue; |
| ... | ... | @@ -755,7 +762,7 @@ pub fn lowerUnnamedConst(self: *Wasm, tv: TypedValue, decl_index: Module.Decl.In |
| 755 | 762 | /// Returns the symbol index from the name of an intrinsic. |
| 756 | 763 | /// If the symbol does not yet exist, creates a new one symbol instead |
| 757 | 764 | /// and then returns the index to it. |
| 758 | pub fn getIntrinsicSymbol(self: *Wasm, name: []const u8) !u64 { | |
| 765 | pub fn getGlobalSymbol(self: *Wasm, name: []const u8) !u32 { | |
| 759 | 766 | const name_index = try self.string_table.put(self.base.allocator, name); |
| 760 | 767 | const gop = try self.globals.getOrPut(self.base.allocator, name_index); |
| 761 | 768 | if (gop.found_existing) { |
| ... | ... | @@ -769,7 +776,7 @@ pub fn getIntrinsicSymbol(self: *Wasm, name: []const u8) !u64 { |
| 769 | 776 | .tag = .function, |
| 770 | 777 | }; |
| 771 | 778 | symbol.setGlobal(true); |
| 772 | symbol.setFlag(.WASM_SYM_UNDEFINED); | |
| 779 | symbol.setUndefined(true); | |
| 773 | 780 | |
| 774 | 781 | const sym_index = if (self.symbols_free_list.popOrNull()) |index| index else blk: { |
| 775 | 782 | var index = @intCast(u32, self.symbols.items.len); |
| ... | ... | @@ -779,7 +786,7 @@ pub fn getIntrinsicSymbol(self: *Wasm, name: []const u8) !u64 { |
| 779 | 786 | }; |
| 780 | 787 | self.symbols.items[sym_index] = symbol; |
| 781 | 788 | gop.value_ptr.* = .{ .index = sym_index, .file = null }; |
| 782 | ||
| 789 | try self.resolved_symbols.put(self.base.allocator, gop.value_ptr.*, {}); | |
| 783 | 790 | return sym_index; |
| 784 | 791 | } |
| 785 | 792 | |
| ... | ... | @@ -982,10 +989,24 @@ fn mapFunctionTable(self: *Wasm) void { |
| 982 | 989 | } |
| 983 | 990 | } |
| 984 | 991 | |
| 985 | pub fn addOrUpdateImport(self: *Wasm, decl: *Module.Decl) !void { | |
| 992 | /// Either creates a new import, or updates one if existing. | |
| 993 | /// When `type_index` is non-null, we assume an external function. | |
| 994 | /// In all other cases, a data-symbol will be created instead. | |
| 995 | pub fn addOrUpdateImport( | |
| 996 | self: *Wasm, | |
| 997 | /// Name of the import | |
| 998 | name: []const u8, | |
| 999 | /// Symbol index that is external | |
| 1000 | symbol_index: u32, | |
| 1001 | /// Optional library name (i.e. `extern "c" fn foo() void` | |
| 1002 | lib_name: ?[*:0]const u8, | |
| 1003 | /// The index of the type that represents the function signature | |
| 1004 | /// when the extern is a function. When this is null, a data-symbol | |
| 1005 | /// is asserted instead. | |
| 1006 | type_index: ?u32, | |
| 1007 | ) !void { | |
| 986 | 1008 | // For the import name itself, we use the decl's name, rather than the fully qualified name |
| 987 | const decl_name_index = try self.string_table.put(self.base.allocator, mem.sliceTo(decl.name, 0)); | |
| 988 | const symbol_index = decl.link.wasm.sym_index; | |
| 1009 | const decl_name_index = try self.string_table.put(self.base.allocator, name); | |
| 989 | 1010 | const symbol: *Symbol = &self.symbols.items[symbol_index]; |
| 990 | 1011 | symbol.setUndefined(true); |
| 991 | 1012 | symbol.setGlobal(true); |
| ... | ... | @@ -996,22 +1017,19 @@ pub fn addOrUpdateImport(self: *Wasm, decl: *Module.Decl) !void { |
| 996 | 1017 | try self.resolved_symbols.put(self.base.allocator, loc, {}); |
| 997 | 1018 | } |
| 998 | 1019 | |
| 999 | switch (decl.ty.zigTypeTag()) { | |
| 1000 | .Fn => { | |
| 1001 | const gop = try self.imports.getOrPut(self.base.allocator, .{ .index = symbol_index, .file = null }); | |
| 1002 | const module_name = if (decl.getExternFn().?.lib_name) |lib_name| blk: { | |
| 1003 | break :blk mem.sliceTo(lib_name, 0); | |
| 1004 | } else self.host_name; | |
| 1005 | if (!gop.found_existing) { | |
| 1006 | gop.value_ptr.* = .{ | |
| 1007 | .module_name = try self.string_table.put(self.base.allocator, module_name), | |
| 1008 | .name = decl_name_index, | |
| 1009 | .kind = .{ .function = decl.fn_link.wasm.type_index }, | |
| 1010 | }; | |
| 1011 | } | |
| 1012 | }, | |
| 1013 | else => @panic("TODO: Implement undefined symbols for non-function declarations"), | |
| 1014 | } | |
| 1020 | if (type_index) |ty_index| { | |
| 1021 | const gop = try self.imports.getOrPut(self.base.allocator, .{ .index = symbol_index, .file = null }); | |
| 1022 | const module_name = if (lib_name) |l_name| blk: { | |
| 1023 | break :blk mem.sliceTo(l_name, 0); | |
| 1024 | } else self.host_name; | |
| 1025 | if (!gop.found_existing) { | |
| 1026 | gop.value_ptr.* = .{ | |
| 1027 | .module_name = try self.string_table.put(self.base.allocator, module_name), | |
| 1028 | .name = decl_name_index, | |
| 1029 | .kind = .{ .function = ty_index }, | |
| 1030 | }; | |
| 1031 | } | |
| 1032 | } else @panic("TODO: Implement undefined symbols for non-function declarations"); | |
| 1015 | 1033 | } |
| 1016 | 1034 | |
| 1017 | 1035 | const Kind = union(enum) { |
| ... | ... | @@ -1251,7 +1269,7 @@ fn mergeSections(self: *Wasm) !void { |
| 1251 | 1269 | symbol.index = @intCast(u32, self.tables.items.len) + self.imported_tables_count; |
| 1252 | 1270 | try self.tables.append(self.base.allocator, original_table); |
| 1253 | 1271 | }, |
| 1254 | else => {}, | |
| 1272 | else => unreachable, | |
| 1255 | 1273 | } |
| 1256 | 1274 | } |
| 1257 | 1275 |
src/link/Wasm/Atom.zig+4-1| ... | ... | @@ -171,7 +171,10 @@ fn relocationValue(self: Atom, relocation: types.Relocation, wasm_bin: *const Wa |
| 171 | 171 | } |
| 172 | 172 | std.debug.assert(symbol.tag == .data); |
| 173 | 173 | const merge_segment = wasm_bin.base.options.output_mode != .Obj; |
| 174 | const segment_name = wasm_bin.segment_info.items[symbol.index].outputName(merge_segment); | |
| 174 | const segment_info = if (self.file) |object_index| blk: { | |
| 175 | break :blk wasm_bin.objects.items[object_index].segment_info; | |
| 176 | } else wasm_bin.segment_info.items; | |
| 177 | const segment_name = segment_info[symbol.index].outputName(merge_segment); | |
| 175 | 178 | const atom_index = wasm_bin.data_segments.get(segment_name).?; |
| 176 | 179 | const target_atom = wasm_bin.symbol_atom.get(target_loc).?; |
| 177 | 180 | const segment = wasm_bin.segments.items[atom_index]; |
src/link/Wasm/Object.zig+24-7| ... | ... | @@ -302,12 +302,16 @@ fn Parser(comptime ReaderType: type) type { |
| 302 | 302 | } |
| 303 | 303 | |
| 304 | 304 | fn parseObject(self: *Self, gpa: Allocator, is_object_file: *bool) Error!void { |
| 305 | errdefer self.object.deinit(gpa); | |
| 305 | 306 | try self.verifyMagicBytes(); |
| 306 | 307 | const version = try self.reader.reader().readIntLittle(u32); |
| 307 | 308 | |
| 308 | 309 | self.object.version = version; |
| 309 | 310 | var relocatable_data = std.ArrayList(RelocatableData).init(gpa); |
| 310 | defer relocatable_data.deinit(); | |
| 311 | ||
| 312 | errdefer while (relocatable_data.popOrNull()) |rel_data| { | |
| 313 | gpa.free(rel_data.data[0..rel_data.size]); | |
| 314 | } else relocatable_data.deinit(); | |
| 311 | 315 | |
| 312 | 316 | var section_index: u32 = 0; |
| 313 | 317 | while (self.reader.reader().readByte()) |byte| : (section_index += 1) { |
| ... | ... | @@ -808,26 +812,29 @@ pub fn parseIntoAtoms(self: *Object, gpa: Allocator, object_index: u16, wasm_bin |
| 808 | 812 | kind: Symbol.Tag, |
| 809 | 813 | index: u32, |
| 810 | 814 | }; |
| 811 | var symbol_for_segment = std.AutoArrayHashMap(Key, u32).init(gpa); | |
| 815 | var symbol_for_segment = std.AutoArrayHashMap(Key, std.ArrayList(u32)).init(gpa); | |
| 812 | 816 | defer symbol_for_segment.deinit(); |
| 813 | 817 | |
| 814 | 818 | for (self.symtable) |symbol, symbol_index| { |
| 815 | 819 | switch (symbol.tag) { |
| 816 | 820 | .function, .data => if (!symbol.isUndefined()) { |
| 817 | try symbol_for_segment.putNoClobber( | |
| 818 | .{ .kind = symbol.tag, .index = symbol.index }, | |
| 819 | @intCast(u32, symbol_index), | |
| 820 | ); | |
| 821 | const gop = try symbol_for_segment.getOrPut(.{ .kind = symbol.tag, .index = symbol.index }); | |
| 822 | const sym_idx = @intCast(u32, symbol_index); | |
| 823 | if (!gop.found_existing) { | |
| 824 | gop.value_ptr.* = std.ArrayList(u32).init(gpa); | |
| 825 | } | |
| 826 | try gop.value_ptr.*.append(sym_idx); | |
| 821 | 827 | }, |
| 822 | 828 | else => continue, |
| 823 | 829 | } |
| 824 | 830 | } |
| 825 | 831 | |
| 826 | 832 | for (self.relocatable_data) |relocatable_data, index| { |
| 827 | const sym_index = symbol_for_segment.get(.{ | |
| 833 | const symbols = symbol_for_segment.getPtr(.{ | |
| 828 | 834 | .kind = relocatable_data.getSymbolKind(), |
| 829 | 835 | .index = @intCast(u32, relocatable_data.index), |
| 830 | 836 | }) orelse continue; // encountered a segment we do not create an atom for |
| 837 | const sym_index = symbols.pop(); | |
| 831 | 838 | const final_index = try wasm_bin.getMatchingSegment(object_index, @intCast(u32, index)); |
| 832 | 839 | |
| 833 | 840 | const atom = try gpa.create(Atom); |
| ... | ... | @@ -862,6 +869,16 @@ pub fn parseIntoAtoms(self: *Object, gpa: Allocator, object_index: u16, wasm_bin |
| 862 | 869 | } |
| 863 | 870 | |
| 864 | 871 | try atom.code.appendSlice(gpa, relocatable_data.data[0..relocatable_data.size]); |
| 872 | ||
| 873 | // symbols referencing the same atom will be added as alias | |
| 874 | // or as 'parent' when they are global. | |
| 875 | while (symbols.popOrNull()) |idx| { | |
| 876 | const alias_symbol = self.symtable[idx]; | |
| 877 | const symbol = self.symtable[atom.sym_index]; | |
| 878 | if (alias_symbol.isGlobal() and symbol.isLocal()) { | |
| 879 | atom.sym_index = idx; | |
| 880 | } | |
| 881 | } | |
| 865 | 882 | try wasm_bin.symbol_atom.putNoClobber(gpa, atom.symbolLoc(), atom); |
| 866 | 883 | |
| 867 | 884 | const segment: *Wasm.Segment = &wasm_bin.segments.items[final_index]; |