authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-11-01 02:16:36-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2024-11-01 02:16:36-07:00
logd30e287543ff525cf62ecf7f4cfcd20fee23a8ee
tree0b83c082e5505451b342d479ee485d5580f41c48
parenta99449d8bebfe551ae4bf91fefd11ec4512cf417
parente501cf51a01f6f0ae4326180cdd4274588ceed1d
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #21874 from ziglang/wasm-linker

link.File.Wasm: unify the string tables

5 files changed, 462 insertions(+), 503 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+30-44
...@@ -1,5 +1,3 @@...@@ -1,5 +1,3 @@
1header: ar_hdr,
2
3/// A list of long file names, delimited by a LF character (0x0a).1/// A list of long file names, delimited by a LF character (0x0a).
4/// This is stored as a single slice of bytes, as the header-names2/// This is stored as a single slice of bytes, as the header-names
5/// point to the character index of a file name, rather than the index3/// point to the character index of a file name, rather than the index
...@@ -14,65 +12,54 @@ toc: Toc,...@@ -14,65 +12,54 @@ toc: Toc,
14const Toc = std.StringArrayHashMapUnmanaged(std.ArrayListUnmanaged(u32));12const Toc = std.StringArrayHashMapUnmanaged(std.ArrayListUnmanaged(u32));
1513
16// Archive files start with the ARMAG identifying string. Then follows a14// Archive files start with the ARMAG identifying string. Then follows a
17// `struct ar_hdr', and as many bytes of member file data as its `ar_size'15// `struct Header', and as many bytes of member file data as its `size'
18// member indicates, for each member file.16// member indicates, for each member file.
19/// String that begins an archive file.17/// String that begins an archive file.
20const ARMAG: *const [SARMAG:0]u8 = "!<arch>\n";18const ARMAG: *const [SARMAG:0]u8 = "!<arch>\n";
21/// Size of that string.19/// Size of that string.
22const SARMAG: u4 = 8;20const SARMAG: u4 = 8;
2321
24/// String in ar_fmag at the end of each header.22/// String in fmag at the end of each header.
25const ARFMAG: *const [2:0]u8 = "`\n";23const ARFMAG: *const [2:0]u8 = "`\n";
2624
27const ar_hdr = extern struct {25const Header = extern struct {
28 /// Member file name, sometimes / terminated.26 /// Member file name, sometimes / terminated.
29 ar_name: [16]u8,27 name: [16]u8,
30
31 /// File date, decimal seconds since Epoch.28 /// File date, decimal seconds since Epoch.
32 ar_date: [12]u8,29 date: [12]u8,
33
34 /// User ID, in ASCII format.30 /// User ID, in ASCII format.
35 ar_uid: [6]u8,31 uid: [6]u8,
36
37 /// Group ID, in ASCII format.32 /// Group ID, in ASCII format.
38 ar_gid: [6]u8,33 gid: [6]u8,
39
40 /// File mode, in ASCII octal.34 /// File mode, in ASCII octal.
41 ar_mode: [8]u8,35 mode: [8]u8,
42
43 /// File size, in ASCII decimal.36 /// File size, in ASCII decimal.
44 ar_size: [10]u8,37 size: [10]u8,
45
46 /// Always contains ARFMAG.38 /// Always contains ARFMAG.
47 ar_fmag: [2]u8,39 fmag: [2]u8,
4840
49 const NameOrIndex = union(enum) {41 const NameOrIndex = union(enum) {
50 name: []const u8,42 name: []const u8,
51 index: u32,43 index: u32,
52 };44 };
5345
54 fn nameOrIndex(archive: ar_hdr) !NameOrIndex {46 fn nameOrIndex(archive: Header) !NameOrIndex {
55 const value = getValue(&archive.ar_name);47 const value = getValue(&archive.name);
56 const slash_index = mem.indexOfScalar(u8, value, '/') orelse return error.MalformedArchive;48 const slash_index = mem.indexOfScalar(u8, value, '/') orelse return error.MalformedArchive;
57 const len = value.len;49 const len = value.len;
58 if (slash_index == len - 1) {50 if (slash_index == len - 1) {
59 // Name stored directly51 // Name stored directly
60 return NameOrIndex{ .name = value };52 return .{ .name = value };
61 } else {53 } else {
62 // Name follows the header directly and its length is encoded in54 // Name follows the header directly and its length is encoded in
63 // the name field.55 // the name field.
64 const index = try std.fmt.parseInt(u32, value[slash_index + 1 ..], 10);56 const index = try std.fmt.parseInt(u32, value[slash_index + 1 ..], 10);
65 return NameOrIndex{ .index = index };57 return .{ .index = index };
66 }58 }
67 }59 }
6860
69 fn date(archive: ar_hdr) !u64 {61 fn parsedSize(archive: Header) !u32 {
70 const value = getValue(&archive.ar_date);62 const value = getValue(&archive.size);
71 return std.fmt.parseInt(u64, value, 10);
72 }
73
74 fn size(archive: ar_hdr) !u32 {
75 const value = getValue(&archive.ar_size);
76 return std.fmt.parseInt(u32, value, 10);63 return std.fmt.parseInt(u32, value, 10);
77 }64 }
7865
...@@ -100,8 +87,8 @@ pub fn parse(gpa: Allocator, file_contents: []const u8) !Archive {...@@ -100,8 +87,8 @@ pub fn parse(gpa: Allocator, file_contents: []const u8) !Archive {
100 const magic = try reader.readBytesNoEof(SARMAG);87 const magic = try reader.readBytesNoEof(SARMAG);
101 if (!mem.eql(u8, &magic, ARMAG)) return error.BadArchiveMagic;88 if (!mem.eql(u8, &magic, ARMAG)) return error.BadArchiveMagic;
10289
103 const header = try reader.readStruct(ar_hdr);90 const header = try reader.readStruct(Header);
104 if (!mem.eql(u8, &header.ar_fmag, ARFMAG)) return error.BadHeaderDelimiter;91 if (!mem.eql(u8, &header.fmag, ARFMAG)) return error.BadHeaderDelimiter;
10592
106 var toc = try parseTableOfContents(gpa, header, reader);93 var toc = try parseTableOfContents(gpa, header, reader);
107 errdefer deinitToc(gpa, &toc);94 errdefer deinitToc(gpa, &toc);
...@@ -110,13 +97,12 @@ pub fn parse(gpa: Allocator, file_contents: []const u8) !Archive {...@@ -110,13 +97,12 @@ pub fn parse(gpa: Allocator, file_contents: []const u8) !Archive {
110 errdefer gpa.free(long_file_names);97 errdefer gpa.free(long_file_names);
11198
112 return .{99 return .{
113 .header = header,
114 .toc = toc,100 .toc = toc,
115 .long_file_names = long_file_names,101 .long_file_names = long_file_names,
116 };102 };
117}103}
118104
119fn parseName(archive: *const Archive, header: ar_hdr) ![]const u8 {105fn parseName(archive: *const Archive, header: Header) ![]const u8 {
120 const name_or_index = try header.nameOrIndex();106 const name_or_index = try header.nameOrIndex();
121 switch (name_or_index) {107 switch (name_or_index) {
122 .name => |name| return name,108 .name => |name| return name,
...@@ -127,10 +113,10 @@ fn parseName(archive: *const Archive, header: ar_hdr) ![]const u8 {...@@ -127,10 +113,10 @@ fn parseName(archive: *const Archive, header: ar_hdr) ![]const u8 {
127 }113 }
128}114}
129115
130fn parseTableOfContents(gpa: Allocator, header: ar_hdr, reader: anytype) !Toc {116fn parseTableOfContents(gpa: Allocator, header: Header, reader: anytype) !Toc {
131 // size field can have extra spaces padded in front as well as the end,117 // size field can have extra spaces padded in front as well as the end,
132 // so we trim those first before parsing the ASCII value.118 // so we trim those first before parsing the ASCII value.
133 const size_trimmed = mem.trim(u8, &header.ar_size, " ");119 const size_trimmed = mem.trim(u8, &header.size, " ");
134 const sym_tab_size = try std.fmt.parseInt(u32, size_trimmed, 10);120 const sym_tab_size = try std.fmt.parseInt(u32, size_trimmed, 10);
135121
136 const num_symbols = try reader.readInt(u32, .big);122 const num_symbols = try reader.readInt(u32, .big);
...@@ -170,14 +156,14 @@ fn parseTableOfContents(gpa: Allocator, header: ar_hdr, reader: anytype) !Toc {...@@ -170,14 +156,14 @@ fn parseTableOfContents(gpa: Allocator, header: ar_hdr, reader: anytype) !Toc {
170}156}
171157
172fn parseNameTable(gpa: Allocator, reader: anytype) ![]const u8 {158fn parseNameTable(gpa: Allocator, reader: anytype) ![]const u8 {
173 const header: ar_hdr = try reader.readStruct(ar_hdr);159 const header: Header = try reader.readStruct(Header);
174 if (!mem.eql(u8, &header.ar_fmag, ARFMAG)) {160 if (!mem.eql(u8, &header.fmag, ARFMAG)) {
175 return error.InvalidHeaderDelimiter;161 return error.InvalidHeaderDelimiter;
176 }162 }
177 if (!mem.eql(u8, header.ar_name[0..2], "//")) {163 if (!mem.eql(u8, header.name[0..2], "//")) {
178 return error.MissingTableName;164 return error.MissingTableName;
179 }165 }
180 const table_size = try header.size();166 const table_size = try header.parsedSize();
181 const long_file_names = try gpa.alloc(u8, table_size);167 const long_file_names = try gpa.alloc(u8, table_size);
182 errdefer gpa.free(long_file_names);168 errdefer gpa.free(long_file_names);
183 try reader.readNoEof(long_file_names);169 try reader.readNoEof(long_file_names);
...@@ -187,16 +173,16 @@ fn parseNameTable(gpa: Allocator, reader: anytype) ![]const u8 {...@@ -187,16 +173,16 @@ fn parseNameTable(gpa: Allocator, reader: anytype) ![]const u8 {
187173
188/// From a given file offset, starts reading for a file header.174/// From a given file offset, starts reading for a file header.
189/// 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.
190pub 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 {
191 var fbs = std.io.fixedBufferStream(file_contents);177 var fbs = std.io.fixedBufferStream(file_contents);
192 const header = try fbs.reader().readStruct(ar_hdr);178 const header = try fbs.reader().readStruct(Header);
193179
194 if (!mem.eql(u8, &header.ar_fmag, ARFMAG)) return error.BadArchiveHeaderDelimiter;180 if (!mem.eql(u8, &header.fmag, ARFMAG)) return error.BadArchiveHeaderDelimiter;
195181
196 const object_name = try archive.parseName(header);182 const object_name = try archive.parseName(header);
197 const object_file_size = try header.size();183 const object_file_size = try header.parsedSize();
198184
199 return Object.create(wasm, file_contents[@sizeOf(ar_hdr)..][0..object_file_size], path, object_name);185 return Object.create(wasm, file_contents[@sizeOf(Header)..][0..object_file_size], path, object_name);
200}186}
201187
202const std = @import("std");188const std = @import("std");
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");