I am building a Webassembly runtime and am currently implementing the WASI APIs. I'm wondering how the ABI looks like, according to this document: https://github.com/WebAssembly/WASI/blob/main/phases/snapshot/docs.md
To test, I have compiled this C application with emscripten to a standalone WASM module.
#include <stdio.h>
int main() {
printf("Hello, World!\n");
return 0;
}
After checking with wasm-objdump, I can see the following function imports:
Import[2]:
- func[0] sig=2 <__wasi_proc_exit> <- wasi_snapshot_preview1.proc_exit
- func[1] sig=11 <__wasi_fd_write> <- wasi_snapshot_preview1.fd_write
with the type signatures:
- type[2] (i32) -> nil
- type[11] (i32, i32, i32, i32) -> i32
According to the spec, the fd_write
function has the signature fd_write(fd: fd, iovs: ciovec_array) -> Result<size, errno>
, which maps to the POSIX system call ssize_t writev(int fd, const struct iovec *iov, int iovcnt);
.
But what is the fourth argument in the WASM file? It receives some pointer to a memory address. So I thought I would have to write Result<size, errno>
to that address, but if I do that and return 0 (for success), the fd_write
gets called just over and over again (presumably because the printf function assumes that nothing was written). If I return the written bytes, the program terminates correctly, but what is then the fourth argument?
Also, how can I return more complex Result
s, which do not fit into an i32?
In wasi-libc, the function signature of __wasi_fd_read
is:
__wasi_errno_t __wasi_fd_read( __wasi_fd_t fd, const __wasi_iovec_t *iovs, size_t iovs_len, __wasi_size_t *retptr0 )
According to some implementations of fd_write
, the last argument is a pointer to return the number of bytes written, and the return value is always 0 (like what you did).
So I guess you should also set the number of bytes that have been read to where retptr0
points to.