diff --git a/Dockerfile b/Dockerfile index b65ca84..327c2cb 100644 --- a/Dockerfile +++ b/Dockerfile @@ -49,8 +49,9 @@ git pull && ./emsdk install latest && ./emsdk activate latest && . ./emsdk_env.s # takes long times to build wasi-sdk in arm64 because wasi-sdk doesn't release arm64 packages. RUN \ if [ "$( uname -m )" = "x86_64" ]; then \ - cd /root && export WASI_VERSION=21 && export WASI_VERSION_FULL=${WASI_VERSION}.0 && ( echo "export WASI_VERSION=21"; echo "export WASI_VERSION_FULL=${WASI_VERSION}.0"; echo "export WASI_SDK_PATH=/root/wasi-sdk-${WASI_VERSION_FULL}" ) >> /root/.bash_profile && \ - wget https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-${WASI_VERSION}/wasi-sdk-${WASI_VERSION_FULL}-linux.tar.gz && tar xvf wasi-sdk-${WASI_VERSION_FULL}-linux.tar.gz && rm wasi-sdk-${WASI_VERSION_FULL}-linux.tar.gz; \ + cd /root && export WASI_OS=linux && export WASI_ARCH=x86_64 && export WASI_VERSION=24 && export WASI_VERSION_FULL=${WASI_VERSION}.0 && \ + ( echo "export WASI_OS=linux"; echo "export WASI_ARCH=x86_64"; echo "export WASI_VERSION=24"; echo "export WASI_VERSION_FULL=${WASI_VERSION}.0"; echo "export WASI_SDK_PATH=/root/wasi-sdk-${WASI_VERSION_FULL}-${WASI_ARCH}-${WASI_OS}" ) >> /root/.bash_profile && \ + wget https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-${WASI_VERSION}/wasi-sdk-${WASI_VERSION_FULL}-${WASI_ARCH}-${WASI_OS}.tar.gz && tar xvf wasi-sdk-${WASI_VERSION_FULL}-${WASI_ARCH}-${WASI_OS}.tar.gz; \ elif [ "$( uname -m )" = "aarch64" ]; then \ cd /root && echo "export WASI_SDK_PATH=/root/wasi-sdk/build/install/opt/wasi-sdk" >> /root/.bash_profile && git clone --recursive https://github.com/WebAssembly/wasi-sdk.git; \ cd wasi-sdk && NINJA_FLAGS=-v make package; \ diff --git a/README.md b/README.md index ca98487..10a0418 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,7 @@ elfconv converts an original ELF binary to the LLVM bitcode using [remill](https and elfconv uses [emscripten](https://github.com/emscripten-core/emscripten) (for browser) or [wasi-sdk](https://github.com/WebAssembly/wasi-sdk) (for WASI runtimes) to generate the WASM binary from the LLVM bitcode file. ## Status -> [!WARNING] -> "**elfconv is a work in progress**" and the test is insufficient, so you may fail to compile your ELF binary or execute the generated WASM binary. Current limitations are as follows. +"**elfconv is a work in progress**" and the test is insufficient, so you may fail to compile your ELF binary or execute the generated WASM binary. Current limitations are as follows. - Only support of aarch64 ELF binary as an input binary - Furthermore, a part of aarch64 instructions are not supported. If your ELF binary's instruction is not supported, elfconv outputs the message (\[WARNING\] Unsupported instruction at 0x...) - No support for stripped binaries @@ -13,7 +12,6 @@ and elfconv uses [emscripten](https://github.com/emscripten-core/emscripten) (fo - a lot of Linux system calls are unimplemented (ref: [`runtime/syscalls/`](https://github.com/yomaytk/elfconv/blob/main/runtime/syscalls)) ## Quick Start You can try elfconv using the docker container (amd64 and arm64) by executing the commands as follows and can execute the WASM application on the both browser and host environment (WASI runtimes). -> [!WARNING] > The container generated by the Dockerfile includes the installation of [wasi-sdk](https://github.com/WebAssembly/wasi-sdk). However, wasi-sdk doesn't release the package for arm64, so we build wasi-sdk in the arm64 container image, and it takes a long time. If you try elfconv, it might be good to use elfconv [release packages](https://github.com/yomaytk/elfconv/releases), or comment out the lines of the installation of wasi-sdk (The relevant part is as follows in the Dockerfile) and try to execute only in the browser. > ```bash > elif [ "$( uname -m )" = "aarch64" ]; then \ @@ -25,13 +23,13 @@ You can try elfconv using the docker container (amd64 and arm64) by executing th ```bash $ git clone --recursive https://github.com/yomaytk/elfconv $ cd elfconv -elfconv/$ docker build . -t elfconv-image -elfconv/$ docker run -it --rm -p 8080:8080 --name elfconv-container elfconv-image -### ENTRYPOINT: elfconv/scripts/container-entry-point.sh +elfconv/$ docker build . -t +elfconv/$ docker run -it --rm -p 8080:8080 --name ### running build and test ... # You can test elfconv using `bin/elfconv.sh` ~/elfconv# cd bin -~/elfconv/bin# TARGET=browser ./elfconv.sh /path/to/ELF # e.g. ../examples/eratosthenes_sieve/a.out +~/elfconv/bin# TARGET=Browser ./elfconv.sh /path/to/ELF # e.g. ../examples/hello/a.out +# exe.js and exe.wasm should be generated. ~/elfconv/bin# emrun --no_browser --port 8080 exe.wasm.html Web server root directory: /root/elfconv/bin Now listening at http://0.0.0.0:8080/ @@ -41,13 +39,12 @@ Now, the WASM application server has started, so that you can access it (e.g. ht ```bash $ git clone --recursive https://github.com/yomaytk/elfconv $ cd elfconv -$ docker build . -t elfconv-image -$ docker run -it --name elfconv-container elfconv-image -### ENTRYPOINT: elfconv/scripts/container-entry-point.sh +$ docker build . -t +$ docker run -it --name ### running build and test ... # You can test elfconv using `bin/elfconv.sh` ~/elfconv# cd bin -~/elfconv/bin# TARGET=wasi ./elfconv.sh /path/to/ELF # e.g. ../examples/eratosthenes_sieve/a.out +~/elfconv/bin# TARGET=Wasi ./elfconv.sh /path/to/ELF # e.g. ../examples/hello/a.out ~/elfconv/bin# wasmtime exe.wasm # wasmtime is preinstalled ``` ## Source code build @@ -84,12 +81,16 @@ After finishing the build, you can find the directory `elfconv/build/`, and you You can compile the ELF binary to the WASM binary using [`scripts/dev.sh`](https://github.com/yomaytk/elfconv/blob/main/scripts/dev.sh) as follows. `dev.sh` execute the translation (ELF -> LLVM bitcode by *'lifter'*) and compiles the [`runtime/`](https://github.com/yomaytk/elfconv/tree/main/runtime) (statically linked with generated LLVM bitcode) and generate the WASM binary. when you execute the script, you should explicitly specify the path of the elfconv directory (`/root/elfconv` on the container) with `NEW_ROOT` or rewrite the `ROOT_DIR` in `dev.sh`. ```bash +### Native +~/elfconv/build# NEW_ROOT=/path/to/elfconv TARGET=Native ../scripts/dev.sh path/to/ELF # generate the Native binary (Host achitecture) under the elfconv/build/lifter +~/elfconv/build# ./exe.${HOST_CPU} +------------------------ ### Browser -~/elfconv/build# NEW_ROOT=/path/to/elfconv TARGET=browser ../scripts/dev.sh path/to/ELF # generate the WASM binary under the elfconv/build/lifter +~/elfconv/build# NEW_ROOT=/path/to/elfconv TARGET=Browser ../scripts/dev.sh path/to/ELF # generate the WASM binary under the elfconv/build/lifter ~/elfconv/build# emrun --no_browser --port 8080 ./lifter/exe.wasm.html # execute the generated WASM binary with emscripten ------------------------ ### Host (WASI Runtimes) -~/elfconv/build# NEW_ROOT=/path/to/elfconv TARGET=wasi ../scripts/dev.sh path/to/ELF +~/elfconv/build# NEW_ROOT=/path/to/elfconv TARGET=Wasi ../scripts/dev.sh path/to/ELF ~/elfconv/build# wasmedge ./lifter/exe.wasm ``` ## Acknowledgement diff --git a/bin/elfconv.sh b/bin/elfconv.sh index bd876e6..9959d60 100755 --- a/bin/elfconv.sh +++ b/bin/elfconv.sh @@ -8,7 +8,7 @@ setting() { UTILS_DIR=${ROOT_DIR}/utils BUILD_DIR=${ROOT_DIR}/build BUILD_LIFTER_DIR=${BUILD_DIR}/lifter - OPTFLAGS="-O0" + OPTFLAGS="-O3" EMCC=emcc EMCCFLAGS="${OPTFLAGS} -I${ROOT_DIR}/backend/remill/include -I${ROOT_DIR}" WASISDKCC=${WASI_SDK_PATH}/bin/clang++ diff --git a/scripts/dev.sh b/scripts/dev.sh index da52ac7..961a834 100755 --- a/scripts/dev.sh +++ b/scripts/dev.sh @@ -125,7 +125,7 @@ main() { ${RUNTIME_DIR}/syscalls/SyscallWasi.cpp ${RUNTIME_DIR}/VmIntrinsics.cpp ${UTILS_DIR}/Util.cpp ${UTILS_DIR}/elfconv.cpp echo -e "[\033[32mINFO\033[0m] exe.wasm was generated." $WASMEDGE_COMPILE_OPT exe.wasm exe_o3.wasm - echo -e "[\033[32mINFO\033[0m] Universal compile optimization was done. (exe_ao3.wasm)" + echo -e "[\033[32mINFO\033[0m] Universal compile optimization was done. (exe_o3.wasm)" return 0 ;; esac