diff --git a/CMakeLists.txt b/CMakeLists.txt index 2c34f334f..38bd9a2a7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -607,6 +607,8 @@ set(ZIG_STD_FILES "os/path.zig" "os/time.zig" "os/uefi.zig" + "os/wasi.zig" + "os/wasi/core.zig" "os/windows.zig" "os/windows/advapi32.zig" "os/windows/error.zig" diff --git a/src/ir.cpp b/src/ir.cpp index 3d4ab45dc..db45496f3 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -15828,6 +15828,13 @@ static void add_link_lib_symbol(IrAnalyze *ira, Buf *lib_name, Buf *symbol_name, ira->codegen->reported_bad_link_libc_error = true; } + bool is_wasi = buf_eql_str(lib_name, "wasi"); + if (is_wasi && ira->codegen->zig_target->os != OsWASI) { + ir_add_error_node(ira, source_node, + buf_sprintf("linking against wasi library")); + ira->codegen->reported_bad_link_libc_error = true; + } + LinkLib *link_lib = add_link_lib(ira->codegen, lib_name); for (size_t i = 0; i < link_lib->symbols.length; i += 1) { Buf *existing_symbol_name = link_lib->symbols.at(i); @@ -15836,7 +15843,7 @@ static void add_link_lib_symbol(IrAnalyze *ira, Buf *lib_name, Buf *symbol_name, } } - if (!is_libc && !ira->codegen->have_pic && !ira->codegen->reported_bad_link_libc_error) { + if (!is_libc && !is_wasi && !ira->codegen->have_pic && !ira->codegen->reported_bad_link_libc_error) { ErrorMsg *msg = ir_add_error_node(ira, source_node, buf_sprintf("dependency on dynamic library '%s' requires enabling Position Independent Code", buf_ptr(lib_name))); diff --git a/src/link.cpp b/src/link.cpp index 78e549c80..6c6ff07ba 100644 --- a/src/link.cpp +++ b/src/link.cpp @@ -1091,7 +1091,9 @@ static void construct_linker_job_wasm(LinkJob *lj) { CodeGen *g = lj->codegen; lj->args.append("-error-limit=0"); - lj->args.append("--no-entry"); // So lld doesn't look for _start. + if (g->zig_target->os != OsWASI) { + lj->args.append("--no-entry"); // So lld doesn't look for _start. + } lj->args.append("--allow-undefined"); lj->args.append("--export-all"); lj->args.append("-o"); diff --git a/std/os.zig b/std/os.zig index d641cf29c..c1d5aa409 100644 --- a/std/os.zig +++ b/std/os.zig @@ -23,6 +23,7 @@ test "std.os" { _ = @import("os/time.zig"); _ = @import("os/windows.zig"); _ = @import("os/uefi.zig"); + _ = @import("os/wasi.zig"); _ = @import("os/get_app_data_dir.zig"); } @@ -33,6 +34,7 @@ pub const freebsd = @import("os/freebsd.zig"); pub const netbsd = @import("os/netbsd.zig"); pub const zen = @import("os/zen.zig"); pub const uefi = @import("os/uefi.zig"); +pub const wasi = @import("os/wasi.zig"); pub const posix = switch (builtin.os) { Os.linux => linux, @@ -40,6 +42,7 @@ pub const posix = switch (builtin.os) { Os.freebsd => freebsd, Os.netbsd => netbsd, Os.zen => zen, + Os.wasi => wasi, else => @compileError("Unsupported OS"), }; @@ -187,7 +190,7 @@ pub fn abort() noreturn { c.abort(); } switch (builtin.os) { - Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => { + Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd, Os.wasi => { _ = posix.raise(posix.SIGABRT); _ = posix.raise(posix.SIGKILL); while (true) {} diff --git a/std/os/wasi.zig b/std/os/wasi.zig new file mode 100644 index 000000000..23c3a05af --- /dev/null +++ b/std/os/wasi.zig @@ -0,0 +1,108 @@ +pub use @import("wasi/core.zig"); + +// Based on https://github.com/CraneStation/wasi-sysroot/blob/wasi/libc-bottom-half/headers/public/wasi/core.h +// and https://github.com/CraneStation/wasmtime/blob/master/docs/WASI-api.md + +pub const STDIN_FILENO = 0; +pub const STDOUT_FILENO = 1; +pub const STDERR_FILENO = 2; + +pub const ESUCCESS = 0; +pub const E2BIG = 1; +pub const EACCES = 2; +pub const EADDRINUSE = 3; +pub const EADDRNOTAVAIL = 4; +pub const EAFNOSUPPORT = 5; +pub const EAGAIN = 6; +pub const EALREADY = 7; +pub const EBADF = 8; +pub const EBADMSG = 9; +pub const EBUSY = 10; +pub const ECANCELED = 11; +pub const ECHILD = 12; +pub const ECONNABORTED = 13; +pub const ECONNREFUSED = 14; +pub const ECONNRESET = 15; +pub const EDEADLK = 16; +pub const EDESTADDRREQ = 17; +pub const EDOM = 18; +pub const EDQUOT = 19; +pub const EEXIST = 20; +pub const EFAULT = 21; +pub const EFBIG = 22; +pub const EHOSTUNREACH = 23; +pub const EIDRM = 24; +pub const EILSEQ = 25; +pub const EINPROGRESS = 26; +pub const EINTR = 27; +pub const EINVAL = 28; +pub const EIO = 29; +pub const EISCONN = 30; +pub const EISDIR = 31; +pub const ELOOP = 32; +pub const EMFILE = 33; +pub const EMLINK = 34; +pub const EMSGSIZE = 35; +pub const EMULTIHOP = 36; +pub const ENAMETOOLONG = 37; +pub const ENETDOWN = 38; +pub const ENETRESET = 39; +pub const ENETUNREACH = 40; +pub const ENFILE = 41; +pub const ENOBUFS = 42; +pub const ENODEV = 43; +pub const ENOENT = 44; +pub const ENOEXEC = 45; +pub const ENOLCK = 46; +pub const ENOLINK = 47; +pub const ENOMEM = 48; +pub const ENOMSG = 49; +pub const ENOPROTOOPT = 50; +pub const ENOSPC = 51; +pub const ENOSYS = 52; +pub const ENOTCONN = 53; +pub const ENOTDIR = 54; +pub const ENOTEMPTY = 55; +pub const ENOTRECOVERABLE = 56; +pub const ENOTSOCK = 57; +pub const ENOTSUP = 58; +pub const ENOTTY = 59; +pub const ENXIO = 60; +pub const EOVERFLOW = 61; +pub const EOWNERDEAD = 62; +pub const EPERM = 63; +pub const EPIPE = 64; +pub const EPROTO = 65; +pub const EPROTONOSUPPORT = 66; +pub const EPROTOTYPE = 67; +pub const ERANGE = 68; +pub const EROFS = 69; +pub const ESPIPE = 70; +pub const ESRCH = 71; +pub const ESTALE = 72; +pub const ETIMEDOUT = 73; +pub const ETXTBSY = 74; +pub const EXDEV = 75; +pub const ENOTCAPABLE = 76; + +// TODO: implement this like darwin does +pub fn getErrno(r: usize) usize { + const signed_r = @bitCast(isize, r); + return if (signed_r > -4096 and signed_r < 0) @intCast(usize, -signed_r) else 0; +} + +pub fn exit(status: i32) noreturn { + __wasi_proc_exit(@bitCast(__wasi_exitcode_t, isize(status))); +} + +pub fn write(fd: i32, buf: [*]const u8, count: usize) usize { + var nwritten: usize = undefined; + + const iovs = []__wasi_ciovec_t{__wasi_ciovec_t{ + .buf = buf, + .buf_len = count, + }}; + + _ = __wasi_fd_write(@bitCast(__wasi_fd_t, isize(fd)), &iovs[0], iovs.len, &nwritten); + return nwritten; +} diff --git a/std/os/wasi/core.zig b/std/os/wasi/core.zig new file mode 100644 index 000000000..cda06cdce --- /dev/null +++ b/std/os/wasi/core.zig @@ -0,0 +1,17 @@ +pub const __wasi_errno_t = u16; +pub const __wasi_exitcode_t = u32; +pub const __wasi_fd_t = u32; +pub const __wasi_signal_t = u8; + +pub const __wasi_ciovec_t = extern struct { + buf: [*]const u8, + buf_len: usize, +}; + +pub const __WASI_SIGABRT: __wasi_signal_t = 6; + +pub extern "wasi" fn __wasi_proc_raise(sig: __wasi_signal_t) __wasi_errno_t; + +pub extern "wasi" fn __wasi_proc_exit(rval: __wasi_exitcode_t) noreturn; + +pub extern "wasi" fn __wasi_fd_write(fd: __wasi_fd_t, iovs: *const __wasi_ciovec_t, iovs_len: usize, nwritten: *usize) __wasi_errno_t; diff --git a/std/special/bootstrap.zig b/std/special/bootstrap.zig index 32f913a5b..520561d54 100644 --- a/std/special/bootstrap.zig +++ b/std/special/bootstrap.zig @@ -20,6 +20,10 @@ comptime { } nakedcc fn _start() noreturn { + if (builtin.os == builtin.Os.wasi) { + std.os.wasi.__wasi_proc_exit(callMain()); + } + switch (builtin.arch) { builtin.Arch.x86_64 => { argc_ptr = asm ("lea (%%rsp), %[argc]" diff --git a/std/special/panic.zig b/std/special/panic.zig index 7cb714395..64d9bf39f 100644 --- a/std/special/panic.zig +++ b/std/special/panic.zig @@ -9,10 +9,15 @@ const std = @import("std"); pub fn panic(msg: []const u8, error_return_trace: ?*builtin.StackTrace) noreturn { @setCold(true); switch (builtin.os) { - // TODO: fix panic in zen. + // TODO: fix panic in zen builtin.Os.freestanding, builtin.Os.zen => { while (true) {} }, + builtin.Os.wasi => { + std.debug.warn("{}", msg); + _ = std.os.wasi.__wasi_proc_raise(std.os.wasi.__WASI_SIGABRT); + unreachable; + }, builtin.Os.uefi => { // TODO look into using the debug info and logging helpful messages std.os.abort();