Search code examples
webassemblywasi

ABI format of WASI functions


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 Results, which do not fit into an i32?


Solution

  • 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.