| author | |
| committer | |
| log | bc7761d8e0bb70adb3c76c588f9f0b62937c6571 |
| tree | 571b5b93cd6611d458cb728198b9796cff9da3ac |
| parent | a95ba0d10d582020dbd3e6efded53f17287ed211 |
| signature | Signed by PGP key 4AEE18F83AFDEB23 |
* 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 | 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 | 467 | /// This data structure is used by the Zig language code generation and |
| 461 | 468 | /// therefore must be kept in sync with the compiler implementation. |
| 462 | 469 | pub const Version = struct { |
lib/std/start.zig+17-11| ... | ... | @@ -65,8 +65,9 @@ comptime { |
| 65 | 65 | } |
| 66 | 66 | } else if (native_os == .uefi) { |
| 67 | 67 | if (!@hasDecl(root, "EfiMain")) @export(EfiMain, .{ .name = "EfiMain" }); |
| 68 | } else if (native_arch.isWasm() and native_os == .freestanding) { | |
| 69 | if (!@hasDecl(root, start_sym_name)) @export(wasm_freestanding_start, .{ .name = start_sym_name }); | |
| 68 | } else if (native_arch.isWasm()) { | |
| 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 | 71 | } else if (native_os != .other and native_os != .freestanding) { |
| 71 | 72 | if (!@hasDecl(root, start_sym_name)) @export(_start, .{ .name = start_sym_name }); |
| 72 | 73 | } |
| ... | ... | @@ -135,10 +136,21 @@ fn _DllMainCRTStartup( |
| 135 | 136 | return std.os.windows.TRUE; |
| 136 | 137 | } |
| 137 | 138 | |
| 138 | fn wasm_freestanding_start() callconv(.C) void { | |
| 139 | // This is marked inline because for some reason LLVM in release mode fails to inline it, | |
| 139 | fn wasm_start() callconv(.C) void { | |
| 140 | // The entrypoint is marked inline because for some reason LLVM in release mode fails to inline it, | |
| 140 | 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 | 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 | 176 | } |
| 165 | 177 | |
| 166 | 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 | 179 | switch (native_arch) { |
| 174 | 180 | .x86_64 => { |
| 175 | 181 | argc_argv_ptr = asm volatile ( |
src/Compilation.zig+14-3| ... | ... | @@ -724,7 +724,7 @@ pub const InitOptions = struct { |
| 724 | 724 | test_name_prefix: ?[]const u8 = null, |
| 725 | 725 | subsystem: ?std.Target.SubSystem = null, |
| 726 | 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 | 730 | fn addPackageTableToCacheHash( |
| ... | ... | @@ -790,6 +790,9 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { |
| 790 | 790 | |
| 791 | 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 | 796 | const comp: *Compilation = comp: { |
| 794 | 797 | // For allocations that have the same lifetime as Compilation. This arena is used only during this |
| 795 | 798 | // initialization and then is freed in deinit(). |
| ... | ... | @@ -1340,7 +1343,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { |
| 1340 | 1343 | .disable_lld_caching = options.disable_lld_caching, |
| 1341 | 1344 | .subsystem = options.subsystem, |
| 1342 | 1345 | .is_test = options.is_test, |
| 1343 | .wasi_exec_model = options.wasi_exec_model, | |
| 1346 | .wasi_exec_model = wasi_exec_model, | |
| 1344 | 1347 | }); |
| 1345 | 1348 | errdefer bin_file.destroy(); |
| 1346 | 1349 | comp.* = .{ |
| ... | ... | @@ -1442,7 +1445,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { |
| 1442 | 1445 | }); |
| 1443 | 1446 | } |
| 1444 | 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 | 1449 | .{ .wasi_libc_crt_file = .libc_a }, |
| 1447 | 1450 | }); |
| 1448 | 1451 | } |
| ... | ... | @@ -3650,6 +3653,14 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: *Allocator) Alloc |
| 3650 | 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 | 3664 | if (comp.bin_file.options.is_test) { |
| 3654 | 3665 | try buffer.appendSlice( |
| 3655 | 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 | 116 | libc_installation: ?*const LibCInstallation, |
| 117 | 117 | |
| 118 | 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 | 121 | pub fn effectiveOutputMode(options: Options) std.builtin.OutputMode { |
| 122 | 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 | 687 | // before corrupting globals. See https://github.com/ziglang/zig/issues/4496 |
| 688 | 688 | try argv.append("--stack-first"); |
| 689 | 689 | |
| 690 | // Reactor execution model does not have _start so lld doesn't look for it. | |
| 691 | if (self.base.options.wasi_exec_model) |exec_model| blk: { | |
| 692 | if (exec_model != .crt1_reactor_o) break :blk; | |
| 690 | if (self.base.options.wasi_exec_model == .reactor) { | |
| 691 | // Reactor execution model does not have _start so lld doesn't look for it. | |
| 693 | 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 | 700 | } else { |
| 696 | 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 | 722 | if (self.base.options.link_libc) { |
| 718 | 723 | try argv.append(try comp.get_libc_crt_file( |
| 719 | 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 | 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 | 321 | \\ medium|large] |
| 322 | 322 | \\ -mred-zone Force-enable the "red-zone" |
| 323 | 323 | \\ -mno-red-zone Force-disable the "red-zone" |
| 324 | \\ -mexec-model=[value] Execution model (WASI only) | |
| 324 | 325 | \\ --name [name] Override root name (not a file path) |
| 325 | 326 | \\ -O [mode] Choose what to optimize for |
| 326 | 327 | \\ Debug (default) Optimizations off, safety on |
| ... | ... | @@ -618,7 +619,7 @@ fn buildOutputType( |
| 618 | 619 | var subsystem: ?std.Target.SubSystem = null; |
| 619 | 620 | var major_subsystem_version: ?u32 = null; |
| 620 | 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 | 624 | var system_libs = std.ArrayList([]const u8).init(gpa); |
| 624 | 625 | defer system_libs.deinit(); |
| ... | ... | @@ -1071,6 +1072,10 @@ fn buildOutputType( |
| 1071 | 1072 | mem.startsWith(u8, arg, "-I")) |
| 1072 | 1073 | { |
| 1073 | 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 | 1079 | } else { |
| 1075 | 1080 | fatal("unrecognized parameter: '{s}'", .{arg}); |
| 1076 | 1081 | } |
| ... | ... | @@ -1277,11 +1282,9 @@ fn buildOutputType( |
| 1277 | 1282 | .nostdlibinc => want_native_include_dirs = false, |
| 1278 | 1283 | .strip => strip = true, |
| 1279 | 1284 | .exec_model => { |
| 1280 | if (std.mem.eql(u8, it.only_arg, "reactor")) { | |
| 1281 | wasi_exec_model = .crt1_reactor_o; | |
| 1282 | } else if (std.mem.eql(u8, it.only_arg, "command")) { | |
| 1283 | wasi_exec_model = .crt1_command_o; | |
| 1284 | } | |
| 1285 | wasi_exec_model = std.meta.stringToEnum(std.builtin.WasiExecModel, it.only_arg) orelse { | |
| 1286 | fatal("expected [command|reactor] for -mexec-mode=[value], found '{s}'", .{it.only_arg}); | |
| 1287 | }; | |
| 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 | 45 | }; |
| 46 | 46 | } |
| 47 | 47 | |
| 48 | pub fn crtFileFullName(crt_file: CRTFile) []const u8 { | |
| 49 | return switch (crt_file) { | |
| 50 | .crt1_o => "crt1.o", | |
| 48 | pub fn execModelCrtFile(wasi_exec_model: std.builtin.WasiExecModel) CRTFile { | |
| 49 | return switch (wasi_exec_model) { | |
| 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 | 57 | .crt1_reactor_o => "crt1-reactor.o", |
| 52 | 58 | .crt1_command_o => "crt1-command.o", |
| 53 | 59 | else => unreachable, |