Enable AoT and wamr-sdk, and change arguments of call wasm API (#157)

* Implement memory profiler, optimize memory usage, modify code indent

* Implement memory.grow and limit heap space base offset to 1G; modify iwasm build type to Release and 64 bit by default

* Add a new extension library: connection

* Fix bug of reading magic number and version in big endian platform

* Re-org platform APIs: move most platform APIs from iwasm to shared-lib

* Enhance wasm loader to fix some security issues

* Fix issue about illegal load of EXC_RETURN into PC on stm32 board

* Updates that let a restricted version of the interpreter run in SGX

* Enable native/app address validation and conversion for wasm app

* Remove wasm_application_exectue_* APIs from wasm_export.h which makes confused

* Refine binary size and fix several minor issues

Optimize interpreter LOAD/STORE opcodes to decrease the binary size
Fix issues when using iwasm library: _bh_log undefined, bh_memory.h not found
Remove unused _stdin/_stdout/_stderr global variables resolve in libc wrapper
Add macros of global heap size, stack size, heap size for Zephyr main.c
Clear compile warning of wasm_application.c

* Add more strict security checks for libc wrapper API's

* Use one libc wrapper copy for sgx and other platforms; remove bh_printf macro for other platform header files

* Enhance security of libc strcpy/sprintf wrapper function

* Fix issue of call native for x86_64/arm/mips, add module inst parameter for native wrapper functions

* Remove get_module_inst() and fix issue of call native

* Refine wgl lib: remove module_inst parameter from widget functions; move function index check to runtime instantiate

* Refine interpreter call native process, refine memory boudary check

* Fix issues of invokeNative function of arm/mips/general version

* Add a switch to build simple sample without gui support

* Add BUILD_TARGET setting in makefile to replace cpu compiler flags in source code

* Re-org shared lib header files, remove unused info; fix compile issues of vxworks

* Add build target general

* Remove unused files

* Update license header

* test push

* Restore file

* Sync up with internal/feature

* Sync up with internal/feature

* Rename build_wamr_app to build_wasm_app

* Fix small issues of README

* Enhance malformed wasm file checking
Fix issue of print hex int and implement utf8 string check
Fix wasi file read/write right issue
Fix minor issue of build wasm app doc

* Sync up with internal/feature

* Sync up with internal/feature: fix interpreter arm issue, fix read leb issue

* Sync up with internal/feature

* Fix bug of config.h and rename wasi config.h to ssp_config.h

* Sync up with internal/feature

* Import wamr aot

* update document

* update document

* Update document, disable WASI in 32bit

* update document

* remove files

* update document

* Update document

* update document

* update document

* update samples

* Sync up with internal repo
This commit is contained in:
wenyongh
2020-01-21 13:26:14 +08:00
committed by Wang Xin
parent 2a4528c749
commit 46b93b9d22
464 changed files with 25137 additions and 7911 deletions

View File

@ -1,14 +1,18 @@
Build WAMR Core
Build WAMR core (iwasm)
=========================
Please follow the instructions below to build the WAMR core on different platforms.
Please follow the instructions below to build the WAMR VM core on different platforms.
Linux
-------------------------
First of all please install library dependencies of lib gcc.
Use installation commands below for Ubuntu Linux:
First of all please install the dependent packages.
Run command below in Ubuntu-18.04:
``` Bash
sudo apt install lib32gcc-5-dev g++-multilib
sudo apt install build-essential cmake g++-multilib libgcc-8-dev lib32gcc-8-dev
```
Or in Ubuntu-16.04:
``` Bash
sudo apt install build-essential cmake g++-multilib libgcc-5-dev lib32gcc-5-dev
```
Or in Fedora:
``` Bash
@ -17,32 +21,60 @@ sudo dnf install glibc-devel.i686
After installing dependencies, build the source code:
``` Bash
cd core/iwasm/products/linux/
cd product-mini/platforms/linux/
mkdir build
cd build
cmake ..
make
```
The binary file iwasm will be generated under build folder.
Note:
The WASI feature is enabled by default, if we want to disable it, please run:
WAMR provides some features which can be easily configured by passing options to cmake:
``` Bash
cmake .. -DWASM_ENABLE_WASI=0
cmake -DWAMR_BUILD_INTERP=1/0 to enable or disable WASM intepreter
cmake -DWAMR_BUILD_AOT=1/0 to enable or disable WASM AOT
cmake -DWAMR_BUILD_JIT=1/0 to enable or disable WASM JIT
cmake -DWAMR_BUILD_LIBC_BUILTIN=1/0 enable or disable Libc builtin API's
cmake -DWAMR_BUILD_LIBC_WASI=1/0 enable or disable Libc WASI API's
cmake -DWAMR_BUILD_TARGET=<arch><sub> to set the building target, including:
X86_64, X86_32, ARM, THUMB, XTENSA and MIPS
for ARM and THUMB, we can specify the <sub> info, e.g. ARMV4, ARMV4T, ARMV5, ARMV5T, THUMBV4T, THUMBV5T and so on.
```
For example, if we want to disable interpreter, enable AOT and WASI, we can:
``` Bash
cmake .. -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_AOT=1 -DWAMR_BUILD_LIBC_WASI=0
```
Or if we want to enable inerpreter, disable AOT and WASI, and build as X86_32, we can:
``` Bash
cmake .. -DWAMR_BUILD_INTERP=1 -DWAMR_BUILD_AOT=0 -DWAMR_BUILD_LIBC_WASI=0 -DWAMR_BUILD_TARGET=X86_32
```
By default in Linux, the interpreter, AOT and WASI are enabled, and JIT is disabled. And the build target is
set to X86_64 or X86_32 depending on the platform's bitwidth.
To enable WASM JIT, firstly we should build LLVM:
``` Bash
cd product-mini/platforms/linux/
./build_llvm.sh (The llvm source code is cloned under <wamr_root_dir>/core/deps/llvm and auto built)
```
Then pass option -DWAMR_BUILD_JIT=1 to cmake to enable WASM JIT:
``` Bash
mkdir build
cd build
cmake .. -DWAMR_BUILD_JIT=1
make
```
Linux SGX (Intel Software Guard Extention)
-------------------------
First of all please install library dependencies of lib gcc.
Use installation commands below for Ubuntu Linux:
``` Bash
sudo apt install lib32gcc-5-dev g++-multilib
```
And then install the [Intel SGX SDK](https://software.intel.com/en-us/sgx/sdk).
First of all please install the [Intel SGX SDK](https://software.intel.com/en-us/sgx/sdk).
After installing dependencies, build the source code:
``` Bash
source <SGX_SDK dir>/environment
cd core/iwasm/products/linux-sgx/
cd product-mini/platforms/linux-sgx/
mkdir build
cd build
cmake ..
@ -64,7 +96,7 @@ source <SGX_SDK dir>/environment
./app
```
Mac
MacOS
-------------------------
Make sure to install Xcode from App Store firstly, and install cmake.
@ -75,12 +107,14 @@ brew install cmake
Then build the source codes:
```
cd core/iwasm/products/darwin/
cd product-mini/platforms/darwin/
mkdir build
cd build
cmake ..
make
```
Note:
WAMR provides some features which can be easily configured by passing options to cmake, please see [Linux platform](./build_wamr.md#linux) for details. Currently in MacOS, interpreter, AoT, and builtin libc are enabled by default.
VxWorks
-------------------------
@ -93,7 +127,7 @@ export <vsb_dir_path>/host/vx-compiler/bin:$PATH
```
Now switch to iwasm source tree to build the source code:
```
cd core/iwasm/products/vxworks/
cd product-mini/platforms/vxworks/
mkdir build
cd build
cmake ..
@ -109,13 +143,8 @@ Copy the generated iwasm executable, the test WASM binary as well as the needed
shared libraries (libc.so.1, libllvm.so.1 or libgnu.so.1 depending on the VSB,
libunix.so.1) to a supported file system (eg: romfs).
WASI
-------------------------
On Linux, WASI is enabled by default. To build iwasm without wasi support, pass an option when you run cmake:
```
cmake .. -DWASM_ENABLE_WASI=0
make
```
Note:
WAMR provides some features which can be easily configured by passing options to cmake, please see [Linux platform](./build_wamr.md#linux) for details. Currently in VxWorks, interpreter and builtin libc are enabled by default.
Zephyr
-------------------------
@ -123,15 +152,17 @@ You need to download the Zephyr source code first and embed WAMR into it.
``` Bash
git clone https://github.com/zephyrproject-rtos/zephyr.git
cd zephyr/samples/
cp -a <iwasm_dir>/products/zephyr/simple .
cp -a <wamr_root_dir>/product-mini/platforms/zephyr/simple .
cd simple
ln -s <iwam_dir> iwasm
ln -s <shared_lib_dir> shared-lib
ln -s <wamr_root_dir> wamr
mkdir build && cd build
source ../../../zephyr-env.sh
cmake -GNinja -DBOARD=qemu_x86 ..
cmake -GNinja -DBOARD=qemu_x86_nommu ..
ninja
```
Note:
WAMR provides some features which can be easily configured by passing options to cmake, please see [Linux platform](./build_wamr.md#linux) for details. Currently in Zephyr, interpreter, AoT and builtin libc are enabled by default.
AliOS-Things
-------------------------
@ -140,19 +171,15 @@ AliOS-Things
``` Bash
git clone https://github.com/alibaba/AliOS-Things.git
```
3. copy <iwasm_root_dir>/products/alios-things directory to AliOS-Things/middleware, and rename it as iwasm
3. copy <wamr_root_dir>/product-mini/platforms/alios-things directory to AliOS-Things/middleware, and rename it as iwasm
``` Bash
cp -a <iwasm_root_dir>/products/alios-things middleware/iwasm
cp -a <wamr_root_dir>/product-mini/platforms/alios-things middleware/iwasm
```
4. create a link to <iwasm_root_dir> in middleware/iwasm/ and rename it to iwasm
4. create a link to <wamr_root_dir> in middleware/iwasm/ and rename it to wamr
``` Bash
ln -s <iwasm_root_dir> middleware/iwasm/iwasm
ln -s <wamr_root_dir> middleware/iwasm/wamr
```
5. create a link to <shared-lib_root_dir> in middleware/iwasm/ and rename it to shared-lib
``` Bash
ln -s <shared-lib_root_dir> middleware/iwasm/shared-lib
```
6. modify file app/example/helloworld/helloworld.c, patch as:
5. modify file app/example/helloworld/helloworld.c, patch as:
``` C
#include <stdbool.h>
#include <aos/kernel.h>
@ -164,11 +191,11 @@ AliOS-Things
...
}
```
7. modify file app/example/helloworld/aos.mk
6. modify file app/example/helloworld/aos.mk
``` C
$(NAME)_COMPONENTS := osal_aos iwasm
```
8. build source code and run
7. build source code and run
For linuxhost:
``` Bash
aos make helloworld@linuxhost -c config
@ -179,7 +206,7 @@ AliOS-Things
For developerkit:
Modify file middleware/iwasm/aos.mk, patch as:
``` C
BUILD_TARGET := THUMBV7M
WAMR_BUILD_TARGET := THUMBV7M
```
``` Bash

View File

@ -1,10 +1,18 @@
Build WASM app
# Prepare WASM building environments
WASI-SDK version 7.0+ is the major tool supported by WAMR for building WASM applications. There are some other WASM compilers such as the standard clang compiler and Emscripten might also work [here](./other_wasm_compilers.md).
Install WASI SDK: Download the [wasi-sdk](https://github.com/CraneStation/wasi-sdk/releases) and extract the archive to default path `/opt/wasi-sdk`
Build WASM applications
=========================
You can write a simple ```test.c``` as the first sample.
```C
``` C
#include <stdio.h>
#include <stdlib.h>
@ -30,146 +38,89 @@ int main(int argc, char **argv)
}
```
There are several methods to build a WASM binary. They are the clang compiler, Docker, Emscripten and so on.
## Use clang compiler
The recommended method to build a WASM binary is to use clang compiler ```clang-8```. You can refer to [apt.llvm.org](https://apt.llvm.org) for the detailed instructions. Here are referenced steps to install clang-8 in Ubuntu 16.04 and Ubuntu 18.04.
To build the source file to WASM bytecode, input following command:
(1) Add source to your system source list from llvm website
For Ubuntu 16.04, add the following lines to /etc/apt/sources.list:
```Bash
deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial main
deb-src http://apt.llvm.org/xenial/ llvm-toolchain-xenial main
# 8
deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-8 main
deb-src http://apt.llvm.org/xenial/ llvm-toolchain-xenial-8 main
# 9
deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-9 main
deb-src http://apt.llvm.org/xenial/ llvm-toolchain-xenial-9 main
``` Bash
/opt/wasi-sdk/bin/clang test.c -o test.wasm
```
For Ubuntu 18.04, add the following lines to /etc/apt/sources.list:
```Bash
# i386 not available
deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic main
deb-src http://apt.llvm.org/bionic/ llvm-toolchain-bionic main
# 8
deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-8 main
deb-src http://apt.llvm.org/bionic/ llvm-toolchain-bionic-8 main
# 9
deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-9 main
deb-src http://apt.llvm.org/bionic/ llvm-toolchain-bionic-9 main
```
# Build a project with cmake
(2) Download and install clang-8 tool-chain using following commands:
If you have complex WASM application project which contains dozens of source files, you can consider using cmake for project building.
```Bash
sudo wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key|sudo apt-key add -
# Fingerprint: 6084 F3CF 814B 57C1 CF12 EFD5 15CF 4D18 AF4F 7421
sudo apt-get update
sudo apt-get install llvm-8 lld-8 clang-8
```
(3) Create a soft link under /usr/bin:
```Bash
cd /usr/bin
sudo ln -s wasm-ld-8 wasm-ld
```
(4) Use the clang-8 command below to build the WASM C source code into the WASM binary.
```Bash
clang-8 --target=wasm32 -O3 \
-z stack-size=4096 -Wl,--initial-memory=65536 \
-Wl,--allow-undefined,--export=main \
-Wl,--strip-all,--no-entry -nostdlib \
-o test.wasm test.c
```
You will get ```test.wasm``` which is the WASM app binary.
## Use cmake
If you have a cmake project, you can cross compile your project by using the toolchain provided by WAMR, the compiler used by WAMR toolchain is `clang-8`.
You can cross compile your project by using the toolchain provided by WAMR.
We can generate a `CMakeLists.txt` file for `test.c`:
```cmake
``` cmake
cmake_minimum_required (VERSION 3.5)
project(hello_world)
set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS},--export=main")
add_executable(hello_world test.c)
```
It is quite simple to build this project by cmake:
```Bash
It is simple to build this project by cmake:
``` Bash
mkdir build && cd build
cmake .. -DCMAKE_TOOLCHAIN_FILE=$WAMR_ROOT/test-tools/toolchain/wamr_toolchain.cmake
cmake .. -DCMAKE_TOOLCHAIN_FILE=$WAMR_ROOT/wamr-sdk/app/wamr_toolchain.cmake
make
```
You will get ```hello_world``` which is the WASM app binary.
For more details about wamr toolchain, please refer to [test-tools/toolchain](../test-tools/toolchain/README.md).
> Note: If you have already built a SDK profile, then the **DCMAKE_TOOLCHAIN_FILE** should be changed into `$WAMR_ROOT/wamr-sdk/out/${PROFILE}/app-sdk/wamr_toolchain.cmake`
## Use wasi-sdk
To build a wasm application with wasi support, wasi-sdk is required. Download the [wasi-sdk](https://github.com/CraneStation/wasi-sdk/releases) and extract the archive, then you can use it to build your application:
```Bash
/path/to/wasi-sdk/bin/clang test.c -o test.wasm
```
# Compile WASM to AoT module
You will get ```test.wasm``` which is the WASM app binary.
Please ensure the wamrc was already generated and available in your shell PATH. Then we can use wamrc to compile WASM app binary to WAMR AoT binary.
## Using Docker
Another method availble is using [Docker](https://www.docker.com/). We assume you've already configured Docker (see Platform section above) and have a running interactive shell. Currently the Dockerfile only supports compiling apps with clang, with Emscripten planned for the future.
Use the clang-8 command below to build the WASM C source code into the WASM binary.
```Bash
clang-8 --target=wasm32 -O3 \
-z stack-size=4096 -Wl,--initial-memory=65536 \
-Wl,--allow-undefined,--export=main \
-Wl,--strip-all,--no-entry -nostdlib \
-o test.wasm test.c
```
You will get ```test.wasm``` which is the WASM app binary.
## Use Emscripten tool
The last method to build a WASM binary is to use Emscripten tool ```emcc```.
Assuming you are using Linux, you may install emcc from Emscripten EMSDK following the steps below:
```
git clone https://github.com/emscripten-core/emsdk.git
cd emsdk
./emsdk install latest-fastcomp
./emsdk activate latest-fastcomp
```
The Emscripten website provides other installation methods beyond Linux.
Use the emcc command below to build the WASM C source code into the WASM binary.
``` Bash
cd emsdk
source emsdk_env.sh (or add it to ~/.bashrc if you don't want to run it each time)
cd <dir of test.c>
EMCC_ONLY_FORCED_STDLIBS=1 emcc -g -O3 -s WASM=1 -s ERROR_ON_UNDEFINED_SYMBOLS=0 \
-s TOTAL_MEMORY=65536 -s TOTAL_STACK=4096 \
-s ASSERTIONS=1 -s STACK_OVERFLOW_CHECK=2 \
-s "EXPORTED_FUNCTIONS=['_main']" -o test.wasm test.c
wamrc -o test.aot test.wasm
```
You will get ```test.wasm``` which is the WASM app binary.
Run WASM app
wamrc supports a number of compilation options through the command line arguments:
``` Bash
wamrc --help
Usage: wamrc [options] -o output_file wasm_file
--target=<arch-name> Set the target arch, which has the general format: <arch><sub>
<arch> = x86_64, i386, arm, thumb, mips.
Default is host arch, e.g. x86_64
<sub> = for ex. on arm or thumb: v5, v6m, v7a, v7m, etc.
Use --target=help to list supported targets
--cpu=<cpu> Set the target CPU (default: host CPU, e.g. skylake)
Use --target=help to list all the CPU supported
--cpu-features=<features> Enable or disable the CPU features
Use +feature to enable a feature, or -feature to disable it
For example, --cpu-features=+feature1,-feature2
Use --cpu-features=+help to list all the features supported
--opt-level=n Set the optimization level (0 to 3, default: 3)
--format=<format> Specifies the format of the output file
The format supported:
aot (default) AoT file
object Native object file
llvmir-unopt Unoptimized LLVM IR
llvmir-opt Optimized LLVM IR
Examples: wamrc -o test.aot test.wasm
wamrc --target=i386 -o test.aot test.wasm
wamrc --target=i386 --format=object -o test.o test.wasm
```
Run WASM app in WAMR mini product build
========================
Assume you are using Linux, the command to run the test.wasm is:
Run the test.wasm or test.aot with WAMR mini product build:
``` Bash
cd iwasm/products/linux/build
./iwasm test.wasm
./iwasm test.wasm or
./iwasm test.aot
```
You will get the following output:
```

View File

@ -8,31 +8,34 @@ A typical WAMR API usage is shown below (some return value checks are ignored):
``` C
static char global_heap_buf[512 * 1024];
char *buffer;
char *buffer, error_buf[128];
wasm_module_t module;
wasm_module_inst_t inst;
wasm_module_inst_t module_inst;
wasm_function_inst_t func;
wasm_exec_env_t env;
uint32 argv[2];
wasm_exec_env_t exec_env;
uint32 argv[2], size, stack_size = 8092, heap_size = 8092;
bh_memory_init_with_pool(global_heap_buf, sizeof(global_heap_buf));
wasm_runtime_init();
buffer = read_wasm_binary_to_buffer(…);
module = wasm_runtime_load(buffer, size, err, err_size);
inst = wasm_runtime_instantiate(module, 0, 0, err, err_size);
func = wasm_runtime_lookup_function(inst, "fib", "(i32)i32");
env = wasm_runtime_create_exec_env(stack_size);
buffer = read_wasm_binary_to_buffer(…, &size);
module = wasm_runtime_load(buffer, size, error_buf, sizeof(error_buf));
module_inst = wasm_runtime_instantiate(module, stack_size, heap_size,
error_buf, sizeof(error_buf));
func = wasm_runtime_lookup_function(module_inst, "fib", "(i32)i32");
exec_env = wasm_runtime_create_exec_env(module_inst, stack_size);
argv[0] = 8;
if (!wasm_runtime_call_wasm(inst, env, func, 1, argv_buf) ) {
wasm_runtime_clear_exception(inst);
if (wasm_runtime_call_wasm(exec_env, func, 1, argv_buf) ) {
/* the return value is stored in argv[0] */
printf("fib function return: %d\n", argv[0]);
}
else {
printf("%s\n", wasm_runtime_get_exception(module_inst));
}
/* the return value is stored in argv[0] */
printf("fib function return: %d\n", argv[0]);
wasm_runtime_destroy_exec_env(env);
wasm_runtime_deinstantiate(inst);
wasm_runtime_destroy_exec_env(exec_env);
wasm_runtime_deinstantiate(module_inst);
wasm_runtime_unload(module);
wasm_runtime_destroy();
bh_memory_destroy();

View File

@ -1,5 +1,5 @@
The mechanism of exporting native API to WASM application
Export native API to WASM application
=======================================================
The basic working flow for WASM application calling into the native API is shown in the following diagram:
@ -21,16 +21,105 @@ static NativeSymbol extended_native_symbol_defs[] = {
};
```
![#f03c15](https://placehold.it/15/f03c15/000000?text=+) **Security attention:** A WebAssembly application should only have access to its own memory space. As a result, the integrator should carefully design the native function to ensure that the memory accesses are safe. The native API to be exported to the WASM application must:
**Security attention:** A WebAssembly application should only have access to its own memory space. As a result, the integrator should carefully design the native function to ensure that the memory accesses are safe. The native API to be exported to the WASM application must:
- Only use 32 bits number for parameters
- Should not pass data to the structure pointer (do data serialization instead)
- Should do the pointer address conversion in the native API
- Should not pass function pointer as callback
Below is a sample of a library extension. All code invoked across WASM and native world must be serialized and de-serialized, and the native world must do a boundary check for every incoming address from the WASM world.
In wasm world:
``` C
void api_send_request(request_t * request, response_handler_f response_handler,
void * user_data)
{
int size;
char *buffer;
transaction_t *trans;
if ((trans = (transaction_t *) malloc(sizeof(transaction_t))) == NULL) {
printf(
"send request: allocate memory for request transaction failed!\n");
return;
}
memset(trans, 0, sizeof(transaction_t));
trans->handler = response_handler;
trans->mid = request->mid;
trans->time = wasm_get_sys_tick_ms();
trans->user_data = user_data;
// pack request
if ((buffer = pack_request(request, &size)) == NULL) {
printf("send request: pack request failed!\n");
free(trans);
return;
}
transaction_add(trans);
/* if the trans is the 1st one, start the timer */
if (trans == g_transactions) {
/* assert(g_trans_timer == NULL); */
if (g_trans_timer == NULL) {
g_trans_timer = api_timer_create(TRANSACTION_TIMEOUT_MS,
false,
true, transaction_timeout_handler);
}
}
// call native API
wasm_post_request(buffer, size);
free_req_resp_packet(buffer);
}
```
In native world:
``` C
void
wasm_post_request(wasm_exec_env_t exec_env,
int32 buffer_offset, int size)
{
wasm_module_inst_t module_inst = get_module_inst(exec_env);
char *buffer = NULL;
// do boundary check
if (!validate_app_addr(buffer_offset, size))
return;
// do address conversion
buffer = addr_app_to_native(buffer_offset);
if (buffer != NULL) {
request_t req[1];
// De-serialize data
if (!unpack_request(buffer, size, req))
return;
// set sender to help dispatch the response to the sender app later
unsigned int mod_id = app_manager_get_module_id(Module_WASM_App,
module_inst);
bh_assert(mod_id != ID_NONE);
req->sender = mod_id;
if (req->action == COAP_EVENT) {
am_publish_event(req);
return;
}
am_dispatch_request(req);
}
}
```
<img src="./pics/safe.PNG" width="90%">
Steps for exporting native API
@ -38,79 +127,77 @@ Steps for exporting native API
WAMR implemented a framework for developers to export API's. Below is the procedure to expose the platform API's in three steps:
**Step 1. Create a header file**<br/>
Declare the API's for your WASM application source project to include.
**Step 2. Create a source file**<br/>
Export the platform API's, for example in ``` products/linux/ext_lib_export.c ```
## Step 1: Define the native API for exporting
Define the function **example_native_func** in your source file, namely `example.c` here:
``` C
#include "lib_export.h"
static NativeSymbol extended_native_symbol_defs[] =
int example_native_func(wasm_exec_env_t exec_env,
int arg1, int arg2)
{
};
#include "ext_lib_export.h"
```
**Step 3. Register new API's**<br/>
Use the macro `EXPORT_WASM_API` and `EXPORT_WASM_API2` to add exported API's into the array of ```extended_native_symbol_defs```.
The pre-defined MACRO `EXPORT_WASM_API` should be used to declare a function export:
``` c
#define EXPORT_WASM_API(symbol) {#symbol, symbol}
```
Below code example shows how to extend the library to support `customized()`:
```
//lib_export_impl.c
void customized()
{
// your code
// Your implementation here
}
```
The first function argument must be defined using type **wasm_exec_env_t** which is the WAMR calling convention for native API exporting.
// lib_export_dec.h
#ifndef _LIB_EXPORT_DEC_H_
#define _LIB_EXPORT_DEC_H_
The function prototype should also be declared in a header file so the wasm application can include it.
``` C
#ifndef _EXAMPLE_H_
#define _EXAMPLE_H_
#ifdef __cplusplus
extern "C" {
#endif
void customized();
void example_native_func(int arg1, int arg2);
#ifdef __cplusplus
}
#endif
#endif
```
## Step 2: Declare the native API exporting
// ext_lib_export.c
#include "lib_export.h"
#include "lib_export_dec.h"
Declare the function **example_native_func** with macro **EXPORT_WASM_API** in your **.inl** file, namely `example.inl` in this sample.
``` C
EXPORT_WASM_API(example_native_func),
```
static NativeSymbol extended_native_symbol_defs[] =
{
EXPORT_WASM_API(customized)
Then include the file **example.inl** in definition of array **extended_native_symbol_defs** in the `ext_lib_export.c`.
``` C
static NativeSymbol extended_native_symbol_defs[] = {
#include "example.inl"
};
#include "ext_lib_export.h"
```
Use extended library
------------------------
In the application source project, it will include the WAMR built-in API's header file and platform extension header files. Assuming the board vendor extends the library which added an API called customized(), the WASM application would be like this:
## Step 3: Compile the runtime product
Add the source file **example.c** and **ext_lib_export.c** into the CMakeList.txt for building runtime with the exported API's:
``` cmake
set (EXT_API_SOURCE example.c)
add_executable (sample
# other source files
# ......
${EXT_API_SOURCE}
ext_lib_export.c
)
```
# Use exported API in wasm application
We can call the exported native API **example_native_func** in wasm application like this:
``` C
#include <stdio.h>
#include "lib_export_dec.h" // provided by the platform vendor
#include "example.h"
int main(int argc, char **argv)
{
int I;
char *buf = “abcd”;
customized(); // customized API provided by the platform vendor
return i;
int a = 0, b = 1;
example_native_func(a, b);
return 0;
}
```
```

View File

@ -1,13 +0,0 @@
Current memory usage, take samples/littlevgl in Zephyr for example:
(1) WASM app binary: 142K for littlevgl ui_app.wasm
(2) WASM app memory space: 64K for littlevgl ui_app.wasm
(3) WASM app heap space: 8K by default
(4) WASM app thread native stack: 4K by default
(5) WASM interpreter stack: 8K by default
(6) WASM block address hash cache: 3K
(7) timer thread stack: 4K
(8) sensor thread stack: 4K
(9) touch screen thread stack: 4K
(10) others: vm, app mgr, queue, native lib: ~22K
Total memory usage: ~263K

115
doc/other_wasm_compilers.md Normal file
View File

@ -0,0 +1,115 @@
## Use clang compiler
The recommended method to build a WASM binary is to use clang compiler ```clang-8```. You can refer to [apt.llvm.org](https://apt.llvm.org) for the detailed instructions. Here are referenced steps to install clang-8 in Ubuntu 16.04 and Ubuntu 18.04.
(1) Add source to your system source list from llvm website
For Ubuntu 16.04, add the following lines to /etc/apt/sources.list:
``` Bash
deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial main
deb-src http://apt.llvm.org/xenial/ llvm-toolchain-xenial main
# 8
deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-8 main
deb-src http://apt.llvm.org/xenial/ llvm-toolchain-xenial-8 main
# 9
deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-9 main
deb-src http://apt.llvm.org/xenial/ llvm-toolchain-xenial-9 main
```
For Ubuntu 18.04, add the following lines to /etc/apt/sources.list:
``` Bash
# i386 not available
deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic main
deb-src http://apt.llvm.org/bionic/ llvm-toolchain-bionic main
# 8
deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-8 main
deb-src http://apt.llvm.org/bionic/ llvm-toolchain-bionic-8 main
# 9
deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-9 main
deb-src http://apt.llvm.org/bionic/ llvm-toolchain-bionic-9 main
```
(2) Download and install clang-8 tool-chain using following commands:
``` Bash
sudo wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key|sudo apt-key add -
# Fingerprint: 6084 F3CF 814B 57C1 CF12 EFD5 15CF 4D18 AF4F 7421
sudo apt-get update
sudo apt-get install llvm-8 lld-8 clang-8
```
(3) Create a soft link under /usr/bin:
``` Bash
cd /usr/bin
sudo ln -s wasm-ld-8 wasm-ld
```
(4) Use the clang-8 command below to build the WASM C source code into the WASM binary.
``` Bash
clang-8 --target=wasm32 -O3 \
-z stack-size=4096 -Wl,--initial-memory=65536 \
-Wl,--allow-undefined,--export=main \
-Wl,--strip-all,--no-entry -nostdlib \
-o test.wasm test.c
```
You will get ```test.wasm``` which is the WASM app binary.
## Use Emscripten tool
The last method to build a WASM binary is to use Emscripten tool ```emcc```.
Assuming you are using Linux, you may install emcc from Emscripten EMSDK following the steps below:
```
git clone https://github.com/emscripten-core/emsdk.git
cd emsdk
./emsdk install latest-fastcomp
./emsdk activate latest-fastcomp
```
The Emscripten website provides other installation methods beyond Linux.
Use the emcc command below to build the WASM C source code into the WASM binary.
``` Bash
cd emsdk
source emsdk_env.sh (or add it to ~/.bashrc if you don't want to run it each time)
cd <dir of test.c>
EMCC_ONLY_FORCED_STDLIBS=1 emcc -g -O3 -s WASM=1 -s ERROR_ON_UNDEFINED_SYMBOLS=0 \
-s TOTAL_MEMORY=65536 -s TOTAL_STACK=4096 \
-s ASSERTIONS=1 -s STACK_OVERFLOW_CHECK=2 \
-s "EXPORTED_FUNCTIONS=['_main']" -o test.wasm test.c
```
You will get ```test.wasm``` which is the WASM app binary.
## Using Docker
Another method availble is using [Docker](https://www.docker.com/). We assume you've already configured Docker (see Platform section above) and have a running interactive shell. Currently the Dockerfile only supports compiling apps with clang, with Emscripten planned for the future.
Use the clang-8 command below to build the WASM C source code into the WASM binary.
``` Bash
clang-8 --target=wasm32 -O3 \
-z stack-size=4096 -Wl,--initial-memory=65536 \
-Wl,--allow-undefined,--export=main \
-Wl,--strip-all,--no-entry -nostdlib \
-o test.wasm test.c
```
You will get ```test.wasm``` which is the WASM app binary.

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

48
doc/port_wamr.md Normal file
View File

@ -0,0 +1,48 @@
WAMR porting guide
=========================
This document describes how to port WAMR to a new platform "**super-os**"
# Step 1: Create folders for the new platform
-------------------------
Create folders:
- **core/shared/platform/super-os**: for platform API layer implementations
- **product-mini/platforms/super-os**: for the platform mini product build
# Step 2: Implement platform API layer
-------------------------
Implement folder core/shared/platform/super-os. Normally in this folder you should implement the following files:
- bh_platform.h and bh_platform.c: define the platform related macros, data types and APIs.
- bh_assert.c: implement function bh_assert_internal() and bh_debug_internal().
- bh_definition.c: implement function b_memcpy_s, b_strcat_s and b_strcpy_s. And implement fopen_s
if we need to read wasm file from file system.
- bh_platform_log.c: implement function bh_log_emit, bh_fprintf and bh_fflush.
- bh_time.c: implement several time related functions.
- bh_thread.c: implement thread, mutex, condition related functions.
- bh_math.c: implement some math functions if the platform doesn't support them, e.g. sqrt,
fabs and isnan. We may use the open source fdlibm implementation, for example,
ref to platform/zephyr/bh_math.c.
Please ref to implementation of other platform for more details, e.g. platform/zephyr, platform/linux.
# Step 3: Create the mini product build for the platform
-------------------------
Implement folder product-mini/platforms/super-os. Normally this folder is to implement the C main function, and generate a WAMR VM core binary named iwasm which can load and run wasm apps. We should implement following files:
- main.c: implement the C main function, which reads wasm file to buffer, loads the wasm file to wasm module, instantiate the module, lookup wasm app main function, and then execute the function.
- ext_lib_export.c: implement the native APIs if you want, and if no native API is to be implemented, just keep array extended_native_symbol_defs empty.
- CMakeLists.txt: there are some settings which can be passed from cmake variables:
- set (WAMR_BUILD_PLATFORM "platform_name"): set the name of the platform
- set (WAMR_BUILD_TARGET <arch><sub>): set the build target, currently the value supported: X86_64, X86_32, ARM[sub], THUMB[sub], MIPS and XTENSA. For ARM and THUMB, you can specify the sub version, e.g. ARMV4, ARMV7, THUMBV4T, THUMBV7T.
- set (WAMR_BUILD_INTERP 1 or 0): whether to interpreter or not
- set (WAMR_BUILD_AOT 1 or 0): whether to build AOT or not
- set (WAMR_BUILD_JIT 1 or 0): whether to build JIT or not
- set (WAMR_BUILD_LIBC_BUILTIN 1 or 0): whether to build Libc builtin or not
- set (WAMR_BUILD_LIBC_WASI 1 or 0): whether to build Libc WASI or not

View File

@ -15,8 +15,6 @@ Major feature releases and contributors
- Contributor: JinZhou Zhu (Alibaba)
**May 24, 2019: Support memory usage profiler**
- Contributors Wenyong Huang (Intel)
@ -57,4 +55,7 @@ Major feature releases and contributors
- Contributor: Jonathan Dong (Alibaba)
**Nov 2019: WASI support** (Intel)
**Jan 2020: Ahead of time and Just-in-Time compilation support** (Intel)

View File

@ -2,15 +2,22 @@
# WebAssembly Micro Runtime Roadmap
## Ahead of time compilation
Status: under development. The first release is targetted to the end of 2019.
## WASI support
Evaluated solution.
## Data serialization
Evauating using cbor as the default data serialization
Evaluating using cbor as the default data serialization
No plan yet.
## Threading
Not started yet
Plan: 2020 Q1
## AssemblyScript Support and API
Currently under evaluation

View File

@ -1,104 +1,66 @@
WAMR application library
WAMR application framework
========================
WAMR APP API includes built-in Libc API's, Base library and Extension library reference.
**Libc API's**<br/>
This is a minimal set of Libc API's for memory allocation, string manipulation and printing. The header file is located at ```lib/app-libs/libc/lib_base.h```. The current supported API set is listed here:
## Application system callbacks
The `on_init` and `on_destroy` functions are wamr application system callbacks which must be implemented in the wasm application if you want to use the APP framework.
``` C
void *malloc(size_t size);
void *calloc(size_t n, size_t size);
void free(void *ptr);
int memcmp(const void *s1, const void *s2, size_t n);
void *memcpy(void *dest, const void *src, size_t n);
void *memmove(void *dest, const void *src, size_t n);
void *memset(void *s, int c, size_t n);
int putchar(int c);
int snprintf(char *str, size_t size, const char *format, ...);
int sprintf(char *str, const char *format, ...);
char *strchr(const char *s, int c);
int strcmp(const char *s1, const char *s2);
char *strcpy(char *dest, const char *src);
size_t strlen(const char *s);
int strncmp(const char * str1, const char * str2, size_t n);
char *strncpy(char *dest, const char *src, unsigned long n);
void on_init()
{
/*
Your init functions here, for example:
* platform initialization
* timer registration
* service / event registration
* ......
*/
}
void on_destroy()
{
/*
your destroy functions here
*/
}
```
**Base library**<br/>
Basic support for communication, timers, etc is available. You can refer to the header file ```lib/app-libs/base/wasm_app.h``` which contains the definitions for request and response API's, event pub/sub API's and timer API's. Please note that these API's require the native implementations.
The API set is listed below:
## Base App library
The base library of application framework supports the essential API for WASM applications, such as inter-app communication, timers, etc. Other application framework components rely on the base library.
When building the WAMR SDK, once application framework is enabled, the base library will automatically enabled.
### Timer
The *timer* API's can be used to create some `soft timers` with single-shot mode or periodic mode. Here is a reference of how to use timer API's to execute a function every one second.
``` C
typedef void(*request_handler_f)(request_t *) ;
typedef void(*response_handler_f)(response_t *, void *) ;
/* User global variable */
static int num = 0;
// Request API's
bool api_register_resource_handler(const char *url, request_handler_f);
void api_send_request(request_t * request, response_handler_f response_handler, void * user_data);
void api_response_send(response_t *response);
/* Timer callback */
void timer1_update(user_timer_t timer)
{
printf("Timer update %d\n", num++);
}
// Event API's
bool api_publish_event(const char *url, int fmt, void *payload, int payload_len);
bool api_subscribe_event(const char * url, request_handler_f handler);
void on_init()
{
user_timer_t timer;
struct user_timer;
typedef struct user_timer * user_timer_t;
/* set up a timer */
timer = api_timer_create(1000, true, false, timer1_update);
api_timer_restart(timer, 1000);
}
// Timer API's
user_timer_t api_timer_create(int interval, bool is_period, bool auto_start, void(*on_user_timer_update)(user_timer_t
));
void api_timer_cancel(user_timer_t timer);
void api_timer_restart(user_timer_t timer, int interval);
void on_destroy()
{
}
```
**Library extension reference**<br/>
Currently we provide several kinds of extension library for reference including sensor, connection and GUI.
Sensor API: In the header file ```lib/app-libs/extension/sensor/sensor.h```, the API set is defined as below:
``` C
sensor_t sensor_open(const char* name, int index,
void(*on_sensor_event)(sensor_t, attr_container_t *, void *),
void *user_data);
bool sensor_config(sensor_t sensor, int interval, int bit_cfg, int delay);
bool sensor_config_with_attr_container(sensor_t sensor, attr_container_t *cfg);
bool sensor_close(sensor_t sensor);
```
Connection API: In the header file `lib/app-libs/extension/connection/connection.h.`, the API set is defined as below:
``` C
/* Connection event type */
typedef enum {
/* Data is received */
CONN_EVENT_TYPE_DATA = 1,
/* Connection is disconnected */
CONN_EVENT_TYPE_DISCONNECT
} conn_event_type_t;
typedef void (*on_connection_event_f)(connection_t *conn,
conn_event_type_t type,
const char *data,
uint32 len,
void *user_data);
connection_t *api_open_connection(const char *name,
attr_container_t *args,
on_connection_event_f on_event,
void *user_data);
void api_close_connection(connection_t *conn);
int api_send_on_connection(connection_t *conn, const char *data, uint32 len);
bool api_config_connection(connection_t *conn, attr_container_t *cfg);
```
GUI API: The API's is list in header file ```lib/app-libs/extension/gui/wgl.h``` which is implemented based open soure 2D graphic library [LittlevGL](https://docs.littlevgl.com/en/html/index.html). Currently supported widgets include button, label, list and check box and more wigdet would be provided in future.
Communication programming models
=========================
WAMR supports two typical communication programming models, the microservice model and the pub/sub model.
Microservice model
-------------------------
### Micro-service model (request/response)
The microservice model is also known as request and response model. One WASM application acts as the server which provides a specific service. Other WASM applications or host/cloud applications request that service and get the response.
<img src="./pics/request.PNG" width="60%" height="60%">
<center><img src="./pics/request.PNG" width="60%" height="60%"></center>
Below is the reference implementation of the server application. It provides room temperature measurement service.
@ -136,11 +98,10 @@ void room_temp_handler(request_t *request)
```
Pub/sub model
-------------------------
### Pub/sub model
One WASM application acts as the event publisher. It publishes events to notify WASM applications or host/cloud applications which subscribe to the events.
<img src="./pics/sub.PNG" width="60%" height="60%">
<center><img src="./pics/sub.PNG" width="60%" height="60%"></center>
Below is the reference implementation of the pub application. It utilizes a timer to repeatedly publish an overheat alert event to the subscriber applications. Then the subscriber applications receive the events immediately.
@ -193,4 +154,198 @@ void on_destroy()
{
}
```
**Note:** You can also subscribe this event from host side by using host tool. Please refer `samples/simple` project for deail usage.
**Note:** You can also subscribe this event from host side by using host tool. Please refer `samples/simple` project for detail usage.
## Sensor API
The API set is defined in the header file ```core/app-framework/sensor/app/wa-inc/sensor.h```.
Here is a reference of how to use sensor API's:
``` C
static sensor_t sensor = NULL;
/* Sensor event callback*/
void sensor_event_handler(sensor_t sensor, attr_container_t *event,
void *user_data)
{
printf("### app get sensor event\n");
attr_container_dump(event);
}
void on_init()
{
char *user_data;
attr_container_t *config;
printf("### app on_init 1\n");
/* open a sensor */
user_data = malloc(100);
printf("### app on_init 2\n");
sensor = sensor_open("sensor_test", 0, sensor_event_handler, user_data);
printf("### app on_init 3\n");
/* config the sensor */
sensor_config(sensor, 1000, 0, 0);
printf("### app on_init 4\n");
}
void on_destroy()
{
if (NULL != sensor) {
sensor_config(sensor, 0, 0, 0);
}
}
```
## Connection API:
The API set is defined in the header file `core/app-framework/connection/app/wa-inc/connection.h`
Here is a reference of how to use connection API's:
``` C
/* User global variable */
static int num = 0;
static user_timer_t g_timer;
static connection_t *g_conn = NULL;
void on_data1(connection_t *conn,
conn_event_type_t type,
const char *data,
uint32 len,
void *user_data)
{
if (type == CONN_EVENT_TYPE_DATA) {
char message[64] = {0};
memcpy(message, data, len);
printf("Client got a message from server -> %s\n", message);
} else if (type == CONN_EVENT_TYPE_DISCONNECT) {
printf("connection is close by server!\n");
} else {
printf("error: got unknown event type!!!\n");
}
}
/* Timer callback */
void timer1_update(user_timer_t timer)
{
char message[64] = {0};
/* Reply to server */
snprintf(message, sizeof(message), "Hello %d", num++);
api_send_on_connection(g_conn, message, strlen(message));
}
void my_close_handler(request_t * request)
{
response_t response[1];
if (g_conn != NULL) {
api_timer_cancel(g_timer);
api_close_connection(g_conn);
}
make_response_for_request(request, response);
set_response(response, DELETED_2_02, 0, NULL, 0);
api_response_send(response);
}
void on_init()
{
user_timer_t timer;
attr_container_t *args;
char *str = "this is client!";
api_register_resource_handler("/close", my_close_handler);
args = attr_container_create("");
attr_container_set_string(&args, "address", "127.0.0.1");
attr_container_set_uint16(&args, "port", 7777);
g_conn = api_open_connection("TCP", args, on_data1, NULL);
if (g_conn == NULL) {
printf("connect to server fail!\n");
return;
}
printf("connect to server success! handle: %p\n", g_conn);
/* set up a timer */
timer = api_timer_create(1000, true, false, timer1_update);
api_timer_restart(timer, 1000);
}
void on_destroy()
{
}
```
## GUI API
The API's is listed in header file ```core/app-framework/wgl/app/wa-inc/wgl.h``` which is implemented based on open soure 2D graphic library [LittlevGL](https://docs.littlevgl.com/en/html/index.html).
``` C
static void btn_event_cb(wgl_obj_t btn, wgl_event_t event);
uint32_t count = 0;
char count_str[11] = { 0 };
wgl_obj_t hello_world_label;
wgl_obj_t count_label;
wgl_obj_t btn1;
wgl_obj_t label_count1;
int label_count1_value = 0;
char label_count1_str[11] = { 0 };
void timer1_update(user_timer_t timer1)
{
if ((count % 100) == 0) {
snprintf(count_str, sizeof(count_str), "%d", count / 100);
wgl_label_set_text(count_label, count_str);
}
++count;
}
void on_init()
{
hello_world_label = wgl_label_create((wgl_obj_t)NULL, (wgl_obj_t)NULL);
wgl_label_set_text(hello_world_label, "Hello world!");
wgl_obj_align(hello_world_label, (wgl_obj_t)NULL, WGL_ALIGN_IN_TOP_LEFT, 0, 0);
count_label = wgl_label_create((wgl_obj_t)NULL, (wgl_obj_t)NULL);
wgl_obj_align(count_label, (wgl_obj_t)NULL, WGL_ALIGN_IN_TOP_MID, 0, 0);
btn1 = wgl_btn_create((wgl_obj_t)NULL, (wgl_obj_t)NULL); /*Create a button on the currently loaded screen*/
wgl_obj_set_event_cb(btn1, btn_event_cb); /*Set function to be called when the button is released*/
wgl_obj_align(btn1, (wgl_obj_t)NULL, WGL_ALIGN_CENTER, 0, 0); /*Align below the label*/
/*Create a label on the button*/
wgl_obj_t btn_label = wgl_label_create(btn1, (wgl_obj_t)NULL);
wgl_label_set_text(btn_label, "Click ++");
label_count1 = wgl_label_create((wgl_obj_t)NULL, (wgl_obj_t)NULL);
wgl_label_set_text(label_count1, "0");
wgl_obj_align(label_count1, (wgl_obj_t)NULL, WGL_ALIGN_IN_BOTTOM_MID, 0, 0);
/* set up a timer */
user_timer_t timer;
timer = api_timer_create(10, true, false, timer1_update);
if (timer)
api_timer_restart(timer, 10);
else
printf("Fail to create timer.\n");
}
static void btn_event_cb(wgl_obj_t btn, wgl_event_t event)
{
if(event == WGL_EVENT_RELEASED) {
label_count1_value++;
snprintf(label_count1_str, sizeof(label_count1_str),
"%d", label_count1_value);
wgl_label_set_text(label_count1, label_count1_str);
}
}
```
Currently supported widgets include button, label, list and check box and more wigdet would be provided in future.