diff --git a/src/Compilation.zig b/src/Compilation.zig index 5827fb8306..c955fdba64 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -3066,7 +3066,7 @@ pub fn saveState(comp: *Compilation) !void { .wasm => { const wasm = lf.cast(.wasm).?; const is_obj = comp.config.output_mode == .Obj; - try bufs.ensureUnusedCapacity(83); + try bufs.ensureUnusedCapacity(85); addBuf(&bufs, wasm.string_bytes.items); // TODO make it well-defined memory layout //addBuf(&bufs, mem.sliceAsBytes(wasm.objects.items)); @@ -3133,6 +3133,8 @@ pub fn saveState(comp: *Compilation) !void { addBuf(&bufs, mem.sliceAsBytes(wasm.missing_exports.keys())); addBuf(&bufs, mem.sliceAsBytes(wasm.function_exports.keys())); addBuf(&bufs, mem.sliceAsBytes(wasm.function_exports.values())); + addBuf(&bufs, mem.sliceAsBytes(wasm.hidden_function_exports.keys())); + addBuf(&bufs, mem.sliceAsBytes(wasm.hidden_function_exports.values())); addBuf(&bufs, mem.sliceAsBytes(wasm.global_exports.items)); addBuf(&bufs, mem.sliceAsBytes(wasm.functions.keys())); addBuf(&bufs, mem.sliceAsBytes(wasm.function_imports.keys())); diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig index f84ea3ca7f..cdb467a113 100644 --- a/src/link/Wasm.zig +++ b/src/link/Wasm.zig @@ -210,8 +210,7 @@ entry_resolution: FunctionImport.Resolution = .unresolved, /// Empty when outputting an object. function_exports: std.AutoArrayHashMapUnmanaged(String, FunctionIndex) = .empty, -/// Tracks the value at the end of prelink. -function_exports_len: u32 = 0, +hidden_function_exports: std.AutoArrayHashMapUnmanaged(String, FunctionIndex) = .empty, global_exports: std.ArrayListUnmanaged(GlobalExport) = .empty, /// Tracks the value at the end of prelink. global_exports_len: u32 = 0, @@ -360,9 +359,8 @@ pub const FunctionIndex = enum(u32) { if (wasm.object_function_imports.getPtr(name)) |import| { return fromResolution(wasm, import.resolution); } - if (wasm.function_exports.get(name)) |index| { - return index; - } + if (wasm.function_exports.get(name)) |index| return index; + if (wasm.hidden_function_exports.get(name)) |index| return index; return null; } @@ -1919,8 +1917,11 @@ pub const DataSegmentId = enum(u32) { const zcu = wasm.base.comp.zcu.?; const ip = &zcu.intern_pool; const nav = ip.getNav(i.key(wasm).*); - return nav.getLinkSection().toSlice(ip) orelse - if (nav.isThreadlocal(ip)) ".tdata" else ".data"; + return nav.getLinkSection().toSlice(ip) orelse switch (category(id, wasm)) { + .tls => ".tdata", + .data => ".data", + .zero => ".bss", + }; }, }; } @@ -3110,6 +3111,7 @@ pub fn deinit(wasm: *Wasm) void { wasm.func_types.deinit(gpa); wasm.function_exports.deinit(gpa); + wasm.hidden_function_exports.deinit(gpa); wasm.function_imports.deinit(gpa); wasm.functions.deinit(gpa); wasm.globals.deinit(gpa); @@ -3417,7 +3419,6 @@ pub fn prelink(wasm: *Wasm, prog_node: std.Progress.Node) link.File.FlushError!v } } wasm.functions_end_prelink = @intCast(wasm.functions.entries.len); - wasm.function_exports_len = @intCast(wasm.function_exports.entries.len); for (wasm.object_global_imports.keys(), wasm.object_global_imports.values(), 0..) |name, *import, i| { if (import.flags.isIncluded(rdynamic)) { @@ -3491,8 +3492,14 @@ fn markFunction(wasm: *Wasm, i: ObjectFunctionIndex) link.File.FlushError!void { const function = i.ptr(wasm); markObject(wasm, function.object_index); - if (!is_obj and function.flags.isExported(rdynamic)) - try wasm.function_exports.put(gpa, function.name.unwrap().?, @enumFromInt(gop.index)); + if (!is_obj and function.flags.isExported(rdynamic)) { + const symbol_name = function.name.unwrap().?; + if (function.flags.visibility_hidden) { + try wasm.hidden_function_exports.put(gpa, symbol_name, @enumFromInt(gop.index)); + } else { + try wasm.function_exports.put(gpa, symbol_name, @enumFromInt(gop.index)); + } + } try wasm.markRelocations(function.relocations(wasm)); } @@ -3778,6 +3785,9 @@ pub fn flushModule( const function_exports_end_zcu: u32 = @intCast(wasm.function_exports.entries.len); defer wasm.function_exports.shrinkRetainingCapacity(function_exports_end_zcu); + const hidden_function_exports_end_zcu: u32 = @intCast(wasm.hidden_function_exports.entries.len); + defer wasm.hidden_function_exports.shrinkRetainingCapacity(hidden_function_exports_end_zcu); + wasm.flush_buffer.clear(); try wasm.flush_buffer.missing_exports.reinit(gpa, wasm.missing_exports.keys(), &.{}); try wasm.flush_buffer.function_imports.reinit(gpa, wasm.function_imports.keys(), wasm.function_imports.values()); diff --git a/src/link/Wasm/Flush.zig b/src/link/Wasm/Flush.zig index dc0c713ff1..6cf283742b 100644 --- a/src/link/Wasm/Flush.zig +++ b/src/link/Wasm/Flush.zig @@ -164,10 +164,14 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { } } - for (wasm.nav_exports.keys()) |*nav_export| { + for (wasm.nav_exports.keys(), wasm.nav_exports.values()) |*nav_export, export_index| { if (ip.isFunctionType(ip.getNav(nav_export.nav_index).typeOf(ip))) { log.debug("flush export '{s}' nav={d}", .{ nav_export.name.slice(wasm), nav_export.nav_index }); - try wasm.function_exports.put(gpa, nav_export.name, Wasm.FunctionIndex.fromIpNav(wasm, nav_export.nav_index).?); + const function_index = Wasm.FunctionIndex.fromIpNav(wasm, nav_export.nav_index).?; + switch (export_index.ptr(zcu).opts.visibility) { + .default, .protected => try wasm.function_exports.put(gpa, nav_export.name, function_index), + .hidden => try wasm.hidden_function_exports.put(gpa, nav_export.name, function_index), + } _ = f.missing_exports.swapRemove(nav_export.name); _ = f.function_imports.swapRemove(nav_export.name); diff --git a/test/link/wasm/bss/build.zig b/test/link/wasm/bss/build.zig index d73c7ed757..2d4cf84b62 100644 --- a/test/link/wasm/bss/build.zig +++ b/test/link/wasm/bss/build.zig @@ -47,16 +47,14 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize_mode: std.builtin.Opt check_lib.checkInHeaders(); check_lib.checkExact("Section custom"); check_lib.checkExact("type data_segment"); - check_lib.checkExact("names 2"); - check_lib.checkExact("index 0"); - check_lib.checkExact("name .rodata"); + check_lib.checkExact("names 1"); // for safe optimization modes `undefined` is stored in data instead of bss. if (is_safe) { - check_lib.checkExact("index 1"); + check_lib.checkExact("index 0"); check_lib.checkExact("name .data"); check_lib.checkNotPresent("name .bss"); } else { - check_lib.checkExact("index 1"); // bss section always last + check_lib.checkExact("index 0"); // bss section always last check_lib.checkExact("name .bss"); } test_step.dependOn(&check_lib.step); @@ -84,10 +82,8 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize_mode: std.builtin.Opt check_lib.checkInHeaders(); check_lib.checkExact("Section custom"); check_lib.checkExact("type data_segment"); - check_lib.checkExact("names 2"); + check_lib.checkExact("names 1"); check_lib.checkExact("index 0"); - check_lib.checkExact("name .rodata"); - check_lib.checkExact("index 1"); check_lib.checkExact("name .bss"); test_step.dependOn(&check_lib.step); diff --git a/test/link/wasm/bss/lib.zig b/test/link/wasm/bss/lib.zig index c1691c608e..5a05d4d6e2 100644 --- a/test/link/wasm/bss/lib.zig +++ b/test/link/wasm/bss/lib.zig @@ -1,5 +1,9 @@ pub var bss: u32 = undefined; -export fn foo() void { - _ = bss; +fn foo() callconv(.c) u32 { + return bss; +} + +comptime { + @export(&foo, .{ .name = "foo", .visibility = .hidden }); } diff --git a/test/link/wasm/bss/lib2.zig b/test/link/wasm/bss/lib2.zig index 9f43128880..2cf1ef87da 100644 --- a/test/link/wasm/bss/lib2.zig +++ b/test/link/wasm/bss/lib2.zig @@ -1,5 +1,9 @@ pub var bss: u32 = 0; -export fn foo() void { - _ = bss; +fn foo() callconv(.c) u32 { + return bss; +} + +comptime { + @export(&foo, .{ .name = "foo", .visibility = .hidden }); }