authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-05-21 20:44:01+02:00
committergravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-06-24 08:12:17+02:00
log8d03e4fc6b361e6cf96865acc05820556ae33863
tree1f6d431c2f2aef13df992f3d571f6291c66f5e7e
parent359b61aec3494197aaca336dabaa39d0515706ff

link: Implement API to get global symbol index


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 };
51135118
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);
51285135
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 }
440440
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 called459 /// 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 symbols433 continue; // Do not overwrite defined symbols with undefined symbols
434 }434 }
435435
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 overwriting443 // 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 instead763/// 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.
758pub fn getIntrinsicSymbol(self: *Wasm, name: []const u8) !u64 {765pub 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);
773780
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 };
782789 try self.resolved_symbols.put(self.base.allocator, gop.value_ptr.*, {});
783 return sym_index;790 return sym_index;
784}791}
785792
...@@ -982,10 +989,24 @@ fn mapFunctionTable(self: *Wasm) void {...@@ -982,10 +989,24 @@ fn mapFunctionTable(self: *Wasm) void {
982 }989 }
983}990}
984991
985pub 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.
995pub 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 name1008 // 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 }
9981019
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}
10161034
1017const Kind = union(enum) {1035const 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 }
12571275
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 }
303303
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);
307308
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();
311315
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();
813817
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 }
825831
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 for836 }) 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));
832839
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 }
863870
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);
866883
867 const segment: *Wasm.Segment = &wasm_bin.segments.items[final_index];884 const segment: *Wasm.Segment = &wasm_bin.segments.items[final_index];