authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-02-27 21:15:33+01:00
committergravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-03-01 08:35:20+01:00
logb1159ab7aecfe704adcb4cf44d6fedafd572a720
tree7ddafb8b9c72922f22cc6c03987b72e9006df300
parent49f01c0a0cd510437f6f2d13d5de3e722f48cc3d

wasm-linker: Intern all symbol names

For all symbols read from object files as well as generated from Zig code will now be interned and have their offset into the string table saved on the `Symbol` instead. Besides interning, local symbols now also use a decl's fully qualified name. When a decl/symbol is extern/to-be-imported, the name of the decl itself will be used for symbol resolving. Similarly for symbols that will be exported, will have their 'export name' set.

4 files changed, 144 insertions(+), 62 deletions(-)

src/link/Wasm.zig+113-36
......@@ -79,6 +79,8 @@ data_segments: std.StringArrayHashMapUnmanaged(u32) = .{},
7979/// A list of `types.Segment` which provide meta data
8080/// about a data symbol such as its name
8181segment_info: std.ArrayListUnmanaged(types.Segment) = .{},
82/// Deduplicated string table for strings used by symbols, imports and exports.
83string_table: StringTable = .{},
8284
8385// Output sections
8486/// Output type section
......@@ -155,6 +157,79 @@ pub const SymbolLoc = struct {
155157 }
156158 return &wasm_bin.symbols.items[self.index];
157159 }
160
161 /// From a given location, returns the name of the symbol.
162 pub fn getName(self: SymbolLoc, wasm_bin: *const Wasm) []const u8 {
163 if (wasm_bin.discarded.get(self)) |new_loc| {
164 return new_loc.getName(wasm_bin);
165 }
166 if (self.file) |object_index| {
167 const object = wasm_bin.objects.items[object_index];
168 return object.string_table.get(object.symtable[self.index].name);
169 }
170 return wasm_bin.string_table.get(wasm_bin.symbols.items[self.index].name);
171 }
172};
173
174/// Generic string table that duplicates strings
175/// and converts them into offsets instead.
176pub const StringTable = struct {
177 /// Table that maps string offsets, which is used to de-duplicate strings.
178 /// Rather than having the offset map to the data, the `StringContext` holds all bytes of the string.
179 /// The strings are stored as a contigious array where each string is zero-terminated.
180 string_table: std.HashMapUnmanaged(
181 u32,
182 void,
183 std.hash_map.StringIndexContext,
184 std.hash_map.default_max_load_percentage,
185 ) = .{},
186 /// Holds the actual data of the string table.
187 string_data: std.ArrayListUnmanaged(u8) = .{},
188
189 /// Accepts a string and searches for a corresponding string.
190 /// When found, de-duplicates the string and returns the existing offset instead.
191 /// When the string is not found in the `string_table`, a new entry will be inserted
192 /// and the new offset to its data will be returned.
193 pub fn put(self: *StringTable, allocator: Allocator, string: []const u8) !u32 {
194 const gop = try self.string_table.getOrPutContextAdapted(
195 allocator,
196 string,
197 std.hash_map.StringIndexAdapter{ .bytes = &self.string_data },
198 .{ .bytes = &self.string_data },
199 );
200 if (gop.found_existing) {
201 const off = gop.key_ptr.*;
202 log.debug("reusing string '{s}' at offset 0x{x}", .{ string, off });
203 return off;
204 }
205
206 try self.string_data.ensureUnusedCapacity(allocator, string.len + 1);
207 const offset = @intCast(u32, self.string_data.items.len);
208
209 log.debug("writing new string '{s}' at offset 0x{x}", .{ string, offset });
210
211 self.string_data.appendSliceAssumeCapacity(string);
212 self.string_data.appendAssumeCapacity(0);
213
214 gop.key_ptr.* = offset;
215
216 return offset;
217 }
218
219 /// From a given offset, returns its corresponding string value.
220 /// Asserts offset does not exceed bounds.
221 pub fn get(self: StringTable, off: u32) []const u8 {
222 assert(off < self.string_data.items.len);
223 return mem.sliceTo(@ptrCast([*:0]const u8, self.string_data.items.ptr + off), 0);
224 }
225
226 /// Frees all resources of the string table. Any references pointing
227 /// to the strings will be invalid.
228 pub fn deinit(self: *StringTable, allocator: Allocator) void {
229 self.string_data.deinit(allocator);
230 self.string_table.deinit(allocator);
231 self.* = undefined;
232 }
158233};
159234
160235pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Options) !*Wasm {
......@@ -177,7 +252,7 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option
177252 // As sym_index '0' is reserved, we use it for our stack pointer symbol
178253 const symbol = try wasm_bin.symbols.addOne(allocator);
179254 symbol.* = .{
180 .name = "__stack_pointer",
255 .name = try wasm_bin.string_table.put(allocator, "__stack_pointer"),
181256 .tag = .global,
182257 .flags = 0,
183258 .index = 0,
......@@ -268,12 +343,12 @@ fn resolveSymbolsInObject(self: *Wasm, object_index: u16) !void {
268343 .file = object_index,
269344 .index = sym_index,
270345 };
271 const sym_name = std.mem.sliceTo(symbol.name, 0);
346 const sym_name = object.string_table.get(symbol.name);
272347
273348 if (symbol.isLocal()) {
274349 if (symbol.isUndefined()) {
275350 log.err("Local symbols are not allowed to reference imports", .{});
276 log.err(" symbol '{s}' defined in '{s}'", .{ symbol.name, object.name });
351 log.err(" symbol '{s}' defined in '{s}'", .{ sym_name, object.name });
277352 return error.undefinedLocal;
278353 }
279354 try self.resolved_symbols.putNoClobber(self.base.allocator, location, {});
......@@ -299,7 +374,7 @@ fn resolveSymbolsInObject(self: *Wasm, object_index: u16) !void {
299374
300375 if (!existing_sym.isUndefined()) {
301376 if (!symbol.isUndefined()) {
302 log.err("symbol '{s}' defined multiple times", .{existing_sym.name});
377 log.err("symbol '{s}' defined multiple times", .{sym_name});
303378 log.err(" first definition in '{s}'", .{existing_file_path});
304379 log.err(" next definition in '{s}'", .{object.name});
305380 return error.SymbolCollision;
......@@ -309,7 +384,7 @@ fn resolveSymbolsInObject(self: *Wasm, object_index: u16) !void {
309384 }
310385
311386 // simply overwrite with the new symbol
312 log.debug("Overwriting symbol '{s}'", .{symbol.name});
387 log.debug("Overwriting symbol '{s}'", .{sym_name});
313388 log.debug(" old definition in '{s}'", .{existing_file_path});
314389 log.debug(" new definition in '{s}'", .{object.name});
315390 try self.discarded.putNoClobber(self.base.allocator, maybe_existing.value_ptr.*, location);
......@@ -328,12 +403,7 @@ pub fn deinit(self: *Wasm) void {
328403
329404 var decl_it = self.decls.keyIterator();
330405 while (decl_it.next()) |decl_ptr| {
331 const decl = decl_ptr.*;
332 const atom: *Atom = &decl.link.wasm;
333 for (atom.locals.items) |local| {
334 gpa.free(mem.sliceTo(self.symbols.items[local.sym_index].name, 0));
335 }
336 decl.link.wasm.deinit(gpa);
406 decl_ptr.*.link.wasm.deinit(gpa);
337407 }
338408
339409 for (self.func_types.items) |*func_type| {
......@@ -374,6 +444,8 @@ pub fn deinit(self: *Wasm) void {
374444 self.function_table.deinit(gpa);
375445 self.tables.deinit(gpa);
376446 self.exports.deinit(gpa);
447
448 self.string_table.deinit(gpa);
377449}
378450
379451pub fn allocateDeclIndexes(self: *Wasm, decl: *Module.Decl) !void {
......@@ -498,7 +570,10 @@ fn finishUpdateDecl(self: *Wasm, decl: *Module.Decl, code: []const u8) !void {
498570 atom.size = @intCast(u32, code.len);
499571 atom.alignment = decl.ty.abiAlignment(self.base.options.target);
500572 const symbol = &self.symbols.items[atom.sym_index];
501 symbol.name = decl.name;
573
574 const full_name = try decl.getFullyQualifiedName(self.base.allocator);
575 defer self.base.allocator.free(full_name);
576 symbol.name = try self.string_table.put(self.base.allocator, full_name);
502577 try atom.code.appendSlice(self.base.allocator, code);
503578}
504579
......@@ -511,8 +586,9 @@ pub fn lowerUnnamedConst(self: *Wasm, decl: *Module.Decl, tv: TypedValue) !u32 {
511586 // Create and initialize a new local symbol and atom
512587 const local_index = decl.link.wasm.locals.items.len;
513588 const name = try std.fmt.allocPrintZ(self.base.allocator, "__unnamed_{s}_{d}", .{ decl.name, local_index });
589 defer self.base.allocator.free(name);
514590 var symbol: Symbol = .{
515 .name = name,
591 .name = try self.string_table.put(self.base.allocator, name),
516592 .flags = 0,
517593 .tag = .data,
518594 .index = undefined,
......@@ -615,7 +691,7 @@ pub fn deleteExport(self: *Wasm, exp: Export) void {
615691 const sym_index = exp.sym_index orelse return;
616692 const loc: SymbolLoc = .{ .file = null, .index = sym_index };
617693 const symbol = loc.getSymbol(self);
618 const symbol_name = mem.sliceTo(symbol.name, 0);
694 const symbol_name = self.string_table.get(symbol.name);
619695 log.debug("Deleting export for decl '{s}'", .{symbol_name});
620696 if (self.export_names.fetchRemove(loc)) |kv| {
621697 assert(self.globals.remove(kv.value));
......@@ -656,7 +732,7 @@ pub fn updateDeclExports(
656732 // are strong symbols, we have a linker error.
657733 // In the other case we replace one with the other.
658734 if (!exp_is_weak and !existing_sym.isWeak()) {
659 try module.failed_exports.putNoClobber(module.gpa, exp, try Module.ErrorMsg.create(
735 try module.failed_exports.put(module.gpa, exp, try Module.ErrorMsg.create(
660736 module.gpa,
661737 decl.srcLoc(),
662738 \\LinkError: symbol '{s}' defined multiple times
......@@ -665,6 +741,7 @@ pub fn updateDeclExports(
665741 ,
666742 .{ exp.options.name, self.name, self.name },
667743 ));
744 continue;
668745 } else if (exp_is_weak) {
669746 continue; // to-be-exported symbol is weak, so we keep the existing symbol
670747 } else {
......@@ -697,7 +774,7 @@ pub fn updateDeclExports(
697774 },
698775 }
699776 // Ensure the symbol will be exported using the given name
700 if (!mem.eql(u8, exp.options.name, mem.sliceTo(exp.exported_decl.name, 0))) {
777 if (!mem.eql(u8, exp.options.name, sym_loc.getName(self))) {
701778 try self.export_names.put(self.base.allocator, sym_loc, exp.options.name);
702779 }
703780
......@@ -725,7 +802,6 @@ pub fn freeDecl(self: *Wasm, decl: *Module.Decl) void {
725802 for (atom.locals.items) |local_atom| {
726803 const local_symbol = &self.symbols.items[local_atom.sym_index];
727804 local_symbol.tag = .dead; // also for any local symbol
728 self.base.allocator.free(mem.sliceTo(local_symbol.name, 0));
729805 self.symbols_free_list.append(self.base.allocator, local_atom.sym_index) catch {};
730806 assert(self.resolved_symbols.swapRemove(local_atom.symbolLoc()));
731807 }
......@@ -755,14 +831,15 @@ fn mapFunctionTable(self: *Wasm) void {
755831}
756832
757833fn addOrUpdateImport(self: *Wasm, decl: *Module.Decl) !void {
834 // For the import name itself, we use the decl's name, rather than the fully qualified name
835 const decl_name = mem.sliceTo(decl.name, 0);
758836 const symbol_index = decl.link.wasm.sym_index;
759837 const symbol: *Symbol = &self.symbols.items[symbol_index];
760 symbol.name = decl.name;
761838 symbol.setUndefined(true);
762839 symbol.setGlobal(true);
763840 try self.globals.putNoClobber(
764841 self.base.allocator,
765 mem.sliceTo(symbol.name, 0),
842 decl_name,
766843 .{ .file = null, .index = symbol_index },
767844 );
768845 try self.resolved_symbols.put(self.base.allocator, .{ .file = null, .index = symbol_index }, {});
......@@ -776,7 +853,7 @@ fn addOrUpdateImport(self: *Wasm, decl: *Module.Decl) !void {
776853 if (!gop.found_existing) {
777854 gop.value_ptr.* = .{
778855 .module_name = module_name,
779 .name = mem.sliceTo(symbol.name, 0),
856 .name = decl_name,
780857 .kind = .{ .function = decl.fn_link.wasm.type_index },
781858 };
782859 }
......@@ -815,7 +892,7 @@ fn parseAtom(self: *Wasm, atom: *Atom, kind: Kind) !void {
815892 // TODO: Add mutables global decls to .bss section instead
816893 const segment_name = try std.mem.concat(self.base.allocator, u8, &.{
817894 ".rodata.",
818 std.mem.span(symbol.name),
895 self.string_table.get(symbol.name),
819896 });
820897 errdefer self.base.allocator.free(segment_name);
821898 const segment_info: types.Segment = .{
......@@ -886,7 +963,7 @@ fn allocateAtoms(self: *Wasm) !void {
886963 atom.offset = offset;
887964 const symbol_loc = atom.symbolLoc();
888965 log.debug("Atom '{s}' allocated from 0x{x:0>8} to 0x{x:0>8} size={d}", .{
889 symbol_loc.getSymbol(self).name,
966 symbol_loc.getName(self),
890967 offset,
891968 offset + atom.size,
892969 atom.size,
......@@ -906,7 +983,7 @@ fn setupImports(self: *Wasm) !void {
906983 // remove an import if it was resolved
907984 if (self.imports.remove(discarded.*)) {
908985 log.debug("Removed symbol '{s}' as an import", .{
909 discarded.getSymbol(self).name,
986 discarded.getName(self),
910987 });
911988 }
912989 }
......@@ -923,7 +1000,7 @@ fn setupImports(self: *Wasm) !void {
9231000 continue;
9241001 }
9251002
926 log.debug("Symbol '{s}' will be imported from the host", .{symbol.name});
1003 log.debug("Symbol '{s}' will be imported from the host", .{symbol_loc.getName(self)});
9271004 const import = self.objects.items[symbol_loc.file.?].findImport(symbol.tag.externalType(), symbol.index);
9281005 // TODO: De-duplicate imports
9291006 try self.imports.putNoClobber(self.base.allocator, symbol_loc, import);
......@@ -1036,12 +1113,12 @@ fn mergeTypes(self: *Wasm) !void {
10361113 }
10371114
10381115 if (symbol.isUndefined()) {
1039 log.debug("Adding type from extern function '{s}'", .{symbol.name});
1116 log.debug("Adding type from extern function '{s}'", .{sym_loc.getName(self)});
10401117 const import: *wasm.Import = self.imports.getPtr(sym_loc).?;
10411118 const original_type = object.func_types[import.kind.function];
10421119 import.kind.function = try self.putOrGetFuncType(original_type);
10431120 } else {
1044 log.debug("Adding type from function '{s}'", .{symbol.name});
1121 log.debug("Adding type from function '{s}'", .{sym_loc.getName(self)});
10451122 const func = &self.functions.items[symbol.index - self.imported_functions_count];
10461123 func.type_index = try self.putOrGetFuncType(object.func_types[func.type_index]);
10471124 }
......@@ -1057,13 +1134,14 @@ fn setupExports(self: *Wasm) !void {
10571134 const symbol = sym_loc.getSymbol(self);
10581135 if (!symbol.isExported()) continue;
10591136
1060 const export_name = if (self.export_names.get(sym_loc)) |name| name else mem.sliceTo(symbol.name, 0);
1137 const sym_name = sym_loc.getName(self);
1138 const export_name = if (self.export_names.get(sym_loc)) |name| name else sym_name;
10611139 const exp: wasm.Export = .{
10621140 .name = export_name,
10631141 .kind = symbol.tag.externalType(),
10641142 .index = symbol.index,
10651143 };
1066 log.debug("Exporting symbol '{s}' as '{s}' at index: ({d})", .{ symbol.name, exp.name, exp.index });
1144 log.debug("Exporting symbol '{s}' as '{s}' at index: ({d})", .{ sym_name, exp.name, exp.index });
10671145 try self.exports.append(self.base.allocator, exp);
10681146 }
10691147
......@@ -1670,8 +1748,8 @@ fn emitNameSection(self: *Wasm, file: fs.File, arena: Allocator) !void {
16701748 for (self.resolved_symbols.keys()) |sym_loc| {
16711749 const symbol = sym_loc.getSymbol(self).*;
16721750 switch (symbol.tag) {
1673 .function => funcs.appendAssumeCapacity(.{ .index = symbol.index, .name = mem.sliceTo(symbol.name, 0) }),
1674 .global => globals.appendAssumeCapacity(.{ .index = symbol.index, .name = mem.sliceTo(symbol.name, 0) }),
1751 .function => funcs.appendAssumeCapacity(.{ .index = symbol.index, .name = sym_loc.getName(self) }),
1752 .global => globals.appendAssumeCapacity(.{ .index = symbol.index, .name = sym_loc.getName(self) }),
16751753 else => {},
16761754 }
16771755 }
......@@ -2275,11 +2353,11 @@ fn emitSymbolTable(self: *Wasm, file: fs.File, arena: Allocator, symbol_table: *
22752353 try leb.writeULEB128(writer, @enumToInt(symbol.tag));
22762354 try leb.writeULEB128(writer, symbol.flags);
22772355
2356 const sym_name = if (self.export_names.get(sym_loc)) |exp_name| exp_name else sym_loc.getName(self);
22782357 switch (symbol.tag) {
22792358 .data => {
2280 const name = mem.sliceTo(symbol.name, 0);
2281 try leb.writeULEB128(writer, @intCast(u32, name.len));
2282 try writer.writeAll(name);
2359 try leb.writeULEB128(writer, @intCast(u32, sym_name.len));
2360 try writer.writeAll(sym_name);
22832361
22842362 if (symbol.isDefined()) {
22852363 try leb.writeULEB128(writer, symbol.index);
......@@ -2294,9 +2372,8 @@ fn emitSymbolTable(self: *Wasm, file: fs.File, arena: Allocator, symbol_table: *
22942372 else => {
22952373 try leb.writeULEB128(writer, symbol.index);
22962374 if (symbol.isDefined()) {
2297 const name = mem.sliceTo(symbol.name, 0);
2298 try leb.writeULEB128(writer, @intCast(u32, name.len));
2299 try writer.writeAll(name);
2375 try leb.writeULEB128(writer, @intCast(u32, sym_name.len));
2376 try writer.writeAll(sym_name);
23002377 }
23012378 },
23022379 }
src/link/Wasm/Atom.zig+4-4
......@@ -103,17 +103,17 @@ pub fn symbolLoc(self: Atom) Wasm.SymbolLoc {
103103/// at the calculated offset.
104104pub fn resolveRelocs(self: *Atom, wasm_bin: *const Wasm) !void {
105105 if (self.relocs.items.len == 0) return;
106 const symbol = self.symbolLoc().getSymbol(wasm_bin).*;
106 const symbol_name = self.symbolLoc().getName(wasm_bin);
107107 log.debug("Resolving relocs in atom '{s}' count({d})", .{
108 symbol.name,
108 symbol_name,
109109 self.relocs.items.len,
110110 });
111111
112112 for (self.relocs.items) |reloc| {
113113 const value = try self.relocationValue(reloc, wasm_bin);
114114 log.debug("Relocating '{s}' referenced in '{s}' offset=0x{x:0>8} value={d}", .{
115 (Wasm.SymbolLoc{ .file = self.file, .index = reloc.index }).getSymbol(wasm_bin).name,
116 symbol.name,
115 (Wasm.SymbolLoc{ .file = self.file, .index = reloc.index }).getName(wasm_bin),
116 symbol_name,
117117 reloc.offset,
118118 value,
119119 });
src/link/Wasm/Object.zig+16-14
......@@ -59,6 +59,10 @@ comdat_info: []const types.Comdat = &.{},
5959/// Represents non-synthetic sections that can essentially be mem-cpy'd into place
6060/// after performing relocations.
6161relocatable_data: []const RelocatableData = &.{},
62/// String table for all strings required by the object file, such as symbol names,
63/// import name, module name and export names. Each string will be deduplicated
64/// and returns an offset into the table.
65string_table: Wasm.StringTable = .{},
6266
6367/// Represents a single item within a section (depending on its `type`)
6468const RelocatableData = struct {
......@@ -142,9 +146,6 @@ pub fn deinit(self: *Object, gpa: Allocator) void {
142146 gpa.free(val);
143147 }
144148 self.relocations.deinit(gpa);
145 for (self.symtable) |symbol| {
146 gpa.free(std.mem.sliceTo(symbol.name, 0));
147 }
148149 gpa.free(self.symtable);
149150 gpa.free(self.comdat_info);
150151 gpa.free(self.init_funcs);
......@@ -156,6 +157,7 @@ pub fn deinit(self: *Object, gpa: Allocator) void {
156157 gpa.free(rel_data.data[0..rel_data.size]);
157158 }
158159 gpa.free(self.relocatable_data);
160 self.string_table.deinit(gpa);
159161 self.* = undefined;
160162}
161163
......@@ -228,7 +230,7 @@ fn checkLegacyIndirectFunctionTable(self: *Object, gpa: Allocator) !?Symbol {
228230
229231 var table_symbol: Symbol = .{
230232 .flags = 0,
231 .name = try gpa.dupeZ(u8, table_import.name),
233 .name = try self.string_table.put(gpa, table_import.name),
232234 .tag = .table,
233235 .index = 0,
234236 };
......@@ -666,7 +668,7 @@ fn Parser(comptime ReaderType: type) type {
666668 symbol.* = try self.parseSymbol(gpa, reader);
667669 log.debug("Found symbol: type({s}) name({s}) flags(0b{b:0>8})", .{
668670 @tagName(symbol.tag),
669 symbol.name,
671 self.object.string_table.get(symbol.name),
670672 symbol.flags,
671673 });
672674 }
......@@ -699,10 +701,10 @@ fn Parser(comptime ReaderType: type) type {
699701 switch (tag) {
700702 .data => {
701703 const name_len = try leb.readULEB128(u32, reader);
702 const name = try gpa.allocSentinel(u8, name_len, 0);
703 errdefer gpa.free(name);
704 const name = try gpa.alloc(u8, name_len);
705 defer gpa.free(name);
704706 try reader.readNoEof(name);
705 symbol.name = name;
707 symbol.name = try self.object.string_table.put(gpa, name);
706708
707709 // Data symbols only have the following fields if the symbol is defined
708710 if (symbol.isDefined()) {
......@@ -714,7 +716,7 @@ fn Parser(comptime ReaderType: type) type {
714716 },
715717 .section => {
716718 symbol.index = try leb.readULEB128(u32, reader);
717 symbol.name = @tagName(symbol.tag);
719 symbol.name = try self.object.string_table.put(gpa, @tagName(symbol.tag));
718720 },
719721 else => {
720722 symbol.index = try leb.readULEB128(u32, reader);
......@@ -727,12 +729,12 @@ fn Parser(comptime ReaderType: type) type {
727729 const explicit_name = symbol.hasFlag(.WASM_SYM_EXPLICIT_NAME);
728730 if (!(is_undefined and !explicit_name)) {
729731 const name_len = try leb.readULEB128(u32, reader);
730 const name = try gpa.allocSentinel(u8, name_len, 0);
731 errdefer gpa.free(name);
732 const name = try gpa.alloc(u8, name_len);
733 defer gpa.free(name);
732734 try reader.readNoEof(name);
733 symbol.name = name;
735 symbol.name = try self.object.string_table.put(gpa, name);
734736 } else {
735 symbol.name = try gpa.dupeZ(u8, maybe_import.?.name);
737 symbol.name = try self.object.string_table.put(gpa, maybe_import.?.name);
736738 }
737739 },
738740 }
......@@ -882,7 +884,7 @@ pub fn parseIntoAtoms(self: *Object, gpa: Allocator, object_index: u16, wasm_bin
882884 } else {
883885 try wasm_bin.atoms.putNoClobber(gpa, final_index, atom);
884886 }
885 log.debug("Parsed into atom: '{s}'", .{self.symtable[atom.sym_index].name});
887 log.debug("Parsed into atom: '{s}'", .{self.string_table.get(self.symtable[atom.sym_index].name)});
886888 }
887889}
888890
src/link/Wasm/Symbol.zig+11-8
......@@ -1,5 +1,8 @@
1//! Wasm symbols describing its kind,
2//! name and its properties.
1//! Represents a wasm symbol. Containing all of its properties,
2//! as well as providing helper methods to determine its functionality
3//! and how it will/must be linked.
4//! The name of the symbol can be found by providing the offset, found
5//! on the `name` field, to a string table in the wasm binary or object file.
36const Symbol = @This();
47
58const std = @import("std");
......@@ -8,15 +11,15 @@ const types = @import("types.zig");
811/// Bitfield containings flags for a symbol
912/// Can contain any of the flags defined in `Flag`
1013flags: u32,
11/// Symbol name, when undefined this will be taken from the import.
12name: [*:0]const u8,
13/// An union that represents both the type of symbol
14/// as well as the data it holds.
15tag: Tag,
14/// Symbol name, when the symbol is undefined the name will be taken from the import.
15/// Note: This is an index into the string table.
16name: u32,
1617/// Index into the list of objects based on set `tag`
1718/// NOTE: This will be set to `undefined` when `tag` is `data`
1819/// and the symbol is undefined.
1920index: u32,
21/// Represents the kind of the symbol, such as a function or global.
22tag: Tag,
2023
2124pub const Tag = enum {
2225 function,
......@@ -164,7 +167,7 @@ pub fn format(self: Symbol, comptime fmt: []const u8, options: std.fmt.FormatOpt
164167 const binding: []const u8 = if (self.isLocal()) "local" else "global";
165168
166169 try writer.print(
167 "{c} binding={s} visible={s} id={d} name={s}",
170 "{c} binding={s} visible={s} id={d} name_offset={d}",
168171 .{ kind_fmt, binding, visible, self.index, self.name },
169172 );
170173}