diff --git a/src/Compilation.zig b/src/Compilation.zig index 67dcbd5a3a..fd8fd357f4 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -1587,6 +1587,7 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil .pdb_source_path = options.pdb_source_path, .pdb_out_path = options.pdb_out_path, .entry_addr = null, // CLI does not expose this option (yet?) + .object_host_name = null, // TODO expose in the CLI }; switch (options.cache_mode) { diff --git a/src/link.zig b/src/link.zig index f3685a6b8b..5a9cd5a7e4 100644 --- a/src/link.zig +++ b/src/link.zig @@ -400,6 +400,7 @@ pub const File = struct { export_table: bool, initial_memory: ?u64, max_memory: ?u64, + object_host_name: ?[]const u8, export_symbol_names: []const []const u8, global_base: ?u64, build_id: std.zig.BuildId, diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig index fa64c4e627..36849cda18 100644 --- a/src/link/Wasm.zig +++ b/src/link/Wasm.zig @@ -150,10 +150,10 @@ nav_fixups: std.ArrayListUnmanaged(NavFixup) = .empty, symbol_table: std.AutoArrayHashMapUnmanaged(String, void) = .empty, /// When importing objects from the host environment, a name must be supplied. -/// LLVM uses "env" by default when none is given. This would be a good default for Zig -/// to support existing code. -/// TODO: Allow setting this through a flag? -host_name: String, +/// LLVM uses "env" by default when none is given. +/// This value is passed to object files since wasm tooling conventions provides +/// no way to specify the module name in the symbol table. +object_host_name: OptionalString, /// Memory section memories: std.wasm.Memory = .{ .limits = .{ @@ -737,7 +737,7 @@ const DebugSection = struct {}; pub const FunctionImport = extern struct { flags: SymbolFlags, - module_name: String, + module_name: OptionalString, source_location: SourceLocation, resolution: Resolution, type: FunctionType.Index, @@ -862,7 +862,7 @@ pub const FunctionImport = extern struct { return index.key(wasm).*; } - pub fn moduleName(index: Index, wasm: *const Wasm) String { + pub fn moduleName(index: Index, wasm: *const Wasm) OptionalString { return index.value(wasm).module_name; } @@ -888,7 +888,7 @@ pub const Function = extern struct { pub const GlobalImport = extern struct { flags: SymbolFlags, - module_name: String, + module_name: OptionalString, source_location: SourceLocation, resolution: Resolution, @@ -1009,7 +1009,7 @@ pub const GlobalImport = extern struct { return index.key(wasm).*; } - pub fn moduleName(index: Index, wasm: *const Wasm) String { + pub fn moduleName(index: Index, wasm: *const Wasm) OptionalString { return index.value(wasm).module_name; } @@ -1114,7 +1114,7 @@ pub const TableImport = extern struct { return index.key(wasm).*; } - pub fn moduleName(index: Index, wasm: *const Wasm) String { + pub fn moduleName(index: Index, wasm: *const Wasm) OptionalString { return index.value(wasm).module_name; } }; @@ -1604,7 +1604,7 @@ pub const ZcuImportIndex = enum(u32) { return wasm.getExistingString(name_slice).?; } - pub fn moduleName(index: ZcuImportIndex, wasm: *const Wasm) String { + pub fn moduleName(index: ZcuImportIndex, wasm: *const Wasm) OptionalString { const zcu = wasm.base.comp.zcu.?; const ip = &zcu.intern_pool; const nav_index = index.ptr(wasm).*; @@ -1613,8 +1613,8 @@ pub const ZcuImportIndex = enum(u32) { .@"extern" => |*ext| ext, else => unreachable, }; - const lib_name = ext.lib_name.toSlice(ip) orelse return wasm.host_name; - return wasm.getExistingString(lib_name).?; + const lib_name = ext.lib_name.toSlice(ip) orelse return .none; + return wasm.getExistingString(lib_name).?.toOptional(); } pub fn functionType(index: ZcuImportIndex, wasm: *Wasm) FunctionType.Index { @@ -1639,8 +1639,8 @@ pub const ZcuImportIndex = enum(u32) { } }; -/// 0. Index into `object_function_imports`. -/// 1. Index into `imports`. +/// 0. Index into `Wasm.object_function_imports`. +/// 1. Index into `Wasm.imports`. pub const FunctionImportId = enum(u32) { _, @@ -1695,7 +1695,7 @@ pub const FunctionImportId = enum(u32) { }; } - pub fn moduleName(id: FunctionImportId, wasm: *const Wasm) String { + pub fn moduleName(id: FunctionImportId, wasm: *const Wasm) OptionalString { return switch (unpack(id, wasm)) { inline .object_function_import, .zcu_import => |i| i.moduleName(wasm), }; @@ -1706,6 +1706,24 @@ pub const FunctionImportId = enum(u32) { inline .object_function_import, .zcu_import => |i| i.functionType(wasm), }; } + + /// Asserts not emitting an object, and `Wasm.import_symbols` is false. + pub fn undefinedAllowed(id: FunctionImportId, wasm: *const Wasm) bool { + assert(!wasm.import_symbols); + assert(wasm.base.comp.config.output_mode != .Obj); + return switch (unpack(id, wasm)) { + .object_function_import => |i| { + const import = i.value(wasm); + return import.flags.binding == .strong and import.module_name != .none; + }, + .zcu_import => |i| { + const zcu = wasm.base.comp.zcu.?; + const ip = &zcu.intern_pool; + const ext = ip.getNav(i.ptr(wasm).*).toExtern(ip).?; + return !ext.is_weak_linkage and ext.lib_name != .none; + }, + }; + } }; /// 0. Index into `object_global_imports`. @@ -1760,7 +1778,7 @@ pub const GlobalImportId = enum(u32) { }; } - pub fn moduleName(id: GlobalImportId, wasm: *const Wasm) String { + pub fn moduleName(id: GlobalImportId, wasm: *const Wasm) OptionalString { return switch (unpack(id, wasm)) { inline .object_global_import, .zcu_import => |i| i.moduleName(wasm), }; @@ -2082,7 +2100,7 @@ pub fn createEmpty( .entry_name = undefined, .dump_argv_list = .empty, - .host_name = undefined, + .object_host_name = .none, .preloaded_strings = undefined, }; if (use_llvm and comp.config.have_zcu) { @@ -2090,7 +2108,7 @@ pub fn createEmpty( } errdefer wasm.base.destroy(); - wasm.host_name = try wasm.internString("env"); + if (options.object_host_name) |name| wasm.object_host_name = (try wasm.internString(name)).toOptional(); inline for (@typeInfo(PreloadedStrings).@"struct".fields) |field| { @field(wasm.preloaded_strings, field.name) = try wasm.internString(field.name); @@ -2162,7 +2180,7 @@ fn parseObject(wasm: *Wasm, obj: link.Input.Object) !void { var ss: Object.ScratchSpace = .{}; defer ss.deinit(gpa); - const object = try Object.parse(wasm, file_contents, obj.path, null, wasm.host_name, &ss, obj.must_link, gc_sections); + const object = try Object.parse(wasm, file_contents, obj.path, null, wasm.object_host_name, &ss, obj.must_link, gc_sections); wasm.objects.appendAssumeCapacity(object); } @@ -2201,7 +2219,7 @@ fn parseArchive(wasm: *Wasm, obj: link.Input.Object) !void { try wasm.objects.ensureUnusedCapacity(gpa, offsets.count()); for (offsets.keys()) |file_offset| { const contents = file_contents[file_offset..]; - const object = try archive.parseObject(wasm, contents, obj.path, wasm.host_name, &ss, obj.must_link, gc_sections); + const object = try archive.parseObject(wasm, contents, obj.path, wasm.object_host_name, &ss, obj.must_link, gc_sections); wasm.objects.appendAssumeCapacity(object); } } @@ -2313,6 +2331,7 @@ pub fn updateNav(wasm: *Wasm, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index assert(!wasm.navs_exe.contains(nav_index)); } const name = try wasm.internString(ext.name.toSlice(ip)); + if (ext.lib_name.toSlice(ip)) |ext_name| _ = try wasm.internString(ext_name); try wasm.imports.ensureUnusedCapacity(gpa, 1); if (ip.isFunctionType(nav.typeOf(ip))) { try wasm.function_imports.ensureUnusedCapacity(gpa, 1); diff --git a/src/link/Wasm/Archive.zig b/src/link/Wasm/Archive.zig index 97c654211f..8cb494d305 100644 --- a/src/link/Wasm/Archive.zig +++ b/src/link/Wasm/Archive.zig @@ -147,7 +147,7 @@ pub fn parseObject( wasm: *Wasm, file_contents: []const u8, path: Path, - host_name: Wasm.String, + host_name: Wasm.OptionalString, scratch_space: *Object.ScratchSpace, must_link: bool, gc_sections: bool, diff --git a/src/link/Wasm/Flush.zig b/src/link/Wasm/Flush.zig index 1df665f0c0..41f866178d 100644 --- a/src/link/Wasm/Flush.zig +++ b/src/link/Wasm/Flush.zig @@ -105,6 +105,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { if (!allow_undefined) { for (f.function_imports.keys(), f.function_imports.values()) |name, function_import_id| { + if (function_import_id.undefinedAllowed(wasm)) continue; const src_loc = function_import_id.sourceLocation(wasm); src_loc.addError(wasm, "undefined function: {s}", .{name.slice(wasm)}); } @@ -403,7 +404,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { const header_offset = try reserveVecSectionHeader(gpa, binary_bytes); for (f.function_imports.values()) |id| { - const module_name = id.moduleName(wasm).slice(wasm); + const module_name = id.moduleName(wasm).slice(wasm).?; try leb.writeUleb128(binary_writer, @as(u32, @intCast(module_name.len))); try binary_writer.writeAll(module_name); @@ -437,7 +438,8 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { total_imports += 1; } else if (import_memory) { try emitMemoryImport(wasm, binary_bytes, &.{ - .module_name = wasm.host_name, + // TODO the import_memory option needs to specify from which module + .module_name = wasm.object_host_name.unwrap().?, .name = if (is_obj) wasm.preloaded_strings.__linear_memory else wasm.preloaded_strings.memory, .limits_min = wasm.memories.limits.min, .limits_max = wasm.memories.limits.max, @@ -448,7 +450,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { } for (f.global_imports.values()) |id| { - const module_name = id.moduleName(wasm).slice(wasm); + const module_name = id.moduleName(wasm).slice(wasm).?; try leb.writeUleb128(binary_writer, @as(u32, @intCast(module_name.len))); try binary_writer.writeAll(module_name); diff --git a/src/link/Wasm/Object.zig b/src/link/Wasm/Object.zig index edf041445a..5dd755fe54 100644 --- a/src/link/Wasm/Object.zig +++ b/src/link/Wasm/Object.zig @@ -179,7 +179,7 @@ pub fn parse( bytes: []const u8, path: Path, archive_member_name: ?[]const u8, - host_name: Wasm.String, + host_name: Wasm.OptionalString, ss: *ScratchSpace, must_link: bool, gc_sections: bool, @@ -560,7 +560,7 @@ pub fn parse( .mutable = mutable, }, }, - .module_name = interned_module_name, + .module_name = interned_module_name.toOptional(), .source_location = source_location, .resolution = .unresolved, });