| author | |
| committer | |
| log | bc7761d8e0bb70adb3c76c588f9f0b62937c6571 |
| tree | 571b5b93cd6611d458cb728198b9796cff9da3ac |
| parent | a95ba0d10d582020dbd3e6efded53f17287ed211 |
| signature |
* 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>7 files changed, 66 insertions(+), 28 deletions(-)
lib/std/builtin.zig+7| ... | @@ -457,6 +457,13 @@ pub const LinkMode = enum { | ... | @@ -457,6 +457,13 @@ pub const LinkMode = enum { |
| 457 | Dynamic, | 457 | Dynamic, |
| 458 | }; | 458 | }; |
| 459 | 459 | ||
| 460 | /// This data structure is used by the Zig language code generation and | ||
| 461 | /// therefore must be kept in sync with the compiler implementation. | ||
| 462 | pub const WasiExecModel = enum { | ||
| 463 | command, | ||
| 464 | reactor, | ||
| 465 | }; | ||
| 466 | |||
| 460 | /// This data structure is used by the Zig language code generation and | 467 | /// This data structure is used by the Zig language code generation and |
| 461 | /// therefore must be kept in sync with the compiler implementation. | 468 | /// therefore must be kept in sync with the compiler implementation. |
| 462 | pub const Version = struct { | 469 | pub const Version = struct { |
lib/std/start.zig+17-11| ... | @@ -65,8 +65,9 @@ comptime { | ... | @@ -65,8 +65,9 @@ comptime { |
| 65 | } | 65 | } |
| 66 | } else if (native_os == .uefi) { | 66 | } else if (native_os == .uefi) { |
| 67 | if (!@hasDecl(root, "EfiMain")) @export(EfiMain, .{ .name = "EfiMain" }); | 67 | if (!@hasDecl(root, "EfiMain")) @export(EfiMain, .{ .name = "EfiMain" }); |
| 68 | } else if (native_arch.isWasm() and native_os == .freestanding) { | 68 | } else if (native_arch.isWasm()) { |
| 69 | if (!@hasDecl(root, start_sym_name)) @export(wasm_freestanding_start, .{ .name = start_sym_name }); | 69 | const wasm_start_sym = if (builtin.wasi_exec_model == .reactor) "_initialize" else "_start"; |
| 70 | if (!@hasDecl(root, wasm_start_sym)) @export(wasm_start, .{ .name = wasm_start_sym }); | ||
| 70 | } else if (native_os != .other and native_os != .freestanding) { | 71 | } else if (native_os != .other and native_os != .freestanding) { |
| 71 | if (!@hasDecl(root, start_sym_name)) @export(_start, .{ .name = start_sym_name }); | 72 | if (!@hasDecl(root, start_sym_name)) @export(_start, .{ .name = start_sym_name }); |
| 72 | } | 73 | } |
| ... | @@ -135,10 +136,21 @@ fn _DllMainCRTStartup( | ... | @@ -135,10 +136,21 @@ fn _DllMainCRTStartup( |
| 135 | return std.os.windows.TRUE; | 136 | return std.os.windows.TRUE; |
| 136 | } | 137 | } |
| 137 | 138 | ||
| 138 | fn wasm_freestanding_start() callconv(.C) void { | 139 | fn wasm_start() callconv(.C) void { |
| 139 | // This is marked inline because for some reason LLVM in release mode fails to inline it, | 140 | // The entrypoint is marked inline because for some reason LLVM in release mode fails to inline it, |
| 140 | // and we want fewer call frames in stack traces. | 141 | // and we want fewer call frames in stack traces. |
| 141 | _ = @call(.{ .modifier = .always_inline }, callMain, .{}); | 142 | switch (native_os) { |
| 143 | .freestanding => { | ||
| 144 | _ = @call(.{ .modifier = .always_inline }, callMain, .{}); | ||
| 145 | }, | ||
| 146 | .wasi => { | ||
| 147 | switch (builtin.wasi_exec_model) { | ||
| 148 | .reactor => _ = @call(.{ .modifier = .always_inline }, callMain, .{}), | ||
| 149 | .command => std.os.wasi.proc_exit(@call(.{ .modifier = .always_inline }, callMain, .{})), | ||
| 150 | } | ||
| 151 | }, | ||
| 152 | else => @compileError("unsupported OS"), | ||
| 153 | } | ||
| 142 | } | 154 | } |
| 143 | 155 | ||
| 144 | fn EfiMain(handle: uefi.Handle, system_table: *uefi.tables.SystemTable) callconv(.C) usize { | 156 | 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 | ... | @@ -164,12 +176,6 @@ fn EfiMain(handle: uefi.Handle, system_table: *uefi.tables.SystemTable) callconv |
| 164 | } | 176 | } |
| 165 | 177 | ||
| 166 | fn _start() callconv(.Naked) noreturn { | 178 | fn _start() callconv(.Naked) noreturn { |
| 167 | if (native_os == .wasi) { | ||
| 168 | // This is marked inline because for some reason LLVM in release mode fails to inline it, | ||
| 169 | // and we want fewer call frames in stack traces. | ||
| 170 | std.os.wasi.proc_exit(@call(.{ .modifier = .always_inline }, callMain, .{})); | ||
| 171 | } | ||
| 172 | |||
| 173 | switch (native_arch) { | 179 | switch (native_arch) { |
| 174 | .x86_64 => { | 180 | .x86_64 => { |
| 175 | argc_argv_ptr = asm volatile ( | 181 | argc_argv_ptr = asm volatile ( |
src/Compilation.zig+14-3| ... | @@ -724,7 +724,7 @@ pub const InitOptions = struct { | ... | @@ -724,7 +724,7 @@ pub const InitOptions = struct { |
| 724 | test_name_prefix: ?[]const u8 = null, | 724 | test_name_prefix: ?[]const u8 = null, |
| 725 | subsystem: ?std.Target.SubSystem = null, | 725 | subsystem: ?std.Target.SubSystem = null, |
| 726 | /// WASI-only. Type of WASI execution model ("command" or "reactor"). | 726 | /// WASI-only. Type of WASI execution model ("command" or "reactor"). |
| 727 | wasi_exec_model: ?wasi_libc.CRTFile = null, | 727 | wasi_exec_model: ?std.builtin.WasiExecModel = null, |
| 728 | }; | 728 | }; |
| 729 | 729 | ||
| 730 | fn addPackageTableToCacheHash( | 730 | fn addPackageTableToCacheHash( |
| ... | @@ -790,6 +790,9 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { | ... | @@ -790,6 +790,9 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { |
| 790 | 790 | ||
| 791 | const needs_c_symbols = !options.skip_linker_dependencies and is_exe_or_dyn_lib; | 791 | const needs_c_symbols = !options.skip_linker_dependencies and is_exe_or_dyn_lib; |
| 792 | 792 | ||
| 793 | // WASI-only. Resolve the optinal exec-model option, defaults to command. | ||
| 794 | const wasi_exec_model = if (options.target.os.tag != .wasi) undefined else options.wasi_exec_model orelse .command; | ||
| 795 | |||
| 793 | const comp: *Compilation = comp: { | 796 | const comp: *Compilation = comp: { |
| 794 | // For allocations that have the same lifetime as Compilation. This arena is used only during this | 797 | // For allocations that have the same lifetime as Compilation. This arena is used only during this |
| 795 | // initialization and then is freed in deinit(). | 798 | // initialization and then is freed in deinit(). |
| ... | @@ -1340,7 +1343,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { | ... | @@ -1340,7 +1343,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { |
| 1340 | .disable_lld_caching = options.disable_lld_caching, | 1343 | .disable_lld_caching = options.disable_lld_caching, |
| 1341 | .subsystem = options.subsystem, | 1344 | .subsystem = options.subsystem, |
| 1342 | .is_test = options.is_test, | 1345 | .is_test = options.is_test, |
| 1343 | .wasi_exec_model = options.wasi_exec_model, | 1346 | .wasi_exec_model = wasi_exec_model, |
| 1344 | }); | 1347 | }); |
| 1345 | errdefer bin_file.destroy(); | 1348 | errdefer bin_file.destroy(); |
| 1346 | comp.* = .{ | 1349 | comp.* = .{ |
| ... | @@ -1442,7 +1445,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { | ... | @@ -1442,7 +1445,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { |
| 1442 | }); | 1445 | }); |
| 1443 | } | 1446 | } |
| 1444 | comp.work_queue.writeAssumeCapacity(&[_]Job{ | 1447 | comp.work_queue.writeAssumeCapacity(&[_]Job{ |
| 1445 | .{ .wasi_libc_crt_file = comp.bin_file.options.wasi_exec_model orelse .crt1_o }, | 1448 | .{ .wasi_libc_crt_file = wasi_libc.execModelCrtFile(wasi_exec_model) }, |
| 1446 | .{ .wasi_libc_crt_file = .libc_a }, | 1449 | .{ .wasi_libc_crt_file = .libc_a }, |
| 1447 | }); | 1450 | }); |
| 1448 | } | 1451 | } |
| ... | @@ -3650,6 +3653,14 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: *Allocator) Alloc | ... | @@ -3650,6 +3653,14 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: *Allocator) Alloc |
| 3650 | std.zig.fmtId(@tagName(comp.bin_file.options.machine_code_model)), | 3653 | std.zig.fmtId(@tagName(comp.bin_file.options.machine_code_model)), |
| 3651 | }); | 3654 | }); |
| 3652 | 3655 | ||
| 3656 | if (target.os.tag == .wasi) { | ||
| 3657 | const wasi_exec_model_fmt = std.zig.fmtId(@tagName(comp.bin_file.options.wasi_exec_model)); | ||
| 3658 | try buffer.writer().print( | ||
| 3659 | \\pub const wasi_exec_model = std.builtin.WasiExecModel.{}; | ||
| 3660 | \\ | ||
| 3661 | , .{wasi_exec_model_fmt}); | ||
| 3662 | } | ||
| 3663 | |||
| 3653 | if (comp.bin_file.options.is_test) { | 3664 | if (comp.bin_file.options.is_test) { |
| 3654 | try buffer.appendSlice( | 3665 | try buffer.appendSlice( |
| 3655 | \\pub var test_functions: []std.builtin.TestFn = undefined; // overwritten later | 3666 | \\pub var test_functions: []std.builtin.TestFn = undefined; // overwritten later |
src/link.zig+1-1| ... | @@ -116,7 +116,7 @@ pub const Options = struct { | ... | @@ -116,7 +116,7 @@ pub const Options = struct { |
| 116 | libc_installation: ?*const LibCInstallation, | 116 | libc_installation: ?*const LibCInstallation, |
| 117 | 117 | ||
| 118 | /// WASI-only. Type of WASI execution model ("command" or "reactor"). | 118 | /// WASI-only. Type of WASI execution model ("command" or "reactor"). |
| 119 | wasi_exec_model: ?wasi_libc.CRTFile = null, | 119 | wasi_exec_model: std.builtin.WasiExecModel = undefined, |
| 120 | 120 | ||
| 121 | pub fn effectiveOutputMode(options: Options) std.builtin.OutputMode { | 121 | pub fn effectiveOutputMode(options: Options) std.builtin.OutputMode { |
| 122 | return if (options.use_lld) .Obj else options.output_mode; | 122 | return if (options.use_lld) .Obj else options.output_mode; |
src/link/Wasm.zig+9-4| ... | @@ -687,10 +687,15 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void { | ... | @@ -687,10 +687,15 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void { |
| 687 | // before corrupting globals. See https://github.com/ziglang/zig/issues/4496 | 687 | // before corrupting globals. See https://github.com/ziglang/zig/issues/4496 |
| 688 | try argv.append("--stack-first"); | 688 | try argv.append("--stack-first"); |
| 689 | 689 | ||
| 690 | // Reactor execution model does not have _start so lld doesn't look for it. | 690 | if (self.base.options.wasi_exec_model == .reactor) { |
| 691 | if (self.base.options.wasi_exec_model) |exec_model| blk: { | 691 | // Reactor execution model does not have _start so lld doesn't look for it. |
| 692 | if (exec_model != .crt1_reactor_o) break :blk; | ||
| 693 | try argv.append("--no-entry"); | 692 | try argv.append("--no-entry"); |
| 693 | // Make sure "_initialize" is exported even if this is pure Zig WASI reactor | ||
| 694 | // where WASM_SYMBOL_EXPORTED flag in LLVM is not set on _initialize. | ||
| 695 | try argv.appendSlice(&[_][]const u8{ | ||
| 696 | "--export", | ||
| 697 | "_initialize", | ||
| 698 | }); | ||
| 694 | } | 699 | } |
| 695 | } else { | 700 | } else { |
| 696 | try argv.append("--no-entry"); // So lld doesn't look for _start. | 701 | try argv.append("--no-entry"); // So lld doesn't look for _start. |
| ... | @@ -717,7 +722,7 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void { | ... | @@ -717,7 +722,7 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void { |
| 717 | if (self.base.options.link_libc) { | 722 | if (self.base.options.link_libc) { |
| 718 | try argv.append(try comp.get_libc_crt_file( | 723 | try argv.append(try comp.get_libc_crt_file( |
| 719 | arena, | 724 | arena, |
| 720 | wasi_libc.crtFileFullName(self.base.options.wasi_exec_model orelse .crt1_o), | 725 | wasi_libc.execModelCrtFileFullName(self.base.options.wasi_exec_model), |
| 721 | )); | 726 | )); |
| 722 | try argv.append(try comp.get_libc_crt_file(arena, "libc.a")); | 727 | try argv.append(try comp.get_libc_crt_file(arena, "libc.a")); |
| 723 | } | 728 | } |
src/main.zig+9-6| ... | @@ -321,6 +321,7 @@ const usage_build_generic = | ... | @@ -321,6 +321,7 @@ const usage_build_generic = |
| 321 | \\ medium|large] | 321 | \\ medium|large] |
| 322 | \\ -mred-zone Force-enable the "red-zone" | 322 | \\ -mred-zone Force-enable the "red-zone" |
| 323 | \\ -mno-red-zone Force-disable the "red-zone" | 323 | \\ -mno-red-zone Force-disable the "red-zone" |
| 324 | \\ -mexec-model=[value] Execution model (WASI only) | ||
| 324 | \\ --name [name] Override root name (not a file path) | 325 | \\ --name [name] Override root name (not a file path) |
| 325 | \\ -O [mode] Choose what to optimize for | 326 | \\ -O [mode] Choose what to optimize for |
| 326 | \\ Debug (default) Optimizations off, safety on | 327 | \\ Debug (default) Optimizations off, safety on |
| ... | @@ -618,7 +619,7 @@ fn buildOutputType( | ... | @@ -618,7 +619,7 @@ fn buildOutputType( |
| 618 | var subsystem: ?std.Target.SubSystem = null; | 619 | var subsystem: ?std.Target.SubSystem = null; |
| 619 | var major_subsystem_version: ?u32 = null; | 620 | var major_subsystem_version: ?u32 = null; |
| 620 | var minor_subsystem_version: ?u32 = null; | 621 | var minor_subsystem_version: ?u32 = null; |
| 621 | var wasi_exec_model: ?wasi_libc.CRTFile = null; | 622 | var wasi_exec_model: ?std.builtin.WasiExecModel = null; |
| 622 | 623 | ||
| 623 | var system_libs = std.ArrayList([]const u8).init(gpa); | 624 | var system_libs = std.ArrayList([]const u8).init(gpa); |
| 624 | defer system_libs.deinit(); | 625 | defer system_libs.deinit(); |
| ... | @@ -1071,6 +1072,10 @@ fn buildOutputType( | ... | @@ -1071,6 +1072,10 @@ fn buildOutputType( |
| 1071 | mem.startsWith(u8, arg, "-I")) | 1072 | mem.startsWith(u8, arg, "-I")) |
| 1072 | { | 1073 | { |
| 1073 | try clang_argv.append(arg); | 1074 | try clang_argv.append(arg); |
| 1075 | } else if (mem.startsWith(u8, arg, "-mexec-model=")) { | ||
| 1076 | wasi_exec_model = std.meta.stringToEnum(std.builtin.WasiExecModel, arg["-mexec-model=".len..]) orelse { | ||
| 1077 | fatal("expected [command|reactor] for -mexec-mode=[value], found '{s}'", .{arg["-mexec-model=".len..]}); | ||
| 1078 | }; | ||
| 1074 | } else { | 1079 | } else { |
| 1075 | fatal("unrecognized parameter: '{s}'", .{arg}); | 1080 | fatal("unrecognized parameter: '{s}'", .{arg}); |
| 1076 | } | 1081 | } |
| ... | @@ -1277,11 +1282,9 @@ fn buildOutputType( | ... | @@ -1277,11 +1282,9 @@ fn buildOutputType( |
| 1277 | .nostdlibinc => want_native_include_dirs = false, | 1282 | .nostdlibinc => want_native_include_dirs = false, |
| 1278 | .strip => strip = true, | 1283 | .strip => strip = true, |
| 1279 | .exec_model => { | 1284 | .exec_model => { |
| 1280 | if (std.mem.eql(u8, it.only_arg, "reactor")) { | 1285 | wasi_exec_model = std.meta.stringToEnum(std.builtin.WasiExecModel, it.only_arg) orelse { |
| 1281 | wasi_exec_model = .crt1_reactor_o; | 1286 | fatal("expected [command|reactor] for -mexec-mode=[value], found '{s}'", .{it.only_arg}); |
| 1282 | } else if (std.mem.eql(u8, it.only_arg, "command")) { | 1287 | }; |
| 1283 | wasi_exec_model = .crt1_command_o; | ||
| 1284 | } | ||
| 1285 | }, | 1288 | }, |
| 1286 | } | 1289 | } |
| 1287 | } | 1290 | } |
src/wasi_libc.zig+9-3| ... | @@ -45,9 +45,15 @@ pub fn emulatedLibCRFileLibName(crt_file: CRTFile) []const u8 { | ... | @@ -45,9 +45,15 @@ pub fn emulatedLibCRFileLibName(crt_file: CRTFile) []const u8 { |
| 45 | }; | 45 | }; |
| 46 | } | 46 | } |
| 47 | 47 | ||
| 48 | pub fn crtFileFullName(crt_file: CRTFile) []const u8 { | 48 | pub fn execModelCrtFile(wasi_exec_model: std.builtin.WasiExecModel) CRTFile { |
| 49 | return switch (crt_file) { | 49 | return switch (wasi_exec_model) { |
| 50 | .crt1_o => "crt1.o", | 50 | .reactor => CRTFile.crt1_reactor_o, |
| 51 | .command => CRTFile.crt1_command_o, | ||
| 52 | }; | ||
| 53 | } | ||
| 54 | |||
| 55 | pub fn execModelCrtFileFullName(wasi_exec_model: std.builtin.WasiExecModel) []const u8 { | ||
| 56 | return switch (execModelCrtFile(wasi_exec_model)) { | ||
| 51 | .crt1_reactor_o => "crt1-reactor.o", | 57 | .crt1_reactor_o => "crt1-reactor.o", |
| 52 | .crt1_command_o => "crt1-command.o", | 58 | .crt1_command_o => "crt1-command.o", |
| 53 | else => unreachable, | 59 | else => unreachable, |