From ba293bc4b8840da34220e1f54313d531d18dde8e Mon Sep 17 00:00:00 2001 From: ruki Date: Tue, 9 Dec 2025 00:29:51 +0800 Subject: add binary readsyms --- xmake/modules/utils/binary/readsyms.lua | 92 +++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 xmake/modules/utils/binary/readsyms.lua (limited to 'xmake/modules/utils/binary') diff --git a/xmake/modules/utils/binary/readsyms.lua b/xmake/modules/utils/binary/readsyms.lua new file mode 100644 index 000000000..ace1c8be3 --- /dev/null +++ b/xmake/modules/utils/binary/readsyms.lua @@ -0,0 +1,92 @@ +--!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.lua +-- + +-- imports +import("core.base.binutils") + +-- get symbols from binary file (auto-detect format: ELF, COFF, Mach-O) +-- +-- @param binaryfile the binary file path (required) +-- @return the symbols table +function _get_symbols(binaryfile) + assert(binaryfile, "usage: xmake l utils.binary.readsyms ") + + binaryfile = path.absolute(binaryfile) + assert(os.isfile(binaryfile), "%s not found!", binaryfile) + + if binutils.readsyms then + local ok, symbols = binutils.readsyms(binaryfile) + if ok then + return symbols + else + raise("readsyms: %s", symbols or "unknown error") + end + else + raise("readsyms: binutils.readsyms not available (C implementation not compiled)") + end +end + +-- dump symbols to console +-- +-- @param binaryfile the object file path (required) +function dump(binaryfile) + local symbols = _get_symbols(binaryfile) + if symbols and #symbols > 0 then + print("") + print("Symbols:") + for i, sym in ipairs(symbols) do + local value_str = "" + if sym.value then + value_str = string.format("0x%x", sym.value) + end + local size_str = "" + if sym.size then + size_str = string.format(" size=%d", sym.size) + end + local section_str = "" + if sym.section and sym.section > 0 then + section_str = string.format(" section=%d", sym.section) + end + local type_str = "" + if sym.type then + type_str = string.format(" type=%s", sym.type) + end + local bind_str = "" + if sym.bind then + bind_str = string.format(" bind=%s", sym.bind) + end + print(string.format(" %s %s%s%s%s%s", sym.name or "", value_str, size_str, section_str, type_str, bind_str)) + end + print("") + cprint("${bright}%d symbols found!", #symbols) + else + print("") + cprint("${bright}No symbols found!") + end +end + +-- read symbols from object file (auto-detect format: ELF, COFF, Mach-O) +-- +-- @param binaryfile the object file path (required) +-- @return the symbols table +function main(binaryfile) + return _get_symbols(binaryfile) +end + -- cgit v1.3.1 From 7b24dfe374f14c8682d8ea2b66d8892b104c7a12 Mon Sep 17 00:00:00 2001 From: ruki Date: Tue, 9 Dec 2025 00:32:02 +0800 Subject: fix dump --- xmake/modules/utils/binary/readsyms.lua | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) (limited to 'xmake/modules/utils/binary') diff --git a/xmake/modules/utils/binary/readsyms.lua b/xmake/modules/utils/binary/readsyms.lua index ace1c8be3..212c99401 100644 --- a/xmake/modules/utils/binary/readsyms.lua +++ b/xmake/modules/utils/binary/readsyms.lua @@ -27,20 +27,11 @@ import("core.base.binutils") -- @return the symbols table function _get_symbols(binaryfile) assert(binaryfile, "usage: xmake l utils.binary.readsyms ") - + binaryfile = path.absolute(binaryfile) assert(os.isfile(binaryfile), "%s not found!", binaryfile) - - if binutils.readsyms then - local ok, symbols = binutils.readsyms(binaryfile) - if ok then - return symbols - else - raise("readsyms: %s", symbols or "unknown error") - end - else - raise("readsyms: binutils.readsyms not available (C implementation not compiled)") - end + + return binutils.readsyms(binaryfile) end -- dump symbols to console -- cgit v1.3.1 From acd4bfbcf3b73349f6b56197f3c0f27f204cc135 Mon Sep 17 00:00:00 2001 From: ruki Date: Tue, 9 Dec 2025 00:32:47 +0800 Subject: improve dump --- core/src/xmake/binutils/coff/readsyms.c | 34 ++++++------ core/src/xmake/binutils/elf/readsyms.c | 96 ++++++++++++++++----------------- core/src/xmake/binutils/readsyms.c | 16 +++--- xmake/modules/utils/binary/readsyms.lua | 68 +++++++++++++++++------ 4 files changed, 125 insertions(+), 89 deletions(-) (limited to 'xmake/modules/utils/binary') diff --git a/core/src/xmake/binutils/coff/readsyms.c b/core/src/xmake/binutils/coff/readsyms.c index edc5cc3ee..d863c2fdf 100644 --- a/core/src/xmake/binutils/coff/readsyms.c +++ b/core/src/xmake/binutils/coff/readsyms.c @@ -36,7 +36,7 @@ tb_bool_t xm_binutils_coff_read_symbols(tb_stream_ref_t istream, lua_State *lua) { tb_assert_and_check_return_val(istream && lua, tb_false); - + // read COFF header xm_coff_header_t header; if (!tb_stream_seek(istream, 0)) { @@ -45,24 +45,24 @@ tb_bool_t xm_binutils_coff_read_symbols(tb_stream_ref_t istream, lua_State *lua) if (!tb_stream_bread(istream, (tb_byte_t*)&header, sizeof(header))) { return tb_false; } - + // check if there are symbols if (header.nsyms == 0 || header.symtabofs == 0) { lua_newtable(lua); return tb_true; } - + // create result table lua_newtable(lua); - + // read string table offset (after symbol table) tb_uint32_t strtab_offset = header.symtabofs + header.nsyms * 18; // each symbol is 18 bytes - + // read symbols if (!tb_stream_seek(istream, header.symtabofs)) { return tb_false; } - + tb_uint32_t sym_index = 0; tb_uint32_t sym_count = 0; while (sym_index < header.nsyms) { @@ -71,7 +71,7 @@ tb_bool_t xm_binutils_coff_read_symbols(tb_stream_ref_t istream, lua_State *lua) if (!tb_stream_bread(istream, (tb_byte_t*)&sym, sizeof(sym))) { return tb_false; } - + // get symbol name tb_char_t name[256]; if (!xm_binutils_coff_get_symbol_name(istream, &sym, strtab_offset, name, sizeof(name)) || !name[0]) { @@ -84,41 +84,41 @@ tb_bool_t xm_binutils_coff_read_symbols(tb_stream_ref_t istream, lua_State *lua) } continue; } - + // create symbol table entry lua_pushinteger(lua, sym_count + 1); lua_newtable(lua); - + // name lua_pushstring(lua, "name"); lua_pushstring(lua, name); lua_settable(lua, -3); - + // value lua_pushstring(lua, "value"); lua_pushinteger(lua, sym.value); lua_settable(lua, -3); - + // section lua_pushstring(lua, "section"); lua_pushinteger(lua, sym.sect); lua_settable(lua, -3); - + // type lua_pushstring(lua, "type"); lua_pushstring(lua, xm_binutils_coff_get_symbol_type(sym.scl)); lua_settable(lua, -3); - + // storage class lua_pushstring(lua, "storage_class"); lua_pushinteger(lua, sym.scl); lua_settable(lua, -3); - + lua_settable(lua, -3); - + sym_count++; sym_index++; - + // skip auxiliary entries if (sym.naux > 0) { sym_index += sym.naux; @@ -128,6 +128,6 @@ tb_bool_t xm_binutils_coff_read_symbols(tb_stream_ref_t istream, lua_State *lua) } } } - + return tb_true; } diff --git a/core/src/xmake/binutils/elf/readsyms.c b/core/src/xmake/binutils/elf/readsyms.c index ce6653bfe..06c17a697 100644 --- a/core/src/xmake/binutils/elf/readsyms.c +++ b/core/src/xmake/binutils/elf/readsyms.c @@ -36,7 +36,7 @@ tb_bool_t xm_binutils_elf_read_symbols_32(tb_stream_ref_t istream, lua_State *lua) { tb_assert_and_check_return_val(istream && lua, tb_false); - + // read ELF header xm_elf32_header_t header; if (!tb_stream_seek(istream, 0)) { @@ -45,23 +45,23 @@ tb_bool_t xm_binutils_elf_read_symbols_32(tb_stream_ref_t istream, lua_State *lu if (!tb_stream_bread(istream, (tb_byte_t*)&header, sizeof(header))) { return tb_false; } - + // find .symtab section xm_elf32_section_t symtab_section; xm_elf32_section_t strtab_section; tb_bool_t found_symtab = tb_false; tb_bool_t found_strtab = tb_false; - + if (!tb_stream_seek(istream, header.e_shoff)) { return tb_false; } - + for (tb_uint16_t i = 0; i < header.e_shnum; i++) { xm_elf32_section_t section; if (!tb_stream_bread(istream, (tb_byte_t*)§ion, sizeof(section))) { return tb_false; } - + if (section.sh_type == XM_ELF_SHT_SYMTAB) { symtab_section = section; found_symtab = tb_true; @@ -74,12 +74,12 @@ tb_bool_t xm_binutils_elf_read_symbols_32(tb_stream_ref_t istream, lua_State *lu } } } - + if (!found_symtab) { lua_newtable(lua); return tb_true; } - + // find string table if (!found_strtab && symtab_section.sh_link < header.e_shnum) { if (!tb_stream_seek(istream, header.e_shoff + symtab_section.sh_link * sizeof(xm_elf32_section_t))) { @@ -90,83 +90,83 @@ tb_bool_t xm_binutils_elf_read_symbols_32(tb_stream_ref_t istream, lua_State *lu } found_strtab = tb_true; } - + if (!found_strtab) { lua_newtable(lua); return tb_true; } - + // create result table lua_newtable(lua); - + // read symbols tb_uint32_t sym_count = symtab_section.sh_size / sizeof(xm_elf32_symbol_t); if (!tb_stream_seek(istream, symtab_section.sh_offset)) { return tb_false; } - + tb_uint32_t result_count = 0; for (tb_uint32_t i = 0; i < sym_count; i++) { xm_elf32_symbol_t sym; if (!tb_stream_bread(istream, (tb_byte_t*)&sym, sizeof(sym))) { return tb_false; } - + // skip NULL symbol if (sym.st_name == 0 && sym.st_value == 0 && sym.st_size == 0) { continue; } - + // get symbol name tb_char_t name[256]; if (!xm_binutils_elf_read_string(istream, strtab_section.sh_offset, sym.st_name, name, sizeof(name)) || !name[0]) { continue; } - + // create symbol table entry lua_pushinteger(lua, result_count + 1); lua_newtable(lua); - + // name lua_pushstring(lua, "name"); lua_pushstring(lua, name); lua_settable(lua, -3); - + // value lua_pushstring(lua, "value"); lua_pushinteger(lua, sym.st_value); lua_settable(lua, -3); - + // size lua_pushstring(lua, "size"); lua_pushinteger(lua, sym.st_size); lua_settable(lua, -3); - + // section lua_pushstring(lua, "section"); lua_pushinteger(lua, sym.st_shndx); lua_settable(lua, -3); - + // type lua_pushstring(lua, "type"); lua_pushstring(lua, xm_binutils_elf_get_symbol_type(sym.st_info)); lua_settable(lua, -3); - + // bind lua_pushstring(lua, "bind"); lua_pushstring(lua, xm_binutils_elf_get_symbol_bind(sym.st_info)); lua_settable(lua, -3); - + lua_settable(lua, -3); result_count++; } - + return tb_true; } tb_bool_t xm_binutils_elf_read_symbols_64(tb_stream_ref_t istream, lua_State *lua) { tb_assert_and_check_return_val(istream && lua, tb_false); - + // read ELF header xm_elf64_header_t header; if (!tb_stream_seek(istream, 0)) { @@ -175,23 +175,23 @@ tb_bool_t xm_binutils_elf_read_symbols_64(tb_stream_ref_t istream, lua_State *lu if (!tb_stream_bread(istream, (tb_byte_t*)&header, sizeof(header))) { return tb_false; } - + // find .symtab section xm_elf64_section_t symtab_section; xm_elf64_section_t strtab_section; tb_bool_t found_symtab = tb_false; tb_bool_t found_strtab = tb_false; - + if (!tb_stream_seek(istream, header.e_shoff)) { return tb_false; } - + for (tb_uint16_t i = 0; i < header.e_shnum; i++) { xm_elf64_section_t section; if (!tb_stream_bread(istream, (tb_byte_t*)§ion, sizeof(section))) { return tb_false; } - + if (section.sh_type == XM_ELF_SHT_SYMTAB) { symtab_section = section; found_symtab = tb_true; @@ -202,12 +202,12 @@ tb_bool_t xm_binutils_elf_read_symbols_64(tb_stream_ref_t istream, lua_State *lu } } } - + if (!found_symtab) { lua_newtable(lua); return tb_true; } - + // find string table if (!found_strtab && symtab_section.sh_link < header.e_shnum) { if (!tb_stream_seek(istream, header.e_shoff + symtab_section.sh_link * sizeof(xm_elf64_section_t))) { @@ -218,83 +218,83 @@ tb_bool_t xm_binutils_elf_read_symbols_64(tb_stream_ref_t istream, lua_State *lu } found_strtab = tb_true; } - + if (!found_strtab) { lua_newtable(lua); return tb_true; } - + // create result table lua_newtable(lua); - + // read symbols tb_uint32_t sym_count = (tb_uint32_t)(symtab_section.sh_size / sizeof(xm_elf64_symbol_t)); if (!tb_stream_seek(istream, symtab_section.sh_offset)) { return tb_false; } - + tb_uint32_t result_count = 0; for (tb_uint32_t i = 0; i < sym_count; i++) { xm_elf64_symbol_t sym; if (!tb_stream_bread(istream, (tb_byte_t*)&sym, sizeof(sym))) { return tb_false; } - + // skip NULL symbol if (sym.st_name == 0 && sym.st_value == 0 && sym.st_size == 0) { continue; } - + // get symbol name tb_char_t name[256]; if (!xm_binutils_elf_read_string(istream, strtab_section.sh_offset, sym.st_name, name, sizeof(name)) || !name[0]) { continue; } - + // create symbol table entry lua_pushinteger(lua, result_count + 1); lua_newtable(lua); - + // name lua_pushstring(lua, "name"); lua_pushstring(lua, name); lua_settable(lua, -3); - + // value lua_pushstring(lua, "value"); lua_pushinteger(lua, sym.st_value); lua_settable(lua, -3); - + // size lua_pushstring(lua, "size"); lua_pushinteger(lua, sym.st_size); lua_settable(lua, -3); - + // section lua_pushstring(lua, "section"); lua_pushinteger(lua, sym.st_shndx); lua_settable(lua, -3); - + // type lua_pushstring(lua, "type"); lua_pushstring(lua, xm_binutils_elf_get_symbol_type(sym.st_info)); lua_settable(lua, -3); - + // bind lua_pushstring(lua, "bind"); lua_pushstring(lua, xm_binutils_elf_get_symbol_bind(sym.st_info)); lua_settable(lua, -3); - + lua_settable(lua, -3); result_count++; } - + return tb_true; } tb_bool_t xm_binutils_elf_read_symbols(tb_stream_ref_t istream, lua_State *lua) { tb_assert_and_check_return_val(istream && lua, tb_false); - + // read and check ELF magic tb_uint8_t magic[4]; if (!xm_binutils_read_magic(istream, magic, 4)) { @@ -303,7 +303,7 @@ tb_bool_t xm_binutils_elf_read_symbols(tb_stream_ref_t istream, lua_State *lua) if (magic[0] != 0x7f || magic[1] != 'E' || magic[2] != 'L' || magic[3] != 'F') { return tb_false; } - + // check ELF class (32-bit or 64-bit) tb_uint8_t elf_class; if (!tb_stream_seek(istream, 4)) { @@ -312,13 +312,13 @@ tb_bool_t xm_binutils_elf_read_symbols(tb_stream_ref_t istream, lua_State *lua) if (!tb_stream_bread(istream, (tb_byte_t*)&elf_class, 1)) { return tb_false; } - + if (elf_class == 1) { return xm_binutils_elf_read_symbols_32(istream, lua); } else if (elf_class == 2) { return xm_binutils_elf_read_symbols_64(istream, lua); } - + return tb_false; } diff --git a/core/src/xmake/binutils/readsyms.c b/core/src/xmake/binutils/readsyms.c index dbb8e5957..ae261782f 100644 --- a/core/src/xmake/binutils/readsyms.c +++ b/core/src/xmake/binutils/readsyms.c @@ -51,11 +51,11 @@ extern tb_bool_t xm_binutils_macho_read_symbols(tb_stream_ref_t istream, lua_Sta */ tb_int_t xm_binutils_readsyms(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); - + // get the object file path tb_char_t const *objectfile = luaL_checkstring(lua, 1); tb_check_return_val(objectfile, 0); - + // open file tb_stream_ref_t istream = tb_stream_init_from_file(objectfile, TB_FILE_MODE_RO); if (!istream) { @@ -63,7 +63,7 @@ tb_int_t xm_binutils_readsyms(lua_State *lua) { lua_pushfstring(lua, "readsyms: open %s failed", objectfile); return 2; } - + tb_bool_t ok = tb_false; do { if (!tb_stream_open(istream)) { @@ -71,7 +71,7 @@ tb_int_t xm_binutils_readsyms(lua_State *lua) { lua_pushfstring(lua, "readsyms: open %s failed", objectfile); break; } - + // detect format tb_int_t format = xm_binutils_detect_format(istream); if (format < 0) { @@ -79,7 +79,7 @@ tb_int_t xm_binutils_readsyms(lua_State *lua) { lua_pushfstring(lua, "readsyms: cannot detect file format"); break; } - + // read symbols based on format if (format == XM_BINUTILS_FORMAT_COFF) { // COFF @@ -108,15 +108,15 @@ tb_int_t xm_binutils_readsyms(lua_State *lua) { lua_pushfstring(lua, "readsyms: unsupported or unknown file format"); break; } - + ok = tb_true; } while (0); - + if (istream) { tb_stream_clos(istream); } istream = tb_null; - + return ok ? 1 : 2; } diff --git a/xmake/modules/utils/binary/readsyms.lua b/xmake/modules/utils/binary/readsyms.lua index 212c99401..899b43f71 100644 --- a/xmake/modules/utils/binary/readsyms.lua +++ b/xmake/modules/utils/binary/readsyms.lua @@ -40,30 +40,66 @@ end function dump(binaryfile) local symbols = _get_symbols(binaryfile) if symbols and #symbols > 0 then - print("") - print("Symbols:") + -- calculate column widths for alignment + local max_value_len = 0 + local max_name_len = 0 + local max_type_len = 0 + local max_bind_len = 0 + local max_section_len = 0 + local max_size_len = 0 + for i, sym in ipairs(symbols) do - local value_str = "" if sym.value then - value_str = string.format("0x%x", sym.value) - end - local size_str = "" - if sym.size then - size_str = string.format(" size=%d", sym.size) + local value_str = string.format("0x%x", sym.value) + max_value_len = math.max(max_value_len, #value_str) end - local section_str = "" - if sym.section and sym.section > 0 then - section_str = string.format(" section=%d", sym.section) + if sym.name then + max_name_len = math.max(max_name_len, #sym.name) end - local type_str = "" if sym.type then - type_str = string.format(" type=%s", sym.type) + max_type_len = math.max(max_type_len, #sym.type) end - local bind_str = "" if sym.bind then - bind_str = string.format(" bind=%s", sym.bind) + max_bind_len = math.max(max_bind_len, #sym.bind) + end + if sym.section then + local section_str = tostring(sym.section) + max_section_len = math.max(max_section_len, #section_str) + end + if sym.size then + local size_str = tostring(sym.size) + max_size_len = math.max(max_size_len, #size_str) end - print(string.format(" %s %s%s%s%s%s", sym.name or "", value_str, size_str, section_str, type_str, bind_str)) + end + + -- calculate column widths + local value_width = math.max(max_value_len, 10) + local type_width = math.max(max_type_len, 4) + local bind_width = math.max(max_bind_len, 4) + local section_width = math.max(max_section_len, 7) + local size_width = math.max(max_size_len, 4) + + -- print header + print("") + print("Symbols:") + local header_format = string.format(" %%-%ds %%-%ds %%-%ds %%-%ds %%-%ds %%s", + value_width, type_width, bind_width, section_width, size_width) + print(string.format(header_format, "VALUE", "TYPE", "BIND", "SECTION", "SIZE", "NAME")) + print(string.rep("-", 80)) + + -- print symbols + local format_str = string.format(" %%-%ds %%-%ds %%-%ds %%-%ds %%-%ds %%s", + value_width, type_width, bind_width, section_width, size_width) + + for i, sym in ipairs(symbols) do + local value_str = sym.value and string.format("0x%x", sym.value) or "" + local type_str = sym.type or "" + local bind_str = sym.bind or "" + local section_str = sym.section and sym.section > 0 and tostring(sym.section) or "" + local size_str = sym.size and tostring(sym.size) or "" + local name_str = sym.name or "" + + print(string.format(format_str, value_str, type_str, bind_str, section_str, size_str, name_str)) end print("") cprint("${bright}%d symbols found!", #symbols) -- cgit v1.3.1 From 333af0b66dfe73fabb2c900bce00ba2d50bfe622 Mon Sep 17 00:00:00 2001 From: ruki Date: Tue, 9 Dec 2025 00:33:18 +0800 Subject: fix readsyms for macho --- core/src/xmake/binutils/macho/prefix.h | 6 +++--- xmake/modules/utils/binary/readsyms.lua | 6 ++---- 2 files changed, 5 insertions(+), 7 deletions(-) (limited to 'xmake/modules/utils/binary') diff --git a/core/src/xmake/binutils/macho/prefix.h b/core/src/xmake/binutils/macho/prefix.h index c11fbebb6..39ac857f1 100644 --- a/core/src/xmake/binutils/macho/prefix.h +++ b/core/src/xmake/binutils/macho/prefix.h @@ -326,7 +326,7 @@ static __tb_inline__ tb_uint32_t xm_binutils_macho_parse_version(tb_char_t const * * @param istream the input stream * @param strtab_offset the string table offset - * @param offset the string offset (relative to string table content, after size field) + * @param offset the string offset (nlist.strx, relative to string table start, including 4-byte size field) * @param name the buffer to store the string * @param name_size the size of the buffer * @return tb_true on success, tb_false on failure @@ -335,8 +335,8 @@ static __tb_inline__ tb_bool_t xm_binutils_macho_read_string(tb_stream_ref_t ist tb_assert_and_check_return_val(istream && name && name_size > 0, tb_false); tb_hize_t saved_pos = tb_stream_offset(istream); - // string table starts with 4-byte size field, so offset is from after that - if (!tb_stream_seek(istream, strtab_offset + 4 + offset)) { + // nlist.strx is offset from string table start (including 4-byte size field) + if (!tb_stream_seek(istream, strtab_offset + offset)) { return tb_false; } diff --git a/xmake/modules/utils/binary/readsyms.lua b/xmake/modules/utils/binary/readsyms.lua index 899b43f71..103b13891 100644 --- a/xmake/modules/utils/binary/readsyms.lua +++ b/xmake/modules/utils/binary/readsyms.lua @@ -82,14 +82,12 @@ function dump(binaryfile) -- print header print("") print("Symbols:") - local header_format = string.format(" %%-%ds %%-%ds %%-%ds %%-%ds %%-%ds %%s", - value_width, type_width, bind_width, section_width, size_width) + local header_format = " %-" .. value_width .. "s %-" .. type_width .. "s %-" .. bind_width .. "s %-" .. section_width .. "s %-" .. size_width .. "s %s" print(string.format(header_format, "VALUE", "TYPE", "BIND", "SECTION", "SIZE", "NAME")) print(string.rep("-", 80)) -- print symbols - local format_str = string.format(" %%-%ds %%-%ds %%-%ds %%-%ds %%-%ds %%s", - value_width, type_width, bind_width, section_width, size_width) + local format_str = " %-" .. value_width .. "s %-" .. type_width .. "s %-" .. bind_width .. "s %-" .. section_width .. "s %-" .. size_width .. "s %s" for i, sym in ipairs(symbols) do local value_str = sym.value and string.format("0x%x", sym.value) or "" -- cgit v1.3.1 From d48b2fcf37ed5c323d8e2d2d407bda9679dc01dc Mon Sep 17 00:00:00 2001 From: ruki Date: Tue, 9 Dec 2025 00:42:30 +0800 Subject: improve symbol dump --- core/src/xmake/binutils/coff/prefix.h | 60 ++++++++++++++++++++++++-------- core/src/xmake/binutils/coff/readsyms.c | 59 ++++++++++++++++++++++--------- core/src/xmake/binutils/elf/readsyms.c | 40 --------------------- core/src/xmake/binutils/macho/readsyms.c | 30 ---------------- xmake/modules/utils/binary/readsyms.lua | 38 ++++---------------- 5 files changed, 93 insertions(+), 134 deletions(-) (limited to 'xmake/modules/utils/binary') diff --git a/core/src/xmake/binutils/coff/prefix.h b/core/src/xmake/binutils/coff/prefix.h index ccc7f6292..1b1c2298e 100644 --- a/core/src/xmake/binutils/coff/prefix.h +++ b/core/src/xmake/binutils/coff/prefix.h @@ -34,6 +34,11 @@ #define XM_COFF_MACHINE_ARM 0x01c0 #define XM_COFF_MACHINE_ARM64 0xaa64 +// COFF section flags +#define XM_COFF_SCN_CNT_CODE 0x20 // IMAGE_SCN_CNT_CODE +#define XM_COFF_SCN_CNT_INITIALIZED_DATA 0x40 // IMAGE_SCN_CNT_INITIALIZED_DATA +#define XM_COFF_SCN_CNT_UNINITIALIZED_DATA 0x80 // IMAGE_SCN_CNT_UNINITIALIZED_DATA + #define XM_COFF_SECTION_RDATA 0x40000040 // IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ /* ////////////////////////////////////////////////////////////////////////////////////// @@ -178,14 +183,18 @@ static __tb_inline__ tb_void_t xm_binutils_coff_write_symbol_name(tb_stream_ref_ /* read string from COFF string table * * @param istream the input stream - * @param strtab_offset the string table offset - * @param offset the string offset (relative to string table content, after size field) + * @param strtab_offset the string table offset (including 4-byte size field) + * @param offset the string offset (from start of string table content, after size field) * @return the string (static buffer, valid until next call) */ static __tb_inline__ tb_bool_t xm_binutils_coff_read_string(tb_stream_ref_t istream, tb_uint32_t strtab_offset, tb_uint32_t offset, tb_char_t *name, tb_size_t name_size) { tb_assert_and_check_return_val(istream && name && name_size > 0, tb_false); - // read string table size + // In COFF format, the offset in symbol table is from the start of string table + // (including the 4-byte size field). So offset=4 points to the first string after + // the size field, offset=74 points to a string at position 74 from the start. + + // read string table size first to validate offset tb_uint32_t strtab_size = 0; tb_hize_t saved_pos = tb_stream_offset(istream); if (!tb_stream_seek(istream, strtab_offset)) { @@ -196,14 +205,17 @@ static __tb_inline__ tb_bool_t xm_binutils_coff_read_string(tb_stream_ref_t istr return tb_false; } - // check offset (offset is relative to start of string table, after the 4-byte size field) - if (offset >= strtab_size - 4) { + // check offset (must be >= 4 to skip the size field, and < strtab_size) + if (offset < 4 || offset >= strtab_size) { tb_stream_seek(istream, saved_pos); return tb_false; } - // seek to string position (offset is from start of string table content, after size field) - if (!tb_stream_seek(istream, strtab_offset + 4 + offset)) { + // seek to string position (offset is from start of string table, including size field) + // strtab_offset points to the start of string table (including 4-byte size field) + // offset is from the start of string table (including size field) + // So we use strtab_offset + offset directly + if (!tb_stream_seek(istream, strtab_offset + offset)) { tb_stream_seek(istream, saved_pos); return tb_false; } @@ -260,11 +272,13 @@ static __tb_inline__ tb_bool_t xm_binutils_coff_get_symbol_name(tb_stream_ref_t /* get symbol type character (nm-style) from COFF symbol * - * @param scl the storage class - * @param sect the section number (0 = undefined) - * @return the type character (T/t/D/d/B/b/U) + * @param scl the storage class + * @param sect the section number (0 = undefined, 1-based) + * @param sections the section headers array + * @param nsects the number of sections + * @return the type character (T/t/D/d/B/b/U) */ -static __tb_inline__ tb_char_t xm_binutils_coff_get_symbol_type_char(tb_uint8_t scl, tb_int16_t sect) { +static __tb_inline__ tb_char_t xm_binutils_coff_get_symbol_type_char(tb_uint8_t scl, tb_int16_t sect, xm_coff_section_t const *sections, tb_uint16_t nsects) { // undefined symbol if (sect == 0) { return 'U'; @@ -273,17 +287,33 @@ static __tb_inline__ tb_char_t xm_binutils_coff_get_symbol_type_char(tb_uint8_t // check if external tb_bool_t is_external = (scl == 2); // IMAGE_SYM_CLASS_EXTERNAL - // For COFF, section 1 is usually .text, section 2 is .data, section 3 is .bss - // This is a heuristic and may not be 100% accurate + // check section flags to determine type + if (sections && sect > 0 && sect <= nsects) { + tb_uint32_t flags = sections[sect - 1].flags; // section numbers are 1-based + // IMAGE_SCN_CNT_CODE (0x20) - code section + if (flags & XM_COFF_SCN_CNT_CODE) { + return is_external ? 'T' : 't'; // text section + } + // IMAGE_SCN_CNT_UNINITIALIZED_DATA (0x80) - bss section + if (flags & XM_COFF_SCN_CNT_UNINITIALIZED_DATA) { + return is_external ? 'B' : 'b'; // bss section + } + // IMAGE_SCN_CNT_INITIALIZED_DATA (0x40) - data section + if (flags & XM_COFF_SCN_CNT_INITIALIZED_DATA) { + return is_external ? 'D' : 'd'; // data section + } + } + + // fallback: use section number heuristic if (sect == 1) { return is_external ? 'T' : 't'; // text section } else if (sect == 2) { return is_external ? 'D' : 'd'; // data section } else if (sect == 3) { return is_external ? 'B' : 'b'; // bss section - } else { - return is_external ? 'S' : 's'; // other section } + + return is_external ? 'S' : 's'; // other section } #endif diff --git a/core/src/xmake/binutils/coff/readsyms.c b/core/src/xmake/binutils/coff/readsyms.c index abe374367..9a10eba9d 100644 --- a/core/src/xmake/binutils/coff/readsyms.c +++ b/core/src/xmake/binutils/coff/readsyms.c @@ -58,8 +58,30 @@ tb_bool_t xm_binutils_coff_read_symbols(tb_stream_ref_t istream, lua_State *lua) // read string table offset (after symbol table) tb_uint32_t strtab_offset = header.symtabofs + header.nsyms * 18; // each symbol is 18 bytes + // read section headers to determine section types + xm_coff_section_t *sections = tb_null; + if (header.nsects > 0) { + sections = (xm_coff_section_t*)tb_malloc(header.nsects * sizeof(xm_coff_section_t)); + if (sections) { + tb_hize_t saved_pos = tb_stream_offset(istream); + // section headers are after COFF header and optional header + tb_uint32_t section_offset = sizeof(xm_coff_header_t) + (header.opthdr > 0 ? header.opthdr : 0); + if (tb_stream_seek(istream, section_offset)) { + for (tb_uint16_t i = 0; i < header.nsects; i++) { + if (!tb_stream_bread(istream, (tb_byte_t*)§ions[i], sizeof(xm_coff_section_t))) { + break; + } + } + } + tb_stream_seek(istream, saved_pos); + } + } + // read symbols if (!tb_stream_seek(istream, header.symtabofs)) { + if (sections) { + tb_free(sections); + } return tb_false; } @@ -84,7 +106,7 @@ tb_bool_t xm_binutils_coff_read_symbols(tb_stream_ref_t istream, lua_State *lua) } continue; } - + // skip internal symbols (starting with .) if (name[0] == '.') { sym_index++; @@ -96,6 +118,20 @@ tb_bool_t xm_binutils_coff_read_symbols(tb_stream_ref_t istream, lua_State *lua) continue; } + // skip compiler-generated symbols (containing $ or .constprop or .startup, etc.) + if (tb_strchr(name, '$') != tb_null || + tb_strstr(name, ".constprop") != tb_null || + tb_strstr(name, ".startup") != tb_null || + tb_strstr(name, "ta$") != tb_null) { + sym_index++; + if (sym.naux > 0) { + sym_index += sym.naux; // skip auxiliary entries + // skip auxiliary data + tb_stream_seek(istream, tb_stream_offset(istream) + sym.naux * 18); + } + continue; + } + // create symbol table entry lua_pushinteger(lua, sym_count + 1); lua_newtable(lua); @@ -105,28 +141,13 @@ tb_bool_t xm_binutils_coff_read_symbols(tb_stream_ref_t istream, lua_State *lua) lua_pushstring(lua, name); lua_settable(lua, -3); - // value - lua_pushstring(lua, "value"); - lua_pushinteger(lua, sym.value); - lua_settable(lua, -3); - - // section - lua_pushstring(lua, "section"); - lua_pushinteger(lua, sym.sect); - lua_settable(lua, -3); - // type (nm-style: T/t/D/d/B/b/U) - tb_char_t type_char = xm_binutils_coff_get_symbol_type_char(sym.scl, sym.sect); + tb_char_t type_char = xm_binutils_coff_get_symbol_type_char(sym.scl, sym.sect, sections, header.nsects); tb_char_t type_str[2] = {type_char, '\0'}; lua_pushstring(lua, "type"); lua_pushstring(lua, type_str); lua_settable(lua, -3); - // storage class - lua_pushstring(lua, "storage_class"); - lua_pushinteger(lua, sym.scl); - lua_settable(lua, -3); - lua_settable(lua, -3); sym_count++; @@ -142,5 +163,9 @@ tb_bool_t xm_binutils_coff_read_symbols(tb_stream_ref_t istream, lua_State *lua) } } + if (sections) { + tb_free(sections); + } + return tb_true; } diff --git a/core/src/xmake/binutils/elf/readsyms.c b/core/src/xmake/binutils/elf/readsyms.c index 1afc80fc6..6a9f333c7 100644 --- a/core/src/xmake/binutils/elf/readsyms.c +++ b/core/src/xmake/binutils/elf/readsyms.c @@ -143,21 +143,6 @@ tb_bool_t xm_binutils_elf_read_symbols_32(tb_stream_ref_t istream, lua_State *lu lua_pushstring(lua, name); lua_settable(lua, -3); - // value - lua_pushstring(lua, "value"); - lua_pushinteger(lua, sym.st_value); - lua_settable(lua, -3); - - // size - lua_pushstring(lua, "size"); - lua_pushinteger(lua, sym.st_size); - lua_settable(lua, -3); - - // section - lua_pushstring(lua, "section"); - lua_pushinteger(lua, sym.st_shndx); - lua_settable(lua, -3); - // type (nm-style: T/t/D/d/B/b/U) tb_char_t type_char = xm_binutils_elf_get_symbol_type_char(sym.st_info, sym.st_shndx); tb_char_t type_str[2] = {type_char, '\0'}; @@ -165,11 +150,6 @@ tb_bool_t xm_binutils_elf_read_symbols_32(tb_stream_ref_t istream, lua_State *lu lua_pushstring(lua, type_str); lua_settable(lua, -3); - // bind - lua_pushstring(lua, "bind"); - lua_pushstring(lua, xm_binutils_elf_get_symbol_bind(sym.st_info)); - lua_settable(lua, -3); - lua_settable(lua, -3); result_count++; } @@ -284,21 +264,6 @@ tb_bool_t xm_binutils_elf_read_symbols_64(tb_stream_ref_t istream, lua_State *lu lua_pushstring(lua, name); lua_settable(lua, -3); - // value - lua_pushstring(lua, "value"); - lua_pushinteger(lua, sym.st_value); - lua_settable(lua, -3); - - // size - lua_pushstring(lua, "size"); - lua_pushinteger(lua, sym.st_size); - lua_settable(lua, -3); - - // section - lua_pushstring(lua, "section"); - lua_pushinteger(lua, sym.st_shndx); - lua_settable(lua, -3); - // type (nm-style: T/t/D/d/B/b/U) tb_char_t type_char = xm_binutils_elf_get_symbol_type_char(sym.st_info, sym.st_shndx); tb_char_t type_str[2] = {type_char, '\0'}; @@ -306,11 +271,6 @@ tb_bool_t xm_binutils_elf_read_symbols_64(tb_stream_ref_t istream, lua_State *lu lua_pushstring(lua, type_str); lua_settable(lua, -3); - // bind - lua_pushstring(lua, "bind"); - lua_pushstring(lua, xm_binutils_elf_get_symbol_bind(sym.st_info)); - lua_settable(lua, -3); - lua_settable(lua, -3); result_count++; } diff --git a/core/src/xmake/binutils/macho/readsyms.c b/core/src/xmake/binutils/macho/readsyms.c index 62596c45e..dbe7925a4 100644 --- a/core/src/xmake/binutils/macho/readsyms.c +++ b/core/src/xmake/binutils/macho/readsyms.c @@ -124,16 +124,6 @@ tb_bool_t xm_binutils_macho_read_symbols_32(tb_stream_ref_t istream, lua_State * lua_pushstring(lua, name); lua_settable(lua, -3); - // value - lua_pushstring(lua, "value"); - lua_pushinteger(lua, nlist.value); - lua_settable(lua, -3); - - // section - lua_pushstring(lua, "section"); - lua_pushinteger(lua, nlist.sect); - lua_settable(lua, -3); - // type (nm-style: T/t/D/d/B/b/U) tb_char_t type_char = xm_binutils_macho_get_symbol_type_char(nlist.type, nlist.sect); tb_char_t type_str[2] = {type_char, '\0'}; @@ -141,11 +131,6 @@ tb_bool_t xm_binutils_macho_read_symbols_32(tb_stream_ref_t istream, lua_State * lua_pushstring(lua, type_str); lua_settable(lua, -3); - // bind - lua_pushstring(lua, "bind"); - lua_pushstring(lua, xm_binutils_macho_get_symbol_bind(nlist.type)); - lua_settable(lua, -3); - lua_settable(lua, -3); result_count++; } @@ -243,16 +228,6 @@ tb_bool_t xm_binutils_macho_read_symbols_64(tb_stream_ref_t istream, lua_State * lua_pushstring(lua, name); lua_settable(lua, -3); - // value - lua_pushstring(lua, "value"); - lua_pushinteger(lua, nlist.value); - lua_settable(lua, -3); - - // section - lua_pushstring(lua, "section"); - lua_pushinteger(lua, nlist.sect); - lua_settable(lua, -3); - // type (nm-style: T/t/D/d/B/b/U) tb_char_t type_char = xm_binutils_macho_get_symbol_type_char(nlist.type, nlist.sect); tb_char_t type_str[2] = {type_char, '\0'}; @@ -260,11 +235,6 @@ tb_bool_t xm_binutils_macho_read_symbols_64(tb_stream_ref_t istream, lua_State * lua_pushstring(lua, type_str); lua_settable(lua, -3); - // bind - lua_pushstring(lua, "bind"); - lua_pushstring(lua, xm_binutils_macho_get_symbol_bind(nlist.type)); - lua_settable(lua, -3); - lua_settable(lua, -3); result_count++; } diff --git a/xmake/modules/utils/binary/readsyms.lua b/xmake/modules/utils/binary/readsyms.lua index 103b13891..7225177e9 100644 --- a/xmake/modules/utils/binary/readsyms.lua +++ b/xmake/modules/utils/binary/readsyms.lua @@ -41,63 +41,37 @@ function dump(binaryfile) local symbols = _get_symbols(binaryfile) if symbols and #symbols > 0 then -- calculate column widths for alignment - local max_value_len = 0 local max_name_len = 0 local max_type_len = 0 - local max_bind_len = 0 - local max_section_len = 0 - local max_size_len = 0 for i, sym in ipairs(symbols) do - if sym.value then - local value_str = string.format("0x%x", sym.value) - max_value_len = math.max(max_value_len, #value_str) - end if sym.name then max_name_len = math.max(max_name_len, #sym.name) end if sym.type then max_type_len = math.max(max_type_len, #sym.type) end - if sym.bind then - max_bind_len = math.max(max_bind_len, #sym.bind) - end - if sym.section then - local section_str = tostring(sym.section) - max_section_len = math.max(max_section_len, #section_str) - end - if sym.size then - local size_str = tostring(sym.size) - max_size_len = math.max(max_size_len, #size_str) - end end -- calculate column widths - local value_width = math.max(max_value_len, 10) local type_width = math.max(max_type_len, 4) - local bind_width = math.max(max_bind_len, 4) - local section_width = math.max(max_section_len, 7) - local size_width = math.max(max_size_len, 4) + local name_width = math.max(max_name_len, 4) -- print header print("") print("Symbols:") - local header_format = " %-" .. value_width .. "s %-" .. type_width .. "s %-" .. bind_width .. "s %-" .. section_width .. "s %-" .. size_width .. "s %s" - print(string.format(header_format, "VALUE", "TYPE", "BIND", "SECTION", "SIZE", "NAME")) + local header_format = " %-" .. type_width .. "s %s" + print(string.format(header_format, "TYPE", "NAME")) print(string.rep("-", 80)) -- print symbols - local format_str = " %-" .. value_width .. "s %-" .. type_width .. "s %-" .. bind_width .. "s %-" .. section_width .. "s %-" .. size_width .. "s %s" + local format_str = " %-" .. type_width .. "s %s" for i, sym in ipairs(symbols) do - local value_str = sym.value and string.format("0x%x", sym.value) or "" - local type_str = sym.type or "" - local bind_str = sym.bind or "" - local section_str = sym.section and sym.section > 0 and tostring(sym.section) or "" - local size_str = sym.size and tostring(sym.size) or "" + local type_str = sym.type or "unknown" local name_str = sym.name or "" - print(string.format(format_str, value_str, type_str, bind_str, section_str, size_str, name_str)) + print(string.format(format_str, type_str, name_str)) end print("") cprint("${bright}%d symbols found!", #symbols) -- cgit v1.3.1 From 102507b96dab0403592c07c8760644f08ed66dff Mon Sep 17 00:00:00 2001 From: ruki Date: Tue, 9 Dec 2025 22:32:28 +0800 Subject: improve bin2obj --- xmake/core/base/binutils.lua | 49 +++++++++--- .../sandbox/modules/import/core/base/binutils.lua | 23 +----- xmake/modules/utils/binary/bin2obj.lua | 93 +++------------------- 3 files changed, 53 insertions(+), 112 deletions(-) (limited to 'xmake/modules/utils/binary') diff --git a/xmake/core/base/binutils.lua b/xmake/core/base/binutils.lua index 8047046b2..995f0d0a7 100644 --- a/xmake/core/base/binutils.lua +++ b/xmake/core/base/binutils.lua @@ -39,23 +39,46 @@ function binutils.bin2c(binaryfile, outputfile, opt) end end --- generate COFF object file from the binary file -function binutils.bin2coff(binaryfile, outputfile, opt) +-- generate object file from the binary file +-- @param binaryfile the binary file path +-- @param outputfile the output object file path +-- @param opt the options +-- - format: the object file format (coff, elf, macho), required +-- - symbol_prefix: the symbol prefix (default: _binary_) +-- - arch: the target architecture (default: x86_64) +-- - plat: the target platform (default: macosx, only for macho) +-- - basename: the base name for symbols +-- - target_minver: the target minimum version (only for macho) +-- - xcode_sdkver: the Xcode SDK version (only for macho) +-- - zeroend: append null terminator (default: false) +function binutils.bin2obj(binaryfile, outputfile, opt) opt = opt or {} - return binutils._bin2coff(binaryfile, outputfile, opt.symbol_prefix or "_binary_", opt.arch or "x86_64", opt.basename, opt.zeroend or false) -end + local format = opt.format + if not format then + return nil, "bin2obj: format is required (coff, elf, or macho)" + end + format = format:lower() --- generate Mach-O object file from the binary file -function binutils.bin2macho(binaryfile, outputfile, opt) - opt = opt or {} - return binutils._bin2macho(binaryfile, outputfile, opt.symbol_prefix or "_binary_", opt.plat or "macosx", opt.arch or "x86_64", opt.basename, opt.target_minver, opt.xcode_sdkver, opt.zeroend or false) + if format == "coff" then + if not binutils._bin2coff then + return nil, "bin2obj: binutils._bin2coff not available (C implementation not compiled)" + end + return binutils._bin2coff(binaryfile, outputfile, opt.symbol_prefix or "_binary_", opt.arch or "x86_64", opt.basename, opt.zeroend or false) + elseif format == "macho" then + if not binutils._bin2macho then + return nil, "bin2obj: binutils._bin2macho not available (C implementation not compiled)" + end + return binutils._bin2macho(binaryfile, outputfile, opt.symbol_prefix or "_binary_", opt.plat or "macosx", opt.arch or "x86_64", opt.basename, opt.target_minver, opt.xcode_sdkver, opt.zeroend or false) + elseif format == "elf" then + if not binutils._bin2elf then + return nil, "bin2obj: binutils._bin2elf not available (C implementation not compiled)" + end + return binutils._bin2elf(binaryfile, outputfile, opt.symbol_prefix or "_binary_", opt.arch or "x86_64", opt.basename, opt.zeroend or false) + else + return nil, string.format("bin2obj: unsupported format '%s' (supported: coff, elf, macho)", format) + end end --- generate ELF object file from the binary file -function binutils.bin2elf(binaryfile, outputfile, opt) - opt = opt or {} - return binutils._bin2elf(binaryfile, outputfile, opt.symbol_prefix or "_binary_", opt.arch or "x86_64", opt.basename, opt.zeroend or false) -end -- read symbols from object file (auto-detect format: COFF, ELF, or Mach-O) function binutils.readsyms(binaryfile) diff --git a/xmake/core/sandbox/modules/import/core/base/binutils.lua b/xmake/core/sandbox/modules/import/core/base/binutils.lua index 9e371d777..b9a502f8d 100644 --- a/xmake/core/sandbox/modules/import/core/base/binutils.lua +++ b/xmake/core/sandbox/modules/import/core/base/binutils.lua @@ -33,29 +33,14 @@ function sandbox_core_base_binutils.bin2c(binaryfile, outputfile, opt) end end --- generate COFF object file from the binary file -function sandbox_core_base_binutils.bin2coff(binaryfile, outputfile, opt) - local ok, errors = binutils.bin2coff(binaryfile, outputfile, opt) +-- generate object file from the binary file +function sandbox_core_base_binutils.bin2obj(binaryfile, outputfile, opt) + local ok, errors = binutils.bin2obj(binaryfile, outputfile, opt) if not ok then - raise("bin2coff: %s", errors or "unknown errors") + raise("bin2obj: %s", errors or "unknown errors") end end --- generate Mach-O object file from the binary file -function sandbox_core_base_binutils.bin2macho(binaryfile, outputfile, opt) - local ok, errors = binutils.bin2macho(binaryfile, outputfile, opt) - if not ok then - raise("bin2macho: %s", errors or "unknown errors") - end -end - --- generate ELF object file from the binary file -function sandbox_core_base_binutils.bin2elf(binaryfile, outputfile, opt) - local ok, errors = binutils.bin2elf(binaryfile, outputfile, opt) - if not ok then - raise("bin2elf: %s", errors or "unknown errors") - end -end -- read symbols from object file (auto-detect format: ELF, COFF, Mach-O) function sandbox_core_base_binutils.readsyms(binaryfile) diff --git a/xmake/modules/utils/binary/bin2obj.lua b/xmake/modules/utils/binary/bin2obj.lua index 10d396551..7870e2544 100644 --- a/xmake/modules/utils/binary/bin2obj.lua +++ b/xmake/modules/utils/binary/bin2obj.lua @@ -34,86 +34,19 @@ local options = { {nil, "zeroend", "k", nil, "Append a null terminator ('\\0') at the end of data."} } -function _do_bin2obj_coff(binarypath, outputpath, opt) - -- get filename from binary path (with extension, dots replaced with underscores) - local filename = path.filename(binarypath) - -- replace dots with underscores for symbol name (e.g., data.bin -> data_bin) - local basename = filename:gsub("%.", "_") - - -- prepare opt - opt = opt or {} - opt.basename = basename - - -- trace - print("converting binary file %s to COFF object file %s ..", binarypath, outputpath) - - -- do dump - if binutils.bin2coff then - binutils.bin2coff(binarypath, outputpath, opt) - else - raise("bin2obj: binutils.bin2coff not available (C implementation not compiled)") - end - - -- trace - cprint("${bright}%s generated!", outputpath) -end - -function _do_bin2obj_elf(binarypath, outputpath, opt) - -- get filename from binary path (with extension, dots replaced with underscores) - local filename = path.filename(binarypath) - -- replace dots with underscores for symbol name (e.g., data.bin -> data_bin) - local basename = filename:gsub("%.", "_") - - -- prepare opt +function _do_bin2obj(binarypath, outputpath, opt) + -- init source directory and options opt = opt or {} - opt.basename = basename - - -- trace - print("converting binary file %s to ELF object file %s ..", binarypath, outputpath) - - -- do dump - if binutils.bin2elf then - binutils.bin2elf(binarypath, outputpath, opt) - else - raise("bin2obj: binutils.bin2elf not available (C implementation not compiled)") - end - - -- trace - cprint("${bright}%s generated!", outputpath) -end + binarypath = path.absolute(binarypath) + outputpath = path.absolute(outputpath) + assert(os.isfile(binarypath), "%s not found!", binarypath) -function _do_bin2obj_macho(binarypath, outputpath, opt) -- get filename from binary path (with extension, dots replaced with underscores) local filename = path.filename(binarypath) -- replace dots with underscores for symbol name (e.g., data.bin -> data_bin) local basename = filename:gsub("%.", "_") - - -- prepare opt - opt = opt or {} opt.basename = basename - -- trace - print("converting binary file %s to Mach-O object file %s ..", binarypath, outputpath) - - -- do dump - if binutils.bin2macho then - binutils.bin2macho(binarypath, outputpath, opt) - else - raise("bin2obj: binutils.bin2macho not available (C implementation not compiled)") - end - - -- trace - cprint("${bright}%s generated!", outputpath) -end - -function _do_bin2obj(binarypath, outputpath, opt) - - -- init source directory and options - opt = opt or {} - binarypath = path.absolute(binarypath) - outputpath = path.absolute(outputpath) - assert(os.isfile(binarypath), "%s not found!", binarypath) - -- get format (default: coff) local format = opt.format or "coff" format = format:lower() @@ -123,14 +56,14 @@ function _do_bin2obj(binarypath, outputpath, opt) raise("bin2obj: unsupported format '%s' (supported: coff, elf, macho)", format) end - -- do conversion based on format - if format == "coff" then - _do_bin2obj_coff(binarypath, outputpath, opt) - elseif format == "elf" then - _do_bin2obj_elf(binarypath, outputpath, opt) - elseif format == "macho" then - _do_bin2obj_macho(binarypath, outputpath, opt) - end + -- trace + print("converting binary file %s to %s object file %s ..", binarypath, format, outputpath) + + -- do conversion + binutils.bin2obj(binarypath, outputpath, opt) + + -- trace + cprint("${bright}%s generated!", outputpath) end function main(...) -- cgit v1.3.1 From 5931e48282914758fd7c4eeaf9ca05a16521692b Mon Sep 17 00:00:00 2001 From: ruki Date: Tue, 9 Dec 2025 22:34:36 +0800 Subject: fix compile error --- core/src/xmake/binutils/elf/prefix.h | 2 +- xmake/core/base/binutils.lua | 13 ++++++++++++- xmake/modules/utils/binary/bin2obj.lua | 14 +++++++------- 3 files changed, 20 insertions(+), 9 deletions(-) (limited to 'xmake/modules/utils/binary') diff --git a/core/src/xmake/binutils/elf/prefix.h b/core/src/xmake/binutils/elf/prefix.h index d79fe3e11..bd3cc9129 100644 --- a/core/src/xmake/binutils/elf/prefix.h +++ b/core/src/xmake/binutils/elf/prefix.h @@ -278,7 +278,7 @@ static __tb_inline__ tb_bool_t xm_binutils_elf_is_64bit(tb_char_t const *arch) { * @param offset the string offset * @return the string (static buffer, valid until next call) */ -static __tb_inline__ tb_bool_t xm_binutils_elf_read_string(tb_stream_ref_t istream, tb_uint32_t strtab_offset, tb_uint32_t offset, tb_char_t *name, tb_size_t name_size) { +static __tb_inline__ tb_bool_t xm_binutils_elf_read_string(tb_stream_ref_t istream, tb_uint64_t strtab_offset, tb_uint32_t offset, tb_char_t *name, tb_size_t name_size) { tb_assert_and_check_return_val(istream && name && name_size > 0, tb_false); tb_hize_t saved_pos = tb_stream_offset(istream); diff --git a/xmake/core/base/binutils.lua b/xmake/core/base/binutils.lua index 995f0d0a7..77b17dc92 100644 --- a/xmake/core/base/binutils.lua +++ b/xmake/core/base/binutils.lua @@ -21,6 +21,9 @@ -- define module local binutils = binutils or {} +-- load modules +local os = require("base/os") + -- save original interfaces binutils._bin2c = binutils._bin2c or binutils.bin2c binutils._bin2coff = binutils._bin2coff or binutils.bin2coff @@ -55,7 +58,15 @@ function binutils.bin2obj(binaryfile, outputfile, opt) opt = opt or {} local format = opt.format if not format then - return nil, "bin2obj: format is required (coff, elf, or macho)" + -- auto-detect format based on host platform + local host = os.host() + if host == "windows" or host == "mingw" or host == "msys" or host == "cygwin" then + format = "coff" + elseif host == "macosx" or host == "iphoneos" or host == "watchos" or host == "appletvos" then + format = "macho" + else + format = "elf" + end end format = format:lower() diff --git a/xmake/modules/utils/binary/bin2obj.lua b/xmake/modules/utils/binary/bin2obj.lua index 7870e2544..95e705ca6 100644 --- a/xmake/modules/utils/binary/bin2obj.lua +++ b/xmake/modules/utils/binary/bin2obj.lua @@ -47,17 +47,17 @@ function _do_bin2obj(binarypath, outputpath, opt) local basename = filename:gsub("%.", "_") opt.basename = basename - -- get format (default: coff) - local format = opt.format or "coff" - format = format:lower() - -- validate format - if format ~= "coff" and format ~= "elf" and format ~= "macho" then - raise("bin2obj: unsupported format '%s' (supported: coff, elf, macho)", format) + local format = opt.format + if format then + format = format:lower() + if format ~= "coff" and format ~= "elf" and format ~= "macho" then + raise("bin2obj: unsupported format '%s' (supported: coff, elf, macho)", format) + end end -- trace - print("converting binary file %s to %s object file %s ..", binarypath, format, outputpath) + print("converting binary file %s to %s object file %s ..", binarypath, format or "coff", outputpath) -- do conversion binutils.bin2obj(binarypath, outputpath, opt) -- cgit v1.3.1 From 841d121decc17e2fe5eb6c7930e4ca4d805b28fd Mon Sep 17 00:00:00 2001 From: ruki Date: Tue, 9 Dec 2025 22:38:02 +0800 Subject: improve export_all --- xmake/modules/utils/binary/readsyms.lua | 4 +- .../rules/utils/symbols/export_all/export_all.lua | 57 +++++++++++++++++++++- 2 files changed, 57 insertions(+), 4 deletions(-) (limited to 'xmake/modules/utils/binary') diff --git a/xmake/modules/utils/binary/readsyms.lua b/xmake/modules/utils/binary/readsyms.lua index 7225177e9..6aaa414d0 100644 --- a/xmake/modules/utils/binary/readsyms.lua +++ b/xmake/modules/utils/binary/readsyms.lua @@ -56,14 +56,14 @@ function dump(binaryfile) -- calculate column widths local type_width = math.max(max_type_len, 4) local name_width = math.max(max_name_len, 4) - + -- print header print("") print("Symbols:") local header_format = " %-" .. type_width .. "s %s" print(string.format(header_format, "TYPE", "NAME")) print(string.rep("-", 80)) - + -- print symbols local format_str = " %-" .. type_width .. "s %s" diff --git a/xmake/rules/utils/symbols/export_all/export_all.lua b/xmake/rules/utils/symbols/export_all/export_all.lua index b218dca39..039c190cc 100644 --- a/xmake/rules/utils/symbols/export_all/export_all.lua +++ b/xmake/rules/utils/symbols/export_all/export_all.lua @@ -23,6 +23,7 @@ import("lib.detect.find_tool") import("core.tool.toolchain") import("core.base.option") import("core.base.hashset") +import("core.base.binutils") import("core.project.depend") import("utils.progress") @@ -146,6 +147,52 @@ function _get_allsymbols_by_objdump(target, objdump, opt) return allsymbols end +-- use readsyms to get all symbols from object files +function _get_allsymbols_by_readsyms(target, opt) + opt = opt or {} + local allsymbols = hashset.new() + local export_classes = opt.export_classes + local export_filter = opt.export_filter + local sourcefiles_map = {} + if export_filter then + _get_sourcefiles_map(target, sourcefiles_map) + end + for _, objectfile in ipairs(target:objectfiles()) do + local symbols, errors = binutils.readsyms(objectfile) + if symbols then + local sourcefile = sourcefiles_map[objectfile] + for _, sym in ipairs(symbols) do + if sym.name and sym.type then + -- only export defined symbols (not undefined 'U') + if sym.type ~= "U" then + local symbol = sym.name + -- we need ignore DllMain, https://github.com/xmake-io/xmake/issues/3992 + if target:is_arch("x86") and symbol:startswith("_") and not symbol:startswith("__") and not symbol:startswith("_DllMain@") then + symbol = symbol:sub(2) + end + if export_filter then + if export_filter(symbol, {objectfile = objectfile, sourcefile = sourcefile}) then + allsymbols:insert(symbol) + end + elseif not symbol:startswith("__") then + if export_classes or not symbol:startswith("?") then + if export_classes then + if not symbol:startswith("??_G") and not symbol:startswith("??_E") then + allsymbols:insert(symbol) + end + else + allsymbols:insert(symbol) + end + end + end + end + end + end + end + end + return allsymbols +end + -- export all symbols for dynamic library function main(target, opt) @@ -177,7 +224,7 @@ function main(target, opt) export_classes = export_classes, export_filter = export_filter}) end - if not allsymbols then + if not allsymbols or allsymbols:empty() then local msvc = toolchain.load("msvc", {plat = target:plat(), arch = target:arch()}) if msvc:check() then local dumpbin = assert(find_tool("dumpbin", {envs = msvc:runenvs()}), "dumpbin not found!") @@ -186,9 +233,15 @@ function main(target, opt) export_filter = export_filter}) end end + -- fallback to readsyms if still no symbols found + if not allsymbols or allsymbols:empty() then + allsymbols = _get_allsymbols_by_readsyms(target, { + export_classes = export_classes, + export_filter = export_filter}) + end -- export all symbols - if allsymbols and allsymbols:size() > 0 then + if allsymbols and not allsymbols:empty() then local allsymbols_file = io.open(allsymbols_filepath, 'w') allsymbols_file:print("EXPORTS") for _, symbol in allsymbols:keys() do -- cgit v1.3.1 From 9bcc8fdd4eecb665ea98a38e3fa03b889663922a Mon Sep 17 00:00:00 2001 From: ruki Date: Tue, 9 Dec 2025 22:41:52 +0800 Subject: improve readsyms --- xmake/modules/utils/binary/readsyms.lua | 25 ++++++++-- .../rules/utils/symbols/export_all/export_all.lua | 56 ++++++++++++---------- 2 files changed, 52 insertions(+), 29 deletions(-) (limited to 'xmake/modules/utils/binary') diff --git a/xmake/modules/utils/binary/readsyms.lua b/xmake/modules/utils/binary/readsyms.lua index 6aaa414d0..e5954e92a 100644 --- a/xmake/modules/utils/binary/readsyms.lua +++ b/xmake/modules/utils/binary/readsyms.lua @@ -81,11 +81,28 @@ function dump(binaryfile) end end --- read symbols from object file (auto-detect format: ELF, COFF, Mach-O) +-- read symbols from object file(s) (auto-detect format: ELF, COFF, Mach-O) -- --- @param binaryfile the object file path (required) --- @return the symbols table +-- @param binaryfile the object file path or table of object files (required) +-- @return the symbols table (all symbols from all files if table is provided) function main(binaryfile) - return _get_symbols(binaryfile) + assert(binaryfile, "usage: xmake l utils.binary.readsyms or readsyms(binaryfiles)") + + local all_symbols = {} + if type(binaryfile) == "string" then + -- single file + return _get_symbols(binaryfile) + else + -- multiple files + for _, objectfile in ipairs(binaryfile) do + local symbols = _get_symbols(objectfile) + if symbols then + for _, sym in ipairs(symbols) do + table.insert(all_symbols, sym) + end + end + end + return all_symbols + end end diff --git a/xmake/rules/utils/symbols/export_all/export_all.lua b/xmake/rules/utils/symbols/export_all/export_all.lua index 8c93fc555..6e077aaf3 100644 --- a/xmake/rules/utils/symbols/export_all/export_all.lua +++ b/xmake/rules/utils/symbols/export_all/export_all.lua @@ -23,9 +23,9 @@ import("lib.detect.find_tool") import("core.tool.toolchain") import("core.base.option") import("core.base.hashset") -import("core.base.binutils") import("core.project.depend") import("utils.progress") +import("utils.binary.readsyms") -- It is not very accurate because some rules automatically -- generate objectfiles and do not save the corresponding sourcefiles. @@ -157,33 +157,39 @@ function _get_allsymbols_by_readsyms(target, opt) if export_filter then _get_sourcefiles_map(target, sourcefiles_map) end - for _, objectfile in ipairs(target:objectfiles()) do - local symbols, errors = binutils.readsyms(objectfile) - if symbols then - local sourcefile = sourcefiles_map[objectfile] - for _, sym in ipairs(symbols) do - if sym.name and sym.type then - -- only export function symbols (T/t) for DLL exports - -- skip data (D/d), bss (B/b), other sections (S/s), and undefined (U) symbols - if sym.type == "T" or sym.type == "t" then - local symbol = sym.name - -- we need ignore DllMain, https://github.com/xmake-io/xmake/issues/3992 - if target:is_arch("x86") and symbol:startswith("_") and not symbol:startswith("__") and not symbol:startswith("_DllMain@") then - symbol = symbol:sub(2) - end - if export_filter then - if export_filter(symbol, {objectfile = objectfile, sourcefile = sourcefile}) then - allsymbols:insert(symbol) + local objectfiles = target:objectfiles() + local symbols = readsyms(objectfiles) + if symbols then + for _, sym in ipairs(symbols) do + if sym.name and sym.type then + -- only export function symbols (T/t) for DLL exports + -- skip data (D/d), bss (B/b), other sections (S/s), and undefined (U) symbols + if sym.type == "T" or sym.type == "t" then + local symbol = sym.name + -- we need ignore DllMain, https://github.com/xmake-io/xmake/issues/3992 + if target:is_arch("x86") and symbol:startswith("_") and not symbol:startswith("__") and not symbol:startswith("_DllMain@") then + symbol = symbol:sub(2) + end + if export_filter then + -- find sourcefile for this symbol (approximate match) + local sourcefile = nil + for objfile, srcfile in pairs(sourcefiles_map) do + if objfile:find(path.basename(symbol), 1, true) then + sourcefile = srcfile + break end - elseif not symbol:startswith("__") then - if export_classes or not symbol:startswith("?") then - if export_classes then - if not symbol:startswith("??_G") and not symbol:startswith("??_E") then - allsymbols:insert(symbol) - end - else + end + if export_filter(symbol, {sourcefile = sourcefile}) then + allsymbols:insert(symbol) + end + elseif not symbol:startswith("__") then + if export_classes or not symbol:startswith("?") then + if export_classes then + if not symbol:startswith("??_G") and not symbol:startswith("??_E") then allsymbols:insert(symbol) end + else + allsymbols:insert(symbol) end end end -- cgit v1.3.1 From 06561a0bf8a82d2d6bed52daee8bbd3963f797b4 Mon Sep 17 00:00:00 2001 From: ruki Date: Tue, 9 Dec 2025 22:58:49 +0800 Subject: improve readsyms --- xmake/modules/utils/binary/readsyms.lua | 16 ++++++++-------- xmake/modules/utils/run_script.lua | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) (limited to 'xmake/modules/utils/binary') diff --git a/xmake/modules/utils/binary/readsyms.lua b/xmake/modules/utils/binary/readsyms.lua index e5954e92a..0641d79e9 100644 --- a/xmake/modules/utils/binary/readsyms.lua +++ b/xmake/modules/utils/binary/readsyms.lua @@ -83,19 +83,19 @@ end -- read symbols from object file(s) (auto-detect format: ELF, COFF, Mach-O) -- --- @param binaryfile the object file path or table of object files (required) --- @return the symbols table (all symbols from all files if table is provided) -function main(binaryfile) - assert(binaryfile, "usage: xmake l utils.binary.readsyms or readsyms(binaryfiles)") +-- @param binaryfiles the object file path or table of object files (required) +-- @return the symbols table (all symbols from all files if table is provided) +function main(binaryfiles) + assert(binaryfiles, "usage: xmake l utils.binary.readsyms or readsyms(binaryfiles)") local all_symbols = {} - if type(binaryfile) == "string" then + if type(binaryfiles) == "string" then -- single file - return _get_symbols(binaryfile) + return _get_symbols(binaryfiles) else -- multiple files - for _, objectfile in ipairs(binaryfile) do - local symbols = _get_symbols(objectfile) + for _, binaryfile in ipairs(binaryfiles) do + local symbols = _get_symbols(binaryfile) if symbols then for _, sym in ipairs(symbols) do table.insert(all_symbols, sym) diff --git a/xmake/modules/utils/run_script.lua b/xmake/modules/utils/run_script.lua index 82fa8cb0d..e6f8469f6 100644 --- a/xmake/modules/utils/run_script.lua +++ b/xmake/modules/utils/run_script.lua @@ -198,7 +198,7 @@ function main(script, opt) table.insert(argv, arg) end local thread_opt = { - curdir = curdir, + curdir = opt.curdir, command = opt.command, deserialize = opt.deserialize, arguments = argv, -- cgit v1.3.1 From c6ffeca9e14d29e0880826b3caac7a4d1ee4a3d1 Mon Sep 17 00:00:00 2001 From: ruki Date: Tue, 9 Dec 2025 23:02:49 +0800 Subject: update comments --- xmake/modules/utils/binary/readsyms.lua | 2 -- 1 file changed, 2 deletions(-) (limited to 'xmake/modules/utils/binary') diff --git a/xmake/modules/utils/binary/readsyms.lua b/xmake/modules/utils/binary/readsyms.lua index 0641d79e9..6058e8121 100644 --- a/xmake/modules/utils/binary/readsyms.lua +++ b/xmake/modules/utils/binary/readsyms.lua @@ -90,10 +90,8 @@ function main(binaryfiles) local all_symbols = {} if type(binaryfiles) == "string" then - -- single file return _get_symbols(binaryfiles) else - -- multiple files for _, binaryfile in ipairs(binaryfiles) do local symbols = _get_symbols(binaryfile) if symbols then -- cgit v1.3.1