aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/arch/wasm/CodeGen.zig21
-rw-r--r--src/link.zig18
-rw-r--r--src/link/Wasm.zig64
-rw-r--r--src/link/Wasm/Atom.zig5
-rw-r--r--src/link/Wasm/Object.zig31
5 files changed, 101 insertions, 38 deletions
diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig
index 28450c19c2..2f82f1f694 100644
--- a/src/arch/wasm/CodeGen.zig
+++ b/src/arch/wasm/CodeGen.zig
@@ -1737,7 +1737,12 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
var func_type = try genFunctype(self.gpa, ext_decl.ty.fnInfo(), self.target);
defer func_type.deinit(self.gpa);
ext_decl.fn_link.wasm.type_index = try self.bin_file.putOrGetFuncType(func_type);
- try self.bin_file.addOrUpdateImport(ext_decl);
+ try self.bin_file.addOrUpdateImport(
+ mem.sliceTo(ext_decl.name, 0),
+ ext_decl.link.wasm.sym_index,
+ ext_decl.getExternFn().?.lib_name,
+ ext_decl.fn_link.wasm.type_index,
+ );
break :blk ext_decl;
} else if (func_val.castTag(.decl_ref)) |decl_ref| {
break :blk module.declPtr(decl_ref.data);
@@ -5107,13 +5112,15 @@ fn callIntrinsic(
args: []const WValue,
) InnerError!WValue {
assert(param_types.len == args.len);
- const symbol_index = @intCast(u32, try self.bin_file.getIntrinsicSymbol(name));
- var pt_tmp = try self.gpa.dupe(Type, param_types);
- defer self.gpa.free(pt_tmp);
+ const symbol_index = self.bin_file.base.getGlobalSymbol(name) catch |err| {
+ return self.fail("Could not find or create global symbol '{s}'", .{@errorName(err)});
+ };
// TODO: have genFunctype accept individual params so we don't,
// need to initialize a fake Fn.Data instance.
- const func_type = try genFunctype(self.base.allocator, .{
+ var pt_tmp = try self.gpa.dupe(Type, param_types);
+ defer self.gpa.free(pt_tmp);
+ var func_type = try genFunctype(self.gpa, .{
.param_types = pt_tmp,
.comptime_params = undefined,
.return_type = return_type,
@@ -5122,9 +5129,9 @@ fn callIntrinsic(
.is_var_args = false,
.is_generic = false,
}, self.target);
- defer func_type.deinit(self.base.allocator);
+ defer func_type.deinit(self.gpa);
const func_type_index = try self.bin_file.putOrGetFuncType(func_type);
- try self.bin_file.addOrUpdateImport(symbol_index, func_type_index);
+ try self.bin_file.addOrUpdateImport(name, symbol_index, null, func_type_index);
const want_sret_param = firstParamSRet(.C, return_type, self.target);
// if we want return as first param, we allocate a pointer to stack,
diff --git a/src/link.zig b/src/link.zig
index ad1fc417f3..8bad44aa21 100644
--- a/src/link.zig
+++ b/src/link.zig
@@ -438,6 +438,24 @@ pub const File = struct {
}
}
+ /// Called from within CodeGen to retrieve the symbol index of a global symbol.
+ /// If no symbol exists yet with this name, a new one will be created instead.
+ pub fn getGlobalSymbol(base: *File, name: []const u8) UpdateDeclError!u32 {
+ log.debug("getGlobalSymbol '{s}'", .{name});
+ switch (base.tag) {
+ // zig fmt: off
+ .coff => unreachable,
+ .elf => unreachable,
+ .macho => unreachable,
+ .plan9 => unreachable,
+ .spirv => unreachable,
+ .c => unreachable,
+ .wasm => return @fieldParentPtr(Wasm, "base", base).getGlobalSymbol(name),
+ .nvptx => unreachable,
+ // zig fmt: on
+ }
+ }
+
/// May be called before or after updateDeclExports but must be called
/// after allocateDeclIndexes for any given Decl.
pub fn updateDecl(base: *File, module: *Module, decl_index: Module.Decl.Index) UpdateDeclError!void {
diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig
index 93240623ca..2e6a5dbc96 100644
--- a/src/link/Wasm.zig
+++ b/src/link/Wasm.zig
@@ -433,6 +433,13 @@ fn resolveSymbolsInObject(self: *Wasm, object_index: u16) !void {
continue; // Do not overwrite defined symbols with undefined symbols
}
+ if (symbol.tag != existing_sym.tag) {
+ log.err("symbol '{s}' mismatching type '{s}", .{ sym_name, @tagName(symbol.tag) });
+ log.err(" first definition in '{s}'", .{existing_file_path});
+ log.err(" next definition in '{s}'", .{object.name});
+ return error.SymbolMismatchingType;
+ }
+
// when both symbols are weak, we skip overwriting
if (existing_sym.isWeak() and symbol.isWeak()) {
continue;
@@ -755,7 +762,7 @@ pub fn lowerUnnamedConst(self: *Wasm, tv: TypedValue, decl_index: Module.Decl.In
/// Returns the symbol index from the name of an intrinsic.
/// If the symbol does not yet exist, creates a new one symbol instead
/// and then returns the index to it.
-pub fn getIntrinsicSymbol(self: *Wasm, name: []const u8) !u64 {
+pub fn getGlobalSymbol(self: *Wasm, name: []const u8) !u32 {
const name_index = try self.string_table.put(self.base.allocator, name);
const gop = try self.globals.getOrPut(self.base.allocator, name_index);
if (gop.found_existing) {
@@ -769,7 +776,7 @@ pub fn getIntrinsicSymbol(self: *Wasm, name: []const u8) !u64 {
.tag = .function,
};
symbol.setGlobal(true);
- symbol.setFlag(.WASM_SYM_UNDEFINED);
+ symbol.setUndefined(true);
const sym_index = if (self.symbols_free_list.popOrNull()) |index| index else blk: {
var index = @intCast(u32, self.symbols.items.len);
@@ -779,7 +786,7 @@ pub fn getIntrinsicSymbol(self: *Wasm, name: []const u8) !u64 {
};
self.symbols.items[sym_index] = symbol;
gop.value_ptr.* = .{ .index = sym_index, .file = null };
-
+ try self.resolved_symbols.put(self.base.allocator, gop.value_ptr.*, {});
return sym_index;
}
@@ -982,10 +989,24 @@ fn mapFunctionTable(self: *Wasm) void {
}
}
-pub fn addOrUpdateImport(self: *Wasm, decl: *Module.Decl) !void {
+/// Either creates a new import, or updates one if existing.
+/// When `type_index` is non-null, we assume an external function.
+/// In all other cases, a data-symbol will be created instead.
+pub fn addOrUpdateImport(
+ self: *Wasm,
+ /// Name of the import
+ name: []const u8,
+ /// Symbol index that is external
+ symbol_index: u32,
+ /// Optional library name (i.e. `extern "c" fn foo() void`
+ lib_name: ?[*:0]const u8,
+ /// The index of the type that represents the function signature
+ /// when the extern is a function. When this is null, a data-symbol
+ /// is asserted instead.
+ type_index: ?u32,
+) !void {
// For the import name itself, we use the decl's name, rather than the fully qualified name
- const decl_name_index = try self.string_table.put(self.base.allocator, mem.sliceTo(decl.name, 0));
- const symbol_index = decl.link.wasm.sym_index;
+ const decl_name_index = try self.string_table.put(self.base.allocator, name);
const symbol: *Symbol = &self.symbols.items[symbol_index];
symbol.setUndefined(true);
symbol.setGlobal(true);
@@ -996,22 +1017,19 @@ pub fn addOrUpdateImport(self: *Wasm, decl: *Module.Decl) !void {
try self.resolved_symbols.put(self.base.allocator, loc, {});
}
- switch (decl.ty.zigTypeTag()) {
- .Fn => {
- const gop = try self.imports.getOrPut(self.base.allocator, .{ .index = symbol_index, .file = null });
- const module_name = if (decl.getExternFn().?.lib_name) |lib_name| blk: {
- break :blk mem.sliceTo(lib_name, 0);
- } else self.host_name;
- if (!gop.found_existing) {
- gop.value_ptr.* = .{
- .module_name = try self.string_table.put(self.base.allocator, module_name),
- .name = decl_name_index,
- .kind = .{ .function = decl.fn_link.wasm.type_index },
- };
- }
- },
- else => @panic("TODO: Implement undefined symbols for non-function declarations"),
- }
+ if (type_index) |ty_index| {
+ const gop = try self.imports.getOrPut(self.base.allocator, .{ .index = symbol_index, .file = null });
+ const module_name = if (lib_name) |l_name| blk: {
+ break :blk mem.sliceTo(l_name, 0);
+ } else self.host_name;
+ if (!gop.found_existing) {
+ gop.value_ptr.* = .{
+ .module_name = try self.string_table.put(self.base.allocator, module_name),
+ .name = decl_name_index,
+ .kind = .{ .function = ty_index },
+ };
+ }
+ } else @panic("TODO: Implement undefined symbols for non-function declarations");
}
const Kind = union(enum) {
@@ -1251,7 +1269,7 @@ fn mergeSections(self: *Wasm) !void {
symbol.index = @intCast(u32, self.tables.items.len) + self.imported_tables_count;
try self.tables.append(self.base.allocator, original_table);
},
- else => {},
+ else => unreachable,
}
}
diff --git a/src/link/Wasm/Atom.zig b/src/link/Wasm/Atom.zig
index 6f65b1b83a..03b6fc6cf4 100644
--- a/src/link/Wasm/Atom.zig
+++ b/src/link/Wasm/Atom.zig
@@ -171,7 +171,10 @@ fn relocationValue(self: Atom, relocation: types.Relocation, wasm_bin: *const Wa
}
std.debug.assert(symbol.tag == .data);
const merge_segment = wasm_bin.base.options.output_mode != .Obj;
- const segment_name = wasm_bin.segment_info.items[symbol.index].outputName(merge_segment);
+ const segment_info = if (self.file) |object_index| blk: {
+ break :blk wasm_bin.objects.items[object_index].segment_info;
+ } else wasm_bin.segment_info.items;
+ const segment_name = segment_info[symbol.index].outputName(merge_segment);
const atom_index = wasm_bin.data_segments.get(segment_name).?;
const target_atom = wasm_bin.symbol_atom.get(target_loc).?;
const segment = wasm_bin.segments.items[atom_index];
diff --git a/src/link/Wasm/Object.zig b/src/link/Wasm/Object.zig
index 8abf78d825..3a24fc6ccb 100644
--- a/src/link/Wasm/Object.zig
+++ b/src/link/Wasm/Object.zig
@@ -302,12 +302,16 @@ fn Parser(comptime ReaderType: type) type {
}
fn parseObject(self: *Self, gpa: Allocator, is_object_file: *bool) Error!void {
+ errdefer self.object.deinit(gpa);
try self.verifyMagicBytes();
const version = try self.reader.reader().readIntLittle(u32);
self.object.version = version;
var relocatable_data = std.ArrayList(RelocatableData).init(gpa);
- defer relocatable_data.deinit();
+
+ errdefer while (relocatable_data.popOrNull()) |rel_data| {
+ gpa.free(rel_data.data[0..rel_data.size]);
+ } else relocatable_data.deinit();
var section_index: u32 = 0;
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
kind: Symbol.Tag,
index: u32,
};
- var symbol_for_segment = std.AutoArrayHashMap(Key, u32).init(gpa);
+ var symbol_for_segment = std.AutoArrayHashMap(Key, std.ArrayList(u32)).init(gpa);
defer symbol_for_segment.deinit();
for (self.symtable) |symbol, symbol_index| {
switch (symbol.tag) {
.function, .data => if (!symbol.isUndefined()) {
- try symbol_for_segment.putNoClobber(
- .{ .kind = symbol.tag, .index = symbol.index },
- @intCast(u32, symbol_index),
- );
+ const gop = try symbol_for_segment.getOrPut(.{ .kind = symbol.tag, .index = symbol.index });
+ const sym_idx = @intCast(u32, symbol_index);
+ if (!gop.found_existing) {
+ gop.value_ptr.* = std.ArrayList(u32).init(gpa);
+ }
+ try gop.value_ptr.*.append(sym_idx);
},
else => continue,
}
}
for (self.relocatable_data) |relocatable_data, index| {
- const sym_index = symbol_for_segment.get(.{
+ const symbols = symbol_for_segment.getPtr(.{
.kind = relocatable_data.getSymbolKind(),
.index = @intCast(u32, relocatable_data.index),
}) orelse continue; // encountered a segment we do not create an atom for
+ const sym_index = symbols.pop();
const final_index = try wasm_bin.getMatchingSegment(object_index, @intCast(u32, index));
const atom = try gpa.create(Atom);
@@ -862,6 +869,16 @@ pub fn parseIntoAtoms(self: *Object, gpa: Allocator, object_index: u16, wasm_bin
}
try atom.code.appendSlice(gpa, relocatable_data.data[0..relocatable_data.size]);
+
+ // symbols referencing the same atom will be added as alias
+ // or as 'parent' when they are global.
+ while (symbols.popOrNull()) |idx| {
+ const alias_symbol = self.symtable[idx];
+ const symbol = self.symtable[atom.sym_index];
+ if (alias_symbol.isGlobal() and symbol.isLocal()) {
+ atom.sym_index = idx;
+ }
+ }
try wasm_bin.symbol_atom.putNoClobber(gpa, atom.symbolLoc(), atom);
const segment: *Wasm.Segment = &wasm_bin.segments.items[final_index];