diff options
| author | ruki <[email protected]> | 2026-02-12 00:53:43 +0800 |
|---|---|---|
| committer | ruki <[email protected]> | 2026-02-12 00:53:43 +0800 |
| commit | af7720f0b49e91bae20648f49133c6eef8f9e003 (patch) | |
| tree | 601c45ede2c0549c2e1999202694c00471fe3d55 | |
| parent | e0e3e4dc010c24c555499962f740f4d76eb25351 (diff) | |
add readsyms support for wasm
| -rw-r--r-- | core/src/xmake/binutils/readsyms.c | 3 | ||||
| -rw-r--r-- | core/src/xmake/binutils/wasm/prefix.h | 212 | ||||
| -rw-r--r-- | core/src/xmake/binutils/wasm/readsyms.c | 350 | ||||
| -rwxr-xr-x | core/src/xmake/xmake.sh | 2 | ||||
| -rw-r--r-- | tests/modules/binutils/test.lua | 50 |
5 files changed, 616 insertions, 1 deletions
diff --git a/core/src/xmake/binutils/readsyms.c b/core/src/xmake/binutils/readsyms.c index e29010314..8cc40bf3c 100644 --- a/core/src/xmake/binutils/readsyms.c +++ b/core/src/xmake/binutils/readsyms.c @@ -41,6 +41,7 @@ extern tb_bool_t xm_binutils_elf_read_symbols(tb_stream_ref_t istream, tb_hize_t extern tb_bool_t xm_binutils_macho_read_symbols(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua); extern tb_bool_t xm_binutils_ar_read_symbols(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua); extern tb_bool_t xm_binutils_mslib_read_symbols(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua); +extern tb_bool_t xm_binutils_wasm_read_symbols(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua); /* ////////////////////////////////////////////////////////////////////////////////////// * implementation @@ -140,6 +141,8 @@ tb_int_t xm_binutils_readsyms(lua_State *lua) { read_ok = xm_binutils_elf_read_symbols(istream, 0, lua); } else if (format == XM_BINUTILS_FORMAT_MACHO) { read_ok = xm_binutils_macho_read_symbols(istream, 0, lua); + } else if (format == XM_BINUTILS_FORMAT_WASM) { + read_ok = xm_binutils_wasm_read_symbols(istream, 0, lua); } if (read_ok) { diff --git a/core/src/xmake/binutils/wasm/prefix.h b/core/src/xmake/binutils/wasm/prefix.h new file mode 100644 index 000000000..9ec011a50 --- /dev/null +++ b/core/src/xmake/binutils/wasm/prefix.h @@ -0,0 +1,212 @@ +/*!A cross-platform build utility based on Lua + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (C) 2015-present, Xmake Open Source Community. + * + * @author ruki + * @file prefix.h + * + */ +#ifndef XM_BINUTILS_WASM_PREFIX_H +#define XM_BINUTILS_WASM_PREFIX_H + +/* ////////////////////////////////////////////////////////////////////////////////////// + * includes + */ +#include "../prefix.h" + +/* ////////////////////////////////////////////////////////////////////////////////////// + * macros + */ + +// wasm file magic: \0asm +#define XM_WASM_MAGIC0 0x00 +#define XM_WASM_MAGIC1 0x61 +#define XM_WASM_MAGIC2 0x73 +#define XM_WASM_MAGIC3 0x6d + +// wasm header size: magic(4) + version(4) +#define XM_WASM_HEADER_SIZE 8 + +// wasm section ids +#define XM_WASM_SECTION_IMPORT 2 +#define XM_WASM_SECTION_EXPORT 7 + +// wasm custom section names +#define XM_WASM_CUSTOM_LINKING "linking" +#define XM_WASM_CUSTOM_NAME "name" + +// wasm import/export kinds +#define XM_WASM_KIND_FUNC 0 +#define XM_WASM_KIND_TABLE 1 +#define XM_WASM_KIND_MEMORY 2 +#define XM_WASM_KIND_GLOBAL 3 +#define XM_WASM_KIND_TAG 4 + +// wasm limits flags +#define XM_WASM_LIMITS_HAS_MAX 0x01 +#define XM_WASM_LIMITS_MEM64 0x04 + +// leb128 max bytes +#define XM_WASM_U32_LEB_MAX 5 +#define XM_WASM_U64_LEB_MAX 10 + +// linking custom section +#define XM_WASM_LINKING_VERSION_2 2 +#define XM_WASM_LINKING_SUBSEC_SYMTAB 8 + +// symbol table kinds (linking section) +#define XM_WASM_SYMTAB_KIND_FUNCTION 0 +#define XM_WASM_SYMTAB_KIND_DATA 1 +#define XM_WASM_SYMTAB_KIND_GLOBAL 2 +#define XM_WASM_SYMTAB_KIND_SECTION 3 +#define XM_WASM_SYMTAB_KIND_EVENT 4 +#define XM_WASM_SYMTAB_KIND_TABLE 5 +#define XM_WASM_SYMTAB_KIND_TAG 6 + +// symbol table flags (linking section) +#define XM_WASM_SYMTAB_FLAG_UNDEFINED 0x10 + +// symbol types for binutils.readsyms +#define XM_WASM_SYM_UNDEF "U" +#define XM_WASM_SYM_TEXT "T" +#define XM_WASM_SYM_DATA "D" + +/* ////////////////////////////////////////////////////////////////////////////////////// + * inline implementation + */ + +// decode unsigned leb128 (u32) from current stream offset +static __tb_inline__ tb_bool_t xm_binutils_wasm_read_u32_leb(tb_stream_ref_t istream, tb_uint32_t* out) { + tb_uint32_t result = 0; + tb_uint32_t shift = 0; + tb_byte_t byte = 0; + for (tb_size_t i = 0; i < XM_WASM_U32_LEB_MAX; i++) { + if (!tb_stream_bread(istream, &byte, 1)) { + return tb_false; + } + result |= ((tb_uint32_t)(byte & 0x7f)) << shift; + if (!(byte & 0x80)) { + *out = result; + return tb_true; + } + shift += 7; + } + return tb_false; +} + +// decode unsigned leb128 (u64) from current stream offset +static __tb_inline__ tb_bool_t xm_binutils_wasm_read_u64_leb(tb_stream_ref_t istream, tb_uint64_t* out) { + tb_uint64_t result = 0; + tb_uint32_t shift = 0; + tb_byte_t byte = 0; + for (tb_size_t i = 0; i < XM_WASM_U64_LEB_MAX; i++) { + if (!tb_stream_bread(istream, &byte, 1)) { + return tb_false; + } + result |= ((tb_uint64_t)(byte & 0x7f)) << shift; + if (!(byte & 0x80)) { + *out = result; + return tb_true; + } + shift += 7; + } + return tb_false; +} + +// read wasm "name" (u32 leb length + bytes), truncate to fit buffer and skip remaining bytes +static __tb_inline__ tb_bool_t xm_binutils_wasm_read_name(tb_stream_ref_t istream, tb_char_t* name, tb_size_t name_size) { + tb_uint32_t len = 0; + if (!xm_binutils_wasm_read_u32_leb(istream, &len)) { + return tb_false; + } + tb_size_t readn = (tb_size_t)tb_min((tb_uint32_t)(name_size > 0 ? name_size - 1 : 0), len); + if (readn && !tb_stream_bread(istream, (tb_byte_t*)name, readn)) { + return tb_false; + } + if (name_size) { + name[readn] = '\0'; + } + if (len > readn) { + if (!tb_stream_skip(istream, (tb_hize_t)(len - readn))) { + return tb_false; + } + } + return tb_true; +} + +// skip wasm limits used by table/memory types, supports wasm32 and wasm64(memory64) +static __tb_inline__ tb_bool_t xm_binutils_wasm_skip_limits(tb_stream_ref_t istream) { + tb_uint32_t flags = 0; + if (!xm_binutils_wasm_read_u32_leb(istream, &flags)) { + return tb_false; + } + if (flags & XM_WASM_LIMITS_MEM64) { + tb_uint64_t tmp64 = 0; + if (!xm_binutils_wasm_read_u64_leb(istream, &tmp64)) { + return tb_false; + } + if (flags & XM_WASM_LIMITS_HAS_MAX) { + if (!xm_binutils_wasm_read_u64_leb(istream, &tmp64)) { + return tb_false; + } + } + } else { + tb_uint32_t tmp32 = 0; + if (!xm_binutils_wasm_read_u32_leb(istream, &tmp32)) { + return tb_false; + } + if (flags & XM_WASM_LIMITS_HAS_MAX) { + if (!xm_binutils_wasm_read_u32_leb(istream, &tmp32)) { + return tb_false; + } + } + } + return tb_true; +} + +// add one symbol table entry: {name=..., type=...} +static __tb_inline__ tb_void_t xm_binutils_wasm_add_symbol(lua_State* lua, tb_size_t* result_count, tb_char_t const* name, tb_char_t const* type) { + lua_pushinteger(lua, (lua_Integer)(*result_count + 1)); + lua_newtable(lua); + + lua_pushstring(lua, "name"); + lua_pushstring(lua, name); + lua_settable(lua, -3); + + lua_pushstring(lua, "type"); + lua_pushstring(lua, type); + lua_settable(lua, -3); + + lua_settable(lua, -3); + (*result_count)++; +} + +// seek and validate wasm header at base_offset, leave stream offset after header +static __tb_inline__ tb_bool_t xm_binutils_wasm_check_header(tb_stream_ref_t istream, tb_hize_t base_offset) { + if (!tb_stream_seek(istream, base_offset)) { + return tb_false; + } + + tb_uint8_t header[XM_WASM_HEADER_SIZE]; + if (!tb_stream_bread(istream, header, XM_WASM_HEADER_SIZE)) { + return tb_false; + } + if (header[0] != XM_WASM_MAGIC0 || header[1] != XM_WASM_MAGIC1 || header[2] != XM_WASM_MAGIC2 || header[3] != XM_WASM_MAGIC3) { + return tb_false; + } + return tb_true; +} + +#endif diff --git a/core/src/xmake/binutils/wasm/readsyms.c b/core/src/xmake/binutils/wasm/readsyms.c new file mode 100644 index 000000000..b57f27433 --- /dev/null +++ b/core/src/xmake/binutils/wasm/readsyms.c @@ -0,0 +1,350 @@ +/*!A cross-platform build utility based on Lua + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (C) 2015-present, Xmake Open Source Community. + * + * @author ruki + * @file readsyms.c + * + */ + +/* ////////////////////////////////////////////////////////////////////////////////////// + * trace + */ +#define TB_TRACE_MODULE_NAME "wasm_readsyms" +#define TB_TRACE_MODULE_DEBUG (0) + +/* ////////////////////////////////////////////////////////////////////////////////////// + * includes + */ +#include "prefix.h" + +/* ////////////////////////////////////////////////////////////////////////////////////// + * implementation + */ +static tb_bool_t xm_binutils_wasm_parse_linking_symtab(tb_stream_ref_t istream, tb_hize_t payload_end, lua_State* lua, tb_size_t* result_count) { + tb_uint32_t symcount = 0; + if (!xm_binutils_wasm_read_u32_leb(istream, &symcount)) { + return tb_false; + } + + for (tb_uint32_t i = 0; i < symcount; i++) { + tb_byte_t kind = 0; + if (!tb_stream_bread(istream, &kind, 1)) { + return tb_false; + } + + tb_uint32_t flags = 0; + if (!xm_binutils_wasm_read_u32_leb(istream, &flags)) { + return tb_false; + } + + tb_bool_t is_undef = (flags & XM_WASM_SYMTAB_FLAG_UNDEFINED) != 0; + tb_char_t name[256] = {0}; + + if (kind == XM_WASM_SYMTAB_KIND_FUNCTION || kind == XM_WASM_SYMTAB_KIND_GLOBAL || + kind == XM_WASM_SYMTAB_KIND_EVENT || kind == XM_WASM_SYMTAB_KIND_TABLE || + kind == XM_WASM_SYMTAB_KIND_TAG) { + + if (!is_undef) { + tb_uint32_t index = 0; + if (!xm_binutils_wasm_read_u32_leb(istream, &index)) { + return tb_false; + } + } + if (!xm_binutils_wasm_read_name(istream, name, sizeof(name))) { + return tb_false; + } + } else if (kind == XM_WASM_SYMTAB_KIND_DATA) { + if (!xm_binutils_wasm_read_name(istream, name, sizeof(name))) { + return tb_false; + } + if (!is_undef) { + tb_uint32_t tmp = 0; + if (!xm_binutils_wasm_read_u32_leb(istream, &tmp)) { // segment + return tb_false; + } + if (!xm_binutils_wasm_read_u32_leb(istream, &tmp)) { // offset + return tb_false; + } + if (!xm_binutils_wasm_read_u32_leb(istream, &tmp)) { // size + return tb_false; + } + } + } else if (kind == XM_WASM_SYMTAB_KIND_SECTION) { + tb_uint32_t section_index = 0; + if (!xm_binutils_wasm_read_u32_leb(istream, §ion_index)) { + return tb_false; + } + if (!xm_binutils_wasm_read_name(istream, name, sizeof(name))) { + return tb_false; + } + } else { + return tb_false; + } + + if (name[0]) { + tb_char_t const* type = XM_WASM_SYM_DATA; + if (is_undef) { + type = XM_WASM_SYM_UNDEF; + } else if (kind == XM_WASM_SYMTAB_KIND_FUNCTION) { + type = XM_WASM_SYM_TEXT; + } + xm_binutils_wasm_add_symbol(lua, result_count, name, type); + } + + if (tb_stream_offset(istream) > payload_end) { + return tb_false; + } + } + return tb_true; +} + +static tb_bool_t xm_binutils_wasm_parse_custom_linking(tb_stream_ref_t istream, tb_hize_t payload_end, lua_State* lua, tb_size_t* result_count) { + tb_uint32_t version = 0; + if (!xm_binutils_wasm_read_u32_leb(istream, &version)) { + return tb_false; + } + + while (tb_stream_offset(istream) < payload_end) { + tb_byte_t subsec_type = 0; + if (!tb_stream_bread(istream, &subsec_type, 1)) { + return tb_false; + } + + tb_uint32_t subsec_size = 0; + if (!xm_binutils_wasm_read_u32_leb(istream, &subsec_size)) { + return tb_false; + } + + tb_hize_t subsec_end = tb_stream_offset(istream) + (tb_hize_t)subsec_size; + if (subsec_end > payload_end) { + return tb_false; + } + + if (subsec_type == XM_WASM_LINKING_SUBSEC_SYMTAB) { + if (!xm_binutils_wasm_parse_linking_symtab(istream, subsec_end, lua, result_count)) { + return tb_false; + } + } + + if (tb_stream_offset(istream) < subsec_end) { + if (!tb_stream_seek(istream, subsec_end)) { + return tb_false; + } + } + } + + return version > 0 ? tb_true : tb_false; +} + +static tb_bool_t xm_binutils_wasm_parse_custom_name(tb_stream_ref_t istream, tb_hize_t payload_end, lua_State* lua, tb_size_t* result_count) { + // only use the name section as a fallback when we have no symbols yet + if (*result_count != 0) { + return tb_true; + } + + while (tb_stream_offset(istream) < payload_end) { + tb_byte_t subsec_type = 0; + if (!tb_stream_bread(istream, &subsec_type, 1)) { + return tb_false; + } + tb_uint32_t subsec_size = 0; + if (!xm_binutils_wasm_read_u32_leb(istream, &subsec_size)) { + return tb_false; + } + tb_hize_t subsec_end = tb_stream_offset(istream) + (tb_hize_t)subsec_size; + if (subsec_end > payload_end) { + return tb_false; + } + + if (subsec_type == 1) { + tb_uint32_t count = 0; + if (!xm_binutils_wasm_read_u32_leb(istream, &count)) { + return tb_false; + } + for (tb_uint32_t i = 0; i < count; i++) { + tb_uint32_t index = 0; + if (!xm_binutils_wasm_read_u32_leb(istream, &index)) { + return tb_false; + } + tb_char_t name[256] = {0}; + if (!xm_binutils_wasm_read_name(istream, name, sizeof(name))) { + return tb_false; + } + if (name[0]) { + xm_binutils_wasm_add_symbol(lua, result_count, name, XM_WASM_SYM_TEXT); + } + if (tb_stream_offset(istream) > subsec_end) { + return tb_false; + } + } + } + + if (tb_stream_offset(istream) < subsec_end) { + if (!tb_stream_seek(istream, subsec_end)) { + return tb_false; + } + } + } + return tb_true; +} + +/* ////////////////////////////////////////////////////////////////////////////////////// + * interfaces + */ +tb_bool_t xm_binutils_wasm_read_symbols(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua) { + tb_assert_and_check_return_val(istream && lua, tb_false); + if (!xm_binutils_wasm_check_header(istream, base_offset)) { + return tb_false; + } + + lua_newtable(lua); + tb_size_t result_count = 0; + + // parse wasm sections until EOF, collect imports/exports as symbols + for (;;) { + tb_byte_t section_id = 0; + if (!tb_stream_bread(istream, §ion_id, 1)) { + break; + } + + tb_uint32_t payload_len = 0; + if (!xm_binutils_wasm_read_u32_leb(istream, &payload_len)) { + break; + } + + tb_hize_t payload_start = tb_stream_offset(istream); + tb_hize_t payload_end = payload_start + (tb_hize_t)payload_len; + if (payload_len == 0) { + continue; + } + + if (section_id == 0) { + // custom section: name + custom payload + tb_char_t custom_name[64] = {0}; + if (!xm_binutils_wasm_read_name(istream, custom_name, sizeof(custom_name))) { + break; + } + + if (!tb_strcmp(custom_name, XM_WASM_CUSTOM_LINKING)) { + if (!xm_binutils_wasm_parse_custom_linking(istream, payload_end, lua, &result_count)) { + break; + } + } else if (!tb_strcmp(custom_name, XM_WASM_CUSTOM_NAME)) { + if (!xm_binutils_wasm_parse_custom_name(istream, payload_end, lua, &result_count)) { + break; + } + } + } else if (section_id == XM_WASM_SECTION_IMPORT) { + // import section: (vec import), each import => undefined symbol + tb_uint32_t count = 0; + if (xm_binutils_wasm_read_u32_leb(istream, &count)) { + for (tb_uint32_t i = 0; i < count; i++) { + tb_char_t module[256] = {0}; + tb_char_t field[256] = {0}; + if (!xm_binutils_wasm_read_name(istream, module, sizeof(module))) { + break; + } + if (!xm_binutils_wasm_read_name(istream, field, sizeof(field))) { + break; + } + tb_byte_t kind = 0; + if (!tb_stream_bread(istream, &kind, 1)) { + break; + } + tb_uint32_t tmp = 0; + if (kind == XM_WASM_KIND_FUNC) { + // type index (u32) + if (!xm_binutils_wasm_read_u32_leb(istream, &tmp)) { + break; + } + } else if (kind == XM_WASM_KIND_TABLE) { + // table type: elemtype + limits + if (!tb_stream_bread(istream, (tb_byte_t*)&kind, 1)) { + break; + } + if (!xm_binutils_wasm_skip_limits(istream)) { + break; + } + } else if (kind == XM_WASM_KIND_MEMORY) { + // memory type: limits + if (!xm_binutils_wasm_skip_limits(istream)) { + break; + } + } else if (kind == XM_WASM_KIND_GLOBAL) { + // global type: valtype + mut + tb_byte_t b = 0; + if (!tb_stream_bread(istream, &b, 1)) { + break; + } + if (!tb_stream_bread(istream, &b, 1)) { + break; + } + } else if (kind == XM_WASM_KIND_TAG) { + // tag: attribute + type index + if (!xm_binutils_wasm_read_u32_leb(istream, &tmp)) { + break; + } + } else { + break; + } + + // keep consistent with nm-style output: use the imported field name as symbol name + if (field[0]) { + xm_binutils_wasm_add_symbol(lua, &result_count, field, XM_WASM_SYM_UNDEF); + } else if (module[0]) { + xm_binutils_wasm_add_symbol(lua, &result_count, module, XM_WASM_SYM_UNDEF); + } + } + } + } else if (section_id == XM_WASM_SECTION_EXPORT) { + // export section: (vec export), each export => defined symbol + tb_uint32_t count = 0; + if (xm_binutils_wasm_read_u32_leb(istream, &count)) { + for (tb_uint32_t i = 0; i < count; i++) { + tb_char_t name[256] = {0}; + if (!xm_binutils_wasm_read_name(istream, name, sizeof(name))) { + break; + } + tb_byte_t kind = 0; + if (!tb_stream_bread(istream, &kind, 1)) { + break; + } + tb_uint32_t index = 0; + if (!xm_binutils_wasm_read_u32_leb(istream, &index)) { + break; + } + if (name[0]) { + // keep consistent with other formats: function => "T", others => "D" + tb_char_t const* type = XM_WASM_SYM_DATA; + if (kind == XM_WASM_KIND_FUNC) { + type = XM_WASM_SYM_TEXT; + } + xm_binutils_wasm_add_symbol(lua, &result_count, name, type); + } + } + } + } + + // always seek to end of section payload to continue scanning + if (tb_stream_offset(istream) < payload_end) { + if (!tb_stream_seek(istream, payload_end)) { + break; + } + } + } + + return tb_true; +} diff --git a/core/src/xmake/xmake.sh b/core/src/xmake/xmake.sh index dfe533aa3..06a3a82fc 100755 --- a/core/src/xmake/xmake.sh +++ b/core/src/xmake/xmake.sh @@ -77,10 +77,10 @@ target "xmake" add_files "binutils/coff/*.c" add_files "binutils/macho/*.c" add_files "binutils/elf/*.c" + add_files "binutils/wasm/*.c" add_files "binutils/ar/*.c" add_files "binutils/mslib/*.c" add_files "thread/*.c" if is_plat "mingw"; then add_files "winos/*.c" fi - diff --git a/tests/modules/binutils/test.lua b/tests/modules/binutils/test.lua index a2801af6e..319a197e6 100644 --- a/tests/modules/binutils/test.lua +++ b/tests/modules/binutils/test.lua @@ -93,3 +93,53 @@ function test_deplibs(t) os.tryrm(tempdir) end + +function test_readsyms(t) + local tempdir = "temp/binutils_readsyms" + os.tryrm(tempdir) + os.mkdir(tempdir) + + local wasmso = path.join(tempdir, "libfoo.so") + io.writefile(wasmso, string.char( + 0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, + 0x02, 0x0b, 0x01, 0x03, 0x65, 0x6e, 0x76, 0x03, 0x62, 0x61, 0x72, 0x00, 0x00, + 0x07, 0x07, 0x01, 0x03, 0x66, 0x6f, 0x6f, 0x00, 0x00)) + local results = binutils.readsyms(wasmso) + t:are_equal(#results, 1) + t:are_equal(results[1].objectfile, "libfoo.so") + t:are_equal(#results[1].symbols, 2) + t:are_equal(results[1].symbols[1].name, "bar") + t:are_equal(results[1].symbols[1].type, "U") + t:are_equal(results[1].symbols[2].name, "foo") + t:are_equal(results[1].symbols[2].type, "T") + + local wasmso64 = path.join(tempdir, "libfoo64.so") + io.writefile(wasmso64, string.char( + 0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, + 0x02, 0x0c, 0x01, 0x03, 0x65, 0x6e, 0x76, 0x03, 0x6d, 0x65, 0x6d, 0x02, 0x04, 0x01, + 0x07, 0x07, 0x01, 0x03, 0x66, 0x6f, 0x6f, 0x00, 0x00)) + local results64 = binutils.readsyms(wasmso64) + t:are_equal(#results64, 1) + t:are_equal(results64[1].objectfile, "libfoo64.so") + t:are_equal(#results64[1].symbols, 2) + t:are_equal(results64[1].symbols[1].name, "mem") + t:are_equal(results64[1].symbols[1].type, "U") + t:are_equal(results64[1].symbols[2].name, "foo") + t:are_equal(results64[1].symbols[2].type, "T") + + local wasmlink = path.join(tempdir, "liblink.so") + io.writefile(wasmlink, string.char( + 0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x04, 0x01, 0x60, 0x00, 0x00, + 0x03, 0x02, 0x01, 0x00, + 0x0a, 0x04, 0x01, 0x02, 0x00, 0x0b, + 0x00, 0x13, 0x07, 0x6c, 0x69, 0x6e, 0x6b, 0x69, 0x6e, 0x67, 0x02, 0x08, 0x08, 0x01, 0x00, 0x00, 0x00, 0x03, 0x61, 0x64, 0x64)) + local resultslink = binutils.readsyms(wasmlink) + t:are_equal(#resultslink, 1) + t:are_equal(resultslink[1].objectfile, "liblink.so") + t:are_equal(#resultslink[1].symbols, 1) + t:are_equal(resultslink[1].symbols[1].name, "add") + t:are_equal(resultslink[1].symbols[1].type, "T") + + os.tryrm(tempdir) +end |
