authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-11-05 18:44:12-05:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-11-05 18:44:12-05:00
log702b809ea3e9b9dbdc1fd6efe9306442487e7103
treebd639378ad2931013ff49789aadfc2104093261c
parentbec36aa7c028f2eaec94a2358f3e1326fcb9a30c
parentc893f837151d4764fd34911376836a01192b4d75
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #17815 from Luukdegram/wasm-no-entry

wasm-linker: implement `-fno-entry` and correctly pass `--shared` and `--pie` when given

21 files changed, 209 insertions(+), 130 deletions(-)

doc/langref.html.in+4-4
...@@ -11336,12 +11336,12 @@ all your base are belong to us{#end_shell_samp#}...@@ -11336,12 +11336,12 @@ all your base are belong to us{#end_shell_samp#}
11336 {#header_open|WebAssembly#}11336 {#header_open|WebAssembly#}
11337 <p>Zig supports building for WebAssembly out of the box.</p>11337 <p>Zig supports building for WebAssembly out of the box.</p>
11338 {#header_open|Freestanding#}11338 {#header_open|Freestanding#}
11339 <p>For host environments like the web browser and nodejs, build as a dynamic library using the freestanding11339 <p>For host environments like the web browser and nodejs, build as an executable using the freestanding
11340 OS target. Here's an example of running Zig code compiled to WebAssembly with nodejs.</p>11340 OS target. Here's an example of running Zig code compiled to WebAssembly with nodejs.</p>
11341 {#code_begin|lib|math#}11341 {#code_begin|exe|math#}
11342 {#target_wasm#}11342 {#target_wasm#}
11343 {#link_mode_dynamic#}11343 {#additonal_option|-fno-entry#}
11344 {#additonal_option|-rdynamic#}11344 {#additonal_option|--export=add#}
11345extern fn print(i32) void;11345extern fn print(i32) void;
1134611346
11347export fn add(a: i32, b: i32) void {11347export fn add(a: i32, b: i32) void {
lib/std/Build/Step/Compile.zig+21-4
...@@ -189,7 +189,8 @@ dll_export_fns: ?bool = null,...@@ -189,7 +189,8 @@ dll_export_fns: ?bool = null,
189189
190subsystem: ?std.Target.SubSystem = null,190subsystem: ?std.Target.SubSystem = null,
191191
192entry_symbol_name: ?[]const u8 = null,192/// How the linker must handle the entry point of the executable.
193entry: Entry = .default,
193194
194/// List of symbols forced as undefined in the symbol table195/// List of symbols forced as undefined in the symbol table
195/// thus forcing their resolution by the linker.196/// thus forcing their resolution by the linker.
...@@ -304,6 +305,18 @@ const FrameworkLinkInfo = struct {...@@ -304,6 +305,18 @@ const FrameworkLinkInfo = struct {
304 weak: bool = false,305 weak: bool = false,
305};306};
306307
308const Entry = union(enum) {
309 /// Let the compiler decide whether to make an entry point and what to name
310 /// it.
311 default,
312 /// The executable will have no entry point.
313 disabled,
314 /// The executable will have an entry point with the default symbol name.
315 enabled,
316 /// The executable will have an entry point with the specified symbol name.
317 symbol_name: []const u8,
318};
319
307pub const IncludeDir = union(enum) {320pub const IncludeDir = union(enum) {
308 path: LazyPath,321 path: LazyPath,
309 path_system: LazyPath,322 path_system: LazyPath,
...@@ -1418,9 +1431,13 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {...@@ -1418,9 +1431,13 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
1418 try zig_args.append(try std.fmt.allocPrint(b.allocator, "-ofmt={s}", .{@tagName(ofmt)}));1431 try zig_args.append(try std.fmt.allocPrint(b.allocator, "-ofmt={s}", .{@tagName(ofmt)}));
1419 }1432 }
14201433
1421 if (self.entry_symbol_name) |entry| {1434 switch (self.entry) {
1422 try zig_args.append("--entry");1435 .default => {},
1423 try zig_args.append(entry);1436 .disabled => try zig_args.append("-fno-entry"),
1437 .enabled => try zig_args.append("-fentry"),
1438 .symbol_name => |entry_name| {
1439 try zig_args.append(try std.fmt.allocPrint(b.allocator, "-fentry={s}", .{entry_name}));
1440 },
1424 }1441 }
14251442
1426 {1443 {
lib/std/start.zig+6-2
...@@ -82,11 +82,15 @@ comptime {...@@ -82,11 +82,15 @@ comptime {
82 .reactor => "_initialize",82 .reactor => "_initialize",
83 .command => "_start",83 .command => "_start",
84 };84 };
85 if (!@hasDecl(root, wasm_start_sym)) {85 if (!@hasDecl(root, wasm_start_sym) and @hasDecl(root, "main")) {
86 // Only call main when defined. For WebAssembly it's allowed to pass `-fno-entry` in which
87 // case it's not required to provide an entrypoint such as main.
86 @export(wasi_start, .{ .name = wasm_start_sym });88 @export(wasi_start, .{ .name = wasm_start_sym });
87 }89 }
88 } else if (native_arch.isWasm() and native_os == .freestanding) {90 } else if (native_arch.isWasm() and native_os == .freestanding) {
89 if (!@hasDecl(root, start_sym_name)) @export(wasm_freestanding_start, .{ .name = start_sym_name });91 // Only call main when defined. For WebAssembly it's allowed to pass `-fno-entry` in which
92 // case it's not required to provide an entrypoint such as main.
93 if (!@hasDecl(root, start_sym_name) and @hasDecl(root, "main")) @export(wasm_freestanding_start, .{ .name = start_sym_name });
90 } else if (native_os != .other and native_os != .freestanding) {94 } else if (native_os != .other and native_os != .freestanding) {
91 if (!@hasDecl(root, start_sym_name)) @export(_start, .{ .name = start_sym_name });95 if (!@hasDecl(root, start_sym_name)) @export(_start, .{ .name = start_sym_name });
92 }96 }
src/link/Wasm.zig+12-21
...@@ -2817,15 +2817,11 @@ fn setupExports(wasm: *Wasm) !void {...@@ -2817,15 +2817,11 @@ fn setupExports(wasm: *Wasm) !void {
2817}2817}
28182818
2819fn setupStart(wasm: *Wasm) !void {2819fn setupStart(wasm: *Wasm) !void {
2820 const entry_name = wasm.base.options.entry orelse "_start";2820 // do not export entry point if user set none or no default was set.
2821 const entry_name = wasm.base.options.entry orelse return;
28212822
2822 const symbol_loc = wasm.findGlobalSymbol(entry_name) orelse {2823 const symbol_loc = wasm.findGlobalSymbol(entry_name) orelse {
2823 if (wasm.base.options.output_mode == .Exe) {2824 log.err("Entry symbol '{s}' missing, use '-fno-entry' to suppress", .{entry_name});
2824 if (wasm.base.options.wasi_exec_model == .reactor) return; // Not required for reactors
2825 } else {
2826 return; // No entry point needed for non-executable wasm files
2827 }
2828 log.err("Entry symbol '{s}' missing", .{entry_name});
2829 return error.MissingSymbol;2825 return error.MissingSymbol;
2830 };2826 };
28312827
...@@ -4535,6 +4531,8 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !...@@ -4535,6 +4531,8 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !
4535 if (wasm.base.options.entry) |entry| {4531 if (wasm.base.options.entry) |entry| {
4536 try argv.append("--entry");4532 try argv.append("--entry");
4537 try argv.append(entry);4533 try argv.append(entry);
4534 } else {
4535 try argv.append("--no-entry");
4538 }4536 }
45394537
4540 // Increase the default stack size to a more reasonable value of 1MB instead of4538 // Increase the default stack size to a more reasonable value of 1MB instead of
...@@ -4544,24 +4542,17 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !...@@ -4544,24 +4542,17 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !
4544 const arg = try std.fmt.allocPrint(arena, "stack-size={d}", .{stack_size});4542 const arg = try std.fmt.allocPrint(arena, "stack-size={d}", .{stack_size});
4545 try argv.append(arg);4543 try argv.append(arg);
45464544
4547 if (wasm.base.options.output_mode == .Exe) {
4548 if (wasm.base.options.wasi_exec_model == .reactor) {
4549 // Reactor execution model does not have _start so lld doesn't look for it.
4550 try argv.append("--no-entry");
4551 // Make sure "_initialize" and other used-defined functions are exported if this is WASI reactor.
4552 // If rdynamic is true, it will already be appended, so only verify if the user did not specify
4553 // the flag in which case, we ensure `--export-dynamic` is called.
4554 if (!wasm.base.options.rdynamic) {
4555 try argv.append("--export-dynamic");
4556 }
4557 }
4558 } else if (wasm.base.options.entry == null) {
4559 try argv.append("--no-entry"); // So lld doesn't look for _start.
4560 }
4561 if (wasm.base.options.import_symbols) {4545 if (wasm.base.options.import_symbols) {
4562 try argv.append("--allow-undefined");4546 try argv.append("--allow-undefined");
4563 }4547 }
45644548
4549 if (wasm.base.options.output_mode == .Lib and wasm.base.options.link_mode == .Dynamic) {
4550 try argv.append("--shared");
4551 }
4552 if (wasm.base.options.pie) {
4553 try argv.append("--pie");
4554 }
4555
4565 // XXX - TODO: add when wasm-ld supports --build-id.4556 // XXX - TODO: add when wasm-ld supports --build-id.
4566 // if (wasm.base.options.build_id) {4557 // if (wasm.base.options.build_id) {
4567 // try argv.append("--build-id=tree");4558 // try argv.append("--build-id=tree");
src/main.zig+54-3
...@@ -519,7 +519,9 @@ const usage_build_generic =...@@ -519,7 +519,9 @@ const usage_build_generic =
519 \\ --dynamic-linker [path] Set the dynamic interpreter path (usually ld.so)519 \\ --dynamic-linker [path] Set the dynamic interpreter path (usually ld.so)
520 \\ --sysroot [path] Set the system root directory (usually /)520 \\ --sysroot [path] Set the system root directory (usually /)
521 \\ --version [ver] Dynamic library semver521 \\ --version [ver] Dynamic library semver
522 \\ --entry [name] Set the entrypoint symbol name522 \\ -fentry Enable entry point with default symbol name
523 \\ -fentry=[name] Override the entry point symbol name
524 \\ -fno-entry Do not output any entry point
523 \\ --force_undefined [name] Specify the symbol must be defined for the link to succeed525 \\ --force_undefined [name] Specify the symbol must be defined for the link to succeed
524 \\ -fsoname[=name] Override the default SONAME value526 \\ -fsoname[=name] Override the default SONAME value
525 \\ -fno-soname Disable emitting a SONAME527 \\ -fno-soname Disable emitting a SONAME
...@@ -845,6 +847,7 @@ fn buildOutputType(...@@ -845,6 +847,7 @@ fn buildOutputType(
845 var linker_import_symbols: bool = false;847 var linker_import_symbols: bool = false;
846 var linker_import_table: bool = false;848 var linker_import_table: bool = false;
847 var linker_export_table: bool = false;849 var linker_export_table: bool = false;
850 var linker_force_entry: ?bool = null;
848 var linker_initial_memory: ?u64 = null;851 var linker_initial_memory: ?u64 = null;
849 var linker_max_memory: ?u64 = null;852 var linker_max_memory: ?u64 = null;
850 var linker_shared_memory: bool = false;853 var linker_shared_memory: bool = false;
...@@ -1081,8 +1084,8 @@ fn buildOutputType(...@@ -1081,8 +1084,8 @@ fn buildOutputType(
1081 subsystem = try parseSubSystem(args_iter.nextOrFatal());1084 subsystem = try parseSubSystem(args_iter.nextOrFatal());
1082 } else if (mem.eql(u8, arg, "-O")) {1085 } else if (mem.eql(u8, arg, "-O")) {
1083 optimize_mode_string = args_iter.nextOrFatal();1086 optimize_mode_string = args_iter.nextOrFatal();
1084 } else if (mem.eql(u8, arg, "--entry")) {1087 } else if (mem.startsWith(u8, arg, "-fentry=")) {
1085 entry = args_iter.nextOrFatal();1088 entry = arg["-fentry=".len..];
1086 } else if (mem.eql(u8, arg, "--force_undefined")) {1089 } else if (mem.eql(u8, arg, "--force_undefined")) {
1087 try force_undefined_symbols.put(gpa, args_iter.nextOrFatal(), {});1090 try force_undefined_symbols.put(gpa, args_iter.nextOrFatal(), {});
1088 } else if (mem.eql(u8, arg, "--stack")) {1091 } else if (mem.eql(u8, arg, "--stack")) {
...@@ -1513,6 +1516,10 @@ fn buildOutputType(...@@ -1513,6 +1516,10 @@ fn buildOutputType(
1513 }1516 }
1514 } else if (mem.eql(u8, arg, "--import-memory")) {1517 } else if (mem.eql(u8, arg, "--import-memory")) {
1515 linker_import_memory = true;1518 linker_import_memory = true;
1519 } else if (mem.eql(u8, arg, "-fentry")) {
1520 linker_force_entry = true;
1521 } else if (mem.eql(u8, arg, "-fno-entry")) {
1522 linker_force_entry = false;
1516 } else if (mem.eql(u8, arg, "--export-memory")) {1523 } else if (mem.eql(u8, arg, "--export-memory")) {
1517 linker_export_memory = true;1524 linker_export_memory = true;
1518 } else if (mem.eql(u8, arg, "--import-symbols")) {1525 } else if (mem.eql(u8, arg, "--import-symbols")) {
...@@ -2144,6 +2151,8 @@ fn buildOutputType(...@@ -2144,6 +2151,8 @@ fn buildOutputType(
2144 linker_import_table = true;2151 linker_import_table = true;
2145 } else if (mem.eql(u8, arg, "--export-table")) {2152 } else if (mem.eql(u8, arg, "--export-table")) {
2146 linker_export_table = true;2153 linker_export_table = true;
2154 } else if (mem.eql(u8, arg, "--no-entry")) {
2155 linker_force_entry = false;
2147 } else if (mem.eql(u8, arg, "--initial-memory")) {2156 } else if (mem.eql(u8, arg, "--initial-memory")) {
2148 const next_arg = linker_args_it.nextOrFatal();2157 const next_arg = linker_args_it.nextOrFatal();
2149 linker_initial_memory = std.fmt.parseUnsigned(u32, eatIntPrefix(next_arg, 16), 16) catch |err| {2158 linker_initial_memory = std.fmt.parseUnsigned(u32, eatIntPrefix(next_arg, 16), 16) catch |err| {
...@@ -2606,6 +2615,23 @@ fn buildOutputType(...@@ -2606,6 +2615,23 @@ fn buildOutputType(
2606 link_libcpp = true;2615 link_libcpp = true;
2607 }2616 }
26082617
2618 if (linker_force_entry) |force| {
2619 if (!force) {
2620 entry = null;
2621 } else if (entry == null and output_mode == .Exe) {
2622 entry = switch (target_info.target.ofmt) {
2623 .coff => "wWinMainCRTStartup",
2624 .macho => "_main",
2625 .elf, .plan9 => "_start",
2626 .wasm => defaultWasmEntryName(wasi_exec_model),
2627 else => |tag| fatal("No default entry point available for output format {s}", .{@tagName(tag)}),
2628 };
2629 }
2630 } else if (entry == null and target_info.target.isWasm() and output_mode == .Exe) {
2631 // For WebAssembly the compiler defaults to setting the entry name when no flags are set.
2632 entry = defaultWasmEntryName(wasi_exec_model);
2633 }
2634
2609 if (target_info.target.ofmt == .coff) {2635 if (target_info.target.ofmt == .coff) {
2610 // Now that we know the target supports resources,2636 // Now that we know the target supports resources,
2611 // we can add the res files as link objects.2637 // we can add the res files as link objects.
...@@ -2628,6 +2654,23 @@ fn buildOutputType(...@@ -2628,6 +2654,23 @@ fn buildOutputType(
2628 if (single_threaded == null) {2654 if (single_threaded == null) {
2629 single_threaded = true;2655 single_threaded = true;
2630 }2656 }
2657 if (link_mode) |mode| {
2658 if (mode == .Dynamic) {
2659 if (linker_export_memory != null and linker_export_memory.?) {
2660 fatal("flags '-dynamic' and '--export-memory' are incompatible", .{});
2661 }
2662 // User did not supply `--export-memory` which is incompatible with -dynamic, therefore
2663 // set the flag to false to ensure it does not get enabled by default.
2664 linker_export_memory = false;
2665 }
2666 }
2667 if (wasi_exec_model != null and wasi_exec_model.? == .reactor) {
2668 if (entry) |entry_name| {
2669 if (!mem.eql(u8, "_initialize", entry_name)) {
2670 fatal("the entry symbol of the reactor model must be '_initialize', but found '{s}'", .{entry_name});
2671 }
2672 }
2673 }
2631 if (linker_shared_memory) {2674 if (linker_shared_memory) {
2632 if (output_mode == .Obj) {2675 if (output_mode == .Obj) {
2633 fatal("shared memory is not allowed in object files", .{});2676 fatal("shared memory is not allowed in object files", .{});
...@@ -7225,3 +7268,11 @@ fn createDependenciesModule(...@@ -7225,3 +7268,11 @@ fn createDependenciesModule(
7225 try main_mod.deps.put(arena, "@dependencies", deps_mod);7268 try main_mod.deps.put(arena, "@dependencies", deps_mod);
7226 return deps_mod;7269 return deps_mod;
7227}7270}
7271
7272fn defaultWasmEntryName(exec_model: ?std.builtin.WasiExecModel) []const u8 {
7273 const model = exec_model orelse .command;
7274 if (model == .reactor) {
7275 return "_initialize";
7276 }
7277 return "_start";
7278}
test/link/elf.zig+2-2
...@@ -658,7 +658,7 @@ fn testEntryPoint(b: *Build, opts: Options) *Step {...@@ -658,7 +658,7 @@ fn testEntryPoint(b: *Build, opts: Options) *Step {
658 const exe = addExecutable(b, "main", opts);658 const exe = addExecutable(b, "main", opts);
659 exe.addObject(a_o);659 exe.addObject(a_o);
660 exe.addObject(b_o);660 exe.addObject(b_o);
661 exe.entry_symbol_name = "foo";661 exe.entry = .{ .symbol_name = "foo" };
662662
663 const check = exe.checkObject();663 const check = exe.checkObject();
664 check.checkStart();664 check.checkStart();
...@@ -674,7 +674,7 @@ fn testEntryPoint(b: *Build, opts: Options) *Step {...@@ -674,7 +674,7 @@ fn testEntryPoint(b: *Build, opts: Options) *Step {
674 const exe = addExecutable(b, "other", opts);674 const exe = addExecutable(b, "other", opts);
675 exe.addObject(a_o);675 exe.addObject(a_o);
676 exe.addObject(b_o);676 exe.addObject(b_o);
677 exe.entry_symbol_name = "bar";677 exe.entry = .{ .symbol_name = "bar" };
678678
679 const check = exe.checkObject();679 const check = exe.checkObject();
680 check.checkStart();680 check.checkStart();
test/link/macho/entry/build.zig+1-1
...@@ -20,7 +20,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize...@@ -20,7 +20,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
20 });20 });
21 exe.addCSourceFile(.{ .file = .{ .path = "main.c" }, .flags = &.{} });21 exe.addCSourceFile(.{ .file = .{ .path = "main.c" }, .flags = &.{} });
22 exe.linkLibC();22 exe.linkLibC();
23 exe.entry_symbol_name = "_non_main";23 exe.entry = .{ .symbol_name = "_non_main" };
2424
25 const check_exe = exe.checkObject();25 const check_exe = exe.checkObject();
2626
test/link/macho/entry_in_dylib/build.zig+1-1
...@@ -30,7 +30,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize...@@ -30,7 +30,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
30 exe.addCSourceFile(.{ .file = .{ .path = "main.c" }, .flags = &.{} });30 exe.addCSourceFile(.{ .file = .{ .path = "main.c" }, .flags = &.{} });
31 exe.linkLibrary(lib);31 exe.linkLibrary(lib);
32 exe.linkLibC();32 exe.linkLibC();
33 exe.entry_symbol_name = "_bootstrap";33 exe.entry = .{ .symbol_name = "_bootstrap" };
34 exe.forceUndefinedSymbol("_my_main");34 exe.forceUndefinedSymbol("_my_main");
3535
36 const check_exe = exe.checkObject();36 const check_exe = exe.checkObject();
test/link/wasm/archive/build.zig+2-1
...@@ -15,12 +15,13 @@ pub fn build(b: *std.Build) void {...@@ -15,12 +15,13 @@ pub fn build(b: *std.Build) void {
15fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.OptimizeMode) void {15fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.OptimizeMode) void {
16 // The code in question will pull-in compiler-rt,16 // The code in question will pull-in compiler-rt,
17 // and therefore link with its archive file.17 // and therefore link with its archive file.
18 const lib = b.addSharedLibrary(.{18 const lib = b.addExecutable(.{
19 .name = "main",19 .name = "main",
20 .root_source_file = .{ .path = "main.zig" },20 .root_source_file = .{ .path = "main.zig" },
21 .optimize = optimize,21 .optimize = optimize,
22 .target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding },22 .target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding },
23 });23 });
24 lib.entry = .disabled;
24 lib.use_llvm = false;25 lib.use_llvm = false;
25 lib.use_lld = false;26 lib.use_lld = false;
26 lib.strip = false;27 lib.strip = false;
test/link/wasm/basic-features/build.zig+2-1
...@@ -4,7 +4,7 @@ pub const requires_stage2 = true;...@@ -4,7 +4,7 @@ pub const requires_stage2 = true;
44
5pub fn build(b: *std.Build) void {5pub fn build(b: *std.Build) void {
6 // Library with explicitly set cpu features6 // Library with explicitly set cpu features
7 const lib = b.addSharedLibrary(.{7 const lib = b.addExecutable(.{
8 .name = "lib",8 .name = "lib",
9 .root_source_file = .{ .path = "main.zig" },9 .root_source_file = .{ .path = "main.zig" },
10 .optimize = .Debug,10 .optimize = .Debug,
...@@ -15,6 +15,7 @@ pub fn build(b: *std.Build) void {...@@ -15,6 +15,7 @@ pub fn build(b: *std.Build) void {
15 .os_tag = .freestanding,15 .os_tag = .freestanding,
16 },16 },
17 });17 });
18 lib.entry = .disabled;
18 lib.use_llvm = false;19 lib.use_llvm = false;
19 lib.use_lld = false;20 lib.use_lld = false;
2021
test/link/wasm/bss/build.zig+4-2
...@@ -14,12 +14,13 @@ pub fn build(b: *std.Build) void {...@@ -14,12 +14,13 @@ pub fn build(b: *std.Build) void {
1414
15fn add(b: *std.Build, test_step: *std.Build.Step, optimize_mode: std.builtin.OptimizeMode, is_safe: bool) void {15fn add(b: *std.Build, test_step: *std.Build.Step, optimize_mode: std.builtin.OptimizeMode, is_safe: bool) void {
16 {16 {
17 const lib = b.addSharedLibrary(.{17 const lib = b.addExecutable(.{
18 .name = "lib",18 .name = "lib",
19 .root_source_file = .{ .path = "lib.zig" },19 .root_source_file = .{ .path = "lib.zig" },
20 .target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding },20 .target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding },
21 .optimize = optimize_mode,21 .optimize = optimize_mode,
22 });22 });
23 lib.entry = .disabled;
23 lib.use_llvm = false;24 lib.use_llvm = false;
24 lib.use_lld = false;25 lib.use_lld = false;
25 lib.strip = false;26 lib.strip = false;
...@@ -60,12 +61,13 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize_mode: std.builtin.Opt...@@ -60,12 +61,13 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize_mode: std.builtin.Opt
6061
61 // verify zero'd declaration is stored in bss for all optimization modes.62 // verify zero'd declaration is stored in bss for all optimization modes.
62 {63 {
63 const lib = b.addSharedLibrary(.{64 const lib = b.addExecutable(.{
64 .name = "lib",65 .name = "lib",
65 .root_source_file = .{ .path = "lib2.zig" },66 .root_source_file = .{ .path = "lib2.zig" },
66 .target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding },67 .target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding },
67 .optimize = optimize_mode,68 .optimize = optimize_mode,
68 });69 });
70 lib.entry = .disabled;
69 lib.use_llvm = false;71 lib.use_llvm = false;
70 lib.use_lld = false;72 lib.use_lld = false;
71 lib.strip = false;73 lib.strip = false;
test/link/wasm/export-data/build.zig+2-1
...@@ -9,12 +9,13 @@ pub fn build(b: *std.Build) void {...@@ -9,12 +9,13 @@ pub fn build(b: *std.Build) void {
9 return;9 return;
10 }10 }
1111
12 const lib = b.addSharedLibrary(.{12 const lib = b.addExecutable(.{
13 .name = "lib",13 .name = "lib",
14 .root_source_file = .{ .path = "lib.zig" },14 .root_source_file = .{ .path = "lib.zig" },
15 .optimize = .ReleaseSafe, // to make the output deterministic in address positions15 .optimize = .ReleaseSafe, // to make the output deterministic in address positions
16 .target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding },16 .target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding },
17 });17 });
18 lib.entry = .disabled;
18 lib.use_lld = false;19 lib.use_lld = false;
19 lib.export_symbol_names = &.{ "foo", "bar" };20 lib.export_symbol_names = &.{ "foo", "bar" };
20 lib.global_base = 0; // put data section at address 0 to make data symbols easier to parse21 lib.global_base = 0; // put data section at address 0 to make data symbols easier to parse
test/link/wasm/export/build.zig+6-3
...@@ -13,31 +13,34 @@ pub fn build(b: *std.Build) void {...@@ -13,31 +13,34 @@ pub fn build(b: *std.Build) void {
13}13}
1414
15fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.OptimizeMode) void {15fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.OptimizeMode) void {
16 const no_export = b.addSharedLibrary(.{16 const no_export = b.addExecutable(.{
17 .name = "no-export",17 .name = "no-export",
18 .root_source_file = .{ .path = "main.zig" },18 .root_source_file = .{ .path = "main.zig" },
19 .optimize = optimize,19 .optimize = optimize,
20 .target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding },20 .target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding },
21 });21 });
22 no_export.entry = .disabled;
22 no_export.use_llvm = false;23 no_export.use_llvm = false;
23 no_export.use_lld = false;24 no_export.use_lld = false;
2425
25 const dynamic_export = b.addSharedLibrary(.{26 const dynamic_export = b.addExecutable(.{
26 .name = "dynamic",27 .name = "dynamic",
27 .root_source_file = .{ .path = "main.zig" },28 .root_source_file = .{ .path = "main.zig" },
28 .optimize = optimize,29 .optimize = optimize,
29 .target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding },30 .target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding },
30 });31 });
32 dynamic_export.entry = .disabled;
31 dynamic_export.rdynamic = true;33 dynamic_export.rdynamic = true;
32 dynamic_export.use_llvm = false;34 dynamic_export.use_llvm = false;
33 dynamic_export.use_lld = false;35 dynamic_export.use_lld = false;
3436
35 const force_export = b.addSharedLibrary(.{37 const force_export = b.addExecutable(.{
36 .name = "force",38 .name = "force",
37 .root_source_file = .{ .path = "main.zig" },39 .root_source_file = .{ .path = "main.zig" },
38 .optimize = optimize,40 .optimize = optimize,
39 .target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding },41 .target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding },
40 });42 });
43 force_export.entry = .disabled;
41 force_export.export_symbol_names = &.{"foo"};44 force_export.export_symbol_names = &.{"foo"};
42 force_export.use_llvm = false;45 force_export.use_llvm = false;
43 force_export.use_lld = false;46 force_export.use_lld = false;
test/link/wasm/extern-mangle/build.zig+2-1
...@@ -11,12 +11,13 @@ pub fn build(b: *std.Build) void {...@@ -11,12 +11,13 @@ pub fn build(b: *std.Build) void {
11}11}
1212
13fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.OptimizeMode) void {13fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.OptimizeMode) void {
14 const lib = b.addSharedLibrary(.{14 const lib = b.addExecutable(.{
15 .name = "lib",15 .name = "lib",
16 .root_source_file = .{ .path = "lib.zig" },16 .root_source_file = .{ .path = "lib.zig" },
17 .target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding },17 .target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding },
18 .optimize = optimize,18 .optimize = optimize,
19 });19 });
20 lib.entry = .disabled;
20 lib.import_symbols = true; // import `a` and `b`21 lib.import_symbols = true; // import `a` and `b`
21 lib.rdynamic = true; // export `foo`22 lib.rdynamic = true; // export `foo`
2223
test/link/wasm/function-table/build.zig+6-3
...@@ -13,32 +13,35 @@ pub fn build(b: *std.Build) void {...@@ -13,32 +13,35 @@ pub fn build(b: *std.Build) void {
13}13}
1414
15fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.OptimizeMode) void {15fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.OptimizeMode) void {
16 const import_table = b.addSharedLibrary(.{16 const import_table = b.addExecutable(.{
17 .name = "import_table",17 .name = "import_table",
18 .root_source_file = .{ .path = "lib.zig" },18 .root_source_file = .{ .path = "lib.zig" },
19 .target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding },19 .target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding },
20 .optimize = optimize,20 .optimize = optimize,
21 });21 });
22 import_table.entry = .disabled;
22 import_table.use_llvm = false;23 import_table.use_llvm = false;
23 import_table.use_lld = false;24 import_table.use_lld = false;
24 import_table.import_table = true;25 import_table.import_table = true;
2526
26 const export_table = b.addSharedLibrary(.{27 const export_table = b.addExecutable(.{
27 .name = "export_table",28 .name = "export_table",
28 .root_source_file = .{ .path = "lib.zig" },29 .root_source_file = .{ .path = "lib.zig" },
29 .target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding },30 .target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding },
30 .optimize = optimize,31 .optimize = optimize,
31 });32 });
33 export_table.entry = .disabled;
32 export_table.use_llvm = false;34 export_table.use_llvm = false;
33 export_table.use_lld = false;35 export_table.use_lld = false;
34 export_table.export_table = true;36 export_table.export_table = true;
3537
36 const regular_table = b.addSharedLibrary(.{38 const regular_table = b.addExecutable(.{
37 .name = "regular_table",39 .name = "regular_table",
38 .root_source_file = .{ .path = "lib.zig" },40 .root_source_file = .{ .path = "lib.zig" },
39 .target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding },41 .target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding },
40 .optimize = optimize,42 .optimize = optimize,
41 });43 });
44 regular_table.entry = .disabled;
42 regular_table.use_llvm = false;45 regular_table.use_llvm = false;
43 regular_table.use_lld = false;46 regular_table.use_lld = false;
4447
test/link/wasm/infer-features/build.zig+2-1
...@@ -17,7 +17,7 @@ pub fn build(b: *std.Build) void {...@@ -17,7 +17,7 @@ pub fn build(b: *std.Build) void {
1717
18 // Wasm library that doesn't have any features specified. This will18 // Wasm library that doesn't have any features specified. This will
19 // infer its featureset from other linked object files.19 // infer its featureset from other linked object files.
20 const lib = b.addSharedLibrary(.{20 const lib = b.addExecutable(.{
21 .name = "lib",21 .name = "lib",
22 .root_source_file = .{ .path = "main.zig" },22 .root_source_file = .{ .path = "main.zig" },
23 .optimize = .Debug,23 .optimize = .Debug,
...@@ -27,6 +27,7 @@ pub fn build(b: *std.Build) void {...@@ -27,6 +27,7 @@ pub fn build(b: *std.Build) void {
27 .os_tag = .freestanding,27 .os_tag = .freestanding,
28 },28 },
29 });29 });
30 lib.entry = .disabled;
30 lib.use_llvm = false;31 lib.use_llvm = false;
31 lib.use_lld = false;32 lib.use_lld = false;
32 lib.addObject(c_obj);33 lib.addObject(c_obj);
test/link/wasm/producers/build.zig+2-1
...@@ -14,12 +14,13 @@ pub fn build(b: *std.Build) void {...@@ -14,12 +14,13 @@ pub fn build(b: *std.Build) void {
14}14}
1515
16fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.OptimizeMode) void {16fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.OptimizeMode) void {
17 const lib = b.addSharedLibrary(.{17 const lib = b.addExecutable(.{
18 .name = "lib",18 .name = "lib",
19 .root_source_file = .{ .path = "lib.zig" },19 .root_source_file = .{ .path = "lib.zig" },
20 .target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding },20 .target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding },
21 .optimize = optimize,21 .optimize = optimize,
22 });22 });
23 lib.entry = .disabled;
23 lib.use_llvm = false;24 lib.use_llvm = false;
24 lib.use_lld = false;25 lib.use_lld = false;
25 lib.strip = false;26 lib.strip = false;
test/link/wasm/segments/build.zig+2-1
...@@ -13,12 +13,13 @@ pub fn build(b: *std.Build) void {...@@ -13,12 +13,13 @@ pub fn build(b: *std.Build) void {
13}13}
1414
15fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.OptimizeMode) void {15fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.OptimizeMode) void {
16 const lib = b.addSharedLibrary(.{16 const lib = b.addExecutable(.{
17 .name = "lib",17 .name = "lib",
18 .root_source_file = .{ .path = "lib.zig" },18 .root_source_file = .{ .path = "lib.zig" },
19 .target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding },19 .target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding },
20 .optimize = optimize,20 .optimize = optimize,
21 });21 });
22 lib.entry = .disabled;
22 lib.use_llvm = false;23 lib.use_llvm = false;
23 lib.use_lld = false;24 lib.use_lld = false;
24 lib.strip = false;25 lib.strip = false;
test/link/wasm/shared-memory/build.zig+74-75
...@@ -11,88 +11,87 @@ pub fn build(b: *std.Build) void {...@@ -11,88 +11,87 @@ pub fn build(b: *std.Build) void {
11}11}
1212
13fn add(b: *std.Build, test_step: *std.Build.Step, optimize_mode: std.builtin.OptimizeMode) void {13fn add(b: *std.Build, test_step: *std.Build.Step, optimize_mode: std.builtin.OptimizeMode) void {
14 {14 const lib = b.addExecutable(.{
15 const lib = b.addSharedLibrary(.{15 .name = "lib",
16 .name = "lib",16 .root_source_file = .{ .path = "lib.zig" },
17 .root_source_file = .{ .path = "lib.zig" },17 .target = .{
18 .target = .{18 .cpu_arch = .wasm32,
19 .cpu_arch = .wasm32,19 .cpu_model = .{ .explicit = &std.Target.wasm.cpu.mvp },
20 .cpu_model = .{ .explicit = &std.Target.wasm.cpu.mvp },20 .cpu_features_add = std.Target.wasm.featureSet(&.{ .atomics, .bulk_memory }),
21 .cpu_features_add = std.Target.wasm.featureSet(&.{ .atomics, .bulk_memory }),21 .os_tag = .freestanding,
22 .os_tag = .freestanding,22 },
23 },23 .optimize = optimize_mode,
24 .optimize = optimize_mode,24 });
25 });25 lib.entry = .disabled;
26 lib.use_lld = false;26 lib.use_lld = false;
27 lib.strip = false;27 lib.strip = false;
28 lib.import_memory = true;28 lib.import_memory = true;
29 lib.export_memory = true;29 lib.export_memory = true;
30 lib.shared_memory = true;30 lib.shared_memory = true;
31 lib.max_memory = 67108864;31 lib.max_memory = 67108864;
32 lib.single_threaded = false;32 lib.single_threaded = false;
33 lib.export_symbol_names = &.{"foo"};33 lib.export_symbol_names = &.{"foo"};
3434
35 const check_lib = lib.checkObject();35 const check_lib = lib.checkObject();
3636
37 check_lib.checkStart("Section import");37 check_lib.checkStart("Section import");
38 check_lib.checkNext("entries 1");38 check_lib.checkNext("entries 1");
39 check_lib.checkNext("module env");39 check_lib.checkNext("module env");
40 check_lib.checkNext("name memory"); // ensure we are importing memory40 check_lib.checkNext("name memory"); // ensure we are importing memory
4141
42 check_lib.checkStart("Section export");42 check_lib.checkStart("Section export");
43 check_lib.checkNext("entries 2");43 check_lib.checkNext("entries 2");
44 check_lib.checkNext("name memory"); // ensure we also export memory again44 check_lib.checkNext("name memory"); // ensure we also export memory again
4545
46 // This section *must* be emit as the start function is set to the index46 // This section *must* be emit as the start function is set to the index
47 // of __wasm_init_memory47 // of __wasm_init_memory
48 // release modes will have the TLS segment optimized out in our test-case.48 // release modes will have the TLS segment optimized out in our test-case.
49 // This means we won't have __wasm_init_memory in such case, and therefore49 // This means we won't have __wasm_init_memory in such case, and therefore
50 // should also not have a section "start"50 // should also not have a section "start"
51 if (optimize_mode == .Debug) {51 if (optimize_mode == .Debug) {
52 check_lib.checkStart("Section start");52 check_lib.checkStart("Section start");
53 }53 }
54
55 // This section is only and *must* be emit when shared-memory is enabled
56 // release modes will have the TLS segment optimized out in our test-case.
57 if (optimize_mode == .Debug) {
58 check_lib.checkStart("Section data_count");
59 check_lib.checkNext("count 3");
60 }
6154
62 check_lib.checkStart("Section custom");55 // This section is only and *must* be emit when shared-memory is enabled
63 check_lib.checkNext("name name");56 // release modes will have the TLS segment optimized out in our test-case.
64 check_lib.checkNext("type function");57 if (optimize_mode == .Debug) {
65 if (optimize_mode == .Debug) {58 check_lib.checkStart("Section data_count");
66 check_lib.checkNext("name __wasm_init_memory");59 check_lib.checkNext("count 3");
67 }60 }
68 check_lib.checkNext("name __wasm_init_tls");
69 check_lib.checkNext("type global");
7061
71 // In debug mode the symbol __tls_base is resolved to an undefined symbol62 check_lib.checkStart("Section custom");
72 // from the object file, hence its placement differs than in release modes63 check_lib.checkNext("name name");
73 // where the entire tls segment is optimized away, and tls_base will have64 check_lib.checkNext("type function");
74 // its original position.65 if (optimize_mode == .Debug) {
75 if (optimize_mode == .Debug) {66 check_lib.checkNext("name __wasm_init_memory");
76 check_lib.checkNext("name __tls_size");67 }
77 check_lib.checkNext("name __tls_align");68 check_lib.checkNext("name __wasm_init_tls");
78 check_lib.checkNext("name __tls_base");69 check_lib.checkNext("type global");
79 } else {
80 check_lib.checkNext("name __tls_base");
81 check_lib.checkNext("name __tls_size");
82 check_lib.checkNext("name __tls_align");
83 }
8470
85 check_lib.checkNext("type data_segment");71 // In debug mode the symbol __tls_base is resolved to an undefined symbol
86 if (optimize_mode == .Debug) {72 // from the object file, hence its placement differs than in release modes
87 check_lib.checkNext("names 3");73 // where the entire tls segment is optimized away, and tls_base will have
88 check_lib.checkNext("index 0");74 // its original position.
89 check_lib.checkNext("name .rodata");75 if (optimize_mode == .Debug) {
90 check_lib.checkNext("index 1");76 check_lib.checkNext("name __tls_size");
91 check_lib.checkNext("name .bss");77 check_lib.checkNext("name __tls_align");
92 check_lib.checkNext("index 2");78 check_lib.checkNext("name __tls_base");
93 check_lib.checkNext("name .tdata");79 } else {
94 }80 check_lib.checkNext("name __tls_base");
81 check_lib.checkNext("name __tls_size");
82 check_lib.checkNext("name __tls_align");
83 }
9584
96 test_step.dependOn(&check_lib.step);85 check_lib.checkNext("type data_segment");
86 if (optimize_mode == .Debug) {
87 check_lib.checkNext("names 3");
88 check_lib.checkNext("index 0");
89 check_lib.checkNext("name .rodata");
90 check_lib.checkNext("index 1");
91 check_lib.checkNext("name .bss");
92 check_lib.checkNext("index 2");
93 check_lib.checkNext("name .tdata");
97 }94 }
95
96 test_step.dependOn(&check_lib.step);
98}97}
test/link/wasm/stack_pointer/build.zig+2-1
...@@ -13,12 +13,13 @@ pub fn build(b: *std.Build) void {...@@ -13,12 +13,13 @@ pub fn build(b: *std.Build) void {
13}13}
1414
15fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.OptimizeMode) void {15fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.OptimizeMode) void {
16 const lib = b.addSharedLibrary(.{16 const lib = b.addExecutable(.{
17 .name = "lib",17 .name = "lib",
18 .root_source_file = .{ .path = "lib.zig" },18 .root_source_file = .{ .path = "lib.zig" },
19 .target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding },19 .target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding },
20 .optimize = optimize,20 .optimize = optimize,
21 });21 });
22 lib.entry = .disabled;
22 lib.use_llvm = false;23 lib.use_llvm = false;
23 lib.use_lld = false;24 lib.use_lld = false;
24 lib.strip = false;25 lib.strip = false;
test/link/wasm/type/build.zig+2-1
...@@ -13,12 +13,13 @@ pub fn build(b: *std.Build) void {...@@ -13,12 +13,13 @@ pub fn build(b: *std.Build) void {
13}13}
1414
15fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.OptimizeMode) void {15fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.OptimizeMode) void {
16 const lib = b.addSharedLibrary(.{16 const lib = b.addExecutable(.{
17 .name = "lib",17 .name = "lib",
18 .root_source_file = .{ .path = "lib.zig" },18 .root_source_file = .{ .path = "lib.zig" },
19 .target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding },19 .target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding },
20 .optimize = optimize,20 .optimize = optimize,
21 });21 });
22 lib.entry = .disabled;
22 lib.use_llvm = false;23 lib.use_llvm = false;
23 lib.use_lld = false;24 lib.use_lld = false;
24 lib.strip = false;25 lib.strip = false;