From 5265b6dfbb255bbf540c7df943fe13e27ddabd36 Mon Sep 17 00:00:00 2001 From: poemm <36397285+poemm@users.noreply.github.com> Date: Thu, 6 Dec 2018 17:15:54 -0600 Subject: [PATCH 01/20] add C/C++ wasmception guide with example --- README.md | 1 + c_cpp_guide.md | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+) create mode 100644 c_cpp_guide.md diff --git a/README.md b/README.md index 8f31a7f..31de080 100644 --- a/README.md +++ b/README.md @@ -90,6 +90,7 @@ One of the [design goals](https://github.com/ewasm/design/blob/master/rationale. At present, we've developed support for the following languages and toolchains: - [C/C++ (LLVM) WebAssembly tutorial](./clang.md) +- [C/C++](./c_cpp_guide.md) - Rust: documentation pending - [AssemblyScript](https://github.com/AssemblyScript/assemblyscript), a subset of TypeScript, which uses the JavaScript toolchain: see the [etherts org](https://github.com/etherts/docs) for more information on writing contracts in AssemblyScript. diff --git a/c_cpp_guide.md b/c_cpp_guide.md new file mode 100644 index 0000000..1a34627 --- /dev/null +++ b/c_cpp_guide.md @@ -0,0 +1,69 @@ +# Compiling C/C++ to Ewasm + +First an introduction to discuss quirks, then a step-by-step guide for how to compile Ewasm contracts from C and C++. Warning: the Ewasm spec and tools below are subject to change. + +## Introduction + +An Ewasm contract is a WebAssembly module with the following restrictions. The module's imports must be among the [Ewasm helper functions](https://github.com/ewasm/design/blob/master/eth_interface.md) which resemble EVM opcodes to interact with the client. The module's exports must be a `main` function which takes no arguments and returns nothing, and the `memory` of the module. The module can't using floats and other sources of non-determinism. + +Below are four quirks of using C/C++ to write Ewasm smart contracts. These quirks may improve as tools and Ewasm improve. + +Quirk 1) WebAssembly is still primitive and lacks features. For example WebAssembly supports function pointers, but lacks support for exceptions. We have no way to do systeam calls. We compile against patched versions of libc and libc++ to allow us to use `malloc`, but the patches are not enough for `std::vector` which uses more than just `malloc` to manage memory. Anyway, smart contracts may not want to manage and `free` memory since this costs gas. This situation will improve as WebAssembly, compilers, and libraries mature. + +Quirk 2) In the current Ewasm design, all communication between the contract and the client is done through the module's memory. For example, the message data ("call data") to the contract is accessed by calling `callDataCopy` to put this data to a memory location. Accessing a contract's storage requires calls to `storageStore` or `storageLoad`, which require memory offsets of the storage key and value. We will allocate memory in C/C++ using `malloc`. For example, before calling `callDataCopy`, one may use `getCallDataSize` to see how many bytes of memory to `malloc`. + +Quirk 3) In the current Ewasm design, the Ethereum client writes data into WebAssembly as big-endian, and WebAssembly memory is little-endian, so all data has reversed bytes when they are in the WebAssembly operand stack. For example, when the call data is brought into memory using `callDataCopy`, and those bytes are loaded to the WebAssembly stack using `i64.load`, all of the bytes are reversed. So a function may be needed in C/C++ to reverse the bytes. + +Quirk 4) The output of compilers is a `.wasm` binary which may have some extra imports and exports with strange names. These must be manually fixed to be a valid Ewasm contract. + + +## Step-by-Step Guide + +The wasmception package offers patches to libc and libc++ which allow using `malloc` when targeting WebAssembly. This tool is not specific to Ewasm, it is maintained by a third party. Warning: compiling wasmception will download llvm, llvm tools, musl C library, and libc++, which will require internet bandwidth, lots of RAM, and time. + +```sh +git clone https://github.com/yurydelendik/wasmception.git +cd wasmception +make -j4 # Warning: this required lots of internet bandwidth, RAM, and one hour on a mid-level laptop. +cd .. +``` + +Write down the end of the output of the above `make` command, it should include something like: `--sysroot=/home/user/repos/wasmception/sysroot`. + +We modified the wasmception example into an Ewasm contract, which we will now download. Make sure to edit the `Makefile` with the sysroot data above, and change the path to clang to our newly compiled version which may look something like `/home/user/repos/wasmception/dist/bin/clang`. Make sure that `main.syms` has a list of Ewasm helper functions you are using. If you are using C++, make sure to modify the Makefile to clang++, use `extern "C"` around the helper function declarations, and follow other tips from wasmception. + +```sh +git clone https://gist.github.com/poemm/91b64ecd2ca2f1cb4a88d31315313b9b.git cwrc20 +cd cwrc20 +# edit the Makefile and main.syms as described above +make +``` + +The output is `main.wasm`, but it needs some cleanup to remove some of it's extra import and export junk. For this, we use PyWebAssembly. + +Aside: Alternatively, one can manually clean this junk. Alternatively, one can use a [rust version of wasm-chisel](https://github.com/wasmx/wasm-chisel) which can be installed with `cargo install chisel`. The Rust version has more features, the Python version is just enough for our use. In either case, before deploying, contracts should be visually inspected to make sure that imports and exports meet Ewasm requirements. + +``` +cd .. +git clone https://github.com/poemm/pywebassembly.git +cd pywebassembly/examples/ +python3 ewasm_chisel.py ../../cwrc20/main.wasm +cd ../../cwrc20 +``` + +The output `main_chiseled.wasm` is an Ewasm contract. To deploy it from http://ewasm.ethereum.org/studio/, we need to convert it form the `.wasm` binary format to the `.wat` (or `.wast`) text format. This conversion can be done with binaryen's `wasm-dis`. + +Aside: Alternatively one can download the precompiled release of Binaryen, or try using Wabt's `wasm2wat` instead. But Binaryen's `wasm-dis` is recommended because Ewasm studio uses Binaryen internally, and Binaryen can be quirky and fail to read the `.wat` generated somewhere else. Also, if Binaryen's `wasm-dis` can't read the `.wasm`, try using Wabt's `wasm2wat` then `wat2wasm` before trying again with Binaryen. + +```sh +cd .. +git clone https://github.com/WebAssembly/binaryen.git # warning 90 MB, can also download precompiled binaries which are 15 MB +cd binaryen +mkdir build && cd build +cmake .. +make -j4 +cd ../../cwrc20 +../binaryen/build/bin/wasm-dis main_chiseled.wasm > main_chiseled.wat +``` + +Now `main_chiseled.wat` can be pasted into http://ewasm.ethereum.org/studio/ and deployed. Happy hacking! From 1f647066da78dd190514b06ad67c81649d486b6f Mon Sep 17 00:00:00 2001 From: poemm <36397285+poemm@users.noreply.github.com> Date: Thu, 6 Dec 2018 19:49:48 -0600 Subject: [PATCH 02/20] C/C++ guide fixes --- c_cpp_guide.md | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/c_cpp_guide.md b/c_cpp_guide.md index 1a34627..3754d17 100644 --- a/c_cpp_guide.md +++ b/c_cpp_guide.md @@ -1,25 +1,25 @@ # Compiling C/C++ to Ewasm -First an introduction to discuss quirks, then a step-by-step guide for how to compile Ewasm contracts from C and C++. Warning: the Ewasm spec and tools below are subject to change. +First an introduction, then a step-by-step guide. Warning: the Ewasm spec and tools below are subject to change. ## Introduction -An Ewasm contract is a WebAssembly module with the following restrictions. The module's imports must be among the [Ewasm helper functions](https://github.com/ewasm/design/blob/master/eth_interface.md) which resemble EVM opcodes to interact with the client. The module's exports must be a `main` function which takes no arguments and returns nothing, and the `memory` of the module. The module can't using floats and other sources of non-determinism. +An Ewasm contract is a WebAssembly module with the following restrictions. The module's imports must be among the [Ewasm helper functions](https://github.com/ewasm/design/blob/master/eth_interface.md) which resemble EVM opcodes to interact with the client. The module's exports must be a `main` function which takes no arguments and returns nothing, and the `memory` of the module. The module can't using floats or other sources of non-determinism. -Below are four quirks of using C/C++ to write Ewasm smart contracts. These quirks may improve as tools and Ewasm improve. +Below are four quirks of using C/C++ to write Ewasm contracts. These quirks may improve as tools and Ewasm improve. -Quirk 1) WebAssembly is still primitive and lacks features. For example WebAssembly supports function pointers, but lacks support for exceptions. We have no way to do systeam calls. We compile against patched versions of libc and libc++ to allow us to use `malloc`, but the patches are not enough for `std::vector` which uses more than just `malloc` to manage memory. Anyway, smart contracts may not want to manage and `free` memory since this costs gas. This situation will improve as WebAssembly, compilers, and libraries mature. +Quirk 1) WebAssembly is still primitive and lacks features. For example WebAssembly lacks support for exceptions and we have no way to do systeam calls in Ewasm. We compile against patched versions of libc and libc++ to allow us to use `malloc`, but the patches are not enough for `std::vector` which uses more than just `malloc` to manage memory. But memory management may be unwanted for Ewasm contracts since it costs gas. This situation will improve as WebAssembly, compilers, and libraries mature. -Quirk 2) In the current Ewasm design, all communication between the contract and the client is done through the module's memory. For example, the message data ("call data") to the contract is accessed by calling `callDataCopy` to put this data to a memory location. Accessing a contract's storage requires calls to `storageStore` or `storageLoad`, which require memory offsets of the storage key and value. We will allocate memory in C/C++ using `malloc`. For example, before calling `callDataCopy`, one may use `getCallDataSize` to see how many bytes of memory to `malloc`. +Quirk 2) In the current Ewasm design, all communication between the contract and the client is done through the module's memory. For example, the message data ("call data") to the contract is accessed by calling `callDataCopy` to put this data to a location in WebAssembly memory. Accessing a contract's storage requires calls to `storageStore` or `storageLoad`, which take as arguments the memory pointers to the storage address and storage value. We must allocate this memory in C/C++ using `malloc`. For example, before calling `callDataCopy`, one may use `getCallDataSize` to see how many bytes of memory to `malloc`. -Quirk 3) In the current Ewasm design, the Ethereum client writes data into WebAssembly as big-endian, and WebAssembly memory is little-endian, so all data has reversed bytes when they are in the WebAssembly operand stack. For example, when the call data is brought into memory using `callDataCopy`, and those bytes are loaded to the WebAssembly stack using `i64.load`, all of the bytes are reversed. So a function may be needed in C/C++ to reverse the bytes. +Quirk 3) In the current Ewasm design, the Ethereum client writes data into WebAssembly as big-endian, and WebAssembly memory is little-endian, so has reversed bytes when the data is in the WebAssembly operand stack. For example, when the call data is brought into memory using `callDataCopy`, and those bytes are loaded to the WebAssembly stack using `i64.load`, all of the bytes are reversed. So extra C/C+ code may be needed to reverse the bytes. -Quirk 4) The output of compilers is a `.wasm` binary which may have some extra imports and exports with strange names. These must be manually fixed to be a valid Ewasm contract. +Quirk 4) The output of compilers is a `.wasm` binary which may have imports and exports which do not meet Ewasm requirements. These must be manually fixed to be a valid Ewasm contract. ## Step-by-Step Guide -The wasmception package offers patches to libc and libc++ which allow using `malloc` when targeting WebAssembly. This tool is not specific to Ewasm, it is maintained by a third party. Warning: compiling wasmception will download llvm, llvm tools, musl C library, and libc++, which will require internet bandwidth, lots of RAM, and time. +The wasmception package offers patches to libc and libc++ which allow using `malloc` when targeting WebAssembly. Wasmception is not specific to Ewasm, it is maintained by a third party. Warning: compiling wasmception will download llvm, llvm tools, musl C library, and libc++, which will require internet bandwidth, lots of RAM, and time. ```sh git clone https://github.com/yurydelendik/wasmception.git @@ -30,7 +30,9 @@ cd .. Write down the end of the output of the above `make` command, it should include something like: `--sysroot=/home/user/repos/wasmception/sysroot`. -We modified the wasmception example into an Ewasm contract, which we will now download. Make sure to edit the `Makefile` with the sysroot data above, and change the path to clang to our newly compiled version which may look something like `/home/user/repos/wasmception/dist/bin/clang`. Make sure that `main.syms` has a list of Ewasm helper functions you are using. If you are using C++, make sure to modify the Makefile to clang++, use `extern "C"` around the helper function declarations, and follow other tips from wasmception. +We modified the wasmception example into an Ewasm contract, which we will now download and compile. Make sure to edit the `Makefile` with the sysroot data above, and change the path to `clang` to our newly compiled version which may look something like `/home/user/repos/wasmception/dist/bin/clang`. Make sure that `main.syms` has a list of Ewasm helper functions you are using. + +Aside: If you are using C++, make sure to modify the Makefile to `clang++`, use `extern "C"` around the helper function declarations, and follow other tips from wasmception. ```sh git clone https://gist.github.com/poemm/91b64ecd2ca2f1cb4a88d31315313b9b.git cwrc20 @@ -39,9 +41,9 @@ cd cwrc20 make ``` -The output is `main.wasm`, but it needs some cleanup to remove some of it's extra import and export junk. For this, we use PyWebAssembly. +The output is `main.wasm` whith needs a cleanup of imports and exports to meet Ewasm requirements. For this, we use PyWebAssembly. -Aside: Alternatively, one can manually clean this junk. Alternatively, one can use a [rust version of wasm-chisel](https://github.com/wasmx/wasm-chisel) which can be installed with `cargo install chisel`. The Rust version has more features, the Python version is just enough for our use. In either case, before deploying, contracts should be visually inspected to make sure that imports and exports meet Ewasm requirements. +Aside: Alternatively, one can manually cleanup. Alternatively, one can use a [rust version of wasm-chisel](https://github.com/wasmx/wasm-chisel) which can be installed with `cargo install chisel`. The Rust version has more features, the Python version is just enough for our use. In either case, before deploying, contracts should be visually inspected to make sure that imports and exports meet Ewasm requirements. ``` cd .. @@ -51,9 +53,9 @@ python3 ewasm_chisel.py ../../cwrc20/main.wasm cd ../../cwrc20 ``` -The output `main_chiseled.wasm` is an Ewasm contract. To deploy it from http://ewasm.ethereum.org/studio/, we need to convert it form the `.wasm` binary format to the `.wat` (or `.wast`) text format. This conversion can be done with binaryen's `wasm-dis`. +The output `main_chiseled.wasm` is an Ewasm contract. To deploy it from http://ewasm.ethereum.org/studio/, we need to convert it form the `.wasm` binary format to the `.wat` (or `.wast`) text format. This conversion can be done with Binaryen's `wasm-dis`. -Aside: Alternatively one can download the precompiled release of Binaryen, or try using Wabt's `wasm2wat` instead. But Binaryen's `wasm-dis` is recommended because Ewasm studio uses Binaryen internally, and Binaryen can be quirky and fail to read the `.wat` generated somewhere else. Also, if Binaryen's `wasm-dis` can't read the `.wasm`, try using Wabt's `wasm2wat` then `wat2wasm` before trying again with Binaryen. +Aside: Alternatively one can use Wabt's `wasm2wat`. But Binaryen's `wasm-dis` is recommended because Ewasm studio uses Binaryen internally, and Binaryen can be quirky and fail to read the `.wat` generated elsewhere. Also, if Binaryen's `wasm-dis` can't read the `.wasm`, try using Wabt's `wasm2wat` then `wat2wasm` before trying again with Binaryen. ```sh cd .. From 9650e3884f9118168d6cab4982eac8f52ca7a74c Mon Sep 17 00:00:00 2001 From: poemm <36397285+poemm@users.noreply.github.com> Date: Thu, 6 Dec 2018 20:31:38 -0600 Subject: [PATCH 03/20] C/C++ guide spellcheck and cleanup --- c_cpp_guide.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/c_cpp_guide.md b/c_cpp_guide.md index 3754d17..875345f 100644 --- a/c_cpp_guide.md +++ b/c_cpp_guide.md @@ -8,9 +8,9 @@ An Ewasm contract is a WebAssembly module with the following restrictions. The m Below are four quirks of using C/C++ to write Ewasm contracts. These quirks may improve as tools and Ewasm improve. -Quirk 1) WebAssembly is still primitive and lacks features. For example WebAssembly lacks support for exceptions and we have no way to do systeam calls in Ewasm. We compile against patched versions of libc and libc++ to allow us to use `malloc`, but the patches are not enough for `std::vector` which uses more than just `malloc` to manage memory. But memory management may be unwanted for Ewasm contracts since it costs gas. This situation will improve as WebAssembly, compilers, and libraries mature. +Quirk 1) WebAssembly is still primitive and lacks features. For example WebAssembly lacks support for exceptions and we have no way to do system calls in Ewasm. We compile against patched versions of libc and libc++ to allow us to use `malloc`, but the patches are not enough for `std::vector` which uses more than just `malloc` to manage memory. But memory management may be unwanted for Ewasm contracts since it costs gas. This situation will improve as WebAssembly, compilers, and libraries mature. -Quirk 2) In the current Ewasm design, all communication between the contract and the client is done through the module's memory. For example, the message data ("call data") to the contract is accessed by calling `callDataCopy` to put this data to a location in WebAssembly memory. Accessing a contract's storage requires calls to `storageStore` or `storageLoad`, which take as arguments the memory pointers to the storage address and storage value. We must allocate this memory in C/C++ using `malloc`. For example, before calling `callDataCopy`, one may use `getCallDataSize` to see how many bytes of memory to `malloc`. +Quirk 2) In the current Ewasm design, all communication between the contract and the client is done through the module's memory. For example, the message data ("call data") to the contract is accessed by calling `callDataCopy`, which puts this data to WebAssembly memory at a location given by a pointer. We must allocate this memory in C/C++ using `malloc`. For example, before calling `callDataCopy`, one may use `getCallDataSize` to see how many bytes of memory to `malloc`. Quirk 3) In the current Ewasm design, the Ethereum client writes data into WebAssembly as big-endian, and WebAssembly memory is little-endian, so has reversed bytes when the data is in the WebAssembly operand stack. For example, when the call data is brought into memory using `callDataCopy`, and those bytes are loaded to the WebAssembly stack using `i64.load`, all of the bytes are reversed. So extra C/C+ code may be needed to reverse the bytes. @@ -24,7 +24,7 @@ The wasmception package offers patches to libc and libc++ which allow using `mal ```sh git clone https://github.com/yurydelendik/wasmception.git cd wasmception -make -j4 # Warning: this required lots of internet bandwidth, RAM, and one hour on a mid-level laptop. +make -j4 # Warning: this required lots of internet bandwidth, RAM, and one hour compiling on a mid-level laptop. cd .. ``` @@ -41,9 +41,9 @@ cd cwrc20 make ``` -The output is `main.wasm` whith needs a cleanup of imports and exports to meet Ewasm requirements. For this, we use PyWebAssembly. +The output is `main.wasm` which needs a cleanup of imports and exports to meet Ewasm requirements. For this, we use PyWebAssembly. -Aside: Alternatively, one can manually cleanup. Alternatively, one can use a [rust version of wasm-chisel](https://github.com/wasmx/wasm-chisel) which can be installed with `cargo install chisel`. The Rust version has more features, the Python version is just enough for our use. In either case, before deploying, contracts should be visually inspected to make sure that imports and exports meet Ewasm requirements. +Aside: Alternatively, one can manually cleanup. Alternatively, one can use a [rust version of wasm-chisel](https://github.com/wasmx/wasm-chisel) which can be installed with `cargo install chisel`. The Rust version is stricter and has more features, the Python version is just enough for our use. In either case, before deploying, contracts should be visually inspected to make sure that imports and exports meet Ewasm requirements. ``` cd .. @@ -53,7 +53,7 @@ python3 ewasm_chisel.py ../../cwrc20/main.wasm cd ../../cwrc20 ``` -The output `main_chiseled.wasm` is an Ewasm contract. To deploy it from http://ewasm.ethereum.org/studio/, we need to convert it form the `.wasm` binary format to the `.wat` (or `.wast`) text format. This conversion can be done with Binaryen's `wasm-dis`. +The output `main_chiseled.wasm` is an Ewasm contract. To deploy it from http://ewasm.ethereum.org/studio/, we need to convert it from the `.wasm` binary format to the `.wat` (or `.wast`) text format. This conversion can be done with Binaryen's `wasm-dis`. Aside: Alternatively one can use Wabt's `wasm2wat`. But Binaryen's `wasm-dis` is recommended because Ewasm studio uses Binaryen internally, and Binaryen can be quirky and fail to read the `.wat` generated elsewhere. Also, if Binaryen's `wasm-dis` can't read the `.wasm`, try using Wabt's `wasm2wat` then `wat2wasm` before trying again with Binaryen. From 7aecffdc1ab169b8b0f9e4a082580c50e8e31b6a Mon Sep 17 00:00:00 2001 From: poemm <36397285+poemm@users.noreply.github.com> Date: Sat, 8 Dec 2018 13:38:02 -0600 Subject: [PATCH 04/20] C/C++ guide clarifications and advanced section --- c_cpp_guide.md | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/c_cpp_guide.md b/c_cpp_guide.md index 875345f..bf15a21 100644 --- a/c_cpp_guide.md +++ b/c_cpp_guide.md @@ -41,7 +41,7 @@ cd cwrc20 make ``` -The output is `main.wasm` which needs a cleanup of imports and exports to meet Ewasm requirements. For this, we use PyWebAssembly. +The output is `main.wasm` which needs a cleanup of imports and exports to meet Ewasm requirements. For this, we use PyWebAssembly. Aside: Alternatively, one can manually cleanup. Alternatively, one can use a [rust version of wasm-chisel](https://github.com/wasmx/wasm-chisel) which can be installed with `cargo install chisel`. The Rust version is stricter and has more features, the Python version is just enough for our use. In either case, before deploying, contracts should be visually inspected to make sure that imports and exports meet Ewasm requirements. @@ -53,7 +53,9 @@ python3 ewasm_chisel.py ../../cwrc20/main.wasm cd ../../cwrc20 ``` -The output `main_chiseled.wasm` is an Ewasm contract. To deploy it from http://ewasm.ethereum.org/studio/, we need to convert it from the `.wasm` binary format to the `.wat` (or `.wast`) text format. This conversion can be done with Binaryen's `wasm-dis`. +If the command line output of the `main_chiseled.wasm` command above lists only valid Ewasm imports and exports, then we may have an valid Ewasm contract! Otherwise, we need a trick to eliminate them, similar to how we used a patched musl libc so that we can use malloc without extra imports or exports. + +To deploy the Ewasm contract from http://ewasm.ethereum.org/studio/, we need to convert it from the `.wasm` binary format to the `.wat` (or `.wast`) text format (these are equivalent formats and can be converted back-and-forth). This conversion can be done with Binaryen's `wasm-dis`. Aside: Alternatively one can use Wabt's `wasm2wat`. But Binaryen's `wasm-dis` is recommended because Ewasm studio uses Binaryen internally, and Binaryen can be quirky and fail to read the `.wat` generated elsewhere. Also, if Binaryen's `wasm-dis` can't read the `.wasm`, try using Wabt's `wasm2wat` then `wat2wasm` before trying again with Binaryen. @@ -69,3 +71,8 @@ cd ../../cwrc20 ``` Now `main_chiseled.wat` can be pasted into http://ewasm.ethereum.org/studio/ and deployed. Happy hacking! + + +## Advanced + +The above guide is for compiling a single C file with no system calls (we enabled `malloc` by patching it). This may be enough for basic examples. The user is encouraged to explore ways to do advanced things. For example, an interesting idea is to statically link against other C files using LLVM IR as described here https://aransentin.github.io/cwasm/ . From 85343a246956e74044bf2f43d658de03795c94dd Mon Sep 17 00:00:00 2001 From: poemm <36397285+poemm@users.noreply.github.com> Date: Sat, 8 Dec 2018 13:42:23 -0600 Subject: [PATCH 05/20] C/C++ guide removed clang stuff --- README.md | 1 - clang.md | 54 ------------------------------------------------------ 2 files changed, 55 deletions(-) delete mode 100644 clang.md diff --git a/README.md b/README.md index 31de080..ab04fe4 100644 --- a/README.md +++ b/README.md @@ -89,7 +89,6 @@ One of the [design goals](https://github.com/ewasm/design/blob/master/rationale. At present, we've developed support for the following languages and toolchains: -- [C/C++ (LLVM) WebAssembly tutorial](./clang.md) - [C/C++](./c_cpp_guide.md) - Rust: documentation pending - [AssemblyScript](https://github.com/AssemblyScript/assemblyscript), a subset of TypeScript, which uses the JavaScript toolchain: see the [etherts org](https://github.com/etherts/docs) for more information on writing contracts in AssemblyScript. diff --git a/clang.md b/clang.md deleted file mode 100644 index ded7333..0000000 --- a/clang.md +++ /dev/null @@ -1,54 +0,0 @@ -# Compiling C/C++ to WebAssembly - -## Rolling your own compiler - -Clang has a WebAssembly target, though it is not easy to use currently. First, a custom build must be made. - -To build `clang`: -```sh -git clone http://llvm.org/git/llvm.git -cd llvm/tools -git clone http://llvm.org/git/clang.git -cd ../projects -git clone http://llvm.org/git/compiler-rt.git -mkdir ../build -cd ../build -cmake -DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD=WebAssembly -DLLVM_TARGETS_TO_BUILD= .. -cmake --build . -cd ../.. -``` - -This will take anything from 1 to 5 hours. - -To build `binaryen`: -```sh -git clone https://github.com/WebAssembly/binaryen.git -cd binaryen -mkdir build -cd build -cmake .. -cmake --build . -cd ../.. -``` - -## Using this compiler - -Now everything is set to finally compile *Hello World*! - -The compilation process has four steps: -- compiling (`clang`) -- linking to LLVM IR (`llc`) -- compiling to WebAssembly S-expressions (`s2wasm`) -- compiling to WebAssembly binary (`wasm-as`) - -Note: the last step can also be accomplished with [wabt](https://github.com/webassembly/wabt) (previously called *sexpr-wasm-prototype*). - -Cheat sheet: -```sh -clang -emit-llvm --target=wasm32-unknown-unknown-elf -nostdlib -S hello.c -llc -o hello.s hello.ll -s2wasm -o hello.wast hello.s -wasm-as -o hello.wasm hello.wast -``` - -There you go, you have your very first WebAssembly binary. From b1471d756fa7534ae55c520ddc31dfe444b87906 Mon Sep 17 00:00:00 2001 From: poemm <36397285+poemm@users.noreply.github.com> Date: Sun, 9 Dec 2018 13:02:01 -0600 Subject: [PATCH 06/20] C/C++ guide changed ewasm_chisel.py to ewasmify.py --- c_cpp_guide.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/c_cpp_guide.md b/c_cpp_guide.md index bf15a21..4b3d20e 100644 --- a/c_cpp_guide.md +++ b/c_cpp_guide.md @@ -43,17 +43,17 @@ make The output is `main.wasm` which needs a cleanup of imports and exports to meet Ewasm requirements. For this, we use PyWebAssembly. -Aside: Alternatively, one can manually cleanup. Alternatively, one can use a [rust version of wasm-chisel](https://github.com/wasmx/wasm-chisel) which can be installed with `cargo install chisel`. The Rust version is stricter and has more features, the Python version is just enough for our use. In either case, before deploying, contracts should be visually inspected to make sure that imports and exports meet Ewasm requirements. +Aside: Alternatively, one can manually cleanup. Alternatively, one can use [wasm-chisel](https://github.com/wasmx/wasm-chisel) which is a program in Rust which can be installed with `cargo install chisel`. The Rust version is stricter and has more features, the Python version is just enough for our use. In either case, before deploying, contracts should be visually inspected to make sure that imports and exports meet Ewasm requirements. ``` cd .. git clone https://github.com/poemm/pywebassembly.git cd pywebassembly/examples/ -python3 ewasm_chisel.py ../../cwrc20/main.wasm +python3 ewasmify.py ../../cwrc20/main.wasm cd ../../cwrc20 ``` -If the command line output of the `main_chiseled.wasm` command above lists only valid Ewasm imports and exports, then we may have an valid Ewasm contract! Otherwise, we need a trick to eliminate them, similar to how we used a patched musl libc so that we can use malloc without extra imports or exports. +If the command line output of the `main_ewasmified.wasm` command above lists only valid Ewasm imports and exports, then we may have an valid Ewasm contract! Otherwise, we need a trick to eliminate them, similar to how we used a patched musl libc so that we can use malloc without extra imports or exports. To deploy the Ewasm contract from http://ewasm.ethereum.org/studio/, we need to convert it from the `.wasm` binary format to the `.wat` (or `.wast`) text format (these are equivalent formats and can be converted back-and-forth). This conversion can be done with Binaryen's `wasm-dis`. @@ -67,10 +67,10 @@ mkdir build && cd build cmake .. make -j4 cd ../../cwrc20 -../binaryen/build/bin/wasm-dis main_chiseled.wasm > main_chiseled.wat +../binaryen/build/bin/wasm-dis main_ewasmified.wasm > main_ewasmified.wat ``` -Now `main_chiseled.wat` can be pasted into http://ewasm.ethereum.org/studio/ and deployed. Happy hacking! +Now `main_ewasmified.wat` can be pasted into http://ewasm.ethereum.org/studio/ and deployed. Happy hacking! ## Advanced From a52a723591766b9e37855d26815bcb2b1e71d6a5 Mon Sep 17 00:00:00 2001 From: poemm <36397285+poemm@users.noreply.github.com> Date: Sun, 9 Dec 2018 13:12:48 -0600 Subject: [PATCH 07/20] C/C++ guide clarify ewasmify.py --- c_cpp_guide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/c_cpp_guide.md b/c_cpp_guide.md index 4b3d20e..e273c97 100644 --- a/c_cpp_guide.md +++ b/c_cpp_guide.md @@ -53,7 +53,7 @@ python3 ewasmify.py ../../cwrc20/main.wasm cd ../../cwrc20 ``` -If the command line output of the `main_ewasmified.wasm` command above lists only valid Ewasm imports and exports, then we may have an valid Ewasm contract! Otherwise, we need a trick to eliminate them, similar to how we used a patched musl libc so that we can use malloc without extra imports or exports. +Check whether the command line output of `ewasmify.py` above lists only valid Ewasm imports and exports. If not, then we need a trick to eliminate non-Ewasm imports or exports, similar to how we used a patched musl libc so that we can use malloc without extra imports or exports. To deploy the Ewasm contract from http://ewasm.ethereum.org/studio/, we need to convert it from the `.wasm` binary format to the `.wat` (or `.wast`) text format (these are equivalent formats and can be converted back-and-forth). This conversion can be done with Binaryen's `wasm-dis`. From 696768cde89b22e51f3f6873039e6c139eb65053 Mon Sep 17 00:00:00 2001 From: poemm <36397285+poemm@users.noreply.github.com> Date: Mon, 10 Dec 2018 17:02:15 -0600 Subject: [PATCH 08/20] C/C++ guide clarifications --- c_cpp_guide.md | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/c_cpp_guide.md b/c_cpp_guide.md index e273c97..b783045 100644 --- a/c_cpp_guide.md +++ b/c_cpp_guide.md @@ -6,16 +6,17 @@ First an introduction, then a step-by-step guide. Warning: the Ewasm spec and to An Ewasm contract is a WebAssembly module with the following restrictions. The module's imports must be among the [Ewasm helper functions](https://github.com/ewasm/design/blob/master/eth_interface.md) which resemble EVM opcodes to interact with the client. The module's exports must be a `main` function which takes no arguments and returns nothing, and the `memory` of the module. The module can't using floats or other sources of non-determinism. -Below are four quirks of using C/C++ to write Ewasm contracts. These quirks may improve as tools and Ewasm improve. +Below are quirks to be aware of when writing Ewasm contracts in C/C++. The last three quirks are not limited to C/C++. These quirks may improve as tools and Ewasm improve. -Quirk 1) WebAssembly is still primitive and lacks features. For example WebAssembly lacks support for exceptions and we have no way to do system calls in Ewasm. We compile against patched versions of libc and libc++ to allow us to use `malloc`, but the patches are not enough for `std::vector` which uses more than just `malloc` to manage memory. But memory management may be unwanted for Ewasm contracts since it costs gas. This situation will improve as WebAssembly, compilers, and libraries mature. +Quirk 1) WebAssembly is still primitive and lacks features. For example, WebAssembly lacks support for exceptions and we have no way to do system calls in Ewasm. Compilers and libraries are still primitive. For example, we compile against patched versions of libc and libc++ to allow us to use `malloc`, but the patches are not enough for `std::vector` which uses more than just `malloc` to manage memory. But anything beyond memory allocation may be unwanted for Ewasm contracts since it costs gas. This situation will improve as WebAssembly, compilers, and libraries mature. -Quirk 2) In the current Ewasm design, all communication between the contract and the client is done through the module's memory. For example, the message data ("call data") to the contract is accessed by calling `callDataCopy`, which puts this data to WebAssembly memory at a location given by a pointer. We must allocate this memory in C/C++ using `malloc`. For example, before calling `callDataCopy`, one may use `getCallDataSize` to see how many bytes of memory to `malloc`. +Quirk 2) In the current Ewasm design, all communication between the contract and the client is done through the module's memory. For example, the message data ("call data") sent to the contract is accessed by calling `callDataCopy()`, which puts this data to WebAssembly memory at a location given by a pointer. We must allocate this pointer's memory in C/C++ using `malloc`. For example, before calling `callDataCopy()`, one may use `getCallDataSize()` to see how many bytes of memory to `malloc`. -Quirk 3) In the current Ewasm design, the Ethereum client writes data into WebAssembly as big-endian, and WebAssembly memory is little-endian, so has reversed bytes when the data is in the WebAssembly operand stack. For example, when the call data is brought into memory using `callDataCopy`, and those bytes are loaded to the WebAssembly stack using `i64.load`, all of the bytes are reversed. So extra C/C+ code may be needed to reverse the bytes. +Quirk 3) In the current Ewasm design, the Ethereum client writes data into WebAssembly as big-endian, and WebAssembly memory is little-endian, so has reversed bytes when the data is brought to/from the WebAssembly operand stack. For example, when the call data is brought into memory using `callDataCopy`, and those bytes are loaded to the WebAssembly stack using `i64.load`, all of the bytes are reversed. So extra C/C++ code may be needed load bytes from the correct location and to reverse the loaded bytes. Quirk 4) The output of compilers is a `.wasm` binary which may have imports and exports which do not meet Ewasm requirements. These must be manually fixed to be a valid Ewasm contract. +Quirk 5) There are no tutorials for debugging/testing a contract. Hera supports extra Ewasm helper functions to print things, to help in writing test cases. A tutorial is needed to allow early adopters to debug/test their contracts. ## Step-by-Step Guide @@ -24,13 +25,13 @@ The wasmception package offers patches to libc and libc++ which allow using `mal ```sh git clone https://github.com/yurydelendik/wasmception.git cd wasmception -make -j4 # Warning: this required lots of internet bandwidth, RAM, and one hour compiling on a mid-level laptop. +make -j4 # Warning: this required lots of internet bandwidth, RAM, disk space, and one hour compiling on a mid-level laptop. cd .. ``` Write down the end of the output of the above `make` command, it should include something like: `--sysroot=/home/user/repos/wasmception/sysroot`. -We modified the wasmception example into an Ewasm contract, which we will now download and compile. Make sure to edit the `Makefile` with the sysroot data above, and change the path to `clang` to our newly compiled version which may look something like `/home/user/repos/wasmception/dist/bin/clang`. Make sure that `main.syms` has a list of Ewasm helper functions you are using. +We modified the wasmception example to create an Ewasm contract, which we will now download and compile. Make sure to edit the `Makefile` with the sysroot data above, and change the path to `clang` to our newly compiled version which may look something like `/home/user/repos/wasmception/dist/bin/clang`. Make sure that `main.syms` has a list of Ewasm helper functions you are using. Aside: If you are using C++, make sure to modify the Makefile to `clang++`, use `extern "C"` around the helper function declarations, and follow other tips from wasmception. @@ -43,7 +44,7 @@ make The output is `main.wasm` which needs a cleanup of imports and exports to meet Ewasm requirements. For this, we use PyWebAssembly. -Aside: Alternatively, one can manually cleanup. Alternatively, one can use [wasm-chisel](https://github.com/wasmx/wasm-chisel) which is a program in Rust which can be installed with `cargo install chisel`. The Rust version is stricter and has more features, the Python version is just enough for our use. In either case, before deploying, contracts should be visually inspected to make sure that imports and exports meet Ewasm requirements. +Aside: Alternatively, one can manually cleanup. Alternatively, one can use [wasm-chisel](https://github.com/wasmx/wasm-chisel) which is a program in Rust which can be installed with `cargo install chisel`. The Rust version is stricter and has more features, the Python version is just enough for our use-case, and Python is available on most machines. ``` cd .. @@ -57,7 +58,7 @@ Check whether the command line output of `ewasmify.py` above lists only valid Ew To deploy the Ewasm contract from http://ewasm.ethereum.org/studio/, we need to convert it from the `.wasm` binary format to the `.wat` (or `.wast`) text format (these are equivalent formats and can be converted back-and-forth). This conversion can be done with Binaryen's `wasm-dis`. -Aside: Alternatively one can use Wabt's `wasm2wat`. But Binaryen's `wasm-dis` is recommended because Ewasm studio uses Binaryen internally, and Binaryen can be quirky and fail to read the `.wat` generated elsewhere. Also, if Binaryen's `wasm-dis` can't read the `.wasm`, try using Wabt's `wasm2wat` then `wat2wasm` before trying again with Binaryen. +Aside: Alternatively one can use Wabt's `wasm2wat`. But Binaryen's `wasm-dis` is recommended because Ewasm studio uses Binaryen internally, and Binaryen can be quirky and fail to read a `.wat` generated by another program. Another tip: if Binaryen's `wasm-dis` can't read the `.wasm`, try using Wabt's `wasm2wat` then `wat2wasm` before trying again with Binaryen. ```sh cd .. @@ -75,4 +76,4 @@ Now `main_ewasmified.wat` can be pasted into http://ewasm.ethereum.org/studio/ a ## Advanced -The above guide is for compiling a single C file with no system calls (we enabled `malloc` by patching it). This may be enough for basic examples. The user is encouraged to explore ways to do advanced things. For example, an interesting idea is to statically link against other C files using LLVM IR as described here https://aransentin.github.io/cwasm/ . +The above guide is for compiling a single C file with no system calls (we enabled `malloc` by patching it). The user is encouraged to explore ways to do advanced things. For example, a way to statically link against other C files using LLVM IR as described here https://aransentin.github.io/cwasm/ . From c229d165800877a4a88a9f1e0928d633876933a2 Mon Sep 17 00:00:00 2001 From: poemm <36397285+poemm@users.noreply.github.com> Date: Wed, 19 Dec 2018 21:50:21 -0600 Subject: [PATCH 09/20] C/C++ guide added basic LLVM guiden --- c_cpp_guide.md | 54 ++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 41 insertions(+), 13 deletions(-) diff --git a/c_cpp_guide.md b/c_cpp_guide.md index b783045..5c16e19 100644 --- a/c_cpp_guide.md +++ b/c_cpp_guide.md @@ -18,25 +18,32 @@ Quirk 4) The output of compilers is a `.wasm` binary which may have imports and Quirk 5) There are no tutorials for debugging/testing a contract. Hera supports extra Ewasm helper functions to print things, to help in writing test cases. A tutorial is needed to allow early adopters to debug/test their contracts. -## Step-by-Step Guide +## Basic Step-by-Step Guide -The wasmception package offers patches to libc and libc++ which allow using `malloc` when targeting WebAssembly. Wasmception is not specific to Ewasm, it is maintained by a third party. Warning: compiling wasmception will download llvm, llvm tools, musl C library, and libc++, which will require internet bandwidth, lots of RAM, and time. +First build the latest version of LLVM. Note that if you wish to use standard libraries, use the version of LLVM in the Advanced section below. That version can also be used here. ```sh -git clone https://github.com/yurydelendik/wasmception.git -cd wasmception -make -j4 # Warning: this required lots of internet bandwidth, RAM, disk space, and one hour compiling on a mid-level laptop. -cd .. +# checkout LLVM, clang, and lld +svn co http://llvm.org/svn/llvm-project/llvm/trunk llvm +cd llvm/tools +svn co http://llvm.org/svn/llvm-project/cfe/trunk clang +svn co http://llvm.org/svn/llvm-project/lld/trunk lld +cd ../.. + +# build LLVM +mkdir llvm-build +cd llvm-build +# note: if you want other targets than WebAssembly, then delete -DLLVM_TARGETS_TO_BUILD +cmake -G "Unix Makefiles" -DLLVM_TARGETS_TO_BUILD= -DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD=WebAssembly $WORKDIR/llvm +make -j 8 # WARNING, THIS CAN TAKE HOURS, NEEDS LOTS OF DISK AND RAM, IF IT FAILS, TRY AGAIN WITHOUT -j 8 ``` -Write down the end of the output of the above `make` command, it should include something like: `--sysroot=/home/user/repos/wasmception/sysroot`. - -We modified the wasmception example to create an Ewasm contract, which we will now download and compile. Make sure to edit the `Makefile` with the sysroot data above, and change the path to `clang` to our newly compiled version which may look something like `/home/user/repos/wasmception/dist/bin/clang`. Make sure that `main.syms` has a list of Ewasm helper functions you are using. +Next download and compile a wrc20 ewasm contract written in C. In `main.c` there are many arrays in global scope -- LLVM puts global arrays in WebAssembly memory, which is needed so that they can be used to communicate with Ethereum helper functions. Before compiling, make sure that the `Makefile` has a path to `llvm-build` above, and that `main.syms` has a list of Ewasm helper functions you are using. -Aside: If you are using C++, make sure to modify the Makefile to `clang++`, use `extern "C"` around the helper function declarations, and follow other tips from wasmception. +Aside: If you are using C++, make sure to modify the Makefile to `clang++`, use `extern "C"` around the helper function declarations. ```sh -git clone https://gist.github.com/poemm/91b64ecd2ca2f1cb4a88d31315313b9b.git cwrc20 +git clone https://gist.github.com/poemm/68a7b70ec353abaeae64bf6fe95d2d52.git cwrc20 cd cwrc20 # edit the Makefile and main.syms as described above make @@ -54,7 +61,7 @@ python3 ewasmify.py ../../cwrc20/main.wasm cd ../../cwrc20 ``` -Check whether the command line output of `ewasmify.py` above lists only valid Ewasm imports and exports. If not, then we need a trick to eliminate non-Ewasm imports or exports, similar to how we used a patched musl libc so that we can use malloc without extra imports or exports. +Check whether the command line output of `ewasmify.py` above lists only valid Ewasm imports and exports. If not, we may need libc to fill these in, see the Advanced section. To deploy the Ewasm contract from http://ewasm.ethereum.org/studio/, we need to convert it from the `.wasm` binary format to the `.wat` (or `.wast`) text format (these are equivalent formats and can be converted back-and-forth). This conversion can be done with Binaryen's `wasm-dis`. @@ -76,4 +83,25 @@ Now `main_ewasmified.wat` can be pasted into http://ewasm.ethereum.org/studio/ a ## Advanced -The above guide is for compiling a single C file with no system calls (we enabled `malloc` by patching it). The user is encouraged to explore ways to do advanced things. For example, a way to statically link against other C files using LLVM IR as described here https://aransentin.github.io/cwasm/ . +The above guide is for compiling a single C file with no libc or system calls. The wasmception package offers patches to libc and libc++ which allow using libc, including things like `malloc`, when targeting WebAssembly. It also allows using libc++. Wasmception is not specific to Ewasm, it is maintained by a third party. + +``` +git clone https://github.com/yurydelendik/wasmception.git +cd wasmception +make -j4 # Warning: this required lots of internet bandwidth, RAM, disk space, and one hour compiling on a mid-level laptop. +cd .. +``` +Write down the end of the output of the above `make` command, it should include something like: `--sysroot=/home/user/repos/wasmception/sysroot`. + +We modified the wasmception example to create a version of wrc20 which uses `malloc`, which we will now download and compile. Make sure to edit the `Makefile` with the sysroot data above, and change the path to `clang` to our newly compiled version which may look something like `/home/user/repos/wasmception/dist/bin/clang`. Make sure that `main.syms` has a list of Ewasm helper functions you are using. + +Aside: If you are using C++, make sure to modify the Makefile to `clang++`, use `extern "C"` around the helper function declarations, and follow other tips from wasmception. + +```sh +git clone https://gist.github.com/poemm/91b64ecd2ca2f1cb4a88d31315313b9b.git cwrc20_with_malloc +cd cwrc20_with_malloc +# edit the Makefile and main.syms as described above +make +``` + +The user is encouraged to expore more advanced things. To statically link against other C files, we can link the LLVM IR as described here https://aransentin.github.io/cwasm/. The user is encouraged to explore ways to do advanced things. From 05561965d3977322501935861d39d2e444e72ce3 Mon Sep 17 00:00:00 2001 From: poemm <36397285+poemm@users.noreply.github.com> Date: Thu, 20 Dec 2018 08:59:16 -0600 Subject: [PATCH 10/20] C/C++ guide typos and clarifications --- c_cpp_guide.md | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/c_cpp_guide.md b/c_cpp_guide.md index 5c16e19..b5acf1b 100644 --- a/c_cpp_guide.md +++ b/c_cpp_guide.md @@ -4,23 +4,25 @@ First an introduction, then a step-by-step guide. Warning: the Ewasm spec and to ## Introduction -An Ewasm contract is a WebAssembly module with the following restrictions. The module's imports must be among the [Ewasm helper functions](https://github.com/ewasm/design/blob/master/eth_interface.md) which resemble EVM opcodes to interact with the client. The module's exports must be a `main` function which takes no arguments and returns nothing, and the `memory` of the module. The module can't using floats or other sources of non-determinism. +An Ewasm contract is a WebAssembly module with the following restrictions. The module's imports must be among the [Ewasm helper functions](https://github.com/ewasm/design/blob/master/eth_interface.md) which resemble EVM opcodes to interact with the client. The module's exports must be a `main` function which takes no arguments and returns nothing, and the `memory` of the module. The module may not use floats or other sources of non-determinism. -Below are quirks to be aware of when writing Ewasm contracts in C/C++. The last three quirks are not limited to C/C++. These quirks may improve as tools and Ewasm improve. +Below are quirks to be aware of when writing Ewasm contracts in C/C++. The last four quirks are not limited to C/C++. Things may improve as tools and Ewasm improve. -Quirk 1) WebAssembly is still primitive and lacks features. For example, WebAssembly lacks support for exceptions and we have no way to do system calls in Ewasm. Compilers and libraries are still primitive. For example, we compile against patched versions of libc and libc++ to allow us to use `malloc`, but the patches are not enough for `std::vector` which uses more than just `malloc` to manage memory. But anything beyond memory allocation may be unwanted for Ewasm contracts since it costs gas. This situation will improve as WebAssembly, compilers, and libraries mature. +Quirk 1) WebAssembly is still primitive and lacks features. For example, WebAssembly lacks support for exceptions and we have no way to do system calls in Ewasm. Compilers and libraries are still primitive. For example, we compile against a patched version of libc to allow us to compile `malloc` into the module, but the patches are not yet enough for `std::vector` which uses more than just `malloc` to manage memory. But any memory management beyond memory allocation may be unwanted for Ewasm contracts since it costs gas. This situation will improve as WebAssembly, compilers, and libraries mature. -Quirk 2) In the current Ewasm design, all communication between the contract and the client is done through the module's memory. For example, the message data ("call data") sent to the contract is accessed by calling `callDataCopy()`, which puts this data to WebAssembly memory at a location given by a pointer. We must allocate this pointer's memory in C/C++ using `malloc`. For example, before calling `callDataCopy()`, one may use `getCallDataSize()` to see how many bytes of memory to `malloc`. +Quirk 2) In the current Ewasm design, all communication between the contract and the client is done through the module's memory. For example, the message data ("call data") sent to the contract is accessed by calling `callDataCopy()`, which puts this data to WebAssembly memory at a location given by a pointer. This pointer must be to either a statically allocated array, or to dynamically allocated memory using `malloc. For example, before calling `callDataCopy()`, one may use `getCallDataSize()` to see how many bytes of memory to `malloc`. -Quirk 3) In the current Ewasm design, the Ethereum client writes data into WebAssembly as big-endian, and WebAssembly memory is little-endian, so has reversed bytes when the data is brought to/from the WebAssembly operand stack. For example, when the call data is brought into memory using `callDataCopy`, and those bytes are loaded to the WebAssembly stack using `i64.load`, all of the bytes are reversed. So extra C/C++ code may be needed load bytes from the correct location and to reverse the loaded bytes. +Quirk 3) In the current Ewasm design, the Ethereum client writes data into WebAssembly as big-endian, but WebAssembly memory is little-endian, so has reversed bytes when the data is brought to/from the WebAssembly operand stack. For example, when the call data is brought into memory using `callDataCopy`, and those bytes are loaded to the WebAssembly stack using `i64.load`, all of the bytes are reversed. So extra C/C++ code may be needed load bytes from the correct location and to reverse the loaded bytes. -Quirk 4) The output of compilers is a `.wasm` binary which may have imports and exports which do not meet Ewasm requirements. These must be manually fixed to be a valid Ewasm contract. +Quirk 4) The output of compilers is a `.wasm` binary which may have imports and exports which do not meet Ewasm requirements. These must be fixed to be a valid Ewasm contract. -Quirk 5) There are no tutorials for debugging/testing a contract. Hera supports extra Ewasm helper functions to print things, to help in writing test cases. A tutorial is needed to allow early adopters to debug/test their contracts. +Quirk 5) There are no tutorials for debugging/testing a contract. Hera supports extra Ewasm helper functions to print things, which have helped in writing test cases. A tutorial is needed to allow early adopters to debug/test their contracts without having to do it on the testnet. ## Basic Step-by-Step Guide -First build the latest version of LLVM. Note that if you wish to use standard libraries, use the version of LLVM in the Advanced section below. That version can also be used here. +First build the latest version of LLVM. + +Aside: If you wish to use standard C/C++ libraries, then build the version of LLVM in the Advanced section below. That version can also be used here. ```sh # checkout LLVM, clang, and lld @@ -33,9 +35,9 @@ cd ../.. # build LLVM mkdir llvm-build cd llvm-build -# note: if you want other targets than WebAssembly, then delete -DLLVM_TARGETS_TO_BUILD +# note: if you want other targets than WebAssembly, then delete -DLLVM_TARGETS_TO_BUILD= cmake -G "Unix Makefiles" -DLLVM_TARGETS_TO_BUILD= -DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD=WebAssembly $WORKDIR/llvm -make -j 8 # WARNING, THIS CAN TAKE HOURS, NEEDS LOTS OF DISK AND RAM, IF IT FAILS, TRY AGAIN WITHOUT -j 8 +make -j 8 # WARNING, THIS CAN TAKE HOURS, NEEDS LOTS OF DISK AND RAM, AND MAY CAUSE YOUR COMPUTER TO FREEZE. IF IT ERRORS, TRY AGAIN WITHOUT -j 8 ``` Next download and compile a wrc20 ewasm contract written in C. In `main.c` there are many arrays in global scope -- LLVM puts global arrays in WebAssembly memory, which is needed so that they can be used to communicate with Ethereum helper functions. Before compiling, make sure that the `Makefile` has a path to `llvm-build` above, and that `main.syms` has a list of Ewasm helper functions you are using. @@ -61,7 +63,7 @@ python3 ewasmify.py ../../cwrc20/main.wasm cd ../../cwrc20 ``` -Check whether the command line output of `ewasmify.py` above lists only valid Ewasm imports and exports. If not, we may need libc to fill these in, see the Advanced section. +Check whether the command line output of `ewasmify.py` above lists only valid Ewasm imports and exports. To troubleshoot, you may wish to also inspect the original WebAssembly module in its text representation, so proceed to the next step with binaryen or wabt. To deploy the Ewasm contract from http://ewasm.ethereum.org/studio/, we need to convert it from the `.wasm` binary format to the `.wat` (or `.wast`) text format (these are equivalent formats and can be converted back-and-forth). This conversion can be done with Binaryen's `wasm-dis`. @@ -83,7 +85,7 @@ Now `main_ewasmified.wat` can be pasted into http://ewasm.ethereum.org/studio/ a ## Advanced -The above guide is for compiling a single C file with no libc or system calls. The wasmception package offers patches to libc and libc++ which allow using libc, including things like `malloc`, when targeting WebAssembly. It also allows using libc++. Wasmception is not specific to Ewasm, it is maintained by a third party. +The above guide is for compiling a single C file with no libc or system calls. Next we use a package which offers patches to libc and libc++ which allow using libc, including things like `malloc`, when targeting WebAssembly. It also allows using libc++. ``` git clone https://github.com/yurydelendik/wasmception.git @@ -93,7 +95,7 @@ cd .. ``` Write down the end of the output of the above `make` command, it should include something like: `--sysroot=/home/user/repos/wasmception/sysroot`. -We modified the wasmception example to create a version of wrc20 which uses `malloc`, which we will now download and compile. Make sure to edit the `Makefile` with the sysroot data above, and change the path to `clang` to our newly compiled version which may look something like `/home/user/repos/wasmception/dist/bin/clang`. Make sure that `main.syms` has a list of Ewasm helper functions you are using. +Next we will download and build a version of wrc20 which uses `malloc`. Make sure to edit the `Makefile` with the sysroot data above, and change the path to `clang` to our newly compiled version which may look something like `/home/user/repos/wasmception/dist/bin/clang`. Make sure that `main.syms` has a list of Ewasm helper functions you are using. Aside: If you are using C++, make sure to modify the Makefile to `clang++`, use `extern "C"` around the helper function declarations, and follow other tips from wasmception. @@ -104,4 +106,6 @@ cd cwrc20_with_malloc make ``` -The user is encouraged to expore more advanced things. To statically link against other C files, we can link the LLVM IR as described here https://aransentin.github.io/cwasm/. The user is encouraged to explore ways to do advanced things. +Now follow the steps above to transform the output `main.wasm` into a valid Ewasm contract. + +The user is encouraged to expore more advanced things. For example, to statically link against other C files, one can link the LLVM IR as described here https://aransentin.github.io/cwasm/. From 19253eec6fafd832c74e902c058071f0ac5b8f4f Mon Sep 17 00:00:00 2001 From: poemm <36397285+poemm@users.noreply.github.com> Date: Thu, 20 Dec 2018 21:51:35 -0600 Subject: [PATCH 11/20] C/C++ guide clarifications --- c_cpp_guide.md | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/c_cpp_guide.md b/c_cpp_guide.md index b5acf1b..daa20ef 100644 --- a/c_cpp_guide.md +++ b/c_cpp_guide.md @@ -1,20 +1,20 @@ # Compiling C/C++ to Ewasm -First an introduction, then a step-by-step guide. Warning: the Ewasm spec and tools below are subject to change. +First an introduction, then a basic step-by-step guide, then advanced things. Warning: the Ewasm spec and tools below are subject to change. ## Introduction An Ewasm contract is a WebAssembly module with the following restrictions. The module's imports must be among the [Ewasm helper functions](https://github.com/ewasm/design/blob/master/eth_interface.md) which resemble EVM opcodes to interact with the client. The module's exports must be a `main` function which takes no arguments and returns nothing, and the `memory` of the module. The module may not use floats or other sources of non-determinism. -Below are quirks to be aware of when writing Ewasm contracts in C/C++. The last four quirks are not limited to C/C++. Things may improve as tools and Ewasm improve. +Below are quirks to be aware of when writing Ewasm contracts in C/C++. These quirks are not limited to C/C++. Things may improve as tools and Ewasm improve. -Quirk 1) WebAssembly is still primitive and lacks features. For example, WebAssembly lacks support for exceptions and we have no way to do system calls in Ewasm. Compilers and libraries are still primitive. For example, we compile against a patched version of libc to allow us to compile `malloc` into the module, but the patches are not yet enough for `std::vector` which uses more than just `malloc` to manage memory. But any memory management beyond memory allocation may be unwanted for Ewasm contracts since it costs gas. This situation will improve as WebAssembly, compilers, and libraries mature. +Quirk 1) WebAssembly is still primitive and lacks features. For example, WebAssembly lacks support for exceptions and we have no way to do system calls in Ewasm. Compilers and libraries are still primitive. For example, we have patched version of libc to allow `malloc`, but the patches are not yet enough for `std::vector` because other memory managment calls are unavailable. But perhaps any memory management beyond memory allocation may be unwanted for Ewasm contracts since it costs gas. This situation will improve as WebAssembly, compilers, and libraries mature. -Quirk 2) In the current Ewasm design, all communication between the contract and the client is done through the module's memory. For example, the message data ("call data") sent to the contract is accessed by calling `callDataCopy()`, which puts this data to WebAssembly memory at a location given by a pointer. This pointer must be to either a statically allocated array, or to dynamically allocated memory using `malloc. For example, before calling `callDataCopy()`, one may use `getCallDataSize()` to see how many bytes of memory to `malloc`. +Quirk 2) In the current Ewasm design, all communication between the contract and the client is done through the module's memory. For example, the message data ("call data") sent to the contract is accessed by calling `callDataCopy()`, which puts this data to WebAssembly memory at a location given by a pointer. This pointer must be to either to a statically allocated array, or to dynamically allocated memory using `malloc`. For example, before calling `callDataCopy()`, one may use `getCallDataSize()` to see how many bytes of memory to `malloc`. -Quirk 3) In the current Ewasm design, the Ethereum client writes data into WebAssembly as big-endian, but WebAssembly memory is little-endian, so has reversed bytes when the data is brought to/from the WebAssembly operand stack. For example, when the call data is brought into memory using `callDataCopy`, and those bytes are loaded to the WebAssembly stack using `i64.load`, all of the bytes are reversed. So extra C/C++ code may be needed load bytes from the correct location and to reverse the loaded bytes. +Quirk 3) In the current Ewasm design, the Ethereum client writes data into WebAssembly as big-endian, but WebAssembly memory is little-endian, so has reversed bytes when the data is brought to/from the WebAssembly operand stack. For example, when the call data is brought into memory using `callDataCopy`, and those bytes are loaded to the WebAssembly stack using `i64.load`, all of the bytes are reversed. So extra C/C++ code may be needed to load bytes from the correct location and to reverse the loaded bytes. -Quirk 4) The output of compilers is a `.wasm` binary which may have imports and exports which do not meet Ewasm requirements. These must be fixed to be a valid Ewasm contract. +Quirk 4) The output of compilers is a `.wasm` binary which may have imports and exports which do not meet Ewasm requirements. We have tools to fix the imports and exports. Quirk 5) There are no tutorials for debugging/testing a contract. Hera supports extra Ewasm helper functions to print things, which have helped in writing test cases. A tutorial is needed to allow early adopters to debug/test their contracts without having to do it on the testnet. @@ -22,7 +22,7 @@ Quirk 5) There are no tutorials for debugging/testing a contract. Hera supports First build the latest version of LLVM. -Aside: If you wish to use standard C/C++ libraries, then build the version of LLVM in the Advanced section below. That version can also be used here. +Aside: If you wish to use C/C++ standard libraries, then build the version of LLVM in the Advanced section below. That version can also be used here. ```sh # checkout LLVM, clang, and lld @@ -32,15 +32,15 @@ svn co http://llvm.org/svn/llvm-project/cfe/trunk clang svn co http://llvm.org/svn/llvm-project/lld/trunk lld cd ../.. -# build LLVM +# build LLVM, clang, and lld mkdir llvm-build cd llvm-build # note: if you want other targets than WebAssembly, then delete -DLLVM_TARGETS_TO_BUILD= -cmake -G "Unix Makefiles" -DLLVM_TARGETS_TO_BUILD= -DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD=WebAssembly $WORKDIR/llvm +cmake -G "Unix Makefiles" -DLLVM_TARGETS_TO_BUILD= -DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD=WebAssembly ../llvm make -j 8 # WARNING, THIS CAN TAKE HOURS, NEEDS LOTS OF DISK AND RAM, AND MAY CAUSE YOUR COMPUTER TO FREEZE. IF IT ERRORS, TRY AGAIN WITHOUT -j 8 ``` -Next download and compile a wrc20 ewasm contract written in C. In `main.c` there are many arrays in global scope -- LLVM puts global arrays in WebAssembly memory, which is needed so that they can be used to communicate with Ethereum helper functions. Before compiling, make sure that the `Makefile` has a path to `llvm-build` above, and that `main.syms` has a list of Ewasm helper functions you are using. +Next download and compile a wrc20 ewasm contract written in C. Note that in `main.c`, there are many arrays in global scope -- LLVM puts global arrays in WebAssembly memory, which is allows them to be used as pointer arguments to Ethereum helper functions. Before compiling, make sure that the `Makefile` has a path to `llvm-build` above, and that `main.syms` has a list of Ewasm helper functions you are using. Aside: If you are using C++, make sure to modify the Makefile to `clang++`, use `extern "C"` around the helper function declarations. @@ -53,7 +53,7 @@ make The output is `main.wasm` which needs a cleanup of imports and exports to meet Ewasm requirements. For this, we use PyWebAssembly. -Aside: Alternatively, one can manually cleanup. Alternatively, one can use [wasm-chisel](https://github.com/wasmx/wasm-chisel) which is a program in Rust which can be installed with `cargo install chisel`. The Rust version is stricter and has more features, the Python version is just enough for our use-case, and Python is available on most machines. +Aside: Alternatively, one can manually cleanup. Alternatively, one can use [wasm-chisel](https://github.com/wasmx/wasm-chisel), a program in Rust which can be installed with `cargo install chisel`. The Rust version is stricter and has more features, the Python version is just enough for our use-case, and Python is available on most machines. ``` cd .. @@ -63,9 +63,9 @@ python3 ewasmify.py ../../cwrc20/main.wasm cd ../../cwrc20 ``` -Check whether the command line output of `ewasmify.py` above lists only valid Ewasm imports and exports. To troubleshoot, you may wish to also inspect the original WebAssembly module in its text representation, so proceed to the next step with binaryen or wabt. +Check whether the command line output of `ewasmify.py` above lists only valid Ewasm imports and exports. To troubleshoot, you may wish to also inspect `main.wasm` in its text representation, so proceed to the next step with binaryen or wabt. -To deploy the Ewasm contract from http://ewasm.ethereum.org/studio/, we need to convert it from the `.wasm` binary format to the `.wat` (or `.wast`) text format (these are equivalent formats and can be converted back-and-forth). This conversion can be done with Binaryen's `wasm-dis`. +We can convert from the `.wasm` binary format to the `.wat` (or `.wast`) text format (these are equivalent formats and can be converted back-and-forth). This conversion can be done with Binaryen's `wasm-dis`. Aside: Alternatively one can use Wabt's `wasm2wat`. But Binaryen's `wasm-dis` is recommended because Ewasm studio uses Binaryen internally, and Binaryen can be quirky and fail to read a `.wat` generated by another program. Another tip: if Binaryen's `wasm-dis` can't read the `.wasm`, try using Wabt's `wasm2wat` then `wat2wasm` before trying again with Binaryen. @@ -80,22 +80,22 @@ cd ../../cwrc20 ../binaryen/build/bin/wasm-dis main_ewasmified.wasm > main_ewasmified.wat ``` -Now `main_ewasmified.wat` can be pasted into http://ewasm.ethereum.org/studio/ and deployed. Happy hacking! +`main_ewasmified.wat` is an ewasm contract. See other notes for how to deploy it. Happy hacking! ## Advanced -The above guide is for compiling a single C file with no libc or system calls. Next we use a package which offers patches to libc and libc++ which allow using libc, including things like `malloc`, when targeting WebAssembly. It also allows using libc++. +The above guide is for compiling a C file with no libc. Next we use a package which provides a minimal toolchain which includes libc and libc++, as well as patches allowing things like `malloc`. ``` git clone https://github.com/yurydelendik/wasmception.git cd wasmception -make -j4 # Warning: this required lots of internet bandwidth, RAM, disk space, and one hour compiling on a mid-level laptop. +make # Warning: this required lots of internet bandwidth, RAM, disk space, and one hour compiling on a mid-level laptop. cd .. ``` Write down the end of the output of the above `make` command, it should include something like: `--sysroot=/home/user/repos/wasmception/sysroot`. -Next we will download and build a version of wrc20 which uses `malloc`. Make sure to edit the `Makefile` with the sysroot data above, and change the path to `clang` to our newly compiled version which may look something like `/home/user/repos/wasmception/dist/bin/clang`. Make sure that `main.syms` has a list of Ewasm helper functions you are using. +Next we will download and build a version of wrc20 which uses `malloc`. Make sure to edit the `Makefile` with the sysroot data above, and change the path of `clang` to our newly compiled version which may look something like `/home/user/repos/wasmception/dist/bin/clang`. Make sure that `main.syms` has a list of Ewasm helper functions you are using. Aside: If you are using C++, make sure to modify the Makefile to `clang++`, use `extern "C"` around the helper function declarations, and follow other tips from wasmception. @@ -106,6 +106,6 @@ cd cwrc20_with_malloc make ``` -Now follow the steps above to transform the output `main.wasm` into a valid Ewasm contract. +Now follow the same steps above to transform the output `main.wasm` into a valid Ewasm contract. -The user is encouraged to expore more advanced things. For example, to statically link against other C files, one can link the LLVM IR as described here https://aransentin.github.io/cwasm/. +Tutorials are needed for more advanced things. For example, to statically link against other C files, one can link the LLVM IR as described here https://aransentin.github.io/cwasm/. From 9585d5c251c9e0115babab4df38c7b8858a5ed18 Mon Sep 17 00:00:00 2001 From: Lane Rettig Date: Thu, 27 Dec 2018 07:04:49 -0500 Subject: [PATCH 12/20] Add link on non-determinism --- c_cpp_guide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/c_cpp_guide.md b/c_cpp_guide.md index daa20ef..2887eb0 100644 --- a/c_cpp_guide.md +++ b/c_cpp_guide.md @@ -4,7 +4,7 @@ First an introduction, then a basic step-by-step guide, then advanced things. Wa ## Introduction -An Ewasm contract is a WebAssembly module with the following restrictions. The module's imports must be among the [Ewasm helper functions](https://github.com/ewasm/design/blob/master/eth_interface.md) which resemble EVM opcodes to interact with the client. The module's exports must be a `main` function which takes no arguments and returns nothing, and the `memory` of the module. The module may not use floats or other sources of non-determinism. +An Ewasm contract is a WebAssembly module with the following restrictions. The module's imports must be among the [Ewasm helper functions](https://github.com/ewasm/design/blob/master/eth_interface.md) which resemble EVM opcodes to interact with the client. The module's exports must be a `main` function which takes no arguments and returns nothing, and the `memory` of the module. The module may not use floats or other [sources of non-determinism](https://github.com/WebAssembly/design/blob/master/Nondeterminism.md). Below are quirks to be aware of when writing Ewasm contracts in C/C++. These quirks are not limited to C/C++. Things may improve as tools and Ewasm improve. From 1e5ee1b061df758f7b1de7033d2305f82e815957 Mon Sep 17 00:00:00 2001 From: Lane Rettig Date: Thu, 27 Dec 2018 07:08:21 -0500 Subject: [PATCH 13/20] Minor tweaks Reformat into bulleted lists. Tweak some wording. --- c_cpp_guide.md | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/c_cpp_guide.md b/c_cpp_guide.md index 2887eb0..0642316 100644 --- a/c_cpp_guide.md +++ b/c_cpp_guide.md @@ -4,19 +4,23 @@ First an introduction, then a basic step-by-step guide, then advanced things. Wa ## Introduction -An Ewasm contract is a WebAssembly module with the following restrictions. The module's imports must be among the [Ewasm helper functions](https://github.com/ewasm/design/blob/master/eth_interface.md) which resemble EVM opcodes to interact with the client. The module's exports must be a `main` function which takes no arguments and returns nothing, and the `memory` of the module. The module may not use floats or other [sources of non-determinism](https://github.com/WebAssembly/design/blob/master/Nondeterminism.md). +An Ewasm contract is a WebAssembly module with the following restrictions: -Below are quirks to be aware of when writing Ewasm contracts in C/C++. These quirks are not limited to C/C++. Things may improve as tools and Ewasm improve. +- The module's imports must be among the [Ewasm helper functions](https://github.com/ewasm/design/blob/master/eth_interface.md) which resemble EVM opcodes to interact with the client. +- The module's exports must be a `main` function which takes no arguments and returns nothing, and the `memory` of the module. +- The module may not use floats or other [sources of non-determinism](https://github.com/WebAssembly/design/blob/master/Nondeterminism.md). -Quirk 1) WebAssembly is still primitive and lacks features. For example, WebAssembly lacks support for exceptions and we have no way to do system calls in Ewasm. Compilers and libraries are still primitive. For example, we have patched version of libc to allow `malloc`, but the patches are not yet enough for `std::vector` because other memory managment calls are unavailable. But perhaps any memory management beyond memory allocation may be unwanted for Ewasm contracts since it costs gas. This situation will improve as WebAssembly, compilers, and libraries mature. +When writing Ewasm contracts in C/C++, one should bear in mind the following caveats: -Quirk 2) In the current Ewasm design, all communication between the contract and the client is done through the module's memory. For example, the message data ("call data") sent to the contract is accessed by calling `callDataCopy()`, which puts this data to WebAssembly memory at a location given by a pointer. This pointer must be to either to a statically allocated array, or to dynamically allocated memory using `malloc`. For example, before calling `callDataCopy()`, one may use `getCallDataSize()` to see how many bytes of memory to `malloc`. +1. WebAssembly is still primitive and lacks features. For example, WebAssembly lacks support for exceptions and we have no way to do system calls in Ewasm. Compilers and libraries are still primitive. For example, we have a patched version of libc to allow `malloc`, but the patches are not yet enough for `std::vector` because other memory managment calls are unavailable. But perhaps any memory management beyond memory allocation may be unwanted for Ewasm contracts since it costs gas. This situation will improve as WebAssembly, compilers, and libraries mature. -Quirk 3) In the current Ewasm design, the Ethereum client writes data into WebAssembly as big-endian, but WebAssembly memory is little-endian, so has reversed bytes when the data is brought to/from the WebAssembly operand stack. For example, when the call data is brought into memory using `callDataCopy`, and those bytes are loaded to the WebAssembly stack using `i64.load`, all of the bytes are reversed. So extra C/C++ code may be needed to load bytes from the correct location and to reverse the loaded bytes. +1. In the current Ewasm design, all communication between the contract and the client is done through the module's memory. For example, the message data ("call data") sent to the contract is accessed by calling `callDataCopy()`, which puts this data to WebAssembly memory at a location given by a pointer. This pointer must be to either to a statically allocated array, or to dynamically allocated memory using `malloc`. For example, before calling `callDataCopy()`, one may use `getCallDataSize()` to see how many bytes of memory to `malloc`. -Quirk 4) The output of compilers is a `.wasm` binary which may have imports and exports which do not meet Ewasm requirements. We have tools to fix the imports and exports. +1. In the current Ewasm design, the Ethereum client writes data into WebAssembly as big-endian, but WebAssembly memory is little-endian, so has reversed bytes when the data is brought to/from the WebAssembly operand stack. For example, when the call data is brought into memory using `callDataCopy`, and those bytes are loaded to the WebAssembly stack using `i64.load`, all of the bytes are reversed. So extra C/C++ code may be needed to load bytes from the correct location and to reverse the loaded bytes. -Quirk 5) There are no tutorials for debugging/testing a contract. Hera supports extra Ewasm helper functions to print things, which have helped in writing test cases. A tutorial is needed to allow early adopters to debug/test their contracts without having to do it on the testnet. +1. The output of compilers is a `.wasm` binary which may have imports and exports which do not meet Ewasm requirements. We have tools to fix the imports and exports. + +1. There are no tutorials for debugging/testing a contract. Hera supports extra Ewasm helper functions to print things, which have helped in writing test cases. A tutorial is needed to allow early adopters to debug/test their contracts without having to do it on the testnet. ## Basic Step-by-Step Guide From 63d742ce95f6727ffc7aa02f861f416d89a31a61 Mon Sep 17 00:00:00 2001 From: Lane Rettig Date: Thu, 27 Dec 2018 07:14:02 -0500 Subject: [PATCH 14/20] Add link to future Wasm features --- c_cpp_guide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/c_cpp_guide.md b/c_cpp_guide.md index 0642316..366c7b3 100644 --- a/c_cpp_guide.md +++ b/c_cpp_guide.md @@ -12,7 +12,7 @@ An Ewasm contract is a WebAssembly module with the following restrictions: When writing Ewasm contracts in C/C++, one should bear in mind the following caveats: -1. WebAssembly is still primitive and lacks features. For example, WebAssembly lacks support for exceptions and we have no way to do system calls in Ewasm. Compilers and libraries are still primitive. For example, we have a patched version of libc to allow `malloc`, but the patches are not yet enough for `std::vector` because other memory managment calls are unavailable. But perhaps any memory management beyond memory allocation may be unwanted for Ewasm contracts since it costs gas. This situation will improve as WebAssembly, compilers, and libraries mature. +1. WebAssembly is still primitive and [lacks features](https://github.com/WebAssembly/design/blob/master/FutureFeatures.md). For example, WebAssembly lacks support for exceptions and we have no way to do system calls in Ewasm. Compilers and libraries are still primitive. For example, we have a patched version of libc to allow `malloc`, but the patches are not yet enough for `std::vector` because other memory managment calls are unavailable. But perhaps any memory management beyond memory allocation may be unwanted for Ewasm contracts since it costs gas. This situation will improve as WebAssembly, compilers, and libraries mature. 1. In the current Ewasm design, all communication between the contract and the client is done through the module's memory. For example, the message data ("call data") sent to the contract is accessed by calling `callDataCopy()`, which puts this data to WebAssembly memory at a location given by a pointer. This pointer must be to either to a statically allocated array, or to dynamically allocated memory using `malloc`. For example, before calling `callDataCopy()`, one may use `getCallDataSize()` to see how many bytes of memory to `malloc`. From 5c6a92b7ac8f8b032f619f8ad1d25649f59349f3 Mon Sep 17 00:00:00 2001 From: Lane Rettig Date: Thu, 27 Dec 2018 07:25:56 -0500 Subject: [PATCH 15/20] Add section header --- c_cpp_guide.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/c_cpp_guide.md b/c_cpp_guide.md index 366c7b3..e16601c 100644 --- a/c_cpp_guide.md +++ b/c_cpp_guide.md @@ -10,6 +10,8 @@ An Ewasm contract is a WebAssembly module with the following restrictions: - The module's exports must be a `main` function which takes no arguments and returns nothing, and the `memory` of the module. - The module may not use floats or other [sources of non-determinism](https://github.com/WebAssembly/design/blob/master/Nondeterminism.md). +## Caveats + When writing Ewasm contracts in C/C++, one should bear in mind the following caveats: 1. WebAssembly is still primitive and [lacks features](https://github.com/WebAssembly/design/blob/master/FutureFeatures.md). For example, WebAssembly lacks support for exceptions and we have no way to do system calls in Ewasm. Compilers and libraries are still primitive. For example, we have a patched version of libc to allow `malloc`, but the patches are not yet enough for `std::vector` because other memory managment calls are unavailable. But perhaps any memory management beyond memory allocation may be unwanted for Ewasm contracts since it costs gas. This situation will improve as WebAssembly, compilers, and libraries mature. From c6ca269b0b2b26ec117cef1ceabe44ec6c0f052d Mon Sep 17 00:00:00 2001 From: Lane Rettig Date: Thu, 27 Dec 2018 07:39:13 -0500 Subject: [PATCH 16/20] Misc cleanup Make some things clearer, and add a few more links for reference --- c_cpp_guide.md | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/c_cpp_guide.md b/c_cpp_guide.md index e16601c..b0fbd21 100644 --- a/c_cpp_guide.md +++ b/c_cpp_guide.md @@ -26,9 +26,7 @@ When writing Ewasm contracts in C/C++, one should bear in mind the following cav ## Basic Step-by-Step Guide -First build the latest version of LLVM. - -Aside: If you wish to use C/C++ standard libraries, then build the version of LLVM in the Advanced section below. That version can also be used here. +First let's build the latest version of LLVM. Note: this section of the document allows you to build LLVM without any standard libraries. If you wish to use C/C++ standard libraries, then build the version of LLVM in the Advanced section below. That version can also be used here. ```sh # checkout LLVM, clang, and lld @@ -43,23 +41,28 @@ mkdir llvm-build cd llvm-build # note: if you want other targets than WebAssembly, then delete -DLLVM_TARGETS_TO_BUILD= cmake -G "Unix Makefiles" -DLLVM_TARGETS_TO_BUILD= -DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD=WebAssembly ../llvm -make -j 8 # WARNING, THIS CAN TAKE HOURS, NEEDS LOTS OF DISK AND RAM, AND MAY CAUSE YOUR COMPUTER TO FREEZE. IF IT ERRORS, TRY AGAIN WITHOUT -j 8 +make -j 8 ``` -Next download and compile a wrc20 ewasm contract written in C. Note that in `main.c`, there are many arrays in global scope -- LLVM puts global arrays in WebAssembly memory, which is allows them to be used as pointer arguments to Ethereum helper functions. Before compiling, make sure that the `Makefile` has a path to `llvm-build` above, and that `main.syms` has a list of Ewasm helper functions you are using. +Warning: this `cmake` step can take hours, requires a lot of disk space and memory, and may cause your computer to freeze. If there is an error, try again without the `-j 8` argument (which attempts to run eight parallel build processes). -Aside: If you are using C++, make sure to modify the Makefile to `clang++`, use `extern "C"` around the helper function declarations. +Next download and compile a wrc20 ewasm contract written in C: ```sh git clone https://gist.github.com/poemm/68a7b70ec353abaeae64bf6fe95d2d52.git cwrc20 +``` + +Note that in `main.c`, there are many arrays in global scope: LLVM puts global arrays in WebAssembly memory, which allows them to be used as pointer arguments to Ethereum helper functions. Before compiling, make sure that the `Makefile` has a path to `llvm-build` above, and that `main.syms` has a list of Ewasm helper functions you are using. + +Aside: If you are using C++, make sure to modify the Makefile to `clang++`, use `extern "C"` around the helper function declarations. + +```sh cd cwrc20 # edit the Makefile and main.syms as described above make ``` -The output is `main.wasm` which needs a cleanup of imports and exports to meet Ewasm requirements. For this, we use PyWebAssembly. - -Aside: Alternatively, one can manually cleanup. Alternatively, one can use [wasm-chisel](https://github.com/wasmx/wasm-chisel), a program in Rust which can be installed with `cargo install chisel`. The Rust version is stricter and has more features, the Python version is just enough for our use-case, and Python is available on most machines. +The output is `main.wasm` which needs a cleanup of imports and exports to meet [Ewasm requirements](https://github.com/ewasm/design/blob/master/contract_interface.md). For this, we use [PyWebAssembly](https://github.com/poemm/pywebassembly), perform the cleanup manually, or use [wasm-chisel](https://github.com/wasmx/wasm-chisel), a program in Rust which can be installed with `cargo install chisel`. `wasm-chisel` is stricter and has more features, whereas `PyWebAssembly` is just enough for our use case, and Python is available on most machines. We therefore recommend using PyWebAssembly as follows: ``` cd .. @@ -69,7 +72,7 @@ python3 ewasmify.py ../../cwrc20/main.wasm cd ../../cwrc20 ``` -Check whether the command line output of `ewasmify.py` above lists only valid Ewasm imports and exports. To troubleshoot, you may wish to also inspect `main.wasm` in its text representation, so proceed to the next step with binaryen or wabt. +Check whether the command line output of `ewasmify.py` above lists only [valid Ewasm imports and exports](https://github.com/ewasm/design/blob/master/eth_interface.md). To troubleshoot, you may wish to also inspect `main.wasm` in its text representation, so proceed to the next step with binaryen or wabt. We can convert from the `.wasm` binary format to the `.wat` (or `.wast`) text format (these are equivalent formats and can be converted back-and-forth). This conversion can be done with Binaryen's `wasm-dis`. From 912f6ed284c59fb696c2831131bb9137e28217cb Mon Sep 17 00:00:00 2001 From: poemm <36397285+poemm@users.noreply.github.com> Date: Thu, 27 Dec 2018 12:08:15 -0600 Subject: [PATCH 17/20] C/C++ guide fixes for Lane's comments --- c_cpp_guide.md | 52 +++++++++++++++++++++----------------------------- 1 file changed, 22 insertions(+), 30 deletions(-) diff --git a/c_cpp_guide.md b/c_cpp_guide.md index b0fbd21..8792de6 100644 --- a/c_cpp_guide.md +++ b/c_cpp_guide.md @@ -1,68 +1,62 @@ # Compiling C/C++ to Ewasm -First an introduction, then a basic step-by-step guide, then advanced things. Warning: the Ewasm spec and tools below are subject to change. ## Introduction -An Ewasm contract is a WebAssembly module with the following restrictions: - -- The module's imports must be among the [Ewasm helper functions](https://github.com/ewasm/design/blob/master/eth_interface.md) which resemble EVM opcodes to interact with the client. -- The module's exports must be a `main` function which takes no arguments and returns nothing, and the `memory` of the module. -- The module may not use floats or other [sources of non-determinism](https://github.com/WebAssembly/design/blob/master/Nondeterminism.md). +The goal of this document is to provide a guide to compile C/C++ to Ewasm. This document assumes knowledge of the [Ewasm design repo](https://github.com/ewasm/design). Especially relevant is that an Ewasm contract is a WebAssembly module with [restrictions](https://github.com/ewasm/design/blob/master/contract_interface.md), and that an Ewasm contract can call [Ewasm helper functions](https://github.com/ewasm/design/blob/master/eth_interface.md), which resemble EVM opcodes. ## Caveats -When writing Ewasm contracts in C/C++, one should bear in mind the following caveats: +When writing Ewasm contracts in C/C++, one should bear in mind the following caveats. + +1. WebAssembly is still primitive and [lacks features](https://github.com/WebAssembly/design/blob/master/FutureFeatures.md). For example, WebAssembly lacks support for exceptions. Also, compilers and standard libraries support is still primitive, often existing as experimental features or third party patches. -1. WebAssembly is still primitive and [lacks features](https://github.com/WebAssembly/design/blob/master/FutureFeatures.md). For example, WebAssembly lacks support for exceptions and we have no way to do system calls in Ewasm. Compilers and libraries are still primitive. For example, we have a patched version of libc to allow `malloc`, but the patches are not yet enough for `std::vector` because other memory managment calls are unavailable. But perhaps any memory management beyond memory allocation may be unwanted for Ewasm contracts since it costs gas. This situation will improve as WebAssembly, compilers, and libraries mature. +1. Ewasm does not support operating system calls, for example `printf()` and `clock()` are unsupported. This is especially relevant for contracts which require memory management -- we patch libc with a WebAssembly-compatible version of `malloc` which we compile into the module. But the patches are not yet enough for `std::vector` because it requries other memory managment calls which are not yet patched. -1. In the current Ewasm design, all communication between the contract and the client is done through the module's memory. For example, the message data ("call data") sent to the contract is accessed by calling `callDataCopy()`, which puts this data to WebAssembly memory at a location given by a pointer. This pointer must be to either to a statically allocated array, or to dynamically allocated memory using `malloc`. For example, before calling `callDataCopy()`, one may use `getCallDataSize()` to see how many bytes of memory to `malloc`. +1. [Ewasm helper functions](https://github.com/ewasm/design/blob/master/eth_interface.md) communicate with the contract by reading/writing to/from the WebAssembly module's memory at locations provided by a C/C++ pointer. For example, this C/C++ pointer can point to a statically allocated array in global scope (since our LLVM compiler maps C/C++ global arrays to WebAssembly memory), or to dynamically allocated memory using `malloc`. To conserve gas, it may be wise to avoid `malloc` whenever possible. -1. In the current Ewasm design, the Ethereum client writes data into WebAssembly as big-endian, but WebAssembly memory is little-endian, so has reversed bytes when the data is brought to/from the WebAssembly operand stack. For example, when the call data is brought into memory using `callDataCopy`, and those bytes are loaded to the WebAssembly stack using `i64.load`, all of the bytes are reversed. So extra C/C++ code may be needed to load bytes from the correct location and to reverse the loaded bytes. +1. Ethereum clients read/write data into WebAssembly memory as big-endian, but WebAssembly memory is little-endian, so bytes are reversed when brought to/from the WebAssembly operand stack. For example, when the call data is brought into memory using Ewasm helper function `callDataCopy`, and those bytes are loaded to the WebAssembly stack using `i64.load`, all of the bytes are reversed. So extra C/C++ code may be needed to to reverse the loaded bytes. -1. The output of compilers is a `.wasm` binary which may have imports and exports which do not meet Ewasm requirements. We have tools to fix the imports and exports. +1. The output of compilers is a `.wasm` binary which may not meet [Ewasm requirements](https://github.com/ewasm/design/blob/master/contract_interface.md). In the examples below, we use tools which automatically apply changes to meet these requirmentes. When writing more complicated contracts, manual inspection and troubleshooting may be required. -1. There are no tutorials for debugging/testing a contract. Hera supports extra Ewasm helper functions to print things, which have helped in writing test cases. A tutorial is needed to allow early adopters to debug/test their contracts without having to do it on the testnet. +1. Tools are needed for developers to debug/test their Ewasm contracts. Early adopters may debug/test on the testnet by printing things to storage. ## Basic Step-by-Step Guide -First let's build the latest version of LLVM. Note: this section of the document allows you to build LLVM without any standard libraries. If you wish to use C/C++ standard libraries, then build the version of LLVM in the Advanced section below. That version can also be used here. +First build the latest version of LLVM, clang, and lld. Below we devaite from the [official instructions](https://clang.llvm.org/get_started.html) by using git and adding some flags to `cmake`. + +Aside: If you wish to use C/C++ standard libraries, then build the version of LLVM in the Advanced section below. That version can also be used here. + +Aside: The following dowloads hundreds of megabytes. The `make` step can take hours, require a lot of disk space and memory, and may even cause your computer to freeze. If there is an out-of-memory error, try again without the `-j 8` argument (which attempts to run eight parallel build processes). ```sh # checkout LLVM, clang, and lld -svn co http://llvm.org/svn/llvm-project/llvm/trunk llvm +git clone http://llvm.org/git/llvm.git cd llvm/tools -svn co http://llvm.org/svn/llvm-project/cfe/trunk clang -svn co http://llvm.org/svn/llvm-project/lld/trunk lld +git clone http://llvm.org/git/clang.git +git clone http://llvm.org/git/lld.git cd ../.. # build LLVM, clang, and lld mkdir llvm-build cd llvm-build -# note: if you want other targets than WebAssembly, then delete -DLLVM_TARGETS_TO_BUILD= cmake -G "Unix Makefiles" -DLLVM_TARGETS_TO_BUILD= -DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD=WebAssembly ../llvm make -j 8 ``` -Warning: this `cmake` step can take hours, requires a lot of disk space and memory, and may cause your computer to freeze. If there is an error, try again without the `-j 8` argument (which attempts to run eight parallel build processes). -Next download and compile a wrc20 ewasm contract written in C: - -```sh -git clone https://gist.github.com/poemm/68a7b70ec353abaeae64bf6fe95d2d52.git cwrc20 -``` - -Note that in `main.c`, there are many arrays in global scope: LLVM puts global arrays in WebAssembly memory, which allows them to be used as pointer arguments to Ethereum helper functions. Before compiling, make sure that the `Makefile` has a path to `llvm-build` above, and that `main.syms` has a list of Ewasm helper functions you are using. +Next download and compile an example ewasm contract written in C. Note that in `main.c`, there are many arrays in global scope: LLVM puts global arrays in WebAssembly memory, which allows them to be used as pointer arguments to Ethereum helper functions. Before compiling, make sure that the `Makefile` has a path to `llvm-build` above, and that `main.syms` has a list of Ewasm helper functions you are using. Aside: If you are using C++, make sure to modify the Makefile to `clang++`, use `extern "C"` around the helper function declarations. ```sh +git clone https://gist.github.com/poemm/68a7b70ec353abaeae64bf6fe95d2d52.git cwrc20 cd cwrc20 # edit the Makefile and main.syms as described above make ``` -The output is `main.wasm` which needs a cleanup of imports and exports to meet [Ewasm requirements](https://github.com/ewasm/design/blob/master/contract_interface.md). For this, we use [PyWebAssembly](https://github.com/poemm/pywebassembly), perform the cleanup manually, or use [wasm-chisel](https://github.com/wasmx/wasm-chisel), a program in Rust which can be installed with `cargo install chisel`. `wasm-chisel` is stricter and has more features, whereas `PyWebAssembly` is just enough for our use case, and Python is available on most machines. We therefore recommend using PyWebAssembly as follows: +The output is `main.wasm` which needs a cleanup of imports and exports to meet [Ewasm requirements](https://github.com/ewasm/design/blob/master/contract_interface.md). For this, we can use [PyWebAssembly](https://github.com/poemm/pywebassembly), perform the cleanup manually, or use [wasm-chisel](https://github.com/wasmx/wasm-chisel), a program in Rust which can be installed with `cargo install chisel`. `wasm-chisel` is stricter and has more features, whereas `PyWebAssembly` is just enough for our use case, and Python is available on most machines. We therefore recommend using PyWebAssembly as follows. ``` cd .. @@ -72,9 +66,7 @@ python3 ewasmify.py ../../cwrc20/main.wasm cd ../../cwrc20 ``` -Check whether the command line output of `ewasmify.py` above lists only [valid Ewasm imports and exports](https://github.com/ewasm/design/blob/master/eth_interface.md). To troubleshoot, you may wish to also inspect `main.wasm` in its text representation, so proceed to the next step with binaryen or wabt. - -We can convert from the `.wasm` binary format to the `.wat` (or `.wast`) text format (these are equivalent formats and can be converted back-and-forth). This conversion can be done with Binaryen's `wasm-dis`. +The output `main_ewasmified.wasm` should be a valid Ewasm contract. But it should be inspected to make sure that the imports and exports meet [Ewasm requirements](https://github.com/ewasm/design/blob/master/contract_interface.md). We do this inspection by first converting from the `.wasm` binary format to the `.wat` text format (these are equivalent formats and can be converted back-and-forth). This conversion can be done with Binaryen's `wasm-dis`. Aside: Alternatively one can use Wabt's `wasm2wat`. But Binaryen's `wasm-dis` is recommended because Ewasm studio uses Binaryen internally, and Binaryen can be quirky and fail to read a `.wat` generated by another program. Another tip: if Binaryen's `wasm-dis` can't read the `.wasm`, try using Wabt's `wasm2wat` then `wat2wasm` before trying again with Binaryen. @@ -89,7 +81,7 @@ cd ../../cwrc20 ../binaryen/build/bin/wasm-dis main_ewasmified.wasm > main_ewasmified.wat ``` -`main_ewasmified.wat` is an ewasm contract. See other notes for how to deploy it. Happy hacking! +`main_ewasmified.wat` is an ewasm contract in text format. See other notes for how to deploy it. Happy hacking! ## Advanced From 3ae267829ef717a23831715e7cb909f4852035b3 Mon Sep 17 00:00:00 2001 From: poemm <36397285+poemm@users.noreply.github.com> Date: Thu, 27 Dec 2018 12:21:16 -0600 Subject: [PATCH 18/20] C/C++ Guide spellcheck --- c_cpp_guide.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/c_cpp_guide.md b/c_cpp_guide.md index 8792de6..ef7351e 100644 --- a/c_cpp_guide.md +++ b/c_cpp_guide.md @@ -11,23 +11,23 @@ When writing Ewasm contracts in C/C++, one should bear in mind the following cav 1. WebAssembly is still primitive and [lacks features](https://github.com/WebAssembly/design/blob/master/FutureFeatures.md). For example, WebAssembly lacks support for exceptions. Also, compilers and standard libraries support is still primitive, often existing as experimental features or third party patches. -1. Ewasm does not support operating system calls, for example `printf()` and `clock()` are unsupported. This is especially relevant for contracts which require memory management -- we patch libc with a WebAssembly-compatible version of `malloc` which we compile into the module. But the patches are not yet enough for `std::vector` because it requries other memory managment calls which are not yet patched. +1. Ewasm does not support operating system calls, for example `printf()` and `clock()` are unsupported. This is especially relevant for contracts which require memory management -- we patch libc with a WebAssembly-compatible version of `malloc` which we compile into the module. But the patches are not yet enough for `std::vector` because it requires other memory management calls which are not yet patched. 1. [Ewasm helper functions](https://github.com/ewasm/design/blob/master/eth_interface.md) communicate with the contract by reading/writing to/from the WebAssembly module's memory at locations provided by a C/C++ pointer. For example, this C/C++ pointer can point to a statically allocated array in global scope (since our LLVM compiler maps C/C++ global arrays to WebAssembly memory), or to dynamically allocated memory using `malloc`. To conserve gas, it may be wise to avoid `malloc` whenever possible. 1. Ethereum clients read/write data into WebAssembly memory as big-endian, but WebAssembly memory is little-endian, so bytes are reversed when brought to/from the WebAssembly operand stack. For example, when the call data is brought into memory using Ewasm helper function `callDataCopy`, and those bytes are loaded to the WebAssembly stack using `i64.load`, all of the bytes are reversed. So extra C/C++ code may be needed to to reverse the loaded bytes. -1. The output of compilers is a `.wasm` binary which may not meet [Ewasm requirements](https://github.com/ewasm/design/blob/master/contract_interface.md). In the examples below, we use tools which automatically apply changes to meet these requirmentes. When writing more complicated contracts, manual inspection and troubleshooting may be required. +1. The output of compilers is a `.wasm` binary which may not meet [Ewasm requirements](https://github.com/ewasm/design/blob/master/contract_interface.md). In the examples below, we use tools which automatically apply changes to meet these requirements. When writing more complicated contracts, manual inspection and troubleshooting may be required. 1. Tools are needed for developers to debug/test their Ewasm contracts. Early adopters may debug/test on the testnet by printing things to storage. ## Basic Step-by-Step Guide -First build the latest version of LLVM, clang, and lld. Below we devaite from the [official instructions](https://clang.llvm.org/get_started.html) by using git and adding some flags to `cmake`. +First build the latest version of LLVM, clang, and lld. Below we deviate from the [official instructions](https://clang.llvm.org/get_started.html) by using git and adding some flags to `cmake`. Aside: If you wish to use C/C++ standard libraries, then build the version of LLVM in the Advanced section below. That version can also be used here. -Aside: The following dowloads hundreds of megabytes. The `make` step can take hours, require a lot of disk space and memory, and may even cause your computer to freeze. If there is an out-of-memory error, try again without the `-j 8` argument (which attempts to run eight parallel build processes). +Aside: The following downloads hundreds of megabytes. The `make` step can take hours, require a lot of disk space and memory, and may even cause your computer to freeze. If there is an out-of-memory error, try again without the `-j 8` argument (which attempts to run eight parallel build processes). ```sh # checkout LLVM, clang, and lld From 4dab4157fc8a009136992db0418b6363f521a0a3 Mon Sep 17 00:00:00 2001 From: poemm <36397285+poemm@users.noreply.github.com> Date: Fri, 28 Dec 2018 16:21:48 -0600 Subject: [PATCH 19/20] C/C++ guide add C++ example --- c_cpp_guide.md | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/c_cpp_guide.md b/c_cpp_guide.md index ef7351e..c097c44 100644 --- a/c_cpp_guide.md +++ b/c_cpp_guide.md @@ -45,14 +45,13 @@ make -j 8 ``` -Next download and compile an example ewasm contract written in C. Note that in `main.c`, there are many arrays in global scope: LLVM puts global arrays in WebAssembly memory, which allows them to be used as pointer arguments to Ethereum helper functions. Before compiling, make sure that the `Makefile` has a path to `llvm-build` above, and that `main.syms` has a list of Ewasm helper functions you are using. +Next download and compile an example ewasm contract written in C. Note that in `main.c`, there are many arrays in global scope: LLVM puts global arrays in WebAssembly memory, which allows them to be used as pointer arguments to Ethereum helper functions. Before compiling, make sure that the `Makefile` has the correct path to `llvm-build` above, and that `main.syms` has a list of Ewasm helper functions you are using. -Aside: If you are using C++, make sure to modify the Makefile to `clang++`, use `extern "C"` around the helper function declarations. +Aside: A similar C++ example is found here https://gist.github.com/poemm/5dda50f354e06371fd0e7cef2271c6b0.git . ```sh git clone https://gist.github.com/poemm/68a7b70ec353abaeae64bf6fe95d2d52.git cwrc20 cd cwrc20 -# edit the Makefile and main.syms as described above make ``` @@ -98,8 +97,6 @@ Write down the end of the output of the above `make` command, it should include Next we will download and build a version of wrc20 which uses `malloc`. Make sure to edit the `Makefile` with the sysroot data above, and change the path of `clang` to our newly compiled version which may look something like `/home/user/repos/wasmception/dist/bin/clang`. Make sure that `main.syms` has a list of Ewasm helper functions you are using. -Aside: If you are using C++, make sure to modify the Makefile to `clang++`, use `extern "C"` around the helper function declarations, and follow other tips from wasmception. - ```sh git clone https://gist.github.com/poemm/91b64ecd2ca2f1cb4a88d31315313b9b.git cwrc20_with_malloc cd cwrc20_with_malloc From e86d665364adfde7232feaaae178c31543734ff2 Mon Sep 17 00:00:00 2001 From: poemm <36397285+poemm@users.noreply.github.com> Date: Thu, 3 Jan 2019 07:14:34 -0600 Subject: [PATCH 20/20] C/C++ Guide get llvm 7 from repositories --- c_cpp_guide.md | 45 ++++++++++++++++++++++----------------------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/c_cpp_guide.md b/c_cpp_guide.md index c097c44..d0f5514 100644 --- a/c_cpp_guide.md +++ b/c_cpp_guide.md @@ -5,9 +5,9 @@ The goal of this document is to provide a guide to compile C/C++ to Ewasm. This document assumes knowledge of the [Ewasm design repo](https://github.com/ewasm/design). Especially relevant is that an Ewasm contract is a WebAssembly module with [restrictions](https://github.com/ewasm/design/blob/master/contract_interface.md), and that an Ewasm contract can call [Ewasm helper functions](https://github.com/ewasm/design/blob/master/eth_interface.md), which resemble EVM opcodes. -## Caveats +## Subtleties -When writing Ewasm contracts in C/C++, one should bear in mind the following caveats. +When writing Ewasm contracts in C/C++, one should bear in mind the following. 1. WebAssembly is still primitive and [lacks features](https://github.com/WebAssembly/design/blob/master/FutureFeatures.md). For example, WebAssembly lacks support for exceptions. Also, compilers and standard libraries support is still primitive, often existing as experimental features or third party patches. @@ -23,36 +23,28 @@ When writing Ewasm contracts in C/C++, one should bear in mind the following cav ## Basic Step-by-Step Guide -First build the latest version of LLVM, clang, and lld. Below we deviate from the [official instructions](https://clang.llvm.org/get_started.html) by using git and adding some flags to `cmake`. +LLVM will be used to compile `.c`/`.cpp` to `.wasm`. First install LLVM 7 or newer. (Older LLVM versions have only experimental WebAssembly support.) -Aside: If you wish to use C/C++ standard libraries, then build the version of LLVM in the Advanced section below. That version can also be used here. +Aside: If you wish to use C/C++ standard libraries, then you need the version of LLVM in the Advanced section below -- that version can also be used here. -Aside: The following downloads hundreds of megabytes. The `make` step can take hours, require a lot of disk space and memory, and may even cause your computer to freeze. If there is an out-of-memory error, try again without the `-j 8` argument (which attempts to run eight parallel build processes). - -```sh -# checkout LLVM, clang, and lld -git clone http://llvm.org/git/llvm.git -cd llvm/tools -git clone http://llvm.org/git/clang.git -git clone http://llvm.org/git/lld.git -cd ../.. - -# build LLVM, clang, and lld -mkdir llvm-build -cd llvm-build -cmake -G "Unix Makefiles" -DLLVM_TARGETS_TO_BUILD= -DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD=WebAssembly ../llvm -make -j 8 -``` +Aside: If you don't have access to a repository with LLVM 7, then follow the [official instructions](https://clang.llvm.org/get_started.html) to compile llvm, clang, and lld. +```sh +apt-get install clang-7 lld-7 # Available in Ubuntu 18.10 or later. LLVM 7 is also available in Fedora 29 and Debian Sid repositories. +``` -Next download and compile an example ewasm contract written in C. Note that in `main.c`, there are many arrays in global scope: LLVM puts global arrays in WebAssembly memory, which allows them to be used as pointer arguments to Ethereum helper functions. Before compiling, make sure that the `Makefile` has the correct path to `llvm-build` above, and that `main.syms` has a list of Ewasm helper functions you are using. +Next download and compile the example ewasm contract written in C. Note that in `main.c`, there are many arrays in global scope: LLVM puts global arrays in WebAssembly memory, which allows them to be used as pointer arguments to Ethereum helper functions. `main.syms` has a list of Ewasm helper functions which you are using. The `Makefile` is optional, we copy/paste build commands below. Aside: A similar C++ example is found here https://gist.github.com/poemm/5dda50f354e06371fd0e7cef2271c6b0.git . +Aside: There may be errors if you are not using LLVM 7 or greater. Check with `clang --version`, `llc --version`, and `wasm-ld --version`. + ```sh git clone https://gist.github.com/poemm/68a7b70ec353abaeae64bf6fe95d2d52.git cwrc20 cd cwrc20 -make +clang -cc1 -Ofast -emit-llvm -triple=wasm32-unknown-unknown-wasm main.c +llc -O3 -filetype=obj main.ll -o main.o +wasm-ld --no-entry main.o -o main.wasm --strip-all -allow-undefined-file=main.syms -export=_main ``` The output is `main.wasm` which needs a cleanup of imports and exports to meet [Ewasm requirements](https://github.com/ewasm/design/blob/master/contract_interface.md). For this, we can use [PyWebAssembly](https://github.com/poemm/pywebassembly), perform the cleanup manually, or use [wasm-chisel](https://github.com/wasmx/wasm-chisel), a program in Rust which can be installed with `cargo install chisel`. `wasm-chisel` is stricter and has more features, whereas `PyWebAssembly` is just enough for our use case, and Python is available on most machines. We therefore recommend using PyWebAssembly as follows. @@ -85,14 +77,19 @@ cd ../../cwrc20 ## Advanced +#### Using C/C++ Standard Libraries + The above guide is for compiling a C file with no libc. Next we use a package which provides a minimal toolchain which includes libc and libc++, as well as patches allowing things like `malloc`. +Aside: To see how minimal it is, see the `Makefile` for wasmception. It just downloads LLVM, musl libc, and libc++, patches things, and builds with certain flags. + ``` git clone https://github.com/yurydelendik/wasmception.git cd wasmception make # Warning: this required lots of internet bandwidth, RAM, disk space, and one hour compiling on a mid-level laptop. cd .. ``` + Write down the end of the output of the above `make` command, it should include something like: `--sysroot=/home/user/repos/wasmception/sysroot`. Next we will download and build a version of wrc20 which uses `malloc`. Make sure to edit the `Makefile` with the sysroot data above, and change the path of `clang` to our newly compiled version which may look something like `/home/user/repos/wasmception/dist/bin/clang`. Make sure that `main.syms` has a list of Ewasm helper functions you are using. @@ -106,4 +103,6 @@ make Now follow the same steps above to transform the output `main.wasm` into a valid Ewasm contract. -Tutorials are needed for more advanced things. For example, to statically link against other C files, one can link the LLVM IR as described here https://aransentin.github.io/cwasm/. +#### Compiling a Library and Statically Linking Against It + +Ways to statically link a `.wasm` file against another `.wasm` file is under development, see https://github.com/WebAssembly/tool-conventions/blob/master/Linking.md . Static linking can be done on LLVM IR as described here https://aransentin.github.io/cwasm/ .