elfconv is an experimental AOT compiler that translates a Linux ELF binary to executable WebAssembly. elfconv converts an original ELF binary to the LLVM bitcode using remill (library for lifting machine code to LLVM bitcode) and elfconv uses emscripten (for browser) or wasi-sdk (for WASI runtimes) to generate the WASM binary from the LLVM bitcode file.
"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
- No support for shared objects
- a lot of Linux system calls are unimplemented (ref:
runtime/syscalls/
)
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).
The container generated by the Dockerfile includes the installation of 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, 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.
elif [ "$( uname -m )" = "aarch64" ]; then \ cd /root && git clone --recursive https://github.com/WebAssembly/wasi-sdk.git; \ cd wasi-sdk && NINJA_FLAGS=-v make package; \ fi
$ git clone --recursive https://github.com/yomaytk/elfconv
$ cd elfconv
elfconv/$ docker build . -t <image-name>
elfconv/$ docker run -it --rm -p 8080:8080 --name <container-name> <image-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/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/
Now, the WASM application server has started, so that you can access it (e.g. http://localhost:8080/exe.wasm.html) from outside the container.
$ git clone --recursive https://github.com/yomaytk/elfconv
$ cd elfconv
$ docker build . -t <image-name>
$ docker run -it --name <container-name> <image-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/hello/a.out
~/elfconv/bin# wasmtime exe.wasm # wasmtime is preinstalled
elfconv provides the Dev Container environment using the root Dockerfile
and .devcontainer.json
, so you can develop without making the build environment if you can use Dev Container on your vscode (Please refer to the official website of vscode for basically using Dev Container).
The libraries required for the build are almost the same as those for remill, and the main libraries are as follows. The other required libraries are automatically installed using cxx-common.
Name | Version |
---|---|
Git | Latest |
CMake | 3.14+ |
Google Flags | Latest |
Google Log | Latest |
Google Test | Latest |
LLVM | 16 |
Clang | 16+ |
Intel XED | Latest |
Unzip | Latest |
ccache | Latest |
If you prepare these libraries, you can easily build elfconv by executing scripts/build.sh
as follows.
$ git clone --recursive https://github.com/yomaytk/elfconv
$ cd elfconv
/elfconv$ ./scripts/build.sh
Note
If you fail to build elfconv, please feel free to submit an issue!
After finishing the build, you can find the directory elfconv/build/
, and you can build the 'lifter' ('lifter' is the module that converts the ELF binary to LLVM bitcode and those source codes are mainly located in the backend/remill/
and lifter/
) by ninja after modifying the 'lifter' codes.
You can compile the ELF binary to the WASM binary using scripts/dev.sh
as follows. dev.sh
execute the translation (ELF -> LLVM bitcode by 'lifter') and compiles the 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
.
### 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# 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# wasmedge ./lifter/exe.wasm
elfconv uses or references some projects as follows. Great thanks to its all developers!
- remill (Apache Lisence 2.0)
- Original Source: https://github.com/lifting-bits/remill
- elfconv uses remill in order to convert machine codes to LLVM IR instructions. the source code is contained in
./backend/remill
and is modified for using from front-end and supporting additional instructions.
- Sleigh Library (Apache Lisence 2.0)
- Original Source: https://github.com/lifting-bits/sleigh
- sleigh is a language to describe the semantics of instructions, and this library is part of the Ghidra reverse engineering platform and underpins its disassemler and decompilation engines.
- MyAOT (Apache Lisence 2.0)
- Original Source: https://github.com/AkihiroSuda/myaot
- An experimental AOT-ish compiler (Linux/riscv32 ELF → Linux/x86_64 ELF, Mach-O, WASM, ...)
- We referenced the design of MyAOT for developing elfconv.