Skip to content

Commit

Permalink
add examples/hostfunc
Browse files Browse the repository at this point in the history
  • Loading branch information
yamt committed Nov 1, 2023
1 parent b176da2 commit 58ae563
Show file tree
Hide file tree
Showing 5 changed files with 235 additions and 0 deletions.
21 changes: 21 additions & 0 deletions examples/hostfunc/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
cmake_minimum_required(VERSION 3.16)

project(runwasi LANGUAGES C)

set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wvla -Werror")

find_package(toywasm-lib-core REQUIRED)
find_package(toywasm-lib-wasi REQUIRED)

# REVISIT: make runwasi.[ch] a library?

set(sources
"../runwasi/runwasi.c"
"../runwasi/runwasi_cli_args.c"
"main.c"
"hostfunc.c"
)

add_executable(hostfunc ${sources})
target_link_libraries(hostfunc toywasm-lib-core toywasm-lib-wasi m)
target_include_directories(hostfunc PRIVATE "../runwasi")
61 changes: 61 additions & 0 deletions examples/hostfunc/hostfunc.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@

#include <errno.h>
#include <stdlib.h>

#include <toywasm/endian.h>
#include <toywasm/host_instance.h>

static int
my_host_inst_load(struct exec_context *ctx, struct host_instance *hi,
const struct functype *ft, const struct cell *params,
struct cell *results)
{
HOST_FUNC_CONVERT_PARAMS(ft, params);
uint32_t pp = HOST_FUNC_PARAM(ft, params, 0, i32);
int host_ret;
uint32_t le32;

host_ret = host_func_copyin(ctx, &le32, pp, 4, 4);
if (host_ret != 0) {
goto fail;
}
uint32_t p = le32_to_host(le32);
host_ret = host_func_copyin(ctx, &le32, p, 4, 4);
if (host_ret != 0) {
goto fail;
}
uint32_t result = le32_to_host(le32);
p += 4;
le32 = host_to_le32(p);
host_ret = host_func_copyout(ctx, &le32, pp, 4, 4);
if (host_ret != 0) {
goto fail;
}
fail:
if (host_ret == 0) {
HOST_FUNC_RESULT_SET(ft, results, 0, i32, result);
}
HOST_FUNC_FREE_CONVERTED_PARAMS();
return host_ret;
}

static const struct host_func my_host_inst_funcs[] = {
HOST_FUNC(my_host_inst_, load, "(i)i"),
};

static const struct name name_my_host_inst =
NAME_FROM_CSTR_LITERAL("my-host-func");

static const struct host_module module_my_host_inst[] = {{
.module_name = &name_my_host_inst,
.funcs = my_host_inst_funcs,
.nfuncs = ARRAYCOUNT(my_host_inst_funcs),
}};

int
import_object_create_for_my_host_inst(void *inst, struct import_object **impp)
{
return import_object_create_for_host_funcs(
module_my_host_inst, ARRAYCOUNT(module_my_host_inst), inst,
impp);
}
4 changes: 4 additions & 0 deletions examples/hostfunc/hostfunc.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
struct import_object;

int import_object_create_for_my_host_inst(void *inst,
struct import_object **impp);
51 changes: 51 additions & 0 deletions examples/hostfunc/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* an example app to run a wasi command.
*
* usage:
* % runwasi --dir=. --env=a=b -- foo.wasm -x -y
*/

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

#include <toywasm/xlog.h>

#include "hostfunc.h"
#include "runwasi.h"
#include "runwasi_cli_args.h"

int
main(int argc, char **argv)
{
struct runwasi_cli_args a0;
struct runwasi_cli_args *a = &a0;
uint32_t wasi_exit_code;
int ret;
const int stdio_fds[3] = {
STDIN_FILENO,
STDOUT_FILENO,
STDERR_FILENO,
};
ret = runwasi_cli_args_parse(argc, argv, a);
if (ret != 0) {
xlog_error("failed to process cli arguments");
exit(1);
}
struct import_object *import_obj;
ret = import_object_create_for_my_host_inst(NULL, &import_obj);
if (ret != 0) {
exit(1);
}
ret = runwasi(a->filename, a->ndirs, a->dirs, a->nenvs,
(const char *const *)a->envs, a->argc,
(const char *const *)a->argv, stdio_fds, import_obj,
&wasi_exit_code);
free(a->dirs);
free(a->envs);
if (ret != 0) {
exit(1);
}
exit(wasi_exit_code);
}
98 changes: 98 additions & 0 deletions examples/hostfunc/wasm/test.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
#include <assert.h>
#include <stdint.h>
#include <stdio.h>

#if defined(USE_HOST_LOAD)
uintptr_t load(const uintptr_t **p)
__attribute__((__import_module__("my-host-func")))
__attribute__((__import_name__("load")));
#else
uintptr_t
load(const uintptr_t **p)
{
return *(*p)++;
}
#endif

uintptr_t
load_add(const uintptr_t **p)
{
uintptr_t a = load(p);
uintptr_t b = load(p);
return a + b;
}

typedef uintptr_t (*fn_t)(const uintptr_t **p);

uintptr_t
load_call(const uintptr_t **p)
{
fn_t f = (void *)load(p);
return f(p);
}

uintptr_t
load_call_add(const uintptr_t **p)
{
uintptr_t a = load_call(p);
uintptr_t b = load_call(p);
return a + b;
}

// sum([1..16]) = 136
const uintptr_t table[] = {
(uintptr_t)load_call_add,
(uintptr_t)load_call_add,
(uintptr_t)load_call_add,
(uintptr_t)load_call_add,
(uintptr_t)load_add,
1,
2,
(uintptr_t)load_add,
3,
4,
(uintptr_t)load_call_add,
(uintptr_t)load_add,
5,
6,
(uintptr_t)load_add,
7,
8,
(uintptr_t)load_call,
(uintptr_t)load_call_add,
(uintptr_t)load_call_add,
(uintptr_t)load_call,
(uintptr_t)load_call,
(uintptr_t)load_call,
(uintptr_t)load_call,
(uintptr_t)load_add,
9,
10,
(uintptr_t)load_add,
11,
12,
(uintptr_t)load_call_add,
(uintptr_t)load,
13,
(uintptr_t)load_call,
(uintptr_t)load_add,
14,
15,
(uintptr_t)load_call,
(uintptr_t)load_call,
(uintptr_t)load_call,
(uintptr_t)load,
16,
};

int
main()
{
const uintptr_t expected = 136;
const uintptr_t *p = table;
uintptr_t result = load_call(&p);
assert(p - table == sizeof(table) / sizeof(table[0]));
printf("result %ju (expected %ju)\n", (uintmax_t)result,
(uintmax_t)expected);
assert(result == expected);
}

0 comments on commit 58ae563

Please sign in to comment.