An ahead-of-time (AOT) binary translator that converts Linux applications to WebAssembly (Wasm) for both browser and WASI runtimes.
- No source code needed — Port pre-built binaries directly to Wasm, even when source code is unavailable
- Linux syscall emulation — Emulates Linux syscalls missing in Wasm environments (e.g.,
fork/execve), enabling unmodified Linux apps to run - Language-agnostic — No per-language compiler support needed; works with any language that compiles to Linux/ELF
Use cases:
- Legacy applications where source code is unavailable or difficult to rebuild
- Porting Linux libraries to Wasm for use in developing web applications
- Porting powerful softwares (e.g., compiler, build systems, etc.) in browsers
fork/execvesupport- elfconv experimentally supports
fork()andexecve()system calls in Wasm in browsers. This enables running more complex Linux applications that rely on multi-process architectures, such as shells, build systems, and server applications that spawn child processes (e.g., GNU Bash + BusyBox on the demo page).
- elfconv experimentally supports
- AOT Compilation
- Existing projects use CPU emulators (e.g., v86, container2wasm) to port Linux applications to Wasm, but incur severe slowdowns of 10× or more. In contrast, elfconv applies AOT compilation to translate machine code directly to LLVM IR, achieving much smaller performance degradation (ref. Performance section).
Warning
elfconv is WORK IN PROGRESS. Testing is insufficient, so you may encounter failures when compiling ELF binaries or executing generated Wasm binaries.
- Architecture Support: Only AArch64 ELF binaries are currently supported
- x86-64 support is under development
- Linking: No support for shared objects (
.sofiles)- Only statically-linked binaries are supported
- System Calls: Partial Linux syscall implementation
- See
runtime/syscalls/for currently supported syscalls - More syscalls are being added continuously
- See
We measured the performance of Wasm generated by elfconv against Wasm compiled directly from source using Emscripten or WASI-SDK. The workflow is:
- Compile source code → AArch64 ELF binary (using gcc/clang)
- Convert ELF binary → Wasm using elfconv
- Compare with: Source code → Wasm directly (using Emscripten/WASI-SDK)
Blog: elfconv: Linux Apps to High-Performance Wasm Binary Translator
| Target Program | from source code | elfconv |
|---|---|---|
eratosthenes_sieve (↓ better) |
0.567 (s) (100%) | 0.692 (s) (82%) |
LINPACK benchmark (↑ better) |
1617 (MFLOPS) (100%) | 1256 (MFLOPS) (78%) |
mnist-neural-network-plain-c (during 30 steps) (↑ better) |
2.138 (s) (100%) | 2.255 (s) (96%) |
| Target Program | from source code | elfconv |
|---|---|---|
eratosthenes_sieve (↓ better) |
0.362 (s) (100%) | 0.608 (s) (60%) |
LINPACK benchmark (↑ better) |
4821 (MFLOPS) (100%) | 2720 (MFLOPS) (56%) |
mnist-neural-network-plain-c (during 30 steps) (↑ better) |
2.271 (s) (100%) | 2.302 (s) (96%) |
Key Takeaway: elfconv achieves 56-96% of native source-to-Wasm performance, significantly better than CPU emulation approaches which typically have 10x or more slowdown.
The easiest way to try elfconv is using Linux container, which supports both x86-64 and ARM64 hosts.
You can either pull a pre-built image from ghcr.io or build from source using the Dockerfile.
Pull pre-built image (recommended):
# For ARM64 hosts
$ docker pull ghcr.io/yomaytk/elfconv:arm64
# For x86-64 hosts
$ docker pull ghcr.io/yomaytk/elfconv:amd64Build from Dockerfile:
$ git clone --recursive https://github.com/yomaytk/elfconv
$ cd elfconv
# For AArch64 ELF target
$ docker build . --build-arg ECV_AARCH64=1
# For x86-64 ELF target
$ docker build . --build-arg ECV_X86=1Choose your execution environment:
- Option 1 - Browser: Run Wasm in a web browser with terminal emulation
- Option 2 - WASI Runtime: Run Wasm on the host using WasmEdge or other WASI-compatible runtimes
# 1. Run container with port forwarding
$ docker run -it -p 8080:8080 <image-name>
# 2. Convert ELF to Wasm
~/elfconv# cd bin
~/elfconv/bin# TARGET=aarch64-wasm INITWASM=1 ./exe.sh /path/to/ELF
# Example: TARGET=aarch64-wasm INITWASM=1 ./exe.sh ../examples/hello/c/a.aarch64
# 3. Start web server
~/elfconv/bin# emrun --no_browser --port 8080 <ELFNAME>.htmlAccess the Wasm application from your browser at http://localhost:8080/<ELFNAME>.html
# 1. Run container
$ docker run -it <image-name>
# 2. Convert ELF to Wasm
~/elfconv# cd bin
~/elfconv/bin# TARGET=aarch64-wasi32 ./exe.sh /path/to/ELF
# Example: TARGET=aarch64-wasi32 ./exe.sh ../examples/hello/c/a.aarch64
# 3. Execute with WasmEdge (preinstalled)
~/elfconv/bin# wasmedge <ELFNAME>.wasmWe welcome contributions! we'd love your help making it better.
For example, the following contributions are expected:
- 🔧 Instruction Support — Implement missing AArch64 instructions or advance x86-64 instruction support.
- ⚙️ System Call Implementation — Add Linux syscall support in
runtime/syscalls/ - 🧪 Testing — Test with various Linux applications and report issues
- 📚 Documentation — Improve documentation, add examples
For questions or discussions, feel free to open an issue or start a discussion.
elfconv uses or references some projects as follows. Great thanks to all its developers!
- Remill (Apache Lisence 2.0)
- Original Source: https://github.com/lifting-bits/remill
- elfconv uses Remill to convert machine codes to LLVM IR instructions. The source code is contained in
./backend/remilland is modified for using from front-end and supporting additional instructions.
- 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, ...)
- elfconv has started as the successor project of MyAOT.