diff options
| author | Takeshi Yoneda <takeshi@tetrate.io> | 2021-07-01 09:02:48 +0900 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-06-30 20:02:48 -0400 |
| commit | bc7761d8e0bb70adb3c76c588f9f0b62937c6571 (patch) | |
| tree | 571b5b93cd6611d458cb728198b9796cff9da3ac | |
| parent | a95ba0d10d582020dbd3e6efded53f17287ed211 (diff) | |
| download | zig-bc7761d8e0bb70adb3c76c588f9f0b62937c6571.tar.gz zig-bc7761d8e0bb70adb3c76c588f9f0b62937c6571.zip | |
Add support for WASI reactor in pure Zig-exe. (#9178)
* Add command line help for "-mexec-model"
* Define WasmExecModel enum in std.builtin.
* Drop the support for the old crt1.o in favor of crt1-command.o
Signed-off-by: Takeshi Yoneda <takeshi@tetrate.io>
| -rw-r--r-- | lib/std/builtin.zig | 7 | ||||
| -rw-r--r-- | lib/std/start.zig | 28 | ||||
| -rw-r--r-- | src/Compilation.zig | 17 | ||||
| -rw-r--r-- | src/link.zig | 2 | ||||
| -rw-r--r-- | src/link/Wasm.zig | 13 | ||||
| -rw-r--r-- | src/main.zig | 15 | ||||
| -rw-r--r-- | src/wasi_libc.zig | 12 |
7 files changed, 66 insertions, 28 deletions
diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig index 615df9b9af..7bf60f5283 100644 --- a/lib/std/builtin.zig +++ b/lib/std/builtin.zig @@ -459,6 +459,13 @@ pub const LinkMode = enum { /// This data structure is used by the Zig language code generation and /// therefore must be kept in sync with the compiler implementation. +pub const WasiExecModel = enum { + command, + reactor, +}; + +/// This data structure is used by the Zig language code generation and +/// therefore must be kept in sync with the compiler implementation. pub const Version = struct { major: u32, minor: u32, diff --git a/lib/std/start.zig b/lib/std/start.zig index 7f73ba46db..b9fbb97c47 100644 --- a/lib/std/start.zig +++ b/lib/std/start.zig @@ -65,8 +65,9 @@ comptime { } } else if (native_os == .uefi) { if (!@hasDecl(root, "EfiMain")) @export(EfiMain, .{ .name = "EfiMain" }); - } else if (native_arch.isWasm() and native_os == .freestanding) { - if (!@hasDecl(root, start_sym_name)) @export(wasm_freestanding_start, .{ .name = start_sym_name }); + } else if (native_arch.isWasm()) { + const wasm_start_sym = if (builtin.wasi_exec_model == .reactor) "_initialize" else "_start"; + if (!@hasDecl(root, wasm_start_sym)) @export(wasm_start, .{ .name = wasm_start_sym }); } else if (native_os != .other and native_os != .freestanding) { if (!@hasDecl(root, start_sym_name)) @export(_start, .{ .name = start_sym_name }); } @@ -135,10 +136,21 @@ fn _DllMainCRTStartup( return std.os.windows.TRUE; } -fn wasm_freestanding_start() callconv(.C) void { - // This is marked inline because for some reason LLVM in release mode fails to inline it, +fn wasm_start() callconv(.C) void { + // The entrypoint is marked inline because for some reason LLVM in release mode fails to inline it, // and we want fewer call frames in stack traces. - _ = @call(.{ .modifier = .always_inline }, callMain, .{}); + switch (native_os) { + .freestanding => { + _ = @call(.{ .modifier = .always_inline }, callMain, .{}); + }, + .wasi => { + switch (builtin.wasi_exec_model) { + .reactor => _ = @call(.{ .modifier = .always_inline }, callMain, .{}), + .command => std.os.wasi.proc_exit(@call(.{ .modifier = .always_inline }, callMain, .{})), + } + }, + else => @compileError("unsupported OS"), + } } fn EfiMain(handle: uefi.Handle, system_table: *uefi.tables.SystemTable) callconv(.C) usize { @@ -164,12 +176,6 @@ fn EfiMain(handle: uefi.Handle, system_table: *uefi.tables.SystemTable) callconv } fn _start() callconv(.Naked) noreturn { - if (native_os == .wasi) { - // This is marked inline because for some reason LLVM in release mode fails to inline it, - // and we want fewer call frames in stack traces. - std.os.wasi.proc_exit(@call(.{ .modifier = .always_inline }, callMain, .{})); - } - switch (native_arch) { .x86_64 => { argc_argv_ptr = asm volatile ( diff --git a/src/Compilation.zig b/src/Compilation.zig index 890100b996..4e6bede26b 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -724,7 +724,7 @@ pub const InitOptions = struct { test_name_prefix: ?[]const u8 = null, subsystem: ?std.Target.SubSystem = null, /// WASI-only. Type of WASI execution model ("command" or "reactor"). - wasi_exec_model: ?wasi_libc.CRTFile = null, + wasi_exec_model: ?std.builtin.WasiExecModel = null, }; fn addPackageTableToCacheHash( @@ -790,6 +790,9 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { const needs_c_symbols = !options.skip_linker_dependencies and is_exe_or_dyn_lib; + // WASI-only. Resolve the optinal exec-model option, defaults to command. + const wasi_exec_model = if (options.target.os.tag != .wasi) undefined else options.wasi_exec_model orelse .command; + const comp: *Compilation = comp: { // For allocations that have the same lifetime as Compilation. This arena is used only during this // initialization and then is freed in deinit(). @@ -1340,7 +1343,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { .disable_lld_caching = options.disable_lld_caching, .subsystem = options.subsystem, .is_test = options.is_test, - .wasi_exec_model = options.wasi_exec_model, + .wasi_exec_model = wasi_exec_model, }); errdefer bin_file.destroy(); comp.* = .{ @@ -1442,7 +1445,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { }); } comp.work_queue.writeAssumeCapacity(&[_]Job{ - .{ .wasi_libc_crt_file = comp.bin_file.options.wasi_exec_model orelse .crt1_o }, + .{ .wasi_libc_crt_file = wasi_libc.execModelCrtFile(wasi_exec_model) }, .{ .wasi_libc_crt_file = .libc_a }, }); } @@ -3650,6 +3653,14 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: *Allocator) Alloc std.zig.fmtId(@tagName(comp.bin_file.options.machine_code_model)), }); + if (target.os.tag == .wasi) { + const wasi_exec_model_fmt = std.zig.fmtId(@tagName(comp.bin_file.options.wasi_exec_model)); + try buffer.writer().print( + \\pub const wasi_exec_model = std.builtin.WasiExecModel.{}; + \\ + , .{wasi_exec_model_fmt}); + } + if (comp.bin_file.options.is_test) { try buffer.appendSlice( \\pub var test_functions: []std.builtin.TestFn = undefined; // overwritten later diff --git a/src/link.zig b/src/link.zig index 3bbd542a15..d429a1b459 100644 --- a/src/link.zig +++ b/src/link.zig @@ -116,7 +116,7 @@ pub const Options = struct { libc_installation: ?*const LibCInstallation, /// WASI-only. Type of WASI execution model ("command" or "reactor"). - wasi_exec_model: ?wasi_libc.CRTFile = null, + wasi_exec_model: std.builtin.WasiExecModel = undefined, pub fn effectiveOutputMode(options: Options) std.builtin.OutputMode { return if (options.use_lld) .Obj else options.output_mode; diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig index 6d38939a88..5758f81a95 100644 --- a/src/link/Wasm.zig +++ b/src/link/Wasm.zig @@ -687,10 +687,15 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void { // before corrupting globals. See https://github.com/ziglang/zig/issues/4496 try argv.append("--stack-first"); - // Reactor execution model does not have _start so lld doesn't look for it. - if (self.base.options.wasi_exec_model) |exec_model| blk: { - if (exec_model != .crt1_reactor_o) break :blk; + if (self.base.options.wasi_exec_model == .reactor) { + // Reactor execution model does not have _start so lld doesn't look for it. try argv.append("--no-entry"); + // Make sure "_initialize" is exported even if this is pure Zig WASI reactor + // where WASM_SYMBOL_EXPORTED flag in LLVM is not set on _initialize. + try argv.appendSlice(&[_][]const u8{ + "--export", + "_initialize", + }); } } else { try argv.append("--no-entry"); // So lld doesn't look for _start. @@ -717,7 +722,7 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void { if (self.base.options.link_libc) { try argv.append(try comp.get_libc_crt_file( arena, - wasi_libc.crtFileFullName(self.base.options.wasi_exec_model orelse .crt1_o), + wasi_libc.execModelCrtFileFullName(self.base.options.wasi_exec_model), )); try argv.append(try comp.get_libc_crt_file(arena, "libc.a")); } diff --git a/src/main.zig b/src/main.zig index 192f6d853c..d53cd5133f 100644 --- a/src/main.zig +++ b/src/main.zig @@ -321,6 +321,7 @@ const usage_build_generic = \\ medium|large] \\ -mred-zone Force-enable the "red-zone" \\ -mno-red-zone Force-disable the "red-zone" + \\ -mexec-model=[value] Execution model (WASI only) \\ --name [name] Override root name (not a file path) \\ -O [mode] Choose what to optimize for \\ Debug (default) Optimizations off, safety on @@ -618,7 +619,7 @@ fn buildOutputType( var subsystem: ?std.Target.SubSystem = null; var major_subsystem_version: ?u32 = null; var minor_subsystem_version: ?u32 = null; - var wasi_exec_model: ?wasi_libc.CRTFile = null; + var wasi_exec_model: ?std.builtin.WasiExecModel = null; var system_libs = std.ArrayList([]const u8).init(gpa); defer system_libs.deinit(); @@ -1071,6 +1072,10 @@ fn buildOutputType( mem.startsWith(u8, arg, "-I")) { try clang_argv.append(arg); + } else if (mem.startsWith(u8, arg, "-mexec-model=")) { + wasi_exec_model = std.meta.stringToEnum(std.builtin.WasiExecModel, arg["-mexec-model=".len..]) orelse { + fatal("expected [command|reactor] for -mexec-mode=[value], found '{s}'", .{arg["-mexec-model=".len..]}); + }; } else { fatal("unrecognized parameter: '{s}'", .{arg}); } @@ -1277,11 +1282,9 @@ fn buildOutputType( .nostdlibinc => want_native_include_dirs = false, .strip => strip = true, .exec_model => { - if (std.mem.eql(u8, it.only_arg, "reactor")) { - wasi_exec_model = .crt1_reactor_o; - } else if (std.mem.eql(u8, it.only_arg, "command")) { - wasi_exec_model = .crt1_command_o; - } + wasi_exec_model = std.meta.stringToEnum(std.builtin.WasiExecModel, it.only_arg) orelse { + fatal("expected [command|reactor] for -mexec-mode=[value], found '{s}'", .{it.only_arg}); + }; }, } } diff --git a/src/wasi_libc.zig b/src/wasi_libc.zig index 8f62afccba..06d83aff36 100644 --- a/src/wasi_libc.zig +++ b/src/wasi_libc.zig @@ -45,9 +45,15 @@ pub fn emulatedLibCRFileLibName(crt_file: CRTFile) []const u8 { }; } -pub fn crtFileFullName(crt_file: CRTFile) []const u8 { - return switch (crt_file) { - .crt1_o => "crt1.o", +pub fn execModelCrtFile(wasi_exec_model: std.builtin.WasiExecModel) CRTFile { + return switch (wasi_exec_model) { + .reactor => CRTFile.crt1_reactor_o, + .command => CRTFile.crt1_command_o, + }; +} + +pub fn execModelCrtFileFullName(wasi_exec_model: std.builtin.WasiExecModel) []const u8 { + return switch (execModelCrtFile(wasi_exec_model)) { .crt1_reactor_o => "crt1-reactor.o", .crt1_command_o => "crt1-command.o", else => unreachable, |
