From 16d95a39d949eaa2b4a46ce406ba5665ec6db722 Mon Sep 17 00:00:00 2001 From: Adam Laszlo Kulcsar Date: Mon, 6 Nov 2023 14:31:35 +0100 Subject: [PATCH] Implement emscripten compability Change runExports so that wasi imports can be used. Improve fd_write so that emscipten compiled programs can be used. Also add example programs. Also update build file to use not use incorrect flags on windows. Signed-off-by: Adam Laszlo Kulcsar --- build/wasi.cmake | 18 ++++---- src/shell/Shell.cpp | 59 +++++++++++++++++++++---- src/wasi/Fd.h | 12 ++--- src/wasi/Wasi.h | 6 --- test/wasi/hello_world.wast | 24 ---------- test/wasi/hello_world/hello_world.c | 14 ++++++ test/wasi/hello_world/hello_world.wasm | Bin 0 -> 11945 bytes test/wasi/hello_world/hello_world.wast | 23 ++++++++++ test/wasi/proc_exit.wast | 11 ----- test/wasi/proc_exit/proc_exit.c | 7 +++ test/wasi/proc_exit/proc_exit.wasm | Bin 0 -> 595 bytes test/wasi/proc_exit/proc_exit.wast | 11 +++++ 12 files changed, 118 insertions(+), 67 deletions(-) delete mode 100644 test/wasi/hello_world.wast create mode 100644 test/wasi/hello_world/hello_world.c create mode 100755 test/wasi/hello_world/hello_world.wasm create mode 100644 test/wasi/hello_world/hello_world.wast delete mode 100644 test/wasi/proc_exit.wast create mode 100644 test/wasi/proc_exit/proc_exit.c create mode 100755 test/wasi/proc_exit/proc_exit.wasm create mode 100644 test/wasi/proc_exit/proc_exit.wast diff --git a/build/wasi.cmake b/build/wasi.cmake index 59be8c760..504d75808 100644 --- a/build/wasi.cmake +++ b/build/wasi.cmake @@ -7,20 +7,20 @@ if(CMAKE_C_COMPILER_ID MATCHES "AppleClang|Clang|GNU") list(APPEND uvwasi_cflags -fvisibility=hidden --std=gnu89) list(APPEND uvwasi_cflags -Wall -Wsign-compare -Wextra -Wstrict-prototypes) list(APPEND uvwasi_cflags -Wno-unused-parameter) -endif() - -set( CMAKE_C_FLAGS -fPIC) + set( CMAKE_C_FLAGS -fPIC) -if(DEFINED WALRUS_ARCH) - if(${WALRUS_ARCH} STREQUAL "x86") + if(DEFINED WALRUS_ARCH) + if(${WALRUS_ARCH} STREQUAL "x86") set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m32") + endif() endif() -endif() -if(DEFINED WALRUS_MODE) - if(${WALRUS_MODE} STREQUAL "debug") - set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g") + if(DEFINED WALRUS_MODE) + if(${WALRUS_MODE} STREQUAL "debug") + set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g") + endif() endif() + endif() if(APPLE) diff --git a/src/shell/Shell.cpp b/src/shell/Shell.cpp index 09b3fb50a..997ec0ced 100644 --- a/src/shell/Shell.cpp +++ b/src/shell/Shell.cpp @@ -290,7 +290,31 @@ static Trap::TrapResult executeWASM(Store* store, const std::string& filename, c Walrus::Trap trap; return trap.run([](ExecutionState& state, void* d) { RunData* data = reinterpret_cast(d); - data->module->instantiate(state, data->importValues); + Instance* instance = data->module->instantiate(state, data->importValues); + + for (auto&& exp : data->module->exports()) { + if (exp->exportType() == ExportType::Function) { + if ("_start" != exp->name()) { + continue; + } + + auto fn = instance->function(exp->itemIndex()); + FunctionType* fnType = fn->asDefinedFunction()->moduleFunction()->functionType(); + + if (!fnType->param().empty()) { + printf("warning: function %s has params, but params are not supported\n", exp->name().c_str()); + return; + } + + if (!fnType->result().empty()) { + printf("warning: function %s has results, but results are not supported\n", exp->name().c_str()); + return; + } + + + fn->call(state, nullptr, nullptr); + } + } }, &data); } @@ -872,7 +896,7 @@ static void executeWAST(Store* store, const std::string& filename, const std::ve } } -static void runExports(Store* store, const std::string& filename, const std::vector& src, std::string& exportToRun) +static void runExports(Store* store, const std::string& filename, const std::vector& src, std::string& exportToRun, SpecTestFunctionTypes& functionTypes) { auto parseResult = WASMParser::parseBinary(store, filename, src.data(), src.size()); @@ -888,21 +912,38 @@ static void runExports(Store* store, const std::string& filename, const std::vec } const auto& importTypes = module->imports(); + ExternVector importValues; + importValues.reserve(importTypes.size()); - if (importTypes.size() != 0) { - fprintf(stderr, "error: module has imports, but imports are not supported\n"); - return; + for (size_t i = 0; i < importTypes.size(); i++) { + auto import = importTypes[i]; + if (import->moduleName() == "wasi_snapshot_preview1") { + Walrus::WASI::WasiFunc* wasiImportFunc = WASI::find(import->fieldName()); + if (wasiImportFunc != nullptr) { + FunctionType* fn = functionTypes[wasiImportFunc->functionType]; + if (fn->equals(import->functionType())) { + importValues.push_back(WasiFunction::createWasiFunction( + store, + const_cast(import->functionType()), + wasiImportFunc->ptr)); + } + } + } else { + fprintf(stderr, "error: module has imports, but imports are not supported\n"); + return; + } } struct RunData { Module* module; + ExternVector& importValues; std::string* exportToRun; - } data = { module.value(), &exportToRun }; + } data = { module.value(), importValues, &exportToRun }; Walrus::Trap trap; trap.run([](ExecutionState& state, void* d) { auto data = reinterpret_cast(d); - Instance* instance = data->module->instantiate(state, ExternVector()); + Instance* instance = data->module->instantiate(state, data->importValues); for (auto&& exp : data->module->exports()) { if (exp->exportType() == ExportType::Function) { @@ -1033,7 +1074,7 @@ int main(int argc, char* argv[]) } if (endsWith(filePath, "wasm")) { if (!argParser.exportToRun.empty()) { - runExports(store, filePath, buf, argParser.exportToRun); + runExports(store, filePath, buf, argParser.exportToRun, functionTypes); } else { auto trapResult = executeWASM(store, filePath, buf, functionTypes); if (trapResult.exception) { @@ -1051,9 +1092,9 @@ int main(int argc, char* argv[]) } // finalize + delete wasi; delete store; delete engine; - delete wasi; #if defined(WALRUS_GOOGLE_PERF) ProfilerStop(); diff --git a/src/wasi/Fd.h b/src/wasi/Fd.h index e27676868..8c86a3df8 100644 --- a/src/wasi/Fd.h +++ b/src/wasi/Fd.h @@ -22,7 +22,6 @@ void WASI::fd_write(ExecutionState& state, Value* argv, Value* result, Instance* uint32_t iovptr = argv[1].asI32(); uint32_t iovcnt = argv[2].asI32(); uint32_t out = argv[3].asI32(); - WASI::wasi_iovec_t wasi_iovs; if (!WASI::checkMemOffset(instance->memory(0), iovptr, iovcnt)) { result[0] = Value(static_cast(WASI::wasi_errno::inval)); @@ -30,17 +29,14 @@ void WASI::fd_write(ExecutionState& state, Value* argv, Value* result, Instance* return; } - uint32_t offset = *reinterpret_cast(instance->memory(0)->buffer() + iovptr); - wasi_iovs.buf = reinterpret_cast(instance->memory(0)->buffer() + offset); - wasi_iovs.len = *reinterpret_cast(instance->memory(0)->buffer() + iovptr + sizeof(uvwasi_size_t)); - std::vector iovs(iovcnt); for (uint32_t i = 0; i < iovcnt; i++) { - iovs[i].buf_len = wasi_iovs.len; - iovs[0].buf = wasi_iovs.buf; + iovs[i].buf = instance->memory(0)->buffer() + *reinterpret_cast(instance->memory(0)->buffer() + iovptr + i * 8); + iovs[i].buf_len = *(instance->memory(0)->buffer() + iovptr + 4 + i * 8); } - uvwasi_size_t out_addr; + uvwasi_size_t out_addr = *(instance->memory(0)->buffer() + out); + result[0] = Value(static_cast(uvwasi_fd_write(WASI::m_uvwasi, fd, iovs.data(), iovs.size(), &out_addr))); *(instance->memory(0)->buffer() + out) = out_addr; } diff --git a/src/wasi/Wasi.h b/src/wasi/Wasi.h index f7d7be360..c90d976ee 100644 --- a/src/wasi/Wasi.h +++ b/src/wasi/Wasi.h @@ -114,12 +114,6 @@ class WASI { ERRORS(TO_ENUM) } wasi_errno_t; #undef TO_ENUM - - typedef struct wasi_iovec { - uint8_t* buf; - uint32_t len; - } wasi_iovec_t; - // end of type definitions WASI(); diff --git a/test/wasi/hello_world.wast b/test/wasi/hello_world.wast deleted file mode 100644 index 49367b31d..000000000 --- a/test/wasi/hello_world.wast +++ /dev/null @@ -1,24 +0,0 @@ -(module - (import "wasi_snapshot_preview1" "fd_write" (func $__wasi_fd_write (param i32 i32 i32 i32) (result i32))) - (memory 1) - - (export "memory" (memory 0)) - (export "_start" (func $_start)) - (data (i32.const 0) "Hello World!\n") - - (func $_start (result i32) - (i32.store (i32.const 24) (i32.const 13)) ;; Lenght of "Hello World!\n" - (i32.store (i32.const 20) (i32.const 0)) ;; memory offset of "Hello World!\n" - (call $__wasi_fd_write - (i32.const 1) ;;file descriptor - (i32.const 20) ;;offset of str offset - (i32.const 1) ;;iovec length - (i32.const 30) ;;result offset - ) - drop - i32.const 32 - i32.load - ) -) - -(assert_return (invoke "_start") (i32.const 0)) diff --git a/test/wasi/hello_world/hello_world.c b/test/wasi/hello_world/hello_world.c new file mode 100644 index 000000000..c8c046b01 --- /dev/null +++ b/test/wasi/hello_world/hello_world.c @@ -0,0 +1,14 @@ +#include +#include + +/* Emscripten compile command: +`emcc hello_world.c --no-entry -sEXPORTED_FUNCTIONS=_start -s EXPORTED_RUNTIME_METHODS=ccall,cwrap -o hello_world.wasm` + + Run in walrus with `walrus --run-export _start hello_world.wasm` +*/ + +int main() +{ + fprintf(stdout, "Hello World!\n"); + return 0; +} diff --git a/test/wasi/hello_world/hello_world.wasm b/test/wasi/hello_world/hello_world.wasm new file mode 100755 index 0000000000000000000000000000000000000000..4f582cb49de30be4641494bc69af6e0142985a21 GIT binary patch literal 11945 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 literal 0 HcmV?d00001 diff --git a/test/wasi/proc_exit/proc_exit.wast b/test/wasi/proc_exit/proc_exit.wast new file mode 100644 index 000000000..e0878b962 --- /dev/null +++ b/test/wasi/proc_exit/proc_exit.wast @@ -0,0 +1,11 @@ +(module + (import "wasi_snapshot_preview1" "proc_exit" (func $wasi_proc_exit (param i32))) + + + (func (export "proc_exit") + i32.const 0 + call $wasi_proc_exit + ) +) + +(assert_return (invoke "proc_exit"))