authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2023-03-19 15:42:39+01:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-03-19 15:42:39+01:00
log322ace70f9fb5c3e8833255d1df033208c448349
tree1fbb00c9ca79b1c7bcb0cf16d8fbc17a1bd0c668
parent8f481dfc3c4f12327499485e3bf10fbbb1023186
parentd0fb1ef9625b55cc71b41438265f596a00d63749
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #14838 from Luukdegram/bss-fix

wasm-linker: fix storing atoms in the correct segment

3 files changed, 91 insertions(+), 37 deletions(-)

src/link/Wasm.zig+12-3
...@@ -2828,22 +2828,31 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod...@@ -2828,22 +2828,31 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod
2828 const decl = mod.declPtr(entry.key_ptr.*);2828 const decl = mod.declPtr(entry.key_ptr.*);
2829 if (decl.isExtern()) continue;2829 if (decl.isExtern()) continue;
2830 const atom_index = entry.value_ptr.*;2830 const atom_index = entry.value_ptr.*;
2831 const atom = wasm.getAtomPtr(atom_index);
2831 if (decl.ty.zigTypeTag() == .Fn) {2832 if (decl.ty.zigTypeTag() == .Fn) {
2832 try wasm.parseAtom(atom_index, .function);2833 try wasm.parseAtom(atom_index, .function);
2833 } else if (decl.getVariable()) |variable| {2834 } else if (decl.getVariable()) |variable| {
2834 if (!variable.is_mutable) {2835 if (!variable.is_mutable) {
2835 try wasm.parseAtom(atom_index, .{ .data = .read_only });2836 try wasm.parseAtom(atom_index, .{ .data = .read_only });
2836 } else if (variable.init.isUndefDeep()) {2837 } else if (variable.init.isUndefDeep()) {
2837 try wasm.parseAtom(atom_index, .{ .data = .uninitialized });2838 // for safe build modes, we store the atom in the data segment,
2839 // whereas for unsafe build modes we store it in bss.
2840 const is_initialized = wasm.base.options.optimize_mode == .Debug or
2841 wasm.base.options.optimize_mode == .ReleaseSafe;
2842 try wasm.parseAtom(atom_index, .{ .data = if (is_initialized) .initialized else .uninitialized });
2838 } else {2843 } else {
2839 try wasm.parseAtom(atom_index, .{ .data = .initialized });2844 // when the decl is all zeroes, we store the atom in the bss segment,
2845 // in all other cases it will be in the data segment.
2846 const is_zeroes = for (atom.code.items) |byte| {
2847 if (byte != 0) break false;
2848 } else true;
2849 try wasm.parseAtom(atom_index, .{ .data = if (is_zeroes) .uninitialized else .initialized });
2840 }2850 }
2841 } else {2851 } else {
2842 try wasm.parseAtom(atom_index, .{ .data = .read_only });2852 try wasm.parseAtom(atom_index, .{ .data = .read_only });
2843 }2853 }
28442854
2845 // also parse atoms for a decl's locals2855 // also parse atoms for a decl's locals
2846 const atom = wasm.getAtomPtr(atom_index);
2847 for (atom.locals.items) |local_atom_index| {2856 for (atom.locals.items) |local_atom_index| {
2848 try wasm.parseAtom(local_atom_index, .{ .data = .read_only });2857 try wasm.parseAtom(local_atom_index, .{ .data = .read_only });
2849 }2858 }
test/link/wasm/bss/build.zig+74-34
...@@ -6,38 +6,78 @@ pub fn build(b: *std.Build) void {...@@ -6,38 +6,78 @@ pub fn build(b: *std.Build) void {
6 const test_step = b.step("test", "Test");6 const test_step = b.step("test", "Test");
7 b.default_step = test_step;7 b.default_step = test_step;
88
9 const lib = b.addSharedLibrary(.{9 add(b, test_step, .Debug, true);
10 .name = "lib",10 add(b, test_step, .ReleaseFast, false);
11 .root_source_file = .{ .path = "lib.zig" },11 add(b, test_step, .ReleaseSmall, false);
12 .target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding },12 add(b, test_step, .ReleaseSafe, true);
13 .optimize = .Debug,13}
14 });14
15 lib.use_llvm = false;15fn add(b: *std.Build, test_step: *std.Build.Step, optimize_mode: std.builtin.OptimizeMode, is_safe: bool) void {
16 lib.use_lld = false;16 {
17 lib.strip = false;17 const lib = b.addSharedLibrary(.{
18 // to make sure the bss segment is emitted, we must import memory18 .name = "lib",
19 lib.import_memory = true;19 .root_source_file = .{ .path = "lib.zig" },
20 lib.install();20 .target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding },
2121 .optimize = optimize_mode,
22 const check_lib = lib.checkObject();22 });
2323 lib.use_llvm = false;
24 // since we import memory, make sure it exists with the correct naming24 lib.use_lld = false;
25 check_lib.checkStart("Section import");25 lib.strip = false;
26 check_lib.checkNext("entries 1");26 // to make sure the bss segment is emitted, we must import memory
27 check_lib.checkNext("module env"); // default module name is "env"27 lib.import_memory = true;
28 check_lib.checkNext("name memory"); // as per linker specification28
2929 const check_lib = lib.checkObject();
30 // since we are importing memory, ensure it's not exported30
31 check_lib.checkNotPresent("Section export");31 // since we import memory, make sure it exists with the correct naming
3232 check_lib.checkStart("Section import");
33 // validate the name of the stack pointer33 check_lib.checkNext("entries 1");
34 check_lib.checkStart("Section custom");34 check_lib.checkNext("module env"); // default module name is "env"
35 check_lib.checkNext("type data_segment");35 check_lib.checkNext("name memory"); // as per linker specification
36 check_lib.checkNext("names 2");36
37 check_lib.checkNext("index 0");37 // since we are importing memory, ensure it's not exported
38 check_lib.checkNext("name .rodata");38 check_lib.checkNotPresent("Section export");
39 check_lib.checkNext("index 1"); // bss section always last39
40 check_lib.checkNext("name .bss");40 // validate the name of the stack pointer
4141 check_lib.checkStart("Section custom");
42 test_step.dependOn(&check_lib.step);42 check_lib.checkNext("type data_segment");
43 check_lib.checkNext("names 2");
44 check_lib.checkNext("index 0");
45 check_lib.checkNext("name .rodata");
46 // for safe optimization modes `undefined` is stored in data instead of bss.
47 if (is_safe) {
48 check_lib.checkNext("index 1");
49 check_lib.checkNext("name .data");
50 check_lib.checkNotPresent("name .bss");
51 } else {
52 check_lib.checkNext("index 1"); // bss section always last
53 check_lib.checkNext("name .bss");
54 }
55 test_step.dependOn(&check_lib.step);
56 }
57
58 // verify zero'd declaration is stored in bss for all optimization modes.
59 {
60 const lib = b.addSharedLibrary(.{
61 .name = "lib",
62 .root_source_file = .{ .path = "lib2.zig" },
63 .target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding },
64 .optimize = optimize_mode,
65 });
66 lib.use_llvm = false;
67 lib.use_lld = false;
68 lib.strip = false;
69 // to make sure the bss segment is emitted, we must import memory
70 lib.import_memory = true;
71
72 const check_lib = lib.checkObject();
73 check_lib.checkStart("Section custom");
74 check_lib.checkNext("type data_segment");
75 check_lib.checkNext("names 2");
76 check_lib.checkNext("index 0");
77 check_lib.checkNext("name .rodata");
78 check_lib.checkNext("index 1");
79 check_lib.checkNext("name .bss");
80
81 test_step.dependOn(&check_lib.step);
82 }
43}83}
test/link/wasm/bss/lib2.zig created+5
...@@ -0,0 +1,5 @@
1pub var bss: u32 = 0;
2
3export fn foo() void {
4 _ = bss;
5}