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
This commit is contained in:
Andrew Kelley 2021-11-09 14:29:20 -07:00
parent 9bb7ff68cc
commit d2cdfb9490
5 changed files with 86 additions and 1 deletions

View File

@ -1439,6 +1439,10 @@ pub const LibExeObjStep = struct {
disable_sanitize_c: bool,
sanitize_thread: bool,
rdynamic: bool,
import_memory: bool = false,
initial_memory: ?u64 = null,
max_memory: ?u64 = null,
global_base: ?u64 = null,
c_std: Builder.CStd,
override_lib_dir: ?[]const u8,
main_pkg_path: ?[]const u8,
@ -2431,6 +2435,18 @@ pub const LibExeObjStep = struct {
if (self.rdynamic) {
try zig_args.append("-rdynamic");
}
if (self.import_memory) {
try zig_args.append("--import-memory");
}
if (self.initial_memory) |initial_memory| {
try zig_args.append(builder.fmt("--initial-memory={d}", .{initial_memory}));
}
if (self.max_memory) |max_memory| {
try zig_args.append(builder.fmt("--max-memory={d}", .{max_memory}));
}
if (self.global_base) |global_base| {
try zig_args.append(builder.fmt("--global-base={d}", .{global_base}));
}
if (self.code_model != .default) {
try zig_args.append("-mcmodel");

View File

@ -716,6 +716,10 @@ pub const InitOptions = struct {
linker_gc_sections: ?bool = null,
linker_allow_shlib_undefined: ?bool = null,
linker_bind_global_refs_locally: ?bool = null,
linker_import_memory: ?bool = null,
linker_initial_memory: ?u64 = null,
linker_max_memory: ?u64 = null,
linker_global_base: ?u64 = null,
each_lib_rpath: ?bool = null,
disable_c_depfile: bool = false,
linker_z_nodelete: bool = false,
@ -1401,6 +1405,10 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
.function_sections = options.function_sections,
.allow_shlib_undefined = options.linker_allow_shlib_undefined,
.bind_global_refs_locally = options.linker_bind_global_refs_locally orelse false,
.import_memory = options.linker_import_memory orelse false,
.initial_memory = options.linker_initial_memory,
.max_memory = options.linker_max_memory,
.global_base = options.linker_global_base,
.z_nodelete = options.linker_z_nodelete,
.z_notext = options.linker_z_notext,
.z_defs = options.linker_z_defs,

View File

@ -82,6 +82,10 @@ pub const Options = struct {
nxcompat: bool,
dynamicbase: bool,
bind_global_refs_locally: bool,
import_memory: bool,
initial_memory: ?u64,
max_memory: ?u64,
global_base: ?u64,
is_native_os: bool,
is_native_abi: bool,
pic: bool,

View File

@ -681,6 +681,10 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void {
try man.addOptionalFile(compiler_rt_path);
man.hash.addOptional(self.base.options.stack_size_override);
man.hash.addListOfBytes(self.base.options.extra_lld_args);
man.hash.add(self.base.options.import_memory);
man.hash.addOptional(self.base.options.initial_memory);
man.hash.addOptional(self.base.options.max_memory);
man.hash.addOptional(self.base.options.global_base);
// We don't actually care whether it's a cache hit or miss; we just need the digest and the lock.
_ = try man.hit();
@ -754,6 +758,25 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void {
}
}
if (self.base.options.import_memory) {
try argv.append("--import-memory");
}
if (self.base.options.initial_memory) |initial_memory| {
const arg = try std.fmt.allocPrint(arena, "--initial-memory={d}", .{initial_memory});
try argv.append(arg);
}
if (self.base.options.max_memory) |max_memory| {
const arg = try std.fmt.allocPrint(arena, "--max-memory={d}", .{max_memory});
try argv.append(arg);
}
if (self.base.options.global_base) |global_base| {
const arg = try std.fmt.allocPrint(arena, "--global-base={d}", .{global_base});
try argv.append(arg);
}
if (self.base.options.output_mode == .Exe) {
// Increase the default stack size to a more reasonable value of 1MB instead of
// the default of 1 Wasm page being 64KB, unless overridden by the user.

View File

@ -332,7 +332,7 @@ const usage_build_generic =
\\ -mno-red-zone Force-disable the "red-zone"
\\ -fomit-frame-pointer Omit the stack frame pointer
\\ -fno-omit-frame-pointer Store the stack frame pointer
\\ -mexec-model=[value] Execution model (WASI only)
\\ -mexec-model=[value] (WASI) Execution model
\\ --name [name] Override root name (not a file path)
\\ -O [mode] Choose what to optimize for
\\ Debug (default) Optimizations off, safety on
@ -424,6 +424,10 @@ const usage_build_generic =
\\ --image-base [addr] Set base address for executable image
\\ -framework [name] (Darwin) link against framework
\\ -F[dir] (Darwin) add search path for frameworks
\\ --import-memory (WebAssembly) import memory from the environment
\\ --initial-memory=[bytes] (WebAssembly) initial size of the linear memory
\\ --max-memory=[bytes] (WebAssembly) maximum size of the linear memory
\\ --global-base=[addr] (WebAssembly) where to start to place global data
\\
\\Test Options:
\\ --test-filter [text] Skip tests that do not match filter
@ -609,6 +613,10 @@ fn buildOutputType(
var linker_gc_sections: ?bool = null;
var linker_allow_shlib_undefined: ?bool = null;
var linker_bind_global_refs_locally: ?bool = null;
var linker_import_memory: ?bool = null;
var linker_initial_memory: ?u64 = null;
var linker_max_memory: ?u64 = null;
var linker_global_base: ?u64 = null;
var linker_z_nodelete = false;
var linker_z_notext = false;
var linker_z_defs = false;
@ -1125,6 +1133,14 @@ fn buildOutputType(
} else {
warn("unsupported linker extension flag: -z {s}", .{z_arg});
}
} else if (mem.eql(u8, arg, "--import-memory")) {
linker_import_memory = true;
} else if (mem.startsWith(u8, arg, "--initial-memory=")) {
linker_initial_memory = parseIntSuffix(arg, "--initial-memory=".len);
} else if (mem.startsWith(u8, arg, "--max-memory=")) {
linker_max_memory = parseIntSuffix(arg, "--max-memory=".len);
} else if (mem.startsWith(u8, arg, "--global-base=")) {
linker_global_base = parseIntSuffix(arg, "--global-base=".len);
} else if (mem.eql(u8, arg, "-Bsymbolic")) {
linker_bind_global_refs_locally = true;
} else if (mem.eql(u8, arg, "--debug-compile-errors")) {
@ -1453,6 +1469,14 @@ fn buildOutputType(
linker_allow_shlib_undefined = false;
} else if (mem.eql(u8, arg, "-Bsymbolic")) {
linker_bind_global_refs_locally = true;
} else if (mem.eql(u8, arg, "--import-memory")) {
linker_import_memory = true;
} else if (mem.startsWith(u8, arg, "--initial-memory=")) {
linker_initial_memory = parseIntSuffix(arg, "--initial-memory=".len);
} else if (mem.startsWith(u8, arg, "--max-memory=")) {
linker_max_memory = parseIntSuffix(arg, "--max-memory=".len);
} else if (mem.startsWith(u8, arg, "--global-base=")) {
linker_global_base = parseIntSuffix(arg, "--global-base=".len);
} else if (mem.eql(u8, arg, "-z")) {
i += 1;
if (i >= linker_args.items.len) {
@ -2148,6 +2172,10 @@ fn buildOutputType(
.linker_gc_sections = linker_gc_sections,
.linker_allow_shlib_undefined = linker_allow_shlib_undefined,
.linker_bind_global_refs_locally = linker_bind_global_refs_locally,
.linker_import_memory = linker_import_memory,
.linker_initial_memory = linker_initial_memory,
.linker_max_memory = linker_max_memory,
.linker_global_base = linker_global_base,
.linker_z_nodelete = linker_z_nodelete,
.linker_z_notext = linker_z_notext,
.linker_z_defs = linker_z_defs,
@ -4371,3 +4399,9 @@ pub fn cmdChangelist(
}
try bw.flush();
}
fn parseIntSuffix(arg: []const u8, prefix_len: usize) u64 {
return std.fmt.parseUnsigned(u64, arg[prefix_len..], 0) catch |err| {
fatal("unable to parse '{s}': {s}", .{ arg, @errorName(err) });
};
}