summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorruki <[email protected]>2026-02-12 00:53:43 +0800
committerruki <[email protected]>2026-02-12 00:53:43 +0800
commitaf7720f0b49e91bae20648f49133c6eef8f9e003 (patch)
tree601c45ede2c0549c2e1999202694c00471fe3d55
parente0e3e4dc010c24c555499962f740f4d76eb25351 (diff)
add readsyms support for wasm
-rw-r--r--core/src/xmake/binutils/readsyms.c3
-rw-r--r--core/src/xmake/binutils/wasm/prefix.h212
-rw-r--r--core/src/xmake/binutils/wasm/readsyms.c350
-rwxr-xr-xcore/src/xmake/xmake.sh2
-rw-r--r--tests/modules/binutils/test.lua50
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, &section_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, &section_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