authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-10-31 21:56:10-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-10-31 22:01:10-07:00
loge501cf51a01f6f0ae4326180cdd4274588ceed1d
tree172175693b81ce2b14609fb9d6347487bdc3b926
parentbf9978a57a9d939aefb3babcca28f87cb34331b0

link.File.Wasm: unify the string tables

Before, the wasm struct had a string table, the ZigObject had a string table, and each Object had a string table. Now there is just the one. This makes for more efficient use of memory and simplifies logic, particularly with regards to linker state serialization. This commit additionally adds significantly more integer type safety.

5 files changed, 433 insertions(+), 460 deletions(-)

src/link/Wasm.zig+374-386
...@@ -36,11 +36,16 @@ const Value = @import("../Value.zig");...@@ -36,11 +36,16 @@ const Value = @import("../Value.zig");
36const ZigObject = @import("Wasm/ZigObject.zig");36const ZigObject = @import("Wasm/ZigObject.zig");
3737
38base: link.File,38base: link.File,
39/// Null-terminated strings, indexes have type String and string_table provides
40/// lookup.
41string_bytes: std.ArrayListUnmanaged(u8),
42/// Omitted when serializing linker state.
43string_table: String.Table,
39/// Symbol name of the entry function to export44/// Symbol name of the entry function to export
40entry_name: ?[]const u8,45entry_name: OptionalString,
41/// When true, will allow undefined symbols46/// When true, will allow undefined symbols
42import_symbols: bool,47import_symbols: bool,
43/// List of *global* symbol names to export to the host environment.48/// Set of *global* symbol names to export to the host environment.
44export_symbol_names: []const []const u8,49export_symbol_names: []const []const u8,
45/// When defined, sets the start of the data section.50/// When defined, sets the start of the data section.
46global_base: ?u64,51global_base: ?u64,
...@@ -63,32 +68,14 @@ objects: std.ArrayListUnmanaged(Object) = .{},...@@ -63,32 +68,14 @@ objects: std.ArrayListUnmanaged(Object) = .{},
63/// LLVM uses "env" by default when none is given. This would be a good default for Zig68/// LLVM uses "env" by default when none is given. This would be a good default for Zig
64/// to support existing code.69/// to support existing code.
65/// TODO: Allow setting this through a flag?70/// TODO: Allow setting this through a flag?
66host_name: []const u8 = "env",71host_name: String,
67/// List of symbols generated by the linker.72/// List of symbols generated by the linker.
68synthetic_symbols: std.ArrayListUnmanaged(Symbol) = .empty,73synthetic_symbols: std.ArrayListUnmanaged(Symbol) = .empty,
69/// Maps atoms to their segment index74/// Maps atoms to their segment index
70atoms: std.AutoHashMapUnmanaged(u32, Atom.Index) = .empty,75atoms: std.AutoHashMapUnmanaged(Segment.Index, Atom.Index) = .empty,
71/// List of all atoms.76/// List of all atoms.
72managed_atoms: std.ArrayListUnmanaged(Atom) = .empty,77managed_atoms: std.ArrayListUnmanaged(Atom) = .empty,
73/// Represents the index into `segments` where the 'code' section78
74/// lives.
75code_section_index: ?u32 = null,
76/// The index of the segment representing the custom '.debug_info' section.
77debug_info_index: ?u32 = null,
78/// The index of the segment representing the custom '.debug_line' section.
79debug_line_index: ?u32 = null,
80/// The index of the segment representing the custom '.debug_loc' section.
81debug_loc_index: ?u32 = null,
82/// The index of the segment representing the custom '.debug_ranges' section.
83debug_ranges_index: ?u32 = null,
84/// The index of the segment representing the custom '.debug_pubnames' section.
85debug_pubnames_index: ?u32 = null,
86/// The index of the segment representing the custom '.debug_pubtypes' section.
87debug_pubtypes_index: ?u32 = null,
88/// The index of the segment representing the custom '.debug_pubtypes' section.
89debug_str_index: ?u32 = null,
90/// The index of the segment representing the custom '.debug_pubtypes' section.
91debug_abbrev_index: ?u32 = null,
92/// The count of imported functions. This number will be appended79/// The count of imported functions. This number will be appended
93/// to the function indexes as their index starts at the lowest non-extern function.80/// to the function indexes as their index starts at the lowest non-extern function.
94imported_functions_count: u32 = 0,81imported_functions_count: u32 = 0,
...@@ -104,13 +91,11 @@ imports: std.AutoHashMapUnmanaged(SymbolLoc, Import) = .empty,...@@ -104,13 +91,11 @@ imports: std.AutoHashMapUnmanaged(SymbolLoc, Import) = .empty,
104/// Used for code, data and custom sections.91/// Used for code, data and custom sections.
105segments: std.ArrayListUnmanaged(Segment) = .empty,92segments: std.ArrayListUnmanaged(Segment) = .empty,
106/// Maps a data segment key (such as .rodata) to the index into `segments`.93/// Maps a data segment key (such as .rodata) to the index into `segments`.
107data_segments: std.StringArrayHashMapUnmanaged(u32) = .empty,94data_segments: std.StringArrayHashMapUnmanaged(Segment.Index) = .empty,
108/// A table of `NamedSegment` which provide meta data95/// A table of `NamedSegment` which provide meta data
109/// about a data symbol such as its name where the key is96/// about a data symbol such as its name where the key is
110/// the segment index, which can be found from `data_segments`97/// the segment index, which can be found from `data_segments`
111segment_info: std.AutoArrayHashMapUnmanaged(u32, NamedSegment) = .empty,98segment_info: std.AutoArrayHashMapUnmanaged(Segment.Index, NamedSegment) = .empty,
112/// Deduplicated string table for strings used by symbols, imports and exports.
113string_table: StringTable = .{},
11499
115// Output sections100// Output sections
116/// Output type section101/// Output type section
...@@ -158,8 +143,8 @@ function_table: std.AutoHashMapUnmanaged(SymbolLoc, u32) = .empty,...@@ -158,8 +143,8 @@ function_table: std.AutoHashMapUnmanaged(SymbolLoc, u32) = .empty,
158/// e.g. when an undefined symbol references a symbol from the archive.143/// e.g. when an undefined symbol references a symbol from the archive.
159lazy_archives: std.ArrayListUnmanaged(LazyArchive) = .empty,144lazy_archives: std.ArrayListUnmanaged(LazyArchive) = .empty,
160145
161/// A map of global names (read: offset into string table) to their symbol location146/// A map of global names to their symbol location
162globals: std.AutoHashMapUnmanaged(u32, SymbolLoc) = .empty,147globals: std.AutoArrayHashMapUnmanaged(String, SymbolLoc) = .empty,
163/// The list of GOT symbols and their location148/// The list of GOT symbols and their location
164got_symbols: std.ArrayListUnmanaged(SymbolLoc) = .empty,149got_symbols: std.ArrayListUnmanaged(SymbolLoc) = .empty,
165/// Maps discarded symbols and their positions to the location of the symbol150/// Maps discarded symbols and their positions to the location of the symbol
...@@ -169,8 +154,7 @@ discarded: std.AutoHashMapUnmanaged(SymbolLoc, SymbolLoc) = .empty,...@@ -169,8 +154,7 @@ discarded: std.AutoHashMapUnmanaged(SymbolLoc, SymbolLoc) = .empty,
169/// into the final binary.154/// into the final binary.
170resolved_symbols: std.AutoArrayHashMapUnmanaged(SymbolLoc, void) = .empty,155resolved_symbols: std.AutoArrayHashMapUnmanaged(SymbolLoc, void) = .empty,
171/// Symbols that remain undefined after symbol resolution.156/// Symbols that remain undefined after symbol resolution.
172/// Note: The key represents an offset into the string table, rather than the actual string.157undefs: std.AutoArrayHashMapUnmanaged(String, SymbolLoc) = .empty,
173undefs: std.AutoArrayHashMapUnmanaged(u32, SymbolLoc) = .empty,
174/// Maps a symbol's location to an atom. This can be used to find meta158/// Maps a symbol's location to an atom. This can be used to find meta
175/// data of a symbol, such as its size, or its offset to perform a relocation.159/// data of a symbol, such as its size, or its offset to perform a relocation.
176/// Undefined (and synthetic) symbols do not have an Atom and therefore cannot be mapped.160/// Undefined (and synthetic) symbols do not have an Atom and therefore cannot be mapped.
...@@ -178,8 +162,103 @@ symbol_atom: std.AutoHashMapUnmanaged(SymbolLoc, Atom.Index) = .empty,...@@ -178,8 +162,103 @@ symbol_atom: std.AutoHashMapUnmanaged(SymbolLoc, Atom.Index) = .empty,
178162
179/// `--verbose-link` output.163/// `--verbose-link` output.
180/// Initialized on creation, appended to as inputs are added, printed during `flush`.164/// Initialized on creation, appended to as inputs are added, printed during `flush`.
165/// String data is allocated into Compilation arena.
181dump_argv_list: std.ArrayListUnmanaged([]const u8),166dump_argv_list: std.ArrayListUnmanaged([]const u8),
182167
168/// Represents the index into `segments` where the 'code' section lives.
169code_section_index: Segment.OptionalIndex = .none,
170custom_sections: CustomSections,
171preloaded_strings: PreloadedStrings,
172
173/// Type reflection is used on the field names to autopopulate each field
174/// during initialization.
175const PreloadedStrings = struct {
176 __heap_base: String,
177 __heap_end: String,
178 __indirect_function_table: String,
179 __linear_memory: String,
180 __stack_pointer: String,
181 __tls_align: String,
182 __tls_base: String,
183 __tls_size: String,
184 __wasm_apply_global_tls_relocs: String,
185 __wasm_call_ctors: String,
186 __wasm_init_memory: String,
187 __wasm_init_memory_flag: String,
188 __wasm_init_tls: String,
189 __zig_err_name_table: String,
190 __zig_err_names: String,
191 __zig_errors_len: String,
192 _initialize: String,
193 _start: String,
194 memory: String,
195};
196
197/// Type reflection is used on the field names to autopopulate each inner `name` field.
198const CustomSections = struct {
199 @".debug_info": CustomSection,
200 @".debug_pubtypes": CustomSection,
201 @".debug_abbrev": CustomSection,
202 @".debug_line": CustomSection,
203 @".debug_str": CustomSection,
204 @".debug_pubnames": CustomSection,
205 @".debug_loc": CustomSection,
206 @".debug_ranges": CustomSection,
207};
208
209const CustomSection = struct {
210 name: String,
211 index: Segment.OptionalIndex,
212};
213
214/// Index into string_bytes
215pub const String = enum(u32) {
216 _,
217
218 const Table = std.HashMapUnmanaged(String, void, TableContext, std.hash_map.default_max_load_percentage);
219
220 const TableContext = struct {
221 bytes: []const u8,
222
223 pub fn eql(_: @This(), a: String, b: String) bool {
224 return a == b;
225 }
226
227 pub fn hash(ctx: @This(), key: String) u64 {
228 return std.hash_map.hashString(mem.sliceTo(ctx.bytes[@intFromEnum(key)..], 0));
229 }
230 };
231
232 const TableIndexAdapter = struct {
233 bytes: []const u8,
234
235 pub fn eql(ctx: @This(), a: []const u8, b: String) bool {
236 return mem.eql(u8, a, mem.sliceTo(ctx.bytes[@intFromEnum(b)..], 0));
237 }
238
239 pub fn hash(_: @This(), adapted_key: []const u8) u64 {
240 assert(mem.indexOfScalar(u8, adapted_key, 0) == null);
241 return std.hash_map.hashString(adapted_key);
242 }
243 };
244
245 pub fn toOptional(i: String) OptionalString {
246 const result: OptionalString = @enumFromInt(@intFromEnum(i));
247 assert(result != .none);
248 return result;
249 }
250};
251
252pub const OptionalString = enum(u32) {
253 none = std.math.maxInt(u32),
254 _,
255
256 pub fn unwrap(i: OptionalString) ?String {
257 if (i == .none) return null;
258 return @enumFromInt(@intFromEnum(i));
259 }
260};
261
183/// Index into objects array or the zig object.262/// Index into objects array or the zig object.
184pub const ObjectId = enum(u16) {263pub const ObjectId = enum(u16) {
185 zig_object = std.math.maxInt(u16) - 1,264 zig_object = std.math.maxInt(u16) - 1,
...@@ -222,6 +301,26 @@ pub const Segment = struct {...@@ -222,6 +301,26 @@ pub const Segment = struct {
222 offset: u32,301 offset: u32,
223 flags: u32,302 flags: u32,
224303
304 const Index = enum(u32) {
305 _,
306
307 pub fn toOptional(i: Index) OptionalIndex {
308 const result: OptionalIndex = @enumFromInt(@intFromEnum(i));
309 assert(result != .none);
310 return result;
311 }
312 };
313
314 const OptionalIndex = enum(u32) {
315 none = std.math.maxInt(u32),
316 _,
317
318 pub fn unwrap(i: OptionalIndex) ?Index {
319 if (i == .none) return null;
320 return @enumFromInt(@intFromEnum(i));
321 }
322 };
323
225 pub const Flag = enum(u32) {324 pub const Flag = enum(u32) {
226 WASM_DATA_SEGMENT_IS_PASSIVE = 0x01,325 WASM_DATA_SEGMENT_IS_PASSIVE = 0x01,
227 WASM_DATA_SEGMENT_HAS_MEMINDEX = 0x02,326 WASM_DATA_SEGMENT_HAS_MEMINDEX = 0x02,
...@@ -260,26 +359,8 @@ pub fn symbolLocSymbol(wasm: *const Wasm, loc: SymbolLoc) *Symbol {...@@ -260,26 +359,8 @@ pub fn symbolLocSymbol(wasm: *const Wasm, loc: SymbolLoc) *Symbol {
260}359}
261360
262/// From a given location, returns the name of the symbol.361/// From a given location, returns the name of the symbol.
263pub fn symbolLocName(wasm: *const Wasm, loc: SymbolLoc) []const u8 {362pub fn symbolLocName(wasm: *const Wasm, loc: SymbolLoc) [:0]const u8 {
264 if (wasm.discarded.get(loc)) |new_loc| {363 return wasm.stringSlice(wasm.symbolLocSymbol(loc).name);
265 return wasm.symbolLocName(new_loc);
266 }
267 switch (loc.file) {
268 .none => {
269 const sym = wasm.synthetic_symbols.items[@intFromEnum(loc.index)];
270 return wasm.string_table.get(sym.name);
271 },
272 .zig_object => {
273 const zo = wasm.zig_object.?;
274 const sym = zo.symbols.items[@intFromEnum(loc.index)];
275 return zo.string_table.get(sym.name).?;
276 },
277 _ => {
278 const obj = &wasm.objects.items[@intFromEnum(loc.file)];
279 const sym = obj.symtable[@intFromEnum(loc.index)];
280 return obj.string_table.get(sym.name);
281 },
282 }
283}364}
284365
285/// From a given symbol location, returns the final location.366/// From a given symbol location, returns the final location.
...@@ -325,75 +406,6 @@ pub const InitFuncLoc = struct {...@@ -325,75 +406,6 @@ pub const InitFuncLoc = struct {
325 return lhs.priority < rhs.priority;406 return lhs.priority < rhs.priority;
326 }407 }
327};408};
328/// Generic string table that duplicates strings
329/// and converts them into offsets instead.
330pub const StringTable = struct {
331 /// Table that maps string offsets, which is used to de-duplicate strings.
332 /// Rather than having the offset map to the data, the `StringContext` holds all bytes of the string.
333 /// The strings are stored as a contigious array where each string is zero-terminated.
334 string_table: std.HashMapUnmanaged(
335 u32,
336 void,
337 std.hash_map.StringIndexContext,
338 std.hash_map.default_max_load_percentage,
339 ) = .{},
340 /// Holds the actual data of the string table.
341 string_data: std.ArrayListUnmanaged(u8) = .empty,
342
343 /// Accepts a string and searches for a corresponding string.
344 /// When found, de-duplicates the string and returns the existing offset instead.
345 /// When the string is not found in the `string_table`, a new entry will be inserted
346 /// and the new offset to its data will be returned.
347 pub fn put(table: *StringTable, allocator: Allocator, string: []const u8) !u32 {
348 const gop = try table.string_table.getOrPutContextAdapted(
349 allocator,
350 string,
351 std.hash_map.StringIndexAdapter{ .bytes = &table.string_data },
352 .{ .bytes = &table.string_data },
353 );
354 if (gop.found_existing) {
355 const off = gop.key_ptr.*;
356 log.debug("reusing string '{s}' at offset 0x{x}", .{ string, off });
357 return off;
358 }
359
360 try table.string_data.ensureUnusedCapacity(allocator, string.len + 1);
361 const offset: u32 = @intCast(table.string_data.items.len);
362
363 log.debug("writing new string '{s}' at offset 0x{x}", .{ string, offset });
364
365 table.string_data.appendSliceAssumeCapacity(string);
366 table.string_data.appendAssumeCapacity(0);
367
368 gop.key_ptr.* = offset;
369
370 return offset;
371 }
372
373 /// From a given offset, returns its corresponding string value.
374 /// Asserts offset does not exceed bounds.
375 pub fn get(table: StringTable, off: u32) []const u8 {
376 assert(off < table.string_data.items.len);
377 return mem.sliceTo(@as([*:0]const u8, @ptrCast(table.string_data.items.ptr + off)), 0);
378 }
379
380 /// Returns the offset of a given string when it exists.
381 /// Will return null if the given string does not yet exist within the string table.
382 pub fn getOffset(table: *StringTable, string: []const u8) ?u32 {
383 return table.string_table.getKeyAdapted(
384 string,
385 std.hash_map.StringIndexAdapter{ .bytes = &table.string_data },
386 );
387 }
388
389 /// Frees all resources of the string table. Any references pointing
390 /// to the strings will be invalid.
391 pub fn deinit(table: *StringTable, allocator: Allocator) void {
392 table.string_data.deinit(allocator);
393 table.string_table.deinit(allocator);
394 table.* = undefined;
395 }
396};
397409
398pub fn open(410pub fn open(
399 arena: Allocator,411 arena: Allocator,
...@@ -451,6 +463,8 @@ pub fn createEmpty(...@@ -451,6 +463,8 @@ pub fn createEmpty(
451 .build_id = options.build_id,463 .build_id = options.build_id,
452 },464 },
453 .name = undefined,465 .name = undefined,
466 .string_table = .empty,
467 .string_bytes = .empty,
454 .import_table = options.import_table,468 .import_table = options.import_table,
455 .export_table = options.export_table,469 .export_table = options.export_table,
456 .import_symbols = options.import_symbols,470 .import_symbols = options.import_symbols,
...@@ -459,20 +473,38 @@ pub fn createEmpty(...@@ -459,20 +473,38 @@ pub fn createEmpty(
459 .initial_memory = options.initial_memory,473 .initial_memory = options.initial_memory,
460 .max_memory = options.max_memory,474 .max_memory = options.max_memory,
461475
462 .entry_name = switch (options.entry) {476 .entry_name = undefined,
463 .disabled => null,
464 .default => if (output_mode != .Exe) null else defaultEntrySymbolName(wasi_exec_model),
465 .enabled => defaultEntrySymbolName(wasi_exec_model),
466 .named => |name| name,
467 },
468 .zig_object = null,477 .zig_object = null,
469 .dump_argv_list = .empty,478 .dump_argv_list = .empty,
479 .host_name = undefined,
480 .custom_sections = undefined,
481 .preloaded_strings = undefined,
470 };482 };
471 if (use_llvm and comp.config.have_zcu) {483 if (use_llvm and comp.config.have_zcu) {
472 wasm.llvm_object = try LlvmObject.create(arena, comp);484 wasm.llvm_object = try LlvmObject.create(arena, comp);
473 }485 }
474 errdefer wasm.base.destroy();486 errdefer wasm.base.destroy();
475487
488 wasm.host_name = try wasm.internString("env");
489
490 inline for (@typeInfo(CustomSections).@"struct".fields) |field| {
491 @field(wasm.custom_sections, field.name) = .{
492 .index = .none,
493 .name = try wasm.internString(field.name),
494 };
495 }
496
497 inline for (@typeInfo(PreloadedStrings).@"struct".fields) |field| {
498 @field(wasm.preloaded_strings, field.name) = try wasm.internString(field.name);
499 }
500
501 wasm.entry_name = switch (options.entry) {
502 .disabled => .none,
503 .default => if (output_mode != .Exe) .none else defaultEntrySymbolName(&wasm.preloaded_strings, wasi_exec_model).toOptional(),
504 .enabled => defaultEntrySymbolName(&wasm.preloaded_strings, wasi_exec_model).toOptional(),
505 .named => |name| (try wasm.internString(name)).toOptional(),
506 };
507
476 if (use_lld and (use_llvm or !comp.config.have_zcu)) {508 if (use_lld and (use_llvm or !comp.config.have_zcu)) {
477 // LLVM emits the object file (if any); LLD links it into the final product.509 // LLVM emits the object file (if any); LLD links it into the final product.
478 return wasm;510 return wasm;
...@@ -498,22 +530,18 @@ pub fn createEmpty(...@@ -498,22 +530,18 @@ pub fn createEmpty(
498530
499 // create stack pointer symbol531 // create stack pointer symbol
500 {532 {
501 const loc = try wasm.createSyntheticSymbol("__stack_pointer", .global);533 const loc = try wasm.createSyntheticSymbol(wasm.preloaded_strings.__stack_pointer, .global);
502 const symbol = wasm.symbolLocSymbol(loc);534 const symbol = wasm.symbolLocSymbol(loc);
503 // For object files we will import the stack pointer symbol535 // For object files we will import the stack pointer symbol
504 if (output_mode == .Obj) {536 if (output_mode == .Obj) {
505 symbol.setUndefined(true);537 symbol.setUndefined(true);
506 symbol.index = @intCast(wasm.imported_globals_count);538 symbol.index = @intCast(wasm.imported_globals_count);
507 wasm.imported_globals_count += 1;539 wasm.imported_globals_count += 1;
508 try wasm.imports.putNoClobber(540 try wasm.imports.putNoClobber(gpa, loc, .{
509 gpa,541 .module_name = wasm.host_name,
510 loc,542 .name = symbol.name,
511 .{543 .kind = .{ .global = .{ .valtype = .i32, .mutable = true } },
512 .module_name = try wasm.string_table.put(gpa, wasm.host_name),544 });
513 .name = symbol.name,
514 .kind = .{ .global = .{ .valtype = .i32, .mutable = true } },
515 },
516 );
517 } else {545 } else {
518 symbol.index = @intCast(wasm.imported_globals_count + wasm.wasm_globals.items.len);546 symbol.index = @intCast(wasm.imported_globals_count + wasm.wasm_globals.items.len);
519 symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);547 symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);
...@@ -530,7 +558,7 @@ pub fn createEmpty(...@@ -530,7 +558,7 @@ pub fn createEmpty(
530558
531 // create indirect function pointer symbol559 // create indirect function pointer symbol
532 {560 {
533 const loc = try wasm.createSyntheticSymbol("__indirect_function_table", .table);561 const loc = try wasm.createSyntheticSymbol(wasm.preloaded_strings.__indirect_function_table, .table);
534 const symbol = wasm.symbolLocSymbol(loc);562 const symbol = wasm.symbolLocSymbol(loc);
535 const table: std.wasm.Table = .{563 const table: std.wasm.Table = .{
536 .limits = .{ .flags = 0, .min = 0, .max = undefined }, // will be overwritten during `mapFunctionTable`564 .limits = .{ .flags = 0, .min = 0, .max = undefined }, // will be overwritten during `mapFunctionTable`
...@@ -541,7 +569,7 @@ pub fn createEmpty(...@@ -541,7 +569,7 @@ pub fn createEmpty(
541 symbol.index = @intCast(wasm.imported_tables_count);569 symbol.index = @intCast(wasm.imported_tables_count);
542 wasm.imported_tables_count += 1;570 wasm.imported_tables_count += 1;
543 try wasm.imports.put(gpa, loc, .{571 try wasm.imports.put(gpa, loc, .{
544 .module_name = try wasm.string_table.put(gpa, wasm.host_name),572 .module_name = wasm.host_name,
545 .name = symbol.name,573 .name = symbol.name,
546 .kind = .{ .table = table },574 .kind = .{ .table = table },
547 });575 });
...@@ -558,7 +586,7 @@ pub fn createEmpty(...@@ -558,7 +586,7 @@ pub fn createEmpty(
558586
559 // create __wasm_call_ctors587 // create __wasm_call_ctors
560 {588 {
561 const loc = try wasm.createSyntheticSymbol("__wasm_call_ctors", .function);589 const loc = try wasm.createSyntheticSymbol(wasm.preloaded_strings.__wasm_call_ctors, .function);
562 const symbol = wasm.symbolLocSymbol(loc);590 const symbol = wasm.symbolLocSymbol(loc);
563 symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);591 symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);
564 // we do not know the function index until after we merged all sections.592 // we do not know the function index until after we merged all sections.
...@@ -569,7 +597,7 @@ pub fn createEmpty(...@@ -569,7 +597,7 @@ pub fn createEmpty(
569 // shared-memory symbols for TLS support597 // shared-memory symbols for TLS support
570 if (shared_memory) {598 if (shared_memory) {
571 {599 {
572 const loc = try wasm.createSyntheticSymbol("__tls_base", .global);600 const loc = try wasm.createSyntheticSymbol(wasm.preloaded_strings.__tls_base, .global);
573 const symbol = wasm.symbolLocSymbol(loc);601 const symbol = wasm.symbolLocSymbol(loc);
574 symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);602 symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);
575 symbol.index = @intCast(wasm.imported_globals_count + wasm.wasm_globals.items.len);603 symbol.index = @intCast(wasm.imported_globals_count + wasm.wasm_globals.items.len);
...@@ -580,7 +608,7 @@ pub fn createEmpty(...@@ -580,7 +608,7 @@ pub fn createEmpty(
580 });608 });
581 }609 }
582 {610 {
583 const loc = try wasm.createSyntheticSymbol("__tls_size", .global);611 const loc = try wasm.createSyntheticSymbol(wasm.preloaded_strings.__tls_size, .global);
584 const symbol = wasm.symbolLocSymbol(loc);612 const symbol = wasm.symbolLocSymbol(loc);
585 symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);613 symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);
586 symbol.index = @intCast(wasm.imported_globals_count + wasm.wasm_globals.items.len);614 symbol.index = @intCast(wasm.imported_globals_count + wasm.wasm_globals.items.len);
...@@ -591,7 +619,7 @@ pub fn createEmpty(...@@ -591,7 +619,7 @@ pub fn createEmpty(
591 });619 });
592 }620 }
593 {621 {
594 const loc = try wasm.createSyntheticSymbol("__tls_align", .global);622 const loc = try wasm.createSyntheticSymbol(wasm.preloaded_strings.__tls_align, .global);
595 const symbol = wasm.symbolLocSymbol(loc);623 const symbol = wasm.symbolLocSymbol(loc);
596 symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);624 symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);
597 symbol.index = @intCast(wasm.imported_globals_count + wasm.wasm_globals.items.len);625 symbol.index = @intCast(wasm.imported_globals_count + wasm.wasm_globals.items.len);
...@@ -602,7 +630,7 @@ pub fn createEmpty(...@@ -602,7 +630,7 @@ pub fn createEmpty(
602 });630 });
603 }631 }
604 {632 {
605 const loc = try wasm.createSyntheticSymbol("__wasm_init_tls", .function);633 const loc = try wasm.createSyntheticSymbol(wasm.preloaded_strings.__wasm_init_tls, .function);
606 const symbol = wasm.symbolLocSymbol(loc);634 const symbol = wasm.symbolLocSymbol(loc);
607 symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);635 symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);
608 }636 }
...@@ -655,13 +683,11 @@ pub fn addOrUpdateImport(...@@ -655,13 +683,11 @@ pub fn addOrUpdateImport(
655683
656/// For a given name, creates a new global synthetic symbol.684/// For a given name, creates a new global synthetic symbol.
657/// Leaves index undefined and the default flags (0).685/// Leaves index undefined and the default flags (0).
658fn createSyntheticSymbol(wasm: *Wasm, name: []const u8, tag: Symbol.Tag) !SymbolLoc {686fn createSyntheticSymbol(wasm: *Wasm, name: String, tag: Symbol.Tag) !SymbolLoc {
659 const gpa = wasm.base.comp.gpa;687 return wasm.createSyntheticSymbolOffset(name, tag);
660 const name_offset = try wasm.string_table.put(gpa, name);
661 return wasm.createSyntheticSymbolOffset(name_offset, tag);
662}688}
663689
664fn createSyntheticSymbolOffset(wasm: *Wasm, name_offset: u32, tag: Symbol.Tag) !SymbolLoc {690fn createSyntheticSymbolOffset(wasm: *Wasm, name_offset: String, tag: Symbol.Tag) !SymbolLoc {
665 const sym_index: Symbol.Index = @enumFromInt(wasm.synthetic_symbols.items.len);691 const sym_index: Symbol.Index = @enumFromInt(wasm.synthetic_symbols.items.len);
666 const loc: SymbolLoc = .{ .index = sym_index, .file = .none };692 const loc: SymbolLoc = .{ .index = sym_index, .file = .none };
667 const gpa = wasm.base.comp.gpa;693 const gpa = wasm.base.comp.gpa;
...@@ -803,16 +829,6 @@ fn objectSymbol(wasm: *const Wasm, object_id: ObjectId, index: Symbol.Index) *Sy...@@ -803,16 +829,6 @@ fn objectSymbol(wasm: *const Wasm, object_id: ObjectId, index: Symbol.Index) *Sy
803 return &obj.symtable[@intFromEnum(index)];829 return &obj.symtable[@intFromEnum(index)];
804}830}
805831
806fn objectSymbolName(wasm: *const Wasm, object_id: ObjectId, index: Symbol.Index) []const u8 {
807 const obj = wasm.objectById(object_id) orelse {
808 const zo = wasm.zig_object.?;
809 const sym = zo.symbols.items[@intFromEnum(index)];
810 return zo.string_table.get(sym.name).?;
811 };
812 const sym = obj.symtable[@intFromEnum(index)];
813 return obj.string_table.get(sym.name);
814}
815
816fn objectFunction(wasm: *const Wasm, object_id: ObjectId, sym_index: Symbol.Index) std.wasm.Func {832fn objectFunction(wasm: *const Wasm, object_id: ObjectId, sym_index: Symbol.Index) std.wasm.Func {
817 const obj = wasm.objectById(object_id) orelse {833 const obj = wasm.objectById(object_id) orelse {
818 const zo = wasm.zig_object.?;834 const zo = wasm.zig_object.?;
...@@ -850,13 +866,6 @@ fn objectImport(wasm: *const Wasm, object_id: ObjectId, symbol_index: Symbol.Ind...@@ -850,13 +866,6 @@ fn objectImport(wasm: *const Wasm, object_id: ObjectId, symbol_index: Symbol.Ind
850 return obj.findImport(obj.symtable[@intFromEnum(symbol_index)]);866 return obj.findImport(obj.symtable[@intFromEnum(symbol_index)]);
851}867}
852868
853/// For a given offset, returns its string value.
854/// Asserts string exists in the object string table.
855fn objectString(wasm: *const Wasm, object_id: ObjectId, offset: u32) []const u8 {
856 const obj = wasm.objectById(object_id) orelse return wasm.zig_object.?.string_table.get(offset).?;
857 return obj.string_table.get(offset);
858}
859
860/// Returns the object element pointer, or null if it is the ZigObject.869/// Returns the object element pointer, or null if it is the ZigObject.
861fn objectById(wasm: *const Wasm, object_id: ObjectId) ?*Object {870fn objectById(wasm: *const Wasm, object_id: ObjectId) ?*Object {
862 if (object_id == .zig_object) return null;871 if (object_id == .zig_object) return null;
...@@ -876,27 +885,25 @@ fn resolveSymbolsInObject(wasm: *Wasm, object_id: ObjectId) !void {...@@ -876,27 +885,25 @@ fn resolveSymbolsInObject(wasm: *Wasm, object_id: ObjectId) !void {
876 .file = object_id.toOptional(),885 .file = object_id.toOptional(),
877 .index = sym_index,886 .index = sym_index,
878 };887 };
879 const sym_name = objectString(wasm, object_id, symbol.name);888 if (symbol.name == wasm.preloaded_strings.__indirect_function_table) continue;
880 if (mem.eql(u8, sym_name, "__indirect_function_table")) {
881 continue;
882 }
883 const sym_name_index = try wasm.string_table.put(gpa, sym_name);
884889
885 if (symbol.isLocal()) {890 if (symbol.isLocal()) {
886 if (symbol.isUndefined()) {891 if (symbol.isUndefined()) {
887 diags.addParseError(obj_path, "local symbol '{s}' references import", .{sym_name});892 diags.addParseError(obj_path, "local symbol '{s}' references import", .{
893 wasm.stringSlice(symbol.name),
894 });
888 }895 }
889 try wasm.resolved_symbols.putNoClobber(gpa, location, {});896 try wasm.resolved_symbols.putNoClobber(gpa, location, {});
890 continue;897 continue;
891 }898 }
892899
893 const maybe_existing = try wasm.globals.getOrPut(gpa, sym_name_index);900 const maybe_existing = try wasm.globals.getOrPut(gpa, symbol.name);
894 if (!maybe_existing.found_existing) {901 if (!maybe_existing.found_existing) {
895 maybe_existing.value_ptr.* = location;902 maybe_existing.value_ptr.* = location;
896 try wasm.resolved_symbols.putNoClobber(gpa, location, {});903 try wasm.resolved_symbols.putNoClobber(gpa, location, {});
897904
898 if (symbol.isUndefined()) {905 if (symbol.isUndefined()) {
899 try wasm.undefs.putNoClobber(gpa, sym_name_index, location);906 try wasm.undefs.putNoClobber(gpa, symbol.name, location);
900 }907 }
901 continue;908 continue;
902 }909 }
...@@ -918,7 +925,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, object_id: ObjectId) !void {...@@ -918,7 +925,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, object_id: ObjectId) !void {
918 }925 }
919 // both are defined and weak, we have a symbol collision.926 // both are defined and weak, we have a symbol collision.
920 var err = try diags.addErrorWithNotes(2);927 var err = try diags.addErrorWithNotes(2);
921 try err.addMsg("symbol '{s}' defined multiple times", .{sym_name});928 try err.addMsg("symbol '{s}' defined multiple times", .{wasm.stringSlice(symbol.name)});
922 try err.addNote("first definition in '{'}'", .{existing_file_path});929 try err.addNote("first definition in '{'}'", .{existing_file_path});
923 try err.addNote("next definition in '{'}'", .{obj_path});930 try err.addNote("next definition in '{'}'", .{obj_path});
924 }931 }
...@@ -929,7 +936,9 @@ fn resolveSymbolsInObject(wasm: *Wasm, object_id: ObjectId) !void {...@@ -929,7 +936,9 @@ fn resolveSymbolsInObject(wasm: *Wasm, object_id: ObjectId) !void {
929936
930 if (symbol.tag != existing_sym.tag) {937 if (symbol.tag != existing_sym.tag) {
931 var err = try diags.addErrorWithNotes(2);938 var err = try diags.addErrorWithNotes(2);
932 try err.addMsg("symbol '{s}' mismatching types '{s}' and '{s}'", .{ sym_name, @tagName(symbol.tag), @tagName(existing_sym.tag) });939 try err.addMsg("symbol '{s}' mismatching types '{s}' and '{s}'", .{
940 wasm.stringSlice(symbol.name), @tagName(symbol.tag), @tagName(existing_sym.tag),
941 });
933 try err.addNote("first definition in '{'}'", .{existing_file_path});942 try err.addNote("first definition in '{'}'", .{existing_file_path});
934 try err.addNote("next definition in '{'}'", .{obj_path});943 try err.addNote("next definition in '{'}'", .{obj_path});
935 }944 }
...@@ -937,22 +946,18 @@ fn resolveSymbolsInObject(wasm: *Wasm, object_id: ObjectId) !void {...@@ -937,22 +946,18 @@ fn resolveSymbolsInObject(wasm: *Wasm, object_id: ObjectId) !void {
937 if (existing_sym.isUndefined() and symbol.isUndefined()) {946 if (existing_sym.isUndefined() and symbol.isUndefined()) {
938 // only verify module/import name for function symbols947 // only verify module/import name for function symbols
939 if (symbol.tag == .function) {948 if (symbol.tag == .function) {
940 const existing_name = if (existing_loc.file.unwrap()) |existing_obj_id| blk: {949 const existing_name = if (existing_loc.file.unwrap()) |existing_obj_id|
941 const imp = objectImport(wasm, existing_obj_id, existing_loc.index);950 objectImport(wasm, existing_obj_id, existing_loc.index).module_name
942 break :blk objectString(wasm, existing_obj_id, imp.module_name);951 else
943 } else blk: {952 wasm.imports.get(existing_loc).?.module_name;
944 const name_index = wasm.imports.get(existing_loc).?.module_name;
945 break :blk wasm.string_table.get(name_index);
946 };
947953
948 const imp = objectImport(wasm, object_id, sym_index);954 const module_name = objectImport(wasm, object_id, sym_index).module_name;
949 const module_name = objectString(wasm, object_id, imp.module_name);955 if (existing_name != module_name) {
950 if (!mem.eql(u8, existing_name, module_name)) {
951 var err = try diags.addErrorWithNotes(2);956 var err = try diags.addErrorWithNotes(2);
952 try err.addMsg("symbol '{s}' module name mismatch. Expected '{s}', but found '{s}'", .{957 try err.addMsg("symbol '{s}' module name mismatch. Expected '{s}', but found '{s}'", .{
953 sym_name,958 wasm.stringSlice(symbol.name),
954 existing_name,959 wasm.stringSlice(existing_name),
955 module_name,960 wasm.stringSlice(module_name),
956 });961 });
957 try err.addNote("first definition in '{'}'", .{existing_file_path});962 try err.addNote("first definition in '{'}'", .{existing_file_path});
958 try err.addNote("next definition in '{'}'", .{obj_path});963 try err.addNote("next definition in '{'}'", .{obj_path});
...@@ -969,7 +974,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, object_id: ObjectId) !void {...@@ -969,7 +974,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, object_id: ObjectId) !void {
969 const new_ty = wasm.getGlobalType(location);974 const new_ty = wasm.getGlobalType(location);
970 if (existing_ty.mutable != new_ty.mutable or existing_ty.valtype != new_ty.valtype) {975 if (existing_ty.mutable != new_ty.mutable or existing_ty.valtype != new_ty.valtype) {
971 var err = try diags.addErrorWithNotes(2);976 var err = try diags.addErrorWithNotes(2);
972 try err.addMsg("symbol '{s}' mismatching global types", .{sym_name});977 try err.addMsg("symbol '{s}' mismatching global types", .{wasm.stringSlice(symbol.name)});
973 try err.addNote("first definition in '{'}'", .{existing_file_path});978 try err.addNote("first definition in '{'}'", .{existing_file_path});
974 try err.addNote("next definition in '{'}'", .{obj_path});979 try err.addNote("next definition in '{'}'", .{obj_path});
975 }980 }
...@@ -980,7 +985,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, object_id: ObjectId) !void {...@@ -980,7 +985,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, object_id: ObjectId) !void {
980 const new_ty = wasm.getFunctionSignature(location);985 const new_ty = wasm.getFunctionSignature(location);
981 if (!existing_ty.eql(new_ty)) {986 if (!existing_ty.eql(new_ty)) {
982 var err = try diags.addErrorWithNotes(3);987 var err = try diags.addErrorWithNotes(3);
983 try err.addMsg("symbol '{s}' mismatching function signatures.", .{sym_name});988 try err.addMsg("symbol '{s}' mismatching function signatures.", .{wasm.stringSlice(symbol.name)});
984 try err.addNote("expected signature {}, but found signature {}", .{ existing_ty, new_ty });989 try err.addNote("expected signature {}, but found signature {}", .{ existing_ty, new_ty });
985 try err.addNote("first definition in '{'}'", .{existing_file_path});990 try err.addNote("first definition in '{'}'", .{existing_file_path});
986 try err.addNote("next definition in '{'}'", .{obj_path});991 try err.addNote("next definition in '{'}'", .{obj_path});
...@@ -996,16 +1001,16 @@ fn resolveSymbolsInObject(wasm: *Wasm, object_id: ObjectId) !void {...@@ -996,16 +1001,16 @@ fn resolveSymbolsInObject(wasm: *Wasm, object_id: ObjectId) !void {
996 }1001 }
9971002
998 // simply overwrite with the new symbol1003 // simply overwrite with the new symbol
999 log.debug("Overwriting symbol '{s}'", .{sym_name});1004 log.debug("Overwriting symbol '{s}'", .{wasm.stringSlice(symbol.name)});
1000 log.debug(" old definition in '{'}'", .{existing_file_path});1005 log.debug(" old definition in '{'}'", .{existing_file_path});
1001 log.debug(" new definition in '{'}'", .{obj_path});1006 log.debug(" new definition in '{'}'", .{obj_path});
1002 try wasm.discarded.putNoClobber(gpa, existing_loc, location);1007 try wasm.discarded.putNoClobber(gpa, existing_loc, location);
1003 maybe_existing.value_ptr.* = location;1008 maybe_existing.value_ptr.* = location;
1004 try wasm.globals.put(gpa, sym_name_index, location);1009 try wasm.globals.put(gpa, symbol.name, location);
1005 try wasm.resolved_symbols.put(gpa, location, {});1010 try wasm.resolved_symbols.put(gpa, location, {});
1006 assert(wasm.resolved_symbols.swapRemove(existing_loc));1011 assert(wasm.resolved_symbols.swapRemove(existing_loc));
1007 if (existing_sym.isUndefined()) {1012 if (existing_sym.isUndefined()) {
1008 _ = wasm.undefs.swapRemove(sym_name_index);1013 _ = wasm.undefs.swapRemove(symbol.name);
1009 }1014 }
1010 }1015 }
1011}1016}
...@@ -1021,7 +1026,7 @@ fn resolveSymbolsInArchives(wasm: *Wasm) !void {...@@ -1021,7 +1026,7 @@ fn resolveSymbolsInArchives(wasm: *Wasm) !void {
1021 const sym_name_index = wasm.undefs.keys()[index];1026 const sym_name_index = wasm.undefs.keys()[index];
10221027
1023 for (wasm.lazy_archives.items) |lazy_archive| {1028 for (wasm.lazy_archives.items) |lazy_archive| {
1024 const sym_name = wasm.string_table.get(sym_name_index);1029 const sym_name = wasm.stringSlice(sym_name_index);
1025 log.debug("Detected symbol '{s}' in archive '{'}', parsing objects..", .{1030 log.debug("Detected symbol '{s}' in archive '{'}', parsing objects..", .{
1026 sym_name, lazy_archive.path,1031 sym_name, lazy_archive.path,
1027 });1032 });
...@@ -1066,13 +1071,13 @@ fn setupInitMemoryFunction(wasm: *Wasm) !void {...@@ -1066,13 +1071,13 @@ fn setupInitMemoryFunction(wasm: *Wasm) !void {
1066 if (!wasm.hasPassiveInitializationSegments()) {1071 if (!wasm.hasPassiveInitializationSegments()) {
1067 return;1072 return;
1068 }1073 }
1069 const sym_loc = try wasm.createSyntheticSymbol("__wasm_init_memory", .function);1074 const sym_loc = try wasm.createSyntheticSymbol(wasm.preloaded_strings.__wasm_init_memory, .function);
1070 wasm.symbolLocSymbol(sym_loc).mark();1075 wasm.symbolLocSymbol(sym_loc).mark();
10711076
1072 const flag_address: u32 = if (shared_memory) address: {1077 const flag_address: u32 = if (shared_memory) address: {
1073 // when we have passive initialization segments and shared memory1078 // when we have passive initialization segments and shared memory
1074 // `setupMemory` will create this symbol and set its virtual address.1079 // `setupMemory` will create this symbol and set its virtual address.
1075 const loc = wasm.findGlobalSymbol("__wasm_init_memory_flag").?;1080 const loc = wasm.globals.get(wasm.preloaded_strings.__wasm_init_memory_flag).?;
1076 break :address wasm.symbolLocSymbol(loc).virtual_address;1081 break :address wasm.symbolLocSymbol(loc).virtual_address;
1077 } else 0;1082 } else 0;
10781083
...@@ -1113,31 +1118,30 @@ fn setupInitMemoryFunction(wasm: *Wasm) !void {...@@ -1113,31 +1118,30 @@ fn setupInitMemoryFunction(wasm: *Wasm) !void {
1113 try writer.writeByte(std.wasm.opcode(.end));1118 try writer.writeByte(std.wasm.opcode(.end));
1114 }1119 }
11151120
1116 var it = wasm.data_segments.iterator();1121 for (wasm.data_segments.keys(), wasm.data_segments.values(), 0..) |key, value, segment_index_usize| {
1117 var segment_index: u32 = 0;1122 const segment_index: u32 = @intCast(segment_index_usize);
1118 while (it.next()) |entry| : (segment_index += 1) {1123 const segment = wasm.segmentPtr(value);
1119 const segment: Segment = wasm.segments.items[entry.value_ptr.*];1124 if (segment.needsPassiveInitialization(import_memory, key)) {
1120 if (segment.needsPassiveInitialization(import_memory, entry.key_ptr.*)) {
1121 // For passive BSS segments we can simple issue a memory.fill(0).1125 // For passive BSS segments we can simple issue a memory.fill(0).
1122 // For non-BSS segments we do a memory.init. Both these1126 // For non-BSS segments we do a memory.init. Both these
1123 // instructions take as their first argument the destination1127 // instructions take as their first argument the destination
1124 // address.1128 // address.
1125 try writeI32Const(writer, segment.offset);1129 try writeI32Const(writer, segment.offset);
11261130
1127 if (shared_memory and std.mem.eql(u8, entry.key_ptr.*, ".tdata")) {1131 if (shared_memory and std.mem.eql(u8, key, ".tdata")) {
1128 // When we initialize the TLS segment we also set the `__tls_base`1132 // When we initialize the TLS segment we also set the `__tls_base`
1129 // global. This allows the runtime to use this static copy of the1133 // global. This allows the runtime to use this static copy of the
1130 // TLS data for the first/main thread.1134 // TLS data for the first/main thread.
1131 try writeI32Const(writer, segment.offset);1135 try writeI32Const(writer, segment.offset);
1132 try writer.writeByte(std.wasm.opcode(.global_set));1136 try writer.writeByte(std.wasm.opcode(.global_set));
1133 const loc = wasm.findGlobalSymbol("__tls_base").?;1137 const loc = wasm.globals.get(wasm.preloaded_strings.__tls_base).?;
1134 try leb.writeUleb128(writer, wasm.symbolLocSymbol(loc).index);1138 try leb.writeUleb128(writer, wasm.symbolLocSymbol(loc).index);
1135 }1139 }
11361140
1137 try writeI32Const(writer, 0);1141 try writeI32Const(writer, 0);
1138 try writeI32Const(writer, segment.size);1142 try writeI32Const(writer, segment.size);
1139 try writer.writeByte(std.wasm.opcode(.misc_prefix));1143 try writer.writeByte(std.wasm.opcode(.misc_prefix));
1140 if (std.mem.eql(u8, entry.key_ptr.*, ".bss")) {1144 if (std.mem.eql(u8, key, ".bss")) {
1141 // fill bss segment with zeroes1145 // fill bss segment with zeroes
1142 try leb.writeUleb128(writer, std.wasm.miscOpcode(.memory_fill));1146 try leb.writeUleb128(writer, std.wasm.miscOpcode(.memory_fill));
1143 } else {1147 } else {
...@@ -1187,11 +1191,9 @@ fn setupInitMemoryFunction(wasm: *Wasm) !void {...@@ -1187,11 +1191,9 @@ fn setupInitMemoryFunction(wasm: *Wasm) !void {
1187 try writer.writeByte(std.wasm.opcode(.end)); // end $drop1191 try writer.writeByte(std.wasm.opcode(.end)); // end $drop
1188 }1192 }
11891193
1190 it.reset();1194 for (wasm.data_segments.keys(), wasm.data_segments.values(), 0..) |name, value, segment_index_usize| {
1191 segment_index = 0;1195 const segment_index: u32 = @intCast(segment_index_usize);
1192 while (it.next()) |entry| : (segment_index += 1) {1196 const segment = wasm.segmentPtr(value);
1193 const name = entry.key_ptr.*;
1194 const segment: Segment = wasm.segments.items[entry.value_ptr.*];
1195 if (segment.needsPassiveInitialization(import_memory, name) and1197 if (segment.needsPassiveInitialization(import_memory, name) and
1196 !std.mem.eql(u8, name, ".bss"))1198 !std.mem.eql(u8, name, ".bss"))
1197 {1199 {
...@@ -1211,7 +1213,7 @@ fn setupInitMemoryFunction(wasm: *Wasm) !void {...@@ -1211,7 +1213,7 @@ fn setupInitMemoryFunction(wasm: *Wasm) !void {
1211 try writer.writeByte(std.wasm.opcode(.end));1213 try writer.writeByte(std.wasm.opcode(.end));
12121214
1213 try wasm.createSyntheticFunction(1215 try wasm.createSyntheticFunction(
1214 "__wasm_init_memory",1216 wasm.preloaded_strings.__wasm_init_memory,
1215 std.wasm.Type{ .params = &.{}, .returns = &.{} },1217 std.wasm.Type{ .params = &.{}, .returns = &.{} },
1216 &function_body,1218 &function_body,
1217 );1219 );
...@@ -1230,7 +1232,7 @@ fn setupTLSRelocationsFunction(wasm: *Wasm) !void {...@@ -1230,7 +1232,7 @@ fn setupTLSRelocationsFunction(wasm: *Wasm) !void {
1230 return;1232 return;
1231 }1233 }
12321234
1233 const loc = try wasm.createSyntheticSymbol("__wasm_apply_global_tls_relocs", .function);1235 const loc = try wasm.createSyntheticSymbol(wasm.preloaded_strings.__wasm_apply_global_tls_relocs, .function);
1234 wasm.symbolLocSymbol(loc).mark();1236 wasm.symbolLocSymbol(loc).mark();
1235 var function_body = std.ArrayList(u8).init(gpa);1237 var function_body = std.ArrayList(u8).init(gpa);
1236 defer function_body.deinit();1238 defer function_body.deinit();
...@@ -1244,7 +1246,7 @@ fn setupTLSRelocationsFunction(wasm: *Wasm) !void {...@@ -1244,7 +1246,7 @@ fn setupTLSRelocationsFunction(wasm: *Wasm) !void {
1244 if (sym.tag == .data and sym.isDefined()) {1246 if (sym.tag == .data and sym.isDefined()) {
1245 // get __tls_base1247 // get __tls_base
1246 try writer.writeByte(std.wasm.opcode(.global_get));1248 try writer.writeByte(std.wasm.opcode(.global_get));
1247 try leb.writeUleb128(writer, wasm.symbolLocSymbol(wasm.findGlobalSymbol("__tls_base").?).index);1249 try leb.writeUleb128(writer, wasm.symbolLocSymbol(wasm.globals.get(wasm.preloaded_strings.__tls_base).?).index);
12481250
1249 // add the virtual address of the symbol1251 // add the virtual address of the symbol
1250 try writer.writeByte(std.wasm.opcode(.i32_const));1252 try writer.writeByte(std.wasm.opcode(.i32_const));
...@@ -1260,7 +1262,7 @@ fn setupTLSRelocationsFunction(wasm: *Wasm) !void {...@@ -1260,7 +1262,7 @@ fn setupTLSRelocationsFunction(wasm: *Wasm) !void {
1260 try writer.writeByte(std.wasm.opcode(.end));1262 try writer.writeByte(std.wasm.opcode(.end));
12611263
1262 try wasm.createSyntheticFunction(1264 try wasm.createSyntheticFunction(
1263 "__wasm_apply_global_tls_relocs",1265 wasm.preloaded_strings.__wasm_apply_global_tls_relocs,
1264 std.wasm.Type{ .params = &.{}, .returns = &.{} },1266 std.wasm.Type{ .params = &.{}, .returns = &.{} },
1265 &function_body,1267 &function_body,
1266 );1268 );
...@@ -1422,7 +1424,7 @@ fn resolveLazySymbols(wasm: *Wasm) !void {...@@ -1422,7 +1424,7 @@ fn resolveLazySymbols(wasm: *Wasm) !void {
1422 const gpa = comp.gpa;1424 const gpa = comp.gpa;
1423 const shared_memory = comp.config.shared_memory;1425 const shared_memory = comp.config.shared_memory;
14241426
1425 if (wasm.string_table.getOffset("__heap_base")) |name_offset| {1427 if (wasm.getExistingString("__heap_base")) |name_offset| {
1426 if (wasm.undefs.fetchSwapRemove(name_offset)) |kv| {1428 if (wasm.undefs.fetchSwapRemove(name_offset)) |kv| {
1427 const loc = try wasm.createSyntheticSymbolOffset(name_offset, .data);1429 const loc = try wasm.createSyntheticSymbolOffset(name_offset, .data);
1428 try wasm.discarded.putNoClobber(gpa, kv.value, loc);1430 try wasm.discarded.putNoClobber(gpa, kv.value, loc);
...@@ -1430,7 +1432,7 @@ fn resolveLazySymbols(wasm: *Wasm) !void {...@@ -1430,7 +1432,7 @@ fn resolveLazySymbols(wasm: *Wasm) !void {
1430 }1432 }
1431 }1433 }
14321434
1433 if (wasm.string_table.getOffset("__heap_end")) |name_offset| {1435 if (wasm.getExistingString("__heap_end")) |name_offset| {
1434 if (wasm.undefs.fetchSwapRemove(name_offset)) |kv| {1436 if (wasm.undefs.fetchSwapRemove(name_offset)) |kv| {
1435 const loc = try wasm.createSyntheticSymbolOffset(name_offset, .data);1437 const loc = try wasm.createSyntheticSymbolOffset(name_offset, .data);
1436 try wasm.discarded.putNoClobber(gpa, kv.value, loc);1438 try wasm.discarded.putNoClobber(gpa, kv.value, loc);
...@@ -1439,7 +1441,7 @@ fn resolveLazySymbols(wasm: *Wasm) !void {...@@ -1439,7 +1441,7 @@ fn resolveLazySymbols(wasm: *Wasm) !void {
1439 }1441 }
14401442
1441 if (!shared_memory) {1443 if (!shared_memory) {
1442 if (wasm.string_table.getOffset("__tls_base")) |name_offset| {1444 if (wasm.getExistingString("__tls_base")) |name_offset| {
1443 if (wasm.undefs.fetchSwapRemove(name_offset)) |kv| {1445 if (wasm.undefs.fetchSwapRemove(name_offset)) |kv| {
1444 const loc = try wasm.createSyntheticSymbolOffset(name_offset, .global);1446 const loc = try wasm.createSyntheticSymbolOffset(name_offset, .global);
1445 try wasm.discarded.putNoClobber(gpa, kv.value, loc);1447 try wasm.discarded.putNoClobber(gpa, kv.value, loc);
...@@ -1456,11 +1458,9 @@ fn resolveLazySymbols(wasm: *Wasm) !void {...@@ -1456,11 +1458,9 @@ fn resolveLazySymbols(wasm: *Wasm) !void {
1456 }1458 }
1457}1459}
14581460
1459// Tries to find a global symbol by its name. Returns null when not found,1461pub fn findGlobalSymbol(wasm: *const Wasm, name: []const u8) ?SymbolLoc {
1460/// and its location when it is found.1462 const name_index = wasm.getExistingString(name) orelse return null;
1461pub fn findGlobalSymbol(wasm: *Wasm, name: []const u8) ?SymbolLoc {1463 return wasm.globals.get(name_index);
1462 const offset = wasm.string_table.getOffset(name) orelse return null;
1463 return wasm.globals.get(offset);
1464}1464}
14651465
1466fn checkUndefinedSymbols(wasm: *const Wasm) !void {1466fn checkUndefinedSymbols(wasm: *const Wasm) !void {
...@@ -1516,7 +1516,7 @@ pub fn deinit(wasm: *Wasm) void {...@@ -1516,7 +1516,7 @@ pub fn deinit(wasm: *Wasm) void {
1516 for (wasm.lazy_archives.items) |*lazy_archive| lazy_archive.deinit(gpa);1516 for (wasm.lazy_archives.items) |*lazy_archive| lazy_archive.deinit(gpa);
1517 wasm.lazy_archives.deinit(gpa);1517 wasm.lazy_archives.deinit(gpa);
15181518
1519 if (wasm.findGlobalSymbol("__wasm_init_tls")) |loc| {1519 if (wasm.globals.get(wasm.preloaded_strings.__wasm_init_tls)) |loc| {
1520 const atom = wasm.symbol_atom.get(loc).?;1520 const atom = wasm.symbol_atom.get(loc).?;
1521 wasm.getAtomPtr(atom).deinit(gpa);1521 wasm.getAtomPtr(atom).deinit(gpa);
1522 }1522 }
...@@ -1544,6 +1544,7 @@ pub fn deinit(wasm: *Wasm) void {...@@ -1544,6 +1544,7 @@ pub fn deinit(wasm: *Wasm) void {
1544 wasm.init_funcs.deinit(gpa);1544 wasm.init_funcs.deinit(gpa);
1545 wasm.exports.deinit(gpa);1545 wasm.exports.deinit(gpa);
15461546
1547 wasm.string_bytes.deinit(gpa);
1547 wasm.string_table.deinit(gpa);1548 wasm.string_table.deinit(gpa);
1548 wasm.dump_argv_list.deinit(gpa);1549 wasm.dump_argv_list.deinit(gpa);
1549}1550}
...@@ -1649,7 +1650,8 @@ fn getFunctionSignature(wasm: *const Wasm, loc: SymbolLoc) std.wasm.Type {...@@ -1649,7 +1650,8 @@ fn getFunctionSignature(wasm: *const Wasm, loc: SymbolLoc) std.wasm.Type {
1649/// and then returns the index to it.1650/// and then returns the index to it.
1650pub fn getGlobalSymbol(wasm: *Wasm, name: []const u8, lib_name: ?[]const u8) !Symbol.Index {1651pub fn getGlobalSymbol(wasm: *Wasm, name: []const u8, lib_name: ?[]const u8) !Symbol.Index {
1651 _ = lib_name;1652 _ = lib_name;
1652 return wasm.zig_object.?.getGlobalSymbol(wasm.base.comp.gpa, name);1653 const name_index = try wasm.internString(name);
1654 return wasm.zig_object.?.getGlobalSymbol(wasm.base.comp.gpa, name_index);
1653}1655}
16541656
1655/// For a given `Nav`, find the given symbol index's atom, and create a relocation for the type.1657/// For a given `Nav`, find the given symbol index's atom, and create a relocation for the type.
...@@ -1721,12 +1723,12 @@ fn mapFunctionTable(wasm: *Wasm) void {...@@ -1721,12 +1723,12 @@ fn mapFunctionTable(wasm: *Wasm) void {
1721 }1723 }
17221724
1723 if (wasm.import_table or wasm.base.comp.config.output_mode == .Obj) {1725 if (wasm.import_table or wasm.base.comp.config.output_mode == .Obj) {
1724 const sym_loc = wasm.findGlobalSymbol("__indirect_function_table").?;1726 const sym_loc = wasm.globals.get(wasm.preloaded_strings.__indirect_function_table).?;
1725 const import = wasm.imports.getPtr(sym_loc).?;1727 const import = wasm.imports.getPtr(sym_loc).?;
1726 import.kind.table.limits.min = index - 1; // we start at index 1.1728 import.kind.table.limits.min = index - 1; // we start at index 1.
1727 } else if (index > 1) {1729 } else if (index > 1) {
1728 log.debug("Appending indirect function table", .{});1730 log.debug("Appending indirect function table", .{});
1729 const sym_loc = wasm.findGlobalSymbol("__indirect_function_table").?;1731 const sym_loc = wasm.globals.get(wasm.preloaded_strings.__indirect_function_table).?;
1730 const symbol = wasm.symbolLocSymbol(sym_loc);1732 const symbol = wasm.symbolLocSymbol(sym_loc);
1731 const table = &wasm.tables.items[symbol.index - wasm.imported_tables_count];1733 const table = &wasm.tables.items[symbol.index - wasm.imported_tables_count];
1732 table.limits = .{ .min = index, .max = index, .flags = 0x1 };1734 table.limits = .{ .min = index, .max = index, .flags = 0x1 };
...@@ -1735,7 +1737,7 @@ fn mapFunctionTable(wasm: *Wasm) void {...@@ -1735,7 +1737,7 @@ fn mapFunctionTable(wasm: *Wasm) void {
17351737
1736/// From a given index, append the given `Atom` at the back of the linked list.1738/// From a given index, append the given `Atom` at the back of the linked list.
1737/// Simply inserts it into the map of atoms when it doesn't exist yet.1739/// Simply inserts it into the map of atoms when it doesn't exist yet.
1738pub fn appendAtomAtIndex(wasm: *Wasm, index: u32, atom_index: Atom.Index) !void {1740pub fn appendAtomAtIndex(wasm: *Wasm, index: Segment.Index, atom_index: Atom.Index) !void {
1739 const gpa = wasm.base.comp.gpa;1741 const gpa = wasm.base.comp.gpa;
1740 const atom = wasm.getAtomPtr(atom_index);1742 const atom = wasm.getAtomPtr(atom_index);
1741 if (wasm.atoms.getPtr(index)) |last_index_ptr| {1743 if (wasm.atoms.getPtr(index)) |last_index_ptr| {
...@@ -1752,9 +1754,9 @@ fn allocateAtoms(wasm: *Wasm) !void {...@@ -1752,9 +1754,9 @@ fn allocateAtoms(wasm: *Wasm) !void {
17521754
1753 var it = wasm.atoms.iterator();1755 var it = wasm.atoms.iterator();
1754 while (it.next()) |entry| {1756 while (it.next()) |entry| {
1755 const segment = &wasm.segments.items[entry.key_ptr.*];1757 const segment = wasm.segmentPtr(entry.key_ptr.*);
1756 var atom_index = entry.value_ptr.*;1758 var atom_index = entry.value_ptr.*;
1757 if (entry.key_ptr.* == wasm.code_section_index) {1759 if (entry.key_ptr.toOptional() == wasm.code_section_index) {
1758 // Code section is allocated upon writing as they are required to be ordered1760 // Code section is allocated upon writing as they are required to be ordered
1759 // to synchronise with the function section.1761 // to synchronise with the function section.
1760 continue;1762 continue;
...@@ -1825,7 +1827,7 @@ fn allocateVirtualAddresses(wasm: *Wasm) void {...@@ -1825,7 +1827,7 @@ fn allocateVirtualAddresses(wasm: *Wasm) void {
1825 };1827 };
1826 const segment_name = segment_info[symbol.index].outputName(merge_segment);1828 const segment_name = segment_info[symbol.index].outputName(merge_segment);
1827 const segment_index = wasm.data_segments.get(segment_name).?;1829 const segment_index = wasm.data_segments.get(segment_name).?;
1828 const segment = wasm.segments.items[segment_index];1830 const segment = wasm.segmentPtr(segment_index);
18291831
1830 // TLS symbols have their virtual address set relative to their own TLS segment,1832 // TLS symbols have their virtual address set relative to their own TLS segment,
1831 // rather than the entire Data section.1833 // rather than the entire Data section.
...@@ -1839,7 +1841,7 @@ fn allocateVirtualAddresses(wasm: *Wasm) void {...@@ -1839,7 +1841,7 @@ fn allocateVirtualAddresses(wasm: *Wasm) void {
18391841
1840fn sortDataSegments(wasm: *Wasm) !void {1842fn sortDataSegments(wasm: *Wasm) !void {
1841 const gpa = wasm.base.comp.gpa;1843 const gpa = wasm.base.comp.gpa;
1842 var new_mapping: std.StringArrayHashMapUnmanaged(u32) = .empty;1844 var new_mapping: std.StringArrayHashMapUnmanaged(Segment.Index) = .empty;
1843 try new_mapping.ensureUnusedCapacity(gpa, wasm.data_segments.count());1845 try new_mapping.ensureUnusedCapacity(gpa, wasm.data_segments.count());
1844 errdefer new_mapping.deinit(gpa);1846 errdefer new_mapping.deinit(gpa);
18451847
...@@ -1894,9 +1896,9 @@ fn setupInitFunctions(wasm: *Wasm) !void {...@@ -1894,9 +1896,9 @@ fn setupInitFunctions(wasm: *Wasm) !void {
1894 };1896 };
1895 if (ty.params.len != 0) {1897 if (ty.params.len != 0) {
1896 var err = try diags.addErrorWithNotes(0);1898 var err = try diags.addErrorWithNotes(0);
1897 try err.addMsg("constructor functions cannot take arguments: '{s}'", .{object.string_table.get(symbol.name)});1899 try err.addMsg("constructor functions cannot take arguments: '{s}'", .{wasm.stringSlice(symbol.name)});
1898 }1900 }
1899 log.debug("appended init func '{s}'\n", .{object.string_table.get(symbol.name)});1901 log.debug("appended init func '{s}'\n", .{wasm.stringSlice(symbol.name)});
1900 wasm.init_funcs.appendAssumeCapacity(.{1902 wasm.init_funcs.appendAssumeCapacity(.{
1901 .index = @enumFromInt(init_func.symbol_index),1903 .index = @enumFromInt(init_func.symbol_index),
1902 .file = @enumFromInt(object_index),1904 .file = @enumFromInt(object_index),
...@@ -1913,7 +1915,7 @@ fn setupInitFunctions(wasm: *Wasm) !void {...@@ -1913,7 +1915,7 @@ fn setupInitFunctions(wasm: *Wasm) !void {
1913 mem.sort(InitFuncLoc, wasm.init_funcs.items, {}, InitFuncLoc.lessThan);1915 mem.sort(InitFuncLoc, wasm.init_funcs.items, {}, InitFuncLoc.lessThan);
19141916
1915 if (wasm.init_funcs.items.len > 0) {1917 if (wasm.init_funcs.items.len > 0) {
1916 const loc = wasm.findGlobalSymbol("__wasm_call_ctors").?;1918 const loc = wasm.globals.get(wasm.preloaded_strings.__wasm_call_ctors).?;
1917 try wasm.mark(loc);1919 try wasm.mark(loc);
1918 }1920 }
1919}1921}
...@@ -1927,10 +1929,10 @@ fn setupInitFunctions(wasm: *Wasm) !void {...@@ -1927,10 +1929,10 @@ fn setupInitFunctions(wasm: *Wasm) !void {
1927fn initializeCallCtorsFunction(wasm: *Wasm) !void {1929fn initializeCallCtorsFunction(wasm: *Wasm) !void {
1928 const gpa = wasm.base.comp.gpa;1930 const gpa = wasm.base.comp.gpa;
1929 // No code to emit, so also no ctors to call1931 // No code to emit, so also no ctors to call
1930 if (wasm.code_section_index == null) {1932 if (wasm.code_section_index == .none) {
1931 // Make sure to remove it from the resolved symbols so we do not emit1933 // Make sure to remove it from the resolved symbols so we do not emit
1932 // it within any section. TODO: Remove this once we implement garbage collection.1934 // it within any section. TODO: Remove this once we implement garbage collection.
1933 const loc = wasm.findGlobalSymbol("__wasm_call_ctors").?;1935 const loc = wasm.globals.get(wasm.preloaded_strings.__wasm_call_ctors).?;
1934 assert(wasm.resolved_symbols.swapRemove(loc));1936 assert(wasm.resolved_symbols.swapRemove(loc));
1935 return;1937 return;
1936 }1938 }
...@@ -1965,7 +1967,7 @@ fn initializeCallCtorsFunction(wasm: *Wasm) !void {...@@ -1965,7 +1967,7 @@ fn initializeCallCtorsFunction(wasm: *Wasm) !void {
1965 }1967 }
19661968
1967 try wasm.createSyntheticFunction(1969 try wasm.createSyntheticFunction(
1968 "__wasm_call_ctors",1970 wasm.preloaded_strings.__wasm_call_ctors,
1969 std.wasm.Type{ .params = &.{}, .returns = &.{} },1971 std.wasm.Type{ .params = &.{}, .returns = &.{} },
1970 &function_body,1972 &function_body,
1971 );1973 );
...@@ -1973,12 +1975,12 @@ fn initializeCallCtorsFunction(wasm: *Wasm) !void {...@@ -1973,12 +1975,12 @@ fn initializeCallCtorsFunction(wasm: *Wasm) !void {
19731975
1974fn createSyntheticFunction(1976fn createSyntheticFunction(
1975 wasm: *Wasm,1977 wasm: *Wasm,
1976 symbol_name: []const u8,1978 symbol_name: String,
1977 func_ty: std.wasm.Type,1979 func_ty: std.wasm.Type,
1978 function_body: *std.ArrayList(u8),1980 function_body: *std.ArrayList(u8),
1979) !void {1981) !void {
1980 const gpa = wasm.base.comp.gpa;1982 const gpa = wasm.base.comp.gpa;
1981 const loc = wasm.findGlobalSymbol(symbol_name).?; // forgot to create symbol?1983 const loc = wasm.globals.get(symbol_name).?;
1982 const symbol = wasm.symbolLocSymbol(loc);1984 const symbol = wasm.symbolLocSymbol(loc);
1983 if (symbol.isDead()) {1985 if (symbol.isDead()) {
1984 return;1986 return;
...@@ -1998,7 +2000,7 @@ fn createSyntheticFunction(...@@ -1998,7 +2000,7 @@ fn createSyntheticFunction(
1998 const atom = wasm.getAtomPtr(atom_index);2000 const atom = wasm.getAtomPtr(atom_index);
1999 atom.size = @intCast(function_body.items.len);2001 atom.size = @intCast(function_body.items.len);
2000 atom.code = function_body.moveToUnmanaged();2002 atom.code = function_body.moveToUnmanaged();
2001 try wasm.appendAtomAtIndex(wasm.code_section_index.?, atom_index);2003 try wasm.appendAtomAtIndex(wasm.code_section_index.unwrap().?, atom_index);
2002}2004}
20032005
2004/// Unlike `createSyntheticFunction` this function is to be called by2006/// Unlike `createSyntheticFunction` this function is to be called by
...@@ -2016,7 +2018,7 @@ pub fn createFunction(...@@ -2016,7 +2018,7 @@ pub fn createFunction(
20162018
2017/// If required, sets the function index in the `start` section.2019/// If required, sets the function index in the `start` section.
2018fn setupStartSection(wasm: *Wasm) !void {2020fn setupStartSection(wasm: *Wasm) !void {
2019 if (wasm.findGlobalSymbol("__wasm_init_memory")) |loc| {2021 if (wasm.globals.get(wasm.preloaded_strings.__wasm_init_memory)) |loc| {
2020 wasm.entry = wasm.symbolLocSymbol(loc).index;2022 wasm.entry = wasm.symbolLocSymbol(loc).index;
2021 }2023 }
2022}2024}
...@@ -2029,7 +2031,7 @@ fn initializeTLSFunction(wasm: *Wasm) !void {...@@ -2029,7 +2031,7 @@ fn initializeTLSFunction(wasm: *Wasm) !void {
2029 if (!shared_memory) return;2031 if (!shared_memory) return;
20302032
2031 // ensure function is marked as we must emit it2033 // ensure function is marked as we must emit it
2032 wasm.symbolLocSymbol(wasm.findGlobalSymbol("__wasm_init_tls").?).mark();2034 wasm.symbolLocSymbol(wasm.globals.get(wasm.preloaded_strings.__wasm_init_tls).?).mark();
20332035
2034 var function_body = std.ArrayList(u8).init(gpa);2036 var function_body = std.ArrayList(u8).init(gpa);
2035 defer function_body.deinit();2037 defer function_body.deinit();
...@@ -2041,14 +2043,14 @@ fn initializeTLSFunction(wasm: *Wasm) !void {...@@ -2041,14 +2043,14 @@ fn initializeTLSFunction(wasm: *Wasm) !void {
2041 // If there's a TLS segment, initialize it during runtime using the bulk-memory feature2043 // If there's a TLS segment, initialize it during runtime using the bulk-memory feature
2042 if (wasm.data_segments.getIndex(".tdata")) |data_index| {2044 if (wasm.data_segments.getIndex(".tdata")) |data_index| {
2043 const segment_index = wasm.data_segments.entries.items(.value)[data_index];2045 const segment_index = wasm.data_segments.entries.items(.value)[data_index];
2044 const segment = wasm.segments.items[segment_index];2046 const segment = wasm.segmentPtr(segment_index);
20452047
2046 const param_local: u32 = 0;2048 const param_local: u32 = 0;
20472049
2048 try writer.writeByte(std.wasm.opcode(.local_get));2050 try writer.writeByte(std.wasm.opcode(.local_get));
2049 try leb.writeUleb128(writer, param_local);2051 try leb.writeUleb128(writer, param_local);
20502052
2051 const tls_base_loc = wasm.findGlobalSymbol("__tls_base").?;2053 const tls_base_loc = wasm.globals.get(wasm.preloaded_strings.__tls_base).?;
2052 try writer.writeByte(std.wasm.opcode(.global_set));2054 try writer.writeByte(std.wasm.opcode(.global_set));
2053 try leb.writeUleb128(writer, wasm.symbolLocSymbol(tls_base_loc).index);2055 try leb.writeUleb128(writer, wasm.symbolLocSymbol(tls_base_loc).index);
20542056
...@@ -2076,7 +2078,7 @@ fn initializeTLSFunction(wasm: *Wasm) !void {...@@ -2076,7 +2078,7 @@ fn initializeTLSFunction(wasm: *Wasm) !void {
2076 // If we have to perform any TLS relocations, call the corresponding function2078 // If we have to perform any TLS relocations, call the corresponding function
2077 // which performs all runtime TLS relocations. This is a synthetic function,2079 // which performs all runtime TLS relocations. This is a synthetic function,
2078 // generated by the linker.2080 // generated by the linker.
2079 if (wasm.findGlobalSymbol("__wasm_apply_global_tls_relocs")) |loc| {2081 if (wasm.globals.get(wasm.preloaded_strings.__wasm_apply_global_tls_relocs)) |loc| {
2080 try writer.writeByte(std.wasm.opcode(.call));2082 try writer.writeByte(std.wasm.opcode(.call));
2081 try leb.writeUleb128(writer, wasm.symbolLocSymbol(loc).index);2083 try leb.writeUleb128(writer, wasm.symbolLocSymbol(loc).index);
2082 wasm.symbolLocSymbol(loc).mark();2084 wasm.symbolLocSymbol(loc).mark();
...@@ -2085,7 +2087,7 @@ fn initializeTLSFunction(wasm: *Wasm) !void {...@@ -2085,7 +2087,7 @@ fn initializeTLSFunction(wasm: *Wasm) !void {
2085 try writer.writeByte(std.wasm.opcode(.end));2087 try writer.writeByte(std.wasm.opcode(.end));
20862088
2087 try wasm.createSyntheticFunction(2089 try wasm.createSyntheticFunction(
2088 "__wasm_init_tls",2090 wasm.preloaded_strings.__wasm_init_tls,
2089 std.wasm.Type{ .params = &.{.i32}, .returns = &.{} },2091 std.wasm.Type{ .params = &.{.i32}, .returns = &.{} },
2090 &function_body,2092 &function_body,
2091 );2093 );
...@@ -2101,21 +2103,18 @@ fn setupImports(wasm: *Wasm) !void {...@@ -2101,21 +2103,18 @@ fn setupImports(wasm: *Wasm) !void {
2101 };2103 };
21022104
2103 const symbol = wasm.symbolLocSymbol(symbol_loc);2105 const symbol = wasm.symbolLocSymbol(symbol_loc);
2104 if (symbol.isDead() or2106 if (symbol.isDead()) continue;
2105 !symbol.requiresImport() or2107 if (!symbol.requiresImport()) continue;
2106 std.mem.eql(u8, wasm.symbolLocName(symbol_loc), "__indirect_function_table"))2108 if (symbol.name == wasm.preloaded_strings.__indirect_function_table) continue;
2107 {
2108 continue;
2109 }
21102109
2111 log.debug("Symbol '{s}' will be imported from the host", .{wasm.symbolLocName(symbol_loc)});2110 log.debug("Symbol '{s}' will be imported from the host", .{wasm.stringSlice(symbol.name)});
2112 const import = objectImport(wasm, object_id, symbol_loc.index);2111 const import = objectImport(wasm, object_id, symbol_loc.index);
21132112
2114 // We copy the import to a new import to ensure the names contain references2113 // We copy the import to a new import to ensure the names contain references
2115 // to the internal string table, rather than of the object file.2114 // to the internal string table, rather than of the object file.
2116 const new_imp: Import = .{2115 const new_imp: Import = .{
2117 .module_name = try wasm.string_table.put(gpa, objectString(wasm, object_id, import.module_name)),2116 .module_name = import.module_name,
2118 .name = try wasm.string_table.put(gpa, objectString(wasm, object_id, import.name)),2117 .name = import.name,
2119 .kind = import.kind,2118 .kind = import.kind,
2120 };2119 };
2121 // TODO: De-duplicate imports when they contain the same names and type2120 // TODO: De-duplicate imports when they contain the same names and type
...@@ -2283,7 +2282,8 @@ fn checkExportNames(wasm: *Wasm) !void {...@@ -2283,7 +2282,8 @@ fn checkExportNames(wasm: *Wasm) !void {
2283 var failed_exports = false;2282 var failed_exports = false;
22842283
2285 for (force_exp_names) |exp_name| {2284 for (force_exp_names) |exp_name| {
2286 const loc = wasm.findGlobalSymbol(exp_name) orelse {2285 const exp_name_interned = try wasm.internString(exp_name);
2286 const loc = wasm.globals.get(exp_name_interned) orelse {
2287 var err = try diags.addErrorWithNotes(0);2287 var err = try diags.addErrorWithNotes(0);
2288 try err.addMsg("could not export '{s}', symbol not found", .{exp_name});2288 try err.addMsg("could not export '{s}', symbol not found", .{exp_name});
2289 failed_exports = true;2289 failed_exports = true;
...@@ -2310,11 +2310,6 @@ fn setupExports(wasm: *Wasm) !void {...@@ -2310,11 +2310,6 @@ fn setupExports(wasm: *Wasm) !void {
2310 const symbol = wasm.symbolLocSymbol(sym_loc);2310 const symbol = wasm.symbolLocSymbol(sym_loc);
2311 if (!symbol.isExported(comp.config.rdynamic)) continue;2311 if (!symbol.isExported(comp.config.rdynamic)) continue;
23122312
2313 const sym_name = wasm.symbolLocName(sym_loc);
2314 const export_name = if (sym_loc.file == .none)
2315 symbol.name
2316 else
2317 try wasm.string_table.put(gpa, sym_name);
2318 const exp: Export = if (symbol.tag == .data) exp: {2313 const exp: Export = if (symbol.tag == .data) exp: {
2319 const global_index = @as(u32, @intCast(wasm.imported_globals_count + wasm.wasm_globals.items.len));2314 const global_index = @as(u32, @intCast(wasm.imported_globals_count + wasm.wasm_globals.items.len));
2320 try wasm.wasm_globals.append(gpa, .{2315 try wasm.wasm_globals.append(gpa, .{
...@@ -2322,18 +2317,18 @@ fn setupExports(wasm: *Wasm) !void {...@@ -2322,18 +2317,18 @@ fn setupExports(wasm: *Wasm) !void {
2322 .init = .{ .i32_const = @as(i32, @intCast(symbol.virtual_address)) },2317 .init = .{ .i32_const = @as(i32, @intCast(symbol.virtual_address)) },
2323 });2318 });
2324 break :exp .{2319 break :exp .{
2325 .name = export_name,2320 .name = symbol.name,
2326 .kind = .global,2321 .kind = .global,
2327 .index = global_index,2322 .index = global_index,
2328 };2323 };
2329 } else .{2324 } else .{
2330 .name = export_name,2325 .name = symbol.name,
2331 .kind = symbol.tag.externalType(),2326 .kind = symbol.tag.externalType(),
2332 .index = symbol.index,2327 .index = symbol.index,
2333 };2328 };
2334 log.debug("Exporting symbol '{s}' as '{s}' at index: ({d})", .{2329 log.debug("Exporting symbol '{s}' as '{s}' at index: ({d})", .{
2335 sym_name,2330 wasm.stringSlice(symbol.name),
2336 wasm.string_table.get(exp.name),2331 wasm.stringSlice(exp.name),
2337 exp.index,2332 exp.index,
2338 });2333 });
2339 try wasm.exports.append(gpa, exp);2334 try wasm.exports.append(gpa, exp);
...@@ -2346,20 +2341,18 @@ fn setupStart(wasm: *Wasm) !void {...@@ -2346,20 +2341,18 @@ fn setupStart(wasm: *Wasm) !void {
2346 const comp = wasm.base.comp;2341 const comp = wasm.base.comp;
2347 const diags = &wasm.base.comp.link_diags;2342 const diags = &wasm.base.comp.link_diags;
2348 // do not export entry point if user set none or no default was set.2343 // do not export entry point if user set none or no default was set.
2349 const entry_name = wasm.entry_name orelse return;2344 const entry_name = wasm.entry_name.unwrap() orelse return;
23502345
2351 const symbol_loc = wasm.findGlobalSymbol(entry_name) orelse {2346 const symbol_loc = wasm.globals.get(entry_name) orelse {
2352 var err = try diags.addErrorWithNotes(0);2347 var err = try diags.addErrorWithNotes(1);
2353 try err.addMsg("Entry symbol '{s}' missing, use '-fno-entry' to suppress", .{entry_name});2348 try err.addMsg("entry symbol '{s}' missing", .{wasm.stringSlice(entry_name)});
2354 return error.FlushFailure;2349 try err.addNote("'-fno-entry' suppresses this error", .{});
2350 return error.LinkFailure;
2355 };2351 };
23562352
2357 const symbol = wasm.symbolLocSymbol(symbol_loc);2353 const symbol = wasm.symbolLocSymbol(symbol_loc);
2358 if (symbol.tag != .function) {2354 if (symbol.tag != .function)
2359 var err = try diags.addErrorWithNotes(0);2355 return diags.fail("entry symbol '{s}' is not a function", .{wasm.stringSlice(entry_name)});
2360 try err.addMsg("Entry symbol '{s}' is not a function", .{entry_name});
2361 return error.FlushFailure;
2362 }
23632356
2364 // Ensure the symbol is exported so host environment can access it2357 // Ensure the symbol is exported so host environment can access it
2365 if (comp.config.output_mode != .Obj) {2358 if (comp.config.output_mode != .Obj) {
...@@ -2387,7 +2380,7 @@ fn setupMemory(wasm: *Wasm) !void {...@@ -2387,7 +2380,7 @@ fn setupMemory(wasm: *Wasm) !void {
23872380
2388 const is_obj = comp.config.output_mode == .Obj;2381 const is_obj = comp.config.output_mode == .Obj;
23892382
2390 const stack_ptr = if (wasm.findGlobalSymbol("__stack_pointer")) |loc| index: {2383 const stack_ptr = if (wasm.globals.get(wasm.preloaded_strings.__stack_pointer)) |loc| index: {
2391 const sym = wasm.symbolLocSymbol(loc);2384 const sym = wasm.symbolLocSymbol(loc);
2392 break :index sym.index - wasm.imported_globals_count;2385 break :index sym.index - wasm.imported_globals_count;
2393 } else null;2386 } else null;
...@@ -2404,20 +2397,20 @@ fn setupMemory(wasm: *Wasm) !void {...@@ -2404,20 +2397,20 @@ fn setupMemory(wasm: *Wasm) !void {
2404 var offset: u32 = @as(u32, @intCast(memory_ptr));2397 var offset: u32 = @as(u32, @intCast(memory_ptr));
2405 var data_seg_it = wasm.data_segments.iterator();2398 var data_seg_it = wasm.data_segments.iterator();
2406 while (data_seg_it.next()) |entry| {2399 while (data_seg_it.next()) |entry| {
2407 const segment = &wasm.segments.items[entry.value_ptr.*];2400 const segment = wasm.segmentPtr(entry.value_ptr.*);
2408 memory_ptr = segment.alignment.forward(memory_ptr);2401 memory_ptr = segment.alignment.forward(memory_ptr);
24092402
2410 // set TLS-related symbols2403 // set TLS-related symbols
2411 if (mem.eql(u8, entry.key_ptr.*, ".tdata")) {2404 if (mem.eql(u8, entry.key_ptr.*, ".tdata")) {
2412 if (wasm.findGlobalSymbol("__tls_size")) |loc| {2405 if (wasm.globals.get(wasm.preloaded_strings.__tls_size)) |loc| {
2413 const sym = wasm.symbolLocSymbol(loc);2406 const sym = wasm.symbolLocSymbol(loc);
2414 wasm.wasm_globals.items[sym.index - wasm.imported_globals_count].init.i32_const = @intCast(segment.size);2407 wasm.wasm_globals.items[sym.index - wasm.imported_globals_count].init.i32_const = @intCast(segment.size);
2415 }2408 }
2416 if (wasm.findGlobalSymbol("__tls_align")) |loc| {2409 if (wasm.globals.get(wasm.preloaded_strings.__tls_align)) |loc| {
2417 const sym = wasm.symbolLocSymbol(loc);2410 const sym = wasm.symbolLocSymbol(loc);
2418 wasm.wasm_globals.items[sym.index - wasm.imported_globals_count].init.i32_const = @intCast(segment.alignment.toByteUnits().?);2411 wasm.wasm_globals.items[sym.index - wasm.imported_globals_count].init.i32_const = @intCast(segment.alignment.toByteUnits().?);
2419 }2412 }
2420 if (wasm.findGlobalSymbol("__tls_base")) |loc| {2413 if (wasm.globals.get(wasm.preloaded_strings.__tls_base)) |loc| {
2421 const sym = wasm.symbolLocSymbol(loc);2414 const sym = wasm.symbolLocSymbol(loc);
2422 wasm.wasm_globals.items[sym.index - wasm.imported_globals_count].init.i32_const = if (shared_memory)2415 wasm.wasm_globals.items[sym.index - wasm.imported_globals_count].init.i32_const = if (shared_memory)
2423 @as(i32, 0)2416 @as(i32, 0)
...@@ -2435,7 +2428,7 @@ fn setupMemory(wasm: *Wasm) !void {...@@ -2435,7 +2428,7 @@ fn setupMemory(wasm: *Wasm) !void {
2435 if (shared_memory and wasm.hasPassiveInitializationSegments()) {2428 if (shared_memory and wasm.hasPassiveInitializationSegments()) {
2436 // align to pointer size2429 // align to pointer size
2437 memory_ptr = mem.alignForward(u64, memory_ptr, 4);2430 memory_ptr = mem.alignForward(u64, memory_ptr, 4);
2438 const loc = try wasm.createSyntheticSymbol("__wasm_init_memory_flag", .data);2431 const loc = try wasm.createSyntheticSymbol(wasm.preloaded_strings.__wasm_init_memory_flag, .data);
2439 const sym = wasm.symbolLocSymbol(loc);2432 const sym = wasm.symbolLocSymbol(loc);
2440 sym.mark();2433 sym.mark();
2441 sym.virtual_address = @as(u32, @intCast(memory_ptr));2434 sym.virtual_address = @as(u32, @intCast(memory_ptr));
...@@ -2452,7 +2445,7 @@ fn setupMemory(wasm: *Wasm) !void {...@@ -2452,7 +2445,7 @@ fn setupMemory(wasm: *Wasm) !void {
24522445
2453 // One of the linked object files has a reference to the __heap_base symbol.2446 // One of the linked object files has a reference to the __heap_base symbol.
2454 // We must set its virtual address so it can be used in relocations.2447 // We must set its virtual address so it can be used in relocations.
2455 if (wasm.findGlobalSymbol("__heap_base")) |loc| {2448 if (wasm.globals.get(wasm.preloaded_strings.__heap_base)) |loc| {
2456 const symbol = wasm.symbolLocSymbol(loc);2449 const symbol = wasm.symbolLocSymbol(loc);
2457 symbol.virtual_address = @intCast(heap_alignment.forward(memory_ptr));2450 symbol.virtual_address = @intCast(heap_alignment.forward(memory_ptr));
2458 }2451 }
...@@ -2482,7 +2475,7 @@ fn setupMemory(wasm: *Wasm) !void {...@@ -2482,7 +2475,7 @@ fn setupMemory(wasm: *Wasm) !void {
2482 wasm.memories.limits.min = @as(u32, @intCast(memory_ptr / page_size));2475 wasm.memories.limits.min = @as(u32, @intCast(memory_ptr / page_size));
2483 log.debug("Total memory pages: {d}", .{wasm.memories.limits.min});2476 log.debug("Total memory pages: {d}", .{wasm.memories.limits.min});
24842477
2485 if (wasm.findGlobalSymbol("__heap_end")) |loc| {2478 if (wasm.globals.get(wasm.preloaded_strings.__heap_end)) |loc| {
2486 const symbol = wasm.symbolLocSymbol(loc);2479 const symbol = wasm.symbolLocSymbol(loc);
2487 symbol.virtual_address = @as(u32, @intCast(memory_ptr));2480 symbol.virtual_address = @as(u32, @intCast(memory_ptr));
2488 }2481 }
...@@ -2512,12 +2505,12 @@ fn setupMemory(wasm: *Wasm) !void {...@@ -2512,12 +2505,12 @@ fn setupMemory(wasm: *Wasm) !void {
2512/// From a given object's index and the index of the segment, returns the corresponding2505/// From a given object's index and the index of the segment, returns the corresponding
2513/// index of the segment within the final data section. When the segment does not yet2506/// index of the segment within the final data section. When the segment does not yet
2514/// exist, a new one will be initialized and appended. The new index will be returned in that case.2507/// exist, a new one will be initialized and appended. The new index will be returned in that case.
2515pub fn getMatchingSegment(wasm: *Wasm, object_id: ObjectId, symbol_index: Symbol.Index) !u32 {2508pub fn getMatchingSegment(wasm: *Wasm, object_id: ObjectId, symbol_index: Symbol.Index) !Segment.Index {
2516 const comp = wasm.base.comp;2509 const comp = wasm.base.comp;
2517 const gpa = comp.gpa;2510 const gpa = comp.gpa;
2518 const diags = &wasm.base.comp.link_diags;2511 const diags = &wasm.base.comp.link_diags;
2519 const symbol = objectSymbols(wasm, object_id)[@intFromEnum(symbol_index)];2512 const symbol = objectSymbols(wasm, object_id)[@intFromEnum(symbol_index)];
2520 const index: u32 = @intCast(wasm.segments.items.len);2513 const index: Segment.Index = @enumFromInt(wasm.segments.items.len);
2521 const shared_memory = comp.config.shared_memory;2514 const shared_memory = comp.config.shared_memory;
25222515
2523 switch (symbol.tag) {2516 switch (symbol.tag) {
...@@ -2545,66 +2538,27 @@ pub fn getMatchingSegment(wasm: *Wasm, object_id: ObjectId, symbol_index: Symbol...@@ -2545,66 +2538,27 @@ pub fn getMatchingSegment(wasm: *Wasm, object_id: ObjectId, symbol_index: Symbol
2545 return index;2538 return index;
2546 } else return result.value_ptr.*;2539 } else return result.value_ptr.*;
2547 },2540 },
2548 .function => return wasm.code_section_index orelse blk: {2541 .function => return wasm.code_section_index.unwrap() orelse blk: {
2549 wasm.code_section_index = index;2542 wasm.code_section_index = index.toOptional();
2550 try wasm.appendDummySegment();2543 try wasm.appendDummySegment();
2551 break :blk index;2544 break :blk index;
2552 },2545 },
2553 .section => {2546 .section => {
2554 const section_name = objectSymbolName(wasm, object_id, symbol_index);2547 const section_name = wasm.objectSymbol(object_id, symbol_index).name;
2555 if (mem.eql(u8, section_name, ".debug_info")) {2548
2556 return wasm.debug_info_index orelse blk: {2549 inline for (@typeInfo(CustomSections).@"struct".fields) |field| {
2557 wasm.debug_info_index = index;2550 if (@field(wasm.custom_sections, field.name).name == section_name) {
2558 try wasm.appendDummySegment();2551 const field_ptr = &@field(wasm.custom_sections, field.name).index;
2559 break :blk index;2552 return field_ptr.unwrap() orelse {
2560 };2553 field_ptr.* = index.toOptional();
2561 } else if (mem.eql(u8, section_name, ".debug_line")) {2554 try wasm.appendDummySegment();
2562 return wasm.debug_line_index orelse blk: {2555 return index;
2563 wasm.debug_line_index = index;2556 };
2564 try wasm.appendDummySegment();2557 }
2565 break :blk index;
2566 };
2567 } else if (mem.eql(u8, section_name, ".debug_loc")) {
2568 return wasm.debug_loc_index orelse blk: {
2569 wasm.debug_loc_index = index;
2570 try wasm.appendDummySegment();
2571 break :blk index;
2572 };
2573 } else if (mem.eql(u8, section_name, ".debug_ranges")) {
2574 return wasm.debug_ranges_index orelse blk: {
2575 wasm.debug_ranges_index = index;
2576 try wasm.appendDummySegment();
2577 break :blk index;
2578 };
2579 } else if (mem.eql(u8, section_name, ".debug_pubnames")) {
2580 return wasm.debug_pubnames_index orelse blk: {
2581 wasm.debug_pubnames_index = index;
2582 try wasm.appendDummySegment();
2583 break :blk index;
2584 };
2585 } else if (mem.eql(u8, section_name, ".debug_pubtypes")) {
2586 return wasm.debug_pubtypes_index orelse blk: {
2587 wasm.debug_pubtypes_index = index;
2588 try wasm.appendDummySegment();
2589 break :blk index;
2590 };
2591 } else if (mem.eql(u8, section_name, ".debug_abbrev")) {
2592 return wasm.debug_abbrev_index orelse blk: {
2593 wasm.debug_abbrev_index = index;
2594 try wasm.appendDummySegment();
2595 break :blk index;
2596 };
2597 } else if (mem.eql(u8, section_name, ".debug_str")) {
2598 return wasm.debug_str_index orelse blk: {
2599 wasm.debug_str_index = index;
2600 try wasm.appendDummySegment();
2601 break :blk index;
2602 };
2603 } else {2558 } else {
2604 var err = try diags.addErrorWithNotes(1);2559 return diags.failParse(objectPath(wasm, object_id), "unknown section: {s}", .{
2605 try err.addMsg("found unknown section '{s}'", .{section_name});2560 wasm.stringSlice(section_name),
2606 try err.addNote("defined in '{'}'", .{objectPath(wasm, object_id)});2561 });
2607 return error.UnexpectedValue;
2608 }2562 }
2609 },2563 },
2610 else => unreachable,2564 else => unreachable,
...@@ -2803,10 +2757,9 @@ fn writeToFile(...@@ -2803,10 +2757,9 @@ fn writeToFile(
2803 }2757 }
28042758
2805 if (import_memory) {2759 if (import_memory) {
2806 const mem_name = if (is_obj) "__linear_memory" else "memory";
2807 const mem_imp: Import = .{2760 const mem_imp: Import = .{
2808 .module_name = try wasm.string_table.put(gpa, wasm.host_name),2761 .module_name = wasm.host_name,
2809 .name = try wasm.string_table.put(gpa, mem_name),2762 .name = if (is_obj) wasm.preloaded_strings.__linear_memory else wasm.preloaded_strings.memory,
2810 .kind = .{ .memory = wasm.memories.limits },2763 .kind = .{ .memory = wasm.memories.limits },
2811 };2764 };
2812 try wasm.emitImport(binary_writer, mem_imp);2765 try wasm.emitImport(binary_writer, mem_imp);
...@@ -2898,7 +2851,7 @@ fn writeToFile(...@@ -2898,7 +2851,7 @@ fn writeToFile(
2898 const header_offset = try reserveVecSectionHeader(&binary_bytes);2851 const header_offset = try reserveVecSectionHeader(&binary_bytes);
28992852
2900 for (wasm.exports.items) |exp| {2853 for (wasm.exports.items) |exp| {
2901 const name = wasm.string_table.get(exp.name);2854 const name = wasm.stringSlice(exp.name);
2902 try leb.writeUleb128(binary_writer, @as(u32, @intCast(name.len)));2855 try leb.writeUleb128(binary_writer, @as(u32, @intCast(name.len)));
2903 try binary_writer.writeAll(name);2856 try binary_writer.writeAll(name);
2904 try leb.writeUleb128(binary_writer, @intFromEnum(exp.kind));2857 try leb.writeUleb128(binary_writer, @intFromEnum(exp.kind));
...@@ -2937,7 +2890,7 @@ fn writeToFile(...@@ -2937,7 +2890,7 @@ fn writeToFile(
2937 if (wasm.function_table.count() > 0) {2890 if (wasm.function_table.count() > 0) {
2938 const header_offset = try reserveVecSectionHeader(&binary_bytes);2891 const header_offset = try reserveVecSectionHeader(&binary_bytes);
29392892
2940 const table_loc = wasm.findGlobalSymbol("__indirect_function_table").?;2893 const table_loc = wasm.globals.get(wasm.preloaded_strings.__indirect_function_table).?;
2941 const table_sym = wasm.symbolLocSymbol(table_loc);2894 const table_sym = wasm.symbolLocSymbol(table_loc);
29422895
2943 const flags: u32 = if (table_sym.index == 0) 0x0 else 0x02; // passive with implicit 0-index table or set table index manually2896 const flags: u32 = if (table_sym.index == 0) 0x0 else 0x02; // passive with implicit 0-index table or set table index manually
...@@ -2982,7 +2935,7 @@ fn writeToFile(...@@ -2982,7 +2935,7 @@ fn writeToFile(
2982 }2935 }
29832936
2984 // Code section2937 // Code section
2985 if (wasm.code_section_index != null) {2938 if (wasm.code_section_index != .none) {
2986 const header_offset = try reserveVecSectionHeader(&binary_bytes);2939 const header_offset = try reserveVecSectionHeader(&binary_bytes);
2987 const start_offset = binary_bytes.items.len - 5; // minus 5 so start offset is 5 to include entry count2940 const start_offset = binary_bytes.items.len - 5; // minus 5 so start offset is 5 to include entry count
29882941
...@@ -3022,7 +2975,7 @@ fn writeToFile(...@@ -3022,7 +2975,7 @@ fn writeToFile(
3022 // want to guarantee the data is zero initialized2975 // want to guarantee the data is zero initialized
3023 if (!import_memory and std.mem.eql(u8, entry.key_ptr.*, ".bss")) continue;2976 if (!import_memory and std.mem.eql(u8, entry.key_ptr.*, ".bss")) continue;
3024 const segment_index = entry.value_ptr.*;2977 const segment_index = entry.value_ptr.*;
3025 const segment = wasm.segments.items[segment_index];2978 const segment = wasm.segmentPtr(segment_index);
3026 if (segment.size == 0) continue; // do not emit empty segments2979 if (segment.size == 0) continue; // do not emit empty segments
3027 segment_count += 1;2980 segment_count += 1;
3028 var atom_index = wasm.atoms.get(segment_index).?;2981 var atom_index = wasm.atoms.get(segment_index).?;
...@@ -3133,24 +3086,8 @@ fn writeToFile(...@@ -3133,24 +3086,8 @@ fn writeToFile(
3133 var debug_bytes = std.ArrayList(u8).init(gpa);3086 var debug_bytes = std.ArrayList(u8).init(gpa);
3134 defer debug_bytes.deinit();3087 defer debug_bytes.deinit();
31353088
3136 const DebugSection = struct {3089 inline for (@typeInfo(CustomSections).@"struct".fields) |field| {
3137 name: []const u8,3090 if (@field(wasm.custom_sections, field.name).index.unwrap()) |index| {
3138 index: ?u32,
3139 };
3140
3141 const debug_sections: []const DebugSection = &.{
3142 .{ .name = ".debug_info", .index = wasm.debug_info_index },
3143 .{ .name = ".debug_pubtypes", .index = wasm.debug_pubtypes_index },
3144 .{ .name = ".debug_abbrev", .index = wasm.debug_abbrev_index },
3145 .{ .name = ".debug_line", .index = wasm.debug_line_index },
3146 .{ .name = ".debug_str", .index = wasm.debug_str_index },
3147 .{ .name = ".debug_pubnames", .index = wasm.debug_pubnames_index },
3148 .{ .name = ".debug_loc", .index = wasm.debug_loc_index },
3149 .{ .name = ".debug_ranges", .index = wasm.debug_ranges_index },
3150 };
3151
3152 for (debug_sections) |item| {
3153 if (item.index) |index| {
3154 var atom = wasm.getAtomPtr(wasm.atoms.get(index).?);3091 var atom = wasm.getAtomPtr(wasm.atoms.get(index).?);
3155 while (true) {3092 while (true) {
3156 atom.resolveRelocs(wasm);3093 atom.resolveRelocs(wasm);
...@@ -3158,7 +3095,7 @@ fn writeToFile(...@@ -3158,7 +3095,7 @@ fn writeToFile(
3158 if (atom.prev == .null) break;3095 if (atom.prev == .null) break;
3159 atom = wasm.getAtomPtr(atom.prev);3096 atom = wasm.getAtomPtr(atom.prev);
3160 }3097 }
3161 try emitDebugSection(&binary_bytes, debug_bytes.items, item.name);3098 try emitDebugSection(&binary_bytes, debug_bytes.items, field.name);
3162 debug_bytes.clearRetainingCapacity();3099 debug_bytes.clearRetainingCapacity();
3163 }3100 }
3164 }3101 }
...@@ -3430,11 +3367,11 @@ fn emitInit(writer: anytype, init_expr: std.wasm.InitExpression) !void {...@@ -3430,11 +3367,11 @@ fn emitInit(writer: anytype, init_expr: std.wasm.InitExpression) !void {
3430}3367}
34313368
3432fn emitImport(wasm: *Wasm, writer: anytype, import: Import) !void {3369fn emitImport(wasm: *Wasm, writer: anytype, import: Import) !void {
3433 const module_name = wasm.string_table.get(import.module_name);3370 const module_name = wasm.stringSlice(import.module_name);
3434 try leb.writeUleb128(writer, @as(u32, @intCast(module_name.len)));3371 try leb.writeUleb128(writer, @as(u32, @intCast(module_name.len)));
3435 try writer.writeAll(module_name);3372 try writer.writeAll(module_name);
34363373
3437 const name = wasm.string_table.get(import.name);3374 const name = wasm.stringSlice(import.name);
3438 try leb.writeUleb128(writer, @as(u32, @intCast(name.len)));3375 try leb.writeUleb128(writer, @as(u32, @intCast(name.len)));
3439 try writer.writeAll(name);3376 try writer.writeAll(name);
34403377
...@@ -3515,7 +3452,7 @@ fn linkWithLLD(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_node:...@@ -3515,7 +3452,7 @@ fn linkWithLLD(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_node:
3515 }3452 }
3516 try man.addOptionalFile(module_obj_path);3453 try man.addOptionalFile(module_obj_path);
3517 try man.addOptionalFilePath(compiler_rt_path);3454 try man.addOptionalFilePath(compiler_rt_path);
3518 man.hash.addOptionalBytes(wasm.entry_name);3455 man.hash.addOptionalBytes(wasm.optionalStringSlice(wasm.entry_name));
3519 man.hash.add(wasm.base.stack_size);3456 man.hash.add(wasm.base.stack_size);
3520 man.hash.add(wasm.base.build_id);3457 man.hash.add(wasm.base.build_id);
3521 man.hash.add(import_memory);3458 man.hash.add(import_memory);
...@@ -3664,7 +3601,7 @@ fn linkWithLLD(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_node:...@@ -3664,7 +3601,7 @@ fn linkWithLLD(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_node:
3664 try argv.append("--export-dynamic");3601 try argv.append("--export-dynamic");
3665 }3602 }
36663603
3667 if (wasm.entry_name) |entry_name| {3604 if (wasm.optionalStringSlice(wasm.entry_name)) |entry_name| {
3668 try argv.appendSlice(&.{ "--entry", entry_name });3605 try argv.appendSlice(&.{ "--entry", entry_name });
3669 } else {3606 } else {
3670 try argv.append("--no-entry");3607 try argv.append("--no-entry");
...@@ -4009,7 +3946,7 @@ fn emitCodeRelocations(...@@ -4009,7 +3946,7 @@ fn emitCodeRelocations(
4009 section_index: u32,3946 section_index: u32,
4010 symbol_table: std.AutoArrayHashMap(SymbolLoc, u32),3947 symbol_table: std.AutoArrayHashMap(SymbolLoc, u32),
4011) !void {3948) !void {
4012 const code_index = wasm.code_section_index orelse return;3949 const code_index = wasm.code_section_index.unwrap() orelse return;
4013 const writer = binary_bytes.writer();3950 const writer = binary_bytes.writer();
4014 const header_offset = try reserveCustomSectionHeader(binary_bytes);3951 const header_offset = try reserveCustomSectionHeader(binary_bytes);
40153952
...@@ -4106,7 +4043,7 @@ fn hasPassiveInitializationSegments(wasm: *const Wasm) bool {...@@ -4106,7 +4043,7 @@ fn hasPassiveInitializationSegments(wasm: *const Wasm) bool {
41064043
4107 var it = wasm.data_segments.iterator();4044 var it = wasm.data_segments.iterator();
4108 while (it.next()) |entry| {4045 while (it.next()) |entry| {
4109 const segment: Segment = wasm.segments.items[entry.value_ptr.*];4046 const segment = wasm.segmentPtr(entry.value_ptr.*);
4110 if (segment.needsPassiveInitialization(import_memory, entry.key_ptr.*)) {4047 if (segment.needsPassiveInitialization(import_memory, entry.key_ptr.*)) {
4111 return true;4048 return true;
4112 }4049 }
...@@ -4213,10 +4150,13 @@ fn mark(wasm: *Wasm, loc: SymbolLoc) !void {...@@ -4213,10 +4150,13 @@ fn mark(wasm: *Wasm, loc: SymbolLoc) !void {
4213 }4150 }
4214}4151}
42154152
4216fn defaultEntrySymbolName(wasi_exec_model: std.builtin.WasiExecModel) []const u8 {4153fn defaultEntrySymbolName(
4154 preloaded_strings: *const PreloadedStrings,
4155 wasi_exec_model: std.builtin.WasiExecModel,
4156) String {
4217 return switch (wasi_exec_model) {4157 return switch (wasi_exec_model) {
4218 .reactor => "_initialize",4158 .reactor => preloaded_strings._initialize,
4219 .command => "_start",4159 .command => preloaded_strings._start,
4220 };4160 };
4221}4161}
42224162
...@@ -4352,7 +4292,7 @@ pub const Atom = struct {...@@ -4352,7 +4292,7 @@ pub const Atom = struct {
4352 symbol.tag != .section and4292 symbol.tag != .section and
4353 symbol.isDead())4293 symbol.isDead())
4354 {4294 {
4355 const val = atom.thombstone(wasm) orelse relocation.addend;4295 const val = atom.tombstone(wasm) orelse relocation.addend;
4356 return @bitCast(val);4296 return @bitCast(val);
4357 }4297 }
4358 switch (relocation.relocation_type) {4298 switch (relocation.relocation_type) {
...@@ -4394,7 +4334,7 @@ pub const Atom = struct {...@@ -4394,7 +4334,7 @@ pub const Atom = struct {
4394 },4334 },
4395 .R_WASM_FUNCTION_OFFSET_I32 => {4335 .R_WASM_FUNCTION_OFFSET_I32 => {
4396 if (symbol.isUndefined()) {4336 if (symbol.isUndefined()) {
4397 const val = atom.thombstone(wasm) orelse relocation.addend;4337 const val = atom.tombstone(wasm) orelse relocation.addend;
4398 return @bitCast(val);4338 return @bitCast(val);
4399 }4339 }
4400 const target_atom_index = wasm.symbol_atom.get(target_loc).?;4340 const target_atom_index = wasm.symbol_atom.get(target_loc).?;
...@@ -4411,16 +4351,19 @@ pub const Atom = struct {...@@ -4411,16 +4351,19 @@ pub const Atom = struct {
4411 }4351 }
4412 }4352 }
44134353
4414 // For a given `Atom` returns whether it has a thombstone value or not.4354 // For a given `Atom` returns whether it has a tombstone value or not.
4415 /// This defines whether we want a specific value when a section is dead.4355 /// This defines whether we want a specific value when a section is dead.
4416 fn thombstone(atom: Atom, wasm: *const Wasm) ?i64 {4356 fn tombstone(atom: Atom, wasm: *const Wasm) ?i64 {
4417 const atom_name = wasm.symbolLocName(atom.symbolLoc());4357 const atom_name = wasm.symbolLocSymbol(atom.symbolLoc()).name;
4418 if (std.mem.eql(u8, atom_name, ".debug_ranges") or std.mem.eql(u8, atom_name, ".debug_loc")) {4358 if (atom_name == wasm.custom_sections.@".debug_ranges".name or
4359 atom_name == wasm.custom_sections.@".debug_loc".name)
4360 {
4419 return -2;4361 return -2;
4420 } else if (std.mem.startsWith(u8, atom_name, ".debug_")) {4362 } else if (std.mem.startsWith(u8, wasm.stringSlice(atom_name), ".debug_")) {
4421 return -1;4363 return -1;
4364 } else {
4365 return null;
4422 }4366 }
4423 return null;
4424 }4367 }
4425};4368};
44264369
...@@ -4509,8 +4452,8 @@ pub const Relocation = struct {...@@ -4509,8 +4452,8 @@ pub const Relocation = struct {
4509/// of the import using offsets into a string table, rather than the slices itself.4452/// of the import using offsets into a string table, rather than the slices itself.
4510/// This saves us (potentially) 24 bytes per import on 64bit machines.4453/// This saves us (potentially) 24 bytes per import on 64bit machines.
4511pub const Import = struct {4454pub const Import = struct {
4512 module_name: u32,4455 module_name: String,
4513 name: u32,4456 name: String,
4514 kind: std.wasm.Import.Kind,4457 kind: std.wasm.Import.Kind,
4515};4458};
45164459
...@@ -4519,7 +4462,7 @@ pub const Import = struct {...@@ -4519,7 +4462,7 @@ pub const Import = struct {
4519/// of the export using offsets into a string table, rather than the slice itself.4462/// of the export using offsets into a string table, rather than the slice itself.
4520/// This saves us (potentially) 12 bytes per export on 64bit machines.4463/// This saves us (potentially) 12 bytes per export on 64bit machines.
4521pub const Export = struct {4464pub const Export = struct {
4522 name: u32,4465 name: String,
4523 index: u32,4466 index: u32,
4524 kind: std.wasm.ExternalKind,4467 kind: std.wasm.ExternalKind,
4525};4468};
...@@ -4719,7 +4662,7 @@ fn parseSymbolIntoAtom(wasm: *Wasm, object_id: ObjectId, symbol_index: Symbol.In...@@ -4719,7 +4662,7 @@ fn parseSymbolIntoAtom(wasm: *Wasm, object_id: ObjectId, symbol_index: Symbol.In
4719 atom.code = std.ArrayListUnmanaged(u8).fromOwnedSlice(relocatable_data.data[0..relocatable_data.size]);4662 atom.code = std.ArrayListUnmanaged(u8).fromOwnedSlice(relocatable_data.data[0..relocatable_data.size]);
4720 atom.original_offset = relocatable_data.offset;4663 atom.original_offset = relocatable_data.offset;
47214664
4722 const segment: *Wasm.Segment = &wasm.segments.items[final_index];4665 const segment = wasm.segmentPtr(final_index);
4723 if (relocatable_data.type == .data) { //code section and custom sections are 1-byte aligned4666 if (relocatable_data.type == .data) { //code section and custom sections are 1-byte aligned
4724 segment.alignment = segment.alignment.max(atom.alignment);4667 segment.alignment = segment.alignment.max(atom.alignment);
4725 }4668 }
...@@ -4782,3 +4725,48 @@ fn searchRelocEnd(relocs: []const Wasm.Relocation, address: u32) usize {...@@ -4782,3 +4725,48 @@ fn searchRelocEnd(relocs: []const Wasm.Relocation, address: u32) usize {
4782 }4725 }
4783 return relocs.len;4726 return relocs.len;
4784}4727}
4728
4729pub fn internString(wasm: *Wasm, bytes: []const u8) error{OutOfMemory}!String {
4730 const gpa = wasm.base.comp.gpa;
4731 const gop = try wasm.string_table.getOrPutContextAdapted(
4732 gpa,
4733 @as([]const u8, bytes),
4734 @as(String.TableIndexAdapter, .{ .bytes = wasm.string_bytes.items }),
4735 @as(String.TableContext, .{ .bytes = wasm.string_bytes.items }),
4736 );
4737 if (gop.found_existing) return gop.key_ptr.*;
4738
4739 try wasm.string_bytes.ensureUnusedCapacity(gpa, bytes.len + 1);
4740 const new_off: String = @enumFromInt(wasm.string_bytes.items.len);
4741
4742 wasm.string_bytes.appendSliceAssumeCapacity(bytes);
4743 wasm.string_bytes.appendAssumeCapacity(0);
4744
4745 gop.key_ptr.* = new_off;
4746
4747 return new_off;
4748}
4749
4750pub fn getExistingString(wasm: *const Wasm, bytes: []const u8) ?String {
4751 return wasm.string_table.getKeyAdapted(bytes, @as(String.TableIndexAdapter, .{
4752 .bytes = wasm.string_bytes.items,
4753 }));
4754}
4755
4756pub fn stringSlice(wasm: *const Wasm, index: String) [:0]const u8 {
4757 const slice = wasm.string_bytes.items[@intFromEnum(index)..];
4758 return slice[0..mem.indexOfScalar(u8, slice, 0).? :0];
4759}
4760
4761pub fn optionalStringSlice(wasm: *const Wasm, index: OptionalString) ?[:0]const u8 {
4762 return stringSlice(wasm, index.unwrap() orelse return null);
4763}
4764
4765pub fn castToString(wasm: *const Wasm, index: u32) String {
4766 assert(index == 0 or wasm.string_bytes.items[index - 1] == 0);
4767 return @enumFromInt(index);
4768}
4769
4770fn segmentPtr(wasm: *const Wasm, index: Segment.Index) *Segment {
4771 return &wasm.segments.items[@intFromEnum(index)];
4772}
src/link/Wasm/Archive.zig+1-1
...@@ -173,7 +173,7 @@ fn parseNameTable(gpa: Allocator, reader: anytype) ![]const u8 {...@@ -173,7 +173,7 @@ fn parseNameTable(gpa: Allocator, reader: anytype) ![]const u8 {
173173
174/// From a given file offset, starts reading for a file header.174/// From a given file offset, starts reading for a file header.
175/// When found, parses the object file into an `Object` and returns it.175/// When found, parses the object file into an `Object` and returns it.
176pub fn parseObject(archive: Archive, wasm: *const Wasm, file_contents: []const u8, path: Path) !Object {176pub fn parseObject(archive: Archive, wasm: *Wasm, file_contents: []const u8, path: Path) !Object {
177 var fbs = std.io.fixedBufferStream(file_contents);177 var fbs = std.io.fixedBufferStream(file_contents);
178 const header = try fbs.reader().readStruct(Header);178 const header = try fbs.reader().readStruct(Header);
179179
src/link/Wasm/Object.zig+23-21
...@@ -63,10 +63,6 @@ comdat_info: []const Wasm.Comdat = &.{},...@@ -63,10 +63,6 @@ comdat_info: []const Wasm.Comdat = &.{},
63/// Represents non-synthetic sections that can essentially be mem-cpy'd into place63/// Represents non-synthetic sections that can essentially be mem-cpy'd into place
64/// after performing relocations.64/// after performing relocations.
65relocatable_data: std.AutoHashMapUnmanaged(RelocatableData.Tag, []RelocatableData) = .empty,65relocatable_data: std.AutoHashMapUnmanaged(RelocatableData.Tag, []RelocatableData) = .empty,
66/// String table for all strings required by the object file, such as symbol names,
67/// import name, module name and export names. Each string will be deduplicated
68/// and returns an offset into the table.
69string_table: Wasm.StringTable = .{},
70/// Amount of functions in the `import` sections.66/// Amount of functions in the `import` sections.
71imported_functions_count: u32 = 0,67imported_functions_count: u32 = 0,
72/// Amount of globals in the `import` section.68/// Amount of globals in the `import` section.
...@@ -126,7 +122,7 @@ pub const RelocatableData = struct {...@@ -126,7 +122,7 @@ pub const RelocatableData = struct {
126/// When a max size is given, will only parse up to the given size,122/// When a max size is given, will only parse up to the given size,
127/// else will read until the end of the file.123/// else will read until the end of the file.
128pub fn create(124pub fn create(
129 wasm: *const Wasm,125 wasm: *Wasm,
130 file_contents: []const u8,126 file_contents: []const u8,
131 path: Path,127 path: Path,
132 archive_member_name: ?[]const u8,128 archive_member_name: ?[]const u8,
...@@ -187,7 +183,6 @@ pub fn deinit(object: *Object, gpa: Allocator) void {...@@ -187,7 +183,6 @@ pub fn deinit(object: *Object, gpa: Allocator) void {
187 }183 }
188 }184 }
189 object.relocatable_data.deinit(gpa);185 object.relocatable_data.deinit(gpa);
190 object.string_table.deinit(gpa);
191 object.* = undefined;186 object.* = undefined;
192}187}
193188
...@@ -242,9 +237,9 @@ fn checkLegacyIndirectFunctionTable(object: *Object, wasm: *const Wasm) !?Symbol...@@ -242,9 +237,9 @@ fn checkLegacyIndirectFunctionTable(object: *Object, wasm: *const Wasm) !?Symbol
242 }237 }
243 } else unreachable;238 } else unreachable;
244239
245 if (!std.mem.eql(u8, object.string_table.get(table_import.name), "__indirect_function_table")) {240 if (table_import.name != wasm.preloaded_strings.__indirect_function_table) {
246 return diags.failParse(object.path, "non-indirect function table import '{s}' is missing a corresponding symbol", .{241 return diags.failParse(object.path, "non-indirect function table import '{s}' is missing a corresponding symbol", .{
247 object.string_table.get(table_import.name),242 wasm.stringSlice(table_import.name),
248 });243 });
249 }244 }
250245
...@@ -264,10 +259,12 @@ const Parser = struct {...@@ -264,10 +259,12 @@ const Parser = struct {
264 reader: std.io.FixedBufferStream([]const u8),259 reader: std.io.FixedBufferStream([]const u8),
265 /// Object file we're building260 /// Object file we're building
266 object: *Object,261 object: *Object,
267 /// Read-only reference to the WebAssembly linker262 /// Mutable so that the string table can be modified.
268 wasm: *const Wasm,263 wasm: *Wasm,
269264
270 fn parseObject(parser: *Parser, gpa: Allocator) anyerror!void {265 fn parseObject(parser: *Parser, gpa: Allocator) anyerror!void {
266 const wasm = parser.wasm;
267
271 {268 {
272 var magic_bytes: [4]u8 = undefined;269 var magic_bytes: [4]u8 = undefined;
273 try parser.reader.reader().readNoEof(&magic_bytes);270 try parser.reader.reader().readNoEof(&magic_bytes);
...@@ -316,7 +313,7 @@ const Parser = struct {...@@ -316,7 +313,7 @@ const Parser = struct {
316 .type = .custom,313 .type = .custom,
317 .data = debug_content.ptr,314 .data = debug_content.ptr,
318 .size = debug_size,315 .size = debug_size,
319 .index = try parser.object.string_table.put(gpa, name),316 .index = @intFromEnum(try wasm.internString(name)),
320 .offset = 0, // debug sections only contain 1 entry, so no need to calculate offset317 .offset = 0, // debug sections only contain 1 entry, so no need to calculate offset
321 .section_index = section_index,318 .section_index = section_index,
322 });319 });
...@@ -375,8 +372,8 @@ const Parser = struct {...@@ -375,8 +372,8 @@ const Parser = struct {
375 };372 };
376373
377 import.* = .{374 import.* = .{
378 .module_name = try parser.object.string_table.put(gpa, module_name),375 .module_name = try wasm.internString(module_name),
379 .name = try parser.object.string_table.put(gpa, name),376 .name = try wasm.internString(name),
380 .kind = kind_value,377 .kind = kind_value,
381 };378 };
382 }379 }
...@@ -422,7 +419,7 @@ const Parser = struct {...@@ -422,7 +419,7 @@ const Parser = struct {
422 defer gpa.free(name);419 defer gpa.free(name);
423 try reader.readNoEof(name);420 try reader.readNoEof(name);
424 exp.* = .{421 exp.* = .{
425 .name = try parser.object.string_table.put(gpa, name),422 .name = try wasm.internString(name),
426 .kind = try readEnum(std.wasm.ExternalKind, reader),423 .kind = try readEnum(std.wasm.ExternalKind, reader),
427 .index = try readLeb(u32, reader),424 .index = try readLeb(u32, reader),
428 };425 };
...@@ -587,6 +584,7 @@ const Parser = struct {...@@ -587,6 +584,7 @@ const Parser = struct {
587 /// `parser` is used to provide access to other sections that may be needed,584 /// `parser` is used to provide access to other sections that may be needed,
588 /// such as access to the `import` section to find the name of a symbol.585 /// such as access to the `import` section to find the name of a symbol.
589 fn parseSubsection(parser: *Parser, gpa: Allocator, reader: anytype) !void {586 fn parseSubsection(parser: *Parser, gpa: Allocator, reader: anytype) !void {
587 const wasm = parser.wasm;
590 const sub_type = try leb.readUleb128(u8, reader);588 const sub_type = try leb.readUleb128(u8, reader);
591 log.debug("Found subsection: {s}", .{@tagName(@as(Wasm.SubsectionType, @enumFromInt(sub_type)))});589 log.debug("Found subsection: {s}", .{@tagName(@as(Wasm.SubsectionType, @enumFromInt(sub_type)))});
592 const payload_len = try leb.readUleb128(u32, reader);590 const payload_len = try leb.readUleb128(u32, reader);
...@@ -680,7 +678,7 @@ const Parser = struct {...@@ -680,7 +678,7 @@ const Parser = struct {
680 symbol.* = try parser.parseSymbol(gpa, reader);678 symbol.* = try parser.parseSymbol(gpa, reader);
681 log.debug("Found symbol: type({s}) name({s}) flags(0b{b:0>8})", .{679 log.debug("Found symbol: type({s}) name({s}) flags(0b{b:0>8})", .{
682 @tagName(symbol.tag),680 @tagName(symbol.tag),
683 parser.object.string_table.get(symbol.name),681 wasm.stringSlice(symbol.name),
684 symbol.flags,682 symbol.flags,
685 });683 });
686 }684 }
...@@ -697,15 +695,18 @@ const Parser = struct {...@@ -697,15 +695,18 @@ const Parser = struct {
697 if (parser.object.relocatable_data.get(.custom)) |custom_sections| {695 if (parser.object.relocatable_data.get(.custom)) |custom_sections| {
698 for (custom_sections) |*data| {696 for (custom_sections) |*data| {
699 if (!data.represented) {697 if (!data.represented) {
698 const name = wasm.castToString(data.index);
700 try symbols.append(.{699 try symbols.append(.{
701 .name = data.index,700 .name = name,
702 .flags = @intFromEnum(Symbol.Flag.WASM_SYM_BINDING_LOCAL),701 .flags = @intFromEnum(Symbol.Flag.WASM_SYM_BINDING_LOCAL),
703 .tag = .section,702 .tag = .section,
704 .virtual_address = 0,703 .virtual_address = 0,
705 .index = data.section_index,704 .index = data.section_index,
706 });705 });
707 data.represented = true;706 data.represented = true;
708 log.debug("Created synthetic custom section symbol for '{s}'", .{parser.object.string_table.get(data.index)});707 log.debug("Created synthetic custom section symbol for '{s}'", .{
708 wasm.stringSlice(name),
709 });
709 }710 }
710 }711 }
711 }712 }
...@@ -719,7 +720,8 @@ const Parser = struct {...@@ -719,7 +720,8 @@ const Parser = struct {
719 /// requires access to `Object` to find the name of a symbol when it's720 /// requires access to `Object` to find the name of a symbol when it's
720 /// an import and flag `WASM_SYM_EXPLICIT_NAME` is not set.721 /// an import and flag `WASM_SYM_EXPLICIT_NAME` is not set.
721 fn parseSymbol(parser: *Parser, gpa: Allocator, reader: anytype) !Symbol {722 fn parseSymbol(parser: *Parser, gpa: Allocator, reader: anytype) !Symbol {
722 const tag = @as(Symbol.Tag, @enumFromInt(try leb.readUleb128(u8, reader)));723 const wasm = parser.wasm;
724 const tag: Symbol.Tag = @enumFromInt(try leb.readUleb128(u8, reader));
723 const flags = try leb.readUleb128(u32, reader);725 const flags = try leb.readUleb128(u32, reader);
724 var symbol: Symbol = .{726 var symbol: Symbol = .{
725 .flags = flags,727 .flags = flags,
...@@ -735,7 +737,7 @@ const Parser = struct {...@@ -735,7 +737,7 @@ const Parser = struct {
735 const name = try gpa.alloc(u8, name_len);737 const name = try gpa.alloc(u8, name_len);
736 defer gpa.free(name);738 defer gpa.free(name);
737 try reader.readNoEof(name);739 try reader.readNoEof(name);
738 symbol.name = try parser.object.string_table.put(gpa, name);740 symbol.name = try wasm.internString(name);
739741
740 // Data symbols only have the following fields if the symbol is defined742 // Data symbols only have the following fields if the symbol is defined
741 if (symbol.isDefined()) {743 if (symbol.isDefined()) {
...@@ -750,7 +752,7 @@ const Parser = struct {...@@ -750,7 +752,7 @@ const Parser = struct {
750 const section_data = parser.object.relocatable_data.get(.custom).?;752 const section_data = parser.object.relocatable_data.get(.custom).?;
751 for (section_data) |*data| {753 for (section_data) |*data| {
752 if (data.section_index == symbol.index) {754 if (data.section_index == symbol.index) {
753 symbol.name = data.index;755 symbol.name = wasm.castToString(data.index);
754 data.represented = true;756 data.represented = true;
755 break;757 break;
756 }758 }
...@@ -765,7 +767,7 @@ const Parser = struct {...@@ -765,7 +767,7 @@ const Parser = struct {
765 const name = try gpa.alloc(u8, name_len);767 const name = try gpa.alloc(u8, name_len);
766 defer gpa.free(name);768 defer gpa.free(name);
767 try reader.readNoEof(name);769 try reader.readNoEof(name);
768 break :name try parser.object.string_table.put(gpa, name);770 break :name try wasm.internString(name);
769 } else parser.object.findImport(symbol).name;771 } else parser.object.findImport(symbol).name;
770 },772 },
771 }773 }
src/link/Wasm/Symbol.zig+3-2
...@@ -8,8 +8,8 @@...@@ -8,8 +8,8 @@
8/// Can contain any of the flags defined in `Flag`8/// Can contain any of the flags defined in `Flag`
9flags: u32,9flags: u32,
10/// Symbol name, when the symbol is undefined the name will be taken from the import.10/// Symbol name, when the symbol is undefined the name will be taken from the import.
11/// Note: This is an index into the string table.11/// Note: This is an index into the wasm string table.
12name: u32,12name: wasm.String,
13/// Index into the list of objects based on set `tag`13/// Index into the list of objects based on set `tag`
14/// NOTE: This will be set to `undefined` when `tag` is `data`14/// NOTE: This will be set to `undefined` when `tag` is `data`
15/// and the symbol is undefined.15/// and the symbol is undefined.
...@@ -207,3 +207,4 @@ pub fn format(symbol: Symbol, comptime fmt: []const u8, options: std.fmt.FormatO...@@ -207,3 +207,4 @@ pub fn format(symbol: Symbol, comptime fmt: []const u8, options: std.fmt.FormatO
207207
208const std = @import("std");208const std = @import("std");
209const Symbol = @This();209const Symbol = @This();
210const wasm = @import("../Wasm.zig");
src/link/Wasm/ZigObject.zig+32-50
...@@ -23,16 +23,14 @@ globals: std.ArrayListUnmanaged(std.wasm.Global) = .empty,...@@ -23,16 +23,14 @@ globals: std.ArrayListUnmanaged(std.wasm.Global) = .empty,
23atom_types: std.AutoHashMapUnmanaged(Atom.Index, u32) = .empty,23atom_types: std.AutoHashMapUnmanaged(Atom.Index, u32) = .empty,
24/// List of all symbols generated by Zig code.24/// List of all symbols generated by Zig code.
25symbols: std.ArrayListUnmanaged(Symbol) = .empty,25symbols: std.ArrayListUnmanaged(Symbol) = .empty,
26/// Map from symbol name offset to their index into the `symbols` list.26/// Map from symbol name to their index into the `symbols` list.
27global_syms: std.AutoHashMapUnmanaged(u32, Symbol.Index) = .empty,27global_syms: std.AutoHashMapUnmanaged(Wasm.String, Symbol.Index) = .empty,
28/// List of symbol indexes which are free to be used.28/// List of symbol indexes which are free to be used.
29symbols_free_list: std.ArrayListUnmanaged(Symbol.Index) = .empty,29symbols_free_list: std.ArrayListUnmanaged(Symbol.Index) = .empty,
30/// Extra metadata about the linking section, such as alignment of segments and their name.30/// Extra metadata about the linking section, such as alignment of segments and their name.
31segment_info: std.ArrayListUnmanaged(Wasm.NamedSegment) = .empty,31segment_info: std.ArrayListUnmanaged(Wasm.NamedSegment) = .empty,
32/// List of indexes which contain a free slot in the `segment_info` list.32/// List of indexes which contain a free slot in the `segment_info` list.
33segment_free_list: std.ArrayListUnmanaged(u32) = .empty,33segment_free_list: std.ArrayListUnmanaged(u32) = .empty,
34/// File encapsulated string table, used to deduplicate strings within the generated file.
35string_table: StringTable = .{},
36/// Map for storing anonymous declarations. Each anonymous decl maps to its Atom's index.34/// Map for storing anonymous declarations. Each anonymous decl maps to its Atom's index.
37uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, Atom.Index) = .empty,35uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, Atom.Index) = .empty,
38/// List of atom indexes of functions that are generated by the backend.36/// List of atom indexes of functions that are generated by the backend.
...@@ -88,13 +86,9 @@ const NavInfo = struct {...@@ -88,13 +86,9 @@ const NavInfo = struct {
88 atom: Atom.Index = .null,86 atom: Atom.Index = .null,
89 exports: std.ArrayListUnmanaged(Symbol.Index) = .empty,87 exports: std.ArrayListUnmanaged(Symbol.Index) = .empty,
9088
91 fn @"export"(ni: NavInfo, zig_object: *const ZigObject, name: []const u8) ?Symbol.Index {89 fn @"export"(ni: NavInfo, zo: *const ZigObject, name: Wasm.String) ?Symbol.Index {
92 for (ni.exports.items) |sym_index| {90 for (ni.exports.items) |sym_index| {
93 const sym_name_index = zig_object.symbol(sym_index).name;91 if (zo.symbol(sym_index).name == name) return sym_index;
94 const sym_name = zig_object.string_table.getAssumeExists(sym_name_index);
95 if (std.mem.eql(u8, name, sym_name)) {
96 return sym_index;
97 }
98 }92 }
99 return null;93 return null;
100 }94 }
...@@ -126,14 +120,14 @@ pub fn init(zig_object: *ZigObject, wasm: *Wasm) !void {...@@ -126,14 +120,14 @@ pub fn init(zig_object: *ZigObject, wasm: *Wasm) !void {
126120
127fn createStackPointer(zig_object: *ZigObject, wasm: *Wasm) !void {121fn createStackPointer(zig_object: *ZigObject, wasm: *Wasm) !void {
128 const gpa = wasm.base.comp.gpa;122 const gpa = wasm.base.comp.gpa;
129 const sym_index = try zig_object.getGlobalSymbol(gpa, "__stack_pointer");123 const sym_index = try zig_object.getGlobalSymbol(gpa, wasm.preloaded_strings.__stack_pointer);
130 const sym = zig_object.symbol(sym_index);124 const sym = zig_object.symbol(sym_index);
131 sym.index = zig_object.imported_globals_count;125 sym.index = zig_object.imported_globals_count;
132 sym.tag = .global;126 sym.tag = .global;
133 const is_wasm32 = wasm.base.comp.root_mod.resolved_target.result.cpu.arch == .wasm32;127 const is_wasm32 = wasm.base.comp.root_mod.resolved_target.result.cpu.arch == .wasm32;
134 try zig_object.imports.putNoClobber(gpa, sym_index, .{128 try zig_object.imports.putNoClobber(gpa, sym_index, .{
135 .name = sym.name,129 .name = sym.name,
136 .module_name = try zig_object.string_table.insert(gpa, wasm.host_name),130 .module_name = wasm.host_name,
137 .kind = .{ .global = .{ .valtype = if (is_wasm32) .i32 else .i64, .mutable = true } },131 .kind = .{ .global = .{ .valtype = if (is_wasm32) .i32 else .i64, .mutable = true } },
138 });132 });
139 zig_object.imported_globals_count += 1;133 zig_object.imported_globals_count += 1;
...@@ -174,7 +168,7 @@ pub fn deinit(zig_object: *ZigObject, wasm: *Wasm) void {...@@ -174,7 +168,7 @@ pub fn deinit(zig_object: *ZigObject, wasm: *Wasm) void {
174 atom.deinit(gpa);168 atom.deinit(gpa);
175 }169 }
176 }170 }
177 if (zig_object.findGlobalSymbol("__zig_errors_len")) |sym_index| {171 if (zig_object.global_syms.get(wasm.preloaded_strings.__zig_errors_len)) |sym_index| {
178 const atom_index = wasm.symbol_atom.get(.{ .file = .zig_object, .index = sym_index }).?;172 const atom_index = wasm.symbol_atom.get(.{ .file = .zig_object, .index = sym_index }).?;
179 wasm.getAtomPtr(atom_index).deinit(gpa);173 wasm.getAtomPtr(atom_index).deinit(gpa);
180 }174 }
...@@ -206,7 +200,6 @@ pub fn deinit(zig_object: *ZigObject, wasm: *Wasm) void {...@@ -206,7 +200,6 @@ pub fn deinit(zig_object: *ZigObject, wasm: *Wasm) void {
206 zig_object.segment_info.deinit(gpa);200 zig_object.segment_info.deinit(gpa);
207 zig_object.segment_free_list.deinit(gpa);201 zig_object.segment_free_list.deinit(gpa);
208202
209 zig_object.string_table.deinit(gpa);
210 if (zig_object.dwarf) |*dwarf| {203 if (zig_object.dwarf) |*dwarf| {
211 dwarf.deinit();204 dwarf.deinit();
212 }205 }
...@@ -219,7 +212,7 @@ pub fn deinit(zig_object: *ZigObject, wasm: *Wasm) void {...@@ -219,7 +212,7 @@ pub fn deinit(zig_object: *ZigObject, wasm: *Wasm) void {
219pub fn allocateSymbol(zig_object: *ZigObject, gpa: std.mem.Allocator) !Symbol.Index {212pub fn allocateSymbol(zig_object: *ZigObject, gpa: std.mem.Allocator) !Symbol.Index {
220 try zig_object.symbols.ensureUnusedCapacity(gpa, 1);213 try zig_object.symbols.ensureUnusedCapacity(gpa, 1);
221 const sym: Symbol = .{214 const sym: Symbol = .{
222 .name = std.math.maxInt(u32), // will be set after updateDecl as well as during atom creation for decls215 .name = undefined, // will be set after updateDecl as well as during atom creation for decls
223 .flags = @intFromEnum(Symbol.Flag.WASM_SYM_BINDING_LOCAL),216 .flags = @intFromEnum(Symbol.Flag.WASM_SYM_BINDING_LOCAL),
224 .tag = .undefined, // will be set after updateDecl217 .tag = .undefined, // will be set after updateDecl
225 .index = std.math.maxInt(u32), // will be set during atom parsing218 .index = std.math.maxInt(u32), // will be set during atom parsing
...@@ -345,7 +338,7 @@ fn finishUpdateNav(...@@ -345,7 +338,7 @@ fn finishUpdateNav(
345 const atom_index = nav_info.atom;338 const atom_index = nav_info.atom;
346 const atom = wasm.getAtomPtr(atom_index);339 const atom = wasm.getAtomPtr(atom_index);
347 const sym = zig_object.symbol(atom.sym_index);340 const sym = zig_object.symbol(atom.sym_index);
348 sym.name = try zig_object.string_table.insert(gpa, nav.fqn.toSlice(ip));341 sym.name = try wasm.internString(nav.fqn.toSlice(ip));
349 try atom.code.appendSlice(gpa, code);342 try atom.code.appendSlice(gpa, code);
350 atom.size = @intCast(code.len);343 atom.size = @intCast(code.len);
351344
...@@ -432,7 +425,7 @@ pub fn getOrCreateAtomForNav(...@@ -432,7 +425,7 @@ pub fn getOrCreateAtomForNav(
432 gop.value_ptr.* = .{ .atom = try wasm.createAtom(sym_index, .zig_object) };425 gop.value_ptr.* = .{ .atom = try wasm.createAtom(sym_index, .zig_object) };
433 const nav = ip.getNav(nav_index);426 const nav = ip.getNav(nav_index);
434 const sym = zig_object.symbol(sym_index);427 const sym = zig_object.symbol(sym_index);
435 sym.name = try zig_object.string_table.insert(gpa, nav.fqn.toSlice(ip));428 sym.name = try wasm.internString(nav.fqn.toSlice(ip));
436 }429 }
437 return gop.value_ptr.atom;430 return gop.value_ptr.atom;
438}431}
...@@ -500,7 +493,7 @@ fn lowerConst(...@@ -500,7 +493,7 @@ fn lowerConst(
500 const segment_name = try std.mem.concat(gpa, u8, &.{ ".rodata.", name });493 const segment_name = try std.mem.concat(gpa, u8, &.{ ".rodata.", name });
501 errdefer gpa.free(segment_name);494 errdefer gpa.free(segment_name);
502 zig_object.symbol(sym_index).* = .{495 zig_object.symbol(sym_index).* = .{
503 .name = try zig_object.string_table.insert(gpa, name),496 .name = try wasm.internString(name),
504 .flags = @intFromEnum(Symbol.Flag.WASM_SYM_BINDING_LOCAL),497 .flags = @intFromEnum(Symbol.Flag.WASM_SYM_BINDING_LOCAL),
505 .tag = .data,498 .tag = .data,
506 .index = try zig_object.createDataSegment(499 .index = try zig_object.createDataSegment(
...@@ -551,11 +544,10 @@ pub fn getErrorTableSymbol(zig_object: *ZigObject, wasm: *Wasm, pt: Zcu.PerThrea...@@ -551,11 +544,10 @@ pub fn getErrorTableSymbol(zig_object: *ZigObject, wasm: *Wasm, pt: Zcu.PerThrea
551 const slice_ty = Type.slice_const_u8_sentinel_0;544 const slice_ty = Type.slice_const_u8_sentinel_0;
552 atom.alignment = slice_ty.abiAlignment(pt.zcu);545 atom.alignment = slice_ty.abiAlignment(pt.zcu);
553546
554 const sym_name = try zig_object.string_table.insert(gpa, "__zig_err_name_table");
555 const segment_name = try gpa.dupe(u8, ".rodata.__zig_err_name_table");547 const segment_name = try gpa.dupe(u8, ".rodata.__zig_err_name_table");
556 const sym = zig_object.symbol(sym_index);548 const sym = zig_object.symbol(sym_index);
557 sym.* = .{549 sym.* = .{
558 .name = sym_name,550 .name = wasm.preloaded_strings.__zig_err_name_table,
559 .tag = .data,551 .tag = .data,
560 .flags = @intFromEnum(Symbol.Flag.WASM_SYM_BINDING_LOCAL),552 .flags = @intFromEnum(Symbol.Flag.WASM_SYM_BINDING_LOCAL),
561 .index = try zig_object.createDataSegment(gpa, segment_name, atom.alignment),553 .index = try zig_object.createDataSegment(gpa, segment_name, atom.alignment),
...@@ -583,11 +575,10 @@ fn populateErrorNameTable(zig_object: *ZigObject, wasm: *Wasm, tid: Zcu.PerThrea...@@ -583,11 +575,10 @@ fn populateErrorNameTable(zig_object: *ZigObject, wasm: *Wasm, tid: Zcu.PerThrea
583 const names_atom_index = try wasm.createAtom(names_sym_index, .zig_object);575 const names_atom_index = try wasm.createAtom(names_sym_index, .zig_object);
584 const names_atom = wasm.getAtomPtr(names_atom_index);576 const names_atom = wasm.getAtomPtr(names_atom_index);
585 names_atom.alignment = .@"1";577 names_atom.alignment = .@"1";
586 const sym_name = try zig_object.string_table.insert(gpa, "__zig_err_names");
587 const segment_name = try gpa.dupe(u8, ".rodata.__zig_err_names");578 const segment_name = try gpa.dupe(u8, ".rodata.__zig_err_names");
588 const names_symbol = zig_object.symbol(names_sym_index);579 const names_symbol = zig_object.symbol(names_sym_index);
589 names_symbol.* = .{580 names_symbol.* = .{
590 .name = sym_name,581 .name = wasm.preloaded_strings.__zig_err_names,
591 .tag = .data,582 .tag = .data,
592 .flags = @intFromEnum(Symbol.Flag.WASM_SYM_BINDING_LOCAL),583 .flags = @intFromEnum(Symbol.Flag.WASM_SYM_BINDING_LOCAL),
593 .index = try zig_object.createDataSegment(gpa, segment_name, names_atom.alignment),584 .index = try zig_object.createDataSegment(gpa, segment_name, names_atom.alignment),
...@@ -661,14 +652,14 @@ pub fn addOrUpdateImport(...@@ -661,14 +652,14 @@ pub fn addOrUpdateImport(
661 // For the import name, we use the decl's name, rather than the fully qualified name652 // For the import name, we use the decl's name, rather than the fully qualified name
662 // Also mangle the name when the lib name is set and not equal to "C" so imports with the same653 // Also mangle the name when the lib name is set and not equal to "C" so imports with the same
663 // name but different module can be resolved correctly.654 // name but different module can be resolved correctly.
664 const mangle_name = lib_name != null and655 const mangle_name = if (lib_name) |n| !std.mem.eql(u8, n, "c") else false;
665 !std.mem.eql(u8, lib_name.?, "c");656 const full_name = if (mangle_name)
666 const full_name = if (mangle_name) full_name: {657 try std.fmt.allocPrint(gpa, "{s}|{s}", .{ name, lib_name.? })
667 break :full_name try std.fmt.allocPrint(gpa, "{s}|{s}", .{ name, lib_name.? });658 else
668 } else name;659 name;
669 defer if (mangle_name) gpa.free(full_name);660 defer if (mangle_name) gpa.free(full_name);
670661
671 const decl_name_index = try zig_object.string_table.insert(gpa, full_name);662 const decl_name_index = try wasm.internString(full_name);
672 const sym: *Symbol = &zig_object.symbols.items[@intFromEnum(symbol_index)];663 const sym: *Symbol = &zig_object.symbols.items[@intFromEnum(symbol_index)];
673 sym.setUndefined(true);664 sym.setUndefined(true);
674 sym.setGlobal(true);665 sym.setGlobal(true);
...@@ -680,13 +671,11 @@ pub fn addOrUpdateImport(...@@ -680,13 +671,11 @@ pub fn addOrUpdateImport(
680671
681 if (type_index) |ty_index| {672 if (type_index) |ty_index| {
682 const gop = try zig_object.imports.getOrPut(gpa, symbol_index);673 const gop = try zig_object.imports.getOrPut(gpa, symbol_index);
683 const module_name = if (lib_name) |l_name| l_name else wasm.host_name;674 const module_name = if (lib_name) |n| try wasm.internString(n) else wasm.host_name;
684 if (!gop.found_existing) {675 if (!gop.found_existing) zig_object.imported_functions_count += 1;
685 zig_object.imported_functions_count += 1;
686 }
687 gop.value_ptr.* = .{676 gop.value_ptr.* = .{
688 .module_name = try zig_object.string_table.insert(gpa, module_name),677 .module_name = module_name,
689 .name = try zig_object.string_table.insert(gpa, name),678 .name = try wasm.internString(name),
690 .kind = .{ .function = ty_index },679 .kind = .{ .function = ty_index },
691 };680 };
692 sym.tag = .function;681 sym.tag = .function;
...@@ -699,8 +688,7 @@ pub fn addOrUpdateImport(...@@ -699,8 +688,7 @@ pub fn addOrUpdateImport(
699/// such as an exported or imported symbol.688/// such as an exported or imported symbol.
700/// If the symbol does not yet exist, creates a new one symbol instead689/// If the symbol does not yet exist, creates a new one symbol instead
701/// and then returns the index to it.690/// and then returns the index to it.
702pub fn getGlobalSymbol(zig_object: *ZigObject, gpa: std.mem.Allocator, name: []const u8) !Symbol.Index {691pub fn getGlobalSymbol(zig_object: *ZigObject, gpa: std.mem.Allocator, name_index: Wasm.String) !Symbol.Index {
703 const name_index = try zig_object.string_table.insert(gpa, name);
704 const gop = try zig_object.global_syms.getOrPut(gpa, name_index);692 const gop = try zig_object.global_syms.getOrPut(gpa, name_index);
705 if (gop.found_existing) {693 if (gop.found_existing) {
706 return gop.value_ptr.*;694 return gop.value_ptr.*;
...@@ -840,7 +828,8 @@ pub fn deleteExport(...@@ -840,7 +828,8 @@ pub fn deleteExport(
840 .uav => @panic("TODO: implement Wasm linker code for exporting a constant value"),828 .uav => @panic("TODO: implement Wasm linker code for exporting a constant value"),
841 };829 };
842 const nav_info = zig_object.navs.getPtr(nav_index) orelse return;830 const nav_info = zig_object.navs.getPtr(nav_index) orelse return;
843 if (nav_info.@"export"(zig_object, name.toSlice(&zcu.intern_pool))) |sym_index| {831 const name_interned = wasm.getExistingString(name.toSlice(&zcu.intern_pool)).?;
832 if (nav_info.@"export"(zig_object, name_interned)) |sym_index| {
844 const sym = zig_object.symbol(sym_index);833 const sym = zig_object.symbol(sym_index);
845 nav_info.deleteExport(sym_index);834 nav_info.deleteExport(sym_index);
846 std.debug.assert(zig_object.global_syms.remove(sym.name));835 std.debug.assert(zig_object.global_syms.remove(sym.name));
...@@ -886,14 +875,13 @@ pub fn updateExports(...@@ -886,14 +875,13 @@ pub fn updateExports(
886 continue;875 continue;
887 }876 }
888877
889 const export_string = exp.opts.name.toSlice(ip);878 const export_name = try wasm.internString(exp.opts.name.toSlice(ip));
890 const sym_index = if (nav_info.@"export"(zig_object, export_string)) |idx| idx else index: {879 const sym_index = if (nav_info.@"export"(zig_object, export_name)) |idx| idx else index: {
891 const sym_index = try zig_object.allocateSymbol(gpa);880 const sym_index = try zig_object.allocateSymbol(gpa);
892 try nav_info.appendExport(gpa, sym_index);881 try nav_info.appendExport(gpa, sym_index);
893 break :index sym_index;882 break :index sym_index;
894 };883 };
895884
896 const export_name = try zig_object.string_table.insert(gpa, export_string);
897 const sym = zig_object.symbol(sym_index);885 const sym = zig_object.symbol(sym_index);
898 sym.setGlobal(true);886 sym.setGlobal(true);
899 sym.setUndefined(false);887 sym.setUndefined(false);
...@@ -922,7 +910,7 @@ pub fn updateExports(...@@ -922,7 +910,7 @@ pub fn updateExports(
922 if (exp.opts.visibility == .hidden) {910 if (exp.opts.visibility == .hidden) {
923 sym.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);911 sym.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);
924 }912 }
925 log.debug(" with name '{s}' - {}", .{ export_string, sym });913 log.debug(" with name '{s}' - {}", .{ wasm.stringSlice(export_name), sym });
926 try zig_object.global_syms.put(gpa, export_name, sym_index);914 try zig_object.global_syms.put(gpa, export_name, sym_index);
927 try wasm.symbol_atom.put(gpa, .{ .file = .zig_object, .index = sym_index }, atom_index);915 try wasm.symbol_atom.put(gpa, .{ .file = .zig_object, .index = sym_index }, atom_index);
928 }916 }
...@@ -1014,7 +1002,7 @@ pub fn putOrGetFuncType(zig_object: *ZigObject, gpa: std.mem.Allocator, func_typ...@@ -1014,7 +1002,7 @@ pub fn putOrGetFuncType(zig_object: *ZigObject, gpa: std.mem.Allocator, func_typ
1014/// This will only be generated if the symbol exists.1002/// This will only be generated if the symbol exists.
1015fn setupErrorsLen(zig_object: *ZigObject, wasm: *Wasm) !void {1003fn setupErrorsLen(zig_object: *ZigObject, wasm: *Wasm) !void {
1016 const gpa = wasm.base.comp.gpa;1004 const gpa = wasm.base.comp.gpa;
1017 const sym_index = zig_object.findGlobalSymbol("__zig_errors_len") orelse return;1005 const sym_index = zig_object.global_syms.get(wasm.preloaded_strings.__zig_errors_len) orelse return;
10181006
1019 const errors_len = 1 + wasm.base.comp.zcu.?.intern_pool.global_error_set.getNamesFromMainThread().len;1007 const errors_len = 1 + wasm.base.comp.zcu.?.intern_pool.global_error_set.getNamesFromMainThread().len;
1020 // overwrite existing atom if it already exists (maybe the error set has increased)1008 // overwrite existing atom if it already exists (maybe the error set has increased)
...@@ -1045,11 +1033,6 @@ fn setupErrorsLen(zig_object: *ZigObject, wasm: *Wasm) !void {...@@ -1045,11 +1033,6 @@ fn setupErrorsLen(zig_object: *ZigObject, wasm: *Wasm) !void {
1045 try atom.code.writer(gpa).writeInt(u16, @intCast(errors_len), .little);1033 try atom.code.writer(gpa).writeInt(u16, @intCast(errors_len), .little);
1046}1034}
10471035
1048fn findGlobalSymbol(zig_object: *ZigObject, name: []const u8) ?Symbol.Index {
1049 const offset = zig_object.string_table.getOffset(name) orelse return null;
1050 return zig_object.global_syms.get(offset);
1051}
1052
1053/// Initializes symbols and atoms for the debug sections1036/// Initializes symbols and atoms for the debug sections
1054/// Initialization is only done when compiling Zig code.1037/// Initialization is only done when compiling Zig code.
1055/// When Zig is invoked as a linker instead, the atoms1038/// When Zig is invoked as a linker instead, the atoms
...@@ -1082,7 +1065,7 @@ pub fn createDebugSectionForIndex(zig_object: *ZigObject, wasm: *Wasm, index: *?...@@ -1082,7 +1065,7 @@ pub fn createDebugSectionForIndex(zig_object: *ZigObject, wasm: *Wasm, index: *?
1082 const atom = wasm.getAtomPtr(atom_index);1065 const atom = wasm.getAtomPtr(atom_index);
1083 zig_object.symbols.items[sym_index] = .{1066 zig_object.symbols.items[sym_index] = .{
1084 .tag = .section,1067 .tag = .section,
1085 .name = try zig_object.string_table.put(gpa, name),1068 .name = try wasm.internString(name),
1086 .index = 0,1069 .index = 0,
1087 .flags = @intFromEnum(Symbol.Flag.WASM_SYM_BINDING_LOCAL),1070 .flags = @intFromEnum(Symbol.Flag.WASM_SYM_BINDING_LOCAL),
1088 };1071 };
...@@ -1197,7 +1180,7 @@ pub fn createFunction(...@@ -1197,7 +1180,7 @@ pub fn createFunction(
1197 const sym_index = try zig_object.allocateSymbol(gpa);1180 const sym_index = try zig_object.allocateSymbol(gpa);
1198 const sym = zig_object.symbol(sym_index);1181 const sym = zig_object.symbol(sym_index);
1199 sym.tag = .function;1182 sym.tag = .function;
1200 sym.name = try zig_object.string_table.insert(gpa, symbol_name);1183 sym.name = try wasm.internString(symbol_name);
1201 const type_index = try zig_object.putOrGetFuncType(gpa, func_ty);1184 const type_index = try zig_object.putOrGetFuncType(gpa, func_ty);
1202 sym.index = try zig_object.appendFunction(gpa, .{ .type_index = type_index });1185 sym.index = try zig_object.appendFunction(gpa, .{ .type_index = type_index });
12031186
...@@ -1244,7 +1227,6 @@ const Dwarf = @import("../Dwarf.zig");...@@ -1244,7 +1227,6 @@ const Dwarf = @import("../Dwarf.zig");
1244const InternPool = @import("../../InternPool.zig");1227const InternPool = @import("../../InternPool.zig");
1245const Liveness = @import("../../Liveness.zig");1228const Liveness = @import("../../Liveness.zig");
1246const Zcu = @import("../../Zcu.zig");1229const Zcu = @import("../../Zcu.zig");
1247const StringTable = @import("../StringTable.zig");
1248const Symbol = @import("Symbol.zig");1230const Symbol = @import("Symbol.zig");
1249const Type = @import("../../Type.zig");1231const Type = @import("../../Type.zig");
1250const Value = @import("../../Value.zig");1232const Value = @import("../../Value.zig");