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.
17371737 var func_type = try genFunctype(self.gpa, ext_decl.ty.fnInfo(), self.target);
17381738 defer func_type.deinit(self.gpa);
17391739 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 );
17411746 break :blk ext_decl;
17421747 } else if (func_val.castTag(.decl_ref)) |decl_ref| {
17431748 break :blk module.declPtr(decl_ref.data);
......@@ -5107,13 +5112,15 @@ fn callIntrinsic(
51075112 args: []const WValue,
51085113) InnerError!WValue {
51095114 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 };
51135118
51145119 // TODO: have genFunctype accept individual params so we don't,
51155120 // 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, .{
51175124 .param_types = pt_tmp,
51185125 .comptime_params = undefined,
51195126 .return_type = return_type,
......@@ -5122,9 +5129,9 @@ fn callIntrinsic(
51225129 .is_var_args = false,
51235130 .is_generic = false,
51245131 }, self.target);
5125 defer func_type.deinit(self.base.allocator);
5132 defer func_type.deinit(self.gpa);
51265133 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
51295136 const want_sret_param = firstParamSRet(.C, return_type, self.target);
51305137 // 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 {
438438 }
439439 }
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
441459 /// May be called before or after updateDeclExports but must be called
442460 /// after allocateDeclIndexes for any given Decl.
443461 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 {
433433 continue; // Do not overwrite defined symbols with undefined symbols
434434 }
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
436443 // when both symbols are weak, we skip overwriting
437444 if (existing_sym.isWeak() and symbol.isWeak()) {
438445 continue;
......@@ -755,7 +762,7 @@ pub fn lowerUnnamedConst(self: *Wasm, tv: TypedValue, decl_index: Module.Decl.In
755762/// Returns the symbol index from the name of an intrinsic.
756763/// If the symbol does not yet exist, creates a new one symbol instead
757764/// 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 {
759766 const name_index = try self.string_table.put(self.base.allocator, name);
760767 const gop = try self.globals.getOrPut(self.base.allocator, name_index);
761768 if (gop.found_existing) {
......@@ -769,7 +776,7 @@ pub fn getIntrinsicSymbol(self: *Wasm, name: []const u8) !u64 {
769776 .tag = .function,
770777 };
771778 symbol.setGlobal(true);
772 symbol.setFlag(.WASM_SYM_UNDEFINED);
779 symbol.setUndefined(true);
773780
774781 const sym_index = if (self.symbols_free_list.popOrNull()) |index| index else blk: {
775782 var index = @intCast(u32, self.symbols.items.len);
......@@ -779,7 +786,7 @@ pub fn getIntrinsicSymbol(self: *Wasm, name: []const u8) !u64 {
779786 };
780787 self.symbols.items[sym_index] = symbol;
781788 gop.value_ptr.* = .{ .index = sym_index, .file = null };
782
789 try self.resolved_symbols.put(self.base.allocator, gop.value_ptr.*, {});
783790 return sym_index;
784791}
785792
......@@ -982,10 +989,24 @@ fn mapFunctionTable(self: *Wasm) void {
982989 }
983990}
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 {
9861008 // 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);
9891010 const symbol: *Symbol = &self.symbols.items[symbol_index];
9901011 symbol.setUndefined(true);
9911012 symbol.setGlobal(true);
......@@ -996,22 +1017,19 @@ pub fn addOrUpdateImport(self: *Wasm, decl: *Module.Decl) !void {
9961017 try self.resolved_symbols.put(self.base.allocator, loc, {});
9971018 }
9981019
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");
10151033}
10161034
10171035const Kind = union(enum) {
......@@ -1251,7 +1269,7 @@ fn mergeSections(self: *Wasm) !void {
12511269 symbol.index = @intCast(u32, self.tables.items.len) + self.imported_tables_count;
12521270 try self.tables.append(self.base.allocator, original_table);
12531271 },
1254 else => {},
1272 else => unreachable,
12551273 }
12561274 }
12571275
src/link/Wasm/Atom.zig+4-1
......@@ -171,7 +171,10 @@ fn relocationValue(self: Atom, relocation: types.Relocation, wasm_bin: *const Wa
171171 }
172172 std.debug.assert(symbol.tag == .data);
173173 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);
175178 const atom_index = wasm_bin.data_segments.get(segment_name).?;
176179 const target_atom = wasm_bin.symbol_atom.get(target_loc).?;
177180 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 {
302302 }
303303
304304 fn parseObject(self: *Self, gpa: Allocator, is_object_file: *bool) Error!void {
305 errdefer self.object.deinit(gpa);
305306 try self.verifyMagicBytes();
306307 const version = try self.reader.reader().readIntLittle(u32);
307308
308309 self.object.version = version;
309310 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
312316 var section_index: u32 = 0;
313317 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
808812 kind: Symbol.Tag,
809813 index: u32,
810814 };
811 var symbol_for_segment = std.AutoArrayHashMap(Key, u32).init(gpa);
815 var symbol_for_segment = std.AutoArrayHashMap(Key, std.ArrayList(u32)).init(gpa);
812816 defer symbol_for_segment.deinit();
813817
814818 for (self.symtable) |symbol, symbol_index| {
815819 switch (symbol.tag) {
816820 .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);
821827 },
822828 else => continue,
823829 }
824830 }
825831
826832 for (self.relocatable_data) |relocatable_data, index| {
827 const sym_index = symbol_for_segment.get(.{
833 const symbols = symbol_for_segment.getPtr(.{
828834 .kind = relocatable_data.getSymbolKind(),
829835 .index = @intCast(u32, relocatable_data.index),
830836 }) orelse continue; // encountered a segment we do not create an atom for
837 const sym_index = symbols.pop();
831838 const final_index = try wasm_bin.getMatchingSegment(object_index, @intCast(u32, index));
832839
833840 const atom = try gpa.create(Atom);
......@@ -862,6 +869,16 @@ pub fn parseIntoAtoms(self: *Object, gpa: Allocator, object_index: u16, wasm_bin
862869 }
863870
864871 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 }
865882 try wasm_bin.symbol_atom.putNoClobber(gpa, atom.symbolLoc(), atom);
866883
867884 const segment: *Wasm.Segment = &wasm_bin.segments.items[final_index];