summaryrefslogtreecommitdiff
path: root/core/src
diff options
context:
space:
mode:
authorruki <[email protected]>2026-02-12 10:09:12 +0800
committerGitHub <[email protected]>2026-02-12 10:09:12 +0800
commit9d084db557d256923fc7f8a5daf66b21709f4bc4 (patch)
tree80be799cf286994b09bc0bc00bb6cdf766029ec6 /core/src
parent2f944ae3380afc0129baff3f944ce31ed1faf72e (diff)
parent37b506c86c3390d6a175ce37828e8defd44a2407 (diff)
Merge pull request #7312 from xmake-io/binutils
Improve binutils to support wasm
Diffstat (limited to 'core/src')
-rw-r--r--core/src/xmake/binutils/ar/prefix.h14
-rw-r--r--core/src/xmake/binutils/ar/readsyms.c28
-rw-r--r--core/src/xmake/binutils/deplibs.c22
-rw-r--r--core/src/xmake/binutils/elf/prefix.h5
-rw-r--r--core/src/xmake/binutils/extractlib.c6
-rw-r--r--core/src/xmake/binutils/format.c10
-rw-r--r--core/src/xmake/binutils/prefix.h1
-rw-r--r--core/src/xmake/binutils/readsyms.c15
-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
11 files changed, 643 insertions, 22 deletions
diff --git a/core/src/xmake/binutils/ar/prefix.h b/core/src/xmake/binutils/ar/prefix.h
index 53df74e5d..c474eefa6 100644
--- a/core/src/xmake/binutils/ar/prefix.h
+++ b/core/src/xmake/binutils/ar/prefix.h
@@ -28,6 +28,7 @@
#include "../coff/prefix.h"
#include "../elf/prefix.h"
#include "../macho/prefix.h"
+#include "../wasm/prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* forward declarations
@@ -35,6 +36,7 @@
extern tb_bool_t xm_binutils_coff_read_symbols(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua);
extern tb_bool_t xm_binutils_elf_read_symbols(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua);
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_wasm_read_symbols(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua);
/* //////////////////////////////////////////////////////////////////////////////////////
* types
@@ -157,6 +159,18 @@ static __tb_inline__ tb_bool_t xm_binutils_ar_get_member_name(tb_stream_ref_t is
}
}
+ if (header->name[0] == '/') {
+ if (header->name[1] == '/') {
+ tb_strlcpy(name, "//", name_size);
+ *name_len = 2;
+ } else {
+ tb_strlcpy(name, "/", name_size);
+ *name_len = 1;
+ }
+ *bytes_read = 0;
+ return tb_true;
+ }
+
// regular name (null-terminated or space-padded)
tb_size_t i = 0;
for (i = 0; i < 16 && i < name_size - 1; i++) {
diff --git a/core/src/xmake/binutils/ar/readsyms.c b/core/src/xmake/binutils/ar/readsyms.c
index 1a0d3b540..9249d0a0a 100644
--- a/core/src/xmake/binutils/ar/readsyms.c
+++ b/core/src/xmake/binutils/ar/readsyms.c
@@ -30,6 +30,30 @@
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
+static tb_int_t xm_binutils_ar_detect_member_format(tb_stream_ref_t istream, tb_hize_t base_offset) {
+ tb_uint8_t magic[8] = {0};
+ if (!tb_stream_seek(istream, base_offset)) {
+ return -1;
+ }
+ if (!tb_stream_bread(istream, magic, 8)) {
+ tb_stream_seek(istream, base_offset);
+ return -1;
+ }
+ tb_stream_seek(istream, base_offset);
+
+ if (magic[0] == XM_WASM_MAGIC0 && magic[1] == XM_WASM_MAGIC1 && magic[2] == XM_WASM_MAGIC2 && magic[3] == XM_WASM_MAGIC3) {
+ return XM_BINUTILS_FORMAT_WASM;
+ }
+ if (magic[0] == XM_ELF_MAGIC0 && magic[1] == XM_ELF_MAGIC1 && magic[2] == XM_ELF_MAGIC2 && magic[3] == XM_ELF_MAGIC3) {
+ return XM_BINUTILS_FORMAT_ELF;
+ }
+ tb_uint32_t macho_magic = tb_bits_get_u32_be(magic);
+ if (macho_magic == XM_MACHO_MAGIC_32 || macho_magic == XM_MACHO_MAGIC_64 ||
+ macho_magic == XM_MACHO_MAGIC_32_BE || macho_magic == XM_MACHO_MAGIC_64_BE) {
+ return XM_BINUTILS_FORMAT_MACHO;
+ }
+ return XM_BINUTILS_FORMAT_UNKNOWN;
+}
/* parse BSD symbol table (__.SYMDEF or __.SYMDEF SORTED)
*
@@ -346,7 +370,7 @@ tb_bool_t xm_binutils_ar_read_symbols(tb_stream_ref_t istream, tb_hize_t base_of
tb_hize_t current_pos = tb_stream_offset(istream);
// detect format
- tb_int_t format = xm_binutils_format_detect(istream);
+ tb_int_t format = xm_binutils_ar_detect_member_format(istream, current_pos);
if (format != XM_BINUTILS_FORMAT_AR) {
// create entry table
lua_newtable(lua);
@@ -365,6 +389,8 @@ tb_bool_t xm_binutils_ar_read_symbols(tb_stream_ref_t istream, tb_hize_t base_of
read_ok = xm_binutils_elf_read_symbols(istream, current_pos, lua);
} else if (format == XM_BINUTILS_FORMAT_MACHO) {
read_ok = xm_binutils_macho_read_symbols(istream, current_pos, lua);
+ } else if (format == XM_BINUTILS_FORMAT_WASM) {
+ read_ok = xm_binutils_wasm_read_symbols(istream, current_pos, lua);
}
if (!read_ok) {
diff --git a/core/src/xmake/binutils/deplibs.c b/core/src/xmake/binutils/deplibs.c
index 48a7cd200..1ce0d5c29 100644
--- a/core/src/xmake/binutils/deplibs.c
+++ b/core/src/xmake/binutils/deplibs.c
@@ -60,7 +60,7 @@ tb_int_t xm_binutils_deplibs(lua_State *lua) {
tb_stream_ref_t istream = tb_stream_init_from_file(binaryfile, TB_FILE_MODE_RO);
if (!istream) {
lua_pushboolean(lua, tb_false);
- lua_pushfstring(lua, "deplibs: open %s failed", binaryfile);
+ lua_pushfstring(lua, "open %s failed", binaryfile);
return 2;
}
@@ -68,7 +68,7 @@ tb_int_t xm_binutils_deplibs(lua_State *lua) {
do {
if (!tb_stream_open(istream)) {
lua_pushboolean(lua, tb_false);
- lua_pushfstring(lua, "deplibs: open %s failed", binaryfile);
+ lua_pushfstring(lua, "open %s failed", binaryfile);
break;
}
@@ -76,7 +76,7 @@ tb_int_t xm_binutils_deplibs(lua_State *lua) {
tb_int_t format = xm_binutils_format_detect(istream);
if (format < 0) {
lua_pushboolean(lua, tb_false);
- lua_pushfstring(lua, "deplibs: cannot detect file format");
+ lua_pushfstring(lua, "cannot detect file format");
break;
}
@@ -88,7 +88,7 @@ tb_int_t xm_binutils_deplibs(lua_State *lua) {
if (!xm_binutils_coff_deplibs(istream, 0, lua)) {
lua_pop(lua, 1); // pop table
lua_pushboolean(lua, tb_false);
- lua_pushfstring(lua, "deplibs: failed to parse COFF");
+ lua_pushfstring(lua, "failed to parse COFF");
break;
}
} else if (format == XM_BINUTILS_FORMAT_PE) {
@@ -96,7 +96,7 @@ tb_int_t xm_binutils_deplibs(lua_State *lua) {
if (!tb_stream_seek(istream, 0x3c)) {
lua_pop(lua, 1); // pop table
lua_pushboolean(lua, tb_false);
- lua_pushfstring(lua, "deplibs: failed to seek to e_lfanew");
+ lua_pushfstring(lua, "failed to seek to e_lfanew");
break;
}
@@ -105,7 +105,7 @@ tb_int_t xm_binutils_deplibs(lua_State *lua) {
if (!tb_stream_bread(istream, (tb_byte_t*)&e_lfanew, 4)) {
lua_pop(lua, 1); // pop table
lua_pushboolean(lua, tb_false);
- lua_pushfstring(lua, "deplibs: failed to read e_lfanew");
+ lua_pushfstring(lua, "failed to read e_lfanew");
break;
}
@@ -116,31 +116,31 @@ tb_int_t xm_binutils_deplibs(lua_State *lua) {
if (!xm_binutils_coff_deplibs(istream, e_lfanew + 4, lua)) {
lua_pop(lua, 1); // pop table
lua_pushboolean(lua, tb_false);
- lua_pushfstring(lua, "deplibs: failed to parse PE/COFF");
+ lua_pushfstring(lua, "failed to parse PE/COFF");
break;
}
} else if (format == XM_BINUTILS_FORMAT_MACHO) {
if (!xm_binutils_macho_deplibs(istream, 0, lua)) {
lua_pop(lua, 1); // pop table
lua_pushboolean(lua, tb_false);
- lua_pushfstring(lua, "deplibs: failed to parse Mach-O");
+ lua_pushfstring(lua, "failed to parse Mach-O");
break;
}
} else if (format == XM_BINUTILS_FORMAT_ELF) {
if (!xm_binutils_elf_deplibs(istream, 0, lua)) {
lua_pop(lua, 1); // pop table
lua_pushboolean(lua, tb_false);
- lua_pushfstring(lua, "deplibs: failed to parse ELF");
+ lua_pushfstring(lua, "failed to parse ELF");
break;
}
+ } else if (format == XM_BINUTILS_FORMAT_WASM) {
} else {
lua_pop(lua, 1); // pop table
lua_pushboolean(lua, tb_false);
- lua_pushfstring(lua, "deplibs: unsupported format %d", format);
+ lua_pushfstring(lua, "unsupported format %d", format);
break;
}
-
ok = tb_true;
} while (0);
diff --git a/core/src/xmake/binutils/elf/prefix.h b/core/src/xmake/binutils/elf/prefix.h
index 2561b41cb..2072ee879 100644
--- a/core/src/xmake/binutils/elf/prefix.h
+++ b/core/src/xmake/binutils/elf/prefix.h
@@ -29,6 +29,11 @@
/* //////////////////////////////////////////////////////////////////////////////////////
* macros
*/
+#define XM_ELF_MAGIC0 0x7f
+#define XM_ELF_MAGIC1 'E'
+#define XM_ELF_MAGIC2 'L'
+#define XM_ELF_MAGIC3 'F'
+
// ELF class
#define XM_ELF_EI_CLASS 4
#define XM_ELF_CLASS32 1
diff --git a/core/src/xmake/binutils/extractlib.c b/core/src/xmake/binutils/extractlib.c
index 5e6559082..fbfbacfef 100644
--- a/core/src/xmake/binutils/extractlib.c
+++ b/core/src/xmake/binutils/extractlib.c
@@ -74,7 +74,7 @@ tb_int_t xm_binutils_extractlib(lua_State *lua) {
tb_stream_ref_t istream = tb_stream_init_from_file(libraryfile, TB_FILE_MODE_RO);
if (!istream) {
lua_pushboolean(lua, tb_false);
- lua_pushfstring(lua, "extractlib: open %s failed", libraryfile);
+ lua_pushfstring(lua, "open %s failed", libraryfile);
return 2;
}
@@ -139,9 +139,9 @@ tb_int_t xm_binutils_extractlib(lua_State *lua) {
} else {
lua_pushboolean(lua, tb_false);
if (error_msg) {
- lua_pushfstring(lua, "extractlib: %s %s", error_msg, libraryfile);
+ lua_pushfstring(lua, "%s %s", error_msg, libraryfile);
} else {
- lua_pushfstring(lua, "extractlib: unknown error for %s", libraryfile);
+ lua_pushfstring(lua, "unknown error for %s", libraryfile);
}
return 2;
}
diff --git a/core/src/xmake/binutils/format.c b/core/src/xmake/binutils/format.c
index dd7e836f3..956340b0a 100644
--- a/core/src/xmake/binutils/format.c
+++ b/core/src/xmake/binutils/format.c
@@ -91,6 +91,10 @@ static __tb_inline__ tb_bool_t xm_binutils_format_is_ape(tb_byte_t const* first8
first8[4] == 'p' && first8[5] == 'D';
}
+static __tb_inline__ tb_bool_t xm_binutils_format_is_wasm(tb_byte_t const* first8) {
+ return first8[0] == 0x00 && first8[1] == 0x61 && first8[2] == 0x73 && first8[3] == 0x6d;
+}
+
static __tb_inline__ tb_bool_t xm_binutils_format_is_elf(tb_byte_t const* first8) {
return first8[0] == 0x7f && first8[1] == 'E' && first8[2] == 'L' && first8[3] == 'F';
}
@@ -164,6 +168,11 @@ tb_int_t xm_binutils_format_detect(tb_stream_ref_t istream) {
break;
}
+ if (xm_binutils_format_is_wasm(p)) {
+ format = XM_BINUTILS_FORMAT_WASM;
+ break;
+ }
+
if (xm_binutils_format_is_elf(p)) {
format = XM_BINUTILS_FORMAT_ELF;
break;
@@ -237,6 +246,7 @@ tb_int_t xm_binutils_format(lua_State *lua) {
case XM_BINUTILS_FORMAT_PE: lua_pushliteral(lua, "pe"); break;
case XM_BINUTILS_FORMAT_SHEBANG: lua_pushliteral(lua, "shebang"); break;
case XM_BINUTILS_FORMAT_APE: lua_pushliteral(lua, "ape"); break;
+ case XM_BINUTILS_FORMAT_WASM: lua_pushliteral(lua, "wasm"); break;
default: lua_pushliteral(lua, "unknown"); break;
}
diff --git a/core/src/xmake/binutils/prefix.h b/core/src/xmake/binutils/prefix.h
index b3ffd8c27..608424958 100644
--- a/core/src/xmake/binutils/prefix.h
+++ b/core/src/xmake/binutils/prefix.h
@@ -36,6 +36,7 @@
#define XM_BINUTILS_FORMAT_PE 5
#define XM_BINUTILS_FORMAT_SHEBANG 6
#define XM_BINUTILS_FORMAT_APE 7
+#define XM_BINUTILS_FORMAT_WASM 8
#define XM_BINUTILS_FORMAT_UNKNOWN 0
// COFF machine types (for format detection)
diff --git a/core/src/xmake/binutils/readsyms.c b/core/src/xmake/binutils/readsyms.c
index e29010314..2c119a538 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
@@ -62,7 +63,7 @@ tb_int_t xm_binutils_readsyms(lua_State *lua) {
tb_stream_ref_t istream = tb_stream_init_from_file(objectfile, TB_FILE_MODE_RO);
if (!istream) {
lua_pushboolean(lua, tb_false);
- lua_pushfstring(lua, "readsyms: open %s failed", objectfile);
+ lua_pushfstring(lua, "open %s failed", objectfile);
return 2;
}
@@ -70,7 +71,7 @@ tb_int_t xm_binutils_readsyms(lua_State *lua) {
do {
if (!tb_stream_open(istream)) {
lua_pushboolean(lua, tb_false);
- lua_pushfstring(lua, "readsyms: open %s failed", objectfile);
+ lua_pushfstring(lua, "open %s failed", objectfile);
break;
}
@@ -78,7 +79,7 @@ tb_int_t xm_binutils_readsyms(lua_State *lua) {
tb_int_t format = xm_binutils_format_detect(istream);
if (format < 0) {
lua_pushboolean(lua, tb_false);
- lua_pushfstring(lua, "readsyms: cannot detect file format");
+ lua_pushfstring(lua, "cannot detect file format");
break;
}
@@ -101,14 +102,14 @@ tb_int_t xm_binutils_readsyms(lua_State *lua) {
// fallback to ar
if (!xm_binutils_ar_read_symbols(istream, 0, lua)) {
lua_pushboolean(lua, tb_false);
- lua_pushfstring(lua, "readsyms: read AR/MSLIB archive symbols failed");
+ lua_pushfstring(lua, "read AR/MSLIB archive symbols failed");
break;
}
}
} else {
if (!xm_binutils_ar_read_symbols(istream, 0, lua)) {
lua_pushboolean(lua, tb_false);
- lua_pushfstring(lua, "readsyms: read AR archive symbols failed");
+ lua_pushfstring(lua, "read AR archive symbols failed");
break;
}
}
@@ -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) {
@@ -148,7 +151,7 @@ tb_int_t xm_binutils_readsyms(lua_State *lua) {
} else {
lua_pop(lua, 2); // pop entry table and result list
lua_pushboolean(lua, tb_false);
- lua_pushfstring(lua, "readsyms: read symbols failed");
+ lua_pushfstring(lua, "read symbols failed");
break;
}
}
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
-