diff options
Diffstat (limited to 'fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_emit_aot_file.c')
-rw-r--r-- | fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_emit_aot_file.c | 2930 |
1 files changed, 2930 insertions, 0 deletions
diff --git a/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_emit_aot_file.c b/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_emit_aot_file.c new file mode 100644 index 000000000..62bb809da --- /dev/null +++ b/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_emit_aot_file.c @@ -0,0 +1,2930 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "aot_compiler.h" +#include "../aot/aot_runtime.h" + +#define PUT_U64_TO_ADDR(addr, value) \ + do { \ + union { \ + uint64 val; \ + uint32 parts[2]; \ + } u; \ + u.val = (value); \ + ((uint32 *)(addr))[0] = u.parts[0]; \ + ((uint32 *)(addr))[1] = u.parts[1]; \ + } while (0) + +#define CHECK_SIZE(size) \ + do { \ + if (size == (uint32)-1) { \ + aot_set_last_error("get symbol size failed."); \ + return (uint32)-1; \ + } \ + } while (0) + +static bool +check_utf8_str(const uint8 *str, uint32 len) +{ + /* The valid ranges are taken from page 125, below link + https://www.unicode.org/versions/Unicode9.0.0/ch03.pdf */ + const uint8 *p = str, *p_end = str + len; + uint8 chr; + + while (p < p_end) { + chr = *p; + if (chr < 0x80) { + p++; + } + else if (chr >= 0xC2 && chr <= 0xDF && p + 1 < p_end) { + if (p[1] < 0x80 || p[1] > 0xBF) { + return false; + } + p += 2; + } + else if (chr >= 0xE0 && chr <= 0xEF && p + 2 < p_end) { + if (chr == 0xE0) { + if (p[1] < 0xA0 || p[1] > 0xBF || p[2] < 0x80 || p[2] > 0xBF) { + return false; + } + } + else if (chr == 0xED) { + if (p[1] < 0x80 || p[1] > 0x9F || p[2] < 0x80 || p[2] > 0xBF) { + return false; + } + } + else if (chr >= 0xE1 && chr <= 0xEF) { + if (p[1] < 0x80 || p[1] > 0xBF || p[2] < 0x80 || p[2] > 0xBF) { + return false; + } + } + p += 3; + } + else if (chr >= 0xF0 && chr <= 0xF4 && p + 3 < p_end) { + if (chr == 0xF0) { + if (p[1] < 0x90 || p[1] > 0xBF || p[2] < 0x80 || p[2] > 0xBF + || p[3] < 0x80 || p[3] > 0xBF) { + return false; + } + } + else if (chr >= 0xF1 && chr <= 0xF3) { + if (p[1] < 0x80 || p[1] > 0xBF || p[2] < 0x80 || p[2] > 0xBF + || p[3] < 0x80 || p[3] > 0xBF) { + return false; + } + } + else if (chr == 0xF4) { + if (p[1] < 0x80 || p[1] > 0x8F || p[2] < 0x80 || p[2] > 0xBF + || p[3] < 0x80 || p[3] > 0xBF) { + return false; + } + } + p += 4; + } + else { + return false; + } + } + return (p == p_end); +} + +/* Internal function in object file */ +typedef struct AOTObjectFunc { + char *func_name; + uint64 text_offset; +} AOTObjectFunc; + +/* Symbol table list node */ +typedef struct AOTSymbolNode { + struct AOTSymbolNode *next; + uint32 str_len; + char *symbol; +} AOTSymbolNode; + +typedef struct AOTSymbolList { + AOTSymbolNode *head; + AOTSymbolNode *end; + uint32 len; +} AOTSymbolList; + +/* AOT object data */ +typedef struct AOTObjectData { + LLVMMemoryBufferRef mem_buf; + LLVMBinaryRef binary; + + AOTTargetInfo target_info; + + void *text; + uint32 text_size; + + /* literal data and size */ + void *literal; + uint32 literal_size; + + AOTObjectDataSection *data_sections; + uint32 data_sections_count; + + AOTObjectFunc *funcs; + uint32 func_count; + + AOTSymbolList symbol_list; + AOTRelocationGroup *relocation_groups; + uint32 relocation_group_count; +} AOTObjectData; + +#if 0 +static void dump_buf(uint8 *buf, uint32 size, char *title) +{ + int i; + printf("------ %s -------", title); + for (i = 0; i < size; i++) { + if ((i % 16) == 0) + printf("\n"); + printf("%02x ", (unsigned char)buf[i]); + } + printf("\n\n"); +} +#endif + +static bool +is_32bit_binary(const AOTObjectData *obj_data) +{ + /* bit 1: 0 is 32-bit, 1 is 64-bit */ + return obj_data->target_info.bin_type & 2 ? false : true; +} + +static bool +is_little_endian_binary(const AOTObjectData *obj_data) +{ + /* bit 0: 0 is little-endian, 1 is big-endian */ + return obj_data->target_info.bin_type & 1 ? false : true; +} + +static bool +str_starts_with(const char *str, const char *prefix) +{ + size_t len_pre = strlen(prefix), len_str = strlen(str); + return (len_str >= len_pre) && !memcmp(str, prefix, len_pre); +} + +static uint32 +get_file_header_size() +{ + /* magic number (4 bytes) + version (4 bytes) */ + return sizeof(uint32) + sizeof(uint32); +} + +static uint32 +get_string_size(AOTCompContext *comp_ctx, const char *s) +{ + /* string size (2 bytes) + string content */ + return (uint32)sizeof(uint16) + (uint32)strlen(s) + + /* emit string with '\0' only in XIP mode */ + (comp_ctx->is_indirect_mode ? 1 : 0); +} + +static uint32 +get_target_info_section_size() +{ + return sizeof(AOTTargetInfo); +} + +static uint32 +get_mem_init_data_size(AOTMemInitData *mem_init_data) +{ + /* init expr type (4 bytes) + init expr value (8 bytes) + + byte count (4 bytes) + bytes */ + uint32 total_size = (uint32)(sizeof(uint32) + sizeof(uint64) + + sizeof(uint32) + mem_init_data->byte_count); + + /* bulk_memory enabled: + is_passive (4 bytes) + memory_index (4 bytes) + bulk memory disabled: + placeholder (4 bytes) + placeholder (4 bytes) + */ + total_size += (sizeof(uint32) + sizeof(uint32)); + + return total_size; +} + +static uint32 +get_mem_init_data_list_size(AOTMemInitData **mem_init_data_list, + uint32 mem_init_data_count) +{ + AOTMemInitData **mem_init_data = mem_init_data_list; + uint32 size = 0, i; + + for (i = 0; i < mem_init_data_count; i++, mem_init_data++) { + size = align_uint(size, 4); + size += get_mem_init_data_size(*mem_init_data); + } + return size; +} + +static uint32 +get_import_memory_size(AOTCompData *comp_data) +{ + /* currently we only emit import_memory_count = 0 */ + return sizeof(uint32); +} + +static uint32 +get_memory_size(AOTCompData *comp_data) +{ + /* memory_count + count * (memory_flags + num_bytes_per_page + + init_page_count + max_page_count) */ + return (uint32)(sizeof(uint32) + + comp_data->memory_count * sizeof(uint32) * 4); +} + +static uint32 +get_mem_info_size(AOTCompData *comp_data) +{ + /* import_memory_size + memory_size + + init_data_count + init_data_list */ + return get_import_memory_size(comp_data) + get_memory_size(comp_data) + + (uint32)sizeof(uint32) + + get_mem_init_data_list_size(comp_data->mem_init_data_list, + comp_data->mem_init_data_count); +} + +static uint32 +get_table_init_data_size(AOTTableInitData *table_init_data) +{ + /* + * mode (4 bytes), elem_type (4 bytes), do not need is_dropped field + * + * table_index(4 bytes) + init expr type (4 bytes) + init expr value (8 + * bytes) + * + func index count (4 bytes) + func indexes + */ + return (uint32)(sizeof(uint32) * 2 + sizeof(uint32) + sizeof(uint32) + + sizeof(uint64) + sizeof(uint32) + + sizeof(uint32) * table_init_data->func_index_count); +} + +static uint32 +get_table_init_data_list_size(AOTTableInitData **table_init_data_list, + uint32 table_init_data_count) +{ + /* + * ------------------------------ + * | table_init_data_count + * ------------------------------ + * | | U32 mode + * | AOTTableInitData[N] | U32 elem_type + * | | U32 table_index + * | | U32 offset.init_expr_type + * | | U64 offset.u.i64 + * | | U32 func_index_count + * | | U32[func_index_count] + * ------------------------------ + */ + AOTTableInitData **table_init_data = table_init_data_list; + uint32 size = 0, i; + + size = (uint32)sizeof(uint32); + + for (i = 0; i < table_init_data_count; i++, table_init_data++) { + size = align_uint(size, 4); + size += get_table_init_data_size(*table_init_data); + } + return size; +} + +static uint32 +get_import_table_size(AOTCompData *comp_data) +{ + /* + * ------------------------------ + * | import_table_count + * ------------------------------ + * | | U32 table_init_size + * | | ---------------------- + * | AOTImpotTable[N] | U32 table_init_size + * | | ---------------------- + * | | U32 possible_grow (convenient than U8) + * ------------------------------ + */ + return (uint32)(sizeof(uint32) + + comp_data->import_table_count * (sizeof(uint32) * 3)); +} + +static uint32 +get_table_size(AOTCompData *comp_data) +{ + /* + * ------------------------------ + * | table_count + * ------------------------------ + * | | U32 elem_type + * | AOTTable[N] | U32 table_flags + * | | U32 table_init_size + * | | U32 table_max_size + * | | U32 possible_grow (convenient than U8) + * ------------------------------ + */ + return (uint32)(sizeof(uint32) + + comp_data->table_count * (sizeof(uint32) * 5)); +} + +static uint32 +get_table_info_size(AOTCompData *comp_data) +{ + /* + * ------------------------------ + * | import_table_count + * ------------------------------ + * | + * | AOTImportTable[import_table_count] + * | + * ------------------------------ + * | table_count + * ------------------------------ + * | + * | AOTTable[table_count] + * | + * ------------------------------ + * | table_init_data_count + * ------------------------------ + * | + * | AOTTableInitData*[table_init_data_count] + * | + * ------------------------------ + */ + return get_import_table_size(comp_data) + get_table_size(comp_data) + + get_table_init_data_list_size(comp_data->table_init_data_list, + comp_data->table_init_data_count); +} + +static uint32 +get_func_type_size(AOTFuncType *func_type) +{ + /* param count + result count + types */ + return (uint32)sizeof(uint32) * 2 + func_type->param_count + + func_type->result_count; +} + +static uint32 +get_func_types_size(AOTFuncType **func_types, uint32 func_type_count) +{ + AOTFuncType **func_type = func_types; + uint32 size = 0, i; + + for (i = 0; i < func_type_count; i++, func_type++) { + size = align_uint(size, 4); + size += get_func_type_size(*func_type); + } + return size; +} + +static uint32 +get_func_type_info_size(AOTCompData *comp_data) +{ + /* func type count + func type list */ + return (uint32)sizeof(uint32) + + get_func_types_size(comp_data->func_types, + comp_data->func_type_count); +} + +static uint32 +get_import_global_size(AOTCompContext *comp_ctx, AOTImportGlobal *import_global) +{ + /* type (1 byte) + is_mutable (1 byte) + module_name + global_name */ + uint32 size = (uint32)sizeof(uint8) * 2 + + get_string_size(comp_ctx, import_global->module_name); + size = align_uint(size, 2); + size += get_string_size(comp_ctx, import_global->global_name); + return size; +} + +static uint32 +get_import_globals_size(AOTCompContext *comp_ctx, + AOTImportGlobal *import_globals, + uint32 import_global_count) +{ + AOTImportGlobal *import_global = import_globals; + uint32 size = 0, i; + + for (i = 0; i < import_global_count; i++, import_global++) { + size = align_uint(size, 2); + size += get_import_global_size(comp_ctx, import_global); + } + return size; +} + +static uint32 +get_import_global_info_size(AOTCompContext *comp_ctx, AOTCompData *comp_data) +{ + /* import global count + import globals */ + return (uint32)sizeof(uint32) + + get_import_globals_size(comp_ctx, comp_data->import_globals, + comp_data->import_global_count); +} + +static uint32 +get_global_size(AOTGlobal *global) +{ + if (global->init_expr.init_expr_type != INIT_EXPR_TYPE_V128_CONST) + /* type (1 byte) + is_mutable (1 byte) + + init expr type (2 byes) + init expr value (8 byes) */ + return sizeof(uint8) * 2 + sizeof(uint16) + sizeof(uint64); + else + /* type (1 byte) + is_mutable (1 byte) + + init expr type (2 byes) + v128 value (16 byes) */ + return sizeof(uint8) * 2 + sizeof(uint16) + sizeof(uint64) * 2; +} + +static uint32 +get_globals_size(AOTGlobal *globals, uint32 global_count) +{ + AOTGlobal *global = globals; + uint32 size = 0, i; + + for (i = 0; i < global_count; i++, global++) { + size = align_uint(size, 4); + size += get_global_size(global); + } + return size; +} + +static uint32 +get_global_info_size(AOTCompData *comp_data) +{ + /* global count + globals */ + return (uint32)sizeof(uint32) + + get_globals_size(comp_data->globals, comp_data->global_count); +} + +static uint32 +get_import_func_size(AOTCompContext *comp_ctx, AOTImportFunc *import_func) +{ + /* type index (2 bytes) + module_name + func_name */ + uint32 size = (uint32)sizeof(uint16) + + get_string_size(comp_ctx, import_func->module_name); + size = align_uint(size, 2); + size += get_string_size(comp_ctx, import_func->func_name); + return size; +} + +static uint32 +get_import_funcs_size(AOTCompContext *comp_ctx, AOTImportFunc *import_funcs, + uint32 import_func_count) +{ + AOTImportFunc *import_func = import_funcs; + uint32 size = 0, i; + + for (i = 0; i < import_func_count; i++, import_func++) { + size = align_uint(size, 2); + size += get_import_func_size(comp_ctx, import_func); + } + return size; +} + +static uint32 +get_import_func_info_size(AOTCompContext *comp_ctx, AOTCompData *comp_data) +{ + /* import func count + import funcs */ + return (uint32)sizeof(uint32) + + get_import_funcs_size(comp_ctx, comp_data->import_funcs, + comp_data->import_func_count); +} + +static uint32 +get_object_data_sections_size(AOTCompContext *comp_ctx, + AOTObjectDataSection *data_sections, + uint32 data_sections_count) +{ + AOTObjectDataSection *data_section = data_sections; + uint32 size = 0, i; + + for (i = 0; i < data_sections_count; i++, data_section++) { + /* name + size + data */ + size = align_uint(size, 2); + size += get_string_size(comp_ctx, data_section->name); + size = align_uint(size, 4); + size += (uint32)sizeof(uint32); + size += data_section->size; + } + return size; +} + +static uint32 +get_object_data_section_info_size(AOTCompContext *comp_ctx, + AOTObjectData *obj_data) +{ + /* data sections count + data sections */ + return (uint32)sizeof(uint32) + + get_object_data_sections_size(comp_ctx, obj_data->data_sections, + obj_data->data_sections_count); +} + +static uint32 +get_init_data_section_size(AOTCompContext *comp_ctx, AOTCompData *comp_data, + AOTObjectData *obj_data) +{ + uint32 size = 0; + + size += get_mem_info_size(comp_data); + + size = align_uint(size, 4); + size += get_table_info_size(comp_data); + + size = align_uint(size, 4); + size += get_func_type_info_size(comp_data); + + size = align_uint(size, 4); + size += get_import_global_info_size(comp_ctx, comp_data); + + size = align_uint(size, 4); + size += get_global_info_size(comp_data); + + size = align_uint(size, 4); + size += get_import_func_info_size(comp_ctx, comp_data); + + /* func count + start func index */ + size = align_uint(size, 4); + size += (uint32)sizeof(uint32) * 2; + + /* aux data/heap/stack data */ + size += sizeof(uint32) * 7; + + size += get_object_data_section_info_size(comp_ctx, obj_data); + return size; +} + +static uint32 +get_text_section_size(AOTObjectData *obj_data) +{ + return (sizeof(uint32) + obj_data->literal_size + obj_data->text_size + 3) + & ~3; +} + +static uint32 +get_func_section_size(AOTCompData *comp_data, AOTObjectData *obj_data) +{ + /* text offsets + function type indexs */ + uint32 size = 0; + + if (is_32bit_binary(obj_data)) + size = (uint32)sizeof(uint32) * comp_data->func_count; + else + size = (uint32)sizeof(uint64) * comp_data->func_count; + + size += (uint32)sizeof(uint32) * comp_data->func_count; + return size; +} + +static uint32 +get_export_size(AOTCompContext *comp_ctx, AOTExport *export) +{ + /* export index + export kind + 1 byte padding + export name */ + return (uint32)sizeof(uint32) + sizeof(uint8) + 1 + + get_string_size(comp_ctx, export->name); +} + +static uint32 +get_exports_size(AOTCompContext *comp_ctx, AOTExport *exports, + uint32 export_count) +{ + AOTExport *export = exports; + uint32 size = 0, i; + + for (i = 0; i < export_count; i++, export ++) { + size = align_uint(size, 4); + size += get_export_size(comp_ctx, export); + } + return size; +} + +static uint32 +get_export_section_size(AOTCompContext *comp_ctx, AOTCompData *comp_data) +{ + /* export count + exports */ + return (uint32)sizeof(uint32) + + get_exports_size(comp_ctx, comp_data->wasm_module->exports, + comp_data->wasm_module->export_count); +} + +static uint32 +get_relocation_size(AOTRelocation *relocation, bool is_32bin) +{ + /* offset + addend + relocation type + symbol name */ + uint32 size = 0; + if (is_32bin) + size = sizeof(uint32) * 2; /* offset and addend */ + else + size = sizeof(uint64) * 2; /* offset and addend */ + size += (uint32)sizeof(uint32); /* relocation type */ + size += (uint32)sizeof(uint32); /* symbol name index */ + return size; +} + +static uint32 +get_relocations_size(AOTRelocation *relocations, uint32 relocation_count, + bool is_32bin) +{ + AOTRelocation *relocation = relocations; + uint32 size = 0, i; + + for (i = 0; i < relocation_count; i++, relocation++) { + size = align_uint(size, 4); + size += get_relocation_size(relocation, is_32bin); + } + return size; +} + +static uint32 +get_relocation_group_size(AOTRelocationGroup *relocation_group, bool is_32bin) +{ + uint32 size = 0; + /* section name index + relocation count + relocations */ + size += (uint32)sizeof(uint32); + size += (uint32)sizeof(uint32); + size += get_relocations_size(relocation_group->relocations, + relocation_group->relocation_count, is_32bin); + return size; +} + +static uint32 +get_relocation_groups_size(AOTRelocationGroup *relocation_groups, + uint32 relocation_group_count, bool is_32bin) +{ + AOTRelocationGroup *relocation_group = relocation_groups; + uint32 size = 0, i; + + for (i = 0; i < relocation_group_count; i++, relocation_group++) { + size = align_uint(size, 4); + size += get_relocation_group_size(relocation_group, is_32bin); + } + return size; +} + +/* return the index (in order of insertion) of the symbol, + create if not exits, -1 if failed */ +static uint32 +get_relocation_symbol_index(const char *symbol_name, bool *is_new, + AOTSymbolList *symbol_list) +{ + AOTSymbolNode *sym; + uint32 index = 0; + + sym = symbol_list->head; + while (sym) { + if (!strcmp(sym->symbol, symbol_name)) { + if (is_new) + *is_new = false; + return index; + } + + sym = sym->next; + index++; + } + + /* Not found in symbol_list, add it */ + sym = wasm_runtime_malloc(sizeof(AOTSymbolNode)); + if (!sym) { + return (uint32)-1; + } + + memset(sym, 0, sizeof(AOTSymbolNode)); + sym->symbol = (char *)symbol_name; + sym->str_len = (uint32)strlen(symbol_name); + + if (!symbol_list->head) { + symbol_list->head = symbol_list->end = sym; + } + else { + symbol_list->end->next = sym; + symbol_list->end = sym; + } + symbol_list->len++; + + if (is_new) + *is_new = true; + return index; +} + +static uint32 +get_relocation_symbol_size(AOTCompContext *comp_ctx, AOTRelocation *relocation, + AOTSymbolList *symbol_list) +{ + uint32 size = 0, index = 0; + bool is_new = false; + + index = get_relocation_symbol_index(relocation->symbol_name, &is_new, + symbol_list); + CHECK_SIZE(index); + + if (is_new) { + size += get_string_size(comp_ctx, relocation->symbol_name); + size = align_uint(size, 2); + } + + relocation->symbol_index = index; + return size; +} + +static uint32 +get_relocations_symbol_size(AOTCompContext *comp_ctx, + AOTRelocation *relocations, uint32 relocation_count, + AOTSymbolList *symbol_list) +{ + AOTRelocation *relocation = relocations; + uint32 size = 0, curr_size, i; + + for (i = 0; i < relocation_count; i++, relocation++) { + curr_size = + get_relocation_symbol_size(comp_ctx, relocation, symbol_list); + CHECK_SIZE(curr_size); + + size += curr_size; + } + return size; +} + +static uint32 +get_relocation_group_symbol_size(AOTCompContext *comp_ctx, + AOTRelocationGroup *relocation_group, + AOTSymbolList *symbol_list) +{ + uint32 size = 0, index = 0, curr_size; + bool is_new = false; + + index = get_relocation_symbol_index(relocation_group->section_name, &is_new, + symbol_list); + CHECK_SIZE(index); + + if (is_new) { + size += get_string_size(comp_ctx, relocation_group->section_name); + size = align_uint(size, 2); + } + + relocation_group->name_index = index; + + curr_size = get_relocations_symbol_size( + comp_ctx, relocation_group->relocations, + relocation_group->relocation_count, symbol_list); + CHECK_SIZE(curr_size); + size += curr_size; + + return size; +} + +static uint32 +get_relocation_groups_symbol_size(AOTCompContext *comp_ctx, + AOTRelocationGroup *relocation_groups, + uint32 relocation_group_count, + AOTSymbolList *symbol_list) +{ + AOTRelocationGroup *relocation_group = relocation_groups; + uint32 size = 0, curr_size, i; + + for (i = 0; i < relocation_group_count; i++, relocation_group++) { + curr_size = get_relocation_group_symbol_size(comp_ctx, relocation_group, + symbol_list); + CHECK_SIZE(curr_size); + size += curr_size; + } + return size; +} + +static uint32 +get_symbol_size_from_symbol_list(AOTCompContext *comp_ctx, + AOTSymbolList *symbol_list) +{ + AOTSymbolNode *sym; + uint32 size = 0; + + sym = symbol_list->head; + while (sym) { + /* (uint16)str_len + str */ + size += get_string_size(comp_ctx, sym->symbol); + size = align_uint(size, 2); + sym = sym->next; + } + + return size; +} + +static uint32 +get_relocation_section_symbol_size(AOTCompContext *comp_ctx, + AOTObjectData *obj_data) +{ + AOTRelocationGroup *relocation_groups = obj_data->relocation_groups; + uint32 relocation_group_count = obj_data->relocation_group_count; + uint32 string_count = 0, symbol_table_size = 0; + + /* section size will be calculated twice, + get symbol size from symbol list directly in the second calculation */ + if (obj_data->symbol_list.len > 0) { + symbol_table_size = + get_symbol_size_from_symbol_list(comp_ctx, &obj_data->symbol_list); + } + else { + symbol_table_size = get_relocation_groups_symbol_size( + comp_ctx, relocation_groups, relocation_group_count, + &obj_data->symbol_list); + } + CHECK_SIZE(symbol_table_size); + string_count = obj_data->symbol_list.len; + + /* string_count + string_offsets + total_string_len + + [str (string_len + str)] */ + return (uint32)(sizeof(uint32) + sizeof(uint32) * string_count + + sizeof(uint32) + symbol_table_size); +} + +static uint32 +get_relocation_section_size(AOTCompContext *comp_ctx, AOTObjectData *obj_data) +{ + AOTRelocationGroup *relocation_groups = obj_data->relocation_groups; + uint32 relocation_group_count = obj_data->relocation_group_count; + uint32 symbol_table_size = 0; + + symbol_table_size = get_relocation_section_symbol_size(comp_ctx, obj_data); + CHECK_SIZE(symbol_table_size); + symbol_table_size = align_uint(symbol_table_size, 4); + + /* relocation group count + symbol_table + relocation groups */ + return (uint32)sizeof(uint32) + symbol_table_size + + get_relocation_groups_size(relocation_groups, + relocation_group_count, + is_32bit_binary(obj_data)); +} + +static uint32 +get_native_symbol_list_size(AOTCompContext *comp_ctx) +{ + uint32 len = 0; + AOTNativeSymbol *sym = NULL; + + sym = bh_list_first_elem(&comp_ctx->native_symbols); + + while (sym) { + len = align_uint(len, 2); + len += get_string_size(comp_ctx, sym->symbol); + sym = bh_list_elem_next(sym); + } + + return len; +} + +static uint32 +get_name_section_size(AOTCompData *comp_data); + +static uint32 +get_custom_sections_size(AOTCompContext *comp_ctx, AOTCompData *comp_data); + +static uint32 +get_aot_file_size(AOTCompContext *comp_ctx, AOTCompData *comp_data, + AOTObjectData *obj_data) +{ + uint32 size = 0; + uint32 size_custom_section = 0; + + /* aot file header */ + size += get_file_header_size(); + + /* target info section */ + size = align_uint(size, 4); + /* section id + section size */ + size += (uint32)sizeof(uint32) * 2; + size += get_target_info_section_size(); + + /* init data section */ + size = align_uint(size, 4); + /* section id + section size */ + size += (uint32)sizeof(uint32) * 2; + size += get_init_data_section_size(comp_ctx, comp_data, obj_data); + + /* text section */ + size = align_uint(size, 4); + /* section id + section size */ + size += (uint32)sizeof(uint32) * 2; + size += get_text_section_size(obj_data); + + /* function section */ + size = align_uint(size, 4); + /* section id + section size */ + size += (uint32)sizeof(uint32) * 2; + size += get_func_section_size(comp_data, obj_data); + + /* export section */ + size = align_uint(size, 4); + /* section id + section size */ + size += (uint32)sizeof(uint32) * 2; + size += get_export_section_size(comp_ctx, comp_data); + + /* relocation section */ + size = align_uint(size, 4); + /* section id + section size */ + size += (uint32)sizeof(uint32) * 2; + size += get_relocation_section_size(comp_ctx, obj_data); + + if (get_native_symbol_list_size(comp_ctx) > 0) { + /* emit only when there are native symbols */ + size = align_uint(size, 4); + /* section id + section size + sub section id + symbol count */ + size += (uint32)sizeof(uint32) * 4; + size += get_native_symbol_list_size(comp_ctx); + } + + if (comp_ctx->enable_aux_stack_frame) { + /* custom name section */ + size = align_uint(size, 4); + /* section id + section size + sub section id */ + size += (uint32)sizeof(uint32) * 3; + size += (comp_data->aot_name_section_size = + get_name_section_size(comp_data)); + } + + size_custom_section = get_custom_sections_size(comp_ctx, comp_data); + if (size_custom_section > 0) { + size = align_uint(size, 4); + size += size_custom_section; + } + + return size; +} + +#define exchange_uint8(p_data) (void)0 + +static void +exchange_uint16(uint8 *p_data) +{ + uint8 value = *p_data; + *p_data = *(p_data + 1); + *(p_data + 1) = value; +} + +static void +exchange_uint32(uint8 *p_data) +{ + uint8 value = *p_data; + *p_data = *(p_data + 3); + *(p_data + 3) = value; + + value = *(p_data + 1); + *(p_data + 1) = *(p_data + 2); + *(p_data + 2) = value; +} + +static void +exchange_uint64(uint8 *pData) +{ + uint32 value; + + value = *(uint32 *)pData; + *(uint32 *)pData = *(uint32 *)(pData + 4); + *(uint32 *)(pData + 4) = value; + exchange_uint32(pData); + exchange_uint32(pData + 4); +} + +static void +exchange_uint128(uint8 *pData) +{ + /* swap high 64bit and low 64bit */ + uint64 value = *(uint64 *)pData; + *(uint64 *)pData = *(uint64 *)(pData + 8); + *(uint64 *)(pData + 8) = value; + /* exchange high 64bit */ + exchange_uint64(pData); + /* exchange low 64bit */ + exchange_uint64(pData + 8); +} + +static union { + int a; + char b; +} __ue = { .a = 1 }; + +#define is_little_endian() (__ue.b == 1) + +#define CHECK_BUF(length) \ + do { \ + if (buf + offset + length > buf_end) { \ + aot_set_last_error("buf overflow"); \ + return false; \ + } \ + } while (0) + +#define EMIT_U8(v) \ + do { \ + CHECK_BUF(1); \ + *(uint8 *)(buf + offset) = (uint8)v; \ + offset++; \ + } while (0) + +#define EMIT_U16(v) \ + do { \ + uint16 t = (uint16)v; \ + CHECK_BUF(2); \ + if (!is_little_endian()) \ + exchange_uint16((uint8 *)&t); \ + *(uint16 *)(buf + offset) = t; \ + offset += (uint32)sizeof(uint16); \ + } while (0) + +#define EMIT_U32(v) \ + do { \ + uint32 t = (uint32)v; \ + CHECK_BUF(4); \ + if (!is_little_endian()) \ + exchange_uint32((uint8 *)&t); \ + *(uint32 *)(buf + offset) = t; \ + offset += (uint32)sizeof(uint32); \ + } while (0) + +#define EMIT_U64(v) \ + do { \ + uint64 t = (uint64)v; \ + CHECK_BUF(8); \ + if (!is_little_endian()) \ + exchange_uint64((uint8 *)&t); \ + PUT_U64_TO_ADDR(buf + offset, t); \ + offset += (uint32)sizeof(uint64); \ + } while (0) + +#define EMIT_V128(v) \ + do { \ + uint64 *t = (uint64 *)v.i64x2; \ + CHECK_BUF(16); \ + if (!is_little_endian()) \ + exchange_uint128((uint8 *)t); \ + PUT_U64_TO_ADDR(buf + offset, t[0]); \ + offset += (uint32)sizeof(uint64); \ + PUT_U64_TO_ADDR(buf + offset, t[1]); \ + offset += (uint32)sizeof(uint64); \ + } while (0) + +#define EMIT_BUF(v, len) \ + do { \ + CHECK_BUF(len); \ + memcpy(buf + offset, v, len); \ + offset += len; \ + } while (0) + +#define EMIT_STR(s) \ + do { \ + uint32 str_len = (uint32)strlen(s); \ + if (str_len > INT16_MAX) { \ + aot_set_last_error("emit string failed: " \ + "string too long"); \ + return false; \ + } \ + if (comp_ctx->is_indirect_mode) \ + /* emit '\0' only in XIP mode */ \ + str_len++; \ + EMIT_U16(str_len); \ + EMIT_BUF(s, str_len); \ + } while (0) + +static bool +read_leb(uint8 **p_buf, const uint8 *buf_end, uint32 maxbits, bool sign, + uint64 *p_result) +{ + const uint8 *buf = *p_buf; + uint64 result = 0; + uint32 shift = 0; + uint32 offset = 0, bcnt = 0; + uint64 byte; + + while (true) { + /* uN or SN must not exceed ceil(N/7) bytes */ + if (bcnt + 1 > (maxbits + 6) / 7) { + aot_set_last_error("integer representation too long"); + return false; + } + + if (buf + offset + 1 > buf_end) { + aot_set_last_error("unexpected end of section or function"); + return false; + } + byte = buf[offset]; + offset += 1; + result |= ((byte & 0x7f) << shift); + shift += 7; + bcnt += 1; + if ((byte & 0x80) == 0) { + break; + } + } + + if (!sign && maxbits == 32 && shift >= maxbits) { + /* The top bits set represent values > 32 bits */ + if (((uint8)byte) & 0xf0) + goto fail_integer_too_large; + } + else if (sign && maxbits == 32) { + if (shift < maxbits) { + /* Sign extend, second highest bit is the sign bit */ + if ((uint8)byte & 0x40) + result |= (~((uint64)0)) << shift; + } + else { + /* The top bits should be a sign-extension of the sign bit */ + bool sign_bit_set = ((uint8)byte) & 0x8; + int top_bits = ((uint8)byte) & 0xf0; + if ((sign_bit_set && top_bits != 0x70) + || (!sign_bit_set && top_bits != 0)) + goto fail_integer_too_large; + } + } + else if (sign && maxbits == 64) { + if (shift < maxbits) { + /* Sign extend, second highest bit is the sign bit */ + if ((uint8)byte & 0x40) + result |= (~((uint64)0)) << shift; + } + else { + /* The top bits should be a sign-extension of the sign bit */ + bool sign_bit_set = ((uint8)byte) & 0x1; + int top_bits = ((uint8)byte) & 0xfe; + + if ((sign_bit_set && top_bits != 0x7e) + || (!sign_bit_set && top_bits != 0)) + goto fail_integer_too_large; + } + } + + *p_buf += offset; + *p_result = result; + return true; + +fail_integer_too_large: + aot_set_last_error("integer too large"); + return false; +} + +#define read_leb_uint32(p, p_end, res) \ + do { \ + uint64 res64; \ + if (!read_leb((uint8 **)&p, p_end, 32, false, &res64)) \ + goto fail; \ + res = (uint32)res64; \ + } while (0) + +static uint32 +get_name_section_size(AOTCompData *comp_data) +{ + const uint8 *p = comp_data->name_section_buf, + *p_end = comp_data->name_section_buf_end; + uint8 *buf, *buf_end; + uint32 name_type, subsection_size; + uint32 previous_name_type = 0; + uint32 num_func_name; + uint32 func_index; + uint32 previous_func_index = ~0U; + uint32 func_name_len; + uint32 name_index; + int i = 0; + uint32 name_len; + uint32 offset = 0; + uint32 max_aot_buf_size = 0; + + if (p >= p_end) { + aot_set_last_error("unexpected end"); + return 0; + } + + max_aot_buf_size = 4 * (uint32)(p_end - p); + if (!(buf = comp_data->aot_name_section_buf = + wasm_runtime_malloc(max_aot_buf_size))) { + aot_set_last_error("allocate memory for custom name section failed."); + return 0; + } + buf_end = buf + max_aot_buf_size; + + read_leb_uint32(p, p_end, name_len); + offset = align_uint(offset, 4); + EMIT_U32(name_len); + + if (name_len == 0 || p + name_len > p_end) { + aot_set_last_error("unexpected end"); + return 0; + } + + if (!check_utf8_str(p, name_len)) { + aot_set_last_error("invalid UTF-8 encoding"); + return 0; + } + + if (memcmp(p, "name", 4) != 0) { + aot_set_last_error("invalid custom name section"); + return 0; + } + EMIT_BUF(p, name_len); + p += name_len; + + while (p < p_end) { + read_leb_uint32(p, p_end, name_type); + if (i != 0) { + if (name_type == previous_name_type) { + aot_set_last_error("duplicate sub-section"); + return 0; + } + if (name_type < previous_name_type) { + aot_set_last_error("out-of-order sub-section"); + return 0; + } + } + previous_name_type = name_type; + read_leb_uint32(p, p_end, subsection_size); + switch (name_type) { + case SUB_SECTION_TYPE_FUNC: + if (subsection_size) { + offset = align_uint(offset, 4); + EMIT_U32(name_type); + EMIT_U32(subsection_size); + + read_leb_uint32(p, p_end, num_func_name); + EMIT_U32(num_func_name); + + for (name_index = 0; name_index < num_func_name; + name_index++) { + read_leb_uint32(p, p_end, func_index); + offset = align_uint(offset, 4); + EMIT_U32(func_index); + if (func_index == previous_func_index) { + aot_set_last_error("duplicate function name"); + return 0; + } + if (func_index < previous_func_index + && previous_func_index != ~0U) { + aot_set_last_error("out-of-order function index "); + return 0; + } + previous_func_index = func_index; + read_leb_uint32(p, p_end, func_name_len); + offset = align_uint(offset, 2); + EMIT_U16(func_name_len); + EMIT_BUF(p, func_name_len); + p += func_name_len; + } + } + break; + case SUB_SECTION_TYPE_MODULE: /* TODO: Parse for module subsection + */ + case SUB_SECTION_TYPE_LOCAL: /* TODO: Parse for local subsection */ + default: + p = p + subsection_size; + break; + } + i++; + } + + return offset; +fail: + return 0; +} + +static uint32 +get_custom_sections_size(AOTCompContext *comp_ctx, AOTCompData *comp_data) +{ +#if WASM_ENABLE_LOAD_CUSTOM_SECTION != 0 + uint32 size = 0, i; + + for (i = 0; i < comp_ctx->custom_sections_count; i++) { + const char *section_name = comp_ctx->custom_sections_wp[i]; + const uint8 *content = NULL; + uint32 length = 0; + + content = wasm_loader_get_custom_section(comp_data->wasm_module, + section_name, &length); + if (!content) { + LOG_WARNING("Can't find custom section [%s], ignore it", + section_name); + continue; + } + + size = align_uint(size, 4); + /* section id + section size + sub section id */ + size += (uint32)sizeof(uint32) * 3; + /* section name and len */ + size += get_string_size(comp_ctx, section_name); + /* section content */ + size += length; + } + + return size; +#else + return 0; +#endif +} + +static bool +aot_emit_file_header(uint8 *buf, uint8 *buf_end, uint32 *p_offset, + AOTCompData *comp_data, AOTObjectData *obj_data) +{ + uint32 offset = *p_offset; + uint32 aot_curr_version = AOT_CURRENT_VERSION; + + EMIT_U8('\0'); + EMIT_U8('a'); + EMIT_U8('o'); + EMIT_U8('t'); + + EMIT_U32(aot_curr_version); + + *p_offset = offset; + return true; +} + +static bool +aot_emit_target_info_section(uint8 *buf, uint8 *buf_end, uint32 *p_offset, + AOTCompData *comp_data, AOTObjectData *obj_data) +{ + uint32 offset = *p_offset; + uint32 section_size = get_target_info_section_size(); + AOTTargetInfo *target_info = &obj_data->target_info; + + *p_offset = offset = align_uint(offset, 4); + + EMIT_U32(AOT_SECTION_TYPE_TARGET_INFO); + EMIT_U32(section_size); + + EMIT_U16(target_info->bin_type); + EMIT_U16(target_info->abi_type); + EMIT_U16(target_info->e_type); + EMIT_U16(target_info->e_machine); + EMIT_U32(target_info->e_version); + EMIT_U32(target_info->e_flags); + EMIT_U32(target_info->reserved); + EMIT_BUF(target_info->arch, sizeof(target_info->arch)); + + if (offset - *p_offset != section_size + sizeof(uint32) * 2) { + aot_set_last_error("emit target info failed."); + return false; + } + + *p_offset = offset; + + return true; +} + +static bool +aot_emit_mem_info(uint8 *buf, uint8 *buf_end, uint32 *p_offset, + AOTCompContext *comp_ctx, AOTCompData *comp_data, + AOTObjectData *obj_data) +{ + uint32 offset = *p_offset, i; + AOTMemInitData **init_datas = comp_data->mem_init_data_list; + + *p_offset = offset = align_uint(offset, 4); + + /* Emit import memory count, only emit 0 currently. + TODO: emit the actual import memory count and + the full import memory info. */ + EMIT_U32(0); + + /* Emit memory count */ + EMIT_U32(comp_data->memory_count); + /* Emit memory items */ + for (i = 0; i < comp_data->memory_count; i++) { + EMIT_U32(comp_data->memories[i].memory_flags); + EMIT_U32(comp_data->memories[i].num_bytes_per_page); + EMIT_U32(comp_data->memories[i].mem_init_page_count); + EMIT_U32(comp_data->memories[i].mem_max_page_count); + } + + /* Emit mem init data count */ + EMIT_U32(comp_data->mem_init_data_count); + /* Emit mem init data items */ + for (i = 0; i < comp_data->mem_init_data_count; i++) { + offset = align_uint(offset, 4); +#if WASM_ENABLE_BULK_MEMORY != 0 + if (comp_ctx->enable_bulk_memory) { + EMIT_U32(init_datas[i]->is_passive); + EMIT_U32(init_datas[i]->memory_index); + } + else +#endif + { + /* emit two placeholder to keep the same size */ + EMIT_U32(0); + EMIT_U32(0); + } + EMIT_U32(init_datas[i]->offset.init_expr_type); + EMIT_U64(init_datas[i]->offset.u.i64); + EMIT_U32(init_datas[i]->byte_count); + EMIT_BUF(init_datas[i]->bytes, init_datas[i]->byte_count); + } + + if (offset - *p_offset != get_mem_info_size(comp_data)) { + aot_set_last_error("emit memory info failed."); + return false; + } + + *p_offset = offset; + + return true; +} + +static bool +aot_emit_table_info(uint8 *buf, uint8 *buf_end, uint32 *p_offset, + AOTCompContext *comp_ctx, AOTCompData *comp_data, + AOTObjectData *obj_data) +{ + uint32 offset = *p_offset, i, j; + AOTTableInitData **init_datas = comp_data->table_init_data_list; + + *p_offset = offset = align_uint(offset, 4); + + /* Emit import table count */ + EMIT_U32(comp_data->import_table_count); + /* Emit table items */ + for (i = 0; i < comp_data->import_table_count; i++) { + /* TODO: + * EMIT_STR(comp_data->import_tables[i].module_name ); + * EMIT_STR(comp_data->import_tables[i].table_name); + */ + EMIT_U32(comp_data->import_tables[i].elem_type); + EMIT_U32(comp_data->import_tables[i].table_init_size); + EMIT_U32(comp_data->import_tables[i].table_max_size); + EMIT_U32(comp_data->import_tables[i].possible_grow & 0x000000FF); + } + + /* Emit table count */ + EMIT_U32(comp_data->table_count); + /* Emit table items */ + for (i = 0; i < comp_data->table_count; i++) { + EMIT_U32(comp_data->tables[i].elem_type); + EMIT_U32(comp_data->tables[i].table_flags); + EMIT_U32(comp_data->tables[i].table_init_size); + EMIT_U32(comp_data->tables[i].table_max_size); + EMIT_U32(comp_data->tables[i].possible_grow & 0x000000FF); + } + + /* Emit table init data count */ + EMIT_U32(comp_data->table_init_data_count); + /* Emit table init data items */ + for (i = 0; i < comp_data->table_init_data_count; i++) { + offset = align_uint(offset, 4); + EMIT_U32(init_datas[i]->mode); + EMIT_U32(init_datas[i]->elem_type); + EMIT_U32(init_datas[i]->table_index); + EMIT_U32(init_datas[i]->offset.init_expr_type); + EMIT_U64(init_datas[i]->offset.u.i64); + EMIT_U32(init_datas[i]->func_index_count); + for (j = 0; j < init_datas[i]->func_index_count; j++) + EMIT_U32(init_datas[i]->func_indexes[j]); + } + + if (offset - *p_offset != get_table_info_size(comp_data)) { + aot_set_last_error("emit table info failed."); + return false; + } + + *p_offset = offset; + + return true; +} + +static bool +aot_emit_func_type_info(uint8 *buf, uint8 *buf_end, uint32 *p_offset, + AOTCompData *comp_data, AOTObjectData *obj_data) +{ + uint32 offset = *p_offset, i; + AOTFuncType **func_types = comp_data->func_types; + + *p_offset = offset = align_uint(offset, 4); + + EMIT_U32(comp_data->func_type_count); + + for (i = 0; i < comp_data->func_type_count; i++) { + offset = align_uint(offset, 4); + EMIT_U32(func_types[i]->param_count); + EMIT_U32(func_types[i]->result_count); + EMIT_BUF(func_types[i]->types, + func_types[i]->param_count + func_types[i]->result_count); + } + + if (offset - *p_offset != get_func_type_info_size(comp_data)) { + aot_set_last_error("emit function type info failed."); + return false; + } + + *p_offset = offset; + + return true; +} + +static bool +aot_emit_import_global_info(uint8 *buf, uint8 *buf_end, uint32 *p_offset, + AOTCompContext *comp_ctx, AOTCompData *comp_data, + AOTObjectData *obj_data) +{ + uint32 offset = *p_offset, i; + AOTImportGlobal *import_global = comp_data->import_globals; + + *p_offset = offset = align_uint(offset, 4); + + EMIT_U32(comp_data->import_global_count); + + for (i = 0; i < comp_data->import_global_count; i++, import_global++) { + offset = align_uint(offset, 2); + EMIT_U8(import_global->type); + EMIT_U8(import_global->is_mutable); + EMIT_STR(import_global->module_name); + offset = align_uint(offset, 2); + EMIT_STR(import_global->global_name); + } + + if (offset - *p_offset + != get_import_global_info_size(comp_ctx, comp_data)) { + aot_set_last_error("emit import global info failed."); + return false; + } + + *p_offset = offset; + + return true; +} + +static bool +aot_emit_global_info(uint8 *buf, uint8 *buf_end, uint32 *p_offset, + AOTCompData *comp_data, AOTObjectData *obj_data) +{ + uint32 offset = *p_offset, i; + AOTGlobal *global = comp_data->globals; + + *p_offset = offset = align_uint(offset, 4); + + EMIT_U32(comp_data->global_count); + + for (i = 0; i < comp_data->global_count; i++, global++) { + offset = align_uint(offset, 4); + EMIT_U8(global->type); + EMIT_U8(global->is_mutable); + EMIT_U16(global->init_expr.init_expr_type); + if (global->init_expr.init_expr_type != INIT_EXPR_TYPE_V128_CONST) + EMIT_U64(global->init_expr.u.i64); + else + EMIT_V128(global->init_expr.u.v128); + } + + if (offset - *p_offset != get_global_info_size(comp_data)) { + aot_set_last_error("emit global info failed."); + return false; + } + + *p_offset = offset; + + return true; +} + +static bool +aot_emit_import_func_info(uint8 *buf, uint8 *buf_end, uint32 *p_offset, + AOTCompContext *comp_ctx, AOTCompData *comp_data, + AOTObjectData *obj_data) +{ + uint32 offset = *p_offset, i; + AOTImportFunc *import_func = comp_data->import_funcs; + + *p_offset = offset = align_uint(offset, 4); + + EMIT_U32(comp_data->import_func_count); + + for (i = 0; i < comp_data->import_func_count; i++, import_func++) { + offset = align_uint(offset, 2); + EMIT_U16(import_func->func_type_index); + EMIT_STR(import_func->module_name); + offset = align_uint(offset, 2); + EMIT_STR(import_func->func_name); + } + + if (offset - *p_offset != get_import_func_info_size(comp_ctx, comp_data)) { + aot_set_last_error("emit import function info failed."); + return false; + } + + *p_offset = offset; + + return true; +} + +static bool +aot_emit_object_data_section_info(uint8 *buf, uint8 *buf_end, uint32 *p_offset, + AOTCompContext *comp_ctx, + AOTObjectData *obj_data) +{ + uint32 offset = *p_offset, i; + AOTObjectDataSection *data_section = obj_data->data_sections; + + *p_offset = offset = align_uint(offset, 4); + + EMIT_U32(obj_data->data_sections_count); + + for (i = 0; i < obj_data->data_sections_count; i++, data_section++) { + offset = align_uint(offset, 2); + EMIT_STR(data_section->name); + offset = align_uint(offset, 4); + EMIT_U32(data_section->size); + EMIT_BUF(data_section->data, data_section->size); + } + + if (offset - *p_offset + != get_object_data_section_info_size(comp_ctx, obj_data)) { + aot_set_last_error("emit object data section info failed."); + return false; + } + + *p_offset = offset; + + return true; +} + +static bool +aot_emit_init_data_section(uint8 *buf, uint8 *buf_end, uint32 *p_offset, + AOTCompContext *comp_ctx, AOTCompData *comp_data, + AOTObjectData *obj_data) +{ + uint32 section_size = + get_init_data_section_size(comp_ctx, comp_data, obj_data); + uint32 offset = *p_offset; + + *p_offset = offset = align_uint(offset, 4); + + EMIT_U32(AOT_SECTION_TYPE_INIT_DATA); + EMIT_U32(section_size); + + if (!aot_emit_mem_info(buf, buf_end, &offset, comp_ctx, comp_data, obj_data) + || !aot_emit_table_info(buf, buf_end, &offset, comp_ctx, comp_data, + obj_data) + || !aot_emit_func_type_info(buf, buf_end, &offset, comp_data, obj_data) + || !aot_emit_import_global_info(buf, buf_end, &offset, comp_ctx, + comp_data, obj_data) + || !aot_emit_global_info(buf, buf_end, &offset, comp_data, obj_data) + || !aot_emit_import_func_info(buf, buf_end, &offset, comp_ctx, + comp_data, obj_data)) + return false; + + offset = align_uint(offset, 4); + EMIT_U32(comp_data->func_count); + EMIT_U32(comp_data->start_func_index); + + EMIT_U32(comp_data->aux_data_end_global_index); + EMIT_U32(comp_data->aux_data_end); + EMIT_U32(comp_data->aux_heap_base_global_index); + EMIT_U32(comp_data->aux_heap_base); + EMIT_U32(comp_data->aux_stack_top_global_index); + EMIT_U32(comp_data->aux_stack_bottom); + EMIT_U32(comp_data->aux_stack_size); + + if (!aot_emit_object_data_section_info(buf, buf_end, &offset, comp_ctx, + obj_data)) + return false; + + if (offset - *p_offset != section_size + sizeof(uint32) * 2) { + aot_set_last_error("emit init data section failed."); + return false; + } + + *p_offset = offset; + + return true; +} + +static bool +aot_emit_text_section(uint8 *buf, uint8 *buf_end, uint32 *p_offset, + AOTCompData *comp_data, AOTObjectData *obj_data) +{ + 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; + } + + *p_offset = offset; + + return true; +} + +static bool +aot_emit_func_section(uint8 *buf, uint8 *buf_end, uint32 *p_offset, + AOTCompData *comp_data, AOTObjectData *obj_data) +{ + uint32 section_size = get_func_section_size(comp_data, obj_data); + uint32 i, offset = *p_offset; + AOTObjectFunc *func = obj_data->funcs; + AOTFunc **funcs = comp_data->funcs; + + *p_offset = offset = align_uint(offset, 4); + + EMIT_U32(AOT_SECTION_TYPE_FUNCTION); + EMIT_U32(section_size); + + for (i = 0; i < obj_data->func_count; i++, func++) { + if (is_32bit_binary(obj_data)) + EMIT_U32(func->text_offset); + else + EMIT_U64(func->text_offset); + } + + for (i = 0; i < comp_data->func_count; i++) + EMIT_U32(funcs[i]->func_type_index); + + if (offset - *p_offset != section_size + sizeof(uint32) * 2) { + aot_set_last_error("emit function section failed."); + return false; + } + + *p_offset = offset; + + return true; +} + +static bool +aot_emit_export_section(uint8 *buf, uint8 *buf_end, uint32 *p_offset, + AOTCompContext *comp_ctx, AOTCompData *comp_data, + AOTObjectData *obj_data) +{ + uint32 section_size = get_export_section_size(comp_ctx, comp_data); + AOTExport *export = comp_data->wasm_module->exports; + uint32 export_count = comp_data->wasm_module->export_count; + uint32 i, offset = *p_offset; + + *p_offset = offset = align_uint(offset, 4); + + EMIT_U32(AOT_SECTION_TYPE_EXPORT); + EMIT_U32(section_size); + EMIT_U32(export_count); + + for (i = 0; i < export_count; i++, export ++) { + offset = align_uint(offset, 4); + EMIT_U32(export->index); + EMIT_U8(export->kind); + EMIT_U8(0); + EMIT_STR(export->name); + } + + if (offset - *p_offset != section_size + sizeof(uint32) * 2) { + aot_set_last_error("emit export section failed."); + return false; + } + + *p_offset = offset; + + return true; +} + +static bool +aot_emit_relocation_symbol_table(uint8 *buf, uint8 *buf_end, uint32 *p_offset, + AOTCompContext *comp_ctx, + AOTCompData *comp_data, + AOTObjectData *obj_data) +{ + uint32 symbol_offset = 0, total_string_len = 0; + uint32 offset = *p_offset; + AOTSymbolNode *sym; + + EMIT_U32(obj_data->symbol_list.len); + + /* emit symbol offsets */ + sym = (AOTSymbolNode *)(obj_data->symbol_list.head); + while (sym) { + EMIT_U32(symbol_offset); + /* string_len + str[0 .. string_len - 1] */ + symbol_offset += get_string_size(comp_ctx, sym->symbol); + symbol_offset = align_uint(symbol_offset, 2); + sym = sym->next; + } + + /* emit total string len */ + total_string_len = symbol_offset; + EMIT_U32(total_string_len); + + /* emit symbols */ + sym = (AOTSymbolNode *)(obj_data->symbol_list.head); + while (sym) { + EMIT_STR(sym->symbol); + offset = align_uint(offset, 2); + sym = sym->next; + } + + *p_offset = offset; + return true; +} + +static bool +aot_emit_relocation_section(uint8 *buf, uint8 *buf_end, uint32 *p_offset, + AOTCompContext *comp_ctx, AOTCompData *comp_data, + AOTObjectData *obj_data) +{ + uint32 section_size = get_relocation_section_size(comp_ctx, obj_data); + uint32 i, offset = *p_offset; + AOTRelocationGroup *relocation_group = obj_data->relocation_groups; + + if (section_size == (uint32)-1) + return false; + + *p_offset = offset = align_uint(offset, 4); + + EMIT_U32(AOT_SECTION_TYPE_RELOCATION); + EMIT_U32(section_size); + + aot_emit_relocation_symbol_table(buf, buf_end, &offset, comp_ctx, comp_data, + obj_data); + + offset = align_uint(offset, 4); + EMIT_U32(obj_data->relocation_group_count); + + /* emit each relocation group */ + for (i = 0; i < obj_data->relocation_group_count; i++, relocation_group++) { + AOTRelocation *relocation = relocation_group->relocations; + uint32 j; + + offset = align_uint(offset, 4); + EMIT_U32(relocation_group->name_index); + offset = align_uint(offset, 4); + EMIT_U32(relocation_group->relocation_count); + + /* emit each relocation */ + for (j = 0; j < relocation_group->relocation_count; j++, relocation++) { + offset = align_uint(offset, 4); + if (is_32bit_binary(obj_data)) { + EMIT_U32(relocation->relocation_offset); + EMIT_U32(relocation->relocation_addend); + } + else { + EMIT_U64(relocation->relocation_offset); + EMIT_U64(relocation->relocation_addend); + } + EMIT_U32(relocation->relocation_type); + EMIT_U32(relocation->symbol_index); + } + } + + if (offset - *p_offset != section_size + sizeof(uint32) * 2) { + aot_set_last_error("emit relocation section failed."); + return false; + } + + *p_offset = offset; + return true; +} + +static bool +aot_emit_native_symbol(uint8 *buf, uint8 *buf_end, uint32 *p_offset, + AOTCompContext *comp_ctx) +{ + uint32 offset = *p_offset; + AOTNativeSymbol *sym = NULL; + + if (bh_list_length(&comp_ctx->native_symbols) == 0) + /* emit only when there are native symbols */ + return true; + + *p_offset = offset = align_uint(offset, 4); + + EMIT_U32(AOT_SECTION_TYPE_CUSTOM); + /* sub section id + symbol count + symbol list */ + EMIT_U32(sizeof(uint32) * 2 + get_native_symbol_list_size(comp_ctx)); + EMIT_U32(AOT_CUSTOM_SECTION_NATIVE_SYMBOL); + EMIT_U32(bh_list_length(&comp_ctx->native_symbols)); + + sym = bh_list_first_elem(&comp_ctx->native_symbols); + + while (sym) { + offset = align_uint(offset, 2); + EMIT_STR(sym->symbol); + sym = bh_list_elem_next(sym); + } + + *p_offset = offset; + + return true; +} + +static bool +aot_emit_name_section(uint8 *buf, uint8 *buf_end, uint32 *p_offset, + AOTCompData *comp_data, AOTCompContext *comp_ctx) +{ + if (comp_ctx->enable_aux_stack_frame) { + uint32 offset = *p_offset; + + *p_offset = offset = align_uint(offset, 4); + + EMIT_U32(AOT_SECTION_TYPE_CUSTOM); + /* sub section id + name section size */ + EMIT_U32(sizeof(uint32) * 1 + comp_data->aot_name_section_size); + EMIT_U32(AOT_CUSTOM_SECTION_NAME); + bh_memcpy_s((uint8 *)(buf + offset), (uint32)(buf_end - buf), + comp_data->aot_name_section_buf, + (uint32)comp_data->aot_name_section_size); + offset += comp_data->aot_name_section_size; + + *p_offset = offset; + } + + return true; +} + +static bool +aot_emit_custom_sections(uint8 *buf, uint8 *buf_end, uint32 *p_offset, + AOTCompData *comp_data, AOTCompContext *comp_ctx) +{ +#if WASM_ENABLE_LOAD_CUSTOM_SECTION != 0 + uint32 offset = *p_offset, i; + + for (i = 0; i < comp_ctx->custom_sections_count; i++) { + const char *section_name = comp_ctx->custom_sections_wp[i]; + const uint8 *content = NULL; + uint32 length = 0; + + content = wasm_loader_get_custom_section(comp_data->wasm_module, + section_name, &length); + if (!content) { + /* Warning has been reported during calculating size */ + continue; + } + + offset = align_uint(offset, 4); + EMIT_U32(AOT_SECTION_TYPE_CUSTOM); + /* sub section id + content */ + EMIT_U32(sizeof(uint32) * 1 + get_string_size(comp_ctx, section_name) + + length); + EMIT_U32(AOT_CUSTOM_SECTION_RAW); + EMIT_STR(section_name); + bh_memcpy_s((uint8 *)(buf + offset), (uint32)(buf_end - buf), content, + length); + offset += length; + } + + *p_offset = offset; +#endif + + return true; +} + +typedef uint32 U32; +typedef int32 I32; +typedef uint16 U16; +typedef uint8 U8; + +struct coff_hdr { + U16 u16Machine; + U16 u16NumSections; + U32 u32DateTimeStamp; + U32 u32SymTblPtr; + U32 u32NumSymbols; + U16 u16PeHdrSize; + U16 u16Characs; +}; + +#define E_TYPE_REL 1 +#define E_TYPE_XIP 4 + +#define IMAGE_FILE_MACHINE_AMD64 0x8664 +#define IMAGE_FILE_MACHINE_I386 0x014c +#define IMAGE_FILE_MACHINE_IA64 0x0200 + +#define AOT_COFF32_BIN_TYPE 4 /* 32-bit little endian */ +#define AOT_COFF64_BIN_TYPE 6 /* 64-bit little endian */ + +#define EI_NIDENT 16 + +typedef uint32 elf32_word; +typedef int32 elf32_sword; +typedef uint16 elf32_half; +typedef uint32 elf32_off; +typedef uint32 elf32_addr; + +struct elf32_ehdr { + unsigned char e_ident[EI_NIDENT]; /* ident bytes */ + elf32_half e_type; /* file type */ + elf32_half e_machine; /* target machine */ + elf32_word e_version; /* file version */ + elf32_addr e_entry; /* start address */ + elf32_off e_phoff; /* phdr file offset */ + elf32_off e_shoff; /* shdr file offset */ + elf32_word e_flags; /* file flags */ + elf32_half e_ehsize; /* sizeof ehdr */ + elf32_half e_phentsize; /* sizeof phdr */ + elf32_half e_phnum; /* number phdrs */ + elf32_half e_shentsize; /* sizeof shdr */ + elf32_half e_shnum; /* number shdrs */ + elf32_half e_shstrndx; /* shdr string index */ +}; + +struct elf32_rel { + elf32_addr r_offset; + elf32_word r_info; +} elf32_rel; + +struct elf32_rela { + elf32_addr r_offset; + elf32_word r_info; + elf32_sword r_addend; +} elf32_rela; + +typedef uint32 elf64_word; +typedef int32 elf64_sword; +typedef uint64 elf64_xword; +typedef int64 elf64_sxword; +typedef uint16 elf64_half; +typedef uint64 elf64_off; +typedef uint64 elf64_addr; + +struct elf64_ehdr { + unsigned char e_ident[EI_NIDENT]; /* ident bytes */ + elf64_half e_type; /* file type */ + elf64_half e_machine; /* target machine */ + elf64_word e_version; /* file version */ + elf64_addr e_entry; /* start address */ + elf64_off e_phoff; /* phdr file offset */ + elf64_off e_shoff; /* shdr file offset */ + elf64_word e_flags; /* file flags */ + elf64_half e_ehsize; /* sizeof ehdr */ + elf64_half e_phentsize; /* sizeof phdr */ + elf64_half e_phnum; /* number phdrs */ + elf64_half e_shentsize; /* sizeof shdr */ + elf64_half e_shnum; /* number shdrs */ + elf64_half e_shstrndx; /* shdr string index */ +}; + +typedef struct elf64_rel { + elf64_addr r_offset; + elf64_xword r_info; +} elf64_rel; + +typedef struct elf64_rela { + elf64_addr r_offset; + elf64_xword r_info; + elf64_sxword r_addend; +} elf64_rela; + +#define SET_TARGET_INFO(f, v, type, little) \ + do { \ + type tmp = elf_header->v; \ + if ((little && !is_little_endian()) \ + || (!little && is_little_endian())) \ + exchange_##type((uint8 *)&tmp); \ + obj_data->target_info.f = tmp; \ + } while (0) + +static bool +aot_resolve_target_info(AOTCompContext *comp_ctx, AOTObjectData *obj_data) +{ + LLVMBinaryType bin_type = LLVMBinaryGetType(obj_data->binary); + const uint8 *elf_buf = (uint8 *)LLVMGetBufferStart(obj_data->mem_buf); + uint32 elf_size = (uint32)LLVMGetBufferSize(obj_data->mem_buf); + + if (bin_type != LLVMBinaryTypeCOFF && bin_type != LLVMBinaryTypeELF32L + && bin_type != LLVMBinaryTypeELF32B && bin_type != LLVMBinaryTypeELF64L + && bin_type != LLVMBinaryTypeELF64B + && bin_type != LLVMBinaryTypeMachO32L + && bin_type != LLVMBinaryTypeMachO32B + && bin_type != LLVMBinaryTypeMachO64L + && bin_type != LLVMBinaryTypeMachO64B) { + aot_set_last_error("invaid llvm binary bin_type."); + return false; + } + + obj_data->target_info.bin_type = bin_type - LLVMBinaryTypeELF32L; + + if (bin_type == LLVMBinaryTypeCOFF) { + struct coff_hdr *coff_header; + + if (!elf_buf || elf_size < sizeof(struct coff_hdr)) { + aot_set_last_error("invalid coff_hdr buffer."); + return false; + } + coff_header = (struct coff_hdr *)elf_buf; + + /* Emit eXecute In Place file type while in indirect mode */ + if (comp_ctx->is_indirect_mode) + obj_data->target_info.e_type = E_TYPE_XIP; + else + obj_data->target_info.e_type = E_TYPE_REL; + + obj_data->target_info.e_machine = coff_header->u16Machine; + obj_data->target_info.e_version = 1; + obj_data->target_info.e_flags = 0; + + if (coff_header->u16Machine == IMAGE_FILE_MACHINE_AMD64 + || coff_header->u16Machine == IMAGE_FILE_MACHINE_IA64) + obj_data->target_info.bin_type = AOT_COFF64_BIN_TYPE; + else if (coff_header->u16Machine == IMAGE_FILE_MACHINE_I386) + obj_data->target_info.bin_type = AOT_COFF32_BIN_TYPE; + } + else if (bin_type == LLVMBinaryTypeELF32L + || bin_type == LLVMBinaryTypeELF32B) { + struct elf32_ehdr *elf_header; + bool is_little_bin = bin_type == LLVMBinaryTypeELF32L; + + if (!elf_buf || elf_size < sizeof(struct elf32_ehdr)) { + aot_set_last_error("invalid elf32 buffer."); + return false; + } + + elf_header = (struct elf32_ehdr *)elf_buf; + + /* Emit eXecute In Place file type while in indirect mode */ + if (comp_ctx->is_indirect_mode) + elf_header->e_type = E_TYPE_XIP; + + SET_TARGET_INFO(e_type, e_type, uint16, is_little_bin); + SET_TARGET_INFO(e_machine, e_machine, uint16, is_little_bin); + SET_TARGET_INFO(e_version, e_version, uint32, is_little_bin); + SET_TARGET_INFO(e_flags, e_flags, uint32, is_little_bin); + } + else if (bin_type == LLVMBinaryTypeELF64L + || bin_type == LLVMBinaryTypeELF64B) { + struct elf64_ehdr *elf_header; + bool is_little_bin = bin_type == LLVMBinaryTypeELF64L; + + if (!elf_buf || elf_size < sizeof(struct elf64_ehdr)) { + aot_set_last_error("invalid elf64 buffer."); + return false; + } + + elf_header = (struct elf64_ehdr *)elf_buf; + + /* Emit eXecute In Place file type while in indirect mode */ + if (comp_ctx->is_indirect_mode) + elf_header->e_type = E_TYPE_XIP; + + SET_TARGET_INFO(e_type, e_type, uint16, is_little_bin); + SET_TARGET_INFO(e_machine, e_machine, uint16, is_little_bin); + SET_TARGET_INFO(e_version, e_version, uint32, is_little_bin); + SET_TARGET_INFO(e_flags, e_flags, uint32, is_little_bin); + } + else if (bin_type == LLVMBinaryTypeMachO32L + || bin_type == LLVMBinaryTypeMachO32B) { + /* TODO: parse file type of Mach-O 32 */ + aot_set_last_error("invaid llvm binary bin_type."); + return false; + } + else if (bin_type == LLVMBinaryTypeMachO64L + || bin_type == LLVMBinaryTypeMachO64B) { + /* TODO: parse file type of Mach-O 64 */ + aot_set_last_error("invaid llvm binary bin_type."); + return false; + } + + bh_assert(sizeof(obj_data->target_info.arch) + == sizeof(comp_ctx->target_arch)); + bh_memcpy_s(obj_data->target_info.arch, sizeof(obj_data->target_info.arch), + comp_ctx->target_arch, sizeof(comp_ctx->target_arch)); + + return true; +} + +static bool +aot_resolve_text(AOTObjectData *obj_data) +{ +#if WASM_ENABLE_DEBUG_AOT != 0 + LLVMBinaryType bin_type = LLVMBinaryGetType(obj_data->binary); + if (bin_type == LLVMBinaryTypeELF32L || bin_type == LLVMBinaryTypeELF64L) { + obj_data->text = (char *)LLVMGetBufferStart(obj_data->mem_buf); + obj_data->text_size = (uint32)LLVMGetBufferSize(obj_data->mem_buf); + } + else +#endif + { + 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, ".text")) { + obj_data->text = (char *)LLVMGetSectionContents(sec_itr); + obj_data->text_size = (uint32)LLVMGetSectionSize(sec_itr); + break; + } + LLVMMoveToNextSection(sec_itr); + } + LLVMDisposeSectionIterator(sec_itr); + } + + 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 +get_relocations_count(LLVMSectionIteratorRef sec_itr, uint32 *p_count); + +static bool +is_data_section(LLVMSectionIteratorRef sec_itr, char *section_name) +{ + uint32 relocation_count = 0; + + return (!strcmp(section_name, ".data") || !strcmp(section_name, ".sdata") + || !strcmp(section_name, ".rodata") + /* ".rodata.cst4/8/16/.." */ + || !strncmp(section_name, ".rodata.cst", strlen(".rodata.cst")) + /* ".rodata.strn.m" */ + || !strncmp(section_name, ".rodata.str", strlen(".rodata.str")) + || (!strcmp(section_name, ".rdata") + && get_relocations_count(sec_itr, &relocation_count) + && relocation_count > 0)); +} + +static bool +get_object_data_sections_count(AOTObjectData *obj_data, uint32 *p_count) +{ + LLVMSectionIteratorRef sec_itr; + char *name; + uint32 count = 0; + + 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)) + && (is_data_section(sec_itr, name))) { + count++; + } + LLVMMoveToNextSection(sec_itr); + } + LLVMDisposeSectionIterator(sec_itr); + + *p_count = count; + return true; +} + +static bool +aot_resolve_object_data_sections(AOTObjectData *obj_data) +{ + LLVMSectionIteratorRef sec_itr; + char *name; + AOTObjectDataSection *data_section; + uint32 sections_count; + uint32 size; + + if (!get_object_data_sections_count(obj_data, §ions_count)) { + return false; + } + + if (sections_count > 0) { + size = (uint32)sizeof(AOTObjectDataSection) * sections_count; + if (!(data_section = obj_data->data_sections = + wasm_runtime_malloc(size))) { + aot_set_last_error("allocate memory for data sections failed."); + return false; + } + memset(obj_data->data_sections, 0, size); + obj_data->data_sections_count = sections_count; + + 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)) + && (is_data_section(sec_itr, name))) { + data_section->name = name; + data_section->data = (uint8 *)LLVMGetSectionContents(sec_itr); + data_section->size = (uint32)LLVMGetSectionSize(sec_itr); + data_section++; + } + LLVMMoveToNextSection(sec_itr); + } + LLVMDisposeSectionIterator(sec_itr); + } + + return true; +} + +static bool +aot_resolve_functions(AOTCompContext *comp_ctx, AOTObjectData *obj_data) +{ + AOTObjectFunc *func; + LLVMSymbolIteratorRef sym_itr; + char *name, *prefix = AOT_FUNC_PREFIX; + uint32 func_index, total_size; + + /* allocate memory for aot function */ + obj_data->func_count = comp_ctx->comp_data->func_count; + if (obj_data->func_count) { + total_size = (uint32)sizeof(AOTObjectFunc) * obj_data->func_count; + if (!(obj_data->funcs = wasm_runtime_malloc(total_size))) { + aot_set_last_error("allocate memory for functions failed."); + return false; + } + memset(obj_data->funcs, 0, total_size); + } + + if (!(sym_itr = LLVMObjectFileCopySymbolIterator(obj_data->binary))) { + aot_set_last_error("llvm get symbol iterator failed."); + return false; + } + + while (!LLVMObjectFileIsSymbolIteratorAtEnd(obj_data->binary, sym_itr)) { + if ((name = (char *)LLVMGetSymbolName(sym_itr)) + && str_starts_with(name, prefix)) { + func_index = (uint32)atoi(name + strlen(prefix)); + if (func_index < obj_data->func_count) { + func = obj_data->funcs + func_index; + func->func_name = name; + func->text_offset = LLVMGetSymbolAddress(sym_itr); + } + } + LLVMMoveToNextSymbol(sym_itr); + } + LLVMDisposeSymbolIterator(sym_itr); + + return true; +} + +static bool +get_relocations_count(LLVMSectionIteratorRef sec_itr, uint32 *p_count) +{ + uint32 relocation_count = 0; + LLVMRelocationIteratorRef rel_itr; + + if (!(rel_itr = LLVMGetRelocations(sec_itr))) { + aot_set_last_error("llvm get relocations failed."); + LLVMDisposeSectionIterator(sec_itr); + return false; + } + + while (!LLVMIsRelocationIteratorAtEnd(sec_itr, rel_itr)) { + relocation_count++; + LLVMMoveToNextRelocation(rel_itr); + } + LLVMDisposeRelocationIterator(rel_itr); + + *p_count = relocation_count; + return true; +} + +static bool +aot_resolve_object_relocation_group(AOTObjectData *obj_data, + AOTRelocationGroup *group, + LLVMSectionIteratorRef rel_sec) +{ + LLVMRelocationIteratorRef rel_itr; + AOTRelocation *relocation = group->relocations; + uint32 size; + bool is_binary_32bit = is_32bit_binary(obj_data); + bool is_binary_little_endian = is_little_endian_binary(obj_data); + bool has_addend = str_starts_with(group->section_name, ".rela"); + uint8 *rela_content = NULL; + + /* calculate relocations count and allocate memory */ + if (!get_relocations_count(rel_sec, &group->relocation_count)) + return false; + if (group->relocation_count == 0) { + aot_set_last_error("invalid relocations count"); + return false; + } + size = (uint32)sizeof(AOTRelocation) * group->relocation_count; + if (!(relocation = group->relocations = wasm_runtime_malloc(size))) { + aot_set_last_error("allocate memory for relocations failed."); + return false; + } + memset(group->relocations, 0, size); + + if (has_addend) { + uint64 rela_content_size; + /* LLVM doesn't provide C API to get relocation addend. So we have to + * parse it manually. */ + rela_content = (uint8 *)LLVMGetSectionContents(rel_sec); + rela_content_size = LLVMGetSectionSize(rel_sec); + if (is_binary_32bit) + size = (uint32)sizeof(struct elf32_rela) * group->relocation_count; + else + size = (uint32)sizeof(struct elf64_rela) * group->relocation_count; + if (rela_content_size != (uint64)size) { + aot_set_last_error("invalid relocation section content."); + return false; + } + } + + /* pares each relocation */ + if (!(rel_itr = LLVMGetRelocations(rel_sec))) { + aot_set_last_error("llvm get relocations failed."); + return false; + } + while (!LLVMIsRelocationIteratorAtEnd(rel_sec, rel_itr)) { + uint64 offset = LLVMGetRelocationOffset(rel_itr); + uint64 type = LLVMGetRelocationType(rel_itr); + LLVMSymbolIteratorRef rel_sym = LLVMGetRelocationSymbol(rel_itr); + + if (!rel_sym) { + aot_set_last_error("llvm get relocation symbol failed."); + goto fail; + } + + /* parse relocation addend from reloction content */ + if (has_addend) { + if (is_binary_32bit) { + int32 addend = + (int32)(((struct elf32_rela *)rela_content)->r_addend); + if (is_binary_little_endian != is_little_endian()) + exchange_uint32((uint8 *)&addend); + relocation->relocation_addend = (int64)addend; + rela_content += sizeof(struct elf32_rela); + } + else { + int64 addend = + (int64)(((struct elf64_rela *)rela_content)->r_addend); + if (is_binary_little_endian != is_little_endian()) + exchange_uint64((uint8 *)&addend); + relocation->relocation_addend = addend; + rela_content += sizeof(struct elf64_rela); + } + } + + /* set relocation fields */ + relocation->relocation_offset = offset; + relocation->relocation_type = (uint32)type; + relocation->symbol_name = (char *)LLVMGetSymbolName(rel_sym); + + /* for ".LCPIxxx", ".LJTIxxx", ".LBBxxx" and switch lookup table + * relocation, transform the symbol name to real section name and set + * addend to the offset of the symbol in the real section */ + if (relocation->symbol_name + && (str_starts_with(relocation->symbol_name, ".LCPI") + || str_starts_with(relocation->symbol_name, ".LJTI") + || str_starts_with(relocation->symbol_name, ".LBB") + || str_starts_with(relocation->symbol_name, + ".Lswitch.table."))) { + /* change relocation->relocation_addend and + relocation->symbol_name */ + LLVMSectionIteratorRef contain_section; + if (!(contain_section = + LLVMObjectFileCopySectionIterator(obj_data->binary))) { + aot_set_last_error("llvm get section iterator failed."); + goto fail; + } + LLVMMoveToContainingSection(contain_section, rel_sym); + if (LLVMObjectFileIsSectionIteratorAtEnd(obj_data->binary, + contain_section)) { + LLVMDisposeSectionIterator(contain_section); + aot_set_last_error("llvm get containing section failed."); + goto fail; + } + relocation->relocation_addend += LLVMGetSymbolAddress(rel_sym); + relocation->symbol_name = + (char *)LLVMGetSectionName(contain_section); + LLVMDisposeSectionIterator(contain_section); + } + + LLVMDisposeSymbolIterator(rel_sym); + LLVMMoveToNextRelocation(rel_itr); + relocation++; + } + LLVMDisposeRelocationIterator(rel_itr); + return true; + +fail: + LLVMDisposeRelocationIterator(rel_itr); + return false; +} + +static bool +is_relocation_section_name(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.sdata") + || !strcmp(section_name, ".rel.sdata") + || !strcmp(section_name, ".rela.rodata") + || !strcmp(section_name, ".rel.rodata") + /* ".rela.rodata.cst4/8/16/.." */ + || !strncmp(section_name, ".rela.rodata.cst", + strlen(".rela.rodata.cst")) + /* ".rel.rodata.cst4/8/16/.." */ + || !strncmp(section_name, ".rel.rodata.cst", + strlen(".rel.rodata.cst"))); +} + +static bool +is_relocation_section(LLVMSectionIteratorRef sec_itr) +{ + uint32 count = 0; + char *name = (char *)LLVMGetSectionName(sec_itr); + if (name) { + if (is_relocation_section_name(name)) + return true; + else if ((!strcmp(name, ".text") || !strcmp(name, ".rdata")) + && get_relocations_count(sec_itr, &count) && count > 0) + return true; + } + return false; +} + +static bool +get_relocation_groups_count(AOTObjectData *obj_data, uint32 *p_count) +{ + uint32 count = 0; + LLVMSectionIteratorRef sec_itr; + + 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 (is_relocation_section(sec_itr)) { + count++; + } + LLVMMoveToNextSection(sec_itr); + } + LLVMDisposeSectionIterator(sec_itr); + + *p_count = count; + return true; +} + +static bool +aot_resolve_object_relocation_groups(AOTObjectData *obj_data) +{ + LLVMSectionIteratorRef sec_itr; + AOTRelocationGroup *relocation_group; + uint32 group_count; + char *name; + uint32 size; + + /* calculate relocation groups count and allocate memory */ + if (!get_relocation_groups_count(obj_data, &group_count)) + return false; + + if (0 == (obj_data->relocation_group_count = group_count)) + return true; + + size = (uint32)sizeof(AOTRelocationGroup) * group_count; + if (!(relocation_group = obj_data->relocation_groups = + wasm_runtime_malloc(size))) { + aot_set_last_error("allocate memory for relocation groups failed."); + return false; + } + + memset(obj_data->relocation_groups, 0, size); + + /* resolve each relocation group */ + 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 (is_relocation_section(sec_itr)) { + name = (char *)LLVMGetSectionName(sec_itr); + relocation_group->section_name = name; + if (!aot_resolve_object_relocation_group(obj_data, relocation_group, + sec_itr)) { + LLVMDisposeSectionIterator(sec_itr); + return false; + } + relocation_group++; + } + LLVMMoveToNextSection(sec_itr); + } + LLVMDisposeSectionIterator(sec_itr); + + return true; +} + +static void +destroy_relocation_groups(AOTRelocationGroup *relocation_groups, + uint32 relocation_group_count) +{ + uint32 i; + AOTRelocationGroup *relocation_group = relocation_groups; + + for (i = 0; i < relocation_group_count; i++, relocation_group++) + if (relocation_group->relocations) + wasm_runtime_free(relocation_group->relocations); + wasm_runtime_free(relocation_groups); +} + +static void +destroy_relocation_symbol_list(AOTSymbolList *symbol_list) +{ + AOTSymbolNode *elem; + + elem = symbol_list->head; + while (elem) { + AOTSymbolNode *next = elem->next; + wasm_runtime_free(elem); + elem = next; + } +} + +static void +aot_obj_data_destroy(AOTObjectData *obj_data) +{ + if (obj_data->binary) + LLVMDisposeBinary(obj_data->binary); + if (obj_data->mem_buf) + LLVMDisposeMemoryBuffer(obj_data->mem_buf); + if (obj_data->funcs) + wasm_runtime_free(obj_data->funcs); + if (obj_data->data_sections) + wasm_runtime_free(obj_data->data_sections); + if (obj_data->relocation_groups) + destroy_relocation_groups(obj_data->relocation_groups, + obj_data->relocation_group_count); + if (obj_data->symbol_list.len) + destroy_relocation_symbol_list(&obj_data->symbol_list); + wasm_runtime_free(obj_data); +} + +static AOTObjectData * +aot_obj_data_create(AOTCompContext *comp_ctx) +{ + char *err = NULL; + AOTObjectData *obj_data; + LLVMTargetRef target = LLVMGetTargetMachineTarget(comp_ctx->target_machine); + + bh_print_time("Begin to emit object file to buffer"); + + if (!(obj_data = wasm_runtime_malloc(sizeof(AOTObjectData)))) { + aot_set_last_error("allocate memory failed."); + return false; + } + memset(obj_data, 0, sizeof(AOTObjectData)); + + bh_print_time("Begin to emit object file"); + if (comp_ctx->external_llc_compiler || comp_ctx->external_asm_compiler) { +#if defined(_WIN32) || defined(_WIN32_) + aot_set_last_error("external toolchain not supported on Windows"); + goto fail; +#else + /* Generate a temp file name */ + int ret; + char obj_file_name[64]; + + if (!aot_generate_tempfile_name("wamrc-obj", "o", obj_file_name, + sizeof(obj_file_name))) { + goto fail; + } + + if (!aot_emit_object_file(comp_ctx, obj_file_name)) { + goto fail; + } + + /* create memory buffer from object file */ + ret = LLVMCreateMemoryBufferWithContentsOfFile( + obj_file_name, &obj_data->mem_buf, &err); + /* remove temp object file */ + unlink(obj_file_name); + + if (ret != 0) { + if (err) { + LLVMDisposeMessage(err); + err = NULL; + } + aot_set_last_error("create mem buffer with file failed."); + goto fail; + } +#endif /* end of defined(_WIN32) || defined(_WIN32_) */ + } + else if (!strncmp(LLVMGetTargetName(target), "arc", 3)) { +#if defined(_WIN32) || defined(_WIN32_) + aot_set_last_error("emit object file on Windows is unsupported."); + goto fail; +#else + /* Emit to assmelby file instead for arc target + as it cannot emit to object file */ + char file_name[] = "wasm-XXXXXX", buf[128]; + int fd, ret; + + if ((fd = mkstemp(file_name)) <= 0) { + aot_set_last_error("make temp file failed."); + goto fail; + } + + /* close and remove temp file */ + close(fd); + unlink(file_name); + + snprintf(buf, sizeof(buf), "%s%s", file_name, ".s"); + if (LLVMTargetMachineEmitToFile(comp_ctx->target_machine, + comp_ctx->module, buf, LLVMAssemblyFile, + &err) + != 0) { + if (err) { + LLVMDisposeMessage(err); + err = NULL; + } + aot_set_last_error("emit elf to object file failed."); + goto fail; + } + + /* call arc gcc to compile assembly file to object file */ + /* TODO: get arc gcc from environment variable firstly + and check whether the toolchain exists actually */ + snprintf(buf, sizeof(buf), "%s%s%s%s%s%s", + "/opt/zephyr-sdk/arc-zephyr-elf/bin/arc-zephyr-elf-gcc ", + "-mcpu=arcem -o ", file_name, ".o -c ", file_name, ".s"); + /* TODO: use try..catch to handle possible exceptions */ + ret = system(buf); + /* remove temp assembly file */ + snprintf(buf, sizeof(buf), "%s%s", file_name, ".s"); + unlink(buf); + + if (ret != 0) { + aot_set_last_error("failed to compile asm file to obj file " + "with arc gcc toolchain."); + goto fail; + } + + /* create memory buffer from object file */ + snprintf(buf, sizeof(buf), "%s%s", file_name, ".o"); + ret = LLVMCreateMemoryBufferWithContentsOfFile(buf, &obj_data->mem_buf, + &err); + /* remove temp object file */ + snprintf(buf, sizeof(buf), "%s%s", file_name, ".o"); + unlink(buf); + + if (ret != 0) { + if (err) { + LLVMDisposeMessage(err); + err = NULL; + } + aot_set_last_error("create mem buffer with file failed."); + goto fail; + } +#endif /* end of defined(_WIN32) || defined(_WIN32_) */ + } + else { + if (LLVMTargetMachineEmitToMemoryBuffer( + comp_ctx->target_machine, comp_ctx->module, LLVMObjectFile, + &err, &obj_data->mem_buf) + != 0) { + if (err) { + LLVMDisposeMessage(err); + err = NULL; + } + aot_set_last_error("llvm emit to memory buffer failed."); + goto fail; + } + } + + if (!(obj_data->binary = LLVMCreateBinary(obj_data->mem_buf, NULL, &err))) { + if (err) { + LLVMDisposeMessage(err); + err = NULL; + } + aot_set_last_error("llvm create binary failed."); + goto fail; + } + + bh_print_time("Begin to resolve object file info"); + + /* 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)) + goto fail; + + return obj_data; + +fail: + aot_obj_data_destroy(obj_data); + return NULL; +} + +uint8 * +aot_emit_aot_file_buf(AOTCompContext *comp_ctx, AOTCompData *comp_data, + uint32 *p_aot_file_size) +{ + AOTObjectData *obj_data = aot_obj_data_create(comp_ctx); + uint8 *aot_file_buf, *buf, *buf_end; + uint32 aot_file_size, offset = 0; + + if (!obj_data) + return NULL; + + aot_file_size = get_aot_file_size(comp_ctx, comp_data, obj_data); + + if (!(buf = aot_file_buf = wasm_runtime_malloc(aot_file_size))) { + aot_set_last_error("allocate memory failed."); + goto fail1; + } + + memset(aot_file_buf, 0, aot_file_size); + buf_end = buf + aot_file_size; + + if (!aot_emit_file_header(buf, buf_end, &offset, comp_data, obj_data) + || !aot_emit_target_info_section(buf, buf_end, &offset, comp_data, + obj_data) + || !aot_emit_init_data_section(buf, buf_end, &offset, comp_ctx, + comp_data, obj_data) + || !aot_emit_text_section(buf, buf_end, &offset, comp_data, obj_data) + || !aot_emit_func_section(buf, buf_end, &offset, comp_data, obj_data) + || !aot_emit_export_section(buf, buf_end, &offset, comp_ctx, comp_data, + obj_data) + || !aot_emit_relocation_section(buf, buf_end, &offset, comp_ctx, + comp_data, obj_data) + || !aot_emit_native_symbol(buf, buf_end, &offset, comp_ctx) + || !aot_emit_name_section(buf, buf_end, &offset, comp_data, comp_ctx) + || !aot_emit_custom_sections(buf, buf_end, &offset, comp_data, + comp_ctx)) + goto fail2; + +#if 0 + dump_buf(buf, offset, "sections"); +#endif + + if (offset != aot_file_size) { + aot_set_last_error("emit aot file failed."); + goto fail2; + } + + *p_aot_file_size = aot_file_size; + + aot_obj_data_destroy(obj_data); + return aot_file_buf; + +fail2: + wasm_runtime_free(aot_file_buf); + +fail1: + aot_obj_data_destroy(obj_data); + return NULL; +} + +bool +aot_emit_aot_file(AOTCompContext *comp_ctx, AOTCompData *comp_data, + const char *file_name) +{ + uint8 *aot_file_buf; + uint32 aot_file_size; + bool ret = false; + FILE *file; + + bh_print_time("Begin to emit AOT file"); + + if (!(aot_file_buf = + aot_emit_aot_file_buf(comp_ctx, comp_data, &aot_file_size))) { + return false; + } + + /* write buffer to file */ + if (!(file = fopen(file_name, "wb"))) { + aot_set_last_error("open or create aot file failed."); + goto fail1; + } + if (!fwrite(aot_file_buf, aot_file_size, 1, file)) { + aot_set_last_error("write to aot file failed."); + goto fail2; + } + + ret = true; + +fail2: + fclose(file); + +fail1: + wasm_runtime_free(aot_file_buf); + + return ret; +} |