| 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,7 +1737,12 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. |
| 1737 | var func_type = try genFunctype(self.gpa, ext_decl.ty.fnInfo(), self.target); | 1737 | var func_type = try genFunctype(self.gpa, ext_decl.ty.fnInfo(), self.target); |
| 1738 | defer func_type.deinit(self.gpa); | 1738 | defer func_type.deinit(self.gpa); |
| 1739 | ext_decl.fn_link.wasm.type_index = try self.bin_file.putOrGetFuncType(func_type); | 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 | break :blk ext_decl; | 1746 | break :blk ext_decl; |
| 1742 | } else if (func_val.castTag(.decl_ref)) |decl_ref| { | 1747 | } else if (func_val.castTag(.decl_ref)) |decl_ref| { |
| 1743 | break :blk module.declPtr(decl_ref.data); | 1748 | break :blk module.declPtr(decl_ref.data); |
| ... | @@ -5107,13 +5112,15 @@ fn callIntrinsic( | ... | @@ -5107,13 +5112,15 @@ fn callIntrinsic( |
| 5107 | args: []const WValue, | 5112 | args: []const WValue, |
| 5108 | ) InnerError!WValue { | 5113 | ) InnerError!WValue { |
| 5109 | assert(param_types.len == args.len); | 5114 | assert(param_types.len == args.len); |
| 5110 | const symbol_index = @intCast(u32, try self.bin_file.getIntrinsicSymbol(name)); | 5115 | const symbol_index = self.bin_file.base.getGlobalSymbol(name) catch |err| { |
| 5111 | var pt_tmp = try self.gpa.dupe(Type, param_types); | 5116 | return self.fail("Could not find or create global symbol '{s}'", .{@errorName(err)}); |
| 5112 | defer self.gpa.free(pt_tmp); | 5117 | }; |
| 5113 | 5118 | ||
| 5114 | // TODO: have genFunctype accept individual params so we don't, | 5119 | // TODO: have genFunctype accept individual params so we don't, |
| 5115 | // need to initialize a fake Fn.Data instance. | 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 | .param_types = pt_tmp, | 5124 | .param_types = pt_tmp, |
| 5118 | .comptime_params = undefined, | 5125 | .comptime_params = undefined, |
| 5119 | .return_type = return_type, | 5126 | .return_type = return_type, |
| ... | @@ -5122,9 +5129,9 @@ fn callIntrinsic( | ... | @@ -5122,9 +5129,9 @@ fn callIntrinsic( |
| 5122 | .is_var_args = false, | 5129 | .is_var_args = false, |
| 5123 | .is_generic = false, | 5130 | .is_generic = false, |
| 5124 | }, self.target); | 5131 | }, self.target); |
| 5125 | defer func_type.deinit(self.base.allocator); | 5132 | defer func_type.deinit(self.gpa); |
| 5126 | const func_type_index = try self.bin_file.putOrGetFuncType(func_type); | 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 | const want_sret_param = firstParamSRet(.C, return_type, self.target); | 5136 | const want_sret_param = firstParamSRet(.C, return_type, self.target); |
| 5130 | // if we want return as first param, we allocate a pointer to stack, | 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,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 | /// May be called before or after updateDeclExports but must be called | 459 | /// May be called before or after updateDeclExports but must be called |
| 442 | /// after allocateDeclIndexes for any given Decl. | 460 | /// after allocateDeclIndexes for any given Decl. |
| 443 | pub fn updateDecl(base: *File, module: *Module, decl_index: Module.Decl.Index) UpdateDeclError!void { | 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,6 +433,13 @@ fn resolveSymbolsInObject(self: *Wasm, object_index: u16) !void { |
| 433 | continue; // Do not overwrite defined symbols with undefined symbols | 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 | // when both symbols are weak, we skip overwriting | 443 | // when both symbols are weak, we skip overwriting |
| 437 | if (existing_sym.isWeak() and symbol.isWeak()) { | 444 | if (existing_sym.isWeak() and symbol.isWeak()) { |
| 438 | continue; | 445 | continue; |
| ... | @@ -755,7 +762,7 @@ pub fn lowerUnnamedConst(self: *Wasm, tv: TypedValue, decl_index: Module.Decl.In | ... | @@ -755,7 +762,7 @@ pub fn lowerUnnamedConst(self: *Wasm, tv: TypedValue, decl_index: Module.Decl.In |
| 755 | /// Returns the symbol index from the name of an intrinsic. | 762 | /// Returns the symbol index from the name of an intrinsic. |
| 756 | /// If the symbol does not yet exist, creates a new one symbol instead | 763 | /// If the symbol does not yet exist, creates a new one symbol instead |
| 757 | /// and then returns the index to it. | 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 | const name_index = try self.string_table.put(self.base.allocator, name); | 766 | const name_index = try self.string_table.put(self.base.allocator, name); |
| 760 | const gop = try self.globals.getOrPut(self.base.allocator, name_index); | 767 | const gop = try self.globals.getOrPut(self.base.allocator, name_index); |
| 761 | if (gop.found_existing) { | 768 | if (gop.found_existing) { |
| ... | @@ -769,7 +776,7 @@ pub fn getIntrinsicSymbol(self: *Wasm, name: []const u8) !u64 { | ... | @@ -769,7 +776,7 @@ pub fn getIntrinsicSymbol(self: *Wasm, name: []const u8) !u64 { |
| 769 | .tag = .function, | 776 | .tag = .function, |
| 770 | }; | 777 | }; |
| 771 | symbol.setGlobal(true); | 778 | symbol.setGlobal(true); |
| 772 | symbol.setFlag(.WASM_SYM_UNDEFINED); | 779 | symbol.setUndefined(true); |
| 773 | 780 | ||
| 774 | const sym_index = if (self.symbols_free_list.popOrNull()) |index| index else blk: { | 781 | const sym_index = if (self.symbols_free_list.popOrNull()) |index| index else blk: { |
| 775 | var index = @intCast(u32, self.symbols.items.len); | 782 | var index = @intCast(u32, self.symbols.items.len); |
| ... | @@ -779,7 +786,7 @@ pub fn getIntrinsicSymbol(self: *Wasm, name: []const u8) !u64 { | ... | @@ -779,7 +786,7 @@ pub fn getIntrinsicSymbol(self: *Wasm, name: []const u8) !u64 { |
| 779 | }; | 786 | }; |
| 780 | self.symbols.items[sym_index] = symbol; | 787 | self.symbols.items[sym_index] = symbol; |
| 781 | gop.value_ptr.* = .{ .index = sym_index, .file = null }; | 788 | gop.value_ptr.* = .{ .index = sym_index, .file = null }; |
| 782 | 789 | try self.resolved_symbols.put(self.base.allocator, gop.value_ptr.*, {}); | |
| 783 | return sym_index; | 790 | return sym_index; |
| 784 | } | 791 | } |
| 785 | 792 | ||
| ... | @@ -982,10 +989,24 @@ fn mapFunctionTable(self: *Wasm) void { | ... | @@ -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 | // For the import name itself, we use the decl's name, rather than the fully qualified name | 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)); | 1009 | const decl_name_index = try self.string_table.put(self.base.allocator, name); |
| 988 | const symbol_index = decl.link.wasm.sym_index; | ||
| 989 | const symbol: *Symbol = &self.symbols.items[symbol_index]; | 1010 | const symbol: *Symbol = &self.symbols.items[symbol_index]; |
| 990 | symbol.setUndefined(true); | 1011 | symbol.setUndefined(true); |
| 991 | symbol.setGlobal(true); | 1012 | symbol.setGlobal(true); |
| ... | @@ -996,22 +1017,19 @@ pub fn addOrUpdateImport(self: *Wasm, decl: *Module.Decl) !void { | ... | @@ -996,22 +1017,19 @@ pub fn addOrUpdateImport(self: *Wasm, decl: *Module.Decl) !void { |
| 996 | try self.resolved_symbols.put(self.base.allocator, loc, {}); | 1017 | try self.resolved_symbols.put(self.base.allocator, loc, {}); |
| 997 | } | 1018 | } |
| 998 | 1019 | ||
| 999 | switch (decl.ty.zigTypeTag()) { | 1020 | if (type_index) |ty_index| { |
| 1000 | .Fn => { | 1021 | const gop = try self.imports.getOrPut(self.base.allocator, .{ .index = symbol_index, .file = null }); |
| 1001 | const gop = try self.imports.getOrPut(self.base.allocator, .{ .index = symbol_index, .file = null }); | 1022 | const module_name = if (lib_name) |l_name| blk: { |
| 1002 | const module_name = if (decl.getExternFn().?.lib_name) |lib_name| blk: { | 1023 | break :blk mem.sliceTo(l_name, 0); |
| 1003 | break :blk mem.sliceTo(lib_name, 0); | 1024 | } else self.host_name; |
| 1004 | } else self.host_name; | 1025 | if (!gop.found_existing) { |
| 1005 | if (!gop.found_existing) { | 1026 | gop.value_ptr.* = .{ |
| 1006 | gop.value_ptr.* = .{ | 1027 | .module_name = try self.string_table.put(self.base.allocator, module_name), |
| 1007 | .module_name = try self.string_table.put(self.base.allocator, module_name), | 1028 | .name = decl_name_index, |
| 1008 | .name = decl_name_index, | 1029 | .kind = .{ .function = ty_index }, |
| 1009 | .kind = .{ .function = decl.fn_link.wasm.type_index }, | 1030 | }; |
| 1010 | }; | 1031 | } |
| 1011 | } | 1032 | } else @panic("TODO: Implement undefined symbols for non-function declarations"); |
| 1012 | }, | ||
| 1013 | else => @panic("TODO: Implement undefined symbols for non-function declarations"), | ||
| 1014 | } | ||
| 1015 | } | 1033 | } |
| 1016 | 1034 | ||
| 1017 | const Kind = union(enum) { | 1035 | const Kind = union(enum) { |
| ... | @@ -1251,7 +1269,7 @@ fn mergeSections(self: *Wasm) !void { | ... | @@ -1251,7 +1269,7 @@ fn mergeSections(self: *Wasm) !void { |
| 1251 | symbol.index = @intCast(u32, self.tables.items.len) + self.imported_tables_count; | 1269 | symbol.index = @intCast(u32, self.tables.items.len) + self.imported_tables_count; |
| 1252 | try self.tables.append(self.base.allocator, original_table); | 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,7 +171,10 @@ fn relocationValue(self: Atom, relocation: types.Relocation, wasm_bin: *const Wa |
| 171 | } | 171 | } |
| 172 | std.debug.assert(symbol.tag == .data); | 172 | std.debug.assert(symbol.tag == .data); |
| 173 | const merge_segment = wasm_bin.base.options.output_mode != .Obj; | 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 | const atom_index = wasm_bin.data_segments.get(segment_name).?; | 178 | const atom_index = wasm_bin.data_segments.get(segment_name).?; |
| 176 | const target_atom = wasm_bin.symbol_atom.get(target_loc).?; | 179 | const target_atom = wasm_bin.symbol_atom.get(target_loc).?; |
| 177 | const segment = wasm_bin.segments.items[atom_index]; | 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,12 +302,16 @@ fn Parser(comptime ReaderType: type) type { |
| 302 | } | 302 | } |
| 303 | 303 | ||
| 304 | fn parseObject(self: *Self, gpa: Allocator, is_object_file: *bool) Error!void { | 304 | fn parseObject(self: *Self, gpa: Allocator, is_object_file: *bool) Error!void { |
| 305 | errdefer self.object.deinit(gpa); | ||
| 305 | try self.verifyMagicBytes(); | 306 | try self.verifyMagicBytes(); |
| 306 | const version = try self.reader.reader().readIntLittle(u32); | 307 | const version = try self.reader.reader().readIntLittle(u32); |
| 307 | 308 | ||
| 308 | self.object.version = version; | 309 | self.object.version = version; |
| 309 | var relocatable_data = std.ArrayList(RelocatableData).init(gpa); | 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 | var section_index: u32 = 0; | 316 | var section_index: u32 = 0; |
| 313 | while (self.reader.reader().readByte()) |byte| : (section_index += 1) { | 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,26 +812,29 @@ pub fn parseIntoAtoms(self: *Object, gpa: Allocator, object_index: u16, wasm_bin |
| 808 | kind: Symbol.Tag, | 812 | kind: Symbol.Tag, |
| 809 | index: u32, | 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 | defer symbol_for_segment.deinit(); | 816 | defer symbol_for_segment.deinit(); |
| 813 | 817 | ||
| 814 | for (self.symtable) |symbol, symbol_index| { | 818 | for (self.symtable) |symbol, symbol_index| { |
| 815 | switch (symbol.tag) { | 819 | switch (symbol.tag) { |
| 816 | .function, .data => if (!symbol.isUndefined()) { | 820 | .function, .data => if (!symbol.isUndefined()) { |
| 817 | try symbol_for_segment.putNoClobber( | 821 | const gop = try symbol_for_segment.getOrPut(.{ .kind = symbol.tag, .index = symbol.index }); |
| 818 | .{ .kind = symbol.tag, .index = symbol.index }, | 822 | const sym_idx = @intCast(u32, symbol_index); |
| 819 | @intCast(u32, symbol_index), | 823 | if (!gop.found_existing) { |
| 820 | ); | 824 | gop.value_ptr.* = std.ArrayList(u32).init(gpa); |
| 825 | } | ||
| 826 | try gop.value_ptr.*.append(sym_idx); | ||
| 821 | }, | 827 | }, |
| 822 | else => continue, | 828 | else => continue, |
| 823 | } | 829 | } |
| 824 | } | 830 | } |
| 825 | 831 | ||
| 826 | for (self.relocatable_data) |relocatable_data, index| { | 832 | for (self.relocatable_data) |relocatable_data, index| { |
| 827 | const sym_index = symbol_for_segment.get(.{ | 833 | const symbols = symbol_for_segment.getPtr(.{ |
| 828 | .kind = relocatable_data.getSymbolKind(), | 834 | .kind = relocatable_data.getSymbolKind(), |
| 829 | .index = @intCast(u32, relocatable_data.index), | 835 | .index = @intCast(u32, relocatable_data.index), |
| 830 | }) orelse continue; // encountered a segment we do not create an atom for | 836 | }) orelse continue; // encountered a segment we do not create an atom for |
| 837 | const sym_index = symbols.pop(); | ||
| 831 | const final_index = try wasm_bin.getMatchingSegment(object_index, @intCast(u32, index)); | 838 | const final_index = try wasm_bin.getMatchingSegment(object_index, @intCast(u32, index)); |
| 832 | 839 | ||
| 833 | const atom = try gpa.create(Atom); | 840 | const atom = try gpa.create(Atom); |
| ... | @@ -862,6 +869,16 @@ pub fn parseIntoAtoms(self: *Object, gpa: Allocator, object_index: u16, wasm_bin | ... | @@ -862,6 +869,16 @@ pub fn parseIntoAtoms(self: *Object, gpa: Allocator, object_index: u16, wasm_bin |
| 862 | } | 869 | } |
| 863 | 870 | ||
| 864 | try atom.code.appendSlice(gpa, relocatable_data.data[0..relocatable_data.size]); | 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 | try wasm_bin.symbol_atom.putNoClobber(gpa, atom.symbolLoc(), atom); | 882 | try wasm_bin.symbol_atom.putNoClobber(gpa, atom.symbolLoc(), atom); |
| 866 | 883 | ||
| 867 | const segment: *Wasm.Segment = &wasm_bin.segments.items[final_index]; | 884 | const segment: *Wasm.Segment = &wasm_bin.segments.items[final_index]; |