Skip to content

Commit

Permalink
add a C version of wasi_hook
Browse files Browse the repository at this point in the history
  • Loading branch information
yamt committed Jun 25, 2023
1 parent dcb8fd3 commit 72bda6c
Show file tree
Hide file tree
Showing 7 changed files with 216 additions and 0 deletions.
1 change: 1 addition & 0 deletions examples/wasi_hook_c/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
C version of [wasi_hook](../wasi_hook).
34 changes: 34 additions & 0 deletions examples/wasi_hook_c/app.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#include <assert.h>
#include <sys/uio.h>

#include <stdio.h>
#include <unistd.h>

#define bufsize 100

int
main()
{
char buf[bufsize];
ssize_t len;

len = read(STDIN_FILENO, buf, sizeof(buf));
assert(len > 0);
printf("hello, \"%.*s\"\n", (int)len, buf);

char fub[bufsize];
struct iovec iov[sizeof(fub)];
ssize_t len2;
int i;
for (i = 0; i < sizeof(fub); i++) {
iov[i].iov_base = &fub[sizeof(fub) - 1 - i];
iov[i].iov_len = 1;
}
len2 = readv(STDIN_FILENO, iov, sizeof(iov));
assert(len2 == len);
/* skip NUL */
assert(fub[sizeof(fub) - len2] == 0);
len2--;
printf("hello, \"%.*s\" (reversed)\n", (int)len2,
&fub[sizeof(fub) - len2]);
}
64 changes: 64 additions & 0 deletions examples/wasi_hook_c/hook-asm.S
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
.text

.tabletype __indirect_function_table, funcref
.globaltype __stack_pointer, i32

.functype my_fd_read (i32,i32,i32,i32) -> (i32)
.functype init_C () -> ()

.functype pivot_set_func (i32,funcref) -> ()
.import_module pivot_set_func,pivot
.import_name pivot_set_func,set_func

.globaltype sp, i32
.globaltype mypage, i32
sp:
mypage:

.globl _initialize
.type _initialize,@function

.globl set_func
.type set_func,@function

_initialize:
.functype _initialize () -> ()
.export_name _initialize,_initialize

# set up C context for this module.
#
# steal a page via memory.grow.
# this requires the main module prepared for this.
# cf. https://github.com/WebAssembly/wasi-libc/pull/377
#
# todo: tls

.local i32

i32.const 1
memory.grow 0
local.tee 0
i32.const -1
i32.eq
if
unreachable
end_if
local.get 0
global.set mypage
local.get 0
i32.const 1
i32.add
i32.const 65536
i32.mul
global.set sp

call init_C
end_function

set_func:
.functype set_func (i32, i32) -> ()
local.get 0
local.get 1
table.get __indirect_function_table
call pivot_set_func
end_function
65 changes: 65 additions & 0 deletions examples/wasi_hook_c/hook-c.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
#include <string.h>
#include <sys/uio.h>

/*
* CAVEAT: only very limited C environment is available here.
*
* - no data/bss (as it overlaps with the main app)
* - no tls
*/

int
my_fd_read(int fd, struct iovec *iov, size_t iovlen, size_t *retp)
{
/*
* this function does something unnecessarily complex to ensure
* using C stack
*/

char buf[10];

/*
* we avoid using string literals because
* they are usually placed in (ro)data section.
* we assume that the compiler is not smart enough to
* turn this into a single memcpy from rodata.
*
* note: linear memory is little endian.
*/
unsigned int meow = 0x776f654d;
unsigned int in_c = 0x43206e69;
memcpy(buf, &meow, 4);
buf[4] = ' ';
memcpy(&buf[5], &in_c, 4);
buf[9] = 0;

const char *cp = buf;
size_t len = strlen(cp) + 1;
while (iovlen > 0) {
size_t n;
if (len > iov->iov_len) {
n = iov->iov_len;
} else {
n = len;
}
memcpy(iov->iov_base, cp, n);
cp += n;
len -= n;
iov++;
iovlen--;
}
*retp = cp - buf;
return 0;
}

void
init_C()
{
void set_func(int, void *);

/*
* the first argument of set_func is the index in $func-table
* in pivot.wat.
*/
set_func(0, my_fd_read);
}
17 changes: 17 additions & 0 deletions examples/wasi_hook_c/pivot.wat
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
(module
(type $fd_read_type (func (param i32 i32 i32 i32) (result i32)))
(func (export "fd_read") (type $fd_read_type)
local.get 0
local.get 1
local.get 2
local.get 3
i32.const 0
call_indirect $func-table (type $fd_read_type)
)
(func (export "set_func") (param i32 funcref)
local.get 0
local.get 1
table.set $func-table
)
(table $func-table 1 1 funcref)
)
11 changes: 11 additions & 0 deletions examples/wasi_hook_c/repl.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
:load pivot.wasm
:register pivot
:register wasi_snapshot_preview1

:module app load app.wasm
:register app

:load hook.wasm
:invoke _initialize

:module app invoke _start
24 changes: 24 additions & 0 deletions examples/wasi_hook_c/run.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#! /bin/sh

set -e

CC=${CC:-/opt/wasi-sdk-20.0/bin/clang}
TOYWASM=${TOYWASM:-toywasm}

wat2wasm pivot.wat

${CC} -o app.wasm app.c

CFLAGS="-O3 -mreference-types -Wall -Werror"
${CC} -c ${CFLAGS} hook-asm.S
${CC} -c ${CFLAGS} hook-c.c
# note: --import-memory makes the linker to use __wasm_init_memory
${CC} -v \
-Wl,--no-entry \
-Wl,--export=__wasm_call_ctors \
-Xlinker --import-memory=app,memory \
-nostdlib \
-o hook.wasm hook-asm.o hook-c.o -lc

${TOYWASM} --trace=5 --wasi --repl < repl.txt
#${TOYWASM} --wasi --repl < repl.txt

0 comments on commit 72bda6c

Please sign in to comment.