WIP: WASI Support (#267)
* feat: Preliminary WASI with fib workload * refactor: Clarify initialize globals * chore: Update empty to WASI * chore: cleanup fib test * chore: cleanup build tooling * chore: cleanup test Makefiles and some nits * chore: Update LLVM and install WASI-SDK * chore: Update build tools and specs * docs: Update example module spec in README * refactor: Clean up HTTP handling * feat: Implement exit WASI call * style: apply clang-format * ci: rewrite compile sledge step * build: Remove LLVM install shims * build: Try manually adding libunwind * build: Try adding libunwind-dev * ci: break out aWsm compile step * fix: Correct test build error * fix: Correct error in WASI fd_write * chore: Increase gocr http buffer size * test: Correct image resize test * chore: Remove zombie wasmception functions * chore: Reduce dummy args to single arg * chore: Add debugging makefile fivebyeight * chore: Remove erronious PHONYs in tests Makefile * ci: Disable gocr tests * chore: Add wat Make rule to fibonacci test * chore: fix apt package name * chore: Enable clean of failed ck install * chore: use LLVM 12 * test: Disable gocr tests * chore: Enhance test makefile * chore: Add CFILES as sledgert dep * chore: Add NULL check for function table pointer * chore: Add missing header * chore: uncomment cleanup in imageresize test * refactor: Remove unused linear memory functions * build: Add bimodal debug makefile * chore: Add linear memory debug logs * refactor: Cleanup region initialization * build: Correct PHONY in runtime Makefile * chore: deb install script for outside of container * refactor: Remove zombie extern. * feat: WebAssembly traps * refactor: Use C18 features * chore: Remove git diff annotations * fix: tweaks to run all sample apps with WASI * test: convert shell script to Makefile * build: clean generated ck Makefile * chore: Use awsm branch with fixes * chore: Revert name changes * fix: Correct type issues * refactor: Reverse additional name change * refactor: Remove awsm compat shims * chore: Remove libc association * build: Better detect header file changes * refactor: current_wasm_module_instance_trap * test: reenable tests * chore: Delete copied script * build: Fix test workloads * fix: Implement HTTP 500 * fix: Protect against overflow on comparison * build: Replace test.sh with makefile * refactor: blow away tmp directory conflicts * refactor: centralize wasm in single submodule * feat: libsledge and sledge ABI * chore: move tests * refactor: tests * chore: update wasm_apps with new sample data * doc: Initial ABI README * feat: globals table * docs: Merge aWsm ABI docs * docs: libsledge ABI * build: rename apps to keep consistent * build: Disable wasm proposals * build: Update wasm apps and fix typo * test: test makefiles * test: Additional test makefiles * build: top-level build and install rules wo Docker * docs: Add wasm lld comment * build: top level makefile * chore: merge debug flags * fix: Correct out of bounds error * feat: indirection to awsm ABI * fix: Correct link hack with proper flag * fix: gps typo * chore: format nit * ci: update makefile rules * ci: check WASI_SDK_PATH * fix: Adjust paths * ci: fix make rule name * refactor: Attempt to use generic vec * refactor: Remove type-specific vec * fix: Resolve assorted TODOs * chore: fix clang format issue * ci: Invalidate app cache on libsledge changes * fix: Correct wasm trap check * fix: free wasm globals * docs: example of running top level tests via make * chore: option to log unsupported wasi * test: add preempt client generator for fib bimodal * refactor: Allocate wasm memory with 4096 align * fix: Handle build without runtime globals * refactor: bypass runtime call for first global * fix: Correct sandbox logging * test: fix incorrect paths in test.mk * refactor: remove wasm traps * refactor: Revert additional traps and changes * refactor: Remove additional traps * refactor: Disable exit support * fix: block preemption in memory allocation * feat: wasm g0 write back * build: cleanup applications Makefile * chore: Reorder bash variables * docs: Add comment explaining LOG_SANDBOX_STDERR * fix: Remove tracking of nonpreemptive siglarms * chore: Validate Linux, C, and POSIX requirements * build: Dry up libsledge makefile * refactor: Remove unused macros * fix: Writeback global 0 on cooperative sched * refactor: Fork WASI from aWsm uvwasi example * build: remove awsm-wasi rules * chore: clang-format 15 * ci: apt update * chore: clang 13 * ci: use llvm script * ci: Use LLVM 13 * refactor: Remove WASI indirectionmaster
parent
5d19891e63
commit
7cacac64c0
@ -1,57 +1,56 @@
|
||||
SHELL:=/bin/bash
|
||||
ARCH:=$(shell arch)
|
||||
|
||||
COMPILER=awsm
|
||||
ROOT=${ROOT:-$(cd "$(dirname ${BASH_SOURCE:-$0})" && pwd)}
|
||||
WASMCEPTION_URL=https://github.com/gwsystems/wasmception/releases/download/v0.2.0/wasmception-linux-x86_64-0.2.0.tar.gz
|
||||
|
||||
# TODO: Add ARM release build
|
||||
.PHONY: build
|
||||
build:
|
||||
ifeq ($(ARCH),x86_64)
|
||||
cd ./awsm/wasmception && wget ${WASMCEPTION_URL} -O wasmception.tar.gz && tar xvfz wasmception.tar.gz && rm wasmception.tar.gz
|
||||
endif
|
||||
test -f ./${COMPILER}/wasmception/dist/bin/clang || make -C ${COMPILER}/wasmception
|
||||
@cd ${COMPILER} && RUSTUP_TOOLCHAIN=stable cargo build --release && cd ${ROOT}
|
||||
|
||||
# Sanity check that the aWsm compiler built and is in our PATH
|
||||
.PHONY: build-validate
|
||||
build-validate:
|
||||
which awsm
|
||||
awsm --version
|
||||
|
||||
.PHONY: build-dev
|
||||
build-dev:
|
||||
test -f ./${COMPILER}/wasmception/dist/bin/clang || make -C ${COMPILER}/wasmception
|
||||
@echo "Building aWsm compiler (default==debug)"
|
||||
@cd ${COMPILER} && cargo build && cd ${ROOT}
|
||||
|
||||
.PHONY: all
|
||||
all: awsm libsledge runtime
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
@echo "Cleaning aWsm compiler"
|
||||
@cd ${COMPILER} && cargo clean && cd ${ROOT}
|
||||
|
||||
# wasmception is too slow to recompile,
|
||||
# so lets not make that part of the "aWsm" cleanup
|
||||
.PHONY: wclean
|
||||
wclean:
|
||||
@echo "Cleaning wasmception toolchain"
|
||||
@cd ${COMPILER} && make -C wasmception clean && cd ${ROOT}
|
||||
|
||||
.PHONY: rtinit
|
||||
rtinit:
|
||||
@echo "Building runtime for the first time!"
|
||||
make -C runtime init
|
||||
clean: awsm.clean libsledge.clean runtime.clean
|
||||
|
||||
.PHONY: runtime
|
||||
runtime:
|
||||
@echo "Building runtime!"
|
||||
make -C runtime
|
||||
.PHONY: submodules
|
||||
submodules:
|
||||
git submodule update --init --recursive
|
||||
|
||||
.PHONY: install
|
||||
install: build rtinit
|
||||
@./install.sh wasmception
|
||||
install: submodules all
|
||||
|
||||
# aWsm: the WebAssembly to LLVM bitcode compiler
|
||||
.PHONY: awsm
|
||||
awsm:
|
||||
cd awsm && cargo build --release
|
||||
|
||||
.PHONY: awsm.clean
|
||||
awsm.clean:
|
||||
cd awsm && cargo clean
|
||||
|
||||
# libsledge: the support library linked with LLVM bitcode emitted by aWsm when building *.so modules
|
||||
.PHONY: libsledge
|
||||
libsledge:
|
||||
make -C libsledge clean all
|
||||
make -C libsledge dist/libsledge.a
|
||||
|
||||
.PHONY: libsledge.clean
|
||||
libsledge.clean:
|
||||
make -C libsledge clean
|
||||
|
||||
# sledgert: the runtime that executes *.so modules
|
||||
.PHONY: runtime
|
||||
runtime:
|
||||
make -C runtime
|
||||
|
||||
|
||||
.PHONY: runtime.clean
|
||||
runtime.clean:
|
||||
make -C runtime clean
|
||||
|
||||
# SLEdge Applications
|
||||
.PHONY: applications
|
||||
applications:
|
||||
make -C applications all
|
||||
|
||||
.PHONY: applications.clean
|
||||
applications.clean:
|
||||
make -C applications clean
|
||||
|
||||
# Tests
|
||||
.PHONY: test
|
||||
test:
|
||||
make -f test.mk all
|
||||
|
@ -1,3 +1 @@
|
||||
*.wasm
|
||||
*.bc
|
||||
*.so
|
||||
dist/*
|
||||
|
@ -0,0 +1 @@
|
||||
Subproject commit 1125852cf199a53bf194f53da880aca97b64c124
|
@ -1 +0,0 @@
|
||||
Subproject commit 9e01b5a5914d3456c3018b3265d74a01656d10bd
|
@ -1 +0,0 @@
|
||||
Subproject commit 8c2654d622e39b0eee84a3fd00174c2cfb5996ee
|
@ -1,12 +0,0 @@
|
||||
WASMCC=wasm32-unknown-unknown-wasm-clang
|
||||
OPTFLAGS=-O3 -flto
|
||||
WASMLINKFLAGS=-Wl,-z,stack-size=524288,--allow-undefined,--no-threads,--stack-first,--no-entry,--export-all,--export=main,--export=dummy
|
||||
WASMCFLAGS=${WASMLINKFLAGS} -nostartfiles
|
||||
|
||||
all: empty.wasm
|
||||
|
||||
clean:
|
||||
rm -rf empty.wasm
|
||||
|
||||
empty.wasm: *.c
|
||||
${WASMCC} ${WASMCFLAGS} ${OPTFLAGS} $^ -o $@
|
@ -1,11 +0,0 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
printf("S\n");
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
// !!! HACK ALERT !!!
|
||||
// We need the __init_libc symbol in the output executable (so the runtime can initialize libc)
|
||||
// We can't directly export it since it's in a linked library
|
||||
// Thus we export a dummy function that uses it, forcing it to be included
|
||||
|
||||
|
||||
#define IMPORT __attribute__((visibility("default")))
|
||||
#define EXPORT __attribute__((visibility("default")))
|
||||
|
||||
IMPORT void __init_libc(char **, char *);
|
||||
EXPORT void
|
||||
dummy()
|
||||
{
|
||||
__init_libc(0, 0);
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
WASMCC=wasm32-unknown-unknown-wasm-clang
|
||||
OPTFLAGS=-O3 -flto
|
||||
WASMLINKFLAGS=-Wl,-z,stack-size=524288,--allow-undefined,--no-threads,--stack-first,--no-entry,--export=main,--export=dummy,--export=__init_libc
|
||||
WASMCFLAGS=${WASMLINKFLAGS} -nostartfiles
|
||||
|
||||
all: fibonacci.wasm
|
||||
|
||||
clean:
|
||||
rm -rf fibonacci.wasm
|
||||
|
||||
fibonacci.wasm: *.c
|
||||
${WASMCC} ${WASMCFLAGS} ${OPTFLAGS} $^ -o $@
|
@ -1,20 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
|
||||
uint32_t
|
||||
fib(uint32_t n)
|
||||
{
|
||||
if (n <= 1) return n;
|
||||
return fib(n - 1) + fib(n - 2);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
uint32_t n = 0;
|
||||
scanf("%u", &n);
|
||||
|
||||
uint32_t result = fib(n);
|
||||
printf("%u\n", result);
|
||||
return 0;
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
// !!! HACK ALERT !!!
|
||||
// We need the __init_libc symbol in the output executable (so the runtime can initialize libc)
|
||||
// We can't directly export it since it's in a linked library
|
||||
// Thus we export a dummy function that uses it, forcing it to be included
|
||||
|
||||
|
||||
#define IMPORT __attribute__((visibility("default")))
|
||||
#define EXPORT __attribute__((visibility("default")))
|
||||
|
||||
IMPORT void __init_libc(char **, char *);
|
||||
EXPORT void
|
||||
dummy()
|
||||
{
|
||||
__init_libc(0, 0);
|
||||
}
|
@ -1 +0,0 @@
|
||||
Subproject commit 0976fd036462264f581a588fa6cfa46718c67716
|
@ -1 +0,0 @@
|
||||
Subproject commit 3bdd8c58c7f9159dd88ec56e5beefccdd503ad9e
|
@ -1 +0,0 @@
|
||||
Subproject commit 0ef276b96503c40bedae5e85453d28e738743f93
|
@ -1,147 +0,0 @@
|
||||
#!/bin/bash
|
||||
# This script is responsible for copying, linking, and aliasing all of our build tools such that they are
|
||||
# in known paths that we can add to PATH and LD_LIBRARY_PATH. The binaries go into "${SYS_PREFIX}/bin" and
|
||||
# the libraries go into "${SYS_PREFIX}/lib". By default, SYS_PREFIX is `/opt/sledge/`, which means that this
|
||||
# script is assumed to be executed as root, as in our Docker build container. However, by by setting
|
||||
# SYS_PREFIX to a directory that the user has access to, this can be avoided.
|
||||
#
|
||||
# For example, in the GitHub Actions workflow, SYS_PREFIX is set to the topmost project directory and the
|
||||
# environment is updated as follows.
|
||||
#
|
||||
# SYS_PREFIX="$(pwd)" ./install.sh
|
||||
# PATH="$(pwd)/bin:$PATH"
|
||||
# LD_LIBRARY_PATH="$(pwd)/lib:$LD_LIBRARY_PATH"
|
||||
#
|
||||
# This is currently executed
|
||||
# - Indirectly via `make install` in the root Makefile, typically when the sledge-dev build container is built
|
||||
# - Directly by the GitHub workflow
|
||||
#
|
||||
# The script takes either wasmception or wasi as the first argument to install either wasmception or WASI-SDK
|
||||
# If no argument is provided, wasmception is assumed
|
||||
# If either wasmception or wasi is provided, an additional `-d` or `--dry-run` flag can be provided to view the commands
|
||||
# and paths that would be generated. This is helpful for sanity checking when setting SYS_PREFIX and using in a new context
|
||||
|
||||
echo "Setting up toolchain environment"
|
||||
|
||||
for last_arg in "$@"; do :; done
|
||||
|
||||
if [[ $last_arg == "-d" ]] || [[ $last_arg == "--dry-run" ]]; then
|
||||
DRY_RUN=true
|
||||
else
|
||||
DRY_RUN=false
|
||||
fi
|
||||
|
||||
if $DRY_RUN; then
|
||||
DRY_RUN_PREFIX=echo
|
||||
else
|
||||
DRY_RUN_PREFIX=
|
||||
fi
|
||||
|
||||
# Get the absolute path of the topmost project directly
|
||||
# The use of dirname is particular. It seems unneccesary how this script is run
|
||||
SYS_SRC_PREFIX=${SYS_SRC_PREFIX:-"$(
|
||||
cd "$(dirname "$(dirname "${0}")")" || exit 1
|
||||
pwd -P
|
||||
)"}
|
||||
$DRY_RUN && echo SYS_SRC_PREFIX: "$SYS_SRC_PREFIX"
|
||||
|
||||
# And check for the presence of this script to make sure we got it right
|
||||
if [ ! -x "${SYS_SRC_PREFIX}/install.sh" ]; then
|
||||
echo "Unable to find the install script" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
SYS_NAME='sledge'
|
||||
COMPILER='awsm'
|
||||
COMPILER_EXECUTABLE=$COMPILER
|
||||
|
||||
# /opt/sledge
|
||||
SYS_PREFIX=${SYS_PREFIX:-"/opt/${SYS_NAME}"}
|
||||
$DRY_RUN && echo SYS_PREFIX: "$SYS_PREFIX"
|
||||
|
||||
# /sledge, where the sledge repo is mounted from the host
|
||||
SYS_SRC_PREFIX=${SYS_SRC_PREFIX:-"/${SYS_NAME}"}
|
||||
$DRY_RUN && echo SYS_SRC_PREFIX: "$SYS_SRC_PREFIX"
|
||||
|
||||
# The release directory containing the binary of the aWsm compiler
|
||||
SYS_COMPILER_REL_DIR=${SYS_COMPILER_REL_DIR:-"${SYS_SRC_PREFIX}/${COMPILER}/target/release"}
|
||||
$DRY_RUN && echo SYS_COMPILER_REL_DIR: "$SYS_COMPILER_REL_DIR"
|
||||
|
||||
# /opt/sledge/bin
|
||||
SYS_BIN_DIR=${SYS_BIN_DIR:-"${SYS_PREFIX}/bin"}
|
||||
$DRY_RUN && echo SYS_BIN_DIR: "$SYS_BIN_DIR"
|
||||
|
||||
# /opt/sledge/lib
|
||||
SYS_LIB_DIR=${SYS_LIB_DIR:-"${SYS_PREFIX}/lib"}
|
||||
$DRY_RUN && echo SYS_LIB_DIR: "$SYS_LIB_DIR"
|
||||
|
||||
# The first argument can be either wasi or wasmception. This determines the system interface used
|
||||
# The default is wasmception
|
||||
# Currently, WASI is not actually supported by the runtime.
|
||||
if [ $# -eq 0 ] || [ "$1" = "wasmception" ]; then
|
||||
echo "Setting up for wasmception"
|
||||
WASM_PREFIX=${WASM_PREFIX:-"${SYS_SRC_PREFIX}/${COMPILER}/wasmception"}
|
||||
WASM_BIN=${WASM_BIN:-"${WASM_PREFIX}/dist/bin"}
|
||||
WASM_SYSROOT=${WASM_SYSROOT:-"${WASM_PREFIX}/sysroot"}
|
||||
WASM_TARGET=${WASM_TARGET:-"wasm32-unknown-unknown-wasm"}
|
||||
WASM_BIN_PREFIX=${WASM_BIN_PREFIX:-"$WASM_TARGET"}
|
||||
WASM_TOOLS=(ar)
|
||||
elif [ "$1" = "wasi" ]; then
|
||||
echo "Setting up for wasi-sdk"
|
||||
WASM_PREFIX=${WASM_PREFIX:-${WASM_SDK:-"/opt/wasi-sdk"}}
|
||||
WASM_BIN=${WASM_BIN:-"${WASM_PREFIX}/bin"}
|
||||
WASM_SYSROOT=${WASM_SYSROOT:-"${WASM_PREFIX}/share/sysroot"}
|
||||
WASM_TARGET=${WASM_TARGET:-"wasm32-wasi"}
|
||||
WASM_BIN_PREFIX=${WASM_BIN_PREFIX:-"$WASM_TARGET"}
|
||||
WASM_TOOLS=(ar dwarfdump nm ranlib size)
|
||||
fi
|
||||
$DRY_RUN && echo WASM_PREFIX: "$WASM_PREFIX"
|
||||
$DRY_RUN && echo WASM_BIN: "$WASM_BIN"
|
||||
$DRY_RUN && echo WASM_SYSROOT: "$WASM_SYSROOT"
|
||||
$DRY_RUN && echo WASM_TARGET: "$WASM_TARGET"
|
||||
$DRY_RUN && echo WASM_BIN_PREFIX: "$WASM_BIN_PREFIX"
|
||||
$DRY_RUN && echo WASM_TOOLS: "${WASM_TOOLS[@]}"
|
||||
|
||||
# Delete all existing installations of the binaries
|
||||
$DRY_RUN_PREFIX rm -f "${SYS_BIN_DIR}"/*
|
||||
|
||||
# And reinstall
|
||||
$DRY_RUN_PREFIX install -d -v "$SYS_BIN_DIR" || exit 1
|
||||
|
||||
# Symbolically link the Awsm compiler
|
||||
# /sledge/awsm/target/release/silverfish /opt/sledge/bin/awsm
|
||||
$DRY_RUN_PREFIX ln -sfv "${SYS_COMPILER_REL_DIR}/${COMPILER_EXECUTABLE}" "${SYS_BIN_DIR}/${COMPILER_EXECUTABLE}"
|
||||
|
||||
# Generate shell script stubs that act as aliases that automatically set the approproiate target and sysroot
|
||||
# for either Wasmception or WASI-SDK
|
||||
# For example, when wasmception is set, calling `wasm32-unknown-unknown-wasm-clang` results in
|
||||
# `exec "/sledge/awsm/wasmception/dist/bin/clang" --target="wasm32-unknown-unknown-wasm" --sysroot="/sledge/awsm/wasmception/sysroot" "$@"`
|
||||
for file in clang clang++; do
|
||||
wrapper_file="$(mktemp)"
|
||||
cat > "$wrapper_file" << EOT
|
||||
#! /bin/sh
|
||||
|
||||
exec "${WASM_BIN}/${file}" --target="$WASM_TARGET" --sysroot="$WASM_SYSROOT" "\$@"
|
||||
EOT
|
||||
cat "$wrapper_file"
|
||||
$DRY_RUN_PREFIX install -p -v "$wrapper_file" "${SYS_BIN_DIR}/${WASM_BIN_PREFIX}-${file}"
|
||||
$DRY_RUN && echo rm -f "$wrapper_file"
|
||||
rm -f "$wrapper_file"
|
||||
done
|
||||
|
||||
# Link the LLVM Tools with the proper prefix
|
||||
for file in "${WASM_TOOLS[@]}"; do
|
||||
$DRY_RUN_PREFIX ln -sfv "${WASM_BIN}/llvm-${file}" "${SYS_BIN_DIR}/${WASM_BIN_PREFIX}-${file}"
|
||||
done
|
||||
|
||||
# Link any other tools with the proper prefix
|
||||
OTHER_TOOLS=(ld)
|
||||
for file in "${OTHER_TOOLS[@]}"; do
|
||||
$DRY_RUN_PREFIX ln -sfv "${WASM_BIN}/wasm-${file}" "${SYS_BIN_DIR}/${WASM_BIN_PREFIX}-${file}"
|
||||
done
|
||||
|
||||
# Link clang as gcc if needed
|
||||
$DRY_RUN_PREFIX ln -svf "${SYS_BIN_DIR}/${WASM_BIN_PREFIX}-clang" "${SYS_BIN_DIR}/${WASM_BIN_PREFIX}-gcc"
|
||||
$DRY_RUN_PREFIX ln -svf "${SYS_BIN_DIR}/${WASM_BIN_PREFIX}-clang++" "${SYS_BIN_DIR}/${WASM_BIN_PREFIX}-g++"
|
||||
|
||||
echo "Done!"
|
@ -0,0 +1,33 @@
|
||||
#!/bin/bash
|
||||
|
||||
HEY_URL=https://hey-release.s3.us-east-2.amazonaws.com/hey_linux_amd64
|
||||
LLVM_VERSION=12
|
||||
SHELLCHECK_URL=https://github.com/koalaman/shellcheck/releases/download/v0.7.1/shellcheck-v0.7.1.linux.x86_64.tar.xz
|
||||
SHFMT_URL=https://github.com/mvdan/sh/releases/download/v3.2.4/shfmt_v3.2.4_linux_amd64
|
||||
WASI_SDK_URL=https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-12/wasi-sdk_12.0_amd64.deb
|
||||
|
||||
apt-get update && apt-get install -y --no-install-recommends \
|
||||
bc \
|
||||
fonts-dejavu \
|
||||
fonts-cascadia-code \
|
||||
fonts-roboto \
|
||||
gnuplot \
|
||||
imagemagick \
|
||||
jq \
|
||||
libz3-4 \
|
||||
netpbm \
|
||||
pango1.0-tools \
|
||||
wamerican
|
||||
|
||||
wget $HEY_URL -O hey && chmod +x hey && sudo mv hey /usr/bin/hey
|
||||
|
||||
wget $SHFMT_URL -O shfmt && chmod +x shfmt && sudo mv shfmt /usr/local/bin/shfmt
|
||||
|
||||
wget $SHELLCHECK_URL -O shellcheck && chmod +x shellcheck && sudo mv shellcheck /usr/local/bin/shellcheck
|
||||
|
||||
./install_llvm.sh $LLVM_VERSION
|
||||
|
||||
curl -sS -L -O $WASI_SDK_URL && dpkg -i wasi-sdk_12.0_amd64.deb && rm -f wasi-sdk_12.0_amd64.deb
|
||||
|
||||
echo "Add WASI_SDK_PATH to your bashrc and resource!"
|
||||
echo "Example: export WASI_SDK_PATH=/opt/wasi-sdk"
|
@ -1,39 +1,34 @@
|
||||
#!/bin/bash
|
||||
# Installs LLVM tooling, delegating the to the LLVM script as much as possible
|
||||
# We need to shim support for LLVM 8 because the LLVM script only supports 9-12
|
||||
|
||||
LLVM_VERSION=$1
|
||||
|
||||
echo "Installing LLVM $LLVM_VERSION"
|
||||
|
||||
# Script Installs clang, lldb, lld, and clangd
|
||||
if [[ "$LLVM_VERSION" -gt 8 ]]; then
|
||||
curl --proto '=https' --tlsv1.2 -sSf https://apt.llvm.org/llvm.sh | bash -s -- "$LLVM_VERSION"
|
||||
else
|
||||
apt-get install -y --no-install-recommends \
|
||||
"clang-$LLVM_VERSION" \
|
||||
"lldb-$LLVM_VERSION" \
|
||||
"lld-$LLVM_VERSION" \
|
||||
"clangd-$LLVM_VERSION"
|
||||
fi
|
||||
curl --proto '=https' --tlsv1.2 -sSf https://apt.llvm.org/llvm.sh | bash -s -- "$LLVM_VERSION"
|
||||
|
||||
apt-get install -y --no-install-recommends \
|
||||
"libc++-$LLVM_VERSION-dev" \
|
||||
"libc++abi-$LLVM_VERSION-dev" \
|
||||
"libc++1-$LLVM_VERSION"
|
||||
"libc++1-$LLVM_VERSION" \
|
||||
"libunwind-$LLVM_VERSION" \
|
||||
"libunwind-$LLVM_VERSION-dev" \
|
||||
"clang-tools-$LLVM_VERSION" \
|
||||
"clang-tidy-$LLVM_VERSION" \
|
||||
"clang-format-$LLVM_VERSION"
|
||||
|
||||
sudo update-alternatives --remove-all clang-format
|
||||
sudo update-alternatives --remove-all clang
|
||||
sudo update-alternatives --remove-all clang++
|
||||
sudo update-alternatives --remove-all llvm-config
|
||||
sudo update-alternatives --remove-all llvm-objdump
|
||||
sudo update-alternatives --remove-all llvm-objdump
|
||||
sudo update-alternatives --remove-all clang-tidy
|
||||
|
||||
update-alternatives --install /usr/bin/clang-format clang-format "/usr/bin/clang-format-$LLVM_VERSION" 100
|
||||
update-alternatives --install /usr/bin/clang clang "/usr/bin/clang-$LLVM_VERSION" 100
|
||||
update-alternatives --install /usr/bin/clang++ clang++ "/usr/bin/clang++-$LLVM_VERSION" 100
|
||||
update-alternatives --install /usr/bin/llvm-config llvm-config "/usr/bin/llvm-config-$LLVM_VERSION" 100
|
||||
update-alternatives --install /usr/bin/llvm-objdump llvm-objdump "/usr/bin/llvm-objdump-$LLVM_VERSION" 100
|
||||
|
||||
# Explicitly use at least clang-format-11 to format source because of changes between 10 and 11
|
||||
if [[ "$LLVM_VERSION" -ge 11 ]]; then
|
||||
apt-get install -y --no-install-recommends \
|
||||
"clang-format-$LLVM_VERSION"
|
||||
update-alternatives --install /usr/bin/clang-format clang-format "/usr/bin/clang-format-$LLVM_VERSION" 100
|
||||
else
|
||||
apt-get install -y --no-install-recommends \
|
||||
"clang-format-11"
|
||||
update-alternatives --install /usr/bin/clang-format clang-format "/usr/bin/clang-format-11" 100
|
||||
fi
|
||||
update-alternatives --install /usr/bin/clang-tidy clang-tidy "/usr/bin/clang-tidy-$LLVM_VERSION" 100
|
||||
|
@ -1,5 +0,0 @@
|
||||
A WebAssembly module instance is statically linked with the backing functions implementing the wasm32 ABI, yielding a *.so file that SLEdge can execute. This ensures that the instance is able to aggressively inline and optimize this code.
|
||||
|
||||
They are broken into instruction types as on https://webassembly.github.io/spec/core/exec/instructions.html. They depend on common headers for the WebAssembly types located in the WebAssembly instance struct. These are located in runtime/include/common.
|
||||
|
||||
The stubs correspond to awsm/src/codegen/runtime_stubs.rs
|
@ -0,0 +1,313 @@
|
||||
#include <stdint.h>
|
||||
#include "sledge_abi.h"
|
||||
|
||||
// TODO: Validate uint32_t as return value;
|
||||
|
||||
uint32_t
|
||||
wasi_snapshot_preview1_args_get(__wasi_size_t argv_retoffset, __wasi_size_t argv_buf_retoffset)
|
||||
{
|
||||
return sledge_abi__wasi_snapshot_preview1_args_get(argv_buf_retoffset, argv_buf_retoffset);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
wasi_snapshot_preview1_args_sizes_get(__wasi_size_t argc_retoffset, __wasi_size_t argv_buf_len_retoffset)
|
||||
{
|
||||
return sledge_abi__wasi_snapshot_preview1_args_sizes_get(argc_retoffset, argv_buf_len_retoffset);
|
||||
};
|
||||
|
||||
uint32_t
|
||||
wasi_snapshot_preview1_clock_res_get(__wasi_clockid_t id, __wasi_size_t resolution_retoffset)
|
||||
{
|
||||
return sledge_abi__wasi_snapshot_preview1_clock_res_get(id, resolution_retoffset);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
wasi_snapshot_preview1_clock_time_get(__wasi_clockid_t clock_id, __wasi_timestamp_t precision,
|
||||
__wasi_size_t time_retoffset)
|
||||
{
|
||||
return sledge_abi__wasi_snapshot_preview1_clock_time_get(clock_id, precision, time_retoffset);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
wasi_snapshot_preview1_environ_get(__wasi_size_t env_retoffset, __wasi_size_t env_buf_retoffset)
|
||||
{
|
||||
return sledge_abi__wasi_snapshot_preview1_environ_get(env_retoffset, env_buf_retoffset);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
wasi_snapshot_preview1_environ_sizes_get(__wasi_size_t envc_retoffset, __wasi_size_t env_buf_len_retoffset)
|
||||
{
|
||||
return sledge_abi__wasi_snapshot_preview1_environ_sizes_get(envc_retoffset, env_buf_len_retoffset);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
wasi_snapshot_preview1_fd_advise(__wasi_fd_t fd, __wasi_filesize_t file_offset, __wasi_filesize_t len,
|
||||
uint32_t advice_extended)
|
||||
{
|
||||
return sledge_abi__wasi_snapshot_preview1_fd_advise(fd, file_offset, len, advice_extended);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
wasi_snapshot_preview1_fd_allocate(__wasi_fd_t fd, __wasi_filesize_t offset, __wasi_filesize_t len)
|
||||
{
|
||||
return sledge_abi__wasi_snapshot_preview1_fd_allocate(fd, offset, len);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
wasi_snapshot_preview1_fd_close(__wasi_fd_t fd)
|
||||
{
|
||||
return sledge_abi__wasi_snapshot_preview1_fd_close(fd);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
wasi_snapshot_preview1_fd_datasync(__wasi_fd_t fd)
|
||||
{
|
||||
return sledge_abi__wasi_snapshot_preview1_fd_datasync(fd);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
wasi_snapshot_preview1_fd_fdstat_get(__wasi_fd_t fd, __wasi_size_t fdstat_retoffset)
|
||||
{
|
||||
return sledge_abi__wasi_snapshot_preview1_fd_fdstat_get(fd, fdstat_retoffset);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
wasi_snapshot_preview1_fd_fdstat_set_flags(__wasi_fd_t fd, uint32_t fdflags_extended)
|
||||
{
|
||||
return sledge_abi__wasi_snapshot_preview1_fd_fdstat_set_flags(fd, fdflags_extended);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
wasi_snapshot_preview1_fd_fdstat_set_rights(__wasi_fd_t fd, __wasi_rights_t fs_rights_base,
|
||||
__wasi_rights_t fs_rights_inheriting)
|
||||
{
|
||||
return sledge_abi__wasi_snapshot_preview1_fd_fdstat_set_rights(fd, fs_rights_base, fs_rights_inheriting);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
wasi_snapshot_preview1_fd_filestat_get(__wasi_fd_t fd, __wasi_size_t filestat_retoffset)
|
||||
{
|
||||
return sledge_abi__wasi_snapshot_preview1_fd_filestat_get(fd, filestat_retoffset);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
wasi_snapshot_preview1_fd_filestat_set_size(__wasi_fd_t fd, __wasi_filesize_t size)
|
||||
{
|
||||
return sledge_abi__wasi_snapshot_preview1_fd_filestat_set_size(fd, size);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
wasi_snapshot_preview1_fd_filestat_set_times(__wasi_fd_t fd, __wasi_timestamp_t atim, __wasi_timestamp_t mtim,
|
||||
uint32_t fstflags_extended)
|
||||
{
|
||||
return sledge_abi__wasi_snapshot_preview1_fd_filestat_set_times(fd, atim, mtim, fstflags_extended);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
wasi_snapshot_preview1_fd_pread(__wasi_fd_t fd, __wasi_size_t iovs_baseoffset, __wasi_size_t iovs_len,
|
||||
__wasi_filesize_t offset, __wasi_size_t nread_retoffset)
|
||||
{
|
||||
return sledge_abi__wasi_snapshot_preview1_fd_pread(fd, iovs_baseoffset, iovs_len, offset, nread_retoffset);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
wasi_snapshot_preview1_fd_prestat_get(__wasi_fd_t fd, __wasi_size_t prestat_retoffset)
|
||||
{
|
||||
return sledge_abi__wasi_snapshot_preview1_fd_prestat_get(fd, prestat_retoffset);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
wasi_snapshot_preview1_fd_prestat_dir_name(__wasi_fd_t fd, __wasi_size_t dirname_retoffset, __wasi_size_t dirname_len)
|
||||
{
|
||||
return sledge_abi__wasi_snapshot_preview1_fd_prestat_dir_name(fd, dirname_retoffset, dirname_len);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
wasi_snapshot_preview1_fd_pwrite(__wasi_fd_t fd, __wasi_size_t iovs_baseoffset, __wasi_size_t iovs_len,
|
||||
__wasi_filesize_t file_offset, __wasi_size_t nwritten_retoffset)
|
||||
{
|
||||
return sledge_abi__wasi_snapshot_preview1_fd_pwrite(fd, iovs_baseoffset, iovs_len, file_offset,
|
||||
nwritten_retoffset);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
wasi_snapshot_preview1_fd_read(__wasi_fd_t fd, __wasi_size_t iovs_baseoffset, __wasi_size_t iovs_len,
|
||||
__wasi_size_t nread_retoffset)
|
||||
{
|
||||
return sledge_abi__wasi_snapshot_preview1_fd_read(fd, iovs_baseoffset, iovs_len, nread_retoffset);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
wasi_snapshot_preview1_fd_readdir(__wasi_fd_t fd, __wasi_size_t buf_baseoffset, __wasi_size_t buf_len,
|
||||
__wasi_dircookie_t cookie, __wasi_size_t nread_retoffset)
|
||||
{
|
||||
return sledge_abi__wasi_snapshot_preview1_fd_readdir(fd, buf_baseoffset, buf_len, cookie, nread_retoffset);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
wasi_snapshot_preview1_fd_renumber(__wasi_fd_t fd, __wasi_fd_t to)
|
||||
{
|
||||
return sledge_abi__wasi_snapshot_preview1_fd_renumber(fd, to);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
wasi_snapshot_preview1_fd_seek(__wasi_fd_t fd, __wasi_filedelta_t file_offset, uint32_t whence_extended,
|
||||
__wasi_size_t newoffset_retoffset)
|
||||
{
|
||||
return sledge_abi__wasi_snapshot_preview1_fd_seek(fd, file_offset, whence_extended, newoffset_retoffset);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
wasi_snapshot_preview1_fd_sync(__wasi_fd_t fd)
|
||||
{
|
||||
return sledge_abi__wasi_snapshot_preview1_fd_sync(fd);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
wasi_snapshot_preview1_fd_tell(__wasi_fd_t fd, __wasi_size_t fileoffset_retoffset)
|
||||
{
|
||||
return sledge_abi__wasi_snapshot_preview1_fd_tell(fd, fileoffset_retoffset);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
wasi_snapshot_preview1_fd_write(__wasi_fd_t fd, __wasi_size_t iovs_baseoffset, __wasi_size_t iovs_len,
|
||||
__wasi_size_t nwritten_retoffset)
|
||||
{
|
||||
return sledge_abi__wasi_snapshot_preview1_fd_write(fd, iovs_baseoffset, iovs_len, nwritten_retoffset);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
wasi_snapshot_preview1_path_create_directory(__wasi_fd_t fd, __wasi_size_t path_baseoffset, __wasi_size_t path_len)
|
||||
{
|
||||
return sledge_abi__wasi_snapshot_preview1_path_create_directory(fd, path_baseoffset, path_len);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
wasi_snapshot_preview1_path_filestat_get(__wasi_fd_t fd, __wasi_lookupflags_t flags, __wasi_size_t path_baseoffset,
|
||||
__wasi_size_t path_len, __wasi_size_t filestat_retoffset)
|
||||
{
|
||||
return sledge_abi__wasi_snapshot_preview1_path_filestat_get(fd, flags, path_baseoffset, path_len,
|
||||
filestat_retoffset);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
wasi_snapshot_preview1_path_filestat_set_times(__wasi_fd_t fd, __wasi_lookupflags_t flags,
|
||||
__wasi_size_t path_baseoffset, __wasi_size_t path_len,
|
||||
__wasi_timestamp_t atim, __wasi_timestamp_t mtim,
|
||||
uint32_t fstflags_extended)
|
||||
{
|
||||
return sledge_abi__wasi_snapshot_preview1_path_filestat_set_times(fd, flags, path_baseoffset, path_len, atim,
|
||||
mtim, fstflags_extended);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
wasi_snapshot_preview1_path_link(__wasi_fd_t old_fd, __wasi_lookupflags_t old_flags, __wasi_size_t old_path_baseoffset,
|
||||
__wasi_size_t old_path_len, __wasi_fd_t new_fd, __wasi_size_t new_path_baseoffset,
|
||||
__wasi_size_t new_path_len)
|
||||
{
|
||||
return sledge_abi__wasi_snapshot_preview1_path_link(old_fd, old_flags, old_path_baseoffset, old_path_len,
|
||||
new_fd, new_path_baseoffset, new_path_len);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
wasi_snapshot_preview1_path_open(__wasi_fd_t dirfd, __wasi_lookupflags_t lookupflags, __wasi_size_t path_baseoffset,
|
||||
__wasi_size_t path_len, uint32_t oflags_extended, __wasi_rights_t fs_rights_base,
|
||||
__wasi_rights_t fs_rights_inheriting, uint32_t fdflags_extended,
|
||||
__wasi_size_t fd_retoffset)
|
||||
{
|
||||
return sledge_abi__wasi_snapshot_preview1_path_open(dirfd, lookupflags, path_baseoffset, path_len,
|
||||
oflags_extended, fs_rights_base, fs_rights_inheriting,
|
||||
fdflags_extended, fd_retoffset);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
wasi_snapshot_preview1_path_readlink(__wasi_fd_t fd, __wasi_size_t path_baseoffset, __wasi_size_t path_len,
|
||||
__wasi_size_t buf_baseretoffset, __wasi_size_t buf_len,
|
||||
__wasi_size_t nread_retoffset)
|
||||
{
|
||||
return sledge_abi__wasi_snapshot_preview1_path_readlink(fd, path_baseoffset, path_len, buf_baseretoffset,
|
||||
buf_len, nread_retoffset);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
wasi_snapshot_preview1_path_remove_directory(__wasi_fd_t fd, __wasi_size_t path_baseoffset, __wasi_size_t path_len)
|
||||
{
|
||||
return sledge_abi__wasi_snapshot_preview1_path_remove_directory(fd, path_baseoffset, path_len);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
wasi_snapshot_preview1_path_rename(__wasi_fd_t fd, __wasi_size_t old_path_baseoffset, __wasi_size_t old_path_len,
|
||||
__wasi_fd_t new_fd, __wasi_size_t new_path_baseoffset, __wasi_size_t new_path_len)
|
||||
{
|
||||
return sledge_abi__wasi_snapshot_preview1_path_rename(fd, old_path_baseoffset, old_path_len, new_fd,
|
||||
new_path_baseoffset, new_path_len);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
wasi_snapshot_preview1_path_symlink(__wasi_size_t old_path_baseoffset, __wasi_size_t old_path_len, __wasi_fd_t fd,
|
||||
__wasi_size_t new_path_baseoffset, __wasi_size_t new_path_len)
|
||||
{
|
||||
return sledge_abi__wasi_snapshot_preview1_path_symlink(old_path_baseoffset, old_path_len, fd,
|
||||
new_path_baseoffset, new_path_len);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
wasi_snapshot_preview1_path_unlink_file(__wasi_fd_t fd, __wasi_size_t path_baseoffset, __wasi_size_t path_len)
|
||||
{
|
||||
return sledge_abi__wasi_snapshot_preview1_path_unlink_file(fd, path_baseoffset, path_len);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
wasi_snapshot_preview1_poll_oneoff(__wasi_size_t in_baseoffset, __wasi_size_t out_baseoffset,
|
||||
__wasi_size_t nsubscriptions, __wasi_size_t nevents_retoffset)
|
||||
{
|
||||
return sledge_abi__wasi_snapshot_preview1_poll_oneoff(in_baseoffset, out_baseoffset, nsubscriptions,
|
||||
nevents_retoffset);
|
||||
}
|
||||
|
||||
void
|
||||
wasi_snapshot_preview1_proc_exit(__wasi_exitcode_t exitcode)
|
||||
{
|
||||
sledge_abi__wasi_snapshot_preview1_proc_raise(exitcode);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
wasi_snapshot_preview1_proc_raise(uint32_t sig_extended)
|
||||
{
|
||||
return sledge_abi__wasi_snapshot_preview1_proc_raise(sig_extended);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
wasi_snapshot_preview1_random_get(__wasi_size_t buf_baseretoffset, __wasi_size_t buf_len)
|
||||
{
|
||||
return sledge_abi__wasi_snapshot_preview1_random_get(buf_baseretoffset, buf_len);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
wasi_snapshot_preview1_sched_yield(void)
|
||||
{
|
||||
return sledge_abi__wasi_snapshot_preview1_sched_yield();
|
||||
}
|
||||
|
||||
uint32_t
|
||||
wasi_snapshot_preview1_sock_recv(__wasi_fd_t fd, __wasi_size_t ri_data_baseretoffset, __wasi_size_t ri_data_len,
|
||||
uint32_t ri_flags_extended, __wasi_size_t ri_data_nbytes_retoffset,
|
||||
__wasi_size_t message_nbytes_retoffset)
|
||||
{
|
||||
return sledge_abi__wasi_snapshot_preview1_sock_recv(fd, ri_data_baseretoffset, ri_data_len, ri_flags_extended,
|
||||
ri_data_nbytes_retoffset, message_nbytes_retoffset);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
wasi_snapshot_preview1_sock_send(__wasi_fd_t fd, __wasi_size_t si_data_baseoffset, __wasi_size_t si_data_len,
|
||||
uint32_t si_flags_extended, __wasi_size_t nbytes_retoffset)
|
||||
{
|
||||
return sledge_abi__wasi_snapshot_preview1_sock_send(fd, si_data_baseoffset, si_data_len, si_flags_extended,
|
||||
nbytes_retoffset);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
wasi_snapshot_preview1_sock_shutdown(__wasi_fd_t fd, uint32_t how)
|
||||
{
|
||||
return sledge_abi__wasi_snapshot_preview1_sock_shutdown(fd, how);
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "sandbox_types.h"
|
||||
|
||||
extern void stub_init(int32_t offset);
|
||||
|
||||
/**
|
||||
* Takes the arguments from the sandbox struct and writes them into the WebAssembly linear memory
|
||||
*/
|
||||
static inline void
|
||||
sandbox_setup_arguments(struct sandbox *sandbox)
|
||||
{
|
||||
assert(sandbox != NULL);
|
||||
int32_t argument_count = 0;
|
||||
|
||||
/* Copy arguments into linear memory. It seems like malloc would clobber this, but I think this goes away in
|
||||
* WASI, so not worth fixing*/
|
||||
|
||||
sandbox->arguments_offset = wasm_memory_get_size(sandbox->memory);
|
||||
|
||||
/* Assumption: we can fit the arguments in a single wasm page */
|
||||
int rc = wasm_memory_expand(sandbox->memory, WASM_PAGE_SIZE);
|
||||
assert(rc == 0);
|
||||
|
||||
/* We have to update our cache here */
|
||||
memcpy(&sledge_abi__current_wasm_module_instance.abi.memory, &sandbox->memory->abi,
|
||||
sizeof(struct sledge_abi__wasm_memory));
|
||||
|
||||
stub_init(sandbox->arguments_offset);
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,427 @@
|
||||
#ifndef __WASI_SERDES_H__
|
||||
#define __WASI_SERDES_H__
|
||||
|
||||
/*
|
||||
The serialization/deserialization logic in this file is derived from uvwasi source code
|
||||
located at the following URL:
|
||||
https://github.com/nodejs/uvwasi/blob/7523499546c351a1642442e6ec7bd32bcac76e2c/src/wasi_serdes.c
|
||||
|
||||
It retains the the Node.js license as follows:
|
||||
|
||||
MIT License
|
||||
-----------
|
||||
|
||||
Copyright (c) 2019 Colin Ihrig and Contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "wasi.h"
|
||||
|
||||
/* Basic uint{8,16,32,64}_t read/write functions. */
|
||||
|
||||
#define BASIC_TYPE(name, type) \
|
||||
static inline void wasi_serdes_write_##name(void *ptr, size_t offset, type value); \
|
||||
static inline type wasi_serdes_read_##name(const void *ptr, size_t offset);
|
||||
|
||||
#define BASIC_TYPE_WASI(type) BASIC_TYPE(type, __wasi_##type)
|
||||
|
||||
#define WASI_SERDES_SIZE_uint8_t sizeof(uint8_t)
|
||||
BASIC_TYPE(uint8_t, uint8_t)
|
||||
#define WASI_SERDES_SIZE_uint16_t sizeof(uint16_t)
|
||||
BASIC_TYPE(uint16_t, uint16_t)
|
||||
#define WASI_SERDES_SIZE_uint32_t sizeof(uint32_t)
|
||||
BASIC_TYPE(uint32_t, uint32_t)
|
||||
#define WASI_SERDES_SIZE_uint64_t sizeof(uint64_t)
|
||||
BASIC_TYPE(uint64_t, uint64_t)
|
||||
|
||||
#define WASI_SERDES_SIZE_advice_t sizeof(__wasi_advice_t)
|
||||
BASIC_TYPE_WASI(advice_t)
|
||||
#define WASI_SERDES_SIZE_clockid_t sizeof(__wasi_clockid_t)
|
||||
BASIC_TYPE_WASI(clockid_t)
|
||||
#define WASI_SERDES_SIZE_device_t sizeof(__wasi_device_t)
|
||||
BASIC_TYPE_WASI(device_t)
|
||||
#define WASI_SERDES_SIZE_dircookie_t sizeof(__wasi_dircookie_t)
|
||||
BASIC_TYPE_WASI(dircookie_t)
|
||||
#define WASI_SERDES_SIZE_eventrwflags_t sizeof(__wasi_eventrwflags_t)
|
||||
BASIC_TYPE_WASI(eventrwflags_t)
|
||||
#define WASI_SERDES_SIZE_eventtype_t sizeof(__wasi_eventtype_t)
|
||||
BASIC_TYPE_WASI(eventtype_t)
|
||||
#define WASI_SERDES_SIZE_exitcode_t sizeof(__wasi_exitcode_t)
|
||||
BASIC_TYPE_WASI(exitcode_t)
|
||||
#define WASI_SERDES_SIZE_fd_t sizeof(__wasi_fd_t)
|
||||
BASIC_TYPE_WASI(fd_t)
|
||||
#define WASI_SERDES_SIZE_fdflags_t sizeof(__wasi_fdflags_t)
|
||||
BASIC_TYPE_WASI(fdflags_t)
|
||||
#define WASI_SERDES_SIZE_filesize_t sizeof(__wasi_filesize_t)
|
||||
BASIC_TYPE_WASI(filesize_t)
|
||||
#define WASI_SERDES_SIZE_fstflags_t sizeof(__wasi_fstflags_t)
|
||||
BASIC_TYPE_WASI(fstflags_t)
|
||||
#define WASI_SERDES_SIZE_inode_t sizeof(__wasi_inode_t)
|
||||
BASIC_TYPE_WASI(inode_t)
|
||||
#define WASI_SERDES_SIZE_linkcount_t sizeof(__wasi_linkcount_t)
|
||||
BASIC_TYPE_WASI(linkcount_t)
|
||||
#define WASI_SERDES_SIZE_lookupflags_t sizeof(__wasi_lookupflags_t)
|
||||
BASIC_TYPE_WASI(lookupflags_t)
|
||||
#define WASI_SERDES_SIZE_oflags_t sizeof(__wasi_oflags_t)
|
||||
BASIC_TYPE_WASI(oflags_t)
|
||||
#define WASI_SERDES_SIZE_preopentype_t sizeof(__wasi_preopentype_t)
|
||||
BASIC_TYPE_WASI(preopentype_t)
|
||||
#define WASI_SERDES_SIZE_riflags_t sizeof(__wasi_riflags_t)
|
||||
BASIC_TYPE_WASI(riflags_t)
|
||||
#define WASI_SERDES_SIZE_rights_t sizeof(__wasi_rights_t)
|
||||
BASIC_TYPE_WASI(rights_t)
|
||||
#define WASI_SERDES_SIZE_roflags_t sizeof(__wasi_roflags_t)
|
||||
BASIC_TYPE_WASI(roflags_t)
|
||||
#define WASI_SERDES_SIZE_sdflags_t sizeof(__wasi_sdflags_t)
|
||||
BASIC_TYPE_WASI(sdflags_t)
|
||||
#define WASI_SERDES_SIZE_siflags_t sizeof(__wasi_siflags_t)
|
||||
BASIC_TYPE_WASI(siflags_t)
|
||||
#define WASI_SERDES_SIZE_size_t sizeof(__wasi_size_t)
|
||||
BASIC_TYPE_WASI(size_t)
|
||||
#define WASI_SERDES_SIZE_inode_t sizeof(__wasi_inode_t)
|
||||
BASIC_TYPE_WASI(inode_t)
|
||||
#define WASI_SERDES_SIZE_signal_t sizeof(__wasi_signal_t)
|
||||
BASIC_TYPE_WASI(signal_t)
|
||||
#define WASI_SERDES_SIZE_subclockflags_t sizeof(__wasi_subclockflags_t)
|
||||
BASIC_TYPE_WASI(subclockflags_t)
|
||||
#define WASI_SERDES_SIZE_timestamp_t sizeof(__wasi_timestamp_t)
|
||||
BASIC_TYPE_WASI(timestamp_t)
|
||||
#define WASI_SERDES_SIZE_userdata_t sizeof(__wasi_userdata_t)
|
||||
BASIC_TYPE_WASI(userdata_t)
|
||||
#define WASI_SERDES_SIZE_whence_t sizeof(__wasi_whence_t)
|
||||
BASIC_TYPE_WASI(whence_t)
|
||||
|
||||
#undef BASIC_TYPE_WASI
|
||||
#undef BASIC_TYPE
|
||||
|
||||
/* WASI structure read/write functions. */
|
||||
|
||||
#define STRUCT(name) \
|
||||
void wasi_serdes_write_##name(void *ptr, size_t offset, const __wasi_##name *value); \
|
||||
void wasi_serdes_read_##name(const void *ptr, size_t offset, __wasi_##name *value);
|
||||
|
||||
/* iovs currently only need to be read from WASM memory. */
|
||||
#define IOVS_STRUCT(name) \
|
||||
static inline __wasi_errno_t wasi_serdes_read_##name(const void *ptr, size_t end, size_t offset, \
|
||||
__wasi_##name *value);
|
||||
|
||||
#define WASI_SERDES_SIZE_ciovec_t 8
|
||||
IOVS_STRUCT(ciovec_t)
|
||||
|
||||
#define WASI_SERDES_SIZE_iovec_t 8
|
||||
IOVS_STRUCT(iovec_t)
|
||||
|
||||
#define WASI_SERDES_SIZE_dirent_t 24
|
||||
STRUCT(dirent_t)
|
||||
|
||||
#define WASI_SERDES_SIZE_fdstat_t 24
|
||||
STRUCT(fdstat_t)
|
||||
|
||||
#define WASI_SERDES_SIZE_filestat_t 64
|
||||
STRUCT(filestat_t)
|
||||
|
||||
#define WASI_SERDES_SIZE_prestat_t 8
|
||||
STRUCT(prestat_t)
|
||||
|
||||
#define WASI_SERDES_SIZE_event_t 32
|
||||
STRUCT(event_t)
|
||||
|
||||
#define WASI_SERDES_SIZE_subscription_t 48
|
||||
STRUCT(subscription_t)
|
||||
|
||||
#undef STRUCT
|
||||
#undef IOVS_STRUCT
|
||||
|
||||
static inline __wasi_errno_t
|
||||
wasi_serdes_readv_ciovec_t(const void *ptr, size_t end, size_t offset, __wasi_ciovec_t *iovs, __wasi_size_t iovs_len);
|
||||
|
||||
static inline __wasi_errno_t
|
||||
wasi_serdes_readv_iovec_t(const void *ptr, size_t end, size_t offset, __wasi_iovec_t *iovs, __wasi_size_t iovs_len);
|
||||
|
||||
/* Helper functions for memory bounds checking. */
|
||||
static inline int wasi_serdes_check_bounds(size_t offset, size_t end, size_t size);
|
||||
static inline int wasi_serdes_check_array_bounds(size_t offset, size_t end, size_t size, size_t count);
|
||||
|
||||
static inline int
|
||||
wasi_serdes_check_bounds(size_t offset, size_t end, size_t size)
|
||||
{
|
||||
return end > offset && size <= (end - offset);
|
||||
}
|
||||
|
||||
static inline void
|
||||
wasi_serdes_write_uint64_t(void *ptr, size_t offset, uint64_t value)
|
||||
{
|
||||
wasi_serdes_write_uint32_t(ptr, offset, (uint32_t)value);
|
||||
wasi_serdes_write_uint32_t(ptr, offset + 4, value >> 32);
|
||||
}
|
||||
|
||||
static inline void
|
||||
wasi_serdes_write_uint32_t(void *ptr, size_t offset, uint32_t value)
|
||||
{
|
||||
wasi_serdes_write_uint16_t(ptr, offset, (uint16_t)value);
|
||||
wasi_serdes_write_uint16_t(ptr, offset + 2, value >> 16);
|
||||
}
|
||||
|
||||
static inline void
|
||||
wasi_serdes_write_uint16_t(void *ptr, size_t offset, uint16_t value)
|
||||
{
|
||||
wasi_serdes_write_uint8_t(ptr, offset, (uint8_t)value);
|
||||
wasi_serdes_write_uint8_t(ptr, offset + 1, value >> 8);
|
||||
}
|
||||
|
||||
static inline void
|
||||
wasi_serdes_write_uint8_t(void *ptr, size_t offset, uint8_t value)
|
||||
{
|
||||
((uint8_t *)ptr)[offset] = value;
|
||||
}
|
||||
|
||||
static inline uint64_t
|
||||
wasi_serdes_read_uint64_t(const void *ptr, size_t offset)
|
||||
{
|
||||
uint64_t low = wasi_serdes_read_uint32_t(ptr, offset);
|
||||
uint64_t high = wasi_serdes_read_uint32_t(ptr, offset + 4);
|
||||
return low | (high << 32);
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
wasi_serdes_read_uint32_t(const void *ptr, size_t offset)
|
||||
{
|
||||
uint32_t low = wasi_serdes_read_uint16_t(ptr, offset);
|
||||
uint32_t high = wasi_serdes_read_uint16_t(ptr, offset + 2);
|
||||
return low | (high << 16);
|
||||
}
|
||||
|
||||
static inline uint16_t
|
||||
wasi_serdes_read_uint16_t(const void *ptr, size_t offset)
|
||||
{
|
||||
uint16_t low = wasi_serdes_read_uint8_t(ptr, offset);
|
||||
uint16_t high = wasi_serdes_read_uint8_t(ptr, offset + 1);
|
||||
return low | (high << 8);
|
||||
}
|
||||
|
||||
static inline uint8_t
|
||||
wasi_serdes_read_uint8_t(const void *ptr, size_t offset)
|
||||
{
|
||||
return ((const uint8_t *)ptr)[offset];
|
||||
}
|
||||
|
||||
#define TYPE_SWITCH switch (value->type)
|
||||
#define TAG_SWITCH switch (value->u.tag)
|
||||
|
||||
#define ALL_TYPES(STRUCT, FIELD, ALIAS) \
|
||||
\
|
||||
ALIAS(advice_t, uint8_t) \
|
||||
ALIAS(clockid_t, uint32_t) \
|
||||
ALIAS(device_t, uint64_t) \
|
||||
ALIAS(dircookie_t, uint64_t) \
|
||||
ALIAS(errno_t, uint16_t) \
|
||||
ALIAS(eventrwflags_t, uint16_t) \
|
||||
ALIAS(eventtype_t, uint8_t) \
|
||||
ALIAS(exitcode_t, uint32_t) \
|
||||
ALIAS(fd_t, uint32_t) \
|
||||
ALIAS(fdflags_t, uint16_t) \
|
||||
ALIAS(filesize_t, uint64_t) \
|
||||
ALIAS(filetype_t, uint8_t) \
|
||||
ALIAS(fstflags_t, uint16_t) \
|
||||
ALIAS(inode_t, uint64_t) \
|
||||
ALIAS(linkcount_t, uint64_t) \
|
||||
ALIAS(lookupflags_t, uint32_t) \
|
||||
ALIAS(oflags_t, uint16_t) \
|
||||
ALIAS(preopentype_t, uint8_t) \
|
||||
ALIAS(riflags_t, uint16_t) \
|
||||
ALIAS(rights_t, uint64_t) \
|
||||
ALIAS(roflags_t, uint16_t) \
|
||||
ALIAS(sdflags_t, uint8_t) \
|
||||
ALIAS(siflags_t, uint16_t) \
|
||||
ALIAS(signal_t, uint8_t) \
|
||||
ALIAS(size_t, uint32_t) \
|
||||
ALIAS(subclockflags_t, uint16_t) \
|
||||
ALIAS(timestamp_t, uint64_t) \
|
||||
ALIAS(userdata_t, uint64_t) \
|
||||
ALIAS(whence_t, uint8_t) \
|
||||
\
|
||||
STRUCT(dirent_t) \
|
||||
{ \
|
||||
FIELD(0, dircookie_t, d_next); \
|
||||
FIELD(8, inode_t, d_ino); \
|
||||
FIELD(16, uint32_t, d_namlen); \
|
||||
FIELD(20, filetype_t, d_type); \
|
||||
} \
|
||||
\
|
||||
STRUCT(fdstat_t) \
|
||||
{ \
|
||||
FIELD(0, filetype_t, fs_filetype); \
|
||||
FIELD(2, fdflags_t, fs_flags); \
|
||||
FIELD(8, rights_t, fs_rights_base); \
|
||||
FIELD(16, rights_t, fs_rights_inheriting); \
|
||||
} \
|
||||
\
|
||||
STRUCT(filestat_t) \
|
||||
{ \
|
||||
FIELD(0, device_t, dev); \
|
||||
FIELD(8, inode_t, ino); \
|
||||
FIELD(16, filetype_t, filetype); \
|
||||
FIELD(24, linkcount_t, nlink); \
|
||||
FIELD(32, filesize_t, size); \
|
||||
FIELD(40, timestamp_t, atim); \
|
||||
FIELD(48, timestamp_t, mtim); \
|
||||
FIELD(56, timestamp_t, ctim); \
|
||||
} \
|
||||
\
|
||||
STRUCT(prestat_t) \
|
||||
{ \
|
||||
FIELD(0, preopentype_t, tag); \
|
||||
FIELD(4, uint32_t, u.dir.pr_name_len); \
|
||||
} \
|
||||
\
|
||||
STRUCT(event_t) \
|
||||
{ \
|
||||
FIELD(0, userdata_t, userdata); \
|
||||
FIELD(8, errno_t, error); \
|
||||
FIELD(10, eventtype_t, type); \
|
||||
TYPE_SWITCH \
|
||||
{ \
|
||||
case __WASI_EVENTTYPE_FD_READ: \
|
||||
case __WASI_EVENTTYPE_FD_WRITE: \
|
||||
FIELD(16, filesize_t, fd_readwrite.nbytes); \
|
||||
FIELD(24, eventrwflags_t, fd_readwrite.flags); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
STRUCT(subscription_t) \
|
||||
{ \
|
||||
FIELD(0, userdata_t, userdata); \
|
||||
FIELD(8, eventtype_t, u.tag); \
|
||||
TAG_SWITCH \
|
||||
{ \
|
||||
case __WASI_EVENTTYPE_CLOCK: \
|
||||
FIELD(16, clockid_t, u.u.clock.id); \
|
||||
FIELD(24, timestamp_t, u.u.clock.timeout); \
|
||||
FIELD(32, timestamp_t, u.u.clock.precision); \
|
||||
FIELD(40, subclockflags_t, u.u.clock.flags); \
|
||||
break; \
|
||||
case __WASI_EVENTTYPE_FD_READ: \
|
||||
FIELD(16, fd_t, u.u.fd_read.file_descriptor); \
|
||||
break; \
|
||||
case __WASI_EVENTTYPE_FD_WRITE: \
|
||||
FIELD(16, fd_t, u.u.fd_write.file_descriptor); \
|
||||
break; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define WRITE_STRUCT(name) void wasi_serdes_write_##name(void *ptr, size_t offset, const __wasi_##name *value)
|
||||
|
||||
#define READ_STRUCT(name) void wasi_serdes_read_##name(const void *ptr, size_t offset, __wasi_##name *value)
|
||||
|
||||
#define WRITE_FIELD(field_offset, type, field) \
|
||||
do { \
|
||||
wasi_serdes_write_##type(ptr, offset + field_offset, value->field); \
|
||||
} while (0)
|
||||
|
||||
#define READ_FIELD(field_offset, type, field) \
|
||||
do { \
|
||||
value->field = wasi_serdes_read_##type(ptr, offset + field_offset); \
|
||||
} while (0)
|
||||
|
||||
#define WRITE_ALIAS(new_name, old_name) \
|
||||
void wasi_serdes_write_##new_name(void *ptr, size_t offset, __wasi_##new_name value) \
|
||||
{ \
|
||||
wasi_serdes_write_##old_name(ptr, offset, value); \
|
||||
}
|
||||
|
||||
#define READ_ALIAS(new_name, old_name) \
|
||||
__wasi_##new_name wasi_serdes_read_##new_name(const void *ptr, size_t offset) \
|
||||
{ \
|
||||
return wasi_serdes_read_##old_name(ptr, offset); \
|
||||
}
|
||||
|
||||
ALL_TYPES(WRITE_STRUCT, WRITE_FIELD, WRITE_ALIAS)
|
||||
ALL_TYPES(READ_STRUCT, READ_FIELD, READ_ALIAS)
|
||||
|
||||
|
||||
static inline __wasi_errno_t
|
||||
wasi_serdes_read_ciovec_t(const void *ptr, size_t end, size_t offset, __wasi_ciovec_t *value)
|
||||
{
|
||||
uint32_t buf_ptr;
|
||||
|
||||
buf_ptr = wasi_serdes_read_uint32_t(ptr, offset);
|
||||
value->buf_len = wasi_serdes_read_size_t(ptr, offset + 4);
|
||||
|
||||
if (!wasi_serdes_check_bounds(buf_ptr, end, value->buf_len)) return __WASI_ERRNO_OVERFLOW;
|
||||
|
||||
value->buf = ((uint8_t *)ptr + buf_ptr);
|
||||
return __WASI_ERRNO_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static inline __wasi_errno_t
|
||||
wasi_serdes_read_iovec_t(const void *ptr, size_t end, size_t offset, __wasi_iovec_t *value)
|
||||
{
|
||||
uint32_t buf_ptr;
|
||||
|
||||
buf_ptr = wasi_serdes_read_uint32_t(ptr, offset);
|
||||
value->buf_len = wasi_serdes_read_size_t(ptr, offset + 4);
|
||||
|
||||
if (!wasi_serdes_check_bounds(buf_ptr, end, value->buf_len)) return __WASI_ERRNO_OVERFLOW;
|
||||
|
||||
value->buf = ((uint8_t *)ptr + buf_ptr);
|
||||
return __WASI_ERRNO_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static inline __wasi_errno_t
|
||||
wasi_serdes_readv_ciovec_t(const void *ptr, size_t end, size_t offset, __wasi_ciovec_t *iovs, __wasi_size_t iovs_len)
|
||||
{
|
||||
__wasi_errno_t err;
|
||||
__wasi_size_t i;
|
||||
|
||||
for (i = 0; i < iovs_len; i++) {
|
||||
err = wasi_serdes_read_ciovec_t(ptr, end, offset, &iovs[i]);
|
||||
if (err != __WASI_ERRNO_SUCCESS) return err;
|
||||
offset += WASI_SERDES_SIZE_ciovec_t;
|
||||
}
|
||||
|
||||
return __WASI_ERRNO_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static inline __wasi_errno_t
|
||||
wasi_serdes_readv_iovec_t(const void *ptr, size_t end, size_t offset, __wasi_iovec_t *iovs, __wasi_size_t iovs_len)
|
||||
{
|
||||
__wasi_errno_t err;
|
||||
__wasi_size_t i;
|
||||
|
||||
for (i = 0; i < iovs_len; i++) {
|
||||
err = wasi_serdes_read_iovec_t(ptr, end, offset, &iovs[i]);
|
||||
if (err != __WASI_ERRNO_SUCCESS) return err;
|
||||
offset += WASI_SERDES_SIZE_iovec_t;
|
||||
}
|
||||
|
||||
return __WASI_ERRNO_SUCCESS;
|
||||
}
|
||||
|
||||
static inline int
|
||||
wasi_serdes_check_array_bounds(size_t offset, size_t end, size_t size, size_t count)
|
||||
{
|
||||
return end > offset && ((count * size) / size == count) && (count * size <= end - offset);
|
||||
}
|
||||
|
||||
|
||||
#endif /* __WASI_SERDES_H__ */
|
@ -1,158 +0,0 @@
|
||||
#include <assert.h>
|
||||
#include <ck_pr.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "arch/getcycles.h"
|
||||
#include "worker_thread.h"
|
||||
#include "current_sandbox.h"
|
||||
|
||||
extern int32_t inner_syscall_handler(int32_t n, int32_t a, int32_t b, int32_t c, int32_t d, int32_t e, int32_t f);
|
||||
|
||||
int32_t
|
||||
env_syscall_handler(int32_t n, int32_t a, int32_t b, int32_t c, int32_t d, int32_t e, int32_t f)
|
||||
{
|
||||
int32_t i = inner_syscall_handler(n, a, b, c, d, e, f);
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
int32_t
|
||||
env___syscall(int32_t n, int32_t a, int32_t b, int32_t c, int32_t d, int32_t e, int32_t f)
|
||||
{
|
||||
return env_syscall_handler(n, a, b, c, d, e, f);
|
||||
}
|
||||
|
||||
void
|
||||
env___unmapself(uint32_t base, uint32_t size)
|
||||
{
|
||||
/* Just do some no op */
|
||||
}
|
||||
|
||||
int32_t
|
||||
env_a_ctz_64(uint64_t x)
|
||||
{
|
||||
return __builtin_ctzll(x);
|
||||
}
|
||||
|
||||
INLINE void
|
||||
env_a_and_64(int32_t p_off, uint64_t v)
|
||||
{
|
||||
uint64_t *p = current_sandbox_get_ptr_void(p_off, sizeof(uint64_t));
|
||||
ck_pr_and_64(p, v);
|
||||
}
|
||||
|
||||
INLINE void
|
||||
env_a_or_64(int32_t p_off, int64_t v)
|
||||
{
|
||||
assert(sizeof(int64_t) == sizeof(uint64_t));
|
||||
uint64_t *p = current_sandbox_get_ptr_void(p_off, sizeof(int64_t));
|
||||
ck_pr_or_64(p, v);
|
||||
}
|
||||
|
||||
int32_t
|
||||
env_a_cas(int32_t p_off, int32_t t, int32_t s)
|
||||
{
|
||||
assert(sizeof(int32_t) == sizeof(volatile int));
|
||||
int *p = current_sandbox_get_ptr_void(p_off, sizeof(int32_t));
|
||||
|
||||
return ck_pr_cas_int(p, t, s);
|
||||
}
|
||||
|
||||
void
|
||||
env_a_or(int32_t p_off, int32_t v)
|
||||
{
|
||||
assert(sizeof(int32_t) == sizeof(volatile int));
|
||||
int *p = current_sandbox_get_ptr_void(p_off, sizeof(int32_t));
|
||||
ck_pr_or_int(p, v);
|
||||
}
|
||||
|
||||
int32_t
|
||||
env_a_swap(int32_t x_off, int32_t v)
|
||||
{
|
||||
assert(sizeof(int32_t) == sizeof(volatile int));
|
||||
int *x = current_sandbox_get_ptr_void(x_off, sizeof(int32_t));
|
||||
|
||||
int p;
|
||||
do {
|
||||
p = ck_pr_load_int(x);
|
||||
} while (!ck_pr_cas_int(x, p, v));
|
||||
v = p;
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
int32_t
|
||||
env_a_fetch_add(int32_t x_off, int32_t v)
|
||||
{
|
||||
assert(sizeof(int32_t) == sizeof(volatile int));
|
||||
int *x = current_sandbox_get_ptr_void(x_off, sizeof(int32_t));
|
||||
return ck_pr_faa_int(x, v);
|
||||
}
|
||||
|
||||
void
|
||||
env_a_inc(int32_t x_off)
|
||||
{
|
||||
assert(sizeof(int32_t) == sizeof(volatile int));
|
||||
int *x = current_sandbox_get_ptr_void(x_off, sizeof(int32_t));
|
||||
ck_pr_inc_int(x);
|
||||
}
|
||||
|
||||
void
|
||||
env_a_dec(int32_t x_off)
|
||||
{
|
||||
assert(sizeof(int32_t) == sizeof(volatile int));
|
||||
int *x = (int *)current_sandbox_get_ptr_void(x_off, sizeof(int32_t));
|
||||
ck_pr_dec_int(x);
|
||||
}
|
||||
|
||||
void
|
||||
env_a_store(int32_t p_off, int32_t x)
|
||||
{
|
||||
assert(sizeof(int32_t) == sizeof(volatile int));
|
||||
int *p = (int *)current_sandbox_get_ptr_void(p_off, sizeof(int32_t));
|
||||
ck_pr_store_int(p, x);
|
||||
}
|
||||
|
||||
int
|
||||
env_a_ctz_32(int32_t x)
|
||||
{
|
||||
return __builtin_ctz(x);
|
||||
}
|
||||
|
||||
void
|
||||
env_do_spin(int32_t i)
|
||||
{
|
||||
ck_pr_stall();
|
||||
}
|
||||
|
||||
void
|
||||
env_do_crash(int32_t i)
|
||||
{
|
||||
printf("crashing: %d\n", i);
|
||||
assert(0);
|
||||
}
|
||||
|
||||
void
|
||||
env_do_barrier(int32_t x)
|
||||
{
|
||||
ck_pr_barrier();
|
||||
}
|
||||
|
||||
/* Floating point routines */
|
||||
INLINE double
|
||||
env_sin(double d)
|
||||
{
|
||||
return sin(d);
|
||||
}
|
||||
|
||||
INLINE double
|
||||
env_cos(double d)
|
||||
{
|
||||
return cos(d);
|
||||
}
|
||||
|
||||
INLINE unsigned long long
|
||||
env_getcycles(void)
|
||||
{
|
||||
return __getcycles();
|
||||
}
|
@ -1,454 +0,0 @@
|
||||
/*
|
||||
* This code originally came from the aWsm compiler
|
||||
* It has since been updated
|
||||
* https://github.com/gwsystems/aWsm/blob/master/runtime/libc/libc_backing.c
|
||||
*/
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/uio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "current_sandbox.h"
|
||||
#include "scheduler.h"
|
||||
#include "sandbox_functions.h"
|
||||
#include "worker_thread.h"
|
||||
#include "wasm_module_instance.h"
|
||||
|
||||
// What should we tell the child program its UID and GID are?
|
||||
#define UID 0xFF
|
||||
#define GID 0xFE
|
||||
|
||||
// Elf auxilary vector values (see google for what those are)
|
||||
#define AT_PHENT 4
|
||||
#define AT_PAGESZ 6
|
||||
#define AT_BASE 7
|
||||
#define AT_FLAGS 8
|
||||
#define AT_ENTRY 9
|
||||
#define AT_NOTELF 10
|
||||
#define AT_UID 11
|
||||
#define AT_EUID 12
|
||||
#define AT_GID 13
|
||||
#define AT_EGID 14
|
||||
#define AT_CLKTCK 17
|
||||
#define AT_SECURE 23
|
||||
#define AT_BASE_PLATFORM 24
|
||||
#define AT_RANDOM 25
|
||||
|
||||
// offset = a WASM ptr to memory the runtime can use
|
||||
void
|
||||
stub_init(int32_t offset)
|
||||
{
|
||||
struct sandbox *current_sandbox = current_sandbox_get();
|
||||
// What program name will we put in the auxiliary vectors
|
||||
char *program_name = current_sandbox->module->name;
|
||||
// Copy the program name into WASM accessible memory
|
||||
int32_t program_name_offset = offset;
|
||||
strcpy(wasm_memory_get_ptr_void(current_sandbox->memory, offset, sizeof(program_name)), program_name);
|
||||
offset += sizeof(program_name);
|
||||
|
||||
// The construction of this is:
|
||||
// evn1, env2, ..., NULL, auxv_n1, auxv_1, auxv_n2, auxv_2 ..., NULL
|
||||
int32_t env_vec[] = {
|
||||
// Env variables would live here, but we don't supply any
|
||||
0,
|
||||
// We supply only the bare minimum AUX vectors
|
||||
AT_PAGESZ,
|
||||
WASM_PAGE_SIZE,
|
||||
AT_UID,
|
||||
UID,
|
||||
AT_EUID,
|
||||
UID,
|
||||
AT_GID,
|
||||
GID,
|
||||
AT_EGID,
|
||||
GID,
|
||||
AT_SECURE,
|
||||
0,
|
||||
AT_RANDOM,
|
||||
(int32_t)rand(), // It's pretty stupid to use rand here, but w/e
|
||||
0,
|
||||
};
|
||||
int32_t env_vec_offset = offset;
|
||||
memcpy(wasm_memory_get_ptr_void(current_sandbox->memory, env_vec_offset, sizeof(env_vec)), env_vec,
|
||||
sizeof(env_vec));
|
||||
|
||||
module_initialize_libc(current_sandbox_get()->module, env_vec_offset, program_name_offset);
|
||||
}
|
||||
|
||||
// Emulated syscall implementations
|
||||
|
||||
// We define our own syscall numbers, because WASM uses x86_64 values even on systems that are not x86_64
|
||||
#define SYS_READ 0
|
||||
|
||||
/**
|
||||
* @param filedes to read
|
||||
* @param buf_offset offset into wasm linear memory
|
||||
* @param nbyte number of bytes to read
|
||||
* @returns returns bytes read or -errno
|
||||
*/
|
||||
uint32_t
|
||||
wasm_read(int32_t filedes, int32_t buf_offset, int32_t nbyte)
|
||||
{
|
||||
struct sandbox *current_sandbox = current_sandbox_get();
|
||||
|
||||
/* Non-blocking copy on stdin */
|
||||
if (filedes == 0) {
|
||||
char * buffer = current_sandbox_get_ptr_void(buf_offset, nbyte);
|
||||
struct http_request *current_request = ¤t_sandbox->http_request;
|
||||
if (current_request->body_length <= 0) return 0;
|
||||
int bytes_to_read = nbyte > current_request->body_length ? current_request->body_length : nbyte;
|
||||
memcpy(buffer, current_request->body + current_request->body_read_length, bytes_to_read);
|
||||
current_request->body_read_length += bytes_to_read;
|
||||
current_request->body_length -= bytes_to_read;
|
||||
return bytes_to_read;
|
||||
}
|
||||
|
||||
char *buf = current_sandbox_get_ptr_void(buf_offset, nbyte);
|
||||
|
||||
int32_t res = 0;
|
||||
while (res < nbyte) {
|
||||
/* Read from the Socket */
|
||||
int32_t length_read = (int32_t)read(filedes, buf, nbyte);
|
||||
if (length_read < 0) {
|
||||
if (errno == EAGAIN)
|
||||
current_sandbox_sleep();
|
||||
else {
|
||||
/* All other errors */
|
||||
debuglog("Error reading socket %d - %s\n", filedes, strerror(errno));
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
res += length_read;
|
||||
}
|
||||
|
||||
done:
|
||||
return res;
|
||||
err:
|
||||
res = -errno;
|
||||
goto done;
|
||||
}
|
||||
|
||||
#define SYS_WRITE 1
|
||||
int32_t
|
||||
wasm_write(int32_t fd, int32_t buf_offset, int32_t buf_size)
|
||||
{
|
||||
struct sandbox *s = current_sandbox_get();
|
||||
char * buffer = current_sandbox_get_ptr_void(buf_offset, buf_size);
|
||||
struct vec_u8 * response = &s->response;
|
||||
|
||||
if (fd == STDERR_FILENO) { write(STDERR_FILENO, buffer, buf_size); }
|
||||
|
||||
if (fd == STDOUT_FILENO) {
|
||||
int buffer_remaining = response->capacity - response->length;
|
||||
int to_write = buffer_remaining > buf_size ? buf_size : buffer_remaining;
|
||||
|
||||
if (to_write == 0) return 0;
|
||||
memcpy(&response->buffer[response->length], buffer, to_write);
|
||||
response->length += to_write;
|
||||
|
||||
return to_write;
|
||||
}
|
||||
|
||||
int res = ENOTSUP;
|
||||
|
||||
done:
|
||||
return res;
|
||||
err:
|
||||
res = -errno;
|
||||
goto done;
|
||||
}
|
||||
|
||||
#define WO_RDONLY 00
|
||||
#define WO_WRONLY 01
|
||||
#define WO_RDWR 02
|
||||
#define WO_CREAT 0100
|
||||
#define WO_EXCL 0200
|
||||
#define WO_APPEND 02000
|
||||
#define WO_RSYNC 04010000
|
||||
#define WO_DIRECTORY 0200000
|
||||
#define WO_NOFOLLOW 0400000
|
||||
#define WO_CLOEXEC 02000000
|
||||
|
||||
|
||||
#define SYS_OPEN 2
|
||||
int32_t
|
||||
wasm_open(int32_t path_off, int32_t flags, int32_t mode)
|
||||
{
|
||||
char *path = current_sandbox_get_string(path_off, MODULE_MAX_PATH_LENGTH);
|
||||
|
||||
int res = ENOTSUP;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
#define SYS_CLOSE 3
|
||||
int32_t
|
||||
wasm_close(int32_t fd)
|
||||
{
|
||||
// Silently disregard client requests to close STDIN, STDOUT, or STDERR
|
||||
if (fd <= STDERR_FILENO) return 0;
|
||||
|
||||
int res = ENOTSUP;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
#define SYS_LSEEK 8
|
||||
int32_t
|
||||
wasm_lseek(int32_t filedes, int32_t file_offset, int32_t whence)
|
||||
{
|
||||
int32_t res = (int32_t)lseek(filedes, file_offset, whence);
|
||||
|
||||
if (res == -1) return -errno;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
#define SYS_MMAP 9
|
||||
uint32_t
|
||||
wasm_mmap(int32_t addr, int32_t len, int32_t prot, int32_t flags, int32_t fd, int32_t offset)
|
||||
{
|
||||
if (addr != 0) {
|
||||
printf("parameter void *addr is not supported!\n");
|
||||
assert(0);
|
||||
}
|
||||
|
||||
if (fd != -1) {
|
||||
printf("file mapping is not supported!\n");
|
||||
assert(0);
|
||||
}
|
||||
|
||||
assert(len % WASM_PAGE_SIZE == 0);
|
||||
|
||||
int32_t result = wasm_memory_get_size(
|
||||
(struct wasm_memory *)&sledge_abi__current_wasm_module_instance.abi.memory);
|
||||
if (wasm_memory_expand((struct wasm_memory *)&sledge_abi__current_wasm_module_instance.abi.memory, len) == -1) {
|
||||
result = (uint32_t)-1;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#define SYS_MUNMAP 11
|
||||
|
||||
#define SYS_BRK 12
|
||||
|
||||
#define SYS_RT_SIGACTION 13
|
||||
|
||||
#define SYS_RT_SIGPROGMASK 14
|
||||
|
||||
#define SYS_IOCTL 16
|
||||
int32_t
|
||||
wasm_ioctl(int32_t fd, int32_t request, int32_t data_offet)
|
||||
{
|
||||
// musl libc does some ioctls to stdout, so just allow these to silently go through
|
||||
// FIXME: The above is idiotic
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define SYS_READV 19
|
||||
struct wasm_iovec {
|
||||
int32_t base_offset;
|
||||
int32_t len;
|
||||
};
|
||||
|
||||
int32_t
|
||||
wasm_readv(int32_t fd, int32_t iov_offset, int32_t iovcnt)
|
||||
{
|
||||
int32_t read = 0;
|
||||
struct wasm_iovec *iov = current_sandbox_get_ptr_void(iov_offset, iovcnt * sizeof(struct wasm_iovec));
|
||||
for (int i = 0; i < iovcnt; i++) { read += wasm_read(fd, iov[i].base_offset, iov[i].len); }
|
||||
|
||||
return read;
|
||||
}
|
||||
|
||||
#define SYS_WRITEV 20
|
||||
int32_t
|
||||
wasm_writev(int32_t fd, int32_t iov_offset, int32_t iovcnt)
|
||||
{
|
||||
struct sandbox *s = current_sandbox_get();
|
||||
if (fd == STDOUT_FILENO || fd == STDERR_FILENO) {
|
||||
// both 1 and 2 go to client.
|
||||
int len = 0;
|
||||
struct wasm_iovec *iov = current_sandbox_get_ptr_void(iov_offset, iovcnt * sizeof(struct wasm_iovec));
|
||||
for (int i = 0; i < iovcnt; i++) { len += wasm_write(fd, iov[i].base_offset, iov[i].len); }
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
// TODO: Implement below
|
||||
assert(0);
|
||||
|
||||
|
||||
struct wasm_iovec *iov = current_sandbox_get_ptr_void(iov_offset, iovcnt * sizeof(struct wasm_iovec));
|
||||
|
||||
// If we aren't on MUSL, pass writev to printf if possible
|
||||
#if defined(__GLIBC__)
|
||||
if (fd == 1) {
|
||||
int sum = 0;
|
||||
for (int i = 0; i < iovcnt; i++) {
|
||||
int32_t len = iov[i].len;
|
||||
void * ptr = current_sandbox_get_ptr_void(iov[i].base_offset, len);
|
||||
|
||||
printf("%.*s", len, (char *)ptr);
|
||||
sum += len;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
#endif
|
||||
|
||||
struct iovec vecs[iovcnt];
|
||||
for (int i = 0; i < iovcnt; i++) {
|
||||
int32_t len = iov[i].len;
|
||||
void * ptr = current_sandbox_get_ptr_void(iov[i].base_offset, len);
|
||||
vecs[i] = (struct iovec){ ptr, len };
|
||||
}
|
||||
|
||||
int32_t res = (int32_t)writev(fd, vecs, iovcnt);
|
||||
if (res == -1) return -errno;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
#define SYS_MREMAP 25
|
||||
int32_t
|
||||
wasm_mremap(int32_t offset, int32_t old_size, int32_t new_size, int32_t flags)
|
||||
{
|
||||
assert(offset >= 0);
|
||||
assert(offset + old_size <= INT32_MAX);
|
||||
|
||||
// We do not implement compaction yet, so just return immediately if shrinking
|
||||
if (new_size <= old_size) return offset;
|
||||
|
||||
// If at end of linear memory, just expand and return same address
|
||||
if (offset + old_size == sledge_abi__current_wasm_module_instance.abi.memory.size) {
|
||||
int32_t amount_to_expand = new_size - old_size;
|
||||
wasm_memory_expand((struct wasm_memory *)&sledge_abi__current_wasm_module_instance.abi.memory,
|
||||
amount_to_expand);
|
||||
return offset;
|
||||
}
|
||||
|
||||
// Otherwise allocate at end of address space and copy
|
||||
int32_t new_offset = sledge_abi__current_wasm_module_instance.abi.memory.size;
|
||||
wasm_memory_expand((struct wasm_memory *)&sledge_abi__current_wasm_module_instance.abi.memory, new_size);
|
||||
|
||||
// Get pointer of old offset and pointer of new offset
|
||||
uint8_t *linear_mem = sledge_abi__current_wasm_module_instance.abi.memory.buffer;
|
||||
uint8_t *src = &linear_mem[offset];
|
||||
uint8_t *dest = &linear_mem[new_offset];
|
||||
|
||||
// Copy Values. We can use memcpy because we don't overlap
|
||||
memcpy((void *)dest, (void *)src, old_size);
|
||||
|
||||
return new_offset;
|
||||
}
|
||||
|
||||
#define SYS_MADVISE 28
|
||||
|
||||
#define SYS_GETPID 39
|
||||
uint32_t
|
||||
wasm_getpid()
|
||||
{
|
||||
return (uint32_t)getpid();
|
||||
}
|
||||
|
||||
|
||||
#define WF_SETFD 2
|
||||
#define WF_GETSIG 11
|
||||
#define WF_SETLK 6
|
||||
#define WF_SETLKW 7
|
||||
#define SYS_SET_THREAD_AREA 205
|
||||
#define SYS_SET_TID_ADDRESS 218
|
||||
#define SYS_GET_TIME 228
|
||||
struct wasm_time_spec {
|
||||
uint64_t sec;
|
||||
uint32_t nanosec;
|
||||
};
|
||||
|
||||
int32_t
|
||||
wasm_get_time(int32_t clock_id, int32_t timespec_off)
|
||||
{
|
||||
clockid_t real_clock;
|
||||
switch (clock_id) {
|
||||
case 0:
|
||||
real_clock = CLOCK_REALTIME;
|
||||
break;
|
||||
case 1:
|
||||
real_clock = CLOCK_MONOTONIC;
|
||||
break;
|
||||
case 2:
|
||||
real_clock = CLOCK_PROCESS_CPUTIME_ID;
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
|
||||
struct wasm_time_spec *timespec = current_sandbox_get_ptr_void(timespec_off, sizeof(struct wasm_time_spec));
|
||||
|
||||
struct timespec native_timespec = { 0, 0 };
|
||||
int res = clock_gettime(real_clock, &native_timespec);
|
||||
if (res == -1) return -errno;
|
||||
|
||||
timespec->sec = native_timespec.tv_sec;
|
||||
timespec->nanosec = native_timespec.tv_nsec;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
#define SYS_EXIT 60
|
||||
#define SYS_EXIT_GROUP 231
|
||||
int32_t
|
||||
wasm_exit_group(int32_t status)
|
||||
{
|
||||
debuglog("Called wasm_exit_group");
|
||||
// I believe that if a sandbox called this, it would cause the runtime to exit
|
||||
// exit(status);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t
|
||||
inner_syscall_handler(int32_t n, int32_t a, int32_t b, int32_t c, int32_t d, int32_t e, int32_t f)
|
||||
{
|
||||
switch (n) {
|
||||
case SYS_READ:
|
||||
return wasm_read(a, b, c);
|
||||
case SYS_WRITE:
|
||||
return wasm_write(a, b, c);
|
||||
case SYS_WRITEV:
|
||||
return wasm_writev(a, b, c);
|
||||
case SYS_CLOSE:
|
||||
return wasm_close(a);
|
||||
case SYS_LSEEK:
|
||||
return wasm_lseek(a, b, c);
|
||||
case SYS_EXIT:
|
||||
case SYS_EXIT_GROUP:
|
||||
return wasm_exit_group(a);
|
||||
case SYS_MMAP:
|
||||
return wasm_mmap(a, b, c, d, e, f);
|
||||
case SYS_GET_TIME:
|
||||
return wasm_get_time(a, b);
|
||||
case SYS_READV:
|
||||
return wasm_readv(a, b, c);
|
||||
case SYS_MUNMAP:
|
||||
case SYS_IOCTL:
|
||||
case SYS_SET_THREAD_AREA:
|
||||
case SYS_SET_TID_ADDRESS:
|
||||
case SYS_BRK:
|
||||
case SYS_MREMAP:
|
||||
return wasm_mremap(a, b, c, b);
|
||||
case SYS_MADVISE:
|
||||
/* Note: These are called, but are unimplemented and fail silently */
|
||||
return 0;
|
||||
case SYS_RT_SIGACTION:
|
||||
case SYS_RT_SIGPROGMASK:
|
||||
default:
|
||||
/* This is a general catch all for the other functions below */
|
||||
debuglog("Call to unknown or implemented syscall %d\n", n);
|
||||
debuglog("syscall %d (%d, %d, %d, %d, %d, %d)\n", n, a, b, c, d, e, f);
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Loading…
Reference in new issue