Răsfoiți Sursa

Add xtensa AOT support and fix build issue of alios (#223)

* Clean compiling warnings of zephyr samples

* Support xtensa AOT and fix build issue of alios
Weining 6 ani în urmă
părinte
comite
c6fc12b7b6

+ 1 - 1
README.md

@@ -53,7 +53,7 @@ Execute following commands to build **wamrc** compiler:
 
 ```shell
 cd wamr-compiler
-./build_llvm.sh
+./build_llvm.sh (use build_llvm_xtensa.sh instead to support xtensa target)
 mkdir build && cd build
 cmake ..
 make

+ 28 - 7
core/iwasm/aot/aot_loader.c

@@ -985,14 +985,21 @@ load_text_section(const uint8 *buf, const uint8 *buf_end,
         return false;
     }
 
-    module->code = (void*)buf;
-    module->code_size = (uint32)(buf_end - buf);
+    read_uint32(buf, buf_end, module->literal_size);
+
+    /* literal data is at begining of the text section */
+    module->literal = (uint8*)buf;
+    module->code = (void*)(buf + module->literal_size);
+    module->code_size = (uint32)(buf_end - (uint8*)module->code);
 
     if (module->code_size > 0) {
         plt_base = (uint8*)buf_end - get_plt_table_size();
         init_plt_table(plt_base);
     }
     return true;
+
+fail:
+    return false;
 }
 
 static bool
@@ -1184,13 +1191,20 @@ resolve_target_sym(const char *symbol, int32 *p_index)
     return NULL;
 }
 
+static bool
+is_literal_relocation(const char *reloc_sec_name)
+{
+    return !strcmp(reloc_sec_name, ".rela.literal");
+}
+
 static bool
 do_text_relocation(AOTModule *module,
                    AOTRelocationGroup *group,
                    char *error_buf, uint32 error_buf_size)
 {
-    uint8 *aot_text = module->code;
-    uint32 aot_text_size = module->code_size;
+    bool is_literal = is_literal_relocation(group->section_name);
+    uint8 *aot_text = is_literal ? module->literal : module->code;
+    uint32 aot_text_size = is_literal ? module->literal_size : module->code_size;
     uint32 i, func_index, symbol_len;
     char symbol_buf[128]  = { 0 }, *symbol, *p;
     void *symbol_addr;
@@ -1248,6 +1262,9 @@ do_text_relocation(AOTModule *module,
                 goto check_symbol_fail;
             }
         }
+        else if (!strcmp(symbol, ".literal")) {
+            symbol_addr = module->literal;
+        }
         else if (!(symbol_addr = resolve_target_sym(symbol, &symbol_index))) {
             if (error_buf != NULL)
                 snprintf(error_buf, error_buf_size,
@@ -1495,7 +1512,8 @@ load_relocation_section(const uint8 *buf, const uint8 *buf_end,
         }
 
         if (!strcmp(group->section_name, ".rel.text")
-            || !strcmp(group->section_name, ".rela.text")) {
+            || !strcmp(group->section_name, ".rela.text")
+            || !strcmp(group->section_name, ".rela.literal")) {
             if (!do_text_relocation(module, group, error_buf, error_buf_size))
                 return false;
         }
@@ -2079,8 +2097,11 @@ aot_unload(AOTModule *module)
     if (module->const_str_set)
         bh_hash_map_destroy(module->const_str_set);
 
-    if (module->code)
-        os_munmap(module->code, module->code_size);
+    if (module->code) {
+        uint8 *mmap_addr = module->literal - sizeof(module->literal_size);
+        uint32 total_size = sizeof(module->literal_size) + module->literal_size + module->code_size;
+        os_munmap(mmap_addr, total_size);
+    }
 
     if (module->data_sections)
         destroy_object_data_sections(module->data_sections,

+ 4 - 0
core/iwasm/aot/aot_runtime.h

@@ -125,6 +125,10 @@ typedef struct AOTModule {
     void *code;
     uint32 code_size;
 
+    /* literal for AOTed code, NULL for JIT mode */
+    uint8 *literal;
+    uint32 literal_size;
+
     /* data sections in AOT object file, including .data, .rodata
      * and .rodata.cstN. NULL for JIT mode. */
     AOTObjectDataSection *data_sections;

+ 169 - 2
core/iwasm/aot/arch/aot_reloc_xtensa.c

@@ -5,10 +5,50 @@
 
 #include "aot_reloc.h"
 
+#define R_XTENSA_32        1   /* Direct 32 bit */
+#define R_XTENSA_SLOT0_OP  20  /* PC relative */
+
+/* for soft-float */
+void __floatsidf();
+void __divdf3();
+void __ltdf2();
+
+/* for mul32 */
+void __mulsi3();
+void __muldi3();
+
+void __modsi3();
+
+void __divdi3();
+
 static SymbolMap target_sym_map[] = {
-    REG_COMMON_SYMBOLS
+    REG_COMMON_SYMBOLS,
+
+    /* API's for soft-float */
+    /* TODO: only register these symbols when Floating-Point Coprocessor
+     * Option is not enabled */
+    REG_SYM(__floatsidf),
+    REG_SYM(__divdf3),
+    REG_SYM(__ltdf2),
+
+    /* API's for 32-bit integer multiply */
+    /* TODO: only register these symbols when 32-bit Integer Multiply Option
+     * is not enabled */
+    REG_SYM(__mulsi3),
+    REG_SYM(__muldi3),
+
+    REG_SYM(__modsi3),
+
+    REG_SYM(__divdi3),
 };
 
+static void
+set_error_buf(char *error_buf, uint32 error_buf_size, const char *string)
+{
+    if (error_buf != NULL)
+        snprintf(error_buf, error_buf_size, "%s", string);
+}
+
 SymbolMap *
 get_target_symbol_map(uint32 *sym_num)
 {
@@ -40,6 +80,67 @@ get_plt_table_size()
     return get_plt_item_size() * (sizeof(target_sym_map) / sizeof(SymbolMap));
 }
 
+static bool
+check_reloc_offset(uint32 target_section_size,
+                   uint64 reloc_offset, uint32 reloc_data_size,
+                   char *error_buf, uint32 error_buf_size)
+{
+    if (!(reloc_offset < (uint64)target_section_size
+          && reloc_offset + reloc_data_size <= (uint64)target_section_size)) {
+        set_error_buf(error_buf, error_buf_size,
+                      "AOT module load failed: invalid relocation offset.");
+        return false;
+    }
+    return true;
+}
+
+/*
+ * CPU like esp32 can read and write data through the instruction bus, but only
+ * in a word aligned manner; non-word-aligned access will cause a CPU exception.
+ * This function uses a world aligned manner to write 16bit value to instruction
+ * addreess.
+ */
+static void
+put_imm16_to_addr(int16 imm16, int16 *addr)
+{
+    int8 bytes[8];
+    int32 *addr_aligned1, *addr_aligned2;
+
+    addr_aligned1 = (int32*)((intptr_t)addr & ~3);
+
+    if ((intptr_t)addr % 4 != 3) {
+        *(int32*)bytes = *addr_aligned1;
+        *(int16*)(bytes + ((intptr_t)addr % 4)) = imm16;
+        memcpy(addr_aligned1, bytes, 4);
+    }
+    else {
+        addr_aligned2 = (int32*)(((intptr_t)addr + 3) & ~3);
+        *(int32*)bytes = *addr_aligned1;
+        *(int32*)(bytes + 4) = *addr_aligned2;
+        *(int16*)(bytes + 3) = imm16;
+        memcpy(addr_aligned1, bytes, 8);
+    }
+}
+
+static union {
+    int a;
+    char b;
+} __ue = { .a = 1 };
+
+#define is_little_endian() (__ue.b == 1)
+
+typedef union {
+    struct l32r_le {
+        int8 other;
+        int16 imm16;
+    } __packed l;
+
+    struct l32r_be {
+        int16 imm16;
+        int8 other;
+    } __packed b;
+} l32r_insn_t;
+
 bool
 apply_relocation(AOTModule *module,
                  uint8 *target_section_addr, uint32 target_section_size,
@@ -48,7 +149,73 @@ apply_relocation(AOTModule *module,
                  char *error_buf, uint32 error_buf_size)
 {
     switch (reloc_type) {
-        /* TODO: implement relocation for xtensa */
+        case R_XTENSA_32:
+        {
+            uint8 *insn_addr = target_section_addr + reloc_offset;
+            int32 initial_addend;
+            /* (S + A) */
+            if ((intptr_t)insn_addr & 3) {
+                set_error_buf(error_buf, error_buf_size,
+                              "AOT module load failed: "
+                              "instruction address unaligned.");
+                return false;
+            }
+            CHECK_RELOC_OFFSET(4);
+            initial_addend = *(int32*)insn_addr;
+            *(uint8**)insn_addr
+                = (uint8*)symbol_addr + initial_addend + reloc_addend;
+            break;
+        }
+
+        case R_XTENSA_SLOT0_OP:
+        {
+            uint8 *insn_addr = target_section_addr + reloc_offset;
+            /* Currently only l32r instruction generates R_XTENSA_SLOT0_OP relocation */
+            l32r_insn_t *l32r_insn = (l32r_insn_t *)insn_addr;
+            uint8 *reloc_addr;
+            int32 relative_offset/*, initial_addend */;
+            int16 imm16;
+
+            CHECK_RELOC_OFFSET(3); /* size of l32r instruction */
+
+            /*
+            imm16 = is_little_endian() ?
+                    l32r_insn->l.imm16 : l32r_insn->b.imm16;
+            initial_addend = (int32)imm16 << 2;
+            */
+
+            reloc_addr = (uint8*)symbol_addr + reloc_addend;
+
+            if ((intptr_t)reloc_addr & 3) {
+                set_error_buf(error_buf, error_buf_size,
+                              "AOT module load failed: "
+                              "relocation address unaligned.");
+                return false;
+            }
+
+            relative_offset = (int32)
+                              ((intptr_t)reloc_addr -
+                               (((intptr_t)insn_addr + 3) & ~(intptr_t)3));
+            /* relative_offset += initial_addend; */
+
+            /* check relative offset boundary */
+            if (relative_offset < -256 * BH_KB || relative_offset > -4) {
+                set_error_buf(error_buf, error_buf_size,
+                              "AOT module load failed: "
+                              "target address out of range.");
+                return false;
+            }
+
+            imm16 = (int16)(relative_offset >> 2);
+
+            /* write back the imm16 to the l32r instruction */
+            if (is_little_endian())
+                put_imm16_to_addr(imm16, &l32r_insn->l.imm16);
+            else
+                put_imm16_to_addr(imm16, &l32r_insn->b.imm16);
+
+            break;
+        }
 
         default:
             if (error_buf != NULL)

+ 37 - 1
core/iwasm/compilation/aot_emit_aot_file.c

@@ -49,6 +49,10 @@ typedef struct AOTObjectData {
     void *text;
     uint32 text_size;
 
+    /* literal data and size */
+    void *literal;
+    uint32 literal_size;
+
     AOTObjectDataSection *data_sections;
     uint32 data_sections_count;
 
@@ -379,7 +383,7 @@ get_init_data_section_size(AOTCompData *comp_data, AOTObjectData *obj_data)
 static uint32
 get_text_section_size(AOTObjectData *obj_data)
 {
-    return obj_data->text_size;
+    return (sizeof(uint32) + obj_data->literal_size + obj_data->text_size + 3) & ~3;
 }
 
 static uint32
@@ -1118,13 +1122,20 @@ aot_emit_text_section(uint8 *buf, uint8 *buf_end, uint32 *p_offset,
 {
     uint32 section_size = get_text_section_size(obj_data);
     uint32 offset = *p_offset;
+    uint8 placeholder = 0;
 
     *p_offset = offset = align_uint(offset, 4);
 
     EMIT_U32(AOT_SECTION_TYPE_TEXT);
     EMIT_U32(section_size);
+    EMIT_U32(obj_data->literal_size);
+    if (obj_data->literal_size > 0)
+        EMIT_BUF(obj_data->literal, obj_data->literal_size);
     EMIT_BUF(obj_data->text, obj_data->text_size);
 
+    while (offset & 3)
+        EMIT_BUF(&placeholder, 1);
+
     if (offset - *p_offset != section_size + sizeof(uint32) * 2) {
         aot_set_last_error("emit text section failed.");
         return false;
@@ -1449,6 +1460,29 @@ aot_resolve_text(AOTObjectData *obj_data)
     return true;
 }
 
+static bool
+aot_resolve_literal(AOTObjectData *obj_data)
+{
+    LLVMSectionIteratorRef sec_itr;
+    char *name;
+
+    if (!(sec_itr = LLVMObjectFileCopySectionIterator(obj_data->binary))) {
+        aot_set_last_error("llvm get section iterator failed.");
+        return false;
+    }
+    while (!LLVMObjectFileIsSectionIteratorAtEnd(obj_data->binary, sec_itr)) {
+        if ((name = (char *)LLVMGetSectionName(sec_itr)) && !strcmp(name, ".literal")) {
+            obj_data->literal = (char *)LLVMGetSectionContents(sec_itr);
+            obj_data->literal_size = (uint32)LLVMGetSectionSize(sec_itr);
+            break;
+        }
+        LLVMMoveToNextSection(sec_itr);
+    }
+    LLVMDisposeSectionIterator(sec_itr);
+
+    return true;
+}
+
 static bool
 is_data_section(char *section_name)
 {
@@ -1701,6 +1735,7 @@ is_relocation_section(char *section_name)
 {
     return (!strcmp(section_name, ".rela.text")
             || !strcmp(section_name, ".rel.text")
+            || !strcmp(section_name, ".rela.literal")
             || !strcmp(section_name, ".rela.data")
             || !strcmp(section_name, ".rel.data")
             || !strcmp(section_name, ".rela.rodata")
@@ -1873,6 +1908,7 @@ aot_obj_data_create(AOTCompContext *comp_ctx)
     /* resolve target info/text/relocations/functions */
     if (!aot_resolve_target_info(comp_ctx, obj_data)
         || !aot_resolve_text(obj_data)
+        || !aot_resolve_literal(obj_data)
         || !aot_resolve_object_data_sections(obj_data)
         || !aot_resolve_object_relocation_groups(obj_data)
         || !aot_resolve_functions(comp_ctx, obj_data))

+ 53 - 8
core/iwasm/compilation/aot_emit_numberic.c

@@ -858,18 +858,63 @@ fail:
 }
 
 static bool
-is_targeting_soft_float(LLVMTargetMachineRef target_machine)
+is_target_arm(AOTCompContext *comp_ctx)
+{
+    return !strncmp(comp_ctx->target_arch, "arm", 3) ||
+           !strncmp(comp_ctx->target_arch, "thumb", 5);
+}
+
+static bool
+is_target_x86(AOTCompContext *comp_ctx)
+{
+    return !strncmp(comp_ctx->target_arch, "x86_64", 6) ||
+           !strncmp(comp_ctx->target_arch, "i386", 4);
+}
+
+static bool
+is_target_xtensa(AOTCompContext *comp_ctx)
+{
+    return !strncmp(comp_ctx->target_arch, "xtensa", 6);
+}
+
+static bool
+is_target_mips(AOTCompContext *comp_ctx)
+{
+    return !strncmp(comp_ctx->target_arch, "mips", 4);
+}
+
+static bool
+is_targeting_soft_float(AOTCompContext *comp_ctx, bool is_f32)
 {
     bool ret = false;
     char *feature_string;
 
     if (!(feature_string =
-                LLVMGetTargetMachineFeatureString(target_machine))) {
+                LLVMGetTargetMachineFeatureString(comp_ctx->target_machine))) {
         aot_set_last_error("llvm get target machine feature string fail.");
         return false;
     }
 
-    ret = strstr(feature_string, "+soft-float") ? true : false;
+    /* Note:
+     * LLVM CodeGen uses FPU Coprocessor registers by default,
+     * so user must specify '--cpu-features=+soft-float' to wamrc if the target
+     * doesn't have or enable FPU on arm, x86 or mips. */
+    if (is_target_arm(comp_ctx) ||
+        is_target_x86(comp_ctx) ||
+        is_target_mips(comp_ctx))
+        ret = strstr(feature_string, "+soft-float") ? true : false;
+    else if (is_target_xtensa(comp_ctx))
+        /* Note:
+         * 1. The Floating-Point Coprocessor Option of xtensa only support
+         * single-precision floating-point operations, so must use soft-float
+         * for f64(i.e. double).
+         * 2. LLVM CodeGen uses Floating-Point Coprocessor registers by default,
+         * so user must specify '--cpu-features=-fp' to wamrc if the target
+         * doesn't have or enable Floating-Point Coprocessor Option on xtensa. */
+        ret = (!is_f32 || strstr(feature_string, "-fp")) ? true : false;
+    else
+        ret = true;
+
     LLVMDisposeMessage(feature_string);
     return ret;
 }
@@ -880,7 +925,7 @@ compile_op_float_arithmetic(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
 {
     switch (arith_op) {
         case FLOAT_ADD:
-            if (is_targeting_soft_float(comp_ctx->target_machine))
+            if (is_targeting_soft_float(comp_ctx, is_f32))
                 DEF_FP_BINARY_OP(LLVMBuildFAdd(comp_ctx->builder, left, right, "fadd"),
                                  "llvm build fadd fail.");
             else
@@ -897,7 +942,7 @@ compile_op_float_arithmetic(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
                                  NULL);
             return true;
         case FLOAT_SUB:
-            if (is_targeting_soft_float(comp_ctx->target_machine))
+            if (is_targeting_soft_float(comp_ctx, is_f32))
                 DEF_FP_BINARY_OP(LLVMBuildFSub(comp_ctx->builder, left, right, "fsub"),
                                  "llvm build fsub fail.");
             else
@@ -914,7 +959,7 @@ compile_op_float_arithmetic(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
                                  NULL);
             return true;
         case FLOAT_MUL:
-            if (is_targeting_soft_float(comp_ctx->target_machine))
+            if (is_targeting_soft_float(comp_ctx, is_f32))
                 DEF_FP_BINARY_OP(LLVMBuildFMul(comp_ctx->builder, left, right, "fmul"),
                                  "llvm build fmul fail.");
             else
@@ -931,7 +976,7 @@ compile_op_float_arithmetic(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
                                  NULL);
             return true;
         case FLOAT_DIV:
-            if (is_targeting_soft_float(comp_ctx->target_machine))
+            if (is_targeting_soft_float(comp_ctx, is_f32))
                 DEF_FP_BINARY_OP(LLVMBuildFDiv(comp_ctx->builder, left, right, "fdiv"),
                                  "llvm build fdiv fail.");
             else
@@ -1050,7 +1095,7 @@ compile_op_float_math(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
                             NULL);
             return true;
         case FLOAT_SQRT:
-            if (is_targeting_soft_float(comp_ctx->target_machine))
+            if (is_targeting_soft_float(comp_ctx, is_f32))
                 DEF_FP_UNARY_OP(call_llvm_float_math_intrinsic(comp_ctx,
                                                    is_f32 ? "llvm.sqrt.f32" :
                                                             "llvm.sqrt.f64",

+ 1 - 0
core/iwasm/compilation/aot_llvm.c

@@ -740,6 +740,7 @@ typedef struct ArchItem {
 static ArchItem valid_archs[] = {
     { "x86_64", false },
     { "i386", false },
+    { "xtensa", false},
     { "mips", true },
     { "aarch64v8", false },
     { "aarch64v8.1", false },

+ 20 - 0
core/shared/platform/zephyr/platform_internal.h

@@ -77,4 +77,24 @@ unsigned long long int strtoull(const char *nptr, char **endptr, int base);
 double strtod(const char *nptr, char **endptr);
 float strtof(const char *nptr, char **endptr);
 
+/**
+ * @brief Allocate executable memroy
+ *
+ * @param size size of the memory to be allocated
+ *
+ * @return the address of the allocated memory if not NULL
+ */
+typedef void* (*exec_mem_alloc_func_t)(unsigned int size);
+
+/**
+ * @brief Release executable memroy
+ *
+ * @param the address of the executable memory to be released
+ */
+typedef void (*exec_mem_free_func_t)(void *addr);
+
+/* Below function are called by external project to set related function pointers that
+ * will be used to malloc/free executable memory. Otherwise default mechanise will be used. */
+void set_exec_mem_alloc_func(exec_mem_alloc_func_t alloc_func, exec_mem_free_func_t free_func);
+
 #endif

+ 20 - 2
core/shared/platform/zephyr/zephyr_platform.c

@@ -6,6 +6,10 @@
 #include "platform_api_vmcore.h"
 #include "platform_api_extension.h"
 
+/* function pointers for executable memory management */
+static exec_mem_alloc_func_t exec_mem_alloc_func = NULL;
+static exec_mem_free_func_t exec_mem_free_func = NULL;
+
 #if WASM_ENABLE_AOT != 0
 #ifdef CONFIG_ARM_MPU
 /**
@@ -108,13 +112,19 @@ os_vprintf(const char *fmt, va_list ap)
 void *
 os_mmap(void *hint, unsigned int size, int prot, int flags)
 {
-    return BH_MALLOC(size);
+    if (exec_mem_alloc_func)
+        return exec_mem_alloc_func(size);
+    else
+        return BH_MALLOC(size);
 }
 
 void
 os_munmap(void *addr, uint32 size)
 {
-    return BH_FREE(addr);
+    if (exec_mem_free_func)
+        exec_mem_free_func(addr);
+    else
+        BH_FREE(addr);
 }
 
 int
@@ -133,3 +143,11 @@ os_dcache_flush()
     irq_unlock(key);
 #endif
 }
+
+void set_exec_mem_alloc_func(exec_mem_alloc_func_t alloc_func,
+                             exec_mem_free_func_t free_func)
+{
+    exec_mem_alloc_func = alloc_func;
+    exec_mem_free_func = free_func;
+}
+

+ 3 - 4
doc/build_wamr.md

@@ -277,14 +277,13 @@ AliOS-Things
    aos make
    ./out/helloworld@linuxhost/binary/helloworld@linuxhost.elf
    ```
-```
-   
+
    For developerkit:
    Modify file middleware/iwasm/aos.mk, patch as:
    
    ``` C
-WAMR_BUILD_TARGET := THUMBV7M
-```
+   WAMR_BUILD_TARGET := THUMBV7M
+   ```
 
    ``` Bash
    aos make helloworld@developerkit -c config

+ 1 - 1
doc/build_wasm_app.md

@@ -90,7 +90,7 @@ wamrc supports a number of compilation options through the command line argument
 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.
+                            <arch> = x86_64, i386, aarch64, arm, thumb, xtensa, 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

+ 1 - 0
product-mini/platforms/alios-things/aos.mk

@@ -92,6 +92,7 @@ $(NAME)_SOURCES := ${SHARED_ROOT}/platform/alios/alios_platform.c \
                    ${SHARED_ROOT}/utils/bh_log.c \
                    ${SHARED_ROOT}/utils/bh_queue.c \
                    ${SHARED_ROOT}/utils/bh_vector.c \
+                   ${SHARED_ROOT}/utils/runtime_timer.c \
                    ${IWASM_ROOT}/libraries/libc-builtin/libc_builtin_wrapper.c \
                    ${IWASM_ROOT}/common/wasm_runtime_common.c \
                    ${IWASM_ROOT}/common/wasm_native.c \

+ 2 - 40
product-mini/platforms/zephyr/simple/CMakeLists.txt

@@ -37,48 +37,10 @@ if (NOT DEFINED WAMR_BUILD_LIBC_WASI)
 endif ()
 
 set (WAMR_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/wamr)
-set (SHARED_DIR ${WAMR_ROOT_DIR}/core/shared)
-set (IWASM_DIR ${WAMR_ROOT_DIR}/core/iwasm)
-set (APP_FRAMEWORK_DIR ${WAMR_ROOT_DIR}/core/app-framework)
 
-# include the build config template makefile
-include (${WAMR_ROOT_DIR}/build-scripts/config_common.cmake)
-
-include_directories (${SHARED_DIR}/include
-                     ${IWASM_DIR}/include)
-
-include (${SHARED_DIR}/platform/${WAMR_BUILD_PLATFORM}/shared_platform.cmake)
-include (${SHARED_DIR}/mem-alloc/mem_alloc.cmake)
-include (${SHARED_DIR}/utils/shared_utils.cmake)
-if (WAMR_BUILD_LIBC_BUILTIN EQUAL 1)
-  include (${IWASM_DIR}/libraries/libc-builtin/libc_builtin.cmake)
-endif ()
-if (WAMR_BUILD_LIBC_WASI EQUAL 1)
-  include (${IWASM_DIR}/libraries/libc-wasi/libc_wasi.cmake)
-endif ()
-
-include (${IWASM_DIR}/common/iwasm_common.cmake)
-
-if (WAMR_BUILD_INTERP EQUAL 1 OR WAMR_BUILD_JIT EQUAL 1)
-  include (${IWASM_DIR}/interpreter/iwasm_interp.cmake)
-endif()
-
-if (WAMR_BUILD_AOT EQUAL 1)
-  include (${IWASM_DIR}/aot/iwasm_aot.cmake)
-endif ()
-
-set (VM_LIB_SRCS
-     ${PLATFORM_SHARED_SOURCE}
-     ${MEM_ALLOC_SHARED_SOURCE}
-     ${UTILS_SHARED_SOURCE}
-     ${LIBC_BUILTIN_SOURCE}
-     ${LIBC_WASI_SOURCE}
-     ${IWASM_COMMON_SOURCE}
-     ${IWASM_INTERP_SOURCE}
-     ${IWASM_AOT_SOURCE}
-     ${IWASM_COMPL_SOURCE})
+include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake)
 
 target_sources(app PRIVATE
-               ${VM_LIB_SRCS}
+               ${WAMR_RUNTIME_LIB_SOURCE}
                src/main.c)
 

+ 20 - 1
product-mini/platforms/zephyr/simple/build.sh

@@ -6,14 +6,18 @@
 X86_TARGET="x86"
 STM32_TARGET="stm32"
 QEMU_CORTEX_A53="qemu_cortex_a53"
+XTENSA_QEMU_TARGET="xtensa-qemu"
+ESP32_TARGET="esp32"
 
 if [ $# != 1 ] ; then
         echo "USAGE:"
-        echo "$0 $X86_TARGET|$STM32_TARGET|$QEMU_CORTEX_A53"
+        echo "$0 $X86_TARGET|$STM32_TARGET|$QEMU_CORTEX_A53|$XTENSA_QEMU_TARGET|$ESP32_TARGET"
         echo "Example:"
         echo "        $0 $X86_TARGET"
         echo "        $0 $STM32_TARGET"
         echo "        $0 $QEMU_CORTEX_A53"
+        echo "        $0 $XTENSA_QEMU_TARGET"
+        echo "        $0 $ESP32_TARGET"
         exit 1
 fi
 
@@ -31,6 +35,21 @@ elif [ "$TARGET" = "$STM32_TARGET" ] ; then
         cmake -GNinja -DBOARD=nucleo_f767zi -DWAMR_BUILD_TARGET=THUMBV7 ..
         ninja
         ninja flash
+elif [ "$TARGET" = "$XTENSA_QEMU_TARGET" ] ; then
+        cp prj_qemu_xtensa.conf prj.conf
+        rm -fr build && mkdir build && cd build
+        cmake -GNinja -DBOARD=qemu_xtensa -DWAMR_BUILD_TARGET=XTENSA ..
+        ninja
+        ninja run
+elif [ "$TARGET" = "$ESP32_TARGET" ] ; then
+        # suppose you have set environment variable ESP_IDF_PATH
+        west build -b esp32 . -p always -- \
+                -DESP_IDF_PATH=$ESP_IDF_PATH \
+                -DCONF_FILE=prj_esp32.conf \
+                -DWAMR_BUILD_TARGET=XTENSA
+        # suppose the serial port is /dev/ttyUSB1 and you should change to
+        # the real name accordingly
+        west flash -d ./build --skip-rebuild --esp-device /dev/ttyUSB1
 elif [ "$TARGET" = "$QEMU_CORTEX_A53" ] ; then
         cp prj_qemu_cortex_a53.conf prj.conf
         rm -fr build && mkdir build && cd build

+ 274 - 0
product-mini/platforms/zephyr/simple/esp32_custom_linker.ld

@@ -0,0 +1,274 @@
+/*
+ * Copyright (c) 2016 Cadence Design Systems, Inc.
+ * Copyright (c) 2017 Intel Corporation
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+/**
+ * @file
+ * @brief Linker command/script file
+ *
+ * Linker script for the Xtensa platform.
+ */
+
+#include <devicetree.h>
+#include <autoconf.h>
+#include <linker/sections.h>
+#include <linker/linker-defs.h>
+#include <linker/linker-tool.h>
+
+#define RAMABLE_REGION dram0_0_seg :dram0_0_phdr
+#define RAMABLE_REGION1 dram0_1_seg :dram0_0_phdr
+#define ROMABLE_REGION iram0_0_seg :iram0_0_phdr
+
+PROVIDE ( __stack = 0x3ffe3f20 );
+
+PROVIDE ( esp32_rom_uart_tx_one_char = 0x40009200 );
+PROVIDE ( esp32_rom_uart_rx_one_char = 0x400092d0 );
+PROVIDE ( esp32_rom_uart_attach = 0x40008fd0 );
+PROVIDE ( esp32_rom_intr_matrix_set = 0x4000681c );
+PROVIDE ( esp32_rom_gpio_matrix_in = 0x40009edc );
+PROVIDE ( esp32_rom_gpio_matrix_out = 0x40009f0c );
+PROVIDE ( esp32_rom_Cache_Flush = 0x40009a14 );
+PROVIDE ( esp32_rom_Cache_Read_Enable = 0x40009a84 );
+PROVIDE ( esp32_rom_ets_set_appcpu_boot_addr = 0x4000689c );
+
+MEMORY
+{
+  iram0_0_seg(RX): org = 0x40080000, len = 0x20000
+  iram0_2_seg(RX): org = 0x400D0018, len = 0x330000
+  dram0_0_seg(RW): org = 0x3FFB0000, len = 0x30000
+  dram0_1_seg(RWX):org = 0x400A0000, len = 0x20000
+  drom0_0_seg(R): org = 0x3F400010, len = 0x800000
+  rtc_iram_seg(RWX): org = 0x400C0000, len = 0x2000
+  rtc_slow_seg(RW): org = 0x50000000, len = 0x1000
+#ifdef CONFIG_GEN_ISR_TABLES
+  IDT_LIST(RW): org = 0x3ebfe010, len = 0x2000
+#endif
+}
+
+PHDRS
+{
+  iram0_0_phdr PT_LOAD;
+  dram0_0_phdr PT_LOAD;
+}
+
+/*  Default entry point:  */
+PROVIDE ( _ResetVector = 0x40000400 );
+ENTRY(CONFIG_KERNEL_ENTRY)
+
+_rom_store_table = 0;
+
+PROVIDE(_memmap_vecbase_reset = 0x40000450);
+PROVIDE(_memmap_reset_vector = 0x40000400);
+
+SECTIONS
+{
+
+#include <linker/rel-sections.ld>
+
+  /* RTC fast memory holds RTC wake stub code,
+     including from any source file named rtc_wake_stub*.c
+  */
+  .rtc.text :
+  {
+    . = ALIGN(4);
+    *(.rtc.literal .rtc.text)
+    *rtc_wake_stub*.o(.literal .text .literal.* .text.*)
+  } >rtc_iram_seg
+
+  /* RTC slow memory holds RTC wake stub
+     data/rodata, including from any source file
+     named rtc_wake_stub*.c
+  */
+  .rtc.data :
+  {
+    _rtc_data_start = ABSOLUTE(.);
+    *(.rtc.data)
+    *(.rtc.rodata)
+    *rtc_wake_stub*.o(.data .rodata .data.* .rodata.* .bss .bss.*)
+    _rtc_data_end = ABSOLUTE(.);
+  } > rtc_slow_seg
+
+  /* RTC bss, from any source file named rtc_wake_stub*.c */
+  .rtc.bss (NOLOAD) :
+  {
+    _rtc_bss_start = ABSOLUTE(.);
+    *rtc_wake_stub*.o(.bss .bss.*)
+    *rtc_wake_stub*.o(COMMON)
+    _rtc_bss_end = ABSOLUTE(.);
+  } > rtc_slow_seg
+
+  /* Send .iram0 code to iram */
+  .iram0.vectors : ALIGN(4)
+  {
+    /* Vectors go to IRAM */
+    _init_start = ABSOLUTE(.);
+    /* Vectors according to builds/RF-2015.2-win32/esp108_v1_2_s5_512int_2/config.html */
+    . = 0x0;
+    KEEP(*(.WindowVectors.text));
+    . = 0x180;
+    KEEP(*(.Level2InterruptVector.text));
+    . = 0x1c0;
+    KEEP(*(.Level3InterruptVector.text));
+    . = 0x200;
+    KEEP(*(.Level4InterruptVector.text));
+    . = 0x240;
+    KEEP(*(.Level5InterruptVector.text));
+    . = 0x280;
+    KEEP(*(.DebugExceptionVector.text));
+    . = 0x2c0;
+    KEEP(*(.NMIExceptionVector.text));
+    . = 0x300;
+    KEEP(*(.KernelExceptionVector.text));
+    . = 0x340;
+    KEEP(*(.UserExceptionVector.text));
+    . = 0x3C0;
+    KEEP(*(.DoubleExceptionVector.text));
+    . = 0x400;
+    *(.*Vector.literal)
+
+    *(.UserEnter.literal);
+    *(.UserEnter.text);
+    . = ALIGN (16);
+    *(.entry.text)
+    *(.init.literal)
+    *(.init)
+    _init_end = ABSOLUTE(.);
+
+    /* This goes here, not at top of linker script, so addr2line finds it last,
+       and uses it in preference to the first symbol in IRAM */
+    _iram_start = ABSOLUTE(0);
+  } GROUP_LINK_IN(ROMABLE_REGION)
+
+#include <linker/common-ram.ld>
+#include <linker/common-rom.ld>
+
+  SECTION_PROLOGUE(_TEXT_SECTION_NAME, , ALIGN(4))
+  {
+    /* Code marked as running out of IRAM */
+    _iram_text_start = ABSOLUTE(.);
+    *(.iram1 .iram1.*)
+    *(.iram0.literal .iram.literal .iram.text.literal .iram0.text .iram.text)
+    *(.literal .text .literal.* .text.*)
+    _iram_text_end = ABSOLUTE(.);
+  } GROUP_LINK_IN(ROMABLE_REGION)
+
+  .dram0.text :
+  {
+    _data_start = ABSOLUTE(.);
+    *(.aot_code_buf)
+    _data_end = ABSOLUTE(.);
+    . = ALIGN(4);
+  } GROUP_LINK_IN(RAMABLE_REGION1)
+
+
+  .dram0.data :
+  {
+    _data_start = ABSOLUTE(.);
+    *(.data)
+    *(.data.*)
+    *(.gnu.linkonce.d.*)
+    *(.data1)
+    *(.sdata)
+    *(.sdata.*)
+    *(.gnu.linkonce.s.*)
+    *(.sdata2)
+    *(.sdata2.*)
+    *(.gnu.linkonce.s2.*)
+    KEEP(*(.jcr))
+    *(.dram1 .dram1.*)
+    _data_end = ABSOLUTE(.);
+    . = ALIGN(4);
+  } GROUP_LINK_IN(RAMABLE_REGION)
+
+  SECTION_PROLOGUE(_RODATA_SECTION_NAME,,ALIGN(4))
+  {
+    _rodata_start = ABSOLUTE(.);
+    *(.rodata)
+    *(.rodata.*)
+    *(.gnu.linkonce.r.*)
+    *(.rodata1)
+    __XT_EXCEPTION_TABLE__ = ABSOLUTE(.);
+    KEEP (*(.xt_except_table))
+    KEEP (*(.gcc_except_table .gcc_except_table.*))
+    *(.gnu.linkonce.e.*)
+    *(.gnu.version_r)
+    KEEP (*(.eh_frame))
+    /*  C++ constructor and destructor tables, properly ordered:  */
+    KEEP (*crtbegin.o(.ctors))
+    KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
+    KEEP (*(SORT(.ctors.*)))
+    KEEP (*(.ctors))
+    KEEP (*crtbegin.o(.dtors))
+    KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
+    KEEP (*(SORT(.dtors.*)))
+    KEEP (*(.dtors))
+    /*  C++ exception handlers table:  */
+    __XT_EXCEPTION_DESCS__ = ABSOLUTE(.);
+    *(.xt_except_desc)
+    *(.gnu.linkonce.h.*)
+    __XT_EXCEPTION_DESCS_END__ = ABSOLUTE(.);
+    *(.xt_except_desc_end)
+    *(.dynamic)
+    *(.gnu.version_d)
+    . = ALIGN(4);               /* this table MUST be 4-byte aligned */
+    _rodata_end = ABSOLUTE(.);
+  } GROUP_LINK_IN(RAMABLE_REGION)
+
+
+  /* Shared RAM */
+  SECTION_DATA_PROLOGUE(_BSS_SECTION_NAME,(NOLOAD),)
+  {
+    . = ALIGN (8);
+    _bss_start = ABSOLUTE(.);
+    *(.dynsbss)
+    *(.sbss)
+    *(.sbss.*)
+    *(.gnu.linkonce.sb.*)
+    *(.scommon)
+    *(.sbss2)
+    *(.sbss2.*)
+    *(.gnu.linkonce.sb2.*)
+    *(.dynbss)
+    *(.bss)
+    *(.bss.*)
+    *(.share.mem)
+    *(.gnu.linkonce.b.*)
+    *(COMMON)
+    . = ALIGN (8);
+    _bss_end = ABSOLUTE(.);
+  } GROUP_LINK_IN(RAMABLE_REGION)
+
+
+   SECTION_DATA_PROLOGUE(_APP_NOINIT_SECTION_NAME, (NOLOAD),)
+   {
+     . = ALIGN (8);
+     *(.app_noinit)
+     *("app_noinit.*")
+     . = ALIGN (8);
+    _app_end = ABSOLUTE(.);
+  } GROUP_LINK_IN(RAMABLE_REGION)
+
+
+  SECTION_DATA_PROLOGUE(_NOINIT_SECTION_NAME, (NOLOAD),)
+  {
+    . = ALIGN (8);
+    *(.noinit)
+    *(".noinit.*")
+    . = ALIGN (8);
+    _heap_start = ABSOLUTE(.);
+  } GROUP_LINK_IN(RAMABLE_REGION)
+
+#ifdef CONFIG_GEN_ISR_TABLES
+#include <linker/intlist.ld>
+#endif
+
+#include <linker/debug-sections.ld>
+
+  SECTION_PROLOGUE(.xtensa.info, 0,)
+  {
+    *(.xtensa.info)
+  }
+
+}

+ 8 - 0
product-mini/platforms/zephyr/simple/prj_esp32.conf

@@ -0,0 +1,8 @@
+# Copyright (C) 2019 Intel Corporation.  All rights reserved.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+CONFIG_STACK_SENTINEL=y
+CONFIG_PRINTK=y
+CONFIG_LOG=y
+CONFIG_HAVE_CUSTOM_LINKER_SCRIPT=y
+CONFIG_CUSTOM_LINKER_SCRIPT="esp32_custom_linker.ld"

+ 6 - 0
product-mini/platforms/zephyr/simple/prj_qemu_xtensa.conf

@@ -0,0 +1,6 @@
+# Copyright (C) 2019 Intel Corporation.  All rights reserved.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+CONFIG_STACK_SENTINEL=y
+CONFIG_PRINTK=y
+CONFIG_LOG=y

+ 69 - 0
product-mini/platforms/zephyr/simple/src/main.c

@@ -54,6 +54,54 @@ app_instance_main(wasm_module_inst_t module_inst)
 
 static char global_heap_buf[CONFIG_GLOBAL_HEAP_BUF_SIZE] = { 0 };
 
+#ifdef CONFIG_BOARD_ESP32
+#include "mem_alloc.h"
+/*
+esp32_technical_reference_manual:
+"
+The capacity of Internal SRAM 1 is 128 KB. Either CPU can read and write this memory at addresses
+0x3FFE_0000 ~ 0x3FFF_FFFF of the data bus, and also at addresses 0x400A_0000 ~ 0x400B_FFFF of the
+instruction bus.
+"
+
+The custom linker script defines dram0_1_seg and map it to 0x400A_0000 ~ 0x400B_FFFF for instruction bus access.
+Here we define the buffer that will be placed to dram0_1_seg.
+*/
+static char esp32_executable_memory_buf[100 * 1024] __attribute__((section (".aot_code_buf"))) = { 0 };
+
+/* the poll allocator for executable memory */
+static mem_allocator_t esp32_exec_mem_pool_allocator;
+
+static int
+esp32_exec_mem_init()
+{
+    if (!(esp32_exec_mem_pool_allocator =
+                mem_allocator_create(esp32_executable_memory_buf,
+                                     sizeof(esp32_executable_memory_buf))))
+        return -1;
+
+    return 0;
+}
+
+static void
+esp32_exec_mem_destroy()
+{
+    mem_allocator_destroy(esp32_exec_mem_pool_allocator);
+}
+
+static void *
+esp32_exec_mem_alloc(unsigned int size)
+{
+    return mem_allocator_malloc(esp32_exec_mem_pool_allocator, size);
+}
+
+static void
+esp32_exec_mem_free(void *addr)
+{
+    mem_allocator_free(esp32_exec_mem_pool_allocator, addr);
+}
+#endif /* end of #ifdef CONFIG_BOARD_ESP32 */
+
 void iwasm_main(void *arg1, void *arg2, void *arg3)
 {
     int start, end;
@@ -72,6 +120,7 @@ void iwasm_main(void *arg1, void *arg2, void *arg3)
     (void) arg2;
     (void) arg3;
 
+
     memset(&init_args, 0, sizeof(RuntimeInitArgs));
 
     init_args.mem_alloc_type = Alloc_With_Pool;
@@ -84,6 +133,16 @@ void iwasm_main(void *arg1, void *arg2, void *arg3)
         return;
     }
 
+#ifdef CONFIG_BOARD_ESP32
+    /* Initialize executable memory */
+    if (esp32_exec_mem_init() != 0) {
+        printf("Init executable memory failed.\n");
+        goto fail1;
+    }
+    /* Set hook functions for executable memory management */
+    set_exec_mem_alloc_func(esp32_exec_mem_alloc, esp32_exec_mem_free);
+#endif
+
 #if WASM_ENABLE_LOG != 0
     bh_log_set_verbose_level(log_verbose_level);
 #endif
@@ -96,7 +155,11 @@ void iwasm_main(void *arg1, void *arg2, void *arg3)
     if (!(wasm_module = wasm_runtime_load(wasm_file_buf, wasm_file_size,
                                           error_buf, sizeof(error_buf)))) {
         printf("%s\n", error_buf);
+#ifdef CONFIG_BOARD_ESP32
+        goto fail1_1;
+#else
         goto fail1;
+#endif
     }
 
     /* instantiate the module */
@@ -119,6 +182,12 @@ fail2:
     /* unload the module */
     wasm_runtime_unload(wasm_module);
 
+#ifdef CONFIG_BOARD_ESP32
+fail1_1:
+    /* destroy executable memory */
+    esp32_exec_mem_destroy();
+#endif
+
 fail1:
     /* destroy runtime environment */
     wasm_runtime_destroy();

+ 44 - 0
wamr-compiler/build_llvm_xtensa.sh

@@ -0,0 +1,44 @@
+#!/bin/sh
+
+# Copyright (C) 2019 Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+DEPS_DIR=${PWD}/../core/deps
+
+cd ${DEPS_DIR}
+if [ ! -d "llvm" ]; then
+  echo "Clone llvm Xtensa to core/deps/ .."
+  git clone https://github.com/espressif/llvm-project.git llvm
+fi
+
+cd llvm
+mkdir -p build
+cd build
+
+if [ ! -f bin/llvm-lto ]; then
+
+  CORE_NUM=$(nproc --all)
+  if [ -z "${CORE_NUM}" ]; then
+    CORE_NUM=1
+  fi
+
+  echo "Build llvm with" ${CORE_NUM} "cores"
+
+  cmake ../llvm \
+          -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \
+          -DCMAKE_BUILD_TYPE:STRING="Release" \
+          -DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD:STRING="Xtensa" \
+          -DLLVM_BUILD_LLVM_DYLIB:BOOL=OFF \
+          -DLLVM_OPTIMIZED_TABLEGEN:BOOL=ON \
+          -DLLVM_INCLUDE_EXAMPLES:BOOL=OFF \
+          -DLLVM_INCLUDE_TESTS:BOOL=OFF \
+          -DLLVM_INCLUDE_BENCHMARKS:BOOL=OFF \
+          -DLLVM_APPEND_VC_REV:BOOL=OFF
+  make -j ${CORE_NUM}
+
+else
+  echo "llvm has already been built"
+fi
+
+cd ${PWD}
+

+ 1 - 1
wamr-compiler/main.c

@@ -14,7 +14,7 @@ print_help()
 {
   printf("Usage: wamrc [options] -o output_file wasm_file\n");
   printf("  --target=<arch-name>      Set the target arch, which has the general format: <arch><sub>\n");
-  printf("                            <arch> = x86_64, i386, aarch64, arm, thumb, mips.\n");
+  printf("                            <arch> = x86_64, i386, aarch64, arm, thumb, xtensa, mips.\n");
   printf("                              Default is host arch, e.g. x86_64\n");
   printf("                            <sub> = for ex. on arm or thumb: v5, v6m, v7a, v7m, etc.\n");
   printf("                            Use --target=help to list supported targets\n");