diff options
| author | ruki <[email protected]> | 2026-02-12 10:09:12 +0800 |
|---|---|---|
| committer | GitHub <[email protected]> | 2026-02-12 10:09:12 +0800 |
| commit | 9d084db557d256923fc7f8a5daf66b21709f4bc4 (patch) | |
| tree | 80be799cf286994b09bc0bc00bb6cdf766029ec6 /core/src | |
| parent | 2f944ae3380afc0129baff3f944ce31ed1faf72e (diff) | |
| parent | 37b506c86c3390d6a175ce37828e8defd44a2407 (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.h | 14 | ||||
| -rw-r--r-- | core/src/xmake/binutils/ar/readsyms.c | 28 | ||||
| -rw-r--r-- | core/src/xmake/binutils/deplibs.c | 22 | ||||
| -rw-r--r-- | core/src/xmake/binutils/elf/prefix.h | 5 | ||||
| -rw-r--r-- | core/src/xmake/binutils/extractlib.c | 6 | ||||
| -rw-r--r-- | core/src/xmake/binutils/format.c | 10 | ||||
| -rw-r--r-- | core/src/xmake/binutils/prefix.h | 1 | ||||
| -rw-r--r-- | core/src/xmake/binutils/readsyms.c | 15 | ||||
| -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 |
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, §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 - |
