authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-11-09 14:29:20-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-11-09 14:29:20-07:00
logd2cdfb949033cfd463cdd4ef1bbf93f94d4d190a
tree6f329fbd1402f5776dc0b8f654452a8ae1471956
parent9bb7ff68ccab8700cb787a83359df02a5bb4370f

stage2: add 4 new linker flags for WebAssembly

--import-memory import memory from the environment --initial-memory=[bytes] initial size of the linear memory --max-memory=[bytes] maximum size of the linear memory --global-base=[addr] where to start to place global data See #8633

5 files changed, 86 insertions(+), 1 deletions(-)

lib/std/build.zig+16
...@@ -1439,6 +1439,10 @@ pub const LibExeObjStep = struct {...@@ -1439,6 +1439,10 @@ pub const LibExeObjStep = struct {
1439 disable_sanitize_c: bool,1439 disable_sanitize_c: bool,
1440 sanitize_thread: bool,1440 sanitize_thread: bool,
1441 rdynamic: bool,1441 rdynamic: bool,
1442 import_memory: bool = false,
1443 initial_memory: ?u64 = null,
1444 max_memory: ?u64 = null,
1445 global_base: ?u64 = null,
1442 c_std: Builder.CStd,1446 c_std: Builder.CStd,
1443 override_lib_dir: ?[]const u8,1447 override_lib_dir: ?[]const u8,
1444 main_pkg_path: ?[]const u8,1448 main_pkg_path: ?[]const u8,
...@@ -2431,6 +2435,18 @@ pub const LibExeObjStep = struct {...@@ -2431,6 +2435,18 @@ pub const LibExeObjStep = struct {
2431 if (self.rdynamic) {2435 if (self.rdynamic) {
2432 try zig_args.append("-rdynamic");2436 try zig_args.append("-rdynamic");
2433 }2437 }
2438 if (self.import_memory) {
2439 try zig_args.append("--import-memory");
2440 }
2441 if (self.initial_memory) |initial_memory| {
2442 try zig_args.append(builder.fmt("--initial-memory={d}", .{initial_memory}));
2443 }
2444 if (self.max_memory) |max_memory| {
2445 try zig_args.append(builder.fmt("--max-memory={d}", .{max_memory}));
2446 }
2447 if (self.global_base) |global_base| {
2448 try zig_args.append(builder.fmt("--global-base={d}", .{global_base}));
2449 }
24342450
2435 if (self.code_model != .default) {2451 if (self.code_model != .default) {
2436 try zig_args.append("-mcmodel");2452 try zig_args.append("-mcmodel");
src/Compilation.zig+8
...@@ -716,6 +716,10 @@ pub const InitOptions = struct {...@@ -716,6 +716,10 @@ pub const InitOptions = struct {
716 linker_gc_sections: ?bool = null,716 linker_gc_sections: ?bool = null,
717 linker_allow_shlib_undefined: ?bool = null,717 linker_allow_shlib_undefined: ?bool = null,
718 linker_bind_global_refs_locally: ?bool = null,718 linker_bind_global_refs_locally: ?bool = null,
719 linker_import_memory: ?bool = null,
720 linker_initial_memory: ?u64 = null,
721 linker_max_memory: ?u64 = null,
722 linker_global_base: ?u64 = null,
719 each_lib_rpath: ?bool = null,723 each_lib_rpath: ?bool = null,
720 disable_c_depfile: bool = false,724 disable_c_depfile: bool = false,
721 linker_z_nodelete: bool = false,725 linker_z_nodelete: bool = false,
...@@ -1401,6 +1405,10 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {...@@ -1401,6 +1405,10 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
1401 .function_sections = options.function_sections,1405 .function_sections = options.function_sections,
1402 .allow_shlib_undefined = options.linker_allow_shlib_undefined,1406 .allow_shlib_undefined = options.linker_allow_shlib_undefined,
1403 .bind_global_refs_locally = options.linker_bind_global_refs_locally orelse false,1407 .bind_global_refs_locally = options.linker_bind_global_refs_locally orelse false,
1408 .import_memory = options.linker_import_memory orelse false,
1409 .initial_memory = options.linker_initial_memory,
1410 .max_memory = options.linker_max_memory,
1411 .global_base = options.linker_global_base,
1404 .z_nodelete = options.linker_z_nodelete,1412 .z_nodelete = options.linker_z_nodelete,
1405 .z_notext = options.linker_z_notext,1413 .z_notext = options.linker_z_notext,
1406 .z_defs = options.linker_z_defs,1414 .z_defs = options.linker_z_defs,
src/link.zig+4
...@@ -82,6 +82,10 @@ pub const Options = struct {...@@ -82,6 +82,10 @@ pub const Options = struct {
82 nxcompat: bool,82 nxcompat: bool,
83 dynamicbase: bool,83 dynamicbase: bool,
84 bind_global_refs_locally: bool,84 bind_global_refs_locally: bool,
85 import_memory: bool,
86 initial_memory: ?u64,
87 max_memory: ?u64,
88 global_base: ?u64,
85 is_native_os: bool,89 is_native_os: bool,
86 is_native_abi: bool,90 is_native_abi: bool,
87 pic: bool,91 pic: bool,
src/link/Wasm.zig+23
...@@ -681,6 +681,10 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void {...@@ -681,6 +681,10 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void {
681 try man.addOptionalFile(compiler_rt_path);681 try man.addOptionalFile(compiler_rt_path);
682 man.hash.addOptional(self.base.options.stack_size_override);682 man.hash.addOptional(self.base.options.stack_size_override);
683 man.hash.addListOfBytes(self.base.options.extra_lld_args);683 man.hash.addListOfBytes(self.base.options.extra_lld_args);
684 man.hash.add(self.base.options.import_memory);
685 man.hash.addOptional(self.base.options.initial_memory);
686 man.hash.addOptional(self.base.options.max_memory);
687 man.hash.addOptional(self.base.options.global_base);
684688
685 // We don't actually care whether it's a cache hit or miss; we just need the digest and the lock.689 // We don't actually care whether it's a cache hit or miss; we just need the digest and the lock.
686 _ = try man.hit();690 _ = try man.hit();
...@@ -754,6 +758,25 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void {...@@ -754,6 +758,25 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void {
754 }758 }
755 }759 }
756760
761 if (self.base.options.import_memory) {
762 try argv.append("--import-memory");
763 }
764
765 if (self.base.options.initial_memory) |initial_memory| {
766 const arg = try std.fmt.allocPrint(arena, "--initial-memory={d}", .{initial_memory});
767 try argv.append(arg);
768 }
769
770 if (self.base.options.max_memory) |max_memory| {
771 const arg = try std.fmt.allocPrint(arena, "--max-memory={d}", .{max_memory});
772 try argv.append(arg);
773 }
774
775 if (self.base.options.global_base) |global_base| {
776 const arg = try std.fmt.allocPrint(arena, "--global-base={d}", .{global_base});
777 try argv.append(arg);
778 }
779
757 if (self.base.options.output_mode == .Exe) {780 if (self.base.options.output_mode == .Exe) {
758 // Increase the default stack size to a more reasonable value of 1MB instead of781 // Increase the default stack size to a more reasonable value of 1MB instead of
759 // the default of 1 Wasm page being 64KB, unless overridden by the user.782 // the default of 1 Wasm page being 64KB, unless overridden by the user.
src/main.zig+35-1
...@@ -332,7 +332,7 @@ const usage_build_generic =...@@ -332,7 +332,7 @@ const usage_build_generic =
332 \\ -mno-red-zone Force-disable the "red-zone"332 \\ -mno-red-zone Force-disable the "red-zone"
333 \\ -fomit-frame-pointer Omit the stack frame pointer333 \\ -fomit-frame-pointer Omit the stack frame pointer
334 \\ -fno-omit-frame-pointer Store the stack frame pointer334 \\ -fno-omit-frame-pointer Store the stack frame pointer
335 \\ -mexec-model=[value] Execution model (WASI only)335 \\ -mexec-model=[value] (WASI) Execution model
336 \\ --name [name] Override root name (not a file path)336 \\ --name [name] Override root name (not a file path)
337 \\ -O [mode] Choose what to optimize for337 \\ -O [mode] Choose what to optimize for
338 \\ Debug (default) Optimizations off, safety on338 \\ Debug (default) Optimizations off, safety on
...@@ -424,6 +424,10 @@ const usage_build_generic =...@@ -424,6 +424,10 @@ const usage_build_generic =
424 \\ --image-base [addr] Set base address for executable image424 \\ --image-base [addr] Set base address for executable image
425 \\ -framework [name] (Darwin) link against framework425 \\ -framework [name] (Darwin) link against framework
426 \\ -F[dir] (Darwin) add search path for frameworks426 \\ -F[dir] (Darwin) add search path for frameworks
427 \\ --import-memory (WebAssembly) import memory from the environment
428 \\ --initial-memory=[bytes] (WebAssembly) initial size of the linear memory
429 \\ --max-memory=[bytes] (WebAssembly) maximum size of the linear memory
430 \\ --global-base=[addr] (WebAssembly) where to start to place global data
427 \\431 \\
428 \\Test Options:432 \\Test Options:
429 \\ --test-filter [text] Skip tests that do not match filter433 \\ --test-filter [text] Skip tests that do not match filter
...@@ -609,6 +613,10 @@ fn buildOutputType(...@@ -609,6 +613,10 @@ fn buildOutputType(
609 var linker_gc_sections: ?bool = null;613 var linker_gc_sections: ?bool = null;
610 var linker_allow_shlib_undefined: ?bool = null;614 var linker_allow_shlib_undefined: ?bool = null;
611 var linker_bind_global_refs_locally: ?bool = null;615 var linker_bind_global_refs_locally: ?bool = null;
616 var linker_import_memory: ?bool = null;
617 var linker_initial_memory: ?u64 = null;
618 var linker_max_memory: ?u64 = null;
619 var linker_global_base: ?u64 = null;
612 var linker_z_nodelete = false;620 var linker_z_nodelete = false;
613 var linker_z_notext = false;621 var linker_z_notext = false;
614 var linker_z_defs = false;622 var linker_z_defs = false;
...@@ -1125,6 +1133,14 @@ fn buildOutputType(...@@ -1125,6 +1133,14 @@ fn buildOutputType(
1125 } else {1133 } else {
1126 warn("unsupported linker extension flag: -z {s}", .{z_arg});1134 warn("unsupported linker extension flag: -z {s}", .{z_arg});
1127 }1135 }
1136 } else if (mem.eql(u8, arg, "--import-memory")) {
1137 linker_import_memory = true;
1138 } else if (mem.startsWith(u8, arg, "--initial-memory=")) {
1139 linker_initial_memory = parseIntSuffix(arg, "--initial-memory=".len);
1140 } else if (mem.startsWith(u8, arg, "--max-memory=")) {
1141 linker_max_memory = parseIntSuffix(arg, "--max-memory=".len);
1142 } else if (mem.startsWith(u8, arg, "--global-base=")) {
1143 linker_global_base = parseIntSuffix(arg, "--global-base=".len);
1128 } else if (mem.eql(u8, arg, "-Bsymbolic")) {1144 } else if (mem.eql(u8, arg, "-Bsymbolic")) {
1129 linker_bind_global_refs_locally = true;1145 linker_bind_global_refs_locally = true;
1130 } else if (mem.eql(u8, arg, "--debug-compile-errors")) {1146 } else if (mem.eql(u8, arg, "--debug-compile-errors")) {
...@@ -1453,6 +1469,14 @@ fn buildOutputType(...@@ -1453,6 +1469,14 @@ fn buildOutputType(
1453 linker_allow_shlib_undefined = false;1469 linker_allow_shlib_undefined = false;
1454 } else if (mem.eql(u8, arg, "-Bsymbolic")) {1470 } else if (mem.eql(u8, arg, "-Bsymbolic")) {
1455 linker_bind_global_refs_locally = true;1471 linker_bind_global_refs_locally = true;
1472 } else if (mem.eql(u8, arg, "--import-memory")) {
1473 linker_import_memory = true;
1474 } else if (mem.startsWith(u8, arg, "--initial-memory=")) {
1475 linker_initial_memory = parseIntSuffix(arg, "--initial-memory=".len);
1476 } else if (mem.startsWith(u8, arg, "--max-memory=")) {
1477 linker_max_memory = parseIntSuffix(arg, "--max-memory=".len);
1478 } else if (mem.startsWith(u8, arg, "--global-base=")) {
1479 linker_global_base = parseIntSuffix(arg, "--global-base=".len);
1456 } else if (mem.eql(u8, arg, "-z")) {1480 } else if (mem.eql(u8, arg, "-z")) {
1457 i += 1;1481 i += 1;
1458 if (i >= linker_args.items.len) {1482 if (i >= linker_args.items.len) {
...@@ -2148,6 +2172,10 @@ fn buildOutputType(...@@ -2148,6 +2172,10 @@ fn buildOutputType(
2148 .linker_gc_sections = linker_gc_sections,2172 .linker_gc_sections = linker_gc_sections,
2149 .linker_allow_shlib_undefined = linker_allow_shlib_undefined,2173 .linker_allow_shlib_undefined = linker_allow_shlib_undefined,
2150 .linker_bind_global_refs_locally = linker_bind_global_refs_locally,2174 .linker_bind_global_refs_locally = linker_bind_global_refs_locally,
2175 .linker_import_memory = linker_import_memory,
2176 .linker_initial_memory = linker_initial_memory,
2177 .linker_max_memory = linker_max_memory,
2178 .linker_global_base = linker_global_base,
2151 .linker_z_nodelete = linker_z_nodelete,2179 .linker_z_nodelete = linker_z_nodelete,
2152 .linker_z_notext = linker_z_notext,2180 .linker_z_notext = linker_z_notext,
2153 .linker_z_defs = linker_z_defs,2181 .linker_z_defs = linker_z_defs,
...@@ -4371,3 +4399,9 @@ pub fn cmdChangelist(...@@ -4371,3 +4399,9 @@ pub fn cmdChangelist(
4371 }4399 }
4372 try bw.flush();4400 try bw.flush();
4373}4401}
4402
4403fn parseIntSuffix(arg: []const u8, prefix_len: usize) u64 {
4404 return std.fmt.parseUnsigned(u64, arg[prefix_len..], 0) catch |err| {
4405 fatal("unable to parse '{s}': {s}", .{ arg, @errorName(err) });
4406 };
4407}