| ... | @@ -607,6 +607,24 @@ fn resolveSymbolsInArchives(self: *Wasm) !void { | ... | @@ -607,6 +607,24 @@ fn resolveSymbolsInArchives(self: *Wasm) !void { |
| 607 | } | 607 | } |
| 608 | } | 608 | } |
| 609 | | 609 | |
| | 610 | fn checkUndefinedSymbols(self: *const Wasm) !void { |
| | 611 | var found_undefined_symbols = false; |
| | 612 | for (self.undefs.values()) |undef| { |
| | 613 | const symbol = undef.getSymbol(self); |
| | 614 | if (symbol.tag == .data) { |
| | 615 | found_undefined_symbols = true; |
| | 616 | const file_name = if (undef.file) |file_index| name: { |
| | 617 | break :name self.objects.items[file_index].name; |
| | 618 | } else self.name; |
| | 619 | log.err("could not resolve undefined symbol '{s}'", .{undef.getName(self)}); |
| | 620 | log.err(" defined in '{s}'", .{file_name}); |
| | 621 | } |
| | 622 | } |
| | 623 | if (found_undefined_symbols) { |
| | 624 | return error.UndefinedSymbol; |
| | 625 | } |
| | 626 | } |
| | 627 | |
| 610 | pub fn deinit(self: *Wasm) void { | 628 | pub fn deinit(self: *Wasm) void { |
| 611 | const gpa = self.base.allocator; | 629 | const gpa = self.base.allocator; |
| 612 | if (build_options.have_llvm) { | 630 | if (build_options.have_llvm) { |
| ... | @@ -783,15 +801,17 @@ pub fn updateDecl(self: *Wasm, mod: *Module, decl_index: Module.Decl.Index) !voi | ... | @@ -783,15 +801,17 @@ pub fn updateDecl(self: *Wasm, mod: *Module, decl_index: Module.Decl.Index) !voi |
| 783 | | 801 | |
| 784 | decl.link.wasm.clear(); | 802 | decl.link.wasm.clear(); |
| 785 | | 803 | |
| 786 | if (decl.isExtern()) { | | |
| 787 | return; | | |
| 788 | } | | |
| 789 | | | |
| 790 | if (decl.val.castTag(.function)) |_| { | 804 | if (decl.val.castTag(.function)) |_| { |
| 791 | return; | 805 | return; |
| 792 | } else if (decl.val.castTag(.extern_fn)) |_| { | 806 | } else if (decl.val.castTag(.extern_fn)) |_| { |
| 793 | return; | 807 | return; |
| 794 | } | 808 | } |
| | 809 | |
| | 810 | if (decl.isExtern()) { |
| | 811 | const variable = decl.getVariable().?; |
| | 812 | const name = mem.sliceTo(decl.name, 0); |
| | 813 | return self.addOrUpdateImport(name, decl.link.wasm.sym_index, variable.lib_name, null); |
| | 814 | } |
| 795 | const val = if (decl.val.castTag(.variable)) |payload| payload.data.init else decl.val; | 815 | const val = if (decl.val.castTag(.variable)) |payload| payload.data.init else decl.val; |
| 796 | | 816 | |
| 797 | var code_writer = std.ArrayList(u8).init(self.base.allocator); | 817 | var code_writer = std.ArrayList(u8).init(self.base.allocator); |
| ... | @@ -834,19 +854,18 @@ pub fn updateDeclLineNumber(self: *Wasm, mod: *Module, decl: *const Module.Decl) | ... | @@ -834,19 +854,18 @@ pub fn updateDeclLineNumber(self: *Wasm, mod: *Module, decl: *const Module.Decl) |
| 834 | } | 854 | } |
| 835 | | 855 | |
| 836 | fn finishUpdateDecl(self: *Wasm, decl: *Module.Decl, code: []const u8) !void { | 856 | fn finishUpdateDecl(self: *Wasm, decl: *Module.Decl, code: []const u8) !void { |
| 837 | if (code.len == 0) return; | | |
| 838 | const mod = self.base.options.module.?; | 857 | const mod = self.base.options.module.?; |
| 839 | const atom: *Atom = &decl.link.wasm; | 858 | const atom: *Atom = &decl.link.wasm; |
| 840 | atom.size = @intCast(u32, code.len); | | |
| 841 | atom.alignment = decl.ty.abiAlignment(self.base.options.target); | | |
| 842 | const symbol = &self.symbols.items[atom.sym_index]; | 859 | const symbol = &self.symbols.items[atom.sym_index]; |
| 843 | | | |
| 844 | const full_name = try decl.getFullyQualifiedName(mod); | 860 | const full_name = try decl.getFullyQualifiedName(mod); |
| 845 | defer self.base.allocator.free(full_name); | 861 | defer self.base.allocator.free(full_name); |
| 846 | symbol.name = try self.string_table.put(self.base.allocator, full_name); | 862 | symbol.name = try self.string_table.put(self.base.allocator, full_name); |
| 847 | try atom.code.appendSlice(self.base.allocator, code); | 863 | try atom.code.appendSlice(self.base.allocator, code); |
| 848 | | | |
| 849 | try self.resolved_symbols.put(self.base.allocator, atom.symbolLoc(), {}); | 864 | try self.resolved_symbols.put(self.base.allocator, atom.symbolLoc(), {}); |
| | 865 | |
| | 866 | if (code.len == 0) return; |
| | 867 | atom.size = @intCast(u32, code.len); |
| | 868 | atom.alignment = decl.ty.abiAlignment(self.base.options.target); |
| 850 | } | 869 | } |
| 851 | | 870 | |
| 852 | /// From a given symbol location, returns its `wasm.GlobalType`. | 871 | /// From a given symbol location, returns its `wasm.GlobalType`. |
| ... | @@ -1235,7 +1254,10 @@ pub fn addOrUpdateImport( | ... | @@ -1235,7 +1254,10 @@ pub fn addOrUpdateImport( |
| 1235 | .kind = .{ .function = ty_index }, | 1254 | .kind = .{ .function = ty_index }, |
| 1236 | }; | 1255 | }; |
| 1237 | } | 1256 | } |
| 1238 | } else @panic("TODO: Implement undefined symbols for non-function declarations"); | 1257 | } else { |
| | 1258 | symbol.tag = .data; |
| | 1259 | return; // non-functions will not be imported from the runtime, but only resolved during link-time |
| | 1260 | } |
| 1239 | } | 1261 | } |
| 1240 | | 1262 | |
| 1241 | /// Kind represents the type of an Atom, which is only | 1263 | /// Kind represents the type of an Atom, which is only |
| ... | @@ -1438,7 +1460,7 @@ fn setupImports(self: *Wasm) !void { | ... | @@ -1438,7 +1460,7 @@ fn setupImports(self: *Wasm) !void { |
| 1438 | if (std.mem.eql(u8, symbol_loc.getName(self), "__indirect_function_table")) { | 1460 | if (std.mem.eql(u8, symbol_loc.getName(self), "__indirect_function_table")) { |
| 1439 | continue; | 1461 | continue; |
| 1440 | } | 1462 | } |
| 1441 | if (symbol.tag == .data or !symbol.requiresImport()) { | 1463 | if (!symbol.requiresImport()) { |
| 1442 | continue; | 1464 | continue; |
| 1443 | } | 1465 | } |
| 1444 | | 1466 | |
| ... | @@ -2007,6 +2029,7 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod | ... | @@ -2007,6 +2029,7 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod |
| 2007 | } | 2029 | } |
| 2008 | | 2030 | |
| 2009 | try self.resolveSymbolsInArchives(); | 2031 | try self.resolveSymbolsInArchives(); |
| | 2032 | try self.checkUndefinedSymbols(); |
| 2010 | | 2033 | |
| 2011 | // When we finish/error we reset the state of the linker | 2034 | // When we finish/error we reset the state of the linker |
| 2012 | // So we can rebuild the binary file on each incremental update | 2035 | // So we can rebuild the binary file on each incremental update |